## ADDED Requirements ### Requirement: Pure-composition utility surface `@suaveplan/crypto-utils` SHALL expose encoding, byte, constant-time, and test-harness utilities that are safe to author from scratch (no field arithmetic, no secret-data side channels beyond constant-time equality). #### Scenario: Encoding utilities available - **WHEN** a consumer imports from `@suaveplan/crypto-utils` - **THEN** `hex`, `base64`, `base64url`, `base58` encoders/decoders are exported, each with `encode(bytes): string` and `decode(text): Uint8Array` - **AND** decoders throw a `SuaveplanError` subclass with stable code `CRYPTO.UTILS.INVALID_ENCODING` on malformed input #### Scenario: Byte utilities available - **WHEN** a consumer imports from `@suaveplan/crypto-utils` - **THEN** `concatBytes(...arrays: Uint8Array[]): Uint8Array`, `xor(a: Uint8Array, b: Uint8Array): Uint8Array`, `i2osp(n: bigint, len: number): Uint8Array`, `os2ip(bytes: Uint8Array): bigint` are exported #### Scenario: Constant-time, random, and zeroize utilities available - **WHEN** a consumer imports from `@suaveplan/crypto-utils` - **THEN** `constantTimeEqual(a: Uint8Array, b: Uint8Array): boolean` is exported and implemented without early return - **AND** `randomBytes(n: number): Uint8Array` is exported, sourcing from `globalThis.crypto.getRandomValues` - **AND** `zeroize(bytes: Uint8Array): void` is exported ### Requirement: Test-vector and fuzz harness `@suaveplan/crypto-utils` SHALL expose harness functions that `crypto-hash`, `crypto-curve`, and `crypto-cipher` use to run KATs and differential fuzz against their primitive impls. #### Scenario: KAT harness - **WHEN** a primitive test imports `runVectors` from `@suaveplan/crypto-utils/testing` - **THEN** it can pass a vector list and a set of impls, and receive a per-impl pass/fail/pending report - **AND** pending impls (throwing `PrimitiveNotImplemented`) are distinguished from failing impls #### Scenario: Differential fuzz harness - **WHEN** a primitive test imports `diffFuzz` from `@suaveplan/crypto-utils/testing` - **THEN** it can pass two impls, an input generator, and an iteration count, and receive a mismatch report - **AND** any byte-level divergence in outputs is reported with the reproducing input ### Requirement: Primitive id registry `@suaveplan/crypto-utils` SHALL export the `PrimitiveId` union type enumerating every hash, curve, and AEAD primitive across the crypto family, and a `PRIMITIVE_IDS` const array for runtime iteration. #### Scenario: Registry available - **WHEN** a consumer imports `PrimitiveId` and `PRIMITIVE_IDS` from `@suaveplan/crypto-utils/primitive-id` - **THEN** `PRIMITIVE_IDS` contains every id supported by `crypto-hash`, `crypto-curve`, and `crypto-cipher` - **AND** `PrimitiveId` narrows to the same union at compile time ### Requirement: No vendored code `@suaveplan/crypto-utils` SHALL contain only original code authored in this monorepo. No `src/vendored/` directory. #### Scenario: No vendored directory - **WHEN** the package tree is inspected - **THEN** no path matches `packages/universal/crypto-utils/src/vendored/**` ### Requirement: Merkle helpers `@suaveplan/crypto-utils` SHALL expose Merkle tree construction and inclusion-proof helpers generic over any hash primitive from `@suaveplan/crypto-hash`. #### Scenario: Merkle helpers available - **WHEN** a consumer imports `merkleRoot` and `merkleProof` from `@suaveplan/crypto-utils/merkle` - **THEN** they accept a hash function parameter and a list of leaves, returning a root and an inclusion proof respectively