2021-09-07 18:28:28 -07:00
|
|
|
use std::marker::PhantomData;
|
2021-02-24 12:25:13 -08:00
|
|
|
|
2021-05-30 13:25:53 -07:00
|
|
|
use crate::field::extension_field::target::ExtensionTarget;
|
|
|
|
|
use crate::field::extension_field::Extendable;
|
2021-09-07 18:28:28 -07:00
|
|
|
use crate::field::field_types::{Field, RichField};
|
2021-07-22 23:48:03 -07:00
|
|
|
use crate::gates::gate::Gate;
|
2021-09-07 18:28:28 -07:00
|
|
|
use crate::hash::gmimc;
|
|
|
|
|
use crate::hash::gmimc::GMiMC;
|
2021-08-20 09:55:49 +02:00
|
|
|
use crate::iop::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator};
|
2021-07-29 22:00:29 -07:00
|
|
|
use crate::iop::target::Target;
|
|
|
|
|
use crate::iop::wire::Wire;
|
2021-08-20 11:13:40 +02:00
|
|
|
use crate::iop::witness::{PartitionWitness, Witness};
|
2021-07-29 22:00:29 -07:00
|
|
|
use crate::plonk::circuit_builder::CircuitBuilder;
|
|
|
|
|
use crate::plonk::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase};
|
2021-02-09 21:25:21 -08:00
|
|
|
|
2021-09-16 17:51:07 +02:00
|
|
|
/// Evaluates a full GMiMC permutation with 12 state elements.
|
2021-04-12 10:38:07 +02:00
|
|
|
///
|
|
|
|
|
/// This also has some extra features to make it suitable for efficiently verifying Merkle proofs.
|
|
|
|
|
/// It has a flag which can be used to swap the first four inputs with the next four, for ordering
|
2021-09-17 13:47:08 +02:00
|
|
|
/// sibling digests.
|
2021-02-09 21:25:21 -08:00
|
|
|
#[derive(Debug)]
|
2021-09-07 18:28:28 -07:00
|
|
|
pub struct GMiMCGate<
|
|
|
|
|
F: RichField + Extendable<D> + GMiMC<WIDTH>,
|
|
|
|
|
const D: usize,
|
|
|
|
|
const WIDTH: usize,
|
|
|
|
|
> {
|
|
|
|
|
_phantom: PhantomData<F>,
|
2021-02-09 21:25:21 -08:00
|
|
|
}
|
|
|
|
|
|
2021-09-07 18:28:28 -07:00
|
|
|
impl<F: RichField + Extendable<D> + GMiMC<WIDTH>, const D: usize, const WIDTH: usize>
|
|
|
|
|
GMiMCGate<F, D, WIDTH>
|
|
|
|
|
{
|
|
|
|
|
pub fn new() -> Self {
|
|
|
|
|
GMiMCGate {
|
|
|
|
|
_phantom: PhantomData,
|
|
|
|
|
}
|
2021-02-09 21:25:21 -08:00
|
|
|
}
|
2021-02-26 13:18:41 -08:00
|
|
|
|
2021-04-12 10:38:07 +02:00
|
|
|
/// The wire index for the `i`th input to the permutation.
|
2021-02-26 13:18:41 -08:00
|
|
|
pub fn wire_input(i: usize) -> usize {
|
2021-03-01 12:35:02 -08:00
|
|
|
i
|
2021-02-26 13:18:41 -08:00
|
|
|
}
|
|
|
|
|
|
2021-04-12 10:38:07 +02:00
|
|
|
/// The wire index for the `i`th output to the permutation.
|
2021-02-26 13:18:41 -08:00
|
|
|
pub fn wire_output(i: usize) -> usize {
|
2021-09-07 18:28:28 -07:00
|
|
|
WIDTH + i
|
2021-03-01 12:35:02 -08:00
|
|
|
}
|
|
|
|
|
|
2021-04-12 10:38:07 +02:00
|
|
|
/// If this is set to 1, the first four inputs will be swapped with the next four inputs. This
|
|
|
|
|
/// is useful for ordering hashes in Merkle proofs. Otherwise, this should be set to 0.
|
2021-09-07 18:28:28 -07:00
|
|
|
pub const WIRE_SWAP: usize = 2 * WIDTH;
|
2021-04-12 10:38:07 +02:00
|
|
|
|
2021-03-28 15:36:51 -07:00
|
|
|
/// A wire which stores the input to the `i`th cubing.
|
|
|
|
|
fn wire_cubing_input(i: usize) -> usize {
|
2021-09-07 18:28:28 -07:00
|
|
|
2 * WIDTH + 1 + i
|
2021-02-26 13:18:41 -08:00
|
|
|
}
|
2021-05-20 05:35:16 -07:00
|
|
|
|
|
|
|
|
/// End of wire indices, exclusive.
|
|
|
|
|
fn end() -> usize {
|
2021-09-07 18:28:28 -07:00
|
|
|
2 * WIDTH + 1 + gmimc::NUM_ROUNDS
|
2021-05-20 05:35:16 -07:00
|
|
|
}
|
2021-02-09 21:25:21 -08:00
|
|
|
}
|
|
|
|
|
|
2021-09-07 18:28:28 -07:00
|
|
|
impl<F: RichField + Extendable<D> + GMiMC<WIDTH>, const D: usize, const WIDTH: usize> Gate<F, D>
|
|
|
|
|
for GMiMCGate<F, D, WIDTH>
|
2021-09-05 10:27:11 -07:00
|
|
|
{
|
2021-02-09 21:25:21 -08:00
|
|
|
fn id(&self) -> String {
|
2021-09-07 18:28:28 -07:00
|
|
|
format!("<WIDTH={}> {:?}", WIDTH, self)
|
2021-02-09 21:25:21 -08:00
|
|
|
}
|
|
|
|
|
|
2021-05-30 13:25:53 -07:00
|
|
|
fn eval_unfiltered(&self, vars: EvaluationVars<F, D>) -> Vec<F::Extension> {
|
2021-04-27 13:16:24 -07:00
|
|
|
let mut constraints = Vec::with_capacity(self.num_constraints());
|
2021-02-24 13:07:22 -08:00
|
|
|
|
2021-04-12 10:38:07 +02:00
|
|
|
// Assert that `swap` is binary.
|
|
|
|
|
let swap = vars.local_wires[Self::WIRE_SWAP];
|
2021-05-30 13:25:53 -07:00
|
|
|
constraints.push(swap * (swap - F::Extension::ONE));
|
2021-04-12 10:38:07 +02:00
|
|
|
|
2021-03-28 15:36:51 -07:00
|
|
|
let mut state = Vec::with_capacity(12);
|
2021-02-26 13:18:41 -08:00
|
|
|
for i in 0..4 {
|
2021-03-28 15:36:51 -07:00
|
|
|
let a = vars.local_wires[i];
|
|
|
|
|
let b = vars.local_wires[i + 4];
|
2021-04-12 10:38:07 +02:00
|
|
|
state.push(a + swap * (b - a));
|
2021-02-26 13:18:41 -08:00
|
|
|
}
|
|
|
|
|
for i in 0..4 {
|
2021-03-28 15:36:51 -07:00
|
|
|
let a = vars.local_wires[i + 4];
|
|
|
|
|
let b = vars.local_wires[i];
|
2021-04-12 10:38:07 +02:00
|
|
|
state.push(a + swap * (b - a));
|
2021-02-26 13:18:41 -08:00
|
|
|
}
|
2021-03-28 15:36:51 -07:00
|
|
|
for i in 8..12 {
|
|
|
|
|
state.push(vars.local_wires[i]);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-12 10:38:07 +02:00
|
|
|
// Value that is implicitly added to each element.
|
|
|
|
|
// See https://affine.group/2020/02/starkware-challenge
|
2021-05-30 13:25:53 -07:00
|
|
|
let mut addition_buffer = F::Extension::ZERO;
|
2021-04-12 10:38:07 +02:00
|
|
|
|
2021-09-07 18:28:28 -07:00
|
|
|
for r in 0..gmimc::NUM_ROUNDS {
|
|
|
|
|
let active = r % WIDTH;
|
|
|
|
|
let constant = F::from_canonical_u64(<F as GMiMC<WIDTH>>::ROUND_CONSTANTS[r]);
|
|
|
|
|
let cubing_input = state[active] + addition_buffer + constant.into();
|
2021-03-28 15:36:51 -07:00
|
|
|
let cubing_input_wire = vars.local_wires[Self::wire_cubing_input(r)];
|
|
|
|
|
constraints.push(cubing_input - cubing_input_wire);
|
|
|
|
|
let f = cubing_input_wire.cube();
|
|
|
|
|
addition_buffer += f;
|
|
|
|
|
state[active] -= f;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-07 18:28:28 -07:00
|
|
|
for i in 0..WIDTH {
|
2021-07-22 14:00:55 +02:00
|
|
|
state[i] += addition_buffer;
|
|
|
|
|
constraints.push(state[i] - vars.local_wires[Self::wire_output(i)]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
constraints
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn eval_unfiltered_base(&self, vars: EvaluationVarsBase<F>) -> Vec<F> {
|
|
|
|
|
let mut constraints = Vec::with_capacity(self.num_constraints());
|
|
|
|
|
|
|
|
|
|
// Assert that `swap` is binary.
|
|
|
|
|
let swap = vars.local_wires[Self::WIRE_SWAP];
|
2021-10-22 19:11:05 -07:00
|
|
|
constraints.push(swap * swap.sub_one());
|
2021-07-22 14:00:55 +02:00
|
|
|
|
|
|
|
|
let mut state = Vec::with_capacity(12);
|
|
|
|
|
for i in 0..4 {
|
|
|
|
|
let a = vars.local_wires[i];
|
|
|
|
|
let b = vars.local_wires[i + 4];
|
|
|
|
|
state.push(a + swap * (b - a));
|
|
|
|
|
}
|
|
|
|
|
for i in 0..4 {
|
|
|
|
|
let a = vars.local_wires[i + 4];
|
|
|
|
|
let b = vars.local_wires[i];
|
|
|
|
|
state.push(a + swap * (b - a));
|
|
|
|
|
}
|
|
|
|
|
for i in 8..12 {
|
|
|
|
|
state.push(vars.local_wires[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Value that is implicitly added to each element.
|
|
|
|
|
// See https://affine.group/2020/02/starkware-challenge
|
|
|
|
|
let mut addition_buffer = F::ZERO;
|
|
|
|
|
|
2021-09-07 18:28:28 -07:00
|
|
|
for r in 0..gmimc::NUM_ROUNDS {
|
|
|
|
|
let active = r % WIDTH;
|
|
|
|
|
let constant = F::from_canonical_u64(<F as GMiMC<WIDTH>>::ROUND_CONSTANTS[r]);
|
|
|
|
|
let cubing_input = state[active] + addition_buffer + constant;
|
2021-03-28 15:36:51 -07:00
|
|
|
let cubing_input_wire = vars.local_wires[Self::wire_cubing_input(r)];
|
|
|
|
|
constraints.push(cubing_input - cubing_input_wire);
|
|
|
|
|
let f = cubing_input_wire.cube();
|
|
|
|
|
addition_buffer += f;
|
|
|
|
|
state[active] -= f;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-07 18:28:28 -07:00
|
|
|
for i in 0..WIDTH {
|
2021-03-28 15:36:51 -07:00
|
|
|
state[i] += addition_buffer;
|
2021-04-12 10:38:07 +02:00
|
|
|
constraints.push(state[i] - vars.local_wires[Self::wire_output(i)]);
|
2021-03-28 15:36:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
constraints
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn eval_unfiltered_recursively(
|
|
|
|
|
&self,
|
2021-05-30 13:25:53 -07:00
|
|
|
builder: &mut CircuitBuilder<F, D>,
|
|
|
|
|
vars: EvaluationTargets<D>,
|
|
|
|
|
) -> Vec<ExtensionTarget<D>> {
|
2021-04-27 13:16:24 -07:00
|
|
|
let mut constraints = Vec::with_capacity(self.num_constraints());
|
|
|
|
|
|
|
|
|
|
let swap = vars.local_wires[Self::WIRE_SWAP];
|
2021-07-13 09:15:16 +02:00
|
|
|
constraints.push(builder.mul_sub_extension(swap, swap, swap));
|
2021-04-27 13:16:24 -07:00
|
|
|
|
|
|
|
|
let mut state = Vec::with_capacity(12);
|
|
|
|
|
for i in 0..4 {
|
|
|
|
|
let a = vars.local_wires[i];
|
|
|
|
|
let b = vars.local_wires[i + 4];
|
2021-05-30 13:25:53 -07:00
|
|
|
let delta = builder.sub_extension(b, a);
|
|
|
|
|
state.push(builder.mul_add_extension(swap, delta, a));
|
2021-04-27 13:16:24 -07:00
|
|
|
}
|
|
|
|
|
for i in 0..4 {
|
|
|
|
|
let a = vars.local_wires[i + 4];
|
|
|
|
|
let b = vars.local_wires[i];
|
2021-05-30 13:25:53 -07:00
|
|
|
let delta = builder.sub_extension(b, a);
|
|
|
|
|
state.push(builder.mul_add_extension(swap, delta, a));
|
2021-04-27 13:16:24 -07:00
|
|
|
}
|
|
|
|
|
for i in 8..12 {
|
|
|
|
|
state.push(vars.local_wires[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Value that is implicitly added to each element.
|
|
|
|
|
// See https://affine.group/2020/02/starkware-challenge
|
2021-05-30 13:25:53 -07:00
|
|
|
let mut addition_buffer = builder.zero_extension();
|
2021-04-27 13:16:24 -07:00
|
|
|
|
2021-09-07 18:28:28 -07:00
|
|
|
for r in 0..gmimc::NUM_ROUNDS {
|
|
|
|
|
let active = r % WIDTH;
|
2021-04-27 13:16:24 -07:00
|
|
|
|
2021-09-07 18:28:28 -07:00
|
|
|
let constant = F::from_canonical_u64(<F as GMiMC<WIDTH>>::ROUND_CONSTANTS[r]);
|
|
|
|
|
let constant = builder.constant_extension(constant.into());
|
2021-05-30 13:25:53 -07:00
|
|
|
let cubing_input =
|
2021-08-17 00:38:41 -07:00
|
|
|
builder.add_many_extension(&[state[active], addition_buffer, constant]);
|
2021-07-13 09:15:16 +02:00
|
|
|
let cubing_input_wire = vars.local_wires[Self::wire_cubing_input(r)];
|
|
|
|
|
constraints.push(builder.sub_extension(cubing_input, cubing_input_wire));
|
2021-08-05 08:03:49 -07:00
|
|
|
let f = builder.cube_extension(cubing_input_wire);
|
2021-08-16 10:18:10 +02:00
|
|
|
addition_buffer = builder.add_extension(addition_buffer, f);
|
|
|
|
|
state[active] = builder.sub_extension(state[active], f);
|
2021-04-27 13:16:24 -07:00
|
|
|
}
|
|
|
|
|
|
2021-09-07 18:28:28 -07:00
|
|
|
for i in 0..WIDTH {
|
2021-05-30 13:25:53 -07:00
|
|
|
state[i] = builder.add_extension(state[i], addition_buffer);
|
|
|
|
|
constraints
|
|
|
|
|
.push(builder.sub_extension(state[i], vars.local_wires[Self::wire_output(i)]));
|
2021-04-27 13:16:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
constraints
|
2021-03-28 15:36:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn generators(
|
|
|
|
|
&self,
|
|
|
|
|
gate_index: usize,
|
|
|
|
|
_local_constants: &[F],
|
|
|
|
|
) -> Vec<Box<dyn WitnessGenerator<F>>> {
|
2021-09-07 18:28:28 -07:00
|
|
|
let gen = GMiMCGenerator::<F, D, WIDTH> {
|
2021-03-28 15:36:51 -07:00
|
|
|
gate_index,
|
2021-09-07 18:28:28 -07:00
|
|
|
_phantom: PhantomData,
|
2021-03-28 15:36:51 -07:00
|
|
|
};
|
2021-09-02 15:03:03 -07:00
|
|
|
vec![Box::new(gen.adapter())]
|
2021-03-28 15:36:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn num_wires(&self) -> usize {
|
2021-05-20 05:35:16 -07:00
|
|
|
Self::end()
|
2021-03-28 15:36:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn num_constants(&self) -> usize {
|
|
|
|
|
0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn degree(&self) -> usize {
|
|
|
|
|
3
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn num_constraints(&self) -> usize {
|
2021-09-07 18:28:28 -07:00
|
|
|
gmimc::NUM_ROUNDS + WIDTH + 1
|
2021-03-28 15:36:51 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
2021-09-07 18:28:28 -07:00
|
|
|
struct GMiMCGenerator<
|
|
|
|
|
F: RichField + Extendable<D> + GMiMC<WIDTH>,
|
|
|
|
|
const D: usize,
|
|
|
|
|
const WIDTH: usize,
|
|
|
|
|
> {
|
2021-03-28 15:36:51 -07:00
|
|
|
gate_index: usize,
|
2021-09-07 18:28:28 -07:00
|
|
|
_phantom: PhantomData<F>,
|
2021-03-28 15:36:51 -07:00
|
|
|
}
|
|
|
|
|
|
2021-09-07 18:28:28 -07:00
|
|
|
impl<F: RichField + Extendable<D> + GMiMC<WIDTH>, const D: usize, const WIDTH: usize>
|
|
|
|
|
SimpleGenerator<F> for GMiMCGenerator<F, D, WIDTH>
|
2021-05-30 13:25:53 -07:00
|
|
|
{
|
2021-03-28 15:36:51 -07:00
|
|
|
fn dependencies(&self) -> Vec<Target> {
|
2021-09-07 18:28:28 -07:00
|
|
|
let mut dep_input_indices = Vec::with_capacity(WIDTH + 1);
|
|
|
|
|
for i in 0..WIDTH {
|
|
|
|
|
dep_input_indices.push(GMiMCGate::<F, D, WIDTH>::wire_input(i));
|
2021-04-12 10:38:07 +02:00
|
|
|
}
|
2021-09-07 18:28:28 -07:00
|
|
|
dep_input_indices.push(GMiMCGate::<F, D, WIDTH>::WIRE_SWAP);
|
2021-04-12 10:38:07 +02:00
|
|
|
|
2021-04-21 22:31:45 +02:00
|
|
|
dep_input_indices
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|input| {
|
|
|
|
|
Target::Wire(Wire {
|
|
|
|
|
gate: self.gate_index,
|
|
|
|
|
input,
|
|
|
|
|
})
|
|
|
|
|
})
|
2021-03-28 15:36:51 -07:00
|
|
|
.collect()
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-20 09:55:49 +02:00
|
|
|
fn run_once(&self, witness: &PartitionWitness<F>, out_buffer: &mut GeneratedValues<F>) {
|
2021-09-07 18:28:28 -07:00
|
|
|
let mut state = (0..WIDTH)
|
2021-04-21 22:31:45 +02:00
|
|
|
.map(|i| {
|
|
|
|
|
witness.get_wire(Wire {
|
|
|
|
|
gate: self.gate_index,
|
2021-09-07 18:28:28 -07:00
|
|
|
input: GMiMCGate::<F, D, WIDTH>::wire_input(i),
|
2021-04-21 22:31:45 +02:00
|
|
|
})
|
|
|
|
|
})
|
2021-03-28 15:36:51 -07:00
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
2021-04-12 10:38:07 +02:00
|
|
|
let swap_value = witness.get_wire(Wire {
|
2021-03-28 15:36:51 -07:00
|
|
|
gate: self.gate_index,
|
2021-09-07 18:28:28 -07:00
|
|
|
input: GMiMCGate::<F, D, WIDTH>::WIRE_SWAP,
|
2021-03-28 15:36:51 -07:00
|
|
|
});
|
2021-04-12 10:38:07 +02:00
|
|
|
debug_assert!(swap_value == F::ZERO || swap_value == F::ONE);
|
|
|
|
|
if swap_value == F::ONE {
|
2021-03-28 15:36:51 -07:00
|
|
|
for i in 0..4 {
|
|
|
|
|
state.swap(i, 4 + i);
|
|
|
|
|
}
|
2021-02-26 13:18:41 -08:00
|
|
|
}
|
|
|
|
|
|
2021-02-24 13:07:22 -08:00
|
|
|
// Value that is implicitly added to each element.
|
|
|
|
|
// See https://affine.group/2020/02/starkware-challenge
|
2021-03-28 15:36:51 -07:00
|
|
|
let mut addition_buffer = F::ZERO;
|
2021-02-24 13:07:22 -08:00
|
|
|
|
2021-09-07 18:28:28 -07:00
|
|
|
for r in 0..gmimc::NUM_ROUNDS {
|
|
|
|
|
let active = r % WIDTH;
|
|
|
|
|
let constant = F::from_canonical_u64(<F as GMiMC<WIDTH>>::ROUND_CONSTANTS[r]);
|
|
|
|
|
let cubing_input = state[active] + addition_buffer + constant;
|
2021-08-02 10:55:10 -07:00
|
|
|
out_buffer.set_wire(
|
2021-03-28 15:36:51 -07:00
|
|
|
Wire {
|
|
|
|
|
gate: self.gate_index,
|
2021-09-07 18:28:28 -07:00
|
|
|
input: GMiMCGate::<F, D, WIDTH>::wire_cubing_input(r),
|
2021-03-28 15:36:51 -07:00
|
|
|
},
|
2021-04-21 22:31:45 +02:00
|
|
|
cubing_input,
|
|
|
|
|
);
|
2021-03-28 15:36:51 -07:00
|
|
|
let f = cubing_input.cube();
|
|
|
|
|
addition_buffer += f;
|
|
|
|
|
state[active] -= f;
|
2021-02-24 13:07:22 -08:00
|
|
|
}
|
|
|
|
|
|
2021-09-07 18:28:28 -07:00
|
|
|
for i in 0..WIDTH {
|
2021-03-28 15:36:51 -07:00
|
|
|
state[i] += addition_buffer;
|
2021-08-02 10:55:10 -07:00
|
|
|
out_buffer.set_wire(
|
2021-03-28 15:36:51 -07:00
|
|
|
Wire {
|
2021-04-12 10:38:07 +02:00
|
|
|
gate: self.gate_index,
|
2021-09-07 18:28:28 -07:00
|
|
|
input: GMiMCGate::<F, D, WIDTH>::wire_output(i),
|
2021-03-28 15:36:51 -07:00
|
|
|
},
|
2021-04-21 22:31:45 +02:00
|
|
|
state[i],
|
|
|
|
|
);
|
2021-02-24 13:07:22 -08:00
|
|
|
}
|
2021-02-24 12:25:13 -08:00
|
|
|
}
|
2021-02-09 21:25:21 -08:00
|
|
|
}
|
2021-02-26 23:30:22 -08:00
|
|
|
|
2021-08-20 12:15:15 +02:00
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use std::convert::TryInto;
|
|
|
|
|
|
|
|
|
|
use anyhow::Result;
|
|
|
|
|
|
|
|
|
|
use crate::field::field_types::Field;
|
2021-11-02 12:04:42 -07:00
|
|
|
use crate::field::goldilocks_field::GoldilocksField;
|
2021-08-20 12:15:15 +02:00
|
|
|
use crate::gates::gate_testing::{test_eval_fns, test_low_degree};
|
2021-09-07 18:28:28 -07:00
|
|
|
use crate::gates::gmimc::GMiMCGate;
|
|
|
|
|
use crate::hash::gmimc::GMiMC;
|
2021-08-20 12:15:15 +02:00
|
|
|
use crate::iop::generator::generate_partial_witness;
|
|
|
|
|
use crate::iop::wire::Wire;
|
2021-09-13 16:38:55 -07:00
|
|
|
use crate::iop::witness::{PartialWitness, Witness};
|
|
|
|
|
use crate::plonk::circuit_builder::CircuitBuilder;
|
|
|
|
|
use crate::plonk::circuit_data::CircuitConfig;
|
2021-08-20 12:15:15 +02:00
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn generated_output() {
|
2021-11-02 12:04:42 -07:00
|
|
|
type F = GoldilocksField;
|
2021-09-07 18:28:28 -07:00
|
|
|
const WIDTH: usize = 12;
|
2021-09-13 16:38:55 -07:00
|
|
|
|
2021-11-03 14:30:32 -07:00
|
|
|
let config = CircuitConfig::standard_recursion_config();
|
2021-09-13 16:38:55 -07:00
|
|
|
let mut builder = CircuitBuilder::new(config);
|
2021-09-07 18:28:28 -07:00
|
|
|
type Gate = GMiMCGate<F, 4, WIDTH>;
|
|
|
|
|
let gate = Gate::new();
|
2021-09-13 16:38:55 -07:00
|
|
|
let gate_index = builder.add_gate(gate, vec![]);
|
|
|
|
|
let circuit = builder.build_prover();
|
2021-08-20 12:15:15 +02:00
|
|
|
|
2021-09-07 18:28:28 -07:00
|
|
|
let permutation_inputs = (0..WIDTH).map(F::from_canonical_usize).collect::<Vec<_>>();
|
2021-08-20 12:15:15 +02:00
|
|
|
|
2021-09-13 16:38:55 -07:00
|
|
|
let mut inputs = PartialWitness::new();
|
|
|
|
|
inputs.set_wire(
|
2021-08-20 12:15:15 +02:00
|
|
|
Wire {
|
2021-09-13 16:38:55 -07:00
|
|
|
gate: gate_index,
|
2021-08-20 12:15:15 +02:00
|
|
|
input: Gate::WIRE_SWAP,
|
|
|
|
|
},
|
|
|
|
|
F::ZERO,
|
|
|
|
|
);
|
2021-09-07 18:28:28 -07:00
|
|
|
for i in 0..WIDTH {
|
2021-09-13 16:38:55 -07:00
|
|
|
inputs.set_wire(
|
2021-08-20 12:15:15 +02:00
|
|
|
Wire {
|
2021-09-13 16:38:55 -07:00
|
|
|
gate: gate_index,
|
2021-08-20 12:15:15 +02:00
|
|
|
input: Gate::wire_input(i),
|
|
|
|
|
},
|
|
|
|
|
permutation_inputs[i],
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-28 22:31:20 -07:00
|
|
|
let witness = generate_partial_witness(inputs, &circuit.prover_only, &circuit.common);
|
2021-08-20 12:15:15 +02:00
|
|
|
|
2021-09-07 18:28:28 -07:00
|
|
|
let expected_outputs: [F; WIDTH] =
|
|
|
|
|
F::gmimc_permute_naive(permutation_inputs.try_into().unwrap());
|
|
|
|
|
for i in 0..WIDTH {
|
2021-09-13 16:38:55 -07:00
|
|
|
let out = witness.get_wire(Wire {
|
2021-08-20 12:15:15 +02:00
|
|
|
gate: 0,
|
|
|
|
|
input: Gate::wire_output(i),
|
|
|
|
|
});
|
|
|
|
|
assert_eq!(out, expected_outputs[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn low_degree() {
|
2021-11-02 12:04:42 -07:00
|
|
|
type F = GoldilocksField;
|
2021-09-07 18:28:28 -07:00
|
|
|
const WIDTH: usize = 12;
|
|
|
|
|
let gate = GMiMCGate::<F, 4, WIDTH>::new();
|
2021-08-20 12:15:15 +02:00
|
|
|
test_low_degree(gate)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn eval_fns() -> Result<()> {
|
2021-11-02 12:04:42 -07:00
|
|
|
type F = GoldilocksField;
|
2021-09-07 18:28:28 -07:00
|
|
|
const WIDTH: usize = 12;
|
|
|
|
|
let gate = GMiMCGate::<F, 4, WIDTH>::new();
|
2021-08-20 12:15:15 +02:00
|
|
|
test_eval_fns(gate)
|
|
|
|
|
}
|
|
|
|
|
}
|