Add Sapling EphemeralPublicKey type that wraps jubjub::AffinePoint
This commit is contained in:
parent
52a10d2837
commit
6b13ce3e83
|
|
@ -9,6 +9,8 @@
|
|||
//! [3.1]: https://zips.z.cash/protocol/protocol.pdf#addressesandkeys
|
||||
#![allow(clippy::unit_arg)]
|
||||
|
||||
#[cfg(test)]
|
||||
mod arbitrary;
|
||||
#[cfg(test)]
|
||||
mod test_vectors;
|
||||
#[cfg(test)]
|
||||
|
|
@ -29,7 +31,8 @@ use proptest_derive::Arbitrary;
|
|||
|
||||
use crate::{
|
||||
redjubjub::{self, SpendAuth},
|
||||
serialization::{ReadZcashExt, SerializationError},
|
||||
serde_helpers,
|
||||
serialization::{ReadZcashExt, SerializationError, ZcashDeserialize, ZcashSerialize},
|
||||
Network,
|
||||
};
|
||||
|
||||
|
|
@ -860,3 +863,59 @@ impl FromStr for FullViewingKey {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An ephemeral public key for Sapling key agreement.
|
||||
///
|
||||
/// https://zips.z.cash/protocol/canopy.pdf#concretesaplingkeyagreement
|
||||
#[derive(Copy, Clone, Deserialize, PartialEq, Serialize)]
|
||||
pub struct EphemeralPublicKey(#[serde(with = "serde_helpers::AffinePoint")] jubjub::AffinePoint);
|
||||
|
||||
impl fmt::Debug for EphemeralPublicKey {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("EphemeralPublicKey")
|
||||
.field("u", &hex::encode(self.0.get_u().to_bytes()))
|
||||
.field("v", &hex::encode(self.0.get_v().to_bytes()))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for EphemeralPublicKey {}
|
||||
|
||||
impl From<&EphemeralPublicKey> for [u8; 32] {
|
||||
fn from(nk: &EphemeralPublicKey) -> [u8; 32] {
|
||||
nk.0.to_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<[u8; 32]> for EphemeralPublicKey {
|
||||
fn eq(&self, other: &[u8; 32]) -> bool {
|
||||
<[u8; 32]>::from(self) == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<[u8; 32]> for EphemeralPublicKey {
|
||||
type Error = &'static str;
|
||||
|
||||
fn try_from(bytes: [u8; 32]) -> Result<Self, Self::Error> {
|
||||
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 EphemeralPublicKey {
|
||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
writer.write_all(&<[u8; 32]>::from(self)[..])?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl ZcashDeserialize for EphemeralPublicKey {
|
||||
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
|
||||
Self::try_from(reader.read_32_bytes()?).map_err(|e| SerializationError::Parse(e))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
use std::convert::TryFrom;
|
||||
|
||||
use proptest::{arbitrary::any, array, prelude::*};
|
||||
|
||||
use crate::keys::sapling;
|
||||
|
||||
impl Arbitrary for sapling::EphemeralPublicKey {
|
||||
type Parameters = ();
|
||||
|
||||
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
|
||||
array::uniform32(any::<u8>())
|
||||
.prop_filter_map("Valid jubjub::AffinePoint", |b| Self::try_from(b).ok())
|
||||
.boxed()
|
||||
}
|
||||
|
||||
type Strategy = BoxedStrategy<Self>;
|
||||
}
|
||||
|
|
@ -9,7 +9,7 @@ use std::{
|
|||
};
|
||||
|
||||
use crate::{
|
||||
commitments, notes,
|
||||
commitments, keys, notes,
|
||||
proofs::ZkSnarkProof,
|
||||
serialization::{
|
||||
ReadZcashExt, SerializationError, WriteZcashExt, ZcashDeserialize, ZcashSerialize,
|
||||
|
|
@ -352,7 +352,7 @@ impl ZcashSerialize for Output {
|
|||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
self.cv.zcash_serialize(&mut writer)?;
|
||||
writer.write_all(&self.cm_u.to_bytes())?;
|
||||
writer.write_all(&self.ephemeral_key.to_bytes())?;
|
||||
self.ephemeral_key.zcash_serialize(&mut writer)?;
|
||||
self.enc_ciphertext.zcash_serialize(&mut writer)?;
|
||||
self.out_ciphertext.zcash_serialize(&mut writer)?;
|
||||
self.zkproof.zcash_serialize(&mut writer)?;
|
||||
|
|
@ -365,7 +365,7 @@ impl ZcashDeserialize for Output {
|
|||
Ok(Output {
|
||||
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(),
|
||||
ephemeral_key: keys::sapling::EphemeralPublicKey::zcash_deserialize(&mut reader)?,
|
||||
enc_ciphertext: notes::sapling::EncryptedCiphertext::zcash_deserialize(&mut reader)?,
|
||||
out_ciphertext: notes::sapling::OutCiphertext::zcash_deserialize(&mut reader)?,
|
||||
zkproof: Groth16Proof::zcash_deserialize(&mut reader)?,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
commitments, notes,
|
||||
commitments, keys, notes,
|
||||
proofs::Groth16Proof,
|
||||
redjubjub::{self, Binding, SpendAuth},
|
||||
serde_helpers,
|
||||
|
|
@ -37,8 +37,7 @@ pub struct Output {
|
|||
#[serde(with = "serde_helpers::Fq")]
|
||||
pub cm_u: jubjub::Fq,
|
||||
/// An encoding of an ephemeral Jubjub public key.
|
||||
#[serde(with = "serde_helpers::AffinePoint")]
|
||||
pub ephemeral_key: jubjub::AffinePoint,
|
||||
pub ephemeral_key: keys::sapling::EphemeralPublicKey,
|
||||
/// A ciphertext component for the encrypted output note.
|
||||
pub enc_ciphertext: notes::sapling::EncryptedCiphertext,
|
||||
/// A ciphertext component for the encrypted output note.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
commitments,
|
||||
commitments, keys,
|
||||
notes::{sapling, sprout},
|
||||
proofs::{Groth16Proof, ZkSnarkProof},
|
||||
transaction::{
|
||||
|
|
@ -97,18 +97,16 @@ impl Arbitrary for Output {
|
|||
(
|
||||
any::<commitments::sapling::ValueCommitment>(),
|
||||
any::<commitments::sapling::NoteCommitment>(),
|
||||
array::uniform32(any::<u8>()).prop_filter("Valid jubjub::AffinePoint", |b| {
|
||||
jubjub::AffinePoint::from_bytes(*b).is_some().unwrap_u8() == 1
|
||||
}),
|
||||
any::<keys::sapling::EphemeralPublicKey>(),
|
||||
any::<sapling::EncryptedCiphertext>(),
|
||||
any::<sapling::OutCiphertext>(),
|
||||
any::<Groth16Proof>(),
|
||||
)
|
||||
.prop_map(
|
||||
|(cv, cm, ephemeral_key_bytes, enc_ciphertext, out_ciphertext, zkproof)| Self {
|
||||
|(cv, cm, ephemeral_key, enc_ciphertext, out_ciphertext, zkproof)| Self {
|
||||
cv,
|
||||
cm_u: cm.extract_u(),
|
||||
ephemeral_key: jubjub::AffinePoint::from_bytes(ephemeral_key_bytes).unwrap(),
|
||||
ephemeral_key,
|
||||
enc_ciphertext,
|
||||
out_ciphertext,
|
||||
zkproof,
|
||||
|
|
|
|||
Loading…
Reference in New Issue