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