Skip to content

Commit

Permalink
Add Sinsemilla test
Browse files Browse the repository at this point in the history
  • Loading branch information
therealyingtong committed Jun 2, 2021
1 parent d037c65 commit 14b2bbc
Show file tree
Hide file tree
Showing 3 changed files with 177 additions and 0 deletions.
5 changes: 5 additions & 0 deletions src/circuit/gadget/ecc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,11 @@ impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> X<C, EccC
pub fn from_inner(chip: EccChip, inner: EccChip::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
Expand Down
1 change: 1 addition & 0 deletions src/circuit/gadget/ecc/chip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ impl<C: CurveAffine> EccChip<C> {
advices[2].into(),
advices[3].into(),
advices[4].into(),
advices[5].into(),
advices[6].into(),
advices[7].into(),
advices[8].into(),
Expand Down
171 changes: 171 additions & 0 deletions src/circuit/gadget/sinsemilla.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<C: CurveAffine>: EccInstructions<C> {
Expand Down Expand Up @@ -230,3 +231,173 @@ impl<C: CurveAffine, SinsemillaChip: SinsemillaInstructions<C> + 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<C: CurveAffine> {
_marker: std::marker::PhantomData<C>,
}

impl<C: CurveAffine> Circuit<C::Base> for MyCircuit<C> {
type Config = (SinsemillaConfig, SinsemillaConfig);

#[allow(non_snake_case)]
fn configure(meta: &mut ConstraintSystem<C::Base>) -> 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::<Vec<_>>(),
);

let ecc_config = EccChip::<C>::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::<C>::configure(
meta,
ecc_config.clone(),
advices[..5].try_into().unwrap(),
lookup,
perm.clone(),
);
let config2 = SinsemillaChip::<C>::configure(
meta,
ecc_config.clone(),
advices[5..].try_into().unwrap(),
lookup,
perm,
);
(config1, config2)
}

fn synthesize(
&self,
cs: &mut impl Assignment<C::Base>,
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::<C>::load(config.0.clone(), &mut layouter)?;
let chip1 = SinsemillaChip::<C>::construct(config.0, loaded1);

let merkle_crh = HashDomain::new(chip1.clone(), &SinsemillaHashDomains::MerkleCrh);

// Left leaf
let left = {
let left: Vec<Option<bool>> =
(0..250).map(|_| Some(rand::random::<bool>())).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<Option<bool>> =
(0..250).map(|_| Some(rand::random::<bool>())).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::<C>::load(config.1.clone(), &mut layouter)?;
let chip2 = SinsemillaChip::<C>::construct(config.1, loaded2);

let commit_ivk =
CommitDomain::new(chip2.clone(), &SinsemillaCommitDomains::CommitIvk);
let r = ScalarFixed::<C, SinsemillaChip<C>>::new(
chip2.clone(),
layouter.namespace(|| "r"),
Some(C::Scalar::rand()),
)?;
let message: Vec<Option<bool>> =
(0..501).map(|_| Some(rand::random::<bool>())).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::<pallas::Affine> {
_marker: std::marker::PhantomData,
};
let prover = MockProver::run(k, &circuit, vec![]).unwrap();
assert_eq!(prover.verify(), Ok(()))
}
}

0 comments on commit 14b2bbc

Please sign in to comment.