From 32f3068886443b495b34fa756e7530a3e29e7ad5 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Thu, 15 Jul 2021 13:05:22 +0800 Subject: [PATCH] ecc.rs: Add MulFixedBaseField type. In the Orchard protocol, only the NullifierK fixed base in used in scalar multiplication with a base field element. The mul_fixed_base_field_elem() API does not have to accept fixed bases other than NullifierK; conversely, NullifierK does not have to work with the full-width mul_fixed() API. --- src/circuit/gadget/ecc.rs | 39 +++++++++--- src/circuit/gadget/ecc/chip.rs | 5 +- src/circuit/gadget/ecc/chip/mul_fixed.rs | 19 +++++- .../ecc/chip/mul_fixed/base_field_elem.rs | 62 ++++--------------- .../gadget/ecc/chip/mul_fixed/full_width.rs | 9 --- src/constants.rs | 2 +- src/constants/load.rs | 40 +++++++++--- 7 files changed, 97 insertions(+), 79 deletions(-) diff --git a/src/circuit/gadget/ecc.rs b/src/circuit/gadget/ecc.rs index 773c4278..3fb3a92f 100644 --- a/src/circuit/gadget/ecc.rs +++ b/src/circuit/gadget/ecc.rs @@ -39,8 +39,10 @@ pub trait EccInstructions: Chip + UtilitiesInstructions /// Variable representing the affine short Weierstrass x-coordinate of an /// elliptic curve point. type X: Clone + Debug; - /// Enumeration of the set of fixed bases to be used in full-width scalar mul. + /// Enumeration of the set of fixed bases to be used in scalar mul with a full-width scalar. type FixedPoints: Clone + Debug; + /// Enumeration of the set of fixed bases to be used in scalar mul with a base field element. + type FixedPointsBaseField: Clone + Debug; /// Enumeration of the set of fixed bases to be used in short signed scalar mul. type FixedPointsShort: Clone + Debug; @@ -113,7 +115,7 @@ pub trait EccInstructions: Chip + UtilitiesInstructions &self, layouter: &mut impl Layouter, base_field_elem: Self::Var, - base: &Self::FixedPoints, + base: &Self::FixedPointsBaseField, ) -> Result; } @@ -258,6 +260,8 @@ impl + Clone + Debug + Eq> X where @@ -294,9 +298,30 @@ where }) } - /// Multiplies `self` using a value encoded in a base field element - /// as the scalar. - pub fn mul_base_field_elem( + /// Wraps the given fixed base (obtained directly from an instruction) in a gadget. + pub fn from_inner(chip: EccChip, inner: EccChip::FixedPoints) -> Self { + FixedPoint { chip, inner } + } +} + +/// A constant elliptic curve point over the given curve, used in scalar multiplication +/// with a base field element +#[derive(Clone, Debug)] +pub struct FixedPointBaseField +where + EccChip: EccInstructions + Clone + Debug + Eq, +{ + chip: EccChip, + inner: EccChip::FixedPointsBaseField, +} + +impl FixedPointBaseField +where + EccChip: EccInstructions + Clone + Debug + Eq, +{ + #[allow(clippy::type_complexity)] + /// Returns `[by] self`. + pub fn mul( &self, mut layouter: impl Layouter, by: EccChip::Var, @@ -310,8 +335,8 @@ where } /// Wraps the given fixed base (obtained directly from an instruction) in a gadget. - pub fn from_inner(chip: EccChip, inner: EccChip::FixedPoints) -> Self { - FixedPoint { chip, inner } + pub fn from_inner(chip: EccChip, inner: EccChip::FixedPointsBaseField) -> Self { + FixedPointBaseField { chip, inner } } } diff --git a/src/circuit/gadget/ecc/chip.rs b/src/circuit/gadget/ecc/chip.rs index 616a28e1..e8a0c446 100644 --- a/src/circuit/gadget/ecc/chip.rs +++ b/src/circuit/gadget/ecc/chip.rs @@ -4,7 +4,7 @@ use crate::{ copy, decompose_running_sum::RunningSumConfig, lookup_range_check::LookupRangeCheckConfig, CellValue, UtilitiesInstructions, Var, }, - constants::{self, OrchardFixedBasesFull, ValueCommitV}, + constants::{self, NullifierK, OrchardFixedBasesFull, ValueCommitV}, primitives::sinsemilla, }; use arrayvec::ArrayVec; @@ -327,6 +327,7 @@ impl EccInstructions for EccChip { type Point = EccPoint; type X = CellValue; type FixedPoints = OrchardFixedBasesFull; + type FixedPointsBaseField = NullifierK; type FixedPointsShort = ValueCommitV; fn constrain_equal( @@ -435,7 +436,7 @@ impl EccInstructions for EccChip { &self, layouter: &mut impl Layouter, base_field_elem: CellValue, - base: &Self::FixedPoints, + base: &Self::FixedPointsBaseField, ) -> Result { let config: mul_fixed::base_field_elem::Config = self.config().into(); config.assign( diff --git a/src/circuit/gadget/ecc/chip/mul_fixed.rs b/src/circuit/gadget/ecc/chip/mul_fixed.rs index 57eb58a1..a21f8106 100644 --- a/src/circuit/gadget/ecc/chip/mul_fixed.rs +++ b/src/circuit/gadget/ecc/chip/mul_fixed.rs @@ -4,7 +4,7 @@ use super::{ }; use crate::constants::{ self, - load::{OrchardFixedBase, OrchardFixedBasesFull, ValueCommitV, WindowUs}, + load::{NullifierK, OrchardFixedBase, OrchardFixedBasesFull, ValueCommitV, WindowUs}, util, }; @@ -37,6 +37,7 @@ lazy_static! { #[derive(Copy, Clone, Debug)] enum OrchardFixedBases { Full(OrchardFixedBasesFull), + NullifierK, ValueCommitV, } @@ -52,10 +53,17 @@ impl From for OrchardFixedBases { } } +impl From for OrchardFixedBases { + fn from(_nullifier_k: NullifierK) -> Self { + Self::NullifierK + } +} + impl OrchardFixedBases { pub fn generator(self) -> pallas::Affine { match self { Self::ValueCommitV => constants::value_commit_v::generator(), + Self::NullifierK => constants::nullifier_k::generator(), Self::Full(base) => base.generator(), } } @@ -63,6 +71,7 @@ impl OrchardFixedBases { pub fn u(self) -> Vec { match self { Self::ValueCommitV => ValueCommitV::get().u_short.0.as_ref().to_vec(), + Self::NullifierK => NullifierK.u().0.as_ref().to_vec(), Self::Full(base) => base.u().0.as_ref().to_vec(), } } @@ -236,6 +245,14 @@ impl Config { base.z.0.as_ref().to_vec(), ) } + OrchardFixedBases::NullifierK => { + assert_eq!(NUM_WINDOWS, constants::NUM_WINDOWS); + let base: OrchardFixedBase = NullifierK.into(); + ( + base.lagrange_coeffs.0.as_ref().to_vec(), + base.z.0.as_ref().to_vec(), + ) + } }; // Assign fixed columns for given fixed base diff --git a/src/circuit/gadget/ecc/chip/mul_fixed/base_field_elem.rs b/src/circuit/gadget/ecc/chip/mul_fixed/base_field_elem.rs index dd93c18d..eabc49a8 100644 --- a/src/circuit/gadget/ecc/chip/mul_fixed/base_field_elem.rs +++ b/src/circuit/gadget/ecc/chip/mul_fixed/base_field_elem.rs @@ -1,4 +1,4 @@ -use super::super::{EccBaseFieldElemFixed, EccConfig, EccPoint, OrchardFixedBasesFull}; +use super::super::{EccBaseFieldElemFixed, EccConfig, EccPoint, NullifierK}; use super::H_BASE; use crate::{ @@ -181,7 +181,7 @@ impl Config { &self, mut layouter: impl Layouter, scalar: CellValue, - base: OrchardFixedBasesFull, + base: NullifierK, ) -> Result { let (scalar, acc, mul_b) = layouter.assign_region( || "Base-field elem fixed-base mul (incomplete addition)", @@ -423,8 +423,8 @@ pub mod tests { use crate::circuit::gadget::{ ecc::{ - chip::{EccChip, OrchardFixedBasesFull}, - FixedPoint, Point, + chip::{EccChip, NullifierK}, + FixedPointBaseField, Point, }, utilities::UtilitiesInstructions, }; @@ -434,59 +434,21 @@ pub mod tests { chip: EccChip, mut layouter: impl Layouter, ) -> Result<(), Error> { - // commit_ivk_r - let commit_ivk_r = OrchardFixedBasesFull::CommitIvkR; - test_single_base( - chip.clone(), - layouter.namespace(|| "commit_ivk_r"), - FixedPoint::from_inner(chip.clone(), commit_ivk_r), - commit_ivk_r.generator(), - )?; - - // note_commit_r - let note_commit_r = OrchardFixedBasesFull::NoteCommitR; - test_single_base( - chip.clone(), - layouter.namespace(|| "note_commit_r"), - FixedPoint::from_inner(chip.clone(), note_commit_r), - note_commit_r.generator(), - )?; - // nullifier_k - let nullifier_k = OrchardFixedBasesFull::NullifierK; + let nullifier_k = NullifierK; test_single_base( chip.clone(), layouter.namespace(|| "nullifier_k"), - FixedPoint::from_inner(chip.clone(), nullifier_k), + FixedPointBaseField::from_inner(chip, nullifier_k), nullifier_k.generator(), - )?; - - // value_commit_r - let value_commit_r = OrchardFixedBasesFull::ValueCommitR; - test_single_base( - chip.clone(), - layouter.namespace(|| "value_commit_r"), - FixedPoint::from_inner(chip.clone(), value_commit_r), - value_commit_r.generator(), - )?; - - // spend_auth_g - let spend_auth_g = OrchardFixedBasesFull::SpendAuthG; - test_single_base( - chip.clone(), - layouter.namespace(|| "spend_auth_g"), - FixedPoint::from_inner(chip, spend_auth_g), - spend_auth_g.generator(), - )?; - - Ok(()) + ) } #[allow(clippy::op_ref)] fn test_single_base( chip: EccChip, mut layouter: impl Layouter, - base: FixedPoint, + base: FixedPointBaseField, base_val: pallas::Affine, ) -> Result<(), Error> { let column = chip.config().advices[0]; @@ -517,7 +479,7 @@ pub mod tests { column, Some(scalar_fixed), )?; - base.mul_base_field_elem(layouter.namespace(|| "random [a]B"), scalar_fixed)? + base.mul(layouter.namespace(|| "random [a]B"), scalar_fixed)? }; constrain_equal( chip.clone(), @@ -545,7 +507,7 @@ pub mod tests { column, Some(scalar_fixed), )?; - base.mul_base_field_elem(layouter.namespace(|| "mul with double"), scalar_fixed)? + base.mul(layouter.namespace(|| "mul with double"), scalar_fixed)? }; constrain_equal( chip.clone(), @@ -563,7 +525,7 @@ pub mod tests { let result = { let scalar_fixed = chip.load_private(layouter.namespace(|| "zero"), column, Some(scalar_fixed))?; - base.mul_base_field_elem(layouter.namespace(|| "mul by zero"), scalar_fixed)? + base.mul(layouter.namespace(|| "mul by zero"), scalar_fixed)? }; constrain_equal( chip.clone(), @@ -580,7 +542,7 @@ pub mod tests { let result = { let scalar_fixed = chip.load_private(layouter.namespace(|| "-1"), column, Some(scalar_fixed))?; - base.mul_base_field_elem(layouter.namespace(|| "mul by -1"), scalar_fixed)? + base.mul(layouter.namespace(|| "mul by -1"), scalar_fixed)? }; constrain_equal( chip, diff --git a/src/circuit/gadget/ecc/chip/mul_fixed/full_width.rs b/src/circuit/gadget/ecc/chip/mul_fixed/full_width.rs index 5e01d920..b7d82ecc 100644 --- a/src/circuit/gadget/ecc/chip/mul_fixed/full_width.rs +++ b/src/circuit/gadget/ecc/chip/mul_fixed/full_width.rs @@ -150,15 +150,6 @@ pub mod tests { note_commit_r.generator(), )?; - // nullifier_k - let nullifier_k = OrchardFixedBasesFull::NullifierK; - test_single_base( - chip.clone(), - layouter.namespace(|| "nullifier_k"), - FixedPoint::from_inner(chip.clone(), nullifier_k), - nullifier_k.generator(), - )?; - // value_commit_r let value_commit_r = OrchardFixedBasesFull::ValueCommitR; test_single_base( diff --git a/src/constants.rs b/src/constants.rs index 324c51b0..50a26277 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -18,7 +18,7 @@ pub mod value_commit_v; pub mod load; pub mod util; -pub use load::{OrchardFixedBase, OrchardFixedBasesFull, ValueCommitV}; +pub use load::{NullifierK, OrchardFixedBase, OrchardFixedBasesFull, ValueCommitV}; /// The Pallas scalar field modulus is $q = 2^{254} + \mathsf{t_q}$. /// diff --git a/src/constants/load.rs b/src/constants/load.rs index 60a28b14..e2743f26 100644 --- a/src/constants/load.rs +++ b/src/constants/load.rs @@ -7,7 +7,6 @@ use pasta_curves::{arithmetic::FieldExt, pallas}; pub enum OrchardFixedBasesFull { CommitIvkR, NoteCommitR, - NullifierK, ValueCommitR, SpendAuthG, } @@ -17,7 +16,6 @@ impl OrchardFixedBasesFull { match self { OrchardFixedBasesFull::CommitIvkR => super::commit_ivk_r::generator(), OrchardFixedBasesFull::NoteCommitR => super::note_commit_r::generator(), - OrchardFixedBasesFull::NullifierK => super::nullifier_k::generator(), OrchardFixedBasesFull::ValueCommitR => super::value_commit_r::generator(), OrchardFixedBasesFull::SpendAuthG => super::spend_auth_g::generator(), } @@ -27,7 +25,6 @@ impl OrchardFixedBasesFull { match self { OrchardFixedBasesFull::CommitIvkR => super::commit_ivk_r::U.into(), OrchardFixedBasesFull::NoteCommitR => super::note_commit_r::U.into(), - OrchardFixedBasesFull::NullifierK => super::nullifier_k::U.into(), OrchardFixedBasesFull::ValueCommitR => super::value_commit_r::U.into(), OrchardFixedBasesFull::SpendAuthG => super::spend_auth_g::U.into(), } @@ -56,11 +53,6 @@ impl From for OrchardFixedBase { super::note_commit_r::Z.into(), super::note_commit_r::U.into(), ), - OrchardFixedBasesFull::NullifierK => ( - super::nullifier_k::generator(), - super::nullifier_k::Z.into(), - super::nullifier_k::U.into(), - ), OrchardFixedBasesFull::ValueCommitR => ( super::value_commit_r::generator(), super::value_commit_r::Z.into(), @@ -82,7 +74,7 @@ impl From for OrchardFixedBase { } } -/// A fixed base to be used in scalar multiplication with a short signed exponent. +/// A fixed base to be used in scalar multiplication with a base field element. #[derive(Clone, Debug, Eq, PartialEq)] pub struct ValueCommitV { pub generator: pallas::Affine, @@ -103,6 +95,36 @@ impl ValueCommitV { } } +/// A fixed base to be used in scalar multiplication with a short signed exponent. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct NullifierK; + +impl From for OrchardFixedBase { + fn from(_nullifier_k: NullifierK) -> Self { + let (generator, z, u) = ( + super::nullifier_k::generator(), + super::nullifier_k::Z.into(), + super::nullifier_k::U.into(), + ); + Self { + generator, + lagrange_coeffs: compute_lagrange_coeffs(generator, NUM_WINDOWS).into(), + z, + u, + } + } +} + +impl NullifierK { + pub fn generator(&self) -> pallas::Affine { + super::nullifier_k::generator() + } + + pub fn u(&self) -> U { + super::nullifier_k::U.into() + } +} + #[derive(Clone, Debug, Eq, PartialEq)] // 8 coefficients per window pub struct WindowLagrangeCoeffs(pub Box<[pallas::Base; H]>);