zcash_primitives: Add OutgoingCipherKey struct
This commit is contained in:
parent
50140c521a
commit
72817b0edc
|
@ -152,6 +152,21 @@ fn kdf_sapling(dhsecret: jubjub::SubgroupPoint, epk: &jubjub::SubgroupPoint) ->
|
||||||
.finalize()
|
.finalize()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A symmetric key that can be used to recover a single Sapling output.
|
||||||
|
pub struct OutgoingCipherKey([u8; 32]);
|
||||||
|
|
||||||
|
impl From<[u8; 32]> for OutgoingCipherKey {
|
||||||
|
fn from(ock: [u8; 32]) -> Self {
|
||||||
|
OutgoingCipherKey(ock)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<[u8]> for OutgoingCipherKey {
|
||||||
|
fn as_ref(&self) -> &[u8] {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Sapling PRF^ock.
|
/// Sapling PRF^ock.
|
||||||
///
|
///
|
||||||
/// Implemented per section 5.4.2 of the Zcash Protocol Specification.
|
/// Implemented per section 5.4.2 of the Zcash Protocol Specification.
|
||||||
|
@ -160,7 +175,8 @@ pub fn prf_ock(
|
||||||
cv: &jubjub::ExtendedPoint,
|
cv: &jubjub::ExtendedPoint,
|
||||||
cmu: &bls12_381::Scalar,
|
cmu: &bls12_381::Scalar,
|
||||||
epk: &jubjub::SubgroupPoint,
|
epk: &jubjub::SubgroupPoint,
|
||||||
) -> Blake2bHash {
|
) -> OutgoingCipherKey {
|
||||||
|
OutgoingCipherKey(
|
||||||
Blake2bParams::new()
|
Blake2bParams::new()
|
||||||
.hash_length(32)
|
.hash_length(32)
|
||||||
.personal(PRF_OCK_PERSONALIZATION)
|
.personal(PRF_OCK_PERSONALIZATION)
|
||||||
|
@ -170,6 +186,10 @@ pub fn prf_ock(
|
||||||
.update(&cmu.to_repr())
|
.update(&cmu.to_repr())
|
||||||
.update(&epk.to_bytes())
|
.update(&epk.to_bytes())
|
||||||
.finalize()
|
.finalize()
|
||||||
|
.as_bytes()
|
||||||
|
.try_into()
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An API for encrypting Sapling notes.
|
/// An API for encrypting Sapling notes.
|
||||||
|
@ -301,7 +321,7 @@ impl SaplingNoteEncryption {
|
||||||
cv: &jubjub::ExtendedPoint,
|
cv: &jubjub::ExtendedPoint,
|
||||||
cmu: &bls12_381::Scalar,
|
cmu: &bls12_381::Scalar,
|
||||||
) -> [u8; OUT_CIPHERTEXT_SIZE] {
|
) -> [u8; OUT_CIPHERTEXT_SIZE] {
|
||||||
let key = prf_ock(&self.ovk, &cv, &cmu, &self.epk);
|
let ock = prf_ock(&self.ovk, &cv, &cmu, &self.epk);
|
||||||
|
|
||||||
let mut input = [0u8; OUT_PLAINTEXT_SIZE];
|
let mut input = [0u8; OUT_PLAINTEXT_SIZE];
|
||||||
input[0..32].copy_from_slice(&self.note.pk_d.to_bytes());
|
input[0..32].copy_from_slice(&self.note.pk_d.to_bytes());
|
||||||
|
@ -310,7 +330,7 @@ impl SaplingNoteEncryption {
|
||||||
let mut output = [0u8; OUT_CIPHERTEXT_SIZE];
|
let mut output = [0u8; OUT_CIPHERTEXT_SIZE];
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ChachaPolyIetf::aead_cipher()
|
ChachaPolyIetf::aead_cipher()
|
||||||
.seal_to(&mut output, &input, &[], key.as_bytes(), &[0u8; 12])
|
.seal_to(&mut output, &input, &[], ock.as_ref(), &[0u8; 12])
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
OUT_CIPHERTEXT_SIZE
|
OUT_CIPHERTEXT_SIZE
|
||||||
);
|
);
|
||||||
|
@ -468,7 +488,7 @@ pub fn try_sapling_compact_note_decryption<P: consensus::Parameters>(
|
||||||
/// For decryption using a Full Viewing Key see [`try_sapling_output_recovery`].
|
/// For decryption using a Full Viewing Key see [`try_sapling_output_recovery`].
|
||||||
pub fn try_sapling_output_recovery_with_ock<P: consensus::Parameters>(
|
pub fn try_sapling_output_recovery_with_ock<P: consensus::Parameters>(
|
||||||
height: u32,
|
height: u32,
|
||||||
ock: &[u8],
|
ock: &OutgoingCipherKey,
|
||||||
cmu: &bls12_381::Scalar,
|
cmu: &bls12_381::Scalar,
|
||||||
epk: &jubjub::SubgroupPoint,
|
epk: &jubjub::SubgroupPoint,
|
||||||
enc_ciphertext: &[u8],
|
enc_ciphertext: &[u8],
|
||||||
|
@ -480,7 +500,7 @@ pub fn try_sapling_output_recovery_with_ock<P: consensus::Parameters>(
|
||||||
let mut op = [0; OUT_CIPHERTEXT_SIZE];
|
let mut op = [0; OUT_CIPHERTEXT_SIZE];
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ChachaPolyIetf::aead_cipher()
|
ChachaPolyIetf::aead_cipher()
|
||||||
.open_to(&mut op, &out_ciphertext, &[], &ock, &[0u8; 12])
|
.open_to(&mut op, &out_ciphertext, &[], ock.as_ref(), &[0u8; 12])
|
||||||
.ok()?,
|
.ok()?,
|
||||||
OUT_PLAINTEXT_SIZE
|
OUT_PLAINTEXT_SIZE
|
||||||
);
|
);
|
||||||
|
@ -583,7 +603,7 @@ pub fn try_sapling_output_recovery<P: consensus::Parameters>(
|
||||||
) -> Option<(Note, PaymentAddress, Memo)> {
|
) -> Option<(Note, PaymentAddress, Memo)> {
|
||||||
try_sapling_output_recovery_with_ock::<P>(
|
try_sapling_output_recovery_with_ock::<P>(
|
||||||
height,
|
height,
|
||||||
prf_ock(&ovk, &cv, &cmu, &epk).as_bytes(),
|
&prf_ock(&ovk, &cv, &cmu, &epk),
|
||||||
cmu,
|
cmu,
|
||||||
epk,
|
epk,
|
||||||
enc_ciphertext,
|
enc_ciphertext,
|
||||||
|
@ -593,7 +613,6 @@ pub fn try_sapling_output_recovery<P: consensus::Parameters>(
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use blake2b_simd::Hash as Blake2bHash;
|
|
||||||
use crypto_api_chachapoly::ChachaPolyIetf;
|
use crypto_api_chachapoly::ChachaPolyIetf;
|
||||||
use ff::{Field, PrimeField};
|
use ff::{Field, PrimeField};
|
||||||
use group::Group;
|
use group::Group;
|
||||||
|
@ -606,8 +625,9 @@ mod tests {
|
||||||
use super::{
|
use super::{
|
||||||
kdf_sapling, prf_ock, sapling_ka_agree, try_sapling_compact_note_decryption,
|
kdf_sapling, prf_ock, sapling_ka_agree, try_sapling_compact_note_decryption,
|
||||||
try_sapling_note_decryption, try_sapling_output_recovery,
|
try_sapling_note_decryption, try_sapling_output_recovery,
|
||||||
try_sapling_output_recovery_with_ock, Memo, SaplingNoteEncryption, COMPACT_NOTE_SIZE,
|
try_sapling_output_recovery_with_ock, Memo, OutgoingCipherKey, SaplingNoteEncryption,
|
||||||
ENC_CIPHERTEXT_SIZE, NOTE_PLAINTEXT_SIZE, OUT_CIPHERTEXT_SIZE, OUT_PLAINTEXT_SIZE,
|
COMPACT_NOTE_SIZE, ENC_CIPHERTEXT_SIZE, NOTE_PLAINTEXT_SIZE, OUT_CIPHERTEXT_SIZE,
|
||||||
|
OUT_PLAINTEXT_SIZE,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
consensus::{
|
consensus::{
|
||||||
|
@ -741,7 +761,7 @@ mod tests {
|
||||||
mut rng: &mut R,
|
mut rng: &mut R,
|
||||||
) -> (
|
) -> (
|
||||||
OutgoingViewingKey,
|
OutgoingViewingKey,
|
||||||
Blake2bHash,
|
OutgoingCipherKey,
|
||||||
jubjub::Fr,
|
jubjub::Fr,
|
||||||
jubjub::ExtendedPoint,
|
jubjub::ExtendedPoint,
|
||||||
bls12_381::Scalar,
|
bls12_381::Scalar,
|
||||||
|
@ -782,7 +802,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
let ock_output_recovery = try_sapling_output_recovery_with_ock::<TestNetwork>(
|
let ock_output_recovery = try_sapling_output_recovery_with_ock::<TestNetwork>(
|
||||||
height,
|
height,
|
||||||
ock.as_bytes(),
|
&ock,
|
||||||
&cmu,
|
&cmu,
|
||||||
&epk,
|
&epk,
|
||||||
&enc_ciphertext,
|
&enc_ciphertext,
|
||||||
|
@ -801,7 +821,7 @@ mod tests {
|
||||||
mut rng: &mut R,
|
mut rng: &mut R,
|
||||||
) -> (
|
) -> (
|
||||||
OutgoingViewingKey,
|
OutgoingViewingKey,
|
||||||
Blake2bHash,
|
OutgoingCipherKey,
|
||||||
jubjub::Fr,
|
jubjub::Fr,
|
||||||
jubjub::ExtendedPoint,
|
jubjub::ExtendedPoint,
|
||||||
bls12_381::Scalar,
|
bls12_381::Scalar,
|
||||||
|
@ -859,7 +879,7 @@ mod tests {
|
||||||
let mut op = [0; OUT_CIPHERTEXT_SIZE];
|
let mut op = [0; OUT_CIPHERTEXT_SIZE];
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ChachaPolyIetf::aead_cipher()
|
ChachaPolyIetf::aead_cipher()
|
||||||
.open_to(&mut op, out_ciphertext, &[], ock.as_bytes(), &[0u8; 12])
|
.open_to(&mut op, out_ciphertext, &[], ock.as_ref(), &[0u8; 12])
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
OUT_PLAINTEXT_SIZE
|
OUT_PLAINTEXT_SIZE
|
||||||
);
|
);
|
||||||
|
@ -1351,7 +1371,7 @@ mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
try_sapling_output_recovery_with_ock::<TestNetwork>(
|
try_sapling_output_recovery_with_ock::<TestNetwork>(
|
||||||
height,
|
height,
|
||||||
&[0u8; 32],
|
&OutgoingCipherKey([0u8; 32]),
|
||||||
&cmu,
|
&cmu,
|
||||||
&epk,
|
&epk,
|
||||||
&enc_ciphertext,
|
&enc_ciphertext,
|
||||||
|
@ -1416,7 +1436,7 @@ mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
try_sapling_output_recovery_with_ock::<TestNetwork>(
|
try_sapling_output_recovery_with_ock::<TestNetwork>(
|
||||||
height,
|
height,
|
||||||
&ock.as_bytes(),
|
&ock,
|
||||||
&bls12_381::Scalar::random(&mut rng),
|
&bls12_381::Scalar::random(&mut rng),
|
||||||
&epk,
|
&epk,
|
||||||
&enc_ctext,
|
&enc_ctext,
|
||||||
|
@ -1454,7 +1474,7 @@ mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
try_sapling_output_recovery_with_ock::<TestNetwork>(
|
try_sapling_output_recovery_with_ock::<TestNetwork>(
|
||||||
height,
|
height,
|
||||||
&ock.as_bytes(),
|
&ock,
|
||||||
&cmu,
|
&cmu,
|
||||||
&jubjub::SubgroupPoint::random(&mut rng),
|
&jubjub::SubgroupPoint::random(&mut rng),
|
||||||
&enc_ciphertext,
|
&enc_ciphertext,
|
||||||
|
@ -1493,7 +1513,7 @@ mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
try_sapling_output_recovery_with_ock::<TestNetwork>(
|
try_sapling_output_recovery_with_ock::<TestNetwork>(
|
||||||
height,
|
height,
|
||||||
&ock.as_bytes(),
|
&ock,
|
||||||
&cmu,
|
&cmu,
|
||||||
&epk,
|
&epk,
|
||||||
&enc_ciphertext,
|
&enc_ciphertext,
|
||||||
|
@ -1532,7 +1552,7 @@ mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
try_sapling_output_recovery_with_ock::<TestNetwork>(
|
try_sapling_output_recovery_with_ock::<TestNetwork>(
|
||||||
height,
|
height,
|
||||||
&ock.as_bytes(),
|
&ock,
|
||||||
&cmu,
|
&cmu,
|
||||||
&epk,
|
&epk,
|
||||||
&enc_ciphertext,
|
&enc_ciphertext,
|
||||||
|
@ -1582,7 +1602,7 @@ mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
try_sapling_output_recovery_with_ock::<TestNetwork>(
|
try_sapling_output_recovery_with_ock::<TestNetwork>(
|
||||||
height,
|
height,
|
||||||
&ock.as_bytes(),
|
&ock,
|
||||||
&cmu,
|
&cmu,
|
||||||
&epk,
|
&epk,
|
||||||
&enc_ciphertext,
|
&enc_ciphertext,
|
||||||
|
@ -1629,7 +1649,7 @@ mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
try_sapling_output_recovery_with_ock::<TestNetwork>(
|
try_sapling_output_recovery_with_ock::<TestNetwork>(
|
||||||
height,
|
height,
|
||||||
&ock.as_bytes(),
|
&ock,
|
||||||
&cmu,
|
&cmu,
|
||||||
&epk,
|
&epk,
|
||||||
&enc_ciphertext,
|
&enc_ciphertext,
|
||||||
|
@ -1676,7 +1696,7 @@ mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
try_sapling_output_recovery_with_ock::<TestNetwork>(
|
try_sapling_output_recovery_with_ock::<TestNetwork>(
|
||||||
height,
|
height,
|
||||||
&ock.as_bytes(),
|
&ock,
|
||||||
&cmu,
|
&cmu,
|
||||||
&epk,
|
&epk,
|
||||||
&enc_ciphertext,
|
&enc_ciphertext,
|
||||||
|
@ -1715,7 +1735,7 @@ mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
try_sapling_output_recovery_with_ock::<TestNetwork>(
|
try_sapling_output_recovery_with_ock::<TestNetwork>(
|
||||||
height,
|
height,
|
||||||
&ock.as_bytes(),
|
&ock,
|
||||||
&cmu,
|
&cmu,
|
||||||
&epk,
|
&epk,
|
||||||
&enc_ciphertext,
|
&enc_ciphertext,
|
||||||
|
@ -1776,7 +1796,7 @@ mod tests {
|
||||||
|
|
||||||
let ovk = OutgoingViewingKey(tv.ovk);
|
let ovk = OutgoingViewingKey(tv.ovk);
|
||||||
let ock = prf_ock(&ovk, &cv, &cmu, &epk);
|
let ock = prf_ock(&ovk, &cv, &cmu, &epk);
|
||||||
assert_eq!(ock.as_bytes(), 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();
|
||||||
let note = to.create_note(tv.v, Rseed::BeforeZip212(rcm)).unwrap();
|
let note = to.create_note(tv.v, Rseed::BeforeZip212(rcm)).unwrap();
|
||||||
|
|
Loading…
Reference in New Issue