From f64e0c4bc576eb8b5b8056c3cbeee95bf05b542b Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Fri, 17 Jul 2020 02:35:11 -0400 Subject: [PATCH] Sapling value commitment, half done Sapling note commitment --- zebra-chain/src/keys/sapling.rs | 4 +- zebra-chain/src/notes/sapling.rs | 17 +++++- zebra-chain/src/notes/sapling/commitments.rs | 58 +++++++++++++++++++- 3 files changed, 74 insertions(+), 5 deletions(-) diff --git a/zebra-chain/src/keys/sapling.rs b/zebra-chain/src/keys/sapling.rs index 9d325c9f..344c7c35 100644 --- a/zebra-chain/src/keys/sapling.rs +++ b/zebra-chain/src/keys/sapling.rs @@ -124,7 +124,9 @@ fn jubjub_group_hash(d: [u8; 8], m: &[u8]) -> Option { /// /// [0]: https://github.com/zcash/librustzcash/blob/master/zcash_primitives/src/jubjub/mod.rs#L409 /// https://zips.z.cash/protocol/protocol.pdf#concretegrouphashjubjub -fn find_group_hash(d: [u8; 8], m: &[u8]) -> jubjub::ExtendedPoint { +// TODO: move common functions like these out of the keys module into +// a more appropriate location +pub fn find_group_hash(d: [u8; 8], m: &[u8]) -> jubjub::ExtendedPoint { let mut tag = m.to_vec(); let i = tag.len(); tag.push(0u8); diff --git a/zebra-chain/src/notes/sapling.rs b/zebra-chain/src/notes/sapling.rs index f949df08..0c379ddd 100644 --- a/zebra-chain/src/notes/sapling.rs +++ b/zebra-chain/src/notes/sapling.rs @@ -8,7 +8,7 @@ mod commitments; mod nullifiers; use crate::{ - keys::sapling::{Diversifier, TransmissionKey}, + keys::sapling::{diversify_hash, find_group_hash, Diversifier, TransmissionKey}, notes::memo::Memo, types::amount::{Amount, NonNegative}, }; @@ -17,6 +17,11 @@ pub use ciphertexts::{EncryptedCiphertext, OutCiphertext}; pub use commitments::{CommitmentRandomness, NoteCommitment, ValueCommitment}; pub use nullifiers::Nullifier; +/// +/// +/// https://zips.z.cash/protocol/protocol.pdf#concretepedersenhash +pub fn pedersen_hash_to_point() {} + /// A Note represents that a value is spendable by the recipient who /// holds the spending key corresponding to a given shielded payment /// address. @@ -32,9 +37,17 @@ impl Note { /// 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 { - unimplemented!() + let g_d = diversify_hash(self.diversifier.0).unwrap(); + + NoteCommitment::new(g_d, self.transmission_key, self.value) } } diff --git a/zebra-chain/src/notes/sapling/commitments.rs b/zebra-chain/src/notes/sapling/commitments.rs index 57d75b67..f4e408e8 100644 --- a/zebra-chain/src/notes/sapling/commitments.rs +++ b/zebra-chain/src/notes/sapling/commitments.rs @@ -1,10 +1,17 @@ use std::{fmt, io}; +use rand_core::{CryptoRng, RngCore}; + use crate::{ + keys::sapling::find_group_hash, serde_helpers, serialization::{ReadZcashExt, SerializationError, ZcashDeserialize, ZcashSerialize}, }; +// TODO: replace with reference to redjubjub or jubjub when merged and +// exported. +type Scalar = jubjub::Fr; + /// The randomness used in the Pedersen Hash for note commitment. #[derive(Copy, Clone, Debug, PartialEq)] pub struct CommitmentRandomness(redjubjub::Randomizer); @@ -38,8 +45,6 @@ impl From for [u8; 32] { } impl ZcashSerialize for NoteCommitment { - // The u-coordinate of the note commitment, for the output note - // LEBS2OSP256(cm_u) where cm_u = Extract_J(r)(cm). ??? fn zcash_serialize(&self, mut writer: W) -> Result<(), io::Error> { writer.write_all(&self.0.to_bytes())?; Ok(()) @@ -55,6 +60,26 @@ impl ZcashDeserialize for NoteCommitment { } impl NoteCommitment { + /// Generate a new _NoteCommitment_. + /// + /// https://zips.z.cash/protocol/protocol.pdf#concretewindowedcommit + #[allow(non_snake_case)] + pub fn new(csprng: &mut T, value_bytes: [u8; 32]) -> Self + where + T: RngCore + CryptoRng, + { + let v = Scalar::from_bytes(&value_bytes).unwrap(); + + let mut rcv_bytes = [0u8; 32]; + csprng.fill_bytes(&mut rcv_bytes); + let rcv = Scalar::from_bytes(&rcv_bytes).unwrap(); + + let V = find_group_hash(*b"Zcash_cv", b"v"); + let R = find_group_hash(*b"Zcash_cv", b"r"); + + Self::from(V * v + R * rcv) + } + /// Hash Extractor for Jubjub (?) /// /// https://zips.z.cash/protocol/protocol.pdf#concreteextractorjubjub @@ -86,6 +111,12 @@ impl From<[u8; 32]> for ValueCommitment { } } +impl From for ValueCommitment { + fn from(extended_point: jubjub::ExtendedPoint) -> Self { + Self(jubjub::AffinePoint::from(extended_point)) + } +} + impl Eq for ValueCommitment {} impl From for [u8; 32] { @@ -112,3 +143,26 @@ impl ZcashDeserialize for ValueCommitment { )) } } + +impl ValueCommitment { + /// Generate a new _ValueCommitment_. + /// + /// https://zips.z.cash/protocol/protocol.pdf#concretehomomorphiccommit + // TODO: accept an Amount instead? + #[allow(non_snake_case)] + pub fn new(csprng: &mut T, value_bytes: [u8; 32]) -> Self + where + T: RngCore + CryptoRng, + { + let v = Scalar::from_bytes(&value_bytes).unwrap(); + + let mut rcv_bytes = [0u8; 32]; + csprng.fill_bytes(&mut rcv_bytes); + let rcv = Scalar::from_bytes(&rcv_bytes).unwrap(); + + let V = find_group_hash(*b"Zcash_cv", b"v"); + let R = find_group_hash(*b"Zcash_cv", b"r"); + + Self::from(V * v + R * rcv) + } +}