aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/app.js11
-rw-r--r--src/i18n.js3
-rw-r--r--src/wallet.js15
3 files changed, 16 insertions, 13 deletions
diff --git a/src/app.js b/src/app.js
index 63b638b..c0b63b9 100644
--- a/src/app.js
+++ b/src/app.js
@@ -771,8 +771,8 @@ function createPane() {
{ class: 'col' },
h('p', { class: 'muted' }, t('genIntro')),
// BYO randomness for the seed — folded away so the common path stays
- // one button. Whatever is typed here is hashed together with the
- // device's own randomness (see newMnemonic), never used alone.
+ // one button. Deterministic on purpose: the typed text alone derives
+ // the seed (see newMnemonic), so re-typing it IS an import.
h('button', {
class: 'linklike small', style: 'align-self:flex-start',
onClick: () => { ui.ownEntropyOpen = !ui.ownEntropyOpen; render(); },
@@ -780,6 +780,7 @@ function createPane() {
ui.ownEntropyOpen
? h('div', { class: 'col gap6' },
h('p', { class: 'small muted', style: 'margin:0' }, t('entropyHint')),
+ h('div', { class: 'warn-box small' }, t('entropyWarn')),
h('textarea', {
rows: '2', style: 'font-family:var(--sans)', placeholder: t('entropyPlaceholder'),
autocapitalize: 'none', autocomplete: 'off', spellcheck: 'false',
@@ -815,12 +816,14 @@ function createPane() {
'div',
{ class: 'row gap6' },
copyBtn(ui.draftMnemonic, t('copyPhrase')),
- h(
+ // With own entropy the phrase is a pure function of the text —
+ // "Regenerate" would hand back the identical words, so it hides.
+ (ui.ownEntropy || '').trim() ? null : h(
'button',
{
class: 'btn-ghost btn-sm',
onClick: () => {
- ui.draftMnemonic = newMnemonic(128, (ui.ownEntropy || '').trim());
+ ui.draftMnemonic = newMnemonic();
render();
},
},
diff --git a/src/i18n.js b/src/i18n.js
index 6d25fd1..be83999 100644
--- a/src/i18n.js
+++ b/src/i18n.js
@@ -41,7 +41,8 @@ const STR = {
clearAll: 'Delete all',
logoutForget: 'Logout & forget all data',
entropyToggle: 'Use my own entropy',
- entropyHint: 'Type anything random — dice rolls, coin flips, shuffled cards. It gets mixed with this device’s own randomness, so it can only make the seed stronger.',
+ entropyHint: 'The seed comes from exactly what you type (SHA-256 → BIP-39). Entering the same text again recreates the same wallet, on any device.',
+ entropyWarn: '⚠ Nothing else is added: anyone who can guess this text can take your money. Use plenty of real-world randomness — think 50+ dice rolls.',
entropyPlaceholder: '4 2 6 6 1 3 5 2 …',
logoutPopBlurb: 'Your wallets stay saved on this device.',
clearAllWarn: '⚠ This removes every wallet from this device. Any wallet whose recovery phrase or key you have not backed up will be lost for good.',
diff --git a/src/wallet.js b/src/wallet.js
index 2ede69d..cdae1ff 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -66,14 +66,13 @@ export const NETS = {
export function newMnemonic(strengthBits = 128, extraEntropy = '') {
if (!extraEntropy) return generateMnemonic(wordlist, strengthBits);
- // User entropy is MIXED with the CSPRNG, never used alone: hashing the two
- // together can only add randomness — weak dice can't weaken the seed, and
- // a distrusted device RNG can't fully determine it either.
- const txt = new TextEncoder().encode(extraEntropy);
- const rnd = crypto.getRandomValues(new Uint8Array(strengthBits / 8));
- const mix = new Uint8Array(txt.length + rnd.length);
- mix.set(txt); mix.set(rnd, txt.length);
- return entropyToMnemonic(sha256(mix).slice(0, strengthBits / 8), wordlist);
+ // User entropy is used ALONE, deterministically: seed = BIP-39 from
+ // SHA-256 of exactly the typed text. The same text recreates the same
+ // wallet on any device (that's the point — it doubles as an import), and
+ // the derivation is simple enough to verify elsewhere. The flip side —
+ // guessable text is stealable money — is the UI's warning to give.
+ const digest = sha256(new TextEncoder().encode(extraEntropy));
+ return entropyToMnemonic(digest.slice(0, strengthBits / 8), wordlist);
}
// The base localStorage cache key for a wallet identity (xpub, xprv, or