Merge pull request #469 from zcash/zcash_note_encryption-api-cleanups
`zcash_note_encryption` API cleanups
This commit is contained in:
commit
905c6e2dd0
|
@ -20,7 +20,7 @@ codegen-units = 1
|
|||
|
||||
[patch.crates-io]
|
||||
# In development.
|
||||
orchard = { git = "https://github.com/zcash/orchard.git", rev = "8c018eff7e795b16fc68aed22d0fd4eebe2710ec" }
|
||||
orchard = { git = "https://github.com/zcash/orchard.git", rev = "4b0b32275fe941b28cdfe632d2748453e6c32fbb" }
|
||||
incrementalmerkletree = { git = "https://github.com/zcash/incrementalmerkletree.git", rev = "b7bd6246122a6e9ace8edb51553fbf5228906cbb" }
|
||||
zcash_encoding = { path = "components/zcash_encoding" }
|
||||
zcash_note_encryption = { path = "components/zcash_note_encryption" }
|
||||
|
|
|
@ -28,6 +28,7 @@ jubjub = "0.8"
|
|||
[features]
|
||||
default = ["std"]
|
||||
alloc = []
|
||||
pre-zip-212 = []
|
||||
std = ["alloc", "blake2b_simd/std"]
|
||||
|
||||
[lib]
|
||||
|
|
|
@ -5,14 +5,14 @@ use core::iter;
|
|||
|
||||
use crate::{
|
||||
try_compact_note_decryption_inner, try_note_decryption_inner, BatchDomain, EphemeralKeyBytes,
|
||||
ShieldedOutput,
|
||||
ShieldedOutput, COMPACT_NOTE_SIZE, ENC_CIPHERTEXT_SIZE,
|
||||
};
|
||||
|
||||
/// Trial decryption of a batch of notes with a set of recipients.
|
||||
///
|
||||
/// This is the batched version of [`crate::try_note_decryption`].
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub fn try_note_decryption<D: BatchDomain, Output: ShieldedOutput<D>>(
|
||||
pub fn try_note_decryption<D: BatchDomain, Output: ShieldedOutput<D, ENC_CIPHERTEXT_SIZE>>(
|
||||
ivks: &[D::IncomingViewingKey],
|
||||
outputs: &[(D, Output)],
|
||||
) -> Vec<Option<(D::Note, D::Recipient, D::Memo)>> {
|
||||
|
@ -22,14 +22,14 @@ pub fn try_note_decryption<D: BatchDomain, Output: ShieldedOutput<D>>(
|
|||
/// Trial decryption of a batch of notes for light clients with a set of recipients.
|
||||
///
|
||||
/// This is the batched version of [`crate::try_compact_note_decryption`].
|
||||
pub fn try_compact_note_decryption<D: BatchDomain, Output: ShieldedOutput<D>>(
|
||||
pub fn try_compact_note_decryption<D: BatchDomain, Output: ShieldedOutput<D, COMPACT_NOTE_SIZE>>(
|
||||
ivks: &[D::IncomingViewingKey],
|
||||
outputs: &[(D, Output)],
|
||||
) -> Vec<Option<(D::Note, D::Recipient)>> {
|
||||
batch_note_decryption(ivks, outputs, try_compact_note_decryption_inner)
|
||||
}
|
||||
|
||||
fn batch_note_decryption<D: BatchDomain, Output: ShieldedOutput<D>, F, FR>(
|
||||
fn batch_note_decryption<D: BatchDomain, Output: ShieldedOutput<D, CS>, F, FR, const CS: usize>(
|
||||
ivks: &[D::IncomingViewingKey],
|
||||
outputs: &[(D, Output)],
|
||||
decrypt_inner: F,
|
||||
|
|
|
@ -82,7 +82,7 @@ pub struct NotePlaintextBytes(pub [u8; NOTE_PLAINTEXT_SIZE]);
|
|||
pub struct OutPlaintextBytes(pub [u8; OUT_PLAINTEXT_SIZE]);
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub enum NoteValidity {
|
||||
enum NoteValidity {
|
||||
Valid,
|
||||
Invalid,
|
||||
}
|
||||
|
@ -148,11 +148,6 @@ pub trait Domain {
|
|||
|
||||
fn epk(ephemeral_key: &EphemeralKeyBytes) -> Option<Self::EphemeralPublicKey>;
|
||||
|
||||
fn check_epk_bytes<F: Fn(&Self::EphemeralSecretKey) -> NoteValidity>(
|
||||
note: &Self::Note,
|
||||
check: F,
|
||||
) -> NoteValidity;
|
||||
|
||||
fn cmstar(note: &Self::Note) -> Self::ExtractedCommitment;
|
||||
|
||||
fn parse_note_plaintext_without_memo_ivk(
|
||||
|
@ -166,19 +161,17 @@ pub trait Domain {
|
|||
pk_d: &Self::DiversifiedTransmissionKey,
|
||||
esk: &Self::EphemeralSecretKey,
|
||||
ephemeral_key: &EphemeralKeyBytes,
|
||||
plaintext: &[u8],
|
||||
plaintext: &NotePlaintextBytes,
|
||||
) -> Option<(Self::Note, Self::Recipient)>;
|
||||
|
||||
// &self is passed here in anticipation of future changes
|
||||
// to memo handling where the memos may no longer be
|
||||
// part of the note plaintext.
|
||||
fn extract_memo(&self, plaintext: &[u8]) -> Self::Memo;
|
||||
fn extract_memo(&self, plaintext: &NotePlaintextBytes) -> Self::Memo;
|
||||
|
||||
fn extract_pk_d(
|
||||
out_plaintext: &[u8; OUT_PLAINTEXT_SIZE],
|
||||
) -> Option<Self::DiversifiedTransmissionKey>;
|
||||
fn extract_pk_d(out_plaintext: &OutPlaintextBytes) -> Option<Self::DiversifiedTransmissionKey>;
|
||||
|
||||
fn extract_esk(out_plaintext: &[u8; OUT_PLAINTEXT_SIZE]) -> Option<Self::EphemeralSecretKey>;
|
||||
fn extract_esk(out_plaintext: &OutPlaintextBytes) -> Option<Self::EphemeralSecretKey>;
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
|
@ -213,10 +206,10 @@ pub trait BatchDomain: Domain {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait ShieldedOutput<D: Domain> {
|
||||
pub trait ShieldedOutput<D: Domain, const CIPHERTEXT_SIZE: usize> {
|
||||
fn ephemeral_key(&self) -> EphemeralKeyBytes;
|
||||
fn cmstar_bytes(&self) -> D::ExtractedCommitmentBytes;
|
||||
fn enc_ciphertext(&self) -> &[u8];
|
||||
fn enc_ciphertext(&self) -> &[u8; CIPHERTEXT_SIZE];
|
||||
}
|
||||
|
||||
/// A struct containing context required for encrypting Sapling and Orchard notes.
|
||||
|
@ -291,12 +284,21 @@ impl<D: Domain> NoteEncryption<D> {
|
|||
memo: D::Memo,
|
||||
) -> Self {
|
||||
let esk = D::derive_esk(¬e).expect("ZIP 212 is active.");
|
||||
Self::new_with_esk(esk, ovk, note, to, memo)
|
||||
NoteEncryption {
|
||||
epk: D::ka_derive_public(¬e, &esk),
|
||||
esk,
|
||||
note,
|
||||
to,
|
||||
memo,
|
||||
ovk,
|
||||
}
|
||||
}
|
||||
|
||||
/// For use only with Sapling. This method is preserved in order that test code
|
||||
/// be able to generate pre-ZIP-212 ciphertexts so that tests can continue to
|
||||
/// cover pre-ZIP-212 transaction decryption.
|
||||
#[cfg(feature = "pre-zip-212")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "pre-zip-212")))]
|
||||
pub fn new_with_esk(
|
||||
esk: D::EphemeralSecretKey,
|
||||
ovk: Option<D::OutgoingViewingKey>,
|
||||
|
@ -387,7 +389,7 @@ impl<D: Domain> NoteEncryption<D> {
|
|||
///
|
||||
/// Implements section 4.19.2 of the
|
||||
/// [Zcash Protocol Specification](https://zips.z.cash/protocol/nu5.pdf#decryptivk).
|
||||
pub fn try_note_decryption<D: Domain, Output: ShieldedOutput<D>>(
|
||||
pub fn try_note_decryption<D: Domain, Output: ShieldedOutput<D, ENC_CIPHERTEXT_SIZE>>(
|
||||
domain: &D,
|
||||
ivk: &D::IncomingViewingKey,
|
||||
output: &Output,
|
||||
|
@ -401,7 +403,7 @@ pub fn try_note_decryption<D: Domain, Output: ShieldedOutput<D>>(
|
|||
try_note_decryption_inner(domain, ivk, &ephemeral_key, output, key)
|
||||
}
|
||||
|
||||
fn try_note_decryption_inner<D: Domain, Output: ShieldedOutput<D>>(
|
||||
fn try_note_decryption_inner<D: Domain, Output: ShieldedOutput<D, ENC_CIPHERTEXT_SIZE>>(
|
||||
domain: &D,
|
||||
ivk: &D::IncomingViewingKey,
|
||||
ephemeral_key: &EphemeralKeyBytes,
|
||||
|
@ -409,16 +411,15 @@ fn try_note_decryption_inner<D: Domain, Output: ShieldedOutput<D>>(
|
|||
key: D::SymmetricKey,
|
||||
) -> Option<(D::Note, D::Recipient, D::Memo)> {
|
||||
let enc_ciphertext = output.enc_ciphertext();
|
||||
assert_eq!(enc_ciphertext.len(), ENC_CIPHERTEXT_SIZE);
|
||||
|
||||
let mut plaintext: [u8; NOTE_PLAINTEXT_SIZE] =
|
||||
enc_ciphertext[..NOTE_PLAINTEXT_SIZE].try_into().unwrap();
|
||||
let mut plaintext =
|
||||
NotePlaintextBytes(enc_ciphertext[..NOTE_PLAINTEXT_SIZE].try_into().unwrap());
|
||||
|
||||
ChaCha20Poly1305::new(key.as_ref().into())
|
||||
.decrypt_in_place_detached(
|
||||
[0u8; 12][..].into(),
|
||||
&[],
|
||||
&mut plaintext,
|
||||
&mut plaintext.0,
|
||||
enc_ciphertext[NOTE_PLAINTEXT_SIZE..].into(),
|
||||
)
|
||||
.ok()?;
|
||||
|
@ -428,7 +429,7 @@ fn try_note_decryption_inner<D: Domain, Output: ShieldedOutput<D>>(
|
|||
ivk,
|
||||
ephemeral_key,
|
||||
&output.cmstar_bytes(),
|
||||
&plaintext,
|
||||
&plaintext.0,
|
||||
)?;
|
||||
let memo = domain.extract_memo(&plaintext);
|
||||
|
||||
|
@ -457,7 +458,7 @@ fn check_note_validity<D: Domain>(
|
|||
cmstar_bytes: &D::ExtractedCommitmentBytes,
|
||||
) -> NoteValidity {
|
||||
if &D::ExtractedCommitmentBytes::from(&D::cmstar(¬e)) == cmstar_bytes {
|
||||
D::check_epk_bytes(¬e, |derived_esk| {
|
||||
if let Some(derived_esk) = D::derive_esk(note) {
|
||||
if D::epk_bytes(&D::ka_derive_public(¬e, &derived_esk))
|
||||
.ct_eq(&ephemeral_key)
|
||||
.into()
|
||||
|
@ -466,7 +467,10 @@ fn check_note_validity<D: Domain>(
|
|||
} else {
|
||||
NoteValidity::Invalid
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// Before ZIP 212
|
||||
NoteValidity::Valid
|
||||
}
|
||||
} else {
|
||||
// Published commitment doesn't match calculated commitment
|
||||
NoteValidity::Invalid
|
||||
|
@ -482,7 +486,7 @@ fn check_note_validity<D: Domain>(
|
|||
/// Implements the procedure specified in [`ZIP 307`].
|
||||
///
|
||||
/// [`ZIP 307`]: https://zips.z.cash/zip-0307
|
||||
pub fn try_compact_note_decryption<D: Domain, Output: ShieldedOutput<D>>(
|
||||
pub fn try_compact_note_decryption<D: Domain, Output: ShieldedOutput<D, COMPACT_NOTE_SIZE>>(
|
||||
domain: &D,
|
||||
ivk: &D::IncomingViewingKey,
|
||||
output: &Output,
|
||||
|
@ -496,15 +500,13 @@ pub fn try_compact_note_decryption<D: Domain, Output: ShieldedOutput<D>>(
|
|||
try_compact_note_decryption_inner(domain, ivk, &ephemeral_key, output, key)
|
||||
}
|
||||
|
||||
fn try_compact_note_decryption_inner<D: Domain, Output: ShieldedOutput<D>>(
|
||||
fn try_compact_note_decryption_inner<D: Domain, Output: ShieldedOutput<D, COMPACT_NOTE_SIZE>>(
|
||||
domain: &D,
|
||||
ivk: &D::IncomingViewingKey,
|
||||
ephemeral_key: &EphemeralKeyBytes,
|
||||
output: &Output,
|
||||
key: D::SymmetricKey,
|
||||
) -> Option<(D::Note, D::Recipient)> {
|
||||
assert_eq!(output.enc_ciphertext().len(), COMPACT_NOTE_SIZE);
|
||||
|
||||
// Start from block 1 to skip over Poly1305 keying output
|
||||
let mut plaintext = [0; COMPACT_NOTE_SIZE];
|
||||
plaintext.copy_from_slice(output.enc_ciphertext());
|
||||
|
@ -530,12 +532,12 @@ fn try_compact_note_decryption_inner<D: Domain, Output: ShieldedOutput<D>>(
|
|||
/// Implements [Zcash Protocol Specification section 4.19.3][decryptovk].
|
||||
///
|
||||
/// [decryptovk]: https://zips.z.cash/protocol/nu5.pdf#decryptovk
|
||||
pub fn try_output_recovery_with_ovk<D: Domain, Output: ShieldedOutput<D>>(
|
||||
pub fn try_output_recovery_with_ovk<D: Domain, Output: ShieldedOutput<D, ENC_CIPHERTEXT_SIZE>>(
|
||||
domain: &D,
|
||||
ovk: &D::OutgoingViewingKey,
|
||||
output: &Output,
|
||||
cv: &D::ValueCommitment,
|
||||
out_ciphertext: &[u8],
|
||||
out_ciphertext: &[u8; OUT_CIPHERTEXT_SIZE],
|
||||
) -> Option<(D::Note, D::Recipient, D::Memo)> {
|
||||
let ock = D::derive_ock(ovk, &cv, &output.cmstar_bytes(), &output.ephemeral_key());
|
||||
try_output_recovery_with_ock(domain, &ock, output, out_ciphertext)
|
||||
|
@ -550,24 +552,22 @@ pub fn try_output_recovery_with_ovk<D: Domain, Output: ShieldedOutput<D>>(
|
|||
/// Implements part of section 4.19.3 of the
|
||||
/// [Zcash Protocol Specification](https://zips.z.cash/protocol/nu5.pdf#decryptovk).
|
||||
/// For decryption using a Full Viewing Key see [`try_output_recovery_with_ovk`].
|
||||
pub fn try_output_recovery_with_ock<D: Domain, Output: ShieldedOutput<D>>(
|
||||
pub fn try_output_recovery_with_ock<D: Domain, Output: ShieldedOutput<D, ENC_CIPHERTEXT_SIZE>>(
|
||||
domain: &D,
|
||||
ock: &OutgoingCipherKey,
|
||||
output: &Output,
|
||||
out_ciphertext: &[u8],
|
||||
out_ciphertext: &[u8; OUT_CIPHERTEXT_SIZE],
|
||||
) -> Option<(D::Note, D::Recipient, D::Memo)> {
|
||||
let enc_ciphertext = output.enc_ciphertext();
|
||||
assert_eq!(enc_ciphertext.len(), ENC_CIPHERTEXT_SIZE);
|
||||
assert_eq!(out_ciphertext.len(), OUT_CIPHERTEXT_SIZE);
|
||||
|
||||
let mut op = [0; OUT_PLAINTEXT_SIZE];
|
||||
op.copy_from_slice(&out_ciphertext[..OUT_PLAINTEXT_SIZE]);
|
||||
let mut op = OutPlaintextBytes([0; OUT_PLAINTEXT_SIZE]);
|
||||
op.0.copy_from_slice(&out_ciphertext[..OUT_PLAINTEXT_SIZE]);
|
||||
|
||||
ChaCha20Poly1305::new(ock.as_ref().into())
|
||||
.decrypt_in_place_detached(
|
||||
[0u8; 12][..].into(),
|
||||
&[],
|
||||
&mut op,
|
||||
&mut op.0,
|
||||
out_ciphertext[OUT_PLAINTEXT_SIZE..].into(),
|
||||
)
|
||||
.ok()?;
|
||||
|
@ -582,14 +582,16 @@ pub fn try_output_recovery_with_ock<D: Domain, Output: ShieldedOutput<D>>(
|
|||
// be okay.
|
||||
let key = D::kdf(shared_secret, &ephemeral_key);
|
||||
|
||||
let mut plaintext = [0; NOTE_PLAINTEXT_SIZE];
|
||||
plaintext.copy_from_slice(&enc_ciphertext[..NOTE_PLAINTEXT_SIZE]);
|
||||
let mut plaintext = NotePlaintextBytes([0; NOTE_PLAINTEXT_SIZE]);
|
||||
plaintext
|
||||
.0
|
||||
.copy_from_slice(&enc_ciphertext[..NOTE_PLAINTEXT_SIZE]);
|
||||
|
||||
ChaCha20Poly1305::new(key.as_ref().into())
|
||||
.decrypt_in_place_detached(
|
||||
[0u8; 12][..].into(),
|
||||
&[],
|
||||
&mut plaintext,
|
||||
&mut plaintext.0,
|
||||
enc_ciphertext[NOTE_PLAINTEXT_SIZE..].into(),
|
||||
)
|
||||
.ok()?;
|
||||
|
|
|
@ -127,7 +127,7 @@ impl TryFrom<compact_formats::CompactOutput> for CompactOutputDescription {
|
|||
Ok(CompactOutputDescription {
|
||||
cmu: value.cmu()?,
|
||||
ephemeral_key: value.ephemeral_key()?,
|
||||
enc_ciphertext: value.ciphertext,
|
||||
enc_ciphertext: value.ciphertext.try_into().map_err(|_| ())?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use ff::PrimeField;
|
|||
use std::collections::HashSet;
|
||||
use std::convert::TryFrom;
|
||||
use subtle::{ConditionallySelectable, ConstantTimeEq, CtOption};
|
||||
use zcash_note_encryption::ShieldedOutput;
|
||||
use zcash_note_encryption::{ShieldedOutput, COMPACT_NOTE_SIZE};
|
||||
use zcash_primitives::{
|
||||
consensus::{self, BlockHeight},
|
||||
merkle_tree::{CommitmentTree, IncrementalWitness},
|
||||
|
@ -109,7 +109,10 @@ pub trait ScanningKey {
|
|||
|
||||
/// Attempts to decrypt a Sapling note and payment address
|
||||
/// from the specified ciphertext using this scanning key.
|
||||
fn try_decryption<P: consensus::Parameters, Output: ShieldedOutput<SaplingDomain<P>>>(
|
||||
fn try_decryption<
|
||||
P: consensus::Parameters,
|
||||
Output: ShieldedOutput<SaplingDomain<P>, COMPACT_NOTE_SIZE>,
|
||||
>(
|
||||
&self,
|
||||
params: &P,
|
||||
height: BlockHeight,
|
||||
|
@ -131,7 +134,10 @@ pub trait ScanningKey {
|
|||
impl ScanningKey for ExtendedFullViewingKey {
|
||||
type Nf = Nullifier;
|
||||
|
||||
fn try_decryption<P: consensus::Parameters, Output: ShieldedOutput<SaplingDomain<P>>>(
|
||||
fn try_decryption<
|
||||
P: consensus::Parameters,
|
||||
Output: ShieldedOutput<SaplingDomain<P>, COMPACT_NOTE_SIZE>,
|
||||
>(
|
||||
&self,
|
||||
params: &P,
|
||||
height: BlockHeight,
|
||||
|
@ -152,7 +158,10 @@ impl ScanningKey for ExtendedFullViewingKey {
|
|||
impl ScanningKey for SaplingIvk {
|
||||
type Nf = ();
|
||||
|
||||
fn try_decryption<P: consensus::Parameters, Output: ShieldedOutput<SaplingDomain<P>>>(
|
||||
fn try_decryption<
|
||||
P: consensus::Parameters,
|
||||
Output: ShieldedOutput<SaplingDomain<P>, COMPACT_NOTE_SIZE>,
|
||||
>(
|
||||
&self,
|
||||
params: &P,
|
||||
height: BlockHeight,
|
||||
|
|
|
@ -45,7 +45,11 @@ secp256k1 = { version = "0.20", optional = true }
|
|||
sha2 = "0.9"
|
||||
subtle = "2.2.3"
|
||||
zcash_encoding = { version = "0.0", path = "../components/zcash_encoding" }
|
||||
zcash_note_encryption = { version = "0.0", path = "../components/zcash_note_encryption" }
|
||||
|
||||
[dependencies.zcash_note_encryption]
|
||||
version = "0.0"
|
||||
path = "../components/zcash_note_encryption"
|
||||
features = ["pre-zip-212"]
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = "0.3"
|
||||
|
|
|
@ -10,8 +10,8 @@ use std::convert::TryInto;
|
|||
use zcash_note_encryption::{
|
||||
try_compact_note_decryption, try_note_decryption, try_output_recovery_with_ock,
|
||||
try_output_recovery_with_ovk, BatchDomain, Domain, EphemeralKeyBytes, NoteEncryption,
|
||||
NotePlaintextBytes, NoteValidity, OutPlaintextBytes, OutgoingCipherKey, ShieldedOutput,
|
||||
COMPACT_NOTE_SIZE, NOTE_PLAINTEXT_SIZE, OUT_PLAINTEXT_SIZE,
|
||||
NotePlaintextBytes, OutPlaintextBytes, OutgoingCipherKey, ShieldedOutput, COMPACT_NOTE_SIZE,
|
||||
ENC_CIPHERTEXT_SIZE, NOTE_PLAINTEXT_SIZE, OUT_PLAINTEXT_SIZE,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
|
@ -247,18 +247,6 @@ impl<P: consensus::Parameters> Domain for SaplingDomain<P> {
|
|||
jubjub::ExtendedPoint::from_bytes(&ephemeral_key.0).into()
|
||||
}
|
||||
|
||||
fn check_epk_bytes<F: FnOnce(&Self::EphemeralSecretKey) -> NoteValidity>(
|
||||
note: &Note,
|
||||
check: F,
|
||||
) -> NoteValidity {
|
||||
if let Some(derived_esk) = note.derive_esk() {
|
||||
check(&derived_esk)
|
||||
} else {
|
||||
// Before ZIP 212
|
||||
NoteValidity::Valid
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_note_plaintext_without_memo_ivk(
|
||||
&self,
|
||||
ivk: &Self::IncomingViewingKey,
|
||||
|
@ -274,9 +262,9 @@ impl<P: consensus::Parameters> Domain for SaplingDomain<P> {
|
|||
pk_d: &Self::DiversifiedTransmissionKey,
|
||||
esk: &Self::EphemeralSecretKey,
|
||||
ephemeral_key: &EphemeralKeyBytes,
|
||||
plaintext: &[u8],
|
||||
plaintext: &NotePlaintextBytes,
|
||||
) -> Option<(Self::Note, Self::Recipient)> {
|
||||
sapling_parse_note_plaintext_without_memo(&self, plaintext, |diversifier| {
|
||||
sapling_parse_note_plaintext_without_memo(&self, &plaintext.0, |diversifier| {
|
||||
if (diversifier.g_d()? * esk).to_bytes() == ephemeral_key.0 {
|
||||
Some(*pk_d)
|
||||
} else {
|
||||
|
@ -289,29 +277,24 @@ impl<P: consensus::Parameters> Domain for SaplingDomain<P> {
|
|||
note.cmu()
|
||||
}
|
||||
|
||||
fn extract_pk_d(op: &[u8; OUT_PLAINTEXT_SIZE]) -> Option<Self::DiversifiedTransmissionKey> {
|
||||
let pk_d = jubjub::SubgroupPoint::from_bytes(
|
||||
op[0..32].try_into().expect("slice is the correct length"),
|
||||
);
|
||||
|
||||
if pk_d.is_none().into() {
|
||||
None
|
||||
} else {
|
||||
Some(pk_d.unwrap())
|
||||
}
|
||||
fn extract_pk_d(op: &OutPlaintextBytes) -> Option<Self::DiversifiedTransmissionKey> {
|
||||
jubjub::SubgroupPoint::from_bytes(
|
||||
op.0[0..32].try_into().expect("slice is the correct length"),
|
||||
)
|
||||
.into()
|
||||
}
|
||||
|
||||
fn extract_esk(op: &[u8; OUT_PLAINTEXT_SIZE]) -> Option<Self::EphemeralSecretKey> {
|
||||
fn extract_esk(op: &OutPlaintextBytes) -> Option<Self::EphemeralSecretKey> {
|
||||
jubjub::Fr::from_repr(
|
||||
op[32..OUT_PLAINTEXT_SIZE]
|
||||
op.0[32..OUT_PLAINTEXT_SIZE]
|
||||
.try_into()
|
||||
.expect("slice is the correct length"),
|
||||
)
|
||||
.into()
|
||||
}
|
||||
|
||||
fn extract_memo(&self, plaintext: &[u8]) -> Self::Memo {
|
||||
MemoBytes::from_bytes(&plaintext[COMPACT_NOTE_SIZE..NOTE_PLAINTEXT_SIZE]).unwrap()
|
||||
fn extract_memo(&self, plaintext: &NotePlaintextBytes) -> Self::Memo {
|
||||
MemoBytes::from_bytes(&plaintext.0[COMPACT_NOTE_SIZE..NOTE_PLAINTEXT_SIZE]).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -404,7 +387,7 @@ pub fn plaintext_version_is_valid<P: consensus::Parameters>(
|
|||
|
||||
pub fn try_sapling_note_decryption<
|
||||
P: consensus::Parameters,
|
||||
Output: ShieldedOutput<SaplingDomain<P>>,
|
||||
Output: ShieldedOutput<SaplingDomain<P>, ENC_CIPHERTEXT_SIZE>,
|
||||
>(
|
||||
params: &P,
|
||||
height: BlockHeight,
|
||||
|
@ -420,7 +403,7 @@ pub fn try_sapling_note_decryption<
|
|||
|
||||
pub fn try_sapling_compact_note_decryption<
|
||||
P: consensus::Parameters,
|
||||
Output: ShieldedOutput<SaplingDomain<P>>,
|
||||
Output: ShieldedOutput<SaplingDomain<P>, COMPACT_NOTE_SIZE>,
|
||||
>(
|
||||
params: &P,
|
||||
height: BlockHeight,
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
use core::fmt::Debug;
|
||||
use std::convert::TryInto;
|
||||
|
||||
use ff::PrimeField;
|
||||
use group::GroupEncoding;
|
||||
use std::io::{self, Read, Write};
|
||||
|
||||
use zcash_note_encryption::{EphemeralKeyBytes, ShieldedOutput, COMPACT_NOTE_SIZE};
|
||||
use zcash_note_encryption::{
|
||||
EphemeralKeyBytes, ShieldedOutput, COMPACT_NOTE_SIZE, ENC_CIPHERTEXT_SIZE,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
consensus,
|
||||
|
@ -219,7 +223,9 @@ pub struct OutputDescription<Proof> {
|
|||
pub zkproof: Proof,
|
||||
}
|
||||
|
||||
impl<P: consensus::Parameters, A> ShieldedOutput<SaplingDomain<P>> for OutputDescription<A> {
|
||||
impl<P: consensus::Parameters, A> ShieldedOutput<SaplingDomain<P>, ENC_CIPHERTEXT_SIZE>
|
||||
for OutputDescription<A>
|
||||
{
|
||||
fn ephemeral_key(&self) -> EphemeralKeyBytes {
|
||||
self.ephemeral_key.clone()
|
||||
}
|
||||
|
@ -228,7 +234,7 @@ impl<P: consensus::Parameters, A> ShieldedOutput<SaplingDomain<P>> for OutputDes
|
|||
self.cmu.to_repr()
|
||||
}
|
||||
|
||||
fn enc_ciphertext(&self) -> &[u8] {
|
||||
fn enc_ciphertext(&self) -> &[u8; ENC_CIPHERTEXT_SIZE] {
|
||||
&self.enc_ciphertext
|
||||
}
|
||||
}
|
||||
|
@ -347,7 +353,7 @@ impl OutputDescriptionV5 {
|
|||
pub struct CompactOutputDescription {
|
||||
pub ephemeral_key: EphemeralKeyBytes,
|
||||
pub cmu: bls12_381::Scalar,
|
||||
pub enc_ciphertext: Vec<u8>,
|
||||
pub enc_ciphertext: [u8; COMPACT_NOTE_SIZE],
|
||||
}
|
||||
|
||||
impl<A> From<OutputDescription<A>> for CompactOutputDescription {
|
||||
|
@ -355,12 +361,14 @@ impl<A> From<OutputDescription<A>> for CompactOutputDescription {
|
|||
CompactOutputDescription {
|
||||
ephemeral_key: out.ephemeral_key,
|
||||
cmu: out.cmu,
|
||||
enc_ciphertext: out.enc_ciphertext[..COMPACT_NOTE_SIZE].to_vec(),
|
||||
enc_ciphertext: out.enc_ciphertext[..COMPACT_NOTE_SIZE].try_into().unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: consensus::Parameters> ShieldedOutput<SaplingDomain<P>> for CompactOutputDescription {
|
||||
impl<P: consensus::Parameters> ShieldedOutput<SaplingDomain<P>, COMPACT_NOTE_SIZE>
|
||||
for CompactOutputDescription
|
||||
{
|
||||
fn ephemeral_key(&self) -> EphemeralKeyBytes {
|
||||
self.ephemeral_key.clone()
|
||||
}
|
||||
|
@ -369,7 +377,7 @@ impl<P: consensus::Parameters> ShieldedOutput<SaplingDomain<P>> for CompactOutpu
|
|||
self.cmu.to_repr()
|
||||
}
|
||||
|
||||
fn enc_ciphertext(&self) -> &[u8] {
|
||||
fn enc_ciphertext(&self) -> &[u8; COMPACT_NOTE_SIZE] {
|
||||
&self.enc_ciphertext
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue