Skip to content

Commit 6e7ad52

Browse files
authored
Merge pull request #74 from BitcoinQnA/bip85pwd
ADD BIP85 PWD BASE64. #55
2 parents 00b30ff + 7f2e1c3 commit 6e7ad52

File tree

3 files changed

+60
-0
lines changed

3 files changed

+60
-0
lines changed

src/www/dev.html

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,6 +1385,26 @@ <h4>Counterparty Details</h4>
13851385
</container>
13861386
</div>
13871387
<hr>
1388+
<button class="accordion" title="Click to expand this section">BIP85: Deterministic Passwords</button>
1389+
<div class="panel">
1390+
<button class="btn" title="Click to learn more about BIP85" onclick="openInfoModal(event, 'BIP85PWD')">BIP85 PWD
1391+
Explained</button>
1392+
<div class="bip85-item bip85-bytes-input bip85">
1393+
<label for="bip85PWDLength">Password Length</label>
1394+
<input id="bip85PWDLength" class="textarea-input" type="number" title="Select the number of bytes to use."
1395+
min="20" max="86" value="21" step="1" />
1396+
</div>
1397+
<div class="bip85-item bip85 bip85-index-input">
1398+
<label for="bip85PWDIndex">BIP85 PWD Index</label>
1399+
<input id="bip85PWDIndex" class="textarea-input" type="number" title="Start from Zero and increment" min="0"
1400+
value="0" step="1" />
1401+
</div>
1402+
<div class="bip85-item bip85">
1403+
<label for="bip85PWDPassword">BIP85 Password</label>
1404+
<div class="copy-wrapper private-data"><textarea id="bip85PWDPassword" title="Private - don't share!"
1405+
class="bip85Field textarea-input" readonly title="BIP85 Password" rows="3"></textarea></div>
1406+
</div>
1407+
</div>
13881408
<button class="accordion" title="Click to expand this section">Credits and licenses</button>
13891409
<div class="panel">
13901410
<button class="btn" title="Click to see the changelog"

src/www/js/dom.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,9 @@ const setupDom = async () => {
195195
DOM.bip85ChildKey = document.getElementById('bip85ChildKey');
196196
DOM.bip85LoadParent = document.getElementById('bip85LoadParent');
197197
DOM.bip85LoadChild = document.getElementById('bip85LoadChild');
198+
DOM.bip85PWDLength = document.getElementById('bip85PWDLength');
199+
DOM.bip85PWDIndex = document.getElementById('bip85PWDIndex');
200+
DOM.bip85PWDPassword = document.getElementById('bip85PWDPassword');
198201
DOM.bip47UsePaynym = document.getElementById('bip47UsePaynym');
199202
DOM.bip47MyPaymentCode = document.getElementById('bip47MyPaymentCode');
200203
DOM.bip47MyNotificationAddress = document.getElementById(
@@ -309,6 +312,9 @@ const setupDom = async () => {
309312
calcBip47CounterParty();
310313
calculateBip47Addresses();
311314
};
315+
// listen for bip85PWD changes
316+
DOM.bip85PWDIndex.oninput = calcBip85Password;
317+
DOM.bip85PWDLength.oninput = calcBip85Password;
312318
// listen for bip85 changes
313319
DOM.bip85Application.oninput = calcBip85;
314320
DOM.bip85MnemonicLength.oninput = calcBip85;
@@ -2085,6 +2091,28 @@ const displayAccountKeys = () => {
20852091
addQRIcon(document.getElementById('pathAccountXpubQR'), xpub);
20862092
};
20872093

2094+
// Calculate BIP85 Password
2095+
const calcBip85Password = async () => {
2096+
const index = DOM.bip85PWDIndex.value;
2097+
const length = parseInt(DOM.bip85PWDLength.value);
2098+
const path = `m/83696968'/707764'/${length}'/${index}'`
2099+
const rootKeyBase58 = DOM.bip32RootKey.value;
2100+
if (!rootKeyBase58) {
2101+
return;
2102+
}
2103+
try {
2104+
const master = bip85.BIP85.fromBase58(rootKeyBase58);
2105+
const child = master.derive(path); // hex string
2106+
// one liner to convert hex to base64, remove whitespace and new lines, then slice to desired length removing padding
2107+
const pwd = btoa(child.match(/\w{2}/g).map(a=>String.fromCharCode(parseInt(a, 16))).join("")).replaceAll(/\s/g, '').slice(0, length);
2108+
DOM.bip85PWDPassword.value = pwd;
2109+
} catch (e) {
2110+
toast('BIP85: ' + e.message);
2111+
console.error('BIP85: ' + e.message);
2112+
DOM.bip85PWDPassword.value = '';
2113+
}
2114+
}
2115+
20882116
// Calculate and populate the BIP85 section
20892117
const calcBip85 = async () => {
20902118
const app = DOM.bip85Application.value;
@@ -2461,6 +2489,7 @@ const setMnemonicFromEntropy = async () => {
24612489
calculateAddresses();
24622490
fillBip32Keys();
24632491
calcBip85();
2492+
calcBip85Password();
24642493
calcBip47();
24652494
};
24662495

@@ -2487,6 +2516,7 @@ const setMnemonicFromRawEntropy = async (entropy) => {
24872516
calculateAddresses();
24882517
fillBip32Keys();
24892518
calcBip85();
2519+
calcBip85Password();
24902520
calcBip47();
24912521
};
24922522

@@ -2805,6 +2835,7 @@ const mnemonicToSeedPopulate = debounce(async () => {
28052835
calculateAddresses();
28062836
fillBip32Keys();
28072837
calcBip85();
2838+
calcBip85Password();
28082839
calcBip47();
28092840
}
28102841
fillRandomXorSeeds();

src/www/js/info.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,15 @@ window.infoHtml = {
357357
<p>
358358
Read more on the official <a href="https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki" target="_blank" rel="noopener noreferrer">BIP85 page</a>
359359
</p>`,
360+
BIP85PWD: /*html*/ `
361+
<h3>BIP85: Deterministic Passwords From BIP32 Keychains</h3>
362+
<p>
363+
BIP85 defines the standard for 'One seed to rule them all'. With BIP85 a user can deterministically derive multiple 'Child Seeds' from a single master
364+
seed. BIP85 Passwords are a way to convert the deterministic entropy from BIP85 into a password by encoding the entropy in Base64 encoding. This enables a user who might have provided their own entropy
365+
to securely generate their own master mnemonic seed (perhaps with the help of this tool), to then generate many high entropy passwords for use with other
366+
apps.
367+
</p>
368+
`,
360369
BIP86: /*html*/ `
361370
<h3>BIP86: Key Derivation for Single Key P2TR Outputs</h3>
362371
<p>

0 commit comments

Comments
 (0)