Add comprehensive installation and setup documentation

- Add GETTING_STARTED.md with quick start guide and development modes
- Add INSTALL.sh automated installation script
- Add INSTALLATION_CHECKLIST.md, INSTALLATION_SUCCESS.md, and INSTALLATION_SUMMARY.md
- Add QUICK_REFERENCE.md for common commands
- Add SETUP_GUIDE.md with detailed setup instructions
- Update README.md with improved project overview
- Add did-wallet app dependencies and node_modules
This commit is contained in:
Dorian
2026-01-27 17:18:21 +00:00
parent a81f655133
commit 0d073fa89e
22658 changed files with 4494151 additions and 6 deletions
+134
View File
@@ -0,0 +1,134 @@
/*! scure-bip39 - MIT License (c) 2022 Patricio Palladino, Paul Miller (paulmillr.com) */
import { bytes as assertBytes, number as assertNumber } from '@noble/hashes/_assert';
import { pbkdf2, pbkdf2Async } from '@noble/hashes/pbkdf2';
import { sha256 } from '@noble/hashes/sha256';
import { sha512 } from '@noble/hashes/sha512';
import { randomBytes } from '@noble/hashes/utils';
import { utils as baseUtils } from '@scure/base';
// Japanese wordlist
const isJapanese = (wordlist) => wordlist[0] === '\u3042\u3044\u3053\u304f\u3057\u3093';
// Normalization replaces equivalent sequences of characters
// so that any two texts that are equivalent will be reduced
// to the same sequence of code points, called the normal form of the original text.
// https://tonsky.me/blog/unicode/#why-is-a----
function nfkd(str) {
if (typeof str !== 'string')
throw new TypeError(`Invalid mnemonic type: ${typeof str}`);
return str.normalize('NFKD');
}
function normalize(str) {
const norm = nfkd(str);
const words = norm.split(' ');
if (![12, 15, 18, 21, 24].includes(words.length))
throw new Error('Invalid mnemonic');
return { nfkd: norm, words };
}
function assertEntropy(entropy) {
assertBytes(entropy, 16, 20, 24, 28, 32);
}
/**
* Generate x random words. Uses Cryptographically-Secure Random Number Generator.
* @param wordlist imported wordlist for specific language
* @param strength mnemonic strength 128-256 bits
* @example
* generateMnemonic(wordlist, 128)
* // 'legal winner thank year wave sausage worth useful legal winner thank yellow'
*/
export function generateMnemonic(wordlist, strength = 128) {
assertNumber(strength);
if (strength % 32 !== 0 || strength > 256)
throw new TypeError('Invalid entropy');
return entropyToMnemonic(randomBytes(strength / 8), wordlist);
}
const calcChecksum = (entropy) => {
// Checksum is ent.length/4 bits long
const bitsLeft = 8 - entropy.length / 4;
// Zero rightmost "bitsLeft" bits in byte
// For example: bitsLeft=4 val=10111101 -> 10110000
return new Uint8Array([(sha256(entropy)[0] >> bitsLeft) << bitsLeft]);
};
function getCoder(wordlist) {
if (!Array.isArray(wordlist) || wordlist.length !== 2048 || typeof wordlist[0] !== 'string')
throw new Error('Wordlist: expected array of 2048 strings');
wordlist.forEach((i) => {
if (typeof i !== 'string')
throw new Error(`Wordlist: non-string element: ${i}`);
});
return baseUtils.chain(baseUtils.checksum(1, calcChecksum), baseUtils.radix2(11, true), baseUtils.alphabet(wordlist));
}
/**
* Reversible: Converts mnemonic string to raw entropy in form of byte array.
* @param mnemonic 12-24 words
* @param wordlist imported wordlist for specific language
* @example
* const mnem = 'legal winner thank year wave sausage worth useful legal winner thank yellow';
* mnemonicToEntropy(mnem, wordlist)
* // Produces
* new Uint8Array([
* 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
* 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f
* ])
*/
export function mnemonicToEntropy(mnemonic, wordlist) {
const { words } = normalize(mnemonic);
const entropy = getCoder(wordlist).decode(words);
assertEntropy(entropy);
return entropy;
}
/**
* Reversible: Converts raw entropy in form of byte array to mnemonic string.
* @param entropy byte array
* @param wordlist imported wordlist for specific language
* @returns 12-24 words
* @example
* const ent = new Uint8Array([
* 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
* 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f
* ]);
* entropyToMnemonic(ent, wordlist);
* // 'legal winner thank year wave sausage worth useful legal winner thank yellow'
*/
export function entropyToMnemonic(entropy, wordlist) {
assertEntropy(entropy);
const words = getCoder(wordlist).encode(entropy);
return words.join(isJapanese(wordlist) ? '\u3000' : ' ');
}
/**
* Validates mnemonic for being 12-24 words contained in `wordlist`.
*/
export function validateMnemonic(mnemonic, wordlist) {
try {
mnemonicToEntropy(mnemonic, wordlist);
}
catch (e) {
return false;
}
return true;
}
const salt = (passphrase) => nfkd(`mnemonic${passphrase}`);
/**
* Irreversible: Uses KDF to derive 64 bytes of key data from mnemonic + optional password.
* @param mnemonic 12-24 words
* @param passphrase string that will additionally protect the key
* @returns 64 bytes of key data
* @example
* const mnem = 'legal winner thank year wave sausage worth useful legal winner thank yellow';
* await mnemonicToSeed(mnem, 'password');
* // new Uint8Array([...64 bytes])
*/
export function mnemonicToSeed(mnemonic, passphrase = '') {
return pbkdf2Async(sha512, normalize(mnemonic).nfkd, salt(passphrase), { c: 2048, dkLen: 64 });
}
/**
* Irreversible: Uses KDF to derive 64 bytes of key data from mnemonic + optional password.
* @param mnemonic 12-24 words
* @param passphrase string that will additionally protect the key
* @returns 64 bytes of key data
* @example
* const mnem = 'legal winner thank year wave sausage worth useful legal winner thank yellow';
* mnemonicToSeedSync(mnem, 'password');
* // new Uint8Array([...64 bytes])
*/
export function mnemonicToSeedSync(mnemonic, passphrase = '') {
return pbkdf2(sha512, normalize(mnemonic).nfkd, salt(passphrase), { c: 2048, dkLen: 64 });
}
+3
View File
@@ -0,0 +1,3 @@
{
"type": "module"
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff