From 06ad0b692503dd193e7815ae7985ef2a2597c7d7 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Thu, 19 Aug 2021 14:59:39 +0800 Subject: [PATCH] ecc: Introduce FixedPoints trait with Full, Base, Short associated types. --- src/circuit.rs | 26 +-- src/circuit/commit_ivk.rs | 52 +++-- src/circuit/gadget.rs | 19 +- src/circuit/gadget/ecc.rs | 130 ++++++------- src/circuit/gadget/ecc/chip.rs | 79 +++++--- src/circuit/gadget/ecc/chip/mul.rs | 5 +- src/circuit/gadget/ecc/chip/mul_fixed.rs | 148 ++++---------- .../ecc/chip/mul_fixed/base_field_elem.rs | 42 ++-- .../gadget/ecc/chip/mul_fixed/full_width.rs | 38 ++-- .../gadget/ecc/chip/mul_fixed/short.rs | 69 ++++--- src/circuit/gadget/sinsemilla.rs | 39 ++-- src/circuit/gadget/sinsemilla/chip.rs | 126 +++++------- .../gadget/sinsemilla/chip/generator_table.rs | 10 +- .../gadget/sinsemilla/chip/hash_to_point.rs | 11 +- src/circuit/gadget/sinsemilla/merkle.rs | 18 +- src/circuit/gadget/sinsemilla/merkle/chip.rs | 114 +++++++---- src/circuit/note_commit.rs | 47 +++-- src/constants.rs | 182 +++++++++++++++++- 18 files changed, 698 insertions(+), 457 deletions(-) diff --git a/src/circuit.rs b/src/circuit.rs index e2e32ca6..a5da1f21 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -13,9 +13,8 @@ use rand::RngCore; use crate::{ constants::{ - load::{NullifierK, OrchardFixedBasesFull, ValueCommitV}, - util::gen_const_array, - MERKLE_DEPTH_ORCHARD, + util::gen_const_array, NullifierK, OrchardCommitDomains, OrchardFixedBases, + OrchardFixedBasesFull, OrchardHashDomains, ValueCommitV, MERKLE_DEPTH_ORCHARD, }, keys::{ CommitIvkRandomness, DiversifiedTransmissionKey, NullifierDerivingKey, SpendValidatingKey, @@ -41,7 +40,7 @@ use gadget::{ }, poseidon::{Hash as PoseidonHash, Pow5Chip as PoseidonChip, Pow5Config as PoseidonConfig}, sinsemilla::{ - chip::{SinsemillaChip, SinsemillaConfig, SinsemillaHashDomains}, + chip::{SinsemillaChip, SinsemillaConfig}, merkle::{ chip::{MerkleChip, MerkleConfig}, MerklePath, @@ -79,12 +78,14 @@ pub struct Config { // Selector for the field addition gate poseidon_hash(nk, rho_old) + psi_old. q_add: Selector, advices: [Column; 10], - ecc_config: EccConfig, + ecc_config: EccConfig, poseidon_config: PoseidonConfig, - merkle_config_1: MerkleConfig, - merkle_config_2: MerkleConfig, - sinsemilla_config_1: SinsemillaConfig, - sinsemilla_config_2: SinsemillaConfig, + merkle_config_1: MerkleConfig, + merkle_config_2: MerkleConfig, + sinsemilla_config_1: + SinsemillaConfig, + sinsemilla_config_2: + SinsemillaConfig, commit_ivk_config: CommitIvkConfig, old_note_commit_config: NoteCommitConfig, new_note_commit_config: NoteCommitConfig, @@ -234,7 +235,8 @@ impl plonk::Circuit for Circuit { // Configuration for curve point operations. // This uses 10 advice columns and spans the whole circuit. - let ecc_config = EccChip::configure(meta, advices, lagrange_coeffs, range_check); + let ecc_config = + EccChip::::configure(meta, advices, lagrange_coeffs, range_check); // Configuration for the Poseidon hash. let poseidon_config = PoseidonChip::configure::( @@ -397,7 +399,7 @@ impl plonk::Circuit for Circuit { let merkle_inputs = MerklePath { chip_1: config.merkle_chip_1(), chip_2: config.merkle_chip_2(), - domain: SinsemillaHashDomains::MerkleCrh, + domain: OrchardHashDomains::MerkleCrh, leaf_pos: self.pos, path, }; @@ -444,7 +446,7 @@ impl plonk::Circuit for Circuit { // commitment = [v_net] ValueCommitV let (commitment, _) = { - let value_commit_v = ValueCommitV::get(); + let value_commit_v = ValueCommitV; let value_commit_v = FixedPointShort::from_inner(ecc_chip.clone(), value_commit_v); value_commit_v.mul(layouter.namespace(|| "[v_net] ValueCommitV"), v_net.clone())? }; diff --git a/src/circuit/commit_ivk.rs b/src/circuit/commit_ivk.rs index 530f5d24..ddb71cff 100644 --- a/src/circuit/commit_ivk.rs +++ b/src/circuit/commit_ivk.rs @@ -9,26 +9,31 @@ use crate::{ circuit::gadget::{ ecc::{chip::EccChip, X}, sinsemilla::{ - chip::{SinsemillaChip, SinsemillaCommitDomains, SinsemillaConfig}, + chip::{SinsemillaChip, SinsemillaConfig}, CommitDomain, Message, MessagePiece, }, utilities::{bitrange_subset, bool_check}, }, - constants::T_P, + constants::{OrchardCommitDomains, OrchardFixedBases, OrchardHashDomains, T_P}, }; #[derive(Clone, Debug)] pub struct CommitIvkConfig { q_commit_ivk: Selector, advices: [Column; 10], - sinsemilla_config: SinsemillaConfig, + sinsemilla_config: + SinsemillaConfig, } impl CommitIvkConfig { pub(in crate::circuit) fn configure( meta: &mut ConstraintSystem, advices: [Column; 10], - sinsemilla_config: SinsemillaConfig, + sinsemilla_config: SinsemillaConfig< + OrchardHashDomains, + OrchardCommitDomains, + OrchardFixedBases, + >, ) -> Self { let q_commit_ivk = meta.selector(); @@ -221,13 +226,17 @@ impl CommitIvkConfig { #[allow(clippy::type_complexity)] pub(in crate::circuit) fn assign_region( &self, - sinsemilla_chip: SinsemillaChip, - ecc_chip: EccChip, + sinsemilla_chip: SinsemillaChip< + OrchardHashDomains, + OrchardCommitDomains, + OrchardFixedBases, + >, + ecc_chip: EccChip, mut layouter: impl Layouter, ak: AssignedCell, nk: AssignedCell, rivk: Option, - ) -> Result, Error> { + ) -> Result>, Error> { // // We need to hash `ak || nk` where each of `ak`, `nk` is a field element (255 bits). // @@ -328,11 +337,8 @@ impl CommitIvkConfig { sinsemilla_chip.clone(), vec![a.clone(), b.clone(), c.clone(), d.clone()], ); - let domain = CommitDomain::new( - sinsemilla_chip, - ecc_chip, - &SinsemillaCommitDomains::CommitIvk, - ); + let domain = + CommitDomain::new(sinsemilla_chip, ecc_chip, &OrchardCommitDomains::CommitIvk); domain.short_commit(layouter.namespace(|| "Hash ak||nk"), message, rivk)? }; @@ -635,7 +641,10 @@ mod tests { sinsemilla::chip::SinsemillaChip, utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions}, }, - constants::{COMMIT_IVK_PERSONALIZATION, L_ORCHARD_BASE, T_Q}, + constants::{ + OrchardCommitDomains, OrchardFixedBases, OrchardHashDomains, + COMMIT_IVK_PERSONALIZATION, L_ORCHARD_BASE, T_Q, + }, primitives::sinsemilla::CommitDomain, }; use group::ff::{Field, PrimeFieldBits}; @@ -662,7 +671,7 @@ mod tests { } impl Circuit for MyCircuit { - type Config = (CommitIvkConfig, EccConfig); + type Config = (CommitIvkConfig, EccConfig); type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { @@ -708,7 +717,11 @@ mod tests { ]; let range_check = LookupRangeCheckConfig::configure(meta, advices[9], table_idx); - let sinsemilla_config = SinsemillaChip::configure( + let sinsemilla_config = SinsemillaChip::< + OrchardHashDomains, + OrchardCommitDomains, + OrchardFixedBases, + >::configure( meta, advices[..5].try_into().unwrap(), advices[2], @@ -720,7 +733,12 @@ mod tests { let commit_ivk_config = CommitIvkConfig::configure(meta, advices, sinsemilla_config); - let ecc_config = EccChip::configure(meta, advices, lagrange_coeffs, range_check); + let ecc_config = EccChip::::configure( + meta, + advices, + lagrange_coeffs, + range_check, + ); (commit_ivk_config, ecc_config) } @@ -733,7 +751,7 @@ mod tests { let (commit_ivk_config, ecc_config) = config; // Load the Sinsemilla generator lookup table used by the whole circuit. - SinsemillaChip::load(commit_ivk_config.sinsemilla_config.clone(), &mut layouter)?; + SinsemillaChip::::load(commit_ivk_config.sinsemilla_config.clone(), &mut layouter)?; // Construct a Sinsemilla chip let sinsemilla_chip = diff --git a/src/circuit/gadget.rs b/src/circuit/gadget.rs index 4bf51c93..a1373c78 100644 --- a/src/circuit/gadget.rs +++ b/src/circuit/gadget.rs @@ -2,6 +2,7 @@ use pasta_curves::pallas; +use crate::constants::{OrchardCommitDomains, OrchardFixedBases, OrchardHashDomains}; use ecc::chip::EccChip; use poseidon::Pow5Chip as PoseidonChip; use sinsemilla::{chip::SinsemillaChip, merkle::chip::MerkleChip}; @@ -12,23 +13,31 @@ pub(crate) mod sinsemilla; pub mod utilities; impl super::Config { - pub(super) fn ecc_chip(&self) -> EccChip { + pub(super) fn ecc_chip(&self) -> EccChip { EccChip::construct(self.ecc_config.clone()) } - pub(super) fn sinsemilla_chip_1(&self) -> SinsemillaChip { + pub(super) fn sinsemilla_chip_1( + &self, + ) -> SinsemillaChip { SinsemillaChip::construct(self.sinsemilla_config_1.clone()) } - pub(super) fn sinsemilla_chip_2(&self) -> SinsemillaChip { + pub(super) fn sinsemilla_chip_2( + &self, + ) -> SinsemillaChip { SinsemillaChip::construct(self.sinsemilla_config_2.clone()) } - pub(super) fn merkle_chip_1(&self) -> MerkleChip { + pub(super) fn merkle_chip_1( + &self, + ) -> MerkleChip { MerkleChip::construct(self.merkle_config_1.clone()) } - pub(super) fn merkle_chip_2(&self) -> MerkleChip { + pub(super) fn merkle_chip_2( + &self, + ) -> MerkleChip { MerkleChip::construct(self.merkle_config_2.clone()) } diff --git a/src/circuit/gadget/ecc.rs b/src/circuit/gadget/ecc.rs index e8aaeefd..810ca50a 100644 --- a/src/circuit/gadget/ecc.rs +++ b/src/circuit/gadget/ecc.rs @@ -13,7 +13,9 @@ use crate::circuit::gadget::utilities::UtilitiesInstructions; pub mod chip; /// The set of circuit instructions required to use the ECC gadgets. -pub trait EccInstructions: Chip + UtilitiesInstructions { +pub trait EccInstructions: + Chip + UtilitiesInstructions + Clone + Debug + Eq +{ /// Variable representing an element of the elliptic curve's base field, that /// is used as a scalar in variable-base scalar mul. /// @@ -41,12 +43,11 @@ 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 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; + /// Enumeration of the set of fixed bases to be used in scalar mul. + /// TODO: When associated consts can be used as const generics, introduce + /// `Self::NUM_WINDOWS`, `Self::NUM_WINDOWS_BASE_FIELD`, `Self::NUM_WINDOWS_SHORT` + /// and use them to differentiate `FixedPoints` types. + type FixedPoints: FixedPoints; /// Constrains point `a` to be equal in value to point `b`. fn constrain_equal( @@ -107,7 +108,7 @@ pub trait EccInstructions: Chip + UtilitiesInstructions &self, layouter: &mut impl Layouter, scalar: Option, - base: &Self::FixedPoints, + base: &>::FullScalar, ) -> Result<(Self::Point, Self::ScalarFixed), Error>; /// Performs fixed-base scalar multiplication using a short signed scalar, returning @@ -116,7 +117,7 @@ pub trait EccInstructions: Chip + UtilitiesInstructions &self, layouter: &mut impl Layouter, magnitude_sign: (Self::Var, Self::Var), - base: &Self::FixedPointsShort, + base: &>::ShortScalar, ) -> Result<(Self::Point, Self::ScalarFixedShort), Error>; /// Performs fixed-base scalar multiplication using a base field element as the scalar. @@ -126,10 +127,17 @@ pub trait EccInstructions: Chip + UtilitiesInstructions &self, layouter: &mut impl Layouter, base_field_elem: Self::Var, - base: &Self::FixedPointsBaseField, + base: &>::Base, ) -> Result; } +/// Defines the fixed points for a given instantiation of the ECC chip. +pub trait FixedPoints: Debug + Eq + Clone { + type FullScalar: Debug + Eq + Clone; + type ShortScalar: Debug + Eq + Clone; + type Base: Debug + Eq + Clone; +} + /// An element of the given elliptic curve's base field, that is used as a scalar /// in variable-base scalar mul. /// @@ -142,41 +150,33 @@ pub trait EccInstructions: Chip + UtilitiesInstructions /// to be in the base field of the curve. (See non-normative notes in /// https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents.) #[derive(Debug)] -pub struct ScalarVar + Clone + Debug + Eq> { +pub struct ScalarVar> { chip: EccChip, inner: EccChip::ScalarVar, } /// A full-width element of the given elliptic curve's scalar field, to be used for fixed-base scalar mul. #[derive(Debug)] -pub struct ScalarFixed -where - EccChip: EccInstructions + Clone + Debug + Eq, -{ +pub struct ScalarFixed> { chip: EccChip, inner: EccChip::ScalarFixed, } /// A signed short element of the given elliptic curve's scalar field, to be used for fixed-base scalar mul. #[derive(Debug)] -pub struct ScalarFixedShort -where - EccChip: EccInstructions + Clone + Debug + Eq, -{ +pub struct ScalarFixedShort> { chip: EccChip, inner: EccChip::ScalarFixedShort, } /// A non-identity elliptic curve point over the given curve. #[derive(Copy, Clone, Debug)] -pub struct NonIdentityPoint + Clone + Debug + Eq> { +pub struct NonIdentityPoint> { chip: EccChip, inner: EccChip::NonIdentityPoint, } -impl + Clone + Debug + Eq> - NonIdentityPoint -{ +impl> NonIdentityPoint { /// Constructs a new point with the given value. pub fn new( chip: EccChip, @@ -351,12 +351,12 @@ impl + Clone + Debug + Eq> Point + Clone + Debug + Eq> { +pub struct X> { chip: EccChip, inner: EccChip::X, } -impl + Clone + Debug + Eq> X { +impl> X { /// Wraps the given x-coordinate (obtained directly from an instruction) in a gadget. pub fn from_inner(chip: EccChip, inner: EccChip::X) -> Self { X { chip, inner } @@ -373,18 +373,34 @@ impl + Clone + Debug + Eq> X +pub struct FixedPoint> { + chip: EccChip, + inner: >::FullScalar, +} + +/// 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::FixedPoints, + inner: >::Base, } -impl FixedPoint +/// A constant elliptic curve point over the given curve, used in scalar multiplication +/// with a short signed exponent +#[derive(Clone, Debug)] +pub struct FixedPointShort where EccChip: EccInstructions + Clone + Debug + Eq, { + chip: EccChip, + inner: >::ShortScalar, +} + +impl> FixedPoint { #[allow(clippy::type_complexity)] /// Returns `[by] self`. pub fn mul( @@ -409,26 +425,15 @@ 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: >::FullScalar, + ) -> Self { + Self { 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, -{ +impl> FixedPointBaseField { #[allow(clippy::type_complexity)] /// Returns `[by] self`. pub fn mul( @@ -445,26 +450,15 @@ where } /// Wraps the given fixed base (obtained directly from an instruction) in a gadget. - pub fn from_inner(chip: EccChip, inner: EccChip::FixedPointsBaseField) -> Self { - FixedPointBaseField { chip, inner } + pub fn from_inner( + chip: EccChip, + inner: >::Base, + ) -> Self { + Self { chip, inner } } } -/// A constant elliptic curve point over the given curve, used in scalar multiplication -/// with a short signed exponent -#[derive(Clone, Debug)] -pub struct FixedPointShort -where - EccChip: EccInstructions + Clone + Debug + Eq, -{ - chip: EccChip, - inner: EccChip::FixedPointsShort, -} - -impl FixedPointShort -where - EccChip: EccInstructions + Clone + Debug + Eq, -{ +impl> FixedPointShort { #[allow(clippy::type_complexity)] /// Returns `[by] self`. pub fn mul( @@ -489,8 +483,11 @@ where } /// Wraps the given fixed base (obtained directly from an instruction) in a gadget. - pub fn from_inner(chip: EccChip, inner: EccChip::FixedPointsShort) -> Self { - FixedPointShort { chip, inner } + pub fn from_inner( + chip: EccChip, + inner: >::ShortScalar, + ) -> Self { + Self { chip, inner } } } @@ -507,6 +504,7 @@ mod tests { use super::chip::{EccChip, EccConfig}; use crate::circuit::gadget::utilities::lookup_range_check::LookupRangeCheckConfig; + use crate::constants::OrchardFixedBases; struct MyCircuit { test_errors: bool, @@ -514,7 +512,7 @@ mod tests { #[allow(non_snake_case)] impl Circuit for MyCircuit { - type Config = EccConfig; + type Config = EccConfig; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { @@ -550,7 +548,7 @@ mod tests { meta.enable_constant(constants); let range_check = LookupRangeCheckConfig::configure(meta, advices[9], lookup_table); - EccChip::configure(meta, advices, lagrange_coeffs, range_check) + EccChip::::configure(meta, advices, lagrange_coeffs, range_check) } fn synthesize( diff --git a/src/circuit/gadget/ecc/chip.rs b/src/circuit/gadget/ecc/chip.rs index c911e224..ef0cc008 100644 --- a/src/circuit/gadget/ecc/chip.rs +++ b/src/circuit/gadget/ecc/chip.rs @@ -1,9 +1,9 @@ -use super::EccInstructions; +use super::{EccInstructions, FixedPoints}; use crate::{ circuit::gadget::utilities::{ lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions, }, - constants::{self, NullifierK, OrchardFixedBasesFull, ValueCommitV}, + constants, primitives::sinsemilla, }; use arrayvec::ArrayVec; @@ -131,7 +131,7 @@ impl From for EccPoint { /// Configuration for the ECC chip #[derive(Clone, Debug, Eq, PartialEq)] #[allow(non_snake_case)] -pub struct EccConfig { +pub struct EccConfig> { /// Advice columns needed by instructions in the ECC chip. pub advices: [Column; 10], @@ -145,11 +145,11 @@ pub struct EccConfig { mul: mul::Config, /// Fixed-base full-width scalar multiplication - mul_fixed_full: mul_fixed::full_width::Config, + mul_fixed_full: mul_fixed::full_width::Config, /// Fixed-base signed short scalar multiplication - mul_fixed_short: mul_fixed::short::Config, + mul_fixed_short: mul_fixed::short::Config, /// Fixed-base mul using a base field element as a scalar - mul_fixed_base_field: mul_fixed::base_field_elem::Config, + mul_fixed_base_field: mul_fixed::base_field_elem::Config, /// Witness point witness_point: witness_point::Config, @@ -158,14 +158,26 @@ pub struct EccConfig { pub lookup_config: LookupRangeCheckConfig, } -/// A chip implementing EccInstructions -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct EccChip { - config: EccConfig, +/// Returns information about a fixed point. +/// +/// TODO: When associated consts can be used as const generics, introduce a +/// `const NUM_WINDOWS: usize` associated const, and return `NUM_WINDOWS`-sized +/// arrays instead of `Vec`s. +pub trait FixedPoint: std::fmt::Debug + Eq + Clone { + fn generator(&self) -> C; + fn u(&self) -> Vec<[[u8; 32]; constants::H]>; + fn z(&self) -> Vec; + fn lagrange_coeffs(&self) -> Vec<[C::Base; constants::H]>; } -impl Chip for EccChip { - type Config = EccConfig; +/// A chip implementing EccInstructions +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct EccChip> { + config: EccConfig, +} + +impl> Chip for EccChip { + type Config = EccConfig; type Loaded = (); fn config(&self) -> &Self::Config { @@ -177,11 +189,13 @@ impl Chip for EccChip { } } -impl UtilitiesInstructions for EccChip { +impl> UtilitiesInstructions + for EccChip +{ type Var = AssignedCell; } -impl EccChip { +impl> EccChip { pub fn construct(config: >::Config) -> Self { Self { config } } @@ -213,7 +227,7 @@ impl EccChip { // Create config that is shared across short, base-field, and full-width // fixed-base scalar mul. - let mul_fixed = mul_fixed::Config::configure( + let mul_fixed = mul_fixed::Config::::configure( meta, lagrange_coeffs, advices[4], @@ -225,13 +239,15 @@ impl EccChip { ); // Create gate that is only used in full-width fixed-base scalar mul. - let mul_fixed_full = mul_fixed::full_width::Config::configure(meta, mul_fixed); + let mul_fixed_full = + mul_fixed::full_width::Config::::configure(meta, mul_fixed.clone()); // Create gate that is only used in short fixed-base scalar mul. - let mul_fixed_short = mul_fixed::short::Config::configure(meta, mul_fixed); + let mul_fixed_short = + mul_fixed::short::Config::::configure(meta, mul_fixed.clone()); // Create gate that is only used in fixed-base mul using a base field element. - let mul_fixed_base_field = mul_fixed::base_field_elem::Config::configure( + let mul_fixed_base_field = mul_fixed::base_field_elem::Config::::configure( meta, advices[6..9].try_into().unwrap(), range_check, @@ -310,16 +326,19 @@ impl EccBaseFieldElemFixed { } } -impl EccInstructions for EccChip { +impl> EccInstructions for EccChip +where + >::Base: FixedPoint, + >::FullScalar: FixedPoint, + >::ShortScalar: FixedPoint, +{ type ScalarFixed = EccScalarFixed; type ScalarFixedShort = EccScalarFixedShort; type ScalarVar = AssignedCell; type Point = EccPoint; type NonIdentityPoint = NonIdentityEccPoint; type X = AssignedCell; - type FixedPoints = OrchardFixedBasesFull; - type FixedPointsBaseField = NullifierK; - type FixedPointsShort = ValueCommitV; + type FixedPoints = Fixed; fn constrain_equal( &self, @@ -413,13 +432,13 @@ impl EccInstructions for EccChip { &self, layouter: &mut impl Layouter, scalar: Option, - base: &Self::FixedPoints, + base: &>::FullScalar, ) -> Result<(Self::Point, Self::ScalarFixed), Error> { - let config = self.config().mul_fixed_full; + let config = self.config().mul_fixed_full.clone(); config.assign( layouter.namespace(|| format!("fixed-base mul of {:?}", base)), scalar, - *base, + base, ) } @@ -427,9 +446,9 @@ impl EccInstructions for EccChip { &self, layouter: &mut impl Layouter, magnitude_sign: MagnitudeSign, - base: &Self::FixedPointsShort, + base: &>::ShortScalar, ) -> Result<(Self::Point, Self::ScalarFixedShort), Error> { - let config: mul_fixed::short::Config = self.config().mul_fixed_short; + let config = self.config().mul_fixed_short.clone(); config.assign( layouter.namespace(|| format!("short fixed-base mul of {:?}", base)), magnitude_sign, @@ -441,13 +460,13 @@ impl EccInstructions for EccChip { &self, layouter: &mut impl Layouter, base_field_elem: AssignedCell, - base: &Self::FixedPointsBaseField, + base: &>::Base, ) -> Result { - let config = self.config().mul_fixed_base_field; + let config = self.config().mul_fixed_base_field.clone(); config.assign( layouter.namespace(|| format!("base-field elem fixed-base mul of {:?}", base)), base_field_elem, - *base, + base, ) } } diff --git a/src/circuit/gadget/ecc/chip/mul.rs b/src/circuit/gadget/ecc/chip/mul.rs index 32a200fc..d4b5f0c2 100644 --- a/src/circuit/gadget/ecc/chip/mul.rs +++ b/src/circuit/gadget/ecc/chip/mul.rs @@ -481,11 +481,12 @@ pub mod tests { }, utilities::UtilitiesInstructions, }; + use crate::constants::OrchardFixedBases; pub fn test_mul( - chip: EccChip, + chip: EccChip, mut layouter: impl Layouter, - p: &NonIdentityPoint, + p: &NonIdentityPoint>, p_val: pallas::Affine, ) -> Result<(), Error> { let column = chip.config().advices[0]; diff --git a/src/circuit/gadget/ecc/chip/mul_fixed.rs b/src/circuit/gadget/ecc/chip/mul_fixed.rs index e5542fa9..5139ffb8 100644 --- a/src/circuit/gadget/ecc/chip/mul_fixed.rs +++ b/src/circuit/gadget/ecc/chip/mul_fixed.rs @@ -1,12 +1,11 @@ use super::{ - add, add_incomplete, EccBaseFieldElemFixed, EccScalarFixed, EccScalarFixedShort, + add, add_incomplete, EccBaseFieldElemFixed, EccScalarFixed, EccScalarFixedShort, FixedPoint, NonIdentityEccPoint, }; use crate::circuit::gadget::utilities::decompose_running_sum::RunningSumConfig; -use crate::constants::{ - self, - load::{NullifierK, OrchardFixedBase, OrchardFixedBasesFull, ValueCommitV, WindowUs}, -}; +use crate::constants; + +use std::marker::PhantomData; use group::{ff::PrimeField, Curve}; use halo2::{ @@ -31,53 +30,8 @@ lazy_static! { static ref H_BASE: pallas::Base = pallas::Base::from(constants::H as u64); } -// A sum type for both full-width and short bases. This enables us to use the -// shared functionality of full-width and short fixed-base scalar multiplication. -#[derive(Copy, Clone, Debug)] -enum OrchardFixedBases { - Full(OrchardFixedBasesFull), - NullifierK, - ValueCommitV, -} - -impl From for OrchardFixedBases { - fn from(full_width_base: OrchardFixedBasesFull) -> Self { - Self::Full(full_width_base) - } -} - -impl From for OrchardFixedBases { - fn from(_value_commit_v: ValueCommitV) -> Self { - Self::ValueCommitV - } -} - -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(), - } - } - - 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(), - } - } -} - #[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct Config { +pub struct Config> { running_sum_config: RunningSumConfig, // The fixed Lagrange interpolation coefficients for `x_p`. lagrange_coeffs: [Column; constants::H], @@ -96,9 +50,10 @@ pub struct Config { add_config: add::Config, // Configuration for `add_incomplete` add_incomplete_config: add_incomplete::Config, + _marker: PhantomData, } -impl Config { +impl> Config { #[allow(clippy::too_many_arguments)] pub(super) fn configure( meta: &mut ConstraintSystem, @@ -126,6 +81,7 @@ impl Config { u, add_config, add_incomplete_config, + _marker: PhantomData, }; // Check relationships between this config and `add_config`. @@ -231,64 +187,41 @@ impl Config { } #[allow(clippy::type_complexity)] - fn assign_region_inner( + fn assign_region_inner, const NUM_WINDOWS: usize>( &self, region: &mut Region<'_, pallas::Base>, offset: usize, scalar: &ScalarFixed, - base: OrchardFixedBases, + base: &F, coords_check_toggle: Selector, ) -> Result<(NonIdentityEccPoint, NonIdentityEccPoint), Error> { // Assign fixed columns for given fixed base - self.assign_fixed_constants::(region, offset, base, coords_check_toggle)?; + self.assign_fixed_constants::(region, offset, base, coords_check_toggle)?; // Initialize accumulator - let acc = self.initialize_accumulator(region, offset, base, scalar)?; + let acc = self.initialize_accumulator::(region, offset, base, scalar)?; // Process all windows excluding least and most significant windows - let acc = self.add_incomplete(region, offset, acc, base, scalar)?; + let acc = self.add_incomplete::(region, offset, acc, base, scalar)?; // Process most significant window using complete addition - let mul_b = self.process_msb::(region, offset, base, scalar)?; + let mul_b = self.process_msb::(region, offset, base, scalar)?; Ok((acc, mul_b)) } - fn assign_fixed_constants( + fn assign_fixed_constants, const NUM_WINDOWS: usize>( &self, region: &mut Region<'_, pallas::Base>, offset: usize, - base: OrchardFixedBases, + base: &F, coords_check_toggle: Selector, ) -> Result<(), Error> { - let mut constants = None; + let lagrange_coeffs = base.lagrange_coeffs(); + assert_eq!(lagrange_coeffs.len(), NUM_WINDOWS); - let build_constants = || match base { - OrchardFixedBases::ValueCommitV => { - assert_eq!(NUM_WINDOWS, constants::NUM_WINDOWS_SHORT); - let base = ValueCommitV::get(); - ( - base.lagrange_coeffs_short.0.as_ref().to_vec(), - base.z_short.0.as_ref().to_vec(), - ) - } - OrchardFixedBases::Full(base) => { - assert_eq!(NUM_WINDOWS, constants::NUM_WINDOWS); - let base: OrchardFixedBase = base.into(); - ( - base.lagrange_coeffs.0.as_ref().to_vec(), - 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(), - ) - } - }; + let z = base.z(); + assert_eq!(z.len(), NUM_WINDOWS); // Assign fixed columns for given fixed base for window in 0..NUM_WINDOWS { @@ -305,13 +238,7 @@ impl Config { }, self.lagrange_coeffs[k], window + offset, - || { - if constants.as_ref().is_none() { - constants = Some(build_constants()); - } - let lagrange_coeffs = &constants.as_ref().unwrap().0; - Ok(lagrange_coeffs[window].0[k]) - }, + || Ok(lagrange_coeffs[window][k]), )?; } @@ -320,27 +247,25 @@ impl Config { || format!("z-value for window: {:?}", window), self.fixed_z, window + offset, - || { - let z = &constants.as_ref().unwrap().1; - Ok(z[window]) - }, + || Ok(pallas::Base::from_u64(z[window])), )?; } Ok(()) } - fn process_window( + fn process_window, const NUM_WINDOWS: usize>( &self, region: &mut Region<'_, pallas::Base>, offset: usize, w: usize, k: Option, k_usize: Option, - base: OrchardFixedBases, + base: &F, ) -> Result { let base_value = base.generator(); let base_u = base.u(); + assert_eq!(base_u.len(), NUM_WINDOWS); // Compute [(k_w + 2) ⋅ 8^w]B let mul_b = { @@ -376,17 +301,17 @@ impl Config { }; // Assign u = (y_p + z_w).sqrt() - let u_val = k_usize.map(|k| base_u[w].0[k]); + let u_val = k_usize.map(|k| pallas::Base::from_bytes(&base_u[w][k]).unwrap()); region.assign_advice(|| "u", self.u, offset + w, || u_val.ok_or(Error::Synthesis))?; Ok(mul_b) } - fn initialize_accumulator( + fn initialize_accumulator, const NUM_WINDOWS: usize>( &self, region: &mut Region<'_, pallas::Base>, offset: usize, - base: OrchardFixedBases, + base: &F, scalar: &ScalarFixed, ) -> Result { // Recall that the message at each window `w` is represented as @@ -395,15 +320,15 @@ impl Config { let w = 0; let k0 = scalar.windows_field()[0]; let k0_usize = scalar.windows_usize()[0]; - self.process_window(region, offset, w, k0, k0_usize, base) + self.process_window::<_, NUM_WINDOWS>(region, offset, w, k0, k0_usize, base) } - fn add_incomplete( + fn add_incomplete, const NUM_WINDOWS: usize>( &self, region: &mut Region<'_, pallas::Base>, offset: usize, mut acc: NonIdentityEccPoint, - base: OrchardFixedBases, + base: &F, scalar: &ScalarFixed, ) -> Result { let scalar_windows_field = scalar.windows_field(); @@ -417,7 +342,8 @@ impl Config { .skip(1) { // Compute [(k_w + 2) ⋅ 8^w]B - let mul_b = self.process_window(region, offset, w, *k, *k_usize, base)?; + let mul_b = + self.process_window::<_, NUM_WINDOWS>(region, offset, w, *k, *k_usize, base)?; // Add to the accumulator acc = self @@ -427,17 +353,17 @@ impl Config { Ok(acc) } - fn process_msb( + fn process_msb, const NUM_WINDOWS: usize>( &self, region: &mut Region<'_, pallas::Base>, offset: usize, - base: OrchardFixedBases, + base: &F, scalar: &ScalarFixed, ) -> Result { // Assign u = (y_p + z_w).sqrt() for the most significant window { - let u_val = - scalar.windows_usize()[NUM_WINDOWS - 1].map(|k| base.u()[NUM_WINDOWS - 1].0[k]); + let u_val = scalar.windows_usize()[NUM_WINDOWS - 1] + .map(|k| pallas::Base::from_bytes(&base.u()[NUM_WINDOWS - 1][k]).unwrap()); region.assign_advice( || "u", self.u, 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 885683df..32ec8449 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, EccPoint, NullifierK}; +use super::super::{EccBaseFieldElemFixed, EccPoint, FixedPoints}; use super::H_BASE; use crate::{ @@ -19,19 +19,19 @@ use pasta_curves::{arithmetic::FieldExt, pallas}; use std::convert::TryInto; #[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Config { +pub struct Config> { q_mul_fixed_base_field: Selector, canon_advices: [Column; 3], lookup_config: LookupRangeCheckConfig, - super_config: super::Config, + super_config: super::Config, } -impl Config { +impl> Config { pub(crate) fn configure( meta: &mut ConstraintSystem, canon_advices: [Column; 3], lookup_config: LookupRangeCheckConfig, - super_config: super::Config, + super_config: super::Config, ) -> Self { for advice in canon_advices.iter() { meta.enable_equality(*advice); @@ -161,8 +161,11 @@ impl Config { &self, mut layouter: impl Layouter, scalar: AssignedCell, - base: NullifierK, - ) -> Result { + base: &>::Base, + ) -> Result + where + >::Base: super::super::FixedPoint, + { let (scalar, acc, mul_b) = layouter.assign_region( || "Base-field elem fixed-base mul (incomplete addition)", |mut region| { @@ -186,11 +189,11 @@ impl Config { let (acc, mul_b) = self .super_config - .assign_region_inner::<{ constants::NUM_WINDOWS }>( + .assign_region_inner::<_, { constants::NUM_WINDOWS }>( &mut region, offset, &(&scalar).into(), - base.into(), + base, self.super_config.running_sum_config.q_range_check, )?; @@ -214,9 +217,9 @@ impl Config { #[cfg(test)] // Check that the correct multiple is obtained. { + use super::super::FixedPoint; use group::{ff::PrimeField, Curve}; - let base: super::OrchardFixedBases = base.into(); let scalar = &scalar .base_field_elem() .value() @@ -387,32 +390,31 @@ pub mod tests { use crate::circuit::gadget::{ ecc::{ - chip::{EccChip, NullifierK}, + chip::{EccChip, FixedPoint}, FixedPointBaseField, NonIdentityPoint, Point, }, utilities::UtilitiesInstructions, }; - use crate::constants; + use crate::constants::{self, NullifierK, OrchardFixedBases}; pub fn test_mul_fixed_base_field( - chip: EccChip, + chip: EccChip, mut layouter: impl Layouter, ) -> Result<(), Error> { // nullifier_k - let nullifier_k = NullifierK; test_single_base( chip.clone(), layouter.namespace(|| "nullifier_k"), - FixedPointBaseField::from_inner(chip, nullifier_k), - nullifier_k.generator(), + FixedPointBaseField::from_inner(chip, NullifierK), + NullifierK.generator(), ) } #[allow(clippy::op_ref)] fn test_single_base( - chip: EccChip, + chip: EccChip, mut layouter: impl Layouter, - base: FixedPointBaseField, + base: FixedPointBaseField>, base_val: pallas::Affine, ) -> Result<(), Error> { let rng = OsRng; @@ -420,11 +422,11 @@ pub mod tests { let column = chip.config().advices[0]; fn constrain_equal_non_id( - chip: EccChip, + chip: EccChip, mut layouter: impl Layouter, base_val: pallas::Affine, scalar_val: pallas::Base, - result: Point, + result: Point>, ) -> Result<(), Error> { // Move scalar from base field into scalar field (which always fits for Pallas). let scalar = pallas::Scalar::from_repr(scalar_val.to_repr()).unwrap(); 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 8426194c..19521a9e 100644 --- a/src/circuit/gadget/ecc/chip/mul_fixed/full_width.rs +++ b/src/circuit/gadget/ecc/chip/mul_fixed/full_width.rs @@ -1,4 +1,4 @@ -use super::super::{EccPoint, EccScalarFixed, OrchardFixedBasesFull}; +use super::super::{EccPoint, EccScalarFixed, FixedPoints}; use crate::{ circuit::gadget::utilities::range_check, @@ -13,15 +13,15 @@ use halo2::{ use pasta_curves::pallas; #[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct Config { +pub struct Config> { q_mul_fixed_full: Selector, - super_config: super::Config, + super_config: super::Config, } -impl Config { +impl> Config { pub(crate) fn configure( meta: &mut ConstraintSystem, - super_config: super::Config, + super_config: super::Config, ) -> Self { let config = Self { q_mul_fixed_full: meta.selector(), @@ -122,8 +122,12 @@ impl Config { &self, mut layouter: impl Layouter, scalar: Option, - base: OrchardFixedBasesFull, - ) -> Result<(EccPoint, EccScalarFixed), Error> { + base: &>::FullScalar, + ) -> Result<(EccPoint, EccScalarFixed), Error> + where + >::FullScalar: + super::super::FixedPoint, + { let (scalar, acc, mul_b) = layouter.assign_region( || "Full-width fixed-base mul (incomplete addition)", |mut region| { @@ -133,11 +137,11 @@ impl Config { let (acc, mul_b) = self .super_config - .assign_region_inner::<{ constants::NUM_WINDOWS }>( + .assign_region_inner::<_, { constants::NUM_WINDOWS }>( &mut region, offset, &(&scalar).into(), - base.into(), + base, self.q_mul_fixed_full, )?; @@ -161,9 +165,9 @@ impl Config { #[cfg(test)] // Check that the correct multiple is obtained. { + use super::super::FixedPoint; use group::Curve; - let base: super::OrchardFixedBases = base.into(); let real_mul = scalar.value.map(|scalar| base.generator() * scalar); let result = result.point(); @@ -184,13 +188,13 @@ pub mod tests { use rand::rngs::OsRng; use crate::circuit::gadget::ecc::{ - chip::{EccChip, OrchardFixedBasesFull}, + chip::{EccChip, FixedPoint as FixedPointTrait}, FixedPoint, NonIdentityPoint, Point, }; - use crate::constants; + use crate::constants::{self, OrchardFixedBases, OrchardFixedBasesFull}; pub fn test_mul_fixed( - chip: EccChip, + chip: EccChip, mut layouter: impl Layouter, ) -> Result<(), Error> { // commit_ivk_r @@ -234,17 +238,17 @@ pub mod tests { #[allow(clippy::op_ref)] fn test_single_base( - chip: EccChip, + chip: EccChip, mut layouter: impl Layouter, - base: FixedPoint, + base: FixedPoint>, base_val: pallas::Affine, ) -> Result<(), Error> { fn constrain_equal_non_id( - chip: EccChip, + chip: EccChip, mut layouter: impl Layouter, base_val: pallas::Affine, scalar_val: pallas::Scalar, - result: Point, + result: Point>, ) -> Result<(), Error> { let expected = NonIdentityPoint::new( chip, diff --git a/src/circuit/gadget/ecc/chip/mul_fixed/short.rs b/src/circuit/gadget/ecc/chip/mul_fixed/short.rs index 25f2af3c..e978437d 100644 --- a/src/circuit/gadget/ecc/chip/mul_fixed/short.rs +++ b/src/circuit/gadget/ecc/chip/mul_fixed/short.rs @@ -1,9 +1,9 @@ use std::{array, convert::TryInto}; -use super::super::{EccPoint, EccScalarFixedShort}; +use super::super::{EccPoint, EccScalarFixedShort, FixedPoints}; use crate::{ circuit::gadget::{ecc::chip::MagnitudeSign, utilities::bool_check}, - constants::{ValueCommitV, L_VALUE, NUM_WINDOWS_SHORT}, + constants::{L_VALUE, NUM_WINDOWS_SHORT}, }; use halo2::{ @@ -14,16 +14,16 @@ use halo2::{ use pasta_curves::pallas; #[derive(Clone, Debug, Copy, Eq, PartialEq)] -pub struct Config { +pub struct Config> { // Selector used for fixed-base scalar mul with short signed exponent. q_mul_fixed_short: Selector, - super_config: super::Config, + super_config: super::Config, } -impl Config { +impl> Config { pub(crate) fn configure( meta: &mut ConstraintSystem, - super_config: super::Config, + super_config: super::Config, ) -> Self { let config = Self { q_mul_fixed_short: meta.selector(), @@ -99,8 +99,12 @@ impl Config { &self, mut layouter: impl Layouter, magnitude_sign: MagnitudeSign, - base: &ValueCommitV, - ) -> Result<(EccPoint, EccScalarFixedShort), Error> { + base: &>::ShortScalar, + ) -> Result<(EccPoint, EccScalarFixedShort), Error> + where + >::ShortScalar: + super::super::FixedPoint, + { let (scalar, acc, mul_b) = layouter.assign_region( || "Short fixed-base mul (incomplete addition)", |mut region| { @@ -109,13 +113,15 @@ impl Config { // Decompose the scalar let scalar = self.decompose(&mut region, offset, magnitude_sign.clone())?; - let (acc, mul_b) = self.super_config.assign_region_inner::( - &mut region, - offset, - &(&scalar).into(), - base.clone().into(), - self.super_config.running_sum_config.q_range_check, - )?; + let (acc, mul_b) = self + .super_config + .assign_region_inner::<_, NUM_WINDOWS_SHORT>( + &mut region, + offset, + &(&scalar).into(), + base, + self.super_config.running_sum_config.q_range_check, + )?; Ok((scalar, acc, mul_b)) }, @@ -187,14 +193,13 @@ impl Config { // Invalid values result in constraint failures which are // tested at the circuit-level. { + use super::super::FixedPoint; use group::{ff::PrimeField, Curve}; if let (Some(magnitude), Some(sign)) = (scalar.magnitude.value(), scalar.sign.value()) { let magnitude_is_valid = magnitude <= &pallas::Base::from(0xFFFF_FFFF_FFFF_FFFFu64); let sign_is_valid = sign * sign == pallas::Base::one(); if magnitude_is_valid && sign_is_valid { - let base: super::OrchardFixedBases = base.clone().into(); - let scalar = scalar.magnitude.value().zip(scalar.sign.value()).map( |(magnitude, sign)| { // Move magnitude from base field into scalar field (which always fits @@ -237,25 +242,24 @@ pub mod tests { use crate::circuit::gadget::{ ecc::{ - chip::{EccChip, MagnitudeSign}, + chip::{EccChip, FixedPoint, MagnitudeSign}, FixedPointShort, NonIdentityPoint, Point, }, utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions}, }; - use crate::constants::load::ValueCommitV; + use crate::constants::{OrchardFixedBases, ValueCommitV}; #[allow(clippy::op_ref)] pub fn test_mul_fixed_short( - chip: EccChip, + chip: EccChip, mut layouter: impl Layouter, ) -> Result<(), Error> { // value_commit_v - let value_commit_v = ValueCommitV::get(); - let base_val = value_commit_v.generator; - let value_commit_v = FixedPointShort::from_inner(chip.clone(), value_commit_v); + let base_val = ValueCommitV.generator(); + let value_commit_v = FixedPointShort::from_inner(chip.clone(), ValueCommitV); fn load_magnitude_sign( - chip: EccChip, + chip: EccChip, mut layouter: impl Layouter, magnitude: pallas::Base, sign: pallas::Base, @@ -269,11 +273,11 @@ pub mod tests { } fn constrain_equal_non_id( - chip: EccChip, + chip: EccChip, mut layouter: impl Layouter, base_val: pallas::Affine, scalar_val: pallas::Scalar, - result: Point, + result: Point>, ) -> Result<(), Error> { let expected = NonIdentityPoint::new( chip, @@ -370,7 +374,10 @@ pub mod tests { #[test] fn invalid_magnitude_sign() { - use crate::circuit::gadget::{ecc::chip::EccConfig, utilities::UtilitiesInstructions}; + use crate::circuit::gadget::{ + ecc::chip::{EccConfig, FixedPoint}, + utilities::UtilitiesInstructions, + }; use halo2::{ circuit::{Layouter, SimpleFloorPlanner}, dev::{FailureLocation, MockProver, VerifyFailure}, @@ -390,7 +397,7 @@ pub mod tests { } impl Circuit for MyCircuit { - type Config = EccConfig; + type Config = EccConfig; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { @@ -427,7 +434,7 @@ pub mod tests { meta.enable_constant(constants); let range_check = LookupRangeCheckConfig::configure(meta, advices[9], lookup_table); - EccChip::configure(meta, advices, lagrange_coeffs, range_check) + EccChip::::configure(meta, advices, lagrange_coeffs, range_check) } fn synthesize( @@ -449,7 +456,7 @@ pub mod tests { (magnitude, sign) }; - short_config.assign(layouter, magnitude_sign, &ValueCommitV::get())?; + short_config.assign(layouter, magnitude_sign, &ValueCommitV)?; Ok(()) } @@ -563,7 +570,7 @@ pub mod tests { }; let negation_check_y = { - *(ValueCommitV::get().generator * pallas::Scalar::from(magnitude_u64)) + *(ValueCommitV.generator() * pallas::Scalar::from(magnitude_u64)) .to_affine() .coordinates() .unwrap() diff --git a/src/circuit/gadget/sinsemilla.rs b/src/circuit/gadget/sinsemilla.rs index ba12e725..9ce3673f 100644 --- a/src/circuit/gadget/sinsemilla.rs +++ b/src/circuit/gadget/sinsemilla.rs @@ -1,6 +1,6 @@ //! Gadget and chips for the Sinsemilla hash function. use crate::circuit::gadget::{ - ecc::{self, EccInstructions}, + ecc::{self, EccInstructions, FixedPoints}, utilities::Var, }; use group::ff::{Field, PrimeField}; @@ -47,7 +47,7 @@ pub trait SinsemillaInstructions; /// HashDomains used in this instruction. type HashDomains: HashDomains; @@ -303,12 +303,12 @@ where } /// Trait allowing circuit's Sinsemilla CommitDomains to be enumerated. -pub trait CommitDomains>: +pub trait CommitDomains, H: HashDomains>: Clone + Debug { /// Returns the fixed point corresponding to the R constant used for /// randomization in this CommitDomain. - fn r(&self) -> F; + fn r(&self) -> F::FullScalar; /// Returns the HashDomain contained in this CommitDomain fn hash_domain(&self) -> H; @@ -357,6 +357,7 @@ where pub fn new( sinsemilla_chip: SinsemillaChip, ecc_chip: EccChip, + // Instead of using SinsemilllaChip::CommitDomains, just use something that implements a CommitDomains trait domain: &SinsemillaChip::CommitDomains, ) -> Self { CommitDomain { @@ -414,7 +415,7 @@ mod tests { use rand::rngs::OsRng; use super::{ - chip::{SinsemillaChip, SinsemillaCommitDomains, SinsemillaConfig, SinsemillaHashDomains}, + chip::{SinsemillaChip, SinsemillaConfig}, CommitDomain, HashDomain, Message, MessagePiece, }; @@ -426,7 +427,10 @@ mod tests { }, utilities::lookup_range_check::LookupRangeCheckConfig, }, - constants::{COMMIT_IVK_PERSONALIZATION, MERKLE_CRH_PERSONALIZATION}, + constants::{ + OrchardCommitDomains, OrchardFixedBases, OrchardHashDomains, + COMMIT_IVK_PERSONALIZATION, MERKLE_CRH_PERSONALIZATION, + }, primitives::sinsemilla::{self, K}, }; @@ -438,7 +442,12 @@ mod tests { struct MyCircuit {} impl Circuit for MyCircuit { - type Config = (EccConfig, SinsemillaConfig, SinsemillaConfig); + #[allow(clippy::type_complexity)] + type Config = ( + EccConfig, + SinsemillaConfig, + SinsemillaConfig, + ); type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { @@ -485,7 +494,12 @@ mod tests { let range_check = LookupRangeCheckConfig::configure(meta, advices[9], table_idx); - let ecc_config = EccChip::configure(meta, advices, lagrange_coeffs, range_check); + let ecc_config = EccChip::::configure( + meta, + advices, + lagrange_coeffs, + range_check, + ); let config1 = SinsemillaChip::configure( meta, @@ -516,7 +530,10 @@ mod tests { let ecc_chip = EccChip::construct(config.0); // The two `SinsemillaChip`s share the same lookup table. - SinsemillaChip::load(config.1.clone(), &mut layouter)?; + SinsemillaChip::::load( + config.1.clone(), + &mut layouter, + )?; // This MerkleCRH example is purely for illustrative purposes. // It is not an implementation of the Orchard protocol spec. @@ -526,7 +543,7 @@ mod tests { let merkle_crh = HashDomain::new( chip1.clone(), ecc_chip.clone(), - &SinsemillaHashDomains::MerkleCrh, + &OrchardHashDomains::MerkleCrh, ); // Layer 31, l = MERKLE_DEPTH_ORCHARD - 1 - layer = 0 @@ -602,7 +619,7 @@ mod tests { let commit_ivk = CommitDomain::new( chip2.clone(), ecc_chip.clone(), - &SinsemillaCommitDomains::CommitIvk, + &OrchardCommitDomains::CommitIvk, ); let r_val = pallas::Scalar::random(rng); let message: Vec> = diff --git a/src/circuit/gadget/sinsemilla/chip.rs b/src/circuit/gadget/sinsemilla/chip.rs index bca8531d..2b9577a5 100644 --- a/src/circuit/gadget/sinsemilla/chip.rs +++ b/src/circuit/gadget/sinsemilla/chip.rs @@ -4,17 +4,14 @@ use super::{ }; use crate::{ circuit::gadget::{ - ecc::chip::NonIdentityEccPoint, utilities::lookup_range_check::LookupRangeCheckConfig, - }, - constants::OrchardFixedBasesFull, - primitives::sinsemilla::{ - self, Q_COMMIT_IVK_M_GENERATOR, Q_MERKLE_CRH, Q_NOTE_COMMITMENT_M_GENERATOR, + ecc::{chip::NonIdentityEccPoint, FixedPoints}, + utilities::lookup_range_check::LookupRangeCheckConfig, }, + primitives::sinsemilla, }; +use std::marker::PhantomData; -use group::ff::PrimeField; use halo2::{ - arithmetic::CurveAffine, circuit::{AssignedCell, Chip, Layouter}, plonk::{ Advice, Column, ConstraintSystem, Error, Expression, Fixed, Selector, TableColumn, @@ -31,7 +28,12 @@ mod hash_to_point; /// Configuration for the Sinsemilla hash chip #[derive(Eq, PartialEq, Clone, Debug)] -pub struct SinsemillaConfig { +pub struct SinsemillaConfig +where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, +{ /// Binary selector used in lookup argument and in the body of the Sinsemilla hash. q_sinsemilla1: Selector, /// Non-binary selector used in lookup argument and in the body of the Sinsemilla hash. @@ -65,10 +67,16 @@ pub struct SinsemillaConfig { /// generators of the Sinsemilla hash. pub(super) generator_table: GeneratorTableConfig, /// An advice column configured to perform lookup range checks. - pub(super) lookup_config: LookupRangeCheckConfig, + lookup_config: LookupRangeCheckConfig, + _marker: PhantomData<(Hash, Commit, F)>, } -impl SinsemillaConfig { +impl SinsemillaConfig +where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, +{ /// Returns an array of all advice columns in this config, in arbitrary order. pub(super) fn advices(&self) -> [Column; 5] { [self.x_a, self.x_p, self.bits, self.lambda_1, self.lambda_2] @@ -81,12 +89,22 @@ impl SinsemillaConfig { } #[derive(Eq, PartialEq, Clone, Debug)] -pub struct SinsemillaChip { - config: SinsemillaConfig, +pub struct SinsemillaChip +where + Hash: HashDomains, + Fixed: FixedPoints, + Commit: CommitDomains, +{ + config: SinsemillaConfig, } -impl Chip for SinsemillaChip { - type Config = SinsemillaConfig; +impl Chip for SinsemillaChip +where + Hash: HashDomains, + Fixed: FixedPoints, + Commit: CommitDomains, +{ + type Config = SinsemillaConfig; type Loaded = (); fn config(&self) -> &Self::Config { @@ -98,13 +116,18 @@ impl Chip for SinsemillaChip { } } -impl SinsemillaChip { +impl SinsemillaChip +where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, +{ pub fn construct(config: >::Config) -> Self { Self { config } } pub fn load( - config: SinsemillaConfig, + config: SinsemillaConfig, layouter: &mut impl Layouter, ) -> Result<>::Loaded, Error> { // Load the lookup table. @@ -129,7 +152,7 @@ impl SinsemillaChip { meta.enable_equality(*advice); } - let config = SinsemillaConfig { + let config = SinsemillaConfig:: { q_sinsemilla1: meta.complex_selector(), q_sinsemilla2: meta.fixed_column(), q_sinsemilla4: meta.selector(), @@ -146,6 +169,7 @@ impl SinsemillaChip { table_y: lookup.2, }, lookup_config: range_check, + _marker: PhantomData, }; // Set up lookup argument @@ -241,8 +265,12 @@ impl SinsemillaChip { } // Implement `SinsemillaInstructions` for `SinsemillaChip` -impl SinsemillaInstructions - for SinsemillaChip +impl SinsemillaInstructions + for SinsemillaChip +where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, { type CellValue = AssignedCell; @@ -253,10 +281,10 @@ impl SinsemillaInstructions; type NonIdentityPoint = NonIdentityEccPoint; - type FixedPoints = OrchardFixedBasesFull; + type FixedPoints = F; - type HashDomains = SinsemillaHashDomains; - type CommitDomains = SinsemillaCommitDomains; + type HashDomains = Hash; + type CommitDomains = Commit; fn witness_message_piece( &self, @@ -298,57 +326,3 @@ impl SinsemillaInstructions for SinsemillaHashDomains { - fn Q(&self) -> pallas::Affine { - match self { - SinsemillaHashDomains::CommitIvk => pallas::Affine::from_xy( - pallas::Base::from_repr(Q_COMMIT_IVK_M_GENERATOR.0).unwrap(), - pallas::Base::from_repr(Q_COMMIT_IVK_M_GENERATOR.1).unwrap(), - ) - .unwrap(), - SinsemillaHashDomains::NoteCommit => pallas::Affine::from_xy( - pallas::Base::from_repr(Q_NOTE_COMMITMENT_M_GENERATOR.0).unwrap(), - pallas::Base::from_repr(Q_NOTE_COMMITMENT_M_GENERATOR.1).unwrap(), - ) - .unwrap(), - SinsemillaHashDomains::MerkleCrh => pallas::Affine::from_xy( - pallas::Base::from_repr(Q_MERKLE_CRH.0).unwrap(), - pallas::Base::from_repr(Q_MERKLE_CRH.1).unwrap(), - ) - .unwrap(), - } - } -} - -#[derive(Clone, Debug)] -pub enum SinsemillaCommitDomains { - NoteCommit, - CommitIvk, -} - -impl CommitDomains - for SinsemillaCommitDomains -{ - fn r(&self) -> OrchardFixedBasesFull { - match self { - Self::NoteCommit => OrchardFixedBasesFull::NoteCommitR, - Self::CommitIvk => OrchardFixedBasesFull::CommitIvkR, - } - } - - fn hash_domain(&self) -> SinsemillaHashDomains { - match self { - Self::NoteCommit => SinsemillaHashDomains::NoteCommit, - Self::CommitIvk => SinsemillaHashDomains::CommitIvk, - } - } -} diff --git a/src/circuit/gadget/sinsemilla/chip/generator_table.rs b/src/circuit/gadget/sinsemilla/chip/generator_table.rs index 71039d28..1bb109f9 100644 --- a/src/circuit/gadget/sinsemilla/chip/generator_table.rs +++ b/src/circuit/gadget/sinsemilla/chip/generator_table.rs @@ -5,6 +5,7 @@ use halo2::{ poly::Rotation, }; +use super::{CommitDomains, FixedPoints, HashDomains}; use pasta_curves::{arithmetic::FieldExt, pallas}; /// Table containing independent generators S[0..2^k] @@ -21,7 +22,14 @@ impl GeneratorTableConfig { /// Even though the lookup table can be used in other parts of the circuit, /// this specific configuration sets up Sinsemilla-specific constraints /// controlled by `q_sinsemilla`, and would likely not apply to other chips. - pub fn configure(meta: &mut ConstraintSystem, config: super::SinsemillaConfig) { + pub fn configure( + meta: &mut ConstraintSystem, + config: super::SinsemillaConfig, + ) where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, + { let (table_idx, table_x, table_y) = ( config.generator_table.table_idx, config.generator_table.table_x, diff --git a/src/circuit/gadget/sinsemilla/chip/hash_to_point.rs b/src/circuit/gadget/sinsemilla/chip/hash_to_point.rs index 517e2202..4fd9103b 100644 --- a/src/circuit/gadget/sinsemilla/chip/hash_to_point.rs +++ b/src/circuit/gadget/sinsemilla/chip/hash_to_point.rs @@ -1,5 +1,7 @@ -use super::super::SinsemillaInstructions; +use super::super::{CommitDomains, HashDomains, SinsemillaInstructions}; use super::{NonIdentityEccPoint, SinsemillaChip}; + +use crate::circuit::gadget::ecc::FixedPoints; use crate::primitives::sinsemilla::{self, lebs2ip_k, INV_TWO_POW_K, SINSEMILLA_S}; use halo2::circuit::AssignedCell; use halo2::{ @@ -15,7 +17,12 @@ use pasta_curves::{ use std::ops::Deref; -impl SinsemillaChip { +impl SinsemillaChip +where + Hash: HashDomains, + Fixed: FixedPoints, + Commit: CommitDomains, +{ #[allow(non_snake_case)] #[allow(clippy::type_complexity)] pub(super) fn hash_message( diff --git a/src/circuit/gadget/sinsemilla/merkle.rs b/src/circuit/gadget/sinsemilla/merkle.rs index 05d1f9f5..893d70d2 100644 --- a/src/circuit/gadget/sinsemilla/merkle.rs +++ b/src/circuit/gadget/sinsemilla/merkle.rs @@ -138,10 +138,12 @@ pub mod tests { use crate::{ circuit::gadget::{ - sinsemilla::chip::{SinsemillaChip, SinsemillaHashDomains}, + sinsemilla::chip::SinsemillaChip, utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions}, }, - constants::MERKLE_DEPTH_ORCHARD, + constants::{ + OrchardCommitDomains, OrchardFixedBases, OrchardHashDomains, MERKLE_DEPTH_ORCHARD, + }, note::commitment::ExtractedNoteCommitment, tree, }; @@ -165,7 +167,10 @@ pub mod tests { } impl Circuit for MyCircuit { - type Config = (MerkleConfig, MerkleConfig); + type Config = ( + MerkleConfig, + MerkleConfig, + ); type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { @@ -233,7 +238,10 @@ pub mod tests { mut layouter: impl Layouter, ) -> Result<(), Error> { // Load generator table (shared across both configs) - SinsemillaChip::load(config.0.sinsemilla_config.clone(), &mut layouter)?; + SinsemillaChip::::load( + config.0.sinsemilla_config.clone(), + &mut layouter, + )?; // Construct Merkle chips which will be placed side-by-side in the circuit. let chip_1 = MerkleChip::construct(config.0.clone()); @@ -248,7 +256,7 @@ pub mod tests { let path = MerklePath { chip_1, chip_2, - domain: SinsemillaHashDomains::MerkleCrh, + domain: OrchardHashDomains::MerkleCrh, leaf_pos: self.leaf_pos, path: self.merkle_path, }; diff --git a/src/circuit/gadget/sinsemilla/merkle/chip.rs b/src/circuit/gadget/sinsemilla/merkle/chip.rs index a53568d3..0d4a7dd4 100644 --- a/src/circuit/gadget/sinsemilla/merkle/chip.rs +++ b/src/circuit/gadget/sinsemilla/merkle/chip.rs @@ -5,17 +5,20 @@ use halo2::{ }; use pasta_curves::{arithmetic::FieldExt, pallas}; -use super::super::{ - chip::{SinsemillaChip, SinsemillaConfig}, - SinsemillaInstructions, -}; use super::MerkleInstructions; use crate::{ - circuit::gadget::utilities::{ - bitrange_subset, - cond_swap::{CondSwapChip, CondSwapConfig, CondSwapInstructions}, - UtilitiesInstructions, + circuit::gadget::{ + ecc::FixedPoints, + sinsemilla::{ + chip::{SinsemillaChip, SinsemillaConfig}, + CommitDomains, HashDomains, SinsemillaInstructions, + }, + utilities::{ + bitrange_subset, + cond_swap::{CondSwapChip, CondSwapConfig, CondSwapInstructions}, + UtilitiesInstructions, + }, }, constants::{L_ORCHARD_BASE, MERKLE_DEPTH_ORCHARD}, primitives::sinsemilla, @@ -23,20 +26,35 @@ use crate::{ use std::array; #[derive(Clone, Debug)] -pub struct MerkleConfig { +pub struct MerkleConfig +where + Hash: HashDomains, + Fixed: FixedPoints, + Commit: CommitDomains, +{ advices: [Column; 5], q_decompose: Selector, pub(super) cond_swap_config: CondSwapConfig, - pub(super) sinsemilla_config: SinsemillaConfig, + pub(super) sinsemilla_config: SinsemillaConfig, } #[derive(Clone, Debug)] -pub struct MerkleChip { - config: MerkleConfig, +pub struct MerkleChip +where + Hash: HashDomains, + Fixed: FixedPoints, + Commit: CommitDomains, +{ + config: MerkleConfig, } -impl Chip for MerkleChip { - type Config = MerkleConfig; +impl Chip for MerkleChip +where + Hash: HashDomains, + Fixed: FixedPoints, + Commit: CommitDomains, +{ + type Config = MerkleConfig; type Loaded = (); fn config(&self) -> &Self::Config { @@ -48,11 +66,16 @@ impl Chip for MerkleChip { } } -impl MerkleChip { +impl MerkleChip +where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, +{ pub fn configure( meta: &mut ConstraintSystem, - sinsemilla_config: SinsemillaConfig, - ) -> MerkleConfig { + sinsemilla_config: SinsemillaConfig, + ) -> MerkleConfig { // All five advice columns are equality-enabled by SinsemillaConfig. let advices = sinsemilla_config.advices(); let cond_swap_config = CondSwapChip::configure(meta, advices); @@ -152,13 +175,18 @@ impl MerkleChip { } } - pub fn construct(config: MerkleConfig) -> Self { + pub fn construct(config: MerkleConfig) -> Self { MerkleChip { config } } } -impl MerkleInstructions - for MerkleChip +impl + MerkleInstructions + for MerkleChip +where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, { #[allow(non_snake_case)] fn hash_layer( @@ -353,11 +381,21 @@ impl MerkleInstructions for MerkleChip { +impl UtilitiesInstructions for MerkleChip +where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, +{ type Var = AssignedCell; } -impl CondSwapInstructions for MerkleChip { +impl CondSwapInstructions for MerkleChip +where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, +{ #[allow(clippy::type_complexity)] fn swap( &self, @@ -371,51 +409,57 @@ impl CondSwapInstructions for MerkleChip { } } -impl SinsemillaInstructions for MerkleChip { - type CellValue = SinsemillaInstructions + for MerkleChip +where + Hash: HashDomains, + F: FixedPoints, + Commit: CommitDomains, +{ + type CellValue = as SinsemillaInstructions< pallas::Affine, { sinsemilla::K }, { sinsemilla::C }, >>::CellValue; - type Message = as SinsemillaInstructions< pallas::Affine, { sinsemilla::K }, { sinsemilla::C }, >>::Message; - type MessagePiece = as SinsemillaInstructions< pallas::Affine, { sinsemilla::K }, { sinsemilla::C }, >>::MessagePiece; - type RunningSum = as SinsemillaInstructions< pallas::Affine, { sinsemilla::K }, { sinsemilla::C }, >>::RunningSum; - type X = as SinsemillaInstructions< pallas::Affine, { sinsemilla::K }, { sinsemilla::C }, >>::X; - type NonIdentityPoint = as SinsemillaInstructions< pallas::Affine, { sinsemilla::K }, { sinsemilla::C }, >>::NonIdentityPoint; - type FixedPoints = as SinsemillaInstructions< pallas::Affine, { sinsemilla::K }, { sinsemilla::C }, >>::FixedPoints; - type HashDomains = as SinsemillaInstructions< pallas::Affine, { sinsemilla::K }, { sinsemilla::C }, >>::HashDomains; - type CommitDomains = as SinsemillaInstructions< pallas::Affine, { sinsemilla::K }, { sinsemilla::C }, @@ -428,7 +472,7 @@ impl SinsemillaInstructions Result { let config = self.config().sinsemilla_config.clone(); - let chip = SinsemillaChip::construct(config); + let chip = SinsemillaChip::::construct(config); chip.witness_message_piece(layouter, value, num_words) } @@ -441,11 +485,11 @@ impl SinsemillaInstructions Result<(Self::NonIdentityPoint, Vec>), Error> { let config = self.config().sinsemilla_config.clone(); - let chip = SinsemillaChip::construct(config); + let chip = SinsemillaChip::::construct(config); chip.hash_to_point(layouter, Q, message) } fn extract(point: &Self::NonIdentityPoint) -> Self::X { - SinsemillaChip::extract(point) + SinsemillaChip::::extract(point) } } diff --git a/src/circuit/note_commit.rs b/src/circuit/note_commit.rs index be964c0c..9b802c7b 100644 --- a/src/circuit/note_commit.rs +++ b/src/circuit/note_commit.rs @@ -12,12 +12,12 @@ use crate::{ Point, }, sinsemilla::{ - chip::{SinsemillaChip, SinsemillaCommitDomains, SinsemillaConfig}, + chip::{SinsemillaChip, SinsemillaConfig}, CommitDomain, Message, MessagePiece, }, utilities::{bitrange_subset, bool_check}, }, - constants::T_P, + constants::{OrchardCommitDomains, OrchardFixedBases, OrchardHashDomains, T_P}, }; /// The values of the running sum at the start and end of the range being used for a @@ -55,7 +55,8 @@ pub struct NoteCommitConfig { q_notecommit_psi: Selector, q_y_canon: Selector, advices: [Column; 10], - sinsemilla_config: SinsemillaConfig, + sinsemilla_config: + SinsemillaConfig, } impl NoteCommitConfig { @@ -64,7 +65,11 @@ impl NoteCommitConfig { pub(in crate::circuit) fn configure( meta: &mut ConstraintSystem, advices: [Column; 10], - sinsemilla_config: SinsemillaConfig, + sinsemilla_config: SinsemillaConfig< + OrchardHashDomains, + OrchardCommitDomains, + OrchardFixedBases, + >, ) -> Self { let q_notecommit_b = meta.selector(); let q_notecommit_d = meta.selector(); @@ -527,8 +532,8 @@ impl NoteCommitConfig { pub(in crate::circuit) fn assign_region( &self, mut layouter: impl Layouter, - chip: SinsemillaChip, - ecc_chip: EccChip, + chip: SinsemillaChip, + ecc_chip: EccChip, g_d: &NonIdentityEccPoint, pk_d: &NonIdentityEccPoint, // TODO: Set V to Orchard value type @@ -536,7 +541,7 @@ impl NoteCommitConfig { rho: AssignedCell, psi: AssignedCell, rcm: Option, - ) -> Result, Error> { + ) -> Result>, Error> { let (gd_x, gd_y) = (g_d.x(), g_d.y()); let (pkd_x, pkd_y) = (pk_d.x(), pk_d.y()); let (gd_x, gd_y) = (gd_x.value(), gd_y.value()); @@ -739,7 +744,7 @@ impl NoteCommitConfig { h.clone(), ], ); - let domain = CommitDomain::new(chip, ecc_chip, &SinsemillaCommitDomains::NoteCommit); + let domain = CommitDomain::new(chip, ecc_chip, &OrchardCommitDomains::NoteCommit); domain.commit( layouter.namespace(|| "Process NoteCommit inputs"), message, @@ -1459,7 +1464,10 @@ mod tests { sinsemilla::chip::SinsemillaChip, utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions}, }, - constants::{L_ORCHARD_BASE, L_VALUE, NOTE_COMMITMENT_PERSONALIZATION, T_Q}, + constants::{ + OrchardCommitDomains, OrchardFixedBases, OrchardHashDomains, L_ORCHARD_BASE, L_VALUE, + NOTE_COMMITMENT_PERSONALIZATION, T_Q, + }, primitives::sinsemilla::CommitDomain, }; @@ -1495,7 +1503,7 @@ mod tests { } impl Circuit for MyCircuit { - type Config = (NoteCommitConfig, EccConfig); + type Config = (NoteCommitConfig, EccConfig); type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { @@ -1542,7 +1550,11 @@ mod tests { ]; let range_check = LookupRangeCheckConfig::configure(meta, advices[9], table_idx); - let sinsemilla_config = SinsemillaChip::configure( + let sinsemilla_config = SinsemillaChip::< + OrchardHashDomains, + OrchardCommitDomains, + OrchardFixedBases, + >::configure( meta, advices[..5].try_into().unwrap(), advices[2], @@ -1553,7 +1565,12 @@ mod tests { let note_commit_config = NoteCommitConfig::configure(meta, advices, sinsemilla_config); - let ecc_config = EccChip::configure(meta, advices, lagrange_coeffs, range_check); + let ecc_config = EccChip::::configure( + meta, + advices, + lagrange_coeffs, + range_check, + ); (note_commit_config, ecc_config) } @@ -1566,7 +1583,11 @@ mod tests { let (note_commit_config, ecc_config) = config; // Load the Sinsemilla generator lookup table used by the whole circuit. - SinsemillaChip::load(note_commit_config.sinsemilla_config.clone(), &mut layouter)?; + SinsemillaChip::< + OrchardHashDomains, + OrchardCommitDomains, + OrchardFixedBases, + >::load(note_commit_config.sinsemilla_config.clone(), &mut layouter)?; // Construct a Sinsemilla chip let sinsemilla_chip = diff --git a/src/constants.rs b/src/constants.rs index 52df6cd5..479bc215 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -1,4 +1,12 @@ //! Constants used in the Orchard protocol. +use crate::circuit::gadget::{ + ecc::{chip::FixedPoint, FixedPoints}, + sinsemilla::{CommitDomains, HashDomains}, +}; +use crate::primitives::sinsemilla::{ + Q_COMMIT_IVK_M_GENERATOR, Q_MERKLE_CRH, Q_NOTE_COMMITMENT_M_GENERATOR, +}; + use arrayvec::ArrayVec; use ff::{Field, PrimeField}; use group::Curve; @@ -15,11 +23,8 @@ pub mod spend_auth_g; pub mod value_commit_r; pub mod value_commit_v; -pub mod load; pub mod util; -pub use load::{NullifierK, OrchardFixedBase, OrchardFixedBasesFull, ValueCommitV}; - /// The Pallas scalar field modulus is $q = 2^{254} + \mathsf{t_q}$. /// pub(crate) const T_Q: u128 = 45560315531506369815346746415080538113; @@ -196,6 +201,177 @@ fn find_zs_and_us(base: C, num_windows: usize) -> Option for OrchardFixedBases { + fn from(full_width_base: OrchardFixedBasesFull) -> Self { + Self::Full(full_width_base) + } +} + +impl From for OrchardFixedBases { + fn from(_value_commit_v: ValueCommitV) -> Self { + Self::ValueCommitV + } +} + +impl From for OrchardFixedBases { + fn from(_nullifier_k: NullifierK) -> Self { + Self::NullifierK + } +} + +/// The Orchard fixed bases used in scalar mul with full-width scalars. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum OrchardFixedBasesFull { + CommitIvkR, + NoteCommitR, + ValueCommitR, + SpendAuthG, +} + +/// NullifierK is used in scalar mul with a base field element. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct NullifierK; + +/// ValueCommitV is used in scalar mul with a short signed scalar. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct ValueCommitV; + +impl FixedPoints for OrchardFixedBases { + type FullScalar = OrchardFixedBasesFull; + type Base = NullifierK; + type ShortScalar = ValueCommitV; +} + +impl FixedPoint for OrchardFixedBasesFull { + fn generator(&self) -> pallas::Affine { + match self { + Self::CommitIvkR => commit_ivk_r::generator(), + Self::NoteCommitR => note_commit_r::generator(), + Self::ValueCommitR => value_commit_r::generator(), + Self::SpendAuthG => spend_auth_g::generator(), + } + } + + fn u(&self) -> Vec<[[u8; 32]; H]> { + match self { + Self::CommitIvkR => commit_ivk_r::U.to_vec(), + Self::NoteCommitR => note_commit_r::U.to_vec(), + Self::ValueCommitR => value_commit_r::U.to_vec(), + Self::SpendAuthG => spend_auth_g::U.to_vec(), + } + } + + fn z(&self) -> Vec { + match self { + Self::CommitIvkR => commit_ivk_r::Z.to_vec(), + Self::NoteCommitR => note_commit_r::Z.to_vec(), + Self::ValueCommitR => value_commit_r::Z.to_vec(), + Self::SpendAuthG => spend_auth_g::Z.to_vec(), + } + } + + fn lagrange_coeffs(&self) -> Vec<[pallas::Base; H]> { + compute_lagrange_coeffs(self.generator(), NUM_WINDOWS) + } +} + +impl FixedPoint for NullifierK { + fn generator(&self) -> pallas::Affine { + nullifier_k::generator() + } + + fn u(&self) -> Vec<[[u8; 32]; H]> { + nullifier_k::U.to_vec() + } + + fn z(&self) -> Vec { + nullifier_k::Z.to_vec() + } + + fn lagrange_coeffs(&self) -> Vec<[pallas::Base; H]> { + compute_lagrange_coeffs(self.generator(), NUM_WINDOWS) + } +} + +impl FixedPoint for ValueCommitV { + fn generator(&self) -> pallas::Affine { + value_commit_v::generator() + } + + fn u(&self) -> Vec<[[u8; 32]; H]> { + value_commit_v::U_SHORT.to_vec() + } + + fn z(&self) -> Vec { + value_commit_v::Z_SHORT.to_vec() + } + + fn lagrange_coeffs(&self) -> Vec<[pallas::Base; H]> { + compute_lagrange_coeffs(self.generator(), NUM_WINDOWS_SHORT) + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum OrchardHashDomains { + NoteCommit, + CommitIvk, + MerkleCrh, +} + +#[allow(non_snake_case)] +impl HashDomains for OrchardHashDomains { + fn Q(&self) -> pallas::Affine { + match self { + OrchardHashDomains::CommitIvk => pallas::Affine::from_xy( + pallas::Base::from_bytes(&Q_COMMIT_IVK_M_GENERATOR.0).unwrap(), + pallas::Base::from_bytes(&Q_COMMIT_IVK_M_GENERATOR.1).unwrap(), + ) + .unwrap(), + OrchardHashDomains::NoteCommit => pallas::Affine::from_xy( + pallas::Base::from_bytes(&Q_NOTE_COMMITMENT_M_GENERATOR.0).unwrap(), + pallas::Base::from_bytes(&Q_NOTE_COMMITMENT_M_GENERATOR.1).unwrap(), + ) + .unwrap(), + OrchardHashDomains::MerkleCrh => pallas::Affine::from_xy( + pallas::Base::from_bytes(&Q_MERKLE_CRH.0).unwrap(), + pallas::Base::from_bytes(&Q_MERKLE_CRH.1).unwrap(), + ) + .unwrap(), + } + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum OrchardCommitDomains { + NoteCommit, + CommitIvk, +} + +impl CommitDomains for OrchardCommitDomains { + fn r(&self) -> OrchardFixedBasesFull { + match self { + Self::NoteCommit => OrchardFixedBasesFull::NoteCommitR, + Self::CommitIvk => OrchardFixedBasesFull::CommitIvkR, + } + } + + fn hash_domain(&self) -> OrchardHashDomains { + match self { + Self::NoteCommit => OrchardHashDomains::NoteCommit, + Self::CommitIvk => OrchardHashDomains::CommitIvk, + } + } +} + #[cfg(test)] // Test that Lagrange interpolation coefficients reproduce the correct x-coordinate // for each fixed-base multiple in each window.