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

chore(acvm)!: expose separate solvers for AND and XOR opcodes #266

Merged
merged 2 commits into from
May 8, 2023
Merged
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
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)
}