@taquito/signer
Version:
Software signer implementations and signing utilities for Taquito.
154 lines (153 loc) • 5.88 kB
JavaScript
"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;