UNPKG

8.65 kBJavaScriptView Raw
1let Buffer = require('buffer').Buffer;
2
3export 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 // return new Random(Random.engines.mt19937().seedWithArray(array)).integer(min, max);
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; //The maximum is inclusive and the minimum is inclusive
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* mt19937 methods
135* */
136
137class mt19937 {
138 constructor(seed) {
139 if (seed == undefined) {
140 seed = new Date().getTime();
141 }
142 /* Period parameters */
143 this.N = 624;
144 this.M = 397;
145 this.MATRIX_A = 0x9908b0df;
146 /* constant vector a */
147 this.UPPER_MASK = 0x80000000;
148 /* most significant w-r bits */
149 this.LOWER_MASK = 0x7fffffff;
150 /* least significant r bits */
151
152 this.mt = new Array(this.N);
153 /* the array for the state vector */
154 this.mti = this.N + 1;
155 /* mti==N+1 means mt[N] is not initialized */
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 /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
166 /* In the previous versions, MSBs of the seed affect */
167 /* only MSBs of the array mt[]. */
168 /* 2002/01/09 modified by Makoto Matsumoto */
169 this.mt[this.mti] >>>= 0;
170 /* for >32 bit machines */
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 /* non linear */
184 this.mt[i] >>>= 0;
185 /* for WORDSIZE > 32 machines */
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 /* non linear */
198 this.mt[i] >>>= 0;
199 /* for WORDSIZE > 32 machines */
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 /* MSB is 1; assuring non-zero initial array */
208 }
209
210 random() {
211 return this.genrand_int32() * (1.0 / 4294967296.0);
212 /* divided by 2^32 */
213 }
214
215 genrand_int32() {
216 var y;
217 var mag01 = new Array(0x0, this.MATRIX_A);
218 /* mag01[x] = x * MATRIX_A for x=0,1 */
219
220 if (this.mti >= this.N) { /* generate N words at one time */
221 var kk;
222
223 if (this.mti == this.N + 1) /* if init_genrand() has not been called, */
224 this.init_genrand(5489);
225 /* a default initial seed is used */
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 /* Tempering */
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