Merge bitcoindevkit/bdk-ffi#219: Added Mnemonic Interface

9866649fdc5ffe0203f5a76082d789a22e5214bf 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](https://github.com/bitcoindevkit/bdk-ffi/pull/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 9866649fdc5ffe0203f5a76082d789a22e5214bf.
  notmandatory:
    ACK 9866649fdc5ffe0203f5a76082d789a22e5214bf

Tree-SHA512: 45f9158beb6fe7bfe2a901c3f17126db855fe0b4b479ecb2a16381e06a415eed295fe6be3c840bd1d1fc8cffaf58bd97dc27bdc1e82699367a827d700e8fd09b
This commit is contained in:
Steve Myers 2022-11-07 11:25:20 -06:00
commit 73ba73fd03
No known key found for this signature in database
GPG Key ID: 8105A46B22C2D051
2 changed files with 56 additions and 18 deletions

View File

@ -1,6 +1,5 @@
namespace bdk {
[Throws=BdkError]
string generate_mnemonic(WordCount word_count);
};
[Error]
@ -274,14 +273,25 @@ interface BumpFeeTxBuilder {
PartiallySignedBitcoinTransaction finish([ByRef] Wallet wallet);
};
interface Mnemonic {
constructor(WordCount word_count);
[Name=from_str, Throws=BdkError]
constructor(string mnemonic);
[Name=from_entropy, Throws=BdkError]
constructor(sequence<u8> entropy);
string as_string();
};
interface DerivationPath {
[Throws=BdkError]
constructor(string path);
};
interface DescriptorSecretKey {
[Throws=BdkError]
constructor(Network network, string mnemonic, string? password);
constructor(Network network, Mnemonic mnemonic, string? password);
[Throws=BdkError]
DescriptorSecretKey derive(DerivationPath path);

View File

@ -15,7 +15,7 @@ use bdk::blockchain::{Blockchain as BdkBlockchain, Progress as BdkProgress};
use bdk::database::any::{AnyDatabase, SledDbConfiguration, SqliteDbConfiguration};
use bdk::database::{AnyDatabaseConfig, ConfigurableDatabase};
use bdk::descriptor::DescriptorXKey;
use bdk::keys::bip39::{Language, Mnemonic, WordCount};
use bdk::keys::bip39::{Language, Mnemonic as BdkMnemonic, WordCount};
use bdk::keys::{
DerivableKey, DescriptorPublicKey as BdkDescriptorPublicKey,
DescriptorSecretKey as BdkDescriptorSecretKey, ExtendedKey, GeneratableKey, GeneratedKey,
@ -857,10 +857,40 @@ impl BumpFeeTxBuilder {
}
}
fn generate_mnemonic(word_count: WordCount) -> Result<String, BdkError> {
let mnemonic: GeneratedKey<_, BareCtx> =
Mnemonic::generate((word_count, Language::English)).unwrap();
Ok(mnemonic.to_string())
/// Mnemonic phrases are a human-readable version of the private keys.
/// Supported number of words are 12, 15, 18, 21 and 24.
struct Mnemonic {
internal: BdkMnemonic,
}
impl Mnemonic {
/// Generates Mnemonic with a random entropy
fn new(word_count: WordCount) -> Self {
let generated_key: GeneratedKey<_, BareCtx> =
BdkMnemonic::generate((word_count, Language::English)).unwrap();
let mnemonic = BdkMnemonic::parse_in(Language::English, generated_key.to_string()).unwrap();
Mnemonic { internal: mnemonic }
}
/// Parse a Mnemonic with given string
fn from_str(mnemonic: String) -> Result<Self, BdkError> {
BdkMnemonic::from_str(&mnemonic)
.map(|m| Mnemonic { internal: m })
.map_err(|e| BdkError::Generic(e.to_string()))
}
/// Create a new Mnemonic in the specified language from the given entropy.
/// Entropy must be a multiple of 32 bits (4 bytes) and 128-256 bits in length.
fn from_entropy(entropy: Vec<u8>) -> Result<Self, BdkError> {
BdkMnemonic::from_entropy(entropy.as_slice())
.map(|m| Mnemonic { internal: m })
.map_err(|e| BdkError::Generic(e.to_string()))
}
/// Returns Mnemonic as string
fn as_string(&self) -> String {
self.internal.to_string()
}
}
struct DerivationPath {
@ -882,19 +912,18 @@ struct DescriptorSecretKey {
}
impl DescriptorSecretKey {
fn new(network: Network, mnemonic: String, password: Option<String>) -> Result<Self, BdkError> {
let mnemonic = Mnemonic::parse_in(Language::English, mnemonic)
.map_err(|e| BdkError::Generic(e.to_string()))?;
let xkey: ExtendedKey = (mnemonic, password).into_extended_key()?;
fn new(network: Network, mnemonic: Arc<Mnemonic>, password: Option<String>) -> Self {
let mnemonic = mnemonic.internal.clone();
let xkey: ExtendedKey = (mnemonic, password).into_extended_key().unwrap();
let descriptor_secret_key = BdkDescriptorSecretKey::XPrv(DescriptorXKey {
origin: None,
xkey: xkey.into_xprv(network).unwrap(),
derivation_path: BdkDerivationPath::master(),
wildcard: bdk::descriptor::Wildcard::Unhardened,
});
Ok(Self {
Self {
descriptor_secret_key_mutex: Mutex::new(descriptor_secret_key),
})
}
}
fn derive(&self, path: Arc<DerivationPath>) -> Result<Arc<Self>, BdkError> {
@ -1118,9 +1147,8 @@ mod test {
}
fn get_descriptor_secret_key() -> DescriptorSecretKey {
let mnemonic =
"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();
DescriptorSecretKey::new(Testnet, mnemonic, None).unwrap()
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();
DescriptorSecretKey::new(Testnet, Arc::new(mnemonic), None)
}
fn derive_dsk(