Skip to content

Commit

Permalink
Fix Sinsemilla chip to work with config abstraction
Browse files Browse the repository at this point in the history
  • Loading branch information
therealyingtong committed Apr 23, 2021
1 parent 9b1ba08 commit 2ad868a
Show file tree
Hide file tree
Showing 4 changed files with 895 additions and 220 deletions.
237 changes: 191 additions & 46 deletions src/circuit/gadget/sinsemilla.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,39 @@ use crate::circuit::gadget::ecc::{self, EccInstructions};
use halo2::{arithmetic::CurveAffine, circuit::Layouter, plonk::Error};
use std::fmt;

mod chip;
// pub use chip::{SinsemillaChip, SinsemillaColumns, SinsemillaConfig};

/// Trait allowing circuit's Sinsemilla HashDomains to be enumerated.
pub trait HashDomains<C: CurveAffine>: Clone + fmt::Debug {}

/// Trait allowing circuit's Sinsemilla CommitDomains to be enumerated.
pub trait CommitDomains<C: CurveAffine, F: ecc::FixedPoints<C>, H: HashDomains<C>>:
Clone + fmt::Debug
{
/// Returns the fixed point corresponding to the R constant for this CommitDomain.
fn r(&self) -> F;

/// Returns the HashDomain contained in this CommitDomain
fn hash_domain(&self) -> H;
}
pub mod chip;
pub use chip::{
Message, SinsemillaChip, SinsemillaCommitDomains, SinsemillaConfigEnum, 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> {
/// Witnessed message.
type Message: Clone + fmt::Debug;
/// Variable representing the set of CommitDomains in the circuit.
/// HashDomains used in this instruction.
type HashDomains: HashDomains<C>;
/// CommitDomains used in this instruction.
type CommitDomains: CommitDomains<
C,
<Self as EccInstructions<C>>::FixedPoints,
Self::HashDomains,
>;
/// Variable representing the set of HashDomains in the circuit.
type HashDomains: HashDomains<C>;
/// Variable representing a Q fixed point for a HashDomain.
type Q: Clone + fmt::Debug;

/// Witnessed message.
type Message: Clone + fmt::Debug;

/// Gets the Q constant for the given domain.
#[allow(non_snake_case)]
fn get_Q(
layouter: &mut impl Layouter<Self>,
&self,
layouter: &mut impl Layouter<C::Base>,
domain: &Self::HashDomains,
) -> Result<Self::Q, Error>;

/// Witnesses a message in the form of a bitstring.
fn witness_message(
layouter: &mut impl Layouter<Self>,
&self,
layouter: &mut impl Layouter<C::Base>,
message: Vec<bool>,
) -> Result<Self::Message, Error>;

Expand All @@ -55,66 +46,96 @@ pub trait SinsemillaInstructions<C: CurveAffine>: EccInstructions<C> {
/// Hashes a message to an ECC curve point.
#[allow(non_snake_case)]
fn hash_to_point(
layouter: &mut impl Layouter<Self>,
&self,
layouter: &mut impl Layouter<C::Base>,
Q: &Self::Q,
message: Self::Message,
) -> Result<Self::Point, Error>;
}

/// Trait allowing circuit's Sinsemilla HashDomains to be enumerated.
#[allow(non_snake_case)]
pub trait HashDomains<C: CurveAffine>: Clone + fmt::Debug {
fn Q(&self) -> C;
}

#[allow(non_snake_case)]
pub struct HashDomain<C: CurveAffine, SinsemillaChip: SinsemillaInstructions<C>> {
Q: SinsemillaChip::Q,
pub Q: SinsemillaChip::Q,
}

impl<C: CurveAffine, SinsemillaChip: SinsemillaInstructions<C>> HashDomain<C, SinsemillaChip> {
#[allow(non_snake_case)]
/// Constructs a new `HashDomain` for the given domain.
pub fn new(
mut layouter: impl Layouter<SinsemillaChip>,
domain: &SinsemillaChip::HashDomains,
chip: SinsemillaChip,
mut layouter: impl Layouter<C::Base>,
domain: &<SinsemillaChip as SinsemillaInstructions<C>>::HashDomains,
) -> Result<Self, Error> {
SinsemillaChip::get_Q(&mut layouter, domain).map(|Q| HashDomain { Q })
chip.get_Q(&mut layouter, domain).map(|Q| HashDomain { Q })
}

/// $\mathsf{SinsemillaHashToPoint}$ from [§ 5.4.1.9][concretesinsemillahash].
///
/// [concretesinsemillahash]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillahash
pub fn hash_to_point(
&self,
mut layouter: impl Layouter<SinsemillaChip>,
message: <SinsemillaChip as SinsemillaInstructions<C>>::Message,
chip: SinsemillaChip,
mut layouter: impl Layouter<C::Base>,
message: Vec<bool>,
) -> Result<ecc::Point<C, SinsemillaChip>, Error> {
SinsemillaChip::hash_to_point(&mut layouter, &self.Q, message).map(ecc::Point::from_inner)
let message = chip.witness_message(&mut layouter, message)?;
chip.hash_to_point(&mut layouter, &self.Q, message)
.map(ecc::Point::from_inner)
}

/// $\mathsf{SinsemillaHash}$ from [§ 5.4.1.9][concretesinsemillahash].
///
/// [concretesinsemillahash]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillahash
pub fn hash(
&self,
layouter: impl Layouter<SinsemillaChip>,
message: <SinsemillaChip as SinsemillaInstructions<C>>::Message,
chip: SinsemillaChip,
layouter: impl Layouter<C::Base>,
message: Vec<bool>,
) -> Result<ecc::X<C, SinsemillaChip>, Error> {
let p = self.hash_to_point(layouter, message);
let p = self.hash_to_point(chip, layouter, message);
p.map(|p| p.extract_p())
}
}

/// Trait allowing circuit's Sinsemilla CommitDomains to be enumerated.
pub trait CommitDomains<C: CurveAffine, F: ecc::FixedPoints<C>, H: HashDomains<C>>:
Clone + fmt::Debug
{
/// Returns the fixed point corresponding to the R constant for this CommitDomain.
fn r(&self) -> F;

/// Returns the HashDomain contained in this CommitDomain
fn hash_domain(&self) -> H;
}

#[allow(non_snake_case)]
pub struct CommitDomain<C: CurveAffine, SinsemillaChip: SinsemillaInstructions<C>> {
M: HashDomain<C, SinsemillaChip>,
R: ecc::FixedPoint<C, SinsemillaChip>,
}

impl<C: CurveAffine, SinsemillaChip: SinsemillaInstructions<C>> CommitDomain<C, SinsemillaChip> {
impl<C: CurveAffine, SinsemillaChip: Clone + SinsemillaInstructions<C>>
CommitDomain<C, SinsemillaChip>
{
/// Constructs a new `CommitDomain` for the given domain.
pub fn new(
mut layouter: impl Layouter<SinsemillaChip>,
chip: SinsemillaChip,
mut layouter: impl Layouter<C::Base>,
domain: &SinsemillaChip::CommitDomains,
) -> Result<Self, Error> {
Ok(CommitDomain {
M: HashDomain::new(layouter.namespace(|| "M"), &domain.hash_domain())?,
R: ecc::FixedPoint::get(layouter.namespace(|| "R"), domain.r())?,
M: HashDomain::new(
chip.clone(),
layouter.namespace(|| "M"),
&domain.hash_domain(),
)?,
R: ecc::FixedPoint::get(chip, domain.r())?,
})
}

Expand All @@ -123,26 +144,150 @@ impl<C: CurveAffine, SinsemillaChip: SinsemillaInstructions<C>> CommitDomain<C,
/// [concretesinsemillacommit]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit
pub fn commit(
&self,
mut layouter: impl Layouter<SinsemillaChip>,
message: <SinsemillaChip as SinsemillaInstructions<C>>::Message,
chip: SinsemillaChip,
mut layouter: impl Layouter<C::Base>,
message: Vec<bool>,
r: ecc::ScalarFixed<C, SinsemillaChip>,
) -> Result<ecc::Point<C, SinsemillaChip>, Error> {
let blind = self.R.mul(layouter.namespace(|| "[r] R"), &r)?;
let blind = self
.R
.mul(chip.clone(), layouter.namespace(|| "[r] R"), &r)?;
self.M
.hash_to_point(layouter.namespace(|| "M"), message)?
.add(layouter.namespace(|| "M + [r] R"), &blind)
.hash_to_point(chip.clone(), layouter.namespace(|| "M"), message)?
.add(chip, layouter.namespace(|| "M + [r] R"), &blind)
}

/// $\mathsf{SinsemillaShortCommit}$ from [§ 5.4.8.4][concretesinsemillacommit].
///
/// [concretesinsemillacommit]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit
pub fn short_commit(
&self,
mut layouter: impl Layouter<SinsemillaChip>,
message: <SinsemillaChip as SinsemillaInstructions<C>>::Message,
chip: SinsemillaChip,
mut layouter: impl Layouter<C::Base>,
message: Vec<bool>,
r: ecc::ScalarFixed<C, SinsemillaChip>,
) -> Result<ecc::X<C, SinsemillaChip>, Error> {
let p = self.commit(layouter.namespace(|| "commit"), message, r);
let p = self.commit(chip, layouter.namespace(|| "commit"), message, r);
p.map(|p| p.extract_p())
}
}

#[cfg(test)]
mod tests {
use halo2::{
arithmetic::{CurveAffine, FieldExt},
circuit::{layouter::SingleChipLayouter, Chip, Layouter, Loaded},
dev::MockProver,
pasta::pallas,
plonk::{Assignment, Circuit, ConstraintSystem, Error, Permutation},
};
use std::collections::BTreeMap;

use super::{
CommitDomain, HashDomain, SinsemillaChip, SinsemillaCommitDomains, SinsemillaConfigEnum,
SinsemillaHashDomains,
};
use crate::circuit::gadget::ecc::ScalarFixed;

struct MyCircuit<C: CurveAffine> {
_marker: std::marker::PhantomData<C>,
}

impl<C: CurveAffine> Circuit<C::Base> for MyCircuit<C> {
type Config = SinsemillaConfigEnum;

fn configure(meta: &mut ConstraintSystem<C::Base>) -> Self::Config {
let mut columns = BTreeMap::new();
let bits = meta.advice_column();
let x_p = meta.advice_column();
let y_p = meta.advice_column();
let x_a = meta.advice_column();
let y_a = meta.advice_column();

columns.insert("bits", bits.into());
columns.insert("u", meta.advice_column().into());

columns.insert("x_a", x_a.into());
columns.insert("y_a", y_a.into());

columns.insert("x_p", x_p.into());
columns.insert("y_p", y_p.into());

columns.insert("lambda1", meta.advice_column().into());
columns.insert("lambda2", meta.advice_column().into());

columns.insert("inv_alpha", meta.advice_column().into());
columns.insert("inv_beta", meta.advice_column().into());
columns.insert("inv_gamma", meta.advice_column().into());
columns.insert("inv_delta", meta.advice_column().into());

columns.insert("bool_a", meta.advice_column().into());
columns.insert("bool_b", meta.advice_column().into());
columns.insert("bool_c", meta.advice_column().into());
columns.insert("bool_d", meta.advice_column().into());

let mut perms = BTreeMap::new();
perms.insert("perm_bits", Permutation::new(meta, &[bits.into()]));
perms.insert(
"perm_sum",
Permutation::new(meta, &[x_p.into(), y_p.into(), x_a.into(), y_a.into()]),
);

let mut chip = SinsemillaChip::<C>::new();
chip.configure(meta, BTreeMap::new(), columns, perms)
}

fn synthesize(
&self,
cs: &mut impl Assignment<C::Base>,
config: Self::Config,
) -> Result<(), Error> {
let mut chip = SinsemillaChip::<C>::construct(
config,
<SinsemillaChip<C> as Chip<C::Base>>::Loaded::empty(),
);
let mut layouter = SingleChipLayouter::new(cs)?;
chip.load(&mut layouter)?;

let merkle_crh = HashDomain::new(
chip.clone(),
layouter.namespace(|| "merkle_crh"),
&SinsemillaHashDomains::MerkleCrh,
)?;
merkle_crh.hash_to_point(
chip.clone(),
layouter.namespace(|| "hash_to_point"),
vec![true, true, false, false],
)?;

let commit_ivk = CommitDomain::new(
chip.clone(),
layouter.namespace(|| "commit_ivk"),
&SinsemillaCommitDomains::CommitIvk,
)?;
let r = ScalarFixed::<C, SinsemillaChip<C>>::new(
chip.clone(),
layouter.namespace(|| "r"),
Some(C::Scalar::rand()),
)?;
commit_ivk.commit(
chip.clone(),
layouter.namespace(|| "commit"),
vec![true, true, false, false],
r,
)?;

Ok(())
}
}

#[test]
fn sinsemilla_gadget() {
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(()))
}
}
Loading

0 comments on commit 2ad868a

Please sign in to comment.