Initial Commit

This commit is contained in:
2026-05-27 23:47:53 +01:00
parent fbc70f96e6
commit 9b28db724f
18103 changed files with 1600554 additions and 0 deletions

View File

@@ -0,0 +1,55 @@
# Hex encoding
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
Convert between `Uint8Array` byte buffers and lowercase hexadecimal strings. Hex is the canonical human-readable representation of cryptographic material (digests, public keys, nonces) because every byte maps to exactly two characters with no ambiguity or padding. This module re-exports `bytesToHex` and `hexToBytes` from `@suaveplan/bytes` under the crypto-friendly names `toHex` / `fromHex`, ensuring every `@suaveplan/crypto-*` package produces byte-for-byte identical output and rejects malformed input with a stable error code.
## Features
- `toHex(bytes)` — lowercase, no `0x` prefix; delegates to `@suaveplan/bytes`.
- `fromHex(hex)` — accepts both upper and lower case; rejects odd length or non-hex characters.
- Throws `BytesError(BYTES.ENCODE.INVALID_HEX)` on malformed input (from `@suaveplan/bytes`).
- Zero implementation code in this module — pure delegation ensures a single source of truth.
## Usage: Basic Example
```ts
import { fromHex, toHex } from "@suaveplan/crypto-utils/encoding";
const digest = new Uint8Array([0xde, 0xad, 0xbe, 0xef]);
const s = toHex(digest); // "deadbeef"
const back = fromHex(s); // Uint8Array([0xde, 0xad, 0xbe, 0xef])
```
## Usage: Advanced Example
```ts
import { fromHex, toHex } from "@suaveplan/crypto-utils/encoding";
import { BytesError } from "@suaveplan/bytes";
function parseDigest(input: string): Uint8Array {
try {
return fromHex(input.trim().replace(/^0x/, ""));
} catch (err) {
if (err instanceof BytesError) {
throw new Error(`digest must be hex-encoded: ${input.slice(0, 32)}`);
}
throw err;
}
}
const digest = parseDigest("0xDEADBEEF");
console.log(toHex(digest));
```
## API Reference
- `toHex(bytes: Uint8Array): string` — Returns a lowercase hex string whose length is `2 * bytes.length`. Never throws. Alias for `bytesToHex` from `@suaveplan/bytes`.
- `fromHex(hex: string): Uint8Array` — Parses upper or lower case. Throws `BytesError` with code `BYTES.ENCODE.INVALID_HEX` on odd-length or non-hex input. Alias for `hexToBytes` from `@suaveplan/bytes`.
## Implementation Notes
This module is a thin delegation layer: `toHex` and `fromHex` are direct `const` aliases for `bytesToHex` and `hexToBytes` from `@suaveplan/bytes`. No encoding logic lives here — this removes duplication between the two packages and ensures all `@suaveplan/crypto-*` consumers share exactly the same implementation. Errors thrown on invalid input originate from `@suaveplan/bytes` as `BytesError` instances; callers should catch `BytesError` rather than the old `CryptoUtilsError`. The public function names (`toHex` / `fromHex`) are preserved so no downstream caller requires import changes.

View File

@@ -0,0 +1,38 @@
import { BytesError } from "@suaveplan/bytes";
import { describe, expect, it } from "@suaveplan/testing/runner";
import { fromHex, toHex } from "./hex.js";
describe("hex", () => {
it("round-trips the empty string", { timeout: 5000 }, () => {
expect(toHex(new Uint8Array())).toBe("");
expect(fromHex("")).toEqual(new Uint8Array());
});
it("encodes known vectors", { timeout: 5000 }, () => {
// RFC 4648 test vectors
expect(toHex(new Uint8Array([0x66]))).toBe("66"); // 'f'
expect(toHex(new Uint8Array([0x66, 0x6f, 0x6f]))).toBe("666f6f"); // 'foo'
expect(toHex(new Uint8Array([0x00, 0xff, 0x10]))).toBe("00ff10");
});
it("decodes known vectors", { timeout: 5000 }, () => {
expect(fromHex("666f6f")).toEqual(new Uint8Array([0x66, 0x6f, 0x6f]));
expect(fromHex("FF10")).toEqual(new Uint8Array([0xff, 0x10]));
});
it("round-trips random bytes", { timeout: 5000 }, () => {
for (let n = 0; n < 200; n += 13) {
const bytes = new Uint8Array(n);
crypto.getRandomValues(bytes);
expect(fromHex(toHex(bytes))).toEqual(bytes);
}
});
it("rejects odd-length input", { timeout: 5000 }, () => {
expect(() => fromHex("abc")).toThrow(BytesError);
});
it("rejects non-hex chars", { timeout: 5000 }, () => {
expect(() => fromHex("zz")).toThrow(BytesError);
});
});

View File

@@ -0,0 +1,7 @@
import { bytesToHex, hexToBytes } from "@suaveplan/bytes";
/** Convert a Uint8Array to lowercase hex string. Delegates to @suaveplan/bytes. */
export const toHex = bytesToHex;
/** Convert a hex string to Uint8Array. Delegates to @suaveplan/bytes. */
export const fromHex = hexToBytes;

View File

@@ -0,0 +1 @@
export { fromHex, toHex } from "./hex";