/ console / program / src / response / mod.rs
mod.rs
  1  // Copyright (c) 2019-2025 Alpha-Delta Network Inc.
  2  // This file is part of the deltavm 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  use crate::{Identifier, ProgramID, Register, Value, ValueType, compute_function_id};
 17  use deltavm_console_network::Network;
 18  use deltavm_console_types::prelude::*;
 19  
 20  #[derive(Clone, Debug, PartialEq, Eq)]
 21  pub 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)]
 37  pub 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  
 44  impl<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  
 51  impl<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  }