Refine JoinSplit ephemeral keys to be x25519_dalek::PublicKey

Impls PartialEq and Eq and Arbitrary on JoinSplit because PublicKey
does not impl them and we can't do it directly.

Resolves #313
This commit is contained in:
Deirdre Connolly 2020-04-13 14:45:43 -04:00 committed by Deirdre Connolly
parent baf305b856
commit 05ca1c0c8a
2 changed files with 74 additions and 6 deletions

View File

@ -16,8 +16,7 @@ use crate::{
/// A _JoinSplit Description_, as described in [protocol specification §7.2][ps].
///
/// [ps]: https://zips.z.cash/protocol/protocol.pdf#joinsplitencoding
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(test, derive(Arbitrary))]
#[derive(Clone, Debug)]
pub struct JoinSplit<P: ZkSnarkProof> {
/// A value that the JoinSplit transfer removes from the transparent value
/// pool.
@ -46,7 +45,7 @@ pub struct JoinSplit<P: ZkSnarkProof> {
/// An X25519 public key.
///
/// XXX refine to an x25519-dalek type?
pub ephemeral_key: [u8; 32],
pub ephemeral_key: x25519_dalek::PublicKey,
/// A 256-bit seed that must be chosen independently at random for each
/// JoinSplit description.
pub random_seed: [u8; 32],
@ -62,8 +61,77 @@ pub struct JoinSplit<P: ZkSnarkProof> {
pub enc_ciphertexts: [EncryptedCiphertext; 2],
}
// Because x25519_dalek::PublicKey does not impl PartialEq
impl<P: ZkSnarkProof> PartialEq for JoinSplit<P> {
fn eq(&self, other: &Self) -> bool {
self.vpub_old == other.vpub_old
&& self.vpub_new == other.vpub_new
&& self.anchor == other.anchor
&& self.nullifiers == other.nullifiers
&& self.commitments == other.commitments
&& self.ephemeral_key.as_bytes() == other.ephemeral_key.as_bytes()
&& self.random_seed == other.random_seed
&& self.vmacs == other.vmacs
&& self.zkproof == other.zkproof
&& self.enc_ciphertexts == other.enc_ciphertexts
}
}
// Because x25519_dalek::PublicKey does not impl Eq
impl<P: ZkSnarkProof> Eq for JoinSplit<P> {}
#[cfg(test)]
impl<P: ZkSnarkProof + Arbitrary + 'static> Arbitrary for JoinSplit<P> {
type Parameters = ();
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
(
any::<u64>(),
any::<u64>(),
array::uniform32(any::<u8>()),
array::uniform2(array::uniform32(any::<u8>())),
array::uniform2(array::uniform32(any::<u8>())),
array::uniform32(any::<u8>()),
array::uniform32(any::<u8>()),
array::uniform2(array::uniform32(any::<u8>())),
any::<P>(),
array::uniform2(any::<EncryptedCiphertext>()),
)
.prop_map(
|(
vpub_old,
vpub_new,
anchor,
nullifiers,
commitments,
ephemeral_key_bytes,
random_seed,
vmacs,
zkproof,
enc_ciphertexts,
)| {
return Self {
vpub_old,
vpub_new,
anchor,
nullifiers,
commitments,
ephemeral_key: x25519_dalek::PublicKey::from(ephemeral_key_bytes),
random_seed,
vmacs,
zkproof,
enc_ciphertexts,
};
},
)
.boxed()
}
type Strategy = BoxedStrategy<Self>;
}
/// A bundle of JoinSplit descriptions and signature data.
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct JoinSplitData<P: ZkSnarkProof> {
/// The first JoinSplit description, using proofs of type `P`.
///

View File

@ -235,7 +235,7 @@ impl<P: ZkSnarkProof> ZcashSerialize for JoinSplit<P> {
writer.write_all(&self.nullifiers[1][..])?;
writer.write_all(&self.commitments[0][..])?;
writer.write_all(&self.commitments[1][..])?;
writer.write_all(&self.ephemeral_key[..])?;
writer.write_all(&self.ephemeral_key.as_bytes()[..])?;
writer.write_all(&self.random_seed[..])?;
writer.write_all(&self.vmacs[0][..])?;
writer.write_all(&self.vmacs[1][..])?;
@ -254,7 +254,7 @@ impl<P: ZkSnarkProof> ZcashDeserialize for JoinSplit<P> {
anchor: reader.read_32_bytes()?,
nullifiers: [reader.read_32_bytes()?, reader.read_32_bytes()?],
commitments: [reader.read_32_bytes()?, reader.read_32_bytes()?],
ephemeral_key: reader.read_32_bytes()?,
ephemeral_key: x25519_dalek::PublicKey::from(reader.read_32_bytes()?),
random_seed: reader.read_32_bytes()?,
vmacs: [reader.read_32_bytes()?, reader.read_32_bytes()?],
zkproof: P::zcash_deserialize(&mut reader)?,