From 73d4205495afcea82a04d49f7d35cd52aa1ced6f Mon Sep 17 00:00:00 2001 From: Blaine Bublitz Date: Mon, 1 May 2023 11:36:45 -0700 Subject: [PATCH 01/19] feat!: Rework crate for fallible traits to avoid panic & unwrap --- Cargo.lock | 13 +- Cargo.toml | 4 + src/acvm_interop/proof_system.rs | 18 ++- src/acvm_interop/pwg.rs | 39 +++-- src/acvm_interop/pwg/merkle.rs | 118 +++++++------- src/acvm_interop/smart_contract.rs | 47 +++--- src/barretenberg_structures.rs | 1 + src/composer.rs | 251 ++++++++++++++--------------- src/lib.rs | 146 +++++++++++++---- src/merkle.rs | 42 +++-- src/pedersen.rs | 81 ++++++---- src/pippenger.rs | 17 +- src/scalar_mul.rs | 21 +-- src/schnorr.rs | 113 ++++++++----- 14 files changed, 551 insertions(+), 360 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5c80a482..0a0e24a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,8 +5,7 @@ version = 3 [[package]] name = "acir" version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "510b65efd4d20bf266185ce0a5dc7d29bcdd196a6a1835c20908fd88040de76c" +source = "git+https://github.com/noir-lang/acvm?rev=ba79379b4087a51a027f991ba6f7e6dff9c1c2a7#ba79379b4087a51a027f991ba6f7e6dff9c1c2a7" dependencies = [ "acir_field", "flate2", @@ -17,8 +16,7 @@ dependencies = [ [[package]] name = "acir_field" version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f032e710c67fd146caedc8fe1dea6e95f01ab59453e42d59b604a51fef3dfe" +source = "git+https://github.com/noir-lang/acvm?rev=ba79379b4087a51a027f991ba6f7e6dff9c1c2a7#ba79379b4087a51a027f991ba6f7e6dff9c1c2a7" dependencies = [ "ark-bn254", "ark-ff", @@ -31,8 +29,7 @@ dependencies = [ [[package]] name = "acvm" version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2611266039740ffd1978f23258bd6ce3166c22cf15b8227685c2f3bb20ae2ee0" +source = "git+https://github.com/noir-lang/acvm?rev=ba79379b4087a51a027f991ba6f7e6dff9c1c2a7#ba79379b4087a51a027f991ba6f7e6dff9c1c2a7" dependencies = [ "acir", "acvm_stdlib", @@ -63,6 +60,7 @@ dependencies = [ "sha3", "sled", "tempfile", + "thiserror", "tokio", "wasmer", ] @@ -70,8 +68,7 @@ dependencies = [ [[package]] name = "acvm_stdlib" version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5ec51160c66eba75dc15a028a2391675386fd395b3897478d89a386c64a48dd" +source = "git+https://github.com/noir-lang/acvm?rev=ba79379b4087a51a027f991ba6f7e6dff9c1c2a7#ba79379b4087a51a027f991ba6f7e6dff9c1c2a7" dependencies = [ "acir", ] diff --git a/Cargo.toml b/Cargo.toml index 7ae36cb7..7ce9aaa3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ license = "MIT OR Apache-2.0" [dependencies] acvm = { version = "0.10.3", features = ["bn254"] } +thiserror = "1.0.21" blake2 = "0.9.1" sha3 = "0.9.1" @@ -67,3 +68,6 @@ wasm = [ "dep:indicatif", ] js = ["wasmer", "dep:rust-embed", "dep:getrandom", "wasmer/js-default"] + +[patch.crates-io] +acvm = { package = "acvm", git = "https://github.com/noir-lang/acvm", rev = "ba79379b4087a51a027f991ba6f7e6dff9c1c2a7" } diff --git a/src/acvm_interop/proof_system.rs b/src/acvm_interop/proof_system.rs index 7a88dad0..e6948036 100644 --- a/src/acvm_interop/proof_system.rs +++ b/src/acvm_interop/proof_system.rs @@ -5,14 +5,16 @@ use std::collections::BTreeMap; use crate::barretenberg_structures::Assignments; use crate::composer::Composer; -use crate::Barretenberg; +use crate::{Barretenberg, Error}; impl ProofSystemCompiler for Barretenberg { + type Error = Error; + fn np_language(&self) -> Language { Language::PLONKCSat { width: 3 } } - fn get_exact_circuit_size(&self, circuit: &Circuit) -> u32 { + fn get_exact_circuit_size(&self, circuit: &Circuit) -> Result { Composer::get_exact_circuit_size(self, &circuit.into()) } @@ -35,13 +37,13 @@ impl ProofSystemCompiler for Barretenberg { } } - fn preprocess(&self, circuit: &Circuit) -> (Vec, Vec) { + fn preprocess(&self, circuit: &Circuit) -> Result<(Vec, Vec), Error> { let constraint_system = &circuit.into(); - let proving_key = self.compute_proving_key(constraint_system); - let verification_key = self.compute_verification_key(constraint_system, &proving_key); + let proving_key = self.compute_proving_key(constraint_system)?; + let verification_key = self.compute_verification_key(constraint_system, &proving_key)?; - (proving_key, verification_key) + Ok((proving_key, verification_key)) } fn prove_with_pk( @@ -49,7 +51,7 @@ impl ProofSystemCompiler for Barretenberg { circuit: &Circuit, witness_values: BTreeMap, proving_key: &[u8], - ) -> Vec { + ) -> Result, Error> { let assignments = flatten_witness_map(circuit, witness_values); self.create_proof_with_pk(&circuit.into(), assignments, proving_key) @@ -61,7 +63,7 @@ impl ProofSystemCompiler for Barretenberg { public_inputs: BTreeMap, circuit: &Circuit, verification_key: &[u8], - ) -> bool { + ) -> Result { // Unlike when proving, we omit any unassigned witnesses. // Witness values should be ordered by their index but we skip over any indices without an assignment. let flattened_public_inputs: Vec = public_inputs.into_values().collect(); diff --git a/src/acvm_interop/pwg.rs b/src/acvm_interop/pwg.rs index 6731f160..2fd41e71 100644 --- a/src/acvm_interop/pwg.rs +++ b/src/acvm_interop/pwg.rs @@ -54,7 +54,8 @@ impl PartialWitnessGenerator for Barretenberg { hash_path?, index, leaf, - ); + ) + .map_err(|err| OpcodeResolutionError::OpcodeSolveFailed(err.to_string()))?; initial_witness.insert(func_call.outputs[0], computed_merkle_root); Ok(OpcodeResolution::Solved) @@ -82,25 +83,39 @@ impl PartialWitnessGenerator for Barretenberg { .copied() .chain(pub_key_y.to_vec()) .collect(); - let pub_key: [u8; 64] = pub_key_bytes.try_into().unwrap(); + let pub_key: [u8; 64] = pub_key_bytes.try_into().map_err(|v: Vec| { + OpcodeResolutionError::OpcodeSolveFailed(format!( + "expected pubkey size {} but received {}", + 64, + v.len() + )) + })?; let mut signature = [0u8; 64]; for (i, sig) in signature.iter_mut().enumerate() { - let _sig_i = inputs_iter.next().unwrap_or_else(|| { - panic!("signature should be 64 bytes long, found only {i} bytes") - }); + let _sig_i = inputs_iter.next().ok_or_else(|| { + OpcodeResolutionError::OpcodeSolveFailed(format!( + "signature should be 64 bytes long, found only {i} bytes" + )) + })?; let sig_i = witness_to_value(initial_witness, _sig_i.witness)?; - *sig = *sig_i.to_be_bytes().last().unwrap() + *sig = *sig_i.to_be_bytes().last().ok_or_else(|| { + OpcodeResolutionError::OpcodeSolveFailed("could not get last bytes".into()) + })?; } let mut message = Vec::new(); for msg in inputs_iter { let msg_i_field = witness_to_value(initial_witness, msg.witness)?; - let msg_i = *msg_i_field.to_be_bytes().last().unwrap(); + let msg_i = *msg_i_field.to_be_bytes().last().ok_or_else(|| { + OpcodeResolutionError::OpcodeSolveFailed("could not get last bytes".into()) + })?; message.push(msg_i); } - let valid_signature = self.verify_signature(pub_key, signature, &message); + let valid_signature = self + .verify_signature(pub_key, signature, &message) + .map_err(|err| OpcodeResolutionError::OpcodeSolveFailed(err.to_string()))?; if !valid_signature { dbg!("signature has failed to verify"); } @@ -122,7 +137,9 @@ impl PartialWitnessGenerator for Barretenberg { .collect(); let scalars: Vec<_> = scalars?.into_iter().cloned().collect(); - let (res_x, res_y) = self.encrypt(scalars); + let (res_x, res_y) = self + .encrypt(scalars) + .map_err(|err| OpcodeResolutionError::OpcodeSolveFailed(err.to_string()))?; initial_witness.insert(func_call.outputs[0], res_x); initial_witness.insert(func_call.outputs[1], res_y); Ok(OpcodeResolution::Solved) @@ -152,7 +169,9 @@ impl PartialWitnessGenerator for Barretenberg { BlackBoxFunc::FixedBaseScalarMul => { let scalar = witness_to_value(initial_witness, func_call.inputs[0].witness)?; - let (pub_x, pub_y) = self.fixed_base(scalar); + let (pub_x, pub_y) = self + .fixed_base(scalar) + .map_err(|err| OpcodeResolutionError::OpcodeSolveFailed(err.to_string()))?; initial_witness.insert(func_call.outputs[0], pub_x); initial_witness.insert(func_call.outputs[1], pub_y); diff --git a/src/acvm_interop/pwg/merkle.rs b/src/acvm_interop/pwg/merkle.rs index 0bf5ebc1..da85ab59 100644 --- a/src/acvm_interop/pwg/merkle.rs +++ b/src/acvm_interop/pwg/merkle.rs @@ -1,11 +1,13 @@ use acvm::FieldElement; +use crate::Error; + pub(super) fn compute_merkle_root( - hash_func: impl Fn(&FieldElement, &FieldElement) -> FieldElement, + hash_func: impl Fn(&FieldElement, &FieldElement) -> Result, hash_path: Vec<&FieldElement>, index: &FieldElement, leaf: &FieldElement, -) -> FieldElement { +) -> Result { let mut index_bits: Vec = index.bits(); index_bits.reverse(); @@ -14,14 +16,17 @@ pub(super) fn compute_merkle_root( "hash path exceeds max depth of tree" ); index_bits.into_iter().zip(hash_path.into_iter()).fold( - *leaf, - |current_node, (path_bit, path_elem)| { - let (left, right) = if !path_bit { - (¤t_node, path_elem) - } else { - (path_elem, ¤t_node) - }; - hash_func(left, right) + Ok(*leaf), + |current_node, (path_bit, path_elem)| match current_node { + Ok(current_node) => { + let (left, right) = if !path_bit { + (¤t_node, path_elem) + } else { + (path_elem, ¤t_node) + }; + hash_func(left, right) + } + Err(_) => current_node, }, ) } @@ -29,11 +34,12 @@ pub(super) fn compute_merkle_root( #[cfg(test)] mod tests { use crate::merkle::{MerkleTree, MessageHasher}; + use crate::Error; use crate::{pedersen::Pedersen, Barretenberg}; use acvm::FieldElement; #[test] - fn test_check_membership() { + fn test_check_membership() -> Result<(), Error> { struct Test<'a> { // Index of the leaf in the MerkleTree index: &'a str, @@ -49,42 +55,42 @@ mod tests { // Note these test cases are not independent. // i.e. If you update index 0, then this will be saved for the next test let tests = vec![ - Test { - index : "0", - result : true, - message : vec![0;64], - should_update_tree: false, - error_msg : "this should always be true, since the tree is initialized with 64 zeroes" - }, - Test { - index : "0", - result : false, - message : vec![10;64], - should_update_tree: false, - error_msg : "this should be false, since the tree was not updated, however the message which derives the leaf has changed" - }, - Test { - index : "0", - result : true, - message : vec![1;64], - should_update_tree: true, - error_msg : "this should be true, since we are updating the tree" - }, - Test { - index : "0", - result : true, - message : vec![1;64], - should_update_tree: false, - error_msg : "this should be true since the index at 4 has not been changed yet, so it would be [0;64]" - }, - Test { - index : "4", - result : true, - message : vec![0;64], - should_update_tree: false, - error_msg : "this should be true since the index at 4 has not been changed yet, so it would be [0;64]" - }, - ]; + Test { + index : "0", + result : true, + message : vec![0;64], + should_update_tree: false, + error_msg : "this should always be true, since the tree is initialized with 64 zeroes" + }, + Test { + index : "0", + result : false, + message : vec![10;64], + should_update_tree: false, + error_msg : "this should be false, since the tree was not updated, however the message which derives the leaf has changed" + }, + Test { + index : "0", + result : true, + message : vec![1;64], + should_update_tree: true, + error_msg : "this should be true, since we are updating the tree" + }, + Test { + index : "0", + result : true, + message : vec![1;64], + should_update_tree: false, + error_msg : "this should be true since the index at 4 has not been changed yet, so it would be [0;64]" + }, + Test { + index : "4", + result : true, + message : vec![0;64], + should_update_tree: false, + error_msg : "this should be true since the index at 4 has not been changed yet, so it would be [0;64]" + }, + ]; use tempfile::tempdir; let temp_dir = tempdir().unwrap(); @@ -102,7 +108,7 @@ mod tests { let mut root = tree.root(); if test_vector.should_update_tree { - root = tree.update_message(index_as_usize, &test_vector.message); + root = tree.update_message(index_as_usize, &test_vector.message)?; } let hash_path = tree.get_hash_path(index_as_usize); @@ -120,7 +126,7 @@ mod tests { hash_path_ref, &index, &leaf, - ); + )?; let is_leaf_in_tree = root == computed_merkle_root; assert_eq!( @@ -129,11 +135,13 @@ mod tests { test_vector.error_msg ); } + + Ok(()) } // This test uses `update_leaf` directly rather than `update_message` #[test] - fn simple_shield() { + fn simple_shield() -> Result<(), Error> { use tempfile::tempdir; let temp_dir = tempdir().unwrap(); @@ -148,7 +156,7 @@ mod tests { "0x2a5d7253a6ed48462fedb2d350cc768d13956310f54e73a8a47914f34a34c5c4", ) .unwrap(); - let (note_commitment_x, _) = barretenberg.encrypt(vec![pubkey_x, pubkey_y]); + let (note_commitment_x, _) = barretenberg.encrypt(vec![pubkey_x, pubkey_y])?; dbg!(note_commitment_x.to_hex()); let leaf = note_commitment_x; @@ -157,7 +165,7 @@ mod tests { let mut index_bits = index.bits(); index_bits.reverse(); - let root = tree.update_leaf(index_as_usize, leaf); + let root = tree.update_leaf(index_as_usize, leaf)?; let hash_path = tree.get_hash_path(index_as_usize); let mut hash_path_ref = Vec::new(); @@ -173,8 +181,10 @@ mod tests { hash_path_ref, &index, &leaf, - ); + )?; + + assert_eq!(root, computed_merkle_root); - assert_eq!(root, computed_merkle_root) + Ok(()) } } diff --git a/src/acvm_interop/smart_contract.rs b/src/acvm_interop/smart_contract.rs index 5ef524d3..275e1bce 100644 --- a/src/acvm_interop/smart_contract.rs +++ b/src/acvm_interop/smart_contract.rs @@ -1,14 +1,16 @@ use acvm::SmartContract; use crate::crs::G2; -use crate::Barretenberg; +use crate::{Barretenberg, Error}; /// Embed the Solidity verifier file const ULTRA_VERIFIER_CONTRACT: &str = include_str!("contract.sol"); #[cfg(feature = "native")] impl SmartContract for Barretenberg { - fn eth_contract_from_vk(&self, verification_key: &[u8]) -> String { + type Error = Error; + + fn eth_contract_from_vk(&self, verification_key: &[u8]) -> Result { use std::slice; let g2 = G2::new(); @@ -28,46 +30,47 @@ impl SmartContract for Barretenberg { }; let verification_key_library: String = sc_as_bytes.iter().map(|b| *b as char).collect(); - format!("{verification_key_library}{ULTRA_VERIFIER_CONTRACT}") + Ok(format!( + "{verification_key_library}{ULTRA_VERIFIER_CONTRACT}" + )) } } #[cfg(not(feature = "native"))] impl SmartContract for Barretenberg { - fn eth_contract_from_vk(&self, verification_key: &[u8]) -> String { - use crate::wasm::POINTER_BYTES; + type Error = Error; + fn eth_contract_from_vk(&self, verification_key: &[u8]) -> Result { let g2 = G2::new(); - let g2_ptr = self.allocate(&g2.data); - let vk_ptr = self.allocate(verification_key); + let g2_ptr = self.allocate(&g2.data)?; + let vk_ptr = self.allocate(verification_key)?; // The smart contract string is not actually written to this pointer. // `contract_ptr_ptr` is a pointer to a pointer which holds the smart contract string. let contract_ptr_ptr: usize = 0; - let contract_size = self - .call_multiple( - "acir_proofs_get_solidity_verifier", - vec![&g2_ptr, &vk_ptr, &contract_ptr_ptr.into()], - ) - .value(); - let contract_size: usize = contract_size.unwrap_i32() as usize; + let contract_size = self.call_multiple( + "acir_proofs_get_solidity_verifier", + vec![&g2_ptr, &vk_ptr, &contract_ptr_ptr.into()], + )?; + let contract_size: usize = contract_size.i32()? as usize; // We then need to read the pointer at `contract_ptr_ptr` to get the smart contract's location // and then slice memory again at `contract_ptr_ptr` to get the smart contract string. - let contract_ptr: [u8; POINTER_BYTES] = self.read_memory(contract_ptr_ptr); - let contract_ptr: usize = u32::from_le_bytes(contract_ptr) as usize; + let contract_ptr = self.get_pointer(contract_ptr_ptr)?; let sc_as_bytes = self.read_memory_variable_length(contract_ptr, contract_size); let verification_key_library: String = sc_as_bytes.iter().map(|b| *b as char).collect(); - format!("{verification_key_library}{ULTRA_VERIFIER_CONTRACT}") + Ok(format!( + "{verification_key_library}{ULTRA_VERIFIER_CONTRACT}" + )) } } #[test] -fn test_smart_contract() { +fn test_smart_contract() -> Result<(), Error> { use crate::barretenberg_structures::{Constraint, ConstraintSystem}; use crate::composer::Composer; use crate::Barretenberg; @@ -91,12 +94,14 @@ fn test_smart_contract() { let bb = Barretenberg::new(); - let proving_key = bb.compute_proving_key(&constraint_system); - let verification_key = bb.compute_verification_key(&constraint_system, &proving_key); + let proving_key = bb.compute_proving_key(&constraint_system)?; + let verification_key = bb.compute_verification_key(&constraint_system, &proving_key)?; - let contract = bb.eth_contract_from_vk(&verification_key); + let contract = bb.eth_contract_from_vk(&verification_key)?; assert!(contract.contains("contract BaseUltraVerifier")); assert!(contract.contains("contract UltraVerifier")); assert!(contract.contains("library UltraVerificationKey")); + + Ok(()) } diff --git a/src/barretenberg_structures.rs b/src/barretenberg_structures.rs index ee64814d..0a4bb276 100644 --- a/src/barretenberg_structures.rs +++ b/src/barretenberg_structures.rs @@ -643,6 +643,7 @@ impl ConstraintSystem { } } +// TODO: TryFrom impl From<&Circuit> for ConstraintSystem { /// Converts an `IR` into the `StandardFormat` constraint system fn from(circuit: &Circuit) -> Self { diff --git a/src/composer.rs b/src/composer.rs index ce699c12..1befea57 100644 --- a/src/composer.rs +++ b/src/composer.rs @@ -1,26 +1,27 @@ use crate::barretenberg_structures::{Assignments, ConstraintSystem}; use crate::crs::{CRS, G2}; -use crate::{Barretenberg, FIELD_BYTES}; +use crate::{Barretenberg, Error, FIELD_BYTES}; const NUM_RESERVED_GATES: u32 = 4; // this must be >= num_roots_cut_out_of_vanishing_polynomial (found under prover settings in barretenberg) pub(crate) trait Composer { - fn get_circuit_size(&self, constraint_system: &ConstraintSystem) -> u32; - fn get_exact_circuit_size(&self, constraint_system: &ConstraintSystem) -> u32; + fn get_circuit_size(&self, constraint_system: &ConstraintSystem) -> Result; - fn compute_proving_key(&self, constraint_system: &ConstraintSystem) -> Vec; + fn get_exact_circuit_size(&self, constraint_system: &ConstraintSystem) -> Result; + + fn compute_proving_key(&self, constraint_system: &ConstraintSystem) -> Result, Error>; fn compute_verification_key( &self, constraint_system: &ConstraintSystem, proving_key: &[u8], - ) -> Vec; + ) -> Result, Error>; fn create_proof_with_pk( &self, constraint_system: &ConstraintSystem, witness: Assignments, proving_key: &[u8], - ) -> Vec; + ) -> Result, Error>; fn verify_with_vk( &self, @@ -30,7 +31,7 @@ pub(crate) trait Composer { proof: &[u8], public_inputs: Assignments, verification_key: &[u8], - ) -> bool; + ) -> Result; } #[cfg(feature = "native")] @@ -45,7 +46,7 @@ impl Composer for Barretenberg { // This method is primarily used to determine how many group // elements we need from the CRS. So using 2^19 on an error // should be an overestimation. - fn get_circuit_size(&self, constraint_system: &ConstraintSystem) -> u32 { + fn get_circuit_size(&self, constraint_system: &ConstraintSystem) -> Result { let cs_buf = constraint_system.to_bytes(); let circuit_size; @@ -57,13 +58,15 @@ impl Composer for Barretenberg { pow2ceil(circuit_size + NUM_RESERVED_GATES) } - fn get_exact_circuit_size(&self, constraint_system: &ConstraintSystem) -> u32 { + fn get_exact_circuit_size(&self, constraint_system: &ConstraintSystem) -> Result { let cs_buf = constraint_system.to_bytes(); - unsafe { barretenberg_sys::composer::get_exact_circuit_size(cs_buf.as_slice().as_ptr()) } + Ok(unsafe { + barretenberg_sys::composer::get_exact_circuit_size(cs_buf.as_slice().as_ptr()) + }) } - fn compute_proving_key(&self, constraint_system: &ConstraintSystem) -> Vec { + fn compute_proving_key(&self, constraint_system: &ConstraintSystem) -> Result, Error> { let cs_buf = constraint_system.to_bytes(); let mut pk_addr: *mut u8 = std::ptr::null_mut(); @@ -80,19 +83,19 @@ impl Composer for Barretenberg { unsafe { result = Vec::from_raw_parts(pk_addr, pk_size, pk_size); } - result + Ok(result) } fn compute_verification_key( &self, constraint_system: &ConstraintSystem, proving_key: &[u8], - ) -> Vec { - let circuit_size = self.get_circuit_size(constraint_system); + ) -> Result, Error> { + let circuit_size = self.get_circuit_size(constraint_system)?; let CRS { g1_data, g2_data, .. } = CRS::new(circuit_size as usize); - let pippenger_ptr = self.get_pippenger(&g1_data).pointer(); + let pippenger_ptr = self.get_pippenger(&g1_data)?.pointer(); let mut vk_addr: *mut u8 = std::ptr::null_mut(); let vk_ptr = &mut vk_addr as *mut *mut u8; @@ -115,7 +118,7 @@ impl Composer for Barretenberg { unsafe { result = Vec::from_raw_parts(vk_addr, vk_size, vk_size); } - result.to_vec() + Ok(result.to_vec()) } fn create_proof_with_pk( @@ -123,12 +126,12 @@ impl Composer for Barretenberg { constraint_system: &ConstraintSystem, witness: Assignments, proving_key: &[u8], - ) -> Vec { - let circuit_size = self.get_circuit_size(constraint_system); + ) -> Result, Error> { + let circuit_size = self.get_circuit_size(constraint_system)?; let CRS { g1_data, g2_data, .. } = CRS::new(circuit_size as usize); - let pippenger_ptr = self.get_pippenger(&g1_data).pointer(); + let pippenger_ptr = self.get_pippenger(&g1_data)?.pointer(); let cs_buf: Vec = constraint_system.to_bytes(); let witness_buf = witness.to_bytes(); @@ -160,7 +163,10 @@ impl Composer for Barretenberg { // Barretenberg returns proofs which are prepended with the public inputs. // This behavior is nonstandard so we strip the public inputs from the proof. - remove_public_inputs(constraint_system.public_inputs_size(), &result) + Ok(remove_public_inputs( + constraint_system.public_inputs_size(), + &result, + )) } fn verify_with_vk( @@ -171,7 +177,7 @@ impl Composer for Barretenberg { proof: &[u8], public_inputs: Assignments, verification_key: &[u8], - ) -> bool { + ) -> Result { let g2_data = G2::new().data; // Barretenberg expects public inputs to be prepended onto the proof @@ -189,7 +195,7 @@ impl Composer for Barretenberg { &proof, ); } - verified + Ok(verified) } } @@ -205,75 +211,65 @@ impl Composer for Barretenberg { // This method is primarily used to determine how many group // elements we need from the CRS. So using 2^19 on an error // should be an overestimation. - fn get_circuit_size(&self, constraint_system: &ConstraintSystem) -> u32 { + fn get_circuit_size(&self, constraint_system: &ConstraintSystem) -> Result { let cs_buf = constraint_system.to_bytes(); - let cs_ptr = self.allocate(&cs_buf); + let cs_ptr = self.allocate(&cs_buf)?; - let circuit_size = self - .call("acir_proofs_get_total_circuit_size", &cs_ptr) - .i32(); - let circuit_size = - u32::try_from(circuit_size).expect("circuit cannot have negative number of gates"); + // This doesn't unwrap the result because we need to free even if there is a failure + let circuit_size = self.call("acir_proofs_get_total_circuit_size", &cs_ptr); - self.free(cs_ptr); + self.free(cs_ptr)?; - pow2ceil(circuit_size + NUM_RESERVED_GATES) + pow2ceil(circuit_size?.u32()? + NUM_RESERVED_GATES) } - fn get_exact_circuit_size(&self, constraint_system: &ConstraintSystem) -> u32 { + fn get_exact_circuit_size(&self, constraint_system: &ConstraintSystem) -> Result { let cs_buf = constraint_system.to_bytes(); - let cs_ptr = self.allocate(&cs_buf); + let cs_ptr = self.allocate(&cs_buf)?; - let circuit_size = self - .call("acir_proofs_get_exact_circuit_size", &cs_ptr) - .i32(); - let circuit_size = - u32::try_from(circuit_size).expect("circuit cannot have negative number of gates"); + // This doesn't unwrap the result because we need to free even if there is a failure + let circuit_size = self.call("acir_proofs_get_exact_circuit_size", &cs_ptr); - self.free(cs_ptr); + self.free(cs_ptr)?; - circuit_size + circuit_size?.u32() } - fn compute_proving_key(&self, constraint_system: &ConstraintSystem) -> Vec { - use super::wasm::POINTER_BYTES; - + fn compute_proving_key(&self, constraint_system: &ConstraintSystem) -> Result, Error> { let cs_buf = constraint_system.to_bytes(); - let cs_ptr = self.allocate(&cs_buf); + let cs_ptr = self.allocate(&cs_buf)?; // The proving key is not actually written to this pointer. // `pk_ptr_ptr` is a pointer to a pointer which holds the proving key. let pk_ptr_ptr: usize = 0; - let pk_size = self.call_multiple( - "acir_proofs_init_proving_key", - vec![&cs_ptr, &pk_ptr_ptr.into()], - ); - let pk_size: usize = pk_size.i32() as usize; + let pk_size = self + .call_multiple( + "acir_proofs_init_proving_key", + vec![&cs_ptr, &pk_ptr_ptr.into()], + )? + .i32()?; // We then need to read the pointer at `pk_ptr_ptr` to get the key's location // and then slice memory again at `pk_ptr` to get the proving key. - let pk_ptr: [u8; POINTER_BYTES] = self.read_memory(pk_ptr_ptr); - let pk_ptr: usize = u32::from_le_bytes(pk_ptr) as usize; + let pk_ptr = self.get_pointer(pk_ptr_ptr)?; - self.read_memory_variable_length(pk_ptr, pk_size) + Ok(self.read_memory_variable_length(pk_ptr, pk_size)) } fn compute_verification_key( &self, constraint_system: &ConstraintSystem, proving_key: &[u8], - ) -> Vec { - use super::wasm::POINTER_BYTES; - - let circuit_size = self.get_circuit_size(constraint_system); + ) -> Result, Error> { + let circuit_size = self.get_circuit_size(constraint_system)?; let CRS { g1_data, g2_data, .. } = CRS::new(circuit_size as usize); - let pippenger_ptr = self.get_pippenger(&g1_data).pointer(); + let pippenger_ptr = self.get_pippenger(&g1_data)?.pointer(); - let g2_ptr = self.allocate(&g2_data); - let pk_ptr = self.allocate(proving_key); + let g2_ptr = self.allocate(&g2_data)?; + let pk_ptr = self.allocate(proving_key)?; // The verification key is not actually written to this pointer. // `vk_ptr_ptr` is a pointer to a pointer which holds the verification key. @@ -282,17 +278,15 @@ impl Composer for Barretenberg { let vk_size = self .call_multiple( "acir_proofs_init_verification_key", - vec![&pippenger_ptr, &g2_ptr, &pk_ptr, &vk_ptr_ptr.into()], - ) - .value(); - let vk_size: usize = vk_size.unwrap_i32() as usize; + vec![&pippenger_ptr.into(), &g2_ptr, &pk_ptr, &vk_ptr_ptr.into()], + )? + .i32()?; // We then need to read the pointer at `vk_ptr_ptr` to get the key's location // and then slice memory again at `vk_ptr` to get the verification key. - let vk_ptr: [u8; POINTER_BYTES] = self.read_memory(vk_ptr_ptr); - let vk_ptr: usize = u32::from_le_bytes(vk_ptr) as usize; + let vk_ptr = self.get_pointer(vk_ptr_ptr)?; - self.read_memory_variable_length(vk_ptr, vk_size) + Ok(self.read_memory_variable_length(vk_ptr, vk_size)) } fn create_proof_with_pk( @@ -300,21 +294,19 @@ impl Composer for Barretenberg { constraint_system: &ConstraintSystem, witness: Assignments, proving_key: &[u8], - ) -> Vec { - use super::wasm::POINTER_BYTES; - - let circuit_size = self.get_circuit_size(constraint_system); + ) -> Result, Error> { + let circuit_size = self.get_circuit_size(constraint_system)?; let CRS { g1_data, g2_data, .. } = CRS::new(circuit_size as usize); - let pippenger_ptr = self.get_pippenger(&g1_data).pointer(); + let pippenger_ptr = self.get_pippenger(&g1_data)?.pointer(); let cs_buf: Vec = constraint_system.to_bytes(); let witness_buf = witness.to_bytes(); - let cs_ptr = self.allocate(&cs_buf); - let witness_ptr = self.allocate(&witness_buf); - let g2_ptr = self.allocate(&g2_data); - let pk_ptr = self.allocate(proving_key); + let cs_ptr = self.allocate(&cs_buf)?; + let witness_ptr = self.allocate(&witness_buf)?; + let g2_ptr = self.allocate(&g2_data)?; + let pk_ptr = self.allocate(proving_key)?; // The proof data is not actually written to this pointer. // `proof_ptr_ptr` is a pointer to a pointer which holds the proof data. @@ -324,27 +316,28 @@ impl Composer for Barretenberg { .call_multiple( "acir_proofs_new_proof", vec![ - &pippenger_ptr, + &pippenger_ptr.into(), &g2_ptr, &pk_ptr, &cs_ptr, &witness_ptr, - &0.into(), + &proof_ptr_ptr.into(), ], - ) - .value(); - let proof_size: usize = proof_size.unwrap_i32() as usize; + )? + .i32()?; // We then need to read the pointer at `proof_ptr_ptr` to get the proof's location // and then slice memory again at `proof_ptr` to get the proof data. - let proof_ptr: [u8; POINTER_BYTES] = self.read_memory(proof_ptr_ptr); - let proof_ptr: usize = u32::from_le_bytes(proof_ptr) as usize; + let proof_ptr = self.get_pointer(proof_ptr_ptr)?; let result = self.read_memory_variable_length(proof_ptr, proof_size); // Barretenberg returns proofs which are prepended with the public inputs. // This behavior is nonstandard so we strip the public inputs from the proof. - remove_public_inputs(constraint_system.public_inputs_size(), &result) + Ok(remove_public_inputs( + constraint_system.public_inputs_size(), + &result, + )) } fn verify_with_vk( @@ -355,45 +348,40 @@ impl Composer for Barretenberg { proof: &[u8], public_inputs: Assignments, verification_key: &[u8], - ) -> bool { + ) -> Result { let g2_data = G2::new().data; // Barretenberg expects public inputs to be prepended onto the proof let proof = prepend_public_inputs(proof.to_vec(), public_inputs); let cs_buf = constraint_system.to_bytes(); - let cs_ptr = self.allocate(&cs_buf); - let proof_ptr = self.allocate(&proof); - let g2_ptr = self.allocate(&g2_data); - let vk_ptr = self.allocate(verification_key); + let cs_ptr = self.allocate(&cs_buf)?; + let proof_ptr = self.allocate(&proof)?; + let g2_ptr = self.allocate(&g2_data)?; + let vk_ptr = self.allocate(verification_key)?; - let verified = self - .call_multiple( - "acir_proofs_verify_proof", - vec![&g2_ptr, &vk_ptr, &cs_ptr, &proof_ptr, &proof.len().into()], - ) - .value(); + // This doesn't unwrap the result because we need to free even if there is a failure + let verified = self.call_multiple( + "acir_proofs_verify_proof", + vec![&g2_ptr, &vk_ptr, &cs_ptr, &proof_ptr, &proof.len().into()], + ); - self.free(proof_ptr); + self.free(proof_ptr)?; - match verified.unwrap_i32() { - 0 => false, - 1 => true, - _ => panic!("Expected a 1 or a zero for the verification result"), - } + verified?.bool() } } -fn pow2ceil(v: u32) -> u32 { +fn pow2ceil(v: u32) -> Result { if v > (u32::MAX >> 1) { - panic!("pow2ceil overflow"); - } - - let mut p = 1; - while p < v { - p <<= 1; + Err(Error::Pow2CeilOverflow(v)) + } else { + let mut p = 1; + while p < v { + p <<= 1; + } + Ok(p) } - p } /// Removes the public inputs which are prepended to a proof by Barretenberg. @@ -431,7 +419,7 @@ mod test { }; #[test] - fn test_no_constraints_no_pub_inputs() { + fn test_no_constraints_no_pub_inputs() -> Result<(), Error> { let constraint_system = ConstraintSystem::new(); let case_1 = WitnessResult { @@ -441,11 +429,11 @@ mod test { }; let test_cases = vec![case_1]; - test_composer_with_pk_vk(constraint_system, test_cases); + test_composer_with_pk_vk(constraint_system, test_cases) } #[test] - fn test_a_single_constraint_no_pub_inputs() { + fn test_a_single_constraint_no_pub_inputs() -> Result<(), Error> { let constraint = Constraint { a: 1, b: 2, @@ -498,10 +486,10 @@ mod test { }; let test_cases = vec![case_1, case_2, case_3, case_4, case_5]; - test_composer_with_pk_vk(constraint_system, test_cases); + test_composer_with_pk_vk(constraint_system, test_cases) } #[test] - fn test_a_single_constraint_with_pub_inputs() { + fn test_a_single_constraint_with_pub_inputs() -> Result<(), Error> { let constraint = Constraint { a: 1, b: 2, @@ -570,11 +558,11 @@ mod test { /*case_1,*/ case_2, case_3, /*case_4,*/ case_5, case_6, ]; - test_composer_with_pk_vk(constraint_system, test_cases); + test_composer_with_pk_vk(constraint_system, test_cases) } #[test] - fn test_multiple_constraints() { + fn test_multiple_constraints() -> Result<(), Error> { let constraint = Constraint { a: 1, b: 2, @@ -612,11 +600,11 @@ mod test { result: false, }; - test_composer_with_pk_vk(constraint_system, vec![case_1, case_2]); + test_composer_with_pk_vk(constraint_system, vec![case_1, case_2]) } #[test] - fn test_schnorr_constraints() { + fn test_schnorr_constraints() -> Result<(), Error> { let mut signature_indices = [0i32; 64]; for i in 13..(13 + 64) { signature_indices[i - 13] = i as i32; @@ -689,11 +677,11 @@ mod test { result: true, }; - test_composer_with_pk_vk(constraint_system, vec![case_1]); + test_composer_with_pk_vk(constraint_system, vec![case_1]) } #[test] - fn test_keccak256_constraint() { + fn test_keccak256_constraint() -> Result<(), Error> { let input_value: u128 = 0xbd; let input_index = 1; @@ -740,10 +728,10 @@ mod test { result: true, }; - test_composer_with_pk_vk(constraint_system, vec![case_1]); + test_composer_with_pk_vk(constraint_system, vec![case_1]) } #[test] - fn test_ped_constraints() { + fn test_ped_constraints() -> Result<(), Error> { let constraint = PedersenConstraint { inputs: vec![1, 2], result_x: 3, @@ -792,11 +780,11 @@ mod test { result: true, }; - test_composer_with_pk_vk(constraint_system, vec![case_1]); + test_composer_with_pk_vk(constraint_system, vec![case_1]) } #[test] - fn test_compute_merkle_root_constraint() { + fn test_compute_merkle_root_constraint() -> Result<(), Error> { use tempfile::tempdir; let temp_dir = tempdir().unwrap(); let mut msg_hasher: blake2::Blake2s = MessageHasher::new(); @@ -843,11 +831,11 @@ mod test { result: true, }; - test_composer_with_pk_vk(constraint_system, vec![case_1]); + test_composer_with_pk_vk(constraint_system, vec![case_1]) } #[test] - fn test_logic_constraints() { + fn test_logic_constraints() -> Result<(), Error> { /* * constraints produced by Noir program: * fn main(x : u32, y : pub u32) { @@ -933,7 +921,7 @@ mod test { result: true, }; - test_composer_with_pk_vk(constraint_system, vec![case_1]); + test_composer_with_pk_vk(constraint_system, vec![case_1]) } #[derive(Clone, Debug)] @@ -946,22 +934,23 @@ mod test { fn test_composer_with_pk_vk( constraint_system: ConstraintSystem, test_cases: Vec, - ) { + ) -> Result<(), Error> { let bb = Barretenberg::new(); - let proving_key = bb.compute_proving_key(&constraint_system); - let verification_key = bb.compute_verification_key(&constraint_system, &proving_key); + let proving_key = bb.compute_proving_key(&constraint_system)?; + let verification_key = bb.compute_verification_key(&constraint_system, &proving_key)?; for test_case in test_cases.into_iter() { let proof = - bb.create_proof_with_pk(&constraint_system, test_case.witness, &proving_key); + bb.create_proof_with_pk(&constraint_system, test_case.witness, &proving_key)?; let verified = bb.verify_with_vk( &constraint_system, &proof, test_case.public_inputs, &verification_key, - ); + )?; assert_eq!(verified, test_case.result); } + Ok(()) } } diff --git a/src/lib.rs b/src/lib.rs index 0bca3f4a..c695ed06 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,6 +20,38 @@ mod pippenger; mod scalar_mul; mod schnorr; +use std::{array::TryFromSliceError, num::TryFromIntError}; + +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum Error { + #[error("The value {0} overflows in the pow2ceil function")] + Pow2CeilOverflow(u32), + #[error("Could not convert schnorr")] + SchnorrConvert(Vec), + #[error("Could not slice schnorr")] + SchnorrSlice { source: TryFromSliceError }, + #[error("Could not slice field element")] + FieldElementSlice { source: TryFromSliceError }, + #[error("Expected a Vec of length {0} but it was {1}")] + FieldToArray(usize, usize), + #[error("Trying to call {0} resulted in an error")] + WasmFunctionCall(String), + #[error("Could not find function export named {0}")] + WasmInvalidExport(String), + #[error("No value available when value was expected")] + WasmNoValue, + #[error("Value expected to be i32")] + WasmInvalidI32, + #[error("Could not convert value {value} from i32 to u32")] + WasmInvalidU32 { value: i32, source: TryFromIntError }, + #[error("Value expected to be 0 or 1 representing a boolean")] + WasmInvalidBool, + #[error("Failed to get pointer")] + WasmInvalidPointer { source: TryFromSliceError }, +} + /// The number of bytes necessary to store a `FieldElement`. const FIELD_BYTES: usize = 32; @@ -37,17 +69,19 @@ impl Default for Barretenberg { } #[test] -fn smoke() { +fn smoke() -> Result<(), Error> { use crate::pedersen::Pedersen; let b = Barretenberg::new(); - let (x, y) = b.encrypt(vec![acvm::FieldElement::zero(), acvm::FieldElement::one()]); + let (x, y) = b.encrypt(vec![acvm::FieldElement::zero(), acvm::FieldElement::one()])?; dbg!(x.to_hex(), y.to_hex()); + Ok(()) } #[cfg(feature = "native")] mod native { use super::Barretenberg; + use super::Error; impl Barretenberg { pub(crate) fn new() -> Barretenberg { @@ -55,12 +89,12 @@ mod native { } } - pub(super) fn field_to_array(f: &acvm::FieldElement) -> [u8; 32] { + pub(super) fn field_to_array(f: &acvm::FieldElement) -> Result<[u8; 32], Error> { let v = f.to_be_bytes(); - let result: [u8; 32] = v.try_into().unwrap_or_else(|v: Vec| { - panic!("Expected a Vec of length {} but it was {}", 32, v.len()) - }); - result + let result: [u8; 32] = v + .try_into() + .map_err(|v: Vec| Error::FieldToArray(32, v.len()))?; + Ok(result) } } @@ -70,6 +104,7 @@ mod wasm { use wasmer::{imports, Function, Instance, Memory, MemoryType, Module, Store, Value}; use super::Barretenberg; + use super::Error; /// The number of bytes necessary to represent a pointer to memory inside the wasm. pub(super) const POINTER_BYTES: usize = 4; @@ -108,12 +143,49 @@ mod wasm { pub(super) struct WASMValue(Option); impl WASMValue { - pub(super) fn value(self) -> Value { - self.0.unwrap() + pub(super) fn value(self) -> Result { + self.0.ok_or(Error::WasmNoValue) + } + pub(super) fn i32(self) -> Result { + self.0 + .and_then(|val| val.i32()) + .ok_or(Error::WasmInvalidI32) + } + pub(super) fn u32(self) -> Result { + let value = self.i32()?; + u32::try_from(value).map_err(|source| Error::WasmInvalidU32 { value, source }) + } + pub(super) fn bool(self) -> Result { + match self.i32() { + Ok(0) => Ok(false), + Ok(1) => Ok(true), + _ => Err(Error::WasmInvalidBool), + } + } + } + + impl From for WASMValue { + fn from(value: usize) -> Self { + WASMValue(Some(Value::I32(value as i32))) + } + } + + impl From for WASMValue { + fn from(value: i32) -> Self { + WASMValue(Some(Value::I32(value))) } + } - pub(super) fn i32(self) -> i32 { - i32::try_from(self.0.unwrap()).expect("expected an i32 value") + impl From for WASMValue { + fn from(value: Value) -> Self { + WASMValue(Some(value)) + } + } + + // TODO: try_into + impl From for Value { + fn from(value: WASMValue) -> Self { + value.0.unwrap() } pub(super) fn bool(self) -> bool { @@ -188,40 +260,60 @@ mod wasm { .collect(); } - pub(super) fn call(&self, name: &str, param: &WASMValue) -> WASMValue { + pub(super) fn get_pointer(&self, ptr_ptr: usize) -> Result { + let ptr = self.slice_memory(ptr_ptr, POINTER_BYTES); + Ok(u32::from_le_bytes( + ptr[0..POINTER_BYTES] + .try_into() + .map_err(|source| Error::WasmInvalidPointer { source })?, + ) as usize) + } + + pub(super) fn call(&self, name: &str, param: &WASMValue) -> Result { self.call_multiple(name, vec![param]) } - pub(super) fn call_multiple(&self, name: &str, params: Vec<&WASMValue>) -> WASMValue { + pub(super) fn call_multiple( + &self, + name: &str, + params: Vec<&WASMValue>, + ) -> Result { // We take in a reference to values, since they do not implement Copy. // We then clone them inside of this function, so that the API does not have a bunch of Clones everywhere - let params: Vec = params - .into_iter() - .map(|param| param.clone().value()) - .collect(); - let func = self.instance.exports.get_function(name).unwrap(); - let option_value = func.call(¶ms).unwrap().first().cloned(); - - WASMValue(option_value) + let params: Vec = params.into_iter().cloned().map(|val| val.into()).collect(); + let func = self + .instance + .exports + .get_function(name) + // We ignore this source error so the Error enum doesn't need to depend on Wasmer + .map_err(|_source| Error::WasmInvalidExport(name.to_string()))?; + let boxed_value = func + .call(¶ms) + // We ignore this source error so the Error enum doesn't need to depend on Wasmer + .map_err(|_source| Error::WasmFunctionCall(name.to_string()))?; + let option_value = boxed_value.first().cloned(); + + Ok(WASMValue(option_value)) } /// Creates a pointer and allocates the bytes that the pointer references to, to the heap - pub(super) fn allocate(&self, bytes: &[u8]) -> WASMValue { - let ptr = self.call("bbmalloc", &bytes.len().into()).value(); + pub(super) fn allocate(&self, bytes: &[u8]) -> Result { + let ptr = self.call("bbmalloc", &bytes.len().into())?.i32()?; - let i32_bytes = ptr.unwrap_i32().to_be_bytes(); + let i32_bytes = ptr.to_be_bytes(); let u32_bytes = u32::from_be_bytes(i32_bytes); self.transfer_to_heap(bytes, u32_bytes as usize); - ptr.into() + Ok(ptr.into()) } /// Frees a pointer. /// Notice we consume the Value, if you clone the value before passing it to free /// It most likely is a bug - pub(super) fn free(&self, pointer: WASMValue) { - self.call("bbfree", &pointer); + pub(super) fn free(&self, pointer: WASMValue) -> Result<(), Error> { + self.call("bbfree", &pointer)?; + Ok(()) } } diff --git a/src/merkle.rs b/src/merkle.rs index 7558ee8c..86272075 100644 --- a/src/merkle.rs +++ b/src/merkle.rs @@ -1,16 +1,16 @@ use acvm::FieldElement; use std::{convert::TryInto, path::Path}; -use crate::{pedersen::Pedersen, Barretenberg}; +use crate::{pedersen::Pedersen, Barretenberg, Error}; // Hashes the leaves up the path, on the way to the root pub(crate) trait PathHasher { fn new() -> Self; - fn hash(&self, left: &FieldElement, right: &FieldElement) -> FieldElement; + fn hash(&self, left: &FieldElement, right: &FieldElement) -> Result; } impl PathHasher for Barretenberg { - fn hash(&self, left: &FieldElement, right: &FieldElement) -> FieldElement { + fn hash(&self, left: &FieldElement, right: &FieldElement) -> Result { self.compress_native(left, right) } @@ -65,6 +65,7 @@ pub(crate) struct MerkleTree { msg_hasher: MH, } +// TODO: Rework this module to return results fn insert_root(db: &mut sled::Db, value: FieldElement) { db.insert("ROOT".as_bytes(), value.to_be_bytes()).unwrap(); } @@ -202,7 +203,8 @@ impl MerkleTree { for i in 0..layer_size { hashes[offset + i] = current; } - current = barretenberg.hash(¤t, ¤t); + // TODO: no unwrap + current = barretenberg.hash(¤t, ¤t).unwrap(); offset += layer_size; layer_size /= 2; @@ -248,7 +250,11 @@ impl MerkleTree { path } /// Updates the message at index and computes the new tree root - pub(crate) fn update_message(&mut self, index: usize, new_message: &[u8]) -> FieldElement { + pub(crate) fn update_message( + &mut self, + index: usize, + new_message: &[u8], + ) -> Result { let current = self.msg_hasher.hash(new_message); insert_preimage(&mut self.db, index as u32, new_message.to_vec()); @@ -285,7 +291,7 @@ impl MerkleTree { &mut self, mut index: usize, mut current: FieldElement, - ) -> FieldElement { + ) -> Result { // Note that this method does not update the list of messages [preimages]| // use `update_message` to do this self.check_if_index_valid_and_increment(index); @@ -299,7 +305,7 @@ impl MerkleTree { current = self.barretenberg.hash( &fetch_hash(&self.db, offset + index), &fetch_hash(&self.db, offset + index + 1), - ); + )?; offset += layer_size as usize; layer_size /= 2; @@ -307,7 +313,7 @@ impl MerkleTree { } insert_root(&mut self.db, current); - current + Ok(current) } #[allow(dead_code)] @@ -368,20 +374,20 @@ fn basic_interop_hashpath() { } #[test] -fn basic_interop_update() { +fn basic_interop_update() -> Result<(), Error> { // Test that computing the HashPath is correct use tempfile::tempdir; let temp_dir = tempdir().unwrap(); let mut tree: MerkleTree = MerkleTree::new(3, &temp_dir); - tree.update_message(0, &[0; 64]); - tree.update_message(1, &[1; 64]); - tree.update_message(2, &[2; 64]); - tree.update_message(3, &[3; 64]); - tree.update_message(4, &[4; 64]); - tree.update_message(5, &[5; 64]); - tree.update_message(6, &[6; 64]); - let root = tree.update_message(7, &[7; 64]); + tree.update_message(0, &[0; 64])?; + tree.update_message(1, &[1; 64])?; + tree.update_message(2, &[2; 64])?; + tree.update_message(3, &[3; 64])?; + tree.update_message(4, &[4; 64])?; + tree.update_message(5, &[5; 64])?; + tree.update_message(6, &[6; 64])?; + let root = tree.update_message(7, &[7; 64])?; assert_eq!( "0ef8e14db4762ebddadb23b2225f93ca200a4c9bd37130b4d028c971bbad16b5", @@ -409,4 +415,6 @@ fn basic_interop_update() { assert_eq!(got.0.to_hex().as_str(), expected_segment.0); assert_eq!(got.1.to_hex().as_str(), expected_segment.1) } + + Ok(()) } diff --git a/src/pedersen.rs b/src/pedersen.rs index 6526c8aa..e4b3e4b4 100644 --- a/src/pedersen.rs +++ b/src/pedersen.rs @@ -1,56 +1,75 @@ use acvm::FieldElement; -use super::Barretenberg; +use super::{Barretenberg, Error}; pub(crate) trait Pedersen { - fn compress_native(&self, left: &FieldElement, right: &FieldElement) -> FieldElement; - fn compress_many(&self, inputs: Vec) -> FieldElement; - fn encrypt(&self, inputs: Vec) -> (FieldElement, FieldElement); + fn compress_native( + &self, + left: &FieldElement, + right: &FieldElement, + ) -> Result; + fn compress_many(&self, inputs: Vec) -> Result; + fn encrypt(&self, inputs: Vec) -> Result<(FieldElement, FieldElement), Error>; } #[cfg(feature = "native")] impl Pedersen for Barretenberg { - fn compress_native(&self, left: &FieldElement, right: &FieldElement) -> FieldElement { + fn compress_native( + &self, + left: &FieldElement, + right: &FieldElement, + ) -> Result { let result_bytes = barretenberg_sys::pedersen::compress_native( - left.to_be_bytes().as_slice().try_into().unwrap(), - right.to_be_bytes().as_slice().try_into().unwrap(), + left.to_be_bytes() + .as_slice() + .try_into() + .map_err(|source| Error::FieldElementSlice { source })?, + right + .to_be_bytes() + .as_slice() + .try_into() + .map_err(|source| Error::FieldElementSlice { source })?, ); - FieldElement::from_be_bytes_reduce(&result_bytes) + Ok(FieldElement::from_be_bytes_reduce(&result_bytes)) } #[allow(dead_code)] - fn compress_many(&self, inputs: Vec) -> FieldElement { + fn compress_many(&self, inputs: Vec) -> Result { use super::native::field_to_array; let mut inputs_buf = Vec::new(); for f in inputs { - inputs_buf.push(field_to_array(&f)); + inputs_buf.push(field_to_array(&f)?); } let result_bytes = barretenberg_sys::pedersen::compress_many(&inputs_buf); - FieldElement::from_be_bytes_reduce(&result_bytes) + Ok(FieldElement::from_be_bytes_reduce(&result_bytes)) } - fn encrypt(&self, inputs: Vec) -> (FieldElement, FieldElement) { + fn encrypt(&self, inputs: Vec) -> Result<(FieldElement, FieldElement), Error> { use super::native::field_to_array; let mut inputs_buf = Vec::new(); for f in inputs { - inputs_buf.push(field_to_array(&f)); + inputs_buf.push(field_to_array(&f)?); } let (point_x_bytes, point_y_bytes) = barretenberg_sys::pedersen::encrypt(&inputs_buf); let point_x = FieldElement::from_be_bytes_reduce(&point_x_bytes); let point_y = FieldElement::from_be_bytes_reduce(&point_y_bytes); - (point_x, point_y) + Ok((point_x, point_y)) } } #[cfg(not(feature = "native"))] impl Pedersen for Barretenberg { - fn compress_native(&self, left: &FieldElement, right: &FieldElement) -> FieldElement { + fn compress_native( + &self, + left: &FieldElement, + right: &FieldElement, + ) -> Result { use super::FIELD_BYTES; let lhs_ptr: usize = 0; @@ -63,42 +82,42 @@ impl Pedersen for Barretenberg { self.call_multiple( "pedersen_plookup_compress_fields", vec![&lhs_ptr.into(), &rhs_ptr.into(), &result_ptr.into()], - ); + )?; let result_bytes: [u8; FIELD_BYTES] = self.read_memory(result_ptr); - FieldElement::from_be_bytes_reduce(&result_bytes) + Ok(FieldElement::from_be_bytes_reduce(&result_bytes)) } #[allow(dead_code)] - fn compress_many(&self, inputs: Vec) -> FieldElement { + fn compress_many(&self, inputs: Vec) -> Result { use super::FIELD_BYTES; use crate::barretenberg_structures::Assignments; let input_buf = Assignments::from(inputs).to_bytes(); - let input_ptr = self.allocate(&input_buf); + let input_ptr = self.allocate(&input_buf)?; let result_ptr: usize = 0; self.call_multiple( "pedersen_plookup_compress", vec![&input_ptr, &result_ptr.into()], - ); + )?; let result_bytes: [u8; FIELD_BYTES] = self.read_memory(result_ptr); - FieldElement::from_be_bytes_reduce(&result_bytes) + Ok(FieldElement::from_be_bytes_reduce(&result_bytes)) } - fn encrypt(&self, inputs: Vec) -> (FieldElement, FieldElement) { + fn encrypt(&self, inputs: Vec) -> Result<(FieldElement, FieldElement), Error> { use super::FIELD_BYTES; use crate::barretenberg_structures::Assignments; let input_buf = Assignments::from(inputs).to_bytes(); - let input_ptr = self.allocate(&input_buf); + let input_ptr = self.allocate(&input_buf)?; let result_ptr: usize = 0; self.call_multiple( "pedersen_plookup_commit", vec![&input_ptr, &result_ptr.into()], - ); + )?; let result_bytes: [u8; 2 * FIELD_BYTES] = self.read_memory(result_ptr); let (point_x_bytes, point_y_bytes) = result_bytes.split_at(FIELD_BYTES); @@ -106,12 +125,12 @@ impl Pedersen for Barretenberg { let point_x = FieldElement::from_be_bytes_reduce(point_x_bytes); let point_y = FieldElement::from_be_bytes_reduce(point_y_bytes); - (point_x, point_y) + Ok((point_x, point_y)) } } #[test] -fn basic_interop() { +fn basic_interop() -> Result<(), Error> { // Expected values were taken from Barretenberg by running `crypto::pedersen::compress_native` // printing the result in hex to `std::cout` and copying struct Test<'a> { @@ -142,17 +161,18 @@ fn basic_interop() { for test in tests { let expected = FieldElement::from_hex(test.expected_hex).unwrap(); - let got = barretenberg.compress_native(&test.input_left, &test.input_right); - let got_many = barretenberg.compress_many(vec![test.input_left, test.input_right]); + let got = barretenberg.compress_native(&test.input_left, &test.input_right)?; + let got_many = barretenberg.compress_many(vec![test.input_left, test.input_right])?; assert_eq!(got, expected); assert_eq!(got, got_many); } + Ok(()) } #[test] -fn pedersen_hash_to_point() { +fn pedersen_hash_to_point() -> Result<(), Error> { let barretenberg = Barretenberg::new(); - let (x, y) = barretenberg.encrypt(vec![FieldElement::zero(), FieldElement::one()]); + let (x, y) = barretenberg.encrypt(vec![FieldElement::zero(), FieldElement::one()])?; let expected_x = FieldElement::from_hex( "0x11831f49876c313f2a9ec6d8d521c7ce0b6311c852117e340bfe27fd1ac096ef", ) @@ -164,4 +184,5 @@ fn pedersen_hash_to_point() { assert_eq!(expected_x.to_hex(), x.to_hex()); assert_eq!(expected_y.to_hex(), y.to_hex()); + Ok(()) } diff --git a/src/pippenger.rs b/src/pippenger.rs index 66e05fa8..b15d80b9 100644 --- a/src/pippenger.rs +++ b/src/pippenger.rs @@ -1,4 +1,4 @@ -use crate::Barretenberg; +use crate::{Barretenberg, Error}; pub(crate) struct Pippenger { #[cfg(feature = "native")] @@ -23,26 +23,29 @@ impl Pippenger { #[cfg(feature = "native")] impl Barretenberg { - pub(crate) fn get_pippenger(&self, crs_data: &[u8]) -> Pippenger { + pub(crate) fn get_pippenger(&self, crs_data: &[u8]) -> Result { let pippenger_ptr = barretenberg_sys::pippenger::new(crs_data); - Pippenger { pippenger_ptr } + Ok(Pippenger { pippenger_ptr }) } } #[cfg(not(feature = "native"))] impl Barretenberg { - pub(crate) fn get_pippenger(&self, crs_data: &[u8]) -> Pippenger { + pub(crate) fn get_pippenger(&self, crs_data: &[u8]) -> Result { use super::FIELD_BYTES; let num_points = crs_data.len() / (2 * FIELD_BYTES); - let crs_ptr = self.allocate(crs_data); + let crs_ptr = self.allocate(crs_data)?; + // This doesn't unwrap the result because we need to free even if there is a failure let pippenger_ptr = self.call_multiple("new_pippenger", vec![&crs_ptr, &num_points.into()]); - self.free(crs_ptr); + self.free(crs_ptr)?; - Pippenger { pippenger_ptr } + Ok(Pippenger { + pippenger_ptr: pippenger_ptr?.value()?, + }) } } diff --git a/src/scalar_mul.rs b/src/scalar_mul.rs index 838c957d..af5e10ea 100644 --- a/src/scalar_mul.rs +++ b/src/scalar_mul.rs @@ -1,17 +1,17 @@ use acvm::FieldElement; -use super::{Barretenberg, FIELD_BYTES}; +use super::{Barretenberg, Error, FIELD_BYTES}; pub(crate) trait ScalarMul { - fn fixed_base(&self, input: &FieldElement) -> (FieldElement, FieldElement); + fn fixed_base(&self, input: &FieldElement) -> Result<(FieldElement, FieldElement), Error>; } #[cfg(feature = "native")] impl ScalarMul for Barretenberg { - fn fixed_base(&self, input: &FieldElement) -> (FieldElement, FieldElement) { + fn fixed_base(&self, input: &FieldElement) -> Result<(FieldElement, FieldElement), Error> { use super::native::field_to_array; - let result_bytes = barretenberg_sys::schnorr::construct_public_key(&field_to_array(input)); + let result_bytes = barretenberg_sys::schnorr::construct_public_key(&field_to_array(input)?); let (pubkey_x_bytes, pubkey_y_bytes) = result_bytes.split_at(FIELD_BYTES); assert!(pubkey_x_bytes.len() == FIELD_BYTES); @@ -19,13 +19,13 @@ impl ScalarMul for Barretenberg { let pubkey_x = FieldElement::from_be_bytes_reduce(pubkey_x_bytes); let pubkey_y = FieldElement::from_be_bytes_reduce(pubkey_y_bytes); - (pubkey_x, pubkey_y) + Ok((pubkey_x, pubkey_y)) } } #[cfg(not(feature = "native"))] impl ScalarMul for Barretenberg { - fn fixed_base(&self, input: &FieldElement) -> (FieldElement, FieldElement) { + fn fixed_base(&self, input: &FieldElement) -> Result<(FieldElement, FieldElement), Error> { let lhs_ptr: usize = 0; let result_ptr: usize = lhs_ptr + FIELD_BYTES; self.transfer_to_heap(&input.to_be_bytes(), lhs_ptr); @@ -33,7 +33,7 @@ impl ScalarMul for Barretenberg { self.call_multiple( "compute_public_key", vec![&lhs_ptr.into(), &result_ptr.into()], - ); + )?; let result_bytes: [u8; 2 * FIELD_BYTES] = self.read_memory(result_ptr); let (pubkey_x_bytes, pubkey_y_bytes) = result_bytes.split_at(FIELD_BYTES); @@ -43,7 +43,7 @@ impl ScalarMul for Barretenberg { let pubkey_x = FieldElement::from_be_bytes_reduce(pubkey_x_bytes); let pubkey_y = FieldElement::from_be_bytes_reduce(pubkey_y_bytes); - (pubkey_x, pubkey_y) + Ok((pubkey_x, pubkey_y)) } } @@ -51,15 +51,16 @@ impl ScalarMul for Barretenberg { mod test { use super::*; #[test] - fn smoke_test() { + fn smoke_test() -> Result<(), Error> { let barretenberg = Barretenberg::new(); let input = FieldElement::one(); - let res = barretenberg.fixed_base(&input); + let res = barretenberg.fixed_base(&input)?; let x = "0000000000000000000000000000000000000000000000000000000000000001"; let y = "0000000000000002cf135e7506a45d632d270d45f1181294833fc48d823f272c"; assert_eq!(x, res.0.to_hex()); assert_eq!(y, res.1.to_hex()); + Ok(()) } } diff --git a/src/schnorr.rs b/src/schnorr.rs index d58affd8..4a690063 100644 --- a/src/schnorr.rs +++ b/src/schnorr.rs @@ -1,31 +1,57 @@ -use super::Barretenberg; +use super::{Barretenberg, Error}; pub(crate) trait SchnorrSig { - fn construct_signature(&self, message: &[u8], private_key: [u8; 32]) -> [u8; 64]; - fn construct_public_key(&self, private_key: [u8; 32]) -> [u8; 64]; - fn verify_signature(&self, pub_key: [u8; 64], sig: [u8; 64], message: &[u8]) -> bool; + fn construct_signature(&self, message: &[u8], private_key: [u8; 32]) + -> Result<[u8; 64], Error>; + fn construct_public_key(&self, private_key: [u8; 32]) -> Result<[u8; 64], Error>; + fn verify_signature( + &self, + pub_key: [u8; 64], + sig: [u8; 64], + message: &[u8], + ) -> Result; } #[cfg(feature = "native")] impl SchnorrSig for Barretenberg { - fn construct_signature(&self, message: &[u8], private_key: [u8; 32]) -> [u8; 64] { + fn construct_signature( + &self, + message: &[u8], + private_key: [u8; 32], + ) -> Result<[u8; 64], Error> { let (sig_s, sig_e) = barretenberg_sys::schnorr::construct_signature(message, private_key); - let sig_bytes: [u8; 64] = [sig_s, sig_e].concat().try_into().unwrap(); - sig_bytes + let sig_bytes: [u8; 64] = [sig_s, sig_e] + .concat() + .try_into() + .map_err(Error::SchnorrConvert)?; + Ok(sig_bytes) } - fn construct_public_key(&self, private_key: [u8; 32]) -> [u8; 64] { - barretenberg_sys::schnorr::construct_public_key(&private_key) + fn construct_public_key(&self, private_key: [u8; 32]) -> Result<[u8; 64], Error> { + Ok(barretenberg_sys::schnorr::construct_public_key( + &private_key, + )) } - fn verify_signature(&self, pub_key: [u8; 64], sig: [u8; 64], message: &[u8]) -> bool { + fn verify_signature( + &self, + pub_key: [u8; 64], + sig: [u8; 64], + message: &[u8], + ) -> Result { let (sig_s, sig_e) = sig.split_at(32); - let sig_s: [u8; 32] = sig_s.try_into().unwrap(); - let sig_e: [u8; 32] = sig_e.try_into().unwrap(); + let sig_s: [u8; 32] = sig_s + .try_into() + .map_err(|source| Error::SchnorrSlice { source })?; + let sig_e: [u8; 32] = sig_e + .try_into() + .map_err(|source| Error::SchnorrSlice { source })?; - barretenberg_sys::schnorr::verify_signature(pub_key, sig_s, sig_e, message) + Ok(barretenberg_sys::schnorr::verify_signature( + pub_key, sig_s, sig_e, message, + )) // Note, currently for Barretenberg plonk, if the signature fails // then the whole circuit fails. @@ -34,7 +60,11 @@ impl SchnorrSig for Barretenberg { #[cfg(not(feature = "native"))] impl SchnorrSig for Barretenberg { - fn construct_signature(&self, message: &[u8], private_key: [u8; 32]) -> [u8; 64] { + fn construct_signature( + &self, + message: &[u8], + private_key: [u8; 32], + ) -> Result<[u8; 64], Error> { use super::{wasm::WASM_SCRATCH_BYTES, FIELD_BYTES}; let sig_s_ptr: usize = 0; @@ -57,17 +87,20 @@ impl SchnorrSig for Barretenberg { &sig_s_ptr.into(), &sig_e_ptr.into(), ], - ); + )?; let sig_s: [u8; FIELD_BYTES] = self.read_memory(sig_s_ptr); let sig_e: [u8; FIELD_BYTES] = self.read_memory(sig_e_ptr); - let sig_bytes: [u8; 64] = [sig_s, sig_e].concat().try_into().unwrap(); - sig_bytes + let sig_bytes: [u8; 64] = [sig_s, sig_e] + .concat() + .try_into() + .map_err(Error::SchnorrConvert)?; + Ok(sig_bytes) } #[allow(dead_code)] - fn construct_public_key(&self, private_key: [u8; 32]) -> [u8; 64] { + fn construct_public_key(&self, private_key: [u8; 32]) -> Result<[u8; 64], Error> { use super::FIELD_BYTES; let private_key_ptr: usize = 0; @@ -78,12 +111,17 @@ impl SchnorrSig for Barretenberg { self.call_multiple( "compute_public_key", vec![&private_key_ptr.into(), &result_ptr.into()], - ); + )?; self.read_memory(result_ptr) } - fn verify_signature(&self, pub_key: [u8; 64], sig: [u8; 64], message: &[u8]) -> bool { + fn verify_signature( + &self, + pub_key: [u8; 64], + sig: [u8; 64], + message: &[u8], + ) -> Result { use super::{wasm::WASM_SCRATCH_BYTES, FIELD_BYTES}; let (sig_s, sig_e) = sig.split_at(FIELD_BYTES); @@ -111,34 +149,34 @@ impl SchnorrSig for Barretenberg { &sig_s_ptr.into(), &sig_e_ptr.into(), ], - ); + )?; - wasm_value.bool() // Note, currently for Barretenberg plonk, if the signature fails // then the whole circuit fails. + wasm_value.bool() } } #[test] -fn basic_interop() { +fn basic_interop() -> Result<(), Error> { let barretenberg = Barretenberg::new(); // First case should pass, standard procedure for Schnorr let private_key = [2; 32]; let message = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - let public_key = barretenberg.construct_public_key(private_key); - let signature = barretenberg.construct_signature(&message, private_key); - let valid_signature = barretenberg.verify_signature(public_key, signature, &message); + let public_key = barretenberg.construct_public_key(private_key)?; + let signature = barretenberg.construct_signature(&message, private_key)?; + let valid_signature = barretenberg.verify_signature(public_key, signature, &message)?; assert!(valid_signature); // Should fail, since the messages are different let private_key = [2; 32]; let message = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - let public_key = barretenberg.construct_public_key(private_key); - let signature = barretenberg.construct_signature(&message, private_key); - let valid_signature = barretenberg.verify_signature(public_key, signature, &[0, 2]); + let public_key = barretenberg.construct_public_key(private_key)?; + let signature = barretenberg.construct_signature(&message, private_key)?; + let valid_signature = barretenberg.verify_signature(public_key, signature, &[0, 2])?; assert!(!valid_signature); // Should fail, since the signature is not valid @@ -146,8 +184,8 @@ fn basic_interop() { let message = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; let signature = [1; 64]; - let public_key = barretenberg.construct_public_key(private_key); - let valid_signature = barretenberg.verify_signature(public_key, signature, &message); + let public_key = barretenberg.construct_public_key(private_key)?; + let valid_signature = barretenberg.verify_signature(public_key, signature, &message)?; assert!(!valid_signature); // Should fail, since the public key does not match @@ -155,17 +193,18 @@ fn basic_interop() { let private_key_b = [2; 32]; let message = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - let public_key_b = barretenberg.construct_public_key(private_key_b); - let signature_a = barretenberg.construct_signature(&message, private_key_a); - let valid_signature = barretenberg.verify_signature(public_key_b, signature_a, &message); + let public_key_b = barretenberg.construct_public_key(private_key_b)?; + let signature_a = barretenberg.construct_signature(&message, private_key_a)?; + let valid_signature = barretenberg.verify_signature(public_key_b, signature_a, &message)?; assert!(!valid_signature); // Test the first case again, to check if memory is being freed and overwritten properly let private_key = [2; 32]; let message = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - let public_key = barretenberg.construct_public_key(private_key); - let signature = barretenberg.construct_signature(&message, private_key); - let valid_signature = barretenberg.verify_signature(public_key, signature, &message); + let public_key = barretenberg.construct_public_key(private_key)?; + let signature = barretenberg.construct_signature(&message, private_key)?; + let valid_signature = barretenberg.verify_signature(public_key, signature, &message)?; assert!(valid_signature); + Ok(()) } From a9035f7eb81319b5e54546404d6101b095acbf19 Mon Sep 17 00:00:00 2001 From: Blaine Bublitz Date: Thu, 4 May 2023 15:13:56 -0700 Subject: [PATCH 02/19] Update to acvm 0.11 --- Cargo.lock | 21 +++++++++++------- Cargo.toml | 5 +---- src/acvm_interop/pwg.rs | 49 ++++++++++++++++++++++++++--------------- 3 files changed, 45 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0a0e24a2..dd5ea760 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,8 +4,9 @@ version = 3 [[package]] name = "acir" -version = "0.10.3" -source = "git+https://github.com/noir-lang/acvm?rev=ba79379b4087a51a027f991ba6f7e6dff9c1c2a7#ba79379b4087a51a027f991ba6f7e6dff9c1c2a7" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "084577e67b44c72d1cdfabe286d48adac6f5e0ad441ef134c5c467f4b6eee291" dependencies = [ "acir_field", "flate2", @@ -15,8 +16,9 @@ dependencies = [ [[package]] name = "acir_field" -version = "0.10.3" -source = "git+https://github.com/noir-lang/acvm?rev=ba79379b4087a51a027f991ba6f7e6dff9c1c2a7#ba79379b4087a51a027f991ba6f7e6dff9c1c2a7" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a267ef529f4b132293199ecdf8c232ade817f01d916039f2d34562cab39e75e9" dependencies = [ "ark-bn254", "ark-ff", @@ -28,8 +30,9 @@ dependencies = [ [[package]] name = "acvm" -version = "0.10.3" -source = "git+https://github.com/noir-lang/acvm?rev=ba79379b4087a51a027f991ba6f7e6dff9c1c2a7#ba79379b4087a51a027f991ba6f7e6dff9c1c2a7" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e1d6795105b50b13fa0dd1779b5191c4d8e9cd98b357b0b9a0b04a847baacf0" dependencies = [ "acir", "acvm_stdlib", @@ -40,6 +43,7 @@ dependencies = [ "num-bigint", "num-traits", "sha2 0.9.9", + "sha3", "thiserror", ] @@ -67,8 +71,9 @@ dependencies = [ [[package]] name = "acvm_stdlib" -version = "0.10.3" -source = "git+https://github.com/noir-lang/acvm?rev=ba79379b4087a51a027f991ba6f7e6dff9c1c2a7#ba79379b4087a51a027f991ba6f7e6dff9c1c2a7" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3131af53d17ac12340c0ff50f8555d8e040321f8078b8ee3cd8846560b6a44a9" dependencies = [ "acir", ] diff --git a/Cargo.toml b/Cargo.toml index 7ce9aaa3..9c54f787 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -acvm = { version = "0.10.3", features = ["bn254"] } +acvm = { version = "0.11.0", features = ["bn254"] } thiserror = "1.0.21" blake2 = "0.9.1" @@ -68,6 +68,3 @@ wasm = [ "dep:indicatif", ] js = ["wasmer", "dep:rust-embed", "dep:getrandom", "wasmer/js-default"] - -[patch.crates-io] -acvm = { package = "acvm", git = "https://github.com/noir-lang/acvm", rev = "ba79379b4087a51a027f991ba6f7e6dff9c1c2a7" } diff --git a/src/acvm_interop/pwg.rs b/src/acvm_interop/pwg.rs index 2fd41e71..6ad44134 100644 --- a/src/acvm_interop/pwg.rs +++ b/src/acvm_interop/pwg.rs @@ -55,7 +55,9 @@ impl PartialWitnessGenerator for Barretenberg { index, leaf, ) - .map_err(|err| OpcodeResolutionError::OpcodeSolveFailed(err.to_string()))?; + .map_err(|err| { + OpcodeResolutionError::BlackBoxFunctionFailed(func_call.name, err.to_string()) + })?; initial_witness.insert(func_call.outputs[0], computed_merkle_root); Ok(OpcodeResolution::Solved) @@ -84,23 +86,26 @@ impl PartialWitnessGenerator for Barretenberg { .chain(pub_key_y.to_vec()) .collect(); let pub_key: [u8; 64] = pub_key_bytes.try_into().map_err(|v: Vec| { - OpcodeResolutionError::OpcodeSolveFailed(format!( - "expected pubkey size {} but received {}", - 64, - v.len() - )) + OpcodeResolutionError::BlackBoxFunctionFailed( + func_call.name, + format!("expected pubkey size {} but received {}", 64, v.len()), + ) })?; let mut signature = [0u8; 64]; for (i, sig) in signature.iter_mut().enumerate() { let _sig_i = inputs_iter.next().ok_or_else(|| { - OpcodeResolutionError::OpcodeSolveFailed(format!( - "signature should be 64 bytes long, found only {i} bytes" - )) + OpcodeResolutionError::BlackBoxFunctionFailed( + func_call.name, + format!("signature should be 64 bytes long, found only {i} bytes"), + ) })?; let sig_i = witness_to_value(initial_witness, _sig_i.witness)?; *sig = *sig_i.to_be_bytes().last().ok_or_else(|| { - OpcodeResolutionError::OpcodeSolveFailed("could not get last bytes".into()) + OpcodeResolutionError::BlackBoxFunctionFailed( + func_call.name, + "could not get last bytes".into(), + ) })?; } @@ -108,14 +113,22 @@ impl PartialWitnessGenerator for Barretenberg { for msg in inputs_iter { let msg_i_field = witness_to_value(initial_witness, msg.witness)?; let msg_i = *msg_i_field.to_be_bytes().last().ok_or_else(|| { - OpcodeResolutionError::OpcodeSolveFailed("could not get last bytes".into()) + OpcodeResolutionError::BlackBoxFunctionFailed( + func_call.name, + "could not get last bytes".into(), + ) })?; message.push(msg_i); } let valid_signature = self .verify_signature(pub_key, signature, &message) - .map_err(|err| OpcodeResolutionError::OpcodeSolveFailed(err.to_string()))?; + .map_err(|err| { + OpcodeResolutionError::BlackBoxFunctionFailed( + func_call.name, + err.to_string(), + ) + })?; if !valid_signature { dbg!("signature has failed to verify"); } @@ -137,9 +150,9 @@ impl PartialWitnessGenerator for Barretenberg { .collect(); let scalars: Vec<_> = scalars?.into_iter().cloned().collect(); - let (res_x, res_y) = self - .encrypt(scalars) - .map_err(|err| OpcodeResolutionError::OpcodeSolveFailed(err.to_string()))?; + let (res_x, res_y) = self.encrypt(scalars).map_err(|err| { + OpcodeResolutionError::BlackBoxFunctionFailed(func_call.name, err.to_string()) + })?; initial_witness.insert(func_call.outputs[0], res_x); initial_witness.insert(func_call.outputs[1], res_y); Ok(OpcodeResolution::Solved) @@ -169,9 +182,9 @@ impl PartialWitnessGenerator for Barretenberg { BlackBoxFunc::FixedBaseScalarMul => { let scalar = witness_to_value(initial_witness, func_call.inputs[0].witness)?; - let (pub_x, pub_y) = self - .fixed_base(scalar) - .map_err(|err| OpcodeResolutionError::OpcodeSolveFailed(err.to_string()))?; + let (pub_x, pub_y) = self.fixed_base(scalar).map_err(|err| { + OpcodeResolutionError::BlackBoxFunctionFailed(func_call.name, err.to_string()) + })?; initial_witness.insert(func_call.outputs[0], pub_x); initial_witness.insert(func_call.outputs[1], pub_y); From 142542527362b9d89a86085c635a19a35e687d07 Mon Sep 17 00:00:00 2001 From: Blaine Bublitz Date: Thu, 4 May 2023 15:51:28 -0700 Subject: [PATCH 03/19] implement TryFrom for circuit and bubble errors --- src/acvm_interop/proof_system.rs | 8 ++-- src/barretenberg_structures.rs | 65 +++++++++++++------------------- 2 files changed, 31 insertions(+), 42 deletions(-) diff --git a/src/acvm_interop/proof_system.rs b/src/acvm_interop/proof_system.rs index e6948036..92389c6d 100644 --- a/src/acvm_interop/proof_system.rs +++ b/src/acvm_interop/proof_system.rs @@ -15,7 +15,7 @@ impl ProofSystemCompiler for Barretenberg { } fn get_exact_circuit_size(&self, circuit: &Circuit) -> Result { - Composer::get_exact_circuit_size(self, &circuit.into()) + Composer::get_exact_circuit_size(self, &circuit.try_into()?) } fn black_box_function_supported(&self, opcode: &BlackBoxFunc) -> bool { @@ -38,7 +38,7 @@ impl ProofSystemCompiler for Barretenberg { } fn preprocess(&self, circuit: &Circuit) -> Result<(Vec, Vec), Error> { - let constraint_system = &circuit.into(); + let constraint_system = &circuit.try_into()?; let proving_key = self.compute_proving_key(constraint_system)?; let verification_key = self.compute_verification_key(constraint_system, &proving_key)?; @@ -54,7 +54,7 @@ impl ProofSystemCompiler for Barretenberg { ) -> Result, Error> { let assignments = flatten_witness_map(circuit, witness_values); - self.create_proof_with_pk(&circuit.into(), assignments, proving_key) + self.create_proof_with_pk(&circuit.try_into()?, assignments, proving_key) } fn verify_with_vk( @@ -70,7 +70,7 @@ impl ProofSystemCompiler for Barretenberg { Composer::verify_with_vk( self, - &circuit.into(), + &circuit.try_into()?, proof, flattened_public_inputs.into(), verification_key, diff --git a/src/barretenberg_structures.rs b/src/barretenberg_structures.rs index 0a4bb276..2758e446 100644 --- a/src/barretenberg_structures.rs +++ b/src/barretenberg_structures.rs @@ -3,6 +3,8 @@ use acvm::acir::native_types::Expression; use acvm::acir::BlackBoxFunc; use acvm::FieldElement; +use crate::Error; + #[derive(Debug, Default, Clone)] pub(crate) struct Assignments(Vec); @@ -643,10 +645,11 @@ impl ConstraintSystem { } } -// TODO: TryFrom -impl From<&Circuit> for ConstraintSystem { +impl TryFrom<&Circuit> for ConstraintSystem { + type Error = Error; + /// Converts an `IR` into the `StandardFormat` constraint system - fn from(circuit: &Circuit) -> Self { + fn try_from(circuit: &Circuit) -> Result { // Create constraint system let mut constraints: Vec = Vec::new(); let mut range_constraints: Vec = Vec::new(); @@ -731,11 +734,8 @@ impl From<&Circuit> for ConstraintSystem { let mut outputs_iter = gadget_call.outputs.iter(); let mut result = [0i32; 32]; for (i, res) in result.iter_mut().enumerate() { - let out_byte = outputs_iter.next().unwrap_or_else(|| { - panic!( - "missing rest of output. Tried to get byte {i} but failed" - ) - }); + let out_byte = + outputs_iter.next().ok_or(Error::MissingOutput(i))?; let out_byte_index = out_byte.witness_index() as i32; *res = out_byte_index @@ -760,11 +760,8 @@ impl From<&Circuit> for ConstraintSystem { let mut outputs_iter = gadget_call.outputs.iter(); let mut result = [0i32; 32]; for (i, res) in result.iter_mut().enumerate() { - let out_byte = outputs_iter.next().unwrap_or_else(|| { - panic!( - "missing rest of output. Tried to get byte {i} but failed" - ) - }); + let out_byte = + outputs_iter.next().ok_or(Error::MissingOutput(i))?; let out_byte_index = out_byte.witness_index() as i32; *res = out_byte_index @@ -781,15 +778,13 @@ impl From<&Circuit> for ConstraintSystem { // leaf let leaf = { - let leaf_input = inputs_iter - .next() - .expect("missing leaf to check membership for"); + let leaf_input = inputs_iter.next().ok_or(Error::MissingLeaf)?; leaf_input.witness.witness_index() as i32 }; // index let index = { let index_input = - inputs_iter.next().expect("missing index for leaf"); + inputs_iter.next().ok_or(Error::MissingLeafIndex)?; index_input.witness.witness_index() as i32 }; @@ -821,26 +816,21 @@ impl From<&Circuit> for ConstraintSystem { // pub_key_x let public_key_x = { - let pub_key_x = inputs_iter - .next() - .expect("missing `x` component for public key"); + let pub_key_x = + inputs_iter.next().ok_or(Error::MissingPublicKeyX)?; pub_key_x.witness.witness_index() as i32 }; // pub_key_y let public_key_y = { - let pub_key_y = inputs_iter - .next() - .expect("missing `y` component for public key"); + let pub_key_y = + inputs_iter.next().ok_or(Error::MissingPublicKeyY)?; pub_key_y.witness.witness_index() as i32 }; // signature let mut signature = [0i32; 64]; for (i, sig) in signature.iter_mut().enumerate() { - let sig_byte = inputs_iter.next().unwrap_or_else(|| { - panic!( - "missing rest of signature. Tried to get byte {i} but failed", - ) - }); + let sig_byte = + inputs_iter.next().ok_or(Error::MissingSignature(i))?; let sig_byte_index = sig_byte.witness.witness_index() as i32; *sig = sig_byte_index } @@ -908,7 +898,8 @@ impl From<&Circuit> for ConstraintSystem { // public key x let mut public_key_x = [0i32; 32]; for (i, pkx) in public_key_x.iter_mut().enumerate() { - let x_byte = inputs_iter.next().unwrap_or_else(|| panic!("missing rest of x component for public key. Tried to get byte {i} but failed")); + let x_byte = + inputs_iter.next().ok_or(Error::MissingPublicKey("x", i))?; let x_byte_index = x_byte.witness.witness_index() as i32; *pkx = x_byte_index; } @@ -916,7 +907,8 @@ impl From<&Circuit> for ConstraintSystem { // public key y let mut public_key_y = [0i32; 32]; for (i, pky) in public_key_y.iter_mut().enumerate() { - let y_byte = inputs_iter.next().unwrap_or_else(|| panic!("missing rest of y component for public key. Tried to get byte {i} but failed")); + let y_byte = + inputs_iter.next().ok_or(Error::MissingPublicKey("y", i))?; let y_byte_index = y_byte.witness.witness_index() as i32; *pky = y_byte_index; } @@ -924,11 +916,8 @@ impl From<&Circuit> for ConstraintSystem { // signature let mut signature = [0i32; 64]; for (i, sig) in signature.iter_mut().enumerate() { - let sig_byte = inputs_iter.next().unwrap_or_else(|| { - panic!( - "missing rest of signature. Tried to get byte {i} but failed", - ) - }); + let sig_byte = + inputs_iter.next().ok_or(Error::MissingSignature(i))?; let sig_byte_index = sig_byte.witness.witness_index() as i32; *sig = sig_byte_index; } @@ -998,7 +987,7 @@ impl From<&Circuit> for ConstraintSystem { keccak_constraints.push(keccak_constraint); } - BlackBoxFunc::AES => panic!("AES has not yet been implemented"), + BlackBoxFunc::AES => return Err(Error::Aes), }; } Opcode::Directive(_) | Opcode::Oracle(_) => { @@ -1011,7 +1000,7 @@ impl From<&Circuit> for ConstraintSystem { } // Create constraint system - ConstraintSystem { + Ok(ConstraintSystem { var_num: circuit.current_witness_index + 1, // number of witnesses is the witness index + 1; public_inputs: circuit.public_inputs().indices(), logic_constraints, @@ -1026,7 +1015,7 @@ impl From<&Circuit> for ConstraintSystem { hash_to_field_constraints, constraints, fixed_base_scalar_mul_constraints, - } + }) } } From 24f25cadb7ce8f35556d27378acb695cd9ee0cdc Mon Sep 17 00:00:00 2001 From: Blaine Bublitz Date: Thu, 4 May 2023 15:51:56 -0700 Subject: [PATCH 04/19] split wasm errors into a separate enum and handle transparently --- src/composer.rs | 8 +++- src/lib.rs | 113 +++++++++++++++++++++++++++++++++--------------- src/schnorr.rs | 4 +- 3 files changed, 87 insertions(+), 38 deletions(-) diff --git a/src/composer.rs b/src/composer.rs index 1befea57..d7c2c889 100644 --- a/src/composer.rs +++ b/src/composer.rs @@ -232,7 +232,9 @@ impl Composer for Barretenberg { self.free(cs_ptr)?; - circuit_size?.u32() + let size = circuit_size?.u32()?; + + Ok(size) } fn compute_proving_key(&self, constraint_system: &ConstraintSystem) -> Result, Error> { @@ -368,7 +370,9 @@ impl Composer for Barretenberg { self.free(proof_ptr)?; - verified?.bool() + let verified = verified?.bool()?; + + Ok(verified) } } diff --git a/src/lib.rs b/src/lib.rs index c695ed06..a3704188 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,10 +20,43 @@ mod pippenger; mod scalar_mul; mod schnorr; -use std::{array::TryFromSliceError, num::TryFromIntError}; +use std::array::TryFromSliceError; use thiserror::Error; +// There are no WasmErrors on native +#[cfg(feature = "native")] +#[derive(Debug, Error)] +pub enum WasmError {} + +#[cfg(not(feature = "native"))] +#[derive(Debug, Error)] +pub enum WasmError { + #[error("Trying to call {name} resulted in an error")] + FunctionCallFailed { + name: String, + source: wasmer::RuntimeError, + }, + #[error("Could not find function export named {name}")] + InvalidExport { + name: String, + source: wasmer::ExportError, + }, + #[error("No value available when value was expected")] + NoValue, + #[error("Value expected to be i32")] + InvalidI32, + #[error("Could not convert value {value} from i32 to u32")] + InvalidU32 { + value: i32, + source: std::num::TryFromIntError, + }, + #[error("Value expected to be 0 or 1 representing a boolean")] + InvalidBool, + #[error("Failed to get pointer")] + InvalidPointer { source: TryFromSliceError }, +} + #[derive(Debug, Error)] pub enum Error { #[error("The value {0} overflows in the pow2ceil function")] @@ -36,20 +69,28 @@ pub enum Error { FieldElementSlice { source: TryFromSliceError }, #[error("Expected a Vec of length {0} but it was {1}")] FieldToArray(usize, usize), - #[error("Trying to call {0} resulted in an error")] - WasmFunctionCall(String), - #[error("Could not find function export named {0}")] - WasmInvalidExport(String), - #[error("No value available when value was expected")] - WasmNoValue, - #[error("Value expected to be i32")] - WasmInvalidI32, - #[error("Could not convert value {value} from i32 to u32")] - WasmInvalidU32 { value: i32, source: TryFromIntError }, - #[error("Value expected to be 0 or 1 representing a boolean")] - WasmInvalidBool, - #[error("Failed to get pointer")] - WasmInvalidPointer { source: TryFromSliceError }, + + #[error("Missing rest of output. Tried to get byte {0} but failed")] + MissingOutput(usize), + #[error("Missing leaf to check membership for")] + MissingLeaf, + #[error("Missing index for leaf")] + MissingLeafIndex, + #[error("Missing `x` component for public key")] + MissingPublicKeyX, + #[error("Missing `y` component for public key")] + MissingPublicKeyY, + #[error("Missing rest of signature. Tried to get byte {0} but failed")] + MissingSignature(usize), + #[error("Missing rest of {0} component for public key. Tried to get byte {1} but failed")] + MissingPublicKey(&'static str, usize), + #[error("Keccak256 has not yet been implemented")] + Keccak256, + #[error("AES has not yet been implemented")] + Aes, + + #[error(transparent)] + WasmError(#[from] WasmError), } /// The number of bytes necessary to store a `FieldElement`. @@ -104,7 +145,7 @@ mod wasm { use wasmer::{imports, Function, Instance, Memory, MemoryType, Module, Store, Value}; use super::Barretenberg; - use super::Error; + use super::{Error, WasmError}; /// The number of bytes necessary to represent a pointer to memory inside the wasm. pub(super) const POINTER_BYTES: usize = 4; @@ -143,23 +184,23 @@ mod wasm { pub(super) struct WASMValue(Option); impl WASMValue { - pub(super) fn value(self) -> Result { - self.0.ok_or(Error::WasmNoValue) + pub(super) fn value(self) -> Result { + self.0.ok_or(WasmError::NoValue) } - pub(super) fn i32(self) -> Result { + pub(super) fn i32(self) -> Result { self.0 .and_then(|val| val.i32()) - .ok_or(Error::WasmInvalidI32) + .ok_or(WasmError::InvalidI32) } - pub(super) fn u32(self) -> Result { + pub(super) fn u32(self) -> Result { let value = self.i32()?; - u32::try_from(value).map_err(|source| Error::WasmInvalidU32 { value, source }) + u32::try_from(value).map_err(|source| WasmError::InvalidU32 { value, source }) } - pub(super) fn bool(self) -> Result { + pub(super) fn bool(self) -> Result { match self.i32() { Ok(0) => Ok(false), Ok(1) => Ok(true), - _ => Err(Error::WasmInvalidBool), + _ => Err(WasmError::InvalidBool), } } } @@ -265,7 +306,7 @@ mod wasm { Ok(u32::from_le_bytes( ptr[0..POINTER_BYTES] .try_into() - .map_err(|source| Error::WasmInvalidPointer { source })?, + .map_err(|source| WasmError::InvalidPointer { source })?, ) as usize) } @@ -282,16 +323,18 @@ mod wasm { // We then clone them inside of this function, so that the API does not have a bunch of Clones everywhere let params: Vec = params.into_iter().cloned().map(|val| val.into()).collect(); - let func = self - .instance - .exports - .get_function(name) - // We ignore this source error so the Error enum doesn't need to depend on Wasmer - .map_err(|_source| Error::WasmInvalidExport(name.to_string()))?; - let boxed_value = func - .call(¶ms) - // We ignore this source error so the Error enum doesn't need to depend on Wasmer - .map_err(|_source| Error::WasmFunctionCall(name.to_string()))?; + let func = self.instance.exports.get_function(name).map_err(|source| { + WasmError::InvalidExport { + name: name.to_string(), + source, + } + })?; + let boxed_value = + func.call(¶ms) + .map_err(|source| WasmError::FunctionCallFailed { + name: name.to_string(), + source, + })?; let option_value = boxed_value.first().cloned(); Ok(WASMValue(option_value)) diff --git a/src/schnorr.rs b/src/schnorr.rs index 4a690063..83b73a12 100644 --- a/src/schnorr.rs +++ b/src/schnorr.rs @@ -153,7 +153,9 @@ impl SchnorrSig for Barretenberg { // Note, currently for Barretenberg plonk, if the signature fails // then the whole circuit fails. - wasm_value.bool() + let verified = wasm_value.bool()?; + + Ok(verified) } } From fe2679feb22dfa28dbad31da0ed90f3b40fc4dbb Mon Sep 17 00:00:00 2001 From: Blaine Bublitz Date: Thu, 4 May 2023 16:04:31 -0700 Subject: [PATCH 05/19] try_into for Value --- src/lib.rs | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a3704188..36282c1b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -223,10 +223,11 @@ mod wasm { } } - // TODO: try_into - impl From for Value { - fn from(value: WASMValue) -> Self { - value.0.unwrap() + impl TryFrom for Value { + type Error = WasmError; + + fn try_from(x: WASMValue) -> Result { + x.value() } pub(super) fn bool(self) -> bool { @@ -322,19 +323,22 @@ mod wasm { // We take in a reference to values, since they do not implement Copy. // We then clone them inside of this function, so that the API does not have a bunch of Clones everywhere - let params: Vec = params.into_iter().cloned().map(|val| val.into()).collect(); + let mut args: Vec = vec![]; + for param in params.into_iter().cloned() { + args.push(param.try_into()?) + } let func = self.instance.exports.get_function(name).map_err(|source| { WasmError::InvalidExport { name: name.to_string(), source, } })?; - let boxed_value = - func.call(¶ms) - .map_err(|source| WasmError::FunctionCallFailed { - name: name.to_string(), - source, - })?; + let boxed_value = func + .call(&args) + .map_err(|source| WasmError::FunctionCallFailed { + name: name.to_string(), + source, + })?; let option_value = boxed_value.first().cloned(); Ok(WASMValue(option_value)) From e97ae0f7ead7b1472f7d06a5b617d1253dee327f Mon Sep 17 00:00:00 2001 From: Blaine Bublitz Date: Fri, 5 May 2023 10:53:48 -0700 Subject: [PATCH 06/19] update for rebase --- src/barretenberg_structures.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/barretenberg_structures.rs b/src/barretenberg_structures.rs index 2758e446..e5e567a3 100644 --- a/src/barretenberg_structures.rs +++ b/src/barretenberg_structures.rs @@ -971,11 +971,8 @@ impl TryFrom<&Circuit> for ConstraintSystem { let mut outputs_iter = gadget_call.outputs.iter(); let mut result = [0i32; 32]; for (i, res) in result.iter_mut().enumerate() { - let out_byte = outputs_iter.next().unwrap_or_else(|| { - panic!( - "missing rest of output. Tried to get byte {i} but failed" - ) - }); + let out_byte = + outputs_iter.next().ok_or(Error::MissingOutput(i))?; let out_byte_index = out_byte.witness_index() as i32; *res = out_byte_index From ee74e1f84be393af14656f286473e7630ab6b85f Mon Sep 17 00:00:00 2001 From: Blaine Bublitz Date: Fri, 5 May 2023 11:54:51 -0700 Subject: [PATCH 07/19] fixing rebase problems --- src/composer.rs | 4 ++-- src/lib.rs | 26 -------------------------- src/pippenger.rs | 2 +- 3 files changed, 3 insertions(+), 29 deletions(-) diff --git a/src/composer.rs b/src/composer.rs index d7c2c889..77ecbc46 100644 --- a/src/composer.rs +++ b/src/composer.rs @@ -280,7 +280,7 @@ impl Composer for Barretenberg { let vk_size = self .call_multiple( "acir_proofs_init_verification_key", - vec![&pippenger_ptr.into(), &g2_ptr, &pk_ptr, &vk_ptr_ptr.into()], + vec![&pippenger_ptr, &g2_ptr, &pk_ptr, &vk_ptr_ptr.into()], )? .i32()?; @@ -318,7 +318,7 @@ impl Composer for Barretenberg { .call_multiple( "acir_proofs_new_proof", vec![ - &pippenger_ptr.into(), + &pippenger_ptr, &g2_ptr, &pk_ptr, &cs_ptr, diff --git a/src/lib.rs b/src/lib.rs index 36282c1b..31c426bc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -229,32 +229,6 @@ mod wasm { fn try_from(x: WASMValue) -> Result { x.value() } - - pub(super) fn bool(self) -> bool { - match self.i32() { - 0 => false, - 1 => true, - _ => panic!("expected a boolean value"), - } - } - } - - impl From for WASMValue { - fn from(value: usize) -> Self { - WASMValue(Some(Value::I32(value as i32))) - } - } - - impl From for WASMValue { - fn from(value: i32) -> Self { - WASMValue(Some(Value::I32(value))) - } - } - - impl From for WASMValue { - fn from(value: Value) -> Self { - WASMValue(Some(value)) - } } impl Barretenberg { diff --git a/src/pippenger.rs b/src/pippenger.rs index b15d80b9..a0aa3e14 100644 --- a/src/pippenger.rs +++ b/src/pippenger.rs @@ -45,7 +45,7 @@ impl Barretenberg { self.free(crs_ptr)?; Ok(Pippenger { - pippenger_ptr: pippenger_ptr?.value()?, + pippenger_ptr: pippenger_ptr?, }) } } From fc01938c9fe83be39e1c5c2b2801762e3fdbb8f4 Mon Sep 17 00:00:00 2001 From: Blaine Bublitz Date: Fri, 5 May 2023 14:32:15 -0700 Subject: [PATCH 08/19] Remove keccak code added before acvm v0.11.0 --- Cargo.lock | 1 - Cargo.toml | 1 - src/acvm_interop/pwg.rs | 58 +---------------------------------------- 3 files changed, 1 insertion(+), 59 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dd5ea760..a9e4ac65 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -61,7 +61,6 @@ dependencies = [ "pkg-config", "reqwest", "rust-embed", - "sha3", "sled", "tempfile", "thiserror", diff --git a/Cargo.toml b/Cargo.toml index 9c54f787..1290ce6f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,6 @@ acvm = { version = "0.11.0", features = ["bn254"] } thiserror = "1.0.21" blake2 = "0.9.1" -sha3 = "0.9.1" dirs = { version = "3.0", optional = true } reqwest = { version = "0.11.16", optional = true, default-features = false, features = [ "stream", diff --git a/src/acvm_interop/pwg.rs b/src/acvm_interop/pwg.rs index 6ad44134..623954d6 100644 --- a/src/acvm_interop/pwg.rs +++ b/src/acvm_interop/pwg.rs @@ -24,7 +24,7 @@ impl PartialWitnessGenerator for Barretenberg { match func_call.name { BlackBoxFunc::SHA256 => hash::sha256(initial_witness, func_call), BlackBoxFunc::Blake2s => hash::blake2s(initial_witness, func_call), - BlackBoxFunc::Keccak256 => keccak256(initial_witness, func_call), + BlackBoxFunc::Keccak256 => hash::keccak256(initial_witness, func_call), BlackBoxFunc::EcdsaSecp256k1 => { signature::ecdsa::secp256k1_prehashed(initial_witness, func_call) } @@ -193,59 +193,3 @@ impl PartialWitnessGenerator for Barretenberg { } } } - -// All of the code below can be removed once we update to acvm 0.11 or greater. -use sha3::Keccak256; -fn keccak256( - initial_witness: &mut BTreeMap, - func_call: &BlackBoxFuncCall, -) -> Result { - let hash = generic_hash_256::(initial_witness, func_call)?; - - for (output_witness, value) in func_call.outputs.iter().zip(hash.iter()) { - insert_value( - output_witness, - FieldElement::from_be_bytes_reduce(&[*value]), - initial_witness, - )?; - } - - Ok(OpcodeResolution::Solved) -} -fn insert_value( - witness: &Witness, - value_to_insert: FieldElement, - initial_witness: &mut BTreeMap, -) -> Result<(), OpcodeResolutionError> { - let optional_old_value = initial_witness.insert(*witness, value_to_insert); - - let old_value = match optional_old_value { - Some(old_value) => old_value, - None => return Ok(()), - }; - - if old_value != value_to_insert { - return Err(OpcodeResolutionError::UnsatisfiedConstrain); - } - - Ok(()) -} -fn generic_hash_256( - initial_witness: &mut BTreeMap, - func_call: &BlackBoxFuncCall, -) -> Result<[u8; 32], OpcodeResolutionError> { - let mut hasher = D::new(); - - // Read witness assignments into hasher. - for input in func_call.inputs.iter() { - let witness = input.witness; - let num_bits = input.num_bits as usize; - - let witness_assignment = witness_to_value(initial_witness, witness)?; - let bytes = witness_assignment.fetch_nearest_bytes(num_bits); - hasher.update(bytes); - } - - let result = hasher.finalize().as_slice().try_into().unwrap(); - Ok(result) -} From 643f32c24ed7f8f349df480bfb435917660f7568 Mon Sep 17 00:00:00 2001 From: Blaine Bublitz Date: Mon, 8 May 2023 10:16:38 -0700 Subject: [PATCH 09/19] issues with rebase --- src/acvm_interop/smart_contract.rs | 2 +- src/composer.rs | 12 ++++++------ src/lib.rs | 11 ++++------- src/schnorr.rs | 2 +- 4 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/acvm_interop/smart_contract.rs b/src/acvm_interop/smart_contract.rs index 275e1bce..8127293a 100644 --- a/src/acvm_interop/smart_contract.rs +++ b/src/acvm_interop/smart_contract.rs @@ -58,7 +58,7 @@ impl SmartContract for Barretenberg { // We then need to read the pointer at `contract_ptr_ptr` to get the smart contract's location // and then slice memory again at `contract_ptr_ptr` to get the smart contract string. - let contract_ptr = self.get_pointer(contract_ptr_ptr)?; + let contract_ptr = self.get_pointer(contract_ptr_ptr); let sc_as_bytes = self.read_memory_variable_length(contract_ptr, contract_size); diff --git a/src/composer.rs b/src/composer.rs index 77ecbc46..4edda71a 100644 --- a/src/composer.rs +++ b/src/composer.rs @@ -254,9 +254,9 @@ impl Composer for Barretenberg { // We then need to read the pointer at `pk_ptr_ptr` to get the key's location // and then slice memory again at `pk_ptr` to get the proving key. - let pk_ptr = self.get_pointer(pk_ptr_ptr)?; + let pk_ptr = self.get_pointer(pk_ptr_ptr); - Ok(self.read_memory_variable_length(pk_ptr, pk_size)) + Ok(self.read_memory_variable_length(pk_ptr, pk_size as usize)) } fn compute_verification_key( @@ -286,9 +286,9 @@ impl Composer for Barretenberg { // We then need to read the pointer at `vk_ptr_ptr` to get the key's location // and then slice memory again at `vk_ptr` to get the verification key. - let vk_ptr = self.get_pointer(vk_ptr_ptr)?; + let vk_ptr = self.get_pointer(vk_ptr_ptr); - Ok(self.read_memory_variable_length(vk_ptr, vk_size)) + Ok(self.read_memory_variable_length(vk_ptr, vk_size as usize)) } fn create_proof_with_pk( @@ -330,9 +330,9 @@ impl Composer for Barretenberg { // We then need to read the pointer at `proof_ptr_ptr` to get the proof's location // and then slice memory again at `proof_ptr` to get the proof data. - let proof_ptr = self.get_pointer(proof_ptr_ptr)?; + let proof_ptr = self.get_pointer(proof_ptr_ptr); - let result = self.read_memory_variable_length(proof_ptr, proof_size); + let result = self.read_memory_variable_length(proof_ptr, proof_size as usize); // Barretenberg returns proofs which are prepended with the public inputs. // This behavior is nonstandard so we strip the public inputs from the proof. diff --git a/src/lib.rs b/src/lib.rs index 31c426bc..bb1f0122 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -256,6 +256,7 @@ mod wasm { } } + // TODO: Consider making this Result-returning pub(super) fn read_memory(&self, start: usize) -> [u8; SIZE] { self.read_memory_variable_length(start, SIZE) .try_into() @@ -276,13 +277,9 @@ mod wasm { .collect(); } - pub(super) fn get_pointer(&self, ptr_ptr: usize) -> Result { - let ptr = self.slice_memory(ptr_ptr, POINTER_BYTES); - Ok(u32::from_le_bytes( - ptr[0..POINTER_BYTES] - .try_into() - .map_err(|source| WasmError::InvalidPointer { source })?, - ) as usize) + pub(super) fn get_pointer(&self, ptr_ptr: usize) -> usize { + let ptr: [u8; POINTER_BYTES] = self.read_memory(ptr_ptr); + u32::from_le_bytes(ptr) as usize } pub(super) fn call(&self, name: &str, param: &WASMValue) -> Result { diff --git a/src/schnorr.rs b/src/schnorr.rs index 83b73a12..bb4d9055 100644 --- a/src/schnorr.rs +++ b/src/schnorr.rs @@ -113,7 +113,7 @@ impl SchnorrSig for Barretenberg { vec![&private_key_ptr.into(), &result_ptr.into()], )?; - self.read_memory(result_ptr) + Ok(self.read_memory(result_ptr)) } fn verify_signature( From cdb7ed2cc3b5e0bcb6e2fe46b9891adc0f7e8802 Mon Sep 17 00:00:00 2001 From: Blaine Bublitz Date: Mon, 8 May 2023 10:44:10 -0700 Subject: [PATCH 10/19] tryfrom all the things --- src/acvm_interop/smart_contract.rs | 3 +- src/composer.rs | 62 +++++++++++------------- src/lib.rs | 75 ++++++++++++++++++++---------- src/schnorr.rs | 6 +-- 4 files changed, 80 insertions(+), 66 deletions(-) diff --git a/src/acvm_interop/smart_contract.rs b/src/acvm_interop/smart_contract.rs index 8127293a..46fdf3b4 100644 --- a/src/acvm_interop/smart_contract.rs +++ b/src/acvm_interop/smart_contract.rs @@ -54,13 +54,12 @@ impl SmartContract for Barretenberg { "acir_proofs_get_solidity_verifier", vec![&g2_ptr, &vk_ptr, &contract_ptr_ptr.into()], )?; - let contract_size: usize = contract_size.i32()? as usize; // We then need to read the pointer at `contract_ptr_ptr` to get the smart contract's location // and then slice memory again at `contract_ptr_ptr` to get the smart contract string. let contract_ptr = self.get_pointer(contract_ptr_ptr); - let sc_as_bytes = self.read_memory_variable_length(contract_ptr, contract_size); + let sc_as_bytes = self.read_memory_variable_length(contract_ptr, contract_size.try_into()?); let verification_key_library: String = sc_as_bytes.iter().map(|b| *b as char).collect(); Ok(format!( diff --git a/src/composer.rs b/src/composer.rs index 4edda71a..f086bd5e 100644 --- a/src/composer.rs +++ b/src/composer.rs @@ -220,7 +220,9 @@ impl Composer for Barretenberg { self.free(cs_ptr)?; - pow2ceil(circuit_size?.u32()? + NUM_RESERVED_GATES) + let size: u32 = circuit_size?.try_into()?; + + pow2ceil(size + NUM_RESERVED_GATES) } fn get_exact_circuit_size(&self, constraint_system: &ConstraintSystem) -> Result { @@ -232,9 +234,7 @@ impl Composer for Barretenberg { self.free(cs_ptr)?; - let size = circuit_size?.u32()?; - - Ok(size) + Ok(circuit_size?.try_into()?) } fn compute_proving_key(&self, constraint_system: &ConstraintSystem) -> Result, Error> { @@ -245,18 +245,16 @@ impl Composer for Barretenberg { // `pk_ptr_ptr` is a pointer to a pointer which holds the proving key. let pk_ptr_ptr: usize = 0; - let pk_size = self - .call_multiple( - "acir_proofs_init_proving_key", - vec![&cs_ptr, &pk_ptr_ptr.into()], - )? - .i32()?; + let pk_size = self.call_multiple( + "acir_proofs_init_proving_key", + vec![&cs_ptr, &pk_ptr_ptr.into()], + )?; // We then need to read the pointer at `pk_ptr_ptr` to get the key's location // and then slice memory again at `pk_ptr` to get the proving key. let pk_ptr = self.get_pointer(pk_ptr_ptr); - Ok(self.read_memory_variable_length(pk_ptr, pk_size as usize)) + Ok(self.read_memory_variable_length(pk_ptr, pk_size.try_into()?)) } fn compute_verification_key( @@ -277,18 +275,16 @@ impl Composer for Barretenberg { // `vk_ptr_ptr` is a pointer to a pointer which holds the verification key. let vk_ptr_ptr: usize = 0; - let vk_size = self - .call_multiple( - "acir_proofs_init_verification_key", - vec![&pippenger_ptr, &g2_ptr, &pk_ptr, &vk_ptr_ptr.into()], - )? - .i32()?; + let vk_size = self.call_multiple( + "acir_proofs_init_verification_key", + vec![&pippenger_ptr, &g2_ptr, &pk_ptr, &vk_ptr_ptr.into()], + )?; // We then need to read the pointer at `vk_ptr_ptr` to get the key's location // and then slice memory again at `vk_ptr` to get the verification key. let vk_ptr = self.get_pointer(vk_ptr_ptr); - Ok(self.read_memory_variable_length(vk_ptr, vk_size as usize)) + Ok(self.read_memory_variable_length(vk_ptr, vk_size.try_into()?)) } fn create_proof_with_pk( @@ -314,25 +310,23 @@ impl Composer for Barretenberg { // `proof_ptr_ptr` is a pointer to a pointer which holds the proof data. let proof_ptr_ptr: usize = 0; - let proof_size = self - .call_multiple( - "acir_proofs_new_proof", - vec![ - &pippenger_ptr, - &g2_ptr, - &pk_ptr, - &cs_ptr, - &witness_ptr, - &proof_ptr_ptr.into(), - ], - )? - .i32()?; + let proof_size = self.call_multiple( + "acir_proofs_new_proof", + vec![ + &pippenger_ptr, + &g2_ptr, + &pk_ptr, + &cs_ptr, + &witness_ptr, + &proof_ptr_ptr.into(), + ], + )?; // We then need to read the pointer at `proof_ptr_ptr` to get the proof's location // and then slice memory again at `proof_ptr` to get the proof data. let proof_ptr = self.get_pointer(proof_ptr_ptr); - let result = self.read_memory_variable_length(proof_ptr, proof_size as usize); + let result = self.read_memory_variable_length(proof_ptr, proof_size.try_into()?); // Barretenberg returns proofs which are prepended with the public inputs. // This behavior is nonstandard so we strip the public inputs from the proof. @@ -370,9 +364,7 @@ impl Composer for Barretenberg { self.free(proof_ptr)?; - let verified = verified?.bool()?; - - Ok(verified) + Ok(verified?.try_into()?) } } diff --git a/src/lib.rs b/src/lib.rs index bb1f0122..677d1a57 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,6 +51,11 @@ pub enum WasmError { value: i32, source: std::num::TryFromIntError, }, + #[error("Could not convert value {value} from i32 to usuze")] + InvalidUsize { + value: i32, + source: std::num::TryFromIntError, + }, #[error("Value expected to be 0 or 1 representing a boolean")] InvalidBool, #[error("Failed to get pointer")] @@ -183,28 +188,6 @@ mod wasm { #[derive(Debug, Clone)] pub(super) struct WASMValue(Option); - impl WASMValue { - pub(super) fn value(self) -> Result { - self.0.ok_or(WasmError::NoValue) - } - pub(super) fn i32(self) -> Result { - self.0 - .and_then(|val| val.i32()) - .ok_or(WasmError::InvalidI32) - } - pub(super) fn u32(self) -> Result { - let value = self.i32()?; - u32::try_from(value).map_err(|source| WasmError::InvalidU32 { value, source }) - } - pub(super) fn bool(self) -> Result { - match self.i32() { - Ok(0) => Ok(false), - Ok(1) => Ok(true), - _ => Err(WasmError::InvalidBool), - } - } - } - impl From for WASMValue { fn from(value: usize) -> Self { WASMValue(Some(Value::I32(value as i32))) @@ -223,11 +206,53 @@ mod wasm { } } + impl TryFrom for bool { + type Error = WasmError; + + fn try_from(value: WASMValue) -> Result { + match value.try_into()? { + 0 => Ok(false), + 1 => Ok(true), + _ => Err(WasmError::InvalidBool), + } + } + } + + impl TryFrom for usize { + type Error = WasmError; + + fn try_from(value: WASMValue) -> Result { + let value: i32 = value.try_into()?; + value + .try_into() + .map_err(|source| WasmError::InvalidUsize { value, source }) + } + } + + impl TryFrom for u32 { + type Error = WasmError; + + fn try_from(value: WASMValue) -> Result { + let value = value.try_into()?; + u32::try_from(value).map_err(|source| WasmError::InvalidU32 { value, source }) + } + } + + impl TryFrom for i32 { + type Error = WasmError; + + fn try_from(value: WASMValue) -> Result { + value.0.map_or(Err(WasmError::NoValue), |val| { + val.i32().ok_or(WasmError::InvalidI32) + }) + } + } + impl TryFrom for Value { type Error = WasmError; - fn try_from(x: WASMValue) -> Result { - x.value() + fn try_from(value: WASMValue) -> Result { + value.0.ok_or(WasmError::NoValue) } } @@ -317,7 +342,7 @@ mod wasm { /// Creates a pointer and allocates the bytes that the pointer references to, to the heap pub(super) fn allocate(&self, bytes: &[u8]) -> Result { - let ptr = self.call("bbmalloc", &bytes.len().into())?.i32()?; + let ptr: i32 = self.call("bbmalloc", &bytes.len().into())?.try_into()?; let i32_bytes = ptr.to_be_bytes(); let u32_bytes = u32::from_be_bytes(i32_bytes); diff --git a/src/schnorr.rs b/src/schnorr.rs index bb4d9055..ac5fa236 100644 --- a/src/schnorr.rs +++ b/src/schnorr.rs @@ -140,7 +140,7 @@ impl SchnorrSig for Barretenberg { self.transfer_to_heap(sig_e, sig_e_ptr); self.transfer_to_heap(message, message_ptr); - let wasm_value = self.call_multiple( + let verified = self.call_multiple( "verify_signature", vec![ &message_ptr.into(), @@ -153,9 +153,7 @@ impl SchnorrSig for Barretenberg { // Note, currently for Barretenberg plonk, if the signature fails // then the whole circuit fails. - let verified = wasm_value.bool()?; - - Ok(verified) + Ok(verified.try_into()?) } } From 7ed2f17d48d60fef4271c662befe79ec553bccbe Mon Sep 17 00:00:00 2001 From: Blaine Bublitz Date: Mon, 8 May 2023 10:44:20 -0700 Subject: [PATCH 11/19] move todos --- src/merkle.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/merkle.rs b/src/merkle.rs index 86272075..395610c4 100644 --- a/src/merkle.rs +++ b/src/merkle.rs @@ -1,3 +1,4 @@ +// TODO(#166): Rework this module to return results use acvm::FieldElement; use std::{convert::TryInto, path::Path}; @@ -65,7 +66,6 @@ pub(crate) struct MerkleTree { msg_hasher: MH, } -// TODO: Rework this module to return results fn insert_root(db: &mut sled::Db, value: FieldElement) { db.insert("ROOT".as_bytes(), value.to_be_bytes()).unwrap(); } @@ -203,7 +203,6 @@ impl MerkleTree { for i in 0..layer_size { hashes[offset + i] = current; } - // TODO: no unwrap current = barretenberg.hash(¤t, ¤t).unwrap(); offset += layer_size; From d7c7d8aa3c09c187bbb5f5550687a424fc6d99f0 Mon Sep 17 00:00:00 2001 From: Blaine Bublitz Date: Mon, 8 May 2023 11:00:50 -0700 Subject: [PATCH 12/19] Move unsafe call --- src/composer.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/composer.rs b/src/composer.rs index f086bd5e..b3ac376d 100644 --- a/src/composer.rs +++ b/src/composer.rs @@ -61,9 +61,13 @@ impl Composer for Barretenberg { fn get_exact_circuit_size(&self, constraint_system: &ConstraintSystem) -> Result { let cs_buf = constraint_system.to_bytes(); - Ok(unsafe { - barretenberg_sys::composer::get_exact_circuit_size(cs_buf.as_slice().as_ptr()) - }) + let circuit_size; + unsafe { + circuit_size = + barretenberg_sys::composer::get_exact_circuit_size(cs_buf.as_slice().as_ptr()) + } + + Ok(circuit_size) } fn compute_proving_key(&self, constraint_system: &ConstraintSystem) -> Result, Error> { From 0757356bdd28da5b92d82f0de2333f31a7428fce Mon Sep 17 00:00:00 2001 From: Blaine Bublitz Date: Mon, 8 May 2023 11:01:05 -0700 Subject: [PATCH 13/19] remove unused error variants --- src/lib.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 677d1a57..f8756fa5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,8 +58,6 @@ pub enum WasmError { }, #[error("Value expected to be 0 or 1 representing a boolean")] InvalidBool, - #[error("Failed to get pointer")] - InvalidPointer { source: TryFromSliceError }, } #[derive(Debug, Error)] @@ -89,8 +87,7 @@ pub enum Error { MissingSignature(usize), #[error("Missing rest of {0} component for public key. Tried to get byte {1} but failed")] MissingPublicKey(&'static str, usize), - #[error("Keccak256 has not yet been implemented")] - Keccak256, + #[error("AES has not yet been implemented")] Aes, From 7af612c8542a41901c6744f7cf33d704ba7d2ea3 Mon Sep 17 00:00:00 2001 From: Blaine Bublitz Date: Mon, 8 May 2023 13:22:03 -0700 Subject: [PATCH 14/19] testing making bb debug --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index f8756fa5..82d3f708 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -98,6 +98,7 @@ pub enum Error { /// The number of bytes necessary to store a `FieldElement`. const FIELD_BYTES: usize = 32; +#[derive(Debug)] pub struct Barretenberg { #[cfg(feature = "wasm")] memory: wasmer::Memory, From 79089d29ab321c2af829ed6bd44f06617f579524 Mon Sep 17 00:00:00 2001 From: Blaine Bublitz Date: Mon, 8 May 2023 14:03:48 -0700 Subject: [PATCH 15/19] update bb in lockfile --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index 428f4797..8d6445d3 100644 --- a/flake.lock +++ b/flake.lock @@ -10,11 +10,11 @@ ] }, "locked": { - "lastModified": 1683235108, - "narHash": "sha256-2NN/pb9hwM5/qJ5mpJfGso1H3fc2RRaZ4sZhVPvT0Dw=", + "lastModified": 1683314474, + "narHash": "sha256-gfHYpOnVTfS+4fhScBhfkB/e5z+jPFCi8zSy+aEh+8s=", "owner": "AztecProtocol", "repo": "barretenberg", - "rev": "e66f1ef38c3c87c223456d8a77878c2bd3d346eb", + "rev": "ad615ee7dc931d3dbea041e47c96b9d8dccebf98", "type": "github" }, "original": { From be7f3dc3b7f6ac8687ce69cab05b9986c2a47a5c Mon Sep 17 00:00:00 2001 From: Blaine Bublitz Date: Tue, 9 May 2023 09:43:21 -0700 Subject: [PATCH 16/19] hide error variants --- src/acvm_interop/proof_system.rs | 25 +++++---- src/acvm_interop/smart_contract.rs | 12 ++--- src/lib.rs | 82 +++++++++++++++++------------- src/pedersen.rs | 6 ++- src/schnorr.rs | 6 ++- 5 files changed, 74 insertions(+), 57 deletions(-) diff --git a/src/acvm_interop/proof_system.rs b/src/acvm_interop/proof_system.rs index 92389c6d..613bc25f 100644 --- a/src/acvm_interop/proof_system.rs +++ b/src/acvm_interop/proof_system.rs @@ -5,17 +5,20 @@ use std::collections::BTreeMap; use crate::barretenberg_structures::Assignments; use crate::composer::Composer; -use crate::{Barretenberg, Error}; +use crate::{BackendError, Barretenberg}; impl ProofSystemCompiler for Barretenberg { - type Error = Error; + type Error = BackendError; fn np_language(&self) -> Language { Language::PLONKCSat { width: 3 } } - fn get_exact_circuit_size(&self, circuit: &Circuit) -> Result { - Composer::get_exact_circuit_size(self, &circuit.try_into()?) + fn get_exact_circuit_size(&self, circuit: &Circuit) -> Result { + Ok(Composer::get_exact_circuit_size( + self, + &circuit.try_into()?, + )?) } fn black_box_function_supported(&self, opcode: &BlackBoxFunc) -> bool { @@ -33,11 +36,11 @@ impl ProofSystemCompiler for Barretenberg { | BlackBoxFunc::EcdsaSecp256k1 | BlackBoxFunc::FixedBaseScalarMul => true, - BlackBoxFunc::AES => false, + BlackBoxFunc::AES => false, } } - fn preprocess(&self, circuit: &Circuit) -> Result<(Vec, Vec), Error> { + fn preprocess(&self, circuit: &Circuit) -> Result<(Vec, Vec), Self::Error> { let constraint_system = &circuit.try_into()?; let proving_key = self.compute_proving_key(constraint_system)?; @@ -51,10 +54,10 @@ impl ProofSystemCompiler for Barretenberg { circuit: &Circuit, witness_values: BTreeMap, proving_key: &[u8], - ) -> Result, Error> { + ) -> Result, Self::Error> { let assignments = flatten_witness_map(circuit, witness_values); - self.create_proof_with_pk(&circuit.try_into()?, assignments, proving_key) + Ok(self.create_proof_with_pk(&circuit.try_into()?, assignments, proving_key)?) } fn verify_with_vk( @@ -63,18 +66,18 @@ impl ProofSystemCompiler for Barretenberg { public_inputs: BTreeMap, circuit: &Circuit, verification_key: &[u8], - ) -> Result { + ) -> Result { // Unlike when proving, we omit any unassigned witnesses. // Witness values should be ordered by their index but we skip over any indices without an assignment. let flattened_public_inputs: Vec = public_inputs.into_values().collect(); - Composer::verify_with_vk( + Ok(Composer::verify_with_vk( self, &circuit.try_into()?, proof, flattened_public_inputs.into(), verification_key, - ) + )?) } } diff --git a/src/acvm_interop/smart_contract.rs b/src/acvm_interop/smart_contract.rs index 46fdf3b4..34d64efc 100644 --- a/src/acvm_interop/smart_contract.rs +++ b/src/acvm_interop/smart_contract.rs @@ -1,16 +1,16 @@ use acvm::SmartContract; use crate::crs::G2; -use crate::{Barretenberg, Error}; +use crate::{BackendError, Barretenberg}; /// Embed the Solidity verifier file const ULTRA_VERIFIER_CONTRACT: &str = include_str!("contract.sol"); #[cfg(feature = "native")] impl SmartContract for Barretenberg { - type Error = Error; + type Error = BackendError; - fn eth_contract_from_vk(&self, verification_key: &[u8]) -> Result { + fn eth_contract_from_vk(&self, verification_key: &[u8]) -> Result { use std::slice; let g2 = G2::new(); @@ -38,9 +38,9 @@ impl SmartContract for Barretenberg { #[cfg(not(feature = "native"))] impl SmartContract for Barretenberg { - type Error = Error; + type Error = BackendError; - fn eth_contract_from_vk(&self, verification_key: &[u8]) -> Result { + fn eth_contract_from_vk(&self, verification_key: &[u8]) -> Result { let g2 = G2::new(); let g2_ptr = self.allocate(&g2.data)?; @@ -69,7 +69,7 @@ impl SmartContract for Barretenberg { } #[test] -fn test_smart_contract() -> Result<(), Error> { +fn test_smart_contract() -> Result<(), BackendError> { use crate::barretenberg_structures::{Constraint, ConstraintSystem}; use crate::composer::Composer; use crate::Barretenberg; diff --git a/src/lib.rs b/src/lib.rs index 82d3f708..2804b3da 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,18 +20,26 @@ mod pippenger; mod scalar_mul; mod schnorr; -use std::array::TryFromSliceError; - use thiserror::Error; -// There are no WasmErrors on native #[cfg(feature = "native")] #[derive(Debug, Error)] -pub enum WasmError {} +enum FeatureError { + #[error("Could not slice schnorr")] + SchnorrSlice { + source: std::array::TryFromSliceError, + }, + #[error("Could not slice field element")] + FieldElementSlice { + source: std::array::TryFromSliceError, + }, + #[error("Expected a Vec of length {0} but it was {1}")] + FieldToArray(usize, usize), +} #[cfg(not(feature = "native"))] #[derive(Debug, Error)] -pub enum WasmError { +enum FeatureError { #[error("Trying to call {name} resulted in an error")] FunctionCallFailed { name: String, @@ -61,17 +69,11 @@ pub enum WasmError { } #[derive(Debug, Error)] -pub enum Error { +enum Error { #[error("The value {0} overflows in the pow2ceil function")] Pow2CeilOverflow(u32), #[error("Could not convert schnorr")] SchnorrConvert(Vec), - #[error("Could not slice schnorr")] - SchnorrSlice { source: TryFromSliceError }, - #[error("Could not slice field element")] - FieldElementSlice { source: TryFromSliceError }, - #[error("Expected a Vec of length {0} but it was {1}")] - FieldToArray(usize, usize), #[error("Missing rest of output. Tried to get byte {0} but failed")] MissingOutput(usize), @@ -92,7 +94,17 @@ pub enum Error { Aes, #[error(transparent)] - WasmError(#[from] WasmError), + FeatureError(#[from] FeatureError), +} + +#[derive(Debug, Error)] +#[error(transparent)] +pub struct BackendError(#[from] Error); + +impl From for BackendError { + fn from(value: FeatureError) -> Self { + value.into() + } } /// The number of bytes necessary to store a `FieldElement`. @@ -124,8 +136,7 @@ fn smoke() -> Result<(), Error> { #[cfg(feature = "native")] mod native { - use super::Barretenberg; - use super::Error; + use super::{Barretenberg, Error, FeatureError}; impl Barretenberg { pub(crate) fn new() -> Barretenberg { @@ -137,7 +148,7 @@ mod native { let v = f.to_be_bytes(); let result: [u8; 32] = v .try_into() - .map_err(|v: Vec| Error::FieldToArray(32, v.len()))?; + .map_err(|v: Vec| FeatureError::FieldToArray(32, v.len()))?; Ok(result) } } @@ -147,8 +158,7 @@ mod wasm { use std::cell::Cell; use wasmer::{imports, Function, Instance, Memory, MemoryType, Module, Store, Value}; - use super::Barretenberg; - use super::{Error, WasmError}; + use super::{Barretenberg, Error, FeatureError}; /// The number of bytes necessary to represent a pointer to memory inside the wasm. pub(super) const POINTER_BYTES: usize = 4; @@ -205,52 +215,52 @@ mod wasm { } impl TryFrom for bool { - type Error = WasmError; + type Error = FeatureError; fn try_from(value: WASMValue) -> Result { match value.try_into()? { 0 => Ok(false), 1 => Ok(true), - _ => Err(WasmError::InvalidBool), + _ => Err(FeatureError::InvalidBool), } } } impl TryFrom for usize { - type Error = WasmError; + type Error = FeatureError; fn try_from(value: WASMValue) -> Result { let value: i32 = value.try_into()?; value .try_into() - .map_err(|source| WasmError::InvalidUsize { value, source }) + .map_err(|source| FeatureError::InvalidUsize { value, source }) } } impl TryFrom for u32 { - type Error = WasmError; + type Error = FeatureError; fn try_from(value: WASMValue) -> Result { let value = value.try_into()?; - u32::try_from(value).map_err(|source| WasmError::InvalidU32 { value, source }) + u32::try_from(value).map_err(|source| FeatureError::InvalidU32 { value, source }) } } impl TryFrom for i32 { - type Error = WasmError; + type Error = FeatureError; fn try_from(value: WASMValue) -> Result { - value.0.map_or(Err(WasmError::NoValue), |val| { - val.i32().ok_or(WasmError::InvalidI32) + value.0.map_or(Err(FeatureError::NoValue), |val| { + val.i32().ok_or(FeatureError::InvalidI32) }) } } impl TryFrom for Value { - type Error = WasmError; + type Error = FeatureError; fn try_from(value: WASMValue) -> Result { - value.0.ok_or(WasmError::NoValue) + value.0.ok_or(FeatureError::NoValue) } } @@ -322,17 +332,17 @@ mod wasm { args.push(param.try_into()?) } let func = self.instance.exports.get_function(name).map_err(|source| { - WasmError::InvalidExport { + FeatureError::InvalidExport { name: name.to_string(), source, } })?; - let boxed_value = func - .call(&args) - .map_err(|source| WasmError::FunctionCallFailed { - name: name.to_string(), - source, - })?; + let boxed_value = + func.call(&args) + .map_err(|source| FeatureError::FunctionCallFailed { + name: name.to_string(), + source, + })?; let option_value = boxed_value.first().cloned(); Ok(WASMValue(option_value)) diff --git a/src/pedersen.rs b/src/pedersen.rs index e4b3e4b4..1297c4e9 100644 --- a/src/pedersen.rs +++ b/src/pedersen.rs @@ -19,16 +19,18 @@ impl Pedersen for Barretenberg { left: &FieldElement, right: &FieldElement, ) -> Result { + use super::FeatureError; + let result_bytes = barretenberg_sys::pedersen::compress_native( left.to_be_bytes() .as_slice() .try_into() - .map_err(|source| Error::FieldElementSlice { source })?, + .map_err(|source| FeatureError::FieldElementSlice { source })?, right .to_be_bytes() .as_slice() .try_into() - .map_err(|source| Error::FieldElementSlice { source })?, + .map_err(|source| FeatureError::FieldElementSlice { source })?, ); Ok(FieldElement::from_be_bytes_reduce(&result_bytes)) diff --git a/src/schnorr.rs b/src/schnorr.rs index ac5fa236..c966e81d 100644 --- a/src/schnorr.rs +++ b/src/schnorr.rs @@ -40,14 +40,16 @@ impl SchnorrSig for Barretenberg { sig: [u8; 64], message: &[u8], ) -> Result { + use super::FeatureError; + let (sig_s, sig_e) = sig.split_at(32); let sig_s: [u8; 32] = sig_s .try_into() - .map_err(|source| Error::SchnorrSlice { source })?; + .map_err(|source| FeatureError::SchnorrSlice { source })?; let sig_e: [u8; 32] = sig_e .try_into() - .map_err(|source| Error::SchnorrSlice { source })?; + .map_err(|source| FeatureError::SchnorrSlice { source })?; Ok(barretenberg_sys::schnorr::verify_signature( pub_key, sig_s, sig_e, message, From 75a23d7bfc6f80de0ac5176e4a533da4fafadb66 Mon Sep 17 00:00:00 2001 From: Blaine Bublitz Date: Tue, 9 May 2023 10:53:01 -0700 Subject: [PATCH 17/19] Condense blackbox errors to two variants --- src/barretenberg_structures.rs | 86 +++++++++++++++++++++++++++------- src/lib.rs | 25 +++------- 2 files changed, 77 insertions(+), 34 deletions(-) diff --git a/src/barretenberg_structures.rs b/src/barretenberg_structures.rs index e5e567a3..ec2334a8 100644 --- a/src/barretenberg_structures.rs +++ b/src/barretenberg_structures.rs @@ -734,8 +734,12 @@ impl TryFrom<&Circuit> for ConstraintSystem { let mut outputs_iter = gadget_call.outputs.iter(); let mut result = [0i32; 32]; for (i, res) in result.iter_mut().enumerate() { - let out_byte = - outputs_iter.next().ok_or(Error::MissingOutput(i))?; + let out_byte = outputs_iter.next().ok_or_else(|| { + Error::MalformedBlackBoxFunc( + gadget_call.name, + format!("Missing rest of output. Tried to get byte {i} but failed"), + ) + })?; let out_byte_index = out_byte.witness_index() as i32; *res = out_byte_index @@ -761,7 +765,12 @@ impl TryFrom<&Circuit> for ConstraintSystem { let mut result = [0i32; 32]; for (i, res) in result.iter_mut().enumerate() { let out_byte = - outputs_iter.next().ok_or(Error::MissingOutput(i))?; + outputs_iter.next().ok_or_else(|| { + Error::MalformedBlackBoxFunc( + gadget_call.name, + format!("Missing rest of output. Tried to get byte {i} but failed"), + ) + })?; let out_byte_index = out_byte.witness_index() as i32; *res = out_byte_index @@ -778,13 +787,22 @@ impl TryFrom<&Circuit> for ConstraintSystem { // leaf let leaf = { - let leaf_input = inputs_iter.next().ok_or(Error::MissingLeaf)?; + let leaf_input = inputs_iter.next().ok_or_else(|| { + Error::MalformedBlackBoxFunc( + gadget_call.name, + "Missing leaf to check membership for".into(), + ) + })?; leaf_input.witness.witness_index() as i32 }; // index let index = { - let index_input = - inputs_iter.next().ok_or(Error::MissingLeafIndex)?; + let index_input = inputs_iter.next().ok_or_else(|| { + Error::MalformedBlackBoxFunc( + gadget_call.name, + "Missing index for leaf".into(), + ) + })?; index_input.witness.witness_index() as i32 }; @@ -816,21 +834,35 @@ impl TryFrom<&Circuit> for ConstraintSystem { // pub_key_x let public_key_x = { - let pub_key_x = - inputs_iter.next().ok_or(Error::MissingPublicKeyX)?; + let pub_key_x = inputs_iter.next().ok_or_else(|| { + Error::MalformedBlackBoxFunc( + gadget_call.name, + "Missing `x` component for public key".into(), + ) + })?; pub_key_x.witness.witness_index() as i32 }; // pub_key_y let public_key_y = { - let pub_key_y = - inputs_iter.next().ok_or(Error::MissingPublicKeyY)?; + let pub_key_y = inputs_iter.next().ok_or_else(|| { + Error::MalformedBlackBoxFunc( + gadget_call.name, + "Missing `y` component for public key".into(), + ) + })?; pub_key_y.witness.witness_index() as i32 }; // signature + let mut signature = [0i32; 64]; for (i, sig) in signature.iter_mut().enumerate() { let sig_byte = - inputs_iter.next().ok_or(Error::MissingSignature(i))?; + inputs_iter.next().ok_or_else(|| { + Error::MalformedBlackBoxFunc( + gadget_call.name, + format!("Missing rest of signature. Tried to get byte {i} but failed"), + ) + })?; let sig_byte_index = sig_byte.witness.witness_index() as i32; *sig = sig_byte_index } @@ -899,7 +931,12 @@ impl TryFrom<&Circuit> for ConstraintSystem { let mut public_key_x = [0i32; 32]; for (i, pkx) in public_key_x.iter_mut().enumerate() { let x_byte = - inputs_iter.next().ok_or(Error::MissingPublicKey("x", i))?; + inputs_iter.next().ok_or_else(|| { + Error::MalformedBlackBoxFunc( + gadget_call.name, + format!("Missing rest of `x` component for public key. Tried to get byte {i} but failed"), + ) + })?; let x_byte_index = x_byte.witness.witness_index() as i32; *pkx = x_byte_index; } @@ -908,7 +945,12 @@ impl TryFrom<&Circuit> for ConstraintSystem { let mut public_key_y = [0i32; 32]; for (i, pky) in public_key_y.iter_mut().enumerate() { let y_byte = - inputs_iter.next().ok_or(Error::MissingPublicKey("y", i))?; + inputs_iter.next().ok_or_else(|| { + Error::MalformedBlackBoxFunc( + gadget_call.name, + format!("Missing rest of `y` component for public key. Tried to get byte {i} but failed"), + ) + })?; let y_byte_index = y_byte.witness.witness_index() as i32; *pky = y_byte_index; } @@ -917,7 +959,12 @@ impl TryFrom<&Circuit> for ConstraintSystem { let mut signature = [0i32; 64]; for (i, sig) in signature.iter_mut().enumerate() { let sig_byte = - inputs_iter.next().ok_or(Error::MissingSignature(i))?; + inputs_iter.next().ok_or_else(|| { + Error::MalformedBlackBoxFunc( + gadget_call.name, + format!("Missing rest of signature. Tried to get byte {i} but failed"), + ) + })?; let sig_byte_index = sig_byte.witness.witness_index() as i32; *sig = sig_byte_index; } @@ -972,7 +1019,12 @@ impl TryFrom<&Circuit> for ConstraintSystem { let mut result = [0i32; 32]; for (i, res) in result.iter_mut().enumerate() { let out_byte = - outputs_iter.next().ok_or(Error::MissingOutput(i))?; + outputs_iter.next().ok_or_else(|| { + Error::MalformedBlackBoxFunc( + gadget_call.name, + format!("Missing rest of output. Tried to get byte {i} but failed"), + ) + })?; let out_byte_index = out_byte.witness_index() as i32; *res = out_byte_index @@ -984,7 +1036,9 @@ impl TryFrom<&Circuit> for ConstraintSystem { keccak_constraints.push(keccak_constraint); } - BlackBoxFunc::AES => return Err(Error::Aes), + BlackBoxFunc::AES => { + return Err(Error::UnsupportedBlackBoxFunc(gadget_call.name)) + } }; } Opcode::Directive(_) | Opcode::Oracle(_) => { diff --git a/src/lib.rs b/src/lib.rs index 2804b3da..1eae4305 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,6 +20,7 @@ mod pippenger; mod scalar_mul; mod schnorr; +use acvm::acir::BlackBoxFunc; use thiserror::Error; #[cfg(feature = "native")] @@ -75,26 +76,14 @@ enum Error { #[error("Could not convert schnorr")] SchnorrConvert(Vec), - #[error("Missing rest of output. Tried to get byte {0} but failed")] - MissingOutput(usize), - #[error("Missing leaf to check membership for")] - MissingLeaf, - #[error("Missing index for leaf")] - MissingLeafIndex, - #[error("Missing `x` component for public key")] - MissingPublicKeyX, - #[error("Missing `y` component for public key")] - MissingPublicKeyY, - #[error("Missing rest of signature. Tried to get byte {0} but failed")] - MissingSignature(usize), - #[error("Missing rest of {0} component for public key. Tried to get byte {1} but failed")] - MissingPublicKey(&'static str, usize), - - #[error("AES has not yet been implemented")] - Aes, + #[error("Malformed Black Box Function: {0} - {1}")] + MalformedBlackBoxFunc(BlackBoxFunc, String), + + #[error("Unsupported Black Box Function: {0}")] + UnsupportedBlackBoxFunc(BlackBoxFunc), #[error(transparent)] - FeatureError(#[from] FeatureError), + FromFeature(#[from] FeatureError), } #[derive(Debug, Error)] From 8c56b112b9f045f2ee7b93d88ef7eb8c809cc5f9 Mon Sep 17 00:00:00 2001 From: Blaine Bublitz Date: Tue, 9 May 2023 12:44:16 -0700 Subject: [PATCH 18/19] Stop trying to combine sig_s and sig_e and then splitting --- src/acvm_interop/pwg.rs | 24 ++++++++++--- src/lib.rs | 6 ---- src/schnorr.rs | 77 +++++++++++++++++------------------------ 3 files changed, 52 insertions(+), 55 deletions(-) diff --git a/src/acvm_interop/pwg.rs b/src/acvm_interop/pwg.rs index 623954d6..3e6df850 100644 --- a/src/acvm_interop/pwg.rs +++ b/src/acvm_interop/pwg.rs @@ -92,12 +92,28 @@ impl PartialWitnessGenerator for Barretenberg { ) })?; - let mut signature = [0u8; 64]; - for (i, sig) in signature.iter_mut().enumerate() { + let mut sig_s: [u8; 32] = [0u8; 32]; + for (i, sig) in sig_s.iter_mut().enumerate() { let _sig_i = inputs_iter.next().ok_or_else(|| { OpcodeResolutionError::BlackBoxFunctionFailed( func_call.name, - format!("signature should be 64 bytes long, found only {i} bytes"), + format!("sig_s should be 32 bytes long, found only {i} bytes"), + ) + })?; + let sig_i = witness_to_value(initial_witness, _sig_i.witness)?; + *sig = *sig_i.to_be_bytes().last().ok_or_else(|| { + OpcodeResolutionError::BlackBoxFunctionFailed( + func_call.name, + "could not get last bytes".into(), + ) + })?; + } + let mut sig_e: [u8; 32] = [0u8; 32]; + for (i, sig) in sig_e.iter_mut().enumerate() { + let _sig_i = inputs_iter.next().ok_or_else(|| { + OpcodeResolutionError::BlackBoxFunctionFailed( + func_call.name, + format!("sig_e should be 32 bytes long, found only {i} bytes"), ) })?; let sig_i = witness_to_value(initial_witness, _sig_i.witness)?; @@ -122,7 +138,7 @@ impl PartialWitnessGenerator for Barretenberg { } let valid_signature = self - .verify_signature(pub_key, signature, &message) + .verify_signature(pub_key, sig_s, sig_e, &message) .map_err(|err| { OpcodeResolutionError::BlackBoxFunctionFailed( func_call.name, diff --git a/src/lib.rs b/src/lib.rs index 1eae4305..bfbaad17 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,10 +26,6 @@ use thiserror::Error; #[cfg(feature = "native")] #[derive(Debug, Error)] enum FeatureError { - #[error("Could not slice schnorr")] - SchnorrSlice { - source: std::array::TryFromSliceError, - }, #[error("Could not slice field element")] FieldElementSlice { source: std::array::TryFromSliceError, @@ -73,8 +69,6 @@ enum FeatureError { enum Error { #[error("The value {0} overflows in the pow2ceil function")] Pow2CeilOverflow(u32), - #[error("Could not convert schnorr")] - SchnorrConvert(Vec), #[error("Malformed Black Box Function: {0} - {1}")] MalformedBlackBoxFunc(BlackBoxFunc, String), diff --git a/src/schnorr.rs b/src/schnorr.rs index c966e81d..cc5c7f69 100644 --- a/src/schnorr.rs +++ b/src/schnorr.rs @@ -1,13 +1,17 @@ use super::{Barretenberg, Error}; pub(crate) trait SchnorrSig { - fn construct_signature(&self, message: &[u8], private_key: [u8; 32]) - -> Result<[u8; 64], Error>; + fn construct_signature( + &self, + message: &[u8], + private_key: [u8; 32], + ) -> Result<([u8; 32], [u8; 32]), Error>; fn construct_public_key(&self, private_key: [u8; 32]) -> Result<[u8; 64], Error>; fn verify_signature( &self, pub_key: [u8; 64], - sig: [u8; 64], + sig_s: [u8; 32], + sig_e: [u8; 32], message: &[u8], ) -> Result; } @@ -18,14 +22,11 @@ impl SchnorrSig for Barretenberg { &self, message: &[u8], private_key: [u8; 32], - ) -> Result<[u8; 64], Error> { - let (sig_s, sig_e) = barretenberg_sys::schnorr::construct_signature(message, private_key); - - let sig_bytes: [u8; 64] = [sig_s, sig_e] - .concat() - .try_into() - .map_err(Error::SchnorrConvert)?; - Ok(sig_bytes) + ) -> Result<([u8; 32], [u8; 32]), Error> { + Ok(barretenberg_sys::schnorr::construct_signature( + message, + private_key, + )) } fn construct_public_key(&self, private_key: [u8; 32]) -> Result<[u8; 64], Error> { @@ -37,20 +38,10 @@ impl SchnorrSig for Barretenberg { fn verify_signature( &self, pub_key: [u8; 64], - sig: [u8; 64], + sig_s: [u8; 32], + sig_e: [u8; 32], message: &[u8], ) -> Result { - use super::FeatureError; - - let (sig_s, sig_e) = sig.split_at(32); - - let sig_s: [u8; 32] = sig_s - .try_into() - .map_err(|source| FeatureError::SchnorrSlice { source })?; - let sig_e: [u8; 32] = sig_e - .try_into() - .map_err(|source| FeatureError::SchnorrSlice { source })?; - Ok(barretenberg_sys::schnorr::verify_signature( pub_key, sig_s, sig_e, message, )) @@ -66,7 +57,7 @@ impl SchnorrSig for Barretenberg { &self, message: &[u8], private_key: [u8; 32], - ) -> Result<[u8; 64], Error> { + ) -> Result<([u8; 32], [u8; 32]), Error> { use super::{wasm::WASM_SCRATCH_BYTES, FIELD_BYTES}; let sig_s_ptr: usize = 0; @@ -94,11 +85,7 @@ impl SchnorrSig for Barretenberg { let sig_s: [u8; FIELD_BYTES] = self.read_memory(sig_s_ptr); let sig_e: [u8; FIELD_BYTES] = self.read_memory(sig_e_ptr); - let sig_bytes: [u8; 64] = [sig_s, sig_e] - .concat() - .try_into() - .map_err(Error::SchnorrConvert)?; - Ok(sig_bytes) + Ok((sig_s, sig_e)) } #[allow(dead_code)] @@ -121,12 +108,11 @@ impl SchnorrSig for Barretenberg { fn verify_signature( &self, pub_key: [u8; 64], - sig: [u8; 64], + sig_s: [u8; 32], + sig_e: [u8; 32], message: &[u8], ) -> Result { - use super::{wasm::WASM_SCRATCH_BYTES, FIELD_BYTES}; - - let (sig_s, sig_e) = sig.split_at(FIELD_BYTES); + use super::wasm::WASM_SCRATCH_BYTES; let public_key_ptr: usize = 0; let sig_s_ptr: usize = public_key_ptr + pub_key.len(); @@ -138,8 +124,8 @@ impl SchnorrSig for Barretenberg { ); self.transfer_to_heap(&pub_key, public_key_ptr); - self.transfer_to_heap(sig_s, sig_s_ptr); - self.transfer_to_heap(sig_e, sig_e_ptr); + self.transfer_to_heap(&sig_s, sig_s_ptr); + self.transfer_to_heap(&sig_e, sig_e_ptr); self.transfer_to_heap(message, message_ptr); let verified = self.call_multiple( @@ -168,8 +154,8 @@ fn basic_interop() -> Result<(), Error> { let message = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; let public_key = barretenberg.construct_public_key(private_key)?; - let signature = barretenberg.construct_signature(&message, private_key)?; - let valid_signature = barretenberg.verify_signature(public_key, signature, &message)?; + let (sig_s, sig_e) = barretenberg.construct_signature(&message, private_key)?; + let valid_signature = barretenberg.verify_signature(public_key, sig_s, sig_e, &message)?; assert!(valid_signature); // Should fail, since the messages are different @@ -177,17 +163,18 @@ fn basic_interop() -> Result<(), Error> { let message = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; let public_key = barretenberg.construct_public_key(private_key)?; - let signature = barretenberg.construct_signature(&message, private_key)?; - let valid_signature = barretenberg.verify_signature(public_key, signature, &[0, 2])?; + let (sig_s, sig_e) = barretenberg.construct_signature(&message, private_key)?; + let valid_signature = barretenberg.verify_signature(public_key, sig_s, sig_e, &[0, 2])?; assert!(!valid_signature); // Should fail, since the signature is not valid let private_key = [2; 32]; let message = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - let signature = [1; 64]; + let sig_s = [1; 32]; + let sig_e = [1; 32]; let public_key = barretenberg.construct_public_key(private_key)?; - let valid_signature = barretenberg.verify_signature(public_key, signature, &message)?; + let valid_signature = barretenberg.verify_signature(public_key, sig_s, sig_e, &message)?; assert!(!valid_signature); // Should fail, since the public key does not match @@ -196,8 +183,8 @@ fn basic_interop() -> Result<(), Error> { let message = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; let public_key_b = barretenberg.construct_public_key(private_key_b)?; - let signature_a = barretenberg.construct_signature(&message, private_key_a)?; - let valid_signature = barretenberg.verify_signature(public_key_b, signature_a, &message)?; + let (sig_s, sig_e) = barretenberg.construct_signature(&message, private_key_a)?; + let valid_signature = barretenberg.verify_signature(public_key_b, sig_s, sig_e, &message)?; assert!(!valid_signature); // Test the first case again, to check if memory is being freed and overwritten properly @@ -205,8 +192,8 @@ fn basic_interop() -> Result<(), Error> { let message = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; let public_key = barretenberg.construct_public_key(private_key)?; - let signature = barretenberg.construct_signature(&message, private_key)?; - let valid_signature = barretenberg.verify_signature(public_key, signature, &message)?; + let (sig_s, sig_e) = barretenberg.construct_signature(&message, private_key)?; + let valid_signature = barretenberg.verify_signature(public_key, sig_s, sig_e, &message)?; assert!(valid_signature); Ok(()) } From 0aa72dec1367b4f546ba96a83894b8ae062240f4 Mon Sep 17 00:00:00 2001 From: Blaine Bublitz Date: Tue, 9 May 2023 13:05:02 -0700 Subject: [PATCH 19/19] cspell --- cspell.json | 1 + src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cspell.json b/cspell.json index 56cb8b03..bdc8f643 100644 --- a/cspell.json +++ b/cspell.json @@ -54,6 +54,7 @@ "nixpkgs", "envrc", "subshell", + "thiserror", // In Solidity // "addmod", diff --git a/src/lib.rs b/src/lib.rs index bfbaad17..0ca43c27 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -56,7 +56,7 @@ enum FeatureError { value: i32, source: std::num::TryFromIntError, }, - #[error("Could not convert value {value} from i32 to usuze")] + #[error("Could not convert value {value} from i32 to usize")] InvalidUsize { value: i32, source: std::num::TryFromIntError,