From 14b2bbced733a129cab0b7359a68417b79d81079 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Tue, 25 May 2021 22:59:33 +0800 Subject: [PATCH] Add Sinsemilla test --- src/circuit/gadget/ecc.rs | 5 + src/circuit/gadget/ecc/chip.rs | 1 + src/circuit/gadget/sinsemilla.rs | 171 +++++++++++++++++++++++++++++++ 3 files changed, 177 insertions(+) diff --git a/src/circuit/gadget/ecc.rs b/src/circuit/gadget/ecc.rs index 986a9621d..0bcda1d88 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/ecc/chip.rs b/src/circuit/gadget/ecc/chip.rs index 1bc282b07..0ca7cc1be 100644 --- a/src/circuit/gadget/ecc/chip.rs +++ b/src/circuit/gadget/ecc/chip.rs @@ -162,6 +162,7 @@ impl EccChip { advices[2].into(), advices[3].into(), advices[4].into(), + advices[5].into(), advices[6].into(), advices[7].into(), advices[8].into(), diff --git a/src/circuit/gadget/sinsemilla.rs b/src/circuit/gadget/sinsemilla.rs index 4fba3239f..d57761a96 100644 --- a/src/circuit/gadget/sinsemilla.rs +++ b/src/circuit/gadget/sinsemilla.rs @@ -4,6 +4,7 @@ use halo2::{arithmetic::CurveAffine, circuit::Layouter, plonk::Error}; use std::fmt::Debug; pub mod chip; +pub use chip::{SinsemillaChip, SinsemillaCommitDomains, SinsemillaConfig, SinsemillaHashDomains}; /// The set of circuit instructions required to use the [`Sinsemilla`](https://zcash.github.io/halo2/design/gadgets/sinsemilla.html) gadget. pub trait SinsemillaInstructions: EccInstructions { @@ -230,3 +231,173 @@ impl + Clone + Debug + 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::{ + CommitDomain, HashDomain, Message, SinsemillaChip, SinsemillaCommitDomains, + SinsemillaConfig, SinsemillaHashDomains, SinsemillaInstructions, + }; + + use crate::circuit::gadget::ecc::{chip::EccChip, ScalarFixed}; + + use rand; + use std::convert::TryInto; + + struct MyCircuit { + _marker: std::marker::PhantomData, + } + + impl Circuit for MyCircuit { + type Config = (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); + + // Fixed columns for the Sinsemilla generator lookup table + let lookup = ( + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + ); + + 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) + } + + fn synthesize( + &self, + cs: &mut impl Assignment, + config: Self::Config, + ) -> Result<(), Error> { + let mut layouter = SingleChipLayouter::new(cs)?; + + // 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 loaded1 = SinsemillaChip::::load(config.0.clone(), &mut layouter)?; + let chip1 = SinsemillaChip::::construct(config.0, loaded1); + + let merkle_crh = HashDomain::new(chip1.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.clone(), + 25, + )?; + let left = merkle_crh.hash_to_point(layouter.namespace(|| "left"), left)?; + let left = left.extract_p(); + Message::new_piece(chip1.clone(), left.inner(), 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.clone(), + 25, + )?; + let right = merkle_crh.hash_to_point(layouter.namespace(|| "right"), right)?; + let right = right.extract_p(); + Message::new_piece(chip1.clone(), right.inner(), 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.clone(), vec![l, left, right]); + merkle_crh.hash_to_point(layouter.namespace(|| "parent"), parent)?; + } + + { + let loaded2 = SinsemillaChip::::load(config.1.clone(), &mut layouter)?; + let chip2 = SinsemillaChip::::construct(config.1, loaded2); + + let commit_ivk = + CommitDomain::new(chip2.clone(), &SinsemillaCommitDomains::CommitIvk); + let r = ScalarFixed::>::new( + chip2.clone(), + layouter.namespace(|| "r"), + Some(C::Scalar::rand()), + )?; + let message: Vec> = + (0..501).map(|_| Some(rand::random::())).collect(); + let message = Message::from_bitstring( + chip2, + layouter.namespace(|| "witness message"), + message.clone(), + 50, + )?; + commit_ivk.commit(layouter.namespace(|| "commit"), message, r)?; + } + + Ok(()) + } + } + + #[test] + fn sinsemilla() { + let k = 11; + let circuit = MyCircuit:: { + _marker: std::marker::PhantomData, + }; + let prover = MockProver::run(k, &circuit, vec![]).unwrap(); + assert_eq!(prover.verify(), Ok(())) + } +}