@taquito/signer
Version:
Software signer implementations and signing utilities for Taquito.
205 lines (204 loc) • 10.1 kB
JavaScript
;
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _InMemorySigner_key;
Object.defineProperty(exports, "__esModule", { value: true });
exports.InMemorySigner = void 0;
exports.publicKeyFromString = publicKeyFromString;
const nacl_1 = require("@stablelib/nacl");
const utils_1 = require("@taquito/utils");
const typedarray_to_buffer_1 = require("typedarray-to-buffer");
const ed_key_1 = require("./ed-key");
const ec_key_1 = require("./ec-key");
const bip39 = require("@scure/bip39");
const english_js_1 = require("@scure/bip39/wordlists/english.js");
const pbkdf2_js_1 = require("@noble/hashes/pbkdf2.js");
const helpers_1 = require("./helpers");
const errors_1 = require("./errors");
const core_1 = require("@taquito/core");
const key_interface_1 = require("./key-interface");
const bls_key_1 = require("./bls-key");
const sha2_js_1 = require("@noble/hashes/sha2.js");
/**
* A local implementation of the signer. Will represent a Tezos account and be able to produce signature in its behalf
*
* @remarks If running in production and dealing with tokens that have real value, it is strongly recommended to use a HSM backed signer so that private key material is not stored in memory or on disk
* @throws InvalidMnemonicError
*/
class InMemorySigner {
static fromFundraiser(email, password, mnemonic) {
if (!bip39.validateMnemonic(mnemonic, english_js_1.wordlist)) {
throw new errors_1.InvalidMnemonicError();
}
const seed = bip39.mnemonicToSeedSync(mnemonic, `${email}${password}`);
const key = (0, utils_1.b58Encode)(seed.subarray(0, 32), utils_1.PrefixV2.Ed25519Seed);
return new InMemorySigner(key);
}
static async fromSecretKey(key, passphrase) {
return new InMemorySigner(key, passphrase);
}
/**
*
* Instantiation of an InMemorySigner instance from a mnemonic
* @returns InMemorySigner
* @throws InvalidMnemonicError
*/
static fromMnemonic({ mnemonic, password = '', derivationPath = "44'/1729'/0'/0'", curve = 'ed25519', }) {
// check if curve is defined if not default tz1
if (!bip39.validateMnemonic(mnemonic, english_js_1.wordlist)) {
// avoiding exposing mnemonic again in case of mistake making invalid
throw new errors_1.InvalidMnemonicError();
}
const seed = bip39.mnemonicToSeedSync(mnemonic, password);
const sk = (0, helpers_1.generateSecretKey)(seed, derivationPath, curve);
return new InMemorySigner(sk);
}
/**
*
* @param key Encoded private key
* @param passphrase Passphrase to decrypt the private key if it is encrypted
* @throws InvalidKeyError
*
*/
constructor(key, passphrase) {
_InMemorySigner_key.set(this, void 0);
const keyPrefixes = [
utils_1.PrefixV2.Ed25519EncryptedSeed,
utils_1.PrefixV2.Ed25519Seed,
utils_1.PrefixV2.Ed25519SecretKey,
utils_1.PrefixV2.Secp256k1EncryptedSecretKey,
utils_1.PrefixV2.Secp256k1SecretKey,
utils_1.PrefixV2.P256EncryptedSecretKey,
utils_1.PrefixV2.P256SecretKey,
utils_1.PrefixV2.BLS12_381EncryptedSecretKey,
utils_1.PrefixV2.BLS12_381SecretKey,
];
const pre = (() => {
try {
const [, pre] = (0, utils_1.b58DecodeAndCheckPrefix)(key, keyPrefixes);
return pre;
}
catch {
throw new core_1.InvalidKeyError(`Invalid private key, expecting one of the following prefixes '${keyPrefixes}'.`);
}
})();
const encrypted = pre === utils_1.PrefixV2.Ed25519EncryptedSeed ||
pre === utils_1.PrefixV2.Secp256k1EncryptedSecretKey ||
pre === utils_1.PrefixV2.P256EncryptedSecretKey ||
pre === utils_1.PrefixV2.BLS12_381EncryptedSecretKey;
let decrypt;
if (encrypted) {
if (!passphrase) {
throw new errors_1.InvalidPassphraseError('No passphrase provided to decrypt encrypted key');
}
decrypt = (data) => {
const salt = (0, typedarray_to_buffer_1.default)(data.slice(0, 8));
const encryptedSk = data.slice(8);
const encryptionKey = (0, pbkdf2_js_1.pbkdf2)(sha2_js_1.sha512, passphrase, salt, { c: 32768, dkLen: 32 });
// Zero nonce is safe here: Tezos encrypted key format uses a fresh random salt per
// encryption, producing a unique PBKDF2-derived key each time. The (key, nonce) pair
// never repeats, satisfying NaCl secretbox requirements. This matches octez-client.
// See: https://gitlab.com/tezos/tezos/-/blob/master/src/lib_signer_backends/encrypted.ml
const res = (0, nacl_1.openSecretBox)(new Uint8Array(encryptionKey), new Uint8Array(24), // zero nonce - uniqueness provided by per-encryption derived key
new Uint8Array(encryptedSk));
if (!res) {
throw new Error("can't decrypt secret key");
}
return res;
};
}
switch (pre) {
case utils_1.PrefixV2.Ed25519EncryptedSeed:
case utils_1.PrefixV2.Ed25519Seed:
case utils_1.PrefixV2.Ed25519SecretKey:
__classPrivateFieldSet(this, _InMemorySigner_key, new ed_key_1.EdKey(key, decrypt), "f");
break;
case utils_1.PrefixV2.Secp256k1EncryptedSecretKey:
case utils_1.PrefixV2.Secp256k1SecretKey:
case utils_1.PrefixV2.P256EncryptedSecretKey:
case utils_1.PrefixV2.P256SecretKey:
__classPrivateFieldSet(this, _InMemorySigner_key, new ec_key_1.ECKey(key, decrypt), "f");
break;
case utils_1.PrefixV2.BLS12_381EncryptedSecretKey:
case utils_1.PrefixV2.BLS12_381SecretKey:
__classPrivateFieldSet(this, _InMemorySigner_key, new bls_key_1.BLSKey(key, decrypt), "f");
break;
}
}
/**
*
* @param message Bytes to sign
* @param watermark Watermark to append to the bytes
*/
async sign(message, watermark) {
const msg = typeof message == 'string' ? (0, utils_1.hex2buf)(message) : message;
const watermarkMsg = watermark !== undefined ? (0, utils_1.mergebuf)(watermark, msg) : msg;
const { rawSignature, sig: signature, prefixSig: prefixedSignature, } = await __classPrivateFieldGet(this, _InMemorySigner_key, "f").sign(watermarkMsg);
return {
bytes: (0, utils_1.buf2hex)(msg),
sig: signature,
prefixSig: prefixedSignature,
sbytes: (0, utils_1.buf2hex)((0, utils_1.mergebuf)(msg,
// bls only Signature_prefix ff03 ref:https://octez.tezos.com/docs/shell/p2p_api.html#signature-prefix-tag-255 & https://octez.tezos.com/docs/shell/p2p_api.html#bls-prefix-tag-3
(0, key_interface_1.isPOP)(__classPrivateFieldGet(this, _InMemorySigner_key, "f")) ? (0, utils_1.mergebuf)(new Uint8Array([255, 3]), rawSignature) : rawSignature)),
};
}
async provePossession() {
if ((0, key_interface_1.isPOP)(__classPrivateFieldGet(this, _InMemorySigner_key, "f"))) {
return __classPrivateFieldGet(this, _InMemorySigner_key, "f").provePossession();
}
else {
throw new core_1.ProhibitedActionError('Only BLS keys can prove possession');
}
}
get canProvePossession() {
return (0, key_interface_1.isPOP)(__classPrivateFieldGet(this, _InMemorySigner_key, "f"));
}
/**
* @returns Encoded public key
*/
publicKey() {
return Promise.resolve(String(__classPrivateFieldGet(this, _InMemorySigner_key, "f").publicKey()));
}
/**
* @returns Encoded public key hash
*/
publicKeyHash() {
return Promise.resolve(__classPrivateFieldGet(this, _InMemorySigner_key, "f").publicKey().hash());
}
/**
* @returns Encoded private key
*/
secretKey() {
return Promise.resolve(__classPrivateFieldGet(this, _InMemorySigner_key, "f").secretKey());
}
}
exports.InMemorySigner = InMemorySigner;
_InMemorySigner_key = new WeakMap();
function publicKeyFromString(src) {
const [keyData, pre] = (0, utils_1.b58DecodeAndCheckPrefix)(src, [
utils_1.PrefixV2.Ed25519PublicKey,
utils_1.PrefixV2.Secp256k1PublicKey,
utils_1.PrefixV2.P256PublicKey,
utils_1.PrefixV2.BLS12_381PublicKey,
]);
switch (pre) {
case utils_1.PrefixV2.Ed25519PublicKey:
return new ed_key_1.EdPublicKey(keyData);
case utils_1.PrefixV2.Secp256k1PublicKey:
return new ec_key_1.ECPublicKey(keyData, 'secp256k1');
case utils_1.PrefixV2.P256PublicKey:
return new ec_key_1.ECPublicKey(keyData, 'p256');
case utils_1.PrefixV2.BLS12_381PublicKey:
return new bls_key_1.BLSPublicKey(keyData);
}
}