From e8fdd0e1f3cfaea6bc4087d655aa5c56d780c62b Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Sat, 8 Aug 2020 04:47:54 -0400 Subject: [PATCH] Impl TryFrom for Commitments, call from impl ZcashDeserialize --- zebra-chain/src/commitments/sapling.rs | 77 +++++++++++++++---- .../src/commitments/sapling/arbitrary.rs | 12 +-- zebra-chain/src/transaction/serialize.rs | 10 +-- 3 files changed, 69 insertions(+), 30 deletions(-) diff --git a/zebra-chain/src/commitments/sapling.rs b/zebra-chain/src/commitments/sapling.rs index 74f4a8aa..412cf11b 100644 --- a/zebra-chain/src/commitments/sapling.rs +++ b/zebra-chain/src/commitments/sapling.rs @@ -7,7 +7,7 @@ mod test_vectors; pub mod pedersen_hashes; -use std::fmt; +use std::{convert::TryFrom, fmt, io}; use bitvec::prelude::*; use rand_core::{CryptoRng, RngCore}; @@ -15,6 +15,7 @@ use rand_core::{CryptoRng, RngCore}; use crate::{ keys::sapling::{find_group_hash, Diversifier, TransmissionKey}, serde_helpers, + serialization::{ReadZcashExt, SerializationError, ZcashDeserialize, ZcashSerialize}, types::amount::{Amount, NonNegative}, }; @@ -37,12 +38,6 @@ impl fmt::Debug for NoteCommitment { } } -impl From<[u8; 32]> for NoteCommitment { - fn from(bytes: [u8; 32]) -> Self { - Self(jubjub::AffinePoint::from_bytes(bytes).unwrap()) - } -} - impl From for NoteCommitment { fn from(extended_point: jubjub::ExtendedPoint) -> Self { Self(jubjub::AffinePoint::from(extended_point)) @@ -57,6 +52,33 @@ impl From for [u8; 32] { impl Eq for NoteCommitment {} +impl TryFrom<[u8; 32]> for NoteCommitment { + type Error = &'static str; + + fn try_from(bytes: [u8; 32]) -> Result { + let possible_point = jubjub::AffinePoint::from_bytes(bytes); + + if possible_point.is_some().into() { + Ok(Self(possible_point.unwrap())) + } else { + Err("Invalid jubjub::AffinePoint value") + } + } +} + +impl ZcashSerialize for NoteCommitment { + fn zcash_serialize(&self, mut writer: W) -> Result<(), io::Error> { + writer.write_all(&<[u8; 32]>::from(*self)[..])?; + Ok(()) + } +} + +impl ZcashDeserialize for NoteCommitment { + fn zcash_deserialize(mut reader: R) -> Result { + Self::try_from(reader.read_32_bytes()?).map_err(|e| SerializationError::Parse(e)) + } +} + impl NoteCommitment { /// Generate a new _NoteCommitment_ and the randomness used to create it. /// @@ -128,16 +150,6 @@ impl fmt::Debug for ValueCommitment { } } -/// LEBS2OSP256(repr_J(cv)) -/// -/// https://zips.z.cash/protocol/protocol.pdf#spendencoding -/// https://zips.z.cash/protocol/protocol.pdf#jubjub -impl From<[u8; 32]> for ValueCommitment { - fn from(bytes: [u8; 32]) -> Self { - Self(jubjub::AffinePoint::from_bytes(bytes).unwrap()) - } -} - impl From for ValueCommitment { fn from(extended_point: jubjub::ExtendedPoint) -> Self { Self(jubjub::AffinePoint::from(extended_point)) @@ -156,6 +168,37 @@ impl From for [u8; 32] { } } +/// LEBS2OSP256(repr_J(cv)) +/// +/// https://zips.z.cash/protocol/protocol.pdf#spendencoding +/// https://zips.z.cash/protocol/protocol.pdf#jubjub +impl TryFrom<[u8; 32]> for ValueCommitment { + type Error = &'static str; + + fn try_from(bytes: [u8; 32]) -> Result { + let possible_point = jubjub::AffinePoint::from_bytes(bytes); + + if possible_point.is_some().into() { + Ok(Self(possible_point.unwrap())) + } else { + Err("Invalid jubjub::AffinePoint value") + } + } +} + +impl ZcashSerialize for ValueCommitment { + fn zcash_serialize(&self, mut writer: W) -> Result<(), io::Error> { + writer.write_all(&<[u8; 32]>::from(*self)[..])?; + Ok(()) + } +} + +impl ZcashDeserialize for ValueCommitment { + fn zcash_deserialize(mut reader: R) -> Result { + Self::try_from(reader.read_32_bytes()?).map_err(|e| SerializationError::Parse(e)) + } +} + impl ValueCommitment { /// Generate a new _ValueCommitment_. /// diff --git a/zebra-chain/src/commitments/sapling/arbitrary.rs b/zebra-chain/src/commitments/sapling/arbitrary.rs index c1351488..27b1abd9 100644 --- a/zebra-chain/src/commitments/sapling/arbitrary.rs +++ b/zebra-chain/src/commitments/sapling/arbitrary.rs @@ -1,3 +1,5 @@ +use std::convert::TryFrom; + use proptest::{arbitrary::any, array, prelude::*}; use crate::commitments::sapling; @@ -7,10 +9,7 @@ impl Arbitrary for sapling::NoteCommitment { 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) + .prop_filter_map("Valid jubjub::AffinePoint", |b| Self::try_from(b).ok()) .boxed() } @@ -22,10 +21,7 @@ impl Arbitrary for sapling::ValueCommitment { 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) + .prop_filter_map("Valid jubjub::AffinePoint", |b| Self::try_from(b).ok()) .boxed() } diff --git a/zebra-chain/src/transaction/serialize.rs b/zebra-chain/src/transaction/serialize.rs index d57b6387..016ab131 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, @@ -321,7 +321,7 @@ impl ZcashDeserialize for Option> { impl ZcashSerialize for Spend { fn zcash_serialize(&self, mut writer: W) -> Result<(), io::Error> { - writer.write_all(&<[u8; 32]>::from(self.cv)[..])?; + self.cv.zcash_serialize(&mut writer)?; writer.write_all(&self.anchor.0[..])?; self.nullifier.zcash_serialize(&mut writer)?; writer.write_all(&<[u8; 32]>::from(self.rk)[..])?; @@ -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: reader.read_32_bytes()?.into(), + 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(), @@ -347,7 +347,7 @@ impl ZcashDeserialize for Spend { impl ZcashSerialize for Output { fn zcash_serialize(&self, mut writer: W) -> Result<(), io::Error> { - writer.write_all(&<[u8; 32]>::from(self.cv)[..])?; + self.cv.zcash_serialize(&mut writer)?; writer.write_all(&self.cm_u.to_bytes())?; writer.write_all(&self.ephemeral_key.to_bytes())?; self.enc_ciphertext.zcash_serialize(&mut writer)?; @@ -360,7 +360,7 @@ impl ZcashSerialize for Output { impl ZcashDeserialize for Output { fn zcash_deserialize(mut reader: R) -> Result { Ok(Output { - cv: reader.read_32_bytes()?.into(), + 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)?,