1 | "use strict";
|
2 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
3 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
4 | };
|
5 | Object.defineProperty(exports, "__esModule", { value: true });
|
6 | exports.hashPersonalMessage = exports.isValidSignature = exports.fromRpcSig = exports.toCompactSig = exports.toRpcSig = exports.ecrecover = exports.ecsign = void 0;
|
7 | const secp256k1_1 = require("ethereum-cryptography/secp256k1");
|
8 | const bn_js_1 = __importDefault(require("bn.js"));
|
9 | const bytes_1 = require("./bytes");
|
10 | const hash_1 = require("./hash");
|
11 | const helpers_1 = require("./helpers");
|
12 | const types_1 = require("./types");
|
13 | function ecsign(msgHash, privateKey, chainId) {
|
14 | const { signature, recid: recovery } = (0, secp256k1_1.ecdsaSign)(msgHash, privateKey);
|
15 | const r = Buffer.from(signature.slice(0, 32));
|
16 | const s = Buffer.from(signature.slice(32, 64));
|
17 | if (!chainId || typeof chainId === 'number') {
|
18 |
|
19 | if (chainId && !Number.isSafeInteger(chainId)) {
|
20 | throw new Error('The provided number is greater than MAX_SAFE_INTEGER (please use an alternative input type)');
|
21 | }
|
22 | const v = chainId ? recovery + (chainId * 2 + 35) : recovery + 27;
|
23 | return { r, s, v };
|
24 | }
|
25 | const chainIdBN = (0, types_1.toType)(chainId, types_1.TypeOutput.BN);
|
26 | const v = chainIdBN.muln(2).addn(35).addn(recovery).toArrayLike(Buffer);
|
27 | return { r, s, v };
|
28 | }
|
29 | exports.ecsign = ecsign;
|
30 | function calculateSigRecovery(v, chainId) {
|
31 | const vBN = (0, types_1.toType)(v, types_1.TypeOutput.BN);
|
32 | if (!chainId) {
|
33 | return vBN.subn(27);
|
34 | }
|
35 | const chainIdBN = (0, types_1.toType)(chainId, types_1.TypeOutput.BN);
|
36 | return vBN.sub(chainIdBN.muln(2).addn(35));
|
37 | }
|
38 | function isValidSigRecovery(recovery) {
|
39 | const rec = new bn_js_1.default(recovery);
|
40 | return rec.eqn(0) || rec.eqn(1);
|
41 | }
|
42 |
|
43 |
|
44 |
|
45 |
|
46 | const ecrecover = function (msgHash, v, r, s, chainId) {
|
47 | const signature = Buffer.concat([(0, bytes_1.setLengthLeft)(r, 32), (0, bytes_1.setLengthLeft)(s, 32)], 64);
|
48 | const recovery = calculateSigRecovery(v, chainId);
|
49 | if (!isValidSigRecovery(recovery)) {
|
50 | throw new Error('Invalid signature v value');
|
51 | }
|
52 | const senderPubKey = (0, secp256k1_1.ecdsaRecover)(signature, recovery.toNumber(), msgHash);
|
53 | return Buffer.from((0, secp256k1_1.publicKeyConvert)(senderPubKey, false).slice(1));
|
54 | };
|
55 | exports.ecrecover = ecrecover;
|
56 |
|
57 |
|
58 |
|
59 |
|
60 | const toRpcSig = function (v, r, s, chainId) {
|
61 | const recovery = calculateSigRecovery(v, chainId);
|
62 | if (!isValidSigRecovery(recovery)) {
|
63 | throw new Error('Invalid signature v value');
|
64 | }
|
65 |
|
66 | return (0, bytes_1.bufferToHex)(Buffer.concat([(0, bytes_1.setLengthLeft)(r, 32), (0, bytes_1.setLengthLeft)(s, 32), (0, bytes_1.toBuffer)(v)]));
|
67 | };
|
68 | exports.toRpcSig = toRpcSig;
|
69 |
|
70 |
|
71 |
|
72 |
|
73 | const toCompactSig = function (v, r, s, chainId) {
|
74 | const recovery = calculateSigRecovery(v, chainId);
|
75 | if (!isValidSigRecovery(recovery)) {
|
76 | throw new Error('Invalid signature v value');
|
77 | }
|
78 | const vn = (0, types_1.toType)(v, types_1.TypeOutput.Number);
|
79 | let ss = s;
|
80 | if ((vn > 28 && vn % 2 === 1) || vn === 1 || vn === 28) {
|
81 | ss = Buffer.from(s);
|
82 | ss[0] |= 0x80;
|
83 | }
|
84 | return (0, bytes_1.bufferToHex)(Buffer.concat([(0, bytes_1.setLengthLeft)(r, 32), (0, bytes_1.setLengthLeft)(ss, 32)]));
|
85 | };
|
86 | exports.toCompactSig = toCompactSig;
|
87 |
|
88 |
|
89 |
|
90 |
|
91 | const fromRpcSig = function (sig) {
|
92 | const buf = (0, bytes_1.toBuffer)(sig);
|
93 | let r;
|
94 | let s;
|
95 | let v;
|
96 | if (buf.length >= 65) {
|
97 | r = buf.slice(0, 32);
|
98 | s = buf.slice(32, 64);
|
99 | v = (0, bytes_1.bufferToInt)(buf.slice(64));
|
100 | }
|
101 | else if (buf.length === 64) {
|
102 |
|
103 | r = buf.slice(0, 32);
|
104 | s = buf.slice(32, 64);
|
105 | v = (0, bytes_1.bufferToInt)(buf.slice(32, 33)) >> 7;
|
106 | s[0] &= 0x7f;
|
107 | }
|
108 | else {
|
109 | throw new Error('Invalid signature length');
|
110 | }
|
111 |
|
112 | if (v < 27) {
|
113 | v += 27;
|
114 | }
|
115 | return {
|
116 | v,
|
117 | r,
|
118 | s,
|
119 | };
|
120 | };
|
121 | exports.fromRpcSig = fromRpcSig;
|
122 |
|
123 |
|
124 |
|
125 |
|
126 | const isValidSignature = function (v, r, s, homesteadOrLater = true, chainId) {
|
127 | const SECP256K1_N_DIV_2 = new bn_js_1.default('7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0', 16);
|
128 | const SECP256K1_N = new bn_js_1.default('fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141', 16);
|
129 | if (r.length !== 32 || s.length !== 32) {
|
130 | return false;
|
131 | }
|
132 | if (!isValidSigRecovery(calculateSigRecovery(v, chainId))) {
|
133 | return false;
|
134 | }
|
135 | const rBN = new bn_js_1.default(r);
|
136 | const sBN = new bn_js_1.default(s);
|
137 | if (rBN.isZero() || rBN.gt(SECP256K1_N) || sBN.isZero() || sBN.gt(SECP256K1_N)) {
|
138 | return false;
|
139 | }
|
140 | if (homesteadOrLater && sBN.cmp(SECP256K1_N_DIV_2) === 1) {
|
141 | return false;
|
142 | }
|
143 | return true;
|
144 | };
|
145 | exports.isValidSignature = isValidSignature;
|
146 |
|
147 |
|
148 |
|
149 |
|
150 |
|
151 |
|
152 | const hashPersonalMessage = function (message) {
|
153 | (0, helpers_1.assertIsBuffer)(message);
|
154 | const prefix = Buffer.from(`\u0019Ethereum Signed Message:\n${message.length}`, 'utf-8');
|
155 | return (0, hash_1.keccak)(Buffer.concat([prefix, message]));
|
156 | };
|
157 | exports.hashPersonalMessage = hashPersonalMessage;
|
158 |
|
\ | No newline at end of file |