diff --git a/acir/src/circuit/mod.rs b/acir/src/circuit/mod.rs index 28c32ab1..c4e3ac0f 100644 --- a/acir/src/circuit/mod.rs +++ b/acir/src/circuit/mod.rs @@ -7,7 +7,7 @@ use crate::native_types::Witness; pub use opcodes::Opcode; use thiserror::Error; -use std::{io::prelude::*, num::ParseIntError, str::FromStr}; +use std::{collections::BTreeMap, io::prelude::*, num::ParseIntError, str::FromStr}; use flate2::Compression; @@ -30,6 +30,10 @@ pub struct Circuit { pub public_parameters: PublicInputs, /// The set of public inputs calculated within the circuit. pub return_values: PublicInputs, + /// Maps opcode locations to failed assertion messages. + /// These messages are embedded in the circuit to provide useful feedback to users + /// when a constraint in the circuit is not satisfied. + pub assert_messages: BTreeMap, } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)] @@ -195,7 +199,7 @@ impl PublicInputs { #[cfg(test)] mod tests { - use std::collections::BTreeSet; + use std::collections::{BTreeMap, BTreeSet}; use super::{ opcodes::{BlackBoxFuncCall, FunctionInput}, @@ -225,6 +229,7 @@ mod tests { private_parameters: BTreeSet::new(), public_parameters: PublicInputs(BTreeSet::from_iter(vec![Witness(2), Witness(12)])), return_values: PublicInputs(BTreeSet::from_iter(vec![Witness(4), Witness(12)])), + assert_messages: BTreeMap::new(), }; fn read_write(circuit: Circuit) -> (Circuit, Circuit) { @@ -254,6 +259,7 @@ mod tests { private_parameters: BTreeSet::new(), public_parameters: PublicInputs(BTreeSet::from_iter(vec![Witness(2)])), return_values: PublicInputs(BTreeSet::from_iter(vec![Witness(2)])), + assert_messages: BTreeMap::new(), }; let json = serde_json::to_string_pretty(&circuit).unwrap(); diff --git a/acir/src/circuit/opcodes.rs b/acir/src/circuit/opcodes.rs index 9f3da3a5..dc7f73b4 100644 --- a/acir/src/circuit/opcodes.rs +++ b/acir/src/circuit/opcodes.rs @@ -24,6 +24,8 @@ pub enum Opcode { MemoryOp { block_id: BlockId, op: MemOp, + /// Predicate of the memory operation - indicates if it should be skipped + predicate: Option, }, MemoryInit { block_id: BlockId, @@ -146,8 +148,12 @@ impl std::fmt::Display for Opcode { writeln!(f, "outputs: {:?}", brillig.outputs)?; writeln!(f, "{:?}", brillig.bytecode) } - Opcode::MemoryOp { block_id, op } => { + Opcode::MemoryOp { block_id, op, predicate } => { write!(f, "MEM ")?; + if let Some(pred) = predicate { + writeln!(f, "PREDICATE = {pred}")?; + } + let is_read = op.operation.is_zero(); let is_write = op.operation == Expression::one(); if is_read { diff --git a/acir/tests/test_program_serialization.rs b/acir/tests/test_program_serialization.rs index a90867f2..750483df 100644 --- a/acir/tests/test_program_serialization.rs +++ b/acir/tests/test_program_serialization.rs @@ -14,7 +14,7 @@ use std::collections::BTreeSet; use acir::{ circuit::{ brillig::{Brillig, BrilligInputs, BrilligOutputs}, - opcodes::{BlackBoxFuncCall, FunctionInput}, + opcodes::{BlackBoxFuncCall, BlockId, FunctionInput, MemOp}, Circuit, Opcode, PublicInputs, }, native_types::{Expression, Witness}, @@ -38,8 +38,8 @@ fn addition_circuit() { current_witness_index: 4, opcodes: vec![addition], private_parameters: BTreeSet::from([Witness(1), Witness(2)]), - public_parameters: PublicInputs::default(), return_values: PublicInputs([Witness(3)].into()), + ..Circuit::default() }; let mut bytes = Vec::new(); @@ -47,11 +47,11 @@ fn addition_circuit() { let expected_serialization: Vec = vec![ 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 144, 187, 13, 192, 32, 12, 68, 249, 100, 32, 27, - 219, 96, 119, 89, 37, 40, 176, 255, 8, 81, 36, 23, 72, 41, 195, 53, 215, 61, 221, 189, 35, - 132, 16, 195, 55, 217, 251, 244, 134, 127, 193, 184, 145, 149, 22, 22, 65, 101, 30, 173, - 12, 36, 188, 160, 88, 87, 1, 150, 94, 21, 21, 69, 229, 46, 74, 52, 148, 181, 89, 183, 6, - 134, 76, 3, 167, 24, 77, 135, 229, 125, 187, 32, 57, 231, 253, 154, 22, 151, 113, 113, 250, - 0, 123, 50, 20, 220, 112, 1, 0, 0, + 219, 96, 119, 89, 37, 40, 176, 255, 8, 17, 18, 5, 74, 202, 240, 154, 235, 158, 238, 238, + 112, 206, 121, 247, 37, 206, 60, 103, 194, 63, 208, 111, 116, 133, 197, 69, 144, 153, 91, + 73, 13, 9, 47, 72, 86, 85, 128, 165, 102, 69, 69, 81, 185, 147, 18, 53, 101, 45, 86, 173, + 128, 33, 83, 195, 46, 70, 125, 202, 226, 190, 94, 16, 166, 103, 108, 13, 203, 151, 254, + 245, 233, 224, 1, 1, 52, 166, 127, 120, 1, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -68,17 +68,17 @@ fn fixed_base_scalar_mul_circuit() { current_witness_index: 4, opcodes: vec![fixed_base_scalar_mul], private_parameters: BTreeSet::from([Witness(1)]), - public_parameters: PublicInputs::default(), return_values: PublicInputs(BTreeSet::from_iter(vec![Witness(2), Witness(3)])), + ..Circuit::default() }; let mut bytes = Vec::new(); circuit.write(&mut bytes).unwrap(); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 138, 201, 9, 0, 0, 8, 195, 234, 241, 114, 255, 121, - 69, 69, 5, 49, 16, 242, 104, 21, 0, 161, 169, 218, 212, 83, 78, 229, 237, 11, 159, 214, 39, - 0, 55, 132, 28, 78, 72, 0, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 137, 91, 10, 0, 0, 4, 4, 215, 227, 203, 253, 207, + 43, 132, 146, 169, 105, 106, 87, 1, 16, 154, 170, 77, 61, 229, 84, 222, 191, 240, 169, 156, + 61, 0, 36, 111, 164, 5, 80, 0, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -96,17 +96,17 @@ fn pedersen_circuit() { current_witness_index: 4, opcodes: vec![pedersen], private_parameters: BTreeSet::from([Witness(1)]), - public_parameters: PublicInputs::default(), return_values: PublicInputs(BTreeSet::from_iter(vec![Witness(2), Witness(3)])), + ..Circuit::default() }; let mut bytes = Vec::new(); circuit.write(&mut bytes).unwrap(); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 138, 65, 10, 0, 64, 8, 2, 103, 183, 232, 255, 47, - 142, 138, 58, 68, 130, 168, 140, 10, 60, 90, 149, 118, 182, 79, 255, 105, 57, 140, 197, - 246, 39, 0, 246, 174, 71, 87, 84, 0, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 138, 9, 10, 0, 64, 8, 2, 103, 15, 250, 255, 139, + 163, 162, 130, 72, 16, 149, 241, 3, 135, 84, 164, 172, 173, 213, 175, 251, 45, 198, 96, + 243, 211, 50, 152, 67, 220, 211, 92, 0, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -138,30 +138,30 @@ fn schnorr_verify_circuit() { current_witness_index: 100, opcodes: vec![schnorr], private_parameters: BTreeSet::from_iter((1..=last_input).map(Witness)), - public_parameters: PublicInputs::default(), return_values: PublicInputs(BTreeSet::from([output])), + ..Circuit::default() }; let mut bytes = Vec::new(); circuit.write(&mut bytes).unwrap(); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 210, 233, 50, 66, 1, 24, 199, 225, 99, 223, 247, - 125, 15, 73, 146, 36, 73, 146, 36, 73, 194, 93, 184, 255, 75, 48, 122, 167, 167, 25, 103, - 230, 204, 83, 211, 151, 230, 253, 255, 126, 146, 36, 25, 73, 6, 79, 56, 193, 223, 254, 59, - 202, 166, 223, 199, 250, 239, 116, 255, 29, 231, 4, 39, 57, 197, 225, 59, 195, 89, 206, - 113, 158, 11, 92, 228, 18, 151, 185, 194, 85, 174, 113, 157, 27, 220, 228, 22, 183, 185, - 195, 93, 238, 113, 159, 7, 60, 228, 17, 83, 60, 230, 9, 79, 153, 230, 25, 51, 60, 103, 150, - 23, 204, 241, 146, 121, 94, 177, 192, 107, 22, 121, 195, 18, 111, 89, 230, 29, 43, 188, - 103, 149, 15, 172, 241, 145, 117, 62, 177, 193, 103, 54, 249, 194, 214, 191, 29, 227, 121, - 245, 189, 205, 55, 118, 248, 206, 46, 63, 216, 227, 39, 191, 248, 237, 115, 60, 209, 94, - 116, 23, 173, 69, 103, 209, 88, 244, 53, 108, 107, 198, 255, 136, 150, 162, 163, 104, 40, - 250, 137, 118, 162, 155, 104, 38, 122, 137, 86, 162, 147, 104, 36, 250, 136, 54, 162, 139, - 104, 34, 122, 136, 22, 162, 131, 104, 32, 246, 143, 237, 83, 201, 96, 243, 216, 59, 182, - 78, 219, 56, 99, 219, 172, 77, 115, 182, 204, 219, 176, 96, 187, 162, 205, 74, 182, 42, - 219, 168, 98, 155, 170, 77, 106, 182, 168, 219, 160, 225, 246, 77, 55, 111, 185, 113, 219, - 109, 59, 110, 218, 117, 203, 158, 27, 14, 111, 54, 188, 91, 226, 150, 127, 214, 93, 14, - 165, 212, 3, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 210, 87, 78, 2, 1, 20, 134, 209, 177, 247, 222, 123, + 71, 68, 68, 68, 68, 68, 68, 68, 68, 68, 221, 133, 251, 95, 130, 145, 27, 206, 36, 78, 50, + 57, 16, 94, 200, 253, 191, 159, 36, 73, 134, 146, 193, 19, 142, 241, 183, 255, 14, 179, + 233, 247, 145, 254, 59, 217, 127, 71, 57, 198, 113, 78, 48, 125, 167, 56, 205, 25, 206, + 114, 142, 243, 92, 224, 34, 151, 184, 204, 21, 174, 114, 141, 235, 220, 224, 38, 183, 184, + 205, 29, 238, 114, 143, 251, 60, 224, 33, 143, 120, 204, 19, 158, 242, 140, 25, 158, 51, + 203, 11, 230, 120, 201, 60, 175, 88, 224, 53, 139, 188, 97, 137, 183, 44, 243, 142, 21, + 222, 179, 202, 7, 214, 248, 200, 58, 159, 216, 224, 51, 155, 124, 97, 235, 223, 142, 241, + 188, 250, 222, 230, 27, 59, 124, 103, 151, 31, 236, 241, 147, 95, 252, 246, 57, 158, 104, + 47, 186, 139, 214, 162, 179, 104, 44, 250, 74, 219, 154, 242, 63, 162, 165, 232, 40, 26, + 138, 126, 162, 157, 232, 38, 154, 137, 94, 162, 149, 232, 36, 26, 137, 62, 162, 141, 232, + 34, 154, 136, 30, 162, 133, 232, 32, 26, 136, 253, 99, 251, 195, 100, 176, 121, 236, 29, + 91, 159, 218, 56, 99, 219, 172, 77, 115, 182, 204, 219, 176, 96, 187, 162, 205, 74, 182, + 42, 219, 168, 98, 155, 170, 77, 106, 182, 168, 219, 160, 225, 246, 77, 55, 111, 185, 113, + 219, 109, 59, 110, 218, 117, 203, 158, 27, 166, 55, 75, 239, 150, 184, 101, 250, 252, 1, + 19, 89, 159, 101, 220, 3, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -195,8 +195,7 @@ fn simple_brillig_foreign_call() { current_witness_index: 8, opcodes, private_parameters: BTreeSet::from([Witness(1), Witness(2)]), - public_parameters: PublicInputs::default(), - return_values: PublicInputs::default(), + ..Circuit::default() }; let mut bytes = Vec::new(); @@ -273,8 +272,7 @@ fn complex_brillig_foreign_call() { current_witness_index: 8, opcodes, private_parameters: BTreeSet::from([Witness(1), Witness(2), Witness(3)]), - public_parameters: PublicInputs::default(), - return_values: PublicInputs::default(), + ..Circuit::default() }; let mut bytes = Vec::new(); @@ -282,12 +280,49 @@ fn complex_brillig_foreign_call() { let expected_serialization: Vec = vec![ 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 83, 219, 10, 128, 48, 8, 245, 210, 101, 159, 179, - 254, 160, 127, 137, 222, 138, 122, 236, 243, 91, 228, 64, 44, 232, 33, 7, 117, 64, 156, - 206, 201, 193, 51, 3, 0, 32, 156, 224, 100, 36, 103, 148, 88, 35, 215, 245, 226, 227, 59, - 116, 232, 215, 43, 150, 226, 72, 63, 224, 200, 5, 56, 230, 255, 240, 81, 189, 61, 117, 113, - 157, 31, 223, 236, 79, 149, 172, 78, 214, 72, 220, 138, 15, 106, 214, 168, 114, 249, 126, - 88, 230, 117, 26, 55, 54, 37, 90, 26, 155, 39, 227, 31, 223, 232, 230, 4, 215, 157, 63, - 176, 3, 89, 64, 134, 157, 36, 4, 0, 0, + 254, 160, 127, 137, 222, 138, 122, 236, 243, 27, 228, 64, 44, 232, 33, 7, 237, 128, 56, + 157, 147, 131, 103, 6, 0, 64, 184, 192, 201, 72, 206, 40, 177, 70, 174, 27, 197, 199, 111, + 24, 208, 175, 87, 44, 197, 145, 42, 224, 200, 5, 56, 230, 255, 240, 83, 189, 61, 117, 113, + 157, 31, 63, 236, 79, 147, 172, 77, 214, 73, 220, 139, 15, 106, 214, 168, 114, 249, 126, + 218, 214, 125, 153, 15, 54, 37, 90, 26, 155, 39, 227, 95, 223, 232, 230, 4, 247, 157, 215, + 56, 1, 153, 86, 63, 138, 44, 4, 0, 0, + ]; + + assert_eq!(bytes, expected_serialization) +} + +#[test] +fn memory_op_circuit() { + let init = vec![Witness(1), Witness(2)]; + + let memory_init = Opcode::MemoryInit { block_id: BlockId(0), init }; + let write = Opcode::MemoryOp { + block_id: BlockId(0), + op: MemOp::write_to_mem_index(FieldElement::from(1u128).into(), Witness(3).into()), + predicate: None, + }; + let read = Opcode::MemoryOp { + block_id: BlockId(0), + op: MemOp::read_at_mem_index(FieldElement::one().into(), Witness(4)), + predicate: None, + }; + + let circuit = Circuit { + current_witness_index: 5, + opcodes: vec![memory_init, write, read], + private_parameters: BTreeSet::from([Witness(1), Witness(2), Witness(3)]), + return_values: PublicInputs([Witness(4)].into()), + ..Circuit::default() + }; + let mut bytes = Vec::new(); + circuit.write(&mut bytes).unwrap(); + + let expected_serialization: Vec = vec![ + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 146, 49, 14, 0, 32, 8, 3, 139, 192, 127, 240, 7, + 254, 255, 85, 198, 136, 9, 131, 155, 48, 216, 165, 76, 77, 57, 80, 0, 140, 45, 117, 111, + 238, 228, 179, 224, 174, 225, 110, 111, 234, 213, 185, 148, 156, 203, 121, 89, 86, 13, 215, + 126, 131, 43, 153, 187, 115, 40, 185, 62, 153, 3, 136, 83, 60, 30, 96, 2, 12, 235, 225, + 124, 14, 3, 0, 0, ]; assert_eq!(bytes, expected_serialization) diff --git a/acvm/src/compiler/mod.rs b/acvm/src/compiler/mod.rs index d4cf3ae7..001b4904 100644 --- a/acvm/src/compiler/mod.rs +++ b/acvm/src/compiler/mod.rs @@ -1,3 +1,5 @@ +use std::collections::BTreeMap; + use acir::{ circuit::{ brillig::BrilligOutputs, directives::Directive, opcodes::UnsupportedMemoryOpcode, Circuit, @@ -58,6 +60,19 @@ impl AcirTransformationMap { } } +fn transform_assert_messages( + assert_messages: BTreeMap, + map: &AcirTransformationMap, +) -> BTreeMap { + assert_messages + .into_iter() + .flat_map(|(location, message)| { + let new_locations = map.new_locations(location); + new_locations.into_iter().map(move |new_location| (new_location, message.clone())) + }) + .collect() +} + /// Applies [`ProofSystemCompiler`][crate::ProofSystemCompiler] specific optimizations to a [`Circuit`]. pub fn compile( acir: Circuit, @@ -90,12 +105,14 @@ pub fn compile( // Range optimization pass let range_optimizer = RangeOptimizer::new(acir); - let (acir, acir_opcode_positions) = + let (mut acir, acir_opcode_positions) = range_optimizer.replace_redundant_ranges(acir_opcode_positions); let mut transformer = match &np_language { crate::Language::R1CS => { let transformation_map = AcirTransformationMap { acir_opcode_positions }; + acir.assert_messages = + transform_assert_messages(acir.assert_messages, &transformation_map); let transformer = R1CSTransformer::new(acir); return Ok((transformer.transform(), transformation_map)); } @@ -248,6 +265,9 @@ pub fn compile( let current_witness_index = next_witness_index - 1; + let transformation_map = + AcirTransformationMap { acir_opcode_positions: new_acir_opcode_positions }; + let acir = Circuit { current_witness_index, opcodes: transformed_opcodes, @@ -255,10 +275,8 @@ pub fn compile( private_parameters: acir.private_parameters, public_parameters: acir.public_parameters, return_values: acir.return_values, + assert_messages: transform_assert_messages(acir.assert_messages, &transformation_map), }; - let transformation_map = - AcirTransformationMap { acir_opcode_positions: new_acir_opcode_positions }; - Ok((acir, transformation_map)) } diff --git a/acvm/src/compiler/optimizers/redundant_range.rs b/acvm/src/compiler/optimizers/redundant_range.rs index 8cabed75..95bd8c26 100644 --- a/acvm/src/compiler/optimizers/redundant_range.rs +++ b/acvm/src/compiler/optimizers/redundant_range.rs @@ -109,9 +109,7 @@ impl RangeOptimizer { Circuit { current_witness_index: self.circuit.current_witness_index, opcodes: optimized_opcodes, - private_parameters: self.circuit.private_parameters, - public_parameters: self.circuit.public_parameters, - return_values: self.circuit.return_values, + ..self.circuit }, new_order_list, ) @@ -137,7 +135,7 @@ fn extract_range_opcode(opcode: &Opcode) -> Option<(Witness, u32)> { #[cfg(test)] mod tests { - use std::collections::BTreeSet; + use std::collections::{BTreeMap, BTreeSet}; use crate::compiler::optimizers::redundant_range::{extract_range_opcode, RangeOptimizer}; use acir::{ @@ -166,6 +164,7 @@ mod tests { private_parameters: BTreeSet::new(), public_parameters: PublicInputs::default(), return_values: PublicInputs::default(), + assert_messages: BTreeMap::new(), } } diff --git a/acvm/src/compiler/transformers/fallback.rs b/acvm/src/compiler/transformers/fallback.rs index 0af6959c..e96fa728 100644 --- a/acvm/src/compiler/transformers/fallback.rs +++ b/acvm/src/compiler/transformers/fallback.rs @@ -60,13 +60,7 @@ impl FallbackTransformer { } Ok(( - Circuit { - current_witness_index: witness_idx, - opcodes: acir_supported_opcodes, - private_parameters: acir.private_parameters, - public_parameters: acir.public_parameters, - return_values: acir.return_values, - }, + Circuit { current_witness_index: witness_idx, opcodes: acir_supported_opcodes, ..acir }, new_opcode_positions, )) } diff --git a/acvm/src/lib.rs b/acvm/src/lib.rs index 3cfb535c..08e6479a 100644 --- a/acvm/src/lib.rs +++ b/acvm/src/lib.rs @@ -37,12 +37,7 @@ pub trait SmartContract { // TODO: Allow a backend to support multiple smart contract platforms /// Returns an Ethereum smart contract to verify proofs against a given common reference string and verification key. - fn eth_contract_from_vk( - &self, - common_reference_string: &[u8], - circuit: &Circuit, - verification_key: &[u8], - ) -> Result; + fn eth_contract(&self, circuit: &Circuit) -> Result; } pub trait ProofSystemCompiler { @@ -61,33 +56,29 @@ pub trait ProofSystemCompiler { /// Returns the number of gates in a circuit fn get_exact_circuit_size(&self, circuit: &Circuit) -> Result; - /// Creates a Proof given the circuit description, the initial witness values, and the proving key + /// Creates a Proof given the [`Circuit`] and the [witness values][`WitnessMap`] /// It is important to note that the intermediate witnesses for black box functions will not generated /// This is the responsibility of the proof system. /// /// The `is_recursive` flag represents whether one wants to create proofs that are to be natively verified. /// A proof system may use a certain hash type for the Fiat-Shamir normally that is not hash friendly (such as keccak to enable Solidity verification), /// but may want to use a snark-friendly hash function when performing native verification. - fn prove_with_pk( + fn prove( &self, - common_reference_string: &[u8], circuit: &Circuit, witness_values: WitnessMap, - proving_key: &[u8], is_recursive: bool, ) -> Result, Self::Error>; - /// Verifies a Proof, given the circuit description, the circuit's public inputs, and the verification key + /// Verifies a Proof, given the [`Circuit`] and [public inputs][`WitnessMap`] /// /// The `is_recursive` flag represents whether one wants to verify proofs that are to be natively verified. /// The flag must match the `is_recursive` flag used to generate the proof passed into this method, otherwise verification will return false. - fn verify_with_vk( + fn verify( &self, - common_reference_string: &[u8], proof: &[u8], public_inputs: WitnessMap, circuit: &Circuit, - verification_key: &[u8], is_recursive: bool, ) -> Result; @@ -103,7 +94,6 @@ pub trait ProofSystemCompiler { /// This method is exposed to enable backends to integrate a native recursion format and optimize their recursive circuits. fn vk_as_fields( &self, - common_reference_string: &[u8], verification_key: &[u8], ) -> Result<(Vec, FieldElement), Self::Error>; } diff --git a/acvm/src/pwg/memory_op.rs b/acvm/src/pwg/memory_op.rs index fadc1bd6..7def24c0 100644 --- a/acvm/src/pwg/memory_op.rs +++ b/acvm/src/pwg/memory_op.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use acir::{ circuit::opcodes::MemOp, - native_types::{Witness, WitnessMap}, + native_types::{Expression, Witness, WitnessMap}, FieldElement, }; @@ -63,6 +63,7 @@ impl MemoryOpSolver { &mut self, op: &MemOp, initial_witness: &mut WitnessMap, + predicate: &Option, ) -> Result<(), OpcodeResolutionError> { let operation = get_value(&op.operation, initial_witness)?; @@ -79,6 +80,12 @@ impl MemoryOpSolver { // `operation == 0` implies a read operation. (`operation == 1` implies write operation). let is_read_operation = operation.is_zero(); + // If the predicate is `None`, then we simply return the value 1 + let pred_value = match predicate { + Some(pred) => get_value(pred, initial_witness), + None => Ok(FieldElement::one()), + }?; + if is_read_operation { // `value_read = arr[memory_index]` // @@ -88,7 +95,13 @@ impl MemoryOpSolver { "Memory must be read into a specified witness index, encountered an Expression", ); - let value_in_array = self.read_memory_index(memory_index)?; + // A zero predicate indicates that we should skip the read operation + // and zero out the operation's output. + let value_in_array = if pred_value.is_zero() { + FieldElement::zero() + } else { + self.read_memory_index(memory_index)? + }; insert_value(&value_read_witness, value_in_array, initial_witness) } else { // `arr[memory_index] = value_write` @@ -97,9 +110,15 @@ impl MemoryOpSolver { // into the memory block. let value_write = value; - let value_to_write = get_value(&value_write, initial_witness)?; - - self.write_memory_index(memory_index, value_to_write) + // A zero predicate indicates that we should skip the write operation. + if pred_value.is_zero() { + // We only want to write to already initialized memory. + // Do nothing if the predicate is zero. + return Ok(()); + } else { + let value_to_write = get_value(&value_write, initial_witness)?; + self.write_memory_index(memory_index, value_to_write) + } } } } @@ -110,7 +129,7 @@ mod tests { use acir::{ circuit::opcodes::MemOp, - native_types::{Witness, WitnessMap}, + native_types::{Expression, Witness, WitnessMap}, FieldElement, }; @@ -135,8 +154,9 @@ mod tests { block_solver.init(&init, &initial_witness).unwrap(); for op in trace { - block_solver.solve_memory_op(&op, &mut initial_witness).unwrap(); + block_solver.solve_memory_op(&op, &mut initial_witness, &None).unwrap(); } + assert_eq!(initial_witness[&Witness(4)], FieldElement::from(2u128)); } @@ -159,9 +179,10 @@ mod tests { let mut err = None; for op in invalid_trace { if err.is_none() { - err = block_solver.solve_memory_op(&op, &mut initial_witness).err(); + err = block_solver.solve_memory_op(&op, &mut initial_witness, &None).err(); } } + assert!(matches!( err, Some(crate::pwg::OpcodeResolutionError::IndexOutOfBounds { @@ -171,4 +192,68 @@ mod tests { }) )); } + + #[test] + fn test_predicate_on_read() { + let mut initial_witness = WitnessMap::from(BTreeMap::from_iter([ + (Witness(1), FieldElement::from(1u128)), + (Witness(2), FieldElement::from(1u128)), + (Witness(3), FieldElement::from(2u128)), + ])); + + let init = vec![Witness(1), Witness(2)]; + + let invalid_trace = vec![ + MemOp::write_to_mem_index(FieldElement::from(1u128).into(), Witness(3).into()), + MemOp::read_at_mem_index(FieldElement::from(2u128).into(), Witness(4)), + ]; + let mut block_solver = MemoryOpSolver::default(); + block_solver.init(&init, &initial_witness).unwrap(); + let mut err = None; + for op in invalid_trace { + if err.is_none() { + err = block_solver + .solve_memory_op(&op, &mut initial_witness, &Some(Expression::zero())) + .err(); + } + } + + // Should have no index out of bounds error where predicate is zero + assert_eq!(err, None); + // The result of a read under a zero predicate should be zero + assert_eq!(initial_witness[&Witness(4)], FieldElement::from(0u128)); + } + + #[test] + fn test_predicate_on_write() { + let mut initial_witness = WitnessMap::from(BTreeMap::from_iter([ + (Witness(1), FieldElement::from(1u128)), + (Witness(2), FieldElement::from(1u128)), + (Witness(3), FieldElement::from(2u128)), + ])); + + let init = vec![Witness(1), Witness(2)]; + + let invalid_trace = vec![ + MemOp::write_to_mem_index(FieldElement::from(2u128).into(), Witness(3).into()), + MemOp::read_at_mem_index(FieldElement::from(0u128).into(), Witness(4).into()), + MemOp::read_at_mem_index(FieldElement::from(1u128).into(), Witness(5).into()), + ]; + let mut block_solver = MemoryOpSolver::default(); + block_solver.init(&init, &initial_witness).unwrap(); + let mut err = None; + for op in invalid_trace { + if err.is_none() { + err = block_solver + .solve_memory_op(&op, &mut initial_witness, &Some(Expression::zero())) + .err(); + } + } + + // Should have no index out of bounds error where predicate is zero + assert_eq!(err, None); + // The memory under a zero predicate should be zeroed out + assert_eq!(initial_witness[&Witness(4)], FieldElement::from(0u128)); + assert_eq!(initial_witness[&Witness(5)], FieldElement::from(0u128)); + } } diff --git a/acvm/src/pwg/mod.rs b/acvm/src/pwg/mod.rs index 350c4c92..8a39311b 100644 --- a/acvm/src/pwg/mod.rs +++ b/acvm/src/pwg/mod.rs @@ -253,9 +253,9 @@ impl<'backend, B: BlackBoxFunctionSolver> ACVM<'backend, B> { let solver = self.block_solvers.entry(*block_id).or_default(); solver.init(init, &self.witness_map) } - Opcode::MemoryOp { block_id, op } => { + Opcode::MemoryOp { block_id, op, predicate } => { let solver = self.block_solvers.entry(*block_id).or_default(); - solver.solve_memory_op(op, &mut self.witness_map) + solver.solve_memory_op(op, &mut self.witness_map, predicate) } Opcode::Brillig(brillig) => { match BrilligSolver::solve(&mut self.witness_map, brillig, self.backend) { diff --git a/acvm/tests/solver.rs b/acvm/tests/solver.rs index 788ec64a..a888a062 100644 --- a/acvm/tests/solver.rs +++ b/acvm/tests/solver.rs @@ -518,7 +518,7 @@ fn unsatisfied_opcode_resolved() { assert_eq!( solver_status, ACVMStatus::Failure(OpcodeResolutionError::UnsatisfiedConstrain { - opcode_location: ErrorLocation::Resolved(OpcodeLocation::Acir(0)) + opcode_location: ErrorLocation::Resolved(OpcodeLocation::Acir(0)), }), "The first opcode is not satisfiable, expected an error indicating this" ); @@ -603,7 +603,7 @@ fn unsatisfied_opcode_resolved_brillig() { opcode_location: ErrorLocation::Resolved(OpcodeLocation::Brillig { acir_index: 0, brillig_index: 2 - }) + }), }), "The first opcode is not satisfiable, expected an error indicating this" ); @@ -624,8 +624,11 @@ fn memory_operations() { let init = Opcode::MemoryInit { block_id, init: (1..6).map(Witness).collect() }; - let read_op = - Opcode::MemoryOp { block_id, op: MemOp::read_at_mem_index(Witness(6).into(), Witness(7)) }; + let read_op = Opcode::MemoryOp { + block_id, + op: MemOp::read_at_mem_index(Witness(6).into(), Witness(7)), + predicate: None, + }; let expression = Opcode::Arithmetic(Expression { mul_terms: Vec::new(), diff --git a/acvm/tests/stdlib.rs b/acvm/tests/stdlib.rs index 17f24938..2413be6c 100644 --- a/acvm/tests/stdlib.rs +++ b/acvm/tests/stdlib.rs @@ -4,7 +4,7 @@ use crate::solver::StubbedBackend; use acir::{ circuit::{ opcodes::{BlackBoxFuncCall, FunctionInput}, - Circuit, Opcode, PublicInputs, + Circuit, Opcode, }, native_types::{Expression, Witness}, FieldElement, @@ -285,8 +285,8 @@ macro_rules! test_hashes { current_witness_index: witness_assignments.len() as u32 + 32, opcodes, private_parameters: BTreeSet::new(), // This is not correct but is unused in this test. - public_parameters: PublicInputs(BTreeSet::new()), - return_values: PublicInputs(BTreeSet::new()) }; + ..Circuit::default() + }; let circuit = compile(circuit, Language::PLONKCSat{ width: 3 }, $opcode_support).unwrap().0; // solve witnesses @@ -341,8 +341,7 @@ proptest! { current_witness_index: witness_assignments.len() as u32 + 1, opcodes, private_parameters: BTreeSet::new(), // This is not correct but is unused in this test. - public_parameters: PublicInputs(BTreeSet::new()), - return_values: PublicInputs(BTreeSet::new()) + ..Circuit::default() }; let circuit = compile(circuit, Language::PLONKCSat{ width: 3 }, does_not_support_hash_to_field).unwrap().0; diff --git a/acvm_js/src/execute.rs b/acvm_js/src/execute.rs index f011cd84..9dda594e 100644 --- a/acvm_js/src/execute.rs +++ b/acvm_js/src/execute.rs @@ -2,7 +2,7 @@ use acvm::{ acir::circuit::Circuit, blackbox_solver::BarretenbergSolver, - pwg::{ACVMStatus, ACVM}, + pwg::{ACVMStatus, ErrorLocation, OpcodeResolutionError, ACVM}, }; use wasm_bindgen::prelude::wasm_bindgen; @@ -75,7 +75,25 @@ pub async fn execute_circuit_with_black_box_solver( ACVMStatus::InProgress => { unreachable!("Execution should not stop while in `InProgress` state.") } - ACVMStatus::Failure(error) => return Err(error.to_string().into()), + ACVMStatus::Failure(error) => { + let assert_message = match &error { + OpcodeResolutionError::UnsatisfiedConstrain { + opcode_location: ErrorLocation::Resolved(opcode_location), + } + | OpcodeResolutionError::IndexOutOfBounds { + opcode_location: ErrorLocation::Resolved(opcode_location), + .. + } => circuit.assert_messages.get(opcode_location).cloned(), + _ => None, + }; + + let error_string = match assert_message { + Some(assert_message) => format!("{}: {}", error, assert_message), + None => error.to_string(), + }; + + return Err(error_string.into()); + } ACVMStatus::RequiresForeignCall(foreign_call) => { let result = resolve_brillig(&foreign_call_handler, &foreign_call).await?; diff --git a/acvm_js/test/browser/execute_circuit.test.ts b/acvm_js/test/browser/execute_circuit.test.ts index dae83d0c..407aa830 100644 --- a/acvm_js/test/browser/execute_circuit.test.ts +++ b/acvm_js/test/browser/execute_circuit.test.ts @@ -162,6 +162,22 @@ it("successfully executes a SchnorrVerify opcode", async () => { expect(solvedWitness).to.be.deep.eq(expectedWitnessMap); }); +it("successfully executes a MemoryOp opcode", async () => { + const { bytecode, initialWitnessMap, expectedWitnessMap } = await import( + "../shared/memory_op" + ); + + const solvedWitness: WitnessMap = await executeCircuit( + bytecode, + initialWitnessMap, + () => { + throw Error("unexpected oracle"); + } + ); + + expect(solvedWitness).to.be.deep.eq(expectedWitnessMap); +}); + it("successfully executes two circuits with same backend", async function () { // chose pedersen op here because it is the one with slow initialization // that led to the decision to pull backend initialization into a separate diff --git a/acvm_js/test/node/execute_circuit.test.ts b/acvm_js/test/node/execute_circuit.test.ts index 08d49836..3b84d8d9 100644 --- a/acvm_js/test/node/execute_circuit.test.ts +++ b/acvm_js/test/node/execute_circuit.test.ts @@ -156,6 +156,22 @@ it("successfully executes a SchnorrVerify opcode", async () => { expect(solvedWitness).to.be.deep.eq(expectedWitnessMap); }); +it("successfully executes a MemoryOp opcode", async () => { + const { bytecode, initialWitnessMap, expectedWitnessMap } = await import( + "../shared/memory_op" + ); + + const solvedWitness: WitnessMap = await executeCircuit( + bytecode, + initialWitnessMap, + () => { + throw Error("unexpected oracle"); + } + ); + + expect(solvedWitness).to.be.deep.eq(expectedWitnessMap); +}); + it("successfully executes two circuits with same backend", async function () { this.timeout(10000); diff --git a/acvm_js/test/shared/addition.ts b/acvm_js/test/shared/addition.ts index 6b08552e..790da506 100644 --- a/acvm_js/test/shared/addition.ts +++ b/acvm_js/test/shared/addition.ts @@ -3,12 +3,12 @@ import { WitnessMap } from "../../../result/"; // See `addition_circuit` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 144, 187, 13, 192, 32, 12, 68, 249, - 100, 32, 27, 219, 96, 119, 89, 37, 40, 176, 255, 8, 81, 36, 23, 72, 41, 195, - 53, 215, 61, 221, 189, 35, 132, 16, 195, 55, 217, 251, 244, 134, 127, 193, - 184, 145, 149, 22, 22, 65, 101, 30, 173, 12, 36, 188, 160, 88, 87, 1, 150, 94, - 21, 21, 69, 229, 46, 74, 52, 148, 181, 89, 183, 6, 134, 76, 3, 167, 24, 77, - 135, 229, 125, 187, 32, 57, 231, 253, 154, 22, 151, 113, 113, 250, 0, 123, 50, - 20, 220, 112, 1, 0, 0, + 100, 32, 27, 219, 96, 119, 89, 37, 40, 176, 255, 8, 17, 18, 5, 74, 202, 240, + 154, 235, 158, 238, 238, 112, 206, 121, 247, 37, 206, 60, 103, 194, 63, 208, + 111, 116, 133, 197, 69, 144, 153, 91, 73, 13, 9, 47, 72, 86, 85, 128, 165, + 102, 69, 69, 81, 185, 147, 18, 53, 101, 45, 86, 173, 128, 33, 83, 195, 46, 70, + 125, 202, 226, 190, 94, 16, 166, 103, 108, 13, 203, 151, 254, 245, 233, 224, + 1, 1, 52, 166, 127, 120, 1, 0, 0, ]); export const initialWitnessMap: WitnessMap = new Map([ diff --git a/acvm_js/test/shared/complex_foreign_call.ts b/acvm_js/test/shared/complex_foreign_call.ts index 2529b640..4d5a7f96 100644 --- a/acvm_js/test/shared/complex_foreign_call.ts +++ b/acvm_js/test/shared/complex_foreign_call.ts @@ -3,13 +3,13 @@ import { WitnessMap } from "../../../result/"; // See `complex_brillig_foreign_call` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 83, 219, 10, 128, 48, 8, 245, 210, - 101, 159, 179, 254, 160, 127, 137, 222, 138, 122, 236, 243, 91, 228, 64, 44, - 232, 33, 7, 117, 64, 156, 206, 201, 193, 51, 3, 0, 32, 156, 224, 100, 36, 103, - 148, 88, 35, 215, 245, 226, 227, 59, 116, 232, 215, 43, 150, 226, 72, 63, 224, - 200, 5, 56, 230, 255, 240, 81, 189, 61, 117, 113, 157, 31, 223, 236, 79, 149, - 172, 78, 214, 72, 220, 138, 15, 106, 214, 168, 114, 249, 126, 88, 230, 117, - 26, 55, 54, 37, 90, 26, 155, 39, 227, 31, 223, 232, 230, 4, 215, 157, 63, 176, - 3, 89, 64, 134, 157, 36, 4, 0, 0, + 101, 159, 179, 254, 160, 127, 137, 222, 138, 122, 236, 243, 27, 228, 64, 44, + 232, 33, 7, 237, 128, 56, 157, 147, 131, 103, 6, 0, 64, 184, 192, 201, 72, + 206, 40, 177, 70, 174, 27, 197, 199, 111, 24, 208, 175, 87, 44, 197, 145, 42, + 224, 200, 5, 56, 230, 255, 240, 83, 189, 61, 117, 113, 157, 31, 63, 236, 79, + 147, 172, 77, 214, 73, 220, 139, 15, 106, 214, 168, 114, 249, 126, 218, 214, + 125, 153, 15, 54, 37, 90, 26, 155, 39, 227, 95, 223, 232, 230, 4, 247, 157, + 215, 56, 1, 153, 86, 63, 138, 44, 4, 0, 0, ]); export const initialWitnessMap: WitnessMap = new Map([ [1, "0x0000000000000000000000000000000000000000000000000000000000000001"], diff --git a/acvm_js/test/shared/fixed_base_scalar_mul.ts b/acvm_js/test/shared/fixed_base_scalar_mul.ts index 625e1f15..4ab05544 100644 --- a/acvm_js/test/shared/fixed_base_scalar_mul.ts +++ b/acvm_js/test/shared/fixed_base_scalar_mul.ts @@ -1,8 +1,8 @@ // See `fixed_base_scalar_mul_circuit` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 138, 201, 9, 0, 0, 8, 195, 234, 241, - 114, 255, 121, 69, 69, 5, 49, 16, 242, 104, 21, 0, 161, 169, 218, 212, 83, 78, - 229, 237, 11, 159, 214, 39, 0, 55, 132, 28, 78, 72, 0, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 137, 91, 10, 0, 0, 4, 4, 215, 227, 203, + 253, 207, 43, 132, 146, 169, 105, 106, 87, 1, 16, 154, 170, 77, 61, 229, 84, + 222, 191, 240, 169, 156, 61, 0, 36, 111, 164, 5, 80, 0, 0, 0, ]); export const initialWitnessMap = new Map([ diff --git a/acvm_js/test/shared/foreign_call.ts b/acvm_js/test/shared/foreign_call.ts index 1d1da9d0..038b64a5 100644 --- a/acvm_js/test/shared/foreign_call.ts +++ b/acvm_js/test/shared/foreign_call.ts @@ -2,11 +2,11 @@ import { WitnessMap } from "../../../result/"; // See `simple_brillig_foreign_call` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 65, 10, 0, 32, 8, 4, 205, 32, - 122, 142, 253, 160, 207, 116, 232, 210, 33, 162, 247, 23, 100, 96, 32, 93, - 106, 64, 92, 92, 144, 93, 15, 0, 6, 22, 86, 104, 201, 190, 69, 222, 244, 70, - 48, 255, 126, 145, 204, 139, 74, 102, 63, 199, 177, 206, 165, 167, 218, 110, - 13, 15, 80, 152, 168, 248, 3, 190, 43, 105, 200, 59, 1, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 81, 10, 0, 16, 16, 68, 199, 42, + 57, 14, 55, 112, 25, 31, 126, 124, 72, 206, 79, 161, 86, 225, 135, 87, 219, + 78, 187, 53, 205, 104, 0, 2, 29, 201, 52, 103, 222, 220, 216, 230, 13, 43, + 254, 121, 25, 158, 151, 54, 153, 117, 27, 53, 116, 136, 197, 167, 124, 107, + 184, 64, 236, 73, 56, 83, 1, 18, 139, 122, 157, 67, 1, 0, 0, ]); export const initialWitnessMap: WitnessMap = new Map([ [1, "0x0000000000000000000000000000000000000000000000000000000000000005"], diff --git a/acvm_js/test/shared/memory_op.ts b/acvm_js/test/shared/memory_op.ts new file mode 100644 index 00000000..ffb37df3 --- /dev/null +++ b/acvm_js/test/shared/memory_op.ts @@ -0,0 +1,21 @@ +// See `memory_op_circuit` integration test in `acir/tests/test_program_serialization.rs`. +export const bytecode = Uint8Array.from([ + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 146, 49, 14, 0, 32, 8, 3, 139, 192, + 127, 240, 7, 254, 255, 85, 198, 136, 9, 131, 155, 48, 216, 165, 76, 77, 57, + 80, 0, 140, 45, 117, 111, 238, 228, 179, 224, 174, 225, 110, 111, 234, 213, + 185, 148, 156, 203, 121, 89, 86, 13, 215, 126, 131, 43, 153, 187, 115, 40, + 185, 62, 153, 3, 136, 83, 60, 30, 96, 2, 12, 235, 225, 124, 14, 3, 0, 0, +]); + +export const initialWitnessMap = new Map([ + [1, "0x0000000000000000000000000000000000000000000000000000000000000001"], + [2, "0x0000000000000000000000000000000000000000000000000000000000000001"], + [3, "0x0000000000000000000000000000000000000000000000000000000000000002"], +]); + +export const expectedWitnessMap = new Map([ + [1, "0x0000000000000000000000000000000000000000000000000000000000000001"], + [2, "0x0000000000000000000000000000000000000000000000000000000000000001"], + [3, "0x0000000000000000000000000000000000000000000000000000000000000002"], + [4, "0x0000000000000000000000000000000000000000000000000000000000000002"], +]); diff --git a/acvm_js/test/shared/pedersen.ts b/acvm_js/test/shared/pedersen.ts index 34d9710b..16e5ded5 100644 --- a/acvm_js/test/shared/pedersen.ts +++ b/acvm_js/test/shared/pedersen.ts @@ -1,8 +1,8 @@ // See `pedersen_circuit` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 138, 65, 10, 0, 64, 8, 2, 103, 183, - 232, 255, 47, 142, 138, 58, 68, 130, 168, 140, 10, 60, 90, 149, 118, 182, 79, - 255, 105, 57, 140, 197, 246, 39, 0, 246, 174, 71, 87, 84, 0, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 138, 9, 10, 0, 64, 8, 2, 103, 15, 250, + 255, 139, 163, 162, 130, 72, 16, 149, 241, 3, 135, 84, 164, 172, 173, 213, + 175, 251, 45, 198, 96, 243, 211, 50, 152, 67, 220, 211, 92, 0, 0, 0, ]); export const initialWitnessMap = new Map([ diff --git a/acvm_js/test/shared/schnorr_verify.ts b/acvm_js/test/shared/schnorr_verify.ts index 2cec8847..fa917134 100644 --- a/acvm_js/test/shared/schnorr_verify.ts +++ b/acvm_js/test/shared/schnorr_verify.ts @@ -1,23 +1,23 @@ // See `schnorr_verify_circuit` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 210, 233, 50, 66, 1, 24, 199, 225, 99, - 223, 247, 125, 15, 73, 146, 36, 73, 146, 36, 73, 194, 93, 184, 255, 75, 48, - 122, 167, 167, 25, 103, 230, 204, 83, 211, 151, 230, 253, 255, 126, 146, 36, - 25, 73, 6, 79, 56, 193, 223, 254, 59, 202, 166, 223, 199, 250, 239, 116, 255, - 29, 231, 4, 39, 57, 197, 225, 59, 195, 89, 206, 113, 158, 11, 92, 228, 18, - 151, 185, 194, 85, 174, 113, 157, 27, 220, 228, 22, 183, 185, 195, 93, 238, - 113, 159, 7, 60, 228, 17, 83, 60, 230, 9, 79, 153, 230, 25, 51, 60, 103, 150, - 23, 204, 241, 146, 121, 94, 177, 192, 107, 22, 121, 195, 18, 111, 89, 230, 29, - 43, 188, 103, 149, 15, 172, 241, 145, 117, 62, 177, 193, 103, 54, 249, 194, - 214, 191, 29, 227, 121, 245, 189, 205, 55, 118, 248, 206, 46, 63, 216, 227, - 39, 191, 248, 237, 115, 60, 209, 94, 116, 23, 173, 69, 103, 209, 88, 244, 53, - 108, 107, 198, 255, 136, 150, 162, 163, 104, 40, 250, 137, 118, 162, 155, 104, - 38, 122, 137, 86, 162, 147, 104, 36, 250, 136, 54, 162, 139, 104, 34, 122, - 136, 22, 162, 131, 104, 32, 246, 143, 237, 83, 201, 96, 243, 216, 59, 182, 78, - 219, 56, 99, 219, 172, 77, 115, 182, 204, 219, 176, 96, 187, 162, 205, 74, - 182, 42, 219, 168, 98, 155, 170, 77, 106, 182, 168, 219, 160, 225, 246, 77, - 55, 111, 185, 113, 219, 109, 59, 110, 218, 117, 203, 158, 27, 14, 111, 54, - 188, 91, 226, 150, 127, 214, 93, 14, 165, 212, 3, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 210, 87, 78, 2, 1, 20, 134, 209, 177, + 247, 222, 123, 71, 68, 68, 68, 68, 68, 68, 68, 68, 68, 221, 133, 251, 95, 130, + 145, 27, 206, 36, 78, 50, 57, 16, 94, 200, 253, 191, 159, 36, 73, 134, 146, + 193, 19, 142, 241, 183, 255, 14, 179, 233, 247, 145, 254, 59, 217, 127, 71, + 57, 198, 113, 78, 48, 125, 167, 56, 205, 25, 206, 114, 142, 243, 92, 224, 34, + 151, 184, 204, 21, 174, 114, 141, 235, 220, 224, 38, 183, 184, 205, 29, 238, + 114, 143, 251, 60, 224, 33, 143, 120, 204, 19, 158, 242, 140, 25, 158, 51, + 203, 11, 230, 120, 201, 60, 175, 88, 224, 53, 139, 188, 97, 137, 183, 44, 243, + 142, 21, 222, 179, 202, 7, 214, 248, 200, 58, 159, 216, 224, 51, 155, 124, 97, + 235, 223, 142, 241, 188, 250, 222, 230, 27, 59, 124, 103, 151, 31, 236, 241, + 147, 95, 252, 246, 57, 158, 104, 47, 186, 139, 214, 162, 179, 104, 44, 250, + 74, 219, 154, 242, 63, 162, 165, 232, 40, 26, 138, 126, 162, 157, 232, 38, + 154, 137, 94, 162, 149, 232, 36, 26, 137, 62, 162, 141, 232, 34, 154, 136, 30, + 162, 133, 232, 32, 26, 136, 253, 99, 251, 195, 100, 176, 121, 236, 29, 91, + 159, 218, 56, 99, 219, 172, 77, 115, 182, 204, 219, 176, 96, 187, 162, 205, + 74, 182, 42, 219, 168, 98, 155, 170, 77, 106, 182, 168, 219, 160, 225, 246, + 77, 55, 111, 185, 113, 219, 109, 59, 110, 218, 117, 203, 158, 27, 166, 55, 75, + 239, 150, 184, 101, 250, 252, 1, 19, 89, 159, 101, 220, 3, 0, 0, ]); export const initialWitnessMap = new Map([