mirror of https://github.com/zcash/orchard.git
Merge pull request #118 from zcash/sinsemilla-chip-commit
Sinsemilla chip with Commit Domain
This commit is contained in:
commit
146156abb6
|
@ -36,9 +36,13 @@ pub trait SinsemillaInstructions<C: CurveAffine, const K: usize, const MAX_WORDS
|
||||||
type X;
|
type X;
|
||||||
/// A point output of [`Self::hash_to_point`].
|
/// A point output of [`Self::hash_to_point`].
|
||||||
type Point: Clone + Debug;
|
type Point: Clone + Debug;
|
||||||
|
/// A type enumerating the fixed points used in `CommitDomains`.
|
||||||
|
type FixedPoints: Clone + Debug;
|
||||||
|
|
||||||
/// HashDomains used in this instruction.
|
/// HashDomains used in this instruction.
|
||||||
type HashDomains: HashDomains<C>;
|
type HashDomains: HashDomains<C>;
|
||||||
|
/// CommitDomains used in this instruction.
|
||||||
|
type CommitDomains: CommitDomains<C, Self::FixedPoints, Self::HashDomains>;
|
||||||
|
|
||||||
/// Witness a message piece given a field element. Returns a [`Self::MessagePiece`]
|
/// Witness a message piece given a field element. Returns a [`Self::MessagePiece`]
|
||||||
/// encoding the given message.
|
/// encoding the given message.
|
||||||
|
@ -222,6 +226,7 @@ pub struct HashDomain<
|
||||||
EccChip: EccInstructions<
|
EccChip: EccInstructions<
|
||||||
C,
|
C,
|
||||||
Point = <SinsemillaChip as SinsemillaInstructions<C, K, MAX_WORDS>>::Point,
|
Point = <SinsemillaChip as SinsemillaInstructions<C, K, MAX_WORDS>>::Point,
|
||||||
|
FixedPoints = <SinsemillaChip as SinsemillaInstructions<C, K, MAX_WORDS>>::FixedPoints,
|
||||||
> + Clone
|
> + Clone
|
||||||
+ Debug
|
+ Debug
|
||||||
+ Eq,
|
+ Eq,
|
||||||
|
@ -238,6 +243,7 @@ where
|
||||||
EccChip: EccInstructions<
|
EccChip: EccInstructions<
|
||||||
C,
|
C,
|
||||||
Point = <SinsemillaChip as SinsemillaInstructions<C, K, MAX_WORDS>>::Point,
|
Point = <SinsemillaChip as SinsemillaInstructions<C, K, MAX_WORDS>>::Point,
|
||||||
|
FixedPoints = <SinsemillaChip as SinsemillaInstructions<C, K, MAX_WORDS>>::FixedPoints,
|
||||||
> + Clone
|
> + Clone
|
||||||
+ Debug
|
+ Debug
|
||||||
+ Eq,
|
+ Eq,
|
||||||
|
@ -284,25 +290,111 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Trait allowing circuit's Sinsemilla CommitDomains to be enumerated.
|
||||||
|
pub trait CommitDomains<C: CurveAffine, F: Clone + Debug, H: HashDomains<C>>:
|
||||||
|
Clone + Debug
|
||||||
|
{
|
||||||
|
/// Returns the fixed point corresponding to the R constant used for
|
||||||
|
/// randomization in this CommitDomain.
|
||||||
|
fn r(&self) -> F;
|
||||||
|
|
||||||
|
/// Returns the HashDomain contained in this CommitDomain
|
||||||
|
fn hash_domain(&self) -> H;
|
||||||
|
}
|
||||||
|
|
||||||
/// Trait allowing circuit's Sinsemilla HashDomains to be enumerated.
|
/// Trait allowing circuit's Sinsemilla HashDomains to be enumerated.
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub trait HashDomains<C: CurveAffine>: Clone + Debug {
|
pub trait HashDomains<C: CurveAffine>: Clone + Debug {
|
||||||
fn Q(&self) -> C;
|
fn Q(&self) -> C;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub struct CommitDomain<
|
||||||
|
C: CurveAffine,
|
||||||
|
SinsemillaChip,
|
||||||
|
EccChip,
|
||||||
|
const K: usize,
|
||||||
|
const MAX_WORDS: usize,
|
||||||
|
> where
|
||||||
|
SinsemillaChip: SinsemillaInstructions<C, K, MAX_WORDS> + Clone + Debug + Eq,
|
||||||
|
EccChip: EccInstructions<
|
||||||
|
C,
|
||||||
|
Point = <SinsemillaChip as SinsemillaInstructions<C, K, MAX_WORDS>>::Point,
|
||||||
|
FixedPoints = <SinsemillaChip as SinsemillaInstructions<C, K, MAX_WORDS>>::FixedPoints,
|
||||||
|
> + Clone
|
||||||
|
+ Debug
|
||||||
|
+ Eq,
|
||||||
|
{
|
||||||
|
M: HashDomain<C, SinsemillaChip, EccChip, K, MAX_WORDS>,
|
||||||
|
R: ecc::FixedPoint<C, EccChip>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: CurveAffine, SinsemillaChip, EccChip, const K: usize, const MAX_WORDS: usize>
|
||||||
|
CommitDomain<C, SinsemillaChip, EccChip, K, MAX_WORDS>
|
||||||
|
where
|
||||||
|
SinsemillaChip: SinsemillaInstructions<C, K, MAX_WORDS> + Clone + Debug + Eq,
|
||||||
|
EccChip: EccInstructions<
|
||||||
|
C,
|
||||||
|
Point = <SinsemillaChip as SinsemillaInstructions<C, K, MAX_WORDS>>::Point,
|
||||||
|
FixedPoints = <SinsemillaChip as SinsemillaInstructions<C, K, MAX_WORDS>>::FixedPoints,
|
||||||
|
> + Clone
|
||||||
|
+ Debug
|
||||||
|
+ Eq,
|
||||||
|
{
|
||||||
|
/// Constructs a new `CommitDomain` for the given domain.
|
||||||
|
pub fn new(
|
||||||
|
sinsemilla_chip: SinsemillaChip,
|
||||||
|
ecc_chip: EccChip,
|
||||||
|
domain: &SinsemillaChip::CommitDomains,
|
||||||
|
) -> Self {
|
||||||
|
CommitDomain {
|
||||||
|
M: HashDomain::new(sinsemilla_chip, ecc_chip.clone(), &domain.hash_domain()),
|
||||||
|
R: ecc::FixedPoint::from_inner(ecc_chip, domain.r()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// $\mathsf{SinsemillaCommit}$ from [§ 5.4.8.4][concretesinsemillacommit].
|
||||||
|
///
|
||||||
|
/// [concretesinsemillacommit]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit
|
||||||
|
pub fn commit(
|
||||||
|
&self,
|
||||||
|
mut layouter: impl Layouter<C::Base>,
|
||||||
|
message: Message<C, SinsemillaChip, K, MAX_WORDS>,
|
||||||
|
r: Option<C::Scalar>,
|
||||||
|
) -> 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)?
|
||||||
|
.add_incomplete(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<C::Base>,
|
||||||
|
message: Message<C, SinsemillaChip, K, MAX_WORDS>,
|
||||||
|
r: Option<C::Scalar>,
|
||||||
|
) -> 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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use halo2::{
|
use halo2::{
|
||||||
circuit::{Layouter, SimpleFloorPlanner},
|
circuit::{Layouter, SimpleFloorPlanner},
|
||||||
dev::MockProver,
|
dev::MockProver,
|
||||||
pasta::pallas,
|
|
||||||
plonk::{Circuit, ConstraintSystem, Error},
|
plonk::{Circuit, ConstraintSystem, Error},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
chip::SinsemillaHashDomains,
|
chip::{SinsemillaChip, SinsemillaCommitDomains, SinsemillaConfig, SinsemillaHashDomains},
|
||||||
chip::{SinsemillaChip, SinsemillaConfig},
|
CommitDomain, HashDomain, Message, MessagePiece,
|
||||||
HashDomain, Message, MessagePiece,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -310,11 +402,12 @@ mod tests {
|
||||||
chip::{EccChip, EccConfig},
|
chip::{EccChip, EccConfig},
|
||||||
Point,
|
Point,
|
||||||
},
|
},
|
||||||
constants::MERKLE_CRH_PERSONALIZATION,
|
constants::{COMMIT_IVK_PERSONALIZATION, MERKLE_CRH_PERSONALIZATION},
|
||||||
primitives::sinsemilla::{self, K},
|
primitives::sinsemilla::{self, K},
|
||||||
};
|
};
|
||||||
|
|
||||||
use group::Curve;
|
use group::Curve;
|
||||||
|
use pasta_curves::{arithmetic::FieldExt, pallas};
|
||||||
|
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
|
||||||
|
@ -466,7 +559,7 @@ mod tests {
|
||||||
};
|
};
|
||||||
|
|
||||||
Point::new(
|
Point::new(
|
||||||
ecc_chip,
|
ecc_chip.clone(),
|
||||||
layouter.namespace(|| "Witness expected parent"),
|
layouter.namespace(|| "Witness expected parent"),
|
||||||
expected_parent,
|
expected_parent,
|
||||||
)?
|
)?
|
||||||
|
@ -484,7 +577,50 @@ mod tests {
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
{
|
||||||
|
let chip2 = SinsemillaChip::construct(config.2);
|
||||||
|
|
||||||
|
let commit_ivk = CommitDomain::new(
|
||||||
|
chip2.clone(),
|
||||||
|
ecc_chip.clone(),
|
||||||
|
&SinsemillaCommitDomains::CommitIvk,
|
||||||
|
);
|
||||||
|
let r_val = pallas::Scalar::rand();
|
||||||
|
let message: Vec<Option<bool>> =
|
||||||
|
(0..500).map(|_| Some(rand::random::<bool>())).collect();
|
||||||
|
|
||||||
|
let result = {
|
||||||
|
let message = Message::from_bitstring(
|
||||||
|
chip2,
|
||||||
|
layouter.namespace(|| "witness message"),
|
||||||
|
message.clone(),
|
||||||
|
)?;
|
||||||
|
commit_ivk.commit(layouter.namespace(|| "commit"), message, Some(r_val))?
|
||||||
|
};
|
||||||
|
|
||||||
|
// Witness expected result.
|
||||||
|
let expected_result = {
|
||||||
|
let message: Option<Vec<bool>> = message.into_iter().collect();
|
||||||
|
let expected_result = if let Some(message) = message {
|
||||||
|
let domain = sinsemilla::CommitDomain::new(COMMIT_IVK_PERSONALIZATION);
|
||||||
|
let point = domain.commit(message.into_iter(), &r_val).unwrap();
|
||||||
|
Some(point.to_affine())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
Point::new(
|
||||||
|
ecc_chip,
|
||||||
|
layouter.namespace(|| "Witness expected result"),
|
||||||
|
expected_result,
|
||||||
|
)?
|
||||||
|
};
|
||||||
|
|
||||||
|
result.constrain_equal(
|
||||||
|
layouter.namespace(|| "result == expected result"),
|
||||||
|
&expected_result,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
use super::{
|
use super::{
|
||||||
message::{Message, MessagePiece},
|
message::{Message, MessagePiece},
|
||||||
HashDomains, SinsemillaInstructions,
|
CommitDomains, HashDomains, SinsemillaInstructions,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
circuit::gadget::{
|
circuit::gadget::{
|
||||||
ecc::chip::EccPoint,
|
ecc::chip::EccPoint,
|
||||||
utilities::{lookup_range_check::LookupRangeCheckConfig, CellValue, Var},
|
utilities::{lookup_range_check::LookupRangeCheckConfig, CellValue, Var},
|
||||||
},
|
},
|
||||||
|
constants::OrchardFixedBasesFull,
|
||||||
primitives::sinsemilla::{
|
primitives::sinsemilla::{
|
||||||
self, Q_COMMIT_IVK_M_GENERATOR, Q_MERKLE_CRH, Q_NOTE_COMMITMENT_M_GENERATOR,
|
self, Q_COMMIT_IVK_M_GENERATOR, Q_MERKLE_CRH, Q_NOTE_COMMITMENT_M_GENERATOR,
|
||||||
},
|
},
|
||||||
|
@ -267,8 +268,10 @@ impl SinsemillaInstructions<pallas::Affine, { sinsemilla::K }, { sinsemilla::C }
|
||||||
|
|
||||||
type X = CellValue<pallas::Base>;
|
type X = CellValue<pallas::Base>;
|
||||||
type Point = EccPoint;
|
type Point = EccPoint;
|
||||||
|
type FixedPoints = OrchardFixedBasesFull;
|
||||||
|
|
||||||
type HashDomains = SinsemillaHashDomains;
|
type HashDomains = SinsemillaHashDomains;
|
||||||
|
type CommitDomains = SinsemillaCommitDomains;
|
||||||
|
|
||||||
fn witness_message_piece(
|
fn witness_message_piece(
|
||||||
&self,
|
&self,
|
||||||
|
@ -340,3 +343,27 @@ impl HashDomains<pallas::Affine> for SinsemillaHashDomains {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum SinsemillaCommitDomains {
|
||||||
|
NoteCommit,
|
||||||
|
CommitIvk,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CommitDomains<pallas::Affine, OrchardFixedBasesFull, SinsemillaHashDomains>
|
||||||
|
for SinsemillaCommitDomains
|
||||||
|
{
|
||||||
|
fn r(&self) -> OrchardFixedBasesFull {
|
||||||
|
match self {
|
||||||
|
Self::NoteCommit => OrchardFixedBasesFull::NoteCommitR,
|
||||||
|
Self::CommitIvk => OrchardFixedBasesFull::CommitIvkR,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hash_domain(&self) -> SinsemillaHashDomains {
|
||||||
|
match self {
|
||||||
|
Self::NoteCommit => SinsemillaHashDomains::NoteCommit,
|
||||||
|
Self::CommitIvk => SinsemillaHashDomains::CommitIvk,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -466,12 +466,22 @@ impl SinsemillaInstructions<pallas::Affine, { sinsemilla::K }, { sinsemilla::C }
|
||||||
{ sinsemilla::K },
|
{ sinsemilla::K },
|
||||||
{ sinsemilla::C },
|
{ sinsemilla::C },
|
||||||
>>::Point;
|
>>::Point;
|
||||||
|
type FixedPoints = <SinsemillaChip as SinsemillaInstructions<
|
||||||
|
pallas::Affine,
|
||||||
|
{ sinsemilla::K },
|
||||||
|
{ sinsemilla::C },
|
||||||
|
>>::FixedPoints;
|
||||||
|
|
||||||
type HashDomains = <SinsemillaChip as SinsemillaInstructions<
|
type HashDomains = <SinsemillaChip as SinsemillaInstructions<
|
||||||
pallas::Affine,
|
pallas::Affine,
|
||||||
{ sinsemilla::K },
|
{ sinsemilla::K },
|
||||||
{ sinsemilla::C },
|
{ sinsemilla::C },
|
||||||
>>::HashDomains;
|
>>::HashDomains;
|
||||||
|
type CommitDomains = <SinsemillaChip as SinsemillaInstructions<
|
||||||
|
pallas::Affine,
|
||||||
|
{ sinsemilla::K },
|
||||||
|
{ sinsemilla::C },
|
||||||
|
>>::CommitDomains;
|
||||||
|
|
||||||
fn witness_message_piece(
|
fn witness_message_piece(
|
||||||
&self,
|
&self,
|
||||||
|
|
Loading…
Reference in New Issue