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
|
//! [3.1]: https://zips.z.cash/protocol/protocol.pdf#addressesandkeys
|
||||||
#![allow(clippy::unit_arg)]
|
#![allow(clippy::unit_arg)]
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod arbitrary;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test_vectors;
|
mod test_vectors;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
@ -29,7 +31,8 @@ use proptest_derive::Arbitrary;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
redjubjub::{self, SpendAuth},
|
redjubjub::{self, SpendAuth},
|
||||||
serialization::{ReadZcashExt, SerializationError},
|
serde_helpers,
|
||||||
|
serialization::{ReadZcashExt, SerializationError, ZcashDeserialize, ZcashSerialize},
|
||||||
Network,
|
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::{
|
use crate::{
|
||||||
commitments, notes,
|
commitments, keys, notes,
|
||||||
proofs::ZkSnarkProof,
|
proofs::ZkSnarkProof,
|
||||||
serialization::{
|
serialization::{
|
||||||
ReadZcashExt, SerializationError, WriteZcashExt, ZcashDeserialize, ZcashSerialize,
|
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> {
|
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||||
self.cv.zcash_serialize(&mut writer)?;
|
self.cv.zcash_serialize(&mut writer)?;
|
||||||
writer.write_all(&self.cm_u.to_bytes())?;
|
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.enc_ciphertext.zcash_serialize(&mut writer)?;
|
||||||
self.out_ciphertext.zcash_serialize(&mut writer)?;
|
self.out_ciphertext.zcash_serialize(&mut writer)?;
|
||||||
self.zkproof.zcash_serialize(&mut writer)?;
|
self.zkproof.zcash_serialize(&mut writer)?;
|
||||||
|
|
@ -365,7 +365,7 @@ impl ZcashDeserialize for Output {
|
||||||
Ok(Output {
|
Ok(Output {
|
||||||
cv: commitments::sapling::ValueCommitment::zcash_deserialize(&mut reader)?,
|
cv: commitments::sapling::ValueCommitment::zcash_deserialize(&mut reader)?,
|
||||||
cm_u: jubjub::Fq::from_bytes(&reader.read_32_bytes()?).unwrap(),
|
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)?,
|
enc_ciphertext: notes::sapling::EncryptedCiphertext::zcash_deserialize(&mut reader)?,
|
||||||
out_ciphertext: notes::sapling::OutCiphertext::zcash_deserialize(&mut reader)?,
|
out_ciphertext: notes::sapling::OutCiphertext::zcash_deserialize(&mut reader)?,
|
||||||
zkproof: Groth16Proof::zcash_deserialize(&mut reader)?,
|
zkproof: Groth16Proof::zcash_deserialize(&mut reader)?,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
commitments, notes,
|
commitments, keys, notes,
|
||||||
proofs::Groth16Proof,
|
proofs::Groth16Proof,
|
||||||
redjubjub::{self, Binding, SpendAuth},
|
redjubjub::{self, Binding, SpendAuth},
|
||||||
serde_helpers,
|
serde_helpers,
|
||||||
|
|
@ -37,8 +37,7 @@ pub struct Output {
|
||||||
#[serde(with = "serde_helpers::Fq")]
|
#[serde(with = "serde_helpers::Fq")]
|
||||||
pub cm_u: jubjub::Fq,
|
pub cm_u: jubjub::Fq,
|
||||||
/// An encoding of an ephemeral Jubjub public key.
|
/// An encoding of an ephemeral Jubjub public key.
|
||||||
#[serde(with = "serde_helpers::AffinePoint")]
|
pub ephemeral_key: keys::sapling::EphemeralPublicKey,
|
||||||
pub ephemeral_key: jubjub::AffinePoint,
|
|
||||||
/// A ciphertext component for the encrypted output note.
|
/// A ciphertext component for the encrypted output note.
|
||||||
pub enc_ciphertext: notes::sapling::EncryptedCiphertext,
|
pub enc_ciphertext: notes::sapling::EncryptedCiphertext,
|
||||||
/// A ciphertext component for the encrypted output note.
|
/// A ciphertext component for the encrypted output note.
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
commitments,
|
commitments, keys,
|
||||||
notes::{sapling, sprout},
|
notes::{sapling, sprout},
|
||||||
proofs::{Groth16Proof, ZkSnarkProof},
|
proofs::{Groth16Proof, ZkSnarkProof},
|
||||||
transaction::{
|
transaction::{
|
||||||
|
|
@ -97,18 +97,16 @@ impl Arbitrary for Output {
|
||||||
(
|
(
|
||||||
any::<commitments::sapling::ValueCommitment>(),
|
any::<commitments::sapling::ValueCommitment>(),
|
||||||
any::<commitments::sapling::NoteCommitment>(),
|
any::<commitments::sapling::NoteCommitment>(),
|
||||||
array::uniform32(any::<u8>()).prop_filter("Valid jubjub::AffinePoint", |b| {
|
any::<keys::sapling::EphemeralPublicKey>(),
|
||||||
jubjub::AffinePoint::from_bytes(*b).is_some().unwrap_u8() == 1
|
|
||||||
}),
|
|
||||||
any::<sapling::EncryptedCiphertext>(),
|
any::<sapling::EncryptedCiphertext>(),
|
||||||
any::<sapling::OutCiphertext>(),
|
any::<sapling::OutCiphertext>(),
|
||||||
any::<Groth16Proof>(),
|
any::<Groth16Proof>(),
|
||||||
)
|
)
|
||||||
.prop_map(
|
.prop_map(
|
||||||
|(cv, cm, ephemeral_key_bytes, enc_ciphertext, out_ciphertext, zkproof)| Self {
|
|(cv, cm, ephemeral_key, enc_ciphertext, out_ciphertext, zkproof)| Self {
|
||||||
cv,
|
cv,
|
||||||
cm_u: cm.extract_u(),
|
cm_u: cm.extract_u(),
|
||||||
ephemeral_key: jubjub::AffinePoint::from_bytes(ephemeral_key_bytes).unwrap(),
|
ephemeral_key,
|
||||||
enc_ciphertext,
|
enc_ciphertext,
|
||||||
out_ciphertext,
|
out_ciphertext,
|
||||||
zkproof,
|
zkproof,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue