Skip to content

Commit

Permalink
chore: reduce code duplication
Browse files Browse the repository at this point in the history
  • Loading branch information
TomAFrench committed Aug 2, 2023
1 parent c198295 commit ae71bc8
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 143 deletions.
6 changes: 1 addition & 5 deletions crates/noirc_evaluator/src/ssa_refactor/ir/dfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,11 +369,7 @@ impl DataFlowGraph {
pub(crate) fn get_array_constant(&self, value: ValueId) -> Option<(im::Vector<ValueId>, 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,
}
}
Expand Down
250 changes: 112 additions & 138 deletions crates/noirc_evaluator/src/ssa_refactor/ir/instruction.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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<Id<Value>>) -> Vec<u8> {
values
.iter()
Expand All @@ -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<u8> = 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<Type> =
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<u8> = 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<Type> =
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<u8> = 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<Id<Value>>) -> 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<u8> = 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(
Expand All @@ -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<bool, BlackBoxResolutionError>;
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, _)),

Check warning on line 569 in crates/noirc_evaluator/src/ssa_refactor/ir/instruction.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (pubkey)
Some((pubkey_y, _)),

Check warning on line 570 in crates/noirc_evaluator/src/ssa_refactor/ir/instruction.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (pubkey)
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)

Check warning on line 573 in crates/noirc_evaluator/src/ssa_refactor/ir/instruction.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (pubkey)
&& array_is_constant(dfg, &pubkey_y)

Check warning on line 574 in crates/noirc_evaluator/src/ssa_refactor/ir/instruction.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (pubkey)
&& 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();

Check warning on line 578 in crates/noirc_evaluator/src/ssa_refactor/ir/instruction.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (pubkey)
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<u8> = 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<u8> = 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<u8> = 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<Type> =
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<u8> = 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.
Expand Down

0 comments on commit ae71bc8

Please sign in to comment.