snarkvm_console_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
16use crate::{Identifier, ProgramID, Register, Value, ValueType, compute_function_id};
17use snarkvm_console_network::Network;
18use snarkvm_console_types::prelude::*;
19
20#[derive(Clone, Debug, PartialEq, Eq)]
21pub enum OutputID<N: Network> {
22    /// The hash of the constant output.
23    Constant(Field<N>),
24    /// The hash of the public output.
25    Public(Field<N>),
26    /// The ciphertext hash of the private output.
27    Private(Field<N>),
28    /// The `(commitment, checksum, sender_ciphertext)` tuple of the record output.
29    Record(Field<N>, Field<N>, Field<N>),
30    /// The hash of the external record's (function_id, record, tvk, output index).
31    ExternalRecord(Field<N>),
32    /// The hash of the future output.
33    Future(Field<N>),
34}
35
36#[derive(Clone, Debug, PartialEq, Eq)]
37pub struct Response<N: Network> {
38    /// The output ID for the transition.
39    output_ids: Vec<OutputID<N>>,
40    /// The function outputs.
41    outputs: Vec<Value<N>>,
42}
43
44impl<N: Network> From<(Vec<OutputID<N>>, Vec<Value<N>>)> for Response<N> {
45    /// Note: This method is used to eject from a circuit.
46    fn from((output_ids, outputs): (Vec<OutputID<N>>, Vec<Value<N>>)) -> Self {
47        Self { output_ids, outputs }
48    }
49}
50
51impl<N: Network> Response<N> {
52    /// Initializes a new response.
53    pub fn new(
54        signer: &Address<N>,
55        network_id: &U16<N>,
56        program_id: &ProgramID<N>,
57        function_name: &Identifier<N>,
58        num_inputs: usize,
59        tvk: &Field<N>,
60        tcm: &Field<N>,
61        outputs: Vec<Value<N>>,
62        output_types: &[ValueType<N>],
63        output_operands: &[Option<Register<N>>],
64    ) -> Result<Self> {
65        // Compute the function ID.
66        let function_id = compute_function_id(network_id, program_id, function_name)?;
67
68        // Compute the output IDs.
69        let output_ids = outputs
70            .iter()
71            .zip_eq(output_types)
72            .zip_eq(output_operands)
73            .enumerate()
74            .map(|(index, ((output, output_type), output_register))| {
75                match output_type {
76                    // For a constant output, compute the hash (using `tcm`) of the output.
77                    ValueType::Constant(..) => {
78                        // Ensure the output is a plaintext.
79                        ensure!(matches!(output, Value::Plaintext(..)), "Expected a plaintext output");
80
81                        // Construct the (console) output index as a field element.
82                        let index = Field::from_u16(
83                            u16::try_from(num_inputs + index).or_halt_with::<N>("Output index exceeds u16"),
84                        );
85                        // Construct the preimage as `(function ID || output || tcm || index)`.
86                        let mut preimage = Vec::new();
87                        preimage.push(function_id);
88                        preimage.extend(output.to_fields()?);
89                        preimage.push(*tcm);
90                        preimage.push(index);
91                        // Hash the output to a field element.
92                        let output_hash = N::hash_psd8(&preimage)?;
93
94                        // Return the output ID.
95                        Ok(OutputID::Constant(output_hash))
96                    }
97                    // For a public output, compute the hash (using `tcm`) of the output.
98                    ValueType::Public(..) => {
99                        // Ensure the output is a plaintext.
100                        ensure!(matches!(output, Value::Plaintext(..)), "Expected a plaintext output");
101
102                        // Construct the (console) output index as a field element.
103                        let index = Field::from_u16(
104                            u16::try_from(num_inputs + index).or_halt_with::<N>("Output index exceeds u16"),
105                        );
106                        // Construct the preimage as `(function ID || output || tcm || index)`.
107                        let mut preimage = Vec::new();
108                        preimage.push(function_id);
109                        preimage.extend(output.to_fields()?);
110                        preimage.push(*tcm);
111                        preimage.push(index);
112                        // Hash the output to a field element.
113                        let output_hash = N::hash_psd8(&preimage)?;
114
115                        // Return the output ID.
116                        Ok(OutputID::Public(output_hash))
117                    }
118                    // For a private output, compute the ciphertext (using `tvk`) and hash the ciphertext.
119                    ValueType::Private(..) => {
120                        // Ensure the output is a plaintext.
121                        ensure!(matches!(output, Value::Plaintext(..)), "Expected a plaintext output");
122                        // Construct the (console) output index as a field element.
123                        let index = Field::from_u16(
124                            u16::try_from(num_inputs + index).or_halt_with::<N>("Output index exceeds u16"),
125                        );
126                        // Compute the output view key as `Hash(function ID || tvk || index)`.
127                        let output_view_key = N::hash_psd4(&[function_id, *tvk, index])?;
128                        // Compute the ciphertext.
129                        let ciphertext = match &output {
130                            Value::Plaintext(plaintext) => plaintext.encrypt_symmetric(output_view_key)?,
131                            // Ensure the output is a plaintext.
132                            Value::Record(..) => bail!("Expected a plaintext output, found a record output"),
133                            Value::Future(..) => bail!("Expected a plaintext output, found a future output"),
134                        };
135                        // Hash the ciphertext to a field element.
136                        let output_hash = N::hash_psd8(&ciphertext.to_fields()?)?;
137                        // Return the output ID.
138                        Ok(OutputID::Private(output_hash))
139                    }
140                    // For a record output, compute the record commitment, and encrypt the record (using `tvk`).
141                    ValueType::Record(record_name) => {
142                        // Retrieve the record.
143                        let record = match &output {
144                            Value::Record(record) => record,
145                            // Ensure the input is a record.
146                            Value::Plaintext(..) => bail!("Expected a record output, found a plaintext output"),
147                            Value::Future(..) => bail!("Expected a record output, found a future output"),
148                        };
149
150                        // Retrieve the output register.
151                        let output_register = match output_register {
152                            Some(output_register) => output_register,
153                            None => bail!("Expected a register to be paired with a record output"),
154                        };
155
156                        // Construct the (console) output index as a field element.
157                        let index = Field::from_u64(output_register.locator());
158                        // Compute the encryption randomizer as `HashToScalar(tvk || index)`.
159                        let randomizer = N::hash_to_scalar_psd2(&[*tvk, index])?;
160
161                        // Encrypt the record, using the randomizer.
162                        let (encrypted_record, record_view_key) = record.encrypt_symmetric(randomizer)?;
163
164                        // Compute the record commitment.
165                        let commitment = record.to_commitment(program_id, record_name, &record_view_key)?;
166
167                        // Compute the record checksum, as the hash of the encrypted record.
168                        let checksum = N::hash_bhp1024(&encrypted_record.to_bits_le())?;
169
170                        // Prepare a randomizer for the sender ciphertext.
171                        let randomizer = N::hash_psd4(&[N::encryption_domain(), record_view_key, Field::one()])?;
172                        // Encrypt the signer address using the randomizer.
173                        let sender_ciphertext = (**signer).to_x_coordinate() + randomizer;
174
175                        // Return the output ID.
176                        Ok(OutputID::Record(commitment, checksum, sender_ciphertext))
177                    }
178                    // For a locator output, compute the hash (using `tvk`) of the output.
179                    ValueType::ExternalRecord(..) => {
180                        // Ensure the output is a record.
181                        ensure!(matches!(output, Value::Record(..)), "Expected a record output");
182
183                        // Construct the (console) output index as a field element.
184                        let index = Field::from_u16(
185                            u16::try_from(num_inputs + index).or_halt_with::<N>("Output index exceeds u16"),
186                        );
187                        // Construct the preimage as `(function ID || output || tvk || index)`.
188                        let mut preimage = Vec::new();
189                        preimage.push(function_id);
190                        preimage.extend(output.to_fields()?);
191                        preimage.push(*tvk);
192                        preimage.push(index);
193                        // Hash the output to a field element.
194                        let output_hash = N::hash_psd8(&preimage)?;
195
196                        // Return the output ID.
197                        Ok(OutputID::ExternalRecord(output_hash))
198                    }
199                    // For a future output, compute the hash (using `tcm`) of the output.
200                    ValueType::Future(..) => {
201                        // Ensure the output is a future.
202                        ensure!(matches!(output, Value::Future(..)), "Expected a future output");
203
204                        // Construct the (console) output index as a field element.
205                        let index = Field::from_u16(
206                            u16::try_from(num_inputs + index).or_halt_with::<N>("Output index exceeds u16"),
207                        );
208                        // Construct the preimage as `(function ID || output || tcm || index)`.
209                        let mut preimage = Vec::new();
210                        preimage.push(function_id);
211                        preimage.extend(output.to_fields()?);
212                        preimage.push(*tcm);
213                        preimage.push(index);
214                        // Hash the output to a field element.
215                        let output_hash = N::hash_psd8(&preimage)?;
216
217                        // Return the output ID.
218                        Ok(OutputID::Future(output_hash))
219                    }
220                }
221            })
222            .collect::<Result<Vec<_>>>()?;
223
224        Ok(Self { output_ids, outputs })
225    }
226
227    /// Returns the output ID for the transition.
228    pub fn output_ids(&self) -> &[OutputID<N>] {
229        &self.output_ids
230    }
231
232    /// Returns the function outputs.
233    pub fn outputs(&self) -> &[Value<N>] {
234        &self.outputs
235    }
236}