From 84172e0326c2c23abd689a46ef6bb9ff7108ec67 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Wed, 16 Jun 2021 17:47:58 +0800 Subject: [PATCH] note_commit.rs: Test canonicity check for different input values. --- src/circuit/gadget/sinsemilla/note_commit.rs | 252 +++++++++++++++++++ 1 file changed, 252 insertions(+) diff --git a/src/circuit/gadget/sinsemilla/note_commit.rs b/src/circuit/gadget/sinsemilla/note_commit.rs index da8c20a9..8cbf5741 100644 --- a/src/circuit/gadget/sinsemilla/note_commit.rs +++ b/src/circuit/gadget/sinsemilla/note_commit.rs @@ -1271,3 +1271,255 @@ struct GateCells { z13_f: CellValue, z13_g: CellValue, } + +#[cfg(test)] +mod tests { + use super::NoteCommitConfig; + use crate::{ + circuit::gadget::{ + ecc::{ + chip::{EccChip, EccConfig}, + Point, + }, + sinsemilla::chip::SinsemillaChip, + utilities::{CellValue, UtilitiesInstructions}, + }, + constants::T_Q, + }; + + use ff::Field; + use halo2::{ + circuit::{Layouter, SimpleFloorPlanner}, + dev::MockProver, + plonk::{Circuit, ConstraintSystem, Error}, + }; + use pasta_curves::{ + arithmetic::{CurveAffine, FieldExt}, + pallas, + }; + + use rand::{rngs::OsRng, RngCore}; + use std::convert::TryInto; + + #[test] + fn note_commit() { + #[derive(Default)] + struct MyCircuit { + gd_x: Option, + pkd_x: Option, + rho: Option, + psi: Option, + } + + impl UtilitiesInstructions for MyCircuit { + type Var = CellValue; + } + + impl Circuit for MyCircuit { + type Config = (NoteCommitConfig, EccConfig); + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + Self::default() + } + + 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(), + ]; + + // Shared fixed columns for loading constants. + // TODO: Replace with public inputs API. + let ecc_constants = [meta.fixed_column(), meta.fixed_column()]; + let sinsemilla_constants = [ + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + ]; + + for advice in advices.iter() { + meta.enable_equality((*advice).into()); + } + for fixed in ecc_constants.iter() { + meta.enable_equality((*fixed).into()); + } + for fixed in sinsemilla_constants.iter() { + meta.enable_equality((*fixed).into()); + } + + let table_idx = meta.fixed_column(); + let lookup = (table_idx, meta.fixed_column(), meta.fixed_column()); + let sinsemilla_config = SinsemillaChip::configure( + meta, + advices[..5].try_into().unwrap(), + lookup, + sinsemilla_constants, + ); + let note_commit_config = + NoteCommitConfig::configure(meta, advices, sinsemilla_config); + + let ecc_config = EccChip::configure(meta, advices, table_idx, ecc_constants); + + (note_commit_config, ecc_config) + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + 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)?; + + // Construct a Sinsemilla chip + let sinsemilla_chip = + SinsemillaChip::construct(note_commit_config.sinsemilla_config.clone()); + + // Construct an ECC chip + let ecc_chip = EccChip::construct(ecc_config); + + // Witness g_d + let g_d = { + let g_d = self.gd_x.map(|x| { + // Calculate y = (x^3 + 5).sqrt() + let y = (x.square() * x + pallas::Affine::b()).sqrt().unwrap(); + pallas::Affine::from_xy(x, y).unwrap() + }); + + Point::new(ecc_chip.clone(), layouter.namespace(|| "witness g_d"), g_d)? + }; + + // Witness pk_d + let pk_d = { + let pk_d = self.pkd_x.map(|x| { + // Calculate y = (x^3 + 5).sqrt() + let y = (x.square() * x + pallas::Affine::b()).sqrt().unwrap(); + pallas::Affine::from_xy(x, y).unwrap() + }); + + Point::new( + ecc_chip.clone(), + layouter.namespace(|| "witness pk_d"), + pk_d, + )? + }; + + // Witness a random non-negative u64 note value + // A note value cannot be negative. + let value = { + let mut rng = OsRng; + let value = pallas::Base::from_u64(rng.next_u64()); + self.load_private( + layouter.namespace(|| "witness value"), + note_commit_config.advices[0], + Some(value), + )? + }; + + // Witness rho + let rho = self.load_private( + layouter.namespace(|| "witness rho"), + note_commit_config.advices[0], + self.rho, + )?; + + // Witness psi + let psi = self.load_private( + layouter.namespace(|| "witness psi"), + note_commit_config.advices[0], + self.psi, + )?; + + let rcm = Some(pallas::Scalar::rand()); + + let _cm = note_commit_config.assign_region( + layouter.namespace(|| "Hash NoteCommit pieces"), + sinsemilla_chip, + ecc_chip, + g_d.inner(), + pk_d.inner(), + value, + rho, + psi, + rcm, + )?; + + Ok(()) + } + } + + let two_pow_254 = pallas::Base::from_u128(1 << 127).square(); + // Test different values of `ak`, `nk` + let circuits = [ + // `gd_x` = -1, `pkd_x` = -1 (these have to be x-coordinates of curve points) + // `rho` = 0, `psi` = 0 + MyCircuit { + gd_x: Some(-pallas::Base::one()), + pkd_x: Some(-pallas::Base::one()), + rho: Some(pallas::Base::zero()), + psi: Some(pallas::Base::zero()), + }, + // `rho` = T_Q - 1, `psi` = T_Q - 1 + MyCircuit { + gd_x: Some(-pallas::Base::one()), + pkd_x: Some(-pallas::Base::one()), + rho: Some(pallas::Base::from_u128(T_Q - 1)), + psi: Some(pallas::Base::from_u128(T_Q - 1)), + }, + // `rho` = T_Q, `psi` = T_Q + MyCircuit { + gd_x: Some(-pallas::Base::one()), + pkd_x: Some(-pallas::Base::one()), + rho: Some(pallas::Base::from_u128(T_Q)), + psi: Some(pallas::Base::from_u128(T_Q)), + }, + // `rho` = 2^127 - 1, `psi` = 2^127 - 1 + MyCircuit { + gd_x: Some(-pallas::Base::one()), + pkd_x: Some(-pallas::Base::one()), + rho: Some(pallas::Base::from_u128((1 << 127) - 1)), + psi: Some(pallas::Base::from_u128((1 << 127) - 1)), + }, + // `rho` = 2^127, `psi` = 2^127 + MyCircuit { + gd_x: Some(-pallas::Base::one()), + pkd_x: Some(-pallas::Base::one()), + rho: Some(pallas::Base::from_u128(1 << 127)), + psi: Some(pallas::Base::from_u128(1 << 127)), + }, + // `rho` = 2^254 - 1, `psi` = 2^254 - 1 + MyCircuit { + gd_x: Some(-pallas::Base::one()), + pkd_x: Some(-pallas::Base::one()), + rho: Some(two_pow_254 - pallas::Base::one()), + psi: Some(two_pow_254 - pallas::Base::one()), + }, + // `rho` = 2^254, `psi` = 2^254 + MyCircuit { + gd_x: Some(-pallas::Base::one()), + pkd_x: Some(-pallas::Base::one()), + rho: Some(two_pow_254), + psi: Some(two_pow_254), + }, + ]; + + for circuit in circuits.iter() { + let prover = MockProver::::run(11, circuit, vec![]).unwrap(); + assert_eq!(prover.verify(), Ok(())); + } + } +}