Skip to content

Commit 9e8f8ed

Browse files
committed
Use associated mnemonic generation
Mnemonic generation no longer needs a separate global entry point now that bindings expose a real mnemonic object. Use numeric word counts for both native and binding constructors so the APIs stay aligned without a binding-specific enum. Co-Authored-By: HAL 9000
1 parent 6997491 commit 9e8f8ed

8 files changed

Lines changed: 34 additions & 114 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
mnemonic phrases must be passed through its fallible constructor, which returns
66
`NodeError::InvalidMnemonic` for invalid input; generated mnemonics can be converted back to a
77
string through their language's standard string conversion.
8+
- `generate_entropy_mnemonic` has been removed. Use `bip39::Mnemonic::generate` in Rust and
9+
`Mnemonic::generate` in the language bindings instead.
810
- Migrating between storage backends does not preserve the relative creation order of
911
pre-existing payments, as the generic KV store migration copies entries in an unspecified
1012
order. Expect the order in which `Node::list_payments` returns pre-existing payments to

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ The primary abstraction of the library is the [`Node`][api_docs_node], which can
1717
```rust
1818
use ldk_node::bitcoin::secp256k1::PublicKey;
1919
use ldk_node::bitcoin::Network;
20-
use ldk_node::entropy::{generate_entropy_mnemonic, NodeEntropy};
20+
use ldk_node::bip39::Mnemonic;
21+
use ldk_node::entropy::NodeEntropy;
2122
use ldk_node::lightning::ln::msgs::SocketAddress;
2223
use ldk_node::lightning_invoice::Bolt11Invoice;
2324
use ldk_node::Builder;
@@ -32,7 +33,7 @@ fn main() {
3233
);
3334

3435

35-
let mnemonic = generate_entropy_mnemonic(None);
36+
let mnemonic = Mnemonic::generate(24).unwrap();
3637
let node_entropy = NodeEntropy::from_bip39_mnemonic(mnemonic, None);
3738
let node = builder.build(node_entropy).unwrap();
3839

bindings/ldk_node.udl

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
namespace ldk_node {
2-
Mnemonic generate_entropy_mnemonic(WordCount? word_count);
32
Config default_config();
43
};
54

@@ -15,8 +14,6 @@ typedef interface NodeEntropy;
1514

1615
typedef interface ProbingConfig;
1716

18-
typedef enum WordCount;
19-
2017
[Remote]
2118
enum LogLevel {
2219
"Gossip",

bindings/python/src/ldk_node/test_ldk_node.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ def send_to_address(address, amount_sats):
9999

100100

101101
def setup_node(tmp_dir, esplora_endpoint, listening_addresses):
102-
mnemonic = generate_entropy_mnemonic(None)
102+
mnemonic = Mnemonic.generate(24)
103103
node_entropy = NodeEntropy.from_bip39_mnemonic(mnemonic, None)
104104
config = default_config()
105105
builder = Builder.from_config(config)
@@ -217,7 +217,7 @@ def test_invalid_mnemonic_returns_node_error(self):
217217
self.assertIsInstance(error.exception, NodeError.InvalidMnemonic)
218218

219219
def test_mnemonic_round_trip(self):
220-
mnemonic = generate_entropy_mnemonic(None)
220+
mnemonic = bindings.Mnemonic.generate(24)
221221
parsed_mnemonic = bindings.Mnemonic.from_str(str(mnemonic))
222222

223223
self.assertIsInstance(mnemonic, bindings.Mnemonic)
@@ -238,7 +238,12 @@ def test_mnemonic_functionality(self):
238238
"c55257c360c07c72029aebc1b53c05ed0362ada38ead3e3e9efa3708e5349553"
239239
"1f09a6987599d18264c1e1c92f2cf141630c7a3c4ab7c81b2f001698e7463b04",
240240
)
241-
self.assertEqual(bindings.Mnemonic.generate(WordCount.WORDS12).word_count(), 12)
241+
self.assertEqual(bindings.Mnemonic.generate(12).word_count(), 12)
242+
243+
with self.assertRaises(NodeError) as error:
244+
bindings.Mnemonic.generate(13)
245+
246+
self.assertIsInstance(error.exception, NodeError.InvalidMnemonic)
242247

243248
with self.assertRaises(NodeError) as error:
244249
bindings.Mnemonic.from_entropy(bytes(15))

src/entropy.rs

Lines changed: 2 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,12 @@
99
1010
use std::fmt;
1111

12-
use bip39::rand::rngs::OsRng;
13-
use bip39::{Language, Mnemonic as Bip39Mnemonic};
14-
1512
use crate::config::WALLET_KEYS_SEED_LEN;
16-
use crate::ffi::{maybe_deref, maybe_wrap};
13+
use crate::ffi::maybe_deref;
1714
use crate::io;
1815

1916
#[cfg(not(feature = "uniffi"))]
20-
type Mnemonic = Bip39Mnemonic;
17+
type Mnemonic = bip39::Mnemonic;
2118
#[cfg(feature = "uniffi")]
2219
type Mnemonic = std::sync::Arc<crate::ffi::Mnemonic>;
2320

@@ -124,89 +121,3 @@ impl fmt::Debug for NodeEntropy {
124121
write!(f, "NODE ENTROPY")
125122
}
126123
}
127-
128-
/// Generates a random [BIP 39] mnemonic with the specified word count.
129-
///
130-
/// If no word count is specified, defaults to 24 words (256-bit entropy).
131-
///
132-
/// The result may be used to initialize the [`NodeEntropy`], i.e., can be given to
133-
/// [`NodeEntropy::from_bip39_mnemonic`].
134-
///
135-
/// [BIP 39]: https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki
136-
/// [`Node`]: crate::Node
137-
pub fn generate_entropy_mnemonic(word_count: Option<WordCount>) -> Mnemonic {
138-
let word_count = word_count.unwrap_or(WordCount::Words24).word_count();
139-
let mnemonic = Bip39Mnemonic::generate_in_with(&mut OsRng, Language::English, word_count)
140-
.expect("Failed to generate mnemonic");
141-
maybe_wrap(mnemonic)
142-
}
143-
144-
/// Supported BIP39 mnemonic word counts for entropy generation.
145-
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
146-
#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
147-
pub enum WordCount {
148-
/// 12-word mnemonic (128-bit entropy)
149-
Words12,
150-
/// 15-word mnemonic (160-bit entropy)
151-
Words15,
152-
/// 18-word mnemonic (192-bit entropy)
153-
Words18,
154-
/// 21-word mnemonic (224-bit entropy)
155-
Words21,
156-
/// 24-word mnemonic (256-bit entropy)
157-
Words24,
158-
}
159-
160-
impl WordCount {
161-
/// Returns the word count as a usize value.
162-
pub fn word_count(&self) -> usize {
163-
match self {
164-
WordCount::Words12 => 12,
165-
WordCount::Words15 => 15,
166-
WordCount::Words18 => 18,
167-
WordCount::Words21 => 21,
168-
WordCount::Words24 => 24,
169-
}
170-
}
171-
}
172-
173-
#[cfg(test)]
174-
mod tests {
175-
use super::*;
176-
177-
#[test]
178-
fn mnemonic_to_entropy_to_mnemonic() {
179-
// Test default (24 words)
180-
let mnemonic = generate_entropy_mnemonic(None);
181-
let mnemonic_inner = maybe_deref(&mnemonic);
182-
let entropy = mnemonic_inner.to_entropy();
183-
assert_eq!(mnemonic_inner, &Bip39Mnemonic::from_entropy(&entropy).unwrap());
184-
assert_eq!(mnemonic_inner.word_count(), 24);
185-
186-
// Test with different word counts
187-
let word_counts = [
188-
WordCount::Words12,
189-
WordCount::Words15,
190-
WordCount::Words18,
191-
WordCount::Words21,
192-
WordCount::Words24,
193-
];
194-
195-
for word_count in word_counts {
196-
let mnemonic = generate_entropy_mnemonic(Some(word_count));
197-
let mnemonic_inner = maybe_deref(&mnemonic);
198-
let entropy = mnemonic_inner.to_entropy();
199-
assert_eq!(mnemonic_inner, &Bip39Mnemonic::from_entropy(&entropy).unwrap());
200-
201-
// Verify expected word count
202-
let expected_words = match word_count {
203-
WordCount::Words12 => 12,
204-
WordCount::Words15 => 15,
205-
WordCount::Words18 => 18,
206-
WordCount::Words21 => 21,
207-
WordCount::Words24 => 24,
208-
};
209-
assert_eq!(mnemonic_inner.word_count(), expected_words);
210-
}
211-
}
212-
}

src/ffi/types.rs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ impl VssClientHeaderProvider for VssHeaderProviderAdapter {
151151

152152
use crate::builder::sanitize_alias;
153153
pub use crate::config::{default_config, ElectrumSyncConfig, EsploraSyncConfig, TorConfig};
154-
pub use crate::entropy::{generate_entropy_mnemonic, NodeEntropy, WordCount};
154+
pub use crate::entropy::NodeEntropy;
155155
use crate::error::Error;
156156
pub use crate::liquidity::LSPS1OrderStatus;
157157
pub use crate::logger::{LogLevel, LogRecord, LogWriter};
@@ -1175,14 +1175,11 @@ impl Mnemonic {
11751175
}
11761176

11771177
/// Generates a random English mnemonic with the specified word count.
1178-
///
1179-
/// Defaults to 24 words when no word count is specified.
11801178
#[uniffi::constructor]
1181-
pub fn generate(word_count: Option<WordCount>) -> Self {
1182-
let word_count = word_count.unwrap_or(WordCount::Words24).word_count();
1183-
let inner = Bip39Mnemonic::generate(word_count)
1184-
.expect("WordCount always maps to a valid BIP 39 word count");
1185-
Self { inner }
1179+
pub fn generate(word_count: u8) -> Result<Self, Error> {
1180+
Bip39Mnemonic::generate(word_count.into())
1181+
.map(Self::from)
1182+
.map_err(|_| Error::InvalidMnemonic)
11861183
}
11871184

11881185
/// Returns the words in the mnemonic.
@@ -3009,7 +3006,8 @@ mod tests {
30093006
assert_eq!(mnemonic.to_entropy(), entropy);
30103007
assert_eq!(mnemonic.checksum(), 3);
30113008
assert_eq!(mnemonic.to_seed("TREZOR").len(), 64);
3012-
assert_eq!(Mnemonic::generate(Some(WordCount::Words12)).word_count(), 12);
3009+
assert_eq!(Mnemonic::generate(12).unwrap().word_count(), 12);
3010+
assert_eq!(Mnemonic::generate(13), Err(Error::InvalidMnemonic));
30133011
assert_eq!(Mnemonic::from_entropy(&[0; 15]), Err(Error::InvalidMnemonic));
30143012
}
30153013
}

src/lib.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929
//!
3030
//! use ldk_node::bitcoin::secp256k1::PublicKey;
3131
//! use ldk_node::bitcoin::Network;
32-
//! use ldk_node::entropy::{generate_entropy_mnemonic, NodeEntropy};
32+
//! use ldk_node::bip39::Mnemonic;
33+
//! use ldk_node::entropy::NodeEntropy;
3334
//! use ldk_node::lightning::ln::msgs::SocketAddress;
3435
//! use ldk_node::lightning_invoice::Bolt11Invoice;
3536
//! use ldk_node::Builder;
@@ -42,7 +43,7 @@
4243
//! "https://rapidsync.lightningdevkit.org/testnet/v2/snapshot".to_string(),
4344
//! );
4445
//!
45-
//! let mnemonic = generate_entropy_mnemonic(None);
46+
//! let mnemonic = Mnemonic::generate(24).unwrap();
4647
//! let node_entropy = NodeEntropy::from_bip39_mnemonic(mnemonic, None);
4748
//! let node = builder.build(node_entropy).unwrap();
4849
//!
@@ -2216,7 +2217,8 @@ impl Node {
22162217
/// # use ldk_node::config::Config;
22172218
/// # use ldk_node::payment::{PaymentDetails, PaymentDirection};
22182219
/// # use ldk_node::bitcoin::Network;
2219-
/// # use ldk_node::entropy::{generate_entropy_mnemonic, NodeEntropy};
2220+
/// # use ldk_node::bip39::Mnemonic;
2221+
/// # use ldk_node::entropy::NodeEntropy;
22202222
/// # use rand::distr::Alphanumeric;
22212223
/// # use rand::{rng, Rng};
22222224
/// # let mut config = Config::default();
@@ -2226,7 +2228,7 @@ impl Node {
22262228
/// # temp_path.push(rand_dir);
22272229
/// # config.storage_dir_path = temp_path.display().to_string();
22282230
/// # let builder = Builder::from_config(config);
2229-
/// # let mnemonic = generate_entropy_mnemonic(None);
2231+
/// # let mnemonic = Mnemonic::generate(24).unwrap();
22302232
/// # let node_entropy = NodeEntropy::from_bip39_mnemonic(mnemonic, None);
22312233
/// # let node = builder.build(node_entropy.into()).unwrap();
22322234
/// let mut outbound = Vec::new();

tests/common/mod.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,12 @@ use bitcoin::{
3737
use electrsd::corepc_node::{Client as BitcoindClient, Node as BitcoinD};
3838
use electrsd::electrum_client::ElectrumApi;
3939
use electrsd::{corepc_node, ElectrsD};
40+
use ldk_node::bip39::Mnemonic;
4041
use ldk_node::config::{
4142
AsyncPaymentsRole, Config, ElectrumSyncConfig, EsploraSyncConfig, HRNResolverConfig,
4243
HumanReadableNamesConfig,
4344
};
44-
use ldk_node::entropy::{generate_entropy_mnemonic, NodeEntropy};
45+
use ldk_node::entropy::NodeEntropy;
4546
use ldk_node::io::sqlite_store::SqliteStore;
4647
use ldk_node::payment::{
4748
PaymentDetails, PaymentDirection, PaymentKind, PaymentStatus, TransactionType,
@@ -644,8 +645,11 @@ impl Default for TestConfig {
644645
let log_writer = Default::default();
645646
let store_type = Default::default();
646647

647-
let mnemonic = generate_entropy_mnemonic(None);
648+
let mnemonic = Mnemonic::generate(24).unwrap();
649+
#[cfg(not(feature = "uniffi"))]
648650
let node_entropy = NodeEntropy::from_bip39_mnemonic(mnemonic, None);
651+
#[cfg(feature = "uniffi")]
652+
let node_entropy = NodeEntropy::from_seed_bytes(mnemonic.to_seed("").to_vec()).unwrap();
649653
let async_payments_role = None;
650654
let wallet_rescan_from_height = None;
651655
let force_wallet_full_scan = false;

0 commit comments

Comments
 (0)