From 6ef1befb3afc304e5d2b75632fab712fe762df3a Mon Sep 17 00:00:00 2001 From: sebastijankuzner Date: Mon, 30 Mar 2026 18:31:22 +0000 Subject: [PATCH 01/22] Remove networks --- packages/crypto-wif/test/networks.json | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 packages/crypto-wif/test/networks.json diff --git a/packages/crypto-wif/test/networks.json b/packages/crypto-wif/test/networks.json deleted file mode 100644 index 0181a6571a..0000000000 --- a/packages/crypto-wif/test/networks.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "devnet": { - "pubKeyHash": 30, - "wif": 170 - } -} From d94e6f4cab0e9f51e64dd66705f4068b59f09df1 Mon Sep 17 00:00:00 2001 From: sebastijankuzner Date: Mon, 30 Mar 2026 18:38:02 +0000 Subject: [PATCH 02/22] Additional tests --- .../crypto-wif/source/wif.factory.test.ts | 25 ++++++++++++++++--- packages/crypto-wif/test/identity.json | 3 ++- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/packages/crypto-wif/source/wif.factory.test.ts b/packages/crypto-wif/source/wif.factory.test.ts index 794358e556..69616cfd2f 100644 --- a/packages/crypto-wif/source/wif.factory.test.ts +++ b/packages/crypto-wif/source/wif.factory.test.ts @@ -6,13 +6,14 @@ import { KeyPairFactory } from "@mainsail/crypto-key-pair-ecdsa/source/pair"; import { Application } from "@mainsail/kernel"; import { describe } from "@mainsail/test-runner"; -import { mnemonic, wif } from "../test/identity.json"; +import { mnemonic, wif, wif170 } from "../test/identity.json"; import { WIFFactory } from "./wif.factory"; import cryptoJson from "../../core/bin/config/devnet/core/crypto.json"; describe<{ app: Application; factory: WIFFactory; + configuration: Contracts.Crypto.Configuration; }>("Identities - WIFFactory", ({ it, assert, beforeEach }) => { beforeEach(async (context) => { context.app = new Application(); @@ -20,10 +21,9 @@ describe<{ await context.app.resolve(ValidationServiceProvider).register(); await context.app.resolve(CryptoConfigServiceProvider).register(); - context.app.get(Identifiers.Cryptography.Configuration).set("network.wif", 170); - context.app.bind(Identifiers.Cryptography.Identity.KeyPair.Factory).to(KeyPairFactory).inSingletonScope(); + context.configuration = context.app.get(Identifiers.Cryptography.Configuration); context.factory = context.app.resolve(WIFFactory); }); @@ -31,6 +31,15 @@ describe<{ assert.equal(await factory.fromMnemonic(mnemonic), wif); }); + it("#fromMnemonic - should be OK for WIF 170", async ({ factory, configuration }) => { + configuration.set("network.wif", 170); + assert.equal(await factory.fromMnemonic(mnemonic), wif170); + }); + + it("#fromMnemonic - should be OK", async ({ factory }) => { + assert.equal(await factory.fromMnemonic(mnemonic), wif); + }); + it("#fromKeys - should be OK", async ({ factory, app }) => { assert.equal( await factory.fromKeys( @@ -39,4 +48,14 @@ describe<{ wif, ); }); + + it("#fromKeys - should be OK for WIF 170", async ({ factory, app, configuration }) => { + configuration.set("network.wif", 170); + assert.equal( + await factory.fromKeys( + await app.get(Identifiers.Cryptography.Identity.KeyPair.Factory).fromMnemonic(mnemonic), + ), + wif170, + ); + }); }); diff --git a/packages/crypto-wif/test/identity.json b/packages/crypto-wif/test/identity.json index ba29cfedc9..60af1b7eed 100644 --- a/packages/crypto-wif/test/identity.json +++ b/packages/crypto-wif/test/identity.json @@ -1,4 +1,5 @@ { - "wif": "SHwubc7KKWJYEmvj9Ymc1LLQa42NYVCEeQYVFes16WkUPJSVAac2", + "wif": "UfDzkBsi7xxjq491zm5tk7rCZ1EouBXsFUWaCvQWxAortbh1zq5T", + "wif170": "SHwubc7KKWJYEmvj9Ymc1LLQa42NYVCEeQYVFes16WkUPJSVAac2", "mnemonic": "this is a top secret mnemonic" } From fbeb7a3ba9cd973b268549c68a6379ef46860609 Mon Sep 17 00:00:00 2001 From: sebastijankuzner Date: Mon, 30 Mar 2026 18:42:15 +0000 Subject: [PATCH 03/22] Fix packages/crypto-address-base58 --- .../source/address.factory.test.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/packages/crypto-address-base58/source/address.factory.test.ts b/packages/crypto-address-base58/source/address.factory.test.ts index 8074acc9d7..610917724e 100644 --- a/packages/crypto-address-base58/source/address.factory.test.ts +++ b/packages/crypto-address-base58/source/address.factory.test.ts @@ -10,8 +10,8 @@ import cryptoJson from "../../core/bin/config/devnet/core/crypto.json"; import { describe } from "@mainsail/test-runner"; import { AddressFactory } from "./address.factory"; -const mnemonic = "this is a top secret passphrase"; -const wif = "SGq4xLgZKCGxs7bjmwnBrWcT4C1ADFEermj846KC97FSv1WFD1dA"; +const mnemonic = "this is a top secret mnemonic"; +const wif = "UfDzkBsi7xxjq491zm5tk7rCZ1EouBXsFUWaCvQWxAortbh1zq5T"; describe<{ app: Application }>("AddressFactory", ({ assert, beforeEach, it }) => { beforeEach(async (context) => { @@ -20,8 +20,6 @@ describe<{ app: Application }>("AddressFactory", ({ assert, beforeEach, it }) => await context.app.resolve(ValidationServiceProvider).register(); await context.app.resolve(CryptoConfigServiceProvider).register(); - context.app.get(Identifiers.Cryptography.Configuration).set("network.wif", 170); - await context.app.resolve(ECDSA).register(); await context.app.resolve(CryptoHashBcrypto).register(); }); @@ -29,7 +27,7 @@ describe<{ app: Application }>("AddressFactory", ({ assert, beforeEach, it }) => it("should derive an address from an mnemonic", async (context) => { assert.is( await context.app.resolve(AddressFactory).fromMnemonic(mnemonic), - "D61mfSggzbvQgTUe6JhYKH2doHaqJ3Dyib", + "DLsMhiUzAVEXBXDTY1NGNZteWz8SDvphfa", ); }); @@ -57,11 +55,11 @@ describe<{ app: Application }>("AddressFactory", ({ assert, beforeEach, it }) => }); it("should derive an address from wif", async (context) => { - assert.is(await context.app.resolve(AddressFactory).fromWIF(wif), "D61mfSggzbvQgTUe6JhYKH2doHaqJ3Dyib"); + assert.is(await context.app.resolve(AddressFactory).fromWIF(wif), "DLsMhiUzAVEXBXDTY1NGNZteWz8SDvphfa"); }); it("should validate addresses", async (context) => { - assert.true(await context.app.resolve(AddressFactory).validate("D61mfSggzbvQgTUe6JhYKH2doHaqJ3Dyib")); + assert.true(await context.app.resolve(AddressFactory).validate("DLsMhiUzAVEXBXDTY1NGNZteWz8SDvphfa")); assert.false( await context.app .resolve(AddressFactory) @@ -73,8 +71,8 @@ describe<{ app: Application }>("AddressFactory", ({ assert, beforeEach, it }) => const addressFactory = context.app.resolve(AddressFactory); assert.equal( - await addressFactory.fromBuffer(await addressFactory.toBuffer("D61mfSggzbvQgTUe6JhYKH2doHaqJ3Dyib")), - "D61mfSggzbvQgTUe6JhYKH2doHaqJ3Dyib", + await addressFactory.fromBuffer(await addressFactory.toBuffer("DLsMhiUzAVEXBXDTY1NGNZteWz8SDvphfa")), + "DLsMhiUzAVEXBXDTY1NGNZteWz8SDvphfa", ); }); @@ -86,7 +84,7 @@ describe<{ app: Application }>("AddressFactory", ({ assert, beforeEach, it }) => .set("network.pubKeyHash", 44); await assert.rejects( - () => addressFactory.toBuffer("D61mfSggzbvQgTUe6JhYKH2doHaqJ3Dyib"), + () => addressFactory.toBuffer("DLsMhiUzAVEXBXDTY1NGNZteWz8SDvphfa"), "Expected address network byte 44, but got 30.", ); }); From 758c11bbb850dbd851dc6b71dc1ed0641eb82866 Mon Sep 17 00:00:00 2001 From: sebastijankuzner Date: Mon, 30 Mar 2026 18:44:28 +0000 Subject: [PATCH 04/22] packages/crypto-address-keccak256 --- .../source/address.factory.test.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/crypto-address-keccak256/source/address.factory.test.ts b/packages/crypto-address-keccak256/source/address.factory.test.ts index fb95cbe334..76c4a61b8a 100644 --- a/packages/crypto-address-keccak256/source/address.factory.test.ts +++ b/packages/crypto-address-keccak256/source/address.factory.test.ts @@ -7,10 +7,8 @@ import { ServiceProvider as ValidationServiceProvider } from "@mainsail/validati import { describe } from "@mainsail/test-runner"; import { AddressFactory } from "./address.factory"; -const mnemonic = - "program fragile industry scare sun visit race erase daughter empty anxiety cereal cycle hunt airport educate giggle picture sunset apart jewel similar pulp moment"; - -const wif = "SDuW66dyGZ1zPZdN7ncEevbJdjaQTj9pT4LcmKzQ7eLFoyCXEdkx"; +const mnemonic = "this is a top secret mnemonic"; +const wif = "UfDzkBsi7xxjq491zm5tk7rCZ1EouBXsFUWaCvQWxAortbh1zq5T"; describe<{ app: Application }>("AddressFactory", ({ assert, beforeEach, it }) => { beforeEach(async (context) => { @@ -24,7 +22,7 @@ describe<{ app: Application }>("AddressFactory", ({ assert, beforeEach, it }) => it("should derive an address from an mnemonic", async (context) => { assert.is( await context.app.resolve(AddressFactory).fromMnemonic(mnemonic), - "0xC7C50f33278bDe272ffe23865fF9fBd0155a5175", + "0xE8F0d8418AF1cE7ADA59c02870FBF38C8909D8ac", ); }); @@ -66,7 +64,7 @@ describe<{ app: Application }>("AddressFactory", ({ assert, beforeEach, it }) => }); it("should derive an address from wif", async (context) => { - assert.is(await context.app.resolve(AddressFactory).fromWIF(wif), "0xC7C50f33278bDe272ffe23865fF9fBd0155a5175"); + assert.is(await context.app.resolve(AddressFactory).fromWIF(wif), "0xE8F0d8418AF1cE7ADA59c02870FBF38C8909D8ac"); }); it("should validate addresses", async (context) => { From 107161d69e097090cccdb938c3992c1fa8e61142 Mon Sep 17 00:00:00 2001 From: sebastijankuzner Date: Thu, 2 Apr 2026 13:22:40 +0000 Subject: [PATCH 05/22] Update crypto key pair --- .../crypto-key-pair-bls12-381/source/pair.test.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/crypto-key-pair-bls12-381/source/pair.test.ts b/packages/crypto-key-pair-bls12-381/source/pair.test.ts index 35f9bcfdb5..6304789da0 100644 --- a/packages/crypto-key-pair-bls12-381/source/pair.test.ts +++ b/packages/crypto-key-pair-bls12-381/source/pair.test.ts @@ -1,8 +1,10 @@ import { Application } from "@mainsail/kernel"; import { Identifiers } from "@mainsail/constants"; -import { Configuration } from "@mainsail/crypto-config"; +import type { Contracts } from "@mainsail/contracts"; import { ServiceProvider as ValidationServiceProvider } from "@mainsail/validation"; +import { ServiceProvider as CryptoConfigServiceProvider } from "@mainsail/crypto-config"; +import cryptoJson from "../../core/bin/config/devnet/core/crypto.json"; import { describe } from "@mainsail/test-runner"; import { KeyPairFactory } from "./pair"; @@ -12,8 +14,10 @@ const mnemonic = describe<{ app: Application; factory: KeyPairFactory }>("KeyPairFactory", ({ assert, beforeEach, it }) => { beforeEach(async (context) => { context.app = new Application(); + + context.app.get(Identifiers.Config.Repository).set("crypto", cryptoJson); await context.app.resolve(ValidationServiceProvider).register(); - context.app.bind(Identifiers.Cryptography.Configuration).to(Configuration).inSingletonScope(); + await context.app.resolve(CryptoConfigServiceProvider).register(); context.factory = context.app.resolve(KeyPairFactory); }); @@ -27,7 +31,7 @@ describe<{ app: Application; factory: KeyPairFactory }>("KeyPairFactory", ({ ass }); }); - it("should derive a key pair from an mnemonic", async ({ factory }) => { + it("should derive a key pair from a private key", async ({ factory }) => { assert.equal( await factory.fromPrivateKey( Buffer.from("3e99d30b3816f60077b1fdb4535ce0e9f9c715e42d1647edc3361fc531fb618f", "hex"), @@ -42,7 +46,7 @@ describe<{ app: Application; factory: KeyPairFactory }>("KeyPairFactory", ({ ass }); it("should derive from a WIF", async ({ factory }) => { - assert.equal(await factory.fromWIF("KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"), { + assert.equal(await factory.fromWIF("UfDzkBsi7xxjq491zm5tk7rCZ1EouBXsFUWaCvQWxAortbh1zq5T"), { compressed: true, privateKey: "0000000000000000000000000000000000000000000000000000000000000001", publicKey: From b0da333c1cd0e442ebf821d0bb36599990426c72 Mon Sep 17 00:00:00 2001 From: sebastijankuzner Date: Thu, 2 Apr 2026 13:46:51 +0000 Subject: [PATCH 06/22] Generate identities in wif --- .../crypto-wif/source/wif.factory.test.ts | 36 +++++++++---------- packages/crypto-wif/test/identities.ts | 24 +++++++++++++ packages/crypto-wif/test/identity.json | 5 --- packages/crypto-wif/test/index.ts | 1 + 4 files changed, 41 insertions(+), 25 deletions(-) create mode 100644 packages/crypto-wif/test/identities.ts delete mode 100644 packages/crypto-wif/test/identity.json create mode 100644 packages/crypto-wif/test/index.ts diff --git a/packages/crypto-wif/source/wif.factory.test.ts b/packages/crypto-wif/source/wif.factory.test.ts index 69616cfd2f..ba8fcfe6d7 100644 --- a/packages/crypto-wif/source/wif.factory.test.ts +++ b/packages/crypto-wif/source/wif.factory.test.ts @@ -6,7 +6,7 @@ import { KeyPairFactory } from "@mainsail/crypto-key-pair-ecdsa/source/pair"; import { Application } from "@mainsail/kernel"; import { describe } from "@mainsail/test-runner"; -import { mnemonic, wif, wif170 } from "../test/identity.json"; +import { wallets } from "../test/index.js"; import { WIFFactory } from "./wif.factory"; import cryptoJson from "../../core/bin/config/devnet/core/crypto.json"; @@ -14,7 +14,7 @@ describe<{ app: Application; factory: WIFFactory; configuration: Contracts.Crypto.Configuration; -}>("Identities - WIFFactory", ({ it, assert, beforeEach }) => { +}>("Identities - WIFFactory", ({ it, assert, beforeEach, each }) => { beforeEach(async (context) => { context.app = new Application(); context.app.get(Identifiers.Config.Repository).set("crypto", cryptoJson); @@ -27,35 +27,31 @@ describe<{ context.factory = context.app.resolve(WIFFactory); }); - it("#fromMnemonic - should be OK", async ({ factory }) => { - assert.equal(await factory.fromMnemonic(mnemonic), wif); - }); + each("#fromMnemonic - should be OK", async ({ context: { factory }, dataset: wallet }) => { + assert.equal(await factory.fromMnemonic(wallet.mnemonic), wallet.wif); + }, wallets); - it("#fromMnemonic - should be OK for WIF 170", async ({ factory, configuration }) => { + each("#fromMnemonic - should be OK for WIF 170", async ({ context: { factory, configuration }, dataset: wallet }) => { configuration.set("network.wif", 170); - assert.equal(await factory.fromMnemonic(mnemonic), wif170); - }); - - it("#fromMnemonic - should be OK", async ({ factory }) => { - assert.equal(await factory.fromMnemonic(mnemonic), wif); - }); + assert.equal(await factory.fromMnemonic(wallet.mnemonic), wallet.wif170); + }, wallets); - it("#fromKeys - should be OK", async ({ factory, app }) => { + each("#fromKeys - should be OK", async ({ context: { factory, app }, dataset: wallet }) => { assert.equal( await factory.fromKeys( - await app.get(Identifiers.Cryptography.Identity.KeyPair.Factory).fromMnemonic(mnemonic), + await app.get(Identifiers.Cryptography.Identity.KeyPair.Factory).fromMnemonic(wallet.mnemonic), ), - wif, + wallet.wif, ); - }); + }, wallets); - it("#fromKeys - should be OK for WIF 170", async ({ factory, app, configuration }) => { + each("#fromKeys - should be OK for WIF 170", async ({ context: { factory, app, configuration }, dataset: wallet }) => { configuration.set("network.wif", 170); assert.equal( await factory.fromKeys( - await app.get(Identifiers.Cryptography.Identity.KeyPair.Factory).fromMnemonic(mnemonic), + await app.get(Identifiers.Cryptography.Identity.KeyPair.Factory).fromMnemonic(wallet.mnemonic), ), - wif170, + wallet.wif170, ); - }); + }, wallets); }); diff --git a/packages/crypto-wif/test/identities.ts b/packages/crypto-wif/test/identities.ts new file mode 100644 index 0000000000..66b9f667da --- /dev/null +++ b/packages/crypto-wif/test/identities.ts @@ -0,0 +1,24 @@ +export const wallet1 = { + address: '0x4DDA5269bC0D28c15006A75C6eaFb282138c71A6', + mnemonic: 'goddess laugh coin share picture napkin sausage surprise busy soft sting nothing drastic stove drive magic border amount symbol child swing peace book brass', + privateKey: 'ae9eac49907186760d8a1e2efa2a537adfa8333bfeddb0aaaa92fde6c86e4043', + publicKey: '02ffa9181f8ea9ea1ed85bed0ce53213367b5e8258b18cc745fa397ed40fa867fe', + validatorPrivateKey: '09dadae56492c1abd8453f393169fc2019c079b91369fe9f76d568e5964a69cf', + validatorPublicKey: '84b19d74a9bcb9d9e6c59b6114499820fba555884403120149a0041b892136141cbe08d929c5a4dfa18b881467da5d68', + wif: 'UchikoX1AAPyjNeLZRh975EAxuMPuC7Xz9gm9Zho1jSzuc6tN5JD', + wif170: 'SFRdcDkcMhjn96S3iDNrNHiNyx8xYVmuP5igCJAHA5PcQJwREvrR', +} + + +export const wallet2 = { + address: '0x3A6DfD8C942eE15fA9b2e17c10A4a38C6BC7d8d4', + mnemonic: 'desert belt subject reject digital flight topic frost decide juice run visa dilemma zoo jelly skirt play turtle soon globe solution vacant first mixture', + privateKey: 'd294208627305427225cf52485ce97c59c73ba178fdc0a0f8c96ad4152bd4a97', + publicKey: '02f032d4e5ee2c75029798ce50217eb403e55965daa3edcc1e9f4abdcccc025f54', + validatorPrivateKey: '59ef9225e0eba62a7c985061cef0bb48a82661c39901f7d3b142246912229100', + validatorPublicKey: 'b4ef04ddab942fbeee07ba6f657bfe2e6a01bdfbc2afb9b04ff2eb44cdf830f162cf6024bd417a97d62d476c9f93da6d', + wif: 'Uducumhc47DYcpxZYjJE8nNNkL3FbNA2vyxYMPW967FxBrAbS8Z4', + wif170: 'SGdXmBwDFeZM2YkGhWywPzramNppEfpQKuzTQ7xdETCZgYyu9ZyU', +} + +export const wallets = [wallet1, wallet2]; diff --git a/packages/crypto-wif/test/identity.json b/packages/crypto-wif/test/identity.json deleted file mode 100644 index 60af1b7eed..0000000000 --- a/packages/crypto-wif/test/identity.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "wif": "UfDzkBsi7xxjq491zm5tk7rCZ1EouBXsFUWaCvQWxAortbh1zq5T", - "wif170": "SHwubc7KKWJYEmvj9Ymc1LLQa42NYVCEeQYVFes16WkUPJSVAac2", - "mnemonic": "this is a top secret mnemonic" -} diff --git a/packages/crypto-wif/test/index.ts b/packages/crypto-wif/test/index.ts new file mode 100644 index 0000000000..717614e637 --- /dev/null +++ b/packages/crypto-wif/test/index.ts @@ -0,0 +1 @@ +export * from "./identities.js"; From e774ca5299caeead02aa4474bf35b179b29a2530 Mon Sep 17 00:00:00 2001 From: sebastijankuzner Date: Thu, 2 Apr 2026 14:26:53 +0000 Subject: [PATCH 07/22] Implement toPrivateKey --- .../source/contracts/crypto/identities.ts | 1 + packages/crypto-wif/package.json | 1 + packages/crypto-wif/source/wif.factory.test.ts | 15 +++++++++++++++ packages/crypto-wif/source/wif.factory.ts | 14 +++++++++++++- packages/exceptions/source/crypto.ts | 6 ++++++ pnpm-lock.yaml | 3 +++ 6 files changed, 39 insertions(+), 1 deletion(-) diff --git a/packages/contracts/source/contracts/crypto/identities.ts b/packages/contracts/source/contracts/crypto/identities.ts index 96312d8b3f..feb1ba9ea4 100644 --- a/packages/contracts/source/contracts/crypto/identities.ts +++ b/packages/contracts/source/contracts/crypto/identities.ts @@ -40,6 +40,7 @@ export interface KeyPairFactory { export interface WIFFactory { fromMnemonic(mnemonic: string): Promise; fromKeys(keys: KeyPair): Promise; + toPrivateKey(wif: string): Promise; } export interface AddressSerializer { diff --git a/packages/crypto-wif/package.json b/packages/crypto-wif/package.json index b1fe009af2..89e87a5125 100644 --- a/packages/crypto-wif/package.json +++ b/packages/crypto-wif/package.json @@ -32,6 +32,7 @@ "@mainsail/crypto-key-pair-ecdsa": "workspace:*", "@mainsail/test-runner": "workspace:*", "@mainsail/validation": "workspace:*", + "@mainsail/exceptions": "workspace:*", "uvu": "0.5.6" }, "engines": { diff --git a/packages/crypto-wif/source/wif.factory.test.ts b/packages/crypto-wif/source/wif.factory.test.ts index ba8fcfe6d7..9e368bb2f2 100644 --- a/packages/crypto-wif/source/wif.factory.test.ts +++ b/packages/crypto-wif/source/wif.factory.test.ts @@ -3,6 +3,7 @@ import { Contracts } from "@mainsail/contracts"; import { ServiceProvider as ValidationServiceProvider } from "@mainsail/validation"; import { ServiceProvider as CryptoConfigServiceProvider } from "@mainsail/crypto-config"; import { KeyPairFactory } from "@mainsail/crypto-key-pair-ecdsa/source/pair"; +import { WifNetworkError } from "@mainsail/exceptions"; import { Application } from "@mainsail/kernel"; import { describe } from "@mainsail/test-runner"; @@ -54,4 +55,18 @@ describe<{ wallet.wif170, ); }, wallets); + + each("#toPrivateKey - should be OK", async ({ context: { factory }, dataset: wallet }) => { + assert.equal(await factory.toPrivateKey(wallet.wif), wallet.privateKey); + }, wallets); + + each("#toPrivateKey - should be OK for WIF 170", async ({ context: { factory, configuration }, dataset: wallet }) => { + configuration.set("network.wif", 170); + assert.equal(await factory.toPrivateKey(wallet.wif170), wallet.privateKey); + }, wallets); + + + each("#toPrivateKey - should throw on invalid WIF network version", async ({ context: { factory }, dataset: wallet }) => { + await assert.rejects(() => factory.toPrivateKey(wallet.wif170), WifNetworkError); + }, wallets); }); diff --git a/packages/crypto-wif/source/wif.factory.ts b/packages/crypto-wif/source/wif.factory.ts index 9ee8b35636..85adc8e126 100644 --- a/packages/crypto-wif/source/wif.factory.ts +++ b/packages/crypto-wif/source/wif.factory.ts @@ -2,7 +2,8 @@ import type { Contracts } from "@mainsail/contracts"; import { Identifiers } from "@mainsail/constants"; import { inject, injectable, tagged } from "@mainsail/container"; -import { encode } from "wif"; +import { WifNetworkError } from "@mainsail/exceptions"; +import { encode, decode } from "wif"; @injectable() export class WIFFactory implements Contracts.Crypto.WIFFactory { @@ -30,4 +31,15 @@ export class WIFFactory implements Contracts.Crypto.WIFFactory { version: this.configuration.get("network.wif"), }); } + + public async toPrivateKey(wif: string): Promise { + const networkVersion = this.configuration.get("network.wif") + const decoded = decode(wif); + + if (decoded.version !== networkVersion) { + throw new WifNetworkError(networkVersion, decoded.version); + } + + return Buffer.from(decoded.privateKey).toString("hex"); + } } diff --git a/packages/exceptions/source/crypto.ts b/packages/exceptions/source/crypto.ts index ba75656583..4aefa6a215 100644 --- a/packages/exceptions/source/crypto.ts +++ b/packages/exceptions/source/crypto.ts @@ -33,6 +33,12 @@ export class NetworkVersionError extends Exception { } } +export class WifNetworkError extends Exception { + public constructor(expected: string | number, given: string | number) { + super(`Expected WIF network version to be ${expected}, but got ${given}.`); + } +} + export class PrivateKeyLengthError extends Exception { public constructor(expected: string | number, given: string | number) { super(`Expected length to be ${expected}, but got ${given}.`); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 270c0e867f..237bdaf452 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1931,6 +1931,9 @@ importers: '@mainsail/crypto-key-pair-ecdsa': specifier: workspace:* version: link:../crypto-key-pair-ecdsa + '@mainsail/exceptions': + specifier: workspace:* + version: link:../exceptions '@mainsail/test-runner': specifier: workspace:* version: link:../test-runner From 5986c21e9591b6b5b5a95f5489c76881114491b1 Mon Sep 17 00:00:00 2001 From: sebastijankuzner Date: Thu, 2 Apr 2026 15:30:43 +0000 Subject: [PATCH 08/22] Test pair --- .../crypto-key-pair-ecdsa/source/pair.test.ts | 45 +++++++++++-------- packages/crypto-key-pair-ecdsa/source/pair.ts | 3 ++ 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/packages/crypto-key-pair-ecdsa/source/pair.test.ts b/packages/crypto-key-pair-ecdsa/source/pair.test.ts index bef53d37ec..d94a582c37 100644 --- a/packages/crypto-key-pair-ecdsa/source/pair.test.ts +++ b/packages/crypto-key-pair-ecdsa/source/pair.test.ts @@ -5,14 +5,12 @@ import { ServiceProvider as ValidationServiceProvider } from "@mainsail/validati import { describe } from "@mainsail/test-runner"; import { KeyPairFactory } from "./pair"; - -const mnemonic = - "program fragile industry scare sun visit race erase daughter empty anxiety cereal cycle hunt airport educate giggle picture sunset apart jewel similar pulp moment"; +import { wallet1, wallets } from "../../crypto-wif/test/index.js"; describe<{ app: Application; factory: KeyPairFactory; -}>("KeyPairFactory", ({ assert, beforeEach, it }) => { +}>("KeyPairFactory", ({ assert, beforeEach, it, each }) => { beforeEach(async (context) => { context.app = new Application(); await context.app.resolve(ValidationServiceProvider).register(); @@ -21,32 +19,41 @@ describe<{ context.factory = context.app.resolve(KeyPairFactory); }); - it("should derive a key pair from an mnemonic", async ({ factory }) => { - assert.equal(await factory.fromMnemonic(mnemonic), { + each("#fromMnemonic - should derive a key pair", async ({ context: { factory }, dataset: wallet }) => { + assert.equal(await factory.fromMnemonic(wallet.mnemonic), { compressed: true, - privateKey: "814857ce48e291893feab95df02e1dbf7ad3994ba46f247f77e4eefd5d8734a2", - publicKey: "03e84093c072af70004a38dd95e34def119d2348d5261228175d032e5f2070e19f", + privateKey: wallet.privateKey, + publicKey: wallet.publicKey, }); - }); + }, wallets); - it("should derive a key pair from an mnemonic", async ({ factory }) => { + each("#fromPrivateKey - should derive a key pair", async ({ context: { factory }, dataset: wallet }) => { assert.equal( await factory.fromPrivateKey( - Buffer.from("814857ce48e291893feab95df02e1dbf7ad3994ba46f247f77e4eefd5d8734a2", "hex"), + Buffer.from(wallet.privateKey, "hex"), ), { compressed: true, - privateKey: "814857ce48e291893feab95df02e1dbf7ad3994ba46f247f77e4eefd5d8734a2", - publicKey: "03e84093c072af70004a38dd95e34def119d2348d5261228175d032e5f2070e19f", + privateKey: wallet.privateKey, + publicKey: wallet.publicKey, }, ); - }); + }, wallets); - it("should derive from a WIF", async ({ factory }) => { - assert.equal(await factory.fromWIF("KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"), { + each("#fromWIF - should derive a key pair from a WIF", async ({ context: { factory }, dataset: wallet }) => { + assert.equal(await factory.fromWIF(wallet.wif), { compressed: true, - privateKey: "0000000000000000000000000000000000000000000000000000000000000001", - publicKey: "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", + privateKey: wallet.privateKey, + publicKey: wallet.publicKey, }); - }); + }, wallets); + + + each("#fromWIF - should derive a key pair from a WIF 170", async ({ context: { factory }, dataset: wallet }) => { + assert.equal(await factory.fromWIF(wallet.wif), { + compressed: true, + privateKey: wallet.privateKey, + publicKey: wallet.publicKey, + }); + }, wallets); }); diff --git a/packages/crypto-key-pair-ecdsa/source/pair.ts b/packages/crypto-key-pair-ecdsa/source/pair.ts index c90754abac..cd5d08e4e2 100644 --- a/packages/crypto-key-pair-ecdsa/source/pair.ts +++ b/packages/crypto-key-pair-ecdsa/source/pair.ts @@ -10,6 +10,9 @@ export class KeyPairFactory implements Contracts.Crypto.KeyPairFactory { @inject(Identifiers.Cryptography.Configuration) private readonly configuration!: Contracts.Crypto.Configuration; + // @inject(Identifiers.Cryptography.Identity.Wif.Factory) + // private readonly wifFactory!: Contracts.Crypto.WIFFactory; + public async fromMnemonic(mnemonic: string, compressed: boolean = true): Promise { return this.fromPrivateKey(SHA256.digest(Buffer.from(mnemonic, "utf8")), compressed); } From 026b96432d479ec6efeac4ec2a267f6ac8165dee Mon Sep 17 00:00:00 2001 From: sebastijankuzner Date: Thu, 2 Apr 2026 15:35:51 +0000 Subject: [PATCH 09/22] Return compressed --- .../contracts/source/contracts/crypto/identities.ts | 5 ++++- packages/crypto-wif/source/wif.factory.test.ts | 4 ++-- packages/crypto-wif/source/wif.factory.ts | 10 ++++++++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/contracts/source/contracts/crypto/identities.ts b/packages/contracts/source/contracts/crypto/identities.ts index feb1ba9ea4..f64441f1b5 100644 --- a/packages/contracts/source/contracts/crypto/identities.ts +++ b/packages/contracts/source/contracts/crypto/identities.ts @@ -40,7 +40,10 @@ export interface KeyPairFactory { export interface WIFFactory { fromMnemonic(mnemonic: string): Promise; fromKeys(keys: KeyPair): Promise; - toPrivateKey(wif: string): Promise; + toPrivateKey(wif: string): Promise<{ + compressed: boolean; + privateKey: string; + }>; } export interface AddressSerializer { diff --git a/packages/crypto-wif/source/wif.factory.test.ts b/packages/crypto-wif/source/wif.factory.test.ts index 9e368bb2f2..1d3c50699f 100644 --- a/packages/crypto-wif/source/wif.factory.test.ts +++ b/packages/crypto-wif/source/wif.factory.test.ts @@ -57,12 +57,12 @@ describe<{ }, wallets); each("#toPrivateKey - should be OK", async ({ context: { factory }, dataset: wallet }) => { - assert.equal(await factory.toPrivateKey(wallet.wif), wallet.privateKey); + assert.equal(await factory.toPrivateKey(wallet.wif), { compressed: true, privateKey: wallet.privateKey }); }, wallets); each("#toPrivateKey - should be OK for WIF 170", async ({ context: { factory, configuration }, dataset: wallet }) => { configuration.set("network.wif", 170); - assert.equal(await factory.toPrivateKey(wallet.wif170), wallet.privateKey); + assert.equal(await factory.toPrivateKey(wallet.wif170), { compressed: true, privateKey: wallet.privateKey }); }, wallets); diff --git a/packages/crypto-wif/source/wif.factory.ts b/packages/crypto-wif/source/wif.factory.ts index 85adc8e126..831f6f6d18 100644 --- a/packages/crypto-wif/source/wif.factory.ts +++ b/packages/crypto-wif/source/wif.factory.ts @@ -32,7 +32,10 @@ export class WIFFactory implements Contracts.Crypto.WIFFactory { }); } - public async toPrivateKey(wif: string): Promise { + public async toPrivateKey(wif: string): Promise<{ + compressed: boolean; + privateKey: string; + }> { const networkVersion = this.configuration.get("network.wif") const decoded = decode(wif); @@ -40,6 +43,9 @@ export class WIFFactory implements Contracts.Crypto.WIFFactory { throw new WifNetworkError(networkVersion, decoded.version); } - return Buffer.from(decoded.privateKey).toString("hex"); + return { + compressed: decoded.compressed, + privateKey: Buffer.from(decoded.privateKey).toString("hex"), + } } } From c64c1c61a5b825e66e6df199a1e1d814f6cbfdbe Mon Sep 17 00:00:00 2001 From: sebastijankuzner Date: Thu, 2 Apr 2026 18:56:29 +0200 Subject: [PATCH 10/22] Add crypto wif to key pair --- packages/crypto-key-pair-ecdsa/package.json | 1 + .../crypto-key-pair-ecdsa/source/pair.test.ts | 101 +++++++++++------- packages/crypto-key-pair-ecdsa/source/pair.ts | 18 +--- pnpm-lock.yaml | 3 + 4 files changed, 69 insertions(+), 54 deletions(-) diff --git a/packages/crypto-key-pair-ecdsa/package.json b/packages/crypto-key-pair-ecdsa/package.json index de47247863..8ee54f75d4 100644 --- a/packages/crypto-key-pair-ecdsa/package.json +++ b/packages/crypto-key-pair-ecdsa/package.json @@ -34,6 +34,7 @@ "@mainsail/crypto-config": "workspace:*", "@mainsail/test-runner": "workspace:*", "@mainsail/validation": "workspace:*", + "@mainsail/crypto-wif": "workspace:*", "bip39": "3.1.0", "uvu": "0.5.6" }, diff --git a/packages/crypto-key-pair-ecdsa/source/pair.test.ts b/packages/crypto-key-pair-ecdsa/source/pair.test.ts index d94a582c37..e601434952 100644 --- a/packages/crypto-key-pair-ecdsa/source/pair.test.ts +++ b/packages/crypto-key-pair-ecdsa/source/pair.test.ts @@ -1,11 +1,16 @@ import { Application } from "@mainsail/kernel"; import { Identifiers } from "@mainsail/constants"; -import { Configuration } from "@mainsail/crypto-config"; +import { Contracts } from "@mainsail/contracts"; import { ServiceProvider as ValidationServiceProvider } from "@mainsail/validation"; +import { ServiceProvider as CryptoConfigServiceProvider } from "@mainsail/crypto-config"; +import { ServiceProvider as CryptoWifServiceProvider } from "@mainsail/crypto-wif"; +import { WIFFactory } from "@mainsail/crypto-wif/source/wif.factory.js"; import { describe } from "@mainsail/test-runner"; import { KeyPairFactory } from "./pair"; import { wallet1, wallets } from "../../crypto-wif/test/index.js"; +import cryptoJson from "../../core/bin/config/devnet/core/crypto.json"; + describe<{ app: Application; @@ -13,47 +18,63 @@ describe<{ }>("KeyPairFactory", ({ assert, beforeEach, it, each }) => { beforeEach(async (context) => { context.app = new Application(); + context.app.get(Identifiers.Config.Repository).set("crypto", cryptoJson); await context.app.resolve(ValidationServiceProvider).register(); - context.app.bind(Identifiers.Cryptography.Configuration).to(Configuration).inSingletonScope(); + await context.app.resolve(CryptoConfigServiceProvider).register(); + // await context.app.resolve(CryptoWifServiceProvider).register(); + + context.app.bind(Identifiers.Cryptography.Identity.Wif.Factory).to(WIFFactory).inSingletonScope(); + + console.log("Is bound: ", context.app.isBound(Identifiers.Cryptography.Identity.Wif.Factory)); + console.log("Get: ", context.app.get(Identifiers.Cryptography.Identity.Wif.Factory)); + + // context.factory = context.app.resolve(KeyPairFactory); + }); - context.factory = context.app.resolve(KeyPairFactory); + + it("#fromMnemonic - should derive a key pair", async ( { factory }) => { + // assert.equal(await factory.fromMnemonic(wallet.mnemonic), { + // compressed: true, + // privateKey: wallet.privateKey, + // publicKey: wallet.publicKey, + // }); }); - each("#fromMnemonic - should derive a key pair", async ({ context: { factory }, dataset: wallet }) => { - assert.equal(await factory.fromMnemonic(wallet.mnemonic), { - compressed: true, - privateKey: wallet.privateKey, - publicKey: wallet.publicKey, - }); - }, wallets); - - each("#fromPrivateKey - should derive a key pair", async ({ context: { factory }, dataset: wallet }) => { - assert.equal( - await factory.fromPrivateKey( - Buffer.from(wallet.privateKey, "hex"), - ), - { - compressed: true, - privateKey: wallet.privateKey, - publicKey: wallet.publicKey, - }, - ); - }, wallets); - - each("#fromWIF - should derive a key pair from a WIF", async ({ context: { factory }, dataset: wallet }) => { - assert.equal(await factory.fromWIF(wallet.wif), { - compressed: true, - privateKey: wallet.privateKey, - publicKey: wallet.publicKey, - }); - }, wallets); - - - each("#fromWIF - should derive a key pair from a WIF 170", async ({ context: { factory }, dataset: wallet }) => { - assert.equal(await factory.fromWIF(wallet.wif), { - compressed: true, - privateKey: wallet.privateKey, - publicKey: wallet.publicKey, - }); - }, wallets); + // each("#fromMnemonic - should derive a key pair", async ({ context: { factory }, dataset: wallet }) => { + // // assert.equal(await factory.fromMnemonic(wallet.mnemonic), { + // // compressed: true, + // // privateKey: wallet.privateKey, + // // publicKey: wallet.publicKey, + // // }); + // }, wallets); + + // each("#fromPrivateKey - should derive a key pair", async ({ context: { factory }, dataset: wallet }) => { + // assert.equal( + // await factory.fromPrivateKey( + // Buffer.from(wallet.privateKey, "hex"), + // ), + // { + // compressed: true, + // privateKey: wallet.privateKey, + // publicKey: wallet.publicKey, + // }, + // ); + // }, wallets); + + // each("#fromWIF - should derive a key pair from a WIF", async ({ context: { factory }, dataset: wallet }) => { + // assert.equal(await factory.fromWIF(wallet.wif), { + // compressed: true, + // privateKey: wallet.privateKey, + // publicKey: wallet.publicKey, + // }); + // }, wallets); + + + // each("#fromWIF - should derive a key pair from a WIF 170", async ({ context: { factory }, dataset: wallet }) => { + // assert.equal(await factory.fromWIF(wallet.wif), { + // compressed: true, + // privateKey: wallet.privateKey, + // publicKey: wallet.publicKey, + // }); + // }, wallets); }); diff --git a/packages/crypto-key-pair-ecdsa/source/pair.ts b/packages/crypto-key-pair-ecdsa/source/pair.ts index cd5d08e4e2..2015a71b8b 100644 --- a/packages/crypto-key-pair-ecdsa/source/pair.ts +++ b/packages/crypto-key-pair-ecdsa/source/pair.ts @@ -3,15 +3,11 @@ import type { Contracts } from "@mainsail/contracts"; import { Identifiers } from "@mainsail/constants"; import { inject, injectable } from "@mainsail/container"; import { secp256k1, SHA256 } from "bcrypto"; -import { decode } from "wif"; @injectable() export class KeyPairFactory implements Contracts.Crypto.KeyPairFactory { - @inject(Identifiers.Cryptography.Configuration) - private readonly configuration!: Contracts.Crypto.Configuration; - - // @inject(Identifiers.Cryptography.Identity.Wif.Factory) - // private readonly wifFactory!: Contracts.Crypto.WIFFactory; + @inject(Identifiers.Cryptography.Identity.Wif.Factory) + private readonly wifFactory!: Contracts.Crypto.WIFFactory; public async fromMnemonic(mnemonic: string, compressed: boolean = true): Promise { return this.fromPrivateKey(SHA256.digest(Buffer.from(mnemonic, "utf8")), compressed); @@ -26,13 +22,7 @@ export class KeyPairFactory implements Contracts.Crypto.KeyPairFactory { } public async fromWIF(wif: string): Promise { - const decoded = decode(wif, this.configuration.get("network.wif")); - const privateKey = Buffer.from(decoded.privateKey); - - return { - compressed: decoded.compressed, - privateKey: privateKey.toString("hex"), - publicKey: secp256k1.publicKeyCreate(privateKey, decoded.compressed).toString("hex"), - }; + const decoded = await this.wifFactory.toPrivateKey(wif); + return this.fromPrivateKey(Buffer.from(decoded.privateKey, "hex"), decoded.compressed); } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 237bdaf452..75a891f3d8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1585,6 +1585,9 @@ importers: '@mainsail/crypto-config': specifier: workspace:* version: link:../crypto-config + '@mainsail/crypto-wif': + specifier: workspace:* + version: link:../crypto-wif '@mainsail/test-runner': specifier: workspace:* version: link:../test-runner From 408599c9081e449c7b6a730d4f9636dfe18f978f Mon Sep 17 00:00:00 2001 From: sebastijankuzner Date: Thu, 2 Apr 2026 17:46:52 +0000 Subject: [PATCH 11/22] Add WIFDecoder --- packages/constants/source/identifiers.ts | 1 + .../source/contracts/crypto/identities.ts | 3 ++ packages/crypto-wif/source/decoder.ts | 29 +++++++++++++++++++ .../source/service-provider.test.ts | 1 + .../crypto-wif/source/service-provider.ts | 2 ++ .../crypto-wif/source/wif.factory.test.ts | 17 ++--------- 6 files changed, 38 insertions(+), 15 deletions(-) create mode 100644 packages/crypto-wif/source/decoder.ts diff --git a/packages/constants/source/identifiers.ts b/packages/constants/source/identifiers.ts index 6fecd8ce9b..c0eeceeab2 100644 --- a/packages/constants/source/identifiers.ts +++ b/packages/constants/source/identifiers.ts @@ -96,6 +96,7 @@ export const Identifiers = { Size: Symbol("Crypto"), }, Wif: { + Decoder: Symbol("Crypto"), Factory: Symbol("Crypto"), }, }, diff --git a/packages/contracts/source/contracts/crypto/identities.ts b/packages/contracts/source/contracts/crypto/identities.ts index f64441f1b5..00af903f80 100644 --- a/packages/contracts/source/contracts/crypto/identities.ts +++ b/packages/contracts/source/contracts/crypto/identities.ts @@ -40,6 +40,9 @@ export interface KeyPairFactory { export interface WIFFactory { fromMnemonic(mnemonic: string): Promise; fromKeys(keys: KeyPair): Promise; +} + +export interface WIFDecoder { toPrivateKey(wif: string): Promise<{ compressed: boolean; privateKey: string; diff --git a/packages/crypto-wif/source/decoder.ts b/packages/crypto-wif/source/decoder.ts new file mode 100644 index 0000000000..52efbd6379 --- /dev/null +++ b/packages/crypto-wif/source/decoder.ts @@ -0,0 +1,29 @@ +import type { Contracts } from "@mainsail/contracts"; + +import { Identifiers } from "@mainsail/constants"; +import { inject, injectable } from "@mainsail/container"; +import { WifNetworkError } from "@mainsail/exceptions"; +import { decode } from "wif"; + +@injectable() +export class WIFDecoder implements Contracts.Crypto.WIFDecoder { + @inject(Identifiers.Cryptography.Configuration) + private readonly configuration!: Contracts.Crypto.Configuration; + + public async toPrivateKey(wif: string): Promise<{ + compressed: boolean; + privateKey: string; + }> { + const networkVersion = this.configuration.get("network.wif") + const decoded = decode(wif); + + if (decoded.version !== networkVersion) { + throw new WifNetworkError(networkVersion, decoded.version); + } + + return { + compressed: decoded.compressed, + privateKey: Buffer.from(decoded.privateKey).toString("hex"), + } + } +} diff --git a/packages/crypto-wif/source/service-provider.test.ts b/packages/crypto-wif/source/service-provider.test.ts index a45d10d7d7..1a4d5b65c0 100644 --- a/packages/crypto-wif/source/service-provider.test.ts +++ b/packages/crypto-wif/source/service-provider.test.ts @@ -20,5 +20,6 @@ describe<{ await serviceProvider.register(); assert.true(app.isBound(Identifiers.Cryptography.Identity.Wif.Factory)); + assert.true(app.isBound(Identifiers.Cryptography.Identity.Wif.Decoder)); }); }); diff --git a/packages/crypto-wif/source/service-provider.ts b/packages/crypto-wif/source/service-provider.ts index 9bf8e3d1ce..4e54968e97 100644 --- a/packages/crypto-wif/source/service-provider.ts +++ b/packages/crypto-wif/source/service-provider.ts @@ -2,11 +2,13 @@ import { Identifiers } from "@mainsail/constants"; import { injectable } from "@mainsail/container"; import { Providers } from "@mainsail/kernel"; +import { WIFDecoder } from "./decoder.js"; import { WIFFactory } from "./wif.factory.js"; @injectable() export class ServiceProvider extends Providers.ServiceProvider { public async register(): Promise { this.app.bind(Identifiers.Cryptography.Identity.Wif.Factory).to(WIFFactory).inSingletonScope(); + this.app.bind(Identifiers.Cryptography.Identity.Wif.Decoder).to(WIFDecoder).inSingletonScope(); } } diff --git a/packages/crypto-wif/source/wif.factory.test.ts b/packages/crypto-wif/source/wif.factory.test.ts index 1d3c50699f..3c6c76ed61 100644 --- a/packages/crypto-wif/source/wif.factory.test.ts +++ b/packages/crypto-wif/source/wif.factory.test.ts @@ -3,7 +3,6 @@ import { Contracts } from "@mainsail/contracts"; import { ServiceProvider as ValidationServiceProvider } from "@mainsail/validation"; import { ServiceProvider as CryptoConfigServiceProvider } from "@mainsail/crypto-config"; import { KeyPairFactory } from "@mainsail/crypto-key-pair-ecdsa/source/pair"; -import { WifNetworkError } from "@mainsail/exceptions"; import { Application } from "@mainsail/kernel"; import { describe } from "@mainsail/test-runner"; @@ -22,6 +21,8 @@ describe<{ await context.app.resolve(ValidationServiceProvider).register(); await context.app.resolve(CryptoConfigServiceProvider).register(); + + context.app.bind(Identifiers.Cryptography.Identity.Wif.Decoder).toConstantValue({}); context.app.bind(Identifiers.Cryptography.Identity.KeyPair.Factory).to(KeyPairFactory).inSingletonScope(); context.configuration = context.app.get(Identifiers.Cryptography.Configuration); @@ -55,18 +56,4 @@ describe<{ wallet.wif170, ); }, wallets); - - each("#toPrivateKey - should be OK", async ({ context: { factory }, dataset: wallet }) => { - assert.equal(await factory.toPrivateKey(wallet.wif), { compressed: true, privateKey: wallet.privateKey }); - }, wallets); - - each("#toPrivateKey - should be OK for WIF 170", async ({ context: { factory, configuration }, dataset: wallet }) => { - configuration.set("network.wif", 170); - assert.equal(await factory.toPrivateKey(wallet.wif170), { compressed: true, privateKey: wallet.privateKey }); - }, wallets); - - - each("#toPrivateKey - should throw on invalid WIF network version", async ({ context: { factory }, dataset: wallet }) => { - await assert.rejects(() => factory.toPrivateKey(wallet.wif170), WifNetworkError); - }, wallets); }); From ee572d503b38f0cf9f8f06723de97640543732d9 Mon Sep 17 00:00:00 2001 From: sebastijankuzner Date: Thu, 2 Apr 2026 17:47:12 +0000 Subject: [PATCH 12/22] Fix crypto-key-pair-ecdsa --- .../crypto-key-pair-ecdsa/source/pair.test.ts | 87 ++++++++----------- packages/crypto-key-pair-ecdsa/source/pair.ts | 6 +- .../source/private.test.ts | 33 ++++--- .../crypto-key-pair-ecdsa/source/private.ts | 6 +- .../source/public.test.ts | 31 ++++--- .../crypto-key-pair-ecdsa/source/public.ts | 6 +- .../source/schemas.test.ts | 17 ++-- .../source/serializer.test.ts | 19 ++-- packages/crypto-wif/source/decoder.test.ts | 42 +++++++++ 9 files changed, 141 insertions(+), 106 deletions(-) create mode 100644 packages/crypto-wif/source/decoder.test.ts diff --git a/packages/crypto-key-pair-ecdsa/source/pair.test.ts b/packages/crypto-key-pair-ecdsa/source/pair.test.ts index e601434952..a405d65836 100644 --- a/packages/crypto-key-pair-ecdsa/source/pair.test.ts +++ b/packages/crypto-key-pair-ecdsa/source/pair.test.ts @@ -4,14 +4,12 @@ import { Contracts } from "@mainsail/contracts"; import { ServiceProvider as ValidationServiceProvider } from "@mainsail/validation"; import { ServiceProvider as CryptoConfigServiceProvider } from "@mainsail/crypto-config"; import { ServiceProvider as CryptoWifServiceProvider } from "@mainsail/crypto-wif"; -import { WIFFactory } from "@mainsail/crypto-wif/source/wif.factory.js"; import { describe } from "@mainsail/test-runner"; import { KeyPairFactory } from "./pair"; -import { wallet1, wallets } from "../../crypto-wif/test/index.js"; +import { wallets } from "../../crypto-wif/test/index.js"; import cryptoJson from "../../core/bin/config/devnet/core/crypto.json"; - describe<{ app: Application; factory: KeyPairFactory; @@ -21,60 +19,47 @@ describe<{ context.app.get(Identifiers.Config.Repository).set("crypto", cryptoJson); await context.app.resolve(ValidationServiceProvider).register(); await context.app.resolve(CryptoConfigServiceProvider).register(); - // await context.app.resolve(CryptoWifServiceProvider).register(); - - context.app.bind(Identifiers.Cryptography.Identity.Wif.Factory).to(WIFFactory).inSingletonScope(); - - console.log("Is bound: ", context.app.isBound(Identifiers.Cryptography.Identity.Wif.Factory)); - console.log("Get: ", context.app.get(Identifiers.Cryptography.Identity.Wif.Factory)); + await context.app.resolve(CryptoWifServiceProvider).register(); - // context.factory = context.app.resolve(KeyPairFactory); + context.factory = context.app.resolve(KeyPairFactory); }); - it("#fromMnemonic - should derive a key pair", async ( { factory }) => { - // assert.equal(await factory.fromMnemonic(wallet.mnemonic), { - // compressed: true, - // privateKey: wallet.privateKey, - // publicKey: wallet.publicKey, - // }); - }); - - // each("#fromMnemonic - should derive a key pair", async ({ context: { factory }, dataset: wallet }) => { - // // assert.equal(await factory.fromMnemonic(wallet.mnemonic), { - // // compressed: true, - // // privateKey: wallet.privateKey, - // // publicKey: wallet.publicKey, - // // }); - // }, wallets); + each("#fromMnemonic - should derive a key pair", async ({ context: { factory }, dataset: wallet }) => { + assert.equal(await factory.fromMnemonic(wallet.mnemonic), { + compressed: true, + privateKey: wallet.privateKey, + publicKey: wallet.publicKey, + }); + }, wallets); - // each("#fromPrivateKey - should derive a key pair", async ({ context: { factory }, dataset: wallet }) => { - // assert.equal( - // await factory.fromPrivateKey( - // Buffer.from(wallet.privateKey, "hex"), - // ), - // { - // compressed: true, - // privateKey: wallet.privateKey, - // publicKey: wallet.publicKey, - // }, - // ); - // }, wallets); + each("#fromPrivateKey - should derive a key pair", async ({ context: { factory }, dataset: wallet }) => { + assert.equal( + await factory.fromPrivateKey( + Buffer.from(wallet.privateKey, "hex"), + ), + { + compressed: true, + privateKey: wallet.privateKey, + publicKey: wallet.publicKey, + }, + ); + }, wallets); - // each("#fromWIF - should derive a key pair from a WIF", async ({ context: { factory }, dataset: wallet }) => { - // assert.equal(await factory.fromWIF(wallet.wif), { - // compressed: true, - // privateKey: wallet.privateKey, - // publicKey: wallet.publicKey, - // }); - // }, wallets); + each("#fromWIF - should derive a key pair from a WIF", async ({ context: { factory }, dataset: wallet }) => { + assert.equal(await factory.fromWIF(wallet.wif), { + compressed: true, + privateKey: wallet.privateKey, + publicKey: wallet.publicKey, + }); + }, wallets); - // each("#fromWIF - should derive a key pair from a WIF 170", async ({ context: { factory }, dataset: wallet }) => { - // assert.equal(await factory.fromWIF(wallet.wif), { - // compressed: true, - // privateKey: wallet.privateKey, - // publicKey: wallet.publicKey, - // }); - // }, wallets); + each("#fromWIF - should derive a key pair from a WIF 170", async ({ context: { factory }, dataset: wallet }) => { + assert.equal(await factory.fromWIF(wallet.wif), { + compressed: true, + privateKey: wallet.privateKey, + publicKey: wallet.publicKey, + }); + }, wallets); }); diff --git a/packages/crypto-key-pair-ecdsa/source/pair.ts b/packages/crypto-key-pair-ecdsa/source/pair.ts index 2015a71b8b..d9114da9e6 100644 --- a/packages/crypto-key-pair-ecdsa/source/pair.ts +++ b/packages/crypto-key-pair-ecdsa/source/pair.ts @@ -6,8 +6,8 @@ import { secp256k1, SHA256 } from "bcrypto"; @injectable() export class KeyPairFactory implements Contracts.Crypto.KeyPairFactory { - @inject(Identifiers.Cryptography.Identity.Wif.Factory) - private readonly wifFactory!: Contracts.Crypto.WIFFactory; + @inject(Identifiers.Cryptography.Identity.Wif.Decoder) + private readonly wifDecoder!: Contracts.Crypto.WIFDecoder; public async fromMnemonic(mnemonic: string, compressed: boolean = true): Promise { return this.fromPrivateKey(SHA256.digest(Buffer.from(mnemonic, "utf8")), compressed); @@ -22,7 +22,7 @@ export class KeyPairFactory implements Contracts.Crypto.KeyPairFactory { } public async fromWIF(wif: string): Promise { - const decoded = await this.wifFactory.toPrivateKey(wif); + const decoded = await this.wifDecoder.toPrivateKey(wif); return this.fromPrivateKey(Buffer.from(decoded.privateKey, "hex"), decoded.compressed); } } diff --git a/packages/crypto-key-pair-ecdsa/source/private.test.ts b/packages/crypto-key-pair-ecdsa/source/private.test.ts index 217374e535..e7ed898b86 100644 --- a/packages/crypto-key-pair-ecdsa/source/private.test.ts +++ b/packages/crypto-key-pair-ecdsa/source/private.test.ts @@ -1,38 +1,43 @@ import { Application } from "@mainsail/kernel"; import { Identifiers } from "@mainsail/constants"; +import { Contracts } from "@mainsail/contracts"; import { ServiceProvider as ValidationServiceProvider } from "@mainsail/validation"; -import { Configuration } from "@mainsail/crypto-config"; +import { ServiceProvider as CryptoConfigServiceProvider } from "@mainsail/crypto-config"; +import { ServiceProvider as CryptoWifServiceProvider } from "@mainsail/crypto-wif"; import { describe } from "@mainsail/test-runner"; -import { KeyPairFactory } from "./pair"; +import { KeyPairFactory } from "./pair.js"; import { PrivateKeyFactory } from "./private"; +import { wallets } from "../../crypto-wif/test/index.js"; -const mnemonic = - "program fragile industry scare sun visit race erase daughter empty anxiety cereal cycle hunt airport educate giggle picture sunset apart jewel similar pulp moment"; +import cryptoJson from "../../core/bin/config/devnet/core/crypto.json"; describe<{ app: Application; factory: PrivateKeyFactory; -}>("PrivateKeyFactory", ({ assert, beforeEach, it }) => { +}>("PrivateKeyFactory", ({ assert, beforeEach, it, each }) => { beforeEach(async (context) => { context.app = new Application(); + context.app.get(Identifiers.Config.Repository).set("crypto", cryptoJson); await context.app.resolve(ValidationServiceProvider).register(); - context.app.bind(Identifiers.Cryptography.Configuration).to(Configuration).inSingletonScope(); + await context.app.resolve(CryptoConfigServiceProvider).register(); + await context.app.resolve(CryptoWifServiceProvider).register(); + context.app.bind(Identifiers.Cryptography.Identity.KeyPair.Factory).to(KeyPairFactory).inSingletonScope(); context.factory = context.app.resolve(PrivateKeyFactory); }); - it("should derive from an mnemonic", async ({ factory }) => { + each("should derive from an mnemonic", async ({ context: { factory }, dataset: wallet }) => { assert.is( - await factory.fromMnemonic(mnemonic), - "814857ce48e291893feab95df02e1dbf7ad3994ba46f247f77e4eefd5d8734a2", + await factory.fromMnemonic(wallet.mnemonic), + wallet.privateKey, ); - }); + }, wallets); - it("should derive from a WIF", async ({ factory }) => { + each("should derive from a WIF", async ({ context: { factory }, dataset: wallet }) => { assert.is( - await factory.fromWIF("KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"), - "0000000000000000000000000000000000000000000000000000000000000001", + await factory.fromWIF(wallet.wif), + wallet.privateKey, ); - }); + }, wallets); }); diff --git a/packages/crypto-key-pair-ecdsa/source/private.ts b/packages/crypto-key-pair-ecdsa/source/private.ts index ae46ad5f55..c3d89f2003 100644 --- a/packages/crypto-key-pair-ecdsa/source/private.ts +++ b/packages/crypto-key-pair-ecdsa/source/private.ts @@ -9,10 +9,12 @@ export class PrivateKeyFactory implements Contracts.Crypto.PrivateKeyFactory { private readonly keyPairFactory!: Contracts.Crypto.KeyPairFactory; public async fromMnemonic(mnemonic: string): Promise { - return (await this.keyPairFactory.fromMnemonic(mnemonic)).privateKey; + const { privateKey } = await this.keyPairFactory.fromMnemonic(mnemonic); + return privateKey; } public async fromWIF(wif: string): Promise { - return (await this.keyPairFactory.fromWIF(wif)).privateKey; + const { privateKey } = await this.keyPairFactory.fromWIF(wif); + return privateKey; } } diff --git a/packages/crypto-key-pair-ecdsa/source/public.test.ts b/packages/crypto-key-pair-ecdsa/source/public.test.ts index 5afe06fc65..c14f045dcd 100644 --- a/packages/crypto-key-pair-ecdsa/source/public.test.ts +++ b/packages/crypto-key-pair-ecdsa/source/public.test.ts @@ -1,12 +1,17 @@ import { Identifiers } from "@mainsail/constants"; -import { Configuration } from "@mainsail/crypto-config"; import { Application } from "@mainsail/kernel"; import * as Exceptions from "@mainsail/exceptions"; +import { Contracts } from "@mainsail/contracts"; import { ServiceProvider as ValidationServiceProvider } from "@mainsail/validation"; +import { ServiceProvider as CryptoConfigServiceProvider } from "@mainsail/crypto-config"; +import { ServiceProvider as CryptoWifServiceProvider } from "@mainsail/crypto-wif"; import { describe } from "@mainsail/test-runner"; import { KeyPairFactory } from "./pair"; import { PublicKeyFactory } from "./public"; +import { wallets } from "../../crypto-wif/test/index.js"; + +import cryptoJson from "../../core/bin/config/devnet/core/crypto.json"; const mnemonic = "program fragile industry scare sun visit race erase daughter empty anxiety cereal cycle hunt airport educate giggle picture sunset apart jewel similar pulp moment"; @@ -14,26 +19,28 @@ const mnemonic = describe<{ app: Application; factory: PublicKeyFactory }>("PrivateKeyFactory", ({ assert, beforeEach, each, it }) => { beforeEach(async (context) => { context.app = new Application(); + context.app.get(Identifiers.Config.Repository).set("crypto", cryptoJson); await context.app.resolve(ValidationServiceProvider).register(); - context.app.bind(Identifiers.Cryptography.Configuration).to(Configuration).inSingletonScope(); - context.app.bind(Identifiers.Cryptography.Identity.KeyPair.Factory).to(KeyPairFactory).inSingletonScope(); + await context.app.resolve(CryptoConfigServiceProvider).register(); + await context.app.resolve(CryptoWifServiceProvider).register(); + context.app.bind(Identifiers.Cryptography.Identity.KeyPair.Factory).to(KeyPairFactory).inSingletonScope(); context.factory = context.app.resolve(PublicKeyFactory); }); - it("should derive a key pair from an mnemonic", async ({ factory }) => { + each("should derive a key pair from an mnemonic", async ({ context: { factory }, dataset: wallet }) => { assert.is( - await factory.fromMnemonic(mnemonic), - "03e84093c072af70004a38dd95e34def119d2348d5261228175d032e5f2070e19f", + await factory.fromMnemonic(wallet.mnemonic), + wallet.publicKey, ); - }); + }, wallets); - it("should derive from a WIF", async ({ factory }) => { + each("should derive from a WIF", async ({ context: { factory }, dataset: wallet }) => { assert.is( - await factory.fromWIF("KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"), - "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", + await factory.fromWIF(wallet.wif), + wallet.publicKey, ); - }); + }, wallets); it("should derive from a musig", async ({ factory }) => { assert.is( @@ -109,7 +116,7 @@ describe<{ app: Application; factory: PublicKeyFactory }>("PrivateKeyFactory", ( "03c075494ad044ab8c0b2dc7ccd19f649db844a4e558e539d3ac2610c4b90a5139", "03aa98d2a27ef50e34f6882a089d0915edc0d21c2c7eedc9bf3323f8ca8c260531", "02d113acc492f613cfed6ec60fe31d0d0c1aa9787122070fb8dd76baf27f7a4766", - ], + ].concat(wallets.map((wallet) => wallet.publicKey)), ); each( diff --git a/packages/crypto-key-pair-ecdsa/source/public.ts b/packages/crypto-key-pair-ecdsa/source/public.ts index eedb9f684c..473f30b830 100644 --- a/packages/crypto-key-pair-ecdsa/source/public.ts +++ b/packages/crypto-key-pair-ecdsa/source/public.ts @@ -12,11 +12,13 @@ export class PublicKeyFactory implements Contracts.Crypto.PublicKeyFactory { private readonly keyPairFactory!: Contracts.Crypto.KeyPairFactory; public async fromMnemonic(mnemonic: string): Promise { - return (await this.keyPairFactory.fromMnemonic(mnemonic)).publicKey; + const { publicKey } = await this.keyPairFactory.fromMnemonic(mnemonic); + return publicKey; } public async fromWIF(wif: string): Promise { - return (await this.keyPairFactory.fromWIF(wif)).publicKey; + const { publicKey } = await this.keyPairFactory.fromWIF(wif); + return publicKey; } public async fromMultiSignatureAsset(asset: Contracts.Crypto.MultiSignatureAsset): Promise { diff --git a/packages/crypto-key-pair-ecdsa/source/schemas.test.ts b/packages/crypto-key-pair-ecdsa/source/schemas.test.ts index 2b7c3a5a7f..67014c3bf0 100644 --- a/packages/crypto-key-pair-ecdsa/source/schemas.test.ts +++ b/packages/crypto-key-pair-ecdsa/source/schemas.test.ts @@ -1,19 +1,18 @@ import { Identifiers } from "@mainsail/constants"; import { ServiceProvider as ValidationServiceProvider } from "@mainsail/validation"; import { ServiceProvider as CryptoConfigServiceProvider } from "@mainsail/crypto-config"; -import { generateMnemonic } from "bip39"; import cryptoJson from "../../core/bin/config/devnet/core/crypto.json"; import { Application } from "@mainsail/kernel"; import { describe } from "@mainsail/test-runner"; -import { KeyPairFactory } from "./pair"; import { schemas } from "./schemas"; import { Contracts } from "@mainsail/contracts"; +import { wallets } from "../../crypto-wif/test/index.js"; describe<{ app: Application; validator: Contracts.Crypto.Validator; -}>("Schemas", ({ it, assert, beforeEach }) => { +}>("Schemas", ({ it, assert, beforeEach, each }) => { const length = 66; beforeEach(async (context) => { @@ -31,7 +30,11 @@ describe<{ } }); - it("publicKey - should be ok", ({ validator }) => { + each("publicKey - should be ok", async ({ context: { validator }, dataset: wallet }) => { + assert.undefined(validator.validate("publicKey", wallet.publicKey).error); + }, wallets); + + it("publicKey - should be ok for valid chars", ({ validator }) => { assert.undefined(validator.validate("publicKey", "0".repeat(length)).error); const validChars = "0123456789abcdef"; @@ -41,12 +44,6 @@ describe<{ } }); - it("publicKey - should be ok from key pair factory", async (context) => { - const kayPair = await context.app.resolve(KeyPairFactory).fromMnemonic(generateMnemonic(256)); - - assert.undefined(context.validator.validate("publicKey", kayPair.publicKey).error); - }); - it("publicKey - should not be ok", ({ validator }) => { assert.defined(validator.validate("publicKey", "0".repeat(length - 1)).error); assert.defined(validator.validate("publicKey", "0".repeat(length + 1)).error); diff --git a/packages/crypto-key-pair-ecdsa/source/serializer.test.ts b/packages/crypto-key-pair-ecdsa/source/serializer.test.ts index ba0b13dd1c..0a1751cf1f 100644 --- a/packages/crypto-key-pair-ecdsa/source/serializer.test.ts +++ b/packages/crypto-key-pair-ecdsa/source/serializer.test.ts @@ -1,5 +1,3 @@ -import { Identifiers } from "@mainsail/constants"; -import { Configuration } from "@mainsail/crypto-config"; import { ByteBuffer } from "@mainsail/utils"; import { Buffer } from "buffer"; @@ -7,28 +5,25 @@ import { Application } from "@mainsail/kernel"; import { describe } from "@mainsail/test-runner"; import { PublicKeySerializer } from "./serializer"; +import { wallets } from "../../crypto-wif/test/index.js"; + describe<{ app: Application; serializer: PublicKeySerializer; -}>("AddressSerializer", ({ it, assert, beforeEach }) => { +}>("AddressSerializer", ({ it, assert, beforeEach, each }) => { beforeEach(async (context) => { context.app = new Application(); - - context.app.bind(Identifiers.Cryptography.Configuration).to(Configuration).inSingletonScope(); - context.serializer = context.app.resolve(PublicKeySerializer); }); - it("should serialize and deserialize address", async ({ serializer }) => { - const publicKey = "03e84093c072af70004a38dd95e34def119d2348d5261228175d032e5f2070e19f"; - + each("should serialize and deserialize address", async ({ context: { serializer }, dataset: wallet }) => { const byteBuffer = ByteBuffer.fromBuffer(Buffer.alloc(100)); - serializer.serialize(byteBuffer, publicKey); + serializer.serialize(byteBuffer, wallet.publicKey); byteBuffer.reset(); const readBuffer = serializer.deserialize(byteBuffer); - assert.equal(readBuffer.toString("hex"), publicKey); - }); + assert.equal(readBuffer.toString("hex"), wallet.publicKey); + }, wallets); }); diff --git a/packages/crypto-wif/source/decoder.test.ts b/packages/crypto-wif/source/decoder.test.ts new file mode 100644 index 0000000000..533aedc2e8 --- /dev/null +++ b/packages/crypto-wif/source/decoder.test.ts @@ -0,0 +1,42 @@ +import { Identifiers } from "@mainsail/constants"; +import { Contracts } from "@mainsail/contracts"; +import { ServiceProvider as ValidationServiceProvider } from "@mainsail/validation"; +import { ServiceProvider as CryptoConfigServiceProvider } from "@mainsail/crypto-config"; +import { KeyPairFactory } from "@mainsail/crypto-key-pair-ecdsa/source/pair"; +import { WifNetworkError } from "@mainsail/exceptions"; + +import { Application } from "@mainsail/kernel"; +import { describe } from "@mainsail/test-runner"; +import { wallets } from "../test/index.js"; +import { WIFDecoder } from "./decoder.js"; +import cryptoJson from "../../core/bin/config/devnet/core/crypto.json"; + +describe<{ + app: Application; + decoder: WIFDecoder; + configuration: Contracts.Crypto.Configuration; +}>("Identities - WIFFactory", ({ it, assert, beforeEach, each }) => { + beforeEach(async (context) => { + context.app = new Application(); + context.app.get(Identifiers.Config.Repository).set("crypto", cryptoJson); + await context.app.resolve(ValidationServiceProvider).register(); + await context.app.resolve(CryptoConfigServiceProvider).register(); + + context.configuration = context.app.get(Identifiers.Cryptography.Configuration); + context.decoder = context.app.resolve(WIFDecoder); + }); + + each("#toPrivateKey - should be OK", async ({ context: { decoder: factory }, dataset: wallet }) => { + assert.equal(await factory.toPrivateKey(wallet.wif), { compressed: true, privateKey: wallet.privateKey }); + }, wallets); + + each("#toPrivateKey - should be OK for WIF 170", async ({ context: { decoder: factory, configuration }, dataset: wallet }) => { + configuration.set("network.wif", 170); + assert.equal(await factory.toPrivateKey(wallet.wif170), { compressed: true, privateKey: wallet.privateKey }); + }, wallets); + + + each("#toPrivateKey - should throw on invalid WIF network version", async ({ context: { decoder: factory }, dataset: wallet }) => { + await assert.rejects(() => factory.toPrivateKey(wallet.wif170), WifNetworkError); + }, wallets); +}); From 04a54d0c49d410edfe0020a0047498ea5369eedf Mon Sep 17 00:00:00 2001 From: sebastijankuzner Date: Thu, 2 Apr 2026 19:06:26 +0000 Subject: [PATCH 13/22] Fix crypto-key-pair-bls12-381 --- .../crypto-key-pair-bls12-381/package.json | 1 + .../source/pair.test.ts | 40 ++++++++---------- .../crypto-key-pair-bls12-381/source/pair.ts | 34 ++++----------- .../source/private.test.ts | 30 ++++++------- .../source/private.ts | 6 ++- .../source/public.test.ts | 42 ++++++++++--------- .../source/public.ts | 5 ++- .../source/schemas.test.ts | 6 +-- .../source/serializer.test.ts | 19 ++++----- pnpm-lock.yaml | 3 ++ 10 files changed, 85 insertions(+), 101 deletions(-) diff --git a/packages/crypto-key-pair-bls12-381/package.json b/packages/crypto-key-pair-bls12-381/package.json index 22924cd3d8..248ba08c2a 100644 --- a/packages/crypto-key-pair-bls12-381/package.json +++ b/packages/crypto-key-pair-bls12-381/package.json @@ -37,6 +37,7 @@ "@mainsail/crypto-config": "workspace:*", "@mainsail/test-runner": "workspace:*", "@mainsail/validation": "workspace:*", + "@mainsail/crypto-wif": "workspace:*", "bip39": "3.1.0", "uvu": "0.5.6" }, diff --git a/packages/crypto-key-pair-bls12-381/source/pair.test.ts b/packages/crypto-key-pair-bls12-381/source/pair.test.ts index 6304789da0..00dc946641 100644 --- a/packages/crypto-key-pair-bls12-381/source/pair.test.ts +++ b/packages/crypto-key-pair-bls12-381/source/pair.test.ts @@ -1,56 +1,50 @@ import { Application } from "@mainsail/kernel"; import { Identifiers } from "@mainsail/constants"; import type { Contracts } from "@mainsail/contracts"; +import { NotImplemented } from "@mainsail/exceptions"; import { ServiceProvider as ValidationServiceProvider } from "@mainsail/validation"; import { ServiceProvider as CryptoConfigServiceProvider } from "@mainsail/crypto-config"; +import { ServiceProvider as CryptoWifServiceProvider } from "@mainsail/crypto-wif"; import cryptoJson from "../../core/bin/config/devnet/core/crypto.json"; import { describe } from "@mainsail/test-runner"; import { KeyPairFactory } from "./pair"; -const mnemonic = - "question measure debris increase false feature journey height fun agent coach office only shell nation skill track upset distance behave easy devote floor shy"; +import { wallets } from "../../crypto-wif/test/index.js"; -describe<{ app: Application; factory: KeyPairFactory }>("KeyPairFactory", ({ assert, beforeEach, it }) => { +describe<{ app: Application; factory: KeyPairFactory }>("KeyPairFactory", ({ assert, beforeEach, it, each }) => { beforeEach(async (context) => { context.app = new Application(); - context.app.get(Identifiers.Config.Repository).set("crypto", cryptoJson); await context.app.resolve(ValidationServiceProvider).register(); await context.app.resolve(CryptoConfigServiceProvider).register(); + await context.app.resolve(CryptoWifServiceProvider).register(); context.factory = context.app.resolve(KeyPairFactory); }); - it("should derive a key pair from an mnemonic", async ({ factory }) => { - assert.equal(await factory.fromMnemonic(mnemonic), { + each("#fromMnemonic - should derive a key pair from mnemonic", async ({ context: { factory }, dataset: wallet }) => { + assert.equal(await factory.fromMnemonic(wallet.mnemonic), { compressed: true, - privateKey: "3e99d30b3816f60077b1fdb4535ce0e9f9c715e42d1647edc3361fc531fb618f", - publicKey: - "b4865127896c3c5286296a7b26e7c8002586a3ecf5832bfb59e689336f1f4c75e10491b9dfaed8dfb2c2fbe22d11fa93", + privateKey: wallet.validatorPrivateKey, + publicKey: wallet.validatorPublicKey, }); - }); + }, wallets); - it("should derive a key pair from a private key", async ({ factory }) => { + each("#fromPrivateKey - should derive a key pair from a private key", async ({ context: { factory }, dataset: wallet }) => { assert.equal( await factory.fromPrivateKey( - Buffer.from("3e99d30b3816f60077b1fdb4535ce0e9f9c715e42d1647edc3361fc531fb618f", "hex"), + Buffer.from(wallet.validatorPrivateKey, "hex"), ), { compressed: true, - privateKey: "3e99d30b3816f60077b1fdb4535ce0e9f9c715e42d1647edc3361fc531fb618f", - publicKey: - "b4865127896c3c5286296a7b26e7c8002586a3ecf5832bfb59e689336f1f4c75e10491b9dfaed8dfb2c2fbe22d11fa93", + privateKey: wallet.validatorPrivateKey, + publicKey: wallet.validatorPublicKey, }, ); - }); + }, wallets); - it("should derive from a WIF", async ({ factory }) => { - assert.equal(await factory.fromWIF("UfDzkBsi7xxjq491zm5tk7rCZ1EouBXsFUWaCvQWxAortbh1zq5T"), { - compressed: true, - privateKey: "0000000000000000000000000000000000000000000000000000000000000001", - publicKey: - "97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", - }); + it("#fromWIF - should throw NotImplemented", async ({ factory }) => { + await assert.rejects(() => factory.fromWIF(""), NotImplemented); }); }); diff --git a/packages/crypto-key-pair-bls12-381/source/pair.ts b/packages/crypto-key-pair-bls12-381/source/pair.ts index 78150455b6..5e79ab98fa 100644 --- a/packages/crypto-key-pair-bls12-381/source/pair.ts +++ b/packages/crypto-key-pair-bls12-381/source/pair.ts @@ -1,46 +1,30 @@ import type { Contracts } from "@mainsail/contracts"; -import { Identifiers } from "@mainsail/constants"; -import { inject, injectable } from "@mainsail/container"; +import { injectable } from "@mainsail/container"; +import { NotImplemented } from "@mainsail/exceptions"; import { mnemonicToSeedSync } from "@scure/bip39"; import { deriveChild, deriveMaster } from "bls12-381-keygen"; -import { decode } from "wif"; import { getBls } from "./get-bls.js"; @injectable() export class KeyPairFactory implements Contracts.Crypto.KeyPairFactory { - @inject(Identifiers.Cryptography.Configuration) - private readonly configuration!: Contracts.Crypto.Configuration; - public async fromMnemonic(mnemonic: string): Promise { - return this.#fromPrivateKey(deriveChild(deriveMaster(mnemonicToSeedSync(mnemonic)), 0)); - } - - public async fromPrivateKey(privateKey: Buffer): Promise { - return this.#fromPrivateKey(privateKey); + return this.fromPrivateKey(Buffer.from(deriveChild(deriveMaster(mnemonicToSeedSync(mnemonic)), 0))); } - public async fromWIF(wif: string): Promise { + public async fromPrivateKey(privateKey: Buffer, compressed: boolean = true): Promise { const bls = await getBls(); - const decoded = decode(wif, this.configuration.get("network.wif")); - const privateKey = Buffer.from(decoded.privateKey); + const secretKey = bls.SecretKey.fromBytes(privateKey); return { - compressed: decoded.compressed, + compressed, privateKey: privateKey.toString("hex"), - publicKey: Buffer.from(bls.SecretKey.fromBytes(decoded.privateKey).toPublicKey().toBytes()).toString("hex"), + publicKey: Buffer.from(secretKey.toPublicKey().toBytes()).toString("hex"), }; } - async #fromPrivateKey(privateKey: Uint8Array): Promise { - const bls = await getBls(); - - const secretKey = bls.SecretKey.fromBytes(privateKey); - return { - compressed: true, - privateKey: Buffer.from(privateKey).toString("hex"), - publicKey: Buffer.from(secretKey.toPublicKey().toBytes()).toString("hex"), - }; + public async fromWIF(wif: string): Promise { + throw new NotImplemented(this.constructor.name, "fromWIF"); } } diff --git a/packages/crypto-key-pair-bls12-381/source/private.test.ts b/packages/crypto-key-pair-bls12-381/source/private.test.ts index 8b7eafb7e9..a6e664ce66 100644 --- a/packages/crypto-key-pair-bls12-381/source/private.test.ts +++ b/packages/crypto-key-pair-bls12-381/source/private.test.ts @@ -1,36 +1,38 @@ import { Application } from "@mainsail/kernel"; import { Identifiers } from "@mainsail/constants"; -import { Configuration } from "@mainsail/crypto-config"; +import type { Contracts } from "@mainsail/contracts"; +import { NotImplemented } from "@mainsail/exceptions"; import { ServiceProvider as ValidationServiceProvider } from "@mainsail/validation"; +import { ServiceProvider as CryptoConfigServiceProvider } from "@mainsail/crypto-config"; +import { ServiceProvider as CryptoWifServiceProvider } from "@mainsail/crypto-wif"; import { describe } from "@mainsail/test-runner"; import { KeyPairFactory } from "./pair"; import { PrivateKeyFactory } from "./private"; +import { wallets } from "../../crypto-wif/test/index.js"; -const mnemonic = - "program fragile industry scare sun visit race erase daughter empty anxiety cereal cycle hunt airport educate giggle picture sunset apart jewel similar pulp moment"; +import cryptoJson from "../../core/bin/config/devnet/core/crypto.json"; -describe<{ app: Application; factory: PrivateKeyFactory }>("PrivateKeyFactory", ({ assert, beforeEach, it }) => { +describe<{ app: Application; factory: PrivateKeyFactory }>("PrivateKeyFactory", ({ assert, beforeEach, it, each }) => { beforeEach(async (context) => { context.app = new Application(); + context.app.get(Identifiers.Config.Repository).set("crypto", cryptoJson); await context.app.resolve(ValidationServiceProvider).register(); - context.app.bind(Identifiers.Cryptography.Configuration).to(Configuration).inSingletonScope(); + await context.app.resolve(CryptoConfigServiceProvider).register(); + await context.app.resolve(CryptoWifServiceProvider).register(); context.app.bind(Identifiers.Cryptography.Identity.KeyPair.Factory).to(KeyPairFactory).inSingletonScope(); context.factory = context.app.resolve(PrivateKeyFactory); }); - it("should derive from an mnemonic", async ({ factory }) => { + each("#fromMnemonic - should derive from an mnemonic", async ({ context: { factory }, dataset: wallet }) => { assert.is( - await factory.fromMnemonic(mnemonic), - "6a0f42158b2412bc038076a9006acca5fd28f5a495479cdbe4117da0c2e18faf", + await factory.fromMnemonic(wallet.mnemonic), + wallet.validatorPrivateKey, ); - }); + }, wallets); - it("should derive from a WIF", async ({ factory }) => { - assert.is( - await factory.fromWIF("KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"), - "0000000000000000000000000000000000000000000000000000000000000001", - ); + it("#fromWIF - should throw NotImplemented", async ({ factory }) => { + await assert.rejects(() => factory.fromWIF(""), NotImplemented); }); }); diff --git a/packages/crypto-key-pair-bls12-381/source/private.ts b/packages/crypto-key-pair-bls12-381/source/private.ts index ae46ad5f55..390e6952e1 100644 --- a/packages/crypto-key-pair-bls12-381/source/private.ts +++ b/packages/crypto-key-pair-bls12-381/source/private.ts @@ -2,6 +2,7 @@ import type { Contracts } from "@mainsail/contracts"; import { Identifiers } from "@mainsail/constants"; import { inject, injectable } from "@mainsail/container"; +import { NotImplemented } from "@mainsail/exceptions"; @injectable() export class PrivateKeyFactory implements Contracts.Crypto.PrivateKeyFactory { @@ -9,10 +10,11 @@ export class PrivateKeyFactory implements Contracts.Crypto.PrivateKeyFactory { private readonly keyPairFactory!: Contracts.Crypto.KeyPairFactory; public async fromMnemonic(mnemonic: string): Promise { - return (await this.keyPairFactory.fromMnemonic(mnemonic)).privateKey; + const { privateKey } = await this.keyPairFactory.fromMnemonic(mnemonic); + return privateKey; } public async fromWIF(wif: string): Promise { - return (await this.keyPairFactory.fromWIF(wif)).privateKey; + throw new NotImplemented(this.constructor.name, "fromWIF"); } } diff --git a/packages/crypto-key-pair-bls12-381/source/public.test.ts b/packages/crypto-key-pair-bls12-381/source/public.test.ts index 7901aae1ea..d95e4d8559 100644 --- a/packages/crypto-key-pair-bls12-381/source/public.test.ts +++ b/packages/crypto-key-pair-bls12-381/source/public.test.ts @@ -1,57 +1,59 @@ import { Application } from "@mainsail/kernel"; import { Identifiers } from "@mainsail/constants"; -import * as Exceptions from "@mainsail/exceptions"; -import { Configuration } from "@mainsail/crypto-config"; +import { NotImplemented } from "@mainsail/exceptions"; +import type { Contracts } from "@mainsail/contracts"; import { ServiceProvider as ValidationServiceProvider } from "@mainsail/validation"; +import { ServiceProvider as CryptoConfigServiceProvider } from "@mainsail/crypto-config"; +import { ServiceProvider as CryptoWifServiceProvider } from "@mainsail/crypto-wif"; import { describe } from "@mainsail/test-runner"; import { KeyPairFactory } from "./pair"; import { PublicKeyFactory } from "./public"; +import { wallets } from "../../crypto-wif/test/index.js"; -const mnemonic = - "program fragile industry scare sun visit race erase daughter empty anxiety cereal cycle hunt airport educate giggle picture sunset apart jewel similar pulp moment"; +import cryptoJson from "../../core/bin/config/devnet/core/crypto.json"; describe<{ app: Application; factory: PublicKeyFactory }>("PublicKeyFactory", ({ assert, beforeEach, each, it }) => { beforeEach(async (context) => { context.app = new Application(); + context.app.get(Identifiers.Config.Repository).set("crypto", cryptoJson); await context.app.resolve(ValidationServiceProvider).register(); - context.app.bind(Identifiers.Cryptography.Configuration).to(Configuration).inSingletonScope(); + await context.app.resolve(CryptoConfigServiceProvider).register(); + await context.app.resolve(CryptoWifServiceProvider).register(); context.app.bind(Identifiers.Cryptography.Identity.KeyPair.Factory).to(KeyPairFactory).inSingletonScope(); context.factory = context.app.resolve(PublicKeyFactory); }); - it("should derive a key pair from an mnemonic", async ({ factory }) => { + each("#fromMnemonic -should derive a key pair from an mnemonic", async ({ context: { factory }, dataset: wallet }) => { assert.is( - await factory.fromMnemonic(mnemonic), - "95af988701a6fb60e09da41d2ca1a9e0b49e43501bda4255b3ca01073f490c34102b6bbcafde6333185e9980745d72cb", + await factory.fromMnemonic(wallet.mnemonic), + wallet.validatorPublicKey, ); - }); + }, wallets); - it("should derive from a WIF", async ({ factory }) => { - assert.is( - await factory.fromWIF("KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"), - "97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", - ); + + it("#fromWIF - should throw NotImplemented", async ({ factory }) => { + await assert.rejects(() => factory.fromWIF(""), NotImplemented); }); - it("should throw not implemented exception when deriving from a musig", async ({ factory }) => { - await assert.rejects(async () => factory.fromMultiSignatureAsset({} as any), Exceptions.NotImplemented); + it("#fromMultiSignatureAsset - should throw NotImplemented", async ({ factory }) => { + await assert.rejects(async () => factory.fromMultiSignatureAsset({} as any), NotImplemented); }); each( - "should pass with valid public keys", + "#verify - should pass with valid public keys", async ({ context, dataset }) => { assert.true(await context.factory.verify(dataset)); }, [ "95af988701a6fb60e09da41d2ca1a9e0b49e43501bda4255b3ca01073f490c34102b6bbcafde6333185e9980745d72cb", "97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", - ], + ].concat(wallets.map((wallet) => wallet.validatorPublicKey)), ); each( - "should fail with invalid public keys", + "#verify - should fail with invalid public keys", async ({ context, dataset }) => { assert.false(await context.factory.verify(dataset)); }, @@ -69,7 +71,7 @@ describe<{ app: Application; factory: PublicKeyFactory }>("PublicKeyFactory", ({ ], ); - it("should aggregate public keys", async ({ factory }) => { + it("#aggregate - should aggregate public keys", async ({ factory }) => { assert.equal( await factory.aggregate([ Buffer.from( diff --git a/packages/crypto-key-pair-bls12-381/source/public.ts b/packages/crypto-key-pair-bls12-381/source/public.ts index 5ec4fb00fc..edef37eec7 100644 --- a/packages/crypto-key-pair-bls12-381/source/public.ts +++ b/packages/crypto-key-pair-bls12-381/source/public.ts @@ -12,11 +12,12 @@ export class PublicKeyFactory implements Contracts.Crypto.PublicKeyFactory { private readonly keyPairFactory!: Contracts.Crypto.KeyPairFactory; public async fromMnemonic(mnemonic: string): Promise { - return (await this.keyPairFactory.fromMnemonic(mnemonic)).publicKey; + const { publicKey } = await this.keyPairFactory.fromMnemonic(mnemonic); + return publicKey; } public async fromWIF(wif: string): Promise { - return (await this.keyPairFactory.fromWIF(wif)).publicKey; + throw new NotImplemented(this.constructor.name, "fromWIF"); } public async fromMultiSignatureAsset(asset: Contracts.Crypto.MultiSignatureAsset): Promise { diff --git a/packages/crypto-key-pair-bls12-381/source/schemas.test.ts b/packages/crypto-key-pair-bls12-381/source/schemas.test.ts index c47b282f4b..6154149c07 100644 --- a/packages/crypto-key-pair-bls12-381/source/schemas.test.ts +++ b/packages/crypto-key-pair-bls12-381/source/schemas.test.ts @@ -30,7 +30,7 @@ describe<{ } }); - it("publicKey - should be ok", ({ validator }) => { + it("#consensusPublicKey - should be ok", ({ validator }) => { assert.undefined(validator.validate("consensusPublicKey", "0".repeat(length)).error); const validChars = "0123456789abcdef"; @@ -40,13 +40,13 @@ describe<{ } }); - it("publicKey - should be ok from key pair factory", async (context) => { + it("#consensusPublicKey - should be ok from key pair factory", async (context) => { const kayPair = await context.app.resolve(KeyPairFactory).fromMnemonic(generateMnemonic(256)); assert.undefined(context.validator.validate("consensusPublicKey", kayPair.publicKey).error); }); - it("publicKey - should not be ok", ({ validator }) => { + it("#consensusPublicKey - should not be ok", ({ validator }) => { assert.defined(validator.validate("consensusPublicKey", "0".repeat(length - 1)).error); assert.defined(validator.validate("consensusPublicKey", "0".repeat(length + 1)).error); assert.defined(validator.validate("consensusPublicKey", 123).error); diff --git a/packages/crypto-key-pair-bls12-381/source/serializer.test.ts b/packages/crypto-key-pair-bls12-381/source/serializer.test.ts index 3e9bd5ac05..6f6e6f82c9 100644 --- a/packages/crypto-key-pair-bls12-381/source/serializer.test.ts +++ b/packages/crypto-key-pair-bls12-381/source/serializer.test.ts @@ -1,5 +1,3 @@ -import { Identifiers } from "@mainsail/constants"; -import { Configuration } from "@mainsail/crypto-config"; import { ByteBuffer } from "@mainsail/utils"; import { Buffer } from "buffer"; @@ -7,29 +5,26 @@ import { Application } from "@mainsail/kernel"; import { describe } from "@mainsail/test-runner"; import { PublicKeySerializer } from "./serializer"; +import { wallets } from "../../crypto-wif/test/index.js"; + describe<{ app: Application; serializer: PublicKeySerializer; -}>("AddressSerializer", ({ it, assert, beforeEach }) => { +}>("AddressSerializer", ({ it, assert, beforeEach, each }) => { beforeEach(async (context) => { context.app = new Application(); - context.app.bind(Identifiers.Cryptography.Configuration).to(Configuration).inSingletonScope(); - context.serializer = context.app.resolve(PublicKeySerializer); }); - it("should serialize and deserialize address", async ({ serializer }) => { - const publicKey = - "95af988701a6fb60e09da41d2ca1a9e0b49e43501bda4255b3ca01073f490c34102b6bbcafde6333185e9980745d72cb"; - + each("#serialize - should serialize and deserialize address", async ({ context: { serializer }, dataset: wallet }) => { const byteBuffer = ByteBuffer.fromBuffer(Buffer.alloc(100)); - serializer.serialize(byteBuffer, publicKey); + serializer.serialize(byteBuffer, wallet.validatorPublicKey); byteBuffer.reset(); const readBuffer = serializer.deserialize(byteBuffer); - assert.equal(readBuffer.toString("hex"), publicKey); - }); + assert.equal(readBuffer.toString("hex"), wallet.validatorPublicKey); + }, wallets); }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 75a891f3d8..c50a2a4e5e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1542,6 +1542,9 @@ importers: '@mainsail/crypto-config': specifier: workspace:* version: link:../crypto-config + '@mainsail/crypto-wif': + specifier: workspace:* + version: link:../crypto-wif '@mainsail/test-runner': specifier: workspace:* version: link:../test-runner From d64867ca214064feba617404a3045f05df24b4ed Mon Sep 17 00:00:00 2001 From: sebastijankuzner Date: Thu, 2 Apr 2026 19:20:27 +0000 Subject: [PATCH 14/22] Remove decoder --- packages/constants/source/identifiers.ts | 1 - .../source/contracts/crypto/identities.ts | 7 ---- .../crypto-key-pair-ecdsa/source/pair.test.ts | 14 +++++-- packages/crypto-key-pair-ecdsa/source/pair.ts | 16 +++++-- .../source/private.test.ts | 2 - .../source/public.test.ts | 2 - packages/crypto-wif/source/decoder.test.ts | 42 ------------------- packages/crypto-wif/source/decoder.ts | 29 ------------- .../crypto-wif/source/service-provider.ts | 2 - 9 files changed, 22 insertions(+), 93 deletions(-) delete mode 100644 packages/crypto-wif/source/decoder.test.ts delete mode 100644 packages/crypto-wif/source/decoder.ts diff --git a/packages/constants/source/identifiers.ts b/packages/constants/source/identifiers.ts index c0eeceeab2..6fecd8ce9b 100644 --- a/packages/constants/source/identifiers.ts +++ b/packages/constants/source/identifiers.ts @@ -96,7 +96,6 @@ export const Identifiers = { Size: Symbol("Crypto"), }, Wif: { - Decoder: Symbol("Crypto"), Factory: Symbol("Crypto"), }, }, diff --git a/packages/contracts/source/contracts/crypto/identities.ts b/packages/contracts/source/contracts/crypto/identities.ts index 00af903f80..96312d8b3f 100644 --- a/packages/contracts/source/contracts/crypto/identities.ts +++ b/packages/contracts/source/contracts/crypto/identities.ts @@ -42,13 +42,6 @@ export interface WIFFactory { fromKeys(keys: KeyPair): Promise; } -export interface WIFDecoder { - toPrivateKey(wif: string): Promise<{ - compressed: boolean; - privateKey: string; - }>; -} - export interface AddressSerializer { serialize(buffer: ByteBuffer, address: Buffer): void; deserialize(buffer: ByteBuffer): Buffer; diff --git a/packages/crypto-key-pair-ecdsa/source/pair.test.ts b/packages/crypto-key-pair-ecdsa/source/pair.test.ts index a405d65836..88e33be90e 100644 --- a/packages/crypto-key-pair-ecdsa/source/pair.test.ts +++ b/packages/crypto-key-pair-ecdsa/source/pair.test.ts @@ -1,9 +1,9 @@ import { Application } from "@mainsail/kernel"; import { Identifiers } from "@mainsail/constants"; import { Contracts } from "@mainsail/contracts"; +import { WifNetworkError } from "@mainsail/exceptions"; import { ServiceProvider as ValidationServiceProvider } from "@mainsail/validation"; import { ServiceProvider as CryptoConfigServiceProvider } from "@mainsail/crypto-config"; -import { ServiceProvider as CryptoWifServiceProvider } from "@mainsail/crypto-wif"; import { describe } from "@mainsail/test-runner"; import { KeyPairFactory } from "./pair"; @@ -13,14 +13,15 @@ import cryptoJson from "../../core/bin/config/devnet/core/crypto.json"; describe<{ app: Application; factory: KeyPairFactory; + configuration: Contracts.Crypto.Configuration; }>("KeyPairFactory", ({ assert, beforeEach, it, each }) => { beforeEach(async (context) => { context.app = new Application(); context.app.get(Identifiers.Config.Repository).set("crypto", cryptoJson); await context.app.resolve(ValidationServiceProvider).register(); await context.app.resolve(CryptoConfigServiceProvider).register(); - await context.app.resolve(CryptoWifServiceProvider).register(); + context.configuration = context.app.get(Identifiers.Cryptography.Configuration); context.factory = context.app.resolve(KeyPairFactory); }); @@ -55,11 +56,16 @@ describe<{ }, wallets); - each("#fromWIF - should derive a key pair from a WIF 170", async ({ context: { factory }, dataset: wallet }) => { - assert.equal(await factory.fromWIF(wallet.wif), { + each("#fromWIF - should derive a key pair from a WIF 170", async ({ context: { factory, configuration }, dataset: wallet }) => { + configuration.set("network.wif", 170); + assert.equal(await factory.fromWIF(wallet.wif170), { compressed: true, privateKey: wallet.privateKey, publicKey: wallet.publicKey, }); }, wallets); + + each("#fromWIF - should derive a key pair from a WIF 170", async ({ context: { factory }, dataset: wallet }) => { + await assert.rejects(() => factory.fromWIF(wallet.wif170), WifNetworkError); + }, wallets); }); diff --git a/packages/crypto-key-pair-ecdsa/source/pair.ts b/packages/crypto-key-pair-ecdsa/source/pair.ts index d9114da9e6..71a20be010 100644 --- a/packages/crypto-key-pair-ecdsa/source/pair.ts +++ b/packages/crypto-key-pair-ecdsa/source/pair.ts @@ -2,12 +2,14 @@ import type { Contracts } from "@mainsail/contracts"; import { Identifiers } from "@mainsail/constants"; import { inject, injectable } from "@mainsail/container"; +import { WifNetworkError } from "@mainsail/exceptions"; import { secp256k1, SHA256 } from "bcrypto"; +import { decode } from "wif"; @injectable() export class KeyPairFactory implements Contracts.Crypto.KeyPairFactory { - @inject(Identifiers.Cryptography.Identity.Wif.Decoder) - private readonly wifDecoder!: Contracts.Crypto.WIFDecoder; + @inject(Identifiers.Cryptography.Configuration) + private readonly configuration!: Contracts.Crypto.Configuration; public async fromMnemonic(mnemonic: string, compressed: boolean = true): Promise { return this.fromPrivateKey(SHA256.digest(Buffer.from(mnemonic, "utf8")), compressed); @@ -22,7 +24,13 @@ export class KeyPairFactory implements Contracts.Crypto.KeyPairFactory { } public async fromWIF(wif: string): Promise { - const decoded = await this.wifDecoder.toPrivateKey(wif); - return this.fromPrivateKey(Buffer.from(decoded.privateKey, "hex"), decoded.compressed); + const networkVersion = this.configuration.get("network.wif") + const decoded = decode(wif); + + if (decoded.version !== networkVersion) { + throw new WifNetworkError(networkVersion, decoded.version); + } + + return this.fromPrivateKey(Buffer.from(decoded.privateKey), decoded.compressed); } } diff --git a/packages/crypto-key-pair-ecdsa/source/private.test.ts b/packages/crypto-key-pair-ecdsa/source/private.test.ts index e7ed898b86..105bbe6fe4 100644 --- a/packages/crypto-key-pair-ecdsa/source/private.test.ts +++ b/packages/crypto-key-pair-ecdsa/source/private.test.ts @@ -3,7 +3,6 @@ import { Identifiers } from "@mainsail/constants"; import { Contracts } from "@mainsail/contracts"; import { ServiceProvider as ValidationServiceProvider } from "@mainsail/validation"; import { ServiceProvider as CryptoConfigServiceProvider } from "@mainsail/crypto-config"; -import { ServiceProvider as CryptoWifServiceProvider } from "@mainsail/crypto-wif"; import { describe } from "@mainsail/test-runner"; import { KeyPairFactory } from "./pair.js"; @@ -21,7 +20,6 @@ describe<{ context.app.get(Identifiers.Config.Repository).set("crypto", cryptoJson); await context.app.resolve(ValidationServiceProvider).register(); await context.app.resolve(CryptoConfigServiceProvider).register(); - await context.app.resolve(CryptoWifServiceProvider).register(); context.app.bind(Identifiers.Cryptography.Identity.KeyPair.Factory).to(KeyPairFactory).inSingletonScope(); context.factory = context.app.resolve(PrivateKeyFactory); diff --git a/packages/crypto-key-pair-ecdsa/source/public.test.ts b/packages/crypto-key-pair-ecdsa/source/public.test.ts index c14f045dcd..1960d32f56 100644 --- a/packages/crypto-key-pair-ecdsa/source/public.test.ts +++ b/packages/crypto-key-pair-ecdsa/source/public.test.ts @@ -4,7 +4,6 @@ import * as Exceptions from "@mainsail/exceptions"; import { Contracts } from "@mainsail/contracts"; import { ServiceProvider as ValidationServiceProvider } from "@mainsail/validation"; import { ServiceProvider as CryptoConfigServiceProvider } from "@mainsail/crypto-config"; -import { ServiceProvider as CryptoWifServiceProvider } from "@mainsail/crypto-wif"; import { describe } from "@mainsail/test-runner"; import { KeyPairFactory } from "./pair"; @@ -22,7 +21,6 @@ describe<{ app: Application; factory: PublicKeyFactory }>("PrivateKeyFactory", ( context.app.get(Identifiers.Config.Repository).set("crypto", cryptoJson); await context.app.resolve(ValidationServiceProvider).register(); await context.app.resolve(CryptoConfigServiceProvider).register(); - await context.app.resolve(CryptoWifServiceProvider).register(); context.app.bind(Identifiers.Cryptography.Identity.KeyPair.Factory).to(KeyPairFactory).inSingletonScope(); context.factory = context.app.resolve(PublicKeyFactory); diff --git a/packages/crypto-wif/source/decoder.test.ts b/packages/crypto-wif/source/decoder.test.ts deleted file mode 100644 index 533aedc2e8..0000000000 --- a/packages/crypto-wif/source/decoder.test.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { Identifiers } from "@mainsail/constants"; -import { Contracts } from "@mainsail/contracts"; -import { ServiceProvider as ValidationServiceProvider } from "@mainsail/validation"; -import { ServiceProvider as CryptoConfigServiceProvider } from "@mainsail/crypto-config"; -import { KeyPairFactory } from "@mainsail/crypto-key-pair-ecdsa/source/pair"; -import { WifNetworkError } from "@mainsail/exceptions"; - -import { Application } from "@mainsail/kernel"; -import { describe } from "@mainsail/test-runner"; -import { wallets } from "../test/index.js"; -import { WIFDecoder } from "./decoder.js"; -import cryptoJson from "../../core/bin/config/devnet/core/crypto.json"; - -describe<{ - app: Application; - decoder: WIFDecoder; - configuration: Contracts.Crypto.Configuration; -}>("Identities - WIFFactory", ({ it, assert, beforeEach, each }) => { - beforeEach(async (context) => { - context.app = new Application(); - context.app.get(Identifiers.Config.Repository).set("crypto", cryptoJson); - await context.app.resolve(ValidationServiceProvider).register(); - await context.app.resolve(CryptoConfigServiceProvider).register(); - - context.configuration = context.app.get(Identifiers.Cryptography.Configuration); - context.decoder = context.app.resolve(WIFDecoder); - }); - - each("#toPrivateKey - should be OK", async ({ context: { decoder: factory }, dataset: wallet }) => { - assert.equal(await factory.toPrivateKey(wallet.wif), { compressed: true, privateKey: wallet.privateKey }); - }, wallets); - - each("#toPrivateKey - should be OK for WIF 170", async ({ context: { decoder: factory, configuration }, dataset: wallet }) => { - configuration.set("network.wif", 170); - assert.equal(await factory.toPrivateKey(wallet.wif170), { compressed: true, privateKey: wallet.privateKey }); - }, wallets); - - - each("#toPrivateKey - should throw on invalid WIF network version", async ({ context: { decoder: factory }, dataset: wallet }) => { - await assert.rejects(() => factory.toPrivateKey(wallet.wif170), WifNetworkError); - }, wallets); -}); diff --git a/packages/crypto-wif/source/decoder.ts b/packages/crypto-wif/source/decoder.ts deleted file mode 100644 index 52efbd6379..0000000000 --- a/packages/crypto-wif/source/decoder.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { Contracts } from "@mainsail/contracts"; - -import { Identifiers } from "@mainsail/constants"; -import { inject, injectable } from "@mainsail/container"; -import { WifNetworkError } from "@mainsail/exceptions"; -import { decode } from "wif"; - -@injectable() -export class WIFDecoder implements Contracts.Crypto.WIFDecoder { - @inject(Identifiers.Cryptography.Configuration) - private readonly configuration!: Contracts.Crypto.Configuration; - - public async toPrivateKey(wif: string): Promise<{ - compressed: boolean; - privateKey: string; - }> { - const networkVersion = this.configuration.get("network.wif") - const decoded = decode(wif); - - if (decoded.version !== networkVersion) { - throw new WifNetworkError(networkVersion, decoded.version); - } - - return { - compressed: decoded.compressed, - privateKey: Buffer.from(decoded.privateKey).toString("hex"), - } - } -} diff --git a/packages/crypto-wif/source/service-provider.ts b/packages/crypto-wif/source/service-provider.ts index 4e54968e97..9bf8e3d1ce 100644 --- a/packages/crypto-wif/source/service-provider.ts +++ b/packages/crypto-wif/source/service-provider.ts @@ -2,13 +2,11 @@ import { Identifiers } from "@mainsail/constants"; import { injectable } from "@mainsail/container"; import { Providers } from "@mainsail/kernel"; -import { WIFDecoder } from "./decoder.js"; import { WIFFactory } from "./wif.factory.js"; @injectable() export class ServiceProvider extends Providers.ServiceProvider { public async register(): Promise { this.app.bind(Identifiers.Cryptography.Identity.Wif.Factory).to(WIFFactory).inSingletonScope(); - this.app.bind(Identifiers.Cryptography.Identity.Wif.Decoder).to(WIFDecoder).inSingletonScope(); } } From e25bb2e0674864eb414ebe0ab3ec39286f8f5b95 Mon Sep 17 00:00:00 2001 From: sebastijankuzner Date: Thu, 2 Apr 2026 19:37:47 +0000 Subject: [PATCH 15/22] Test crypto-address-keccak256 --- .../source/address.factory.test.ts | 91 ++++++++++--------- .../source/schemas.test.ts | 6 +- .../source/serializer.test.ts | 21 ++--- 3 files changed, 59 insertions(+), 59 deletions(-) diff --git a/packages/crypto-address-keccak256/source/address.factory.test.ts b/packages/crypto-address-keccak256/source/address.factory.test.ts index 76c4a61b8a..48177953c0 100644 --- a/packages/crypto-address-keccak256/source/address.factory.test.ts +++ b/packages/crypto-address-keccak256/source/address.factory.test.ts @@ -1,88 +1,91 @@ import { Identifiers } from "@mainsail/constants"; -import { Configuration } from "@mainsail/crypto-config"; import { ServiceProvider as ECDSA } from "@mainsail/crypto-key-pair-ecdsa"; import { Application } from "@mainsail/kernel"; +import { Contracts } from "@mainsail/contracts"; import { ServiceProvider as ValidationServiceProvider } from "@mainsail/validation"; +import { ServiceProvider as CryptoConfigServiceProvider } from "@mainsail/crypto-config"; import { describe } from "@mainsail/test-runner"; import { AddressFactory } from "./address.factory"; -const mnemonic = "this is a top secret mnemonic"; -const wif = "UfDzkBsi7xxjq491zm5tk7rCZ1EouBXsFUWaCvQWxAortbh1zq5T"; +import { wallets } from "../../crypto-wif/test/index.js"; +import cryptoJson from "../../core/bin/config/devnet/core/crypto.json"; -describe<{ app: Application }>("AddressFactory", ({ assert, beforeEach, it }) => { +describe<{ app: Application, factory: AddressFactory }>("AddressFactory", ({ assert, beforeEach, it, each }) => { beforeEach(async (context) => { context.app = new Application(); - context.app.bind(Identifiers.Cryptography.Configuration).to(Configuration).inSingletonScope(); - + context.app.get(Identifiers.Config.Repository).set("crypto", cryptoJson); await context.app.resolve(ValidationServiceProvider).register(); + await context.app.resolve(CryptoConfigServiceProvider).register(); + await context.app.resolve(ECDSA).register(); - }); - it("should derive an address from an mnemonic", async (context) => { - assert.is( - await context.app.resolve(AddressFactory).fromMnemonic(mnemonic), - "0xE8F0d8418AF1cE7ADA59c02870FBF38C8909D8ac", - ); + context.factory = context.app.resolve(AddressFactory); }); - it("should derive an address from multi signature address", async (context) => { + each("#fromMnemonic - should derive an address from an mnemonic", async ({ context: { factory }, dataset: wallet}) => { assert.is( - await context.app.resolve(AddressFactory).fromMultiSignatureAsset({ - min: 3, - publicKeys: [ - "0235d486fea0193cbe77e955ab175b8f6eb9eaf784de689beffbd649989f5d6be3", - "03a46f2547d20b47003c1c376788db5a54d67264df2ae914f70bf453b6a1fa1b3a", - "03d7dfe44e771039334f4712fb95ad355254f674c8f5d286503199157b7bf7c357", - ], - }), - "0x970996B998f3C854D9a4D2C327Cc049ae6241C40", + await factory.fromMnemonic(wallet.mnemonic), + wallet.address, ); - }); + }, wallets); - it("should derive an address from a public key", async (context) => { + each("#fromPublicKey - should derive an address from a public key", async ({ context: { factory }, dataset: wallet}) => { assert.is( - await context.app - .resolve(AddressFactory) - .fromPublicKey("03e84093c072af70004a38dd95e34def119d2348d5261228175d032e5f2070e19f"), - "0xC7C50f33278bDe272ffe23865fF9fBd0155a5175", + await factory.fromPublicKey(wallet.publicKey), + wallet.address, ); - }); + }, wallets); - it("should throw if public key doesn't have 65 chars", async (context) => { + it("#fromPublicKey - should throw if public key doesn't have 65 chars", async ({ factory }) => { await assert.rejects( - () => context.app.resolve(AddressFactory).fromPublicKey("0".repeat(66 * 2)), + () => factory.fromPublicKey("0".repeat(66 * 2)), "Invalid uncompressed public key", ); }); - it("should throw if public key doesn't start with 0x04", async (context) => { + it("#fromPublicKey - should throw if public key doesn't start with 0x04", async ({ factory }) => { await assert.rejects( - () => context.app.resolve(AddressFactory).fromPublicKey("0".repeat(65 * 2)), + () => factory.fromPublicKey("0".repeat(65 * 2)), "Invalid uncompressed public key", ); }); - it("should derive an address from wif", async (context) => { - assert.is(await context.app.resolve(AddressFactory).fromWIF(wif), "0xE8F0d8418AF1cE7ADA59c02870FBF38C8909D8ac"); + each("#fromWIF - should derive an address from wif", async ({ context: { factory }, dataset: wallet}) => { + assert.is(await factory.fromWIF(wallet.wif), wallet.address); + }, wallets); + + it("#fromMultiSignatureAsset - should derive an address from multi signature address", async ({ factory }) => { + assert.is( + await factory.fromMultiSignatureAsset({ + min: 3, + publicKeys: [ + "0235d486fea0193cbe77e955ab175b8f6eb9eaf784de689beffbd649989f5d6be3", + "03a46f2547d20b47003c1c376788db5a54d67264df2ae914f70bf453b6a1fa1b3a", + "03d7dfe44e771039334f4712fb95ad355254f674c8f5d286503199157b7bf7c357", + ], + }), + "0x970996B998f3C854D9a4D2C327Cc049ae6241C40", + ); }); - it("should validate addresses", async (context) => { - assert.true(await context.app.resolve(AddressFactory).validate("0xC7C50f33278bDe272ffe23865fF9fBd0155a5175")); - assert.true(await context.app.resolve(AddressFactory).validate("0xC7C50f33278bDe272ffe23865fF9fBd0155a5175")); - assert.false(await context.app.resolve(AddressFactory).validate("0xC7C50f33278bde272ffe23865ff9fbd0155a5175")); + each("#validate - should be valid", async ({ context: { factory }, dataset: address}) => { + assert.true(await factory.validate(address)); + }, ["0xC7C50f33278bDe272ffe23865fF9fBd0155a5175", "0xC7C50f33278bDe272ffe23865fF9fBd0155a5175"].concat(wallets.map(wallet => wallet.address))); + + it("#validate - should be invalid", async ({ factory}) => { + assert.false(await factory.validate("0xC7C50f33278bde272ffe23865ff9fbd0155a5175")); assert.false( - await context.app - .resolve(AddressFactory) + await factory .validate("m0d1q05ypy7qw2hhqqz28rwetc6dauge6g6g65npy2qht5pjuheqwrse7gxkhwv"), ); }); - it("should convert from and to buffer", async (context) => { - const buffer = await context.app.resolve(AddressFactory).toBuffer("0xC7C50f33278bDe272ffe23865fF9fBd0155a5175"); + it("#toBuffer and #fromBuffer - should convert from and to buffer", async ({ factory }) => { + const buffer = await factory.toBuffer("0xC7C50f33278bDe272ffe23865fF9fBd0155a5175"); assert.equal(buffer.byteLength, 20); - const restored = await context.app.resolve(AddressFactory).fromBuffer(buffer); + const restored = await factory.fromBuffer(buffer); assert.equal(restored, "0xC7C50f33278bDe272ffe23865fF9fBd0155a5175"); }); }); diff --git a/packages/crypto-address-keccak256/source/schemas.test.ts b/packages/crypto-address-keccak256/source/schemas.test.ts index 1aa12ce1b1..5a7669c98f 100644 --- a/packages/crypto-address-keccak256/source/schemas.test.ts +++ b/packages/crypto-address-keccak256/source/schemas.test.ts @@ -31,7 +31,7 @@ describe<{ } }); - it("address - should be ok", ({ validator }) => { + it("#address - should be ok", ({ validator }) => { const prefix = "0x"; assert.undefined(validator.validate("address", prefix + "a".repeat(length - prefix.length)).error); @@ -43,7 +43,7 @@ describe<{ } }); - it("address - should be ok for factory", async (context) => { + it("#address - should be ok for factory", async (context) => { await context.app.resolve(ECDSA).register(); assert.undefined( @@ -54,7 +54,7 @@ describe<{ ); }); - it("address - should not be ok", ({ validator }) => { + it("#address - should not be ok", ({ validator }) => { const prefix = "0x"; const invalidPrefix = "1x"; diff --git a/packages/crypto-address-keccak256/source/serializer.test.ts b/packages/crypto-address-keccak256/source/serializer.test.ts index 78991aed76..5867bb96e1 100644 --- a/packages/crypto-address-keccak256/source/serializer.test.ts +++ b/packages/crypto-address-keccak256/source/serializer.test.ts @@ -1,7 +1,4 @@ import { Identifiers } from "@mainsail/constants"; -import { Configuration } from "@mainsail/crypto-config"; -import { ServiceProvider as ECDSA } from "@mainsail/crypto-key-pair-ecdsa"; -import { ServiceProvider as ValidationServiceProvider } from "@mainsail/validation"; import { ByteBuffer } from "@mainsail/utils"; import { Buffer } from "buffer"; @@ -10,25 +7,25 @@ import { describe } from "@mainsail/test-runner"; import { AddressFactory } from "./address.factory"; import { AddressSerializer } from "./serializer"; +import { wallets } from "../../crypto-wif/test/index.js"; + describe<{ app: Application; serializer: AddressSerializer; factory: AddressFactory; -}>("AddressSerializer", ({ it, assert, beforeEach }) => { +}>("AddressSerializer", ({ it, assert, beforeEach, each }) => { beforeEach(async (context) => { context.app = new Application(); - context.app.bind(Identifiers.Cryptography.Configuration).to(Configuration).inSingletonScope(); - await context.app.resolve(ValidationServiceProvider).register(); - await context.app.resolve(ECDSA).register(); + context.app.bind(Identifiers.Cryptography.Identity.KeyPair.Factory).toConstantValue({}); + context.app.bind(Identifiers.Cryptography.Identity.PublicKey.Factory).toConstantValue({}); context.serializer = context.app.resolve(AddressSerializer); context.factory = context.app.resolve(AddressFactory); }); - it("should serialize and deserialize address", async ({ factory, serializer }) => { - const address = "0xC7C50f33278bDe272ffe23865fF9fBd0155a5175"; - const buffer = await factory.toBuffer(address); + each("#serialize & #deserialize - should serialize and deserialize address", async ({ context: { factory, serializer }, dataset: wallet }) => { + const buffer = await factory.toBuffer(wallet.address); const byteBuffer = ByteBuffer.fromBuffer(Buffer.alloc(100)); @@ -37,6 +34,6 @@ describe<{ const readBuffer = serializer.deserialize(byteBuffer); - assert.equal(await factory.fromBuffer(readBuffer), address); - }); + assert.equal(await factory.fromBuffer(readBuffer), wallet.address); + }, wallets); }); From f20f1343e68eaef1bebeb746306fdec92ae22805 Mon Sep 17 00:00:00 2001 From: sebastijankuzner Date: Thu, 2 Apr 2026 19:43:32 +0000 Subject: [PATCH 16/22] Test crypto-address-base58 --- .../source/address.factory.test.ts | 49 ++++++++----------- .../source/schemas.test.ts | 6 +-- 2 files changed, 23 insertions(+), 32 deletions(-) diff --git a/packages/crypto-address-base58/source/address.factory.test.ts b/packages/crypto-address-base58/source/address.factory.test.ts index 610917724e..242dda351d 100644 --- a/packages/crypto-address-base58/source/address.factory.test.ts +++ b/packages/crypto-address-base58/source/address.factory.test.ts @@ -13,7 +13,7 @@ import { AddressFactory } from "./address.factory"; const mnemonic = "this is a top secret mnemonic"; const wif = "UfDzkBsi7xxjq491zm5tk7rCZ1EouBXsFUWaCvQWxAortbh1zq5T"; -describe<{ app: Application }>("AddressFactory", ({ assert, beforeEach, it }) => { +describe<{ app: Application, factory: AddressFactory }>("AddressFactory", ({ assert, beforeEach, it }) => { beforeEach(async (context) => { context.app = new Application(); context.app.get(Identifiers.Config.Repository).set("crypto", cryptoJson); @@ -22,18 +22,19 @@ describe<{ app: Application }>("AddressFactory", ({ assert, beforeEach, it }) => await context.app.resolve(ECDSA).register(); await context.app.resolve(CryptoHashBcrypto).register(); + context.factory = context.app.resolve(AddressFactory); }); - it("should derive an address from an mnemonic", async (context) => { + it("#fromMnemonic - should derive an address from an mnemonic", async ({ factory }) => { assert.is( - await context.app.resolve(AddressFactory).fromMnemonic(mnemonic), + await factory.fromMnemonic(mnemonic), "DLsMhiUzAVEXBXDTY1NGNZteWz8SDvphfa", ); }); - it("should derive an address from multi signature address", async (context) => { + it("#fromMultiSignatureAsset - should derive an address from multi signature address", async ({ factory }) => { assert.is( - await context.app.resolve(AddressFactory).fromMultiSignatureAsset({ + await factory.fromMultiSignatureAsset({ min: 3, publicKeys: [ "0235d486fea0193cbe77e955ab175b8f6eb9eaf784de689beffbd649989f5d6be3", @@ -45,55 +46,45 @@ describe<{ app: Application }>("AddressFactory", ({ assert, beforeEach, it }) => ); }); - it("should derive an address from a public key", async (context) => { + it("#fromPublicKey - should derive an address from a public key", async ({ factory }) => { assert.is( - await context.app - .resolve(AddressFactory) - .fromPublicKey("034151a3ec46b5670a682b0a63394f863587d1bc97483b1b6c70eb58e7f0aed192"), + await factory.fromPublicKey("034151a3ec46b5670a682b0a63394f863587d1bc97483b1b6c70eb58e7f0aed192"), "D61mfSggzbvQgTUe6JhYKH2doHaqJ3Dyib", ); }); - it("should derive an address from wif", async (context) => { - assert.is(await context.app.resolve(AddressFactory).fromWIF(wif), "DLsMhiUzAVEXBXDTY1NGNZteWz8SDvphfa"); + it("#fromWIF - should derive an address from wif", async ({ factory }) => { + assert.is(await factory.fromWIF(wif), "DLsMhiUzAVEXBXDTY1NGNZteWz8SDvphfa"); }); - it("should validate addresses", async (context) => { - assert.true(await context.app.resolve(AddressFactory).validate("DLsMhiUzAVEXBXDTY1NGNZteWz8SDvphfa")); + it("#validate - should validate addresses", async ({ factory }) => { + assert.true(await factory.validate("DLsMhiUzAVEXBXDTY1NGNZteWz8SDvphfa")); assert.false( - await context.app - .resolve(AddressFactory) - .validate("m0d1q05ypy7qw2hhqqz28rwetc6dauge6g6g65npy2qht5pjuheqwrse7gxkhwv"), + await factory.validate("m0d1q05ypy7qw2hhqqz28rwetc6dauge6g6g65npy2qht5pjuheqwrse7gxkhwv"), ); }); - it("should convert between buffer", async (context) => { - const addressFactory = context.app.resolve(AddressFactory); - + it("#toBuffer & #fromBuffer - should convert between buffer", async ({ factory }) => { assert.equal( - await addressFactory.fromBuffer(await addressFactory.toBuffer("DLsMhiUzAVEXBXDTY1NGNZteWz8SDvphfa")), + await factory.fromBuffer(await factory.toBuffer("DLsMhiUzAVEXBXDTY1NGNZteWz8SDvphfa")), "DLsMhiUzAVEXBXDTY1NGNZteWz8SDvphfa", ); }); - it("should throw if pubKeyHash doesn't match", async (context) => { - const addressFactory = context.app.resolve(AddressFactory); - - context.app + it("should throw if pubKeyHash doesn't match", async ({ factory, app }) => { + app .get(Identifiers.Cryptography.Configuration) .set("network.pubKeyHash", 44); await assert.rejects( - () => addressFactory.toBuffer("DLsMhiUzAVEXBXDTY1NGNZteWz8SDvphfa"), + () => factory.toBuffer("DLsMhiUzAVEXBXDTY1NGNZteWz8SDvphfa"), "Expected address network byte 44, but got 30.", ); }); - it("should throw invalid checksum", async (context) => { - const addressFactory = context.app.resolve(AddressFactory); - + it("#toBuffer - should throw invalid checksum", async ({ factory }) => { await assert.rejects( - () => addressFactory.toBuffer("E61mfSggzbvQgTUe6JhYKH2doHaqJ3Dyib"), + () => factory.toBuffer("E61mfSggzbvQgTUe6JhYKH2doHaqJ3Dyib"), "Invalid checksum for base58 string.", ); }); diff --git a/packages/crypto-address-base58/source/schemas.test.ts b/packages/crypto-address-base58/source/schemas.test.ts index 4fbdc30382..e10e2d8ff5 100644 --- a/packages/crypto-address-base58/source/schemas.test.ts +++ b/packages/crypto-address-base58/source/schemas.test.ts @@ -34,7 +34,7 @@ describe<{ } }); - it("address - should be ok", ({ validator }) => { + it("#legacyAddress - should be ok", ({ validator }) => { assert.undefined(validator.validate("legacyAddress", "a".repeat(length)).error); const validChars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; @@ -44,7 +44,7 @@ describe<{ } }); - it("address - should be ok for factory", async (context) => { + it("#legacyAddress - should be ok for factory", async (context) => { await context.app.resolve(ECDSA).register(); assert.undefined( @@ -55,7 +55,7 @@ describe<{ ); }); - it("address - should not be ok", ({ validator }) => { + it("#legacyAddress - should not be ok", ({ validator }) => { assert.defined(validator.validate("legacyAddress", "a".repeat(length - 2)).error); assert.defined(validator.validate("legacyAddress", "a".repeat(length + 1)).error); assert.defined(validator.validate("legacyAddress", 123).error); From 0f93ae7020fe09fb82147d377490a5e9aa02c44b Mon Sep 17 00:00:00 2001 From: sebastijankuzner Date: Thu, 2 Apr 2026 19:49:02 +0000 Subject: [PATCH 17/22] Fix wif tests --- packages/crypto-wif/source/service-provider.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/crypto-wif/source/service-provider.test.ts b/packages/crypto-wif/source/service-provider.test.ts index 1a4d5b65c0..a45d10d7d7 100644 --- a/packages/crypto-wif/source/service-provider.test.ts +++ b/packages/crypto-wif/source/service-provider.test.ts @@ -20,6 +20,5 @@ describe<{ await serviceProvider.register(); assert.true(app.isBound(Identifiers.Cryptography.Identity.Wif.Factory)); - assert.true(app.isBound(Identifiers.Cryptography.Identity.Wif.Decoder)); }); }); From bed810cc42c4275465c79f3dc8d142703a43f288 Mon Sep 17 00:00:00 2001 From: sebastijankuzner <58827427+sebastijankuzner@users.noreply.github.com> Date: Thu, 2 Apr 2026 19:51:57 +0000 Subject: [PATCH 18/22] style: resolve style guide violations [ci-lint-fix] --- .../source/address.factory.test.ts | 15 +--- .../source/address.factory.test.ts | 67 ++++++++------- .../source/serializer.test.ts | 20 +++-- .../crypto-key-pair-bls12-381/package.json | 2 +- .../source/pair.test.ts | 37 ++++---- .../source/private.test.ts | 15 ++-- .../source/public.test.ts | 16 ++-- .../source/serializer.test.ts | 18 ++-- packages/crypto-key-pair-ecdsa/package.json | 2 +- .../crypto-key-pair-ecdsa/source/pair.test.ts | 85 +++++++++++-------- packages/crypto-key-pair-ecdsa/source/pair.ts | 2 +- .../source/private.test.ts | 26 +++--- .../source/public.test.ts | 26 +++--- .../source/schemas.test.ts | 10 ++- .../source/serializer.test.ts | 18 ++-- packages/crypto-wif/package.json | 2 +- .../crypto-wif/source/wif.factory.test.ts | 75 ++++++++++------ packages/crypto-wif/source/wif.factory.ts | 4 +- packages/crypto-wif/test/identities.ts | 41 ++++----- 19 files changed, 268 insertions(+), 213 deletions(-) diff --git a/packages/crypto-address-base58/source/address.factory.test.ts b/packages/crypto-address-base58/source/address.factory.test.ts index 242dda351d..d5263d9400 100644 --- a/packages/crypto-address-base58/source/address.factory.test.ts +++ b/packages/crypto-address-base58/source/address.factory.test.ts @@ -13,7 +13,7 @@ import { AddressFactory } from "./address.factory"; const mnemonic = "this is a top secret mnemonic"; const wif = "UfDzkBsi7xxjq491zm5tk7rCZ1EouBXsFUWaCvQWxAortbh1zq5T"; -describe<{ app: Application, factory: AddressFactory }>("AddressFactory", ({ assert, beforeEach, it }) => { +describe<{ app: Application; factory: AddressFactory }>("AddressFactory", ({ assert, beforeEach, it }) => { beforeEach(async (context) => { context.app = new Application(); context.app.get(Identifiers.Config.Repository).set("crypto", cryptoJson); @@ -26,10 +26,7 @@ describe<{ app: Application, factory: AddressFactory }>("AddressFactory", ({ ass }); it("#fromMnemonic - should derive an address from an mnemonic", async ({ factory }) => { - assert.is( - await factory.fromMnemonic(mnemonic), - "DLsMhiUzAVEXBXDTY1NGNZteWz8SDvphfa", - ); + assert.is(await factory.fromMnemonic(mnemonic), "DLsMhiUzAVEXBXDTY1NGNZteWz8SDvphfa"); }); it("#fromMultiSignatureAsset - should derive an address from multi signature address", async ({ factory }) => { @@ -59,9 +56,7 @@ describe<{ app: Application, factory: AddressFactory }>("AddressFactory", ({ ass it("#validate - should validate addresses", async ({ factory }) => { assert.true(await factory.validate("DLsMhiUzAVEXBXDTY1NGNZteWz8SDvphfa")); - assert.false( - await factory.validate("m0d1q05ypy7qw2hhqqz28rwetc6dauge6g6g65npy2qht5pjuheqwrse7gxkhwv"), - ); + assert.false(await factory.validate("m0d1q05ypy7qw2hhqqz28rwetc6dauge6g6g65npy2qht5pjuheqwrse7gxkhwv")); }); it("#toBuffer & #fromBuffer - should convert between buffer", async ({ factory }) => { @@ -72,9 +67,7 @@ describe<{ app: Application, factory: AddressFactory }>("AddressFactory", ({ ass }); it("should throw if pubKeyHash doesn't match", async ({ factory, app }) => { - app - .get(Identifiers.Cryptography.Configuration) - .set("network.pubKeyHash", 44); + app.get(Identifiers.Cryptography.Configuration).set("network.pubKeyHash", 44); await assert.rejects( () => factory.toBuffer("DLsMhiUzAVEXBXDTY1NGNZteWz8SDvphfa"), diff --git a/packages/crypto-address-keccak256/source/address.factory.test.ts b/packages/crypto-address-keccak256/source/address.factory.test.ts index 48177953c0..f9c8c7d0a0 100644 --- a/packages/crypto-address-keccak256/source/address.factory.test.ts +++ b/packages/crypto-address-keccak256/source/address.factory.test.ts @@ -11,7 +11,7 @@ import { AddressFactory } from "./address.factory"; import { wallets } from "../../crypto-wif/test/index.js"; import cryptoJson from "../../core/bin/config/devnet/core/crypto.json"; -describe<{ app: Application, factory: AddressFactory }>("AddressFactory", ({ assert, beforeEach, it, each }) => { +describe<{ app: Application; factory: AddressFactory }>("AddressFactory", ({ assert, beforeEach, it, each }) => { beforeEach(async (context) => { context.app = new Application(); context.app.get(Identifiers.Config.Repository).set("crypto", cryptoJson); @@ -23,37 +23,37 @@ describe<{ app: Application, factory: AddressFactory }>("AddressFactory", ({ ass context.factory = context.app.resolve(AddressFactory); }); - each("#fromMnemonic - should derive an address from an mnemonic", async ({ context: { factory }, dataset: wallet}) => { - assert.is( - await factory.fromMnemonic(wallet.mnemonic), - wallet.address, - ); - }, wallets); + each( + "#fromMnemonic - should derive an address from an mnemonic", + async ({ context: { factory }, dataset: wallet }) => { + assert.is(await factory.fromMnemonic(wallet.mnemonic), wallet.address); + }, + wallets, + ); - each("#fromPublicKey - should derive an address from a public key", async ({ context: { factory }, dataset: wallet}) => { - assert.is( - await factory.fromPublicKey(wallet.publicKey), - wallet.address, - ); - }, wallets); + each( + "#fromPublicKey - should derive an address from a public key", + async ({ context: { factory }, dataset: wallet }) => { + assert.is(await factory.fromPublicKey(wallet.publicKey), wallet.address); + }, + wallets, + ); it("#fromPublicKey - should throw if public key doesn't have 65 chars", async ({ factory }) => { - await assert.rejects( - () => factory.fromPublicKey("0".repeat(66 * 2)), - "Invalid uncompressed public key", - ); + await assert.rejects(() => factory.fromPublicKey("0".repeat(66 * 2)), "Invalid uncompressed public key"); }); it("#fromPublicKey - should throw if public key doesn't start with 0x04", async ({ factory }) => { - await assert.rejects( - () => factory.fromPublicKey("0".repeat(65 * 2)), - "Invalid uncompressed public key", - ); + await assert.rejects(() => factory.fromPublicKey("0".repeat(65 * 2)), "Invalid uncompressed public key"); }); - each("#fromWIF - should derive an address from wif", async ({ context: { factory }, dataset: wallet}) => { - assert.is(await factory.fromWIF(wallet.wif), wallet.address); - }, wallets); + each( + "#fromWIF - should derive an address from wif", + async ({ context: { factory }, dataset: wallet }) => { + assert.is(await factory.fromWIF(wallet.wif), wallet.address); + }, + wallets, + ); it("#fromMultiSignatureAsset - should derive an address from multi signature address", async ({ factory }) => { assert.is( @@ -69,16 +69,19 @@ describe<{ app: Application, factory: AddressFactory }>("AddressFactory", ({ ass ); }); - each("#validate - should be valid", async ({ context: { factory }, dataset: address}) => { - assert.true(await factory.validate(address)); - }, ["0xC7C50f33278bDe272ffe23865fF9fBd0155a5175", "0xC7C50f33278bDe272ffe23865fF9fBd0155a5175"].concat(wallets.map(wallet => wallet.address))); + each( + "#validate - should be valid", + async ({ context: { factory }, dataset: address }) => { + assert.true(await factory.validate(address)); + }, + ["0xC7C50f33278bDe272ffe23865fF9fBd0155a5175", "0xC7C50f33278bDe272ffe23865fF9fBd0155a5175"].concat( + wallets.map((wallet) => wallet.address), + ), + ); - it("#validate - should be invalid", async ({ factory}) => { + it("#validate - should be invalid", async ({ factory }) => { assert.false(await factory.validate("0xC7C50f33278bde272ffe23865ff9fbd0155a5175")); - assert.false( - await factory - .validate("m0d1q05ypy7qw2hhqqz28rwetc6dauge6g6g65npy2qht5pjuheqwrse7gxkhwv"), - ); + assert.false(await factory.validate("m0d1q05ypy7qw2hhqqz28rwetc6dauge6g6g65npy2qht5pjuheqwrse7gxkhwv")); }); it("#toBuffer and #fromBuffer - should convert from and to buffer", async ({ factory }) => { diff --git a/packages/crypto-address-keccak256/source/serializer.test.ts b/packages/crypto-address-keccak256/source/serializer.test.ts index 5867bb96e1..340edcb0f2 100644 --- a/packages/crypto-address-keccak256/source/serializer.test.ts +++ b/packages/crypto-address-keccak256/source/serializer.test.ts @@ -24,16 +24,20 @@ describe<{ context.factory = context.app.resolve(AddressFactory); }); - each("#serialize & #deserialize - should serialize and deserialize address", async ({ context: { factory, serializer }, dataset: wallet }) => { - const buffer = await factory.toBuffer(wallet.address); + each( + "#serialize & #deserialize - should serialize and deserialize address", + async ({ context: { factory, serializer }, dataset: wallet }) => { + const buffer = await factory.toBuffer(wallet.address); - const byteBuffer = ByteBuffer.fromBuffer(Buffer.alloc(100)); + const byteBuffer = ByteBuffer.fromBuffer(Buffer.alloc(100)); - serializer.serialize(byteBuffer, buffer); - byteBuffer.reset(); + serializer.serialize(byteBuffer, buffer); + byteBuffer.reset(); - const readBuffer = serializer.deserialize(byteBuffer); + const readBuffer = serializer.deserialize(byteBuffer); - assert.equal(await factory.fromBuffer(readBuffer), wallet.address); - }, wallets); + assert.equal(await factory.fromBuffer(readBuffer), wallet.address); + }, + wallets, + ); }); diff --git a/packages/crypto-key-pair-bls12-381/package.json b/packages/crypto-key-pair-bls12-381/package.json index 248ba08c2a..1a78eca646 100644 --- a/packages/crypto-key-pair-bls12-381/package.json +++ b/packages/crypto-key-pair-bls12-381/package.json @@ -35,9 +35,9 @@ "devDependencies": { "@mainsail/contracts": "workspace:*", "@mainsail/crypto-config": "workspace:*", + "@mainsail/crypto-wif": "workspace:*", "@mainsail/test-runner": "workspace:*", "@mainsail/validation": "workspace:*", - "@mainsail/crypto-wif": "workspace:*", "bip39": "3.1.0", "uvu": "0.5.6" }, diff --git a/packages/crypto-key-pair-bls12-381/source/pair.test.ts b/packages/crypto-key-pair-bls12-381/source/pair.test.ts index 00dc946641..2e5cb46da9 100644 --- a/packages/crypto-key-pair-bls12-381/source/pair.test.ts +++ b/packages/crypto-key-pair-bls12-381/source/pair.test.ts @@ -23,28 +23,31 @@ describe<{ app: Application; factory: KeyPairFactory }>("KeyPairFactory", ({ ass context.factory = context.app.resolve(KeyPairFactory); }); - each("#fromMnemonic - should derive a key pair from mnemonic", async ({ context: { factory }, dataset: wallet }) => { - assert.equal(await factory.fromMnemonic(wallet.mnemonic), { - compressed: true, - privateKey: wallet.validatorPrivateKey, - publicKey: wallet.validatorPublicKey, - }); - }, wallets); + each( + "#fromMnemonic - should derive a key pair from mnemonic", + async ({ context: { factory }, dataset: wallet }) => { + assert.equal(await factory.fromMnemonic(wallet.mnemonic), { + compressed: true, + privateKey: wallet.validatorPrivateKey, + publicKey: wallet.validatorPublicKey, + }); + }, + wallets, + ); - each("#fromPrivateKey - should derive a key pair from a private key", async ({ context: { factory }, dataset: wallet }) => { - assert.equal( - await factory.fromPrivateKey( - Buffer.from(wallet.validatorPrivateKey, "hex"), - ), - { + each( + "#fromPrivateKey - should derive a key pair from a private key", + async ({ context: { factory }, dataset: wallet }) => { + assert.equal(await factory.fromPrivateKey(Buffer.from(wallet.validatorPrivateKey, "hex")), { compressed: true, privateKey: wallet.validatorPrivateKey, publicKey: wallet.validatorPublicKey, - }, - ); - }, wallets); + }); + }, + wallets, + ); - it("#fromWIF - should throw NotImplemented", async ({ factory }) => { + it("#fromWIF - should throw NotImplemented", async ({ factory }) => { await assert.rejects(() => factory.fromWIF(""), NotImplemented); }); }); diff --git a/packages/crypto-key-pair-bls12-381/source/private.test.ts b/packages/crypto-key-pair-bls12-381/source/private.test.ts index a6e664ce66..3772e6b416 100644 --- a/packages/crypto-key-pair-bls12-381/source/private.test.ts +++ b/packages/crypto-key-pair-bls12-381/source/private.test.ts @@ -25,14 +25,15 @@ describe<{ app: Application; factory: PrivateKeyFactory }>("PrivateKeyFactory", context.factory = context.app.resolve(PrivateKeyFactory); }); - each("#fromMnemonic - should derive from an mnemonic", async ({ context: { factory }, dataset: wallet }) => { - assert.is( - await factory.fromMnemonic(wallet.mnemonic), - wallet.validatorPrivateKey, - ); - }, wallets); + each( + "#fromMnemonic - should derive from an mnemonic", + async ({ context: { factory }, dataset: wallet }) => { + assert.is(await factory.fromMnemonic(wallet.mnemonic), wallet.validatorPrivateKey); + }, + wallets, + ); - it("#fromWIF - should throw NotImplemented", async ({ factory }) => { + it("#fromWIF - should throw NotImplemented", async ({ factory }) => { await assert.rejects(() => factory.fromWIF(""), NotImplemented); }); }); diff --git a/packages/crypto-key-pair-bls12-381/source/public.test.ts b/packages/crypto-key-pair-bls12-381/source/public.test.ts index d95e4d8559..338ce47787 100644 --- a/packages/crypto-key-pair-bls12-381/source/public.test.ts +++ b/packages/crypto-key-pair-bls12-381/source/public.test.ts @@ -25,15 +25,15 @@ describe<{ app: Application; factory: PublicKeyFactory }>("PublicKeyFactory", ({ context.factory = context.app.resolve(PublicKeyFactory); }); - each("#fromMnemonic -should derive a key pair from an mnemonic", async ({ context: { factory }, dataset: wallet }) => { - assert.is( - await factory.fromMnemonic(wallet.mnemonic), - wallet.validatorPublicKey, - ); - }, wallets); - + each( + "#fromMnemonic -should derive a key pair from an mnemonic", + async ({ context: { factory }, dataset: wallet }) => { + assert.is(await factory.fromMnemonic(wallet.mnemonic), wallet.validatorPublicKey); + }, + wallets, + ); - it("#fromWIF - should throw NotImplemented", async ({ factory }) => { + it("#fromWIF - should throw NotImplemented", async ({ factory }) => { await assert.rejects(() => factory.fromWIF(""), NotImplemented); }); diff --git a/packages/crypto-key-pair-bls12-381/source/serializer.test.ts b/packages/crypto-key-pair-bls12-381/source/serializer.test.ts index 6f6e6f82c9..82aa7b818d 100644 --- a/packages/crypto-key-pair-bls12-381/source/serializer.test.ts +++ b/packages/crypto-key-pair-bls12-381/source/serializer.test.ts @@ -17,14 +17,18 @@ describe<{ context.serializer = context.app.resolve(PublicKeySerializer); }); - each("#serialize - should serialize and deserialize address", async ({ context: { serializer }, dataset: wallet }) => { - const byteBuffer = ByteBuffer.fromBuffer(Buffer.alloc(100)); + each( + "#serialize - should serialize and deserialize address", + async ({ context: { serializer }, dataset: wallet }) => { + const byteBuffer = ByteBuffer.fromBuffer(Buffer.alloc(100)); - serializer.serialize(byteBuffer, wallet.validatorPublicKey); - byteBuffer.reset(); + serializer.serialize(byteBuffer, wallet.validatorPublicKey); + byteBuffer.reset(); - const readBuffer = serializer.deserialize(byteBuffer); + const readBuffer = serializer.deserialize(byteBuffer); - assert.equal(readBuffer.toString("hex"), wallet.validatorPublicKey); - }, wallets); + assert.equal(readBuffer.toString("hex"), wallet.validatorPublicKey); + }, + wallets, + ); }); diff --git a/packages/crypto-key-pair-ecdsa/package.json b/packages/crypto-key-pair-ecdsa/package.json index 8ee54f75d4..12ec0372c2 100644 --- a/packages/crypto-key-pair-ecdsa/package.json +++ b/packages/crypto-key-pair-ecdsa/package.json @@ -32,9 +32,9 @@ "devDependencies": { "@mainsail/contracts": "workspace:*", "@mainsail/crypto-config": "workspace:*", + "@mainsail/crypto-wif": "workspace:*", "@mainsail/test-runner": "workspace:*", "@mainsail/validation": "workspace:*", - "@mainsail/crypto-wif": "workspace:*", "bip39": "3.1.0", "uvu": "0.5.6" }, diff --git a/packages/crypto-key-pair-ecdsa/source/pair.test.ts b/packages/crypto-key-pair-ecdsa/source/pair.test.ts index 88e33be90e..b9ad442fa8 100644 --- a/packages/crypto-key-pair-ecdsa/source/pair.test.ts +++ b/packages/crypto-key-pair-ecdsa/source/pair.test.ts @@ -25,47 +25,60 @@ describe<{ context.factory = context.app.resolve(KeyPairFactory); }); - - each("#fromMnemonic - should derive a key pair", async ({ context: { factory }, dataset: wallet }) => { - assert.equal(await factory.fromMnemonic(wallet.mnemonic), { - compressed: true, - privateKey: wallet.privateKey, - publicKey: wallet.publicKey, - }); - }, wallets); - - each("#fromPrivateKey - should derive a key pair", async ({ context: { factory }, dataset: wallet }) => { - assert.equal( - await factory.fromPrivateKey( - Buffer.from(wallet.privateKey, "hex"), - ), - { + each( + "#fromMnemonic - should derive a key pair", + async ({ context: { factory }, dataset: wallet }) => { + assert.equal(await factory.fromMnemonic(wallet.mnemonic), { compressed: true, privateKey: wallet.privateKey, publicKey: wallet.publicKey, - }, - ); - }, wallets); + }); + }, + wallets, + ); - each("#fromWIF - should derive a key pair from a WIF", async ({ context: { factory }, dataset: wallet }) => { - assert.equal(await factory.fromWIF(wallet.wif), { - compressed: true, - privateKey: wallet.privateKey, - publicKey: wallet.publicKey, - }); - }, wallets); + each( + "#fromPrivateKey - should derive a key pair", + async ({ context: { factory }, dataset: wallet }) => { + assert.equal(await factory.fromPrivateKey(Buffer.from(wallet.privateKey, "hex")), { + compressed: true, + privateKey: wallet.privateKey, + publicKey: wallet.publicKey, + }); + }, + wallets, + ); + each( + "#fromWIF - should derive a key pair from a WIF", + async ({ context: { factory }, dataset: wallet }) => { + assert.equal(await factory.fromWIF(wallet.wif), { + compressed: true, + privateKey: wallet.privateKey, + publicKey: wallet.publicKey, + }); + }, + wallets, + ); - each("#fromWIF - should derive a key pair from a WIF 170", async ({ context: { factory, configuration }, dataset: wallet }) => { - configuration.set("network.wif", 170); - assert.equal(await factory.fromWIF(wallet.wif170), { - compressed: true, - privateKey: wallet.privateKey, - publicKey: wallet.publicKey, - }); - }, wallets); + each( + "#fromWIF - should derive a key pair from a WIF 170", + async ({ context: { factory, configuration }, dataset: wallet }) => { + configuration.set("network.wif", 170); + assert.equal(await factory.fromWIF(wallet.wif170), { + compressed: true, + privateKey: wallet.privateKey, + publicKey: wallet.publicKey, + }); + }, + wallets, + ); - each("#fromWIF - should derive a key pair from a WIF 170", async ({ context: { factory }, dataset: wallet }) => { - await assert.rejects(() => factory.fromWIF(wallet.wif170), WifNetworkError); - }, wallets); + each( + "#fromWIF - should derive a key pair from a WIF 170", + async ({ context: { factory }, dataset: wallet }) => { + await assert.rejects(() => factory.fromWIF(wallet.wif170), WifNetworkError); + }, + wallets, + ); }); diff --git a/packages/crypto-key-pair-ecdsa/source/pair.ts b/packages/crypto-key-pair-ecdsa/source/pair.ts index 71a20be010..03cd52ac4a 100644 --- a/packages/crypto-key-pair-ecdsa/source/pair.ts +++ b/packages/crypto-key-pair-ecdsa/source/pair.ts @@ -24,7 +24,7 @@ export class KeyPairFactory implements Contracts.Crypto.KeyPairFactory { } public async fromWIF(wif: string): Promise { - const networkVersion = this.configuration.get("network.wif") + const networkVersion = this.configuration.get("network.wif"); const decoded = decode(wif); if (decoded.version !== networkVersion) { diff --git a/packages/crypto-key-pair-ecdsa/source/private.test.ts b/packages/crypto-key-pair-ecdsa/source/private.test.ts index 105bbe6fe4..ab95355d7e 100644 --- a/packages/crypto-key-pair-ecdsa/source/private.test.ts +++ b/packages/crypto-key-pair-ecdsa/source/private.test.ts @@ -25,17 +25,19 @@ describe<{ context.factory = context.app.resolve(PrivateKeyFactory); }); - each("should derive from an mnemonic", async ({ context: { factory }, dataset: wallet }) => { - assert.is( - await factory.fromMnemonic(wallet.mnemonic), - wallet.privateKey, - ); - }, wallets); + each( + "should derive from an mnemonic", + async ({ context: { factory }, dataset: wallet }) => { + assert.is(await factory.fromMnemonic(wallet.mnemonic), wallet.privateKey); + }, + wallets, + ); - each("should derive from a WIF", async ({ context: { factory }, dataset: wallet }) => { - assert.is( - await factory.fromWIF(wallet.wif), - wallet.privateKey, - ); - }, wallets); + each( + "should derive from a WIF", + async ({ context: { factory }, dataset: wallet }) => { + assert.is(await factory.fromWIF(wallet.wif), wallet.privateKey); + }, + wallets, + ); }); diff --git a/packages/crypto-key-pair-ecdsa/source/public.test.ts b/packages/crypto-key-pair-ecdsa/source/public.test.ts index 1960d32f56..067507887c 100644 --- a/packages/crypto-key-pair-ecdsa/source/public.test.ts +++ b/packages/crypto-key-pair-ecdsa/source/public.test.ts @@ -26,19 +26,21 @@ describe<{ app: Application; factory: PublicKeyFactory }>("PrivateKeyFactory", ( context.factory = context.app.resolve(PublicKeyFactory); }); - each("should derive a key pair from an mnemonic", async ({ context: { factory }, dataset: wallet }) => { - assert.is( - await factory.fromMnemonic(wallet.mnemonic), - wallet.publicKey, - ); - }, wallets); + each( + "should derive a key pair from an mnemonic", + async ({ context: { factory }, dataset: wallet }) => { + assert.is(await factory.fromMnemonic(wallet.mnemonic), wallet.publicKey); + }, + wallets, + ); - each("should derive from a WIF", async ({ context: { factory }, dataset: wallet }) => { - assert.is( - await factory.fromWIF(wallet.wif), - wallet.publicKey, - ); - }, wallets); + each( + "should derive from a WIF", + async ({ context: { factory }, dataset: wallet }) => { + assert.is(await factory.fromWIF(wallet.wif), wallet.publicKey); + }, + wallets, + ); it("should derive from a musig", async ({ factory }) => { assert.is( diff --git a/packages/crypto-key-pair-ecdsa/source/schemas.test.ts b/packages/crypto-key-pair-ecdsa/source/schemas.test.ts index 67014c3bf0..b11daf64ae 100644 --- a/packages/crypto-key-pair-ecdsa/source/schemas.test.ts +++ b/packages/crypto-key-pair-ecdsa/source/schemas.test.ts @@ -30,9 +30,13 @@ describe<{ } }); - each("publicKey - should be ok", async ({ context: { validator }, dataset: wallet }) => { - assert.undefined(validator.validate("publicKey", wallet.publicKey).error); - }, wallets); + each( + "publicKey - should be ok", + async ({ context: { validator }, dataset: wallet }) => { + assert.undefined(validator.validate("publicKey", wallet.publicKey).error); + }, + wallets, + ); it("publicKey - should be ok for valid chars", ({ validator }) => { assert.undefined(validator.validate("publicKey", "0".repeat(length)).error); diff --git a/packages/crypto-key-pair-ecdsa/source/serializer.test.ts b/packages/crypto-key-pair-ecdsa/source/serializer.test.ts index 0a1751cf1f..d97817c6a5 100644 --- a/packages/crypto-key-pair-ecdsa/source/serializer.test.ts +++ b/packages/crypto-key-pair-ecdsa/source/serializer.test.ts @@ -16,14 +16,18 @@ describe<{ context.serializer = context.app.resolve(PublicKeySerializer); }); - each("should serialize and deserialize address", async ({ context: { serializer }, dataset: wallet }) => { - const byteBuffer = ByteBuffer.fromBuffer(Buffer.alloc(100)); + each( + "should serialize and deserialize address", + async ({ context: { serializer }, dataset: wallet }) => { + const byteBuffer = ByteBuffer.fromBuffer(Buffer.alloc(100)); - serializer.serialize(byteBuffer, wallet.publicKey); - byteBuffer.reset(); + serializer.serialize(byteBuffer, wallet.publicKey); + byteBuffer.reset(); - const readBuffer = serializer.deserialize(byteBuffer); + const readBuffer = serializer.deserialize(byteBuffer); - assert.equal(readBuffer.toString("hex"), wallet.publicKey); - }, wallets); + assert.equal(readBuffer.toString("hex"), wallet.publicKey); + }, + wallets, + ); }); diff --git a/packages/crypto-wif/package.json b/packages/crypto-wif/package.json index 89e87a5125..1d3882bc82 100644 --- a/packages/crypto-wif/package.json +++ b/packages/crypto-wif/package.json @@ -30,9 +30,9 @@ "@mainsail/contracts": "workspace:*", "@mainsail/crypto-config": "workspace:*", "@mainsail/crypto-key-pair-ecdsa": "workspace:*", + "@mainsail/exceptions": "workspace:*", "@mainsail/test-runner": "workspace:*", "@mainsail/validation": "workspace:*", - "@mainsail/exceptions": "workspace:*", "uvu": "0.5.6" }, "engines": { diff --git a/packages/crypto-wif/source/wif.factory.test.ts b/packages/crypto-wif/source/wif.factory.test.ts index 3c6c76ed61..26f9802476 100644 --- a/packages/crypto-wif/source/wif.factory.test.ts +++ b/packages/crypto-wif/source/wif.factory.test.ts @@ -21,7 +21,6 @@ describe<{ await context.app.resolve(ValidationServiceProvider).register(); await context.app.resolve(CryptoConfigServiceProvider).register(); - context.app.bind(Identifiers.Cryptography.Identity.Wif.Decoder).toConstantValue({}); context.app.bind(Identifiers.Cryptography.Identity.KeyPair.Factory).to(KeyPairFactory).inSingletonScope(); @@ -29,31 +28,51 @@ describe<{ context.factory = context.app.resolve(WIFFactory); }); - each("#fromMnemonic - should be OK", async ({ context: { factory }, dataset: wallet }) => { - assert.equal(await factory.fromMnemonic(wallet.mnemonic), wallet.wif); - }, wallets); - - each("#fromMnemonic - should be OK for WIF 170", async ({ context: { factory, configuration }, dataset: wallet }) => { - configuration.set("network.wif", 170); - assert.equal(await factory.fromMnemonic(wallet.mnemonic), wallet.wif170); - }, wallets); - - each("#fromKeys - should be OK", async ({ context: { factory, app }, dataset: wallet }) => { - assert.equal( - await factory.fromKeys( - await app.get(Identifiers.Cryptography.Identity.KeyPair.Factory).fromMnemonic(wallet.mnemonic), - ), - wallet.wif, - ); - }, wallets); - - each("#fromKeys - should be OK for WIF 170", async ({ context: { factory, app, configuration }, dataset: wallet }) => { - configuration.set("network.wif", 170); - assert.equal( - await factory.fromKeys( - await app.get(Identifiers.Cryptography.Identity.KeyPair.Factory).fromMnemonic(wallet.mnemonic), - ), - wallet.wif170, - ); - }, wallets); + each( + "#fromMnemonic - should be OK", + async ({ context: { factory }, dataset: wallet }) => { + assert.equal(await factory.fromMnemonic(wallet.mnemonic), wallet.wif); + }, + wallets, + ); + + each( + "#fromMnemonic - should be OK for WIF 170", + async ({ context: { factory, configuration }, dataset: wallet }) => { + configuration.set("network.wif", 170); + assert.equal(await factory.fromMnemonic(wallet.mnemonic), wallet.wif170); + }, + wallets, + ); + + each( + "#fromKeys - should be OK", + async ({ context: { factory, app }, dataset: wallet }) => { + assert.equal( + await factory.fromKeys( + await app + .get(Identifiers.Cryptography.Identity.KeyPair.Factory) + .fromMnemonic(wallet.mnemonic), + ), + wallet.wif, + ); + }, + wallets, + ); + + each( + "#fromKeys - should be OK for WIF 170", + async ({ context: { factory, app, configuration }, dataset: wallet }) => { + configuration.set("network.wif", 170); + assert.equal( + await factory.fromKeys( + await app + .get(Identifiers.Cryptography.Identity.KeyPair.Factory) + .fromMnemonic(wallet.mnemonic), + ), + wallet.wif170, + ); + }, + wallets, + ); }); diff --git a/packages/crypto-wif/source/wif.factory.ts b/packages/crypto-wif/source/wif.factory.ts index 831f6f6d18..7fd59292d9 100644 --- a/packages/crypto-wif/source/wif.factory.ts +++ b/packages/crypto-wif/source/wif.factory.ts @@ -36,7 +36,7 @@ export class WIFFactory implements Contracts.Crypto.WIFFactory { compressed: boolean; privateKey: string; }> { - const networkVersion = this.configuration.get("network.wif") + const networkVersion = this.configuration.get("network.wif"); const decoded = decode(wif); if (decoded.version !== networkVersion) { @@ -46,6 +46,6 @@ export class WIFFactory implements Contracts.Crypto.WIFFactory { return { compressed: decoded.compressed, privateKey: Buffer.from(decoded.privateKey).toString("hex"), - } + }; } } diff --git a/packages/crypto-wif/test/identities.ts b/packages/crypto-wif/test/identities.ts index 66b9f667da..411eb92614 100644 --- a/packages/crypto-wif/test/identities.ts +++ b/packages/crypto-wif/test/identities.ts @@ -1,24 +1,27 @@ export const wallet1 = { - address: '0x4DDA5269bC0D28c15006A75C6eaFb282138c71A6', - mnemonic: 'goddess laugh coin share picture napkin sausage surprise busy soft sting nothing drastic stove drive magic border amount symbol child swing peace book brass', - privateKey: 'ae9eac49907186760d8a1e2efa2a537adfa8333bfeddb0aaaa92fde6c86e4043', - publicKey: '02ffa9181f8ea9ea1ed85bed0ce53213367b5e8258b18cc745fa397ed40fa867fe', - validatorPrivateKey: '09dadae56492c1abd8453f393169fc2019c079b91369fe9f76d568e5964a69cf', - validatorPublicKey: '84b19d74a9bcb9d9e6c59b6114499820fba555884403120149a0041b892136141cbe08d929c5a4dfa18b881467da5d68', - wif: 'UchikoX1AAPyjNeLZRh975EAxuMPuC7Xz9gm9Zho1jSzuc6tN5JD', - wif170: 'SFRdcDkcMhjn96S3iDNrNHiNyx8xYVmuP5igCJAHA5PcQJwREvrR', -} - + address: "0x4DDA5269bC0D28c15006A75C6eaFb282138c71A6", + mnemonic: + "goddess laugh coin share picture napkin sausage surprise busy soft sting nothing drastic stove drive magic border amount symbol child swing peace book brass", + privateKey: "ae9eac49907186760d8a1e2efa2a537adfa8333bfeddb0aaaa92fde6c86e4043", + publicKey: "02ffa9181f8ea9ea1ed85bed0ce53213367b5e8258b18cc745fa397ed40fa867fe", + validatorPrivateKey: "09dadae56492c1abd8453f393169fc2019c079b91369fe9f76d568e5964a69cf", + validatorPublicKey: + "84b19d74a9bcb9d9e6c59b6114499820fba555884403120149a0041b892136141cbe08d929c5a4dfa18b881467da5d68", + wif: "UchikoX1AAPyjNeLZRh975EAxuMPuC7Xz9gm9Zho1jSzuc6tN5JD", + wif170: "SFRdcDkcMhjn96S3iDNrNHiNyx8xYVmuP5igCJAHA5PcQJwREvrR", +}; export const wallet2 = { - address: '0x3A6DfD8C942eE15fA9b2e17c10A4a38C6BC7d8d4', - mnemonic: 'desert belt subject reject digital flight topic frost decide juice run visa dilemma zoo jelly skirt play turtle soon globe solution vacant first mixture', - privateKey: 'd294208627305427225cf52485ce97c59c73ba178fdc0a0f8c96ad4152bd4a97', - publicKey: '02f032d4e5ee2c75029798ce50217eb403e55965daa3edcc1e9f4abdcccc025f54', - validatorPrivateKey: '59ef9225e0eba62a7c985061cef0bb48a82661c39901f7d3b142246912229100', - validatorPublicKey: 'b4ef04ddab942fbeee07ba6f657bfe2e6a01bdfbc2afb9b04ff2eb44cdf830f162cf6024bd417a97d62d476c9f93da6d', - wif: 'Uducumhc47DYcpxZYjJE8nNNkL3FbNA2vyxYMPW967FxBrAbS8Z4', - wif170: 'SGdXmBwDFeZM2YkGhWywPzramNppEfpQKuzTQ7xdETCZgYyu9ZyU', -} + address: "0x3A6DfD8C942eE15fA9b2e17c10A4a38C6BC7d8d4", + mnemonic: + "desert belt subject reject digital flight topic frost decide juice run visa dilemma zoo jelly skirt play turtle soon globe solution vacant first mixture", + privateKey: "d294208627305427225cf52485ce97c59c73ba178fdc0a0f8c96ad4152bd4a97", + publicKey: "02f032d4e5ee2c75029798ce50217eb403e55965daa3edcc1e9f4abdcccc025f54", + validatorPrivateKey: "59ef9225e0eba62a7c985061cef0bb48a82661c39901f7d3b142246912229100", + validatorPublicKey: + "b4ef04ddab942fbeee07ba6f657bfe2e6a01bdfbc2afb9b04ff2eb44cdf830f162cf6024bd417a97d62d476c9f93da6d", + wif: "Uducumhc47DYcpxZYjJE8nNNkL3FbNA2vyxYMPW967FxBrAbS8Z4", + wif170: "SGdXmBwDFeZM2YkGhWywPzramNppEfpQKuzTQ7xdETCZgYyu9ZyU", +}; export const wallets = [wallet1, wallet2]; From e53dafdcbece7cc9f01778901394ac2023760eba Mon Sep 17 00:00:00 2001 From: sebastijankuzner Date: Thu, 2 Apr 2026 19:55:54 +0000 Subject: [PATCH 19/22] Fix deps --- packages/crypto-key-pair-bls12-381/package.json | 3 +-- packages/crypto-key-pair-ecdsa/package.json | 2 +- pnpm-lock.yaml | 12 ------------ 3 files changed, 2 insertions(+), 15 deletions(-) diff --git a/packages/crypto-key-pair-bls12-381/package.json b/packages/crypto-key-pair-bls12-381/package.json index 1a78eca646..f520f07c47 100644 --- a/packages/crypto-key-pair-bls12-381/package.json +++ b/packages/crypto-key-pair-bls12-381/package.json @@ -29,8 +29,7 @@ "@mainsail/kernel": "workspace:*", "@mainsail/utils": "workspace:*", "@scure/bip39": "2.0.1", - "bls12-381-keygen": "0.2.4", - "wif": "5.0.0" + "bls12-381-keygen": "0.2.4" }, "devDependencies": { "@mainsail/contracts": "workspace:*", diff --git a/packages/crypto-key-pair-ecdsa/package.json b/packages/crypto-key-pair-ecdsa/package.json index 12ec0372c2..8ee54f75d4 100644 --- a/packages/crypto-key-pair-ecdsa/package.json +++ b/packages/crypto-key-pair-ecdsa/package.json @@ -32,9 +32,9 @@ "devDependencies": { "@mainsail/contracts": "workspace:*", "@mainsail/crypto-config": "workspace:*", - "@mainsail/crypto-wif": "workspace:*", "@mainsail/test-runner": "workspace:*", "@mainsail/validation": "workspace:*", + "@mainsail/crypto-wif": "workspace:*", "bip39": "3.1.0", "uvu": "0.5.6" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c50a2a4e5e..ef3e806fce 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1532,9 +1532,6 @@ importers: bls12-381-keygen: specifier: 0.2.4 version: 0.2.4 - wif: - specifier: 5.0.0 - version: 5.0.0 devDependencies: '@mainsail/contracts': specifier: workspace:* @@ -1588,18 +1585,12 @@ importers: '@mainsail/crypto-config': specifier: workspace:* version: link:../crypto-config - '@mainsail/crypto-wif': - specifier: workspace:* - version: link:../crypto-wif '@mainsail/test-runner': specifier: workspace:* version: link:../test-runner '@mainsail/validation': specifier: workspace:* version: link:../validation - bip39: - specifier: 3.1.0 - version: 3.1.0 uvu: specifier: 0.5.6 version: 0.5.6 @@ -1937,9 +1928,6 @@ importers: '@mainsail/crypto-key-pair-ecdsa': specifier: workspace:* version: link:../crypto-key-pair-ecdsa - '@mainsail/exceptions': - specifier: workspace:* - version: link:../exceptions '@mainsail/test-runner': specifier: workspace:* version: link:../test-runner From 4a3c230c106702efeb60bab9bafbdac709b029f1 Mon Sep 17 00:00:00 2001 From: sebastijankuzner Date: Thu, 2 Apr 2026 19:57:55 +0000 Subject: [PATCH 20/22] Lock file --- pnpm-lock.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ef3e806fce..82a7161632 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1585,12 +1585,18 @@ importers: '@mainsail/crypto-config': specifier: workspace:* version: link:../crypto-config + '@mainsail/crypto-wif': + specifier: workspace:* + version: link:../crypto-wif '@mainsail/test-runner': specifier: workspace:* version: link:../test-runner '@mainsail/validation': specifier: workspace:* version: link:../validation + bip39: + specifier: 3.1.0 + version: 3.1.0 uvu: specifier: 0.5.6 version: 0.5.6 @@ -1928,6 +1934,9 @@ importers: '@mainsail/crypto-key-pair-ecdsa': specifier: workspace:* version: link:../crypto-key-pair-ecdsa + '@mainsail/exceptions': + specifier: workspace:* + version: link:../exceptions '@mainsail/test-runner': specifier: workspace:* version: link:../test-runner From b4691a01d95cccb83654bebde529fe324731b40b Mon Sep 17 00:00:00 2001 From: sebastijankuzner Date: Thu, 2 Apr 2026 20:00:38 +0000 Subject: [PATCH 21/22] Fix deps --- packages/crypto-key-pair-ecdsa/package.json | 2 -- packages/crypto-wif/package.json | 1 - pnpm-lock.yaml | 9 --------- 3 files changed, 12 deletions(-) diff --git a/packages/crypto-key-pair-ecdsa/package.json b/packages/crypto-key-pair-ecdsa/package.json index 8ee54f75d4..5dd5489bea 100644 --- a/packages/crypto-key-pair-ecdsa/package.json +++ b/packages/crypto-key-pair-ecdsa/package.json @@ -34,8 +34,6 @@ "@mainsail/crypto-config": "workspace:*", "@mainsail/test-runner": "workspace:*", "@mainsail/validation": "workspace:*", - "@mainsail/crypto-wif": "workspace:*", - "bip39": "3.1.0", "uvu": "0.5.6" }, "engines": { diff --git a/packages/crypto-wif/package.json b/packages/crypto-wif/package.json index 1d3882bc82..b1fe009af2 100644 --- a/packages/crypto-wif/package.json +++ b/packages/crypto-wif/package.json @@ -30,7 +30,6 @@ "@mainsail/contracts": "workspace:*", "@mainsail/crypto-config": "workspace:*", "@mainsail/crypto-key-pair-ecdsa": "workspace:*", - "@mainsail/exceptions": "workspace:*", "@mainsail/test-runner": "workspace:*", "@mainsail/validation": "workspace:*", "uvu": "0.5.6" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 82a7161632..ef3e806fce 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1585,18 +1585,12 @@ importers: '@mainsail/crypto-config': specifier: workspace:* version: link:../crypto-config - '@mainsail/crypto-wif': - specifier: workspace:* - version: link:../crypto-wif '@mainsail/test-runner': specifier: workspace:* version: link:../test-runner '@mainsail/validation': specifier: workspace:* version: link:../validation - bip39: - specifier: 3.1.0 - version: 3.1.0 uvu: specifier: 0.5.6 version: 0.5.6 @@ -1934,9 +1928,6 @@ importers: '@mainsail/crypto-key-pair-ecdsa': specifier: workspace:* version: link:../crypto-key-pair-ecdsa - '@mainsail/exceptions': - specifier: workspace:* - version: link:../exceptions '@mainsail/test-runner': specifier: workspace:* version: link:../test-runner From 339b65cb5234ea0de9f2058822c6911dbff8b855 Mon Sep 17 00:00:00 2001 From: sebastijankuzner Date: Thu, 2 Apr 2026 20:04:25 +0000 Subject: [PATCH 22/22] Remove toPrivateKey --- packages/crypto-wif/source/wif.factory.ts | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/packages/crypto-wif/source/wif.factory.ts b/packages/crypto-wif/source/wif.factory.ts index 7fd59292d9..9ee8b35636 100644 --- a/packages/crypto-wif/source/wif.factory.ts +++ b/packages/crypto-wif/source/wif.factory.ts @@ -2,8 +2,7 @@ import type { Contracts } from "@mainsail/contracts"; import { Identifiers } from "@mainsail/constants"; import { inject, injectable, tagged } from "@mainsail/container"; -import { WifNetworkError } from "@mainsail/exceptions"; -import { encode, decode } from "wif"; +import { encode } from "wif"; @injectable() export class WIFFactory implements Contracts.Crypto.WIFFactory { @@ -31,21 +30,4 @@ export class WIFFactory implements Contracts.Crypto.WIFFactory { version: this.configuration.get("network.wif"), }); } - - public async toPrivateKey(wif: string): Promise<{ - compressed: boolean; - privateKey: string; - }> { - const networkVersion = this.configuration.get("network.wif"); - const decoded = decode(wif); - - if (decoded.version !== networkVersion) { - throw new WifNetworkError(networkVersion, decoded.version); - } - - return { - compressed: decoded.compressed, - privateKey: Buffer.from(decoded.privateKey).toString("hex"), - }; - } }