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 }