From 2fdfa4b6710d020bdd4a768225d9ed2a4f208e7c Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 11 Jul 2018 01:28:10 +0100 Subject: [PATCH] ExtendedSpendingKey::master() --- Cargo.toml | 4 ++++ src/lib.rs | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 0872467..764a2a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,10 @@ repository = "https://github.com/zcash-hackworks/zip32" lazy_static = "1.0" pairing = "0.14.2" +[dependencies.blake2-rfc] +git = "https://github.com/gtank/blake2-rfc" +rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9" + [dependencies.sapling-crypto] git = "https://github.com/zcash-hackworks/sapling-crypto" rev = "21084bde2019c04bd34208e63c3560fe2c02fb0e" diff --git a/src/lib.rs b/src/lib.rs index 60429eb..88b8438 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,19 +1,33 @@ +extern crate blake2_rfc; #[macro_use] extern crate lazy_static; extern crate pairing; extern crate sapling_crypto; +use blake2_rfc::blake2b::{Blake2b, Blake2bResult}; use pairing::bls12_381::Bls12; use sapling_crypto::{ - jubjub::{FixedGenerators, JubjubBls12, JubjubEngine, JubjubParams}, primitives::ViewingKey, + jubjub::{FixedGenerators, JubjubBls12, JubjubEngine, JubjubParams, ToUniform}, + primitives::ViewingKey, }; lazy_static! { static ref JUBJUB: JubjubBls12 = { JubjubBls12::new() }; } +pub const PRF_EXPAND_PERSONALIZATION: &'static [u8; 16] = b"Zcash_ExpandSeed"; +pub const ZIP32_SAPLING_MASTER_PERSONALIZATION: &'static [u8; 16] = b"ZcashIP32Sapling"; + // Sapling key components +/// PRF^expand(sk, t) := BLAKE2b-512("Zcash_ExpandSeed", sk || t) +fn prf_expand(sk: &[u8], t: &[u8]) -> Blake2bResult { + let mut h = Blake2b::with_params(64, &[], &[], PRF_EXPAND_PERSONALIZATION); + h.update(sk); + h.update(t); + h.finalize() +} + /// An outgoing viewing key #[derive(Clone, Copy)] struct OutgoingViewingKey([u8; 32]); @@ -31,6 +45,17 @@ struct FullViewingKey { ovk: OutgoingViewingKey, } +impl ExpandedSpendingKey { + fn from_spending_key(sk: &[u8]) -> Self { + let ask = E::Fs::to_uniform(prf_expand(sk, &[0x00]).as_bytes()); + let nsk = E::Fs::to_uniform(prf_expand(sk, &[0x01]).as_bytes()); + let mut ovk = OutgoingViewingKey([0u8; 32]); + ovk.0 + .copy_from_slice(&prf_expand(sk, &[0x02]).as_bytes()[..32]); + ExpandedSpendingKey { ask, nsk, ovk } + } +} + impl FullViewingKey { fn from_expanded_spending_key(xsk: &ExpandedSpendingKey, params: &E::Params) -> Self { FullViewingKey { @@ -70,6 +95,12 @@ impl From for FVKTag { } } +impl FVKTag { + fn master() -> Self { + FVKTag([0u8; 4]) + } +} + /// A child index for a derived key #[derive(Clone, Copy)] pub enum ChildIndex { @@ -84,6 +115,10 @@ impl ChildIndex { n => ChildIndex::NonHardened(n), } } + + fn master() -> Self { + ChildIndex::from_index(0) + } } /// A chain code @@ -94,6 +129,14 @@ struct ChainCode([u8; 32]); #[derive(Clone, Copy)] struct DiversifierKey([u8; 32]); +impl DiversifierKey { + 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]); + DiversifierKey(dk_m) + } +} + /// A Sapling extended spending key pub struct ExtendedSpendingKey { depth: u8, @@ -114,6 +157,27 @@ pub struct ExtendedFullViewingKey { dk: DiversifierKey, } +impl ExtendedSpendingKey { + pub fn master(seed: &[u8]) -> Self { + let mut h = Blake2b::with_params(64, &[], &[], ZIP32_SAPLING_MASTER_PERSONALIZATION); + h.update(seed); + let i = h.finalize(); + + let sk_m = &i.as_bytes()[..32]; + let mut c_m = [0u8; 32]; + c_m.copy_from_slice(&i.as_bytes()[32..]); + + ExtendedSpendingKey { + depth: 0, + parent_fvk_tag: FVKTag::master(), + child_index: ChildIndex::master(), + chain_code: ChainCode(c_m), + xsk: ExpandedSpendingKey::from_spending_key(sk_m), + dk: DiversifierKey::master(sk_m), + } + } +} + impl<'a> From<&'a ExtendedSpendingKey> for ExtendedFullViewingKey { fn from(xsk: &ExtendedSpendingKey) -> Self { ExtendedFullViewingKey {