-
Notifications
You must be signed in to change notification settings - Fork 0
/
merkle-utils.ts
139 lines (124 loc) · 3.73 KB
/
merkle-utils.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import crypto from 'crypto'
/**
utility function to remove a leading 0x on a string representing a hex number.
If no 0x is present then it returns the string un-altered.
*/
export function strip0x(hex: string) {
if (typeof hex === 'undefined') return '';
if (typeof hex === 'string' && hex.indexOf('0x') === 0) {
return hex.slice(2).toString();
}
return hex.toString();
}
/**
utility function to check that a string is hexadecimal
*/
export function isHex(value: string) {
if (typeof value !== 'string') return false;
if (value.indexOf('0x') !== 0) return false;
const regexp = /^[0-9a-fA-F]+$/;
return regexp.test(strip0x(value));
}
/** Helper function for the converting any base to any base
*/
export function convertBase(str: string, fromBase: number, toBase: number) {
const digits = parseToDigitsArray(str, fromBase);
if (digits === null) return null;
let outArray: number[] = [];
let power = [1];
for (let i = 0; i < digits.length; i += 1) {
// invariant: at this point, fromBase^i = power
if (digits[i]) {
outArray = add(outArray, multiplyByNumber(digits[i], power, toBase), toBase);
}
power = multiplyByNumber(fromBase, power, toBase);
}
let out = '';
for (let i = outArray.length - 1; i >= 0; i -= 1) {
out += outArray[i].toString(toBase);
}
// if the original input was equivalent to zero, then 'out' will still be empty ''. Let's check for zero.
if (out === '') {
let sum = 0;
for (let i = 0; i < digits.length; i += 1) {
sum += digits[i];
}
if (sum === 0) out = '0';
}
return out;
}
function parseToDigitsArray(str: string, base: number) {
const digits = str.split('');
const ary = [];
for (let i = digits.length - 1; i >= 0; i -= 1) {
const n = parseInt(digits[i], base);
if (Number.isNaN(n)) return null;
ary.push(n);
}
return ary;
}
function add(x: any[], y: any[], base: number) {
const z = [];
const n = Math.max(x.length, y.length);
let carry = 0;
let i = 0;
while (i < n || carry) {
const xi = i < x.length ? x[i] : 0;
const yi = i < y.length ? y[i] : 0;
const zi = carry + xi + yi;
z.push(zi % base);
carry = Math.floor(zi / base);
i += 1;
}
return z;
}
/** Helper function for the converting any base to any base
Returns a*x, where x is an array of decimal digits and a is an ordinary
JavaScript number. base is the number base of the array x.
*/
function multiplyByNumber(num: number, x: number[], base: number): number[] {
if (num < 0) return [];
if (num === 0) return [];
let result: number[] = [];
let power = x;
// eslint-disable-next-line no-constant-condition
while (true) {
// eslint-disable-next-line no-bitwise
if (num & 1) {
result = add(result, power, base);
}
num >>= 1; // eslint-disable-line
if (num === 0) break;
power = add(power, power, base);
}
return result;
}
/**
Utility function to concatenate two hex strings and return as buffer
Looks like the inputs are somehow being changed to decimal!
*/
function concatenate(a: Buffer, b: Buffer) {
const length = a.length + b.length;
const buffer = Buffer.allocUnsafe(length); // creates a buffer object of length 'length'
for (let i = 0; i < a.length; i += 1) {
buffer[i] = a[i];
}
for (let j = 0; j < b.length; j += 1) {
buffer[a.length + j] = b[j];
}
return buffer;
}
export function shaHash(...items: string[]) {
const concatvalue = items
.map(item => Buffer.from(strip0x(item), 'hex'))
.reduce((acc, item) => concatenate(acc, item));
// console.log(concatvalue.toString('hex'))
const h = `0x${crypto
.createHash('sha256')
.update(concatvalue)
.digest('hex')}`;
return h;
}
export function concatenateThenHash(...items: string[]) {
return shaHash(...items);
}