Skip to content

Commit

Permalink
Remove SinsemillaInstructions: EccInstructions trait bound
Browse files Browse the repository at this point in the history
  • Loading branch information
therealyingtong committed Jun 4, 2021
1 parent f7e9002 commit 7e1ff20
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 193 deletions.
186 changes: 115 additions & 71 deletions src/circuit/gadget/sinsemilla.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,10 @@ use halo2::{arithmetic::CurveAffine, circuit::Layouter, plonk::Error};
use std::fmt::Debug;

pub mod chip;
pub use chip::{SinsemillaChip, SinsemillaCommitDomains, SinsemillaConfig, SinsemillaHashDomains};
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.
pub trait SinsemillaInstructions<C: CurveAffine>: EccInstructions<C> {
/// 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,
>;

pub trait SinsemillaInstructions<C: CurveAffine> {
/// A piece in a message containing a number of `K`-bit words.
/// A [`MessagePiece`] fits in a single cell, which means it can only
/// contain up to `N` words, where `N*K <= C::Base::NUM_BITS`.
Expand All @@ -25,6 +16,16 @@ pub trait SinsemillaInstructions<C: CurveAffine>: EccInstructions<C> {
/// A cell in the circuit
type CellValue;

/// A point output of [ hash_to_point`].
type Point: Clone + Debug;
/// The fixed points used in `CommitDomains`.
type FixedPoints: Clone + Debug;

/// HashDomains used in this instruction.
type HashDomains: HashDomains<C>;
/// CommitDomains used in this instruction.
type CommitDomains: CommitDomains<C, Self::FixedPoints, Self::HashDomains>;

/// Witness a message given a bitstring.
fn witness_message(
&self,
Expand Down Expand Up @@ -52,9 +53,6 @@ pub trait SinsemillaInstructions<C: CurveAffine>: EccInstructions<C> {
/// Prepare a message piece given a [`CellValue`] and a length.
fn prepare_message_piece(cell: &Self::CellValue, length: usize) -> Self::MessagePiece;

/// Extracts the x-coordinate from a curve point.
fn extract(point: &Self::Point) -> Self::X;

/// Hashes a message to an ECC curve point.
#[allow(non_snake_case)]
fn hash_to_point(
Expand Down Expand Up @@ -85,7 +83,7 @@ impl<C: CurveAffine, SinsemillaChip: SinsemillaInstructions<C> + Clone + Debug +
num_words: usize,
) -> Result<Self, Error> {
println!("from_bitstring num_words: {}", num_words);
let inner = chip.witness_message(layouter, bitstring.clone(), num_words)?;
let inner = chip.witness_message(layouter, bitstring, num_words)?;
Ok(Self { chip, inner })
}

Expand All @@ -112,32 +110,44 @@ impl<C: CurveAffine, SinsemillaChip: SinsemillaInstructions<C> + Clone + Debug +
}
}

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

#[allow(non_snake_case)]
pub struct HashDomain<
C: CurveAffine,
pub struct HashDomain<C: CurveAffine, SinsemillaChip, EccChip>
where
SinsemillaChip: SinsemillaInstructions<C> + Clone + Debug + Eq,
> {
chip: SinsemillaChip,
EccChip: EccInstructions<
C,
Point = <SinsemillaChip as SinsemillaInstructions<C>>::Point,
FixedPoints = <SinsemillaChip as SinsemillaInstructions<C>>::FixedPoints,
> + Clone
+ Debug
+ Eq,
{
sinsemilla_chip: SinsemillaChip,
ecc_chip: EccChip,
pub Q: C,
}

impl<C: CurveAffine, SinsemillaChip: SinsemillaInstructions<C> + Clone + Debug + Eq>
HashDomain<C, SinsemillaChip>
impl<C: CurveAffine, SinsemillaChip, EccChip> HashDomain<C, SinsemillaChip, EccChip>
where
SinsemillaChip: SinsemillaInstructions<C> + Clone + Debug + Eq,
EccChip: EccInstructions<
C,
Point = <SinsemillaChip as SinsemillaInstructions<C>>::Point,
FixedPoints = <SinsemillaChip as SinsemillaInstructions<C>>::FixedPoints,
> + Clone
+ Debug
+ Eq,
{
#[allow(non_snake_case)]
/// Constructs a new `HashDomain` for the given domain.
pub fn new(
chip: SinsemillaChip,
domain: &<SinsemillaChip as SinsemillaInstructions<C>>::HashDomains,
sinsemilla_chip: SinsemillaChip,
ecc_chip: EccChip,
domain: &SinsemillaChip::HashDomains,
) -> Self {
HashDomain {
chip: chip.clone(),
sinsemilla_chip,
ecc_chip,
Q: domain.Q(),
}
}
Expand All @@ -149,11 +159,11 @@ impl<C: CurveAffine, SinsemillaChip: SinsemillaInstructions<C> + Clone + Debug +
&self,
layouter: impl Layouter<C::Base>,
message: Message<C, SinsemillaChip>,
) -> Result<ecc::Point<C, SinsemillaChip>, Error> {
assert_eq!(self.chip, message.chip);
self.chip
) -> Result<ecc::Point<C, EccChip>, Error> {
assert_eq!(self.sinsemilla_chip, message.chip);
self.sinsemilla_chip
.hash_to_point(layouter, self.Q, message.inner)
.map(|point| ecc::Point::from_inner(self.chip.clone(), point))
.map(|point| ecc::Point::from_inner(self.ecc_chip.clone(), point))
}

/// $\mathsf{SinsemillaHash}$ from [§ 5.4.1.9][concretesinsemillahash].
Expand All @@ -163,8 +173,8 @@ impl<C: CurveAffine, SinsemillaChip: SinsemillaInstructions<C> + Clone + Debug +
&self,
layouter: impl Layouter<C::Base>,
message: Message<C, SinsemillaChip>,
) -> Result<ecc::X<C, SinsemillaChip>, Error> {
assert_eq!(self.chip, message.chip);
) -> Result<ecc::X<C, EccChip>, Error> {
assert_eq!(self.sinsemilla_chip, message.chip);
let p = self.hash_to_point(layouter, message);
p.map(|p| p.extract_p())
}
Expand All @@ -181,23 +191,48 @@ pub trait CommitDomains<C: CurveAffine, F: Clone + Debug, H: HashDomains<C>>:
fn hash_domain(&self) -> H;
}

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

#[allow(non_snake_case)]
pub struct CommitDomain<
C: CurveAffine,
pub struct CommitDomain<C: CurveAffine, SinsemillaChip, EccChip>
where
SinsemillaChip: SinsemillaInstructions<C> + Clone + Debug + Eq,
> {
M: HashDomain<C, SinsemillaChip>,
R: ecc::FixedPoint<C, SinsemillaChip>,
EccChip: EccInstructions<
C,
Point = <SinsemillaChip as SinsemillaInstructions<C>>::Point,
FixedPoints = <SinsemillaChip as SinsemillaInstructions<C>>::FixedPoints,
> + Clone
+ Debug
+ Eq,
{
M: HashDomain<C, SinsemillaChip, EccChip>,
R: ecc::FixedPoint<C, EccChip>,
}

impl<C: CurveAffine, SinsemillaChip: SinsemillaInstructions<C> + Clone + Debug + Eq>
CommitDomain<C, SinsemillaChip>
impl<C: CurveAffine, SinsemillaChip, EccChip> CommitDomain<C, SinsemillaChip, EccChip>
where
SinsemillaChip: SinsemillaInstructions<C> + Clone + Debug + Eq,
EccChip: EccInstructions<
C,
Point = <SinsemillaChip as SinsemillaInstructions<C>>::Point,
FixedPoints = <SinsemillaChip as SinsemillaInstructions<C>>::FixedPoints,
> + Clone
+ Debug
+ Eq,
{
/// Constructs a new `CommitDomain` for the given domain.
pub fn new(chip: SinsemillaChip, domain: &SinsemillaChip::CommitDomains) -> Self {
pub fn new(
sinsemilla_chip: SinsemillaChip,
ecc_chip: EccChip,
domain: &SinsemillaChip::CommitDomains,
) -> Self {
CommitDomain {
M: HashDomain::new(chip.clone(), &domain.hash_domain()),
R: ecc::FixedPoint::from_inner(chip, domain.r()),
M: HashDomain::new(sinsemilla_chip, ecc_chip.clone(), &domain.hash_domain()),
R: ecc::FixedPoint::from_inner(ecc_chip, domain.r()),
}
}

Expand All @@ -208,9 +243,9 @@ impl<C: CurveAffine, SinsemillaChip: SinsemillaInstructions<C> + Clone + Debug +
&self,
mut layouter: impl Layouter<C::Base>,
message: Message<C, SinsemillaChip>,
r: ecc::ScalarFixed<C, SinsemillaChip>,
) -> Result<ecc::Point<C, SinsemillaChip>, Error> {
assert_eq!(self.M.chip, message.chip);
r: ecc::ScalarFixed<C, EccChip>,
) -> Result<ecc::Point<C, EccChip>, Error> {
assert_eq!(self.M.sinsemilla_chip, message.chip);
let blind = self.R.mul(layouter.namespace(|| "[r] R"), &r)?;
self.M
.hash_to_point(layouter.namespace(|| "M"), message)?
Expand All @@ -224,9 +259,9 @@ impl<C: CurveAffine, SinsemillaChip: SinsemillaInstructions<C> + Clone + Debug +
&self,
mut layouter: impl Layouter<C::Base>,
message: Message<C, SinsemillaChip>,
r: ecc::ScalarFixed<C, SinsemillaChip>,
) -> Result<ecc::X<C, SinsemillaChip>, Error> {
assert_eq!(self.M.chip, message.chip);
r: ecc::ScalarFixed<C, EccChip>,
) -> Result<ecc::X<C, EccChip>, Error> {
assert_eq!(self.M.sinsemilla_chip, message.chip);
let p = self.commit(layouter.namespace(|| "commit"), message, r);
p.map(|p| p.extract_p())
}
Expand All @@ -243,21 +278,24 @@ mod tests {
};

use super::{
CommitDomain, HashDomain, Message, SinsemillaChip, SinsemillaCommitDomains,
SinsemillaConfig, SinsemillaHashDomains, SinsemillaInstructions,
chip::{SinsemillaCommitDomains, SinsemillaHashDomains},
CommitDomain, HashDomain, Message, SinsemillaChip, SinsemillaConfig,
SinsemillaInstructions,
};

use crate::circuit::gadget::ecc::{chip::EccChip, ScalarFixed};
use crate::circuit::gadget::ecc::{
chip::{EccChip, EccConfig},
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);
type Config = (EccConfig, SinsemillaConfig, SinsemillaConfig);

#[allow(non_snake_case)]
fn configure(meta: &mut ConstraintSystem<C::Base>) -> Self::Config {
Expand Down Expand Up @@ -291,19 +329,17 @@ mod tests {

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)
(ecc_config, config1, config2)
}

fn synthesize(
Expand All @@ -312,17 +348,22 @@ mod tests {
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>::load(config.0.clone(), &mut layouter)?;
SinsemillaChip::<C>::load(config.1.clone(), &mut layouter)?;

// 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 chip1 = SinsemillaChip::<C>::construct(config.0);
let chip1 = SinsemillaChip::<C>::construct(config.1);

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

// Left leaf
let left = {
Expand All @@ -331,7 +372,7 @@ mod tests {
let left = Message::from_bitstring(
chip1.clone(),
layouter.namespace(|| "witness left"),
left.clone(),
left,
25,
)?;
let left = merkle_crh.hash_to_point(layouter.namespace(|| "left"), left)?;
Expand All @@ -346,7 +387,7 @@ mod tests {
let right = Message::from_bitstring(
chip1.clone(),
layouter.namespace(|| "witness right"),
right.clone(),
right,
25,
)?;
let right = merkle_crh.hash_to_point(layouter.namespace(|| "right"), right)?;
Expand All @@ -363,17 +404,20 @@ mod tests {
};

// Parent
let parent = Message::from_pieces(chip1.clone(), vec![l, left, right]);
let parent = Message::from_pieces(chip1, vec![l, left, right]);
merkle_crh.hash_to_point(layouter.namespace(|| "parent"), parent)?;
}

{
let chip2 = SinsemillaChip::<C>::construct(config.1);
let chip2 = SinsemillaChip::<C>::construct(config.2);

let commit_ivk =
CommitDomain::new(chip2.clone(), &SinsemillaCommitDomains::CommitIvk);
let r = ScalarFixed::<C, SinsemillaChip<C>>::new(
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()),
)?;
Expand All @@ -382,7 +426,7 @@ mod tests {
let message = Message::from_bitstring(
chip2,
layouter.namespace(|| "witness message"),
message.clone(),
message,
50,
)?;
commit_ivk.commit(layouter.namespace(|| "commit"), message, r)?;
Expand Down
Loading

0 comments on commit 7e1ff20

Please sign in to comment.