Store OutputDescription `ephemeral_key` as bytes
This removes an unnecessary `to_bytes` during trial decryption of notes, and more closely matches the protocol spec. We retain the consensus rule canonicity check on epk due to `SaplingVerificationContext::check_output` taking a `jubjub::ExtendedPoint`, forcing `zcashd` to parse the bytes.
This commit is contained in:
parent
99d877e22d
commit
83c6a2d1ca
|
@ -1,7 +1,6 @@
|
||||||
//! Generated code for handling light client protobuf structs.
|
//! Generated code for handling light client protobuf structs.
|
||||||
|
|
||||||
use ff::PrimeField;
|
use ff::PrimeField;
|
||||||
use group::GroupEncoding;
|
|
||||||
use std::convert::{TryFrom, TryInto};
|
use std::convert::{TryFrom, TryInto};
|
||||||
|
|
||||||
use zcash_primitives::{
|
use zcash_primitives::{
|
||||||
|
@ -103,13 +102,8 @@ impl compact_formats::CompactOutput {
|
||||||
/// A convenience method that parses [`CompactOutput.epk`].
|
/// A convenience method that parses [`CompactOutput.epk`].
|
||||||
///
|
///
|
||||||
/// [`CompactOutput.epk`]: #structfield.epk
|
/// [`CompactOutput.epk`]: #structfield.epk
|
||||||
pub fn epk(&self) -> Result<jubjub::ExtendedPoint, ()> {
|
pub fn ephemeral_key(&self) -> Result<[u8; 32], ()> {
|
||||||
let p = jubjub::ExtendedPoint::from_bytes(&self.epk[..].try_into().map_err(|_| ())?);
|
self.epk[..].try_into().map_err(|_| ())
|
||||||
if p.is_some().into() {
|
|
||||||
Ok(p.unwrap())
|
|
||||||
} else {
|
|
||||||
Err(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +111,7 @@ impl<A: sapling::Authorization> From<OutputDescription<A>> for compact_formats::
|
||||||
fn from(out: OutputDescription<A>) -> compact_formats::CompactOutput {
|
fn from(out: OutputDescription<A>) -> compact_formats::CompactOutput {
|
||||||
let mut result = compact_formats::CompactOutput::new();
|
let mut result = compact_formats::CompactOutput::new();
|
||||||
result.set_cmu(out.cmu.to_repr().to_vec());
|
result.set_cmu(out.cmu.to_repr().to_vec());
|
||||||
result.set_epk(out.ephemeral_key.to_bytes().to_vec());
|
result.set_epk(out.ephemeral_key.to_vec());
|
||||||
result.set_ciphertext(out.enc_ciphertext[..COMPACT_NOTE_SIZE].to_vec());
|
result.set_ciphertext(out.enc_ciphertext[..COMPACT_NOTE_SIZE].to_vec());
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
@ -129,7 +123,7 @@ impl TryFrom<compact_formats::CompactOutput> for CompactOutputDescription {
|
||||||
fn try_from(value: compact_formats::CompactOutput) -> Result<Self, Self::Error> {
|
fn try_from(value: compact_formats::CompactOutput) -> Result<Self, Self::Error> {
|
||||||
Ok(CompactOutputDescription {
|
Ok(CompactOutputDescription {
|
||||||
cmu: value.cmu()?,
|
cmu: value.cmu()?,
|
||||||
epk: value.epk()?,
|
ephemeral_key: value.ephemeral_key()?,
|
||||||
enc_ciphertext: value.ciphertext,
|
enc_ciphertext: value.ciphertext,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ pub struct WalletShieldedSpend {
|
||||||
pub struct WalletShieldedOutput<N> {
|
pub struct WalletShieldedOutput<N> {
|
||||||
pub index: usize,
|
pub index: usize,
|
||||||
pub cmu: bls12_381::Scalar,
|
pub cmu: bls12_381::Scalar,
|
||||||
pub epk: jubjub::ExtendedPoint,
|
pub ephemeral_key: [u8; 32],
|
||||||
pub account: AccountId,
|
pub account: AccountId,
|
||||||
pub note: Note,
|
pub note: Note,
|
||||||
pub to: PaymentAddress,
|
pub to: PaymentAddress,
|
||||||
|
|
|
@ -76,7 +76,7 @@ fn scan_output<P: consensus::Parameters, K: ScanningKey>(
|
||||||
return Some(WalletShieldedOutput {
|
return Some(WalletShieldedOutput {
|
||||||
index,
|
index,
|
||||||
cmu: output.cmu,
|
cmu: output.cmu,
|
||||||
epk: output.epk,
|
ephemeral_key: output.ephemeral_key,
|
||||||
account: **account,
|
account: **account,
|
||||||
note,
|
note,
|
||||||
to,
|
to,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use criterion::{criterion_group, criterion_main, Criterion};
|
use criterion::{criterion_group, criterion_main, Criterion};
|
||||||
use ff::Field;
|
use ff::Field;
|
||||||
|
use group::GroupEncoding;
|
||||||
use rand_core::OsRng;
|
use rand_core::OsRng;
|
||||||
use zcash_primitives::{
|
use zcash_primitives::{
|
||||||
consensus::{NetworkUpgrade::Canopy, Parameters, TestNetwork, TEST_NETWORK},
|
consensus::{NetworkUpgrade::Canopy, Parameters, TestNetwork, TEST_NETWORK},
|
||||||
|
@ -49,7 +50,7 @@ fn bench_note_decryption(c: &mut Criterion) {
|
||||||
|
|
||||||
let ne =
|
let ne =
|
||||||
sapling_note_encryption::<_, TestNetwork>(None, note, pa, MemoBytes::empty(), &mut rng);
|
sapling_note_encryption::<_, TestNetwork>(None, note, pa, MemoBytes::empty(), &mut rng);
|
||||||
let ephemeral_key = *ne.epk();
|
let ephemeral_key = ne.epk().to_bytes();
|
||||||
let enc_ciphertext = ne.encrypt_note_plaintext();
|
let enc_ciphertext = ne.encrypt_note_plaintext();
|
||||||
let out_ciphertext = ne.encrypt_outgoing_plaintext(&cv, &cmu, &mut rng);
|
let out_ciphertext = ne.encrypt_outgoing_plaintext(&cv, &cmu, &mut rng);
|
||||||
|
|
||||||
|
|
|
@ -436,8 +436,8 @@ mod tests {
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
|
||||||
use zcash_note_encryption::{
|
use zcash_note_encryption::{
|
||||||
NoteEncryption, OutgoingCipherKey, ENC_CIPHERTEXT_SIZE, NOTE_PLAINTEXT_SIZE,
|
EphemeralKeyBytes, NoteEncryption, OutgoingCipherKey, ENC_CIPHERTEXT_SIZE,
|
||||||
OUT_CIPHERTEXT_SIZE, OUT_PLAINTEXT_SIZE,
|
NOTE_PLAINTEXT_SIZE, OUT_CIPHERTEXT_SIZE, OUT_PLAINTEXT_SIZE,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
@ -538,7 +538,7 @@ mod tests {
|
||||||
let output = OutputDescription {
|
let output = OutputDescription {
|
||||||
cv,
|
cv,
|
||||||
cmu,
|
cmu,
|
||||||
ephemeral_key: epk,
|
ephemeral_key: epk.to_bytes(),
|
||||||
enc_ciphertext: ne.encrypt_note_plaintext(),
|
enc_ciphertext: ne.encrypt_note_plaintext(),
|
||||||
out_ciphertext: ne.encrypt_outgoing_plaintext(&cv, &cmu, &mut rng),
|
out_ciphertext: ne.encrypt_outgoing_plaintext(&cv, &cmu, &mut rng),
|
||||||
zkproof: [0u8; GROTH_PROOF_SIZE],
|
zkproof: [0u8; GROTH_PROOF_SIZE],
|
||||||
|
@ -551,12 +551,17 @@ mod tests {
|
||||||
ovk: &OutgoingViewingKey,
|
ovk: &OutgoingViewingKey,
|
||||||
cv: &jubjub::ExtendedPoint,
|
cv: &jubjub::ExtendedPoint,
|
||||||
cmu: &bls12_381::Scalar,
|
cmu: &bls12_381::Scalar,
|
||||||
epk: &jubjub::ExtendedPoint,
|
ephemeral_key: &[u8; 32],
|
||||||
enc_ciphertext: &mut [u8; ENC_CIPHERTEXT_SIZE],
|
enc_ciphertext: &mut [u8; ENC_CIPHERTEXT_SIZE],
|
||||||
out_ciphertext: &[u8; OUT_CIPHERTEXT_SIZE],
|
out_ciphertext: &[u8; OUT_CIPHERTEXT_SIZE],
|
||||||
modify_plaintext: impl Fn(&mut [u8; NOTE_PLAINTEXT_SIZE]),
|
modify_plaintext: impl Fn(&mut [u8; NOTE_PLAINTEXT_SIZE]),
|
||||||
) {
|
) {
|
||||||
let ock = prf_ock(&ovk, &cv, &cmu.to_repr(), &epk_bytes(epk));
|
let ock = prf_ock(
|
||||||
|
&ovk,
|
||||||
|
&cv,
|
||||||
|
&cmu.to_repr(),
|
||||||
|
&EphemeralKeyBytes(*ephemeral_key),
|
||||||
|
);
|
||||||
|
|
||||||
let mut op = [0; OUT_CIPHERTEXT_SIZE];
|
let mut op = [0; OUT_CIPHERTEXT_SIZE];
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -571,7 +576,7 @@ mod tests {
|
||||||
let esk = jubjub::Fr::from_repr(op[32..OUT_PLAINTEXT_SIZE].try_into().unwrap()).unwrap();
|
let esk = jubjub::Fr::from_repr(op[32..OUT_PLAINTEXT_SIZE].try_into().unwrap()).unwrap();
|
||||||
|
|
||||||
let shared_secret = sapling_ka_agree(&esk, &pk_d.into());
|
let shared_secret = sapling_ka_agree(&esk, &pk_d.into());
|
||||||
let key = kdf_sapling(shared_secret, &epk_bytes(&epk));
|
let key = kdf_sapling(shared_secret, &EphemeralKeyBytes(*ephemeral_key));
|
||||||
|
|
||||||
let mut plaintext = {
|
let mut plaintext = {
|
||||||
let mut buf = [0; ENC_CIPHERTEXT_SIZE];
|
let mut buf = [0; ENC_CIPHERTEXT_SIZE];
|
||||||
|
@ -664,7 +669,7 @@ mod tests {
|
||||||
for &height in heights.iter() {
|
for &height in heights.iter() {
|
||||||
let (_, _, ivk, mut output) = random_enc_ciphertext(height, &mut rng);
|
let (_, _, ivk, mut output) = random_enc_ciphertext(height, &mut rng);
|
||||||
|
|
||||||
output.ephemeral_key = jubjub::ExtendedPoint::random(&mut rng);
|
output.ephemeral_key = jubjub::ExtendedPoint::random(&mut rng).to_bytes();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
try_sapling_note_decryption(&TEST_NETWORK, height, &ivk, &output,),
|
try_sapling_note_decryption(&TEST_NETWORK, height, &ivk, &output,),
|
||||||
|
@ -829,7 +834,7 @@ mod tests {
|
||||||
|
|
||||||
for &height in heights.iter() {
|
for &height in heights.iter() {
|
||||||
let (_, _, ivk, mut output) = random_enc_ciphertext(height, &mut rng);
|
let (_, _, ivk, mut output) = random_enc_ciphertext(height, &mut rng);
|
||||||
output.ephemeral_key = jubjub::ExtendedPoint::random(&mut rng);
|
output.ephemeral_key = jubjub::ExtendedPoint::random(&mut rng).to_bytes();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
try_sapling_compact_note_decryption(
|
try_sapling_compact_note_decryption(
|
||||||
|
@ -1061,7 +1066,7 @@ mod tests {
|
||||||
|
|
||||||
for &height in heights.iter() {
|
for &height in heights.iter() {
|
||||||
let (ovk, ock, _, mut output) = random_enc_ciphertext(height, &mut rng);
|
let (ovk, ock, _, mut output) = random_enc_ciphertext(height, &mut rng);
|
||||||
output.ephemeral_key = jubjub::ExtendedPoint::random(&mut rng);
|
output.ephemeral_key = jubjub::ExtendedPoint::random(&mut rng).to_bytes();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
try_sapling_output_recovery(&TEST_NETWORK, height, &ovk, &output,),
|
try_sapling_output_recovery(&TEST_NETWORK, height, &ovk, &output,),
|
||||||
|
@ -1275,7 +1280,7 @@ mod tests {
|
||||||
let cv = read_point!(tv.cv);
|
let cv = read_point!(tv.cv);
|
||||||
let cmu = read_bls12_381_scalar!(tv.cmu);
|
let cmu = read_bls12_381_scalar!(tv.cmu);
|
||||||
let esk = read_jubjub_scalar!(tv.esk);
|
let esk = read_jubjub_scalar!(tv.esk);
|
||||||
let epk = read_point!(tv.epk);
|
let ephemeral_key = EphemeralKeyBytes(tv.epk);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Test the individual components
|
// Test the individual components
|
||||||
|
@ -1284,11 +1289,11 @@ mod tests {
|
||||||
let shared_secret = sapling_ka_agree(&esk, &pk_d.into());
|
let shared_secret = sapling_ka_agree(&esk, &pk_d.into());
|
||||||
assert_eq!(shared_secret.to_bytes(), tv.shared_secret);
|
assert_eq!(shared_secret.to_bytes(), tv.shared_secret);
|
||||||
|
|
||||||
let k_enc = kdf_sapling(shared_secret, &epk_bytes(&epk));
|
let k_enc = kdf_sapling(shared_secret, &ephemeral_key);
|
||||||
assert_eq!(k_enc.as_bytes(), tv.k_enc);
|
assert_eq!(k_enc.as_bytes(), tv.k_enc);
|
||||||
|
|
||||||
let ovk = OutgoingViewingKey(tv.ovk);
|
let ovk = OutgoingViewingKey(tv.ovk);
|
||||||
let ock = prf_ock(&ovk, &cv, &cmu.to_repr(), &epk_bytes(&epk));
|
let ock = prf_ock(&ovk, &cv, &cmu.to_repr(), &ephemeral_key);
|
||||||
assert_eq!(ock.as_ref(), tv.ock);
|
assert_eq!(ock.as_ref(), tv.ock);
|
||||||
|
|
||||||
let to = PaymentAddress::from_parts(Diversifier(tv.default_d), pk_d).unwrap();
|
let to = PaymentAddress::from_parts(Diversifier(tv.default_d), pk_d).unwrap();
|
||||||
|
@ -1298,7 +1303,7 @@ mod tests {
|
||||||
let output = OutputDescription {
|
let output = OutputDescription {
|
||||||
cv,
|
cv,
|
||||||
cmu,
|
cmu,
|
||||||
ephemeral_key: epk,
|
ephemeral_key: ephemeral_key.0,
|
||||||
enc_ciphertext: tv.c_enc,
|
enc_ciphertext: tv.c_enc,
|
||||||
out_ciphertext: tv.c_out,
|
out_ciphertext: tv.c_out,
|
||||||
zkproof: [0u8; GROTH_PROOF_SIZE],
|
zkproof: [0u8; GROTH_PROOF_SIZE],
|
||||||
|
|
|
@ -213,7 +213,7 @@ impl SpendDescriptionV5 {
|
||||||
pub struct OutputDescription<Proof> {
|
pub struct OutputDescription<Proof> {
|
||||||
pub cv: jubjub::ExtendedPoint,
|
pub cv: jubjub::ExtendedPoint,
|
||||||
pub cmu: bls12_381::Scalar,
|
pub cmu: bls12_381::Scalar,
|
||||||
pub ephemeral_key: jubjub::ExtendedPoint,
|
pub ephemeral_key: [u8; 32],
|
||||||
pub enc_ciphertext: [u8; 580],
|
pub enc_ciphertext: [u8; 580],
|
||||||
pub out_ciphertext: [u8; 80],
|
pub out_ciphertext: [u8; 80],
|
||||||
pub zkproof: Proof,
|
pub zkproof: Proof,
|
||||||
|
@ -221,7 +221,7 @@ pub struct OutputDescription<Proof> {
|
||||||
|
|
||||||
impl<P: consensus::Parameters, A> ShieldedOutput<SaplingDomain<P>> for OutputDescription<A> {
|
impl<P: consensus::Parameters, A> ShieldedOutput<SaplingDomain<P>> for OutputDescription<A> {
|
||||||
fn ephemeral_key(&self) -> EphemeralKeyBytes {
|
fn ephemeral_key(&self) -> EphemeralKeyBytes {
|
||||||
EphemeralKeyBytes(self.ephemeral_key.to_bytes())
|
EphemeralKeyBytes(self.ephemeral_key)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmstar_bytes(&self) -> [u8; 32] {
|
fn cmstar_bytes(&self) -> [u8; 32] {
|
||||||
|
@ -255,9 +255,10 @@ impl OutputDescription<GrothProofBytes> {
|
||||||
let cmu = read_base(&mut reader, "cmu")?;
|
let cmu = read_base(&mut reader, "cmu")?;
|
||||||
|
|
||||||
// Consensus rules (§4.5):
|
// Consensus rules (§4.5):
|
||||||
// - Canonical encoding is enforced here.
|
// - Canonical encoding is enforced in librustzcash_sapling_check_output by zcashd
|
||||||
// - "Not small order" is enforced in SaplingVerificationContext::check_output()
|
// - "Not small order" is enforced in SaplingVerificationContext::check_output()
|
||||||
let ephemeral_key = read_point(&mut reader, "ephemeral key")?;
|
let mut ephemeral_key = [0u8; 32];
|
||||||
|
reader.read_exact(&mut ephemeral_key)?;
|
||||||
|
|
||||||
let mut enc_ciphertext = [0u8; 580];
|
let mut enc_ciphertext = [0u8; 580];
|
||||||
let mut out_ciphertext = [0u8; 80];
|
let mut out_ciphertext = [0u8; 80];
|
||||||
|
@ -279,7 +280,7 @@ impl OutputDescription<GrothProofBytes> {
|
||||||
pub fn write_v4<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
pub fn write_v4<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
||||||
writer.write_all(&self.cv.to_bytes())?;
|
writer.write_all(&self.cv.to_bytes())?;
|
||||||
writer.write_all(self.cmu.to_repr().as_ref())?;
|
writer.write_all(self.cmu.to_repr().as_ref())?;
|
||||||
writer.write_all(&self.ephemeral_key.to_bytes())?;
|
writer.write_all(&self.ephemeral_key)?;
|
||||||
writer.write_all(&self.enc_ciphertext)?;
|
writer.write_all(&self.enc_ciphertext)?;
|
||||||
writer.write_all(&self.out_ciphertext)?;
|
writer.write_all(&self.out_ciphertext)?;
|
||||||
writer.write_all(&self.zkproof)
|
writer.write_all(&self.zkproof)
|
||||||
|
@ -288,7 +289,7 @@ impl OutputDescription<GrothProofBytes> {
|
||||||
pub fn write_v5_without_proof<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
pub fn write_v5_without_proof<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
||||||
writer.write_all(&self.cv.to_bytes())?;
|
writer.write_all(&self.cv.to_bytes())?;
|
||||||
writer.write_all(self.cmu.to_repr().as_ref())?;
|
writer.write_all(self.cmu.to_repr().as_ref())?;
|
||||||
writer.write_all(&self.ephemeral_key.to_bytes())?;
|
writer.write_all(&self.ephemeral_key)?;
|
||||||
writer.write_all(&self.enc_ciphertext)?;
|
writer.write_all(&self.enc_ciphertext)?;
|
||||||
writer.write_all(&self.out_ciphertext)
|
writer.write_all(&self.out_ciphertext)
|
||||||
}
|
}
|
||||||
|
@ -298,7 +299,7 @@ impl OutputDescription<GrothProofBytes> {
|
||||||
pub struct OutputDescriptionV5 {
|
pub struct OutputDescriptionV5 {
|
||||||
pub cv: jubjub::ExtendedPoint,
|
pub cv: jubjub::ExtendedPoint,
|
||||||
pub cmu: bls12_381::Scalar,
|
pub cmu: bls12_381::Scalar,
|
||||||
pub ephemeral_key: jubjub::ExtendedPoint,
|
pub ephemeral_key: [u8; 32],
|
||||||
pub enc_ciphertext: [u8; 580],
|
pub enc_ciphertext: [u8; 580],
|
||||||
pub out_ciphertext: [u8; 80],
|
pub out_ciphertext: [u8; 80],
|
||||||
}
|
}
|
||||||
|
@ -307,7 +308,12 @@ impl OutputDescriptionV5 {
|
||||||
pub fn read<R: Read>(mut reader: &mut R) -> io::Result<Self> {
|
pub fn read<R: Read>(mut reader: &mut R) -> io::Result<Self> {
|
||||||
let cv = read_point(&mut reader, "cv")?;
|
let cv = read_point(&mut reader, "cv")?;
|
||||||
let cmu = read_base(&mut reader, "cmu")?;
|
let cmu = read_base(&mut reader, "cmu")?;
|
||||||
let ephemeral_key = read_point(&mut reader, "ephemeral key")?;
|
|
||||||
|
// Consensus rules (§4.5):
|
||||||
|
// - Canonical encoding is enforced in librustzcash_sapling_check_output by zcashd
|
||||||
|
// - "Not small order" is enforced in SaplingVerificationContext::check_output()
|
||||||
|
let mut ephemeral_key = [0u8; 32];
|
||||||
|
reader.read_exact(&mut ephemeral_key)?;
|
||||||
|
|
||||||
let mut enc_ciphertext = [0u8; 580];
|
let mut enc_ciphertext = [0u8; 580];
|
||||||
let mut out_ciphertext = [0u8; 80];
|
let mut out_ciphertext = [0u8; 80];
|
||||||
|
@ -339,7 +345,7 @@ impl OutputDescriptionV5 {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CompactOutputDescription {
|
pub struct CompactOutputDescription {
|
||||||
pub epk: jubjub::ExtendedPoint,
|
pub ephemeral_key: [u8; 32],
|
||||||
pub cmu: bls12_381::Scalar,
|
pub cmu: bls12_381::Scalar,
|
||||||
pub enc_ciphertext: Vec<u8>,
|
pub enc_ciphertext: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
@ -347,7 +353,7 @@ pub struct CompactOutputDescription {
|
||||||
impl<A> From<OutputDescription<A>> for CompactOutputDescription {
|
impl<A> From<OutputDescription<A>> for CompactOutputDescription {
|
||||||
fn from(out: OutputDescription<A>) -> CompactOutputDescription {
|
fn from(out: OutputDescription<A>) -> CompactOutputDescription {
|
||||||
CompactOutputDescription {
|
CompactOutputDescription {
|
||||||
epk: out.ephemeral_key,
|
ephemeral_key: out.ephemeral_key,
|
||||||
cmu: out.cmu,
|
cmu: out.cmu,
|
||||||
enc_ciphertext: out.enc_ciphertext[..COMPACT_NOTE_SIZE].to_vec(),
|
enc_ciphertext: out.enc_ciphertext[..COMPACT_NOTE_SIZE].to_vec(),
|
||||||
}
|
}
|
||||||
|
@ -356,7 +362,7 @@ impl<A> From<OutputDescription<A>> for CompactOutputDescription {
|
||||||
|
|
||||||
impl<P: consensus::Parameters> ShieldedOutput<SaplingDomain<P>> for CompactOutputDescription {
|
impl<P: consensus::Parameters> ShieldedOutput<SaplingDomain<P>> for CompactOutputDescription {
|
||||||
fn ephemeral_key(&self) -> EphemeralKeyBytes {
|
fn ephemeral_key(&self) -> EphemeralKeyBytes {
|
||||||
EphemeralKeyBytes(self.epk.to_bytes())
|
EphemeralKeyBytes(self.ephemeral_key)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmstar_bytes(&self) -> [u8; 32] {
|
fn cmstar_bytes(&self) -> [u8; 32] {
|
||||||
|
@ -371,7 +377,7 @@ impl<P: consensus::Parameters> ShieldedOutput<SaplingDomain<P>> for CompactOutpu
|
||||||
#[cfg(any(test, feature = "test-dependencies"))]
|
#[cfg(any(test, feature = "test-dependencies"))]
|
||||||
pub mod testing {
|
pub mod testing {
|
||||||
use ff::Field;
|
use ff::Field;
|
||||||
use group::Group;
|
use group::{Group, GroupEncoding};
|
||||||
use proptest::collection::vec;
|
use proptest::collection::vec;
|
||||||
use proptest::prelude::*;
|
use proptest::prelude::*;
|
||||||
use rand::{rngs::StdRng, SeedableRng};
|
use rand::{rngs::StdRng, SeedableRng};
|
||||||
|
@ -438,7 +444,7 @@ pub mod testing {
|
||||||
.prop_map(|v| bls12_381::Scalar::from_bytes_wide(&v)),
|
.prop_map(|v| bls12_381::Scalar::from_bytes_wide(&v)),
|
||||||
enc_ciphertext in vec(any::<u8>(), 580)
|
enc_ciphertext in vec(any::<u8>(), 580)
|
||||||
.prop_map(|v| <[u8;580]>::try_from(v.as_slice()).unwrap()),
|
.prop_map(|v| <[u8;580]>::try_from(v.as_slice()).unwrap()),
|
||||||
ephemeral_key in arb_extended_point(),
|
epk in arb_extended_point(),
|
||||||
out_ciphertext in vec(any::<u8>(), 80)
|
out_ciphertext in vec(any::<u8>(), 80)
|
||||||
.prop_map(|v| <[u8;80]>::try_from(v.as_slice()).unwrap()),
|
.prop_map(|v| <[u8;80]>::try_from(v.as_slice()).unwrap()),
|
||||||
zkproof in vec(any::<u8>(), GROTH_PROOF_SIZE)
|
zkproof in vec(any::<u8>(), GROTH_PROOF_SIZE)
|
||||||
|
@ -447,7 +453,7 @@ pub mod testing {
|
||||||
OutputDescription {
|
OutputDescription {
|
||||||
cv,
|
cv,
|
||||||
cmu,
|
cmu,
|
||||||
ephemeral_key,
|
ephemeral_key: epk.to_bytes(),
|
||||||
enc_ciphertext,
|
enc_ciphertext,
|
||||||
out_ciphertext,
|
out_ciphertext,
|
||||||
zkproof,
|
zkproof,
|
||||||
|
|
|
@ -4,6 +4,7 @@ use std::fmt;
|
||||||
use std::sync::mpsc::Sender;
|
use std::sync::mpsc::Sender;
|
||||||
|
|
||||||
use ff::Field;
|
use ff::Field;
|
||||||
|
use group::GroupEncoding;
|
||||||
use rand::{seq::SliceRandom, RngCore};
|
use rand::{seq::SliceRandom, RngCore};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -136,12 +137,12 @@ impl SaplingOutput {
|
||||||
let enc_ciphertext = encryptor.encrypt_note_plaintext();
|
let enc_ciphertext = encryptor.encrypt_note_plaintext();
|
||||||
let out_ciphertext = encryptor.encrypt_outgoing_plaintext(&cv, &cmu, rng);
|
let out_ciphertext = encryptor.encrypt_outgoing_plaintext(&cv, &cmu, rng);
|
||||||
|
|
||||||
let ephemeral_key = *encryptor.epk();
|
let epk = *encryptor.epk();
|
||||||
|
|
||||||
OutputDescription {
|
OutputDescription {
|
||||||
cv,
|
cv,
|
||||||
cmu,
|
cmu,
|
||||||
ephemeral_key,
|
ephemeral_key: epk.to_bytes(),
|
||||||
enc_ciphertext,
|
enc_ciphertext,
|
||||||
out_ciphertext,
|
out_ciphertext,
|
||||||
zkproof,
|
zkproof,
|
||||||
|
@ -463,7 +464,7 @@ impl<P: consensus::Parameters> SaplingBuilder<P> {
|
||||||
OutputDescription {
|
OutputDescription {
|
||||||
cv,
|
cv,
|
||||||
cmu,
|
cmu,
|
||||||
ephemeral_key: epk.into(),
|
ephemeral_key: epk.to_bytes(),
|
||||||
enc_ciphertext,
|
enc_ciphertext,
|
||||||
out_ciphertext,
|
out_ciphertext,
|
||||||
zkproof,
|
zkproof,
|
||||||
|
|
|
@ -173,7 +173,7 @@ pub(crate) fn hash_sapling_outputs<A>(shielded_outputs: &[OutputDescription<A>])
|
||||||
let mut nh = hasher(ZCASH_SAPLING_OUTPUTS_NONCOMPACT_HASH_PERSONALIZATION);
|
let mut nh = hasher(ZCASH_SAPLING_OUTPUTS_NONCOMPACT_HASH_PERSONALIZATION);
|
||||||
for s_out in shielded_outputs {
|
for s_out in shielded_outputs {
|
||||||
ch.write_all(&s_out.cmu.to_repr().as_ref()).unwrap();
|
ch.write_all(&s_out.cmu.to_repr().as_ref()).unwrap();
|
||||||
ch.write_all(&s_out.ephemeral_key.to_bytes()).unwrap();
|
ch.write_all(&s_out.ephemeral_key).unwrap();
|
||||||
ch.write_all(&s_out.enc_ciphertext[..52]).unwrap();
|
ch.write_all(&s_out.enc_ciphertext[..52]).unwrap();
|
||||||
|
|
||||||
mh.write_all(&s_out.enc_ciphertext[52..564]).unwrap();
|
mh.write_all(&s_out.enc_ciphertext[52..564]).unwrap();
|
||||||
|
|
Loading…
Reference in New Issue