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

Commit

Permalink
chore(acvm)!: expose separate solvers for AND and XOR opcodes (#266)
Browse files Browse the repository at this point in the history
* chore!: expose separate solvers for AND and XOR opcodes

* chore: replace boolean flag and `num_bits` args with closure
  • Loading branch information
TomAFrench authored May 8, 2023
1 parent 7bc42c6 commit 84b5d18
Showing 1 changed file with 32 additions and 46 deletions.
78 changes: 32 additions & 46 deletions acvm/src/pwg/logic.rs
Original file line number Diff line number Diff line change
@@ -1,58 +1,28 @@
use super::{insert_value, witness_to_value};
use crate::{pwg::OpcodeResolution, OpcodeResolutionError};
use acir::{circuit::opcodes::BlackBoxFuncCall, native_types::Witness, BlackBoxFunc, FieldElement};
use acir::{circuit::opcodes::BlackBoxFuncCall, native_types::Witness, FieldElement};
use std::collections::BTreeMap;

pub fn solve_logic_opcode(
/// 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>,
func_call: &BlackBoxFuncCall,
gate: &BlackBoxFuncCall,
) -> Result<OpcodeResolution, OpcodeResolutionError> {
match func_call.name {
BlackBoxFunc::AND => LogicSolver::solve_and_gate(initial_witness, func_call),
BlackBoxFunc::XOR => LogicSolver::solve_xor_gate(initial_witness, func_call),
_ => Err(OpcodeResolutionError::UnexpectedOpcode("logic opcode", func_call.name)),
}
let (a, b, result, num_bits) = extract_input_output(gate);
solve_logic_gate(initial_witness, &a, &b, result, |left, right| left.and(right, num_bits))
}

pub struct LogicSolver;

impl LogicSolver {
/// Derives the rest of the witness based on the initial low level variables
fn solve_logic_gate(
initial_witness: &mut BTreeMap<Witness, FieldElement>,
a: &Witness,
b: &Witness,
result: Witness,
num_bits: u32,
is_xor_gate: bool,
) -> Result<OpcodeResolution, OpcodeResolutionError> {
let w_l_value = witness_to_value(initial_witness, *a)?;
let w_r_value = witness_to_value(initial_witness, *b)?;

let assignment = if is_xor_gate {
w_l_value.xor(w_r_value, num_bits)
} else {
w_l_value.and(w_r_value, num_bits)
};
insert_value(&result, assignment, initial_witness)?;
Ok(OpcodeResolution::Solved)
}

pub fn solve_and_gate(
initial_witness: &mut BTreeMap<Witness, FieldElement>,
gate: &BlackBoxFuncCall,
) -> Result<OpcodeResolution, OpcodeResolutionError> {
let (a, b, result, num_bits) = extract_input_output(gate);
LogicSolver::solve_logic_gate(initial_witness, &a, &b, result, num_bits, false)
}
pub fn solve_xor_gate(
initial_witness: &mut BTreeMap<Witness, FieldElement>,
gate: &BlackBoxFuncCall,
) -> Result<OpcodeResolution, OpcodeResolutionError> {
let (a, b, result, num_bits) = extract_input_output(gate);
LogicSolver::solve_logic_gate(initial_witness, &a, &b, result, num_bits, true)
}
/// 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,
) -> Result<OpcodeResolution, OpcodeResolutionError> {
let (a, b, result, num_bits) = extract_input_output(gate);
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(
Expand All @@ -69,3 +39,19 @@ pub(crate) fn extract_input_output(

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

/// Derives the rest of the witness based on the initial low level variables
fn solve_logic_gate(
initial_witness: &mut BTreeMap<Witness, FieldElement>,
a: &Witness,
b: &Witness,
result: Witness,
logic_op: impl Fn(&FieldElement, &FieldElement) -> FieldElement,
) -> Result<OpcodeResolution, OpcodeResolutionError> {
let w_l_value = witness_to_value(initial_witness, *a)?;
let w_r_value = witness_to_value(initial_witness, *b)?;
let assignment = logic_op(w_l_value, w_r_value);

insert_value(&result, assignment, initial_witness)?;
Ok(OpcodeResolution::Solved)
}

0 comments on commit 84b5d18

Please sign in to comment.