snarkvm_circuit_program/response/
mod.rs

1// Copyright (c) 2019-2025 Provable Inc.
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::{Address, 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, sender_ciphertext)` tuple of the record output.
34    Record(Field<A>, 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, sender_ciphertext) => Self::Record(
56                Field::new(Mode::Public, commitment),
57                Field::new(Mode::Public, checksum),
58                Field::new(Mode::Public, sender_ciphertext),
59            ),
60            // Inject the expected hash as `Mode::Public`.
61            console::OutputID::ExternalRecord(hash) => Self::ExternalRecord(Field::new(Mode::Public, hash)),
62            // Inject the expected hash as `Mode::Public`.
63            console::OutputID::Future(hash) => Self::Future(Field::new(Mode::Public, hash)),
64        }
65    }
66}
67
68impl<A: Aleo> OutputID<A> {
69    /// Initializes a constant output ID.
70    fn constant(expected_hash: Field<A>) -> Self {
71        // Inject the expected hash as `Mode::Public`.
72        let output_hash = Field::new(Mode::Public, expected_hash.eject_value());
73        // Ensure the injected hash matches the given hash.
74        A::assert_eq(&output_hash, expected_hash);
75        // Return the output ID.
76        Self::Constant(output_hash)
77    }
78
79    /// Initializes a public output ID.
80    fn public(expected_hash: Field<A>) -> Self {
81        // Inject the expected hash as `Mode::Public`.
82        let output_hash = Field::new(Mode::Public, expected_hash.eject_value());
83        // Ensure the injected hash matches the given hash.
84        A::assert_eq(&output_hash, expected_hash);
85        // Return the output ID.
86        Self::Public(output_hash)
87    }
88
89    /// Initializes a private output ID.
90    fn private(expected_hash: Field<A>) -> Self {
91        // Inject the ciphertext hash as `Mode::Public`.
92        let output_hash = Field::new(Mode::Public, expected_hash.eject_value());
93        // Ensure the injected hash matches the given hash.
94        A::assert_eq(&output_hash, expected_hash);
95        // Return the output ID.
96        Self::Private(output_hash)
97    }
98
99    /// Initializes a record output ID.
100    fn record(
101        expected_commitment: Field<A>,
102        expected_checksum: Field<A>,
103        expected_sender_ciphertext: Field<A>,
104    ) -> Self {
105        // Inject the expected commitment, checksum, and sender ciphertext as `Mode::Public`.
106        let output_commitment = Field::new(Mode::Public, expected_commitment.eject_value());
107        let output_checksum = Field::new(Mode::Public, expected_checksum.eject_value());
108        let output_sender_ciphertext = Field::new(Mode::Public, expected_sender_ciphertext.eject_value()); // Note: Set to `0field` here and in consensus to make optional or deactivated.
109        // Ensure the injected commitment and checksum matches the given commitment and checksum.
110        A::assert_eq(&output_commitment, expected_commitment);
111        A::assert_eq(&output_checksum, expected_checksum);
112        // Ensure the sender ciphertext matches, or the sender ciphertext is zero.
113        // Note: The option to allow a zero-value in the sender ciphertext allows
114        // this feature to become optional or deactivated in the future.
115        let is_sender_ciphertext_equal = output_sender_ciphertext.is_equal(&expected_sender_ciphertext);
116        let is_sender_ciphertext_zero = output_sender_ciphertext.is_zero();
117        A::assert(is_sender_ciphertext_equal | is_sender_ciphertext_zero);
118        // Return the output ID.
119        Self::Record(output_commitment, output_checksum, output_sender_ciphertext)
120    }
121
122    /// Initializes an external record output ID.
123    fn external_record(expected_hash: Field<A>) -> Self {
124        // Inject the expected hash as `Mode::Public`.
125        let output_hash = Field::new(Mode::Public, expected_hash.eject_value());
126        // Ensure the injected hash matches the given commitment.
127        A::assert_eq(&output_hash, expected_hash);
128        // Return the output ID.
129        Self::ExternalRecord(output_hash)
130    }
131
132    /// Initializes a future output ID.
133    fn future(expected_hash: Field<A>) -> Self {
134        // Inject the expected hash as `Mode::Public`.
135        let output_hash = Field::new(Mode::Public, expected_hash.eject_value());
136        // Ensure the injected hash matches the given hash.
137        A::assert_eq(&output_hash, expected_hash);
138        // Return the output ID.
139        Self::Future(output_hash)
140    }
141}
142
143#[cfg(feature = "console")]
144impl<A: Aleo> Eject for OutputID<A> {
145    type Primitive = console::OutputID<A::Network>;
146
147    /// Ejects the mode of the output ID.
148    fn eject_mode(&self) -> Mode {
149        match self {
150            Self::Constant(field) => field.eject_mode(),
151            Self::Public(field) => field.eject_mode(),
152            Self::Private(field) => field.eject_mode(),
153            Self::Record(commitment, checksum, sender_ciphertext) => {
154                Mode::combine(commitment.eject_mode(), [checksum.eject_mode(), sender_ciphertext.eject_mode()])
155            }
156            Self::ExternalRecord(hash) => hash.eject_mode(),
157            Self::Future(hash) => hash.eject_mode(),
158        }
159    }
160
161    /// Ejects the output ID as a primitive.
162    fn eject_value(&self) -> Self::Primitive {
163        match self {
164            Self::Constant(field) => console::OutputID::Constant(field.eject_value()),
165            Self::Public(field) => console::OutputID::Public(field.eject_value()),
166            Self::Private(field) => console::OutputID::Private(field.eject_value()),
167            Self::Record(commitment, checksum, sender_ciphertext) => console::OutputID::Record(
168                commitment.eject_value(),
169                checksum.eject_value(),
170                sender_ciphertext.eject_value(),
171            ),
172            Self::ExternalRecord(hash) => console::OutputID::ExternalRecord(hash.eject_value()),
173            Self::Future(hash) => console::OutputID::Future(hash.eject_value()),
174        }
175    }
176}
177
178pub struct Response<A: Aleo> {
179    /// The function output IDs.
180    output_ids: Vec<OutputID<A>>,
181    /// The function outputs.
182    outputs: Vec<Value<A>>,
183}
184
185impl<A: Aleo> Response<A> {
186    /// Returns the output IDs for the transition.
187    pub fn output_ids(&self) -> &[OutputID<A>] {
188        &self.output_ids
189    }
190
191    /// Returns the function outputs.
192    pub fn outputs(&self) -> &[Value<A>] {
193        &self.outputs
194    }
195}
196
197#[cfg(feature = "console")]
198impl<A: Aleo> Eject for Response<A> {
199    type Primitive = console::Response<A::Network>;
200
201    /// Ejects the mode of the response.
202    fn eject_mode(&self) -> Mode {
203        Mode::combine(self.output_ids.eject_mode(), [self.outputs.eject_mode()])
204    }
205
206    /// Ejects the response as a primitive.
207    fn eject_value(&self) -> Self::Primitive {
208        Self::Primitive::from((
209            self.output_ids.iter().map(|output_id| output_id.eject_value()).collect(),
210            self.outputs.eject_value(),
211        ))
212    }
213}