Skip to content

fix(wallet-core): confirm and pin provision_wallet's entropy source as a CSPRNG - #381

Merged
Emmyt24 merged 2 commits into
Octo-Protocol-org:dev-branchfrom
Favourice01:fix/wallet-core/audit-provision-entropy-source
Sep 28, 2026
Merged

Emmyt24 merged 2 commits into
Octo-Protocol-org:dev-branchfrom
Favourice01:fix/wallet-core/audit-provision-entropy-source

Conversation

@Favourice01

Copy link
Copy Markdown

Closes #319

Audit finding

Call chain before this PR (tiny-bip39 2.0.0, rand 0.8.5 per Cargo.lock):

  1. provision_wallet (crates/wallet-core/src/provision.rs) → WalletSeed::generate()
  2. WalletSeed::generate() → bip39::Mnemonic::new(MnemonicType::Words12, …)
  3. tiny-bip39-2.0.0/src/mnemonic.rs:66 Mnemonic::new (#[cfg(feature = "rand")]) → crypto::gen_random_bytes(16)
  4. tiny-bip39-2.0.0/src/crypto.rs:24 gen_random_bytes → rand::thread_rng().fill_bytes(..)
  5. rand 0.8 ThreadRng = ChaCha12 block RNG, seeded and periodically reseeded from OsRng.

So the source was a CSPRNG. But the guarantee was implicit: it only exists while tiny-bip39's default rand feature is on, and the algorithm is a rand implementation detail that a version bump could change without anyone noticing.

Change

  • WalletSeed::generate() now fills 16 bytes of entropy from rand::rngs::OsRng (getrandom(2)), zeroizes the buffer, and builds the mnemonic with Mnemonic::from_entropy. Mnemonic::new is no longer called.
  • A permanent doc comment on WalletSeed::generate() records the source, plus a doc-test.
  • Pinning notes are in the workspace Cargo.toml (tiny-bip39, rand), crates/wallet-core/Cargo.toml, and docs/architecture.md ("Entropy source (load-bearing)").

Tests

  • generated_mnemonics_never_collide_across_a_large_sample: draws 10,000 mnemonics with no collision, then checks that two full generate() calls differ. This is a smoke test, not a randomness-quality audit.
  • Doc-test on WalletSeed::generate.
  • cargo test -p octo-wallet-core: all pass.

…s a CSPRNG

provision_wallet's mnemonic generation depended transitively on tiny-bip39's
Mnemonic::new, which draws entropy from rand::thread_rng() only when the crate's
default `rand` feature is enabled. Generate the 128-bit entropy from OsRng
explicitly and build the mnemonic with Mnemonic::from_entropy, so the guarantee
no longer rests on a dependency default. Documents the source on
WalletSeed::generate, in Cargo.toml and in docs/architecture.md, and adds a
collision smoke test.

Closes Octo-Protocol-org#319
@drips-wave

drips-wave Bot commented Sep 26, 2026

Copy link
Copy Markdown

@Favourice01 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

…re/audit-provision-entropy-source

# Conflicts:
#	crates/wallet-core/src/derive.rs
#	docs/architecture.md
@Emmyt24
Emmyt24 merged commit e531a07 into Octo-Protocol-org:dev-branch Sep 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Confirm provision_wallet's generated mnemonic entropy source is a CSPRNG, not a weaker default

2 participants