138 lines
5.4 KiB
JavaScript
138 lines
5.4 KiB
JavaScript
|
"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;
|