diff --git a/packages/util-crypto/package.json b/packages/util-crypto/package.json index 79735a55e2..8d37c9a4d8 100644 --- a/packages/util-crypto/package.json +++ b/packages/util-crypto/package.json @@ -36,6 +36,7 @@ "@polkadot/x-bigint": "13.5.7", "@polkadot/x-randomvalues": "13.5.7", "@scure/base": "^1.1.7", + "@scure/sr25519": "^0.2.0", "tslib": "^2.8.0" }, "peerDependencies": { diff --git a/packages/util-crypto/src/sr25519/agreement.spec.ts b/packages/util-crypto/src/sr25519/agreement.spec.ts index 741cf46651..55433796e1 100644 --- a/packages/util-crypto/src/sr25519/agreement.spec.ts +++ b/packages/util-crypto/src/sr25519/agreement.spec.ts @@ -6,7 +6,6 @@ import type { Keypair } from '../types.js'; import { u8aToHex } from '@polkadot/util'; -import { waitReady } from '@polkadot/wasm-crypto'; import { sr25519Agreement, sr25519PairFromSeed } from './index.js'; @@ -14,9 +13,7 @@ describe('agreement', (): void => { let pairA: Keypair; let pairB: Keypair; - beforeEach(async (): Promise => { - await waitReady(); - + beforeEach((): void => { pairA = sr25519PairFromSeed('0x98b3d305d5a5eace562387e47e59badd4d77e3f72cabfb10a60f8a197059f0a8'); pairB = sr25519PairFromSeed('0x9732eea001851ff862d949a1699c9971f3a26edbede2ad7922cbbe9a0701f366'); }); diff --git a/packages/util-crypto/src/sr25519/agreement.ts b/packages/util-crypto/src/sr25519/agreement.ts index 0ab39ec3af..87cb050510 100644 --- a/packages/util-crypto/src/sr25519/agreement.ts +++ b/packages/util-crypto/src/sr25519/agreement.ts @@ -1,8 +1,9 @@ // Copyright 2017-2025 @polkadot/util-crypto authors & contributors // SPDX-License-Identifier: Apache-2.0 +import { getSharedSecret } from '@scure/sr25519'; + import { u8aToU8a } from '@polkadot/util'; -import { sr25519Agree } from '@polkadot/wasm-crypto'; /** * @name sr25519Agreement @@ -18,5 +19,5 @@ export function sr25519Agreement (secretKey: string | Uint8Array, publicKey: str throw new Error(`Invalid secretKey, received ${secretKeyU8a.length} bytes, expected 64`); } - return sr25519Agree(publicKeyU8a, secretKeyU8a); + return getSharedSecret(secretKeyU8a, publicKeyU8a); } diff --git a/packages/util-crypto/src/sr25519/derive.ts b/packages/util-crypto/src/sr25519/derive.ts index 0738b0e142..d4f0682932 100644 --- a/packages/util-crypto/src/sr25519/derive.ts +++ b/packages/util-crypto/src/sr25519/derive.ts @@ -3,10 +3,9 @@ import type { Keypair } from '../types.js'; -import { isU8a } from '@polkadot/util'; +import * as sr25519 from '@scure/sr25519'; -import { sr25519PairFromU8a } from './pair/fromU8a.js'; -import { sr25519KeypairToU8a } from './pair/toU8a.js'; +import { isU8a } from '@polkadot/util'; export function createDeriveFn (derive: (pair: Uint8Array, cc: Uint8Array) => Uint8Array): (keypair: Keypair, chainCode: Uint8Array) => Keypair { return (keypair: Keypair, chainCode: Uint8Array): Keypair => { @@ -14,8 +13,9 @@ export function createDeriveFn (derive: (pair: Uint8Array, cc: Uint8Array) => Ui throw new Error('Invalid chainCode passed to derive'); } - return sr25519PairFromU8a( - derive(sr25519KeypairToU8a(keypair), chainCode) - ); + const secretKey = derive(keypair.secretKey, chainCode); + const publicKey = sr25519.getPublicKey(secretKey); + + return { publicKey, secretKey }; }; } diff --git a/packages/util-crypto/src/sr25519/deriveHard.ts b/packages/util-crypto/src/sr25519/deriveHard.ts index 4a7717e564..17ac637d23 100644 --- a/packages/util-crypto/src/sr25519/deriveHard.ts +++ b/packages/util-crypto/src/sr25519/deriveHard.ts @@ -1,8 +1,9 @@ // Copyright 2017-2025 @polkadot/util-crypto authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { sr25519DeriveKeypairHard } from '@polkadot/wasm-crypto'; +import * as sr25519 from '@scure/sr25519'; import { createDeriveFn } from './derive.js'; -export const sr25519DeriveHard = /*#__PURE__*/ createDeriveFn(sr25519DeriveKeypairHard); +// eslint-disable-next-line @typescript-eslint/unbound-method +export const sr25519DeriveHard = /*#__PURE__*/ createDeriveFn(sr25519.HDKD.secretHard); diff --git a/packages/util-crypto/src/sr25519/derivePublic.ts b/packages/util-crypto/src/sr25519/derivePublic.ts index e0ce2c0f5b..1b2c9d8a9d 100644 --- a/packages/util-crypto/src/sr25519/derivePublic.ts +++ b/packages/util-crypto/src/sr25519/derivePublic.ts @@ -1,8 +1,9 @@ // Copyright 2017-2025 @polkadot/util-crypto authors & contributors // SPDX-License-Identifier: Apache-2.0 +import * as sr25519 from '@scure/sr25519'; + import { isU8a, u8aToU8a } from '@polkadot/util'; -import { sr25519DerivePublicSoft } from '@polkadot/wasm-crypto'; export function sr25519DerivePublic (publicKey: string | Uint8Array, chainCode: Uint8Array): Uint8Array { const publicKeyU8a = u8aToU8a(publicKey); @@ -13,5 +14,5 @@ export function sr25519DerivePublic (publicKey: string | Uint8Array, chainCode: throw new Error(`Invalid publicKey, received ${publicKeyU8a.length} bytes, expected 32`); } - return sr25519DerivePublicSoft(publicKeyU8a, chainCode); + return sr25519.HDKD.publicSoft(publicKeyU8a, chainCode); } diff --git a/packages/util-crypto/src/sr25519/deriveSoft.ts b/packages/util-crypto/src/sr25519/deriveSoft.ts index 0e689e79ee..6d40428513 100644 --- a/packages/util-crypto/src/sr25519/deriveSoft.ts +++ b/packages/util-crypto/src/sr25519/deriveSoft.ts @@ -1,8 +1,9 @@ // Copyright 2017-2025 @polkadot/util-crypto authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { sr25519DeriveKeypairSoft } from '@polkadot/wasm-crypto'; +import * as sr25519 from '@scure/sr25519'; import { createDeriveFn } from './derive.js'; -export const sr25519DeriveSoft = /*#__PURE__*/ createDeriveFn(sr25519DeriveKeypairSoft); +// eslint-disable-next-line @typescript-eslint/unbound-method +export const sr25519DeriveSoft = /*#__PURE__*/ createDeriveFn(sr25519.HDKD.secretSoft); diff --git a/packages/util-crypto/src/sr25519/pair/fromSeed.spec.ts b/packages/util-crypto/src/sr25519/pair/fromSeed.spec.ts index 63d602a139..8450a53277 100644 --- a/packages/util-crypto/src/sr25519/pair/fromSeed.spec.ts +++ b/packages/util-crypto/src/sr25519/pair/fromSeed.spec.ts @@ -4,7 +4,6 @@ /// import { stringToU8a, u8aToHex } from '@polkadot/util'; -import { waitReady } from '@polkadot/wasm-crypto'; import { mnemonicToMiniSecret } from '../../mnemonic/index.js'; import { sr25519PairFromSeed } from '../index.js'; @@ -17,10 +16,6 @@ describe('sr25519PairFromSeed', (): void => { secretKey: new Uint8Array([240, 16, 102, 96, 195, 221, 162, 63, 22, 218, 169, 172, 91, 129, 27, 150, 48, 119, 245, 188, 10, 248, 159, 133, 128, 79, 13, 232, 228, 36, 240, 80, 249, 141, 102, 243, 148, 66, 80, 111, 249, 71, 253, 145, 31, 24, 199, 167, 165, 218, 99, 154, 99, 232, 211, 180, 226, 51, 247, 65, 67, 217, 81, 193]) }; - beforeEach(async (): Promise => { - await waitReady(); - }); - it('generates a valid publicKey/secretKey pair (u8a)', (): void => { expect( sr25519PairFromSeed(TEST) diff --git a/packages/util-crypto/src/sr25519/pair/fromSeed.ts b/packages/util-crypto/src/sr25519/pair/fromSeed.ts index 854fb0c7b9..f232f7782f 100644 --- a/packages/util-crypto/src/sr25519/pair/fromSeed.ts +++ b/packages/util-crypto/src/sr25519/pair/fromSeed.ts @@ -3,10 +3,9 @@ import type { Keypair } from '../../types.js'; -import { u8aToU8a } from '@polkadot/util'; -import { sr25519KeypairFromSeed } from '@polkadot/wasm-crypto'; +import * as sr25519 from '@scure/sr25519'; -import { sr25519PairFromU8a } from './fromU8a.js'; +import { u8aToU8a } from '@polkadot/util'; /** * @name sr25519PairFromSeed @@ -19,7 +18,11 @@ export function sr25519PairFromSeed (seed: string | Uint8Array): Keypair { throw new Error(`Expected a seed matching 32 bytes, found ${seedU8a.length}`); } - return sr25519PairFromU8a( - sr25519KeypairFromSeed(seedU8a) - ); + const sec = sr25519.secretFromSeed(seedU8a); + const pub = sr25519.getPublicKey(sec); + + return { + publicKey: pub, + secretKey: sec + }; } diff --git a/packages/util-crypto/src/sr25519/sign.spec.ts b/packages/util-crypto/src/sr25519/sign.spec.ts index 452be470fe..6f6aaa5e5c 100644 --- a/packages/util-crypto/src/sr25519/sign.spec.ts +++ b/packages/util-crypto/src/sr25519/sign.spec.ts @@ -4,7 +4,6 @@ /// import { stringToU8a } from '@polkadot/util'; -import { waitReady } from '@polkadot/wasm-crypto'; import { randomAsU8a } from '../random/asU8a.js'; import { sr25519PairFromSeed } from './pair/fromSeed.js'; @@ -13,10 +12,6 @@ import { sr25519Sign } from './sign.js'; const MESSAGE = stringToU8a('this is a message'); describe('sign', (): void => { - beforeEach(async (): Promise => { - await waitReady(); - }); - it('has 64-byte signatures', (): void => { const pair = sr25519PairFromSeed(randomAsU8a()); diff --git a/packages/util-crypto/src/sr25519/sign.ts b/packages/util-crypto/src/sr25519/sign.ts index 0e314683a9..f5dee514ac 100644 --- a/packages/util-crypto/src/sr25519/sign.ts +++ b/packages/util-crypto/src/sr25519/sign.ts @@ -3,8 +3,9 @@ import type { Keypair } from '../types.js'; +import * as sr25519 from '@scure/sr25519'; + import { u8aToU8a } from '@polkadot/util'; -import { sr25519Sign as wasmSign } from '@polkadot/wasm-crypto'; /** * @name sr25519Sign @@ -17,5 +18,5 @@ export function sr25519Sign (message: string | Uint8Array, { publicKey, secretKe throw new Error('Expected a valid secretKey, 64-bytes'); } - return wasmSign(publicKey, secretKey, u8aToU8a(message)); + return sr25519.sign(secretKey, u8aToU8a(message)); } diff --git a/packages/util-crypto/src/sr25519/verify.spec.ts b/packages/util-crypto/src/sr25519/verify.spec.ts index 6487443422..c964d6d072 100644 --- a/packages/util-crypto/src/sr25519/verify.spec.ts +++ b/packages/util-crypto/src/sr25519/verify.spec.ts @@ -4,7 +4,6 @@ /// import { stringToU8a } from '@polkadot/util'; -import { waitReady } from '@polkadot/wasm-crypto'; import { randomAsU8a } from '../random/asU8a.js'; import { sr25519PairFromSeed } from './pair/fromSeed.js'; @@ -14,10 +13,6 @@ import { sr25519Verify } from './verify.js'; const MESSAGE = stringToU8a('this is a message'); describe('verify', (): void => { - beforeEach(async (): Promise => { - await waitReady(); - }); - it('can sign and verify a message', (): void => { const pair = sr25519PairFromSeed(randomAsU8a()); const signature = sr25519Sign(MESSAGE, pair); diff --git a/packages/util-crypto/src/sr25519/verify.ts b/packages/util-crypto/src/sr25519/verify.ts index e7b1b1e439..8af7c0d8eb 100644 --- a/packages/util-crypto/src/sr25519/verify.ts +++ b/packages/util-crypto/src/sr25519/verify.ts @@ -1,8 +1,9 @@ // Copyright 2017-2025 @polkadot/util-crypto authors & contributors // SPDX-License-Identifier: Apache-2.0 +import * as sr25519 from '@scure/sr25519'; + import { u8aToU8a } from '@polkadot/util'; -import { sr25519Verify as wasmVerify } from '@polkadot/wasm-crypto'; /** * @name sr25519Verify @@ -18,5 +19,5 @@ export function sr25519Verify (message: string | Uint8Array, signature: string | throw new Error(`Invalid signature, received ${signatureU8a.length} bytes, expected 64`); } - return wasmVerify(signatureU8a, u8aToU8a(message), publicKeyU8a); + return sr25519.verify(u8aToU8a(message), signatureU8a, publicKeyU8a); } diff --git a/packages/util-crypto/src/sr25519/vrfSign.ts b/packages/util-crypto/src/sr25519/vrfSign.ts index 1b665b62e0..ee68721a6b 100644 --- a/packages/util-crypto/src/sr25519/vrfSign.ts +++ b/packages/util-crypto/src/sr25519/vrfSign.ts @@ -3,8 +3,10 @@ import type { Keypair } from '../types.js'; +import { randomBytes } from '@noble/hashes/utils'; +import * as sr25519 from '@scure/sr25519'; + import { u8aToU8a } from '@polkadot/util'; -import { vrfSign } from '@polkadot/wasm-crypto'; const EMPTY_U8A = new Uint8Array(); @@ -17,5 +19,6 @@ export function sr25519VrfSign (message: string | Uint8Array, { secretKey }: Par throw new Error('Invalid secretKey, expected 64-bytes'); } - return vrfSign(secretKey, u8aToU8a(context), u8aToU8a(message), u8aToU8a(extra)); + return sr25519.vrf.sign(u8aToU8a(message), secretKey, u8aToU8a(context), u8aToU8a(extra), randomBytes); + // return vrfSign(secretKey, u8aToU8a(context), u8aToU8a(message), u8aToU8a(extra)); } diff --git a/packages/util-crypto/src/sr25519/vrfSignVerify.spec.ts b/packages/util-crypto/src/sr25519/vrfSignVerify.spec.ts index 67473cec58..df92bddadd 100644 --- a/packages/util-crypto/src/sr25519/vrfSignVerify.spec.ts +++ b/packages/util-crypto/src/sr25519/vrfSignVerify.spec.ts @@ -4,7 +4,6 @@ /// import { stringToU8a, u8aEq } from '@polkadot/util'; -import { waitReady } from '@polkadot/wasm-crypto'; import { randomAsU8a } from '../random/asU8a.js'; import { sr25519PairFromSeed } from './pair/fromSeed.js'; @@ -14,10 +13,6 @@ import { sr25519VrfVerify } from './vrfVerify.js'; const MESSAGE = stringToU8a('this is a message'); describe('vrf sign and verify', (): void => { - beforeEach(async (): Promise => { - await waitReady(); - }); - it('has 96-byte proofs', (): void => { const pair = sr25519PairFromSeed(randomAsU8a()); diff --git a/packages/util-crypto/src/sr25519/vrfVerify.ts b/packages/util-crypto/src/sr25519/vrfVerify.ts index d81d239fb1..5bd76501ff 100644 --- a/packages/util-crypto/src/sr25519/vrfVerify.ts +++ b/packages/util-crypto/src/sr25519/vrfVerify.ts @@ -1,8 +1,9 @@ // Copyright 2017-2025 @polkadot/util-crypto authors & contributors // SPDX-License-Identifier: Apache-2.0 +import * as sr25519 from '@scure/sr25519'; + import { u8aToU8a } from '@polkadot/util'; -import { vrfVerify } from '@polkadot/wasm-crypto'; const EMPTY_U8A = new Uint8Array(); @@ -20,5 +21,5 @@ export function sr25519VrfVerify (message: string | Uint8Array, signOutput: stri throw new Error('Invalid vrfSign output, expected 96 bytes'); } - return vrfVerify(publicKeyU8a, u8aToU8a(context), u8aToU8a(message), u8aToU8a(extra), proofU8a); + return sr25519.vrf.verify(u8aToU8a(message), proofU8a, publicKeyU8a, u8aToU8a(context), u8aToU8a(extra)); } diff --git a/yarn.lock b/yarn.lock index 678359dd7d..7e4d1b6cf4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1313,6 +1313,15 @@ __metadata: languageName: node linkType: hard +"@noble/curves@npm:~1.9.2": + version: 1.9.7 + resolution: "@noble/curves@npm:1.9.7" + dependencies: + "@noble/hashes": "npm:1.8.0" + checksum: 10/3cfe2735ea94972988ca9e217e0ebb2044372a7160b2079bf885da789492a6291fc8bf76ca3d8bf8dee477847ee2d6fac267d1e6c4f555054059f5e8c4865d44 + languageName: node + linkType: hard + "@noble/hashes@npm:1.3.3, @noble/hashes@npm:^1.3.3": version: 1.3.3 resolution: "@noble/hashes@npm:1.3.3" @@ -1320,6 +1329,13 @@ __metadata: languageName: node linkType: hard +"@noble/hashes@npm:1.8.0, @noble/hashes@npm:~1.8.0": + version: 1.8.0 + resolution: "@noble/hashes@npm:1.8.0" + checksum: 10/474b7f56bc6fb2d5b3a42132561e221b0ea4f91e590f4655312ca13667840896b34195e2b53b7f097ec080a1fdd3b58d902c2a8d0fbdf51d2e238b53808a177e + languageName: node + linkType: hard + "@nodelib/fs.scandir@npm:2.1.5": version: 2.1.5 resolution: "@nodelib/fs.scandir@npm:2.1.5" @@ -1638,6 +1654,7 @@ __metadata: "@polkadot/x-bigint": "npm:13.5.7" "@polkadot/x-randomvalues": "npm:13.5.7" "@scure/base": "npm:^1.1.7" + "@scure/sr25519": "npm:^0.2.0" tslib: "npm:^2.8.0" peerDependencies: "@polkadot/util": 13.5.7 @@ -2386,6 +2403,16 @@ __metadata: languageName: node linkType: hard +"@scure/sr25519@npm:^0.2.0": + version: 0.2.0 + resolution: "@scure/sr25519@npm:0.2.0" + dependencies: + "@noble/curves": "npm:~1.9.2" + "@noble/hashes": "npm:~1.8.0" + checksum: 10/3c47b474811642b43fd8c96f7846c9d88c9a06eefa7d6360b6421ebdfb6cf582e1e8fdce9ae4708b088a0e323cd6519c883c3a33a284c2fad592414b02f19049 + languageName: node + linkType: hard + "@sideway/address@npm:^4.1.4": version: 4.1.4 resolution: "@sideway/address@npm:4.1.4"