2022-02-04 14:12:00 +11:00
|
|
|
import { keccak256, Message } from "js-sha3";
|
2022-01-13 11:33:26 +11:00
|
|
|
|
2022-02-11 17:27:15 +11:00
|
|
|
/**
|
|
|
|
|
* Convert input to a Buffer.
|
2022-02-14 10:50:02 +11:00
|
|
|
*
|
|
|
|
|
* @deprecated Use `hexToBytes` instead.
|
2022-02-11 17:27:15 +11:00
|
|
|
*/
|
2021-07-12 17:09:44 +10:00
|
|
|
export function hexToBuf(hex: string | Buffer | Uint8Array): Buffer {
|
2022-02-04 14:12:00 +11:00
|
|
|
if (typeof hex === "string") {
|
|
|
|
|
return Buffer.from(hex.replace(/^0x/i, ""), "hex");
|
2021-07-12 17:09:44 +10:00
|
|
|
} else {
|
|
|
|
|
return Buffer.from(hex);
|
|
|
|
|
}
|
2021-07-09 15:12:52 +10:00
|
|
|
}
|
|
|
|
|
|
2022-02-14 10:50:02 +11:00
|
|
|
/**
|
|
|
|
|
* Convert input to a byte array.
|
|
|
|
|
*/
|
|
|
|
|
export function hexToBytes(hex: string | Uint8Array): Uint8Array {
|
|
|
|
|
if (typeof hex === "string") {
|
|
|
|
|
const _hex = hex.replace(/^0x/i, "");
|
|
|
|
|
const bytes = [];
|
|
|
|
|
for (let c = 0; c < _hex.length; c += 2)
|
|
|
|
|
bytes.push(parseInt(_hex.substring(c, c + 2), 16));
|
|
|
|
|
|
|
|
|
|
return new Uint8Array(bytes);
|
|
|
|
|
}
|
|
|
|
|
return hex;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-11 17:27:15 +11:00
|
|
|
/**
|
|
|
|
|
* Convert input to hex string (no `0x` prefix).
|
2022-02-14 10:50:02 +11:00
|
|
|
*
|
|
|
|
|
* @deprecated Use `bytesToHex` instead.
|
2022-02-11 17:27:15 +11:00
|
|
|
*/
|
2021-07-09 15:57:47 +10:00
|
|
|
export function bufToHex(buf: Uint8Array | Buffer | ArrayBuffer): string {
|
2021-07-09 15:12:52 +10:00
|
|
|
const _buf = Buffer.from(buf);
|
2022-02-04 14:12:00 +11:00
|
|
|
return _buf.toString("hex");
|
2021-07-09 15:12:52 +10:00
|
|
|
}
|
|
|
|
|
|
2022-02-14 10:50:02 +11:00
|
|
|
/**
|
|
|
|
|
* Convert byte array to hex string (no `0x` prefix).
|
|
|
|
|
*/
|
|
|
|
|
export function bytesToHex(bytes: Uint8Array): string {
|
|
|
|
|
const hex = [];
|
|
|
|
|
for (let i = 0; i < bytes.length; i++) {
|
|
|
|
|
const current = bytes[i] < 0 ? bytes[i] + 256 : bytes[i];
|
|
|
|
|
hex.push((current >>> 4).toString(16));
|
|
|
|
|
hex.push((current & 0xf).toString(16));
|
|
|
|
|
}
|
|
|
|
|
return hex.join("");
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-11 17:27:15 +11:00
|
|
|
/**
|
|
|
|
|
* Compare both inputs, return true if they represent the same byte array.
|
|
|
|
|
*/
|
2021-07-09 15:12:52 +10:00
|
|
|
export function equalByteArrays(
|
2022-02-14 10:50:02 +11:00
|
|
|
a: Uint8Array | string,
|
|
|
|
|
b: Uint8Array | string
|
2021-07-09 15:12:52 +10:00
|
|
|
): boolean {
|
2022-02-14 10:50:02 +11:00
|
|
|
let _a: string;
|
|
|
|
|
let _b: string;
|
2022-02-04 14:12:00 +11:00
|
|
|
if (typeof a === "string") {
|
2022-02-14 10:50:02 +11:00
|
|
|
_a = a.replace(/^0x/i, "").toLowerCase();
|
2021-07-09 15:12:52 +10:00
|
|
|
} else {
|
2022-02-14 10:50:02 +11:00
|
|
|
_a = bytesToHex(a);
|
2021-07-09 15:12:52 +10:00
|
|
|
}
|
|
|
|
|
|
2022-02-04 14:12:00 +11:00
|
|
|
if (typeof b === "string") {
|
2022-02-14 10:50:02 +11:00
|
|
|
_b = b.replace(/^0x/i, "").toLowerCase();
|
2021-07-09 15:12:52 +10:00
|
|
|
} else {
|
2022-02-14 10:50:02 +11:00
|
|
|
_b = bytesToHex(b);
|
2021-07-09 15:12:52 +10:00
|
|
|
}
|
|
|
|
|
|
2022-02-14 10:50:02 +11:00
|
|
|
return _a === _b;
|
2021-07-05 15:48:57 +10:00
|
|
|
}
|
2022-01-13 11:33:26 +11:00
|
|
|
|
2022-02-11 17:27:15 +11:00
|
|
|
/**
|
|
|
|
|
* Return Keccak-256 of the input.
|
|
|
|
|
*/
|
2022-01-13 11:33:26 +11:00
|
|
|
export function keccak256Buf(message: Message): Buffer {
|
|
|
|
|
return Buffer.from(keccak256.arrayBuffer(message));
|
|
|
|
|
}
|
2022-02-16 12:11:54 +11:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Convert base64 string to byte array.
|
|
|
|
|
*/
|
|
|
|
|
export function base64ToBytes(base64: string): Uint8Array {
|
|
|
|
|
const e = new Map<string, number>();
|
|
|
|
|
|
|
|
|
|
const len = base64.length;
|
|
|
|
|
const res = [];
|
|
|
|
|
const A = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
|
|
|
for (let i = 0; i < 64; i++) {
|
|
|
|
|
e.set(A.charAt(i), i);
|
|
|
|
|
}
|
|
|
|
|
e.set("+", 62);
|
|
|
|
|
e.set("/", 63);
|
|
|
|
|
|
|
|
|
|
let b = 0,
|
|
|
|
|
l = 0,
|
|
|
|
|
a;
|
|
|
|
|
for (let i = 0; i < len; i++) {
|
|
|
|
|
const c = e.get(base64.charAt(i));
|
|
|
|
|
if (c === undefined)
|
|
|
|
|
throw new Error(`Invalid base64 character ${base64.charAt(i)}`);
|
|
|
|
|
b = (b << 6) + c;
|
|
|
|
|
l += 6;
|
|
|
|
|
while (l >= 8) {
|
|
|
|
|
((a = (b >>> (l -= 8)) & 0xff) || i < len - 2) && res.push(a);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return new Uint8Array(res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Convert byte array to base64 string.
|
|
|
|
|
*/
|
|
|
|
|
export async function bytesToBase64(bytes: Uint8Array): Promise<string> {
|
|
|
|
|
const base64url: string = await new Promise((r) => {
|
|
|
|
|
const reader = new window.FileReader();
|
|
|
|
|
reader.onload = (): void => r(reader.result as string);
|
|
|
|
|
reader.readAsDataURL(new Blob([bytes]));
|
|
|
|
|
});
|
|
|
|
|
const base64 = base64url.split(",", 2)[1];
|
|
|
|
|
// We want URL and Filename Safe base64: https://datatracker.ietf.org/doc/html/rfc4648#section-5
|
|
|
|
|
// Without trailing padding
|
|
|
|
|
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
|
|
|
}
|