Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Black box func slice handling #2562

Merged
merged 5 commits into from
Sep 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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