1 | let Buffer = require('buffer').Buffer;
|
2 |
|
3 | export class Sp8deCrypto {
|
4 | constructor(eth = undefined) {
|
5 | this.EthJS = !eth ? window.EthJS.Util : eth;
|
6 | }
|
7 |
|
8 | sing(privateKey, seed, nonce) {
|
9 | if (privateKey === undefined ||
|
10 | seed === undefined ||
|
11 | nonce === undefined) {
|
12 | console.error('Invalid parameters');
|
13 | return null;
|
14 | }
|
15 | let pubKey = this.getPubKey(privateKey),
|
16 | message = `${pubKey};${seed};${nonce}`,
|
17 | msg = this.EthJS.hashPersonalMessage(this.EthJS.toBuffer(message)),
|
18 | signed = this.EthJS.ecsign(msg, this.EthJS.toBuffer(privateKey)),
|
19 | tx = signed.r.toString('hex') + signed.s.toString('hex') + this.EthJS.stripHexPrefix(this.EthJS.intToHex(signed.v));
|
20 | return {
|
21 | pubKey: pubKey,
|
22 | message: message,
|
23 | sign: this.EthJS.addHexPrefix(tx),
|
24 | version: '3',
|
25 | signer: 'MEW'
|
26 | };
|
27 | }
|
28 |
|
29 | getPubKey(privateKey) {
|
30 | if (!privateKey) {
|
31 | console.error('Invalid parameter');
|
32 | return;
|
33 | }
|
34 | return this.EthJS.addHexPrefix(this.EthJS.privateToAddress(privateKey).toString('hex'))
|
35 | }
|
36 |
|
37 | getRandomFromArray(array, min, max) {
|
38 | if (array === undefined ||
|
39 | !Array.isArray(array) ||
|
40 | min === undefined ||
|
41 | max === undefined) {
|
42 | console.error('Invalid parameters');
|
43 | return;
|
44 | }
|
45 | let rand = new mt19937();
|
46 | rand.init_by_array(array, array.length);
|
47 | return this.getRandomIntInclusive(rand.random(), min, max);
|
48 |
|
49 | }
|
50 |
|
51 | getRandomIntInclusive(rnd, min, max) {
|
52 | min = Math.ceil(min);
|
53 | max = Math.floor(max);
|
54 | return Math.floor(rnd * (max - min + 1)) + min;
|
55 | }
|
56 |
|
57 | generateSeed() {
|
58 | let rnd = new Uint32Array(1);
|
59 | window.crypto.getRandomValues(rnd);
|
60 | return rnd[0];
|
61 | };
|
62 |
|
63 | validate(signedMessage) {
|
64 | let item, hash, sign, pubKey;
|
65 |
|
66 | try {
|
67 | if (!signedMessage) throw new TypeError('Please enter signed message');
|
68 | item = typeof item === 'string' ? JSON.parse(signedMessage) : signedMessage;
|
69 | if (!item.sign) throw new TypeError('Empty sign');
|
70 | if (item.sign.length % 2 !== 0) throw new TypeError('Invalid hex string');
|
71 | sign = Buffer.from(this.getNakedAddress(item.sign), 'hex');
|
72 | if (sign.length !== 65) throw new TypeError('sign length is not valid');
|
73 | sign[64] = sign[64] === 0 || sign[64] === 1 ? sign[64] + 27 : sign[64];
|
74 | hash = this.EthJS.hashPersonalMessage(this.EthJS.toBuffer(item.message));
|
75 |
|
76 | if (item.version === '3') {
|
77 | if (item.signer === 'trezor') {
|
78 | hash = this.getTrezorHash(item.message);
|
79 | } else if (item.signer === 'ledger') {
|
80 | hash = this.EthJS.hashPersonalMessage(Buffer.from(item.message));
|
81 | }
|
82 | } else if (item.version === '1') {
|
83 | hash = this.EthJS.sha3(item.message);
|
84 | }
|
85 |
|
86 | pubKey = this.EthJS.ecrecover(
|
87 | hash,
|
88 | sign[64],
|
89 | sign.slice(0, 32),
|
90 | sign.slice(32, 64)
|
91 | );
|
92 |
|
93 | if (this.getNakedAddress(item.pubKey) !== this.EthJS.pubToAddress(pubKey).toString('hex')) throw new TypeError('sign is not valid');
|
94 | } catch (e) {
|
95 | if (e instanceof SyntaxError) console.error('JSON is not valid');
|
96 | else console.error(e);
|
97 | return false;
|
98 | }
|
99 | return true;
|
100 | }
|
101 |
|
102 | getNakedAddress(address) {
|
103 | return address.toLowerCase().replace('0x', '');
|
104 | };
|
105 |
|
106 | getTrezorLenBuf(msgLen) {
|
107 | if (msgLen < 253) return Buffer.from([msgLen & 0xff]);
|
108 | else if (msgLen < 0x10000)
|
109 | return Buffer.from([253, msgLen & 0xff, (msgLen >> 8) & 0xff]);
|
110 | else {
|
111 | return Buffer.from([
|
112 | 254,
|
113 | msgLen & 0xff,
|
114 | (msgLen >> 8) & 0xff,
|
115 | (msgLen >> 16) & 0xff,
|
116 | (msgLen >> 24) & 0xff
|
117 | ]);
|
118 | }
|
119 | };
|
120 |
|
121 | getTrezorHash(msg) {
|
122 | return this.EthJS.sha3(
|
123 | Buffer.concat([
|
124 | this.EthJS.toBuffer('\u0019Ethereum Signed Message:\n'),
|
125 | this.getTrezorLenBuf(msg.length),
|
126 | this.EthJS.toBuffer(msg)
|
127 | ])
|
128 | );
|
129 | };
|
130 |
|
131 | }
|
132 |
|
133 |
|
134 |
|
135 |
|
136 |
|
137 | class mt19937 {
|
138 | constructor(seed) {
|
139 | if (seed == undefined) {
|
140 | seed = new Date().getTime();
|
141 | }
|
142 |
|
143 | this.N = 624;
|
144 | this.M = 397;
|
145 | this.MATRIX_A = 0x9908b0df;
|
146 |
|
147 | this.UPPER_MASK = 0x80000000;
|
148 |
|
149 | this.LOWER_MASK = 0x7fffffff;
|
150 |
|
151 |
|
152 | this.mt = new Array(this.N);
|
153 |
|
154 | this.mti = this.N + 1;
|
155 |
|
156 |
|
157 | this.init_genrand(seed);
|
158 | }
|
159 |
|
160 | init_genrand(s) {
|
161 | this.mt[0] = s >>> 0;
|
162 | for (this.mti = 1; this.mti < this.N; this.mti++) {
|
163 | s = this.mt[this.mti - 1] ^ (this.mt[this.mti - 1] >>> 30);
|
164 | this.mt[this.mti] = (((((s & 0xffff0000) >>> 16) * 1812433253) << 16) + (s & 0x0000ffff) * 1812433253) + this.mti;
|
165 |
|
166 |
|
167 |
|
168 |
|
169 | this.mt[this.mti] >>>= 0;
|
170 |
|
171 | }
|
172 | }
|
173 |
|
174 | init_by_array(init_key, key_length) {
|
175 | var i, j, k;
|
176 | this.init_genrand(19650218);
|
177 | i = 1;
|
178 | j = 0;
|
179 | k = (this.N > key_length ? this.N : key_length);
|
180 | for (; k; k--) {
|
181 | var s = this.mt[i - 1] ^ (this.mt[i - 1] >>> 30)
|
182 | this.mt[i] = (this.mt[i] ^ (((((s & 0xffff0000) >>> 16) * 1664525) << 16) + ((s & 0x0000ffff) * 1664525))) + init_key[j] + j;
|
183 |
|
184 | this.mt[i] >>>= 0;
|
185 |
|
186 | i++;
|
187 | j++;
|
188 | if (i >= this.N) {
|
189 | this.mt[0] = this.mt[this.N - 1];
|
190 | i = 1;
|
191 | }
|
192 | if (j >= key_length) j = 0;
|
193 | }
|
194 | for (k = this.N - 1; k; k--) {
|
195 | var s = this.mt[i - 1] ^ (this.mt[i - 1] >>> 30);
|
196 | this.mt[i] = (this.mt[i] ^ (((((s & 0xffff0000) >>> 16) * 1566083941) << 16) + (s & 0x0000ffff) * 1566083941)) - i;
|
197 |
|
198 | this.mt[i] >>>= 0;
|
199 |
|
200 | i++;
|
201 | if (i >= this.N) {
|
202 | this.mt[0] = this.mt[this.N - 1];
|
203 | i = 1;
|
204 | }
|
205 | }
|
206 | this.mt[0] = 0x80000000;
|
207 |
|
208 | }
|
209 |
|
210 | random() {
|
211 | return this.genrand_int32() * (1.0 / 4294967296.0);
|
212 |
|
213 | }
|
214 |
|
215 | genrand_int32() {
|
216 | var y;
|
217 | var mag01 = new Array(0x0, this.MATRIX_A);
|
218 |
|
219 |
|
220 | if (this.mti >= this.N) {
|
221 | var kk;
|
222 |
|
223 | if (this.mti == this.N + 1)
|
224 | this.init_genrand(5489);
|
225 |
|
226 |
|
227 | for (kk = 0; kk < this.N - this.M; kk++) {
|
228 | y = (this.mt[kk] & this.UPPER_MASK) | (this.mt[kk + 1] & this.LOWER_MASK);
|
229 | this.mt[kk] = this.mt[kk + this.M] ^ (y >>> 1) ^ mag01[y & 0x1];
|
230 | }
|
231 | for (; kk < this.N - 1; kk++) {
|
232 | y = (this.mt[kk] & this.UPPER_MASK) | (this.mt[kk + 1] & this.LOWER_MASK);
|
233 | this.mt[kk] = this.mt[kk + (this.M - this.N)] ^ (y >>> 1) ^ mag01[y & 0x1];
|
234 | }
|
235 | y = (this.mt[this.N - 1] & this.UPPER_MASK) | (this.mt[0] & this.LOWER_MASK);
|
236 | this.mt[this.N - 1] = this.mt[this.M - 1] ^ (y >>> 1) ^ mag01[y & 0x1];
|
237 |
|
238 | this.mti = 0;
|
239 | }
|
240 |
|
241 | y = this.mt[this.mti++];
|
242 |
|
243 |
|
244 | y ^= (y >>> 11);
|
245 | y ^= (y << 7) & 0x9d2c5680;
|
246 | y ^= (y << 15) & 0xefc60000;
|
247 | y ^= (y >>> 18);
|
248 |
|
249 | return y >>> 0;
|
250 | }
|
251 | }
|
252 |
|
253 |
|
254 |
|