// https://github.com/MetaMask/eth-simple-keyring/blob/a1ce8d2c360e348d49e980915a4a94feb270e4e2/index.js#L16 functiongenerateKey() { const privateKey = randomBytes(32); // I don't think this is possible, but this validation was here previously, // so it has been preserved just in case. // istanbul ignore next if (!ethUtil.isValidPrivate(privateKey)) { thrownewError( 'Private key does not satisfy the curve requirements (ie. it is invalid)', ); } return privateKey; }
// generate random bytes. // https://github.com/crypto-browserify/randombytes/blob/master/browser.jshttps://github.com/crypto-browserify/randombytes/blob/master/browser.js functionrandomBytes (size, cb) { // phantomjs needs to throw if (size > MAX_UINT32) thrownewRangeError('requested too many random bytes')
var bytes = Buffer.allocUnsafe(size)
if (size > 0) { // getRandomValues fails on IE if size == 0 if (size > MAX_BYTES) { // this is the max bytes crypto.getRandomValues // can do at once see . // https://developer.mozilla.org/en-US/docs/Web/API/window.crypto.getRandomValues for (var generated = 0; generated < size; generated += MAX_BYTES) { // buffer.slice automatically checks if the end is past the end of // the buffer so we don't have to here. // generate random numbers.The Crypto.getRandomValues() method lets you get cryptographically strong random values. crypto.getRandomValues(bytes.slice(generated, generated + MAX_BYTES)) } } else { crypto.getRandomValues(bytes) } }
// https://github.com/MetaMask/eth-simple-keyring/blob/a1ce8d2c360e348d49e980915a4a94feb270e4e2/index.js#L16 asyncaddAccounts(n = 1) { const newWallets = []; for (let i = 0; i < n; i++) { const privateKey = generateKey(); // get public key from private key. const publicKey = ethUtil.privateToPublic(privateKey); newWallets.push({ privateKey, publicKey }); } this._wallets = this._wallets.concat(newWallets); const hexWallets = newWallets.map(({ publicKey }) => ethUtil.bufferToHex(ethUtil.publicToAddress(publicKey)), ); return hexWallets; }
// https://github.com/ethereumjs/ethereumjs-util/blob/ebf40a0fba8b00ba9acae58405bca4415e383a0d/src/account.ts exportconst privateToPublic = function(privateKey: Buffer): Buffer { assertIsBuffer(privateKey) // skip the type flag and use the X, Y points returnBuffer.from(publicKeyCreate(privateKey, false)).slice(1) }
// transform the private key to a number(value). functionnormalizePrivateKey(key: PrivKey): bigint { letnum: bigint; if (typeof key === 'bigint') { num = key; } elseif (typeof key === 'number' && Number.isSafeInteger(key) && key > 0) { num = BigInt(key); } elseif (typeof key === 'string') { if (key.length !== 64) thrownewError('Expected 32 bytes of private key'); num = hexToNumber(key); } elseif (key instanceofUint8Array) { if (key.length !== 32) thrownewError('Expected 32 bytes of private key'); num = bytesToNumber(key); } else { thrownewTypeError('Expected valid private key'); } if (!isWithinCurveOrder(num)) thrownewError('Expected private key: 0 < key < n'); return num; }
// https://github.com/paulmillr/noble-secp256k1/blob/88c35c2b30ae6f803e57bb3c78ddebbb4f6f0eaa/index.ts#L861 functionisWithinCurveOrder(num: bigint): boolean { return0 < num && num < CURVE.n; }
// https://github.com/paulmillr/noble-secp256k1/blob/88c35c2b30ae6f803e57bb3c78ddebbb4f6f0eaa/index.ts#L21 // CAUTION: //this is the max private key value. // 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 CURVE.n = POW_2_256 - BigInt('432420386565659656852420866394968145599')
椭圆曲线方程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
// https://github.com/paulmillr/noble-secp256k1/blob/88c35c2b30ae6f803e57bb3c78ddebbb4f6f0eaa/index.ts#L13 constCURVE = { // Params: a, b a: _0n, b: BigInt(7), // Field over which we'll do calculations P: POW_2_256 - _2n ** BigInt(32) - BigInt(977), // Curve order. Specifically, it belongs to prime-order subgroup; // but our curve is h=1, so other subgroups don't exist n: POW_2_256 - BigInt('432420386565659656852420866394968145599'), // Cofactor h: _1n, // Base point (x, y) aka generator point Gx: BigInt('55066263022277343669578718895168534326250603453777594175500187360389116729240'), Gy: BigInt('32670510020758816978083085130507043184471273380659243275938904335757337482424'), // For endomorphism, see below beta: BigInt('0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee'), };
// https://github.com/ethereumjs/ethereumjs-util/blob/ebf40a0fba8b00ba9acae58405bca4415e383a0d/src/account.ts exportconst pubToAddress = function(pubKey: Buffer, sanitize: boolean = false): Buffer { assertIsBuffer(pubKey) if (sanitize && pubKey.length !== 64) { pubKey = Buffer.from(publicKeyConvert(pubKey, false).slice(1)) } // public key length should 64 assert(pubKey.length === 64) // Only take the lower 160bits of the hash returnkeccak(pubKey).slice(-20) }
// https://github.com/ethereum/js-ethereum-cryptography/blob/bce953bceb9b7bf125c276e10e69e4de3eb96eed/src/secp256k1-compat.ts // guarantee the length should be 64,if public key length can not satisfied. exportfunctionpublicKeyConvert( publicKey: Uint8Array, compressed = true, // binary or hex. out?: Output ): Uint8Array { // So, public key length should in [32,64] . assertBytes(publicKey, 33, 65); assertBool(compressed); const res = secp.Point.fromHex(publicKey).toRawBytes(compressed); returnoutput(out, compressed ? 33 : 65, res); }