plonky2/src/gates/gmimc.rs

136 lines
4.5 KiB
Rust
Raw Normal View History

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-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.
pub const WIRE_SWITCH: usize = 0;
/// The wire index for the i'th input to the permutation.
pub fn wire_input(i: usize) -> usize {
i + 1
}
/// 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 {
i + 1
}
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-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-02-24 13:07:22 -08:00
let f = (&state[active] + &addition_buffer + round_constant).cube();
addition_buffer += &f;
state[active] -= f;
}
for i in 0..W {
state[i] += &addition_buffer;
}
2021-02-26 13:18:41 -08:00
let outputs = state.into_iter()
.enumerate()
.map(|(i, out)| (GateOutputLocation::NextWire(Self::wire_output(i)), out))
.collect();
2021-02-24 12:25:13 -08:00
2021-02-28 21:43:10 -08:00
OutputGraph { 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;
use crate::field::crandall_field::CrandallField;
use crate::gates::gmimc::GMiMCGate;
use crate::field::field::Field;
use crate::circuit_data::CircuitConfig;
use crate::gates::deterministic_gate::DeterministicGate;
#[test]
2021-02-27 21:42:12 -08:00
#[ignore]
2021-02-26 23:30:22 -08:00
fn degree() {
type F = CrandallField;
const W: usize = 12;
2021-02-27 21:42:12 -08:00
const R: usize = 20;
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,
security_bits: 128
};
let outs = gate.outputs(config);
assert_eq!(outs.max_wire_input_index(), Some(50));
}
}