diff --git a/packages/crypto-address-base58/source/address.factory.test.ts b/packages/crypto-address-base58/source/address.factory.test.ts index 8074acc9d7..d5263d9400 100644 --- a/packages/crypto-address-base58/source/address.factory.test.ts +++ b/packages/crypto-address-base58/source/address.factory.test.ts @@ -10,32 +10,28 @@ 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 }) => { +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); 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(); + context.factory = context.app.resolve(AddressFactory); }); - it("should derive an address from an mnemonic", async (context) => { - assert.is( - await context.app.resolve(AddressFactory).fromMnemonic(mnemonic), - "D61mfSggzbvQgTUe6JhYKH2doHaqJ3Dyib", - ); + it("#fromMnemonic - should derive an address from an mnemonic", async ({ factory }) => { + assert.is(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", @@ -47,55 +43,41 @@ 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), "D61mfSggzbvQgTUe6JhYKH2doHaqJ3Dyib"); + 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("D61mfSggzbvQgTUe6JhYKH2doHaqJ3Dyib")); - assert.false( - await context.app - .resolve(AddressFactory) - .validate("m0d1q05ypy7qw2hhqqz28rwetc6dauge6g6g65npy2qht5pjuheqwrse7gxkhwv"), - ); + it("#validate - should validate addresses", async ({ factory }) => { + assert.true(await factory.validate("DLsMhiUzAVEXBXDTY1NGNZteWz8SDvphfa")); + assert.false(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("D61mfSggzbvQgTUe6JhYKH2doHaqJ3Dyib")), - "D61mfSggzbvQgTUe6JhYKH2doHaqJ3Dyib", + 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 - .get(Identifiers.Cryptography.Configuration) - .set("network.pubKeyHash", 44); + 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("D61mfSggzbvQgTUe6JhYKH2doHaqJ3Dyib"), + () => 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); diff --git a/packages/crypto-address-keccak256/source/address.factory.test.ts b/packages/crypto-address-keccak256/source/address.factory.test.ts index fb95cbe334..f9c8c7d0a0 100644 --- a/packages/crypto-address-keccak256/source/address.factory.test.ts +++ b/packages/crypto-address-keccak256/source/address.factory.test.ts @@ -1,36 +1,63 @@ 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 = - "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 { wallets } from "../../crypto-wif/test/index.js"; +import cryptoJson from "../../core/bin/config/devnet/core/crypto.json"; -const wif = "SDuW66dyGZ1zPZdN7ncEevbJdjaQTj9pT4LcmKzQ7eLFoyCXEdkx"; - -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(); + + context.factory = context.app.resolve(AddressFactory); }); - it("should derive an address from an mnemonic", async (context) => { - assert.is( - await context.app.resolve(AddressFactory).fromMnemonic(mnemonic), - "0xC7C50f33278bDe272ffe23865fF9fBd0155a5175", - ); + 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, + ); + + 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"); + }); + + 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"); }); - it("should derive an address from multi signature address", async (context) => { + 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 context.app.resolve(AddressFactory).fromMultiSignatureAsset({ + await factory.fromMultiSignatureAsset({ min: 3, publicKeys: [ "0235d486fea0193cbe77e955ab175b8f6eb9eaf784de689beffbd649989f5d6be3", @@ -42,49 +69,26 @@ describe<{ app: Application }>("AddressFactory", ({ assert, beforeEach, it }) => ); }); - it("should derive an address from a public key", async (context) => { - assert.is( - await context.app - .resolve(AddressFactory) - .fromPublicKey("03e84093c072af70004a38dd95e34def119d2348d5261228175d032e5f2070e19f"), - "0xC7C50f33278bDe272ffe23865fF9fBd0155a5175", - ); - }); - - it("should throw if public key doesn't have 65 chars", async (context) => { - await assert.rejects( - () => context.app.resolve(AddressFactory).fromPublicKey("0".repeat(66 * 2)), - "Invalid uncompressed public key", - ); - }); + 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("should throw if public key doesn't start with 0x04", async (context) => { - await assert.rejects( - () => context.app.resolve(AddressFactory).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), "0xC7C50f33278bDe272ffe23865fF9fBd0155a5175"); - }); - - 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")); - assert.false( - await context.app - .resolve(AddressFactory) - .validate("m0d1q05ypy7qw2hhqqz28rwetc6dauge6g6g65npy2qht5pjuheqwrse7gxkhwv"), - ); + it("#validate - should be invalid", async ({ factory }) => { + assert.false(await factory.validate("0xC7C50f33278bde272ffe23865ff9fbd0155a5175")); + assert.false(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..340edcb0f2 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,33 +7,37 @@ 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)); + 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), address); - }); + 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 22924cd3d8..f520f07c47 100644 --- a/packages/crypto-key-pair-bls12-381/package.json +++ b/packages/crypto-key-pair-bls12-381/package.json @@ -29,12 +29,12 @@ "@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:*", "@mainsail/crypto-config": "workspace:*", + "@mainsail/crypto-wif": "workspace:*", "@mainsail/test-runner": "workspace:*", "@mainsail/validation": "workspace:*", "bip39": "3.1.0", 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..2e5cb46da9 100644 --- a/packages/crypto-key-pair-bls12-381/source/pair.test.ts +++ b/packages/crypto-key-pair-bls12-381/source/pair.test.ts @@ -1,52 +1,53 @@ 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 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(); - context.app.bind(Identifiers.Cryptography.Configuration).to(Configuration).inSingletonScope(); + 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), { - compressed: true, - privateKey: "3e99d30b3816f60077b1fdb4535ce0e9f9c715e42d1647edc3361fc531fb618f", - publicKey: - "b4865127896c3c5286296a7b26e7c8002586a3ecf5832bfb59e689336f1f4c75e10491b9dfaed8dfb2c2fbe22d11fa93", - }); - }); + 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, + ); - it("should derive a key pair from an mnemonic", async ({ factory }) => { - assert.equal( - await factory.fromPrivateKey( - Buffer.from("3e99d30b3816f60077b1fdb4535ce0e9f9c715e42d1647edc3361fc531fb618f", "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: "3e99d30b3816f60077b1fdb4535ce0e9f9c715e42d1647edc3361fc531fb618f", - publicKey: - "b4865127896c3c5286296a7b26e7c8002586a3ecf5832bfb59e689336f1f4c75e10491b9dfaed8dfb2c2fbe22d11fa93", - }, - ); - }); + privateKey: wallet.validatorPrivateKey, + publicKey: wallet.validatorPublicKey, + }); + }, + wallets, + ); - it("should derive from a WIF", async ({ factory }) => { - assert.equal(await factory.fromWIF("KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"), { - 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..3772e6b416 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,39 @@ 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 }) => { - assert.is( - await factory.fromMnemonic(mnemonic), - "6a0f42158b2412bc038076a9006acca5fd28f5a495479cdbe4117da0c2e18faf", - ); - }); + each( + "#fromMnemonic - should derive from an mnemonic", + async ({ context: { factory }, dataset: wallet }) => { + assert.is(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..338ce47787 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 }) => { - assert.is( - await factory.fromMnemonic(mnemonic), - "95af988701a6fb60e09da41d2ca1a9e0b49e43501bda4255b3ca01073f490c34102b6bbcafde6333185e9980745d72cb", - ); - }); + 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("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..82aa7b818d 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,30 @@ 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)); - const byteBuffer = ByteBuffer.fromBuffer(Buffer.alloc(100)); + serializer.serialize(byteBuffer, wallet.validatorPublicKey); + byteBuffer.reset(); - serializer.serialize(byteBuffer, publicKey); - byteBuffer.reset(); + const readBuffer = serializer.deserialize(byteBuffer); - const readBuffer = serializer.deserialize(byteBuffer); - - assert.equal(readBuffer.toString("hex"), publicKey); - }); + 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 de47247863..5dd5489bea 100644 --- a/packages/crypto-key-pair-ecdsa/package.json +++ b/packages/crypto-key-pair-ecdsa/package.json @@ -34,7 +34,6 @@ "@mainsail/crypto-config": "workspace:*", "@mainsail/test-runner": "workspace:*", "@mainsail/validation": "workspace:*", - "bip39": "3.1.0", "uvu": "0.5.6" }, "engines": { diff --git a/packages/crypto-key-pair-ecdsa/source/pair.test.ts b/packages/crypto-key-pair-ecdsa/source/pair.test.ts index bef53d37ec..b9ad442fa8 100644 --- a/packages/crypto-key-pair-ecdsa/source/pair.test.ts +++ b/packages/crypto-key-pair-ecdsa/source/pair.test.ts @@ -1,52 +1,84 @@ import { Application } from "@mainsail/kernel"; import { Identifiers } from "@mainsail/constants"; -import { Configuration } from "@mainsail/crypto-config"; +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 { 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 { wallets } from "../../crypto-wif/test/index.js"; +import cryptoJson from "../../core/bin/config/devnet/core/crypto.json"; describe<{ app: Application; factory: KeyPairFactory; -}>("KeyPairFactory", ({ assert, beforeEach, it }) => { + 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(); - context.app.bind(Identifiers.Cryptography.Configuration).to(Configuration).inSingletonScope(); + await context.app.resolve(CryptoConfigServiceProvider).register(); + context.configuration = context.app.get(Identifiers.Cryptography.Configuration); context.factory = context.app.resolve(KeyPairFactory); }); - it("should derive a key pair from an mnemonic", async ({ factory }) => { - assert.equal(await factory.fromMnemonic(mnemonic), { - compressed: true, - privateKey: "814857ce48e291893feab95df02e1dbf7ad3994ba46f247f77e4eefd5d8734a2", - publicKey: "03e84093c072af70004a38dd95e34def119d2348d5261228175d032e5f2070e19f", - }); - }); + 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, + ); - it("should derive a key pair from an mnemonic", async ({ factory }) => { - assert.equal( - await factory.fromPrivateKey( - Buffer.from("814857ce48e291893feab95df02e1dbf7ad3994ba46f247f77e4eefd5d8734a2", "hex"), - ), - { + 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: "814857ce48e291893feab95df02e1dbf7ad3994ba46f247f77e4eefd5d8734a2", - publicKey: "03e84093c072af70004a38dd95e34def119d2348d5261228175d032e5f2070e19f", - }, - ); - }); + privateKey: wallet.privateKey, + publicKey: wallet.publicKey, + }); + }, + wallets, + ); - it("should derive from a WIF", async ({ factory }) => { - assert.equal(await factory.fromWIF("KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"), { - compressed: true, - privateKey: "0000000000000000000000000000000000000000000000000000000000000001", - publicKey: "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", - }); - }); + 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 }, 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 c90754abac..03cd52ac4a 100644 --- a/packages/crypto-key-pair-ecdsa/source/pair.ts +++ b/packages/crypto-key-pair-ecdsa/source/pair.ts @@ -2,6 +2,7 @@ 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"; @@ -23,13 +24,13 @@ 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); + const networkVersion = this.configuration.get("network.wif"); + const decoded = decode(wif); - return { - compressed: decoded.compressed, - privateKey: privateKey.toString("hex"), - publicKey: secp256k1.publicKeyCreate(privateKey, decoded.compressed).toString("hex"), - }; + 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 217374e535..ab95355d7e 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 { 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(); + 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 }) => { - assert.is( - await factory.fromMnemonic(mnemonic), - "814857ce48e291893feab95df02e1dbf7ad3994ba46f247f77e4eefd5d8734a2", - ); - }); + each( + "should derive from an mnemonic", + async ({ context: { factory }, dataset: wallet }) => { + assert.is(await factory.fromMnemonic(wallet.mnemonic), wallet.privateKey); + }, + wallets, + ); - it("should derive from a WIF", async ({ factory }) => { - assert.is( - await factory.fromWIF("KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"), - "0000000000000000000000000000000000000000000000000000000000000001", - ); - }); + 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/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..067507887c 100644 --- a/packages/crypto-key-pair-ecdsa/source/public.test.ts +++ b/packages/crypto-key-pair-ecdsa/source/public.test.ts @@ -1,12 +1,16 @@ 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 { 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 +18,29 @@ 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(); + 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 }) => { - assert.is( - await factory.fromMnemonic(mnemonic), - "03e84093c072af70004a38dd95e34def119d2348d5261228175d032e5f2070e19f", - ); - }); + each( + "should derive a key pair from an mnemonic", + async ({ context: { factory }, dataset: wallet }) => { + assert.is(await factory.fromMnemonic(wallet.mnemonic), wallet.publicKey); + }, + wallets, + ); - it("should derive from a WIF", async ({ factory }) => { - assert.is( - await factory.fromWIF("KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"), - "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", - ); - }); + 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( @@ -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..b11daf64ae 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,15 @@ 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 +48,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..d97817c6a5 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,29 @@ 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)); - const byteBuffer = ByteBuffer.fromBuffer(Buffer.alloc(100)); + serializer.serialize(byteBuffer, wallet.publicKey); + byteBuffer.reset(); - serializer.serialize(byteBuffer, publicKey); - byteBuffer.reset(); + const readBuffer = serializer.deserialize(byteBuffer); - 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/wif.factory.test.ts b/packages/crypto-wif/source/wif.factory.test.ts index 794358e556..26f9802476 100644 --- a/packages/crypto-wif/source/wif.factory.test.ts +++ b/packages/crypto-wif/source/wif.factory.test.ts @@ -6,37 +6,73 @@ 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 { wallets } from "../test/index.js"; import { WIFFactory } from "./wif.factory"; import cryptoJson from "../../core/bin/config/devnet/core/crypto.json"; describe<{ app: Application; factory: WIFFactory; -}>("Identities - WIFFactory", ({ it, assert, beforeEach }) => { + 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.app.get(Identifiers.Cryptography.Configuration).set("network.wif", 170); - + 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); 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("#fromKeys - should be OK", async ({ factory, app }) => { - assert.equal( - await factory.fromKeys( - await app.get(Identifiers.Cryptography.Identity.KeyPair.Factory).fromMnemonic(mnemonic), - ), - wif, - ); - }); + 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/test/identities.ts b/packages/crypto-wif/test/identities.ts new file mode 100644 index 0000000000..411eb92614 --- /dev/null +++ b/packages/crypto-wif/test/identities.ts @@ -0,0 +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", +}; + +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 ba29cfedc9..0000000000 --- a/packages/crypto-wif/test/identity.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "wif": "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"; 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 - } -} 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..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:* @@ -1542,6 +1539,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 @@ -1591,9 +1591,6 @@ importers: '@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