mirror of
https://github.com/XRPLF/xrpl-dev-portal.git
synced 2025-12-06 17:27:57 +00:00
Update key-derivation sample
This commit is contained in:
@@ -3,16 +3,49 @@
|
||||
// Organize imports
|
||||
const assert = require("assert")
|
||||
const brorand = require("brorand")
|
||||
const BN = require("bn.js")
|
||||
const { BigNumber } = require("bignumber.js")
|
||||
const elliptic = require("elliptic");
|
||||
const Ed25519 = elliptic.eddsa('ed25519');
|
||||
const Secp256k1 = elliptic.ec('secp256k1');
|
||||
const hashjs = require("hash.js");
|
||||
const Sha512 = require("ripple-keypairs/dist/Sha512")
|
||||
const isomorphic = require("@xrplf/isomorphic/sha512")
|
||||
const noble = require('@noble/curves/abstract/utils')
|
||||
const { codec, encodeAccountPublic, encodeNodePublic } = require("ripple-address-codec");
|
||||
|
||||
const XRPL_SEED_PREFIX = 0x21
|
||||
|
||||
class Sha512 {
|
||||
// instantiate empty sha512 hash
|
||||
hash = isomorphic.sha512.create()
|
||||
|
||||
static half(input) {
|
||||
return new Sha512().add(input).first256()
|
||||
}
|
||||
|
||||
add(bytes) {
|
||||
this.hash.update(bytes)
|
||||
return this
|
||||
}
|
||||
|
||||
addU32(i) {
|
||||
const buffer = new Uint8Array(4)
|
||||
new DataView(buffer.buffer).setUint32(0, i)
|
||||
return this.add(buffer)
|
||||
}
|
||||
|
||||
finish() {
|
||||
return this.hash.digest()
|
||||
}
|
||||
|
||||
first256() {
|
||||
return this.finish().slice(0, 32)
|
||||
}
|
||||
|
||||
first256BigInt() {
|
||||
return noble.bytesToNumberBE(this.first256())
|
||||
}
|
||||
}
|
||||
|
||||
const isHex = function(value) {
|
||||
const regex = new RegExp(/^[0-9a-f]+$/, 'i')
|
||||
return regex.test(value)
|
||||
@@ -27,7 +60,7 @@ const bytesToHex = function(bytes) {
|
||||
|
||||
const hexToBytes = function(hex) {
|
||||
assert.ok(hex.length % 2 === 0);
|
||||
return hex.length === 0 ? [] : new BN(hex, 16).toArray(null, hex.length / 2);
|
||||
return hex.length === 0 ? [] : new BigNumber(hex, 16).toArray(null, hex.length / 2);
|
||||
}
|
||||
|
||||
const encodeUTF8 = function (string) {
|
||||
@@ -87,7 +120,7 @@ class Seed {
|
||||
const publicKey = prefix + bytesToHex(Ed25519.keyFromSecret(rawPrivateKey).pubBytes());
|
||||
return { privateKey, publicKey };
|
||||
}
|
||||
|
||||
|
||||
_deriveSecp256K1Keypair(entropy, options) {
|
||||
const prefix = '00';
|
||||
const privateKey = prefix + this._deriveSecp256K1PrivateKey(entropy, options).toString(16, 64).toUpperCase()
|
||||
@@ -112,27 +145,25 @@ class Seed {
|
||||
// Almost everyone just uses the first account, `0`.
|
||||
const accountIndex = opts.accountIndex || 0;
|
||||
|
||||
return this._deriveScalar(publicGen.encodeCompressed(), accountIndex)
|
||||
.add(privateGen)
|
||||
.mod(order);
|
||||
const scalar = this._deriveScalar(publicGen.encodeCompressed(), accountIndex)
|
||||
return BigNumber(scalar).plus(privateGen).mod(order);
|
||||
}
|
||||
|
||||
_deriveScalar(bytes, discrim) {
|
||||
const order = Secp256k1.curve.n;
|
||||
for (let i = 0; i <= 0xffffffff; i++) {
|
||||
// We hash the bytes to find a 256 bit number, looping until we are sure it
|
||||
const order = Secp256k1.curve.n
|
||||
for (let i = 0; i <= 0xffff_ffff; i++) {
|
||||
// We hash the bytes to find a 256-bit number, looping until we are sure it
|
||||
// is less than the order of the curve.
|
||||
const hasher = new Sha512.default().add(bytes);
|
||||
const hasher = new Sha512().add(bytes)
|
||||
// If the optional discriminator index was passed in, update the hash.
|
||||
if (discrim !== undefined) {
|
||||
hasher.addU32(discrim);
|
||||
hasher.addU32(discrim)
|
||||
}
|
||||
hasher.addU32(i);
|
||||
const key = hasher.first256BN();
|
||||
hasher.addU32(i)
|
||||
const key = hasher.first256BigInt()
|
||||
/* istanbul ignore else */
|
||||
/* istanbul ignore else */
|
||||
if (key.cmpn(0) > 0 && key.cmp(order) < 0) {
|
||||
return key;
|
||||
if (key > 0 && key < order) {
|
||||
return key
|
||||
}
|
||||
}
|
||||
// This error is practically impossible to reach.
|
||||
@@ -141,10 +172,10 @@ class Seed {
|
||||
// How often will an (essentially) random number generated by Sha512 be larger than that?
|
||||
// There's 2^32 chances (the for loop) to get a number smaller than the order,
|
||||
// and it's rare that you'll even get past the first loop iteration.
|
||||
// Note that in TypeScript we actually need the throw, otherwise the function signature would be BN | undefined
|
||||
// Note that in TypeScript we actually need the throw, otherwise the function signature would be bigint | undefined
|
||||
//
|
||||
/* istanbul ignore next */
|
||||
throw new Error('impossible unicorn ;)');
|
||||
throw new Error('impossible unicorn ;)')
|
||||
}
|
||||
|
||||
getBase58ED25519Account() {
|
||||
|
||||
@@ -3,7 +3,16 @@
|
||||
"version": "0.1.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"xrpl": "^2.11.0"
|
||||
"@noble/curves": "^1.3.0",
|
||||
"@xrplf/isomorphic": "^1.0.0",
|
||||
"bignumber.js": "^9.1.2",
|
||||
"brorand": "^1.1.0",
|
||||
"elliptic": "^6.5.4",
|
||||
"hash.js": "^1.1.7",
|
||||
"ripple-address-codec": "^5.0.0",
|
||||
"ripple-keypairs": "^2.0.0",
|
||||
"secp256k1": "^5.0.0",
|
||||
"xrpl": "^3.0.0"
|
||||
},
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
||||
Reference in New Issue
Block a user