2021-02-24 12:25:13 -08:00
|
|
|
use std::convert::TryInto;
|
2021-02-24 13:07:22 -08:00
|
|
|
use std::sync::Arc;
|
2021-02-24 12:25:13 -08:00
|
|
|
|
2021-03-01 12:35:02 -08:00
|
|
|
use num::{BigUint, One};
|
|
|
|
|
|
2021-02-09 21:25:21 -08:00
|
|
|
use crate::circuit_data::CircuitConfig;
|
|
|
|
|
use crate::constraint_polynomial::ConstraintPolynomial;
|
|
|
|
|
use crate::field::field::Field;
|
2021-02-26 13:18:41 -08:00
|
|
|
use crate::gates::deterministic_gate::{DeterministicGate, DeterministicGateAdapter};
|
2021-02-24 12:25:13 -08:00
|
|
|
use crate::gates::gate::{Gate, GateRef};
|
2021-02-26 13:18:41 -08:00
|
|
|
use crate::gates::output_graph::{GateOutputLocation, OutputGraph};
|
2021-02-24 12:25:13 -08:00
|
|
|
use crate::generator::{SimpleGenerator, WitnessGenerator2};
|
2021-02-26 13:18:41 -08:00
|
|
|
use crate::gmimc::{gmimc_permute, gmimc_permute_array};
|
|
|
|
|
use crate::target::Target;
|
2021-02-24 12:25:13 -08:00
|
|
|
use crate::wire::Wire;
|
|
|
|
|
use crate::witness::PartialWitness;
|
2021-02-09 21:25:21 -08:00
|
|
|
|
2021-02-24 12:25:13 -08:00
|
|
|
/// Evaluates a full GMiMC permutation, and writes the output to the next gate's first `width`
|
|
|
|
|
/// wires (which could be the input of another `GMiMCGate`).
|
2021-02-09 21:25:21 -08:00
|
|
|
#[derive(Debug)]
|
2021-02-24 12:25:13 -08:00
|
|
|
pub struct GMiMCGate<F: Field, const W: usize, const R: usize> {
|
2021-02-24 13:15:21 -08:00
|
|
|
constants: Arc<[F; R]>,
|
2021-02-09 21:25:21 -08:00
|
|
|
}
|
|
|
|
|
|
2021-02-24 12:25:13 -08:00
|
|
|
impl<F: Field, const W: usize, const R: usize> GMiMCGate<F, W, R> {
|
2021-02-24 13:15:21 -08:00
|
|
|
pub fn with_constants(constants: Arc<[F; R]>) -> GateRef<F> {
|
2021-02-26 13:18:41 -08:00
|
|
|
let gate = GMiMCGate::<F, W, R> { constants };
|
|
|
|
|
let adapter = DeterministicGateAdapter::new(gate);
|
|
|
|
|
GateRef::new(adapter)
|
2021-02-24 13:15:21 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn with_automatic_constants() -> GateRef<F> {
|
2021-02-09 21:25:21 -08:00
|
|
|
todo!()
|
|
|
|
|
}
|
2021-02-26 13:18:41 -08: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.
|
|
|
|
|
// TODO: Assert binary.
|
2021-03-01 12:35:02 -08:00
|
|
|
pub const WIRE_SWITCH: usize = W;
|
2021-02-26 13:18:41 -08:00
|
|
|
|
|
|
|
|
/// The wire index for the i'th input to the permutation.
|
|
|
|
|
pub fn wire_input(i: usize) -> usize {
|
2021-03-01 12:35:02 -08:00
|
|
|
i
|
2021-02-26 13:18:41 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The wire index for the i'th output to the permutation.
|
|
|
|
|
/// Note that outputs are written to the next gate's wires.
|
|
|
|
|
pub fn wire_output(i: usize) -> usize {
|
2021-03-01 12:35:02 -08:00
|
|
|
i
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Adds a local wire output to this output graph. Returns a `ConstraintPolynomial` which
|
|
|
|
|
/// references the newly-created wire.
|
|
|
|
|
///
|
|
|
|
|
/// This may seem like it belongs in `OutputGraph`, but it is not that general, since it uses
|
|
|
|
|
/// a notion of "next available" local wire indices specific to this gate.
|
|
|
|
|
fn add_local(
|
|
|
|
|
outputs: &mut OutputGraph<F>,
|
|
|
|
|
poly: ConstraintPolynomial<F>,
|
|
|
|
|
) -> ConstraintPolynomial<F> {
|
|
|
|
|
let index = outputs.max_local_output_index().map_or(W + 1, |i| i + 1);
|
|
|
|
|
outputs.add(GateOutputLocation::LocalWire(index), poly);
|
|
|
|
|
ConstraintPolynomial::local_wire_value(index)
|
2021-02-26 13:18:41 -08:00
|
|
|
}
|
2021-02-09 21:25:21 -08:00
|
|
|
}
|
|
|
|
|
|
2021-02-26 13:18:41 -08:00
|
|
|
impl<F: Field, const W: usize, const R: usize> DeterministicGate<F> for GMiMCGate<F, W, R> {
|
2021-02-09 21:25:21 -08:00
|
|
|
fn id(&self) -> String {
|
2021-02-26 13:18:41 -08:00
|
|
|
// TODO: This won't include generic params?
|
2021-02-09 21:25:21 -08:00
|
|
|
format!("{:?}", self)
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-26 13:18:41 -08:00
|
|
|
fn outputs(&self, config: CircuitConfig) -> OutputGraph<F> {
|
|
|
|
|
let original_inputs = (0..W)
|
|
|
|
|
.map(|i| ConstraintPolynomial::local_wire_value(Self::wire_input(i)))
|
2021-02-24 13:07:22 -08:00
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
2021-03-01 12:35:02 -08:00
|
|
|
let mut outputs = OutputGraph::new();
|
|
|
|
|
|
2021-02-26 13:18:41 -08:00
|
|
|
// Conditionally switch inputs based on the (boolean) switch wire.
|
|
|
|
|
let switch = ConstraintPolynomial::local_wire_value(Self::WIRE_SWITCH);
|
|
|
|
|
let mut state = Vec::new();
|
|
|
|
|
for i in 0..4 {
|
|
|
|
|
let a = &original_inputs[i];
|
|
|
|
|
let b = &original_inputs[i + 4];
|
|
|
|
|
state.push(a + &switch * (b - a));
|
|
|
|
|
}
|
|
|
|
|
for i in 0..4 {
|
|
|
|
|
let a = &original_inputs[i + 4];
|
|
|
|
|
let b = &original_inputs[i];
|
|
|
|
|
state.push(a + &switch * (b - a));
|
|
|
|
|
}
|
|
|
|
|
for i in 8..W {
|
|
|
|
|
state.push(original_inputs[i].clone());
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-24 13:07:22 -08:00
|
|
|
// Value that is implicitly added to each element.
|
|
|
|
|
// See https://affine.group/2020/02/starkware-challenge
|
|
|
|
|
let mut addition_buffer = ConstraintPolynomial::zero();
|
|
|
|
|
|
|
|
|
|
for r in 0..R {
|
|
|
|
|
let active = r % W;
|
2021-02-24 13:15:21 -08:00
|
|
|
let round_constant = ConstraintPolynomial::constant(self.constants[r]);
|
2021-03-01 12:35:02 -08:00
|
|
|
let mut f_input = &state[active] + &addition_buffer + round_constant;
|
|
|
|
|
if f_input.degree() > BigUint::one() {
|
|
|
|
|
f_input = Self::add_local(&mut outputs, f_input);
|
|
|
|
|
}
|
|
|
|
|
let f_output = f_input.cube();
|
|
|
|
|
addition_buffer += &f_output;
|
|
|
|
|
state[active] -= f_output;
|
2021-02-24 13:07:22 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for i in 0..W {
|
2021-03-01 12:35:02 -08:00
|
|
|
outputs.add(GateOutputLocation::NextWire(i), &state[i] + &addition_buffer);
|
2021-02-24 13:07:22 -08:00
|
|
|
}
|
|
|
|
|
|
2021-03-01 12:35:02 -08:00
|
|
|
outputs
|
2021-02-24 12:25:13 -08:00
|
|
|
}
|
|
|
|
|
|
2021-02-26 13:18:41 -08:00
|
|
|
fn additional_constraints(&self, _config: CircuitConfig) -> Vec<ConstraintPolynomial<F>> {
|
|
|
|
|
let switch = ConstraintPolynomial::local_wire_value(Self::WIRE_SWITCH);
|
|
|
|
|
let switch_bool_constraint = &switch * (&switch - 1);
|
|
|
|
|
vec![switch_bool_constraint]
|
2021-02-24 12:25:13 -08:00
|
|
|
}
|
2021-02-09 21:25:21 -08:00
|
|
|
}
|
2021-02-26 23:30:22 -08:00
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use std::sync::Arc;
|
|
|
|
|
|
2021-03-01 12:35:02 -08:00
|
|
|
use crate::circuit_data::CircuitConfig;
|
2021-02-26 23:30:22 -08:00
|
|
|
use crate::field::crandall_field::CrandallField;
|
|
|
|
|
use crate::field::field::Field;
|
|
|
|
|
use crate::gates::deterministic_gate::DeterministicGate;
|
2021-03-01 12:35:02 -08:00
|
|
|
use crate::gates::gmimc::GMiMCGate;
|
|
|
|
|
use crate::circuit_builder::CircuitBuilder2;
|
2021-02-26 23:30:22 -08:00
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn degree() {
|
|
|
|
|
type F = CrandallField;
|
|
|
|
|
const W: usize = 12;
|
2021-03-01 12:35:02 -08:00
|
|
|
const R: usize = 101;
|
2021-02-26 23:30:22 -08:00
|
|
|
let gate = GMiMCGate::<F, W, R> { constants: Arc::new([F::TWO; R]) };
|
|
|
|
|
let config = CircuitConfig {
|
|
|
|
|
num_wires: 200,
|
|
|
|
|
num_routed_wires: 200,
|
2021-03-01 12:35:02 -08:00
|
|
|
security_bits: 128,
|
2021-02-26 23:30:22 -08:00
|
|
|
};
|
|
|
|
|
let outs = gate.outputs(config);
|
2021-03-01 12:35:02 -08:00
|
|
|
|
|
|
|
|
assert_eq!(outs.degree(), 3);
|
|
|
|
|
assert_eq!(outs.max_local_output_index(), Some(57));
|
|
|
|
|
panic!();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn generated_output() {
|
|
|
|
|
type F = CrandallField;
|
|
|
|
|
const W: usize = 12;
|
|
|
|
|
const R: usize = 101;
|
|
|
|
|
let constants = Arc::new([F::TWO; R]);
|
|
|
|
|
let gate = GMiMCGate::<F, W, R>::with_constants(constants);
|
|
|
|
|
|
|
|
|
|
let config = CircuitConfig {
|
|
|
|
|
num_wires: 200,
|
|
|
|
|
num_routed_wires: 200,
|
|
|
|
|
security_bits: 128,
|
|
|
|
|
};
|
|
|
|
|
let mut builder = CircuitBuilder2::new(config);
|
|
|
|
|
builder.add_gate(gate, Vec::new());
|
|
|
|
|
// let circuit = builder.build();
|
|
|
|
|
|
|
|
|
|
// TODO: generate witness & compare output to normal GMiMC function.
|
2021-02-26 23:30:22 -08:00
|
|
|
}
|
|
|
|
|
}
|