Skip to content
This repository has been archived by the owner on Apr 9, 2024. It is now read-only.

Commit

Permalink
feat(acvm)!: update black box solver interfaces to match `pwg:black_b…
Browse files Browse the repository at this point in the history
…ox::solve` (#268)

* feat!: update black box solver interfaces to match `pwg:black_box::solve`

* fix: fix build errors

* chore: remove outputs from `StubbedPwg::range`

* chore: remove unnecessary scopes
  • Loading branch information
TomAFrench authored May 9, 2023
1 parent f24dfa4 commit 0098b7d
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 77 deletions.
6 changes: 4 additions & 2 deletions acvm/src/compiler/transformers/fallback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ impl FallbackTransformer {
) -> Result<(u32, Vec<Opcode>), CompileError> {
let (updated_witness_index, opcodes_fallback) = match gc.name {
BlackBoxFunc::AND => {
let (lhs, rhs, result, num_bits) = crate::pwg::logic::extract_input_output(gc);
let (lhs, rhs, result, num_bits) =
crate::pwg::logic::extract_input_output(&gc.inputs, &gc.outputs);
stdlib::fallback::and(
Expression::from(lhs),
Expression::from(rhs),
Expand All @@ -86,7 +87,8 @@ impl FallbackTransformer {
)
}
BlackBoxFunc::XOR => {
let (lhs, rhs, result, num_bits) = crate::pwg::logic::extract_input_output(gc);
let (lhs, rhs, result, num_bits) =
crate::pwg::logic::extract_input_output(&gc.inputs, &gc.outputs);
stdlib::fallback::xor(
Expression::from(lhs),
Expression::from(rhs),
Expand Down
54 changes: 13 additions & 41 deletions acvm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ pub trait PartialWitnessGenerator {
&self,
initial_witness: &mut BTreeMap<Witness, FieldElement>,
inputs: &[FunctionInput],
outputs: &[Witness],
) -> Result<pwg::OpcodeResolution, OpcodeResolutionError>;
fn sha256(
&self,
Expand Down Expand Up @@ -283,129 +282,102 @@ mod test {
_inputs: &[FunctionInput],
_outputs: &[Witness],
) -> Result<OpcodeResolution, OpcodeResolutionError> {
{
panic!("Path not trodden by this test")
}
panic!("Path not trodden by this test")
}
fn and(
&self,
_initial_witness: &mut BTreeMap<Witness, FieldElement>,
_inputs: &[FunctionInput],
_outputs: &[Witness],
) -> Result<OpcodeResolution, OpcodeResolutionError> {
{
panic!("Path not trodden by this test")
}
panic!("Path not trodden by this test")
}
fn xor(
&self,
_initial_witness: &mut BTreeMap<Witness, FieldElement>,
_inputs: &[FunctionInput],
_outputs: &[Witness],
) -> Result<OpcodeResolution, OpcodeResolutionError> {
{
panic!("Path not trodden by this test")
}
panic!("Path not trodden by this test")
}
fn range(
&self,
_initial_witness: &mut BTreeMap<Witness, FieldElement>,
_inputs: &[FunctionInput],
_outputs: &[Witness],
) -> Result<OpcodeResolution, OpcodeResolutionError> {
{
panic!("Path not trodden by this test")
}
panic!("Path not trodden by this test")
}
fn sha256(
&self,
_initial_witness: &mut BTreeMap<Witness, FieldElement>,
_inputs: &[FunctionInput],
_outputs: &[Witness],
) -> Result<OpcodeResolution, OpcodeResolutionError> {
{
panic!("Path not trodden by this test")
}
panic!("Path not trodden by this test")
}
fn blake2s(
&self,
_initial_witness: &mut BTreeMap<Witness, FieldElement>,
_inputs: &[FunctionInput],
_outputs: &[Witness],
) -> Result<OpcodeResolution, OpcodeResolutionError> {
{
panic!("Path not trodden by this test")
}
panic!("Path not trodden by this test")
}
fn compute_merkle_root(
&self,
_initial_witness: &mut BTreeMap<Witness, FieldElement>,
_inputs: &[FunctionInput],
_outputs: &[Witness],
) -> Result<OpcodeResolution, OpcodeResolutionError> {
{
panic!("Path not trodden by this test")
}
panic!("Path not trodden by this test")
}
fn schnorr_verify(
&self,
_initial_witness: &mut BTreeMap<Witness, FieldElement>,
_inputs: &[FunctionInput],
_outputs: &[Witness],
) -> Result<OpcodeResolution, OpcodeResolutionError> {
{
panic!("Path not trodden by this test")
}
panic!("Path not trodden by this test")
}
fn pedersen(
&self,
_initial_witness: &mut BTreeMap<Witness, FieldElement>,
_inputs: &[FunctionInput],
_outputs: &[Witness],
) -> Result<OpcodeResolution, OpcodeResolutionError> {
{
panic!("Path not trodden by this test")
}
panic!("Path not trodden by this test")
}
fn hash_to_field128_security(
&self,
_initial_witness: &mut BTreeMap<Witness, FieldElement>,
_inputs: &[FunctionInput],
_outputs: &[Witness],
) -> Result<OpcodeResolution, OpcodeResolutionError> {
{
panic!("Path not trodden by this test")
}
panic!("Path not trodden by this test")
}
fn ecdsa_secp256k1(
&self,
_initial_witness: &mut BTreeMap<Witness, FieldElement>,
_inputs: &[FunctionInput],
_outputs: &[Witness],
) -> Result<OpcodeResolution, OpcodeResolutionError> {
{
panic!("Path not trodden by this test")
}
panic!("Path not trodden by this test")
}
fn fixed_base_scalar_mul(
&self,
_initial_witness: &mut BTreeMap<Witness, FieldElement>,
_inputs: &[FunctionInput],
_outputs: &[Witness],
) -> Result<OpcodeResolution, OpcodeResolutionError> {
{
panic!("Path not trodden by this test")
}
panic!("Path not trodden by this test")
}
fn keccak256(
&self,
_initial_witness: &mut BTreeMap<Witness, FieldElement>,
_inputs: &[FunctionInput],
_outputs: &[Witness],
) -> Result<OpcodeResolution, OpcodeResolutionError> {
{
panic!("Path not trodden by this test")
}
panic!("Path not trodden by this test")
}
}

Expand Down
3 changes: 2 additions & 1 deletion acvm/src/pwg/blackbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ pub(crate) fn solve(
backend.xor(initial_witness, inputs, outputs)
}
BlackBoxFuncCall { name: BlackBoxFunc::RANGE, inputs, outputs } => {
backend.range(initial_witness, inputs, outputs)
assert!(outputs.is_empty());
backend.range(initial_witness, inputs)
}
BlackBoxFuncCall { name: BlackBoxFunc::SHA256, inputs, outputs } => {
backend.sha256(initial_witness, inputs, outputs)
Expand Down
34 changes: 19 additions & 15 deletions acvm/src/pwg/hash.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use acir::{circuit::opcodes::BlackBoxFuncCall, native_types::Witness, FieldElement};
use acir::{circuit::opcodes::FunctionInput, native_types::Witness, FieldElement};
use blake2::{Blake2s256, Digest};
use sha2::Sha256;
use sha3::Keccak256;
Expand All @@ -10,11 +10,12 @@ use super::{insert_value, witness_to_value};

pub fn blake2s256(
initial_witness: &mut BTreeMap<Witness, FieldElement>,
func_call: &BlackBoxFuncCall,
inputs: &[FunctionInput],
outputs: &[Witness],
) -> Result<OpcodeResolution, OpcodeResolutionError> {
let hash = generic_hash_256::<Blake2s256>(initial_witness, func_call)?;
let hash = generic_hash_256::<Blake2s256>(initial_witness, inputs)?;

for (output_witness, value) in func_call.outputs.iter().zip(hash.iter()) {
for (output_witness, value) in outputs.iter().zip(hash.iter()) {
insert_value(
output_witness,
FieldElement::from_be_bytes_reduce(&[*value]),
Expand All @@ -27,11 +28,12 @@ pub fn blake2s256(

pub fn sha256(
initial_witness: &mut BTreeMap<Witness, FieldElement>,
func_call: &BlackBoxFuncCall,
inputs: &[FunctionInput],
outputs: &[Witness],
) -> Result<OpcodeResolution, OpcodeResolutionError> {
let hash = generic_hash_256::<Sha256>(initial_witness, func_call)?;
let hash = generic_hash_256::<Sha256>(initial_witness, inputs)?;

for (output_witness, value) in func_call.outputs.iter().zip(hash.iter()) {
for (output_witness, value) in outputs.iter().zip(hash.iter()) {
insert_value(
output_witness,
FieldElement::from_be_bytes_reduce(&[*value]),
Expand All @@ -44,11 +46,12 @@ pub fn sha256(

pub fn keccak256(
initial_witness: &mut BTreeMap<Witness, FieldElement>,
func_call: &BlackBoxFuncCall,
inputs: &[FunctionInput],
outputs: &[Witness],
) -> Result<OpcodeResolution, OpcodeResolutionError> {
let hash = generic_hash_256::<Keccak256>(initial_witness, func_call)?;
let hash = generic_hash_256::<Keccak256>(initial_witness, inputs)?;

for (output_witness, value) in func_call.outputs.iter().zip(hash.iter()) {
for (output_witness, value) in outputs.iter().zip(hash.iter()) {
insert_value(
output_witness,
FieldElement::from_be_bytes_reduce(&[*value]),
Expand All @@ -61,24 +64,25 @@ pub fn keccak256(

pub fn hash_to_field_128_security(
initial_witness: &mut BTreeMap<Witness, FieldElement>,
func_call: &BlackBoxFuncCall,
inputs: &[FunctionInput],
outputs: &[Witness],
) -> Result<OpcodeResolution, OpcodeResolutionError> {
let hash = generic_hash_256::<Blake2s256>(initial_witness, func_call)?;
let hash = generic_hash_256::<Blake2s256>(initial_witness, inputs)?;

let reduced_res = FieldElement::from_be_bytes_reduce(&hash);
insert_value(&func_call.outputs[0], reduced_res, initial_witness)?;
insert_value(&outputs[0], reduced_res, initial_witness)?;

Ok(OpcodeResolution::Solved)
}

fn generic_hash_256<D: Digest>(
initial_witness: &mut BTreeMap<Witness, FieldElement>,
func_call: &BlackBoxFuncCall,
inputs: &[FunctionInput],
) -> Result<[u8; 32], OpcodeResolutionError> {
let mut hasher = D::new();

// Read witness assignments into hasher.
for input in func_call.inputs.iter() {
for input in inputs.iter() {
let witness = input.witness;
let num_bits = input.num_bits as usize;

Expand Down
23 changes: 13 additions & 10 deletions acvm/src/pwg/logic.rs
Original file line number Diff line number Diff line change
@@ -1,43 +1,46 @@
use super::{insert_value, witness_to_value};
use crate::{pwg::OpcodeResolution, OpcodeResolutionError};
use acir::{circuit::opcodes::BlackBoxFuncCall, native_types::Witness, FieldElement};
use acir::{circuit::opcodes::FunctionInput, native_types::Witness, FieldElement};
use std::collections::BTreeMap;

/// Solves a [`BlackBoxFunc::And`][acir::circuit::black_box_functions::BlackBoxFunc::AND] opcode and inserts
/// the result into the supplied witness map
pub fn and(
initial_witness: &mut BTreeMap<Witness, FieldElement>,
gate: &BlackBoxFuncCall,
inputs: &[FunctionInput],
outputs: &[Witness],
) -> Result<OpcodeResolution, OpcodeResolutionError> {
let (a, b, result, num_bits) = extract_input_output(gate);
let (a, b, result, num_bits) = extract_input_output(inputs, outputs);
solve_logic_gate(initial_witness, &a, &b, result, |left, right| left.and(right, num_bits))
}

/// Solves a [`BlackBoxFunc::XOR`][acir::circuit::black_box_functions::BlackBoxFunc::XOR] opcode and inserts
/// the result into the supplied witness map
pub fn xor(
initial_witness: &mut BTreeMap<Witness, FieldElement>,
gate: &BlackBoxFuncCall,
inputs: &[FunctionInput],
outputs: &[Witness],
) -> Result<OpcodeResolution, OpcodeResolutionError> {
let (a, b, result, num_bits) = extract_input_output(gate);
let (a, b, result, num_bits) = extract_input_output(inputs, outputs);
solve_logic_gate(initial_witness, &a, &b, result, |left, right| left.xor(right, num_bits))
}

// TODO: Is there somewhere else that we can put this?
// TODO: extraction methods are needed for some opcodes like logic and range
pub(crate) fn extract_input_output(
bb_func_call: &BlackBoxFuncCall,
inputs: &[FunctionInput],
outputs: &[Witness],
) -> (Witness, Witness, Witness, u32) {
let a = &bb_func_call.inputs[0];
let b = &bb_func_call.inputs[1];
let result = &bb_func_call.outputs[0];
let a = &inputs[0];
let b = &inputs[1];
let result = outputs[0];

// The num_bits variable should be the same for all witnesses
assert_eq!(a.num_bits, b.num_bits, "number of bits specified for each input must be the same");

let num_bits = a.num_bits;

(a.witness, b.witness, *result, num_bits)
(a.witness, b.witness, result, num_bits)
}

/// Derives the rest of the witness based on the initial low level variables
Expand Down
8 changes: 4 additions & 4 deletions acvm/src/pwg/range.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use crate::{pwg::witness_to_value, pwg::OpcodeResolution, OpcodeResolutionError};
use acir::{circuit::opcodes::BlackBoxFuncCall, native_types::Witness, BlackBoxFunc, FieldElement};
use acir::{circuit::opcodes::FunctionInput, native_types::Witness, BlackBoxFunc, FieldElement};
use std::collections::BTreeMap;

pub fn solve_range_opcode(
initial_witness: &mut BTreeMap<Witness, FieldElement>,
func_call: &BlackBoxFuncCall,
inputs: &[FunctionInput],
) -> Result<OpcodeResolution, OpcodeResolutionError> {
// TODO: this consistency check can be moved to a general function
let defined_input_size = BlackBoxFunc::RANGE
Expand All @@ -13,7 +13,7 @@ pub fn solve_range_opcode(
.fixed_size()
.expect("infallible: input for range gate is fixed");

let num_arguments = func_call.inputs.len();
let num_arguments = inputs.len();
if num_arguments != defined_input_size as usize {
return Err(OpcodeResolutionError::IncorrectNumFunctionArguments(
defined_input_size as usize,
Expand All @@ -25,7 +25,7 @@ pub fn solve_range_opcode(
// For the range constraint, we know that the input size should be one
assert_eq!(defined_input_size, 1);

let input = func_call.inputs.first().expect("infallible: checked that input size is 1");
let input = inputs.first().expect("infallible: checked that input size is 1");

let w_value = witness_to_value(initial_witness, input.witness)?;
if w_value.num_bits() > input.num_bits {
Expand Down
9 changes: 5 additions & 4 deletions acvm/src/pwg/signature/ecdsa.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
use acir::{circuit::opcodes::BlackBoxFuncCall, native_types::Witness, FieldElement};
use acir::{circuit::opcodes::FunctionInput, native_types::Witness, FieldElement};
use std::collections::BTreeMap;

use crate::{pwg::witness_to_value, pwg::OpcodeResolution, OpcodeResolutionError};

pub fn secp256k1_prehashed(
initial_witness: &mut BTreeMap<Witness, FieldElement>,
gadget_call: &BlackBoxFuncCall,
inputs: &[FunctionInput],
outputs: &[Witness],
) -> Result<OpcodeResolution, OpcodeResolutionError> {
let mut inputs_iter = gadget_call.inputs.iter();
let mut inputs_iter = inputs.iter();

let mut pub_key_x = [0u8; 32];
for (i, pkx) in pub_key_x.iter_mut().enumerate() {
Expand Down Expand Up @@ -50,7 +51,7 @@ pub fn secp256k1_prehashed(
ecdsa_secp256k1::verify_prehashed(&hashed_message, &pub_key_x, &pub_key_y, &signature)
.is_ok();

initial_witness.insert(gadget_call.outputs[0], FieldElement::from(result));
initial_witness.insert(outputs[0], FieldElement::from(result));
Ok(OpcodeResolution::Solved)
}

Expand Down

0 comments on commit 0098b7d

Please sign in to comment.