Skip to content

Instantly share code, notes, and snippets.

@TransparentLC
Last active June 25, 2021 11:58
Show Gist options
  • Save TransparentLC/abdddb1eeade0f694e36b9b9b8c6717d to your computer and use it in GitHub Desktop.
Save TransparentLC/abdddb1eeade0f694e36b9b9b8c6717d to your computer and use it in GitHub Desktop.
10 KB 左右的 Ed25519 签名和验证算法实现,在 https://github.com/paulmillr/noble-ed25519 的基础上添加了 IIFE,将使用的 SHA-512 从 Web Crypto API 替换成 https://github.com/emn178/js-sha512 从而实现同步调用,并进行了部分修改以减小 minify 后的大小。
const Ed25519 = require('./ed25519.min.js');
const hexToBytes = e => new Uint8Array(e.match(/[0-9a-f]{2}/gi).map(e => parseInt(e, 16)));
const bytesToHex = e => Array.from(e).map(e => e.toString(16).padStart(2, 0)).join('');
// Test vectors from:
// https://datatracker.ietf.org/doc/html/rfc8032#section-7.1
const privateA = hexToBytes('4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb');
const messageA = hexToBytes('72');
const publicA = Ed25519.getPublicKey(privateA);
console.assert(bytesToHex(publicA) === '3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c', 'Public A');
const signA = Ed25519.sign(messageA, privateA);
console.assert(
bytesToHex(signA) === '92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00',
'Sign A'
);
const verifyA = Ed25519.verify(messageA, signA, publicA);
console.assert(verifyA, 'Verify A');
const privateB = hexToBytes('c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7');
const messageB = hexToBytes('af82');
const publicB = Ed25519.getPublicKey(privateB);
console.assert(bytesToHex(publicB) === 'fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025', 'Public B');
const signB = Ed25519.sign(messageB, privateB);
console.assert(
bytesToHex(signB) === '6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a',
'Sign B'
);
const verifyB = Ed25519.verify(messageB, signB, publicB);
console.assert(verifyB, 'Verify B');
const privateC = hexToBytes('833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42');
const messageC = hexToBytes(''
+ 'ddaf35a193617abacc417349ae204131'
+ '12e6fa4e89a97ea20a9eeee64b55d39a'
+ '2192992a274fc1a836ba3c23a3feebbd'
+ '454d4423643ce80e2a9ac94fa54ca49f'
);
const publicC = Ed25519.getPublicKey(privateC);
console.assert(bytesToHex(publicC) === 'ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf', 'Public C');
const signC = Ed25519.sign(messageC, privateC);
console.assert(
bytesToHex(signC) === 'dc2a4459e7369633a52b1bf277839a00201009a3efbf3ecb69bea2186c26b58909351fc9ac90b3ecfdfbc7c66431e0303dca179c138ac17ad9bef1177331a704',
'Sign C'
);
const verifyC = Ed25519.verify(messageC, signC, publicC);
console.assert(verifyC, 'Verify C');
const privateD = hexToBytes('f5e5767cf153319517630f226876b86c8160cc583bc013744c6bf255f5cc0ee5');
const messageD = hexToBytes(''
+ '08b8b2b733424243760fe426a4b54908'
+ '632110a66c2f6591eabd3345e3e4eb98'
+ 'fa6e264bf09efe12ee50f8f54e9f77b1'
+ 'e355f6c50544e23fb1433ddf73be84d8'
+ '79de7c0046dc4996d9e773f4bc9efe57'
+ '38829adb26c81b37c93a1b270b20329d'
+ '658675fc6ea534e0810a4432826bf58c'
+ '941efb65d57a338bbd2e26640f89ffbc'
+ '1a858efcb8550ee3a5e1998bd177e93a'
+ '7363c344fe6b199ee5d02e82d522c4fe'
+ 'ba15452f80288a821a579116ec6dad2b'
+ '3b310da903401aa62100ab5d1a36553e'
+ '06203b33890cc9b832f79ef80560ccb9'
+ 'a39ce767967ed628c6ad573cb116dbef'
+ 'efd75499da96bd68a8a97b928a8bbc10'
+ '3b6621fcde2beca1231d206be6cd9ec7'
+ 'aff6f6c94fcd7204ed3455c68c83f4a4'
+ '1da4af2b74ef5c53f1d8ac70bdcb7ed1'
+ '85ce81bd84359d44254d95629e9855a9'
+ '4a7c1958d1f8ada5d0532ed8a5aa3fb2'
+ 'd17ba70eb6248e594e1a2297acbbb39d'
+ '502f1a8c6eb6f1ce22b3de1a1f40cc24'
+ '554119a831a9aad6079cad88425de6bd'
+ 'e1a9187ebb6092cf67bf2b13fd65f270'
+ '88d78b7e883c8759d2c4f5c65adb7553'
+ '878ad575f9fad878e80a0c9ba63bcbcc'
+ '2732e69485bbc9c90bfbd62481d9089b'
+ 'eccf80cfe2df16a2cf65bd92dd597b07'
+ '07e0917af48bbb75fed413d238f5555a'
+ '7a569d80c3414a8d0859dc65a46128ba'
+ 'b27af87a71314f318c782b23ebfe808b'
+ '82b0ce26401d2e22f04d83d1255dc51a'
+ 'ddd3b75a2b1ae0784504df543af8969b'
+ 'e3ea7082ff7fc9888c144da2af58429e'
+ 'c96031dbcad3dad9af0dcbaaaf268cb8'
+ 'fcffead94f3c7ca495e056a9b47acdb7'
+ '51fb73e666c6c655ade8297297d07ad1'
+ 'ba5e43f1bca32301651339e22904cc8c'
+ '42f58c30c04aafdb038dda0847dd988d'
+ 'cda6f3bfd15c4b4c4525004aa06eeff8'
+ 'ca61783aacec57fb3d1f92b0fe2fd1a8'
+ '5f6724517b65e614ad6808d6f6ee34df'
+ 'f7310fdc82aebfd904b01e1dc54b2927'
+ '094b2db68d6f903b68401adebf5a7e08'
+ 'd78ff4ef5d63653a65040cf9bfd4aca7'
+ '984a74d37145986780fc0b16ac451649'
+ 'de6188a7dbdf191f64b5fc5e2ab47b57'
+ 'f7f7276cd419c17a3ca8e1b939ae49e4'
+ '88acba6b965610b5480109c8b17b80e1'
+ 'b7b750dfc7598d5d5011fd2dcc5600a3'
+ '2ef5b52a1ecc820e308aa342721aac09'
+ '43bf6686b64b2579376504ccc493d97e'
+ '6aed3fb0f9cd71a43dd497f01f17c0e2'
+ 'cb3797aa2a2f256656168e6c496afc5f'
+ 'b93246f6b1116398a346f1a641f3b041'
+ 'e989f7914f90cc2c7fff357876e506b5'
+ '0d334ba77c225bc307ba537152f3f161'
+ '0e4eafe595f6d9d90d11faa933a15ef1'
+ '369546868a7f3a45a96768d40fd9d034'
+ '12c091c6315cf4fde7cb68606937380d'
+ 'b2eaaa707b4c4185c32eddcdd306705e'
+ '4dc1ffc872eeee475a64dfac86aba41c'
+ '0618983f8741c5ef68d3a101e8a3b8ca'
+ 'c60c905c15fc910840b94c00a0b9d0'
);
const publicD = Ed25519.getPublicKey(privateD);
console.assert(bytesToHex(publicD) === '278117fc144c72340f67d0f2316e8386ceffbf2b2428c9c51fef7c597f1d426e', 'Public D');
const signD = Ed25519.sign(messageD, privateD);
console.assert(
bytesToHex(signD) === '0aab4c900501b3e24d7cdf4663326a3a87df5e4843b2cbdb67cbf6e460fec350aa5371b1508f9f4528ecea23c436d94b5e8fcd4f681e30a6ac00a9704a188a03',
'Sign D'
);
const verifyD = Ed25519.verify(messageD, signD, publicD);
console.assert(verifyD, 'Verify D');
/*! noble-ed25519 - MIT License (c) Paul Miller (paulmillr.com) */
/*
* [js-sha512]{@link https://github.com/emn178/js-sha512}
*
* @version 0.8.0
* @author Chen, Yi-Cyuan [[email protected]]
* @copyright Chen, Yi-Cyuan 2014-2018
* @license MIT
*/
(() => {
/** @type {globalThis} */
const GLOBAL = typeof globalThis !== 'undefined' ? globalThis : (global || self);
const {
BigInt,
Error,
Int32Array,
Uint8Array,
} = GLOBAL;
const K = new Int32Array([
0x428A2F98, 0xD728AE22, 0x71374491, 0x23EF65CD,
0xB5C0FBCF, 0xEC4D3B2F, 0xE9B5DBA5, 0x8189DBBC,
0x3956C25B, 0xF348B538, 0x59F111F1, 0xB605D019,
0x923F82A4, 0xAF194F9B, 0xAB1C5ED5, 0xDA6D8118,
0xD807AA98, 0xA3030242, 0x12835B01, 0x45706FBE,
0x243185BE, 0x4EE4B28C, 0x550C7DC3, 0xD5FFB4E2,
0x72BE5D74, 0xF27B896F, 0x80DEB1FE, 0x3B1696B1,
0x9BDC06A7, 0x25C71235, 0xC19BF174, 0xCF692694,
0xE49B69C1, 0x9EF14AD2, 0xEFBE4786, 0x384F25E3,
0x0FC19DC6, 0x8B8CD5B5, 0x240CA1CC, 0x77AC9C65,
0x2DE92C6F, 0x592B0275, 0x4A7484AA, 0x6EA6E483,
0x5CB0A9DC, 0xBD41FBD4, 0x76F988DA, 0x831153B5,
0x983E5152, 0xEE66DFAB, 0xA831C66D, 0x2DB43210,
0xB00327C8, 0x98FB213F, 0xBF597FC7, 0xBEEF0EE4,
0xC6E00BF3, 0x3DA88FC2, 0xD5A79147, 0x930AA725,
0x06CA6351, 0xE003826F, 0x14292967, 0x0A0E6E70,
0x27B70A85, 0x46D22FFC, 0x2E1B2138, 0x5C26C926,
0x4D2C6DFC, 0x5AC42AED, 0x53380D13, 0x9D95B3DF,
0x650A7354, 0x8BAF63DE, 0x766A0ABB, 0x3C77B2A8,
0x81C2C92E, 0x47EDAEE6, 0x92722C85, 0x1482353B,
0xA2BFE8A1, 0x4CF10364, 0xA81A664B, 0xBC423001,
0xC24B8B70, 0xD0F89791, 0xC76C51A3, 0x0654BE30,
0xD192E819, 0xD6EF5218, 0xD6990624, 0x5565A910,
0xF40E3585, 0x5771202A, 0x106AA070, 0x32BBD1B8,
0x19A4C116, 0xB8D2D0C8, 0x1E376C08, 0x5141AB53,
0x2748774C, 0xDF8EEB99, 0x34B0BCB5, 0xE19B48A8,
0x391C0CB3, 0xC5C95A63, 0x4ED8AA4A, 0xE3418ACB,
0x5B9CCA4F, 0x7763E373, 0x682E6FF3, 0xD6B2B8A3,
0x748F82EE, 0x5DEFB2FC, 0x78A5636F, 0x43172F60,
0x84C87814, 0xA1F0AB72, 0x8CC70208, 0x1A6439EC,
0x90BEFFFA, 0x23631E28, 0xA4506CEB, 0xDE82BDE9,
0xBEF9A3F7, 0xB2C67915, 0xC67178F2, 0xE372532B,
0xCA273ECE, 0xEA26619C, 0xD186B8C7, 0x21C0C207,
0xEADA7DD6, 0xCDE0EB1E, 0xF57D4F7F, 0xEE6ED178,
0x06F067AA, 0x72176FBA, 0x0A637DC5, 0xA2C898A6,
0x113F9804, 0xBEF90DAE, 0x1B710B35, 0x131C471B,
0x28DB77F5, 0x23047D84, 0x32CAAB7B, 0x40C72493,
0x3C9EBE0A, 0x15C9BEBC, 0x431D67C4, 0x9C100D4C,
0x4CC5D4BE, 0xCB3E42B6, 0x597F299C, 0xFC657E2A,
0x5FCB6FAB, 0x3AD6FAEC, 0x6C44198C, 0x4A475817
]);
class Sha512 {
constructor() {
this.blocks = new Int32Array(160);
this.h = new Int32Array([
0x6A09E667, 0xF3BCC908,
0xBB67AE85, 0x84CAA73B,
0x3C6EF372, 0xFE94F82B,
0xA54FF53A, 0x5F1D36F1,
0x510E527F, 0xADE682D1,
0x9B05688C, 0x2B3E6C1F,
0x1F83D9AB, 0xFB41BD6B,
0x5BE0CD19, 0x137E2179,
]);
this.block = this.start = this.bytes = this.hBytes = 0;
this.finalized = this.hashed = false;
}
/**
* @param {Uint8Array} message
* @returns
*/
update(message) {
if (this.finalized) return;
let index = 0;
let i;
const length = message.length;
const blocks = this.blocks;
while (index < length) {
if (this.hashed) {
this.hashed = false;
blocks.set(new Int32Array(33));
blocks[0] = this.block;
}
for (i = this.start; index < length && i < 128; index++) {
blocks[i >> 2] |= message[index] << (3 - (i++ & 3) << 3);
}
this.lastByteIndex = i;
this.bytes += i - this.start;
if (i >= 128) {
this.block = blocks[32];
this.start = i - 128;
this.hash();
this.hashed = true;
} else {
this.start = i;
}
}
if (this.bytes > 4294967295) {
this.hBytes += this.bytes / 4294967296 << 0;
this.bytes %= 4294967296;
}
}
/**
* @returns {Uint8Array}
*/
final() {
if (this.finalized) return;
this.finalized = true;
const blocks = this.blocks;
let i = this.lastByteIndex;
blocks[32] = this.block;
blocks[i >> 2] |= 0x80 << (3 - (i & 3) << 3);
this.block = blocks[32];
if (i >= 112) {
if (!this.hashed) {
this.hash();
}
blocks.set(new Int32Array(33));
blocks[0] = this.block;
}
blocks[30] = this.hBytes << 3 | this.bytes >>> 29;
blocks[31] = this.bytes << 3;
this.hash();
const hash = new Uint8Array(64);
const dataView = new DataView(hash.buffer);
for (let i = 0; i < 16; i++) {
dataView.setInt32(i << 2, this.h[i]);
}
return hash;
}
hash() {
const blocks = this.blocks;
const h = this.h;
const g = this.h.slice();
const s = new Int32Array(4);
const c = new Int32Array(4);
const a = new Int32Array(8);
let i, j, majh, majl, t1h, t1l, t2h, t2l, chh, chl;
for (j = 32; j < 160; j += 2) {
t1h = blocks[j - 30];
t1l = blocks[j - 29];
s[0] = ((t1h >>> 1) | (t1l << 31)) ^ ((t1h >>> 8) | (t1l << 24)) ^ (t1h >>> 7);
s[1] = ((t1l >>> 1) | (t1h << 31)) ^ ((t1l >>> 8) | (t1h << 24)) ^ ((t1l >>> 7) | t1h << 25);
t1h = blocks[j - 4];
t1l = blocks[j - 3];
s[2] = ((t1h >>> 19) | (t1l << 13)) ^ ((t1l >>> 29) | (t1h << 3)) ^ (t1h >>> 6);
s[3] = ((t1l >>> 19) | (t1h << 13)) ^ ((t1h >>> 29) | (t1l << 3)) ^ ((t1l >>> 6) | t1h << 26);
t1h = blocks[j - 32];
t1l = blocks[j - 31];
t2h = blocks[j - 14];
t2l = blocks[j - 13];
c[0] = (t2l & 0xFFFF) + (t1l & 0xFFFF) + (s[1] & 0xFFFF) + (s[3] & 0xFFFF);
c[1] = (t2l >>> 16) + (t1l >>> 16) + (s[1] >>> 16) + (s[3] >>> 16) + (c[0] >>> 16);
c[2] = (t2h & 0xFFFF) + (t1h & 0xFFFF) + (s[0] & 0xFFFF) + (s[2] & 0xFFFF) + (c[1] >>> 16);
c[3] = (t2h >>> 16) + (t1h >>> 16) + (s[0] >>> 16) + (s[2] >>> 16) + (c[2] >>> 16);
blocks[j] = (c[3] << 16) | (c[2] & 0xFFFF);
blocks[j + 1] = (c[1] << 16) | (c[0] & 0xFFFF);
}
a[6] = g[2] & g[4];
a[7] = g[3] & g[5];
for (j = 0; j < 160; j += 8) {
for (i = 0; i < 4; i++) { // [0, 1, 2, 3]
const m = (8 - (i << 1) & 7); // [0, 6, 4, 2]
const n = m + 1; // [1, 7, 5, 3]
const o = m + 8; // [8, 14, 12, 10]
const p = o + 1; // [9, 15, 13, 11]
const q = i << 1; // [0, 2, 4, 6]
const r = q + 1; // [1, 3, 5, 7]
s[0] = ((g[m] >>> 28) | (g[n] << 4)) ^ ((g[n] >>> 2) | (g[m] << 30)) ^ ((g[n] >>> 7) | (g[m] << 25));
s[1] = ((g[n] >>> 28) | (g[m] << 4)) ^ ((g[m] >>> 2) | (g[n] << 30)) ^ ((g[m] >>> 7) | (g[n] << 25));
s[2] = ((g[o] >>> 14) | (g[p] << 18)) ^ ((g[o] >>> 18) | (g[p] << 14)) ^ ((g[p] >>> 9) | (g[o] << 23));
s[3] = ((g[p] >>> 14) | (g[o] << 18)) ^ ((g[p] >>> 18) | (g[o] << 14)) ^ ((g[o] >>> 9) | (g[p] << 23));
a[q] = g[m] & g[(m + 2) & 7];
a[r] = g[n] & g[(n + 2) & 7];
majh = a[q] ^ (g[q] & g[(q + 4) & 7]) ^ a[(q + 6) & 7];
majl = a[r] ^ (g[r] & g[(r + 4) & 7]) ^ a[(r + 6) & 7];
chh = (g[o] & g[((m + 2) & 7) + 8]) ^ (~g[o] & g[((m + 4) & 7) + 8]);
chl = (g[p] & g[((n + 2) & 7) + 8]) ^ (~g[p] & g[((n + 4) & 7) + 8]);
t1h = blocks[j + q];
t1l = blocks[j + r];
t2h = K[j + q];
t2l = K[j + r];
c[0] = (t2l & 0xFFFF) + (t1l & 0xFFFF) + (chl & 0xFFFF) + (s[3] & 0xFFFF) + (g[16 - r] & 0xFFFF);
c[1] = (t2l >>> 16) + (t1l >>> 16) + (chl >>> 16) + (s[3] >>> 16) + (g[16 - r] >>> 16) + (c[0] >>> 16);
c[2] = (t2h & 0xFFFF) + (t1h & 0xFFFF) + (chh & 0xFFFF) + (s[2] & 0xFFFF) + (g[15 - r] & 0xFFFF) + (c[1] >>> 16);
c[3] = (t2h >>> 16) + (t1h >>> 16) + (chh >>> 16) + (s[2] >>> 16) + (g[15 - r] >>> 16) + (c[2] >>> 16);
t1h = (c[3] << 16) | (c[2] & 0xFFFF);
t1l = (c[1] << 16) | (c[0] & 0xFFFF);
c[0] = (majl & 0xFFFF) + (s[1] & 0xFFFF);
c[1] = (majl >>> 16) + (s[1] >>> 16) + (c[0] >>> 16);
c[2] = (majh & 0xFFFF) + (s[0] & 0xFFFF) + (c[1] >>> 16);
c[3] = (majh >>> 16) + (s[0] >>> 16) + (c[2] >>> 16);
t2h = (c[3] << 16) | (c[2] & 0xFFFF);
t2l = (c[1] << 16) | (c[0] & 0xFFFF);
c[0] = (g[8 - r] & 0xFFFF) + (t1l & 0xFFFF);
c[1] = (g[8 - r] >>> 16) + (t1l >>> 16) + (c[0] >>> 16);
c[2] = (g[7 - r] & 0xFFFF) + (t1h & 0xFFFF) + (c[1] >>> 16);
c[3] = (g[7 - r] >>> 16) + (t1h >>> 16) + (c[2] >>> 16);
g[14 - q] = (c[3] << 16) | (c[2] & 0xFFFF);
g[15 - q] = (c[1] << 16) | (c[0] & 0xFFFF);
c[0] = (t2l & 0xFFFF) + (t1l & 0xFFFF);
c[1] = (t2l >>> 16) + (t1l >>> 16) + (c[0] >>> 16);
c[2] = (t2h & 0xFFFF) + (t1h & 0xFFFF) + (c[1] >>> 16);
c[3] = (t2h >>> 16) + (t1h >>> 16) + (c[2] >>> 16);
g[6 - q] = (c[3] << 16) | (c[2] & 0xFFFF);
g[7 - q] = (c[1] << 16) | (c[0] & 0xFFFF);
}
}
for (j = 0; j < 16; j += 2) {
c[0] = (h[j + 1] & 0xFFFF) + (g[j + 1] & 0xFFFF);
c[1] = (h[j + 1] >>> 16) + (g[j + 1] >>> 16) + (c[0] >>> 16);
c[2] = (h[j] & 0xFFFF) + (g[j] & 0xFFFF) + (c[1] >>> 16);
c[3] = (h[j] >>> 16) + (g[j] >>> 16) + (c[2] >>> 16);
this.h[j] = (c[3] << 16) | (c[2] & 0xFFFF);
this.h[j + 1] = (c[1] << 16) | (c[0] & 0xFFFF);
}
}
}
const sha512 = message => {
const s = new Sha512;
s.update(message);
return s.final();
};
const CURVE = {
a: -1n,
d: 37095705934669439343138083508754565189542113879843219016388785533085940283555n,
P: 2n ** 255n - 19n,
n: 2n ** 252n + 27742317777372353535851937790883648493n,
h: 8n,
Gx: 15112221349535400772501151409588531511454012693041857206046113283949847762202n,
Gy: 46316835694926478169428394003475163141307993866256225615783033603165251855960n,
};
const SQRT_M1 = 19681161376707505956807079304988542015446066515923890162744021073123829784752n;
const 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;
}
const hexToBytes = hex => {
const array = new Uint8Array(hex.length / 2);
for (let i = 0; i < array.length; i++) {
const j = i * 2;
array[i] = parseInt(hex.slice(j, j + 2), 16);
}
return array;
}
const numberToHex = num => {
const hex = num.toString(16);
return hex.length & 1 ? `0${hex}` : hex;
}
const edIsNegative = num => (mod(num) & 1n) === 1n;
const isValidScalar = num => (typeof num === 'bigint' && num > 0n) || (typeof num === 'number' && num > 0 && Number.isSafeInteger(num));
const bytesToNumberLE = uint8a => {
let value = 0n;
for (let i = 0; i < uint8a.length; i++) {
value += BigInt(uint8a[i]) << (8n * BigInt(i));
}
return value;
}
const mod = (a, b = CURVE.P) => {
const res = a % b;
return res >= 0n ? res : b + res;
}
const invert = (number, modulo = CURVE.P) => {
if (number === 0n || modulo <= 0n) {
throw new Error(`invert: expected positive integers, got n=${number} mod=${modulo}`);
}
let a = mod(number, modulo);
let b = modulo;
let [x, y, u, v] = [0n, 1n, 1n, 0n];
while (a !== 0n) {
const q = b / a;
const r = b % a;
const m = x - u * q;
const n = y - v * q;
[b, a] = [a, r];
[x, y] = [u, v];
[u, v] = [m, n];
}
const gcd = b;
if (gcd !== 1n) throw new Error('invert: does not exist');
return mod(x, modulo);
}
const invertBatch = (nums, n = CURVE.P) => {
const len = nums.length;
const scratch = [];
scratch.length = 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;
}
const pow2 = (x, power) => {
const { P } = CURVE;
let res = x;
while (power-- > 0n) {
res *= res;
res %= P;
}
return res;
}
const pow_2_252_3 = x => {
const { P } = CURVE;
const x2 = (x * x) % P;
const b2 = (x2 * x) % P;
const b4 = (pow2(b2, 2n) * b2) % P;
const b5 = (pow2(b4, 1n) * x) % P;
const b10 = (pow2(b5, 5n) * b5) % P;
const b20 = (pow2(b10, 10n) * b10) % P;
const b40 = (pow2(b20, 20n) * b20) % P;
const b80 = (pow2(b40, 40n) * b40) % P;
const b160 = (pow2(b80, 80n) * b80) % P;
const b240 = (pow2(b160, 80n) * b80) % P;
const b250 = (pow2(b240, 10n) * b10) % P;
const pow_p_5_8 = (pow2(b250, 2n) * x) % P;
return pow_p_5_8;
}
const uvRatio = (u, v) => {
const v3 = mod(v * v * v);
const v7 = mod(v3 * v3 * v);
let x = mod(u * v3 * pow_2_252_3(u * v7));
const vx2 = mod(v * x * x);
const root1 = x;
const root2 = mod(x * SQRT_M1);
const useRoot1 = vx2 === u;
const useRoot2 = vx2 === mod(-u);
const noRoot = vx2 === mod(-u * SQRT_M1);
if (useRoot1)
x = root1;
if (useRoot2 || noRoot)
x = root2;
if (edIsNegative(x))
x = mod(-x);
return { isValid: useRoot1 || useRoot2, value: x };
}
const sha512ToNumberLE = (...args) => {
const messageArray = concatBytes(...args);
const hash = sha512(messageArray);
const value = bytesToNumberLE(hash);
return mod(value, CURVE.n);
}
const encodePrivate = privateBytes => {
const head = privateBytes.slice(0, 32);
head[0] &= 248;
head[31] &= 127;
head[31] |= 64;
return mod(bytesToNumberLE(head), CURVE.n);
}
const isWithinCurveOrder = num => 0 < num && num < CURVE.n;
class ExtendedPoint {
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 Error('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);
}
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 (!isValidScalar(scalar))
throw new Error('Point#multiply: expected number or bigint');
let n = mod(BigInt(scalar), CURVE.n);
if (n === 1n)
return this;
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 = ExtendedPoint.normalizeZ(this.precomputeWindow(W));
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 (!isValidScalar(scalar))
throw new Error('Point#multiply: expected number or bigint');
const n = mod(BigInt(scalar), CURVE.n);
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);
}
}
ExtendedPoint.BASE = new ExtendedPoint(CURVE.Gx, CURVE.Gy, 1n, mod(CURVE.Gx * CURVE.Gy));
ExtendedPoint.ZERO = new ExtendedPoint(0n, 1n, 1n, 0n);
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
static fromHex(hash) {
const { d, P } = CURVE;
const bytes = hash;
if (bytes.length !== 32)
throw new Error('Point.fromHex: expected 32 bytes');
const last = bytes[31];
const normedLast = last & ~0x80;
const isLastByteOdd = (last & 0x80) !== 0;
const normed = Uint8Array.from(Array.from(bytes.slice(0, 31)).concat(normedLast));
const y = bytesToNumberLE(normed);
if (y >= P)
throw new Error('Point.fromHex expects hex <= Fp');
const y2 = mod(y * y);
const u = mod(y2 - 1n);
const v = mod(d * y2 + 1n);
let { isValid, value: x } = uvRatio(u, v);
if (!isValid) throw new Error('Point.fromHex: invalid y coordinate');
const isXOdd = (x & 1n) === 1n;
if (isLastByteOdd !== isXOdd) {
x = mod(-x);
}
return new Point(x, y);
}
static fromPrivateKey(privateKey) {
return Point.BASE.multiply(encodePrivate(sha512(privateKey)));
}
toRawBytes() {
const hex = numberToHex(this.y);
const u8 = new Uint8Array(32);
for (let i = hex.length - 2, j = 0; j < 32 && i >= 0; i -= 2, j++) {
u8[j] = parseInt(hex[i] + hex[i + 1], 16);
}
const mask = this.x & 1n ? 0x80 : 0;
u8[31] |= mask;
return u8;
}
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 = new Point(CURVE.Gx, CURVE.Gy);
Point.ZERO = new Point(0n, 1n);
class Signature {
constructor(r, s) {
this.r = r;
this.s = s;
}
static fromHex(hex) {
const r = Point.fromHex(hex.slice(0, 32));
const s = bytesToNumberLE(hex.slice(32));
if (!isWithinCurveOrder(s))
throw new Error('Signature.fromHex expects s <= CURVE.n');
return new Signature(r, s);
}
toRawBytes() {
const numberBytes = hexToBytes(numberToHex(this.s)).reverse();
const sBytes = new Uint8Array(32);
sBytes.set(numberBytes);
const res = new Uint8Array(64);
res.set(this.r.toRawBytes());
res.set(sBytes, 32);
return res;
}
}
const Ed25519 = {
/**
* @param {Uint8Array} privateKey
* @returns {Uint8Array}
*/
'getPublicKey': privateKey => Point.fromPrivateKey(privateKey).toRawBytes(),
/**
*
* @param {Uint8Array} message
* @param {Uint8Array} privateKey
* @returns {Uint8Array}
*/
'sign': (message, privateKey) => {
const privBytes = sha512(privateKey);
const p = encodePrivate(privBytes);
const P = Point.BASE.multiply(p);
const r = sha512ToNumberLE(privBytes.slice(32), message);
const R = Point.BASE.multiply(r);
const h = sha512ToNumberLE(R.toRawBytes(), P.toRawBytes(), message);
const S = mod(r + h * p, CURVE.n);
const sig = new Signature(R, S);
return sig.toRawBytes();
},
/**
* @param {Uint8Array} message
* @param {Uint8Array} signature
* @param {Uint8Array} publicKey
* @returns {Boolean}
*/
'verify': (message, signature, publicKey) => {
publicKey = Point.fromHex(publicKey);
signature = Signature.fromHex(signature);
const hs = sha512ToNumberLE(signature.r.toRawBytes(), publicKey.toRawBytes(), message);
const Ph = ExtendedPoint.fromAffine(publicKey).multiplyUnsafe(hs);
const Gs = ExtendedPoint.BASE.multiply(signature.s);
const RPh = ExtendedPoint.fromAffine(signature.r).add(Ph);
return RPh.subtract(Gs).multiplyUnsafe(8n).equals(ExtendedPoint.ZERO);
},
};
if (typeof module !== 'undefined') {
module.exports = Ed25519;
} else {
GLOBAL['Ed25519'] = Ed25519;
}
})();
(()=>{const t="undefined"!=typeof globalThis?globalThis:global||self,{BigInt:n,Error:e,Int32Array:s,Uint8Array:i}=t,r=new s([1116352408,3609767458,1899447441,602891725,3049323471,3964484399,3921009573,2173295548,961987163,4081628472,1508970993,3053834265,2453635748,2937671579,2870763221,3664609560,3624381080,2734883394,310598401,1164996542,607225278,1323610764,1426881987,3590304994,1925078388,4068182383,2162078206,991336113,2614888103,633803317,3248222580,3479774868,3835390401,2666613458,4022224774,944711139,264347078,2341262773,604807628,2007800933,770255983,1495990901,1249150122,1856431235,1555081692,3175218132,1996064986,2198950837,2554220882,3999719339,2821834349,766784016,2952996808,2566594879,3210313671,3203337956,3336571891,1034457026,3584528711,2466948901,113926993,3758326383,338241895,168717936,666307205,1188179964,773529912,1546045734,1294757372,1522805485,1396182291,2643833823,1695183700,2343527390,1986661051,1014477480,2177026350,1206759142,2456956037,344077627,2730485921,1290863460,2820302411,3158454273,3259730800,3505952657,3345764771,106217008,3516065817,3606008344,3600352804,1432725776,4094571909,1467031594,275423344,851169720,430227734,3100823752,506948616,1363258195,659060556,3750685593,883997877,3785050280,958139571,3318307427,1322822218,3812723403,1537002063,2003034995,1747873779,3602036899,1955562222,1575990012,2024104815,1125592928,2227730452,2716904306,2361852424,442776044,2428436474,593698344,2756734187,3733110249,3204031479,2999351573,3329325298,3815920427,3391569614,3928383900,3515267271,566280711,3940187606,3454069534,4118630271,4000239992,116418474,1914138554,174292421,2731055270,289380356,3203993006,460393269,320620315,685471733,587496836,852142971,1086792851,1017036298,365543100,1126000580,2618297676,1288033470,3409855158,1501505948,4234509866,1607167915,987167468,1816402316,1246189591]);class o{constructor(){this.t=new s(160),this.i=new s([1779033703,4089235720,3144134277,2227873595,1013904242,4271175723,2773480762,1595750129,1359893119,2917565137,2600822924,725511199,528734635,4215389547,1541459225,327033209]),this.o=this.start=this.h=this.u=0,this.l=this.m=!1}update(t){if(this.l)return;let n,e=0;const i=t.length,r=this.t;for(;e<i;){for(this.m&&(this.m=!1,r.set(new s(33)),r[0]=this.o),n=this.start;e<i&&n<128;e++)r[n>>2]|=t[e]<<(3-(3&n++)<<3);this.p=n,this.h+=n-this.start,n>=128?(this.o=r[32],this.start=n-128,this.hash(),this.m=!0):this.start=n}this.h>4294967295&&(this.u+=this.h/4294967296<<0,this.h%=4294967296)}P(){if(this.l)return;this.l=!0;const t=this.t;let n=this.p;t[32]=this.o,t[n>>2]|=128<<(3-(3&n)<<3),this.o=t[32],n>=112&&(this.m||this.hash(),t.set(new s(33)),t[0]=this.o),t[30]=this.u<<3|this.h>>>29,t[31]=this.h<<3,this.hash();const e=new i(64),r=new DataView(e.buffer);for(let t=0;t<16;t++)r.setInt32(t<<2,this.i[t]);return e}hash(){const t=this.t,n=this.i,e=this.i.slice(),i=new s(4),o=new s(4),h=new s(8);let c,u,f,l,w,a,d,m,p,y;for(u=32;u<160;u+=2)w=t[u-30],a=t[u-29],i[0]=(w>>>1|a<<31)^(w>>>8|a<<24)^w>>>7,i[1]=(a>>>1|w<<31)^(a>>>8|w<<24)^(a>>>7|w<<25),w=t[u-4],a=t[u-3],i[2]=(w>>>19|a<<13)^(a>>>29|w<<3)^w>>>6,i[3]=(a>>>19|w<<13)^(w>>>29|a<<3)^(a>>>6|w<<26),w=t[u-32],a=t[u-31],d=t[u-14],m=t[u-13],o[0]=(65535&m)+(65535&a)+(65535&i[1])+(65535&i[3]),o[1]=(m>>>16)+(a>>>16)+(i[1]>>>16)+(i[3]>>>16)+(o[0]>>>16),o[2]=(65535&d)+(65535&w)+(65535&i[0])+(65535&i[2])+(o[1]>>>16),o[3]=(d>>>16)+(w>>>16)+(i[0]>>>16)+(i[2]>>>16)+(o[2]>>>16),t[u]=o[3]<<16|65535&o[2],t[u+1]=o[1]<<16|65535&o[0];for(h[6]=e[2]&e[4],h[7]=e[3]&e[5],u=0;u<160;u+=8)for(c=0;c<4;c++){const n=8-(c<<1)&7,s=n+1,x=n+8,b=x+1,P=c<<1,g=P+1;i[0]=(e[n]>>>28|e[s]<<4)^(e[s]>>>2|e[n]<<30)^(e[s]>>>7|e[n]<<25),i[1]=(e[s]>>>28|e[n]<<4)^(e[n]>>>2|e[s]<<30)^(e[n]>>>7|e[s]<<25),i[2]=(e[x]>>>14|e[b]<<18)^(e[x]>>>18|e[b]<<14)^(e[b]>>>9|e[x]<<23),i[3]=(e[b]>>>14|e[x]<<18)^(e[b]>>>18|e[x]<<14)^(e[x]>>>9|e[b]<<23),h[P]=e[n]&e[n+2&7],h[g]=e[s]&e[s+2&7],f=h[P]^e[P]&e[P+4&7]^h[P+6&7],l=h[g]^e[g]&e[g+4&7]^h[g+6&7],p=e[x]&e[8+(n+2&7)]^~e[x]&e[8+(n+4&7)],y=e[b]&e[8+(s+2&7)]^~e[b]&e[8+(s+4&7)],w=t[u+P],a=t[u+g],d=r[u+P],m=r[u+g],o[0]=(65535&m)+(65535&a)+(65535&y)+(65535&i[3])+(65535&e[16-g]),o[1]=(m>>>16)+(a>>>16)+(y>>>16)+(i[3]>>>16)+(e[16-g]>>>16)+(o[0]>>>16),o[2]=(65535&d)+(65535&w)+(65535&p)+(65535&i[2])+(65535&e[15-g])+(o[1]>>>16),o[3]=(d>>>16)+(w>>>16)+(p>>>16)+(i[2]>>>16)+(e[15-g]>>>16)+(o[2]>>>16),w=o[3]<<16|65535&o[2],a=o[1]<<16|65535&o[0],o[0]=(65535&l)+(65535&i[1]),o[1]=(l>>>16)+(i[1]>>>16)+(o[0]>>>16),o[2]=(65535&f)+(65535&i[0])+(o[1]>>>16),o[3]=(f>>>16)+(i[0]>>>16)+(o[2]>>>16),d=o[3]<<16|65535&o[2],m=o[1]<<16|65535&o[0],o[0]=(65535&e[8-g])+(65535&a),o[1]=(e[8-g]>>>16)+(a>>>16)+(o[0]>>>16),o[2]=(65535&e[7-g])+(65535&w)+(o[1]>>>16),o[3]=(e[7-g]>>>16)+(w>>>16)+(o[2]>>>16),e[14-P]=o[3]<<16|65535&o[2],e[15-P]=o[1]<<16|65535&o[0],o[0]=(65535&m)+(65535&a),o[1]=(m>>>16)+(a>>>16)+(o[0]>>>16),o[2]=(65535&d)+(65535&w)+(o[1]>>>16),o[3]=(d>>>16)+(w>>>16)+(o[2]>>>16),e[6-P]=o[3]<<16|65535&o[2],e[7-P]=o[1]<<16|65535&o[0]}for(u=0;u<16;u+=2)o[0]=(65535&n[u+1])+(65535&e[u+1]),o[1]=(n[u+1]>>>16)+(e[u+1]>>>16)+(o[0]>>>16),o[2]=(65535&n[u])+(65535&e[u])+(o[1]>>>16),o[3]=(n[u]>>>16)+(e[u]>>>16)+(o[2]>>>16),this.i[u]=o[3]<<16|65535&o[2],this.i[u+1]=o[1]<<16|65535&o[0]}}const h=t=>{const n=new o;return n.update(t),n.P()},c={a:-1n,d:37095705934669439343138083508754565189542113879843219016388785533085940283555n,g:2n**255n-19n,n:2n**252n+27742317777372353535851937790883648493n,i:8n,v:15112221349535400772501151409588531511454012693041857206046113283949847762202n,A:46316835694926478169428394003475163141307993866256225615783033603165251855960n},u=19681161376707505956807079304988542015446066515923890162744021073123829784752n,f=t=>{const n=t.toString(16);return 1&n.length?`0${n}`:n},l=t=>"bigint"==typeof t&&t>0n||"number"==typeof t&&t>0&&Number.isSafeInteger(t),w=t=>{let e=0n;for(let s=0;s<t.length;s++)e+=n(t[s])<<8n*n(s);return e},a=(t,n=c.g)=>{const e=t%n;return e>=0n?e:n+e},d=(t,n=c.g)=>{if(0n===t||n<=0n)throw new e(`invert: expected positive integers, got n=${t} mod=${n}`);let s=a(t,n),i=n,[r,o,h,u]=[0n,1n,1n,0n];for(;0n!==s;){const t=i/s,n=i%s,e=r-h*t,c=o-u*t;[i,s]=[s,n],[r,o]=[h,u],[h,u]=[e,c]}if(1n!==i)throw new e("invert: does not exist");return a(r,n)},m=(t,n)=>{const{g:e}=c;let s=t;for(;n-- >0n;)s*=s,s%=e;return s},p=(...t)=>{const n=((...t)=>{if(1===t.length)return t[0];const n=t.reduce(((t,n)=>t+n.length),0),e=new i(n);for(let n=0,s=0;n<t.length;n++){const i=t[n];e.set(i,s),s+=i.length}return e})(...t),e=h(n),s=w(e);return a(s,c.n)},y=t=>{const n=t.slice(0,32);return n[0]&=248,n[31]&=127,n[31]|=64,a(w(n),c.n)};class x{constructor(t,n,e,s){this.x=t,this.y=n,this.z=e,this.H=s}static I(t){if(!(t instanceof b))throw new e("ExtendedPoint#fromAffine: expected Point");return t.equals(b.ZERO)?x.ZERO:new x(t.x,t.y,1n,a(t.x*t.y))}static B(t){const n=((t,n=c.g)=>{const e=t.length,s=[];s.length=e;let i=1n;for(let r=0;r<e;r++)0n!==t[r]&&(s[r]=i,i=a(i*t[r],n));i=d(i,n);for(let r=e-1;r>=0;r--){if(0n===t[r])continue;let e=a(i*t[r],n);t[r]=a(i*s[r],n),i=e}return t})(t.map((t=>t.z)));return t.map(((t,e)=>t.N(n[e])))}static V(t){return this.B(t).map(this.I)}equals(t){const n=t,[e,s,i,r]=[this.H,n.H,this.z,n.z];return a(e*r)===a(s*i)}F(){return new x(a(-this.x),this.y,this.z,a(-this.H))}R(){const t=this.x,n=this.y,e=this.z,{a:s}=c,i=a(t**2n),r=a(n**2n),o=a(2n*e**2n),h=a(s*i),u=a((t+n)**2n-i-r),f=a(h+r),l=a(f-o),w=a(h-r),d=a(u*l),m=a(f*w),p=a(u*w),y=a(l*f);return new x(d,m,y,p)}add(t){const n=this.x,e=this.y,s=this.z,i=this.H,r=t.x,o=t.y,h=t.z,c=t.H,u=a((e-n)*(o+r)),f=a((e+n)*(o-r)),l=a(f-u);if(0n===l)return this.R();const w=a(2n*s*c),d=a(2n*i*h),m=a(d+w),p=a(f+u),y=a(d-w),b=a(m*l),P=a(p*y),g=a(m*y),v=a(l*p);return new x(b,P,v,g)}U(t){return this.add(t.F())}$(t){if(!l(t))throw new e("Point#multiply: expected number or bigint");let s=a(n(t),c.n);if(1n===s)return this;let i=x.ZERO,r=this;for(;s>0n;)1n&s&&(i=i.add(r)),r=r.R(),s>>=1n;return i}q(t){const n=256/t+1;let e=[],s=this,i=s;for(let r=0;r<n;r++){i=s,e.push(i);for(let n=1;n<2**(t-1);n++)i=i.add(s),e.push(i);s=i.R()}return e}G(t,s){!s&&this.equals(x.K)&&(s=b.K);const i=s&&s.T||1;if(256%i)throw new e("Point#wNAF: Invalid precomputation window, must be power of 2");let r=x.V(this.q(i)),o=x.ZERO,h=x.ZERO;const c=256/i+1,u=2**(i-1),f=n(2**i-1),l=2**i,w=n(i);for(let n=0;n<c;n++){const e=n*u;let s=Number(t&f);if(t>>=w,s>u&&(s-=l,t+=1n),0===s)h=h.add(n%2?r[e].F():r[e]);else{const t=r[e+Math.abs(s)-1];o=o.add(s<0?t.F():t)}}return[o,h]}multiply(t,s){if(!l(t))throw new e("Point#multiply: expected number or bigint");const i=a(n(t),c.n);return x.V(this.G(i,s))[0]}N(t=d(this.z)){const n=a(this.x*t),e=a(this.y*t);return new b(n,e)}}x.K=new x(c.v,c.A,1n,a(c.v*c.A)),x.ZERO=new x(0n,1n,1n,0n);class b{constructor(t,n){this.x=t,this.y=n}static C(t){const{d:n,g:s}=c,r=t;if(32!==r.length)throw new e("Point.fromHex: expected 32 bytes");const o=r[31],h=-129&o,f=0!=(128&o),l=i.from(Array.from(r.slice(0,31)).concat(h)),d=w(l);if(d>=s)throw new e("Point.fromHex expects hex <= Fp");const p=a(d*d),y=a(p-1n),x=a(n*p+1n);let{D:P,value:g}=((t,n)=>{const e=a(n*n*n),s=a(e*e*n);let i=a(t*e*(t=>{const{g:n}=c,e=t*t%n*t%n,s=m(e,2n)*e%n,i=m(s,1n)*t%n,r=m(i,5n)*i%n,o=m(r,10n)*r%n,h=m(o,20n)*o%n,u=m(h,40n)*h%n,f=m(u,80n)*u%n,l=m(f,80n)*u%n,w=m(l,10n)*r%n;return m(w,2n)*t%n})(t*s));const r=a(n*i*i),o=i,h=a(i*u),f=r===t,l=r===a(-t),w=r===a(-t*u);return f&&(i=o),(l||w)&&(i=h),1n===(1n&a(i))&&(i=a(-i)),{D:f||l,value:i}})(y,x);if(!P)throw new e("Point.fromHex: invalid y coordinate");return f!==(1n===(1n&g))&&(g=a(-g)),new b(g,d)}static M(t){return b.K.multiply(y(h(t)))}S(){const t=f(this.y),n=new i(32);for(let e=t.length-2,s=0;s<32&&e>=0;e-=2,s++)n[s]=parseInt(t[e]+t[e+1],16);const e=1n&this.x?128:0;return n[31]|=e,n}equals(t){return this.x===t.x&&this.y===t.y}multiply(t){return x.I(this).multiply(t,this).N()}}b.K=new b(c.v,c.A),b.ZERO=new b(0n,1n);class P{constructor(t,n){this.r=t,this.s=n}static C(t){const n=b.C(t.slice(0,32)),s=w(t.slice(32));if(!(0<(i=s)&&i<c.n))throw new e("Signature.fromHex expects s <= CURVE.n");var i;return new P(n,s)}S(){const t=(t=>{const n=new i(t.length/2);for(let e=0;e<n.length;e++){const s=2*e;n[e]=parseInt(t.slice(s,s+2),16)}return n})(f(this.s)).reverse(),n=new i(32);n.set(t);const e=new i(64);return e.set(this.r.S()),e.set(n,32),e}}const g={getPublicKey:t=>b.M(t).S(),sign:(t,n)=>{const e=h(n),s=y(e),i=b.K.multiply(s),r=p(e.slice(32),t),o=b.K.multiply(r),u=p(o.S(),i.S(),t),f=a(r+u*s,c.n);return new P(o,f).S()},verify:(t,n,e)=>{e=b.C(e),n=P.C(n);const s=p(n.r.S(),e.S(),t),i=x.I(e).$(s),r=x.K.multiply(n.s);return x.I(n.r).add(i).U(r).$(8n).equals(x.ZERO)}};"undefined"!=typeof module?module.exports=g:t.Ed25519=g})()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment