Skip to content

Commit

Permalink
gadget::sinsemilla.rs: Add Sinsemilla test.
Browse files Browse the repository at this point in the history
  • Loading branch information
therealyingtong committed Jun 6, 2021
1 parent d692304 commit 96290d9
Show file tree
Hide file tree
Showing 2 changed files with 203 additions and 1 deletion.
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
199 changes: 198 additions & 1 deletion src/circuit/gadget/sinsemilla.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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<C: CurveAffine, const K: usize, const MAX_WORDS: usize> {
_marker: std::marker::PhantomData<C>,
}

impl<C: CurveAffine, const K: usize, const MAX_WORDS: usize> Circuit<C::Base>
for MyCircuit<C, K, MAX_WORDS>
{
type Config = (
EccConfig,
SinsemillaConfig<C, K, MAX_WORDS>,
SinsemillaConfig<C, K, MAX_WORDS>,
);

#[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, perm.clone());

// Fixed columns for the Sinsemilla generator lookup table
let lookup = (
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
);

let config1 = SinsemillaChip::<C, K, MAX_WORDS>::configure(
meta,
advices[..5].try_into().unwrap(),
lookup,
perm.clone(),
);
let config2 = SinsemillaChip::<C, K, MAX_WORDS>::configure(
meta,
advices[5..].try_into().unwrap(),
lookup,
perm,
);
(ecc_config, config1, config2)
}

fn synthesize(
&self,
cs: &mut impl Assignment<C::Base>,
config: Self::Config,
) -> Result<(), Error> {
let mut layouter = SingleChipLayouter::new(cs)?;
let ecc_chip = EccChip::<C>::construct(config.0);

// The two `SinsemillaChip`s share the same lookup table.
SinsemillaChip::<C, K, MAX_WORDS>::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::<C, K, MAX_WORDS>::construct(config.1);

let merkle_crh = HashDomain::new(
chip1.clone(),
ecc_chip.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,
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<Option<bool>> =
(0..250).map(|_| Some(rand::random::<bool>())).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::<C, K, MAX_WORDS>::construct(config.2);

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

0 comments on commit 96290d9

Please sign in to comment.