Merge pull request #1061 from zcash/1044-sapling-prf-expand
zcash_primitives: Introduce type-safe `PRF^expand`
This commit is contained in:
commit
ecd5402266
|
@ -3114,6 +3114,7 @@ dependencies = [
|
|||
"zcash_address",
|
||||
"zcash_encoding",
|
||||
"zcash_note_encryption",
|
||||
"zcash_spec",
|
||||
"zip32",
|
||||
]
|
||||
|
||||
|
@ -3139,6 +3140,15 @@ dependencies = [
|
|||
"zcash_primitives",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zcash_spec"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7a3bf58b673cb3dacd8ae09ba345998923a197ab0da70d6239d8e8838949e9b"
|
||||
dependencies = [
|
||||
"blake2b_simd",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.25"
|
||||
|
|
|
@ -39,6 +39,7 @@ ff = "0.13"
|
|||
group = "0.13"
|
||||
incrementalmerkletree = "0.5"
|
||||
shardtree = "0.2"
|
||||
zcash_spec = "0.1"
|
||||
|
||||
# Payment protocols
|
||||
# - Sapling
|
||||
|
|
|
@ -215,6 +215,9 @@ and this library adheres to Rust's notion of
|
|||
### Removed
|
||||
- `zcash_primitives::constants`:
|
||||
- All `const` values (moved to `zcash_primitives::sapling::constants`).
|
||||
- `zcash_primitives::keys`:
|
||||
- `PRF_EXPAND_PERSONALIZATION`
|
||||
- `prf_expand, prf_expand_vec` (use `zcash_spec::PrfExpand` instead).
|
||||
- `zcash_primitives::sapling`:
|
||||
- `bundle`:
|
||||
- `SpendDescription::{read, read_nullifier, read_rk, read_spend_auth_sig}`
|
||||
|
|
|
@ -48,6 +48,7 @@ group = { workspace = true, features = ["wnaf-memuse"] }
|
|||
jubjub.workspace = true
|
||||
nonempty.workspace = true
|
||||
orchard.workspace = true
|
||||
zcash_spec.workspace = true
|
||||
|
||||
# - Note Commitment Trees
|
||||
incrementalmerkletree = { workspace = true, features = ["legacy-api"] }
|
||||
|
|
|
@ -1,22 +1 @@
|
|||
use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams};
|
||||
|
||||
pub use crate::sapling::keys::OutgoingViewingKey;
|
||||
|
||||
pub const PRF_EXPAND_PERSONALIZATION: &[u8; 16] = b"Zcash_ExpandSeed";
|
||||
|
||||
/// PRF^expand(sk, t) := BLAKE2b-512("Zcash_ExpandSeed", sk || t)
|
||||
pub fn prf_expand(sk: &[u8], t: &[u8]) -> Blake2bHash {
|
||||
prf_expand_vec(sk, &[t])
|
||||
}
|
||||
|
||||
pub fn prf_expand_vec(sk: &[u8], ts: &[&[u8]]) -> Blake2bHash {
|
||||
let mut h = Blake2bParams::new()
|
||||
.hash_length(64)
|
||||
.personal(PRF_EXPAND_PERSONALIZATION)
|
||||
.to_state();
|
||||
h.update(sk);
|
||||
for t in ts {
|
||||
h.update(t);
|
||||
}
|
||||
h.finalize()
|
||||
}
|
||||
|
|
|
@ -4,8 +4,9 @@ use hdwallet::{
|
|||
};
|
||||
use secp256k1::PublicKey;
|
||||
use sha2::{Digest, Sha256};
|
||||
use zcash_spec::PrfExpand;
|
||||
|
||||
use crate::{consensus, keys::prf_expand_vec, zip32::AccountId};
|
||||
use crate::{consensus, zip32::AccountId};
|
||||
|
||||
use super::TransparentAddress;
|
||||
|
||||
|
@ -111,11 +112,8 @@ impl AccountPubKey {
|
|||
///
|
||||
/// [transparent-ovk]: https://zips.z.cash/zip-0316#deriving-internal-keys
|
||||
pub fn ovks_for_shielding(&self) -> (InternalOvk, ExternalOvk) {
|
||||
let i_ovk = prf_expand_vec(
|
||||
&self.0.chain_code,
|
||||
&[&[0xd0], &self.0.public_key.serialize()],
|
||||
);
|
||||
let i_ovk = i_ovk.as_bytes();
|
||||
let i_ovk = PrfExpand::TRANSPARENT_ZIP316_OVK
|
||||
.with(&self.0.chain_code, &self.0.public_key.serialize());
|
||||
let ovk_external = ExternalOvk(i_ovk[..32].try_into().unwrap());
|
||||
let ovk_internal = InternalOvk(i_ovk[32..].try_into().unwrap());
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@ use super::{
|
|||
PreparedBaseSubgroup, PreparedScalar,
|
||||
},
|
||||
};
|
||||
use crate::keys::prf_expand;
|
||||
|
||||
use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams};
|
||||
use ff::{Field, PrimeField};
|
||||
|
@ -25,6 +24,7 @@ use group::{Curve, Group, GroupEncoding};
|
|||
use redjubjub::SpendAuth;
|
||||
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
|
||||
use zcash_note_encryption::EphemeralKeyBytes;
|
||||
use zcash_spec::PrfExpand;
|
||||
|
||||
#[cfg(test)]
|
||||
use rand_core::RngCore;
|
||||
|
@ -69,7 +69,7 @@ impl From<&SpendValidatingKey> for jubjub::ExtendedPoint {
|
|||
impl SpendAuthorizingKey {
|
||||
/// Derives ask from sk. Internal use only, does not enforce all constraints.
|
||||
fn derive_inner(sk: &[u8]) -> jubjub::Scalar {
|
||||
jubjub::Scalar::from_bytes_wide(prf_expand(sk, &[0x00]).as_array())
|
||||
jubjub::Scalar::from_bytes_wide(&PrfExpand::SAPLING_ASK.with(sk))
|
||||
}
|
||||
|
||||
/// Constructs a `SpendAuthorizingKey` from a raw scalar.
|
||||
|
@ -232,10 +232,10 @@ impl ExpandedSpendingKey {
|
|||
pub fn from_spending_key(sk: &[u8]) -> Self {
|
||||
let ask =
|
||||
SpendAuthorizingKey::from_spending_key(sk).expect("negligible chance of ask == 0");
|
||||
let nsk = jubjub::Fr::from_bytes_wide(prf_expand(sk, &[0x01]).as_array());
|
||||
let nsk = jubjub::Fr::from_bytes_wide(&PrfExpand::SAPLING_NSK.with(sk));
|
||||
let mut ovk = OutgoingViewingKey([0u8; 32]);
|
||||
ovk.0
|
||||
.copy_from_slice(&prf_expand(sk, &[0x02]).as_bytes()[..32]);
|
||||
.copy_from_slice(&PrfExpand::SAPLING_OVK.with(sk)[..32]);
|
||||
ExpandedSpendingKey { ask, nsk, ovk }
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use group::{ff::Field, GroupEncoding};
|
||||
use rand_core::{CryptoRng, RngCore};
|
||||
use zcash_spec::PrfExpand;
|
||||
|
||||
use super::{
|
||||
keys::EphemeralSecretKey, value::NoteValue, Nullifier, NullifierDerivingKey, PaymentAddress,
|
||||
};
|
||||
use crate::keys::prf_expand;
|
||||
|
||||
mod commitment;
|
||||
pub use self::commitment::{ExtractedNoteCommitment, NoteCommitment};
|
||||
|
@ -30,7 +30,7 @@ impl Rseed {
|
|||
commitment::NoteCommitTrapdoor(match self {
|
||||
Rseed::BeforeZip212(rcm) => *rcm,
|
||||
Rseed::AfterZip212(rseed) => {
|
||||
jubjub::Fr::from_bytes_wide(prf_expand(rseed, &[0x04]).as_array())
|
||||
jubjub::Fr::from_bytes_wide(&PrfExpand::SAPLING_RCM.with(rseed))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ impl Note {
|
|||
match self.rseed {
|
||||
Rseed::BeforeZip212(_) => None,
|
||||
Rseed::AfterZip212(rseed) => Some(EphemeralSecretKey(jubjub::Fr::from_bytes_wide(
|
||||
prf_expand(&rseed, &[0x05]).as_array(),
|
||||
&PrfExpand::SAPLING_ESK.with(&rseed),
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -358,9 +358,9 @@ impl ShieldedOutput<SaplingDomain, COMPACT_NOTE_SIZE> for CompactOutputDescripti
|
|||
/// use ff::Field;
|
||||
/// use rand_core::OsRng;
|
||||
/// use zcash_primitives::{
|
||||
/// keys::{OutgoingViewingKey, prf_expand},
|
||||
/// consensus::{TEST_NETWORK, NetworkUpgrade, Parameters},
|
||||
/// sapling::{
|
||||
/// keys::OutgoingViewingKey,
|
||||
/// note_encryption::{sapling_note_encryption, Zip212Enforcement},
|
||||
/// util::generate_random_rseed,
|
||||
/// value::{NoteValue, ValueCommitTrapdoor, ValueCommitment},
|
||||
|
|
|
@ -8,13 +8,13 @@ use aes::Aes256;
|
|||
use blake2b_simd::Params as Blake2bParams;
|
||||
use byteorder::{ByteOrder, LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||
use fpe::ff1::{BinaryNumeralString, FF1};
|
||||
use zcash_spec::PrfExpand;
|
||||
|
||||
use std::io::{self, Read, Write};
|
||||
use std::ops::AddAssign;
|
||||
|
||||
use super::{Diversifier, NullifierDerivingKey, PaymentAddress, ViewingKey};
|
||||
use crate::{
|
||||
keys::{prf_expand, prf_expand_vec},
|
||||
sapling::{
|
||||
constants::PROOF_GENERATION_KEY_GENERATOR,
|
||||
keys::{
|
||||
|
@ -69,7 +69,7 @@ pub fn sapling_default_address(
|
|||
/// Convenience function for child OVK derivation
|
||||
fn derive_child_ovk(parent: &OutgoingViewingKey, i_l: &[u8]) -> OutgoingViewingKey {
|
||||
let mut ovk = [0u8; 32];
|
||||
ovk.copy_from_slice(&prf_expand_vec(i_l, &[&[0x15], &parent.0]).as_bytes()[..32]);
|
||||
ovk.copy_from_slice(&PrfExpand::SAPLING_ZIP32_CHILD_OVK.with(i_l, &parent.0)[..32]);
|
||||
OutgoingViewingKey(ovk)
|
||||
}
|
||||
|
||||
|
@ -91,9 +91,9 @@ pub fn sapling_derive_internal_fvk(
|
|||
h.update(&dk.0);
|
||||
h.finalize()
|
||||
};
|
||||
let i_nsk = jubjub::Fr::from_bytes_wide(prf_expand(i.as_bytes(), &[0x17]).as_array());
|
||||
let r = prf_expand(i.as_bytes(), &[0x18]);
|
||||
let r = r.as_bytes();
|
||||
let i_nsk =
|
||||
jubjub::Fr::from_bytes_wide(&PrfExpand::SAPLING_ZIP32_INTERNAL_NSK.with(i.as_bytes()));
|
||||
let r = PrfExpand::SAPLING_ZIP32_INTERNAL_DK_OVK.with(i.as_bytes());
|
||||
// PROOF_GENERATION_KEY_GENERATOR = \mathcal{H}^Sapling
|
||||
let nk_internal = NullifierDerivingKey(PROOF_GENERATION_KEY_GENERATOR * i_nsk + fvk.vk.nk.0);
|
||||
let dk_internal = DiversifierKey(r[..32].try_into().unwrap());
|
||||
|
@ -156,7 +156,7 @@ pub struct DiversifierKey([u8; 32]);
|
|||
impl DiversifierKey {
|
||||
pub fn master(sk_m: &[u8]) -> Self {
|
||||
let mut dk_m = [0u8; 32];
|
||||
dk_m.copy_from_slice(&prf_expand(sk_m, &[0x10]).as_bytes()[..32]);
|
||||
dk_m.copy_from_slice(&PrfExpand::SAPLING_ZIP32_MASTER_DK.with(sk_m)[..32]);
|
||||
DiversifierKey(dk_m)
|
||||
}
|
||||
|
||||
|
@ -172,7 +172,7 @@ impl DiversifierKey {
|
|||
|
||||
fn derive_child(&self, i_l: &[u8]) -> Self {
|
||||
let mut dk = [0u8; 32];
|
||||
dk.copy_from_slice(&prf_expand_vec(i_l, &[&[0x16], &self.0]).as_bytes()[..32]);
|
||||
dk.copy_from_slice(&PrfExpand::SAPLING_ZIP32_CHILD_DK.with(i_l, &self.0)[..32]);
|
||||
DiversifierKey(dk)
|
||||
}
|
||||
|
||||
|
@ -422,14 +422,16 @@ impl ExtendedSpendingKey {
|
|||
let tmp = {
|
||||
let mut le_i = [0; 4];
|
||||
LittleEndian::write_u32(&mut le_i, i.index());
|
||||
prf_expand_vec(
|
||||
PrfExpand::SAPLING_ZIP32_CHILD_HARDENED.with(
|
||||
self.chain_code.as_bytes(),
|
||||
&[&[0x11], &self.expsk.to_bytes(), &self.dk.0, &le_i],
|
||||
&self.expsk.to_bytes(),
|
||||
&self.dk.0,
|
||||
&le_i,
|
||||
)
|
||||
};
|
||||
let i_l = &tmp.as_bytes()[..32];
|
||||
let i_l = &tmp[..32];
|
||||
let mut c_i = [0u8; 32];
|
||||
c_i.copy_from_slice(&tmp.as_bytes()[32..]);
|
||||
c_i.copy_from_slice(&tmp[32..]);
|
||||
|
||||
ExtendedSpendingKey {
|
||||
depth: self.depth + 1,
|
||||
|
@ -437,8 +439,10 @@ impl ExtendedSpendingKey {
|
|||
child_index: KeyIndex::Child(i),
|
||||
chain_code: ChainCode::new(c_i),
|
||||
expsk: {
|
||||
let mut ask = jubjub::Fr::from_bytes_wide(prf_expand(i_l, &[0x13]).as_array());
|
||||
let mut nsk = jubjub::Fr::from_bytes_wide(prf_expand(i_l, &[0x14]).as_array());
|
||||
let mut ask =
|
||||
jubjub::Fr::from_bytes_wide(&PrfExpand::SAPLING_ZIP32_CHILD_I_ASK.with(i_l));
|
||||
let mut nsk =
|
||||
jubjub::Fr::from_bytes_wide(&PrfExpand::SAPLING_ZIP32_CHILD_I_NSK.with(i_l));
|
||||
ask.add_assign(self.expsk.ask.to_scalar());
|
||||
nsk.add_assign(&self.expsk.nsk);
|
||||
let ovk = derive_child_ovk(&self.expsk.ovk, i_l);
|
||||
|
@ -474,9 +478,9 @@ impl ExtendedSpendingKey {
|
|||
h.update(&self.dk.0);
|
||||
h.finalize()
|
||||
};
|
||||
let i_nsk = jubjub::Fr::from_bytes_wide(prf_expand(i.as_bytes(), &[0x17]).as_array());
|
||||
let r = prf_expand(i.as_bytes(), &[0x18]);
|
||||
let r = r.as_bytes();
|
||||
let i_nsk =
|
||||
jubjub::Fr::from_bytes_wide(&PrfExpand::SAPLING_ZIP32_INTERNAL_NSK.with(i.as_bytes()));
|
||||
let r = PrfExpand::SAPLING_ZIP32_INTERNAL_DK_OVK.with(i.as_bytes());
|
||||
let nsk_internal = i_nsk + self.expsk.nsk;
|
||||
let dk_internal = DiversifierKey(r[..32].try_into().unwrap());
|
||||
let ovk_internal = OutgoingViewingKey(r[32..].try_into().unwrap());
|
||||
|
|
Loading…
Reference in New Issue