diff --git a/e2e/fixtures/auth.ts b/e2e/fixtures/auth.ts index b11f9948..2d14cbab 100644 --- a/e2e/fixtures/auth.ts +++ b/e2e/fixtures/auth.ts @@ -1,5 +1,5 @@ import fs from 'node:fs' -import { ed25519 } from '@noble/curves/ed25519' +import { ed25519 } from '@noble/curves/ed25519.js' const BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' diff --git a/package.json b/package.json index cf4c7190..17d338d2 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ }, "dependencies": { "@anthropic-ai/claude-agent-sdk": "^0.3.185", - "@noble/curves": "^1.8.2", + "@noble/curves": "^2.4.0", "@noble/hashes": "^2.2.0", "@sip-protocol/sdk": "^0.11.0", "@sip-protocol/types": "^0.2.2", diff --git a/packages/agent/src/routes/auth.ts b/packages/agent/src/routes/auth.ts index 247ef3f5..33693c02 100644 --- a/packages/agent/src/routes/auth.ts +++ b/packages/agent/src/routes/auth.ts @@ -1,7 +1,7 @@ import { Router, type Request, type Response, type NextFunction } from 'express' import jwt from 'jsonwebtoken' import crypto from 'node:crypto' -import { ed25519 } from '@noble/curves/ed25519' +import { ed25519 } from '@noble/curves/ed25519.js' import { createStore } from '../state/ephemeral.js' // ───────────────────────────────────────────────────────────────────────────── diff --git a/packages/agent/src/sentinel/scanner.ts b/packages/agent/src/sentinel/scanner.ts index 3d0e88e3..35d79e66 100644 --- a/packages/agent/src/sentinel/scanner.ts +++ b/packages/agent/src/sentinel/scanner.ts @@ -6,7 +6,7 @@ import { WSOL_MINT, } from '@sipher/sdk' import type { ScanParams } from '@sipher/sdk' -import { ed25519 } from '@noble/curves/ed25519' +import { ed25519 } from '@noble/curves/ed25519.js' import { type Detection, detectUnclaimedPayment, detectBalanceChange } from './detector.js' import { getSentinelConfig } from './config.js' import { loadNetworkConfig } from '../config/network.js' diff --git a/packages/agent/src/tools/claim-helpers.ts b/packages/agent/src/tools/claim-helpers.ts index 753c3e9a..673450b7 100644 --- a/packages/agent/src/tools/claim-helpers.ts +++ b/packages/agent/src/tools/claim-helpers.ts @@ -1,5 +1,5 @@ import { Buffer } from 'node:buffer' -import { ed25519 } from '@noble/curves/ed25519' +import { ed25519 } from '@noble/curves/ed25519.js' import { WSOL_MINT, USDC_MINT, diff --git a/packages/agent/src/tools/consolidate.ts b/packages/agent/src/tools/consolidate.ts index b74adf4c..17a55b9b 100644 --- a/packages/agent/src/tools/consolidate.ts +++ b/packages/agent/src/tools/consolidate.ts @@ -1,7 +1,7 @@ import type { AnthropicTool } from '../pi/tool-adapter.js' import { createScheduledOp, getOrCreateSession } from '../db.js' import { createConnection, scanForPayments } from '@sipher/sdk' -import { ed25519 } from '@noble/curves/ed25519' +import { ed25519 } from '@noble/curves/ed25519.js' import { loadNetworkConfig } from '../config/network.js' // ───────────────────────────────────────────────────────────────────────────── diff --git a/packages/agent/src/tools/scan.ts b/packages/agent/src/tools/scan.ts index 085820bd..bf9cf320 100644 --- a/packages/agent/src/tools/scan.ts +++ b/packages/agent/src/tools/scan.ts @@ -4,7 +4,7 @@ import { scanForPayments, fromBaseUnits, } from '@sipher/sdk' -import { ed25519 } from '@noble/curves/ed25519' +import { ed25519 } from '@noble/curves/ed25519.js' import { loadNetworkConfig } from '../config/network.js' // ───────────────────────────────────────────────────────────────────────────── diff --git a/packages/agent/tests/routes/auth.test.ts b/packages/agent/tests/routes/auth.test.ts index 6c5f30e0..38c93aac 100644 --- a/packages/agent/tests/routes/auth.test.ts +++ b/packages/agent/tests/routes/auth.test.ts @@ -2,7 +2,7 @@ import { describe, it, expect, beforeEach, afterEach } from 'vitest' import express from 'express' import supertest from 'supertest' import jwt from 'jsonwebtoken' -import { ed25519 } from '@noble/curves/ed25519' +import { ed25519 } from '@noble/curves/ed25519.js' const JWT_SECRET = 'test-jwt-secret-at-least-16-chars' @@ -30,7 +30,7 @@ function encodeBase58(bytes: Uint8Array): string { * Returns { privateKey, publicKey, wallet } where wallet is the base58 address. */ function generateTestWallet() { - const privateKey = ed25519.utils.randomPrivateKey() + const privateKey = ed25519.utils.randomSecretKey() const publicKey = ed25519.getPublicKey(privateKey) return { privateKey, publicKey, wallet: encodeBase58(publicKey) } } diff --git a/packages/sdk/src/privacy.ts b/packages/sdk/src/privacy.ts index 373aac93..77e3b5a5 100644 --- a/packages/sdk/src/privacy.ts +++ b/packages/sdk/src/privacy.ts @@ -8,7 +8,7 @@ import { import { TOKEN_PROGRAM_ID } from '@solana/spl-token' import { checkEd25519StealthAddress } from '@sip-protocol/sdk' import type { StealthAddress } from '@sip-protocol/sdk' -import { ed25519 } from '@noble/curves/ed25519' +import { ed25519 } from '@noble/curves/ed25519.js' import { sha256 as sha256Hash, sha512 } from '@noble/hashes/sha2.js' import { SIPHER_VAULT_PROGRAM_ID, @@ -350,9 +350,9 @@ export async function scanForPayments( // Compute viewTag: sha256(viewingScalar * ephemeralPub)[0] // This matches what checkEd25519StealthAddress does internally. - const ephPoint = ed25519.ExtendedPoint.fromHex(ephRaw) + const ephPoint = ed25519.Point.fromBytes(ephRaw) const sharedSecretPoint = ephPoint.multiply(viewingScalar) - const sharedSecretHash = sha256Hash(sharedSecretPoint.toRawBytes()) + const sharedSecretHash = sha256Hash(sharedSecretPoint.toBytes()) const viewTag = sharedSecretHash[0] const stealthAddr: StealthAddress = { diff --git a/packages/sdk/tests/privacy.test.ts b/packages/sdk/tests/privacy.test.ts index de94bb12..b5baa678 100644 --- a/packages/sdk/tests/privacy.test.ts +++ b/packages/sdk/tests/privacy.test.ts @@ -8,7 +8,7 @@ import { } from '@sip-protocol/sdk' import { sha256 } from '@noble/hashes/sha2.js' import { sha512 } from '@noble/hashes/sha2.js' -import { ed25519 } from '@noble/curves/ed25519' +import { ed25519 } from '@noble/curves/ed25519.js' import { PublicKey, type Connection } from '@solana/web3.js' import { scanForPayments, buildPrivateSendTx } from '../src/privacy.js' import { deriveVaultConfigPDA } from '../src/vault.js' @@ -411,9 +411,9 @@ describe('Scan matching simulation', () => { // On-chain events don't store the viewTag, so the scanner derives it // (canonical EIP-5564: the ECDH shared secret is computed on the viewing key). const viewingScalar = deriveEd25519Scalar(hexToBytes(meta.viewingPrivateKey)) - const ephPoint = ed25519.ExtendedPoint.fromHex(stripped) + const ephPoint = ed25519.Point.fromBytes(stripped) const sharedPoint = ephPoint.multiply(viewingScalar) - const sharedHash = sha256(sharedPoint.toRawBytes()) + const sharedHash = sha256(sharedPoint.toBytes()) const viewTag = sharedHash[0] const reconstructed = { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2ee011e3..5e84515d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,8 +17,8 @@ importers: specifier: ^0.3.185 version: 0.3.191(@anthropic-ai/sdk@0.91.1(zod@4.4.3))(@modelcontextprotocol/sdk@1.29.0(@cfworker/json-schema@4.1.1)(zod@4.4.3))(zod@4.4.3) '@noble/curves': - specifier: ^1.8.2 - version: 1.9.7 + specifier: ^2.4.0 + version: 2.4.0 '@noble/hashes': specifier: ^2.2.0 version: 2.2.0 @@ -194,7 +194,7 @@ importers: version: 6.0.3(vite@8.1.0(@types/node@26.6.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0)) jsdom: specifier: ^29.1.1 - version: 29.1.1(@noble/hashes@2.2.0) + version: 29.1.1(@noble/hashes@2.4.0) typescript: specifier: ^5.7.0 version: 5.9.3 @@ -203,7 +203,7 @@ importers: version: 8.1.0(@types/node@26.6.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0) vitest: specifier: ^4.1.9 - version: 4.1.9(@types/node@26.6.2)(jsdom@29.1.1(@noble/hashes@2.2.0))(vite@8.1.0(@types/node@26.6.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0)) + version: 4.1.9(@types/node@26.6.2)(jsdom@29.1.1(@noble/hashes@2.4.0))(vite@8.1.0(@types/node@26.6.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0)) examples/vault-privacy-provider: dependencies: @@ -307,7 +307,7 @@ importers: version: 5.9.3 vitest: specifier: ^4.1.9 - version: 4.1.9(@types/node@26.6.2)(jsdom@29.1.1(@noble/hashes@2.2.0))(vite@8.1.0(@types/node@26.6.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0)) + version: 4.1.9(@types/node@26.6.2)(jsdom@29.1.1(@noble/hashes@2.4.0))(vite@8.1.0(@types/node@26.6.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0)) packages/sdk: dependencies: @@ -329,7 +329,7 @@ importers: version: 5.9.3 vitest: specifier: ^4.1.9 - version: 4.1.9(@types/node@26.6.2)(jsdom@29.1.1(@noble/hashes@2.2.0))(vite@8.1.0(@types/node@26.6.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0)) + version: 4.1.9(@types/node@26.6.2)(jsdom@29.1.1(@noble/hashes@2.4.0))(vite@8.1.0(@types/node@26.6.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0)) packages: @@ -1456,6 +1456,10 @@ packages: resolution: {integrity: sha512-T/BoHgFXirb0ENSPBquzX0rcjXeM6Lo892a2jlYJkqk83LqZx0l1Of7DzlKJ6jkpvMrkHSnAcgb5JegL8SeIkQ==} engines: {node: '>= 20.19.0'} + '@noble/curves@2.4.0': + resolution: {integrity: sha512-P4/62zrgfH33CneE3Dn4WhJVA22YUU0eR51wKIan4NVRvwsA0YnPTwWGpNbpuacSujmSFLvyzpyuR30+fbq2Ew==} + engines: {node: '>= 20.19.0'} + '@noble/hashes@1.4.0': resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} engines: {node: '>= 16'} @@ -1480,6 +1484,10 @@ packages: resolution: {integrity: sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg==} engines: {node: '>= 20.19.0'} + '@noble/hashes@2.4.0': + resolution: {integrity: sha512-X5XaVWZIBCT7HHZGm5I7ZQXDwLG+bGXuSrMQAW+7Zvl87h1kmc1ZB1VSRJcpUfoUrGQp4Fkoxm5kZ+Ms+aW+eA==} + engines: {node: '>= 20.19.0'} + '@noir-lang/acvm_js@1.0.0-beta.18': resolution: {integrity: sha512-QQXAaowxSzGKk+Ua7ofc2jcpvUTYSxmDuF5SzwwOFMue9+ccp9QcqOkjyyIZWjtapcenV7YCXrzcBjvEt7N8Nw==} @@ -8556,13 +8564,13 @@ snapshots: '@ethereumjs/common': 10.1.1 '@ethereumjs/rlp': 10.1.2 '@ethereumjs/util': 10.1.1 - '@noble/curves': 2.2.0 + '@noble/curves': 2.4.0 '@noble/hashes': 2.2.0 '@ethereumjs/util@10.1.1': dependencies: '@ethereumjs/rlp': 10.1.2 - '@noble/curves': 2.2.0 + '@noble/curves': 2.4.0 '@noble/hashes': 2.2.0 '@ethereumjs/util@9.1.0': @@ -8573,6 +8581,11 @@ snapshots: '@exodus/bytes@1.15.1(@noble/hashes@2.2.0)': optionalDependencies: '@noble/hashes': 2.2.0 + optional: true + + '@exodus/bytes@1.15.1(@noble/hashes@2.4.0)': + optionalDependencies: + '@noble/hashes': 2.4.0 '@fivebinaries/coin-selection@3.0.0': dependencies: @@ -9089,6 +9102,10 @@ snapshots: dependencies: '@noble/hashes': 2.2.0 + '@noble/curves@2.4.0': + dependencies: + '@noble/hashes': 2.4.0 + '@noble/hashes@1.4.0': {} '@noble/hashes@1.7.0': {} @@ -9101,6 +9118,8 @@ snapshots: '@noble/hashes@2.2.0': {} + '@noble/hashes@2.4.0': {} + '@noir-lang/acvm_js@1.0.0-beta.18': {} '@noir-lang/noir_js@1.0.0-beta.18': @@ -11961,7 +11980,7 @@ snapshots: '@trezor/device-authenticity@1.1.2(tslib@2.8.1)': dependencies: - '@noble/curves': 2.2.0 + '@noble/curves': 2.4.0 '@trezor/crypto-utils': 1.2.0(tslib@2.8.1) '@trezor/protobuf': 1.5.2(tslib@2.8.1) '@trezor/schema-utils': 1.4.0(tslib@2.8.1) @@ -13838,6 +13857,14 @@ snapshots: whatwg-url: 16.0.1(@noble/hashes@2.2.0) transitivePeerDependencies: - '@noble/hashes' + optional: true + + data-urls@7.0.0(@noble/hashes@2.4.0): + dependencies: + whatwg-mimetype: 5.0.0 + whatwg-url: 16.0.1(@noble/hashes@2.4.0) + transitivePeerDependencies: + - '@noble/hashes' dateformat@4.6.3: {} @@ -14594,6 +14621,13 @@ snapshots: '@exodus/bytes': 1.15.1(@noble/hashes@2.2.0) transitivePeerDependencies: - '@noble/hashes' + optional: true + + html-encoding-sniffer@6.0.0(@noble/hashes@2.4.0): + dependencies: + '@exodus/bytes': 1.15.1(@noble/hashes@2.4.0) + transitivePeerDependencies: + - '@noble/hashes' http-errors@2.0.1: dependencies: @@ -14930,6 +14964,33 @@ snapshots: xml-name-validator: 5.0.0 transitivePeerDependencies: - '@noble/hashes' + optional: true + + jsdom@29.1.1(@noble/hashes@2.4.0): + dependencies: + '@asamuzakjp/css-color': 5.1.11 + '@asamuzakjp/dom-selector': 7.1.1 + '@bramus/specificity': 2.4.2 + '@csstools/css-syntax-patches-for-csstree': 1.1.5(css-tree@3.2.1) + '@exodus/bytes': 1.15.1(@noble/hashes@2.4.0) + css-tree: 3.2.1 + data-urls: 7.0.0(@noble/hashes@2.4.0) + decimal.js: 10.6.0 + html-encoding-sniffer: 6.0.0(@noble/hashes@2.4.0) + is-potential-custom-element-name: 1.0.1 + lru-cache: 11.5.1 + parse5: 8.0.1 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 6.0.1 + undici: 7.28.0 + w3c-xmlserializer: 5.0.0 + webidl-conversions: 8.0.1 + whatwg-mimetype: 5.0.0 + whatwg-url: 16.0.1(@noble/hashes@2.4.0) + xml-name-validator: 5.0.0 + transitivePeerDependencies: + - '@noble/hashes' jsesc@3.1.0: {} @@ -17259,6 +17320,34 @@ snapshots: transitivePeerDependencies: - msw + vitest@4.1.9(@types/node@26.6.2)(jsdom@29.1.1(@noble/hashes@2.4.0))(vite@8.1.0(@types/node@26.6.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0)): + dependencies: + '@vitest/expect': 4.1.9 + '@vitest/mocker': 4.1.9(vite@8.1.0(@types/node@26.6.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0)) + '@vitest/pretty-format': 4.1.9 + '@vitest/runner': 4.1.9 + '@vitest/snapshot': 4.1.9 + '@vitest/spy': 4.1.9 + '@vitest/utils': 4.1.9 + es-module-lexer: 2.1.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.3 + pathe: 2.0.3 + picomatch: 4.0.4 + std-env: 4.1.0 + tinybench: 2.9.0 + tinyexec: 1.2.4 + tinyglobby: 0.2.17 + tinyrainbow: 3.1.0 + vite: 8.1.0(@types/node@26.6.2)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 26.6.2 + jsdom: 29.1.1(@noble/hashes@2.4.0) + transitivePeerDependencies: + - msw + vlq@1.0.1: {} w3c-xmlserializer@5.0.0: @@ -17297,6 +17386,15 @@ snapshots: webidl-conversions: 8.0.1 transitivePeerDependencies: - '@noble/hashes' + optional: true + + whatwg-url@16.0.1(@noble/hashes@2.4.0): + dependencies: + '@exodus/bytes': 1.15.1(@noble/hashes@2.4.0) + tr46: 6.0.0 + webidl-conversions: 8.0.1 + transitivePeerDependencies: + - '@noble/hashes' whatwg-url@5.0.0: dependencies: diff --git a/src/routes/transfer.ts b/src/routes/transfer.ts index 19a607c8..a0d7a465 100644 --- a/src/routes/transfer.ts +++ b/src/routes/transfer.ts @@ -16,7 +16,7 @@ import { sha256 } from '@noble/hashes/sha2.js' import { bytesToHex, hexToBytes } from '@noble/hashes/utils.js' import { PublicKey, Keypair, Transaction } from '@solana/web3.js' import { getAssociatedTokenAddress, createTransferInstruction, getAccount } from '@solana/spl-token' -import { ed25519 } from '@noble/curves/ed25519' +import { ed25519 } from '@noble/curves/ed25519.js' const router = Router() @@ -191,7 +191,7 @@ router.post( let validScalar = scalarBigInt % ED25519_ORDER if (validScalar === 0n) validScalar = 1n - const derivedPubKeyBytes = ed25519.ExtendedPoint.BASE.multiply(validScalar).toRawBytes() + const derivedPubKeyBytes = ed25519.Point.BASE.multiply(validScalar).toBytes() if (!derivedPubKeyBytes.every((b, i) => b === expectedPubKeyBytes[i])) { throw new Error('Stealth key derivation failed: derived key does not match expected public key') }