Skip to content
This repository has been archived by the owner on Dec 9, 2021. It is now read-only.

Partial rewrite #88

Draft
wants to merge 24 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "plonky"
description = "Recursive SNARKs based on Plonk and Halo"
version = "0.1.0"
authors = ["Daniel Lubarov"]
authors = ["Daniel Lubarov <[email protected]>", "William Borgeaud <[email protected]>"]
readme = "README.md"
license = "MIT OR Apache-2.0"
repository = "https://github.com/mir-protocol/plonky"
Expand Down
4 changes: 4 additions & 0 deletions src/field/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,10 @@ pub trait Field:
self.exp(Self::from_canonical_usize(power))
}

fn kth_root_usize(&self, k: usize) -> Self {
self.kth_root(Self::from_canonical_usize(k))
}

fn kth_root_u32(&self, k: u32) -> Self {
self.kth_root(Self::from_canonical_u32(k))
}
Expand Down
3 changes: 3 additions & 0 deletions src/gadgets/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub use range_check::*;

mod range_check;
Empty file added src/gadgets/range_check.rs
Empty file.
96 changes: 96 additions & 0 deletions src/gates2/arithmetic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
use crate::{CircuitBuilder2, CircuitConfig, ConstraintPolynomial, DeterministicGate, DeterministicGateAdapter, Field, GateRef, Target2};

/// A gate which can be configured to perform various arithmetic. In particular, it computes
///
/// ```text
/// output := product_weight * multiplicand_0 * multiplicand_1
/// + addend_weight * addend
/// ```
///
/// where `product_weight` and `addend_weight` are constants, and the other variables are wires.
#[derive(Eq, PartialEq, Hash)]
pub struct ArithmeticGate2;

impl ArithmeticGate2 {
pub fn get_ref<F: Field>() -> GateRef<F> {
GateRef::new(DeterministicGateAdapter::new(ArithmeticGate2))
}

pub const CONST_PRODUCT_WEIGHT: usize = 0;
pub const CONST_ADDEND_WEIGHT: usize = 1;

pub const WIRE_MULTIPLICAND_0: usize = 0;
pub const WIRE_MULTIPLICAND_1: usize = 1;
pub const WIRE_ADDEND: usize = 2;
pub const WIRE_OUTPUT: usize = 3;

/// Computes `x y + z`.
pub fn mul_add<F: Field>(
builder: &mut CircuitBuilder2<F>,
x: Target2<F>,
y: Target2<F>,
z: Target2<F>,
) -> Target2<F> {
let gate_type = ArithmeticGate2::get_ref();
let constants = vec![F::ONE, F::ONE];
let gate = builder.add_gate(gate_type, constants);

builder.route(x, Target2::wire(gate, Self::WIRE_MULTIPLICAND_0));
builder.route(y, Target2::wire(gate, Self::WIRE_MULTIPLICAND_1));
builder.route(z, Target2::wire(gate, Self::WIRE_ADDEND));

Target2::wire(gate, Self::WIRE_OUTPUT)
}

/// Computes `x y`.
pub fn mul<F: Field>(
builder: &mut CircuitBuilder2<F>,
x: Target2<F>,
y: Target2<F>,
) -> Target2<F> {
let zero = builder.zero();
Self::mul_add(builder, x, y, zero)
}

/// Computes `x + y`.
pub fn add<F: Field>(
builder: &mut CircuitBuilder2<F>,
x: Target2<F>,
y: Target2<F>,
) -> Target2<F> {
let one = builder.one();
Self::mul_add(builder, x, one, y)
}
}

impl<F: Field> DeterministicGate<F> for ArithmeticGate2 {
fn id(&self) -> String {
"ArithmeticGate".into()
}

fn outputs(&self, _config: CircuitConfig) -> Vec<(usize, ConstraintPolynomial<F>)> {
let const_0 = ConstraintPolynomial::local_constant(Self::CONST_PRODUCT_WEIGHT);
let const_1 = ConstraintPolynomial::local_constant(Self::CONST_ADDEND_WEIGHT);
let multiplicand_0 = ConstraintPolynomial::local_wire_value(Self::WIRE_MULTIPLICAND_0);
let multiplicand_1 = ConstraintPolynomial::local_wire_value(Self::WIRE_MULTIPLICAND_1);
let addend = ConstraintPolynomial::local_wire_value(Self::WIRE_ADDEND);

let out = const_0 * multiplicand_0 * &multiplicand_1 + const_1 * &addend;
vec![(Self::WIRE_OUTPUT, out)]
}
}

#[cfg(test)]
mod tests {
use crate::{CircuitBuilder2, CircuitConfig, TweedledumBase};
use crate::gates2::arithmetic::ArithmeticGate2;

fn add() {
let config = CircuitConfig { num_wires: 3, num_routed_wires: 3, security_bits: 128 };
let mut builder = CircuitBuilder2::<TweedledumBase>::new(config);
let one = builder.one();
let two = builder.two();
let sum = ArithmeticGate2::add(&mut builder, one, one);
todo!()
}
}
17 changes: 17 additions & 0 deletions src/gates2/buffer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use crate::{CircuitConfig, ConstraintPolynomial, DeterministicGate, Field};

/// A gate which doesn't perform any arithmetic, but just acts as a buffer for receiving data.
/// Some gates, such as the Rescue round gate, "output" their results using one of the next gate's
/// "input" wires. The last such gate has no next gate of the same type, so we add a buffer gate
/// for receiving the last gate's output.
pub struct BufferGate2;

impl<F: Field> DeterministicGate<F> for BufferGate2 {
fn id(&self) -> String {
"Buffer".into()
}

fn outputs(&self, _config: CircuitConfig) -> Vec<(usize, ConstraintPolynomial<F>)> {
Vec::new()
}
}
25 changes: 25 additions & 0 deletions src/gates2/constant.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use crate::{CircuitConfig, ConstraintPolynomial, DeterministicGate, DeterministicGateAdapter, Field, GateRef};

/// A gate which takes a single constant parameter and outputs that value.
pub struct ConstantGate2;

impl ConstantGate2 {
pub fn get_ref<F: Field>() -> GateRef<F> {
GateRef::new(DeterministicGateAdapter::new(ConstantGate2))
}

pub const CONST_INPUT: usize = 0;

pub const WIRE_OUTPUT: usize = 0;
}

impl<F: Field> DeterministicGate<F> for ConstantGate2 {
fn id(&self) -> String {
"ConstantGate".into()
}

fn outputs(&self, _config: CircuitConfig) -> Vec<(usize, ConstraintPolynomial<F>)> {
let out = ConstraintPolynomial::local_constant(Self::CONST_INPUT);
vec![(Self::WIRE_OUTPUT, out)]
}
}
201 changes: 201 additions & 0 deletions src/gates2/curve_add.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
use serde::export::PhantomData;

use crate::{CircuitConfig, ConstraintPolynomial, Curve, Field, Gate2, PartialWitness2, SimpleGenerator, Target2, Wire, WitnessGenerator2};

pub struct CurveAddGate2<C: Curve> {
_phantom: PhantomData<C>,
}

impl<C: Curve> CurveAddGate2<C> {
pub const WIRE_GROUP_ACC_X: usize = 0;
pub const WIRE_GROUP_ACC_Y: usize = 1;
pub const WIRE_SCALAR_ACC_OLD: usize = 2;
pub const WIRE_SCALAR_ACC_NEW: usize = 3;
pub const WIRE_ADDEND_X: usize = 4;
pub const WIRE_ADDEND_Y: usize = 5;
pub const WIRE_SCALAR_BIT: usize = 6;
pub const WIRE_INVERSE: usize = 7;
pub const WIRE_LAMBDA: usize = 8;
}

impl<C: Curve> Gate2<C::BaseField> for CurveAddGate2<C> {
fn id(&self) -> String {
"CurveAddGate".into()
}

fn constraints(
&self,
_config: CircuitConfig,
) -> Vec<ConstraintPolynomial<<C as Curve>::BaseField>> {
// Notation:
// - p1 is the accumulator;
// - p2 is the addend;
// - p3 = p1 + p2;
// - p4 = if scalar_bit { p3 } else { p1 }

let x1 = ConstraintPolynomial::<C::BaseField>::local_wire_value(Self::WIRE_GROUP_ACC_X);
let y1 = ConstraintPolynomial::<C::BaseField>::local_wire_value(Self::WIRE_GROUP_ACC_Y);
let x4 = ConstraintPolynomial::<C::BaseField>::next_wire_value(Self::WIRE_GROUP_ACC_X);
let y4 = ConstraintPolynomial::<C::BaseField>::next_wire_value(Self::WIRE_GROUP_ACC_Y);
let scalar_acc_old = ConstraintPolynomial::<C::BaseField>::local_wire_value(Self::WIRE_SCALAR_ACC_OLD);
let scalar_acc_new = ConstraintPolynomial::<C::BaseField>::local_wire_value(Self::WIRE_SCALAR_ACC_NEW);
let x2 = ConstraintPolynomial::<C::BaseField>::local_wire_value(Self::WIRE_ADDEND_X);
let y2 = ConstraintPolynomial::<C::BaseField>::local_wire_value(Self::WIRE_ADDEND_Y);
let scalar_bit = ConstraintPolynomial::<C::BaseField>::local_wire_value(Self::WIRE_SCALAR_BIT);
let inverse = ConstraintPolynomial::<C::BaseField>::local_wire_value(Self::WIRE_INVERSE);
let lambda = ConstraintPolynomial::<C::BaseField>::local_wire_value(Self::WIRE_LAMBDA);

let computed_lambda = (&y1 - &y2) * &inverse;
let x3 = lambda.square() - &x1 - &x2;
// We subtract x4 instead of x3 in order to minimize degree. This will give an incorrect
// result for y3 if x3 != x4, which happens when scalar_bit = 0, but in that case y3 will
// be ignored (i.e. multiplied by zero), so we're okay.
let y3 = &lambda * (&x1 - &x4) - &y1;

let not_scalar_bit = ConstraintPolynomial::constant_usize(1) - &scalar_bit;
let computed_x4 = &scalar_bit * &x3 + &not_scalar_bit * &x1;
let computed_y4 = &scalar_bit * &y3 + &not_scalar_bit * &y1;

vec![
&computed_lambda - &lambda,
&computed_x4 - &x4,
&computed_y4 - &y4,
&scalar_acc_new - (scalar_acc_old.double() + &scalar_bit),
&scalar_bit * &not_scalar_bit,
&inverse * (&x1 - &x2) - C::BaseField::ONE,
]
}

fn generators(
&self,
_config: CircuitConfig,
gate_index: usize,
_local_constants: Vec<<C as Curve>::BaseField>,
_next_constants: Vec<<C as Curve>::BaseField>,
) -> Vec<Box<dyn WitnessGenerator2<C::BaseField>>> {
let gen = CurveAddGateGenerator::<C> { gate_index, _phantom: PhantomData };
vec![Box::new(gen)]
}
}

struct CurveAddGateGenerator<C: Curve> {
gate_index: usize,
_phantom: PhantomData<C>,
}

impl<C: Curve> SimpleGenerator<C::BaseField> for CurveAddGateGenerator<C> {
fn dependencies(&self) -> Vec<Target2<C::BaseField>> {
vec![
Target2::Wire(Wire {
gate: self.gate_index,
input: CurveAddGate2::<C>::WIRE_GROUP_ACC_X,
}),
Target2::Wire(Wire {
gate: self.gate_index,
input: CurveAddGate2::<C>::WIRE_GROUP_ACC_Y,
}),
Target2::Wire(Wire {
gate: self.gate_index,
input: CurveAddGate2::<C>::WIRE_SCALAR_ACC_OLD,
}),
Target2::Wire(Wire {
gate: self.gate_index,
input: CurveAddGate2::<C>::WIRE_ADDEND_X,
}),
Target2::Wire(Wire {
gate: self.gate_index,
input: CurveAddGate2::<C>::WIRE_ADDEND_Y,
}),
]
}

fn run_once(
&mut self,
witness: &PartialWitness2<C::BaseField>,
) -> PartialWitness2<C::BaseField> {
// Notation:
// - p1 is the accumulator;
// - p2 is the addend;
// - p3 = p1 + p2;
// - p4 = if scalar_bit { p3 } else { p1 }

let x1_wire = Wire {
gate: self.gate_index,
input: CurveAddGate2::<C>::WIRE_GROUP_ACC_X,
};
let y1_wire = Wire {
gate: self.gate_index,
input: CurveAddGate2::<C>::WIRE_GROUP_ACC_Y,
};
let x4_wire = Wire {
gate: self.gate_index + 1,
input: CurveAddGate2::<C>::WIRE_GROUP_ACC_X,
};
let y4_wire = Wire {
gate: self.gate_index + 1,
input: CurveAddGate2::<C>::WIRE_GROUP_ACC_Y,
};
let scalar_acc_old_wire = Wire {
gate: self.gate_index,
input: CurveAddGate2::<C>::WIRE_SCALAR_ACC_OLD,
};
let scalar_acc_new_wire = Wire {
gate: self.gate_index,
input: CurveAddGate2::<C>::WIRE_SCALAR_ACC_NEW,
};
let x2_wire = Wire {
gate: self.gate_index,
input: CurveAddGate2::<C>::WIRE_ADDEND_X,
};
let y2_wire = Wire {
gate: self.gate_index,
input: CurveAddGate2::<C>::WIRE_ADDEND_Y,
};
let scalar_bit_wire = Wire {
gate: self.gate_index,
input: CurveAddGate2::<C>::WIRE_SCALAR_BIT,
};
let inverse_wire = Wire {
gate: self.gate_index,
input: CurveAddGate2::<C>::WIRE_INVERSE,
};
let lambda_wire = Wire {
gate: self.gate_index,
input: CurveAddGate2::<C>::WIRE_LAMBDA,
};

let x1 = witness.get_wire(x1_wire);
let y1 = witness.get_wire(y1_wire);

let scalar_acc_old = witness.get_wire(scalar_acc_old_wire);

let x2 = witness.get_wire(x2_wire);
let y2 = witness.get_wire(y2_wire);

let scalar_bit = witness.get_wire(scalar_bit_wire);
debug_assert!(scalar_bit.is_zero() || scalar_bit.is_one());

let scalar_acc_new = scalar_acc_old.double() + scalar_bit;

let dx = x1 - x2;
let dy = y1 - y2;
let inverse = dx.multiplicative_inverse().expect("x_1 = x_2");
let lambda = dy * inverse;
let x3 = lambda.square() - x1 - x2;
let y3 = lambda * (x1 - x3) - y1;

let (x4, y4) = if scalar_bit.is_one() {
(x3, y3)
} else {
(x1, y1)
};

let mut result = PartialWitness2::new();
result.set_wire(x4_wire, x4);
result.set_wire(y4_wire, y4);
result.set_wire(scalar_acc_new_wire, scalar_acc_new);
result.set_wire(inverse_wire, inverse);
result.set_wire(lambda_wire, lambda);
result
}
}
Loading