Move commitment types into commitments module

Docs, tidy
This commit is contained in:
Deirdre Connolly 2020-07-27 19:02:33 -04:00 committed by Deirdre Connolly
parent 4ccec84768
commit b6385ca36f
14 changed files with 131 additions and 117 deletions

View File

@ -0,0 +1,4 @@
//! Note and value commitments and associated types.
pub mod sapling;
pub mod sprout;

View File

@ -1,4 +1,9 @@
//! Sapling note and value commitments //! Sapling note and value commitments and types.
#![allow(clippy::unit_arg)]
#[cfg(test)]
mod arbitrary;
use std::{fmt, io}; use std::{fmt, io};
@ -7,6 +12,7 @@ use rand_core::{CryptoRng, RngCore};
use crate::{ use crate::{
keys::sapling::{find_group_hash, Diversifier, TransmissionKey}, keys::sapling::{find_group_hash, Diversifier, TransmissionKey},
notes::sapling::Note,
serde_helpers, serde_helpers,
serialization::{ReadZcashExt, SerializationError, ZcashDeserialize, ZcashSerialize}, serialization::{ReadZcashExt, SerializationError, ZcashDeserialize, ZcashSerialize},
types::amount::{Amount, NonNegative}, types::amount::{Amount, NonNegative},
@ -125,14 +131,38 @@ impl From<jubjub::ExtendedPoint> for NoteCommitment {
} }
} }
impl Eq for NoteCommitment {}
impl From<NoteCommitment> for [u8; 32] { impl From<NoteCommitment> for [u8; 32] {
fn from(cm: NoteCommitment) -> [u8; 32] { fn from(cm: NoteCommitment) -> [u8; 32] {
cm.0.to_bytes() cm.0.to_bytes()
} }
} }
impl From<Note> for NoteCommitment {
/// Construct a “windowed” Pedersen commitment by reusing a
/// Perderson hash constructon, and adding a randomized point on
/// the Jubjub curve.
///
/// WindowedPedersenCommit_r (s) := \
/// PedersenHashToPoint(“Zcash_PH”, s) + [r]FindGroupHash^J^(r)(“Zcash_PH”, “r”)
///
/// NoteCommit^Sapling_rcm (g*_d , pk*_d , v) := \
/// WindowedPedersenCommit_rcm([1; 6] || I2LEBSP_64(v) || g*_d || pk*_d)
///
/// https://zips.z.cash/protocol/protocol.pdf#concretewindowedcommit
fn from(note: Note) -> NoteCommitment {
use rand_core::OsRng;
NoteCommitment::new(
&mut OsRng,
note.diversifier,
note.transmission_key,
note.value,
)
}
}
impl Eq for NoteCommitment {}
impl ZcashSerialize for NoteCommitment { impl ZcashSerialize for NoteCommitment {
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> { fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
writer.write_all(&self.0.to_bytes())?; writer.write_all(&self.0.to_bytes())?;

View File

@ -0,0 +1,33 @@
use proptest::{arbitrary::any, array, prelude::*};
use crate::commitments::sapling;
impl Arbitrary for sapling::NoteCommitment {
type Parameters = ();
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
array::uniform32(any::<u8>())
.prop_filter("Valid jubjub::AffinePoint", |b| {
jubjub::AffinePoint::from_bytes(*b).is_some().unwrap_u8() == 1
})
.prop_map(Self::from)
.boxed()
}
type Strategy = BoxedStrategy<Self>;
}
impl Arbitrary for sapling::ValueCommitment {
type Parameters = ();
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
array::uniform32(any::<u8>())
.prop_filter("Valid jubjub::AffinePoint", |b| {
jubjub::AffinePoint::from_bytes(*b).is_some().unwrap_u8() == 1
})
.prop_map(Self::from)
.boxed()
}
type Strategy = BoxedStrategy<Self>;
}

View File

@ -1,6 +1,15 @@
//! Sprout commitment types.
#![allow(clippy::unit_arg)]
use std::io; use std::io;
use crate::serialization::{ReadZcashExt, SerializationError, ZcashDeserialize, ZcashSerialize}; use sha2::{Digest, Sha256};
use crate::{
notes::sprout::Note,
serialization::{ReadZcashExt, SerializationError, ZcashDeserialize, ZcashSerialize},
};
/// The randomness used in the Pedersen Hash for note commitment. /// The randomness used in the Pedersen Hash for note commitment.
#[derive(Copy, Clone, Debug, PartialEq)] #[derive(Copy, Clone, Debug, PartialEq)]
@ -18,6 +27,22 @@ impl AsRef<[u8]> for CommitmentRandomness {
#[cfg_attr(test, derive(proptest_derive::Arbitrary))] #[cfg_attr(test, derive(proptest_derive::Arbitrary))]
pub struct NoteCommitment(pub(crate) [u8; 32]); pub struct NoteCommitment(pub(crate) [u8; 32]);
impl From<Note> for NoteCommitment {
/// NoteCommit_rcm^Sprout(a_pk, v, rho)
///
/// https://zips.z.cash/protocol/protocol.pdf#concretesproutnotecommit
fn from(note: Note) -> NoteCommitment {
let leading_byte: u8 = 0xB0;
let mut hasher = Sha256::default();
hasher.input([leading_byte]);
hasher.input(note.paying_key);
hasher.input(note.value.to_bytes());
hasher.input(note.rho);
hasher.input(note.rcm);
NoteCommitment(hasher.result().into())
}
}
impl ZcashSerialize for NoteCommitment { impl ZcashSerialize for NoteCommitment {
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> { fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
writer.write_all(&self.0[..])?; writer.write_all(&self.0[..])?;

View File

@ -17,6 +17,7 @@ mod sha256d_writer;
pub mod addresses; pub mod addresses;
pub mod block; pub mod block;
pub mod commitments;
pub mod equihash_solution; pub mod equihash_solution;
pub mod keys; pub mod keys;
pub mod notes; pub mod notes;

View File

@ -1,5 +1,7 @@
//! Notes, note and value commitments, note encryption, and nullifier types. //! Notes, note encryption, and nullifier types.
#[cfg(test)]
mod arbitrary;
mod memo; mod memo;
pub mod sapling; pub mod sapling;

View File

@ -1,6 +1,6 @@
use crate::notes::memo::Memo; use crate::notes::memo::Memo;
use proptest::{arbitrary::any, array, collection::vec, prelude::*}; use proptest::{arbitrary::any, collection::vec, prelude::*};
impl Arbitrary for Memo { impl Arbitrary for Memo {
type Parameters = (); type Parameters = ();

View File

@ -6,51 +6,33 @@
#[cfg(test)] #[cfg(test)]
mod arbitrary; mod arbitrary;
mod ciphertexts; mod ciphertexts;
mod commitments;
mod nullifiers; mod nullifiers;
use crate::{ use crate::{
commitments::sapling::CommitmentRandomness,
keys::sapling::{Diversifier, TransmissionKey}, keys::sapling::{Diversifier, TransmissionKey},
notes::memo::Memo, notes::memo::Memo,
types::amount::{Amount, NonNegative}, types::amount::{Amount, NonNegative},
}; };
pub use ciphertexts::{EncryptedCiphertext, OutCiphertext}; pub use ciphertexts::{EncryptedCiphertext, OutCiphertext};
pub use commitments::{CommitmentRandomness, NoteCommitment, ValueCommitment};
pub use nullifiers::Nullifier; pub use nullifiers::Nullifier;
/// A Note represents that a value is spendable by the recipient who /// A Note represents that a value is spendable by the recipient who
/// holds the spending key corresponding to a given shielded payment /// holds the spending key corresponding to a given shielded payment
/// address. /// address.
pub struct Note { pub struct Note {
diversifier: Diversifier, /// The diversier of the recipients shielded payment address.
transmission_key: TransmissionKey, pub diversifier: Diversifier,
value: Amount<NonNegative>, /// The diversied transmission key of the recipients shielded
rcm: CommitmentRandomness, /// payment address.
} pub transmission_key: TransmissionKey,
/// An integer representing the value of the note in zatoshi.
impl Note { pub value: Amount<NonNegative>,
/// Construct a “windowed” Pedersen commitment by reusing a /// A random commitment trapdoor used to produce the associated
/// Perderson hash constructon, and adding a randomized point on /// note commitment.
/// the Jubjub curve. pub rcm: CommitmentRandomness,
///
/// WindowedPedersenCommit_r (s) := \
/// PedersenHashToPoint(“Zcash_PH”, s) + [r]FindGroupHash^J^(r)(“Zcash_PH”, “r”)
///
/// NoteCommit^Sapling_rcm (g*_d , pk*_d , v) := \
/// WindowedPedersenCommit_rcm([1; 6] || I2LEBSP_64(v) || g*_d || pk*_d)
///
/// https://zips.z.cash/protocol/protocol.pdf#concretewindowedcommit
pub fn commit(&self) -> NoteCommitment {
use rand_core::OsRng;
NoteCommitment::new(
&mut OsRng,
self.diversifier,
self.transmission_key,
self.value,
)
}
} }
/// The decrypted form of encrypted Sapling notes on the blockchain. /// The decrypted form of encrypted Sapling notes on the blockchain.

View File

@ -1,4 +1,4 @@
use proptest::{arbitrary::any, array, collection::vec, prelude::*}; use proptest::{arbitrary::any, collection::vec, prelude::*};
use crate::notes::sapling; use crate::notes::sapling;
@ -33,33 +33,3 @@ impl Arbitrary for sapling::OutCiphertext {
type Strategy = BoxedStrategy<Self>; type Strategy = BoxedStrategy<Self>;
} }
impl Arbitrary for sapling::NoteCommitment {
type Parameters = ();
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
array::uniform32(any::<u8>())
.prop_filter("Valid jubjub::AffinePoint", |b| {
jubjub::AffinePoint::from_bytes(*b).is_some().unwrap_u8() == 1
})
.prop_map(Self::from)
.boxed()
}
type Strategy = BoxedStrategy<Self>;
}
impl Arbitrary for sapling::ValueCommitment {
type Parameters = ();
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
array::uniform32(any::<u8>())
.prop_filter("Valid jubjub::AffinePoint", |b| {
jubjub::AffinePoint::from_bytes(*b).is_some().unwrap_u8() == 1
})
.prop_map(Self::from)
.boxed()
}
type Strategy = BoxedStrategy<Self>;
}

View File

@ -6,19 +6,17 @@
#[cfg(test)] #[cfg(test)]
mod arbitrary; mod arbitrary;
mod ciphertexts; mod ciphertexts;
mod commitments;
mod nullifiers; mod nullifiers;
use sha2::{Digest, Sha256};
use crate::{ use crate::{
commitments::sprout::CommitmentRandomness,
keys::sprout::PayingKey, keys::sprout::PayingKey,
notes::memo::Memo, notes::memo::Memo,
types::amount::{Amount, NonNegative}, types::amount::{Amount, NonNegative},
}; };
pub use ciphertexts::EncryptedCiphertext; pub use ciphertexts::EncryptedCiphertext;
pub use commitments::{CommitmentRandomness, NoteCommitment};
pub use nullifiers::{Nullifier, NullifierSeed}; pub use nullifiers::{Nullifier, NullifierSeed};
/// A Note represents that a value is spendable by the recipient who /// A Note represents that a value is spendable by the recipient who
@ -30,30 +28,14 @@ pub use nullifiers::{Nullifier, NullifierSeed};
#[cfg_attr(test, derive(proptest_derive::Arbitrary))] #[cfg_attr(test, derive(proptest_derive::Arbitrary))]
pub struct Note { pub struct Note {
/// The paying key of the recipients shielded payment address /// The paying key of the recipients shielded payment address
paying_key: PayingKey, pub paying_key: PayingKey,
/// An integer representing the value of the note in zatoshi (1 ZEC /// An integer representing the value of the note in zatoshi (1 ZEC
/// = 10^8 zatoshi) /// = 10^8 zatoshi)
value: Amount<NonNegative>, pub value: Amount<NonNegative>,
/// Input to PRF^nf to derive the nullifier of the note /// Input to PRF^nf to derive the nullifier of the note
rho: NullifierSeed, pub rho: NullifierSeed,
/// A random commitment trapdoor /// A random commitment trapdoor
rcm: CommitmentRandomness, pub rcm: CommitmentRandomness,
}
impl Note {
/// NoteCommit_rcm^Sprout(a_pk, v, rho)
///
/// https://zips.z.cash/protocol/protocol.pdf#concretesproutnotecommit
pub fn commit(&self) -> NoteCommitment {
let leading_byte: u8 = 0xB0;
let mut hasher = Sha256::default();
hasher.input([leading_byte]);
hasher.input(self.paying_key);
hasher.input(self.value.to_bytes());
hasher.input(self.rho);
hasher.input(self.rcm);
NoteCommitment(hasher.result().into())
}
} }
/// The decrypted form of encrypted Sprout notes on the blockchain. /// The decrypted form of encrypted Sprout notes on the blockchain.

View File

@ -1,22 +1,6 @@
use proptest::{arbitrary::any, collection::vec, prelude::*}; use proptest::{arbitrary::any, collection::vec, prelude::*};
use crate::notes::{memo::Memo, sprout}; use crate::notes::sprout;
impl Arbitrary for Memo {
type Parameters = ();
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
(vec(any::<u8>(), 512))
.prop_map(|v| {
let mut bytes = [0; 512];
bytes.copy_from_slice(v.as_slice());
Memo(Box::new(bytes))
})
.boxed()
}
type Strategy = BoxedStrategy<Self>;
}
impl Arbitrary for sprout::EncryptedCiphertext { impl Arbitrary for sprout::EncryptedCiphertext {
type Parameters = (); type Parameters = ();

View File

@ -9,7 +9,7 @@ use std::{
}; };
use crate::{ use crate::{
notes, commitments, notes,
proofs::ZkSnarkProof, proofs::ZkSnarkProof,
serialization::{ serialization::{
ReadZcashExt, SerializationError, WriteZcashExt, ZcashDeserialize, ZcashSerialize, ReadZcashExt, SerializationError, WriteZcashExt, ZcashDeserialize, ZcashSerialize,
@ -335,7 +335,7 @@ impl ZcashDeserialize for Spend {
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> { fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
use crate::treestate::note_commitment_tree::SaplingNoteTreeRootHash; use crate::treestate::note_commitment_tree::SaplingNoteTreeRootHash;
Ok(Spend { Ok(Spend {
cv: notes::sapling::ValueCommitment::zcash_deserialize(&mut reader)?, cv: commitments::sapling::ValueCommitment::zcash_deserialize(&mut reader)?,
anchor: SaplingNoteTreeRootHash(reader.read_32_bytes()?), anchor: SaplingNoteTreeRootHash(reader.read_32_bytes()?),
nullifier: notes::sapling::Nullifier::zcash_deserialize(&mut reader)?, nullifier: notes::sapling::Nullifier::zcash_deserialize(&mut reader)?,
rk: reader.read_32_bytes()?.into(), rk: reader.read_32_bytes()?.into(),
@ -360,7 +360,7 @@ impl ZcashSerialize for Output {
impl ZcashDeserialize for Output { impl ZcashDeserialize for Output {
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> { fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
Ok(Output { Ok(Output {
cv: notes::sapling::ValueCommitment::zcash_deserialize(&mut reader)?, cv: commitments::sapling::ValueCommitment::zcash_deserialize(&mut reader)?,
cm_u: jubjub::Fq::from_bytes(&reader.read_32_bytes()?).unwrap(), cm_u: jubjub::Fq::from_bytes(&reader.read_32_bytes()?).unwrap(),
ephemeral_key: jubjub::AffinePoint::from_bytes(reader.read_32_bytes()?).unwrap(), ephemeral_key: jubjub::AffinePoint::from_bytes(reader.read_32_bytes()?).unwrap(),
enc_ciphertext: notes::sapling::EncryptedCiphertext::zcash_deserialize(&mut reader)?, enc_ciphertext: notes::sapling::EncryptedCiphertext::zcash_deserialize(&mut reader)?,

View File

@ -1,5 +1,5 @@
use crate::{ use crate::{
notes, commitments, notes,
proofs::Groth16Proof, proofs::Groth16Proof,
redjubjub::{self, Binding, SpendAuth}, redjubjub::{self, Binding, SpendAuth},
serde_helpers, serde_helpers,
@ -13,7 +13,7 @@ use futures::future::Either;
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Spend { pub struct Spend {
/// A value commitment to the value of the input note. /// A value commitment to the value of the input note.
pub cv: notes::sapling::ValueCommitment, pub cv: commitments::sapling::ValueCommitment,
/// A root of the Sapling note commitment tree at some block height in the past. /// A root of the Sapling note commitment tree at some block height in the past.
pub anchor: SaplingNoteTreeRootHash, pub anchor: SaplingNoteTreeRootHash,
/// The nullifier of the input note. /// The nullifier of the input note.
@ -32,7 +32,7 @@ pub struct Spend {
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Output { pub struct Output {
/// A value commitment to the value of the input note. /// A value commitment to the value of the input note.
pub cv: notes::sapling::ValueCommitment, pub cv: commitments::sapling::ValueCommitment,
/// The u-coordinate of the note commitment for the output note. /// The u-coordinate of the note commitment for the output note.
#[serde(with = "serde_helpers::Fq")] #[serde(with = "serde_helpers::Fq")]
pub cm_u: jubjub::Fq, pub cm_u: jubjub::Fq,

View File

@ -1,4 +1,5 @@
use crate::{ use crate::{
commitments,
notes::{sapling, sprout}, notes::{sapling, sprout},
proofs::{Groth16Proof, ZkSnarkProof}, proofs::{Groth16Proof, ZkSnarkProof},
transaction::{ transaction::{
@ -94,8 +95,8 @@ impl Arbitrary for Output {
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
( (
any::<sapling::ValueCommitment>(), any::<commitments::sapling::ValueCommitment>(),
any::<sapling::NoteCommitment>(), any::<commitments::sapling::NoteCommitment>(),
array::uniform32(any::<u8>()).prop_filter("Valid jubjub::AffinePoint", |b| { array::uniform32(any::<u8>()).prop_filter("Valid jubjub::AffinePoint", |b| {
jubjub::AffinePoint::from_bytes(*b).is_some().unwrap_u8() == 1 jubjub::AffinePoint::from_bytes(*b).is_some().unwrap_u8() == 1
}), }),
@ -154,7 +155,7 @@ impl Arbitrary for Spend {
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
( (
any::<SaplingNoteTreeRootHash>(), any::<SaplingNoteTreeRootHash>(),
any::<sapling::ValueCommitment>(), any::<commitments::sapling::ValueCommitment>(),
any::<sapling::Nullifier>(), any::<sapling::Nullifier>(),
array::uniform32(any::<u8>()), array::uniform32(any::<u8>()),
any::<Groth16Proof>(), any::<Groth16Proof>(),