Skip to content

Commit 31b0c93

Browse files
committed
hkd32: Factor tiny-bip39 code into hkd32
Merges the `tiny-bip39` code `hkd32` properly, testing it against the 24-word BIP39 test vectors.
1 parent ff4880a commit 31b0c93

19 files changed

+378
-1636
lines changed

Cargo.lock

Lines changed: 2 additions & 200 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

hkd32/Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@ travis-ci = { repository = "iqlusioninc/crates", branch = "develop" }
2323
[dependencies]
2424
getrandom = { version = "0.1", optional = true }
2525
hmac = { version = "0.7", default-features = false }
26+
lazy_static = { version = "1", optional = true, default-features = false }
2627
sha2 = { version = "0.8", default-features = false }
27-
tiny-bip39 = { version = "0.6", default-features = false, optional = true }
28+
pbkdf2 = { version = "0.3", optional = true, default-features = false }
2829

2930
[dependencies.subtle-encoding]
3031
version = "0.4"
@@ -41,7 +42,7 @@ path = "../zeroize"
4142
default = ["alloc", "bech32", "getrandom"]
4243
alloc = ["zeroize/alloc"]
4344
bech32 = ["alloc", "subtle-encoding/bech32-preview"]
44-
mnemonic = ["alloc", "tiny-bip39"]
45+
mnemonic = ["alloc", "getrandom", "lazy_static", "pbkdf2"]
4546

4647
[package.metadata.docs.rs]
4748
all-features = true

hkd32/src/key_material.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -127,12 +127,6 @@ impl KeyMaterial {
127127
let b32 = Bech32::default().encode(hrp, self.as_bytes());
128128
Zeroizing::new(b32)
129129
}
130-
131-
/// Serialize this `KeyMaterial` as a BIP39 mnemonic phrase
132-
#[cfg(feature = "mnemonic")]
133-
pub fn to_mnemonic(&self, language: mnemonic::Language) -> mnemonic::Phrase {
134-
mnemonic::Phrase::from_key_material(self, language)
135-
}
136130
}
137131

138132
impl From<[u8; KEY_SIZE]> for KeyMaterial {

hkd32/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
#![doc(html_root_url = "https://docs.rs/hkd32/0.1.2")]
4242

4343
#[cfg(feature = "alloc")]
44-
#[cfg_attr(test, macro_use)]
44+
#[cfg_attr(any(feature = "mnemonic", test), macro_use)]
4545
extern crate alloc;
4646

4747
mod key_material;

hkd32/src/mnemonic.rs

Lines changed: 9 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,107 +1,13 @@
1-
//! Support for BIP39 mnemonics.
1+
//! Support for BIP39 mnemonic phrases.
22
//!
33
//! These enable deriving `hkd32::KeyMaterial` from a 24-word BIP39 phrase.
4+
//!
5+
//! Adapted from the `bip39` crate.
6+
//! Copyright © 2017-2018 Stephen Oliver with contributions by Maciej Hirsz.
47
5-
use crate::{Error, KeyMaterial};
6-
use alloc::string::String;
7-
use zeroize::Zeroize;
8-
9-
/// Number of words required for an HKD32-compatible mnemonic phrase
10-
pub const WORD_COUNT: usize = 24;
11-
12-
/// Supported languages.
13-
///
14-
/// Presently only English is specified by the BIP39 standard
15-
#[derive(Copy, Clone, Debug)]
16-
pub enum Language {
17-
/// English is presently the only supported language
18-
English,
19-
}
20-
21-
impl Default for Language {
22-
fn default() -> Language {
23-
Language::English
24-
}
25-
}
26-
27-
impl From<Language> for bip39::Language {
28-
fn from(language: Language) -> bip39::Language {
29-
match language {
30-
Language::English => bip39::Language::English,
31-
}
32-
}
33-
}
34-
35-
/// 24-word BIP39 Mnemonic phrase
36-
pub struct Phrase {
37-
/// String value containing the phrase
38-
string: String,
39-
40-
/// Associated language for this phrase
41-
language: Language,
42-
}
43-
44-
impl Phrase {
45-
/// Create a random BIP39 mnemonic phrase.
46-
pub fn random(language: Language) -> Self {
47-
Self::from_key_material(&KeyMaterial::random(), language)
48-
}
49-
50-
/// Create a new BIP39 mnemonic phrase from the given string.
51-
///
52-
/// Must be a valid 24-word BIP39 mnemonic.
53-
pub fn new<S>(phrase: S, language: Language) -> Result<Phrase, Error>
54-
where
55-
S: AsRef<str>,
56-
{
57-
let phrase = phrase.as_ref();
58-
59-
if bip39::Mnemonic::validate(phrase, language.into()).is_err() {
60-
return Err(Error);
61-
}
62-
63-
if phrase.split(' ').count() != WORD_COUNT {
64-
return Err(Error);
65-
}
66-
67-
Ok(Phrase {
68-
string: phrase.into(),
69-
language,
70-
})
71-
}
72-
73-
/// Create a new BIP39 mnemonic phrase from the given `KeyMaterial`
74-
pub(crate) fn from_key_material(key_material: &KeyMaterial, language: Language) -> Self {
75-
let mnemonic =
76-
bip39::Mnemonic::from_entropy(key_material.as_bytes(), language.into()).unwrap();
77-
78-
Phrase {
79-
string: mnemonic.into_phrase(),
80-
language,
81-
}
82-
}
83-
84-
/// Borrow this mnemonic phrase as a string.
85-
pub fn as_str(&self) -> &str {
86-
self.string.as_ref()
87-
}
88-
89-
/// Language this phrase's wordlist is for
90-
pub fn language(&self) -> Language {
91-
self.language
92-
}
93-
}
94-
95-
impl Drop for Phrase {
96-
fn drop(&mut self) {
97-
self.string.zeroize();
98-
}
99-
}
8+
mod bits;
9+
mod language;
10+
mod phrase;
11+
mod seed;
10012

101-
impl From<Phrase> for KeyMaterial {
102-
fn from(phrase: Phrase) -> KeyMaterial {
103-
let mnemonic =
104-
bip39::Mnemonic::from_phrase(&phrase.string, phrase.language.into()).unwrap();
105-
Self::from_bytes(mnemonic.entropy()).unwrap()
106-
}
107-
}
13+
pub use self::{language::Language, phrase::Phrase, seed::Seed};

hkd32/src/mnemonic/util.rs renamed to hkd32/src/mnemonic/bits.rs

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
//! Bit manipulation for BIP39 derivation
2+
//!
3+
//! Adapted from the `bip39` crate
4+
5+
use alloc::{string::String, vec::Vec};
6+
use core::marker::PhantomData;
7+
18
pub(crate) trait IterExt: Iterator {
29
fn join<R>(&mut self, glue: &str) -> R
310
where
@@ -114,10 +121,6 @@ impl BitWriter {
114121
}
115122
}
116123

117-
pub fn len(&self) -> usize {
118-
self.inner.len() * 8 + self.offset
119-
}
120-
121124
pub fn into_bytes(mut self) -> Vec<u8> {
122125
if self.offset != 0 {
123126
self.inner.push((self.remainder >> 24) as u8);
@@ -128,7 +131,7 @@ impl BitWriter {
128131
}
129132

130133
pub(crate) struct BitIter<In: Bits, Out: Bits, I: Iterator<Item = In> + Sized> {
131-
_phantom: ::std::marker::PhantomData<Out>,
134+
_phantom: PhantomData<Out>,
132135
source: I,
133136
read: usize,
134137
buffer: u64,
@@ -144,7 +147,7 @@ where
144147
let source = source.into_iter();
145148

146149
BitIter {
147-
_phantom: ::std::marker::PhantomData,
150+
_phantom: PhantomData,
148151
source,
149152
read: 0,
150153
buffer: 0,
@@ -169,7 +172,6 @@ where
169172
}
170173

171174
let result = (self.buffer >> (64 - Out::SIZE)) as u16;
172-
173175
self.buffer <<= Out::SIZE;
174176
self.read -= Out::SIZE;
175177

@@ -185,10 +187,3 @@ where
185187
)
186188
}
187189
}
188-
189-
/// Extract the first `bits` from the `source` byte
190-
pub(crate) fn checksum(source: u8, bits: u8) -> u8 {
191-
debug_assert!(bits <= 8, "Can operate on 8-bit integers only");
192-
193-
source >> (8 - bits)
194-
}

hkd32/src/mnemonic/crypto.rs

Lines changed: 0 additions & 43 deletions
This file was deleted.

hkd32/src/mnemonic/error.rs

Lines changed: 0 additions & 18 deletions
This file was deleted.

0 commit comments

Comments
 (0)