"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.sign = exports.makeSigner = exports.assertSigner = exports.makePrivateKeySigner = exports.recoverAddress = exports.defaultSign = void 0; // For ESM compatibility const elliptic_1 = __importDefault(require("elliptic")); const { ec } = elliptic_1.default; const error_1 = require("../utils/error"); const bytes_1 = require("../utils/bytes"); const hash_1 = require("../utils/hash"); const hex_1 = require("../utils/hex"); const types_1 = require("../types"); const type_1 = require("../utils/type"); const UNCOMPRESSED_RECOVERY_ID = 27; function hashWithEthereumPrefix(data) { const ethereumSignedMessagePrefix = `\x19Ethereum Signed Message:\n${data.length}`; const prefixBytes = new TextEncoder().encode(ethereumSignedMessagePrefix); return (0, hash_1.keccak256Hash)(prefixBytes, data); } /** * The default signer function that can be used for integrating with * other applications (e.g. wallets). * * @param data The data to be signed * @param privateKey The private key used for signing the data */ function defaultSign(data, privateKey) { const curve = new ec('secp256k1'); const keyPair = curve.keyFromPrivate(privateKey); const hashedDigest = hashWithEthereumPrefix(data); const sigRaw = curve.sign(hashedDigest, keyPair, { canonical: true, pers: undefined }); if (sigRaw.recoveryParam === null) { throw new error_1.BeeError('signDigest recovery param was null'); } const signature = new Uint8Array([ ...sigRaw.r.toArray('be', 32), ...sigRaw.s.toArray('be', 32), sigRaw.recoveryParam + UNCOMPRESSED_RECOVERY_ID, ]); return signature; } exports.defaultSign = defaultSign; function publicKeyToAddress(pubKey) { const pubBytes = pubKey.encode('array', false); return (0, hash_1.keccak256Hash)(pubBytes.slice(1)).slice(12); } /** * Recovers the ethereum address from a given signature. * * Can be used for verifying a piece of data when the public key is * known. * * @param signature The signature * @param digest The digest of the data * * @returns the recovered address */ function recoverAddress(signature, digest) { const curve = new ec('secp256k1'); const sig = { r: signature.slice(0, 32), s: signature.slice(32, 64), }; const recoveryParam = signature[64] - UNCOMPRESSED_RECOVERY_ID; const hash = hashWithEthereumPrefix(digest); const recPubKey = curve.recoverPubKey(hash, sig, recoveryParam); return publicKeyToAddress(recPubKey); } exports.recoverAddress = recoverAddress; /** * Creates a singer object that can be used when the private key is known. * * @param privateKey The private key */ function makePrivateKeySigner(privateKey) { const curve = new ec('secp256k1'); const keyPair = curve.keyFromPrivate(privateKey); const address = publicKeyToAddress(keyPair.getPublic()); return { sign: (digest) => defaultSign(digest, privateKey), address, }; } exports.makePrivateKeySigner = makePrivateKeySigner; function assertSigner(signer) { if (!(0, type_1.isStrictlyObject)(signer)) { throw new TypeError('Signer must be an object!'); } const typedSigner = signer; if (!(0, bytes_1.isBytes)(typedSigner.address, 20)) { throw new TypeError("Signer's address must be Uint8Array with 20 bytes!"); } if (typeof typedSigner.sign !== 'function') { throw new TypeError('Signer sign property needs to be function!'); } } exports.assertSigner = assertSigner; function makeSigner(signer) { if (typeof signer === 'string') { const hexKey = (0, hex_1.makeHexString)(signer, 64); const keyBytes = (0, hex_1.hexToBytes)(hexKey); // HexString is verified for 64 length => 32 is guaranteed return makePrivateKeySigner(keyBytes); } else if (signer instanceof Uint8Array) { (0, bytes_1.assertBytes)(signer, 32); return makePrivateKeySigner(signer); } assertSigner(signer); return signer; } exports.makeSigner = makeSigner; function sign(signer, data) { return __awaiter(this, void 0, void 0, function* () { const result = yield signer.sign((0, bytes_1.wrapBytesWithHelpers)(data)); if (typeof result === 'string') { const hexString = (0, hex_1.makeHexString)(result, types_1.SIGNATURE_HEX_LENGTH); return (0, hex_1.hexToBytes)(hexString); } if (result instanceof Uint8Array) { (0, bytes_1.assertBytes)(result, types_1.SIGNATURE_BYTES_LENGTH); return result; } throw new TypeError('Invalid output of sign function!'); }); } exports.sign = sign;