use super::{
blake2s::create_blake2s_constraint,
utils::{byte_decomposition, round_to_nearest_byte},
UInt32,
};
use crate::helpers::VariableStore;
use acir::{
brillig::{self, RegisterIndex},
circuit::{
brillig::{Brillig, BrilligInputs, BrilligOutputs},
Opcode,
},
native_types::{Expression, Witness},
FieldElement,
};
pub fn hash_to_field(
inputs: Vec<(Expression, u32)>,
outputs: Witness,
mut num_witness: u32,
) -> (u32, Vec<Opcode>) {
let mut new_opcodes = Vec::new();
let mut new_inputs = Vec::new();
for (witness, num_bits) in inputs {
let num_bytes = round_to_nearest_byte(num_bits);
let (extra_opcodes, extra_inputs, updated_witness_counter) =
byte_decomposition(witness, num_bytes, num_witness);
new_opcodes.extend(extra_opcodes);
new_inputs.extend(extra_inputs);
num_witness = updated_witness_counter;
}
let (result, num_witness, extra_opcodes) = create_blake2s_constraint(new_inputs, num_witness);
new_opcodes.extend(extra_opcodes);
let (result, extra_opcodes, num_witness) = field_from_be_bytes(&result, num_witness);
new_opcodes.extend(extra_opcodes);
let mut expr = Expression::from(outputs);
expr.push_addition_term(-FieldElement::one(), result);
new_opcodes.push(Opcode::Arithmetic(expr));
(num_witness, new_opcodes)
}
fn field_from_be_bytes(result: &[Witness], num_witness: u32) -> (Witness, Vec<Opcode>, u32) {
let mut new_opcodes = Vec::new();
let (new_witness, extra_opcodes, num_witness) = UInt32::load_constant(0, num_witness);
let mut new_witness = new_witness.inner;
new_opcodes.extend(extra_opcodes);
let (const_256, extra_opcodes, mut num_witness) = UInt32::load_constant(256, num_witness);
let const_256 = const_256.inner;
new_opcodes.extend(extra_opcodes);
for r in result.iter().take(result.len() - 1) {
let (updated_witness, extra_opcodes, updated_witness_counter) =
field_addition(&new_witness, r, num_witness);
new_opcodes.extend(extra_opcodes);
let (updated_witness, extra_opcodes, updated_witness_counter) =
field_mul(&updated_witness, &const_256, updated_witness_counter);
new_opcodes.extend(extra_opcodes);
new_witness = updated_witness;
num_witness = updated_witness_counter;
}
let (new_witness, extra_opcodes, num_witness) =
field_addition(&new_witness, &result[result.len() - 1], num_witness);
new_opcodes.extend(extra_opcodes);
(new_witness, new_opcodes, num_witness)
}
fn field_addition(
lhs: &Witness,
rhs: &Witness,
mut num_witness: u32,
) -> (Witness, Vec<Opcode>, u32) {
let mut new_opcodes = Vec::new();
let mut variables = VariableStore::new(&mut num_witness);
let new_witness = variables.new_variable();
let brillig_opcode = Opcode::Brillig(Brillig {
inputs: vec![
BrilligInputs::Single(Expression {
mul_terms: vec![],
linear_combinations: vec![(FieldElement::one(), *lhs)],
q_c: FieldElement::zero(),
}),
BrilligInputs::Single(Expression {
mul_terms: vec![],
linear_combinations: vec![(FieldElement::one(), *rhs)],
q_c: FieldElement::zero(),
}),
],
outputs: vec![BrilligOutputs::Simple(new_witness)],
foreign_call_results: vec![],
bytecode: vec![brillig::Opcode::BinaryFieldOp {
op: brillig::BinaryFieldOp::Add,
lhs: RegisterIndex::from(0),
rhs: RegisterIndex::from(1),
destination: RegisterIndex::from(0),
}],
predicate: None,
});
new_opcodes.push(brillig_opcode);
let num_witness = variables.finalize();
let mut add_expr = Expression::from(new_witness);
add_expr.push_addition_term(-FieldElement::one(), *lhs);
add_expr.push_addition_term(-FieldElement::one(), *rhs);
new_opcodes.push(Opcode::Arithmetic(add_expr));
(new_witness, new_opcodes, num_witness)
}
pub(crate) fn field_mul(
lhs: &Witness,
rhs: &Witness,
mut num_witness: u32,
) -> (Witness, Vec<Opcode>, u32) {
let mut new_opcodes = Vec::new();
let mut variables = VariableStore::new(&mut num_witness);
let new_witness = variables.new_variable();
let brillig_opcode = Opcode::Brillig(Brillig {
inputs: vec![
BrilligInputs::Single(Expression {
mul_terms: vec![],
linear_combinations: vec![(FieldElement::one(), *lhs)],
q_c: FieldElement::zero(),
}),
BrilligInputs::Single(Expression {
mul_terms: vec![],
linear_combinations: vec![(FieldElement::one(), *rhs)],
q_c: FieldElement::zero(),
}),
],
outputs: vec![BrilligOutputs::Simple(new_witness)],
foreign_call_results: vec![],
bytecode: vec![brillig::Opcode::BinaryFieldOp {
op: brillig::BinaryFieldOp::Mul,
lhs: RegisterIndex::from(0),
rhs: RegisterIndex::from(1),
destination: RegisterIndex::from(0),
}],
predicate: None,
});
new_opcodes.push(brillig_opcode);
let num_witness = variables.finalize();
let mut mul_constraint = Expression::from(new_witness);
mul_constraint.push_multiplication_term(-FieldElement::one(), *lhs, *rhs);
new_opcodes.push(Opcode::Arithmetic(mul_constraint));
(new_witness, new_opcodes, num_witness)
}