snarkvm_circuit_program/response/
mod.rs

1// Copyright 2024-2025 Aleo Network Foundation
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16#[cfg(test)]
17use snarkvm_circuit_types::environment::assert_scope;
18
19mod from_outputs;
20mod process_outputs_from_callback;
21
22use crate::{Identifier, ProgramID, Value, compute_function_id};
23use snarkvm_circuit_network::Aleo;
24use snarkvm_circuit_types::{Field, U16, environment::prelude::*};
25
26pub enum OutputID<A: Aleo> {
27    /// The hash of the constant output.
28    Constant(Field<A>),
29    /// The hash of the public output.
30    Public(Field<A>),
31    /// The ciphertext hash of the private output.
32    Private(Field<A>),
33    /// The `(commitment, checksum)` tuple of the record output.
34    Record(Field<A>, Field<A>),
35    /// The hash of the external record output.
36    ExternalRecord(Field<A>),
37    /// The hash of the future output.
38    Future(Field<A>),
39}
40
41#[cfg(feature = "console")]
42impl<A: Aleo> Inject for OutputID<A> {
43    type Primitive = console::OutputID<A::Network>;
44
45    /// Initializes the output ID from the given mode and console output ID.
46    fn new(_: Mode, output: Self::Primitive) -> Self {
47        match output {
48            // Inject the expected hash as `Mode::Public`.
49            console::OutputID::Constant(field) => Self::Constant(Field::new(Mode::Public, field)),
50            // Inject the expected hash as `Mode::Public`.
51            console::OutputID::Public(field) => Self::Public(Field::new(Mode::Public, field)),
52            // Inject the ciphertext hash as `Mode::Public`.
53            console::OutputID::Private(field) => Self::Private(Field::new(Mode::Public, field)),
54            // Inject the expected commitment and checksum as `Mode::Public`.
55            console::OutputID::Record(commitment, checksum) => {
56                Self::Record(Field::new(Mode::Public, commitment), Field::new(Mode::Public, checksum))
57            }
58            // Inject the expected hash as `Mode::Public`.
59            console::OutputID::ExternalRecord(hash) => Self::ExternalRecord(Field::new(Mode::Public, hash)),
60            // Inject the expected hash as `Mode::Public`.
61            console::OutputID::Future(hash) => Self::Future(Field::new(Mode::Public, hash)),
62        }
63    }
64}
65
66impl<A: Aleo> OutputID<A> {
67    /// Initializes a constant output ID.
68    fn constant(expected_hash: Field<A>) -> Self {
69        // Inject the expected hash as `Mode::Public`.
70        let output_hash = Field::new(Mode::Public, expected_hash.eject_value());
71        // Ensure the injected hash matches the given hash.
72        A::assert_eq(&output_hash, expected_hash);
73        // Return the output ID.
74        Self::Constant(output_hash)
75    }
76
77    /// Initializes a public output ID.
78    fn public(expected_hash: Field<A>) -> Self {
79        // Inject the expected hash as `Mode::Public`.
80        let output_hash = Field::new(Mode::Public, expected_hash.eject_value());
81        // Ensure the injected hash matches the given hash.
82        A::assert_eq(&output_hash, expected_hash);
83        // Return the output ID.
84        Self::Public(output_hash)
85    }
86
87    /// Initializes a private output ID.
88    fn private(expected_hash: Field<A>) -> Self {
89        // Inject the ciphertext hash as `Mode::Public`.
90        let output_hash = Field::new(Mode::Public, expected_hash.eject_value());
91        // Ensure the injected hash matches the given hash.
92        A::assert_eq(&output_hash, expected_hash);
93        // Return the output ID.
94        Self::Private(output_hash)
95    }
96
97    /// Initializes a record output ID.
98    fn record(expected_commitment: Field<A>, expected_checksum: Field<A>) -> Self {
99        // Inject the expected commitment and checksum as `Mode::Public`.
100        let output_commitment = Field::new(Mode::Public, expected_commitment.eject_value());
101        let output_checksum = Field::new(Mode::Public, expected_checksum.eject_value());
102        // Ensure the injected commitment and checksum match the given commitment and checksum.
103        A::assert_eq(&output_commitment, expected_commitment);
104        A::assert_eq(&output_checksum, expected_checksum);
105        // Return the output ID.
106        Self::Record(output_commitment, output_checksum)
107    }
108
109    /// Initializes an external record output ID.
110    fn external_record(expected_hash: Field<A>) -> Self {
111        // Inject the expected hash as `Mode::Public`.
112        let output_hash = Field::new(Mode::Public, expected_hash.eject_value());
113        // Ensure the injected hash matches the given commitment.
114        A::assert_eq(&output_hash, expected_hash);
115        // Return the output ID.
116        Self::ExternalRecord(output_hash)
117    }
118
119    /// Initializes a future output ID.
120    fn future(expected_hash: Field<A>) -> Self {
121        // Inject the expected hash as `Mode::Public`.
122        let output_hash = Field::new(Mode::Public, expected_hash.eject_value());
123        // Ensure the injected hash matches the given hash.
124        A::assert_eq(&output_hash, expected_hash);
125        // Return the output ID.
126        Self::Future(output_hash)
127    }
128}
129
130#[cfg(feature = "console")]
131impl<A: Aleo> Eject for OutputID<A> {
132    type Primitive = console::OutputID<A::Network>;
133
134    /// Ejects the mode of the output ID.
135    fn eject_mode(&self) -> Mode {
136        match self {
137            Self::Constant(field) => field.eject_mode(),
138            Self::Public(field) => field.eject_mode(),
139            Self::Private(field) => field.eject_mode(),
140            Self::Record(commitment, checksum) => Mode::combine(commitment.eject_mode(), [checksum.eject_mode()]),
141            Self::ExternalRecord(hash) => hash.eject_mode(),
142            Self::Future(hash) => hash.eject_mode(),
143        }
144    }
145
146    /// Ejects the output ID as a primitive.
147    fn eject_value(&self) -> Self::Primitive {
148        match self {
149            Self::Constant(field) => console::OutputID::Constant(field.eject_value()),
150            Self::Public(field) => console::OutputID::Public(field.eject_value()),
151            Self::Private(field) => console::OutputID::Private(field.eject_value()),
152            Self::Record(commitment, checksum) => {
153                console::OutputID::Record(commitment.eject_value(), checksum.eject_value())
154            }
155            Self::ExternalRecord(hash) => console::OutputID::ExternalRecord(hash.eject_value()),
156            Self::Future(hash) => console::OutputID::Future(hash.eject_value()),
157        }
158    }
159}
160
161pub struct Response<A: Aleo> {
162    /// The function output IDs.
163    output_ids: Vec<OutputID<A>>,
164    /// The function outputs.
165    outputs: Vec<Value<A>>,
166}
167
168impl<A: Aleo> Response<A> {
169    /// Returns the output IDs for the transition.
170    pub fn output_ids(&self) -> &[OutputID<A>] {
171        &self.output_ids
172    }
173
174    /// Returns the function outputs.
175    pub fn outputs(&self) -> &[Value<A>] {
176        &self.outputs
177    }
178}
179
180#[cfg(feature = "console")]
181impl<A: Aleo> Eject for Response<A> {
182    type Primitive = console::Response<A::Network>;
183
184    /// Ejects the mode of the response.
185    fn eject_mode(&self) -> Mode {
186        Mode::combine(self.output_ids.eject_mode(), [self.outputs.eject_mode()])
187    }
188
189    /// Ejects the response as a primitive.
190    fn eject_value(&self) -> Self::Primitive {
191        Self::Primitive::from((
192            self.output_ids.iter().map(|output_id| output_id.eject_value()).collect(),
193            self.outputs.eject_value(),
194        ))
195    }
196}