diff --git a/src/__tests__/address.test.ts b/src/__tests__/address.test.ts new file mode 100644 index 0000000..1beace7 --- /dev/null +++ b/src/__tests__/address.test.ts @@ -0,0 +1,32 @@ +import { describe, expect, it } from "vitest"; +import { deriveAddress, isValidAddress } from "../address.js"; +import { CurveType } from "../types.js"; + +describe("deriveAddress", () => { + it("derives addresses for valid public key sizes", () => { + const publicKeys = [ + ["11".repeat(32), CurveType.ED25519], + ["22".repeat(48), CurveType.BLS12381], + ["02" + "33".repeat(32), CurveType.SECP256K1], + ["44".repeat(64), CurveType.ETHSECP256K1], + ["04" + "55".repeat(64), CurveType.ETHSECP256K1], + ] as const; + + for (const [publicKey, curveType] of publicKeys) { + expect(isValidAddress(deriveAddress(publicKey, curveType))).toBe(true); + } + }); + + it("rejects public keys with invalid sizes", () => { + const invalidPublicKeys = [ + ["11".repeat(31), CurveType.ED25519], + ["22".repeat(47), CurveType.BLS12381], + ["33".repeat(32), CurveType.SECP256K1], + ["44".repeat(63), CurveType.ETHSECP256K1], + ] as const; + + for (const [publicKey, curveType] of invalidPublicKeys) { + expect(() => deriveAddress(publicKey, curveType)).toThrow("public key size"); + } + }); +}); \ No newline at end of file diff --git a/src/address.ts b/src/address.ts index 5549ea9..170e84d 100644 --- a/src/address.ts +++ b/src/address.ts @@ -4,11 +4,39 @@ import { keccak_256 } from "@noble/hashes/sha3.js"; import { hexToBytes, bytesToHex } from "@noble/hashes/utils.js"; import { CurveType, KEY_SIZES } from "./types.js"; +function assertPublicKeySize(curveType: CurveType, length: number): void { + switch (curveType) { + case CurveType.ED25519: + if (length !== KEY_SIZES.PUBLIC.ED25519) { + throw new Error(`Invalid ED25519 public key size: ${length}`); + } + return; + case CurveType.BLS12381: + if (length !== KEY_SIZES.PUBLIC.BLS12381) { + throw new Error(`Invalid BLS12381 public key size: ${length}`); + } + return; + case CurveType.SECP256K1: + if (length !== KEY_SIZES.PUBLIC.SECP256K1) { + throw new Error(`Invalid SECP256K1 public key size: ${length}`); + } + return; + case CurveType.ETHSECP256K1: + if (length !== KEY_SIZES.PUBLIC.ETHSECP256K1 && length !== 65) { + throw new Error(`Invalid ETHSECP256K1 public key size: ${length}`); + } + return; + default: + return; + } +} + export function deriveAddress( publicKeyHex: string, curveType: CurveType ): string { const pubKeyBytes = hexToBytes(publicKeyHex); + assertPublicKeySize(curveType, pubKeyBytes.length); switch (curveType) { case CurveType.ED25519: {