From 00e750654a984052ec9ee17c8e7f342a977d163e Mon Sep 17 00:00:00 2001 From: Jane Lusby Date: Wed, 1 Jul 2020 17:57:32 -0700 Subject: [PATCH] add nullifier types (#568) * add nullifier types * Apply suggestions from code review Co-authored-by: Deirdre Connolly * add zcash_deserialize impls * Add docs Co-authored-by: Deirdre Connolly --- zebra-chain/src/lib.rs | 1 + zebra-chain/src/nullifier.rs | 4 +++ zebra-chain/src/nullifier/sapling.rs | 30 +++++++++++++++++++ zebra-chain/src/nullifier/sprout.rs | 30 +++++++++++++++++++ zebra-chain/src/transaction/joinsplit.rs | 2 +- zebra-chain/src/transaction/serialize.rs | 13 ++++---- zebra-chain/src/transaction/shielded_data.rs | 4 +-- .../src/transaction/tests/arbitrary.rs | 4 +-- 8 files changed, 77 insertions(+), 11 deletions(-) create mode 100644 zebra-chain/src/nullifier.rs create mode 100644 zebra-chain/src/nullifier/sapling.rs create mode 100644 zebra-chain/src/nullifier/sprout.rs diff --git a/zebra-chain/src/lib.rs b/zebra-chain/src/lib.rs index 9902bb19..c070606e 100644 --- a/zebra-chain/src/lib.rs +++ b/zebra-chain/src/lib.rs @@ -17,6 +17,7 @@ pub mod equihash_solution; pub mod keys; pub mod note_commitment_tree; pub mod notes; +pub mod nullifier; pub mod proofs; pub mod serialization; pub mod transaction; diff --git a/zebra-chain/src/nullifier.rs b/zebra-chain/src/nullifier.rs new file mode 100644 index 00000000..7304409a --- /dev/null +++ b/zebra-chain/src/nullifier.rs @@ -0,0 +1,4 @@ +//! Nullifier set types for sproud and sapling + +pub mod sapling; +pub mod sprout; diff --git a/zebra-chain/src/nullifier/sapling.rs b/zebra-chain/src/nullifier/sapling.rs new file mode 100644 index 00000000..21845a9d --- /dev/null +++ b/zebra-chain/src/nullifier/sapling.rs @@ -0,0 +1,30 @@ +//! Sapling Nullifier Set types and impls +#![allow(clippy::unit_arg)] +use crate::serialization::{ReadZcashExt, SerializationError, ZcashDeserialize, ZcashSerialize}; +use serde::{Deserialize, Serialize}; +use std::io; + +/// A Nullifier Set for Sapling transactions +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[cfg_attr(test, derive(proptest_derive::Arbitrary))] +pub struct Nullifier([u8; 32]); + +impl From<[u8; 32]> for Nullifier { + fn from(buf: [u8; 32]) -> Self { + Self(buf) + } +} + +impl ZcashDeserialize for Nullifier { + fn zcash_deserialize(mut reader: R) -> Result { + let bytes = reader.read_32_bytes()?; + + Ok(Self(bytes)) + } +} + +impl ZcashSerialize for Nullifier { + fn zcash_serialize(&self, mut writer: W) -> Result<(), io::Error> { + writer.write_all(&self.0[..]) + } +} diff --git a/zebra-chain/src/nullifier/sprout.rs b/zebra-chain/src/nullifier/sprout.rs new file mode 100644 index 00000000..de0b3a6b --- /dev/null +++ b/zebra-chain/src/nullifier/sprout.rs @@ -0,0 +1,30 @@ +//! Sprout Nullifier Set types and impls +#![allow(clippy::unit_arg)] +use crate::serialization::{ReadZcashExt, SerializationError, ZcashDeserialize, ZcashSerialize}; +use serde::{Deserialize, Serialize}; +use std::io; + +/// A Nullifier Set for Sprout transactions +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[cfg_attr(test, derive(proptest_derive::Arbitrary))] +pub struct Nullifier([u8; 32]); + +impl From<[u8; 32]> for Nullifier { + fn from(buf: [u8; 32]) -> Self { + Self(buf) + } +} + +impl ZcashDeserialize for Nullifier { + fn zcash_deserialize(mut reader: R) -> Result { + let bytes = reader.read_32_bytes()?; + + Ok(Self(bytes)) + } +} + +impl ZcashSerialize for Nullifier { + fn zcash_serialize(&self, mut writer: W) -> Result<(), io::Error> { + writer.write_all(&self.0[..]) + } +} diff --git a/zebra-chain/src/transaction/joinsplit.rs b/zebra-chain/src/transaction/joinsplit.rs index 8ce679e8..f94ed08e 100644 --- a/zebra-chain/src/transaction/joinsplit.rs +++ b/zebra-chain/src/transaction/joinsplit.rs @@ -23,7 +23,7 @@ pub struct JoinSplit { /// A nullifier for the input notes. /// /// XXX refine type to [T; 2] -- there are two nullifiers - pub nullifiers: [[u8; 32]; 2], + pub nullifiers: [crate::nullifier::sprout::Nullifier; 2], /// A note commitment for this output note. /// /// XXX refine type to [T; 2] -- there are two commitments diff --git a/zebra-chain/src/transaction/serialize.rs b/zebra-chain/src/transaction/serialize.rs index d49e7a6f..f98bb5b6 100644 --- a/zebra-chain/src/transaction/serialize.rs +++ b/zebra-chain/src/transaction/serialize.rs @@ -236,8 +236,8 @@ impl ZcashSerialize for JoinSplit

{ writer.write_u64::(self.vpub_old.into())?; writer.write_u64::(self.vpub_new.into())?; writer.write_all(&self.anchor[..])?; - writer.write_all(&self.nullifiers[0][..])?; - writer.write_all(&self.nullifiers[1][..])?; + self.nullifiers[0].zcash_serialize(&mut writer)?; + self.nullifiers[1].zcash_serialize(&mut writer)?; writer.write_all(&self.commitments[0][..])?; writer.write_all(&self.commitments[1][..])?; writer.write_all(&self.ephemeral_key.as_bytes()[..])?; @@ -257,7 +257,10 @@ impl ZcashDeserialize for JoinSplit

{ vpub_old: reader.read_u64::()?.try_into()?, vpub_new: reader.read_u64::()?.try_into()?, anchor: reader.read_32_bytes()?, - nullifiers: [reader.read_32_bytes()?, reader.read_32_bytes()?], + nullifiers: [ + crate::nullifier::sprout::Nullifier::zcash_deserialize(&mut reader)?, + crate::nullifier::sprout::Nullifier::zcash_deserialize(&mut reader)?, + ], commitments: [reader.read_32_bytes()?, reader.read_32_bytes()?], ephemeral_key: x25519_dalek::PublicKey::from(reader.read_32_bytes()?), random_seed: reader.read_32_bytes()?, @@ -314,7 +317,7 @@ impl ZcashSerialize for Spend { fn zcash_serialize(&self, mut writer: W) -> Result<(), io::Error> { writer.write_all(&self.cv[..])?; writer.write_all(&self.anchor.0[..])?; - writer.write_all(&self.nullifier[..])?; + self.nullifier.zcash_serialize(&mut writer)?; writer.write_all(&<[u8; 32]>::from(self.rk)[..])?; self.zkproof.zcash_serialize(&mut writer)?; writer.write_all(&<[u8; 64]>::from(self.spend_auth_sig)[..])?; @@ -328,7 +331,7 @@ impl ZcashDeserialize for Spend { Ok(Spend { cv: reader.read_32_bytes()?, anchor: SaplingNoteTreeRootHash(reader.read_32_bytes()?), - nullifier: reader.read_32_bytes()?, + nullifier: crate::nullifier::sapling::Nullifier::zcash_deserialize(&mut reader)?, rk: reader.read_32_bytes()?.into(), zkproof: Groth16Proof::zcash_deserialize(&mut reader)?, spend_auth_sig: reader.read_64_bytes()?.into(), diff --git a/zebra-chain/src/transaction/shielded_data.rs b/zebra-chain/src/transaction/shielded_data.rs index 3776c235..f97aac54 100644 --- a/zebra-chain/src/transaction/shielded_data.rs +++ b/zebra-chain/src/transaction/shielded_data.rs @@ -18,9 +18,7 @@ pub struct Spend { /// A root of the Sapling note commitment tree at some block height in the past. pub anchor: SaplingNoteTreeRootHash, /// The nullifier of the input note. - /// - /// XXX refine to a specific type. - pub nullifier: [u8; 32], + pub nullifier: crate::nullifier::sapling::Nullifier, /// The randomized public key for `spend_auth_sig`. pub rk: redjubjub::PublicKeyBytes, /// The ZK spend proof. diff --git a/zebra-chain/src/transaction/tests/arbitrary.rs b/zebra-chain/src/transaction/tests/arbitrary.rs index 3e40dda4..e988cb0d 100644 --- a/zebra-chain/src/transaction/tests/arbitrary.rs +++ b/zebra-chain/src/transaction/tests/arbitrary.rs @@ -22,7 +22,7 @@ impl Arbitrary for JoinSplit

{ any::>(), any::>(), array::uniform32(any::()), - array::uniform2(array::uniform32(any::())), + array::uniform2(any::()), array::uniform2(array::uniform32(any::())), array::uniform32(any::()), array::uniform32(any::()), @@ -155,7 +155,7 @@ impl Arbitrary for Spend { ( array::uniform32(any::()), any::(), - array::uniform32(any::()), + any::(), array::uniform32(any::()), any::(), vec(any::(), 64),