UNPKG

@taquito/signer

Version:

Software signer implementations and signing utilities for Taquito.

154 lines (153 loc) 5.88 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PrivateKey = void 0; /* eslint-disable @typescript-eslint/no-this-alias */ const secp256k1_1 = require("@noble/curves/secp256k1"); const nist_1 = require("@noble/curves/nist"); const types_1 = require("./types"); const hmac_js_1 = require("@noble/hashes/hmac.js"); const sha2_js_1 = require("@noble/hashes/sha2.js"); const bn_js_1 = require("bn.js"); const utils_1 = require("./utils"); const errors_1 = require("../errors"); const core_1 = require("@taquito/core"); const seedKey = { p256: 'Nist256p1 seed', secp256k1: 'Bitcoin seed', }; // MinSeedSize is the minimal allowed seed byte length const minSeedSize = 16; // MaxSeedSize is the maximal allowed seed byte length const maxSeedSize = 64; class PrivateKey { /** * * @param priv { secretKey: BN, curve: 'p256' | 'secp256k1' } * @param chainCode slice 32->n HMAC hash key and seedkey (first instance curve default seedKey. after hmac value slice 32->n) */ constructor(priv, chainCode) { this.priv = priv; this.chainCode = chainCode; const privateKeyBytes = priv.secretKey.toArray('be', 32); const privateKeyUint8 = new Uint8Array(privateKeyBytes); const publicKey = priv.curve === 'secp256k1' ? secp256k1_1.secp256k1.getPublicKey(privateKeyUint8, true) // compressed public key : nist_1.p256.getPublicKey(privateKeyUint8, true); // compressed public key this.keyPair = { curve: priv.curve, secretKey: priv.secretKey, publicKey: publicKey, }; } /** * @param seedSrc result of Bip39.mnemonicToSeed * @param curve known supported curve p256 or secp256k1 * @returns instance of PrivateKey non-HD keys derived * @throws InvalidBitSize | InvalidCurveError | InvalidSeedLengthError */ static fromSeed(seedSrc, curve) { let seed = typeof seedSrc === 'string' ? (0, utils_1.parseHex)(seedSrc) : seedSrc; if (seed.length < minSeedSize || seed.length > maxSeedSize) { throw new errors_1.InvalidSeedLengthError(seed.length); } if (!Object.prototype.hasOwnProperty.call(seedKey, curve)) { throw new errors_1.InvalidCurveError(`Unsupported curve "${curve}" expecting either "p256" or "secp256k1"`); } // Get curve order for validation let curveOrder; if (curve === 'secp256k1') { curveOrder = new bn_js_1.default(secp256k1_1.secp256k1.Point.CURVE().n.toString()); } else { curveOrder = new bn_js_1.default(nist_1.p256.Point.CURVE().n.toString()); } if (curveOrder.bitLength() !== 256) { throw new errors_1.InvalidBitSize(`Invalid curve "${curve}" with bit size "${curveOrder.bitLength()}" expecting bit size "256"`); } const key = new TextEncoder().encode(seedKey[curve]); let d = null; let chain = new Uint8Array(); let i = 0; while (i === 0) { const sum = (0, hmac_js_1.hmac)(sha2_js_1.sha512, key, seed); d = new bn_js_1.default(sum.subarray(0, 32)); chain = sum.subarray(32); if (d.isZero() || d.cmp(curveOrder) >= 0) { seed = sum; } else { i++; } } return new PrivateKey({ curve, secretKey: d }, chain); } /** * * @param index derivation path item pre-hardened if applicable ie: 44' -> 2^31 + 44 * @returns child PrivateKey of the current PrivateKey */ derive(index) { const data = new Uint8Array(37); if ((index & types_1.Hard) !== 0) { // hardened derivation data.set(this.keyPair.secretKey.toArray(), 1); } else { data.set(this.keyPair.publicKey, 0); } new DataView(data.buffer).setUint32(33, index); let d = new bn_js_1.default(0); let chain = new Uint8Array(); let i = 0; while (i === 0) { const sum = (0, hmac_js_1.hmac)(sha2_js_1.sha512, this.chainCode, data); d = new bn_js_1.default(sum.subarray(0, 32)); chain = sum.subarray(32); // Get curve order for comparison let curveOrder; if (this.keyPair.curve === 'secp256k1') { curveOrder = new bn_js_1.default(secp256k1_1.secp256k1.Point.CURVE().n.toString()); } else { curveOrder = new bn_js_1.default(nist_1.p256.Point.CURVE().n.toString()); } if (d.cmp(curveOrder) < 0) { d = d.add(this.keyPair.secretKey).mod(curveOrder); if (!d.isZero()) { i++; } } data.set(chain, 1); data[0] = 1; } return new PrivateKey({ curve: this.keyPair.curve, secretKey: d }, chain); } /** * * @param path pre-hardened (if applicable) derivation path items ie 44'/1729'/0/0 -> 2^31 + 44/2^31 + 1729/0/0 * @returns final child of the full HD keys derivation */ derivePath(path) { let key = this; for (const x of path) { key = key.derive(x); } return key; } /** * * @returns Uint8Array (if contains a private key) * @throws InvalidKeyError */ bytes() { if (!this.keyPair.secretKey) { throw new core_1.InvalidKeyError('missing private key'); } // pad to 32 bytes as toArray() length argument seems to be ignored (BN bug) const src = this.keyPair.secretKey.toArray(); const out = new Uint8Array(32); out.set(src, out.length - src.length); return out; } } exports.PrivateKey = PrivateKey;