diff --git a/Cargo.toml b/Cargo.toml index 48cc9ec..cdfbebb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,26 +2,21 @@ name = "zip32" version = "0.0.0" authors = [ - "Jack Grigg ", + "Jack Grigg ", + "Kris Nuttycombe ", ] -license = "MIT/Apache-2.0" - description = "Library for implementing shielded hierarchical deterministic wallets" documentation = "https://docs.rs/zip32/" homepage = "https://github.com/zcash-hackworks/zip32" repository = "https://github.com/zcash-hackworks/zip32" +license = "MIT OR Apache-2.0" +edition = "2021" +rust-version = "1.65" [dependencies] -aes = "0.2" -byteorder = "1" -fpe = "0.1" -lazy_static = "1.0" -pairing = "0.14.2" +blake2b_simd = "1" +memuse = "0.2.1" +subtle = "2.2.3" -[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" +[dev-dependencies] +assert_matches = "1.5" diff --git a/src/fingerprint.rs b/src/fingerprint.rs new file mode 100644 index 0000000..8c4cffb --- /dev/null +++ b/src/fingerprint.rs @@ -0,0 +1,80 @@ +//! Seed Fingerprints according to ZIP 32 +//! +//! Implements section `Seed Fingerprints` of Shielded Hierarchical Deterministic Wallets (ZIP 32) +//! +//! [Section Seed Fingerprints]: https://zips.z.cash/zip-0032#seed-fingerprints +use blake2b_simd::Params as Blake2bParams; + +pub const ZIP32_SEED_FP_PERSONALIZATION: &[u8; 16] = b"Zcash_HD_Seed_FP"; +pub struct SeedFingerprint([u8; 32]); + +impl SeedFingerprint { + /// Return the seed fingerprint of the wallet as defined in + /// or None + /// if the length of `seed_bytes` is less than 32 or + /// greater than 252. + pub fn from_seed(seed_bytes: &[u8]) -> Option { + let seed_len = seed_bytes.len(); + + if (32..=252).contains(&seed_len) { + let seed_len: u8 = seed_len.try_into().unwrap(); + Some(SeedFingerprint( + Blake2bParams::new() + .hash_length(32) + .personal(ZIP32_SEED_FP_PERSONALIZATION) + .to_state() + .update(&[seed_len]) + .update(seed_bytes) + .finalize() + .as_bytes() + .try_into() + .expect("hash length should be 32 bytes"), + )) + } else { + None + } + } + + /// Returns the fingerprint as a byte array. + pub fn to_bytes(&self) -> [u8; 32] { + self.0 + } +} + +#[test] +fn test_seed_fingerprint() { + struct TestVector { + root_seed: Vec, + fingerprint: Vec, + } + + let test_vectors = vec![TestVector { + root_seed: vec![ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, + 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, + ], + fingerprint: vec![ + 0xde, 0xff, 0x60, 0x4c, 0x24, 0x67, 0x10, 0xf7, 0x17, 0x6d, 0xea, 0xd0, 0x2a, 0xa7, + 0x46, 0xf2, 0xfd, 0x8d, 0x53, 0x89, 0xf7, 0x7, 0x25, 0x56, 0xdc, 0xb5, 0x55, 0xfd, + 0xbe, 0x5e, 0x3a, 0xe3, + ], + }]; + + for tv in test_vectors { + let fp = SeedFingerprint::from_seed(&tv.root_seed).expect("root_seed has valid length"); + assert_eq!(&fp.to_bytes(), &tv.fingerprint[..]); + } +} +#[test] +fn test_seed_fingerprint_is_none() { + let odd_seed = vec![ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, + ]; + + assert!( + SeedFingerprint::from_seed(&odd_seed).is_none(), + "fingerprint from short seed should be `None`" + ); +} diff --git a/src/lib.rs b/src/lib.rs index 70173ea..a130b6b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,279 +1,132 @@ -extern crate aes; -extern crate blake2_rfc; -extern crate byteorder; -extern crate fpe; -#[macro_use] -extern crate lazy_static; -extern crate pairing; -extern crate sapling_crypto; +//! Implementation of [ZIP 32] for hierarchical deterministic key management. +//! +//! [ZIP 32]: https://zips.z.cash/zip-0032 -use aes::Aes256; -use blake2_rfc::blake2b::{Blake2b, Blake2bResult}; -use byteorder::{ByteOrder, LittleEndian, ReadBytesExt, WriteBytesExt}; -use fpe::ff1::{BinaryNumeralString, FF1}; -use pairing::{bls12_381::Bls12, Field, PrimeField, PrimeFieldRepr}; -use sapling_crypto::{ - jubjub::{ - edwards, FixedGenerators, JubjubBls12, JubjubEngine, JubjubParams, ToUniform, Unknown, - }, - primitives::{Diversifier, PaymentAddress, ViewingKey}, -}; -use std::io::{self, Read, Write}; +use memuse::{self, DynamicUsage}; +use subtle::{Choice, ConditionallySelectable}; -lazy_static! { - static ref JUBJUB: JubjubBls12 = { JubjubBls12::new() }; -} +pub mod fingerprint; -pub const PRF_EXPAND_PERSONALIZATION: &'static [u8; 16] = b"Zcash_ExpandSeed"; -pub const ZIP32_SAPLING_MASTER_PERSONALIZATION: &'static [u8; 16] = b"ZcashIP32Sapling"; -pub const ZIP32_SAPLING_FVFP_PERSONALIZATION: &'static [u8; 16] = b"ZcashSaplingFVFP"; +/// A type-safe wrapper for account identifiers. +#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct AccountId(u32); -// Sapling key components +memuse::impl_no_dynamic_usage!(AccountId); -/// PRF^expand(sk, t) := BLAKE2b-512("Zcash_ExpandSeed", sk || t) -fn prf_expand(sk: &[u8], t: &[u8]) -> Blake2bResult { - prf_expand_vec(sk, &vec![t]) -} - -fn prf_expand_vec(sk: &[u8], ts: &[&[u8]]) -> Blake2bResult { - let mut h = Blake2b::with_params(64, &[], &[], PRF_EXPAND_PERSONALIZATION); - h.update(sk); - for t in ts { - h.update(t); - } - h.finalize() -} - -/// An outgoing viewing key -#[derive(Clone, Copy, PartialEq)] -struct OutgoingViewingKey([u8; 32]); - -impl OutgoingViewingKey { - fn derive_child(&self, i_l: &[u8]) -> Self { - let mut ovk = [0u8; 32]; - ovk.copy_from_slice(&prf_expand_vec(i_l, &[&[0x15], &self.0]).as_bytes()[..32]); - OutgoingViewingKey(ovk) +impl From for AccountId { + fn from(id: u32) -> Self { + Self(id) } } -/// A Sapling expanded spending key -#[derive(Clone)] -pub struct ExpandedSpendingKey { - ask: E::Fs, - nsk: E::Fs, - ovk: OutgoingViewingKey, -} - -/// A Sapling full viewing key -pub struct FullViewingKey { - vk: ViewingKey, - 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 } - } - - fn derive_child(&self, i_l: &[u8]) -> Self { - let mut ask = E::Fs::to_uniform(prf_expand(i_l, &[0x13]).as_bytes()); - let mut nsk = E::Fs::to_uniform(prf_expand(i_l, &[0x14]).as_bytes()); - ask.add_assign(&self.ask); - nsk.add_assign(&self.nsk); - let ovk = self.ovk.derive_child(i_l); - ExpandedSpendingKey { ask, nsk, ovk } - } - - pub fn read(mut reader: R) -> io::Result { - let mut ask_repr = ::Repr::default(); - ask_repr.read_le(&mut reader)?; - let ask = - E::Fs::from_repr(ask_repr).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; - - let mut nsk_repr = ::Repr::default(); - nsk_repr.read_le(&mut reader)?; - let nsk = - E::Fs::from_repr(nsk_repr).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; - - let mut ovk = [0; 32]; - reader.read_exact(&mut ovk)?; - - Ok(ExpandedSpendingKey { - ask, - nsk, - ovk: OutgoingViewingKey(ovk), - }) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - self.ask.into_repr().write_le(&mut writer)?; - self.nsk.into_repr().write_le(&mut writer)?; - writer.write_all(&self.ovk.0)?; - - Ok(()) - } - - fn to_bytes(&self) -> [u8; 96] { - let mut result = [0u8; 96]; - self.write(&mut result[..]) - .expect("should be able to serialize an ExpandedSpendingKey"); - result +impl From for u32 { + fn from(id: AccountId) -> Self { + id.0 } } -impl FullViewingKey { - fn from_expanded_spending_key(expsk: &ExpandedSpendingKey, params: &E::Params) -> Self { - FullViewingKey { - vk: ViewingKey { - ak: params - .generator(FixedGenerators::SpendingKeyGenerator) - .mul(expsk.ask, params), - nk: params - .generator(FixedGenerators::ProofGenerationKey) - .mul(expsk.nsk, params), - }, - ovk: expsk.ovk, - } +impl From for ChildIndex { + fn from(id: AccountId) -> Self { + // Account IDs are always hardened in derivation paths. + ChildIndex::hardened(id.0) } +} - fn derive_child(&self, i_l: &[u8], params: &E::Params) -> Self { - let i_ask = E::Fs::to_uniform(prf_expand(i_l, &[0x13]).as_bytes()); - let i_nsk = E::Fs::to_uniform(prf_expand(i_l, &[0x14]).as_bytes()); - let ak = params - .generator(FixedGenerators::SpendingKeyGenerator) - .mul(i_ask, params) - .add(&self.vk.ak, params); - let nk = params - .generator(FixedGenerators::ProofGenerationKey) - .mul(i_nsk, params) - .add(&self.vk.nk, params); - - FullViewingKey { - vk: ViewingKey { ak, nk }, - ovk: self.ovk.derive_child(i_l), - } - } - - pub fn read(mut reader: R, params: &E::Params) -> io::Result { - let ak = edwards::Point::::read(&mut reader, params)?; - let ak = match ak.as_prime_order(params) { - Some(p) => p, - None => { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - "ak not of prime order", - )) - } - }; - - let nk = edwards::Point::::read(&mut reader, params)?; - let nk = match nk.as_prime_order(params) { - Some(p) => p, - None => { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - "nk not of prime order", - )) - } - }; - - let mut ovk = [0; 32]; - reader.read_exact(&mut ovk)?; - - Ok(FullViewingKey { - vk: ViewingKey { ak, nk }, - ovk: OutgoingViewingKey(ovk), - }) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - self.vk.ak.write(&mut writer)?; - self.vk.nk.write(&mut writer)?; - writer.write_all(&self.ovk.0)?; - - Ok(()) - } - - fn to_bytes(&self) -> [u8; 96] { - let mut result = [0u8; 96]; - self.write(&mut result[..]) - .expect("should be able to serialize a FullViewingKey"); - result - } - - fn fingerprint(&self) -> FVKFingerprint { - let mut h = Blake2b::with_params(32, &[], &[], ZIP32_SAPLING_FVFP_PERSONALIZATION); - h.update(&self.to_bytes()); - let mut fvfp = [0u8; 32]; - fvfp.copy_from_slice(h.finalize().as_bytes()); - FVKFingerprint(fvfp) +impl ConditionallySelectable for AccountId { + fn conditional_select(a0: &Self, a1: &Self, c: Choice) -> Self { + AccountId(u32::conditional_select(&a0.0, &a1.0, c)) } } // ZIP 32 structures -/// A Sapling full viewing key fingerprint -struct FVKFingerprint([u8; 32]); - -/// A Sapling full viewing key tag -#[derive(Clone, Copy, Debug, PartialEq)] -struct FVKTag([u8; 4]); - -impl FVKFingerprint { - fn tag(&self) -> FVKTag { - let mut tag = [0u8; 4]; - tag.copy_from_slice(&self.0[..4]); - FVKTag(tag) - } -} - -impl FVKTag { - fn master() -> Self { - FVKTag([0u8; 4]) - } -} - -/// A child index for a derived key -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum ChildIndex { - NonHardened(u32), - Hardened(u32), // Hardened(n) == n + (1 << 31) == n' in path notation -} +/// A child index for a derived key. +/// +/// Only hardened derivation is supported. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct ChildIndex(u32); impl ChildIndex { - pub fn from_index(i: u32) -> Self { - match i { - n if n >= (1 << 31) => ChildIndex::Hardened(n - (1 << 31)), - n => ChildIndex::NonHardened(n), + /// Parses the given ZIP 32 child index. + /// + /// Returns `None` if the hardened bit is not set. + pub fn from_index(i: u32) -> Option { + if i >= (1 << 31) { + Some(ChildIndex(i)) + } else { + None } } - fn master() -> Self { - ChildIndex::from_index(0) + /// Constructs a hardened `ChildIndex` from the given value. + /// + /// # Panics + /// + /// Panics if `value >= (1 << 31)`. + pub const fn hardened(value: u32) -> Self { + assert!(value < (1 << 31)); + Self(value + (1 << 31)) } - fn to_index(&self) -> u32 { - match self { - &ChildIndex::Hardened(i) => i + (1 << 31), - &ChildIndex::NonHardened(i) => i, - } + /// Returns the index as a 32-bit integer, including the hardened bit. + pub fn index(&self) -> u32 { + self.0 } } -/// A chain code -#[derive(Clone, Copy, Debug, PartialEq)] -struct ChainCode([u8; 32]); +/// A value that is needed, in addition to a spending key, in order to derive descendant +/// keys and addresses of that key. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct ChainCode([u8; 32]); -#[derive(Clone, Copy, Debug, PartialEq)] +impl ChainCode { + /// Constructs a `ChainCode` from the given array. + pub fn new(c: [u8; 32]) -> Self { + Self(c) + } + + /// Returns the byte representation of the chain code, as required for + /// [ZIP 32](https://zips.z.cash/zip-0032) encoding. + pub fn as_bytes(&self) -> &[u8; 32] { + &self.0 + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct DiversifierIndex(pub [u8; 11]); +impl Default for DiversifierIndex { + fn default() -> Self { + DiversifierIndex::new() + } +} + +impl From for DiversifierIndex { + fn from(i: u32) -> Self { + u64::from(i).into() + } +} + +impl From for DiversifierIndex { + fn from(i: u64) -> Self { + let mut result = DiversifierIndex([0; 11]); + result.0[..8].copy_from_slice(&i.to_le_bytes()); + result + } +} + +impl TryFrom for u32 { + type Error = std::num::TryFromIntError; + + fn try_from(di: DiversifierIndex) -> Result { + let mut u128_bytes = [0u8; 16]; + u128_bytes[0..11].copy_from_slice(&di.0[..]); + u128::from_le_bytes(u128_bytes).try_into() + } +} + impl DiversifierIndex { - fn new() -> Self { + pub fn new() -> Self { DiversifierIndex([0; 11]) } @@ -290,942 +143,48 @@ impl DiversifierIndex { } } -/// A key used to derive diversifiers for a particular child key -#[derive(Clone, Copy, Debug, PartialEq)] -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) - } - - 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]); - 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::::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::(&JUBJUB) { - Some(_) => return Ok((j, d_j)), - None => if j.increment().is_err() { - return Err(()); - }, - } - } - } +/// The scope of a viewing key or address. +/// +/// A "scope" narrows the visibility or usage to a level below "full". +/// +/// Consistent usage of `Scope` enables the user to provide consistent views over a wallet +/// to other people. For example, a user can give an external [SaplingIvk] to a merchant +/// terminal, enabling it to only detect "real" transactions from customers and not +/// internal transactions from the wallet. +/// +/// [SaplingIvk]: crate::sapling::SaplingIvk +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum Scope { + /// A scope used for wallet-external operations, namely deriving addresses to give to + /// other users in order to receive funds. + External, + /// A scope used for wallet-internal operations, such as creating change notes, + /// auto-shielding, and note management. + Internal, } -/// A Sapling extended spending key -#[derive(Clone)] -pub struct ExtendedSpendingKey { - depth: u8, - parent_fvk_tag: FVKTag, - child_index: ChildIndex, - chain_code: ChainCode, - pub expsk: ExpandedSpendingKey, - dk: DiversifierKey, -} - -// A Sapling extended full viewing key -pub struct ExtendedFullViewingKey { - depth: u8, - parent_fvk_tag: FVKTag, - child_index: ChildIndex, - chain_code: ChainCode, - pub fvk: FullViewingKey, - dk: DiversifierKey, -} - -impl std::cmp::PartialEq for ExtendedSpendingKey { - fn eq(&self, rhs: &ExtendedSpendingKey) -> bool { - self.depth == rhs.depth - && self.parent_fvk_tag == rhs.parent_fvk_tag - && self.child_index == rhs.child_index - && self.chain_code == rhs.chain_code - && self.expsk.ask == rhs.expsk.ask - && self.expsk.nsk == rhs.expsk.nsk - && self.expsk.ovk == rhs.expsk.ovk - && self.dk == rhs.dk - } -} - -impl std::fmt::Debug for ExtendedSpendingKey { - fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { - write!( - f, - "ExtendedSpendingKey(d = {}, tag_p = {:?}, i = {:?})", - self.depth, self.parent_fvk_tag, self.child_index - ) - } -} - -impl std::cmp::PartialEq for ExtendedFullViewingKey { - fn eq(&self, rhs: &ExtendedFullViewingKey) -> bool { - self.depth == rhs.depth - && self.parent_fvk_tag == rhs.parent_fvk_tag - && self.child_index == rhs.child_index - && self.chain_code == rhs.chain_code - && self.fvk.vk.ak == rhs.fvk.vk.ak - && self.fvk.vk.nk == rhs.fvk.vk.nk - && self.fvk.ovk == rhs.fvk.ovk - && self.dk == rhs.dk - } -} - -impl std::fmt::Debug for ExtendedFullViewingKey { - fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { - write!( - f, - "ExtendedFullViewingKey(d = {}, tag_p = {:?}, i = {:?})", - self.depth, self.parent_fvk_tag, self.child_index - ) - } -} - -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), - expsk: ExpandedSpendingKey::from_spending_key(sk_m), - dk: DiversifierKey::master(sk_m), - } - } - - pub fn read(mut reader: R) -> io::Result { - let depth = reader.read_u8()?; - let mut tag = [0; 4]; - reader.read_exact(&mut tag)?; - let i = reader.read_u32::()?; - let mut c = [0; 32]; - reader.read_exact(&mut c)?; - let expsk = ExpandedSpendingKey::read(&mut reader)?; - let mut dk = [0; 32]; - reader.read_exact(&mut dk)?; - - Ok(ExtendedSpendingKey { - depth, - parent_fvk_tag: FVKTag(tag), - child_index: ChildIndex::from_index(i), - chain_code: ChainCode(c), - expsk, - dk: DiversifierKey(dk), - }) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - writer.write_u8(self.depth)?; - writer.write_all(&self.parent_fvk_tag.0)?; - writer.write_u32::(self.child_index.to_index())?; - writer.write_all(&self.chain_code.0)?; - writer.write_all(&self.expsk.to_bytes())?; - writer.write_all(&self.dk.0)?; - - Ok(()) - } - - /// Returns the child key corresponding to the path derived from the master key - pub fn from_path(master: &ExtendedSpendingKey, path: &[ChildIndex]) -> Self { - let mut xsk = master.clone(); - for &i in path.iter() { - xsk = xsk.derive_child(i); - } - xsk - } - - pub fn derive_child(&self, i: ChildIndex) -> Self { - let fvk = FullViewingKey::from_expanded_spending_key(&self.expsk, &JUBJUB); - let tmp = match i { - ChildIndex::Hardened(i) => { - let mut le_i = [0; 4]; - LittleEndian::write_u32(&mut le_i, i + (1 << 31)); - prf_expand_vec( - &self.chain_code.0, - &[&[0x11], &self.expsk.to_bytes(), &self.dk.0, &le_i], - ) - } - ChildIndex::NonHardened(i) => { - let mut le_i = [0; 4]; - LittleEndian::write_u32(&mut le_i, i); - prf_expand_vec( - &self.chain_code.0, - &[&[0x12], &fvk.to_bytes(), &self.dk.0, &le_i], - ) - } - }; - let i_l = &tmp.as_bytes()[..32]; - let mut c_i = [0u8; 32]; - c_i.copy_from_slice(&tmp.as_bytes()[32..]); - - ExtendedSpendingKey { - depth: self.depth + 1, - parent_fvk_tag: fvk.fingerprint().tag(), - child_index: i, - chain_code: ChainCode(c_i), - expsk: self.expsk.derive_child(i_l), - dk: self.dk.derive_child(i_l), - } - } - - pub fn default_address(&self) -> Result<(DiversifierIndex, PaymentAddress), ()> { - ExtendedFullViewingKey::from(self).default_address() - } -} - -impl<'a> From<&'a ExtendedSpendingKey> for ExtendedFullViewingKey { - fn from(xsk: &ExtendedSpendingKey) -> Self { - ExtendedFullViewingKey { - depth: xsk.depth, - parent_fvk_tag: xsk.parent_fvk_tag, - child_index: xsk.child_index, - chain_code: xsk.chain_code, - fvk: FullViewingKey::from_expanded_spending_key(&xsk.expsk, &JUBJUB), - dk: xsk.dk, - } - } -} - -impl ExtendedFullViewingKey { - pub fn read(mut reader: R) -> io::Result { - let depth = reader.read_u8()?; - let mut tag = [0; 4]; - reader.read_exact(&mut tag)?; - let i = reader.read_u32::()?; - let mut c = [0; 32]; - reader.read_exact(&mut c)?; - let fvk = FullViewingKey::read(&mut reader, &*JUBJUB)?; - let mut dk = [0; 32]; - reader.read_exact(&mut dk)?; - - Ok(ExtendedFullViewingKey { - depth, - parent_fvk_tag: FVKTag(tag), - child_index: ChildIndex::from_index(i), - chain_code: ChainCode(c), - fvk, - dk: DiversifierKey(dk), - }) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - writer.write_u8(self.depth)?; - writer.write_all(&self.parent_fvk_tag.0)?; - writer.write_u32::(self.child_index.to_index())?; - writer.write_all(&self.chain_code.0)?; - writer.write_all(&self.fvk.to_bytes())?; - writer.write_all(&self.dk.0)?; - - Ok(()) - } - - pub fn derive_child(&self, i: ChildIndex) -> Result { - let tmp = match i { - ChildIndex::Hardened(_) => return Err(()), - ChildIndex::NonHardened(i) => { - let mut le_i = [0; 4]; - LittleEndian::write_u32(&mut le_i, i); - prf_expand_vec( - &self.chain_code.0, - &[&[0x12], &self.fvk.to_bytes(), &self.dk.0, &le_i], - ) - } - }; - let i_l = &tmp.as_bytes()[..32]; - let mut c_i = [0u8; 32]; - c_i.copy_from_slice(&tmp.as_bytes()[32..]); - - Ok(ExtendedFullViewingKey { - depth: self.depth + 1, - parent_fvk_tag: self.fvk.fingerprint().tag(), - child_index: i, - chain_code: ChainCode(c_i), - fvk: self.fvk.derive_child(i_l, &JUBJUB), - dk: self.dk.derive_child(i_l), - }) - } - - pub fn address( - &self, - j: DiversifierIndex, - ) -> Result<(DiversifierIndex, PaymentAddress), ()> { - let (j, d_j) = match self.dk.diversifier(j) { - Ok(ret) => ret, - Err(()) => return Err(()), - }; - match self.fvk.vk.into_payment_address(d_j, &JUBJUB) { - Some(addr) => Ok((j, addr)), - None => Err(()), - } - } - - pub fn default_address(&self) -> Result<(DiversifierIndex, PaymentAddress), ()> { - self.address(DiversifierIndex::new()) - } -} +memuse::impl_no_dynamic_usage!(Scope); #[cfg(test)] mod tests { - use super::*; + use super::DiversifierIndex; + use assert_matches::assert_matches; #[test] - fn derive_nonhardened_child() { - let seed = [0; 32]; - let xsk_m = ExtendedSpendingKey::master(&seed); - let xfvk_m = ExtendedFullViewingKey::from(&xsk_m); + fn diversifier_index_to_u32() { + let two = DiversifierIndex([ + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ]); + assert_eq!(u32::try_from(two), Ok(2)); - let i_5 = ChildIndex::NonHardened(5); - let xsk_5 = xsk_m.derive_child(i_5); - let xfvk_5 = xfvk_m.derive_child(i_5); + let max_u32 = DiversifierIndex([ + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ]); + assert_eq!(u32::try_from(max_u32), Ok(u32::MAX)); - assert!(xfvk_5.is_ok()); - assert_eq!(ExtendedFullViewingKey::from(&xsk_5), xfvk_5.unwrap()); - } - - #[test] - fn derive_hardened_child() { - let seed = [0; 32]; - let xsk_m = ExtendedSpendingKey::master(&seed); - let xfvk_m = ExtendedFullViewingKey::from(&xsk_m); - - let i_5h = ChildIndex::Hardened(5); - let xsk_5h = xsk_m.derive_child(i_5h); - let xfvk_5h = xfvk_m.derive_child(i_5h); - - // Cannot derive a hardened child from an ExtendedFullViewingKey - assert!(xfvk_5h.is_err()); - let xfvk_5h = ExtendedFullViewingKey::from(&xsk_5h); - - let i_7 = ChildIndex::NonHardened(7); - let xsk_5h_7 = xsk_5h.derive_child(i_7); - let xfvk_5h_7 = xfvk_5h.derive_child(i_7); - - // But we *can* derive a non-hardened child from a hardened parent - assert!(xfvk_5h_7.is_ok()); - assert_eq!(ExtendedFullViewingKey::from(&xsk_5h_7), xfvk_5h_7.unwrap()); - } - - #[test] - fn path() { - let seed = [0; 32]; - let xsk_m = ExtendedSpendingKey::master(&seed); - - let xsk_5h = xsk_m.derive_child(ChildIndex::Hardened(5)); - assert_eq!( - ExtendedSpendingKey::from_path(&xsk_m, &[ChildIndex::Hardened(5)]), - xsk_5h - ); - - let xsk_5h_7 = xsk_5h.derive_child(ChildIndex::NonHardened(7)); - assert_eq!( - ExtendedSpendingKey::from_path( - &xsk_m, - &[ChildIndex::Hardened(5), ChildIndex::NonHardened(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); - } - - #[test] - fn default_address() { - let seed = [0; 32]; - let xsk_m = ExtendedSpendingKey::master(&seed); - let (j_m, addr_m) = xsk_m.default_address().unwrap(); - assert_eq!(j_m.0, [0; 11]); - assert_eq!( - addr_m.diversifier.0, - // Computed using this Rust implementation - [59, 246, 250, 31, 131, 191, 69, 99, 200, 167, 19] - ); - } - - #[test] - fn read_write() { - let seed = [0; 32]; - let xsk = ExtendedSpendingKey::master(&seed); - let fvk = ExtendedFullViewingKey::from(&xsk); - - let mut ser = vec![]; - xsk.write(&mut ser).unwrap(); - let xsk2 = ExtendedSpendingKey::read(&ser[..]).unwrap(); - assert_eq!(xsk2, xsk); - - let mut ser = vec![]; - fvk.write(&mut ser).unwrap(); - let fvk2 = ExtendedFullViewingKey::read(&ser[..]).unwrap(); - assert_eq!(fvk2, fvk); - } - - #[test] - fn test_vectors() { - struct TestVector { - ask: Option<[u8; 32]>, - nsk: Option<[u8; 32]>, - ovk: [u8; 32], - dk: [u8; 32], - c: [u8; 32], - ak: [u8; 32], - nk: [u8; 32], - ivk: [u8; 32], - xsk: Option<[u8; 169]>, - xfvk: [u8; 169], - fp: [u8; 32], - d0: Option<[u8; 11]>, - d1: Option<[u8; 11]>, - d2: Option<[u8; 11]>, - dmax: Option<[u8; 11]>, - }; - - // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_zip32.py - let test_vectors = vec![ - TestVector { - ask: Some([ - 0xb6, 0xc0, 0x0c, 0x93, 0xd3, 0x60, 0x32, 0xb9, 0xa2, 0x68, 0xe9, 0x9e, 0x86, - 0xa8, 0x60, 0x77, 0x65, 0x60, 0xbf, 0x0e, 0x83, 0xc1, 0xa1, 0x0b, 0x51, 0xf6, - 0x07, 0xc9, 0x54, 0x74, 0x25, 0x06, - ]), - nsk: Some([ - 0x82, 0x04, 0xed, 0xe8, 0x3b, 0x2f, 0x1f, 0xbd, 0x84, 0xf9, 0xb4, 0x5d, 0x7f, - 0x99, 0x6e, 0x2e, 0xbd, 0x0a, 0x03, 0x0a, 0xd2, 0x43, 0xb4, 0x8e, 0xd3, 0x9f, - 0x74, 0x8a, 0x88, 0x21, 0xea, 0x06, - ]), - ovk: [ - 0x39, 0x58, 0x84, 0x89, 0x03, 0x23, 0xb9, 0xd4, 0x93, 0x3c, 0x02, 0x1d, 0xb8, - 0x9b, 0xcf, 0x76, 0x7d, 0xf2, 0x19, 0x77, 0xb2, 0xff, 0x06, 0x83, 0x84, 0x83, - 0x21, 0xa4, 0xdf, 0x4a, 0xfb, 0x21, - ], - dk: [ - 0x77, 0xc1, 0x7c, 0xb7, 0x5b, 0x77, 0x96, 0xaf, 0xb3, 0x9f, 0x0f, 0x3e, 0x91, - 0xc9, 0x24, 0x60, 0x7d, 0xa5, 0x6f, 0xa9, 0xa2, 0x0e, 0x28, 0x35, 0x09, 0xbc, - 0x8a, 0x3e, 0xf9, 0x96, 0xa1, 0x72, - ], - c: [ - 0xd0, 0x94, 0x7c, 0x4b, 0x03, 0xbf, 0x72, 0xa3, 0x7a, 0xb4, 0x4f, 0x72, 0x27, - 0x6d, 0x1c, 0xf3, 0xfd, 0xcd, 0x7e, 0xbf, 0x3e, 0x73, 0x34, 0x8b, 0x7e, 0x55, - 0x0d, 0x75, 0x20, 0x18, 0x66, 0x8e, - ], - ak: [ - 0x93, 0x44, 0x2e, 0x5f, 0xef, 0xfb, 0xff, 0x16, 0xe7, 0x21, 0x72, 0x02, 0xdc, - 0x73, 0x06, 0x72, 0x9f, 0xff, 0xfe, 0x85, 0xaf, 0x56, 0x83, 0xbc, 0xe2, 0x64, - 0x2e, 0x3e, 0xeb, 0x5d, 0x38, 0x71, - ], - nk: [ - 0xdc, 0xe8, 0xe7, 0xed, 0xec, 0xe0, 0x4b, 0x89, 0x50, 0x41, 0x7f, 0x85, 0xba, - 0x57, 0x69, 0x1b, 0x78, 0x3c, 0x45, 0xb1, 0xa2, 0x74, 0x22, 0xdb, 0x16, 0x93, - 0xdc, 0xeb, 0x67, 0xb1, 0x01, 0x06, - ], - ivk: [ - 0x48, 0x47, 0xa1, 0x30, 0xe7, 0x99, 0xd3, 0xdb, 0xea, 0x36, 0xa1, 0xc1, 0x64, - 0x67, 0xd6, 0x21, 0xfb, 0x2d, 0x80, 0xe3, 0x0b, 0x3b, 0x1d, 0x1a, 0x42, 0x68, - 0x93, 0x41, 0x5d, 0xad, 0x66, 0x01, - ], - xsk: Some([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x94, 0x7c, 0x4b, - 0x03, 0xbf, 0x72, 0xa3, 0x7a, 0xb4, 0x4f, 0x72, 0x27, 0x6d, 0x1c, 0xf3, 0xfd, - 0xcd, 0x7e, 0xbf, 0x3e, 0x73, 0x34, 0x8b, 0x7e, 0x55, 0x0d, 0x75, 0x20, 0x18, - 0x66, 0x8e, 0xb6, 0xc0, 0x0c, 0x93, 0xd3, 0x60, 0x32, 0xb9, 0xa2, 0x68, 0xe9, - 0x9e, 0x86, 0xa8, 0x60, 0x77, 0x65, 0x60, 0xbf, 0x0e, 0x83, 0xc1, 0xa1, 0x0b, - 0x51, 0xf6, 0x07, 0xc9, 0x54, 0x74, 0x25, 0x06, 0x82, 0x04, 0xed, 0xe8, 0x3b, - 0x2f, 0x1f, 0xbd, 0x84, 0xf9, 0xb4, 0x5d, 0x7f, 0x99, 0x6e, 0x2e, 0xbd, 0x0a, - 0x03, 0x0a, 0xd2, 0x43, 0xb4, 0x8e, 0xd3, 0x9f, 0x74, 0x8a, 0x88, 0x21, 0xea, - 0x06, 0x39, 0x58, 0x84, 0x89, 0x03, 0x23, 0xb9, 0xd4, 0x93, 0x3c, 0x02, 0x1d, - 0xb8, 0x9b, 0xcf, 0x76, 0x7d, 0xf2, 0x19, 0x77, 0xb2, 0xff, 0x06, 0x83, 0x84, - 0x83, 0x21, 0xa4, 0xdf, 0x4a, 0xfb, 0x21, 0x77, 0xc1, 0x7c, 0xb7, 0x5b, 0x77, - 0x96, 0xaf, 0xb3, 0x9f, 0x0f, 0x3e, 0x91, 0xc9, 0x24, 0x60, 0x7d, 0xa5, 0x6f, - 0xa9, 0xa2, 0x0e, 0x28, 0x35, 0x09, 0xbc, 0x8a, 0x3e, 0xf9, 0x96, 0xa1, 0x72, - ]), - xfvk: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x94, 0x7c, 0x4b, - 0x03, 0xbf, 0x72, 0xa3, 0x7a, 0xb4, 0x4f, 0x72, 0x27, 0x6d, 0x1c, 0xf3, 0xfd, - 0xcd, 0x7e, 0xbf, 0x3e, 0x73, 0x34, 0x8b, 0x7e, 0x55, 0x0d, 0x75, 0x20, 0x18, - 0x66, 0x8e, 0x93, 0x44, 0x2e, 0x5f, 0xef, 0xfb, 0xff, 0x16, 0xe7, 0x21, 0x72, - 0x02, 0xdc, 0x73, 0x06, 0x72, 0x9f, 0xff, 0xfe, 0x85, 0xaf, 0x56, 0x83, 0xbc, - 0xe2, 0x64, 0x2e, 0x3e, 0xeb, 0x5d, 0x38, 0x71, 0xdc, 0xe8, 0xe7, 0xed, 0xec, - 0xe0, 0x4b, 0x89, 0x50, 0x41, 0x7f, 0x85, 0xba, 0x57, 0x69, 0x1b, 0x78, 0x3c, - 0x45, 0xb1, 0xa2, 0x74, 0x22, 0xdb, 0x16, 0x93, 0xdc, 0xeb, 0x67, 0xb1, 0x01, - 0x06, 0x39, 0x58, 0x84, 0x89, 0x03, 0x23, 0xb9, 0xd4, 0x93, 0x3c, 0x02, 0x1d, - 0xb8, 0x9b, 0xcf, 0x76, 0x7d, 0xf2, 0x19, 0x77, 0xb2, 0xff, 0x06, 0x83, 0x84, - 0x83, 0x21, 0xa4, 0xdf, 0x4a, 0xfb, 0x21, 0x77, 0xc1, 0x7c, 0xb7, 0x5b, 0x77, - 0x96, 0xaf, 0xb3, 0x9f, 0x0f, 0x3e, 0x91, 0xc9, 0x24, 0x60, 0x7d, 0xa5, 0x6f, - 0xa9, 0xa2, 0x0e, 0x28, 0x35, 0x09, 0xbc, 0x8a, 0x3e, 0xf9, 0x96, 0xa1, 0x72, - ], - fp: [ - 0x14, 0xc2, 0x71, 0x3a, 0xdc, 0xe9, 0x3a, 0x83, 0x0e, 0xa8, 0x3a, 0x05, 0x19, - 0x08, 0xb7, 0x44, 0x77, 0x83, 0xf5, 0xd1, 0x06, 0xc0, 0x98, 0x5e, 0x02, 0x55, - 0x0e, 0x42, 0x6f, 0x27, 0x59, 0x7c, - ], - d0: Some([ - 0xd8, 0x62, 0x1b, 0x98, 0x1c, 0xf3, 0x00, 0xe9, 0xd4, 0xcc, 0x89, - ]), - d1: Some([ - 0x48, 0xea, 0x17, 0xa1, 0x99, 0xc8, 0x4b, 0xd1, 0xba, 0xa5, 0xd4, - ]), - d2: None, - dmax: None, - }, - TestVector { - ask: Some([ - 0x28, 0x2b, 0xc1, 0x97, 0xa5, 0x16, 0x28, 0x7c, 0x8e, 0xa8, 0xf6, 0x8c, 0x42, - 0x4a, 0xba, 0xd3, 0x02, 0xb4, 0x5c, 0xdf, 0x95, 0x40, 0x79, 0x61, 0xd7, 0xb8, - 0xb4, 0x55, 0x26, 0x7a, 0x35, 0x0c, - ]), - nsk: Some([ - 0xe7, 0xa3, 0x29, 0x88, 0xfd, 0xca, 0x1e, 0xfc, 0xd6, 0xd1, 0xc4, 0xc5, 0x62, - 0xe6, 0x29, 0xc2, 0xe9, 0x6b, 0x2c, 0x3f, 0x7e, 0xda, 0x04, 0xac, 0x4e, 0xfd, - 0x18, 0x10, 0xff, 0x6b, 0xba, 0x01, - ]), - ovk: [ - 0x5f, 0x13, 0x81, 0xfc, 0x88, 0x86, 0xda, 0x6a, 0x02, 0xdf, 0xfe, 0xef, 0xcf, - 0x50, 0x3c, 0x40, 0xfa, 0x8f, 0x5a, 0x36, 0xf7, 0xa7, 0x14, 0x2f, 0xd8, 0x1b, - 0x55, 0x18, 0xc5, 0xa4, 0x74, 0x74, - ], - dk: [ - 0xe0, 0x4d, 0xe8, 0x32, 0xa2, 0xd7, 0x91, 0xec, 0x12, 0x9a, 0xb9, 0x00, 0x2b, - 0x91, 0xc9, 0xe9, 0xcd, 0xee, 0xd7, 0x92, 0x41, 0xa7, 0xc4, 0x96, 0x0e, 0x51, - 0x78, 0xd8, 0x70, 0xc1, 0xb4, 0xdc, - ], - c: [ - 0x01, 0x47, 0x11, 0x0c, 0x69, 0x1a, 0x03, 0xb9, 0xd9, 0xf0, 0xba, 0x90, 0x05, - 0xc5, 0xe7, 0x90, 0xa5, 0x95, 0xb7, 0xf0, 0x4e, 0x33, 0x29, 0xd2, 0xfa, 0x43, - 0x8a, 0x67, 0x05, 0xda, 0xbc, 0xe6, - ], - ak: [ - 0xdc, 0x14, 0xb5, 0x14, 0xd3, 0xa9, 0x25, 0x94, 0xc2, 0x19, 0x25, 0xaf, 0x2f, - 0x77, 0x65, 0xa5, 0x47, 0xb3, 0x0e, 0x73, 0xfa, 0x7b, 0x70, 0x0e, 0xa1, 0xbf, - 0xf2, 0xe5, 0xef, 0xaa, 0xa8, 0x8b, - ], - nk: [ - 0x61, 0x52, 0xeb, 0x7f, 0xdb, 0x25, 0x27, 0x79, 0xdd, 0xcb, 0x95, 0xd2, 0x17, - 0xea, 0x4b, 0x6f, 0xd3, 0x40, 0x36, 0xe9, 0xad, 0xad, 0xb3, 0xb5, 0xc9, 0xcb, - 0xec, 0xeb, 0x41, 0xba, 0x45, 0x2a, - ], - ivk: [ - 0x15, 0x5a, 0x8e, 0xe2, 0x05, 0xd3, 0x87, 0x2d, 0x12, 0xf8, 0xa3, 0xe6, 0x39, - 0x91, 0x46, 0x33, 0xc2, 0x3c, 0xde, 0x1f, 0x30, 0xed, 0x50, 0x51, 0xe5, 0x21, - 0x30, 0xb1, 0xd0, 0x10, 0x4c, 0x06, - ], - xsk: Some([ - 0x01, 0x14, 0xc2, 0x71, 0x3a, 0x01, 0x00, 0x00, 0x00, 0x01, 0x47, 0x11, 0x0c, - 0x69, 0x1a, 0x03, 0xb9, 0xd9, 0xf0, 0xba, 0x90, 0x05, 0xc5, 0xe7, 0x90, 0xa5, - 0x95, 0xb7, 0xf0, 0x4e, 0x33, 0x29, 0xd2, 0xfa, 0x43, 0x8a, 0x67, 0x05, 0xda, - 0xbc, 0xe6, 0x28, 0x2b, 0xc1, 0x97, 0xa5, 0x16, 0x28, 0x7c, 0x8e, 0xa8, 0xf6, - 0x8c, 0x42, 0x4a, 0xba, 0xd3, 0x02, 0xb4, 0x5c, 0xdf, 0x95, 0x40, 0x79, 0x61, - 0xd7, 0xb8, 0xb4, 0x55, 0x26, 0x7a, 0x35, 0x0c, 0xe7, 0xa3, 0x29, 0x88, 0xfd, - 0xca, 0x1e, 0xfc, 0xd6, 0xd1, 0xc4, 0xc5, 0x62, 0xe6, 0x29, 0xc2, 0xe9, 0x6b, - 0x2c, 0x3f, 0x7e, 0xda, 0x04, 0xac, 0x4e, 0xfd, 0x18, 0x10, 0xff, 0x6b, 0xba, - 0x01, 0x5f, 0x13, 0x81, 0xfc, 0x88, 0x86, 0xda, 0x6a, 0x02, 0xdf, 0xfe, 0xef, - 0xcf, 0x50, 0x3c, 0x40, 0xfa, 0x8f, 0x5a, 0x36, 0xf7, 0xa7, 0x14, 0x2f, 0xd8, - 0x1b, 0x55, 0x18, 0xc5, 0xa4, 0x74, 0x74, 0xe0, 0x4d, 0xe8, 0x32, 0xa2, 0xd7, - 0x91, 0xec, 0x12, 0x9a, 0xb9, 0x00, 0x2b, 0x91, 0xc9, 0xe9, 0xcd, 0xee, 0xd7, - 0x92, 0x41, 0xa7, 0xc4, 0x96, 0x0e, 0x51, 0x78, 0xd8, 0x70, 0xc1, 0xb4, 0xdc, - ]), - xfvk: [ - 0x01, 0x14, 0xc2, 0x71, 0x3a, 0x01, 0x00, 0x00, 0x00, 0x01, 0x47, 0x11, 0x0c, - 0x69, 0x1a, 0x03, 0xb9, 0xd9, 0xf0, 0xba, 0x90, 0x05, 0xc5, 0xe7, 0x90, 0xa5, - 0x95, 0xb7, 0xf0, 0x4e, 0x33, 0x29, 0xd2, 0xfa, 0x43, 0x8a, 0x67, 0x05, 0xda, - 0xbc, 0xe6, 0xdc, 0x14, 0xb5, 0x14, 0xd3, 0xa9, 0x25, 0x94, 0xc2, 0x19, 0x25, - 0xaf, 0x2f, 0x77, 0x65, 0xa5, 0x47, 0xb3, 0x0e, 0x73, 0xfa, 0x7b, 0x70, 0x0e, - 0xa1, 0xbf, 0xf2, 0xe5, 0xef, 0xaa, 0xa8, 0x8b, 0x61, 0x52, 0xeb, 0x7f, 0xdb, - 0x25, 0x27, 0x79, 0xdd, 0xcb, 0x95, 0xd2, 0x17, 0xea, 0x4b, 0x6f, 0xd3, 0x40, - 0x36, 0xe9, 0xad, 0xad, 0xb3, 0xb5, 0xc9, 0xcb, 0xec, 0xeb, 0x41, 0xba, 0x45, - 0x2a, 0x5f, 0x13, 0x81, 0xfc, 0x88, 0x86, 0xda, 0x6a, 0x02, 0xdf, 0xfe, 0xef, - 0xcf, 0x50, 0x3c, 0x40, 0xfa, 0x8f, 0x5a, 0x36, 0xf7, 0xa7, 0x14, 0x2f, 0xd8, - 0x1b, 0x55, 0x18, 0xc5, 0xa4, 0x74, 0x74, 0xe0, 0x4d, 0xe8, 0x32, 0xa2, 0xd7, - 0x91, 0xec, 0x12, 0x9a, 0xb9, 0x00, 0x2b, 0x91, 0xc9, 0xe9, 0xcd, 0xee, 0xd7, - 0x92, 0x41, 0xa7, 0xc4, 0x96, 0x0e, 0x51, 0x78, 0xd8, 0x70, 0xc1, 0xb4, 0xdc, - ], - fp: [ - 0xdb, 0x99, 0x9e, 0x07, 0x1d, 0xcb, 0x58, 0xdd, 0x93, 0x02, 0x9a, 0xe6, 0x97, - 0x05, 0x3e, 0x90, 0xed, 0xb3, 0x59, 0xd1, 0xa1, 0xb7, 0xa1, 0x25, 0x16, 0x7e, - 0xfb, 0xe9, 0x28, 0x06, 0x84, 0x23, - ], - d0: Some([ - 0x8b, 0x41, 0x38, 0x32, 0x0d, 0xfa, 0xfd, 0x7b, 0x39, 0x97, 0x81, - ]), - d1: None, - d2: Some([ - 0x57, 0x49, 0xa1, 0x33, 0x52, 0xbc, 0x22, 0x3e, 0x30, 0x80, 0x78, - ]), - dmax: Some([ - 0x63, 0x89, 0x57, 0x4c, 0xde, 0x0f, 0xbb, 0xc6, 0x36, 0x81, 0x31, - ]), - }, - TestVector { - ask: Some([ - 0x8b, 0xe8, 0x11, 0x3c, 0xee, 0x34, 0x13, 0xa7, 0x1f, 0x82, 0xc4, 0x1f, 0xc8, - 0xda, 0x51, 0x7b, 0xe1, 0x34, 0x04, 0x98, 0x32, 0xe6, 0x82, 0x5c, 0x92, 0xda, - 0x6b, 0x84, 0xfe, 0xe4, 0xc6, 0x0d, - ]), - nsk: Some([ - 0x37, 0x78, 0x05, 0x9d, 0xc5, 0x69, 0xe7, 0xd0, 0xd3, 0x23, 0x91, 0x57, 0x3f, - 0x95, 0x1b, 0xbd, 0xe9, 0x2f, 0xc6, 0xb9, 0xcf, 0x61, 0x47, 0x73, 0x66, 0x1c, - 0x5c, 0x27, 0x3a, 0xa6, 0x99, 0x0c, - ]), - ovk: [ - 0xcf, 0x81, 0x18, 0x2e, 0x96, 0x22, 0x3c, 0x02, 0x8c, 0xe3, 0xd6, 0xeb, 0x47, - 0x94, 0xd3, 0x11, 0x3b, 0x95, 0x06, 0x9d, 0x14, 0xc5, 0x75, 0x88, 0xe1, 0x93, - 0xb6, 0x5e, 0xfc, 0x28, 0x13, 0xbc, - ], - dk: [ - 0xa3, 0xed, 0xa1, 0x9f, 0x9e, 0xff, 0x46, 0xca, 0x12, 0xdf, 0xa1, 0xbf, 0x10, - 0x37, 0x1b, 0x48, 0xd1, 0xb4, 0xa4, 0x0c, 0x4d, 0x05, 0xa0, 0xd8, 0xdc, 0xe0, - 0xe7, 0xdc, 0x62, 0xb0, 0x7b, 0x37, - ], - c: [ - 0x97, 0xce, 0x15, 0xf4, 0xed, 0x1b, 0x97, 0x39, 0xb0, 0x26, 0x2a, 0x46, 0x3b, - 0xcb, 0x3d, 0xc9, 0xb3, 0xbd, 0x23, 0x23, 0xa9, 0xba, 0xa4, 0x41, 0xca, 0x42, - 0x77, 0x73, 0x83, 0xa8, 0xd4, 0x35, - ], - ak: [ - 0xa6, 0xc5, 0x92, 0x5a, 0x0f, 0x85, 0xfa, 0x4f, 0x1e, 0x40, 0x5e, 0x3a, 0x49, - 0x70, 0xd0, 0xc4, 0xa4, 0xb4, 0x81, 0x44, 0x38, 0xf4, 0xe9, 0xd4, 0x52, 0x0e, - 0x20, 0xf7, 0xfd, 0xcf, 0x38, 0x41, - ], - nk: [ - 0x30, 0x4e, 0x30, 0x59, 0x16, 0x21, 0x6b, 0xeb, 0x7b, 0x65, 0x4d, 0x8a, 0xae, - 0x50, 0xec, 0xd1, 0x88, 0xfc, 0xb3, 0x84, 0xbc, 0x36, 0xc0, 0x0c, 0x66, 0x4f, - 0x30, 0x77, 0x25, 0xe2, 0xee, 0x11, - ], - ivk: [ - 0xa2, 0xa1, 0x3c, 0x1e, 0x38, 0xb4, 0x59, 0x84, 0x44, 0x58, 0x03, 0xe4, 0x30, - 0xa6, 0x83, 0xc9, 0x0b, 0xb2, 0xe1, 0x4d, 0x4c, 0x86, 0x92, 0xff, 0x25, 0x3a, - 0x64, 0x84, 0xdd, 0x9b, 0xb5, 0x04, - ], - xsk: Some([ - 0x02, 0xdb, 0x99, 0x9e, 0x07, 0x02, 0x00, 0x00, 0x80, 0x97, 0xce, 0x15, 0xf4, - 0xed, 0x1b, 0x97, 0x39, 0xb0, 0x26, 0x2a, 0x46, 0x3b, 0xcb, 0x3d, 0xc9, 0xb3, - 0xbd, 0x23, 0x23, 0xa9, 0xba, 0xa4, 0x41, 0xca, 0x42, 0x77, 0x73, 0x83, 0xa8, - 0xd4, 0x35, 0x8b, 0xe8, 0x11, 0x3c, 0xee, 0x34, 0x13, 0xa7, 0x1f, 0x82, 0xc4, - 0x1f, 0xc8, 0xda, 0x51, 0x7b, 0xe1, 0x34, 0x04, 0x98, 0x32, 0xe6, 0x82, 0x5c, - 0x92, 0xda, 0x6b, 0x84, 0xfe, 0xe4, 0xc6, 0x0d, 0x37, 0x78, 0x05, 0x9d, 0xc5, - 0x69, 0xe7, 0xd0, 0xd3, 0x23, 0x91, 0x57, 0x3f, 0x95, 0x1b, 0xbd, 0xe9, 0x2f, - 0xc6, 0xb9, 0xcf, 0x61, 0x47, 0x73, 0x66, 0x1c, 0x5c, 0x27, 0x3a, 0xa6, 0x99, - 0x0c, 0xcf, 0x81, 0x18, 0x2e, 0x96, 0x22, 0x3c, 0x02, 0x8c, 0xe3, 0xd6, 0xeb, - 0x47, 0x94, 0xd3, 0x11, 0x3b, 0x95, 0x06, 0x9d, 0x14, 0xc5, 0x75, 0x88, 0xe1, - 0x93, 0xb6, 0x5e, 0xfc, 0x28, 0x13, 0xbc, 0xa3, 0xed, 0xa1, 0x9f, 0x9e, 0xff, - 0x46, 0xca, 0x12, 0xdf, 0xa1, 0xbf, 0x10, 0x37, 0x1b, 0x48, 0xd1, 0xb4, 0xa4, - 0x0c, 0x4d, 0x05, 0xa0, 0xd8, 0xdc, 0xe0, 0xe7, 0xdc, 0x62, 0xb0, 0x7b, 0x37, - ]), - xfvk: [ - 0x02, 0xdb, 0x99, 0x9e, 0x07, 0x02, 0x00, 0x00, 0x80, 0x97, 0xce, 0x15, 0xf4, - 0xed, 0x1b, 0x97, 0x39, 0xb0, 0x26, 0x2a, 0x46, 0x3b, 0xcb, 0x3d, 0xc9, 0xb3, - 0xbd, 0x23, 0x23, 0xa9, 0xba, 0xa4, 0x41, 0xca, 0x42, 0x77, 0x73, 0x83, 0xa8, - 0xd4, 0x35, 0xa6, 0xc5, 0x92, 0x5a, 0x0f, 0x85, 0xfa, 0x4f, 0x1e, 0x40, 0x5e, - 0x3a, 0x49, 0x70, 0xd0, 0xc4, 0xa4, 0xb4, 0x81, 0x44, 0x38, 0xf4, 0xe9, 0xd4, - 0x52, 0x0e, 0x20, 0xf7, 0xfd, 0xcf, 0x38, 0x41, 0x30, 0x4e, 0x30, 0x59, 0x16, - 0x21, 0x6b, 0xeb, 0x7b, 0x65, 0x4d, 0x8a, 0xae, 0x50, 0xec, 0xd1, 0x88, 0xfc, - 0xb3, 0x84, 0xbc, 0x36, 0xc0, 0x0c, 0x66, 0x4f, 0x30, 0x77, 0x25, 0xe2, 0xee, - 0x11, 0xcf, 0x81, 0x18, 0x2e, 0x96, 0x22, 0x3c, 0x02, 0x8c, 0xe3, 0xd6, 0xeb, - 0x47, 0x94, 0xd3, 0x11, 0x3b, 0x95, 0x06, 0x9d, 0x14, 0xc5, 0x75, 0x88, 0xe1, - 0x93, 0xb6, 0x5e, 0xfc, 0x28, 0x13, 0xbc, 0xa3, 0xed, 0xa1, 0x9f, 0x9e, 0xff, - 0x46, 0xca, 0x12, 0xdf, 0xa1, 0xbf, 0x10, 0x37, 0x1b, 0x48, 0xd1, 0xb4, 0xa4, - 0x0c, 0x4d, 0x05, 0xa0, 0xd8, 0xdc, 0xe0, 0xe7, 0xdc, 0x62, 0xb0, 0x7b, 0x37, - ], - fp: [ - 0x48, 0xc1, 0x83, 0x75, 0x7b, 0x5d, 0xa6, 0x61, 0x2a, 0x81, 0xb3, 0x0e, 0x40, - 0xb4, 0xac, 0xaa, 0x2d, 0x9e, 0x73, 0x95, 0x12, 0xe1, 0xd2, 0xd0, 0x01, 0x0e, - 0x92, 0xa7, 0xf7, 0xf2, 0xfc, 0xdf, - ], - d0: Some([ - 0xe8, 0xd0, 0x37, 0x93, 0xcd, 0xd2, 0xba, 0xcc, 0x9c, 0x70, 0x41, - ]), - d1: Some([ - 0x02, 0x0a, 0x7a, 0x6b, 0x0b, 0xf8, 0x4d, 0x3e, 0x89, 0x9f, 0x68, - ]), - d2: None, - dmax: None, - }, - TestVector { - ask: None, - nsk: None, - ovk: [ - 0xcf, 0x81, 0x18, 0x2e, 0x96, 0x22, 0x3c, 0x02, 0x8c, 0xe3, 0xd6, 0xeb, 0x47, - 0x94, 0xd3, 0x11, 0x3b, 0x95, 0x06, 0x9d, 0x14, 0xc5, 0x75, 0x88, 0xe1, 0x93, - 0xb6, 0x5e, 0xfc, 0x28, 0x13, 0xbc, - ], - dk: [ - 0xa3, 0xed, 0xa1, 0x9f, 0x9e, 0xff, 0x46, 0xca, 0x12, 0xdf, 0xa1, 0xbf, 0x10, - 0x37, 0x1b, 0x48, 0xd1, 0xb4, 0xa4, 0x0c, 0x4d, 0x05, 0xa0, 0xd8, 0xdc, 0xe0, - 0xe7, 0xdc, 0x62, 0xb0, 0x7b, 0x37, - ], - c: [ - 0x97, 0xce, 0x15, 0xf4, 0xed, 0x1b, 0x97, 0x39, 0xb0, 0x26, 0x2a, 0x46, 0x3b, - 0xcb, 0x3d, 0xc9, 0xb3, 0xbd, 0x23, 0x23, 0xa9, 0xba, 0xa4, 0x41, 0xca, 0x42, - 0x77, 0x73, 0x83, 0xa8, 0xd4, 0x35, - ], - ak: [ - 0xa6, 0xc5, 0x92, 0x5a, 0x0f, 0x85, 0xfa, 0x4f, 0x1e, 0x40, 0x5e, 0x3a, 0x49, - 0x70, 0xd0, 0xc4, 0xa4, 0xb4, 0x81, 0x44, 0x38, 0xf4, 0xe9, 0xd4, 0x52, 0x0e, - 0x20, 0xf7, 0xfd, 0xcf, 0x38, 0x41, - ], - nk: [ - 0x30, 0x4e, 0x30, 0x59, 0x16, 0x21, 0x6b, 0xeb, 0x7b, 0x65, 0x4d, 0x8a, 0xae, - 0x50, 0xec, 0xd1, 0x88, 0xfc, 0xb3, 0x84, 0xbc, 0x36, 0xc0, 0x0c, 0x66, 0x4f, - 0x30, 0x77, 0x25, 0xe2, 0xee, 0x11, - ], - ivk: [ - 0xa2, 0xa1, 0x3c, 0x1e, 0x38, 0xb4, 0x59, 0x84, 0x44, 0x58, 0x03, 0xe4, 0x30, - 0xa6, 0x83, 0xc9, 0x0b, 0xb2, 0xe1, 0x4d, 0x4c, 0x86, 0x92, 0xff, 0x25, 0x3a, - 0x64, 0x84, 0xdd, 0x9b, 0xb5, 0x04, - ], - xsk: None, - xfvk: [ - 0x02, 0xdb, 0x99, 0x9e, 0x07, 0x02, 0x00, 0x00, 0x80, 0x97, 0xce, 0x15, 0xf4, - 0xed, 0x1b, 0x97, 0x39, 0xb0, 0x26, 0x2a, 0x46, 0x3b, 0xcb, 0x3d, 0xc9, 0xb3, - 0xbd, 0x23, 0x23, 0xa9, 0xba, 0xa4, 0x41, 0xca, 0x42, 0x77, 0x73, 0x83, 0xa8, - 0xd4, 0x35, 0xa6, 0xc5, 0x92, 0x5a, 0x0f, 0x85, 0xfa, 0x4f, 0x1e, 0x40, 0x5e, - 0x3a, 0x49, 0x70, 0xd0, 0xc4, 0xa4, 0xb4, 0x81, 0x44, 0x38, 0xf4, 0xe9, 0xd4, - 0x52, 0x0e, 0x20, 0xf7, 0xfd, 0xcf, 0x38, 0x41, 0x30, 0x4e, 0x30, 0x59, 0x16, - 0x21, 0x6b, 0xeb, 0x7b, 0x65, 0x4d, 0x8a, 0xae, 0x50, 0xec, 0xd1, 0x88, 0xfc, - 0xb3, 0x84, 0xbc, 0x36, 0xc0, 0x0c, 0x66, 0x4f, 0x30, 0x77, 0x25, 0xe2, 0xee, - 0x11, 0xcf, 0x81, 0x18, 0x2e, 0x96, 0x22, 0x3c, 0x02, 0x8c, 0xe3, 0xd6, 0xeb, - 0x47, 0x94, 0xd3, 0x11, 0x3b, 0x95, 0x06, 0x9d, 0x14, 0xc5, 0x75, 0x88, 0xe1, - 0x93, 0xb6, 0x5e, 0xfc, 0x28, 0x13, 0xbc, 0xa3, 0xed, 0xa1, 0x9f, 0x9e, 0xff, - 0x46, 0xca, 0x12, 0xdf, 0xa1, 0xbf, 0x10, 0x37, 0x1b, 0x48, 0xd1, 0xb4, 0xa4, - 0x0c, 0x4d, 0x05, 0xa0, 0xd8, 0xdc, 0xe0, 0xe7, 0xdc, 0x62, 0xb0, 0x7b, 0x37, - ], - fp: [ - 0x48, 0xc1, 0x83, 0x75, 0x7b, 0x5d, 0xa6, 0x61, 0x2a, 0x81, 0xb3, 0x0e, 0x40, - 0xb4, 0xac, 0xaa, 0x2d, 0x9e, 0x73, 0x95, 0x12, 0xe1, 0xd2, 0xd0, 0x01, 0x0e, - 0x92, 0xa7, 0xf7, 0xf2, 0xfc, 0xdf, - ], - d0: Some([ - 0xe8, 0xd0, 0x37, 0x93, 0xcd, 0xd2, 0xba, 0xcc, 0x9c, 0x70, 0x41, - ]), - d1: Some([ - 0x02, 0x0a, 0x7a, 0x6b, 0x0b, 0xf8, 0x4d, 0x3e, 0x89, 0x9f, 0x68, - ]), - d2: None, - dmax: None, - }, - TestVector { - ask: None, - nsk: None, - ovk: [ - 0x69, 0xb9, 0xe0, 0xfa, 0x1c, 0x4b, 0x3d, 0xeb, 0x91, 0xd5, 0x3b, 0xee, 0xe8, - 0x71, 0x15, 0x61, 0x21, 0x47, 0x4b, 0x8b, 0x62, 0xef, 0x24, 0x13, 0x44, 0x78, - 0xdc, 0x34, 0x99, 0x69, 0x1a, 0xf6, - ], - dk: [ - 0xbe, 0xcb, 0x50, 0xc3, 0x63, 0xbb, 0x2e, 0xd9, 0xda, 0x5c, 0x30, 0x43, 0xce, - 0xb0, 0xf1, 0xa0, 0x52, 0x7b, 0xf8, 0x36, 0xb2, 0x9a, 0x35, 0xf7, 0xc0, 0xc9, - 0xf2, 0x61, 0x12, 0x3b, 0xe5, 0x6e, - ], - c: [ - 0x8d, 0x93, 0x7b, 0xcf, 0x81, 0xba, 0x43, 0x0d, 0x5b, 0x49, 0xaf, 0xc0, 0xa4, - 0x03, 0x36, 0x7b, 0x1f, 0xd9, 0x98, 0x79, 0xec, 0xba, 0x41, 0xbe, 0x05, 0x1c, - 0x5a, 0x4a, 0xa7, 0xd6, 0xe7, 0xe8, - ], - ak: [ - 0xb1, 0x85, 0xc5, 0x7b, 0x50, 0x9c, 0x25, 0x36, 0xc4, 0xf2, 0xd3, 0x26, 0xd7, - 0x66, 0xc8, 0xfa, 0xb2, 0x54, 0x47, 0xde, 0x53, 0x75, 0xa9, 0x32, 0x8d, 0x64, - 0x9d, 0xda, 0xbd, 0x97, 0xa6, 0xa3, - ], - nk: [ - 0xdb, 0x88, 0x04, 0x9e, 0x02, 0xd2, 0x07, 0x56, 0x8a, 0xfc, 0x42, 0xe0, 0x7d, - 0xb2, 0xab, 0xed, 0x50, 0x0b, 0x27, 0x01, 0xc0, 0x1b, 0xbf, 0xf3, 0x63, 0x99, - 0x76, 0x4b, 0x81, 0xc0, 0x66, 0x4f, - ], - ivk: [ - 0xb0, 0xa5, 0xf3, 0x37, 0x23, 0x2f, 0x2c, 0x3d, 0xac, 0x70, 0xc2, 0xa4, 0x10, - 0xfa, 0x56, 0x1f, 0xc4, 0x5d, 0x8c, 0xc5, 0x9c, 0xda, 0x24, 0x6d, 0x31, 0xc8, - 0xb1, 0x71, 0x5a, 0x57, 0xd9, 0x00, - ], - xsk: None, - xfvk: [ - 0x03, 0x48, 0xc1, 0x83, 0x75, 0x03, 0x00, 0x00, 0x00, 0x8d, 0x93, 0x7b, 0xcf, - 0x81, 0xba, 0x43, 0x0d, 0x5b, 0x49, 0xaf, 0xc0, 0xa4, 0x03, 0x36, 0x7b, 0x1f, - 0xd9, 0x98, 0x79, 0xec, 0xba, 0x41, 0xbe, 0x05, 0x1c, 0x5a, 0x4a, 0xa7, 0xd6, - 0xe7, 0xe8, 0xb1, 0x85, 0xc5, 0x7b, 0x50, 0x9c, 0x25, 0x36, 0xc4, 0xf2, 0xd3, - 0x26, 0xd7, 0x66, 0xc8, 0xfa, 0xb2, 0x54, 0x47, 0xde, 0x53, 0x75, 0xa9, 0x32, - 0x8d, 0x64, 0x9d, 0xda, 0xbd, 0x97, 0xa6, 0xa3, 0xdb, 0x88, 0x04, 0x9e, 0x02, - 0xd2, 0x07, 0x56, 0x8a, 0xfc, 0x42, 0xe0, 0x7d, 0xb2, 0xab, 0xed, 0x50, 0x0b, - 0x27, 0x01, 0xc0, 0x1b, 0xbf, 0xf3, 0x63, 0x99, 0x76, 0x4b, 0x81, 0xc0, 0x66, - 0x4f, 0x69, 0xb9, 0xe0, 0xfa, 0x1c, 0x4b, 0x3d, 0xeb, 0x91, 0xd5, 0x3b, 0xee, - 0xe8, 0x71, 0x15, 0x61, 0x21, 0x47, 0x4b, 0x8b, 0x62, 0xef, 0x24, 0x13, 0x44, - 0x78, 0xdc, 0x34, 0x99, 0x69, 0x1a, 0xf6, 0xbe, 0xcb, 0x50, 0xc3, 0x63, 0xbb, - 0x2e, 0xd9, 0xda, 0x5c, 0x30, 0x43, 0xce, 0xb0, 0xf1, 0xa0, 0x52, 0x7b, 0xf8, - 0x36, 0xb2, 0x9a, 0x35, 0xf7, 0xc0, 0xc9, 0xf2, 0x61, 0x12, 0x3b, 0xe5, 0x6e, - ], - fp: [ - 0x2e, 0x08, 0x15, 0x6d, 0xf8, 0xdf, 0xa2, 0x5b, 0x50, 0x55, 0xfc, 0x06, 0x3c, - 0x67, 0x15, 0x35, 0xa6, 0xa6, 0x5a, 0x60, 0x43, 0x7d, 0x96, 0xe7, 0x93, 0x08, - 0x15, 0xd0, 0x90, 0xf6, 0x2d, 0x67, - ], - d0: None, - d1: Some([ - 0x03, 0x0f, 0xfb, 0x26, 0x3a, 0x93, 0x9e, 0x23, 0x0e, 0x96, 0xdd, - ]), - d2: Some([ - 0x7b, 0xbf, 0x63, 0x93, 0x4c, 0x7e, 0x92, 0x67, 0x0c, 0xdb, 0x55, - ]), - dmax: Some([ - 0x1a, 0x73, 0x0f, 0xeb, 0x00, 0x59, 0xcf, 0x1f, 0x5b, 0xde, 0xa8, - ]), - }, - ]; - - let seed = [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, - ]; - - let i1 = ChildIndex::NonHardened(1); - let i2h = ChildIndex::Hardened(2); - let i3 = ChildIndex::NonHardened(3); - - let m = ExtendedSpendingKey::master(&seed); - let m_1 = m.derive_child(i1); - let m_1_2h = ExtendedSpendingKey::from_path(&m, &[i1, i2h]); - let m_1_2hv = ExtendedFullViewingKey::from(&m_1_2h); - let m_1_2hv_3 = m_1_2hv.derive_child(i3).unwrap(); - - let xfvks = [ - ExtendedFullViewingKey::from(&m), - ExtendedFullViewingKey::from(&m_1), - ExtendedFullViewingKey::from(&m_1_2h), - m_1_2hv, // Appears twice so we can de-duplicate test code below - m_1_2hv_3, - ]; - assert_eq!(test_vectors.len(), xfvks.len()); - - let xsks = [m, m_1, m_1_2h]; - - for j in 0..xsks.len() { - let xsk = &xsks[j]; - let tv = &test_vectors[j]; - - let mut buf = [0; 32]; - xsk.expsk.ask.into_repr().write_le(&mut buf[..]).unwrap(); - assert_eq!(buf, tv.ask.unwrap()); - xsk.expsk.nsk.into_repr().write_le(&mut buf[..]).unwrap(); - assert_eq!(buf, tv.nsk.unwrap()); - - assert_eq!(xsk.expsk.ovk.0, tv.ovk); - assert_eq!(xsk.dk.0, tv.dk); - assert_eq!(xsk.chain_code.0, tv.c); - - let mut ser = vec![]; - xsk.write(&mut ser).unwrap(); - assert_eq!(&ser[..], &tv.xsk.unwrap()[..]); - } - - for j in 0..xfvks.len() { - let xfvk = &xfvks[j]; - let tv = &test_vectors[j]; - - let mut buf = [0; 32]; - xfvk.fvk.vk.ak.write(&mut buf[..]).unwrap(); - assert_eq!(buf, tv.ak); - xfvk.fvk.vk.nk.write(&mut buf[..]).unwrap(); - assert_eq!(buf, tv.nk); - - assert_eq!(xfvk.fvk.ovk.0, tv.ovk); - assert_eq!(xfvk.dk.0, tv.dk); - assert_eq!(xfvk.chain_code.0, tv.c); - - xfvk.fvk - .vk - .ivk() - .into_repr() - .write_le(&mut buf[..]) - .unwrap(); - assert_eq!(buf, tv.ivk); - - let mut ser = vec![]; - xfvk.write(&mut ser).unwrap(); - assert_eq!(&ser[..], &tv.xfvk[..]); - assert_eq!(xfvk.fvk.fingerprint().0, tv.fp); - - // d0 - let mut di = DiversifierIndex::new(); - match xfvk.dk.diversifier(di) { - Ok((l, d)) if l == di => assert_eq!(d.0, tv.d0.unwrap()), - Ok((_, _)) => assert!(tv.d0.is_none()), - Err(_) => panic!(), - } - - // d1 - di.increment().unwrap(); - match xfvk.dk.diversifier(di) { - Ok((l, d)) if l == di => assert_eq!(d.0, tv.d1.unwrap()), - Ok((_, _)) => assert!(tv.d1.is_none()), - Err(_) => panic!(), - } - - // d2 - di.increment().unwrap(); - match xfvk.dk.diversifier(di) { - Ok((l, d)) if l == di => assert_eq!(d.0, tv.d2.unwrap()), - Ok((_, _)) => assert!(tv.d2.is_none()), - Err(_) => panic!(), - } - - // dmax - let dmax = DiversifierIndex([0xff; 11]); - match xfvk.dk.diversifier(dmax) { - Ok((l, d)) if l == dmax => assert_eq!(d.0, tv.dmax.unwrap()), - Ok((_, _)) => panic!(), - Err(_) => assert!(tv.dmax.is_none()), - } - } + let too_big = DiversifierIndex([ + 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ]); + assert_matches!(u32::try_from(too_big), Err(_)); } }