From 334c19051f161c6ec1375cf931294f91b9f38fa6 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Tue, 20 Apr 2021 22:59:28 +0800 Subject: [PATCH] Fix ECC chip to work with new chip trait --- Cargo.toml | 2 +- src/circuit/gadget/ecc.rs | 112 ++- src/circuit/gadget/ecc/chip.rs | 864 ++++++++++-------- src/circuit/gadget/ecc/chip/add.rs | 43 +- src/circuit/gadget/ecc/chip/add_complete.rs | 86 +- src/circuit/gadget/ecc/chip/double.rs | 45 +- src/circuit/gadget/ecc/chip/mul.rs | 69 +- src/circuit/gadget/ecc/chip/mul_fixed.rs | 65 +- .../gadget/ecc/chip/mul_fixed_short.rs | 48 +- src/circuit/gadget/ecc/chip/util.rs | 12 +- src/circuit/gadget/ecc/chip/witness_point.rs | 18 +- .../gadget/ecc/chip/witness_scalar_fixed.rs | 22 +- .../ecc/chip/witness_scalar_fixed_short.rs | 22 +- .../gadget/ecc/chip/witness_scalar_var.rs | 20 +- src/constants.rs | 12 +- 15 files changed, 800 insertions(+), 640 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6c4a15f9a..7f6a51efc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ subtle = "2.3" [dependencies.halo2] git = "https://github.com/zcash/halo2.git" -rev = "6acacf1aca12f34fc311aa59056e40adc0e6d8bd" +branch = "chip-config" [dependencies.pasta_curves] git = "https://github.com/zcash/pasta_curves.git" diff --git a/src/circuit/gadget/ecc.rs b/src/circuit/gadget/ecc.rs index de13b165a..74cd37642 100644 --- a/src/circuit/gadget/ecc.rs +++ b/src/circuit/gadget/ecc.rs @@ -8,13 +8,13 @@ use halo2::{ plonk::Error, }; -mod chip; +pub mod chip; /// Trait allowing circuit's fixed points to be enumerated. -pub trait FixedPoints: Clone + fmt::Debug {} +pub trait FixedPoints {} /// The set of circuit instructions required to use the ECC gadgets. -pub trait EccInstructions: Chip { +pub trait EccInstructions: Chip { /// Variable representing an element of the elliptic curve's scalar field, to be used for variable-base scalar mul. type ScalarVar: Clone + fmt::Debug; /// Variable representing a full-width element of the elliptic curve's scalar field, to be used for fixed-base scalar mul. @@ -32,25 +32,29 @@ pub trait EccInstructions: Chip { /// Witnesses the given scalar as a private input to the circuit for variable-based scalar mul. fn witness_scalar_var( - layouter: &mut impl Layouter, + &self, + layouter: &mut impl Layouter, value: Option, ) -> Result; /// Witnesses the given full-width scalar as a private input to the circuit for fixed-based scalar mul. fn witness_scalar_fixed( - layouter: &mut impl Layouter, + &self, + layouter: &mut impl Layouter, value: Option, ) -> Result; /// Witnesses the given signed short scalar as a private input to the circuit for fixed-based scalar mul. fn witness_scalar_fixed_short( - layouter: &mut impl Layouter, + &self, + layouter: &mut impl Layouter, value: Option, ) -> Result; /// Witnesses the given point as a private input to the circuit. fn witness_point( - layouter: &mut impl Layouter, + &self, + layouter: &mut impl Layouter, value: Option, ) -> Result; @@ -58,45 +62,51 @@ pub trait EccInstructions: Chip { fn extract_p(point: &Self::Point) -> &Self::X; /// Gets a fixed point into the circuit. - fn get_fixed( - layouter: &mut impl Layouter, - fixed_points: Self::FixedPoints, - ) -> Result; + fn get_fixed(&self, fixed_points: Self::FixedPoints) -> Result; /// Performs point addition, returning `a + b`. fn add( - layouter: &mut impl Layouter, + &self, + layouter: &mut impl Layouter, a: &Self::Point, b: &Self::Point, ) -> Result; /// Performs complete point addition, returning `a + b`. fn add_complete( - layouter: &mut impl Layouter, + &self, + layouter: &mut impl Layouter, a: &Self::Point, b: &Self::Point, ) -> Result; /// Performs point doubling, returning `[2] a`. - fn double(layouter: &mut impl Layouter, a: &Self::Point) -> Result; + fn double( + &self, + layouter: &mut impl Layouter, + a: &Self::Point, + ) -> Result; /// Performs variable-base scalar multiplication, returning `[scalar] base`. fn mul( - layouter: &mut impl Layouter, + &self, + layouter: &mut impl Layouter, scalar: &Self::ScalarVar, base: &Self::Point, ) -> Result; /// Performs fixed-base scalar multiplication using a full-width scalar, returning `[scalar] base`. fn mul_fixed( - layouter: &mut impl Layouter, + &self, + layouter: &mut impl Layouter, scalar: &Self::ScalarFixed, base: &Self::FixedPoint, ) -> Result; /// Performs fixed-base scalar multiplication using a short signed scalar, returning `[scalar] base`. fn mul_fixed_short( - layouter: &mut impl Layouter, + &self, + layouter: &mut impl Layouter, scalar: &Self::ScalarFixedShort, base: &Self::FixedPoint, ) -> Result; @@ -111,10 +121,12 @@ pub struct ScalarVar> { impl> ScalarVar { /// Constructs a new ScalarVar with the given value. pub fn new( - mut layouter: impl Layouter, + chip: EccChip, + mut layouter: impl Layouter, value: Option, ) -> Result { - EccChip::witness_scalar_var(&mut layouter, value).map(|inner| ScalarVar { inner }) + chip.witness_scalar_var(&mut layouter, value) + .map(|inner| ScalarVar { inner }) } } @@ -127,10 +139,12 @@ pub struct ScalarFixed> { impl> ScalarFixed { /// Constructs a new ScalarFixed with the given value. pub fn new( - mut layouter: impl Layouter, + chip: EccChip, + mut layouter: impl Layouter, value: Option, ) -> Result { - EccChip::witness_scalar_fixed(&mut layouter, value).map(|inner| ScalarFixed { inner }) + chip.witness_scalar_fixed(&mut layouter, value) + .map(|inner| ScalarFixed { inner }) } } @@ -143,10 +157,11 @@ pub struct ScalarFixedShort> { impl> ScalarFixedShort { /// Constructs a new ScalarFixedShort with the given value. pub fn new( - mut layouter: impl Layouter, + chip: EccChip, + mut layouter: impl Layouter, value: Option, ) -> Result { - EccChip::witness_scalar_fixed_short(&mut layouter, value) + chip.witness_scalar_fixed_short(&mut layouter, value) .map(|inner| ScalarFixedShort { inner }) } } @@ -159,8 +174,13 @@ pub struct Point> { impl> Point { /// Constructs a new point with the given value. - pub fn new(mut layouter: impl Layouter, value: Option) -> Result { - EccChip::witness_point(&mut layouter, value).map(|inner| Point { inner }) + pub fn new( + chip: EccChip, + mut layouter: impl Layouter, + value: Option, + ) -> Result { + chip.witness_point(&mut layouter, value) + .map(|inner| Point { inner }) } /// Extracts the x-coordinate of a point. @@ -174,22 +194,35 @@ impl> Point { } /// Returns `self + other`. - pub fn add(&self, mut layouter: impl Layouter, other: &Self) -> Result { - EccChip::add(&mut layouter, &self.inner, &other.inner).map(|inner| Point { inner }) + pub fn add( + &self, + chip: EccChip, + mut layouter: impl Layouter, + other: &Self, + ) -> Result { + chip.add(&mut layouter, &self.inner, &other.inner) + .map(|inner| Point { inner }) } /// Returns `[2] self`. - pub fn double(&self, mut layouter: impl Layouter) -> Result { - EccChip::double(&mut layouter, &self.inner).map(|inner| Point { inner }) + pub fn double( + &self, + chip: EccChip, + mut layouter: impl Layouter, + ) -> Result { + chip.double(&mut layouter, &self.inner) + .map(|inner| Point { inner }) } /// Returns `[by] self`. pub fn mul( &self, - mut layouter: impl Layouter, + chip: EccChip, + mut layouter: impl Layouter, by: &ScalarVar, ) -> Result { - EccChip::mul(&mut layouter, &by.inner, &self.inner).map(|inner| Point { inner }) + chip.mul(&mut layouter, &by.inner, &self.inner) + .map(|inner| Point { inner }) } } @@ -208,26 +241,27 @@ impl> X { /// A constant elliptic curve point over the given curve, for which scalar multiplication /// is more efficient. -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct FixedPoint> { inner: EccChip::FixedPoint, } +impl> FixedPoints for FixedPoint {} + impl> FixedPoint { /// Gets a reference to the specified fixed point in the circuit. - pub fn get( - mut layouter: impl Layouter, - point: EccChip::FixedPoints, - ) -> Result { - EccChip::get_fixed(&mut layouter, point).map(|inner| FixedPoint { inner }) + pub fn get(chip: EccChip, point: EccChip::FixedPoints) -> Result { + chip.get_fixed(point).map(|inner| FixedPoint { inner }) } /// Returns `[by] self`. pub fn mul( &self, - mut layouter: impl Layouter, + chip: EccChip, + mut layouter: impl Layouter, by: &ScalarFixed, ) -> Result, Error> { - EccChip::mul_fixed(&mut layouter, &by.inner, &self.inner).map(|inner| Point { inner }) + chip.mul_fixed(&mut layouter, &by.inner, &self.inner) + .map(|inner| Point { inner }) } } diff --git a/src/circuit/gadget/ecc/chip.rs b/src/circuit/gadget/ecc/chip.rs index c5dd68bc2..9c6406148 100644 --- a/src/circuit/gadget/ecc/chip.rs +++ b/src/circuit/gadget/ecc/chip.rs @@ -1,12 +1,12 @@ -use std::{collections::BTreeMap, marker::PhantomData}; +use std::{collections::BTreeMap, convert::TryFrom, marker::PhantomData}; use super::{EccInstructions, FixedPoints}; -use crate::constants::{self, FixedBase, OrchardFixedBases}; +use crate::constants::{self, FixedBase, Name}; use ff::PrimeField; use halo2::{ arithmetic::{CurveAffine, FieldExt}, - circuit::{Cell, Chip, Layouter}, - plonk::{Advice, Column, ConstraintSystem, Error, Fixed, Permutation, Selector}, + circuit::{CellValue, Chip, Config, Layouter, Loaded}, + plonk::{Advice, Any, Column, ConstraintSystem, Error, Fixed, Permutation, Selector}, poly::Rotation, }; @@ -26,90 +26,236 @@ mod witness_scalar_var; /// assigned to a cell. #[derive(Clone, Debug)] pub struct EccPoint { - x: CellValue, - y: CellValue, + /// x-coordinate + pub x: CellValue, + /// y-coordinate + pub y: CellValue, } -/// A structure containing a cell and its assigned value. +/// Configuration for the ECC chip #[derive(Clone, Debug)] -pub struct CellValue { - cell: Cell, - value: Option, -} - -impl CellValue { - pub fn new(cell: Cell, value: Option) -> Self { - CellValue { cell, value } - } +#[allow(non_snake_case)] +pub struct EccConfig { + /// Advice column for scalar decomposition into bits + pub bits: Column, + /// Witness u = (y + z).sqrt(), used in fixed-base scalar multiplication + pub u: Column, + /// Holds a point (x_a, y_a) that is usually the result of an addition + pub A: (Column, Column), + /// Holds a point (x_p, y_p) + pub P: (Column, Column), + /// A pair (lambda1, lambda2) representing gradients + pub lambda: (Column, Column), + /// [A, B, C, D] boolean flags used in complete addition + pub add_complete_bool: [Column; 4], + /// [alpha, beta, gamma, delta] inverses used in complete addition + pub add_complete_inv: [Column; 4], + /// Coefficients of interpolation polynomials for x-coordinates (used in fixed-base scalar multiplication) + pub lagrange_coeffs: [Column; constants::H], + /// Fixed z such that y + z = u^2 some square, and -y + z is a non-square. (Used in fixed-base scalar multiplication) + pub fixed_z: Column, + + /// Incomplete addition + pub q_add: Selector, + /// Complete addition + pub q_add_complete: Selector, + /// Point doubling + pub q_double: Selector, + /// Variable-base scalar multiplication + pub q_mul: Selector, + /// Fixed-base full-width scalar multiplication + pub q_mul_fixed: Selector, + /// Fixed-base signed short scalar multiplication + pub q_mul_fixed_short: Selector, + /// Witness point + pub q_point: Selector, + /// Witness scalar for variable-base scalar mul + pub q_scalar_var: Selector, + /// Witness full-width scalar for fixed-base scalar mul + pub q_scalar_fixed: Selector, + /// Witness signed short scalar for full-width fixed-base scalar mul + pub q_scalar_fixed_short: Selector, + /// Copy bits of decomposed scalars + pub perm_bits: Permutation, + /// Copy between (x_p, y_p) and (x_a, y_a) + pub perm_sum: Permutation, } -/// Configuration for the ECC chip +/// Enum for the EccConfig #[derive(Clone, Debug)] #[allow(non_snake_case)] -pub struct EccConfig { - // Advice column for scalar decomposition into bits - bits: Column, - // Witness u = (y + z).sqrt(), used in fixed-base scalar multiplication - u: Column, - // Holds a point (x_a, y_a) that is usually the result of an addition - A: (Column, Column), - // Holds a point (x_p, y_p) - P: (Column, Column), - // A pair (lambda1, lambda2) representing gradients - lambda: (Column, Column), - // [A, B, C, D] boolean flags used in complete addition - add_complete_bool: [Column; 4], - // [alpha, beta, gamma, delta] inverses used in complete addition - add_complete_inv: [Column; 4], - // Coefficients of interpolation polynomials for x-coordinates (used in fixed-base scalar multiplication) - lagrange_coeffs: [Column; constants::H], - // Fixed z such that y + z = u^2 some square, and -y + z is a non-square. (Used in fixed-base scalar multiplication) - fixed_z: Column, - - // Incomplete addition - q_add: Selector, - // Complete addition - q_add_complete: Selector, - // Point doubling - q_double: Selector, - // Variable-base scalar multiplication - q_mul: Selector, - // Fixed-base full-width scalar multiplication - q_mul_fixed: Selector, - // Fixed-base signed short scalar multiplication - q_mul_fixed_short: Selector, - // Witness point - q_point: Selector, - // Witness scalar for variable-base scalar mul - q_scalar_var: Selector, - // Witness full-width scalar for fixed-base scalar mul - q_scalar_fixed: Selector, - // Witness signed short scalar for full-width fixed-base scalar mul - q_scalar_fixed_short: Selector, - // Copy bits of decomposed scalars - perm_scalar: Permutation, - // Copy between (x_p, y_p) and (x_a, y_a) - perm_sum: Permutation, +pub enum EccConfigEnum { + Empty, + Config(EccConfig), +} + +impl Config for EccConfigEnum { + fn empty() -> Self { + Self::Empty + } } /// A chip implementing EccInstructions #[derive(Debug)] pub struct EccChip { - _marker: PhantomData, + pub config: EccConfigEnum, + pub loaded: EccLoaded, + pub _marker: PhantomData, +} + +#[derive(Copy, Clone, Debug)] +pub enum OrchardFixedBases { + CommitIvkR(constants::CommitIvkR), + NoteCommitR(constants::NoteCommitR), + NullifierK(constants::NullifierK), + ValueCommitR(constants::ValueCommitR), + ValueCommitV(constants::ValueCommitV), +} + +impl Name for OrchardFixedBases { + fn name(&self) -> &[u8] { + match self { + Self::CommitIvkR(base) => base.name(), + Self::NoteCommitR(base) => base.name(), + Self::NullifierK(base) => base.name(), + Self::ValueCommitR(base) => base.name(), + Self::ValueCommitV(base) => base.name(), + } + } +} + +impl PartialEq for OrchardFixedBases { + fn eq(&self, other: &Self) -> bool { + self.name() == other.name() + } +} + +impl Eq for OrchardFixedBases {} + +impl PartialOrd for OrchardFixedBases { + fn partial_cmp(&self, other: &Self) -> Option { + self.name().partial_cmp(other.name()) + } +} + +impl Ord for OrchardFixedBases { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.name().cmp(other.name()) + } +} + +#[derive(Clone, Debug)] +/// For each Orchard fixed base, we precompute: +/// - coefficients for x-coordinate interpolation polynomials, and +/// - z-values such that y + z = u^2 some square while -y + z is non-square. +pub struct EccLoaded { + lagrange_coeffs: BTreeMap, Vec>>, + lagrange_coeffs_short: BTreeMap, Vec>>, + z: BTreeMap, [u64; constants::NUM_WINDOWS]>, + z_short: BTreeMap, [u64; constants::NUM_WINDOWS_SHORT]>, + u: BTreeMap, Vec>>, + u_short: BTreeMap, Vec>>, +} + +impl Loaded for EccLoaded { + fn empty() -> Self { + Self { + lagrange_coeffs: BTreeMap::default(), + lagrange_coeffs_short: BTreeMap::default(), + z: BTreeMap::default(), + z_short: BTreeMap::default(), + u: BTreeMap::default(), + u_short: BTreeMap::default(), + } + } +} + +impl EccLoaded { + fn lagrange_coeffs(&self, point: OrchardFixedBases) -> Option>> { + self.lagrange_coeffs.get(&point).cloned() + } + + fn lagrange_coeffs_short(&self, point: OrchardFixedBases) -> Option>> { + self.lagrange_coeffs_short.get(&point).cloned() + } + + fn z(&self, point: OrchardFixedBases) -> Option<[u64; constants::NUM_WINDOWS]> { + self.z.get(&point).cloned() + } + + fn z_short(&self, point: OrchardFixedBases) -> Option<[u64; constants::NUM_WINDOWS_SHORT]> { + self.z_short.get(&point).cloned() + } + + fn u(&self, point: OrchardFixedBases) -> Option>> { + self.u.get(&point).cloned() + } + + fn u_short(&self, point: OrchardFixedBases) -> Option>> { + self.u_short.get(&point).cloned() + } +} + +impl FixedPoints for OrchardFixedBases {} + +impl Chip for EccChip { + type Config = EccConfigEnum; + type Loaded = EccLoaded; + + fn config(&self) -> &Self::Config { + &self.config + } + + fn loaded(&self) -> &Self::Loaded { + &self.loaded + } } -#[allow(non_snake_case)] impl EccChip { - fn configure( + pub fn new() -> Self { + Self { + config: >::Config::empty(), + loaded: >::Loaded::empty(), + _marker: PhantomData, + } + } + + pub fn construct( + config: >::Config, + loaded: >::Loaded, + ) -> Self { + Self { + config, + loaded, + _marker: PhantomData, + } + } + + #[allow(non_snake_case)] + pub fn configure( + &mut self, meta: &mut ConstraintSystem, - bits: Column, - u: Column, - A: (Column, Column), - P: (Column, Column), - lambda: (Column, Column), - add_complete_bool: [Column; 4], - add_complete_inv: [Column; 4], - ) -> EccConfig { + _selectors: BTreeMap<&str, Selector>, + columns: BTreeMap<&str, Column>, + perms: BTreeMap<&str, Permutation>, + ) -> >::Config { + let bits = *columns.get("bits").unwrap(); + let u = *columns.get("u").unwrap(); + let x_a = *columns.get("x_a").unwrap(); + let y_a = *columns.get("y_a").unwrap(); + let x_p = *columns.get("x_p").unwrap(); + let y_p = *columns.get("y_p").unwrap(); + let lambda1 = *columns.get("lambda1").unwrap(); + let lambda2 = *columns.get("lambda2").unwrap(); + let bool_a = *columns.get("bool_a").unwrap(); + let bool_b = *columns.get("bool_b").unwrap(); + let bool_c = *columns.get("bool_c").unwrap(); + let bool_d = *columns.get("bool_d").unwrap(); + let inv_alpha = *columns.get("inv_alpha").unwrap(); + let inv_beta = *columns.get("inv_beta").unwrap(); + let inv_gamma = *columns.get("inv_gamma").unwrap(); + let inv_delta = *columns.get("inv_delta").unwrap(); + let q_add = meta.selector(); let q_add_complete = meta.selector(); let q_double = meta.selector(); @@ -133,16 +279,15 @@ impl EccChip { ]; let fixed_z = meta.fixed_column(); - let perm_scalar = Permutation::new(meta, &[bits.into()]); - - let perm_sum = Permutation::new(meta, &[P.0.into(), P.1.into(), A.0.into(), A.1.into()]); + let perm_bits = perms.get("perm_bits").unwrap(); + let perm_sum = perms.get("perm_sum").unwrap(); // Create witness point gate { let q_point = meta.query_selector(q_point, Rotation::cur()); let P = ( - meta.query_advice(P.0, Rotation::cur()), - meta.query_advice(P.1, Rotation::cur()), + meta.query_any(x_p, Rotation::cur()), + meta.query_any(y_p, Rotation::cur()), ); witness_point::create_gate::(meta, q_point, P.0, P.1); } @@ -150,75 +295,75 @@ impl EccChip { // Create witness scalar_var gate { let q_scalar_var = meta.query_selector(q_scalar_var, Rotation::cur()); - let k = meta.query_advice(bits, Rotation::cur()); + let k = meta.query_any(bits, Rotation::cur()); - witness_scalar_var::create_gate::(meta, q_scalar_var, k); + witness_scalar_var::create_gate(meta, q_scalar_var, k); } // Create witness scalar_fixed gate { let q_scalar_fixed = meta.query_selector(q_scalar_fixed, Rotation::cur()); - let k = meta.query_advice(bits, Rotation::cur()); - witness_scalar_fixed::create_gate::(meta, q_scalar_fixed, k); + let k = meta.query_any(bits, Rotation::cur()); + witness_scalar_fixed::create_gate(meta, q_scalar_fixed, k); } // Create witness scalar_fixed_short gate { let q_scalar_fixed_short = meta.query_selector(q_scalar_fixed_short, Rotation::cur()); - let k = meta.query_advice(bits, Rotation::cur()); - witness_scalar_fixed_short::create_gate::(meta, q_scalar_fixed_short, k); + let k = meta.query_any(bits, Rotation::cur()); + witness_scalar_fixed_short::create_gate(meta, q_scalar_fixed_short, k); } // Create point doubling gate { let q_double = meta.query_selector(q_double, Rotation::cur()); - let x_a = meta.query_advice(A.0, Rotation::cur()); - let y_a = meta.query_advice(A.1, Rotation::cur()); - let x_p = meta.query_advice(P.0, Rotation::cur()); - let y_p = meta.query_advice(P.1, Rotation::cur()); + let x_a = meta.query_any(x_a, Rotation::cur()); + let y_a = meta.query_any(y_a, Rotation::cur()); + let x_p = meta.query_any(x_p, Rotation::cur()); + let y_p = meta.query_any(y_p, Rotation::cur()); - double::create_gate::(meta, q_double, x_a, y_a, x_p, y_p); + double::create_gate(meta, q_double, x_a, y_a, x_p, y_p); } // Create point addition gate { let q_add = meta.query_selector(q_add, Rotation::cur()); - let x_p = meta.query_advice(P.0, Rotation::cur()); - let y_p = meta.query_advice(P.1, Rotation::cur()); - let x_q = meta.query_advice(A.0, Rotation::cur()); - let y_q = meta.query_advice(A.1, Rotation::cur()); - let x_a = meta.query_advice(A.0, Rotation::next()); - let y_a = meta.query_advice(A.1, Rotation::next()); - - add::create_gate::(meta, q_add, x_p, y_p, x_q, y_q, x_a, y_a); + let x_p = meta.query_any(x_p, Rotation::cur()); + let y_p = meta.query_any(y_p, Rotation::cur()); + let x_q = meta.query_any(x_a, Rotation::cur()); + let y_q = meta.query_any(y_a, Rotation::cur()); + let x_a = meta.query_any(x_a, Rotation::next()); + let y_a = meta.query_any(y_a, Rotation::next()); + + add::create_gate(meta, q_add, x_p, y_p, x_q, y_q, x_a, y_a); } // Create complete point addition gate { let q_add_complete = meta.query_selector(q_add_complete, Rotation::cur()); - let x_p = meta.query_advice(P.0, Rotation::cur()); - let y_p = meta.query_advice(P.1, Rotation::cur()); - let x_q = meta.query_advice(A.0, Rotation::cur()); - let y_q = meta.query_advice(A.1, Rotation::cur()); - let x_r = meta.query_advice(A.0, Rotation::next()); - let y_r = meta.query_advice(A.1, Rotation::next()); - let lambda = meta.query_advice(lambda.0, Rotation::cur()); - - let a = meta.query_advice(add_complete_bool[0], Rotation::cur()); - let b = meta.query_advice(add_complete_bool[1], Rotation::cur()); - let c = meta.query_advice(add_complete_bool[2], Rotation::cur()); - let d = meta.query_advice(add_complete_bool[3], Rotation::cur()); + let x_p = meta.query_any(x_p, Rotation::cur()); + let y_p = meta.query_any(y_p, Rotation::cur()); + let x_q = meta.query_any(x_a, Rotation::cur()); + let y_q = meta.query_any(y_a, Rotation::cur()); + let x_r = meta.query_any(x_a, Rotation::next()); + let y_r = meta.query_any(y_a, Rotation::next()); + let lambda = meta.query_any(lambda1, Rotation::cur()); + + let a = meta.query_any(bool_a, Rotation::cur()); + let b = meta.query_any(bool_b, Rotation::cur()); + let c = meta.query_any(bool_c, Rotation::cur()); + let d = meta.query_any(bool_d, Rotation::cur()); // \alpha = (x_q - x_p)^{-1} - let alpha = meta.query_advice(add_complete_inv[0], Rotation::cur()); + let alpha = meta.query_any(inv_alpha, Rotation::cur()); // \beta = x_p^{-1} - let beta = meta.query_advice(add_complete_inv[1], Rotation::cur()); + let beta = meta.query_any(inv_beta, Rotation::cur()); // \gamma = x_q^{-1} - let gamma = meta.query_advice(add_complete_inv[2], Rotation::cur()); + let gamma = meta.query_any(inv_gamma, Rotation::cur()); // \delta = (y_p + y_q)^{-1} - let delta = meta.query_advice(add_complete_inv[3], Rotation::cur()); + let delta = meta.query_any(inv_delta, Rotation::cur()); - add_complete::create_gate::( + add_complete::create_gate( meta, q_add_complete, a, @@ -242,38 +387,38 @@ impl EccChip { // Create fixed-base full-width scalar mul gate { let q_mul_fixed = meta.query_selector(q_mul_fixed, Rotation::cur()); - let x_p = meta.query_advice(P.0, Rotation::cur()); - let y_p = meta.query_advice(P.1, Rotation::cur()); - let k = meta.query_advice(bits, Rotation::cur()); - let u = meta.query_advice(u, Rotation::cur()); + let x_p = meta.query_any(x_p, Rotation::cur()); + let y_p = meta.query_any(y_p, Rotation::cur()); + let k = meta.query_any(bits, Rotation::cur()); + let u = meta.query_any(u, Rotation::cur()); let z = meta.query_fixed(fixed_z, Rotation::cur()); - mul_fixed::create_gate::(meta, lagrange_coeffs, q_mul_fixed, x_p, y_p, k, u, z); + mul_fixed::create_gate(meta, lagrange_coeffs, q_mul_fixed, x_p, y_p, k, u, z); } // Create fixed-base short signed scalar mul gate { let q_mul_fixed_short = meta.query_selector(q_mul_fixed_short, Rotation::cur()); - let s = meta.query_advice(bits, Rotation::cur()); - let y_a = meta.query_advice(A.1, Rotation::cur()); - let y_p = meta.query_advice(P.1, Rotation::cur()); + let s = meta.query_any(bits, Rotation::cur()); + let y_a = meta.query_any(y_a, Rotation::cur()); + let y_p = meta.query_any(y_p, Rotation::cur()); - mul_fixed_short::create_gate::(meta, q_mul_fixed_short, s, y_a, y_p); + mul_fixed_short::create_gate(meta, q_mul_fixed_short, s, y_a, y_p); } // Create variable-base scalar mul gate { let q_mul = meta.query_selector(q_mul, Rotation::cur()); - let x_a_cur = meta.query_advice(A.0, Rotation::cur()); - let x_a_next = meta.query_advice(A.0, Rotation::next()); - let x_p_cur = meta.query_advice(P.0, Rotation::cur()); - let x_p_next = meta.query_advice(P.0, Rotation::next()); - let lambda1_cur = meta.query_advice(lambda.0, Rotation::cur()); - let lambda1_next = meta.query_advice(lambda.0, Rotation::next()); - let lambda2_cur = meta.query_advice(lambda.1, Rotation::cur()); - let lambda2_next = meta.query_advice(lambda.1, Rotation::next()); - - mul::create_gate::( + let x_a_cur = meta.query_any(x_a, Rotation::cur()); + let x_a_next = meta.query_any(x_a, Rotation::next()); + let x_p_cur = meta.query_any(x_p, Rotation::cur()); + let x_p_next = meta.query_any(x_p, Rotation::next()); + let lambda1_cur = meta.query_any(lambda1, Rotation::cur()); + let lambda1_next = meta.query_any(lambda1, Rotation::next()); + let lambda2_cur = meta.query_any(lambda2, Rotation::cur()); + let lambda2_next = meta.query_any(lambda2, Rotation::next()); + + mul::create_gate( meta, q_mul, x_a_cur, @@ -287,14 +432,33 @@ impl EccChip { ) } - EccConfig { - bits, - u, - A, - P, - lambda, - add_complete_bool, - add_complete_inv, + let config = EccConfigEnum::Config(EccConfig { + bits: Column::::try_from(bits).unwrap(), + u: Column::::try_from(u).unwrap(), + A: ( + Column::::try_from(x_a).unwrap(), + Column::::try_from(y_a).unwrap(), + ), + P: ( + Column::::try_from(x_p).unwrap(), + Column::::try_from(y_p).unwrap(), + ), + lambda: ( + Column::::try_from(lambda1).unwrap(), + Column::::try_from(lambda2).unwrap(), + ), + add_complete_bool: [ + Column::::try_from(bool_a).unwrap(), + Column::::try_from(bool_b).unwrap(), + Column::::try_from(bool_c).unwrap(), + Column::::try_from(bool_d).unwrap(), + ], + add_complete_inv: [ + Column::::try_from(inv_alpha).unwrap(), + Column::::try_from(inv_beta).unwrap(), + Column::::try_from(inv_gamma).unwrap(), + Column::::try_from(inv_delta).unwrap(), + ], lagrange_coeffs, fixed_z, q_add, @@ -307,158 +471,64 @@ impl EccChip { q_scalar_var, q_scalar_fixed, q_scalar_fixed_short, - perm_scalar, - perm_sum, - } + perm_bits: perm_bits.clone(), + perm_sum: perm_sum.clone(), + }); + self.config = config.clone(); + config } -} -#[derive(Copy, Clone, Debug)] -pub enum EccFixedPoints { - CommitIvkR(constants::CommitIvkR), - NoteCommitR(constants::NoteCommitR), - NullifierK(constants::NullifierK), - ValueCommitR(constants::ValueCommitR), - ValueCommitV(constants::ValueCommitV), -} - -impl OrchardFixedBases for EccFixedPoints { - fn name(&self) -> &[u8] { - match self { - Self::CommitIvkR(base) => base.name(), - Self::NoteCommitR(base) => base.name(), - Self::NullifierK(base) => base.name(), - Self::ValueCommitR(base) => base.name(), - Self::ValueCommitV(base) => base.name(), - } - } -} - -impl PartialEq for EccFixedPoints { - fn eq(&self, other: &Self) -> bool { - self.name() == other.name() - } -} - -impl Eq for EccFixedPoints {} - -impl PartialOrd for EccFixedPoints { - fn partial_cmp(&self, other: &Self) -> Option { - self.name().partial_cmp(other.name()) - } -} - -impl Ord for EccFixedPoints { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.name().cmp(other.name()) - } -} - -#[derive(Clone, Debug)] -/// For each Orchard fixed base, we precompute: -/// - coefficients for x-coordinate interpolation polynomials, and -/// - z-values such that y + z = u^2 some square while -y + z is non-square. -pub struct EccLoaded { - lagrange_coeffs: BTreeMap, Vec>>, - lagrange_coeffs_short: BTreeMap, Vec>>, - z: BTreeMap, [u64; constants::NUM_WINDOWS]>, - z_short: BTreeMap, [u64; constants::NUM_WINDOWS_SHORT]>, - u: BTreeMap, Vec>>, - u_short: BTreeMap, Vec>>, -} - -impl EccLoaded { - fn lagrange_coeffs(&self, point: EccFixedPoints) -> Option>> { - self.lagrange_coeffs.get(&point).cloned() - } - - fn lagrange_coeffs_short(&self, point: EccFixedPoints) -> Option>> { - self.lagrange_coeffs_short.get(&point).cloned() - } - - fn z(&self, point: EccFixedPoints) -> Option<[u64; constants::NUM_WINDOWS]> { - self.z.get(&point).cloned() - } - - fn z_short(&self, point: EccFixedPoints) -> Option<[u64; constants::NUM_WINDOWS_SHORT]> { - self.z_short.get(&point).cloned() - } - - fn u(&self, point: EccFixedPoints) -> Option>> { - self.u.get(&point).cloned() - } - - fn u_short(&self, point: EccFixedPoints) -> Option>> { - self.u_short.get(&point).cloned() - } -} - -impl FixedPoints for EccFixedPoints {} - -impl Chip for EccChip { - type Config = EccConfig; - type Field = C::Base; - type Loaded = EccLoaded; - - fn load(_layouter: &mut impl Layouter) -> Result { - let mut lagrange_coeffs = BTreeMap::, Vec>>::new(); - let mut lagrange_coeffs_short = BTreeMap::, Vec>>::new(); - let mut z = BTreeMap::, [u64; constants::NUM_WINDOWS]>::new(); - let mut z_short = BTreeMap::, [u64; constants::NUM_WINDOWS_SHORT]>::new(); - let mut u = BTreeMap::, Vec>>::new(); - let mut u_short = BTreeMap::, Vec>>::new(); + pub fn load( + &mut self, + _layouter: &mut impl Layouter, + ) -> Result<>::Loaded, Error> { + let mut lagrange_coeffs = BTreeMap::, Vec>>::new(); + let mut lagrange_coeffs_short = BTreeMap::, Vec>>::new(); + let mut z = BTreeMap::, [u64; constants::NUM_WINDOWS]>::new(); + let mut z_short = + BTreeMap::, [u64; constants::NUM_WINDOWS_SHORT]>::new(); + let mut u = BTreeMap::, Vec>>::new(); + let mut u_short = BTreeMap::, Vec>>::new(); let bases: [( - EccFixedPoints, + OrchardFixedBases, [u64; constants::NUM_WINDOWS], - [u64; constants::NUM_WINDOWS_SHORT], [[[u8; 32]; constants::H]; constants::NUM_WINDOWS], - [[[u8; 32]; constants::H]; constants::NUM_WINDOWS_SHORT], ); 5] = [ ( - EccFixedPoints::CommitIvkR(constants::commit_ivk_r::generator()), + OrchardFixedBases::CommitIvkR(constants::commit_ivk_r::generator()), constants::commit_ivk_r::Z, - constants::commit_ivk_r::Z_SHORT, constants::commit_ivk_r::U, - constants::commit_ivk_r::U_SHORT, ), ( - EccFixedPoints::NoteCommitR(constants::note_commit_r::generator()), + OrchardFixedBases::NoteCommitR(constants::note_commit_r::generator()), constants::note_commit_r::Z, - constants::note_commit_r::Z_SHORT, constants::note_commit_r::U, - constants::note_commit_r::U_SHORT, ), ( - EccFixedPoints::NullifierK(constants::nullifier_k::generator()), + OrchardFixedBases::NullifierK(constants::nullifier_k::generator()), constants::nullifier_k::Z, - constants::nullifier_k::Z_SHORT, constants::nullifier_k::U, - constants::nullifier_k::U_SHORT, ), ( - EccFixedPoints::ValueCommitR(constants::value_commit_r::generator()), + OrchardFixedBases::ValueCommitR(constants::value_commit_r::generator()), constants::value_commit_r::Z, - constants::value_commit_r::Z_SHORT, constants::value_commit_r::U, - constants::value_commit_r::U_SHORT, ), ( - EccFixedPoints::ValueCommitV(constants::value_commit_v::generator()), + OrchardFixedBases::ValueCommitV(constants::value_commit_v::generator()), constants::value_commit_v::Z, - constants::value_commit_v::Z_SHORT, constants::value_commit_v::U, - constants::value_commit_v::U_SHORT, ), ]; for base in bases.iter() { let inner = match base.0 { - EccFixedPoints::CommitIvkR(inner) => inner.0, - EccFixedPoints::NoteCommitR(inner) => inner.0, - EccFixedPoints::NullifierK(inner) => inner.0, - EccFixedPoints::ValueCommitR(inner) => inner.0, - EccFixedPoints::ValueCommitV(inner) => inner.0, + OrchardFixedBases::CommitIvkR(inner) => inner.0, + OrchardFixedBases::NoteCommitR(inner) => inner.0, + OrchardFixedBases::NullifierK(inner) => inner.0, + OrchardFixedBases::ValueCommitR(inner) => inner.0, + OrchardFixedBases::ValueCommitV(inner) => inner.0, }; lagrange_coeffs.insert( base.0, @@ -468,19 +538,10 @@ impl Chip for EccChip { .map(|window| window.to_vec()) .collect(), ); - lagrange_coeffs_short.insert( - base.0, - inner - .compute_lagrange_coeffs(constants::NUM_WINDOWS_SHORT) - .iter() - .map(|window| window.to_vec()) - .collect(), - ); z.insert(base.0, base.1); - z_short.insert(base.0, base.2); u.insert( base.0, - base.3 + base.2 .iter() .map(|window_us| { window_us @@ -490,9 +551,27 @@ impl Chip for EccChip { }) .collect::>(), ); + } + + // We use fixed-base scalar multiplication with signed short exponent + // for `ValueCommitV`. + { + let inner = constants::value_commit_v::generator(); + let value_commit_v = OrchardFixedBases::ValueCommitV(inner); + + lagrange_coeffs_short.insert( + value_commit_v, + inner + .0 + .compute_lagrange_coeffs(constants::NUM_WINDOWS_SHORT) + .iter() + .map(|window| window.to_vec()) + .collect(), + ); + z_short.insert(value_commit_v, constants::value_commit_v::Z_SHORT); u_short.insert( - base.0, - base.4 + value_commit_v, + constants::value_commit_v::U_SHORT .iter() .map(|window_us| { window_us @@ -504,14 +583,16 @@ impl Chip for EccChip { ); } - Ok(EccLoaded { + let loaded = EccLoaded { lagrange_coeffs, lagrange_coeffs_short, z, z_short, u, u_short, - }) + }; + self.loaded = loaded.clone(); + Ok(loaded) } } @@ -550,7 +631,7 @@ pub struct EccScalarFixedShort { /// - z-values such that y + z = u^2 some square while -y + z is non-square. #[derive(Clone, Debug)] pub struct EccFixedPoint { - fixed_point: EccFixedPoints, + fixed_point: OrchardFixedBases, lagrange_coeffs: Option>>, lagrange_coeffs_short: Option>>, z: Option<[u64; constants::NUM_WINDOWS]>, @@ -566,13 +647,17 @@ impl EccInstructions for EccChip { type Point = EccPoint; type X = CellValue; type FixedPoint = EccFixedPoint; - type FixedPoints = EccFixedPoints; + type FixedPoints = OrchardFixedBases; fn witness_scalar_var( - layouter: &mut impl Layouter, + &self, + layouter: &mut impl Layouter, value: Option, ) -> Result { - let config = layouter.config().clone(); + let config = match self.config() { + EccConfigEnum::Config(config) => config, + _ => unreachable!(), + }; let scalar = layouter.assign_region( || "witness scalar for variable-base mul", @@ -583,10 +668,14 @@ impl EccInstructions for EccChip { } fn witness_scalar_fixed( - layouter: &mut impl Layouter, + &self, + layouter: &mut impl Layouter, value: Option, ) -> Result { - let config = layouter.config().clone(); + let config = match self.config() { + EccConfigEnum::Config(config) => config, + _ => unreachable!(), + }; let scalar = layouter.assign_region( || "witness scalar for fixed-base mul", @@ -605,10 +694,14 @@ impl EccInstructions for EccChip { } fn witness_scalar_fixed_short( - layouter: &mut impl Layouter, + &self, + layouter: &mut impl Layouter, value: Option, ) -> Result { - let config = layouter.config().clone(); + let config = match self.config() { + EccConfigEnum::Config(config) => config, + _ => unreachable!(), + }; let scalar = layouter.assign_region( || "witness scalar for fixed-base mul", @@ -621,10 +714,14 @@ impl EccInstructions for EccChip { } fn witness_point( - layouter: &mut impl Layouter, + &self, + layouter: &mut impl Layouter, value: Option, ) -> Result { - let config = layouter.config().clone(); + let config = match self.config() { + EccConfigEnum::Config(config) => config, + _ => unreachable!(), + }; let point = layouter.assign_region( || "witness point", @@ -638,11 +735,8 @@ impl EccInstructions for EccChip { &point.x } - fn get_fixed( - layouter: &mut impl Layouter, - fixed_point: Self::FixedPoints, - ) -> Result { - let loaded = layouter.loaded(); + fn get_fixed(&self, fixed_point: Self::FixedPoints) -> Result { + let loaded = self.loaded(); let lagrange_coeffs = loaded.lagrange_coeffs(fixed_point); let lagrange_coeffs_short = loaded.lagrange_coeffs_short(fixed_point); @@ -663,87 +757,116 @@ impl EccInstructions for EccChip { } fn add( - layouter: &mut impl Layouter, + &self, + layouter: &mut impl Layouter, a: &Self::Point, b: &Self::Point, ) -> Result { - let config = layouter.config().clone(); + let config = match self.config() { + EccConfigEnum::Config(config) => config, + _ => unreachable!(), + }; let point = layouter.assign_region( || "point addition", - |mut region| add::assign_region(a, b, 0, &mut region, config.clone()), + |mut region| add::assign_region::(a, b, 0, &mut region, config.clone()), )?; Ok(point) } fn add_complete( - layouter: &mut impl Layouter, + &self, + layouter: &mut impl Layouter, a: &Self::Point, b: &Self::Point, ) -> Result { - let config = layouter.config().clone(); + let config = match self.config() { + EccConfigEnum::Config(config) => config, + _ => unreachable!(), + }; let point = layouter.assign_region( || "point addition", - |mut region| add_complete::assign_region(a, b, 0, &mut region, config.clone()), + |mut region| add_complete::assign_region::(a, b, 0, &mut region, config.clone()), )?; Ok(point) } - fn double(layouter: &mut impl Layouter, a: &Self::Point) -> Result { - let config = layouter.config().clone(); + fn double( + &self, + layouter: &mut impl Layouter, + a: &Self::Point, + ) -> Result { + let config = match self.config() { + EccConfigEnum::Config(config) => config, + _ => unreachable!(), + }; let point = layouter.assign_region( || "point doubling", - |mut region| double::assign_region(a, 0, &mut region, config.clone()), + |mut region| double::assign_region::(a, 0, &mut region, config.clone()), )?; Ok(point) } fn mul( - layouter: &mut impl Layouter, + &self, + layouter: &mut impl Layouter, scalar: &Self::ScalarVar, base: &Self::Point, ) -> Result { - let config = layouter.config().clone(); + let config = match self.config() { + EccConfigEnum::Config(config) => config, + _ => unreachable!(), + }; let point = layouter.assign_region( || "variable-base mul", - |mut region| mul::assign_region(scalar, base, 0, &mut region, config.clone()), + |mut region| mul::assign_region::(scalar, base, 0, &mut region, config.clone()), )?; Ok(point) } fn mul_fixed( - layouter: &mut impl Layouter, + &self, + layouter: &mut impl Layouter, scalar: &Self::ScalarFixed, base: &Self::FixedPoint, ) -> Result { - let config = layouter.config().clone(); + let config = match self.config() { + EccConfigEnum::Config(config) => config, + _ => unreachable!(), + }; let point = layouter.assign_region( || format!("Multiply {:?}", base.fixed_point), - |mut region| mul_fixed::assign_region(scalar, base, 0, &mut region, config.clone()), + |mut region| { + mul_fixed::assign_region::(scalar, base, 0, &mut region, config.clone()) + }, )?; Ok(point) } fn mul_fixed_short( - layouter: &mut impl Layouter, + &self, + layouter: &mut impl Layouter, scalar: &Self::ScalarFixedShort, base: &Self::FixedPoint, ) -> Result { - let config = layouter.config().clone(); + let config = match self.config() { + EccConfigEnum::Config(config) => config, + _ => unreachable!(), + }; let point = layouter.assign_region( || format!("Multiply {:?}", base.fixed_point), |mut region| { - mul_fixed_short::assign_region(scalar, base, 0, &mut region, config.clone()) + mul_fixed_short::assign_region::(scalar, base, 0, &mut region, config.clone()) }, )?; @@ -757,14 +880,15 @@ mod tests { use group::{Curve, Group}; use halo2::{ arithmetic::{CurveAffine, FieldExt}, - circuit::{layouter, Chip}, + circuit::{layouter::SingleChipLayouter, Chip, Loaded}, dev::MockProver, pasta::pallas, - plonk::{Assignment, Circuit, ConstraintSystem, Error}, + plonk::{Assignment, Circuit, ConstraintSystem, Error, Permutation}, }; + use std::collections::BTreeMap; use super::super::EccInstructions; - use super::{EccChip, EccConfig, EccFixedPoints}; + use super::{EccChip, EccConfigEnum, OrchardFixedBases}; struct MyCircuit { _marker: std::marker::PhantomData, @@ -772,54 +896,66 @@ mod tests { #[allow(non_snake_case)] impl Circuit for MyCircuit { - type Config = EccConfig; + type Config = EccConfigEnum; - fn configure(meta: &mut ConstraintSystem) -> EccConfig { + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + let mut columns = BTreeMap::new(); let bits = meta.advice_column(); - let u = meta.advice_column(); - let A = (meta.advice_column(), meta.advice_column()); - let P = (meta.advice_column(), meta.advice_column()); - let lambda = (meta.advice_column(), meta.advice_column()); - let add_complete_inv = [ - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - ]; - let add_complete_bool = [ - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - ]; - - EccChip::::configure( - meta, - bits, - u, - A, - P, - lambda, - add_complete_inv, - add_complete_bool, - ) + let x_p = meta.advice_column(); + let y_p = meta.advice_column(); + let x_a = meta.advice_column(); + let y_a = meta.advice_column(); + + columns.insert("bits", bits.into()); + columns.insert("u", meta.advice_column().into()); + + columns.insert("x_a", x_a.into()); + columns.insert("y_a", y_a.into()); + + columns.insert("x_p", x_p.into()); + columns.insert("y_p", y_p.into()); + + columns.insert("lambda1", meta.advice_column().into()); + columns.insert("lambda2", meta.advice_column().into()); + + columns.insert("inv_alpha", meta.advice_column().into()); + columns.insert("inv_beta", meta.advice_column().into()); + columns.insert("inv_gamma", meta.advice_column().into()); + columns.insert("inv_delta", meta.advice_column().into()); + + columns.insert("bool_a", meta.advice_column().into()); + columns.insert("bool_b", meta.advice_column().into()); + columns.insert("bool_c", meta.advice_column().into()); + columns.insert("bool_d", meta.advice_column().into()); + + let mut perms = BTreeMap::new(); + perms.insert("perm_bits", Permutation::new(meta, &[bits.into()])); + perms.insert( + "perm_sum", + Permutation::new(meta, &[x_p.into(), y_p.into(), x_a.into(), y_a.into()]), + ); + + let mut chip = EccChip::::new(); + chip.configure(meta, BTreeMap::new(), columns, perms) } fn synthesize( &self, cs: &mut impl Assignment, - config: EccConfig, + config: Self::Config, ) -> Result<(), Error> { - let mut layouter = layouter::SingleChip::new(cs, config.clone())?; - EccChip::::load(&mut layouter)?; + let mut chip = + EccChip::construct(config, as Chip>::Loaded::empty()); + let mut layouter = SingleChipLayouter::new(cs)?; + chip.load(&mut layouter)?; // Generate a random point let point_val = C::CurveExt::random(rand::rngs::OsRng).to_affine(); // P - let point = EccChip::::witness_point(&mut layouter, Some(point_val))?; + let point = chip.witness_point(&mut layouter, Some(point_val))?; // Check doubled point [2]P let real_doubled = point_val * C::Scalar::from_u64(2); // [2]P - let doubled = EccChip::::double(&mut layouter, &point)?; + let doubled = chip.double(&mut layouter, &point)?; if let (Some(x), Some(y)) = (doubled.x.value, doubled.y.value) { assert_eq!(real_doubled.to_affine(), C::from_xy(x, y).unwrap()); } @@ -828,7 +964,7 @@ mod tests { // Check incomplete addition point [3]P { - let added = EccChip::::add(&mut layouter, &point, &doubled)?; + let added = chip.add(&mut layouter, &point, &doubled)?; if let (Some(x), Some(y)) = (added.x.value, added.y.value) { assert_eq!(real_added.to_affine(), C::from_xy(x, y).unwrap()); } @@ -836,7 +972,7 @@ mod tests { // Check complete addition point [3]P { - let added_complete = EccChip::::add_complete(&mut layouter, &point, &doubled)?; + let added_complete = chip.add_complete(&mut layouter, &point, &doubled)?; if let (Some(x), Some(y)) = (added_complete.x.value, added_complete.y.value) { if C::from_xy(x, y).is_some().into() { assert_eq!(real_added.to_affine(), C::from_xy(x, y).unwrap()); @@ -851,14 +987,9 @@ mod tests { let base = nullifier_k.0.value(); let real_mul_fixed = base * scalar_fixed; - let scalar_fixed = - EccChip::::witness_scalar_fixed(&mut layouter, Some(scalar_fixed))?; - let nullifier_k = EccChip::::get_fixed( - &mut layouter, - EccFixedPoints::NullifierK(nullifier_k), - )?; - let mul_fixed = - EccChip::::mul_fixed(&mut layouter, &scalar_fixed, &nullifier_k)?; + let scalar_fixed = chip.witness_scalar_fixed(&mut layouter, Some(scalar_fixed))?; + let nullifier_k = chip.get_fixed(OrchardFixedBases::NullifierK(nullifier_k))?; + let mul_fixed = chip.mul_fixed(&mut layouter, &scalar_fixed, &nullifier_k)?; if let (Some(x), Some(y)) = (mul_fixed.x.value, mul_fixed.y.value) { assert_eq!(real_mul_fixed.to_affine(), C::from_xy(x, y).unwrap()); } @@ -870,19 +1001,12 @@ mod tests { let value_commit_v = constants::value_commit_v::generator(); let real_mul_fixed_short = value_commit_v.0.value() * scalar_fixed_short; - let scalar_fixed_short = EccChip::::witness_scalar_fixed_short( - &mut layouter, - Some(scalar_fixed_short), - )?; - let value_commit_v = EccChip::::get_fixed( - &mut layouter, - EccFixedPoints::ValueCommitV(value_commit_v), - )?; - let mul_fixed_short = EccChip::::mul_fixed_short( - &mut layouter, - &scalar_fixed_short, - &value_commit_v, - )?; + let scalar_fixed_short = + chip.witness_scalar_fixed_short(&mut layouter, Some(scalar_fixed_short))?; + let value_commit_v = + chip.get_fixed(OrchardFixedBases::ValueCommitV(value_commit_v))?; + let mul_fixed_short = + chip.mul_fixed_short(&mut layouter, &scalar_fixed_short, &value_commit_v)?; if let (Some(x), Some(y)) = (mul_fixed_short.x.value, mul_fixed_short.y.value) { assert_eq!(real_mul_fixed_short.to_affine(), C::from_xy(x, y).unwrap()); } @@ -896,7 +1020,7 @@ mod tests { let scalar_val = C::Scalar::rand(); let real_mul = point_val * scalar_val; - let scalar_var = EccChip::::witness_scalar_var(&mut layouter, Some(scalar_val))?; + let scalar_var = chip.witness_scalar_var(&mut layouter, Some(scalar_val))?; let computed_scalar: Option> = scalar_var.k_bits.iter().map(|bit| bit.value).collect(); @@ -910,7 +1034,7 @@ mod tests { assert_eq!(scalar_val + C::Scalar::from_u128(t_q), computed_scalar); } - let mul = EccChip::::mul(&mut layouter, &scalar_var, &point)?; + let mul = chip.mul(&mut layouter, &scalar_var, &point)?; if let (Some(x), Some(y)) = (mul.x.value, mul.y.value) { assert_eq!(real_mul.to_affine(), C::from_xy(x, y).unwrap()); } diff --git a/src/circuit/gadget/ecc/chip/add.rs b/src/circuit/gadget/ecc/chip/add.rs index 1a2da899f..42b5377ba 100644 --- a/src/circuit/gadget/ecc/chip/add.rs +++ b/src/circuit/gadget/ecc/chip/add.rs @@ -1,21 +1,20 @@ -use super::super::EccInstructions; -use super::{util, CellValue, EccChip, EccPoint}; +use super::{util, EccConfig, EccPoint}; use group::Curve; use halo2::{ - arithmetic::CurveAffine, - circuit::{Chip, Region}, + arithmetic::{CurveAffine, FieldExt}, + circuit::{CellValue, Region}, plonk::{ConstraintSystem, Error, Expression}, }; -pub(super) fn create_gate( - meta: &mut ConstraintSystem, - q_add: Expression, - x_p: Expression, - y_p: Expression, - x_q: Expression, - y_q: Expression, - x_a: Expression, - y_a: Expression, +pub(super) fn create_gate( + meta: &mut ConstraintSystem, + q_add: Expression, + x_p: Expression, + y_p: Expression, + x_q: Expression, + y_q: Expression, + x_a: Expression, + y_a: Expression, ) { // (x_a + x_q + x_p)⋅(x_p − x_q)^2 − (y_p − y_q)^2 = 0 meta.create_gate("point addition expr1", |_| { @@ -36,11 +35,11 @@ pub(super) fn create_gate( } pub(super) fn assign_region( - a: & as EccInstructions>::Point, - b: & as EccInstructions>::Point, + a: &EccPoint, + b: &EccPoint, offset: usize, - region: &mut Region<'_, EccChip>, - config: as Chip>::Config, + region: &mut Region<'_, C::Base>, + config: EccConfig, ) -> Result, Error> { // Enable `q_add` selector config.q_add.enable(region, offset)?; @@ -64,11 +63,11 @@ pub(super) fn assign_region( .map(|(((x_p, y_p), x_q), y_q)| { let p = C::from_xy(x_p, y_p).unwrap(); let q = C::from_xy(x_q, y_q).unwrap(); - (p + q).to_affine().get_xy().unwrap() + (p + q).to_affine().coordinates().unwrap() }); // Assign the sum to `x_a`, `y_a` columns in the next row - let x_a_val = sum.map(|sum| sum.0); + let x_a_val = sum.map(|sum| *sum.x()); let x_a_var = region.assign_advice( || "x_a", config.A.0, @@ -76,7 +75,7 @@ pub(super) fn assign_region( || x_a_val.ok_or(Error::SynthesisError), )?; - let y_a_val = sum.map(|sum| sum.1); + let y_a_val = sum.map(|sum| *sum.y()); let y_a_var = region.assign_advice( || "y_a", config.A.1, @@ -85,7 +84,7 @@ pub(super) fn assign_region( )?; Ok(EccPoint { - x: CellValue::new(x_a_var, x_a_val), - y: CellValue::new(y_a_var, y_a_val), + x: CellValue::::new(x_a_var, x_a_val), + y: CellValue::::new(y_a_var, y_a_val), }) } diff --git a/src/circuit/gadget/ecc/chip/add_complete.rs b/src/circuit/gadget/ecc/chip/add_complete.rs index 3119165ad..ee4dafb03 100644 --- a/src/circuit/gadget/ecc/chip/add_complete.rs +++ b/src/circuit/gadget/ecc/chip/add_complete.rs @@ -1,45 +1,44 @@ -use super::super::EccInstructions; -use super::{util, CellValue, EccChip, EccPoint}; +use super::{util, EccConfig, EccPoint}; use group::Curve; use halo2::{ arithmetic::{CurveAffine, CurveExt, Field, FieldExt}, - circuit::{Chip, Region}, + circuit::{CellValue, Region}, plonk::{ConstraintSystem, Error, Expression}, }; -pub(crate) fn create_gate( - meta: &mut ConstraintSystem, - q_add_complete: Expression, - a: Expression, - b: Expression, - c: Expression, - d: Expression, - alpha: Expression, - beta: Expression, - gamma: Expression, - delta: Expression, - lambda: Expression, - x_p: Expression, - y_p: Expression, - x_q: Expression, - y_q: Expression, - x_r: Expression, - y_r: Expression, +pub(crate) fn create_gate( + meta: &mut ConstraintSystem, + q_add_complete: Expression, + a: Expression, + b: Expression, + c: Expression, + d: Expression, + alpha: Expression, + beta: Expression, + gamma: Expression, + delta: Expression, + lambda: Expression, + x_p: Expression, + y_p: Expression, + x_q: Expression, + y_q: Expression, + x_r: Expression, + y_r: Expression, ) { // Boolean checks on A, B, C, D { meta.create_gate("Check A is boolean", |_| { - q_add_complete.clone() * a.clone() * (Expression::Constant(C::Base::one()) - a.clone()) + q_add_complete.clone() * a.clone() * (Expression::Constant(F::one()) - a.clone()) }); meta.create_gate("Check B is boolean", |_| { - q_add_complete.clone() * b.clone() * (Expression::Constant(C::Base::one()) - b.clone()) + q_add_complete.clone() * b.clone() * (Expression::Constant(F::one()) - b.clone()) }); meta.create_gate("Check C is boolean", |_| { - q_add_complete.clone() * c.clone() * (Expression::Constant(C::Base::one()) - c.clone()) + q_add_complete.clone() * c.clone() * (Expression::Constant(F::one()) - c.clone()) }); meta.create_gate("Check D is boolean", |_| { - q_add_complete.clone() * d.clone() * (Expression::Constant(C::Base::one()) - d.clone()) + q_add_complete.clone() * d.clone() * (Expression::Constant(F::one()) - d.clone()) }); } @@ -48,14 +47,14 @@ pub(crate) fn create_gate( // x_q = x_p ⟹ A meta.create_gate("x_q = x_p ⟹ A", |_| { let lhs = (x_q.clone() - x_p.clone()) * alpha.clone(); - let rhs = Expression::Constant(C::Base::one()) - a.clone(); + let rhs = Expression::Constant(F::one()) - a.clone(); q_add_complete.clone() * (lhs - rhs) }); // x_p = 0 ⟹ B meta.create_gate("x_p = 0 ⟹ B", |_| { let lhs = x_p.clone() * beta.clone(); - let rhs = Expression::Constant(C::Base::one()) - b.clone(); + let rhs = Expression::Constant(F::one()) - b.clone(); q_add_complete.clone() * (lhs - rhs) }); @@ -67,7 +66,7 @@ pub(crate) fn create_gate( // x_q = 0 ⟹ C meta.create_gate("x_q = 0 ⟹ C", |_| { let lhs = x_q.clone() * gamma.clone(); - let rhs = Expression::Constant(C::Base::one()) - c.clone(); + let rhs = Expression::Constant(F::one()) - c.clone(); q_add_complete.clone() * (lhs - rhs) }); @@ -79,7 +78,7 @@ pub(crate) fn create_gate( // y_q = -y_p ⟹ D meta.create_gate("y_q = y_p ⟹ D", |_| { let lhs = (y_q.clone() + y_p.clone()) * delta.clone(); - let rhs = Expression::Constant(C::Base::one()) - d.clone(); + let rhs = Expression::Constant(F::one()) - d.clone(); q_add_complete.clone() * (lhs - rhs) }); } @@ -95,17 +94,16 @@ pub(crate) fn create_gate( // A ∧ y_p ≠ 0 ⟹ λ = (3 * x_p^2) / 2 * y_p meta.create_gate("x equal, y nonzero", |_| { - let three_x_p_sq = - Expression::Constant(C::Base::from_u64(3)) * x_p.clone() * x_p.clone(); - let two_y_p = Expression::Constant(C::Base::from_u64(2)) * y_p.clone(); + let three_x_p_sq = Expression::Constant(F::from_u64(3)) * x_p.clone() * x_p.clone(); + let two_y_p = Expression::Constant(F::from_u64(2)) * y_p.clone(); let gradient = two_y_p * lambda.clone() - three_x_p_sq; q_add_complete.clone() * a.clone() * gradient }); // (¬B ∧ ¬C ⟹ x_r = λ^2 − x_p − x_q) ∧ (B ⟹ x_r = x_q) meta.create_gate("x_r check", |_| { - let not_b = Expression::Constant(C::Base::one()) - b.clone(); - let not_c = Expression::Constant(C::Base::one()) - c.clone(); + let not_b = Expression::Constant(F::one()) - b.clone(); + let not_c = Expression::Constant(F::one()) - c.clone(); let x_r_lambda = lambda.clone() * lambda.clone() - x_p.clone() - x_q.clone() - x_r.clone(); let x_r_x_q = b.clone() * (x_r.clone() - x_q.clone()); @@ -114,8 +112,8 @@ pub(crate) fn create_gate( // ¬B ∧ ¬C ⟹ y_r = λ⋅(x_p − x_r) − y_p) ∧ (B ⟹ y_r = y_q) meta.create_gate("y_r check", |_| { - let not_b = Expression::Constant(C::Base::one()) - b.clone(); - let not_c = Expression::Constant(C::Base::one()) - c.clone(); + let not_b = Expression::Constant(F::one()) - b.clone(); + let not_c = Expression::Constant(F::one()) - c.clone(); let y_r_lambda = lambda.clone() * (x_p.clone() - x_r.clone()) - y_p.clone() - y_r.clone(); let y_r_y_q = b.clone() * (y_r.clone() - y_q.clone()); @@ -145,11 +143,11 @@ pub(crate) fn create_gate( } pub(super) fn assign_region( - a: & as EccInstructions>::Point, - b: & as EccInstructions>::Point, + a: &EccPoint, + b: &EccPoint, offset: usize, - region: &mut Region<'_, EccChip>, - config: as Chip>::Config, + region: &mut Region<'_, C::Base>, + config: EccConfig, ) -> Result, Error> { // Enable `q_add_complete` selector config.q_add_complete.enable(region, offset)?; @@ -248,18 +246,18 @@ pub(super) fn assign_region( r.map_or(Err(Error::SynthesisError), |r| { if r.is_on_curve().into() { // Assign `x_r` - let x_r_val = r.to_affine().get_xy().unwrap().0; + let x_r_val = *r.to_affine().coordinates().unwrap().x(); let x_r_cell = region.assign_advice(|| "set x_r", config.A.0, offset + 1, || Ok(x_r_val))?; // Assign `y_r` - let y_r_val = r.to_affine().get_xy().unwrap().1; + let y_r_val = *r.to_affine().coordinates().unwrap().y(); let y_r_cell = region.assign_advice(|| "set y_r", config.A.1, offset + 1, || Ok(y_r_val))?; Ok(EccPoint { - x: CellValue::new(x_r_cell, Some(x_r_val)), - y: CellValue::new(y_r_cell, Some(y_r_val)), + x: CellValue::::new(x_r_cell, Some(x_r_val)), + y: CellValue::::new(y_r_cell, Some(y_r_val)), }) } else { Err(Error::SynthesisError) diff --git a/src/circuit/gadget/ecc/chip/double.rs b/src/circuit/gadget/ecc/chip/double.rs index b0208bd75..7888b7ef5 100644 --- a/src/circuit/gadget/ecc/chip/double.rs +++ b/src/circuit/gadget/ecc/chip/double.rs @@ -1,46 +1,45 @@ -use super::super::EccInstructions; -use super::{util, CellValue, EccChip, EccPoint}; +use super::{util, EccConfig, EccPoint}; use group::Curve; use halo2::{ arithmetic::{CurveAffine, FieldExt}, - circuit::{Chip, Region}, + circuit::{CellValue, Region}, plonk::{ConstraintSystem, Error, Expression}, }; -pub(super) fn create_gate( - meta: &mut ConstraintSystem, - q_double: Expression, - x_a: Expression, - y_a: Expression, - x_p: Expression, - y_p: Expression, +pub(super) fn create_gate( + meta: &mut ConstraintSystem, + q_double: Expression, + x_a: Expression, + y_a: Expression, + x_p: Expression, + y_p: Expression, ) { // 4⋅(y_p)^2⋅(x_a + 2⋅x_p) − 9⋅(x_p)^4 = 0 meta.create_gate("point doubling expr1", |_| { let x_p_4 = x_p.clone() * x_p.clone() * x_p.clone() * x_p.clone(); let expr1 = y_p.clone() * y_p.clone() - * (x_a.clone() + x_p.clone() * C::Base::from_u64(2)) - * C::Base::from_u64(4) - - x_p_4 * C::Base::from_u64(9); + * (x_a.clone() + x_p.clone() * F::from_u64(2)) + * F::from_u64(4) + - x_p_4 * F::from_u64(9); q_double.clone() * expr1 }); // 2⋅y_p⋅(y_a + y_p) − 3⋅(x_p)^2⋅(x_p − x_a) = 0 meta.create_gate("point doubling expr2", |_| { - let expr2 = y_p.clone() * (y_a + y_p) * C::Base::from_u64(2) - - x_p.clone() * x_p.clone() * (x_p - x_a) * C::Base::from_u64(3); + let expr2 = y_p.clone() * (y_a + y_p) * F::from_u64(2) + - x_p.clone() * x_p.clone() * (x_p - x_a) * F::from_u64(3); q_double * expr2 }); } pub(super) fn assign_region( - a: & as EccInstructions>::Point, + a: &EccPoint, offset: usize, - region: &mut Region<'_, EccChip>, - config: as Chip>::Config, + region: &mut Region<'_, C::Base>, + config: EccConfig, ) -> Result, Error> { // Enable `q_double` selector config.q_double.enable(region, offset)?; @@ -54,11 +53,11 @@ pub(super) fn assign_region( let doubled = x_p_val.zip(y_p_val).map(|(x, y)| { (C::from_xy(x, y).unwrap() * C::Scalar::from_u64(2)) .to_affine() - .get_xy() + .coordinates() .unwrap() }); - let x_a_val = doubled.map(|doubled| doubled.0); - let y_a_val = doubled.map(|doubled| doubled.1); + let x_a_val = doubled.map(|doubled| *doubled.x()); + let y_a_val = doubled.map(|doubled| *doubled.y()); // Assign the doubled point to `x_a`, `y_a` columns let x_a_var = region.assign_advice( @@ -75,7 +74,7 @@ pub(super) fn assign_region( )?; Ok(EccPoint { - x: CellValue::new(x_a_var, x_a_val), - y: CellValue::new(y_a_var, y_a_val), + x: CellValue::::new(x_a_var, x_a_val), + y: CellValue::::new(y_a_var, y_a_val), }) } diff --git a/src/circuit/gadget/ecc/chip/mul.rs b/src/circuit/gadget/ecc/chip/mul.rs index 354aba89e..a9dfab1c0 100644 --- a/src/circuit/gadget/ecc/chip/mul.rs +++ b/src/circuit/gadget/ecc/chip/mul.rs @@ -1,34 +1,33 @@ -use super::super::EccInstructions; -use super::{add_complete, double, util, CellValue, EccChip, EccPoint}; +use super::{add_complete, double, util, EccConfig, EccPoint, EccScalarVar}; use crate::constants; use ff::PrimeField; use halo2::{ arithmetic::{CurveAffine, Field, FieldExt}, - circuit::{Chip, Region}, + circuit::{CellValue, Region}, plonk::{ConstraintSystem, Error, Expression}, }; -pub(super) fn create_gate( - meta: &mut ConstraintSystem, - q_mul: Expression, - x_a_cur: Expression, - x_a_next: Expression, - x_p_cur: Expression, - x_p_next: Expression, - lambda1_cur: Expression, - lambda1_next: Expression, - lambda2_cur: Expression, - lambda2_next: Expression, +pub(super) fn create_gate( + meta: &mut ConstraintSystem, + q_mul: Expression, + x_a_cur: Expression, + x_a_next: Expression, + x_p_cur: Expression, + x_p_next: Expression, + lambda1_cur: Expression, + lambda1_next: Expression, + lambda2_cur: Expression, + lambda2_next: Expression, ) { let y_a_cur = (lambda1_cur.clone() + lambda2_cur.clone()) * (x_a_cur.clone() - (lambda1_cur.clone() * lambda1_cur.clone() - x_a_cur.clone() - x_p_cur.clone())) - * C::Base::TWO_INV; + * F::TWO_INV; let y_a_next = (lambda1_next.clone() + lambda2_next) * (x_a_next.clone() - (lambda1_next.clone() * lambda1_next - x_a_next.clone() - x_p_next)) - * C::Base::TWO_INV; + * F::TWO_INV; // λ_{2,i}^2 − x_{A,i+1} −(λ_{1,i}^2 − x_{A,i} − x_{P,i}) − x_{A,i} = 0 meta.create_gate("Double-and-add expr1", |_| { @@ -49,11 +48,11 @@ pub(super) fn create_gate( } pub(super) fn assign_region( - scalar: & as EccInstructions>::ScalarVar, - base: & as EccInstructions>::Point, + scalar: &EccScalarVar, + base: &EccPoint, offset: usize, - region: &mut Region<'_, EccChip>, - config: as Chip>::Config, + region: &mut Region<'_, C::Base>, + config: EccConfig, ) -> Result, Error> { // Copy the scalar decomposition for (w, k) in scalar.k_bits.iter().enumerate() { @@ -63,12 +62,12 @@ pub(super) fn assign_region( config.bits, w + offset, k, - &config.perm_scalar, + &config.perm_bits, )?; } // Initialise acc := [2]B - let mut acc = double::assign_region(&base, offset, region, config.clone()).unwrap(); + let mut acc = double::assign_region::(&base, offset, region, config.clone()).unwrap(); let mut x_a = acc.x.value; let mut y_a = acc.y.value; @@ -182,8 +181,8 @@ pub(super) fn assign_region( || y_a.ok_or(Error::SynthesisError), )?; acc = EccPoint { - x: CellValue::new(x_a_cell, x_a), - y: CellValue::new(y_a_cell, y_a), + x: CellValue::::new(x_a_cell, x_a), + y: CellValue::::new(y_a_cell, y_a), }; } @@ -215,12 +214,13 @@ pub(super) fn assign_region( || y_p.ok_or(Error::SynthesisError), )?; let p = EccPoint { - x: CellValue::new(x_p_cell, x_p), - y: CellValue::new(y_p_cell, y_p), + x: CellValue::::new(x_p_cell, x_p), + y: CellValue::::new(y_p_cell, y_p), }; // Acc + U - let tmp_acc = add_complete::assign_region(&p, &acc, row + offset, region, config.clone())?; + let tmp_acc = + add_complete::assign_region::(&p, &acc, row + offset, region, config.clone())?; // Copy acc from `x_a`, `y_a` over to `x_p`, `y_p` on the next row let acc_x = util::assign_and_constrain( @@ -243,8 +243,13 @@ pub(super) fn assign_region( acc = EccPoint { x: acc_x, y: acc_y }; // Acc + U + Acc - acc = - add_complete::assign_region(&acc, &tmp_acc, row + offset + 1, region, config.clone())?; + acc = add_complete::assign_region::( + &acc, + &tmp_acc, + row + offset + 1, + region, + config.clone(), + )?; } // Process the least significant bit @@ -269,12 +274,12 @@ pub(super) fn assign_region( || y_p.ok_or(Error::SynthesisError), )?; let p = EccPoint { - x: CellValue::new(x_p_cell, x_p), - y: CellValue::new(y_p_cell, y_p), + x: CellValue::::new(x_p_cell, x_p), + y: CellValue::::new(y_p_cell, y_p), }; // Return the result of the final complete addition as `[scalar]B` - add_complete::assign_region(&p, &acc, k_0_row + offset, region, config.clone()) + add_complete::assign_region::(&p, &acc, k_0_row + offset, region, config.clone()) } else { // If `k_0` is 1, simply return `Acc` Ok(acc) diff --git a/src/circuit/gadget/ecc/chip/mul_fixed.rs b/src/circuit/gadget/ecc/chip/mul_fixed.rs index 3b2f76b2b..50bb180d3 100644 --- a/src/circuit/gadget/ecc/chip/mul_fixed.rs +++ b/src/circuit/gadget/ecc/chip/mul_fixed.rs @@ -1,39 +1,38 @@ -use super::super::EccInstructions; -use super::{add, util, witness_point, EccChip, EccFixedPoints, EccPoint}; +use super::{ + add, util, witness_point, EccConfig, EccFixedPoint, EccPoint, EccScalarFixed, OrchardFixedBases, +}; use crate::constants; use group::Curve; use halo2::{ arithmetic::{CurveAffine, Field, FieldExt}, - circuit::{Chip, Region}, + circuit::Region, plonk::{Column, ConstraintSystem, Error, Expression, Fixed}, poly::Rotation, }; -pub(super) fn create_gate( - meta: &mut ConstraintSystem, +pub(super) fn create_gate( + meta: &mut ConstraintSystem, lagrange_coeffs: [Column; constants::H], - q_mul_fixed: Expression, - x_p: Expression, - y_p: Expression, - k: Expression, - u: Expression, - z: Expression, + q_mul_fixed: Expression, + x_p: Expression, + y_p: Expression, + k: Expression, + u: Expression, + z: Expression, ) { // Check interpolation of x-coordinate meta.create_gate("fixed-base scalar mul (x)", |meta| { - let k_pow: Vec> = (0..constants::H) - .map(|pow| { - (0..pow).fold(Expression::Constant(C::Base::one()), |acc, _| { - acc * k.clone() - }) - }) + let k_pow: Vec> = (0..constants::H) + .map(|pow| (0..pow).fold(Expression::Constant(F::one()), |acc, _| acc * k.clone())) .collect(); - let interpolated_x = k_pow.iter().zip(lagrange_coeffs.iter()).fold( - Expression::Constant(C::Base::zero()), - |acc, (k_pow, coeff)| acc + (k_pow.clone() * meta.query_fixed(*coeff, Rotation::cur())), - ); + let interpolated_x = k_pow + .iter() + .zip(lagrange_coeffs.iter()) + .fold(Expression::Constant(F::zero()), |acc, (k_pow, coeff)| { + acc + (k_pow.clone() * meta.query_fixed(*coeff, Rotation::cur())) + }); q_mul_fixed.clone() * (interpolated_x - x_p) }); @@ -45,11 +44,11 @@ pub(super) fn create_gate( } pub(super) fn assign_region( - scalar: & as EccInstructions>::ScalarFixed, - base: & as EccInstructions>::FixedPoint, + scalar: &EccScalarFixed, + base: &EccFixedPoint, offset: usize, - region: &mut Region<'_, EccChip>, - config: as Chip>::Config, + region: &mut Region<'_, C::Base>, + config: EccConfig, ) -> Result, Error> { // Assign fixed columns for given fixed base for w in 0..constants::NUM_WINDOWS { @@ -97,17 +96,17 @@ pub(super) fn assign_region( config.bits, w + offset, k, - &config.perm_scalar, + &config.perm_bits, )?; } // Get the value of the fixed base let b = match base.fixed_point { - EccFixedPoints::CommitIvkR(inner) => inner.0.value(), - EccFixedPoints::NoteCommitR(inner) => inner.0.value(), - EccFixedPoints::NullifierK(inner) => inner.0.value(), - EccFixedPoints::ValueCommitR(inner) => inner.0.value(), - EccFixedPoints::ValueCommitV(inner) => inner.0.value(), + OrchardFixedBases::CommitIvkR(inner) => inner.0.value(), + OrchardFixedBases::NoteCommitR(inner) => inner.0.value(), + OrchardFixedBases::NullifierK(inner) => inner.0.value(), + OrchardFixedBases::ValueCommitR(inner) => inner.0.value(), + OrchardFixedBases::ValueCommitV(inner) => inner.0.value(), }; // The scalar decomposition was done in the base field. For computation @@ -193,7 +192,7 @@ pub(super) fn assign_region( region.assign_advice(|| "u", config.u, w, || u_val.ok_or(Error::SynthesisError))?; // Add to the cumulative sum - sum = add::assign_region(&mul_b, &sum, offset + w, region, config.clone())?; + sum = add::assign_region::(&mul_b, &sum, offset + w, region, config.clone())?; } // Process most significant window outside the for loop @@ -228,7 +227,7 @@ pub(super) fn assign_region( } // Add to the cumulative sum and return the final result as `[scalar]B`. - add::assign_region( + add::assign_region::( &mul_b, &sum, offset + constants::NUM_WINDOWS - 1, diff --git a/src/circuit/gadget/ecc/chip/mul_fixed_short.rs b/src/circuit/gadget/ecc/chip/mul_fixed_short.rs index 1a765a421..9f4aaecc4 100644 --- a/src/circuit/gadget/ecc/chip/mul_fixed_short.rs +++ b/src/circuit/gadget/ecc/chip/mul_fixed_short.rs @@ -1,22 +1,24 @@ -use super::super::EccInstructions; -use super::{add, util, witness_point, EccChip, EccFixedPoints, EccPoint}; +use super::{ + add, util, witness_point, EccConfig, EccFixedPoint, EccPoint, EccScalarFixedShort, + OrchardFixedBases, +}; use crate::constants; use group::Curve; use halo2::{ arithmetic::{CurveAffine, Field, FieldExt}, - circuit::{Chip, Region}, + circuit::Region, plonk::{ConstraintSystem, Error, Expression}, }; // We reuse the constraints in the `mul_fixed` gate so exclude them here. // Here, we add some new constraints specific to the short signed case. -pub(super) fn create_gate( - meta: &mut ConstraintSystem, - q_mul_fixed_short: Expression, - s: Expression, - y_a: Expression, - y_p: Expression, +pub(super) fn create_gate( + meta: &mut ConstraintSystem, + q_mul_fixed_short: Expression, + s: Expression, + y_a: Expression, + y_p: Expression, ) { // `(x_a, y_a)` is the result of `[m]B`, where `m` is the magnitude. // We conditionally negate this result using `y_p = y_a * s`, where `s` is the sign. @@ -31,11 +33,11 @@ pub(super) fn create_gate( } pub(super) fn assign_region( - scalar: & as EccInstructions>::ScalarFixedShort, - base: & as EccInstructions>::FixedPoint, + scalar: &EccScalarFixedShort, + base: &EccFixedPoint, offset: usize, - region: &mut Region<'_, EccChip>, - config: as Chip>::Config, + region: &mut Region<'_, C::Base>, + config: EccConfig, ) -> Result, Error> { // Assign fixed columns for given fixed base for w in 0..constants::NUM_WINDOWS_SHORT { @@ -83,17 +85,17 @@ pub(super) fn assign_region( config.bits, w + offset, k, - &config.perm_scalar, + &config.perm_bits, )?; } // Get the value of the fixed base let b = match base.fixed_point { - EccFixedPoints::CommitIvkR(inner) => inner.0.value(), - EccFixedPoints::NoteCommitR(inner) => inner.0.value(), - EccFixedPoints::NullifierK(inner) => inner.0.value(), - EccFixedPoints::ValueCommitR(inner) => inner.0.value(), - EccFixedPoints::ValueCommitV(inner) => inner.0.value(), + OrchardFixedBases::CommitIvkR(inner) => inner.0.value(), + OrchardFixedBases::NoteCommitR(inner) => inner.0.value(), + OrchardFixedBases::NullifierK(inner) => inner.0.value(), + OrchardFixedBases::ValueCommitR(inner) => inner.0.value(), + OrchardFixedBases::ValueCommitV(inner) => inner.0.value(), }; // The scalar decomposition was done in the base field. For computation @@ -183,7 +185,7 @@ pub(super) fn assign_region( region.assign_advice(|| "u", config.u, w, || u_val.ok_or(Error::SynthesisError))?; // Add to the cumulative sum - sum = add::assign_region(&mul_b, &sum, offset + w, region, config.clone()).unwrap(); + sum = add::assign_region::(&mul_b, &sum, offset + w, region, config.clone()).unwrap(); } // Process most significant window outside the for loop @@ -219,7 +221,7 @@ pub(super) fn assign_region( } // Add to the cumulative sum to get `[magnitude]B`. - let magnitude_mul = add::assign_region( + let magnitude_mul = add::assign_region::( &mul_b, &sum, offset + constants::NUM_WINDOWS_SHORT - 1, @@ -234,14 +236,14 @@ pub(super) fn assign_region( config.bits, offset + constants::NUM_WINDOWS_SHORT, &scalar.sign, - &config.perm_scalar, + &config.perm_bits, )?; // Conditionally negate `y`-coordinate let y_val = match sign.value { Some(sign) => { if sign == -C::Base::one() { - magnitude_mul.y.value.map(|y| -y) + magnitude_mul.y.value.map(|y: C::Base| -y) } else { magnitude_mul.y.value } diff --git a/src/circuit/gadget/ecc/chip/util.rs b/src/circuit/gadget/ecc/chip/util.rs index 34a0ccc4c..eea77d66e 100644 --- a/src/circuit/gadget/ecc/chip/util.rs +++ b/src/circuit/gadget/ecc/chip/util.rs @@ -1,19 +1,19 @@ -use super::{CellValue, EccChip}; +use super::CellValue; use halo2::{ - arithmetic::CurveAffine, + arithmetic::FieldExt, circuit::Region, plonk::{Advice, Column, Error, Permutation}, }; /// Assign a cell the same value as another cell and set up a copy constraint between them. -pub(super) fn assign_and_constrain( - region: &mut Region<'_, EccChip>, +pub(super) fn assign_and_constrain( + region: &mut Region<'_, F>, annotation: A, column: Column, row: usize, - copy: &CellValue, + copy: &CellValue, perm: &Permutation, -) -> Result, Error> +) -> Result, Error> where A: Fn() -> AR, AR: Into, diff --git a/src/circuit/gadget/ecc/chip/witness_point.rs b/src/circuit/gadget/ecc/chip/witness_point.rs index 34c3f8a89..43c7a0f27 100644 --- a/src/circuit/gadget/ecc/chip/witness_point.rs +++ b/src/circuit/gadget/ecc/chip/witness_point.rs @@ -1,8 +1,8 @@ -use super::{CellValue, EccChip, EccPoint}; +use super::{CellValue, EccConfig, EccPoint}; use halo2::{ arithmetic::CurveAffine, - circuit::{Chip, Region}, + circuit::Region, plonk::{ConstraintSystem, Error, Expression}, }; @@ -22,16 +22,16 @@ pub(super) fn create_gate( pub(super) fn assign_region( value: Option, offset: usize, - region: &mut Region<'_, EccChip>, - config: as Chip>::Config, + region: &mut Region<'_, C::Base>, + config: EccConfig, ) -> Result, Error> { // Enable `q_point` selector config.q_point.enable(region, offset)?; - let value = value.map(|value| value.get_xy().unwrap()); + let value = value.map(|value| value.coordinates().unwrap()); // Assign `x_p` value - let x_p_val = value.map(|value| value.0); + let x_p_val = value.map(|value| *value.x()); let x_p_var = region.assign_advice( || "x_p", config.P.0, @@ -40,7 +40,7 @@ pub(super) fn assign_region( )?; // Assign `y_p` value - let y_p_val = value.map(|value| value.1); + let y_p_val = value.map(|value| *value.y()); let y_p_var = region.assign_advice( || "y_p", config.P.1, @@ -49,7 +49,7 @@ pub(super) fn assign_region( )?; Ok(EccPoint { - x: CellValue::new(x_p_var, x_p_val), - y: CellValue::new(y_p_var, y_p_val), + x: CellValue::::new(x_p_var, x_p_val), + y: CellValue::::new(y_p_var, y_p_val), }) } diff --git a/src/circuit/gadget/ecc/chip/witness_scalar_fixed.rs b/src/circuit/gadget/ecc/chip/witness_scalar_fixed.rs index e886071bf..9ea33c9b5 100644 --- a/src/circuit/gadget/ecc/chip/witness_scalar_fixed.rs +++ b/src/circuit/gadget/ecc/chip/witness_scalar_fixed.rs @@ -1,20 +1,20 @@ -use super::{CellValue, EccChip, EccScalarFixed}; +use super::{CellValue, EccConfig, EccScalarFixed}; use crate::constants::{self, util}; use halo2::{ - arithmetic::{CurveAffine, Field, FieldExt}, - circuit::{Chip, Region}, + arithmetic::{CurveAffine, FieldExt}, + circuit::Region, plonk::{ConstraintSystem, Error, Expression}, }; -pub(super) fn create_gate( - meta: &mut ConstraintSystem, - q_scalar_fixed: Expression, - k: Expression, +pub(super) fn create_gate( + meta: &mut ConstraintSystem, + q_scalar_fixed: Expression, + k: Expression, ) { meta.create_gate("witness scalar fixed", |_| { // Check that `k` is within the allowed window size - let range_check = (0..constants::H).fold(Expression::Constant(C::Base::one()), |acc, i| { - acc * (k.clone() - Expression::Constant(C::Base::from_u64(i as u64))) + let range_check = (0..constants::H).fold(Expression::Constant(F::one()), |acc, i| { + acc * (k.clone() - Expression::Constant(F::from_u64(i as u64))) }); q_scalar_fixed * range_check }); @@ -24,8 +24,8 @@ pub(super) fn assign_region( value: Option, scalar_num_bits: usize, offset: usize, - region: &mut Region<'_, EccChip>, - config: as Chip>::Config, + region: &mut Region<'_, C::Base>, + config: EccConfig, ) -> Result, Error> { // Decompose scalar into windows let bits: Option> = value.map(|value| { diff --git a/src/circuit/gadget/ecc/chip/witness_scalar_fixed_short.rs b/src/circuit/gadget/ecc/chip/witness_scalar_fixed_short.rs index 687269ad8..1f61dca27 100644 --- a/src/circuit/gadget/ecc/chip/witness_scalar_fixed_short.rs +++ b/src/circuit/gadget/ecc/chip/witness_scalar_fixed_short.rs @@ -1,29 +1,29 @@ -use super::{CellValue, EccChip, EccScalarFixedShort}; +use super::{CellValue, EccConfig, EccScalarFixedShort}; use crate::constants::{self, util}; use halo2::{ arithmetic::{CurveAffine, Field, FieldExt}, - circuit::{Chip, Region}, + circuit::Region, plonk::{ConstraintSystem, Error, Expression}, }; -pub(super) fn create_gate( - meta: &mut ConstraintSystem, - q_scalar_fixed_short: Expression, - s: Expression, +pub(super) fn create_gate( + meta: &mut ConstraintSystem, + q_scalar_fixed_short: Expression, + s: Expression, ) { // Check that s \in {1, -1} meta.create_gate("check sign", |_| { q_scalar_fixed_short - * (s.clone() + Expression::Constant(C::Base::one())) - * (s - Expression::Constant(C::Base::one())) + * (s.clone() + Expression::Constant(F::one())) + * (s - Expression::Constant(F::one())) }); } pub(super) fn assign_region( value: Option, offset: usize, - region: &mut Region<'_, EccChip>, - config: as Chip>::Config, + region: &mut Region<'_, C::Base>, + config: EccConfig, ) -> Result, Error> { // Compute the scalar's sign let sign = value.map(|value| { @@ -98,7 +98,7 @@ pub(super) fn assign_region( Ok(EccScalarFixedShort { magnitude, - sign: CellValue::new(sign_cell, sign), + sign: CellValue::::new(sign_cell, sign), k_bits, }) } diff --git a/src/circuit/gadget/ecc/chip/witness_scalar_var.rs b/src/circuit/gadget/ecc/chip/witness_scalar_var.rs index b59dff1d0..7d491d72c 100644 --- a/src/circuit/gadget/ecc/chip/witness_scalar_var.rs +++ b/src/circuit/gadget/ecc/chip/witness_scalar_var.rs @@ -1,28 +1,28 @@ -use super::{CellValue, EccChip, EccScalarVar}; +use super::{CellValue, EccConfig, EccScalarVar}; use ff::PrimeField; use halo2::{ - arithmetic::{CurveAffine, Field, FieldExt}, - circuit::{Chip, Region}, + arithmetic::{CurveAffine, FieldExt}, + circuit::Region, plonk::{ConstraintSystem, Error, Expression}, }; -pub(super) fn create_gate( - meta: &mut ConstraintSystem, - q_scalar_var: Expression, - k: Expression, +pub(super) fn create_gate( + meta: &mut ConstraintSystem, + q_scalar_var: Expression, + k: Expression, ) { meta.create_gate("witness point", |_| { // Check that k \in {0, 1} - q_scalar_var * (k.clone()) * (Expression::Constant(C::Base::one()) - k) + q_scalar_var * (k.clone()) * (Expression::Constant(F::one()) - k) }); } pub(super) fn assign_region( value: Option, offset: usize, - region: &mut Region<'_, EccChip>, - config: as Chip>::Config, + region: &mut Region<'_, C::Base>, + config: EccConfig, ) -> Result, Error> { // The scalar field `F_q = 2^254 + t_q` // FIXME: Derive this from constants in `Fq` module diff --git a/src/constants.rs b/src/constants.rs index fb5c8ea8c..b6d6bcdb3 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -56,13 +56,13 @@ pub const NUM_WINDOWS_SHORT: usize = /// Number of bits used in complete addition (for variable-base scalar mul) pub const NUM_COMPLETE_BITS: usize = 3; -pub trait OrchardFixedBases { +pub trait Name { fn name(&self) -> &[u8]; } #[derive(Copy, Clone, Debug)] pub struct CommitIvkR(pub OrchardFixedBase); -impl OrchardFixedBases for CommitIvkR { +impl Name for CommitIvkR { fn name(&self) -> &[u8] { b"CommitIvkR" } @@ -70,7 +70,7 @@ impl OrchardFixedBases for CommitIvkR { #[derive(Copy, Clone, Debug)] pub struct NoteCommitR(pub OrchardFixedBase); -impl OrchardFixedBases for NoteCommitR { +impl Name for NoteCommitR { fn name(&self) -> &[u8] { b"NoteCommitR" } @@ -78,7 +78,7 @@ impl OrchardFixedBases for NoteCommitR { #[derive(Copy, Clone, Debug)] pub struct NullifierK(pub OrchardFixedBase); -impl OrchardFixedBases for NullifierK { +impl Name for NullifierK { fn name(&self) -> &[u8] { b"NullifierK" } @@ -86,7 +86,7 @@ impl OrchardFixedBases for NullifierK { #[derive(Copy, Clone, Debug)] pub struct ValueCommitR(pub OrchardFixedBase); -impl OrchardFixedBases for ValueCommitR { +impl Name for ValueCommitR { fn name(&self) -> &[u8] { b"ValueCommitR" } @@ -94,7 +94,7 @@ impl OrchardFixedBases for ValueCommitR { #[derive(Copy, Clone, Debug)] pub struct ValueCommitV(pub OrchardFixedBase); -impl OrchardFixedBases for ValueCommitV { +impl Name for ValueCommitV { fn name(&self) -> &[u8] { b"ValueCommitV" }