From ae71bc8bd6b4ed657b62724afdf0c3baf422783b Mon Sep 17 00:00:00 2001 From: TomAFrench Date: Wed, 26 Jul 2023 04:11:21 +0000 Subject: [PATCH] chore: reduce code duplication --- .../src/ssa_refactor/ir/dfg.rs | 6 +- .../src/ssa_refactor/ir/instruction.rs | 250 ++++++++---------- 2 files changed, 113 insertions(+), 143 deletions(-) diff --git a/crates/noirc_evaluator/src/ssa_refactor/ir/dfg.rs b/crates/noirc_evaluator/src/ssa_refactor/ir/dfg.rs index c6309c4fe11..caf65c85a7e 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/ir/dfg.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/ir/dfg.rs @@ -369,11 +369,7 @@ impl DataFlowGraph { pub(crate) fn get_array_constant(&self, value: ValueId) -> Option<(im::Vector, Type)> { match &self.values[self.resolve(value)] { // Vectors are shared, so cloning them is cheap - Value::Array { array, typ } - if array.iter().all(|value| self.get_numeric_constant(*value).is_some()) => - { - Some((array.clone(), typ.clone())) - } + Value::Array { array, typ } => Some((array.clone(), typ.clone())), _ => None, } } diff --git a/crates/noirc_evaluator/src/ssa_refactor/ir/instruction.rs b/crates/noirc_evaluator/src/ssa_refactor/ir/instruction.rs index 024ba43639a..e65a7935e30 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/ir/instruction.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/ir/instruction.rs @@ -1,6 +1,6 @@ use std::rc::Rc; -use acvm::{acir::BlackBoxFunc, FieldElement}; +use acvm::{acir::BlackBoxFunc, BlackBoxResolutionError, FieldElement}; use iter_extended::vecmap; use num_bigint::BigUint; @@ -499,14 +499,12 @@ fn simplify_call(func: ValueId, arguments: &[ValueId], dfg: &mut DataFlowGraph) } /// Try to simplify this black box call. If the call can be simplified to a known value, -/// that value is returned. Otherwise None is returned. +/// that value is returned. Otherwise [`SimplifyResult::None`] is returned. fn simplify_bb_func( bb_func: BlackBoxFunc, arguments: &[ValueId], dfg: &mut DataFlowGraph, ) -> SimplifyResult { - use SimplifyResult::*; - fn to_u8_vec(dfg: &DataFlowGraph, values: im::Vector>) -> Vec { values .iter() @@ -519,95 +517,20 @@ fn simplify_bb_func( .collect() } - match bb_func { - BlackBoxFunc::AND => { - if let (Some((lhs, Type::Numeric(NumericType::Unsigned { bit_size }))), Some(rhs)) = ( - dfg.get_numeric_constant_with_type(arguments[0]), - dfg.get_numeric_constant(arguments[1]), - ) { - let output = lhs.and(&rhs, bit_size); - let output = dfg.make_constant(output, Type::unsigned(bit_size)); - SimplifiedTo(output) - } else { - None - } - } - BlackBoxFunc::XOR => { - if let (Some((lhs, Type::Numeric(NumericType::Unsigned { bit_size }))), Some(rhs)) = ( - dfg.get_numeric_constant_with_type(arguments[0]), - dfg.get_numeric_constant(arguments[1]), - ) { - let output = lhs.xor(&rhs, bit_size); - let output = dfg.make_constant(output, Type::unsigned(bit_size)); - SimplifiedTo(output) - } else { - None - } - } - BlackBoxFunc::SHA256 => { - if let Some((input, _)) = dfg.get_array_constant(arguments[0]) { - let input_bytes: Vec = to_u8_vec(dfg, input); - - let hash = acvm::blackbox_solver::sha256(&input_bytes).unwrap(); - - let hash_values = vecmap(hash, |byte| { - dfg.make_constant( - FieldElement::from_be_bytes_reduce(&[byte]), - Type::unsigned(8), - ) - }); - let element_type: Vec = - hash_values.iter().map(|_| Type::unsigned(8)).collect(); - let new_slice = dfg.make_array(hash_values.into(), element_type.into()); - - SimplifiedTo(new_slice) - } else { - None - } - } - BlackBoxFunc::Blake2s => { - if let Some((input, _)) = dfg.get_array_constant(arguments[0]) { - let input_bytes: Vec = to_u8_vec(dfg, input); - - let hash = acvm::blackbox_solver::blake2s(&input_bytes).unwrap(); - - let hash_values = vecmap(hash, |byte| { - dfg.make_constant( - FieldElement::from_be_bytes_reduce(&[byte]), - Type::unsigned(8), - ) - }); - let element_type: Vec = - hash_values.iter().map(|_| Type::unsigned(8)).collect(); - let new_slice = dfg.make_array(hash_values.into(), element_type.into()); - - SimplifiedTo(new_slice) - } else { - None - } - } - BlackBoxFunc::HashToField128Security => { - if let Some((input, _)) = dfg.get_array_constant(arguments[0]) { - let input_bytes: Vec = to_u8_vec(dfg, input); - - let field = - acvm::blackbox_solver::hash_to_field_128_security(&input_bytes).unwrap(); + fn array_is_constant(dfg: &DataFlowGraph, values: &im::Vector>) -> bool { + values.iter().all(|value| dfg.get_numeric_constant(*value).is_some()) + } - let field_constant = dfg.make_constant(field, Type::field()); - SimplifiedTo(field_constant) - } else { - None - } - } - BlackBoxFunc::Keccak256 => { - if let (Some((input, _)), Some(num_bytes)) = - (dfg.get_array_constant(arguments[0]), dfg.get_numeric_constant(arguments[1])) - { + fn simplify_hash( + dfg: &mut DataFlowGraph, + arguments: &[ValueId], + hash_function: fn(&[u8]) -> Result<[u8; 32], BlackBoxResolutionError>, + ) -> SimplifyResult { + match dfg.get_array_constant(arguments[0]) { + Some((input, _)) if array_is_constant(dfg, &input) => { let input_bytes: Vec = to_u8_vec(dfg, input); - let num_bytes = num_bytes.to_u128() as usize; - let truncated_input_bytes = &input_bytes[0..num_bytes]; - let hash = acvm::blackbox_solver::keccak256(truncated_input_bytes).unwrap(); + let hash = hash_function(&input_bytes).unwrap(); let hash_values = vecmap(hash, |byte| { dfg.make_constant( @@ -619,80 +542,131 @@ fn simplify_bb_func( hash_values.iter().map(|_| Type::unsigned(8)).collect(); let new_slice = dfg.make_array(hash_values.into(), element_type.into()); - SimplifiedTo(new_slice) - } else { - None + SimplifyResult::SimplifiedTo(new_slice) } + _ => SimplifyResult::None, } + } - BlackBoxFunc::EcdsaSecp256k1 => { - if let ( + type ECDSASignatureVerifier = fn( + hashed_msg: &[u8], + public_key_x: &[u8; 32], + public_key_y: &[u8; 32], + signature: &[u8; 64], + ) -> Result; + fn simplify_signature( + dfg: &mut DataFlowGraph, + arguments: &[ValueId], + signature_verifier: ECDSASignatureVerifier, + ) -> SimplifyResult { + match ( + dfg.get_array_constant(arguments[0]), + dfg.get_array_constant(arguments[1]), + dfg.get_array_constant(arguments[2]), + dfg.get_array_constant(arguments[3]), + ) { + ( Some((pubkey_x, _)), Some((pubkey_y, _)), Some((signature, _)), Some((hashed_message, _)), - ) = ( - dfg.get_array_constant(arguments[0]), - dfg.get_array_constant(arguments[1]), - dfg.get_array_constant(arguments[2]), - dfg.get_array_constant(arguments[3]), - ) { + ) if array_is_constant(dfg, &pubkey_x) + && array_is_constant(dfg, &pubkey_y) + && array_is_constant(dfg, &signature) + && array_is_constant(dfg, &hashed_message) => + { let public_key_x: [u8; 32] = to_u8_vec(dfg, pubkey_x).try_into().unwrap(); let public_key_y: [u8; 32] = to_u8_vec(dfg, pubkey_y).try_into().unwrap(); let signature: [u8; 64] = to_u8_vec(dfg, signature).try_into().unwrap(); let hashed_message: Vec = to_u8_vec(dfg, hashed_message); - let valid_signature = acvm::blackbox_solver::ecdsa_secp256k1_verify( - &hashed_message, - &public_key_x, - &public_key_y, - &signature, - ) - .unwrap(); + let valid_signature = + signature_verifier(&hashed_message, &public_key_x, &public_key_y, &signature) + .unwrap(); let valid_signature = dfg.make_constant(valid_signature.into(), Type::bool()); - SimplifiedTo(valid_signature) + SimplifyResult::SimplifiedTo(valid_signature) + } + _ => SimplifyResult::None, + } + } + + match bb_func { + BlackBoxFunc::AND => { + if let (Some((lhs, Type::Numeric(NumericType::Unsigned { bit_size }))), Some(rhs)) = ( + dfg.get_numeric_constant_with_type(arguments[0]), + dfg.get_numeric_constant(arguments[1]), + ) { + let output = lhs.and(&rhs, bit_size); + let output = dfg.make_constant(output, Type::unsigned(bit_size)); + SimplifyResult::SimplifiedTo(output) } else { - None + SimplifyResult::None } } - BlackBoxFunc::EcdsaSecp256r1 => { - if let ( - Some((pubkey_x, _)), - Some((pubkey_y, _)), - Some((signature, _)), - Some((hashed_message, _)), - ) = ( - dfg.get_array_constant(arguments[0]), - dfg.get_array_constant(arguments[1]), - dfg.get_array_constant(arguments[2]), - dfg.get_array_constant(arguments[3]), + BlackBoxFunc::XOR => { + if let (Some((lhs, Type::Numeric(NumericType::Unsigned { bit_size }))), Some(rhs)) = ( + dfg.get_numeric_constant_with_type(arguments[0]), + dfg.get_numeric_constant(arguments[1]), ) { - let public_key_x: [u8; 32] = to_u8_vec(dfg, pubkey_x).try_into().unwrap(); - let public_key_y: [u8; 32] = to_u8_vec(dfg, pubkey_y).try_into().unwrap(); - let signature: [u8; 64] = to_u8_vec(dfg, signature).try_into().unwrap(); - let hashed_message: Vec = to_u8_vec(dfg, hashed_message); + let output = lhs.xor(&rhs, bit_size); + let output = dfg.make_constant(output, Type::unsigned(bit_size)); + SimplifyResult::SimplifiedTo(output) + } else { + SimplifyResult::None + } + } + BlackBoxFunc::SHA256 => simplify_hash(dfg, arguments, acvm::blackbox_solver::sha256), + BlackBoxFunc::Blake2s => simplify_hash(dfg, arguments, acvm::blackbox_solver::blake2s), + BlackBoxFunc::Keccak256 => { + match (dfg.get_array_constant(arguments[0]), dfg.get_numeric_constant(arguments[1])) { + (Some((input, _)), Some(num_bytes)) if array_is_constant(dfg, &input) => { + let input_bytes: Vec = to_u8_vec(dfg, input); + + let num_bytes = num_bytes.to_u128() as usize; + let truncated_input_bytes = &input_bytes[0..num_bytes]; + let hash = acvm::blackbox_solver::keccak256(truncated_input_bytes).unwrap(); + + let hash_values = vecmap(hash, |byte| { + dfg.make_constant( + FieldElement::from_be_bytes_reduce(&[byte]), + Type::unsigned(8), + ) + }); + let element_type: Vec = + hash_values.iter().map(|_| Type::unsigned(8)).collect(); + let new_slice = dfg.make_array(hash_values.into(), element_type.into()); + + SimplifyResult::SimplifiedTo(new_slice) + } + _ => SimplifyResult::None, + } + } + BlackBoxFunc::HashToField128Security => match dfg.get_array_constant(arguments[0]) { + Some((input, _)) if array_is_constant(dfg, &input) => { + let input_bytes: Vec = to_u8_vec(dfg, input); - let valid_signature = acvm::blackbox_solver::ecdsa_secp256r1_verify( - &hashed_message, - &public_key_x, - &public_key_y, - &signature, - ) - .unwrap(); + let field = + acvm::blackbox_solver::hash_to_field_128_security(&input_bytes).unwrap(); - let valid_signature = dfg.make_constant(valid_signature.into(), Type::bool()); - SimplifiedTo(valid_signature) - } else { - None + let field_constant = dfg.make_constant(field, Type::field()); + SimplifyResult::SimplifiedTo(field_constant) } + _ => SimplifyResult::None, + }, + + BlackBoxFunc::EcdsaSecp256k1 => { + simplify_signature(dfg, arguments, acvm::blackbox_solver::ecdsa_secp256k1_verify) + } + BlackBoxFunc::EcdsaSecp256r1 => { + simplify_signature(dfg, arguments, acvm::blackbox_solver::ecdsa_secp256r1_verify) } BlackBoxFunc::FixedBaseScalarMul | BlackBoxFunc::SchnorrVerify | BlackBoxFunc::Pedersen => { // Currently unsolvable here as we rely on an implementation in the backend. - None + SimplifyResult::None } - BlackBoxFunc::RANGE | BlackBoxFunc::RecursiveAggregation => None, + BlackBoxFunc::RANGE | BlackBoxFunc::RecursiveAggregation => SimplifyResult::None, } } /// Returns a Value::Array of constants corresponding to the limbs of the radix decomposition.