Skip to content

Instantly share code, notes, and snippets.

@intrnl
Last active Dec 14, 2020
Embed
What would you like to do?
Discord slash commands example on Cloudflare Workers
import * as ed from './noble-ed25519';
let encoder = new TextEncoder();
let commands = new Map();
export function define (name, handler) {
commands.set(name, handler);
}
export function start (key) {
addEventListener('fetch', (event) => {
event.respondWith(
handleRequest(event.request, key)
.catch((err = {}) => {
let { name, message, stack } = err;
console.log('error during request', { name, message, stack });
return respond({
status: 500,
data: { message: 'Error during request', error: { name, message } },
});
})
);
});
}
function respond ({ data, ...init }) {
console.log('created response', { data, ...init });
return new Response(JSON.stringify(data), init);
}
function reply (data = {}) {
console.log('created reply', data);
if (typeof data == 'string') data = { data: { content: data } };
return respond({ status: 200, data: { type: 4, ...data } });
}
/**
* @param {Request} request
* @param {string} key
*/
async function handleRequest (request, key) {
if (request.method != 'POST') {
return respond({ status: 400, data: { message: 'Not implemented' } });
}
if (!request.headers.has('x-signature-ed25519') || !request.headers.has('x-signature-timestamp')) {
return respond({ status: 400, data: { message: 'Missing signature headers' } });
}
let body = await request.text();
let timestamp = request.headers.get('x-signature-timestamp');
let signature = request.headers.get('x-signature-ed25519');
let hash = encoder.encode(timestamp + body);
let valid = await ed.verify(signature, hash, key);
if (!valid) {
return respond({ status: 400, data: { message: 'Invalid signature' } });
}
let interaction = JSON.parse(body);
if (interaction.type == 1) {
return respond({ status: 200, data: { type: 1 } });
} else if (interaction.type == 2) {
let { name: command } = interaction.data;
let handler = commands.get(command);
if (!handler) {
return reply('Invalid command');
}
return Promise.resolve(handler(interaction))
.catch((err) => {
let { name, message, stack } = err ?? {};
console.error('error during command', { command, name, message, stack });
return [
`Error occured while processing \`${command}\``,
'```',
name ?? '<No name>',
message ?? '<No message>',
'```',
].join('\n');
})
.then((response) => reply(response));
}
}
import { define, start } from './handler';
import { PUBLIC_KEY } from './secret';
start(PUBLIC_KEY);
define('ping', ({ member }) => {
return `Hello, ${member.nick ?? member.user.username}! It is ${new Date().toUTCString()} currently.`;
});
// noble-ed25519, converted to ES Modules, without Node-specific stuff
// Originally licensed under MIT, (c) Paul Miller (paulmillr.com)
// https://github.com/paulmillr/noble-ed25519
export const CURVE = {
a: -1n,
d: 37095705934669439343138083508754565189542113879843219016388785533085940283555n,
P: 2n ** 255n - 19n,
n: 2n ** 252n + 27742317777372353535851937790883648493n,
h: 8n,
Gx: 15112221349535400772501151409588531511454012693041857206046113283949847762202n,
Gy: 46316835694926478169428394003475163141307993866256225615783033603165251855960n,
};
const ENCODING_LENGTH = 32;
const DIV_8_MINUS_3 = (CURVE.P + 3n) / 8n;
const I = powMod(2n, (CURVE.P + 1n) / 4n, CURVE.P);
const SQRT_M1 = 19681161376707505956807079304988542015446066515923890162744021073123829784752n;
const INVSQRT_A_MINUS_D = 54469307008909316920995813868745141605393597292927456921205312896311721017578n;
const SQRT_AD_MINUS_ONE = 25063068953384623474111414158702152701244531502492656460079210482610430750235n;
export class ExtendedPoint {
static BASE = new ExtendedPoint(CURVE.Gx, CURVE.Gy, 1n, mod(CURVE.Gx * CURVE.Gy));
static ZERO = new ExtendedPoint(0n, 1n, 1n, 0n);
constructor(x, y, z, t) {
this.x = x;
this.y = y;
this.z = z;
this.t = t;
}
static fromAffine(p) {
if (!(p instanceof Point)) {
throw new TypeError('ExtendedPoint#fromAffine: expected Point');
}
if (p.equals(Point.ZERO))
return ExtendedPoint.ZERO;
return new ExtendedPoint(p.x, p.y, 1n, mod(p.x * p.y));
}
static toAffineBatch(points) {
const toInv = invertBatch(points.map((p) => p.z));
return points.map((p, i) => p.toAffine(toInv[i]));
}
static normalizeZ(points) {
return this.toAffineBatch(points).map(this.fromAffine);
}
static fromRistrettoHash(hash) {
const r1 = bytesToNumberRst(hash.slice(0, ENCODING_LENGTH));
const R1 = this.elligatorRistrettoFlavor(r1);
const r2 = bytesToNumberRst(hash.slice(ENCODING_LENGTH, ENCODING_LENGTH * 2));
const R2 = this.elligatorRistrettoFlavor(r2);
return R1.add(R2);
}
static elligatorRistrettoFlavor(r0) {
const { d } = CURVE;
const oneMinusDSq = mod(1n - d ** 2n);
const dMinusOneSq = (d - 1n) ** 2n;
const r = SQRT_M1 * (r0 * r0);
const NS = mod((r + 1n) * oneMinusDSq);
let c = mod(-1n);
const D = mod((c - d * r) * mod(r + d));
let { isNotZeroSquare, value: S } = sqrtRatio(NS, D);
let sPrime = mod(S * r0);
sPrime = edIsNegative(sPrime) ? sPrime : mod(-sPrime);
S = isNotZeroSquare ? S : sPrime;
c = isNotZeroSquare ? c : r;
const NT = c * (r - 1n) * dMinusOneSq - D;
const sSquared = S * S;
const W0 = (S + S) * D;
const W1 = NT * SQRT_AD_MINUS_ONE;
const W2 = 1n - sSquared;
const W3 = 1n + sSquared;
return new ExtendedPoint(mod(W0 * W3), mod(W2 * W1), mod(W1 * W3), mod(W0 * W2));
}
static fromRistrettoBytes(bytes) {
const s = bytesToNumberRst(bytes);
const sEncodingIsCanonical = equalBytes(numberToBytesPadded(s, ENCODING_LENGTH), bytes);
const sIsNegative = edIsNegative(s);
if (!sEncodingIsCanonical || sIsNegative) {
throw new Error('Cannot convert bytes to Ristretto Point');
}
const s2 = s * s;
const u1 = 1n - s2;
const u2 = 1n + s2;
const squaredU2 = u2 * u2;
const v = u1 * u1 * -CURVE.d - squaredU2;
const { isNotZeroSquare, value: I } = invertSqrt(mod(v * squaredU2));
const Dx = I * u2;
const Dy = I * Dx * v;
let x = mod((s + s) * Dx);
if (edIsNegative(x))
x = mod(-x);
const y = mod(u1 * Dy);
const t = mod(x * y);
if (!isNotZeroSquare || edIsNegative(t) || y === 0n) {
throw new Error('Cannot convert bytes to Ristretto Point');
}
return new ExtendedPoint(x, y, 1n, t);
}
toRistrettoBytes() {
let { x, y, z, t } = this;
const u1 = (z + y) * (z - y);
const u2 = x * y;
const { value: invsqrt } = invertSqrt(mod(u2 ** 2n * u1));
const i1 = invsqrt * u1;
const i2 = invsqrt * u2;
const invz = i1 * i2 * t;
let invDeno = i2;
if (edIsNegative(t * invz)) {
const iX = mod(x * SQRT_M1);
const iY = mod(y * SQRT_M1);
x = iY;
y = iX;
invDeno = mod(i1 * INVSQRT_A_MINUS_D);
}
if (edIsNegative(x * invz))
y = mod(-y);
let s = mod((z - y) * invDeno);
if (edIsNegative(s))
s = mod(-s);
return numberToBytesPadded(s, ENCODING_LENGTH);
}
equals(other) {
const a = this;
const b = other;
const [T1, T2, Z1, Z2] = [a.t, b.t, a.z, b.z];
return mod(T1 * Z2) === mod(T2 * Z1);
}
negate() {
return new ExtendedPoint(mod(-this.x), this.y, this.z, mod(-this.t));
}
double() {
const X1 = this.x;
const Y1 = this.y;
const Z1 = this.z;
const { a } = CURVE;
const A = mod(X1 ** 2n);
const B = mod(Y1 ** 2n);
const C = mod(2n * Z1 ** 2n);
const D = mod(a * A);
const E = mod((X1 + Y1) ** 2n - A - B);
const G = mod(D + B);
const F = mod(G - C);
const H = mod(D - B);
const X3 = mod(E * F);
const Y3 = mod(G * H);
const T3 = mod(E * H);
const Z3 = mod(F * G);
return new ExtendedPoint(X3, Y3, Z3, T3);
}
add(other) {
const X1 = this.x;
const Y1 = this.y;
const Z1 = this.z;
const T1 = this.t;
const X2 = other.x;
const Y2 = other.y;
const Z2 = other.z;
const T2 = other.t;
const A = mod((Y1 - X1) * (Y2 + X2));
const B = mod((Y1 + X1) * (Y2 - X2));
const F = mod(B - A);
if (F === 0n) {
return this.double();
}
const C = mod(Z1 * 2n * T2);
const D = mod(T1 * 2n * Z2);
const E = mod(D + C);
const G = mod(B + A);
const H = mod(D - C);
const X3 = mod(E * F);
const Y3 = mod(G * H);
const T3 = mod(E * H);
const Z3 = mod(F * G);
return new ExtendedPoint(X3, Y3, Z3, T3);
}
subtract(other) {
return this.add(other.negate());
}
multiplyUnsafe(scalar) {
if (typeof scalar !== 'number' && typeof scalar !== 'bigint') {
throw new TypeError('Point#multiply: expected number or bigint');
}
let n = mod(BigInt(scalar), CURVE.n);
if (n <= 0) {
throw new Error('Point#multiply: invalid scalar, expected positive integer');
}
let p = ExtendedPoint.ZERO;
let d = this;
while (n > 0n) {
if (n & 1n)
p = p.add(d);
d = d.double();
n >>= 1n;
}
return p;
}
precomputeWindow(W) {
const windows = 256 / W + 1;
let points = [];
let p = this;
let base = p;
for (let window = 0; window < windows; window++) {
base = p;
points.push(base);
for (let i = 1; i < 2 ** (W - 1); i++) {
base = base.add(p);
points.push(base);
}
p = base.double();
}
return points;
}
wNAF(n, affinePoint) {
if (!affinePoint && this.equals(ExtendedPoint.BASE))
affinePoint = Point.BASE;
const W = (affinePoint && affinePoint._WINDOW_SIZE) || 1;
if (256 % W) {
throw new Error('Point#wNAF: Invalid precomputation window, must be power of 2');
}
let precomputes = affinePoint && pointPrecomputes.get(affinePoint);
if (!precomputes) {
precomputes = this.precomputeWindow(W);
if (affinePoint && W !== 1) {
precomputes = ExtendedPoint.normalizeZ(precomputes);
pointPrecomputes.set(affinePoint, precomputes);
}
}
let p = ExtendedPoint.ZERO;
let f = ExtendedPoint.ZERO;
const windows = 256 / W + 1;
const windowSize = 2 ** (W - 1);
const mask = BigInt(2 ** W - 1);
const maxNumber = 2 ** W;
const shiftBy = BigInt(W);
for (let window = 0; window < windows; window++) {
const offset = window * windowSize;
let wbits = Number(n & mask);
n >>= shiftBy;
if (wbits > windowSize) {
wbits -= maxNumber;
n += 1n;
}
if (wbits === 0) {
f = f.add(window % 2 ? precomputes[offset].negate() : precomputes[offset]);
}
else {
const cached = precomputes[offset + Math.abs(wbits) - 1];
p = p.add(wbits < 0 ? cached.negate() : cached);
}
}
return [p, f];
}
multiply(scalar, affinePoint) {
if (typeof scalar !== 'number' && typeof scalar !== 'bigint') {
throw new TypeError('Point#multiply: expected number or bigint');
}
const n = mod(BigInt(scalar), CURVE.n);
if (n <= 0) {
throw new Error('Point#multiply: invalid scalar, expected positive integer');
}
return ExtendedPoint.normalizeZ(this.wNAF(n, affinePoint))[0];
}
toAffine(invZ = invert(this.z)) {
const x = mod(this.x * invZ);
const y = mod(this.y * invZ);
return new Point(x, y);
}
}
const pointPrecomputes = new WeakMap();
export class Point {
static BASE = new Point(CURVE.Gx, CURVE.Gy);
static ZERO = new Point(0n, 1n);
constructor(x, y) {
this.x = x;
this.y = y;
}
_setWindowSize(windowSize) {
this._WINDOW_SIZE = windowSize;
pointPrecomputes.delete(this);
}
static fromHex(hash) {
const { d, P } = CURVE;
const bytes = hash instanceof Uint8Array ? hash : hexToBytes(hash);
const len = bytes.length - 1;
const normedLast = bytes[len] & ~0x80;
const isLastByteOdd = (bytes[len] & 0x80) !== 0;
const normed = Uint8Array.from(Array.from(bytes.slice(0, len)).concat(normedLast));
const y = bytesToNumberLE(normed);
if (y >= P) {
throw new Error('Point#fromHex expects hex <= Fp');
}
const sqrY = y * y;
const sqrX = mod((sqrY - 1n) * invert(d * sqrY + 1n));
let x = powMod(sqrX, DIV_8_MINUS_3);
if (mod(x * x - sqrX) !== 0n) {
x = mod(x * I);
}
const isXOdd = (x & 1n) === 1n;
if (isLastByteOdd !== isXOdd) {
x = mod(-x);
}
return new Point(x, y);
}
toRawBytes() {
const hex = numberToHex(this.y);
const u8 = new Uint8Array(ENCODING_LENGTH);
for (let i = hex.length - 2, j = 0; j < ENCODING_LENGTH && i >= 0; i -= 2, j++) {
u8[j] = parseInt(hex[i] + hex[i + 1], 16);
}
const mask = this.x & 1n ? 0x80 : 0;
u8[ENCODING_LENGTH - 1] |= mask;
return u8;
}
toHex() {
return bytesToHex(this.toRawBytes());
}
toX25519() {
return mod((1n + this.y) * invert(1n - this.y));
}
equals(other) {
return this.x === other.x && this.y === other.y;
}
negate() {
return new Point(mod(-this.x), this.y);
}
add(other) {
return ExtendedPoint.fromAffine(this).add(ExtendedPoint.fromAffine(other)).toAffine();
}
subtract(other) {
return this.add(other.negate());
}
multiply(scalar) {
return ExtendedPoint.fromAffine(this).multiply(scalar, this).toAffine();
}
}
Point.BASE._setWindowSize(8);
export class SignResult {
constructor(r, s) {
this.r = r;
this.s = s;
}
static fromHex(hex) {
hex = ensureBytes(hex);
const r = Point.fromHex(hex.slice(0, 32));
const s = bytesToNumberLE(hex.slice(32));
return new SignResult(r, s);
}
toRawBytes() {
const numberBytes = hexToBytes(numberToHex(this.s)).reverse();
const sBytes = new Uint8Array(ENCODING_LENGTH);
sBytes.set(numberBytes);
const res = new Uint8Array(ENCODING_LENGTH * 2);
res.set(this.r.toRawBytes());
res.set(sBytes, 32);
return res;
}
toHex() {
return bytesToHex(this.toRawBytes());
}
}
function concatBytes(...arrays) {
if (arrays.length === 1)
return arrays[0];
const length = arrays.reduce((a, arr) => a + arr.length, 0);
const result = new Uint8Array(length);
for (let i = 0, pad = 0; i < arrays.length; i++) {
const arr = arrays[i];
result.set(arr, pad);
pad += arr.length;
}
return result;
}
function bytesToHex(uint8a) {
let hex = '';
for (let i = 0; i < uint8a.length; i++) {
hex += uint8a[i].toString(16).padStart(2, '0');
}
return hex;
}
function pad64(num) {
return num.toString(16).padStart(ENCODING_LENGTH * 2, '0');
}
function hexToBytes(hex) {
hex = hex.length & 1 ? `0${hex}` : hex;
const array = new Uint8Array(hex.length / 2);
for (let i = 0; i < array.length; i++) {
let j = i * 2;
array[i] = Number.parseInt(hex.slice(j, j + 2), 16);
}
return array;
}
function numberToHex(num) {
const hex = num.toString(16);
return hex.length & 1 ? `0${hex}` : hex;
}
function numberToBytesPadded(num, length = ENCODING_LENGTH) {
const hex = numberToHex(num).padStart(length * 2, '0');
return hexToBytes(hex).reverse();
}
function edIsNegative(num) {
const hex = numberToHex(mod(num));
const byte = Number.parseInt(hex.slice(hex.length - 2, hex.length), 16);
return Boolean(byte & 1);
}
function bytesToNumberLE(uint8a) {
let value = 0n;
for (let i = 0; i < uint8a.length; i++) {
value += BigInt(uint8a[i]) << (8n * BigInt(i));
}
return value;
}
function load8(input, padding = 0) {
return (BigInt(input[0 + padding]) |
(BigInt(input[1 + padding]) << 8n) |
(BigInt(input[2 + padding]) << 16n) |
(BigInt(input[3 + padding]) << 24n) |
(BigInt(input[4 + padding]) << 32n) |
(BigInt(input[5 + padding]) << 40n) |
(BigInt(input[6 + padding]) << 48n) |
(BigInt(input[7 + padding]) << 56n));
}
const low51bitMask = (1n << 51n) - 1n;
function bytesToNumberRst(bytes) {
const octet1 = load8(bytes, 0) & low51bitMask;
const octet2 = (load8(bytes, 6) >> 3n) & low51bitMask;
const octet3 = (load8(bytes, 12) >> 6n) & low51bitMask;
const octet4 = (load8(bytes, 19) >> 1n) & low51bitMask;
const octet5 = (load8(bytes, 24) >> 12n) & low51bitMask;
return mod(octet1 + (octet2 << 51n) + (octet3 << 102n) + (octet4 << 153n) + (octet5 << 204n));
}
function mod(a, b = CURVE.P) {
const res = a % b;
return res >= 0n ? res : b + res;
}
function powMod(a, power, m = CURVE.P) {
let res = 1n;
while (power > 0n) {
if (power & 1n) {
res = mod(res * a, m);
}
power >>= 1n;
a = mod(a * a, m);
}
return res;
}
function egcd(a, b) {
let [x, y, u, v] = [0n, 1n, 1n, 0n];
while (a !== 0n) {
let q = b / a;
let r = b % a;
let m = x - u * q;
let n = y - v * q;
[b, a] = [a, r];
[x, y] = [u, v];
[u, v] = [m, n];
}
let gcd = b;
return [gcd, x, y];
}
function invert(number, modulo = CURVE.P) {
if (number === 0n || modulo <= 0n) {
throw new Error('invert: expected positive integers');
}
let [gcd, x] = egcd(mod(number, modulo), modulo);
if (gcd !== 1n) {
throw new Error('invert: does not exist');
}
return mod(x, modulo);
}
function invertBatch(nums, n = CURVE.P) {
const len = nums.length;
const scratch = new Array(len);
let acc = 1n;
for (let i = 0; i < len; i++) {
if (nums[i] === 0n)
continue;
scratch[i] = acc;
acc = mod(acc * nums[i], n);
}
acc = invert(acc, n);
for (let i = len - 1; i >= 0; i--) {
if (nums[i] === 0n)
continue;
let tmp = mod(acc * nums[i], n);
nums[i] = mod(acc * scratch[i], n);
acc = tmp;
}
return nums;
}
function invertSqrt(number) {
return sqrtRatio(1n, number);
}
function powMod2(t, power) {
const { P } = CURVE;
let res = t;
while (power-- > 0n) {
res *= res;
res %= P;
}
return res;
}
function pow_2_252_3(t) {
t = mod(t);
const { P } = CURVE;
const t0 = (t * t) % P;
const t1 = t0 ** 4n % P;
const t2 = (t * t1) % P;
const t3 = (t0 * t2) % P;
const t4 = t3 ** 2n % P;
const t5 = (t2 * t4) % P;
const t6 = powMod2(t5, 5n);
const t7 = (t6 * t5) % P;
const t8 = powMod2(t7, 10n);
const t9 = (t8 * t7) % P;
const t10 = powMod2(t9, 20n);
const t11 = (t10 * t9) % P;
const t12 = powMod2(t11, 10n);
const t13 = (t12 * t7) % P;
const t14 = powMod2(t13, 50n);
const t15 = (t14 * t13) % P;
const t16 = powMod2(t15, 100n);
const t17 = (t16 * t15) % P;
const t18 = powMod2(t17, 50n);
const t19 = (t18 * t13) % P;
const t20 = (t19 * t19) % P;
const t21 = (t20 * t20 * t) % P;
return t21;
}
function sqrtRatio(t, v) {
const v3 = mod(v * v * v);
const v7 = mod(v3 * v3 * v);
let r = mod(pow_2_252_3(t * v7) * t * v3);
const check = mod(r * r * v);
const i = SQRT_M1;
const correctSignSqrt = check === t;
const flippedSignSqrt = check === mod(-t);
const flippedSignSqrtI = check === mod(mod(-t) * i);
const rPrime = mod(SQRT_M1 * r);
r = flippedSignSqrt || flippedSignSqrtI ? rPrime : r;
if (edIsNegative(r))
r = mod(-r);
const isNotZeroSquare = correctSignSqrt || flippedSignSqrt;
return { isNotZeroSquare, value: mod(r) };
}
async function sha512ToNumberLE(...args) {
const messageArray = concatBytes(...args);
const hash = await utils.sha512(messageArray);
const value = bytesToNumberLE(hash);
return mod(value, CURVE.n);
}
function keyPrefix(privateBytes) {
return privateBytes.slice(ENCODING_LENGTH);
}
function encodePrivate(privateBytes) {
const last = ENCODING_LENGTH - 1;
const head = privateBytes.slice(0, ENCODING_LENGTH);
head[0] &= 248;
head[last] &= 127;
head[last] |= 64;
return bytesToNumberLE(head);
}
function ensureBytes(hash) {
return hash instanceof Uint8Array ? hash : hexToBytes(hash);
}
function equalBytes(b1, b2) {
if (b1.length !== b2.length) {
return false;
}
let diff = 0;
for (let i = 0; i < b1.length; i++) {
diff |= b1[i] ^ b2[i];
}
return diff === 0;
}
function ensurePrivInputBytes(privateKey) {
if (privateKey instanceof Uint8Array)
return privateKey;
if (typeof privateKey === 'string')
return hexToBytes(privateKey.padStart(ENCODING_LENGTH * 2, '0'));
return hexToBytes(pad64(BigInt(privateKey)));
}
export async function getPublicKey(privateKey) {
const privBytes = await utils.sha512(ensurePrivInputBytes(privateKey));
const publicKey = Point.BASE.multiply(encodePrivate(privBytes));
return typeof privateKey === 'string' ? publicKey.toHex() : publicKey.toRawBytes();
}
export async function sign(hash, privateKey) {
const privBytes = await utils.sha512(ensurePrivInputBytes(privateKey));
const p = encodePrivate(privBytes);
const P = Point.BASE.multiply(p);
const msg = ensureBytes(hash);
const r = await sha512ToNumberLE(keyPrefix(privBytes), msg);
const R = Point.BASE.multiply(r);
const h = await sha512ToNumberLE(R.toRawBytes(), P.toRawBytes(), msg);
const S = mod(r + h * p, CURVE.n);
const sig = new SignResult(R, S);
return typeof hash === 'string' ? sig.toHex() : sig.toRawBytes();
}
export async function verify(signature, hash, publicKey) {
hash = ensureBytes(hash);
if (!(publicKey instanceof Point))
publicKey = Point.fromHex(publicKey);
if (!(signature instanceof SignResult))
signature = SignResult.fromHex(signature);
const h = await sha512ToNumberLE(signature.r.toRawBytes(), publicKey.toRawBytes(), hash);
const Ph = ExtendedPoint.fromAffine(publicKey).multiplyUnsafe(h);
const Gs = ExtendedPoint.BASE.multiply(signature.s);
const RPh = ExtendedPoint.fromAffine(signature.r).add(Ph);
return Gs.equals(RPh);
}
export const utils = {
TORSION_SUBGROUP: [
'0100000000000000000000000000000000000000000000000000000000000000',
'c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a',
'0000000000000000000000000000000000000000000000000000000000000080',
'26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05',
'ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f',
'26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85',
'0000000000000000000000000000000000000000000000000000000000000000',
'c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa',
],
randomPrivateKey: (bytesLength = 32) => {
return crypto.getRandomValues(new Uint8Array(bytesLength));
},
sha512: async (message) => {
const buffer = await crypto.subtle.digest('SHA-512', message.buffer);
return new Uint8Array(buffer);
},
precompute(windowSize = 8, point = Point.BASE) {
const cached = point.equals(Point.BASE) ? point : new Point(point.x, point.y);
cached._setWindowSize(windowSize);
cached.multiply(1n);
return cached;
},
};
@Wolfkid200444

This comment has been minimized.

Copy link

@Wolfkid200444 Wolfkid200444 commented Dec 14, 2020

wa

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment