From 0f46a9b6a84f07ef23f1f0cf289fd920a035bf5a Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Mon, 13 Jul 2020 18:38:49 -0400 Subject: [PATCH] NoteCommitments, renames, ValueCommitment, strategies, stub commit() --- zebra-chain/src/keys/sprout.rs | 1 + zebra-chain/src/notes/memo.rs | 20 ++++++++++++++++ zebra-chain/src/notes/sapling.rs | 31 ++++++++++++++++++++++--- zebra-chain/src/notes/sprout.rs | 40 +++++++++++++++++++++----------- 4 files changed, 76 insertions(+), 16 deletions(-) diff --git a/zebra-chain/src/keys/sprout.rs b/zebra-chain/src/keys/sprout.rs index 10ccc0e9..f320166a 100644 --- a/zebra-chain/src/keys/sprout.rs +++ b/zebra-chain/src/keys/sprout.rs @@ -176,6 +176,7 @@ impl From for ReceivingKey { /// Derived from a _SpendingKey_. #[derive(Copy, Clone, Eq, PartialEq)] +#[cfg_attr(test, derive(proptest_derive::Arbitrary))] pub struct PayingKey(pub [u8; 32]); impl AsRef<[u8]> for PayingKey { diff --git a/zebra-chain/src/notes/memo.rs b/zebra-chain/src/notes/memo.rs index 49c34ee1..9d9bfd1e 100644 --- a/zebra-chain/src/notes/memo.rs +++ b/zebra-chain/src/notes/memo.rs @@ -1,5 +1,8 @@ use std::{cmp, convert::TryFrom, fmt}; +#[cfg(test)] +use proptest::{arbitrary::Arbitrary, collection::vec, prelude::*}; + /// A 512-byte _Memo_ field associated with a note, as described in /// [protocol specification §5.5][ps]. /// @@ -48,6 +51,23 @@ impl fmt::Debug for Memo { } } +#[cfg(test)] +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; +} + #[test] fn memo_fmt() { let memo = Memo(Box::new( diff --git a/zebra-chain/src/notes/sapling.rs b/zebra-chain/src/notes/sapling.rs index 9a3195e2..b0a4ead9 100644 --- a/zebra-chain/src/notes/sapling.rs +++ b/zebra-chain/src/notes/sapling.rs @@ -1,4 +1,3 @@ -//! #![allow(clippy::unit_arg)] #![allow(dead_code)] @@ -51,14 +50,33 @@ pub struct Note { diversifier: Diversifier, transmission_key: TransmissionKey, value: Amount, - note_commitment_randomness: NoteCommitmentRandomness, + rcm: NoteCommitmentRandomness, } +impl Note { + /// Construct a “windowed” Pedersen commitment by reusing a + /// Perderson hash constructon, and adding a randomized point on + /// the Jubjub curve. + /// + /// https://zips.z.cash/protocol/protocol.pdf#concretewindowedcommit + pub fn commit(&self) -> NoteCommitment { + // Windowed Pedersen Commitment + + // NoteCommitment() + unimplemented!() + } +} + +/// +#[derive(Clone, Copy, Debug)] +//#[cfg_attr(test, derive(proptest_derive::Arbitrary))] +pub struct NoteCommitment(jubjub::ExtendedPoint); + /// The decrypted form of encrypted Sapling notes on the blockchain. pub struct NotePlaintext { diversifier: Diversifier, value: Amount, - note_commitment_randomness: NoteCommitmentRandomness, + rcm: NoteCommitmentRandomness, memo: memo::Memo, } @@ -190,6 +208,13 @@ impl Arbitrary for OutCiphertext { type Strategy = BoxedStrategy; } +/// A Homomorphic Pedersen commitment to the value of a note, used in +/// Spend and Output Descriptions. +/// +/// https://zips.z.cash/protocol/protocol.pdf#concretehomomorphiccommit +#[derive(Clone, Copy, Debug)] +pub struct ValueCommitment(pub jubjub::ExtendedPoint); + #[cfg(test)] proptest! { diff --git a/zebra-chain/src/notes/sprout.rs b/zebra-chain/src/notes/sprout.rs index 067c5de5..c65bb180 100644 --- a/zebra-chain/src/notes/sprout.rs +++ b/zebra-chain/src/notes/sprout.rs @@ -46,8 +46,9 @@ fn prf_nf(a_sk: [u8; 32], rho: [u8; 32]) -> [u8; 32] { /// Nullifier seed, named rho in the [spec][ps]. /// /// [ps]: https://zips.z.cash/protocol/protocol.pdf#sproutkeycomponents -#[derive(Clone, Copy)] -struct NullifierSeed([u8; 32]); +#[derive(Clone, Copy, Debug)] +#[cfg_attr(test, derive(proptest_derive::Arbitrary))] +pub struct NullifierSeed([u8; 32]); impl AsRef<[u8]> for NullifierSeed { fn as_ref(&self) -> &[u8] { @@ -94,6 +95,7 @@ impl ZcashSerialize for Nullifier { /// The randomness used in the Pedersen Hash for note commitment. #[derive(Copy, Clone, Debug, PartialEq)] +#[cfg_attr(test, derive(proptest_derive::Arbitrary))] pub struct NoteCommitmentRandomness(pub [u8; 32]); impl AsRef<[u8]> for NoteCommitmentRandomness { @@ -102,39 +104,51 @@ impl AsRef<[u8]> for NoteCommitmentRandomness { } } +/// +#[derive(Clone, Copy, Debug)] +#[cfg_attr(test, derive(proptest_derive::Arbitrary))] +pub struct NoteCommitment([u8; 32]); + /// A Note represents that a value is spendable by the recipient who /// holds the spending key corresponding to a given shielded payment /// address. +/// +/// https://zips.z.cash/protocol/protocol.pdf#notes +#[derive(Clone, Copy, Debug)] +#[cfg_attr(test, derive(proptest_derive::Arbitrary))] pub struct Note { + /// The paying key of the recipient’s shielded payment address paying_key: PayingKey, + /// An integer representing the value of the note in zatoshi (1 ZEC + /// = 10^8 zatoshi) value: Amount, - nullifier_seed: NullifierSeed, - note_commitment_randomness: NoteCommitmentRandomness, + /// Input to PRF^nf to derive the nullifier of the note + rho: NullifierSeed, + /// A random commitment trapdoor + rcm: NoteCommitmentRandomness, } impl Note { - pub fn commitment(&self) -> NoteCommitment { + 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.nullifier_seed); - hasher.input(self.note_commitment_randomness); + hasher.input(self.rho); + hasher.input(self.rcm); NoteCommitment(hasher.result().into()) } } -/// -pub struct NoteCommitment([u8; 32]); - /// The decrypted form of encrypted Sprout notes on the blockchain. +#[derive(Clone, Debug)] +#[cfg_attr(test, derive(proptest_derive::Arbitrary))] pub struct NotePlaintext { value: Amount, - // TODO: refine type - rho: [u8; 32], - note_commitment_randomness: NoteCommitmentRandomness, + rho: NullifierSeed, + rcm: NoteCommitmentRandomness, memo: Memo, }