Wallet-session pairing и browser plugin wallet, оплаты пока не работают

This commit is contained in:
AidarKC
2026-06-16 16:23:08 +04:00
parent 5c155ef503
commit 3efa8bb7ee
41 changed files with 3260 additions and 37 deletions
@@ -0,0 +1,78 @@
function getCryptoApi() {
const api = globalThis.crypto;
if (!api?.subtle || typeof api.getRandomValues !== 'function') {
throw new Error('WebCrypto недоступен в текущем браузере.');
}
return api;
}
function getSubtleApi() {
return getCryptoApi().subtle;
}
function base64UrlToBase64(value) {
const normalized = String(value || '').trim().replace(/-/g, '+').replace(/_/g, '/');
return normalized + '='.repeat((4 - (normalized.length % 4)) % 4);
}
export function utf8Bytes(value) {
return new TextEncoder().encode(String(value ?? ''));
}
export function bytesToBase64(bytes) {
let binary = '';
const chunk = 0x8000;
for (let i = 0; i < bytes.length; i += chunk) {
const slice = bytes.subarray(i, i + chunk);
binary += String.fromCharCode(...slice);
}
return btoa(binary);
}
export function base64ToBytes(value) {
const binary = atob(base64UrlToBase64(value));
const out = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i += 1) out[i] = binary.charCodeAt(i);
return out;
}
export async function generateEd25519Pair() {
return getSubtleApi().generateKey({ name: 'Ed25519' }, true, ['sign', 'verify']);
}
export async function exportEd25519PublicKeyB64(publicKey) {
const raw = await getSubtleApi().exportKey('raw', publicKey);
return bytesToBase64(new Uint8Array(raw));
}
export async function exportPkcs8B64(privateKey) {
const raw = await getSubtleApi().exportKey('pkcs8', privateKey);
return bytesToBase64(new Uint8Array(raw));
}
export async function importPkcs8Ed25519(pkcs8B64) {
return getSubtleApi().importKey('pkcs8', base64ToBytes(pkcs8B64), { name: 'Ed25519' }, false, ['sign']);
}
export async function signBase64(privateKey, text) {
const signature = await getSubtleApi().sign({ name: 'Ed25519' }, privateKey, utf8Bytes(text));
return bytesToBase64(new Uint8Array(signature));
}
export async function sha256Bytes(bytes) {
const digest = await getSubtleApi().digest('SHA-256', bytes);
return new Uint8Array(digest);
}
export async function sha256Text(text) {
return sha256Bytes(utf8Bytes(text));
}
export function randomBase64(size) {
const bytes = getCryptoApi().getRandomValues(new Uint8Array(size));
return bytesToBase64(bytes);
}
export function bytesToHex(bytes) {
return [...bytes].map((byte) => byte.toString(16).padStart(2, '0')).join('');
}
@@ -0,0 +1,90 @@
import {
base64ToBytes,
bytesToBase64,
bytesToHex,
exportEd25519PublicKeyB64,
exportPkcs8B64,
generateEd25519Pair,
sha256Bytes,
sha256Text,
utf8Bytes,
} from './crypto-utils.js';
import { edwardsToMontgomeryPriv, x25519 } from './vendor/noble-ed25519-bundle.js';
const PAIRING_ENVELOPE_PREFIX = 'shine-esp-pairing-v1:';
const PAIRING_HASH_PREFIX = 'sha256$';
const PAIRING_HASH_VERSION = 'shine-pairing';
const ED25519_PKCS8_PREFIX = new Uint8Array([
0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x04, 0x22, 0x04, 0x20,
]);
function getCryptoApi() {
const api = globalThis.crypto;
if (!api?.subtle || typeof api.getRandomValues !== 'function') {
throw new Error('WebCrypto недоступен.');
}
return api;
}
async function importAesKeyFromSharedSecret(sharedSecretBytes) {
const digest = await sha256Bytes(sharedSecretBytes);
return getCryptoApi().subtle.importKey('raw', digest, { name: 'AES-GCM' }, false, ['decrypt']);
}
function base64UrlToBytes(value) {
const normalized = String(value || '').trim().replace(/-/g, '+').replace(/_/g, '/');
const padded = normalized + '='.repeat((4 - (normalized.length % 4)) % 4);
return base64ToBytes(padded);
}
function extractSeedFromPkcs8(pkcs8B64) {
const raw = base64ToBytes(pkcs8B64);
if (raw.length !== ED25519_PKCS8_PREFIX.length + 32) {
throw new Error('Некорректный приватный Ed25519 ключ');
}
for (let i = 0; i < ED25519_PKCS8_PREFIX.length; i += 1) {
if (raw[i] !== ED25519_PKCS8_PREFIX[i]) {
throw new Error('Неподдерживаемый формат приватного Ed25519 ключа');
}
}
return raw.slice(ED25519_PKCS8_PREFIX.length);
}
export async function createRequesterPairingMaterial() {
const sessionPair = await generateEd25519Pair();
const sessionPublicB64 = await exportEd25519PublicKeyB64(sessionPair.publicKey);
return {
sessionKey: `ed25519/${sessionPublicB64}`,
sessionPrivPkcs8: await exportPkcs8B64(sessionPair.privateKey),
};
}
export async function deriveEspPairingPasswordHash(login, password) {
const loginLower = String(login || '').trim().toLowerCase();
const preimage = `${PAIRING_HASH_VERSION}|${loginLower}|${String(password ?? '')}`;
const digest = await sha256Text(preimage);
return `${PAIRING_HASH_PREFIX}${bytesToHex(digest)}`;
}
export async function decryptPairingPayloadFromEnvelope(encryptedPayload, requesterPairingMaterial) {
const raw = String(encryptedPayload || '').trim();
if (!raw.startsWith(PAIRING_ENVELOPE_PREFIX)) {
throw new Error('Неподдерживаемый формат pairing payload');
}
const jsonBytes = base64UrlToBytes(raw.slice(PAIRING_ENVELOPE_PREFIX.length));
const envelope = JSON.parse(new TextDecoder().decode(jsonBytes));
if (Number(envelope?.v) !== 1 || String(envelope?.alg || '') !== 'x25519-aes256-gcm') {
throw new Error('Неподдерживаемая версия pairing payload');
}
const requesterSeed = extractSeedFromPkcs8(String(requesterPairingMaterial?.sessionPrivPkcs8 || ''));
const requesterMontPriv = edwardsToMontgomeryPriv(requesterSeed);
const sharedSecret = x25519.getSharedSecret(requesterMontPriv, base64ToBytes(String(envelope?.ephPubB64 || '')));
const aesKey = await importAesKeyFromSharedSecret(sharedSecret);
const plain = await getCryptoApi().subtle.decrypt(
{ name: 'AES-GCM', iv: base64ToBytes(String(envelope?.ivB64 || '')) },
aesKey,
base64ToBytes(String(envelope?.cipherB64 || '')),
);
return JSON.parse(new TextDecoder().decode(plain));
}
@@ -0,0 +1,152 @@
import { base64ToBytes, bytesToBase64 } from './crypto-utils.js';
const DB_NAME = 'shine-wallet-plugin';
const DB_VERSION = 1;
const STORE_META = 'meta';
const STORE_VAULT = 'vault';
const SESSION_ENTRY_ID = 'active-session';
const VAULT_KEY_ID = 'session-wrap-key';
function openDb() {
return new Promise((resolve, reject) => {
const request = indexedDB.open(DB_NAME, DB_VERSION);
request.onupgradeneeded = () => {
const db = request.result;
if (!db.objectStoreNames.contains(STORE_META)) {
db.createObjectStore(STORE_META, { keyPath: 'id' });
}
if (!db.objectStoreNames.contains(STORE_VAULT)) {
db.createObjectStore(STORE_VAULT, { keyPath: 'id' });
}
};
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error || new Error('IndexedDB недоступен'));
});
}
async function withStore(storeName, mode, run) {
const db = await openDb();
try {
return await new Promise((resolve, reject) => {
const tx = db.transaction(storeName, mode);
const store = tx.objectStore(storeName);
let settled = false;
const done = (fn) => (value) => {
if (settled) return;
settled = true;
fn(value);
};
tx.oncomplete = () => done(resolve)(undefined);
tx.onerror = () => done(reject)(tx.error || new Error('IndexedDB transaction failed'));
Promise.resolve(run(store, tx, done)).catch((error) => done(reject)(error));
});
} finally {
db.close();
}
}
async function put(storeName, value) {
return withStore(storeName, 'readwrite', (store) => {
store.put(value);
});
}
async function get(storeName, key) {
const db = await openDb();
try {
return await new Promise((resolve, reject) => {
const tx = db.transaction(storeName, 'readonly');
const req = tx.objectStore(storeName).get(key);
req.onsuccess = () => resolve(req.result || null);
req.onerror = () => reject(req.error || new Error('Ошибка чтения из IndexedDB'));
});
} finally {
db.close();
}
}
async function deleteById(storeName, key) {
return withStore(storeName, 'readwrite', (store) => {
store.delete(key);
});
}
async function getOrCreateVaultKey() {
const current = await get(STORE_META, VAULT_KEY_ID);
if (current?.key) return current.key;
const key = await crypto.subtle.generateKey(
{ name: 'AES-GCM', length: 256 },
false,
['encrypt', 'decrypt'],
);
await put(STORE_META, { id: VAULT_KEY_ID, key, createdAtMs: Date.now() });
return key;
}
async function encryptJson(value) {
const key = await getOrCreateVaultKey();
const iv = crypto.getRandomValues(new Uint8Array(12));
const plainBytes = new TextEncoder().encode(JSON.stringify(value));
const cipher = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, plainBytes);
return {
ivB64: bytesToBase64(iv),
cipherB64: bytesToBase64(new Uint8Array(cipher)),
};
}
async function decryptJson(envelope) {
const key = await getOrCreateVaultKey();
const plain = await crypto.subtle.decrypt(
{ name: 'AES-GCM', iv: base64ToBytes(envelope.ivB64) },
key,
base64ToBytes(envelope.cipherB64),
);
return JSON.parse(new TextDecoder().decode(plain));
}
function storageApi() {
if (globalThis.chrome?.storage?.local) return globalThis.chrome.storage.local;
return null;
}
export async function savePluginSettings(settings) {
const api = storageApi();
if (api) {
await api.set({ shineWalletSettings: settings });
return;
}
localStorage.setItem('shineWalletSettings', JSON.stringify(settings));
}
export async function loadPluginSettings() {
const api = storageApi();
if (api) {
const row = await api.get('shineWalletSettings');
return row?.shineWalletSettings || {};
}
try {
return JSON.parse(localStorage.getItem('shineWalletSettings') || '{}');
} catch {
return {};
}
}
export async function saveSessionMaterial(sessionRecord) {
const encrypted = await encryptJson(sessionRecord);
await put(STORE_VAULT, {
id: SESSION_ENTRY_ID,
encrypted,
updatedAtMs: Date.now(),
});
}
export async function loadSessionMaterial() {
const row = await get(STORE_VAULT, SESSION_ENTRY_ID);
if (!row?.encrypted) return null;
return decryptJson(row.encrypted);
}
export async function clearSessionMaterial() {
await deleteById(STORE_VAULT, SESSION_ENTRY_ID);
}
@@ -0,0 +1,111 @@
import { importPkcs8Ed25519, signBase64 } from './crypto-utils.js';
import { WsJsonClient } from './ws-client.js';
const SESSION_TYPE_WALLET = 50;
function normalizeServerUrl(url) {
const value = String(url || '').trim();
if (!value) return 'wss://shineup.me/ws';
if (value.startsWith('ws://') || value.startsWith('wss://')) return value;
if (value.startsWith('http://') || value.startsWith('https://')) {
const parsed = new URL(value);
parsed.protocol = parsed.protocol === 'https:' ? 'wss:' : 'ws:';
if (!parsed.pathname || parsed.pathname === '/') parsed.pathname = '/ws';
return parsed.toString();
}
return value;
}
function opError(op, response) {
const payload = response?.payload || {};
const message = payload?.message || response?.message || payload?.error || response?.error || 'Unknown server error';
const code = String(payload?.code || response?.code || payload?.error || response?.error || 'UNKNOWN').toUpperCase();
const error = new Error(`${op}: ${message} (${code})`);
error.op = op;
error.code = code;
error.status = response?.status || 0;
return error;
}
export class ShineApiClient {
constructor(serverUrl) {
this.serverUrl = normalizeServerUrl(serverUrl);
this.ws = new WsJsonClient(this.serverUrl);
}
async getUser(login) {
const response = await this.ws.request('GetUser', { login: String(login || '').trim() });
if (response.status !== 200) throw opError('GetUser', response);
return response.payload || {};
}
async startEspPairing({ login, passwordHash, requesterSessionKey, payloadType = 1 }) {
const response = await this.ws.request('StartEspPairing', {
login: String(login || '').trim(),
passwordHash: String(passwordHash || '').trim(),
requesterSessionKey: String(requesterSessionKey || '').trim(),
requesterSessionType: SESSION_TYPE_WALLET,
requesterClientPlatform: 'Chrome Extension Wallet',
payloadType: Number(payloadType) || 1,
});
if (response.status !== 200) throw opError('StartEspPairing', response);
return response.payload || {};
}
async getEspPairingStatus(pairingId) {
const response = await this.ws.request('GetEspPairingStatus', {
pairingId: String(pairingId || '').trim(),
});
if (response.status !== 200) throw opError('GetEspPairingStatus', response);
return response.payload || {};
}
async cancelEspPairing(pairingId, requesterSessionKey) {
const response = await this.ws.request('CancelEspPairing', {
pairingId: String(pairingId || '').trim(),
requesterSessionKey: String(requesterSessionKey || '').trim(),
});
if (response.status !== 200) throw opError('CancelEspPairing', response);
return response.payload || {};
}
async resumeSession(sessionRecord) {
const login = String(sessionRecord?.login || '').trim();
const sessionId = String(sessionRecord?.sessionId || '').trim();
const sessionKey = String(sessionRecord?.sessionKey || '').trim();
const sessionPrivPkcs8 = String(sessionRecord?.sessionPrivPkcs8 || '').trim();
if (!login || !sessionId || !sessionKey || !sessionPrivPkcs8) {
throw new Error('Сохранённая wallet-session неполная');
}
const privateKey = await importPkcs8Ed25519(sessionPrivPkcs8);
const challengeResp = await this.ws.request('SessionChallenge', { sessionId });
if (challengeResp.status !== 200) throw opError('SessionChallenge', challengeResp);
const nonce = challengeResp?.payload?.nonce;
if (!nonce) throw new Error('SessionChallenge: сервер не вернул nonce');
const timeMs = Date.now();
const preimage = `SESSION_LOGIN:${sessionId}:${timeMs}:${nonce}`;
const signatureB64 = await signBase64(privateKey, preimage);
const loginResp = await this.ws.request('SessionLogin', {
sessionId,
sessionKey,
timeMs,
signatureB64,
sessionType: Number(sessionRecord?.sessionType || SESSION_TYPE_WALLET) || SESSION_TYPE_WALLET,
clientPlatform: 'Chrome Extension Wallet',
clientInfo: 'SHiNE Browser Plugin Wallet',
});
if (loginResp.status !== 200) throw opError('SessionLogin', loginResp);
return {
login,
sessionId,
storagePwd: String(loginResp?.payload?.storagePwd || '').trim(),
};
}
close() {
this.ws.close();
}
}
@@ -0,0 +1,995 @@
// node_modules/@noble/curves/node_modules/@noble/hashes/esm/_assert.js
function isBytes(a) {
return a instanceof Uint8Array || a != null && typeof a === "object" && a.constructor.name === "Uint8Array";
}
function bytes(b, ...lengths) {
if (!isBytes(b))
throw new Error("Uint8Array expected");
if (lengths.length > 0 && !lengths.includes(b.length))
throw new Error(`Uint8Array expected of length ${lengths}, not of length=${b.length}`);
}
function exists(instance, checkFinished = true) {
if (instance.destroyed)
throw new Error("Hash instance has been destroyed");
if (checkFinished && instance.finished)
throw new Error("Hash#digest() has already been called");
}
function output(out, instance) {
bytes(out);
const min = instance.outputLen;
if (out.length < min) {
throw new Error(`digestInto() expects output buffer of length at least ${min}`);
}
}
// node_modules/@noble/curves/node_modules/@noble/hashes/esm/crypto.js
var crypto = typeof globalThis === "object" && "crypto" in globalThis ? globalThis.crypto : void 0;
// node_modules/@noble/curves/node_modules/@noble/hashes/esm/utils.js
var createView = (arr) => new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
var isLE = new Uint8Array(new Uint32Array([287454020]).buffer)[0] === 68;
function utf8ToBytes(str) {
if (typeof str !== "string")
throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
return new Uint8Array(new TextEncoder().encode(str));
}
function toBytes(data) {
if (typeof data === "string")
data = utf8ToBytes(data);
bytes(data);
return data;
}
var Hash = class {
// Safe version that clones internal state
clone() {
return this._cloneInto();
}
};
var toStr = {}.toString;
function wrapConstructor(hashCons) {
const hashC = (msg) => hashCons().update(toBytes(msg)).digest();
const tmp = hashCons();
hashC.outputLen = tmp.outputLen;
hashC.blockLen = tmp.blockLen;
hashC.create = () => hashCons();
return hashC;
}
function randomBytes(bytesLength = 32) {
if (crypto && typeof crypto.getRandomValues === "function") {
return crypto.getRandomValues(new Uint8Array(bytesLength));
}
throw new Error("crypto.getRandomValues must be defined");
}
// node_modules/@noble/curves/node_modules/@noble/hashes/esm/_md.js
function setBigUint64(view, byteOffset, value, isLE2) {
if (typeof view.setBigUint64 === "function")
return view.setBigUint64(byteOffset, value, isLE2);
const _32n2 = BigInt(32);
const _u32_max = BigInt(4294967295);
const wh = Number(value >> _32n2 & _u32_max);
const wl = Number(value & _u32_max);
const h = isLE2 ? 4 : 0;
const l = isLE2 ? 0 : 4;
view.setUint32(byteOffset + h, wh, isLE2);
view.setUint32(byteOffset + l, wl, isLE2);
}
var HashMD = class extends Hash {
constructor(blockLen, outputLen, padOffset, isLE2) {
super();
this.blockLen = blockLen;
this.outputLen = outputLen;
this.padOffset = padOffset;
this.isLE = isLE2;
this.finished = false;
this.length = 0;
this.pos = 0;
this.destroyed = false;
this.buffer = new Uint8Array(blockLen);
this.view = createView(this.buffer);
}
update(data) {
exists(this);
const { view, buffer, blockLen } = this;
data = toBytes(data);
const len = data.length;
for (let pos = 0; pos < len; ) {
const take = Math.min(blockLen - this.pos, len - pos);
if (take === blockLen) {
const dataView = createView(data);
for (; blockLen <= len - pos; pos += blockLen)
this.process(dataView, pos);
continue;
}
buffer.set(data.subarray(pos, pos + take), this.pos);
this.pos += take;
pos += take;
if (this.pos === blockLen) {
this.process(view, 0);
this.pos = 0;
}
}
this.length += data.length;
this.roundClean();
return this;
}
digestInto(out) {
exists(this);
output(out, this);
this.finished = true;
const { buffer, view, blockLen, isLE: isLE2 } = this;
let { pos } = this;
buffer[pos++] = 128;
this.buffer.subarray(pos).fill(0);
if (this.padOffset > blockLen - pos) {
this.process(view, 0);
pos = 0;
}
for (let i = pos; i < blockLen; i++)
buffer[i] = 0;
setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE2);
this.process(view, 0);
const oview = createView(out);
const len = this.outputLen;
if (len % 4)
throw new Error("_sha2: outputLen should be aligned to 32bit");
const outLen = len / 4;
const state = this.get();
if (outLen > state.length)
throw new Error("_sha2: outputLen bigger than state");
for (let i = 0; i < outLen; i++)
oview.setUint32(4 * i, state[i], isLE2);
}
digest() {
const { buffer, outputLen } = this;
this.digestInto(buffer);
const res = buffer.slice(0, outputLen);
this.destroy();
return res;
}
_cloneInto(to) {
to || (to = new this.constructor());
to.set(...this.get());
const { blockLen, buffer, length, finished, destroyed, pos } = this;
to.length = length;
to.pos = pos;
to.finished = finished;
to.destroyed = destroyed;
if (length % blockLen)
to.buffer.set(buffer);
return to;
}
};
// node_modules/@noble/curves/node_modules/@noble/hashes/esm/_u64.js
var U32_MASK64 = /* @__PURE__ */ BigInt(2 ** 32 - 1);
var _32n = /* @__PURE__ */ BigInt(32);
function fromBig(n, le = false) {
if (le)
return { h: Number(n & U32_MASK64), l: Number(n >> _32n & U32_MASK64) };
return { h: Number(n >> _32n & U32_MASK64) | 0, l: Number(n & U32_MASK64) | 0 };
}
function split(lst, le = false) {
let Ah = new Uint32Array(lst.length);
let Al = new Uint32Array(lst.length);
for (let i = 0; i < lst.length; i++) {
const { h, l } = fromBig(lst[i], le);
[Ah[i], Al[i]] = [h, l];
}
return [Ah, Al];
}
var toBig = (h, l) => BigInt(h >>> 0) << _32n | BigInt(l >>> 0);
var shrSH = (h, _l, s) => h >>> s;
var shrSL = (h, l, s) => h << 32 - s | l >>> s;
var rotrSH = (h, l, s) => h >>> s | l << 32 - s;
var rotrSL = (h, l, s) => h << 32 - s | l >>> s;
var rotrBH = (h, l, s) => h << 64 - s | l >>> s - 32;
var rotrBL = (h, l, s) => h >>> s - 32 | l << 64 - s;
var rotr32H = (_h, l) => l;
var rotr32L = (h, _l) => h;
var rotlSH = (h, l, s) => h << s | l >>> 32 - s;
var rotlSL = (h, l, s) => l << s | h >>> 32 - s;
var rotlBH = (h, l, s) => l << s - 32 | h >>> 64 - s;
var rotlBL = (h, l, s) => h << s - 32 | l >>> 64 - s;
function add(Ah, Al, Bh, Bl) {
const l = (Al >>> 0) + (Bl >>> 0);
return { h: Ah + Bh + (l / 2 ** 32 | 0) | 0, l: l | 0 };
}
var add3L = (Al, Bl, Cl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0);
var add3H = (low, Ah, Bh, Ch) => Ah + Bh + Ch + (low / 2 ** 32 | 0) | 0;
var add4L = (Al, Bl, Cl, Dl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0);
var add4H = (low, Ah, Bh, Ch, Dh) => Ah + Bh + Ch + Dh + (low / 2 ** 32 | 0) | 0;
var add5L = (Al, Bl, Cl, Dl, El) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0) + (El >>> 0);
var add5H = (low, Ah, Bh, Ch, Dh, Eh) => Ah + Bh + Ch + Dh + Eh + (low / 2 ** 32 | 0) | 0;
var u64 = {
fromBig,
split,
toBig,
shrSH,
shrSL,
rotrSH,
rotrSL,
rotrBH,
rotrBL,
rotr32H,
rotr32L,
rotlSH,
rotlSL,
rotlBH,
rotlBL,
add,
add3L,
add3H,
add4L,
add4H,
add5H,
add5L
};
var u64_default = u64;
// node_modules/@noble/curves/node_modules/@noble/hashes/esm/sha512.js
var [SHA512_Kh, SHA512_Kl] = /* @__PURE__ */ (() => u64_default.split([
"0x428a2f98d728ae22",
"0x7137449123ef65cd",
"0xb5c0fbcfec4d3b2f",
"0xe9b5dba58189dbbc",
"0x3956c25bf348b538",
"0x59f111f1b605d019",
"0x923f82a4af194f9b",
"0xab1c5ed5da6d8118",
"0xd807aa98a3030242",
"0x12835b0145706fbe",
"0x243185be4ee4b28c",
"0x550c7dc3d5ffb4e2",
"0x72be5d74f27b896f",
"0x80deb1fe3b1696b1",
"0x9bdc06a725c71235",
"0xc19bf174cf692694",
"0xe49b69c19ef14ad2",
"0xefbe4786384f25e3",
"0x0fc19dc68b8cd5b5",
"0x240ca1cc77ac9c65",
"0x2de92c6f592b0275",
"0x4a7484aa6ea6e483",
"0x5cb0a9dcbd41fbd4",
"0x76f988da831153b5",
"0x983e5152ee66dfab",
"0xa831c66d2db43210",
"0xb00327c898fb213f",
"0xbf597fc7beef0ee4",
"0xc6e00bf33da88fc2",
"0xd5a79147930aa725",
"0x06ca6351e003826f",
"0x142929670a0e6e70",
"0x27b70a8546d22ffc",
"0x2e1b21385c26c926",
"0x4d2c6dfc5ac42aed",
"0x53380d139d95b3df",
"0x650a73548baf63de",
"0x766a0abb3c77b2a8",
"0x81c2c92e47edaee6",
"0x92722c851482353b",
"0xa2bfe8a14cf10364",
"0xa81a664bbc423001",
"0xc24b8b70d0f89791",
"0xc76c51a30654be30",
"0xd192e819d6ef5218",
"0xd69906245565a910",
"0xf40e35855771202a",
"0x106aa07032bbd1b8",
"0x19a4c116b8d2d0c8",
"0x1e376c085141ab53",
"0x2748774cdf8eeb99",
"0x34b0bcb5e19b48a8",
"0x391c0cb3c5c95a63",
"0x4ed8aa4ae3418acb",
"0x5b9cca4f7763e373",
"0x682e6ff3d6b2b8a3",
"0x748f82ee5defb2fc",
"0x78a5636f43172f60",
"0x84c87814a1f0ab72",
"0x8cc702081a6439ec",
"0x90befffa23631e28",
"0xa4506cebde82bde9",
"0xbef9a3f7b2c67915",
"0xc67178f2e372532b",
"0xca273eceea26619c",
"0xd186b8c721c0c207",
"0xeada7dd6cde0eb1e",
"0xf57d4f7fee6ed178",
"0x06f067aa72176fba",
"0x0a637dc5a2c898a6",
"0x113f9804bef90dae",
"0x1b710b35131c471b",
"0x28db77f523047d84",
"0x32caab7b40c72493",
"0x3c9ebe0a15c9bebc",
"0x431d67c49c100d4c",
"0x4cc5d4becb3e42b6",
"0x597f299cfc657e2a",
"0x5fcb6fab3ad6faec",
"0x6c44198c4a475817"
].map((n) => BigInt(n))))();
var SHA512_W_H = /* @__PURE__ */ new Uint32Array(80);
var SHA512_W_L = /* @__PURE__ */ new Uint32Array(80);
var SHA512 = class extends HashMD {
constructor() {
super(128, 64, 16, false);
this.Ah = 1779033703 | 0;
this.Al = 4089235720 | 0;
this.Bh = 3144134277 | 0;
this.Bl = 2227873595 | 0;
this.Ch = 1013904242 | 0;
this.Cl = 4271175723 | 0;
this.Dh = 2773480762 | 0;
this.Dl = 1595750129 | 0;
this.Eh = 1359893119 | 0;
this.El = 2917565137 | 0;
this.Fh = 2600822924 | 0;
this.Fl = 725511199 | 0;
this.Gh = 528734635 | 0;
this.Gl = 4215389547 | 0;
this.Hh = 1541459225 | 0;
this.Hl = 327033209 | 0;
}
// prettier-ignore
get() {
const { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this;
return [Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl];
}
// prettier-ignore
set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl) {
this.Ah = Ah | 0;
this.Al = Al | 0;
this.Bh = Bh | 0;
this.Bl = Bl | 0;
this.Ch = Ch | 0;
this.Cl = Cl | 0;
this.Dh = Dh | 0;
this.Dl = Dl | 0;
this.Eh = Eh | 0;
this.El = El | 0;
this.Fh = Fh | 0;
this.Fl = Fl | 0;
this.Gh = Gh | 0;
this.Gl = Gl | 0;
this.Hh = Hh | 0;
this.Hl = Hl | 0;
}
process(view, offset) {
for (let i = 0; i < 16; i++, offset += 4) {
SHA512_W_H[i] = view.getUint32(offset);
SHA512_W_L[i] = view.getUint32(offset += 4);
}
for (let i = 16; i < 80; i++) {
const W15h = SHA512_W_H[i - 15] | 0;
const W15l = SHA512_W_L[i - 15] | 0;
const s0h = u64_default.rotrSH(W15h, W15l, 1) ^ u64_default.rotrSH(W15h, W15l, 8) ^ u64_default.shrSH(W15h, W15l, 7);
const s0l = u64_default.rotrSL(W15h, W15l, 1) ^ u64_default.rotrSL(W15h, W15l, 8) ^ u64_default.shrSL(W15h, W15l, 7);
const W2h = SHA512_W_H[i - 2] | 0;
const W2l = SHA512_W_L[i - 2] | 0;
const s1h = u64_default.rotrSH(W2h, W2l, 19) ^ u64_default.rotrBH(W2h, W2l, 61) ^ u64_default.shrSH(W2h, W2l, 6);
const s1l = u64_default.rotrSL(W2h, W2l, 19) ^ u64_default.rotrBL(W2h, W2l, 61) ^ u64_default.shrSL(W2h, W2l, 6);
const SUMl = u64_default.add4L(s0l, s1l, SHA512_W_L[i - 7], SHA512_W_L[i - 16]);
const SUMh = u64_default.add4H(SUMl, s0h, s1h, SHA512_W_H[i - 7], SHA512_W_H[i - 16]);
SHA512_W_H[i] = SUMh | 0;
SHA512_W_L[i] = SUMl | 0;
}
let { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this;
for (let i = 0; i < 80; i++) {
const sigma1h = u64_default.rotrSH(Eh, El, 14) ^ u64_default.rotrSH(Eh, El, 18) ^ u64_default.rotrBH(Eh, El, 41);
const sigma1l = u64_default.rotrSL(Eh, El, 14) ^ u64_default.rotrSL(Eh, El, 18) ^ u64_default.rotrBL(Eh, El, 41);
const CHIh = Eh & Fh ^ ~Eh & Gh;
const CHIl = El & Fl ^ ~El & Gl;
const T1ll = u64_default.add5L(Hl, sigma1l, CHIl, SHA512_Kl[i], SHA512_W_L[i]);
const T1h = u64_default.add5H(T1ll, Hh, sigma1h, CHIh, SHA512_Kh[i], SHA512_W_H[i]);
const T1l = T1ll | 0;
const sigma0h = u64_default.rotrSH(Ah, Al, 28) ^ u64_default.rotrBH(Ah, Al, 34) ^ u64_default.rotrBH(Ah, Al, 39);
const sigma0l = u64_default.rotrSL(Ah, Al, 28) ^ u64_default.rotrBL(Ah, Al, 34) ^ u64_default.rotrBL(Ah, Al, 39);
const MAJh = Ah & Bh ^ Ah & Ch ^ Bh & Ch;
const MAJl = Al & Bl ^ Al & Cl ^ Bl & Cl;
Hh = Gh | 0;
Hl = Gl | 0;
Gh = Fh | 0;
Gl = Fl | 0;
Fh = Eh | 0;
Fl = El | 0;
({ h: Eh, l: El } = u64_default.add(Dh | 0, Dl | 0, T1h | 0, T1l | 0));
Dh = Ch | 0;
Dl = Cl | 0;
Ch = Bh | 0;
Cl = Bl | 0;
Bh = Ah | 0;
Bl = Al | 0;
const All = u64_default.add3L(T1l, sigma0l, MAJl);
Ah = u64_default.add3H(All, T1h, sigma0h, MAJh);
Al = All | 0;
}
({ h: Ah, l: Al } = u64_default.add(this.Ah | 0, this.Al | 0, Ah | 0, Al | 0));
({ h: Bh, l: Bl } = u64_default.add(this.Bh | 0, this.Bl | 0, Bh | 0, Bl | 0));
({ h: Ch, l: Cl } = u64_default.add(this.Ch | 0, this.Cl | 0, Ch | 0, Cl | 0));
({ h: Dh, l: Dl } = u64_default.add(this.Dh | 0, this.Dl | 0, Dh | 0, Dl | 0));
({ h: Eh, l: El } = u64_default.add(this.Eh | 0, this.El | 0, Eh | 0, El | 0));
({ h: Fh, l: Fl } = u64_default.add(this.Fh | 0, this.Fl | 0, Fh | 0, Fl | 0));
({ h: Gh, l: Gl } = u64_default.add(this.Gh | 0, this.Gl | 0, Gh | 0, Gl | 0));
({ h: Hh, l: Hl } = u64_default.add(this.Hh | 0, this.Hl | 0, Hh | 0, Hl | 0));
this.set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl);
}
roundClean() {
SHA512_W_H.fill(0);
SHA512_W_L.fill(0);
}
destroy() {
this.buffer.fill(0);
this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
};
var sha512 = /* @__PURE__ */ wrapConstructor(() => new SHA512());
// node_modules/@noble/curves/esm/abstract/utils.js
var _0n = /* @__PURE__ */ BigInt(0);
var _1n = /* @__PURE__ */ BigInt(1);
var _2n = /* @__PURE__ */ BigInt(2);
function isBytes2(a) {
return a instanceof Uint8Array || a != null && typeof a === "object" && a.constructor.name === "Uint8Array";
}
function abytes(item) {
if (!isBytes2(item))
throw new Error("Uint8Array expected");
}
var hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
function bytesToHex(bytes2) {
abytes(bytes2);
let hex = "";
for (let i = 0; i < bytes2.length; i++) {
hex += hexes[bytes2[i]];
}
return hex;
}
function hexToNumber(hex) {
if (typeof hex !== "string")
throw new Error("hex string expected, got " + typeof hex);
return BigInt(hex === "" ? "0" : `0x${hex}`);
}
var asciis = { _0: 48, _9: 57, _A: 65, _F: 70, _a: 97, _f: 102 };
function asciiToBase16(char) {
if (char >= asciis._0 && char <= asciis._9)
return char - asciis._0;
if (char >= asciis._A && char <= asciis._F)
return char - (asciis._A - 10);
if (char >= asciis._a && char <= asciis._f)
return char - (asciis._a - 10);
return;
}
function hexToBytes(hex) {
if (typeof hex !== "string")
throw new Error("hex string expected, got " + typeof hex);
const hl = hex.length;
const al = hl / 2;
if (hl % 2)
throw new Error("padded hex string expected, got unpadded hex of length " + hl);
const array = new Uint8Array(al);
for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {
const n1 = asciiToBase16(hex.charCodeAt(hi));
const n2 = asciiToBase16(hex.charCodeAt(hi + 1));
if (n1 === void 0 || n2 === void 0) {
const char = hex[hi] + hex[hi + 1];
throw new Error('hex string expected, got non-hex character "' + char + '" at index ' + hi);
}
array[ai] = n1 * 16 + n2;
}
return array;
}
function bytesToNumberBE(bytes2) {
return hexToNumber(bytesToHex(bytes2));
}
function bytesToNumberLE(bytes2) {
abytes(bytes2);
return hexToNumber(bytesToHex(Uint8Array.from(bytes2).reverse()));
}
function numberToBytesBE(n, len) {
return hexToBytes(n.toString(16).padStart(len * 2, "0"));
}
function numberToBytesLE(n, len) {
return numberToBytesBE(n, len).reverse();
}
function ensureBytes(title, hex, expectedLength) {
let res;
if (typeof hex === "string") {
try {
res = hexToBytes(hex);
} catch (e) {
throw new Error(`${title} must be valid hex string, got "${hex}". Cause: ${e}`);
}
} else if (isBytes2(hex)) {
res = Uint8Array.from(hex);
} else {
throw new Error(`${title} must be hex string or Uint8Array`);
}
const len = res.length;
if (typeof expectedLength === "number" && len !== expectedLength)
throw new Error(`${title} expected ${expectedLength} bytes, got ${len}`);
return res;
}
var isPosBig = (n) => typeof n === "bigint" && _0n <= n;
function inRange(n, min, max) {
return isPosBig(n) && isPosBig(min) && isPosBig(max) && min <= n && n < max;
}
function aInRange(title, n, min, max) {
if (!inRange(n, min, max))
throw new Error(`expected valid ${title}: ${min} <= n < ${max}, got ${typeof n} ${n}`);
}
var bitMask = (n) => (_2n << BigInt(n - 1)) - _1n;
var validatorFns = {
bigint: (val) => typeof val === "bigint",
function: (val) => typeof val === "function",
boolean: (val) => typeof val === "boolean",
string: (val) => typeof val === "string",
stringOrUint8Array: (val) => typeof val === "string" || isBytes2(val),
isSafeInteger: (val) => Number.isSafeInteger(val),
array: (val) => Array.isArray(val),
field: (val, object) => object.Fp.isValid(val),
hash: (val) => typeof val === "function" && Number.isSafeInteger(val.outputLen)
};
function validateObject(object, validators, optValidators = {}) {
const checkField = (fieldName, type, isOptional) => {
const checkVal = validatorFns[type];
if (typeof checkVal !== "function")
throw new Error(`Invalid validator "${type}", expected function`);
const val = object[fieldName];
if (isOptional && val === void 0)
return;
if (!checkVal(val, object)) {
throw new Error(`Invalid param ${String(fieldName)}=${val} (${typeof val}), expected ${type}`);
}
};
for (const [fieldName, type] of Object.entries(validators))
checkField(fieldName, type, false);
for (const [fieldName, type] of Object.entries(optValidators))
checkField(fieldName, type, true);
return object;
}
// node_modules/@noble/curves/esm/abstract/modular.js
var _0n2 = BigInt(0);
var _1n2 = BigInt(1);
var _2n2 = BigInt(2);
var _3n = BigInt(3);
var _4n = BigInt(4);
var _5n = BigInt(5);
var _8n = BigInt(8);
var _9n = BigInt(9);
var _16n = BigInt(16);
function mod(a, b) {
const result = a % b;
return result >= _0n2 ? result : b + result;
}
function pow(num, power, modulo) {
if (modulo <= _0n2 || power < _0n2)
throw new Error("Expected power/modulo > 0");
if (modulo === _1n2)
return _0n2;
let res = _1n2;
while (power > _0n2) {
if (power & _1n2)
res = res * num % modulo;
num = num * num % modulo;
power >>= _1n2;
}
return res;
}
function pow2(x, power, modulo) {
let res = x;
while (power-- > _0n2) {
res *= res;
res %= modulo;
}
return res;
}
function invert(number, modulo) {
if (number === _0n2 || modulo <= _0n2) {
throw new Error(`invert: expected positive integers, got n=${number} mod=${modulo}`);
}
let a = mod(number, modulo);
let b = modulo;
let x = _0n2, y = _1n2, u = _1n2, v = _0n2;
while (a !== _0n2) {
const q = b / a;
const r = b % a;
const m = x - u * q;
const n = y - v * q;
b = a, a = r, x = u, y = v, u = m, v = n;
}
const gcd = b;
if (gcd !== _1n2)
throw new Error("invert: does not exist");
return mod(x, modulo);
}
function tonelliShanks(P) {
const legendreC = (P - _1n2) / _2n2;
let Q, S, Z;
for (Q = P - _1n2, S = 0; Q % _2n2 === _0n2; Q /= _2n2, S++)
;
for (Z = _2n2; Z < P && pow(Z, legendreC, P) !== P - _1n2; Z++)
;
if (S === 1) {
const p1div4 = (P + _1n2) / _4n;
return function tonelliFast(Fp2, n) {
const root = Fp2.pow(n, p1div4);
if (!Fp2.eql(Fp2.sqr(root), n))
throw new Error("Cannot find square root");
return root;
};
}
const Q1div2 = (Q + _1n2) / _2n2;
return function tonelliSlow(Fp2, n) {
if (Fp2.pow(n, legendreC) === Fp2.neg(Fp2.ONE))
throw new Error("Cannot find square root");
let r = S;
let g = Fp2.pow(Fp2.mul(Fp2.ONE, Z), Q);
let x = Fp2.pow(n, Q1div2);
let b = Fp2.pow(n, Q);
while (!Fp2.eql(b, Fp2.ONE)) {
if (Fp2.eql(b, Fp2.ZERO))
return Fp2.ZERO;
let m = 1;
for (let t2 = Fp2.sqr(b); m < r; m++) {
if (Fp2.eql(t2, Fp2.ONE))
break;
t2 = Fp2.sqr(t2);
}
const ge = Fp2.pow(g, _1n2 << BigInt(r - m - 1));
g = Fp2.sqr(ge);
x = Fp2.mul(x, ge);
b = Fp2.mul(b, g);
r = m;
}
return x;
};
}
function FpSqrt(P) {
if (P % _4n === _3n) {
const p1div4 = (P + _1n2) / _4n;
return function sqrt3mod4(Fp2, n) {
const root = Fp2.pow(n, p1div4);
if (!Fp2.eql(Fp2.sqr(root), n))
throw new Error("Cannot find square root");
return root;
};
}
if (P % _8n === _5n) {
const c1 = (P - _5n) / _8n;
return function sqrt5mod8(Fp2, n) {
const n2 = Fp2.mul(n, _2n2);
const v = Fp2.pow(n2, c1);
const nv = Fp2.mul(n, v);
const i = Fp2.mul(Fp2.mul(nv, _2n2), v);
const root = Fp2.mul(nv, Fp2.sub(i, Fp2.ONE));
if (!Fp2.eql(Fp2.sqr(root), n))
throw new Error("Cannot find square root");
return root;
};
}
if (P % _16n === _9n) {
}
return tonelliShanks(P);
}
var isNegativeLE = (num, modulo) => (mod(num, modulo) & _1n2) === _1n2;
function FpPow(f, num, power) {
if (power < _0n2)
throw new Error("Expected power > 0");
if (power === _0n2)
return f.ONE;
if (power === _1n2)
return num;
let p = f.ONE;
let d = num;
while (power > _0n2) {
if (power & _1n2)
p = f.mul(p, d);
d = f.sqr(d);
power >>= _1n2;
}
return p;
}
function FpInvertBatch(f, nums) {
const tmp = new Array(nums.length);
const lastMultiplied = nums.reduce((acc, num, i) => {
if (f.is0(num))
return acc;
tmp[i] = acc;
return f.mul(acc, num);
}, f.ONE);
const inverted = f.inv(lastMultiplied);
nums.reduceRight((acc, num, i) => {
if (f.is0(num))
return acc;
tmp[i] = f.mul(acc, tmp[i]);
return f.mul(acc, num);
}, inverted);
return tmp;
}
function nLength(n, nBitLength) {
const _nBitLength = nBitLength !== void 0 ? nBitLength : n.toString(2).length;
const nByteLength = Math.ceil(_nBitLength / 8);
return { nBitLength: _nBitLength, nByteLength };
}
function Field(ORDER, bitLen, isLE2 = false, redef = {}) {
if (ORDER <= _0n2)
throw new Error(`Expected Field ORDER > 0, got ${ORDER}`);
const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, bitLen);
if (BYTES > 2048)
throw new Error("Field lengths over 2048 bytes are not supported");
const sqrtP = FpSqrt(ORDER);
const f = Object.freeze({
ORDER,
BITS,
BYTES,
MASK: bitMask(BITS),
ZERO: _0n2,
ONE: _1n2,
create: (num) => mod(num, ORDER),
isValid: (num) => {
if (typeof num !== "bigint")
throw new Error(`Invalid field element: expected bigint, got ${typeof num}`);
return _0n2 <= num && num < ORDER;
},
is0: (num) => num === _0n2,
isOdd: (num) => (num & _1n2) === _1n2,
neg: (num) => mod(-num, ORDER),
eql: (lhs, rhs) => lhs === rhs,
sqr: (num) => mod(num * num, ORDER),
add: (lhs, rhs) => mod(lhs + rhs, ORDER),
sub: (lhs, rhs) => mod(lhs - rhs, ORDER),
mul: (lhs, rhs) => mod(lhs * rhs, ORDER),
pow: (num, power) => FpPow(f, num, power),
div: (lhs, rhs) => mod(lhs * invert(rhs, ORDER), ORDER),
// Same as above, but doesn't normalize
sqrN: (num) => num * num,
addN: (lhs, rhs) => lhs + rhs,
subN: (lhs, rhs) => lhs - rhs,
mulN: (lhs, rhs) => lhs * rhs,
inv: (num) => invert(num, ORDER),
sqrt: redef.sqrt || ((n) => sqrtP(f, n)),
invertBatch: (lst) => FpInvertBatch(f, lst),
// TODO: do we really need constant cmov?
// We don't have const-time bigints anyway, so probably will be not very useful
cmov: (a, b, c) => c ? b : a,
toBytes: (num) => isLE2 ? numberToBytesLE(num, BYTES) : numberToBytesBE(num, BYTES),
fromBytes: (bytes2) => {
if (bytes2.length !== BYTES)
throw new Error(`Fp.fromBytes: expected ${BYTES}, got ${bytes2.length}`);
return isLE2 ? bytesToNumberLE(bytes2) : bytesToNumberBE(bytes2);
}
});
return Object.freeze(f);
}
// node_modules/@noble/curves/esm/abstract/montgomery.js
var _0n3 = BigInt(0);
var _1n3 = BigInt(1);
function validateOpts(curve) {
validateObject(curve, {
a: "bigint"
}, {
montgomeryBits: "isSafeInteger",
nByteLength: "isSafeInteger",
adjustScalarBytes: "function",
domain: "function",
powPminus2: "function",
Gu: "bigint"
});
return Object.freeze({ ...curve });
}
function montgomery(curveDef) {
const CURVE = validateOpts(curveDef);
const { P } = CURVE;
const modP = (n) => mod(n, P);
const montgomeryBits = CURVE.montgomeryBits;
const montgomeryBytes = Math.ceil(montgomeryBits / 8);
const fieldLen = CURVE.nByteLength;
const adjustScalarBytes2 = CURVE.adjustScalarBytes || ((bytes2) => bytes2);
const powPminus2 = CURVE.powPminus2 || ((x) => pow(x, P - BigInt(2), P));
function cswap(swap, x_2, x_3) {
const dummy = modP(swap * (x_2 - x_3));
x_2 = modP(x_2 - dummy);
x_3 = modP(x_3 + dummy);
return [x_2, x_3];
}
const a24 = (CURVE.a - BigInt(2)) / BigInt(4);
function montgomeryLadder(u, scalar) {
aInRange("u", u, _0n3, P);
aInRange("scalar", scalar, _0n3, P);
const k = scalar;
const x_1 = u;
let x_2 = _1n3;
let z_2 = _0n3;
let x_3 = u;
let z_3 = _1n3;
let swap = _0n3;
let sw;
for (let t = BigInt(montgomeryBits - 1); t >= _0n3; t--) {
const k_t = k >> t & _1n3;
swap ^= k_t;
sw = cswap(swap, x_2, x_3);
x_2 = sw[0];
x_3 = sw[1];
sw = cswap(swap, z_2, z_3);
z_2 = sw[0];
z_3 = sw[1];
swap = k_t;
const A = x_2 + z_2;
const AA = modP(A * A);
const B = x_2 - z_2;
const BB = modP(B * B);
const E = AA - BB;
const C = x_3 + z_3;
const D = x_3 - z_3;
const DA = modP(D * A);
const CB = modP(C * B);
const dacb = DA + CB;
const da_cb = DA - CB;
x_3 = modP(dacb * dacb);
z_3 = modP(x_1 * modP(da_cb * da_cb));
x_2 = modP(AA * BB);
z_2 = modP(E * (AA + modP(a24 * E)));
}
sw = cswap(swap, x_2, x_3);
x_2 = sw[0];
x_3 = sw[1];
sw = cswap(swap, z_2, z_3);
z_2 = sw[0];
z_3 = sw[1];
const z2 = powPminus2(z_2);
return modP(x_2 * z2);
}
function encodeUCoordinate(u) {
return numberToBytesLE(modP(u), montgomeryBytes);
}
function decodeUCoordinate(uEnc) {
const u = ensureBytes("u coordinate", uEnc, montgomeryBytes);
if (fieldLen === 32)
u[31] &= 127;
return bytesToNumberLE(u);
}
function decodeScalar(n) {
const bytes2 = ensureBytes("scalar", n);
const len = bytes2.length;
if (len !== montgomeryBytes && len !== fieldLen)
throw new Error(`Expected ${montgomeryBytes} or ${fieldLen} bytes, got ${len}`);
return bytesToNumberLE(adjustScalarBytes2(bytes2));
}
function scalarMult(scalar, u) {
const pointU = decodeUCoordinate(u);
const _scalar = decodeScalar(scalar);
const pu = montgomeryLadder(pointU, _scalar);
if (pu === _0n3)
throw new Error("Invalid private or public key received");
return encodeUCoordinate(pu);
}
const GuBytes = encodeUCoordinate(CURVE.Gu);
function scalarMultBase(scalar) {
return scalarMult(scalar, GuBytes);
}
return {
scalarMult,
scalarMultBase,
getSharedSecret: (privateKey, publicKey) => scalarMult(privateKey, publicKey),
getPublicKey: (privateKey) => scalarMultBase(privateKey),
utils: { randomPrivateKey: () => CURVE.randomBytes(CURVE.nByteLength) },
GuBytes
};
}
// node_modules/@noble/curves/esm/ed25519.js
var ED25519_P = BigInt("57896044618658097711785492504343953926634992332820282019728792003956564819949");
var ED25519_SQRT_M1 = /* @__PURE__ */ BigInt("19681161376707505956807079304988542015446066515923890162744021073123829784752");
var _0n4 = BigInt(0);
var _1n4 = BigInt(1);
var _2n3 = BigInt(2);
var _3n2 = BigInt(3);
var _5n2 = BigInt(5);
var _8n2 = BigInt(8);
function ed25519_pow_2_252_3(x) {
const _10n = BigInt(10), _20n = BigInt(20), _40n = BigInt(40), _80n = BigInt(80);
const P = ED25519_P;
const x2 = x * x % P;
const b2 = x2 * x % P;
const b4 = pow2(b2, _2n3, P) * b2 % P;
const b5 = pow2(b4, _1n4, P) * x % P;
const b10 = pow2(b5, _5n2, P) * b5 % P;
const b20 = pow2(b10, _10n, P) * b10 % P;
const b40 = pow2(b20, _20n, P) * b20 % P;
const b80 = pow2(b40, _40n, P) * b40 % P;
const b160 = pow2(b80, _80n, P) * b80 % P;
const b240 = pow2(b160, _80n, P) * b80 % P;
const b250 = pow2(b240, _10n, P) * b10 % P;
const pow_p_5_8 = pow2(b250, _2n3, P) * x % P;
return { pow_p_5_8, b2 };
}
function adjustScalarBytes(bytes2) {
bytes2[0] &= 248;
bytes2[31] &= 127;
bytes2[31] |= 64;
return bytes2;
}
function uvRatio(u, v) {
const P = ED25519_P;
const v3 = mod(v * v * v, P);
const v7 = mod(v3 * v3 * v, P);
const pow3 = ed25519_pow_2_252_3(u * v7).pow_p_5_8;
let x = mod(u * v3 * pow3, P);
const vx2 = mod(v * x * x, P);
const root1 = x;
const root2 = mod(x * ED25519_SQRT_M1, P);
const useRoot1 = vx2 === u;
const useRoot2 = vx2 === mod(-u, P);
const noRoot = vx2 === mod(-u * ED25519_SQRT_M1, P);
if (useRoot1)
x = root1;
if (useRoot2 || noRoot)
x = root2;
if (isNegativeLE(x, P))
x = mod(-x, P);
return { isValid: useRoot1 || useRoot2, value: x };
}
var Fp = /* @__PURE__ */ (() => Field(ED25519_P, void 0, true))();
var ed25519Defaults = /* @__PURE__ */ (() => ({
// Param: a
a: BigInt(-1),
// Fp.create(-1) is proper; our way still works and is faster
// d is equal to -121665/121666 over finite field.
// Negative number is P - number, and division is invert(number, P)
d: BigInt("37095705934669439343138083508754565189542113879843219016388785533085940283555"),
// Finite field 𝔽p over which we'll do calculations; 2n**255n - 19n
Fp,
// Subgroup order: how many points curve has
// 2n**252n + 27742317777372353535851937790883648493n;
n: BigInt("7237005577332262213973186563042994240857116359379907606001950938285454250989"),
// Cofactor
h: _8n2,
// Base point (x, y) aka generator point
Gx: BigInt("15112221349535400772501151409588531511454012693041857206046113283949847762202"),
Gy: BigInt("46316835694926478169428394003475163141307993866256225615783033603165251855960"),
hash: sha512,
randomBytes,
adjustScalarBytes,
// dom2
// Ratio of u to v. Allows us to combine inversion and square root. Uses algo from RFC8032 5.1.3.
// Constant-time, u/√v
uvRatio
}))();
var x25519 = /* @__PURE__ */ (() => montgomery({
P: ED25519_P,
a: BigInt(486662),
montgomeryBits: 255,
// n is 253 bits
nByteLength: 32,
Gu: BigInt(9),
powPminus2: (x) => {
const P = ED25519_P;
const { pow_p_5_8, b2 } = ed25519_pow_2_252_3(x);
return mod(pow2(pow_p_5_8, _3n2, P) * b2, P);
},
adjustScalarBytes,
randomBytes
}))();
function edwardsToMontgomeryPriv(edwardsPriv) {
const hashed = ed25519Defaults.hash(edwardsPriv.subarray(0, 32));
return ed25519Defaults.adjustScalarBytes(hashed).subarray(0, 32);
}
export {
edwardsToMontgomeryPriv,
x25519
};
/*! Bundled license information:
@noble/hashes/esm/utils.js:
(*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
@noble/curves/esm/abstract/utils.js:
@noble/curves/esm/abstract/modular.js:
@noble/curves/esm/abstract/montgomery.js:
@noble/curves/esm/ed25519.js:
(*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
*/
@@ -0,0 +1,3 @@
import { edwardsToMontgomeryPriv, x25519 } from '../../../node_modules/@noble/curves/esm/ed25519.js';
export { edwardsToMontgomeryPriv, x25519 };
@@ -0,0 +1,101 @@
const DEFAULT_TIMEOUT_MS = 12000;
const runtimeTimers = globalThis;
function buildWsUrl(raw) {
const value = String(raw || '').trim();
if (!value) return 'wss://shineup.me/ws';
if (value.startsWith('ws://') || value.startsWith('wss://')) return value;
if (value.startsWith('http://') || value.startsWith('https://')) {
const parsed = new URL(value);
parsed.protocol = parsed.protocol === 'https:' ? 'wss:' : 'ws:';
if (!parsed.pathname || parsed.pathname === '/') parsed.pathname = '/ws';
return parsed.toString();
}
return value;
}
function createRequestId(op) {
return `${op}-${Date.now()}-${Math.random().toString(16).slice(2)}`;
}
export class WsJsonClient {
constructor(url) {
this.url = buildWsUrl(url);
this.ws = null;
this.openPromise = null;
this.pending = new Map();
}
async open() {
if (this.ws && this.ws.readyState === WebSocket.OPEN) return;
if (this.openPromise) return this.openPromise;
this.openPromise = new Promise((resolve, reject) => {
const ws = new WebSocket(this.url);
this.ws = ws;
ws.addEventListener('open', () => resolve(), { once: true });
ws.addEventListener('error', () => reject(new Error(`Не удалось подключиться к ${this.url}`)), { once: true });
ws.addEventListener('close', () => this.failPending('WebSocket соединение закрыто'));
ws.addEventListener('message', (event) => this.handleMessage(event.data));
}).finally(() => {
this.openPromise = null;
});
return this.openPromise;
}
async request(op, payload = {}, timeoutMs = DEFAULT_TIMEOUT_MS) {
await this.open();
const requestId = createRequestId(op);
const body = { op, requestId, payload };
const response = new Promise((resolve, reject) => {
const timer = runtimeTimers.setTimeout(() => {
this.pending.delete(requestId);
reject(new Error(`Таймаут ответа для операции ${op}`));
}, timeoutMs);
this.pending.set(requestId, {
resolve: (value) => {
runtimeTimers.clearTimeout(timer);
resolve(value);
},
reject: (error) => {
runtimeTimers.clearTimeout(timer);
reject(error);
},
});
});
this.ws.send(JSON.stringify(body));
return response;
}
handleMessage(raw) {
let data;
try {
data = JSON.parse(raw);
} catch {
return;
}
const requestId = data?.requestId;
if (!requestId) return;
const slot = this.pending.get(requestId);
if (!slot) return;
this.pending.delete(requestId);
slot.resolve(data);
}
failPending(message) {
const error = new Error(message);
for (const slot of this.pending.values()) slot.reject(error);
this.pending.clear();
}
close() {
if (this.ws) {
this.ws.close();
this.ws = null;
}
}
}