From b6385ca36f32b33300e3cb8cd9a3cb3fa6d19a57 Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Mon, 27 Jul 2020 19:02:33 -0400 Subject: [PATCH] Move commitment types into commitments module Docs, tidy --- zebra-chain/src/commitments.rs | 4 ++ .../commitments.rs => commitments/sapling.rs} | 36 ++++++++++++++-- .../src/commitments/sapling/arbitrary.rs | 33 +++++++++++++++ .../commitments.rs => commitments/sprout.rs} | 27 +++++++++++- zebra-chain/src/lib.rs | 1 + zebra-chain/src/notes.rs | 4 +- zebra-chain/src/notes/arbitrary.rs | 2 +- zebra-chain/src/notes/sapling.rs | 42 ++++++------------- zebra-chain/src/notes/sapling/arbitrary.rs | 32 +------------- zebra-chain/src/notes/sprout.rs | 30 +++---------- zebra-chain/src/notes/sprout/arbitrary.rs | 18 +------- zebra-chain/src/transaction/serialize.rs | 6 +-- zebra-chain/src/transaction/shielded_data.rs | 6 +-- .../src/transaction/tests/arbitrary.rs | 7 ++-- 14 files changed, 131 insertions(+), 117 deletions(-) create mode 100644 zebra-chain/src/commitments.rs rename zebra-chain/src/{notes/sapling/commitments.rs => commitments/sapling.rs} (90%) create mode 100644 zebra-chain/src/commitments/sapling/arbitrary.rs rename zebra-chain/src/{notes/sprout/commitments.rs => commitments/sprout.rs} (53%) diff --git a/zebra-chain/src/commitments.rs b/zebra-chain/src/commitments.rs new file mode 100644 index 000000000..15f094805 --- /dev/null +++ b/zebra-chain/src/commitments.rs @@ -0,0 +1,4 @@ +//! Note and value commitments and associated types. + +pub mod sapling; +pub mod sprout; diff --git a/zebra-chain/src/notes/sapling/commitments.rs b/zebra-chain/src/commitments/sapling.rs similarity index 90% rename from zebra-chain/src/notes/sapling/commitments.rs rename to zebra-chain/src/commitments/sapling.rs index 80da2f975..0f5cdce5a 100644 --- a/zebra-chain/src/notes/sapling/commitments.rs +++ b/zebra-chain/src/commitments/sapling.rs @@ -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}; @@ -7,6 +12,7 @@ use rand_core::{CryptoRng, RngCore}; use crate::{ keys::sapling::{find_group_hash, Diversifier, TransmissionKey}, + notes::sapling::Note, serde_helpers, serialization::{ReadZcashExt, SerializationError, ZcashDeserialize, ZcashSerialize}, types::amount::{Amount, NonNegative}, @@ -125,14 +131,38 @@ impl From for NoteCommitment { } } -impl Eq for NoteCommitment {} - impl From for [u8; 32] { fn from(cm: NoteCommitment) -> [u8; 32] { cm.0.to_bytes() } } +impl From 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 { fn zcash_serialize(&self, mut writer: W) -> Result<(), io::Error> { writer.write_all(&self.0.to_bytes())?; diff --git a/zebra-chain/src/commitments/sapling/arbitrary.rs b/zebra-chain/src/commitments/sapling/arbitrary.rs new file mode 100644 index 000000000..c13514888 --- /dev/null +++ b/zebra-chain/src/commitments/sapling/arbitrary.rs @@ -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::()) + .prop_filter("Valid jubjub::AffinePoint", |b| { + jubjub::AffinePoint::from_bytes(*b).is_some().unwrap_u8() == 1 + }) + .prop_map(Self::from) + .boxed() + } + + type Strategy = BoxedStrategy; +} + +impl Arbitrary for sapling::ValueCommitment { + type Parameters = (); + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + array::uniform32(any::()) + .prop_filter("Valid jubjub::AffinePoint", |b| { + jubjub::AffinePoint::from_bytes(*b).is_some().unwrap_u8() == 1 + }) + .prop_map(Self::from) + .boxed() + } + + type Strategy = BoxedStrategy; +} diff --git a/zebra-chain/src/notes/sprout/commitments.rs b/zebra-chain/src/commitments/sprout.rs similarity index 53% rename from zebra-chain/src/notes/sprout/commitments.rs rename to zebra-chain/src/commitments/sprout.rs index 931d9c85d..ecbe26168 100644 --- a/zebra-chain/src/notes/sprout/commitments.rs +++ b/zebra-chain/src/commitments/sprout.rs @@ -1,6 +1,15 @@ +//! Sprout commitment types. + +#![allow(clippy::unit_arg)] + 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. #[derive(Copy, Clone, Debug, PartialEq)] @@ -18,6 +27,22 @@ impl AsRef<[u8]> for CommitmentRandomness { #[cfg_attr(test, derive(proptest_derive::Arbitrary))] pub struct NoteCommitment(pub(crate) [u8; 32]); +impl From 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 { fn zcash_serialize(&self, mut writer: W) -> Result<(), io::Error> { writer.write_all(&self.0[..])?; diff --git a/zebra-chain/src/lib.rs b/zebra-chain/src/lib.rs index 776849d7a..e7546bc71 100644 --- a/zebra-chain/src/lib.rs +++ b/zebra-chain/src/lib.rs @@ -17,6 +17,7 @@ mod sha256d_writer; pub mod addresses; pub mod block; +pub mod commitments; pub mod equihash_solution; pub mod keys; pub mod notes; diff --git a/zebra-chain/src/notes.rs b/zebra-chain/src/notes.rs index 319a1cb3a..83b556eaa 100644 --- a/zebra-chain/src/notes.rs +++ b/zebra-chain/src/notes.rs @@ -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; pub mod sapling; diff --git a/zebra-chain/src/notes/arbitrary.rs b/zebra-chain/src/notes/arbitrary.rs index 7ca9994c4..c562f784c 100644 --- a/zebra-chain/src/notes/arbitrary.rs +++ b/zebra-chain/src/notes/arbitrary.rs @@ -1,6 +1,6 @@ use crate::notes::memo::Memo; -use proptest::{arbitrary::any, array, collection::vec, prelude::*}; +use proptest::{arbitrary::any, collection::vec, prelude::*}; impl Arbitrary for Memo { type Parameters = (); diff --git a/zebra-chain/src/notes/sapling.rs b/zebra-chain/src/notes/sapling.rs index 1189ca235..fe4171580 100644 --- a/zebra-chain/src/notes/sapling.rs +++ b/zebra-chain/src/notes/sapling.rs @@ -6,51 +6,33 @@ #[cfg(test)] mod arbitrary; mod ciphertexts; -mod commitments; mod nullifiers; use crate::{ + commitments::sapling::CommitmentRandomness, keys::sapling::{Diversifier, TransmissionKey}, notes::memo::Memo, types::amount::{Amount, NonNegative}, }; pub use ciphertexts::{EncryptedCiphertext, OutCiphertext}; -pub use commitments::{CommitmentRandomness, NoteCommitment, ValueCommitment}; + pub use nullifiers::Nullifier; /// A Note represents that a value is spendable by the recipient who /// holds the spending key corresponding to a given shielded payment /// address. pub struct Note { - diversifier: Diversifier, - transmission_key: TransmissionKey, - value: Amount, - rcm: CommitmentRandomness, -} - -impl Note { - /// 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 - pub fn commit(&self) -> NoteCommitment { - use rand_core::OsRng; - - NoteCommitment::new( - &mut OsRng, - self.diversifier, - self.transmission_key, - self.value, - ) - } + /// The diversier of the recipient’s shielded payment address. + pub diversifier: Diversifier, + /// The diversied transmission key of the recipient’s shielded + /// payment address. + pub transmission_key: TransmissionKey, + /// An integer representing the value of the note in zatoshi. + pub value: Amount, + /// A random commitment trapdoor used to produce the associated + /// note commitment. + pub rcm: CommitmentRandomness, } /// The decrypted form of encrypted Sapling notes on the blockchain. diff --git a/zebra-chain/src/notes/sapling/arbitrary.rs b/zebra-chain/src/notes/sapling/arbitrary.rs index 1526f1a2c..12812930d 100644 --- a/zebra-chain/src/notes/sapling/arbitrary.rs +++ b/zebra-chain/src/notes/sapling/arbitrary.rs @@ -1,4 +1,4 @@ -use proptest::{arbitrary::any, array, collection::vec, prelude::*}; +use proptest::{arbitrary::any, collection::vec, prelude::*}; use crate::notes::sapling; @@ -33,33 +33,3 @@ impl Arbitrary for sapling::OutCiphertext { type Strategy = BoxedStrategy; } - -impl Arbitrary for sapling::NoteCommitment { - type Parameters = (); - - fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { - array::uniform32(any::()) - .prop_filter("Valid jubjub::AffinePoint", |b| { - jubjub::AffinePoint::from_bytes(*b).is_some().unwrap_u8() == 1 - }) - .prop_map(Self::from) - .boxed() - } - - type Strategy = BoxedStrategy; -} - -impl Arbitrary for sapling::ValueCommitment { - type Parameters = (); - - fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { - array::uniform32(any::()) - .prop_filter("Valid jubjub::AffinePoint", |b| { - jubjub::AffinePoint::from_bytes(*b).is_some().unwrap_u8() == 1 - }) - .prop_map(Self::from) - .boxed() - } - - type Strategy = BoxedStrategy; -} diff --git a/zebra-chain/src/notes/sprout.rs b/zebra-chain/src/notes/sprout.rs index 1f346b6c6..55ff0e58a 100644 --- a/zebra-chain/src/notes/sprout.rs +++ b/zebra-chain/src/notes/sprout.rs @@ -6,19 +6,17 @@ #[cfg(test)] mod arbitrary; mod ciphertexts; -mod commitments; mod nullifiers; -use sha2::{Digest, Sha256}; - use crate::{ + commitments::sprout::CommitmentRandomness, keys::sprout::PayingKey, notes::memo::Memo, types::amount::{Amount, NonNegative}, }; pub use ciphertexts::EncryptedCiphertext; -pub use commitments::{CommitmentRandomness, NoteCommitment}; + pub use nullifiers::{Nullifier, NullifierSeed}; /// 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))] pub struct Note { /// The paying key of the recipient’s shielded payment address - paying_key: PayingKey, + pub paying_key: PayingKey, /// An integer representing the value of the note in zatoshi (1 ZEC /// = 10^8 zatoshi) - value: Amount, + pub value: Amount, /// Input to PRF^nf to derive the nullifier of the note - rho: NullifierSeed, + pub rho: NullifierSeed, /// A random commitment trapdoor - 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()) - } + pub rcm: CommitmentRandomness, } /// The decrypted form of encrypted Sprout notes on the blockchain. diff --git a/zebra-chain/src/notes/sprout/arbitrary.rs b/zebra-chain/src/notes/sprout/arbitrary.rs index 68470d878..becdc6e44 100644 --- a/zebra-chain/src/notes/sprout/arbitrary.rs +++ b/zebra-chain/src/notes/sprout/arbitrary.rs @@ -1,22 +1,6 @@ use proptest::{arbitrary::any, collection::vec, prelude::*}; -use crate::notes::{memo::Memo, sprout}; - -impl Arbitrary for Memo { - type Parameters = (); - - fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { - (vec(any::(), 512)) - .prop_map(|v| { - let mut bytes = [0; 512]; - bytes.copy_from_slice(v.as_slice()); - Memo(Box::new(bytes)) - }) - .boxed() - } - - type Strategy = BoxedStrategy; -} +use crate::notes::sprout; impl Arbitrary for sprout::EncryptedCiphertext { type Parameters = (); diff --git a/zebra-chain/src/transaction/serialize.rs b/zebra-chain/src/transaction/serialize.rs index f9c6ffa28..016ab1319 100644 --- a/zebra-chain/src/transaction/serialize.rs +++ b/zebra-chain/src/transaction/serialize.rs @@ -9,7 +9,7 @@ use std::{ }; use crate::{ - notes, + commitments, notes, proofs::ZkSnarkProof, serialization::{ ReadZcashExt, SerializationError, WriteZcashExt, ZcashDeserialize, ZcashSerialize, @@ -335,7 +335,7 @@ impl ZcashDeserialize for Spend { fn zcash_deserialize(mut reader: R) -> Result { use crate::treestate::note_commitment_tree::SaplingNoteTreeRootHash; Ok(Spend { - cv: notes::sapling::ValueCommitment::zcash_deserialize(&mut reader)?, + cv: commitments::sapling::ValueCommitment::zcash_deserialize(&mut reader)?, anchor: SaplingNoteTreeRootHash(reader.read_32_bytes()?), nullifier: notes::sapling::Nullifier::zcash_deserialize(&mut reader)?, rk: reader.read_32_bytes()?.into(), @@ -360,7 +360,7 @@ impl ZcashSerialize for Output { impl ZcashDeserialize for Output { fn zcash_deserialize(mut reader: R) -> Result { 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(), ephemeral_key: jubjub::AffinePoint::from_bytes(reader.read_32_bytes()?).unwrap(), enc_ciphertext: notes::sapling::EncryptedCiphertext::zcash_deserialize(&mut reader)?, diff --git a/zebra-chain/src/transaction/shielded_data.rs b/zebra-chain/src/transaction/shielded_data.rs index b4c3fbc20..a7a7927ae 100644 --- a/zebra-chain/src/transaction/shielded_data.rs +++ b/zebra-chain/src/transaction/shielded_data.rs @@ -1,5 +1,5 @@ use crate::{ - notes, + commitments, notes, proofs::Groth16Proof, redjubjub::{self, Binding, SpendAuth}, serde_helpers, @@ -13,7 +13,7 @@ use futures::future::Either; #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct Spend { /// 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. pub anchor: SaplingNoteTreeRootHash, /// The nullifier of the input note. @@ -32,7 +32,7 @@ pub struct Spend { #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Output { /// 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. #[serde(with = "serde_helpers::Fq")] pub cm_u: jubjub::Fq, diff --git a/zebra-chain/src/transaction/tests/arbitrary.rs b/zebra-chain/src/transaction/tests/arbitrary.rs index 7aba6e3bc..7ef78f8dd 100644 --- a/zebra-chain/src/transaction/tests/arbitrary.rs +++ b/zebra-chain/src/transaction/tests/arbitrary.rs @@ -1,4 +1,5 @@ use crate::{ + commitments, notes::{sapling, sprout}, proofs::{Groth16Proof, ZkSnarkProof}, transaction::{ @@ -94,8 +95,8 @@ impl Arbitrary for Output { fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { ( - any::(), - any::(), + any::(), + any::(), array::uniform32(any::()).prop_filter("Valid jubjub::AffinePoint", |b| { 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 { ( any::(), - any::(), + any::(), any::(), array::uniform32(any::()), any::(),