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