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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use crate::error::CryptoError;
use crate::identity::{MnemonicPhrase, MNEMONIC_LEN};
use bip39::Language::English;
use bip39::{Mnemonic, MnemonicType};
use hkdf::Hkdf;
use sha2::Sha256;
#[tracing::instrument(level = "debug", ret)]
pub fn generate_random_mnemonic() -> Result<MnemonicPhrase, CryptoError> {
Mnemonic::new(
MnemonicType::for_word_count(MNEMONIC_LEN)
.map_err(|e| CryptoError::MnemonicGenerationError(e.to_string()))?,
English,
)
.phrase()
.split(' ')
.map(|word| word.to_owned())
.collect::<Vec<String>>()
.try_into()
.map_err(|e: Vec<_>| {
CryptoError::MnemonicGenerationError(format!(
"Invalid mnemonic phrase length: {} - expected {}",
e.len(),
MNEMONIC_LEN
))
})
}
#[tracing::instrument(level = "debug", skip(seed, target))]
pub(crate) fn extend_seed(seed: &[u8], target: &mut [u8; 96]) {
let info = [87, 105, 108, 100, 108, 97, 110, 100]; let hk = Hkdf::<Sha256>::new(None, seed);
hk.expand(&info, target)
.expect("Should return 96 bytes of randomness");
}
#[cfg(test)]
mod tests {
use bip39::Language::English;
use bip39::{Mnemonic, Seed};
use hex_literal::hex;
use crate::common::test_utilities::MNEMONIC_PHRASE;
use super::*;
#[test]
fn expanding_the_seed_from_vector() {
let ikm = hex!(
"
0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
"
);
let mut output_key_material = [0u8; 96];
extend_seed(&ikm, &mut output_key_material);
let (secret_key, chain_code) = output_key_material.split_at(64);
let expected_secret = hex!(
"
540d175899e60c3fae2e80592a19ef98
3b26186b5b4be4bbb9cf590ab401d689
7e293e76ac281196ec04b7bc68d2e8a0
36ef6b6171f6fcde3836fdaacbd1a661
"
);
assert_eq!(secret_key, expected_secret);
let expected_chain_code = hex!(
"
d4d1716dc1a50023fc97267109d4e4e7
b1ff0ba00e5404d7127b48bfd4900e79
"
);
assert_eq!(chain_code, expected_chain_code);
}
#[test]
fn seed_should_be_deterministic() {
let mnemonic = Mnemonic::from_phrase(MNEMONIC_PHRASE, English).unwrap();
let seed = Seed::new(&mnemonic, "");
let mut output_key_material = [0u8; 96];
extend_seed(seed.as_bytes(), &mut output_key_material);
let (secret_key, chain_code) = output_key_material.split_at(64);
let expected_secret = hex!(
"
18617dff4efef20450dd5eafc060fd85
faacca13d95ace3bda0be32e4694fcd7
a1b2c4786672c20ccdda8a97f4a6d623
838cc246eccd7b4846d72c24b60f199e
"
);
assert_eq!(secret_key, expected_secret);
let expected_chain_code = hex!(
"
75a1d31d7dc30cec8a9bce03100b368f
d1df07fa09fc8e574fd6d34502939f3f
"
);
assert_eq!(chain_code, expected_chain_code);
}
}