Skip to content

Commit 05cb330

Browse files
committed
feat: add configurable BIP39 mnemonic word counts
Support generating BIP39 mnemonics with configurable word counts (12, 15, 18, 21, 24). Defaults to 24 words (256-bit entropy) for backward compatibility. - Add MnemonicWordCount enum (12–24 variants) - Update generate_entropy_mnemonic to accept optional word_count - Map word counts to correct entropy sizes per BIP39 - Extend tests for all word count options and defaults - Expose enum and updated function in UDL bindings
1 parent cef82e4 commit 05cb330

File tree

4 files changed

+75
-9
lines changed

4 files changed

+75
-9
lines changed

bindings/ldk_node.udl

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
namespace ldk_node {
2-
Mnemonic generate_entropy_mnemonic();
2+
Mnemonic generate_entropy_mnemonic(MnemonicWordCount? word_count);
33
Config default_config();
44
};
55

@@ -46,6 +46,14 @@ dictionary LSPS2ServiceConfig {
4646
u64 max_payment_size_msat;
4747
};
4848

49+
enum MnemonicWordCount {
50+
"Words12",
51+
"Words15",
52+
"Words18",
53+
"Words21",
54+
"Words24",
55+
};
56+
4957
enum LogLevel {
5058
"Gossip",
5159
"Trace",

src/io/utils.rs

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,23 +47,26 @@ use crate::io::{
4747
};
4848
use crate::logger::{log_error, LdkLogger, Logger};
4949
use crate::peer_store::PeerStore;
50-
use crate::types::{Broadcaster, DynStore, KeysManager, Sweeper};
50+
use crate::types::{Broadcaster, DynStore, KeysManager, MnemonicWordCount, Sweeper};
5151
use crate::wallet::ser::{ChangeSetDeserWrapper, ChangeSetSerWrapper};
5252
use crate::{Error, EventQueue, NodeMetrics, PaymentDetails};
5353

5454
pub const EXTERNAL_PATHFINDING_SCORES_CACHE_KEY: &str = "external_pathfinding_scores_cache";
5555

56-
/// Generates a random [BIP 39] mnemonic.
56+
/// Generates a random [BIP 39] mnemonic with the specified word count.
57+
///
58+
/// If no word count is specified, defaults to 24 words (256-bit entropy).
5759
///
5860
/// The result may be used to initialize the [`Node`] entropy, i.e., can be given to
5961
/// [`Builder::set_entropy_bip39_mnemonic`].
6062
///
6163
/// [BIP 39]: https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki
6264
/// [`Node`]: crate::Node
6365
/// [`Builder::set_entropy_bip39_mnemonic`]: crate::Builder::set_entropy_bip39_mnemonic
64-
pub fn generate_entropy_mnemonic() -> Mnemonic {
65-
// bip39::Mnemonic supports 256 bit entropy max
66-
let mut entropy = [0; 32];
66+
pub fn generate_entropy_mnemonic(word_count: Option<MnemonicWordCount>) -> Mnemonic {
67+
let word_count = word_count.unwrap_or(MnemonicWordCount::Words24);
68+
let entropy_bytes = word_count.entropy_bytes();
69+
let mut entropy = vec![0u8; entropy_bytes];
6770
OsRng.try_fill_bytes(&mut entropy).expect("Failed to generate entropy");
6871
Mnemonic::from_entropy(&entropy).unwrap()
6972
}
@@ -627,9 +630,35 @@ mod tests {
627630

628631
#[test]
629632
fn mnemonic_to_entropy_to_mnemonic() {
630-
let mnemonic = generate_entropy_mnemonic();
631-
633+
// Test default (24 words)
634+
let mnemonic = generate_entropy_mnemonic(None);
632635
let entropy = mnemonic.to_entropy();
633636
assert_eq!(mnemonic, Mnemonic::from_entropy(&entropy).unwrap());
637+
assert_eq!(mnemonic.word_count(), 24);
638+
639+
// Test with different word counts
640+
let word_counts = [
641+
MnemonicWordCount::Words12,
642+
MnemonicWordCount::Words15,
643+
MnemonicWordCount::Words18,
644+
MnemonicWordCount::Words21,
645+
MnemonicWordCount::Words24,
646+
];
647+
648+
for word_count in word_counts {
649+
let mnemonic = generate_entropy_mnemonic(Some(word_count));
650+
let entropy = mnemonic.to_entropy();
651+
assert_eq!(mnemonic, Mnemonic::from_entropy(&entropy).unwrap());
652+
653+
// Verify expected word count
654+
let expected_words = match word_count {
655+
MnemonicWordCount::Words12 => 12,
656+
MnemonicWordCount::Words15 => 15,
657+
MnemonicWordCount::Words18 => 18,
658+
MnemonicWordCount::Words21 => 21,
659+
MnemonicWordCount::Words24 => 24,
660+
};
661+
assert_eq!(mnemonic.word_count(), expected_words);
662+
}
634663
}
635664
}

src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,8 @@ use types::{
155155
OnionMessenger, PaymentStore, PeerManager, Router, Scorer, Sweeper, Wallet,
156156
};
157157
pub use types::{
158-
ChannelDetails, CustomTlvRecord, DynStore, PeerDetails, SyncAndAsyncKVStore, UserChannelId,
158+
ChannelDetails, CustomTlvRecord, DynStore, MnemonicWordCount, PeerDetails, SyncAndAsyncKVStore,
159+
UserChannelId,
159160
};
160161
pub use {
161162
bip39, bitcoin, lightning, lightning_invoice, lightning_liquidity, lightning_types, tokio,

src/types.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,34 @@ use crate::logger::Logger;
3636
use crate::message_handler::NodeCustomMessageHandler;
3737
use crate::payment::PaymentDetails;
3838

39+
/// Supported BIP39 mnemonic word counts for entropy generation.
40+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
41+
pub enum MnemonicWordCount {
42+
/// 12-word mnemonic (128-bit entropy)
43+
Words12,
44+
/// 15-word mnemonic (160-bit entropy)
45+
Words15,
46+
/// 18-word mnemonic (192-bit entropy)
47+
Words18,
48+
/// 21-word mnemonic (224-bit entropy)
49+
Words21,
50+
/// 24-word mnemonic (256-bit entropy)
51+
Words24,
52+
}
53+
54+
impl MnemonicWordCount {
55+
/// Returns the entropy size in bytes for the word count.
56+
pub fn entropy_bytes(&self) -> usize {
57+
match self {
58+
MnemonicWordCount::Words12 => 16, // 128 bits
59+
MnemonicWordCount::Words15 => 20, // 160 bits
60+
MnemonicWordCount::Words18 => 24, // 192 bits
61+
MnemonicWordCount::Words21 => 28, // 224 bits
62+
MnemonicWordCount::Words24 => 32, // 256 bits
63+
}
64+
}
65+
}
66+
3967
/// A supertrait that requires that a type implements both [`KVStore`] and [`KVStoreSync`] at the
4068
/// same time.
4169
pub trait SyncAndAsyncKVStore: KVStore + KVStoreSync {}

0 commit comments

Comments
 (0)