mirror of https://github.com/zcash/zip32.git
Diversifier derivation
This commit is contained in:
parent
f5d6091c93
commit
fea07c52de
|
@ -12,7 +12,9 @@ homepage = "https://github.com/zcash-hackworks/zip32"
|
||||||
repository = "https://github.com/zcash-hackworks/zip32"
|
repository = "https://github.com/zcash-hackworks/zip32"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
aes = "0.2"
|
||||||
byteorder = "1"
|
byteorder = "1"
|
||||||
|
fpe = "0.1"
|
||||||
lazy_static = "1.0"
|
lazy_static = "1.0"
|
||||||
pairing = "0.14.2"
|
pairing = "0.14.2"
|
||||||
|
|
||||||
|
|
86
src/lib.rs
86
src/lib.rs
|
@ -1,16 +1,20 @@
|
||||||
|
extern crate aes;
|
||||||
extern crate blake2_rfc;
|
extern crate blake2_rfc;
|
||||||
extern crate byteorder;
|
extern crate byteorder;
|
||||||
|
extern crate fpe;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
extern crate pairing;
|
extern crate pairing;
|
||||||
extern crate sapling_crypto;
|
extern crate sapling_crypto;
|
||||||
|
|
||||||
|
use aes::Aes256;
|
||||||
use blake2_rfc::blake2b::{Blake2b, Blake2bResult};
|
use blake2_rfc::blake2b::{Blake2b, Blake2bResult};
|
||||||
use byteorder::{ByteOrder, LittleEndian};
|
use byteorder::{ByteOrder, LittleEndian};
|
||||||
|
use fpe::ff1::{BinaryNumeralString, FF1};
|
||||||
use pairing::{bls12_381::Bls12, Field, PrimeField, PrimeFieldRepr};
|
use pairing::{bls12_381::Bls12, Field, PrimeField, PrimeFieldRepr};
|
||||||
use sapling_crypto::{
|
use sapling_crypto::{
|
||||||
jubjub::{FixedGenerators, JubjubBls12, JubjubEngine, JubjubParams, ToUniform},
|
jubjub::{FixedGenerators, JubjubBls12, JubjubEngine, JubjubParams, ToUniform},
|
||||||
primitives::ViewingKey,
|
primitives::{Diversifier, ViewingKey},
|
||||||
};
|
};
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
|
@ -208,6 +212,31 @@ impl ChildIndex {
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
struct ChainCode([u8; 32]);
|
struct ChainCode([u8; 32]);
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub struct DiversifierIndex([u8; 11]);
|
||||||
|
|
||||||
|
impl DiversifierIndex {
|
||||||
|
fn new() -> Self {
|
||||||
|
DiversifierIndex([0; 11])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn increment(&mut self) -> Result<(), ()> {
|
||||||
|
let mut k = 0;
|
||||||
|
loop {
|
||||||
|
self.0[k] += 1;
|
||||||
|
if self.0[k] != 0 {
|
||||||
|
// No overflow
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
// Overflow
|
||||||
|
k += 1;
|
||||||
|
if k == 11 {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A key used to derive diversifiers for a particular child key
|
/// A key used to derive diversifiers for a particular child key
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
struct DiversifierKey([u8; 32]);
|
struct DiversifierKey([u8; 32]);
|
||||||
|
@ -224,6 +253,29 @@ impl DiversifierKey {
|
||||||
dk.copy_from_slice(&prf_expand_vec(i_l, &[&[0x16], &self.0]).as_bytes()[..32]);
|
dk.copy_from_slice(&prf_expand_vec(i_l, &[&[0x16], &self.0]).as_bytes()[..32]);
|
||||||
DiversifierKey(dk)
|
DiversifierKey(dk)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the first index starting from j that generates a valid
|
||||||
|
/// diversifier, along with the corresponding diversifier. Returns
|
||||||
|
/// an error if the diversifier space is exhausted.
|
||||||
|
fn diversifier(&self, mut j: DiversifierIndex) -> Result<(DiversifierIndex, Diversifier), ()> {
|
||||||
|
let ff = FF1::<Aes256>::new(&self.0, 2).unwrap();
|
||||||
|
loop {
|
||||||
|
// Generate d_j
|
||||||
|
let enc = ff.encrypt(&[], &BinaryNumeralString::from_bytes_le(&j.0[..]))
|
||||||
|
.unwrap();
|
||||||
|
let mut d_j = [0; 11];
|
||||||
|
d_j.copy_from_slice(&enc.to_bytes_le());
|
||||||
|
let d_j = Diversifier(d_j);
|
||||||
|
|
||||||
|
// Return (j, d_j) if valid, else increment j and try again
|
||||||
|
match d_j.g_d::<Bls12>(&JUBJUB) {
|
||||||
|
Some(_) => return Ok((j, d_j)),
|
||||||
|
None => if j.increment().is_err() {
|
||||||
|
return Err(());
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A Sapling extended spending key
|
/// A Sapling extended spending key
|
||||||
|
@ -459,4 +511,36 @@ mod tests {
|
||||||
xsk_5h_7
|
xsk_5h_7
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn diversifier() {
|
||||||
|
let dk = DiversifierKey([0; 32]);
|
||||||
|
let j_0 = DiversifierIndex::new();
|
||||||
|
let j_1 = DiversifierIndex([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
|
||||||
|
let j_2 = DiversifierIndex([2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
|
||||||
|
let j_3 = DiversifierIndex([3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
|
||||||
|
// Computed using this Rust implementation
|
||||||
|
let d_0 = [220, 231, 126, 188, 236, 10, 38, 175, 214, 153, 140];
|
||||||
|
let d_3 = [60, 253, 170, 8, 171, 147, 220, 31, 3, 144, 34];
|
||||||
|
|
||||||
|
// j = 0
|
||||||
|
let (j, d_j) = dk.diversifier(j_0).unwrap();
|
||||||
|
assert_eq!(j, j_0);
|
||||||
|
assert_eq!(d_j.0, d_0);
|
||||||
|
|
||||||
|
// j = 1
|
||||||
|
let (j, d_j) = dk.diversifier(j_1).unwrap();
|
||||||
|
assert_eq!(j, j_3);
|
||||||
|
assert_eq!(d_j.0, d_3);
|
||||||
|
|
||||||
|
// j = 2
|
||||||
|
let (j, d_j) = dk.diversifier(j_2).unwrap();
|
||||||
|
assert_eq!(j, j_3);
|
||||||
|
assert_eq!(d_j.0, d_3);
|
||||||
|
|
||||||
|
// j = 3
|
||||||
|
let (j, d_j) = dk.diversifier(j_3).unwrap();
|
||||||
|
assert_eq!(j, j_3);
|
||||||
|
assert_eq!(d_j.0, d_3);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue