mod.rs
1 // Copyright (c) 2019-2025 Alpha-Delta Network Inc. 2 // This file is part of the alphavm 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 alphavm_console_network::Network; 18 use alphavm_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 }