From 7e1ff20b59cdea73443c984255154b57943ab2cc Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Thu, 3 Jun 2021 00:54:22 +0800 Subject: [PATCH] Remove SinsemillaInstructions: EccInstructions trait bound --- src/circuit/gadget/sinsemilla.rs | 186 +++++++++++------- src/circuit/gadget/sinsemilla/chip.rs | 130 ++---------- .../gadget/sinsemilla/chip/hash_to_point.rs | 7 +- 3 files changed, 130 insertions(+), 193 deletions(-) diff --git a/src/circuit/gadget/sinsemilla.rs b/src/circuit/gadget/sinsemilla.rs index f8842dc17..27e16bedf 100644 --- a/src/circuit/gadget/sinsemilla.rs +++ b/src/circuit/gadget/sinsemilla.rs @@ -4,19 +4,10 @@ use halo2::{arithmetic::CurveAffine, circuit::Layouter, plonk::Error}; use std::fmt::Debug; pub mod chip; -pub use chip::{SinsemillaChip, SinsemillaCommitDomains, SinsemillaConfig, SinsemillaHashDomains}; +pub use chip::{SinsemillaChip, SinsemillaConfig}; /// The set of circuit instructions required to use the [`Sinsemilla`](https://zcash.github.io/halo2/design/gadgets/sinsemilla.html) gadget. -pub trait SinsemillaInstructions: EccInstructions { - /// HashDomains used in this instruction. - type HashDomains: HashDomains; - /// CommitDomains used in this instruction. - type CommitDomains: CommitDomains< - C, - >::FixedPoints, - Self::HashDomains, - >; - +pub trait SinsemillaInstructions { /// A piece in a message containing a number of `K`-bit words. /// A [`MessagePiece`] fits in a single cell, which means it can only /// contain up to `N` words, where `N*K <= C::Base::NUM_BITS`. @@ -25,6 +16,16 @@ pub trait SinsemillaInstructions: EccInstructions { /// A cell in the circuit type CellValue; + /// A point output of [ hash_to_point`]. + type Point: Clone + Debug; + /// The fixed points used in `CommitDomains`. + type FixedPoints: Clone + Debug; + + /// HashDomains used in this instruction. + type HashDomains: HashDomains; + /// CommitDomains used in this instruction. + type CommitDomains: CommitDomains; + /// Witness a message given a bitstring. fn witness_message( &self, @@ -52,9 +53,6 @@ pub trait SinsemillaInstructions: EccInstructions { /// Prepare a message piece given a [`CellValue`] and a length. fn prepare_message_piece(cell: &Self::CellValue, length: usize) -> Self::MessagePiece; - /// Extracts the x-coordinate from a curve point. - fn extract(point: &Self::Point) -> Self::X; - /// Hashes a message to an ECC curve point. #[allow(non_snake_case)] fn hash_to_point( @@ -85,7 +83,7 @@ impl + Clone + Debug + num_words: usize, ) -> Result { println!("from_bitstring num_words: {}", num_words); - let inner = chip.witness_message(layouter, bitstring.clone(), num_words)?; + let inner = chip.witness_message(layouter, bitstring, num_words)?; Ok(Self { chip, inner }) } @@ -112,32 +110,44 @@ impl + Clone + Debug + } } -/// Trait allowing circuit's Sinsemilla HashDomains to be enumerated. -#[allow(non_snake_case)] -pub trait HashDomains: Clone + Debug { - fn Q(&self) -> C; -} - #[allow(non_snake_case)] -pub struct HashDomain< - C: CurveAffine, +pub struct HashDomain +where SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, -> { - chip: SinsemillaChip, + EccChip: EccInstructions< + C, + Point = >::Point, + FixedPoints = >::FixedPoints, + > + Clone + + Debug + + Eq, +{ + sinsemilla_chip: SinsemillaChip, + ecc_chip: EccChip, pub Q: C, } -impl + Clone + Debug + Eq> - HashDomain +impl HashDomain +where + SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, + EccChip: EccInstructions< + C, + Point = >::Point, + FixedPoints = >::FixedPoints, + > + Clone + + Debug + + Eq, { #[allow(non_snake_case)] /// Constructs a new `HashDomain` for the given domain. pub fn new( - chip: SinsemillaChip, - domain: &>::HashDomains, + sinsemilla_chip: SinsemillaChip, + ecc_chip: EccChip, + domain: &SinsemillaChip::HashDomains, ) -> Self { HashDomain { - chip: chip.clone(), + sinsemilla_chip, + ecc_chip, Q: domain.Q(), } } @@ -149,11 +159,11 @@ impl + Clone + Debug + &self, layouter: impl Layouter, message: Message, - ) -> Result, Error> { - assert_eq!(self.chip, message.chip); - self.chip + ) -> Result, Error> { + assert_eq!(self.sinsemilla_chip, message.chip); + self.sinsemilla_chip .hash_to_point(layouter, self.Q, message.inner) - .map(|point| ecc::Point::from_inner(self.chip.clone(), point)) + .map(|point| ecc::Point::from_inner(self.ecc_chip.clone(), point)) } /// $\mathsf{SinsemillaHash}$ from [ยง 5.4.1.9][concretesinsemillahash]. @@ -163,8 +173,8 @@ impl + Clone + Debug + &self, layouter: impl Layouter, message: Message, - ) -> Result, Error> { - assert_eq!(self.chip, message.chip); + ) -> Result, Error> { + assert_eq!(self.sinsemilla_chip, message.chip); let p = self.hash_to_point(layouter, message); p.map(|p| p.extract_p()) } @@ -181,23 +191,48 @@ pub trait CommitDomains>: fn hash_domain(&self) -> H; } +/// Trait allowing circuit's Sinsemilla HashDomains to be enumerated. +#[allow(non_snake_case)] +pub trait HashDomains: Clone + Debug { + fn Q(&self) -> C; +} + #[allow(non_snake_case)] -pub struct CommitDomain< - C: CurveAffine, +pub struct CommitDomain +where SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, -> { - M: HashDomain, - R: ecc::FixedPoint, + EccChip: EccInstructions< + C, + Point = >::Point, + FixedPoints = >::FixedPoints, + > + Clone + + Debug + + Eq, +{ + M: HashDomain, + R: ecc::FixedPoint, } -impl + Clone + Debug + Eq> - CommitDomain +impl CommitDomain +where + SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, + EccChip: EccInstructions< + C, + Point = >::Point, + FixedPoints = >::FixedPoints, + > + Clone + + Debug + + Eq, { /// Constructs a new `CommitDomain` for the given domain. - pub fn new(chip: SinsemillaChip, domain: &SinsemillaChip::CommitDomains) -> Self { + pub fn new( + sinsemilla_chip: SinsemillaChip, + ecc_chip: EccChip, + domain: &SinsemillaChip::CommitDomains, + ) -> Self { CommitDomain { - M: HashDomain::new(chip.clone(), &domain.hash_domain()), - R: ecc::FixedPoint::from_inner(chip, domain.r()), + M: HashDomain::new(sinsemilla_chip, ecc_chip.clone(), &domain.hash_domain()), + R: ecc::FixedPoint::from_inner(ecc_chip, domain.r()), } } @@ -208,9 +243,9 @@ impl + Clone + Debug + &self, mut layouter: impl Layouter, message: Message, - r: ecc::ScalarFixed, - ) -> Result, Error> { - assert_eq!(self.M.chip, message.chip); + r: ecc::ScalarFixed, + ) -> Result, Error> { + assert_eq!(self.M.sinsemilla_chip, message.chip); let blind = self.R.mul(layouter.namespace(|| "[r] R"), &r)?; self.M .hash_to_point(layouter.namespace(|| "M"), message)? @@ -224,9 +259,9 @@ impl + Clone + Debug + &self, mut layouter: impl Layouter, message: Message, - r: ecc::ScalarFixed, - ) -> Result, Error> { - assert_eq!(self.M.chip, message.chip); + r: ecc::ScalarFixed, + ) -> Result, Error> { + assert_eq!(self.M.sinsemilla_chip, message.chip); let p = self.commit(layouter.namespace(|| "commit"), message, r); p.map(|p| p.extract_p()) } @@ -243,13 +278,16 @@ mod tests { }; use super::{ - CommitDomain, HashDomain, Message, SinsemillaChip, SinsemillaCommitDomains, - SinsemillaConfig, SinsemillaHashDomains, SinsemillaInstructions, + chip::{SinsemillaCommitDomains, SinsemillaHashDomains}, + CommitDomain, HashDomain, Message, SinsemillaChip, SinsemillaConfig, + SinsemillaInstructions, }; - use crate::circuit::gadget::ecc::{chip::EccChip, ScalarFixed}; + use crate::circuit::gadget::ecc::{ + chip::{EccChip, EccConfig}, + ScalarFixed, + }; - use rand; use std::convert::TryInto; struct MyCircuit { @@ -257,7 +295,7 @@ mod tests { } impl Circuit for MyCircuit { - type Config = (SinsemillaConfig, SinsemillaConfig); + type Config = (EccConfig, SinsemillaConfig, SinsemillaConfig); #[allow(non_snake_case)] fn configure(meta: &mut ConstraintSystem) -> Self::Config { @@ -291,19 +329,17 @@ mod tests { let config1 = SinsemillaChip::::configure( meta, - ecc_config.clone(), advices[..5].try_into().unwrap(), lookup, perm.clone(), ); let config2 = SinsemillaChip::::configure( meta, - ecc_config.clone(), advices[5..].try_into().unwrap(), lookup, perm, ); - (config1, config2) + (ecc_config, config1, config2) } fn synthesize( @@ -312,17 +348,22 @@ mod tests { config: Self::Config, ) -> Result<(), Error> { let mut layouter = SingleChipLayouter::new(cs)?; + let ecc_chip = EccChip::::construct(config.0); // The two `SinsemillaChip`s share the same lookup table. - SinsemillaChip::::load(config.0.clone(), &mut layouter)?; + SinsemillaChip::::load(config.1.clone(), &mut layouter)?; // This MerkleCRH example does not use the optimal bit-packing that will // be used in the actual Orchard circuit. // That requires bit decomposition which will be done in the Orchard circuit. { - let chip1 = SinsemillaChip::::construct(config.0); + let chip1 = SinsemillaChip::::construct(config.1); - let merkle_crh = HashDomain::new(chip1.clone(), &SinsemillaHashDomains::MerkleCrh); + let merkle_crh = HashDomain::new( + chip1.clone(), + ecc_chip.clone(), + &SinsemillaHashDomains::MerkleCrh, + ); // Left leaf let left = { @@ -331,7 +372,7 @@ mod tests { let left = Message::from_bitstring( chip1.clone(), layouter.namespace(|| "witness left"), - left.clone(), + left, 25, )?; let left = merkle_crh.hash_to_point(layouter.namespace(|| "left"), left)?; @@ -346,7 +387,7 @@ mod tests { let right = Message::from_bitstring( chip1.clone(), layouter.namespace(|| "witness right"), - right.clone(), + right, 25, )?; let right = merkle_crh.hash_to_point(layouter.namespace(|| "right"), right)?; @@ -363,17 +404,20 @@ mod tests { }; // Parent - let parent = Message::from_pieces(chip1.clone(), vec![l, left, right]); + let parent = Message::from_pieces(chip1, vec![l, left, right]); merkle_crh.hash_to_point(layouter.namespace(|| "parent"), parent)?; } { - let chip2 = SinsemillaChip::::construct(config.1); + let chip2 = SinsemillaChip::::construct(config.2); - let commit_ivk = - CommitDomain::new(chip2.clone(), &SinsemillaCommitDomains::CommitIvk); - let r = ScalarFixed::>::new( + let commit_ivk = CommitDomain::new( chip2.clone(), + ecc_chip.clone(), + &SinsemillaCommitDomains::CommitIvk, + ); + let r = ScalarFixed::>::new( + ecc_chip, layouter.namespace(|| "r"), Some(C::Scalar::rand()), )?; @@ -382,7 +426,7 @@ mod tests { let message = Message::from_bitstring( chip2, layouter.namespace(|| "witness message"), - message.clone(), + message, 50, )?; commit_ivk.commit(layouter.namespace(|| "commit"), message, r)?; diff --git a/src/circuit/gadget/sinsemilla/chip.rs b/src/circuit/gadget/sinsemilla/chip.rs index 8ef568a22..c7f98d030 100644 --- a/src/circuit/gadget/sinsemilla/chip.rs +++ b/src/circuit/gadget/sinsemilla/chip.rs @@ -1,7 +1,4 @@ -use super::super::ecc::{ - chip::{CellValue, EccChip, EccConfig, EccPoint}, - EccInstructions, -}; +use super::super::ecc::chip::{CellValue, EccPoint}; use super::{CommitDomains, HashDomains, SinsemillaInstructions}; use crate::constants::OrchardFixedBasesFull; @@ -58,7 +55,6 @@ pub struct SinsemillaConfig { lambda: (Column, Column), perm: Permutation, generator_table: GeneratorTableConfig, - ecc_config: EccConfig, } #[derive(Clone, Debug)] @@ -103,15 +99,13 @@ impl SinsemillaChip { layouter: &mut impl Layouter, ) -> Result<>::Loaded, Error> { // Load the lookup table. - let generator_table_chip = - GeneratorTableChip::::construct(config.generator_table.clone()); + let generator_table_chip = GeneratorTableChip::::construct(config.generator_table); generator_table_chip.load(layouter) } #[allow(clippy::too_many_arguments)] pub fn configure( meta: &mut ConstraintSystem, - ecc_config: EccConfig, advices: [Column; 5], lookup: (Column, Column, Column), perm: Permutation, @@ -187,19 +181,21 @@ impl SinsemillaChip { lambda, perm, generator_table, - ecc_config, } } } // Impl SinsemillaInstructions for SinsemillaChip impl SinsemillaInstructions for SinsemillaChip { - type HashDomains = SinsemillaHashDomains; - type CommitDomains = SinsemillaCommitDomains; - type MessagePiece = MessagePiece; type CellValue = CellValue; + type Point = EccPoint; + type FixedPoints = OrchardFixedBasesFull; + + type HashDomains = SinsemillaHashDomains; + type CommitDomains = SinsemillaCommitDomains; + #[allow(non_snake_case)] fn witness_message( &self, @@ -214,7 +210,7 @@ impl SinsemillaInstructions for SinsemillaChip { // If message is shorter than the number of words specified, pad it to the // correct length. let pad_len = num_words * K - message.len(); - let mut message = message.clone(); + let mut message = message; message.extend_from_slice(&vec![None; pad_len]); message } else { @@ -263,7 +259,7 @@ impl SinsemillaInstructions for SinsemillaChip { // Closure to parse a vector of K-bit words into a base field element. let to_base_field = |words: &[Word]| -> Option { let bits = words - .into_iter() + .iter() .map(|word| word.0.to_vec()) .flatten() .collect::>>(); @@ -336,10 +332,6 @@ impl SinsemillaInstructions for SinsemillaChip { MessagePiece::new(cell.clone(), length) } - fn extract(point: &Self::Point) -> Self::X { - point.x.clone() - } - #[allow(non_snake_case)] fn hash_to_point( &self, @@ -355,107 +347,6 @@ impl SinsemillaInstructions for SinsemillaChip { } } -// Impl EccInstructions for SinsemillaChip -impl EccInstructions for SinsemillaChip { - type ScalarFixed = as EccInstructions>::ScalarFixed; - type ScalarFixedShort = as EccInstructions>::ScalarFixedShort; - type ScalarVar = as EccInstructions>::ScalarVar; - type Point = as EccInstructions>::Point; - type X = as EccInstructions>::X; - type FixedPoints = as EccInstructions>::FixedPoints; - type FixedPointsShort = as EccInstructions>::FixedPointsShort; - - fn witness_scalar_var( - &self, - layouter: &mut impl Layouter, - value: Option, - ) -> Result { - let ecc_chip = EccChip::::construct(self.config.ecc_config.clone()); - ecc_chip.witness_scalar_var(layouter, value) - } - - fn witness_scalar_fixed( - &self, - layouter: &mut impl Layouter, - value: Option, - ) -> Result { - let ecc_chip = EccChip::::construct(self.config.ecc_config.clone()); - ecc_chip.witness_scalar_fixed(layouter, value) - } - - fn witness_scalar_fixed_short( - &self, - layouter: &mut impl Layouter, - value: Option, - ) -> Result { - let ecc_chip = EccChip::::construct(self.config.ecc_config.clone()); - ecc_chip.witness_scalar_fixed_short(layouter, value) - } - - fn witness_point( - &self, - layouter: &mut impl Layouter, - value: Option, - ) -> Result { - let ecc_chip = EccChip::::construct(self.config.ecc_config.clone()); - ecc_chip.witness_point(layouter, value) - } - - fn extract_p(point: &Self::Point) -> &Self::X { - EccChip::::extract_p(point) - } - - fn add_incomplete( - &self, - layouter: &mut impl Layouter, - a: &Self::Point, - b: &Self::Point, - ) -> Result { - let ecc_chip = EccChip::::construct(self.config.ecc_config.clone()); - ecc_chip.add_incomplete(layouter, a, b) - } - - fn add( - &self, - layouter: &mut impl Layouter, - a: &Self::Point, - b: &Self::Point, - ) -> Result { - let ecc_chip = EccChip::::construct(self.config.ecc_config.clone()); - ecc_chip.add(layouter, a, b) - } - - fn mul( - &self, - layouter: &mut impl Layouter, - scalar: &Self::ScalarVar, - base: &Self::Point, - ) -> Result { - let ecc_chip = EccChip::::construct(self.config.ecc_config.clone()); - ecc_chip.mul(layouter, scalar, base) - } - - fn mul_fixed( - &self, - layouter: &mut impl Layouter, - scalar: &Self::ScalarFixed, - base: &Self::FixedPoints, - ) -> Result { - let ecc_chip = EccChip::::construct(self.config.ecc_config.clone()); - ecc_chip.mul_fixed(layouter, scalar, base) - } - - fn mul_fixed_short( - &self, - layouter: &mut impl Layouter, - scalar: &Self::ScalarFixedShort, - base: &Self::FixedPointsShort, - ) -> Result { - let ecc_chip = EccChip::::construct(self.config.ecc_config.clone()); - ecc_chip.mul_fixed_short(layouter, scalar, base) - } -} - #[derive(Clone, Debug)] pub enum SinsemillaHashDomains { NoteCommit, @@ -463,6 +354,7 @@ pub enum SinsemillaHashDomains { MerkleCrh, } +#[allow(non_snake_case)] impl HashDomains for SinsemillaHashDomains { fn Q(&self) -> C { match self { diff --git a/src/circuit/gadget/sinsemilla/chip/hash_to_point.rs b/src/circuit/gadget/sinsemilla/chip/hash_to_point.rs index 5a9cda214..6a789ee62 100644 --- a/src/circuit/gadget/sinsemilla/chip/hash_to_point.rs +++ b/src/circuit/gadget/sinsemilla/chip/hash_to_point.rs @@ -16,8 +16,8 @@ pub(super) fn hash_message( Q: C, message: &[MessagePiece], ) -> Result, Error> { - let x_q = Q.coordinates().unwrap().x().clone(); - let y_q = Q.coordinates().unwrap().y().clone(); + let x_q = *Q.coordinates().unwrap().x(); + let y_q = *Q.coordinates().unwrap().y(); // Assign the `x`-coordinate of our starting `Q` base. let x_q_cell = region.assign_advice(|| "x_q", config.x_a, 0, || Ok(x_q))?; @@ -29,7 +29,7 @@ pub(super) fn hash_message( let mut offset = 0; for piece in message.iter() { let a = hash_piece::(region, config.clone(), offset, piece, x_a, y_a)?; - offset = offset + piece.length; + offset += piece.length; x_a = a.0; y_a = a.1; } @@ -85,6 +85,7 @@ pub(super) fn hash_message( }) } +#[allow(clippy::type_complexity)] // Hash a message piece containing `piece.length` number of `K`-bit words. fn hash_piece( region: &mut Region<'_, C::Base>,