Skip to content

Commit

Permalink
fix: Black box func slice handling (#2562)
Browse files Browse the repository at this point in the history
  • Loading branch information
vezenovm authored Sep 5, 2023
1 parent ed24448 commit c67cd7d
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 195 deletions.
Binary file modified crates/nargo_cli/tests/acir_artifacts/schnorr/target/acir.gz
Binary file not shown.
Binary file modified crates/nargo_cli/tests/acir_artifacts/schnorr/target/witness.gz
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,22 @@ fn main(
input_aggregation_object : [Field; 16],
proof_b : [Field; 94],
) -> pub [Field; 16] {

let verification_key : [Field] = verification_key;
let proof : [Field] = proof;
let proof_b : [Field] = proof_b;
let public_inputs : [Field] = public_inputs;


let output_aggregation_object_a = std::verify_proof(
verification_key,
proof,
public_inputs,
key_hash,
verification_key.as_slice(),
proof.as_slice(),
public_inputs.as_slice(),
key_hash,
input_aggregation_object
);

let output_aggregation_object = std::verify_proof(
verification_key,
proof_b,
public_inputs,
verification_key.as_slice(),
proof_b.as_slice(),
public_inputs.as_slice(),
key_hash,
output_aggregation_object_a
);

let mut output = [0; 16];
for i in 0..16 {
output[i] = output_aggregation_object[i];
Expand Down
157 changes: 33 additions & 124 deletions crates/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,10 @@ pub(crate) fn convert_black_box_call(
) {
match bb_func {
BlackBoxFunc::SHA256 => {
if let ([..], [RegisterOrMemory::HeapArray(result_array)]) =
if let ([message], [RegisterOrMemory::HeapArray(result_array)]) =
(function_arguments, function_results)
{
// Slices are represented as a tuple of (length, slice contents).
// We must check the number of inputs to differentiate between arrays and slices
// and make sure that we pass the correct inputs to the function call.
let message = if function_arguments.len() > 1 {
&function_arguments[1]
} else {
&function_arguments[0]
};
let message_vector = match message {
RegisterOrMemory::HeapArray(message_array) => {
brillig_context.array_to_vector(message_array)
}
RegisterOrMemory::HeapVector(message_vector) => *message_vector,
_ => unreachable!("ICE: SHA256 expects the message to be an array or a vector"),
};
let message_vector = convert_array_or_vector(brillig_context, message, bb_func);
brillig_context.black_box_op_instruction(BlackBoxOp::Sha256 {
message: message_vector,
output: *result_array,
Expand All @@ -43,26 +29,10 @@ pub(crate) fn convert_black_box_call(
}
}
BlackBoxFunc::Blake2s => {
if let ([..], [RegisterOrMemory::HeapArray(result_array)]) =
if let ([message], [RegisterOrMemory::HeapArray(result_array)]) =
(function_arguments, function_results)
{
// Slices are represented as a tuple of (length, slice contents).
// We must check the number of inputs to differentiate between arrays and slices
// and make sure that we pass the correct inputs to the function call.
let message = if function_arguments.len() > 1 {
&function_arguments[1]
} else {
&function_arguments[0]
};
let message_vector = match message {
RegisterOrMemory::HeapArray(message_array) => {
brillig_context.array_to_vector(message_array)
}
RegisterOrMemory::HeapVector(message_vector) => *message_vector,
_ => {
unreachable!("ICE: Blake2s expects the message to be an array or a vector")
}
};
let message_vector = convert_array_or_vector(brillig_context, message, bb_func);
brillig_context.black_box_op_instruction(BlackBoxOp::Blake2s {
message: message_vector,
output: *result_array,
Expand All @@ -73,27 +43,13 @@ pub(crate) fn convert_black_box_call(
}
BlackBoxFunc::Keccak256 => {
if let (
[.., RegisterOrMemory::RegisterIndex(array_size)],
[message, RegisterOrMemory::RegisterIndex(array_size)],
[RegisterOrMemory::HeapArray(result_array)],
) = (function_arguments, function_results)
{
// Slices are represented as a tuple of (length, slice contents).
// We must check the number of inputs to differentiate between arrays and slices
// and make sure that we pass the correct inputs to the function call.
let message = if function_arguments.len() > 2 {
&function_arguments[1]
} else {
&function_arguments[0]
};
let message_vector = match message {
RegisterOrMemory::HeapArray(message_array) => {
HeapVector { size: *array_size, pointer: message_array.pointer }
}
RegisterOrMemory::HeapVector(message_vector) => *message_vector,
_ => unreachable!(
"ICE: Keccak256 expects the message to be an array or a vector"
),
};
let mut message_vector = convert_array_or_vector(brillig_context, message, bb_func);
message_vector.size = *array_size;

brillig_context.black_box_op_instruction(BlackBoxOp::Keccak256 {
message: message_vector,
output: *result_array,
Expand All @@ -103,26 +59,10 @@ pub(crate) fn convert_black_box_call(
}
}
BlackBoxFunc::HashToField128Security => {
if let ([..], [RegisterOrMemory::RegisterIndex(result_register)]) =
if let ([message], [RegisterOrMemory::RegisterIndex(result_register)]) =
(function_arguments, function_results)
{
// Slices are represented as a tuple of (length, slice contents).
// We must check the number of inputs to differentiate between arrays and slices
// and make sure that we pass the correct inputs to the function call.
let message = if function_arguments.len() > 1 {
&function_arguments[1]
} else {
&function_arguments[0]
};
let message_vector = match message {
RegisterOrMemory::HeapArray(message_array) => {
brillig_context.array_to_vector(message_array)
}
RegisterOrMemory::HeapVector(message_vector) => {
*message_vector
}
_ => unreachable!("ICE: HashToField128Security expects the message to be an array or a vector"),
};
let message_vector = convert_array_or_vector(brillig_context, message, bb_func);
brillig_context.black_box_op_instruction(BlackBoxOp::HashToField128Security {
message: message_vector,
output: *result_register,
Expand All @@ -133,27 +73,12 @@ pub(crate) fn convert_black_box_call(
}
BlackBoxFunc::EcdsaSecp256k1 => {
if let (
[RegisterOrMemory::HeapArray(public_key_x), RegisterOrMemory::HeapArray(public_key_y), RegisterOrMemory::HeapArray(signature), ..],
[RegisterOrMemory::HeapArray(public_key_x), RegisterOrMemory::HeapArray(public_key_y), RegisterOrMemory::HeapArray(signature), message],
[RegisterOrMemory::RegisterIndex(result_register)],
) = (function_arguments, function_results)
{
// Slices are represented as a tuple of (length, slice contents).
// We must check the number of inputs to differentiate between arrays and slices
// and make sure that we pass the correct inputs to the function call.
let message = if function_arguments.len() > 4 {
&function_arguments[4]
} else {
&function_arguments[3]
};
let message_hash_vector = match message {
RegisterOrMemory::HeapArray(message_hash) => {
brillig_context.array_to_vector(message_hash)
}
RegisterOrMemory::HeapVector(message_hash_vector) => *message_hash_vector,
_ => unreachable!(
"ICE: EcdsaSecp256k1 expects the message to be an array or a vector"
),
};
let message_hash_vector =
convert_array_or_vector(brillig_context, message, bb_func);
brillig_context.black_box_op_instruction(BlackBoxOp::EcdsaSecp256k1 {
hashed_msg: message_hash_vector,
public_key_x: *public_key_x,
Expand All @@ -169,27 +94,11 @@ pub(crate) fn convert_black_box_call(
}
BlackBoxFunc::Pedersen => {
if let (
[.., RegisterOrMemory::RegisterIndex(domain_separator)],
[message, RegisterOrMemory::RegisterIndex(domain_separator)],
[RegisterOrMemory::HeapArray(result_array)],
) = (function_arguments, function_results)
{
// Slices are represented as a tuple of (length, slice contents).
// We must check the number of inputs to differentiate between arrays and slices
// and make sure that we pass the correct inputs to the function call.
let message = if function_arguments.len() > 2 {
&function_arguments[1]
} else {
&function_arguments[0]
};
let message_vector = match message {
RegisterOrMemory::HeapArray(message_array) => {
brillig_context.array_to_vector(message_array)
}
RegisterOrMemory::HeapVector(message_vector) => *message_vector,
_ => {
unreachable!("ICE: Pedersen expects the message to be an array or a vector")
}
};
let message_vector = convert_array_or_vector(brillig_context, message, bb_func);
brillig_context.black_box_op_instruction(BlackBoxOp::Pedersen {
inputs: message_vector,
domain_separator: *domain_separator,
Expand All @@ -201,27 +110,11 @@ pub(crate) fn convert_black_box_call(
}
BlackBoxFunc::SchnorrVerify => {
if let (
[RegisterOrMemory::RegisterIndex(public_key_x), RegisterOrMemory::RegisterIndex(public_key_y), RegisterOrMemory::HeapArray(signature), ..],
[RegisterOrMemory::RegisterIndex(public_key_x), RegisterOrMemory::RegisterIndex(public_key_y), RegisterOrMemory::HeapArray(signature), message],
[RegisterOrMemory::RegisterIndex(result_register)],
) = (function_arguments, function_results)
{
// Slices are represented as a tuple of (length, slice contents).
// We must check the number of inputs to differentiate between arrays and slices
// and make sure that we pass the correct inputs to the function call.
let message = if function_arguments.len() > 4 {
&function_arguments[4]
} else {
&function_arguments[3]
};
let message_hash = match message {
RegisterOrMemory::HeapArray(message_hash) => {
brillig_context.array_to_vector(message_hash)
}
RegisterOrMemory::HeapVector(message_hash) => *message_hash,
_ => unreachable!(
"ICE: Schnorr verify expects the message to be an array or a vector"
),
};
let message_hash = convert_array_or_vector(brillig_context, message, bb_func);
let signature = brillig_context.array_to_vector(signature);
brillig_context.black_box_op_instruction(BlackBoxOp::SchnorrVerify {
public_key_x: *public_key_x,
Expand Down Expand Up @@ -253,3 +146,19 @@ pub(crate) fn convert_black_box_call(
_ => unimplemented!("ICE: Black box function {:?} is not implemented", bb_func),
}
}

fn convert_array_or_vector(
brillig_context: &mut BrilligContext,
array_or_vector: &RegisterOrMemory,
bb_func: &BlackBoxFunc,
) -> HeapVector {
match array_or_vector {
RegisterOrMemory::HeapArray(array) => brillig_context.array_to_vector(array),
RegisterOrMemory::HeapVector(vector) => *vector,
_ => unreachable!(
"ICE: {} expected an array or a vector, but got {:?}",
bb_func.name(),
array_or_vector
),
}
}
23 changes: 22 additions & 1 deletion crates/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,8 +308,29 @@ impl<'block> BrilligBlock<'block> {
self.convert_ssa_function_call(*func_id, arguments, dfg, instruction_id);
}
Value::Intrinsic(Intrinsic::BlackBox(bb_func)) => {
// Slices are represented as a tuple of (length, slice contents).
// We must check the inputs to determine if there are slices
// and make sure that we pass the correct inputs to the black box function call.
// The loop below only keeps the slice contents, so that
// setting up a black box function with slice inputs matches the expected
// number of arguments specified in the function signature.
let mut arguments_no_slice_len = Vec::new();
for (i, arg) in arguments.iter().enumerate() {
if matches!(dfg.type_of_value(*arg), Type::Numeric(_)) {
if i < arguments.len() - 1 {
if !matches!(dfg.type_of_value(arguments[i + 1]), Type::Slice(_)) {
arguments_no_slice_len.push(*arg);
}
} else {
arguments_no_slice_len.push(*arg);
}
} else {
arguments_no_slice_len.push(*arg);
}
}

let function_arguments =
vecmap(arguments, |arg| self.convert_ssa_value(*arg, dfg));
vecmap(&arguments_no_slice_len, |arg| self.convert_ssa_value(*arg, dfg));
let function_results = dfg.instruction_results(instruction_id);
let function_results = vecmap(function_results, |result| {
self.allocate_external_call_result(*result, dfg)
Expand Down
Loading

0 comments on commit c67cd7d

Please sign in to comment.