Skip to content

Commit 73ba73f

Browse files
committed
Merge #219: Added Mnemonic Interface
9866649 Added Mnemonic Interface (dhruvbaliyan) Pull request description: ### Description This PR adds `interface Mnemonic` which will make the API to generate new DescriptorSecretKey have type-safe arguments. <!-- Describe the purpose of this PR, what's being adding and/or fixed --> ### Notes to the reviewers This PR doesn't have any issue linked to it, as it was discusses on a call during the implementation of `DescriptorSecretKey` (PR #154). It was discussed to make `Mnemonic` an interface and use that instead of string `Mnemonic` so that the API to generate `DescriptorSecretKey` doesn't have any potential failure (like in case it's provided with incorrect Mnemonic words). APIs added ``` // generates and returns Mnemonic with random entropy Mnemonic::new(word_count: WordCount) -> Self { ... } // converts string Mnemonic to Mnemonic type with error (in case of incorrect string Mnemonic) Mnemonic::from_str(mnemonic: String) -> Result<Self, BdkError> { ... } // generates and returns Mnemonic with given entropy Mnemonic::from_entropy(entropy: Vec<u8>) -> Result<Self, BdkError> {...} // view mnemonic as string Mnemonic::as_string(&self) -> String { ... } ``` Along with some changes to `DescriptorSecretKey::new()` to fit these new APIs ### Changelog notice ``` - Added Struct Mnemonic with following methods [#219] - new(word_count: WordCount) generates and returns Mnemonic with random entropy - from_str(mnemonic: String) converts string Mnemonic to Mnemonic type with error - from_entropy(entropy: Vec<u8>) generates and returns Mnemonic with given entropy - as_string() view Mnemonic as string - API removed [#219] - generate_mnemonic(word_count: WordCount) [#219](#219) ``` ### Checklists #### All Submissions: * [x] I've signed all my commits * [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md) * [x] I ran `cargo fmt` and `cargo clippy` before committing #### New Features: * [x] I've added docs for the new feature #### Bugfixes: * [x] This pull request breaks the existing API * Top level function `generate_mnemonic(...)` was removed ACKs for top commit: thunderbiscuit: ACK 9866649. notmandatory: ACK 9866649 Tree-SHA512: 45f9158beb6fe7bfe2a901c3f17126db855fe0b4b479ecb2a16381e06a415eed295fe6be3c840bd1d1fc8cffaf58bd97dc27bdc1e82699367a827d700e8fd09b
2 parents c2aecb0 + 9866649 commit 73ba73f

File tree

2 files changed

+56
-18
lines changed

2 files changed

+56
-18
lines changed

src/bdk.udl

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
namespace bdk {
2-
[Throws=BdkError]
3-
string generate_mnemonic(WordCount word_count);
2+
43
};
54

65
[Error]
@@ -274,14 +273,25 @@ interface BumpFeeTxBuilder {
274273
PartiallySignedBitcoinTransaction finish([ByRef] Wallet wallet);
275274
};
276275

276+
interface Mnemonic {
277+
constructor(WordCount word_count);
278+
279+
[Name=from_str, Throws=BdkError]
280+
constructor(string mnemonic);
281+
282+
[Name=from_entropy, Throws=BdkError]
283+
constructor(sequence<u8> entropy);
284+
285+
string as_string();
286+
};
287+
277288
interface DerivationPath {
278289
[Throws=BdkError]
279290
constructor(string path);
280291
};
281292

282293
interface DescriptorSecretKey {
283-
[Throws=BdkError]
284-
constructor(Network network, string mnemonic, string? password);
294+
constructor(Network network, Mnemonic mnemonic, string? password);
285295

286296
[Throws=BdkError]
287297
DescriptorSecretKey derive(DerivationPath path);

src/lib.rs

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use bdk::blockchain::{Blockchain as BdkBlockchain, Progress as BdkProgress};
1515
use bdk::database::any::{AnyDatabase, SledDbConfiguration, SqliteDbConfiguration};
1616
use bdk::database::{AnyDatabaseConfig, ConfigurableDatabase};
1717
use bdk::descriptor::DescriptorXKey;
18-
use bdk::keys::bip39::{Language, Mnemonic, WordCount};
18+
use bdk::keys::bip39::{Language, Mnemonic as BdkMnemonic, WordCount};
1919
use bdk::keys::{
2020
DerivableKey, DescriptorPublicKey as BdkDescriptorPublicKey,
2121
DescriptorSecretKey as BdkDescriptorSecretKey, ExtendedKey, GeneratableKey, GeneratedKey,
@@ -857,10 +857,40 @@ impl BumpFeeTxBuilder {
857857
}
858858
}
859859

860-
fn generate_mnemonic(word_count: WordCount) -> Result<String, BdkError> {
861-
let mnemonic: GeneratedKey<_, BareCtx> =
862-
Mnemonic::generate((word_count, Language::English)).unwrap();
863-
Ok(mnemonic.to_string())
860+
/// Mnemonic phrases are a human-readable version of the private keys.
861+
/// Supported number of words are 12, 15, 18, 21 and 24.
862+
struct Mnemonic {
863+
internal: BdkMnemonic,
864+
}
865+
866+
impl Mnemonic {
867+
/// Generates Mnemonic with a random entropy
868+
fn new(word_count: WordCount) -> Self {
869+
let generated_key: GeneratedKey<_, BareCtx> =
870+
BdkMnemonic::generate((word_count, Language::English)).unwrap();
871+
let mnemonic = BdkMnemonic::parse_in(Language::English, generated_key.to_string()).unwrap();
872+
Mnemonic { internal: mnemonic }
873+
}
874+
875+
/// Parse a Mnemonic with given string
876+
fn from_str(mnemonic: String) -> Result<Self, BdkError> {
877+
BdkMnemonic::from_str(&mnemonic)
878+
.map(|m| Mnemonic { internal: m })
879+
.map_err(|e| BdkError::Generic(e.to_string()))
880+
}
881+
882+
/// Create a new Mnemonic in the specified language from the given entropy.
883+
/// Entropy must be a multiple of 32 bits (4 bytes) and 128-256 bits in length.
884+
fn from_entropy(entropy: Vec<u8>) -> Result<Self, BdkError> {
885+
BdkMnemonic::from_entropy(entropy.as_slice())
886+
.map(|m| Mnemonic { internal: m })
887+
.map_err(|e| BdkError::Generic(e.to_string()))
888+
}
889+
890+
/// Returns Mnemonic as string
891+
fn as_string(&self) -> String {
892+
self.internal.to_string()
893+
}
864894
}
865895

866896
struct DerivationPath {
@@ -882,19 +912,18 @@ struct DescriptorSecretKey {
882912
}
883913

884914
impl DescriptorSecretKey {
885-
fn new(network: Network, mnemonic: String, password: Option<String>) -> Result<Self, BdkError> {
886-
let mnemonic = Mnemonic::parse_in(Language::English, mnemonic)
887-
.map_err(|e| BdkError::Generic(e.to_string()))?;
888-
let xkey: ExtendedKey = (mnemonic, password).into_extended_key()?;
915+
fn new(network: Network, mnemonic: Arc<Mnemonic>, password: Option<String>) -> Self {
916+
let mnemonic = mnemonic.internal.clone();
917+
let xkey: ExtendedKey = (mnemonic, password).into_extended_key().unwrap();
889918
let descriptor_secret_key = BdkDescriptorSecretKey::XPrv(DescriptorXKey {
890919
origin: None,
891920
xkey: xkey.into_xprv(network).unwrap(),
892921
derivation_path: BdkDerivationPath::master(),
893922
wildcard: bdk::descriptor::Wildcard::Unhardened,
894923
});
895-
Ok(Self {
924+
Self {
896925
descriptor_secret_key_mutex: Mutex::new(descriptor_secret_key),
897-
})
926+
}
898927
}
899928

900929
fn derive(&self, path: Arc<DerivationPath>) -> Result<Arc<Self>, BdkError> {
@@ -1118,9 +1147,8 @@ mod test {
11181147
}
11191148

11201149
fn get_descriptor_secret_key() -> DescriptorSecretKey {
1121-
let mnemonic =
1122-
"chaos fabric time speed sponsor all flat solution wisdom trophy crack object robot pave observe combine where aware bench orient secret primary cable detect".to_string();
1123-
DescriptorSecretKey::new(Testnet, mnemonic, None).unwrap()
1150+
let mnemonic = Mnemonic::from_str("chaos fabric time speed sponsor all flat solution wisdom trophy crack object robot pave observe combine where aware bench orient secret primary cable detect".to_string()).unwrap();
1151+
DescriptorSecretKey::new(Testnet, Arc::new(mnemonic), None)
11241152
}
11251153

11261154
fn derive_dsk(

0 commit comments

Comments
 (0)