UNPKG

@taquito/signer

Version:

Software signer implementations and signing utilities for Taquito.

205 lines (204 loc) 10.1 kB
"use strict"; 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); } }