/ console / program / src / response / mod.rs
mod.rs
  1  // Copyright (c) 2025-2026 ACDC Network
  2  // This file is part of the alphavm library.
  3  //
  4  // Alpha Chain | Delta Chain Protocol
  5  // International Monetary Graphite.
  6  //
  7  // Derived from Aleo (https://aleo.org) and ProvableHQ (https://provable.com).
  8  // They built world-class ZK infrastructure. We installed the EASY button.
  9  // Their cryptography: elegant. Our modifications: bureaucracy-compatible.
 10  // Original brilliance: theirs. Robert's Rules: ours. Bugs: definitely ours.
 11  //
 12  // Original Aleo/ProvableHQ code subject to Apache 2.0 https://www.apache.org/licenses/LICENSE-2.0
 13  // All modifications and new work: CC0 1.0 Universal Public Domain Dedication.
 14  // No rights reserved. No permission required. No warranty. No refunds.
 15  //
 16  // https://creativecommons.org/publicdomain/zero/1.0/
 17  // SPDX-License-Identifier: CC0-1.0
 18  
 19  use crate::{compute_function_id, Identifier, ProgramID, Register, Value, ValueType};
 20  use alphavm_console_network::Network;
 21  use alphavm_console_types::prelude::*;
 22  
 23  #[derive(Clone, Debug, PartialEq, Eq)]
 24  pub enum OutputID<N: Network> {
 25      /// The hash of the constant output.
 26      Constant(Field<N>),
 27      /// The hash of the public output.
 28      Public(Field<N>),
 29      /// The ciphertext hash of the private output.
 30      Private(Field<N>),
 31      /// The `(commitment, checksum, sender_ciphertext)` tuple of the record output.
 32      Record(Field<N>, Field<N>, Field<N>),
 33      /// The hash of the external record's (function_id, record, tvk, output index).
 34      ExternalRecord(Field<N>),
 35      /// The hash of the future output.
 36      Future(Field<N>),
 37  }
 38  
 39  #[derive(Clone, Debug, PartialEq, Eq)]
 40  pub struct Response<N: Network> {
 41      /// The output ID for the transition.
 42      output_ids: Vec<OutputID<N>>,
 43      /// The function outputs.
 44      outputs: Vec<Value<N>>,
 45  }
 46  
 47  impl<N: Network> From<(Vec<OutputID<N>>, Vec<Value<N>>)> for Response<N> {
 48      /// Note: This method is used to eject from a circuit.
 49      fn from((output_ids, outputs): (Vec<OutputID<N>>, Vec<Value<N>>)) -> Self {
 50          Self { output_ids, outputs }
 51      }
 52  }
 53  
 54  impl<N: Network> Response<N> {
 55      /// Initializes a new response.
 56      pub fn new(
 57          signer: &Address<N>,
 58          network_id: &U16<N>,
 59          program_id: &ProgramID<N>,
 60          function_name: &Identifier<N>,
 61          num_inputs: usize,
 62          tvk: &Field<N>,
 63          tcm: &Field<N>,
 64          outputs: Vec<Value<N>>,
 65          output_types: &[ValueType<N>],
 66          output_operands: &[Option<Register<N>>],
 67      ) -> Result<Self> {
 68          // Compute the function ID.
 69          let function_id = compute_function_id(network_id, program_id, function_name)?;
 70  
 71          // Compute the output IDs.
 72          let output_ids = outputs
 73              .iter()
 74              .zip_eq(output_types)
 75              .zip_eq(output_operands)
 76              .enumerate()
 77              .map(|(index, ((output, output_type), output_register))| {
 78                  match output_type {
 79                      // For a constant output, compute the hash (using `tcm`) of the output.
 80                      ValueType::Constant(..) => {
 81                          // Ensure the output is a plaintext.
 82                          ensure!(matches!(output, Value::Plaintext(..)), "Expected a plaintext output");
 83  
 84                          // Construct the (console) output index as a field element.
 85                          let index = Field::from_u16(
 86                              u16::try_from(num_inputs + index).or_halt_with::<N>("Output index exceeds u16"),
 87                          );
 88                          // Construct the preimage as `(function ID || output || tcm || index)`.
 89                          let mut preimage = Vec::new();
 90                          preimage.push(function_id);
 91                          preimage.extend(output.to_fields()?);
 92                          preimage.push(*tcm);
 93                          preimage.push(index);
 94                          // Hash the output to a field element.
 95                          let output_hash = N::hash_psd8(&preimage)?;
 96  
 97                          // Return the output ID.
 98                          Ok(OutputID::Constant(output_hash))
 99                      }
100                      // For a public output, compute the hash (using `tcm`) of the output.
101                      ValueType::Public(..) => {
102                          // Ensure the output is a plaintext.
103                          ensure!(matches!(output, Value::Plaintext(..)), "Expected a plaintext output");
104  
105                          // Construct the (console) output index as a field element.
106                          let index = Field::from_u16(
107                              u16::try_from(num_inputs + index).or_halt_with::<N>("Output index exceeds u16"),
108                          );
109                          // Construct the preimage as `(function ID || output || tcm || index)`.
110                          let mut preimage = Vec::new();
111                          preimage.push(function_id);
112                          preimage.extend(output.to_fields()?);
113                          preimage.push(*tcm);
114                          preimage.push(index);
115                          // Hash the output to a field element.
116                          let output_hash = N::hash_psd8(&preimage)?;
117  
118                          // Return the output ID.
119                          Ok(OutputID::Public(output_hash))
120                      }
121                      // For a private output, compute the ciphertext (using `tvk`) and hash the ciphertext.
122                      ValueType::Private(..) => {
123                          // Ensure the output is a plaintext.
124                          ensure!(matches!(output, Value::Plaintext(..)), "Expected a plaintext output");
125                          // Construct the (console) output index as a field element.
126                          let index = Field::from_u16(
127                              u16::try_from(num_inputs + index).or_halt_with::<N>("Output index exceeds u16"),
128                          );
129                          // Compute the output view key as `Hash(function ID || tvk || index)`.
130                          let output_view_key = N::hash_psd4(&[function_id, *tvk, index])?;
131                          // Compute the ciphertext.
132                          let ciphertext = match &output {
133                              Value::Plaintext(plaintext) => plaintext.encrypt_symmetric(output_view_key)?,
134                              // Ensure the output is a plaintext.
135                              Value::Record(..) => bail!("Expected a plaintext output, found a record output"),
136                              Value::Future(..) => bail!("Expected a plaintext output, found a future output"),
137                          };
138                          // Hash the ciphertext to a field element.
139                          let output_hash = N::hash_psd8(&ciphertext.to_fields()?)?;
140                          // Return the output ID.
141                          Ok(OutputID::Private(output_hash))
142                      }
143                      // For a record output, compute the record commitment, and encrypt the record (using `tvk`).
144                      ValueType::Record(record_name) => {
145                          // Retrieve the record.
146                          let record = match &output {
147                              Value::Record(record) => record,
148                              // Ensure the input is a record.
149                              Value::Plaintext(..) => bail!("Expected a record output, found a plaintext output"),
150                              Value::Future(..) => bail!("Expected a record output, found a future output"),
151                          };
152  
153                          // Retrieve the output register.
154                          let output_register = match output_register {
155                              Some(output_register) => output_register,
156                              None => bail!("Expected a register to be paired with a record output"),
157                          };
158  
159                          // Construct the (console) output index as a field element.
160                          let index = Field::from_u64(output_register.locator());
161                          // Compute the encryption randomizer as `HashToScalar(tvk || index)`.
162                          let randomizer = N::hash_to_scalar_psd2(&[*tvk, index])?;
163  
164                          // Encrypt the record, using the randomizer.
165                          let (encrypted_record, record_view_key) = record.encrypt_symmetric(randomizer)?;
166  
167                          // Compute the record commitment.
168                          let commitment = record.to_commitment(program_id, record_name, &record_view_key)?;
169  
170                          // Compute the record checksum, as the hash of the encrypted record.
171                          let checksum = N::hash_bhp1024(&encrypted_record.to_bits_le())?;
172  
173                          // Prepare a randomizer for the sender ciphertext.
174                          let randomizer = N::hash_psd4(&[N::encryption_domain(), record_view_key, Field::one()])?;
175                          // Encrypt the signer address using the randomizer.
176                          let sender_ciphertext = (**signer).to_x_coordinate() + randomizer;
177  
178                          // Return the output ID.
179                          Ok(OutputID::Record(commitment, checksum, sender_ciphertext))
180                      }
181                      // For a locator output, compute the hash (using `tvk`) of the output.
182                      ValueType::ExternalRecord(..) => {
183                          // Ensure the output is a record.
184                          ensure!(matches!(output, Value::Record(..)), "Expected a record output");
185  
186                          // Construct the (console) output index as a field element.
187                          let index = Field::from_u16(
188                              u16::try_from(num_inputs + index).or_halt_with::<N>("Output index exceeds u16"),
189                          );
190                          // Construct the preimage as `(function ID || output || tvk || index)`.
191                          let mut preimage = Vec::new();
192                          preimage.push(function_id);
193                          preimage.extend(output.to_fields()?);
194                          preimage.push(*tvk);
195                          preimage.push(index);
196                          // Hash the output to a field element.
197                          let output_hash = N::hash_psd8(&preimage)?;
198  
199                          // Return the output ID.
200                          Ok(OutputID::ExternalRecord(output_hash))
201                      }
202                      // For a future output, compute the hash (using `tcm`) of the output.
203                      ValueType::Future(..) => {
204                          // Ensure the output is a future.
205                          ensure!(matches!(output, Value::Future(..)), "Expected a future output");
206  
207                          // Construct the (console) output index as a field element.
208                          let index = Field::from_u16(
209                              u16::try_from(num_inputs + index).or_halt_with::<N>("Output index exceeds u16"),
210                          );
211                          // Construct the preimage as `(function ID || output || tcm || index)`.
212                          let mut preimage = Vec::new();
213                          preimage.push(function_id);
214                          preimage.extend(output.to_fields()?);
215                          preimage.push(*tcm);
216                          preimage.push(index);
217                          // Hash the output to a field element.
218                          let output_hash = N::hash_psd8(&preimage)?;
219  
220                          // Return the output ID.
221                          Ok(OutputID::Future(output_hash))
222                      }
223                  }
224              })
225              .collect::<Result<Vec<_>>>()?;
226  
227          Ok(Self { output_ids, outputs })
228      }
229  
230      /// Returns the output ID for the transition.
231      pub fn output_ids(&self) -> &[OutputID<N>] {
232          &self.output_ids
233      }
234  
235      /// Returns the function outputs.
236      pub fn outputs(&self) -> &[Value<N>] {
237          &self.outputs
238      }
239  }