use crate::helpers::VariableStore;
use acir::{
circuit::{directives::Directive, Opcode},
native_types::{Expression, Witness},
};
use acir_field::FieldElement;
#[deprecated(note = "use bit_decomposition function instead")]
pub fn split(
gate: Expression,
bit_size: u32,
num_witness: u32,
new_gates: &mut Vec<Opcode>,
) -> Vec<Witness> {
let (extra_gates, bits, _) = bit_decomposition(gate, bit_size, num_witness);
new_gates.extend(extra_gates);
bits
}
pub(crate) fn bit_decomposition(
gate: Expression,
bit_size: u32,
mut num_witness: u32,
) -> (Vec<Opcode>, Vec<Witness>, u32) {
let mut new_gates = Vec::new();
let mut variables = VariableStore::new(&mut num_witness);
let mut bit_vector = Vec::with_capacity(bit_size as usize);
for _ in 0..bit_size {
bit_vector.push(variables.new_variable())
}
new_gates.push(Opcode::Directive(Directive::ToRadix {
a: gate.clone(),
b: bit_vector.clone(),
radix: 2,
}));
let mut binary_exprs = Vec::new();
let mut bit_decomp_constraint = gate;
let mut two_pow = FieldElement::one();
let two = FieldElement::from(2_i128);
for &bit in &bit_vector {
let mut expr = Expression::default();
expr.term_multiplication(FieldElement::one(), bit, bit);
expr.term_addition(-FieldElement::one(), bit);
binary_exprs.push(Opcode::Arithmetic(expr));
bit_decomp_constraint.term_addition(-two_pow, bit);
two_pow = two * two_pow;
}
new_gates.extend(binary_exprs);
bit_decomp_constraint.sort(); new_gates.push(Opcode::Arithmetic(bit_decomp_constraint));
(new_gates, bit_vector, variables.finalize())
}
pub fn range(gate: Expression, bit_size: u32, num_witness: u32) -> (u32, Vec<Opcode>) {
let (new_gates, _, updated_witness_counter) = bit_decomposition(gate, bit_size, num_witness);
(updated_witness_counter, new_gates)
}
pub fn and(
a: Expression,
b: Expression,
result: Witness,
bit_size: u32,
num_witness: u32,
) -> (u32, Vec<Opcode>) {
let (extra_gates_a, a_bits, updated_witness_counter) =
bit_decomposition(a, bit_size, num_witness);
let (extra_gates_b, b_bits, updated_witness_counter) =
bit_decomposition(b, bit_size, updated_witness_counter);
assert_eq!(a_bits.len(), b_bits.len());
assert_eq!(a_bits.len(), bit_size as usize);
let mut two_pow = FieldElement::one();
let two = FieldElement::from(2_i128);
let mut and_expr = Expression::default();
for (a_bit, b_bit) in a_bits.into_iter().zip(b_bits) {
and_expr.term_multiplication(two_pow, a_bit, b_bit);
two_pow = two * two_pow;
}
and_expr.term_addition(-FieldElement::one(), result);
and_expr.sort();
let mut new_gates = Vec::new();
new_gates.extend(extra_gates_a);
new_gates.extend(extra_gates_b);
new_gates.push(Opcode::Arithmetic(and_expr));
(updated_witness_counter, new_gates)
}
pub fn xor(
a: Expression,
b: Expression,
result: Witness,
bit_size: u32,
num_witness: u32,
) -> (u32, Vec<Opcode>) {
let (extra_gates_a, a_bits, updated_witness_counter) =
bit_decomposition(a, bit_size, num_witness);
let (extra_gates_b, b_bits, updated_witness_counter) =
bit_decomposition(b, bit_size, updated_witness_counter);
assert_eq!(a_bits.len(), b_bits.len());
assert_eq!(a_bits.len(), bit_size as usize);
let mut two_pow = FieldElement::one();
let two = FieldElement::from(2_i128);
let mut xor_expr = Expression::default();
for (a_bit, b_bit) in a_bits.into_iter().zip(b_bits) {
xor_expr.term_addition(two_pow, a_bit);
xor_expr.term_addition(two_pow, b_bit);
two_pow = two * two_pow;
xor_expr.term_multiplication(-two_pow, a_bit, b_bit);
}
xor_expr.term_addition(-FieldElement::one(), result);
xor_expr.sort();
let mut new_gates = Vec::new();
new_gates.extend(extra_gates_a);
new_gates.extend(extra_gates_b);
new_gates.push(Opcode::Arithmetic(xor_expr));
(updated_witness_counter, new_gates)
}