From 2b254f83ab23a34e229e64d5f56a6dad0030a3bb Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Sat, 5 Jun 2021 16:28:52 +0800 Subject: [PATCH] gadget::sinsemilla.rs: Add Sinsemilla test. --- src/circuit/gadget/ecc.rs | 5 + src/circuit/gadget/sinsemilla.rs | 199 ++++++++++++++++++++++++++++++- 2 files changed, 203 insertions(+), 1 deletion(-) diff --git a/src/circuit/gadget/ecc.rs b/src/circuit/gadget/ecc.rs index 86abd9b55..bcbc9135a 100644 --- a/src/circuit/gadget/ecc.rs +++ b/src/circuit/gadget/ecc.rs @@ -301,6 +301,11 @@ impl + Clone + Debug + Eq> X Self { X { chip, inner } } + + /// Returns the inner `EccChip::X` representation in the circuit + pub fn inner(&self) -> &EccChip::X { + &self.inner + } } /// A constant elliptic curve point over the given curve, for which window tables have diff --git a/src/circuit/gadget/sinsemilla.rs b/src/circuit/gadget/sinsemilla.rs index 6cfb97372..79e5032ab 100644 --- a/src/circuit/gadget/sinsemilla.rs +++ b/src/circuit/gadget/sinsemilla.rs @@ -6,7 +6,7 @@ use std::fmt::Debug; pub mod chip; mod message; -// pub use chip::{SinsemillaChip, SinsemillaConfig}; +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. /// This trait is bounded on two constant parameters: `K`, the number of bits @@ -303,3 +303,200 @@ where p.map(|p| p.extract_p()) } } + +#[cfg(test)] +mod tests { + use halo2::{ + arithmetic::{CurveAffine, FieldExt}, + circuit::{layouter::SingleChipLayouter, Layouter}, + dev::MockProver, + pasta::pallas, + plonk::{Assignment, Circuit, ConstraintSystem, Error}, + }; + + use super::{ + chip::{SinsemillaCommitDomains, SinsemillaHashDomains}, + CommitDomain, HashDomain, Message, SinsemillaChip, SinsemillaConfig, + SinsemillaInstructions, + }; + + use crate::circuit::gadget::{ + ecc::{ + chip::{EccChip, EccConfig}, + ScalarFixed, + }, + utilities::Var, + }; + + use std::convert::TryInto; + + struct MyCircuit { + _marker: std::marker::PhantomData, + } + + impl Circuit + for MyCircuit + { + type Config = ( + EccConfig, + SinsemillaConfig, + SinsemillaConfig, + ); + + #[allow(non_snake_case)] + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + let advices = [ + meta.advice_column(), + meta.advice_column(), + meta.advice_column(), + meta.advice_column(), + meta.advice_column(), + meta.advice_column(), + meta.advice_column(), + meta.advice_column(), + meta.advice_column(), + meta.advice_column(), + ]; + let perm = meta.permutation( + &advices + .iter() + .map(|advice| (*advice).into()) + .collect::>(), + ); + + let ecc_config = EccChip::::configure(meta, advices, perm.clone()); + + // Fixed columns for the Sinsemilla generator lookup table + let lookup = ( + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + ); + + let config1 = SinsemillaChip::::configure( + meta, + advices[..5].try_into().unwrap(), + lookup, + perm.clone(), + ); + let config2 = SinsemillaChip::::configure( + meta, + advices[5..].try_into().unwrap(), + lookup, + perm, + ); + (ecc_config, config1, config2) + } + + fn synthesize( + &self, + cs: &mut impl Assignment, + 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.1.clone(), &mut layouter)?; + + // This MerkleCRH example is purely for illustrative purposes. + // It is not an implementation of the Orchard protocol spec. + { + let chip1 = SinsemillaChip::::construct(config.1); + + let merkle_crh = HashDomain::new( + chip1.clone(), + ecc_chip.clone(), + &SinsemillaHashDomains::MerkleCrh, + ); + + // Left leaf + let left = { + let left: Vec> = + (0..250).map(|_| Some(rand::random::())).collect(); + let left = Message::from_bitstring( + chip1.clone(), + layouter.namespace(|| "witness left"), + left, + 25, + )?; + let left = merkle_crh.hash_to_point(layouter.namespace(|| "left"), left)?; + let left = left.extract_p(); + chip1.witness_message_piece_field( + layouter.namespace(|| "witness left piece"), + left.inner().value(), + 25, + )? + }; + + // Right leaf + let right = { + let right: Vec> = + (0..250).map(|_| Some(rand::random::())).collect(); + let right = Message::from_bitstring( + chip1.clone(), + layouter.namespace(|| "witness right"), + right, + 25, + )?; + let right = merkle_crh.hash_to_point(layouter.namespace(|| "right"), right)?; + let right = right.extract_p(); + chip1.witness_message_piece_field( + layouter.namespace(|| "witness left piece"), + right.inner().value(), + 25, + )? + }; + + // Layer 0 + let l = { + let merkle_depth_orchard = 32; + let layer = 0; + let l = C::Base::from_u64(merkle_depth_orchard - 1 - layer); + chip1.witness_message_piece_field(layouter.namespace(|| "l"), Some(l), 1)? + }; + + // Parent + let parent = Message::from_pieces(chip1, vec![l, left, right]); + merkle_crh.hash_to_point(layouter.namespace(|| "parent"), parent)?; + } + + { + let chip2 = SinsemillaChip::::construct(config.2); + + 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()), + )?; + let message: Vec> = + (0..500).map(|_| Some(rand::random::())).collect(); + let message = Message::from_bitstring( + chip2, + layouter.namespace(|| "witness message"), + message, + 50, + )?; + commit_ivk.commit(layouter.namespace(|| "commit"), message, r)?; + } + + Ok(()) + } + } + + #[test] + fn sinsemilla() { + use crate::primitives::sinsemilla::{C, K}; + let k = 11; + let circuit = MyCircuit:: { + _marker: std::marker::PhantomData, + }; + let prover = MockProver::run(k, &circuit, vec![]).unwrap(); + assert_eq!(prover.verify(), Ok(())) + } +}