Skip to content

Commit

Permalink
Use ephemeral_key bytes instead of the epk abstract point where speci…
Browse files Browse the repository at this point in the history
…fied.
  • Loading branch information
nuttycom committed Apr 12, 2021
1 parent 324fc36 commit 6fc1d1d
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 27 deletions.
26 changes: 17 additions & 9 deletions components/zcash_note_encryption/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ impl AsRef<[u8]> for OutgoingCipherKey {

pub struct EphemeralKeyBytes(pub [u8; 32]);

impl AsRef<[u8]> for EphemeralKeyBytes {
fn as_ref(&self) -> &[u8] {
&self.0
}
}

impl From<[u8; 32]> for EphemeralKeyBytes {
fn from(value: [u8; 32]) -> EphemeralKeyBytes {
EphemeralKeyBytes(value)
Expand Down Expand Up @@ -90,7 +96,7 @@ pub trait Domain {
epk: &Self::EphemeralPublicKey,
) -> Self::SharedSecret;

fn kdf(secret: Self::SharedSecret, epk: &Self::EphemeralPublicKey) -> Self::SymmetricKey;
fn kdf(secret: Self::SharedSecret, ephemeral_key: &EphemeralKeyBytes) -> Self::SymmetricKey;

// for right now, we just need `recipient` to get `d`; in the future when we
// can get that from a Sapling note, the recipient parameter will be able
Expand All @@ -101,11 +107,11 @@ pub trait Domain {
memo: &Self::Memo,
) -> NotePlaintextBytes;

fn get_ock(
fn derive_ock(
ovk: &Self::OutgoingViewingKey,
cv: &Self::ValueCommitment,
cm: &Self::NoteCommitment,
epk: &Self::EphemeralPublicKey,
ephemeral_key: &EphemeralKeyBytes,
) -> OutgoingCipherKey;

fn outgoing_plaintext_bytes(
Expand Down Expand Up @@ -227,7 +233,9 @@ impl<D: Domain> NoteEncryption<D> {
Self::new_with_esk(esk, ovk, note, to, memo)
}

/// For use only with Sapling.
/// 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.
pub fn new_with_esk(
esk: D::EphemeralSecretKey,
ovk: Option<D::OutgoingViewingKey>,
Expand Down Expand Up @@ -259,7 +267,7 @@ impl<D: Domain> NoteEncryption<D> {
pub fn encrypt_note_plaintext(&self) -> [u8; ENC_CIPHERTEXT_SIZE] {
let pk_d = D::get_pk_d(&self.note);
let shared_secret = D::ka_agree_enc(&self.esk, &pk_d);
let key = D::kdf(shared_secret, &self.epk);
let key = D::kdf(shared_secret, &D::epk_bytes(&self.epk));
let input = D::note_plaintext_bytes(&self.note, &self.to, &self.memo);

let mut output = [0u8; ENC_CIPHERTEXT_SIZE];
Expand All @@ -281,7 +289,7 @@ impl<D: Domain> NoteEncryption<D> {
rng: &mut R,
) -> [u8; OUT_CIPHERTEXT_SIZE] {
let (ock, input) = if let Some(ovk) = &self.ovk {
let ock = D::get_ock(ovk, &cv, &cm, &self.epk);
let ock = D::derive_ock(ovk, &cv, &cm, &D::epk_bytes(&self.epk));
let input = D::outgoing_plaintext_bytes(&self.note, &self.esk);

(ock, input)
Expand Down Expand Up @@ -323,7 +331,7 @@ pub fn try_note_decryption<D: Domain, Output: ShieldedOutput<D>>(
assert_eq!(output.enc_ciphertext().len(), ENC_CIPHERTEXT_SIZE);

let shared_secret = D::ka_agree_dec(ivk, output.epk());
let key = D::kdf(shared_secret, output.epk());
let key = D::kdf(shared_secret, &D::epk_bytes(output.epk()));

let mut plaintext = [0; ENC_CIPHERTEXT_SIZE];
assert_eq!(
Expand Down Expand Up @@ -407,7 +415,7 @@ pub fn try_compact_note_decryption<D: Domain, Output: ShieldedOutput<D>>(
assert_eq!(output.enc_ciphertext().len(), COMPACT_NOTE_SIZE);

let shared_secret = D::ka_agree_dec(&ivk, output.epk());
let key = D::kdf(shared_secret, output.epk());
let key = D::kdf(shared_secret, &D::epk_bytes(output.epk()));

// Start from block 1 to skip over Poly1305 keying output
let mut plaintext = [0; COMPACT_NOTE_SIZE];
Expand Down Expand Up @@ -446,7 +454,7 @@ pub fn try_output_recovery_with_ock<D: Domain, Output: ShieldedOutput<D>>(
let esk = D::extract_esk(&op)?;

let shared_secret = D::ka_agree_enc(&esk, &pk_d);
let key = D::kdf(shared_secret, output.epk());
let key = D::kdf(shared_secret, &D::epk_bytes(output.epk()));

let mut plaintext = [0; ENC_CIPHERTEXT_SIZE];
assert_eq!(
Expand Down
43 changes: 26 additions & 17 deletions zcash_primitives/src/sapling/note_encryption.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@ pub fn sapling_ka_agree(esk: &jubjub::Fr, pk_d: &jubjub::ExtendedPoint) -> jubju
/// Sapling KDF for note encryption.
///
/// Implements section 5.4.4.4 of the Zcash Protocol Specification.
fn kdf_sapling(dhsecret: jubjub::SubgroupPoint, epk: &jubjub::ExtendedPoint) -> Blake2bHash {
fn kdf_sapling(dhsecret: jubjub::SubgroupPoint, ephemeral_key: &EphemeralKeyBytes) -> Blake2bHash {
Blake2bParams::new()
.hash_length(32)
.personal(KDF_SAPLING_PERSONALIZATION)
.to_state()
.update(&dhsecret.to_bytes())
.update(&epk.to_bytes())
.update(ephemeral_key.as_ref())
.finalize()
}

Expand All @@ -55,7 +55,7 @@ pub fn prf_ock(
ovk: &OutgoingViewingKey,
cv: &jubjub::ExtendedPoint,
cmu: &bls12_381::Scalar,
epk: &jubjub::ExtendedPoint,
ephemeral_key: &EphemeralKeyBytes,
) -> OutgoingCipherKey {
OutgoingCipherKey(
Blake2bParams::new()
Expand All @@ -65,14 +65,18 @@ pub fn prf_ock(
.update(&ovk.0)
.update(&cv.to_bytes())
.update(&cmu.to_repr())
.update(&epk.to_bytes())
.update(ephemeral_key.as_ref())
.finalize()
.as_bytes()
.try_into()
.unwrap(),
)
}

fn epk_bytes(epk: &jubjub::ExtendedPoint) -> EphemeralKeyBytes {
EphemeralKeyBytes(epk.to_bytes())
}

fn sapling_parse_note_plaintext_without_memo<F, P: consensus::Parameters>(
domain: &SaplingDomain<P>,
plaintext: &[u8],
Expand Down Expand Up @@ -164,7 +168,7 @@ impl<P: consensus::Parameters> Domain for SaplingDomain<P> {
/// Sapling KDF for note encryption.
///
/// Implements section 5.4.4.4 of the Zcash Protocol Specification.
fn kdf(dhsecret: jubjub::SubgroupPoint, epk: &jubjub::ExtendedPoint) -> Blake2bHash {
fn kdf(dhsecret: jubjub::SubgroupPoint, epk: &EphemeralKeyBytes) -> Blake2bHash {
kdf_sapling(dhsecret, epk)
}

Expand Down Expand Up @@ -199,11 +203,11 @@ impl<P: consensus::Parameters> Domain for SaplingDomain<P> {
NotePlaintextBytes(input)
}

fn get_ock(
fn derive_ock(
ovk: &Self::OutgoingViewingKey,
cv: &Self::ValueCommitment,
cmu: &Self::NoteCommitment,
epk: &Self::EphemeralPublicKey,
epk: &EphemeralKeyBytes,
) -> OutgoingCipherKey {
prf_ock(ovk, cv, cmu, epk)
}
Expand All @@ -220,7 +224,7 @@ impl<P: consensus::Parameters> Domain for SaplingDomain<P> {
}

fn epk_bytes(epk: &Self::EphemeralPublicKey) -> EphemeralKeyBytes {
EphemeralKeyBytes(epk.to_bytes())
epk_bytes(epk)
}

fn check_epk_bytes<F: FnOnce(&Self::EphemeralSecretKey) -> NoteValidity>(
Expand Down Expand Up @@ -412,7 +416,12 @@ pub fn try_sapling_output_recovery<P: consensus::Parameters, Output: SaplingShie
try_sapling_output_recovery_with_ock(
params,
height,
&prf_ock(&ovk, &cv, output.cmu(), output.epk()),
&prf_ock(
&ovk,
&cv,
output.cmu(),
&SaplingDomain::<P>::epk_bytes(output.epk()),
),
output,
out_ciphertext,
)
Expand All @@ -434,7 +443,7 @@ mod tests {
};

use super::{
kdf_sapling, prf_ock, sapling_ka_agree, sapling_note_encryption,
epk_bytes, kdf_sapling, prf_ock, sapling_ka_agree, sapling_note_encryption,
try_sapling_compact_note_decryption, try_sapling_note_decryption,
try_sapling_output_recovery, try_sapling_output_recovery_with_ock, SaplingDomain,
};
Expand Down Expand Up @@ -533,13 +542,13 @@ mod tests {
MemoBytes::empty(),
&mut rng,
);
let ephemeral_key = *ne.epk();
let ock = prf_ock(&ovk, &cv, &cmu, &ephemeral_key);
let epk = *ne.epk();
let ock = prf_ock(&ovk, &cv, &cmu, &epk_bytes(&epk));

let output = OutputDescription {
cv,
cmu,
ephemeral_key,
ephemeral_key: epk,
enc_ciphertext: ne.encrypt_note_plaintext(),
out_ciphertext: ne.encrypt_outgoing_plaintext(&cv, &cmu, &mut rng),
zkproof: [0u8; GROTH_PROOF_SIZE],
Expand All @@ -557,7 +566,7 @@ mod tests {
out_ciphertext: &[u8; OUT_CIPHERTEXT_SIZE],
modify_plaintext: impl Fn(&mut [u8; NOTE_PLAINTEXT_SIZE]),
) {
let ock = prf_ock(&ovk, &cv, &cmu, &epk);
let ock = prf_ock(&ovk, &cv, &cmu, &epk_bytes(epk));

let mut op = [0; OUT_CIPHERTEXT_SIZE];
assert_eq!(
Expand All @@ -572,7 +581,7 @@ mod tests {
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 key = kdf_sapling(shared_secret, &epk);
let key = kdf_sapling(shared_secret, &epk_bytes(&epk));

let mut plaintext = {
let mut buf = [0; ENC_CIPHERTEXT_SIZE];
Expand Down Expand Up @@ -1403,11 +1412,11 @@ mod tests {
let shared_secret = sapling_ka_agree(&esk, &pk_d.into());
assert_eq!(shared_secret.to_bytes(), tv.shared_secret);

let k_enc = kdf_sapling(shared_secret, &epk);
let k_enc = kdf_sapling(shared_secret, &epk_bytes(&epk));
assert_eq!(k_enc.as_bytes(), tv.k_enc);

let ovk = OutgoingViewingKey(tv.ovk);
let ock = prf_ock(&ovk, &cv, &cmu, &epk);
let ock = prf_ock(&ovk, &cv, &cmu, &epk_bytes(&epk));
assert_eq!(ock.as_ref(), tv.ock);

let to = PaymentAddress::from_parts(Diversifier(tv.default_d), pk_d).unwrap();
Expand Down
1 change: 0 additions & 1 deletion zcash_primitives/src/transaction/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,6 @@ impl<P: consensus::Parameters> SaplingOutput<P> {

let enc_ciphertext = encryptor.encrypt_note_plaintext();
let out_ciphertext = encryptor.encrypt_outgoing_plaintext(&cv, &cmu, rng);

let ephemeral_key = *encryptor.epk();

OutputDescription {
Expand Down

0 comments on commit 6fc1d1d

Please sign in to comment.