Skip to content

Commit

Permalink
Merge pull request #74 from BitcoinQnA/bip85pwd
Browse files Browse the repository at this point in the history
ADD BIP85 PWD BASE64. #55
  • Loading branch information
BitcoinQnA authored Dec 30, 2024
2 parents 00b30ff + 7f2e1c3 commit 6e7ad52
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 0 deletions.
20 changes: 20 additions & 0 deletions src/www/dev.html
Original file line number Diff line number Diff line change
Expand Up @@ -1385,6 +1385,26 @@ <h4>Counterparty Details</h4>
</container>
</div>
<hr>
<button class="accordion" title="Click to expand this section">BIP85: Deterministic Passwords</button>
<div class="panel">
<button class="btn" title="Click to learn more about BIP85" onclick="openInfoModal(event, 'BIP85PWD')">BIP85 PWD
Explained</button>
<div class="bip85-item bip85-bytes-input bip85">
<label for="bip85PWDLength">Password Length</label>
<input id="bip85PWDLength" class="textarea-input" type="number" title="Select the number of bytes to use."
min="20" max="86" value="21" step="1" />
</div>
<div class="bip85-item bip85 bip85-index-input">
<label for="bip85PWDIndex">BIP85 PWD Index</label>
<input id="bip85PWDIndex" class="textarea-input" type="number" title="Start from Zero and increment" min="0"
value="0" step="1" />
</div>
<div class="bip85-item bip85">
<label for="bip85PWDPassword">BIP85 Password</label>
<div class="copy-wrapper private-data"><textarea id="bip85PWDPassword" title="Private - don't share!"
class="bip85Field textarea-input" readonly title="BIP85 Password" rows="3"></textarea></div>
</div>
</div>
<button class="accordion" title="Click to expand this section">Credits and licenses</button>
<div class="panel">
<button class="btn" title="Click to see the changelog"
Expand Down
31 changes: 31 additions & 0 deletions src/www/js/dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,9 @@ const setupDom = async () => {
DOM.bip85ChildKey = document.getElementById('bip85ChildKey');
DOM.bip85LoadParent = document.getElementById('bip85LoadParent');
DOM.bip85LoadChild = document.getElementById('bip85LoadChild');
DOM.bip85PWDLength = document.getElementById('bip85PWDLength');
DOM.bip85PWDIndex = document.getElementById('bip85PWDIndex');
DOM.bip85PWDPassword = document.getElementById('bip85PWDPassword');
DOM.bip47UsePaynym = document.getElementById('bip47UsePaynym');
DOM.bip47MyPaymentCode = document.getElementById('bip47MyPaymentCode');
DOM.bip47MyNotificationAddress = document.getElementById(
Expand Down Expand Up @@ -309,6 +312,9 @@ const setupDom = async () => {
calcBip47CounterParty();
calculateBip47Addresses();
};
// listen for bip85PWD changes
DOM.bip85PWDIndex.oninput = calcBip85Password;
DOM.bip85PWDLength.oninput = calcBip85Password;
// listen for bip85 changes
DOM.bip85Application.oninput = calcBip85;
DOM.bip85MnemonicLength.oninput = calcBip85;
Expand Down Expand Up @@ -2085,6 +2091,28 @@ const displayAccountKeys = () => {
addQRIcon(document.getElementById('pathAccountXpubQR'), xpub);
};

// Calculate BIP85 Password
const calcBip85Password = async () => {
const index = DOM.bip85PWDIndex.value;
const length = parseInt(DOM.bip85PWDLength.value);
const path = `m/83696968'/707764'/${length}'/${index}'`
const rootKeyBase58 = DOM.bip32RootKey.value;
if (!rootKeyBase58) {
return;
}
try {
const master = bip85.BIP85.fromBase58(rootKeyBase58);
const child = master.derive(path); // hex string
// one liner to convert hex to base64, remove whitespace and new lines, then slice to desired length removing padding
const pwd = btoa(child.match(/\w{2}/g).map(a=>String.fromCharCode(parseInt(a, 16))).join("")).replaceAll(/\s/g, '').slice(0, length);
DOM.bip85PWDPassword.value = pwd;
} catch (e) {
toast('BIP85: ' + e.message);
console.error('BIP85: ' + e.message);
DOM.bip85PWDPassword.value = '';
}
}

// Calculate and populate the BIP85 section
const calcBip85 = async () => {
const app = DOM.bip85Application.value;
Expand Down Expand Up @@ -2461,6 +2489,7 @@ const setMnemonicFromEntropy = async () => {
calculateAddresses();
fillBip32Keys();
calcBip85();
calcBip85Password();
calcBip47();
};

Expand All @@ -2487,6 +2516,7 @@ const setMnemonicFromRawEntropy = async (entropy) => {
calculateAddresses();
fillBip32Keys();
calcBip85();
calcBip85Password();
calcBip47();
};

Expand Down Expand Up @@ -2805,6 +2835,7 @@ const mnemonicToSeedPopulate = debounce(async () => {
calculateAddresses();
fillBip32Keys();
calcBip85();
calcBip85Password();
calcBip47();
}
fillRandomXorSeeds();
Expand Down
9 changes: 9 additions & 0 deletions src/www/js/info.js
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,15 @@ window.infoHtml = {
<p>
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>
</p>`,
BIP85PWD: /*html*/ `
<h3>BIP85: Deterministic Passwords From BIP32 Keychains</h3>
<p>
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
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
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
apps.
</p>
`,
BIP86: /*html*/ `
<h3>BIP86: Key Derivation for Single Key P2TR Outputs</h3>
<p>
Expand Down

0 comments on commit 6e7ad52

Please sign in to comment.