diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 4830da8..11c2e63 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,6 +5,7 @@ updates: schedule: interval: "weekly" labels: [ "dependencies" ] + reviewers: ["leonardocustodio"] groups: node: patterns: @@ -13,6 +14,7 @@ updates: - package-ecosystem: github-actions directory: '/' labels: [ "gh-actions" ] + reviewers: ["leonardocustodio"] schedule: interval: weekly groups: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9afd37c..d53681d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,15 +16,15 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - name: Setup Bun - uses: oven-sh/setup-bun@v2 + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 with: bun-version: latest - name: Setup Node.js - uses: actions/setup-node@v7 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7 with: node-version: '24' @@ -64,15 +64,15 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - name: Setup Bun - uses: oven-sh/setup-bun@v2 + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 with: bun-version: latest - name: Setup Node.js - uses: actions/setup-node@v7 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7 with: node-version: '24' @@ -120,6 +120,6 @@ jobs: test "$mismatch_status" -eq 1 printf '%s\n' "$mismatch" | grep -q ' 1 MISMATCH$' test "$classes_status" -eq 0 - printf '%s\n' "$classes" | grep -q '^4 vectors - 1 match, 1 panic-mapped, 2 js-only (J3 1, J4 1), 0 unparsable, 0 MISMATCH$' + printf '%s\n' "$classes" | grep -q '^3 vectors - 1 match, 2 js-only (J3 1, J4 1), 0 unparsable, 0 MISMATCH$' test "$malformed_status" -eq 1 printf '%s\n' "$malformed" | grep -q ', 1 unparsable, 0 MISMATCH$' diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 36042eb..2c46347 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -19,15 +19,15 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - name: Setup Bun - uses: oven-sh/setup-bun@v2 + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 with: bun-version: latest - name: Setup Node.js - uses: actions/setup-node@v7 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7 with: node-version: '24' @@ -41,10 +41,10 @@ jobs: run: test -s docs/index.html - name: Setup Pages - uses: actions/configure-pages@v6 + uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6 - name: Upload Pages artifact - uses: actions/upload-pages-artifact@v5 + uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5 with: path: docs @@ -62,4 +62,4 @@ jobs: steps: - name: Deploy id: deployment - uses: actions/deploy-pages@v5 + uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2a0d545..1457be2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,15 +16,15 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - name: Setup Bun - uses: oven-sh/setup-bun@v2 + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 with: bun-version: latest - name: Setup Node.js - uses: actions/setup-node@v7 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7 with: node-version: '24' registry-url: 'https://registry.npmjs.org' diff --git a/.github/workflows/upstream.yml b/.github/workflows/upstream.yml index 201b0c4..4b073a7 100644 --- a/.github/workflows/upstream.yml +++ b/.github/workflows/upstream.yml @@ -16,7 +16,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - name: Install yq run: | diff --git a/.gitignore b/.gitignore index 50fcae8..b85bead 100644 --- a/.gitignore +++ b/.gitignore @@ -38,5 +38,13 @@ bench/charts/*.html # Rust cross-validation harness build artifacts tests/rust-validation/target -# The baseline closure is installed, not committed -tests/baseline/node_modules/ +# Lockfile: intentionally absent until @blockchaincommons/provenance-mark +# 1.0.0-beta.3 is on npm (the registry has beta.2, and this package needs the +# newer one; every other dependency is published). Until then nothing can be +# resolved from the registry at all, and a local install resolves that +# dependency through the workspace link, which would bake an unpublishable +# path into the lockfile. The lockfile that used to be committed here listed +# only devDependencies and no runtime ones, so `--frozen-lockfile` failed on +# it. Once provenance-mark publishes, commit a real lockfile and switch the +# workflows to `bun install --frozen-lockfile`. +bun.lock diff --git a/.prettierignore b/.prettierignore index 7d0790a..2d9094f 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,4 +1,3 @@ tests/baseline/*.mjs tests/baseline/*.d.mts -tests/baseline/node_modules tests/vectors/vectors.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 71af024..8d9b788 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,34 @@ # Changelog +## 1.0.0-beta.3 - 2026-09-16 + +### Changed (breaking) + +- **Dates are `DateInput`.** `XIDGenesis.date` and the next-mark options' `date` take a `Date` or a `CborDate` (provenance-mark's `DateInput`, re-exported), as every date input in envelope, gstp and provenance-mark does. A value of another kind is a `TypeError`; a `Date` without a time is now `ProvenanceMark` with cause `InvalidDate`, the generator's own check, where it was a `TypeError`. +- **Object arguments are checked for their class.** An argument that is not the class the API names is a `TypeError` naming the argument: the inception key (`PublicKeys`, a `PrivateKeyBase`, or a pair whose `publicKeys` and `privateKeys` are checked), `addKey`, `addService`, `addDelegate`, `setProvenance`, both arguments of `setProvenanceWithGenerator`, the generator of `nextProvenanceMarkWithProvidedGenerator`, `Provenance.from`, `setMark`, `setGenerator`, and `XIDDocument.equals`/`Provenance.equals`. A plain object used to crash inside a sibling package (`undefined is not an object`) or, for the marks, to be stored and fail at the next `toEnvelope`. `Provenance.equals` names its own argument (`other must be a Provenance`). +- `Provenance.equals` compares generators through `ProvenanceMarkGenerator.equals` instead of their JSON. +- **`Delegate.from` copies the controller.** The delegate holds its own copy of the document it was built from, taken at construction, as the reference's `Delegate::new` clones it; a later change to the caller's document is not seen. `delegate.controller` is the live handle to that copy. (`Delegate.clone()` and `XIDDocument.clone()` still copy; the reference's clones share the controller through its `Shared` handle, a mechanism a JavaScript `Map` does not need.) +- **`HasPermissions` carries the reference's names.** On `Key`, `Service`, `Delegate` and `Permissions`: `allow` and `deny` are the read-only sets, `addAllow`, `addDeny`, `removeAllow`, `removeDeny` and `clearAllPermissions` edit them; `Key.addPermission` is the reference's alias of `addAllow`. The carriers' `allow(p)`/`deny(p)` adders and `Permissions.clear` are gone, as are `Permissions.isAllowed`/`isDenied`, a precedence rule the reference does not define. +- **Lookups, checks and extraction under the reference's names.** `findKeyByPublicKeys`, `findKeyByReference`, `findDelegateByXid`, `findDelegateByReference`, `findServiceByUri`; `checkContainsKey`, `checkContainsDelegate`, `checkServicesConsistency`, `checkServiceConsistency` (all `void`); `extractInceptionPrivateKeysFromEnvelope`; `getAttachment`. `key`, `keyByReference`, `delegate`, `delegateByReference`, `service`, `expectKey`, `expectDelegate`, `expectServicesConsistent`, `expectServiceConsistent`, `inceptionPrivateKeysFromEnvelope`, `attachment` and `edge` are gone (`getEdge` stays). +- **Two next-mark methods.** `nextProvenanceMarkWithEmbeddedGenerator({ password?, date?, info? })` and `nextProvenanceMarkWithProvidedGenerator(generator, { date?, info? })` replace `nextProvenanceMark`, each with the reference's preconditions (`NoGenerator`/`InvalidPassword`, `GeneratorConflict`); `NextProvenanceMarkOptions` lost `generator`, `ProvidedGeneratorOptions` is new. +- **Returns that carry the item.** `removeResolutionMethod` returns the `URI` removed (or `undefined`); `Provenance.takeGenerator` returns `TakenGenerator` — the generator as held (`GeneratorData`, in the clear or the locked envelope) with its salt — or `undefined`. +- **Removals the reference has.** `Key.removeEndpoint`, `Service.removeKeyReference`, `Service.removeDelegateReference` (the reference's `endpoints_mut`, `key_referenecs_mut`, `delegate_references_mut`), each returning whether the item was there. +- **Gone.** `Service.addKeyReferenceHex`/`addDelegateReferenceHex` (write `addKeyReference(Reference.fromHex(hex))`); `Delegate.fromEnvelope`'s `parseDocument` option with `DelegateParseOptions` and `ParseXIDDocument` (the controller is always parsed with `XIDDocument.fromEnvelope`). +- `EmptyValue`'s detail is `field`, the reference's name; `ItemDetails` covers the three `item` codes and `EmptyValueDetails` the fourth. +- Requires `@blockchaincommons/provenance-mark` 1.0.0-beta.3. + +### Added + +- `examples/document.ts`: builds a document with a genesis mark, keys, a service and a delegate, signs it into an envelope, parses it back verified and advances the chain. +- `tests/guards.test.ts`: every guard against eight plain values and a property over arbitrary non-instance values; `CborDate` at both date inputs; generator equality through an envelope round trip. +- The frozen baseline for the differential is this package's 1.0.0-beta.2 with the `@blockchaincommons` siblings inlined, built by `scripts/build-baseline.ts`; the `@bcts/xid` closure is gone from the package. +- Vectors for the removers, both next-mark forms (the caller's generator advanced in place, a stale one, another chain, no mark, the document's own generator in the way), `takeGenerator` on absent, clear, unlocked and locked generators, and a delegate whose source document keeps changing after the delegate was built; the harness replays them all against the reference. The panic-mapped class is gone with the hex adders: a reference panic is a MISMATCH. +- `GeneratorData`, `TakenGenerator`, `ProvidedGeneratorOptions`, `EmptyValueDetails`. + +### Verification + +- Rust harness: 389 vectors - 362 match, 27 js-only (J3 23, J4 4), 0 unparsable, 0 MISMATCH. + ## 1.0.0-beta.2 - 2026-09-16 ### Changed (breaking) @@ -23,4 +52,4 @@ ## 1.0.0-beta.1 -- Initial beta implementation \ No newline at end of file +- Initial beta implementation diff --git a/CLA.md b/CLA.md index e99f4ac..49ddc2c 100644 --- a/CLA.md +++ b/CLA.md @@ -8,7 +8,7 @@ E-Mail: `$email` Legal Jurisdiction: Wyoming, United States of America -Project: https://github.com/BlockchainCommons/bc-lethe-kit +Project: https://github.com/BlockchainCommons/bc-xid-ts Date: `$date` diff --git a/MIGRATION.md b/MIGRATION.md index 2f1cc5c..1dbe1fb 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -1,28 +1,61 @@ # Migrating to `@blockchaincommons/xid` +## 1.0.0-beta.3 + +Every wire form is unchanged. What changed is what the package accepts, +what it throws, and the names and signatures that now follow the +reference's: + +| Before | After | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Delegate.from(controller)` keeping the caller's document, so a later change to it changed what the delegate serialised | the delegate holds its own copy, taken at construction (as `Delegate::new` clones); `delegate.controller` is the live handle to that copy | +| `key.allow(p)` / `key.deny(p)` (also on `Service` and `Delegate`) adding a privilege; `Permissions.clear()` | `addAllow(p)` / `addDeny(p)` / `removeAllow(p)` / `removeDeny(p)` / `clearAllPermissions()` on `Key`, `Service`, `Delegate` and `Permissions`; `allow` / `deny` on the carriers are the read-only sets; `Key.addPermission(p)` is `addAllow`; `HasPermissions` lists all of them | +| `Permissions.isAllowed(p)` / `isDenied(p)` | gone (a rule the reference does not define); read `allow` / `deny` | +| `doc.key(p)` / `keyByReference(r)` / `delegate(x)` / `delegateByReference(r)` / `service(u)` | `findKeyByPublicKeys(p)` / `findKeyByReference(r)` / `findDelegateByXid(x)` / `findDelegateByReference(r)` / `findServiceByUri(u)` | +| `expectKey(p)` / `expectDelegate(x)` returning the item; `expectServicesConsistent()` / `expectServiceConsistent(s)` | `checkContainsKey(p)` / `checkContainsDelegate(x)` / `checkServicesConsistency()` / `checkServiceConsistency(s)`, all `void` | +| `XIDDocument.inceptionPrivateKeysFromEnvelope(e, { password })`; `doc.attachment(d)`; `doc.edge(d)` | `extractInceptionPrivateKeysFromEnvelope(e, { password })`; `getAttachment(d)`; `getEdge(d)` only | +| `nextProvenanceMark({ date?, info?, password?, generator? })` | `nextProvenanceMarkWithEmbeddedGenerator({ password?, date?, info? })` / `nextProvenanceMarkWithProvidedGenerator(generator, { date?, info? })` (`ProvidedGeneratorOptions`); `NextProvenanceMarkOptions` has no `generator` | +| `removeResolutionMethod(u): boolean` | `removeResolutionMethod(u): URI \| undefined` (the URI removed) | +| `provenance.takeGenerator(): boolean` | `takeGenerator(): TakenGenerator \| undefined` — `{ data: GeneratorData, salt }`, the generator as held (in the clear or the locked envelope) and its salt; `GeneratorData` and `TakenGenerator` are exported | +| no way to remove an endpoint or a service reference | `key.removeEndpoint(u)`, `service.removeKeyReference(r)`, `service.removeDelegateReference(r)`, each returning whether it was there | +| `service.addKeyReferenceHex(hex)` / `addDelegateReferenceHex(hex)` | gone; `service.addKeyReference(Reference.fromHex(hex))` | +| `Delegate.fromEnvelope(envelope, { parseDocument })`, `DelegateParseOptions`, `ParseXIDDocument` | `Delegate.fromEnvelope(envelope)`; the controller is always parsed with `XIDDocument.fromEnvelope` | +| `EmptyValue` details under `item`; `ItemDetails` covering four codes | `details.field` (the reference's field name); `ItemDetails` covers `Duplicate`, `NotFound`, `StillReferenced`; `EmptyValueDetails` for `EmptyValue` | + +What the package accepts and what it throws: + +| Before | After | +| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `genesis.date` and the next-mark `date` typed `Date`; a `CborDate` a `TypeError` | `DateInput` (`Date \| CborDate`, provenance-mark's type, re-exported); a `CborDate` accepted | +| `new Date(NaN)` at either date a `TypeError` (`must be a valid Date`) | `XIDError` `ProvenanceMark` with cause `InvalidDate` (the generator's check); a value that is neither a `Date` nor a `CborDate` is still a `TypeError` | +| A plain object where a `Key`, `Service`, `Delegate`, `ProvenanceMark`, `ProvenanceMarkGenerator`, `Provenance` or `XIDDocument` goes (`addKey`, `addService`, `addDelegate`, `setProvenance`, `setProvenanceWithGenerator`, the provided generator of the next mark, `Provenance.from`/`setMark`/`setGenerator`, both `equals`, an inception key pair's `publicKeys`/`privateKeys`) crashing inside a sibling, or stored as is | `TypeError` naming the argument (`key must be a Key`, `mark must be a ProvenanceMark`, …) | +| `provenance.equals({})` reporting `other must be a ProvenanceMark` | `other must be a Provenance` | + +`Provenance.equals` compares generators through `ProvenanceMarkGenerator.equals` +(same answer as before). Requires `@blockchaincommons/provenance-mark` 1.0.0-beta.3. + ## 1.0.0-beta.2 Every wire form is unchanged. What changed is what the package accepts, what it throws, and a few names: -| Before | After | -|---|---| +| Before | After | +| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | A sibling error (`EnvelopeError`, `ComponentsError`, `CborError`, `ProvenanceMarkError`) escaping from `fromEnvelope`, `Key.fromEnvelope`, `Service.fromEnvelope`, `Delegate.fromEnvelope`, `Provenance.fromEnvelope`, `codec.decode`, `fromUR` | an `XIDError` with code `EnvelopeParsing`, `Cbor` or `ProvenanceMark`; the sibling error is `cause`, its message `details.message`; the message is the reference's (`envelope parsing error`, `CBOR error`, `provenance mark error`) | -| `InvalidXid` for a subject that is not a leaf; `InvalidResolutionMethod` for a `'dereferenceVia'` node; `UnknownPrivilege` for an `'allow'` that is not a known value; `EnvelopeParsing` for a non-text `'capability'`/`'name'` | `EnvelopeParsing`, `EnvelopeParsing`, `EnvelopeParsing`, `Cbor` (the reference's codes) | -| `Key.fromEnvelope` reading two `'nickname'`s or a non-text one as `""` | `EnvelopeParsing` | -| `error.details.reference` and the message: the full 64-hex reference | `Reference()` | -| `XIDDocument.codec.decode(c)` accepting tagged and untagged CBOR; no `fromCbor` | `fromCbor(c)` (tag required; `codec.decode` is the same), `fromUntaggedCbor(c)` (untagged only) | -| `XIDError.isXIDError(x)` by `name` and `code` | `instanceof`; `error.is(code)` narrows `details`; `XIDErrorTyped`, `XIDErrorDetailsByCode` | -| `XIDDocument.random({ rng }, genesis)` | `XIDDocument.random({ rng, genesis })` | -| `inceptionPrivateKeysFromEnvelope(envelope, password)` | `inceptionPrivateKeysFromEnvelope(envelope, { password })` | -| `addAttachment(payload, vendor, conformsTo)` | `addAttachment({ payload, vendor, conformsTo })` | -| `Delegate.fromEnvelope(envelope, parseDocument)` | `Delegate.fromEnvelope(envelope)` (or `{ parseDocument }`) | -| `provenance.takeGenerator()` returning the internal generator data | `takeGenerator()` returning whether a generator was held | -| `PrivateKeyData`, `GeneratorData` exported | gone; `hasPrivateKeys`/`hasEncryptedPrivateKeys`, `hasGenerator`/`hasEncryptedGenerator` | -| `permissions.allow`/`deny` returning the live sets | copies | -| `Key.from(pub, { privateKeys: null })`, `genesis: {}`, a 40-byte seed (cut to 32), `new Date(NaN)`, `resolution: "bogus"`, `verify: "bogus"`, `privateKeys: "bogus"`, `sign: "bogus"`, `inceptionKey: undefined` | `TypeError`; a seed of the wrong length is `ProvenanceMark` | -| `doc.attachments.len()`, `.isEmpty()`, `.iter()`; `doc.edges().len()` … | `size`, iteration (`for (const e of doc.edges())`): envelope's `Attachments`/`Edges` | -| Formatting a document without registering tags | call `registerTags()` from `@blockchaincommons/provenance-mark` once (it registers envelope's summarisers too) | +| `InvalidXid` for a subject that is not a leaf; `InvalidResolutionMethod` for a `'dereferenceVia'` node; `UnknownPrivilege` for an `'allow'` that is not a known value; `EnvelopeParsing` for a non-text `'capability'`/`'name'` | `EnvelopeParsing`, `EnvelopeParsing`, `EnvelopeParsing`, `Cbor` (the reference's codes) | +| `Key.fromEnvelope` reading two `'nickname'`s or a non-text one as `""` | `EnvelopeParsing` | +| `error.details.reference` and the message: the full 64-hex reference | `Reference()` | +| `XIDDocument.codec.decode(c)` accepting tagged and untagged CBOR; no `fromCbor` | `fromCbor(c)` (tag required; `codec.decode` is the same), `fromUntaggedCbor(c)` (untagged only) | +| `XIDError.isXIDError(x)` by `name` and `code` | `instanceof`; `error.is(code)` narrows `details`; `XIDErrorTyped`, `XIDErrorDetailsByCode` | +| `XIDDocument.random({ rng }, genesis)` | `XIDDocument.random({ rng, genesis })` | +| `inceptionPrivateKeysFromEnvelope(envelope, password)` | `extractInceptionPrivateKeysFromEnvelope(envelope, { password })` (its beta.3 name) | +| `addAttachment(payload, vendor, conformsTo)` | `addAttachment({ payload, vendor, conformsTo })` | +| `Delegate.fromEnvelope(envelope, parseDocument)` | `Delegate.fromEnvelope(envelope)` | +| `PrivateKeyData` exported | gone; `hasPrivateKeys`/`hasEncryptedPrivateKeys`, `hasGenerator`/`hasEncryptedGenerator` say what is held (`GeneratorData` stays, as `takeGenerator`'s data) | +| `permissions.allow`/`deny` returning the live sets | copies | +| `Key.from(pub, { privateKeys: null })`, `genesis: {}`, a 40-byte seed (cut to 32), `new Date(NaN)`, `resolution: "bogus"`, `verify: "bogus"`, `privateKeys: "bogus"`, `sign: "bogus"`, `inceptionKey: undefined` | `TypeError`; a seed of the wrong length is `ProvenanceMark` | +| `doc.attachments.len()`, `.isEmpty()`, `.iter()`; `doc.edges().len()` … | `size`, iteration (`for (const e of doc.edges())`): envelope's `Attachments`/`Edges` | +| Formatting a document without registering tags | call `registerTags()` from `@blockchaincommons/provenance-mark` once (it registers envelope's summarisers too) | Added: `Key.addNickname` (sets once: `Duplicate`, `EmptyValue`); `XIDGenesis.seed` as a `ProvenanceSeed`. @@ -50,63 +83,64 @@ Two behaviours moved toward the reference on the way: ## 1. Documents -| Before | After | -|---|---| -| `XIDDocument.new({ type: "publicKeys", publicKeys }, { type: "none" })` | `XIDDocument.from({ inceptionKey: publicKeys })` | -| `XIDDocument.new({ type: "privateKeyBase", privateKeyBase }, …)` | `XIDDocument.from({ inceptionKey: privateKeyBase })` | -| `XIDDocument.new({ type: "privateKeys", privateKeys, publicKeys }, …)` | `XIDDocument.from({ inceptionKey: { publicKeys, privateKeys } })` | -| `XIDDocument.new()` / `{ type: "default" }` | `XIDDocument.random({ rng? })` | -| genesis `{ type: "passphrase", passphrase, resolution, date, info }` / `{ type: "seed", seed, … }` | `genesis: { passphrase \| seed, resolution?, date?, info? }` (resolution is `"low" \| "medium" \| "quartile" \| "high"`) | +| Before | After | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `XIDDocument.new({ type: "publicKeys", publicKeys }, { type: "none" })` | `XIDDocument.from({ inceptionKey: publicKeys })` | +| `XIDDocument.new({ type: "privateKeyBase", privateKeyBase }, …)` | `XIDDocument.from({ inceptionKey: privateKeyBase })` | +| `XIDDocument.new({ type: "privateKeys", privateKeys, publicKeys }, …)` | `XIDDocument.from({ inceptionKey: { publicKeys, privateKeys } })` | +| `XIDDocument.new()` / `{ type: "default" }` | `XIDDocument.random({ rng? })` | +| genesis `{ type: "passphrase", passphrase, resolution, date, info }` / `{ type: "seed", seed, … }` | `genesis: { passphrase \| seed, resolution?, date?, info? }` (resolution is `"low" \| "medium" \| "quartile" \| "high"`) | | `doc.xid()`, `reference()`, `keys()`, `delegates()`, `services()`, `resolutionMethods()`, `provenance()`, `provenanceGenerator()`, `inceptionKey()`, `inceptionPrivateKeys()`, `inceptionSigningKey()`, `verificationKey()`, `encryptionKey()`, `isEmpty()`, `hasAttachments()`, `getAttachments()`, `extraAssertions()` | getters: `doc.xid`, `doc.reference`, `doc.keys`, … `doc.attachments`, `doc.extraAssertions` (`edges()` and `hasEdges()` stay methods: envelope's `Edgeable`) | -| `findKeyByPublicKeys(p)` / `findKeyByReference(r)` / `findDelegateByXid(x)` / `findDelegateByReference(r)` / `findServiceByUri(u)` | `key(p)` / `keyByReference(r)` / `delegate(x)` / `delegateByReference(r)` / `service(u)` | -| `checkContainsKey(p)` / `checkContainsDelegate(x)` / `checkServicesConsistency()` / `checkServiceConsistency(s)` | `expectKey(p)` / `expectDelegate(x)` / `expectServicesConsistent()` / `expectServiceConsistent(s)` (the first two return the item) | -| `removeKey(p): void` / `removeDelegate(x): void` / `removeService(u): void` | return the removed item (`StillReferenced`/`NotFound` as before); `takeKey`/`takeDelegate`/`takeService` unchanged (unchecked, `undefined` when absent) | -| `getAttachment(d)` | `attachment(d)` (`getEdge(d)` stays for envelope's `Edgeable`, `edge(d)` added) | -| `toEnvelope(privateKeyOptions, generatorOptions, signingOptions)` | `toEnvelope({ privateKeys?, generator?, sign? })` — `sign` is `"none"`, `"inception"` or a `Signer` | -| `intoEnvelope()` | `toEnvelope()` (`ToEnvelope`) | -| `toSignedEnvelope(signer)` / `toSignedEnvelopeOpt(signer, privateKeyOptions)` | `toSignedEnvelope(signer, { privateKeys? })` | -| `fromEnvelope(envelope, password, verifySignature)` / `tryFromEnvelope(envelope)` | `fromEnvelope(envelope, { password?, verify?: "none" \| "inception" })` | -| `extractInceptionPrivateKeysFromEnvelope(e, pw)` | `inceptionPrivateKeysFromEnvelope(e, { password })` | -| `privateKeyEnvelopeForKey(p, password)` | `privateKeyEnvelopeForKey(p, { password })` | -| `nextProvenanceMarkWithEmbeddedGenerator(password, date, info)` / `nextProvenanceMarkWithProvidedGenerator(generator, date, info)` | `nextProvenanceMark({ date?, info?, password?, generator? })` | -| `ur()` / `urString()` / `fromUR` / `fromURString(s)` | `toUR()` / `toUR().toString()` / `fromUR(ur)` / `fromUR(UR.parse(s))` | -| `untaggedCbor()` / `fromUntaggedCbor(c)` | `untaggedCbor()`, `toCbor()` (tag `xid`), `XIDDocument.codec` (`fromCbor`/`fromUntaggedCbor` arrived in beta.2) | +| `findKeyByPublicKeys(p)` / `findKeyByReference(r)` / `findDelegateByXid(x)` / `findDelegateByReference(r)` / `findServiceByUri(u)` | unchanged | +| `checkContainsKey(p)` / `checkContainsDelegate(x)` / `checkServicesConsistency()` / `checkServiceConsistency(s)` | unchanged | +| `removeKey(p): void` / `removeDelegate(x): void` / `removeService(u): void` | return the removed item (`StillReferenced`/`NotFound` as before); `takeKey`/`takeDelegate`/`takeService` unchanged (unchecked, `undefined` when absent) | +| `getAttachment(d)` / `getEdge(d)` | unchanged | +| `toEnvelope(privateKeyOptions, generatorOptions, signingOptions)` | `toEnvelope({ privateKeys?, generator?, sign? })` — `sign` is `"none"`, `"inception"` or a `Signer` | +| `intoEnvelope()` | `toEnvelope()` (`ToEnvelope`) | +| `toSignedEnvelope(signer)` / `toSignedEnvelopeOpt(signer, privateKeyOptions)` | `toSignedEnvelope(signer, { privateKeys? })` | +| `fromEnvelope(envelope, password, verifySignature)` / `tryFromEnvelope(envelope)` | `fromEnvelope(envelope, { password?, verify?: "none" \| "inception" })` | +| `extractInceptionPrivateKeysFromEnvelope(e, pw)` | `extractInceptionPrivateKeysFromEnvelope(e, { password? })` | +| `privateKeyEnvelopeForKey(p, password)` | `privateKeyEnvelopeForKey(p, { password })` | +| `nextProvenanceMarkWithEmbeddedGenerator(password, date, info)` / `nextProvenanceMarkWithProvidedGenerator(generator, date, info)` | `nextProvenanceMarkWithEmbeddedGenerator({ password?, date?, info? })` / `nextProvenanceMarkWithProvidedGenerator(generator, { date?, info? })` | +| `removeResolutionMethod(u)` returning the URI removed | unchanged (`URI \| undefined`) | +| `ur()` / `urString()` / `fromUR` / `fromURString(s)` | `toUR()` / `toUR().toString()` / `fromUR(ur)` / `fromUR(UR.parse(s))` | +| `untaggedCbor()` / `fromUntaggedCbor(c)` | `untaggedCbor()`, `toCbor()` (tag `xid`), `XIDDocument.codec` (`fromCbor`/`fromUntaggedCbor` arrived in beta.2) | ## 2. Keys, services, delegates, provenance -| Before | After | -|---|---| -| `Key.new(p)` / `Key.newAllowAll(p)` / `Key.newWithPrivateKeys(priv, pub)` / `Key.newWithPrivateKeyBase(b)` | `Key.from(p, { privateKeys?, nickname?, endpoints?, permissions? })` / `Key.allowAll(p)` / `Key.from(pub, { privateKeys: priv })` / `Key.fromPrivateKeyBase(b)` | -| `key.publicKeys()`, `privateKeys()`, `hasPrivateKeys()`, `hasEncryptedPrivateKeys()`, `privateKeySalt()`, `reference()`, `signingPublicKey()`, `nickname()`, `endpoints()`, `permissions()`, `permissionsMut()` | getters (`encapsulationPublicKey()` stays a method, like `PublicKeys`') | -| `key.addPermission(p)` / `HasPermissionsMixin.addAllow(key, p)` / `…addDeny` | `key.allow(p)` / `key.deny(p)` (also on `Service` and `Delegate`); `key.permissions` for the rest | -| `HasNicknameMixin.addNickname(key, n)` | `key.addNickname(n)` (`setNickname` overwrites) | -| `key.intoEnvelopeOpt(options)` / `intoEnvelope()` | `key.toEnvelope({ privateKeys? })` | -| `Key.tryFromEnvelope(e, password)` | `Key.fromEnvelope(e, { password? })` | -| `key.privateKeyEnvelope(password)` | `key.privateKeyEnvelope({ password? })` | -| `key.hashKey()` | `key.reference.toHex()` | -| `Service.new(uri)` | `Service.from(uri, { capability?, name?, keyReferences?, delegateReferences?, permissions? })` | -| `service.uri()`, `uriString()`, `capability()`, `name()`, `keyReferences()`, `delegateReferences()`, `permissions()`, `keyReferencesMut()`, `delegateReferencesMut()` | `service.uri`, `uri.toString()`, `capability`, `name`, `keyReferences`, `delegateReferences`, `permissions`; `hasKeyReference(r)`/`hasDelegateReference(r)` | -| `service.addKey({ publicKeys() })` / `addDelegate({ xid() })` | `addKey(key)` / `addDelegate(delegate \| document)` (getters) | -| `Service.tryFromEnvelope(e)` / `service.intoEnvelope()` | `Service.fromEnvelope(e)` / `service.toEnvelope()` | -| `Delegate.new(controller)`, `delegate.controller().read()`, `xid()`, `reference()`, `permissions()` | `Delegate.from(controller, { permissions? })`, `delegate.controller`, `xid`, `reference`, `permissions` | -| `Delegate.tryFromEnvelope(e)` (after `registerXIDDocumentClass`) | `Delegate.fromEnvelope(e)` | -| `Provenance.new(mark)` / `Provenance.newWithGenerator(generator, mark)` | `Provenance.from(mark, { generator? })` | -| `provenance.mark()`, `generator()`, `hasGenerator()`, `hasEncryptedGenerator()`, `generatorSalt()` | getters | -| `provenance.generatorMut(password)` / `generatorEnvelope(password)` | `unlockGenerator({ password })` / `generatorEnvelope({ password })` | -| `provenance.intoEnvelopeOpt(options)` / `Provenance.tryFromEnvelope(e, password)` | `toEnvelope({ generator? })` / `Provenance.fromEnvelope(e, { password? })` | -| `Permissions.new()` / `newAllowAll()` / `new Permissions(allow, deny)` / `tryFromEnvelope(e)` | `Permissions.from({ allow?, deny? })` / `allowAll()` / `fromEnvelope(e)`; `allow`/`deny` are read-only sets, `addAllow`/`addDeny`/`removeAllow`/`removeDeny`/`clear` mutate | +| Before | After | +| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Key.new(p)` / `Key.newAllowAll(p)` / `Key.newWithPrivateKeys(priv, pub)` / `Key.newWithPrivateKeyBase(b)` | `Key.from(p, { privateKeys?, nickname?, endpoints?, permissions? })` / `Key.allowAll(p)` / `Key.from(pub, { privateKeys: priv })` / `Key.fromPrivateKeyBase(b)` | +| `key.publicKeys()`, `privateKeys()`, `hasPrivateKeys()`, `hasEncryptedPrivateKeys()`, `privateKeySalt()`, `reference()`, `signingPublicKey()`, `nickname()`, `endpoints()`, `permissions()`, `permissionsMut()` | getters (`encapsulationPublicKey()` stays a method, like `PublicKeys`') | +| `key.addPermission(p)` / `HasPermissionsMixin.addAllow(key, p)` / `…addDeny` / `…removeAllow` / `…removeDeny` / `…clearAllPermissions` | the same names as methods on `Key`, `Service`, `Delegate` and `Permissions`; `allow` / `deny` are the read-only sets | +| `HasNicknameMixin.addNickname(key, n)` | `key.addNickname(n)` (`setNickname` overwrites) | +| `key.intoEnvelopeOpt(options)` / `intoEnvelope()` | `key.toEnvelope({ privateKeys? })` | +| `Key.tryFromEnvelope(e, password)` | `Key.fromEnvelope(e, { password? })` | +| `key.privateKeyEnvelope(password)` | `key.privateKeyEnvelope({ password? })` | +| `key.hashKey()` | `key.reference.toHex()` | +| `Service.new(uri)` | `Service.from(uri, { capability?, name?, keyReferences?, delegateReferences?, permissions? })` | +| `service.uri()`, `uriString()`, `capability()`, `name()`, `keyReferences()`, `delegateReferences()`, `permissions()`, `keyReferencesMut()`, `delegateReferencesMut()` | `service.uri`, `uri.toString()`, `capability`, `name`, `keyReferences`, `delegateReferences`, `permissions`; `hasKeyReference(r)`/`hasDelegateReference(r)`, `removeKeyReference(r)`/`removeDelegateReference(r)`; `key.endpointsMut()` is `removeEndpoint(u)` | +| `service.addKey({ publicKeys() })` / `addDelegate({ xid() })` | `addKey(key)` / `addDelegate(delegate \| document)` (getters) | +| `Service.tryFromEnvelope(e)` / `service.intoEnvelope()` | `Service.fromEnvelope(e)` / `service.toEnvelope()` | +| `Delegate.new(controller)`, `delegate.controller().read()`, `xid()`, `reference()`, `permissions()` | `Delegate.from(controller, { permissions? })` (copies the controller as `new` does), `delegate.controller`, `xid`, `reference`, `permissions` | +| `Delegate.tryFromEnvelope(e)` (after `registerXIDDocumentClass`) | `Delegate.fromEnvelope(e)` | +| `Provenance.new(mark)` / `Provenance.newWithGenerator(generator, mark)` | `Provenance.from(mark, { generator? })` | +| `provenance.mark()`, `generator()`, `hasGenerator()`, `hasEncryptedGenerator()`, `generatorSalt()`; `takeGenerator()` | getters; `takeGenerator(): TakenGenerator \| undefined` (`{ data: GeneratorData, salt }`) | +| `provenance.generatorMut(password)` / `generatorEnvelope(password)` | `unlockGenerator({ password })` / `generatorEnvelope({ password })` | +| `provenance.intoEnvelopeOpt(options)` / `Provenance.tryFromEnvelope(e, password)` | `toEnvelope({ generator? })` / `Provenance.fromEnvelope(e, { password? })` | +| `Permissions.new()` / `newAllowAll()` / `new Permissions(allow, deny)` / `tryFromEnvelope(e)` | `Permissions.from({ allow?, deny? })` / `allowAll()` / `fromEnvelope(e)`; `allow`/`deny` are read-only sets, `addAllow`/`addDeny`/`removeAllow`/`removeDeny`/`clearAllPermissions` mutate | ## 3. Options, privileges, errors -| Before | After | -|---|---| -| `XIDPrivateKeyOptions.Omit` / `.Include` / `.Elide` / `{ type: XIDPrivateKeyOptions.Encrypt, password, method? }` | `"omit"` / `"include"` / `"elide"` / `{ encrypt: password, method? }` (`XIDPrivateKeyOptions` is the union) | -| `XIDGeneratorOptions` likewise | likewise | -| `XIDVerifySignature.None` / `.Inception` | `"none"` / `"inception"` | -| `Privilege.All` … `Privilege.Revoke` (enum) | `"All"` … `"Revoke"` (`Privilege` union, `PRIVILEGES`, `isPrivilege`) | -| `privilegeToKnownValue` / `privilegeToEnvelope` | `privilegeKnownValue` / `privilegeEnvelope` (`privilegeFromKnownValue`/`privilegeFromEnvelope` unchanged) | -| `XIDErrorCode.DUPLICATE` … (enum), `error.code` | `error.code` is `"Duplicate"` … `"ProvenanceMark"` (the reference's variant names; `XIDErrorCode`, `XID_ERROR_CODES`), `error.details` typed per code, `XIDError.isXIDError`, `error.is(code)` | -| `XIDResult` | gone (it was `T`) | +| Before | After | +| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `XIDPrivateKeyOptions.Omit` / `.Include` / `.Elide` / `{ type: XIDPrivateKeyOptions.Encrypt, password, method? }` | `"omit"` / `"include"` / `"elide"` / `{ encrypt: password, method? }` (`XIDPrivateKeyOptions` is the union) | +| `XIDGeneratorOptions` likewise | likewise | +| `XIDVerifySignature.None` / `.Inception` | `"none"` / `"inception"` | +| `Privilege.All` … `Privilege.Revoke` (enum) | `"All"` … `"Revoke"` (`Privilege` union, `PRIVILEGES`, `isPrivilege`) | +| `privilegeToKnownValue` / `privilegeToEnvelope` | `privilegeKnownValue` / `privilegeEnvelope` (`privilegeFromKnownValue`/`privilegeFromEnvelope` unchanged) | +| `XIDErrorCode.DUPLICATE` … (enum), `error.code` | `error.code` is `"Duplicate"` … `"ProvenanceMark"` (the reference's variant names; `XIDErrorCode`, `XID_ERROR_CODES`), `error.details` typed per code, `XIDError.isXIDError`, `error.is(code)` | +| `XIDResult` | gone (it was `T`) | | `Shared`, `HasNickname`, `HasPermissionsMixin`, `HasNicknameMixin`, `registerXIDDocumentClass`, `XIDDocumentType`, `VERSION`, the `XID`/`Attachments`/`Edges`/`Edgeable` re-exports | gone: import `XID` from `@blockchaincommons/components`, `Attachments` from `@blockchaincommons/envelope/attachment`, `Edges`/`Edgeable` from `@blockchaincommons/envelope/edge`; `HasPermissions` and `XIDDocumentLike` are the remaining shape types | ## 4. Dependencies @@ -158,10 +192,10 @@ number here does **not** mean older code. ### 3. Node and TypeScript floors moved up -| | `@bcts/xid` | `@blockchaincommons/xid` | -|---|---|---| -| Node | `>= 18` | `>= 22.12` | -| TypeScript (consumers) | 6.x | `>= 5.7` | +| | `@bcts/xid` | `@blockchaincommons/xid` | +| ---------------------- | ----------- | ------------------------ | +| Node | `>= 18` | `>= 22.12` | +| TypeScript (consumers) | 6.x | `>= 5.7` | ### 4. The IIFE / global-script build is gone @@ -177,9 +211,9 @@ Every sibling library moved from the `@bcts` scope to `@blockchaincommons`. If you depend on more than one, rename them together so a single copy of each shared type is resolved: -| Old | New | -|---|---| -| `@bcts/dcbor` | `@blockchaincommons/dcbor` | +| Old | New | +| -------------- | --------------------------- | +| `@bcts/dcbor` | `@blockchaincommons/dcbor` | | `@bcts/` | `@blockchaincommons/` | ### 6. What did not change diff --git a/README.md b/README.md index dc191ea..51b9a45 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ bun add @blockchaincommons/xid ```typescript import { PrivateKeyBase } from "@blockchaincommons/components"; +import { CborDate } from "@blockchaincommons/dcbor"; import { registerTags } from "@blockchaincommons/provenance-mark"; import { XIDDocument, Key, Service } from "@blockchaincommons/xid"; @@ -34,17 +35,27 @@ const doc = XIDDocument.from({ genesis: { passphrase: "wolf", resolution: "low" }, }); doc.addResolutionMethod("https://resolver.example.com"); -const service = Service.from("https://messaging.example.com", { capability: "com.example.messaging" }); +const service = Service.from("https://messaging.example.com", { + capability: "com.example.messaging", +}); service.addKey(doc.inceptionKey!); -service.allow("Sign"); +service.addAllow("Sign"); doc.addService(service); const signed = doc.toEnvelope({ privateKeys: { encrypt: "password" }, sign: "inception" }); const back = XIDDocument.fromEnvelope(signed, { password: "password", verify: "inception" }); back.equals(doc); // true doc.toUR().toString(); // "ur:xid/…" +doc.nextProvenanceMarkWithEmbeddedGenerator({ + date: CborDate.fromString("2025-06-01T00:00:00Z"), // a `Date` works too +}); ``` +Every argument is checked at the boundary: a value that is not the class the +API names (a plain object where a `Key`, `Service`, `Delegate`, +`ProvenanceMark`, `ProvenanceMarkGenerator` or document goes, a date that is +neither a `Date` nor a `CborDate`) is a `TypeError` naming the argument. + Runnable examples live in the [`examples/`](https://github.com/BlockchainCommons/bc-xid-ts/tree/master/examples) directory. ## Status - Beta @@ -53,6 +64,7 @@ Runnable examples live in the [`examples/`](https://github.com/BlockchainCommons ### Version History +- **1.0.0-beta.3 (September 16, 2026)** - Dates take a `Date` or a `CborDate` (`DateInput`); every object argument is checked for its class; `Provenance.equals` compares generators through `ProvenanceMarkGenerator.equals`; the surface follows the reference's names (`findKeyByPublicKeys`, `checkContainsKey`, `addAllow`/`removeAllow`/`clearAllPermissions`, the two `nextProvenanceMarkWith…Generator` methods, `getAttachment`); `Delegate.from` copies its controller; endpoints and service references can be removed; `takeGenerator` and `removeResolutionMethod` return what they removed; the frozen baseline is this package's beta.2; a runnable `examples/document.ts`. - **1.0.0-beta.2 (September 16, 2026)** - Every decode failure is an `XIDError` with the reference's codes and messages; strict CBOR decoders (`fromCbor`, `fromUntaggedCbor`); typed error details; `addNickname`; options objects throughout; the JavaScript input domain checked. - **1.0.0-beta.1 (September 9, 2026)** - Initial beta implementation. @@ -96,7 +108,7 @@ The best place to talk about Blockchain Commons and its projects is in our GitHu [**Gordian User Community**](https://github.com/BlockchainCommons/Gordian/discussions). For users of the Gordian reference apps, including [Gordian Coordinator](https://github.com/BlockchainCommons/iOS-GordianCoordinator), [Gordian Seed Tool](https://github.com/BlockchainCommons/GordianSeedTool-iOS), [Gordian Server](https://github.com/BlockchainCommons/GordianServer-macOS), [Gordian Wallet](https://github.com/BlockchainCommons/GordianWallet-iOS), and [SpotBit](https://github.com/BlockchainCommons/spotbit) as well as our whole series of [CLI apps](https://github.com/BlockchainCommons/Gordian/blob/master/Docs/Overview-Apps.md#cli-apps). This is a place to talk about bug reports and feature requests as well as to explore how our reference apps embody the [Gordian Principles](https://github.com/BlockchainCommons/Gordian#gordian-principles). -[**Blockchain Commons Discussions**](https://github.com/BlockchainCommons/Community/discussions). For developers, interns, and patrons of Blockchain Commons, please use the discussions area of the [Community repo](https://github.com/BlockchainCommons/Community) to talk about general Blockchain Commons issues, the intern program, or topics other than those covered by the [Gordian Developer Community](https://github.com/BlockchainCommons/Gordian-Developer-Community/discussions) or the +[**Blockchain Commons Discussions**](https://github.com/BlockchainCommons/Community/discussions). For developers, interns, and patrons of Blockchain Commons, please use the discussions area of the [Community repo](https://github.com/BlockchainCommons/Community) to talk about general Blockchain Commons issues, the intern program, or topics other than those covered by the [Gordian Developer Community](https://github.com/BlockchainCommons/Gordian-Developer-Community/discussions) or the [Gordian User Community](https://github.com/BlockchainCommons/Gordian/discussions). ### Other Questions & Problems @@ -109,11 +121,11 @@ If your company requires support to use our projects, please feel free to contac The following people directly contributed to this repository. You can add your name here by getting involved. The first step is learning how to contribute from our [CONTRIBUTING.md](./CONTRIBUTING.md) documentation. -| Name | Role | Github | Email | GPG Fingerprint | -| ----------------- | ------------------- | ------------------------------------------------- | ------------------------------------- | -------------------------------------------------- | -| Christopher Allen | Principal Architect | [@ChristopherA](https://github.com/ChristopherA) | \ | FDFE 14A5 4ECB 30FC 5D22 74EF F8D3 6C91 3574 05ED | -| Wolf McNally | Lead Researcher/Engineer | [@wolfmcnally](https://github.com/wolfmcnally) | \ | 9436 52EE 3844 1760 C3DC 3536 4B6C 2FCF 8947 80AE | -| Leonardo Custodio | Software Engineer | [@leonardocustodio](https://github.com/leonardocustodio) | \ | 59DA D997 67EF 3BAB 2B90 D057 5384 DEF3 B582 450D | +| Name | Role | Github | Email | GPG Fingerprint | +| ----------------- | ------------------------ | -------------------------------------------------------- | ------------------------------------- | ------------------------------------------------- | +| Christopher Allen | Principal Architect | [@ChristopherA](https://github.com/ChristopherA) | \ | FDFE 14A5 4ECB 30FC 5D22 74EF F8D3 6C91 3574 05ED | +| Wolf McNally | Lead Researcher/Engineer | [@wolfmcnally](https://github.com/wolfmcnally) | \ | 9436 52EE 3844 1760 C3DC 3536 4B6C 2FCF 8947 80AE | +| Leonardo Custodio | Software Engineer | [@leonardocustodio](https://github.com/leonardocustodio) | \ | 59DA D997 67EF 3BAB 2B90 D057 5384 DEF3 B582 450D | ### Contributing Sponsor @@ -133,8 +145,8 @@ Please report suspected security vulnerabilities in private via email to Christo The following keys may be used to communicate sensitive information to developers: -| Name | Fingerprint | -| ----------------- | -------------------------------------------------- | -| Christopher Allen | FDFE 14A5 4ECB 30FC 5D22 74EF F8D3 6C91 3574 05ED | +| Name | Fingerprint | +| ----------------- | ------------------------------------------------- | +| Christopher Allen | FDFE 14A5 4ECB 30FC 5D22 74EF F8D3 6C91 3574 05ED | You can import a key by running the following command with that individual’s fingerprint: `gpg --recv-keys ""` Ensure that you put quotes around fingerprints that contain spaces. diff --git a/api/index.d.mts b/api/index.d.mts index 645ccaf..5ee2536 100644 --- a/api/index.d.mts +++ b/api/index.d.mts @@ -2,7 +2,7 @@ import { KnownValue } from "@blockchaincommons/known-values"; import { Envelope, EnvelopeInput, ToEnvelope } from "@blockchaincommons/envelope"; import { Cbor, CborCodec, CborTagged, Tag, ToCbor } from "@blockchaincommons/dcbor"; import { Digest, EncapsulationPublicKey, PrivateKeyBase, PrivateKeys, PublicKeys, Reference, Salt, Signature, Signer, SigningPublicKey, URI, Verifier, XID } from "@blockchaincommons/components"; -import { ProvenanceMark, ProvenanceMarkGenerator, ProvenanceMarkResolution, ProvenanceSeed } from "@blockchaincommons/provenance-mark"; +import { DateInput, DateInput as DateInput$1, ProvenanceMark, ProvenanceMarkGenerator, ProvenanceMarkResolution, ProvenanceSeed } from "@blockchaincommons/provenance-mark"; import { KeyDerivationMethod } from "@blockchaincommons/components/kdf"; import { Attachments } from "@blockchaincommons/envelope/attachment"; import { Edgeable, Edges } from "@blockchaincommons/envelope/edge"; @@ -18,7 +18,7 @@ import { RngOptions } from "@blockchaincommons/rand"; /** Every code an `XIDError` can carry: the reference's `Error` variant names. */ type XIDErrorCode = "Duplicate" | "NotFound" | "StillReferenced" | "EmptyValue" | "UnknownPrivilege" | "InvalidXid" | "MissingInceptionKey" | "InvalidResolutionMethod" | "MultipleProvenanceMarks" | "UnexpectedPredicate" | "UnexpectedNestedAssertions" | "NoPermissions" | "NoReferences" | "UnknownKeyReference" | "UnknownDelegateReference" | "KeyNotFoundInDocument" | "DelegateNotFoundInDocument" | "InvalidPassword" | "EnvelopeNotSigned" | "SignatureVerificationFailed" | "NoProvenanceMark" | "GeneratorConflict" | "NoGenerator" | "ChainIdMismatch" | "SequenceMismatch" | "EnvelopeParsing" | "Component" | "Cbor" | "ProvenanceMark"; /** Every code, for exhaustive tables and tests. */ -declare const XID_ERROR_CODES: readonly XIDErrorCode[]; +export declare const XID_ERROR_CODES: readonly XIDErrorCode[]; /** The fields each code carries besides `code`. */ interface XIDErrorDetailsByCode { /** An item of this kind is already there. */ @@ -39,7 +39,7 @@ interface XIDErrorDetailsByCode { /** The field must not be empty. */ EmptyValue: { /** The field's name. */ - readonly item: string; + readonly field: string; }; /** A known value that names no privilege. */ UnknownPrivilege: unknown; @@ -82,12 +82,12 @@ interface XIDErrorDetailsByCode { /** The service's URI. */ readonly uri: string; }; - /** `expectKey` found no such key. */ + /** `checkContainsKey` found no such key. */ KeyNotFoundInDocument: { /** The key's public keys, rendered. */ readonly key: string; }; - /** `expectDelegate` found no such delegate. */ + /** `checkContainsDelegate` found no such delegate. */ DelegateNotFoundInDocument: { /** The delegate's XID, rendered. */ readonly delegate: string; @@ -157,8 +157,10 @@ type XIDErrorTyped = C extends XIDErrorCo /** The condition's fields. */ readonly details: XIDErrorDetailsFor; } : never; -/** `details` of the four item codes. */ -type ItemDetails = XIDErrorDetailsFor<"Duplicate" | "NotFound" | "StillReferenced" | "EmptyValue">; +/** `details` of the three item codes. */ +type ItemDetails = XIDErrorDetailsFor<"Duplicate" | "NotFound" | "StillReferenced">; +/** `details` of `EmptyValue`. */ +type EmptyValueDetails = XIDErrorDetailsFor<"EmptyValue">; /** `details` of the codes with nothing more to say. */ type PlainDetails = XIDErrorDetailsFor<"UnknownPrivilege" | "InvalidXid" | "MissingInceptionKey" | "InvalidResolutionMethod" | "MultipleProvenanceMarks" | "UnexpectedNestedAssertions" | "InvalidPassword" | "EnvelopeNotSigned" | "SignatureVerificationFailed" | "NoProvenanceMark" | "GeneratorConflict" | "NoGenerator">; /** `details` of `UnexpectedPredicate`. */ @@ -191,7 +193,7 @@ type WrappedDetails = XIDErrorDetailsFor<"EnvelopeParsing" | "Component" | "Cbor * } * ``` */ -declare class XIDError extends Error { +export declare class XIDError extends Error { /** Always `"XIDError"`. */ override readonly name = "XIDError"; /** The condition, one of `XIDErrorCode`. */ @@ -235,9 +237,9 @@ declare class XIDError extends Error { static unknownKeyReference(reference: string, uri: string): XIDErrorTyped<"UnknownKeyReference">; /** `UnknownDelegateReference`: the service names a delegate the document lacks. */ static unknownDelegateReference(reference: string, uri: string): XIDErrorTyped<"UnknownDelegateReference">; - /** `KeyNotFoundInDocument`: `expectKey` found no such key. */ + /** `KeyNotFoundInDocument`: `checkContainsKey` found no such key. */ static keyNotFoundInDocument(key: string): XIDErrorTyped<"KeyNotFoundInDocument">; - /** `DelegateNotFoundInDocument`: `expectDelegate` found no such delegate. */ + /** `DelegateNotFoundInDocument`: `checkContainsDelegate` found no such delegate. */ static delegateNotFoundInDocument(delegate: string): XIDErrorTyped<"DelegateNotFoundInDocument">; /** `InvalidPassword`: a locked key or generator did not open. */ static invalidPassword(): XIDErrorTyped<"InvalidPassword">; @@ -284,21 +286,21 @@ declare class XIDError extends Error { */ type Privilege = "All" | "Auth" | "Sign" | "Encrypt" | "Elide" | "Issue" | "Access" | "Delegate" | "Verify" | "Update" | "Transfer" | "Elect" | "Burn" | "Revoke"; /** Every privilege, in the reference's order. */ -declare const PRIVILEGES: readonly Privilege[]; +export declare const PRIVILEGES: readonly Privilege[]; /** Whether `value` is one of the privilege names. */ -declare function isPrivilege(value: unknown): value is Privilege; +export declare function isPrivilege(value: unknown): value is Privilege; /** The known value the privilege is encoded as; `UnknownPrivilege` for a name that is not one. */ -declare function privilegeKnownValue(privilege: Privilege): KnownValue; +export declare function privilegeKnownValue(privilege: Privilege): KnownValue; /** The privilege a known value names; `UnknownPrivilege` for any other value. */ -declare function privilegeFromKnownValue(knownValue: KnownValue): Privilege; +export declare function privilegeFromKnownValue(knownValue: KnownValue): Privilege; /** The privilege as a known-value envelope. */ -declare function privilegeEnvelope(privilege: Privilege): Envelope; +export declare function privilegeEnvelope(privilege: Privilege): Envelope; /** * The privilege a known-value envelope names: `EnvelopeParsing` when the * subject is not a known value, `UnknownPrivilege` when it names no * privilege. */ -declare function privilegeFromEnvelope(envelope: Envelope): Privilege; +export declare function privilegeFromEnvelope(envelope: Envelope): Privilege; //#endregion //#region src/permissions.d.ts /** What `Permissions.from` takes. */ @@ -308,17 +310,32 @@ interface PermissionsInput { /** The privileges denied. */ deny?: Iterable | undefined; } -/** Something that carries permissions: a key, a delegate, a service. */ +/** + * Something that carries permissions: a key, a delegate, a service. The + * members are the reference's `HasPermissions` trait: `allow` and `deny` + * are the sets, `addAllow`/`addDeny`/`removeAllow`/`removeDeny` and + * `clearAllPermissions` edit them. + */ interface HasPermissions { /** The permissions (live). */ readonly permissions: Permissions; + /** The allowed privileges (a copy). */ + readonly allow: ReadonlySet; + /** The denied privileges (a copy). */ + readonly deny: ReadonlySet; /** Allows `privilege`. */ - allow(privilege: Privilege): void; + addAllow(privilege: Privilege): void; /** Denies `privilege`. */ - deny(privilege: Privilege): void; + addDeny(privilege: Privilege): void; + /** Stops allowing `privilege`. */ + removeAllow(privilege: Privilege): void; + /** Stops denying `privilege`. */ + removeDeny(privilege: Privilege): void; + /** Empties both sets. */ + clearAllPermissions(): void; } /** An allow set and a deny set of privileges. */ -declare class Permissions { +export declare class Permissions { private readonly _allow; private readonly _deny; private constructor(); @@ -339,15 +356,7 @@ declare class Permissions { /** Stops denying `privilege`. */ removeDeny(privilege: Privilege): void; /** Empties both sets. */ - clear(): void; - /** - * Allowed (directly or through `All`) and not denied (directly or - * through `All`): a denial wins over an allowance. This is the - * package's own rule; the reference exposes the sets only. - */ - isAllowed(privilege: Privilege): boolean; - /** Denied directly or through `All`. */ - isDenied(privilege: Privilege): boolean; + clearAllPermissions(): void; /** Adds an `'allow'` assertion per allowed privilege, then a `'deny'` per denied one. */ addToEnvelope(envelope: Envelope): Envelope; /** @@ -401,7 +410,7 @@ interface KeyEnvelopeOptions { * A key of a XID document: public keys, optionally private keys (in the * clear or password-locked), a nickname, endpoints and permissions. */ -declare class Key implements HasPermissions, Verifier { +export declare class Key implements HasPermissions, Verifier { private readonly _publicKeys; private readonly _privateKeyData; private _nickname; @@ -440,6 +449,8 @@ declare class Key implements HasPermissions, Verifier { get endpoints(): ReadonlySet; /** Adds an endpoint, as a URI or its text (a components error for text that is not a URI). */ addEndpoint(endpoint: URI | string): void; + /** Removes an endpoint; whether it was there. */ + removeEndpoint(endpoint: URI | string): boolean; /** The nickname; empty when there is none. */ get nickname(): string; /** Sets (or clears, with `""`) the nickname. */ @@ -448,10 +459,22 @@ declare class Key implements HasPermissions, Verifier { addNickname(name: string): void; /** The permissions (live). */ get permissions(): Permissions; + /** The allowed privileges (a copy). */ + get allow(): ReadonlySet; + /** The denied privileges (a copy). */ + get deny(): ReadonlySet; /** Allows `privilege`. */ - allow(privilege: Privilege): void; + addAllow(privilege: Privilege): void; /** Denies `privilege`. */ - deny(privilege: Privilege): void; + addDeny(privilege: Privilege): void; + /** Stops allowing `privilege`. */ + removeAllow(privilege: Privilege): void; + /** Stops denying `privilege`. */ + removeDeny(privilege: Privilege): void; + /** Empties both sets. */ + clearAllPermissions(): void; + /** `addAllow` under the reference's `Key::add_permission` name. */ + addPermission(privilege: Privilege): void; private privateKeyAssertionEnvelope; /** * The public keys as the subject, the private keys per `privateKeys` @@ -507,7 +530,7 @@ interface ServiceInput { * permissions round-trip: the parser rejects `'deny'` as the reference's * does. */ -declare class Service implements HasPermissions { +export declare class Service implements HasPermissions { private readonly _uri; private readonly _keyReferences; private readonly _delegateReferences; @@ -534,8 +557,8 @@ declare class Service implements HasPermissions { hasKeyReference(reference: Reference): boolean; /** Adds a key reference; `Duplicate` when it is already there. */ addKeyReference(keyReference: Reference): void; - /** Adds a key reference given as 64 hex characters (a components error otherwise). */ - addKeyReferenceHex(keyReferenceHex: string): void; + /** Removes a key reference; whether it was there. */ + removeKeyReference(reference: Reference): boolean; /** References the key's public keys. */ addKey(key: { readonly publicKeys: PublicKeys; @@ -546,8 +569,8 @@ declare class Service implements HasPermissions { hasDelegateReference(reference: Reference): boolean; /** Adds a delegate reference; `Duplicate` when it is already there. */ addDelegateReference(delegateReference: Reference): void; - /** Adds a delegate reference given as 64 hex characters (a components error otherwise). */ - addDelegateReferenceHex(delegateReferenceHex: string): void; + /** Removes a delegate reference; whether it was there. */ + removeDelegateReference(reference: Reference): boolean; /** References the delegate's (or document's) XID. */ addDelegate(delegate: { readonly xid: XID; @@ -558,10 +581,20 @@ declare class Service implements HasPermissions { setName(name: string): void; /** The permissions (live). */ get permissions(): Permissions; + /** The allowed privileges (a copy). */ + get allow(): ReadonlySet; + /** The denied privileges (a copy). */ + get deny(): ReadonlySet; /** Allows `privilege`. */ - allow(privilege: Privilege): void; - /** Denies `privilege` (written to the wire, but not read back: see the class). */ - deny(privilege: Privilege): void; + addAllow(privilege: Privilege): void; + /** Denies `privilege`. Written to the wire, but not read back: see the class. */ + addDeny(privilege: Privilege): void; + /** Stops allowing `privilege`. */ + removeAllow(privilege: Privilege): void; + /** Stops denying `privilege`. */ + removeDeny(privilege: Privilege): void; + /** Empties both sets. */ + clearAllPermissions(): void; /** The URI as the subject; `'key'`, `'delegate'`, `'capability'`, `'name'` and the permissions. */ toEnvelope(): Envelope; /** @@ -590,45 +623,52 @@ interface XIDDocumentLike { /** A deep copy of the controller. */ clone(): XIDDocumentLike; } -/** Parses a controller document from its envelope: `XIDDocument.fromEnvelope`. */ -type ParseXIDDocument = (envelope: Envelope) => XIDDocumentLike; /** What `Delegate.from` takes besides the controller. */ interface DelegateInput { /** The permissions granted; none unless given. */ permissions?: Permissions | undefined; } -/** What `Delegate.fromEnvelope` takes besides the envelope. */ -interface DelegateParseOptions { - /** The parser of the controller's envelope; `XIDDocument.fromEnvelope` unless given. */ - parseDocument?: ParseXIDDocument | undefined; -} /** A delegate: a controller document and the permissions this document grants it. */ -declare class Delegate implements HasPermissions { +export declare class Delegate implements HasPermissions { private readonly _controller; private readonly _permissions; private constructor(); - /** A delegate controlled by `controller`, with no permissions unless given. */ + /** + * A delegate controlled by a copy of `controller` taken now (as the + * reference's `Delegate::new` clones it): a later change to the + * caller's document is not seen. No permissions unless given. + */ static from(controller: XIDDocumentLike, { permissions }?: DelegateInput): Delegate; - /** The controlling document (live: mutating it mutates the delegate). */ + /** The delegate's own copy of the controlling document (live: mutating it mutates the delegate). */ get controller(): XIDDocumentLike; /** The controller's XID. */ get xid(): XID; /** The reference of the controller's XID. */ get reference(): Reference; - /** The permissions granted (live). */ + /** The permissions (live). */ get permissions(): Permissions; + /** The allowed privileges (a copy). */ + get allow(): ReadonlySet; + /** The denied privileges (a copy). */ + get deny(): ReadonlySet; /** Allows `privilege`. */ - allow(privilege: Privilege): void; + addAllow(privilege: Privilege): void; /** Denies `privilege`. */ - deny(privilege: Privilege): void; + addDeny(privilege: Privilege): void; + /** Stops allowing `privilege`. */ + removeAllow(privilege: Privilege): void; + /** Stops denying `privilege`. */ + removeDeny(privilege: Privilege): void; + /** Empties both sets. */ + clearAllPermissions(): void; /** The controller's envelope, wrapped, with the permissions. */ toEnvelope(): Envelope; /** * A delegate from its envelope: the permissions, then the unwrapped - * controller parsed by `parseDocument` (`XIDDocument.fromEnvelope` - * unless given). A sibling failure is `EnvelopeParsing`. + * controller parsed with `XIDDocument.fromEnvelope`. A sibling failure + * is `EnvelopeParsing`. */ - static fromEnvelope(envelope: Envelope, { parseDocument }?: DelegateParseOptions): Delegate; + static fromEnvelope(envelope: Envelope): Delegate; /** Same controller document and permissions — as the reference's equality. */ equals(other: Delegate): boolean; /** A deep copy. */ @@ -638,6 +678,25 @@ declare class Delegate implements HasPermissions { //#region src/provenance.d.ts /** How the generator goes into an envelope; the same four forms as private keys. */ type XIDGeneratorOptions = "omit" | "include" | "elide" | EncryptOptions; +/** The generator as held: in the clear, or the locked envelope as parsed. */ +type GeneratorData = { + /** Held in the clear. */ + type: "decrypted"; + /** The generator. */ + generator: ProvenanceMarkGenerator; +} | { + /** Held locked (parsed without the password). */ + type: "encrypted"; + /** The locked envelope. */ + envelope: Envelope; +}; +/** What `takeGenerator` hands back: the generator as held and its salt. */ +interface TakenGenerator { + /** The generator as held. */ + readonly data: GeneratorData; + /** The salt the `'provenanceGenerator'` assertion carried. */ + readonly salt: Salt; +} /** What `Provenance.from` takes besides the mark. */ interface ProvenanceInput { /** The generator that produced the mark, when the document should keep it. */ @@ -649,7 +708,7 @@ interface ProvenanceEnvelopeOptions { generator?: XIDGeneratorOptions | undefined; } /** A provenance mark and, optionally, the generator that continues its chain. */ -declare class Provenance { +export declare class Provenance { private _mark; private _generator; private constructor(); @@ -669,8 +728,11 @@ declare class Provenance { setMark(mark: ProvenanceMark): void; /** Sets or replaces the generator, with a fresh salt. */ setGenerator(generator: ProvenanceMarkGenerator): void; - /** Removes the generator, returning whether one was held. */ - takeGenerator(): boolean; + /** + * Removes and returns the generator as held (in the clear or the locked + * envelope) with its salt; `undefined` when there is none. + */ + takeGenerator(): TakenGenerator | undefined; /** * The generator, unlocking a locked one with the password (it stays * unlocked); `InvalidPassword` when it is locked and the password is @@ -732,8 +794,8 @@ interface XIDGenesis { seed?: Uint8Array | ProvenanceSeed | undefined; /** The chain's resolution; `"high"` unless given. */ resolution?: ProvenanceMarkResolution | undefined; - /** The genesis mark's date; now unless given. */ - date?: Date | undefined; + /** The genesis mark's date, a `Date` or a `CborDate`; now unless given. */ + date?: DateInput$1 | undefined; /** The genesis mark's info. */ info?: Cbor | undefined; } @@ -781,17 +843,19 @@ interface AttachmentInput { /** The URI of the format the payload conforms to. */ conformsTo?: string | undefined; } -/** What `nextProvenanceMark` takes. */ +/** What `nextProvenanceMarkWithEmbeddedGenerator` takes. */ interface NextProvenanceMarkOptions extends PasswordOptions { - /** The new mark's date; now unless given. */ - date?: Date | undefined; + /** The new mark's date, a `Date` or a `CborDate`; now unless given. */ + date?: DateInput$1 | undefined; + /** The new mark's info. */ + info?: Cbor | undefined; +} +/** What `nextProvenanceMarkWithProvidedGenerator` takes besides the generator. */ +interface ProvidedGeneratorOptions { + /** The new mark's date, a `Date` or a `CborDate`; now unless given. */ + date?: DateInput$1 | undefined; /** The new mark's info. */ info?: Cbor | undefined; - /** - * A generator kept outside the document; refused when the document - * holds one. When given, `password` is not used. - */ - generator?: ProvenanceMarkGenerator | undefined; } /** The document's CBOR codec, with the tag it carries. */ interface XIDDocumentCodec extends CborCodec { @@ -805,7 +869,7 @@ interface XIDDocumentCodec extends CborCodec { * `services` are copied-out arrays of live values, and `attachments` and * `edges()` are the document's own containers. */ -declare class XIDDocument implements ToEnvelope, ToCbor, CborTagged, ToUR, Edgeable { +export declare class XIDDocument implements ToEnvelope, ToCbor, CborTagged, ToUR, Edgeable { private readonly _xid; private readonly _resolutionMethods; private readonly _keys; @@ -844,16 +908,16 @@ declare class XIDDocument implements ToEnvelope, ToCbor, CborTagged, ToUR, Edgea get resolutionMethods(): ReadonlySet; /** Adds a resolution method, as a URI or its text (a components error for text that is not a URI). */ addResolutionMethod(method: URI | string): void; - /** Removes a resolution method; whether it was there. */ - removeResolutionMethod(method: URI | string): boolean; + /** Removes and returns a resolution method; `undefined` when it was not there. */ + removeResolutionMethod(method: URI | string): URI | undefined; /** The keys (a copied-out array of live keys). */ get keys(): readonly Key[]; /** Adds a key; `Duplicate` when the public keys are already there. */ addKey(key: Key): void; /** The key with these public keys. */ - key(publicKeys: PublicKeys): Key | undefined; + findKeyByPublicKeys(publicKeys: PublicKeys): Key | undefined; /** The key with this reference. */ - keyByReference(reference: Reference): Key | undefined; + findKeyByReference(reference: Reference): Key | undefined; /** * Removes and returns the key; `StillReferenced` when a service names * it, `NotFound` when it is not there. @@ -861,8 +925,8 @@ declare class XIDDocument implements ToEnvelope, ToCbor, CborTagged, ToUR, Edgea removeKey(publicKeys: PublicKeys): Key; /** Removes and returns the key without checking services; `undefined` when absent. */ takeKey(publicKeys: PublicKeys): Key | undefined; - /** The key with these public keys; `KeyNotFoundInDocument` unless it is there. */ - expectKey(publicKeys: PublicKeys): Key; + /** `KeyNotFoundInDocument` unless the key with these public keys is there. */ + checkContainsKey(publicKeys: PublicKeys): void; /** Whether the XID derives from this signing key. */ isInceptionSigningKey(signingPublicKey: SigningPublicKey): boolean; /** The key whose signing key the XID derives from. */ @@ -882,25 +946,25 @@ declare class XIDDocument implements ToEnvelope, ToCbor, CborTagged, ToUR, Edgea /** The private keys of a key as an envelope (see `Key.privateKeyEnvelope`). */ privateKeyEnvelopeForKey(publicKeys: PublicKeys, options?: PasswordOptions): Envelope | undefined; /** The inception key's private keys of a parsed envelope, unlocked with the password. */ - static inceptionPrivateKeysFromEnvelope(envelope: Envelope, { password }?: PasswordOptions): PrivateKeys | undefined; + static extractInceptionPrivateKeysFromEnvelope(envelope: Envelope, { password }?: PasswordOptions): PrivateKeys | undefined; /** The delegates (a copied-out array of live delegates). */ get delegates(): readonly Delegate[]; /** Adds a delegate; `Duplicate` when a delegate with that XID is already there. */ addDelegate(delegate: Delegate): void; /** The delegate with this XID. */ - delegate(xid: XID): Delegate | undefined; + findDelegateByXid(xid: XID): Delegate | undefined; /** The delegate whose XID has this reference. */ - delegateByReference(reference: Reference): Delegate | undefined; + findDelegateByReference(reference: Reference): Delegate | undefined; /** Removes and returns the delegate; `StillReferenced` when a service names it, `NotFound` when absent. */ removeDelegate(xid: XID): Delegate; /** Removes and returns the delegate without checking services; `undefined` when absent. */ takeDelegate(xid: XID): Delegate | undefined; - /** The delegate with this XID; `DelegateNotFoundInDocument` unless it is there. */ - expectDelegate(xid: XID): Delegate; + /** `DelegateNotFoundInDocument` unless the delegate with this XID is there. */ + checkContainsDelegate(xid: XID): void; /** The services (a copied-out array of live services). */ get services(): readonly Service[]; /** The service at this URI. */ - service(uri: URI | string): Service | undefined; + findServiceByUri(uri: URI | string): Service | undefined; /** Adds a service; `Duplicate` when a service at that URI is already there. */ addService(service: Service): void; /** Removes and returns the service; `undefined` when absent. */ @@ -908,13 +972,13 @@ declare class XIDDocument implements ToEnvelope, ToCbor, CborTagged, ToUR, Edgea /** Removes and returns the service; `NotFound` when absent. */ removeService(uri: URI | string): Service; /** Every service references known keys and delegates and allows something. */ - expectServicesConsistent(): void; + checkServicesConsistency(): void; /** * `NoReferences` without any key or delegate reference, * `UnknownKeyReference`/`UnknownDelegateReference` for one the document * lacks, `NoPermissions` without an allowed privilege. */ - expectServiceConsistent(service: Service): void; + checkServiceConsistency(service: Service): void; /** Whether any service references this key. */ servicesReferenceKey(publicKeys: PublicKeys): boolean; /** Whether any service references this delegate. */ @@ -926,7 +990,7 @@ declare class XIDDocument implements ToEnvelope, ToCbor, CborTagged, ToUR, Edgea /** Adds an attachment. */ addAttachment({ payload, vendor, conformsTo }: AttachmentInput): void; /** The attachment with this digest. */ - attachment(digest: Digest): Envelope | undefined; + getAttachment(digest: Digest): Envelope | undefined; /** Removes and returns the attachment with this digest. */ removeAttachment(digest: Digest): Envelope | undefined; /** Removes every attachment. */ @@ -939,9 +1003,7 @@ declare class XIDDocument implements ToEnvelope, ToCbor, CborTagged, ToUR, Edgea hasEdges(): boolean; /** Adds an edge envelope. */ addEdge(edgeEnvelope: Envelope): void; - /** The edge with this digest. */ - edge(digest: Digest): Envelope | undefined; - /** `edge(digest)` under the name envelope's `Edgeable` uses. */ + /** The edge with this digest (envelope's `Edgeable`). */ getEdge(digest: Digest): Envelope | undefined; /** Removes and returns the edge with this digest. */ removeEdge(digest: Digest): Envelope | undefined; @@ -956,15 +1018,28 @@ declare class XIDDocument implements ToEnvelope, ToCbor, CborTagged, ToUR, Edgea /** Sets the mark and the generator that continues its chain. */ setProvenanceWithGenerator(generator: ProvenanceMarkGenerator, mark: ProvenanceMark): void; /** - * Advances the chain: with the document's own generator (unlocked with - * the password when locked), or with a provided one when the document - * has none. The generator must continue the current mark's chain at - * the next sequence number. `NoProvenanceMark` without a mark, - * `NoGenerator`/`GeneratorConflict` for the wrong choice, - * `ChainIdMismatch`/`SequenceMismatch` for a generator that does not - * continue the mark; an invalid date is a `TypeError`. + * Advances the chain with the document's own generator, unlocked with + * the password when it is locked; the generator stays in the document. + * `NoProvenanceMark` without a mark, `NoGenerator` without a generator, + * `InvalidPassword` when it is locked and the password is missing or + * wrong, `ChainIdMismatch`/`SequenceMismatch` when the generator does + * not continue the mark at the next sequence number; a `Date` without a + * time is `ProvenanceMark[InvalidDate]`; a date of another kind is a + * `TypeError`. + */ + nextProvenanceMarkWithEmbeddedGenerator({ password, date, info }?: NextProvenanceMarkOptions): void; + /** + * Advances the chain with a generator the caller keeps; the generator + * is advanced in place and not stored. `NoProvenanceMark` without a + * mark, `GeneratorConflict` when the document holds a generator (in the + * clear or locked), `ChainIdMismatch`/`SequenceMismatch` when the + * generator does not continue the mark at the next sequence number; a + * `Date` without a time is `ProvenanceMark[InvalidDate]`; a generator or + * date of another kind is a `TypeError`. */ - nextProvenanceMark({ date, info, password, generator }?: NextProvenanceMarkOptions): void; + nextProvenanceMarkWithProvidedGenerator(generator: ProvenanceMarkGenerator, { date, info }?: ProvidedGeneratorOptions): void; + /** The checks and the step both forms share. */ + private advance; /** * The XID as the subject; `'dereferenceVia'`, `'key'`, `'delegate'`, * `'service'`, `'provenance'`, the extra assertions, attachments and @@ -1033,5 +1108,5 @@ declare class XIDDocument implements ToEnvelope, ToCbor, CborTagged, ToUR, Edgea toString(): string; } //#endregion -export { type AttachmentInput, type ChainIdMismatchDetails, Delegate, type DelegateInput, type DelegateNotFoundDetails, type DelegateParseOptions, type EncryptOptions, type HasPermissions, type ItemDetails, Key, type KeyEnvelopeOptions, type KeyInput, type KeyNotFoundDetails, type NextProvenanceMarkOptions, PRIVILEGES, type ParseXIDDocument, type PasswordOptions, Permissions, type PermissionsInput, type PlainDetails, type Privilege, Provenance, type ProvenanceEnvelopeOptions, type ProvenanceInput, type SequenceMismatchDetails, Service, type ServiceDetails, type ServiceInput, type SignedEnvelopeOptions, type UnexpectedPredicateDetails, type UnknownReferenceDetails, type WrappedDetails, XIDDocument, type XIDDocumentCodec, type XIDDocumentInput, type XIDDocumentLike, type XIDEnvelopeOptions, XIDError, type XIDErrorCode, type XIDErrorDetails, type XIDErrorDetailsByCode, type XIDErrorDetailsFor, type XIDErrorTyped, type XIDGeneratorOptions, type XIDGenesis, type XIDInceptionKey, type XIDInceptionKeyPair, type XIDParseOptions, type XIDPrivateKeyOptions, type XIDRandomOptions, type XIDSigning, type XIDVerifySignature, XID_ERROR_CODES, isPrivilege, privilegeEnvelope, privilegeFromEnvelope, privilegeFromKnownValue, privilegeKnownValue }; +export type { AttachmentInput, ChainIdMismatchDetails, DateInput, DelegateInput, DelegateNotFoundDetails, EmptyValueDetails, EncryptOptions, GeneratorData, HasPermissions, ItemDetails, KeyEnvelopeOptions, KeyInput, KeyNotFoundDetails, NextProvenanceMarkOptions, PasswordOptions, PermissionsInput, PlainDetails, Privilege, ProvenanceEnvelopeOptions, ProvenanceInput, ProvidedGeneratorOptions, SequenceMismatchDetails, ServiceDetails, ServiceInput, SignedEnvelopeOptions, TakenGenerator, UnexpectedPredicateDetails, UnknownReferenceDetails, WrappedDetails, XIDDocumentCodec, XIDDocumentInput, XIDDocumentLike, XIDEnvelopeOptions, XIDErrorCode, XIDErrorDetails, XIDErrorDetailsByCode, XIDErrorDetailsFor, XIDErrorTyped, XIDGeneratorOptions, XIDGenesis, XIDInceptionKey, XIDInceptionKeyPair, XIDParseOptions, XIDPrivateKeyOptions, XIDRandomOptions, XIDSigning, XIDVerifySignature }; //# sourceMappingURL=index.d.mts.map \ No newline at end of file diff --git a/api/xid.api.md b/api/xid.api.md index 213d56f..eccbf0f 100644 --- a/api/xid.api.md +++ b/api/xid.api.md @@ -8,6 +8,7 @@ import { Attachments } from '@blockchaincommons/envelope/attachment'; import { Cbor } from '@blockchaincommons/dcbor'; import { CborCodec } from '@blockchaincommons/dcbor'; import { CborTagged } from '@blockchaincommons/dcbor'; +import { DateInput } from '@blockchaincommons/provenance-mark'; import { Digest } from '@blockchaincommons/components'; import { Edgeable } from '@blockchaincommons/envelope/edge'; import { Edges } from '@blockchaincommons/envelope/edge'; @@ -48,17 +49,24 @@ export interface AttachmentInput { // @public export type ChainIdMismatchDetails = XIDErrorDetailsFor<"ChainIdMismatch">; +export { DateInput } + // @public export class Delegate implements HasPermissions { - allow(privilege: Privilege): void; + addAllow(privilege: Privilege): void; + addDeny(privilege: Privilege): void; + get allow(): ReadonlySet; + clearAllPermissions(): void; clone(): Delegate; get controller(): XIDDocumentLike; - deny(privilege: Privilege): void; + get deny(): ReadonlySet; equals(other: Delegate): boolean; static from(controller: XIDDocumentLike, input?: DelegateInput): Delegate; - static fromEnvelope(envelope: Envelope, input?: DelegateParseOptions): Delegate; + static fromEnvelope(envelope: Envelope): Delegate; get permissions(): Permissions; get reference(): Reference; + removeAllow(privilege: Privilege): void; + removeDeny(privilege: Privilege): void; toEnvelope(): Envelope; get xid(): XID; } @@ -72,9 +80,7 @@ export interface DelegateInput { export type DelegateNotFoundDetails = XIDErrorDetailsFor<"DelegateNotFoundInDocument">; // @public -export interface DelegateParseOptions { - parseDocument?: ParseXIDDocument | undefined; -} +export type EmptyValueDetails = XIDErrorDetailsFor<"EmptyValue">; // @public export interface EncryptOptions { @@ -82,27 +88,45 @@ export interface EncryptOptions { method?: KeyDerivationMethod | undefined; } +// @public +export type GeneratorData = { + type: "decrypted"; + generator: ProvenanceMarkGenerator; +} | { + type: "encrypted"; + envelope: Envelope; +}; + // @public export interface HasPermissions { - allow(privilege: Privilege): void; - deny(privilege: Privilege): void; + addAllow(privilege: Privilege): void; + addDeny(privilege: Privilege): void; + readonly allow: ReadonlySet; + clearAllPermissions(): void; + readonly deny: ReadonlySet; readonly permissions: Permissions; + removeAllow(privilege: Privilege): void; + removeDeny(privilege: Privilege): void; } // @public export function isPrivilege(value: unknown): value is Privilege; // @public -export type ItemDetails = XIDErrorDetailsFor<"Duplicate" | "NotFound" | "StillReferenced" | "EmptyValue">; +export type ItemDetails = XIDErrorDetailsFor<"Duplicate" | "NotFound" | "StillReferenced">; // @public export class Key implements HasPermissions, Verifier { + addAllow(privilege: Privilege): void; + addDeny(privilege: Privilege): void; addEndpoint(endpoint: URI | string): void; addNickname(name: string): void; - allow(privilege: Privilege): void; + addPermission(privilege: Privilege): void; + get allow(): ReadonlySet; static allowAll(publicKeys: PublicKeys): Key; + clearAllPermissions(): void; clone(): Key; - deny(privilege: Privilege): void; + get deny(): ReadonlySet; encapsulationPublicKey(): EncapsulationPublicKey; get endpoints(): ReadonlySet; equals(other: Key): boolean; @@ -118,6 +142,9 @@ export class Key implements HasPermissions, Verifier { get privateKeySalt(): Salt | undefined; get publicKeys(): PublicKeys; get reference(): Reference; + removeAllow(privilege: Privilege): void; + removeDeny(privilege: Privilege): void; + removeEndpoint(endpoint: URI | string): boolean; setNickname(name: string): void; get signingPublicKey(): SigningPublicKey; toEnvelope(input?: KeyEnvelopeOptions): Envelope; @@ -142,14 +169,10 @@ export type KeyNotFoundDetails = XIDErrorDetailsFor<"KeyNotFoundInDocument">; // @public export interface NextProvenanceMarkOptions extends PasswordOptions { - date?: Date | undefined; - generator?: ProvenanceMarkGenerator | undefined; + date?: DateInput | undefined; info?: Cbor | undefined; } -// @public -export type ParseXIDDocument = (envelope: Envelope) => XIDDocumentLike; - // @public export interface PasswordOptions { password?: Uint8Array | string | undefined; @@ -162,14 +185,12 @@ export class Permissions { addToEnvelope(envelope: Envelope): Envelope; get allow(): ReadonlySet; static allowAll(): Permissions; - clear(): void; + clearAllPermissions(): void; clone(): Permissions; get deny(): ReadonlySet; equals(other: Permissions): boolean; static from(input?: PermissionsInput): Permissions; static fromEnvelope(envelope: Envelope): Permissions; - isAllowed(privilege: Privilege): boolean; - isDenied(privilege: Privilege): boolean; removeAllow(privilege: Privilege): void; removeDeny(privilege: Privilege): void; } @@ -215,7 +236,7 @@ export class Provenance { get mark(): ProvenanceMark; setGenerator(generator: ProvenanceMarkGenerator): void; setMark(mark: ProvenanceMark): void; - takeGenerator(): boolean; + takeGenerator(): TakenGenerator | undefined; toEnvelope(input?: ProvenanceEnvelopeOptions): Envelope; unlockGenerator(input?: PasswordOptions): ProvenanceMarkGenerator | undefined; } @@ -230,27 +251,34 @@ export interface ProvenanceInput { generator?: ProvenanceMarkGenerator | undefined; } +// @public +export interface ProvidedGeneratorOptions { + date?: DateInput | undefined; + info?: Cbor | undefined; +} + // @public export type SequenceMismatchDetails = XIDErrorDetailsFor<"SequenceMismatch">; // @public export class Service implements HasPermissions { + addAllow(privilege: Privilege): void; addCapability(capability: string): void; addDelegate(delegate: { readonly xid: XID; }): void; addDelegateReference(delegateReference: Reference): void; - addDelegateReferenceHex(delegateReferenceHex: string): void; + addDeny(privilege: Privilege): void; addKey(key: { readonly publicKeys: PublicKeys; }): void; addKeyReference(keyReference: Reference): void; - addKeyReferenceHex(keyReferenceHex: string): void; - allow(privilege: Privilege): void; + get allow(): ReadonlySet; get capability(): string; + clearAllPermissions(): void; clone(): Service; get delegateReferences(): ReadonlySet; - deny(privilege: Privilege): void; + get deny(): ReadonlySet; equals(other: Service): boolean; static from(uri: URI | string, input?: ServiceInput): Service; static fromEnvelope(envelope: Envelope): Service; @@ -259,6 +287,10 @@ export class Service implements HasPermissions { get keyReferences(): ReadonlySet; get name(): string; get permissions(): Permissions; + removeAllow(privilege: Privilege): void; + removeDelegateReference(reference: Reference): boolean; + removeDeny(privilege: Privilege): void; + removeKeyReference(reference: Reference): boolean; setCapability(capability: string): void; setName(name: string): void; toEnvelope(): Envelope; @@ -282,6 +314,12 @@ export interface SignedEnvelopeOptions { privateKeys?: XIDPrivateKeyOptions | undefined; } +// @public +export interface TakenGenerator { + readonly data: GeneratorData; + readonly salt: Salt; +} + // @public export type UnexpectedPredicateDetails = XIDErrorDetailsFor<"UnexpectedPredicate">; @@ -302,45 +340,46 @@ export class XIDDocument implements ToEnvelope, ToCbor, CborTagged, ToUR, Edgeab addKey(key: Key): void; addResolutionMethod(method: URI | string): void; addService(service: Service): void; - attachment(digest: Digest): Envelope | undefined; get attachments(): Attachments; cborTags(): Tag[]; + checkContainsDelegate(xid: XID): void; + checkContainsKey(publicKeys: PublicKeys): void; + checkServiceConsistency(service: Service): void; + checkServicesConsistency(): void; clearAttachments(): void; clearEdges(): void; clone(): XIDDocument; static get codec(): XIDDocumentCodec; - delegate(xid: XID): Delegate | undefined; - delegateByReference(reference: Reference): Delegate | undefined; get delegates(): readonly Delegate[]; - edge(digest: Digest): Envelope | undefined; edges(): Edges; edgesMut(): Edges; get encryptionKey(): EncapsulationPublicKey | undefined; equals(other: XIDDocument): boolean; - expectDelegate(xid: XID): Delegate; - expectKey(publicKeys: PublicKeys): Key; - expectServiceConsistent(service: Service): void; - expectServicesConsistent(): void; get extraAssertions(): readonly Envelope[]; + static extractInceptionPrivateKeysFromEnvelope(envelope: Envelope, input?: PasswordOptions): PrivateKeys | undefined; + findDelegateByReference(reference: Reference): Delegate | undefined; + findDelegateByXid(xid: XID): Delegate | undefined; + findKeyByPublicKeys(publicKeys: PublicKeys): Key | undefined; + findKeyByReference(reference: Reference): Key | undefined; + findServiceByUri(uri: URI | string): Service | undefined; static from(input: XIDDocumentInput): XIDDocument; static fromCbor(cborValue: Cbor): XIDDocument; static fromEnvelope(envelope: Envelope, input?: XIDParseOptions): XIDDocument; static fromUntaggedCbor(cborValue: Cbor): XIDDocument; static fromUR(ur: UR): XIDDocument; static fromXid(xid: XID): XIDDocument; + getAttachment(digest: Digest): Envelope | undefined; getEdge(digest: Digest): Envelope | undefined; get hasAttachments(): boolean; hasEdges(): boolean; get inceptionKey(): Key | undefined; get inceptionPrivateKeys(): PrivateKeys | undefined; - static inceptionPrivateKeysFromEnvelope(envelope: Envelope, input?: PasswordOptions): PrivateKeys | undefined; get inceptionSigningKey(): SigningPublicKey | undefined; get isEmpty(): boolean; isInceptionSigningKey(signingPublicKey: SigningPublicKey): boolean; - key(publicKeys: PublicKeys): Key | undefined; - keyByReference(reference: Reference): Key | undefined; get keys(): readonly Key[]; - nextProvenanceMark(input?: NextProvenanceMarkOptions): void; + nextProvenanceMarkWithEmbeddedGenerator(input?: NextProvenanceMarkOptions): void; + nextProvenanceMarkWithProvidedGenerator(generator: ProvenanceMarkGenerator, input?: ProvidedGeneratorOptions): void; privateKeyEnvelopeForKey(publicKeys: PublicKeys, options?: PasswordOptions): Envelope | undefined; get provenance(): ProvenanceMark | undefined; get provenanceGenerator(): ProvenanceMarkGenerator | undefined; @@ -351,10 +390,9 @@ export class XIDDocument implements ToEnvelope, ToCbor, CborTagged, ToUR, Edgeab removeEdge(digest: Digest): Envelope | undefined; removeInceptionKey(): Key | undefined; removeKey(publicKeys: PublicKeys): Key; - removeResolutionMethod(method: URI | string): boolean; + removeResolutionMethod(method: URI | string): URI | undefined; removeService(uri: URI | string): Service; get resolutionMethods(): ReadonlySet; - service(uri: URI | string): Service | undefined; get services(): readonly Service[]; servicesReferenceDelegate(xid: XID): boolean; servicesReferenceKey(publicKeys: PublicKeys): boolean; @@ -464,7 +502,7 @@ export interface XIDErrorDetailsByCode { readonly item: string; }; EmptyValue: { - readonly item: string; + readonly field: string; }; EnvelopeNotSigned: unknown; EnvelopeParsing: { @@ -532,7 +570,7 @@ export type XIDGeneratorOptions = "omit" | "include" | "elide" | EncryptOptions; // @public export interface XIDGenesis { - date?: Date | undefined; + date?: DateInput | undefined; info?: Cbor | undefined; passphrase?: string | undefined; resolution?: ProvenanceMarkResolution | undefined; diff --git a/bench/benchmark.mjs b/bench/benchmark.mjs new file mode 100644 index 0000000..8361d50 --- /dev/null +++ b/bench/benchmark.mjs @@ -0,0 +1,51 @@ +// Bench: build a document (inception key, genesis mark, a key, a service, a +// delegate), sign it into an envelope, parse it back verified, advance the +// provenance chain. Run: bun run bench (builds dist first) +import { performance } from "node:perf_hooks"; +import { PrivateKeyBase } from "@blockchaincommons/components"; +import { DirectoryConfig, setDirectoryConfig } from "@blockchaincommons/known-values"; +import { registerTags } from "@blockchaincommons/provenance-mark"; +import { Key, Service, XIDDocument } from "../dist/index.mjs"; + +setDirectoryConfig(new DirectoryConfig()); +registerTags(); + +const time = (label, iterations, fn) => { + fn(); + const t0 = performance.now(); + for (let i = 0; i < iterations; i++) fn(); + const ms = (performance.now() - t0) / iterations; + console.log(`${label.padEnd(48)} ${ms.toFixed(3)} ms/op`); +}; + +const inception = PrivateKeyBase.from(Uint8Array.from({ length: 32 }, (_, i) => i + 1)); +const other = PrivateKeyBase.from(Uint8Array.from({ length: 32 }, (_, i) => 255 - i)); +const build = () => { + const doc = XIDDocument.from({ + inceptionKey: inception, + genesis: { passphrase: "bench", date: new Date("2023-06-20T12:00:00Z") }, + }); + doc.addKey(Key.fromPrivateKeyBase(other)); + const service = Service.from("https://example.com/api"); + service.addKey(doc.inceptionKey); + service.addAllow("All"); + doc.addService(service); + return doc; +}; +time("build document with genesis, key, service", 50, build); +const doc = build(); +time("toEnvelope signed, private keys included", 50, () => + doc.toEnvelope({ privateKeys: "include", generator: "include", sign: "inception" }), +); +const envelope = doc.toEnvelope({ + privateKeys: "include", + generator: "include", + sign: "inception", +}); +time("fromEnvelope verified", 50, () => + XIDDocument.fromEnvelope(envelope, { verify: "inception" }), +); +time("nextProvenanceMarkWithEmbeddedGenerator", 50, () => { + const d = XIDDocument.fromEnvelope(envelope); + d.nextProvenanceMarkWithEmbeddedGenerator({ date: new Date("2023-06-21T12:00:00Z") }); +}); diff --git a/bun.lock b/bun.lock deleted file mode 100644 index c15011e..0000000 --- a/bun.lock +++ /dev/null @@ -1,830 +0,0 @@ -{ - "lockfileVersion": 2, - "configVersion": 1, - "workspaces": { - "": { - "name": "@blockchaincommons/xid", - "devDependencies": { - "@arethetypeswrong/cli": "^0.18.5", - "@eslint/js": "^10.0.1", - "@microsoft/api-extractor": "^7.58.9", - "@size-limit/preset-small-lib": "^13.0.3", - "@types/node": "^26.1.1", - "@typescript-eslint/eslint-plugin": "^8.64.0", - "@typescript-eslint/parser": "^8.64.0", - "@vitest/coverage-v8": "^4.1.10", - "ajv": "^8.20.0", - "eslint": "^10.7.0", - "prettier": "3.9.6", - "publint": "^0.3.21", - "size-limit": "^13.0.3", - "tsdown": "^0.22.8", - "typedoc": "^0.28.20", - "typescript": "^7.0.2", - "typescript6": "npm:typescript@^6.0.3", - "vitest": "^4.1.10", - }, - }, - }, - "packages": { - "@andrewbranch/untar.js": ["@andrewbranch/untar.js@1.0.4", "", {}, "sha512-pVXSwPsLuw8IGLo2Di0EaOfsk+ntVvpkk942J/sHYIkwvtKUakEcPh7HBgZ6tuimgzKSEHgCvO4XgQ05DEbwDw=="], - - "@arethetypeswrong/cli": ["@arethetypeswrong/cli@0.18.5", "", { "dependencies": { "@arethetypeswrong/core": "0.18.5", "chalk": "^4.1.2", "cli-table3": "^0.6.3", "commander": "^10.0.1", "marked": "^9.1.2", "marked-terminal": "^7.1.0", "semver": "^7.5.4" }, "bin": { "attw": "./dist/index.js" } }, "sha512-gM+8vRsQOD/Uc7EnBedUhkG5OCsDWE4uoak5QvomGpMpaky0Eh41p04nIMgrWb8EOmqZUJGc6zz9hsP6E56R7g=="], - - "@arethetypeswrong/core": ["@arethetypeswrong/core@0.18.5", "", { "dependencies": { "@andrewbranch/untar.js": "^1.0.3", "@loaderkit/resolve": "^1.0.2", "cjs-module-lexer": "^1.2.3", "fflate": "^0.8.3", "lru-cache": "^11.0.1", "semver": "^7.5.4", "typescript": "5.6.1-rc", "validate-npm-package-name": "^5.0.0" } }, "sha512-9ytjzGwxjm9Uz7I9avfbt5vlQt6uk9uRRESzJjqrznl6WKvI6dwYTo+vJ3U02Wrq/mR3iql/PzhvHhKdJIAjDQ=="], - - "@babel/helper-string-parser": ["@babel/helper-string-parser@7.29.7", "", {}, "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw=="], - - "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.29.7", "", {}, "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg=="], - - "@babel/parser": ["@babel/parser@7.29.8", "", { "dependencies": { "@babel/types": "^7.29.8" }, "bin": "./bin/babel-parser.js" }, "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA=="], - - "@babel/types": ["@babel/types@7.29.8", "", { "dependencies": { "@babel/helper-string-parser": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7" } }, "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg=="], - - "@bcoe/v8-coverage": ["@bcoe/v8-coverage@1.0.2", "", {}, "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA=="], - - "@braidai/lang": ["@braidai/lang@1.1.2", "", {}, "sha512-qBcknbBufNHlui137Hft8xauQMTZDKdophmLFv05r2eNmdIv/MlPuP4TdUknHG68UdWLgVZwgxVe735HzJNIwA=="], - - "@cacheable/memory": ["@cacheable/memory@2.2.0", "", { "dependencies": { "@cacheable/utils": "^2.5.0", "@keyv/bigmap": "^1.3.1", "hookified": "^1.15.1", "keyv": "^5.6.0" } }, "sha512-CTLKqLItRCEixEAewD3/j9DB3/o96gpTPD4eJ1v+DGOlxZRZncRQkGYqqnAGCscYd6RNeXfGeiuCphsPtqyIfQ=="], - - "@cacheable/utils": ["@cacheable/utils@2.5.0", "", { "dependencies": { "hashery": "^1.5.1", "keyv": "^5.6.0" } }, "sha512-buipgOVDkkPXNR5+xBpDw7Zk2n1EvU7qBJCNUcL7rhQ//kfpOXPAvQ511Os0vpLYJ1pZnvudNytkQt2hst3wqA=="], - - "@colors/colors": ["@colors/colors@1.5.0", "", {}, "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ=="], - - "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.28.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ=="], - - "@esbuild/android-arm": ["@esbuild/android-arm@0.28.2", "", { "os": "android", "cpu": "arm" }, "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg=="], - - "@esbuild/android-arm64": ["@esbuild/android-arm64@0.28.2", "", { "os": "android", "cpu": "arm64" }, "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A=="], - - "@esbuild/android-x64": ["@esbuild/android-x64@0.28.2", "", { "os": "android", "cpu": "x64" }, "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q=="], - - "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.28.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw=="], - - "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.28.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw=="], - - "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.28.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw=="], - - "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.28.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg=="], - - "@esbuild/linux-arm": ["@esbuild/linux-arm@0.28.2", "", { "os": "linux", "cpu": "arm" }, "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w=="], - - "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.28.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug=="], - - "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.28.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ=="], - - "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ=="], - - "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA=="], - - "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.28.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ=="], - - "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA=="], - - "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.28.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg=="], - - "@esbuild/linux-x64": ["@esbuild/linux-x64@0.28.2", "", { "os": "linux", "cpu": "x64" }, "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ=="], - - "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.28.2", "", { "os": "none", "cpu": "arm64" }, "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw=="], - - "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.28.2", "", { "os": "none", "cpu": "x64" }, "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw=="], - - "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.28.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ=="], - - "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.28.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw=="], - - "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.28.2", "", { "os": "none", "cpu": "arm64" }, "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q=="], - - "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.28.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g=="], - - "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.28.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ=="], - - "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.28.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA=="], - - "@esbuild/win32-x64": ["@esbuild/win32-x64@0.28.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g=="], - - "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.10.1", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg=="], - - "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.2", "", {}, "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew=="], - - "@eslint/config-array": ["@eslint/config-array@0.23.5", "", { "dependencies": { "@eslint/object-schema": "^3.0.5", "debug": "^4.3.1", "minimatch": "^10.2.4" } }, "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA=="], - - "@eslint/config-helpers": ["@eslint/config-helpers@0.7.0", "", { "dependencies": { "@eslint/core": "^1.2.1" } }, "sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw=="], - - "@eslint/core": ["@eslint/core@1.2.1", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ=="], - - "@eslint/js": ["@eslint/js@10.0.1", "", { "peerDependencies": { "eslint": "^10.0.0" }, "optionalPeers": ["eslint"] }, "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA=="], - - "@eslint/object-schema": ["@eslint/object-schema@3.0.5", "", {}, "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw=="], - - "@eslint/plugin-kit": ["@eslint/plugin-kit@0.7.3", "", { "dependencies": { "@eslint/core": "^1.2.1", "levn": "^0.4.1" } }, "sha512-IkO+/KEUvwbVpiURZg+P7zF74z5Jxe0UgJxVni+RtoHQ6IZieXaO02kmadomap/q+l6bc/jdPGGqTjhuZnuz1Q=="], - - "@gerrit0/mini-shiki": ["@gerrit0/mini-shiki@3.23.0", "", { "dependencies": { "@shikijs/engine-oniguruma": "^3.23.0", "@shikijs/langs": "^3.23.0", "@shikijs/themes": "^3.23.0", "@shikijs/types": "^3.23.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-bEMORlG0cqdjVyCEuU0cDQbORWX+kYCeo0kV1lbxF5bt4r7SID2l9bqsxJEM0zndaxpOUT7riCyIVEuqq/Ynxg=="], - - "@humanfs/core": ["@humanfs/core@0.19.2", "", { "dependencies": { "@humanfs/types": "^0.15.0" } }, "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA=="], - - "@humanfs/node": ["@humanfs/node@0.16.8", "", { "dependencies": { "@humanfs/core": "^0.19.2", "@humanfs/types": "^0.15.0", "@humanwhocodes/retry": "^0.4.0" } }, "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ=="], - - "@humanfs/types": ["@humanfs/types@0.15.0", "", {}, "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q=="], - - "@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="], - - "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="], - - "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], - - "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.6.0", "", {}, "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw=="], - - "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], - - "@keyv/bigmap": ["@keyv/bigmap@1.3.1", "", { "dependencies": { "hashery": "^1.4.0", "hookified": "^1.15.0" }, "peerDependencies": { "keyv": "^5.6.0" } }, "sha512-WbzE9sdmQtKy8vrNPa9BRnwZh5UF4s1KTmSK0KUVLo3eff5BlQNNWDnFOouNpKfPKDnms9xynJjsMYjMaT/aFQ=="], - - "@keyv/serialize": ["@keyv/serialize@1.1.1", "", {}, "sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA=="], - - "@loaderkit/resolve": ["@loaderkit/resolve@1.0.6", "", { "dependencies": { "@braidai/lang": "^1.0.0" } }, "sha512-G8FdIoF5CypfwmD9rl8BXod5HDn8JqB0CCNBXDTaRZ+yRYhARrrSToX1zg1zy9jX3zLqigsELwhT4gNtkdQAUg=="], - - "@microsoft/api-extractor": ["@microsoft/api-extractor@7.59.1", "", { "dependencies": { "@microsoft/api-extractor-model": "7.33.12", "@microsoft/tsdoc": "~0.16.0", "@microsoft/tsdoc-config": "~0.18.1", "@rushstack/node-core-library": "5.24.1", "@rushstack/rig-package": "0.7.3", "@rushstack/terminal": "0.24.4", "@rushstack/ts-command-line": "5.3.14", "diff": "~8.0.2", "minimatch": "10.2.3", "resolve": "~1.22.1", "semver": "~7.7.4", "source-map": "~0.6.1", "typescript": "5.9.3" }, "bin": { "api-extractor": "bin/api-extractor" } }, "sha512-GjRUqx1MTY7xuH36urwASkfBPzrdxYG+irVeV7C9JEdRtn509AgMmwit/BhvztQzIoFk9vhFDTVYOp2cjw+9Uw=="], - - "@microsoft/api-extractor-model": ["@microsoft/api-extractor-model@7.33.12", "", { "dependencies": { "@microsoft/tsdoc": "~0.16.0", "@microsoft/tsdoc-config": "~0.18.1", "@rushstack/node-core-library": "5.24.1" } }, "sha512-TdKOYgwf98xLjNW+y3iXIiCf4ZLQbilGAlqkMTTAqqAWfgRXAn9YCSGMsaiB1U7OPRvslUWg6n08EqQPbP93tA=="], - - "@microsoft/tsdoc": ["@microsoft/tsdoc@0.16.0", "", {}, "sha512-xgAyonlVVS+q7Vc7qLW0UrJU7rSFcETRWsqdXZtjzRU8dF+6CkozTK4V4y1LwOX7j8r/vHphjDeMeGI4tNGeGA=="], - - "@microsoft/tsdoc-config": ["@microsoft/tsdoc-config@0.18.1", "", { "dependencies": { "@microsoft/tsdoc": "0.16.0", "ajv": "~8.18.0", "jju": "~1.4.0", "resolve": "~1.22.2" } }, "sha512-9brPoVdfN9k9g0dcWkFeA7IH9bbcttzDJlXvkf8b2OBzd5MueR1V2wkKBL0abn0otvmkHJC6aapBOTJDDeMCZg=="], - - "@oxc-project/types": ["@oxc-project/types@0.149.0", "", {}, "sha512-Efcc+iF0j3Bf67YjEqIqWXbX5XddXoK/Mw4K1/JuXwRCZ8N16VR7iT23nlCc9XrveFVh/E5Rqs2StT0V8v9LdA=="], - - "@publint/pack": ["@publint/pack@0.1.7", "", { "dependencies": { "tinyexec": "^1.3.0" } }, "sha512-4EDEmvxWtgsCnnVeBvtFIFZtUhPPt1+bA9JrSwU4Sa//6oKtzCSlGGXYJr44OD9aGISymbieJ4mCKHUygUDU+g=="], - - "@quansync/fs": ["@quansync/fs@1.0.0", "", { "dependencies": { "quansync": "^1.0.0" } }, "sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ=="], - - "@rolldown/binding-android-arm-eabi": ["@rolldown/binding-android-arm-eabi@1.2.8", "", { "os": "android", "cpu": "arm" }, "sha512-tN5aztYkKCte4i5SIrrz5yK/HMjEuCqCSCJa418jOV8tZ1cBY3YF2otxB1ktPxzsLA1BeTqwapK0bfjxNvHJVw=="], - - "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.2.8", "", { "os": "android", "cpu": "arm64" }, "sha512-dIYTWl9XprMUiQFoc55KUyk/oS8SKYH3zFl0LTR7RT0Xj4hgSVyuJcroH8JUu8RcpF8fTB6E0aOwCkZoYPcDSQ=="], - - "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.2.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-PCSDQGXD2IyTEFrcgPyBM8jJuGmrbCMuoIOXdbEGVemruKACXoLQJrb+A45Z0L5t1RQkdfJprAYPkikbh7dzdA=="], - - "@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.2.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-Uk7lRsGhPFHVX/sAUC6D5H9Ol30dFHd6iquokll2th3LpdJ3F5CzQB+7DHn0Ri2mG+U7k2zXiPHDrwZenXhwSA=="], - - "@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.2.8", "", { "os": "freebsd", "cpu": "x64" }, "sha512-DjszaTEVogPqA5bYzsEeqDCQxbcp2fexQwKcRspYji2yzR68fCf+e4fx6kBSRDwX5/brZaHw/hWS9+A/+/w9sQ=="], - - "@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.2.8", "", { "os": "linux", "cpu": "arm" }, "sha512-zmwa7FTmdzB6aaEEuuls18H6Ap5JmJPSoPTuXixeJZV6tG40SyLkApQtz1g8ptZtiEKqj9OM0oNLPh1AgvE31Q=="], - - "@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.2.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-KdYQDPHwJVnbFwdTGMgxsI9SqblBlz6STGM+w1We/d5B8OWWidYH0MwkU/uA1wM5fIpO2MkOVxXrNzzuZhw9ew=="], - - "@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.2.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-jFJTifHnNPY+yzOoNZQfSIysrVyXzEQPhPnOUjmD1bcQGHH6s7c8cViKWar8YplQImE5N9JRqMCLrM2CdxOrZA=="], - - "@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.2.8", "", { "os": "linux", "cpu": "ppc64" }, "sha512-FhiOziBDWPBjbcmRzfLyIJnaP7AVMFXT7YCXPjXxj7wKU3vx24RjrCNN/zjvVa+N2vVoHJwCoUBvsrN/DG3zIA=="], - - "@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.2.8", "", { "os": "linux", "cpu": "s390x" }, "sha512-WnHfADMzOV2Y55wlx1hzzQnar/wDt/VdvWSD99r18Mz9ylNieIGOkRx3UV21h7m/eJvjySYJkO26VvGNFkwsIQ=="], - - "@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.2.8", "", { "os": "linux", "cpu": "x64" }, "sha512-H9tRr5ibfXFVLxbPOseVewewFpl28zcEdjRDt2FTUZU7odxP0gEv1ki4/kGmcGOh78oRwZuuQllGLZ9zTJp84g=="], - - "@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.2.8", "", { "os": "linux", "cpu": "x64" }, "sha512-UefiqfM3D6IVNlZ8tSGs9+Ejjud2T+oxO0IHADU45Y+lyEjD2dVFyZHbkfX0LUb5Zugo/oIv1eCO/KVYhgYJYA=="], - - "@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.2.8", "", { "os": "none", "cpu": "arm64" }, "sha512-637Ke4kWSy6rp9cxQ9gMOXlxPgIw/c1beASV4M//3+9I4uwBVOOl74G+e3zyU3u19U7RkRl/HuewixZ/Z6+Rjg=="], - - "@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.2.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-xWBkPOF1Q9k/Gv1nQXnVdLxKu74jXppuOM4Z3mnypVUJJJwLsMl7hNJGRAUJoG8A5MgOI1ACKM+wBFxSJzKy4A=="], - - "@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.2.8", "", { "os": "win32", "cpu": "x64" }, "sha512-uz2ZvfgXbxqNwijjjbxrnvALwpyODDcgc1T1N8N3rf/DXKQmaFwmB4LX4yyjggpwN2obdQLb2rgirX5ffCWYng=="], - - "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.1", "", {}, "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw=="], - - "@rushstack/node-core-library": ["@rushstack/node-core-library@5.24.1", "", { "dependencies": { "ajv": "~8.20.0", "ajv-draft-04": "~1.0.0", "ajv-formats": "~3.0.1", "fs-extra": "~11.3.0", "import-lazy": "~4.0.0", "jju": "~1.4.0", "resolve": "~1.22.1", "semver": "~7.7.4" }, "peerDependencies": { "@types/node": "*" }, "optionalPeers": ["@types/node"] }, "sha512-ZlOrzv92MwnsCXA45qWfDj4L/kTasKghXezu+M2WmdtkbnXyPnZSCovfeBZx1Yc5qm+LkElbLw6IeSSWZDhZUg=="], - - "@rushstack/problem-matcher": ["@rushstack/problem-matcher@0.2.1", "", { "peerDependencies": { "@types/node": "*" }, "optionalPeers": ["@types/node"] }, "sha512-gulfhBs6n+I5b7DvjKRfhMGyUejtSgOHTclF/eONr8hcgF1APEDjhxIsfdUYYMzC3rvLwGluqLjbwCFZ8nxrog=="], - - "@rushstack/rig-package": ["@rushstack/rig-package@0.7.3", "", { "dependencies": { "jju": "~1.4.0", "resolve": "~1.22.1" } }, "sha512-aAA518n6wxxjCfnTAOjQnm7ngNE0FVHxHAw2pxKlIhxrMn0XQjGcXKF0oKWpjBgJOmsaJpVob/v+zr3zxgPWuA=="], - - "@rushstack/terminal": ["@rushstack/terminal@0.24.4", "", { "dependencies": { "@rushstack/node-core-library": "5.24.1", "@rushstack/problem-matcher": "0.2.1", "supports-color": "~8.1.1" }, "peerDependencies": { "@types/node": "*" }, "optionalPeers": ["@types/node"] }, "sha512-3fRBWK0IMY293lBx5ycgit1DTMUi+nhOjALHlrIad9hQsqzM9Ak+XdBI1gJ/tZPxW+LraeAc4SsmMdcOflBmAQ=="], - - "@rushstack/ts-command-line": ["@rushstack/ts-command-line@5.3.14", "", { "dependencies": { "@rushstack/terminal": "0.24.4", "@types/argparse": "1.0.38", "argparse": "~1.0.9", "string-argv": "~0.3.1" } }, "sha512-lT2JKZk2dukBMp4GFOh4RaDfVzpZehGgQOGpzpSliUn317NgEmOOCXyd7/d0eU46HHsbRxizP83GAm39s0lAlg=="], - - "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g=="], - - "@shikijs/langs": ["@shikijs/langs@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0" } }, "sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg=="], - - "@shikijs/themes": ["@shikijs/themes@3.23.0", "", { "dependencies": { "@shikijs/types": "3.23.0" } }, "sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA=="], - - "@shikijs/types": ["@shikijs/types@3.23.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ=="], - - "@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="], - - "@sindresorhus/is": ["@sindresorhus/is@4.6.0", "", {}, "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw=="], - - "@size-limit/esbuild": ["@size-limit/esbuild@13.0.3", "", { "dependencies": { "esbuild": "^0.28.1", "nanoid": "^6.0.0" }, "peerDependencies": { "size-limit": "13.0.3" } }, "sha512-g24wsTxM3N/SaGv1MiiDjTShNrIna1WCNJ7NXMrlsWBHWv1OL0nCyllR1bDDHf+gV41lF7QxX7vknswoOr71DQ=="], - - "@size-limit/file": ["@size-limit/file@13.0.3", "", { "peerDependencies": { "size-limit": "13.0.3" } }, "sha512-PWTITIXH5p9aGIf6qq2Fruihn/b9nBQyfkyoAyb6DzFJgS1Ek9MSPJYKxKFLO8jdo0aqSgBPd3sevbS6PyBiJw=="], - - "@size-limit/preset-small-lib": ["@size-limit/preset-small-lib@13.0.3", "", { "dependencies": { "@size-limit/esbuild": "13.0.3", "@size-limit/file": "13.0.3", "size-limit": "13.0.3" } }, "sha512-rqKn1+JkVF5ckZRmcxeQPZ8g0e9Fqddh6bjmDotijXJtN40KJQ+5TG6pTiYq3RaA4nkuEkixHULpDBGcgAARAg=="], - - "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], - - "@types/argparse": ["@types/argparse@1.0.38", "", {}, "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA=="], - - "@types/chai": ["@types/chai@5.2.3", "", { "dependencies": { "@types/deep-eql": "*", "assertion-error": "^2.0.1" } }, "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA=="], - - "@types/deep-eql": ["@types/deep-eql@4.0.2", "", {}, "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw=="], - - "@types/esrecurse": ["@types/esrecurse@4.3.1", "", {}, "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw=="], - - "@types/estree": ["@types/estree@1.0.9", "", {}, "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg=="], - - "@types/hast": ["@types/hast@3.0.5", "", { "dependencies": { "@types/unist": "*" } }, "sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g=="], - - "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], - - "@types/node": ["@types/node@26.5.1", "", { "dependencies": { "undici-types": "~8.9.0" } }, "sha512-CzNm2FezW4VR/LjG6yUdiEgLE/rAQ9Slj5gCu/C2VrdcW7I0ahNZ8DRbHT7zOZ6r3ONgd/bsQIeSaoDGrd1C6g=="], - - "@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="], - - "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.70.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.70.0", "@typescript-eslint/type-utils": "8.70.0", "@typescript-eslint/utils": "8.70.0", "@typescript-eslint/visitor-keys": "8.70.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.70.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-/v8HZt6RlyIZxB3ntehELOcUcfxKPVGWXnQdJuHRmzrqgF8nQypcC/oxGW+Ot4VGKDq81XugPKxx0n5PBtf9PA=="], - - "@typescript-eslint/parser": ["@typescript-eslint/parser@8.70.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.70.0", "@typescript-eslint/types": "8.70.0", "@typescript-eslint/typescript-estree": "8.70.0", "@typescript-eslint/visitor-keys": "8.70.0", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-zYvrmj9Yxd63UGaXw+kdt6A0F0s0qveJyuatIM77bYC2DE4pgmg7a50u8LR7PRtXd0x+h+Tl3eXabGm06SWd3Q=="], - - "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.70.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.70.0", "@typescript-eslint/types": "^8.70.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-hFHbTNqhU9G+2eKFXCBVb1tjFT/LceiJ4+HfLO4pTpDI0KHi6iajpcFFkaSQ9gXmCh7n82A0PthaayEdN6mspQ=="], - - "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.70.0", "", { "dependencies": { "@typescript-eslint/types": "8.70.0", "@typescript-eslint/visitor-keys": "8.70.0" } }, "sha512-8nP3Kwh5hlgZ4FicGvmznAmJe8UL4sdU8tLukrPaMuQmDuk4Y8xYfzu/aYZW4xT2JCgc7H/TpDI5cGlxcWJSqQ=="], - - "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.70.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-adnkeeNq9Sq1sUf4+FRVc0KdgYghzsgFpZSQVZVvY0LCuUuN0FnQgyGzCJeC4fW1cdXseBAjU2EOqUIjbNcZUw=="], - - "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.70.0", "", { "dependencies": { "@typescript-eslint/types": "8.70.0", "@typescript-eslint/typescript-estree": "8.70.0", "@typescript-eslint/utils": "8.70.0", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-NUMKIhYVaVIVLnRL9CRt+VVcuLgSHUCpXn4/+K8wql+vdInUzvx8BjUO1oJ7cG9shjFJKtF8F8Hh2kCh3/KBVw=="], - - "@typescript-eslint/types": ["@typescript-eslint/types@8.70.0", "", {}, "sha512-asTOIYhDg4zdzOScCyaytrsV3cR6B4ecPQlXw/dJIm7J/MZTtCtfVII9JD8Geh4jTCrK/Xe6cg5UevoleMcoJQ=="], - - "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.70.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.70.0", "@typescript-eslint/tsconfig-utils": "8.70.0", "@typescript-eslint/types": "8.70.0", "@typescript-eslint/visitor-keys": "8.70.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-d9NmHMPEKQ7QCLLm1jI3zmoQBwT5KwFYjXBJ9ymZfKCUU+5rmTRykKAFvH5Qn/ZCds3CEAFS9OC9M/jkl0X2bA=="], - - "@typescript-eslint/utils": ["@typescript-eslint/utils@8.70.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.70.0", "@typescript-eslint/types": "8.70.0", "@typescript-eslint/typescript-estree": "8.70.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-oZmtKJz/4fufZ2p3+Cn3ijEojcdfR+1zYDH2xKYrEly0dR/Q/1xUPRCOlKGxod78nWlU2UnDe09GZ3TaknBFGA=="], - - "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.70.0", "", { "dependencies": { "@typescript-eslint/types": "8.70.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-BoC8PiO4Hkdo0TVJh9Ntxr5MxPDI7/oFsrygN5ADelFSeXG/qgNuucIGA+L5Z6JpPTE/uRfcTWtscjbUaufepQ=="], - - "@typescript/typescript-aix-ppc64": ["@typescript/typescript-aix-ppc64@7.0.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ=="], - - "@typescript/typescript-darwin-arm64": ["@typescript/typescript-darwin-arm64@7.0.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA=="], - - "@typescript/typescript-darwin-x64": ["@typescript/typescript-darwin-x64@7.0.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA=="], - - "@typescript/typescript-freebsd-arm64": ["@typescript/typescript-freebsd-arm64@7.0.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ=="], - - "@typescript/typescript-freebsd-x64": ["@typescript/typescript-freebsd-x64@7.0.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw=="], - - "@typescript/typescript-linux-arm": ["@typescript/typescript-linux-arm@7.0.2", "", { "os": "linux", "cpu": "arm" }, "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ=="], - - "@typescript/typescript-linux-arm64": ["@typescript/typescript-linux-arm64@7.0.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ=="], - - "@typescript/typescript-linux-loong64": ["@typescript/typescript-linux-loong64@7.0.2", "", { "os": "linux", "cpu": "none" }, "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ=="], - - "@typescript/typescript-linux-mips64el": ["@typescript/typescript-linux-mips64el@7.0.2", "", { "os": "linux", "cpu": "none" }, "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA=="], - - "@typescript/typescript-linux-ppc64": ["@typescript/typescript-linux-ppc64@7.0.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA=="], - - "@typescript/typescript-linux-riscv64": ["@typescript/typescript-linux-riscv64@7.0.2", "", { "os": "linux", "cpu": "none" }, "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ=="], - - "@typescript/typescript-linux-s390x": ["@typescript/typescript-linux-s390x@7.0.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw=="], - - "@typescript/typescript-linux-x64": ["@typescript/typescript-linux-x64@7.0.2", "", { "os": "linux", "cpu": "x64" }, "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A=="], - - "@typescript/typescript-netbsd-arm64": ["@typescript/typescript-netbsd-arm64@7.0.2", "", { "os": "none", "cpu": "arm64" }, "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA=="], - - "@typescript/typescript-netbsd-x64": ["@typescript/typescript-netbsd-x64@7.0.2", "", { "os": "none", "cpu": "x64" }, "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA=="], - - "@typescript/typescript-openbsd-arm64": ["@typescript/typescript-openbsd-arm64@7.0.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ=="], - - "@typescript/typescript-openbsd-x64": ["@typescript/typescript-openbsd-x64@7.0.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg=="], - - "@typescript/typescript-sunos-x64": ["@typescript/typescript-sunos-x64@7.0.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g=="], - - "@typescript/typescript-win32-arm64": ["@typescript/typescript-win32-arm64@7.0.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ=="], - - "@typescript/typescript-win32-x64": ["@typescript/typescript-win32-x64@7.0.2", "", { "os": "win32", "cpu": "x64" }, "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g=="], - - "@vitest/coverage-v8": ["@vitest/coverage-v8@4.1.11", "", { "dependencies": { "@bcoe/v8-coverage": "^1.0.2", "@vitest/utils": "4.1.11", "ast-v8-to-istanbul": "^1.0.0", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-report": "^3.0.1", "istanbul-reports": "^3.2.0", "magicast": "^0.5.2", "obug": "^2.1.1", "std-env": "^4.0.0-rc.1", "tinyrainbow": "^3.1.0" }, "peerDependencies": { "@vitest/browser": "4.1.11", "vitest": "4.1.11" }, "optionalPeers": ["@vitest/browser"] }, "sha512-8MVGEFnJIcdGjcbfKmeq8z0pZHH0JlVtoVZH9Q/qwUp6wyFnEJUBMrw9DCaj+ra3vShGmhavjalMIhPNxZAUcw=="], - - "@vitest/expect": ["@vitest/expect@4.1.11", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", "@vitest/spy": "4.1.11", "@vitest/utils": "4.1.11", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" } }, "sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw=="], - - "@vitest/mocker": ["@vitest/mocker@4.1.11", "", { "dependencies": { "@vitest/spy": "4.1.11", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["msw", "vite"] }, "sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ=="], - - "@vitest/pretty-format": ["@vitest/pretty-format@4.1.11", "", { "dependencies": { "tinyrainbow": "^3.1.0" } }, "sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw=="], - - "@vitest/runner": ["@vitest/runner@4.1.11", "", { "dependencies": { "@vitest/utils": "4.1.11", "pathe": "^2.0.3" } }, "sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw=="], - - "@vitest/snapshot": ["@vitest/snapshot@4.1.11", "", { "dependencies": { "@vitest/pretty-format": "4.1.11", "@vitest/utils": "4.1.11", "magic-string": "^0.30.21", "pathe": "^2.0.3" } }, "sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog=="], - - "@vitest/spy": ["@vitest/spy@4.1.11", "", {}, "sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA=="], - - "@vitest/utils": ["@vitest/utils@4.1.11", "", { "dependencies": { "@vitest/pretty-format": "4.1.11", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" } }, "sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ=="], - - "@yuku-codegen/binding-android-arm64": ["@yuku-codegen/binding-android-arm64@0.8.7", "", { "os": "android", "cpu": "arm64" }, "sha512-C/0zV5IhgVdYhGJTwrY0v8dknxlhiKwtVJkMUaexu9/QvRmzlV4vfU3hZlUSgqc2BxQHntL1mCVbDq8j0FRFDw=="], - - "@yuku-codegen/binding-darwin-arm64": ["@yuku-codegen/binding-darwin-arm64@0.8.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-/u+REDMI4a0/lsJXTM4c53/w31OGZLOReZIyg62uhgLs0kc8NHsj/nOcxTdlQjq5gi0zhdkccD9LaLTXcdzPvw=="], - - "@yuku-codegen/binding-darwin-x64": ["@yuku-codegen/binding-darwin-x64@0.8.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-sMMzFOwCo4WXR+/6zIBThOocSC50iIIZZdfiIDbaLvj0Ax/rWt/iavyfEAqajyvzydLyCqR/ZItdLWSRlu1umw=="], - - "@yuku-codegen/binding-freebsd-x64": ["@yuku-codegen/binding-freebsd-x64@0.8.7", "", { "os": "freebsd", "cpu": "x64" }, "sha512-MpdpKXix9P+Y1rKgjvcNeNtGjXeL1CmttNhYINrWls8kRpm4xM/oBGTmn6w7to8lAlwj5jm8q03dQPl5mRv4Qw=="], - - "@yuku-codegen/binding-linux-arm-gnu": ["@yuku-codegen/binding-linux-arm-gnu@0.8.7", "", { "os": "linux", "cpu": "arm" }, "sha512-rr1srFLlPAmC1vtxfc9C1YLDe3iH09YjfSeeIidBqKhzx1MATjOAq4mjlRUOnhr/L27MotWIYOFKwVsd5JZFOg=="], - - "@yuku-codegen/binding-linux-arm-musl": ["@yuku-codegen/binding-linux-arm-musl@0.8.7", "", { "os": "linux", "cpu": "arm" }, "sha512-eAufXh8qBRpiSO6ueaMDL+yyoXIGLhpUce72YbcACtZU2qhExwBIJyEtQf5kH2Ki0X2aqkSjSfog4OPtKXan3Q=="], - - "@yuku-codegen/binding-linux-arm64-gnu": ["@yuku-codegen/binding-linux-arm64-gnu@0.8.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-gw4w6wPoHObBrdIC4duVWLmJOvpdE25j5D7yrM5mACNlK4klRz/lv8hK+ssQk9EJHBgZjSaqZIJVFgqNYbfv7A=="], - - "@yuku-codegen/binding-linux-arm64-musl": ["@yuku-codegen/binding-linux-arm64-musl@0.8.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-L68N6Y4XkqcIaKo3Ra88JEvBEH4AHff44A4INcrxeVWZ8CZtu2tCpfVxe3hR8qQQMcvBSQlDn24KpkCKEhVvfA=="], - - "@yuku-codegen/binding-linux-x64-gnu": ["@yuku-codegen/binding-linux-x64-gnu@0.8.7", "", { "os": "linux", "cpu": "x64" }, "sha512-dzyAbltJmf3Cqlb8HcFuYIf5Yn0fl1vTr3XJ9HiVNNvOlhqPSArOqtw9vI1p6/VTXTjrMLXlU+s+/kNHiIy/Cw=="], - - "@yuku-codegen/binding-linux-x64-musl": ["@yuku-codegen/binding-linux-x64-musl@0.8.7", "", { "os": "linux", "cpu": "x64" }, "sha512-Otw4MH3404q0Bbvl+YTdW9aoUV5vXmUw8260bWvt1XlaoIX/ceSgI4ygheRDMfBPoHt6FDayQaO9OLVUZAgkFA=="], - - "@yuku-codegen/binding-win32-arm64": ["@yuku-codegen/binding-win32-arm64@0.8.7", "", { "os": "win32", "cpu": "arm64" }, "sha512-qo/jyrzryiBuKEsFiuWaBCBe3tRMynQ0qFWFgOEjcCMQeZfBm+wKiVEUEFXXLc7bh8YezguAWp0Mtnhq4ARNyA=="], - - "@yuku-codegen/binding-win32-x64": ["@yuku-codegen/binding-win32-x64@0.8.7", "", { "os": "win32", "cpu": "x64" }, "sha512-D5lDsVDx6m00E6bWySlWdH72Ca4TPSaphDqB6QjU6MpuNLIJqoGoatYyq2rOmBE8Zv/kunot/o58KGL03P3eiA=="], - - "@yuku-parser/binding-android-arm64": ["@yuku-parser/binding-android-arm64@0.8.7", "", { "os": "android", "cpu": "arm64" }, "sha512-eGKYiUDX7Y0V7tDTmg+JTVnXnjMqfXXsorZ+EDf5kxwchQ3Or1HS14MzI2fw+jFhHR85fCWt+mtX33Yao73hIQ=="], - - "@yuku-parser/binding-darwin-arm64": ["@yuku-parser/binding-darwin-arm64@0.8.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Re0RHelKLnjEURulY2/KxW+Ngb8zuNA4BRZuMwgGQNzVumT6u4U2N2hc01oeYVNVof0i7GrXE4UCNBgbpRRnjQ=="], - - "@yuku-parser/binding-darwin-x64": ["@yuku-parser/binding-darwin-x64@0.8.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-Hn8DROtQkjlA1ACbPgj4a7eP9IuVOI504oiTwpkWPbpaDWD9KdmnVYCqW+1LfenNK/g7O9NhWGpXEdaCNX7lIA=="], - - "@yuku-parser/binding-freebsd-x64": ["@yuku-parser/binding-freebsd-x64@0.8.7", "", { "os": "freebsd", "cpu": "x64" }, "sha512-bAP2OV8wRuzplX/jYxv9+vvqQT8JxyNphI8fLfXGL054Xs+4/J5u33cIm3y4rxY8rdoLmmdiJs2Tq7r7lrDRfA=="], - - "@yuku-parser/binding-linux-arm-gnu": ["@yuku-parser/binding-linux-arm-gnu@0.8.7", "", { "os": "linux", "cpu": "arm" }, "sha512-kTYwJQQgmZeAWdDIWabiReIZMpmfLueIj1tCmjStUtFGhR1Z0qwxonKVfUC4N7h/VhGGzLZ//7O1kgt1QKqgCg=="], - - "@yuku-parser/binding-linux-arm-musl": ["@yuku-parser/binding-linux-arm-musl@0.8.7", "", { "os": "linux", "cpu": "arm" }, "sha512-uL4jE8HPT2BLlxAXyD10LqgPuXa9eDa0BKpCdSANmzIJghq/2eZo3/gQNtaxPZMupWoxjYzSad9IXrwu7aYPXQ=="], - - "@yuku-parser/binding-linux-arm64-gnu": ["@yuku-parser/binding-linux-arm64-gnu@0.8.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-3gVN4pWSKZmXiNX7cU164dR9MPvesCHnlH6nPfpK+yQsCuYphjKKplcb4SnZBrhiqmXbgb2HR0c2TS0IZUPhgA=="], - - "@yuku-parser/binding-linux-arm64-musl": ["@yuku-parser/binding-linux-arm64-musl@0.8.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-S0mwfEjoLpxzXeZw802Wa4RaELsQiPtWqG6INcy8j4GtvNFtl4LCX3eGO1XLn9pyLAISLzTRyU3zUCBUPin8lg=="], - - "@yuku-parser/binding-linux-x64-gnu": ["@yuku-parser/binding-linux-x64-gnu@0.8.7", "", { "os": "linux", "cpu": "x64" }, "sha512-lnbWdPmerE5D1uH1G4IEZKnPzCrWCStRGrtgpSIe1RibAo5bZIjDbbbPYXmMHCEh4F+x/JaJpElh26a3r+BPbg=="], - - "@yuku-parser/binding-linux-x64-musl": ["@yuku-parser/binding-linux-x64-musl@0.8.7", "", { "os": "linux", "cpu": "x64" }, "sha512-769uwndMvMzUvATWbAcEvyLHKA+DzhHSCl/obBUrRdYfRo26yxui6S8y3z7uJ+Naup7UKrDxrpK7OnQkxkl9KQ=="], - - "@yuku-parser/binding-win32-arm64": ["@yuku-parser/binding-win32-arm64@0.8.7", "", { "os": "win32", "cpu": "arm64" }, "sha512-mEB/9PlaAkisJ6KWGz0zvywXoU6+80dTlR2LwS7s/jcXXoU6fm2+sitBZXtqu3+Q4DcDgPxM45uWMCzPs0TSRw=="], - - "@yuku-parser/binding-win32-x64": ["@yuku-parser/binding-win32-x64@0.8.7", "", { "os": "win32", "cpu": "x64" }, "sha512-8vNB2DP0ou61nGb8tc/qfi41gfyDXz1MHr2zqL3nR+cJ6CEbiuWV/l/a/vv151gCgiZLLAyGkQGENpozdg716w=="], - - "@yuku-toolchain/types": ["@yuku-toolchain/types@0.8.7", "", {}, "sha512-2Z53dNxAJL6UvFoIrDZvYf3zlO8s4VJK4O2hhaB4mXVwwpX/7ajtss3cmfqKvamlNLWyt9FSWs4eoYdlbxpnHA=="], - - "acorn": ["acorn@8.18.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ=="], - - "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], - - "ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="], - - "ajv-draft-04": ["ajv-draft-04@1.0.0", "", { "peerDependencies": { "ajv": "^8.5.0" }, "optionalPeers": ["ajv"] }, "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw=="], - - "ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="], - - "ansi-escapes": ["ansi-escapes@7.3.0", "", { "dependencies": { "environment": "^1.0.0" } }, "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg=="], - - "ansi-regex": ["ansi-regex@6.3.0", "", {}, "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ=="], - - "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], - - "ansis": ["ansis@4.3.1", "", {}, "sha512-BJ8/l4R5LRE7hW9WdSuGYrLSHi2ynxeFpDFbH0K/CgNeY/tyhk+vO6TYxXC5r5CpUhNVX310xzPsN/H9lCdfOA=="], - - "any-promise": ["any-promise@1.3.0", "", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="], - - "argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], - - "assertion-error": ["assertion-error@2.0.1", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="], - - "ast-v8-to-istanbul": ["ast-v8-to-istanbul@1.0.6", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.31", "estree-walker": "^3.0.3", "js-tokens": "^10.0.0" } }, "sha512-fvpl29helSO2w/z7utIbrkNXILdrLwDwAMH2I/zPKlGf5244+gf+B4cyS1sANcrPY2h+hWCGSgC8N61s/+AF9A=="], - - "balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], - - "brace-expansion": ["brace-expansion@5.0.9", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg=="], - - "bytes-iec": ["bytes-iec@3.1.1", "", {}, "sha512-fey6+4jDK7TFtFg/klGSvNKJctyU7n2aQdnM+CO0ruLPbqqMOM8Tio0Pc+deqUeVKX1tL5DQep1zQ7+37aTAsA=="], - - "cac": ["cac@7.0.0", "", {}, "sha512-tixWYgm5ZoOD+3g6UTea91eow5z6AAHaho3g0V9CNSNb45gM8SmflpAc+GRd1InC4AqN/07Unrgp56Y94N9hJQ=="], - - "cacheable": ["cacheable@2.5.0", "", { "dependencies": { "@cacheable/memory": "^2.2.0", "@cacheable/utils": "^2.5.0", "hookified": "^1.15.0", "keyv": "^5.6.0", "qified": "^0.10.1" } }, "sha512-60cyAOytib/OzBw1JNSoSV/boK1AtHryDIjvVBk7XbN4ugfkM3+Sry7fEjNgPMGgOjuaZPAp8ruZ0Cxafwyq9g=="], - - "chai": ["chai@6.2.2", "", {}, "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg=="], - - "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], - - "char-regex": ["char-regex@1.0.2", "", {}, "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw=="], - - "cjs-module-lexer": ["cjs-module-lexer@1.4.3", "", {}, "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q=="], - - "cli-highlight": ["cli-highlight@2.1.11", "", { "dependencies": { "chalk": "^4.0.0", "highlight.js": "^10.7.1", "mz": "^2.4.0", "parse5": "^5.1.1", "parse5-htmlparser2-tree-adapter": "^6.0.0", "yargs": "^16.0.0" }, "bin": { "highlight": "bin/highlight" } }, "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg=="], - - "cli-table3": ["cli-table3@0.6.5", "", { "dependencies": { "string-width": "^4.2.0" }, "optionalDependencies": { "@colors/colors": "1.5.0" } }, "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ=="], - - "cliui": ["cliui@7.0.4", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^7.0.0" } }, "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ=="], - - "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], - - "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], - - "commander": ["commander@10.0.1", "", {}, "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug=="], - - "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], - - "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], - - "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" }, "peerDependencies": { "supports-color": "*" }, "optionalPeers": ["supports-color"] }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], - - "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], - - "defu": ["defu@6.1.7", "", {}, "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ=="], - - "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], - - "diff": ["diff@8.0.4", "", {}, "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw=="], - - "dts-resolver": ["dts-resolver@3.0.0", "", { "peerDependencies": { "oxc-resolver": ">=11.0.0" }, "optionalPeers": ["oxc-resolver"] }, "sha512-1T1f+z+4tl9XD+m+0HBgWoL/nm0bOIffyWaUuUSBlFg/86IWvfx+wjNaO/ybU0AJzG9/Mi5hBUgGV6zCmWEN7Q=="], - - "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], - - "emojilib": ["emojilib@2.4.0", "", {}, "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw=="], - - "empathic": ["empathic@2.0.1", "", {}, "sha512-YGRs8knHhKHVShLkFET/rWAU8kmHbOV5LwN938RHI0pljAJ1Gf6SzXsSmRaEzcXTtOOmVqJ5+WtQPL5uigY50Q=="], - - "entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], - - "environment": ["environment@1.1.0", "", {}, "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q=="], - - "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], - - "es-module-lexer": ["es-module-lexer@2.3.2", "", {}, "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw=="], - - "esbuild": ["esbuild@0.28.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.2", "@esbuild/android-arm": "0.28.2", "@esbuild/android-arm64": "0.28.2", "@esbuild/android-x64": "0.28.2", "@esbuild/darwin-arm64": "0.28.2", "@esbuild/darwin-x64": "0.28.2", "@esbuild/freebsd-arm64": "0.28.2", "@esbuild/freebsd-x64": "0.28.2", "@esbuild/linux-arm": "0.28.2", "@esbuild/linux-arm64": "0.28.2", "@esbuild/linux-ia32": "0.28.2", "@esbuild/linux-loong64": "0.28.2", "@esbuild/linux-mips64el": "0.28.2", "@esbuild/linux-ppc64": "0.28.2", "@esbuild/linux-riscv64": "0.28.2", "@esbuild/linux-s390x": "0.28.2", "@esbuild/linux-x64": "0.28.2", "@esbuild/netbsd-arm64": "0.28.2", "@esbuild/netbsd-x64": "0.28.2", "@esbuild/openbsd-arm64": "0.28.2", "@esbuild/openbsd-x64": "0.28.2", "@esbuild/openharmony-arm64": "0.28.2", "@esbuild/sunos-x64": "0.28.2", "@esbuild/win32-arm64": "0.28.2", "@esbuild/win32-ia32": "0.28.2", "@esbuild/win32-x64": "0.28.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA=="], - - "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], - - "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], - - "eslint": ["eslint@10.10.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.2", "@eslint/config-array": "^0.23.5", "@eslint/config-helpers": "^0.7.0", "@eslint/core": "^1.2.1", "@eslint/plugin-kit": "^0.7.3", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.14.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^9.1.2", "eslint-visitor-keys": "^5.0.1", "espree": "^11.2.0", "esquery": "^1.7.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "11.1.5 || >11.1.6 <12", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "minimatch": "^10.2.5", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-NPXn6r5zl4uET1DAVPaOwzX3rut4c0wcmw3dWJAfOsTM5+TogXo0DDjz8pwm/hL8cyVNpHqeK4JpN0NjnyFFNw=="], - - "eslint-scope": ["eslint-scope@9.1.2", "", { "dependencies": { "@types/esrecurse": "^4.3.1", "@types/estree": "^1.0.8", "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ=="], - - "eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="], - - "espree": ["espree@11.2.0", "", { "dependencies": { "acorn": "^8.16.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^5.0.1" } }, "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw=="], - - "esquery": ["esquery@1.7.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g=="], - - "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="], - - "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], - - "estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="], - - "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], - - "expect-type": ["expect-type@1.4.0", "", {}, "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA=="], - - "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], - - "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], - - "fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="], - - "fast-uri": ["fast-uri@3.1.7", "", {}, "sha512-dOvZVzjdZdz7phd9v6jCbwxrBW3fK6n8Rc0CtdmM4bumzMnxywBYhuph6J819RRw/ku+rLbelwfMunktuzVVHg=="], - - "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], - - "fflate": ["fflate@0.8.3", "", {}, "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA=="], - - "file-entry-cache": ["file-entry-cache@11.1.5", "", { "dependencies": { "flat-cache": "^6.1.23" } }, "sha512-+PFTHITI08JIGhnNpGNI8T8inUpgZfk3GNEqfT9R2zZV2iFXg3CvqzSl/uEhs7TSGujYRELEANyDvS8Fj7+S7Q=="], - - "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="], - - "flat-cache": ["flat-cache@6.1.23", "", { "dependencies": { "cacheable": "^2.5.0", "flatted": "^3.4.2", "hookified": "^1.15.0" } }, "sha512-f++BY9pTk+983xK1FLzlLpmM0i0z+jHmx3QESGkURMXujQZz1k5wzwX6hjnQ8goaD0B+sYnDK1yZ6MTyZfUaqA=="], - - "flatted": ["flatted@3.4.4", "", {}, "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q=="], - - "fs-extra": ["fs-extra@11.3.6", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-w8ZNZr2mKIc7qeNaQ9AVPT1+iFaI+Avd4xudVOvdDJ8VytREi1Ft5Ih7hd9jjehod8vAM5GMsfQ/TpPf4EyoEA=="], - - "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], - - "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], - - "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], - - "get-tsconfig": ["get-tsconfig@5.0.0-beta.5", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-/6gFNr0N04nob252sTQxyFLi3eKFRqIg1I87YcqAMT1i6SQrSF6KujUEQrtrjMV0H/eejTCltLdDSTEMzHbnsQ=="], - - "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], - - "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], - - "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], - - "hashery": ["hashery@1.5.1", "", { "dependencies": { "hookified": "^1.15.0" } }, "sha512-iZyKG96/JwPz1N55vj2Ie2vXbhu440zfUfJvSwEqEbeLluk7NnapfGqa7LH0mOsnDxTF85Mx8/dyR6HfqcbmbQ=="], - - "hasown": ["hasown@2.0.4", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A=="], - - "highlight.js": ["highlight.js@10.7.3", "", {}, "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A=="], - - "hookable": ["hookable@6.1.1", "", {}, "sha512-U9LYDy1CwhMCnprUfeAZWZGByVbhd54hwepegYTK7Pi5NvqEj63ifz5z+xukznehT7i6NIZRu89Ay1AZmRsLEQ=="], - - "hookified": ["hookified@1.15.1", "", {}, "sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg=="], - - "html-escaper": ["html-escaper@2.0.2", "", {}, "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg=="], - - "ignore": ["ignore@7.0.9", "", {}, "sha512-brTTsvFRt5C1gGHtPst/281UjPD5t9fBqbgoMPlVWy11ZLTPfu7HxK4ZYqO9H7o/yC9rSTCI85EaQ4OoY12qYw=="], - - "import-lazy": ["import-lazy@4.0.0", "", {}, "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw=="], - - "import-without-cache": ["import-without-cache@0.4.0", "", {}, "sha512-NkJQA7oZ4YHQhd2+H3BoRFKF3d/XNsiKpHZCQEMH9pDX27hQQLsTyOocyRgaIVtf8gHX3Nt3LPkR4e5EdtPAGQ=="], - - "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], - - "is-core-module": ["is-core-module@2.16.2", "", { "dependencies": { "hasown": "^2.0.3" } }, "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA=="], - - "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], - - "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], - - "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], - - "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], - - "istanbul-lib-coverage": ["istanbul-lib-coverage@3.2.2", "", {}, "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg=="], - - "istanbul-lib-report": ["istanbul-lib-report@3.0.1", "", { "dependencies": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^4.0.0", "supports-color": "^7.1.0" } }, "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw=="], - - "istanbul-reports": ["istanbul-reports@3.2.0", "", { "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" } }, "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA=="], - - "jju": ["jju@1.4.0", "", {}, "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA=="], - - "js-tokens": ["js-tokens@10.0.0", "", {}, "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q=="], - - "json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], - - "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="], - - "jsonfile": ["jsonfile@6.2.1", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q=="], - - "keyv": ["keyv@5.6.0", "", { "dependencies": { "@keyv/serialize": "^1.1.1" } }, "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw=="], - - "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], - - "lightningcss": ["lightningcss@1.33.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.33.0", "lightningcss-darwin-arm64": "1.33.0", "lightningcss-darwin-x64": "1.33.0", "lightningcss-freebsd-x64": "1.33.0", "lightningcss-linux-arm-gnueabihf": "1.33.0", "lightningcss-linux-arm64-gnu": "1.33.0", "lightningcss-linux-arm64-musl": "1.33.0", "lightningcss-linux-x64-gnu": "1.33.0", "lightningcss-linux-x64-musl": "1.33.0", "lightningcss-win32-arm64-msvc": "1.33.0", "lightningcss-win32-x64-msvc": "1.33.0" } }, "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA=="], - - "lightningcss-android-arm64": ["lightningcss-android-arm64@1.33.0", "", { "os": "android", "cpu": "arm64" }, "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg=="], - - "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.33.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg=="], - - "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.33.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ=="], - - "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.33.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg=="], - - "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.33.0", "", { "os": "linux", "cpu": "arm" }, "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ=="], - - "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.33.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg=="], - - "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.33.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ=="], - - "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.33.0", "", { "os": "linux", "cpu": "x64" }, "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg=="], - - "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.33.0", "", { "os": "linux", "cpu": "x64" }, "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw=="], - - "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.33.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA=="], - - "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.33.0", "", { "os": "win32", "cpu": "x64" }, "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA=="], - - "lilconfig": ["lilconfig@3.1.3", "", {}, "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw=="], - - "linkify-it": ["linkify-it@5.0.2", "", { "dependencies": { "uc.micro": "^2.0.0" } }, "sha512-ONTm2jCMAVZjgQa/Fy1kScXsuOoF5NPTsoFBdE1KVIZ2vAh/r9+Bqo+0jINCBYnavTPQZz38QzFTme79ENoN3Q=="], - - "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], - - "lru-cache": ["lru-cache@11.5.2", "", {}, "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g=="], - - "lunr": ["lunr@2.3.9", "", {}, "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow=="], - - "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], - - "magicast": ["magicast@0.5.4", "", { "dependencies": { "@babel/parser": "^7.29.7", "@babel/types": "^7.29.7", "source-map-js": "^1.2.1" } }, "sha512-llBEhWm1SacoRwgHUoQJYtwp4PBLF4faQi5TCpIGyGs9n4y5+juI0tDgyKIfpqxckRHaHzouUEph3THklWh03w=="], - - "make-dir": ["make-dir@4.0.0", "", { "dependencies": { "semver": "^7.5.3" } }, "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw=="], - - "markdown-it": ["markdown-it@14.3.1", "", { "dependencies": { "argparse": "^2.0.1", "entities": "^4.5.0", "linkify-it": "^5.0.2", "mdurl": "^2.0.0", "punycode.js": "^2.3.1", "uc.micro": "^2.1.0" }, "bin": { "markdown-it": "bin/markdown-it.mjs" } }, "sha512-4Ej49aYTDFIQ+uBkfX8GBvJGccoARxxPep+7aWTs55ozbjQJpW9M26Fe53vnGgvLeVzva/amzjQQaQu9w0vMhA=="], - - "marked": ["marked@9.1.6", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-jcByLnIFkd5gSXZmjNvS1TlmRhCXZjIzHYlaGkPlLIekG55JDR2Z4va9tZwCiP+/RDERiNhMOFu01xd6O5ct1Q=="], - - "marked-terminal": ["marked-terminal@7.3.0", "", { "dependencies": { "ansi-escapes": "^7.0.0", "ansi-regex": "^6.1.0", "chalk": "^5.4.1", "cli-highlight": "^2.1.11", "cli-table3": "^0.6.5", "node-emoji": "^2.2.0", "supports-hyperlinks": "^3.1.0" }, "peerDependencies": { "marked": ">=1 <16" } }, "sha512-t4rBvPsHc57uE/2nJOLmMbZCQ4tgAccAED3ngXQqW6g+TxA488JzJ+FK3lQkzBQOI1mRV/r/Kq+1ZlJ4D0owQw=="], - - "mdurl": ["mdurl@2.1.0", "", {}, "sha512-1+HBaOx0zi/dQWht8rNv9MYf9qqpqL/kxI0hXImU6Y547zM6Sni8BQibt7ifgMcYtQg41ao3Ivd6cnSM86inpg=="], - - "minimatch": ["minimatch@10.2.3", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-Rwi3pnapEqirPSbWbrZaa6N3nmqq4Xer/2XooiOKyV3q12ML06f7MOuc5DVH8ONZIFhwIYQ3yzPH4nt7iWHaTg=="], - - "mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="], - - "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], - - "mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="], - - "nanoid": ["nanoid@6.0.1", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-3wVS3i51pE2pi1k5FFL/95BGfVS0kSsvDVuGXHOtxox/TywUmtgq+3qiTOTbs9J7KfHaXPiN171k/A6dBnaXFw=="], - - "nanospinner": ["nanospinner@1.2.2", "", { "dependencies": { "picocolors": "^1.1.1" } }, "sha512-Zt/AmG6qRU3e+WnzGGLuMCEAO/dAu45stNbHY223tUxldaDAeE+FxSPsd9Q+j+paejmm0ZbrNVs5Sraqy3dRxA=="], - - "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], - - "node-emoji": ["node-emoji@2.2.0", "", { "dependencies": { "@sindresorhus/is": "^4.6.0", "char-regex": "^1.0.2", "emojilib": "^2.4.0", "skin-tone": "^2.0.0" } }, "sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw=="], - - "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], - - "obug": ["obug@2.2.1", "", {}, "sha512-XrsrhT5sybtKI6wakr2SPOlGZWWYbUXZ7a0jT8/QOeAPau+1X/bSegNe5YR75oJmEZQbKningirmGOEJCIk61Q=="], - - "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], - - "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], - - "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], - - "package-manager-detector": ["package-manager-detector@1.8.0", "", {}, "sha512-yQA4H19AmPEoMUeavPMDIe1higySl/gH/yaQrkT/s07Qp+7pp2hYz30N3z2l5BkjVkF9Ow6o0wjJamm2y7Sn0A=="], - - "parse5": ["parse5@5.1.1", "", {}, "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug=="], - - "parse5-htmlparser2-tree-adapter": ["parse5-htmlparser2-tree-adapter@6.0.1", "", { "dependencies": { "parse5": "^6.0.1" } }, "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA=="], - - "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], - - "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], - - "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], - - "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], - - "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], - - "picomatch": ["picomatch@4.0.7", "", {}, "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA=="], - - "postcss": ["postcss@8.5.28", "", { "dependencies": { "nanoid": "^3.3.18", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A=="], - - "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], - - "prettier": ["prettier@3.9.6", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g=="], - - "publint": ["publint@0.3.24", "", { "dependencies": { "@publint/pack": "^0.1.7", "package-manager-detector": "^1.8.0", "picocolors": "^1.1.1", "sade": "^1.8.1" }, "bin": { "publint": "./src/cli.js" } }, "sha512-9zS56KrKBoqi5Qt8h92uMP8TTM9AYZSgnmCo4u2priMqkOZvQnTsziZ2p5LJ2ywbYkAjoCDp2jda9u4cgFefIw=="], - - "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], - - "punycode.js": ["punycode.js@2.3.1", "", {}, "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA=="], - - "qified": ["qified@0.10.1", "", { "dependencies": { "hookified": "^2.1.1" } }, "sha512-+Owyggi9IxT1ePKGafcI87ubSmxol6smwJ+RAHDQlx9+9cPwFWDiKFFCPuWhr9ignlGpZ9vDQLw67N4dcTVFEA=="], - - "quansync": ["quansync@1.0.0", "", {}, "sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA=="], - - "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], - - "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], - - "resolve": ["resolve@1.22.12", "", { "dependencies": { "es-errors": "^1.3.0", "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA=="], - - "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], - - "rolldown": ["rolldown@1.2.8", "", { "dependencies": { "@oxc-project/types": "=0.149.0", "@rolldown/pluginutils": "^1.0.0" }, "optionalDependencies": { "@rolldown/binding-android-arm-eabi": "1.2.8", "@rolldown/binding-android-arm64": "1.2.8", "@rolldown/binding-darwin-arm64": "1.2.8", "@rolldown/binding-darwin-x64": "1.2.8", "@rolldown/binding-freebsd-x64": "1.2.8", "@rolldown/binding-linux-arm-gnueabihf": "1.2.8", "@rolldown/binding-linux-arm64-gnu": "1.2.8", "@rolldown/binding-linux-arm64-musl": "1.2.8", "@rolldown/binding-linux-ppc64-gnu": "1.2.8", "@rolldown/binding-linux-s390x-gnu": "1.2.8", "@rolldown/binding-linux-x64-gnu": "1.2.8", "@rolldown/binding-linux-x64-musl": "1.2.8", "@rolldown/binding-openharmony-arm64": "1.2.8", "@rolldown/binding-win32-arm64-msvc": "1.2.8", "@rolldown/binding-win32-x64-msvc": "1.2.8" }, "bin": { "rolldown": "./bin/cli.mjs" } }, "sha512-Z67nTmhZe7anqnM/EjI392w5i/ANUinjip7QYsOyN37oayduxt3ksdX0hf5OOamkAd53BiIHfbfSzfUmzKFQqQ=="], - - "rolldown-plugin-dts": ["rolldown-plugin-dts@0.27.14", "", { "dependencies": { "dts-resolver": "^3.0.0", "get-tsconfig": "5.0.0-beta.5", "obug": "^2.1.4", "yuku-ast": "^0.8.0", "yuku-codegen": "^0.8.0", "yuku-parser": "^0.8.0" }, "peerDependencies": { "@typescript/native-preview": "*", "@volar/typescript": "~2.4.0", "rolldown": "^1.0.0", "typescript": "^5.0.0 || ^6.0.0 || ~7.0.0", "vue-tsc": "~3.2.0 || ~3.3.0" }, "optionalPeers": ["@typescript/native-preview", "@volar/typescript", "typescript", "vue-tsc"] }, "sha512-ZvuDDwoIpRK9RPxDXratCpklFO9QZZWndf/sd0VBFb4LEj0jj07UcHK9OCh7V4XiFz2Z89ziyBC2K6tJiDjrbw=="], - - "sade": ["sade@1.8.1", "", { "dependencies": { "mri": "^1.1.0" } }, "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A=="], - - "semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], - - "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], - - "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], - - "siginfo": ["siginfo@2.0.0", "", {}, "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g=="], - - "size-limit": ["size-limit@13.0.3", "", { "dependencies": { "bytes-iec": "^3.1.1", "lilconfig": "^3.1.3", "nanospinner": "^1.2.2" }, "bin": { "size-limit": "bin.js" } }, "sha512-KVb2aNEU49BwTR21SVjD+2QHP9gBV/nWsTHzNB/heRwXtHyA7lLQiDZDQ1TiNh/B/TZXKAZrHYyTt+cvBUrzYw=="], - - "skin-tone": ["skin-tone@2.0.0", "", { "dependencies": { "unicode-emoji-modifier-base": "^1.0.0" } }, "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA=="], - - "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], - - "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], - - "sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="], - - "stackback": ["stackback@0.0.2", "", {}, "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="], - - "std-env": ["std-env@4.2.0", "", {}, "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw=="], - - "string-argv": ["string-argv@0.3.2", "", {}, "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q=="], - - "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], - - "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - - "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], - - "supports-hyperlinks": ["supports-hyperlinks@3.2.0", "", { "dependencies": { "has-flag": "^4.0.0", "supports-color": "^7.0.0" } }, "sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig=="], - - "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], - - "thenify": ["thenify@3.3.1", "", { "dependencies": { "any-promise": "^1.0.0" } }, "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw=="], - - "thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="], - - "tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="], - - "tinyexec": ["tinyexec@1.3.1", "", {}, "sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA=="], - - "tinyglobby": ["tinyglobby@0.2.17", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g=="], - - "tinyrainbow": ["tinyrainbow@3.1.1", "", {}, "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw=="], - - "tree-kill": ["tree-kill@1.2.2", "", { "bin": { "tree-kill": "cli.js" } }, "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="], - - "ts-api-utils": ["ts-api-utils@2.5.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA=="], - - "tsdown": ["tsdown@0.22.14", "", { "dependencies": { "ansis": "^4.3.1", "cac": "^7.0.0", "defu": "^6.1.7", "empathic": "^2.0.1", "hookable": "^6.1.1", "import-without-cache": "^0.4.0", "obug": "^2.1.4", "picomatch": "^4.0.5", "rolldown": "~1.2.0", "rolldown-plugin-dts": "^0.27.13", "tinyexec": "^1.2.4", "tinyglobby": "^0.2.17", "tree-kill": "^1.2.2", "unconfig-core": "^7.5.0", "verkit": "^0.3.0" }, "peerDependencies": { "@arethetypeswrong/core": "^0.18.1", "@tsdown/css": "0.22.14", "@tsdown/exe": "0.22.14", "@vitejs/devtools": "*", "publint": "^0.3.8", "tsx": "*", "typescript": "^5.0.0 || ^6.0.0 || ^7.0.0", "unplugin-unused": "^0.5.0", "unrun": "*" }, "optionalPeers": ["@arethetypeswrong/core", "@tsdown/css", "@tsdown/exe", "@vitejs/devtools", "publint", "tsx", "typescript", "unplugin-unused", "unrun"], "bin": { "tsdown": "./dist/run.mjs" } }, "sha512-ule7Y+fsAN2iZbLDoo7C4KYljFJNJJ+fLshyn+9gozeTspVersWHxwdGB+Dm2hzA38s6muFnUTl0jK3vJm9ifQ=="], - - "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], - - "typedoc": ["typedoc@0.28.20", "", { "dependencies": { "@gerrit0/mini-shiki": "^3.23.0", "lunr": "^2.3.9", "markdown-it": "^14.3.0", "minimatch": "^10.2.5", "yaml": "^2.9.0" }, "peerDependencies": { "typescript": "5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x || 5.9.x || 6.0.x" }, "bin": { "typedoc": "bin/typedoc" } }, "sha512-uSKqkh8Cr48vllnEy+jdaAgOeR6Y+QCBW7usgUsKj7gJEfR7stw9U/fE49LBnj2tPRKPY0c0EBJSWe9Appmplg=="], - - "typescript": ["typescript@7.0.2", "", { "optionalDependencies": { "@typescript/typescript-aix-ppc64": "7.0.2", "@typescript/typescript-darwin-arm64": "7.0.2", "@typescript/typescript-darwin-x64": "7.0.2", "@typescript/typescript-freebsd-arm64": "7.0.2", "@typescript/typescript-freebsd-x64": "7.0.2", "@typescript/typescript-linux-arm": "7.0.2", "@typescript/typescript-linux-arm64": "7.0.2", "@typescript/typescript-linux-loong64": "7.0.2", "@typescript/typescript-linux-mips64el": "7.0.2", "@typescript/typescript-linux-ppc64": "7.0.2", "@typescript/typescript-linux-riscv64": "7.0.2", "@typescript/typescript-linux-s390x": "7.0.2", "@typescript/typescript-linux-x64": "7.0.2", "@typescript/typescript-netbsd-arm64": "7.0.2", "@typescript/typescript-netbsd-x64": "7.0.2", "@typescript/typescript-openbsd-arm64": "7.0.2", "@typescript/typescript-openbsd-x64": "7.0.2", "@typescript/typescript-sunos-x64": "7.0.2", "@typescript/typescript-win32-arm64": "7.0.2", "@typescript/typescript-win32-x64": "7.0.2" }, "bin": { "tsc": "bin/tsc" } }, "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA=="], - - "typescript6": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="], - - "uc.micro": ["uc.micro@2.1.0", "", {}, "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A=="], - - "unconfig-core": ["unconfig-core@7.5.0", "", { "dependencies": { "@quansync/fs": "^1.0.0", "quansync": "^1.0.0" } }, "sha512-Su3FauozOGP44ZmKdHy2oE6LPjk51M/TRRjHv2HNCWiDvfvCoxC2lno6jevMA91MYAdCdwP05QnWdWpSbncX/w=="], - - "undici-types": ["undici-types@8.9.0", "", {}, "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg=="], - - "unicode-emoji-modifier-base": ["unicode-emoji-modifier-base@1.0.0", "", {}, "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g=="], - - "universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], - - "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], - - "validate-npm-package-name": ["validate-npm-package-name@5.0.1", "", {}, "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ=="], - - "verkit": ["verkit@0.3.2", "", {}, "sha512-zj/ob3UsvJGN0whEAKFp53REA5X66hvffVqoCtVQAakJKnKlH+/PcOfMoFwIG/o4rElqLv/ycAFlx8ZlXUorCg=="], - - "vite": ["vite@8.3.0", "", { "dependencies": { "lightningcss": "^1.33.0", "picomatch": "^4.0.7", "postcss": "^8.5.28", "rolldown": "~1.2.6", "tinyglobby": "^0.2.17" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.7.1", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-lhZBVvEHefgE+HQZC9O7EBJgCU/nVzFNl7vkS4RE0APtWLP02/8QVIkQtzBxPquh7lq5/78NHipTj7ODQ6XuyQ=="], - - "vitest": ["vitest@4.1.11", "", { "dependencies": { "@vitest/expect": "4.1.11", "@vitest/mocker": "4.1.11", "@vitest/pretty-format": "4.1.11", "@vitest/runner": "4.1.11", "@vitest/snapshot": "4.1.11", "@vitest/spy": "4.1.11", "@vitest/utils": "4.1.11", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^4.0.0-rc.1", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.1.0", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@vitest/browser-playwright": "4.1.11", "@vitest/browser-preview": "4.1.11", "@vitest/browser-webdriverio": "4.1.11", "@vitest/coverage-istanbul": "4.1.11", "@vitest/coverage-v8": "4.1.11", "@vitest/ui": "4.1.11", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@opentelemetry/api", "@types/node", "@vitest/browser-playwright", "@vitest/browser-preview", "@vitest/browser-webdriverio", "@vitest/coverage-istanbul", "@vitest/coverage-v8", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "./vitest.mjs" } }, "sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw=="], - - "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], - - "why-is-node-running": ["why-is-node-running@2.3.0", "", { "dependencies": { "siginfo": "^2.0.0", "stackback": "0.0.2" }, "bin": { "why-is-node-running": "cli.js" } }, "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w=="], - - "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], - - "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], - - "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], - - "yaml": ["yaml@2.9.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA=="], - - "yargs": ["yargs@16.2.2", "", { "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.0", "y18n": "^5.0.5", "yargs-parser": "^20.2.2" } }, "sha512-Nt9ZJjXTv5R8MHbqby/wXQ6Gi0Bb3TcYZkR1bzuL4yB2OxWPkXknz513gEF0GoA6tn00UpbPvERW8rzCuWCA6w=="], - - "yargs-parser": ["yargs-parser@20.2.9", "", {}, "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="], - - "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], - - "yuku-ast": ["yuku-ast@0.8.7", "", { "dependencies": { "@yuku-toolchain/types": "^0.8.7" } }, "sha512-h6+4bDfyootiMB9vckk5uKo5r5j0GHrkr17FQTDNfEsFT3DWlN9uu1HJwQwc64pgmLCI945fWM3lbTIqxjT3GQ=="], - - "yuku-codegen": ["yuku-codegen@0.8.7", "", { "dependencies": { "@yuku-toolchain/types": "^0.8.7" }, "optionalDependencies": { "@yuku-codegen/binding-android-arm64": "0.8.7", "@yuku-codegen/binding-darwin-arm64": "0.8.7", "@yuku-codegen/binding-darwin-x64": "0.8.7", "@yuku-codegen/binding-freebsd-x64": "0.8.7", "@yuku-codegen/binding-linux-arm-gnu": "0.8.7", "@yuku-codegen/binding-linux-arm-musl": "0.8.7", "@yuku-codegen/binding-linux-arm64-gnu": "0.8.7", "@yuku-codegen/binding-linux-arm64-musl": "0.8.7", "@yuku-codegen/binding-linux-x64-gnu": "0.8.7", "@yuku-codegen/binding-linux-x64-musl": "0.8.7", "@yuku-codegen/binding-win32-arm64": "0.8.7", "@yuku-codegen/binding-win32-x64": "0.8.7" } }, "sha512-adwDZSh8oVDzhE6Du9PwVWxcOxeV0e2EVhUuMKWfhSY4wkrDq9eqixlxFF3l/XGUV1E7UFzhpz9393MUumkyNw=="], - - "yuku-parser": ["yuku-parser@0.8.7", "", { "dependencies": { "@yuku-toolchain/types": "^0.8.7", "yuku-ast": "^0.8.7" }, "optionalDependencies": { "@yuku-parser/binding-android-arm64": "0.8.7", "@yuku-parser/binding-darwin-arm64": "0.8.7", "@yuku-parser/binding-darwin-x64": "0.8.7", "@yuku-parser/binding-freebsd-x64": "0.8.7", "@yuku-parser/binding-linux-arm-gnu": "0.8.7", "@yuku-parser/binding-linux-arm-musl": "0.8.7", "@yuku-parser/binding-linux-arm64-gnu": "0.8.7", "@yuku-parser/binding-linux-arm64-musl": "0.8.7", "@yuku-parser/binding-linux-x64-gnu": "0.8.7", "@yuku-parser/binding-linux-x64-musl": "0.8.7", "@yuku-parser/binding-win32-arm64": "0.8.7", "@yuku-parser/binding-win32-x64": "0.8.7" } }, "sha512-vRD9nwt4L3aYpxNqeSC4WqLv58xrXef0Ong1Mc45CTXTIpvLafx7JO05sczmQZwdLEZvywrLOGdNC5+Rp5N1BQ=="], - - "@arethetypeswrong/core/typescript": ["typescript@5.6.1-rc", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-E3b2+1zEFu84jB0YQi9BORDjz9+jGbwwy1Zi3G0LUNw7a7cePUrHMRNy8aPh53nXpkFGVHSxIZo5vKTfYaFiBQ=="], - - "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], - - "@eslint/config-array/minimatch": ["minimatch@10.2.6", "", { "dependencies": { "brace-expansion": "^5.0.8" } }, "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A=="], - - "@microsoft/api-extractor/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], - - "@microsoft/api-extractor/typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], - - "@microsoft/tsdoc-config/ajv": ["ajv@8.18.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A=="], - - "@rushstack/node-core-library/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], - - "@rushstack/terminal/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], - - "@typescript-eslint/typescript-estree/minimatch": ["minimatch@10.2.6", "", { "dependencies": { "brace-expansion": "^5.0.8" } }, "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A=="], - - "eslint/ajv": ["ajv@6.15.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw=="], - - "eslint/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], - - "eslint/minimatch": ["minimatch@10.2.6", "", { "dependencies": { "brace-expansion": "^5.0.8" } }, "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A=="], - - "markdown-it/argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], - - "marked-terminal/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], - - "parse5-htmlparser2-tree-adapter/parse5": ["parse5@6.0.1", "", {}, "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw=="], - - "postcss/nanoid": ["nanoid@3.3.19", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug=="], - - "qified/hookified": ["hookified@2.2.0", "", {}, "sha512-p/LgFzRN5FeoD3DLS6bkUapeye6E4SI6yJs6KetENd18S+FBthqYq2amJUWpt5z0EQwwHemidjY5OqJGEKm5uA=="], - - "strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - - "typedoc/minimatch": ["minimatch@10.2.6", "", { "dependencies": { "brace-expansion": "^5.0.8" } }, "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A=="], - - "eslint/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], - } -} diff --git a/eslint.config.mjs b/eslint.config.mjs index 5b993ba..f367ae9 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -34,7 +34,7 @@ export default [ ...tsPlugin.configs["recommended-type-checked"].rules, ...tsPlugin.configs["stylistic-type-checked"].rules, - // Conflicts with tsconfig `isolatedDeclarations` (P1.3), which REQUIRES + // Conflicts with tsconfig `isolatedDeclarations`, which REQUIRES // explicit annotations on exported consts the rule deems inferrable. "@typescript-eslint/no-inferrable-types": "off", diff --git a/examples/document.ts b/examples/document.ts new file mode 100644 index 0000000..4e9071f --- /dev/null +++ b/examples/document.ts @@ -0,0 +1,64 @@ +/** + * Builds a XID document, signs it into an envelope, parses it back + * verified, and advances its provenance chain. + * + * bun examples/document.ts + */ +import { PrivateKeyBase } from "@blockchaincommons/components"; +import { CborDate } from "@blockchaincommons/dcbor"; +import { format } from "@blockchaincommons/envelope/format"; +import { registerTags } from "@blockchaincommons/provenance-mark"; +import { Delegate, Key, Service, XIDDocument } from "@blockchaincommons/xid"; + +registerTags(); // once: the envelope and provenance-mark summarisers, for `format()` + +// The inception key controls the document; a genesis mark starts its provenance chain. +const alice = PrivateKeyBase.from(Uint8Array.from({ length: 32 }, (_, i) => i + 1)); +const doc = XIDDocument.from({ + inceptionKey: alice, + genesis: { passphrase: "wolf", resolution: "low", date: new Date("2025-01-01T00:00:00Z") }, +}); +doc.addResolutionMethod("https://resolver.example.com"); + +// A second key, allowed to sign only. +const bob = PrivateKeyBase.from(Uint8Array.from({ length: 32 }, (_, i) => 255 - i)); +const signing = Key.from(bob.schnorrPublicKeys(), { privateKeys: bob.schnorrPrivateKeys() }); +signing.addAllow("Sign"); +doc.addKey(signing); + +// A service the inception key may use. +const service = Service.from("https://messaging.example.com", { + capability: "com.example.messaging", +}); +service.addKey(doc.inceptionKey ?? signing); +service.addAllow("All"); +doc.addService(service); + +// A delegate: another party's document (its public keys only), allowed to encrypt on this one's behalf. +const carol = XIDDocument.from({ + inceptionKey: PrivateKeyBase.from( + Uint8Array.from({ length: 32 }, (_, i) => 2 * i + 1), + ).schnorrPublicKeys(), +}); +const delegate = Delegate.from(carol); +delegate.addAllow("Encrypt"); +doc.addDelegate(delegate); + +// Signed by the inception key, private keys encrypted with a password, generator kept. +const envelope = doc.toEnvelope({ + privateKeys: { encrypt: "password" }, + generator: { encrypt: "password" }, + sign: "inception", +}); +console.log(format(envelope)); +console.log(doc.toUR().toString()); + +// Parsed back with the signature verified and the material unlocked. +const back = XIDDocument.fromEnvelope(envelope, { password: "password", verify: "inception" }); +console.log("round trip equal:", back.equals(doc)); + +// The next mark in the chain; the date is a `Date` or a `CborDate`. +back.nextProvenanceMarkWithEmbeddedGenerator({ + date: CborDate.fromString("2025-06-01T00:00:00Z"), +}); +console.log("provenance seq:", back.provenance?.seq, back.provenance?.toString()); diff --git a/package.json b/package.json index 11d2a17..9319b11 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@blockchaincommons/xid", - "version": "1.0.0-beta.2", + "version": "1.0.0-beta.3", "type": "module", "sideEffects": false, "description": "Blockchain Commons XID for TypeScript", @@ -54,19 +54,19 @@ "lint:fix": "eslint 'src/**/*.ts' 'tests/**/*.ts' --fix", "format": "prettier --write 'src/**/*.ts' 'tests/**/*.ts'", "format:check": "prettier --check 'src/**/*.ts' 'tests/**/*.ts'", - "typecheck": "tsc --noEmit", + "typecheck": "tsc --noEmit && tsc --project scripts/tsconfig.json", "size": "size-limit", - "api:snapshot": "bun scripts/api-snapshot.mjs && node scripts/api-report.mjs --local", - "api:check": "bun scripts/api-snapshot.mjs --check && node scripts/api-report.mjs", + "api:snapshot": "bun scripts/api-snapshot.ts && bun scripts/api-report.ts --local", + "api:check": "bun scripts/api-snapshot.ts --check && bun scripts/api-report.ts", "clean": "rm -rf dist", "docs": "typedoc", - "bench": "bun bench/benchmark.mjs", - "postinstall": "node scripts/pin-lint-typescript.mjs", + "bench": "bun run build && bun bench/benchmark.mjs", + "prepare": "bun scripts/pin-lint-typescript.ts", "prepublishOnly": "npm run build", "lint:pkg": "publint && attw --pack . --profile node16", - "check:deps": "node scripts/check-deps.mjs", - "baseline:build": "bun scripts/build-baseline.mjs", - "vectors:generate": "bun scripts/generate-vectors.mjs", + "check:deps": "bun scripts/check-deps.ts", + "baseline:build": "bun scripts/build-baseline.ts", + "vectors:generate": "bun scripts/generate-vectors.ts", "test:golden": "vitest run tests/golden-vectors.test.ts", "test:differential": "vitest run tests/differential.test.ts" }, @@ -88,30 +88,29 @@ "@blockchaincommons/dcbor": "^1.0.0-beta.3", "@blockchaincommons/envelope": "^1.0.0-beta.3", "@blockchaincommons/known-values": "^1.0.0-beta.3", - "@blockchaincommons/provenance-mark": "^1.0.0-beta.2", + "@blockchaincommons/provenance-mark": "^1.0.0-beta.3", "@blockchaincommons/rand": "^1.0.0-beta.3", "@blockchaincommons/tags": "^1.0.0-beta.3", "@blockchaincommons/uniform-resources": "^1.0.0-beta.3" }, "devDependencies": { "@arethetypeswrong/cli": "^0.18.5", - "@blockchaincommons/rand": "^1.0.0-beta.3", "@eslint/js": "^10.0.1", - "@microsoft/api-extractor": "^7.58.9", - "@size-limit/preset-small-lib": "^13.0.3", - "@types/node": "^26.1.1", - "@typescript-eslint/eslint-plugin": "^8.64.0", - "@typescript-eslint/parser": "^8.64.0", - "@vitest/coverage-v8": "^4.1.10", - "ajv": "^8.20.0", - "eslint": "^10.7.0", - "prettier": "3.9.6", - "publint": "^0.3.21", - "size-limit": "^13.0.3", - "tsdown": "^0.22.8", + "@microsoft/api-extractor": "^7.59.1", + "@size-limit/preset-small-lib": "^14.0.0", + "@types/node": "^26.6.1", + "@typescript-eslint/eslint-plugin": "^8.70.0", + "@typescript-eslint/parser": "^8.70.0", + "@vitest/coverage-v8": "^5.0.1", + "fast-check": "^4.10.1", + "eslint": "^10.10.0", + "prettier": "3.9.7", + "publint": "^0.3.24", + "size-limit": "^14.0.0", + "tsdown": "^0.23.0", "typedoc": "^0.28.20", "typescript": "^7.0.2", "typescript6": "npm:typescript@^6.0.3", - "vitest": "^4.1.10" + "vitest": "^5.0.1" } } diff --git a/scripts/annotate-isolated-declarations.mjs b/scripts/annotate-isolated-declarations.mjs deleted file mode 100644 index 4d56d5e..0000000 --- a/scripts/annotate-isolated-declarations.mjs +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Annotates the mechanical `--isolatedDeclarations` cases. - * - * node scripts/annotate-isolated-declarations.mjs [--dry-run] - * - * The reference tsconfig enables `isolatedDeclarations`, which the monorepo did - * not. It requires an explicit type on any exported declaration whose type a - * single-file emit cannot infer. Most of those are one shape: - * - * export const FOO = new Bar(...) -> export const FOO: Bar = new Bar(...) - * static readonly SIZE = OTHER_CONST -> static readonly SIZE: number = ... - * export const FOO = someFn -> needs the function's signature, skipped - * - * This handles the `new Bar(...)` form and numeric-constant aliases, reports - * everything it could not decide, and never guesses: anything ambiguous is left - * for a human to annotate. - */ -import { execFileSync } from "node:child_process"; -import { readFileSync, writeFileSync } from "node:fs"; -import { dirname, join } from "node:path"; -import { fileURLToPath } from "node:url"; - -const root = join(dirname(fileURLToPath(import.meta.url)), ".."); -const dry = process.argv.includes("--dry-run"); - -let out = ""; -try { - out = execFileSync("bunx", ["tsc", "--noEmit"], { cwd: root, encoding: "utf8" }); -} catch (e) { - out = String(e.stdout ?? ""); -} - -const errors = []; -for (const line of out.split("\n")) { - const m = /^(\S+\.ts)\((\d+),(\d+)\): error (TS901[02]):/.exec(line.trim()); - if (m) errors.push({ file: m[1], line: Number(m[2]), code: m[4] }); -} -if (errors.length === 0) { console.log("no isolatedDeclarations errors"); process.exit(0); } - -const byFile = new Map(); -for (const e of errors) { - if (!byFile.has(e.file)) byFile.set(e.file, []); - byFile.get(e.file).push(e); -} - -let fixed = 0; -const skipped = []; -for (const [file, list] of byFile) { - const path = join(root, file); - const lines = readFileSync(path, "utf8").split("\n"); - // descending, so earlier edits do not shift later line numbers - for (const e of [...list].sort((a, b) => b.line - a.line)) { - const idx = e.line - 1; - const text = lines[idx]; - if (text === undefined || /:\s*\S+\s*=/.test(text.replace(/=.*/, "$&"))) continue; - - // export const NAME = new Klass( | static readonly NAME = new Klass( - const ctor = /^(\s*(?:export\s+)?(?:static\s+)?(?:readonly\s+)?(?:const\s+)?)([A-Za-z_$][\w$]*)(\s*=\s*new\s+)([A-Za-z_$][\w$.]*)/.exec(text); - if (ctor && !text.includes(": ")) { - const type = ctor[4].split(".").pop(); - lines[idx] = text.replace(`${ctor[2]}${ctor[3]}`, `${ctor[2]}: ${type}${ctor[3]}`); - fixed++; - continue; - } - skipped.push(`${file}:${e.line}: ${text.trim()}`); - } - if (!dry) writeFileSync(path, lines.join("\n")); -} - -console.log(`annotated ${fixed} declaration(s)`); -if (skipped.length) { - console.log(`\n${skipped.length} left for manual annotation:`); - for (const s of skipped) console.log(" " + s); -} diff --git a/scripts/api-report.mjs b/scripts/api-report.ts similarity index 66% rename from scripts/api-report.mjs rename to scripts/api-report.ts index 057ca2b..7666daf 100644 --- a/scripts/api-report.mjs +++ b/scripts/api-report.ts @@ -1,18 +1,17 @@ /** - * Public API report via @microsoft/api-extractor (P1.2). + * Public API report via @microsoft/api-extractor. * * Usage: - * bun scripts/api-report.mjs --local # (re)generate the api/.api.md report - * bun scripts/api-report.mjs # verify the committed report matches + * bun scripts/api-report.ts --local # (re)generate api/xid.api.md + * bun scripts/api-report.ts # verify the committed report matches * * api-extractor requires a `.d.ts` entry point; tsdown emits `.d.mts`, so a * transient copy is made inside dist/ first. The committed report - * (api/.api.md) is the reviewable record of the public surface - - * "API deliberately unstable, wire frozen" is enforced by making every - * surface change a visible diff here and in api/index.d.mts. + * (api/xid.api.md) is the reviewable record of the public surface: every + * surface change is a visible diff here and in api/index.d.mts. */ -import { copyFileSync, existsSync, readFileSync, rmSync } from "node:fs"; +import { copyFileSync, existsSync, rmSync } from "node:fs"; import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; @@ -20,8 +19,6 @@ import { Extractor, ExtractorConfig } from "@microsoft/api-extractor"; const root = join(dirname(fileURLToPath(import.meta.url)), ".."); const local = process.argv.includes("--local"); -const REPORT = JSON.parse(readFileSync(join(root, "api-extractor.json"), "utf8")).apiReport - .reportFileName; const dmts = join(root, "dist", "index.d.mts"); const dts = join(root, "dist", "index.d.ts"); @@ -47,15 +44,14 @@ try { } if (result.apiReportChanged && !local) { console.error( - `Public API surface changed but api/${REPORT} was not updated. -` + + "Public API surface changed but api/xid.api.md was not updated.\n" + "Review the change, then run `bun run api:snapshot` to accept it.", ); process.exit(1); } console.log( local - ? `API report (api/${REPORT}) is up to date.` + ? "API report (api/xid.api.md) is up to date." : "API report matches the committed snapshot.", ); } finally { diff --git a/scripts/api-snapshot.mjs b/scripts/api-snapshot.ts similarity index 88% rename from scripts/api-snapshot.mjs rename to scripts/api-snapshot.ts index 2f7b05b..f912ceb 100644 --- a/scripts/api-snapshot.mjs +++ b/scripts/api-snapshot.ts @@ -1,9 +1,9 @@ /** * Public-API snapshot. * - * Snapshots the built public type declarations of EVERY entry point - * (dist/.d.mts) to api/.d.mts so any change to the public - * surface is a reviewable diff (P3.18: index + diagnostic + walk + debug). + * Snapshots the built public type declarations of the entry point (index) + * from dist/.d.mts to api/.d.mts, so + * any change to the public surface is a reviewable diff. * * bun run api:snapshot # write/update the snapshots from the current build * bun run api:check # fail if any built .d.mts differs from its snapshot diff --git a/scripts/build-baseline.mjs b/scripts/build-baseline.mjs deleted file mode 100644 index 0c10e53..0000000 --- a/scripts/build-baseline.mjs +++ /dev/null @@ -1,89 +0,0 @@ -/** - * Build the frozen baseline bundle. - * - * bun scripts/build-baseline.mjs - * - * Bundles src/index.ts as a single ESM file with every @blockchaincommons - * sibling INLINED, resolving each sibling to ITS frozen baseline bundle - * (..//tests/baseline/-baseline.mjs) when one exists, so the - * baseline keeps the published behaviour of its dependencies even after - * they change. Writes tests/baseline/-baseline.mjs, the .d.mts API - * snapshot, and README.md with the commit and sha256 pinned. - */ -import { build } from "tsdown"; -import { createHash } from "node:crypto"; -import { execSync } from "node:child_process"; -import { - existsSync, - mkdirSync, - readFileSync, - writeFileSync, - copyFileSync, - readdirSync, -} from "node:fs"; -import { dirname, join, resolve } from "node:path"; -import { fileURLToPath } from "node:url"; - -const root = resolve(dirname(fileURLToPath(import.meta.url)), ".."); -const parent = dirname(root); -const pkg = JSON.parse(readFileSync(join(root, "package.json"), "utf8")); -const short = pkg.name.replace("@blockchaincommons/", ""); -const outDir = join(root, "tests", "baseline"); -mkdirSync(outDir, { recursive: true }); - -// The closure is the published `@bcts/*` packages installed -// under tests/baseline (see its package.json): one copy of every sibling, -// unlike the per-package frozen bundles, which each inline their own. -const alias = {}; -await build({ - // Never load the package's own tsdown.config.ts: its `deps.neverBundle` / - // `external` settings would keep the siblings external. - config: false, - // A package may provide tests/baseline/entry.ts to widen the bundle surface - // (e.g. expose an inlined dependency's global store to the differential). - entry: { [`${short}-baseline`]: join(outDir, "entry.ts") }, - outDir, - format: ["esm"], - dts: false, - sourcemap: false, - clean: false, - target: "es2022", - // Everything but Node builtins is inlined: the bundle is self-contained. - noExternal: [/^(?!node:)/], - alias, - inputOptions: { - onwarn(w, d) { - if (w.code !== "SOURCEMAP_BROKEN") d(w); - }, - }, -}); - -const bundle = join(outDir, `${short}-baseline.mjs`); -let text = readFileSync(bundle, "utf8").replace(/\n\/\/# sourceMappingURL=.*\n?$/, "\n"); -writeFileSync(bundle, text); -const sha = createHash("sha256").update(text).digest("hex"); -const commit = execSync("git rev-parse HEAD", { cwd: root }).toString().trim(); -if (existsSync(join(root, "api/index.d.mts"))) - copyFileSync(join(root, "api/index.d.mts"), join(outDir, `${short}-baseline.d.mts`)); -writeFileSync( - join(outDir, "README.md"), - `# Frozen baseline build - -\`${short}-baseline.mjs\` is the self-contained ESM bundle of \`${pkg.name}\` built from -commit \`${commit}\`, the wire-format reference before this package's API. It is built from -the PUBLISHED \`@bcts\` packages (\`@bcts/xid\` 1.0.0-beta.6 and its closure, -pinned by tests/baseline/package.json), so every sibling is inlined exactly -once, with the behaviour consumers had. -\`${short}-baseline.d.mts\` is the public surface at that commit. - -\`tests/differential.test.ts\` runs every corpus recipe through this bundle and -the working tree and asserts identical outcomes; it pins the sha256 below so -an accidental rebuild cannot turn the differential into a self-comparison. - -Baseline commit: ${commit} -Baseline sha256: ${sha} -`, -); -console.log( - `wrote ${bundle}\nsha256 ${sha}\ncommit ${commit}\naliases: ${JSON.stringify(alias, null, 1)}`, -); diff --git a/scripts/build-baseline.ts b/scripts/build-baseline.ts new file mode 100644 index 0000000..7437878 --- /dev/null +++ b/scripts/build-baseline.ts @@ -0,0 +1,118 @@ +/** + * Build the frozen baseline bundle: the package as it shipped at the + * baseline commit, as one self-contained ESM file. + * + * bun scripts/build-baseline.ts [commit] + * + * The baseline commit's `src/` is extracted from git and bundled with every + * `@blockchaincommons` sibling INLINED from the workspace, so the bundle + * keeps behaving as it did even after the siblings change. The entry also + * re-exports the sibling values the differential drives the bundle with + * (keys, envelopes, CBOR, known values, the provenance generator), so they + * are the bundle's own classes. Writes tests/baseline/-baseline.mjs, + * the .d.mts API snapshot, and README.md with the commit and sha256 + * pinned. The commit defaults to the one recorded in tests/baseline/README.md. + */ +import { build } from "tsdown"; +import { createHash } from "node:crypto"; +import { execSync } from "node:child_process"; +import { copyFileSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"; +import { dirname, join, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; + +const root = resolve(dirname(fileURLToPath(import.meta.url)), ".."); +const pkg = JSON.parse(readFileSync(join(root, "package.json"), "utf8")) as { name: string }; +const short: string = pkg.name.replace("@blockchaincommons/", ""); +const outDir = join(root, "tests", "baseline"); +mkdirSync(outDir, { recursive: true }); + +const readme = existsSync(join(outDir, "README.md")) + ? readFileSync(join(outDir, "README.md"), "utf8") + : ""; +const commit = + process.argv[2] ?? + readme.match(/Baseline commit: ([0-9a-f]{40})/)?.[1] ?? + execSync("git rev-parse HEAD", { cwd: root }).toString().trim(); + +// The baseline sources live under the package so module resolution finds the +// workspace's node_modules; the directory is removed after the build. +const srcDir = join(outDir, ".src"); +rmSync(srcDir, { recursive: true, force: true }); +mkdirSync(srcDir, { recursive: true }); +execSync(`git archive ${commit} src | tar -x -C ${JSON.stringify(srcDir)}`, { cwd: root }); +writeFileSync( + join(srcDir, "entry.ts"), + `export * from "./src/index.ts"; +export { + Digest, + PrivateKeyBase, + PrivateKeys, + PublicKeys, + Reference, + Salt, + URI, +} from "@blockchaincommons/components"; +export { KeyDerivationMethod } from "@blockchaincommons/components/kdf"; +export { cbor as baselineCbor } from "@blockchaincommons/dcbor"; +export { Envelope } from "@blockchaincommons/envelope"; +export { format as formatEnvelope } from "@blockchaincommons/envelope/format"; +export { sign as signEnvelope } from "@blockchaincommons/envelope/signature"; +export { IS_A, SOURCE, TARGET } from "@blockchaincommons/known-values"; +export { + ProvenanceMarkGenerator, + ProvenanceSeed, + registerTags as baselineRegisterTags, +} from "@blockchaincommons/provenance-mark"; +export { UR, decodeURWith } from "@blockchaincommons/uniform-resources"; +`, +); + +try { + await build({ + config: false, + entry: { [`${short}-baseline`]: join(srcDir, "entry.ts") }, + outDir, + format: ["esm"], + dts: false, + sourcemap: false, + clean: false, + target: "es2022", + deps: { alwaysBundle: [/^(?!node:)/] }, + inputOptions: { + onwarn(w, d) { + if (w.code !== "SOURCEMAP_BROKEN" && w.code !== "EMPTY_IMPORT_META") d(w); + }, + }, + }); +} finally { + rmSync(srcDir, { recursive: true, force: true }); +} + +const bundle = join(outDir, `${short}-baseline.mjs`); +const text = readFileSync(bundle, "utf8").replace(/\n\/\/# sourceMappingURL=.*\n?$/, "\n"); +writeFileSync(bundle, text); +const sha = createHash("sha256").update(text).digest("hex"); +if (existsSync(join(root, "api/index.d.mts"))) + copyFileSync(join(root, "api/index.d.mts"), join(outDir, `${short}-baseline.d.mts`)); +writeFileSync( + join(outDir, "README.md"), + `# Frozen baseline build + +\`${short}-baseline.mjs\` is the self-contained ESM bundle of \`${pkg.name}\` as it +shipped at commit \`${commit}\` (\`1.0.0-beta.2\`), with every \`@blockchaincommons\` +sibling inlined from the workspace. It also re-exports the sibling values the +differential drives it with (keys, envelopes, CBOR, known values, the +provenance generator), so they are the bundle's own classes. +\`${short}-baseline.d.mts\` is the public surface at that commit. + +\`tests/differential.test.ts\` runs every corpus recipe through this bundle and +the working tree and asserts identical outcomes outside the enumerated +tombstones; it pins the sha256 below so an accidental rebuild cannot turn the +differential into a self-comparison. Rebuild with +\`bun scripts/build-baseline.ts ${commit.slice(0, 7)}\`. + +Baseline commit: ${commit} +Baseline sha256: ${sha} +`, +); +console.log(`wrote ${bundle}\nsha256 ${sha}\ncommit ${commit}`); diff --git a/scripts/check-deps.mjs b/scripts/check-deps.ts similarity index 58% rename from scripts/check-deps.mjs rename to scripts/check-deps.ts index e312972..43fa462 100644 --- a/scripts/check-deps.mjs +++ b/scripts/check-deps.ts @@ -1,20 +1,22 @@ /** * Dependency hygiene gate. * - * node scripts/check-deps.mjs # no monorepo leftovers may survive - * node scripts/check-deps.mjs --zero # additionally: zero runtime deps + * bun scripts/check-deps.ts # no unpublishable dependency + * bun scripts/check-deps.ts --zero # additionally: zero runtime deps * - * The first check is universal: an extracted repository must never ship a - * `@bcts/*` dependency or a `workspace:` protocol range, both of which are - * unresolvable outside the bcts monorepo. The `--zero` form additionally - * enforces the zero-runtime-dependency policy for the packages that hold it. + * A published package must not depend on `@bcts/*` (the packages this library + * was extracted from) or use a `workspace:` protocol range; the `--zero` form + * additionally enforces a zero-runtime-dependency policy. */ import { readFileSync } from "node:fs"; import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; const root = join(dirname(fileURLToPath(import.meta.url)), ".."); -const pkg = JSON.parse(readFileSync(join(root, "package.json"), "utf8")); +const pkg = JSON.parse(readFileSync(join(root, "package.json"), "utf8")) as Record< + string, + Record | undefined +>; const zero = process.argv.includes("--zero"); const groups = ["dependencies", "peerDependencies", "optionalDependencies", "devDependencies"]; @@ -23,7 +25,7 @@ let failed = false; for (const group of groups) { for (const [name, range] of Object.entries(pkg[group] ?? {})) { if (name.startsWith("@bcts/")) { - console.error(`${group}: "${name}" is a monorepo package and cannot be published.`); + console.error(`${group}: "${name}" is an unpublished package and cannot be depended on.`); failed = true; } if (typeof range === "string" && range.startsWith("workspace:")) { @@ -34,7 +36,7 @@ for (const group of groups) { } if (zero) { - const runtime = Object.keys(pkg.dependencies ?? {}); + const runtime = Object.keys(pkg["dependencies"] ?? {}); if (runtime.length > 0) { console.error("zero-dependency policy violated:", runtime.join(", ")); failed = true; @@ -42,4 +44,4 @@ if (zero) { } if (failed) process.exit(1); -console.log(zero ? "zero runtime dependencies" : "no monorepo dependencies"); +console.log(zero ? "zero runtime dependencies" : "no unpublishable dependencies"); diff --git a/scripts/generate-vectors.mjs b/scripts/generate-vectors.ts similarity index 83% rename from scripts/generate-vectors.mjs rename to scripts/generate-vectors.ts index 4e5d36c..28b9320 100644 --- a/scripts/generate-vectors.mjs +++ b/scripts/generate-vectors.ts @@ -1,5 +1,5 @@ /** - * Golden vector generator. `bun scripts/generate-vectors.mjs`. + * Golden vector generator. `bun scripts/generate-vectors.ts`. * Materialises the golden recipe subset with the WORKING TREE and writes * tests/vectors/vectors.json. With VECTORS_FROM=baseline it materialises * with the frozen bundle instead, the way the file was first created. @@ -14,7 +14,6 @@ import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; import { DirectoryConfig, setDirectoryConfig } from "@blockchaincommons/known-values"; import { materialize, recipeName } from "../tests/vectors/recipes.ts"; -import { baselineAdapterFor } from "../tests/vectors/baseline-adapter.ts"; import { workingTreeAdapterFor } from "../tests/vectors/working-tree-adapter.ts"; import { goldenRecipes } from "../tests/corpus/corpus.ts"; import { baselineDeps, baselineModule, currentDeps, currentModule } from "../tests/vectors/deps.ts"; @@ -24,13 +23,13 @@ setDirectoryConfig(new DirectoryConfig()); const root = join(dirname(fileURLToPath(import.meta.url)), ".."); const api = - process.env.VECTORS_FROM === "baseline" + process.env["VECTORS_FROM"] === "baseline" ? await (async () => { const m = await baselineModule(); - return baselineAdapterFor(m, baselineDeps(m)); + return workingTreeAdapterFor(m, baselineDeps(m)); })() : workingTreeAdapterFor(await currentModule(), currentDeps); -const vectors = []; +const vectors: { name: string; recipe: unknown; expect: string }[] = []; for (const recipe of goldenRecipes(materializedFrom(api))) vectors.push({ name: recipeName(recipe), recipe, expect: materialize(api, recipe) }); writeFileSync( @@ -39,5 +38,5 @@ writeFileSync( ); const throws = vectors.filter((v) => v.expect.startsWith("throw:")).length; console.log( - `wrote ${vectors.length} vectors (${throws} throw) from ${process.env.VECTORS_FROM === "baseline" ? "the frozen baseline" : "working tree"}`, + `wrote ${vectors.length} vectors (${throws} throw) from ${process.env["VECTORS_FROM"] === "baseline" ? "the frozen baseline" : "working tree"}`, ); diff --git a/scripts/pin-lint-typescript.mjs b/scripts/pin-lint-typescript.ts similarity index 64% rename from scripts/pin-lint-typescript.mjs rename to scripts/pin-lint-typescript.ts index b6e6daf..1fb8318 100644 --- a/scripts/pin-lint-typescript.mjs +++ b/scripts/pin-lint-typescript.ts @@ -6,8 +6,13 @@ * `typescript6` npm alias devDependency) via node_modules symlinks; `tsc` * and tsdown keep resolving the root TypeScript 7. * - * Runs from the root `postinstall` hook. Remove this script together with - * the `typescript6` devDependency once upstream supports TS7. + * Runs from the root `prepare` hook, which a package manager runs for the + * project being installed and not for a dependency fetched from the registry + * (this script is not shipped). It also runs on `npm pack` and `npm publish`, + * so a missing `typescript6` is a notice, not a failure: inside the + * `bc-typescript` workspace the dependency is hoisted to the root, which + * applies the same pin once with `bun run pin`. Remove this script together + * with the `typescript6` devDependency once upstream supports TS7. */ import { existsSync, mkdirSync, readdirSync, rmSync, symlinkSync } from "node:fs"; import { dirname, join } from "node:path"; @@ -17,14 +22,12 @@ const nodeModules = join(dirname(fileURLToPath(import.meta.url)), "..", "node_mo const ts6 = join(nodeModules, "typescript6"); if (!existsSync(ts6)) { - console.error("pin-lint-typescript: node_modules/typescript6 missing - run bun install"); - process.exit(1); + console.log("pin-lint-typescript: no local node_modules/typescript6 - nothing to pin here"); + process.exit(0); } const consumers = [ - ...readdirSync(join(nodeModules, "@typescript-eslint")).map((d) => - join("@typescript-eslint", d), - ), + ...readdirSync(join(nodeModules, "@typescript-eslint")).map((d) => join("@typescript-eslint", d)), "ts-api-utils", "typedoc", ]; diff --git a/scripts/set-coverage-floors.mjs b/scripts/set-coverage-floors.ts similarity index 66% rename from scripts/set-coverage-floors.mjs rename to scripts/set-coverage-floors.ts index 5fd03e2..a1dde54 100644 --- a/scripts/set-coverage-floors.mjs +++ b/scripts/set-coverage-floors.ts @@ -1,7 +1,7 @@ /** * Seeds vitest.config.ts coverage thresholds from a measured run. * - * bun run test:coverage && node scripts/set-coverage-floors.mjs + * bun run test:coverage && bun scripts/set-coverage-floors.ts * * Reads coverage/coverage-summary.json and writes each metric's floor a few * points below the measured value. Thresholds are raise-only by policy: this @@ -17,13 +17,17 @@ if (!existsSync(summaryPath)) { console.error("coverage/coverage-summary.json not found - run `bun run test:coverage` first."); process.exit(1); } -const total = JSON.parse(readFileSync(summaryPath, "utf8")).total; +const total = ( + JSON.parse(readFileSync(summaryPath, "utf8")) as { + total: Record; + } +).total; const HEADROOM = 2; const measured = { - statements: Math.max(0, Math.floor(total.statements.pct) - HEADROOM), - branches: Math.max(0, Math.floor(total.branches.pct) - HEADROOM), - functions: Math.max(0, Math.floor(total.functions.pct) - HEADROOM), - lines: Math.max(0, Math.floor(total.lines.pct) - HEADROOM), + statements: Math.max(0, Math.floor(total["statements"].pct) - HEADROOM), + branches: Math.max(0, Math.floor(total["branches"].pct) - HEADROOM), + functions: Math.max(0, Math.floor(total["functions"].pct) - HEADROOM), + lines: Math.max(0, Math.floor(total["lines"].pct) - HEADROOM), }; const cfgPath = join(root, "vitest.config.ts"); @@ -31,10 +35,13 @@ let cfg = readFileSync(cfgPath, "utf8"); for (const [metric, value] of Object.entries(measured)) { const re = new RegExp(`(${metric}:\\s*)(\\d+)`); const m = re.exec(cfg); - if (!m) { console.error(`no ${metric} threshold found in vitest.config.ts`); process.exit(1); } + if (!m) { + console.error(`no ${metric} threshold found in vitest.config.ts`); + process.exit(1); + } const current = Number(m[2]); const next = Math.max(current, value); cfg = cfg.replace(re, `$1${next}`); - console.log(`${metric}: ${current} -> ${next} (measured ${total[metric].pct}%)`); + console.log(`${metric}: ${current} -> ${next} (measured ${total[metric]?.pct}%)`); } writeFileSync(cfgPath, cfg); diff --git a/scripts/set-size-limits.mjs b/scripts/set-size-limits.mjs deleted file mode 100644 index 0cdda7d..0000000 --- a/scripts/set-size-limits.mjs +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Seeds .size-limit.json from a real measurement. - * - * node scripts/set-size-limits.mjs - * - * Runs size-limit in JSON mode with the limits removed, then writes each - * entry's limit at the measured size plus 20% headroom, rounded up to the next - * whole kB. Guessed budgets are worse than measured ones: a budget that is too - * tight fails CI on day one, and one that is too loose never catches anything. - */ -import { execFileSync } from "node:child_process"; -import { readFileSync, writeFileSync } from "node:fs"; -import { dirname, join } from "node:path"; -import { fileURLToPath } from "node:url"; - -const root = join(dirname(fileURLToPath(import.meta.url)), ".."); -const cfgPath = join(root, ".size-limit.json"); -const cfg = JSON.parse(readFileSync(cfgPath, "utf8")); - -// measure with the limits lifted -const probe = cfg.map(({ limit, ...rest }) => ({ ...rest, void: limit })); -writeFileSync(cfgPath, JSON.stringify(probe.map(({ void: _v, ...r }) => r), null, 2) + "\n"); - -let measured; -try { - const out = execFileSync("bunx", ["size-limit", "--json"], { cwd: root, encoding: "utf8" }); - measured = JSON.parse(out.slice(out.indexOf("["))); -} finally { - writeFileSync(cfgPath, JSON.stringify(cfg, null, 2) + "\n"); -} - -const updated = cfg.map((entry, i) => { - const bytes = measured[i]?.size ?? 0; - const kb = Math.ceil((bytes * 1.2) / 1000); - console.log(`${entry.name}: measured ${(bytes / 1000).toFixed(2)} kB -> limit ${kb} kB`); - return { ...entry, limit: `${kb} kB` }; -}); -writeFileSync(cfgPath, JSON.stringify(updated, null, 2) + "\n"); diff --git a/scripts/tsconfig.json b/scripts/tsconfig.json new file mode 100644 index 0000000..a445d39 --- /dev/null +++ b/scripts/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "noEmit": true, + "rootDir": "..", + "isolatedDeclarations": false, + "allowImportingTsExtensions": true + }, + "include": ["./**/*.ts"] +} diff --git a/src/delegate.ts b/src/delegate.ts index 48ac04d..0d3e771 100644 --- a/src/delegate.ts +++ b/src/delegate.ts @@ -25,7 +25,7 @@ export interface XIDDocumentLike { } /** Parses a controller document from its envelope: `XIDDocument.fromEnvelope`. */ -export type ParseXIDDocument = (envelope: Envelope) => XIDDocumentLike; +type ParseXIDDocument = (envelope: Envelope) => XIDDocumentLike; /** What `Delegate.from` takes besides the controller. */ export interface DelegateInput { @@ -33,17 +33,11 @@ export interface DelegateInput { permissions?: Permissions | undefined; } -/** What `Delegate.fromEnvelope` takes besides the envelope. */ -export interface DelegateParseOptions { - /** The parser of the controller's envelope; `XIDDocument.fromEnvelope` unless given. */ - parseDocument?: ParseXIDDocument | undefined; -} - -let defaultParser: ParseXIDDocument | undefined; +let documentParser: ParseXIDDocument | undefined; -/** Installs the default controller parser (`XIDDocument.fromEnvelope`), late-bound to avoid an import cycle. */ +/** Installs the controller parser (`XIDDocument.fromEnvelope`), late-bound to avoid an import cycle. @internal */ export function setDefaultDocumentParser(parser: ParseXIDDocument): void { - defaultParser = parser; + documentParser = parser; } /** A delegate: a controller document and the permissions this document grants it. */ @@ -56,12 +50,16 @@ export class Delegate implements HasPermissions { this._permissions = permissions; } - /** A delegate controlled by `controller`, with no permissions unless given. */ + /** + * A delegate controlled by a copy of `controller` taken now (as the + * reference's `Delegate::new` clones it): a later change to the + * caller's document is not seen. No permissions unless given. + */ static from(controller: XIDDocumentLike, { permissions }: DelegateInput = {}): Delegate { - return new Delegate(controller, permissions ?? Permissions.from()); + return new Delegate(controller.clone(), permissions ?? Permissions.from()); } - /** The controlling document (live: mutating it mutates the delegate). */ + /** The delegate's own copy of the controlling document (live: mutating it mutates the delegate). */ get controller(): XIDDocumentLike { return this._controller; } @@ -76,21 +74,46 @@ export class Delegate implements HasPermissions { return this.xid.reference(); } - /** The permissions granted (live). */ + /** The permissions (live). */ get permissions(): Permissions { return this._permissions; } + /** The allowed privileges (a copy). */ + get allow(): ReadonlySet { + return this._permissions.allow; + } + + /** The denied privileges (a copy). */ + get deny(): ReadonlySet { + return this._permissions.deny; + } + /** Allows `privilege`. */ - allow(privilege: Privilege): void { + addAllow(privilege: Privilege): void { this._permissions.addAllow(privilege); } /** Denies `privilege`. */ - deny(privilege: Privilege): void { + addDeny(privilege: Privilege): void { this._permissions.addDeny(privilege); } + /** Stops allowing `privilege`. */ + removeAllow(privilege: Privilege): void { + this._permissions.removeAllow(privilege); + } + + /** Stops denying `privilege`. */ + removeDeny(privilege: Privilege): void { + this._permissions.removeDeny(privilege); + } + + /** Empties both sets. */ + clearAllPermissions(): void { + this._permissions.clearAllPermissions(); + } + /** The controller's envelope, wrapped, with the permissions. */ toEnvelope(): Envelope { return this._permissions.addToEnvelope(this._controller.toEnvelope().wrap()); @@ -98,15 +121,14 @@ export class Delegate implements HasPermissions { /** * A delegate from its envelope: the permissions, then the unwrapped - * controller parsed by `parseDocument` (`XIDDocument.fromEnvelope` - * unless given). A sibling failure is `EnvelopeParsing`. + * controller parsed with `XIDDocument.fromEnvelope`. A sibling failure + * is `EnvelopeParsing`. */ - static fromEnvelope(envelope: Envelope, { parseDocument }: DelegateParseOptions = {}): Delegate { - const parse = parseDocument ?? defaultParser; - if (parse === undefined) throw new TypeError("parseDocument is required"); + static fromEnvelope(envelope: Envelope): Delegate { + if (documentParser === undefined) throw new Error("the document module is not loaded"); const permissions = Permissions.fromEnvelope(envelope); const inner = guarded(() => envelope.unwrap()); - return new Delegate(parse(inner), permissions); + return new Delegate(documentParser(inner), permissions); } /** Same controller document and permissions — as the reference's equality. */ diff --git a/src/domain.ts b/src/domain.ts index 6054d25..00d02ba 100644 --- a/src/domain.ts +++ b/src/domain.ts @@ -15,10 +15,10 @@ * `ProvenanceMarkError` with code `Cbor` contributes its cause the same * way (`ProvenanceMark::try_from(CBOR)` returns the dcbor error). */ -import { CborError, type Cbor } from "@blockchaincommons/dcbor"; +import { CborDate, CborError, type Cbor } from "@blockchaincommons/dcbor"; import { ComponentsError } from "@blockchaincommons/components"; import { type Envelope, EnvelopeError, type EnvelopeInput } from "@blockchaincommons/envelope"; -import { ProvenanceMarkError } from "@blockchaincommons/provenance-mark"; +import { type DateInput, ProvenanceMarkError } from "@blockchaincommons/provenance-mark"; import { XIDError } from "./error"; /** @@ -142,10 +142,30 @@ export function expectOneOf( throw new TypeError(`${name} must be one of ${allowed.map((a) => `"${a}"`).join(", ")}`); } -/** A `Date` that holds a time, else a `TypeError`. */ -export function expectValidDate(value: unknown, name: string): Date { - if (value instanceof Date && !Number.isNaN(value.getTime())) return value; - throw new TypeError(`${name} must be a valid Date`); +/** A class whose instances a guard checks for (its constructor may be private). */ +export interface InstanceClass { + readonly prototype: T; + readonly name: string; +} + +/** `value` is an instance of `cls`, else a `TypeError` naming the argument. */ +export function expectInstance( + value: unknown, + cls: InstanceClass, + name: string, + what = `a ${cls.name}`, +): T { + if (value instanceof (cls as unknown as abstract new () => T)) return value; + throw new TypeError(`${name} must be ${what}`); +} + +/** + * A `Date` or `CborDate`, else a `TypeError`. Whether the date holds a + * time is the mark generator's check (`ProvenanceMark[InvalidDate]`). + */ +export function expectDateInput(value: unknown, name: string): DateInput { + if (value instanceof Date || value instanceof CborDate) return value; + throw new TypeError(`${name} must be a Date or a CborDate`); } /** `value` is not `null` (an absent option is `undefined`), else a `TypeError`. */ diff --git a/src/error.ts b/src/error.ts index c38dd21..20a3806 100644 --- a/src/error.ts +++ b/src/error.ts @@ -90,7 +90,7 @@ export interface XIDErrorDetailsByCode { /** The field must not be empty. */ EmptyValue: { /** The field's name. */ - readonly item: string; + readonly field: string; }; /** A known value that names no privilege. */ UnknownPrivilege: unknown; @@ -133,12 +133,12 @@ export interface XIDErrorDetailsByCode { /** The service's URI. */ readonly uri: string; }; - /** `expectKey` found no such key. */ + /** `checkContainsKey` found no such key. */ KeyNotFoundInDocument: { /** The key's public keys, rendered. */ readonly key: string; }; - /** `expectDelegate` found no such delegate. */ + /** `checkContainsDelegate` found no such delegate. */ DelegateNotFoundInDocument: { /** The delegate's XID, rendered. */ readonly delegate: string; @@ -216,10 +216,10 @@ export type XIDErrorTyped = C extends XID } : never; -/** `details` of the four item codes. */ -export type ItemDetails = XIDErrorDetailsFor< - "Duplicate" | "NotFound" | "StillReferenced" | "EmptyValue" ->; +/** `details` of the three item codes. */ +export type ItemDetails = XIDErrorDetailsFor<"Duplicate" | "NotFound" | "StillReferenced">; +/** `details` of `EmptyValue`. */ +export type EmptyValueDetails = XIDErrorDetailsFor<"EmptyValue">; /** `details` of the codes with nothing more to say. */ export type PlainDetails = XIDErrorDetailsFor< | "UnknownPrivilege" @@ -333,7 +333,7 @@ export class XIDError extends Error { /** `EmptyValue`: the field must not be empty. */ static emptyValue(field: string): XIDErrorTyped<"EmptyValue"> { - return XIDError.make(`invalid or empty value: ${field}`, { code: "EmptyValue", item: field }); + return XIDError.make(`invalid or empty value: ${field}`, { code: "EmptyValue", field }); } // Structure ----------------------------------------------------------------- @@ -412,7 +412,7 @@ export class XIDError extends Error { }); } - /** `KeyNotFoundInDocument`: `expectKey` found no such key. */ + /** `KeyNotFoundInDocument`: `checkContainsKey` found no such key. */ static keyNotFoundInDocument(key: string): XIDErrorTyped<"KeyNotFoundInDocument"> { return XIDError.make(`key not found in XID document: ${key}`, { code: "KeyNotFoundInDocument", @@ -420,7 +420,7 @@ export class XIDError extends Error { }); } - /** `DelegateNotFoundInDocument`: `expectDelegate` found no such delegate. */ + /** `DelegateNotFoundInDocument`: `checkContainsDelegate` found no such delegate. */ static delegateNotFoundInDocument(delegate: string): XIDErrorTyped<"DelegateNotFoundInDocument"> { return XIDError.make(`delegate not found in XID document: ${delegate}`, { code: "DelegateNotFoundInDocument", diff --git a/src/index.ts b/src/index.ts index 7ca2696..b8eaaf4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,6 +15,7 @@ export { type XIDErrorDetailsFor, type XIDErrorTyped, type ItemDetails, + type EmptyValueDetails, type PlainDetails, type UnexpectedPredicateDetails, type ServiceDetails, @@ -49,20 +50,18 @@ export { export { Service, type ServiceInput } from "./service"; -export { - Delegate, - type DelegateInput, - type DelegateParseOptions, - type ParseXIDDocument, - type XIDDocumentLike, -} from "./delegate"; +export { Delegate, type DelegateInput, type XIDDocumentLike } from "./delegate"; export { Provenance, type ProvenanceInput, type ProvenanceEnvelopeOptions, type XIDGeneratorOptions, + type GeneratorData, + type TakenGenerator, } from "./provenance"; +/** The date inputs (`genesis.date`, the next-mark options) take a `Date` or a `CborDate`. */ +export { type DateInput } from "@blockchaincommons/provenance-mark"; export { XIDDocument, @@ -79,4 +78,5 @@ export { type SignedEnvelopeOptions, type AttachmentInput, type NextProvenanceMarkOptions, + type ProvidedGeneratorOptions, } from "./xid-document"; diff --git a/src/key.ts b/src/key.ts index 9e076a7..8416a4e 100644 --- a/src/key.ts +++ b/src/key.ts @@ -245,6 +245,11 @@ export class Key implements HasPermissions, Verifier { this._endpoints.set(uri.toString(), uri); } + /** Removes an endpoint; whether it was there. */ + removeEndpoint(endpoint: URI | string): boolean { + return this._endpoints.delete(endpoint.toString()); + } + /** The nickname; empty when there is none. */ get nickname(): string { return this._nickname; @@ -267,16 +272,46 @@ export class Key implements HasPermissions, Verifier { return this._permissions; } + /** The allowed privileges (a copy). */ + get allow(): ReadonlySet { + return this._permissions.allow; + } + + /** The denied privileges (a copy). */ + get deny(): ReadonlySet { + return this._permissions.deny; + } + /** Allows `privilege`. */ - allow(privilege: Privilege): void { + addAllow(privilege: Privilege): void { this._permissions.addAllow(privilege); } /** Denies `privilege`. */ - deny(privilege: Privilege): void { + addDeny(privilege: Privilege): void { this._permissions.addDeny(privilege); } + /** Stops allowing `privilege`. */ + removeAllow(privilege: Privilege): void { + this._permissions.removeAllow(privilege); + } + + /** Stops denying `privilege`. */ + removeDeny(privilege: Privilege): void { + this._permissions.removeDeny(privilege); + } + + /** Empties both sets. */ + clearAllPermissions(): void { + this._permissions.clearAllPermissions(); + } + + /** `addAllow` under the reference's `Key::add_permission` name. */ + addPermission(privilege: Privilege): void { + this._permissions.addAllow(privilege); + } + private privateKeyAssertionEnvelope(): Envelope { if (this._privateKeyData === undefined) { throw new Error("privateKeyAssertionEnvelope called with no private key data"); diff --git a/src/permissions.ts b/src/permissions.ts index 7099e94..5135820 100644 --- a/src/permissions.ts +++ b/src/permissions.ts @@ -18,14 +18,29 @@ export interface PermissionsInput { deny?: Iterable | undefined; } -/** Something that carries permissions: a key, a delegate, a service. */ +/** + * Something that carries permissions: a key, a delegate, a service. The + * members are the reference's `HasPermissions` trait: `allow` and `deny` + * are the sets, `addAllow`/`addDeny`/`removeAllow`/`removeDeny` and + * `clearAllPermissions` edit them. + */ export interface HasPermissions { /** The permissions (live). */ readonly permissions: Permissions; + /** The allowed privileges (a copy). */ + readonly allow: ReadonlySet; + /** The denied privileges (a copy). */ + readonly deny: ReadonlySet; /** Allows `privilege`. */ - allow(privilege: Privilege): void; + addAllow(privilege: Privilege): void; /** Denies `privilege`. */ - deny(privilege: Privilege): void; + addDeny(privilege: Privilege): void; + /** Stops allowing `privilege`. */ + removeAllow(privilege: Privilege): void; + /** Stops denying `privilege`. */ + removeDeny(privilege: Privilege): void; + /** Empties both sets. */ + clearAllPermissions(): void; } /** An allow set and a deny set of privileges. */ @@ -79,26 +94,11 @@ export class Permissions { } /** Empties both sets. */ - clear(): void { + clearAllPermissions(): void { this._allow.clear(); this._deny.clear(); } - /** - * Allowed (directly or through `All`) and not denied (directly or - * through `All`): a denial wins over an allowance. This is the - * package's own rule; the reference exposes the sets only. - */ - isAllowed(privilege: Privilege): boolean { - if (this._deny.has(privilege) || this._deny.has("All")) return false; - return this._allow.has(privilege) || this._allow.has("All"); - } - - /** Denied directly or through `All`. */ - isDenied(privilege: Privilege): boolean { - return this._deny.has(privilege) || this._deny.has("All"); - } - /** Adds an `'allow'` assertion per allowed privilege, then a `'deny'` per denied one. */ addToEnvelope(envelope: Envelope): Envelope { let result = envelope; diff --git a/src/provenance.ts b/src/provenance.ts index e494417..8a857e7 100644 --- a/src/provenance.ts +++ b/src/provenance.ts @@ -24,15 +24,33 @@ import { kdfOf, passwordBytes, } from "./key"; -import { extractObjectForPredicate, guarded, leafAs } from "./domain"; +import { expectInstance, extractObjectForPredicate, guarded, leafAs } from "./domain"; /** How the generator goes into an envelope; the same four forms as private keys. */ export type XIDGeneratorOptions = "omit" | "include" | "elide" | EncryptOptions; /** The generator as held: in the clear, or the locked envelope as parsed. */ -type GeneratorData = - | { type: "decrypted"; generator: ProvenanceMarkGenerator } - | { type: "encrypted"; envelope: Envelope }; +export type GeneratorData = + | { + /** Held in the clear. */ + type: "decrypted"; + /** The generator. */ + generator: ProvenanceMarkGenerator; + } + | { + /** Held locked (parsed without the password). */ + type: "encrypted"; + /** The locked envelope. */ + envelope: Envelope; + }; + +/** What `takeGenerator` hands back: the generator as held and its salt. */ +export interface TakenGenerator { + /** The generator as held. */ + readonly data: GeneratorData; + /** The salt the `'provenanceGenerator'` assertion carried. */ + readonly salt: Salt; +} /** What `Provenance.from` takes besides the mark. */ export interface ProvenanceInput { @@ -59,10 +77,16 @@ export class Provenance { /** A mark, with the generator that produced it when the document should keep it. */ static from(mark: ProvenanceMark, { generator }: ProvenanceInput = {}): Provenance { return new Provenance( - mark, + expectInstance(mark, ProvenanceMark, "mark"), generator === undefined ? undefined - : { data: { type: "decrypted", generator }, salt: Salt.random({ length: 32 }) }, + : { + data: { + type: "decrypted", + generator: expectInstance(generator, ProvenanceMarkGenerator, "generator"), + }, + salt: Salt.random({ length: 32 }), + }, ); } @@ -93,19 +117,23 @@ export class Provenance { /** Replaces the mark (no chain check, as the reference's `set_mark`). */ setMark(mark: ProvenanceMark): void { - this._mark = mark; + this._mark = expectInstance(mark, ProvenanceMark, "mark"); } /** Sets or replaces the generator, with a fresh salt. */ setGenerator(generator: ProvenanceMarkGenerator): void { + expectInstance(generator, ProvenanceMarkGenerator, "generator"); this._generator = { data: { type: "decrypted", generator }, salt: Salt.random({ length: 32 }) }; } - /** Removes the generator, returning whether one was held. */ - takeGenerator(): boolean { - const had = this._generator !== undefined; + /** + * Removes and returns the generator as held (in the clear or the locked + * envelope) with its salt; `undefined` when there is none. + */ + takeGenerator(): TakenGenerator | undefined { + const taken = this._generator; this._generator = undefined; - return had; + return taken; } /** @@ -232,15 +260,14 @@ export class Provenance { /** Same mark and generator (in the clear or locked, with its salt) — as the reference's equality. */ equals(other: Provenance): boolean { + expectInstance(other, Provenance, "other"); if (!this._mark.equals(other._mark)) return false; const a = this._generator; const b = other._generator; if (a === undefined || b === undefined) return a === b; if (!a.salt.equals(b.salt)) return false; if (a.data.type === "decrypted" && b.data.type === "decrypted") { - return ( - JSON.stringify(a.data.generator.toJSON()) === JSON.stringify(b.data.generator.toJSON()) - ); + return a.data.generator.equals(b.data.generator); } if (a.data.type === "encrypted" && b.data.type === "encrypted") { return envelopeBytesEqual(a.data.envelope, b.data.envelope); diff --git a/src/service.ts b/src/service.ts index a35d33e..b5aadf9 100644 --- a/src/service.ts +++ b/src/service.ts @@ -121,9 +121,9 @@ export class Service implements HasPermissions { this._keyReferences.set(key, keyReference); } - /** Adds a key reference given as 64 hex characters (a components error otherwise). */ - addKeyReferenceHex(keyReferenceHex: string): void { - this.addKeyReference(Reference.fromHex(keyReferenceHex)); + /** Removes a key reference; whether it was there. */ + removeKeyReference(reference: Reference): boolean { + return this._keyReferences.delete(reference.toHex()); } /** References the key's public keys. */ @@ -148,9 +148,9 @@ export class Service implements HasPermissions { this._delegateReferences.set(key, delegateReference); } - /** Adds a delegate reference given as 64 hex characters (a components error otherwise). */ - addDelegateReferenceHex(delegateReferenceHex: string): void { - this.addDelegateReference(Reference.fromHex(delegateReferenceHex)); + /** Removes a delegate reference; whether it was there. */ + removeDelegateReference(reference: Reference): boolean { + return this._delegateReferences.delete(reference.toHex()); } /** References the delegate's (or document's) XID. */ @@ -175,16 +175,41 @@ export class Service implements HasPermissions { return this._permissions; } + /** The allowed privileges (a copy). */ + get allow(): ReadonlySet { + return this._permissions.allow; + } + + /** The denied privileges (a copy). */ + get deny(): ReadonlySet { + return this._permissions.deny; + } + /** Allows `privilege`. */ - allow(privilege: Privilege): void { + addAllow(privilege: Privilege): void { this._permissions.addAllow(privilege); } - /** Denies `privilege` (written to the wire, but not read back: see the class). */ - deny(privilege: Privilege): void { + /** Denies `privilege`. Written to the wire, but not read back: see the class. */ + addDeny(privilege: Privilege): void { this._permissions.addDeny(privilege); } + /** Stops allowing `privilege`. */ + removeAllow(privilege: Privilege): void { + this._permissions.removeAllow(privilege); + } + + /** Stops denying `privilege`. */ + removeDeny(privilege: Privilege): void { + this._permissions.removeDeny(privilege); + } + + /** Empties both sets. */ + clearAllPermissions(): void { + this._permissions.clearAllPermissions(); + } + /** The URI as the subject; `'key'`, `'delegate'`, `'capability'`, `'name'` and the permissions. */ toEnvelope(): Envelope { let envelope = Envelope.from(this._uri); diff --git a/src/xid-document.ts b/src/xid-document.ts index 8e62284..6465790 100644 --- a/src/xid-document.ts +++ b/src/xid-document.ts @@ -37,9 +37,9 @@ import { URI, XID, type Digest, - type PublicKeys, + PublicKeys, PrivateKeyBase, - type PrivateKeys, + PrivateKeys, type Signer, type EncapsulationPublicKey, type SigningPublicKey, @@ -48,7 +48,8 @@ import { TAG_XID } from "@blockchaincommons/tags"; import { type ToUR, type UR, decodeURWith, urFor } from "@blockchaincommons/uniform-resources"; import { type RngOptions } from "@blockchaincommons/rand"; import { - type ProvenanceMark, + type DateInput, + ProvenanceMark, ProvenanceMarkGenerator, type ProvenanceMarkResolution, PROVENANCE_MARK_RESOLUTIONS, @@ -66,7 +67,15 @@ import { Service } from "./service"; import { Delegate, setDefaultDocumentParser } from "./delegate"; import { Provenance, type XIDGeneratorOptions } from "./provenance"; import { XIDError } from "./error"; -import { cborErrorOf, expectOneOf, expectValidDate, guarded, leafAs, wrapForeign } from "./domain"; +import { + cborErrorOf, + expectDateInput, + expectInstance, + expectOneOf, + guarded, + leafAs, + wrapForeign, +} from "./domain"; /** * The inception key of a new document: public keys only, a private key @@ -95,8 +104,8 @@ export interface XIDGenesis { seed?: Uint8Array | ProvenanceSeed | undefined; /** The chain's resolution; `"high"` unless given. */ resolution?: ProvenanceMarkResolution | undefined; - /** The genesis mark's date; now unless given. */ - date?: Date | undefined; + /** The genesis mark's date, a `Date` or a `CborDate`; now unless given. */ + date?: DateInput | undefined; /** The genesis mark's info. */ info?: Cbor | undefined; } @@ -153,17 +162,20 @@ export interface AttachmentInput { conformsTo?: string | undefined; } -/** What `nextProvenanceMark` takes. */ +/** What `nextProvenanceMarkWithEmbeddedGenerator` takes. */ export interface NextProvenanceMarkOptions extends PasswordOptions { - /** The new mark's date; now unless given. */ - date?: Date | undefined; + /** The new mark's date, a `Date` or a `CborDate`; now unless given. */ + date?: DateInput | undefined; + /** The new mark's info. */ + info?: Cbor | undefined; +} + +/** What `nextProvenanceMarkWithProvidedGenerator` takes besides the generator. */ +export interface ProvidedGeneratorOptions { + /** The new mark's date, a `Date` or a `CborDate`; now unless given. */ + date?: DateInput | undefined; /** The new mark's info. */ info?: Cbor | undefined; - /** - * A generator kept outside the document; refused when the document - * holds one. When given, `password` is not used. - */ - generator?: ProvenanceMarkGenerator | undefined; } /** The document's CBOR codec, with the tag it carries. */ @@ -257,16 +269,27 @@ export class XIDDocument implements ToEnvelope, ToCbor, CborTagged, ToUR, Edgeab } private static keyFor(inceptionKey: XIDInceptionKey): Key { - if (typeof inceptionKey !== "object" || inceptionKey === null) { - throw new TypeError( - "inceptionKey must be PublicKeys, a PrivateKeyBase or { publicKeys, privateKeys }", - ); - } + if (inceptionKey instanceof PublicKeys) return Key.allowAll(inceptionKey); if (inceptionKey instanceof PrivateKeyBase) return Key.fromPrivateKeyBase(inceptionKey); - if ("privateKeys" in inceptionKey) { - return Key.from(inceptionKey.publicKeys, { privateKeys: inceptionKey.privateKeys }); + if ( + typeof inceptionKey === "object" && + inceptionKey !== null && + "privateKeys" in inceptionKey + ) { + return Key.from( + expectInstance(inceptionKey.publicKeys, PublicKeys, "inceptionKey.publicKeys"), + { + privateKeys: expectInstance( + inceptionKey.privateKeys, + PrivateKeys, + "inceptionKey.privateKeys", + ), + }, + ); } - return Key.allowAll(inceptionKey); + throw new TypeError( + "inceptionKey must be PublicKeys, a PrivateKeyBase or { publicKeys, privateKeys }", + ); } private static genesisFor(genesis: XIDGenesis | undefined): Provenance | undefined { @@ -282,12 +305,12 @@ export class XIDDocument implements ToEnvelope, ToCbor, CborTagged, ToUR, Edgeab resolution === undefined ? "high" : expectOneOf(resolution, PROVENANCE_MARK_RESOLUTIONS, "genesis.resolution"); - const at = date === undefined ? new Date() : expectValidDate(date, "genesis.date"); + const at = date === undefined ? new Date() : expectDateInput(date, "genesis.date"); const generator = passphrase !== undefined ? ProvenanceMarkGenerator.fromPassphrase(res, passphrase) : ProvenanceMarkGenerator.from({ res, seed: XIDDocument.seedOf(seed) }); - const mark = generator.next(at, { info }); + const mark = guarded(() => generator.next(at, info)); return Provenance.from(mark, { generator }); } @@ -344,9 +367,12 @@ export class XIDDocument implements ToEnvelope, ToCbor, CborTagged, ToUR, Edgeab this._resolutionMethods.set(uri.toString(), uri); } - /** Removes a resolution method; whether it was there. */ - removeResolutionMethod(method: URI | string): boolean { - return this._resolutionMethods.delete(method instanceof URI ? method.toString() : method); + /** Removes and returns a resolution method; `undefined` when it was not there. */ + removeResolutionMethod(method: URI | string): URI | undefined { + const key = method.toString(); + const uri = this._resolutionMethods.get(key); + if (uri !== undefined) this._resolutionMethods.delete(key); + return uri; } // Keys ---------------------------------------------------------------------- @@ -358,18 +384,19 @@ export class XIDDocument implements ToEnvelope, ToCbor, CborTagged, ToUR, Edgeab /** Adds a key; `Duplicate` when the public keys are already there. */ addKey(key: Key): void { + expectInstance(key, Key, "key"); const id = key.reference.toHex(); if (this._keys.has(id)) throw XIDError.duplicate("key"); this._keys.set(id, key); } /** The key with these public keys. */ - key(publicKeys: PublicKeys): Key | undefined { + findKeyByPublicKeys(publicKeys: PublicKeys): Key | undefined { return this._keys.get(publicKeys.reference().toHex()); } /** The key with this reference. */ - keyByReference(reference: Reference): Key | undefined { + findKeyByReference(reference: Reference): Key | undefined { for (const key of this._keys.values()) if (key.reference.equals(reference)) return key; return undefined; } @@ -395,11 +422,11 @@ export class XIDDocument implements ToEnvelope, ToCbor, CborTagged, ToUR, Edgeab return key; } - /** The key with these public keys; `KeyNotFoundInDocument` unless it is there. */ - expectKey(publicKeys: PublicKeys): Key { - const key = this.key(publicKeys); - if (key === undefined) throw XIDError.keyNotFoundInDocument(publicKeys.toString()); - return key; + /** `KeyNotFoundInDocument` unless the key with these public keys is there. */ + checkContainsKey(publicKeys: PublicKeys): void { + if (this.findKeyByPublicKeys(publicKeys) === undefined) { + throw XIDError.keyNotFoundInDocument(publicKeys.toString()); + } } /** Whether the XID derives from this signing key. */ @@ -446,7 +473,7 @@ export class XIDDocument implements ToEnvelope, ToCbor, CborTagged, ToUR, Edgeab /** Sets the key's nickname; `NotFound` unless the key is there. */ setNameForKey(publicKeys: PublicKeys, name: string): void { - const key = this.key(publicKeys); + const key = this.findKeyByPublicKeys(publicKeys); if (key === undefined) throw XIDError.notFound("key"); key.setNickname(name); } @@ -456,11 +483,11 @@ export class XIDDocument implements ToEnvelope, ToCbor, CborTagged, ToUR, Edgeab publicKeys: PublicKeys, options: PasswordOptions = {}, ): Envelope | undefined { - return this.key(publicKeys)?.privateKeyEnvelope(options); + return this.findKeyByPublicKeys(publicKeys)?.privateKeyEnvelope(options); } /** The inception key's private keys of a parsed envelope, unlocked with the password. */ - static inceptionPrivateKeysFromEnvelope( + static extractInceptionPrivateKeysFromEnvelope( envelope: Envelope, { password }: PasswordOptions = {}, ): PrivateKeys | undefined { @@ -476,18 +503,19 @@ export class XIDDocument implements ToEnvelope, ToCbor, CborTagged, ToUR, Edgeab /** Adds a delegate; `Duplicate` when a delegate with that XID is already there. */ addDelegate(delegate: Delegate): void { + expectInstance(delegate, Delegate, "delegate"); const id = delegate.xid.toHex(); if (this._delegates.has(id)) throw XIDError.duplicate("delegate"); this._delegates.set(id, delegate); } /** The delegate with this XID. */ - delegate(xid: XID): Delegate | undefined { + findDelegateByXid(xid: XID): Delegate | undefined { return this._delegates.get(xid.toHex()); } /** The delegate whose XID has this reference. */ - delegateByReference(reference: Reference): Delegate | undefined { + findDelegateByReference(reference: Reference): Delegate | undefined { for (const d of this._delegates.values()) if (d.reference.equals(reference)) return d; return undefined; } @@ -510,11 +538,11 @@ export class XIDDocument implements ToEnvelope, ToCbor, CborTagged, ToUR, Edgeab return delegate; } - /** The delegate with this XID; `DelegateNotFoundInDocument` unless it is there. */ - expectDelegate(xid: XID): Delegate { - const delegate = this.delegate(xid); - if (delegate === undefined) throw XIDError.delegateNotFoundInDocument(xid.toString()); - return delegate; + /** `DelegateNotFoundInDocument` unless the delegate with this XID is there. */ + checkContainsDelegate(xid: XID): void { + if (this.findDelegateByXid(xid) === undefined) { + throw XIDError.delegateNotFoundInDocument(xid.toString()); + } } // Services ------------------------------------------------------------------ @@ -525,12 +553,13 @@ export class XIDDocument implements ToEnvelope, ToCbor, CborTagged, ToUR, Edgeab } /** The service at this URI. */ - service(uri: URI | string): Service | undefined { + findServiceByUri(uri: URI | string): Service | undefined { return this._services.get(uri.toString()); } /** Adds a service; `Duplicate` when a service at that URI is already there. */ addService(service: Service): void { + expectInstance(service, Service, "service"); const id = service.uri.toString(); if (this._services.has(id)) throw XIDError.duplicate("service"); this._services.set(id, service); @@ -554,8 +583,8 @@ export class XIDDocument implements ToEnvelope, ToCbor, CborTagged, ToUR, Edgeab } /** Every service references known keys and delegates and allows something. */ - expectServicesConsistent(): void { - for (const service of this._services.values()) this.expectServiceConsistent(service); + checkServicesConsistency(): void { + for (const service of this._services.values()) this.checkServiceConsistency(service); } /** @@ -563,18 +592,18 @@ export class XIDDocument implements ToEnvelope, ToCbor, CborTagged, ToUR, Edgeab * `UnknownKeyReference`/`UnknownDelegateReference` for one the document * lacks, `NoPermissions` without an allowed privilege. */ - expectServiceConsistent(service: Service): void { + checkServiceConsistency(service: Service): void { const uri = service.uri.toString(); if (service.keyReferences.size === 0 && service.delegateReferences.size === 0) { throw XIDError.noReferences(uri); } for (const ref of service.keyReferences) { - if (this.keyByReference(ref) === undefined) { + if (this.findKeyByReference(ref) === undefined) { throw XIDError.unknownKeyReference(ref.toString(), uri); } } for (const ref of service.delegateReferences) { - if (this.delegateByReference(ref) === undefined) { + if (this.findDelegateByReference(ref) === undefined) { throw XIDError.unknownDelegateReference(ref.toString(), uri); } } @@ -615,7 +644,7 @@ export class XIDDocument implements ToEnvelope, ToCbor, CborTagged, ToUR, Edgeab } /** The attachment with this digest. */ - attachment(digest: Digest): Envelope | undefined { + getAttachment(digest: Digest): Envelope | undefined { return this._attachments.get(digest); } @@ -649,12 +678,7 @@ export class XIDDocument implements ToEnvelope, ToCbor, CborTagged, ToUR, Edgeab this._edges.add(edgeEnvelope); } - /** The edge with this digest. */ - edge(digest: Digest): Envelope | undefined { - return this._edges.get(digest); - } - - /** `edge(digest)` under the name envelope's `Edgeable` uses. */ + /** The edge with this digest (envelope's `Edgeable`). */ getEdge(digest: Digest): Envelope | undefined { return this._edges.get(digest); } @@ -683,44 +707,79 @@ export class XIDDocument implements ToEnvelope, ToCbor, CborTagged, ToUR, Edgeab /** Sets (or clears) the mark, dropping any generator. */ setProvenance(provenance: ProvenanceMark | undefined): void { - this._provenance = provenance === undefined ? undefined : Provenance.from(provenance); + this._provenance = + provenance === undefined + ? undefined + : Provenance.from(expectInstance(provenance, ProvenanceMark, "provenance")); } /** Sets the mark and the generator that continues its chain. */ setProvenanceWithGenerator(generator: ProvenanceMarkGenerator, mark: ProvenanceMark): void { - this._provenance = Provenance.from(mark, { generator }); + this._provenance = Provenance.from(expectInstance(mark, ProvenanceMark, "mark"), { + generator: expectInstance(generator, ProvenanceMarkGenerator, "generator"), + }); + } + + /** + * Advances the chain with the document's own generator, unlocked with + * the password when it is locked; the generator stays in the document. + * `NoProvenanceMark` without a mark, `NoGenerator` without a generator, + * `InvalidPassword` when it is locked and the password is missing or + * wrong, `ChainIdMismatch`/`SequenceMismatch` when the generator does + * not continue the mark at the next sequence number; a `Date` without a + * time is `ProvenanceMark[InvalidDate]`; a date of another kind is a + * `TypeError`. + */ + nextProvenanceMarkWithEmbeddedGenerator({ + password, + date, + info, + }: NextProvenanceMarkOptions = {}): void { + const at = date === undefined ? new Date() : expectDateInput(date, "date"); + if (this._provenance === undefined) throw XIDError.noProvenanceMark(); + const generator = this._provenance.unlockGenerator({ password }); + if (generator === undefined) throw XIDError.noGenerator(); + this.advance(this._provenance, generator, at, info); } /** - * Advances the chain: with the document's own generator (unlocked with - * the password when locked), or with a provided one when the document - * has none. The generator must continue the current mark's chain at - * the next sequence number. `NoProvenanceMark` without a mark, - * `NoGenerator`/`GeneratorConflict` for the wrong choice, - * `ChainIdMismatch`/`SequenceMismatch` for a generator that does not - * continue the mark; an invalid date is a `TypeError`. + * Advances the chain with a generator the caller keeps; the generator + * is advanced in place and not stored. `NoProvenanceMark` without a + * mark, `GeneratorConflict` when the document holds a generator (in the + * clear or locked), `ChainIdMismatch`/`SequenceMismatch` when the + * generator does not continue the mark at the next sequence number; a + * `Date` without a time is `ProvenanceMark[InvalidDate]`; a generator or + * date of another kind is a `TypeError`. */ - nextProvenanceMark({ date, info, password, generator }: NextProvenanceMarkOptions = {}): void { - const at = date === undefined ? new Date() : expectValidDate(date, "date"); + nextProvenanceMarkWithProvidedGenerator( + generator: ProvenanceMarkGenerator, + { date, info }: ProvidedGeneratorOptions = {}, + ): void { + expectInstance(generator, ProvenanceMarkGenerator, "generator"); + const at = date === undefined ? new Date() : expectDateInput(date, "date"); if (this._provenance === undefined) throw XIDError.noProvenanceMark(); - const currentMark = this._provenance.mark; - let gen: ProvenanceMarkGenerator; - if (generator !== undefined) { - if (this._provenance.hasGenerator || this._provenance.hasEncryptedGenerator) { - throw XIDError.generatorConflict(); - } - gen = generator; - } else { - const own = this._provenance.unlockGenerator({ password }); - if (own === undefined) throw XIDError.noGenerator(); - gen = own; + if (this._provenance.hasGenerator || this._provenance.hasEncryptedGenerator) { + throw XIDError.generatorConflict(); } - if (!bytesEqual(gen.chainId, currentMark.chainId)) { - throw XIDError.chainIdMismatch(currentMark.chainId, gen.chainId); + this.advance(this._provenance, generator, at, info); + } + + /** The checks and the step both forms share. */ + private advance( + provenance: Provenance, + generator: ProvenanceMarkGenerator, + at: DateInput, + info: Cbor | undefined, + ): void { + const currentMark = provenance.mark; + if (!bytesEqual(generator.chainId, currentMark.chainId)) { + throw XIDError.chainIdMismatch(currentMark.chainId, generator.chainId); } const expectedSeq = currentMark.seq + 1; - if (gen.nextSeq !== expectedSeq) throw XIDError.sequenceMismatch(expectedSeq, gen.nextSeq); - this._provenance.setMark(gen.next(at, { info })); + if (generator.nextSeq !== expectedSeq) { + throw XIDError.sequenceMismatch(expectedSeq, generator.nextSeq); + } + provenance.setMark(guarded(() => generator.next(at, info))); } // Envelope ------------------------------------------------------------------ @@ -874,7 +933,7 @@ export class XIDDocument implements ToEnvelope, ToCbor, CborTagged, ToUR, Edgeab } doc._attachments = attachments; doc._edges = edges; - doc.expectServicesConsistent(); + doc.checkServicesConsistency(); return doc; } @@ -983,6 +1042,7 @@ export class XIDDocument implements ToEnvelope, ToCbor, CborTagged, ToUR, Edgeab * the reference's equality. */ equals(other: XIDDocument): boolean { + expectInstance(other, XIDDocument, "other", "an XIDDocument"); if (!this._xid.equals(other._xid)) return false; if (this._resolutionMethods.size !== other._resolutionMethods.size) return false; for (const key of this._resolutionMethods.keys()) { diff --git a/tests/__snapshots__/boundary-behaviours.test.ts.snap b/tests/__snapshots__/boundary-behaviours.test.ts.snap new file mode 100644 index 0000000..c59f4b8 --- /dev/null +++ b/tests/__snapshots__/boundary-behaviours.test.ts.snap @@ -0,0 +1,25 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`boundary behaviours > a CborDate at the date inputs 1`] = ` +[ + "0", + "1", + "throw:ProvenanceMark|provenance mark error", +] +`; + +exports[`boundary behaviours > plain objects where instances go 1`] = ` +[ + "throw:TypeError|inceptionKey must be PublicKeys, a PrivateKeyBase or { publicKeys, privateKeys }", + "throw:TypeError|inceptionKey.publicKeys must be a PublicKeys", + "throw:TypeError|key must be a Key", + "throw:TypeError|service must be a Service", + "throw:TypeError|delegate must be a Delegate", + "throw:TypeError|other must be an XIDDocument", + "throw:TypeError|generator must be a ProvenanceMarkGenerator", + "throw:TypeError|provenance must be a ProvenanceMark", + "throw:TypeError|mark must be a ProvenanceMark", + "throw:TypeError|mark must be a ProvenanceMark", + "throw:TypeError|other must be a Provenance", +] +`; diff --git a/tests/__snapshots__/golden.test.ts.snap b/tests/__snapshots__/golden.test.ts.snap index 296f2d7..d08d675 100644 --- a/tests/__snapshots__/golden.test.ts.snap +++ b/tests/__snapshots__/golden.test.ts.snap @@ -277,8 +277,8 @@ XID(71274df1) [ ]", "## mutate privateKeyBase:7eb559bb res×1: addResolution,removeResolution,removeResolution,addResolution addResolution=ok -removeResolution=true -removeResolution=false +removeResolution=https://r.example +removeResolution=undefined addResolution=ok === XID(71274df1) [ @@ -328,6 +328,76 @@ XID(71274df1) [ 'allow': 'All' ] 'provenance': ProvenanceMark(2c4ca5f83803166663f9f8cedacc1946b570632324b377f9be8bdfba3fae9f21) +]", + "## mutate privateKeyBase:7eb559bb genesis(low "Wolf" 2025-01-01T00:00:00Z): nextMarkProvided,dropGenerator,nextMarkProvided,nextMarkProvided,nextMark,nextMarkProvided(fresh),nextMarkProvided +nextMarkProvided=throw:GeneratorConflict|document already has generator, cannot provide external generator +dropGenerator=ok +nextMarkProvided=ok +nextMarkProvided=ok +nextMark=throw:NoGenerator|document does not have generator, must provide external generator +nextMarkProvided=throw:SequenceMismatch|generator sequence mismatch: expected 3, got 1 +nextMarkProvided=throw:ChainIdMismatch|generator chain ID mismatch: expected 090bf2f8, got 3403eea7 +=== +XID(71274df1) [ + 'key': PublicKeys(eb9b1cae, SigningPublicKey(71274df1, SchnorrPublicKey(9022010e)), EncapsulationPublicKey(b4f7059a, X25519PublicKey(b4f7059a))) [ + 'allow': 'All' + ] + 'provenance': ProvenanceMark(db0363c595aa57034b5042bd490f0988a45ed784cc56cc70253678520d0d0628) +]", + "## mutate privateKeyBase:7eb559bb: nextMarkProvided,dropGenerator +nextMarkProvided=throw:NoProvenanceMark|no provenance mark to advance +dropGenerator=ok +=== +XID(71274df1) [ + 'key': PublicKeys(eb9b1cae, SigningPublicKey(71274df1, SchnorrPublicKey(9022010e)), EncapsulationPublicKey(b4f7059a, X25519PublicKey(b4f7059a))) [ + 'allow': 'All' + ] +]", + "## mutate privateKeyBase:7eb559bb keys×2: removeEndpoint,removeEndpoint,removeEndpoint,removeEndpoint +removeEndpoint=true +removeEndpoint=false +removeEndpoint=false +removeEndpoint=false +=== +XID(71274df1) [ + 'key': PublicKeys(22355237, SigningPublicKey(48f7e2df, Ed25519PublicKey(2c3d976b)), EncapsulationPublicKey(36a0b431, X25519PublicKey(36a0b431))) + 'key': PublicKeys(b67d8052, SigningPublicKey(8ba3695a, Ed25519PublicKey(b19aa0c9)), EncapsulationPublicKey(e472f495, X25519PublicKey(e472f495))) [ + 'allow': 'Sign' + 'endpoint': URI(https://e2.example) + ] + 'key': PublicKeys(eb9b1cae, SigningPublicKey(71274df1, SchnorrPublicKey(9022010e)), EncapsulationPublicKey(b4f7059a, X25519PublicKey(b4f7059a))) [ + 'allow': 'All' + ] +]", + "## mutate privateKeyBase:7eb559bb keys×2 services×1: removeKeyReference,removeKeyReference,removeKeyReference,checkServices,removeKey +removeKeyReference=true +removeKeyReference=false +removeKeyReference=undefined +checkServices=throw:NoReferences|no key or delegate references in service 'https://s.example' +removeKey=ok +=== +XID(71274df1) [ + 'key': PublicKeys(22355237, SigningPublicKey(48f7e2df, Ed25519PublicKey(2c3d976b)), EncapsulationPublicKey(36a0b431, X25519PublicKey(36a0b431))) + 'key': PublicKeys(eb9b1cae, SigningPublicKey(71274df1, SchnorrPublicKey(9022010e)), EncapsulationPublicKey(b4f7059a, X25519PublicKey(b4f7059a))) [ + 'allow': 'All' + ] + 'service': URI(https://s.example) [ + 'allow': 'Sign' + ] +]", + "## mutate privateKeyBase:7eb559bb delegates×1 services×1: removeDelegateReference,removeDelegateReference,removeDelegate,checkServices +removeDelegateReference=true +removeDelegateReference=false +removeDelegate=ok +checkServices=throw:NoReferences|no key or delegate references in service 'https://d.example' +=== +XID(71274df1) [ + 'key': PublicKeys(eb9b1cae, SigningPublicKey(71274df1, SchnorrPublicKey(9022010e)), EncapsulationPublicKey(b4f7059a, X25519PublicKey(b4f7059a))) [ + 'allow': 'All' + ] + 'service': URI(https://d.example) [ + 'allow': 'Access' + ] ]", ] `; diff --git a/tests/baseline/README.md b/tests/baseline/README.md index a3ffded..a226e26 100644 --- a/tests/baseline/README.md +++ b/tests/baseline/README.md @@ -1,15 +1,17 @@ # Frozen baseline build -`xid-baseline.mjs` is the self-contained ESM bundle of `@blockchaincommons/xid` built from -commit `c1425268d9c23764aaf396fb2c77f66475f4a434`, the wire-format reference before this package's API. It is built from -the PUBLISHED `@bcts` packages (`@bcts/xid` 1.0.0-beta.6 and its closure, -pinned by tests/baseline/package.json), so every sibling is inlined exactly -once, with the behaviour consumers had. +`xid-baseline.mjs` is the self-contained ESM bundle of `@blockchaincommons/xid` as it +shipped at commit `050785674b2002245d332cd9df9e094168d97fd2` (`1.0.0-beta.2`), with every `@blockchaincommons` +sibling inlined from the workspace. It also re-exports the sibling values the +differential drives it with (keys, envelopes, CBOR, known values, the +provenance generator), so they are the bundle's own classes. `xid-baseline.d.mts` is the public surface at that commit. `tests/differential.test.ts` runs every corpus recipe through this bundle and -the working tree and asserts identical outcomes; it pins the sha256 below so -an accidental rebuild cannot turn the differential into a self-comparison. +the working tree and asserts identical outcomes outside the enumerated +tombstones; it pins the sha256 below so an accidental rebuild cannot turn the +differential into a self-comparison. Rebuild with +`bun scripts/build-baseline.ts 0507856`. -Baseline commit: c1425268d9c23764aaf396fb2c77f66475f4a434 -Baseline sha256: fe7af93fb0dcbc7a484ef135b6f82161838c7fffa76e9f63dff60c66dd3f32a1 +Baseline commit: 050785674b2002245d332cd9df9e094168d97fd2 +Baseline sha256: 44de782eb959ff35f0ee98b6dd803020d7d6e0dc28f1b05f13aaf4e059e78bb2 diff --git a/tests/baseline/entry.ts b/tests/baseline/entry.ts deleted file mode 100644 index 76ea710..0000000 --- a/tests/baseline/entry.ts +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Baseline bundle entry: the PUBLISHED `@bcts` packages (`@bcts/*` - * 1.0.0-beta.6, one copy of each, installed under this directory from - * `package.json`) plus the sibling values the differential needs to drive - * them (seeded keys, envelopes, CBOR values). - */ -export * from "@bcts/xid"; -export { - PrivateKeyBase, - PrivateKeys, - PublicKeys, - Digest, - Reference, - URI, - KeyDerivationMethod, -} from "@bcts/components"; -export { Envelope } from "@bcts/envelope"; -export { IS_A, SOURCE, TARGET } from "@bcts/known-values"; -export { makeFakeRandomNumberGenerator } from "@bcts/rand"; -export { - ProvenanceMarkGenerator, - ProvenanceMarkResolution, - ProvenanceSeed, -} from "@bcts/provenance-mark"; -export { cbor as baselineCbor } from "@bcts/dcbor"; diff --git a/tests/baseline/package-lock.json b/tests/baseline/package-lock.json deleted file mode 100644 index 9d03b5c..0000000 --- a/tests/baseline/package-lock.json +++ /dev/null @@ -1,334 +0,0 @@ -{ - "name": "xid-baseline-closure", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "xid-baseline-closure", - "dependencies": { - "@bcts/xid": "1.0.0-beta.6" - } - }, - "node_modules/@bcts/components": { - "version": "1.0.0-beta.6", - "resolved": "https://registry.npmjs.org/@bcts/components/-/components-1.0.0-beta.6.tgz", - "integrity": "sha512-49XuO8p/JbAL8roFkBjUDhMwqvQHIvAcdWqzGS6Grq2un578E4BsnItWaTVgzOZYSAWq0gBJorXocFUu1hrEhA==", - "license": "BSD-2-Clause-Patent", - "dependencies": { - "@bcts/crypto": "^1.0.0-beta.6", - "@bcts/dcbor": "^1.0.0-beta.6", - "@bcts/rand": "^1.0.0-beta.6", - "@bcts/sskr": "^1.0.0-beta.6", - "@bcts/tags": "^1.0.0-beta.6", - "@bcts/uniform-resources": "^1.0.0-beta.6", - "@noble/curves": "^2.2.0", - "@noble/hashes": "^2.2.0", - "@noble/post-quantum": "^0.6.1", - "@scure/base": "^2.2.0", - "@scure/sr25519": "^2.2.0", - "pako": "^3.0.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@bcts/crypto": { - "version": "1.0.0-beta.6", - "resolved": "https://registry.npmjs.org/@bcts/crypto/-/crypto-1.0.0-beta.6.tgz", - "integrity": "sha512-o05OmhjLTNeGRBKKuduWmPNACYs+oyUQ7Kdbu5nMGehv0E/QHPSfX+jZHjonPow9wYz6cvwU8Lln0S/lC0Cxuw==", - "license": "BSD-2-Clause-Patent", - "dependencies": { - "@bcts/rand": "^1.0.0-beta.6", - "@noble/ciphers": "^2.2.0", - "@noble/curves": "^2.2.0", - "@noble/hashes": "^2.2.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@bcts/dcbor": { - "version": "1.0.0-beta.6", - "resolved": "https://registry.npmjs.org/@bcts/dcbor/-/dcbor-1.0.0-beta.6.tgz", - "integrity": "sha512-LVnifVJPD3RkvVGzzYzDWYTrgTxUBPuLpPvnFbDnYeS/7pFvN6qv9OjnRnLb4Ug2WrwBMm7aMnG17iqT87u4/A==", - "license": "BSD-2-Clause-Patent", - "dependencies": { - "@blockchaincommons/dcbor": "^1.0.0-beta.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@bcts/envelope": { - "version": "1.0.0-beta.6", - "resolved": "https://registry.npmjs.org/@bcts/envelope/-/envelope-1.0.0-beta.6.tgz", - "integrity": "sha512-70n4xshiHikE/Xur7oi+s2s684upb38dcPHetLVBjCuVd3/Wv1jDPphLwOzHDvopGd2nYIFtzBlmCd92NGay0g==", - "license": "BSD-2-Clause-Patent", - "dependencies": { - "@bcts/components": "^1.0.0-beta.6", - "@bcts/crypto": "^1.0.0-beta.6", - "@bcts/dcbor": "^1.0.0-beta.6", - "@bcts/known-values": "^1.0.0-beta.6", - "@bcts/rand": "^1.0.0-beta.6", - "@bcts/sskr": "^1.0.0-beta.6", - "@bcts/tags": "^1.0.0-beta.6", - "@bcts/uniform-resources": "^1.0.0-beta.6", - "pako": "^3.0.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@bcts/known-values": { - "version": "1.0.0-beta.6", - "resolved": "https://registry.npmjs.org/@bcts/known-values/-/known-values-1.0.0-beta.6.tgz", - "integrity": "sha512-oIoQKnlmFR1cKeo7pj0RhzA6nW3PGVx2LETnZoTESBsqXz90ezmjA/3M4yvJN3PSouyd6CYBPeXYmZ4GZPP93A==", - "license": "BSD-2-Clause-Patent", - "dependencies": { - "@bcts/components": "^1.0.0-beta.6", - "@bcts/dcbor": "^1.0.0-beta.6" - } - }, - "node_modules/@bcts/provenance-mark": { - "version": "1.0.0-beta.6", - "resolved": "https://registry.npmjs.org/@bcts/provenance-mark/-/provenance-mark-1.0.0-beta.6.tgz", - "integrity": "sha512-SD9iniN3WozunIpXX9Bou3xveWmgXh2AB0b62MqYTi+VKqyEe51pOq2J9hHoWjawYcQDHEKFiN40cNWAIqxQfA==", - "license": "BSD-2-Clause-Patent", - "dependencies": { - "@bcts/dcbor": "^1.0.0-beta.6", - "@bcts/envelope": "^1.0.0-beta.6", - "@bcts/rand": "^1.0.0-beta.6", - "@bcts/tags": "^1.0.0-beta.6", - "@bcts/uniform-resources": "^1.0.0-beta.6", - "@noble/ciphers": "^2.2.0", - "@noble/hashes": "^2.2.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@bcts/rand": { - "version": "1.0.0-beta.6", - "resolved": "https://registry.npmjs.org/@bcts/rand/-/rand-1.0.0-beta.6.tgz", - "integrity": "sha512-i8ayDtIqSBZDKid04yuHzGZsG3uUGGG5tQ+uME59+40K1c0oNy+ESgNpBn+Etj+Q1+3P8isZ8z0LQX18ZZmYvw==", - "license": "BSD-2-Clause-Patent", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@bcts/shamir": { - "version": "1.0.0-beta.6", - "resolved": "https://registry.npmjs.org/@bcts/shamir/-/shamir-1.0.0-beta.6.tgz", - "integrity": "sha512-5iH9tgcWzsRwJ7F470n/QFO8Ck3jZaTfJbg2uHmzGtkEBFIuyA9OExdmn+db0A+ZA4z3dB2o/r4gyT+JWKylDg==", - "license": "BSD-2-Clause-Patent", - "dependencies": { - "@bcts/crypto": "^1.0.0-beta.6", - "@bcts/rand": "^1.0.0-beta.6" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@bcts/sskr": { - "version": "1.0.0-beta.6", - "resolved": "https://registry.npmjs.org/@bcts/sskr/-/sskr-1.0.0-beta.6.tgz", - "integrity": "sha512-3Yh2izDx/8S4GZzmEWTvhwTRooaXLXBjepgKpcrspAQ1by1GsU8YV7uhLRnFtTKPtrdRezHJIvlXwkDwKb5MHw==", - "license": "BSD-2-Clause-Patent", - "dependencies": { - "@bcts/rand": "^1.0.0-beta.6", - "@bcts/shamir": "^1.0.0-beta.6" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@bcts/tags": { - "version": "1.0.0-beta.6", - "resolved": "https://registry.npmjs.org/@bcts/tags/-/tags-1.0.0-beta.6.tgz", - "integrity": "sha512-yEDdEfSHmMyM4gFwHCuYw6rUcuGG0qmeN9tH5Lc6gJW8vFsWFNdsx2OyAUX8aIhjBNAo2onV3ruzL4fv1A5qOQ==", - "license": "BSD-2-Clause-Patent", - "dependencies": { - "@bcts/dcbor": "^1.0.0-beta.6" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@bcts/uniform-resources": { - "version": "1.0.0-beta.6", - "resolved": "https://registry.npmjs.org/@bcts/uniform-resources/-/uniform-resources-1.0.0-beta.6.tgz", - "integrity": "sha512-bord9vidOdp94OoAqfOxwU/wOp9ozpSBEmw9gXOnQ0OMXEUWoyZ4jjp0AAL5cLkk8RIX7Kslq9dJWe6tXt0R+A==", - "license": "BSD-2-Clause-Patent", - "dependencies": { - "@bcts/crypto": "^1.0.0-beta.6", - "@bcts/dcbor": "^1.0.0-beta.6" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@bcts/xid": { - "version": "1.0.0-beta.6", - "resolved": "https://registry.npmjs.org/@bcts/xid/-/xid-1.0.0-beta.6.tgz", - "integrity": "sha512-EY+ngaBDGJqMjRkPiU6mo3mv/UEnH3FoBhP1lDQbvxc1V0ccDwZh5B9a2J7ey/j/CYqQOPzpZQ8koqkvuc72kQ==", - "license": "BSD-2-Clause-Patent", - "dependencies": { - "@bcts/components": "^1.0.0-beta.6", - "@bcts/dcbor": "^1.0.0-beta.6", - "@bcts/envelope": "^1.0.0-beta.6", - "@bcts/known-values": "^1.0.0-beta.6", - "@bcts/provenance-mark": "^1.0.0-beta.6", - "@bcts/uniform-resources": "^1.0.0-beta.6" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@blockchaincommons/dcbor": { - "version": "1.0.0-beta.1", - "resolved": "https://registry.npmjs.org/@blockchaincommons/dcbor/-/dcbor-1.0.0-beta.1.tgz", - "integrity": "sha512-VJrG/3KTYtSP0UJel1MA3HpatTpsgtbre/W9ejfjepAaNCJchJgv6Efv1UDPwLdS1MhJtXd2bM3GNUSK79dhdw==", - "hasInstallScript": true, - "license": "BSD-2-Clause-Patent", - "engines": { - "node": ">=22.12" - } - }, - "node_modules/@noble/ciphers": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-2.4.0.tgz", - "integrity": "sha512-AnjFn0Jv92laAkvMrghlFZq4qQCIN/4DxFV/eooqtC2YTjB7kBeLMS2T9KJX4Dn+ZVXLOwK0lSgqDtx9gvxtiw==", - "license": "MIT", - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/curves": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.4.0.tgz", - "integrity": "sha512-P4/62zrgfH33CneE3Dn4WhJVA22YUU0eR51wKIan4NVRvwsA0YnPTwWGpNbpuacSujmSFLvyzpyuR30+fbq2Ew==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "2.4.0" - }, - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/hashes": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.4.0.tgz", - "integrity": "sha512-X5XaVWZIBCT7HHZGm5I7ZQXDwLG+bGXuSrMQAW+7Zvl87h1kmc1ZB1VSRJcpUfoUrGQp4Fkoxm5kZ+Ms+aW+eA==", - "license": "MIT", - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/post-quantum": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/@noble/post-quantum/-/post-quantum-0.6.1.tgz", - "integrity": "sha512-+pormrDZwjRw05U8ADK4JpHejo87+gBd+muRBB/ozztH5yhDLMDF4jHQWN3NQQAsu1zBNPWTG0ZwVI0CR29H0A==", - "license": "MIT", - "dependencies": { - "@noble/ciphers": "~2.2.0", - "@noble/curves": "~2.2.0", - "@noble/hashes": "~2.2.0" - }, - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/post-quantum/node_modules/@noble/ciphers": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-2.2.0.tgz", - "integrity": "sha512-Z6pjIZ/8IJcCGzb2S/0Px5J81yij85xASuk1teLNeg75bfT07MV3a/O2Mtn1I2se43k3lkVEcFaR10N4cgQcZA==", - "license": "MIT", - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/post-quantum/node_modules/@noble/curves": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.2.0.tgz", - "integrity": "sha512-T/BoHgFXirb0ENSPBquzX0rcjXeM6Lo892a2jlYJkqk83LqZx0l1Of7DzlKJ6jkpvMrkHSnAcgb5JegL8SeIkQ==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "2.2.0" - }, - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/post-quantum/node_modules/@noble/hashes": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.2.0.tgz", - "integrity": "sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg==", - "license": "MIT", - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/base": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-2.4.0.tgz", - "integrity": "sha512-thZ1TuJwFwBblOhgsjDKvvGirBxNp+wSvY/DR6tJBJOTDhdAAcHJ8Vbr2eFnqaxeca4+t0i9KBf+uHYGWwZORg==", - "license": "MIT", - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/sr25519": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@scure/sr25519/-/sr25519-2.4.0.tgz", - "integrity": "sha512-Xzpy/MuVqR8wNHrXrz6HHLqCI8nPirQmJEhOMabZ8jSrM6bQiDg+1xkUgw4+Kr7857u3xxQL/PfKFeav9rodZg==", - "license": "MIT", - "dependencies": { - "@noble/curves": "2.4.0", - "@noble/hashes": "2.4.0" - }, - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/pako": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/pako/-/pako-3.0.1.tgz", - "integrity": "sha512-GupotUUI0mlhugKjUs4bjOwLt3nrehy9Ys2dxC0GtgVef5cnKggkDMmf2bq2poCCuVXopWPmqsc9VDT2iJUy+w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/puzrin" - }, - { - "type": "github", - "url": "https://github.com/sponsors/nodeca" - } - ], - "license": "(MIT AND Zlib)" - } - } -} diff --git a/tests/baseline/package.json b/tests/baseline/package.json deleted file mode 100644 index 4bc6c50..0000000 --- a/tests/baseline/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "xid-baseline-closure", - "private": true, - "description": "The published @bcts packages the frozen baseline bundle is built from (one copy of each).", - "dependencies": { - "@bcts/xid": "1.0.0-beta.6" - } -} diff --git a/tests/baseline/xid-baseline.d.mts b/tests/baseline/xid-baseline.d.mts index 19a77d7..5e5eed0 100644 --- a/tests/baseline/xid-baseline.d.mts +++ b/tests/baseline/xid-baseline.d.mts @@ -1,454 +1,407 @@ -import { EncapsulationPublicKey, KeyDerivationMethod, PrivateKeyBase, PrivateKeys, PublicKeys, Reference, Salt, Signature, Signer, SigningPrivateKey, SigningPublicKey, URI, Verifier, XID, XID as XID$1 } from "@blockchaincommons/components"; import { KnownValue } from "@blockchaincommons/known-values"; -import { Attachments, Attachments as Attachments$1, Digest, Edgeable, Edgeable as Edgeable$1, Edges, Edges as Edges$1, Envelope, EnvelopeEncodable, EnvelopeEncodableValue } from "@blockchaincommons/envelope"; -import { ProvenanceMark, ProvenanceMarkGenerator, ProvenanceMarkResolution } from "@blockchaincommons/provenance-mark"; -import { Cbor } from "@blockchaincommons/dcbor-compat"; -import { UR } from "@blockchaincommons/uniform-resources"; +import { Envelope, EnvelopeInput, ToEnvelope } from "@blockchaincommons/envelope"; +import { Cbor, CborCodec, CborTagged, Tag, ToCbor } from "@blockchaincommons/dcbor"; +import { Digest, EncapsulationPublicKey, PrivateKeyBase, PrivateKeys, PublicKeys, Reference, Salt, Signature, Signer, SigningPublicKey, URI, Verifier, XID } from "@blockchaincommons/components"; +import { ProvenanceMark, ProvenanceMarkGenerator, ProvenanceMarkResolution, ProvenanceSeed } from "@blockchaincommons/provenance-mark"; +import { KeyDerivationMethod } from "@blockchaincommons/components/kdf"; +import { Attachments } from "@blockchaincommons/envelope/attachment"; +import { Edgeable, Edges } from "@blockchaincommons/envelope/edge"; +import { ToUR, UR } from "@blockchaincommons/uniform-resources"; +import { RngOptions } from "@blockchaincommons/rand"; //#region src/error.d.ts /** * Copyright © 2023-2026 Blockchain Commons, LLC * - * - * XID Error Types - * - * Error types returned when operating on XID Documents. - * Ported from bc-xid-rust/src/error.rs + * The one error this package throws: a `code` naming what went wrong (the + * reference's variant names) and `details` typed by that code. */ -declare enum XIDErrorCode { - DUPLICATE = "DUPLICATE", - NOT_FOUND = "NOT_FOUND", - STILL_REFERENCED = "STILL_REFERENCED", - EMPTY_VALUE = "EMPTY_VALUE", - UNKNOWN_PRIVILEGE = "UNKNOWN_PRIVILEGE", - INVALID_XID = "INVALID_XID", - MISSING_INCEPTION_KEY = "MISSING_INCEPTION_KEY", - INVALID_RESOLUTION_METHOD = "INVALID_RESOLUTION_METHOD", - MULTIPLE_PROVENANCE_MARKS = "MULTIPLE_PROVENANCE_MARKS", - UNEXPECTED_PREDICATE = "UNEXPECTED_PREDICATE", - UNEXPECTED_NESTED_ASSERTIONS = "UNEXPECTED_NESTED_ASSERTIONS", - NO_PERMISSIONS = "NO_PERMISSIONS", - NO_REFERENCES = "NO_REFERENCES", - UNKNOWN_KEY_REFERENCE = "UNKNOWN_KEY_REFERENCE", - UNKNOWN_DELEGATE_REFERENCE = "UNKNOWN_DELEGATE_REFERENCE", - KEY_NOT_FOUND_IN_DOCUMENT = "KEY_NOT_FOUND_IN_DOCUMENT", - DELEGATE_NOT_FOUND_IN_DOCUMENT = "DELEGATE_NOT_FOUND_IN_DOCUMENT", - INVALID_PASSWORD = "INVALID_PASSWORD", - ENVELOPE_NOT_SIGNED = "ENVELOPE_NOT_SIGNED", - SIGNATURE_VERIFICATION_FAILED = "SIGNATURE_VERIFICATION_FAILED", - NO_PROVENANCE_MARK = "NO_PROVENANCE_MARK", - GENERATOR_CONFLICT = "GENERATOR_CONFLICT", - NO_GENERATOR = "NO_GENERATOR", - CHAIN_ID_MISMATCH = "CHAIN_ID_MISMATCH", - SEQUENCE_MISMATCH = "SEQUENCE_MISMATCH", - ENVELOPE_PARSING = "ENVELOPE_PARSING", - COMPONENT = "COMPONENT", - CBOR = "CBOR", - PROVENANCE_MARK = "PROVENANCE_MARK" -} -declare class XIDError extends Error { - readonly code: XIDErrorCode; - readonly cause?: Error; - constructor(code: XIDErrorCode, message: string, cause?: Error); - /** - * Returned when attempting to add a duplicate item. - */ - static duplicate(item: string): XIDError; - /** - * Returned when an item is not found. - */ - static notFound(item: string): XIDError; - /** - * Returned when an item is still referenced by other items. - */ - static stillReferenced(item: string): XIDError; - /** - * Returned when a value is invalid or empty. - */ - static emptyValue(field: string): XIDError; - /** - * Returned when an unknown privilege is encountered. - */ - static unknownPrivilege(): XIDError; - /** - * Returned when the XID is invalid. - */ - static invalidXid(): XIDError; - /** - * Returned when the inception key is missing. - */ - static missingInceptionKey(): XIDError; - /** - * Returned when the resolution method is invalid. - */ - static invalidResolutionMethod(): XIDError; - /** - * Returned when multiple provenance marks are found. - */ - static multipleProvenanceMarks(): XIDError; - /** - * Returned when an unexpected predicate is encountered. - */ - static unexpectedPredicate(predicate: string): XIDError; - /** - * Returned when unexpected nested assertions are found. - */ - static unexpectedNestedAssertions(): XIDError; - /** - * Returned when a service has no permissions. - */ - static noPermissions(uri: string): XIDError; - /** - * Returned when a service has no key or delegate references. - */ - static noReferences(uri: string): XIDError; - /** - * Returned when an unknown key reference is found in a service. - */ - static unknownKeyReference(reference: string, uri: string): XIDError; - /** - * Returned when an unknown delegate reference is found in a service. - */ - static unknownDelegateReference(reference: string, uri: string): XIDError; - /** - * Returned when a key is not found in the XID document. - */ - static keyNotFoundInDocument(key: string): XIDError; - /** - * Returned when a delegate is not found in the XID document. - */ - static delegateNotFoundInDocument(delegate: string): XIDError; - /** - * Returned when the password is invalid. - */ - static invalidPassword(): XIDError; - /** - * Returned when the envelope is not signed. - */ - static envelopeNotSigned(): XIDError; - /** - * Returned when signature verification fails. - */ - static signatureVerificationFailed(): XIDError; - /** - * Returned when there is no provenance mark to advance. - */ - static noProvenanceMark(): XIDError; - /** - * Returned when document already has generator but external generator was provided. - */ - static generatorConflict(): XIDError; - /** - * Returned when document does not have generator but needs one. - */ - static noGenerator(): XIDError; - /** - * Returned when generator chain ID doesn't match. - */ - static chainIdMismatch(expected: Uint8Array, actual: Uint8Array): XIDError; - /** - * Returned when generator sequence doesn't match. - */ - static sequenceMismatch(expected: number, actual: number): XIDError; - /** - * Envelope parsing error wrapper. - */ - static envelopeParsing(cause?: Error): XIDError; - /** - * Component error wrapper. - */ - static component(cause?: Error): XIDError; - /** - * CBOR error wrapper. - */ - static cbor(cause?: Error): XIDError; - /** - * Provenance mark error wrapper. - */ - static provenanceMark(cause?: Error): XIDError; +/** Every code an `XIDError` can carry: the reference's `Error` variant names. */ +type XIDErrorCode = "Duplicate" | "NotFound" | "StillReferenced" | "EmptyValue" | "UnknownPrivilege" | "InvalidXid" | "MissingInceptionKey" | "InvalidResolutionMethod" | "MultipleProvenanceMarks" | "UnexpectedPredicate" | "UnexpectedNestedAssertions" | "NoPermissions" | "NoReferences" | "UnknownKeyReference" | "UnknownDelegateReference" | "KeyNotFoundInDocument" | "DelegateNotFoundInDocument" | "InvalidPassword" | "EnvelopeNotSigned" | "SignatureVerificationFailed" | "NoProvenanceMark" | "GeneratorConflict" | "NoGenerator" | "ChainIdMismatch" | "SequenceMismatch" | "EnvelopeParsing" | "Component" | "Cbor" | "ProvenanceMark"; +/** Every code, for exhaustive tables and tests. */ +export declare const XID_ERROR_CODES: readonly XIDErrorCode[]; +/** The fields each code carries besides `code`. */ +interface XIDErrorDetailsByCode { + /** An item of this kind is already there. */ + Duplicate: { + /** The item's kind: `"key"`, `"delegate"`, `"service"`, `"nickname"`, … */ + readonly item: string; + }; + /** No item of this kind is there. */ + NotFound: { + /** The item's kind. */ + readonly item: string; + }; + /** A service still names the item. */ + StillReferenced: { + /** The item's kind. */ + readonly item: string; + }; + /** The field must not be empty. */ + EmptyValue: { + /** The field's name. */ + readonly item: string; + }; + /** A known value that names no privilege. */ + UnknownPrivilege: unknown; + /** The inception key does not produce the document's XID. */ + InvalidXid: unknown; + /** The document has no inception key, or it has no private keys. */ + MissingInceptionKey: unknown; + /** A `'dereferenceVia'` object that is not a URI. */ + InvalidResolutionMethod: unknown; + /** More than one `'provenance'` assertion. */ + MultipleProvenanceMarks: unknown; + /** A service assertion with a predicate the parser does not take. */ + UnexpectedPredicate: { + /** The predicate's known value, as decimal text. */ + readonly predicate: string; + }; + /** A service assertion whose object has assertions. */ + UnexpectedNestedAssertions: unknown; + /** The service allows nothing. */ + NoPermissions: { + /** The service's URI. */ + readonly uri: string; + }; + /** The service names no key and no delegate. */ + NoReferences: { + /** The service's URI. */ + readonly uri: string; + }; + /** The service names a key the document lacks. */ + UnknownKeyReference: { + /** The reference, rendered `Reference()`. */ + readonly reference: string; + /** The service's URI. */ + readonly uri: string; + }; + /** The service names a delegate the document lacks. */ + UnknownDelegateReference: { + /** The reference, rendered `Reference()`. */ + readonly reference: string; + /** The service's URI. */ + readonly uri: string; + }; + /** `expectKey` found no such key. */ + KeyNotFoundInDocument: { + /** The key's public keys, rendered. */ + readonly key: string; + }; + /** `expectDelegate` found no such delegate. */ + DelegateNotFoundInDocument: { + /** The delegate's XID, rendered. */ + readonly delegate: string; + }; + /** A locked key or generator did not open. */ + InvalidPassword: unknown; + /** Verification was asked of an unsigned envelope. */ + EnvelopeNotSigned: unknown; + /** The inception key did not sign the envelope. */ + SignatureVerificationFailed: unknown; + /** The document has no mark to advance. */ + NoProvenanceMark: unknown; + /** A generator was given to a document that holds one. */ + GeneratorConflict: unknown; + /** The document holds no generator and none was given. */ + NoGenerator: unknown; + /** The generator continues another chain. */ + ChainIdMismatch: { + /** The mark's chain id. */ + readonly expected: Uint8Array; + /** The generator's chain id. */ + readonly actual: Uint8Array; + }; + /** The generator's next sequence number is not the mark's plus one. */ + SequenceMismatch: { + /** The sequence number the mark demands. */ + readonly expected: number; + /** The generator's next sequence number. */ + readonly actual: number; + }; + /** An envelope error inside a decoder; the error itself is `cause`. */ + EnvelopeParsing: { + /** The envelope error's message. */ + readonly message: string; + }; + /** A components error; the error itself is `cause`. */ + Component: { + /** The components error's message. */ + readonly message: string; + }; + /** A dcbor error inside a decoder; the error itself is `cause`. */ + Cbor: { + /** The dcbor error's message. */ + readonly message: string; + }; + /** A provenance-mark error; the error itself is `cause`. */ + ProvenanceMark: { + /** The provenance-mark error's message. */ + readonly message: string; + }; } +/** `details` of one code: `code` and that code's fields. */ +type XIDErrorDetailsFor = C extends XIDErrorCode ? { + /** The discriminant. */ + readonly code: C; +} & XIDErrorDetailsByCode[C] : never; +/** `details` is discriminated by `code`. */ +type XIDErrorDetails = XIDErrorDetailsFor; /** - * Result type for XID operations. + * An `XIDError` whose `code` and `details` are narrowed to one code (or, + * with the default argument, the union over every code), so `error.code + * === "Duplicate"` narrows `error.details.item` to a string. */ -type XIDResult = T; -//#endregion -//#region src/privilege.d.ts +type XIDErrorTyped = C extends XIDErrorCode ? XIDError & { + /** The condition. */ + readonly code: C; + /** The condition's fields. */ + readonly details: XIDErrorDetailsFor; +} : never; +/** `details` of the four item codes. */ +type ItemDetails = XIDErrorDetailsFor<"Duplicate" | "NotFound" | "StillReferenced" | "EmptyValue">; +/** `details` of the codes with nothing more to say. */ +type PlainDetails = XIDErrorDetailsFor<"UnknownPrivilege" | "InvalidXid" | "MissingInceptionKey" | "InvalidResolutionMethod" | "MultipleProvenanceMarks" | "UnexpectedNestedAssertions" | "InvalidPassword" | "EnvelopeNotSigned" | "SignatureVerificationFailed" | "NoProvenanceMark" | "GeneratorConflict" | "NoGenerator">; +/** `details` of `UnexpectedPredicate`. */ +type UnexpectedPredicateDetails = XIDErrorDetailsFor<"UnexpectedPredicate">; +/** `details` of a service that is incomplete. */ +type ServiceDetails = XIDErrorDetailsFor<"NoPermissions" | "NoReferences">; +/** `details` of a service reference that names nothing in the document. */ +type UnknownReferenceDetails = XIDErrorDetailsFor<"UnknownKeyReference" | "UnknownDelegateReference">; +/** `details` of `KeyNotFoundInDocument`. */ +type KeyNotFoundDetails = XIDErrorDetailsFor<"KeyNotFoundInDocument">; +/** `details` of `DelegateNotFoundInDocument`. */ +type DelegateNotFoundDetails = XIDErrorDetailsFor<"DelegateNotFoundInDocument">; +/** `details` of `ChainIdMismatch`. */ +type ChainIdMismatchDetails = XIDErrorDetailsFor<"ChainIdMismatch">; +/** `details` of `SequenceMismatch`. */ +type SequenceMismatchDetails = XIDErrorDetailsFor<"SequenceMismatch">; +/** `details` of a wrapped failure from envelope, components, dcbor or provenance-mark. */ +type WrappedDetails = XIDErrorDetailsFor<"EnvelopeParsing" | "Component" | "Cbor" | "ProvenanceMark">; /** - * Enum representing XID privileges. + * The error every operation of this package throws. `code` names the + * condition (one of `XIDErrorCode`, the reference's variant names), + * `details` is discriminated by it, and `cause` carries the sibling + * error when a decoder wrapped one. + * + * ```ts + * try { + * doc.addKey(key); + * } catch (e) { + * if (XIDError.isXIDError(e) && e.is("Duplicate")) console.log(e.details.item); + * } + * ``` */ -declare enum Privilege { - /** Allow all applicable XID operations */ - All = "All", - /** Authenticate as the subject (e.g., log into services) */ - Auth = "Auth", - /** Sign digital communications as the subject */ - Sign = "Sign", - /** Encrypt messages from the subject */ - Encrypt = "Encrypt", - /** Elide data under the subject's control */ - Elide = "Elide", - /** Issue or revoke verifiable credentials on the subject's authority */ - Issue = "Issue", - /** Access resources under the subject's control */ - Access = "Access", - /** Delegate privileges to third parties */ - Delegate = "Delegate", - /** Verify (update) the XID document */ - Verify = "Verify", - /** Update service endpoints */ - Update = "Update", - /** Remove the inception key from the XID document */ - Transfer = "Transfer", - /** Add or remove other verifiers (rotate keys) */ - Elect = "Elect", - /** Transition to a new provenance mark chain */ - Burn = "Burn", - /** Revoke the XID entirely */ - Revoke = "Revoke" +export declare class XIDError extends Error { + /** Always `"XIDError"`. */ + override readonly name = "XIDError"; + /** The condition, one of `XIDErrorCode`. */ + readonly code: XIDErrorCode; + /** The fields of the condition, discriminated by `code`. */ + readonly details: XIDErrorDetails; + private constructor(); + private static make; + /** Whether `value` is an `XIDError`: an instance of this class. */ + static isXIDError(value: unknown): value is XIDError; + /** Whether this error's code is `code`, narrowing `details`. */ + is(code: C): this is XIDErrorTyped; + private static plain; + /** `Duplicate`: an item of this kind is already there. */ + static duplicate(item: string): XIDErrorTyped<"Duplicate">; + /** `NotFound`: no item of this kind is there. */ + static notFound(item: string): XIDErrorTyped<"NotFound">; + /** `StillReferenced`: a service still names the item. */ + static stillReferenced(item: string): XIDErrorTyped<"StillReferenced">; + /** `EmptyValue`: the field must not be empty. */ + static emptyValue(field: string): XIDErrorTyped<"EmptyValue">; + /** `UnknownPrivilege`: a known value that names no privilege. */ + static unknownPrivilege(): XIDErrorTyped<"UnknownPrivilege">; + /** `InvalidXid`: the inception key does not produce the document's XID. */ + static invalidXid(): XIDErrorTyped<"InvalidXid">; + /** `MissingInceptionKey`: the document has no inception key, or it has no private keys. */ + static missingInceptionKey(): XIDErrorTyped<"MissingInceptionKey">; + /** `InvalidResolutionMethod`: a `'dereferenceVia'` object that is not a URI. */ + static invalidResolutionMethod(): XIDErrorTyped<"InvalidResolutionMethod">; + /** `MultipleProvenanceMarks`: more than one `'provenance'` assertion. */ + static multipleProvenanceMarks(): XIDErrorTyped<"MultipleProvenanceMarks">; + /** `UnexpectedPredicate`: a service assertion with a predicate the parser does not take. */ + static unexpectedPredicate(predicate: string): XIDErrorTyped<"UnexpectedPredicate">; + /** `UnexpectedNestedAssertions`: a service assertion whose object has assertions. */ + static unexpectedNestedAssertions(): XIDErrorTyped<"UnexpectedNestedAssertions">; + /** `NoPermissions`: the service allows nothing. */ + static noPermissions(uri: string): XIDErrorTyped<"NoPermissions">; + /** `NoReferences`: the service names no key and no delegate. */ + static noReferences(uri: string): XIDErrorTyped<"NoReferences">; + /** `UnknownKeyReference`: the service names a key the document lacks. */ + static unknownKeyReference(reference: string, uri: string): XIDErrorTyped<"UnknownKeyReference">; + /** `UnknownDelegateReference`: the service names a delegate the document lacks. */ + static unknownDelegateReference(reference: string, uri: string): XIDErrorTyped<"UnknownDelegateReference">; + /** `KeyNotFoundInDocument`: `expectKey` found no such key. */ + static keyNotFoundInDocument(key: string): XIDErrorTyped<"KeyNotFoundInDocument">; + /** `DelegateNotFoundInDocument`: `expectDelegate` found no such delegate. */ + static delegateNotFoundInDocument(delegate: string): XIDErrorTyped<"DelegateNotFoundInDocument">; + /** `InvalidPassword`: a locked key or generator did not open. */ + static invalidPassword(): XIDErrorTyped<"InvalidPassword">; + /** `EnvelopeNotSigned`: verification was asked of an unsigned envelope. */ + static envelopeNotSigned(): XIDErrorTyped<"EnvelopeNotSigned">; + /** `SignatureVerificationFailed`: the inception key did not sign the envelope. */ + static signatureVerificationFailed(): XIDErrorTyped<"SignatureVerificationFailed">; + /** `NoProvenanceMark`: the document has no mark to advance. */ + static noProvenanceMark(): XIDErrorTyped<"NoProvenanceMark">; + /** `GeneratorConflict`: a generator was given to a document that holds one. */ + static generatorConflict(): XIDErrorTyped<"GeneratorConflict">; + /** `NoGenerator`: the document holds no generator and none was given. */ + static noGenerator(): XIDErrorTyped<"NoGenerator">; + /** `ChainIdMismatch`: the generator continues another chain. */ + static chainIdMismatch(expected: Uint8Array, actual: Uint8Array): XIDErrorTyped<"ChainIdMismatch">; + /** `SequenceMismatch`: the generator's next sequence number is not the mark's plus one. */ + static sequenceMismatch(expected: number, actual: number): XIDErrorTyped<"SequenceMismatch">; + /** + * `EnvelopeParsing`: an envelope error inside a decoder. The message is + * the reference's `envelope parsing error`; the envelope error is + * `cause` and its message is `details.message`. + */ + static envelopeParsing(cause: unknown): XIDErrorTyped<"EnvelopeParsing">; + /** `Component`: a components error; the message is the reference's `component error`. */ + static component(cause: unknown): XIDErrorTyped<"Component">; + /** `Cbor`: a dcbor error inside a decoder; the message is the reference's `CBOR error`. */ + static cbor(cause: unknown): XIDErrorTyped<"Cbor">; + /** + * `Cbor` from a CBOR or UR decoder entry point (`fromCbor`, + * `fromUntaggedCbor`, `fromUR`), where the reference returns the dcbor + * error itself: the message is the dcbor error's. + */ + static cborDecode(cause: Error): XIDErrorTyped<"Cbor">; + /** `ProvenanceMark`: a provenance-mark error; the message is the reference's `provenance mark error`. */ + static provenanceMark(cause: unknown): XIDErrorTyped<"ProvenanceMark">; } +//#endregion +//#region src/privilege.d.ts /** - * Convert a Privilege to its corresponding KnownValue. - */ -declare function privilegeToKnownValue(privilege: Privilege): KnownValue; -/** - * Convert a KnownValue to its corresponding Privilege. - */ -declare function privilegeFromKnownValue(knownValue: KnownValue): Privilege; -/** - * Convert a Privilege to an Envelope. + * `All` grants every privilege; the operational ones (`Auth`, `Sign`, + * `Encrypt`, `Elide`, `Issue`, `Access`) and the management ones + * (`Delegate`, `Verify`, `Update`, `Transfer`, `Elect`, `Burn`, `Revoke`) + * name one capability each. */ -declare function privilegeToEnvelope(privilege: Privilege): Envelope; +type Privilege = "All" | "Auth" | "Sign" | "Encrypt" | "Elide" | "Issue" | "Access" | "Delegate" | "Verify" | "Update" | "Transfer" | "Elect" | "Burn" | "Revoke"; +/** Every privilege, in the reference's order. */ +export declare const PRIVILEGES: readonly Privilege[]; +/** Whether `value` is one of the privilege names. */ +export declare function isPrivilege(value: unknown): value is Privilege; +/** The known value the privilege is encoded as; `UnknownPrivilege` for a name that is not one. */ +export declare function privilegeKnownValue(privilege: Privilege): KnownValue; +/** The privilege a known value names; `UnknownPrivilege` for any other value. */ +export declare function privilegeFromKnownValue(knownValue: KnownValue): Privilege; +/** The privilege as a known-value envelope. */ +export declare function privilegeEnvelope(privilege: Privilege): Envelope; /** - * Convert an Envelope to a Privilege. + * The privilege a known-value envelope names: `EnvelopeParsing` when the + * subject is not a known value, `UnknownPrivilege` when it names no + * privilege. */ -declare function privilegeFromEnvelope(envelope: Envelope): Privilege; +export declare function privilegeFromEnvelope(envelope: Envelope): Privilege; //#endregion //#region src/permissions.d.ts -/** - * Interface for types that have permissions. - */ +/** What `Permissions.from` takes. */ +interface PermissionsInput { + /** The privileges allowed. */ + allow?: Iterable | undefined; + /** The privileges denied. */ + deny?: Iterable | undefined; +} +/** Something that carries permissions: a key, a delegate, a service. */ interface HasPermissions { - /** - * Get the permissions for this object. - */ - permissions(): Permissions; - /** - * Get a mutable reference to the permissions. - */ - permissionsMut(): Permissions; + /** The permissions (live). */ + readonly permissions: Permissions; + /** Allows `privilege`. */ + allow(privilege: Privilege): void; + /** Denies `privilege`. */ + deny(privilege: Privilege): void; } -/** - * Helper methods for HasPermissions implementers. - */ -declare const HasPermissionsMixin: { - /** - * Get the set of allowed privileges. - */ - allow(obj: HasPermissions): Set; - /** - * Get the set of denied privileges. - */ - deny(obj: HasPermissions): Set; - /** - * Add an allowed privilege. - */ - addAllow(obj: HasPermissions, privilege: Privilege): void; - /** - * Add a denied privilege. - */ - addDeny(obj: HasPermissions, privilege: Privilege): void; - /** - * Remove an allowed privilege. - */ - removeAllow(obj: HasPermissions, privilege: Privilege): void; - /** - * Remove a denied privilege. - */ - removeDeny(obj: HasPermissions, privilege: Privilege): void; - /** - * Clear all permissions. - */ - clearAllPermissions(obj: HasPermissions): void; -}; -/** - * Represents the permissions granted to a key or delegate. - */ -declare class Permissions implements HasPermissions { - allow: Set; - deny: Set; - constructor(allow?: Set, deny?: Set); - /** - * Create a new empty Permissions object. - */ - static new(): Permissions; - /** - * Create a new Permissions object that allows all privileges. - */ - static newAllowAll(): Permissions; - /** - * Add permissions assertions to an envelope. - */ - addToEnvelope(envelope: Envelope): Envelope; - /** - * Try to extract Permissions from an envelope. - */ - static tryFromEnvelope(envelope: Envelope): Permissions; - /** - * Add an allowed privilege. - */ +/** An allow set and a deny set of privileges. */ +export declare class Permissions { + private readonly _allow; + private readonly _deny; + private constructor(); + /** Empty sets unless given. */ + static from({ allow, deny }?: PermissionsInput): Permissions; + /** `All` allowed, nothing denied. */ + static allowAll(): Permissions; + /** The allowed privileges (a copy). */ + get allow(): ReadonlySet; + /** The denied privileges (a copy). */ + get deny(): ReadonlySet; + /** Allows `privilege`. */ addAllow(privilege: Privilege): void; - /** - * Add a denied privilege. - */ + /** Denies `privilege`. */ addDeny(privilege: Privilege): void; + /** Stops allowing `privilege`. */ + removeAllow(privilege: Privilege): void; + /** Stops denying `privilege`. */ + removeDeny(privilege: Privilege): void; + /** Empties both sets. */ + clear(): void; /** - * Check if a specific privilege is allowed. + * Allowed (directly or through `All`) and not denied (directly or + * through `All`): a denial wins over an allowance. This is the + * package's own rule; the reference exposes the sets only. */ isAllowed(privilege: Privilege): boolean; - /** - * Check if a specific privilege is denied. - */ + /** Denied directly or through `All`. */ isDenied(privilege: Privilege): boolean; - permissions(): Permissions; - permissionsMut(): Permissions; + /** Adds an `'allow'` assertion per allowed privilege, then a `'deny'` per denied one. */ + addToEnvelope(envelope: Envelope): Envelope; /** - * Check equality with another Permissions object. + * The `'allow'` and `'deny'` assertions of an envelope. An object that + * is not a known value is `EnvelopeParsing`; one that names no + * privilege is `UnknownPrivilege`. */ + static fromEnvelope(envelope: Envelope): Permissions; + /** Same allow and deny sets. */ equals(other: Permissions): boolean; - /** - * Clone this Permissions object. - */ + /** A copy. */ clone(): Permissions; } //#endregion -//#region src/name.d.ts +//#region src/key.d.ts /** - * Interface for types that have a nickname. + * How a key's private keys go into an envelope: left out, included (with + * a salt), elided (the digest of the included form), or locked with a + * password (Argon2id unless `method` says otherwise). */ -interface HasNickname { - /** - * Get the nickname for this object. - */ - nickname(): string; - /** - * Set the nickname for this object. - */ - setNickname(name: string): void; +type XIDPrivateKeyOptions = "omit" | "include" | "elide" | EncryptOptions; +/** The password-locked form of private keys or a generator. */ +interface EncryptOptions { + /** The password, as text or bytes. */ + encrypt: Uint8Array | string; + /** The key derivation method; Argon2id unless given. */ + method?: KeyDerivationMethod | undefined; } -/** - * Helper methods for HasNickname implementers. - */ -declare const HasNicknameMixin: { - /** - * Add a nickname, throwing if one already exists or is empty. - */ - addNickname(obj: HasNickname, name: string): void; -}; -//#endregion -//#region src/shared.d.ts -/** - * Copyright © 2023-2026 Blockchain Commons, LLC - * - * - * Shared Reference Wrapper - * - * Provides a wrapper for shared references to objects. - * In TypeScript, we don't have Arc/RwLock like Rust, but we can provide - * a simple wrapper that allows shared access to a value. - * - * Ported from bc-xid-rust/src/shared.rs - */ -/** - * A wrapper for shared references to objects. - * - * Unlike Rust's Arc>, JavaScript uses reference semantics for objects, - * so this is primarily a type-safe wrapper that makes the sharing explicit. - */ -declare class Shared { - private readonly value; - constructor(value: T); - /** - * Create a new Shared instance. - */ - static new(value: T): Shared; - /** - * Get a read-only reference to the value. - */ - read(): T; - /** - * Get a mutable reference to the value. - */ - write(): T; - /** - * Check equality with another Shared instance. - */ - equals(other: Shared): boolean; - /** - * Clone this Shared instance. - * Note: This creates a shallow copy in JS; for deep copy, implement on T. - */ - clone(): Shared; +/** What `Key.from` takes besides the public keys. */ +interface KeyInput { + /** With private keys the key is allowed `All` unless `permissions` says otherwise. */ + privateKeys?: PrivateKeys | undefined; + /** The nickname; none unless given. */ + nickname?: string | undefined; + /** The endpoints, as URIs or their text. */ + endpoints?: Iterable | undefined; + /** The permissions; empty unless given (or `All` with private keys). */ + permissions?: Permissions | undefined; } -//#endregion -//#region src/key.d.ts -/** - * Options for handling private keys in envelopes. - */ -declare enum XIDPrivateKeyOptions { - /** Omit the private key from the envelope (default). */ - Omit = "Omit", - /** Include the private key in plaintext (with salt for decorrelation). */ - Include = "Include", - /** Include the private key assertion but elide it (maintains digest tree). */ - Elide = "Elide", - /** Include the private key encrypted with a password. */ - Encrypt = "Encrypt" +/** A password for a locked key or generator, as text or bytes. */ +interface PasswordOptions { + /** The password; absent means "leave locked material locked". */ + password?: Uint8Array | string | undefined; } -/** - * Configuration for encrypting private keys. - */ -interface XIDPrivateKeyEncryptConfig { - type: XIDPrivateKeyOptions.Encrypt; - password: Uint8Array; - method?: KeyDerivationMethod; +/** What `Key.toEnvelope` takes. */ +interface KeyEnvelopeOptions { + /** How the private keys go into the envelope; `"omit"` unless given. */ + privateKeys?: XIDPrivateKeyOptions | undefined; } /** - * Union type for all private key options. - */ -type XIDPrivateKeyOptionsValue = XIDPrivateKeyOptions.Omit | XIDPrivateKeyOptions.Include | XIDPrivateKeyOptions.Elide | XIDPrivateKeyEncryptConfig; -/** - * Private key data that can be either decrypted or encrypted. + * A key of a XID document: public keys, optionally private keys (in the + * clear or password-locked), a nickname, endpoints and permissions. */ -type PrivateKeyData = { - type: "decrypted"; - privateKeys: PrivateKeys; -} | { - type: "encrypted"; - envelope: Envelope; -}; -/** - * Represents a key in an XID document. - * - * Mirrors `bc-xid-rust/src/key.rs`. The on-the-wire shape: - * - * ``` - * PublicKeys [ - * { - * 'privateKey': PrivateKeys ← (or encrypted/elided) - * } [ - * 'salt': Salt - * ] - * 'nickname': "..." - * 'endpoint': URI(...) - * 'allow': '...' - * ] - * ``` - * - * Notably the private-key assertion is itself a node — the `'salt'` - * lives nested under the assertion, not as a sibling on the parent - * envelope. This is what `add_salt_instance(salt)` produces in Rust and - * what `Envelope.prototype.addSaltInstance` produces in TS. - */ -declare class Key implements HasNickname, HasPermissions, EnvelopeEncodable, Verifier { +export declare class Key implements HasPermissions, Verifier { private readonly _publicKeys; private readonly _privateKeyData; private _nickname; @@ -456,516 +409,403 @@ declare class Key implements HasNickname, HasPermissions, EnvelopeEncodable, Ver private readonly _permissions; private constructor(); /** - * Create a new Key with only public keys. - */ - static new(publicKeys: PublicKeys): Key; - /** - * Create a new Key with public keys and allow-all permissions. - */ - static newAllowAll(publicKeys: PublicKeys): Key; - /** - * Create a new Key with private keys. - */ - static newWithPrivateKeys(privateKeys: PrivateKeys, publicKeys: PublicKeys): Key; - /** - * Create a new Key with private key base (derives keys from it). - */ - static newWithPrivateKeyBase(privateKeyBase: PrivateKeyBase): Key; - /** - * Get the public keys. - */ - publicKeys(): PublicKeys; - /** - * Get the private keys, if available and decrypted. - */ - privateKeys(): PrivateKeys | undefined; - /** - * Check if this key has decrypted private keys. - */ - hasPrivateKeys(): boolean; - /** - * Check if this key has encrypted private keys. - */ - hasEncryptedPrivateKeys(): boolean; - /** - * Get the salt used for private key decorrelation. - */ - privateKeySalt(): Salt | undefined; - /** - * Get the reference for this key (based on public keys tagged CBOR). - */ - reference(): Reference; - /** - * Get the signing public key. - */ - signingPublicKey(): SigningPublicKey; - /** - * Get the encapsulation public key. - */ + * A key from its public keys; no permissions unless private keys or + * `permissions` are given. A `null` `privateKeys` is a `TypeError`: + * absent private keys are `undefined`. + */ + static from(publicKeys: PublicKeys, { privateKeys, nickname, endpoints, permissions }?: KeyInput): Key; + /** A public key allowed `All`. */ + static allowAll(publicKeys: PublicKeys): Key; + /** The Schnorr and X25519 keys of a base, private keys included, allowed `All`. */ + static fromPrivateKeyBase(privateKeyBase: PrivateKeyBase): Key; + /** The public keys. */ + get publicKeys(): PublicKeys; + /** The private keys when held in the clear. */ + get privateKeys(): PrivateKeys | undefined; + /** Whether the private keys are held in the clear. */ + get hasPrivateKeys(): boolean; + /** Whether the private keys are held locked (parsed without the password). */ + get hasEncryptedPrivateKeys(): boolean; + /** The salt the `'privateKey'` assertion carries. */ + get privateKeySalt(): Salt | undefined; + /** The reference of the public keys. */ + get reference(): Reference; + /** The signing public key. */ + get signingPublicKey(): SigningPublicKey; + /** The encapsulation public key. */ encapsulationPublicKey(): EncapsulationPublicKey; - /** - * Verify a signature against a message. - */ + /** Whether `signature` is the public keys' signature of `message`. */ verify(signature: Signature, message: Uint8Array): boolean; - /** - * Get the endpoints set. The set holds typed `URI` values (mirrors - * Rust `HashSet`); use `.toString()` on a URI for a plain - * string view. - */ - endpoints(): Set; - /** - * Get the endpoints set for mutation. - */ - endpointsMut(): Set; - /** - * Add an endpoint. Accepts either a URI value or a string (for - * ergonomic test/REPL use). The URI is the canonical form. - */ + /** The endpoints (a copy). */ + get endpoints(): ReadonlySet; + /** Adds an endpoint, as a URI or its text (a components error for text that is not a URI). */ addEndpoint(endpoint: URI | string): void; - /** - * Add a permission. - */ - addPermission(privilege: Privilege): void; - nickname(): string; + /** The nickname; empty when there is none. */ + get nickname(): string; + /** Sets (or clears, with `""`) the nickname. */ setNickname(name: string): void; - permissions(): Permissions; - permissionsMut(): Permissions; - /** - * Build the nested salt-bearing assertion envelope: - * ``` - * { 'privateKey': PrivateKeys } [ 'salt': Salt ] - * ``` - * Mirrors Rust `Key::private_key_assertion_envelope()`. - */ + /** Sets the nickname once: `Duplicate` when set, `EmptyValue` when empty. */ + addNickname(name: string): void; + /** The permissions (live). */ + get permissions(): Permissions; + /** Allows `privilege`. */ + allow(privilege: Privilege): void; + /** Denies `privilege`. */ + deny(privilege: Privilege): void; private privateKeyAssertionEnvelope; /** - * Convert to envelope with specified options. + * The public keys as the subject, the private keys per `privateKeys` + * (a locked key stays locked), then `'nickname'`, `'endpoint'`s and + * the permissions. An unknown option is a `TypeError`. */ - intoEnvelopeOpt(privateKeyOptions?: XIDPrivateKeyOptionsValue): Envelope; - intoEnvelope(): Envelope; + toEnvelope({ privateKeys }?: KeyEnvelopeOptions): Envelope; /** - * Try to extract a Key from an envelope, optionally with password for decryption. - * - * Mirrors Rust `Key::try_from_envelope` exactly: - * - Subject must be a tagged-CBOR PublicKeys leaf. - * - Optional private-key assertion follows the - * `{predicate: object} [ 'salt': Salt ]` shape. - * - Endpoints are tagged URIs, not bare text. - * - Missing salt under a present private-key assertion is an error. + * A key from its envelope. A locked `'privateKey'` is unlocked with the + * password when one is given and it fits; otherwise it is kept locked. + * Every failure is an `XIDError`: a subject or leaf of the wrong type + * is `Cbor`; a missing or repeated `'salt'`, a second `'nickname'` or + * one that is not text are `EnvelopeParsing`; a permission that is not + * a known value is `EnvelopeParsing`, one that names no privilege is + * `UnknownPrivilege`. */ - static tryFromEnvelope(envelope: Envelope, password?: Uint8Array): Key; + static fromEnvelope(envelope: Envelope, { password }?: PasswordOptions): Key; + private static privateKeyDataOf; /** - * Get the private key envelope, optionally decrypting it. - * - * Mirrors Rust `Key::private_key_envelope(password: Option<&[u8]>)`. - * Password is bytes; the legacy `string` form is accepted as a - * convenience for callers that have not yet migrated. + * The private keys as an envelope: in the clear when held so, unlocked + * with the password when locked (an `InvalidPassword` error when it + * does not fit), or the locked envelope itself without a password. */ - privateKeyEnvelope(password?: Uint8Array | string): Envelope | undefined; + privateKeyEnvelope({ password }?: PasswordOptions): Envelope | undefined; /** - * Check equality with another Key. + * Same public keys, private material (in the clear or locked, with its + * salt), nickname, endpoints and permissions — as the reference's + * equality; a key parsed from an envelope that omitted its private + * keys is not equal to the original. */ equals(other: Key): boolean; - /** - * Get a hash key for use in Sets/Maps. - */ - hashKey(): string; - /** - * Clone this Key. - */ + /** A copy: the private material shared, the endpoints and permissions copied. */ clone(): Key; } //#endregion //#region src/service.d.ts +/** What `Service.from` takes besides the URI. */ +interface ServiceInput { + /** The capability (`addCapability`). */ + capability?: string | undefined; + /** The name (`setName`). */ + name?: string | undefined; + /** The keys the service is reached through, by reference. */ + keyReferences?: Iterable | undefined; + /** The delegates the service is reached through, by reference. */ + delegateReferences?: Iterable | undefined; + /** The permissions; empty unless given. */ + permissions?: Permissions | undefined; +} /** - * Represents a service endpoint in an XID document. + * A service of a XID document: a URI, key and delegate references, a + * capability, a name and permissions. On the wire only `'allow'` + * permissions round-trip: the parser rejects `'deny'` as the reference's + * does. */ -declare class Service implements HasPermissions, EnvelopeEncodable { +export declare class Service implements HasPermissions { private readonly _uri; - private _keyReferences; - private _delegateReferences; - private _permissions; + private readonly _keyReferences; + private readonly _delegateReferences; + private readonly _permissions; private _capability; private _name; - constructor(uri: URI | string); - /** - * Create a new Service with the given URI. - */ - static new(uri: URI | string): Service; - /** - * Get the service URI as a typed value. - */ - uri(): URI; - /** - * Get the service URI as a plain string. - */ - uriString(): string; - /** - * Get the capability string. - */ - capability(): string; + private constructor(); /** - * Set the capability string. + * A service at a URI (a components error for text that is not a URI); + * references and permissions can be added later. */ + static from(uri: URI | string, { capability, name, keyReferences, delegateReferences, permissions }?: ServiceInput): Service; + /** The URI. */ + get uri(): URI; + /** The capability; empty when there is none. */ + get capability(): string; + /** Sets (or clears, with `""`) the capability. */ setCapability(capability: string): void; - /** - * Add a capability, throwing if one already exists or is empty. - */ + /** Sets the capability once; `Duplicate` when set, `EmptyValue` when empty. */ addCapability(capability: string): void; - /** - * Get the key references as a Set of typed Reference values. - */ - keyReferences(): Set; - /** - * Get the underlying key-references Map for direct mutation. - */ - keyReferencesMut(): Map; - /** - * Add a key reference by hex string (back-compat alias). - */ - addKeyReferenceHex(keyReferenceHex: string): void; - /** - * Add a key reference. - */ + /** The key references (a copy). */ + get keyReferences(): ReadonlySet; + /** Whether the service references this key. */ + hasKeyReference(reference: Reference): boolean; + /** Adds a key reference; `Duplicate` when it is already there. */ addKeyReference(keyReference: Reference): void; - /** - * Get the delegate references as a Set of typed Reference values. - */ - delegateReferences(): Set; - /** - * Get the underlying delegate-references Map for direct mutation. - */ - delegateReferencesMut(): Map; - /** - * Add a delegate reference by hex string (back-compat alias). - */ - addDelegateReferenceHex(delegateReferenceHex: string): void; - /** - * Add a delegate reference. - */ - addDelegateReference(delegateReference: Reference): void; - /** - * Add a key by its public keys provider (convenience method). - * Matches Rust's `add_key(&mut self, key: &dyn PublicKeysProvider)`. - */ - addKey(keyProvider: { - publicKeys(): PublicKeys; + /** Adds a key reference given as 64 hex characters (a components error otherwise). */ + addKeyReferenceHex(keyReferenceHex: string): void; + /** References the key's public keys. */ + addKey(key: { + readonly publicKeys: PublicKeys; }): void; - /** - * Add a delegate by its XID provider (convenience method). - * - * Mirrors Rust's `add_delegate(&mut self, delegate: &dyn XIDProvider)`, - * which delegates to `xid.reference()` — i.e. the XID's 32 bytes used - * directly as the Reference. The earlier port hashed the bytes with - * SHA-256, producing a different reference that didn't round-trip - * across implementations. - */ - addDelegate(xidProvider: { - xid(): XID$1; + /** The delegate references (a copy). */ + get delegateReferences(): ReadonlySet; + /** Whether the service references this delegate. */ + hasDelegateReference(reference: Reference): boolean; + /** Adds a delegate reference; `Duplicate` when it is already there. */ + addDelegateReference(delegateReference: Reference): void; + /** Adds a delegate reference given as 64 hex characters (a components error otherwise). */ + addDelegateReferenceHex(delegateReferenceHex: string): void; + /** References the delegate's (or document's) XID. */ + addDelegate(delegate: { + readonly xid: XID; }): void; - /** - * Get the name. - */ - name(): string; - /** - * Set the name, throwing if one already exists or is empty. - */ + /** The name; empty when there is none. */ + get name(): string; + /** Sets the name once; `Duplicate` when set, `EmptyValue` when empty. */ setName(name: string): void; - permissions(): Permissions; - permissionsMut(): Permissions; - /** - * Convert to envelope. - */ - intoEnvelope(): Envelope; - /** - * Try to extract a Service from an envelope. - * - * Mirrors Rust `Service::try_from`: - * - Subject must be a tagged-CBOR URI leaf. - * - Each `'key'`/`'delegate'` object is a tagged Reference leaf. - * - Nested assertions on any object are rejected. - * - Unknown predicates are rejected. - */ - static tryFromEnvelope(envelope: Envelope): Service; - /** - * Check equality with another Service (based on URI). - */ + /** The permissions (live). */ + get permissions(): Permissions; + /** Allows `privilege`. */ + allow(privilege: Privilege): void; + /** Denies `privilege` (written to the wire, but not read back: see the class). */ + deny(privilege: Privilege): void; + /** The URI as the subject; `'key'`, `'delegate'`, `'capability'`, `'name'` and the permissions. */ + toEnvelope(): Envelope; + /** + * A service from its envelope. Rejects nested assertions + * (`UnexpectedNestedAssertions`) and any predicate but `'key'`, + * `'delegate'`, `'capability'`, `'name'` and `'allow'` + * (`UnexpectedPredicate`; a predicate that is not a known value is + * `EnvelopeParsing`); a subject or object of the wrong type is `Cbor`. + */ + static fromEnvelope(envelope: Envelope): Service; + /** Same URI, references, permissions, capability and name — as the reference's equality. */ equals(other: Service): boolean; - /** - * Get a hash key for use in Sets/Maps. - */ - hashKey(): string; - /** - * Clone this Service. - */ + /** A copy. */ clone(): Service; } //#endregion //#region src/delegate.d.ts -/** - * Forward declaration interface for XIDDocument to avoid circular dependency. - * The actual XIDDocument class implements this interface. - */ -interface XIDDocumentType { - xid(): XID$1; - intoEnvelope(): Envelope; - clone(): XIDDocumentType; +/** What a delegate needs of its controller: `XIDDocument`, without importing it. */ +interface XIDDocumentLike { + /** The controller's XID. */ + readonly xid: XID; + /** The controller's envelope (private keys and generator omitted, unsigned). */ + toEnvelope(): Envelope; + /** Whether the controller equals `other`. */ + equals(other: XIDDocumentLike): boolean; + /** A deep copy of the controller. */ + clone(): XIDDocumentLike; } -/** - * Register the XIDDocument class to avoid circular dependency issues. - * Called by xid-document.ts when it loads. - */ -declare function registerXIDDocumentClass(cls: { - tryFromEnvelope(envelope: Envelope): XIDDocumentType; -}): void; -/** - * Represents a delegate in an XID document. - */ -declare class Delegate implements HasPermissions, EnvelopeEncodable { +/** Parses a controller document from its envelope: `XIDDocument.fromEnvelope`. */ +type ParseXIDDocument = (envelope: Envelope) => XIDDocumentLike; +/** What `Delegate.from` takes besides the controller. */ +interface DelegateInput { + /** The permissions granted; none unless given. */ + permissions?: Permissions | undefined; +} +/** What `Delegate.fromEnvelope` takes besides the envelope. */ +interface DelegateParseOptions { + /** The parser of the controller's envelope; `XIDDocument.fromEnvelope` unless given. */ + parseDocument?: ParseXIDDocument | undefined; +} +/** A delegate: a controller document and the permissions this document grants it. */ +export declare class Delegate implements HasPermissions { private readonly _controller; private readonly _permissions; private constructor(); - /** - * Create a new Delegate with the given controller document. - */ - static new(controller: XIDDocumentType): Delegate; - /** - * Get the controller document. - */ - controller(): Shared; - /** - * Get the XID of the controller. - */ - xid(): XID$1; - /** - * Get the reference for this delegate. - * - * Mirrors Rust `impl ReferenceProvider for Delegate`, which delegates - * to `self.controller.read().xid().reference()` — i.e. the XID's - * 32 bytes used directly as the Reference. The previous TS port - * SHA-256-hashed the XID bytes, producing a different reference - * value that did not round-trip across implementations. - */ - reference(): Reference; - permissions(): Permissions; - permissionsMut(): Permissions; - /** - * Convert to envelope. - */ - intoEnvelope(): Envelope; - /** - * Try to extract a Delegate from an envelope. - */ - static tryFromEnvelope(envelope: Envelope): Delegate; - /** - * Check equality with another Delegate (based on controller XID). - */ + /** A delegate controlled by `controller`, with no permissions unless given. */ + static from(controller: XIDDocumentLike, { permissions }?: DelegateInput): Delegate; + /** The controlling document (live: mutating it mutates the delegate). */ + get controller(): XIDDocumentLike; + /** The controller's XID. */ + get xid(): XID; + /** The reference of the controller's XID. */ + get reference(): Reference; + /** The permissions granted (live). */ + get permissions(): Permissions; + /** Allows `privilege`. */ + allow(privilege: Privilege): void; + /** Denies `privilege`. */ + deny(privilege: Privilege): void; + /** The controller's envelope, wrapped, with the permissions. */ + toEnvelope(): Envelope; + /** + * A delegate from its envelope: the permissions, then the unwrapped + * controller parsed by `parseDocument` (`XIDDocument.fromEnvelope` + * unless given). A sibling failure is `EnvelopeParsing`. + */ + static fromEnvelope(envelope: Envelope, { parseDocument }?: DelegateParseOptions): Delegate; + /** Same controller document and permissions — as the reference's equality. */ equals(other: Delegate): boolean; - /** - * Get a hash key for use in Sets/Maps. - */ - hashKey(): string; - /** - * Clone this Delegate. - */ + /** A deep copy. */ clone(): Delegate; } //#endregion //#region src/provenance.d.ts -/** - * Options for handling generators in envelopes. - */ -declare enum XIDGeneratorOptions { - /** Omit the generator from the envelope (default). */ - Omit = "Omit", - /** Include the generator in plaintext (with salt for decorrelation). */ - Include = "Include", - /** Include the generator assertion but elide it (maintains digest tree). */ - Elide = "Elide", - /** Include the generator encrypted with a password. */ - Encrypt = "Encrypt" +/** How the generator goes into an envelope; the same four forms as private keys. */ +type XIDGeneratorOptions = "omit" | "include" | "elide" | EncryptOptions; +/** What `Provenance.from` takes besides the mark. */ +interface ProvenanceInput { + /** The generator that produced the mark, when the document should keep it. */ + generator?: ProvenanceMarkGenerator | undefined; } -/** - * Configuration for encrypting generators. - */ -interface XIDGeneratorEncryptConfig { - type: XIDGeneratorOptions.Encrypt; - password: Uint8Array; - method?: KeyDerivationMethod; +/** What `Provenance.toEnvelope` takes. */ +interface ProvenanceEnvelopeOptions { + /** How the generator goes into the envelope; `"omit"` unless given. */ + generator?: XIDGeneratorOptions | undefined; } -/** - * Union type for all generator options. - */ -type XIDGeneratorOptionsValue = XIDGeneratorOptions.Omit | XIDGeneratorOptions.Include | XIDGeneratorOptions.Elide | XIDGeneratorEncryptConfig; -/** - * Generator data that can be either decrypted or encrypted. - */ -type GeneratorData = { - type: "decrypted"; - generator: ProvenanceMarkGenerator; -} | { - type: "encrypted"; - envelope: Envelope; -}; -/** - * Represents provenance information in an XID document. - */ -declare class Provenance implements EnvelopeEncodable { +/** A provenance mark and, optionally, the generator that continues its chain. */ +export declare class Provenance { private _mark; private _generator; private constructor(); - /** - * Create a new Provenance with just a mark. - */ - static new(mark: ProvenanceMark): Provenance; - /** - * Create a new Provenance with a generator and mark. - */ - static newWithGenerator(generator: ProvenanceMarkGenerator, mark: ProvenanceMark): Provenance; - /** - * Get the provenance mark. - */ - mark(): ProvenanceMark; - /** - * Get the generator, if available and decrypted. - */ - generator(): ProvenanceMarkGenerator | undefined; - /** - * Check if this provenance has a decrypted generator. - */ - hasGenerator(): boolean; - /** - * Check if this provenance has an encrypted generator. - */ - hasEncryptedGenerator(): boolean; - /** - * Get the salt used for generator decorrelation. - */ - generatorSalt(): Salt | undefined; - /** - * Update the provenance mark. - */ + /** A mark, with the generator that produced it when the document should keep it. */ + static from(mark: ProvenanceMark, { generator }?: ProvenanceInput): Provenance; + /** The current mark. */ + get mark(): ProvenanceMark; + /** The generator when held in the clear. */ + get generator(): ProvenanceMarkGenerator | undefined; + /** Whether the generator is held in the clear. */ + get hasGenerator(): boolean; + /** Whether the generator is held locked (parsed without the password). */ + get hasEncryptedGenerator(): boolean; + /** The salt the `'provenanceGenerator'` assertion carries. */ + get generatorSalt(): Salt | undefined; + /** Replaces the mark (no chain check, as the reference's `set_mark`). */ setMark(mark: ProvenanceMark): void; - /** - * Set or replace the generator. - */ + /** Sets or replaces the generator, with a fresh salt. */ setGenerator(generator: ProvenanceMarkGenerator): void; + /** Removes the generator, returning whether one was held. */ + takeGenerator(): boolean; /** - * Take and remove the generator. - */ - takeGenerator(): { - data: GeneratorData; - salt: Salt; - } | undefined; - /** - * Get a mutable reference to the generator, decrypting if necessary. - */ - generatorMut(password?: Uint8Array): ProvenanceMarkGenerator | undefined; - /** - * Build the salted assertion envelope: - * ``` - * { 'provenanceGenerator': } [ 'salt': Salt ] - * ``` - * Mirrors Rust `Provenance::generator_assertion_envelope()`. + * The generator, unlocking a locked one with the password (it stays + * unlocked); `InvalidPassword` when it is locked and the password is + * missing or wrong; `undefined` when there is no generator. */ + unlockGenerator({ password }?: PasswordOptions): ProvenanceMarkGenerator | undefined; + /** A generator from its envelope; a provenance-mark failure is `ProvenanceMark`. */ + private static generatorOf; private generatorAssertionEnvelope; /** - * Get the generator envelope, optionally decrypting it. - * - * Mirrors Rust `Provenance::generator_envelope(password)`. The - * unencrypted variant returns the same structured envelope produced - * by `ProvenanceMarkGenerator::into_envelope()` — never the legacy - * JSON-bytes form. - */ - generatorEnvelope(password?: Uint8Array | string): Envelope | undefined; - /** - * Convert to envelope with specified options. + * The generator as an envelope: in the clear when held so, unlocked + * with the password when locked (`InvalidPassword` when it does not + * fit), or the locked envelope itself without a password. */ - intoEnvelopeOpt(generatorOptions?: XIDGeneratorOptionsValue): Envelope; - intoEnvelope(): Envelope; + generatorEnvelope({ password }?: PasswordOptions): Envelope | undefined; /** - * Try to extract a Provenance from an envelope, optionally with password for decryption. - * - * Mirrors Rust `Provenance::try_from_envelope`: - * - Subject is a tagged-CBOR ProvenanceMark leaf. - * - The optional generator assertion follows the - * `{ predicate: object } [ 'salt': Salt ]` shape. - * - Missing salt under a present generator assertion is an error. + * The mark as the subject; the generator per `generator` (a locked one + * stays locked). An unknown option is a `TypeError`. */ - static tryFromEnvelope(envelope: Envelope, password?: Uint8Array): Provenance; + toEnvelope({ generator }?: ProvenanceEnvelopeOptions): Envelope; /** - * Check equality with another Provenance. + * A provenance from its envelope. A locked generator is unlocked with + * the password when one is given and it fits; otherwise it is kept + * locked. A subject that is not a mark is `Cbor`; a missing or repeated + * `'salt'` is `EnvelopeParsing`; a generator envelope that is not a + * generator's is `ProvenanceMark`. */ + static fromEnvelope(envelope: Envelope, { password }?: PasswordOptions): Provenance; + private static generatorDataOf; + /** Same mark and generator (in the clear or locked, with its salt) — as the reference's equality. */ equals(other: Provenance): boolean; - /** - * Clone this Provenance. - * Note: ProvenanceMark is immutable so we can use the same instance. - */ + /** A copy: the generator material shared. */ clone(): Provenance; } //#endregion //#region src/xid-document.d.ts /** - * Options for creating the inception key. + * The inception key of a new document: public keys only, a private key + * base (Schnorr keys, private keys held), or a public/private pair. */ -type XIDInceptionKeyOptions = { - type: "default"; -} | { - type: "publicKeys"; +type XIDInceptionKey = PublicKeys | PrivateKeyBase | XIDInceptionKeyPair; +/** An inception key given as a public/private pair. */ +interface XIDInceptionKeyPair { + /** The public keys. */ publicKeys: PublicKeys; -} | { - type: "privateKeyBase"; - privateKeyBase: PrivateKeyBase; -} | { - type: "privateKeys"; + /** The private keys (not checked against the public keys, as the reference does not). */ privateKeys: PrivateKeys; - publicKeys: PublicKeys; -}; -/** - * Options for creating the genesis mark. - */ -type XIDGenesisMarkOptions = { - type: "none"; -} | { - type: "passphrase"; - passphrase: string; - resolution?: ProvenanceMarkResolution; - date?: Date; - info?: Cbor; -} | { - type: "seed"; - seed: Uint8Array; - resolution?: ProvenanceMarkResolution; - date?: Date; - info?: Cbor; -}; -/** - * Options for signing an envelope. - */ -type XIDSigningOptions = { - type: "none"; -} | { - type: "inception"; -} | { - type: "privateKeys"; - privateKeys: PrivateKeys; -} | { - type: "signingPrivateKey"; - signingPrivateKey: SigningPrivateKey; -}; +} /** - * Options for verifying the signature on an envelope when loading. + * The genesis provenance mark of a new document: exactly one of a + * passphrase or a 32-byte seed (a `ProvenanceSeed` or its bytes), the + * resolution (`"high"` unless given), the date (now unless given) and + * the mark's info. */ -declare enum XIDVerifySignature { - /** Do not verify the signature (default). */ - None = "None", - /** Verify that the envelope is signed with the inception key. */ - Inception = "Inception" +interface XIDGenesis { + /** The passphrase the chain's seed derives from. */ + passphrase?: string | undefined; + /** The chain's seed: a `ProvenanceSeed` or exactly 32 bytes. */ + seed?: Uint8Array | ProvenanceSeed | undefined; + /** The chain's resolution; `"high"` unless given. */ + resolution?: ProvenanceMarkResolution | undefined; + /** The genesis mark's date; now unless given. */ + date?: Date | undefined; + /** The genesis mark's info. */ + info?: Cbor | undefined; +} +/** What `XIDDocument.from` takes. */ +interface XIDDocumentInput { + /** The inception key, whose signing key the XID derives from. */ + inceptionKey: XIDInceptionKey; + /** A genesis mark to start the provenance chain with. */ + genesis?: XIDGenesis | undefined; +} +/** What `XIDDocument.random` takes. */ +interface XIDRandomOptions extends RngOptions { + /** A genesis mark to start the provenance chain with. */ + genesis?: XIDGenesis | undefined; +} +/** Who signs the document's envelope: nobody, the inception key, or a given signer. */ +type XIDSigning = "none" | "inception" | Signer; +/** Which signature `fromEnvelope` demands. */ +type XIDVerifySignature = "none" | "inception"; +/** What `XIDDocument.toEnvelope` takes. */ +interface XIDEnvelopeOptions { + /** How each key's private keys go into the envelope; `"omit"` unless given. */ + privateKeys?: XIDPrivateKeyOptions | undefined; + /** How the provenance generator goes into the envelope; `"omit"` unless given. */ + generator?: XIDGeneratorOptions | undefined; + /** Who signs; `"none"` unless given. */ + sign?: XIDSigning | undefined; +} +/** What `XIDDocument.fromEnvelope` takes. */ +interface XIDParseOptions extends PasswordOptions { + /** Which signature to demand; `"none"` unless given. */ + verify?: XIDVerifySignature | undefined; +} +/** What `XIDDocument.toSignedEnvelope` takes besides the signer. */ +interface SignedEnvelopeOptions { + /** How each key's private keys go into the envelope; `"omit"` unless given. */ + privateKeys?: XIDPrivateKeyOptions | undefined; +} +/** What `XIDDocument.addAttachment` takes. */ +interface AttachmentInput { + /** The payload, as anything an envelope is made from. */ + payload: EnvelopeInput; + /** The vendor, a reverse domain name. */ + vendor: string; + /** The URI of the format the payload conforms to. */ + conformsTo?: string | undefined; +} +/** What `nextProvenanceMark` takes. */ +interface NextProvenanceMarkOptions extends PasswordOptions { + /** The new mark's date; now unless given. */ + date?: Date | undefined; + /** The new mark's info. */ + info?: Cbor | undefined; + /** + * A generator kept outside the document; refused when the document + * holds one. When given, `password` is not used. + */ + generator?: ProvenanceMarkGenerator | undefined; +} +/** The document's CBOR codec, with the tag it carries. */ +interface XIDDocumentCodec extends CborCodec { + /** The `xid` tag (40024). */ + readonly tags: readonly Tag[]; } /** - * Represents an XID document. + * A XID document: the keys, delegates, services, resolution methods, + * provenance, attachments and edges published under an extensible + * identifier. The document is mutable; its `keys`, `delegates` and + * `services` are copied-out arrays of live values, and `attachments` and + * `edges()` are the document's own containers. */ -declare class XIDDocument implements EnvelopeEncodable, Edgeable$1 { +export declare class XIDDocument implements ToEnvelope, ToCbor, CborTagged, ToUR, Edgeable { private readonly _xid; private readonly _resolutionMethods; private readonly _keys; @@ -977,352 +817,221 @@ declare class XIDDocument implements EnvelopeEncodable, Edgeable$1 { private _extraAssertions; private constructor(); /** - * Create a new XIDDocument with the given options. - */ - static new(keyOptions?: XIDInceptionKeyOptions, markOptions?: XIDGenesisMarkOptions): XIDDocument; - private static inceptionKeyForOptions; - private static genesisMarkWithOptions; - /** - * Create an XIDDocument from just an XID. - */ - static fromXid(xid: XID$1): XIDDocument; - /** - * Get the XID. - */ - xid(): XID$1; - /** - * Get the resolution methods as a Set of typed URI values. - * - * Mirrors Rust `&HashSet`. Use `.toString()` on a URI for the - * plain-string form. - */ - resolutionMethods(): Set; - /** - * Add a resolution method. Accepts either a typed URI value or a - * string (the latter is converted via `URI.from`). - */ + * A document whose XID derives from the inception key's signing key; + * the key is added allowed `All`. A genesis mark starts the provenance + * chain and keeps the generator in the document. A missing inception + * key or a malformed genesis is a `TypeError`; a seed of the wrong + * length is `ProvenanceMark`. + */ + static from({ inceptionKey, genesis }: XIDDocumentInput): XIDDocument; + /** A document with a random private key base as its inception key. */ + static random({ rng, genesis }?: XIDRandomOptions): XIDDocument; + /** An empty document: just the XID. */ + static fromXid(xid: XID): XIDDocument; + private static keyFor; + private static genesisFor; + /** A `ProvenanceSeed` from bytes; the wrong length is `ProvenanceMark`. */ + private static seedOf; + /** The XID. */ + get xid(): XID; + /** The XID's reference. */ + get reference(): Reference; + /** No keys, delegates, services, resolution methods, provenance, attachments, edges or extra assertions. */ + get isEmpty(): boolean; + /** Assertions the parser did not recognise, kept as they were (a copy). */ + get extraAssertions(): readonly Envelope[]; + /** The resolution methods (a copy). */ + get resolutionMethods(): ReadonlySet; + /** Adds a resolution method, as a URI or its text (a components error for text that is not a URI). */ addResolutionMethod(method: URI | string): void; - /** - * Remove a resolution method. - */ + /** Removes a resolution method; whether it was there. */ removeResolutionMethod(method: URI | string): boolean; - /** - * Get all keys. - */ - keys(): Key[]; - /** - * Add a key. - */ + /** The keys (a copied-out array of live keys). */ + get keys(): readonly Key[]; + /** Adds a key; `Duplicate` when the public keys are already there. */ addKey(key: Key): void; + /** The key with these public keys. */ + key(publicKeys: PublicKeys): Key | undefined; + /** The key with this reference. */ + keyByReference(reference: Reference): Key | undefined; /** - * Find a key by its public keys. - */ - findKeyByPublicKeys(publicKeys: PublicKeys): Key | undefined; - /** - * Find a key by its reference. - */ - findKeyByReference(reference: Reference): Key | undefined; - /** - * Take and remove a key. + * Removes and returns the key; `StillReferenced` when a service names + * it, `NotFound` when it is not there. */ + removeKey(publicKeys: PublicKeys): Key; + /** Removes and returns the key without checking services; `undefined` when absent. */ takeKey(publicKeys: PublicKeys): Key | undefined; - /** - * Remove a key. - */ - removeKey(publicKeys: PublicKeys): void; - /** - * Check if the given signing public key is the inception signing key. - * Matches Rust: `is_inception_signing_key(&self, signing_public_key: &SigningPublicKey) -> bool` - */ + /** The key with these public keys; `KeyNotFoundInDocument` unless it is there. */ + expectKey(publicKeys: PublicKeys): Key; + /** Whether the XID derives from this signing key. */ isInceptionSigningKey(signingPublicKey: SigningPublicKey): boolean; - /** - * Get the inception key, if it exists in the document. - */ - inceptionKey(): Key | undefined; - /** - * Get the inception private keys, if available. - */ - inceptionPrivateKeys(): PrivateKeys | undefined; - /** - * Get the encryption key (encapsulation public key) for this document. - * - * Prefers the inception key for encryption. If no inception key is available, - * falls back to the first key in the document. - */ - encryptionKey(): EncapsulationPublicKey | undefined; - /** - * Remove the inception key from the document. - */ + /** The key whose signing key the XID derives from. */ + get inceptionKey(): Key | undefined; + /** The inception key's private keys, when held in the clear. */ + get inceptionPrivateKeys(): PrivateKeys | undefined; + /** The inception key's signing key. */ + get inceptionSigningKey(): SigningPublicKey | undefined; + /** The inception key's signing key, else the first key's. */ + get verificationKey(): SigningPublicKey | undefined; + /** The inception key's encapsulation key, else the first key's. */ + get encryptionKey(): EncapsulationPublicKey | undefined; + /** Removes and returns the inception key, if there is one. */ removeInceptionKey(): Key | undefined; - /** - * Set the name (nickname) for a key identified by its public keys. - */ + /** Sets the key's nickname; `NotFound` unless the key is there. */ setNameForKey(publicKeys: PublicKeys, name: string): void; - /** - * Get the inception signing public key, if it exists. - */ - inceptionSigningKey(): SigningPublicKey | undefined; - /** - * Get the verification (signing) key for this document. - * Prefers the inception key. Falls back to the first key. - */ - verificationKey(): SigningPublicKey | undefined; - /** - * Extract inception private keys from an envelope (convenience static method). - */ - static extractInceptionPrivateKeysFromEnvelope(envelope: Envelope, password: Uint8Array): PrivateKeys | undefined; - /** - * Get the private key envelope for a specific key, optionally decrypting it. - */ - privateKeyEnvelopeForKey(publicKeys: PublicKeys, password?: string): Envelope | undefined; - /** - * Check that the document contains a key with the given public keys. - * Throws if not found. - */ - checkContainsKey(publicKeys: PublicKeys): void; - /** - * Check that the document contains a delegate with the given XID. - * Throws if not found. - */ - checkContainsDelegate(xid: XID$1): void; - /** - * Get the attachments container. - */ - getAttachments(): Attachments$1; - /** - * Add an attachment with the specified payload and metadata. - */ - addAttachment(payload: EnvelopeEncodableValue, vendor: string, conformsTo?: string): void; - /** - * Check if the document has any attachments. - */ - hasAttachments(): boolean; - /** - * Remove all attachments. - */ - clearAttachments(): void; - /** - * Get an attachment by its digest. - */ - getAttachment(digest: Digest): Envelope | undefined; - /** - * Remove an attachment by its digest. - */ + /** The private keys of a key as an envelope (see `Key.privateKeyEnvelope`). */ + privateKeyEnvelopeForKey(publicKeys: PublicKeys, options?: PasswordOptions): Envelope | undefined; + /** The inception key's private keys of a parsed envelope, unlocked with the password. */ + static inceptionPrivateKeysFromEnvelope(envelope: Envelope, { password }?: PasswordOptions): PrivateKeys | undefined; + /** The delegates (a copied-out array of live delegates). */ + get delegates(): readonly Delegate[]; + /** Adds a delegate; `Duplicate` when a delegate with that XID is already there. */ + addDelegate(delegate: Delegate): void; + /** The delegate with this XID. */ + delegate(xid: XID): Delegate | undefined; + /** The delegate whose XID has this reference. */ + delegateByReference(reference: Reference): Delegate | undefined; + /** Removes and returns the delegate; `StillReferenced` when a service names it, `NotFound` when absent. */ + removeDelegate(xid: XID): Delegate; + /** Removes and returns the delegate without checking services; `undefined` when absent. */ + takeDelegate(xid: XID): Delegate | undefined; + /** The delegate with this XID; `DelegateNotFoundInDocument` unless it is there. */ + expectDelegate(xid: XID): Delegate; + /** The services (a copied-out array of live services). */ + get services(): readonly Service[]; + /** The service at this URI. */ + service(uri: URI | string): Service | undefined; + /** Adds a service; `Duplicate` when a service at that URI is already there. */ + addService(service: Service): void; + /** Removes and returns the service; `undefined` when absent. */ + takeService(uri: URI | string): Service | undefined; + /** Removes and returns the service; `NotFound` when absent. */ + removeService(uri: URI | string): Service; + /** Every service references known keys and delegates and allows something. */ + expectServicesConsistent(): void; + /** + * `NoReferences` without any key or delegate reference, + * `UnknownKeyReference`/`UnknownDelegateReference` for one the document + * lacks, `NoPermissions` without an allowed privilege. + */ + expectServiceConsistent(service: Service): void; + /** Whether any service references this key. */ + servicesReferenceKey(publicKeys: PublicKeys): boolean; + /** Whether any service references this delegate. */ + servicesReferenceDelegate(xid: XID): boolean; + /** The attachments: the document's own container. */ + get attachments(): Attachments; + /** Whether there are attachments. */ + get hasAttachments(): boolean; + /** Adds an attachment. */ + addAttachment({ payload, vendor, conformsTo }: AttachmentInput): void; + /** The attachment with this digest. */ + attachment(digest: Digest): Envelope | undefined; + /** Removes and returns the attachment with this digest. */ removeAttachment(digest: Digest): Envelope | undefined; - /** - * Get the edges container (read-only). - */ - edges(): Edges$1; - /** - * Get the edges container (mutable). - */ - edgesMut(): Edges$1; - /** - * Add an edge envelope. - */ + /** Removes every attachment. */ + clearAttachments(): void; + /** The edges: the document's own container (envelope's `Edgeable`). */ + edges(): Edges; + /** The same container as `edges()` (envelope's `Edgeable` names both). */ + edgesMut(): Edges; + /** Whether there are edges (envelope's `Edgeable`). */ + hasEdges(): boolean; + /** Adds an edge envelope. */ addEdge(edgeEnvelope: Envelope): void; - /** - * Get an edge by its digest. - */ + /** The edge with this digest. */ + edge(digest: Digest): Envelope | undefined; + /** `edge(digest)` under the name envelope's `Edgeable` uses. */ getEdge(digest: Digest): Envelope | undefined; - /** - * Remove an edge by its digest. - */ + /** Removes and returns the edge with this digest. */ removeEdge(digest: Digest): Envelope | undefined; - /** - * Remove all edges. - */ + /** Removes every edge. */ clearEdges(): void; - /** - * Check if the document has any edges. - */ - hasEdges(): boolean; - /** - * Check if the document is empty: no resolution methods, keys, delegates, - * services, provenance, attachments, edges, or extension assertions. - * - * Mirrors Rust `XIDDocument::is_empty`. - */ - isEmpty(): boolean; - /** - * Get the preserved extension assertions — top-level assertions that are - * not recognized as XID document fields and round-trip unchanged. - * - * Mirrors Rust `XIDDocument::extra_assertions(&self) -> &[Envelope]`. - */ - extraAssertions(): Envelope[]; - /** - * Get all delegates. - */ - delegates(): Delegate[]; - /** - * Add a delegate. - */ - addDelegate(delegate: Delegate): void; - /** - * Find a delegate by XID. - */ - findDelegateByXid(xid: XID$1): Delegate | undefined; - /** - * Find a delegate by reference. - */ - findDelegateByReference(reference: Reference): Delegate | undefined; - /** - * Take and remove a delegate. - */ - takeDelegate(xid: XID$1): Delegate | undefined; - /** - * Remove a delegate. - */ - removeDelegate(xid: XID$1): void; - /** - * Get all services. - */ - services(): Service[]; - /** - * Find a service by URI. - */ - findServiceByUri(uri: string): Service | undefined; - /** - * Add a service. - */ - addService(service: Service): void; - /** - * Take and remove a service. - */ - takeService(uri: string): Service | undefined; - /** - * Remove a service. - */ - removeService(uri: string): void; - /** - * Check service consistency. - */ - checkServicesConsistency(): void; - /** - * Check consistency of a single service. - */ - checkServiceConsistency(service: Service): void; - /** - * Check if any service references the given key. - */ - servicesReferenceKey(publicKeys: PublicKeys): boolean; - /** - * Check if any service references the given delegate. - * - * Mirrors Rust `services_reference_delegate(xid)` which uses - * `xid.reference()` — the XID bytes used directly as the - * Reference (no SHA-256 wrap), the same value used by - * `Service::add_delegate(...)` on the producer side. - */ - servicesReferenceDelegate(xid: XID$1): boolean; - /** - * Get the provenance mark. - */ - provenance(): ProvenanceMark | undefined; - /** - * Get the provenance generator. - */ - provenanceGenerator(): ProvenanceMarkGenerator | undefined; - /** - * Set the provenance. - */ + /** The current provenance mark. */ + get provenance(): ProvenanceMark | undefined; + /** The generator when the document holds it in the clear. */ + get provenanceGenerator(): ProvenanceMarkGenerator | undefined; + /** Sets (or clears) the mark, dropping any generator. */ setProvenance(provenance: ProvenanceMark | undefined): void; - /** - * Set provenance with generator. - */ + /** Sets the mark and the generator that continues its chain. */ setProvenanceWithGenerator(generator: ProvenanceMarkGenerator, mark: ProvenanceMark): void; /** - * Advance the provenance mark using the embedded generator. - */ - nextProvenanceMarkWithEmbeddedGenerator(password?: Uint8Array, date?: Date, info?: Cbor): void; - /** - * Advance the provenance mark using a provided generator. - */ - nextProvenanceMarkWithProvidedGenerator(generator: ProvenanceMarkGenerator, date?: Date, info?: Cbor): void; - /** - * Convert to envelope with options. - */ - toEnvelope(privateKeyOptions?: XIDPrivateKeyOptionsValue, generatorOptions?: XIDGeneratorOptionsValue, signingOptions?: XIDSigningOptions): Envelope; - intoEnvelope(): Envelope; - /** - * Returns the untagged CBOR encoding for this document. - * - * Mirrors Rust `CBORTaggedEncodable for XIDDocument::untagged_cbor`: - * empty docs serialize as the raw 32-byte XID byte string; non-empty - * docs serialize as the envelope's tagged CBOR (tag 200). - */ + * Advances the chain: with the document's own generator (unlocked with + * the password when locked), or with a provided one when the document + * has none. The generator must continue the current mark's chain at + * the next sequence number. `NoProvenanceMark` without a mark, + * `NoGenerator`/`GeneratorConflict` for the wrong choice, + * `ChainIdMismatch`/`SequenceMismatch` for a generator that does not + * continue the mark; an invalid date is a `TypeError`. + */ + nextProvenanceMark({ date, info, password, generator }?: NextProvenanceMarkOptions): void; + /** + * The XID as the subject; `'dereferenceVia'`, `'key'`, `'delegate'`, + * `'service'`, `'provenance'`, the extra assertions, attachments and + * edges; then signed per `sign` (`MissingInceptionKey` when the + * inception key or its private keys are missing). An unknown option + * is a `TypeError`. + */ + toEnvelope({ privateKeys, generator, sign: signing }?: XIDEnvelopeOptions): Envelope; + /** The `sign` option checked: one of the two names, or a signer. */ + private static signerOf; + /** `toEnvelope` signed by `signer`, the generator omitted. */ + toSignedEnvelope(signer: Signer, { privateKeys }?: SignedEnvelopeOptions): Envelope; + /** + * A document from its envelope. With `verify: "inception"` the envelope + * must be signed by the document's own inception key + * (`EnvelopeNotSigned`, `SignatureVerificationFailed`, `InvalidXid`); + * otherwise a wrapped (signed) subject is unwrapped and read as it is. + * The password unlocks locked private keys and generators. Every + * failure is an `XIDError`: a sibling error inside the parser is + * wrapped with the reference's code. An unknown `verify` is a + * `TypeError`. + */ + static fromEnvelope(envelope: Envelope, { password, verify }?: XIDParseOptions): XIDDocument; + private static parse; + /** An empty document is its XID's bytes; otherwise the envelope's tagged CBOR. */ untaggedCbor(): Cbor; - /** - * Returns the UR for this document. - * - * UR type is `xid` (matching `TAG_XID.name` and Rust). Body bytes are - * `untaggedCbor()`. - */ - ur(): UR; - /** - * Returns the `ur:xid/...` string representation of this document. - * - * Mirrors Rust `xid_document.ur_string()`. Round-trip with - * {@link XIDDocument.fromURString} is byte-identical to Rust. - */ - urString(): string; - /** - * Decode an XIDDocument from a UR. - * - * Mirrors Rust `CBORTaggedDecodable::from_untagged_cbor`: - * - if the body is a CBOR byte string (32 bytes), it's an empty - * XIDDocument carrying just the XID; - * - otherwise it's an envelope's tagged CBOR (tag 200), which we - * decode and feed through `fromEnvelope`. + /** Tag `xid` (40024) over `untaggedCbor`. */ + toCbor(): Cbor; + /** The tags this document's CBOR carries: `xid` (40024). */ + cborTags(): Tag[]; + /** The tagged-CBOR codec: `decode` is `fromCbor`, the tag required. */ + static get codec(): XIDDocumentCodec; + /** + * A document from its tagged CBOR: the `xid` tag (40024) over the + * untagged form. A missing or different tag, or a form the untagged + * decoder rejects, is `Cbor` with the dcbor error's message. + */ + static fromCbor(cborValue: Cbor): XIDDocument; + /** + * A document from its untagged CBOR: a 32-byte string is the XID of an + * empty document; anything else is a document envelope. A tagged value + * is rejected (the envelope tag is expected), as the reference's + * `from_untagged_cbor` rejects it. A rejection is `Cbor`: the dcbor + * error's message, or the document error's (`envelope parsing error`, + * …) when the envelope decodes but the document does not. + */ + static fromUntaggedCbor(cborValue: Cbor): XIDDocument; + /** `ur:xid/…` over `untaggedCbor`. */ + toUR(): UR; + /** + * A document from a `ur:xid/…` UR. A UR of another type is `Cbor` + * (`expected UR type xid, but found …`), as the reference's `from_ur` + * reports it. */ static fromUR(ur: UR): XIDDocument; /** - * Decode an XIDDocument from a `ur:xid/...` string. - */ - static fromURString(urString: string): XIDDocument; - /** - * Decode an XIDDocument from untagged CBOR (the UR-body form). - */ - static fromUntaggedCbor(cbor: Cbor): XIDDocument; - /** - * Extract an XIDDocument from an envelope. - */ - static fromEnvelope(envelope: Envelope, password?: Uint8Array, verifySignature?: XIDVerifySignature): XIDDocument; - private static fromEnvelopeInner; - /** - * Create a signed envelope. - */ - toSignedEnvelope(signingKey: Signer): Envelope; - /** - * Create a signed envelope with private key options. - */ - toSignedEnvelopeOpt(signingKey: Signer, privateKeyOptions?: XIDPrivateKeyOptionsValue): Envelope; - /** - * Get the reference for this document. - * - * Mirrors Rust `impl ReferenceProvider for XIDDocument` ↔ - * `XID::reference` which is `Reference::from_data(*self.data())` — - * the XID's bytes used directly. The previous TS implementation - * SHA-256-hashed the bytes, producing a different reference value. - */ - reference(): Reference; - /** - * Check equality with another XIDDocument. + * Same XID, resolution methods, keys (public and private material, + * nickname, endpoints, permissions), delegates, services, provenance + * (mark and generator), attachments, edges and extra assertions — as + * the reference's equality. */ equals(other: XIDDocument): boolean; - /** - * Clone this XIDDocument. - */ + /** A deep copy. */ clone(): XIDDocument; - /** - * Try to extract from envelope (alias for fromEnvelope with default options). - */ - static tryFromEnvelope(envelope: Envelope): XIDDocument; + /** `XIDDocument()`. */ + toString(): string; } //#endregion -//#region src/index.d.ts -declare const VERSION = "1.0.0-alpha.3"; -//#endregion -export { Attachments, Delegate, type Edgeable, Edges, type GeneratorData, type HasNickname, HasNicknameMixin, type HasPermissions, HasPermissionsMixin, Key, Permissions, type PrivateKeyData, Privilege, Provenance, Service, Shared, VERSION, XID, XIDDocument, type XIDDocumentType, XIDError, XIDErrorCode, type XIDGeneratorEncryptConfig, XIDGeneratorOptions, type XIDGeneratorOptionsValue, type XIDGenesisMarkOptions, type XIDInceptionKeyOptions, type XIDPrivateKeyEncryptConfig, XIDPrivateKeyOptions, type XIDPrivateKeyOptionsValue, type XIDResult, type XIDSigningOptions, XIDVerifySignature, privilegeFromEnvelope, privilegeFromKnownValue, privilegeToEnvelope, privilegeToKnownValue, registerXIDDocumentClass }; +export type { AttachmentInput, ChainIdMismatchDetails, DelegateInput, DelegateNotFoundDetails, DelegateParseOptions, EncryptOptions, HasPermissions, ItemDetails, KeyEnvelopeOptions, KeyInput, KeyNotFoundDetails, NextProvenanceMarkOptions, ParseXIDDocument, PasswordOptions, PermissionsInput, PlainDetails, Privilege, ProvenanceEnvelopeOptions, ProvenanceInput, SequenceMismatchDetails, ServiceDetails, ServiceInput, SignedEnvelopeOptions, UnexpectedPredicateDetails, UnknownReferenceDetails, WrappedDetails, XIDDocumentCodec, XIDDocumentInput, XIDDocumentLike, XIDEnvelopeOptions, XIDErrorCode, XIDErrorDetails, XIDErrorDetailsByCode, XIDErrorDetailsFor, XIDErrorTyped, XIDGeneratorOptions, XIDGenesis, XIDInceptionKey, XIDInceptionKeyPair, XIDParseOptions, XIDPrivateKeyOptions, XIDRandomOptions, XIDSigning, XIDVerifySignature }; //# sourceMappingURL=index.d.mts.map \ No newline at end of file diff --git a/tests/baseline/xid-baseline.mjs b/tests/baseline/xid-baseline.mjs index 89896e4..a6cc8c1 100644 --- a/tests/baseline/xid-baseline.mjs +++ b/tests/baseline/xid-baseline.mjs @@ -1,5 +1,268 @@ -//#region tests/baseline/node_modules/@blockchaincommons/dcbor/dist/error-BXLcx8Bl.mjs -const MajorType$1 = { +//#region tests/baseline/.src/src/error.ts +/** Every code, for exhaustive tables and tests. */ +const XID_ERROR_CODES = Object.freeze([ + "Duplicate", + "NotFound", + "StillReferenced", + "EmptyValue", + "UnknownPrivilege", + "InvalidXid", + "MissingInceptionKey", + "InvalidResolutionMethod", + "MultipleProvenanceMarks", + "UnexpectedPredicate", + "UnexpectedNestedAssertions", + "NoPermissions", + "NoReferences", + "UnknownKeyReference", + "UnknownDelegateReference", + "KeyNotFoundInDocument", + "DelegateNotFoundInDocument", + "InvalidPassword", + "EnvelopeNotSigned", + "SignatureVerificationFailed", + "NoProvenanceMark", + "GeneratorConflict", + "NoGenerator", + "ChainIdMismatch", + "SequenceMismatch", + "EnvelopeParsing", + "Component", + "Cbor", + "ProvenanceMark" +]); +const hex = (bytes) => Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join(""); +const messageOf$2 = (cause) => cause instanceof Error ? cause.message : typeof cause === "string" ? cause : ""; +/** +* The error every operation of this package throws. `code` names the +* condition (one of `XIDErrorCode`, the reference's variant names), +* `details` is discriminated by it, and `cause` carries the sibling +* error when a decoder wrapped one. +* +* ```ts +* try { +* doc.addKey(key); +* } catch (e) { +* if (XIDError.isXIDError(e) && e.is("Duplicate")) console.log(e.details.item); +* } +* ``` +*/ +var XIDError = class XIDError extends Error { + /** Always `"XIDError"`. */ + name = "XIDError"; + /** The condition, one of `XIDErrorCode`. */ + code; + /** The fields of the condition, discriminated by `code`. */ + details; + constructor(message, details, cause) { + super(message, cause === void 0 ? void 0 : { cause }); + this.code = details.code; + this.details = details; + } + static make(message, details, cause) { + return new XIDError(message, details, cause); + } + /** Whether `value` is an `XIDError`: an instance of this class. */ + static isXIDError(value) { + return value instanceof XIDError; + } + /** Whether this error's code is `code`, narrowing `details`. */ + is(code) { + return this.code === code; + } + static plain(code, message) { + return XIDError.make(message, { code }); + } + /** `Duplicate`: an item of this kind is already there. */ + static duplicate(item) { + return XIDError.make(`duplicate item: ${item}`, { + code: "Duplicate", + item + }); + } + /** `NotFound`: no item of this kind is there. */ + static notFound(item) { + return XIDError.make(`item not found: ${item}`, { + code: "NotFound", + item + }); + } + /** `StillReferenced`: a service still names the item. */ + static stillReferenced(item) { + return XIDError.make(`item is still referenced: ${item}`, { + code: "StillReferenced", + item + }); + } + /** `EmptyValue`: the field must not be empty. */ + static emptyValue(field) { + return XIDError.make(`invalid or empty value: ${field}`, { + code: "EmptyValue", + item: field + }); + } + /** `UnknownPrivilege`: a known value that names no privilege. */ + static unknownPrivilege() { + return XIDError.plain("UnknownPrivilege", "unknown privilege"); + } + /** `InvalidXid`: the inception key does not produce the document's XID. */ + static invalidXid() { + return XIDError.plain("InvalidXid", "invalid XID"); + } + /** `MissingInceptionKey`: the document has no inception key, or it has no private keys. */ + static missingInceptionKey() { + return XIDError.plain("MissingInceptionKey", "missing inception key"); + } + /** `InvalidResolutionMethod`: a `'dereferenceVia'` object that is not a URI. */ + static invalidResolutionMethod() { + return XIDError.plain("InvalidResolutionMethod", "invalid resolution method"); + } + /** `MultipleProvenanceMarks`: more than one `'provenance'` assertion. */ + static multipleProvenanceMarks() { + return XIDError.plain("MultipleProvenanceMarks", "multiple provenance marks"); + } + /** `UnexpectedPredicate`: a service assertion with a predicate the parser does not take. */ + static unexpectedPredicate(predicate) { + return XIDError.make(`unexpected predicate: ${predicate}`, { + code: "UnexpectedPredicate", + predicate + }); + } + /** `UnexpectedNestedAssertions`: a service assertion whose object has assertions. */ + static unexpectedNestedAssertions() { + return XIDError.plain("UnexpectedNestedAssertions", "unexpected nested assertions"); + } + /** `NoPermissions`: the service allows nothing. */ + static noPermissions(uri) { + return XIDError.make(`no permissions in service '${uri}'`, { + code: "NoPermissions", + uri + }); + } + /** `NoReferences`: the service names no key and no delegate. */ + static noReferences(uri) { + return XIDError.make(`no key or delegate references in service '${uri}'`, { + code: "NoReferences", + uri + }); + } + /** `UnknownKeyReference`: the service names a key the document lacks. */ + static unknownKeyReference(reference, uri) { + return XIDError.make(`unknown key reference ${reference} in service '${uri}'`, { + code: "UnknownKeyReference", + reference, + uri + }); + } + /** `UnknownDelegateReference`: the service names a delegate the document lacks. */ + static unknownDelegateReference(reference, uri) { + return XIDError.make(`unknown delegate reference ${reference} in service '${uri}'`, { + code: "UnknownDelegateReference", + reference, + uri + }); + } + /** `KeyNotFoundInDocument`: `expectKey` found no such key. */ + static keyNotFoundInDocument(key) { + return XIDError.make(`key not found in XID document: ${key}`, { + code: "KeyNotFoundInDocument", + key + }); + } + /** `DelegateNotFoundInDocument`: `expectDelegate` found no such delegate. */ + static delegateNotFoundInDocument(delegate) { + return XIDError.make(`delegate not found in XID document: ${delegate}`, { + code: "DelegateNotFoundInDocument", + delegate + }); + } + /** `InvalidPassword`: a locked key or generator did not open. */ + static invalidPassword() { + return XIDError.plain("InvalidPassword", "invalid password"); + } + /** `EnvelopeNotSigned`: verification was asked of an unsigned envelope. */ + static envelopeNotSigned() { + return XIDError.plain("EnvelopeNotSigned", "envelope is not signed"); + } + /** `SignatureVerificationFailed`: the inception key did not sign the envelope. */ + static signatureVerificationFailed() { + return XIDError.plain("SignatureVerificationFailed", "signature verification failed"); + } + /** `NoProvenanceMark`: the document has no mark to advance. */ + static noProvenanceMark() { + return XIDError.plain("NoProvenanceMark", "no provenance mark to advance"); + } + /** `GeneratorConflict`: a generator was given to a document that holds one. */ + static generatorConflict() { + return XIDError.plain("GeneratorConflict", "document already has generator, cannot provide external generator"); + } + /** `NoGenerator`: the document holds no generator and none was given. */ + static noGenerator() { + return XIDError.plain("NoGenerator", "document does not have generator, must provide external generator"); + } + /** `ChainIdMismatch`: the generator continues another chain. */ + static chainIdMismatch(expected, actual) { + return XIDError.make(`generator chain ID mismatch: expected ${hex(expected)}, got ${hex(actual)}`, { + code: "ChainIdMismatch", + expected, + actual + }); + } + /** `SequenceMismatch`: the generator's next sequence number is not the mark's plus one. */ + static sequenceMismatch(expected, actual) { + return XIDError.make(`generator sequence mismatch: expected ${expected}, got ${actual}`, { + code: "SequenceMismatch", + expected, + actual + }); + } + /** + * `EnvelopeParsing`: an envelope error inside a decoder. The message is + * the reference's `envelope parsing error`; the envelope error is + * `cause` and its message is `details.message`. + */ + static envelopeParsing(cause) { + return XIDError.make("envelope parsing error", { + code: "EnvelopeParsing", + message: messageOf$2(cause) + }, cause); + } + /** `Component`: a components error; the message is the reference's `component error`. */ + static component(cause) { + return XIDError.make("component error", { + code: "Component", + message: messageOf$2(cause) + }, cause); + } + /** `Cbor`: a dcbor error inside a decoder; the message is the reference's `CBOR error`. */ + static cbor(cause) { + return XIDError.make("CBOR error", { + code: "Cbor", + message: messageOf$2(cause) + }, cause); + } + /** + * `Cbor` from a CBOR or UR decoder entry point (`fromCbor`, + * `fromUntaggedCbor`, `fromUR`), where the reference returns the dcbor + * error itself: the message is the dcbor error's. + */ + static cborDecode(cause) { + return XIDError.make(cause.message, { + code: "Cbor", + message: cause.message + }, cause); + } + /** `ProvenanceMark`: a provenance-mark error; the message is the reference's `provenance mark error`. */ + static provenanceMark(cause) { + return XIDError.make("provenance mark error", { + code: "ProvenanceMark", + message: messageOf$2(cause) + }, cause); + } +}; +//#endregion +//#region ../bc-dcbor-ts/dist/error-BM_wVk_h.mjs +const MajorType = { Unsigned: 0, Negative: 1, ByteString: 2, @@ -9,10 +272,10 @@ const MajorType$1 = { Tagged: 6, Simple: 7 }; -const isCborNumber$1 = (value) => { +const isCborNumber = (value) => { return typeof value === "number" || typeof value === "bigint"; }; -const isCbor$1 = (value) => { +const isCbor = (value) => { return value !== null && typeof value === "object" && "isCbor" in value && value.isCbor === true; }; /** @@ -23,7 +286,7 @@ const isCbor$1 = (value) => { * @internal Exported for cross-module use; not part of the public surface - * use `Tag.equals` instead. */ -const tagValuesEqual$1 = (a, b) => { +const tagValuesEqual = (a, b) => { if (typeof a === "bigint" || typeof b === "bigint") return BigInt(a) === BigInt(b); return a === b; }; @@ -36,24 +299,27 @@ const Tag = { /** * Create a Tag from its numeric value, optionally with a name. * + * The returned object is frozen: a `Tag` is a value, as in the reference, + * and a store keeps the tags it is given by identity when they are frozen. + * * ```typescript * Tag.from(1, "date"); * Tag.from(12345); * ``` */ from(value, name) { - if (name !== void 0) return { + if (name !== void 0) return Object.freeze({ value, name - }; - return { value }; + }); + return Object.freeze({ value }); }, /** * Compare two tags for equality: compares by `value` only (normalizing * `number` vs `bigint`) and ignores the optional `name`. */ equals(a, b) { - return tagValuesEqual$1(a.value, b.value); + return tagValuesEqual(a.value, b.value); } }; /** @@ -65,7 +331,7 @@ const Tag = { * * @internal */ -const tagToString$1 = (tag) => tag.name ?? tag.value.toString(); +const tagToString = (tag) => tag.name ?? tag.value.toString(); const captureStackTrace = Error.captureStackTrace; /** * The single error type thrown by dCBOR encoding, decoding, and extraction. @@ -81,7 +347,7 @@ const captureStackTrace = Error.captureStackTrace; * } * ``` */ -var CborError$1 = class CborError extends Error { +var CborError = class CborError extends Error { /** Machine-readable discriminant; switch on this to handle errors. */ code; /** Structured, code-specific data (see {@link CborErrorDetails}). */ @@ -149,7 +415,7 @@ var CborError$1 = class CborError extends Error { } /** A tagged value had a tag other than the one expected. */ static wrongTag(expected, actual) { - return new CborError("WrongTag", `expected CBOR tag ${tagToString$1(expected)}, but got ${tagToString$1(actual)}`, { + return new CborError("WrongTag", `expected CBOR tag ${tagToString(expected)}, but got ${tagToString(actual)}`, { expectedTag: expected, actualTag: actual }); @@ -168,7 +434,7 @@ var CborError$1 = class CborError extends Error { } }; //#endregion -//#region tests/baseline/node_modules/@blockchaincommons/dcbor/dist/tags-store-BZjfminT.mjs +//#region ../bc-dcbor-ts/dist/tags-store-BSBP9gpt.mjs /** * Byte-array utilities shared across the library. * @@ -191,7 +457,7 @@ const lexicographicallyCompareBytes = (a, b) => { for (let i = 0; i < minLen; i++) { const aVal = a[i]; const bVal = b[i]; - if (aVal === void 0 || bVal === void 0) throw CborError$1.custom("Unexpected undefined byte in array"); + if (aVal === void 0 || bVal === void 0) throw CborError.custom("Unexpected undefined byte in array"); if (aVal < bVal) return -1; if (aVal > bVal) return 1; } @@ -280,6 +546,18 @@ var SortedByteMap = class { const n = this.items.length; return n > 0 ? this.items[n - 1].key : void 0; } + /** + * The key at position `i` in ascending key order. Positional access lets + * two maps be walked in lockstep, and a single map be encoded, without + * materializing an entries array; the caller keeps `i` within `[0, size)`. + */ + keyAt(i) { + return this.items[i].key; + } + /** The value at position `i` in ascending key order (see {@link keyAt}). */ + valueAt(i) { + return this.items[i].value; + } /** Map over each value (with its key) in ascending key order. */ map(fn) { return this.items.map((e) => fn(e.value, e.key)); @@ -291,7 +569,7 @@ var SortedByteMap = class { * ## The `number` / `bigint` contract * * dCBOR integers span `[-(2^64), 2^64)`, which exceeds JavaScript's safe -* integer range (`±(2^53 − 1)`). The single, repo-wide rule is: +* integer range (`±(2^53 − 1)`). The rule is: * * - An integer that fits in the IEEE-754 **safe** range is represented as a * `number`; anything larger (in magnitude) is a `bigint`. @@ -300,8 +578,7 @@ var SortedByteMap = class { * ones remain lossless `bigint`s. * - Encoding accepts either at the public edge and normalises once. * -* Every module funnels its boundary logic through this file - nothing else -* should hard-code `Number.MAX_SAFE_INTEGER`, `2^64`, etc. +* The integer range constants and the saturating float casts live here. * * @module numeric */ @@ -309,6 +586,14 @@ var SortedByteMap = class { const SAFE_MAX_BIG = BigInt(Number.MAX_SAFE_INTEGER); /** `BigInt(Number.MIN_SAFE_INTEGER)`. */ const SAFE_MIN_BIG = BigInt(Number.MIN_SAFE_INTEGER); +/** `u64::MAX` = 2^64 − 1. */ +const U64_MAX$4 = 18446744073709551615n; +/** `i64::MAX` = 2^63 − 1. */ +const I64_MAX = 9223372036854775807n; +/** `i64::MIN` = −2^63. */ +const I64_MIN = -9223372036854775808n; +/** `u128::MAX` = 2^128 − 1. */ +const U128_MAX = (1n << 128n) - 1n; /** Smallest dCBOR-encodable integer: −(2^64). */ const CBOR_INT_MIN = -(1n << 64n); /** @@ -318,6 +603,40 @@ const CBOR_INT_MIN = -(1n << 64n); */ const narrowInteger = (value) => value >= SAFE_MIN_BIG && value <= SAFE_MAX_BIG ? Number(value) : value; /** +* Truncate a float to `u64` with saturating semantics: NaN and negatives clamp +* to 0, values at/above 2^64 clamp to `u64::MAX`. Lets the exact-float checks +* verify the `(f as u64) == source` round-trip. +*/ +const saturateFloatToU64 = (f) => { + if (Number.isNaN(f)) return 0n; + const t = Math.trunc(f); + if (t <= 0) return 0n; + const big = BigInt(t); + return big > 18446744073709551615n ? U64_MAX$4 : big; +}; +/** +* Truncate a float to `i64` with saturating semantics: NaN clamps to 0, values +* clamp to `i64::MAX`/`i64::MIN` at the bounds. +*/ +const saturateFloatToI64 = (f) => { + if (Number.isNaN(f)) return 0n; + const big = BigInt(Math.trunc(f)); + if (big > 9223372036854775807n) return I64_MAX; + if (big < -9223372036854775808n) return I64_MIN; + return big; +}; +/** +* Truncate a float to `u128` with saturating semantics: NaN and negatives clamp +* to 0, values at/above 2^128 clamp to `u128::MAX`. +*/ +const saturateFloatToU128 = (f) => { + if (Number.isNaN(f)) return 0n; + const t = Math.trunc(f); + if (t <= 0) return 0n; + const big = BigInt(t); + return big > U128_MAX ? U128_MAX : big; +}; +/** * A growable output buffer for encoding. * * The encoder writes a whole CBOR tree into a single `BufWriter` rather than @@ -386,14 +705,14 @@ const typeBits = (t) => { /** * Write a CBOR head (major type + argument) straight into `writer`, avoiding * the intermediate `Uint8Array` that {@link encodeVarInt} allocates. This is -* the encoder hot path (every node emits a head). It MUST stay byte-identical +* the encoder hot path (every node emits a head). It must stay byte-identical * to {@link encodeVarInt}; the golden vectors cover both. */ const writeVarInt = (writer, value, majorType) => { - if (value < 0) throw CborError$1.outOfRange(); - if (typeof value === "number" && hasFractionalPart(value)) throw CborError$1.outOfRange(); + if (value < 0) throw CborError.outOfRange(); + if (typeof value === "number" && hasFractionalPart(value)) throw CborError.outOfRange(); const type = typeBits(majorType); - if (isCborNumber$1(value) && value <= Number.MAX_SAFE_INTEGER) { + if (isCborNumber(value) && value <= Number.MAX_SAFE_INTEGER) { const n = Number(value); if (n <= 23) writer.writeByte(n | type); else if (n <= 255) { @@ -411,16 +730,22 @@ const writeVarInt = (writer, value, majorType) => { } } else { const big = BigInt(value); - if (big > 18446744073709551615n) throw CborError$1.outOfRange(); + if (big > 18446744073709551615n) throw CborError.outOfRange(); writer.writeByte(27 | type); writer.writeBigUint64(big); } }; +/** +* Encode a CBOR head (major type + argument) in its shortest form. +* +* @throws {CborError} `OutOfRange` for a negative, fractional, or +* above-u64 argument. +*/ const encodeVarInt = (value, majorType) => { - if (value < 0) throw CborError$1.outOfRange(); - if (typeof value === "number" && hasFractionalPart(value)) throw CborError$1.outOfRange(); + if (value < 0) throw CborError.outOfRange(); + if (typeof value === "number" && hasFractionalPart(value)) throw CborError.outOfRange(); const type = typeBits(majorType); - if (isCborNumber$1(value) && value <= Number.MAX_SAFE_INTEGER) { + if (isCborNumber(value) && value <= Number.MAX_SAFE_INTEGER) { value = Number(value); if (value <= 23) return new Uint8Array([value | type]); else if (value <= 255) return new Uint8Array([24 | type, value]); @@ -445,7 +770,7 @@ const encodeVarInt = (value, majorType) => { } } else { const big = BigInt(value); - if (big > 18446744073709551615n) throw CborError$1.outOfRange(); + if (big > 18446744073709551615n) throw CborError.outOfRange(); const buffer = /* @__PURE__ */ new ArrayBuffer(9); const view = new DataView(buffer); view.setUint8(0, 27 | type); @@ -599,23 +924,65 @@ var ExactU64 = class { } }; /** +* Exact conversions for f64 (double precision float). +*/ +var ExactF64 = class { + static exactFromF16(source) { + if (Number.isNaN(source)) return NaN; + return source; + } + static exactFromF32(source) { + if (Number.isNaN(source)) return NaN; + return source; + } + static exactFromF64(source) { + if (Number.isNaN(source)) return NaN; + return source; + } + static exactFromU64(source) { + const srcBig = typeof source === "bigint" ? source : BigInt(source); + const n = Number(srcBig); + if (!Number.isFinite(n)) return void 0; + return saturateFloatToU64(n) === srcBig ? n : void 0; + } + static exactFromI64(source) { + const srcBig = typeof source === "bigint" ? source : BigInt(source); + const n = Number(srcBig); + if (!Number.isFinite(n)) return void 0; + return saturateFloatToI64(n) === srcBig ? n : void 0; + } + static exactFromU128(source) { + const n = Number(source); + if (!Number.isFinite(n)) return void 0; + return saturateFloatToU128(n) === source ? n : void 0; + } + static exactFromI128(source) { + if (source < -9223372036854775808n || source > 9223372036854775807n) return; + const absSource = source < 0n ? -source : source; + if (absSource <= 4503599627370495n) return Number(source); + const trailingZeros = countTrailingZeros(absSource); + if (trailingZeros >= 53 && trailingZeros <= 63) return Number(source); + } +}; +const countTrailingZeros = (n) => { + if (n === 0n) return 0; + let count = 0; + while ((n & 1n) === 0n) { + count++; + n = n >> 1n; + } + return count; +}; +/** * Float encoding and conversion utilities for dCBOR. * -* # Floating Point Number Support in dCBOR -* -* dCBOR provides canonical encoding for floating point values. -* -* Per the dCBOR specification, the canonical encoding rules ensure -* deterministic representation: +* The dCBOR canonical encoding rules for floating point values: * -* - Numeric reduction: Floating point values with zero fractional part in -* range [-2^63, 2^64-1] are automatically encoded as integers (e.g., 42.0 -* becomes 42) -* - Values are encoded in the smallest possible representation that preserves -* their value -* - All NaN values are canonicalized to a single representation: 0xf97e00 -* - Positive/negative infinity are canonicalized to half-precision -* representations +* - Numeric reduction: a float with zero fractional part in +* [-2^64, 2^64-1] is encoded as an integer (42.0 becomes 42) +* - Other values use the smallest width (f16, f32, f64) that preserves them +* - Every NaN is encoded as the single representation 0xf97e00 +* - Positive and negative infinity are encoded as half-precision floats * * @module float */ @@ -653,11 +1020,10 @@ const f32ScratchView = /* @__PURE__ */ new DataView(/* @__PURE__ */ new ArrayBuf * Compute the 16-bit pattern of the IEEE-754 half-precision value nearest `n`, * rounding ties to even. * -* All call sites pass values already exactly representable in binary16 (the -* reduction gates in {@link f16CborData} ensure this), so no rounding occurs on -* a value that is actually stored; the rounding path exists only so the -* reduction round-trip probe (`binary16ToNumber(numberToBinary16(n)) === n`) -* answers correctly for non-representable inputs. +* A value is only stored as a half after the round-trip probe +* (`binary16ToNumber(numberToBinary16(n)) === n`) succeeds, so stored values +* never round; the rounding makes that probe, and the reference's +* `f16::from_f32` in `validateCanonicalF32`, answer correctly for any input. */ const float16Bits = (n) => { f32ScratchView.setFloat32(0, n, false); @@ -724,11 +1090,11 @@ const f64CborData = (value) => { const i128 = ExactI128.exactFromF64(n); if (i128 !== void 0) { const i = ExactU64.exactFromI128(-1n - i128); - if (i !== void 0) return encodeVarInt(i, MajorType$1.Negative); + if (i !== void 0) return encodeVarInt(i, MajorType.Negative); } } const u = ExactU64.exactFromF64(n); - if (u !== void 0) return encodeVarInt(u, MajorType$1.Unsigned); + if (u !== void 0) return encodeVarInt(u, MajorType.Unsigned); if (Number.isNaN(value)) return CBOR_NAN; const buffer = /* @__PURE__ */ new ArrayBuffer(8); new DataView(buffer).setFloat64(0, n, false); @@ -747,10 +1113,10 @@ const f32CborData = (value) => { if (f === n) return f16CborData(f); if (n < 0) { const u = ExactU64.exactFromF32(Math.fround(-1 - n)); - if (u !== void 0) return encodeVarInt(u, MajorType$1.Negative); + if (u !== void 0) return encodeVarInt(u, MajorType.Negative); } const u = ExactU32.exactFromF32(n); - if (u !== void 0) return encodeVarInt(u, MajorType$1.Unsigned); + if (u !== void 0) return encodeVarInt(u, MajorType.Unsigned); if (Number.isNaN(value)) return CBOR_NAN; const bytes = numberToBinary32(n); return new Uint8Array([250, ...bytes]); @@ -764,39 +1130,319 @@ const f16CborData = (value) => { const n = value; if (n < 0) { const u = ExactU64.exactFromF64(-1 - n); - if (u !== void 0) return encodeVarInt(u, MajorType$1.Negative); + if (u !== void 0) return encodeVarInt(u, MajorType.Negative); } const u = ExactU16.exactFromF64(n); - if (u !== void 0) return encodeVarInt(u, MajorType$1.Unsigned); + if (u !== void 0) return encodeVarInt(u, MajorType.Unsigned); if (Number.isNaN(value)) return CBOR_NAN; const bytes = numberToBinary16(value); return new Uint8Array([249, ...bytes]); }; +const TWO_POW_63 = 2 ** 63; /** -* Render a float to its diagnostic string. -* -* Finite non-zero values with magnitude in [1e-4, 1e16) print in decimal with -* at least one fractional digit (whole values get a trailing `.0`); everything -* else prints in exponential form. Zero prints as `0.0`/`-0.0`. -* -* JS already produces the same shortest round-tripping digits; we only fix up -* the notation threshold, the `e+` → `e` exponent, and the `.0` suffix. -* -* @param value - The float value -* @returns The diagnostic string +* Rust `n as i64 as f64`: NaN → 0; saturates at the i64 bounds. `i64::MAX` +* (2^63 - 1) is not a double, so the saturated image converts back to 2^63, +* and every double at or above 2^63 saturates to it. +*/ +const saturatingI64AsF64 = (n) => { + if (Number.isNaN(n)) return 0; + if (n >= TWO_POW_63) return TWO_POW_63; + if (n <= -TWO_POW_63) return -TWO_POW_63; + return Math.trunc(n); +}; +/** Rust `n as i32 as f32` for an f32 value: NaN → 0; saturates at the i32 bounds. */ +const saturatingI32AsF32 = (n) => { + if (Number.isNaN(n)) return 0; + if (n >= 2147483647) return Math.fround(2147483647); + if (n <= -2147483648) return -2147483648; + return Math.fround(Math.trunc(n)); +}; +/** +* `validate_canonical_f16`: a half head is non-canonical when it is +* whole-valued (must be an integer) or a NaN other than `0x7e00`. +* @internal +*/ +const validateCanonicalF16 = (bits, n) => { + if (n === saturatingI64AsF64(n) || Number.isNaN(n) && bits !== 32256) throw CborError.nonCanonicalNumeric(); +}; +/** +* `validate_canonical_f32`: a single head is non-canonical when it fits a half +* (including ±0 and ±Infinity), equals its saturating `i32` image, or is NaN. +* @internal +*/ +const validateCanonicalF32 = (n) => { + if (n === binary16ToNumber(numberToBinary16(n)) || n === saturatingI32AsF32(n) || Number.isNaN(n)) throw CborError.nonCanonicalNumeric(); +}; +/** +* `validate_canonical_f64`: a double head is non-canonical when it fits a +* single, equals its saturating `i64` image, or is NaN. +* @internal +*/ +const validateCanonicalF64 = (n) => { + if (n === Math.fround(n) || n === saturatingI64AsF64(n) || Number.isNaN(n)) throw CborError.nonCanonicalNumeric(); +}; +const unsignedNode = (value) => ({ + isCbor: true, + type: MajorType.Unsigned, + value +}); +const negativeNode = (magnitude) => ({ + isCbor: true, + type: MajorType.Negative, + value: magnitude +}); +const floatNode = (value) => ({ + isCbor: true, + type: MajorType.Simple, + value: { + type: "Float", + value + } +}); +/** `From for CBOR`. @internal */ +const cborNodeFromF16 = (n) => { + if (n < 0) { + const i = ExactU64.exactFromF64(-1 - n); + if (i !== void 0) return negativeNode(i); + } + const u = ExactU16.exactFromF64(n); + if (u !== void 0) return unsignedNode(u); + return floatNode(n); +}; +/** +* `From for CBOR`. The negative magnitude is computed in f32 arithmetic +* (`-1f32 - n`): `Math.fround(-1 - n)` is exactly that, since a double holds +* the difference of two singles with at most one rounding. +* @internal +*/ +const cborNodeFromF32 = (n) => { + if (n < 0) { + const i = ExactU64.exactFromF32(Math.fround(-1 - n)); + if (i !== void 0) return negativeNode(i); + } + const u = ExactU32.exactFromF32(n); + if (u !== void 0) return unsignedNode(u); + return floatNode(n); +}; +/** `From for CBOR`. @internal */ +const cborNodeFromF64 = (n) => { + if (n < 0) { + const i128 = ExactI128.exactFromF64(n); + if (i128 !== void 0) { + const i = ExactU64.exactFromI128(-1n - i128); + if (i !== void 0) return negativeNode(i); + } + } + const u = ExactU64.exactFromF64(n); + if (u !== void 0) return unsignedNode(u); + return floatNode(n); +}; +/** +* Shortest round-trip decimal digits of a finite positive double, as the pair +* (significant digits without trailing zeros, scientific exponent), where the +* value is `d1.d2…dk × 10^exp10`. +* +* `String(x)` already yields the shortest digit string; this only re-shapes +* it (ECMAScript picks between "123.45", "1.5e-7", "1e+21" and "0.000001" by +* magnitude) so the caller can apply Rust's notation rules. +*/ +const shortestDigits = (abs) => { + const text = String(abs); + const eIndex = text.indexOf("e"); + const mantissa = eIndex === -1 ? text : text.slice(0, eIndex); + const exponent = eIndex === -1 ? 0 : Number(text.slice(eIndex + 1)); + const dot = mantissa.indexOf("."); + let digits = dot === -1 ? mantissa : mantissa.slice(0, dot) + mantissa.slice(dot + 1); + let pointPos = dot === -1 ? mantissa.length : dot; + while (digits.length > 1 && digits.startsWith("0")) { + digits = digits.slice(1); + pointPos--; + } + digits = digits.replace(/0+$/, ""); + if (digits === "") digits = "0"; + return { + digits, + exp10: pointPos - 1 + exponent + }; +}; +/** The exact value of a finite positive double as `mantissa × 2^exp2`. */ +const exactBinary = (abs) => { + const view = /* @__PURE__ */ new DataView(/* @__PURE__ */ new ArrayBuffer(8)); + view.setFloat64(0, abs, false); + const hi = view.getUint32(0, false); + const lo = view.getUint32(4, false); + const biasedExp = hi >>> 20 & 2047; + const fraction = BigInt(hi & 1048575) << 32n | BigInt(lo); + return biasedExp === 0 ? { + mantissa: fraction, + exp2: -1074 + } : { + mantissa: fraction | 1n << 52n, + exp2: biasedExp - 1075 + }; +}; +/** +* The exact decimal expansion of a finite positive double, as its significant +* digits (no trailing zeros). Every double is a dyadic rational, so +* `m × 2^q = m × 5^-q / 10^-q` for negative `q` gives the digits exactly. +*/ +const exactDecimalDigits = (abs) => { + const { mantissa, exp2 } = exactBinary(abs); + return (exp2 >= 0 ? mantissa << BigInt(exp2) : mantissa * 5n ** BigInt(-exp2)).toString().replace(/0+$/, ""); +}; +/** +* Shortest round-trip digits the way Rust's `{:?}` produces them. +* +* JS and Rust agree on the shortest digit string except when the exact value +* sits precisely halfway between the two shortest candidates: ECMAScript +* (`Number::toString`) picks the even candidate, Rust's `flt2dec` rounds the +* magnitude up. `10 × 2^-24` is exactly `5.9604644775390625e-7`, which JS +* prints as `…062e-7` and Rust as `…063e-7`. Detect the tie exactly and take +* the upper candidate when it also round-trips. +*/ +const rustShortestDigits = (abs) => { + const shortest = shortestDigits(abs); + const k = shortest.digits.length; + const probe = abs.toPrecision(k + 1); + const probeIndex = probe.indexOf("e"); + if (!(probeIndex === -1 ? probe : probe.slice(0, probeIndex)).endsWith("5")) return shortest; + const exact = exactDecimalDigits(abs); + if (exact.length !== k + 1 || !exact.endsWith("5")) return shortest; + let upper = (BigInt(exact.slice(0, k)) + 1n).toString(); + let exp10 = shortest.exp10; + if (upper.length > k) exp10 += 1; + upper = upper.replace(/0+$/, ""); + if (upper === "") upper = "0"; + return Number(`${upper[0]}.${upper.slice(1)}e${exp10}`) === abs ? { + digits: upper, + exp10 + } : shortest; +}; +/** +* Render a float to its diagnostic string, the reference's `Display for +* Simple` (`simple.rs`) - the rendering `diagnostic()` and `hexAnnotated()` +* use. +* +* Non-finite values print as `NaN`, `Infinity` and `-Infinity`, exactly as the +* reference's `Display` does - not the `inf`/`-inf` of Rust's `{:?}`, which is +* `Simple::name()`'s rendering and is ported as `simpleName` (`simple.ts`). +* +* Finite values match Rust's `{:?}` for `f64`: non-zero values with magnitude +* in [1e-4, 1e16) print in decimal with at least one fractional digit (whole +* values get a trailing `.0`); everything else prints in exponential form +* (`1.5e20`, `5e-324` - no `+`, no padding). Zero prints as `0.0`/`-0.0`. +* Digits are the shortest round-trip sequence, with exact decimal ties rounded +* up like Rust (see {@link rustShortestDigits}). */ const floatDisplayString = (value) => { if (Number.isNaN(value)) return "NaN"; if (!Number.isFinite(value)) return value > 0 ? "Infinity" : "-Infinity"; if (value === 0) return Object.is(value, -0) ? "-0.0" : "0.0"; - const abs = Math.abs(value); - if (abs >= 1e-4 && abs < 0x2386f26fc10000) { - let str = String(value); - if (!str.includes(".")) str = `${str}.0`; - return str; + const sign = value < 0 ? "-" : ""; + const { digits, exp10 } = rustShortestDigits(Math.abs(value)); + if (exp10 >= -4 && exp10 < 16) { + if (exp10 < 0) return `${sign}0.${"0".repeat(-exp10 - 1)}${digits}`; + const intLen = exp10 + 1; + return `${sign}${digits.length >= intLen ? digits.slice(0, intLen) : digits.padEnd(intLen, "0")}.${digits.length > intLen ? digits.slice(intLen) : "0"}`; } - return value.toExponential().replace("e+", "e"); + return `${sign}${digits.length > 1 ? `${digits[0]}.${digits.slice(1)}` : digits}e${exp10}`; +}; +/** +* UTF-8 validation failure description, mirroring `core::str::Utf8Error`. +* +* The decoder rejects malformed text with the WHATWG `TextDecoder` (fatal +* mode), whose error text is host-defined. To report the same message as the +* reference (`str::from_utf8` → `Utf8Error` → `Display`), the failing bytes +* are re-scanned here with a port of `core::str::validations:: +* run_utf8_validation`, which yields the reference's `(valid_up_to, +* error_len)` pair. +* +* @module utf8 +* @internal +*/ +/** +* `core::str::validations::utf8_char_width`: the sequence length a lead byte +* announces, or 0 for a byte that can never start a sequence (a continuation +* byte `80-bf`, the overlong leads `c0`/`c1`, or `f5-ff`). +*/ +const utf8CharWidth = (lead) => { + if (lead < 128) return 1; + if (lead < 194) return 0; + if (lead < 224) return 2; + if (lead < 240) return 3; + if (lead < 245) return 4; + return 0; }; +/** A byte that is not a UTF-8 continuation byte (`80-bf`). */ +const isNotContinuation = (byte) => byte < 128 || byte > 191; +/** +* Locate the first UTF-8 error in `bytes` the way `run_utf8_validation` +* does, or return `undefined` when the bytes are valid. +* +* `validUpTo` is the index of the offending lead byte. `errorLength` is the +* number of bytes to skip (1, 2 or 3) when an invalid byte is present, or +* `undefined` when the input ends inside a sequence. A present invalid byte +* always beats "incomplete": the continuation bytes are checked one at a +* time as they are read. +*/ +const findUtf8Error = (bytes) => { + const len = bytes.length; + let index = 0; + while (index < len) { + const first = bytes[index]; + if (first < 128) { + index++; + continue; + } + const start = index; + const next = () => { + index++; + return index < len ? bytes[index] : void 0; + }; + const err = (errorLength) => ({ + validUpTo: start, + errorLength + }); + const width = utf8CharWidth(first); + if (width === 2) { + const b1 = next(); + if (b1 === void 0) return err(void 0); + if (isNotContinuation(b1)) return err(1); + } else if (width === 3) { + const b1 = next(); + if (b1 === void 0) return err(void 0); + if (!(first === 224 && b1 >= 160 && b1 <= 191 || first >= 225 && first <= 236 && b1 >= 128 && b1 <= 191 || first === 237 && b1 >= 128 && b1 <= 159 || first >= 238 && first <= 239 && b1 >= 128 && b1 <= 191)) return err(1); + const b2 = next(); + if (b2 === void 0) return err(void 0); + if (isNotContinuation(b2)) return err(2); + } else if (width === 4) { + const b1 = next(); + if (b1 === void 0) return err(void 0); + if (!(first === 240 && b1 >= 144 && b1 <= 191 || first >= 241 && first <= 243 && b1 >= 128 && b1 <= 191 || first === 244 && b1 >= 128 && b1 <= 143)) return err(1); + const b2 = next(); + if (b2 === void 0) return err(void 0); + if (isNotContinuation(b2)) return err(2); + const b3 = next(); + if (b3 === void 0) return err(void 0); + if (isNotContinuation(b3)) return err(3); + } else return err(1); + index++; + } +}; +/** +* `Utf8Error`'s `Display` text for `bytes`, which must be invalid UTF-8: +* `invalid utf-8 sequence of N bytes from index I` or `incomplete utf-8 byte +* sequence from index I`. +*/ +const utf8ErrorDescription = (bytes) => { + const info = findUtf8Error(bytes); + if (info === void 0) return "invalid utf-8 sequence"; + return info.errorLength === void 0 ? `incomplete utf-8 byte sequence from index ${info.validUpTo}` : `invalid utf-8 sequence of ${info.errorLength} bytes from index ${info.validUpTo}`; +}; +const utf8Decoder = new TextDecoder("utf-8", { + fatal: true, + ignoreBOM: true +}); /** * A forward-only cursor over the input bytes. * @@ -849,14 +1495,13 @@ var ByteReader = class { * @remarks Decoded byte strings are zero-copy views aliasing the input * buffer - mutating the input after decoding (or mutating the returned * bytes) changes the other side. Call `.slice()` first if you need an -* independent copy. This is deliberate: the zero-copy decode performance -* profile is part of the library's contract. +* independent copy. */ -function decodeCbor$1(data) { +function decodeCbor(data) { const reader = new ByteReader(data); const cbor = readCbor(reader); const remaining = reader.byteLength - reader.pos; - if (remaining !== 0) throw CborError$1.unusedData(remaining); + if (remaining !== 0) throw CborError.unusedData(remaining); return cbor; } function parseHeader(header) { @@ -871,7 +1516,7 @@ function parseHeader(header) { * for canonical minimal-length encoding. */ function readHeaderVarint(reader) { - if (reader.remaining < 1) throw CborError$1.underrun(); + if (reader.remaining < 1) throw CborError.underrun(); const header = reader.peek(0); const { majorType, headerValue } = parseHeader(header); const dataRemaining = reader.remaining - 1; @@ -881,22 +1526,22 @@ function readHeaderVarint(reader) { value = headerValue; varIntLen = 1; } else if (headerValue === 24) { - if (dataRemaining < 1) throw CborError$1.underrun(); + if (dataRemaining < 1) throw CborError.underrun(); value = reader.peek(1); - if (value < 24) throw CborError$1.nonCanonicalNumeric(); + if (value < 24) throw CborError.nonCanonicalNumeric(); varIntLen = 2; } else if (headerValue === 25) { - if (dataRemaining < 2) throw CborError$1.underrun(); + if (dataRemaining < 2) throw CborError.underrun(); value = (reader.peek(1) << 8 | reader.peek(2)) >>> 0; - if (value <= 255 && header !== 249) throw CborError$1.nonCanonicalNumeric(); + if (value <= 255 && header !== 249) throw CborError.nonCanonicalNumeric(); varIntLen = 3; } else if (headerValue === 26) { - if (dataRemaining < 4) throw CborError$1.underrun(); + if (dataRemaining < 4) throw CborError.underrun(); value = (reader.peek(1) << 24 | reader.peek(2) << 16 | reader.peek(3) << 8 | reader.peek(4)) >>> 0; - if (value <= 65535 && header !== 250) throw CborError$1.nonCanonicalNumeric(); + if (value <= 65535 && header !== 250) throw CborError.nonCanonicalNumeric(); varIntLen = 5; } else if (headerValue === 27) { - if (dataRemaining < 8) throw CborError$1.underrun(); + if (dataRemaining < 8) throw CborError.underrun(); const a = BigInt(reader.peek(1)) << 56n; const b = BigInt(reader.peek(2)) << 48n; const c = BigInt(reader.peek(3)) << 40n; @@ -906,9 +1551,9 @@ function readHeaderVarint(reader) { const g = BigInt(reader.peek(7)) << 8n; const h = BigInt(reader.peek(8)); value = narrowInteger(a | b | c | d | e | f | g | h); - if (value <= 4294967295 && header !== 251) throw CborError$1.nonCanonicalNumeric(); + if (value <= 4294967295 && header !== 251) throw CborError.nonCanonicalNumeric(); varIntLen = 9; - } else throw CborError$1.unsupportedHeaderValue(headerValue); + } else throw CborError.unsupportedHeaderValue(headerValue); reader.advance(varIntLen); return { majorType, @@ -917,170 +1562,148 @@ function readHeaderVarint(reader) { }; } function readCbor(reader) { - if (reader.remaining < 1) throw CborError$1.underrun(); + if (reader.remaining < 1) throw CborError.underrun(); const headStart = reader.pos; const { majorType, value, varIntLen } = readHeaderVarint(reader); switch (majorType) { - case MajorType$1.Unsigned: { - const cbor = attachMethods$1({ + case MajorType.Unsigned: { + const cbor = attachMethods({ isCbor: true, - type: MajorType$1.Unsigned, + type: MajorType.Unsigned, value }); checkCanonicalEncoding(cbor, reader.bytesAt(headStart, varIntLen)); return cbor; } - case MajorType$1.Negative: { - const cbor = attachMethods$1({ + case MajorType.Negative: { + const cbor = attachMethods({ isCbor: true, - type: MajorType$1.Negative, + type: MajorType.Negative, value }); checkCanonicalEncoding(cbor, reader.bytesAt(headStart, varIntLen)); return cbor; } - case MajorType$1.ByteString: { - if (typeof value === "bigint") throw CborError$1.underrun(); - if (reader.remaining < value) throw CborError$1.underrun(); + case MajorType.ByteString: { + if (typeof value === "bigint") throw CborError.underrun(); + if (reader.remaining < value) throw CborError.underrun(); const bytes = reader.bytesAt(reader.pos, value); reader.advance(value); - return attachMethods$1({ + return attachMethods({ isCbor: true, - type: MajorType$1.ByteString, + type: MajorType.ByteString, value: bytes }); } - case MajorType$1.Text: { - if (typeof value === "bigint") throw CborError$1.underrun(); - if (reader.remaining < value) throw CborError$1.underrun(); + case MajorType.Text: { + if (typeof value === "bigint") throw CborError.underrun(); + if (reader.remaining < value) throw CborError.underrun(); const textBytes = reader.bytesAt(reader.pos, value); reader.advance(value); let text; try { - text = new TextDecoder("utf-8", { fatal: true }).decode(textBytes); - } catch (e) { - throw CborError$1.invalidUtf8(e instanceof Error ? e.message : String(e)); + text = utf8Decoder.decode(textBytes); + } catch { + throw CborError.invalidUtf8(utf8ErrorDescription(textBytes)); } - if (text.normalize("NFC") !== text) throw CborError$1.nonCanonicalString(); - return attachMethods$1({ + if (text.normalize("NFC") !== text) throw CborError.nonCanonicalString(); + return attachMethods({ isCbor: true, - type: MajorType$1.Text, + type: MajorType.Text, value: text }); } - case MajorType$1.Array: { + case MajorType.Array: { const items = []; for (let i = 0; i < value; i++) items.push(readCbor(reader)); - return attachMethods$1({ + return attachMethods({ isCbor: true, - type: MajorType$1.Array, + type: MajorType.Array, value: items }); } - case MajorType$1.Map: { - const map = new CborMap$1(); + case MajorType.Map: { + const map = new CborMap(); for (let i = 0; i < value; i++) { const key = readCbor(reader); const val = readCbor(reader); map.setNext(key, val); } - return attachMethods$1({ + return attachMethods({ isCbor: true, - type: MajorType$1.Map, + type: MajorType.Map, value: map }); } - case MajorType$1.Tagged: { + case MajorType.Tagged: { const item = readCbor(reader); - return attachMethods$1({ + return attachMethods({ isCbor: true, - type: MajorType$1.Tagged, + type: MajorType.Tagged, tag: value, value: item }); } - case MajorType$1.Simple: switch (varIntLen) { + case MajorType.Simple: switch (varIntLen) { case 3: { const f = binary16ToNumber(reader.bytesAt(headStart + 1, 2)); - checkCanonicalEncoding(f, reader.bytesAt(headStart, varIntLen)); - return attachMethods$1({ - isCbor: true, - type: MajorType$1.Simple, - value: { - type: "Float", - value: f - } - }); + validateCanonicalF16(Number(value), f); + return attachMethods(cborNodeFromF16(f)); } case 5: { const f = binary32ToNumber(reader.bytesAt(headStart + 1, 4)); - checkCanonicalEncoding(f, reader.bytesAt(headStart, varIntLen)); - return attachMethods$1({ - isCbor: true, - type: MajorType$1.Simple, - value: { - type: "Float", - value: f - } - }); + validateCanonicalF32(f); + return attachMethods(cborNodeFromF32(f)); } case 9: { const f = binary64ToNumber(reader.bytesAt(headStart + 1, 8)); - checkCanonicalEncoding(f, reader.bytesAt(headStart, varIntLen)); - return attachMethods$1({ - isCbor: true, - type: MajorType$1.Simple, - value: { - type: "Float", - value: f - } - }); + validateCanonicalF64(f); + return attachMethods(cborNodeFromF64(f)); } default: switch (value) { - case 20: return attachMethods$1({ + case 20: return attachMethods({ isCbor: true, - type: MajorType$1.Simple, + type: MajorType.Simple, value: { type: "False" } }); - case 21: return attachMethods$1({ + case 21: return attachMethods({ isCbor: true, - type: MajorType$1.Simple, + type: MajorType.Simple, value: { type: "True" } }); - case 22: return attachMethods$1({ + case 22: return attachMethods({ isCbor: true, - type: MajorType$1.Simple, + type: MajorType.Simple, value: { type: "Null" } }); - default: throw CborError$1.invalidSimpleValue(); + default: throw CborError.invalidSimpleValue(); } } } } function checkCanonicalEncoding(cbor, buf) { - if (!areBytesEqual(buf, encodeCbor(cbor))) throw CborError$1.nonCanonicalNumeric(); + const buf2 = encodeCbor(cbor); + if (!areBytesEqual(buf, buf2)) throw CborError.nonCanonicalNumeric(); } /** -* Extract native JavaScript value from CBOR. -* Converts CBOR types to their JavaScript equivalents. -* -* Returns the closed union {@link CborNative}. Note the two asymmetries -* documented there: maps come back as `CborMap` and tagged values as `Cbor`. +* Extract the native JavaScript value from a CBOR value, decoding it first +* when given bytes. Maps come back as `CborMap` and tagged values as `Cbor` +* (see {@link CborNative}). */ -const extractCbor$1 = (cbor) => { +const extractCbor = (cbor) => { let c; - if (cbor instanceof Uint8Array) c = decodeCbor$1(cbor); + if (cbor instanceof Uint8Array) c = decodeCbor(cbor); else c = cbor; switch (c.type) { - case MajorType$1.Unsigned: return c.value; - case MajorType$1.Negative: if (typeof c.value === "bigint") return -c.value - 1n; + case MajorType.Unsigned: return c.value; + case MajorType.Negative: if (typeof c.value === "bigint") return -c.value - 1n; else return -c.value - 1; - case MajorType$1.ByteString: return c.value; - case MajorType$1.Text: return c.value; - case MajorType$1.Array: return c.value.map(extractCbor$1); - case MajorType$1.Map: return c.value; - case MajorType$1.Tagged: return c; - case MajorType$1.Simple: { + case MajorType.ByteString: return c.value; + case MajorType.Text: return c.value; + case MajorType.Array: return c.value.map(extractCbor); + case MajorType.Map: return c.value; + case MajorType.Tagged: return c; + case MajorType.Simple: { const simple = c.value; switch (simple.type) { case "True": return true; @@ -1094,28 +1717,17 @@ const extractCbor$1 = (cbor) => { } }; /** -* Map Support in dCBOR -* -* A deterministic CBOR map implementation that ensures maps with the same -* content always produce identical binary encodings, regardless of insertion -* order. -* -* ## Deterministic Map Representation +* A deterministic CBOR map: maps with the same content encode identically, +* regardless of insertion order. * -* The `CborMap` type follows strict deterministic encoding rules as specified by -* dCBOR: -* -* - Map keys are always sorted in lexicographic order of their encoded CBOR bytes -* - Duplicate keys are not allowed (enforced by the implementation) +* - Entries are kept in lexicographic order of their encoded key bytes +* - Setting a key whose encoding is already present replaces that entry * - Keys and values can be any type that can be converted to CBOR -* - Numeric reduction is applied (e.g., 3.0 is stored as integer 3) -* -* ## Vocabulary * * `CborMap` mirrors the JS `Map` protocol: `set`, `get`, `getOrThrow`, `has`, * `delete`, `clear`, `size`, `keys()`, `values()`, `entries()`, `forEach`, -* iteration. `get` returns the STORED `Cbor` node (symmetric with -* `entries()`); extract natives explicitly with `extractCbor(map.get(k))`. +* iteration. `get` returns the stored `Cbor` node, like `entries()`; extract +* natives explicitly with `extractCbor(map.getOrThrow(k))`. * * @module map */ @@ -1125,7 +1737,7 @@ const extractCbor$1 = (cbor) => { * Maps are always encoded with keys sorted lexicographically by their * encoded CBOR representation, ensuring deterministic encoding. */ -var CborMap$1 = class { +var CborMap = class { /** Debug label: `Object.prototype.toString` reports `[object CborMap]`. */ get [Symbol.toStringTag]() { return "CborMap"; @@ -1155,8 +1767,8 @@ var CborMap$1 = class { * @public */ set(key, value) { - const keyCbor = cbor$1(key); - const valueCbor = cbor$1(value); + const keyCbor = cbor(key); + const valueCbor = cbor(value); const keyData = encodeCbor(keyCbor); this._dict.set(keyData, { key: keyCbor, @@ -1164,13 +1776,12 @@ var CborMap$1 = class { }); } _makeKey(key) { - return encodeCbor(cbor$1(key)); + return encodeCbor(cbor(key)); } /** - * Get the STORED `Cbor` node for a key, or `undefined` if absent. + * Get the stored `Cbor` node for a key, or `undefined` if absent. * - * This is symmetric with `entries()` - no hidden native extraction, no - * unwitnessed generics. To read a native value, compose explicitly: + * To read a native value, compose explicitly: * * ```typescript * asNumber(map.get("age")); // number | undefined, checked @@ -1188,7 +1799,7 @@ var CborMap$1 = class { */ getOrThrow(key) { const value = this.get(key); - if (value === void 0) throw CborError$1.missingMapKey(); + if (value === void 0) throw CborError.missingMapKey(); return value; } delete(key) { @@ -1220,6 +1831,28 @@ var CborMap$1 = class { value: value.value })); } + /** + * The stored entry at position `i` in canonical ascending encoded-key + * order; the caller keeps `i` within `[0, size)`. + * + * @internal Positional access for the encoder and for structural equality, + * which walk a map (or two maps in lockstep) without materializing + * `entriesArray`; not part of the supported surface. + */ + entryAt(i) { + return this._dict.valueAt(i); + } + /** + * The encoded CBOR bytes of the key at position `i` - the bytes the entry + * is sorted by, computed once when it was inserted. + * + * @internal The encoder writes these directly, as the reference's + * `Map::cbor_data` writes its stored `MapKey`, instead of re-encoding the + * key node; not part of the supported surface. + */ + encodedKeyAt(i) { + return this._dict.keyAt(i); + } /** Iterate keys in canonical (sorted encoded-key) order. */ *keys() { for (const entry of this.entriesArray) yield entry.key; @@ -1243,23 +1876,24 @@ var CborMap$1 = class { for (const entry of this.entriesArray) yield [entry.key, entry.value]; } /** - * Inserts the next key-value pair into the map during decoding. - * This is used for efficient map building during CBOR decoding. - * Throws if the key is not in ascending order or is a duplicate. + * Append a key-value pair whose encoded key must sort strictly after every + * existing key. * * @internal The decoder's append path; not part of the supported surface. + * @throws {CborError} `DuplicateMapKey` for a repeated key, + * `MisorderedMapKey` for a key out of ascending order. */ setNext(key, value) { - const keyCbor = cbor$1(key); + const keyCbor = cbor(key); const newKey = encodeCbor(keyCbor); - if (this._dict.has(newKey)) throw CborError$1.duplicateMapKey(); + if (this._dict.has(newKey)) throw CborError.duplicateMapKey(); const greatest = this._dict.maxKey(); if (greatest !== void 0) { - if (lexicographicallyCompareBytes(newKey, greatest) <= 0) throw CborError$1.misorderedMapKey(); + if (lexicographicallyCompareBytes(newKey, greatest) <= 0) throw CborError.misorderedMapKey(); } this._dict.appendGreatest(newKey, { key: keyCbor, - value: cbor$1(value) + value: cbor(value) }); } /** @@ -1269,11 +1903,15 @@ var CborMap$1 = class { */ toMap() { const map = /* @__PURE__ */ new Map(); - for (const entry of this.entriesArray) map.set(extractCbor$1(entry.key), extractCbor$1(entry.value)); + for (const entry of this.entriesArray) map.set(extractCbor(entry.key), extractCbor(entry.value)); return map; } }; /** +* Checks if the simple value is a floating point number. +*/ +const isFloat$1 = (simple) => simple.type === "Float"; +/** * Encodes the simple value to its raw CBOR byte representation. * * Returns the CBOR bytes that represent this simple value according to the @@ -1281,24 +1919,45 @@ var CborMap$1 = class { * - `False` encodes as `0xf4` * - `True` encodes as `0xf5` * - `Null` encodes as `0xf6` -* - `Float` values encode according to the IEEE 754 floating point rules, -* using the shortest representation that preserves precision. +* - `Float` values reduce to an integer when whole, otherwise encode in the +* shortest IEEE 754 width that preserves the value. */ const simpleCborData = (simple) => { switch (simple.type) { - case "False": return encodeVarInt(20, MajorType$1.Simple); - case "True": return encodeVarInt(21, MajorType$1.Simple); - case "Null": return encodeVarInt(22, MajorType$1.Simple); + case "False": return encodeVarInt(20, MajorType.Simple); + case "True": return encodeVarInt(21, MajorType.Simple); + case "Null": return encodeVarInt(22, MajorType.Simple); case "Float": return f64CborData(simple.value); } }; +/** +* Compare two Simple values for equality. +* +* Two `Simple` values are equal if they're the same variant. For `Float` +* variants, the contained floating point values are compared for equality, +* with NaN values considered equal to each other. +*/ +const simpleEquals = (a, b) => { + if (a.type !== b.type) return false; + switch (a.type) { + case "False": + case "True": + case "Null": return true; + case "Float": { + if (!isFloat$1(b)) return false; + const v1 = a.value; + const v2 = b.value; + return v1 === v2 || Number.isNaN(v1) && Number.isNaN(v2); + } + } +}; Uint8Array.fromHex; /** * Convert bytes to a lowercase hex string. * * Delegates to the native `Uint8Array.prototype.toHex` where available. */ -const bytesToHex$5 = (bytes) => { +const bytesToHex$2 = (bytes) => { const native = bytes.toHex; if (typeof native === "function") return native.call(bytes); let out = ""; @@ -1338,10 +1997,10 @@ const CBOR_METHODS = { return encodeCbor(this); }, toHex() { - return bytesToHex$5(encodeCbor(this)); + return bytesToHex$2(encodeCbor(this)); }, toString() { - return `Cbor(0x${bytesToHex$5(encodeCbor(this))})`; + return `Cbor(0x${bytesToHex$2(encodeCbor(this))})`; }, [Symbol.toStringTag]: "Cbor", [Symbol.for("nodejs.util.inspect.custom")]() { @@ -1357,29 +2016,77 @@ const CBOR_METHODS = { * * @internal */ -const attachMethods$1 = (obj) => { +const attachMethods = (obj) => { const decorated = Object.create(CBOR_METHODS); return Object.assign(decorated, obj); }; -const CBOR_FALSE = attachMethods$1({ +const CBOR_FALSE = attachMethods({ isCbor: true, - type: MajorType$1.Simple, + type: MajorType.Simple, value: { type: "False" } }); -const CBOR_TRUE = attachMethods$1({ +const CBOR_TRUE = attachMethods({ isCbor: true, - type: MajorType$1.Simple, + type: MajorType.Simple, value: { type: "True" } }); -const CBOR_NULL = attachMethods$1({ +const CBOR_NULL = attachMethods({ isCbor: true, - type: MajorType$1.Simple, + type: MajorType.Simple, value: { type: "Null" } }); -const hasTaggedCbor$1 = (value) => { +/** +* Structural CBOR value equality, the reference's `PartialEq for CBOR` +* (`cbor.rs`): two values are equal when they have the same major type and +* equal contents, compared recursively. +* +* This is not "encode to the same bytes": a float node whose value is whole +* (`Float(2.0)`, reachable through a bare node) encodes as the integer `2` +* but is not equal to the integer node; a text node keeps the string it was +* built from, so a decomposed `"é"` is not equal to the composed one although +* both encode composed. Integers compare by value across `number`/`bigint`; +* tags compare by value only (the carried name is ignored); NaN equals NaN; +* maps compare entry by entry in canonical key order, keys and values both +* structurally. +* +* Use this rather than `===` (which compares JS object references) when +* you need value equality across two `Cbor` instances built independently. +*/ +const cborEquals = (a, b) => { + if (a === b) return true; + switch (a.type) { + case MajorType.Unsigned: return b.type === MajorType.Unsigned && BigInt(a.value) === BigInt(b.value); + case MajorType.Negative: return b.type === MajorType.Negative && BigInt(a.value) === BigInt(b.value); + case MajorType.ByteString: return b.type === MajorType.ByteString && areBytesEqual(a.value, b.value); + case MajorType.Text: return b.type === MajorType.Text && a.value === b.value; + case MajorType.Array: return b.type === MajorType.Array && a.value.length === b.value.length && a.value.every((item, i) => cborEquals(item, b.value[i])); + case MajorType.Map: return b.type === MajorType.Map && mapEquals(a.value, b.value); + case MajorType.Tagged: return b.type === MajorType.Tagged && tagValuesEqual(a.tag, b.tag) && cborEquals(a.value, b.value); + case MajorType.Simple: return b.type === MajorType.Simple && simpleEquals(a.value, b.value); + } +}; +/** +* `PartialEq for Map` (`map.rs`): the same entries in canonical key order, +* each with a structurally equal stored key node and value node. Both maps +* iterate in encoded-key order, so a lockstep walk is exact, and like the +* reference's `BTreeMap` equality it stops at the first mismatch. (The +* reference also compares the stored key bytes; that is implied here, since +* structurally equal key nodes always encode to the same bytes.) +*/ +const mapEquals = (a, b) => { + const n = a.size; + if (n !== b.size) return false; + for (let i = 0; i < n; i++) { + const l = a.entryAt(i); + const r = b.entryAt(i); + if (!cborEquals(l.key, r.key) || !cborEquals(l.value, r.value)) return false; + } + return true; +}; +const hasTaggedCbor = (value) => { return typeof value === "object" && value !== null && "taggedCbor" in value && typeof value.taggedCbor === "function"; }; -const hasToCbor$1 = (value) => { +const hasToCbor = (value) => { return typeof value === "object" && value !== null && "toCbor" in value && typeof value.toCbor === "function"; }; /** @@ -1393,7 +2100,7 @@ const hasToCbor$1 = (value) => { * @example * ```typescript * cbor(42); // integer -* cbor("héllo"); // NFC-normalized text +* cbor("héllo"); // text (NFC-normalized when encoded) * cbor([1, "two", true, null]); // array * cbor(new Map([["k", 1]])); // map (canonical key order) * cbor({ name: "Alice", age: 30 }); // plain object -> map @@ -1415,191 +2122,205 @@ const hasToCbor$1 = (value) => { * - objects implementing `taggedCbor()` but not `toCbor()`: add * `toCbor() { return this.taggedCbor(); }`. */ -const cbor$1 = (value) => { - if (isCbor$1(value) && "toData" in value) return value; - if (isCbor$1(value)) return attachMethods$1(value); +const cbor = (value) => { + if (isCbor(value) && "toData" in value) return value; + if (isCbor(value)) return attachMethods(value); let result; - if (isCborNumber$1(value)) if (typeof value === "number" && Number.isNaN(value)) result = { - isCbor: true, - type: MajorType$1.Simple, - value: { - type: "Float", - value: NaN - } - }; - else if (typeof value === "number" && hasFractionalPart(value)) result = { - isCbor: true, - type: MajorType$1.Simple, - value: { - type: "Float", - value - } - }; - else if (value == Infinity) result = { - isCbor: true, - type: MajorType$1.Simple, - value: { - type: "Float", - value: Infinity - } - }; - else if (value == -Infinity) result = { - isCbor: true, - type: MajorType$1.Simple, - value: { - type: "Float", - value: -Infinity - } - }; - else if (typeof value === "number" && !Number.isSafeInteger(value)) { - const big = BigInt(value); - if (big >= 0n && big <= 18446744073709551615n) result = { + if (isCborNumber(value)) { + if (typeof value === "number" && Number.isNaN(value)) result = { isCbor: true, - type: MajorType$1.Unsigned, - value: big + type: MajorType.Simple, + value: { + type: "Float", + value: NaN + } + }; + else if (typeof value === "number" && hasFractionalPart(value)) result = { + isCbor: true, + type: MajorType.Simple, + value: { + type: "Float", + value + } }; - else if (big < 0n && big >= CBOR_INT_MIN) result = { + else if (value == Infinity) result = { isCbor: true, - type: MajorType$1.Negative, - value: -big - 1n + type: MajorType.Simple, + value: { + type: "Float", + value: Infinity + } }; - else result = { + else if (value == -Infinity) result = { isCbor: true, - type: MajorType$1.Simple, + type: MajorType.Simple, value: { type: "Float", - value + value: -Infinity } }; - } else if (typeof value === "bigint" && (value > 18446744073709551615n || value < CBOR_INT_MIN)) throw CborError$1.outOfRange(); - else if (value < 0) if (typeof value === "bigint") result = { - isCbor: true, - type: MajorType$1.Negative, - value: -value - 1n - }; - else result = { - isCbor: true, - type: MajorType$1.Negative, - value: -value - 1 - }; - else result = { + else if (typeof value === "number" && !Number.isSafeInteger(value)) { + const big = BigInt(value); + if (big >= 0n && big <= 18446744073709551615n) result = { + isCbor: true, + type: MajorType.Unsigned, + value: big + }; + else if (big < 0n && big >= CBOR_INT_MIN) result = { + isCbor: true, + type: MajorType.Negative, + value: -big - 1n + }; + else result = { + isCbor: true, + type: MajorType.Simple, + value: { + type: "Float", + value + } + }; + } else if (typeof value === "bigint" && (value > 18446744073709551615n || value < CBOR_INT_MIN)) throw CborError.outOfRange(); + else if (value < 0) { + if (typeof value === "bigint") result = { + isCbor: true, + type: MajorType.Negative, + value: -value - 1n + }; + else result = { + isCbor: true, + type: MajorType.Negative, + value: -value - 1 + }; + } else result = { + isCbor: true, + type: MajorType.Unsigned, + value + }; + } else if (typeof value === "string") result = { isCbor: true, - type: MajorType$1.Unsigned, + type: MajorType.Text, value }; - else if (typeof value === "string") { - const normalized = value.normalize("NFC"); - result = { - isCbor: true, - type: MajorType$1.Text, - value: normalized - }; - } else if (value === null || value === void 0) return CBOR_NULL; + else if (value === null || value === void 0) return CBOR_NULL; else if (value === true) return CBOR_TRUE; else if (value === false) return CBOR_FALSE; else if (Array.isArray(value)) result = { isCbor: true, - type: MajorType$1.Array, - value: value.map(cbor$1) + type: MajorType.Array, + value: value.map(cbor) }; else if (value instanceof Uint8Array) result = { isCbor: true, - type: MajorType$1.ByteString, + type: MajorType.ByteString, value }; - else if (value instanceof CborMap$1) result = { + else if (value instanceof CborMap) result = { isCbor: true, - type: MajorType$1.Map, + type: MajorType.Map, value }; else if (value instanceof Map) result = { isCbor: true, - type: MajorType$1.Map, - value: new CborMap$1(value) + type: MajorType.Map, + value: new CborMap(value) }; else if (value instanceof Set) result = { isCbor: true, - type: MajorType$1.Array, - value: Array.from(value).map(cbor$1) + type: MajorType.Array, + value: Array.from(value).map(cbor) }; - else if (hasToCbor$1(value)) return value.toCbor(); - else if (hasTaggedCbor$1(value)) throw CborError$1.custom("objects implementing taggedCbor() are no longer auto-wrapped by cbor(); implement toCbor() (e.g. `toCbor() { return this.taggedCbor(); }`)"); + else if (hasToCbor(value)) return value.toCbor(); + else if (hasTaggedCbor(value)) throw CborError.custom("objects implementing taggedCbor() are not auto-wrapped by cbor(); implement toCbor() (e.g. `toCbor() { return this.taggedCbor(); }`)"); else if (typeof value === "object" && "tag" in value && "value" in value) { const keys = Object.keys(value); - if (keys.length === 2 && keys.includes("tag") && keys.includes("value")) throw CborError$1.custom("plain { tag, value } objects are ambiguous and no longer encode as tagged values; use taggedValue(tag, content) for a tagged value, or add/rename a key to encode a map"); - const map = new CborMap$1(); - for (const [key, val] of Object.entries(value)) map.set(cbor$1(key), cbor$1(val)); + if (keys.length === 2 && keys.includes("tag") && keys.includes("value")) throw CborError.custom("plain { tag, value } objects are ambiguous and do not encode as tagged values; use taggedValue(tag, content) for a tagged value, or add/rename a key to encode a map"); + const map = new CborMap(); + for (const [key, val] of Object.entries(value)) map.set(cbor(key), cbor(val)); result = { isCbor: true, - type: MajorType$1.Map, + type: MajorType.Map, value: map }; } else if (typeof value === "object") { - const map = new CborMap$1(); - for (const [key, val] of Object.entries(value)) map.set(cbor$1(key), cbor$1(val)); + const map = new CborMap(); + for (const [key, val] of Object.entries(value)) map.set(cbor(key), cbor(val)); result = { isCbor: true, - type: MajorType$1.Map, + type: MajorType.Map, value: map }; - } else throw CborError$1.custom("Unsupported type for CBOR encoding"); - return attachMethods$1(result); + } else throw CborError.custom("Unsupported type for CBOR encoding"); + return attachMethods(result); +}; +const textEncoder$1 = new TextEncoder(); +/** +* dCBOR requires every encoded text string to be in Unicode Normalization +* Form C. Like the reference (`cbor.rs`: `x.nfc().collect()` inside +* `cbor_data`), normalization happens here at encode time, so the node keeps +* the string it was built from. Strings whose code units are all below U+0300 +* (the first combining mark) contain nothing that can compose or decompose +* and are already NFC; skipping `normalize` for them keeps the ASCII/Latin-1 +* hot path allocation-free. +*/ +const toNfc = (text) => { + for (let i = 0; i < text.length; i++) if (text.charCodeAt(i) >= 768) return text.normalize("NFC"); + return text; }; -const textEncoder = new TextEncoder(); /** * Write a CBOR value into `writer`. The whole tree encodes into one growable * buffer, so nested containers don't allocate-and-concatenate a fresh array * per level. */ const writeCborInto = (writer, value) => { - const c = cbor$1(value); + const c = cbor(value); switch (c.type) { - case MajorType$1.Unsigned: - writeVarInt(writer, c.value, MajorType$1.Unsigned); + case MajorType.Unsigned: + writeVarInt(writer, c.value, MajorType.Unsigned); return; - case MajorType$1.Negative: - writeVarInt(writer, c.value, MajorType$1.Negative); + case MajorType.Negative: + writeVarInt(writer, c.value, MajorType.Negative); return; - case MajorType$1.ByteString: + case MajorType.ByteString: if (c.value instanceof Uint8Array) { - writeVarInt(writer, c.value.length, MajorType$1.ByteString); + writeVarInt(writer, c.value.length, MajorType.ByteString); writer.writeBytes(c.value); return; } break; - case MajorType$1.Text: + case MajorType.Text: if (typeof c.value === "string") { - const utf8Bytes = textEncoder.encode(c.value); - writeVarInt(writer, utf8Bytes.length, MajorType$1.Text); + const utf8Bytes = textEncoder$1.encode(toNfc(c.value)); + writeVarInt(writer, utf8Bytes.length, MajorType.Text); writer.writeBytes(utf8Bytes); return; } break; - case MajorType$1.Tagged: + case MajorType.Tagged: if (typeof c.tag === "bigint" || typeof c.tag === "number") { - writeVarInt(writer, c.tag, MajorType$1.Tagged); + writeVarInt(writer, c.tag, MajorType.Tagged); writeCborInto(writer, c.value); return; } break; - case MajorType$1.Simple: + case MajorType.Simple: writer.writeBytes(simpleCborData(c.value)); return; - case MajorType$1.Array: - writeVarInt(writer, c.value.length, MajorType$1.Array); + case MajorType.Array: + writeVarInt(writer, c.value.length, MajorType.Array); for (const item of c.value) writeCborInto(writer, item); return; - case MajorType$1.Map: { - const entries = c.value.entriesArray; - writeVarInt(writer, entries.length, MajorType$1.Map); - for (const { key, value: entryValue } of entries) { - writeCborInto(writer, key); - writeCborInto(writer, entryValue); + case MajorType.Map: { + const map = c.value; + const n = map.size; + writeVarInt(writer, n, MajorType.Map); + for (let i = 0; i < n; i++) { + writer.writeBytes(map.encodedKeyAt(i)); + writeCborInto(writer, map.entryAt(i).value); } return; } } - throw CborError$1.wrongType(); + throw CborError.wrongType(); }; /** * Encode a value to deterministic CBOR bytes. Accepts anything `cbor()` @@ -1618,11 +2339,11 @@ const writeCborInto = (writer, value) => { * @public */ const encodeCbor = (value) => { - const c = cbor$1(value); + const c = cbor(value); switch (c.type) { - case MajorType$1.Unsigned: return encodeVarInt(c.value, MajorType$1.Unsigned); - case MajorType$1.Negative: return encodeVarInt(c.value, MajorType$1.Negative); - case MajorType$1.Simple: return simpleCborData(c.value); + case MajorType.Unsigned: return encodeVarInt(c.value, MajorType.Unsigned); + case MajorType.Negative: return encodeVarInt(c.value, MajorType.Negative); + case MajorType.Simple: return simpleCborData(c.value); default: { const writer = new BufWriter(); writeCborInto(writer, c); @@ -1631,7 +2352,7 @@ const encodeCbor = (value) => { } }; /** -* Construct a tagged value - the ONLY explicit tagged-value constructor. +* Construct a tagged value - the only explicit tagged-value constructor. * * @example * ```typescript @@ -1639,18 +2360,34 @@ const encodeCbor = (value) => { * taggedValue(Tag.from(32), "https://example.com/"); // URI, tag 32 * ``` * -* @param tag - The tag number (`number | bigint`) or a `Tag` object (its -* `.value` is used; names never reach the wire). +* @param tag - The tag number (`number | bigint`) or a `Tag` object. Its +* `.value` goes on the wire; a `.name` is kept on the node (see +* `CborTaggedType.tagName`) so a `WrongTag` error can name the tag that +* was found, as the reference does. * @param content - Anything `cbor()` accepts. * @public */ const taggedValue = (tag, content) => { - const tagVal = typeof tag === "object" && "value" in tag ? tag.value : tag; - return attachMethods$1({ + if (typeof tag === "object" && "value" in tag) { + if (tag.name !== void 0) return attachMethods({ + isCbor: true, + type: MajorType.Tagged, + tag: tag.value, + tagName: tag.name, + value: cbor(content) + }); + return attachMethods({ + isCbor: true, + type: MajorType.Tagged, + tag: tag.value, + value: cbor(content) + }); + } + return attachMethods({ isCbor: true, - type: MajorType$1.Tagged, - tag: tagVal, - value: cbor$1(content) + type: MajorType.Tagged, + tag, + value: cbor(content) }); }; /** @@ -1658,7 +2395,7 @@ const taggedValue = (tag, content) => { * * Stores tags with their names and optional summarizer functions. */ -var TagsStore$1 = class { +var TagsStore = class TagsStore { /** Debug label: `Object.prototype.toString` reports `[object TagsStore]`. */ get [Symbol.toStringTag]() { return "TagsStore"; @@ -1674,8 +2411,14 @@ var TagsStore$1 = class { * - Throws if a tag with the same value exists with a different name * - Allows re-registering the same tag value with the same name * + * The store holds frozen tags, as the reference stores clones it owns: a + * frozen argument (every `Tag.from` result) is kept by identity, an + * unfrozen object literal is copied, so later mutation of the caller's + * object never changes a lookup. + * * @param tag - The tag to register (must have a non-empty name) - * @throws Error if tag has no name, empty name, or conflicts with existing registration + * @throws {CborError} `Custom` if the tag has no name, an empty name, or + * conflicts with an existing registration * * @example * ```typescript @@ -1685,21 +2428,39 @@ var TagsStore$1 = class { */ register(tag) { const name = tag.name; - if (name === void 0 || name === "") throw new Error(`Tag ${tag.value} must have a non-empty name`); + if (name === void 0 || name === "") throw CborError.custom(`Tag ${tag.value} must have a non-empty name`); const key = this._valueKey(tag.value); const existing = this._tagsByValue.get(key); - if (existing?.name !== void 0 && existing.name !== name) throw new Error(`Attempt to register tag: ${tag.value} '${existing.name}' with different name: '${name}'`); - this._tagsByValue.set(key, tag); - this._tagsByName.set(name, tag); + if (existing?.name !== void 0 && existing.name !== name) throw CborError.custom(`Attempt to register tag: ${tag.value} '${existing.name}' with different name: '${name}'`); + const stored = Object.isFrozen(tag) ? tag : Tag.from(tag.value, name); + this._tagsByValue.set(key, stored); + this._tagsByName.set(name, stored); } /** * Register multiple tags; the conflict-throwing validation in `register()` - * applies per tag. + * applies per tag. Accepts any iterable, including a `readonly` array. */ registerAll(tags) { for (const tag of tags) this.register(tag); } /** + * An independent copy of this store (the reference's `#[derive(Clone)]` + * on `TagsStore`). + * + * The clone holds the same frozen tags by identity and shares the + * summarizer functions, as the reference's `Arc` summarizers are shared. + * Registering a tag or setting a summarizer on either store leaves the + * other unchanged. The clone is a plain store; it never replaces the + * global store. + */ + clone() { + const copy = new TagsStore(); + for (const [key, tag] of this._tagsByValue) copy._tagsByValue.set(key, tag); + for (const [name, tag] of this._tagsByName) copy._tagsByName.set(name, tag); + for (const [key, summarizer] of this._summarizers) copy._summarizers.set(key, summarizer); + return copy; + } + /** * Register a custom summarizer function for a tag. * * @param tagValue - The numeric tag value @@ -1707,10 +2468,10 @@ var TagsStore$1 = class { * * @example * ```typescript - * store.setSummarizer(1, (cbor, flat) => { - * // Custom date formatting - * return `Date(${extractCbor(cbor)})`; - * }); + * store.setSummarizer(1, (cbor, flat) => ({ + * ok: true, + * value: `Date(${extractCbor(cbor)})`, + * })); * ``` */ setSummarizer(tagValue, summarizer) { @@ -1739,24 +2500,25 @@ var TagsStore$1 = class { const key = this._valueKey(tag); return this._summarizers.get(key); } - /** - * Create a string key for a numeric tag value. - * Handles both number and bigint types. - * - * @private - */ + /** Map key for a tag value, equal for a `number` and the same `bigint`. */ _valueKey(value) { return value.toString(); } }; /** -* Global singleton instance of the tags store. +* The slot the global store lives in. It is keyed on `globalThis` by a +* registered symbol rather than held in a module variable so that every copy +* of this module in a process - the ESM and CommonJS builds, or two bundled +* copies - resolves the SAME store, the way the reference's `GLOBAL_TAGS` +* static is one per process. The `@1` names the store's major version; bump +* it on a breaking `TagsStore` change so incompatible copies do not share. */ -let globalTagsStore$1; +const GLOBAL_TAGS_KEY = Symbol.for("@blockchaincommons/dcbor/global-tags-store@1"); /** * Get the global tags store instance. * -* Creates the instance on first access. +* Creates the instance on first access. One store per process for dcbor +* 1.x, shared by the ESM and CommonJS builds (see `GLOBAL_TAGS_KEY`). * * @returns The global TagsStore instance * @@ -1766,14 +2528,11 @@ let globalTagsStore$1; * store.register(Tag.from(999, 'myTag')); * ``` */ -const getGlobalTagsStore$1 = () => { - globalTagsStore$1 ??= new TagsStore$1(); - return globalTagsStore$1; -}; +const getGlobalTagsStore = () => globalThis[GLOBAL_TAGS_KEY] ??= new TagsStore(); //#endregion -//#region tests/baseline/node_modules/@blockchaincommons/dcbor/dist/index.mjs +//#region ../bc-dcbor-ts/dist/index.mjs /** -* Helper function to validate that a CBOR value has one of the expected tags. +* Validate that a CBOR value has one of the expected tags. * * @param cbor - CBOR value to validate * @param expectedTags - Array of valid tags @@ -1781,64 +2540,161 @@ const getGlobalTagsStore$1 = () => { * @throws {CborError} `WrongType` if the value is not tagged; `WrongTag` if * the tag matches none of `expectedTags`. */ -const validateTag$1 = (cbor, expectedTags) => { - if (cbor.type !== MajorType$1.Tagged) throw CborError$1.wrongType(); +const validateTag = (cbor, expectedTags) => { + if (cbor.type !== MajorType.Tagged) throw CborError.wrongType(); const tagValue = cbor.tag; - const matchingTag = expectedTags.find((t) => tagValuesEqual$1(t.value, tagValue)); - if (matchingTag === void 0) throw CborError$1.wrongTag(expectedTags[0], { value: tagValue }); + const matchingTag = expectedTags.find((t) => tagValuesEqual(t.value, tagValue)); + if (matchingTag === void 0) throw CborError.wrongTag(expectedTags[0], Tag.from(tagValue, cbor.tagName)); return matchingTag; }; /** -* Helper function to extract the content from a tagged CBOR value. +* Extract the content from a tagged CBOR value. * * @param cbor - Tagged CBOR value * @returns The untagged content * @throws {CborError} `WrongType` if the value is not tagged. */ -const extractTaggedContent$1 = (cbor) => { - if (cbor.type !== MajorType$1.Tagged) throw CborError$1.wrongType(); +const extractTaggedContent = (cbor) => { + if (cbor.type !== MajorType.Tagged) throw CborError.wrongType(); return cbor.value; }; /** -* Normalize a timestamp (seconds since the Unix epoch) to whole seconds plus a -* non-negative, sub-second nanosecond part, so dates round-trip byte-identically. -* -* The nanosecond part is truncated toward zero and clamped to [0, u32::MAX]. So -* a negative fraction floors the value (`-1.5` becomes `-1.0`) and sub-nanosecond -* precision is dropped (`1.0000000005` becomes `1.0`). +* The reference's representable range: chrono's `NaiveDateTime::MIN` +* (−262143-01-01T00:00:00) and `MAX` (262142-12-31T23:59:59.999999999) as +* Unix seconds. Beyond it `Date::from_timestamp` panics (`timestamp_opt(…) +* .unwrap()`); here it is `InvalidDate`. JS `Date` reaches further (±8.64e12 +* s), so `toDate()` can represent every accepted value. +*/ +const MIN_TIMESTAMP_SECONDS = -8334601228800; +const MAX_TIMESTAMP_SECONDS = 8210266876799; +/** `f64::exact_from_u64`: the magnitude as a number, or `OutOfRange` when inexact. */ +function exactNumber(magnitude) { + const n = Number(magnitude); + if (!Number.isFinite(n) || BigInt(n) !== magnitude) throw CborError.outOfRange(); + return n; +} +/** chrono's `NaiveDate` year range (`MIN_YEAR` / `MAX_YEAR`). */ +const MIN_YEAR = -262143; +const MAX_YEAR = 262142; +const isLeapYear = (year) => year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0); +const DAYS_IN_MONTH = [ + 31, + 28, + 31, + 30, + 31, + 30, + 31, + 31, + 30, + 31, + 30, + 31 +]; +const daysInMonth$1 = (year, month) => month === 2 && isLeapYear(year) ? 29 : DAYS_IN_MONTH[month - 1] ?? 0; +/** +* Days since 1970-01-01 of a proleptic-Gregorian civil date (the components +* must already be valid). Pure integer arithmetic, as chrono computes it: JS +* `Date.UTC` would map years 0–99 to 1900–1999. +*/ +function daysFromCivil(year, month, day) { + const y = month <= 2 ? year - 1 : year; + const era = Math.floor(y / 400); + const yoe = y - era * 400; + const doy = Math.floor((153 * (month + (month > 2 ? -3 : 9)) + 2) / 5) + day - 1; + const doe = yoe * 365 + Math.floor(yoe / 4) - Math.floor(yoe / 100) + doy; + return era * 146097 + doe - 719468; +} +/** The civil date of a day count since 1970-01-01 (inverse of `daysFromCivil`). */ +function civilFromDays(days) { + const z = days + 719468; + const era = Math.floor(z / 146097); + const doe = z - era * 146097; + const yoe = Math.floor((doe - Math.floor(doe / 1460) + Math.floor(doe / 36524) - Math.floor(doe / 146096)) / 365); + const doy = doe - (365 * yoe + Math.floor(yoe / 4) - Math.floor(yoe / 100)); + const mp = Math.floor((5 * doy + 2) / 153); + const day = doy - Math.floor((153 * mp + 2) / 5) + 1; + const month = mp < 10 ? mp + 3 : mp - 9; + return [ + yoe + era * 400 + (month <= 2 ? 1 : 0), + month, + day + ]; +} +/** +* Whole seconds since the Unix epoch of the given UTC components, or +* `undefined` when they are not a valid date-time. The checks are chrono's +* (`NaiveDate::from_ymd_opt`, `NaiveTime::from_hms_opt`): the year within +* −262143…+262142, a calendar-valid month and day, and `hh:mm:ss` within 23:59:59. +*/ +function civilSeconds(year, month, day, hour, minute, second) { + if (![ + year, + month, + day, + hour, + minute, + second + ].every(Number.isInteger)) return void 0; + if (year < MIN_YEAR || year > MAX_YEAR) return void 0; + if (month < 1 || month > 12 || day < 1 || day > daysInMonth$1(year, month)) return void 0; + if (hour < 0 || hour > 23 || minute < 0 || minute > 59 || second < 0 || second > 59) return; + return daysFromCivil(year, month, day) * 86400 + hour * 3600 + minute * 60 + second; +} +/** Rust's `char::is_whitespace` (Unicode `White_Space`), as a character class. */ +const WHITESPACE = "[\\t\\n\\v\\f\\r \\u0085\\u00a0\\u1680\\u2000-\\u200a\\u2028\\u2029\\u202f\\u205f\\u3000]"; +/** +* chrono's fixed-layout RFC 3339 grammar (`DateTime::parse_from_rfc3339`): +* `YYYY-MM-DD`, a `T`/`t`/space separator, `hh:mm:ss`, an optional fraction +* of which the first nine digits count, then `Z`/`z` or `±hh:mm` (U+2212 is +* accepted as the minus sign). Nothing may follow. +*/ +const RFC3339 = /^(\d{4})-(\d{2})-(\d{2})[Tt ](\d{2}):(\d{2}):(\d{2})(?:\.(\d{1,9})\d*)?(?:[Zz]|([+\-\u2212])(\d{2}):(\d{2}))$/; +/** +* chrono's strftime `%Y-%m-%d` (`NaiveDate::parse_from_str`): each number may +* be preceded by whitespace; `%Y` is one to four digits, or a sign followed by +* any number of digits; `%m` and `%d` are one or two digits; nothing may +* follow. +*/ +const YMD = new RegExp(`^${WHITESPACE}*(?:([+-])(\\d+)|(\\d{1,4}))-${WHITESPACE}*(\\d{1,2})-${WHITESPACE}*(\\d{1,2})$`); +/** +* Split a timestamp (seconds since the Unix epoch) into the (whole seconds, +* nanoseconds) pair the reference's `Date::from_timestamp` builds: +* +* - `trunc() as i64` for the seconds - NaN saturates to 0 (the epoch); +* ±Infinity saturates to the `i64` bounds, which chrono rejects and the +* reference then panics on, so here it is `InvalidDate`; +* - `(fract() * 1e9) as u32` for the nanoseconds - truncated toward zero and +* saturated to `[0, u32::MAX]`, so a negative fraction is dropped (`-1.5` +* becomes `-1`) and sub-nanosecond precision is lost; +* - `timestamp_opt(...)` then requires the whole seconds inside chrono's +* range (the fraction does not take part, so `MIN - 0.5` is `MIN`). * * @internal */ -function normalizeTimestampSeconds(seconds) { - if (!Number.isFinite(seconds)) throw CborError$1.invalidDate("non-finite timestamp"); +function timestampParts(seconds) { + if (Number.isNaN(seconds)) return [0, 0]; + if (!Number.isFinite(seconds)) throw CborError.invalidDate("non-finite timestamp"); const whole = Math.trunc(seconds); - let nsecs = Math.trunc((seconds - whole) * 1e9); - if (nsecs < 0) nsecs = 0; - else if (nsecs > 4294967295) nsecs = 4294967295; - return whole + nsecs / 1e9; + if (whole < MIN_TIMESTAMP_SECONDS || whole > MAX_TIMESTAMP_SECONDS) throw CborError.invalidDate("timestamp outside the representable range"); + let nanoseconds = Math.trunc((seconds - whole) * 1e9); + if (nanoseconds < 0) nanoseconds = 0; + else if (nanoseconds > 4294967295) nanoseconds = 4294967295; + return [whole, nanoseconds]; } +let dateCodec; /** -* A CBOR-friendly representation of a date and time. +* A UTC date and time, encoded as CBOR tag 1 (RFC 8949 epoch-based +* date/time). * -* The `CborDate` type provides a wrapper around JavaScript's native `Date` that -* supports encoding and decoding to/from CBOR with tag 1, following the CBOR -* date/time standard specified in RFC 8949. -* -* When encoded to CBOR, dates are represented as tag 1 followed by a numeric -* value representing the number of seconds since (or before) the Unix epoch -* (1970-01-01T00:00:00Z). The numeric value can be a positive or negative -* integer, or a floating-point value for dates with fractional seconds. -* -* # Features -* -* - Supports UTC dates with optional fractional seconds -* - Provides convenient constructors for common date creation patterns -* - Implements the `CborTagged` interface and the `ToCbor` protocol -* - Supports arithmetic operations with durations and between dates +* The instant is held as whole seconds since the Unix epoch plus nanoseconds. +* On the wire it is tag 1 followed by the seconds since (or before) +* 1970-01-01T00:00:00Z: an integer for whole seconds, a float otherwise. +* Implements the `CborTagged` interface and the `ToCbor` protocol. * * @example * ```typescript -* import { CborDate } from './date'; +* import { CborDate } from "@blockchaincommons/dcbor"; * * // Create a date from a timestamp (seconds since Unix epoch) * const date = CborDate.fromEpochSeconds(1675854714.0); @@ -1853,34 +2709,32 @@ function normalizeTimestampSeconds(seconds) { * const decoded = CborDate.fromTaggedCbor(cborValue); * ``` */ -let dateCodec; -var CborDate$1 = class CborDate { +var CborDate = class CborDate { /** Debug label: `Object.prototype.toString` reports `[object CborDate]`. */ get [Symbol.toStringTag]() { return "CborDate"; } /** - * Canonical timestamp in seconds since the Unix epoch as a JS `number` - * (`f64`). dCBOR encodes Date (tag 1) as a numeric value in seconds, so - * keeping `_seconds` as the source of truth avoids the millisecond-only - * round-trip precision loss that going through a JS `Date` instance would - * introduce. - * - * f64 bounds the achievable precision (~16 decimal digits, so roughly - * microseconds for current epoch values), but the encode/decode round-trip - * is byte-identical. + * The instant as the reference's `chrono::DateTime` holds it: whole + * seconds since the Unix epoch plus a nanosecond part in + * `[0, 1_999_999_999]` (values from 10⁹ up represent a leap second, e.g. + * `23:59:60`, as chrono does). Keeping the pair rather than one `f64` + * means display, equality and ordering see exactly what the reference + * sees; the wire value is derived from it as `timestamp()` does. */ _seconds; + _nanoseconds; /** * Creates a new `CborDate` from the given JavaScript `Date`. * - * This method creates a new `CborDate` instance by wrapping a - * JavaScript `Date`. - * - * @param dateTime - A `Date` instance to wrap + * @param dateTime - A `Date` instance * * @returns A new `CborDate` instance * + * @throws `InvalidDate` for an invalid `Date` (`NaN` time) or one outside + * the reference's representable range (years −262143 to 262142), which a chrono + * value handed to `Date::from_datetime` can never be. + * * @example * ```typescript * const datetime = new Date(); @@ -1888,14 +2742,15 @@ var CborDate$1 = class CborDate { * ``` */ static fromDate(dateTime) { - const instance = new CborDate(); - instance._seconds = dateTime.getTime() / 1e3; - return instance; + const ms = dateTime.getTime(); + if (!Number.isFinite(ms)) throw CborError.invalidDate("non-finite timestamp"); + const whole = Math.floor(ms / 1e3); + if (whole < MIN_TIMESTAMP_SECONDS || whole > MAX_TIMESTAMP_SECONDS) throw CborError.invalidDate("timestamp outside the representable range"); + return new CborDate(whole, (ms - whole * 1e3) * 1e6); } /** - * Creates a new `CborDate` from year, month, and day components. - * - * This method creates a new `CborDate` with the time set to 00:00:00 UTC. + * Creates a new `CborDate` from year, month, and day components, at + * 00:00:00 UTC. * * @param year - The year component (e.g., 2023) * @param month - The month component (1-12) @@ -1909,11 +2764,11 @@ var CborDate$1 = class CborDate { * const date = CborDate.fromYmd(2023, 2, 8); * ``` * - * @throws Error if the provided components do not form a valid date. + * @throws `InvalidDate` if the components do not form a valid date (the + * reference panics there). */ static fromYmd(year, month, day) { - const dt = new Date(Date.UTC(year, month - 1, day, 0, 0, 0, 0)); - return CborDate.fromDate(dt); + return CborDate.fromYmdHms(year, month, day, 0, 0, 0); } /** * Creates a new `CborDate` from year, month, day, hour, minute, and second @@ -1934,18 +2789,25 @@ var CborDate$1 = class CborDate { * const date = CborDate.fromYmdHms(2023, 2, 8, 15, 30, 45); * ``` * - * @throws Error if the provided components do not form a valid date and time. + * @throws `InvalidDate` if the components do not form a valid date and time + * — the checks the reference's `with_ymd_and_hms(…).unwrap()` panics on: + * a year outside −262143…+262142, an impossible month or day, or a time past + * 23:59:59 (no leap second here; `fromString` accepts `:60`). */ static fromYmdHms(year, month, day, hour, minute, second) { - const dt = new Date(Date.UTC(year, month - 1, day, hour, minute, second, 0)); - return CborDate.fromDate(dt); + const seconds = civilSeconds(year, month, day, hour, minute, second); + if (seconds === void 0) throw CborError.invalidDate("Invalid date components"); + return new CborDate(seconds, 0); } /** - * Creates a new `CborDate` from seconds since (or before) the Unix epoch. + * Creates a new `CborDate` from seconds since the Unix epoch + * (1970-01-01T00:00:00Z); negative values are before the epoch. * - * This method creates a new `CborDate` representing the specified number of - * seconds since the Unix epoch (1970-01-01T00:00:00Z). Negative values - * represent times before the epoch. + * The value is split as the reference's `from_timestamp` splits it: whole + * seconds by truncation toward zero, then the fraction in nanoseconds + * (truncated, never negative), so `-1.5` is the instant `-1` and + * `1.0000000001` is `1`. `NaN` is the epoch, as the reference's saturating + * cast makes it. * * @param secondsSinceUnixEpoch - Seconds from the Unix epoch (positive or * negative), which can include a fractional part for sub-second @@ -1953,6 +2815,10 @@ var CborDate$1 = class CborDate { * * @returns A new `CborDate` instance * + * @throws `InvalidDate` for ±Infinity, or when the whole seconds fall + * outside the reference's representable range (years −262143 to 262142), + * where the reference panics. + * * @example * ```typescript * // Create a date from a timestamp @@ -1966,25 +2832,37 @@ var CborDate$1 = class CborDate { * ``` */ static fromEpochSeconds(secondsSinceUnixEpoch) { - const instance = new CborDate(); - instance._seconds = normalizeTimestampSeconds(secondsSinceUnixEpoch); - return instance; + const [seconds, nanoseconds] = timestampParts(secondsSinceUnixEpoch); + return new CborDate(seconds, nanoseconds); } /** * Creates a new `CborDate` from a string containing an ISO-8601 (RFC-3339) * date (with or without time). * - * This method parses a string representation of a date or date-time in - * ISO-8601/RFC-3339 format and creates a new `CborDate` instance. It - * supports both full date-time strings (e.g., "2023-02-08T15:30:45Z") - * and date-only strings (e.g., "2023-02-08"). + * Accepts exactly what the reference's `Date::from_string` accepts: + * + * - An RFC 3339 date-time (`2023-02-08T15:30:45Z`, `…45.123456789+05:30`), + * with `T`, `t` or a space between date and time, up to nine fraction + * digits kept (further digits are ignored), `Z`/`z` or an offset within + * ±23:59, and the `:60` leap second (read as second 59 plus one second, + * as chrono represents it). + * - A bare date read as UTC midnight, in chrono's `%Y-%m-%d` form: one to + * four year digits or a signed year of any length (`-0001-01-01`, + * `+12023-02-08`), one- or two-digit month and day, with whitespace + * allowed before each number (`2023-2-8`, ` 2023-02-08`). + * + * The fraction is kept exactly as nanoseconds, so a decimal fraction + * encodes to the same bytes on both sides (`timestamp()`: whole seconds + * plus nanoseconds over 10⁹) and a leap second still displays as `:60`. * * @param value - A string containing a date or date-time in ISO-8601/RFC-3339 * format * * @returns A new `CborDate` instance if parsing succeeds * - * @throws Error if the string cannot be parsed as a valid date or date-time + * @throws `InvalidDate` if the string cannot be parsed as a valid date or + * date-time (an impossible calendar date, a time past `23:59:60`, an + * offset beyond ±23:59, a missing offset, or trailing characters). * * @example * ```typescript @@ -1996,17 +2874,32 @@ var CborDate$1 = class CborDate { * ``` */ static fromString(value) { - const invalidDate = CborError$1.invalidDate("Invalid date string"); - const rfc3339 = /^\d{4}-\d{2}-\d{2}[Tt]\d{2}:\d{2}:\d{2}(\.\d+)?([Zz]|[+-]\d{2}:\d{2})$/; - const dateOnly = /^\d{4}-\d{2}-\d{2}$/; - let parsed; - if (rfc3339.test(value)) parsed = new Date(value); - else if (dateOnly.test(value)) parsed = /* @__PURE__ */ new Date(`${value}T00:00:00Z`); - else throw invalidDate; - const [y, m, d] = value.slice(0, 10).split("-").map(Number); - const probe = new Date(Date.UTC(y, m - 1, d)); - if (!(probe.getUTCFullYear() === y && probe.getUTCMonth() === m - 1 && probe.getUTCDate() === d) || isNaN(parsed.getTime())) throw invalidDate; - return CborDate.fromDate(parsed); + const invalidDate = () => CborError.invalidDate("Invalid date string"); + const dt = RFC3339.exec(value); + if (dt !== null) { + const [, y, mo, d, h, mi, sec, frac = "", sign, oh, om] = dt; + let second = Number(sec); + let nanoseconds = frac === "" ? 0 : Number(frac.padEnd(9, "0")); + if (second === 60) { + second = 59; + nanoseconds += 1e9; + } + const offsetHours = sign === void 0 ? 0 : Number(oh); + const offsetMinutes = sign === void 0 ? 0 : Number(om); + if (offsetHours > 23 || offsetMinutes > 59) throw invalidDate(); + const offset = (sign === "+" ? 1 : -1) * (offsetHours * 3600 + offsetMinutes * 60); + const whole = civilSeconds(Number(y), Number(mo), Number(d), Number(h), Number(mi), second); + if (whole === void 0) throw invalidDate(); + return new CborDate(whole - offset, nanoseconds); + } + const ymd = YMD.exec(value); + if (ymd !== null) { + const [, sign, signedYear, plainYear, mo, d] = ymd; + const whole = civilSeconds(sign === void 0 ? Number(plainYear) : Number(`${sign}${signedYear}`), Number(mo), Number(d), 0, 0, 0); + if (whole === void 0) throw invalidDate(); + return new CborDate(whole, 0); + } + throw invalidDate(); } /** * Creates a new `CborDate` containing the current date and time. @@ -2041,12 +2934,10 @@ var CborDate$1 = class CborDate { return CborDate.fromDate(future); } /** - * Returns the underlying JavaScript `Date` object. + * Returns a new JavaScript `Date` for this instant (millisecond precision; + * sub-millisecond digits are lost). * - * This method provides access to the wrapped JavaScript `Date` - * instance. - * - * @returns The wrapped `Date` instance + * @returns A new `Date` instance * * @example * ```typescript @@ -2056,7 +2947,7 @@ var CborDate$1 = class CborDate { * ``` */ toDate() { - return /* @__PURE__ */ new Date(this._seconds * 1e3); + return /* @__PURE__ */ new Date(this.epochSeconds * 1e3); } /** * The date as the number of seconds since the Unix epoch @@ -2064,6 +2955,9 @@ var CborDate$1 = class CborDate { * represent times before the epoch; the fractional part is sub-second * precision. * + * This is the reference's `timestamp()`: whole seconds plus nanoseconds + * over 10⁹, computed in `f64`, and it is the value that goes on the wire. + * * @example * ```typescript * const date = CborDate.fromYmd(2023, 2, 8); @@ -2071,7 +2965,7 @@ var CborDate$1 = class CborDate { * ``` */ get epochSeconds() { - return this._seconds; + return this._seconds + this._nanoseconds / 1e9; } /** * Add seconds to this date. @@ -2121,16 +3015,17 @@ var CborDate$1 = class CborDate { return this.epochSeconds - other.epochSeconds; } /** - * Implementation of the `CborTagged` interface for `CborDate`. + * The CBOR tags for `CborDate`: tag 1, the RFC 8949 epoch-based date/time. * - * This implementation specifies that `CborDate` values are tagged with CBOR tag 1, - * which is the standard CBOR tag for date/time values represented as seconds - * since the Unix epoch per RFC 8949. + * The tag carries whatever name the global tags store has for 1 at the + * time of the call (`tags_for_values` in the reference): `date` once + * `registerStandardTags()` has run, otherwise none. That name is what a + * `WrongTag` error prints as the expected tag. * - * @returns A vector containing tag 1 + * @returns An array containing tag 1 */ cborTags() { - return [Tag.from(1, "date")]; + return [getGlobalTagsStore().tagForValue(1) ?? Tag.from(1)]; } /** * Converts this `CborDate` to its untagged CBOR content: the epoch-seconds @@ -2140,7 +3035,7 @@ var CborDate$1 = class CborDate { * @returns A CBOR value representing the timestamp */ untaggedCbor() { - return cbor$1(this.epochSeconds); + return cbor(this.epochSeconds); } /** * Converts this `CborDate` to a tagged CBOR value with tag 1. @@ -2149,7 +3044,7 @@ var CborDate$1 = class CborDate { */ taggedCbor() { const tag = this.cborTags()[0]; - if (tag === void 0) throw CborError$1.custom("No tags defined for this type"); + if (tag === void 0) throw CborError.custom("No tags defined for this type"); return taggedValue(tag, this.untaggedCbor()); } /** @@ -2159,48 +3054,52 @@ var CborDate$1 = class CborDate { return this.taggedCbor(); } /** - * Populates this `CborDate` in place from an untagged CBOR value, which - * must be a number (integer or floating-point) of seconds since the Unix - * epoch. The static `CborDate.fromUntaggedCbor` is the usual entry point; - * this instance form exists for reuse. + * Creates a `CborDate` from an untagged CBOR value, which must be a number + * (integer or floating-point) of seconds since the Unix epoch. The static + * `CborDate.fromUntaggedCbor` is the usual entry point; this instance form + * exists for the `CborTagged` protocol and returns a new instance. * * @param cbor - The untagged CBOR value * - * @returns this (populated in place) + * @returns The decoded date * - * @throws Error if the CBOR value is not a valid timestamp + * @throws `WrongType` for a non-numeric value, `OutOfRange` for an integer + * `f64` cannot hold exactly, `InvalidDate` beyond the representable + * range. A float `NaN` is the epoch, as in the reference. */ fromUntaggedCbor(cbor) { let timestamp; switch (cbor.type) { - case MajorType$1.Unsigned: - timestamp = typeof cbor.value === "number" ? cbor.value : Number(cbor.value); + case MajorType.Unsigned: + timestamp = typeof cbor.value === "number" ? cbor.value : exactNumber(cbor.value); break; - case MajorType$1.Negative: - if (typeof cbor.value === "bigint") timestamp = Number(-cbor.value - 1n); + case MajorType.Negative: + if (typeof cbor.value === "bigint") timestamp = -exactNumber(cbor.value) - 1; else timestamp = -cbor.value - 1; break; - case MajorType$1.Simple: + case MajorType.Simple: if (cbor.value.type === "Float") timestamp = cbor.value.value; - else throw CborError$1.wrongType(); + else throw CborError.wrongType(); break; - default: throw CborError$1.wrongType(); + default: throw CborError.wrongType(); } - this._seconds = normalizeTimestampSeconds(timestamp); - return this; + return CborDate.fromEpochSeconds(timestamp); } /** - * Populates this `CborDate` in place from a tag-1 CBOR value. + * Creates a `CborDate` from a tag-1 CBOR value (the `CborTagged` + * protocol's instance form; returns a new instance). * * @param cbor - Tagged CBOR value * - * @returns this (populated in place) + * @returns The decoded date * - * @throws Error if the CBOR value has the wrong tag or cannot be decoded + * @throws {CborError} `WrongType` if the value is not tagged, `WrongTag` + * for a tag other than 1, or what `fromUntaggedCbor` throws for the content */ fromTaggedCbor(cbor) { - validateTag$1(cbor, this.cborTags()); - const content = extractTaggedContent$1(cbor); + const expectedTags = this.cborTags(); + validateTag(cbor, expectedTags); + const content = extractTaggedContent(cbor); return this.fromUntaggedCbor(content); } /** @@ -2210,7 +3109,7 @@ var CborDate$1 = class CborDate { * @returns New CborDate instance */ static fromTaggedCbor(cbor) { - return new CborDate().fromTaggedCbor(cbor); + return CborDate.EPOCH.fromTaggedCbor(cbor); } /** * The {@link CborCodec} exemplar: a runtime witness that binds @@ -2223,21 +3122,22 @@ var CborDate$1 = class CborDate { */ static get codec() { dateCodec ??= { - tags: [Tag.from(1, "date")], + get tags() { + return CborDate.EPOCH.cborTags(); + }, decode: (c) => CborDate.fromTaggedCbor(c), encode: (value) => value.taggedCbor() }; return dateCodec; } static fromUntaggedCbor(cbor) { - return new CborDate().fromUntaggedCbor(cbor); + return CborDate.EPOCH.fromUntaggedCbor(cbor); } + /** 1970-01-01T00:00:00Z: the receiver for the protocol's instance decoders. */ + static EPOCH = new CborDate(0, 0); /** - * Implementation of the `toString` method for `CborDate`. - * - * This implementation provides a string representation of a `CborDate` in ISO-8601 - * format. For dates with time exactly at midnight (00:00:00), only the date - * part is shown. For other times, a full date-time string is shown. + * The date in ISO-8601 format: only the date part when the time is exactly + * midnight (00:00:00), otherwise a date-time to the second with `Z`. * * @returns String representation in ISO-8601 format * @@ -2250,36 +3150,46 @@ var CborDate$1 = class CborDate { * * // A date with time will display as date and time * const date2 = CborDate.fromYmdHms(2023, 2, 8, 15, 30, 45); - * // Returns "2023-02-08T15:30:45.000Z" + * // Returns "2023-02-08T15:30:45Z" * console.log(date2.toString()); * ``` */ toString() { - const dt = /* @__PURE__ */ new Date(this._seconds * 1e3); - if (!(dt.getUTCHours() !== 0 || dt.getUTCMinutes() !== 0 || dt.getUTCSeconds() !== 0)) { - const datePart = dt.toISOString().split("T")[0]; - if (datePart === void 0) throw CborError$1.custom("Invalid ISO string format"); - return datePart; - } else return dt.toISOString().replace(/\.\d{3}Z$/, "Z"); - } - /** - * Compare two dates for equality. + const total = this._seconds; + const days = Math.floor(total / 86400); + const secondOfDay = total - days * 86400; + const [year, month, day] = civilFromDays(days); + const pad = (n, width = 2) => String(n).padStart(width, "0"); + const date = `${year >= 0 && year <= 9999 ? pad(year, 4) : `${year < 0 ? "-" : "+"}${pad(Math.abs(year), 4)}`}-${pad(month)}-${pad(day)}`; + if (secondOfDay === 0) return date; + const hour = Math.floor(secondOfDay / 3600); + const minute = Math.floor(secondOfDay % 3600 / 60); + const second = secondOfDay % 60 + (this._nanoseconds >= 1e9 ? 1 : 0); + return `${date}T${pad(hour)}:${pad(minute)}:${pad(second)}Z`; + } + /** + * Compare two dates for equality: the same whole seconds and the same + * nanoseconds (chrono's `PartialEq`). A leap second `23:59:60` is a + * different instant from the following `00:00:00`, although both encode + * to the same wire value. * * @param other - Other CborDate to compare * @returns true if dates represent the same moment in time */ equals(other) { - return this._seconds === other._seconds; + return this._seconds === other._seconds && this._nanoseconds === other._nanoseconds; } /** - * Compare two dates. + * Compare two dates: by whole seconds, then by nanoseconds (chrono's + * `Ord`, so a leap second sorts after `:59.999999999` and before the next + * `:00`). * * @param other - Other CborDate to compare * @returns -1 if this < other, 0 if equal, 1 if this > other */ compare(other) { - if (this._seconds < other._seconds) return -1; - if (this._seconds > other._seconds) return 1; + if (this._seconds !== other._seconds) return this._seconds < other._seconds ? -1 : 1; + if (this._nanoseconds !== other._nanoseconds) return this._nanoseconds < other._nanoseconds ? -1 : 1; return 0; } /** @@ -2290,8 +3200,9 @@ var CborDate$1 = class CborDate { toJSON() { return this.toString(); } - constructor() { - this._seconds = Date.now() / 1e3; + constructor(seconds, nanoseconds) { + this._seconds = seconds; + this._nanoseconds = nanoseconds; } }; /** @@ -2306,13 +3217,13 @@ var CborDate$1 = class CborDate { * * @param bytes - The magnitude byte string to validate * @param isNegative - Whether this is for a negative bignum (tag 3) -* @throws CborError with type NonCanonicalNumeric on validation failure +* @throws {CborError} `NonCanonicalNumeric` on validation failure */ function validateBignumMagnitude(bytes, isNegative) { if (isNegative) { - if (bytes.length === 0) throw CborError$1.nonCanonicalNumeric(); - if (bytes.length > 1 && bytes[0] === 0) throw CborError$1.nonCanonicalNumeric(); - } else if (bytes.length > 0 && bytes[0] === 0) throw CborError$1.nonCanonicalNumeric(); + if (bytes.length === 0) throw CborError.nonCanonicalNumeric(); + if (bytes.length > 1 && bytes[0] === 0) throw CborError.nonCanonicalNumeric(); + } else if (bytes.length > 0 && bytes[0] === 0) throw CborError.nonCanonicalNumeric(); } /** * Convert a big-endian byte array to a bigint. @@ -2322,7 +3233,7 @@ function validateBignumMagnitude(bytes, isNegative) { * @param bytes - Big-endian byte representation * @returns The bigint value */ -function bytesToBigint$1(bytes) { +function bytesToBigint$2(bytes) { if (bytes.length === 0) return 0n; let result = 0n; for (const byte of bytes) result = result << 8n | BigInt(byte); @@ -2339,14 +3250,14 @@ function bytesToBigint$1(bytes) { * * @param cbor - A CBOR value that should be a byte string * @returns Non-negative bigint -* @throws CborError with type WrongType if not a byte string -* @throws CborError with type NonCanonicalNumeric if encoding is non-canonical +* @throws {CborError} `WrongType` if not a byte string +* @throws {CborError} `NonCanonicalNumeric` if encoding is non-canonical */ -function biguintFromUntaggedCbor$1(cbor) { - if (cbor.type !== MajorType$1.ByteString) throw CborError$1.wrongType(); +function biguintFromUntaggedCbor(cbor) { + if (cbor.type !== MajorType.ByteString) throw CborError.wrongType(); const bytes = cbor.value; validateBignumMagnitude(bytes, false); - return bytesToBigint$1(bytes); + return bytesToBigint$2(bytes); } /** * Decode a BigInt from an untagged CBOR byte string for a negative bignum. @@ -2360,63069 +3271,35470 @@ function biguintFromUntaggedCbor$1(cbor) { * * @param cbor - A CBOR value that should be a byte string * @returns Negative bigint -* @throws CborError with type WrongType if not a byte string -* @throws CborError with type NonCanonicalNumeric if encoding is non-canonical +* @throws {CborError} `WrongType` if not a byte string +* @throws {CborError} `NonCanonicalNumeric` if encoding is non-canonical */ -function bigintFromNegativeUntaggedCbor$1(cbor) { - if (cbor.type !== MajorType$1.ByteString) throw CborError$1.wrongType(); +function bigintFromNegativeUntaggedCbor(cbor) { + if (cbor.type !== MajorType.ByteString) throw CborError.wrongType(); const bytes = cbor.value; validateBignumMagnitude(bytes, true); - return -(bytesToBigint$1(bytes) + 1n); + return -(bytesToBigint$2(bytes) + 1n); } -//#endregion -//#region tests/baseline/node_modules/@blockchaincommons/dcbor/dist/diag-BpAWXEUJ.mjs /** -* String utilities for dCBOR, including Unicode normalization. -* -* @module string-util +* Name for tag 2 (positive bignum). */ +const TAG_NAME_POSITIVE_BIGNUM = "positive-bignum"; /** -* Flank a string with left and right strings. -* -* @param s - String to flank -* @param left - Left flanking string -* @param right - Right flanking string -* @returns Flanked string +* Name for tag 3 (negative bignum). */ -const flanked$1 = (s, left, right) => left + s + right; +const TAG_NAME_NEGATIVE_BIGNUM = "negative-bignum"; /** -* Check if a character is printable. Internal helper for {@link sanitized}. -* -* @param c - Character to check -* @returns True if printable +* Name for tag 1 (date). */ -const isPrintable = (c) => { - if (c.length !== 1) return false; - const code = c.charCodeAt(0); - return code > 127 || code >= 32 && code <= 126; -}; +const TAG_NAME_DATE = "date"; /** -* Sanitize a string by replacing non-printable characters with dots. -* Returns None if the string has no printable characters. -* -* @param str - String to sanitize -* @returns Sanitized string or undefined if no printable characters -*/ -const sanitized = (str) => { - let hasPrintable = false; - const chars = []; - for (const c of str) if (isPrintable(c)) { - hasPrintable = true; - chars.push(c); - } else chars.push("."); - if (!hasPrintable) return; - return chars.join(""); -}; -const resolveOpts = (opts) => { - const summarize = opts?.summarize ?? false; - return { - annotate: opts?.annotate ?? false, - summarize, - flat: summarize || (opts?.flat ?? false), - tags: opts?.tags ?? "global" - }; +* Register the standard tags (date, and the bignums with `bignum`) and their +* summarizers into `store`. +* +* Re-registering is idempotent and moves each standard name back to its +* standard value, as the reference's `insert_all` does: a store that had +* named tag 99 `date` names tag 1 `date` afterwards. Registering tag 1 (or +* 2/3 with `bignum`) under a different name throws `CborError` `Custom` +* from the store's conflict validation, before any summarizer is set. +* +* @param store - Target store; defaults to the global tags store. +*/ +const registerStandardTags = (store = getGlobalTagsStore(), options = {}) => { + const bignum = options.bignum ?? false; + const tagsStore = store; + tagsStore.registerAll([Tag.from(1, TAG_NAME_DATE)]); + tagsStore.setSummarizer(1, (untaggedCbor, _flat) => { + try { + return { + ok: true, + value: CborDate.fromUntaggedCbor(untaggedCbor).toString() + }; + } catch (e) { + const message = e instanceof Error ? e.message : String(e); + return { + ok: false, + error: CborError.custom(message) + }; + } + }); + if (!bignum) return; + tagsStore.registerAll([Tag.from(2, TAG_NAME_POSITIVE_BIGNUM), Tag.from(3, TAG_NAME_NEGATIVE_BIGNUM)]); + tagsStore.setSummarizer(2, (untaggedCbor, _flat) => { + try { + return { + ok: true, + value: `bignum(${biguintFromUntaggedCbor(untaggedCbor)})` + }; + } catch (e) { + const message = e instanceof Error ? e.message : String(e); + return { + ok: false, + error: CborError.custom(message) + }; + } + }); + tagsStore.setSummarizer(3, (untaggedCbor, _flat) => { + try { + return { + ok: true, + value: `bignum(${bigintFromNegativeUntaggedCbor(untaggedCbor)})` + }; + } catch (e) { + const message = e instanceof Error ? e.message : String(e); + return { + ok: false, + error: CborError.custom(message) + }; + } + }); }; /** -* Format a CBOR value - or a walk visitor's `WalkElement` - as CBOR -* diagnostic notation. +* Resolve tag values through the global tags store. A value the store does +* not know becomes an unnamed `Tag`. * +* @example * ```typescript -* diagnostic(value); // pretty-printed -* diagnostic(value, { flat: true }); // single line -* diagnostic(value, { annotate: true }); // tag names as annotations -* diagnostic(value, { summarize: true }); // registered summarizers (implies flat) +* registerStandardTags(); +* const tags = tagsForValues([1, 42]); +* tags[0].name; // "date" +* tags[1].name; // undefined * ``` -* -* @param input - CBOR value, or a `WalkElement` from a walk visitor -* @param opts - Formatting options (explicit `undefined` fields mean -* "use the default") -* @public */ -function diagnostic$1(input, opts) { - const state = resolveOpts(opts); - if (typeof input === "object" && "type" in input && (input.type === "single" || input.type === "keyvalue")) { - if (input.type === "single") return diagFormat(diagItem(input.cbor, state), state); - return `${diagFormat(diagItem(input.key, state), state)}: ${diagFormat(diagItem(input.value, state), state)}`; - } - return diagFormat(diagItem(input, state), state); -} -const item = (value) => ({ - kind: "item", - value -}); -const group = (begin, end, items, isPairs, comment) => { - const g = { - kind: "group", - begin, - end, - items, - isPairs - }; - if (comment !== void 0) g.comment = comment; - return g; +const tagsForValues = (values) => { + const globalStore = getGlobalTagsStore(); + return values.map((value) => { + const tag = globalStore.tagForValue(value); + if (tag !== void 0) return tag; + return Tag.from(value); + }); }; -const isGroup = (i) => i.kind === "group"; -const containsGroup = (i) => i.kind === "group" && i.items.some(isGroup); -const totalStringsLen = (i) => i.kind === "item" ? i.value.length : i.items.reduce((acc, c) => acc + totalStringsLen(c), 0); -const greatestStringsLen = (i) => i.kind === "item" ? i.value.length : i.items.reduce((acc, c) => Math.max(acc, totalStringsLen(c)), 0); /** -* Alternates between `pairSeparator` (after even-indexed items - keys) and -* `itemSeparator` (after odd-indexed items - values). Falls back to -* `itemSeparator` for non-pair groups. +* Check if CBOR value is an unsigned integer. +* +* @param cbor - CBOR value to check +* @returns True if value is unsigned integer +* +* @example +* ```typescript +* if (isUnsigned(value)) { +* console.log('Unsigned:', value.value); +* } +* ``` */ -function joined(elements, itemSeparator, pairSeparator) { - const sep = pairSeparator ?? itemSeparator; - let result = ""; - const len = elements.length; - for (let i = 0; i < len; i++) { - result += elements[i]; - if (i !== len - 1) result += (i & 1) !== 0 ? itemSeparator : sep; - } - return result; -} -const diagFormat = (i, opts) => diagFormatOpt(i, 0, "", opts); -function diagFormatOpt(i, level, separator, opts) { - if (i.kind === "item") return formatLine(level, opts, i.value, separator, void 0); - if (opts.flat !== true && (containsGroup(i) || totalStringsLen(i) > 20 || greatestStringsLen(i) > 20)) return multilineComposition(i, level, separator, opts); - return singleLineComposition(i, level, separator, opts); -} -function formatLine(level, opts, string, separator, comment) { - const result = `${opts.flat === true ? "" : " ".repeat(level * 4)}${string}${separator}`; - if (comment !== void 0) return `${result} / ${comment} /`; - return result; -} -function singleLineComposition(i, level, separator, opts) { - let str; - let comment; - if (i.kind === "item") { - str = i.value; - comment = void 0; - } else { - str = flanked$1(joined(i.items.map((c) => c.kind === "item" ? c.value : singleLineComposition(c, level + 1, separator, opts)), ", ", i.isPairs ? ": " : ", "), i.begin, i.end); - comment = i.comment; - } - return formatLine(level, opts, str, separator, comment); -} -function multilineComposition(i, level, separator, opts) { - if (i.kind === "item") return i.value; - const lines = []; - const openOpts = { - ...opts, - flat: false - }; - lines.push(formatLine(level, openOpts, i.begin, "", i.comment)); - for (let idx = 0; idx < i.items.length; idx++) { - const sep = idx === i.items.length - 1 ? "" : i.isPairs && (idx & 1) === 0 ? ":" : ","; - lines.push(diagFormatOpt(i.items[idx], level + 1, sep, opts)); - } - lines.push(formatLine(level, opts, i.end, separator, void 0)); - return lines.join("\n"); -} -function diagItem(cbor, opts) { - switch (cbor.type) { - case MajorType$1.Unsigned: return item(formatUnsigned(cbor.value)); - case MajorType$1.Negative: return item(formatNegative(cbor.value)); - case MajorType$1.ByteString: return item(formatBytes(cbor.value)); - case MajorType$1.Text: return item(formatText(cbor.value)); - case MajorType$1.Array: return item_array(cbor.value, opts); - case MajorType$1.Map: return item_map(cbor.value, opts); - case MajorType$1.Tagged: return item_tagged(cbor.tag, cbor.value, opts); - case MajorType$1.Simple: return item(formatSimple(cbor.value)); - } -} -function item_array(items, opts) { - return group("[", "]", items.map((it) => diagItem(it, opts)), false); -} -function item_map(map, opts) { - const entries = map?.entriesArray ?? []; - const flatItems = []; - for (const e of entries) { - flatItems.push(diagItem(e.key, opts)); - flatItems.push(diagItem(e.value, opts)); - } - return group("{", "}", flatItems, true); -} -function item_tagged(tag, content, opts) { - if (opts.summarize === true) { - const summarizer = resolveTagsStore(opts.tags)?.summarizer(tag); - if (summarizer !== void 0) { - const result = summarizer(content, opts.flat ?? false); - if (result.ok) return item(result.value); - return item(``); - } - } - let comment; - if (opts.annotate === true) { - const store = resolveTagsStore(opts.tags); - const tagObj = { value: tag }; - const assignedName = store?.assignedNameForTag(tagObj); - if (assignedName !== void 0) comment = assignedName; - } - return group(`${String(tag)}(`, ")", [diagItem(content, opts)], false, comment); -} -function formatUnsigned(value) { - return String(value); -} -function formatNegative(value) { - if (typeof value === "bigint") return String(-value - 1n); - return String(-value - 1); -} -function formatBytes(value) { - return `h'${bytesToHex$5(value)}'`; -} -function formatText(value) { - return `"${value.replace(/"/g, "\\\"")}"`; -} -function formatSimple(value) { - switch (value.type) { - case "True": return "true"; - case "False": return "false"; - case "Null": return "null"; - case "Float": return formatFloat(value.value); - } -} +const isUnsigned = (cbor) => { + return cbor.type === MajorType.Unsigned; +}; /** -* Format a CBOR float for diagnostic output. Shared with the hex-dump -* annotation path; see {@link floatDisplayString}. +* Check if CBOR value is a negative integer. +* +* @param cbor - CBOR value to check +* @returns True if value is negative integer */ -function formatFloat(value) { - return floatDisplayString(value); -} -function resolveTagsStore(tags) { - if (tags === "none") return void 0; - if (tags === "global" || tags === void 0) return getGlobalTagsStore$1(); - return tags; -} -//#endregion -//#region tests/baseline/node_modules/@blockchaincommons/dcbor/dist/diagnostic.mjs +const isNegative = (cbor) => { + return cbor.type === MajorType.Negative; +}; /** -* Hex dump utilities for CBOR data. -* -* Affordances for viewing the encoded binary representation of CBOR as hexadecimal. -* Optionally annotates the output, breaking it up into semantically meaningful lines, -* formatting dates, and adding names of known tags. +* Check if CBOR value is a byte string. * -* @module dump +* @param cbor - CBOR value to check +* @returns True if value is byte string */ +const isBytes$7 = (cbor) => { + return cbor.type === MajorType.ByteString; +}; /** -* Render CBOR as an annotated hex dump: the encoding broken into -* semantically meaningful lines with offsets, values, and tag names -* resolved through the tags store. -* -* For plain hex use `c.toHex()` or `bytesToHex(encodeCbor(v))`. +* Check if CBOR value is a text string. * -* @param cbor - CBOR value to render -* @param opts - Formatting options (explicit `undefined` fields mean -* "use the default") +* @param cbor - CBOR value to check +* @returns True if value is text string */ -const hexAnnotated = (cbor, opts) => { - const items = dumpItems(cbor, 0, opts?.tagsStore ?? getGlobalTagsStore$1()); - const roundedNoteColumn = (items.reduce((largest, item) => { - return Math.max(largest, item.formatFirstColumn().length); - }, 0) + 4 & -4) - 1; - return items.map((item) => item.format(roundedNoteColumn)).join("\n"); +const isText = (cbor) => { + return cbor.type === MajorType.Text; }; /** -* Internal structure for dump items. +* Check if CBOR value is an array. +* +* @param cbor - CBOR value to check +* @returns True if value is array */ -var DumpItem = class { - level; - data; - note; - constructor(level, data, note) { - this.level = level; - this.data = data; - this.note = note; - } - format(noteColumn) { - const column1 = this.formatFirstColumn(); - let column2 = ""; - let padding = ""; - if (this.note !== void 0) { - const paddingCount = Math.max(1, Math.min(39, noteColumn) - column1.length + 1); - padding = " ".repeat(paddingCount); - column2 = `# ${this.note}`; - } - return column1 + padding + column2; - } - formatFirstColumn() { - return " ".repeat(this.level * 4) + this.data.map(bytesToHex$5).filter((x) => x.length > 0).join(" "); - } +const isArray = (cbor) => { + return cbor.type === MajorType.Array; }; /** -* Generate dump items for a CBOR value (recursive). +* Check if CBOR value is a map. +* +* @param cbor - CBOR value to check +* @returns True if value is map */ -function dumpItems(cbor, level, tagsStore) { - const items = []; - switch (cbor.type) { - case MajorType$1.Unsigned: { - const data = encodeCbor(cbor); - items.push(new DumpItem(level, [data], `unsigned(${cbor.value})`)); - break; - } - case MajorType$1.Negative: { - const data = encodeCbor(cbor); - const actualValue = typeof cbor.value === "bigint" ? -1n - cbor.value : -1 - cbor.value; - items.push(new DumpItem(level, [data], `negative(${actualValue})`)); - break; - } - case MajorType$1.ByteString: { - const header = encodeVarInt(cbor.value.length, MajorType$1.ByteString); - items.push(new DumpItem(level, [header], `bytes(${cbor.value.length})`)); - if (cbor.value.length > 0) { - let note = void 0; - try { - const sanitizedText = sanitized(new TextDecoder("utf-8", { fatal: true }).decode(cbor.value)); - if (sanitizedText !== void 0 && sanitizedText !== "") note = flanked$1(sanitizedText, "\"", "\""); - } catch {} - items.push(new DumpItem(level + 1, [cbor.value], note)); - } - break; - } - case MajorType$1.Text: { - const utf8Data = new TextEncoder().encode(cbor.value); - const header = encodeVarInt(utf8Data.length, MajorType$1.Text); - const firstByte = header[0]; - if (firstByte === void 0) throw CborError$1.custom("Invalid varint encoding"); - const headerData = [new Uint8Array([firstByte]), header.slice(1)]; - items.push(new DumpItem(level, headerData, `text(${utf8Data.length})`)); - items.push(new DumpItem(level + 1, [utf8Data], flanked$1(cbor.value, "\"", "\""))); - break; - } - case MajorType$1.Array: { - const header = encodeVarInt(cbor.value.length, MajorType$1.Array); - const firstByte = header[0]; - if (firstByte === void 0) throw CborError$1.custom("Invalid varint encoding"); - const headerData = [new Uint8Array([firstByte]), header.slice(1)]; - items.push(new DumpItem(level, headerData, `array(${cbor.value.length})`)); - for (const item of cbor.value) items.push(...dumpItems(item, level + 1, tagsStore)); - break; - } - case MajorType$1.Map: { - const header = encodeVarInt(cbor.value.size, MajorType$1.Map); - const firstByte = header[0]; - if (firstByte === void 0) throw CborError$1.custom("Invalid varint encoding"); - const headerData = [new Uint8Array([firstByte]), header.slice(1)]; - items.push(new DumpItem(level, headerData, `map(${cbor.value.size})`)); - for (const entry of cbor.value.entriesArray) { - items.push(...dumpItems(entry.key, level + 1, tagsStore)); - items.push(...dumpItems(entry.value, level + 1, tagsStore)); - } - break; - } - case MajorType$1.Tagged: { - const tagValue = cbor.tag; - if (tagValue === void 0) throw CborError$1.custom("Tagged CBOR value must have a tag"); - const header = encodeVarInt(tagValue, MajorType$1.Tagged); - const firstByte = header[0]; - if (firstByte === void 0) throw CborError$1.custom("Invalid varint encoding"); - const headerData = [new Uint8Array([firstByte]), header.slice(1)]; - const noteComponents = [`tag(${tagValue})`]; - const tag = Tag.from(tagValue); - const tagName = tagsStore.assignedNameForTag(tag); - if (tagName !== void 0) noteComponents.push(tagName); - const tagNote = noteComponents.join(" "); - items.push(new DumpItem(level, headerData, tagNote)); - items.push(...dumpItems(cbor.value, level + 1, tagsStore)); - break; - } - case MajorType$1.Simple: { - const data = encodeCbor(cbor); - const simple = cbor.value; - let note; - if (simple.type === "True") note = "true"; - else if (simple.type === "False") note = "false"; - else if (simple.type === "Null") note = "null"; - else if (simple.type === "Float") note = floatDisplayString(simple.value); - else note = "simple"; - items.push(new DumpItem(level, [data], note)); - break; - } - } - return items; -} -//#endregion -//#region tests/baseline/node_modules/@bcts/dcbor/dist/index.mjs +const isMap = (cbor) => { + return cbor.type === MajorType.Map; +}; /** -* Create a new Tag. -* -* @param value - The numeric tag value -* @param name - Optional human-readable name -* @returns A new Tag object +* Check if CBOR value is tagged. * -* @example -* ```typescript -* const dateTag = createTag(1, 'date'); -* const customTag = createTag(12345, 'myCustomTag'); -* ``` +* @param cbor - CBOR value to check +* @returns True if value is tagged */ -const createTag = (value, name) => { - if (name !== void 0) return { - value, - name - }; - return { value }; +const isTagged = (cbor) => { + return cbor.type === MajorType.Tagged; }; /** -* Compare two tag values for equality, normalizing `number` vs `bigint`. -* A raw `===` would treat `100n` and `100` as unequal, so a large tag that -* decoded to a `bigint` wouldn't match the same value written as a `number`. +* Check if CBOR value is a simple value. +* +* @param cbor - CBOR value to check +* @returns True if value is simple */ -const tagValuesEqual = (a, b) => { - if (typeof a === "bigint" || typeof b === "bigint") return BigInt(a) === BigInt(b); - return a === b; +const isSimple = (cbor) => { + return cbor.type === MajorType.Simple; }; /** -* Get the string representation of a tag. -* Internal function used for error messages. -* -* @param tag - The tag to represent -* @returns String representation (name if available, otherwise value) +* Check if CBOR value is null. * -* @internal +* @param cbor - CBOR value to check +* @returns True if value is null */ -const tagToString = (tag) => tag.name ?? tag.value.toString(); -/** -* Convert an Error to a display string. -* -* Matches Rust's `Display` trait / `to_string()` method. -*/ -const errorToString = (error) => { - switch (error.type) { - case "Underrun": return "early end of CBOR data"; - case "UnsupportedHeaderValue": return "unsupported value in CBOR header"; - case "NonCanonicalNumeric": return "a CBOR numeric value was encoded in non-canonical form"; - case "InvalidSimpleValue": return "an invalid CBOR simple value was encountered"; - case "InvalidString": return `an invalidly-encoded UTF-8 string was encountered in the CBOR (${error.message})`; - case "NonCanonicalString": return "a CBOR string was not encoded in Unicode Canonical Normalization Form C"; - case "UnusedData": return `the decoded CBOR had ${error.count} extra bytes at the end`; - case "MisorderedMapKey": return "the decoded CBOR map has keys that are not in canonical order"; - case "DuplicateMapKey": return "the decoded CBOR map has a duplicate key"; - case "MissingMapKey": return "missing CBOR map key"; - case "OutOfRange": return "the CBOR numeric value could not be represented in the specified numeric type"; - case "WrongType": return "the decoded CBOR value was not the expected type"; - case "WrongTag": return `expected CBOR tag ${tagToString(error.expected)}, but got ${tagToString(error.actual)}`; - case "InvalidUtf8": return `invalid UTF‑8 string: ${error.message}`; - case "InvalidDate": return `invalid ISO 8601 date string: ${error.message}`; - case "Custom": return error.message; - } +const isNull = (cbor) => { + if (cbor.type !== MajorType.Simple) return false; + return cbor.value.type === "Null"; }; /** -* Typed error class for all CBOR-related errors. +* Check if CBOR value is a float (f16, f32, or f64). * -* Wraps the discriminated union Error type in a JavaScript Error object -* for proper error handling with stack traces. -* -* @example -* ```typescript -* throw new CborError({ type: 'Underrun' }); -* throw new CborError({ type: 'WrongTag', expected: tag1, actual: tag2 }); -* ``` +* @param cbor - CBOR value to check +* @returns True if value is float */ -var CborError = class CborError extends Error { - /** - * The structured error information. - */ - errorType; - /** - * Create a new CborError. - * - * @param errorType - The discriminated union error type - * @param message - Optional custom message (defaults to errorToString(errorType)) - */ - constructor(errorType, message) { - super(message ?? errorToString(errorType)); - this.name = "CborError"; - this.errorType = errorType; - if ("captureStackTrace" in Error) Error.captureStackTrace(this, CborError); - } - /** - * Check if an error is a CborError. - * - * @param error - Error to check - * @returns True if error is a CborError - */ - static isCborError(error) { - return error instanceof CborError; - } +const isFloat = (cbor) => { + if (cbor.type !== MajorType.Simple) return false; + return isFloat$1(cbor.value); }; /** -* Convert a legacy node into a canonical `@blockchaincommons/dcbor` node. +* Check if CBOR value is any numeric type (unsigned, negative, or float). * -* Leaves are shared, not copied: the canonical functions never mutate their -* inputs. Map nodes unwrap to the inner canonical `CborMap`, so later -* mutations through the legacy wrapper stay visible. -*/ -const toNew = (c) => { - switch (c.type) { - case MajorType.Array: return { - isCbor: true, - type: MajorType.Array, - value: c.value.map(toNew) - }; - case MajorType.Map: return { - isCbor: true, - type: MajorType.Map, - value: c.value._inner - }; - case MajorType.Tagged: return { - isCbor: true, - type: MajorType.Tagged, - tag: c.tag, - value: toNew(c.value) - }; - default: return { - isCbor: true, - type: c.type, - value: c.value - }; - } -}; -/** -* Convert a canonical node into a legacy node with the legacy method set. -* Map nodes wrap the canonical `CborMap` without copying entries. +* @param cbor - CBOR value +* @returns True if value is numeric */ -const fromNew = (n) => { - switch (n.type) { - case MajorType.Array: return attachMethods({ - isCbor: true, - type: MajorType.Array, - value: n.value.map(fromNew) - }); - case MajorType.Map: return attachMethods({ - isCbor: true, - type: MajorType.Map, - value: CborMap._fromInner(n.value) - }); - case MajorType.Tagged: return attachMethods({ - isCbor: true, - type: MajorType.Tagged, - tag: n.tag, - value: fromNew(n.value) - }); - default: return attachMethods({ - isCbor: true, - type: n.type, - value: n.value - }); - } +const isNumber = (cbor) => { + if (cbor.type === MajorType.Unsigned || cbor.type === MajorType.Negative) return true; + if (cbor.type === MajorType.Simple) return isFloat$1(cbor.value); + return false; }; /** -* Translate a canonical `CborError` (code + details) back into the legacy -* discriminated-union `CborError`. Non-CborError values are re-thrown as-is. +* Extract unsigned integer value if type matches. +* +* @param cbor - CBOR value +* @returns Unsigned integer or undefined */ -const toLegacyError = (e) => { - if (!CborError$1.isCborError(e)) { - if (e instanceof CborError) return e; - throw e; - } - const details = e.details; - let errorType; - switch (e.code) { - case "UnsupportedHeaderValue": - errorType = { - type: "UnsupportedHeaderValue", - value: details["headerValue"] - }; - break; - case "UnusedData": - errorType = { - type: "UnusedData", - count: details["count"] - }; - break; - case "WrongTag": - errorType = { - type: "WrongTag", - expected: details["expectedTag"], - actual: details["actualTag"] - }; - break; - case "InvalidString": - errorType = { - type: "InvalidString", - message: details["cause"] ?? e.message - }; - break; - case "InvalidUtf8": - errorType = { - type: "InvalidUtf8", - message: details["cause"] ?? e.message - }; - break; - case "InvalidDate": - errorType = { - type: "InvalidDate", - message: details["cause"] ?? e.message - }; - break; - case "Custom": - errorType = { - type: "Custom", - message: e.message - }; - break; - default: errorType = { type: e.code }; - } - return new CborError(errorType); -}; -/** Run a canonical-package operation, translating thrown errors. */ -const delegating = (op) => { - try { - return op(); - } catch (e) { - throw toLegacyError(e); - } +const asUnsigned = (cbor) => { + if (cbor.type === MajorType.Unsigned) return cbor.value; }; /** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -* -* Tag registry and management system. -* -* The TagsStore provides a centralized registry for CBOR tags, -* including name resolution and custom summarizer functions. +* Extract byte string value if type matches. * -* The store wraps the `@blockchaincommons/dcbor` `TagsStore` — and the -* global singleton wraps the canonical package's *global* store — so tag -* names and summarizers registered through this legacy API are visible to -* the delegated diagnostic/hex formatters (and vice versa). +* Decoded byte strings are zero-copy views aliasing the input buffer - +* mutating the input after decoding (or mutating the returned bytes) changes +* the other side. Call `.slice()` first if you need an independent copy. * -* @module tags-store +* @param cbor - CBOR value +* @returns Byte string or undefined */ +const asBytes = (cbor) => { + if (cbor.type === MajorType.ByteString) return cbor.value; +}; /** -* Convert a canonical tag (whose `name` may be explicitly `undefined`) to the -* legacy `Tag` shape, which omits the property instead. +* Extract text string value if type matches. +* +* @param cbor - CBOR value +* @returns Text string or undefined */ -const toLegacyTag = (tag) => { - if (tag === void 0) return void 0; - return tag.name !== void 0 ? { - value: tag.value, - name: tag.name - } : { value: tag.value }; +const asText = (cbor) => { + if (cbor.type === MajorType.Text) return cbor.value; }; /** -* Tag registry implementation. +* Extract array value if type matches. * -* Stores tags with their names and optional summarizer functions, delegating -* storage to the canonical `@blockchaincommons/dcbor` store. +* @param cbor - CBOR value +* @returns Array or undefined */ -var TagsStore = class TagsStore { - _store; - /** Original (legacy-signature) summarizers, for the `summarizer()` accessor. */ - _legacySummarizers = /* @__PURE__ */ new Map(); - constructor() { - this._store = new TagsStore$1(); - } - /** - * The wrapped canonical `@blockchaincommons/dcbor` store. - * @internal - */ - get _inner() { - return this._store; - } - /** - * Wrap an existing canonical store without copying registrations. - * @internal - */ - static _fromInner(inner) { - const store = new TagsStore(); - store._store = inner; - return store; - } - /** - * Insert a tag into the registry. - * - * Matches Rust's TagsStore::insert() behavior: - * - Throws if the tag name is undefined or empty - * - Throws if a tag with the same value exists with a different name - * - Allows re-registering the same tag value with the same name - * - * @param tag - The tag to register (must have a non-empty name) - * @throws Error if tag has no name, empty name, or conflicts with existing registration - * - * @example - * ```typescript - * const store = new TagsStore(); - * store.insert(createTag(12345, 'myCustomTag')); - * ``` - */ - insert(tag) { - const name = tag.name; - if (name === void 0 || name === "") throw new Error(`Tag ${tag.value} must have a non-empty name`); - const existing = this._store.tagForValue(tag.value); - if (existing?.name !== void 0 && existing.name !== name) throw new Error(`Attempt to register tag: ${tag.value} '${existing.name}' with different name: '${name}'`); - this._store.register(Tag.from(tag.value, name)); - } - /** - * Insert multiple tags into the registry. - * Matches Rust's insert_all() method. - * - * @param tags - Array of tags to register - * - * @example - * ```typescript - * const store = new TagsStore(); - * store.insertAll([ - * createTag(1, 'date'), - * createTag(100, 'custom') - * ]); - * ``` - */ - insertAll(tags) { - for (const tag of tags) this.insert(tag); - } - /** - * Register a custom summarizer function for a tag. - * - * The summarizer is adapted and forwarded to the canonical store, so the - * delegated diagnostic formatters invoke it (with a legacy-shaped node). - * - * @param tagValue - The numeric tag value - * @param summarizer - The summarizer function - * - * @example - * ```typescript - * store.setSummarizer(1, (cbor, flat) => { - * // Custom date formatting - * return `Date(${extractCbor(cbor)})`; - * }); - * ``` - */ - setSummarizer(tagValue, summarizer) { - this._legacySummarizers.set(this._valueKey(tagValue), summarizer); - this._store.setSummarizer(tagValue, (cbor, flat) => { - const result = summarizer(fromNew(cbor), flat); - if (result.ok) return result; - return { - ok: false, - error: CborError$1.custom(errorToString(result.error)) - }; - }); - } - assignedNameForTag(tag) { - return this._store.tagForValue(tag.value)?.name; - } - nameForTag(tag) { - return this.assignedNameForTag(tag) ?? tag.value.toString(); - } - tagForValue(value) { - return toLegacyTag(this._store.tagForValue(value)); - } - tagForName(name) { - return toLegacyTag(this._store.tagForName(name)); - } - nameForValue(value) { - const tag = this.tagForValue(value); - return tag !== void 0 ? this.nameForTag(tag) : value.toString(); - } - summarizer(tag) { - return this._legacySummarizers.get(this._valueKey(tag)); - } - _valueKey(value) { - return value.toString(); - } +const asArray = (cbor) => { + if (cbor.type === MajorType.Array) return cbor.value; }; /** -* Global singleton instance of the tags store. +* Extract map value if type matches. +* +* @param cbor - CBOR value +* @returns Map or undefined */ -let globalTagsStore; +const asMap = (cbor) => { + if (cbor.type === MajorType.Map) return cbor.value; +}; /** -* Get the global tags store instance. -* -* Creates the instance on first access, wrapping the canonical package's -* global store so registrations are shared with the delegated formatters. -* -* @returns The global TagsStore instance +* Extract boolean value if type matches. * -* @example -* ```typescript -* const store = getGlobalTagsStore(); -* store.insert(createTag(999, 'myTag')); -* ``` +* @param cbor - CBOR value +* @returns Boolean or undefined */ -const getGlobalTagsStore = () => { - globalTagsStore ??= TagsStore._fromInner(getGlobalTagsStore$1()); - return globalTagsStore; +const asBoolean = (cbor) => { + if (cbor.type !== MajorType.Simple) return; + if (cbor.value.type === "True") return true; + if (cbor.value.type === "False") return false; }; /** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies +* Extract float value if type matches. * -* -* Hex dump utilities for CBOR data. -* -* Affordances for viewing the encoded binary representation of CBOR as hexadecimal. -* Optionally annotates the output, breaking it up into semantically meaningful lines, -* formatting dates, and adding names of known tags. -* -* The annotated rendering delegates to `@blockchaincommons/dcbor/diagnostic`. -* -* @module dump +* @param cbor - CBOR value +* @returns Float or undefined */ +const asFloat = (cbor) => { + if (cbor.type === MajorType.Unsigned) return ExactF64.exactFromU64(cbor.value); + if (cbor.type === MajorType.Negative) { + const f = ExactF64.exactFromU64(cbor.value); + return f === void 0 ? void 0 : -1 - f; + } + if (cbor.type === MajorType.Simple) return isFloat$1(cbor.value) ? cbor.value.value : void 0; +}; /** -* Convert bytes to hex string. +* Extract any numeric value (integer or float). +* +* @param cbor - CBOR value +* @returns Number or undefined */ -const bytesToHex$4 = (bytes) => { - return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join(""); +const asNumber = (cbor) => { + if (cbor.type === MajorType.Unsigned) return cbor.value; + if (cbor.type === MajorType.Negative) { + if (typeof cbor.value === "bigint") return -cbor.value - 1n; + else return -cbor.value - 1; + } + if (cbor.type === MajorType.Simple) { + const simple = cbor.value; + if (isFloat$1(simple)) return simple.value; + } }; /** -* Returns the encoded hexadecimal representation of CBOR. +* Get tag value from tagged CBOR. * -* @param cbor - CBOR value to convert -* @returns Hex string +* @param cbor - CBOR value (must be tagged) +* @returns Tag value or undefined */ -const hex = (cbor) => bytesToHex$4(cborData(cbor)); +const tagValue = (cbor) => { + if (cbor.type !== MajorType.Tagged) return; + return cbor.tag; +}; /** -* Returns the encoded hexadecimal representation of CBOR with options. -* -* Optionally annotates the output, e.g., breaking the output up into -* semantically meaningful lines, formatting dates, and adding names of -* known tags. +* Extract tagged value as tuple [Tag, Cbor] if CBOR is tagged. * -* @param cbor - CBOR value to convert -* @param opts - Formatting options -* @returns Hex string (possibly annotated) +* @param cbor - CBOR value +* @returns [Tag, Cbor] tuple or undefined */ -const hexOpt = (cbor, opts = {}) => { - if (opts.annotate !== true) return hex(cbor); - const tagsStore = opts.tagsStore ?? getGlobalTagsStore(); - return delegating(() => hexAnnotated(toNew(cbor), { tagsStore: tagsStore._inner })); +const asTaggedValue = (cbor) => { + if (cbor.type !== MajorType.Tagged) return; + return [getGlobalTagsStore().tagForValue(cbor.tag) ?? { value: cbor.tag }, cbor.value]; }; /** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* +* Extract unsigned integer value, throwing if type doesn't match. * -* Enhanced diagnostic formatting for CBOR values. +* With `options`, the value is checked against a fixed width and, when +* `wrapNegative` is set, a negative node is wrapped exactly as the +* reference's `u*::try_from` wraps it (see {@link ExpectUnsignedOptions}). * -* Provides multiple formatting options including -* - Annotated diagnostics with tag names -* - Summarized values using custom summarizers -* - Flat (single-line) vs. pretty (multi-line) formatting -* - Configurable tag store usage +* @param cbor - CBOR value +* @param options - Fixed-width extraction (optional; without it the +* behaviour is the plain `Unsigned`-or-`WrongType` check) +* @returns Unsigned integer (`bigint` above `Number.MAX_SAFE_INTEGER`) +* @throws {CborError} `WrongType` if cbor is not an unsigned integer (or, +* with `wrapNegative`, not an integer); `OutOfRange` when the value does +* not fit `width` +*/ +const expectUnsigned = (cbor, options) => { + if (options === void 0) { + const value = asUnsigned(cbor); + if (value === void 0) throw CborError.wrongType(); + return value; + } + const max = (1n << BigInt(options.width)) - 1n; + if (cbor.type === MajorType.Unsigned) { + const value = BigInt(cbor.value); + if (value > max) throw CborError.outOfRange(); + return narrowInteger(value); + } + if (cbor.type === MajorType.Negative && options.wrapNegative === true) { + const magnitude = BigInt(cbor.value); + if (magnitude > max) throw CborError.outOfRange(); + return narrowInteger(max - magnitude); + } + throw CborError.wrongType(); +}; +/** +* Extract byte string value, throwing if type doesn't match. * -* Rendering delegates to `@blockchaincommons/dcbor/diagnostic` (which shares -* this module's option vocabulary); summarizers registered through this -* package's `TagsStore` are consulted through the wrapped canonical store. +* Decoded byte strings are zero-copy views aliasing the input buffer - +* mutating the input after decoding (or mutating the returned bytes) changes +* the other side. Call `.slice()` first if you need an independent copy. * -* @module diag -*/ -/** -* Convert the legacy tags-store option to the canonical one (unwrap a -* wrapped store; pass the string variants through). +* @param cbor - CBOR value +* @returns Byte string +* @throws {CborError} `WrongType` if cbor is not a byte string */ -const toBcTagsOpt = (tags) => { - if (tags instanceof TagsStore) return tags._inner; - return tags; +const expectBytes$1 = (cbor) => { + const value = asBytes(cbor); + if (value === void 0) throw CborError.wrongType(); + return value; }; /** -* Format CBOR value as diagnostic notation with options. -* -* @param cbor - CBOR value to format -* @param opts - Formatting options -* @returns Diagnostic string +* Extract text string value, throwing if type doesn't match. * -* @example -* ```typescript -* const value = cbor({ name: 'Alice', age: 30 }); -* console.log(diagnosticOpt(value, { flat: true })); -* // {\"name\": \"Alice\", \"age\": 30} -* ``` +* @param cbor - CBOR value +* @returns Text string +* @throws {CborError} `WrongType` if cbor is not a text string */ -function diagnosticOpt(cbor, opts) { - return delegating(() => diagnostic$1(toNew(cbor), { - annotate: opts?.annotate, - summarize: opts?.summarize, - flat: opts?.summarize === true ? true : opts?.flat, - tags: toBcTagsOpt(opts?.tags) - })); -} +const expectText = (cbor) => { + const value = asText(cbor); + if (value === void 0) throw CborError.wrongType(); + return value; +}; /** -* Format CBOR value as standard diagnostic notation. +* Extract array value, throwing if type doesn't match. * -* @param cbor - CBOR value to format -* @returns Diagnostic string (pretty-printed with multiple lines for complex structures) -* -* @example -* ```typescript -* const value = cbor([1, 2, 3]); -* console.log(diagnostic(value)); -* // For simple arrays: "[1, 2, 3]" -* // For nested structures: multi-line formatted output -* ``` -*/ -function diagnostic(cbor) { - return diagnosticOpt(cbor); -} -/** -* Checks if the simple value is a floating point number. -*/ -const isFloat$1 = (simple) => simple.type === "Float"; -/** -* Checks if the simple value is the NaN (Not a Number) representation. +* @param cbor - CBOR value +* @returns Array +* @throws {CborError} `WrongType` if cbor is not an array */ -const isNaN$1 = (simple) => simple.type === "Float" && Number.isNaN(simple.value); +const expectArray = (cbor) => { + const value = asArray(cbor); + if (value === void 0) throw CborError.wrongType(); + return value; +}; /** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* +* Extract map value, throwing if type doesn't match. * -* dCBOR decoding — delegates to `@blockchaincommons/dcbor`, the canonical -* implementation, then rewraps the result into this package's legacy node -* shape. All deterministic-encoding enforcement (canonical numeric forms, -* NFC text, map-key order, no trailing bytes) happens in the canonical -* decoder; thrown errors are translated back to the legacy `CborError`. +* @param cbor - CBOR value +* @returns Map +* @throws {CborError} `WrongType` if cbor is not a map */ -function decodeCbor(data) { - return fromNew(delegating(() => decodeCbor$1(data))); -} +const expectMap = (cbor) => { + const value = asMap(cbor); + if (value === void 0) throw CborError.wrongType(); + return value; +}; /** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -* -* Convenience utilities for working with CBOR values. -* -* Provides type-safe helpers for checking types, extracting values, -* and working with arrays, maps, and tagged values. +* Extract boolean value, throwing if type doesn't match. * -* @module conveniences -*/ -/** -* Extract native JavaScript value from CBOR. -* Converts CBOR types to their JavaScript equivalents. +* @param cbor - CBOR value +* @returns Boolean +* @throws {CborError} `WrongType` if cbor is not a boolean */ -const extractCbor = (cbor) => { - let c; - if (cbor instanceof Uint8Array) c = decodeCbor(cbor); - else c = cbor; - switch (c.type) { - case MajorType.Unsigned: return c.value; - case MajorType.Negative: if (typeof c.value === "bigint") return -c.value - 1n; - else return -c.value - 1; - case MajorType.ByteString: return c.value; - case MajorType.Text: return c.value; - case MajorType.Array: return c.value.map(extractCbor); - case MajorType.Map: return c.value; - case MajorType.Tagged: return c; - case MajorType.Simple: - if (c.value.type === "True") return true; - if (c.value.type === "False") return false; - if (c.value.type === "Null") return null; - if (c.value.type === "Float") return c.value.value; - return c; - } +const expectBoolean = (cbor) => { + const value = asBoolean(cbor); + if (value === void 0) throw CborError.wrongType(); + return value; }; /** -* Check if CBOR value is an unsigned integer. +* Extract float value, throwing if type doesn't match. * -* @param cbor - CBOR value to check -* @returns True if value is unsigned integer +* Integers coerce to float, as for {@link asFloat}. * -* @example -* ```typescript -* if (isUnsigned(value)) { -* console.log('Unsigned:', value.value); -* } -* ``` -*/ -const isUnsigned = (cbor) => { - return cbor.type === MajorType.Unsigned; +* @param cbor - CBOR value +* @returns Float +* @throws {CborError} `WrongType` if cbor is not numeric; `OutOfRange` if an +* integer is not exactly representable as f64 +*/ +const expectFloat = (cbor) => { + if (cbor.type === MajorType.Unsigned || cbor.type === MajorType.Negative) { + const value = asFloat(cbor); + if (value === void 0) throw CborError.outOfRange(); + return value; + } + if (cbor.type === MajorType.Simple && isFloat$1(cbor.value)) return cbor.value.value; + throw CborError.wrongType(); }; /** -* Check if CBOR value is a negative integer. +* Extract any numeric value, throwing if type doesn't match. * -* @param cbor - CBOR value to check -* @returns True if value is negative integer +* @param cbor - CBOR value +* @returns Number +* @throws {CborError} `WrongType` if cbor is not a number */ -const isNegative = (cbor) => { - return cbor.type === MajorType.Negative; +const expectNumber = (cbor) => { + const value = asNumber(cbor); + if (value === void 0) throw CborError.wrongType(); + return value; }; /** -* Check if CBOR value is a byte string. +* Extract content if has specific tag, throwing if not (the reference's +* `try_into_expected_tagged_value`). * -* @param cbor - CBOR value to check -* @returns True if value is byte string -*/ -const isBytes$5 = (cbor) => { - return cbor.type === MajorType.ByteString; -}; -/** -* Check if CBOR value is a text string. +* The `WrongTag` error names the expected tag as it was given (a `Tag` keeps +* its name; a number or bigint stays unnamed) and the actual tag as the node +* carries it. * -* @param cbor - CBOR value to check -* @returns True if value is text string +* @param cbor - CBOR value +* @param tag - Expected tag value, or a `Tag` +* @returns Tagged content +* @throws {CborError} `WrongType` if `cbor` is not tagged; `WrongTag` (with +* `details.expectedTag` and `details.actualTag`) if the tag doesn't match */ -const isText = (cbor) => { - return cbor.type === MajorType.Text; +const expectTaggedContent = (cbor, tag) => { + if (cbor.type !== MajorType.Tagged) throw CborError.wrongType(); + const expected = typeof tag === "object" ? tag : Tag.from(tag); + if (!tagValuesEqual(cbor.tag, expected.value)) throw CborError.wrongTag(expected, Tag.from(cbor.tag, cbor.tagName)); + return cbor.value; }; +//#endregion +//#region ../bc-tags-ts/dist/index.mjs /** -* Check if CBOR value is an array. +* The Blockchain Commons CBOR tag registry. * -* @param cbor - CBOR value to check -* @returns True if value is array -*/ -const isArray = (cbor) => { - return cbor.type === MajorType.Array; -}; -/** -* Check if CBOR value is a map. +* Values are the CBOR tag numbers on the wire; names are wire too, since +* `uniform-resources` derives UR types from them (`ur:envelope`). Neither +* may change without a specification change. Every constant is frozen. * -* @param cbor - CBOR value to check -* @returns True if value is map -*/ -const isMap = (cbor) => { - return cbor.type === MajorType.Map; -}; +* Tags compare by value: `TAG_ENVELOPE === Tag.from(200, "envelope")` is +* `false` (two objects), `Tag.equals(a, b)` and `a.value === b.value` are +* the comparisons to write. +* +* @see https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2020-006-urtypes.md +* @module tags +*/ +/** +* One immutable tag. dcbor's `Tag.from` returns a frozen object (since +* 1.0.0-beta.3, as the reference's `Tag` is a value); the freeze here is +* kept as defence in depth so the constants stay frozen on any dcbor the +* floor admits. The names are wire, so nothing may rewrite them +* process-wide. +*/ +const tag = (value, name) => Object.freeze(Tag.from(value, name)); +/** #6.32: URI (RFC 8949 §3.4.5.3), named `url` in this stack. */ +const TAG_URI = tag(32, "url"); +/** #6.37: binary UUID (RFC 4122). */ +const TAG_UUID = tag(37, "uuid"); +/** #6.24: encoded CBOR data item; the pre-#6.201 Envelope leaf header, accepted on decode only. */ +const TAG_ENCODED_CBOR = tag(24, "encoded-cbor"); +/** #6.200: Gordian Envelope. */ +const TAG_ENVELOPE = tag(200, "envelope"); +/** #6.201: dCBOR data item; the Envelope leaf case. */ +const TAG_LEAF = tag(201, "leaf"); +/** #6.262: byte string holding UTF-8 JSON text. */ +const TAG_JSON = tag(262, "json"); +/** #6.40000: known value, a registered unsigned integer with a fixed meaning. */ +const TAG_KNOWN_VALUE = tag(4e4, "known-value"); +/** #6.40001: SHA-256 digest. */ +const TAG_DIGEST = tag(40001, "digest"); +/** #6.40002: encrypted message (IETF ChaCha20-Poly1305). */ +const TAG_ENCRYPTED = tag(40002, "encrypted"); +/** #6.40003: DEFLATE-compressed data with the digest of the original. */ +const TAG_COMPRESSED = tag(40003, "compressed"); +/** #6.40004: request. */ +const TAG_REQUEST = tag(40004, "request"); +/** #6.40005: response. */ +const TAG_RESPONSE = tag(40005, "response"); +/** #6.40006: function identifier. */ +const TAG_FUNCTION = tag(40006, "function"); +/** #6.40007: parameter identifier. */ +const TAG_PARAMETER = tag(40007, "parameter"); +/** #6.40008: placeholder. */ +const TAG_PLACEHOLDER = tag(40008, "placeholder"); +/** #6.40009: replacement. */ +const TAG_REPLACEMENT = tag(40009, "replacement"); +/** #6.40010: X25519 key-agreement private key. */ +const TAG_X25519_PRIVATE_KEY = tag(40010, "agreement-private-key"); +/** #6.40011: X25519 key-agreement public key. */ +const TAG_X25519_PUBLIC_KEY = tag(40011, "agreement-public-key"); +/** #6.40012: apparently random identifier (32 bytes). */ +const TAG_ARID = tag(40012, "arid"); +/** #6.40013: a signing and an encapsulation private key together. */ +const TAG_PRIVATE_KEYS = tag(40013, "crypto-prvkeys"); +/** #6.40014: nonce. */ +const TAG_NONCE = tag(40014, "nonce"); +/** #6.40015: password. */ +const TAG_PASSWORD = tag(40015, "password"); +/** #6.40016: private key base, the material every other key derives from. */ +const TAG_PRIVATE_KEY_BASE = tag(40016, "crypto-prvkey-base"); +/** #6.40017: a signing and an encapsulation public key together. */ +const TAG_PUBLIC_KEYS = tag(40017, "crypto-pubkeys"); +/** #6.40018: salt. */ +const TAG_SALT = tag(40018, "salt"); +/** #6.40019: sealed message, encrypted to a recipient's public keys. */ +const TAG_SEALED_MESSAGE = tag(40019, "crypto-sealed"); +/** #6.40020: signature. */ +const TAG_SIGNATURE = tag(40020, "signature"); +/** #6.40021: signing private key. */ +const TAG_SIGNING_PRIVATE_KEY = tag(40021, "signing-private-key"); +/** #6.40022: signing public key. */ +const TAG_SIGNING_PUBLIC_KEY = tag(40022, "signing-public-key"); +/** #6.40023: symmetric encryption key. */ +const TAG_SYMMETRIC_KEY = tag(40023, "crypto-key"); +/** #6.40024: extensible identifier (XID). */ +const TAG_XID = tag(40024, "xid"); +/** #6.40025: reference to an identifier by a prefix of it. */ +const TAG_REFERENCE = tag(40025, "reference"); +/** #6.40026: distributed function call event. */ +const TAG_EVENT = tag(40026, "event"); +/** #6.40027: symmetric key wrapped for a recipient. */ +const TAG_ENCRYPTED_KEY = tag(40027, "encrypted-key"); +/** #6.40100: ML-KEM (FIPS 203) private key. */ +const TAG_MLKEM_PRIVATE_KEY = tag(40100, "mlkem-private-key"); +/** #6.40101: ML-KEM (FIPS 203) public key. */ +const TAG_MLKEM_PUBLIC_KEY = tag(40101, "mlkem-public-key"); +/** #6.40102: ML-KEM (FIPS 203) encapsulated ciphertext. */ +const TAG_MLKEM_CIPHERTEXT = tag(40102, "mlkem-ciphertext"); +/** #6.40103: ML-DSA (FIPS 204) private key. */ +const TAG_MLDSA_PRIVATE_KEY = tag(40103, "mldsa-private-key"); +/** #6.40104: ML-DSA (FIPS 204) public key. */ +const TAG_MLDSA_PUBLIC_KEY = tag(40104, "mldsa-public-key"); +/** #6.40105: ML-DSA (FIPS 204) signature. */ +const TAG_MLDSA_SIGNATURE = tag(40105, "mldsa-signature"); +/** #6.40300: cryptographic seed. */ +const TAG_SEED = tag(40300, "seed"); +/** #6.40303: BIP-32 hierarchical deterministic key. */ +const TAG_HDKEY = tag(40303, "hdkey"); +/** #6.40304: BIP-32 derivation path. */ +const TAG_DERIVATION_PATH = tag(40304, "keypath"); +/** #6.40305: coin type and network (`coin-info`). */ +const TAG_USE_INFO = tag(40305, "coin-info"); +/** #6.40306: elliptic-curve key. */ +const TAG_EC_KEY = tag(40306, "eckey"); +/** #6.40307: address. */ +const TAG_ADDRESS = tag(40307, "address"); +/** #6.40308: output descriptor. */ +const TAG_OUTPUT_DESCRIPTOR = tag(40308, "output-descriptor"); +/** #6.40309: SSKR share. */ +const TAG_SSKR_SHARE = tag(40309, "sskr"); +/** #6.40310: partially signed Bitcoin transaction. */ +const TAG_PSBT = tag(40310, "psbt"); +/** #6.40311: account descriptor. */ +const TAG_ACCOUNT_DESCRIPTOR = tag(40311, "account-descriptor"); +/** #6.40800: OpenSSH text-format private key. */ +const TAG_SSH_TEXT_PRIVATE_KEY = tag(40800, "ssh-private"); +/** #6.40801: OpenSSH text-format public key. */ +const TAG_SSH_TEXT_PUBLIC_KEY = tag(40801, "ssh-public"); +/** #6.40802: OpenSSH text-format signature. */ +const TAG_SSH_TEXT_SIGNATURE = tag(40802, "ssh-signature"); +/** #6.40803: OpenSSH text-format certificate. */ +const TAG_SSH_TEXT_CERTIFICATE = tag(40803, "ssh-certificate"); +/** #6.1347571542: provenance mark. */ +const TAG_PROVENANCE_MARK = tag(1347571542, "provenance"); +/** #6.400: output descriptor `sh` (script hash). */ +const TAG_OUTPUT_SCRIPT_HASH = tag(400, "output-script-hash"); +/** #6.401: output descriptor `wsh` (witness script hash). */ +const TAG_OUTPUT_WITNESS_SCRIPT_HASH = tag(401, "output-witness-script-hash"); +/** #6.402: output descriptor `pk` (public key). */ +const TAG_OUTPUT_PUBLIC_KEY = tag(402, "output-public-key"); +/** #6.403: output descriptor `pkh` (public key hash). */ +const TAG_OUTPUT_PUBLIC_KEY_HASH = tag(403, "output-public-key-hash"); +/** #6.404: output descriptor `wpkh` (witness public key hash). */ +const TAG_OUTPUT_WITNESS_PUBLIC_KEY_HASH = tag(404, "output-witness-public-key-hash"); +/** #6.405: output descriptor `combo`. */ +const TAG_OUTPUT_COMBO = tag(405, "output-combo"); +/** #6.406: output descriptor `multi` (multisig). */ +const TAG_OUTPUT_MULTISIG = tag(406, "output-multisig"); +/** #6.407: output descriptor `sortedmulti` (sorted multisig). */ +const TAG_OUTPUT_SORTED_MULTISIG = tag(407, "output-sorted-multisig"); +/** #6.408: output descriptor `raw` (raw script). */ +const TAG_OUTPUT_RAW_SCRIPT = tag(408, "output-raw-script"); +/** #6.409: output descriptor `tr` (taproot). */ +const TAG_OUTPUT_TAPROOT = tag(409, "output-taproot"); +/** #6.410: output descriptor cosigner. */ +const TAG_OUTPUT_COSIGNER = tag(410, "output-cosigner"); +/** +* Superseded tags, accepted on decode only. They sit in IANA's +* "Specification Required" range (300–311) and were replaced by the +* first-come-first-served 40300+ tags above; existing data still uses them. +* Never emit these for new data. Frozen, like every entry in it. +*/ +const LEGACY_TAGS = Object.freeze({ + SEED_V1: tag(300, "crypto-seed"), + EC_KEY_V1: tag(306, "crypto-eckey"), + SSKR_SHARE_V1: tag(309, "crypto-sskr"), + HDKEY_V1: tag(303, "crypto-hdkey"), + DERIVATION_PATH_V1: tag(304, "crypto-keypath"), + USE_INFO_V1: tag(305, "crypto-coin-info"), + OUTPUT_DESCRIPTOR_V1: tag(307, "crypto-output"), + PSBT_V1: tag(310, "crypto-psbt"), + ACCOUNT_V1: tag(311, "crypto-account") +}); /** -* Check if CBOR value is tagged. +* Every tag this package defines, in registration order (the order the +* Rust reference registers them). Iterate this rather than the constants. +* Frozen, like every entry in it. +*/ +const ALL_TAGS = Object.freeze([ + TAG_URI, + TAG_UUID, + TAG_ENCODED_CBOR, + TAG_ENVELOPE, + TAG_LEAF, + TAG_JSON, + TAG_KNOWN_VALUE, + TAG_DIGEST, + TAG_ENCRYPTED, + TAG_COMPRESSED, + TAG_REQUEST, + TAG_RESPONSE, + TAG_FUNCTION, + TAG_PARAMETER, + TAG_PLACEHOLDER, + TAG_REPLACEMENT, + TAG_EVENT, + LEGACY_TAGS.SEED_V1, + LEGACY_TAGS.EC_KEY_V1, + LEGACY_TAGS.SSKR_SHARE_V1, + TAG_SEED, + TAG_EC_KEY, + TAG_SSKR_SHARE, + TAG_X25519_PRIVATE_KEY, + TAG_X25519_PUBLIC_KEY, + TAG_ARID, + TAG_PRIVATE_KEYS, + TAG_NONCE, + TAG_PASSWORD, + TAG_PRIVATE_KEY_BASE, + TAG_PUBLIC_KEYS, + TAG_SALT, + TAG_SEALED_MESSAGE, + TAG_SIGNATURE, + TAG_SIGNING_PRIVATE_KEY, + TAG_SIGNING_PUBLIC_KEY, + TAG_SYMMETRIC_KEY, + TAG_XID, + TAG_REFERENCE, + TAG_ENCRYPTED_KEY, + TAG_MLKEM_PRIVATE_KEY, + TAG_MLKEM_PUBLIC_KEY, + TAG_MLKEM_CIPHERTEXT, + TAG_MLDSA_PRIVATE_KEY, + TAG_MLDSA_PUBLIC_KEY, + TAG_MLDSA_SIGNATURE, + LEGACY_TAGS.HDKEY_V1, + LEGACY_TAGS.DERIVATION_PATH_V1, + LEGACY_TAGS.USE_INFO_V1, + LEGACY_TAGS.OUTPUT_DESCRIPTOR_V1, + LEGACY_TAGS.PSBT_V1, + LEGACY_TAGS.ACCOUNT_V1, + TAG_HDKEY, + TAG_DERIVATION_PATH, + TAG_USE_INFO, + TAG_ADDRESS, + TAG_OUTPUT_DESCRIPTOR, + TAG_PSBT, + TAG_ACCOUNT_DESCRIPTOR, + TAG_SSH_TEXT_PRIVATE_KEY, + TAG_SSH_TEXT_PUBLIC_KEY, + TAG_SSH_TEXT_SIGNATURE, + TAG_SSH_TEXT_CERTIFICATE, + TAG_OUTPUT_SCRIPT_HASH, + TAG_OUTPUT_WITNESS_SCRIPT_HASH, + TAG_OUTPUT_PUBLIC_KEY, + TAG_OUTPUT_PUBLIC_KEY_HASH, + TAG_OUTPUT_WITNESS_PUBLIC_KEY_HASH, + TAG_OUTPUT_COMBO, + TAG_OUTPUT_MULTISIG, + TAG_OUTPUT_SORTED_MULTISIG, + TAG_OUTPUT_RAW_SCRIPT, + TAG_OUTPUT_TAPROOT, + TAG_OUTPUT_COSIGNER, + TAG_PROVENANCE_MARK +]); +/** +* Registration into a dCBOR tags store. * -* @param cbor - CBOR value to check -* @returns True if value is tagged +* @module register */ -const isTagged = (cbor) => { - return cbor.type === MajorType.Tagged; -}; /** -* Check if CBOR value is a simple value. +* Register dcbor's standard tags and every tag in {@link ALL_TAGS} into +* `store` (default: the global store), in the reference's order: `date` +* (tag 1) with its summarizer, then the 75 tags of this package. * -* @param cbor - CBOR value to check -* @returns True if value is simple +* Idempotent: a value already registered under the same name is a no-op, +* and a name already registered under another value moves to this +* package's value, as the reference's `insert_all` does. Tags 2 and 3 stay +* unnamed, as in the reference's default build; for the `num-bigint` +* registry call `registerStandardTags(store, { bignum: true })` before this +* function. +* +* @param store - The store to register into; defaults to dcbor's global store. +* @throws {CborError} Code `Custom` (dcbor's store) when a value is already +* registered under a different name; the message is the reference's panic +* text, e.g. `Attempt to register tag: 200 'foo' with different name: 'envelope'`. +* Tags registered earlier in the same call stay registered, and the rejected +* entry is unchanged. */ -const isSimple = (cbor) => { - return cbor.type === MajorType.Simple; -}; +function registerTags$2(store = getGlobalTagsStore()) { + registerStandardTags(store); + store.registerAll(ALL_TAGS); +} +//#endregion +//#region ../bc-components-ts/dist/domain-CD4Y4F3r.mjs /** -* Check if CBOR value is null. +* Error raised by every component operation. * -* @param cbor - CBOR value to check -* @returns True if value is null +* ```ts +* try { +* Digest.from(bytes); +* } catch (e) { +* if (ComponentsError.isComponentsError(e) && e.code === "InvalidSize") { +* console.log(e.details.expected, e.details.actual); +* } +* } +* ``` */ -const isNull = (cbor) => { - if (cbor.type !== MajorType.Simple) return false; - return cbor.value.type === "Null"; +var ComponentsError = class ComponentsError extends Error { + /** Always `"ComponentsError"`; the cross-copy identity `isComponentsError` checks. */ + name = "ComponentsError"; + /** The failure code. */ + code; + /** Structured details, discriminated by `code`. */ + details; + constructor(message, details, cause) { + super(message, cause === void 0 ? void 0 : { cause }); + this.code = details.code; + this.details = details; + } + /** `true` for a `ComponentsError` from any copy of this package. */ + static isComponentsError(value) { + return value instanceof Error && value.name === "ComponentsError" && "code" in value; + } + /** `true` when this error carries `code`. */ + is(code) { + return this.code === code; + } + /** + * `InvalidSize`: `invalid size: expected , got + * `, with the reference's `data_type` (`"digest"`, `"nonce"`, + * `"symmetric key"`, `"ECDSA public key"`, …). + */ + static invalidSize(dataType, expected, actual) { + return new ComponentsError(`invalid ${dataType} size: expected ${expected}, got ${actual}`, { + code: "InvalidSize", + dataType, + expected, + actual + }); + } + /** `InvalidData` for unnamed data. */ + static invalidData(reason, cause) { + return ComponentsError.invalidDataForType("data", reason, cause); + } + /** `InvalidData` naming the type or parameter. */ + static invalidDataForType(dataType, reason, cause) { + return new ComponentsError(`invalid ${dataType}: ${reason}`, { + code: "InvalidData", + dataType, + reason + }, cause); + } + /** `DataTooShort`: fewer bytes than the type's minimum. */ + static dataTooShort(dataType, minimum, actual) { + return new ComponentsError(`data too short: ${dataType} expected at least ${minimum}, got ${actual}`, { + code: "DataTooShort", + dataType, + minimum, + actual + }); + } + /** `InvalidData` for a malformed text form (an SSH PEM, a URI). */ + static invalidFormat(reason, cause) { + return ComponentsError.invalidDataForType("format", reason, cause); + } + /** `Crypto`: a cryptographic operation failed (authentication, signing). */ + static crypto(message, cause) { + return ComponentsError.of("Crypto", `cryptographic operation failed: ${message}`, message, cause); + } + /** + * `Cbor` with the `CBOR error: ` prefix: a dcbor failure inside an + * operation whose reference error type is the component `Error` + * (`Error::Cbor`), or a dcbor failure met outside a decoder. + */ + static cbor(message, cause) { + return ComponentsError.of("Cbor", `CBOR error: ${message}`, message, cause); + } + /** + * `Cbor` as a decoder reports it: the message is the dcbor `Display` of + * `cause` with no prefix, as the reference's `from_tagged_cbor` returns a + * `dcbor::Error`; `cause` is that `CborError`. + */ + static cborDecode(cause) { + return ComponentsError.of("Cbor", cause.message, cause.message, cause); + } + /** `Sskr`: a failure from the sskr package. */ + static sskr(message, cause) { + return ComponentsError.of("Sskr", `SSKR error: ${message}`, message, cause); + } + /** `Ssh`: an SSH key, signature or certificate could not be parsed or used. */ + static ssh(message, cause) { + return ComponentsError.of("Ssh", `SSH operation failed: ${message}`, message, cause); + } + /** `SshAgent`: an SSH-agent operation is not available. */ + static sshAgent(message, cause) { + return ComponentsError.of("SshAgent", `SSH agent error: ${message}`, message, cause); + } + /** `Uri`: not a valid URI. */ + static uri(message, cause) { + return ComponentsError.of("Uri", `invalid URI: ${message}`, message, cause); + } + /** `Compression`: a DEFLATE stream or its checksum is corrupt. */ + static compression(message, cause) { + return ComponentsError.of("Compression", `compression error: ${message}`, message, cause); + } + /** `PostQuantum`: an ML-DSA / ML-KEM level or key is invalid. */ + static postQuantum(message, cause) { + return ComponentsError.of("PostQuantum", `post-quantum cryptography error: ${message}`, message, cause); + } + /** `LevelMismatch`: an ML-DSA signature and key of different levels. */ + static levelMismatch() { + const message = "signature level does not match key level"; + return ComponentsError.of("LevelMismatch", message, message); + } + /** `Hex`: a malformed hex string (`hex decoding error: `, the `hex` crate's texts). */ + static hex(message, cause) { + return ComponentsError.of("Hex", `hex decoding error: ${message}`, message, cause); + } + /** `Utf8`: bytes that are not valid UTF-8 (`UTF-8 conversion error: `). */ + static utf8(message, cause) { + return ComponentsError.of("Utf8", `UTF-8 conversion error: ${message}`, message, cause); + } + /** `Env`: an environment variable an SSH-agent transport needs is missing or unreadable. */ + static env(message, cause) { + return ComponentsError.of("Env", `environment variable error: ${message}`, message, cause); + } + /** `SshAgentClient`: the SSH-agent transport failed (socket, protocol). */ + static sshAgentClient(message, cause) { + return ComponentsError.of("SshAgentClient", `SSH agent client error: ${message}`, message, cause); + } + /** `General`: anything the other codes do not name. */ + static general(message, cause) { + return ComponentsError.of("General", message, message, cause); + } + static of(code, fullMessage, message, cause) { + return new ComponentsError(fullMessage, { + code, + message + }, cause); + } }; +/** The inclusive maximum of a `u32`. */ +const U32_MAX$1 = 4294967295; /** -* Extract unsigned integer value if type matches. -* -* @param cbor - CBOR value -* @returns Unsigned integer or undefined +* The fixed-width unsigned fields the reference decodes with +* `u8`/`u32`/`usize: TryFrom`, which wrap a negative head (dcbor +* 0.25.2 `int.rs`): pass one to dcbor's `expectUnsigned`. */ -const asUnsigned = (cbor) => { - if (cbor.type === MajorType.Unsigned) return cbor.value; -}; +const U8_FIELD = Object.freeze({ + width: 8, + wrapNegative: true +}); +/** See {@link U8_FIELD}. */ +const U32_FIELD = Object.freeze({ + width: 32, + wrapNegative: true +}); +/** See {@link U8_FIELD}; `usize` is 64 bits wide on the reference's targets. */ +const USIZE_FIELD = Object.freeze({ + width: 64, + wrapNegative: true +}); +/** Throws `InvalidData` unless `value` is an integer `number` in `[min, max]`. Returns it. */ +function expectInt$2(value, min, max, parameter) { + if (typeof value !== "number" || !Number.isInteger(value) || value < min || value > max) throw ComponentsError.invalidDataForType(parameter, `must be an integer in [${min}, ${max}], got ${String(value)}`); + return value; +} +/** `expectInt` over `[0, 255]`. */ +function expectU8(value, parameter) { + return expectInt$2(value, 0, 255, parameter); +} +/** `expectInt` over `[0, 4294967295]`. */ +function expectU32(value, parameter) { + return expectInt$2(value, 0, U32_MAX$1, parameter); +} /** -* Extract any integer value (unsigned or negative) if type matches. -* -* @param cbor - CBOR value -* @returns Integer or undefined +* A byte length: an integer `≥ 0` (`InvalidData` otherwise) that is at +* least `minimum` (`DataTooShort` otherwise). Returns it. */ -const asInteger = (cbor) => { - if (cbor.type === MajorType.Unsigned) return cbor.value; - else if (cbor.type === MajorType.Negative) if (typeof cbor.value === "bigint") return -cbor.value - 1n; - else return -cbor.value - 1; -}; +function expectLength(value, minimum, dataType) { + expectInt$2(value, 0, U32_MAX$1, `${dataType} length`); + if (value < minimum) throw ComponentsError.dataTooShort(dataType, minimum, value); + return value; +} +/** Throws `InvalidData` unless `value` is a string. Returns it. */ +function expectString$1(value, parameter) { + if (typeof value !== "string") throw ComponentsError.invalidDataForType(parameter, `must be a string, got ${typeName(value)}`); + return value; +} +/** Throws `InvalidData` unless `value` is a valid `Date`. Returns it. */ +function expectDate$1(value, parameter) { + if (!(value instanceof Date) || Number.isNaN(value.getTime())) throw ComponentsError.invalidDataForType(parameter, `must be a valid Date, got ${typeName(value)}`); + return value; +} +const HEX_VALUE = (/* @__PURE__ */ new Int8Array(256)).fill(-1); +for (let i = 0; i < 10; i++) HEX_VALUE[48 + i] = i; +for (let i = 0; i < 6; i++) { + HEX_VALUE[65 + i] = 10 + i; + HEX_VALUE[97 + i] = 10 + i; +} +/** +* Rust's `char::escape_debug` for the Latin-1 range, the way `{:?}` +* prints the offending byte of a hex string: `\0`, `\t`, `\n`, `\r`, `\'` +* and `\\` by name, the other controls (U+0001–U+001F, U+007F–U+00A0) and +* U+00AD as `\u{..}`, everything else as itself. +*/ +function rustCharDebug(byte) { + switch (byte) { + case 0: return "\\0"; + case 9: return "\\t"; + case 10: return "\\n"; + case 13: return "\\r"; + case 39: return "\\'"; + case 92: return "\\\\"; + default: + if (byte < 32 || byte >= 127 && byte <= 160 || byte === 173) return `\\u{${byte.toString(16)}}`; + return String.fromCharCode(byte); + } +} +/** +* Bytes from a hex string, as the reference's `hex::decode` (hex 0.4.3) +* reads it: over the UTF-8 bytes of `text`, an odd byte count first +* (`Odd number of digits`), then the first byte outside `[0-9a-fA-F]` +* (`Invalid character '' at position `), as `Hex` failures with +* the crate's `Display`. Whitespace is not tolerated. The reference +* `unwrap`s this in most `from_hex`s (a panic) and returns it for the +* Ed25519 keys. +*/ +function decodeHexStrict(text) { + const bytes = new TextEncoder().encode(text); + if (bytes.length % 2 !== 0) throw ComponentsError.hex("Odd number of digits"); + const out = new Uint8Array(bytes.length / 2); + for (let i = 0; i < bytes.length; i++) { + const v = HEX_VALUE[bytes[i]]; + if (v < 0) throw ComponentsError.hex(`Invalid character '${rustCharDebug(bytes[i])}' at position ${i}`); + if (i % 2 === 0) out[i >> 1] = v << 4; + else out[i >> 1] |= v; + } + return out; +} +/** {@link decodeHexStrict}, the door every `fromHex` uses. */ +function bytesFromHex(hex) { + return decodeHexStrict(hex); +} +/** +* Rust's `str::trim`: the Unicode `White_Space` set (U+0009–U+000D, +* U+0020, U+0085, U+00A0, U+1680, U+2000–U+200A, U+2028, U+2029, U+202F, +* U+205F, U+3000), which is not `String.prototype.trim`'s set: U+FEFF is not +* trimmed. +*/ +function rustTrim(text) { + const ws = (c) => c >= 9 && c <= 13 || c === 32 || c === 133 || c === 160 || c === 5760 || c >= 8192 && c <= 8202 || c === 8232 || c === 8233 || c === 8239 || c === 8287 || c === 12288; + let start = 0; + let end = text.length; + while (start < end && ws(text.charCodeAt(start))) start++; + while (end > start && ws(text.charCodeAt(end - 1))) end--; + return text.slice(start, end); +} +/** `rustTrim` from the right only (`str::trim_end`). */ +function rustTrimEnd(text) { + return rustTrim(`x${text}`).slice(1); +} +/** +* The boundary: a dependency's error as a `ComponentsError` with `cause`. +* A `ComponentsError` passes through unchanged. crypto's +* `AuthenticationFailed` becomes `Crypto` with the reference's one +* `bc_crypto::Error` text, `AEAD error`; its `InvalidData`, `InvalidSize` +* and `InvalidParameter` become `InvalidData` for `dataType` (the input was +* malformed, not the operation: the points where the reference panics); +* dcbor's errors become `Cbor`; anything else becomes `Crypto` with its +* own message. +*/ +function wrapForeign$1(e, dataType) { + if (ComponentsError.isComponentsError(e)) return e; + const name = e instanceof Error ? e.name : ""; + const code = e.code; + if (name === "CryptoError") { + if (code === "AuthenticationFailed") return ComponentsError.crypto("AEAD error", e); + return ComponentsError.invalidDataForType(dataType, messageOf$1(e), e); + } + if (name === "CborError") return ComponentsError.cbor(messageOf$1(e), e); + return ComponentsError.crypto(messageOf$1(e), e); +} +/** Runs `f`; a foreign throw becomes a `ComponentsError` for `dataType`. */ +function guarded$1(dataType, f) { + try { + return f(); + } catch (e) { + throw wrapForeign$1(e, dataType); + } +} +function messageOf$1(e) { + return e instanceof Error ? e.message : String(e); +} +function typeName(value) { + if (value === null) return "null"; + if (typeof value === "object") return value.constructor.name; + return typeof value; +} +//#endregion +//#region ../bc-components-ts/dist/utils-P9RTxqwn.mjs /** -* Extract byte string value if type matches. +* The one codable mechanism of this package. * -* @param cbor - CBOR value -* @returns Byte string or undefined +* Every value type exposes a `codec` (a dcbor `CborCodec` over its tagged +* form; `decode` requires one of the type's tags), `toCbor()` (tagged), +* `toUR()`, and `fromCbor(cbor)`. Bytes and UR strings compose with dcbor +* and uniform-resources: `decodeWith(bytes, X.codec)`, +* `decodeURWith(UR.parse(s), X.codec)`, `x.toCbor().toData()`, +* `x.toUR().toString()`. +* +* Tags are held by value. Their names come from dcbor's global tags store +* at the moment they are asked for (`codec.tags`, `cborTags()`, the +* expected tag in a `WrongTag` message), as the reference's `cbor_tags()` +* calls `tags_for_values`: call `registerTags()` (`/tags`) first to name +* them, as the reference's `register_tags()`. A UR needs the name. +* +* Every decode failure is a `ComponentsError` with code `Cbor` whose +* message is the dcbor `Display` and whose `cause` is the `CborError`, the +* reference's `dcbor::Error` from `from_tagged_cbor`; see {@link decodeWith}. +* +* @module codable */ -const asBytes = (cbor) => { - if (cbor.type === MajorType.ByteString) return cbor.value; -}; /** -* Extract text string value if type matches. -* -* @param cbor - CBOR value -* @returns Text string or undefined +* Build a type's codec once. `decode` validates the tag against the store +* (dcbor's `validateTag`: an untagged value is `WrongType`, a foreign tag +* `WrongTag` naming the expected tag as the store names it) and hands the +* content to `decodeTagged` or `decodeUntagged`; every failure inside goes +* through {@link decodeWith}. */ -const asText = (cbor) => { - if (cbor.type === MajorType.Text) return cbor.value; -}; +function defineCodec(spec) { + const tagValues = Object.freeze(spec.tags.map((t) => t.value)); + const first = tagValues[0]; + if (first === void 0) throw new Error("defineCodec: a codec needs at least one tag"); + return { + tagValues, + get tags() { + return tagsForValues([...tagValues]); + }, + decodeUntagged: spec.decodeUntagged, + encodeUntagged: spec.encodeUntagged, + encode: spec.encode ?? ((value) => taggedValue(tagsForValues([first])[0] ?? first, spec.encodeUntagged(value))), + decode: (cbor) => decodeWith(() => { + if (spec.decodeAny !== void 0) return spec.decodeAny(cbor); + const tag = validateTag(cbor, tagsForValues([...tagValues])); + const content = extractTaggedContent(cbor); + return spec.decodeTagged === void 0 ? spec.decodeUntagged(content) : spec.decodeTagged(tag, content, cbor); + }) + }; +} /** -* Extract array value if type matches. +* Runs a decoder under the reference's error rule for a `dcbor::Error` +* result (`from_tagged_cbor`, and every `TryFrom` whose error type is +* `dcbor::Error`): the failure is a `ComponentsError` with code `Cbor`, the +* bare dcbor message and the `CborError` as `cause`. * -* @param cbor - CBOR value -* @returns Array or undefined +* - a `CborError` is wrapped as is; +* - a `ComponentsError` with code `Cbor` (a nested decoder, or a +* `CBOR error: …` from a component-typed site) contributes its +* `CborError` cause, as `From for dcbor::Error` unwraps +* `Error::Cbor`; +* - any other `ComponentsError` (a size or format check inside the decoder) +* becomes `CborError.custom()`, with the inner error kept as +* that cause's `cause`, as `dcbor::Error::msg(err.to_string())` does. +* +* Anything else (an engine error from a JS-only input) propagates. */ -const asArray = (cbor) => { - if (cbor.type === MajorType.Array) return cbor.value; -}; -/** -* Extract map value if type matches. -* -* @param cbor - CBOR value -* @returns Map or undefined -*/ -const asMap = (cbor) => { - if (cbor.type === MajorType.Map) return cbor.value; -}; -/** -* Extract boolean value if type matches. -* -* @param cbor - CBOR value -* @returns Boolean or undefined -*/ -const asBoolean = (cbor) => { - if (cbor.type !== MajorType.Simple) return; - if (cbor.value.type === "True") return true; - if (cbor.value.type === "False") return false; -}; +function decodeWith(f) { + try { + return f(); + } catch (e) { + if (CborError.isCborError(e)) throw ComponentsError.cborDecode(e); + if (ComponentsError.isComponentsError(e)) { + if (e.code === "Cbor") { + const inner = e.cause; + if (CborError.isCborError(inner)) throw ComponentsError.cborDecode(inner); + throw e; + } + const custom = CborError.custom(e.message); + custom.cause = e; + throw ComponentsError.cborDecode(custom); + } + throw e; + } +} /** -* Extract any numeric value (integer or float). -* -* @param cbor - CBOR value -* @returns Number or undefined +* Runs a decoder whose reference error type is the component `Error` +* (`HashType`, `AuthenticationTag`, the ML-KEM and ML-DSA levels, +* `KeyDerivationMethod`): a dcbor failure inside is `Cbor` with the +* `CBOR error: ` prefix (`Error::Cbor`), a component failure keeps its code. */ -const asNumber = (cbor) => { - if (cbor.type === MajorType.Unsigned) return cbor.value; - if (cbor.type === MajorType.Negative) if (typeof cbor.value === "bigint") return -cbor.value - 1n; - else return -cbor.value - 1; - if (cbor.type === MajorType.Simple) { - const simple = cbor.value; - if (isFloat$1(simple)) return simple.value; +function decodeComponent(f) { + try { + return f(); + } catch (e) { + if (CborError.isCborError(e)) throw ComponentsError.cbor(e.message, e); + if (ComponentsError.isComponentsError(e) && e.details.code === "Cbor" && e.message === e.details.message) { + const inner = e.cause; + if (CborError.isCborError(inner)) throw ComponentsError.cbor(inner.message, inner); + } + throw e; } -}; +} /** -* Extract unsigned integer value, throwing if type doesn't match. -* -* @param cbor - CBOR value -* @returns Unsigned integer -* @throws {CborError} With type 'WrongType' if cbor is not an unsigned integer +* Tagged CBOR memo, keyed by the value object. Every codable type here is an +* immutable value (readonly fields, no setters) except `Seed`, whose setters +* call `forgetTaggedCbor`. The memo makes repeated `toCbor().toData()` / +* `Digest.fromImage(...)` calls on the same object (references, XIDs, +* envelope leaf digests) free after the first. */ -const expectUnsigned = (cbor) => { - const value = asUnsigned(cbor); - if (value === void 0) throw new CborError({ type: "WrongType" }); - return value; -}; +const TAGGED_CBOR = /* @__PURE__ */ new WeakMap(); +/** The value's untagged CBOR wrapped in its first tag; memoised per object. */ +function taggedCborOf(value) { + const memo = TAGGED_CBOR.get(value); + if (memo !== void 0) return memo; + const tag = value.cborTags()[0]; + if (tag === void 0) throw new Error("No tags defined for this type"); + const out = taggedValue(tag, value.untaggedCbor()); + TAGGED_CBOR.set(value, out); + return out; +} +/** Drop the memoised tagged CBOR of a value that has just been mutated. */ +function forgetTaggedCbor(value) { + TAGGED_CBOR.delete(value); +} +/** See {@link mapGetBoolean}. */ +function mapGetText(map, key) { + const v = map.get(key); + return v === void 0 ? void 0 : asText(v); +} +/** See {@link mapGetBoolean}: a value that is not a decodable tagged date is absent. */ +function mapGetDate(map, key) { + const v = map.get(key); + if (v === void 0) return void 0; + try { + return CborDate.fromTaggedCbor(v); + } catch { + return; + } +} /** -* Extract any integer value, throwing if type doesn't match. +* Convert a Uint8Array to a base64-encoded string. * -* @param cbor - CBOR value -* @returns Integer -* @throws {CborError} With type 'WrongType' if cbor is not an integer -*/ -const expectInteger = (cbor) => { - const value = asInteger(cbor); - if (value === void 0) throw new CborError({ type: "WrongType" }); - return value; -}; -/** -* Extract byte string value, throwing if type doesn't match. +* This function works in both browser and Node.js environments. +* Uses btoa which is available in browsers and Node.js 16+. * -* @param cbor - CBOR value -* @returns Byte string -* @throws {CborError} With type 'WrongType' if cbor is not a byte string -*/ -const expectBytes = (cbor) => { - const value = asBytes(cbor); - if (value === void 0) throw new CborError({ type: "WrongType" }); - return value; -}; -/** -* Extract text string value, throwing if type doesn't match. +* @param data - The byte array to encode +* @returns A base64-encoded string * -* @param cbor - CBOR value -* @returns Text string -* @throws {CborError} With type 'WrongType' if cbor is not a text string +* @example +* ```typescript +* const bytes = new Uint8Array([72, 101, 108, 108, 111]); // "Hello" +* toBase64(bytes); // "SGVsbG8=" +* ``` */ -const expectText = (cbor) => { - const value = asText(cbor); - if (value === void 0) throw new CborError({ type: "WrongType" }); - return value; -}; +function toBase64$1(data) { + let binary = ""; + for (const byte of data) binary += String.fromCharCode(byte); + return btoa(binary); +} /** -* Extract array value, throwing if type doesn't match. +* Compare two Uint8Arrays for equality using constant-time comparison. * -* @param cbor - CBOR value -* @returns Array -* @throws {CborError} With type 'WrongType' if cbor is not an array -*/ -const expectArray = (cbor) => { - const value = asArray(cbor); - if (value === void 0) throw new CborError({ type: "WrongType" }); - return value; -}; -/** -* Extract map value, throwing if type doesn't match. +* This function is designed to be resistant to timing attacks by always +* comparing all bytes regardless of where a difference is found. The +* comparison time depends only on the length of the arrays, not on where +* they differ. * -* @param cbor - CBOR value -* @returns Map -* @throws {CborError} With type 'WrongType' if cbor is not a map -*/ -const expectMap = (cbor) => { - const value = asMap(cbor); - if (value === void 0) throw new CborError({ type: "WrongType" }); - return value; -}; -/** -* Extract boolean value, throwing if type doesn't match. +* **Security Note**: If the arrays have different lengths, this function +* returns `false` immediately, which does leak length information. For +* cryptographic uses where length should also be secret, ensure both +* arrays are the same length before comparison. * -* @param cbor - CBOR value -* @returns Boolean -* @throws {CborError} With type 'WrongType' if cbor is not a boolean -*/ -const expectBoolean = (cbor) => { - const value = asBoolean(cbor); - if (value === void 0) throw new CborError({ type: "WrongType" }); - return value; -}; -/** -* Extract any numeric value, throwing if type doesn't match. +* @param a - First byte array +* @param b - Second byte array +* @returns `true` if both arrays have the same length and identical contents * -* @param cbor - CBOR value -* @returns Number -* @throws {CborError} With type 'WrongType' if cbor is not a number -*/ -const expectNumber = (cbor) => { - const value = asNumber(cbor); - if (value === void 0) throw new CborError({ type: "WrongType" }); - return value; -}; -/** -* Get tag value from tagged CBOR. +* @example +* ```typescript +* const key1 = new Uint8Array([1, 2, 3, 4]); +* const key2 = new Uint8Array([1, 2, 3, 4]); +* const key3 = new Uint8Array([1, 2, 3, 5]); * -* @param cbor - CBOR value (must be tagged) -* @returns Tag value or undefined +* bytesEqual(key1, key2); // true +* bytesEqual(key1, key3); // false +* ``` */ -const tagValue = (cbor) => { - if (cbor.type !== MajorType.Tagged) return; - return cbor.tag; -}; +function bytesEqual$4(a, b) { + if (a.length !== b.length) return false; + let result = 0; + for (let i = 0; i < a.length; i++) result |= a[i] ^ b[i]; + return result === 0; +} +//#endregion +//#region ../bc-ur-ts/dist/domain-BEYQUr-y.mjs +/** The received value of an `InvalidParameter`, rendered so that no two values read alike. */ +function render$4(value) { + if (typeof value === "bigint") return `${value}n`; + if (typeof value === "number") return Number.isInteger(value) && !Number.isSafeInteger(value) ? BigInt(value).toString() : String(value); + if (typeof value === "string") return JSON.stringify(value); + if (typeof value === "function") return "function"; + if (Array.isArray(value)) return "Array"; + if (typeof value === "object" && value !== null) { + const name = value.constructor?.name; + return typeof name === "string" && name !== "" ? name : "object"; + } + return String(value); +} /** -* Extract content if has specific tag, throwing if not. +* Thrown for malformed UR strings (`InvalidScheme`, `TypeUnspecified`, +* `InvalidType`, `NotSinglePart`), a type other than the one expected +* (`UnexpectedType`), a bytewords failure in `decodeBytewords` +* (`Bytewords`), CBOR failures (`Cbor`), anything the reference's `ur` +* crate rejects inside a UR string or a part (`Decoder`: bytewords inside a +* UR string, the header, the part CBOR, the fountain decoder), an argument +* outside its domain (`InvalidParameter`) and a tag with no name to build a +* UR type from (`TagUnnamed`). Codes and messages are the reference's +* wherever it has an outcome; branch on `code`. * -* Mirrors Rust `try_into_expected_tagged_value`. Throws `{ type: "WrongType" }` -* if `cbor` is not tagged at all, otherwise `{ type: "WrongTag", expected, -* actual }` if the tag doesn't match. +* Instances come from the static factories only; a wrapped CBOR or part +* error is the `cause`. * -* @param cbor - CBOR value -* @param tag - Expected tag value -* @returns Tagged content +* @example +* ```ts +* try { +* UR.parse(s); +* } catch (e) { +* if (URError.isURError(e) && e.is("UnexpectedType")) { +* // e.details.expected, e.details.found +* } +* } +* ``` */ -const expectTaggedContent = (cbor, tag) => { - if (cbor.type !== MajorType.Tagged) throw new CborError({ type: "WrongType" }); - if (!tagValuesEqual(cbor.tag, tag)) throw new CborError({ - type: "WrongTag", - expected: { value: tag }, - actual: { value: cbor.tag } - }); - return cbor.value; +var URError = class URError extends Error { + /** Always `"URError"`; the cross-copy identity {@link URError.isURError} checks. */ + name = "URError"; + /** The discriminant; equals `details.code`. */ + code; + /** The structured payload, discriminated by `code`. */ + details; + constructor(message, details, cause) { + super(message, cause === void 0 ? void 0 : { cause }); + this.code = details.code; + this.details = details; + } + /** Type guard for a `URError`, including one from another copy of this package. */ + static isURError(value) { + return value instanceof Error && value.name === "URError" && "code" in value; + } + /** `true` when `code` is this error's code. */ + is(code) { + return this.code === code; + } + /** The string does not start with `ur:`. */ + static invalidScheme() { + return new URError("invalid UR scheme", { code: "InvalidScheme" }); + } + /** The string has no `/` after the scheme, so no type. */ + static typeUnspecified() { + return new URError("no UR type specified", { code: "TypeUnspecified" }); + } + /** The type uses a character outside `[a-z0-9-]`. */ + static invalidType() { + return new URError("invalid UR type", { code: "InvalidType" }); + } + /** A well-formed multipart header where a single-part UR was required. */ + static notSinglePart() { + return new URError("UR is not a single-part", { code: "NotSinglePart" }); + } + /** The UR's type is `found` where `expected` was required. */ + static unexpectedType(expected, found) { + return new URError(`expected UR type ${expected}, but found ${found}`, { + code: "UnexpectedType", + expected, + found + }); + } + /** A `decodeBytewords` failure, in the reference's words. */ + static bytewords(message) { + return new URError(`Bytewords error (${message})`, { code: "Bytewords" }); + } + /** A CBOR failure; the dcbor error is the `cause` when one was caught. */ + static cbor(message, cause) { + return new URError(`CBOR error (${message})`, { code: "Cbor" }, cause); + } + /** Anything the reference's `ur` crate rejects, in its words (its `Error::UR`). */ + static decoder(message, cause) { + return new URError(`UR decoder error (${message})`, { code: "Decoder" }, cause); + } + /** `parameter` must be `requirement`; `value` is what was received, rendered exactly. */ + static invalidParameter(parameter, value, requirement) { + return new URError(`${parameter} must be ${requirement}, got ${render$4(value)}`, { + code: "InvalidParameter", + parameter, + value + }); + } + /** `tag` has no registered name, or (`undefined`) the codec has no tag at all. */ + static tagUnnamed(tag) { + return new URError(tag === void 0 ? "the codec has no tags; a UR type needs a named tag" : `CBOR tag ${String(tag)} must have a name; register the tags first`, { + code: "TagUnnamed", + tag + }); + } }; +/** A `Uint8Array` from any realm (`Buffer` included), never another typed array. */ +function isBytes$6(value) { + return value instanceof Uint8Array || ArrayBuffer.isView(value) && value.constructor.name === "Uint8Array"; +} +/** Throws `InvalidParameter` unless `value` is a `Uint8Array`. */ +function expectBytes(parameter, value) { + if (!isBytes$6(value)) throw URError.invalidParameter(parameter, value, "a Uint8Array"); + return value; +} +/** Throws `InvalidParameter` unless `value` is a string. */ +function expectString(parameter, value) { + if (typeof value !== "string") throw URError.invalidParameter(parameter, value, "a string"); + return value; +} +/** `value` when it is one of `allowed`, `fallback` when it is `undefined`; `InvalidParameter` otherwise. */ +function expectChoice(parameter, value, allowed, fallback) { + if (value === void 0) return fallback; + if (typeof value === "string" && allowed.includes(value)) return value; + throw URError.invalidParameter(parameter, value, `one of ${allowed.map((s) => JSON.stringify(s)).join(", ")}`); +} +//#endregion +//#region ../../node_modules/@noble/hashes/utils.js /** -* Extract tagged value as tuple [Tag, Cbor] if CBOR is tagged. -* This is used by envelope for decoding. -* -* @param cbor - CBOR value -* @returns [Tag, Cbor] tuple or undefined +* Checks if something is Uint8Array. Be careful: nodejs Buffer will return true. +* @param a - value to test +* @returns `true` when the value is a Uint8Array-compatible view. +* @example +* Check whether a value is a Uint8Array-compatible view. +* ```ts +* isBytes(new Uint8Array([1, 2, 3])); +* ``` */ -const asTaggedValue = (cbor) => { - if (cbor.type !== MajorType.Tagged) return; - return [getGlobalTagsStore().tagForValue(cbor.tag) ?? { value: cbor.tag }, cbor.value]; -}; +function isBytes$5(a) { + return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array" && "BYTES_PER_ELEMENT" in a && a.BYTES_PER_ELEMENT === 1; +} +const atitle$2 = (title) => title ? `"${title}" ` : ""; /** -* Alias for asBytes - extract byte string value if type matches. -* Named asByteString for envelope compatibility. -* -* @param cbor - CBOR value -* @returns Byte string or undefined +* Asserts something is a non-negative integer. +* @param n - number to validate +* @param title - label included in thrown errors +* @returns The validated number. +* @throws On wrong argument types. {@link TypeError} +* @throws On wrong argument ranges or values. {@link RangeError} +* @example +* Validate a non-negative integer option. +* ```ts +* anumber(32, 'length'); +* ``` */ -const asByteString = asBytes; +function anumber$2(n, title = "") { + if (typeof n !== "number") throw new TypeError(atitle$2(title) + "expected number, got " + typeof n); + if (!Number.isSafeInteger(n) || n < 0) throw new RangeError(atitle$2(title) + "expected integer >= 0, got " + n); + return n; +} /** -* Extract array value with get() method for envelope compatibility. -* -* @param cbor - CBOR value -* @returns Array wrapper with get() method or undefined +* Asserts something is a boolean. +* @param value - value to validate +* @param title - label included in thrown errors +* @returns The validated boolean. +* @throws On wrong argument types. {@link TypeError} +* @example +* Validate a boolean option. +* ```ts +* abool(true, 'enableXOF'); +* ``` */ -const asCborArray = (cbor) => { - if (cbor.type !== MajorType.Array) return; - const arr = cbor.value; - return { - length: arr.length, - get(index) { - return arr[index]; - }, - [Symbol.iterator]() { - return arr[Symbol.iterator](); - } - }; -}; -/** -* Alias for asMap - extract map value if type matches. -* Named asCborMap for envelope compatibility. -* -* @param cbor - CBOR value -* @returns Map or undefined -*/ -const asCborMap = asMap; +function abool$2(value, title = "") { + if (typeof value !== "boolean") throw new TypeError(atitle$2(title) + "expected boolean, got type=" + typeof value); + return value; +} /** -* Check if CBOR value is any numeric type (unsigned, negative, or float). -* -* @param cbor - CBOR value -* @returns True if value is numeric +* Asserts something is Uint8Array. +* @param value - value to validate +* @param length - optional exact length constraint +* @param title - label included in thrown errors +* @returns The validated byte array. +* @throws On wrong argument types. {@link TypeError} +* @throws On wrong argument ranges or values. {@link RangeError} +* @example +* Validate that a value is a byte array. +* ```ts +* abytes(new Uint8Array([1, 2, 3])); +* ``` */ -const isNumber = (cbor) => { - if (cbor.type === MajorType.Unsigned || cbor.type === MajorType.Negative) return true; - if (cbor.type === MajorType.Simple) return isFloat$1(cbor.value); - return false; -}; +function abytes$2(value, length, title = "") { + if (isBytes$5(value) && (length === void 0 || value.length === length)) return value; + if (length !== void 0) anumber$2(length, "length"); + const bytes = isBytes$5(value); + const ofLen = length !== void 0 ? ` of length ${length}` : ""; + const got = bytes ? `length=${value.length}` : `type=${typeof value}`; + const message = atitle$2(title) + "expected Uint8Array" + ofLen + ", got " + got; + if (!bytes) throw new TypeError(message); + throw new RangeError(message); +} /** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -* -* Map Support in dCBOR -* -* A deterministic CBOR map that ensures maps with the same content always -* produce identical binary encodings, regardless of insertion order. -* -* This class keeps the historical `@bcts/dcbor` map API (Rust-flavored -* `insert`/`containsKey`/`len`/`iter` alongside the JS `Map` vocabulary) but -* stores its entries in a `@blockchaincommons/dcbor` `CborMap` — the -* canonical implementation owns key ordering (lexicographic by encoded CBOR -* bytes), duplicate handling, and the decode-time `setNext` ordering checks. -* -* @module map +* Copies bytes into a fresh Uint8Array. +* Buffer-style slices can alias the same backing store, so callers that need ownership should copy. +* @param bytes - source bytes to clone +* @returns Freshly allocated copy of `bytes`. +* @throws On wrong argument types. {@link TypeError} +* @example +* Clone a byte array before mutating it. +* ```ts +* const copy = copyBytes(new Uint8Array([1, 2, 3])); +* ``` */ +function copyBytes$3(bytes) { + return Uint8Array.from(abytes$2(bytes)); +} /** -* A deterministic CBOR map implementation. -* -* Maps are always encoded with keys sorted lexicographically by their -* encoded CBOR representation, ensuring deterministic encoding. +* Asserts something is a wrapped hash constructor. +* @param h - hash constructor to validate +* @throws On wrong argument types or invalid hash wrapper shape. {@link TypeError} +* @throws On invalid hash metadata ranges or values. {@link RangeError} +* @throws If the hash metadata allows empty outputs or block sizes. {@link Error} +* @example +* Validate a callable hash wrapper. +* ```ts +* import { ahash } from '@noble/hashes/utils.js'; +* import { sha256 } from '@noble/hashes/sha2.js'; +* ahash(sha256); +* ``` */ -var CborMap = class CborMap { - _map; - /** - * Creates a new, empty CBOR Map. - * Optionally initializes from a JavaScript Map. - */ - constructor(map) { - this._map = new CborMap$1(); - if (map !== void 0) for (const [key, value] of map.entries()) this.set(key, value); - } - /** - * The wrapped canonical `@blockchaincommons/dcbor` map. - * @internal - */ - get _inner() { - return this._map; - } - /** - * Wrap an existing canonical map without copying entries. - * @internal - */ - static _fromInner(inner) { - const map = new CborMap(); - map._map = inner; - return map; - } - /** - * Creates a new, empty CBOR Map. - * Matches Rust's Map::new(). - */ - static new() { - return new CborMap(); - } - /** - * Inserts a key-value pair into the map. - * Matches Rust's Map::insert(). - */ - set(key, value) { - const keyCbor = cbor(key); - const valueCbor = cbor(value); - delegating(() => this._map.set(toNew(keyCbor), toNew(valueCbor))); - } - /** - * Alias for set() to match Rust's insert() method. - */ - insert(key, value) { - this.set(key, value); - } - /** - * Get a value from the map, given a key. - * Returns undefined if the key is not present in the map. - * Matches Rust's Map::get(). - */ - get(key) { - const stored = delegating(() => this._map.get(toNew(cbor(key)))); - if (stored === void 0) return; - return extractCbor(fromNew(stored)); - } - /** - * Get a value from the map, given a key. - * Throws an error if the key is not present. - * Matches Rust's Map::extract(). - */ - extract(key) { - const value = this.get(key); - if (value === void 0) throw new CborError({ type: "MissingMapKey" }); - return value; - } - /** - * Tests if the map contains a key. - * Matches Rust's Map::contains_key(). - */ - containsKey(key) { - return delegating(() => this._map.has(toNew(cbor(key)))); - } - delete(key) { - return delegating(() => this._map.delete(toNew(cbor(key)))); - } - has(key) { - return this.containsKey(key); - } - clear() { - this._map.clear(); - } - /** - * Returns the number of entries in the map. - * Matches Rust's Map::len(). - */ - get length() { - return this._map.size; - } - /** - * Alias for length to match JavaScript Map API. - * Also matches Rust's Map::len(). - */ - get size() { - return this._map.size; - } - /** - * Returns the number of entries in the map. - * Matches Rust's Map::len(). - */ - len() { - return this._map.size; - } - /** - * Checks if the map is empty. - * Matches Rust's Map::is_empty(). - */ - isEmpty() { - return this._map.size === 0; - } - /** - * Get the entries of the map as an array. - * Keys are sorted in lexicographic order of their encoded CBOR bytes. - */ - get entriesArray() { - const entries = []; - for (const [key, value] of this._map.entries()) entries.push({ - key: fromNew(key), - value: fromNew(value) - }); - return entries; - } - /** - * Gets an iterator over the entries of the CBOR map, sorted by key. - * Key sorting order is lexicographic by the key's binary-encoded CBOR. - * Matches Rust's Map::iter(). - */ - iter() { - return this.entriesArray; - } - /** - * Returns an iterator of [key, value] tuples for JavaScript Map API compatibility. - * This matches the standard JavaScript Map.entries() method behavior. - */ - *entries() { - for (const entry of this.entriesArray) yield [entry.key, entry.value]; - } - /** - * Inserts the next key-value pair into the map during decoding. - * This is used for efficient map building during CBOR decoding. - * Throws if the key is not in ascending order or is a duplicate. - * Matches Rust's Map::insert_next(). - */ - setNext(key, value) { - const keyCbor = cbor(key); - const valueCbor = cbor(value); - delegating(() => this._map.setNext(toNew(keyCbor), toNew(valueCbor))); - } - get debug() { - return `map({${this.entriesArray.map(CborMap.entryDebug).join(", ")}})`; - } - get diagnostic() { - return `{${this.entriesArray.map(CborMap.entryDiagnostic).join(", ")}}`; - } - static entryDebug(entry) { - const keyDebug = CborMap.formatDebug(entry.key); - const valueDebug = CborMap.formatDebug(entry.value); - return `0x${bytesToHex$4(encodeCbor$1(entry.key))}: (${keyDebug}, ${valueDebug})`; - } - static formatDebug(cbor) { - switch (cbor.type) { - case MajorType.Unsigned: return `unsigned(${cbor.value})`; - case MajorType.Negative: return `negative(${typeof cbor.value === "bigint" ? -cbor.value - 1n : -cbor.value - 1})`; - case MajorType.ByteString: return `bytes(${bytesToHex$4(cbor.value)})`; - case MajorType.Text: return `text("${cbor.value}")`; - case MajorType.Array: return `array([${cbor.value.map(CborMap.formatDebug).join(", ")}])`; - case MajorType.Map: return cbor.value.debug; - case MajorType.Tagged: return `tagged(${cbor.tag}, ${CborMap.formatDebug(cbor.value)})`; - case MajorType.Simple: { - const simple = cbor.value; - if (typeof simple === "object" && simple !== null && "type" in simple) switch (simple.type) { - case "True": return "simple(true)"; - case "False": return "simple(false)"; - case "Null": return "simple(null)"; - case "Float": return `simple(${simple.value})`; - } - return "simple"; - } - default: return diagnostic(cbor); - } - } - static entryDiagnostic(entry) { - return `${diagnostic(entry.key)}: ${diagnostic(entry.value)}`; - } - *[Symbol.iterator]() { - for (const entry of this.entriesArray) yield [entry.key, entry.value]; - } - toMap() { - const map = /* @__PURE__ */ new Map(); - for (const entry of this.entriesArray) map.set(extractCbor(entry.key), extractCbor(entry.value)); - return map; - } +function ahash(h) { + if (typeof h !== "function" || typeof h.create !== "function") throw new TypeError("expected hash wrapped by utils.createHasher"); + anumber$2(h.outputLen); + anumber$2(h.blockLen); + if (h.outputLen < 1 || h.blockLen < 1) throw new Error("hash blockLen / outputLen must be >= 1"); +} +const aobject$3 = (value, label) => { + if (value === null || typeof value !== "object" || Array.isArray(value)) throw new TypeError((label === "object" ? "" : `"${label}" `) + "expected object, got type=" + typeof value); }; -/** -* Clone helper used to give each descendant subtree an independent copy of -* the post-visit state — mirrors Rust `State: Clone` + `state.clone()` per -* child in `walk.rs`. Falls back to the value as-is for primitives (which -* don't need cloning) and uses `structuredClone` for objects. -*/ -const cloneState = (s) => { - if (s === null) return s; - const t = typeof s; - if (t !== "object" && t !== "function") return s; - return globalThis.structuredClone(s); +const aopts = (value, label) => { + aobject$3(value, label); + const proto = Object.getPrototypeOf(value); + if (proto !== Object.prototype && proto !== null) throw new TypeError(`"${label}" expected plain object`); + if (Object.hasOwn(value, "__proto__")) throw new TypeError(`"${label}.__proto__" is not allowed`); }; /** -* Walk a CBOR tree, visiting each element with a visitor function. -* -* The visitor function is called for each element in the tree, in depth-first order. -* State semantics mirror Rust's `walk_internal`: -* -* - The visitor's returned `newState` propagates **down** to descendants of -* the just-visited node only. -* - Sibling subtrees each receive an independent clone of the parent's -* post-visit state, so accumulating mutations in one subtree never leak -* into a sibling. -* - State changes do not propagate **up**: the public `walk` returns `void`. -* -* For maps, the visitor is called with: -* 1. A 'keyvalue' element containing both key and value -* 2. The key individually (if descent wasn't stopped) -* 3. The value individually (if descent wasn't stopped) -* -* @template State - The type of state to pass into each visit -* @param cbor - The CBOR value to traverse -* @param initialState - Initial state value -* @param visitor - Function to call for each element +* Asserts a hash instance has not been destroyed or finished. +* @param instance - hash instance to validate +* @param checkFinished - whether to reject finalized instances +* @throws If the hash instance has already been destroyed or finalized. {@link Error} +* @example +* Validate that a hash instance is still usable. +* ```ts +* import { aexists } from '@noble/hashes/utils.js'; +* import { sha256 } from '@noble/hashes/sha2.js'; +* const hash = sha256.create(); +* aexists(hash); +* ``` */ -const walk = (cbor, initialState, visitor) => { - walkInternal(cbor, 0, { type: "none" }, initialState, visitor); -}; +function aexists$1(instance, checkFinished = true) { + if (instance.destroyed) throw new Error("hash was destroyed"); + if (checkFinished && instance.finished) throw new Error("digest() was already called"); +} /** -* Internal recursive walk implementation. -* -* @internal +* Asserts output is a sufficiently-sized byte array. +* @param out - destination buffer +* @param instance - hash instance providing output length +* Oversized buffers are allowed; downstream code only promises to fill the first `outputLen` bytes. +* @throws On wrong argument types. {@link TypeError} +* @throws On wrong argument ranges or values. {@link RangeError} +* @example +* Validate a caller-provided digest buffer. +* ```ts +* import { aoutput } from '@noble/hashes/utils.js'; +* import { sha256 } from '@noble/hashes/sha2.js'; +* const hash = sha256.create(); +* aoutput(new Uint8Array(hash.outputLen), hash); +* ``` */ -function walkInternal(cbor, level, edge, state, visitor) { - const [postVisitState, stop] = visitor({ - type: "single", - cbor - }, level, edge, state); - if (stop) return; - switch (cbor.type) { - case MajorType.Array: - walkArray(cbor, level, postVisitState, visitor); - break; - case MajorType.Map: - walkMap(cbor, level, postVisitState, visitor); - break; - case MajorType.Tagged: walkTagged(cbor, level, postVisitState, visitor); - } +function aoutput$1(out, instance) { + abytes$2(out, void 0, "output"); + const min = instance.outputLen; + if (!(out.length >= min)) throw new RangeError("\"output\" expected length >= " + min); } /** -* Walk an array's elements. Each element is visited with an independent -* clone of `parentState`. -* -* @internal +* Casts a typed array view to Uint8Array. +* @param arr - source typed array +* @returns Uint8Array view over the same buffer. +* @example +* Reinterpret a typed array as bytes. +* ```ts +* u8(new Uint32Array([1, 2])); +* ``` */ -function walkArray(cbor, level, parentState, visitor) { - for (let index = 0; index < cbor.value.length; index++) { - const item = cbor.value[index]; - if (item === void 0) throw new CborError({ - type: "Custom", - message: `Array element at index ${index} is undefined` - }); - walkInternal(item, level + 1, { - type: "array_element", - index - }, cloneState(parentState), visitor); - } +function u8(arr) { + return new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength); } /** -* Walk a map's key-value pairs. -* -* Each kv pair receives a clone of `parentState`. If descent isn't stopped, -* the key and value subtrees receive independent clones of the kv-visit's -* post-visit state. -* -* @internal +* Casts a typed array view to Uint32Array. +* `arr.byteOffset` must already be 4-byte aligned or the platform +* Uint32Array constructor will throw. +* @param arr - source typed array +* @returns Uint32Array view over the same buffer. +* @example +* Reinterpret a byte array as 32-bit words. +* ```ts +* u32(new Uint8Array(8)); +* ``` */ -function walkMap(cbor, level, parentState, visitor) { - for (const entry of cbor.value.entriesArray) { - const { key, value } = entry; - const [kvPostState, kvStop] = visitor({ - type: "keyvalue", - key, - value - }, level + 1, { type: "map_key_value" }, cloneState(parentState)); - if (kvStop) continue; - walkInternal(key, level + 1, { type: "map_key" }, cloneState(kvPostState), visitor); - walkInternal(value, level + 1, { type: "map_value" }, cloneState(kvPostState), visitor); - } +function u32$1(arr) { + return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4)); } /** -* Walk a tagged value's content. The content visit receives a clone of -* `parentState`. -* -* @internal +* Zeroizes typed arrays in place. Warning: JS provides no guarantees. +* @param arrays - arrays to overwrite with zeros +* @example +* Zeroize sensitive buffers in place. +* ```ts +* clean(new Uint8Array([1, 2, 3])); +* ``` */ -function walkTagged(cbor, level, parentState, visitor) { - walkInternal(cbor.value, level + 1, { type: "tagged_content" }, cloneState(parentState), visitor); +function clean$1(...arrays) { + for (let i = 0; i < arrays.length; i++) arrays[i].fill(0); } /** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* +* Creates a DataView for byte-level manipulation. +* @param arr - source typed array +* @returns DataView over the same buffer region. +* @example +* Create a DataView over an existing buffer. +* ```ts +* createView(new Uint8Array(4)); +* ``` */ -const MajorType = { - Unsigned: 0, - Negative: 1, - ByteString: 2, - Text: 3, - Array: 4, - Map: 5, - Tagged: 6, - Simple: 7 -}; -const MajorTypeNames = { - [MajorType.Unsigned]: "Unsigned", - [MajorType.Negative]: "Negative", - [MajorType.ByteString]: "ByteString", - [MajorType.Text]: "Text", - [MajorType.Array]: "Array", - [MajorType.Map]: "Map", - [MajorType.Tagged]: "Tagged", - [MajorType.Simple]: "Simple" -}; -const getMajorTypeName = (type) => MajorTypeNames[type]; -const isCborNumber = (value) => { - return typeof value === "number" || typeof value === "bigint"; -}; -const isCbor = (value) => { - return value !== null && typeof value === "object" && "isCbor" in value && value.isCbor === true; -}; +function createView$1(arr) { + return new DataView(arr.buffer, arr.byteOffset, arr.byteLength); +} /** -* Type guard to check if value has taggedCbor method. +* Rotate-right operation for uint32 values. +* @param word - source word +* @param shift - shift amount in bits +* @returns Rotated word. +* @example +* Rotate a 32-bit word to the right. +* ```ts +* rotr(0x12345678, 8); +* ``` */ +function rotr(word, shift) { + return word << 32 - shift | word >>> shift; +} /** -* Resolve a numeric/bigint tag value to a `Tag` object, looking up the -* canonical name from the global tags store (matches Rust's -* `try_into_tagged_value` returning the stored `Tag`). Falls back to a -* name-less `{ value }` if no name is registered — never synthesizes a -* placeholder `tag-${value}` string. +* Rotate-left operation for uint32 values. +* @param word - source word +* @param shift - shift amount in bits +* @returns Rotated word. +* @example +* Rotate a 32-bit word to the left. +* ```ts +* rotl(0x12345678, 8); +* ``` */ -const resolveTag = (value) => { - const stored = getGlobalTagsStore().tagForValue(value); - if (stored !== void 0) return stored; - return { value }; -}; -const hasTaggedCbor = (value) => { - return typeof value === "object" && value !== null && "taggedCbor" in value && typeof value.taggedCbor === "function"; -}; +function rotl$1(word, shift) { + return word << shift | word >>> 32 - shift >>> 0; +} +/** Whether the current platform is little-endian. */ +const isLE$1 = /* @__PURE__ */ (() => new Uint8Array(new Uint32Array([287454020]).buffer)[0] === 68)(); /** -* Type guard to check if value has toCbor method. +* Byte-swap operation for uint32 values. +* @param word - source word +* @returns Word with reversed byte order. +* @example +* Reverse the byte order of a 32-bit word. +* ```ts +* byteSwap(0x11223344); +* ``` */ -const hasToCbor = (value) => { - return typeof value === "object" && value !== null && "toCbor" in value && typeof value.toCbor === "function"; -}; +function byteSwap$1(word) { + return word << 24 & 4278190080 | word << 8 & 16711680 | word >>> 8 & 65280 | word >>> 24 & 255; +} /** -* Convert any value to a CBOR representation. -* Matches Rust's `From` trait implementations for CBOR. +* Conditionally byte-swaps one 32-bit word on big-endian platforms. +* @param n - source word +* @returns Original or byte-swapped word depending on platform endianness. +* @example +* Normalize a 32-bit word for host endianness. +* ```ts +* swap8IfBE(0x11223344); +* ``` */ -const cbor = (value) => { - if (isCbor(value) && "toData" in value) return value; - if (isCbor(value)) return attachMethods(value); - let result; - if (isCborNumber(value)) if (typeof value === "number" && Number.isNaN(value)) result = { - isCbor: true, - type: MajorType.Simple, - value: { - type: "Float", - value: NaN - } - }; - else if (typeof value === "number" && hasFractionalPart(value)) result = { - isCbor: true, - type: MajorType.Simple, - value: { - type: "Float", - value - } - }; - else if (value == Infinity) result = { - isCbor: true, - type: MajorType.Simple, - value: { - type: "Float", - value: Infinity - } - }; - else if (value == -Infinity) result = { - isCbor: true, - type: MajorType.Simple, - value: { - type: "Float", - value: -Infinity - } - }; - else if (typeof value === "number" && !Number.isSafeInteger(value)) { - const big = BigInt(value); - if (big >= 0n && big <= 18446744073709551615n) result = { - isCbor: true, - type: MajorType.Unsigned, - value: big - }; - else if (big < 0n && big >= -18446744073709551616n) result = { - isCbor: true, - type: MajorType.Negative, - value: -big - 1n - }; - else result = { - isCbor: true, - type: MajorType.Simple, - value: { - type: "Float", - value - } - }; - } else if (typeof value === "bigint" && (value > 18446744073709551615n || value < -18446744073709551616n)) throw new CborError({ type: "OutOfRange" }); - else if (value < 0) if (typeof value === "bigint") result = { - isCbor: true, - type: MajorType.Negative, - value: -value - 1n - }; - else result = { - isCbor: true, - type: MajorType.Negative, - value: -value - 1 - }; - else result = { - isCbor: true, - type: MajorType.Unsigned, - value - }; - else if (typeof value === "string") { - const normalized = value.normalize("NFC"); - result = { - isCbor: true, - type: MajorType.Text, - value: normalized - }; - } else if (value === null || value === void 0) result = { - isCbor: true, - type: MajorType.Simple, - value: { type: "Null" } - }; - else if (value === true) result = { - isCbor: true, - type: MajorType.Simple, - value: { type: "True" } - }; - else if (value === false) result = { - isCbor: true, - type: MajorType.Simple, - value: { type: "False" } - }; - else if (Array.isArray(value)) result = { - isCbor: true, - type: MajorType.Array, - value: value.map(cbor) - }; - else if (value instanceof Uint8Array) result = { - isCbor: true, - type: MajorType.ByteString, - value - }; - else if (value instanceof CborMap) result = { - isCbor: true, - type: MajorType.Map, - value - }; - else if (value instanceof Map) result = { - isCbor: true, - type: MajorType.Map, - value: new CborMap(value) - }; - else if (value instanceof Set) result = { - isCbor: true, - type: MajorType.Array, - value: Array.from(value).map((v) => cbor(v)) - }; - else if (hasTaggedCbor(value)) return value.taggedCbor(); - else if (hasToCbor(value)) return value.toCbor(); - else if (typeof value === "object" && value !== null && "tag" in value && "value" in value) { - const keys = Object.keys(value); - const objValue = value; - if (keys.length === 2 && keys.includes("tag") && keys.includes("value")) return taggedCbor(objValue.tag, objValue.value); - const map = new CborMap(); - for (const [key, val] of Object.entries(value)) map.set(cbor(key), cbor(val)); - result = { - isCbor: true, - type: MajorType.Map, - value: map - }; - } else if (typeof value === "object" && value !== null) { - const map = new CborMap(); - for (const [key, val] of Object.entries(value)) map.set(cbor(key), cbor(val)); - result = { - isCbor: true, - type: MajorType.Map, - value: map - }; - } else throw new CborError({ - type: "Custom", - message: "Unsupported type for CBOR encoding" - }); - return attachMethods(result); -}; +const swap8IfBE = isLE$1 ? (n) => n : (n) => byteSwap$1(n) >>> 0; /** -* Encode a CBOR value to binary data. -* Matches Rust's `CBOR::to_cbor_data()` method. -* -* Delegates to `@blockchaincommons/dcbor` — the canonical encoder — via the -* structural node bridge. +* Byte-swaps every word of a Uint32Array in place. +* @param arr - array to mutate +* @returns The same array after mutation; callers pass live state arrays here. +* @example +* Reverse the byte order of every word in place. +* ```ts +* byteSwap32(new Uint32Array([0x11223344])); +* ``` */ -const cborData = (value) => { - const c = cbor(value); - return delegating(() => encodeCbor(toNew(c))); -}; -const encodeCbor$1 = (value) => { - return cborData(cbor(value)); -}; -const taggedCbor = (tag, value) => { - const tagNumber = typeof tag === "number" || typeof tag === "bigint" ? tag : Number(tag); - return attachMethods({ - isCbor: true, - type: MajorType.Tagged, - tag: tagNumber, - value: cbor(value) - }); -}; -const toByteString = (data) => { - return cbor(data); -}; -const toTaggedValue = (tag, item) => { - const tagValue = typeof tag === "object" && "value" in tag ? tag.value : tag; - return attachMethods({ - isCbor: true, - type: MajorType.Tagged, - tag: tagValue, - value: cbor(item) - }); -}; +function byteSwap32$1(arr) { + for (let i = 0; i < arr.length; i++) arr[i] = byteSwap$1(arr[i]); + return arr; +} /** -* Attaches instance methods to a CBOR value. -* This enables method chaining like cbor.toHex() instead of Cbor.toHex(cbor). -* @internal +* Conditionally byte-swaps a Uint32Array on big-endian platforms. +* @param u - array to normalize for host endianness +* @returns Original or byte-swapped array depending on platform endianness. +* On big-endian runtimes this mutates `u` in place via `byteSwap32(...)`. +* @example +* Normalize a word array for host endianness. +* ```ts +* swap32IfBE(new Uint32Array([0x11223344])); +* ``` */ -const attachMethods = (obj) => { - return Object.assign(obj, { - toData() { - return cborData(this); - }, - toHex() { - return bytesToHex$4(cborData(this)); - }, - toHexAnnotated(tagsStore) { - tagsStore = tagsStore ?? getGlobalTagsStore(); - return hexOpt(this, { - annotate: true, - tagsStore - }); - }, - toString() { - return diagnosticOpt(this, { flat: true }); - }, - toDebugString() { - return diagnosticOpt(this, { flat: false }); - }, - toDiagnostic() { - return diagnosticOpt(this, { flat: false }); - }, - toDiagnosticAnnotated() { - return diagnosticOpt(this, { annotate: true }); - }, - isByteString() { - return this.type === MajorType.ByteString; - }, - isText() { - return this.type === MajorType.Text; - }, - isArray() { - return this.type === MajorType.Array; - }, - isMap() { - return this.type === MajorType.Map; - }, - isTagged() { - return this.type === MajorType.Tagged; - }, - isSimple() { - return this.type === MajorType.Simple; - }, - isBool() { - return this.type === MajorType.Simple && (this.value.type === "True" || this.value.type === "False"); - }, - isTrue() { - return this.type === MajorType.Simple && this.value.type === "True"; - }, - isFalse() { - return this.type === MajorType.Simple && this.value.type === "False"; - }, - isNull() { - return this.type === MajorType.Simple && this.value.type === "Null"; - }, - isNumber() { - if (this.type === MajorType.Unsigned || this.type === MajorType.Negative) return true; - if (this.type === MajorType.Simple) return isFloat$1(this.value); - return false; - }, - isInteger() { - return this.type === MajorType.Unsigned || this.type === MajorType.Negative; - }, - isUnsigned() { - return this.type === MajorType.Unsigned; - }, - isNegative() { - return this.type === MajorType.Negative; - }, - isNaN() { - return this.type === MajorType.Simple && this.value.type === "Float" && Number.isNaN(this.value.value); - }, - isFloat() { - return this.type === MajorType.Simple && isFloat$1(this.value); - }, - asByteString() { - return this.type === MajorType.ByteString ? this.value : void 0; - }, - asText() { - return this.type === MajorType.Text ? this.value : void 0; - }, - asArray() { - return this.type === MajorType.Array ? this.value : void 0; - }, - asMap() { - return this.type === MajorType.Map ? this.value : void 0; - }, - asTagged() { - if (this.type !== MajorType.Tagged) return; - return [resolveTag(this.tag), this.value]; - }, - asBool() { - if (this.type !== MajorType.Simple) return void 0; - if (this.value.type === "True") return true; - if (this.value.type === "False") return false; - }, - asInteger() { - if (this.type === MajorType.Unsigned) return this.value; - else if (this.type === MajorType.Negative) if (typeof this.value === "bigint") return -this.value - 1n; - else return -this.value - 1; - }, - asNumber() { - if (this.type === MajorType.Unsigned) return this.value; - else if (this.type === MajorType.Negative) if (typeof this.value === "bigint") return -this.value - 1n; - else return -this.value - 1; - else if (this.type === MajorType.Simple && isFloat$1(this.value)) return this.value.value; - }, - asSimpleValue() { - return this.type === MajorType.Simple ? this.value : void 0; - }, - toByteString() { - if (this.type !== MajorType.ByteString) throw new TypeError(`Cannot convert CBOR to ByteString: expected ByteString type, got ${getMajorTypeName(this.type)}`); - return this.value; - }, - toText() { - if (this.type !== MajorType.Text) throw new TypeError(`Cannot convert CBOR to Text: expected Text type, got ${getMajorTypeName(this.type)}`); - return this.value; - }, - toArray() { - if (this.type !== MajorType.Array) throw new TypeError(`Cannot convert CBOR to Array: expected Array type, got ${getMajorTypeName(this.type)}`); - return this.value; - }, - toMap() { - if (this.type !== MajorType.Map) throw new TypeError(`Cannot convert CBOR to Map: expected Map type, got ${getMajorTypeName(this.type)}`); - return this.value; - }, - toTagged() { - if (this.type !== MajorType.Tagged) throw new TypeError(`Cannot convert CBOR to Tagged: expected Tagged type, got ${getMajorTypeName(this.type)}`); - return [resolveTag(this.tag), this.value]; - }, - toBool() { - const result = this.asBool(); - if (result === void 0) throw new TypeError(`Cannot convert CBOR to boolean: expected Simple(True/False) type, got ${getMajorTypeName(this.type)}`); - return result; - }, - toInteger() { - const result = this.asInteger(); - if (result === void 0) throw new TypeError(`Cannot convert CBOR to integer: expected Unsigned or Negative type, got ${getMajorTypeName(this.type)}`); - return result; - }, - toNumber() { - const result = this.asNumber(); - if (result === void 0) throw new TypeError(`Cannot convert CBOR to number: expected Unsigned, Negative, or Float type, got ${getMajorTypeName(this.type)}`); - return result; - }, - toSimpleValue() { - if (this.type !== MajorType.Simple) throw new TypeError(`Cannot convert CBOR to Simple: expected Simple type, got ${getMajorTypeName(this.type)}`); - return this.value; - }, - expectTag(expectedTag) { - if (this.type !== MajorType.Tagged) throw new CborError({ type: "WrongType" }); - const expected = typeof expectedTag === "object" && "value" in expectedTag ? expectedTag : { value: expectedTag }; - if (!tagValuesEqual(this.tag, expected.value)) throw new CborError({ - type: "WrongTag", - expected, - actual: { value: this.tag } - }); - return this.value; - }, - walk(initialState, visitor) { - walk(this, initialState, visitor); - }, - validateTag(expectedTags) { - if (this.type !== MajorType.Tagged) throw new CborError({ type: "WrongType" }); - const tagValue = this.tag; - const matchingTag = expectedTags.find((t) => tagValuesEqual(t.value, tagValue)); - if (matchingTag === void 0) throw new CborError({ - type: "WrongTag", - expected: expectedTags[0], - actual: { value: tagValue } - }); - return matchingTag; - }, - untagged() { - if (this.type !== MajorType.Tagged) throw new CborError({ type: "WrongType" }); - return this.value; - } - }); -}; -attachMethods({ - isCbor: true, - type: MajorType.Simple, - value: { type: "False" } -}), attachMethods({ - isCbor: true, - type: MajorType.Simple, - value: { type: "True" } -}), attachMethods({ - isCbor: true, - type: MajorType.Simple, - value: { type: "Null" } -}), attachMethods({ - isCbor: true, - type: MajorType.Simple, - value: { - type: "Float", - value: NaN - } -}); +const swap32IfBE$1 = isLE$1 ? (u) => u : byteSwap32$1; +const hasHexBuiltin = /* @__PURE__ */ (() => typeof Uint8Array.from([]).toHex === "function" && typeof Uint8Array.fromHex === "function")(); +const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0")); /** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -* -* Tagged CBOR encoding support. -* -* This module provides the `CborTaggedEncodable` interface, which enables types to -* be encoded as tagged CBOR values. -* -* CBOR tags provide semantic information about the encoded data. For example, -* tag 1 is used for dates, indicating that the value should be interpreted -* as a timestamp. The dCBOR library ensures these tags are encoded -* deterministically. -* -* This interface enables seamless encoding of TypeScript types to properly tagged CBOR -* values. -* -* @module cbor-tagged-encodable +* Convert byte array to hex string. +* Uses the built-in function when available and assumes it matches the tested +* fallback semantics. +* @param bytes - bytes to encode +* @returns Lowercase hexadecimal string. +* @throws On wrong argument types. {@link TypeError} +* @example +* Convert bytes to lowercase hexadecimal. +* ```ts +* bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])); // 'cafe0123' +* ``` */ +function bytesToHex$1(bytes) { + abytes$2(bytes); + if (hasHexBuiltin) return bytes.toHex(); + let hex = ""; + for (let i = 0; i < bytes.length; i++) hex += hexes[bytes[i]]; + return hex; +} +function asciiToBase16(ch) { + return ch >= 48 && ch <= 57 ? ch - 48 : ch >= 65 && ch <= 70 ? ch - 55 : ch >= 97 && ch <= 102 ? ch - 87 : void 0; +} /** -* Helper function to create tagged CBOR from an encodable object. -* -* Uses the first tag from cborTags(). -* -* @param encodable - Object implementing CborTaggedEncodable -* @returns Tagged CBOR value +* Convert hex string to byte array. Uses built-in function, when available. +* @param hex - hexadecimal string to decode +* @returns Decoded bytes. +* @throws On wrong argument types. {@link TypeError} +* @throws On wrong argument ranges or values. {@link RangeError} +* @example +* Decode lowercase hexadecimal into bytes. +* ```ts +* hexToBytes('cafe0123'); // Uint8Array.from([0xca, 0xfe, 0x01, 0x23]) +* ``` */ -const createTaggedCbor = (encodable) => { - const tags = encodable.cborTags(); - if (tags.length === 0) throw new CborError({ - type: "Custom", - message: "No tags defined for this type" - }); - const tag = tags[0]; - if (tag === void 0) throw new CborError({ - type: "Custom", - message: "Tag is undefined" - }); - const untagged = encodable.untaggedCbor(); - return attachMethods({ - isCbor: true, - type: MajorType.Tagged, - tag: tag.value, - value: untagged - }); -}; +function hexToBytes$1(hex) { + if (typeof hex !== "string") throw new TypeError("hex string expected, got " + typeof hex); + if (hasHexBuiltin) try { + return Uint8Array.fromHex(hex); + } catch (error) { + if (error instanceof SyntaxError) throw new RangeError(error.message); + throw error; + } + const hl = hex.length; + const al = hl / 2; + if (hl % 2) throw new RangeError("hex string expected, got unpadded hex of length " + hl); + const array = new Uint8Array(al); + for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) { + const n1 = asciiToBase16(hex.charCodeAt(hi)); + const n2 = asciiToBase16(hex.charCodeAt(hi + 1)); + if (n1 === void 0 || n2 === void 0) { + const char = hex[hi] + hex[hi + 1]; + throw new RangeError("hex string expected, got non-hex character \"" + char + "\" at index " + hi); + } + array[ai] = n1 * 16 + n2; + } + return array; +} /** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -* -* Tagged CBOR decoding support. -* -* This module provides the `CborTaggedDecodable` interface, which enables types to -* be decoded from tagged CBOR values. -* -* Tagged CBOR values include semantic information about how to interpret the -* data. This interface allows TypeScript types to verify that incoming CBOR data has the -* expected tag(s) and to decode the data appropriately. -* -* @module cbor-tagged-decodable +* Converts string to bytes using UTF8 encoding. +* Built-in doesn't validate input to be string: we do the check. +* Non-ASCII details are delegated to the platform `TextEncoder`. +* @param str - string to encode +* @returns UTF-8 encoded bytes. +* @throws On wrong argument types. {@link TypeError} +* @example +* Encode a string as UTF-8 bytes. +* ```ts +* utf8ToBytes('abc'); // Uint8Array.from([97, 98, 99]) +* ``` */ +function utf8ToBytes(str) { + if (typeof str !== "string") throw new TypeError("string expected"); + const encoded = new TextEncoder().encode(str); + try { + return new Uint8Array(encoded); + } finally { + clean$1(encoded); + } +} /** -* Helper function to validate that a CBOR value has one of the expected tags. -* -* @param cbor - CBOR value to validate -* @param expectedTags - Array of valid tags -* @returns The matching tag -* @throws Error if the value is not tagged or has an unexpected tag +* Helper for KDFs: consumes Uint8Array or string. +* String inputs are UTF-8 encoded; byte-array inputs stay aliased to the caller buffer. +* @param data - user-provided KDF input +* @param errorTitle - label included in thrown errors +* @returns Byte representation of the input. +* @throws On wrong argument types. {@link TypeError} +* @example +* Normalize KDF input to bytes. +* ```ts +* kdfInputToBytes('password'); +* ``` */ -const validateTag = (cbor, expectedTags) => { - if (cbor.type !== MajorType.Tagged) throw new CborError({ type: "WrongType" }); - const tagValue = cbor.tag; - const matchingTag = expectedTags.find((t) => tagValuesEqual(t.value, tagValue)); - if (matchingTag === void 0) throw new CborError({ - type: "WrongTag", - expected: expectedTags[0], - actual: { value: tagValue } - }); - return matchingTag; -}; +function kdfInputToBytes(data, errorTitle = "") { + if (typeof data === "string") return utf8ToBytes(data); + return abytes$2(data, void 0, errorTitle); +} /** -* Helper function to extract the content from a tagged CBOR value. -* -* @param cbor - Tagged CBOR value -* @returns The untagged content -* @throws Error if the value is not tagged +* Copies several Uint8Arrays into one. +* @param arrays - arrays to concatenate +* @returns Concatenated byte array. +* @throws On wrong argument types. {@link TypeError} +* @example +* Concatenate multiple byte arrays. +* ```ts +* concatBytes(new Uint8Array([1]), new Uint8Array([2])); +* ``` */ -const extractTaggedContent = (cbor) => { - if (cbor.type !== MajorType.Tagged) throw new CborError({ type: "WrongType" }); - return cbor.value; -}; +function concatBytes$2(...arrays) { + let sum = 0; + for (let i = 0; i < arrays.length; i++) { + const a = arrays[i]; + abytes$2(a); + sum += a.length; + } + const res = new Uint8Array(sum); + for (let i = 0, pad = 0; i < arrays.length; i++) { + const a = arrays[i]; + res.set(a, pad); + pad += a.length; + } + return res; +} /** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -* -* Date/time support for CBOR with tag(1) encoding. -* -* A CBOR-friendly representation of a date and time. -* -* The `CborDate` type keeps the historical `@bcts/dcbor` API -* (`fromTimestamp`/`timestamp()`/`fromDatetime`/`datetime()` alongside the -* tagged-CBOR protocol methods) but wraps the canonical -* `@blockchaincommons/dcbor` `CborDate`, which owns timestamp normalization -* (Rust `Date::from_timestamp` parity), strict RFC-3339 parsing, and -* ISO-8601 formatting. -* -* When encoded to CBOR, dates are represented as tag 1 followed by a numeric -* value representing the number of seconds since (or before) the Unix epoch -* (1970-01-01T00:00:00Z). The numeric value can be a positive or negative -* integer, or a floating-point value for dates with fractional seconds. -* -* @module date +* Merges default options and passed options. +* @param defaults - base option object +* @param opts - user overrides +* @param title - label included in thrown override errors +* @returns Fresh merged option object with a null prototype. +* @throws On wrong argument types. {@link TypeError} +* @example +* Merge user overrides onto default options. +* ```ts +* checkOpts({ dkLen: 32 }, { asyncTick: 10 }); +* ``` */ +function checkOpts$1(defaults, opts, title = "opts") { + aopts(defaults, "defaults"); + if (opts !== void 0) aopts(opts, title); + return Object.assign(Object.create(null), defaults, opts); +} /** -* A CBOR-friendly representation of a date and time. -* -* When encoded to CBOR, dates are represented as tag 1 followed by a numeric -* value representing the number of seconds since (or before) the Unix epoch -* (1970-01-01T00:00:00Z). The numeric value can be a positive or negative -* integer, or a floating-point value for dates with fractional seconds. -* -* # Features -* -* - Supports UTC dates with optional fractional seconds -* - Provides convenient constructors for common date creation patterns -* - Implements the `CborTagged`, `CborTaggedEncodable`, and -* `CborTaggedDecodable` interfaces -* - Supports arithmetic operations with durations and between dates -* +* Creates a callable hash function from a stateful class constructor. +* @param hashCons - hash constructor or factory +* @param info - optional metadata such as DER OID +* @returns Frozen callable hash wrapper with `.create()`. +* Wrapper construction eagerly calls `hashCons(undefined)` once to read +* `outputLen` / `blockLen`, so constructor side effects happen at module +* init time. +* @throws On wrong argument types. {@link TypeError} * @example -* ```typescript -* import { CborDate } from './date'; -* -* // Create a date from a timestamp (seconds since Unix epoch) -* const date = CborDate.fromTimestamp(1675854714.0); -* -* // Create a date from year, month, day -* const date2 = CborDate.fromYmd(2023, 2, 8); -* -* // Convert to CBOR -* const cborValue = date.taggedCbor(); -* -* // Decode from CBOR -* const decoded = CborDate.fromTaggedCbor(cborValue); +* Wrap a stateful hash constructor into a callable helper. +* ```ts +* import { createHasher } from '@noble/hashes/utils.js'; +* import { sha256 } from '@noble/hashes/sha2.js'; +* const wrapped = createHasher(sha256.create, { oid: sha256.oid }); +* wrapped(new Uint8Array([1])); * ``` */ -var CborDate = class CborDate { - /** - * The wrapped canonical `@blockchaincommons/dcbor` date. It stores the - * normalized timestamp (seconds since the Unix epoch as an `f64`), so - * encoding, equality, and ordering match the Rust reference exactly. - */ - _date; - /** - * Creates a new `CborDate` from the given JavaScript `Date`. - * - * @param dateTime - A `Date` instance to wrap - * @returns A new `CborDate` instance - * - * @example - * ```typescript - * const datetime = new Date(); - * const date = CborDate.fromDatetime(datetime); - * ``` - */ - static fromDatetime(dateTime) { - return new CborDate(delegating(() => CborDate$1.fromDate(dateTime))); - } - /** - * Creates a new `CborDate` from year, month, and day components. - * - * This method creates a new `CborDate` with the time set to 00:00:00 UTC. - * - * @param year - The year component (e.g., 2023) - * @param month - The month component (1-12) - * @param day - The day component (1-31) - * @returns A new `CborDate` instance - * - * @example - * ```typescript - * // Create February 8, 2023 - * const date = CborDate.fromYmd(2023, 2, 8); - * ``` - */ - static fromYmd(year, month, day) { - return new CborDate(delegating(() => CborDate$1.fromYmd(year, month, day))); +function createHasher(hashCons, info = {}) { + if (typeof hashCons !== "function") throw new TypeError("\"hashCons\" expected function, got type=" + typeof hashCons); + info = checkOpts$1({}, info, "info"); + const hashC = (msg, opts) => hashCons(opts).update(msg).digest(); + const tmp = hashCons(void 0); + hashC.outputLen = tmp.outputLen; + hashC.blockLen = tmp.blockLen; + hashC.canXOF = tmp.canXOF; + hashC.create = (opts) => hashCons(opts); + Object.assign(hashC, info); + return Object.freeze(hashC); +} +/** +* Cryptographically secure PRNG backed by `crypto.getRandomValues`. +* @param bytesLength - number of random bytes to generate +* @returns Random bytes. +* The platform `getRandomValues()` implementation still defines any +* single-call length cap, and this helper rejects oversize requests +* with a stable library `RangeError` instead of host-specific errors. +* @throws On wrong argument types. {@link TypeError} +* @throws On wrong argument ranges or values. {@link RangeError} +* @throws If the current runtime does not provide `crypto.getRandomValues`. {@link Error} +* @example +* Generate a fresh random key or nonce. +* ```ts +* const key = randomBytes(16); +* ``` +*/ +function randomBytes$3(bytesLength = 32) { + anumber$2(bytesLength, "bytesLength"); + const cr = typeof globalThis === "object" ? globalThis.crypto : null; + if (typeof cr?.getRandomValues !== "function") throw new Error("crypto.getRandomValues must be defined"); + if (bytesLength > 65536) throw new RangeError(`"bytesLength" expected <= 65536, got ${bytesLength}`); + return cr.getRandomValues(new Uint8Array(bytesLength)); +} +/** +* Creates OID metadata for NIST hashes with prefix `06 09 60 86 48 01 65 03 04 02`. +* @param suffix - final OID byte for the selected hash. +* The helper accepts any byte even though only the documented NIST hash +* suffixes are meaningful downstream. +* @returns Object containing the DER-encoded OID. +* @example +* Build OID metadata for a NIST hash. +* ```ts +* oidNist(0x01); +* ``` +*/ +const oidNist = (suffix) => ({ oid: Uint8Array.from([ + 6, + 9, + 96, + 134, + 72, + 1, + 101, + 3, + 4, + 2, + suffix +]) }); +//#endregion +//#region ../../node_modules/@noble/hashes/_u64.js +const U32_MASK64 = /* @__PURE__ */ (() => BigInt(2 ** 32 - 1))(); +const _32n = /* @__PURE__ */ BigInt(32); +function fromBig(n, le = false) { + if (le) return { + h: Number(n & U32_MASK64), + l: Number(n >> _32n & U32_MASK64) + }; + return { + h: Number(n >> _32n & U32_MASK64) | 0, + l: Number(n & U32_MASK64) | 0 + }; +} +function split$1(lst, le = false) { + const len = lst.length; + let Ah = new Uint32Array(len); + let Al = new Uint32Array(len); + for (let i = 0; i < len; i++) { + const { h, l } = fromBig(lst[i], le); + [Ah[i], Al[i]] = [h, l]; } - /** - * Creates a new `CborDate` from year, month, day, hour, minute, and second - * components. - * - * @param year - The year component (e.g., 2023) - * @param month - The month component (1-12) - * @param day - The day component (1-31) - * @param hour - The hour component (0-23) - * @param minute - The minute component (0-59) - * @param second - The second component (0-59) - * @returns A new `CborDate` instance - * - * @example - * ```typescript - * // Create February 8, 2023, 15:30:45 UTC - * const date = CborDate.fromYmdHms(2023, 2, 8, 15, 30, 45); - * ``` - */ - static fromYmdHms(year, month, day, hour, minute, second) { - return new CborDate(delegating(() => CborDate$1.fromYmdHms(year, month, day, hour, minute, second))); + return [Ah, Al]; +} +const fromNumH = (n) => n / 2 ** 32 | 0; +const fromNumL = (n) => n >>> 0; +function setU64FromNum(view, byteOffset, n, isLE) { + const h = fromNumH(n); + const l = fromNumL(n); + view.setUint32(byteOffset, isLE ? l : h, isLE); + view.setUint32(byteOffset + 4, isLE ? h : l, isLE); +} +const shrSH = (h, _l, s) => h >>> s; +const shrSL = (h, l, s) => h << 32 - s | l >>> s; +const rotrSH = (h, l, s) => h >>> s | l << 32 - s; +const rotrSL = (h, l, s) => h << 32 - s | l >>> s; +const rotrBH = (h, l, s) => h << 64 - s | l >>> s - 32; +const rotrBL = (h, l, s) => h >>> s - 32 | l << 64 - s; +const rotr32H = (_h, l) => l; +const rotr32L = (h, _l) => h; +function add(Ah, Al, Bh, Bl) { + const l = (Al >>> 0) + (Bl >>> 0); + return { + h: Ah + Bh + (l / 2 ** 32 | 0) | 0, + l: l | 0 + }; +} +const add3L = (Al, Bl, Cl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0); +const add3H = (low, Ah, Bh, Ch) => Ah + Bh + Ch + (low / 2 ** 32 | 0) | 0; +const add4L = (Al, Bl, Cl, Dl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0); +const add4H = (low, Ah, Bh, Ch, Dh) => Ah + Bh + Ch + Dh + (low / 2 ** 32 | 0) | 0; +const add5L = (Al, Bl, Cl, Dl, El) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0) + (El >>> 0); +const add5H = (low, Ah, Bh, Ch, Dh, Eh) => Ah + Bh + Ch + Dh + Eh + (low / 2 ** 32 | 0) | 0; +//#endregion +//#region ../../node_modules/@noble/hashes/_md.js +/** +* Internal Merkle-Damgard hash utils. +* @module +*/ +/** +* Shared 32-bit conditional boolean primitive reused by SHA-256, SHA-1, and MD5 `F`. +* Returns bits from `b` when `a` is set, otherwise from `c`. +* The XOR form is equivalent to MD5's `F(X,Y,Z) = XY v not(X)Z` because the masked terms never +* set the same bit. +* @param a - selector word +* @param b - word chosen when selector bit is set +* @param c - word chosen when selector bit is clear +* @returns Mixed 32-bit word. +* @example +* Combine three words with the shared 32-bit choice primitive. +* ```ts +* Chi(0xffffffff, 0x12345678, 0x87654321); +* ``` +*/ +function Chi(a, b, c) { + return a & b ^ ~a & c; +} +/** +* Shared 32-bit majority primitive reused by SHA-256 and SHA-1. +* Returns bits shared by at least two inputs. +* @param a - first input word +* @param b - second input word +* @param c - third input word +* @returns Mixed 32-bit word. +* @example +* Combine three words with the shared 32-bit majority primitive. +* ```ts +* Maj(0xffffffff, 0x12345678, 0x87654321); +* ``` +*/ +function Maj(a, b, c) { + return a & b ^ a & c ^ b & c; +} +/** +* Merkle-Damgard hash construction base class. +* Could be used to create MD5, RIPEMD, SHA1, SHA2. +* Accepts only byte-aligned `Uint8Array` input, even when the underlying spec describes bit +* strings with partial-byte tails. +* @param blockLen - internal block size in bytes +* @param outputLen - digest size in bytes +* @param padOffset - trailing length field size in bytes +* @param isLE - whether length and state words are encoded in little-endian +* @example +* Use a concrete subclass to get the shared Merkle-Damgard update/digest flow. +* ```ts +* import { _SHA1 } from '@noble/hashes/legacy.js'; +* const hash = new _SHA1(); +* hash.update(new Uint8Array([97, 98, 99])); +* hash.digest(); +* ``` +*/ +var HashMD = class { + blockLen; + outputLen; + canXOF = false; + padOffset; + isLE; + buffer; + view; + finished = false; + length = 0; + pos = 0; + destroyed = false; + constructor(blockLen, outputLen, padOffset, isLE) { + this.blockLen = blockLen; + this.outputLen = outputLen; + this.padOffset = padOffset; + this.isLE = isLE; + this.buffer = new Uint8Array(blockLen); + this.view = createView$1(this.buffer); } - /** - * Creates a new `CborDate` from seconds since (or before) the Unix epoch. - * - * The value is normalized on construction (matching Rust's - * `Date::from_timestamp`) so the stored value — and thus its encoding, - * equality, and ordering — matches the reference. - * - * @param secondsSinceUnixEpoch - Seconds from the Unix epoch (positive or - * negative), which can include a fractional part for sub-second - * precision - * @returns A new `CborDate` instance - * - * @example - * ```typescript - * // Create a date from a timestamp - * const date = CborDate.fromTimestamp(1675854714.0); - * - * // Create a date one second before the Unix epoch - * const beforeEpoch = CborDate.fromTimestamp(-1.0); - * - * // Create a date with fractional seconds - * const withFraction = CborDate.fromTimestamp(1675854714.5); - * ``` - */ - static fromTimestamp(secondsSinceUnixEpoch) { - return new CborDate(delegating(() => CborDate$1.fromEpochSeconds(secondsSinceUnixEpoch))); + update(data) { + aexists$1(this); + abytes$2(data); + const { view, buffer, blockLen } = this; + const len = data.length; + let processed = false; + for (let pos = 0; pos < len;) { + const take = Math.min(blockLen - this.pos, len - pos); + if (take === blockLen) { + const dataView = createView$1(data); + for (; blockLen <= len - pos; pos += blockLen) this.process(dataView, pos); + processed = true; + continue; + } + buffer.set(pos === 0 && take === len ? data : data.subarray(pos, pos + take), this.pos); + this.pos += take; + pos += take; + if (this.pos === blockLen) { + this.process(view, 0); + this.pos = 0; + processed = true; + } + } + this.length += data.length; + if (processed) this.roundClean(); + return this; } - /** - * Creates a new `CborDate` from a string containing an ISO-8601 (RFC-3339) - * date (with or without time). - * - * Accepts only strict RFC-3339 date-times (with seconds and an explicit - * `Z`/±HH:MM offset) or bare `YYYY-MM-DD` dates (read as UTC midnight), - * matching Rust's `Date::from_string`. - * - * @param value - A string containing a date or date-time in ISO-8601/RFC-3339 - * format - * @returns A new `CborDate` instance if parsing succeeds - * @throws Error if the string cannot be parsed as a valid date or date-time - * - * @example - * ```typescript - * // Parse a date-time string - * const date = CborDate.fromString("2023-02-08T15:30:45Z"); - * - * // Parse a date-only string (time will be set to 00:00:00) - * const date2 = CborDate.fromString("2023-02-08"); - * ``` - */ - static fromString(value) { - return new CborDate(delegating(() => CborDate$1.fromString(value))); - } - /** - * Creates a new `CborDate` containing the current date and time. - * - * @returns A new `CborDate` instance representing the current UTC date and time - * - * @example - * ```typescript - * const now = CborDate.now(); - * ``` - */ - static now() { - return new CborDate(delegating(() => CborDate$1.now())); - } - /** - * Creates a new `CborDate` containing the current date and time plus the given - * duration. - * - * @param durationMs - The duration in milliseconds to add to the current time - * @returns A new `CborDate` instance representing the current UTC date and time plus - * the duration - * - * @example - * ```typescript - * // Get a date 1 hour from now - * const oneHourLater = CborDate.withDurationFromNow(3600 * 1000); - * ``` - */ - static withDurationFromNow(durationMs) { - const future = new Date((/* @__PURE__ */ new Date()).getTime() + durationMs); - return CborDate.fromDatetime(future); - } - /** - * Returns the underlying JavaScript `Date` object. - * - * @returns The wrapped `Date` instance - * - * @example - * ```typescript - * const date = CborDate.now(); - * const datetime = date.datetime(); - * const year = datetime.getFullYear(); - * ``` - */ - datetime() { - return this._date.toDate(); - } - /** - * Returns the `CborDate` as the number of seconds since the Unix epoch. - * - * Negative values represent times before the epoch. The fractional - * part represents sub-second precision. - * - * @returns Seconds since the Unix epoch as a `number` - * - * @example - * ```typescript - * const date = CborDate.fromYmd(2023, 2, 8); - * const timestamp = date.timestamp(); - * ``` - */ - timestamp() { - return this._date.epochSeconds; - } - /** - * Add seconds to this date. - * - * @param seconds - Seconds to add (can be fractional) - * @returns New CborDate instance - * - * @example - * ```typescript - * const date = CborDate.fromYmd(2022, 3, 21); - * const tomorrow = date.add(24 * 60 * 60); - * ``` - */ - add(seconds) { - return CborDate.fromTimestamp(this.timestamp() + seconds); - } - /** - * Subtract seconds from this date. - * - * @param seconds - Seconds to subtract (can be fractional) - * @returns New CborDate instance - * - * @example - * ```typescript - * const date = CborDate.fromYmd(2022, 3, 21); - * const yesterday = date.subtract(24 * 60 * 60); - * ``` - */ - subtract(seconds) { - return CborDate.fromTimestamp(this.timestamp() - seconds); - } - /** - * Get the difference in seconds between this date and another. - * - * @param other - Other CborDate to compare with - * @returns Difference in seconds (this - other) - * - * @example - * ```typescript - * const date1 = CborDate.fromYmd(2022, 3, 22); - * const date2 = CborDate.fromYmd(2022, 3, 21); - * const diff = date1.difference(date2); - * // Returns 86400 (one day in seconds) - * ``` - */ - difference(other) { - return this.timestamp() - other.timestamp(); - } - /** - * Implementation of the `CborTagged` interface for `CborDate`. - * - * This implementation specifies that `CborDate` values are tagged with CBOR tag 1, - * which is the standard CBOR tag for date/time values represented as seconds - * since the Unix epoch per RFC 8949. - * - * @returns A vector containing tag 1 - */ - cborTags() { - return [createTag(1, "date")]; - } - /** - * Implementation of the `CborTaggedEncodable` interface for `CborDate`. - * - * Converts this `CborDate` to an untagged CBOR value. - * - * The date is converted to a numeric value representing the number of - * seconds since the Unix epoch. This value may be an integer or a - * floating-point number, depending on whether the date has fractional - * seconds. - * - * @returns A CBOR value representing the timestamp - */ - untaggedCbor() { - return cbor(this.timestamp()); - } - /** - * Converts this `CborDate` to a tagged CBOR value with tag 1. - * - * @returns Tagged CBOR value - */ - taggedCbor() { - return createTaggedCbor(this); - } - /** - * Implementation of the `CborTaggedDecodable` interface for `CborDate`. - * - * Creates a `CborDate` from an untagged CBOR value. - * - * The CBOR value must be a numeric value (integer or floating-point) - * representing the number of seconds since the Unix epoch. - * - * @param cbor - The untagged CBOR value - * @returns This CborDate instance (mutated) - * @throws Error if the CBOR value is not a valid timestamp - */ - fromUntaggedCbor(cbor) { - let timestamp; - switch (cbor.type) { - case MajorType.Unsigned: - timestamp = typeof cbor.value === "number" ? cbor.value : Number(cbor.value); - break; - case MajorType.Negative: - if (typeof cbor.value === "bigint") timestamp = Number(-cbor.value - 1n); - else timestamp = -cbor.value - 1; - break; - case MajorType.Simple: - if (cbor.value.type === "Float") timestamp = cbor.value.value; - else throw new CborError({ type: "WrongType" }); - break; - default: throw new CborError({ type: "WrongType" }); + digestInto(out) { + aexists$1(this); + aoutput$1(out, this); + this.finished = true; + const { buffer, view, blockLen, isLE } = this; + let { pos } = this; + buffer[pos++] = 128; + buffer.fill(0, pos); + if (this.padOffset > blockLen - pos) { + this.process(view, 0); + buffer.fill(0); } - this._date = delegating(() => CborDate$1.fromEpochSeconds(timestamp)); - return this; - } - /** - * Creates a `CborDate` from a tagged CBOR value with tag 1. - * - * @param cbor - Tagged CBOR value - * @returns This CborDate instance (mutated) - * @throws Error if the CBOR value has the wrong tag or cannot be decoded - */ - fromTaggedCbor(cbor) { - const expectedTags = this.cborTags(); - validateTag(cbor, expectedTags); - const content = extractTaggedContent(cbor); - return this.fromUntaggedCbor(content); - } - /** - * Static method to create a CborDate from tagged CBOR. - * - * @param cbor - Tagged CBOR value - * @returns New CborDate instance - */ - static fromTaggedCbor(cbor) { - return new CborDate().fromTaggedCbor(cbor); - } - /** - * Static method to create a CborDate from untagged CBOR. - * - * @param cbor - Untagged CBOR value - * @returns New CborDate instance - */ - static fromUntaggedCbor(cbor) { - return new CborDate().fromUntaggedCbor(cbor); - } - /** - * Implementation of the `toString` method for `CborDate`. - * - * This implementation provides a string representation of a `CborDate` in ISO-8601 - * format. For dates with time exactly at midnight (00:00:00), only the date - * part is shown. For other times, a full date-time string is shown. - * - * @returns String representation in ISO-8601 format - * - * @example - * ```typescript - * // A date at midnight will display as just the date - * const date = CborDate.fromYmd(2023, 2, 8); - * // Returns "2023-02-08" - * console.log(date.toString()); - * - * // A date with time will display as date and time - * const date2 = CborDate.fromYmdHms(2023, 2, 8, 15, 30, 45); - * // Returns "2023-02-08T15:30:45Z" - * console.log(date2.toString()); - * ``` - */ - toString() { - return this._date.toString(); - } - /** - * Compare two dates for equality. - * - * @param other - Other CborDate to compare - * @returns true if dates represent the same moment in time - */ - equals(other) { - return this.timestamp() === other.timestamp(); + setU64FromNum(view, blockLen - 8, this.length * 8, isLE); + this.process(view, 0); + this.roundClean(); + const oview = out === buffer ? view : createView$1(out); + const len = this.outputLen; + const outLen = len / 4; + const state = this.get(); + if (len % 4 || outLen > state.length) throw new Error("invalid outputLen"); + for (let i = 0; i < outLen; i++) oview.setUint32(4 * i, state[i], isLE); } - /** - * Compare two dates. - * - * @param other - Other CborDate to compare - * @returns -1 if this < other, 0 if equal, 1 if this > other - */ - compare(other) { - if (this.timestamp() < other.timestamp()) return -1; - if (this.timestamp() > other.timestamp()) return 1; - return 0; + digest() { + const { buffer, outputLen } = this; + this.digestInto(buffer); + const res = buffer.slice(0, outputLen); + this.destroy(); + return res; } - /** - * Convert to JSON (returns ISO 8601 string). - * - * @returns ISO 8601 string - */ - toJSON() { - return this.toString(); + _cloneIntoMeta(to) { + const { buffer, length, finished, destroyed, pos } = this; + to.destroyed = destroyed; + to.finished = finished; + to.length = length; + to.pos = pos; + if (pos) to.buffer.set(buffer); + return to; } - constructor(date) { - this._date = date ?? CborDate$1.now(); + clone() { + return this._cloneInto(); } }; /** -* Decode a BigUint from an untagged CBOR byte string. -* -* Matches Rust's `biguint_from_untagged_cbor()`. -* -* This function is intended for use in tag summarizers where the tag has -* already been stripped. It expects a CBOR byte string representing the -* big-endian magnitude of a positive bignum (tag 2 content). -* -* Enforces canonical encoding: no leading zero bytes (except empty for zero). -* -* @param cbor - A CBOR value that should be a byte string -* @returns Non-negative bigint -* @throws CborError with type WrongType if not a byte string -* @throws CborError with type NonCanonicalNumeric if encoding is non-canonical -*/ -function biguintFromUntaggedCbor(cbor) { - return delegating(() => biguintFromUntaggedCbor$1(toNew(cbor))); -} -/** -* Decode a BigInt from an untagged CBOR byte string for a negative bignum. -* -* Matches Rust's `bigint_from_negative_untagged_cbor()`. -* -* This function is intended for use in tag summarizers where the tag has -* already been stripped. It expects a CBOR byte string representing `n` where -* the actual value is `-1 - n` (tag 3 content per RFC 8949). -* -* Enforces canonical encoding: no leading zero bytes (except single `0x00` -* for -1). -* -* @param cbor - A CBOR value that should be a byte string -* @returns Negative bigint -* @throws CborError with type WrongType if not a byte string -* @throws CborError with type NonCanonicalNumeric if encoding is non-canonical -*/ -function bigintFromNegativeUntaggedCbor(cbor) { - return delegating(() => bigintFromNegativeUntaggedCbor$1(toNew(cbor))); -} -/** -* Name for tag 2 (positive bignum). -* Matches Rust's `TAG_NAME_POSITIVE_BIGNUM`. +* Initial SHA-2 state: fractional parts of square roots of first 16 primes 2..53. +* Check out `test/misc/sha2-gen-iv.js` for recomputation guide. */ -const TAG_NAME_POSITIVE_BIGNUM = "positive-bignum"; +/** Initial SHA256 state from RFC 6234 §6.1: the first 32 bits of the fractional parts of the +* square roots of the first eight prime numbers. Exported as a shared table; callers must treat +* it as read-only because constructors copy words from it by index. */ +const SHA256_IV = /* @__PURE__ */ Uint32Array.from([ + 1779033703, + 3144134277, + 1013904242, + 2773480762, + 1359893119, + 2600822924, + 528734635, + 1541459225 +]); +/** Initial SHA384 state from RFC 6234 §6.3: eight RFC 64-bit `H(0)` words stored as sixteen +* big-endian 32-bit halves. Derived from the fractional parts of the square roots of the ninth +* through sixteenth prime numbers. Exported as a shared table; callers must treat it as read-only +* because constructors copy halves from it by index. */ +const SHA384_IV = /* @__PURE__ */ Uint32Array.from([ + 3418070365, + 3238371032, + 1654270250, + 914150663, + 2438529370, + 812702999, + 355462360, + 4144912697, + 1731405415, + 4290775857, + 2394180231, + 1750603025, + 3675008525, + 1694076839, + 1203062813, + 3204075428 +]); +/** Initial SHA512 state from RFC 6234 §6.3: eight RFC 64-bit `H(0)` words stored as sixteen +* big-endian 32-bit halves. Derived from the fractional parts of the square roots of the first +* eight prime numbers. Exported as a shared table; callers must treat it as read-only because +* constructors copy halves from it by index. */ +const SHA512_IV = /* @__PURE__ */ Uint32Array.from([ + 1779033703, + 4089235720, + 3144134277, + 2227873595, + 1013904242, + 4271175723, + 2773480762, + 1595750129, + 1359893119, + 2917565137, + 2600822924, + 725511199, + 528734635, + 4215389547, + 1541459225, + 327033209 +]); +//#endregion +//#region ../../node_modules/@noble/hashes/sha2.js /** -* Name for tag 3 (negative bignum). -* Matches Rust's `TAG_NAME_NEGATIVE_BIGNUM`. +* SHA2 hash function. A.k.a. sha256, sha384, sha512, sha512_224, sha512_256. +* SHA256 is the fastest hash implementable in JS, even faster than Blake3. +* Check out {@link https://www.rfc-editor.org/rfc/rfc4634 | RFC 4634} and +* {@link https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf | FIPS 180-4}. +* @module */ -const TAG_NAME_NEGATIVE_BIGNUM = "negative-bignum"; -const TAG_NAME_DATE = "date"; /** -* Register standard tags in a specific tags store. -* Matches Rust's register_tags_in() function. -* -* @param tagsStore - The tags store to register tags into +* SHA-224 / SHA-256 round constants from RFC 6234 §5.1: the first 32 bits +* of the cube roots of the first 64 primes (2..311). */ -const registerTagsIn$1 = (tagsStore) => { - const tags = [createTag(1, TAG_NAME_DATE)]; - tagsStore.insertAll(tags); - tagsStore.setSummarizer(1, (untaggedCbor, _flat) => { - try { - return { - ok: true, - value: CborDate.fromUntaggedCbor(untaggedCbor).toString() - }; - } catch (e) { - return { - ok: false, - error: { - type: "Custom", - message: e instanceof Error ? e.message : String(e) - } - }; - } - }); - const biguintTag = createTag(2, TAG_NAME_POSITIVE_BIGNUM); - const bigintTag = createTag(3, TAG_NAME_NEGATIVE_BIGNUM); - tagsStore.insertAll([biguintTag, bigintTag]); - tagsStore.setSummarizer(2, (untaggedCbor, _flat) => { - try { - return { - ok: true, - value: `bignum(${biguintFromUntaggedCbor(untaggedCbor)})` - }; - } catch (e) { - return { - ok: false, - error: { - type: "Custom", - message: e instanceof Error ? e.message : String(e) - } - }; +const SHA256_K = /* @__PURE__ */ Uint32Array.from([ + 1116352408, + 1899447441, + 3049323471, + 3921009573, + 961987163, + 1508970993, + 2453635748, + 2870763221, + 3624381080, + 310598401, + 607225278, + 1426881987, + 1925078388, + 2162078206, + 2614888103, + 3248222580, + 3835390401, + 4022224774, + 264347078, + 604807628, + 770255983, + 1249150122, + 1555081692, + 1996064986, + 2554220882, + 2821834349, + 2952996808, + 3210313671, + 3336571891, + 3584528711, + 113926993, + 338241895, + 666307205, + 773529912, + 1294757372, + 1396182291, + 1695183700, + 1986661051, + 2177026350, + 2456956037, + 2730485921, + 2820302411, + 3259730800, + 3345764771, + 3516065817, + 3600352804, + 4094571909, + 275423344, + 430227734, + 506948616, + 659060556, + 883997877, + 958139571, + 1322822218, + 1537002063, + 1747873779, + 1955562222, + 2024104815, + 2227730452, + 2361852424, + 2428436474, + 2756734187, + 3204031479, + 3329325298 +]); +/** Reusable SHA-224 / SHA-256 message schedule buffer `W_t` from RFC 6234 §6.2 step 1. */ +const SHA256_W = /* @__PURE__ */ new Uint32Array(64); +/** Internal SHA-224 / SHA-256 compression engine from RFC 6234 §6.2. */ +var SHA2_32B = class extends HashMD { + A = 0; + B = 0; + C = 0; + D = 0; + E = 0; + F = 0; + G = 0; + H = 0; + constructor(outputLen, IV) { + super(64, outputLen, 8, false); + this.A = IV[0] | 0; + this.B = IV[1] | 0; + this.C = IV[2] | 0; + this.D = IV[3] | 0; + this.E = IV[4] | 0; + this.F = IV[5] | 0; + this.G = IV[6] | 0; + this.H = IV[7] | 0; + } + get() { + const { A, B, C, D, E, F, G, H } = this; + return [ + A, + B, + C, + D, + E, + F, + G, + H + ]; + } + set(A, B, C, D, E, F, G, H) { + this.A = A | 0; + this.B = B | 0; + this.C = C | 0; + this.D = D | 0; + this.E = E | 0; + this.F = F | 0; + this.G = G | 0; + this.H = H | 0; + } + _cloneInto(to) { + (to ||= new this.constructor()).set(...this.get()); + return this._cloneIntoMeta(to); + } + process(view, offset) { + for (let i = 0; i < 16; i++, offset += 4) SHA256_W[i] = view.getUint32(offset, false); + for (let i = 16; i < 64; i++) { + const W15 = SHA256_W[i - 15]; + const W2 = SHA256_W[i - 2]; + const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ W15 >>> 3; + const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ W2 >>> 10; + SHA256_W[i] = s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16] | 0; } - }); - tagsStore.setSummarizer(3, (untaggedCbor, _flat) => { - try { - return { - ok: true, - value: `bignum(${bigintFromNegativeUntaggedCbor(untaggedCbor)})` - }; - } catch (e) { - return { - ok: false, - error: { - type: "Custom", - message: e instanceof Error ? e.message : String(e) - } - }; - } - }); -}; -/** -* Converts an array of tag values to their corresponding Tag objects. -* Matches Rust's tags_for_values() function. -* -* This function looks up each tag value in the global tag registry and returns -* an array of complete Tag objects. For any tag values that aren't -* registered in the global registry, it creates a basic Tag with just the -* value (no name). -* -* @param values - Array of numeric tag values to convert -* @returns Array of Tag objects corresponding to the input values -* -* @example -* ```typescript -* // Register some tags first -* registerTags(); -* -* // Convert tag values to Tag objects -* const tags = tagsForValues([1, 42, 999]); -* -* // The first tag (value 1) should be registered as "date" -* console.log(tags[0].value); // 1 -* console.log(tags[0].name); // "date" -* -* // Unregistered tags will have a value but no name -* console.log(tags[1].value); // 42 -* console.log(tags[2].value); // 999 -* ``` -*/ -const tagsForValues = (values) => { - const globalStore = getGlobalTagsStore(); - return values.map((value) => { - const tag = globalStore.tagForValue(value); - if (tag !== void 0) return tag; - return createTag(value); - }); -}; -//#endregion -//#region tests/baseline/node_modules/@bcts/tags/dist/index.mjs -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -* -* CBOR Tags Registry -* -* This is a 1:1 port of the Rust bc-tags-rust implementation. -* -* @see https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2020-006-urtypes.md -* -* As of August 13 2022, the [IANA registry of CBOR tags](https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml) -* has the following low-numbered values available: -* -* One byte encoding: 6-15, 19-20 -* Two byte encoding: 48-51, 53, 55-60, 62, 88-95, 99, 102, 105-109, 113-119, -* 128-255 -* -* Tags in the range 0-23 require "standards action" for the IANA to recognize. -* Tags in the range 24-32767 require a specification to reserve. -* Tags in the range 24-255 only require two bytes to encode. -* Higher numbered tags are first-come, first-served. -*/ -const URI$1 = createTag(32, "url"); -const UUID$1 = createTag(37, "uuid"); -const ENCODED_CBOR = createTag(24, "encoded-cbor"); -const ENVELOPE = createTag(200, "envelope"); -const LEAF = createTag(201, "leaf"); -const JSON$2 = createTag(262, "json"); -const KNOWN_VALUE = createTag(4e4, "known-value"); -const DIGEST = createTag(40001, "digest"); -const ENCRYPTED = createTag(40002, "encrypted"); -const COMPRESSED = createTag(40003, "compressed"); -const REQUEST = createTag(40004, "request"); -const RESPONSE = createTag(40005, "response"); -const FUNCTION = createTag(40006, "function"); -const PARAMETER = createTag(40007, "parameter"); -const PLACEHOLDER = createTag(40008, "placeholder"); -const REPLACEMENT = createTag(40009, "replacement"); -const X25519_PRIVATE_KEY = createTag(40010, "agreement-private-key"); -const X25519_PUBLIC_KEY = createTag(40011, "agreement-public-key"); -const ARID$1 = createTag(40012, "arid"); -const PRIVATE_KEYS = createTag(40013, "crypto-prvkeys"); -const NONCE = createTag(40014, "nonce"); -const PASSWORD = createTag(40015, "password"); -const PRIVATE_KEY_BASE = createTag(40016, "crypto-prvkey-base"); -const PUBLIC_KEYS = createTag(40017, "crypto-pubkeys"); -const SALT$2 = createTag(40018, "salt"); -const SEALED_MESSAGE = createTag(40019, "crypto-sealed"); -const SIGNATURE = createTag(40020, "signature"); -const SIGNING_PRIVATE_KEY = createTag(40021, "signing-private-key"); -const SIGNING_PUBLIC_KEY = createTag(40022, "signing-public-key"); -const SYMMETRIC_KEY = createTag(40023, "crypto-key"); -const XID$1 = createTag(40024, "xid"); -const REFERENCE = createTag(40025, "reference"); -const EVENT = createTag(40026, "event"); -const ENCRYPTED_KEY = createTag(40027, "encrypted-key"); -const MLKEM_PRIVATE_KEY = createTag(40100, "mlkem-private-key"); -const MLKEM_PUBLIC_KEY = createTag(40101, "mlkem-public-key"); -const MLKEM_CIPHERTEXT = createTag(40102, "mlkem-ciphertext"); -const MLDSA_PRIVATE_KEY = createTag(40103, "mldsa-private-key"); -const MLDSA_PUBLIC_KEY = createTag(40104, "mldsa-public-key"); -const MLDSA_SIGNATURE = createTag(40105, "mldsa-signature"); -const SEED = createTag(40300, "seed"); -const HDKEY = createTag(40303, "hdkey"); -const DERIVATION_PATH = createTag(40304, "keypath"); -const USE_INFO = createTag(40305, "coin-info"); -const EC_KEY = createTag(40306, "eckey"); -const ADDRESS = createTag(40307, "address"); -const OUTPUT_DESCRIPTOR$1 = createTag(40308, "output-descriptor"); -const SSKR_SHARE$1 = createTag(40309, "sskr"); -const PSBT = createTag(40310, "psbt"); -const ACCOUNT_DESCRIPTOR = createTag(40311, "account-descriptor"); -const SSH_TEXT_PRIVATE_KEY = createTag(40800, "ssh-private"); -const SSH_TEXT_PUBLIC_KEY = createTag(40801, "ssh-public"); -const SSH_TEXT_SIGNATURE = createTag(40802, "ssh-signature"); -const SSH_TEXT_CERTIFICATE = createTag(40803, "ssh-certificate"); -const PROVENANCE_MARK = createTag(1347571542, "provenance"); -const SEED_V1 = createTag(300, "crypto-seed"); -const EC_KEY_V1 = createTag(306, "crypto-eckey"); -const SSKR_SHARE_V1 = createTag(309, "crypto-sskr"); -const HDKEY_V1 = createTag(303, "crypto-hdkey"); -const DERIVATION_PATH_V1 = createTag(304, "crypto-keypath"); -const USE_INFO_V1 = createTag(305, "crypto-coin-info"); -const OUTPUT_DESCRIPTOR_V1 = createTag(307, "crypto-output"); -const PSBT_V1 = createTag(310, "crypto-psbt"); -const ACCOUNT_V1 = createTag(311, "crypto-account"); -const OUTPUT_SCRIPT_HASH = createTag(400, "output-script-hash"); -const OUTPUT_WITNESS_SCRIPT_HASH = createTag(401, "output-witness-script-hash"); -const OUTPUT_PUBLIC_KEY = createTag(402, "output-public-key"); -const OUTPUT_PUBLIC_KEY_HASH = createTag(403, "output-public-key-hash"); -const OUTPUT_WITNESS_PUBLIC_KEY_HASH = createTag(404, "output-witness-public-key-hash"); -const OUTPUT_COMBO = createTag(405, "output-combo"); -const OUTPUT_MULTISIG = createTag(406, "output-multisig"); -const OUTPUT_SORTED_MULTISIG = createTag(407, "output-sorted-multisig"); -const OUTPUT_RAW_SCRIPT = createTag(408, "output-raw-script"); -const OUTPUT_TAPROOT = createTag(409, "output-taproot"); -const OUTPUT_COSIGNER = createTag(410, "output-cosigner"); -/** -* Register all Blockchain Commons tags in a specific tags store. -* This matches the Rust function `register_tags_in()`. -* -* @param tagsStore - The tags store to register tags into -*/ -function registerTagsIn(tagsStore) { - registerTagsIn$1(tagsStore); - const tags = [ - URI$1, - UUID$1, - ENCODED_CBOR, - ENVELOPE, - LEAF, - JSON$2, - KNOWN_VALUE, - DIGEST, - ENCRYPTED, - COMPRESSED, - REQUEST, - RESPONSE, - FUNCTION, - PARAMETER, - PLACEHOLDER, - REPLACEMENT, - EVENT, - SEED_V1, - EC_KEY_V1, - SSKR_SHARE_V1, - SEED, - EC_KEY, - SSKR_SHARE$1, - X25519_PRIVATE_KEY, - X25519_PUBLIC_KEY, - ARID$1, - PRIVATE_KEYS, - NONCE, - PASSWORD, - PRIVATE_KEY_BASE, - PUBLIC_KEYS, - SALT$2, - SEALED_MESSAGE, - SIGNATURE, - SIGNING_PRIVATE_KEY, - SIGNING_PUBLIC_KEY, - SYMMETRIC_KEY, - XID$1, - REFERENCE, - ENCRYPTED_KEY, - MLKEM_PRIVATE_KEY, - MLKEM_PUBLIC_KEY, - MLKEM_CIPHERTEXT, - MLDSA_PRIVATE_KEY, - MLDSA_PUBLIC_KEY, - MLDSA_SIGNATURE, - HDKEY_V1, - DERIVATION_PATH_V1, - USE_INFO_V1, - OUTPUT_DESCRIPTOR_V1, - PSBT_V1, - ACCOUNT_V1, - HDKEY, - DERIVATION_PATH, - USE_INFO, - ADDRESS, - OUTPUT_DESCRIPTOR$1, - PSBT, - ACCOUNT_DESCRIPTOR, - SSH_TEXT_PRIVATE_KEY, - SSH_TEXT_PUBLIC_KEY, - SSH_TEXT_SIGNATURE, - SSH_TEXT_CERTIFICATE, - OUTPUT_SCRIPT_HASH, - OUTPUT_WITNESS_SCRIPT_HASH, - OUTPUT_PUBLIC_KEY, - OUTPUT_PUBLIC_KEY_HASH, - OUTPUT_WITNESS_PUBLIC_KEY_HASH, - OUTPUT_COMBO, - OUTPUT_MULTISIG, - OUTPUT_SORTED_MULTISIG, - OUTPUT_RAW_SCRIPT, - OUTPUT_TAPROOT, - OUTPUT_COSIGNER, - PROVENANCE_MARK - ]; - tagsStore.insertAll(tags); -} -/** -* Register all Blockchain Commons tags in the global tags store. -* This matches the Rust function `register_tags()`. -* -* This function is idempotent - calling it multiple times is safe. -*/ -function registerTags() { - registerTagsIn(getGlobalTagsStore()); -} -//#endregion -//#region tests/baseline/node_modules/pako/dist/pako.mjs -var Z_FIXED = 4; -var Z_BINARY = 0; -var Z_TEXT = 1; -var Z_UNKNOWN = 2; -function zero$1(buf) { - let len = buf.length; - while (--len >= 0) buf[len] = 0; -} -var LENGTH_CODES = 29; -var LITERALS = 256; -var L_CODES = 286; -var D_CODES = 30; -var BL_CODES = 19; -var HEAP_SIZE$1 = 573; -var MAX_BITS = 15; -var Buf_size = 16; -var MAX_BL_BITS = 7; -var END_BLOCK = 256; -var REP_3_6 = 16; -var REPZ_3_10 = 17; -var REPZ_11_138 = 18; -var extra_lbits = new Uint8Array([ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 1, - 2, - 2, - 2, - 2, - 3, - 3, - 3, - 3, - 4, - 4, - 4, - 4, - 5, - 5, - 5, - 5, - 0 -]); -var extra_dbits = new Uint8Array([ - 0, - 0, - 0, - 0, - 1, - 1, - 2, - 2, - 3, - 3, - 4, - 4, - 5, - 5, - 6, - 6, - 7, - 7, - 8, - 8, - 9, - 9, - 10, - 10, - 11, - 11, - 12, - 12, - 13, - 13 -]); -var extra_blbits = new Uint8Array([ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - 3, - 7 -]); -var bl_order = new Uint8Array([ - 16, - 17, - 18, - 0, - 8, - 7, - 9, - 6, - 10, - 5, - 11, - 4, - 12, - 3, - 13, - 2, - 14, - 1, - 15 -]); -var DIST_CODE_LEN = 512; -var static_ltree = new Array(576); -zero$1(static_ltree); -var static_dtree = new Array(D_CODES * 2); -zero$1(static_dtree); -var _dist_code = new Array(DIST_CODE_LEN); -zero$1(_dist_code); -var _length_code = new Array(256); -zero$1(_length_code); -var base_length = new Array(LENGTH_CODES); -zero$1(base_length); -var base_dist = new Array(D_CODES); -zero$1(base_dist); -var StaticTreeDesc = class { - constructor(static_tree, extra_bits, extra_base, elems, max_length) { - this.static_tree = static_tree; - this.extra_bits = extra_bits; - this.extra_base = extra_base; - this.elems = elems; - this.max_length = max_length; - this.has_stree = static_tree && static_tree.length; - } -}; -var static_l_desc; -var static_d_desc; -var static_bl_desc; -var TreeDesc = class { - constructor(dyn_tree, stat_desc) { - this.dyn_tree = dyn_tree; - this.max_code = 0; - this.stat_desc = stat_desc; - } -}; -var d_code = (dist) => { - return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)]; -}; -var put_short = (s, w) => { - s.pending_buf[s.pending++] = w & 255; - s.pending_buf[s.pending++] = w >>> 8 & 255; -}; -var send_bits = (s, value, length) => { - if (s.bi_valid > Buf_size - length) { - s.bi_buf |= value << s.bi_valid & 65535; - put_short(s, s.bi_buf); - s.bi_buf = value >> Buf_size - s.bi_valid; - s.bi_valid += length - Buf_size; - } else { - s.bi_buf |= value << s.bi_valid & 65535; - s.bi_valid += length; - } -}; -var send_code = (s, c, tree) => { - send_bits(s, tree[c * 2], tree[c * 2 + 1]); -}; -var bi_reverse = (code, len) => { - let res = 0; - do { - res |= code & 1; - code >>>= 1; - res <<= 1; - } while (--len > 0); - return res >>> 1; -}; -var bi_flush = (s) => { - if (s.bi_valid === 16) { - put_short(s, s.bi_buf); - s.bi_buf = 0; - s.bi_valid = 0; - } else if (s.bi_valid >= 8) { - s.pending_buf[s.pending++] = s.bi_buf & 255; - s.bi_buf >>= 8; - s.bi_valid -= 8; - } -}; -var gen_bitlen = (s, desc) => { - const tree = desc.dyn_tree; - const max_code = desc.max_code; - const stree = desc.stat_desc.static_tree; - const has_stree = desc.stat_desc.has_stree; - const extra = desc.stat_desc.extra_bits; - const base = desc.stat_desc.extra_base; - const max_length = desc.stat_desc.max_length; - let h; - let n, m; - let bits; - let xbits; - let f; - let overflow = 0; - for (bits = 0; bits <= MAX_BITS; bits++) s.bl_count[bits] = 0; - tree[s.heap[s.heap_max] * 2 + 1] = 0; - for (h = s.heap_max + 1; h < HEAP_SIZE$1; h++) { - n = s.heap[h]; - bits = tree[tree[n * 2 + 1] * 2 + 1] + 1; - if (bits > max_length) { - bits = max_length; - overflow++; - } - tree[n * 2 + 1] = bits; - if (n > max_code) continue; - s.bl_count[bits]++; - xbits = 0; - if (n >= base) xbits = extra[n - base]; - f = tree[n * 2]; - s.opt_len += f * (bits + xbits); - if (has_stree) s.static_len += f * (stree[n * 2 + 1] + xbits); - } - if (overflow === 0) return; - do { - bits = max_length - 1; - while (s.bl_count[bits] === 0) bits--; - s.bl_count[bits]--; - s.bl_count[bits + 1] += 2; - s.bl_count[max_length]--; - overflow -= 2; - } while (overflow > 0); - for (bits = max_length; bits !== 0; bits--) { - n = s.bl_count[bits]; - while (n !== 0) { - m = s.heap[--h]; - if (m > max_code) continue; - if (tree[m * 2 + 1] !== bits) { - s.opt_len += (bits - tree[m * 2 + 1]) * tree[m * 2]; - tree[m * 2 + 1] = bits; - } - n--; - } - } -}; -var gen_codes = (tree, max_code, bl_count) => { - const next_code = new Array(16); - let code = 0; - let bits; - let n; - for (bits = 1; bits <= MAX_BITS; bits++) { - code = code + bl_count[bits - 1] << 1; - next_code[bits] = code; - } - for (n = 0; n <= max_code; n++) { - let len = tree[n * 2 + 1]; - if (len === 0) continue; - tree[n * 2] = bi_reverse(next_code[len]++, len); - } -}; -var tr_static_init = () => { - let n; - let bits; - let length; - let code; - let dist; - const bl_count = new Array(16); - length = 0; - for (code = 0; code < LENGTH_CODES - 1; code++) { - base_length[code] = length; - for (n = 0; n < 1 << extra_lbits[code]; n++) _length_code[length++] = code; - } - _length_code[length - 1] = code; - dist = 0; - for (code = 0; code < 16; code++) { - base_dist[code] = dist; - for (n = 0; n < 1 << extra_dbits[code]; n++) _dist_code[dist++] = code; - } - dist >>= 7; - for (; code < D_CODES; code++) { - base_dist[code] = dist << 7; - for (n = 0; n < 1 << extra_dbits[code] - 7; n++) _dist_code[256 + dist++] = code; - } - for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; - n = 0; - while (n <= 143) { - static_ltree[n * 2 + 1] = 8; - n++; - bl_count[8]++; - } - while (n <= 255) { - static_ltree[n * 2 + 1] = 9; - n++; - bl_count[9]++; - } - while (n <= 279) { - static_ltree[n * 2 + 1] = 7; - n++; - bl_count[7]++; - } - while (n <= 287) { - static_ltree[n * 2 + 1] = 8; - n++; - bl_count[8]++; - } - gen_codes(static_ltree, 287, bl_count); - for (n = 0; n < D_CODES; n++) { - static_dtree[n * 2 + 1] = 5; - static_dtree[n * 2] = bi_reverse(n, 5); - } - static_l_desc = new StaticTreeDesc(static_ltree, extra_lbits, 257, L_CODES, MAX_BITS); - static_d_desc = new StaticTreeDesc(static_dtree, extra_dbits, 0, D_CODES, MAX_BITS); - static_bl_desc = new StaticTreeDesc(new Array(0), extra_blbits, 0, BL_CODES, MAX_BL_BITS); -}; -var init_block = (s) => { - let n = 0; - for (; n < L_CODES; n++) s.dyn_ltree[n * 2] = 0; - for (n = 0; n < D_CODES; n++) s.dyn_dtree[n * 2] = 0; - for (n = 0; n < BL_CODES; n++) s.bl_tree[n * 2] = 0; - s.dyn_ltree[END_BLOCK * 2] = 1; - s.opt_len = s.static_len = 0; - s.sym_next = s.matches = 0; -}; -var bi_windup = (s) => { - if (s.bi_valid > 8) put_short(s, s.bi_buf); - else if (s.bi_valid > 0) s.pending_buf[s.pending++] = s.bi_buf; - s.bi_buf = 0; - s.bi_valid = 0; -}; -var smaller = (tree, n, m, depth) => { - const _n2 = n * 2; - const _m2 = m * 2; - return tree[_n2] < tree[_m2] || tree[_n2] === tree[_m2] && depth[n] <= depth[m]; -}; -var pqdownheap = (s, tree, k) => { - const v = s.heap[k]; - let j = k << 1; - while (j <= s.heap_len) { - if (j < s.heap_len && smaller(tree, s.heap[j + 1], s.heap[j], s.depth)) j++; - if (smaller(tree, v, s.heap[j], s.depth)) break; - s.heap[k] = s.heap[j]; - k = j; - j <<= 1; - } - s.heap[k] = v; -}; -var compress_block = (s, ltree, dtree) => { - let dist; - let lc; - let sx = 0; - let code; - let extra; - if (s.sym_next !== 0) do { - dist = s.pending_buf[s.sym_buf + sx++] & 255; - dist += (s.pending_buf[s.sym_buf + sx++] & 255) << 8; - lc = s.pending_buf[s.sym_buf + sx++]; - if (dist === 0) send_code(s, lc, ltree); - else { - code = _length_code[lc]; - send_code(s, code + LITERALS + 1, ltree); - extra = extra_lbits[code]; - if (extra !== 0) { - lc -= base_length[code]; - send_bits(s, lc, extra); - } - dist--; - code = d_code(dist); - send_code(s, code, dtree); - extra = extra_dbits[code]; - if (extra !== 0) { - dist -= base_dist[code]; - send_bits(s, dist, extra); - } - } - } while (sx < s.sym_next); - send_code(s, END_BLOCK, ltree); -}; -var build_tree = (s, desc) => { - const tree = desc.dyn_tree; - const stree = desc.stat_desc.static_tree; - const has_stree = desc.stat_desc.has_stree; - const elems = desc.stat_desc.elems; - let n, m; - let max_code = -1; - let node; - s.heap_len = 0; - s.heap_max = HEAP_SIZE$1; - for (n = 0; n < elems; n++) if (tree[n * 2] !== 0) { - s.heap[++s.heap_len] = max_code = n; - s.depth[n] = 0; - } else tree[n * 2 + 1] = 0; - while (s.heap_len < 2) { - node = s.heap[++s.heap_len] = max_code < 2 ? ++max_code : 0; - tree[node * 2] = 1; - s.depth[node] = 0; - s.opt_len--; - if (has_stree) s.static_len -= stree[node * 2 + 1]; - } - desc.max_code = max_code; - for (n = s.heap_len >> 1; n >= 1; n--) pqdownheap(s, tree, n); - node = elems; - do { - /*** pqremove ***/ - n = s.heap[1]; - s.heap[1] = s.heap[s.heap_len--]; - pqdownheap(s, tree, 1); - m = s.heap[1]; - s.heap[--s.heap_max] = n; - s.heap[--s.heap_max] = m; - tree[node * 2] = tree[n * 2] + tree[m * 2]; - s.depth[node] = (s.depth[n] >= s.depth[m] ? s.depth[n] : s.depth[m]) + 1; - tree[n * 2 + 1] = tree[m * 2 + 1] = node; - s.heap[1] = node++; - pqdownheap(s, tree, 1); - } while (s.heap_len >= 2); - s.heap[--s.heap_max] = s.heap[1]; - gen_bitlen(s, desc); - gen_codes(tree, max_code, s.bl_count); -}; -var scan_tree = (s, tree, max_code) => { - let n; - let prevlen = -1; - let curlen; - let nextlen = tree[1]; - let count = 0; - let max_count = 7; - let min_count = 4; - if (nextlen === 0) { - max_count = 138; - min_count = 3; - } - tree[(max_code + 1) * 2 + 1] = 65535; - for (n = 0; n <= max_code; n++) { - curlen = nextlen; - nextlen = tree[(n + 1) * 2 + 1]; - if (++count < max_count && curlen === nextlen) continue; - else if (count < min_count) s.bl_tree[curlen * 2] += count; - else if (curlen !== 0) { - if (curlen !== prevlen) s.bl_tree[curlen * 2]++; - s.bl_tree[32]++; - } else if (count <= 10) s.bl_tree[34]++; - else s.bl_tree[36]++; - count = 0; - prevlen = curlen; - if (nextlen === 0) { - max_count = 138; - min_count = 3; - } else if (curlen === nextlen) { - max_count = 6; - min_count = 3; - } else { - max_count = 7; - min_count = 4; - } - } -}; -var send_tree = (s, tree, max_code) => { - let n; - let prevlen = -1; - let curlen; - let nextlen = tree[1]; - let count = 0; - let max_count = 7; - let min_count = 4; - if (nextlen === 0) { - max_count = 138; - min_count = 3; - } - for (n = 0; n <= max_code; n++) { - curlen = nextlen; - nextlen = tree[(n + 1) * 2 + 1]; - if (++count < max_count && curlen === nextlen) continue; - else if (count < min_count) do - send_code(s, curlen, s.bl_tree); - while (--count !== 0); - else if (curlen !== 0) { - if (curlen !== prevlen) { - send_code(s, curlen, s.bl_tree); - count--; - } - send_code(s, REP_3_6, s.bl_tree); - send_bits(s, count - 3, 2); - } else if (count <= 10) { - send_code(s, REPZ_3_10, s.bl_tree); - send_bits(s, count - 3, 3); - } else { - send_code(s, REPZ_11_138, s.bl_tree); - send_bits(s, count - 11, 7); - } - count = 0; - prevlen = curlen; - if (nextlen === 0) { - max_count = 138; - min_count = 3; - } else if (curlen === nextlen) { - max_count = 6; - min_count = 3; - } else { - max_count = 7; - min_count = 4; + let { A, B, C, D, E, F, G, H } = this; + for (let i = 0; i < 64; i++) { + const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25); + const T1 = H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i] | 0; + const T2 = (rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22)) + Maj(A, B, C) | 0; + H = G; + G = F; + F = E; + E = D + T1 | 0; + D = C; + C = B; + B = A; + A = T1 + T2 | 0; } + A = A + this.A | 0; + B = B + this.B | 0; + C = C + this.C | 0; + D = D + this.D | 0; + E = E + this.E | 0; + F = F + this.F | 0; + G = G + this.G | 0; + H = H + this.H | 0; + this.set(A, B, C, D, E, F, G, H); } -}; -var build_bl_tree = (s) => { - let max_blindex; - scan_tree(s, s.dyn_ltree, s.l_desc.max_code); - scan_tree(s, s.dyn_dtree, s.d_desc.max_code); - build_tree(s, s.bl_desc); - for (max_blindex = 18; max_blindex >= 3; max_blindex--) if (s.bl_tree[bl_order[max_blindex] * 2 + 1] !== 0) break; - s.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4; - return max_blindex; -}; -var send_all_trees = (s, lcodes, dcodes, blcodes) => { - let rank; - send_bits(s, lcodes - 257, 5); - send_bits(s, dcodes - 1, 5); - send_bits(s, blcodes - 4, 4); - for (rank = 0; rank < blcodes; rank++) send_bits(s, s.bl_tree[bl_order[rank] * 2 + 1], 3); - send_tree(s, s.dyn_ltree, lcodes - 1); - send_tree(s, s.dyn_dtree, dcodes - 1); -}; -var detect_data_type = (s) => { - let block_mask = 4093624447; - let n = 0; - for (; n <= 31; n++, block_mask >>>= 1) if (block_mask & 1 && s.dyn_ltree[n * 2] !== 0) return Z_BINARY; - if (s.dyn_ltree[18] !== 0 || s.dyn_ltree[20] !== 0 || s.dyn_ltree[26] !== 0) return Z_TEXT; - for (n = 32; n < LITERALS; n++) if (s.dyn_ltree[n * 2] !== 0) return Z_TEXT; - return Z_BINARY; -}; -var static_init_done = false; -var _tr_init = (s) => { - if (!static_init_done) { - tr_static_init(); - static_init_done = true; - } - s.l_desc = new TreeDesc(s.dyn_ltree, static_l_desc); - s.d_desc = new TreeDesc(s.dyn_dtree, static_d_desc); - s.bl_desc = new TreeDesc(s.bl_tree, static_bl_desc); - s.bi_buf = 0; - s.bi_valid = 0; - init_block(s); -}; -var _tr_stored_block = (s, buf, stored_len, last) => { - send_bits(s, 0 + (last ? 1 : 0), 3); - bi_windup(s); - put_short(s, stored_len); - put_short(s, ~stored_len); - if (stored_len) s.pending_buf.set(s.window.subarray(buf, buf + stored_len), s.pending); - s.pending += stored_len; -}; -var _tr_align = (s) => { - send_bits(s, 2, 3); - send_code(s, END_BLOCK, static_ltree); - bi_flush(s); -}; -var _tr_flush_block = (s, buf, stored_len, last) => { - let opt_lenb, static_lenb; - let max_blindex = 0; - if (s.level > 0) { - if (s.strm.data_type === Z_UNKNOWN) s.strm.data_type = detect_data_type(s); - build_tree(s, s.l_desc); - build_tree(s, s.d_desc); - max_blindex = build_bl_tree(s); - opt_lenb = s.opt_len + 3 + 7 >>> 3; - static_lenb = s.static_len + 3 + 7 >>> 3; - if (static_lenb <= opt_lenb) opt_lenb = static_lenb; - } else opt_lenb = static_lenb = stored_len + 5; - if (stored_len + 4 <= opt_lenb && buf !== -1) _tr_stored_block(s, buf, stored_len, last); - else if (s.strategy === Z_FIXED || static_lenb === opt_lenb) { - send_bits(s, 2 + (last ? 1 : 0), 3); - compress_block(s, static_ltree, static_dtree); - } else { - send_bits(s, 4 + (last ? 1 : 0), 3); - send_all_trees(s, s.l_desc.max_code + 1, s.d_desc.max_code + 1, max_blindex + 1); - compress_block(s, s.dyn_ltree, s.dyn_dtree); + roundClean() { + clean$1(SHA256_W); } - init_block(s); - if (last) bi_windup(s); -}; -var _tr_tally = (s, dist, lc) => { - s.pending_buf[s.sym_buf + s.sym_next++] = dist; - s.pending_buf[s.sym_buf + s.sym_next++] = dist >> 8; - s.pending_buf[s.sym_buf + s.sym_next++] = lc; - if (dist === 0) s.dyn_ltree[lc * 2]++; - else { - s.matches++; - dist--; - s.dyn_ltree[(_length_code[lc] + LITERALS + 1) * 2]++; - s.dyn_dtree[d_code(dist) * 2]++; + destroy() { + this.destroyed = true; + this.set(0, 0, 0, 0, 0, 0, 0, 0); + clean$1(this.buffer); } - return s.sym_next === s.sym_end; -}; -var adler32 = (adler, buf, len, pos) => { - let s1 = adler & 65535 | 0, s2 = adler >>> 16 & 65535 | 0, n = 0; - while (len !== 0) { - n = len > 2e3 ? 2e3 : len; - len -= n; - do { - s1 = s1 + buf[pos++] | 0; - s2 = s2 + s1 | 0; - } while (--n); - s1 %= 65521; - s2 %= 65521; - } - return s1 | s2 << 16 | 0; -}; -var makeTable = () => { - let c, table = []; - for (var n = 0; n < 256; n++) { - c = n; - for (var k = 0; k < 8; k++) c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1; - table[n] = c; - } - return table; -}; -var crcTable = new Uint32Array(makeTable()); -var crc32$2 = (crc, buf, len, pos) => { - const t = crcTable; - const end = pos + len; - crc ^= -1; - for (let i = pos; i < end; i++) crc = crc >>> 8 ^ t[(crc ^ buf[i]) & 255]; - return crc ^ -1; -}; -var messages_default = { - 2: "need dictionary", - 1: "stream end", - 0: "", - "-1": "file error", - "-2": "stream error", - "-3": "data error", - "-4": "insufficient memory", - "-5": "buffer error", - "-6": "incompatible version" }; -var MAX_MEM_LEVEL = 9; -var HEAP_SIZE = 573; -var MIN_MATCH = 3; -var MAX_MATCH = 258; -var MIN_LOOKAHEAD = 262; -var PRESET_DICT = 32; -var INIT_STATE = 42; -var GZIP_STATE = 57; -var EXTRA_STATE = 69; -var NAME_STATE = 73; -var COMMENT_STATE = 91; -var HCRC_STATE = 103; -var BUSY_STATE = 113; -var FINISH_STATE = 666; -var BS_NEED_MORE = 1; -var BS_BLOCK_DONE = 2; -var BS_FINISH_STARTED = 3; -var BS_FINISH_DONE = 4; -var OS_CODE = 3; -var err = (strm, errorCode) => { - strm.msg = messages_default[errorCode]; - return errorCode; -}; -var rank = (f) => { - return f * 2 - (f > 4 ? 9 : 0); -}; -var zero = (buf) => { - let len = buf.length; - while (--len >= 0) buf[len] = 0; -}; -var slide_hash = (s) => { - let n, m; - let p; - let wsize = s.w_size; - n = s.hash_size; - p = n; - do { - m = s.head[--p]; - s.head[p] = m >= wsize ? m - wsize : 0; - } while (--n); - n = wsize; - p = n; - do { - m = s.prev[--p]; - s.prev[p] = m >= wsize ? m - wsize : 0; - } while (--n); -}; -var HASH = (s, prev, data) => (prev << s.hash_shift ^ data) & s.hash_mask; -var INSERT_STRING = (s, str) => { - let h; - if (s.legacy_hash) h = s.ins_h = HASH(s, s.ins_h, s.window[str + MIN_MATCH - 1]); - else { - const w = s.window; - const value = w[str] | w[str + 1] << 8 | w[str + 2] << 16 | w[str + 3] << 24; - h = s.ins_h = Math.imul(value, 66521) + 66521 >>> 16 & s.hash_mask; +/** Internal SHA-256 hash class grounded in RFC 6234 §6.2. */ +var _SHA256 = class extends SHA2_32B { + constructor() { + super(32, SHA256_IV); } - const hash_head = s.prev[str & s.w_mask] = s.head[h]; - s.head[h] = str; - return hash_head; -}; -var flush_pending = (strm) => { - const s = strm.state; - let len = s.pending; - if (len > strm.avail_out) len = strm.avail_out; - if (len === 0) return; - strm.output.set(s.pending_buf.subarray(s.pending_out, s.pending_out + len), strm.next_out); - strm.next_out += len; - s.pending_out += len; - strm.total_out += len; - strm.avail_out -= len; - s.pending -= len; - if (s.pending === 0) s.pending_out = 0; -}; -var flush_block_only = (s, last) => { - _tr_flush_block(s, s.block_start >= 0 ? s.block_start : -1, s.strstart - s.block_start, last); - s.block_start = s.strstart; - flush_pending(s.strm); -}; -var put_byte = (s, b) => { - s.pending_buf[s.pending++] = b; -}; -var putShortMSB = (s, b) => { - s.pending_buf[s.pending++] = b >>> 8 & 255; - s.pending_buf[s.pending++] = b & 255; }; -var read_buf = (strm, buf, start, size) => { - let len = strm.avail_in; - if (len > size) len = size; - if (len === 0) return 0; - strm.avail_in -= len; - buf.set(strm.input.subarray(strm.next_in, strm.next_in + len), start); - if (strm.state.wrap === 1) strm.adler = adler32(strm.adler, buf, len, start); - else if (strm.state.wrap === 2) strm.adler = crc32$2(strm.adler, buf, len, start); - strm.next_in += len; - strm.total_in += len; - return len; -}; -var longest_match = (s, cur_match) => { - let chain_length = s.max_chain_length; - let scan = s.strstart; - let match; - let len; - let best_len = s.prev_length; - let nice_match = s.nice_match; - const limit = s.strstart > s.w_size - MIN_LOOKAHEAD ? s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0; - const _win = s.window; - const wmask = s.w_mask; - const prev = s.prev; - const strend = s.strstart + MAX_MATCH; - let scan_end1 = _win[scan + best_len - 1]; - let scan_end = _win[scan + best_len]; - if (s.prev_length >= s.good_match) chain_length >>= 2; - if (nice_match > s.lookahead) nice_match = s.lookahead; - do { - match = cur_match; - if (_win[match + best_len] !== scan_end || _win[match + best_len - 1] !== scan_end1 || _win[match] !== _win[scan] || _win[++match] !== _win[scan + 1]) continue; - scan += 2; - match++; - do ; -while (_win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && scan < strend); - len = MAX_MATCH - (strend - scan); - scan = strend - MAX_MATCH; - if (len > best_len) { - s.match_start = cur_match; - best_len = len; - if (len >= nice_match) break; - scan_end1 = _win[scan + best_len - 1]; - scan_end = _win[scan + best_len]; - } - } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length !== 0); - if (best_len <= s.lookahead) return best_len; - return s.lookahead; -}; -var fill_window = (s) => { - const _w_size = s.w_size; - let n, more, str; - do { - more = s.window_size - s.lookahead - s.strstart; - if (s.strstart >= _w_size + (_w_size - MIN_LOOKAHEAD)) { - s.window.set(s.window.subarray(_w_size, _w_size + _w_size - more), 0); - s.match_start -= _w_size; - s.strstart -= _w_size; - s.block_start -= _w_size; - if (s.insert > s.strstart) s.insert = s.strstart; - slide_hash(s); - more += _w_size; - } - if (s.strm.avail_in === 0) break; - n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more); - s.lookahead += n; - if (!s.legacy_hash) { - if (s.lookahead + s.insert > MIN_MATCH) { - str = s.strstart - s.insert; - while (s.insert) { - INSERT_STRING(s, str); - str++; - s.insert--; - if (s.lookahead + s.insert <= MIN_MATCH) break; - } - } - } else if (s.lookahead + s.insert >= MIN_MATCH) { - str = s.strstart - s.insert; - s.ins_h = s.window[str]; - s.ins_h = HASH(s, s.ins_h, s.window[str + 1]); - while (s.insert) { - INSERT_STRING(s, str); - str++; - s.insert--; - if (s.lookahead + s.insert < MIN_MATCH) break; - } - } - } while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0); -}; -var deflate_stored = (s, flush) => { - let min_block = s.pending_buf_size - 5 > s.w_size ? s.w_size : s.pending_buf_size - 5; - let len, left, have, last = 0; - let used = s.strm.avail_in; - do { - len = 65535; - have = s.bi_valid + 42 >> 3; - if (s.strm.avail_out < have) break; - have = s.strm.avail_out - have; - left = s.strstart - s.block_start; - if (len > left + s.strm.avail_in) len = left + s.strm.avail_in; - if (len > have) len = have; - if (len < min_block && (len === 0 && flush !== 4 || flush === 0 || len !== left + s.strm.avail_in)) break; - last = flush === 4 && len === left + s.strm.avail_in ? 1 : 0; - _tr_stored_block(s, 0, 0, last); - s.pending_buf[s.pending - 4] = len; - s.pending_buf[s.pending - 3] = len >> 8; - s.pending_buf[s.pending - 2] = ~len; - s.pending_buf[s.pending - 1] = ~len >> 8; - flush_pending(s.strm); - if (left) { - if (left > len) left = len; - s.strm.output.set(s.window.subarray(s.block_start, s.block_start + left), s.strm.next_out); - s.strm.next_out += left; - s.strm.avail_out -= left; - s.strm.total_out += left; - s.block_start += left; - len -= left; - } - if (len) { - read_buf(s.strm, s.strm.output, s.strm.next_out, len); - s.strm.next_out += len; - s.strm.avail_out -= len; - s.strm.total_out += len; - } - } while (last === 0); - used -= s.strm.avail_in; - if (used) { - if (used >= s.w_size) { - s.matches = 2; - s.window.set(s.strm.input.subarray(s.strm.next_in - s.w_size, s.strm.next_in), 0); - s.strstart = s.w_size; - s.insert = s.strstart; - } else { - if (s.window_size - s.strstart <= used) { - s.strstart -= s.w_size; - s.window.set(s.window.subarray(s.w_size, s.w_size + s.strstart), 0); - if (s.matches < 2) s.matches++; - if (s.insert > s.strstart) s.insert = s.strstart; - } - s.window.set(s.strm.input.subarray(s.strm.next_in - used, s.strm.next_in), s.strstart); - s.strstart += used; - s.insert += used > s.w_size - s.insert ? s.w_size - s.insert : used; - } - s.block_start = s.strstart; - } - if (s.high_water < s.strstart) s.high_water = s.strstart; - if (last) return BS_FINISH_DONE; - if (flush !== 0 && flush !== 4 && s.strm.avail_in === 0 && s.strstart === s.block_start) return BS_BLOCK_DONE; - have = s.window_size - s.strstart; - if (s.strm.avail_in > have && s.block_start >= s.w_size) { - s.block_start -= s.w_size; - s.strstart -= s.w_size; - s.window.set(s.window.subarray(s.w_size, s.w_size + s.strstart), 0); - if (s.matches < 2) s.matches++; - have += s.w_size; - if (s.insert > s.strstart) s.insert = s.strstart; - } - if (have > s.strm.avail_in) have = s.strm.avail_in; - if (have) { - read_buf(s.strm, s.window, s.strstart, have); - s.strstart += have; - s.insert += have > s.w_size - s.insert ? s.w_size - s.insert : have; - } - if (s.high_water < s.strstart) s.high_water = s.strstart; - have = s.bi_valid + 42 >> 3; - have = s.pending_buf_size - have > 65535 ? 65535 : s.pending_buf_size - have; - min_block = have > s.w_size ? s.w_size : have; - left = s.strstart - s.block_start; - if (left >= min_block || (left || flush === 4) && flush !== 0 && s.strm.avail_in === 0 && left <= have) { - len = left > have ? have : left; - last = flush === 4 && s.strm.avail_in === 0 && len === left ? 1 : 0; - _tr_stored_block(s, s.block_start, len, last); - s.block_start += len; - flush_pending(s.strm); - } - return last ? BS_FINISH_STARTED : BS_NEED_MORE; -}; -var deflate_fast = (s, flush) => { - let hash_head; - let bflush; - for (;;) { - if (s.lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s.lookahead < MIN_LOOKAHEAD && flush === 0) return BS_NEED_MORE; - if (s.lookahead === 0) break; - } - hash_head = 0; - if (s.lookahead >= MIN_MATCH) hash_head = INSERT_STRING(s, s.strstart); - if (hash_head !== 0 && s.strstart - hash_head <= s.w_size - MIN_LOOKAHEAD) s.match_length = longest_match(s, hash_head); - if (s.match_length >= MIN_MATCH) { - /*** _tr_tally_dist(s, s.strstart - s.match_start, - s.match_length - MIN_MATCH, bflush); ***/ - bflush = _tr_tally(s, s.strstart - s.match_start, s.match_length - MIN_MATCH); - s.lookahead -= s.match_length; - if (s.match_length <= s.max_lazy_match && s.lookahead >= MIN_MATCH) { - s.match_length--; - do { - s.strstart++; - hash_head = INSERT_STRING(s, s.strstart); - } while (--s.match_length !== 0); - s.strstart++; - } else { - s.strstart += s.match_length; - s.match_length = 0; - if (s.legacy_hash) { - s.ins_h = s.window[s.strstart]; - s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + 1]); - } - } - } else { - /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ - bflush = _tr_tally(s, 0, s.window[s.strstart]); - s.lookahead--; - s.strstart++; - } - if (bflush) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) return BS_NEED_MORE; - } - } - s.insert = s.strstart < MIN_MATCH - 1 ? s.strstart : MIN_MATCH - 1; - if (flush === 4) { - /*** FLUSH_BLOCK(s, 1); ***/ - flush_block_only(s, true); - if (s.strm.avail_out === 0) return BS_FINISH_STARTED; - return BS_FINISH_DONE; - } - if (s.sym_next) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) return BS_NEED_MORE; - } - return BS_BLOCK_DONE; -}; -var deflate_slow = (s, flush) => { - let hash_head; - let bflush; - let max_insert; - for (;;) { - if (s.lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s.lookahead < MIN_LOOKAHEAD && flush === 0) return BS_NEED_MORE; - if (s.lookahead === 0) break; - } - hash_head = 0; - if (s.lookahead >= MIN_MATCH) hash_head = INSERT_STRING(s, s.strstart); - s.prev_length = s.match_length; - s.prev_match = s.match_start; - s.match_length = MIN_MATCH - 1; - if (hash_head !== 0 && s.prev_length < s.max_lazy_match && s.strstart - hash_head <= s.w_size - MIN_LOOKAHEAD) { - s.match_length = longest_match(s, hash_head); - if (s.match_length <= 5 && (s.strategy === 1 || s.match_length === MIN_MATCH && s.strstart - s.match_start > 4096)) s.match_length = MIN_MATCH - 1; - } - if (s.prev_length >= MIN_MATCH && s.match_length <= s.prev_length) { - max_insert = s.strstart + s.lookahead - MIN_MATCH; - /***_tr_tally_dist(s, s.strstart - 1 - s.prev_match, - s.prev_length - MIN_MATCH, bflush);***/ - bflush = _tr_tally(s, s.strstart - 1 - s.prev_match, s.prev_length - MIN_MATCH); - s.lookahead -= s.prev_length - 1; - s.prev_length -= 2; - do - if (++s.strstart <= max_insert) hash_head = INSERT_STRING(s, s.strstart); - while (--s.prev_length !== 0); - s.match_available = 0; - s.match_length = MIN_MATCH - 1; - s.strstart++; - if (bflush) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) return BS_NEED_MORE; - } - } else if (s.match_available) { - /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/ - bflush = _tr_tally(s, 0, s.window[s.strstart - 1]); - if (bflush) - /*** FLUSH_BLOCK_ONLY(s, 0) ***/ - flush_block_only(s, false); - s.strstart++; - s.lookahead--; - if (s.strm.avail_out === 0) return BS_NEED_MORE; - } else { - s.match_available = 1; - s.strstart++; - s.lookahead--; - } +const K512 = /* @__PURE__ */ (() => split$1([ + "0x428a2f98d728ae22", + "0x7137449123ef65cd", + "0xb5c0fbcfec4d3b2f", + "0xe9b5dba58189dbbc", + "0x3956c25bf348b538", + "0x59f111f1b605d019", + "0x923f82a4af194f9b", + "0xab1c5ed5da6d8118", + "0xd807aa98a3030242", + "0x12835b0145706fbe", + "0x243185be4ee4b28c", + "0x550c7dc3d5ffb4e2", + "0x72be5d74f27b896f", + "0x80deb1fe3b1696b1", + "0x9bdc06a725c71235", + "0xc19bf174cf692694", + "0xe49b69c19ef14ad2", + "0xefbe4786384f25e3", + "0x0fc19dc68b8cd5b5", + "0x240ca1cc77ac9c65", + "0x2de92c6f592b0275", + "0x4a7484aa6ea6e483", + "0x5cb0a9dcbd41fbd4", + "0x76f988da831153b5", + "0x983e5152ee66dfab", + "0xa831c66d2db43210", + "0xb00327c898fb213f", + "0xbf597fc7beef0ee4", + "0xc6e00bf33da88fc2", + "0xd5a79147930aa725", + "0x06ca6351e003826f", + "0x142929670a0e6e70", + "0x27b70a8546d22ffc", + "0x2e1b21385c26c926", + "0x4d2c6dfc5ac42aed", + "0x53380d139d95b3df", + "0x650a73548baf63de", + "0x766a0abb3c77b2a8", + "0x81c2c92e47edaee6", + "0x92722c851482353b", + "0xa2bfe8a14cf10364", + "0xa81a664bbc423001", + "0xc24b8b70d0f89791", + "0xc76c51a30654be30", + "0xd192e819d6ef5218", + "0xd69906245565a910", + "0xf40e35855771202a", + "0x106aa07032bbd1b8", + "0x19a4c116b8d2d0c8", + "0x1e376c085141ab53", + "0x2748774cdf8eeb99", + "0x34b0bcb5e19b48a8", + "0x391c0cb3c5c95a63", + "0x4ed8aa4ae3418acb", + "0x5b9cca4f7763e373", + "0x682e6ff3d6b2b8a3", + "0x748f82ee5defb2fc", + "0x78a5636f43172f60", + "0x84c87814a1f0ab72", + "0x8cc702081a6439ec", + "0x90befffa23631e28", + "0xa4506cebde82bde9", + "0xbef9a3f7b2c67915", + "0xc67178f2e372532b", + "0xca273eceea26619c", + "0xd186b8c721c0c207", + "0xeada7dd6cde0eb1e", + "0xf57d4f7fee6ed178", + "0x06f067aa72176fba", + "0x0a637dc5a2c898a6", + "0x113f9804bef90dae", + "0x1b710b35131c471b", + "0x28db77f523047d84", + "0x32caab7b40c72493", + "0x3c9ebe0a15c9bebc", + "0x431d67c49c100d4c", + "0x4cc5d4becb3e42b6", + "0x597f299cfc657e2a", + "0x5fcb6fab3ad6faec", + "0x6c44198c4a475817" +].map((n) => BigInt(n))))(); +const SHA512_Kh = /* @__PURE__ */ (() => K512[0])(); +const SHA512_Kl = /* @__PURE__ */ (() => K512[1])(); +const SHA512_W_H = /* @__PURE__ */ new Uint32Array(80); +const SHA512_W_L = /* @__PURE__ */ new Uint32Array(80); +/** Internal SHA-384 / SHA-512 compression engine from RFC 6234 §6.4. */ +var SHA2_64B = class extends HashMD { + Ah = 0; + Al = 0; + Bh = 0; + Bl = 0; + Ch = 0; + Cl = 0; + Dh = 0; + Dl = 0; + Eh = 0; + El = 0; + Fh = 0; + Fl = 0; + Gh = 0; + Gl = 0; + Hh = 0; + Hl = 0; + constructor(outputLen, IV) { + super(128, outputLen, 16, false); + this.Ah = IV[0] | 0; + this.Al = IV[1] | 0; + this.Bh = IV[2] | 0; + this.Bl = IV[3] | 0; + this.Ch = IV[4] | 0; + this.Cl = IV[5] | 0; + this.Dh = IV[6] | 0; + this.Dl = IV[7] | 0; + this.Eh = IV[8] | 0; + this.El = IV[9] | 0; + this.Fh = IV[10] | 0; + this.Fl = IV[11] | 0; + this.Gh = IV[12] | 0; + this.Gl = IV[13] | 0; + this.Hh = IV[14] | 0; + this.Hl = IV[15] | 0; } - if (s.match_available) { - /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/ - bflush = _tr_tally(s, 0, s.window[s.strstart - 1]); - s.match_available = 0; + get() { + const { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this; + return [ + Ah, + Al, + Bh, + Bl, + Ch, + Cl, + Dh, + Dl, + Eh, + El, + Fh, + Fl, + Gh, + Gl, + Hh, + Hl + ]; } - s.insert = s.strstart < MIN_MATCH - 1 ? s.strstart : MIN_MATCH - 1; - if (flush === 4) { - /*** FLUSH_BLOCK(s, 1); ***/ - flush_block_only(s, true); - if (s.strm.avail_out === 0) return BS_FINISH_STARTED; - return BS_FINISH_DONE; + set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl) { + this.Ah = Ah | 0; + this.Al = Al | 0; + this.Bh = Bh | 0; + this.Bl = Bl | 0; + this.Ch = Ch | 0; + this.Cl = Cl | 0; + this.Dh = Dh | 0; + this.Dl = Dl | 0; + this.Eh = Eh | 0; + this.El = El | 0; + this.Fh = Fh | 0; + this.Fl = Fl | 0; + this.Gh = Gh | 0; + this.Gl = Gl | 0; + this.Hh = Hh | 0; + this.Hl = Hl | 0; } - if (s.sym_next) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) return BS_NEED_MORE; + _cloneInto(to) { + (to ||= new this.constructor()).set(...this.get()); + return this._cloneIntoMeta(to); } - return BS_BLOCK_DONE; -}; -var deflate_rle = (s, flush) => { - let bflush; - let prev; - let scan, strend; - const _win = s.window; - for (;;) { - if (s.lookahead <= MAX_MATCH) { - fill_window(s); - if (s.lookahead <= MAX_MATCH && flush === 0) return BS_NEED_MORE; - if (s.lookahead === 0) break; - } - s.match_length = 0; - if (s.lookahead >= MIN_MATCH && s.strstart > 0) { - scan = s.strstart - 1; - prev = _win[scan]; - if (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan]) { - strend = s.strstart + MAX_MATCH; - do ; -while (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan] && scan < strend); - s.match_length = MAX_MATCH - (strend - scan); - if (s.match_length > s.lookahead) s.match_length = s.lookahead; - } + process(view, offset) { + for (let i = 0; i < 16; i++, offset += 4) { + SHA512_W_H[i] = view.getUint32(offset); + SHA512_W_L[i] = view.getUint32(offset += 4); } - if (s.match_length >= MIN_MATCH) { - /*** _tr_tally_dist(s, 1, s.match_length - MIN_MATCH, bflush); ***/ - bflush = _tr_tally(s, 1, s.match_length - MIN_MATCH); - s.lookahead -= s.match_length; - s.strstart += s.match_length; - s.match_length = 0; - } else { - /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ - bflush = _tr_tally(s, 0, s.window[s.strstart]); - s.lookahead--; - s.strstart++; + for (let i = 16; i < 80; i++) { + const W15h = SHA512_W_H[i - 15] | 0; + const W15l = SHA512_W_L[i - 15] | 0; + const s0h = rotrSH(W15h, W15l, 1) ^ rotrSH(W15h, W15l, 8) ^ shrSH(W15h, W15l, 7); + const s0l = rotrSL(W15h, W15l, 1) ^ rotrSL(W15h, W15l, 8) ^ shrSL(W15h, W15l, 7); + const W2h = SHA512_W_H[i - 2] | 0; + const W2l = SHA512_W_L[i - 2] | 0; + const s1h = rotrSH(W2h, W2l, 19) ^ rotrBH(W2h, W2l, 61) ^ shrSH(W2h, W2l, 6); + const s1l = rotrSL(W2h, W2l, 19) ^ rotrBL(W2h, W2l, 61) ^ shrSL(W2h, W2l, 6); + const SUMl = add4L(s0l, s1l, SHA512_W_L[i - 7], SHA512_W_L[i - 16]); + const SUMh = add4H(SUMl, s0h, s1h, SHA512_W_H[i - 7], SHA512_W_H[i - 16]); + SHA512_W_H[i] = SUMh | 0; + SHA512_W_L[i] = SUMl | 0; } - if (bflush) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) return BS_NEED_MORE; + let { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this; + for (let i = 0; i < 80; i++) { + const sigma1h = rotrSH(Eh, El, 14) ^ rotrSH(Eh, El, 18) ^ rotrBH(Eh, El, 41); + const sigma1l = rotrSL(Eh, El, 14) ^ rotrSL(Eh, El, 18) ^ rotrBL(Eh, El, 41); + const CHIh = Eh & Fh ^ ~Eh & Gh; + const CHIl = El & Fl ^ ~El & Gl; + const T1ll = add5L(Hl, sigma1l, CHIl, SHA512_Kl[i], SHA512_W_L[i]); + const T1h = add5H(T1ll, Hh, sigma1h, CHIh, SHA512_Kh[i], SHA512_W_H[i]); + const T1l = T1ll | 0; + const sigma0h = rotrSH(Ah, Al, 28) ^ rotrBH(Ah, Al, 34) ^ rotrBH(Ah, Al, 39); + const sigma0l = rotrSL(Ah, Al, 28) ^ rotrBL(Ah, Al, 34) ^ rotrBL(Ah, Al, 39); + const MAJh = Ah & Bh ^ Ah & Ch ^ Bh & Ch; + const MAJl = Al & Bl ^ Al & Cl ^ Bl & Cl; + Hh = Gh | 0; + Hl = Gl | 0; + Gh = Fh | 0; + Gl = Fl | 0; + Fh = Eh | 0; + Fl = El | 0; + ({h: Eh, l: El} = add(Dh | 0, Dl | 0, T1h | 0, T1l | 0)); + Dh = Ch | 0; + Dl = Cl | 0; + Ch = Bh | 0; + Cl = Bl | 0; + Bh = Ah | 0; + Bl = Al | 0; + const All = add3L(T1l, sigma0l, MAJl); + Ah = add3H(All, T1h, sigma0h, MAJh); + Al = All | 0; } + ({h: Ah, l: Al} = add(this.Ah | 0, this.Al | 0, Ah | 0, Al | 0)); + ({h: Bh, l: Bl} = add(this.Bh | 0, this.Bl | 0, Bh | 0, Bl | 0)); + ({h: Ch, l: Cl} = add(this.Ch | 0, this.Cl | 0, Ch | 0, Cl | 0)); + ({h: Dh, l: Dl} = add(this.Dh | 0, this.Dl | 0, Dh | 0, Dl | 0)); + ({h: Eh, l: El} = add(this.Eh | 0, this.El | 0, Eh | 0, El | 0)); + ({h: Fh, l: Fl} = add(this.Fh | 0, this.Fl | 0, Fh | 0, Fl | 0)); + ({h: Gh, l: Gl} = add(this.Gh | 0, this.Gl | 0, Gh | 0, Gl | 0)); + ({h: Hh, l: Hl} = add(this.Hh | 0, this.Hl | 0, Hh | 0, Hl | 0)); + this.set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl); } - s.insert = 0; - if (flush === 4) { - /*** FLUSH_BLOCK(s, 1); ***/ - flush_block_only(s, true); - if (s.strm.avail_out === 0) return BS_FINISH_STARTED; - return BS_FINISH_DONE; + roundClean() { + clean$1(SHA512_W_H, SHA512_W_L); } - if (s.sym_next) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) return BS_NEED_MORE; + destroy() { + this.destroyed = true; + clean$1(this.buffer); + this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } - return BS_BLOCK_DONE; }; -var deflate_huff = (s, flush) => { - let bflush; - for (;;) { - if (s.lookahead === 0) { - fill_window(s); - if (s.lookahead === 0) { - if (flush === 0) return BS_NEED_MORE; - break; - } - } - s.match_length = 0; - /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ - bflush = _tr_tally(s, 0, s.window[s.strstart]); - s.lookahead--; - s.strstart++; - if (bflush) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) return BS_NEED_MORE; - } - } - s.insert = 0; - if (flush === 4) { - /*** FLUSH_BLOCK(s, 1); ***/ - flush_block_only(s, true); - if (s.strm.avail_out === 0) return BS_FINISH_STARTED; - return BS_FINISH_DONE; - } - if (s.sym_next) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) return BS_NEED_MORE; - } - return BS_BLOCK_DONE; -}; -var Config = class { - constructor(good_length, max_lazy, nice_length, max_chain, func) { - this.good_length = good_length; - this.max_lazy = max_lazy; - this.nice_length = nice_length; - this.max_chain = max_chain; - this.func = func; +/** Internal SHA-512 hash class grounded in RFC 6234 §6.3 and §6.4. */ +var _SHA512 = class extends SHA2_64B { + constructor() { + super(64, SHA512_IV); } }; -var configuration_table = [ - new Config(0, 0, 0, 0, deflate_stored), - new Config(4, 4, 8, 4, deflate_fast), - new Config(4, 5, 16, 8, deflate_fast), - new Config(4, 6, 32, 32, deflate_fast), - new Config(4, 4, 16, 16, deflate_slow), - new Config(8, 16, 32, 32, deflate_slow), - new Config(8, 16, 128, 128, deflate_slow), - new Config(8, 32, 128, 256, deflate_slow), - new Config(32, 128, 258, 1024, deflate_slow), - new Config(32, 258, 258, 4096, deflate_slow) -]; -var lm_init = (s) => { - s.window_size = 2 * s.w_size; - /*** CLEAR_HASH(s); ***/ - zero(s.head); - s.max_lazy_match = configuration_table[s.level].max_lazy; - s.good_match = configuration_table[s.level].good_length; - s.nice_match = configuration_table[s.level].nice_length; - s.max_chain_length = configuration_table[s.level].max_chain; - s.strstart = 0; - s.block_start = 0; - s.lookahead = 0; - s.insert = 0; - s.match_length = s.prev_length = MIN_MATCH - 1; - s.match_available = 0; - s.ins_h = 0; -}; -var DeflateState = class { +/** Internal SHA-384 hash class grounded in RFC 6234 §6.3 and §6.4. */ +var _SHA384 = class extends SHA2_64B { constructor() { - this.strm = null; - this.status = 0; - this.pending_buf = null; - this.pending_buf_size = 0; - this.pending_out = 0; - this.pending = 0; - this.wrap = 0; - this.gzhead = null; - this.gzindex = 0; - this.method = 8; - this.last_flush = -1; - this.w_size = 0; - this.w_bits = 0; - this.w_mask = 0; - this.window = null; - this.window_size = 0; - this.prev = null; - this.head = null; - this.ins_h = 0; - this.legacy_hash = 0; - this.hash_size = 0; - this.hash_bits = 0; - this.hash_mask = 0; - this.hash_shift = 0; - this.block_start = 0; - this.match_length = 0; - this.prev_match = 0; - this.match_available = 0; - this.strstart = 0; - this.match_start = 0; - this.lookahead = 0; - this.prev_length = 0; - this.max_chain_length = 0; - this.max_lazy_match = 0; - this.level = 0; - this.strategy = 0; - this.good_match = 0; - this.nice_match = 0; - this.dyn_ltree = new Uint16Array(HEAP_SIZE * 2); - this.dyn_dtree = /* @__PURE__ */ new Uint16Array(122); - this.bl_tree = /* @__PURE__ */ new Uint16Array(78); - zero(this.dyn_ltree); - zero(this.dyn_dtree); - zero(this.bl_tree); - this.l_desc = null; - this.d_desc = null; - this.bl_desc = null; - this.bl_count = /* @__PURE__ */ new Uint16Array(16); - this.heap = /* @__PURE__ */ new Uint16Array(573); - zero(this.heap); - this.heap_len = 0; - this.heap_max = 0; - this.depth = /* @__PURE__ */ new Uint16Array(573); - zero(this.depth); - this.sym_buf = 0; - this.lit_bufsize = 0; - this.sym_next = 0; - this.sym_end = 0; - this.opt_len = 0; - this.static_len = 0; - this.matches = 0; - this.insert = 0; - this.bi_buf = 0; - this.bi_valid = 0; + super(48, SHA384_IV); } }; -var deflateStateCheck = (strm) => { - if (!strm) return 1; - const s = strm.state; - if (!s || s.strm !== strm || s.status !== INIT_STATE && s.status !== GZIP_STATE && s.status !== EXTRA_STATE && s.status !== NAME_STATE && s.status !== COMMENT_STATE && s.status !== HCRC_STATE && s.status !== BUSY_STATE && s.status !== FINISH_STATE) return 1; - return 0; -}; -var deflateResetKeep = (strm) => { - if (deflateStateCheck(strm)) return err(strm, -2); - strm.total_in = strm.total_out = 0; - strm.data_type = 2; - const s = strm.state; - s.pending = 0; - s.pending_out = 0; - if (s.wrap < 0) s.wrap = -s.wrap; - s.status = s.wrap === 2 ? GZIP_STATE : s.wrap ? INIT_STATE : BUSY_STATE; - strm.adler = s.wrap === 2 ? 0 : 1; - s.last_flush = -2; - _tr_init(s); - return 0; -}; -var deflateReset = (strm) => { - const ret = deflateResetKeep(strm); - if (ret === 0) lm_init(strm.state); - return ret; -}; -var deflateInit2 = (strm, level, method, windowBits, memLevel, strategy, legacyHash) => { - if (!strm) return -2; - let wrap = 1; - if (level === -1) level = 6; - if (windowBits < 0) { - wrap = 0; - windowBits = -windowBits; - } else if (windowBits > 15) { - wrap = 2; - windowBits -= 16; - } - if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method !== 8 || windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || strategy < 0 || strategy > 4 || windowBits === 8 && wrap !== 1) return err(strm, -2); - if (windowBits === 8) windowBits = 9; - const s = new DeflateState(); - strm.state = s; - s.strm = strm; - s.status = INIT_STATE; - s.wrap = wrap; - s.gzhead = null; - s.w_bits = windowBits; - s.w_size = 1 << s.w_bits; - s.w_mask = s.w_size - 1; - s.legacy_hash = legacyHash ? 1 : 0; - s.hash_bits = memLevel + 7; - if (!s.legacy_hash && s.hash_bits < 15) s.hash_bits = 15; - s.hash_size = 1 << s.hash_bits; - s.hash_mask = s.hash_size - 1; - s.hash_shift = ~~((s.hash_bits + MIN_MATCH - 1) / MIN_MATCH); - s.window = new Uint8Array(s.w_size * 2); - s.head = new Uint16Array(s.hash_size); - s.prev = new Uint16Array(s.w_size); - s.lit_bufsize = 1 << memLevel + 6; - s.pending_buf_size = s.lit_bufsize * 4; - s.pending_buf = new Uint8Array(s.pending_buf_size); - s.sym_buf = s.lit_bufsize; - s.sym_end = (s.lit_bufsize - 1) * 3; - s.level = level; - s.strategy = strategy; - s.method = method; - return deflateReset(strm); -}; -var deflate$1 = (strm, flush) => { - if (deflateStateCheck(strm) || flush > 5 || flush < 0) return strm ? err(strm, -2) : -2; - const s = strm.state; - if (!strm.output || strm.avail_in !== 0 && !strm.input || s.status === FINISH_STATE && flush !== 4) return err(strm, strm.avail_out === 0 ? -5 : -2); - const old_flush = s.last_flush; - s.last_flush = flush; - if (s.pending !== 0) { - flush_pending(strm); - if (strm.avail_out === 0) { - s.last_flush = -1; - return 0; - } - } else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) && flush !== 4) return err(strm, -5); - if (s.status === FINISH_STATE && strm.avail_in !== 0) return err(strm, -5); - if (s.status === INIT_STATE && s.wrap === 0) s.status = BUSY_STATE; - if (s.status === INIT_STATE) { - let header = 8 + (s.w_bits - 8 << 4) << 8; - let level_flags = -1; - if (s.strategy >= 2 || s.level < 2) level_flags = 0; - else if (s.level < 6) level_flags = 1; - else if (s.level === 6) level_flags = 2; - else level_flags = 3; - header |= level_flags << 6; - if (s.strstart !== 0) header |= PRESET_DICT; - header += 31 - header % 31; - putShortMSB(s, header); - if (s.strstart !== 0) { - putShortMSB(s, strm.adler >>> 16); - putShortMSB(s, strm.adler & 65535); - } - strm.adler = 1; - s.status = BUSY_STATE; - flush_pending(strm); - if (s.pending !== 0) { - s.last_flush = -1; - return 0; - } +/** +* SHA2-256 hash function from RFC 4634. In JS it's the fastest: even faster than Blake3. Some info: +* +* - Trying 2^128 hashes would get 50% chance of collision, using birthday attack. +* - BTC network is doing 2^70 hashes/sec (2^95 hashes/year) as per 2025. +* - Each sha256 hash is executing 2^18 bit operations. +* - Good 2024 ASICs can do 200Th/sec with 3500 watts of power, corresponding to 2^36 hashes/joule. +* @param msg - message bytes to hash +* @param opts - Reserved hash options. +* @returns Digest bytes. +* @example +* Hash a message with SHA2-256. +* ```ts +* sha256(new Uint8Array([97, 98, 99])); +* ``` +*/ +const sha256$1 = /* @__PURE__ */ createHasher(() => new _SHA256(), /* @__PURE__ */ oidNist(1)); +/** +* SHA2-512 hash function from RFC 4634. +* @param msg - message bytes to hash +* @param opts - Reserved hash options. +* @returns Digest bytes. +* @example +* Hash a message with SHA2-512. +* ```ts +* sha512(new Uint8Array([97, 98, 99])); +* ``` +*/ +const sha512 = /* @__PURE__ */ createHasher(() => new _SHA512(), /* @__PURE__ */ oidNist(3)); +/** +* SHA2-384 hash function from RFC 4634. +* @param msg - message bytes to hash +* @param opts - Reserved hash options. +* @returns Digest bytes. +* @example +* Hash a message with SHA2-384. +* ```ts +* sha384(new Uint8Array([97, 98, 99])); +* ``` +*/ +const sha384 = /* @__PURE__ */ createHasher(() => new _SHA384(), /* @__PURE__ */ oidNist(2)); +//#endregion +//#region ../../node_modules/@noble/hashes/hmac.js +/** +* HMAC: RFC2104 message authentication code. +* @module +*/ +/** +* Internal class for HMAC. +* Accepts any byte key, although RFC 2104 §3 recommends keys at least +* `HashLen` bytes long. +*/ +var _HMAC = class { + oHash; + iHash; + blockLen; + outputLen; + canXOF = false; + finished = false; + destroyed = false; + constructor(hash, key) { + ahash(hash); + abytes$2(key, void 0, "key"); + this.iHash = hash.create(); + if (typeof this.iHash.update !== "function") throw new Error("expected Hash instance"); + this.blockLen = this.iHash.blockLen; + this.outputLen = this.iHash.outputLen; + const blockLen = this.blockLen; + const pad = new Uint8Array(blockLen); + pad.set(key.length > blockLen ? hash.create().update(key).digest() : key); + for (let i = 0; i < pad.length; i++) pad[i] ^= 54; + this.iHash.update(pad); + this.oHash = hash.create(); + for (let i = 0; i < pad.length; i++) pad[i] ^= 106; + this.oHash.update(pad); + clean$1(pad); } - if (s.status === GZIP_STATE) { - strm.adler = 0; - put_byte(s, 31); - put_byte(s, 139); - put_byte(s, 8); - if (!s.gzhead) { - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, s.level === 9 ? 2 : s.strategy >= 2 || s.level < 2 ? 4 : 0); - put_byte(s, OS_CODE); - s.status = BUSY_STATE; - flush_pending(strm); - if (s.pending !== 0) { - s.last_flush = -1; - return 0; - } - } else { - put_byte(s, (s.gzhead.text ? 1 : 0) + (s.gzhead.hcrc ? 2 : 0) + (!s.gzhead.extra ? 0 : 4) + (!s.gzhead.name ? 0 : 8) + (!s.gzhead.comment ? 0 : 16)); - put_byte(s, s.gzhead.time & 255); - put_byte(s, s.gzhead.time >> 8 & 255); - put_byte(s, s.gzhead.time >> 16 & 255); - put_byte(s, s.gzhead.time >> 24 & 255); - put_byte(s, s.level === 9 ? 2 : s.strategy >= 2 || s.level < 2 ? 4 : 0); - put_byte(s, s.gzhead.os & 255); - if (s.gzhead.extra && s.gzhead.extra.length) { - put_byte(s, s.gzhead.extra.length & 255); - put_byte(s, s.gzhead.extra.length >> 8 & 255); - } - if (s.gzhead.hcrc) strm.adler = crc32$2(strm.adler, s.pending_buf, s.pending, 0); - s.gzindex = 0; - s.status = EXTRA_STATE; - } + update(buf) { + aexists$1(this); + this.iHash.update(buf); + return this; } - if (s.status === EXTRA_STATE) { - if (s.gzhead.extra) { - let beg = s.pending; - let left = (s.gzhead.extra.length & 65535) - s.gzindex; - while (s.pending + left > s.pending_buf_size) { - let copy = s.pending_buf_size - s.pending; - s.pending_buf.set(s.gzhead.extra.subarray(s.gzindex, s.gzindex + copy), s.pending); - s.pending = s.pending_buf_size; - if (s.gzhead.hcrc && s.pending > beg) strm.adler = crc32$2(strm.adler, s.pending_buf, s.pending - beg, beg); - s.gzindex += copy; - flush_pending(strm); - if (s.pending !== 0) { - s.last_flush = -1; - return 0; - } - beg = 0; - left -= copy; - } - let gzhead_extra = new Uint8Array(s.gzhead.extra); - s.pending_buf.set(gzhead_extra.subarray(s.gzindex, s.gzindex + left), s.pending); - s.pending += left; - if (s.gzhead.hcrc && s.pending > beg) strm.adler = crc32$2(strm.adler, s.pending_buf, s.pending - beg, beg); - s.gzindex = 0; - } - s.status = NAME_STATE; - } - if (s.status === NAME_STATE) { - if (s.gzhead.name) { - let beg = s.pending; - let val; - do { - if (s.pending === s.pending_buf_size) { - if (s.gzhead.hcrc && s.pending > beg) strm.adler = crc32$2(strm.adler, s.pending_buf, s.pending - beg, beg); - flush_pending(strm); - if (s.pending !== 0) { - s.last_flush = -1; - return 0; - } - beg = 0; - } - if (s.gzindex < s.gzhead.name.length) val = s.gzhead.name.charCodeAt(s.gzindex++) & 255; - else val = 0; - put_byte(s, val); - } while (val !== 0); - if (s.gzhead.hcrc && s.pending > beg) strm.adler = crc32$2(strm.adler, s.pending_buf, s.pending - beg, beg); - s.gzindex = 0; - } - s.status = COMMENT_STATE; - } - if (s.status === COMMENT_STATE) { - if (s.gzhead.comment) { - let beg = s.pending; - let val; - do { - if (s.pending === s.pending_buf_size) { - if (s.gzhead.hcrc && s.pending > beg) strm.adler = crc32$2(strm.adler, s.pending_buf, s.pending - beg, beg); - flush_pending(strm); - if (s.pending !== 0) { - s.last_flush = -1; - return 0; - } - beg = 0; - } - if (s.gzindex < s.gzhead.comment.length) val = s.gzhead.comment.charCodeAt(s.gzindex++) & 255; - else val = 0; - put_byte(s, val); - } while (val !== 0); - if (s.gzhead.hcrc && s.pending > beg) strm.adler = crc32$2(strm.adler, s.pending_buf, s.pending - beg, beg); - } - s.status = HCRC_STATE; - } - if (s.status === HCRC_STATE) { - if (s.gzhead.hcrc) { - if (s.pending + 2 > s.pending_buf_size) { - flush_pending(strm); - if (s.pending !== 0) { - s.last_flush = -1; - return 0; - } - } - put_byte(s, strm.adler & 255); - put_byte(s, strm.adler >> 8 & 255); - strm.adler = 0; - } - s.status = BUSY_STATE; - flush_pending(strm); - if (s.pending !== 0) { - s.last_flush = -1; - return 0; - } + digestInto(out) { + aexists$1(this); + aoutput$1(out, this); + this.finished = true; + const buf = out.subarray(0, this.outputLen); + this.iHash.digestInto(buf); + this.oHash.update(buf); + this.oHash.digestInto(buf); + this.destroy(); } - if (strm.avail_in !== 0 || s.lookahead !== 0 || flush !== 0 && s.status !== FINISH_STATE) { - let bstate = s.level === 0 ? deflate_stored(s, flush) : s.strategy === 2 ? deflate_huff(s, flush) : s.strategy === 3 ? deflate_rle(s, flush) : configuration_table[s.level].func(s, flush); - if (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) s.status = FINISH_STATE; - if (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) { - if (strm.avail_out === 0) s.last_flush = -1; - return 0; - } - if (bstate === BS_BLOCK_DONE) { - if (flush === 1) _tr_align(s); - else if (flush !== 5) { - _tr_stored_block(s, 0, 0, false); - if (flush === 3) { - /*** CLEAR_HASH(s); ***/ zero(s.head); - if (s.lookahead === 0) { - s.strstart = 0; - s.block_start = 0; - s.insert = 0; - } - } - } - flush_pending(strm); - if (strm.avail_out === 0) { - s.last_flush = -1; - return 0; - } - } + digest() { + const out = new Uint8Array(this.oHash.outputLen); + this.digestInto(out); + return out; } - if (flush !== 4) return 0; - if (s.wrap <= 0) return 1; - if (s.wrap === 2) { - put_byte(s, strm.adler & 255); - put_byte(s, strm.adler >> 8 & 255); - put_byte(s, strm.adler >> 16 & 255); - put_byte(s, strm.adler >> 24 & 255); - put_byte(s, strm.total_in & 255); - put_byte(s, strm.total_in >> 8 & 255); - put_byte(s, strm.total_in >> 16 & 255); - put_byte(s, strm.total_in >> 24 & 255); - } else { - putShortMSB(s, strm.adler >>> 16); - putShortMSB(s, strm.adler & 65535); + _cloneInto(to) { + to ||= Object.create(Object.getPrototypeOf(this), {}); + const { oHash, iHash, finished, destroyed, blockLen, outputLen, canXOF } = this; + to = to; + to.finished = finished; + to.destroyed = destroyed; + to.blockLen = blockLen; + to.outputLen = outputLen; + to.canXOF = canXOF; + to.oHash = oHash._cloneInto(to.oHash); + to.iHash = iHash._cloneInto(to.iHash); + return to; + } + clone() { + return this._cloneInto(); + } + destroy() { + this.destroyed = true; + this.oHash.destroy(); + this.iHash.destroy(); } - flush_pending(strm); - if (s.wrap > 0) s.wrap = -s.wrap; - return s.pending !== 0 ? 0 : 1; -}; -var deflateEnd = (strm) => { - if (deflateStateCheck(strm)) return -2; - const status = strm.state.status; - strm.state = null; - return status === BUSY_STATE ? err(strm, -3) : 0; -}; -var deflateSetDictionary = (strm, dictionary) => { - let dictLength = dictionary.length; - if (deflateStateCheck(strm)) return -2; - const s = strm.state; - const wrap = s.wrap; - if (wrap === 2 || wrap === 1 && s.status !== INIT_STATE || s.lookahead) return -2; - if (wrap === 1) strm.adler = adler32(strm.adler, dictionary, dictLength, 0); - s.wrap = 0; - if (dictLength >= s.w_size) { - if (wrap === 0) { - /*** CLEAR_HASH(s); ***/ - zero(s.head); - s.strstart = 0; - s.block_start = 0; - s.insert = 0; - } - let tmpDict = new Uint8Array(s.w_size); - tmpDict.set(dictionary.subarray(dictLength - s.w_size, dictLength), 0); - dictionary = tmpDict; - dictLength = s.w_size; - } - const avail = strm.avail_in; - const next = strm.next_in; - const input = strm.input; - strm.avail_in = dictLength; - strm.next_in = 0; - strm.input = dictionary; - fill_window(s); - while (s.lookahead >= MIN_MATCH) { - let str = s.strstart; - let n = s.lookahead - (MIN_MATCH - 1); - do { - INSERT_STRING(s, str); - str++; - } while (--n); - s.strstart = str; - s.lookahead = MIN_MATCH - 1; - fill_window(s); - } - s.strstart += s.lookahead; - s.block_start = s.strstart; - s.insert = s.lookahead; - s.lookahead = 0; - s.match_length = s.prev_length = MIN_MATCH - 1; - s.match_available = 0; - strm.next_in = next; - strm.input = input; - strm.avail_in = avail; - s.wrap = wrap; - return 0; }; -var BAD$1 = 16209; -var TYPE$1 = 16191; -function inflate_fast(strm, start) { - let _in; - let last; - let _out; - let beg; - let end; - let dmax; - let wsize; - let whave; - let wnext; - let s_window; - let hold; - let bits; - let lcode; - let dcode; - let lmask; - let dmask; - let here; - let op; - let len; - let dist; - let from; - let from_source; - let input, output; - const state = strm.state; - _in = strm.next_in; - input = strm.input; - last = _in + (strm.avail_in - 5); - _out = strm.next_out; - output = strm.output; - beg = _out - (start - strm.avail_out); - end = _out + (strm.avail_out - 257); - dmax = state.dmax; - wsize = state.wsize; - whave = state.whave; - wnext = state.wnext; - s_window = state.window; - hold = state.hold; - bits = state.bits; - lcode = state.lencode; - dcode = state.distcode; - lmask = (1 << state.lenbits) - 1; - dmask = (1 << state.distbits) - 1; - top: do { - if (bits < 15) { - hold += input[_in++] << bits; - bits += 8; - hold += input[_in++] << bits; - bits += 8; +const hmac = /* @__PURE__ */ (() => { + const hmac_ = ((hash, key, message) => new _HMAC(hash, key).update(message).digest()); + hmac_.create = (hash, key) => new _HMAC(hash, key); + return hmac_; +})(); +//#endregion +//#region ../../node_modules/@noble/hashes/pbkdf2.js +/** +* PBKDF (RFC 2898). Can be used to create a key from password and salt. +* @module +*/ +function pbkdf2Init(hash, _password, _salt, _opts) { + ahash(hash); + const { c, dkLen, asyncTick } = checkOpts$1({ + dkLen: 32, + asyncTick: 10 + }, _opts); + anumber$2(c, "c"); + anumber$2(dkLen, "dkLen"); + anumber$2(asyncTick, "asyncTick"); + if (c < 1) throw new Error("\"c\" (iterations) must be >= 1"); + if (dkLen < 1) throw new Error("\"dkLen\" must be >= 1"); + if (dkLen > (2 ** 32 - 1) * hash.outputLen) throw new Error("derived key too long"); + const p = kdfInputToBytes(_password, "password"); + try { + const s = kdfInputToBytes(_salt, "salt"); + try { + const DK = new Uint8Array(dkLen); + const { iHash, oHash, outputLen } = hmac.create(hash, p); + return { + c, + dkLen, + asyncTick, + DK, + outputLen, + eng: pbkdf2Engine(iHash, oHash, s, new Uint8Array(outputLen)) + }; + } finally { + if (typeof _salt === "string") clean$1(s); } - here = lcode[hold & lmask]; - dolen: for (;;) { - op = here >>> 24; - hold >>>= op; - bits -= op; - op = here >>> 16 & 255; - if (op === 0) output[_out++] = here & 65535; - else if (op & 16) { - len = here & 65535; - op &= 15; - if (op) { - if (bits < op) { - hold += input[_in++] << bits; - bits += 8; - } - len += hold & (1 << op) - 1; - hold >>>= op; - bits -= op; - } - if (bits < 15) { - hold += input[_in++] << bits; - bits += 8; - hold += input[_in++] << bits; - bits += 8; - } - here = dcode[hold & dmask]; - dodist: for (;;) { - op = here >>> 24; - hold >>>= op; - bits -= op; - op = here >>> 16 & 255; - if (op & 16) { - dist = here & 65535; - op &= 15; - if (bits < op) { - hold += input[_in++] << bits; - bits += 8; - if (bits < op) { - hold += input[_in++] << bits; - bits += 8; - } - } - dist += hold & (1 << op) - 1; - if (dist > dmax) { - strm.msg = "invalid distance too far back"; - state.mode = BAD$1; - break top; - } - hold >>>= op; - bits -= op; - op = _out - beg; - if (dist > op) { - op = dist - op; - if (op > whave) { - if (state.sane) { - strm.msg = "invalid distance too far back"; - state.mode = BAD$1; - break top; - } - } - from = 0; - from_source = s_window; - if (wnext === 0) { - from += wsize - op; - if (op < len) { - len -= op; - do - output[_out++] = s_window[from++]; - while (--op); - from = _out - dist; - from_source = output; - } - } else if (wnext < op) { - from += wsize + wnext - op; - op -= wnext; - if (op < len) { - len -= op; - do - output[_out++] = s_window[from++]; - while (--op); - from = 0; - if (wnext < len) { - op = wnext; - len -= op; - do - output[_out++] = s_window[from++]; - while (--op); - from = _out - dist; - from_source = output; - } - } - } else { - from += wnext - op; - if (op < len) { - len -= op; - do - output[_out++] = s_window[from++]; - while (--op); - from = _out - dist; - from_source = output; - } - } - while (len > 2) { - output[_out++] = from_source[from++]; - output[_out++] = from_source[from++]; - output[_out++] = from_source[from++]; - len -= 3; - } - if (len) { - output[_out++] = from_source[from++]; - if (len > 1) output[_out++] = from_source[from++]; - } - } else { - from = _out - dist; - do { - output[_out++] = output[from++]; - output[_out++] = output[from++]; - output[_out++] = output[from++]; - len -= 3; - } while (len > 2); - if (len) { - output[_out++] = output[from++]; - if (len > 1) output[_out++] = output[from++]; - } - } - } else if ((op & 64) === 0) { - here = dcode[(here & 65535) + (hold & (1 << op) - 1)]; - continue dodist; - } else { - strm.msg = "invalid distance code"; - state.mode = BAD$1; - break top; - } - break; - } - } else if ((op & 64) === 0) { - here = lcode[(here & 65535) + (hold & (1 << op) - 1)]; - continue dolen; - } else if (op & 32) { - state.mode = TYPE$1; - break top; - } else { - strm.msg = "invalid literal/length code"; - state.mode = BAD$1; - break top; + } finally { + if (typeof _password === "string") clean$1(p); + } +} +function pbkdf2Engine(iHash, oHash, salt, u) { + const counter = /* @__PURE__ */ new Uint8Array(4); + const view = createView$1(counter); + const salted = iHash._cloneInto().update(salt); + const work = oHash._cloneInto(); + const iClone = iHash._cloneInto; + const oClone = oHash._cloneInto; + return { + u1: (ti, Ti) => { + view.setInt32(0, ti, false); + salted._cloneInto(work).update(counter).digestInto(u); + oHash._cloneInto(work).update(u).digestInto(u); + Ti.set(u.subarray(0, Ti.length)); + }, + rounds: (c, Ti) => { + for (let ui = 1; ui < c; ui++) { + iClone.call(iHash, work).update(u).digestInto(u); + oClone.call(oHash, work).update(u).digestInto(u); + for (let i = 0; i < Ti.length; i++) Ti[i] ^= u[i]; } - break; - } - } while (_in < last && _out < end); - len = bits >> 3; - _in -= len; - bits -= len << 3; - hold &= (1 << bits) - 1; - strm.next_in = _in; - strm.next_out = _out; - strm.avail_in = _in < last ? 5 + (last - _in) : 5 - (_in - last); - strm.avail_out = _out < end ? 257 + (end - _out) : 257 - (_out - end); - state.hold = hold; - state.bits = bits; -} -var MAXBITS = 15; -var ENOUGH_LENS$1 = 852; -var ENOUGH_DISTS$1 = 592; -var CODES$1 = 0; -var LENS$1 = 1; -var DISTS$1 = 2; -var lbase = new Uint16Array([ - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 13, - 15, - 17, - 19, - 23, - 27, - 31, - 35, - 43, - 51, - 59, - 67, - 83, - 99, - 115, - 131, - 163, - 195, - 227, - 258, - 0, - 0 -]); -var lext = new Uint8Array([ - 16, - 16, - 16, - 16, - 16, - 16, - 16, - 16, - 17, - 17, - 17, - 17, - 18, - 18, - 18, - 18, - 19, - 19, - 19, - 19, - 20, - 20, - 20, - 20, - 21, - 21, - 21, - 21, - 16, - 199, - 75 -]); -var dbase = new Uint16Array([ - 1, - 2, - 3, - 4, - 5, - 7, - 9, - 13, - 17, - 25, - 33, - 49, - 65, - 97, - 129, - 193, - 257, - 385, - 513, - 769, - 1025, - 1537, - 2049, - 3073, - 4097, - 6145, - 8193, - 12289, - 16385, - 24577, - 0, - 0 -]); -var dext = new Uint8Array([ - 16, - 16, - 16, - 16, - 17, - 17, - 18, - 18, - 19, - 19, - 20, - 20, - 21, - 21, - 22, - 22, - 23, - 23, - 24, - 24, - 25, - 25, - 26, - 26, - 27, - 27, - 28, - 28, - 29, - 29, - 64, - 64 -]); -var inflate_table = (type, lens, lens_index, codes, table, table_index, work, opts) => { - const bits = opts.bits; - let len = 0; - let sym = 0; - let min = 0, max = 0; - let root = 0; - let curr = 0; - let drop = 0; - let left = 0; - let used = 0; - let huff = 0; - let incr; - let fill; - let low; - let mask; - let next; - let base = null; - let match; - const count = /* @__PURE__ */ new Uint16Array(16); - const offs = /* @__PURE__ */ new Uint16Array(16); - let extra = null; - let here_bits, here_op, here_val; - for (len = 0; len <= MAXBITS; len++) count[len] = 0; - for (sym = 0; sym < codes; sym++) count[lens[lens_index + sym]]++; - root = bits; - for (max = MAXBITS; max >= 1; max--) if (count[max] !== 0) break; - if (root > max) root = max; - if (max === 0) { - table[table_index++] = 20971520; - table[table_index++] = 20971520; - opts.bits = 1; - return 0; - } - for (min = 1; min < max; min++) if (count[min] !== 0) break; - if (root < min) root = min; - left = 1; - for (len = 1; len <= MAXBITS; len++) { - left <<= 1; - left -= count[len]; - if (left < 0) return -1; - } - if (left > 0 && (type === CODES$1 || max !== 1)) return -1; - offs[1] = 0; - for (len = 1; len < MAXBITS; len++) offs[len + 1] = offs[len] + count[len]; - for (sym = 0; sym < codes; sym++) if (lens[lens_index + sym] !== 0) work[offs[lens[lens_index + sym]]++] = sym; - if (type === CODES$1) { - base = extra = work; - match = 20; - } else if (type === LENS$1) { - base = lbase; - extra = lext; - match = 257; - } else { - base = dbase; - extra = dext; - match = 0; - } - huff = 0; - sym = 0; - len = min; - next = table_index; - curr = root; - drop = 0; - low = -1; - used = 1 << root; - mask = used - 1; - if (type === LENS$1 && used > ENOUGH_LENS$1 || type === DISTS$1 && used > ENOUGH_DISTS$1) return 1; - for (;;) { - here_bits = len - drop; - if (work[sym] + 1 < match) { - here_op = 0; - here_val = work[sym]; - } else if (work[sym] >= match) { - here_op = extra[work[sym] - match]; - here_val = base[work[sym] - match]; - } else { - here_op = 96; - here_val = 0; - } - incr = 1 << len - drop; - fill = 1 << curr; - min = fill; - do { - fill -= incr; - table[next + (huff >> drop) + fill] = here_bits << 24 | here_op << 16 | here_val | 0; - } while (fill !== 0); - incr = 1 << len - 1; - while (huff & incr) incr >>= 1; - if (incr !== 0) { - huff &= incr - 1; - huff += incr; - } else huff = 0; - sym++; - if (--count[len] === 0) { - if (len === max) break; - len = lens[lens_index + work[sym]]; - } - if (len > root && (huff & mask) !== low) { - if (drop === 0) drop = root; - next += min; - curr = len - drop; - left = 1 << curr; - while (curr + drop < max) { - left -= count[curr + drop]; - if (left <= 0) break; - curr++; - left <<= 1; - } - used += 1 << curr; - if (type === LENS$1 && used > ENOUGH_LENS$1 || type === DISTS$1 && used > ENOUGH_DISTS$1) return 1; - low = huff & mask; - table[low] = root << 24 | curr << 16 | next - table_index | 0; + }, + output: (DK) => { + iHash.destroy(); + oHash.destroy(); + salted.destroy(); + work.destroy(); + clean$1(u); + return DK; } + }; +} +/** +* PBKDF2-HMAC: RFC 8018 key derivation function. +* @param hash - hash function that would be used e.g. sha256 +* @param password - password from which a derived key is generated; +* JS string inputs are UTF-8 encoded first +* @param salt - cryptographic salt; JS string inputs are UTF-8 encoded first +* @param opts - PBKDF2 work factor and output settings. `dkLen`, if provided, +* must be `>= 1` per RFC 8018 §5.2. See {@link Pbkdf2Opt}. +* @returns Derived key bytes. +* @throws If the PBKDF2 iteration count or derived-key settings are invalid. {@link Error} +* @example +* PBKDF2-HMAC: RFC 2898 key derivation function. +* ```ts +* import { pbkdf2 } from '@noble/hashes/pbkdf2.js'; +* import { sha256 } from '@noble/hashes/sha2.js'; +* const key = pbkdf2(sha256, 'password', 'salt', { dkLen: 32, c: Math.pow(2, 18) }); +* ``` +*/ +function pbkdf2(hash, password, salt, opts) { + const { c, dkLen, DK, outputLen, eng } = pbkdf2Init(hash, password, salt, opts); + for (let ti = 1, pos = 0; pos < dkLen; ti++, pos += outputLen) { + const Ti = DK.subarray(pos, pos + outputLen); + eng.u1(ti, Ti); + eng.rounds(c, Ti); } - if (huff !== 0) table[next + huff] = len - drop << 24 | 4194304; - opts.bits = root; - return 0; -}; -var CODES = 0; -var LENS = 1; -var DISTS = 2; -var HEAD = 16180; -var FLAGS = 16181; -var TIME = 16182; -var OS = 16183; -var EXLEN = 16184; -var EXTRA = 16185; -var NAME$1 = 16186; -var COMMENT = 16187; -var HCRC = 16188; -var DICTID = 16189; -var DICT = 16190; -var TYPE = 16191; -var TYPEDO = 16192; -var STORED = 16193; -var COPY_ = 16194; -var COPY = 16195; -var TABLE = 16196; -var LENLENS = 16197; -var CODELENS = 16198; -var LEN_ = 16199; -var LEN = 16200; -var LENEXT = 16201; -var DIST = 16202; -var DISTEXT = 16203; -var MATCH = 16204; -var LIT = 16205; -var CHECK = 16206; -var LENGTH = 16207; -var DONE = 16208; -var BAD = 16209; -var MEM = 16210; -var SYNC = 16211; -var ENOUGH_LENS = 852; -var ENOUGH_DISTS = 592; -var zswap32 = (q) => { - return (q >>> 24 & 255) + (q >>> 8 & 65280) + ((q & 65280) << 8) + ((q & 255) << 24); -}; -var InflateState = class { - constructor() { - this.strm = null; - this.mode = 0; - this.last = false; - this.wrap = 0; - this.havedict = false; - this.flags = 0; - this.dmax = 0; - this.check = 0; - this.total = 0; - this.head = null; - this.wbits = 0; - this.wsize = 0; - this.whave = 0; - this.wnext = 0; - this.window = null; - this.hold = 0; - this.bits = 0; - this.length = 0; - this.offset = 0; - this.extra = 0; - this.lencode = null; - this.distcode = null; - this.lenbits = 0; - this.distbits = 0; - this.ncode = 0; - this.nlen = 0; - this.ndist = 0; - this.have = 0; - this.next = null; - this.lens = /* @__PURE__ */ new Uint16Array(320); - this.work = /* @__PURE__ */ new Uint16Array(288); - this.lendyn = null; - this.distdyn = null; - this.sane = 0; - this.back = 0; - this.was = 0; + return eng.output(DK); +} +//#endregion +//#region ../../node_modules/@noble/hashes/hkdf.js +/** +* HKDF (RFC 5869): extract + expand in one step. +* See {@link https://soatok.blog/2021/11/17/understanding-hkdf/}. +* @module +*/ +const HKDF_COUNTER = /* @__PURE__ */ Uint8Array.of(0); +const EMPTY_BUFFER = /* @__PURE__ */ Uint8Array.of(); +/** +* HKDF-expand from the spec. The most important part. `HKDF-Expand(PRK, info, L) -> OKM` +* @param hash - hash function that would be used (e.g. sha256) +* @param prk - a pseudorandom key of at least HashLen octets +* (usually, the output from the extract step) +* @param info - optional context and application specific information (can be a zero-length string) +* @param length - length of output keying material in bytes. +* RFC 5869 §2.3 allows `0..255*HashLen`, so `0` returns an empty OKM. +* @param _recycled - Internal destroyed extract hashes owned by the combined `hkdf()` call. +* @returns Output keying material with the requested length. +* @throws If the requested output length exceeds the HKDF limit +* for the selected hash. {@link Error} +* @example +* Run the HKDF expand step. +* ```ts +* import { expand } from '@noble/hashes/hkdf.js'; +* import { sha256 } from '@noble/hashes/sha2.js'; +* expand(sha256, new Uint8Array(32), new Uint8Array([1, 2, 3]), 16); +* ``` +*/ +function expand(hash, prk, info, length = 32, _recycled) { + ahash(hash); + anumber$2(length, "length"); + abytes$2(prk, void 0, "prk"); + const olen = hash.outputLen; + if (prk.length < olen) throw new Error("\"prk\" must be at least HashLen octets"); + if (length > 255 * olen) throw new Error("Length must be <= 255*HashLen"); + const blocks = Math.ceil(length / olen); + if (info === void 0) info = EMPTY_BUFFER; + else abytes$2(info, void 0, "info"); + if (!blocks) { + if (_recycled) clean$1(prk); + return /* @__PURE__ */ new Uint8Array(); } -}; -var inflateStateCheck = (strm) => { - if (!strm) return 1; - const state = strm.state; - if (!state || state.strm !== strm || state.mode < HEAD || state.mode > SYNC) return 1; - return 0; -}; -var inflateResetKeep = (strm) => { - if (inflateStateCheck(strm)) return -2; - const state = strm.state; - strm.total_in = strm.total_out = state.total = 0; - strm.msg = ""; - if (state.wrap) strm.adler = state.wrap & 1; - state.mode = HEAD; - state.last = 0; - state.havedict = 0; - state.flags = -1; - state.dmax = 32768; - state.head = null; - state.hold = 0; - state.bits = 0; - state.lencode = state.lendyn = new Int32Array(ENOUGH_LENS); - state.distcode = state.distdyn = new Int32Array(ENOUGH_DISTS); - state.sane = 1; - state.back = -1; - return 0; -}; -var inflateReset = (strm) => { - if (inflateStateCheck(strm)) return -2; - const state = strm.state; - state.wsize = 0; - state.whave = 0; - state.wnext = 0; - return inflateResetKeep(strm); -}; -var inflateReset2 = (strm, windowBits) => { - let wrap; - if (inflateStateCheck(strm)) return -2; - const state = strm.state; - if (windowBits < 0) { - wrap = 0; - windowBits = -windowBits; - } else { - wrap = (windowBits >> 4) + 5; - if (windowBits < 48) windowBits &= 15; - } - if (windowBits && (windowBits < 8 || windowBits > 15)) return -2; - if (state.window !== null && state.wbits !== windowBits) state.window = null; - state.wrap = wrap; - state.wbits = windowBits; - return inflateReset(strm); -}; -var inflateInit2 = (strm, windowBits) => { - if (!strm) return -2; - const state = new InflateState(); - strm.state = state; - state.strm = strm; - state.window = null; - state.mode = HEAD; - const ret = inflateReset2(strm, windowBits); - if (ret !== 0) strm.state = null; - return ret; -}; -var virgin = true; -var lenfix; -var distfix; -var fixedtables = (state) => { - if (virgin) { - lenfix = /* @__PURE__ */ new Int32Array(512); - distfix = /* @__PURE__ */ new Int32Array(32); - let sym = 0; - while (sym < 144) state.lens[sym++] = 8; - while (sym < 256) state.lens[sym++] = 9; - while (sym < 280) state.lens[sym++] = 7; - while (sym < 288) state.lens[sym++] = 8; - inflate_table(LENS, state.lens, 0, 288, lenfix, 0, state.work, { bits: 9 }); - sym = 0; - while (sym < 32) state.lens[sym++] = 5; - inflate_table(DISTS, state.lens, 0, 32, distfix, 0, state.work, { bits: 5 }); - virgin = false; - } - state.lencode = lenfix; - state.lenbits = 9; - state.distcode = distfix; - state.distbits = 5; -}; -var updatewindow = (strm, src, end, copy) => { - let dist; - const state = strm.state; - if (state.window === null) state.window = new Uint8Array(1 << state.wbits); - if (state.wsize === 0) { - state.wsize = 1 << state.wbits; - state.wnext = 0; - state.whave = 0; - } - if (copy >= state.wsize) { - state.window.set(src.subarray(end - state.wsize, end), 0); - state.wnext = 0; - state.whave = state.wsize; - } else { - dist = state.wsize - state.wnext; - if (dist > copy) dist = copy; - state.window.set(src.subarray(end - copy, end - copy + dist), state.wnext); - copy -= dist; - if (copy) { - state.window.set(src.subarray(end - copy, end), 0); - state.wnext = copy; - state.whave = state.wsize; - } else { - state.wnext += dist; - if (state.wnext === state.wsize) state.wnext = 0; - if (state.whave < state.wsize) state.whave += dist; - } + const okm = _recycled && blocks === 1 ? prk : new Uint8Array(blocks * olen); + const { iHash, oHash } = hmac.create(hash, prk); + const T = _recycled ? prk : new Uint8Array(olen); + const worker = blocks > 1 ? _recycled?.iHash || hash.create() : void 0; + for (let counter = 0; counter < blocks - 1; counter++) { + HKDF_COUNTER[0] = counter + 1; + const iWork = iHash._cloneInto(worker); + if (counter) iWork.update(T); + iWork.update(info).update(HKDF_COUNTER).digestInto(T); + oHash._cloneInto(worker).update(T).digestInto(T); + okm.set(T, olen * counter); } - return 0; -}; -var inflate$1 = (strm, flush) => { - let state; - let input, output; - let next; - let put; - let have, left; - let hold; - let bits; - let _in, _out; - let copy; - let from; - let from_source; - let here = 0; - let here_bits, here_op, here_val; - let last_bits, last_op, last_val; - let len; - let ret; - const hbuf = /* @__PURE__ */ new Uint8Array(4); - let opts; - let n; - const order = new Uint8Array([ - 16, - 17, - 18, - 0, - 8, - 7, - 9, - 6, - 10, - 5, - 11, - 4, - 12, - 3, - 13, - 2, - 14, - 1, - 15 - ]); - if (inflateStateCheck(strm) || !strm.output || !strm.input && strm.avail_in !== 0) return -2; - state = strm.state; - if (state.mode === TYPE) state.mode = TYPEDO; - put = strm.next_out; - output = strm.output; - left = strm.avail_out; - next = strm.next_in; - input = strm.input; - have = strm.avail_in; - hold = state.hold; - bits = state.bits; - _in = have; - _out = left; - ret = 0; - inf_leave: for (;;) switch (state.mode) { - case HEAD: - if (state.wrap === 0) { - state.mode = TYPEDO; - break; - } - while (bits < 16) { - if (have === 0) break inf_leave; - have--; - hold += input[next++] << bits; - bits += 8; - } - if (state.wrap & 2 && hold === 35615) { - if (state.wbits === 0) state.wbits = 15; - state.check = 0; - hbuf[0] = hold & 255; - hbuf[1] = hold >>> 8 & 255; - state.check = crc32$2(state.check, hbuf, 2, 0); - hold = 0; - bits = 0; - state.mode = FLAGS; - break; - } - if (state.head) state.head.done = false; - if (!(state.wrap & 1) || (((hold & 255) << 8) + (hold >> 8)) % 31) { - strm.msg = "incorrect header check"; - state.mode = BAD; - break; - } - if ((hold & 15) !== 8) { - strm.msg = "unknown compression method"; - state.mode = BAD; - break; - } - hold >>>= 4; - bits -= 4; - len = (hold & 15) + 8; - if (state.wbits === 0) state.wbits = len; - if (len > 15 || len > state.wbits) { - strm.msg = "invalid window size"; - state.mode = BAD; - break; - } - state.dmax = 1 << state.wbits; - state.flags = 0; - strm.adler = state.check = 1; - state.mode = hold & 512 ? DICTID : TYPE; - hold = 0; - bits = 0; - break; - case FLAGS: - while (bits < 16) { - if (have === 0) break inf_leave; - have--; - hold += input[next++] << bits; - bits += 8; - } - state.flags = hold; - if ((state.flags & 255) !== 8) { - strm.msg = "unknown compression method"; - state.mode = BAD; - break; - } - if (state.flags & 57344) { - strm.msg = "unknown header flags set"; - state.mode = BAD; - break; - } - if (state.head) state.head.text = hold >> 8 & 1; - if (state.flags & 512 && state.wrap & 4) { - hbuf[0] = hold & 255; - hbuf[1] = hold >>> 8 & 255; - state.check = crc32$2(state.check, hbuf, 2, 0); - } - hold = 0; - bits = 0; - state.mode = TIME; - case TIME: - while (bits < 32) { - if (have === 0) break inf_leave; - have--; - hold += input[next++] << bits; - bits += 8; - } - if (state.head) state.head.time = hold; - if (state.flags & 512 && state.wrap & 4) { - hbuf[0] = hold & 255; - hbuf[1] = hold >>> 8 & 255; - hbuf[2] = hold >>> 16 & 255; - hbuf[3] = hold >>> 24 & 255; - state.check = crc32$2(state.check, hbuf, 4, 0); - } - hold = 0; - bits = 0; - state.mode = OS; - case OS: - while (bits < 16) { - if (have === 0) break inf_leave; - have--; - hold += input[next++] << bits; - bits += 8; - } - if (state.head) { - state.head.xflags = hold & 255; - state.head.os = hold >> 8; - } - if (state.flags & 512 && state.wrap & 4) { - hbuf[0] = hold & 255; - hbuf[1] = hold >>> 8 & 255; - state.check = crc32$2(state.check, hbuf, 2, 0); - } - hold = 0; - bits = 0; - state.mode = EXLEN; - case EXLEN: - if (state.flags & 1024) { - while (bits < 16) { - if (have === 0) break inf_leave; - have--; - hold += input[next++] << bits; - bits += 8; - } - state.length = hold; - if (state.head) state.head.extra_len = hold; - if (state.flags & 512 && state.wrap & 4) { - hbuf[0] = hold & 255; - hbuf[1] = hold >>> 8 & 255; - state.check = crc32$2(state.check, hbuf, 2, 0); - } - hold = 0; - bits = 0; - } else if (state.head) state.head.extra = null; - state.mode = EXTRA; - case EXTRA: - if (state.flags & 1024) { - copy = state.length; - if (copy > have) copy = have; - if (copy) { - if (state.head) { - len = state.head.extra_len - state.length; - if (!state.head.extra) state.head.extra = new Uint8Array(state.head.extra_len); - state.head.extra.set(input.subarray(next, next + copy), len); - } - if (state.flags & 512 && state.wrap & 4) state.check = crc32$2(state.check, input, copy, next); - have -= copy; - next += copy; - state.length -= copy; - } - if (state.length) break inf_leave; - } - state.length = 0; - state.mode = NAME$1; - case NAME$1: - if (state.flags & 2048) { - if (have === 0) break inf_leave; - copy = 0; - do { - len = input[next + copy++]; - if (state.head && len && state.length < 65536) state.head.name += String.fromCharCode(len); - } while (len && copy < have); - if (state.flags & 512 && state.wrap & 4) state.check = crc32$2(state.check, input, copy, next); - have -= copy; - next += copy; - if (len) break inf_leave; - } else if (state.head) state.head.name = null; - state.length = 0; - state.mode = COMMENT; - case COMMENT: - if (state.flags & 4096) { - if (have === 0) break inf_leave; - copy = 0; - do { - len = input[next + copy++]; - if (state.head && len && state.length < 65536) state.head.comment += String.fromCharCode(len); - } while (len && copy < have); - if (state.flags & 512 && state.wrap & 4) state.check = crc32$2(state.check, input, copy, next); - have -= copy; - next += copy; - if (len) break inf_leave; - } else if (state.head) state.head.comment = null; - state.mode = HCRC; - case HCRC: - if (state.flags & 512) { - while (bits < 16) { - if (have === 0) break inf_leave; - have--; - hold += input[next++] << bits; - bits += 8; - } - if (state.wrap & 4 && hold !== (state.check & 65535)) { - strm.msg = "header crc mismatch"; - state.mode = BAD; - break; - } - hold = 0; - bits = 0; - } - if (state.head) { - state.head.hcrc = state.flags >> 9 & 1; - state.head.done = true; - } - strm.adler = state.check = 0; - state.mode = TYPE; - break; - case DICTID: - while (bits < 32) { - if (have === 0) break inf_leave; - have--; - hold += input[next++] << bits; - bits += 8; - } - strm.adler = state.check = zswap32(hold); - hold = 0; - bits = 0; - state.mode = DICT; - case DICT: - if (state.havedict === 0) { - strm.next_out = put; - strm.avail_out = left; - strm.next_in = next; - strm.avail_in = have; - state.hold = hold; - state.bits = bits; - return 2; - } - strm.adler = state.check = 1; - state.mode = TYPE; - case TYPE: if (flush === 5 || flush === 6) break inf_leave; - case TYPEDO: - if (state.last) { - hold >>>= bits & 7; - bits -= bits & 7; - state.mode = CHECK; - break; - } - while (bits < 3) { - if (have === 0) break inf_leave; - have--; - hold += input[next++] << bits; - bits += 8; - } - state.last = hold & 1; - hold >>>= 1; - bits -= 1; - switch (hold & 3) { - case 0: - state.mode = STORED; - break; - case 1: - fixedtables(state); - state.mode = LEN_; - if (flush === 6) { - hold >>>= 2; - bits -= 2; - break inf_leave; - } - break; - case 2: - state.mode = TABLE; - break; - case 3: - strm.msg = "invalid block type"; - state.mode = BAD; - } - hold >>>= 2; - bits -= 2; - break; - case STORED: - hold >>>= bits & 7; - bits -= bits & 7; - while (bits < 32) { - if (have === 0) break inf_leave; - have--; - hold += input[next++] << bits; - bits += 8; - } - if ((hold & 65535) !== (hold >>> 16 ^ 65535)) { - strm.msg = "invalid stored block lengths"; - state.mode = BAD; - break; - } - state.length = hold & 65535; - hold = 0; - bits = 0; - state.mode = COPY_; - if (flush === 6) break inf_leave; - case COPY_: state.mode = COPY; - case COPY: - copy = state.length; - if (copy) { - if (copy > have) copy = have; - if (copy > left) copy = left; - if (copy === 0) break inf_leave; - output.set(input.subarray(next, next + copy), put); - have -= copy; - next += copy; - left -= copy; - put += copy; - state.length -= copy; - break; - } - state.mode = TYPE; - break; - case TABLE: - while (bits < 14) { - if (have === 0) break inf_leave; - have--; - hold += input[next++] << bits; - bits += 8; - } - state.nlen = (hold & 31) + 257; - hold >>>= 5; - bits -= 5; - state.ndist = (hold & 31) + 1; - hold >>>= 5; - bits -= 5; - state.ncode = (hold & 15) + 4; - hold >>>= 4; - bits -= 4; - if (state.nlen > 286 || state.ndist > 30) { - strm.msg = "too many length or distance symbols"; - state.mode = BAD; - break; - } - state.have = 0; - state.mode = LENLENS; - case LENLENS: - while (state.have < state.ncode) { - while (bits < 3) { - if (have === 0) break inf_leave; - have--; - hold += input[next++] << bits; - bits += 8; - } - state.lens[order[state.have++]] = hold & 7; - hold >>>= 3; - bits -= 3; - } - while (state.have < 19) state.lens[order[state.have++]] = 0; - state.lencode = state.lendyn; - state.lenbits = 7; - opts = { bits: state.lenbits }; - ret = inflate_table(CODES, state.lens, 0, 19, state.lencode, 0, state.work, opts); - state.lenbits = opts.bits; - if (ret) { - strm.msg = "invalid code lengths set"; - state.mode = BAD; - break; - } - state.have = 0; - state.mode = CODELENS; - case CODELENS: - while (state.have < state.nlen + state.ndist) { - for (;;) { - here = state.lencode[hold & (1 << state.lenbits) - 1]; - here_bits = here >>> 24; - here_op = here >>> 16 & 255; - here_val = here & 65535; - if (here_bits <= bits) break; - if (have === 0) break inf_leave; - have--; - hold += input[next++] << bits; - bits += 8; - } - if (here_val < 16) { - hold >>>= here_bits; - bits -= here_bits; - state.lens[state.have++] = here_val; - } else { - if (here_val === 16) { - n = here_bits + 2; - while (bits < n) { - if (have === 0) break inf_leave; - have--; - hold += input[next++] << bits; - bits += 8; - } - hold >>>= here_bits; - bits -= here_bits; - if (state.have === 0) { - strm.msg = "invalid bit length repeat"; - state.mode = BAD; - break; - } - len = state.lens[state.have - 1]; - copy = 3 + (hold & 3); - hold >>>= 2; - bits -= 2; - } else if (here_val === 17) { - n = here_bits + 3; - while (bits < n) { - if (have === 0) break inf_leave; - have--; - hold += input[next++] << bits; - bits += 8; - } - hold >>>= here_bits; - bits -= here_bits; - len = 0; - copy = 3 + (hold & 7); - hold >>>= 3; - bits -= 3; - } else { - n = here_bits + 7; - while (bits < n) { - if (have === 0) break inf_leave; - have--; - hold += input[next++] << bits; - bits += 8; - } - hold >>>= here_bits; - bits -= here_bits; - len = 0; - copy = 11 + (hold & 127); - hold >>>= 7; - bits -= 7; - } - if (state.have + copy > state.nlen + state.ndist) { - strm.msg = "invalid bit length repeat"; - state.mode = BAD; - break; - } - while (copy--) state.lens[state.have++] = len; - } - } - if (state.mode === BAD) break; - if (state.lens[256] === 0) { - strm.msg = "invalid code -- missing end-of-block"; - state.mode = BAD; - break; - } - state.lenbits = 9; - opts = { bits: state.lenbits }; - ret = inflate_table(LENS, state.lens, 0, state.nlen, state.lencode, 0, state.work, opts); - state.lenbits = opts.bits; - if (ret) { - strm.msg = "invalid literal/lengths set"; - state.mode = BAD; - break; - } - state.distbits = 6; - state.distcode = state.distdyn; - opts = { bits: state.distbits }; - ret = inflate_table(DISTS, state.lens, state.nlen, state.ndist, state.distcode, 0, state.work, opts); - state.distbits = opts.bits; - if (ret) { - strm.msg = "invalid distances set"; - state.mode = BAD; - break; - } - state.mode = LEN_; - if (flush === 6) break inf_leave; - case LEN_: state.mode = LEN; - case LEN: - if (have >= 6 && left >= 258) { - strm.next_out = put; - strm.avail_out = left; - strm.next_in = next; - strm.avail_in = have; - state.hold = hold; - state.bits = bits; - inflate_fast(strm, _out); - put = strm.next_out; - output = strm.output; - left = strm.avail_out; - next = strm.next_in; - input = strm.input; - have = strm.avail_in; - hold = state.hold; - bits = state.bits; - if (state.mode === TYPE) state.back = -1; - break; - } - state.back = 0; - for (;;) { - here = state.lencode[hold & (1 << state.lenbits) - 1]; - here_bits = here >>> 24; - here_op = here >>> 16 & 255; - here_val = here & 65535; - if (here_bits <= bits) break; - if (have === 0) break inf_leave; - have--; - hold += input[next++] << bits; - bits += 8; - } - if (here_op && (here_op & 240) === 0) { - last_bits = here_bits; - last_op = here_op; - last_val = here_val; - for (;;) { - here = state.lencode[last_val + ((hold & (1 << last_bits + last_op) - 1) >> last_bits)]; - here_bits = here >>> 24; - here_op = here >>> 16 & 255; - here_val = here & 65535; - if (last_bits + here_bits <= bits) break; - if (have === 0) break inf_leave; - have--; - hold += input[next++] << bits; - bits += 8; - } - hold >>>= last_bits; - bits -= last_bits; - state.back += last_bits; - } - hold >>>= here_bits; - bits -= here_bits; - state.back += here_bits; - state.length = here_val; - if (here_op === 0) { - state.mode = LIT; - break; - } - if (here_op & 32) { - state.back = -1; - state.mode = TYPE; - break; - } - if (here_op & 64) { - strm.msg = "invalid literal/length code"; - state.mode = BAD; - break; - } - state.extra = here_op & 15; - state.mode = LENEXT; - case LENEXT: - if (state.extra) { - n = state.extra; - while (bits < n) { - if (have === 0) break inf_leave; - have--; - hold += input[next++] << bits; - bits += 8; - } - state.length += hold & (1 << state.extra) - 1; - hold >>>= state.extra; - bits -= state.extra; - state.back += state.extra; - } - state.was = state.length; - state.mode = DIST; - case DIST: - for (;;) { - here = state.distcode[hold & (1 << state.distbits) - 1]; - here_bits = here >>> 24; - here_op = here >>> 16 & 255; - here_val = here & 65535; - if (here_bits <= bits) break; - if (have === 0) break inf_leave; - have--; - hold += input[next++] << bits; - bits += 8; - } - if ((here_op & 240) === 0) { - last_bits = here_bits; - last_op = here_op; - last_val = here_val; - for (;;) { - here = state.distcode[last_val + ((hold & (1 << last_bits + last_op) - 1) >> last_bits)]; - here_bits = here >>> 24; - here_op = here >>> 16 & 255; - here_val = here & 65535; - if (last_bits + here_bits <= bits) break; - if (have === 0) break inf_leave; - have--; - hold += input[next++] << bits; - bits += 8; - } - hold >>>= last_bits; - bits -= last_bits; - state.back += last_bits; - } - hold >>>= here_bits; - bits -= here_bits; - state.back += here_bits; - if (here_op & 64) { - strm.msg = "invalid distance code"; - state.mode = BAD; - break; - } - state.offset = here_val; - state.extra = here_op & 15; - state.mode = DISTEXT; - case DISTEXT: - if (state.extra) { - n = state.extra; - while (bits < n) { - if (have === 0) break inf_leave; - have--; - hold += input[next++] << bits; - bits += 8; - } - state.offset += hold & (1 << state.extra) - 1; - hold >>>= state.extra; - bits -= state.extra; - state.back += state.extra; - } - if (state.offset > state.dmax) { - strm.msg = "invalid distance too far back"; - state.mode = BAD; - break; - } - state.mode = MATCH; - case MATCH: - if (left === 0) break inf_leave; - copy = _out - left; - if (state.offset > copy) { - copy = state.offset - copy; - if (copy > state.whave) { - if (state.sane) { - strm.msg = "invalid distance too far back"; - state.mode = BAD; - break; - } - } - if (copy > state.wnext) { - copy -= state.wnext; - from = state.wsize - copy; - } else from = state.wnext - copy; - if (copy > state.length) copy = state.length; - from_source = state.window; - } else { - from_source = output; - from = put - state.offset; - copy = state.length; - } - if (copy > left) copy = left; - left -= copy; - state.length -= copy; - do - output[put++] = from_source[from++]; - while (--copy); - if (state.length === 0) state.mode = LEN; - break; - case LIT: - if (left === 0) break inf_leave; - output[put++] = state.length; - left--; - state.mode = LEN; - break; - case CHECK: - if (state.wrap) { - while (bits < 32) { - if (have === 0) break inf_leave; - have--; - hold |= input[next++] << bits; - bits += 8; - } - _out -= left; - strm.total_out += _out; - state.total += _out; - if (state.wrap & 4 && _out) strm.adler = state.check = state.flags ? crc32$2(state.check, output, _out, put - _out) : adler32(state.check, output, _out, put - _out); - _out = left; - if (state.wrap & 4 && (state.flags ? hold : zswap32(hold)) !== state.check) { - strm.msg = "incorrect data check"; - state.mode = BAD; - break; - } - hold = 0; - bits = 0; - } - state.mode = LENGTH; - case LENGTH: - if (state.wrap && state.flags) { - while (bits < 32) { - if (have === 0) break inf_leave; - have--; - hold += input[next++] << bits; - bits += 8; - } - if (state.wrap & 4 && hold !== (state.total & 4294967295)) { - strm.msg = "incorrect length check"; - state.mode = BAD; - break; - } - hold = 0; - bits = 0; - } - state.mode = DONE; - case DONE: - ret = 1; - break inf_leave; - case BAD: - ret = -3; - break inf_leave; - case MEM: return -4; - case SYNC: - default: return -2; - } - strm.next_out = put; - strm.avail_out = left; - strm.next_in = next; - strm.avail_in = have; - state.hold = hold; - state.bits = bits; - if (state.wsize || _out !== strm.avail_out && state.mode < BAD && (state.mode < CHECK || flush !== 4)) { - if (updatewindow(strm, strm.output, strm.next_out, _out - strm.avail_out)) { - state.mode = MEM; - return -4; - } - } - _in -= strm.avail_in; - _out -= strm.avail_out; - strm.total_in += _in; - strm.total_out += _out; - state.total += _out; - if (state.wrap & 4 && _out) strm.adler = state.check = state.flags ? crc32$2(state.check, output, _out, strm.next_out - _out) : adler32(state.check, output, _out, strm.next_out - _out); - strm.data_type = state.bits + (state.last ? 64 : 0) + (state.mode === TYPE ? 128 : 0) + (state.mode === LEN_ || state.mode === COPY_ ? 256 : 0); - if ((_in === 0 && _out === 0 || flush === 4) && ret === 0) ret = -5; - return ret; -}; -var inflateEnd = (strm) => { - if (inflateStateCheck(strm)) return -2; - let state = strm.state; - if (state.window) state.window = null; - strm.state = null; - return 0; -}; -var inflateSetDictionary = (strm, dictionary) => { - const dictLength = dictionary.length; - let state; - let dictid; - let ret; - if (inflateStateCheck(strm)) return -2; - state = strm.state; - if (state.wrap !== 0 && state.mode !== DICT) return -2; - if (state.mode === DICT) { - dictid = 1; - dictid = adler32(dictid, dictionary, dictLength, 0); - if (dictid !== state.check) return -3; - } - ret = updatewindow(strm, dictionary, dictLength, dictLength); - if (ret) { - state.mode = MEM; - return -4; - } - state.havedict = 1; - return 0; -}; -var ZStream = class { - constructor() { - this.input = null; - this.next_in = 0; - this.avail_in = 0; - this.total_in = 0; - this.output = null; - this.next_out = 0; - this.avail_out = 0; - this.total_out = 0; - this.msg = ""; - this.state = null; - this.data_type = 2; - this.adler = 0; - } -}; -var flattenChunks = (chunks) => { - const result = new Uint8Array(chunks.reduce((len, chunk) => len + chunk.length, 0)); - let pos = 0; - for (const chunk of chunks) { - result.set(chunk, pos); - pos += chunk.length; - } - return result; -}; -var toString$1 = Object.prototype.toString; -var defaultOptions$1 = { - level: -1, - chunkSize: 16384, - windowBits: 15, - memLevel: 8, - strategy: 0, - raw: false, - gzip: false, - legacyHash: false, - dictionary: /* @__PURE__ */ new Uint8Array(0) + HKDF_COUNTER[0] = blocks; + if (blocks > 1) iHash.update(T); + iHash.update(info).update(HKDF_COUNTER).digestInto(T); + oHash.update(T).digestInto(T); + okm.set(T, olen * (blocks - 1)); + iHash.destroy(); + oHash.destroy(); + worker?.destroy(); + if (T !== okm) clean$1(T); + clean$1(HKDF_COUNTER); + if (length === okm.length) return okm; + const res = okm.slice(0, length); + clean$1(okm); + return res; +} +/** +* HKDF (RFC 5869): derive keys from an initial input. +* Combines hkdf_extract + hkdf_expand in one step +* @param hash - hash function that would be used (e.g. sha256) +* @param ikm - input keying material, the initial key +* @param salt - optional salt value (a non-secret random value) +* @param info - optional context and application specific information bytes +* @param length - length of output keying material in bytes. +* RFC 5869 §2.3 allows `0..255*HashLen`, so `0` returns an empty OKM. +* @returns Output keying material derived from the input key. +* @throws If the requested output length exceeds the HKDF limit +* for the selected hash. {@link Error} +* @example +* HKDF (RFC 5869): derive keys from an initial input. +* ```ts +* import { hkdf } from '@noble/hashes/hkdf.js'; +* import { sha256 } from '@noble/hashes/sha2.js'; +* import { randomBytes, utf8ToBytes } from '@noble/hashes/utils.js'; +* const inputKey = randomBytes(32); +* const salt = randomBytes(32); +* const info = utf8ToBytes('application-key'); +* const okm = hkdf(sha256, inputKey, salt, info, 32); +* ``` +*/ +const hkdf = (hash, ikm, salt, info, length) => { + ahash(hash); + if (salt === void 0) salt = new Uint8Array(hash.outputLen); + const HMAC = hmac.create(hash, salt).update(ikm); + return expand(hash, HMAC.digest(), info, length, HMAC); }; +//#endregion +//#region ../../node_modules/@noble/hashes/scrypt.js /** -* Generic JS-style wrapper for zlib calls. If you don't need -* streaming behaviour, use the simpler functions {@link deflate}, -* {@link deflateRaw} and {@link gzip}. +* RFC 7914 Scrypt KDF. Can be used to create a key from password and salt. +* @module */ -var Deflate = class { - options; - /** - * Error code after deflate finishes. {@link Z_OK} on success. - * You will not need it in real life, because deflate errors - * are possible only on wrong options or bad custom `onData` / `onEnd` - * handlers. - */ - err; - /** Error message, if {@link Deflate.err} is not {@link Z_OK}. */ - msg; - ended; - started; - /** - * Chunks of output data, if {@link Deflate.onData} not overridden. - * @internal - */ - chunks; - strm; - /** - * Compressed result, generated by default {@link Deflate.onData} - * and {@link Deflate.onEnd} handlers. Filled after you push last chunk - * (call {@link Deflate.push} with {@link Z_FINISH} / `true` param). - */ - result; - /** - * Creates a new deflator instance with the specified params. Throws an - * exception on bad params. See {@link DeflateOptions} for the list of - * supported options. - * - * @example - * ```javascript - * import { Deflate } from 'pako' - * - * const chunk1 = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9]) - * const chunk2 = new Uint8Array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19]) - * - * const deflate = new Deflate({ level: 3 }) - * - * deflate.push(chunk1, false) - * deflate.push(chunk2, true) // true -> last chunk - * - * if (deflate.err) throw new Error(deflate.err) - * - * console.log(deflate.result) - * ``` - */ - constructor(options = {}) { - this.options = Object.assign({}, defaultOptions$1, options); - const opt = this.options; - if (opt.raw && opt.windowBits > 0) opt.windowBits = -opt.windowBits; - else if (opt.gzip && opt.windowBits > 0 && opt.windowBits < 16) opt.windowBits += 16; - this.err = 0; - this.msg = ""; - this.ended = false; - this.started = false; - this.chunks = []; - this.result = /* @__PURE__ */ new Uint8Array(0); - this.strm = new ZStream(); - this.strm.avail_out = 0; - let status = deflateInit2(this.strm, opt.level, 8, opt.windowBits, opt.memLevel, opt.strategy, opt.legacyHash); - if (status !== 0) throw new Error(messages_default[status]); - if (toString$1.call(opt.dictionary) === "[object ArrayBuffer]") opt.dictionary = new Uint8Array(opt.dictionary); - const dictionary = opt.dictionary; - if (dictionary.length) { - if (opt.gzip) throw new Error("dictionary is not supported with gzip"); - status = deflateSetDictionary(this.strm, dictionary); - if (status !== 0) throw new Error(messages_default[status]); - } - } - /** - * Sends input data to the deflate pipe, generating {@link Deflate.onData} calls - * with new compressed chunks. Returns `true` on success. The last data block must - * have `flush_mode` {@link Z_FINISH} (or `true`). That will flush the internal - * pending buffers and call {@link Deflate.onEnd}. - * - * On failure, calls {@link Deflate.onEnd} with the error code and returns false. - * - * @param data input data. Strings will be converted to utf8 byte sequence. - * @param flush_mode 0..6 for corresponding {@link Z_NO_FLUSH}..{@link Z_TREES} modes. - * See constants. Skipped or `false` means {@link Z_NO_FLUSH}, `true` means {@link Z_FINISH}. - * - * @example - * ```javascript - * push(chunk, false) // push one of data chunks - * ... - * push(chunk, true) // push last chunk - * ``` - */ - push(data, flush_mode = false) { - const strm = this.strm; - const chunkSize = this.options.chunkSize; - let status; - let _flush_mode; - if (this.ended) return false; - if (typeof flush_mode === "number") _flush_mode = flush_mode; - else _flush_mode = flush_mode === true ? 4 : 0; - if (typeof data === "string") strm.input = new TextEncoder().encode(data); - else if (toString$1.call(data) === "[object ArrayBuffer]") strm.input = new Uint8Array(data); - else strm.input = data; - strm.next_in = 0; - strm.avail_in = strm.input.length; - if (!this.started) { - this.started = true; - this.onStart(strm); - } - for (;;) { - if (strm.avail_out === 0) { - strm.output = new Uint8Array(chunkSize); - strm.next_out = 0; - strm.avail_out = chunkSize; - } - if ((_flush_mode === 2 || _flush_mode === 3) && strm.avail_out <= 6) { - this.onData(strm.output.subarray(0, strm.next_out)); - strm.avail_out = 0; - continue; - } - status = deflate$1(strm, _flush_mode); - if (status === -2) break; - if (status === 1) { - if (strm.next_out > 0) this.onData(strm.output.subarray(0, strm.next_out)); - status = deflateEnd(this.strm); - break; - } - if (strm.avail_out === 0) { - this.onData(strm.output); - continue; - } - if (_flush_mode > 0 && strm.next_out > 0) { - this.onData(strm.output.subarray(0, strm.next_out)); - strm.avail_out = 0; - continue; - } - if (strm.avail_in === 0) return true; - } - this.err = status; - this.msg = strm.msg || messages_default[status]; - this.ended = true; - this.onEnd(status); - return status === 0; - } - /** - * Called once before the first low-level deflate call. - */ - onStart(strm) {} - /** - * By default, stores data blocks in the {@link Deflate.chunks} property and glues - * them in {@link Deflate.onEnd}. Override this handler if you need another behaviour. - */ - onData(chunk) { - this.chunks.push(chunk); - } - /** - * Called once after you tell deflate that the input stream is - * complete ({@link Z_FINISH}). By default, joins the collected {@link Deflate.chunks} - * into the {@link Deflate.result} property. - * - * @param status deflate status. {@link Z_OK} on success, other if not. - */ - onEnd(status) { - if (status === 0) this.result = flattenChunks(this.chunks); - this.chunks = []; +function XorAndSalsa(prev, pi, input, ii, out, oi) { + let y00 = prev[pi++] ^ input[ii++], y01 = prev[pi++] ^ input[ii++]; + let y02 = prev[pi++] ^ input[ii++], y03 = prev[pi++] ^ input[ii++]; + let y04 = prev[pi++] ^ input[ii++], y05 = prev[pi++] ^ input[ii++]; + let y06 = prev[pi++] ^ input[ii++], y07 = prev[pi++] ^ input[ii++]; + let y08 = prev[pi++] ^ input[ii++], y09 = prev[pi++] ^ input[ii++]; + let y10 = prev[pi++] ^ input[ii++], y11 = prev[pi++] ^ input[ii++]; + let y12 = prev[pi++] ^ input[ii++], y13 = prev[pi++] ^ input[ii++]; + let y14 = prev[pi++] ^ input[ii++], y15 = prev[pi++] ^ input[ii++]; + let x00 = y00, x01 = y01, x02 = y02, x03 = y03, x04 = y04, x05 = y05, x06 = y06, x07 = y07, x08 = y08, x09 = y09, x10 = y10, x11 = y11, x12 = y12, x13 = y13, x14 = y14, x15 = y15; + for (let i = 0; i < 8; i += 2) { + x04 ^= rotl$1(x00 + x12 | 0, 7); + x08 ^= rotl$1(x04 + x00 | 0, 9); + x12 ^= rotl$1(x08 + x04 | 0, 13); + x00 ^= rotl$1(x12 + x08 | 0, 18); + x09 ^= rotl$1(x05 + x01 | 0, 7); + x13 ^= rotl$1(x09 + x05 | 0, 9); + x01 ^= rotl$1(x13 + x09 | 0, 13); + x05 ^= rotl$1(x01 + x13 | 0, 18); + x14 ^= rotl$1(x10 + x06 | 0, 7); + x02 ^= rotl$1(x14 + x10 | 0, 9); + x06 ^= rotl$1(x02 + x14 | 0, 13); + x10 ^= rotl$1(x06 + x02 | 0, 18); + x03 ^= rotl$1(x15 + x11 | 0, 7); + x07 ^= rotl$1(x03 + x15 | 0, 9); + x11 ^= rotl$1(x07 + x03 | 0, 13); + x15 ^= rotl$1(x11 + x07 | 0, 18); + x01 ^= rotl$1(x00 + x03 | 0, 7); + x02 ^= rotl$1(x01 + x00 | 0, 9); + x03 ^= rotl$1(x02 + x01 | 0, 13); + x00 ^= rotl$1(x03 + x02 | 0, 18); + x06 ^= rotl$1(x05 + x04 | 0, 7); + x07 ^= rotl$1(x06 + x05 | 0, 9); + x04 ^= rotl$1(x07 + x06 | 0, 13); + x05 ^= rotl$1(x04 + x07 | 0, 18); + x11 ^= rotl$1(x10 + x09 | 0, 7); + x08 ^= rotl$1(x11 + x10 | 0, 9); + x09 ^= rotl$1(x08 + x11 | 0, 13); + x10 ^= rotl$1(x09 + x08 | 0, 18); + x12 ^= rotl$1(x15 + x14 | 0, 7); + x13 ^= rotl$1(x12 + x15 | 0, 9); + x14 ^= rotl$1(x13 + x12 | 0, 13); + x15 ^= rotl$1(x14 + x13 | 0, 18); } -}; -/** -* Compress `data` with deflate algorithm and `options`. -* See {@link DeflateOptions} for the list of supported options. -* -* @example -* ```javascript -* import { deflate } from 'pako' -* -* const data = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9]) -* -* console.log(deflate(data)) -* ``` -*/ -function deflate(input, options = {}) { - const deflator = new Deflate(options); - deflator.push(input, true); - if (deflator.err) throw new Error(deflator.msg); - return deflator.result; + out[oi++] = y00 + x00 | 0; + out[oi++] = y01 + x01 | 0; + out[oi++] = y02 + x02 | 0; + out[oi++] = y03 + x03 | 0; + out[oi++] = y04 + x04 | 0; + out[oi++] = y05 + x05 | 0; + out[oi++] = y06 + x06 | 0; + out[oi++] = y07 + x07 | 0; + out[oi++] = y08 + x08 | 0; + out[oi++] = y09 + x09 | 0; + out[oi++] = y10 + x10 | 0; + out[oi++] = y11 + x11 | 0; + out[oi++] = y12 + x12 | 0; + out[oi++] = y13 + x13 | 0; + out[oi++] = y14 + x14 | 0; + out[oi++] = y15 + x15 | 0; } -/** -* The same as {@link deflate}, but creates raw data without a wrapper -* (header and adler32 crc). -*/ -function deflateRaw(input, options = {}) { - return deflate(input, Object.assign({}, options, { raw: true })); +function BlockMix(input, ii, out, oi, r) { + let head = oi + 0; + let tail = oi + 16 * r; + for (let i = 0; i < 16; i++) out[tail + i] = input[ii + (2 * r - 1) * 16 + i]; + for (let i = 0; i < r; i++, head += 16, ii += 16) { + XorAndSalsa(out, tail, input, ii, out, head); + if (i > 0) tail += 16; + XorAndSalsa(out, head, input, ii += 16, out, tail); + } } -var toString = Object.prototype.toString; -var defaultOptions = { - chunkSize: 65536, - windowBits: 15, - raw: false, - dictionary: /* @__PURE__ */ new Uint8Array(0) -}; -/** -* Generic JS-style wrapper for zlib calls. If you don't need -* streaming behaviour, use the simpler functions {@link inflate} -* and {@link inflateRaw}. -*/ -var Inflate = class { - options; - /** - * Error code after inflate finishes. {@link Z_OK} on success. - * Should be checked when broken data is possible. - */ - err; - /** Error message, if {@link Inflate.err} is not {@link Z_OK}. */ - msg; - /** - * `true` once the compressed stream has ended. A stream may end before the - * caller's data does (trailing bytes), so check this to know when to stop - * pushing - further {@link Inflate.push} calls are no-ops. - */ - ended; - started; - /** - * Chunks of output data, if {@link Inflate.onData} not overridden. - * @internal - */ - chunks; - strm; - /** - * Uncompressed result, generated by default {@link Inflate.onData} - * and {@link Inflate.onEnd} handlers. Filled after you push last chunk - * (call {@link Inflate.push} with {@link Z_FINISH} / `true` param). - */ - result; - /** - * Creates a new inflator instance with the specified params. Throws an - * exception on bad params. See {@link InflateOptions} for the list of - * supported options. - * - * By default, when no options are set, the deflate/gzip data format is - * autodetected via the wrapper header. - * - * @example - * ```javascript - * import { Inflate } from 'pako' - * - * const chunk1 = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9]) - * const chunk2 = new Uint8Array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19]) - * - * const inflate = new Inflate({ level: 3 }) - * - * inflate.push(chunk1, false) - * inflate.push(chunk2, true) // true -> last chunk - * - * if (inflate.err) throw new Error(inflate.err) - * - * console.log(inflate.result) - * ``` - */ - constructor(options = {}) { - this.options = Object.assign({}, defaultOptions, options); - const opt = this.options; - if (opt.raw && opt.windowBits >= 0 && opt.windowBits < 16) { - opt.windowBits = -opt.windowBits; - if (opt.windowBits === 0) opt.windowBits = -15; - } - if (opt.windowBits >= 0 && opt.windowBits < 16 && !options.windowBits) opt.windowBits += 32; - if (opt.windowBits > 15 && opt.windowBits < 48) { - if ((opt.windowBits & 15) === 0) opt.windowBits |= 15; - } - this.err = 0; - this.msg = ""; - this.ended = false; - this.started = false; - this.chunks = []; - this.result = /* @__PURE__ */ new Uint8Array(0); - this.strm = new ZStream(); - this.strm.avail_out = 0; - let status = inflateInit2(this.strm, opt.windowBits); - if (status !== 0) throw new Error(messages_default[status]); - if (toString.call(opt.dictionary) === "[object ArrayBuffer]") opt.dictionary = new Uint8Array(opt.dictionary); - const dictionary = opt.dictionary; - if (opt.raw && dictionary.length) { - status = inflateSetDictionary(this.strm, dictionary); - if (status !== 0) throw new Error(messages_default[status]); - } - } - /** - * Sends input data to the inflate pipe, generating {@link Inflate.onData} calls - * with new output chunks. Returns `true` on success. If end of stream is - * detected, {@link Inflate.onEnd} will be called. - * - * `flush_mode` is not needed for normal operation, because end of stream - * is detected automatically. Pass {@link Z_SYNC_FLUSH} to force the decoder - * to emit all currently available output — handy when you need to decode - * data frame-by-frame from a long-running stream. - * - * On failure, calls {@link Inflate.onEnd} with the error code and returns false. - * - * Once the stream has ended (a compressed stream may end before your data - * does), further `push` calls are no-ops and return whether the decode - * finished successfully. The final outcome is in {@link Inflate.result}, - * {@link Inflate.err} and {@link Inflate.msg}. - * - * @param flush_mode 0..6 for corresponding {@link Z_NO_FLUSH}..{@link Z_TREES} - * flush modes. See constants. Skipped or `false` means {@link Z_NO_FLUSH}, - * `true` means {@link Z_FINISH}. - * - * @example - * ```javascript - * push(chunk, false) // push one of data chunks - * ... - * push(chunk, true) // push last chunk - * ``` - */ - push(data, flush_mode = false) { - const strm = this.strm; - const chunkSize = this.options.chunkSize; - let status; - let _flush_mode; - let last_avail_out; - if (this.ended) return this.err === 0; - if (typeof flush_mode === "number") _flush_mode = flush_mode; - else _flush_mode = flush_mode === true ? 4 : 0; - if (toString.call(data) === "[object ArrayBuffer]") strm.input = new Uint8Array(data); - else strm.input = data; - strm.next_in = 0; - strm.avail_in = strm.input.length; - if (!this.started) { - this.started = true; - this.onStart(strm); - } - for (;;) { - if (strm.avail_out === 0) { - strm.output = new Uint8Array(chunkSize); - strm.next_out = 0; - strm.avail_out = chunkSize; - } - status = inflate$1(strm, _flush_mode); - if (status === 2) { - const dictionary = this.options.dictionary; - if (dictionary.length) { - status = inflateSetDictionary(strm, dictionary); - if (status === 0) status = inflate$1(strm, _flush_mode); - else if (status === -3) status = 2; - } - } - while (strm.avail_in > 0 && status === 1 && strm.state.wrap & 2 && strm.state.flags !== 0 && strm.input[strm.next_in] !== 0) { - inflateReset(strm); - status = inflate$1(strm, _flush_mode); - } - if (status === -2 || status === -3 || status === 2 || status === -4) break; - last_avail_out = strm.avail_out; - if (strm.next_out) { - if (strm.avail_out === 0 || status === 1 || _flush_mode > 0) { - this.onData(strm.output.length === strm.next_out ? strm.output : strm.output.subarray(0, strm.next_out)); - strm.avail_out = 0; - strm.next_out = 0; - } - } - if ((status === 0 || status === -5) && last_avail_out === 0) continue; - if (status === 1) { - status = inflateEnd(this.strm); - break; - } - if (strm.avail_in === 0) { - if (_flush_mode === 4) { - status = inflateEnd(this.strm); - if (status === 0) status = -5; - break; - } - return true; - } - } - this.err = status; - this.msg = strm.msg || messages_default[status]; - this.ended = true; - this.onEnd(status); - return status === 0; - } - /** - * Called once before the first low-level inflate call. - * - * Override this handler to attach low-level inflate state, for example to read - * gzip header metadata: - * - * ```javascript - * import { Inflate, GZheader, zlibInflateGetHeader } from 'pako' - * - * const inflator = new Inflate() - * - * inflator.onStart = function (strm) { - * this.header = new GZheader() - * zlibInflateGetHeader(strm, this.header) - * } - * - * inflator.push(data, true) - * console.log(inflator.header.name) - * ``` - */ - onStart(strm) {} - /** - * By default, stores data blocks in the {@link Inflate.chunks} property and glues - * them in {@link Inflate.onEnd}. Override this handler if you need another behaviour. - * - * @param chunk output data. - */ - onData(chunk) { - this.chunks.push(chunk); - } - /** - * Called after you tell inflate that the input stream is - * complete ({@link Z_FINISH}). By default, joins the collected {@link Inflate.chunks}, - * frees memory and fills the {@link Inflate.result} property. - * - * @param status inflate status. {@link Z_OK} on success, other if not. - */ - onEnd(status) { - if (status === 0) this.result = flattenChunks(this.chunks); - this.chunks = []; - } -}; -/** -* One-shot inflate decompress. Autodetects `gzip`/`zlib` -* format via the wrapper header — so {@link ungzip} is just a convenience alias of -* this function. See {@link InflateOptions} for zlib options. Set -* `toText: true` to decode the result as UTF-8 text. -* -* @example -* ```javascript -* import { deflate, inflate } from 'pako' -* -* const input = deflate(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9])) -* let output -* -* try { -* output = inflate(input) -* } catch (err) { -* console.log(err) -* } -* ``` -*/ -function inflate(input, options = {}) { - const inflator = new Inflate(options); - inflator.push(input, true); - if (inflator.err) throw new Error(inflator.msg); - const result = inflator.result; - return options.toText ? new TextDecoder().decode(result) : result; -} -/** -* The same as {@link inflate}, but consumes raw data without a wrapper -* (header and adler32 crc). -*/ -function inflateRaw(input, options = {}) { - return inflate(input, { - ...options, - raw: true - }); -} -//#endregion -//#region tests/baseline/node_modules/@bcts/crypto/dist/rolldown-runtime-w6R9maHv.mjs -var __defProp = Object.defineProperty; -var __exportAll = (all, no_symbols) => { - let target = {}; - for (var name in all) __defProp(target, name, { - get: all[name], - enumerable: true +const SCRYPT_DEFAULT_MAXMEM = 1024 * (2 ** 20 + 1 + 1); +function scryptInit(password, salt, _opts) { + const { N, r, p, dkLen, asyncTick, maxmem, onProgress } = checkOpts$1({ + dkLen: 32, + asyncTick: 10, + maxmem: SCRYPT_DEFAULT_MAXMEM + }, _opts); + anumber$2(N, "N"); + anumber$2(r, "r"); + anumber$2(p, "p"); + anumber$2(dkLen, "dkLen"); + anumber$2(asyncTick, "asyncTick"); + anumber$2(maxmem, "maxmem"); + if (onProgress !== void 0 && typeof onProgress !== "function") throw new Error("\"onProgress\" must be a function"); + if (r < 1) throw new Error("\"r\" expected integer >= 1"); + const blockSize = 128 * r; + const blockSize32 = blockSize / 4; + const pow32 = Math.pow(2, 32); + if (N <= 1 || (N & N - 1) !== 0 || N > pow32) throw new Error("\"N\" expected a power of 2, and 2^1 <= N <= 2^32"); + if (p < 1 || p > (pow32 - 1) * 32 / blockSize) throw new Error("\"p\" expected integer 1..((2^32 - 1) * 32) / (128 * r)"); + if (dkLen < 1 || dkLen > (pow32 - 1) * 32) throw new Error("\"dkLen\" expected integer 1..(2^32 - 1) * 32"); + const memUsed = blockSize * (N + p + 1); + if (memUsed > maxmem) throw new Error("\"maxmem\" limit was hit: memUsed(128*r*(N+p+1))=" + memUsed + ", maxmem=" + maxmem); + const B = pbkdf2(sha256$1, password, salt, { + c: 1, + dkLen: blockSize * p }); - if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" }); - return target; -}; -//#endregion -//#region tests/baseline/node_modules/@noble/hashes/_u64.js -const U32_MASK64$1 = /* @__PURE__ */ (() => BigInt(2 ** 32 - 1))(); -const _32n$1 = /* @__PURE__ */ BigInt(32); -function fromBig$1(n, le = false) { - if (le) return { - h: Number(n & U32_MASK64$1), - l: Number(n >> _32n$1 & U32_MASK64$1) - }; - return { - h: Number(n >> _32n$1 & U32_MASK64$1) | 0, - l: Number(n & U32_MASK64$1) | 0 - }; -} -function split$1(lst, le = false) { - const len = lst.length; - let Ah = new Uint32Array(len); - let Al = new Uint32Array(len); - for (let i = 0; i < len; i++) { - const { h, l } = fromBig$1(lst[i], le); - [Ah[i], Al[i]] = [h, l]; + const B32 = u32$1(B); + const V = u32$1(new Uint8Array(blockSize * N)); + const tmp = u32$1(new Uint8Array(blockSize)); + let blockMixCb = () => {}; + if (onProgress) { + const totalBlockMix = 2 * N * p; + const callbackPer = Math.max(Math.floor(totalBlockMix / 1e4), 1); + let blockMixCnt = 0; + blockMixCb = () => { + blockMixCnt++; + if (onProgress && (!(blockMixCnt % callbackPer) || blockMixCnt === totalBlockMix)) try { + onProgress(blockMixCnt / totalBlockMix); + } catch (e) { + clean$1(B, V, tmp); + throw e; + } + }; } - return [Ah, Al]; -} -const fromNumH = (n) => n / 2 ** 32 | 0; -const fromNumL = (n) => n >>> 0; -function setU64FromNum(view, byteOffset, n, isLE) { - const h = fromNumH(n); - const l = fromNumL(n); - view.setUint32(byteOffset, isLE ? l : h, isLE); - view.setUint32(byteOffset + 4, isLE ? h : l, isLE); -} -const shrSH = (h, _l, s) => h >>> s; -const shrSL = (h, l, s) => h << 32 - s | l >>> s; -const rotrSH = (h, l, s) => h >>> s | l << 32 - s; -const rotrSL = (h, l, s) => h << 32 - s | l >>> s; -const rotrBH = (h, l, s) => h << 64 - s | l >>> s - 32; -const rotrBL = (h, l, s) => h >>> s - 32 | l << 64 - s; -const rotr32H = (_h, l) => l; -const rotr32L = (h, _l) => h; -function add(Ah, Al, Bh, Bl) { - const l = (Al >>> 0) + (Bl >>> 0); return { - h: Ah + Bh + (l / 2 ** 32 | 0) | 0, - l: l | 0 + N, + r, + p, + dkLen, + blockSize32, + V, + B32, + B, + tmp, + blockMixCb, + asyncTick }; } -const add3L = (Al, Bl, Cl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0); -const add3H = (low, Ah, Bh, Ch) => Ah + Bh + Ch + (low / 2 ** 32 | 0) | 0; -const add4L = (Al, Bl, Cl, Dl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0); -const add4H = (low, Ah, Bh, Ch, Dh) => Ah + Bh + Ch + Dh + (low / 2 ** 32 | 0) | 0; -const add5L = (Al, Bl, Cl, Dl, El) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0) + (El >>> 0); -const add5H = (low, Ah, Bh, Ch, Dh, Eh) => Ah + Bh + Ch + Dh + Eh + (low / 2 ** 32 | 0) | 0; -//#endregion -//#region tests/baseline/node_modules/@noble/hashes/utils.js -/** -* Checks if something is Uint8Array. Be careful: nodejs Buffer will return true. -* @param a - value to test -* @returns `true` when the value is a Uint8Array-compatible view. -* @example -* Check whether a value is a Uint8Array-compatible view. -* ```ts -* isBytes(new Uint8Array([1, 2, 3])); -* ``` -*/ -function isBytes$4(a) { - return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array" && "BYTES_PER_ELEMENT" in a && a.BYTES_PER_ELEMENT === 1; +function scryptOutput(password, dkLen, B, V, tmp) { + const res = pbkdf2(sha256$1, password, B, { + c: 1, + dkLen + }); + clean$1(B, V, tmp); + return res; } -const atitle$2 = (title) => title ? `"${title}" ` : ""; /** -* Asserts something is a non-negative integer. -* @param n - number to validate -* @param title - label included in thrown errors -* @returns The validated number. -* @throws On wrong argument types. {@link TypeError} -* @throws On wrong argument ranges or values. {@link RangeError} +* Scrypt KDF from RFC 7914. See {@link ScryptOpts}. +* @param password - password or key material to derive from; +* JS string inputs are UTF-8 encoded first +* @param salt - unique salt bytes or string; JS string inputs are UTF-8 encoded first +* @param opts - Scrypt cost and memory parameters. `dkLen`, if provided, +* must be `>= 1` per RFC 7914 §2. See {@link ScryptOpts}. +* @returns Derived key bytes. +* @throws If the Scrypt cost, memory, or callback options are invalid. {@link Error} * @example -* Validate a non-negative integer option. +* Derive a key with scrypt. * ```ts -* anumber(32, 'length'); +* scrypt('password', 'salt', { N: 2**18, r: 8, p: 1, dkLen: 32 }); * ``` -*/ -function anumber$4(n, title = "") { - if (typeof n !== "number") throw new TypeError(atitle$2(title) + "expected number, got " + typeof n); - if (!Number.isSafeInteger(n) || n < 0) throw new RangeError(atitle$2(title) + "expected integer >= 0, got " + n); - return n; -} -/** -* Asserts something is Uint8Array. -* @param value - value to validate -* @param length - optional exact length constraint -* @param title - label included in thrown errors -* @returns The validated byte array. -* @throws On wrong argument types. {@link TypeError} -* @throws On wrong argument ranges or values. {@link RangeError} * @example -* Validate that a value is a byte array. +* Derive a key with small demo costs and progress/memory controls. * ```ts -* abytes(new Uint8Array([1, 2, 3])); +* const progressLog: number[] = []; +* scrypt('password', 'salt', { +* N: 16, +* r: 8, +* p: 1, +* dkLen: 32, +* maxmem: 1024 * 1024, +* asyncTick: 10, +* onProgress(progress) { +* progressLog.push(progress); +* }, +* }); * ``` */ -function abytes$5(value, length, title = "") { - if (isBytes$4(value) && (length === void 0 || value.length === length)) return value; - if (length !== void 0) anumber$4(length, "length"); - const bytes = isBytes$4(value); - const ofLen = length !== void 0 ? ` of length ${length}` : ""; - const got = bytes ? `length=${value.length}` : `type=${typeof value}`; - const message = atitle$2(title) + "expected Uint8Array" + ofLen + ", got " + got; - if (!bytes) throw new TypeError(message); - throw new RangeError(message); +function scrypt$1(password, salt, opts) { + const { N, r, p, dkLen, blockSize32, V, B32, B, tmp, blockMixCb } = scryptInit(password, salt, opts); + swap32IfBE$1(B32); + for (let pi = 0; pi < p; pi++) { + const Pi = blockSize32 * pi; + for (let i = 0; i < blockSize32; i++) V[i] = B32[Pi + i]; + for (let i = 0, pos = 0; i < N - 1; i++) { + BlockMix(V, pos, V, pos += blockSize32, r); + blockMixCb(); + } + BlockMix(V, (N - 1) * blockSize32, B32, Pi, r); + blockMixCb(); + for (let i = 0; i < N; i++) { + const j = (B32[Pi + blockSize32 - 16] & N - 1) >>> 0; + for (let k = 0; k < blockSize32; k++) tmp[k] = B32[Pi + k] ^ V[j * blockSize32 + k]; + BlockMix(tmp, 0, B32, Pi, r); + blockMixCb(); + } + } + swap32IfBE$1(B32); + return scryptOutput(password, dkLen, B, V, tmp); } +//#endregion +//#region ../../node_modules/@noble/hashes/_blake.js /** -* Copies bytes into a fresh Uint8Array. -* Buffer-style slices can alias the same backing store, so callers that need ownership should copy. -* @param bytes - source bytes to clone -* @returns Freshly allocated copy of `bytes`. -* @throws On wrong argument types. {@link TypeError} -* @example -* Clone a byte array before mutating it. -* ```ts -* const copy = copyBytes(new Uint8Array([1, 2, 3])); -* ``` +* Internal blake permutation table. +* Rows `0..9` serve BLAKE2s, rows `0..11` serve BLAKE2b with `10..11 = 0..1`, and Blake1 also +* reuses the later rows shown below. Blake1 expands rounds `10..15` as `SIGMA[i % 10]`, so rows +* `10..15` intentionally repeat rows `0..5` for the 14-round (256) and 16-round (512) variants. */ -function copyBytes$3(bytes) { - return Uint8Array.from(abytes$5(bytes)); -} -/** -* Asserts something is a wrapped hash constructor. -* @param h - hash constructor to validate -* @throws On wrong argument types or invalid hash wrapper shape. {@link TypeError} -* @throws On invalid hash metadata ranges or values. {@link RangeError} -* @throws If the hash metadata allows empty outputs or block sizes. {@link Error} -* @example -* Validate a callable hash wrapper. -* ```ts -* import { ahash } from '@noble/hashes/utils.js'; -* import { sha256 } from '@noble/hashes/sha2.js'; -* ahash(sha256); -* ``` -*/ -function ahash(h) { - if (typeof h !== "function" || typeof h.create !== "function") throw new TypeError("expected hash wrapped by utils.createHasher"); - anumber$4(h.outputLen); - anumber$4(h.blockLen); - if (h.outputLen < 1 || h.blockLen < 1) throw new Error("hash blockLen / outputLen must be >= 1"); -} -const aobject$2 = (value, label) => { - if (value === null || typeof value !== "object" || Array.isArray(value)) throw new TypeError((label === "object" ? "" : `"${label}" `) + "expected object, got type=" + typeof value); -}; -const aopts = (value, label) => { - aobject$2(value, label); - const proto = Object.getPrototypeOf(value); - if (proto !== Object.prototype && proto !== null) throw new TypeError(`"${label}" expected plain object`); - if (Object.hasOwn(value, "__proto__")) throw new TypeError(`"${label}.__proto__" is not allowed`); -}; -/** -* Asserts a hash instance has not been destroyed or finished. -* @param instance - hash instance to validate -* @param checkFinished - whether to reject finalized instances -* @throws If the hash instance has already been destroyed or finalized. {@link Error} -* @example -* Validate that a hash instance is still usable. -* ```ts -* import { aexists } from '@noble/hashes/utils.js'; -* import { sha256 } from '@noble/hashes/sha2.js'; -* const hash = sha256.create(); -* aexists(hash); -* ``` -*/ -function aexists$2(instance, checkFinished = true) { - if (instance.destroyed) throw new Error("hash was destroyed"); - if (checkFinished && instance.finished) throw new Error("digest() was already called"); -} -/** -* Asserts output is a sufficiently-sized byte array. -* @param out - destination buffer -* @param instance - hash instance providing output length -* Oversized buffers are allowed; downstream code only promises to fill the first `outputLen` bytes. -* @throws On wrong argument types. {@link TypeError} -* @throws On wrong argument ranges or values. {@link RangeError} -* @example -* Validate a caller-provided digest buffer. -* ```ts -* import { aoutput } from '@noble/hashes/utils.js'; -* import { sha256 } from '@noble/hashes/sha2.js'; -* const hash = sha256.create(); -* aoutput(new Uint8Array(hash.outputLen), hash); -* ``` -*/ -function aoutput$2(out, instance) { - abytes$5(out, void 0, "output"); - const min = instance.outputLen; - if (!(out.length >= min)) throw new RangeError("\"output\" expected length >= " + min); -} -/** -* Casts a typed array view to Uint8Array. -* @param arr - source typed array -* @returns Uint8Array view over the same buffer. -* @example -* Reinterpret a typed array as bytes. -* ```ts -* u8(new Uint32Array([1, 2])); -* ``` -*/ -function u8(arr) { - return new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength); -} -/** -* Casts a typed array view to Uint32Array. -* `arr.byteOffset` must already be 4-byte aligned or the platform -* Uint32Array constructor will throw. -* @param arr - source typed array -* @returns Uint32Array view over the same buffer. -* @example -* Reinterpret a byte array as 32-bit words. -* ```ts -* u32(new Uint8Array(8)); -* ``` -*/ -function u32$2(arr) { - return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4)); -} -/** -* Zeroizes typed arrays in place. Warning: JS provides no guarantees. -* @param arrays - arrays to overwrite with zeros -* @example -* Zeroize sensitive buffers in place. -* ```ts -* clean(new Uint8Array([1, 2, 3])); -* ``` -*/ -function clean$2(...arrays) { - for (let i = 0; i < arrays.length; i++) arrays[i].fill(0); -} -/** -* Creates a DataView for byte-level manipulation. -* @param arr - source typed array -* @returns DataView over the same buffer region. -* @example -* Create a DataView over an existing buffer. -* ```ts -* createView(new Uint8Array(4)); -* ``` -*/ -function createView$1(arr) { - return new DataView(arr.buffer, arr.byteOffset, arr.byteLength); -} -/** -* Rotate-right operation for uint32 values. -* @param word - source word -* @param shift - shift amount in bits -* @returns Rotated word. -* @example -* Rotate a 32-bit word to the right. -* ```ts -* rotr(0x12345678, 8); -* ``` -*/ -function rotr(word, shift) { - return word << 32 - shift | word >>> shift; -} -/** -* Rotate-left operation for uint32 values. -* @param word - source word -* @param shift - shift amount in bits -* @returns Rotated word. -* @example -* Rotate a 32-bit word to the left. -* ```ts -* rotl(0x12345678, 8); -* ``` -*/ -function rotl$2(word, shift) { - return word << shift | word >>> 32 - shift >>> 0; -} -/** Whether the current platform is little-endian. */ -const isLE$2 = /* @__PURE__ */ (() => new Uint8Array(new Uint32Array([287454020]).buffer)[0] === 68)(); -/** -* Byte-swap operation for uint32 values. -* @param word - source word -* @returns Word with reversed byte order. -* @example -* Reverse the byte order of a 32-bit word. -* ```ts -* byteSwap(0x11223344); -* ``` -*/ -function byteSwap$2(word) { - return word << 24 & 4278190080 | word << 8 & 16711680 | word >>> 8 & 65280 | word >>> 24 & 255; -} -/** -* Conditionally byte-swaps one 32-bit word on big-endian platforms. -* @param n - source word -* @returns Original or byte-swapped word depending on platform endianness. -* @example -* Normalize a 32-bit word for host endianness. -* ```ts -* swap8IfBE(0x11223344); -* ``` -*/ -const swap8IfBE = isLE$2 ? (n) => n : (n) => byteSwap$2(n) >>> 0; -/** -* Byte-swaps every word of a Uint32Array in place. -* @param arr - array to mutate -* @returns The same array after mutation; callers pass live state arrays here. -* @example -* Reverse the byte order of every word in place. -* ```ts -* byteSwap32(new Uint32Array([0x11223344])); -* ``` -*/ -function byteSwap32$2(arr) { - for (let i = 0; i < arr.length; i++) arr[i] = byteSwap$2(arr[i]); - return arr; -} -/** -* Conditionally byte-swaps a Uint32Array on big-endian platforms. -* @param u - array to normalize for host endianness -* @returns Original or byte-swapped array depending on platform endianness. -* On big-endian runtimes this mutates `u` in place via `byteSwap32(...)`. -* @example -* Normalize a word array for host endianness. -* ```ts -* swap32IfBE(new Uint32Array([0x11223344])); -* ``` -*/ -const swap32IfBE$2 = isLE$2 ? (u) => u : byteSwap32$2; -const hasHexBuiltin = /* @__PURE__ */ (() => typeof Uint8Array.from([]).toHex === "function" && typeof Uint8Array.fromHex === "function")(); -const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0")); -/** -* Convert byte array to hex string. -* Uses the built-in function when available and assumes it matches the tested -* fallback semantics. -* @param bytes - bytes to encode -* @returns Lowercase hexadecimal string. -* @throws On wrong argument types. {@link TypeError} -* @example -* Convert bytes to lowercase hexadecimal. -* ```ts -* bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])); // 'cafe0123' -* ``` -*/ -function bytesToHex$3(bytes) { - abytes$5(bytes); - if (hasHexBuiltin) return bytes.toHex(); - let hex = ""; - for (let i = 0; i < bytes.length; i++) hex += hexes[bytes[i]]; - return hex; -} -function asciiToBase16(ch) { - return ch >= 48 && ch <= 57 ? ch - 48 : ch >= 65 && ch <= 70 ? ch - 55 : ch >= 97 && ch <= 102 ? ch - 87 : void 0; -} -/** -* Convert hex string to byte array. Uses built-in function, when available. -* @param hex - hexadecimal string to decode -* @returns Decoded bytes. -* @throws On wrong argument types. {@link TypeError} -* @throws On wrong argument ranges or values. {@link RangeError} -* @example -* Decode lowercase hexadecimal into bytes. -* ```ts -* hexToBytes('cafe0123'); // Uint8Array.from([0xca, 0xfe, 0x01, 0x23]) -* ``` -*/ -function hexToBytes$2(hex) { - if (typeof hex !== "string") throw new TypeError("hex string expected, got " + typeof hex); - if (hasHexBuiltin) try { - return Uint8Array.fromHex(hex); - } catch (error) { - if (error instanceof SyntaxError) throw new RangeError(error.message); - throw error; - } - const hl = hex.length; - const al = hl / 2; - if (hl % 2) throw new RangeError("hex string expected, got unpadded hex of length " + hl); - const array = new Uint8Array(al); - for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) { - const n1 = asciiToBase16(hex.charCodeAt(hi)); - const n2 = asciiToBase16(hex.charCodeAt(hi + 1)); - if (n1 === void 0 || n2 === void 0) { - const char = hex[hi] + hex[hi + 1]; - throw new RangeError("hex string expected, got non-hex character \"" + char + "\" at index " + hi); - } - array[ai] = n1 * 16 + n2; - } - return array; -} -/** -* Converts string to bytes using UTF8 encoding. -* Built-in doesn't validate input to be string: we do the check. -* Non-ASCII details are delegated to the platform `TextEncoder`. -* @param str - string to encode -* @returns UTF-8 encoded bytes. -* @throws On wrong argument types. {@link TypeError} -* @example -* Encode a string as UTF-8 bytes. -* ```ts -* utf8ToBytes('abc'); // Uint8Array.from([97, 98, 99]) -* ``` -*/ -function utf8ToBytes(str) { - if (typeof str !== "string") throw new TypeError("string expected"); - const encoded = new TextEncoder().encode(str); - try { - return new Uint8Array(encoded); - } finally { - clean$2(encoded); - } -} -/** -* Helper for KDFs: consumes Uint8Array or string. -* String inputs are UTF-8 encoded; byte-array inputs stay aliased to the caller buffer. -* @param data - user-provided KDF input -* @param errorTitle - label included in thrown errors -* @returns Byte representation of the input. -* @throws On wrong argument types. {@link TypeError} -* @example -* Normalize KDF input to bytes. -* ```ts -* kdfInputToBytes('password'); -* ``` -*/ -function kdfInputToBytes(data, errorTitle = "") { - if (typeof data === "string") return utf8ToBytes(data); - return abytes$5(data, void 0, errorTitle); -} -/** -* Copies several Uint8Arrays into one. -* @param arrays - arrays to concatenate -* @returns Concatenated byte array. -* @throws On wrong argument types. {@link TypeError} -* @example -* Concatenate multiple byte arrays. -* ```ts -* concatBytes(new Uint8Array([1]), new Uint8Array([2])); -* ``` -*/ -function concatBytes$3(...arrays) { - let sum = 0; - for (let i = 0; i < arrays.length; i++) { - const a = arrays[i]; - abytes$5(a); - sum += a.length; - } - const res = new Uint8Array(sum); - for (let i = 0, pad = 0; i < arrays.length; i++) { - const a = arrays[i]; - res.set(a, pad); - pad += a.length; - } - return res; -} -/** -* Merges default options and passed options. -* @param defaults - base option object -* @param opts - user overrides -* @param title - label included in thrown override errors -* @returns Fresh merged option object with a null prototype. -* @throws On wrong argument types. {@link TypeError} -* @example -* Merge user overrides onto default options. -* ```ts -* checkOpts({ dkLen: 32 }, { asyncTick: 10 }); -* ``` -*/ -function checkOpts$1(defaults, opts, title = "opts") { - aopts(defaults, "defaults"); - if (opts !== void 0) aopts(opts, title); - return Object.assign(Object.create(null), defaults, opts); -} -/** -* Creates a callable hash function from a stateful class constructor. -* @param hashCons - hash constructor or factory -* @param info - optional metadata such as DER OID -* @returns Frozen callable hash wrapper with `.create()`. -* Wrapper construction eagerly calls `hashCons(undefined)` once to read -* `outputLen` / `blockLen`, so constructor side effects happen at module -* init time. -* @throws On wrong argument types. {@link TypeError} -* @example -* Wrap a stateful hash constructor into a callable helper. -* ```ts -* import { createHasher } from '@noble/hashes/utils.js'; -* import { sha256 } from '@noble/hashes/sha2.js'; -* const wrapped = createHasher(sha256.create, { oid: sha256.oid }); -* wrapped(new Uint8Array([1])); -* ``` -*/ -function createHasher$1(hashCons, info = {}) { - if (typeof hashCons !== "function") throw new TypeError("\"hashCons\" expected function, got type=" + typeof hashCons); - info = checkOpts$1({}, info, "info"); - const hashC = (msg, opts) => hashCons(opts).update(msg).digest(); - const tmp = hashCons(void 0); - hashC.outputLen = tmp.outputLen; - hashC.blockLen = tmp.blockLen; - hashC.canXOF = tmp.canXOF; - hashC.create = (opts) => hashCons(opts); - Object.assign(hashC, info); - return Object.freeze(hashC); -} -/** -* Cryptographically secure PRNG backed by `crypto.getRandomValues`. -* @param bytesLength - number of random bytes to generate -* @returns Random bytes. -* The platform `getRandomValues()` implementation still defines any -* single-call length cap, and this helper rejects oversize requests -* with a stable library `RangeError` instead of host-specific errors. -* @throws On wrong argument types. {@link TypeError} -* @throws On wrong argument ranges or values. {@link RangeError} -* @throws If the current runtime does not provide `crypto.getRandomValues`. {@link Error} -* @example -* Generate a fresh random key or nonce. -* ```ts -* const key = randomBytes(16); -* ``` -*/ -function randomBytes$3(bytesLength = 32) { - anumber$4(bytesLength, "bytesLength"); - const cr = typeof globalThis === "object" ? globalThis.crypto : null; - if (typeof cr?.getRandomValues !== "function") throw new Error("crypto.getRandomValues must be defined"); - if (bytesLength > 65536) throw new RangeError(`"bytesLength" expected <= 65536, got ${bytesLength}`); - return cr.getRandomValues(new Uint8Array(bytesLength)); -} -/** -* Creates OID metadata for NIST hashes with prefix `06 09 60 86 48 01 65 03 04 02`. -* @param suffix - final OID byte for the selected hash. -* The helper accepts any byte even though only the documented NIST hash -* suffixes are meaningful downstream. -* @returns Object containing the DER-encoded OID. -* @example -* Build OID metadata for a NIST hash. -* ```ts -* oidNist(0x01); -* ``` -*/ -const oidNist$1 = (suffix) => ({ oid: Uint8Array.from([ - 6, - 9, - 96, - 134, - 72, - 1, - 101, - 3, - 4, - 2, - suffix -]) }); -//#endregion -//#region tests/baseline/node_modules/@noble/hashes/_md.js -/** -* Internal Merkle-Damgard hash utils. -* @module -*/ -/** -* Shared 32-bit conditional boolean primitive reused by SHA-256, SHA-1, and MD5 `F`. -* Returns bits from `b` when `a` is set, otherwise from `c`. -* The XOR form is equivalent to MD5's `F(X,Y,Z) = XY v not(X)Z` because the masked terms never -* set the same bit. -* @param a - selector word -* @param b - word chosen when selector bit is set -* @param c - word chosen when selector bit is clear -* @returns Mixed 32-bit word. -* @example -* Combine three words with the shared 32-bit choice primitive. -* ```ts -* Chi(0xffffffff, 0x12345678, 0x87654321); -* ``` -*/ -function Chi(a, b, c) { - return a & b ^ ~a & c; -} -/** -* Shared 32-bit majority primitive reused by SHA-256 and SHA-1. -* Returns bits shared by at least two inputs. -* @param a - first input word -* @param b - second input word -* @param c - third input word -* @returns Mixed 32-bit word. -* @example -* Combine three words with the shared 32-bit majority primitive. -* ```ts -* Maj(0xffffffff, 0x12345678, 0x87654321); -* ``` -*/ -function Maj(a, b, c) { - return a & b ^ a & c ^ b & c; -} -/** -* Merkle-Damgard hash construction base class. -* Could be used to create MD5, RIPEMD, SHA1, SHA2. -* Accepts only byte-aligned `Uint8Array` input, even when the underlying spec describes bit -* strings with partial-byte tails. -* @param blockLen - internal block size in bytes -* @param outputLen - digest size in bytes -* @param padOffset - trailing length field size in bytes -* @param isLE - whether length and state words are encoded in little-endian -* @example -* Use a concrete subclass to get the shared Merkle-Damgard update/digest flow. -* ```ts -* import { _SHA1 } from '@noble/hashes/legacy.js'; -* const hash = new _SHA1(); -* hash.update(new Uint8Array([97, 98, 99])); -* hash.digest(); -* ``` -*/ -var HashMD = class { - blockLen; - outputLen; - canXOF = false; - padOffset; - isLE; - buffer; - view; - finished = false; - length = 0; - pos = 0; - destroyed = false; - constructor(blockLen, outputLen, padOffset, isLE) { - this.blockLen = blockLen; - this.outputLen = outputLen; - this.padOffset = padOffset; - this.isLE = isLE; - this.buffer = new Uint8Array(blockLen); - this.view = createView$1(this.buffer); - } - update(data) { - aexists$2(this); - abytes$5(data); - const { view, buffer, blockLen } = this; - const len = data.length; - let processed = false; - for (let pos = 0; pos < len;) { - const take = Math.min(blockLen - this.pos, len - pos); - if (take === blockLen) { - const dataView = createView$1(data); - for (; blockLen <= len - pos; pos += blockLen) this.process(dataView, pos); - processed = true; - continue; - } - buffer.set(pos === 0 && take === len ? data : data.subarray(pos, pos + take), this.pos); - this.pos += take; - pos += take; - if (this.pos === blockLen) { - this.process(view, 0); - this.pos = 0; - processed = true; - } - } - this.length += data.length; - if (processed) this.roundClean(); - return this; - } - digestInto(out) { - aexists$2(this); - aoutput$2(out, this); - this.finished = true; - const { buffer, view, blockLen, isLE } = this; - let { pos } = this; - buffer[pos++] = 128; - buffer.fill(0, pos); - if (this.padOffset > blockLen - pos) { - this.process(view, 0); - buffer.fill(0); - } - setU64FromNum(view, blockLen - 8, this.length * 8, isLE); - this.process(view, 0); - this.roundClean(); - const oview = out === buffer ? view : createView$1(out); - const len = this.outputLen; - const outLen = len / 4; - const state = this.get(); - if (len % 4 || outLen > state.length) throw new Error("invalid outputLen"); - for (let i = 0; i < outLen; i++) oview.setUint32(4 * i, state[i], isLE); - } - digest() { - const { buffer, outputLen } = this; - this.digestInto(buffer); - const res = buffer.slice(0, outputLen); - this.destroy(); - return res; - } - _cloneIntoMeta(to) { - const { buffer, length, finished, destroyed, pos } = this; - to.destroyed = destroyed; - to.finished = finished; - to.length = length; - to.pos = pos; - if (pos) to.buffer.set(buffer); - return to; - } - clone() { - return this._cloneInto(); - } -}; -/** -* Initial SHA-2 state: fractional parts of square roots of first 16 primes 2..53. -* Check out `test/misc/sha2-gen-iv.js` for recomputation guide. -*/ -/** Initial SHA256 state from RFC 6234 §6.1: the first 32 bits of the fractional parts of the -* square roots of the first eight prime numbers. Exported as a shared table; callers must treat -* it as read-only because constructors copy words from it by index. */ -const SHA256_IV = /* @__PURE__ */ Uint32Array.from([ - 1779033703, - 3144134277, - 1013904242, - 2773480762, - 1359893119, - 2600822924, - 528734635, - 1541459225 -]); -/** Initial SHA384 state from RFC 6234 §6.3: eight RFC 64-bit `H(0)` words stored as sixteen -* big-endian 32-bit halves. Derived from the fractional parts of the square roots of the ninth -* through sixteenth prime numbers. Exported as a shared table; callers must treat it as read-only -* because constructors copy halves from it by index. */ -const SHA384_IV = /* @__PURE__ */ Uint32Array.from([ - 3418070365, - 3238371032, - 1654270250, - 914150663, - 2438529370, - 812702999, - 355462360, - 4144912697, - 1731405415, - 4290775857, - 2394180231, - 1750603025, - 3675008525, - 1694076839, - 1203062813, - 3204075428 -]); -/** Initial SHA512 state from RFC 6234 §6.3: eight RFC 64-bit `H(0)` words stored as sixteen -* big-endian 32-bit halves. Derived from the fractional parts of the square roots of the first -* eight prime numbers. Exported as a shared table; callers must treat it as read-only because -* constructors copy halves from it by index. */ -const SHA512_IV = /* @__PURE__ */ Uint32Array.from([ - 1779033703, - 4089235720, - 3144134277, - 2227873595, - 1013904242, - 4271175723, - 2773480762, - 1595750129, - 1359893119, - 2917565137, - 2600822924, - 725511199, - 528734635, - 4215389547, - 1541459225, - 327033209 -]); -//#endregion -//#region tests/baseline/node_modules/@noble/hashes/sha2.js -/** -* SHA2 hash function. A.k.a. sha256, sha384, sha512, sha512_224, sha512_256. -* SHA256 is the fastest hash implementable in JS, even faster than Blake3. -* Check out {@link https://www.rfc-editor.org/rfc/rfc4634 | RFC 4634} and -* {@link https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf | FIPS 180-4}. -* @module -*/ -/** -* SHA-224 / SHA-256 round constants from RFC 6234 §5.1: the first 32 bits -* of the cube roots of the first 64 primes (2..311). -*/ -const SHA256_K = /* @__PURE__ */ Uint32Array.from([ - 1116352408, - 1899447441, - 3049323471, - 3921009573, - 961987163, - 1508970993, - 2453635748, - 2870763221, - 3624381080, - 310598401, - 607225278, - 1426881987, - 1925078388, - 2162078206, - 2614888103, - 3248222580, - 3835390401, - 4022224774, - 264347078, - 604807628, - 770255983, - 1249150122, - 1555081692, - 1996064986, - 2554220882, - 2821834349, - 2952996808, - 3210313671, - 3336571891, - 3584528711, - 113926993, - 338241895, - 666307205, - 773529912, - 1294757372, - 1396182291, - 1695183700, - 1986661051, - 2177026350, - 2456956037, - 2730485921, - 2820302411, - 3259730800, - 3345764771, - 3516065817, - 3600352804, - 4094571909, - 275423344, - 430227734, - 506948616, - 659060556, - 883997877, - 958139571, - 1322822218, - 1537002063, - 1747873779, - 1955562222, - 2024104815, - 2227730452, - 2361852424, - 2428436474, - 2756734187, - 3204031479, - 3329325298 -]); -/** Reusable SHA-224 / SHA-256 message schedule buffer `W_t` from RFC 6234 §6.2 step 1. */ -const SHA256_W = /* @__PURE__ */ new Uint32Array(64); -/** Internal SHA-224 / SHA-256 compression engine from RFC 6234 §6.2. */ -var SHA2_32B = class extends HashMD { - A = 0; - B = 0; - C = 0; - D = 0; - E = 0; - F = 0; - G = 0; - H = 0; - constructor(outputLen, IV) { - super(64, outputLen, 8, false); - this.A = IV[0] | 0; - this.B = IV[1] | 0; - this.C = IV[2] | 0; - this.D = IV[3] | 0; - this.E = IV[4] | 0; - this.F = IV[5] | 0; - this.G = IV[6] | 0; - this.H = IV[7] | 0; - } - get() { - const { A, B, C, D, E, F, G, H } = this; - return [ - A, - B, - C, - D, - E, - F, - G, - H - ]; - } - set(A, B, C, D, E, F, G, H) { - this.A = A | 0; - this.B = B | 0; - this.C = C | 0; - this.D = D | 0; - this.E = E | 0; - this.F = F | 0; - this.G = G | 0; - this.H = H | 0; - } - _cloneInto(to) { - (to ||= new this.constructor()).set(...this.get()); - return this._cloneIntoMeta(to); - } - process(view, offset) { - for (let i = 0; i < 16; i++, offset += 4) SHA256_W[i] = view.getUint32(offset, false); - for (let i = 16; i < 64; i++) { - const W15 = SHA256_W[i - 15]; - const W2 = SHA256_W[i - 2]; - const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ W15 >>> 3; - const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ W2 >>> 10; - SHA256_W[i] = s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16] | 0; - } - let { A, B, C, D, E, F, G, H } = this; - for (let i = 0; i < 64; i++) { - const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25); - const T1 = H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i] | 0; - const T2 = (rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22)) + Maj(A, B, C) | 0; - H = G; - G = F; - F = E; - E = D + T1 | 0; - D = C; - C = B; - B = A; - A = T1 + T2 | 0; - } - A = A + this.A | 0; - B = B + this.B | 0; - C = C + this.C | 0; - D = D + this.D | 0; - E = E + this.E | 0; - F = F + this.F | 0; - G = G + this.G | 0; - H = H + this.H | 0; - this.set(A, B, C, D, E, F, G, H); - } - roundClean() { - clean$2(SHA256_W); - } - destroy() { - this.destroyed = true; - this.set(0, 0, 0, 0, 0, 0, 0, 0); - clean$2(this.buffer); - } -}; -/** Internal SHA-256 hash class grounded in RFC 6234 §6.2. */ -var _SHA256 = class extends SHA2_32B { - constructor() { - super(32, SHA256_IV); - } -}; -const K512 = /* @__PURE__ */ (() => split$1([ - "0x428a2f98d728ae22", - "0x7137449123ef65cd", - "0xb5c0fbcfec4d3b2f", - "0xe9b5dba58189dbbc", - "0x3956c25bf348b538", - "0x59f111f1b605d019", - "0x923f82a4af194f9b", - "0xab1c5ed5da6d8118", - "0xd807aa98a3030242", - "0x12835b0145706fbe", - "0x243185be4ee4b28c", - "0x550c7dc3d5ffb4e2", - "0x72be5d74f27b896f", - "0x80deb1fe3b1696b1", - "0x9bdc06a725c71235", - "0xc19bf174cf692694", - "0xe49b69c19ef14ad2", - "0xefbe4786384f25e3", - "0x0fc19dc68b8cd5b5", - "0x240ca1cc77ac9c65", - "0x2de92c6f592b0275", - "0x4a7484aa6ea6e483", - "0x5cb0a9dcbd41fbd4", - "0x76f988da831153b5", - "0x983e5152ee66dfab", - "0xa831c66d2db43210", - "0xb00327c898fb213f", - "0xbf597fc7beef0ee4", - "0xc6e00bf33da88fc2", - "0xd5a79147930aa725", - "0x06ca6351e003826f", - "0x142929670a0e6e70", - "0x27b70a8546d22ffc", - "0x2e1b21385c26c926", - "0x4d2c6dfc5ac42aed", - "0x53380d139d95b3df", - "0x650a73548baf63de", - "0x766a0abb3c77b2a8", - "0x81c2c92e47edaee6", - "0x92722c851482353b", - "0xa2bfe8a14cf10364", - "0xa81a664bbc423001", - "0xc24b8b70d0f89791", - "0xc76c51a30654be30", - "0xd192e819d6ef5218", - "0xd69906245565a910", - "0xf40e35855771202a", - "0x106aa07032bbd1b8", - "0x19a4c116b8d2d0c8", - "0x1e376c085141ab53", - "0x2748774cdf8eeb99", - "0x34b0bcb5e19b48a8", - "0x391c0cb3c5c95a63", - "0x4ed8aa4ae3418acb", - "0x5b9cca4f7763e373", - "0x682e6ff3d6b2b8a3", - "0x748f82ee5defb2fc", - "0x78a5636f43172f60", - "0x84c87814a1f0ab72", - "0x8cc702081a6439ec", - "0x90befffa23631e28", - "0xa4506cebde82bde9", - "0xbef9a3f7b2c67915", - "0xc67178f2e372532b", - "0xca273eceea26619c", - "0xd186b8c721c0c207", - "0xeada7dd6cde0eb1e", - "0xf57d4f7fee6ed178", - "0x06f067aa72176fba", - "0x0a637dc5a2c898a6", - "0x113f9804bef90dae", - "0x1b710b35131c471b", - "0x28db77f523047d84", - "0x32caab7b40c72493", - "0x3c9ebe0a15c9bebc", - "0x431d67c49c100d4c", - "0x4cc5d4becb3e42b6", - "0x597f299cfc657e2a", - "0x5fcb6fab3ad6faec", - "0x6c44198c4a475817" -].map((n) => BigInt(n))))(); -const SHA512_Kh = /* @__PURE__ */ (() => K512[0])(); -const SHA512_Kl = /* @__PURE__ */ (() => K512[1])(); -const SHA512_W_H = /* @__PURE__ */ new Uint32Array(80); -const SHA512_W_L = /* @__PURE__ */ new Uint32Array(80); -/** Internal SHA-384 / SHA-512 compression engine from RFC 6234 §6.4. */ -var SHA2_64B = class extends HashMD { - Ah = 0; - Al = 0; - Bh = 0; - Bl = 0; - Ch = 0; - Cl = 0; - Dh = 0; - Dl = 0; - Eh = 0; - El = 0; - Fh = 0; - Fl = 0; - Gh = 0; - Gl = 0; - Hh = 0; - Hl = 0; - constructor(outputLen, IV) { - super(128, outputLen, 16, false); - this.Ah = IV[0] | 0; - this.Al = IV[1] | 0; - this.Bh = IV[2] | 0; - this.Bl = IV[3] | 0; - this.Ch = IV[4] | 0; - this.Cl = IV[5] | 0; - this.Dh = IV[6] | 0; - this.Dl = IV[7] | 0; - this.Eh = IV[8] | 0; - this.El = IV[9] | 0; - this.Fh = IV[10] | 0; - this.Fl = IV[11] | 0; - this.Gh = IV[12] | 0; - this.Gl = IV[13] | 0; - this.Hh = IV[14] | 0; - this.Hl = IV[15] | 0; - } - get() { - const { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this; - return [ - Ah, - Al, - Bh, - Bl, - Ch, - Cl, - Dh, - Dl, - Eh, - El, - Fh, - Fl, - Gh, - Gl, - Hh, - Hl - ]; - } - set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl) { - this.Ah = Ah | 0; - this.Al = Al | 0; - this.Bh = Bh | 0; - this.Bl = Bl | 0; - this.Ch = Ch | 0; - this.Cl = Cl | 0; - this.Dh = Dh | 0; - this.Dl = Dl | 0; - this.Eh = Eh | 0; - this.El = El | 0; - this.Fh = Fh | 0; - this.Fl = Fl | 0; - this.Gh = Gh | 0; - this.Gl = Gl | 0; - this.Hh = Hh | 0; - this.Hl = Hl | 0; - } - _cloneInto(to) { - (to ||= new this.constructor()).set(...this.get()); - return this._cloneIntoMeta(to); - } - process(view, offset) { - for (let i = 0; i < 16; i++, offset += 4) { - SHA512_W_H[i] = view.getUint32(offset); - SHA512_W_L[i] = view.getUint32(offset += 4); - } - for (let i = 16; i < 80; i++) { - const W15h = SHA512_W_H[i - 15] | 0; - const W15l = SHA512_W_L[i - 15] | 0; - const s0h = rotrSH(W15h, W15l, 1) ^ rotrSH(W15h, W15l, 8) ^ shrSH(W15h, W15l, 7); - const s0l = rotrSL(W15h, W15l, 1) ^ rotrSL(W15h, W15l, 8) ^ shrSL(W15h, W15l, 7); - const W2h = SHA512_W_H[i - 2] | 0; - const W2l = SHA512_W_L[i - 2] | 0; - const s1h = rotrSH(W2h, W2l, 19) ^ rotrBH(W2h, W2l, 61) ^ shrSH(W2h, W2l, 6); - const s1l = rotrSL(W2h, W2l, 19) ^ rotrBL(W2h, W2l, 61) ^ shrSL(W2h, W2l, 6); - const SUMl = add4L(s0l, s1l, SHA512_W_L[i - 7], SHA512_W_L[i - 16]); - const SUMh = add4H(SUMl, s0h, s1h, SHA512_W_H[i - 7], SHA512_W_H[i - 16]); - SHA512_W_H[i] = SUMh | 0; - SHA512_W_L[i] = SUMl | 0; - } - let { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this; - for (let i = 0; i < 80; i++) { - const sigma1h = rotrSH(Eh, El, 14) ^ rotrSH(Eh, El, 18) ^ rotrBH(Eh, El, 41); - const sigma1l = rotrSL(Eh, El, 14) ^ rotrSL(Eh, El, 18) ^ rotrBL(Eh, El, 41); - const CHIh = Eh & Fh ^ ~Eh & Gh; - const CHIl = El & Fl ^ ~El & Gl; - const T1ll = add5L(Hl, sigma1l, CHIl, SHA512_Kl[i], SHA512_W_L[i]); - const T1h = add5H(T1ll, Hh, sigma1h, CHIh, SHA512_Kh[i], SHA512_W_H[i]); - const T1l = T1ll | 0; - const sigma0h = rotrSH(Ah, Al, 28) ^ rotrBH(Ah, Al, 34) ^ rotrBH(Ah, Al, 39); - const sigma0l = rotrSL(Ah, Al, 28) ^ rotrBL(Ah, Al, 34) ^ rotrBL(Ah, Al, 39); - const MAJh = Ah & Bh ^ Ah & Ch ^ Bh & Ch; - const MAJl = Al & Bl ^ Al & Cl ^ Bl & Cl; - Hh = Gh | 0; - Hl = Gl | 0; - Gh = Fh | 0; - Gl = Fl | 0; - Fh = Eh | 0; - Fl = El | 0; - ({h: Eh, l: El} = add(Dh | 0, Dl | 0, T1h | 0, T1l | 0)); - Dh = Ch | 0; - Dl = Cl | 0; - Ch = Bh | 0; - Cl = Bl | 0; - Bh = Ah | 0; - Bl = Al | 0; - const All = add3L(T1l, sigma0l, MAJl); - Ah = add3H(All, T1h, sigma0h, MAJh); - Al = All | 0; - } - ({h: Ah, l: Al} = add(this.Ah | 0, this.Al | 0, Ah | 0, Al | 0)); - ({h: Bh, l: Bl} = add(this.Bh | 0, this.Bl | 0, Bh | 0, Bl | 0)); - ({h: Ch, l: Cl} = add(this.Ch | 0, this.Cl | 0, Ch | 0, Cl | 0)); - ({h: Dh, l: Dl} = add(this.Dh | 0, this.Dl | 0, Dh | 0, Dl | 0)); - ({h: Eh, l: El} = add(this.Eh | 0, this.El | 0, Eh | 0, El | 0)); - ({h: Fh, l: Fl} = add(this.Fh | 0, this.Fl | 0, Fh | 0, Fl | 0)); - ({h: Gh, l: Gl} = add(this.Gh | 0, this.Gl | 0, Gh | 0, Gl | 0)); - ({h: Hh, l: Hl} = add(this.Hh | 0, this.Hl | 0, Hh | 0, Hl | 0)); - this.set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl); - } - roundClean() { - clean$2(SHA512_W_H, SHA512_W_L); - } - destroy() { - this.destroyed = true; - clean$2(this.buffer); - this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - } -}; -/** Internal SHA-512 hash class grounded in RFC 6234 §6.3 and §6.4. */ -var _SHA512 = class extends SHA2_64B { - constructor() { - super(64, SHA512_IV); - } -}; -/** Internal SHA-384 hash class grounded in RFC 6234 §6.3 and §6.4. */ -var _SHA384 = class extends SHA2_64B { - constructor() { - super(48, SHA384_IV); - } -}; -/** -* SHA2-256 hash function from RFC 4634. In JS it's the fastest: even faster than Blake3. Some info: -* -* - Trying 2^128 hashes would get 50% chance of collision, using birthday attack. -* - BTC network is doing 2^70 hashes/sec (2^95 hashes/year) as per 2025. -* - Each sha256 hash is executing 2^18 bit operations. -* - Good 2024 ASICs can do 200Th/sec with 3500 watts of power, corresponding to 2^36 hashes/joule. -* @param msg - message bytes to hash -* @param opts - Reserved hash options. -* @returns Digest bytes. -* @example -* Hash a message with SHA2-256. -* ```ts -* sha256(new Uint8Array([97, 98, 99])); -* ``` -*/ -const sha256$2 = /* @__PURE__ */ createHasher$1(() => new _SHA256(), /* @__PURE__ */ oidNist$1(1)); -/** -* SHA2-512 hash function from RFC 4634. -* @param msg - message bytes to hash -* @param opts - Reserved hash options. -* @returns Digest bytes. -* @example -* Hash a message with SHA2-512. -* ```ts -* sha512(new Uint8Array([97, 98, 99])); -* ``` -*/ -const sha512$1 = /* @__PURE__ */ createHasher$1(() => new _SHA512(), /* @__PURE__ */ oidNist$1(3)); -/** -* SHA2-384 hash function from RFC 4634. -* @param msg - message bytes to hash -* @param opts - Reserved hash options. -* @returns Digest bytes. -* @example -* Hash a message with SHA2-384. -* ```ts -* sha384(new Uint8Array([97, 98, 99])); -* ``` -*/ -const sha384 = /* @__PURE__ */ createHasher$1(() => new _SHA384(), /* @__PURE__ */ oidNist$1(2)); -//#endregion -//#region tests/baseline/node_modules/@noble/hashes/hmac.js -/** -* HMAC: RFC2104 message authentication code. -* @module -*/ -/** -* Internal class for HMAC. -* Accepts any byte key, although RFC 2104 §3 recommends keys at least -* `HashLen` bytes long. -*/ -var _HMAC = class { - oHash; - iHash; - blockLen; - outputLen; - canXOF = false; - finished = false; - destroyed = false; - constructor(hash, key) { - ahash(hash); - abytes$5(key, void 0, "key"); - this.iHash = hash.create(); - if (typeof this.iHash.update !== "function") throw new Error("expected Hash instance"); - this.blockLen = this.iHash.blockLen; - this.outputLen = this.iHash.outputLen; - const blockLen = this.blockLen; - const pad = new Uint8Array(blockLen); - pad.set(key.length > blockLen ? hash.create().update(key).digest() : key); - for (let i = 0; i < pad.length; i++) pad[i] ^= 54; - this.iHash.update(pad); - this.oHash = hash.create(); - for (let i = 0; i < pad.length; i++) pad[i] ^= 106; - this.oHash.update(pad); - clean$2(pad); - } - update(buf) { - aexists$2(this); - this.iHash.update(buf); - return this; - } - digestInto(out) { - aexists$2(this); - aoutput$2(out, this); - this.finished = true; - const buf = out.subarray(0, this.outputLen); - this.iHash.digestInto(buf); - this.oHash.update(buf); - this.oHash.digestInto(buf); - this.destroy(); - } - digest() { - const out = new Uint8Array(this.oHash.outputLen); - this.digestInto(out); - return out; - } - _cloneInto(to) { - to ||= Object.create(Object.getPrototypeOf(this), {}); - const { oHash, iHash, finished, destroyed, blockLen, outputLen, canXOF } = this; - to = to; - to.finished = finished; - to.destroyed = destroyed; - to.blockLen = blockLen; - to.outputLen = outputLen; - to.canXOF = canXOF; - to.oHash = oHash._cloneInto(to.oHash); - to.iHash = iHash._cloneInto(to.iHash); - return to; - } - clone() { - return this._cloneInto(); - } - destroy() { - this.destroyed = true; - this.oHash.destroy(); - this.iHash.destroy(); - } -}; -const hmac = /* @__PURE__ */ (() => { - const hmac_ = ((hash, key, message) => new _HMAC(hash, key).update(message).digest()); - hmac_.create = (hash, key) => new _HMAC(hash, key); - return hmac_; -})(); -//#endregion -//#region tests/baseline/node_modules/@noble/hashes/pbkdf2.js -/** -* PBKDF (RFC 2898). Can be used to create a key from password and salt. -* @module -*/ -function pbkdf2Init(hash, _password, _salt, _opts) { - ahash(hash); - const { c, dkLen, asyncTick } = checkOpts$1({ - dkLen: 32, - asyncTick: 10 - }, _opts); - anumber$4(c, "c"); - anumber$4(dkLen, "dkLen"); - anumber$4(asyncTick, "asyncTick"); - if (c < 1) throw new Error("\"c\" (iterations) must be >= 1"); - if (dkLen < 1) throw new Error("\"dkLen\" must be >= 1"); - if (dkLen > (2 ** 32 - 1) * hash.outputLen) throw new Error("derived key too long"); - const p = kdfInputToBytes(_password, "password"); - try { - const s = kdfInputToBytes(_salt, "salt"); - try { - const DK = new Uint8Array(dkLen); - const { iHash, oHash, outputLen } = hmac.create(hash, p); - return { - c, - dkLen, - asyncTick, - DK, - outputLen, - eng: pbkdf2Engine(iHash, oHash, s, new Uint8Array(outputLen)) - }; - } finally { - if (typeof _salt === "string") clean$2(s); - } - } finally { - if (typeof _password === "string") clean$2(p); - } -} -function pbkdf2Engine(iHash, oHash, salt, u) { - const counter = /* @__PURE__ */ new Uint8Array(4); - const view = createView$1(counter); - const salted = iHash._cloneInto().update(salt); - const work = oHash._cloneInto(); - const iClone = iHash._cloneInto; - const oClone = oHash._cloneInto; - return { - u1: (ti, Ti) => { - view.setInt32(0, ti, false); - salted._cloneInto(work).update(counter).digestInto(u); - oHash._cloneInto(work).update(u).digestInto(u); - Ti.set(u.subarray(0, Ti.length)); - }, - rounds: (c, Ti) => { - for (let ui = 1; ui < c; ui++) { - iClone.call(iHash, work).update(u).digestInto(u); - oClone.call(oHash, work).update(u).digestInto(u); - for (let i = 0; i < Ti.length; i++) Ti[i] ^= u[i]; - } - }, - output: (DK) => { - iHash.destroy(); - oHash.destroy(); - salted.destroy(); - work.destroy(); - clean$2(u); - return DK; - } - }; -} -/** -* PBKDF2-HMAC: RFC 8018 key derivation function. -* @param hash - hash function that would be used e.g. sha256 -* @param password - password from which a derived key is generated; -* JS string inputs are UTF-8 encoded first -* @param salt - cryptographic salt; JS string inputs are UTF-8 encoded first -* @param opts - PBKDF2 work factor and output settings. `dkLen`, if provided, -* must be `>= 1` per RFC 8018 §5.2. See {@link Pbkdf2Opt}. -* @returns Derived key bytes. -* @throws If the PBKDF2 iteration count or derived-key settings are invalid. {@link Error} -* @example -* PBKDF2-HMAC: RFC 2898 key derivation function. -* ```ts -* import { pbkdf2 } from '@noble/hashes/pbkdf2.js'; -* import { sha256 } from '@noble/hashes/sha2.js'; -* const key = pbkdf2(sha256, 'password', 'salt', { dkLen: 32, c: Math.pow(2, 18) }); -* ``` -*/ -function pbkdf2(hash, password, salt, opts) { - const { c, dkLen, DK, outputLen, eng } = pbkdf2Init(hash, password, salt, opts); - for (let ti = 1, pos = 0; pos < dkLen; ti++, pos += outputLen) { - const Ti = DK.subarray(pos, pos + outputLen); - eng.u1(ti, Ti); - eng.rounds(c, Ti); - } - return eng.output(DK); -} -//#endregion -//#region tests/baseline/node_modules/@noble/hashes/hkdf.js -/** -* HKDF (RFC 5869): extract + expand in one step. -* See {@link https://soatok.blog/2021/11/17/understanding-hkdf/}. -* @module -*/ -const HKDF_COUNTER = /* @__PURE__ */ Uint8Array.of(0); -const EMPTY_BUFFER = /* @__PURE__ */ Uint8Array.of(); -/** -* HKDF-expand from the spec. The most important part. `HKDF-Expand(PRK, info, L) -> OKM` -* @param hash - hash function that would be used (e.g. sha256) -* @param prk - a pseudorandom key of at least HashLen octets -* (usually, the output from the extract step) -* @param info - optional context and application specific information (can be a zero-length string) -* @param length - length of output keying material in bytes. -* RFC 5869 §2.3 allows `0..255*HashLen`, so `0` returns an empty OKM. -* @param _recycled - Internal destroyed extract hashes owned by the combined `hkdf()` call. -* @returns Output keying material with the requested length. -* @throws If the requested output length exceeds the HKDF limit -* for the selected hash. {@link Error} -* @example -* Run the HKDF expand step. -* ```ts -* import { expand } from '@noble/hashes/hkdf.js'; -* import { sha256 } from '@noble/hashes/sha2.js'; -* expand(sha256, new Uint8Array(32), new Uint8Array([1, 2, 3]), 16); -* ``` -*/ -function expand(hash, prk, info, length = 32, _recycled) { - ahash(hash); - anumber$4(length, "length"); - abytes$5(prk, void 0, "prk"); - const olen = hash.outputLen; - if (prk.length < olen) throw new Error("\"prk\" must be at least HashLen octets"); - if (length > 255 * olen) throw new Error("Length must be <= 255*HashLen"); - const blocks = Math.ceil(length / olen); - if (info === void 0) info = EMPTY_BUFFER; - else abytes$5(info, void 0, "info"); - if (!blocks) { - if (_recycled) clean$2(prk); - return /* @__PURE__ */ new Uint8Array(); - } - const okm = _recycled && blocks === 1 ? prk : new Uint8Array(blocks * olen); - const { iHash, oHash } = hmac.create(hash, prk); - const T = _recycled ? prk : new Uint8Array(olen); - const worker = blocks > 1 ? _recycled?.iHash || hash.create() : void 0; - for (let counter = 0; counter < blocks - 1; counter++) { - HKDF_COUNTER[0] = counter + 1; - const iWork = iHash._cloneInto(worker); - if (counter) iWork.update(T); - iWork.update(info).update(HKDF_COUNTER).digestInto(T); - oHash._cloneInto(worker).update(T).digestInto(T); - okm.set(T, olen * counter); - } - HKDF_COUNTER[0] = blocks; - if (blocks > 1) iHash.update(T); - iHash.update(info).update(HKDF_COUNTER).digestInto(T); - oHash.update(T).digestInto(T); - okm.set(T, olen * (blocks - 1)); - iHash.destroy(); - oHash.destroy(); - worker?.destroy(); - if (T !== okm) clean$2(T); - clean$2(HKDF_COUNTER); - if (length === okm.length) return okm; - const res = okm.slice(0, length); - clean$2(okm); - return res; -} -/** -* HKDF (RFC 5869): derive keys from an initial input. -* Combines hkdf_extract + hkdf_expand in one step -* @param hash - hash function that would be used (e.g. sha256) -* @param ikm - input keying material, the initial key -* @param salt - optional salt value (a non-secret random value) -* @param info - optional context and application specific information bytes -* @param length - length of output keying material in bytes. -* RFC 5869 §2.3 allows `0..255*HashLen`, so `0` returns an empty OKM. -* @returns Output keying material derived from the input key. -* @throws If the requested output length exceeds the HKDF limit -* for the selected hash. {@link Error} -* @example -* HKDF (RFC 5869): derive keys from an initial input. -* ```ts -* import { hkdf } from '@noble/hashes/hkdf.js'; -* import { sha256 } from '@noble/hashes/sha2.js'; -* import { randomBytes, utf8ToBytes } from '@noble/hashes/utils.js'; -* const inputKey = randomBytes(32); -* const salt = randomBytes(32); -* const info = utf8ToBytes('application-key'); -* const okm = hkdf(sha256, inputKey, salt, info, 32); -* ``` -*/ -const hkdf = (hash, ikm, salt, info, length) => { - ahash(hash); - if (salt === void 0) salt = new Uint8Array(hash.outputLen); - const HMAC = hmac.create(hash, salt).update(ikm); - return expand(hash, HMAC.digest(), info, length, HMAC); -}; -//#endregion -//#region tests/baseline/node_modules/@noble/ciphers/utils.js -/*! noble-ciphers - MIT License (c) 2023 Paul Miller (paulmillr.com) */ -/** -* Checks if something is Uint8Array. Be careful: nodejs Buffer will return true. -* @param a - Value to inspect. -* @returns `true` when the value is a Uint8Array view, including Node's `Buffer`. -* @example -* Guards a value before treating it as raw key material. -* -* ```ts -* isBytes(new Uint8Array()); -* ``` -*/ -function isBytes$3(a) { - return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array" && "BYTES_PER_ELEMENT" in a && a.BYTES_PER_ELEMENT === 1; -} -const atitle$1 = (title) => title ? `"${title}" ` : ""; -/** -* Asserts something is boolean. -* @param value - Value to validate. -* @returns The validated boolean. -* @throws On wrong argument types. {@link TypeError} -* @example -* Validates a boolean option before branching on it. -* -* ```ts -* abool(true); -* ``` -*/ -function abool$2(value, title = "") { - if (typeof value !== "boolean") throw new TypeError(atitle$1(title) + "expected boolean, got type=" + typeof value); - return value; -} -/** -* Asserts something is a non-negative safe integer. -* @param n - Value to validate. -* @returns The validated number. -* @throws On wrong argument types. {@link TypeError} -* @throws On wrong argument ranges or values. {@link RangeError} -* @example -* Validates a non-negative length or counter. -* -* ```ts -* anumber(1); -* ``` -*/ -function anumber$3(n, title = "") { - if (typeof n !== "number") throw new TypeError(atitle$1(title) + "expected number, got " + typeof n); - if (!Number.isSafeInteger(n) || n < 0) throw new RangeError(atitle$1(title) + "expected integer >= 0, got " + n); - return n; -} -/** -* Asserts something is Uint8Array. -* @param value - Value to validate. -* @param length - Expected byte length. -* @param title - Optional label used in error messages. -* @returns The validated byte array. -* On Node, `Buffer` is accepted too because it is a Uint8Array view. -* @throws On wrong argument types. {@link TypeError} -* @throws On wrong argument lengths. {@link RangeError} -* @example -* Validates a fixed-length nonce or key buffer. -* -* ```ts -* abytes(new Uint8Array([1, 2]), 2); -* ``` -*/ -function abytes$4(value, length, title = "") { - if (isBytes$3(value) && (length === void 0 || value.length === length)) return value; - if (length !== void 0) anumber$3(length, "length"); - const bytes = isBytes$3(value); - const ofLen = length !== void 0 ? ` of length ${length}` : ""; - const got = bytes ? `length=${value.length}` : `type=${typeof value}`; - const message = atitle$1(title) + "expected Uint8Array" + ofLen + ", got " + got; - if (!bytes) throw new TypeError(message); - throw new RangeError(message); -} -const aobject$1 = (value, label) => { - if (value === null || typeof value !== "object" || Array.isArray(value)) throw new TypeError(label === "object" ? "expected valid options object" : `"${label}" expected object, got type=${typeof value}`); -}; -/** -* Asserts a hash- or MAC-like instance has not been destroyed or finished. -* @param instance - Stateful instance to validate. -* @param checkFinished - Whether to reject finished instances. -* When `false`, only `destroyed` is checked. -* @throws If the hash instance has already been destroyed or finalized. {@link Error} -* @example -* Guards against calling `update()` or `digest()` on a finished hash. -* -* ```ts -* aexists({ destroyed: false, finished: false }); -* ``` -*/ -function aexists$1(instance, checkFinished = true) { - if (instance.destroyed) throw new Error("hash was destroyed"); - if (checkFinished && instance.finished) throw new Error("digest() was already called"); -} -/** -* Asserts output is a sufficiently-sized byte array. -* @param out - Output buffer to validate. -* @param instance - Hash-like instance providing `outputLen`. -* This is the relaxed `digestInto()`-style contract: output must be at least `outputLen`, -* unlike one-shot cipher helpers elsewhere in the repo that often require exact lengths. -* @throws On wrong argument types. {@link TypeError} -* @throws On wrong output buffer lengths. {@link RangeError} -* @example -* Verifies that a caller-provided output buffer is large enough. -* -* ```ts -* aoutput(new Uint8Array(16), { outputLen: 16 }); -* ``` -*/ -function aoutput$1(out, instance) { - abytes$4(out, void 0, "output"); - const min = instance.outputLen; - if (!(out.length >= min)) throw new RangeError("\"output\" expected length >= " + min); -} -/** -* Casts a typed-array view to Uint32Array. -* @param arr - Typed-array view to reinterpret. -* @returns Uint32Array view over the same bytes. Callers are expected to provide a -* 4-byte-aligned offset; trailing `1..3` bytes are silently dropped. -* @example -* Views a byte buffer as 32-bit words for block processing. -* -* ```ts -* u32(new Uint8Array(4)); -* ``` -*/ -function u32$1(arr) { - return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4)); -} -/** -* Zeroizes typed arrays in place. -* Warning: JS provides no guarantees. -* @param arrays - Arrays to wipe. -* @example -* Wipes a temporary key buffer after use. -* -* ```ts -* const bytes = new Uint8Array([1]); -* clean(bytes); -* ``` -*/ -function clean$1(...arrays) { - for (let i = 0; i < arrays.length; i++) arrays[i].fill(0); -} -/** -* Creates a DataView for byte-level manipulation. -* @param arr - Typed-array view to wrap. -* @returns DataView over the same bytes. -* @example -* Creates an endian-aware view for length encoding. -* -* ```ts -* createView(new Uint8Array(4)); -* ``` -*/ -function createView(arr) { - return new DataView(arr.buffer, arr.byteOffset, arr.byteLength); -} -/** -* Whether the current platform is little-endian. -* Most are; some IBM systems are not. -*/ -const isLE$1 = /* @__PURE__ */ (() => new Uint8Array(new Uint32Array([287454020]).buffer)[0] === 68)(); -/** -* Reverses byte order of one 32-bit word. -* @param word - Unsigned 32-bit word to swap. -* @returns The same word with bytes reversed. -* @example -* Swaps a big-endian word into little-endian byte order. -* -* ```ts -* byteSwap(0x11223344); -* ``` -*/ -function byteSwap$1(word) { - return word << 24 & 4278190080 | word << 8 & 16711680 | word >>> 8 & 65280 | word >>> 24 & 255; -} -/** -* Byte-swaps every word of a Uint32Array in place. -* @param arr - Uint32Array whose words should be swapped. -* @returns The same array after in-place byte swapping. -* @example -* Swaps every 32-bit word in a word-view buffer. -* -* ```ts -* byteSwap32(new Uint32Array([0x11223344])); -* ``` -*/ -function byteSwap32$1(arr) { - for (let i = 0; i < arr.length; i++) arr[i] = byteSwap$1(arr[i]); - return arr; -} -/** -* Normalizes a Uint32Array view to the little-endian representation expected by cipher cores. -* @param u - Word view to normalize in place. -* @returns Little-endian normalized word view. -* @example -* Normalizes a word-view buffer before block processing. -* -* ```ts -* swap32IfBE(new Uint32Array([0x11223344])); -* ``` -*/ -const swap32IfBE$1 = isLE$1 ? (u) => u : byteSwap32$1; -/** -* Checks if two U8A use same underlying buffer and overlaps. -* This is invalid and can corrupt data. -* @param a - First byte view. -* @param b - Second byte view. -* @returns `true` when the views overlap in memory. -* @example -* Detects whether two slices alias the same backing buffer. -* -* ```ts -* overlapBytes(new Uint8Array(4), new Uint8Array(4)); -* ``` -*/ -function overlapBytes(a, b) { - if (!a.byteLength || !b.byteLength) return false; - return a.buffer === b.buffer && a.byteOffset < b.byteOffset + b.byteLength && b.byteOffset < a.byteOffset + a.byteLength; -} -/** -* If input and output overlap and input starts before output, we will overwrite end of input before -* we start processing it, so this is not supported by forward-processing ciphers. -* @param input - Input bytes. -* @param output - Output bytes. -* @throws If the output view would overwrite unread input bytes. {@link Error} -* @example -* Rejects an in-place layout that would overwrite unread input bytes. -* -* ```ts -* const buffer = new Uint8Array(8); -* complexOverlapBytes(buffer.subarray(0, 4), buffer.subarray(2, 6)); -* ``` -*/ -function complexOverlapBytes(input, output) { - if (overlapBytes(input, output) && input.byteOffset < output.byteOffset) throw new Error("complex overlap of input and output is not supported"); -} -/** -* Merges user options into defaults. -* @param defaults - Default option values. -* @param opts - User-provided overrides. -* @returns Combined options object. -* `defaults` is a library-owned mutable object; user-provided `opts` only need to be -* object-shaped, since "plain object" checks reject valid proxy/cross-realm containers. -* The merge mutates `defaults` in place and returns the same object, so direct callers -* should pass a fresh defaults object unless they intentionally want shared state updated. -* @throws If options are missing or not an object. {@link Error} -* @example -* Applies user overrides to the default cipher options. -* -* ```ts -* checkOpts({ rounds: 20 }, { rounds: 8 }); -* ``` -*/ -function checkOpts(defaults, opts) { - aobject$1(defaults, "defaults"); - aobject$1(opts, "opts"); - return Object.assign(defaults, opts); -} -/** -* Compares two byte arrays in kinda constant time once lengths already match. -* @param a - First byte array. -* @param b - Second byte array. -* @returns `true` when the arrays contain the same bytes. Different lengths still return early. -* @example -* Compares an expected authentication tag with the received one. -* -* ```ts -* equalBytes(new Uint8Array([1]), new Uint8Array([1])); -* ``` -*/ -function equalBytes$2(a, b) { - a = abytes$4(a); - b = abytes$4(b); - if (a.length !== b.length) return false; - let diff = 0; - for (let i = 0; i < a.length; i++) diff |= a[i] ^ b[i]; - return diff === 0; -} -/** -* Wraps a keyed MAC constructor into a one-shot helper with `.create()`. -* @param keyLen - Valid probe-key length used to read static metadata once. -* The probe key is only used for `outputLen` / `blockLen`, so callers with several valid key sizes -* can pass any representative size as long as those values stay fixed. -* @param macCons - Keyed MAC constructor or factory. -* @param fromMsg - Optional adapter that derives extra constructor args from the one-shot message. -* @returns Callable MAC helper with `.create()`. -*/ -function wrapMacConstructor(keyLen, macCons, fromMsg) { - const mac = macCons; - const getArgs = fromMsg || (() => []); - const macC = (msg, key) => mac(key, ...getArgs(msg)).update(msg).digest(); - const tmp = mac(new Uint8Array(keyLen), ...getArgs(/* @__PURE__ */ new Uint8Array(0))); - macC.outputLen = tmp.outputLen; - macC.blockLen = tmp.blockLen; - macC.create = (key, ...args) => mac(key, ...args); - return macC; -} -/** -* Wraps a cipher: validates args, ensures encrypt() can only be called once. -* Used internally by the exported cipher constructors. -* Output-buffer support is inferred from the wrapped `encrypt` / `decrypt` -* arity (`fn.length === 2`), so wrapped output-capable methods must use a normal -* second parameter, not a default/rest parameter. AAD support is explicit in -* `params.withAAD`; optional AAD starts after the nonce slot when one is present. -* @__NO_SIDE_EFFECTS__ -* @param params - Static cipher metadata. See {@link CipherParams}. -* @param constructor - Cipher constructor. -* @returns Wrapped constructor with validation. -*/ -const wrapCipher = (params, constructor) => { - function wrappedCipher(key, ...args) { - abytes$4(key, void 0, "key"); - if (params.nonceLength !== void 0) { - const nonce = args[0]; - abytes$4(nonce, params.varSizeNonce ? void 0 : params.nonceLength, "nonce"); - } - const tagl = params.tagLength; - const aadStart = params.nonceLength !== void 0 ? 1 : 0; - if (!params.withAAD) { - for (let i = aadStart; i < args.length; i++) if (isBytes$3(args[i])) throw new Error("AAD not supported"); - } - if (params.withAAD && args[aadStart] !== void 0) abytes$4(args[aadStart], void 0, "AAD"); - const cipher = constructor(key, ...args); - const checkOutput = (fnLength, output) => { - if (output !== void 0) { - if (fnLength !== 2) throw new Error("cipher output not supported"); - abytes$4(output, void 0, "output"); - } - }; - let called = false; - return { - encrypt(data, output) { - if (called) throw new Error("cannot encrypt() twice with same key + nonce"); - called = true; - abytes$4(data, void 0, "data"); - checkOutput(cipher.encrypt.length, output); - return cipher.encrypt(data, output); - }, - decrypt(data, output) { - abytes$4(data, void 0, "data"); - if (tagl && data.length < tagl) throw new Error("\"ciphertext\" expected length >= tagLength=" + tagl); - checkOutput(cipher.decrypt.length, output); - return cipher.decrypt(data, output); - } - }; - } - Object.assign(wrappedCipher, params); - return wrappedCipher; -}; -/** -* By default, returns u8a of length. -* When out is available, it checks it for validity and uses it. -* @param expectedLength - Required output length. -* @param out - Optional destination buffer. -* @param onlyAligned - Whether `out` must be 4-byte aligned. -* @returns Output buffer ready for writing. -* @throws On wrong argument types. {@link TypeError} -* @throws If the provided output buffer has the wrong size. {@link RangeError} -* @throws If the provided output buffer has the wrong alignment. {@link Error} -* @example -* Reuses a caller-provided output buffer when lengths match. -* -* ```ts -* getOutput(16, new Uint8Array(16)); -* ``` -*/ -function getOutput(expectedLength, out, onlyAligned = true) { - if (out === void 0) return new Uint8Array(expectedLength); - abytes$4(out, expectedLength, "output"); - if (onlyAligned && !isAligned32(out)) throw new Error("invalid output, must be aligned"); - return out; -} -/** -* Encodes data and AAD lengths into a 16-byte buffer. -* @param dataLength - Data length. Units are caller-defined: GCM passes bit -* lengths, ChaCha20-Poly1305 passes byte lengths — the helper writes the raw values. -* @param aadLength - AAD length, same unit convention as `dataLength`. -* The serialized block is still `aadLength || dataLength`, matching GCM/Poly1305 -* conventions even though the helper parameter order is `(dataLength, aadLength)`. -* @param isLE - Whether to encode lengths as little-endian. -* @returns 16-byte length block. -* @throws On wrong argument types passed to the endian validator. {@link TypeError} -* @throws On wrong argument ranges or values. {@link RangeError} -* @example -* Builds the length block appended by GCM and Poly1305. -* -* ```ts -* u64Lengths(16, 8, true); -* ``` -*/ -function u64Lengths(dataLength, aadLength, isLE) { - anumber$3(dataLength); - anumber$3(aadLength); - abool$2(isLE); - const num = /* @__PURE__ */ new Uint8Array(16); - const view = createView(num); - view.setBigUint64(0, BigInt(aadLength), isLE); - view.setBigUint64(8, BigInt(dataLength), isLE); - return num; -} -/** -* Checks whether a byte array is aligned to a 4-byte offset. -* @param bytes - Byte array to inspect. -* @returns `true` when the view is 4-byte aligned. -* @example -* Checks whether a buffer can be safely viewed as Uint32Array. -* -* ```ts -* isAligned32(new Uint8Array(4)); -* ``` -*/ -function isAligned32(bytes) { - return bytes.byteOffset % 4 === 0; -} -/** -* Copies bytes into a new Uint8Array. -* @param bytes - Bytes to copy. -* @returns Copied byte array. -* @throws On wrong argument types. {@link TypeError} -* @example -* Copies input into an aligned Uint8Array before block processing. -* -* ```ts -* copyBytes(new Uint8Array([1, 2])); -* ``` -*/ -function copyBytes$2(bytes) { - return Uint8Array.from(abytes$4(bytes)); -} -//#endregion -//#region tests/baseline/node_modules/@noble/ciphers/_arx.js -/** -* Basic utils for ARX (add-rotate-xor) salsa and chacha ciphers. - -RFC8439 requires multi-step cipher stream, where -authKey starts with counter: 0, actual msg with counter: 1. - -For this, we need a way to re-use nonce / counter: - -const counter = new Uint8Array(4); -chacha(..., counter, ...); // counter is now 1 -chacha(..., counter, ...); // counter is now 2 - -This is complicated: - -- 32-bit counters are enough, no need for 64-bit: max ArrayBuffer size in JS is 4GB -- Original papers don't allow mutating counters -- Counter overflow is undefined [^1] -- Idea A: allow providing (nonce | counter) instead of just nonce, re-use it -- Caveat: Cannot be re-used through all cases: -- * chacha has (counter | nonce) -- * xchacha has (nonce16 | counter | nonce16) -- Idea B: separate nonce / counter and provide separate API for counter re-use -- Caveat: there are different counter sizes depending on an algorithm. -- salsa & chacha also differ in structures of key & sigma: -salsa20: s[0] | k(4) | s[1] | nonce(2) | cnt(2) | s[2] | k(4) | s[3] -chacha: s(4) | k(8) | cnt(1) | nonce(3) -chacha20orig: s(4) | k(8) | cnt(2) | nonce(2) -- Idea C: helper method such as `setSalsaState(key, nonce, sigma, data)` -- Caveat: we can't re-use counter array - -xchacha uses the subkey and remaining 8 byte nonce with ChaCha20 as normal -(prefixed by 4 NUL bytes, since RFC8439 specifies a 12-byte nonce). -Counter overflow is undefined; see {@link https://mailarchive.ietf.org/arch/msg/cfrg/gsOnTJzcbgG6OqD8Sc0GO5aR_tU/ | the CFRG thread}. -Current noble policy is strict non-wrap for the shared 32-bit counter path: -exported ARX ciphers reject initial `0xffffffff` and stop before any implicit -wrap back to zero. -See {@link https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha#appendix-A.2 | the XChaCha appendix} for the extended-nonce construction. - -* @module -*/ -const encodeStr = (str) => Uint8Array.from(str.split(""), (c) => c.charCodeAt(0)); -const sigma16_32 = /* @__PURE__ */ (() => swap32IfBE$1(u32$1(encodeStr("expand 16-byte k"))))(); -const sigma32_32 = /* @__PURE__ */ (() => swap32IfBE$1(u32$1(encodeStr("expand 32-byte k"))))(); -/** -* Rotates a 32-bit word left. -* @param a - Input word. -* @param b - Rotation count in bits. -* @returns Rotated 32-bit word. -* @example -* Moves the top byte of `0x12345678` into the low byte position. -* ```ts -* rotl(0x12345678, 8); -* ``` -*/ -function rotl$1(a, b) { - return a << b | a >>> 32 - b; -} -const BLOCK_LEN = 64; -const BLOCK_LEN32 = 16; -const MAX_COUNTER = /* @__PURE__ */ (() => 2 ** 32 - 1)(); -const U32_EMPTY = /* @__PURE__ */ Uint32Array.of(); -function runCipher(core, sigma, key, nonce, data, output, counter, rounds) { - const len = data.length; - const block = new Uint8Array(BLOCK_LEN); - const b32 = u32$1(block); - const isAligned = isLE$1 && isAligned32(data) && isAligned32(output); - const d32 = isAligned ? u32$1(data) : U32_EMPTY; - const o32 = isAligned ? u32$1(output) : U32_EMPTY; - if (!isLE$1) { - for (let pos = 0; pos < len; counter++) { - core(sigma, key, nonce, b32, counter, rounds); - swap32IfBE$1(b32); - if (counter >= MAX_COUNTER) throw new Error("arx: counter overflow"); - const take = Math.min(BLOCK_LEN, len - pos); - for (let j = 0, posj; j < take; j++) { - posj = pos + j; - output[posj] = data[posj] ^ block[j]; - } - pos += take; - } - return; - } - for (let pos = 0; pos < len; counter++) { - core(sigma, key, nonce, b32, counter, rounds); - if (counter >= MAX_COUNTER) throw new Error("arx: counter overflow"); - const take = Math.min(BLOCK_LEN, len - pos); - if (isAligned && take === BLOCK_LEN) { - const pos32 = pos / 4; - if (pos % 4 !== 0) throw new Error("arx: invalid block position"); - for (let j = 0, posj; j < BLOCK_LEN32; j++) { - posj = pos32 + j; - o32[posj] = d32[posj] ^ b32[j]; - } - pos += BLOCK_LEN; - continue; - } - for (let j = 0, posj; j < take; j++) { - posj = pos + j; - output[posj] = data[posj] ^ block[j]; - } - pos += take; - } -} -/** -* Creates an ARX stream cipher from a 32-bit core permutation. -* Used internally to build the exported Salsa and ChaCha stream ciphers. -* @param core - Core function that fills one keystream block. -* @param opts - Cipher layout and nonce-extension options. See {@link CipherOpts}. -* @returns Stream cipher function over byte arrays. -* @throws If the core callback, key size, counter, or output sizing is invalid. {@link Error} -*/ -function createCipher(core, opts) { - const { allowShortKeys, extendNonceFn, counterLength, counterRight, rounds } = checkOpts({ - allowShortKeys: false, - counterLength: 8, - counterRight: false, - rounds: 20 - }, opts); - if (typeof core !== "function") throw new Error("core must be a function"); - anumber$3(counterLength); - anumber$3(rounds); - abool$2(counterRight); - abool$2(allowShortKeys); - return (key, nonce, data, output, counter = 0) => { - abytes$4(key, void 0, "key"); - abytes$4(nonce, void 0, "nonce"); - abytes$4(data, void 0, "data"); - const len = data.length; - const hasOutput = output !== void 0; - output = getOutput(len, output, false); - if (hasOutput) complexOverlapBytes(data, output); - anumber$3(counter); - if (counter < 0 || counter >= MAX_COUNTER) throw new Error("arx: counter overflow"); - const toClean = []; - let l = key.length; - let k; - let sigma; - if (l === 32) { - toClean.push(k = copyBytes$2(key)); - sigma = sigma32_32; - } else if (l === 16 && allowShortKeys) { - k = /* @__PURE__ */ new Uint8Array(32); - k.set(key); - k.set(key, 16); - sigma = sigma16_32; - toClean.push(k); - } else { - abytes$4(key, 32, "arx key"); - throw new Error("invalid key size"); - } - if (!isLE$1 || !isAligned32(nonce)) toClean.push(nonce = copyBytes$2(nonce)); - let k32 = u32$1(k); - if (extendNonceFn) { - if (nonce.length !== 24) throw new Error("arx: extended nonce must be 24 bytes"); - const n16 = nonce.subarray(0, 16); - if (isLE$1) extendNonceFn(sigma, k32, u32$1(n16), k32); - else { - const sigmaRaw = swap32IfBE$1(Uint32Array.from(sigma)); - extendNonceFn(sigmaRaw, k32, u32$1(n16), k32); - clean$1(sigmaRaw); - swap32IfBE$1(k32); - } - nonce = nonce.subarray(16); - } else if (!isLE$1) swap32IfBE$1(k32); - const nonceNcLen = 16 - counterLength; - if (nonceNcLen !== nonce.length) throw new Error(`arx: nonce must be ${nonceNcLen} or 16 bytes`); - if (nonceNcLen !== 12) { - const nc = /* @__PURE__ */ new Uint8Array(12); - nc.set(nonce, counterRight ? 0 : 12 - nonce.length); - nonce = nc; - toClean.push(nonce); - } - const n32 = swap32IfBE$1(u32$1(nonce)); - try { - runCipher(core, sigma, k32, n32, data, output, counter, rounds); - return output; - } finally { - clean$1(...toClean); - } - }; -} -//#endregion -//#region tests/baseline/node_modules/@noble/ciphers/_poly1305.js -/** -* Poly1305 ({@link https://cr.yp.to/mac/poly1305-20050329.pdf | PDF}, -* {@link https://en.wikipedia.org/wiki/Poly1305 | wiki}) -* is a fast and parallel secret-key message-authentication code suitable for -* a wide variety of applications. It was standardized in -* {@link https://www.rfc-editor.org/rfc/rfc8439 | RFC 8439} and is now used in TLS 1.3. -* -* Polynomial MACs are not perfect for every situation: -* they lack Random Key Robustness: the MAC can be forged, and can't be used in PAKE schemes. -* See {@link https://keymaterial.net/2020/09/07/invisible-salamanders-in-aes-gcm-siv/ | the invisible salamanders attack writeup}. -* To combat invisible salamanders, `hash(key)` can be included in ciphertext, -* however, this would violate ciphertext indistinguishability: -* an attacker would know which key was used - so `HKDF(key, i)` -* could be used instead. -* -* Check out the {@link https://cr.yp.to/mac.html | original website}. -* Based on public-domain {@link https://github.com/floodyberry/poly1305-donna | poly1305-donna}. -* @module -*/ -function u8to16(a, i) { - return a[i++] & 255 | (a[i++] & 255) << 8; -} -/** -* Incremental Poly1305 MAC state. -* Prefer `poly1305()` for one-shot use. -* @param key - 32-byte Poly1305 one-time key. -* @example -* Feeds one chunk into an incremental Poly1305 state with a fresh one-time key. -* -* ```ts -* import { Poly1305 } from '@noble/ciphers/_poly1305.js'; -* import { randomBytes } from '@noble/ciphers/utils.js'; -* const key = randomBytes(32); -* const mac = new Poly1305(key); -* mac.update(new Uint8Array([1, 2, 3])); -* mac.digest(); -* ``` -*/ -var Poly1305 = class { - blockLen = 16; - outputLen = 16; - buffer = /* @__PURE__ */ new Uint8Array(16); - r = /* @__PURE__ */ new Uint16Array(10); - h = /* @__PURE__ */ new Uint16Array(10); - pad = /* @__PURE__ */ new Uint16Array(8); - pos = 0; - finished = false; - destroyed = false; - constructor(key) { - key = copyBytes$2(abytes$4(key, 32, "key")); - const t0 = u8to16(key, 0); - const t1 = u8to16(key, 2); - const t2 = u8to16(key, 4); - const t3 = u8to16(key, 6); - const t4 = u8to16(key, 8); - const t5 = u8to16(key, 10); - const t6 = u8to16(key, 12); - const t7 = u8to16(key, 14); - this.r[0] = t0 & 8191; - this.r[1] = (t0 >>> 13 | t1 << 3) & 8191; - this.r[2] = (t1 >>> 10 | t2 << 6) & 7939; - this.r[3] = (t2 >>> 7 | t3 << 9) & 8191; - this.r[4] = (t3 >>> 4 | t4 << 12) & 255; - this.r[5] = t4 >>> 1 & 8190; - this.r[6] = (t4 >>> 14 | t5 << 2) & 8191; - this.r[7] = (t5 >>> 11 | t6 << 5) & 8065; - this.r[8] = (t6 >>> 8 | t7 << 8) & 8191; - this.r[9] = t7 >>> 5 & 127; - for (let i = 0; i < 8; i++) this.pad[i] = u8to16(key, 16 + 2 * i); - } - process(data, offset, isLast = false) { - const hibit = isLast ? 0 : 2048; - const { h, r } = this; - const r0 = r[0]; - const r1 = r[1]; - const r2 = r[2]; - const r3 = r[3]; - const r4 = r[4]; - const r5 = r[5]; - const r6 = r[6]; - const r7 = r[7]; - const r8 = r[8]; - const r9 = r[9]; - const t0 = u8to16(data, offset + 0); - const t1 = u8to16(data, offset + 2); - const t2 = u8to16(data, offset + 4); - const t3 = u8to16(data, offset + 6); - const t4 = u8to16(data, offset + 8); - const t5 = u8to16(data, offset + 10); - const t6 = u8to16(data, offset + 12); - const t7 = u8to16(data, offset + 14); - let h0 = h[0] + (t0 & 8191); - let h1 = h[1] + ((t0 >>> 13 | t1 << 3) & 8191); - let h2 = h[2] + ((t1 >>> 10 | t2 << 6) & 8191); - let h3 = h[3] + ((t2 >>> 7 | t3 << 9) & 8191); - let h4 = h[4] + ((t3 >>> 4 | t4 << 12) & 8191); - let h5 = h[5] + (t4 >>> 1 & 8191); - let h6 = h[6] + ((t4 >>> 14 | t5 << 2) & 8191); - let h7 = h[7] + ((t5 >>> 11 | t6 << 5) & 8191); - let h8 = h[8] + ((t6 >>> 8 | t7 << 8) & 8191); - let h9 = h[9] + (t7 >>> 5 | hibit); - let c = 0; - let d0 = c + h0 * r0 + h1 * (5 * r9) + h2 * (5 * r8) + h3 * (5 * r7) + h4 * (5 * r6); - c = d0 >>> 13; - d0 &= 8191; - d0 += h5 * (5 * r5) + h6 * (5 * r4) + h7 * (5 * r3) + h8 * (5 * r2) + h9 * (5 * r1); - c += d0 >>> 13; - d0 &= 8191; - let d1 = c + h0 * r1 + h1 * r0 + h2 * (5 * r9) + h3 * (5 * r8) + h4 * (5 * r7); - c = d1 >>> 13; - d1 &= 8191; - d1 += h5 * (5 * r6) + h6 * (5 * r5) + h7 * (5 * r4) + h8 * (5 * r3) + h9 * (5 * r2); - c += d1 >>> 13; - d1 &= 8191; - let d2 = c + h0 * r2 + h1 * r1 + h2 * r0 + h3 * (5 * r9) + h4 * (5 * r8); - c = d2 >>> 13; - d2 &= 8191; - d2 += h5 * (5 * r7) + h6 * (5 * r6) + h7 * (5 * r5) + h8 * (5 * r4) + h9 * (5 * r3); - c += d2 >>> 13; - d2 &= 8191; - let d3 = c + h0 * r3 + h1 * r2 + h2 * r1 + h3 * r0 + h4 * (5 * r9); - c = d3 >>> 13; - d3 &= 8191; - d3 += h5 * (5 * r8) + h6 * (5 * r7) + h7 * (5 * r6) + h8 * (5 * r5) + h9 * (5 * r4); - c += d3 >>> 13; - d3 &= 8191; - let d4 = c + h0 * r4 + h1 * r3 + h2 * r2 + h3 * r1 + h4 * r0; - c = d4 >>> 13; - d4 &= 8191; - d4 += h5 * (5 * r9) + h6 * (5 * r8) + h7 * (5 * r7) + h8 * (5 * r6) + h9 * (5 * r5); - c += d4 >>> 13; - d4 &= 8191; - let d5 = c + h0 * r5 + h1 * r4 + h2 * r3 + h3 * r2 + h4 * r1; - c = d5 >>> 13; - d5 &= 8191; - d5 += h5 * r0 + h6 * (5 * r9) + h7 * (5 * r8) + h8 * (5 * r7) + h9 * (5 * r6); - c += d5 >>> 13; - d5 &= 8191; - let d6 = c + h0 * r6 + h1 * r5 + h2 * r4 + h3 * r3 + h4 * r2; - c = d6 >>> 13; - d6 &= 8191; - d6 += h5 * r1 + h6 * r0 + h7 * (5 * r9) + h8 * (5 * r8) + h9 * (5 * r7); - c += d6 >>> 13; - d6 &= 8191; - let d7 = c + h0 * r7 + h1 * r6 + h2 * r5 + h3 * r4 + h4 * r3; - c = d7 >>> 13; - d7 &= 8191; - d7 += h5 * r2 + h6 * r1 + h7 * r0 + h8 * (5 * r9) + h9 * (5 * r8); - c += d7 >>> 13; - d7 &= 8191; - let d8 = c + h0 * r8 + h1 * r7 + h2 * r6 + h3 * r5 + h4 * r4; - c = d8 >>> 13; - d8 &= 8191; - d8 += h5 * r3 + h6 * r2 + h7 * r1 + h8 * r0 + h9 * (5 * r9); - c += d8 >>> 13; - d8 &= 8191; - let d9 = c + h0 * r9 + h1 * r8 + h2 * r7 + h3 * r6 + h4 * r5; - c = d9 >>> 13; - d9 &= 8191; - d9 += h5 * r4 + h6 * r3 + h7 * r2 + h8 * r1 + h9 * r0; - c += d9 >>> 13; - d9 &= 8191; - c = (c << 2) + c | 0; - c = c + d0 | 0; - d0 = c & 8191; - c = c >>> 13; - d1 += c; - h[0] = d0; - h[1] = d1; - h[2] = d2; - h[3] = d3; - h[4] = d4; - h[5] = d5; - h[6] = d6; - h[7] = d7; - h[8] = d8; - h[9] = d9; - } - finalize() { - const { h, pad } = this; - const g = /* @__PURE__ */ new Uint16Array(10); - let c = h[1] >>> 13; - h[1] &= 8191; - for (let i = 2; i < 10; i++) { - h[i] += c; - c = h[i] >>> 13; - h[i] &= 8191; - } - h[0] += c * 5; - c = h[0] >>> 13; - h[0] &= 8191; - h[1] += c; - c = h[1] >>> 13; - h[1] &= 8191; - h[2] += c; - g[0] = h[0] + 5; - c = g[0] >>> 13; - g[0] &= 8191; - for (let i = 1; i < 10; i++) { - g[i] = h[i] + c; - c = g[i] >>> 13; - g[i] &= 8191; - } - g[9] -= 8192; - let mask = (c ^ 1) - 1; - for (let i = 0; i < 10; i++) g[i] &= mask; - mask = ~mask; - for (let i = 0; i < 10; i++) h[i] = h[i] & mask | g[i]; - h[0] = (h[0] | h[1] << 13) & 65535; - h[1] = (h[1] >>> 3 | h[2] << 10) & 65535; - h[2] = (h[2] >>> 6 | h[3] << 7) & 65535; - h[3] = (h[3] >>> 9 | h[4] << 4) & 65535; - h[4] = (h[4] >>> 12 | h[5] << 1 | h[6] << 14) & 65535; - h[5] = (h[6] >>> 2 | h[7] << 11) & 65535; - h[6] = (h[7] >>> 5 | h[8] << 8) & 65535; - h[7] = (h[8] >>> 8 | h[9] << 5) & 65535; - let f = h[0] + pad[0]; - h[0] = f & 65535; - for (let i = 1; i < 8; i++) { - f = (h[i] + pad[i] | 0) + (f >>> 16) | 0; - h[i] = f & 65535; - } - clean$1(g); - } - update(data) { - aexists$1(this); - abytes$4(data); - data = copyBytes$2(data); - const { buffer, blockLen } = this; - const len = data.length; - for (let pos = 0; pos < len;) { - const take = Math.min(blockLen - this.pos, len - pos); - if (take === blockLen) { - for (; blockLen <= len - pos; pos += blockLen) this.process(data, pos); - continue; - } - buffer.set(data.subarray(pos, pos + take), this.pos); - this.pos += take; - pos += take; - if (this.pos === blockLen) { - this.process(buffer, 0, false); - this.pos = 0; - } - } - return this; - } - destroy() { - this.destroyed = true; - clean$1(this.h, this.r, this.buffer, this.pad); - } - digestInto(out) { - aexists$1(this); - aoutput$1(out, this); - this.finished = true; - const { buffer, h } = this; - let { pos } = this; - if (pos) { - buffer[pos++] = 1; - for (; pos < 16; pos++) buffer[pos] = 0; - this.process(buffer, 0, true); - } - this.finalize(); - let opos = 0; - for (let i = 0; i < 8; i++) { - out[opos++] = h[i] >>> 0; - out[opos++] = h[i] >>> 8; - } - } - digest() { - const { buffer, outputLen } = this; - this.digestInto(buffer); - const res = buffer.slice(0, outputLen); - this.destroy(); - return res; - } -}; -/** -* Poly1305 MAC from RFC 8439. -* @param msg - Message bytes to authenticate. -* @param key - 32-byte Poly1305 one-time key. -* @returns 16-byte authentication tag. -* @example -* Authenticates one message with a one-shot Poly1305 call and a fresh key. -* -* ```ts -* import { poly1305 } from '@noble/ciphers/_poly1305.js'; -* import { randomBytes } from '@noble/ciphers/utils.js'; -* const key = randomBytes(32); -* poly1305(new Uint8Array(), key); -* ``` -*/ -const poly1305 = /* @__PURE__ */ wrapMacConstructor(32, (key) => new Poly1305(key)); -//#endregion -//#region tests/baseline/node_modules/@noble/ciphers/chacha.js -/** -* ChaCha stream cipher, released -* in 2008. Developed after Salsa20, ChaCha aims to increase diffusion per round. -* It was standardized in -* {@link https://www.rfc-editor.org/rfc/rfc8439 | RFC 8439} and -* is now used in TLS 1.3. -* -* {@link https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha | XChaCha20} -* extended-nonce variant is also provided. Similar to XSalsa, it's safe to use with -* randomly-generated nonces. -* -* Check out -* {@link http://cr.yp.to/chacha/chacha-20080128.pdf | PDF}, -* {@link https://en.wikipedia.org/wiki/Salsa20 | wiki}, and -* {@link https://cr.yp.to/chacha.html | website}. -* -* @module -*/ -/** -* ChaCha core function. Uses an unrolled loop (chachaCore, hchacha) - 4x -* faster than a simple loop, but larger & harder to read. A simple-loop -* reference version lives in `test/misc/micro-ciphers.ts`; -* `test/arx.test.ts` keeps the two aligned. -* The specific implementation is selected in `createCipher` below. -*/ -/** RFC 8439 §2.3 block core for `state = constants | key | counter | nonce`. */ -function chachaCore(s, k, n, out, cnt, rounds = 20) { - let y00 = s[0], y01 = s[1], y02 = s[2], y03 = s[3], y04 = k[0], y05 = k[1], y06 = k[2], y07 = k[3], y08 = k[4], y09 = k[5], y10 = k[6], y11 = k[7], y12 = cnt, y13 = n[0], y14 = n[1], y15 = n[2]; - let x00 = y00, x01 = y01, x02 = y02, x03 = y03, x04 = y04, x05 = y05, x06 = y06, x07 = y07, x08 = y08, x09 = y09, x10 = y10, x11 = y11, x12 = y12, x13 = y13, x14 = y14, x15 = y15; - for (let r = 0; r < rounds; r += 2) { - x00 = x00 + x04 | 0; - x12 = rotl$1(x12 ^ x00, 16); - x08 = x08 + x12 | 0; - x04 = rotl$1(x04 ^ x08, 12); - x00 = x00 + x04 | 0; - x12 = rotl$1(x12 ^ x00, 8); - x08 = x08 + x12 | 0; - x04 = rotl$1(x04 ^ x08, 7); - x01 = x01 + x05 | 0; - x13 = rotl$1(x13 ^ x01, 16); - x09 = x09 + x13 | 0; - x05 = rotl$1(x05 ^ x09, 12); - x01 = x01 + x05 | 0; - x13 = rotl$1(x13 ^ x01, 8); - x09 = x09 + x13 | 0; - x05 = rotl$1(x05 ^ x09, 7); - x02 = x02 + x06 | 0; - x14 = rotl$1(x14 ^ x02, 16); - x10 = x10 + x14 | 0; - x06 = rotl$1(x06 ^ x10, 12); - x02 = x02 + x06 | 0; - x14 = rotl$1(x14 ^ x02, 8); - x10 = x10 + x14 | 0; - x06 = rotl$1(x06 ^ x10, 7); - x03 = x03 + x07 | 0; - x15 = rotl$1(x15 ^ x03, 16); - x11 = x11 + x15 | 0; - x07 = rotl$1(x07 ^ x11, 12); - x03 = x03 + x07 | 0; - x15 = rotl$1(x15 ^ x03, 8); - x11 = x11 + x15 | 0; - x07 = rotl$1(x07 ^ x11, 7); - x00 = x00 + x05 | 0; - x15 = rotl$1(x15 ^ x00, 16); - x10 = x10 + x15 | 0; - x05 = rotl$1(x05 ^ x10, 12); - x00 = x00 + x05 | 0; - x15 = rotl$1(x15 ^ x00, 8); - x10 = x10 + x15 | 0; - x05 = rotl$1(x05 ^ x10, 7); - x01 = x01 + x06 | 0; - x12 = rotl$1(x12 ^ x01, 16); - x11 = x11 + x12 | 0; - x06 = rotl$1(x06 ^ x11, 12); - x01 = x01 + x06 | 0; - x12 = rotl$1(x12 ^ x01, 8); - x11 = x11 + x12 | 0; - x06 = rotl$1(x06 ^ x11, 7); - x02 = x02 + x07 | 0; - x13 = rotl$1(x13 ^ x02, 16); - x08 = x08 + x13 | 0; - x07 = rotl$1(x07 ^ x08, 12); - x02 = x02 + x07 | 0; - x13 = rotl$1(x13 ^ x02, 8); - x08 = x08 + x13 | 0; - x07 = rotl$1(x07 ^ x08, 7); - x03 = x03 + x04 | 0; - x14 = rotl$1(x14 ^ x03, 16); - x09 = x09 + x14 | 0; - x04 = rotl$1(x04 ^ x09, 12); - x03 = x03 + x04 | 0; - x14 = rotl$1(x14 ^ x03, 8); - x09 = x09 + x14 | 0; - x04 = rotl$1(x04 ^ x09, 7); - } - let oi = 0; - out[oi++] = y00 + x00 | 0; - out[oi++] = y01 + x01 | 0; - out[oi++] = y02 + x02 | 0; - out[oi++] = y03 + x03 | 0; - out[oi++] = y04 + x04 | 0; - out[oi++] = y05 + x05 | 0; - out[oi++] = y06 + x06 | 0; - out[oi++] = y07 + x07 | 0; - out[oi++] = y08 + x08 | 0; - out[oi++] = y09 + x09 | 0; - out[oi++] = y10 + x10 | 0; - out[oi++] = y11 + x11 | 0; - out[oi++] = y12 + x12 | 0; - out[oi++] = y13 + x13 | 0; - out[oi++] = y14 + x14 | 0; - out[oi++] = y15 + x15 | 0; -} -/** -* ChaCha stream cipher. Conforms to RFC 8439 (IETF, TLS). 12-byte nonce, 4-byte counter. -* With smaller nonce, it's not safe to make it random (CSPRNG), due to collision chance. -* @param key - 32-byte key. -* @param nonce - 12-byte nonce. -* @param data - Input bytes to xor with the keystream. -* @param output - Optional destination buffer. -* @param counter - Initial block counter. -* @returns Encrypted or decrypted bytes. -* @example -* Encrypts bytes with the RFC 8439 ChaCha20 stream cipher and a fresh key/nonce. -* -* ```ts -* import { chacha20 } from '@noble/ciphers/chacha.js'; -* import { randomBytes } from '@noble/ciphers/utils.js'; -* const key = randomBytes(32); -* const nonce = randomBytes(12); -* chacha20(key, nonce, new Uint8Array(4)); -* ``` -*/ -const chacha20 = /* @__PURE__ */ createCipher(chachaCore, { - counterRight: false, - counterLength: 4, - allowShortKeys: false -}); -const ZEROS16 = /* @__PURE__ */ new Uint8Array(16); -const updatePadded = (h, msg) => { - h.update(msg); - const leftover = msg.length % 16; - if (leftover) h.update(ZEROS16.subarray(leftover)); -}; -const ZEROS32 = /* @__PURE__ */ new Uint8Array(32); -function computeTag(fn, key, nonce, ciphertext, AAD) { - if (AAD !== void 0) abytes$4(AAD, void 0, "AAD"); - const authKey = fn(key, nonce, ZEROS32); - const lengths = u64Lengths(ciphertext.length, AAD ? AAD.length : 0, true); - const h = poly1305.create(authKey); - if (AAD) updatePadded(h, AAD); - updatePadded(h, ciphertext); - h.update(lengths); - const res = h.digest(); - clean$1(authKey, lengths); - return res; -} -/** -* AEAD algorithm from RFC 8439. -* Salsa20 and chacha (RFC 8439) use poly1305 differently. -* We could have composed them, but it's hard because of authKey: -* In salsa20, authKey changes position in salsa stream. -* In chacha, authKey can't be computed inside computeTag, it modifies the counter. -*/ -const _poly1305_aead = (xorStream) => (key, nonce, AAD) => { - const tagLength = 16; - return { - encrypt(plaintext, output) { - const plength = plaintext.length; - output = getOutput(plength + tagLength, output, false); - output.set(plaintext); - const oPlain = output.subarray(0, -16); - xorStream(key, nonce, oPlain, oPlain, 1); - const tag = computeTag(xorStream, key, nonce, oPlain, AAD); - output.set(tag, plength); - clean$1(tag); - return output; - }, - decrypt(ciphertext, output) { - output = getOutput(ciphertext.length - tagLength, output, false); - const data = ciphertext.subarray(0, -16); - const passedTag = ciphertext.subarray(-16); - const tag = computeTag(xorStream, key, nonce, data, AAD); - if (!equalBytes$2(passedTag, tag)) { - clean$1(tag); - throw new Error("invalid tag"); - } - output.set(ciphertext.subarray(0, -16)); - xorStream(key, nonce, output, output, 1); - clean$1(tag); - return output; - } - }; -}; -/** -* ChaCha20-Poly1305 from RFC 8439. -* -* Unsafe to use random nonces under the same key, due to collision chance. -* Prefer XChaCha instead. -* @param key - 32-byte key. -* @param nonce - 12-byte nonce. -* @param AAD - Additional authenticated data. -* @returns AEAD cipher instance. -* @example -* Encrypts and authenticates plaintext with a fresh key and nonce. -* -* ```ts -* import { chacha20poly1305 } from '@noble/ciphers/chacha.js'; -* import { randomBytes } from '@noble/ciphers/utils.js'; -* const key = randomBytes(32); -* const nonce = randomBytes(12); -* const aad = new TextEncoder().encode('session metadata'); -* const cipher = chacha20poly1305(key, nonce, aad); -* cipher.encrypt(new Uint8Array([1, 2, 3])); -* ``` -*/ -const chacha20poly1305 = /* @__PURE__ */ wrapCipher({ - blockSize: 64, - nonceLength: 12, - tagLength: 16, - withAAD: true -}, /* @__PURE__ */ _poly1305_aead(chacha20)); -//#endregion -//#region tests/baseline/node_modules/@noble/curves/utils.js -/** -* Hex, bytes and number utilities. -* @module -*/ -/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ -/** -* Validates that a value is an array, optionally validating each element. -* @param item - Value to validate. -* @param title - Label included in thrown errors. -* @param inner - Optional per-element validator, called with the element and its label. -* @returns The validated array. -* @example -* Validate an array of points before batch processing. -* -* ```ts -* aarray([1n, 2n], 'scalars'); -* ``` -*/ -function aarray(item, title, inner = () => {}) { - if (!Array.isArray(item)) throw new TypeError(`"${title}" expected array, got type=${typeof item}`); - for (let i = 0; i < item.length; i++) inner(item[i], `${title}[${i}]`); - return item; -} -/** -* Validates that a value is a byte array. -* @param value - Value to validate. -* @param length - Optional exact byte length. -* @param title - Optional field name. -* @returns Original byte array. -* @example -* Reject non-byte input before passing data into curve code. -* -* ```ts -* abytes(new Uint8Array(1)); -* ``` -*/ -const abytes$3 = (value, length, title) => abytes$5(value, length, title); -/** -* Validates that a value is a non-negative safe integer. -* @param n - Value to validate. -* @param title - Optional field name. -* @returns The validated number. -* @example -* Validate a numeric length before allocating buffers. -* -* ```ts -* anumber(1); -* ``` -*/ -const anumber$2 = anumber$4; -/** -* Asserts something is a string. -* @param value - Value to validate. -* @param title - Label included in thrown errors. -* @returns The validated string. -* @throws On wrong argument types. {@link TypeError} -* @example -* Validate a label string. -* -* ```ts -* astring('example', 'label'); -* ``` -*/ -function astring(value, title = "") { - if (typeof value !== "string") { - const prefix = title && `"${title}" `; - throw new TypeError(prefix + "expected string, got type=" + typeof value); - } - return value; -} -/** -* Asserts something is a plain object-ish value, not null or array. -* @param value - Value to validate. -* @param title - Label included in thrown errors. -* @returns The validated object. -* @throws On wrong argument types. {@link TypeError} -* @example -* Validate an options object before checking fields. -* -* ```ts -* aobject({ flag: true }); -* ``` -*/ -function aobject(value, title = "object") { - if (value === null || typeof value !== "object" || Array.isArray(value)) throw new TypeError(title === "object" ? "expected valid options object" : `"${title}" expected object, got type=${typeof value}`); - return value; -} -/** -* Asserts something is a function. -* @param value - Value to validate. -* @param title - Label included in thrown errors. -* @returns The validated function. -* @throws On wrong argument types. {@link TypeError} -* @example -* Validate a required method before calling it. -* -* ```ts -* afunction(() => true, 'predicate'); -* ``` -*/ -function afunction(value, title) { - if (typeof value !== "function") throw new TypeError(`"${title}" is invalid: expected function, got ${typeof value}`); - return value; -} -/** -* Encodes bytes as lowercase hex. -* @param bytes - Bytes to encode. -* @returns Lowercase hex string. -* @example -* Serialize bytes as hex for logging or fixtures. -* -* ```ts -* bytesToHex(Uint8Array.of(1, 2, 3)); -* ``` -*/ -const bytesToHex$2 = bytesToHex$3; -/** -* Concatenates byte arrays. -* @param arrays - Byte arrays to join. -* @returns Concatenated bytes. -* @example -* Join domain-separated chunks into one buffer. -* -* ```ts -* concatBytes(Uint8Array.of(1), Uint8Array.of(2)); -* ``` -*/ -const concatBytes$2 = (...arrays) => concatBytes$3(...arrays); -/** -* Decodes lowercase or uppercase hex into bytes. -* @param hex - Hex string to decode. -* @returns Decoded bytes. -* @example -* Parse fixture hex into bytes before hashing. -* -* ```ts -* hexToBytes('0102'); -* ``` -*/ -const hexToBytes$1 = (hex) => hexToBytes$2(hex); -/** -* Checks whether a value is a Uint8Array. -* @param a - Value to inspect. -* @returns `true` when `a` is a Uint8Array. -* @example -* Branch on byte input before decoding it. -* -* ```ts -* isBytes(new Uint8Array(1)); -* ``` -*/ -const isBytes$2 = isBytes$4; -/** -* Reads random bytes from the platform CSPRNG. -* @param bytesLength - Number of random bytes to read. -* @returns Fresh random bytes. -* @example -* Generate a random seed for a keypair. -* -* ```ts -* randomBytes(2); -* ``` -*/ -const randomBytes$2 = (bytesLength) => randomBytes$3(bytesLength); -const _0n$11 = /* @__PURE__ */ BigInt(0); -const _1n$8 = /* @__PURE__ */ BigInt(1); -const atitle = (title) => title ? `"${title}" ` : ""; -/** -* Validates that a flag is boolean. -* @param value - Value to validate. -* @param title - Optional field name. -* @returns Original value. -* @throws On wrong argument types. {@link TypeError} -* @example -* Reject non-boolean option flags early. -* -* ```ts -* abool(true); -* ``` -*/ -function abool$1(value, title = "") { - if (typeof value !== "boolean") throw new TypeError(atitle(title) + "expected boolean, got type=" + typeof value); - return value; -} -/** -* Validates that a value is a non-negative bigint or safe integer. -* @param n - Value to validate. -* @returns The same validated value. -* @throws On wrong argument ranges or values. {@link RangeError} -* @example -* Validate one integer-like value before serializing it. -* -* ```ts -* abignumber(1n); -* ``` -*/ -function abignumber(n) { - if (typeof n === "bigint") { - if (!isPosBig(n)) throw new RangeError("positive bigint expected, got " + n); - } else anumber$2(n); - return n; -} -/** -* Validates that a value is a safe integer. -* @param value - Integer to validate. -* @param title - Optional field name. -* @throws On wrong argument types. {@link TypeError} -* @throws On wrong argument ranges or values. {@link RangeError} -* @example -* Validate a window size before scalar arithmetic uses it. -* -* ```ts -* asafenumber(1); -* ``` -*/ -function asafenumber(value, title = "") { - if (typeof value !== "number") { - const prefix = title && `"${title}" `; - throw new TypeError(prefix + "expected number, got type=" + typeof value); - } - if (!Number.isSafeInteger(value)) { - const prefix = title && `"${title}" `; - throw new RangeError(prefix + "expected safe integer, got " + value); - } -} -/** -* Encodes a bigint into even-length big-endian hex. -* The historical "unpadded" name only means "no fixed-width field padding"; odd-length hex still -* gets one leading zero nibble so the result always represents whole bytes. -* @param num - Number to encode. -* @returns Big-endian hex string. -* @throws On wrong argument ranges or values. {@link RangeError} -* @example -* Encode a scalar into hex without a `0x` prefix. -* -* ```ts -* numberToHexUnpadded(255n); -* ``` -*/ -function numberToHexUnpadded(num) { - const hex = abignumber(num).toString(16); - return hex.length & 1 ? "0" + hex : hex; -} -/** -* Parses a big-endian hex string into bigint. -* Accepts odd-length hex through the native `BigInt('0x' + hex)` parser and currently surfaces the -* same native `SyntaxError` for malformed hex instead of wrapping it in a library-specific error. -* @param hex - Hex string without `0x`. -* @returns Parsed bigint value. -* @throws On wrong argument types. {@link TypeError} -* @example -* Parse a scalar from fixture hex. -* -* ```ts -* hexToNumber('ff'); -* ``` -*/ -function hexToNumber(hex) { - if (typeof hex !== "string") throw new TypeError("hex string expected, got " + typeof hex); - return hex === "" ? _0n$11 : BigInt("0x" + hex); -} -/** -* Parses big-endian bytes into bigint. -* @param bytes - Bytes in big-endian order. -* @returns Parsed bigint value. -* @throws On wrong argument types. {@link TypeError} -* @example -* Read a scalar encoded in network byte order. -* -* ```ts -* bytesToNumberBE(Uint8Array.of(1, 0)); -* ``` -*/ -function bytesToNumberBE(bytes) { - return hexToNumber(bytesToHex$3(bytes)); -} -/** -* Parses little-endian bytes into bigint. -* @param bytes - Bytes in little-endian order. -* @returns Parsed bigint value. -* @throws On wrong argument types. {@link TypeError} -* @example -* Read a scalar encoded in little-endian form. -* -* ```ts -* bytesToNumberLE(Uint8Array.of(1, 0)); -* ``` -*/ -function bytesToNumberLE(bytes) { - return hexToNumber(bytesToHex$3(copyBytes$1(abytes$5(bytes)).reverse())); -} -/** -* Encodes a bigint into fixed-length big-endian bytes. -* @param n - Number to encode. -* @param len - Output length in bytes. Must be greater than zero. -* @returns Big-endian byte array. -* @throws On wrong argument ranges or values. {@link RangeError} -* @throws If a documented runtime validation or state check fails. {@link Error} -* @example -* Serialize a scalar into a 32-byte field element. -* -* ```ts -* numberToBytesBE(255n, 2); -* ``` -*/ -function numberToBytesBE(n, len) { - anumber$4(len); - if (len === 0) throw new Error("zero output length is invalid"); - n = abignumber(n); - const expectedLen = len * 2; - const hex = n.toString(16); - if (hex.length > expectedLen) throw new RangeError("number is too large"); - return hexToBytes$2(hex.padStart(expectedLen, "0")); -} -/** -* Encodes a bigint into fixed-length little-endian bytes. -* @param n - Number to encode. -* @param len - Output length in bytes. -* @returns Little-endian byte array. -* @throws On wrong argument ranges or values. {@link RangeError} -* @throws If a documented runtime validation or state check fails. {@link Error} -* @example -* Serialize a scalar for little-endian protocols. -* -* ```ts -* numberToBytesLE(255n, 2); -* ``` -*/ -function numberToBytesLE(n, len) { - return numberToBytesBE(n, len).reverse(); -} -/** -* Compares two byte arrays in constant-ish time. -* @param a - Left byte array. -* @param b - Right byte array. -* @returns `true` when bytes match. -* @example -* Compare two encoded points without early exit. -* -* ```ts -* equalBytes(Uint8Array.of(1), Uint8Array.of(1)); -* ``` -*/ -function equalBytes$1(a, b) { - a = abytes$3(a); - b = abytes$3(b); - if (a.length !== b.length) return false; - let diff = 0; - for (let i = 0; i < a.length; i++) diff |= a[i] ^ b[i]; - return diff === 0; -} -/** -* Copies Uint8Array. We can't use u8a.slice(), because u8a can be Buffer, -* and Buffer#slice creates mutable copy. Never use Buffers! -* @param bytes - Bytes to copy. -* @returns Detached copy. -* @example -* Make an isolated copy before mutating serialized bytes. -* -* ```ts -* copyBytes(Uint8Array.of(1, 2, 3)); -* ``` -*/ -function copyBytes$1(bytes) { - return Uint8Array.from(abytes$3(bytes)); -} -/** -* Decodes 7-bit ASCII string to Uint8Array, throws on non-ascii symbols -* Should be safe to use for things expected to be ASCII. -* Returns exact same result as `TextEncoder` for ASCII or throws. -* @param ascii - ASCII input text. -* @returns Encoded bytes. -* @throws On wrong argument types. {@link TypeError} -* @example -* Encode an ASCII domain-separation tag. -* -* ```ts -* asciiToBytes('ABC'); -* ``` -*/ -function asciiToBytes(ascii) { - if (typeof ascii !== "string") throw new TypeError("ascii string expected, got " + typeof ascii); - return Uint8Array.from(ascii, (c, i) => { - const charCode = c.charCodeAt(0); - if (c.length !== 1 || charCode > 127) throw new RangeError(`string contains non-ASCII character "${ascii[i]}" with code ${charCode} at position ${i}`); - return charCode; - }); -} -/** -* Checks whether n is non-negative bigint. Historical name. -* @param n - candidate value -* @returns `true` when the value is bigint and 0 or larger -* @example -* Check a candidate scalar before range validation. -* -* ```ts -* isPosBig(2n); -* ``` -*/ -function isPosBig(n) { - return typeof n === "bigint" && _0n$11 <= n; -} -/** -* Checks whether a bigint lies inside a half-open range. -* @param n - Candidate value. -* @param min - Inclusive lower bound. -* @param max - Exclusive upper bound. -* @returns `true` when the value is inside the range. -* @example -* Check whether a candidate scalar fits the field order. -* -* ```ts -* inRange(2n, 1n, 3n); -* ``` -*/ -function inRange(n, min, max) { - return isPosBig(n) && isPosBig(min) && isPosBig(max) && min <= n && n < max; -} -/** -* Asserts `min <= n < max`. NOTE: upper bound is exclusive. -* @param title - Value label for error messages. -* @param n - Candidate value. -* @param min - Inclusive lower bound. -* @param max - Exclusive upper bound. -* Wrong-type inputs are not separated from out-of-range values here: they still flow through the -* shared `RangeError` path because this is only a throwing wrapper around `inRange(...)`. -* @throws On wrong argument ranges or values. {@link RangeError} -* @example -* Assert that a bigint stays within one half-open range. -* -* ```ts -* aInRange('x', 2n, 1n, 256n); -* ``` -*/ -function aInRange(title, n, min, max) { - if (!inRange(n, min, max)) throw new RangeError("expected valid " + title + ": " + min + " <= n < " + max + ", got " + n); -} -/** -* Calculates amount of bits in a bigint. -* Same as `n.toString(2).length` -* TODO: merge with nLength in modular -* @param n - Value to inspect. -* @returns Bit length. -* @throws If the value is negative. {@link Error} -* @example -* Measure the bit length of a scalar before serialization. -* -* ```ts -* bitLen(8n); -* ``` -*/ -function bitLen(n) { - if (n < _0n$11) throw new Error("expected non-negative bigint, got " + n); - return n === _0n$11 ? 0 : n.toString(2).length; -} -/** -* Calculate mask for N bits. Not using ** operator with bigints because of old engines. -* Same as BigInt(`0b${Array(i).fill('1').join('')}`) -* @param n - Number of bits. Negative widths are currently passed through to raw bigint shift -* semantics and therefore produce `-1n`. -* @returns Bitmask value. -* @example -* Calculate mask for N bits. -* -* ```ts -* bitMask(4); -* ``` -*/ -const bitMask = (n) => { - asafenumber(n, "n"); - return (_1n$8 << BigInt(n)) - _1n$8; -}; -/** -* Minimal HMAC-DRBG from NIST 800-90 for RFC6979 sigs. -* @param hashLen - Hash output size in bytes. Callers are expected to pass a positive length; `0` -* is not rejected here and would make the internal generate loop non-progressing. -* @param qByteLen - Requested output size in bytes. Callers are expected to pass a positive length. -* @param hmacFn - HMAC implementation. -* @returns Function that will call DRBG until the predicate returns anything -* other than `undefined`. -* @throws On wrong argument types. {@link TypeError} -* @example -* Build a deterministic nonce generator for RFC6979-style signing. -* -* ```ts -* import { createHmacDrbg } from '@noble/curves/utils.js'; -* import { hmac } from '@noble/hashes/hmac.js'; -* import { sha256 } from '@noble/hashes/sha2.js'; -* const hmacFn = (key: Uint8Array, msg: Uint8Array) => hmac(sha256, key, msg); -* const drbg = createHmacDrbg(32, 32, hmacFn); -* const seed = new Uint8Array(32); -* drbg(seed, (bytes) => bytes); -* ``` -*/ -function createHmacDrbg(hashLen, qByteLen, hmacFn) { - anumber$4(hashLen, "hashLen"); - anumber$4(qByteLen, "qByteLen"); - if (typeof hmacFn !== "function") throw new TypeError("hmacFn must be a function"); - const u8n = (len) => new Uint8Array(len); - const NULL = Uint8Array.of(); - const byte0 = Uint8Array.of(0); - const byte1 = Uint8Array.of(1); - const _maxDrbgIters = 1e3; - let v = u8n(hashLen); - let k = u8n(hashLen); - let i = 0; - const reset = () => { - v.fill(1); - k.fill(0); - i = 0; - }; - const h = (...msgs) => hmacFn(k, concatBytes$2(v, ...msgs)); - const reseed = (seed = NULL) => { - k = h(byte0, seed); - v = h(); - if (seed.length === 0) return; - k = h(byte1, seed); - v = h(); - }; - const gen = () => { - if (i++ >= _maxDrbgIters) throw new Error("drbg: tried max amount of iterations"); - let len = 0; - const out = []; - while (len < qByteLen) { - v = h(); - const sl = v.slice(); - out.push(sl); - len += v.length; - } - return concatBytes$2(...out); - }; - const genUntil = (seed, pred) => { - reset(); - reseed(seed); - let res = void 0; - while ((res = pred(gen())) === void 0) reseed(); - reset(); - return res; - }; - return genUntil; -} -/** -* Validates declared required and optional field types on a plain object. -* Extra keys are intentionally ignored because many callers validate only the subset they use from -* richer option bags or runtime objects. -* This walks field schemas and formats detailed errors, so avoid it on hot paths; use direct -* one-line guards such as `aobject()`, `afunction()`, `abool()`, or `asafenumber()` instead. -* @param object - Object to validate. -* @param fields - Required field types. -* @param optFields - Optional field types. -* @param title - Object label included in thrown errors. -* @throws On wrong argument types. {@link TypeError} -* @example -* Check user options before building a curve helper. -* -* ```ts -* validateObject({ flag: true }, { flag: 'boolean' }); -* ``` -*/ -function validateObject(object, fields = {}, optFields = {}, title = "object") { - aobject(object, title); - aobject(fields, "fields"); - aobject(optFields, "optFields"); - function checkField(fieldName, expectedType, isOpt) { - const label = title === "object" ? `param "${String(fieldName)}"` : `"${title}.${String(fieldName)}"`; - const val = object[fieldName]; - if (!Object.hasOwn(object, fieldName) && (isOpt ? val !== void 0 : expectedType !== "function")) throw new TypeError(`${label} is invalid: expected own property`); - if (isOpt && val === void 0) return; - const current = typeof val; - if (current !== expectedType || val === null) throw new TypeError(`${label} is invalid: expected ${expectedType}, got ${current}`); - } - const iter = (f, isOpt) => Object.entries(f).forEach(([k, v]) => checkField(k, v, isOpt)); - iter(fields, false); - iter(optFields, true); -} -/** -* Throws not implemented error. -* @returns Never returns. -* @throws If the unfinished code path is reached. {@link Error} -* @example -* Surface the placeholder error from an unfinished code path. -* -* ```ts -* try { -* notImplemented(); -* } catch {} -* ``` -*/ -const notImplemented = () => { - throw new Error("not implemented"); -}; -//#endregion -//#region tests/baseline/node_modules/@noble/curves/abstract/modular.js -/** -* Utils for modular division and fields. -* Field over 11 is a finite (Galois) field is integer number operations `mod 11`. -* There is no division: it is replaced by modular multiplicative inverse. -* @module -*/ -/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ -const _0n$10 = /* @__PURE__ */ BigInt(0); -const _1n$7 = /* @__PURE__ */ BigInt(1); -const _2n$7 = /* @__PURE__ */ BigInt(2); -const _3n$3 = /* @__PURE__ */ BigInt(3); -const _4n$3 = /* @__PURE__ */ BigInt(4); -const _5n$1 = /* @__PURE__ */ BigInt(5); -const _7n$2 = /* @__PURE__ */ BigInt(7); -const _8n$2 = /* @__PURE__ */ BigInt(8); -const _9n = /* @__PURE__ */ BigInt(9); -const _15n = /* @__PURE__ */ BigInt(15); -const _16n = /* @__PURE__ */ BigInt(16); -const POW_WINDOWED_MIN = /* @__PURE__ */ BigInt("0x10000000000000000"); -/** -* @param a - Dividend value. -* @param b - Positive modulus. -* @returns Reduced value in `[0, b)` only when `b` is positive. -* @throws If the modulus is not positive. {@link Error} -* @example -* Normalize a bigint into one field residue. -* -* ```ts -* mod(-1n, 5n); -* ``` -*/ -function mod(a, b) { - if (b <= _0n$10) throw new Error("mod: expected positive modulus, got " + b); - const result = a % b; - return result >= _0n$10 ? result : b + result; -} -/** -* Efficiently raise num to a power with modular reduction. -* Unsafe in some contexts: uses ladder, so can expose bigint bits. -* Low-level helper: callers that need canonical residues must pass a valid `num` for the chosen -* modulus instead of relying on the `power===0/1` fast paths to normalize it. -* @param num - Base value. -* @param power - Exponent value. -* @param modulo - Reduction modulus. -* @returns Modular exponentiation result. -* @throws If the modulus or exponent is invalid. {@link Error} -* @example -* Raise one bigint to a modular power. -* -* ```ts -* pow(2n, 6n, 11n) // 64n % 11n == 9n -* ``` -*/ -function pow(num, power, modulo) { - if (modulo <= _1n$7) throw new Error("pow: expected modulus > 1, got " + modulo); - if (typeof power !== "bigint") throw new TypeError("invalid exponent: expected bigint, got " + typeof power); - if (power < _0n$10) throw new Error("invalid exponent, negatives unsupported"); - if (power === _0n$10) return _1n$7; - if (power === _1n$7) return num; - let d = num % modulo; - if (d < _0n$10) d += modulo; - if (power < POW_WINDOWED_MIN) { - let p = _1n$7; - while (power > _0n$10) { - if (power & _1n$7) p = p * d % modulo; - d = d * d % modulo; - power >>= _1n$7; - } - return p; - } - const digits = []; - while (power > _0n$10) { - digits.push(Number(power & _15n)); - power >>= _4n$3; - } - const table = new Array(16); - table[0] = _1n$7; - table[1] = d; - for (let i = 2; i < 16; i++) table[i] = table[i - 1] * d % modulo; - let p = table[digits[digits.length - 1]]; - for (let w = digits.length - 2; w >= 0; w--) { - p = p * p % modulo; - p = p * p % modulo; - p = p * p % modulo; - p = p * p % modulo; - const digit = digits[w]; - if (digit !== 0) p = p * table[digit] % modulo; - } - return p; -} -/** -* Does `x^(2^power)` mod p. `pow2(30, 4)` == `30^(2^4)`. -* Low-level helper: callers that need canonical residues must pass a valid `x` for the chosen -* modulus; the `power===0` fast path intentionally returns the input unchanged. -* @param x - Base value. -* @param power - Number of squarings. -* @param modulo - Reduction modulus. -* @returns Repeated-squaring result. -* @throws If the exponent is negative. {@link Error} -* @example -* Apply repeated squaring inside one field. -* -* ```ts -* pow2(3n, 2n, 11n); -* ``` -*/ -function pow2(x, power, modulo) { - if (modulo <= _1n$7) throw new Error("pow2: expected modulus > 1, got " + modulo); - if (power < _0n$10) throw new Error("pow2: expected non-negative exponent, got " + power); - let res = x; - while (power-- > _0n$10) { - res *= res; - res %= modulo; - } - return res; -} -/** -* Inverses number over modulo. -* Implemented using the {@link https://brilliant.org/wiki/extended-euclidean-algorithm/ | extended Euclidean algorithm}. -* @param number - Value to invert. -* @param modulo - Modulus greater than 1. -* @returns Multiplicative inverse. -* @throws If the modulus is invalid or the inverse does not exist. {@link Error} -* @example -* Compute one modular inverse with the extended Euclidean algorithm. -* -* ```ts -* invert(3n, 11n); -* ``` -*/ -function invert(number, modulo) { - if (number === _0n$10) throw new Error("invert: expected non-zero number"); - if (modulo <= _1n$7) throw new Error("invert: expected modulus > 1, got " + modulo); - let a = mod(number, modulo); - let b = modulo; - let x = _0n$10, u = _1n$7; - while (a !== _0n$10) { - const q = b / a; - const r = b - a * q; - const m = x - u * q; - b = a, a = r, x = u, u = m; - } - if (b !== _1n$7) throw new Error("invert: does not exist"); - return mod(x, modulo); -} -/** -* Inverses number over modulo using Fermat's little theorem: `a^(p-2) ≡ a⁻¹ (mod p)`. -* -* Unlike {@link invert} (extended Euclidean), the exponent `p-2` is a public constant, so the -* underlying square-and-multiply has the same control flow for every secret `a`: there is no -* data-dependent branching or loop count that could leak `a` through timing (e.g. Minerva-style -* ECDSA nonce-inversion attacks). This is only "algorithmically" constant-time — JS bigint -* multiplication/reduction is still value-dependent — and it is roughly 4x slower than -* {@link invert}. -* -* REQUIRES a prime modulus; Fermat's theorem does not hold otherwise. The result is verified to be -* a real inverse, so a non-prime modulus (or a non-invertible input) fails closed with an error -* instead of returning a wrong value. -* @param a - Value to invert. -* @param prime - Prime modulus. -* @returns Multiplicative inverse in `[1, prime)`. -* @throws If the modulus is below 2, the input reduces to zero, or the inverse does not exist. -* {@link Error} -* @example -* Compute one modular inverse without secret-dependent branching. -* -* ```ts -* invertCt(3n, 11n); // 4n, since 3 * 4 = 12 ≡ 1 (mod 11) -* ``` -*/ -function invertCt(a, prime) { - if (prime <= _1n$7) throw new Error("invertCt: expected prime modulus > 1, got " + prime); - const an = mod(a, prime); - if (an === _0n$10) throw new Error("invertCt: expected non-zero number"); - const inverse = pow(an, prime - _2n$7, prime); - if (mod(an * inverse, prime) !== _1n$7) throw new Error("invertCt: does not exist"); - return inverse; -} -function assertIsSquare(Fp, root, n) { - const F = Fp; - if (!F.eql(F.sqr(root), n)) throw new Error("Cannot find square root"); -} -function aoddModulus(order, fnName) { - if ((order & _1n$7) === _0n$10) throw new Error(fnName + ": expected odd modulus, got " + order); -} -function sqrt3mod4(Fp, n) { - const F = Fp; - const p1div4 = (F.ORDER + _1n$7) / _4n$3; - const root = F.pow(n, p1div4); - assertIsSquare(F, root, n); - return root; -} -function sqrt5mod8(Fp, n) { - const F = Fp; - const p5div8 = (F.ORDER - _5n$1) / _8n$2; - const n2 = F.mul(n, _2n$7); - const v = F.pow(n2, p5div8); - const nv = F.mul(n, v); - const i = F.mul(F.mul(nv, _2n$7), v); - const root = F.mul(nv, F.sub(i, F.ONE)); - assertIsSquare(F, root, n); - return root; -} -function sqrt9mod16(P) { - const Fp_ = Field(P); - const tn = tonelliShanks(P); - const c1 = tn(Fp_, Fp_.neg(Fp_.ONE)); - const c2 = tn(Fp_, c1); - const c3 = tn(Fp_, Fp_.neg(c1)); - const c4 = (P + _7n$2) / _16n; - return ((Fp, n) => { - const F = Fp; - let tv1 = F.pow(n, c4); - let tv2 = F.mul(tv1, c1); - const tv3 = F.mul(tv1, c2); - const tv4 = F.mul(tv1, c3); - const e1 = F.eql(F.sqr(tv2), n); - const e2 = F.eql(F.sqr(tv3), n); - tv1 = F.cmov(tv1, tv2, e1); - tv2 = F.cmov(tv4, tv3, e2); - const e3 = F.eql(F.sqr(tv2), n); - const root = F.cmov(tv1, tv2, e3); - assertIsSquare(F, root, n); - return root; - }); -} -/** -* Tonelli-Shanks square root search algorithm. -* This implementation is variable-time: it searches data-dependently for the first non-residue `Z` -* and for the smallest `i` in the main loop, unlike RFC 9380 Appendix I.4's constant-time shape. -* 1. {@link https://eprint.iacr.org/2012/685.pdf | eprint 2012/685}, page 12 -* 2. Square Roots from 1; 24, 51, 10 to Dan Shanks -* @param P - field order -* @returns function that takes field Fp (created from P) and number n -* @throws If the field is too small, non-prime, or the square root does not exist. {@link Error} -* @example -* Construct a square-root helper for primes that need Tonelli-Shanks. -* -* ```ts -* import { Field, tonelliShanks } from '@noble/curves/abstract/modular.js'; -* const Fp = Field(17n); -* const sqrt = tonelliShanks(17n)(Fp, 4n); -* ``` -*/ -function tonelliShanks(P) { - if (P < _3n$3) throw new Error("sqrt is not defined for small field"); - aoddModulus(P, "tonelliShanks"); - let Q = P - _1n$7; - let S = 0; - while (Q % _2n$7 === _0n$10) { - Q /= _2n$7; - S++; - } - let Z = _2n$7; - const _Fp = Field(P); - while (FpLegendre(_Fp, Z) === 1) if (Z++ > 1e3) throw new Error("Cannot find square root: probably non-prime P"); - if (S === 1) return sqrt3mod4; - let cc = _Fp.pow(Z, Q); - const Q1div2 = (Q + _1n$7) / _2n$7; - return function tonelliSlow(Fp, n) { - const F = Fp; - if (F.is0(n)) return n; - if (FpLegendre(F, n) !== 1) throw new Error("Cannot find square root"); - let M = S; - let c = F.mul(F.ONE, cc); - let t = F.pow(n, Q); - let R = F.pow(n, Q1div2); - while (!F.eql(t, F.ONE)) { - if (F.is0(t)) throw new Error("Cannot find square root: probably non-prime P"); - let i = 1; - let t_tmp = F.sqr(t); - while (!F.eql(t_tmp, F.ONE)) { - i++; - t_tmp = F.sqr(t_tmp); - if (i === M) throw new Error("Cannot find square root"); - } - const exponent = _1n$7 << BigInt(M - i - 1); - const b = F.pow(c, exponent); - M = i; - c = F.sqr(b); - t = F.mul(t, c); - R = F.mul(R, b); - } - return R; - }; -} -/** -* Square root for a finite field. Will try optimized versions first: -* -* 1. P ≡ 3 (mod 4) -* 2. P ≡ 5 (mod 8) -* 3. P ≡ 9 (mod 16) -* 4. Tonelli-Shanks algorithm -* -* Different algorithms can give different roots, it is up to user to decide which one they want. -* For example there is FpSqrtOdd/FpSqrtEven to choose a root by oddness -* (used for hash-to-curve). -* @param P - Field order. -* @returns Square-root helper. The generic fallback inherits Tonelli-Shanks' variable-time -* behavior and this selector assumes prime-field-style integer moduli. -* @throws If the field is unsupported or the square root does not exist. {@link Error} -* @example -* Choose the square-root helper appropriate for one field modulus. -* -* ```ts -* import { Field, FpSqrt } from '@noble/curves/abstract/modular.js'; -* const Fp = Field(17n); -* const sqrt = FpSqrt(17n)(Fp, 4n); -* ``` -*/ -function FpSqrt(P) { - aoddModulus(P, "Fp.sqrt"); - if (P % _4n$3 === _3n$3) return sqrt3mod4; - if (P % _8n$2 === _5n$1) return sqrt5mod8; - if (P % _16n === _9n) return sqrt9mod16(P); - return tonelliShanks(P); -} -/** -* @param num - Value to inspect. -* @param modulo - Field modulus. -* @returns `true` when the least-significant little-endian bit is set. -* @throws If the modulus is invalid for `mod(...)`. {@link Error} -* @example -* Inspect the low bit used by little-endian sign conventions. -* -* ```ts -* isNegativeLE(3n, 11n); -* ``` -*/ -const isNegativeLE = (num, modulo) => (mod(num, modulo) & _1n$7) === _1n$7; -const FIELD_FIELDS = [ - "create", - "isValid", - "is0", - "neg", - "inv", - "sqrt", - "sqr", - "eql", - "add", - "sub", - "mul", - "pow", - "div", - "addN", - "subN", - "mulN", - "sqrN" -]; -/** -* @param field - Field implementation. -* @returns Validated field. This only checks the arithmetic subset needed by generic helpers; it -* does not guarantee full runtime-method coverage for serialization, batching, `cmov`, or -* field-specific extras beyond positive `BYTES` / `BITS`. -* @throws If the field shape or numeric metadata are invalid. {@link Error} -* @example -* Check that a field implementation exposes the operations curve code expects. -* -* ```ts -* import { Field, validateField } from '@noble/curves/abstract/modular.js'; -* const Fp = validateField(Field(17n)); -* ``` -*/ -function validateField(field) { - aobject(field, "field"); - if (typeof field.ORDER !== "bigint") throw new TypeError("param \"ORDER\" is invalid: expected bigint, got " + typeof field.ORDER); - asafenumber(field.BYTES, "BYTES"); - asafenumber(field.BITS, "BITS"); - for (const name of FIELD_FIELDS) afunction(field[name], "field." + name); - if (field.BYTES < 1 || field.BITS < 1) throw new Error("invalid field: expected BYTES/BITS > 0"); - if (field.ORDER <= _1n$7) throw new Error("invalid field: expected ORDER > 1, got " + field.ORDER); - return field; -} -function FpInvertBatch(Fp, nums, passZero = false) { - validateField(Fp); - aarray(nums, "nums"); - abool$1(passZero, "passZero"); - const F = Fp; - const inverted = new Array(nums.length).fill(passZero ? F.ZERO : void 0); - const multipliedAcc = nums.reduce((acc, num, i) => { - if (F.is0(num)) return acc; - inverted[i] = acc; - return F.mul(acc, num); - }, F.ONE); - const invertedAcc = F.inv(multipliedAcc); - nums.reduceRight((acc, num, i) => { - if (F.is0(num)) return acc; - inverted[i] = F.mul(acc, inverted[i]); - return F.mul(acc, num); - }, invertedAcc); - return inverted; -} -/** -* Legendre symbol. -* Legendre constant is used to calculate Legendre symbol (a | p) -* which denotes the value of a^((p-1)/2) (mod p). -* -* * (a | p) ≡ 1 if a is a square (mod p), quadratic residue -* * (a | p) ≡ -1 if a is not a square (mod p), quadratic non residue -* * (a | p) ≡ 0 if a ≡ 0 (mod p) -* @param Fp - Field implementation. -* @param n - Value to inspect. -* @returns Legendre symbol. -* @throws If the powered value does not match a valid Legendre symbol. {@link Error} -* @example -* Compute the Legendre symbol of one field element. -* -* ```ts -* import { Field, FpLegendre } from '@noble/curves/abstract/modular.js'; -* const Fp = Field(17n); -* const symbol = FpLegendre(Fp, 4n); -* ``` -*/ -function FpLegendre(Fp, n) { - validateField(Fp); - const F = Fp; - aoddModulus(F.ORDER, "FpLegendre"); - const p1mod2 = (F.ORDER - _1n$7) / _2n$7; - const powered = F.pow(n, p1mod2); - const yes = F.eql(powered, F.ONE); - const zero = F.eql(powered, F.ZERO); - const no = F.eql(powered, F.neg(F.ONE)); - if (!yes && !zero && !no) throw new Error("invalid Legendre symbol result"); - return yes ? 1 : zero ? 0 : -1; -} -/** -* @param n - Curve order. Callers are expected to pass a positive order. -* @param nBitLength - Optional cached bit length. Callers are expected to pass a positive cached -* value when overriding the derived bit length. -* @returns Byte and bit lengths. -* @throws If the order or cached bit length is invalid. {@link Error} -* @example -* Measure the encoding sizes needed for one modulus. -* -* ```ts -* nLength(255n); -* ``` -*/ -function nLength(n, nBitLength) { - if (nBitLength !== void 0) anumber$2(nBitLength); - if (n <= _0n$10) throw new Error("invalid n length: expected positive n, got " + n); - if (nBitLength !== void 0 && nBitLength < 1) throw new Error("invalid n length: expected positive bit length, got " + nBitLength); - const bits = bitLen(n); - if (nBitLength !== void 0 && nBitLength < bits) throw new Error(`invalid n length: expected nBitLength (${nBitLength}) >= bitLen(n) (${bits})`); - const _nBitLength = nBitLength !== void 0 ? nBitLength : bits; - return { - nBitLength: _nBitLength, - nByteLength: Math.ceil(_nBitLength / 8) - }; -} -const FIELD_SQRT = /* @__PURE__ */ new WeakMap(); -var _Field = class { - ORDER; - BITS; - BYTES; - isLE; - ZERO = _0n$10; - ONE = _1n$7; - _lengths; - _mod; - constructor(ORDER, opts = {}) { - if (ORDER <= _1n$7) throw new Error("invalid field: expected ORDER > 1, got " + ORDER); - let _nbitLength = void 0; - this.isLE = false; - if (opts != null && typeof opts === "object") { - if (typeof opts.BITS === "number") _nbitLength = opts.BITS; - if (typeof opts.sqrt === "function") Object.defineProperty(this, "sqrt", { - value: opts.sqrt, - enumerable: true - }); - if (typeof opts.isLE === "boolean") this.isLE = opts.isLE; - if (opts.allowedLengths) this._lengths = Object.freeze(opts.allowedLengths.slice()); - if (typeof opts.modFromBytes === "boolean") this._mod = opts.modFromBytes; - } - const { nBitLength, nByteLength } = nLength(ORDER, _nbitLength); - if (nByteLength > 2048) throw new Error("invalid field: expected ORDER of <= 2048 bytes"); - this.ORDER = ORDER; - this.BITS = nBitLength; - this.BYTES = nByteLength; - Object.freeze(this); - } - create(num) { - return mod(num, this.ORDER); - } - isValid(num) { - if (typeof num !== "bigint") throw new TypeError("invalid field element: expected bigint, got " + typeof num); - return _0n$10 <= num && num < this.ORDER; - } - is0(num) { - return num === _0n$10; - } - isValidNot0(num) { - return !this.is0(num) && this.isValid(num); - } - isOdd(num) { - return (num & _1n$7) === _1n$7; - } - neg(num) { - return mod(-num, this.ORDER); - } - eql(lhs, rhs) { - return lhs === rhs; - } - sqr(num) { - return mod(num * num, this.ORDER); - } - add(lhs, rhs) { - return mod(lhs + rhs, this.ORDER); - } - sub(lhs, rhs) { - return mod(lhs - rhs, this.ORDER); - } - mul(lhs, rhs) { - return mod(lhs * rhs, this.ORDER); - } - pow(num, power) { - return pow(num, power, this.ORDER); - } - div(lhs, rhs) { - return mod(lhs * invert(rhs, this.ORDER), this.ORDER); - } - sqrN(num) { - return num * num; - } - addN(lhs, rhs) { - return lhs + rhs; - } - subN(lhs, rhs) { - return lhs - rhs; - } - mulN(lhs, rhs) { - return lhs * rhs; - } - inv(num) { - return invert(num, this.ORDER); - } - sqrt(num) { - let sqrt = FIELD_SQRT.get(this); - if (!sqrt) FIELD_SQRT.set(this, sqrt = FpSqrt(this.ORDER)); - return sqrt(this, num); - } - toBytes(num) { - return this.isLE ? numberToBytesLE(num, this.BYTES) : numberToBytesBE(num, this.BYTES); - } - fromBytes(bytes, skipValidation = false) { - abytes$3(bytes); - const { _lengths: allowedLengths, BYTES, isLE, ORDER, _mod: modFromBytes } = this; - if (allowedLengths) { - if (bytes.length < 1 || !allowedLengths.includes(bytes.length) || bytes.length > BYTES) throw new Error("Field.fromBytes: expected " + allowedLengths + " bytes, got " + bytes.length); - const padded = new Uint8Array(BYTES); - padded.set(bytes, isLE ? 0 : padded.length - bytes.length); - bytes = padded; - } - if (bytes.length !== BYTES) throw new Error("Field.fromBytes: expected " + BYTES + " bytes, got " + bytes.length); - let scalar = isLE ? bytesToNumberLE(bytes) : bytesToNumberBE(bytes); - if (modFromBytes) scalar = mod(scalar, ORDER); - if (!skipValidation) { - if (!this.isValid(scalar)) throw new Error("invalid field element: outside of range 0..ORDER"); - } - return scalar; - } - invertBatch(lst) { - return FpInvertBatch(this, lst, true); - } - cmov(a, b, condition) { - abool$1(condition, "condition"); - return condition ? b : a; - } -}; -/** -* Creates a finite field. Major performance optimizations: -* * 1. Denormalized operations like mulN instead of mul. -* * 2. Identical object shape: never add or remove keys. -* * 3. Frozen stable object shape; the lazy sqrt cache lives in a module-level `WeakMap`. -* Fragile: always run a benchmark on a change. -* Security note: operations and low-level serializers like `toBytes` don't check `isValid` for -* all elements for performance and protocol-flexibility reasons; callers are responsible for -* supplying valid elements when they need canonical field behavior. -* This is low-level code, please make sure you know what you're doing. -* -* Note about field properties: -* * CHARACTERISTIC p = prime number, number of elements in main subgroup. -* * ORDER q = similar to cofactor in curves, may be composite `q = p^m`. -* -* @param ORDER - field order, probably prime, or could be composite -* @param opts - Field options such as bit length or endianness. See {@link FieldOpts}. -* @returns Frozen field instance with a stable object shape. This wrapper forwards `opts` straight -* into `_Field`, so it inherits `_Field`'s assumptions about cached sizes and `allowedLengths`. -* @example -* Construct one prime field with optional overrides. -* -* ```ts -* Field(11n); -* ``` -*/ -function Field(ORDER, opts = {}) { - Object.freeze(_Field.prototype); - return new _Field(ORDER, opts); -} -/** -* Returns total number of bytes consumed by the field element. -* For example, 32 bytes for usual 256-bit weierstrass curve. -* @param fieldOrder - number of field elements, usually CURVE.n. Callers are expected to pass an -* order greater than 1. -* @returns byte length of field -* @throws If the field order is not a bigint. {@link Error} -* @example -* Read the fixed-width byte length of one field. -* -* ```ts -* getFieldBytesLength(255n); -* ``` -*/ -function getFieldBytesLength(fieldOrder) { - if (typeof fieldOrder !== "bigint") throw new Error("field order must be bigint"); - if (fieldOrder <= _1n$7) throw new Error("field order must be greater than 1"); - const bitLength = bitLen(fieldOrder - _1n$7); - return Math.ceil(bitLength / 8); -} -/** -* Returns minimal amount of bytes that can be safely reduced -* by field order. -* Should be 2^-128 for 128-bit curve such as P256. -* This is the reduction / modulo-bias lower bound; higher-level helpers may still impose a larger -* absolute floor for policy reasons. -* @param fieldOrder - number of field elements greater than 1, usually CURVE.n. -* @returns byte length of target hash -* @throws If the field order is invalid. {@link Error} -* @example -* Compute the minimum hash length needed for field reduction. -* -* ```ts -* getMinHashLength(255n); -* ``` -*/ -function getMinHashLength(fieldOrder) { - const length = getFieldBytesLength(fieldOrder); - return length + Math.ceil(length / 2); -} -/** -* "Constant-time" private key generation utility. -* Can take (n + n/2) or more bytes of uniform input e.g. from CSPRNG or KDF -* and convert them into private scalar, with the modulo bias being negligible. -* Needs at least 48 bytes of input for 32-byte private key. The implementation also keeps a hard -* 16-byte minimum even when `getMinHashLength(...)` is smaller, so toy-small inputs do not look -* accidentally acceptable for real scalar derivation. -* See {@link https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/ | Kudelski's modulo-bias guide}, -* {@link https://csrc.nist.gov/publications/detail/fips/186/5/final | FIPS 186-5 appendix A.2}, and -* {@link https://www.rfc-editor.org/rfc/rfc9380#section-5 | RFC 9380 section 5}. Unlike RFC 9380 -* `hash_to_field`, this helper intentionally maps into the non-zero private-scalar range `1..n-1`. -* @param key - Uniform input bytes. -* @param fieldOrder - Size of subgroup. -* @param isLE - interpret hash bytes as LE num -* @returns valid private scalar -* @throws If the hash length or field order is invalid for scalar reduction. {@link Error} -* @example -* Map hash output into a private scalar range. -* -* ```ts -* mapHashToField(new Uint8Array(48).fill(1), 255n); -* ``` -*/ -function mapHashToField(key, fieldOrder, isLE = false) { - abytes$3(key); - const len = key.length; - const fieldLen = getFieldBytesLength(fieldOrder); - const minLen = Math.max(getMinHashLength(fieldOrder), 16); - if (len < minLen || len > 1024) throw new Error("expected " + minLen + "-1024 bytes of input, got " + len); - const reduced = mod(isLE ? bytesToNumberLE(key) : bytesToNumberBE(key), fieldOrder - _1n$7) + _1n$7; - return isLE ? numberToBytesLE(reduced, fieldLen) : numberToBytesBE(reduced, fieldLen); -} -//#endregion -//#region tests/baseline/node_modules/@noble/curves/abstract/curve.js -/** -* Methods for elliptic curve multiplication by scalars. -* Contains wNAF-based ScalarMultiplier, pippenger. -* @module -*/ -/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ -const _0n$9 = /* @__PURE__ */ BigInt(0); -const _1n$6 = /* @__PURE__ */ BigInt(1); -const _4n$2 = /* @__PURE__ */ BigInt(4); -const BLIND_BYTES = 16; -const BLIND_BITS = 128; -const FW_WINDOW = 5; -const TABLE_BYTES_MAX = /* @__PURE__ */ (() => 2 ** 31)(); -/** -* Validates the static surface of a point constructor. -* This is only a cheap sanity check for the constructor hooks and fields consumed by generic -* factories; it does not certify `BASE`/`ZERO` semantics or prove the curve implementation itself. -* @param Point - Runtime point constructor. -* @throws On missing constructor hooks or malformed field metadata. {@link TypeError} -* @example -* Check that one point constructor exposes the static hooks generic helpers need. -* -* ```ts -* import { ed25519 } from '@noble/curves/ed25519.js'; -* import { validatePointCons } from '@noble/curves/abstract/curve.js'; -* validatePointCons(ed25519.Point); -* ``` -*/ -function validatePointCons(Point) { - const pc = Point; - if (typeof pc !== "function") throw new TypeError("\"Point\" expected constructor, got type=" + typeof Point); - afunction(pc.fromAffine, "Point.fromAffine"); - afunction(pc.fromBytes, "Point.fromBytes"); - afunction(pc.fromHex, "Point.fromHex"); - aobject(pc.BASE, "Point.BASE"); - aobject(pc.ZERO, "Point.ZERO"); - validateField(pc.Fp); - validateField(pc.Fn); -} -/** -* Takes a bunch of Projective Points but executes only one -* inversion on all of them. Inversion is very slow operation, -* so this improves performance massively. -* Optimization: converts a list of projective points to a list of identical points with Z=1. -* Input points are left unchanged; the normalized points are returned as fresh instances. -* @param c - Point constructor. -* @param points - Projective points. -* @returns Fresh projective points reconstructed from normalized affine coordinates. -* @example -* Batch-normalize projective points with a single shared inversion. -* -* ```ts -* import { normalizeZ } from '@noble/curves/abstract/curve.js'; -* import { p256 } from '@noble/curves/nist.js'; -* const points = normalizeZ(p256.Point, [p256.Point.BASE, p256.Point.BASE.double()]); -* ``` -*/ -function normalizeZ(c, points) { - validatePointCons(c); - validateMSMPoints(points, c); - const invertedZs = FpInvertBatch(c.Fp, points.map((p) => p.Z)); - return points.map((p, i) => c.fromAffine(p.toAffine(invertedZs[i]))); -} -function validateW(W, bits, min = 1) { - if (!Number.isSafeInteger(W) || W < min || W > bits) throw new Error("invalid window size, expected [" + min + ".." + bits + "], got W=" + W); -} -function validateTableBytes(numPoints, fpBytes) { - const bytes = numPoints * (4 * fpBytes + 128); - if (bytes > TABLE_BYTES_MAX) throw new Error("invalid window size: table would need ~" + Math.ceil(bytes / 2 ** 20) + " MiB, max " + TABLE_BYTES_MAX / 2 ** 20 + " MiB"); -} -/** -* Probes an RNG once, at construction time: returns `undefined` when it is unavailable — -* throws or returns malformed bytes — so callers can downgrade to their unblinded / -* deterministic constant-time fallback. Blinding is defense-in-depth (DPA/template -* hardening), not a correctness or key-secrecy requirement, so availability-based -* downgrade is acceptable. -* -* The downgrade decision is deliberately static. After a successful probe the RNG becomes -* part of the trusted contract: later misbehavior must fail closed in per-call validation -* (throw), never downgrade — a dynamic fallback would let a tampered RNG silently strip -* blinding on demand. A probe can only ever classify broken environments, not adversarial -* RNGs: a stateful RNG can always behave while probed and misbehave later. -* @param randomBytes - RNG to probe, or `undefined` when the environment provides none. -* @param length - Byte length requested from the probe call. -* @returns The RNG when the probe produced `length` valid bytes; `undefined` otherwise. -* @example -* Probe an RNG once before enabling scalar blinding. -* -* ```ts -* import { probeRandomBytes } from '@noble/curves/abstract/curve.js'; -* import { randomBytes } from '@noble/hashes/utils.js'; -* const rng = probeRandomBytes(randomBytes, 16); -* ``` -*/ -function probeRandomBytes(randomBytes, length) { - if (randomBytes === void 0) return void 0; - afunction(randomBytes, "randomBytes"); - try { - const probe = randomBytes(length); - if (!isBytes$2(probe) || probe.length !== length) return void 0; - } catch { - return; - } - return randomBytes; -} -function validateMSMPoints(points, c) { - aarray(points, "points"); - points.forEach((p, i) => { - if (!(p instanceof c)) throw new Error("invalid point at index " + i); - }); -} -function validateMSMScalars(scalars, field, maxScalar) { - if (!Array.isArray(scalars)) throw new Error("array of scalars expected"); - scalars.forEach((s, i) => { - if (!(maxScalar === void 0 ? field.isValid(s) : isPosBig(s) && s < maxScalar)) throw new Error("invalid scalar at index " + i); - }); -} -const pointWindowSizes = /* @__PURE__ */ new WeakMap(); -function getWindowSize(P) { - return pointWindowSizes.get(P) || 1; -} -/** Table of odd multiples [1P, 3P, ..., (2⋅size−1)P]; width-W wNAF uses size = 2^(W−2). */ -function oddMultiples(p, size) { - const dbl = p.double(); - const t = [p]; - for (let j = 1; j < size; j++) t.push(t[j - 1].add(dbl)); - return t; -} -/** -* Width-W wNAF signed-digit recoding (W >= 2), LSB-first: digits are 0 or odd with -* |digit| < 2^(W−1); nonzero density ~1/(W+1) (a nonzero digit is followed by W−1 zeros). -*/ -function wnafDigits(n, W) { - const size = 2 ** W; - const half = size / 2; - const mask = BigInt(size - 1); - const d = []; - while (n > _0n$9) { - let w = 0; - if (n & _1n$6) { - w = Number(n & mask); - if (w >= half) w -= size; - n -= BigInt(w); - } - d.push(w); - n >>= _1n$6; - } - return d; -} -/** -* Fixed-position signed-window recoding for precomputed wNAF: `n = Σ digits[w]⋅2^(w⋅W)` with -* digits in `[−2^(W−1)+1, 2^(W−1)]`. Digit count is fixed by `windows` (callers reserve one -* extra window for the final carry), so recoding length does not depend on the scalar. -*/ -function signedWindowDigits(n, W, windows) { - const size = 2 ** W; - const half = size / 2; - const mask = BigInt(size - 1); - const shiftBy = BigInt(W); - const d = []; - for (let w = 0; w < windows; w++) { - let v = Number(n & mask); - n >>= shiftBy; - if (v > half) { - v -= size; - n += _1n$6; - } - d.push(v); - } - if (n !== _0n$9) throw new Error("invalid wnaf"); - return d; -} -/** -* Shared vartime walk over per-scalar wNAF digit streams: one doubling of a single shared -* accumulator per bit position of the longest recoding, one signed table addition per -* nonzero digit. `tables[i]` must hold the odd multiples of the i-th point. -*/ -function wnafWalk(zero, tables, digits) { - let max = 0; - for (const d of digits) max = Math.max(max, d.length); - let acc = zero; - for (let bit = max - 1; bit >= 0; bit--) { - if (bit !== max - 1) acc = acc.double(); - for (let i = 0; i < digits.length; i++) { - const w = digits[i][bit]; - if (w) { - const item = tables[i][Math.abs(w) - 1 >> 1]; - acc = acc.add(w < 0 ? item.negate() : item); - } - } - } - return acc; -} -/** -* Elliptic curve multiplication of Point by scalar. -* Routes between cached-table, fixed-window, and one-shot wNAF paths; entry points validate -* their own scalars (`mulCT`/`mulCTBlinded`: `1 <= s < Fn.ORDER`; `mulUnsafe`: up to the -* `Fn.ORDER^4` DoS cap via {@link mulAddUnsafe}). -* Table generation is expensive and happens on first call of `multiply()` -* (or eagerly via `precompute(W, false)`). By default, `BASE` point is precomputed. -* -* Cached algorithm is signed fixed-window wNAF: -* - table stores, for every window w, the multiples `[1..2^(W−1)]⋅2^(w⋅W)⋅P` — all doublings -* are baked in, so a multiplication is exactly one table addition per window -* - window count is fixed (`ceil(bits/W) + 1`), so the point-operation count is scalar-independent -* (basis of the constant-time path) -* - for a 256-bit curve and W=6: 44⋅32 = 1408 table points, 44 additions per multiply -* - secret scalars are additionally blinded (see {@link ScalarMultiplier.mulCTBlinded}), which -* widens tables by 128 bits -* @param Point - Point constructor. -* @param randomBytes - RNG used for scalar blinding; required by the blinded secret path. -* @example -* Elliptic curve multiplication of Point by scalar. -* -* ```ts -* import { ScalarMultiplier } from '@noble/curves/abstract/curve.js'; -* import { p256 } from '@noble/curves/nist.js'; -* const mul = new ScalarMultiplier(p256.Point); -* ``` -*/ -var ScalarMultiplier = class { - Point; - BASE; - ZERO; - randomBytes; - wnafPrecomputes = /* @__PURE__ */ new WeakMap(); - baseCanBeBlinded; - bits; - constructor(Point, randomBytes) { - validatePointCons(Point); - this.randomBytes = probeRandomBytes(randomBytes, BLIND_BYTES); - this.Point = Point; - this.BASE = Point.BASE; - this.ZERO = Point.ZERO; - this.bits = Point.Fn.BITS; - } - /** - * Creates a signed fixed-window wNAF precomputation table: for every window w, the - * multiples `[1..2^(W−1)]⋅2^(w⋅W)⋅P`, flattened. All doublings are baked into the table, - * so cached multiplication is additions-only. `windows = ceil(bits/W) + 1`: the extra - * window absorbs the final carry of signed-digit recoding. - * For a 256-bit curve and W=6, the table is 44⋅32 = 1408 points. - * @param point - Point instance - * @param W - window size - * @param bits - scalar bitlength the table must cover - */ - buildWnafTable(point, W, bits) { - const windows = Math.ceil(bits / W) + 1; - const half = 2 ** (W - 1); - const comp = []; - let base = point; - for (let w = 0; w < windows; w++) { - let acc = base; - for (let i = 0; i < half; i++) { - comp.push(acc); - acc = acc.add(base); - } - base = comp[comp.length - 1].double(); - } - return { - W, - bits, - windows, - comp - }; - } - /** - * Implements ec multiplication using precomputed signed fixed-window wNAF tables. - * Constant-time: fixed window count with one table addition per window — zero digits feed - * the fake accumulator — and no doublings; the lookup scans the whole window slice. - * Scalar bounds are validated by the public entry points ({@link ScalarMultiplier.mulCT}, - * {@link ScalarMultiplier.mulCTBlinded}, {@link ScalarMultiplier.mulUnsafe}); - * signedWindowDigits throws if `n` exceeds the table. - * @returns real and fake (for const-time) points - */ - wnafCachedCT(precomputes, n) { - const { W, windows, comp } = precomputes; - const half = 2 ** (W - 1); - const digits = signedWindowDigits(n, W, windows); - let p = this.ZERO; - let f = this.BASE; - for (let w = 0; w < windows; w++) { - const digit = digits[w]; - const start = w * half; - const idx = Math.abs(digit) - 1; - let sel = comp[start]; - for (let i = 1; i < half; i++) sel = i === idx ? comp[start + i] : sel; - const neg = sel.negate(); - if (digit === 0) f = f.add(comp[start]); - else p = p.add(digit < 0 ? neg : sel); - } - return { - p, - f - }; - } - getWnafPrecomputes(W, point, bits, transform) { - let entries = this.wnafPrecomputes.get(point); - let comp = entries?.find((entry) => entry.W === W && entry.bits === bits); - if (!comp) { - comp = this.buildWnafTable(point, W, bits); - if (typeof transform === "function") comp = { - ...comp, - comp: transform(comp.comp) - }; - if (!entries) { - entries = []; - this.wnafPrecomputes.set(point, entries); - } - entries.push(comp); - } - return comp; - } - assertPoint(point) { - if (!(point instanceof this.Point)) throw new TypeError("\"point\" expected Point instance, got type=" + typeof point); - } - validateMulInput(point, scalar) { - this.assertPoint(point); - if (!inRange(scalar, _1n$6, this.Point.Fn.ORDER)) throw new Error("invalid scalar"); - } - runCT(point, n, bits, transform) { - const W = getWindowSize(point); - if (W === 1) return this.fixedWindowCT(point, n, bits); - return this.wnafCachedCT(this.getWnafPrecomputes(W, point, bits, transform), n); - } - mulCT(point, scalar, transform) { - this.validateMulInput(point, scalar); - return this.runCT(point, scalar, this.bits, transform); - } - mulCTBlinded(point, scalar, transform) { - this.validateMulInput(point, scalar); - if (this.randomBytes === void 0) throw new Error("randomBytes is required for scalar blinding"); - const bits = this.Point.Fn.BITS + BLIND_BITS; - const blind = this.randomBytes(BLIND_BYTES); - if (!isBytes$2(blind) || blind.length !== BLIND_BYTES) throw new Error("randomBytes returned invalid byte array"); - blind[0] = blind[0] & 63 | 128; - const n = scalar + bytesToNumberBE(blind) * this.Point.Fn.ORDER; - return this.runCT(point, n, bits, transform); - } - /** - * Constant-time multiplication `n*point` for an un-precomputed point, via a small fixed window. - * A cached wNAF table only pays off when reused; a flat 2^FW_WINDOW table (`size-1` adds) is - * far cheaper to build for a single use. The point-operation sequence is independent of `n`: - * build the table, then per window exactly FW_WINDOW doublings, a data-oblivious scan over - * every table entry, and one addition (adds the identity when the window digit is 0 — never - * skipped). - * - * `n` must be `< 2^bits`. Assumes complete addition (adding the identity costs the same as any - * add), which holds for the Weierstrass/Edwards point types used here. The table is left in - * projective form (no normalizeZ): normalizing this small a table costs more than the - * mixed-add savings it would buy for a single multiply. - * @returns real point `p`; `f` duplicates it only to match {@link wnafCachedCT}'s return shape - * (this path needs no fake accumulator — its op-count is already scalar-independent). - */ - fixedWindowCT(point, n, bits) { - const W = FW_WINDOW; - const size = 32; - const mask = bitMask(W); - const table = new Array(size); - table[0] = this.ZERO; - for (let i = 1; i < size; i++) table[i] = table[i - 1].add(point); - const windows = Math.ceil(bits / W); - let acc = this.ZERO; - for (let window = windows - 1; window >= 0; window--) { - if (window !== windows - 1) for (let d = 0; d < W; d++) acc = acc.double(); - const digit = Number(n >> BigInt(window * W) & mask); - let sel = table[0]; - for (let i = 1; i < size; i++) sel = i === digit ? table[i] : sel; - acc = acc.add(sel); - } - return { - p: acc, - f: acc - }; - } - shouldBlind(point, cofactor) { - if (this.randomBytes === void 0) return false; - if (cofactor === _1n$6) return true; - if (point !== this.BASE) return false; - if (this.baseCanBeBlinded === void 0) this.baseCanBeBlinded = this.mulUnsafe(this.BASE, this.Point.Fn.ORDER).is0(); - return this.baseCanBeBlinded; - } - mulSecret(point, scalar, cofactor, transform) { - return this.shouldBlind(point, cofactor) ? this.mulCTBlinded(point, scalar, transform) : this.mulCT(point, scalar, transform); - } - mulUnsafe(point, scalar, transform) { - this.assertPoint(point); - if (!isPosBig(scalar)) throw new Error("invalid scalar"); - const W = getWindowSize(point); - if (W === 1 || scalar >= this.Point.Fn.ORDER) return mulAddUnsafe(this.Point, [point], [scalar], true); - const precomputes = this.getWnafPrecomputes(W, point, this.bits, transform); - return this.wnafCachedCT(precomputes, scalar).p; - } - setWindowSize(point, W) { - this.assertPoint(point); - validateW(W, this.bits); - validateTableBytes((Math.ceil((this.bits + BLIND_BITS) / W) + 1) * 2 ** (W - 1), this.Point.Fp.BYTES); - pointWindowSizes.set(point, W); - this.wnafPrecomputes.delete(point); - } - hasWindowSize(point) { - return getWindowSize(point) !== 1; - } -}; -/** -* Combined multi-scalar multiplication `Σ scalars[i]⋅points[i]` via interleaved width-4 wNAF -* (Strauss–Shamir). Every input gets its own table of odd multiples `[1P, 3P, 5P, 7P]` and -* signed-digit recoding, but all walks share one doubling chain, so total cost is -* `~bits` doublings + `L⋅bits/5` additions instead of `L⋅bits` doublings for separate -* multiplications. Intended for the 2-4 point shapes of signature verification -* (`R = u1⋅G + u2⋅P`); use {@link pippenger} for larger batches. -* -* Not constant-time: only for public inputs. Scalars must satisfy `0 <= s < Fn.ORDER`; -* fold negative signs into the points before calling. -* @param c - Point constructor. -* @param points - Array of curve points. -* @param scalars - Array of non-negative scalars, same length as points. -* @param allowOversized - Replace the `s < Fn.ORDER` scalar check with a `Fn.ORDER^4` DoS cap. -* Off by default. For scalars that must NOT be reduced mod ORDER: torsion checks -* (`Fn.ORDER⋅P ≟ O`) and cofactor-clearing multiples. Walk length grows with `bitLen(s)`. -* @returns Combined multiplication result; identity for empty input. -* @throws If the point set or scalar set is invalid. {@link Error} -* @example -* Combined multi-scalar multiplication via Strauss–Shamir. -* -* ```ts -* import { mulAddUnsafe } from '@noble/curves/abstract/curve.js'; -* import { p256 } from '@noble/curves/nist.js'; -* const G = p256.Point.BASE; -* const R = mulAddUnsafe(p256.Point, [G, G.double()], [2n, 3n]); // 2⋅G + 3⋅(2⋅G) -* ``` -*/ -function mulAddUnsafe(c, points, scalars, allowOversized = false) { - validatePointCons(c); - validateMSMPoints(points, c); - abool$1(allowOversized, "allowOversized"); - validateMSMScalars(scalars, c.Fn, allowOversized ? c.Fn.ORDER ** _4n$2 : void 0); - if (points.length !== scalars.length) throw new Error("arrays of points and scalars must have equal length"); - const tables = points.map((p) => oddMultiples(p, 4)); - const digits = scalars.map((n) => wnafDigits(n, 4)); - return wnafWalk(c.ZERO, tables, digits); -} -function createField(order, field, isLE) { - if (field) { - if (field.ORDER !== order) throw new Error("Field.ORDER must match order: Fp == p, Fn == n"); - validateField(field); - return field; - } else return Field(order, { isLE }); -} -/** -* Validates basic CURVE shape and field membership, then creates fields. -* This does not prove that the generator is on-curve, that subgroup/order data are consistent, or -* that the curve equation itself is otherwise sane. -* @param type - Curve family. -* @param CURVE - Curve parameters. -* @param curveOpts - Optional field overrides. See {@link FpFn}: -* - `Fp` (optional): Optional base-field override. -* - `Fn` (optional): Optional scalar-field override. -* @param FpFnLE - Whether field encoding is little-endian. -* @returns Frozen curve parameters and fields. -* @throws If the curve parameters or field overrides are invalid. {@link Error} -* @example -* Build curve fields from raw constants before constructing a curve instance. -* -* ```ts -* const curve = createCurveFields('weierstrass', { -* p: 17n, -* n: 19n, -* h: 1n, -* a: 2n, -* b: 2n, -* Gx: 5n, -* Gy: 1n, -* }); -* ``` -*/ -function createCurveFields(type, CURVE, curveOpts = {}, FpFnLE) { - if (type !== "weierstrass" && type !== "edwards") throw new Error("expected curve type \"weierstrass\" or \"edwards\""); - if (FpFnLE === void 0) FpFnLE = type === "edwards"; - if (!CURVE || typeof CURVE !== "object") throw new Error(`expected valid ${type} CURVE object`); - validateObject(curveOpts); - for (const p of [ - "p", - "n", - "h" - ]) { - const val = CURVE[p]; - if (!(isPosBig(val) && val !== _0n$9)) throw new Error(`CURVE.${p} must be positive bigint`); - } - const Fp = createField(CURVE.p, curveOpts.Fp, FpFnLE); - const Fn = createField(CURVE.n, curveOpts.Fn, FpFnLE); - const params = [ - "Gx", - "Gy", - "a", - type === "weierstrass" ? "b" : "d" - ]; - for (const p of params) if (!Fp.isValid(CURVE[p])) throw new Error(`CURVE.${p} must be valid field element of CURVE.Fp`); - CURVE = Object.freeze(Object.assign({}, CURVE)); - return { - CURVE, - Fp, - Fn - }; -} -/** -* @param randomSecretKey - Secret-key generator. -* @param getPublicKey - Public-key derivation helper. -* @returns Keypair generator. -* @example -* Build a `keygen()` helper from existing secret-key and public-key primitives. -* -* ```ts -* import { createKeygen } from '@noble/curves/abstract/curve.js'; -* import { p256 } from '@noble/curves/nist.js'; -* const keygen = createKeygen(p256.utils.randomSecretKey, p256.getPublicKey); -* const pair = keygen(); -* ``` -*/ -function createKeygen(randomSecretKey, getPublicKey) { - return function keygen(seed) { - const secretKey = randomSecretKey(seed); - return { - secretKey, - publicKey: getPublicKey(secretKey) - }; - }; -} -//#endregion -//#region tests/baseline/node_modules/@noble/curves/abstract/edwards.js -/** -* Twisted Edwards curve. The formula is: ax² + y² = 1 + dx²y². -* For design rationale of types / exports, see weierstrass module documentation. -* Untwisted Edwards curves exist, but they aren't used in real-world protocols. -* @module -*/ -/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ -const _0n$8 = /* @__PURE__ */ BigInt(0); -const _1n$5 = /* @__PURE__ */ BigInt(1); -const _2n$6 = /* @__PURE__ */ BigInt(2); -const _4n$1 = /* @__PURE__ */ BigInt(4); -const _8n$1 = /* @__PURE__ */ BigInt(8); -function isEdValidXY(Fp, CURVE, x, y) { - const x2 = Fp.sqr(x); - const y2 = Fp.sqr(y); - const left = Fp.add(Fp.mul(CURVE.a, x2), y2); - const right = Fp.add(Fp.ONE, Fp.mul(CURVE.d, Fp.mul(x2, y2))); - return Fp.eql(left, right); -} -/** -* @param params - Curve parameters. See {@link EdwardsOpts}. -* @param extraOpts - Optional helpers and overrides. See {@link EdwardsExtraOpts}. -* @returns Edwards point constructor. Generator validation here only checks -* that `(Gx, Gy)` satisfies the affine Edwards equation. -* RFC 8032 base-point constraints like `B != (0,1)` and `[L]B = 0` -* are left to the caller's chosen parameters, since eager subgroup -* validation here adds about 10-15ms to heavyweight imports like ed448. -* The returned constructor also eagerly marks `Point.BASE` for W=6 -* precompute caching. Some code paths still assume -* `Fp.BYTES === Fn.BYTES`, so mismatched byte lengths are not fully audited here. -* @throws If the curve parameters or Edwards overrides are invalid. {@link Error} -* @example -* ```ts -* import { edwards } from '@noble/curves/abstract/edwards.js'; -* import { jubjub } from '@noble/curves/misc.js'; -* // Build a point constructor from explicit curve parameters, then use its base point. -* const Point = edwards(jubjub.Point.CURVE()); -* Point.BASE.toHex(); -* ``` -*/ -function edwards(params, extraOpts = {}) { - validateObject(extraOpts, {}, {}, "extraOpts"); - const opts = extraOpts; - const validated = createCurveFields("edwards", params, opts, opts.FpFnLE); - const { Fp, Fn } = validated; - let CURVE = validated.CURVE; - const { h: cofactor } = CURVE; - if (FpLegendre(Fp, CURVE.a) !== 1) throw new Error("edwards: CURVE.a must be a square in Fp for complete addition formulas"); - if (FpLegendre(Fp, CURVE.d) !== -1) throw new Error("edwards: CURVE.d must be a non-square in Fp for complete addition formulas"); - validateObject(opts, {}, { - uvRatio: "function", - randomBytes: "function" - }); - const randomBytes = opts.randomBytes === void 0 ? randomBytes$2 : opts.randomBytes; - const MASK = _2n$6 << BigInt(Fp.BYTES * 8) - _1n$5; - function isOdd(n) { - if (!Fp.isOdd) throw new Error("Field does not have .isOdd()"); - return Fp.isOdd(n); - } - const uvRatio = opts.uvRatio === void 0 ? (u, v) => { - try { - return { - isValid: true, - value: Fp.sqrt(Fp.div(u, v)) - }; - } catch (e) { - return { - isValid: false, - value: _0n$8 - }; - } - } : opts.uvRatio; - if (!isEdValidXY(Fp, CURVE, CURVE.Gx, CURVE.Gy)) throw new Error("bad curve params: generator point"); - const mulA = Fp.eql(CURVE.a, Fp.neg(Fp.ONE)) ? (x) => Fp.neg(x) : Fp.eql(CURVE.a, Fp.ONE) ? (x) => x : (x) => Fp.mul(CURVE.a, x); - /** - * Asserts coordinate is valid: 0 <= n < MASK. - * Coordinates >= Fp.ORDER are allowed for zip215. - */ - function acoord(title, n, banZero = false) { - const min = banZero ? _1n$5 : _0n$8; - aInRange("coordinate " + title, n, min, MASK); - return n; - } - function aedpoint(other) { - if (!(other instanceof Point)) throw new Error("EdwardsPoint expected"); - } - class Point { - static BASE = new Point(CURVE.Gx, CURVE.Gy, Fp.ONE, Fp.mul(CURVE.Gx, CURVE.Gy)); - static ZERO = new Point(Fp.ZERO, Fp.ONE, Fp.ONE, Fp.ZERO); - static Fp = Fp; - static Fn = Fn; - X; - Y; - Z; - T; - constructor(X, Y, Z, T) { - this.X = acoord("x", X); - this.Y = acoord("y", Y); - this.Z = acoord("z", Z, true); - this.T = acoord("t", T); - Object.freeze(this); - } - static CURVE() { - return CURVE; - } - /** - * Create one extended Edwards point from affine coordinates. - * Does NOT validate that the point is on-curve or torsion-free. - * Use `.assertValidity()` on adversarial inputs. - */ - static fromAffine(p) { - if (p instanceof Point) throw new Error("extended point not allowed"); - const { x, y } = p || {}; - acoord("x", x); - acoord("y", y); - return new Point(x, y, Fp.ONE, Fp.mul(x, y)); - } - static fromBytes(bytes, zip215 = false) { - const len = Fp.BYTES; - const { a, d } = CURVE; - bytes = copyBytes$1(abytes$3(bytes, len, "point")); - abool$1(zip215, "zip215"); - const normed = copyBytes$1(bytes); - const lastByte = bytes[len - 1]; - normed[len - 1] = lastByte & -129; - const y = bytesToNumberLE(normed); - const max = zip215 ? MASK : Fp.ORDER; - aInRange("point.y", y, _0n$8, max); - const y2 = Fp.sqr(y); - const u = Fp.sub(y2, Fp.ONE); - const v = Fp.sub(Fp.mulN(d, y2), a); - let { isValid, value: x } = uvRatio(u, v); - if (!isValid) throw new Error("bad point: invalid y coordinate"); - const isXOdd = isOdd(x); - const isLastByteOdd = (lastByte & 128) !== 0; - if (!zip215 && Fp.is0(x) && isLastByteOdd) throw new Error("bad point: x=0 and x_0=1"); - if (isLastByteOdd !== isXOdd) x = Fp.neg(x); - return Point.fromAffine({ - x, - y - }); - } - static fromHex(hex, zip215 = false) { - return Point.fromBytes(hexToBytes$1(hex), zip215); - } - get x() { - return this.toAffine().x; - } - get y() { - return this.toAffine().y; - } - precompute(windowSize = 6, isLazy = true) { - wnaf.setWindowSize(this, windowSize); - if (!isLazy) this.multiply(_2n$6); - return this; - } - assertValidity() { - const p = this; - const { a, d } = CURVE; - if (p.is0()) throw new Error("bad point: ZERO"); - const { X, Y, Z, T } = p; - const X2 = Fp.sqr(X); - const Y2 = Fp.sqr(Y); - const Z2 = Fp.sqr(Z); - const Z4 = Fp.sqr(Z2); - const aX2 = Fp.mul(X2, a); - const left = Fp.mul(Fp.add(aX2, Y2), Z2); - const right = Fp.add(Z4, Fp.mul(d, Fp.mul(X2, Y2))); - if (!Fp.eql(left, right)) throw new Error("bad point: equation left != right (1)"); - const XY = Fp.mul(X, Y); - const ZT = Fp.mul(Z, T); - if (!Fp.eql(XY, ZT)) throw new Error("bad point: equation left != right (2)"); - } - equals(other) { - aedpoint(other); - const { X: X1, Y: Y1, Z: Z1 } = this; - const { X: X2, Y: Y2, Z: Z2 } = other; - const X1Z2 = Fp.mul(X1, Z2); - const X2Z1 = Fp.mul(X2, Z1); - const Y1Z2 = Fp.mul(Y1, Z2); - const Y2Z1 = Fp.mul(Y2, Z1); - return Fp.eql(X1Z2, X2Z1) && Fp.eql(Y1Z2, Y2Z1); - } - is0() { - return this.equals(Point.ZERO); - } - negate() { - return new Point(Fp.neg(this.X), this.Y, this.Z, Fp.neg(this.T)); - } - double() { - const { X: X1, Y: Y1, Z: Z1 } = this; - const A = Fp.sqr(X1); - const B = Fp.sqr(Y1); - const C = Fp.mul(Fp.sqr(Z1), _2n$6); - const D = mulA(A); - const x1y1 = Fp.addN(X1, Y1); - const E = Fp.sub(Fp.subN(Fp.sqr(x1y1), A), B); - const G = Fp.addN(D, B); - const F = Fp.subN(G, C); - const H = Fp.subN(D, B); - const X3 = Fp.mul(E, F); - const Y3 = Fp.mul(G, H); - const T3 = Fp.mul(E, H); - const Z3 = Fp.mul(F, G); - return new Point(X3, Y3, Z3, T3); - } - add(other) { - aedpoint(other); - const { d } = CURVE; - const { X: X1, Y: Y1, Z: Z1, T: T1 } = this; - const { X: X2, Y: Y2, Z: Z2, T: T2 } = other; - const A = Fp.mul(X1, X2); - const B = Fp.mul(Y1, Y2); - const C = Fp.mul(Fp.mulN(T1, d), T2); - const D = Fp.mul(Z1, Z2); - const E = Fp.sub(Fp.subN(Fp.mulN(Fp.addN(X1, Y1), Fp.addN(X2, Y2)), A), B); - const F = Fp.subN(D, C); - const G = Fp.addN(D, C); - const H = Fp.sub(B, mulA(A)); - const X3 = Fp.mul(E, F); - const Y3 = Fp.mul(G, H); - const T3 = Fp.mul(E, H); - const Z3 = Fp.mul(F, G); - return new Point(X3, Y3, Z3, T3); - } - subtract(other) { - aedpoint(other); - return this.add(other.negate()); - } - multiply(scalar) { - if (!Fn.isValidNot0(scalar)) throw new RangeError("invalid scalar: expected 1 <= sc < curve.n"); - const { p, f } = wnaf.mulSecret(this, scalar, cofactor, normalize); - return normalize([p, f])[0]; - } - multiplyUnsafe(scalar) { - if (!Fn.isValid(scalar)) throw new RangeError("invalid scalar: expected 0 <= sc < curve.n"); - if (scalar === _0n$8) return Point.ZERO; - if (this.is0() || scalar === _1n$5) return this; - return wnaf.mulUnsafe(this, scalar, normalize); - } - isSmallOrder() { - return this.clearCofactor().is0(); - } - isTorsionFree() { - return wnaf.mulUnsafe(this, CURVE.n).is0(); - } - toAffine(invertedZ) { - const p = this; - let iz = invertedZ; - if (iz != null && typeof iz !== "bigint") throw new TypeError("\"invertedZ\" expected bigint, got type=" + typeof iz); - const { X, Y, Z } = p; - const is0 = p.is0(); - if (iz == null) iz = is0 ? Fp.create(_8n$1) : Fp.inv(Z); - const x = Fp.mul(X, iz); - const y = Fp.mul(Y, iz); - const zz = Fp.mul(Z, iz); - if (is0) return { - x: Fp.ZERO, - y: Fp.ONE - }; - if (!Fp.eql(zz, Fp.ONE)) throw new Error("invZ was invalid"); - return { - x, - y - }; - } - clearCofactor() { - if (cofactor === _1n$5) return this; - if (cofactor === _2n$6) return this.double(); - if (cofactor === _4n$1) return this.double().double(); - if (cofactor === _8n$1) return this.double().double().double(); - return this.multiplyUnsafe(cofactor); - } - toBytes() { - const { x, y } = this.toAffine(); - const bytes = Fp.toBytes(y); - bytes[bytes.length - 1] |= isOdd(x) ? 128 : 0; - return bytes; - } - toHex() { - return bytesToHex$2(this.toBytes()); - } - toString() { - return ``; - } - } - const normalize = (points) => normalizeZ(Point, points); - const wnaf = new ScalarMultiplier(Point, randomBytes); - if (wnaf.bits >= 6) Point.BASE.precompute(6); - Object.freeze(Point.prototype); - Object.freeze(Point); - return Point; -} -/** -* Base class for prime-order points like Ristretto255 and Decaf448. -* These points eliminate cofactor issues by representing equivalence classes -* of Edwards curve points. Multiple Edwards representatives can describe the -* same abstract wrapper element, so wrapper validity is not the same thing as -* the hidden representative being torsion-free. -* @param ep - Backing Edwards point. -* @example -* Base class for prime-order points like Ristretto255 and Decaf448. -* -* ```ts -* import { ristretto255 } from '@noble/curves/ed25519.js'; -* const point = ristretto255.Point.BASE.multiply(2n); -* ``` -*/ -var PrimeEdwardsPoint = class { - static BASE; - static ZERO; - static Fp; - static Fn; - ep; - /** - * Wrap one internal Edwards representative directly. - * This is not a canonical encoding boundary: alternate Edwards - * representatives may still describe the same abstract wrapper element. - */ - constructor(ep) { - this.ep = ep; - } - static fromBytes(_bytes) { - notImplemented(); - } - static fromHex(_hex) { - notImplemented(); - } - get x() { - return this.toAffine().x; - } - get y() { - return this.toAffine().y; - } - clearCofactor() { - return this; - } - assertValidity() { - this.ep.assertValidity(); - } - /** - * Return affine coordinates of the current internal Edwards representative. - * This is a convenience helper, not a canonical Ristretto/Decaf encoding. - * Equal abstract elements may expose different `x` / `y`; use - * `toBytes()` / `fromBytes()` for canonical roundtrips. - */ - toAffine(invertedZ) { - return this.ep.toAffine(invertedZ); - } - toHex() { - return bytesToHex$2(this.toBytes()); - } - toString() { - return this.toHex(); - } - isTorsionFree() { - return true; - } - isSmallOrder() { - return false; - } - add(other) { - this.assertSame(other); - return this.init(this.ep.add(other.ep)); - } - subtract(other) { - this.assertSame(other); - return this.init(this.ep.subtract(other.ep)); - } - multiply(scalar) { - return this.init(this.ep.multiply(scalar)); - } - multiplyUnsafe(scalar) { - return this.init(this.ep.multiplyUnsafe(scalar)); - } - double() { - return this.init(this.ep.double()); - } - negate() { - return this.init(this.ep.negate()); - } - precompute(windowSize, isLazy) { - this.ep.precompute(windowSize, isLazy); - return this; - } -}; -/** -* Initializes EdDSA signatures over given Edwards curve. -* @param Point - Edwards point constructor. -* @param cHash - Hash function. -* @param eddsaOpts - Optional signature helpers. See {@link EdDSAOpts}. -* @returns EdDSA helper namespace. -* @throws If the hash function, options, or derived point operations are invalid. {@link Error} -* @example -* Initializes EdDSA signatures over given Edwards curve. -* -* ```ts -* import { eddsa } from '@noble/curves/abstract/edwards.js'; -* import { jubjub } from '@noble/curves/misc.js'; -* import { sha512 } from '@noble/hashes/sha2.js'; -* const sigs = eddsa(jubjub.Point, sha512); -* const { secretKey, publicKey } = sigs.keygen(); -* const msg = new TextEncoder().encode('hello noble'); -* const sig = sigs.sign(msg, secretKey); -* const isValid = sigs.verify(sig, msg, publicKey); -* ``` -*/ -function eddsa(Point, cHash, eddsaOpts = {}) { - validatePointCons(Point); - if (typeof cHash !== "function") throw new Error("\"hash\" function param is required"); - const hash = cHash; - const opts = eddsaOpts; - validateObject(opts, {}, { - adjustScalarBytes: "function", - randomBytes: "function", - domain: "function", - prehash: "function", - zip215: "boolean", - mapToCurve: "function", - toMontgomery: "function", - toMontgomerySecret: "function" - }); - const { prehash } = opts; - const { BASE, Fp, Fn } = Point; - const outputLen = hash.outputLen; - const expectedLen = 2 * Fp.BYTES; - if (outputLen !== void 0) { - asafenumber(outputLen, "hash.outputLen"); - if (outputLen !== expectedLen) throw new Error(`hash.outputLen must be ${expectedLen}, got ${outputLen}`); - } - const randomBytes = opts.randomBytes === void 0 ? randomBytes$2 : opts.randomBytes; - const toMontgomery = opts.toMontgomery; - const toMontgomerySecret = opts.toMontgomerySecret; - const adjustScalarBytes = opts.adjustScalarBytes === void 0 ? (bytes) => bytes : opts.adjustScalarBytes; - const domain = opts.domain === void 0 ? (data, ctx, phflag) => { - abool$1(phflag, "phflag"); - if (ctx.length || phflag) throw new Error("Contexts/pre-hash are not supported"); - return data; - } : opts.domain; - function modN_LE(hash) { - return Fn.create(bytesToNumberLE(hash)); - } - function getPrivateScalar(key) { - const len = lengths.secretKey; - abytes$3(key, lengths.secretKey, "secretKey"); - const hashed = abytes$3(hash(key), 2 * len, "hashedSecretKey"); - const head = adjustScalarBytes(hashed.slice(0, len)); - return { - head, - prefix: hashed.slice(len, 2 * len), - scalar: modN_LE(head) - }; - } - /** Convenience method that creates public key from scalar. RFC8032 5.1.5 - * Also exposes the derived scalar/prefix tuple and point form reused by sign(). - */ - function getExtendedPublicKey(secretKey) { - const { head, prefix, scalar } = getPrivateScalar(secretKey); - const point = BASE.multiply(scalar); - return { - head, - prefix, - scalar, - point, - pointBytes: point.toBytes() - }; - } - /** Calculates EdDSA pub key. RFC8032 5.1.5. */ - function getPublicKey(secretKey) { - return getExtendedPublicKey(secretKey).pointBytes; - } - function hashDomainToScalar(context = Uint8Array.of(), ...msgs) { - const msg = concatBytes$2(...msgs); - return modN_LE(hash(domain(msg, abytes$3(context, void 0, "context"), !!prehash))); - } - /** Signs message with secret key. RFC8032 5.1.6 */ - function sign(msg, secretKey, options = {}) { - validateObject(options, {}, {}, "options"); - msg = copyBytes$1(abytes$3(msg, void 0, "message")); - if (prehash) msg = prehash(msg); - const { prefix, scalar, pointBytes } = getExtendedPublicKey(secretKey); - const r = hashDomainToScalar(options.context, prefix, msg); - const R = BASE.multiply(r).toBytes(); - const k = hashDomainToScalar(options.context, R, pointBytes, msg); - const s = Fn.create(r + k * scalar); - if (!Fn.isValid(s)) throw new Error("sign failed: invalid s"); - const rs = concatBytes$2(R, Fn.toBytes(s)); - return abytes$3(rs, lengths.signature, "result"); - } - const verifyOpts = { zip215: opts.zip215 }; - /** - * Verifies EdDSA signature against message and public key. RFC 8032 §§5.1.7 and 5.2.7. - * A cofactored verification equation is checked. - */ - function verify(sig, msg, publicKey, options = verifyOpts) { - validateObject(options); - const { context } = options; - const zip215 = options.zip215 === void 0 ? !!verifyOpts.zip215 : options.zip215; - const len = lengths.signature; - sig = abytes$3(sig, len, "signature"); - msg = abytes$3(msg, void 0, "message"); - publicKey = abytes$3(publicKey, lengths.publicKey, "publicKey"); - if (zip215 !== void 0) abool$1(zip215, "zip215"); - if (prehash) msg = prehash(msg); - const mid = len / 2; - const r = sig.subarray(0, mid); - const s = bytesToNumberLE(sig.subarray(mid, len)); - let A, R, SB; - try { - A = Point.fromBytes(publicKey, zip215); - R = Point.fromBytes(r, zip215); - SB = BASE.multiplyUnsafe(s); - } catch (error) { - return false; - } - if (!zip215 && A.isSmallOrder()) return false; - const k = hashDomainToScalar(context, r, publicKey, msg); - return R.add(A.multiplyUnsafe(k)).subtract(SB).clearCofactor().is0(); - } - const _size = Fp.BYTES; - const lengths = { - secretKey: _size, - publicKey: _size, - signature: 2 * _size, - seed: _size - }; - function randomSecretKey(seed) { - seed = seed === void 0 ? randomBytes(lengths.seed) : seed; - return abytes$3(seed, lengths.seed, "seed"); - } - function isValidSecretKey(key) { - return isBytes$2(key) && key.length === lengths.secretKey; - } - function isValidPublicKey(key, zip215) { - try { - return !!Point.fromBytes(key, zip215 === void 0 ? verifyOpts.zip215 : zip215); - } catch (error) { - return false; - } - } - const utils = { - getExtendedPublicKey, - randomSecretKey, - isValidSecretKey, - isValidPublicKey, - /** Converts an Edwards public key to a companion Montgomery public key. */ - toMontgomery(publicKey) { - if (toMontgomery === void 0) throw new Error("Montgomery conversion is not supported for this curve"); - return toMontgomery(Point.fromBytes(publicKey)); - }, - toMontgomerySecret(secretKey) { - if (toMontgomerySecret === void 0) throw new Error("Montgomery conversion is not supported for this curve"); - return toMontgomerySecret(secretKey); - } - }; - Object.freeze(lengths); - Object.freeze(utils); - return Object.freeze({ - keygen: createKeygen(randomSecretKey, getPublicKey), - getPublicKey, - sign, - verify, - utils, - Point, - lengths - }); -} -//#endregion -//#region tests/baseline/node_modules/@noble/curves/abstract/montgomery.js -/** -* Montgomery curve methods. It's not really whole montgomery curve, -* just bunch of very specific methods for X25519 / X448 from -* [RFC 7748](https://www.rfc-editor.org/rfc/rfc7748) -* @module -*/ -/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ -const _0n$7 = /* @__PURE__ */ BigInt(0); -const _1n$4 = /* @__PURE__ */ BigInt(1); -const _2n$5 = /* @__PURE__ */ BigInt(2); -/** -* Selector for cswap(): `P` to keep, `P + 1` to swap, chosen by the low bit of `swap`. -* Higher bits are ignored, and `swap` is passed in whole rather than as a {0n, 1n} bit on -* purpose: `P + (swap & _1n)` would short-circuit the addition whenever the bit is clear, which -* is the very leak this construction avoids, one round-trip further down. Subtracting `swap` -* with its low bit cleared keeps every operand full-width instead. -* @param P - Field modulus. -* @param swap - Value whose low bit selects; ignored above that bit. -* @returns `P` when the low bit is clear, `P + 1` when it is set. -*/ -function cmask(P, swap) { - return P + swap - (swap >> _1n$4 << _1n$4); -} -/** -* Swap two field elements when `mask` is `P + 1`, keep them when it is `P`: -* -* d = 6P + x_3 - x_2 -* x_2' = d * mask + x_2 (mod P) x_3' = (x_2 + x_3) - x_2' -* -* The extra `6P * mask` vanishes modulo P, so `mask === P` leaves x_2 and `mask === P + 1` -* leaves x_3. Without the offset, the reduction dividend changes sign with input order and crosses -* BigInt limb boundaries; those classes measured differently on the tested Node/V8 build. For -* canonical inputs, the deliberately left-associative `offset + x_3 - x_2` is between 5P and 7P, -* keeping the dividend positive and in one word-count band for both RFC fields and masks. Six is -* the smallest coefficient `c` for which the shared offset `cP` has that property. -* -* This reduced the tested sign/size timing ratios, but JavaScript BigInt has no constant-time -* contract and the contents of the multiply and remainder still vary. Valid ladder states can -* contain genuine zero coordinates; this construction does not mask those value-shape effects. -* Computing `x_3'` independently as `((6P + x_2 - x_3) * mask + x_3) % P` is more symmetric. -* On the tested Node/V8 build, it reduced the timing difference between keeping `(0, v)` and -* swapping `(v, 0)`—both return `(0, v)`—from about 10%/13% for X25519/X448 to about 3%. -* Successful calls cannot reach that zero-in-the-first-output case. For the case they can reach, -* swapping `(0, v)` and keeping `(v, 0)` both return `(v, 0)`; the difference instead grew from -* about 0.7%/1.1% to 2.7%/2.8%. The extra multiply/remainder also made public -* `getSharedSecret()` about 16% slower. The retained one-remainder form measured about 2.5% -* slower than the prior helper for public X25519 `getSharedSecret()` in the same environment. -* x_3' falls out of the sum, which a swap leaves invariant: no second multiply or reduction is -* needed. Bind `6P` once per field so production and the timing regression exercise the same -* configured helper without paying for the multiplication in every ladder round. -* -* The returned function is called twice per ladder round, so it validates nothing. Both elements -* MUST already be reduced mod P; unreduced input silently corrupts the kept-side output. -* @param P - Field modulus. -* @returns A field-bound swap function taking mask, x_2, and x_3. -*/ -function cswap(P) { - const offset = BigInt(6) * P; - return (mask, x_2, x_3) => { - const sum = x_2 + x_3; - const a = ((offset + x_3 - x_2) * mask + x_2) % P; - return { - x_2: a, - x_3: sum - a - }; - }; -} -function validateOpts$1(curve) { - validateObject(curve, { - P: "bigint", - type: "string", - adjustScalarBytes: "function", - powPminus2: "function" - }, { - randomBytes: "function", - scalarMultBase: "function" - }); - return Object.freeze({ ...curve }); -} -/** -* @param curveDef - Montgomery curve definition. -* @returns ECDH helper namespace. -* @throws If the curve definition or derived shared point is invalid. {@link Error} -* @example -* Build an X25519 helper from curve parameters, then derive one public key. -* -* ```ts -* import { montgomery } from '@noble/curves/abstract/montgomery.js'; -* const P = 2n ** 255n - 19n; -* const mod = (num: bigint) => { -* const out = num % P; -* return out >= 0n ? out : out + P; -* }; -* const pow = (num: bigint, power: bigint) => { -* let res = 1n; -* for (; power > 0n; power >>= 1n) { -* if (power & 1n) res = mod(res * num); -* num = mod(num * num); -* } -* return res; -* }; -* const x25519 = montgomery({ -* P, -* type: 'x25519', -* adjustScalarBytes(bytes: Uint8Array) { -* bytes[0] &= 248; -* bytes[31] &= 127; -* bytes[31] |= 64; -* return bytes; -* }, -* powPminus2(x) { -* return pow(x, P - 2n); -* }, -* }); -* const publicKey = x25519.getPublicKey(new Uint8Array(32).fill(1)); -* ``` -*/ -function montgomery(curveDef) { - const CURVE = validateOpts$1(curveDef); - const { P, type, adjustScalarBytes, powPminus2, randomBytes: rand } = CURVE; - const mulBaseHook = CURVE.scalarMultBase; - const is25519 = type === "x25519"; - if (!is25519 && type !== "x448") throw new Error("invalid type"); - const randomBytes_ = rand === void 0 ? randomBytes$2 : rand; - const montgomeryBits = is25519 ? 255 : 448; - const swap = cswap(P); - const fieldLen = is25519 ? 32 : 56; - const Gu = is25519 ? BigInt(9) : BigInt(5); - const a24 = is25519 ? BigInt(121665) : BigInt(39081); - const minScalar = is25519 ? _2n$5 ** BigInt(254) : _2n$5 ** BigInt(447); - const maxScalar = minScalar + (is25519 ? BigInt(8) * (_2n$5 ** BigInt(251) - _1n$4) : BigInt(4) * (_2n$5 ** BigInt(445) - _1n$4)) + _1n$4; - const modP = (n) => mod(n, P); - const GuBytes = encodeU(Gu); - function encodeU(u) { - return numberToBytesLE(modP(u), fieldLen); - } - function decodeU(u) { - const _u = copyBytes$1(abytes$3(u, fieldLen, "uCoordinate")); - if (is25519) _u[31] &= 127; - return modP(bytesToNumberLE(_u)); - } - function decodeScalar(scalar) { - return bytesToNumberLE(adjustScalarBytes(copyBytes$1(abytes$3(scalar, fieldLen, "scalar")))); - } - /** - * u coordinates whose order divides the cofactor, on the curve and on its quadratic twist - - * the ladder sends every one of them to zero. Same blocklist libsodium and post-CVE-2017-0379 - * Libgcrypt carry. decodeU() reduces mod P first, so the non-canonical encodings P and P + 1 - * collapse onto 0 and 1, and `type` admits no curve beyond these two, so both lists are total. - * - * Complete by construction: x-only doubling sends u to (u^2 - 1)^2 / 4u(u^2 + a*u + 1). Order 4 - * therefore needs (u^2 - 1)^2 === 0, i.e. u = +-1; order 2 needs u(u^2 + a*u + 1) === 0, and - * a^2 - 4 is a non-residue on both curves, leaving u = 0. curve448 stops there (cofactor 4); - * curve25519 (cofactor 8) adds the two order-8 roots below. Cross-checked by clearing the - * cofactor with those same doublings over 200k random u: no sixth value exists. - */ - const lowOrderU = new Set(is25519 ? [ - _0n$7, - _1n$4, - P - _1n$4, - BigInt("325606250916557431795983626356110631294008115727848805560023387167927233504"), - BigInt("39382357235489614581723060781553021112529911719440698176882885853963445705823") - ] : [ - _0n$7, - _1n$4, - P - _1n$4 - ]); - function scalarMult(scalar, u) { - const pointU = decodeU(u); - if (lowOrderU.has(pointU)) throw new Error("invalid private or public key received"); - const pu = montgomeryLadder(pointU, decodeScalar(scalar)); - if (pu === _0n$7) throw new Error("invalid private or public key received"); - return encodeU(pu); - } - function scalarMultBase(scalar) { - if (mulBaseHook === void 0) return scalarMult(scalar, GuBytes); - const k = decodeScalar(scalar); - aInRange("scalar", k, minScalar, maxScalar); - const pu = modP(mulBaseHook(k)); - if (pu === _0n$7) throw new Error("invalid private or public key received"); - return encodeU(pu); - } - const getPublicKey = scalarMultBase; - const getSharedSecret = scalarMult; - /** - * Montgomery x-only multiplication ladder for the selected X25519/X448 curve. - * @param pointU - decoded Montgomery u coordinate for the selected curve - * @param scalar - decoded clamped scalar by which the point is multiplied - * @returns resulting Montgomery u coordinate for the selected curve - */ - function montgomeryLadder(u, scalar) { - aInRange("u", u, _0n$7, P); - aInRange("scalar", scalar, minScalar, maxScalar); - const k = scalar; - const x_1 = u; - let x_2 = _1n$4; - let z_2 = _0n$7; - let x_3 = u; - let z_3 = _1n$4; - const kx = k ^ k >> _1n$4; - for (let t = BigInt(montgomeryBits - 1); t >= _0n$7; t--) { - const mask = cmask(P, kx >> t); - ({x_2, x_3} = swap(mask, x_2, x_3)); - ({x_2: z_2, x_3: z_3} = swap(mask, z_2, z_3)); - const A = x_2 + z_2; - const AA = modP(A * A); - const B = x_2 - z_2; - const BB = modP(B * B); - const E = AA - BB; - const C = x_3 + z_3; - const D = x_3 - z_3; - const DA = modP(D * A); - const CB = modP(C * B); - const dacb = DA + CB; - const da_cb = DA - CB; - x_3 = modP(dacb * dacb); - z_3 = modP(x_1 * modP(da_cb * da_cb)); - x_2 = modP(AA * BB); - z_2 = modP(E * (AA + modP(a24 * E))); - } - const mask = cmask(P, k); - ({x_2, x_3} = swap(mask, x_2, x_3)); - ({x_2: z_2, x_3: z_3} = swap(mask, z_2, z_3)); - const z2 = powPminus2(z_2); - return modP(x_2 * z2); - } - const lengths = { - secretKey: fieldLen, - publicKey: fieldLen, - seed: fieldLen - }; - const randomSecretKey = (seed) => { - seed = seed === void 0 ? randomBytes_(fieldLen) : seed; - abytes$3(seed, lengths.seed, "seed"); - return seed; - }; - const utils = { randomSecretKey }; - Object.freeze(lengths); - Object.freeze(utils); - return Object.freeze({ - keygen: createKeygen(randomSecretKey, getPublicKey), - getSharedSecret, - getPublicKey, - scalarMult, - scalarMultBase, - utils, - GuBytes: GuBytes.slice(), - lengths - }); -} -//#endregion -//#region tests/baseline/node_modules/@noble/curves/ed25519.js -/** -* ed25519 Twisted Edwards curve with following addons: -* - X25519 ECDH -* - Ristretto cofactor elimination -* - Elligator hash-to-group / point indistinguishability -* @module -*/ -/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ -const _0n$6 = /* @__PURE__ */ BigInt(0); -const _1n$3 = /* @__PURE__ */ BigInt(1); -const _2n$4 = /* @__PURE__ */ BigInt(2); -const _3n$2 = /* @__PURE__ */ BigInt(3); -const _5n = /* @__PURE__ */ BigInt(5); -const _8n = /* @__PURE__ */ BigInt(8); -const ed25519_CURVE_p = /* @__PURE__ */ BigInt("0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed"); -const ed25519_CURVE = /* @__PURE__ */ (() => ({ - p: ed25519_CURVE_p, - n: BigInt("0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed"), - h: _8n, - a: BigInt("0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec"), - d: BigInt("0x52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3"), - Gx: BigInt("0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a"), - Gy: BigInt("0x6666666666666666666666666666666666666666666666666666666666666658") -}))(); -function ed25519_pow_2_252_3(x) { - const _10n = BigInt(10), _20n = BigInt(20), _40n = BigInt(40), _80n = BigInt(80); - const P = ed25519_CURVE_p; - const b2 = x * x % P * x % P; - const b5 = pow2(pow2(b2, _2n$4, P) * b2 % P, _1n$3, P) * x % P; - const b10 = pow2(b5, _5n, P) * b5 % P; - const b20 = pow2(b10, _10n, P) * b10 % P; - const b40 = pow2(b20, _20n, P) * b20 % P; - const b80 = pow2(b40, _40n, P) * b40 % P; - return { - pow_p_5_8: pow2(pow2(pow2(pow2(b80, _80n, P) * b80 % P, _80n, P) * b80 % P, _10n, P) * b10 % P, _2n$4, P) * x % P, - b2 - }; -} -function adjustScalarBytes(bytes) { - bytes[0] &= 248; - bytes[31] &= 127; - bytes[31] |= 64; - return bytes; -} -const ED25519_SQRT_M1 = /* @__PURE__ */ BigInt("19681161376707505956807079304988542015446066515923890162744021073123829784752"); -function uvRatio(u, v) { - const P = ed25519_CURVE_p; - const v3 = mod(v * v * v, P); - const pow = ed25519_pow_2_252_3(u * mod(v3 * v3 * v, P)).pow_p_5_8; - let x = mod(u * v3 * pow, P); - const vx2 = mod(v * x * x, P); - const root1 = x; - const root2 = mod(x * ED25519_SQRT_M1, P); - const useRoot1 = vx2 === u; - const useRoot2 = vx2 === mod(-u, P); - const noRoot = vx2 === mod(-u * ED25519_SQRT_M1, P); - if (useRoot1) x = root1; - if (useRoot2 || noRoot) x = root2; - if (isNegativeLE(x, P)) x = mod(-x, P); - return { - isValid: useRoot1 || useRoot2, - value: x - }; -} -const ed25519_Point = /* @__PURE__ */ edwards(ed25519_CURVE, { uvRatio }); -const Fp = /* @__PURE__ */ (() => ed25519_Point.Fp)(); -function toMontgomery(point) { - const { y } = point; - return Fp.toBytes(Fp.div(_1n$3 + y, _1n$3 - y)); -} -function toMontgomerySecret(secretKey) { - const size = ed25519_Point.Fp.BYTES; - abytes$5(secretKey, size); - return adjustScalarBytes(sha512$1(secretKey.subarray(0, size))).subarray(0, size); -} -const Fn = /* @__PURE__ */ (() => ed25519_Point.Fn)(); -function ed(opts) { - return eddsa(ed25519_Point, sha512$1, Object.assign({ - adjustScalarBytes, - toMontgomery, - toMontgomerySecret, - zip215: true - }, opts)); -} -/** -* ed25519 curve with EdDSA signatures. -* Seeded `keygen(seed)` / `utils.randomSecretKey(seed)` reuse the provided -* 32-byte seed buffer instead of copying it. -* @example -* Generate one Ed25519 keypair, sign a message, and verify it. -* -* ```js -* import { ed25519 } from '@noble/curves/ed25519.js'; -* const { secretKey, publicKey } = ed25519.keygen(); -* // const publicKey = ed25519.getPublicKey(secretKey); -* const msg = new TextEncoder().encode('hello noble'); -* const sig = ed25519.sign(msg, secretKey); -* const isValid = ed25519.verify(sig, msg, publicKey); // ZIP215 -* // RFC8032 / FIPS 186-5 -* const isValid2 = ed25519.verify(sig, msg, publicKey, { zip215: false }); -* ``` -*/ -const ed25519 = /* @__PURE__ */ ed({}); -/** -* ECDH using curve25519 aka x25519. -* `getSharedSecret()` rejects low-order peer inputs by default, and seeded -* `keygen(seed)` reuses the provided 32-byte seed buffer instead of copying it. -* @example -* Derive one shared secret between two X25519 peers. -* -* ```js -* import { x25519 } from '@noble/curves/ed25519.js'; -* const alice = x25519.keygen(); -* const bob = x25519.keygen(); -* const alicePublic = x25519.getPublicKey(alice.secretKey); -* const shared = x25519.getSharedSecret(alice.secretKey, bob.publicKey); -* ``` -*/ -const x25519 = /* @__PURE__ */ (() => { - const P = ed25519_CURVE_p; - const powPminus2 = (x) => { - const { pow_p_5_8, b2 } = ed25519_pow_2_252_3(x); - return mod(pow2(pow_p_5_8, _3n$2, P) * b2, P); - }; - return montgomery({ - P, - type: "x25519", - powPminus2, - adjustScalarBytes, - scalarMultBase: (k) => { - const kn = mod(k, ed25519_Point.Fn.ORDER); - if (kn === _0n$6) return _0n$6; - const p = ed25519_Point.BASE.multiply(kn); - return mod((p.Z + p.Y) * powPminus2(mod(p.Z - p.Y, P)), P); - } - }); -})(); -const SQRT_M1 = ED25519_SQRT_M1; -const INVSQRT_A_MINUS_D = /* @__PURE__ */ BigInt("54469307008909316920995813868745141605393597292927456921205312896311721017578"); -const invertSqrt = (number) => uvRatio(_1n$3, number); -const MAX_255B = /* @__PURE__ */ BigInt("0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); -const bytes255ToNumberLE = (bytes) => Fp.create(bytesToNumberLE(bytes) & MAX_255B); -/** -* Wrapper over Edwards Point for ristretto255. -* -* Each ed25519/EdwardsPoint has 8 different equivalent points. This can be -* a source of bugs for protocols like ring signatures. Ristretto was created to solve this. -* Ristretto point operates in X:Y:Z:T extended coordinates like EdwardsPoint, -* but it should work in its own namespace: do not combine those two. -* See [RFC9496](https://www.rfc-editor.org/rfc/rfc9496). -*/ -var _RistrettoPoint = class _RistrettoPoint extends PrimeEdwardsPoint { - static BASE = /* @__PURE__ */ (() => new _RistrettoPoint(ed25519_Point.BASE))(); - static ZERO = /* @__PURE__ */ (() => new _RistrettoPoint(ed25519_Point.ZERO))(); - static Fp = /* @__PURE__ */ (() => Fp)(); - static Fn = /* @__PURE__ */ (() => Fn)(); - constructor(ep) { - super(ep); - } - /** - * Create one Ristretto255 point from affine Edwards coordinates. - * This wraps the internal Edwards representative directly and is not a - * canonical ristretto255 decoding path. - * Use `toBytes()` / `fromBytes()` if canonical ristretto255 bytes matter. - */ - static fromAffine(ap) { - return new _RistrettoPoint(ed25519_Point.fromAffine(ap)); - } - assertSame(other) { - if (!(other instanceof _RistrettoPoint)) throw new Error("RistrettoPoint expected"); - } - init(ep) { - return new _RistrettoPoint(ep); - } - static fromBytes(bytes) { - abytes$5(bytes, 32); - const { a, d } = ed25519_CURVE; - const s = bytes255ToNumberLE(bytes); - if (!equalBytes$1(Fp.toBytes(s), bytes) || Fp.isOdd(s)) throw new Error("invalid ristretto255 encoding 1"); - const s2 = Fp.sqr(s); - const u1 = Fp.add(_1n$3, Fp.mulN(a, s2)); - const u2 = Fp.sub(_1n$3, Fp.mulN(a, s2)); - const u1_2 = Fp.sqr(u1); - const u2_2 = Fp.sqr(u2); - const v = Fp.sub(Fp.mulN(Fp.mulN(a, d), u1_2), u2_2); - const { isValid, value: I } = invertSqrt(Fp.mul(v, u2_2)); - const Dx = Fp.mul(I, u2); - const Dy = Fp.mul(Fp.mulN(I, Dx), v); - let x = Fp.mul(Fp.addN(s, s), Dx); - if (Fp.isOdd(x)) x = Fp.neg(x); - const y = Fp.mul(u1, Dy); - const t = Fp.mul(x, y); - if (!isValid || Fp.isOdd(t) || Fp.is0(y)) throw new Error("invalid ristretto255 encoding 2"); - return new _RistrettoPoint(new ed25519_Point(x, y, Fp.ONE, t)); - } - /** - * Converts ristretto-encoded string to ristretto point. - * Described in [RFC9496](https://www.rfc-editor.org/rfc/rfc9496#name-decode). - * @param hex - Ristretto-encoded 32 bytes. Not every 32-byte string is valid ristretto encoding - */ - static fromHex(hex) { - return _RistrettoPoint.fromBytes(hexToBytes$2(hex)); - } - /** - * Encodes ristretto point to Uint8Array. - * Described in [RFC9496](https://www.rfc-editor.org/rfc/rfc9496#name-encode). - */ - toBytes() { - let { X, Y, Z, T } = this.ep; - const u1 = Fp.mul(Fp.add(Z, Y), Fp.sub(Z, Y)); - const u2 = Fp.mul(X, Y); - const u2sq = Fp.sqr(u2); - const { value: invsqrt } = invertSqrt(Fp.mul(u1, u2sq)); - const D1 = Fp.mul(invsqrt, u1); - const D2 = Fp.mul(invsqrt, u2); - const zInv = Fp.mul(Fp.mulN(D1, D2), T); - let D; - if (Fp.isOdd(Fp.mul(T, zInv))) { - let _x = Fp.mul(Y, SQRT_M1); - let _y = Fp.mul(X, SQRT_M1); - X = _x; - Y = _y; - D = Fp.mul(D1, INVSQRT_A_MINUS_D); - } else D = D2; - if (Fp.isOdd(Fp.mul(X, zInv))) Y = Fp.neg(Y); - let s = Fp.mul(Fp.subN(Z, Y), D); - if (Fp.isOdd(s)) s = Fp.neg(s); - return Fp.toBytes(s); - } - /** - * Compares two Ristretto points. - * Described in [RFC9496](https://www.rfc-editor.org/rfc/rfc9496#name-equals). - */ - equals(other) { - this.assertSame(other); - const { X: X1, Y: Y1 } = this.ep; - const { X: X2, Y: Y2 } = other.ep; - const one = Fp.eql(Fp.mul(X1, Y2), Fp.mul(Y1, X2)); - const two = Fp.eql(Fp.mul(Y1, Y2), Fp.mul(X1, X2)); - return one || two; - } - is0() { - return this.equals(_RistrettoPoint.ZERO); - } -}; -/** Prime-order Ristretto255 group bundle. */ -const ristretto255 = /* @__PURE__ */ (() => { - Object.freeze(_RistrettoPoint.BASE); - Object.freeze(_RistrettoPoint.ZERO); - Object.freeze(_RistrettoPoint.prototype); - Object.freeze(_RistrettoPoint); - return Object.freeze({ Point: _RistrettoPoint }); -})(); -//#endregion -//#region tests/baseline/node_modules/@noble/curves/abstract/der.js -/** -* ASN.1 DER (Distinguished Encoding Rules) helpers for ECDSA signatures. -* Only implements the tiny subset needed for `SEQUENCE(INTEGER r, INTEGER s)`. -* @module -*/ -/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ -const _0n$5 = /* @__PURE__ */ BigInt(0); -/** -* @param m - Error message. -* @example -* Throw a DER-specific error when signature parsing encounters invalid bytes. -* -* ```ts -* new DERErr('bad der'); -* ``` -*/ -var DERErr = class extends Error { - constructor(m = "") { - super(m); - } -}; -const _DER = { - Err: DERErr, - _tlv: { - encode: (tag, data) => { - const { Err: E } = _DER; - asafenumber(tag, "tag"); - if (tag < 0 || tag > 255) throw new E("tlv.encode: wrong tag"); - astring(data, "data"); - if (data.length & 1) throw new E("tlv.encode: unpadded data"); - const dataLen = data.length / 2; - const len = numberToHexUnpadded(dataLen); - if (len.length / 2 & 128) throw new E("tlv.encode: long form length too big"); - const lenLen = dataLen > 127 ? numberToHexUnpadded(len.length / 2 | 128) : ""; - return numberToHexUnpadded(tag) + lenLen + len + data; - }, - decode(tag, data) { - const { Err: E } = _DER; - data = abytes$3(data, void 0, "DER data"); - let pos = 0; - if (tag < 0 || tag > 255) throw new E("tlv.decode: wrong tag"); - if (data.length < 2 || data[pos++] !== tag) throw new E("tlv.decode: wrong tlv"); - const first = data[pos++]; - const isLong = !!(first & 128); - let length = 0; - if (!isLong) length = first; - else { - const lenLen = first & 127; - if (!lenLen) throw new E("tlv.decode(long): indefinite length not supported"); - if (lenLen > 4) throw new E("tlv.decode(long): byte length is too big"); - const lengthBytes = data.subarray(pos, pos + lenLen); - if (lengthBytes.length !== lenLen) throw new E("tlv.decode: length bytes not complete"); - if (lengthBytes[0] === 0) throw new E("tlv.decode(long): zero leftmost byte"); - for (const b of lengthBytes) length = length << 8 | b; - pos += lenLen; - if (length < 128) throw new E("tlv.decode(long): not minimal encoding"); - } - const v = data.subarray(pos, pos + length); - if (v.length !== length) throw new E("tlv.decode: wrong value length"); - return { - v, - l: data.subarray(pos + length) - }; - } - }, - _int: { - encode(num) { - const { Err: E } = _DER; - abignumber(num); - if (num < _0n$5) throw new E("integer: negative integers are not allowed"); - let hex = numberToHexUnpadded(num); - if (Number.parseInt(hex[0], 16) & 8) hex = "00" + hex; - if (hex.length & 1) throw new E("unexpected DER parsing assertion: unpadded hex"); - return hex; - }, - decode(data) { - const { Err: E } = _DER; - if (data.length < 1) throw new E("invalid signature integer: empty"); - if (data[0] & 128) throw new E("invalid signature integer: negative"); - if (data.length > 1 && data[0] === 0 && !(data[1] & 128)) throw new E("invalid signature integer: unnecessary leading zero"); - return bytesToNumberBE(data); - } - }, - toSig(bytes, maxScalarBytes) { - const { Err: E, _int: int, _tlv: tlv } = _DER; - if (maxScalarBytes !== void 0) { - asafenumber(maxScalarBytes, "maxScalarBytes"); - if (maxScalarBytes < 1) throw new E("invalid signature: maxScalarBytes must be positive"); - } - const data = abytes$3(bytes, void 0, "signature"); - const { v: seqBytes, l: seqLeftBytes } = tlv.decode(48, data); - if (seqLeftBytes.length) throw new E("invalid signature: left bytes after parsing"); - const { v: rBytes, l: rLeftBytes } = tlv.decode(2, seqBytes); - const { v: sBytes, l: sLeftBytes } = tlv.decode(2, rLeftBytes); - if (sLeftBytes.length) throw new E("invalid signature: left bytes after parsing"); - if (maxScalarBytes !== void 0 && (rBytes.length > maxScalarBytes || sBytes.length > maxScalarBytes)) throw new E("invalid signature: integer too large"); - return { - r: int.decode(rBytes), - s: int.decode(sBytes) - }; - }, - hexFromSig(sig) { - const { _tlv: tlv, _int: int } = _DER; - validateObject(sig, { - r: "bigint", - s: "bigint" - }, {}, "sig"); - const seq = tlv.encode(2, int.encode(sig.r)) + tlv.encode(2, int.encode(sig.s)); - return tlv.encode(48, seq); - } -}; -/** -* ASN.1 DER encoding utilities. ASN is very complex & fragile. Format: -* -* [0x30 (SEQUENCE), bytelength, 0x02 (INTEGER), intLength, R, 0x02 (INTEGER), intLength, S] -* -* Docs: {@link https://letsencrypt.org/docs/a-warm-welcome-to-asn1-and-der/ | Let's Encrypt ASN.1 guide} and -* {@link https://luca.ntop.org/Teaching/Appunti/asn1.html | Luca Deri's ASN.1 notes}. -* @example -* ASN.1 DER encoding utilities. -* -* ```ts -* const der = DER.hexFromSig({ r: 1n, s: 2n }); -* ``` -*/ -const DER = /* @__PURE__ */ (() => { - Object.freeze(_DER._tlv); - Object.freeze(_DER._int); - return Object.freeze(_DER); -})(); -//#endregion -//#region tests/baseline/node_modules/@noble/curves/abstract/weierstrass.js -/** -* Short Weierstrass curve methods. The formula is: y² = x³ + ax + b. -* -* ### Design rationale for types -* -* * Interaction between classes from different curves should fail: -* `k256.Point.BASE.add(p256.Point.BASE)` -* * For this purpose we want to use `instanceof` operator, which is fast and works during runtime -* * Different calls of `curve()` would return different classes - -* `curve(params) !== curve(params)`: if somebody decided to monkey-patch their curve, -* it won't affect others -* -* TypeScript can't infer types for classes created inside a function. Classes is one instance -* of nominative types in TypeScript and interfaces only check for shape, so it's hard to create -* unique type for every function call. -* -* We can use generic types via some param, like curve opts, but that would: -* 1. Enable interaction between `curve(params)` and `curve(params)` (curves of same params) -* which is hard to debug. -* 2. Params can be generic and we can't enforce them to be constant value: -* if somebody creates curve from non-constant params, -* it would be allowed to interact with other curves with non-constant params -* -* @todo https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html#unique-symbol -* @module -*/ -/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ -const divNearest = (num, den) => (num + (num >= 0 ? den : -den) / _2n$3) / den; -/** Splits scalar for GLV endomorphism. */ -function _splitEndoScalar(k, basis, n) { - aInRange("scalar", k, _0n$4, n); - const [[a1, b1], [a2, b2]] = basis; - const c1 = divNearest(b2 * k, n); - const c2 = divNearest(-b1 * k, n); - let k1 = k - c1 * a1 - c2 * a2; - let k2 = -c1 * b1 - c2 * b2; - const k1neg = k1 < _0n$4; - const k2neg = k2 < _0n$4; - if (k1neg) k1 = -k1; - if (k2neg) k2 = -k2; - const MAX_NUM = bitMask(Math.ceil(bitLen(n) / 2)) + _1n$2; - if (k1 < _0n$4 || k1 >= MAX_NUM || k2 < _0n$4 || k2 >= MAX_NUM) throw new Error("splitScalar (endomorphism): failed for k"); - return { - k1neg, - k1, - k2neg, - k2 - }; -} -function validateSigFormat(format) { - if (![ - "compact", - "recovered", - "der" - ].includes(format)) throw new Error("Signature format must be \"compact\", \"recovered\", or \"der\""); - return format; -} -function validateSigOpts$1(opts, def) { - validateObject(opts); - const optsn = {}; - for (let optName of Object.keys(def)) optsn[optName] = opts[optName] === void 0 ? def[optName] : opts[optName]; - abool$1(optsn.lowS, "lowS"); - abool$1(optsn.prehash, "prehash"); - if (optsn.format !== void 0) validateSigFormat(optsn.format); - return optsn; -} -const _0n$4 = /* @__PURE__ */ BigInt(0); -const _1n$2 = /* @__PURE__ */ BigInt(1); -const _2n$3 = /* @__PURE__ */ BigInt(2); -const _3n$1 = /* @__PURE__ */ BigInt(3); -const _4n = /* @__PURE__ */ BigInt(4); -/** -* Creates weierstrass Point constructor, based on specified curve options. -* -* See {@link WeierstrassOpts}. -* @param params - Curve parameters. See {@link WeierstrassOpts}. -* @param extraOpts - Optional helpers and overrides. See {@link WeierstrassExtraOpts}. -* @returns Weierstrass point constructor. -* @throws If the curve parameters, overrides, or point codecs are invalid. {@link Error} -* -* @example -* Construct a point type from explicit Weierstrass curve parameters. -* -* ```js -* const opts = { -* p: 0xfffffffffffffffffffffffffffffffeffffac73n, -* n: 0x100000000000000000001b8fa16dfab9aca16b6b3n, -* h: 1n, -* a: 0n, -* b: 7n, -* Gx: 0x3b4c382ce37aa192a4019e763036f4f5dd4d7ebbn, -* Gy: 0x938cf935318fdced6bc28286531733c3f03c4feen, -* }; -* const secp160k1_Point = weierstrass(opts); -* ``` -*/ -function weierstrass(params, extraOpts = {}) { - const validated = createCurveFields("weierstrass", params, extraOpts); - const Fp = validated.Fp; - const Fn = validated.Fn; - let CURVE = validated.CURVE; - const { h: cofactor, n: CURVE_ORDER } = CURVE; - validateObject(extraOpts, {}, { - allowInfinityPoint: "boolean", - clearCofactor: "function", - isTorsionFree: "function", - fromBytes: "function", - toBytes: "function", - endo: "object", - randomBytes: "function" - }); - const { endo: endoOpts, allowInfinityPoint, clearCofactor, isTorsionFree, fromBytes, toBytes } = extraOpts; - const randomBytes = extraOpts.randomBytes === void 0 ? randomBytes$2 : extraOpts.randomBytes; - if (endoOpts) { - if (!Fp.is0(CURVE.a) || typeof endoOpts.beta !== "bigint" || !Array.isArray(endoOpts.basises)) throw new Error("invalid endo: expected \"beta\": bigint and \"basises\": array"); - } - const endo = endoOpts ? { - beta: endoOpts.beta, - basises: endoOpts.basises.map((basis) => [...basis]) - } : void 0; - const lengths = getWLengths(Fp, Fn); - function assertCompressionIsSupported() { - if (!Fp.isOdd) throw new Error("compression is not supported: Field does not have .isOdd()"); - } - function pointToBytes(_c, point, isCompressed) { - if (point.is0()) { - if (!allowInfinityPoint) throw new Error("bad point: ZERO"); - return Uint8Array.of(0); - } - const { x, y } = point.toAffine(); - const bx = Fp.toBytes(x); - abool$1(isCompressed, "isCompressed"); - if (isCompressed) { - assertCompressionIsSupported(); - const hasEvenY = !Fp.isOdd(y); - return concatBytes$2(pprefix(hasEvenY), bx); - } else return concatBytes$2(Uint8Array.of(4), bx, Fp.toBytes(y)); - } - function pointFromBytes(bytes) { - abytes$3(bytes, void 0, "Point"); - const { publicKey: comp, publicKeyUncompressed: uncomp } = lengths; - const length = bytes.length; - const head = bytes[0]; - const tail = bytes.subarray(1); - if (allowInfinityPoint && length === 1 && head === 0) return { - x: Fp.ZERO, - y: Fp.ZERO - }; - if (length === comp && (head === 2 || head === 3)) { - const x = Fp.fromBytes(tail); - if (!Fp.isValid(x)) throw new Error("bad point: is not on curve, wrong x"); - const y2 = weierstrassEquation(x); - let y; - try { - y = Fp.sqrt(y2); - } catch (sqrtError) { - const err = sqrtError instanceof Error ? ": " + sqrtError.message : ""; - throw new Error("bad point: is not on curve, sqrt error" + err); - } - assertCompressionIsSupported(); - const evenY = Fp.isOdd(y); - if ((head & 1) === 1 !== evenY) y = Fp.neg(y); - return { - x, - y - }; - } else if (length === uncomp && head === 4) { - const L = Fp.BYTES; - const x = Fp.fromBytes(tail.subarray(0, L)); - const y = Fp.fromBytes(tail.subarray(L, L * 2)); - if (!isValidXY(x, y)) throw new Error("bad point: is not on curve"); - return { - x, - y - }; - } else throw new Error(`bad point: got length ${length}, expected compressed=${comp} or uncompressed=${uncomp}`); - } - const encodePoint = toBytes === void 0 ? pointToBytes : toBytes; - const decodePoint = fromBytes === void 0 ? pointFromBytes : fromBytes; - const b3 = Fp.mul(CURVE.b, _3n$1); - const mulA = Fp.is0(CURVE.a) ? (_) => Fp.ZERO : (x) => Fp.mul(CURVE.a, x); - function weierstrassEquation(x) { - const x2 = Fp.sqr(x); - const x3 = Fp.mul(x2, x); - return Fp.add(Fp.add(x3, Fp.mul(x, CURVE.a)), CURVE.b); - } - /** Checks whether equation holds for given x, y: y² == x³ + ax + b */ - function isValidXY(x, y) { - const left = Fp.sqr(y); - const right = weierstrassEquation(x); - return Fp.eql(left, right); - } - if (!isValidXY(CURVE.Gx, CURVE.Gy)) throw new Error("bad curve params: generator point"); - const _4a3 = Fp.mul(Fp.pow(CURVE.a, _3n$1), _4n); - const _27b2 = Fp.mul(Fp.sqr(CURVE.b), BigInt(27)); - if (Fp.is0(Fp.add(_4a3, _27b2))) throw new Error("bad curve params: a or b"); - /** Asserts coordinate is valid: 0 <= n < Fp.ORDER. */ - function acoord(title, n, banZero = false) { - if (!Fp.isValid(n) || banZero && Fp.is0(n)) throw new Error(`bad point coordinate ${title}`); - return typeof n === "object" && n !== null ? Fp.create(n) : n; - } - function aprjpoint(other) { - if (!(other instanceof Point)) throw new Error("Weierstrass Point expected"); - } - function splitEndoScalarN(k) { - if (!endo || !endo.basises) throw new Error("no endo"); - return _splitEndoScalar(k, endo.basises, Fn.ORDER); - } - /** - * Appends a (point, scalar) pair to the inputs of a vartime wNAF walk - * ({@link mulAddUnsafe}). With GLV endomorphism the scalar is split into two half-width - * pairs against P and ψ(P) = (β⋅x, y), halving the walk's shared doubling chain; - * split signs fold into the points. - */ - function pushWnafPair(points, scalars, p, k) { - if (!Fn.isValid(k)) throw new RangeError("invalid scalar: out of range"); - if (endo) { - const { k1neg, k1, k2neg, k2 } = splitEndoScalarN(k); - const psi = new Point(Fp.mul(p.X, endo.beta), p.Y, p.Z); - points.push(k1neg ? p.negate() : p, k2neg ? psi.negate() : psi); - scalars.push(k1, k2); - } else { - points.push(p); - scalars.push(k); - } - } - const validityCache = /* @__PURE__ */ new WeakSet(); - /** - * Projective Point works in 3d / projective (homogeneous) coordinates:(X, Y, Z) ∋ (x=X/Z, y=Y/Z). - * Default Point works in 2d / affine coordinates: (x, y). - * We're doing calculations in projective, because its operations don't require costly inversion. - */ - class Point { - static BASE = new Point(CURVE.Gx, CURVE.Gy, Fp.ONE); - static ZERO = new Point(Fp.ZERO, Fp.ONE, Fp.ZERO); - static Fp = Fp; - static Fn = Fn; - X; - Y; - Z; - /** Does NOT validate if the point is valid. Use `.assertValidity()`. */ - constructor(X, Y, Z) { - this.X = acoord("x", X); - this.Y = acoord("y", Y, true); - this.Z = acoord("z", Z); - Object.freeze(this); - } - static CURVE() { - return CURVE; - } - /** Does NOT validate if the point is valid. Use `.assertValidity()`. */ - static fromAffine(p) { - const { x, y } = p || {}; - if (!p || !Fp.isValid(x) || !Fp.isValid(y)) throw new Error("invalid affine point"); - if (p instanceof Point) throw new Error("projective point not allowed"); - if (Fp.is0(x) && Fp.is0(y)) return Point.ZERO; - return new Point(x, y, Fp.ONE); - } - static fromBytes(bytes) { - const P = Point.fromAffine(decodePoint(abytes$3(bytes, void 0, "point"))); - P.assertValidity(); - return P; - } - static fromHex(hex) { - return Point.fromBytes(hexToBytes$1(hex)); - } - get x() { - return this.toAffine().x; - } - get y() { - return this.toAffine().y; - } - /** - * @param isLazy - true will defer table computation until the first multiplication - */ - precompute(windowSize = 6, isLazy = true) { - wnaf.setWindowSize(this, windowSize); - if (!isLazy) this.multiply(_3n$1); - return this; - } - /** A point on curve is valid if it conforms to equation. */ - assertValidity() { - const p = this; - if (p.is0()) { - if (allowInfinityPoint && Fp.is0(p.X) && Fp.eql(p.Y, Fp.ONE) && Fp.is0(p.Z)) return; - throw new Error("bad point: ZERO"); - } - if (validityCache.has(p)) return; - const { x, y } = p.toAffine(); - if (!Fp.isValid(x) || !Fp.isValid(y)) throw new Error("bad point: x or y not field elements"); - if (!isValidXY(x, y)) throw new Error("bad point: equation left != right"); - if (!p.isTorsionFree()) throw new Error("bad point: not in prime-order subgroup"); - validityCache.add(p); - } - hasEvenY() { - const { y } = this.toAffine(); - if (!Fp.isOdd) throw new Error("Field doesn't support isOdd"); - return !Fp.isOdd(y); - } - /** Compare one point to another. */ - equals(other) { - aprjpoint(other); - const { X: X1, Y: Y1, Z: Z1 } = this; - const { X: X2, Y: Y2, Z: Z2 } = other; - const U1 = Fp.eql(Fp.mul(X1, Z2), Fp.mul(X2, Z1)); - const U2 = Fp.eql(Fp.mul(Y1, Z2), Fp.mul(Y2, Z1)); - return U1 && U2; - } - /** Flips point to one corresponding to (x, -y) in Affine coordinates. */ - negate() { - return new Point(this.X, Fp.neg(this.Y), this.Z); - } - double() { - const { X: X1, Y: Y1, Z: Z1 } = this; - let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO; - let t0 = Fp.mul(X1, X1); - let t1 = Fp.mul(Y1, Y1); - let t2 = Fp.mul(Z1, Z1); - let t3 = Fp.mul(X1, Y1); - t3 = Fp.add(t3, t3); - Z3 = Fp.mul(X1, Z1); - Z3 = Fp.add(Z3, Z3); - X3 = mulA(Z3); - Y3 = Fp.mul(b3, t2); - Y3 = Fp.add(X3, Y3); - X3 = Fp.sub(t1, Y3); - Y3 = Fp.add(t1, Y3); - Y3 = Fp.mul(X3, Y3); - X3 = Fp.mul(t3, X3); - Z3 = Fp.mul(b3, Z3); - t2 = mulA(t2); - t3 = Fp.sub(t0, t2); - t3 = mulA(t3); - t3 = Fp.add(t3, Z3); - Z3 = Fp.add(t0, t0); - t0 = Fp.add(Z3, t0); - t0 = Fp.add(t0, t2); - t0 = Fp.mul(t0, t3); - Y3 = Fp.add(Y3, t0); - t2 = Fp.mul(Y1, Z1); - t2 = Fp.add(t2, t2); - t0 = Fp.mul(t2, t3); - X3 = Fp.sub(X3, t0); - Z3 = Fp.mul(t2, t1); - Z3 = Fp.add(Z3, Z3); - Z3 = Fp.add(Z3, Z3); - return new Point(X3, Y3, Z3); - } - add(other) { - aprjpoint(other); - const { X: X1, Y: Y1, Z: Z1 } = this; - const { X: X2, Y: Y2, Z: Z2 } = other; - let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO; - let t0 = Fp.mul(X1, X2); - let t1 = Fp.mul(Y1, Y2); - let t2 = Fp.mul(Z1, Z2); - let t3 = Fp.add(X1, Y1); - let t4 = Fp.add(X2, Y2); - t3 = Fp.mul(t3, t4); - t4 = Fp.add(t0, t1); - t3 = Fp.sub(t3, t4); - t4 = Fp.add(X1, Z1); - let t5 = Fp.add(X2, Z2); - t4 = Fp.mul(t4, t5); - t5 = Fp.add(t0, t2); - t4 = Fp.sub(t4, t5); - t5 = Fp.add(Y1, Z1); - X3 = Fp.add(Y2, Z2); - t5 = Fp.mul(t5, X3); - X3 = Fp.add(t1, t2); - t5 = Fp.sub(t5, X3); - Z3 = mulA(t4); - X3 = Fp.mul(b3, t2); - Z3 = Fp.add(X3, Z3); - X3 = Fp.sub(t1, Z3); - Z3 = Fp.add(t1, Z3); - Y3 = Fp.mul(X3, Z3); - t1 = Fp.add(t0, t0); - t1 = Fp.add(t1, t0); - t2 = mulA(t2); - t4 = Fp.mul(b3, t4); - t1 = Fp.add(t1, t2); - t2 = Fp.sub(t0, t2); - t2 = mulA(t2); - t4 = Fp.add(t4, t2); - t0 = Fp.mul(t1, t4); - Y3 = Fp.add(Y3, t0); - t0 = Fp.mul(t5, t4); - X3 = Fp.mul(t3, X3); - X3 = Fp.sub(X3, t0); - t0 = Fp.mul(t3, t1); - Z3 = Fp.mul(t5, Z3); - Z3 = Fp.add(Z3, t0); - return new Point(X3, Y3, Z3); - } - subtract(other) { - aprjpoint(other); - return this.add(other.negate()); - } - is0() { - return this.equals(Point.ZERO); - } - /** - * Constant time multiplication. - * Uses precomputed tables (signed fixed-window wNAF) when available. - * Uses scalar blinding and avoids endomorphism splitting in the secret-scalar path. - * @param scalar - by which the point would be multiplied - * @returns New point - */ - multiply(scalar) { - if (!Fn.isValidNot0(scalar)) throw new RangeError("invalid scalar: out of range"); - const { p, f } = wnaf.mulSecret(this, scalar, cofactor, normalize); - return normalize([p, f])[0]; - } - /** - * Non-constant-time multiplication. Uses width-4 wNAF with GLV endomorphism splitting - * when available (two half-width scalars sharing one halved doubling chain). - * It's faster, but should only be used when you don't care about - * an exposed secret key e.g. sig verification, which works over *public* keys. - */ - multiplyUnsafe(scalar) { - const p = this; - const sc = scalar; - if (!Fn.isValid(sc)) throw new RangeError("invalid scalar: out of range"); - if (sc === _0n$4 || p.is0()) return Point.ZERO; - if (sc === _1n$2) return p; - if (wnaf.hasWindowSize(this)) return wnaf.mulUnsafe(p, sc, normalize); - const points = []; - const scalars = []; - pushWnafPair(points, scalars, p, sc); - return mulAddUnsafe(Point, points, scalars); - } - /** - * Non-constant-time double-scalar multiplication `a⋅this + b⋅other` (Strauss–Shamir). - * Both walks share one doubling chain via {@link mulAddUnsafe}, and GLV endomorphism - * (when available) halves the chain again by splitting each scalar into two half-width - * parts. Used by ECDSA verification and public-key recovery for `R = u1⋅G + u2⋅P`. - * Only for public scalars. - */ - mulAddUnsafe(a, other, b) { - aprjpoint(other); - const points = []; - const scalars = []; - pushWnafPair(points, scalars, this, a); - pushWnafPair(points, scalars, other, b); - return mulAddUnsafe(Point, points, scalars); - } - /** - * Converts Projective point to affine (x, y) coordinates. - * (X, Y, Z) ∋ (x=X/Z, y=Y/Z). - * @param invertedZ - Z^-1 (inverted zero) - optional, precomputation is useful for invertBatch - */ - toAffine(invertedZ) { - const p = this; - let iz = invertedZ; - if (iz != null && !Fp.isValid(iz)) throw new RangeError("\"invertedZ\" expected valid field element"); - const { X, Y, Z } = p; - if (Fp.eql(Z, Fp.ONE)) return { - x: X, - y: Y - }; - const is0 = p.is0(); - if (iz == null) iz = is0 ? Fp.ONE : Fp.inv(Z); - const x = Fp.mul(X, iz); - const y = Fp.mul(Y, iz); - const zz = Fp.mul(Z, iz); - if (is0) return { - x: Fp.ZERO, - y: Fp.ZERO - }; - if (!Fp.eql(zz, Fp.ONE)) throw new Error("invZ was invalid"); - return { - x, - y - }; - } - /** - * Checks whether Point is free of torsion elements (is in prime subgroup). - * Always torsion-free for cofactor=1 curves. - */ - isTorsionFree() { - if (cofactor === _1n$2) return true; - if (isTorsionFree) return isTorsionFree(Point, this); - return wnaf.mulUnsafe(this, CURVE_ORDER).is0(); - } - clearCofactor() { - if (cofactor === _1n$2) return this; - if (clearCofactor) return clearCofactor(Point, this); - return this.multiplyUnsafe(cofactor); - } - isSmallOrder() { - if (cofactor === _1n$2) return this.is0(); - return this.clearCofactor().is0(); - } - toBytes(isCompressed = true) { - abool$1(isCompressed, "isCompressed"); - this.assertValidity(); - return encodePoint(Point, this, isCompressed); - } - toHex(isCompressed = true) { - return bytesToHex$2(this.toBytes(isCompressed)); - } - toString() { - return ``; - } - } - const normalize = (points) => normalizeZ(Point, points); - const wnaf = new ScalarMultiplier(Point, randomBytes); - if (wnaf.bits >= 6) Point.BASE.precompute(6); - Object.freeze(Point.prototype); - Object.freeze(Point); - return Point; -} -function pprefix(hasEvenY) { - return Uint8Array.of(hasEvenY ? 2 : 3); -} -function getWLengths(Fp, Fn) { - return { - secretKey: Fn.BYTES, - publicKey: 1 + Fp.BYTES, - publicKeyUncompressed: 1 + 2 * Fp.BYTES, - publicKeyHasPrefix: true, - signature: 2 * Fn.BYTES - }; -} -/** -* Sometimes users only need getPublicKey, getSharedSecret, and secret key handling. -* This helper ensures no signature functionality is present. Less code, smaller bundle size. -* @param Point - Weierstrass point constructor. -* @param ecdhOpts - Optional randomness helpers: -* - `randomBytes` (optional): Optional RNG override. -* @returns ECDH helper namespace. -* @example -* Sometimes users only need getPublicKey, getSharedSecret, and secret key handling. -* -* ```ts -* import { ecdh } from '@noble/curves/abstract/weierstrass.js'; -* import { p256 } from '@noble/curves/nist.js'; -* const dh = ecdh(p256.Point); -* const alice = dh.keygen(); -* const shared = dh.getSharedSecret(alice.secretKey, alice.publicKey); -* ``` -*/ -function ecdh(Point, ecdhOpts = {}) { - validatePointCons(Point); - const { Fn } = Point; - const randomBytes_ = ecdhOpts.randomBytes === void 0 ? randomBytes$2 : ecdhOpts.randomBytes; - const lengths = Object.assign(getWLengths(Point.Fp, Fn), { seed: Math.max(getMinHashLength(Fn.ORDER), 16) }); - function isValidSecretKey(secretKey) { - try { - const num = Fn.fromBytes(secretKey); - return Fn.isValidNot0(num); - } catch (error) { - return false; - } - } - function isValidPublicKey(publicKey, isCompressed) { - const { publicKey: comp, publicKeyUncompressed } = lengths; - try { - const l = publicKey.length; - if (isCompressed === true && l !== comp) return false; - if (isCompressed === false && l !== publicKeyUncompressed) return false; - return !Point.fromBytes(publicKey).is0(); - } catch (error) { - return false; - } - } - /** - * Produces cryptographically secure secret key from random of size - * (groupLen + ceil(groupLen / 2)) with modulo bias being negligible. - */ - function randomSecretKey(seed) { - seed = seed === void 0 ? randomBytes_(lengths.seed) : seed; - return mapHashToField(abytes$3(seed, lengths.seed, "seed"), Fn.ORDER); - } - /** - * Computes public key for a secret key. Checks for validity of the secret key. - * @param isCompressed - whether to return compact (default), or full key - * @returns Public key, full when isCompressed=false; short when isCompressed=true - */ - function getPublicKey(secretKey, isCompressed = true) { - return Point.BASE.multiply(Fn.fromBytes(secretKey)).toBytes(isCompressed); - } - /** - * Quick and dirty check for item being public key. Does not validate hex, or being on-curve. - */ - function isProbPub(item) { - const { secretKey, publicKey, publicKeyUncompressed } = lengths; - const allowedLengths = Fn._lengths; - if (!isBytes$2(item)) return void 0; - const l = abytes$3(item, void 0, "key").length; - const isPub = l === publicKey || l === publicKeyUncompressed; - const isSec = l === secretKey || !!allowedLengths?.includes(l); - if (isPub && isSec) return void 0; - return isPub; - } - /** - * ECDH (Elliptic Curve Diffie Hellman). - * Computes encoded shared point from secret key A and public key B. - * Checks: 1) secret key validity 2) shared key is on-curve. - * Does NOT hash the result or expose the SEC 1 x-coordinate-only `z`. - * Returns the encoded shared point on purpose: callers that need `x_P` - * can derive it from the encoded point, but `x_P` alone cannot recover the - * point/parity back. - * This helper only exposes the fully validated public-key path, not cofactor DH. - * @param isCompressed - whether to return compact (default), or full key - * @returns shared point encoding - */ - function getSharedSecret(secretKeyA, publicKeyB, isCompressed = true) { - if (isProbPub(secretKeyA) === true) throw new Error("first arg must be private key"); - if (isProbPub(publicKeyB) === false) throw new Error("second arg must be public key"); - const s = Fn.fromBytes(secretKeyA); - const b = Point.fromBytes(publicKeyB); - if (b.is0()) throw new Error("invalid public key: point at infinity"); - return b.multiply(s).toBytes(isCompressed); - } - const utils = { - isValidSecretKey, - isValidPublicKey, - randomSecretKey - }; - const keygen = createKeygen(randomSecretKey, getPublicKey); - Object.freeze(utils); - Object.freeze(lengths); - return Object.freeze({ - getPublicKey, - getSharedSecret, - keygen, - Point, - utils, - lengths - }); -} -/** -* Creates ECDSA signing interface for given elliptic curve `Point` and `hash` function. -* -* @param Point - created using {@link weierstrass} function -* @param hash - used for 1) message prehash-ing 2) k generation in `sign`, using hmac_drbg(hash) -* @param ecdsaOpts - rarely needed, see {@link ECDSAOpts}: -* - `lowS`: Default low-S policy. -* - `hmac`: HMAC implementation used by RFC6979 DRBG. -* - `randomBytes`: Optional RNG override. -* - `bits2int`: Optional hash-to-int conversion override. -* - `bits2int_modN`: Optional hash-to-int-mod-n conversion override. -* -* @returns ECDSA helper namespace. -* @example -* Create an ECDSA signer/verifier bundle for one curve implementation. -* -* ```ts -* import { ecdsa } from '@noble/curves/abstract/weierstrass.js'; -* import { p256 } from '@noble/curves/nist.js'; -* import { sha256 } from '@noble/hashes/sha2.js'; -* const p256ecdsa = ecdsa(p256.Point, sha256); -* const { secretKey, publicKey } = p256ecdsa.keygen(); -* const msg = new TextEncoder().encode('hello noble'); -* const sig = p256ecdsa.sign(msg, secretKey); -* const isValid = p256ecdsa.verify(sig, msg, publicKey); -* ``` -*/ -function ecdsa(Point, hash, ecdsaOpts = {}) { - validatePointCons(Point); - const hash_ = hash; - ahash(hash_); - validateObject(ecdsaOpts, {}, { - hmac: "function", - lowS: "boolean", - randomBytes: "function", - bits2int: "function", - bits2int_modN: "function" - }); - const opts = Object.assign({}, ecdsaOpts); - const randomBytes = opts.randomBytes === void 0 ? randomBytes$2 : opts.randomBytes; - const hmac$1 = opts.hmac === void 0 ? (key, msg) => hmac(hash_, key, msg) : opts.hmac; - const { Fp, Fn } = Point; - const { ORDER: CURVE_ORDER, BITS: fnBits } = Fn; - const blindLength = getMinHashLength(CURVE_ORDER); - const csprng = probeRandomBytes(randomBytes, blindLength); - const { keygen, getPublicKey, getSharedSecret, utils, lengths } = ecdh(Point, opts); - const defaultSigOpts = { - prehash: true, - lowS: typeof opts.lowS === "boolean" ? opts.lowS : true, - format: "compact", - extraEntropy: false - }; - const hasLargeRecoveryLifts = CURVE_ORDER * _2n$3 + _1n$2 < Fp.ORDER; - function isBiggerThanHalfOrder(number) { - return number > CURVE_ORDER >> _1n$2; - } - function validateRS(title, num) { - if (!Fn.isValidNot0(num)) throw new Error(`invalid signature ${title}: out of range 1..Point.Fn.ORDER`); - return num; - } - function assertFieldSignIsSupported() { - if (!Fp.isOdd) throw new Error("Field doesn't support isOdd"); - } - function getRecoveryBit(x, y, r) { - assertFieldSignIsSupported(); - return (x === r ? 0 : 2) | Number(Fp.isOdd(y)); - } - function assertRecoverableCurve() { - if (hasLargeRecoveryLifts) throw new Error("\"recovered\" sig type is not supported for cofactor >2 curves"); - } - function validateSigLength(bytes, format) { - validateSigFormat(format); - const size = lengths.signature; - const sizer = format === "compact" ? size : format === "recovered" ? size + 1 : void 0; - return abytes$3(bytes, sizer); - } - /** - * ECDSA signature with its (r, s) properties. Supports compact, recovered & DER representations. - */ - class Signature { - r; - s; - recovery; - constructor(r, s, recovery) { - this.r = validateRS("r", r); - this.s = validateRS("s", s); - if (recovery != null) { - assertRecoverableCurve(); - if (![ - 0, - 1, - 2, - 3 - ].includes(recovery)) throw new Error("invalid recovery id"); - this.recovery = recovery; - } - Object.freeze(this); - } - static fromBytes(bytes, format = defaultSigOpts.format) { - validateSigLength(bytes, format); - let recid; - if (format === "der") { - if (bytes.length > 2 * Fn.BYTES + 16) throw new DER.Err("invalid signature: DER signature too long"); - const { r, s } = DER.toSig(abytes$3(bytes), Fn.BYTES + 1); - return new Signature(r, s); - } - if (format === "recovered") { - recid = bytes[0]; - format = "compact"; - bytes = bytes.subarray(1); - } - const L = lengths.signature / 2; - const r = bytes.subarray(0, L); - const s = bytes.subarray(L, L * 2); - return new Signature(Fn.fromBytes(r), Fn.fromBytes(s), recid); - } - static fromHex(hex, format) { - return this.fromBytes(hexToBytes$1(hex), format); - } - assertRecovery() { - const { recovery } = this; - if (recovery == null) throw new Error("invalid recovery id: must be present"); - return recovery; - } - addRecoveryBit(recovery) { - return new Signature(this.r, this.s, recovery); - } - recoverPublicKey(messageHash) { - const { r, s } = this; - const recovery = this.assertRecovery(); - const radj = recovery === 2 || recovery === 3 ? r + CURVE_ORDER : r; - if (!Fp.isValid(radj)) throw new Error("invalid recovery id: sig.r+curve.n != R.x"); - const x = Fp.toBytes(radj); - const R = Point.fromBytes(concatBytes$2(pprefix((recovery & 1) === 0), x)); - const ir = Fn.inv(radj); - const h = bits2int_modN(abytes$3(messageHash, void 0, "msgHash")); - const u1 = Fn.create(-h * ir); - const u2 = Fn.create(s * ir); - const Q = Point.BASE.mulAddUnsafe(u1, R, u2); - if (Q.is0()) throw new Error("invalid recovery: point at infinify"); - Q.assertValidity(); - return Q; - } - hasHighS() { - return isBiggerThanHalfOrder(this.s); - } - toBytes(format = defaultSigOpts.format) { - validateSigFormat(format); - if (format === "der") return hexToBytes$1(DER.hexFromSig(this)); - const { r, s } = this; - const rb = Fn.toBytes(r); - const sb = Fn.toBytes(s); - if (format === "recovered") { - assertRecoverableCurve(); - return concatBytes$2(Uint8Array.of(this.assertRecovery()), rb, sb); - } - return concatBytes$2(rb, sb); - } - toHex(format) { - return bytesToHex$2(this.toBytes(format)); - } - } - Object.freeze(Signature.prototype); - Object.freeze(Signature); - const bits2int = opts.bits2int === void 0 ? function bits2int_def(bytes) { - if (bytes.length > 8192) throw new Error("input is too large"); - const num = bytesToNumberBE(bytes); - const delta = bytes.length * 8 - fnBits; - return delta > 0 ? num >> BigInt(delta) : num; - } : opts.bits2int; - const bits2int_modN = opts.bits2int_modN === void 0 ? function bits2int_modN_def(bytes) { - return Fn.create(bits2int(bytes)); - } : opts.bits2int_modN; - const ORDER_MASK = bitMask(fnBits); - /** Converts to bytes. Checks if num in `[0..ORDER_MASK-1]` e.g.: `[0..2^256-1]`. */ - function int2octets(num) { - aInRange("num < 2^" + fnBits, num, _0n$4, ORDER_MASK); - return Fn.toBytes(num); - } - function validateMsgAndHash(message, prehash) { - abytes$3(message, void 0, "message"); - return prehash ? abytes$3(hash_(message), void 0, "prehashed message") : message; - } - /** - * Steps A, D of RFC6979 3.2. - * Creates RFC6979 seed; converts msg/privKey to numbers. - * Used only in sign, not in verify. - * - * Warning: we cannot assume here that message has same amount of bytes as curve order, - * this will be invalid at least for P521. Also it can be bigger for P224 + SHA256. - */ - function prepSig(message, secretKey, opts) { - const { lowS, prehash, extraEntropy } = validateSigOpts$1(opts, defaultSigOpts); - message = validateMsgAndHash(message, prehash); - const h1int = bits2int_modN(message); - const d = Fn.fromBytes(secretKey); - if (!Fn.isValidNot0(d)) throw new Error("invalid private key"); - const seedArgs = [int2octets(d), int2octets(h1int)]; - if (extraEntropy != null && extraEntropy !== false) { - const e = extraEntropy === true ? randomBytes(lengths.secretKey) : extraEntropy; - seedArgs.push(abytes$3(e, void 0, "extraEntropy")); - } - const seed = concatBytes$2(...seedArgs); - const m = h1int; - function k2sig(kBytes) { - const k = bits2int(kBytes); - if (!Fn.isValidNot0(k)) return; - const q = Point.BASE.multiply(k).toAffine(); - const r = Fn.create(q.x); - if (r === _0n$4) return; - let s; - if (csprng !== void 0) { - const b = bytesToNumberBE(mapHashToField(csprng(blindLength), CURVE_ORDER)); - const ibk = Fn.inv(Fn.mul(b, k)); - const bm = Fn.mul(b, m); - const bd = Fn.mul(b, d); - s = Fn.create(ibk * Fn.create(bm + bd * r)); - } else { - const ik = invertCt(k, CURVE_ORDER); - s = Fn.create(ik * Fn.create(m + r * d)); - } - if (s === _0n$4) return; - let recovery = getRecoveryBit(q.x, q.y, r); - let normS = s; - if (lowS && isBiggerThanHalfOrder(s)) { - normS = Fn.neg(s); - recovery ^= 1; - } - return new Signature(r, normS, hasLargeRecoveryLifts ? void 0 : recovery); - } - return { - seed, - k2sig - }; - } - /** - * Signs a message or message hash with a secret key. - * With the default `prehash: true`, raw message bytes are hashed internally; - * only `{ prehash: false }` expects a caller-supplied digest. - * - * ``` - * sign(m, d) where - * k = rfc6979_hmac_drbg(m, d) - * (x, y) = G × k - * r = x mod n - * s = (m + dr) / k mod n - * ``` - */ - function sign(message, secretKey, opts = {}) { - const { seed, k2sig } = prepSig(message, secretKey, opts); - return createHmacDrbg(hash_.outputLen, Fn.BYTES, hmac$1)(seed, k2sig).toBytes(opts.format); - } - /** - * Verifies a signature against message and public key. - * Rejects lowS signatures by default: see {@link ECDSAVerifyOpts}. - * Implements section 4.1.4 from https://www.secg.org/sec1-v2.pdf: - * - * ``` - * verify(r, s, h, P) where - * u1 = hs^-1 mod n - * u2 = rs^-1 mod n - * R = u1⋅G + u2⋅P - * mod(R.x, n) == r - * ``` - */ - function verify(signature, message, publicKey, opts = {}) { - const { lowS, prehash, format } = validateSigOpts$1(opts, defaultSigOpts); - publicKey = abytes$3(publicKey, void 0, "publicKey"); - message = validateMsgAndHash(message, prehash); - if (!isBytes$2(signature)) { - const end = signature instanceof Signature ? ", use sig.toBytes()" : ""; - throw new Error("verify expects Uint8Array signature" + end); - } - validateSigLength(signature, format); - try { - const sig = Signature.fromBytes(signature, format); - const P = Point.fromBytes(publicKey); - if (P.is0()) return false; - if (lowS && sig.hasHighS()) return false; - const { r, s } = sig; - const h = bits2int_modN(message); - const is = Fn.inv(s); - const u1 = Fn.create(h * is); - const u2 = Fn.create(r * is); - const R = Point.BASE.mulAddUnsafe(u1, P, u2); - if (R.is0()) return false; - const q = R.toAffine(); - if (Fn.create(q.x) !== r) return false; - if (format === "recovered" && sig.recovery !== getRecoveryBit(q.x, q.y, r)) return false; - return true; - } catch (e) { - return false; - } - } - function recoverPublicKey(signature, message, opts = {}) { - const { prehash } = validateSigOpts$1(opts, defaultSigOpts); - message = validateMsgAndHash(message, prehash); - return Signature.fromBytes(signature, "recovered").recoverPublicKey(message).toBytes(); - } - return Object.freeze({ - keygen, - getPublicKey, - getSharedSecret, - utils, - lengths, - Point, - sign, - verify, - recoverPublicKey, - Signature, - hash: hash_ - }); -} -//#endregion -//#region tests/baseline/node_modules/@noble/curves/secp256k1.js -/** -* SECG secp256k1. See [pdf](https://www.secg.org/sec2-v2.pdf). -* -* Belongs to Koblitz curves: it has efficiently-computable GLV endomorphism ψ, -* check out {@link EndomorphismOpts}. Seems to be rigid (not backdoored). -* @module -*/ -/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ -const secp256k1_CURVE = { - p: BigInt("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"), - n: BigInt("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"), - h: BigInt(1), - a: BigInt(0), - b: BigInt(7), - Gx: BigInt("0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"), - Gy: BigInt("0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8") -}; -const secp256k1_ENDO = { - beta: BigInt("0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee"), - basises: [[BigInt("0x3086d221a7d46bcde86c90e49284eb15"), -BigInt("0xe4437ed6010e88286f547fa90abfe4c3")], [BigInt("0x114ca50f7a8e2f3f657c1108d9d44cfd8"), BigInt("0x3086d221a7d46bcde86c90e49284eb15")]] -}; -const _0n$3 = /* @__PURE__ */ BigInt(0); -const _2n$2 = /* @__PURE__ */ BigInt(2); -/** -* √n = n^((p+1)/4) for fields p = 3 mod 4. We unwrap the loop and multiply bit-by-bit. -* (P+1n/4n).toString(2) would produce bits [223x 1, 0, 22x 1, 4x 0, 11, 00] -*/ -function sqrtMod(y) { - const P = secp256k1_CURVE.p; - const _3n = BigInt(3), _6n = BigInt(6), _11n = BigInt(11), _22n = BigInt(22); - const _23n = BigInt(23), _44n = BigInt(44), _88n = BigInt(88); - const b2 = y * y * y % P; - const b3 = b2 * b2 * y % P; - const b11 = pow2(pow2(pow2(b3, _3n, P) * b3 % P, _3n, P) * b3 % P, _2n$2, P) * b2 % P; - const b22 = pow2(b11, _11n, P) * b11 % P; - const b44 = pow2(b22, _22n, P) * b22 % P; - const b88 = pow2(b44, _44n, P) * b44 % P; - const root = pow2(pow2(pow2(pow2(pow2(pow2(b88, _88n, P) * b88 % P, _44n, P) * b44 % P, _3n, P) * b3 % P, _23n, P) * b22 % P, _6n, P) * b2 % P, _2n$2, P); - if (!Fpk1.eql(Fpk1.sqr(root), y)) throw new Error("Cannot find square root"); - return root; -} -const Fpk1 = /* @__PURE__ */ Field(secp256k1_CURVE.p, { sqrt: sqrtMod }); -const Pointk1 = /* @__PURE__ */ weierstrass(secp256k1_CURVE, { - Fp: Fpk1, - endo: secp256k1_ENDO -}); -/** -* secp256k1 curve: ECDSA and ECDH methods. -* -* Uses sha256 to hash messages. To use a different hash, -* pass `{ prehash: false }` to sign / verify. -* -* @example -* Generate one secp256k1 keypair, sign a message, and verify it. -* -* ```js -* import { secp256k1 } from '@noble/curves/secp256k1.js'; -* const { secretKey, publicKey } = secp256k1.keygen(); -* // const publicKey = secp256k1.getPublicKey(secretKey); -* const msg = new TextEncoder().encode('hello noble'); -* const sig = secp256k1.sign(msg, secretKey); -* const isValid = secp256k1.verify(sig, msg, publicKey); -* // const sigKeccak = secp256k1.sign(keccak256(msg), secretKey, { prehash: false }); -* ``` -*/ -const secp256k1 = /* @__PURE__ */ ecdsa(Pointk1, sha256$2); -/** An object mapping tags to their tagged hash prefix of [SHA256(tag) | SHA256(tag)] */ -const TAGGED_HASH_PREFIXES = Object.create(null); -function taggedHash(tag, ...messages) { - let tagP = TAGGED_HASH_PREFIXES[tag]; - if (tagP === void 0) { - const tagH = sha256$2(asciiToBytes(tag)); - tagP = concatBytes$2(tagH, tagH); - TAGGED_HASH_PREFIXES[tag] = tagP; - } - return sha256$2(concatBytes$2(tagP, ...messages)); -} -const pointToBytes = (point) => point.toBytes(true).slice(1); -const affineXToBytes = ({ x }) => Fpk1.toBytes(x); -const hasEven = (y) => !Fpk1.isOdd(y); -function schnorrGetExtPubKey(priv) { - const { Fn, BASE } = Pointk1; - const d_ = Fn.fromBytes(abytes$3(priv, 32, "secretKey")); - const affine = BASE.multiply(d_).toAffine(); - return { - scalar: hasEven(affine.y) ? d_ : Fn.neg(d_), - bytes: affineXToBytes(affine) - }; -} -/** -* lift_x from BIP340. Convert 32-byte x coordinate to elliptic curve point. -* @returns valid point checked for being on-curve -*/ -function lift_x(x) { - const Fp = Fpk1; - if (!Fp.isValidNot0(x)) throw new Error("invalid x: Fail if x ≥ p"); - const xx = Fp.sqr(x); - const c = Fp.add(Fp.mulN(xx, x), BigInt(7)); - let y = Fp.sqrt(c); - if (!hasEven(y)) y = Fp.neg(y); - const p = Pointk1.fromAffine({ - x, - y - }); - p.assertValidity(); - return p; -} -const num = bytesToNumberBE; -/** Create tagged hash, convert it to bigint, reduce modulo-n. */ -function challenge(...args) { - return Pointk1.Fn.create(num(taggedHash("BIP0340/challenge", ...args))); -} -/** Schnorr public key is just `x` coordinate of Point as per BIP340. */ -function schnorrGetPublicKey(secretKey) { - return schnorrGetExtPubKey(secretKey).bytes; -} -/** -* Creates Schnorr signature as per BIP340. Verifies itself before returning anything. -* `auxRand` is optional and is not the sole source of `k` generation: bad CSPRNG output will not -* be catastrophic, but BIP-340 still recommends fresh auxiliary randomness when available to harden -* deterministic signing against side-channel and fault-injection attacks. -*/ -function schnorrSign$1(message, secretKey, auxRand = randomBytes$3(32)) { - const { Fn, BASE } = Pointk1; - const m = copyBytes$1(abytes$3(message, void 0, "message")); - const { bytes: px, scalar: d } = schnorrGetExtPubKey(secretKey); - const a = abytes$3(auxRand, 32, "auxRand"); - const rand = taggedHash("BIP0340/nonce", Fn.toBytes(d ^ num(taggedHash("BIP0340/aux", a))), px, m); - const k_ = Fn.create(num(rand)); - if (k_ === _0n$3) throw new Error("sign failed: k is zero"); - const affine = BASE.multiply(k_).toAffine(); - const k = hasEven(affine.y) ? k_ : Fn.neg(k_); - const rx = affineXToBytes(affine); - const e = challenge(rx, px, m); - const sig = /* @__PURE__ */ new Uint8Array(64); - sig.set(rx, 0); - sig.set(Fn.toBytes(Fn.create(k + e * d)), 32); - if (!schnorrVerify$1(sig, m, px)) throw new Error("sign: Invalid signature produced"); - return sig; -} -/** -* Verifies Schnorr signature. -* Will swallow errors & return false except for initial type validation of arguments. -*/ -function schnorrVerify$1(signature, message, publicKey) { - const { Fp, Fn, BASE } = Pointk1; - const sig = abytes$3(signature, 64, "signature"); - const m = abytes$3(message, void 0, "message"); - const pub = abytes$3(publicKey, 32, "publicKey"); - try { - const P = lift_x(num(pub)); - const rBytes = sig.subarray(0, 32); - const r = num(rBytes); - if (!Fp.isValidNot0(r)) return false; - const s = num(sig.subarray(32, 64)); - if (!Fn.isValidNot0(s)) return false; - const e = challenge(rBytes, pointToBytes(P), m); - const R = BASE.mulAddUnsafe(s, P, Fn.neg(e)); - const { x, y } = R.toAffine(); - if (R.is0() || !hasEven(y) || !Fp.eql(x, r)) return false; - return true; - } catch (error) { - return false; - } -} -/** -* Schnorr signatures over secp256k1. -* See {@link https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki | BIP 340}. -* @example -* Generate one BIP340 Schnorr keypair, sign a message, and verify it. -* -* ```js -* import { schnorr } from '@noble/curves/secp256k1.js'; -* const { secretKey, publicKey } = schnorr.keygen(); -* // const publicKey = schnorr.getPublicKey(secretKey); -* const msg = new TextEncoder().encode('hello'); -* const sig = schnorr.sign(msg, secretKey); -* const isValid = schnorr.verify(sig, msg, publicKey); -* ``` -*/ -const schnorr = /* @__PURE__ */ (() => { - const size = 32; - const seedLength = 48; - const randomSecretKey = (seed) => { - seed = seed === void 0 ? randomBytes$3(seedLength) : seed; - return mapHashToField(abytes$3(seed, seedLength, "seed"), secp256k1_CURVE.n); - }; - return Object.freeze({ - keygen: createKeygen(randomSecretKey, schnorrGetPublicKey), - getPublicKey: schnorrGetPublicKey, - sign: schnorrSign$1, - verify: schnorrVerify$1, - Point: Pointk1, - utils: Object.freeze({ - randomSecretKey, - taggedHash, - lift_x, - pointToBytes - }), - lengths: Object.freeze({ - secretKey: size, - publicKey: size, - publicKeyHasPrefix: false, - signature: 64, - seed: seedLength - }) - }); -})(); -//#endregion -//#region tests/baseline/node_modules/@bcts/rand/dist/index.mjs -/** -* Wide multiplication for 32-bit unsigned integers. -* @param a - First 32-bit value -* @param b - Second 32-bit value -* @returns Tuple of (low 32 bits, high 32 bits) as bigints -*/ -function wideMulU32(a, b) { - const wide = BigInt(a >>> 0) * BigInt(b >>> 0); - return [wide & 4294967295n, wide >> 32n]; -} -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -*/ -/** -* Converts a signed integer to its unsigned magnitude. -* For positive numbers, returns the number unchanged. -* For negative numbers, returns the absolute value (wrapping for MIN values). -* -* This matches Rust's wrapping_abs() behavior. -*/ -function toMagnitude(value, bits) { - switch (bits) { - case 8: { - const i8Value = value << 24 >> 24; - return Math.abs(i8Value) & 255; - } - case 16: { - const i16Value = value << 16 >> 16; - return Math.abs(i16Value) & 65535; - } - case 32: { - const i32Value = value | 0; - if (i32Value === -2147483648) return 2147483648; - return Math.abs(i32Value) >>> 0; - } - } -} -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -*/ -/** -* Returns a Uint8Array of random bytes of the given size. -*/ -function rngRandomData(rng, size) { - const data = new Uint8Array(size); - rng.fillRandomData(data); - return data; -} -/** -* Returns a random `u32` value strictly less than `upperBound`. -*/ -function rngNextWithUpperBoundU32(rng, upperBound) { - if (upperBound === 0) throw new Error("upperBound must be non-zero"); - const ub = upperBound >>> 0; - let random = Number(rng.nextU64() & 4294967295n); - let m = wideMulU32(random, ub); - if (Number(m[0]) < ub) { - const t = (4294967296 - ub >>> 0) % ub; - while (Number(m[0]) < t) { - random = Number(rng.nextU64() & 4294967295n); - m = wideMulU32(random, ub); - } - } - return Number(m[1]); -} -function fromU64ThrowsIfAbove(value, max) { - if (value > max) throw new Error("from_u64 conversion overflow"); - return value; -} -/** Random `i32` in the closed range [start, end]. */ -function rngNextInClosedRangeI32(rng, start, end) { - if (start > end) throw new Error("start must be less than or equal to end"); - const lo = start | 0; - const delta = toMagnitude((end | 0) - lo, 32); - if (delta === 4294967295) return Number(fromU64ThrowsIfAbove(rng.nextU64(), 2147483647n)); - return lo + rngNextWithUpperBoundU32(rng, delta + 1) | 0; -} -/** -* Returns the Web Crypto API for the current environment. Available natively -* in browsers and in Node.js >= 15 via `globalThis.crypto`. -*/ -function getCrypto() { - if (typeof globalThis !== "undefined" && globalThis.crypto != null) return globalThis.crypto; - throw new Error("No crypto API available in this environment"); -} -/** -* Generate a Uint8Array of cryptographically strong random bytes of the given size. -*/ -function randomData(size) { - const data = new Uint8Array(size); - fillRandomData(data); - return data; -} -/** -* Fill the given Uint8Array with cryptographically strong random bytes. -*/ -function fillRandomData(data) { - getCrypto().getRandomValues(data); -} -/** -* Returns the next cryptographically strong random 64-bit unsigned integer. -* -* This mirrors Rust's module-private `secure_random::next_u64()` and is not -* re-exported from the package surface (matches Rust `lib.rs` behavior). -*/ -function nextU64() { - const data = /* @__PURE__ */ new Uint8Array(8); - fillRandomData(data); - return new DataView(data.buffer).getBigUint64(0, true); -} -/** -* A random number generator that can be used as a source of -* cryptographically-strong randomness. -* -* Uses the Web Crypto API (crypto.getRandomValues) which is available -* in both browsers and Node.js >= 15. -*/ -var SecureRandomNumberGenerator = class { - /** - * Returns the next random 32-bit unsigned integer. - * - * Mirrors Rust's `next_u32` impl which returns `next_u64() as u32` — - * the low 32 bits of a 64-bit draw. - */ - nextU32() { - return Number(this.nextU64() & 4294967295n) >>> 0; - } - /** - * Returns the next random 64-bit unsigned integer as a bigint. - */ - nextU64() { - return nextU64(); - } - /** - * Fills the given Uint8Array with random bytes. - */ - fillBytes(dest) { - fillRandomData(dest); - } - /** - * Returns a Uint8Array of random bytes of the given size. - */ - randomData(size) { - return randomData(size); - } - /** - * Fills the given Uint8Array with random bytes. - */ - fillRandomData(data) { - fillRandomData(data); - } -}; -/** -* Rotate left for 64-bit bigint -*/ -function rotl(x, k) { - return (x << BigInt(k) | x >> BigInt(64 - k)) & 18446744073709551615n; -} -/** -* Xoshiro256** PRNG implementation -* This is the same algorithm used by rand_xoshiro in Rust -*/ -function xoshiro256StarStar(state) { - const mask = 18446744073709551615n; - const result = rotl(state.s1 * 5n & mask, 7) * 9n & mask; - const t = state.s1 << 17n & mask; - state.s2 ^= state.s0; - state.s3 ^= state.s1; - state.s1 ^= state.s2; - state.s0 ^= state.s3; - state.s2 ^= t; - state.s3 = rotl(state.s3, 45); - return result; -} -/** -* A random number generator that can be used as a source of deterministic -* pseudo-randomness for testing purposes. -* -* Uses the Xoshiro256** algorithm, which is the same algorithm used by -* rand_xoshiro in Rust. This ensures cross-platform compatibility with -* the Rust implementation. -* -* WARNING: This is NOT cryptographically secure and should only be used -* for testing purposes. -*/ -var SeededRandomNumberGenerator = class { - state; - /** - * Creates a new seeded random number generator. - * - * The seed should be a 256-bit value, represented as an array of 4 64-bit - * integers (as bigints). For the output distribution to look random, the seed - * should not have any obvious patterns, like all zeroes or all ones. - * - * This is not cryptographically secure, and should only be used for - * testing purposes. - * - * @param seed - Array of 4 64-bit unsigned integers as bigints - */ - constructor(seed) { - this.state = { - s0: seed[0] & 18446744073709551615n, - s1: seed[1] & 18446744073709551615n, - s2: seed[2] & 18446744073709551615n, - s3: seed[3] & 18446744073709551615n - }; - } - /** - * Returns the next random 64-bit unsigned integer as a bigint. - */ - nextU64() { - return xoshiro256StarStar(this.state); - } - /** - * Returns the next random 32-bit unsigned integer. - */ - nextU32() { - return Number(this.nextU64() & 4294967295n) >>> 0; - } - /** - * Fills the given Uint8Array with random bytes. - * - * Note: This implementation matches the Rust behavior exactly - - * it uses one nextU64() call per byte (taking only the low byte), - * which matches the Swift version's behavior. - */ - fillBytes(dest) { - for (let i = 0; i < dest.length; i++) dest[i] = Number(this.nextU64() & 255n); - } - /** - * Returns a Uint8Array of random bytes of the given size. - * - * This might not be the most efficient implementation, - * but it works the same as the Swift version. - */ - randomData(size) { - const data = new Uint8Array(size); - for (let i = 0; i < size; i++) data[i] = Number(this.nextU64() & 255n); - return data; - } - /** - * Fills the given Uint8Array with random bytes. - */ - fillRandomData(data) { - this.fillBytes(data); - } -}; -/** -* Standard test seed for `makeFakeRandomNumberGenerator`. Module-private to -* mirror Rust where the equivalent constant lives inside `mod tests`. -*/ -const TEST_SEED = [ - 17295166580085024720n, - 422929670265678780n, - 5577237070365765850n, - 7953171132032326923n -]; -/** -* Creates a seeded random number generator with a fixed seed. -* This is useful for reproducible testing across different platforms. -*/ -function makeFakeRandomNumberGenerator() { - return new SeededRandomNumberGenerator(TEST_SEED); -} -//#endregion -//#region tests/baseline/node_modules/@noble/hashes/scrypt.js -/** -* RFC 7914 Scrypt KDF. Can be used to create a key from password and salt. -* @module -*/ -function XorAndSalsa(prev, pi, input, ii, out, oi) { - let y00 = prev[pi++] ^ input[ii++], y01 = prev[pi++] ^ input[ii++]; - let y02 = prev[pi++] ^ input[ii++], y03 = prev[pi++] ^ input[ii++]; - let y04 = prev[pi++] ^ input[ii++], y05 = prev[pi++] ^ input[ii++]; - let y06 = prev[pi++] ^ input[ii++], y07 = prev[pi++] ^ input[ii++]; - let y08 = prev[pi++] ^ input[ii++], y09 = prev[pi++] ^ input[ii++]; - let y10 = prev[pi++] ^ input[ii++], y11 = prev[pi++] ^ input[ii++]; - let y12 = prev[pi++] ^ input[ii++], y13 = prev[pi++] ^ input[ii++]; - let y14 = prev[pi++] ^ input[ii++], y15 = prev[pi++] ^ input[ii++]; - let x00 = y00, x01 = y01, x02 = y02, x03 = y03, x04 = y04, x05 = y05, x06 = y06, x07 = y07, x08 = y08, x09 = y09, x10 = y10, x11 = y11, x12 = y12, x13 = y13, x14 = y14, x15 = y15; - for (let i = 0; i < 8; i += 2) { - x04 ^= rotl$2(x00 + x12 | 0, 7); - x08 ^= rotl$2(x04 + x00 | 0, 9); - x12 ^= rotl$2(x08 + x04 | 0, 13); - x00 ^= rotl$2(x12 + x08 | 0, 18); - x09 ^= rotl$2(x05 + x01 | 0, 7); - x13 ^= rotl$2(x09 + x05 | 0, 9); - x01 ^= rotl$2(x13 + x09 | 0, 13); - x05 ^= rotl$2(x01 + x13 | 0, 18); - x14 ^= rotl$2(x10 + x06 | 0, 7); - x02 ^= rotl$2(x14 + x10 | 0, 9); - x06 ^= rotl$2(x02 + x14 | 0, 13); - x10 ^= rotl$2(x06 + x02 | 0, 18); - x03 ^= rotl$2(x15 + x11 | 0, 7); - x07 ^= rotl$2(x03 + x15 | 0, 9); - x11 ^= rotl$2(x07 + x03 | 0, 13); - x15 ^= rotl$2(x11 + x07 | 0, 18); - x01 ^= rotl$2(x00 + x03 | 0, 7); - x02 ^= rotl$2(x01 + x00 | 0, 9); - x03 ^= rotl$2(x02 + x01 | 0, 13); - x00 ^= rotl$2(x03 + x02 | 0, 18); - x06 ^= rotl$2(x05 + x04 | 0, 7); - x07 ^= rotl$2(x06 + x05 | 0, 9); - x04 ^= rotl$2(x07 + x06 | 0, 13); - x05 ^= rotl$2(x04 + x07 | 0, 18); - x11 ^= rotl$2(x10 + x09 | 0, 7); - x08 ^= rotl$2(x11 + x10 | 0, 9); - x09 ^= rotl$2(x08 + x11 | 0, 13); - x10 ^= rotl$2(x09 + x08 | 0, 18); - x12 ^= rotl$2(x15 + x14 | 0, 7); - x13 ^= rotl$2(x12 + x15 | 0, 9); - x14 ^= rotl$2(x13 + x12 | 0, 13); - x15 ^= rotl$2(x14 + x13 | 0, 18); - } - out[oi++] = y00 + x00 | 0; - out[oi++] = y01 + x01 | 0; - out[oi++] = y02 + x02 | 0; - out[oi++] = y03 + x03 | 0; - out[oi++] = y04 + x04 | 0; - out[oi++] = y05 + x05 | 0; - out[oi++] = y06 + x06 | 0; - out[oi++] = y07 + x07 | 0; - out[oi++] = y08 + x08 | 0; - out[oi++] = y09 + x09 | 0; - out[oi++] = y10 + x10 | 0; - out[oi++] = y11 + x11 | 0; - out[oi++] = y12 + x12 | 0; - out[oi++] = y13 + x13 | 0; - out[oi++] = y14 + x14 | 0; - out[oi++] = y15 + x15 | 0; -} -function BlockMix(input, ii, out, oi, r) { - let head = oi + 0; - let tail = oi + 16 * r; - for (let i = 0; i < 16; i++) out[tail + i] = input[ii + (2 * r - 1) * 16 + i]; - for (let i = 0; i < r; i++, head += 16, ii += 16) { - XorAndSalsa(out, tail, input, ii, out, head); - if (i > 0) tail += 16; - XorAndSalsa(out, head, input, ii += 16, out, tail); - } -} -const SCRYPT_DEFAULT_MAXMEM = 1024 * (2 ** 20 + 1 + 1); -function scryptInit(password, salt, _opts) { - const { N, r, p, dkLen, asyncTick, maxmem, onProgress } = checkOpts$1({ - dkLen: 32, - asyncTick: 10, - maxmem: SCRYPT_DEFAULT_MAXMEM - }, _opts); - anumber$4(N, "N"); - anumber$4(r, "r"); - anumber$4(p, "p"); - anumber$4(dkLen, "dkLen"); - anumber$4(asyncTick, "asyncTick"); - anumber$4(maxmem, "maxmem"); - if (onProgress !== void 0 && typeof onProgress !== "function") throw new Error("\"onProgress\" must be a function"); - if (r < 1) throw new Error("\"r\" expected integer >= 1"); - const blockSize = 128 * r; - const blockSize32 = blockSize / 4; - const pow32 = Math.pow(2, 32); - if (N <= 1 || (N & N - 1) !== 0 || N > pow32) throw new Error("\"N\" expected a power of 2, and 2^1 <= N <= 2^32"); - if (p < 1 || p > (pow32 - 1) * 32 / blockSize) throw new Error("\"p\" expected integer 1..((2^32 - 1) * 32) / (128 * r)"); - if (dkLen < 1 || dkLen > (pow32 - 1) * 32) throw new Error("\"dkLen\" expected integer 1..(2^32 - 1) * 32"); - const memUsed = blockSize * (N + p + 1); - if (memUsed > maxmem) throw new Error("\"maxmem\" limit was hit: memUsed(128*r*(N+p+1))=" + memUsed + ", maxmem=" + maxmem); - const B = pbkdf2(sha256$2, password, salt, { - c: 1, - dkLen: blockSize * p - }); - const B32 = u32$2(B); - const V = u32$2(new Uint8Array(blockSize * N)); - const tmp = u32$2(new Uint8Array(blockSize)); - let blockMixCb = () => {}; - if (onProgress) { - const totalBlockMix = 2 * N * p; - const callbackPer = Math.max(Math.floor(totalBlockMix / 1e4), 1); - let blockMixCnt = 0; - blockMixCb = () => { - blockMixCnt++; - if (onProgress && (!(blockMixCnt % callbackPer) || blockMixCnt === totalBlockMix)) try { - onProgress(blockMixCnt / totalBlockMix); - } catch (e) { - clean$2(B, V, tmp); - throw e; - } - }; - } - return { - N, - r, - p, - dkLen, - blockSize32, - V, - B32, - B, - tmp, - blockMixCb, - asyncTick - }; -} -function scryptOutput(password, dkLen, B, V, tmp) { - const res = pbkdf2(sha256$2, password, B, { - c: 1, - dkLen - }); - clean$2(B, V, tmp); - return res; -} -/** -* Scrypt KDF from RFC 7914. See {@link ScryptOpts}. -* @param password - password or key material to derive from; -* JS string inputs are UTF-8 encoded first -* @param salt - unique salt bytes or string; JS string inputs are UTF-8 encoded first -* @param opts - Scrypt cost and memory parameters. `dkLen`, if provided, -* must be `>= 1` per RFC 7914 §2. See {@link ScryptOpts}. -* @returns Derived key bytes. -* @throws If the Scrypt cost, memory, or callback options are invalid. {@link Error} -* @example -* Derive a key with scrypt. -* ```ts -* scrypt('password', 'salt', { N: 2**18, r: 8, p: 1, dkLen: 32 }); -* ``` -* @example -* Derive a key with small demo costs and progress/memory controls. -* ```ts -* const progressLog: number[] = []; -* scrypt('password', 'salt', { -* N: 16, -* r: 8, -* p: 1, -* dkLen: 32, -* maxmem: 1024 * 1024, -* asyncTick: 10, -* onProgress(progress) { -* progressLog.push(progress); -* }, -* }); -* ``` -*/ -function scrypt(password, salt, opts) { - const { N, r, p, dkLen, blockSize32, V, B32, B, tmp, blockMixCb } = scryptInit(password, salt, opts); - swap32IfBE$2(B32); - for (let pi = 0; pi < p; pi++) { - const Pi = blockSize32 * pi; - for (let i = 0; i < blockSize32; i++) V[i] = B32[Pi + i]; - for (let i = 0, pos = 0; i < N - 1; i++) { - BlockMix(V, pos, V, pos += blockSize32, r); - blockMixCb(); - } - BlockMix(V, (N - 1) * blockSize32, B32, Pi, r); - blockMixCb(); - for (let i = 0; i < N; i++) { - const j = (B32[Pi + blockSize32 - 16] & N - 1) >>> 0; - for (let k = 0; k < blockSize32; k++) tmp[k] = B32[Pi + k] ^ V[j * blockSize32 + k]; - BlockMix(tmp, 0, B32, Pi, r); - blockMixCb(); - } - } - swap32IfBE$2(B32); - return scryptOutput(password, dkLen, B, V, tmp); -} -//#endregion -//#region tests/baseline/node_modules/@noble/hashes/_blake.js -/** -* Internal blake permutation table. -* Rows `0..9` serve BLAKE2s, rows `0..11` serve BLAKE2b with `10..11 = 0..1`, and Blake1 also -* reuses the later rows shown below. Blake1 expands rounds `10..15` as `SIGMA[i % 10]`, so rows -* `10..15` intentionally repeat rows `0..5` for the 14-round (256) and 16-round (512) variants. -*/ -const BSIGMA = /* @__PURE__ */ Uint8Array.from([ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 14, - 10, - 4, - 8, - 9, - 15, - 13, - 6, - 1, - 12, - 0, - 2, - 11, - 7, - 5, - 3, - 11, - 8, - 12, - 0, - 5, - 2, - 15, - 13, - 10, - 14, - 3, - 6, - 7, - 1, - 9, - 4, - 7, - 9, - 3, - 1, - 13, - 12, - 11, - 14, - 2, - 6, - 5, - 10, - 4, - 0, - 15, - 8, - 9, - 0, - 5, - 7, - 2, - 4, - 10, - 15, - 14, - 1, - 11, - 12, - 6, - 8, - 3, - 13, - 2, - 12, - 6, - 10, - 0, - 11, - 8, - 3, - 4, - 13, - 7, - 5, - 15, - 14, - 1, - 9, - 12, - 5, - 1, - 15, - 14, - 13, - 4, - 10, - 0, - 7, - 6, - 3, - 9, - 2, - 8, - 11, - 13, - 11, - 7, - 14, - 12, - 1, - 3, - 9, - 5, - 0, - 15, - 4, - 8, - 6, - 2, - 10, - 6, - 15, - 14, - 9, - 11, - 3, - 0, - 8, - 12, - 2, - 13, - 7, - 1, - 4, - 10, - 5, - 10, - 2, - 8, - 4, - 7, - 6, - 1, - 5, - 15, - 11, - 9, - 14, - 3, - 12, - 13, - 0, - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 14, - 10, - 4, - 8, - 9, - 15, - 13, - 6, - 1, - 12, - 0, - 2, - 11, - 7, - 5, - 3, - 11, - 8, - 12, - 0, - 5, - 2, - 15, - 13, - 10, - 14, - 3, - 6, - 7, - 1, - 9, - 4, - 7, - 9, - 3, - 1, - 13, - 12, - 11, - 14, - 2, - 6, - 5, - 10, - 4, - 0, - 15, - 8, - 9, - 0, - 5, - 7, - 2, - 4, - 10, - 15, - 14, - 1, - 11, - 12, - 6, - 8, - 3, - 13, - 2, - 12, - 6, - 10, - 0, - 11, - 8, - 3, - 4, - 13, - 7, - 5, - 15, - 14, - 1, - 9 -]); -//#endregion -//#region tests/baseline/node_modules/@noble/hashes/blake2.js -/** -* blake2b (64-bit) & blake2s (8 to 32-bit) hash functions. -* b could have been faster, but there is no fast u64 in js, so s is 1.5x faster. -* @module -*/ -const B2B_IV = /* @__PURE__ */ Uint32Array.from([ - 4089235720, - 1779033703, - 2227873595, - 3144134277, - 4271175723, - 1013904242, - 1595750129, - 2773480762, - 2917565137, - 1359893119, - 725511199, - 2600822924, - 4215389547, - 528734635, - 327033209, - 1541459225 -]); -const BBUF = /* @__PURE__ */ new Uint32Array(32); -function G1b(a, b, c, d, msg, x) { - const Xl = msg[x], Xh = msg[x + 1]; - let Al = BBUF[2 * a], Ah = BBUF[2 * a + 1]; - let Bl = BBUF[2 * b], Bh = BBUF[2 * b + 1]; - let Cl = BBUF[2 * c], Ch = BBUF[2 * c + 1]; - let Dl = BBUF[2 * d], Dh = BBUF[2 * d + 1]; - const ll = add3L(Al, Bl, Xl); - Ah = add3H(ll, Ah, Bh, Xh); - Al = ll | 0; - let xh = Dh ^ Ah, xl = Dl ^ Al; - Dh = rotr32H(xh, xl); - Dl = rotr32L(xh, xl); - ({h: Ch, l: Cl} = add(Ch, Cl, Dh, Dl)); - xh = Bh ^ Ch; - xl = Bl ^ Cl; - Bh = rotrSH(xh, xl, 24); - Bl = rotrSL(xh, xl, 24); - BBUF[2 * a] = Al; - BBUF[2 * a + 1] = Ah; - BBUF[2 * b] = Bl; - BBUF[2 * b + 1] = Bh; - BBUF[2 * c] = Cl; - BBUF[2 * c + 1] = Ch; - BBUF[2 * d] = Dl; - BBUF[2 * d + 1] = Dh; -} -function G2b(a, b, c, d, msg, x) { - const Xl = msg[x], Xh = msg[x + 1]; - let Al = BBUF[2 * a], Ah = BBUF[2 * a + 1]; - let Bl = BBUF[2 * b], Bh = BBUF[2 * b + 1]; - let Cl = BBUF[2 * c], Ch = BBUF[2 * c + 1]; - let Dl = BBUF[2 * d], Dh = BBUF[2 * d + 1]; - const ll = add3L(Al, Bl, Xl); - Ah = add3H(ll, Ah, Bh, Xh); - Al = ll | 0; - let xh = Dh ^ Ah, xl = Dl ^ Al; - Dh = rotrSH(xh, xl, 16); - Dl = rotrSL(xh, xl, 16); - ({h: Ch, l: Cl} = add(Ch, Cl, Dh, Dl)); - xh = Bh ^ Ch; - xl = Bl ^ Cl; - Bh = rotrBH(xh, xl, 63); - Bl = rotrBL(xh, xl, 63); - BBUF[2 * a] = Al; - BBUF[2 * a + 1] = Ah; - BBUF[2 * b] = Bl; - BBUF[2 * b + 1] = Bh; - BBUF[2 * c] = Cl; - BBUF[2 * c + 1] = Ch; - BBUF[2 * d] = Dl; - BBUF[2 * d + 1] = Dh; -} -function checkBlake2Opts(outputLen, opts = {}, keyLen, saltLen, persLen) { - anumber$4(keyLen); - if (outputLen <= 0 || outputLen > keyLen) throw new Error("\"dkLen\" must be 1.." + keyLen + ", got " + outputLen); - const { key, salt, personalization } = opts; - if (key !== void 0 && (key.length < 1 || key.length > keyLen)) throw new Error("\"key\" expected to be undefined or of length=1.." + keyLen); - if (salt !== void 0) abytes$5(salt, saltLen, "salt"); - if (personalization !== void 0) abytes$5(personalization, persLen, "personalization"); -} -/** Internal base class for BLAKE2. */ -var _BLAKE2 = class { - buffer; - buffer32; - finished = false; - destroyed = false; - length = 0; - pos = 0; - blockLen; - outputLen; - canXOF = false; - constructor(blockLen, outputLen) { - anumber$4(blockLen); - anumber$4(outputLen); - this.blockLen = blockLen; - this.outputLen = outputLen; - this.buffer = new Uint8Array(blockLen); - this.buffer32 = u32$2(this.buffer); - } - update(data) { - aexists$2(this); - abytes$5(data); - const { blockLen, buffer, buffer32 } = this; - const len = data.length; - const offset = data.byteOffset; - const buf = data.buffer; - for (let pos = 0; pos < len;) { - if (this.pos === blockLen) { - swap32IfBE$2(buffer32); - this.compress(buffer32, 0, false); - swap32IfBE$2(buffer32); - this.pos = 0; - } - const take = Math.min(blockLen - this.pos, len - pos); - const dataOffset = offset + pos; - if (take === blockLen && !(dataOffset % 4) && pos + take < len) { - const data32 = new Uint32Array(buf, dataOffset, Math.floor((len - pos) / 4)); - swap32IfBE$2(data32); - for (let pos32 = 0; pos + blockLen < len; pos32 += buffer32.length, pos += blockLen) { - this.length += blockLen; - this.compress(data32, pos32, false); - } - swap32IfBE$2(data32); - continue; - } - buffer.set(pos === 0 && take === len ? data : data.subarray(pos, pos + take), this.pos); - this.pos += take; - this.length += take; - pos += take; - } - return this; - } - digestInto(out) { - aexists$2(this); - aoutput$2(out, this); - if (out.byteOffset & 3) throw new RangeError("\"output\" expected 4-byte aligned byteOffset, got " + out.byteOffset); - const { pos, buffer32 } = this; - this.finished = true; - this.buffer.fill(0, pos); - swap32IfBE$2(buffer32); - this.compress(buffer32, 0, true); - swap32IfBE$2(buffer32); - const state = this.get(); - const out32 = out === this.buffer ? buffer32 : u32$2(out); - const full = Math.floor(this.outputLen / 4); - for (let i = 0; i < full; i++) out32[i] = swap8IfBE(state[i]); - const tail = this.outputLen % 4; - if (!tail) return; - const off = full * 4; - const word = state[full]; - for (let i = 0; i < tail; i++) out[off + i] = word >>> 8 * i; - } - digest() { - const { buffer, outputLen } = this; - this.digestInto(buffer); - const res = buffer.slice(0, outputLen); - this.destroy(); - return res; - } - _cloneInto(to) { - const { buffer, length, finished, destroyed, outputLen, pos } = this; - to ||= new this.constructor({ dkLen: outputLen }); - to.set(...this.get()); - to.buffer.set(buffer); - to.destroyed = destroyed; - to.finished = finished; - to.length = length; - to.pos = pos; - to.outputLen = outputLen; - return to; - } - clone() { - return this._cloneInto(); - } -}; -/** Internal blake2b hash class with state stored as LE u32 low/high halves. */ -var _BLAKE2b = class extends _BLAKE2 { - v0l = B2B_IV[0] | 0; - v0h = B2B_IV[1] | 0; - v1l = B2B_IV[2] | 0; - v1h = B2B_IV[3] | 0; - v2l = B2B_IV[4] | 0; - v2h = B2B_IV[5] | 0; - v3l = B2B_IV[6] | 0; - v3h = B2B_IV[7] | 0; - v4l = B2B_IV[8] | 0; - v4h = B2B_IV[9] | 0; - v5l = B2B_IV[10] | 0; - v5h = B2B_IV[11] | 0; - v6l = B2B_IV[12] | 0; - v6h = B2B_IV[13] | 0; - v7l = B2B_IV[14] | 0; - v7h = B2B_IV[15] | 0; - constructor(opts = {}) { - opts = checkOpts$1({}, opts); - const olen = opts.dkLen === void 0 ? 64 : opts.dkLen; - super(128, olen); - checkBlake2Opts(olen, opts, 64, 16, 16); - let { key, personalization, salt } = opts; - let keyLength = 0; - if (key !== void 0) { - abytes$5(key, void 0, "key"); - keyLength = key.length; - } - this.v0l ^= this.outputLen | keyLength << 8 | 16842752; - if (salt !== void 0) { - abytes$5(salt, void 0, "salt"); - const slt = u32$2(copyBytes$3(salt)); - this.v4l ^= swap8IfBE(slt[0]); - this.v4h ^= swap8IfBE(slt[1]); - this.v5l ^= swap8IfBE(slt[2]); - this.v5h ^= swap8IfBE(slt[3]); - } - if (personalization !== void 0) { - abytes$5(personalization, void 0, "personalization"); - const pers = u32$2(copyBytes$3(personalization)); - this.v6l ^= swap8IfBE(pers[0]); - this.v6h ^= swap8IfBE(pers[1]); - this.v7l ^= swap8IfBE(pers[2]); - this.v7h ^= swap8IfBE(pers[3]); - } - if (key !== void 0) { - const tmp = new Uint8Array(this.blockLen); - tmp.set(key); - this.update(tmp); - clean$2(tmp); - } - } - get() { - let { v0l, v0h, v1l, v1h, v2l, v2h, v3l, v3h, v4l, v4h, v5l, v5h, v6l, v6h, v7l, v7h } = this; - return [ - v0l, - v0h, - v1l, - v1h, - v2l, - v2h, - v3l, - v3h, - v4l, - v4h, - v5l, - v5h, - v6l, - v6h, - v7l, - v7h - ]; - } - set(v0l, v0h, v1l, v1h, v2l, v2h, v3l, v3h, v4l, v4h, v5l, v5h, v6l, v6h, v7l, v7h) { - this.v0l = v0l | 0; - this.v0h = v0h | 0; - this.v1l = v1l | 0; - this.v1h = v1h | 0; - this.v2l = v2l | 0; - this.v2h = v2h | 0; - this.v3l = v3l | 0; - this.v3h = v3h | 0; - this.v4l = v4l | 0; - this.v4h = v4h | 0; - this.v5l = v5l | 0; - this.v5h = v5h | 0; - this.v6l = v6l | 0; - this.v6h = v6h | 0; - this.v7l = v7l | 0; - this.v7h = v7h | 0; - } - compress(msg, offset, isLast) { - const { v0l, v0h, v1l, v1h, v2l, v2h, v3l, v3h, v4l, v4h, v5l, v5h, v6l, v6h, v7l, v7h } = this; - BBUF[0] = v0l; - BBUF[1] = v0h; - BBUF[2] = v1l; - BBUF[3] = v1h; - BBUF[4] = v2l; - BBUF[5] = v2h; - BBUF[6] = v3l; - BBUF[7] = v3h; - BBUF[8] = v4l; - BBUF[9] = v4h; - BBUF[10] = v5l; - BBUF[11] = v5h; - BBUF[12] = v6l; - BBUF[13] = v6h; - BBUF[14] = v7l; - BBUF[15] = v7h; - BBUF.set(B2B_IV, 16); - const l = fromNumL(this.length); - const h = fromNumH(this.length); - BBUF[24] = B2B_IV[8] ^ l; - BBUF[25] = B2B_IV[9] ^ h; - if (isLast) { - BBUF[28] = ~BBUF[28]; - BBUF[29] = ~BBUF[29]; - } - let j = 0; - const s = BSIGMA; - for (let i = 0; i < 12; i++) { - G1b(0, 4, 8, 12, msg, offset + 2 * s[j++]); - G2b(0, 4, 8, 12, msg, offset + 2 * s[j++]); - G1b(1, 5, 9, 13, msg, offset + 2 * s[j++]); - G2b(1, 5, 9, 13, msg, offset + 2 * s[j++]); - G1b(2, 6, 10, 14, msg, offset + 2 * s[j++]); - G2b(2, 6, 10, 14, msg, offset + 2 * s[j++]); - G1b(3, 7, 11, 15, msg, offset + 2 * s[j++]); - G2b(3, 7, 11, 15, msg, offset + 2 * s[j++]); - G1b(0, 5, 10, 15, msg, offset + 2 * s[j++]); - G2b(0, 5, 10, 15, msg, offset + 2 * s[j++]); - G1b(1, 6, 11, 12, msg, offset + 2 * s[j++]); - G2b(1, 6, 11, 12, msg, offset + 2 * s[j++]); - G1b(2, 7, 8, 13, msg, offset + 2 * s[j++]); - G2b(2, 7, 8, 13, msg, offset + 2 * s[j++]); - G1b(3, 4, 9, 14, msg, offset + 2 * s[j++]); - G2b(3, 4, 9, 14, msg, offset + 2 * s[j++]); - } - this.v0l ^= BBUF[0] ^ BBUF[16]; - this.v0h ^= BBUF[1] ^ BBUF[17]; - this.v1l ^= BBUF[2] ^ BBUF[18]; - this.v1h ^= BBUF[3] ^ BBUF[19]; - this.v2l ^= BBUF[4] ^ BBUF[20]; - this.v2h ^= BBUF[5] ^ BBUF[21]; - this.v3l ^= BBUF[6] ^ BBUF[22]; - this.v3h ^= BBUF[7] ^ BBUF[23]; - this.v4l ^= BBUF[8] ^ BBUF[24]; - this.v4h ^= BBUF[9] ^ BBUF[25]; - this.v5l ^= BBUF[10] ^ BBUF[26]; - this.v5h ^= BBUF[11] ^ BBUF[27]; - this.v6l ^= BBUF[12] ^ BBUF[28]; - this.v6h ^= BBUF[13] ^ BBUF[29]; - this.v7l ^= BBUF[14] ^ BBUF[30]; - this.v7h ^= BBUF[15] ^ BBUF[31]; - clean$2(BBUF); - } - destroy() { - this.destroyed = true; - clean$2(this.buffer32); - this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - } -}; -/** -* Blake2b hash function. 64-bit. 1.5x slower than blake2s in JS. -* @param msg - message that would be hashed -* @param opts - Optional output, MAC, salt, and personalization settings. -* `dkLen` must be 1..64 bytes; `salt` and `personalization`, if present, -* must be 16 bytes each. See {@link Blake2Opts}. -* @returns Digest bytes. -* @example -* Hash a message with Blake2b. -* ```ts -* blake2b(new Uint8Array([97, 98, 99])); -* ``` -* @example -* Hash a message with Blake2b while selecting output, MAC, salt, and personalization settings. -* ```ts -* blake2b(new Uint8Array([97, 98, 99]), { -* dkLen: 32, -* key: new Uint8Array(32), -* salt: new Uint8Array(16), -* personalization: new Uint8Array(16), -* }); -* ``` -*/ -const blake2b = /* @__PURE__ */ createHasher$1((opts) => new _BLAKE2b(opts)); -//#endregion -//#region tests/baseline/node_modules/@noble/hashes/argon2.js -/** -* Argon2 KDF from RFC 9106. Can be used to create a key from password and salt. -* We suggest to use Scrypt. JS Argon is 2-10x slower than native code because of 64-bitness: -* * argon uses uint64, but JS doesn't have fast uint64array -* * uint64 multiplication is 1/3 of time -* * `P` function would be very nice with u64, because most of value will be in registers, -* hovewer with u32 it will require 32 registers, which is too much. -* * JS arrays do slow bound checks, so reading from `A2_BUF` slows it down -* @module -*/ -const AT = { - Argon2d: 0, - Argon2i: 1, - Argon2id: 2 -}; -const ARGON2_SYNC_POINTS = 4; -const abytesOrZero = (buf, errorTitle = "") => { - if (buf === void 0) return Uint8Array.of(); - return kdfInputToBytes(buf, errorTitle); -}; -const A2_BUF = /* @__PURE__ */ new Uint32Array(256); -function G(a, b, c, d) { - let Al = A2_BUF[2 * a], Ah = A2_BUF[2 * a + 1]; - let Bl = A2_BUF[2 * b], Bh = A2_BUF[2 * b + 1]; - let Cl = A2_BUF[2 * c], Ch = A2_BUF[2 * c + 1]; - let Dl = A2_BUF[2 * d], Dh = A2_BUF[2 * d + 1]; - let ml = 0, mh = 0, rl = 0, xh = 0, xl = 0; - ml = Math.imul(Al, Bl); - mh = ((Al >>> 0) * (Bl >>> 0) - (ml >>> 0)) / 4294967296 + .5 | 0; - rl = (Al >>> 0) + (Bl >>> 0) + (ml << 1 >>> 0); - Ah = Ah + Bh + (mh << 1 | ml >>> 31) + (rl / 4294967296 | 0) | 0; - Al = rl | 0; - xh = Dh ^ Ah; - xl = Dl ^ Al; - Dh = xl; - Dl = xh; - ml = Math.imul(Cl, Dl); - mh = ((Cl >>> 0) * (Dl >>> 0) - (ml >>> 0)) / 4294967296 + .5 | 0; - rl = (Cl >>> 0) + (Dl >>> 0) + (ml << 1 >>> 0); - Ch = Ch + Dh + (mh << 1 | ml >>> 31) + (rl / 4294967296 | 0) | 0; - Cl = rl | 0; - xh = Bh ^ Ch; - xl = Bl ^ Cl; - Bh = xh >>> 24 | xl << 8; - Bl = xh << 8 | xl >>> 24; - ml = Math.imul(Al, Bl); - mh = ((Al >>> 0) * (Bl >>> 0) - (ml >>> 0)) / 4294967296 + .5 | 0; - rl = (Al >>> 0) + (Bl >>> 0) + (ml << 1 >>> 0); - Ah = Ah + Bh + (mh << 1 | ml >>> 31) + (rl / 4294967296 | 0) | 0; - Al = rl | 0; - xh = Dh ^ Ah; - xl = Dl ^ Al; - Dh = xh >>> 16 | xl << 16; - Dl = xh << 16 | xl >>> 16; - ml = Math.imul(Cl, Dl); - mh = ((Cl >>> 0) * (Dl >>> 0) - (ml >>> 0)) / 4294967296 + .5 | 0; - rl = (Cl >>> 0) + (Dl >>> 0) + (ml << 1 >>> 0); - Ch = Ch + Dh + (mh << 1 | ml >>> 31) + (rl / 4294967296 | 0) | 0; - Cl = rl | 0; - xh = Bh ^ Ch; - xl = Bl ^ Cl; - Bh = xh << 1 | xl >>> 31; - Bl = xh >>> 31 | xl << 1; - A2_BUF[2 * a] = Al, A2_BUF[2 * a + 1] = Ah; - A2_BUF[2 * b] = Bl, A2_BUF[2 * b + 1] = Bh; - A2_BUF[2 * c] = Cl, A2_BUF[2 * c + 1] = Ch; - A2_BUF[2 * d] = Dl, A2_BUF[2 * d + 1] = Dh; -} -function P(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11, v12, v13, v14, v15) { - G(v00, v04, v08, v12); - G(v01, v05, v09, v13); - G(v02, v06, v10, v14); - G(v03, v07, v11, v15); - G(v00, v05, v10, v15); - G(v01, v06, v11, v12); - G(v02, v07, v08, v13); - G(v03, v04, v09, v14); -} -function block(x, xPos, yPos, outPos, needXor) { - if (needXor) for (let i = 0; i < 256; i++) { - const r = x[xPos + i] ^ x[yPos + i]; - A2_BUF[i] = r; - x[outPos + i] ^= r; - } - else for (let i = 0; i < 256; i++) { - const r = x[xPos + i] ^ x[yPos + i]; - A2_BUF[i] = r; - x[outPos + i] = r; - } - for (let i = 0; i < 128; i += 16) P(i, i + 1, i + 2, i + 3, i + 4, i + 5, i + 6, i + 7, i + 8, i + 9, i + 10, i + 11, i + 12, i + 13, i + 14, i + 15); - for (let i = 0; i < 16; i += 2) P(i, i + 1, i + 16, i + 17, i + 32, i + 33, i + 48, i + 49, i + 64, i + 65, i + 80, i + 81, i + 96, i + 97, i + 112, i + 113); - for (let i = 0; i < 256; i++) x[outPos + i] ^= A2_BUF[i]; - clean$2(A2_BUF); -} -function Hp(A, dkLen) { - const A8 = u8(A); - const T = /* @__PURE__ */ new Uint32Array(1); - const T8 = u8(T); - T[0] = swap8IfBE(dkLen); - if (dkLen <= 64) return blake2b.create({ dkLen }).update(T8).update(A8).digest(); - const out = new Uint8Array(dkLen); - let V = blake2b.create({}).update(T8).update(A8).digest(); - let pos = 0; - out.set(V.subarray(0, 32)); - pos += 32; - for (; dkLen - pos > 64; pos += 32) { - const Vh = blake2b.create({}).update(V); - Vh.digestInto(V); - Vh.destroy(); - out.set(V.subarray(0, 32), pos); - } - out.set(blake2b(V, { dkLen: dkLen - pos }), pos); - clean$2(V, T); - return out; -} -function indexAlpha(r, s, laneLen, segmentLen, index, randL, sameLane = false) { - let area; - if (r === 0) { - if (s === 0) area = index - 1; - else if (sameLane) area = s * segmentLen + index - 1; - else area = s * segmentLen + (index == 0 ? -1 : 0); - } else if (sameLane) area = laneLen - segmentLen + index - 1; - else area = laneLen - segmentLen + (index == 0 ? -1 : 0); - const startPos = r !== 0 && s !== 3 ? (s + 1) * segmentLen : 0; - const randLow = Math.imul(randL, randL); - const randHigh = ((randL >>> 0) * (randL >>> 0) - (randLow >>> 0)) / 4294967296 + .5 | 0; - const areaLow = Math.imul(area, randHigh); - const areaHigh = ((area >>> 0) * (randHigh >>> 0) - (areaLow >>> 0)) / 4294967296 + .5 | 0; - return (startPos + (area - 1 - areaHigh)) % laneLen; -} -const maxUint32 = Math.pow(2, 32); -const ARGON2_DEFAULT_MEMORY = 1024 ** 2; -const ARGON2_DEFAULT_MAXMEM = ARGON2_DEFAULT_MEMORY * 1024; -function isU32(num) { - return Number.isSafeInteger(num) && num >= 0 && num < maxUint32; -} -function argon2Opts(opts = {}) { - opts = checkOpts$1({}, opts); - const merged = { - t: 3, - m: ARGON2_DEFAULT_MEMORY, - p: 1, - version: 19, - dkLen: 32, - maxmem: ARGON2_DEFAULT_MAXMEM, - asyncTick: 10 - }; - for (let [k, v] of Object.entries(opts)) if (v !== void 0) merged[k] = v; - const { dkLen, p, m, t, version, onProgress, asyncTick } = merged; - if (!isU32(dkLen) || dkLen < 4) throw new Error("\"dkLen\" must be 4.."); - if (!isU32(p) || p < 1 || p >= Math.pow(2, 24)) throw new Error("\"p\" must be 1..2^24"); - if (!isU32(m)) throw new Error("\"m\" must be 0..2^32"); - if (!isU32(t) || t < 1) throw new Error("\"t\" (iterations) must be 1..2^32"); - if (onProgress !== void 0 && typeof onProgress !== "function") throw new Error("\"onProgress\" must be a function"); - anumber$4(asyncTick, "asyncTick"); - if (!isU32(m) || m < 8 * p) throw new Error("\"m\" (memory) must be at least 8*p bytes"); - if (version !== 16 && version !== 19) throw new Error("\"version\" must be 0x10 or 0x13, got " + version); - return merged; -} -function argon2InitialHash(password, salt, type, opts) { - const ownedInputs = []; - const BUF = /* @__PURE__ */ new Uint32Array(1); - const BUF8 = u8(BUF); - let h; - let H0; - let succeeded = false; - const rememberOwned = (input, bytes) => { - if (typeof input === "string") ownedInputs.push(bytes); - return bytes; - }; - try { - const passwordBytes = rememberOwned(password, kdfInputToBytes(password, "password")); - const saltBytes = rememberOwned(salt, kdfInputToBytes(salt, "salt")); - if (!isU32(passwordBytes.length)) throw new Error("\"password\" must be less of length 1..4Gb"); - if (!isU32(saltBytes.length) || saltBytes.length < 8) throw new Error("\"salt\" must be of length 8..4Gb"); - if (!Object.values(AT).includes(type)) throw new Error("\"type\" was invalid"); - let { p, dkLen, m, t, version, key, personalization, maxmem, onProgress, asyncTick } = argon2Opts(opts); - const keyInput = key; - key = rememberOwned(keyInput, abytesOrZero(keyInput, "key")); - const personalizationInput = personalization; - personalization = rememberOwned(personalizationInput, abytesOrZero(personalizationInput, "personalization")); - h = blake2b.create(); - for (let item of [ - p, - dkLen, - m, - t, - version, - type - ]) { - BUF[0] = swap8IfBE(item); - h.update(BUF8); - } - for (let i of [ - passwordBytes, - saltBytes, - key, - personalization - ]) { - BUF[0] = swap8IfBE(i.length); - h.update(BUF8).update(i); - } - H0 = /* @__PURE__ */ new Uint32Array(18); - h.digestInto(u8(H0)); - succeeded = true; - return { - H0, - p, - dkLen, - m, - t, - version, - maxmem, - onProgress, - asyncTick - }; - } finally { - if (h) h.destroy(); - clean$2(BUF, ...ownedInputs); - if (!succeeded && H0) clean$2(H0); - } -} -function argon2Init(password, salt, type, opts) { - const { H0, p, dkLen, m, t, version, maxmem, onProgress, asyncTick } = argon2InitialHash(password, salt, type, opts); - try { - const lanes = p; - const mP = 4 * p * Math.floor(m / (ARGON2_SYNC_POINTS * p)); - const laneLen = Math.floor(mP / p); - const segmentLen = Math.floor(laneLen / ARGON2_SYNC_POINTS); - const memUsed = mP * 1024; - if (!isU32(maxmem)) throw new Error("\"maxmem\" expected <2**32, got " + maxmem); - if (memUsed > maxmem) throw new Error("\"maxmem\" limit was hit: memUsed(mP*1024)=" + memUsed + ", maxmem=" + maxmem); - const B = new Uint32Array(memUsed / 4); - for (let l = 0; l < p; l++) { - const i = 256 * laneLen * l; - H0[17] = swap8IfBE(l); - H0[16] = swap8IfBE(0); - B.set(swap32IfBE$2(u32$2(Hp(H0, 1024))), i); - H0[16] = swap8IfBE(1); - B.set(swap32IfBE$2(u32$2(Hp(H0, 1024))), i + 256); - } - let perBlock = () => {}; - if (onProgress) { - const totalBlock = t * ARGON2_SYNC_POINTS * p * segmentLen - 2 * p; - const callbackPer = Math.max(Math.floor(totalBlock / 1e4), 1); - let blockCnt = 0; - perBlock = () => { - blockCnt++; - if (onProgress && (!(blockCnt % callbackPer) || blockCnt === totalBlock)) onProgress(blockCnt / totalBlock); - }; - } - return { - type, - mP, - p, - t, - version, - B, - laneLen, - lanes, - segmentLen, - dkLen, - perBlock, - asyncTick - }; - } finally { - clean$2(H0); - } -} -function argon2Output(B, p, laneLen, dkLen) { - const B_final = /* @__PURE__ */ new Uint32Array(256); - for (let l = 0; l < p; l++) for (let j = 0; j < 256; j++) B_final[j] ^= B[256 * (laneLen * l + laneLen - 1) + j]; - const res = Hp(swap32IfBE$2(B_final), dkLen); - clean$2(B, B_final); - return res; -} -/** -* Fills every Argon2 block for all passes / slices / lanes, yielding once per -* processed block so callers control pacing: the sync driver just drains the -* generator, while the async driver awaits `nextTick()` between time slices. -*/ -function* argon2Blocks(ctx, address) { - const { type, mP, p, t, version, B, laneLen, lanes, segmentLen, perBlock } = ctx; - address[262] = mP; - address[264] = t; - address[266] = type; - for (let r = 0; r < t; r++) { - const needXor = r !== 0 && version === 19; - address[256] = r; - for (let s = 0; s < ARGON2_SYNC_POINTS; s++) { - address[260] = s; - const dataIndependent = type == AT.Argon2i || type == AT.Argon2id && r === 0 && s < 2; - for (let l = 0; l < p; l++) { - address[258] = l; - address[268] = 0; - let startPos = 0; - if (r === 0 && s === 0) { - startPos = 2; - if (dataIndependent) { - address[268]++; - block(address, 256, 512, 0, false); - block(address, 0, 512, 0, false); - } - } - let offset = l * laneLen + s * segmentLen + startPos; - for (let index = startPos; index < segmentLen; index++, offset++) { - perBlock(); - const prev = offset % laneLen ? offset - 1 : offset + laneLen - 1; - let randL, randH; - if (dataIndependent) { - let i128 = index % 128; - if (i128 === 0) { - address[268]++; - block(address, 256, 512, 0, false); - block(address, 0, 512, 0, false); - } - randL = address[2 * i128]; - randH = address[2 * i128 + 1]; - } else { - const T = 256 * prev; - randL = B[T]; - randH = B[T + 1]; - } - const refLane = r === 0 && s === 0 ? l : randH % lanes; - const refPos = indexAlpha(r, s, laneLen, segmentLen, index, randL, refLane == l); - const refBlock = laneLen * refLane + refPos; - block(B, 256 * prev, 256 * refBlock, offset * 256, needXor); - yield; - } - } - } - } - clean$2(address); -} -function argon2(type, password, salt, opts) { - const ctx = argon2Init(password, salt, type, opts); - const blocks = argon2Blocks(ctx, /* @__PURE__ */ new Uint32Array(768)); - while (!blocks.next().done); - return argon2Output(ctx.B, ctx.p, ctx.laneLen, ctx.dkLen); -} -/** -* Argon2id, combining i+d, the most popular version from RFC 9106. -* @param password - password or input key material -* @param salt - unique salt value -* @param opts - Argon2 cost and optional tuning parameters. See {@link ArgonOpts}. -* @returns Derived key bytes. -* @throws If the Argon2 input or cost parameters are invalid. {@link Error} -* @example -* Derive a key with Argon2id. -* ```ts -* argon2id('password', 'salt1234', { t: 1, m: 8, p: 1, dkLen: 32 }); -* ``` -*/ -const argon2id$1 = (password, salt, opts = {}) => argon2(AT.Argon2id, password, salt, opts); -//#endregion -//#region tests/baseline/node_modules/@bcts/crypto/dist/index.mjs -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -*/ -var hash_exports = /* @__PURE__ */ __exportAll({ - CRC32_SIZE: () => 4, - SHA256_SIZE: () => 32, - SHA512_SIZE: () => 64, - crc32: () => crc32$1, - crc32Data: () => crc32Data, - crc32DataOpt: () => crc32DataOpt, - doubleSha256: () => doubleSha256, - hkdfHmacSha256: () => hkdfHmacSha256$1, - hkdfHmacSha512: () => hkdfHmacSha512, - hmacSha256: () => hmacSha256, - hmacSha512: () => hmacSha512, - pbkdf2HmacSha256: () => pbkdf2HmacSha256, - pbkdf2HmacSha512: () => pbkdf2HmacSha512, - sha256: () => sha256$1, - sha512: () => sha512 -}); -const CRC32_TABLE$1 = /* @__PURE__ */ new Uint32Array(256); -for (let i = 0; i < 256; i++) { - let crc = i; - for (let j = 0; j < 8; j++) crc = (crc & 1) !== 0 ? crc >>> 1 ^ 3988292384 : crc >>> 1; - CRC32_TABLE$1[i] = crc >>> 0; -} -/** -* Calculate CRC-32 checksum -*/ -function crc32$1(data) { - let crc = 4294967295; - for (const byte of data) crc = CRC32_TABLE$1[(crc ^ byte) & 255] ^ crc >>> 8; - return (crc ^ 4294967295) >>> 0; -} -/** -* Calculate CRC-32 checksum and return as a 4-byte big-endian array -*/ -function crc32Data(data) { - return crc32DataOpt(data, false); -} -/** -* Calculate CRC-32 checksum and return as a 4-byte array -* @param data - Input data -* @param littleEndian - If true, returns little-endian; otherwise big-endian -*/ -function crc32DataOpt(data, littleEndian) { - const checksum = crc32$1(data); - const result = /* @__PURE__ */ new Uint8Array(4); - new DataView(result.buffer).setUint32(0, checksum, littleEndian); - return result; -} -/** -* Calculate SHA-256 hash -*/ -function sha256$1(data) { - return sha256$2(data); -} -/** -* Calculate double SHA-256 hash (SHA-256 of SHA-256) -* This is the standard Bitcoin hashing function -*/ -function doubleSha256(message) { - return sha256$1(sha256$1(message)); -} -/** -* Calculate SHA-512 hash -*/ -function sha512(data) { - return sha512$1(data); -} -/** -* Calculate HMAC-SHA-256 -*/ -function hmacSha256(key, message) { - return hmac(sha256$2, key, message); -} -/** -* Calculate HMAC-SHA-512 -*/ -function hmacSha512(key, message) { - return hmac(sha512$1, key, message); -} -/** -* Derive a key using PBKDF2 with HMAC-SHA-256 -*/ -function pbkdf2HmacSha256(password, salt, iterations, keyLen) { - return pbkdf2(sha256$2, password, salt, { - c: iterations, - dkLen: keyLen - }); -} -/** -* Derive a key using PBKDF2 with HMAC-SHA-512 -*/ -function pbkdf2HmacSha512(password, salt, iterations, keyLen) { - return pbkdf2(sha512$1, password, salt, { - c: iterations, - dkLen: keyLen - }); -} -/** -* Derive a key using HKDF with HMAC-SHA-256 -*/ -function hkdfHmacSha256$1(keyMaterial, salt, keyLen) { - return hkdf(sha256$2, keyMaterial, salt, void 0, keyLen); -} -/** -* Derive a key using HKDF with HMAC-SHA-512 -*/ -function hkdfHmacSha512(keyMaterial, salt, keyLen) { - return hkdf(sha512$1, keyMaterial, salt, void 0, keyLen); -} -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -*/ -/** -* AEAD-specific error for authentication failures -*/ -var AeadError = class extends Error { - constructor(message = "AEAD authentication failed") { - super(message); - this.name = "AeadError"; - } -}; -/** -* Generic crypto error type -*/ -var CryptoError$1 = class CryptoError extends Error { - cause; - constructor(message, cause) { - super(message); - this.name = "CryptoError"; - this.cause = cause; - } - /** - * Create a CryptoError for AEAD authentication failures. - * - * @param error - Optional underlying AeadError - * @returns A CryptoError wrapping the AEAD error - */ - static aead(error) { - return new CryptoError("AEAD error", error ?? new AeadError()); - } - /** - * Create a CryptoError for invalid parameter values. - * - * **TS-specific.** Rust's `bc_crypto::Error` enum has no - * `InvalidParameter` variant; size validation in Rust is enforced at - * compile time via fixed-size array references (e.g. `&[u8; 32]`) or - * via `panic!`/`expect(...)` for runtime checks. The TS port has no - * fixed-size array types, so it surfaces those same conditions through - * a thrown `CryptoError.invalidParameter(...)`. Catching this is - * equivalent to defensive guards around an `expect`-style panic on the - * Rust side. - * - * @param message - Description of the invalid parameter - * @returns A CryptoError describing the invalid parameter - */ - static invalidParameter(message) { - return new CryptoError(`Invalid parameter: ${message}`); - } -}; -/** -* Securely zero out a typed array. -* -* Mirrors Rust `bc_crypto::memzero(s: &mut [T])`. The Rust impl uses -* `std::ptr::write_volatile()` to guarantee the writes survive optimization; -* JavaScript has no equivalent primitive, so this is **best-effort** — JIT -* compilers may still elide the loop, though the post-hoc verification -* check forces the engine to keep the writes observable. -* -* For truly sensitive cryptographic operations, consider using the Web -* Crypto API's `crypto.subtle` with non-extractable keys when possible, as -* it provides stronger guarantees than what can be achieved with pure -* JavaScript. -* -* Accepts any of the standard numeric typed arrays — `Uint8Array`, -* `Uint8ClampedArray`, `Uint16Array`, `Uint32Array`, `Int8Array`, -* `Int16Array`, `Int32Array`, `Float32Array`, `Float64Array` — matching -* Rust's generic `&mut [T]`. (`BigInt64Array` / `BigUint64Array` are -* excluded because their elements are `bigint`, not `number`; if that -* support is needed, add a dedicated overload.) -*/ -function memzero(data) { - const len = data.length; - for (let i = 0; i < len; i++) data[i] = 0; - if (data.length > 0 && data[0] !== 0) throw new Error("memzero failed"); -} -/** -* Securely zero out an array of Uint8Arrays. -*/ -function memzeroVecVecU8(arrays) { - for (const arr of arrays) memzero(arr); -} -/** -* Encrypt data using ChaCha20-Poly1305 AEAD cipher with additional authenticated data. -* -* **Security Warning**: The nonce MUST be unique for every encryption operation -* with the same key. Reusing a nonce completely breaks the security of the -* encryption scheme and can reveal plaintext. -* -* @param plaintext - The data to encrypt -* @param key - 32-byte encryption key -* @param nonce - 12-byte nonce (MUST be unique per encryption with the same key) -* @param aad - Additional authenticated data (not encrypted, but integrity-protected) -* @returns Tuple of [ciphertext, authTag] where authTag is 16 bytes -* @throws {CryptoError} If key is not 32 bytes or nonce is not 12 bytes -*/ -function aeadChaCha20Poly1305EncryptWithAad(plaintext, key, nonce, aad) { - if (key.length !== 32) throw CryptoError$1.invalidParameter(`Key must be 32 bytes`); - if (nonce.length !== 12) throw CryptoError$1.invalidParameter(`Nonce must be 12 bytes`); - const sealed = chacha20poly1305(key, nonce, aad).encrypt(plaintext); - return [sealed.slice(0, sealed.length - 16), sealed.slice(sealed.length - 16)]; -} -/** -* Decrypt data using ChaCha20-Poly1305 AEAD cipher with additional authenticated data. -* -* @param ciphertext - The encrypted data -* @param key - 32-byte encryption key (must match key used for encryption) -* @param nonce - 12-byte nonce (must match nonce used for encryption) -* @param aad - Additional authenticated data (must exactly match AAD used for encryption) -* @param authTag - 16-byte authentication tag from encryption -* @returns Decrypted plaintext -* @throws {CryptoError} If key/nonce/authTag sizes are invalid -* @throws {CryptoError} If authentication fails (tampered data, wrong key/nonce, or AAD mismatch) -*/ -function aeadChaCha20Poly1305DecryptWithAad(ciphertext, key, nonce, aad, authTag) { - if (key.length !== 32) throw CryptoError$1.invalidParameter(`Key must be 32 bytes`); - if (nonce.length !== 12) throw CryptoError$1.invalidParameter(`Nonce must be 12 bytes`); - if (authTag.length !== 16) throw CryptoError$1.invalidParameter(`Auth tag must be 16 bytes`); - const sealed = new Uint8Array(ciphertext.length + authTag.length); - sealed.set(ciphertext); - sealed.set(authTag, ciphertext.length); - try { - return chacha20poly1305(key, nonce, aad).decrypt(sealed); - } catch (error) { - const aeadError = new AeadError(`Decryption failed: ${error instanceof Error ? error.message : "authentication error"}`); - throw CryptoError$1.aead(aeadError); - } -} -/** -* Derive an X25519 agreement private key from key material. -* Uses HKDF with "agreement" as domain separation salt. -*/ -function deriveAgreementPrivateKey(keyMaterial) { - return hkdfHmacSha256$1(keyMaterial, new TextEncoder().encode("agreement"), 32); -} -/** -* Derive a signing private key from key material. -* Uses HKDF with "signing" as domain separation salt. -*/ -function deriveSigningPrivateKey(keyMaterial) { - return hkdfHmacSha256$1(keyMaterial, new TextEncoder().encode("signing"), 32); -} -/** -* Derive an X25519 public key from a private key. -*/ -function x25519PublicKeyFromPrivateKey(privateKey) { - if (privateKey.length !== 32) throw new Error(`Private key must be 32 bytes`); - return x25519.getPublicKey(privateKey); -} -const SYMMETRIC_KEY_SIZE$1 = 32; -/** -* Compute a shared symmetric key using X25519 key agreement (ECDH). -* -* This function performs X25519 Diffie-Hellman key agreement and then -* derives a symmetric key using HKDF-SHA256 with "agreement" as the salt. -* This matches the Rust bc-crypto implementation for cross-platform compatibility. -* -* **Low-order public key handling.** The underlying `@noble/curves` X25519 -* implementation rejects low-order public keys (where the u-coordinate is -* `0`) by throwing `'invalid private or public key received'`. Rust's -* `x25519-dalek` (v2.0-rc.2) instead silently produces the all-zero shared -* secret. This means an adversarial low-order public key fed in via TS -* surfaces as an exception, while in Rust it would yield an HKDF-derived -* key from a zero shared secret. For honest inputs both implementations -* produce byte-identical results; the TS port's stricter behaviour is a -* security improvement, not a parity bug. -* -* @param x25519Private - 32-byte X25519 private key -* @param x25519Public - 32-byte X25519 public key from the other party -* @returns 32-byte derived symmetric key -* @throws {Error} If private key is not 32 bytes or public key is not 32 bytes -* @throws {Error} If the public key is low-order (`@noble/curves`-specific guard) -*/ -function x25519SharedKey(x25519Private, x25519Public) { - if (x25519Private.length !== 32) throw new Error(`Private key must be 32 bytes`); - if (x25519Public.length !== 32) throw new Error(`Public key must be 32 bytes`); - return hkdfHmacSha256$1(x25519.getSharedSecret(x25519Private, x25519Public), new TextEncoder().encode("agreement"), SYMMETRIC_KEY_SIZE$1); -} -/** -* Derive a compressed ECDSA public key from a private key. -*/ -function ecdsaPublicKeyFromPrivateKey(privateKey) { - if (privateKey.length !== 32) throw new Error(`Private key must be 32 bytes`); - return secp256k1.getPublicKey(privateKey, true); -} -/** -* Decompress a compressed public key to uncompressed format. -*/ -function ecdsaDecompressPublicKey(compressed) { - if (compressed.length !== 33) throw new Error(`Compressed public key must be 33 bytes`); - return secp256k1.Point.fromBytes(compressed).toBytes(false); -} -/** -* Compress an uncompressed public key. -*/ -function ecdsaCompressPublicKey(uncompressed) { - if (uncompressed.length !== 65) throw new Error(`Uncompressed public key must be 65 bytes`); - return secp256k1.Point.fromBytes(uncompressed).toBytes(true); -} -/** -* Derive an ECDSA private key from key material using HKDF. -* -* Note: This directly returns the HKDF output without validation, -* matching the Rust reference implementation behavior. -*/ -function ecdsaDerivePrivateKey(keyMaterial) { - return hkdfHmacSha256$1(keyMaterial, new TextEncoder().encode("signing"), 32); -} -/** -* Extract the x-only (Schnorr) public key from a private key. -* This is used for BIP-340 Schnorr signatures. -*/ -function schnorrPublicKeyFromPrivateKey(privateKey) { - if (privateKey.length !== 32) throw new Error(`Private key must be 32 bytes`); - return secp256k1.getPublicKey(privateKey, false).slice(1, 33); -} -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -*/ -/** -* Sign a message using ECDSA with secp256k1. -* -* The message is hashed with double SHA-256 before signing (Bitcoin standard). -* -* **Security Note**: The private key must be kept secret. ECDSA requires -* cryptographically secure random nonces internally; this is handled by -* the underlying library using RFC 6979 deterministic nonces. -* -* @param privateKey - 32-byte secp256k1 private key -* @param message - Message to sign (any length, will be double-SHA256 hashed) -* @returns 64-byte compact signature (r || s format) -* @throws {Error} If private key is not 32 bytes -*/ -function ecdsaSign(privateKey, message) { - if (privateKey.length !== 32) throw new Error(`Private key must be 32 bytes`); - const messageHash = doubleSha256(message); - return secp256k1.sign(messageHash, privateKey, { prehash: false }); -} -/** -* Verify an ECDSA signature with secp256k1. -* -* The message is hashed with double SHA-256 before verification (Bitcoin standard). -* -* @param publicKey - 33-byte compressed secp256k1 public key -* @param signature - 64-byte compact signature (r || s format) -* @param message - Original message that was signed -* @returns `true` if signature is valid, `false` if signature verification fails -* @throws {Error} If public key is not 33 bytes or signature is not 64 bytes -*/ -function ecdsaVerify(publicKey, signature, message) { - if (publicKey.length !== 33) throw new Error(`Public key must be 33 bytes`); - if (signature.length !== 64) throw new Error(`Signature must be 64 bytes`); - try { - const messageHash = doubleSha256(message); - return secp256k1.verify(signature, messageHash, publicKey, { prehash: false }); - } catch { - return false; - } -} -/** -* Sign a message using Schnorr signature (BIP-340). -* Uses secure random auxiliary randomness. -* -* @param ecdsaPrivateKey - 32-byte private key -* @param message - Message to sign (not pre-hashed, per BIP-340) -* @returns 64-byte Schnorr signature -*/ -function schnorrSign(ecdsaPrivateKey, message) { - return schnorrSignUsing(ecdsaPrivateKey, message, new SecureRandomNumberGenerator()); -} -/** -* Sign a message using Schnorr signature with a custom RNG. -* -* @param ecdsaPrivateKey - 32-byte private key -* @param message - Message to sign -* @param rng - Random number generator for auxiliary randomness -* @returns 64-byte Schnorr signature -*/ -function schnorrSignUsing(ecdsaPrivateKey, message, rng) { - return schnorrSignWithAuxRand(ecdsaPrivateKey, message, rng.randomData(32)); -} -/** -* Sign a message using Schnorr signature with specific auxiliary randomness. -* This is useful for deterministic signing in tests. -* -* @param ecdsaPrivateKey - 32-byte private key -* @param message - Message to sign -* @param auxRand - 32-byte auxiliary randomness (per BIP-340) -* @returns 64-byte Schnorr signature -*/ -function schnorrSignWithAuxRand(ecdsaPrivateKey, message, auxRand) { - if (ecdsaPrivateKey.length !== 32) throw new Error(`Private key must be 32 bytes`); - if (auxRand.length !== 32) throw new Error("Auxiliary randomness must be 32 bytes"); - return schnorr.sign(message, ecdsaPrivateKey, auxRand); -} -/** -* Verify a Schnorr signature (BIP-340). -* -* @param schnorrPublicKey - 32-byte x-only public key -* @param signature - 64-byte Schnorr signature -* @param message - Original message -* @returns true if signature is valid -*/ -function schnorrVerify(schnorrPublicKey, signature, message) { - if (schnorrPublicKey.length !== 32) throw new Error(`Public key must be 32 bytes`); - if (signature.length !== 64) throw new Error(`Signature must be 64 bytes`); - try { - return schnorr.verify(signature, message, schnorrPublicKey); - } catch { - return false; - } -} -/** -* Derive an Ed25519 public key from a private key. -*/ -function ed25519PublicKeyFromPrivateKey(privateKey) { - if (privateKey.length !== 32) throw new Error(`Private key must be 32 bytes`); - return ed25519.getPublicKey(privateKey); -} -/** -* Sign a message using Ed25519. -* -* **Security Note**: The private key must be kept secret. The same private key -* can safely sign multiple messages. -* -* @param privateKey - 32-byte Ed25519 private key -* @param message - Message to sign (any length) -* @returns 64-byte Ed25519 signature -* @throws {Error} If private key is not 32 bytes -*/ -function ed25519Sign(privateKey, message) { - if (privateKey.length !== 32) throw new Error(`Private key must be 32 bytes`); - return ed25519.sign(message, privateKey); -} -/** -* Verify an Ed25519 signature. -* -* @param publicKey - 32-byte Ed25519 public key -* @param message - Original message that was signed -* @param signature - 64-byte Ed25519 signature -* @returns `true` if signature is valid, `false` if signature verification fails -* @throws {Error} If public key is not 32 bytes or signature is not 64 bytes -*/ -function ed25519Verify(publicKey, message, signature) { - if (publicKey.length !== 32) throw new Error(`Public key must be 32 bytes`); - if (signature.length !== 64) throw new Error(`Signature must be 64 bytes`); - try { - return ed25519.verify(signature, message, publicKey); - } catch { - return false; - } -} -/** -* Derive a key using Scrypt with custom parameters. -* -* @param password - Password or passphrase -* @param salt - Salt value -* @param outputLen - Desired output length -* @param logN - Log2 of the CPU/memory cost parameter N (must be <64) -* @param r - Block size parameter (must be >0) -* @param p - Parallelization parameter (must be >0) -* @returns Derived key -*/ -function scryptOpt(password, salt, outputLen, logN, r, p) { - if (logN >= 64) throw new Error("logN must be <64"); - if (r === 0) throw new Error("r must be >0"); - if (p === 0) throw new Error("p must be >0"); - return scrypt(password, salt, { - N: 1 << logN, - r, - p, - dkLen: outputLen - }); -} -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -*/ -/** -* Derive a key using Argon2id with default parameters. -* -* Mirrors Rust `bc_crypto::argon2id` which calls `Argon2::default()`. The -* upstream `argon2` crate's defaults are `t = 2` iterations, `m = 19 * 1024 -* = 19456` KiB of memory, `p = 1` lane (per `argon2-0.5.x/src/params.rs`). -* -* @param password - Password or passphrase -* @param salt - Salt value (must be at least 8 bytes) -* @param outputLen - Desired output length -* @returns Derived key -*/ -function argon2id(password, salt, outputLen) { - return argon2idHashOpt(password, salt, outputLen, 2, 19456, 1); -} -/** -* Derive a key using Argon2id with custom parameters. -* -* @param password - Password or passphrase -* @param salt - Salt value (must be at least 8 bytes) -* @param outputLen - Desired output length -* @param iterations - Number of iterations (t) -* @param memory - Memory in KiB (m) -* @param parallelism - Degree of parallelism (p) -* @returns Derived key -*/ -function argon2idHashOpt(password, salt, outputLen, iterations, memory, parallelism) { - return argon2id$1(password, salt, { - t: iterations, - m: memory, - p: parallelism, - dkLen: outputLen - }); -} -//#endregion -//#region tests/baseline/node_modules/@bcts/uniform-resources/dist/index.mjs -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -* -* Error type for UR encoding/decoding operations. -*/ -var URError = class extends Error { - constructor(message) { - super(message); - this.name = "URError"; - } -}; -/** -* Error type for invalid UR schemes. -* -* Message matches Rust bc-ur-rust/src/error.rs: `invalid UR scheme`. -*/ -var InvalidSchemeError = class extends URError { - constructor() { - super("invalid UR scheme"); - this.name = "InvalidSchemeError"; - } -}; -/** -* Error type for unspecified UR types. -* -* Message matches Rust bc-ur-rust/src/error.rs: `no UR type specified`. -*/ -var TypeUnspecifiedError = class extends URError { - constructor() { - super("no UR type specified"); - this.name = "TypeUnspecifiedError"; - } -}; -/** -* Error type for invalid UR types. -* -* Message matches Rust bc-ur-rust/src/error.rs: `invalid UR type`. -*/ -var InvalidTypeError = class extends URError { - constructor() { - super("invalid UR type"); - this.name = "InvalidTypeError"; - } -}; -/** -* Error type for non-single-part URs. -*/ -var NotSinglePartError = class extends URError { - constructor() { - super("UR is not a single-part"); - this.name = "NotSinglePartError"; - } -}; -/** -* Error type for unexpected UR types. -* -* Message matches Rust bc-ur-rust/src/error.rs: -* `expected UR type {expected}, but found {found}`. -*/ -var UnexpectedTypeError = class extends URError { - constructor(expected, found) { - super(`expected UR type ${expected}, but found ${found}`); - this.name = "UnexpectedTypeError"; - } -}; -/** -* Error type for Bytewords encoding/decoding errors. -* -* Message matches Rust bc-ur-rust/src/error.rs: `Bytewords error ({0})`. -*/ -var BytewordsError = class extends URError { - constructor(message) { - super(`Bytewords error (${message})`); - this.name = "BytewordsError"; - } -}; -/** -* Error type for CBOR encoding/decoding errors. -* -* Message matches Rust bc-ur-rust/src/error.rs: `CBOR error ({0})`. -*/ -var CBORError = class extends URError { - constructor(message) { - super(`CBOR error (${message})`); - this.name = "CBORError"; - } -}; -/** -* Error type for UR decoder errors. -* Matches Rust's Error::UR(String) variant. -*/ -var URDecodeError = class extends URError { - constructor(message) { - super(`UR decoder error (${message})`); - this.name = "URDecodeError"; - } -}; -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -*/ -/** -* Checks if a character is a valid UR type character. -* -* Mirrors Rust's `URTypeChar::is_ur_type` (`bc-ur-rust/src/utils.rs:6-19`): -* lowercase a-z, digits 0-9, and the hyphen `-`. -*/ -function isURTypeChar(char) { - const code = char.charCodeAt(0); - if (code >= 97 && code <= 122) return true; - if (code >= 48 && code <= 57) return true; - if (code === 45) return true; - return false; -} -/** -* Checks if a string is a valid UR type. -* -* Mirrors Rust's `URTypeString::is_ur_type` (`bc-ur-rust/src/utils.rs:26-32`) -* which is `self.chars().all(...)` — meaning **the empty string is accepted** -* (a vacuously-true `all` over no chars). We mirror that here so that -* `URType::new("")` succeeds in both ports; the round-trip then fails at -* decode-time with `TypeUnspecified`. -*/ -function isValidURType(urType) { - return Array.from(urType).every((char) => isURTypeChar(char)); -} -/** -* Bytewords for encoding/decoding bytes as words. -* See: https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2020-004-bytewords.md -*/ -const BYTEWORDS = [ - "able", - "acid", - "also", - "apex", - "aqua", - "arch", - "atom", - "aunt", - "away", - "axis", - "back", - "bald", - "barn", - "belt", - "beta", - "bias", - "blue", - "body", - "brag", - "brew", - "bulb", - "buzz", - "calm", - "cash", - "cats", - "chef", - "city", - "claw", - "code", - "cola", - "cook", - "cost", - "crux", - "curl", - "cusp", - "cyan", - "dark", - "data", - "days", - "deli", - "dice", - "diet", - "door", - "down", - "draw", - "drop", - "drum", - "dull", - "duty", - "each", - "easy", - "echo", - "edge", - "epic", - "even", - "exam", - "exit", - "eyes", - "fact", - "fair", - "fern", - "figs", - "film", - "fish", - "fizz", - "flap", - "flew", - "flux", - "foxy", - "free", - "frog", - "fuel", - "fund", - "gala", - "game", - "gear", - "gems", - "gift", - "girl", - "glow", - "good", - "gray", - "grim", - "guru", - "gush", - "gyro", - "half", - "hang", - "hard", - "hawk", - "heat", - "help", - "high", - "hill", - "holy", - "hope", - "horn", - "huts", - "iced", - "idea", - "idle", - "inch", - "inky", - "into", - "iris", - "iron", - "item", - "jade", - "jazz", - "join", - "jolt", - "jowl", - "judo", - "jugs", - "jump", - "junk", - "jury", - "keep", - "keno", - "kept", - "keys", - "kick", - "kiln", - "king", - "kite", - "kiwi", - "knob", - "lamb", - "lava", - "lazy", - "leaf", - "legs", - "liar", - "limp", - "lion", - "list", - "logo", - "loud", - "love", - "luau", - "luck", - "lung", - "main", - "many", - "math", - "maze", - "memo", - "menu", - "meow", - "mild", - "mint", - "miss", - "monk", - "nail", - "navy", - "need", - "news", - "next", - "noon", - "note", - "numb", - "obey", - "oboe", - "omit", - "onyx", - "open", - "oval", - "owls", - "paid", - "part", - "peck", - "play", - "plus", - "poem", - "pool", - "pose", - "puff", - "puma", - "purr", - "quad", - "quiz", - "race", - "ramp", - "real", - "redo", - "rich", - "road", - "rock", - "roof", - "ruby", - "ruin", - "runs", - "rust", - "safe", - "saga", - "scar", - "sets", - "silk", - "skew", - "slot", - "soap", - "solo", - "song", - "stub", - "surf", - "swan", - "taco", - "task", - "taxi", - "tent", - "tied", - "time", - "tiny", - "toil", - "tomb", - "toys", - "trip", - "tuna", - "twin", - "ugly", - "undo", - "unit", - "urge", - "user", - "vast", - "very", - "veto", - "vial", - "vibe", - "view", - "visa", - "void", - "vows", - "wall", - "wand", - "warm", - "wasp", - "wave", - "waxy", - "webs", - "what", - "when", - "whiz", - "wolf", - "work", - "yank", - "yawn", - "yell", - "yoga", - "yurt", - "zaps", - "zero", - "zest", - "zinc", - "zone", - "zoom" -]; -/** -* Create a reverse mapping for fast byteword lookup. -*/ -function createBytewordsMap() { - const map = /* @__PURE__ */ new Map(); - BYTEWORDS.forEach((word, index) => { - map.set(word, index); - }); - return map; -} -const BYTEWORDS_MAP = createBytewordsMap(); -/** -* Bytemojis for encoding/decoding bytes as emojis. -* See: https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2024-008-bytemoji.md -*/ -const BYTEMOJIS = [ - "😀", - "😂", - "😆", - "😉", - "🙄", - "😋", - "😎", - "😍", - "😘", - "😭", - "🫠", - "🥱", - "🤩", - "😶", - "🤨", - "🫥", - "🥵", - "🥶", - "😳", - "🤪", - "😵", - "😡", - "🤢", - "😇", - "🤠", - "🤡", - "🥳", - "🥺", - "😬", - "🤑", - "🙃", - "🤯", - "😈", - "👹", - "👺", - "💀", - "👻", - "👽", - "😺", - "😹", - "😻", - "😽", - "🙀", - "😿", - "🫶", - "🤲", - "🙌", - "🤝", - "👍", - "👎", - "👈", - "👆", - "💪", - "👄", - "🦷", - "👂", - "👃", - "🧠", - "👀", - "🤚", - "🦶", - "🍎", - "🍊", - "🍋", - "🍌", - "🍉", - "🍇", - "🍓", - "🫐", - "🍒", - "🍑", - "🍍", - "🥝", - "🍆", - "🥑", - "🥦", - "🍅", - "🌽", - "🥕", - "🫒", - "🧄", - "🥐", - "🥯", - "🍞", - "🧀", - "🥚", - "🍗", - "🌭", - "🍔", - "🍟", - "🍕", - "🌮", - "🥙", - "🍱", - "🍜", - "🍤", - "🍚", - "🥠", - "🍨", - "🍦", - "🎂", - "🪴", - "🌵", - "🌱", - "💐", - "🍁", - "🍄", - "🌹", - "🌺", - "🌼", - "🌻", - "🌸", - "💨", - "🌊", - "💧", - "💦", - "🌀", - "🌈", - "🌞", - "🌝", - "🌛", - "🌜", - "🌙", - "🌎", - "💫", - "⭐", - "🪐", - "🌐", - "💛", - "💔", - "💘", - "💖", - "💕", - "🏁", - "🚩", - "💬", - "💯", - "🚫", - "🔴", - "🔷", - "🟩", - "🛑", - "🔺", - "🚗", - "🚑", - "🚒", - "🚜", - "🛵", - "🚨", - "🚀", - "🚁", - "🛟", - "🚦", - "🏰", - "🎡", - "🎢", - "🎠", - "🏠", - "🔔", - "🔑", - "🚪", - "🪑", - "🎈", - "💌", - "📦", - "📫", - "📖", - "📚", - "📌", - "🧮", - "🔒", - "💎", - "📷", - "⏰", - "⏳", - "📡", - "💡", - "💰", - "🧲", - "🧸", - "🎁", - "🎀", - "🎉", - "🪭", - "👑", - "🫖", - "🔭", - "🛁", - "🏆", - "🥁", - "🎷", - "🎺", - "🏀", - "🏈", - "🎾", - "🏓", - "✨", - "🔥", - "💥", - "👕", - "👚", - "👖", - "🩳", - "👗", - "👔", - "🧢", - "👓", - "🧶", - "🧵", - "💍", - "👠", - "👟", - "🧦", - "🧤", - "👒", - "👜", - "🐱", - "🐶", - "🐭", - "🐹", - "🐰", - "🦊", - "🐻", - "🐼", - "🐨", - "🐯", - "🦁", - "🐮", - "🐷", - "🐸", - "🐵", - "🐔", - "🐥", - "🦆", - "🦉", - "🐴", - "🦄", - "🐝", - "🐛", - "🦋", - "🐌", - "🐞", - "🐢", - "🐺", - "🐍", - "🪽", - "🐙", - "🦑", - "🪼", - "🦞", - "🦀", - "🐚", - "🦭", - "🐟", - "🐬", - "🐳" -]; -/** -* Encodes an arbitrary byte slice as a string of space-separated bytewords. -* -* Mirrors `bytewords::encode_to_words` in `bc-ur-rust` (≥ v0.19.1). Does not -* add a CRC32 checksum — use {@link encodeBytewords} for UR-style encoding. -*/ -function encodeToWords(data) { - const words = []; - for (const byte of data) { - const word = BYTEWORDS[byte]; - if (word === void 0) throw new Error(`Invalid byte value: ${byte}`); - words.push(word); - } - return words.join(" "); -} -/** -* Encodes an arbitrary byte slice as a string of space-separated bytemojis. -* -* Mirrors `bytewords::encode_to_bytemojis` in `bc-ur-rust` (≥ v0.19.1). -*/ -function encodeToBytemojis(data) { - const emojis = []; - for (const byte of data) { - const emoji = BYTEMOJIS[byte]; - if (emoji === void 0) throw new Error(`Invalid byte value: ${byte}`); - emojis.push(emoji); - } - return emojis.join(" "); -} -/** -* Encodes an arbitrary byte slice as minimal bytewords (first + last letter of -* each word, concatenated with no separator). -* -* Mirrors `bytewords::encode_to_minimal_bytewords` in `bc-ur-rust` -* (≥ v0.19.1). Does not add a CRC32 checksum. -*/ -function encodeToMinimalBytewords(data) { - let out = ""; - for (const byte of data) { - const word = BYTEWORDS[byte]; - if (word === void 0) throw new Error(`Invalid byte value: ${byte}`); - out += word[0] + word[word.length - 1]; - } - return out; -} -/** -* Encodes a 4-byte slice as a string of bytewords for identification. -* -* Thin wrapper over {@link encodeToWords} that enforces the 4-byte length -* contract historically used by `bc-ur-rust`'s `bytewords::identifier`. -*/ -function encodeBytewordsIdentifier(data) { - if (data.length !== 4) throw new Error("Identifier data must be exactly 4 bytes"); - return encodeToWords(data); -} -/** -* Encodes a 4-byte slice as a string of bytemojis for identification. -* -* Thin wrapper over {@link encodeToBytemojis} that enforces the 4-byte length -* contract historically used by `bc-ur-rust`'s `bytewords::bytemoji_identifier`. -*/ -function encodeBytemojisIdentifier(data) { - if (data.length !== 4) throw new Error("Identifier data must be exactly 4 bytes"); - return encodeToBytemojis(data); -} -/** -* Bytewords encoding style. -*/ -let BytewordsStyle = /* @__PURE__ */ function(BytewordsStyle) { - /** Full 4-letter words separated by spaces */ - BytewordsStyle["Standard"] = "standard"; - /** Full 4-letter words separated by hyphens (URI-safe) */ - BytewordsStyle["Uri"] = "uri"; - /** First and last character only (minimal) - used by UR encoding */ - BytewordsStyle["Minimal"] = "minimal"; - return BytewordsStyle; -}({}); -/** -* Create a reverse mapping for minimal bytewords (first+last char) lookup. -*/ -function createMinimalBytewordsMap() { - const map = /* @__PURE__ */ new Map(); - BYTEWORDS.forEach((word, index) => { - const minimal = word[0] + word[3]; - map.set(minimal, index); - }); - return map; -} -const MINIMAL_BYTEWORDS_MAP = createMinimalBytewordsMap(); -new Set(BYTEMOJIS); -(() => { - const map = /* @__PURE__ */ new Map(); - for (const word of BYTEWORDS) map.set(word[0] + word[word.length - 1], word); - return map; -})(); -(() => { - const map = /* @__PURE__ */ new Map(); - for (const word of BYTEWORDS) map.set(word.slice(0, 3), word); - return map; -})(); -(() => { - const map = /* @__PURE__ */ new Map(); - for (const word of BYTEWORDS) map.set(word.slice(1), word); - return map; -})(); -/** -* CRC32 lookup table (IEEE polynomial). -*/ -const CRC32_TABLE = (() => { - const table = []; - for (let i = 0; i < 256; i++) { - let c = i; - for (let j = 0; j < 8; j++) c = (c & 1) !== 0 ? 3988292384 ^ c >>> 1 : c >>> 1; - table.push(c >>> 0); - } - return table; -})(); -/** -* Calculate CRC32 checksum of data. -*/ -function crc32(data) { - let crc = 4294967295; - for (const byte of data) crc = (CRC32_TABLE[(crc ^ byte) & 255] ^ crc >>> 8) >>> 0; - return (crc ^ 4294967295) >>> 0; -} -/** -* Convert a 32-bit number to 4 bytes (big-endian). -*/ -function uint32ToBytes(value) { - return new Uint8Array([ - value >>> 24 & 255, - value >>> 16 & 255, - value >>> 8 & 255, - value & 255 - ]); -} -/** -* Encode data as bytewords with the specified style. -* Includes CRC32 checksum. -*/ -function encodeBytewords(data, style = "minimal") { - const checksumBytes = uint32ToBytes(crc32(data)); - const dataWithChecksum = new Uint8Array(data.length + 4); - dataWithChecksum.set(data); - dataWithChecksum.set(checksumBytes, data.length); - const words = []; - for (const byte of dataWithChecksum) { - const word = BYTEWORDS[byte]; - if (word === void 0) throw new Error(`Invalid byte value: ${byte}`); - switch (style) { - case "standard": - words.push(word); - break; - case "uri": - words.push(word); - break; - case "minimal": words.push(word[0] + word[3]); - } - } - switch (style) { - case "standard": return words.join(" "); - case "uri": return words.join("-"); - case "minimal": return words.join(""); - } -} -/** -* Returns true if every code unit of `s` is in the ASCII range (0..=127). -* -* Mirrors Rust's `str::is_ascii` used at `ur::bytewords::decode` line 105. -* We test the raw code units (rather than Array.from + codepoint) because -* any non-BMP character has surrogate pairs both ≥ 0xD800, which already -* exceed 0x7F. -*/ -function isAsciiString(s) { - for (let i = 0; i < s.length; i++) if (s.charCodeAt(i) > 127) return false; - return true; -} -/** -* Decode bytewords string back to data. -* Validates and removes CRC32 checksum. -* -* Errors mirror the upstream Rust `ur::bytewords::Error` enum -* (`ur-0.4.1/src/bytewords.rs`): -* - `NonAscii` — input contains non-ASCII characters (checked first). -* - `InvalidLength` — minimal-style input has odd length. -* - `InvalidWord` — a token does not map to a byteword index. -* - `InvalidChecksum` — the trailing 4-byte CRC32 does not match. -* -* All variants are surfaced as {@link BytewordsError} with the same default -* `Display` strings as Rust (e.g. "invalid checksum", "non-ASCII"), so -* callers can branch on the error class rather than the bare `Error` -* thrown by earlier revisions of this port. -*/ -function decodeBytewords(encoded, style = "minimal") { - if (!isAsciiString(encoded)) throw new BytewordsError("bytewords string contains non-ASCII characters"); - const lowercased = encoded.toLowerCase(); - let bytes; - switch (style) { - case "standard": - bytes = lowercased.split(" ").map((word) => { - const index = BYTEWORDS_MAP.get(word); - if (index === void 0) throw new BytewordsError("invalid word"); - return index; - }); - break; - case "uri": - bytes = lowercased.split("-").map((word) => { - const index = BYTEWORDS_MAP.get(word); - if (index === void 0) throw new BytewordsError("invalid word"); - return index; - }); - break; - case "minimal": - if (lowercased.length % 2 !== 0) throw new BytewordsError("invalid length"); - bytes = []; - for (let i = 0; i < lowercased.length; i += 2) { - const minimal = lowercased.slice(i, i + 2); - const index = MINIMAL_BYTEWORDS_MAP.get(minimal); - if (index === void 0) throw new BytewordsError("invalid word"); - bytes.push(index); - } - } - if (bytes.length < 4) throw new BytewordsError("invalid checksum"); - const dataWithChecksum = new Uint8Array(bytes); - const data = dataWithChecksum.slice(0, -4); - const checksumBytes = dataWithChecksum.slice(-4); - if (crc32(data) !== (checksumBytes[0] << 24 | checksumBytes[1] << 16 | checksumBytes[2] << 8 | checksumBytes[3]) >>> 0) throw new BytewordsError("invalid checksum"); - return data; -} -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -*/ -/** -* Represents a UR (Uniform Resource) type identifier. -* -* Valid UR types contain only lowercase letters, digits, and hyphens. -* -* @example -* ```typescript -* const urType = new URType('test'); -* console.log(urType.string()); // "test" -* ``` -*/ -var URType = class URType { - _type; - /** - * Creates a new URType from the provided type string. - * - * @param urType - The UR type as a string - * @throws {InvalidTypeError} If the type contains invalid characters - * - * @example - * ```typescript - * const urType = new URType('test'); - * ``` - */ - constructor(urType) { - if (!isValidURType(urType)) throw new InvalidTypeError(); - this._type = urType; - } - /** - * Returns the string representation of the URType. - * - * @example - * ```typescript - * const urType = new URType('test'); - * console.log(urType.string()); // "test" - * ``` - */ - string() { - return this._type; - } - /** - * Checks equality with another URType based on the type string. - */ - equals(other) { - return this._type === other._type; - } - /** - * Returns the string representation. - */ - toString() { - return this._type; - } - /** - * Creates a URType from a string, throwing an error if invalid. - * - * @param value - The UR type string - * @returns A new URType instance - * @throws {InvalidTypeError} If the type is invalid - */ - static from(value) { - return new URType(value); - } - /** - * Safely creates a URType, returning a typed `Result`-shaped - * discriminated union instead of throwing. - * - * Mirrors Rust `impl TryFrom<&str> for URType` / - * `impl TryFrom for URType` (`bc-ur-rust/src/ur_type.rs`), - * which return `Result`. The TS shape is the - * idiomatic discriminated form so callers can branch on `ok` - * without `instanceof`: - * - * @example - * ```typescript - * const r = URType.tryFrom("test"); - * if (r.ok) { - * console.log(r.value.string()); // "test" - * } else { - * console.error(r.error.message); - * } - * ``` - * - * @param value - The UR type string - * @returns A typed Result: `{ ok: true; value: URType }` on success, - * `{ ok: false; error: InvalidTypeError }` on failure. - */ - static tryFrom(value) { - try { - return { - ok: true, - value: new URType(value) - }; - } catch (error) { - return { - ok: false, - error - }; - } - } -}; -/** -* A Uniform Resource (UR) is a URI-encoded CBOR object. -* -* URs are defined in [BCR-2020-005: Uniform Resources](https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2020-005-ur.md). -* -* @example -* ```typescript -* import { UR } from '@bcts/uniform-resources'; -* import { CBOR } from '@bcts/dcbor'; -* -* // Create a UR from a CBOR object -* const cbor = CBOR.fromArray([1, 2, 3]); -* const ur = UR.new('test', cbor); -* -* // Encode to string -* const urString = ur.string(); -* console.log(urString); // "ur:test/..." -* -* // Decode from string -* const decodedUR = UR.fromURString(urString); -* console.log(decodedUR.urTypeStr()); // "test" -* ``` -*/ -var UR = class UR { - _urType; - _cbor; - /** - * Creates a new UR from the provided type and CBOR data. - * - * @param urType - The UR type (will be validated) - * @param cbor - The CBOR data to encode - * @throws {InvalidTypeError} If the type is invalid - * - * @example - * ```typescript - * const ur = UR.new('bytes', CBOR.fromString('hello')); - * ``` - */ - static new(urType, cbor) { - const type = typeof urType === "string" ? new URType(urType) : urType; - return new UR(type, cbor); - } - /** - * Creates a new UR from a UR string. - * - * Mirrors Rust's `UR::from_ur_string` (`bc-ur-rust/src/ur.rs:25-38`): - * 1. lowercase the entire string. - * 2. strip the `"ur:"` prefix → {@link InvalidSchemeError} if absent. - * 3. split on the first `/` → {@link TypeUnspecifiedError} if absent. - * 4. validate the type via {@link URType} → {@link InvalidTypeError}. - * 5. delegate the data section to the upstream-style decoder, which - * classifies the UR as single- or multi-part. Multi-part input is - * rejected with {@link NotSinglePartError}. - * 6. decode the bytewords payload (CRC32 + minimal mapping) → - * {@link BytewordsError} on failure. - * 7. parse the resulting bytes as CBOR → {@link CBORError} on failure. - * - * @param urString - A UR string like "ur:test/..." - * @throws {InvalidSchemeError} If the string doesn't start with "ur:" - * @throws {TypeUnspecifiedError} If no `/` separator is present - * @throws {InvalidTypeError} If the type contains invalid characters - * @throws {NotSinglePartError} If the UR is multi-part - * @throws {URDecodeError} For upstream-decoder errors (invalid indices, etc.) - * @throws {BytewordsError} If bytewords decoding fails - * @throws {CBORError} If CBOR parsing fails - * - * @example - * ```typescript - * const ur = UR.fromURString('ur:test/lsadaoaxjygonesw'); - * ``` - */ - static fromURString(urString) { - const { urType, cbor } = URStringDecoder.decode(urString); - return new UR(urType, cbor); - } - constructor(urType, cbor) { - this._urType = urType; - this._cbor = cbor; - } - /** - * Returns the UR type. - */ - urType() { - return this._urType; - } - /** - * Returns the UR type as a string. - */ - urTypeStr() { - return this._urType.string(); - } - /** - * Returns the CBOR data. - */ - cbor() { - return this._cbor; - } - /** - * Returns the string representation of the UR (lowercase, suitable for display). - * - * @example - * ```typescript - * const ur = UR.new('test', CBOR.fromArray([1, 2, 3])); - * console.log(ur.string()); // "ur:test/lsadaoaxjygonesw" - * ``` - */ - string() { - const cborData = this._cbor.toData(); - return URStringEncoder.encode(this._urType.string(), cborData); - } - /** - * Returns the QR string representation (uppercase, most efficient for QR codes). - */ - qrString() { - return this.string().toUpperCase(); - } - /** - * Returns the QR data as bytes (uppercase UR string as UTF-8). - * - * Mirrors Rust's `UR::qr_data` (`ur.rs:52`) which does - * `self.qr_string().as_bytes().to_vec()` — the string's UTF-8 byte - * representation. We use `TextEncoder` rather than per-codepoint - * truncation so the behaviour stays correct if the QR string ever - * contains non-ASCII characters. - */ - qrData() { - return new TextEncoder().encode(this.qrString()); - } - /** - * Checks if the UR type matches the expected type. - * - * @param expectedType - The expected type - * @throws {UnexpectedTypeError} If the types don't match - */ - checkType(expectedType) { - const expected = typeof expectedType === "string" ? new URType(expectedType) : expectedType; - if (!this._urType.equals(expected)) throw new UnexpectedTypeError(expected.string(), this._urType.string()); - } - /** - * Returns the string representation. - */ - toString() { - return this.string(); - } - /** - * Checks equality with another UR. - * - * Mirrors Rust's derived `PartialEq for UR` which compares the inner - * `ur_type` and the inner `cbor` field directly. We compare CBOR - * bytewise — `Uint8Array` equality, not `Array#toString` (which would - * coerce to a comma-joined string and could collide on pathological - * inputs). - */ - equals(other) { - if (!this._urType.equals(other._urType)) return false; - const a = this._cbor.toData(); - const b = other._cbor.toData(); - if (a.length !== b.length) return false; - for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false; - return true; - } -}; -/** -* Encodes a UR string using Bytewords minimal encoding. -* This handles single-part URs according to BCR-2020-005. -*/ -var URStringEncoder = class { - static encode(urType, cborData) { - return `ur:${urType}/${encodeBytewords(cborData, "minimal")}`; - } -}; -/** -* Decodes a UR string back to its components. -* -* Mirrors the validation pipeline of Rust's `UR::from_ur_string` -* (`bc-ur-rust/src/ur.rs:25-38`) plus the upstream `ur::decode` -* (`ur-0.4.1/src/ur.rs:238-266`): -* -* 1. lowercase -* 2. strip `"ur:"` → {@link InvalidSchemeError} -* 3. find `/` → {@link TypeUnspecifiedError} -* 4. validate the type → {@link InvalidTypeError} -* 5. classify single- vs multi-part by looking at the data section -* 6. multi-part → {@link NotSinglePartError} -* 7. invalid multi-part indices → {@link URDecodeError("Invalid indices")} -* 8. minimal bytewords decode → {@link BytewordsError} -* 9. CBOR parse → {@link CBORError} -*/ -var URStringDecoder = class { - static decode(urString) { - const lowercased = urString.toLowerCase(); - if (!lowercased.startsWith("ur:")) throw new InvalidSchemeError(); - const afterScheme = lowercased.substring(3); - const slashIdx = afterScheme.indexOf("/"); - if (slashIdx === -1) throw new TypeUnspecifiedError(); - const typeStr = afterScheme.substring(0, slashIdx); - const dataSection = afterScheme.substring(slashIdx + 1); - const urType = new URType(typeStr); - const lastSlash = dataSection.lastIndexOf("/"); - if (lastSlash !== -1) { - const indices = dataSection.substring(0, lastSlash); - const dashIdx = indices.indexOf("-"); - if (dashIdx === -1) throw new URDecodeError("Invalid indices"); - const seqNumStr = indices.substring(0, dashIdx); - const seqLenStr = indices.substring(dashIdx + 1); - if (!/^\d+$/.test(seqNumStr) || !/^\d+$/.test(seqLenStr)) throw new URDecodeError("Invalid indices"); - const seqNum = Number(seqNumStr); - const seqLen = Number(seqLenStr); - if (seqNum > 65535 || seqLen > 65535) throw new URDecodeError("Invalid indices"); - throw new NotSinglePartError(); - } - let cborData; - try { - cborData = decodeBytewords(dataSection, "minimal"); - } catch (error) { - if (error instanceof BytewordsError) throw error; - throw new BytewordsError(error instanceof Error ? error.message : String(error)); - } - let cbor; - try { - cbor = decodeCbor(cborData); - } catch (error) { - if (error instanceof CBORError) throw error; - throw new CBORError(error instanceof Error ? error.message : String(error)); - } - return { - urType, - cbor - }; - } -}; -//#endregion -//#region tests/baseline/node_modules/@noble/hashes/sha3.js -/** -* SHA3 (keccak) hash function, based on a new "Sponge function" design. -* Different from older hashes, the internal state is bigger than output size. -* -* Check out -* {@link https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf | FIPS-202}, -* {@link https://keccak.team/keccak.html | Website}, and -* {@link https://crypto.stackexchange.com/q/15727 | the differences between -* SHA-3 and Keccak}. -* -* Check out `sha3-addons` module for cSHAKE, k12, and others. -* @module -*/ -const _0n$2 = BigInt(0); -const _1n$1 = BigInt(1); -const _2n$1 = BigInt(2); -const _7n$1 = BigInt(7); -const _256n$1 = BigInt(256); -const _0x71n$1 = BigInt(113); -const SHA3_PI$1 = []; -const SHA3_ROTL$1 = []; -const _SHA3_IOTA$1 = []; -for (let round = 0, R = _1n$1, x = 1, y = 0; round < 24; round++) { - [x, y] = [y, (2 * x + 3 * y) % 5]; - SHA3_PI$1.push(2 * (5 * y + x)); - SHA3_ROTL$1.push((round + 1) * (round + 2) / 2 % 64); - let t = _0n$2; - for (let j = 0; j < 7; j++) { - R = (R << _1n$1 ^ (R >> _7n$1) * _0x71n$1) % _256n$1; - if (R & _2n$1) t ^= _1n$1 << (_1n$1 << BigInt(j)) - _1n$1; - } - _SHA3_IOTA$1.push(t); -} -const IOTAS$1 = split$1(_SHA3_IOTA$1, true); -const SHA3_IOTA_H$1 = IOTAS$1[0]; -const SHA3_IOTA_L$1 = IOTAS$1[1]; -const rotlSH$1 = (h, l, s) => h << s | l >>> 32 - s; -const rotlSL$1 = (h, l, s) => l << s | h >>> 32 - s; -const rotlBH$1 = (h, l, s) => l << s - 32 | h >>> 64 - s; -const rotlBL$1 = (h, l, s) => h << s - 32 | l >>> 64 - s; -const rotlH$1 = (h, l, s) => s > 32 ? rotlBH$1(h, l, s) : rotlSH$1(h, l, s); -const rotlL$1 = (h, l, s) => s > 32 ? rotlBL$1(h, l, s) : rotlSL$1(h, l, s); -const B = /* @__PURE__ */ new Uint32Array(10); -/** -* `keccakf1600` internal permutation, additionally allows adjusting the round count. -* @param s - 5x5 Keccak state encoded as 25 lanes split into 50 uint32 words -* in this file's local little-endian lane-word order -* @param rounds - number of rounds to execute -* @throws On wrong argument types. {@link TypeError} -* @throws On wrong argument ranges or values. {@link RangeError} -* @throws If `rounds` is outside the supported `1..24` range. {@link Error} -* @example -* Permute a Keccak state with the default 24 rounds. -* ```ts -* keccakP(new Uint32Array(50)); -* ``` -*/ -function keccakP$1(s, rounds = 24) { - if (!(s instanceof Uint32Array)) throw new TypeError("\"s\" expected Uint32Array(50), got type=" + typeof s); - if (s.length !== 50) throw new RangeError("\"s\" expected Uint32Array(50), got length=" + s.length); - anumber$4(rounds, "rounds"); - if (rounds < 1 || rounds > 24) throw new Error("\"rounds\" expected integer 1..24"); - for (let round = 24 - rounds; round < 24; round++) { - for (let x = 0; x < 10; x++) B[x] = s[x] ^ s[x + 10] ^ s[x + 20] ^ s[x + 30] ^ s[x + 40]; - for (let x = 0; x < 10; x += 2) { - const idx1 = (x + 8) % 10; - const idx0 = (x + 2) % 10; - const B0 = B[idx0]; - const B1 = B[idx0 + 1]; - const Th = rotlH$1(B0, B1, 1) ^ B[idx1]; - const Tl = rotlL$1(B0, B1, 1) ^ B[idx1 + 1]; - for (let y = 0; y < 50; y += 10) { - s[x + y] ^= Th; - s[x + y + 1] ^= Tl; - } - } - let curH = s[2]; - let curL = s[3]; - for (let t = 0; t < 24; t++) { - const shift = SHA3_ROTL$1[t]; - const Th = rotlH$1(curH, curL, shift); - const Tl = rotlL$1(curH, curL, shift); - const PI = SHA3_PI$1[t]; - curH = s[PI]; - curL = s[PI + 1]; - s[PI] = Th; - s[PI + 1] = Tl; - } - for (let y = 0; y < 50; y += 10) { - const b0 = s[y], b1 = s[y + 1], b2 = s[y + 2], b3 = s[y + 3]; - s[y] ^= ~s[y + 2] & s[y + 4]; - s[y + 1] ^= ~s[y + 3] & s[y + 5]; - s[y + 2] ^= ~s[y + 4] & s[y + 6]; - s[y + 3] ^= ~s[y + 5] & s[y + 7]; - s[y + 4] ^= ~s[y + 6] & s[y + 8]; - s[y + 5] ^= ~s[y + 7] & s[y + 9]; - s[y + 6] ^= ~s[y + 8] & b0; - s[y + 7] ^= ~s[y + 9] & b1; - s[y + 8] ^= ~b0 & b2; - s[y + 9] ^= ~b1 & b3; - } - s[0] ^= SHA3_IOTA_H$1[round]; - s[1] ^= SHA3_IOTA_L$1[round]; - } - clean$2(B); -} -//#endregion -//#region tests/baseline/node_modules/@scure/sr25519/index.js -/** -* Minimal JS implementation of sr25519 cryptography for Polkadot. -* -* Uses [Merlin](https://merlin.cool/index.html), -* a transcript construction, built on [Strobe](https://strobe.sourceforge.io). -* Merlin ensures two parties agree on the same state when communicating. -* -* More: https://wiki.polkadot.network/docs/learn-cryptography. -*/ -const _0n$1 = /* @__PURE__ */ BigInt(0); -const _3n = /* @__PURE__ */ BigInt(3); -const RistrettoPoint = /* @__PURE__ */ (() => ristretto255.Point)(); -function toData(d) { - if (typeof d === "string") return utf8ToBytes(d); - if (isBytes$2(d)) return d; - throw new TypeError("Wrong data"); -} -function abytes$2(title, b, ...lengths) { - if (!isBytes$2(b)) throw new TypeError(`${title}: Uint8Array expected`); - if (lengths.length && !lengths.includes(b.length)) throw new RangeError(`${title}: Uint8Array expected of length ${lengths}, not of length=${b.length}`); -} -function checkU32$1(title, n) { - if (typeof n !== "number") throw new TypeError(`${title}: wrong u32 integer: ${n}`); - if (!Number.isSafeInteger(n) || n < 0 || n > 4294967295) throw new RangeError(`${title}: wrong u32 integer: ${n}`); - return n; -} -function cleanBytes$1(...list) { - for (const t of list) t.fill(0); -} -const CURVE_ORDER = /* @__PURE__ */ (() => ed25519.Point.Fn.ORDER)(); -const modN = (n) => mod(n, CURVE_ORDER); -const STROBE_R = 166; -const Flags = /* @__PURE__ */ (() => ({ - I: 1, - A: 2, - C: 4, - T: 8, - M: 16, - K: 32 -}))(); -var Strobe128 = class Strobe128 { - state = /* @__PURE__ */ new Uint8Array(200); - state32; - pos = 0; - posBegin = 0; - curFlags = 0; - constructor(protocolLabel) { - this.state.set([ - 1, - 168, - 1, - 0, - 1, - 96 - ], 0); - this.state.set(utf8ToBytes("STROBEv1.0.2"), 6); - this.state32 = u32$2(this.state); - this.keccakF1600(); - this.metaAD(protocolLabel, false); - } - keccakF1600() { - keccakP$1(this.state32); - } - runF() { - this.state[this.pos] ^= this.posBegin; - this.state[this.pos + 1] ^= 4; - this.state[167] ^= 128; - this.keccakF1600(); - this.pos = 0; - this.posBegin = 0; - } - absorb(data) { - for (let i = 0; i < data.length; i++) { - this.state[this.pos++] ^= data[i]; - if (this.pos === STROBE_R) this.runF(); - } - } - squeeze(len) { - const data = new Uint8Array(len); - for (let i = 0; i < data.length; i++) { - data[i] = this.state[this.pos]; - this.state[this.pos++] = 0; - if (this.pos === STROBE_R) this.runF(); - } - return data; - } - overwrite(data) { - for (let i = 0; i < data.length; i++) { - this.state[this.pos++] = data[i]; - if (this.pos === STROBE_R) this.runF(); - } - } - beginOp(flags, more) { - if (more) { - if (this.curFlags !== flags) throw new Error(`Continued op with changed flags from ${this.curFlags.toString(2)} to ${flags.toString(2)}`); - return; - } - if ((flags & Flags.T) !== 0) throw new Error("T flag is not supported"); - const oldBegin = this.posBegin; - this.posBegin = this.pos + 1; - this.curFlags = flags; - this.absorb(new Uint8Array([oldBegin, flags])); - if ((flags & (Flags.C | Flags.K)) !== 0 && this.pos !== 0) this.runF(); - } - metaAD(data, more) { - this.beginOp(Flags.M | Flags.A, more); - this.absorb(toData(data)); - } - AD(data, more) { - this.beginOp(Flags.A, more); - this.absorb(toData(data)); - } - PRF(len, more) { - this.beginOp(Flags.I | Flags.A | Flags.C, more); - return this.squeeze(len); - } - KEY(data, more) { - this.beginOp(Flags.A | Flags.C, more); - this.overwrite(toData(data)); - } - clone() { - const n = new Strobe128("0"); - n.pos = this.pos; - n.posBegin = this.posBegin; - n.state.set(this.state); - n.curFlags = this.curFlags; - return n; - } - clean() { - this.state.fill(0); - this.pos = 0; - this.curFlags = 0; - this.posBegin = 0; - } -}; -var Merlin = class { - strobe; - constructor(label) { - this.strobe = new Strobe128("Merlin v1.0"); - this.appendMessage("dom-sep", label); - } - appendMessage(label, message) { - this.strobe.metaAD(label, false); - checkU32$1("Merlin.appendMessage", message.length); - this.strobe.metaAD(numberToBytesLE(message.length, 4), true); - this.strobe.AD(message, false); - } - challengeBytes(label, len) { - this.strobe.metaAD(label, false); - checkU32$1("Merlin.challengeBytes", len); - this.strobe.metaAD(numberToBytesLE(len, 4), true); - return this.strobe.PRF(len, false); - } - clean() { - this.strobe.clean(); - } -}; -var SigningContext = class extends Merlin { - constructor(name) { - super(name); - } - label(label) { - this.appendMessage("", label); - } - bytes(bytes) { - this.appendMessage("sign-bytes", bytes); - return this; - } - protoName(label) { - this.appendMessage("proto-name", label); - } - commitPoint(label, point) { - this.appendMessage(label, point.toBytes()); - } - challengeScalar(label) { - return modN(bytesToNumberLE(this.challengeBytes(label, 64))); - } - witnessScalar(label, random, nonceSeeds = []) { - return modN(bytesToNumberLE(this.witnessBytes(label, 64, random, nonceSeeds))); - } - witnessBytes(label, len, random, nonceSeeds = []) { - checkU32$1("SigningContext.witnessBytes", len); - const strobeRng = this.strobe.clone(); - for (const ns of nonceSeeds) { - strobeRng.metaAD(label, false); - checkU32$1("SigningContext.witnessBytes nonce length", ns.length); - strobeRng.metaAD(numberToBytesLE(ns.length, 4), true); - strobeRng.KEY(ns, false); - } - abytes$2("random", random, 32); - strobeRng.metaAD("rng", false); - strobeRng.KEY(random, false); - strobeRng.metaAD(numberToBytesLE(len, 4), false); - return strobeRng.PRF(len, false); - } -}; -const MASK = /* @__PURE__ */ bitMask(256); -const encodeScalar = (n) => numberToBytesLE(n << _3n & MASK, 32); -const decodeScalar = (n) => bytesToNumberLE(n) >> _3n; -/** -* Derives the public key for an sr25519 secret key. -* @param secretKey - 64-byte secret key returned by `secretFromSeed()` -* @returns 32-byte sr25519 public key -* @throws On wrong argument types. {@link TypeError} -* @throws On wrong argument lengths. {@link RangeError} -* @example -* Derive the public key bytes for a freshly expanded sr25519 secret key. -* ```ts -* import { getPublicKey, secretFromSeed } from '@scure/sr25519'; -* import { randomBytes } from '@noble/hashes/utils.js'; -* const secretKey = secretFromSeed(randomBytes(32)); -* getPublicKey(secretKey); -* ``` -*/ -function getPublicKey(secretKey) { - abytes$2("secretKey", secretKey, 64); - const scalar = decodeScalar(secretKey.subarray(0, 32)); - return RistrettoPoint.BASE.multiply(scalar).toBytes(); -} -/** -* Expands a 32-byte seed into a 64-byte sr25519 secret key. -* @param seed - 32-byte seed -* @returns 64-byte secret key -* @throws On wrong argument types. {@link TypeError} -* @throws On wrong argument lengths. {@link RangeError} -* @example -* Turn seed material into the sr25519 secret-key format used by the rest of the API. -* ```ts -* import { secretFromSeed } from '@scure/sr25519'; -* import { randomBytes } from '@noble/hashes/utils.js'; -* secretFromSeed(randomBytes(32)); -* ``` -*/ -function secretFromSeed(seed) { - abytes$2("seed", seed, 32); - const r = sha512$1(seed); - r[0] &= 248; - r[31] &= 63; - r[31] |= 64; - const key = encodeScalar(decodeScalar(r.subarray(0, 32))); - const nonce = r.subarray(32, 64); - const res = concatBytes$3(key, nonce); - cleanBytes$1(key, nonce, r); - return res; -} -const SUBSTRATE_CONTEXT = /* @__PURE__ */ utf8ToBytes("substrate"); -/** -* Signs a message with sr25519. -* @param secretKey - 64-byte secret key returned by `secretFromSeed()` -* @param message - message bytes to sign -* @param random - optional 32-byte nonce seed -* @returns 64-byte signature -* @throws On malformed sr25519 key or point data during signing. {@link Error} -* @throws On wrong argument types. {@link TypeError} -* @throws On wrong argument lengths. {@link RangeError} -* @example -* Sign a message with sr25519, using built-in nonce generation. -* ```ts -* import { secretFromSeed, sign } from '@scure/sr25519'; -* import { randomBytes } from '@noble/hashes/utils.js'; -* const secretKey = secretFromSeed(randomBytes(32)); -* sign(secretKey, new Uint8Array([1, 2, 3])); -* ``` -*/ -function sign(secretKey, message, random = randomBytes$3(32)) { - abytes$2("message", message); - abytes$2("secretKey", secretKey, 64); - const t = new SigningContext("SigningContext"); - t.label(SUBSTRATE_CONTEXT); - t.bytes(message); - const keyScalar = decodeScalar(secretKey.subarray(0, 32)); - const nonce = secretKey.subarray(32, 64); - const pubPoint = RistrettoPoint.fromBytes(getPublicKey(secretKey)); - t.protoName("Schnorr-sig"); - t.commitPoint("sign:pk", pubPoint); - const r = t.witnessScalar("signing", random, [nonce]); - const R = RistrettoPoint.BASE.multiply(r); - t.commitPoint("sign:R", R); - const k = t.challengeScalar("sign:c"); - const s = modN(k * keyScalar + r); - const res = concatBytes$3(R.toBytes(), numberToBytesLE(s, 32)); - res[63] |= 128; - t.clean(); - return res; -} -/** -* Verifies an sr25519 signature. -* @param message - message bytes that were signed -* @param signature - 64-byte signature returned by `sign()` -* @param publicKey - 32-byte public key returned by `getPublicKey()` -* @returns `true` when the signature is valid -* @throws If the signature marker or decoded sr25519 point data is invalid. {@link Error} -* @throws On wrong argument types. {@link TypeError} -* @throws On wrong argument lengths. {@link RangeError} -* @example -* Verify the signature against the same message and derived public key. -* ```ts -* import { getPublicKey, secretFromSeed, sign, verify } from '@scure/sr25519'; -* import { randomBytes } from '@noble/hashes/utils.js'; -* const secretKey = secretFromSeed(randomBytes(32)); -* const message = new Uint8Array([1, 2, 3]); -* const signature = sign(secretKey, message); -* verify(message, signature, getPublicKey(secretKey)); -* ``` -*/ -function verify(message, signature, publicKey) { - abytes$2("message", message); - abytes$2("signature", signature, 64); - abytes$2("publicKey", publicKey, 32); - if ((signature[63] & 128) === 0) throw new Error("Schnorrkel marker missing"); - const sBytes = Uint8Array.from(signature.subarray(32, 64)); - sBytes[31] &= 127; - const R = RistrettoPoint.fromBytes(signature.subarray(0, 32)); - const s = bytesToNumberLE(sBytes); - aInRange("s", s, _0n$1, CURVE_ORDER); - const t = new SigningContext("SigningContext"); - t.label(SUBSTRATE_CONTEXT); - t.bytes(message); - const pubPoint = RistrettoPoint.fromBytes(publicKey); - if (pubPoint.equals(RistrettoPoint.ZERO)) return false; - t.protoName("Schnorr-sig"); - t.commitPoint("sign:pk", pubPoint); - t.commitPoint("sign:R", R); - const k = t.challengeScalar("sign:c"); - const sP = RistrettoPoint.BASE.multiply(s); - const RR = pubPoint.negate().multiply(k).add(sP); - t.clean(); - cleanBytes$1(sBytes); - return RR.equals(R); -} -//#endregion -//#region tests/baseline/node_modules/@noble/post-quantum/node_modules/@noble/hashes/utils.js -/** -* Checks if something is Uint8Array. Be careful: nodejs Buffer will return true. -* @param a - value to test -* @returns `true` when the value is a Uint8Array-compatible view. -* @example -* Check whether a value is a Uint8Array-compatible view. -* ```ts -* isBytes(new Uint8Array([1, 2, 3])); -* ``` -*/ -function isBytes$1(a) { - return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array" && "BYTES_PER_ELEMENT" in a && a.BYTES_PER_ELEMENT === 1; -} -/** -* Asserts something is a non-negative integer. -* @param n - number to validate -* @param title - label included in thrown errors -* @throws On wrong argument types. {@link TypeError} -* @throws On wrong argument ranges or values. {@link RangeError} -* @example -* Validate a non-negative integer option. -* ```ts -* anumber(32, 'length'); -* ``` -*/ -function anumber$1(n, title = "") { - if (typeof n !== "number") { - const prefix = title && `"${title}" `; - throw new TypeError(`${prefix}expected number, got ${typeof n}`); - } - if (!Number.isSafeInteger(n) || n < 0) { - const prefix = title && `"${title}" `; - throw new RangeError(`${prefix}expected integer >= 0, got ${n}`); - } -} -/** -* Asserts something is Uint8Array. -* @param value - value to validate -* @param length - optional exact length constraint -* @param title - label included in thrown errors -* @returns The validated byte array. -* @throws On wrong argument types. {@link TypeError} -* @throws On wrong argument ranges or values. {@link RangeError} -* @example -* Validate that a value is a byte array. -* ```ts -* abytes(new Uint8Array([1, 2, 3])); -* ``` -*/ -function abytes$1(value, length, title = "") { - const bytes = isBytes$1(value); - const len = value?.length; - const needsLen = length !== void 0; - if (!bytes || needsLen && len !== length) { - const prefix = title && `"${title}" `; - const ofLen = needsLen ? ` of length ${length}` : ""; - const got = bytes ? `length=${len}` : `type=${typeof value}`; - const message = prefix + "expected Uint8Array" + ofLen + ", got " + got; - if (!bytes) throw new TypeError(message); - throw new RangeError(message); - } - return value; -} -/** -* Asserts a hash instance has not been destroyed or finished. -* @param instance - hash instance to validate -* @param checkFinished - whether to reject finalized instances -* @throws If the hash instance has already been destroyed or finalized. {@link Error} -* @example -* Validate that a hash instance is still usable. -* ```ts -* import { aexists } from '@noble/hashes/utils.js'; -* import { sha256 } from '@noble/hashes/sha2.js'; -* const hash = sha256.create(); -* aexists(hash); -* ``` -*/ -function aexists(instance, checkFinished = true) { - if (instance.destroyed) throw new Error("Hash instance has been destroyed"); - if (checkFinished && instance.finished) throw new Error("Hash#digest() has already been called"); -} -/** -* Asserts output is a sufficiently-sized byte array. -* @param out - destination buffer -* @param instance - hash instance providing output length -* Oversized buffers are allowed; downstream code only promises to fill the first `outputLen` bytes. -* @throws On wrong argument types. {@link TypeError} -* @throws On wrong argument ranges or values. {@link RangeError} -* @example -* Validate a caller-provided digest buffer. -* ```ts -* import { aoutput } from '@noble/hashes/utils.js'; -* import { sha256 } from '@noble/hashes/sha2.js'; -* const hash = sha256.create(); -* aoutput(new Uint8Array(hash.outputLen), hash); -* ``` -*/ -function aoutput(out, instance) { - abytes$1(out, void 0, "digestInto() output"); - const min = instance.outputLen; - if (out.length < min) throw new RangeError("\"digestInto() output\" expected to be of length >=" + min); -} -/** -* Casts a typed array view to Uint32Array. -* `arr.byteOffset` must already be 4-byte aligned or the platform -* Uint32Array constructor will throw. -* @param arr - source typed array -* @returns Uint32Array view over the same buffer. -* @example -* Reinterpret a byte array as 32-bit words. -* ```ts -* u32(new Uint8Array(8)); -* ``` -*/ -function u32(arr) { - return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4)); -} -/** -* Zeroizes typed arrays in place. Warning: JS provides no guarantees. -* @param arrays - arrays to overwrite with zeros -* @example -* Zeroize sensitive buffers in place. -* ```ts -* clean(new Uint8Array([1, 2, 3])); -* ``` -*/ -function clean(...arrays) { - for (let i = 0; i < arrays.length; i++) arrays[i].fill(0); -} -/** Whether the current platform is little-endian. */ -const isLE = /* @__PURE__ */ (() => new Uint8Array(new Uint32Array([287454020]).buffer)[0] === 68)(); -/** -* Byte-swap operation for uint32 values. -* @param word - source word -* @returns Word with reversed byte order. -* @example -* Reverse the byte order of a 32-bit word. -* ```ts -* byteSwap(0x11223344); -* ``` -*/ -function byteSwap(word) { - return word << 24 & 4278190080 | word << 8 & 16711680 | word >>> 8 & 65280 | word >>> 24 & 255; -} -/** -* Byte-swaps every word of a Uint32Array in place. -* @param arr - array to mutate -* @returns The same array after mutation; callers pass live state arrays here. -* @example -* Reverse the byte order of every word in place. -* ```ts -* byteSwap32(new Uint32Array([0x11223344])); -* ``` -*/ -function byteSwap32(arr) { - for (let i = 0; i < arr.length; i++) arr[i] = byteSwap(arr[i]); - return arr; -} -/** -* Conditionally byte-swaps a Uint32Array on big-endian platforms. -* @param u - array to normalize for host endianness -* @returns Original or byte-swapped array depending on platform endianness. -* On big-endian runtimes this mutates `u` in place via `byteSwap32(...)`. -* @example -* Normalize a word array for host endianness. -* ```ts -* swap32IfBE(new Uint32Array([0x11223344])); -* ``` -*/ -const swap32IfBE = isLE ? (u) => u : byteSwap32; -/** -* Copies several Uint8Arrays into one. -* @param arrays - arrays to concatenate -* @returns Concatenated byte array. -* @throws On wrong argument types. {@link TypeError} -* @example -* Concatenate multiple byte arrays. -* ```ts -* concatBytes(new Uint8Array([1]), new Uint8Array([2])); -* ``` -*/ -function concatBytes$1(...arrays) { - let sum = 0; - for (let i = 0; i < arrays.length; i++) { - const a = arrays[i]; - abytes$1(a); - sum += a.length; - } - const res = new Uint8Array(sum); - for (let i = 0, pad = 0; i < arrays.length; i++) { - const a = arrays[i]; - res.set(a, pad); - pad += a.length; - } - return res; -} -/** -* Creates a callable hash function from a stateful class constructor. -* @param hashCons - hash constructor or factory -* @param info - optional metadata such as DER OID -* @returns Frozen callable hash wrapper with `.create()`. -* Wrapper construction eagerly calls `hashCons(undefined)` once to read -* `outputLen` / `blockLen`, so constructor side effects happen at module -* init time. -* @example -* Wrap a stateful hash constructor into a callable helper. -* ```ts -* import { createHasher } from '@noble/hashes/utils.js'; -* import { sha256 } from '@noble/hashes/sha2.js'; -* const wrapped = createHasher(sha256.create, { oid: sha256.oid }); -* wrapped(new Uint8Array([1])); -* ``` -*/ -function createHasher(hashCons, info = {}) { - const hashC = (msg, opts) => hashCons(opts).update(msg).digest(); - const tmp = hashCons(void 0); - hashC.outputLen = tmp.outputLen; - hashC.blockLen = tmp.blockLen; - hashC.canXOF = tmp.canXOF; - hashC.create = (opts) => hashCons(opts); - Object.assign(hashC, info); - return Object.freeze(hashC); -} -/** -* Cryptographically secure PRNG backed by `crypto.getRandomValues`. -* @param bytesLength - number of random bytes to generate -* @returns Random bytes. -* The platform `getRandomValues()` implementation still defines any -* single-call length cap, and this helper rejects oversize requests -* with a stable library `RangeError` instead of host-specific errors. -* @throws On wrong argument types. {@link TypeError} -* @throws On wrong argument ranges or values. {@link RangeError} -* @throws If the current runtime does not provide `crypto.getRandomValues`. {@link Error} -* @example -* Generate a fresh random key or nonce. -* ```ts -* const key = randomBytes(16); -* ``` -*/ -function randomBytes$1(bytesLength = 32) { - anumber$1(bytesLength, "bytesLength"); - const cr = typeof globalThis === "object" ? globalThis.crypto : null; - if (typeof cr?.getRandomValues !== "function") throw new Error("crypto.getRandomValues must be defined"); - if (bytesLength > 65536) throw new RangeError(`"bytesLength" expected <= 65536, got ${bytesLength}`); - return cr.getRandomValues(new Uint8Array(bytesLength)); -} -/** -* Creates OID metadata for NIST hashes with prefix `06 09 60 86 48 01 65 03 04 02`. -* @param suffix - final OID byte for the selected hash. -* The helper accepts any byte even though only the documented NIST hash -* suffixes are meaningful downstream. -* @returns Object containing the DER-encoded OID. -* @example -* Build OID metadata for a NIST hash. -* ```ts -* oidNist(0x01); -* ``` -*/ -const oidNist = (suffix) => ({ oid: Uint8Array.from([ - 6, - 9, - 96, - 134, - 72, - 1, - 101, - 3, - 4, - 2, - suffix -]) }); -//#endregion -//#region tests/baseline/node_modules/@noble/post-quantum/node_modules/@noble/curves/utils.js -/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ -/** -* Validates that a flag is boolean. -* @param value - Value to validate. -* @param title - Optional field name. -* @returns Original value. -* @throws On wrong argument types. {@link TypeError} -* @example -* Reject non-boolean option flags early. -* -* ```ts -* abool(true); -* ``` -*/ -function abool(value, title = "") { - if (typeof value !== "boolean") { - const prefix = title && `"${title}" `; - throw new TypeError(prefix + "expected boolean, got type=" + typeof value); - } - return value; -} -//#endregion -//#region tests/baseline/node_modules/@noble/post-quantum/node_modules/@noble/hashes/_u64.js -const U32_MASK64 = /* @__PURE__ */ BigInt(2 ** 32 - 1); -const _32n = /* @__PURE__ */ BigInt(32); -function fromBig(n, le = false) { - if (le) return { - h: Number(n & U32_MASK64), - l: Number(n >> _32n & U32_MASK64) - }; - return { - h: Number(n >> _32n & U32_MASK64) | 0, - l: Number(n & U32_MASK64) | 0 - }; -} -function split(lst, le = false) { - const len = lst.length; - let Ah = new Uint32Array(len); - let Al = new Uint32Array(len); - for (let i = 0; i < len; i++) { - const { h, l } = fromBig(lst[i], le); - [Ah[i], Al[i]] = [h, l]; - } - return [Ah, Al]; -} -const rotlSH = (h, l, s) => h << s | l >>> 32 - s; -const rotlSL = (h, l, s) => l << s | h >>> 32 - s; -const rotlBH = (h, l, s) => l << s - 32 | h >>> 64 - s; -const rotlBL = (h, l, s) => h << s - 32 | l >>> 64 - s; -//#endregion -//#region tests/baseline/node_modules/@noble/post-quantum/node_modules/@noble/hashes/sha3.js -/** -* SHA3 (keccak) hash function, based on a new "Sponge function" design. -* Different from older hashes, the internal state is bigger than output size. -* -* Check out -* {@link https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf | FIPS-202}, -* {@link https://keccak.team/keccak.html | Website}, and -* {@link https://crypto.stackexchange.com/q/15727 | the differences between -* SHA-3 and Keccak}. -* -* Check out `sha3-addons` module for cSHAKE, k12, and others. -* @module -*/ -const _0n = BigInt(0); -const _1n = BigInt(1); -const _2n = BigInt(2); -const _7n = BigInt(7); -const _256n = BigInt(256); -const _0x71n = BigInt(113); -const SHA3_PI = []; -const SHA3_ROTL = []; -const _SHA3_IOTA = []; -for (let round = 0, R = _1n, x = 1, y = 0; round < 24; round++) { - [x, y] = [y, (2 * x + 3 * y) % 5]; - SHA3_PI.push(2 * (5 * y + x)); - SHA3_ROTL.push((round + 1) * (round + 2) / 2 % 64); - let t = _0n; - for (let j = 0; j < 7; j++) { - R = (R << _1n ^ (R >> _7n) * _0x71n) % _256n; - if (R & _2n) t ^= _1n << (_1n << BigInt(j)) - _1n; - } - _SHA3_IOTA.push(t); -} -const IOTAS = split(_SHA3_IOTA, true); -const SHA3_IOTA_H = IOTAS[0]; -const SHA3_IOTA_L = IOTAS[1]; -const rotlH = (h, l, s) => s > 32 ? rotlBH(h, l, s) : rotlSH(h, l, s); -const rotlL = (h, l, s) => s > 32 ? rotlBL(h, l, s) : rotlSL(h, l, s); -/** -* `keccakf1600` internal permutation, additionally allows adjusting the round count. -* @param s - 5x5 Keccak state encoded as 25 lanes split into 50 uint32 words -* in this file's local little-endian lane-word order -* @param rounds - number of rounds to execute -* @throws If `rounds` is outside the supported `1..24` range. {@link Error} -* @example -* Permute a Keccak state with the default 24 rounds. -* ```ts -* keccakP(new Uint32Array(50)); -* ``` -*/ -function keccakP(s, rounds = 24) { - anumber$1(rounds, "rounds"); - if (rounds < 1 || rounds > 24) throw new Error("\"rounds\" expected integer 1..24"); - const B = /* @__PURE__ */ new Uint32Array(10); - for (let round = 24 - rounds; round < 24; round++) { - for (let x = 0; x < 10; x++) B[x] = s[x] ^ s[x + 10] ^ s[x + 20] ^ s[x + 30] ^ s[x + 40]; - for (let x = 0; x < 10; x += 2) { - const idx1 = (x + 8) % 10; - const idx0 = (x + 2) % 10; - const B0 = B[idx0]; - const B1 = B[idx0 + 1]; - const Th = rotlH(B0, B1, 1) ^ B[idx1]; - const Tl = rotlL(B0, B1, 1) ^ B[idx1 + 1]; - for (let y = 0; y < 50; y += 10) { - s[x + y] ^= Th; - s[x + y + 1] ^= Tl; - } - } - let curH = s[2]; - let curL = s[3]; - for (let t = 0; t < 24; t++) { - const shift = SHA3_ROTL[t]; - const Th = rotlH(curH, curL, shift); - const Tl = rotlL(curH, curL, shift); - const PI = SHA3_PI[t]; - curH = s[PI]; - curL = s[PI + 1]; - s[PI] = Th; - s[PI + 1] = Tl; - } - for (let y = 0; y < 50; y += 10) { - const b0 = s[y], b1 = s[y + 1], b2 = s[y + 2], b3 = s[y + 3]; - s[y] ^= ~s[y + 2] & s[y + 4]; - s[y + 1] ^= ~s[y + 3] & s[y + 5]; - s[y + 2] ^= ~s[y + 4] & s[y + 6]; - s[y + 3] ^= ~s[y + 5] & s[y + 7]; - s[y + 4] ^= ~s[y + 6] & s[y + 8]; - s[y + 5] ^= ~s[y + 7] & s[y + 9]; - s[y + 6] ^= ~s[y + 8] & b0; - s[y + 7] ^= ~s[y + 9] & b1; - s[y + 8] ^= ~b0 & b2; - s[y + 9] ^= ~b1 & b3; - } - s[0] ^= SHA3_IOTA_H[round]; - s[1] ^= SHA3_IOTA_L[round]; - } - clean(B); -} -/** -* Keccak sponge function. -* @param blockLen - absorb/squeeze rate in bytes -* @param suffix - domain separation suffix byte -* @param outputLen - default digest length in bytes. This base sponge only -* requires a non-negative integer; wrappers that need positive output -* lengths must enforce that themselves. -* @param enableXOF - whether XOF output is allowed -* @param rounds - number of Keccak-f rounds -* @example -* Build a sponge state, absorb bytes, then finalize a digest. -* ```ts -* const hash = new Keccak(136, 0x06, 32); -* hash.update(new Uint8Array([1, 2, 3])); -* hash.digest(); -* ``` -*/ -var Keccak = class Keccak { - state; - pos = 0; - posOut = 0; - finished = false; - state32; - destroyed = false; - blockLen; - suffix; - outputLen; - canXOF; - enableXOF = false; - rounds; - constructor(blockLen, suffix, outputLen, enableXOF = false, rounds = 24) { - this.blockLen = blockLen; - this.suffix = suffix; - this.outputLen = outputLen; - this.enableXOF = enableXOF; - this.canXOF = enableXOF; - this.rounds = rounds; - anumber$1(outputLen, "outputLen"); - if (!(0 < blockLen && blockLen < 200)) throw new Error("only keccak-f1600 function is supported"); - this.state = /* @__PURE__ */ new Uint8Array(200); - this.state32 = u32(this.state); - } - clone() { - return this._cloneInto(); - } - keccak() { - swap32IfBE(this.state32); - keccakP(this.state32, this.rounds); - swap32IfBE(this.state32); - this.posOut = 0; - this.pos = 0; - } - update(data) { - aexists(this); - abytes$1(data); - const { blockLen, state } = this; - const len = data.length; - for (let pos = 0; pos < len;) { - const take = Math.min(blockLen - this.pos, len - pos); - for (let i = 0; i < take; i++) state[this.pos++] ^= data[pos++]; - if (this.pos === blockLen) this.keccak(); - } - return this; - } - finish() { - if (this.finished) return; - this.finished = true; - const { state, suffix, pos, blockLen } = this; - state[pos] ^= suffix; - if ((suffix & 128) !== 0 && pos === blockLen - 1) this.keccak(); - state[blockLen - 1] ^= 128; - this.keccak(); - } - writeInto(out) { - aexists(this, false); - abytes$1(out); - this.finish(); - const bufferOut = this.state; - const { blockLen } = this; - for (let pos = 0, len = out.length; pos < len;) { - if (this.posOut >= blockLen) this.keccak(); - const take = Math.min(blockLen - this.posOut, len - pos); - out.set(bufferOut.subarray(this.posOut, this.posOut + take), pos); - this.posOut += take; - pos += take; - } - return out; - } - xofInto(out) { - if (!this.enableXOF) throw new Error("XOF is not possible for this instance"); - return this.writeInto(out); - } - xof(bytes) { - anumber$1(bytes); - return this.xofInto(new Uint8Array(bytes)); - } - digestInto(out) { - aoutput(out, this); - if (this.finished) throw new Error("digest() was already called"); - this.writeInto(out.subarray(0, this.outputLen)); - this.destroy(); - } - digest() { - const out = new Uint8Array(this.outputLen); - this.digestInto(out); - return out; - } - destroy() { - this.destroyed = true; - clean(this.state); - } - _cloneInto(to) { - const { blockLen, suffix, outputLen, rounds, enableXOF } = this; - to ||= new Keccak(blockLen, suffix, outputLen, enableXOF, rounds); - to.blockLen = blockLen; - to.state32.set(this.state32); - to.pos = this.pos; - to.posOut = this.posOut; - to.finished = this.finished; - to.rounds = rounds; - to.suffix = suffix; - to.outputLen = outputLen; - to.enableXOF = enableXOF; - to.canXOF = this.canXOF; - to.destroyed = this.destroyed; - return to; - } -}; -const genKeccak = (suffix, blockLen, outputLen, info = {}) => createHasher(() => new Keccak(blockLen, suffix, outputLen), info); -/** -* SHA3-256 hash function. Different from keccak-256. -* @param msg - message bytes to hash -* @returns Digest bytes. -* @example -* Hash a message with SHA3-256. -* ```ts -* sha3_256(new Uint8Array([97, 98, 99])); -* ``` -*/ -const sha3_256 = /* @__PURE__ */ genKeccak(6, 136, 32, /* @__PURE__ */ oidNist(8)); -/** -* SHA3-512 hash function. -* @param msg - message bytes to hash -* @returns Digest bytes. -* @example -* Hash a message with SHA3-512. -* ```ts -* sha3_512(new Uint8Array([97, 98, 99])); -* ``` -*/ -const sha3_512 = /* @__PURE__ */ genKeccak(6, 72, 64, /* @__PURE__ */ oidNist(10)); -const genShake = (suffix, blockLen, outputLen, info = {}) => createHasher((opts = {}) => new Keccak(blockLen, suffix, opts.dkLen === void 0 ? outputLen : opts.dkLen, true), info); -/** -* SHAKE128 XOF with 128-bit security and a 16-byte default output. -* @param msg - message bytes to hash -* @param opts - Optional output-length override. See {@link ShakeOpts}. -* @returns Digest bytes. -* @example -* Hash a message with SHAKE128. -* ```ts -* shake128(new Uint8Array([97, 98, 99]), { dkLen: 32 }); -* ``` -*/ -const shake128 = /* @__PURE__ */ genShake(31, 168, 16, /* @__PURE__ */ oidNist(11)); -/** -* SHAKE256 XOF with 256-bit security and a 32-byte default output. -* @param msg - message bytes to hash -* @param opts - Optional output-length override. See {@link ShakeOpts}. -* @returns Digest bytes. -* @example -* Hash a message with SHAKE256. -* ```ts -* shake256(new Uint8Array([97, 98, 99]), { dkLen: 64 }); -* ``` -*/ -const shake256 = /* @__PURE__ */ genShake(31, 136, 32, /* @__PURE__ */ oidNist(12)); -//#endregion -//#region tests/baseline/node_modules/@noble/post-quantum/node_modules/@noble/curves/abstract/fft.js -function checkU32(n) { - if (!Number.isSafeInteger(n) || n < 0 || n > 4294967295) throw new Error("wrong u32 integer:" + n); - return n; -} -/** -* Checks if integer is in form of `1 << X`. -* @param x - Integer to inspect. -* @returns `true` when the value is a power of two. -* @throws If `x` is not a valid unsigned 32-bit integer. {@link Error} -* @example -* Validate that an FFT size is a power of two. -* -* ```ts -* isPowerOfTwo(8); -* ``` -*/ -function isPowerOfTwo(x) { - checkU32(x); - return (x & x - 1) === 0 && x !== 0; -} -/** -* @param n - Value to reverse. -* @param bits - Number of bits to use. -* @returns Bit-reversed integer. -* @throws If `n` is not a valid unsigned 32-bit integer. {@link Error} -* @example -* Reverse the low `bits` bits of one index. -* -* ```ts -* reverseBits(3, 3); -* ``` -*/ -function reverseBits(n, bits) { - checkU32(n); - if (!Number.isSafeInteger(bits) || bits < 0 || bits > 32) throw new Error(`expected integer 0 <= bits <= 32, got ${bits}`); - let reversed = 0; - for (let i = 0; i < bits; i++, n >>>= 1) reversed = reversed << 1 | n & 1; - return reversed >>> 0; -} -/** -* Similar to `bitLen(x)-1` but much faster for small integers, like indices. -* @param n - Input value. -* @returns Base-2 logarithm. For `n = 0`, the current implementation returns `-1`. -* @throws If `n` is not a valid unsigned 32-bit integer. {@link Error} -* @example -* Compute the radix-2 stage count for one transform size. -* -* ```ts -* log2(8); -* ``` -*/ -function log2(n) { - checkU32(n); - return 31 - Math.clz32(n); -} -/** -* Moves lowest bit to highest position, which at first step splits -* array on even and odd indices, then it applied again to each part, -* which is core of fft -* @param values - Mutable coefficient array. -* @returns Mutated input array. -* @throws If the array length is not a positive power of two. {@link Error} -* @example -* Reorder coefficients into bit-reversed order in place. -* -* ```ts -* const values = Uint8Array.from([0, 1, 2, 3]); -* bitReversalInplace(values); -* ``` -*/ -function bitReversalInplace(values) { - const n = values.length; - if (!isPowerOfTwo(n)) throw new Error("expected positive power-of-two length, got " + n); - const bits = log2(n); - for (let i = 0; i < n; i++) { - const j = reverseBits(i, bits); - if (i < j) { - const tmp = values[i]; - values[i] = values[j]; - values[j] = tmp; - } - } - return values; -} -/** -* Constructs different flavors of FFT. radix2 implementation of low level mutating API. Flavors: -* -* - DIT (Decimation-in-Time): Bottom-Up (leaves to root), Cool-Turkey -* - DIF (Decimation-in-Frequency): Top-Down (root to leaves), Gentleman-Sande -* -* DIT takes brp input, returns natural output. -* DIF takes natural input, returns brp output. -* -* The output is actually identical. Time / frequence distinction is not meaningful -* for Polynomial multiplication in fields. -* Which means if protocol supports/needs brp output/inputs, then we can skip this step. -* -* Cyclic NTT: Rq = Zq[x]/(x^n-1). butterfly_DIT+loop_DIT OR butterfly_DIF+loop_DIT, roots are omega -* Negacyclic NTT: Rq = Zq[x]/(x^n+1). butterfly_DIT+loop_DIF, at least for mlkem / mldsa -* @param F - Field operations. -* @param coreOpts - FFT configuration: -* - `N`: Transform size. Must be a power of two. -* - `roots`: Stage roots for the selected transform size. -* - `dit`: Whether to run the DIT variant instead of DIF. -* - `invertButterflies` (optional): Whether to invert butterfly placement. -* - `skipStages` (optional): Number of initial stages to skip. -* - `brp` (optional): Whether to apply bit-reversal permutation at the boundary. -* @returns Low-level FFT loop. -* @throws If the FFT options or cached roots are invalid for the requested size. {@link Error} -* @example -* Constructs different flavors of FFT. -* -* ```ts -* import { FFTCore, rootsOfUnity } from '@noble/curves/abstract/fft.js'; -* import { Field } from '@noble/curves/abstract/modular.js'; -* const Fp = Field(17n); -* const roots = rootsOfUnity(Fp).roots(2); -* const loop = FFTCore(Fp, { N: 4, roots, dit: true }); -* const values = loop([1n, 2n, 3n, 4n]); -* ``` -*/ -const FFTCore = (F, coreOpts) => { - const { N, roots, dit, invertButterflies = false, skipStages = 0, brp = true } = coreOpts; - const bits = log2(N); - if (!isPowerOfTwo(N)) throw new Error("FFT: Polynomial size should be power of two"); - if (roots.length !== N) throw new Error(`FFT: wrong roots length: expected ${N}, got ${roots.length}`); - const isDit = dit !== invertButterflies; - return (values) => { - if (values.length !== N) throw new Error("FFT: wrong Polynomial length"); - if (dit && brp) bitReversalInplace(values); - for (let i = 0, g = 1; i < bits - skipStages; i++) { - const s = dit ? i + 1 + skipStages : bits - i; - const m = 1 << s; - const m2 = m >> 1; - const stride = N >> s; - for (let k = 0; k < N; k += m) for (let j = 0, grp = g++; j < m2; j++) { - const rootPos = invertButterflies ? dit ? N - grp : grp : j * stride; - const i0 = k + j; - const i1 = k + j + m2; - const omega = roots[rootPos]; - const b = values[i1]; - const a = values[i0]; - if (isDit) { - const t = F.mul(b, omega); - values[i0] = F.add(a, t); - values[i1] = F.sub(a, t); - } else if (invertButterflies) { - values[i0] = F.add(b, a); - values[i1] = F.mul(F.sub(b, a), omega); - } else { - values[i0] = F.add(a, b); - values[i1] = F.mul(F.sub(a, b), omega); - } - } - } - if (!dit && brp) bitReversalInplace(values); - return values; - }; -}; -//#endregion -//#region tests/baseline/node_modules/@noble/post-quantum/utils.js -/** -* Utilities for hex, bytearray and number handling. -* @module -*/ -/*! noble-post-quantum - MIT License (c) 2024 Paul Miller (paulmillr.com) */ -/** -* Asserts that a value is a byte array and optionally checks its length. -* Returns the original reference unchanged on success, and currently also accepts Node `Buffer` -* values through the upstream validator. -* This helper throws on malformed input, so APIs that must return `false` need to guard lengths -* before decoding or before calling it. -* @example -* Validate that a value is a byte array with the expected length. -* ```ts -* abytes(new Uint8Array([1]), 1); -* ``` -*/ -const abytesDoc = abytes$1; -/** -* Returns cryptographically secure random bytes. -* Requires `globalThis.crypto.getRandomValues` and throws if that API is unavailable. -* `bytesLength` is validated by the upstream helper as a non-negative integer before allocation, -* so negative and fractional values both throw instead of truncating through JS `ToIndex`. -* @param bytesLength - Number of random bytes to generate. -* @returns Fresh random bytes. -* @example -* Generate a fresh random seed. -* ```ts -* const seed = randomBytes(4); -* ``` -*/ -const randomBytes = randomBytes$1; -/** -* Compares two byte arrays in a length-constant way for equal lengths. -* Unequal lengths return `false` immediately, and there is no runtime type validation. -* @param a - First byte array. -* @param b - Second byte array. -* @returns Whether both arrays contain the same bytes. -* @example -* Compare two byte arrays for equality. -* ```ts -* equalBytes(new Uint8Array([1]), new Uint8Array([1])); -* ``` -*/ -function equalBytes(a, b) { - if (a.length !== b.length) return false; - let diff = 0; - for (let i = 0; i < a.length; i++) diff |= a[i] ^ b[i]; - return diff === 0; -} -/** -* Copies bytes into a fresh `Uint8Array`. -* Returns a detached plain `Uint8Array` after validating that the input is real bytes. -* @param bytes - Source bytes. -* @returns Copy of the input bytes. -* @example -* Copy bytes into a fresh array. -* ```ts -* copyBytes(new Uint8Array([1, 2])); -* ``` -*/ -function copyBytes(bytes) { - return Uint8Array.from(abytes$1(bytes)); -} -/** -* Validates that an options bag is a plain object. -* @param opts - Options object to validate. -* @throws On wrong argument types. {@link TypeError} -* @example -* Validate that an options bag is a plain object. -* ```ts -* validateOpts({}); -* ``` -*/ -function validateOpts(opts) { - if (Object.prototype.toString.call(opts) !== "[object Object]") throw new TypeError("expected valid options object"); -} -/** -* Validates common verification options. -* `context` itself is validated with `abytes(...)`, and individual algorithms may narrow support -* further after this shared plain-object gate. -* @param opts - Verification options. See {@link VerOpts}. -* @throws On wrong argument types. {@link TypeError} -* @example -* Validate common verification options. -* ```ts -* validateVerOpts({ context: new Uint8Array([1]) }); -* ``` -*/ -function validateVerOpts(opts) { - validateOpts(opts); - if (opts.context !== void 0) abytes$1(opts.context, void 0, "opts.context"); -} -/** -* Validates common signing options. -* `extraEntropy` is validated with `abytes(...)`; exact lengths and extra algorithm-specific -* restrictions are enforced later by callers. -* @param opts - Signing options. See {@link SigOpts}. -* @throws On wrong argument types. {@link TypeError} -* @example -* Validate common signing options. -* ```ts -* validateSigOpts({ extraEntropy: new Uint8Array([1]) }); -* ``` -*/ -function validateSigOpts(opts) { - validateVerOpts(opts); - if (opts.extraEntropy !== false && opts.extraEntropy !== void 0) abytes$1(opts.extraEntropy, void 0, "opts.extraEntropy"); -} -/** -* Builds a fixed-layout coder from byte lengths and nested coders. -* Raw-length fields decode as zero-copy `subarray(...)` views, and nested coders may preserve that -* aliasing too. Nested coder `encode(...)` results are treated as owned scratch: `splitCoder` -* copies them into the output and then zeroizes them with `fill(0)`. If a nested encoder forwards -* caller-owned bytes, it must do so only after detaching them into a disposable copy. -* @param label - Label used in validation errors. -* @param lengths - Field lengths or nested coders. -* @returns Composite fixed-length coder. -* @example -* Build a fixed-layout coder from byte lengths and nested coders. -* ```ts -* splitCoder('demo', 1, 2).encode([new Uint8Array([1]), new Uint8Array([2, 3])]); -* ``` -*/ -function splitCoder(label, ...lengths) { - const getLength = (c) => typeof c === "number" ? c : c.bytesLen; - const bytesLen = lengths.reduce((sum, a) => sum + getLength(a), 0); - return { - bytesLen, - encode: (bufs) => { - const res = new Uint8Array(bytesLen); - for (let i = 0, pos = 0; i < lengths.length; i++) { - const c = lengths[i]; - const l = getLength(c); - const b = typeof c === "number" ? bufs[i] : c.encode(bufs[i]); - abytes$1(b, l, label); - res.set(b, pos); - if (typeof c !== "number") b.fill(0); - pos += l; - } - return res; - }, - decode: (buf) => { - abytes$1(buf, bytesLen, label); - const res = []; - for (const c of lengths) { - const l = getLength(c); - const b = buf.subarray(0, l); - res.push(typeof c === "number" ? b : c.decode(b)); - buf = buf.subarray(l); - } - return res; - } - }; -} -/** -* Builds a fixed-length vector coder from another fixed-length coder. -* Element decoding receives `subarray(...)` views, so aliasing depends on the element coder. -* Element coder `encode(...)` results are treated as owned scratch: `vecCoder` copies them into -* the output and then zeroizes them with `fill(0)`. If an element encoder forwards caller-owned -* bytes, it must do so only after detaching them into a disposable copy. `vecCoder` also trusts -* the `BytesCoderLen` contract: each encoded element must already be exactly `c.bytesLen` bytes. -* @param c - Element coder. -* @param vecLen - Number of elements in the vector. -* @returns Fixed-length vector coder. -* @example -* Build a fixed-length vector coder from another fixed-length coder. -* ```ts -* vecCoder( -* { bytesLen: 1, encode: (n: number) => Uint8Array.of(n), decode: (b: Uint8Array) => b[0] || 0 }, -* 2 -* ).encode([1, 2]); -* ``` -*/ -function vecCoder(c, vecLen) { - const coder = c; - const bytesLen = vecLen * coder.bytesLen; - return { - bytesLen, - encode: (u) => { - if (u.length !== vecLen) throw new RangeError(`vecCoder.encode: wrong length=${u.length}. Expected: ${vecLen}`); - const res = new Uint8Array(bytesLen); - for (let i = 0, pos = 0; i < u.length; i++) { - const b = coder.encode(u[i]); - res.set(b, pos); - b.fill(0); - pos += b.length; - } - return res; - }, - decode: (a) => { - abytes$1(a, bytesLen); - const r = []; - for (let i = 0; i < a.length; i += coder.bytesLen) r.push(coder.decode(a.subarray(i, i + coder.bytesLen))); - return r; - } - }; -} -/** -* Overwrites supported typed-array inputs with zeroes in place. -* Accepts direct typed arrays and one-level arrays of them. -* @param list - Typed arrays or one-level lists of typed arrays to clear. -* @example -* Overwrite typed arrays with zeroes. -* ```ts -* const buf = Uint8Array.of(1, 2, 3); -* cleanBytes(buf); -* ``` -*/ -function cleanBytes(...list) { - for (const t of list) if (Array.isArray(t)) for (const b of t) b.fill(0); - else t.fill(0); -} -/** -* Creates a 32-bit mask with the lowest `bits` bits set. -* @param bits - Number of low bits to keep. -* @returns Bit mask with `bits` ones. -* @throws On wrong argument ranges or values. {@link RangeError} -* @example -* Create a low-bit mask for packed-field operations. -* ```ts -* const mask = getMask(4); -* ``` -*/ -function getMask(bits) { - if (!Number.isSafeInteger(bits) || bits < 0 || bits > 32) throw new RangeError(`expected bits in [0..32], got ${bits}`); - return bits === 32 ? 4294967295 : ~(-1 << bits) >>> 0; -} -/** Shared empty byte array used as the default context. */ -const EMPTY = /* @__PURE__ */ Uint8Array.of(); -/** -* Builds the domain-separated message payload for the pure sign/verify paths. -* Context length `255` is valid; only `ctx.length > 255` is rejected. -* @param msg - Message bytes. -* @param ctx - Optional context bytes. -* @returns Domain-separated message payload. -* @throws On wrong argument ranges or values. {@link RangeError} -* @example -* Build the domain-separated payload before direct signing. -* ```ts -* const payload = getMessage(new Uint8Array([1, 2])); -* ``` -*/ -function getMessage(msg, ctx = EMPTY) { - abytes$1(msg); - abytes$1(ctx); - if (ctx.length > 255) throw new RangeError("context should be 255 bytes or less"); - return concatBytes$1(new Uint8Array([0, ctx.length]), ctx, msg); -} -const oidNistP = /* @__PURE__ */ Uint8Array.from([ - 6, - 9, - 96, - 134, - 72, - 1, - 101, - 3, - 4, - 2 -]); -/** -* Validates that a hash exposes a NIST hash OID and enough collision resistance. -* Current accepted surface is broader than the FIPS algorithm tables: any hash/XOF under the NIST -* `2.16.840.1.101.3.4.2.*` subtree is accepted if its effective `outputLen` is strong enough. -* XOF callers must pass a callable whose `outputLen` matches the digest length they actually intend -* to sign; bare `shake128` / `shake256` defaults are too short for the stronger prehash modes. -* @param hash - Hash function to validate. -* @param requiredStrength - Minimum required collision-resistance strength in bits. -* @throws If the hash metadata or collision resistance is insufficient. {@link Error} -* @example -* Validate that a hash exposes a NIST hash OID and enough collision resistance. -* ```ts -* import { sha256 } from '@noble/hashes/sha2.js'; -* import { checkHash } from '@noble/post-quantum/utils.js'; -* checkHash(sha256, 128); -* ``` -*/ -function checkHash(hash, requiredStrength = 0) { - if (!hash.oid || !equalBytes(hash.oid.subarray(0, 10), oidNistP)) throw new Error("hash.oid is invalid: expected NIST hash"); - const collisionResistance = hash.outputLen * 8 / 2; - if (requiredStrength > collisionResistance) throw new Error("Pre-hash security strength too low: " + collisionResistance + ", required: " + requiredStrength); -} -/** -* Builds the domain-separated prehash payload for the prehash sign/verify paths. -* Callers are expected to vet `hash.oid` first, e.g. via `checkHash(...)`; calling this helper -* directly with a hash object that lacks `oid` currently throws later inside `concatBytes(...)`. -* Context length `255` is valid; only `ctx.length > 255` is rejected. -* @param hash - Prehash function. -* @param msg - Message bytes. -* @param ctx - Optional context bytes. -* @returns Domain-separated prehash payload. -* @throws On wrong argument ranges or values. {@link RangeError} -* @example -* Build the domain-separated prehash payload for external hashing. -* ```ts -* import { sha256 } from '@noble/hashes/sha2.js'; -* import { getMessagePrehash } from '@noble/post-quantum/utils.js'; -* getMessagePrehash(sha256, new Uint8Array([1, 2])); -* ``` -*/ -function getMessagePrehash(hash, msg, ctx = EMPTY) { - abytes$1(msg); - abytes$1(ctx); - if (ctx.length > 255) throw new RangeError("context should be 255 bytes or less"); - const hashed = hash(msg); - return concatBytes$1(new Uint8Array([1, ctx.length]), ctx, hash.oid, hashed); -} -//#endregion -//#region tests/baseline/node_modules/@noble/post-quantum/_crystals.js -/** -* Internal methods for lattice-based ML-KEM and ML-DSA. -* @module -*/ -/*! noble-post-quantum - MIT License (c) 2024 Paul Miller (paulmillr.com) */ -/** -* Creates shared modular arithmetic, NTT, and packing helpers for CRYSTALS schemes. -* @param opts - Polynomial and transform parameters. See {@link CrystalOpts}. -* @returns CRYSTALS arithmetic and encoding helpers. -* @example -* Create shared modular arithmetic and NTT helpers for a CRYSTALS parameter set. -* ```ts -* const crystals = genCrystals({ -* newPoly: (n) => new Uint16Array(n), -* N: 256, -* Q: 3329, -* F: 3303, -* ROOT_OF_UNITY: 17, -* brvBits: 7, -* isKyber: true, -* }); -* const reduced = crystals.mod(-1); -* ``` -*/ -const genCrystals = (opts) => { - const { newPoly, N, Q, F, ROOT_OF_UNITY, brvBits, isKyber } = opts; - const mod = (a, modulo = Q) => { - const result = a % modulo | 0; - return (result >= 0 ? result | 0 : modulo + result | 0) | 0; - }; - const smod = (a, modulo = Q) => { - const r = mod(a, modulo) | 0; - return (r > modulo >> 1 ? r - modulo | 0 : r) | 0; - }; - function getZettas() { - const out = newPoly(N); - for (let i = 0; i < N; i++) { - const b = reverseBits(i, brvBits); - const p = BigInt(ROOT_OF_UNITY) ** BigInt(b) % BigInt(Q); - out[i] = Number(p) | 0; - } - return out; - } - const nttZetas = getZettas(); - const field = { - add: (a, b) => mod((a | 0) + (b | 0)) | 0, - sub: (a, b) => mod((a | 0) - (b | 0)) | 0, - mul: (a, b) => mod((a | 0) * (b | 0)) | 0, - inv: (_a) => { - throw new Error("not implemented"); - } - }; - const nttOpts = { - N, - roots: nttZetas, - invertButterflies: true, - skipStages: isKyber ? 1 : 0, - brp: false - }; - const dif = FFTCore(field, { - dit: false, - ...nttOpts - }); - const dit = FFTCore(field, { - dit: true, - ...nttOpts - }); - const NTT = { - encode: (r) => { - return dif(r); - }, - decode: (r) => { - dit(r); - for (let i = 0; i < r.length; i++) r[i] = mod(F * r[i]); - return r; - } - }; - const bitsCoder = (d, c) => { - const mask = getMask(d); - const bytesLen = d * (N / 8); - return { - bytesLen, - encode: (poly_) => { - const poly = poly_; - const r = new Uint8Array(bytesLen); - for (let i = 0, buf = 0, bufLen = 0, pos = 0; i < poly.length; i++) { - buf |= (c.encode(poly[i]) & mask) << bufLen; - bufLen += d; - for (; bufLen >= 8; bufLen -= 8, buf >>= 8) r[pos++] = buf & getMask(bufLen); - } - return r; - }, - decode: (bytes) => { - const r = newPoly(N); - for (let i = 0, buf = 0, bufLen = 0, pos = 0; i < bytes.length; i++) { - buf |= bytes[i] << bufLen; - bufLen += 8; - for (; bufLen >= d; bufLen -= d, buf >>= d) r[pos++] = c.decode(buf & mask); - } - return r; - } - }; - }; - return { - mod, - smod, - nttZetas, - NTT: { - encode: (r) => NTT.encode(r), - decode: (r) => NTT.decode(r) - }, - bitsCoder - }; -}; -const createXofShake = (shake) => (seed, blockLen) => { - if (!blockLen) blockLen = shake.blockLen; - const _seed = new Uint8Array(seed.length + 2); - _seed.set(seed); - const seedLen = seed.length; - const buf = new Uint8Array(blockLen); - let h = shake.create({}); - let calls = 0; - let xofs = 0; - return { - stats: () => ({ - calls, - xofs - }), - get: (x, y) => { - _seed[seedLen + 0] = x; - _seed[seedLen + 1] = y; - h.destroy(); - h = shake.create({}).update(_seed); - calls++; - return () => { - xofs++; - return h.xofInto(buf); - }; - }, - clean: () => { - h.destroy(); - cleanBytes(buf, _seed); - } - }; -}; -/** -* SHAKE128-based extendable-output reader factory used by ML-KEM. -* `get(x, y)` selects one coordinate pair at a time; calling it again invalidates previously -* returned readers, and each squeeze reuses one mutable internal output buffer. -* @param seed - Seed bytes for the reader. -* @param blockLen - Optional output block length. -* @returns Stateful XOF reader. -* @example -* Build the ML-KEM SHAKE128 matrix expander and read one block. -* ```ts -* import { randomBytes } from '@noble/post-quantum/utils.js'; -* import { XOF128 } from '@noble/post-quantum/_crystals.js'; -* const reader = XOF128(randomBytes(32)); -* const block = reader.get(0, 0)(); -* ``` -*/ -const XOF128 = /* @__PURE__ */ createXofShake(shake128); -/** -* SHAKE256-based extendable-output reader factory used by ML-DSA. -* `get(x, y)` appends raw one-byte coordinates to the seed, invalidates previously returned -* readers, and reuses one mutable internal output buffer for each squeeze. -* @param seed - Seed bytes for the reader. -* @param blockLen - Optional output block length. -* @returns Stateful XOF reader. -* @example -* Build the ML-DSA SHAKE256 coefficient expander and read one block. -* ```ts -* import { randomBytes } from '@noble/post-quantum/utils.js'; -* import { XOF256 } from '@noble/post-quantum/_crystals.js'; -* const reader = XOF256(randomBytes(32)); -* const block = reader.get(0, 0)(); -* ``` -*/ -const XOF256 = /* @__PURE__ */ createXofShake(shake256); -//#endregion -//#region tests/baseline/node_modules/@noble/post-quantum/ml-dsa.js -/** -* ML-DSA: Module Lattice-based Digital Signature Algorithm from -* [FIPS-204](https://csrc.nist.gov/pubs/fips/204/ipd). A.k.a. CRYSTALS-Dilithium. -* -* Has similar internals to ML-KEM, but their keys and params are different. -* Check out [official site](https://www.pq-crystals.org/dilithium/index.shtml), -* [repo](https://github.com/pq-crystals/dilithium). -* @module -*/ -/*! noble-post-quantum - MIT License (c) 2024 Paul Miller (paulmillr.com) */ -function validateInternalOpts(opts) { - validateOpts(opts); - if (opts.externalMu !== void 0) abool(opts.externalMu, "opts.externalMu"); -} -const N$1 = 256; -const Q$1 = 8380417; -const ROOT_OF_UNITY = 1753; -const F = 8347681; -const D = 13; -const GAMMA2_1 = Math.floor(95232) | 0; -const GAMMA2_2 = Math.floor(261888) | 0; -/** Internal params for different versions of ML-DSA */ -/** Built-in ML-DSA parameter presets keyed by security categories `2/3/5` -* for `ml_dsa44` / `ml_dsa65` / `ml_dsa87`. -* This is only the Table 1 subset used directly here: `BETA = TAU * ETA` is derived later, -* while `C_TILDE_BYTES`, `TR_BYTES`, `CRH_BYTES`, and `securityLevel` live in the preset wrappers. -*/ -const PARAMS$1 = /* @__PURE__ */ (() => Object.freeze({ - 2: Object.freeze({ - K: 4, - L: 4, - D, - GAMMA1: 2 ** 17, - GAMMA2: GAMMA2_1, - TAU: 39, - ETA: 2, - OMEGA: 80 - }), - 3: Object.freeze({ - K: 6, - L: 5, - D, - GAMMA1: 2 ** 19, - GAMMA2: GAMMA2_2, - TAU: 49, - ETA: 4, - OMEGA: 55 - }), - 5: Object.freeze({ - K: 8, - L: 7, - D, - GAMMA1: 2 ** 19, - GAMMA2: GAMMA2_2, - TAU: 60, - ETA: 2, - OMEGA: 75 - }) -}))(); -const newPoly = (n) => new Int32Array(n); -const crystals$1 = /* @__PURE__ */ genCrystals({ - N: N$1, - Q: Q$1, - F, - ROOT_OF_UNITY, - newPoly, - isKyber: false, - brvBits: 8 -}); -const id = (n) => n; -const polyCoder$1 = (d, compress = id, verify = id) => crystals$1.bitsCoder(d, { - encode: (i) => compress(verify(i)), - decode: (i) => verify(compress(i)) -}); -const polyAdd$1 = (a_, b_) => { - const a = a_; - const b = b_; - for (let i = 0; i < a.length; i++) a[i] = crystals$1.mod(a[i] + b[i]); - return a; -}; -const polySub$1 = (a_, b_) => { - const a = a_; - const b = b_; - for (let i = 0; i < a.length; i++) a[i] = crystals$1.mod(a[i] - b[i]); - return a; -}; -const polyShiftl = (p_) => { - const p = p_; - for (let i = 0; i < N$1; i++) p[i] <<= D; - return p; -}; -const polyChknorm = (p_, B) => { - const p = p_; - for (let i = 0; i < N$1; i++) if (Math.abs(crystals$1.smod(p[i])) >= B) return true; - return false; -}; -const MultiplyNTTs$1 = (a_, b_) => { - const a = a_; - const b = b_; - const c = newPoly(N$1); - for (let i = 0; i < a.length; i++) c[i] = crystals$1.mod(a[i] * b[i]); - return c; -}; -function RejNTTPoly(xof_) { - const xof = xof_; - const r = newPoly(N$1); - for (let j = 0; j < N$1;) { - const b = xof(); - if (b.length % 3) throw new Error("RejNTTPoly: unaligned block"); - for (let i = 0; j < N$1 && i <= b.length - 3; i += 3) { - const t = (b[i + 0] | b[i + 1] << 8 | b[i + 2] << 16) & 8388607; - if (t < Q$1) r[j++] = t; - } - } - return r; -} -function getDilithium(opts_) { - const opts = opts_; - const { K, L, GAMMA1, GAMMA2, TAU, ETA, OMEGA } = opts; - const { CRH_BYTES, TR_BYTES, C_TILDE_BYTES, XOF128, XOF256, securityLevel } = opts; - if (![2, 4].includes(ETA)) throw new Error("Wrong ETA"); - if (![1 << 17, 1 << 19].includes(GAMMA1)) throw new Error("Wrong GAMMA1"); - if (![GAMMA2_1, GAMMA2_2].includes(GAMMA2)) throw new Error("Wrong GAMMA2"); - const BETA = TAU * ETA; - const decompose = (r) => { - const rPlus = crystals$1.mod(r); - const r0 = crystals$1.smod(rPlus, 2 * GAMMA2) | 0; - if (rPlus - r0 === 8380416) return { - r1: 0, - r0: r0 - 1 | 0 - }; - return { - r1: Math.floor((rPlus - r0) / (2 * GAMMA2)) | 0, - r0 - }; - }; - const HighBits = (r) => decompose(r).r1; - const LowBits = (r) => decompose(r).r0; - const MakeHint = (z, r) => { - return z <= GAMMA2 || z > Q$1 - GAMMA2 || z === Q$1 - GAMMA2 && r === 0 ? 0 : 1; - }; - const UseHint = (h, r) => { - const m = Math.floor(8380416 / (2 * GAMMA2)); - const { r1, r0 } = decompose(r); - if (h === 1) return r0 > 0 ? crystals$1.mod(r1 + 1, m) | 0 : crystals$1.mod(r1 - 1, m) | 0; - return r1 | 0; - }; - const Power2Round = (r) => { - const rPlus = crystals$1.mod(r); - const r0 = crystals$1.smod(rPlus, 2 ** D) | 0; - return { - r1: Math.floor((rPlus - r0) / 2 ** D) | 0, - r0 - }; - }; - const hintCoder = { - bytesLen: OMEGA + K, - encode: (h_) => { - const h = h_; - if (h === false) throw new Error("hint.encode: hint is false"); - const res = new Uint8Array(OMEGA + K); - for (let i = 0, k = 0; i < K; i++) { - for (let j = 0; j < N$1; j++) if (h[i][j] !== 0) res[k++] = j; - res[OMEGA + i] = k; - } - return res; - }, - decode: (buf) => { - const h = []; - let k = 0; - for (let i = 0; i < K; i++) { - const hi = newPoly(N$1); - if (buf[OMEGA + i] < k || buf[OMEGA + i] > OMEGA) return false; - for (let j = k; j < buf[OMEGA + i]; j++) { - if (j > k && buf[j] <= buf[j - 1]) return false; - hi[buf[j]] = 1; - } - k = buf[OMEGA + i]; - h.push(hi); - } - for (let j = k; j < OMEGA; j++) if (buf[j] !== 0) return false; - return h; - } - }; - const ETACoder = polyCoder$1(ETA === 2 ? 3 : 4, (i) => ETA - i, (i) => { - if (!(-ETA <= i && i <= ETA)) throw new Error(`malformed key s1/s3 ${i} outside of ETA range [${-ETA}, ${ETA}]`); - return i; - }); - const T0Coder = polyCoder$1(13, (i) => 4096 - i); - const T1Coder = polyCoder$1(10); - const ZCoder = polyCoder$1(GAMMA1 === 1 << 17 ? 18 : 20, (i) => crystals$1.smod(GAMMA1 - i)); - const W1Vec = vecCoder(polyCoder$1(GAMMA2 === GAMMA2_1 ? 6 : 4), K); - const publicCoder = splitCoder("publicKey", 32, vecCoder(T1Coder, K)); - const secretCoder = splitCoder("secretKey", 32, 32, TR_BYTES, vecCoder(ETACoder, L), vecCoder(ETACoder, K), vecCoder(T0Coder, K)); - const sigCoder = splitCoder("signature", C_TILDE_BYTES, vecCoder(ZCoder, L), hintCoder); - const CoefFromHalfByte = ETA === 2 ? (n) => n < 15 ? 2 - n % 5 : false : (n) => n < 9 ? 4 - n : false; - function RejBoundedPoly(xof_) { - const xof = xof_; - const r = newPoly(N$1); - for (let j = 0; j < N$1;) { - const b = xof(); - for (let i = 0; j < N$1 && i < b.length; i += 1) { - const d1 = CoefFromHalfByte(b[i] & 15); - const d2 = CoefFromHalfByte(b[i] >> 4 & 15); - if (d1 !== false) r[j++] = d1; - if (j < N$1 && d2 !== false) r[j++] = d2; - } - } - return r; - } - const SampleInBall = (seed) => { - const pre = newPoly(N$1); - const s = shake256.create({}).update(seed); - const buf = new Uint8Array(shake256.blockLen); - s.xofInto(buf); - const masks = buf.slice(0, 8); - for (let i = N$1 - TAU, pos = 8, maskPos = 0, maskBit = 0; i < N$1; i++) { - let b = i + 1; - for (; b > i;) { - b = buf[pos++]; - if (pos < shake256.blockLen) continue; - s.xofInto(buf); - pos = 0; - } - pre[i] = pre[b]; - pre[b] = 1 - ((masks[maskPos] >> maskBit++ & 1) << 1); - if (maskBit >= 8) { - maskPos++; - maskBit = 0; - } - } - return pre; - }; - const polyPowerRound = (p_) => { - const p = p_; - const res0 = newPoly(N$1); - const res1 = newPoly(N$1); - for (let i = 0; i < p.length; i++) { - const { r0, r1 } = Power2Round(p[i]); - res0[i] = r0; - res1[i] = r1; - } - return { - r0: res0, - r1: res1 - }; - }; - const polyUseHint = (u_, h_) => { - const u = u_; - const h = h_; - for (let i = 0; i < N$1; i++) u[i] = UseHint(h[i], u[i]); - return u; - }; - const polyMakeHint = (a_, b_) => { - const a = a_; - const b = b_; - const v = newPoly(N$1); - let cnt = 0; - for (let i = 0; i < N$1; i++) { - const h = MakeHint(a[i], b[i]); - v[i] = h; - cnt += h; - } - return { - v, - cnt - }; - }; - const signRandBytes = 32; - const seedCoder = splitCoder("seed", 32, 64, 32); - const internal = Object.freeze({ - info: Object.freeze({ type: "internal-ml-dsa" }), - lengths: Object.freeze({ - secretKey: secretCoder.bytesLen, - publicKey: publicCoder.bytesLen, - seed: 32, - signature: sigCoder.bytesLen, - signRand: signRandBytes - }), - keygen: (seed) => { - const seedDst = /* @__PURE__ */ new Uint8Array(34); - const randSeed = seed === void 0; - if (randSeed) seed = randomBytes(32); - abytesDoc(seed, 32, "seed"); - seedDst.set(seed); - if (randSeed) cleanBytes(seed); - seedDst[32] = K; - seedDst[33] = L; - const [rho, rhoPrime, K_] = seedCoder.decode(shake256(seedDst, { dkLen: seedCoder.bytesLen })); - const xofPrime = XOF256(rhoPrime); - const s1 = []; - for (let i = 0; i < L; i++) s1.push(RejBoundedPoly(xofPrime.get(i & 255, i >> 8 & 255))); - const s2 = []; - for (let i = L; i < L + K; i++) s2.push(RejBoundedPoly(xofPrime.get(i & 255, i >> 8 & 255))); - const s1Hat = s1.map((i) => crystals$1.NTT.encode(i.slice())); - const t0 = []; - const t1 = []; - const xof = XOF128(rho); - const t = newPoly(N$1); - for (let i = 0; i < K; i++) { - cleanBytes(t); - for (let j = 0; j < L; j++) { - const aij = RejNTTPoly(xof.get(j, i)); - polyAdd$1(t, MultiplyNTTs$1(aij, s1Hat[j])); - } - crystals$1.NTT.decode(t); - const { r0, r1 } = polyPowerRound(polyAdd$1(t, s2[i])); - t0.push(r0); - t1.push(r1); - } - const publicKey = publicCoder.encode([rho, t1]); - const tr = shake256(publicKey, { dkLen: TR_BYTES }); - const secretKey = secretCoder.encode([ - rho, - K_, - tr, - s1, - s2, - t0 - ]); - xof.clean(); - xofPrime.clean(); - cleanBytes(rho, rhoPrime, K_, s1, s2, s1Hat, t, t0, t1, tr, seedDst); - return { - publicKey, - secretKey - }; - }, - getPublicKey: (secretKey) => { - const [rho, _K, _tr, s1, s2, _t0] = secretCoder.decode(secretKey); - const xof = XOF128(rho); - const s1Hat = s1.map((p) => crystals$1.NTT.encode(p.slice())); - const t1 = []; - const tmp = newPoly(N$1); - for (let i = 0; i < K; i++) { - tmp.fill(0); - for (let j = 0; j < L; j++) { - const aij = RejNTTPoly(xof.get(j, i)); - polyAdd$1(tmp, MultiplyNTTs$1(aij, s1Hat[j])); - } - crystals$1.NTT.decode(tmp); - polyAdd$1(tmp, s2[i]); - const { r1 } = polyPowerRound(tmp); - t1.push(r1); - } - xof.clean(); - cleanBytes(tmp, s1Hat, _t0, s1, s2); - return publicCoder.encode([rho, t1]); - }, - sign: (msg, secretKey, opts = {}) => { - validateSigOpts(opts); - validateInternalOpts(opts); - let { extraEntropy: random, externalMu = false } = opts; - const [rho, _K, tr, s1, s2, t0] = secretCoder.decode(secretKey); - const A = []; - const xof = XOF128(rho); - for (let i = 0; i < K; i++) { - const pv = []; - for (let j = 0; j < L; j++) pv.push(RejNTTPoly(xof.get(j, i))); - A.push(pv); - } - xof.clean(); - for (let i = 0; i < L; i++) crystals$1.NTT.encode(s1[i]); - for (let i = 0; i < K; i++) { - crystals$1.NTT.encode(s2[i]); - crystals$1.NTT.encode(t0[i]); - } - const mu = externalMu ? msg : shake256.create({ dkLen: CRH_BYTES }).update(tr).update(msg).digest(); - const rnd = random === false ? /* @__PURE__ */ new Uint8Array(32) : random === void 0 ? randomBytes(signRandBytes) : random; - abytesDoc(rnd, 32, "extraEntropy"); - const rhoprime = shake256.create({ dkLen: CRH_BYTES }).update(_K).update(rnd).update(mu).digest(); - abytesDoc(rhoprime, CRH_BYTES); - const x256 = XOF256(rhoprime, ZCoder.bytesLen); - main_loop: for (let kappa = 0;;) { - const y = []; - for (let i = 0; i < L; i++, kappa++) y.push(ZCoder.decode(x256.get(kappa & 255, kappa >> 8)())); - const z = y.map((i) => crystals$1.NTT.encode(i.slice())); - const w = []; - for (let i = 0; i < K; i++) { - const wi = newPoly(N$1); - for (let j = 0; j < L; j++) polyAdd$1(wi, MultiplyNTTs$1(A[i][j], z[j])); - crystals$1.NTT.decode(wi); - w.push(wi); - } - const w1 = w.map((j) => j.map(HighBits)); - const cTilde = shake256.create({ dkLen: C_TILDE_BYTES }).update(mu).update(W1Vec.encode(w1)).digest(); - const cHat = crystals$1.NTT.encode(SampleInBall(cTilde)); - const cs1 = s1.map((i) => MultiplyNTTs$1(i, cHat)); - for (let i = 0; i < L; i++) { - polyAdd$1(crystals$1.NTT.decode(cs1[i]), y[i]); - if (polyChknorm(cs1[i], GAMMA1 - BETA)) continue main_loop; - } - let cnt = 0; - const h = []; - for (let i = 0; i < K; i++) { - const cs2 = crystals$1.NTT.decode(MultiplyNTTs$1(s2[i], cHat)); - const r0 = polySub$1(w[i], cs2).map(LowBits); - if (polyChknorm(r0, GAMMA2 - BETA)) continue main_loop; - const ct0 = crystals$1.NTT.decode(MultiplyNTTs$1(t0[i], cHat)); - if (polyChknorm(ct0, GAMMA2)) continue main_loop; - polyAdd$1(r0, ct0); - const hint = polyMakeHint(r0, w1[i]); - h.push(hint.v); - cnt += hint.cnt; - } - if (cnt > OMEGA) continue; - x256.clean(); - const res = sigCoder.encode([ - cTilde, - cs1, - h - ]); - cleanBytes(cTilde, cs1, h, cHat, w1, w, z, y, rhoprime, s1, s2, t0, ...A); - if (!externalMu) cleanBytes(mu); - return res; - } - throw new Error("Unreachable code path reached, report this error"); - }, - verify: (sig, msg, publicKey, opts = {}) => { - validateInternalOpts(opts); - const { externalMu = false } = opts; - const [rho, t1] = publicCoder.decode(publicKey); - const tr = shake256(publicKey, { dkLen: TR_BYTES }); - if (sig.length !== sigCoder.bytesLen) return false; - const [cTilde, z, h] = sigCoder.decode(sig); - if (h === false) return false; - for (let i = 0; i < L; i++) if (polyChknorm(z[i], GAMMA1 - BETA)) return false; - const mu = externalMu ? msg : shake256.create({ dkLen: CRH_BYTES }).update(tr).update(msg).digest(); - const c = crystals$1.NTT.encode(SampleInBall(cTilde)); - const zNtt = z.map((i) => i.slice()); - for (let i = 0; i < L; i++) crystals$1.NTT.encode(zNtt[i]); - const wTick1 = []; - const xof = XOF128(rho); - for (let i = 0; i < K; i++) { - const ct12d = MultiplyNTTs$1(crystals$1.NTT.encode(polyShiftl(t1[i])), c); - const Az = newPoly(N$1); - for (let j = 0; j < L; j++) { - const aij = RejNTTPoly(xof.get(j, i)); - polyAdd$1(Az, MultiplyNTTs$1(aij, zNtt[j])); - } - const wApprox = crystals$1.NTT.decode(polySub$1(Az, ct12d)); - wTick1.push(polyUseHint(wApprox, h[i])); - } - xof.clean(); - const c2 = shake256.create({ dkLen: C_TILDE_BYTES }).update(mu).update(W1Vec.encode(wTick1)).digest(); - for (const t of h) if (!(t.reduce((acc, i) => acc + i, 0) <= OMEGA)) return false; - for (const t of z) if (polyChknorm(t, GAMMA1 - BETA)) return false; - return equalBytes(cTilde, c2); - } - }); - return Object.freeze({ - info: Object.freeze({ type: "ml-dsa" }), - internal, - securityLevel, - keygen: internal.keygen, - lengths: internal.lengths, - getPublicKey: internal.getPublicKey, - sign: (msg, secretKey, opts = {}) => { - validateSigOpts(opts); - const M = getMessage(msg, opts.context); - const res = internal.sign(M, secretKey, opts); - cleanBytes(M); - return res; - }, - verify: (sig, msg, publicKey, opts = {}) => { - validateVerOpts(opts); - return internal.verify(sig, getMessage(msg, opts.context), publicKey); - }, - prehash: (hash) => { - checkHash(hash, securityLevel); - return Object.freeze({ - info: Object.freeze({ type: "hashml-dsa" }), - securityLevel, - lengths: internal.lengths, - keygen: internal.keygen, - getPublicKey: internal.getPublicKey, - sign: (msg, secretKey, opts = {}) => { - validateSigOpts(opts); - const M = getMessagePrehash(hash, msg, opts.context); - const res = internal.sign(M, secretKey, opts); - cleanBytes(M); - return res; - }, - verify: (sig, msg, publicKey, opts = {}) => { - validateVerOpts(opts); - return internal.verify(sig, getMessagePrehash(hash, msg, opts.context), publicKey); - } - }); - } - }); -} -/** ML-DSA-44 for 128-bit security level. Not recommended after 2030, as per ASD. */ -const ml_dsa44 = /* @__PURE__ */ (() => getDilithium({ - ...PARAMS$1[2], - CRH_BYTES: 64, - TR_BYTES: 64, - C_TILDE_BYTES: 32, - XOF128, - XOF256, - securityLevel: 128 -}))(); -/** ML-DSA-65 for 192-bit security level. Not recommended after 2030, as per ASD. */ -const ml_dsa65 = /* @__PURE__ */ (() => getDilithium({ - ...PARAMS$1[3], - CRH_BYTES: 64, - TR_BYTES: 64, - C_TILDE_BYTES: 48, - XOF128, - XOF256, - securityLevel: 192 -}))(); -/** ML-DSA-87 for 256-bit security level. OK after 2030, as per ASD. */ -const ml_dsa87 = /* @__PURE__ */ (() => getDilithium({ - ...PARAMS$1[5], - CRH_BYTES: 64, - TR_BYTES: 64, - C_TILDE_BYTES: 64, - XOF128, - XOF256, - securityLevel: 256 -}))(); -//#endregion -//#region tests/baseline/node_modules/@noble/hashes/legacy.js -/** - -SHA1 (RFC 3174), MD5 (RFC 1321), and RIPEMD160 legacy, weak hash functions. -RFC 2286 only covers HMAC-RIPEMD160 wrapper material and test vectors, -not the base RIPEMD-160 compression spec. -Don't use them in a new protocol. What "weak" means: - -- Collisions can be made with 2^18 effort in MD5, 2^60 in SHA1, 2^80 in RIPEMD160. -- No practical pre-image attacks (only theoretical, 2^123.4) -- HMAC seems kinda ok: https://www.rfc-editor.org/rfc/rfc6151 -* @module -*/ -/** Initial SHA-1 state from RFC 3174 §6.1. */ -const SHA1_IV = /* @__PURE__ */ Uint32Array.from([ - 1732584193, - 4023233417, - 2562383102, - 271733878, - 3285377520 -]); -const SHA1_W = /* @__PURE__ */ new Uint32Array(80); -/** Internal SHA1 legacy hash class. */ -var _SHA1 = class extends HashMD { - A = SHA1_IV[0] | 0; - B = SHA1_IV[1] | 0; - C = SHA1_IV[2] | 0; - D = SHA1_IV[3] | 0; - E = SHA1_IV[4] | 0; - constructor() { - super(64, 20, 8, false); - } - get() { - const { A, B, C, D, E } = this; - return [ - A, - B, - C, - D, - E - ]; - } - set(A, B, C, D, E) { - this.A = A | 0; - this.B = B | 0; - this.C = C | 0; - this.D = D | 0; - this.E = E | 0; - } - _cloneInto(to) { - (to ||= new this.constructor()).set(...this.get()); - return this._cloneIntoMeta(to); - } - process(view, offset) { - for (let i = 0; i < 16; i++, offset += 4) SHA1_W[i] = view.getUint32(offset, false); - for (let i = 16; i < 80; i++) SHA1_W[i] = rotl$2(SHA1_W[i - 3] ^ SHA1_W[i - 8] ^ SHA1_W[i - 14] ^ SHA1_W[i - 16], 1); - let { A, B, C, D, E } = this; - for (let i = 0; i < 80; i++) { - let F, K; - if (i < 20) { - F = Chi(B, C, D); - K = 1518500249; - } else if (i < 40) { - F = B ^ C ^ D; - K = 1859775393; - } else if (i < 60) { - F = Maj(B, C, D); - K = 2400959708; - } else { - F = B ^ C ^ D; - K = 3395469782; - } - const T = rotl$2(A, 5) + F + E + K + SHA1_W[i] | 0; - E = D; - D = C; - C = rotl$2(B, 30); - B = A; - A = T; - } - A = A + this.A | 0; - B = B + this.B | 0; - C = C + this.C | 0; - D = D + this.D | 0; - E = E + this.E | 0; - this.set(A, B, C, D, E); - } - roundClean() { - clean$2(SHA1_W); - } - destroy() { - this.destroyed = true; - this.set(0, 0, 0, 0, 0); - clean$2(this.buffer); - } -}; -/** -* SHA1 (RFC 3174) legacy hash function. It was cryptographically broken. -* @param msg - message bytes to hash -* @param opts - Reserved hash options. -* @returns Digest bytes. -* @example -* Hash a message with SHA1. -* ```ts -* sha1(new Uint8Array([97, 98, 99])); -* ``` -*/ -const sha1 = /* @__PURE__ */ createHasher$1(() => new _SHA1()); -//#endregion -//#region tests/baseline/node_modules/@noble/curves/nist.js -/** -* NIST P256, P384, P521 curves. -* https://www.secg.org/sec2-v2.pdf, https://neuromancer.sk/std/nist/P-256 -* @module -*/ -/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ -const p256_CURVE = /* @__PURE__ */ (() => ({ - p: BigInt("0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff"), - n: BigInt("0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"), - h: BigInt(1), - a: BigInt("0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc"), - b: BigInt("0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b"), - Gx: BigInt("0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296"), - Gy: BigInt("0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5") -}))(); -const p384_CURVE = /* @__PURE__ */ (() => ({ - p: BigInt("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff"), - n: BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973"), - h: BigInt(1), - a: BigInt("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc"), - b: BigInt("0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef"), - Gx: BigInt("0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7"), - Gy: BigInt("0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f") -}))(); -/** -* NIST P256 (aka secp256r1, prime256v1) curve, ECDSA and ECDH methods. -* Hashes inputs with sha256 by default. -* -* @example -* Generate one P-256 keypair, sign a message, and verify it. -* -* ```js -* import { p256 } from '@noble/curves/nist.js'; -* const { secretKey, publicKey } = p256.keygen(); -* const recovered = p256.getPublicKey(secretKey); -* const peer = p256.keygen(); -* const shared = p256.getSharedSecret(secretKey, peer.publicKey); -* const msg = new TextEncoder().encode('hello noble'); -* const sig = p256.sign(msg, secretKey, { lowS: true, prehash: true }); -* const isValid = p256.verify(sig, msg, publicKey); -* // const sigKeccak = p256.sign(keccak256(msg), secretKey, { prehash: false }); -* ``` -*/ -const p256 = /* @__PURE__ */ ecdsa(/* @__PURE__ */ weierstrass(p256_CURVE), sha256$2); -/** -* NIST P384 (aka secp384r1) curve, ECDSA and ECDH methods. Hashes inputs with sha384 by default. -* @example -* Generate one P-384 keypair, sign a message, and verify it. -* -* ```ts -* const { secretKey, publicKey } = p384.keygen(); -* const msg = new TextEncoder().encode('hello noble'); -* const sig = p384.sign(msg, secretKey); -* const isValid = p384.verify(sig, msg, publicKey); -* ``` -*/ -const p384 = /* @__PURE__ */ ecdsa(/* @__PURE__ */ weierstrass(p384_CURVE), sha384); -//#endregion -//#region tests/baseline/node_modules/@scure/base/index.js -/*! scure-base - MIT License (c) 2022 Paul Miller (paulmillr.com) */ -const freeze = (fn) => Object.freeze(fn()); -function isBytes(a) { - return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array" && "BYTES_PER_ELEMENT" in a && a.BYTES_PER_ELEMENT === 1; -} -/** Asserts something is Uint8Array. */ -function abytes(b) { - if (!isBytes(b)) throw new TypeError("Uint8Array expected"); -} -function astr(label, input) { - if (typeof input !== "string") throw new TypeError(`${label}: string expected`); - return true; -} -function anumber(n, title = "number") { - if (typeof n !== "number") throw new TypeError(`${title}: expected number, got ${typeof n}`); - if (!Number.isSafeInteger(n)) throw new RangeError(`${title}: expected safe integer, got ${n}`); -} -function chain(...args) { - const id = (a) => a; - const wrap = (a, b) => (c) => a(b(c)); - return { - encode: args.map((x) => x.encode).reduceRight(wrap, id), - decode: args.map((x) => x.decode).reduce(wrap, id) - }; -} -const powers = /* @__PURE__ */ (() => { - let res = []; - for (let i = 0; i < 40; i++) res.push(2 ** i); - return res; -})(); -const asciiDecoder = /* @__PURE__ */ (() => { - try { - const decoder = new TextDecoder(); - return decoder.decode(Uint8Array.of(65, 48, 43, 127)) === "A0+" ? decoder : void 0; - } catch (e) { - return; - } -})(); -const B2S_CHUNK = 8192; -function charcodesToString(codes) { - const len = codes.length; - if (asciiDecoder !== void 0 && len >= 12) return asciiDecoder.decode(codes); - if (len <= B2S_CHUNK) return String.fromCharCode.apply(null, codes); - let res = ""; - for (let i = 0; i < len; i += B2S_CHUNK) res += String.fromCharCode.apply(null, codes.subarray(i, i + B2S_CHUNK)); - return res; -} -/** -* Linear 8 <-> bits regrouping (radix2Slow semantics), with Uint8Array digits and -* preallocated output. -*/ -function radix2(bits) { - anumber(bits); - if (bits <= 0 || bits > 8) throw new RangeError("radix2: bits should be in (0..8]"); - const mask = powers[bits] - 1; - return { - encode: (bytes) => { - abytes(bytes); - const len = bytes.length; - const res = new Uint8Array(Math.ceil(len * 8 / bits)); - let carry = 0; - let pos = 0; - let j = 0; - for (let i = 0; i < len;) { - if (i + 2 < len) { - carry = carry << 24 | bytes[i] << 16 | bytes[i + 1] << 8 | bytes[i + 2]; - pos += 24; - i += 3; - } else { - carry = (carry << 8 | bytes[i]) & 65535; - pos += 8; - i++; - } - for (;;) { - pos -= bits; - res[j++] = carry >> pos & mask; - if (pos < bits) break; - } - } - if (pos > 0) res[j] = carry << bits - pos & mask; - return res; - }, - decode: (digits) => { - const len = digits.length; - const res = new Uint8Array(Math.floor(len * bits / 8)); - let carry = 0; - let pos = 0; - let j = 0; - for (let i = 0; i < len; i++) { - carry = (carry << bits | digits[i]) & 65535; - pos += bits; - for (; pos >= 8; pos -= 8) res[j++] = carry >> pos - 8 & 255; - } - carry = carry << 8 - pos & 255; - if (pos >= bits) throw new Error("Excess padding"); - if (carry > 0) throw new Error(`Non-zero padding: ${carry}`); - return res; - } - }; -} -/** -* Digit <-> letter mapping fused with string join (chain(alphabetSlow(letters), join('')) -* semantics), via char-code lookup tables. -*/ -function alphabet(letters, aliases) { - const len = letters.length; - if (len > 128) throw new Error("alphabet: max 128 letters"); - const encTable = new Uint8Array(len); - const decTable = (/* @__PURE__ */ new Int8Array(128)).fill(-1); - for (let i = 0; i < len; i++) { - const code = letters.charCodeAt(i); - if (letters.codePointAt(i) !== code || code > 127) throw new Error("alphabet: single-char ASCII letters only"); - encTable[i] = code; - decTable[code] = i; - } - if (aliases !== void 0) for (const alias of Object.keys(aliases)) { - const code = alias.charCodeAt(0); - const target = decTable[aliases[alias].charCodeAt(0)]; - if (alias.length !== 1 || code > 127 || target === void 0 || target === -1) throw new Error(`alphabet: invalid alias ${alias}`); - decTable[code] = target; - } - return { - encode: (digits) => { - const codes = new Uint8Array(digits.length); - for (let i = 0; i < digits.length; i++) { - const d = digits[i]; - const code = encTable[d]; - if (code === void 0) throw new Error(`alphabet.encode: invalid digit ${d}`); - codes[i] = code; - } - return charcodesToString(codes); - }, - decode: (input) => { - astr("decode", input); - const slen = input.length; - const digits = new Uint8Array(slen); - for (let i = 0; i < slen; i++) { - const code = input.charCodeAt(i); - const digit = code < 128 ? decTable[code] : -1; - if (digit === -1) throw new Error(`Unknown letter "${input[i]}". Allowed: ${letters}`); - digits[i] = digit; - } - return digits; - } - }; -} -/** -* Pad / unpad (paddingSlow semantics), on the joined string. -*/ -function padding(bits, chr = "=") { - anumber(bits); - astr("padding", chr); - return { - encode(data) { - while (data.length * bits % 8) data += chr; - return data; - }, - decode(input) { - astr("decode", input); - let end = input.length; - if (end * bits % 8) throw new Error("padding: invalid length"); - for (; end > 0 && input[end - 1] === chr; end--) if ((end - 1) * bits % 8 === 0) throw new Error("padding: excess padding"); - return input.slice(0, end); - } - }; -} -const hasBase64Builtin = /* @__PURE__ */ (() => typeof Uint8Array.from([]).toBase64 === "function" && typeof Uint8Array.fromBase64 === "function")(); -const ASCII_WHITESPACE = /[\t\n\f\r ]/; -const decodeBase64Builtin = (s, isUrl) => { - astr("base64", s); - const alphabet = isUrl ? "base64url" : "base64"; - if (s.length > 0 && ASCII_WHITESPACE.test(s)) throw new Error("invalid base64"); - return Uint8Array.fromBase64(s, { - alphabet, - lastChunkHandling: "strict" - }); -}; -/** base64 from RFC 4648. Padded. Pure JS version */ -const base64Fallback = /* @__PURE__ */ freeze(() => chain(radix2(6), alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"), padding(6))); -/** -* base64 from RFC 4648. Padded. -* Alternative variants: `base64nopad`, `base64url`, `base64urlnopad`. -* Utilizes native `Uint8Array.fromBase64` builtin, otherwise falls back to `base64fallback` when it's unavailable. -* @example -* ```js -* base64.encode(Uint8Array.from([0x12, 0xab])); -* // => 'Eqs=' -* base64.decode('Eqs='); -* // => Uint8Array.from([0x12, 0xab]) -* ``` -*/ -const base64 = /* @__PURE__ */ freeze(() => hasBase64Builtin ? { - encode(b) { - abytes(b); - return b.toBase64(); - }, - decode(s) { - return decodeBase64Builtin(s, false); - } -} : base64Fallback); -//#endregion -//#region tests/baseline/node_modules/@noble/post-quantum/ml-kem.js -/** -* ML-KEM: Module Lattice-based Key Encapsulation Mechanism from -* [FIPS-203](https://csrc.nist.gov/pubs/fips/203/ipd). A.k.a. CRYSTALS-Kyber. -* -* Key encapsulation is similar to DH / ECDH (think X25519), with important differences: -* * Unlike in ECDH, we can't verify if it was "Bob" who've sent the shared secret -* * Unlike ECDH, it is probabalistic and relies on quality of randomness (CSPRNG). -* * Decapsulation never throws an error, even when shared secret was -* encrypted by a different public key. It will just return a different shared secret. -* -* There are some concerns with regards to security: see -* [djb blog](https://blog.cr.yp.to/20231003-countcorrectly.html) and -* [mailing list](https://groups.google.com/a/list.nist.gov/g/pqc-forum/c/W2VOzy0wz_E). -* -* Has similar internals to ML-DSA, but their keys and params are different. -* -* Check out [official site](https://www.pq-crystals.org/kyber/resources.shtml), -* [repo](https://github.com/pq-crystals/kyber), -* [spec](https://datatracker.ietf.org/doc/draft-cfrg-schwabe-kyber/). -* @module -*/ -/*! noble-post-quantum - MIT License (c) 2024 Paul Miller (paulmillr.com) */ -/** Key encapsulation mechanism interface */ -const N = 256; -const Q = 3329; -const crystals = /* @__PURE__ */ genCrystals({ - N, - Q, - F: 3303, - ROOT_OF_UNITY: 17, - newPoly: (n) => new Uint16Array(n), - brvBits: 7, - isKyber: true -}); -/** Internal params of ML-KEM versions */ -/** Built-in ML-KEM parameter presets keyed by the public export names -* `ml_kem512` / `ml_kem768` / `ml_kem1024`. -* `RBGstrength` is Table 2's required randomness-source strength in bits, -* not a generic security label. -*/ -const PARAMS = /* @__PURE__ */ (() => Object.freeze({ - 512: Object.freeze({ - N, - Q, - K: 2, - ETA1: 3, - ETA2: 2, - du: 10, - dv: 4, - RBGstrength: 128 - }), - 768: Object.freeze({ - N, - Q, - K: 3, - ETA1: 2, - ETA2: 2, - du: 10, - dv: 4, - RBGstrength: 192 - }), - 1024: Object.freeze({ - N, - Q, - K: 4, - ETA1: 2, - ETA2: 2, - du: 11, - dv: 5, - RBGstrength: 256 - }) -}))(); -const compress = (d) => { - if (d >= 12) return { - encode: (i) => i, - decode: (i) => i >= Q ? i - Q : i - }; - const a = 2 ** (d - 1); - return { - encode: (i) => ((i << d) + Q / 2) / Q, - decode: (i) => i * Q + a >>> d - }; -}; -const byteCoder = (d) => crystals.bitsCoder(d, d === 12 ? { - encode: (i) => i, - decode: (i) => i >= Q ? i - Q : i -} : { - encode: (i) => i, - decode: (i) => i -}); -const polyCoder = (d) => d === 12 ? byteCoder(12) : crystals.bitsCoder(d, compress(d)); -function polyAdd(a_, b_) { - const a = a_; - const b = b_; - for (let i = 0; i < N; i++) a[i] = crystals.mod(a[i] + b[i]); -} -function polySub(a_, b_) { - const a = a_; - const b = b_; - for (let i = 0; i < N; i++) a[i] = crystals.mod(a[i] - b[i]); -} -function BaseCaseMultiply(a0, a1, b0, b1, zeta) { - return { - c0: crystals.mod(a1 * b1 * zeta + a0 * b0), - c1: crystals.mod(a0 * b1 + a1 * b0) - }; -} -function MultiplyNTTs(f_, g_) { - const f = f_; - const g = g_; - for (let i = 0; i < N / 2; i++) { - let z = crystals.nttZetas[64 + (i >> 1)]; - if (i & 1) z = -z; - const { c0, c1 } = BaseCaseMultiply(f[2 * i + 0], f[2 * i + 1], g[2 * i + 0], g[2 * i + 1], z); - f[2 * i + 0] = c0; - f[2 * i + 1] = c1; - } - return f; -} -function SampleNTT(xof_) { - const xof = xof_; - const r = new Uint16Array(N); - for (let j = 0; j < N;) { - const b = xof(); - if (b.length % 3) throw new Error("SampleNTT: unaligned block"); - for (let i = 0; j < N && i + 3 <= b.length; i += 3) { - const d1 = (b[i + 0] >> 0 | b[i + 1] << 8) & 4095; - const d2 = (b[i + 1] >> 4 | b[i + 2] << 4) & 4095; - if (d1 < Q) r[j++] = d1; - if (j < N && d2 < Q) r[j++] = d2; - } - } - return r; -} -const sampleCBDBytes = (buf, eta) => { - const r = new Uint16Array(N); - const b32 = u32(buf); - swap32IfBE(b32); - let len = 0; - for (let i = 0, p = 0, bb = 0, t0 = 0; i < b32.length; i++) { - let b = b32[i]; - for (let j = 0; j < 32; j++) { - bb += b & 1; - b >>= 1; - len += 1; - if (len === eta) { - t0 = bb; - bb = 0; - } else if (len === 2 * eta) { - r[p++] = crystals.mod(t0 - bb); - bb = 0; - len = 0; - } - } - } - swap32IfBE(b32); - if (len) throw new Error(`sampleCBD: leftover bits: ${len}`); - return r; -}; -function sampleCBD(PRF_, seed, nonce, eta) { - return sampleCBDBytes(PRF_(eta * N / 4, seed, nonce), eta); -} -const genKPKE = (opts_) => { - const { K, PRF, XOF, HASH512, ETA1, ETA2, du, dv } = opts_; - const poly1 = polyCoder(1); - const polyV = polyCoder(dv); - const polyU = polyCoder(du); - const publicCoder = splitCoder("publicKey", vecCoder(polyCoder(12), K), 32); - const secretCoder = vecCoder(polyCoder(12), K); - const cipherCoder = splitCoder("ciphertext", vecCoder(polyU, K), polyV); - const seedCoder = splitCoder("seed", 32, 32); - return { - secretCoder, - lengths: { - secretKey: secretCoder.bytesLen, - publicKey: publicCoder.bytesLen, - cipherText: cipherCoder.bytesLen - }, - keygen: (seed) => { - abytesDoc(seed, 32, "seed"); - const seedDst = /* @__PURE__ */ new Uint8Array(33); - seedDst.set(seed); - seedDst[32] = K; - const seedHash = HASH512(seedDst); - const [rho, sigma] = seedCoder.decode(seedHash); - const sHat = []; - const tHat = []; - for (let i = 0; i < K; i++) sHat.push(crystals.NTT.encode(sampleCBD(PRF, sigma, i, ETA1))); - const x = XOF(rho); - for (let i = 0; i < K; i++) { - const e = crystals.NTT.encode(sampleCBD(PRF, sigma, K + i, ETA1)); - for (let j = 0; j < K; j++) polyAdd(e, MultiplyNTTs(SampleNTT(x.get(j, i)), sHat[j])); - tHat.push(e); - } - x.clean(); - const res = { - publicKey: publicCoder.encode([tHat, rho]), - secretKey: secretCoder.encode(sHat) - }; - cleanBytes(rho, sigma, sHat, tHat, seedDst, seedHash); - return res; - }, - encrypt: (publicKey, msg, seed) => { - const [tHat, rho] = publicCoder.decode(publicKey); - const rHat = []; - for (let i = 0; i < K; i++) rHat.push(crystals.NTT.encode(sampleCBD(PRF, seed, i, ETA1))); - const x = XOF(rho); - const tmp2 = new Uint16Array(N); - const u = []; - for (let i = 0; i < K; i++) { - const e1 = sampleCBD(PRF, seed, K + i, ETA2); - const tmp = new Uint16Array(N); - for (let j = 0; j < K; j++) polyAdd(tmp, MultiplyNTTs(SampleNTT(x.get(i, j)), rHat[j])); - polyAdd(e1, crystals.NTT.decode(tmp)); - u.push(e1); - polyAdd(tmp2, MultiplyNTTs(tHat[i], rHat[i])); - cleanBytes(tmp); - } - x.clean(); - const e2 = sampleCBD(PRF, seed, 2 * K, ETA2); - polyAdd(e2, crystals.NTT.decode(tmp2)); - const v = poly1.decode(msg); - polyAdd(v, e2); - cleanBytes(tHat, rHat, tmp2, e2); - return cipherCoder.encode([u, v]); - }, - decrypt: (cipherText, privateKey) => { - const [u, v] = cipherCoder.decode(cipherText); - const sk = secretCoder.decode(privateKey); - const tmp = new Uint16Array(N); - for (let i = 0; i < K; i++) polyAdd(tmp, MultiplyNTTs(sk[i], crystals.NTT.encode(u[i]))); - polySub(v, crystals.NTT.decode(tmp)); - cleanBytes(tmp, sk, u); - return poly1.encode(v); - } - }; -}; -/** -* Public ML-KEM wrapper over the internal K-PKE subroutine. -* `keygen(seed)` and `encapsulate(publicKey, msg)` are deterministic/test-oriented hooks that map -* more directly to Algorithms 16-17 than to the pure no-input / random-internal Algorithms 19-20. -* decapsulate() tries to follow the Algorithms 18/21 implicit-reject structure as closely as -* practical here by re-encrypting, comparing ciphertexts, returning `Khat` on match or `Kbar` on -* mismatch, and zeroizing the non-returned shared-secret candidate; JS/JIT still provides no -* constant-time guarantees for that path. -*/ -function createKyber(opts) { - const rawOpts = opts; - const KPKE = genKPKE(rawOpts); - const { HASH256, HASH512, KDF } = rawOpts; - const { secretCoder: KPKESecretCoder, lengths } = KPKE; - const secretCoder = splitCoder("secretKey", lengths.secretKey, lengths.publicKey, 32, 32); - const msgLen = 32; - const seedLen = 64; - const kemLengths = Object.freeze({ - ...lengths, - seed: 64, - msg: msgLen, - msgRand: msgLen, - secretKey: secretCoder.bytesLen - }); - return Object.freeze({ - info: Object.freeze({ type: "ml-kem" }), - lengths: kemLengths, - keygen: (seed = randomBytes(seedLen)) => { - abytesDoc(seed, seedLen, "seed"); - const { publicKey, secretKey: sk } = KPKE.keygen(seed.subarray(0, 32)); - const publicKeyHash = HASH256(publicKey); - const secretKey = secretCoder.encode([ - sk, - publicKey, - publicKeyHash, - seed.subarray(32) - ]); - cleanBytes(sk, publicKeyHash); - return { - publicKey, - secretKey - }; - }, - getPublicKey: (secretKey) => { - const [_sk, publicKey, _publicKeyHash, _z] = secretCoder.decode(secretKey); - return Uint8Array.from(publicKey); - }, - encapsulate: (publicKey, msg = randomBytes(msgLen)) => { - abytesDoc(publicKey, lengths.publicKey, "publicKey"); - abytesDoc(msg, msgLen, "message"); - const eke = publicKey.subarray(0, 384 * opts.K); - const ek = KPKESecretCoder.encode(KPKESecretCoder.decode(copyBytes(eke))); - if (!equalBytes(ek, eke)) { - cleanBytes(ek); - throw new Error("ML-KEM.encapsulate: wrong publicKey modulus"); - } - cleanBytes(ek); - const kr = HASH512.create().update(msg).update(HASH256(publicKey)).digest(); - const cipherText = KPKE.encrypt(publicKey, msg, kr.subarray(32, 64)); - cleanBytes(kr.subarray(32)); - return { - cipherText, - sharedSecret: kr.subarray(0, 32) - }; - }, - decapsulate: (cipherText, secretKey) => { - abytesDoc(secretKey, secretCoder.bytesLen, "secretKey"); - abytesDoc(cipherText, lengths.cipherText, "cipherText"); - const k768 = secretCoder.bytesLen - 96; - const start = k768 + 32; - if (!equalBytes(HASH256(secretKey.subarray(k768 / 2, start)), secretKey.subarray(start, start + 32))) throw new Error("invalid secretKey: hash check failed"); - const [sk, publicKey, publicKeyHash, z] = secretCoder.decode(secretKey); - const msg = KPKE.decrypt(cipherText, sk); - const kr = HASH512.create().update(msg).update(publicKeyHash).digest(); - const Khat = kr.subarray(0, 32); - const cipherText2 = KPKE.encrypt(publicKey, msg, kr.subarray(32, 64)); - const isValid = equalBytes(cipherText, cipherText2); - const Kbar = KDF.create({ dkLen: 32 }).update(z).update(cipherText).digest(); - cleanBytes(msg, cipherText2, !isValid ? Khat : Kbar); - return isValid ? Khat : Kbar; - } - }); -} -function shakePRF(dkLen, key, nonce) { - return shake256.create({ dkLen }).update(key).update(new Uint8Array([nonce])).digest(); -} -const opts = /* @__PURE__ */ (() => ({ - HASH256: sha3_256, - HASH512: sha3_512, - KDF: shake256, - XOF: XOF128, - PRF: shakePRF -}))(); -const mk = (params) => createKyber({ - ...opts, - ...params -}); -/** -* ML-KEM-512: Table 2 row `k=2, η1=3, η2=2, du=10, dv=4`; Table 3 sizes `800/1632/768/32`. -* The ASD lifecycle note here is external policy guidance, not a FIPS 203 requirement. -*/ -const ml_kem512 = /* @__PURE__ */ (() => mk(PARAMS[512]))(); -/** -* ML-KEM-768: Table 2 row `k=3, η1=2, η2=2, du=10, dv=4`; Table 3 sizes `1184/2400/1088/32`. -* The ASD lifecycle note here is external policy guidance, not a FIPS 203 requirement. -*/ -const ml_kem768 = /* @__PURE__ */ (() => mk(PARAMS[768]))(); -/** -* ML-KEM-1024: Table 2 row `k=4, η1=2, η2=2, du=11, dv=5`; Table 3 sizes `1568/3168/1568/32`. -* The ASD lifecycle note here is external policy guidance, not a FIPS 203 requirement. -*/ -const ml_kem1024 = /* @__PURE__ */ (() => mk(PARAMS[1024]))(); -//#endregion -//#region tests/baseline/node_modules/@bcts/shamir/dist/index.mjs -/** -* Error class for Shamir secret sharing operations. -*/ -var ShamirError = class ShamirError extends Error { - type; - constructor(type, message) { - super(message ?? ShamirError.defaultMessage(type)); - this.type = type; - this.name = "ShamirError"; - } - static defaultMessage(type) { - switch (type) { - case "SecretTooLong": return "secret is too long"; - case "TooManyShares": return "too many shares"; - case "InterpolationFailure": return "interpolation failed"; - case "ChecksumFailure": return "checksum failure"; - case "SecretTooShort": return "secret is too short"; - case "SecretNotEvenLen": return "secret is not of even length"; - case "InvalidThreshold": return "invalid threshold"; - case "SharesUnequalLength": return "shares have unequal length"; - } - } -}; -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -*/ -/** -* Internal contract guard. Mirrors a Rust `assert!(condition, message)` -* panic on the boundary between hazmat helpers — kept as a bare `Error` -* so it cannot be confused with a `ShamirError` from the public API. -*/ -function assertContract(condition, message) { - if (!condition) throw new Error(message); -} -/** -* Convert an array of bytes into a bitsliced representation. -* Takes the first 32 bytes from x and produces 8 u32 values. -* -* @param r - Output array of 8 u32 values (bitsliced representation) -* @param x - Input array of at least 32 bytes -*/ -function bitslice(r, x) { - assertContract(x.length >= 32, "bitslice: input must be at least 32 bytes"); - assertContract(r.length === 8, "bitslice: output must have 8 elements"); - memzero(r); - for (let arrIdx = 0; arrIdx < 32; arrIdx++) { - const cur = x[arrIdx]; - for (let bitIdx = 0; bitIdx < 8; bitIdx++) r[bitIdx] |= (cur & 1 << bitIdx) >>> bitIdx << arrIdx; - } -} -/** -* Convert a bitsliced representation back to bytes. -* -* @param r - Output array of at least 32 bytes -* @param x - Input array of 8 u32 values (bitsliced representation) -*/ -function unbitslice(r, x) { - assertContract(r.length >= 32, "unbitslice: output must be at least 32 bytes"); - assertContract(x.length === 8, "unbitslice: input must have 8 elements"); - memzero(r.subarray(0, 32)); - for (let bitIdx = 0; bitIdx < 8; bitIdx++) { - const cur = x[bitIdx]; - for (let arrIdx = 0; arrIdx < 32; arrIdx++) r[arrIdx] |= (cur & 1 << arrIdx) >>> arrIdx << bitIdx; - } -} -/** -* Set all 32 positions in a bitsliced array to the same byte value. -* -* @param r - Output array of 8 u32 values -* @param x - Byte value to set in all positions -*/ -function bitsliceSetall(r, x) { - assertContract(r.length === 8, "bitsliceSetall: output must have 8 elements"); - for (let idx = 0; idx < 8; idx++) { - const bit = x >>> idx & 1; - r[idx] = bit === 1 ? 4294967295 : 0; - } -} -/** -* Add (XOR) r with x and store the result in r. -* In GF(2^8), addition is XOR. -* -* @param r - First operand and result -* @param x - Second operand -*/ -function gf256Add(r, x) { - assertContract(r.length === 8 && x.length === 8, "gf256Add: arrays must have 8 elements"); - for (let i = 0; i < 8; i++) r[i] ^= x[i]; -} -/** -* Safely multiply two bitsliced polynomials in GF(2^8) reduced by -* x^8 + x^4 + x^3 + x + 1. r and a may overlap, but overlapping of r -* and b will produce an incorrect result! If you need to square a polynomial -* use gf256Square instead. -* -* @param r - Result array (8 u32 values) -* @param a - First operand (may overlap with r) -* @param b - Second operand (must NOT overlap with r) -*/ -function gf256Mul(r, a, b) { - assertContract(r.length === 8 && a.length === 8 && b.length === 8, "gf256Mul: arrays must have 8 elements"); - const a2 = new Uint32Array(a); - r[0] = a2[0] & b[0]; - r[1] = a2[1] & b[0]; - r[2] = a2[2] & b[0]; - r[3] = a2[3] & b[0]; - r[4] = a2[4] & b[0]; - r[5] = a2[5] & b[0]; - r[6] = a2[6] & b[0]; - r[7] = a2[7] & b[0]; - a2[0] ^= a2[7]; - a2[2] ^= a2[7]; - a2[3] ^= a2[7]; - r[0] ^= a2[7] & b[1]; - r[1] ^= a2[0] & b[1]; - r[2] ^= a2[1] & b[1]; - r[3] ^= a2[2] & b[1]; - r[4] ^= a2[3] & b[1]; - r[5] ^= a2[4] & b[1]; - r[6] ^= a2[5] & b[1]; - r[7] ^= a2[6] & b[1]; - a2[7] ^= a2[6]; - a2[1] ^= a2[6]; - a2[2] ^= a2[6]; - r[0] ^= a2[6] & b[2]; - r[1] ^= a2[7] & b[2]; - r[2] ^= a2[0] & b[2]; - r[3] ^= a2[1] & b[2]; - r[4] ^= a2[2] & b[2]; - r[5] ^= a2[3] & b[2]; - r[6] ^= a2[4] & b[2]; - r[7] ^= a2[5] & b[2]; - a2[6] ^= a2[5]; - a2[0] ^= a2[5]; - a2[1] ^= a2[5]; - r[0] ^= a2[5] & b[3]; - r[1] ^= a2[6] & b[3]; - r[2] ^= a2[7] & b[3]; - r[3] ^= a2[0] & b[3]; - r[4] ^= a2[1] & b[3]; - r[5] ^= a2[2] & b[3]; - r[6] ^= a2[3] & b[3]; - r[7] ^= a2[4] & b[3]; - a2[5] ^= a2[4]; - a2[7] ^= a2[4]; - a2[0] ^= a2[4]; - r[0] ^= a2[4] & b[4]; - r[1] ^= a2[5] & b[4]; - r[2] ^= a2[6] & b[4]; - r[3] ^= a2[7] & b[4]; - r[4] ^= a2[0] & b[4]; - r[5] ^= a2[1] & b[4]; - r[6] ^= a2[2] & b[4]; - r[7] ^= a2[3] & b[4]; - a2[4] ^= a2[3]; - a2[6] ^= a2[3]; - a2[7] ^= a2[3]; - r[0] ^= a2[3] & b[5]; - r[1] ^= a2[4] & b[5]; - r[2] ^= a2[5] & b[5]; - r[3] ^= a2[6] & b[5]; - r[4] ^= a2[7] & b[5]; - r[5] ^= a2[0] & b[5]; - r[6] ^= a2[1] & b[5]; - r[7] ^= a2[2] & b[5]; - a2[3] ^= a2[2]; - a2[5] ^= a2[2]; - a2[6] ^= a2[2]; - r[0] ^= a2[2] & b[6]; - r[1] ^= a2[3] & b[6]; - r[2] ^= a2[4] & b[6]; - r[3] ^= a2[5] & b[6]; - r[4] ^= a2[6] & b[6]; - r[5] ^= a2[7] & b[6]; - r[6] ^= a2[0] & b[6]; - r[7] ^= a2[1] & b[6]; - a2[2] ^= a2[1]; - a2[4] ^= a2[1]; - a2[5] ^= a2[1]; - r[0] ^= a2[1] & b[7]; - r[1] ^= a2[2] & b[7]; - r[2] ^= a2[3] & b[7]; - r[3] ^= a2[4] & b[7]; - r[4] ^= a2[5] & b[7]; - r[5] ^= a2[6] & b[7]; - r[6] ^= a2[7] & b[7]; - r[7] ^= a2[0] & b[7]; -} -/** -* Square x in GF(2^8) and write the result to r. -* r and x may overlap. -* -* @param r - Result array (8 u32 values) -* @param x - Value to square -*/ -function gf256Square(r, x) { - assertContract(r.length === 8 && x.length === 8, "gf256Square: arrays must have 8 elements"); - const r14 = x[7]; - const r12 = x[6]; - let r10 = x[5]; - let r8 = x[4]; - r[6] = x[3]; - r[4] = x[2]; - r[2] = x[1]; - r[0] = x[0]; - r[7] = r14; - r[6] ^= r14; - r10 ^= r14; - r[4] ^= r12; - r[5] = r12; - r[7] ^= r12; - r8 ^= r12; - r[2] ^= r10; - r[3] = r10; - r[5] ^= r10; - r[6] ^= r10; - r[1] = r14; - r[2] ^= r14; - r[4] ^= r14; - r[5] ^= r14; - r[0] ^= r8; - r[1] ^= r8; - r[3] ^= r8; - r[4] ^= r8; -} -/** -* Invert x in GF(2^8) and write the result to r. -* -* @param r - Result array (8 u32 values) -* @param x - Value to invert (will be modified) -*/ -function gf256Inv(r, x) { - assertContract(r.length === 8 && x.length === 8, "gf256Inv: arrays must have 8 elements"); - const y = /* @__PURE__ */ new Uint32Array(8); - const z = /* @__PURE__ */ new Uint32Array(8); - gf256Square(y, x); - gf256Square(y, new Uint32Array(y)); - gf256Square(r, y); - gf256Mul(z, r, x); - gf256Square(r, new Uint32Array(r)); - gf256Mul(r, new Uint32Array(r), z); - gf256Square(r, new Uint32Array(r)); - gf256Square(z, r); - gf256Square(z, new Uint32Array(z)); - gf256Mul(r, new Uint32Array(r), z); - gf256Mul(r, new Uint32Array(r), y); -} -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -*/ -/** -* Calculate the lagrange basis coefficients for the lagrange polynomial -* defined by the x coordinates xc at the value x. -* -* After the function runs, the values array should hold data satisfying: -* --- (x-xc[j]) -* values[i] = | | ------------- -* j != i (xc[i]-xc[j]) -* -* @param values - Output array for the lagrange basis values -* @param n - Number of points (length of the xc array, 0 < n <= 32) -* @param xc - Array of x components to use as interpolating points -* @param x - x coordinate to evaluate lagrange polynomials at -*/ -function hazmatLagrangeBasis(values, n, xc, x) { - const xx = /* @__PURE__ */ new Uint8Array(48); - const xSlice = /* @__PURE__ */ new Uint32Array(8); - const lxi = []; - for (let i = 0; i < n; i++) lxi.push(/* @__PURE__ */ new Uint32Array(8)); - const numerator = /* @__PURE__ */ new Uint32Array(8); - const denominator = /* @__PURE__ */ new Uint32Array(8); - const temp = /* @__PURE__ */ new Uint32Array(8); - xx.set(xc.subarray(0, n), 0); - for (let i = 0; i < n; i++) { - bitslice(lxi[i], xx.subarray(i)); - xx[i + n] = xx[i]; - } - bitsliceSetall(xSlice, x); - bitsliceSetall(numerator, 1); - bitsliceSetall(denominator, 1); - for (let i = 1; i < n; i++) { - temp.set(xSlice); - gf256Add(temp, lxi[i]); - gf256Mul(numerator, new Uint32Array(numerator), temp); - temp.set(lxi[0]); - gf256Add(temp, lxi[i]); - gf256Mul(denominator, new Uint32Array(denominator), temp); - } - gf256Inv(temp, denominator); - gf256Mul(numerator, new Uint32Array(numerator), temp); - unbitslice(xx, numerator); - values.set(xx.subarray(0, n), 0); -} -/** -* Safely interpolate the polynomial going through -* the points (x0 [y0_0 y0_1 y0_2 ... y0_31]) , (x1 [y1_0 ...]), ... -* -* where -* xi points to [x0 x1 ... xn-1 ] -* y contains an array of pointers to 32-bit arrays of y values -* y contains [y0 y1 y2 ... yn-1] -* and each of the yi arrays contain [yi_0 yi_i ... yi_31]. -* -* @param n - Number of points to interpolate -* @param xi - x coordinates for points (array of length n) -* @param yl - Length of y coordinate arrays -* @param yij - Array of n arrays of length yl -* @param x - Coordinate to interpolate at -* @returns The interpolated result of length yl -*/ -function interpolate(n, xi, yl, yij, x) { - const y = []; - for (let i = 0; i < n; i++) y.push(/* @__PURE__ */ new Uint8Array(32)); - const values = /* @__PURE__ */ new Uint8Array(32); - for (let i = 0; i < n; i++) y[i].set(yij[i].subarray(0, yl), 0); - const lagrange = new Uint8Array(n); - const ySlice = /* @__PURE__ */ new Uint32Array(8); - const resultSlice = /* @__PURE__ */ new Uint32Array(8); - const temp = /* @__PURE__ */ new Uint32Array(8); - hazmatLagrangeBasis(lagrange, n, xi, x); - bitsliceSetall(resultSlice, 0); - for (let i = 0; i < n; i++) { - bitslice(ySlice, y[i]); - bitsliceSetall(temp, lagrange[i]); - gf256Mul(temp, new Uint32Array(temp), ySlice); - gf256Add(resultSlice, temp); - } - unbitslice(values, resultSlice); - const result = new Uint8Array(yl); - result.set(values.subarray(0, yl), 0); - memzero(lagrange); - memzero(ySlice); - memzero(resultSlice); - memzero(temp); - memzeroVecVecU8(y); - memzero(values); - return result; -} -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -*/ -const SECRET_INDEX = 255; -const DIGEST_INDEX = 254; -function createDigest(randomData, sharedSecret) { - return hmacSha256(randomData, sharedSecret); -} -function validateParameters(threshold, shareCount, secretLength) { - if (shareCount > 16) throw new ShamirError("TooManyShares"); - else if (threshold < 1 || threshold > shareCount) throw new ShamirError("InvalidThreshold"); - else if (secretLength > 32) throw new ShamirError("SecretTooLong"); - else if (secretLength < 16) throw new ShamirError("SecretTooShort"); - else if ((secretLength & 1) !== 0) throw new ShamirError("SecretNotEvenLen"); -} -/** -* Splits a secret into shares using the Shamir secret sharing algorithm. -* -* @param threshold - The minimum number of shares required to reconstruct the -* secret. Must be greater than or equal to 1 and less than or equal to -* shareCount. -* @param shareCount - The total number of shares to generate. Must be at least -* threshold and less than or equal to MAX_SHARE_COUNT. -* @param secret - A Uint8Array containing the secret to be split. Must be at -* least MIN_SECRET_LEN bytes long and at most MAX_SECRET_LEN bytes long. -* The length must be an even number. -* @param randomGenerator - An implementation of the RandomNumberGenerator -* interface, used to generate random data. -* @returns An array of Uint8Array representing the shares of the secret. -* @throws ShamirError if parameters are invalid -* -* @example -* ```typescript -* import { splitSecret } from "@bcts/shamir"; -* import { SecureRandomNumberGenerator } from "@bcts/rand"; -* -* const threshold = 2; -* const shareCount = 3; -* const secret = new TextEncoder().encode("my secret belongs to me."); -* const rng = new SecureRandomNumberGenerator(); -* -* const shares = splitSecret(threshold, shareCount, secret, rng); -* console.log(shares.length); // 3 -* ``` -*/ -function splitSecret(threshold, shareCount, secret, randomGenerator) { - validateParameters(threshold, shareCount, secret.length); - if (threshold === 1) { - const result = []; - for (let i = 0; i < shareCount; i++) result.push(new Uint8Array(secret)); - return result; - } else { - const x = new Uint8Array(shareCount); - const y = []; - for (let i = 0; i < shareCount; i++) y.push(new Uint8Array(secret.length)); - let n = 0; - const result = []; - for (let i = 0; i < shareCount; i++) result.push(new Uint8Array(secret.length)); - for (let index = 0; index < threshold - 2; index++) { - randomGenerator.fillRandomData(result[index]); - x[n] = index; - y[n].set(result[index]); - n++; - } - const digest = new Uint8Array(secret.length); - randomGenerator.fillRandomData(digest.subarray(4)); - const d = createDigest(digest.subarray(4), secret); - digest.set(d.subarray(0, 4), 0); - x[n] = DIGEST_INDEX; - y[n].set(digest); - n++; - x[n] = SECRET_INDEX; - y[n].set(secret); - n++; - for (let index = threshold - 2; index < shareCount; index++) { - const v = interpolate(n, x, secret.length, y, index); - result[index].set(v); - } - memzero(digest); - memzero(x); - memzeroVecVecU8(y); - return result; - } -} -/** -* Recovers the secret from the given shares using the Shamir secret sharing -* algorithm. -* -* @param indexes - An array of indexes of the shares to be used for recovering -* the secret. These are the indexes of the shares returned by splitSecret. -* @param shares - An array of shares of the secret matching the indexes in -* indexes. These are the shares returned by splitSecret. -* @returns A Uint8Array representing the recovered secret. -* @throws ShamirError if parameters are invalid or checksum verification fails -* -* @example -* ```typescript -* import { recoverSecret } from "@bcts/shamir"; -* -* const indexes = [0, 2]; -* const shares = [ -* new Uint8Array([47, 165, 102, 232, ...]), -* new Uint8Array([221, 174, 116, 201, ...]), -* ]; -* -* const secret = recoverSecret(indexes, shares); -* console.log(new TextDecoder().decode(secret)); // "my secret belongs to me." -* ``` -*/ -function recoverSecret(indexes, shares) { - const threshold = shares.length; - if (threshold === 0 || indexes.length !== threshold) throw new ShamirError("InvalidThreshold"); - const shareLength = shares[0].length; - validateParameters(threshold, threshold, shareLength); - if (!shares.every((share) => share.length === shareLength)) throw new ShamirError("SharesUnequalLength"); - if (threshold === 1) return new Uint8Array(shares[0]); - else { - const indexesU8 = new Uint8Array(indexes); - const digest = interpolate(threshold, indexesU8, shareLength, shares, DIGEST_INDEX); - const secret = interpolate(threshold, indexesU8, shareLength, shares, SECRET_INDEX); - const verify = createDigest(digest.subarray(4), secret); - let valid = true; - for (let i = 0; i < 4; i++) valid = valid && digest[i] === verify[i]; - memzero(digest); - memzero(verify); - if (!valid) throw new ShamirError("ChecksumFailure"); - return secret; - } -} -//#endregion -//#region tests/baseline/node_modules/@bcts/sskr/dist/index.mjs -/** -* Error class for SSKR operations. -*/ -var SSKRError = class SSKRError extends Error { - type; - shamirError; - constructor(type, message, shamirError) { - super(message ?? SSKRError.defaultMessage(type, shamirError)); - this.type = type; - this.shamirError = shamirError; - this.name = "SSKRError"; - } - static defaultMessage(type, shamirError) { - switch (type) { - case "DuplicateMemberIndex": return "When combining shares, the provided shares contained a duplicate member index"; - case "GroupSpecInvalid": return "Invalid group specification."; - case "GroupCountInvalid": return "When creating a split spec, the group count is invalid"; - case "GroupThresholdInvalid": return "SSKR group threshold is invalid"; - case "MemberCountInvalid": return "SSKR member count is invalid"; - case "MemberThresholdInvalid": return "SSKR member threshold is invalid"; - case "NotEnoughGroups": return "SSKR shares did not contain enough groups"; - case "SecretLengthNotEven": return "SSKR secret is not of even length"; - case "SecretTooLong": return "SSKR secret is too long"; - case "SecretTooShort": return "SSKR secret is too short"; - case "ShareLengthInvalid": return "SSKR shares did not contain enough serialized bytes"; - case "ShareReservedBitsInvalid": return "SSKR shares contained invalid reserved bits"; - case "SharesEmpty": return "SSKR shares were empty"; - case "ShareSetInvalid": return "SSKR shares were invalid"; - case "ShamirError": return shamirError != null ? `SSKR Shamir error: ${shamirError.message}` : "SSKR Shamir error"; - } - } - static fromShamirError(error) { - return new SSKRError("ShamirError", void 0, error); - } -}; -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -*/ -/** -* A secret to be split into shares. -*/ -var Secret = class Secret { - data; - constructor(data) { - this.data = data; - } - /** - * Creates a new Secret instance with the given data. - * - * @param data - The secret data to be split into shares. - * @returns A new Secret instance. - * @throws SSKRError if the length of the secret is less than - * MIN_SECRET_LEN, greater than MAX_SECRET_LEN, or not even. - */ - static new(data) { - const bytes = typeof data === "string" ? new TextEncoder().encode(data) : data; - const len = bytes.length; - if (len < MIN_SECRET_LEN) throw new SSKRError("SecretTooShort"); - if (len > MAX_SECRET_LEN) throw new SSKRError("SecretTooLong"); - if ((len & 1) !== 0) throw new SSKRError("SecretLengthNotEven"); - return new Secret(new Uint8Array(bytes)); - } - /** - * Returns the length of the secret. - */ - len() { - return this.data.length; - } - /** - * Returns true if the secret is empty. - */ - isEmpty() { - return this.len() === 0; - } - /** - * Returns a reference to the secret data. - * - * Mirrors Rust's `Secret::data(&self) -> &[u8]` - * (`bc-sskr-rust/src/secret.rs:43`). - */ - getData() { - return this.data; - } - /** - * Returns the secret data as a Uint8Array. - * - * Mirrors Rust's `impl AsRef<[u8]> for Secret` - * (`bc-sskr-rust/src/secret.rs:46-49`). In Rust, `as_ref()` is - * provided via the `AsRef<[u8]>` trait, which lets the `Secret` flow - * naturally through any API expecting `impl AsRef<[u8]>`. TypeScript - * has no equivalent of that trait, so we expose the same backing - * buffer through both {@link getData} (the field accessor) and - * `asRef` (the trait-style accessor) for ergonomic parity. Callers - * may pick whichever name reads better at the call site. - */ - asRef() { - return this.data; - } - /** - * Check equality with another Secret. - */ - equals(other) { - if (this.data.length !== other.data.length) return false; - for (let i = 0; i < this.data.length; i++) if (this.data[i] !== other.data[i]) return false; - return true; - } - /** - * Clone the secret. - */ - clone() { - return new Secret(new Uint8Array(this.data)); - } -}; -/** -* A share in the SSKR scheme. -*/ -var SSKRShare = class { - _identifier; - _groupIndex; - _groupThreshold; - _groupCount; - _memberIndex; - _memberThreshold; - _value; - constructor(identifier, groupIndex, groupThreshold, groupCount, memberIndex, memberThreshold, value) { - this._identifier = identifier; - this._groupIndex = groupIndex; - this._groupThreshold = groupThreshold; - this._groupCount = groupCount; - this._memberIndex = memberIndex; - this._memberThreshold = memberThreshold; - this._value = value; - } - identifier() { - return this._identifier; - } - groupIndex() { - return this._groupIndex; - } - groupThreshold() { - return this._groupThreshold; - } - groupCount() { - return this._groupCount; - } - memberIndex() { - return this._memberIndex; - } - memberThreshold() { - return this._memberThreshold; - } - value() { - return this._value; - } -}; -/** -* Generates SSKR shares for the given Spec and Secret. -* -* @param spec - The Spec instance that defines the group and member thresholds. -* @param masterSecret - The Secret instance to be split into shares. -* @returns A vector of groups, each containing a vector of shares, -* each of which is a Uint8Array. -*/ -function sskrGenerate(spec, masterSecret) { - return sskrGenerateUsing(spec, masterSecret, new SecureRandomNumberGenerator()); -} -/** -* Generates SSKR shares for the given Spec and Secret using the provided -* random number generator. -* -* @param spec - The Spec instance that defines the group and member thresholds. -* @param masterSecret - The Secret instance to be split into shares. -* @param randomGenerator - The random number generator to use for generating -* shares. -* @returns A vector of groups, each containing a vector of shares, -* each of which is a Uint8Array. -*/ -function sskrGenerateUsing(spec, masterSecret, randomGenerator) { - return generateShares(spec, masterSecret, randomGenerator).map((group) => group.map(serializeShare)); -} -/** -* Combines the given SSKR shares into a Secret. -* -* @param shares - A array of SSKR shares to be combined. -* @returns The reconstructed Secret. -* @throws SSKRError if the shares do not meet the necessary quorum of groups -* and member shares within each group. -*/ -function sskrCombine(shares) { - const sskrShares = []; - for (const share of shares) { - const sskrShare = deserializeShare(share); - sskrShares.push(sskrShare); - } - return combineShares(sskrShares); -} -function serializeShare(share) { - const valueData = share.value().getData(); - const result = new Uint8Array(valueData.length + 5); - const id = share.identifier(); - const gt = share.groupThreshold() - 1 & 15; - const gc = share.groupCount() - 1 & 15; - const gi = share.groupIndex() & 15; - const mt = share.memberThreshold() - 1 & 15; - const mi = share.memberIndex() & 15; - const id1 = id >> 8; - const id2 = id & 255; - result[0] = id1; - result[1] = id2; - result[2] = gt << 4 | gc; - result[3] = gi << 4 | mt; - result[4] = mi; - result.set(valueData, 5); - return result; -} -function deserializeShare(source) { - if (source.length < 5) throw new SSKRError("ShareLengthInvalid"); - const groupThreshold = (source[2] >> 4) + 1; - const groupCount = (source[2] & 15) + 1; - if (groupThreshold > groupCount) throw new SSKRError("GroupThresholdInvalid"); - const identifier = source[0] << 8 | source[1]; - const groupIndex = source[3] >> 4; - const memberThreshold = (source[3] & 15) + 1; - if (source[4] >> 4 !== 0) throw new SSKRError("ShareReservedBitsInvalid"); - return new SSKRShare(identifier, groupIndex, groupThreshold, groupCount, source[4] & 15, memberThreshold, Secret.new(source.subarray(5))); -} -function generateShares(spec, masterSecret, randomGenerator) { - const identifierBytes = /* @__PURE__ */ new Uint8Array(2); - randomGenerator.fillRandomData(identifierBytes); - const identifier = identifierBytes[0] << 8 | identifierBytes[1]; - const groupsShares = []; - let groupSecrets; - try { - groupSecrets = splitSecret(spec.groupThreshold(), spec.groupCount(), masterSecret.getData(), randomGenerator); - } catch (e) { - if (e instanceof ShamirError) throw SSKRError.fromShamirError(e); - throw e; - } - for (let groupIndex = 0; groupIndex < spec.groups().length; groupIndex++) { - const group = spec.groups()[groupIndex]; - const groupSecret = groupSecrets[groupIndex]; - let memberSecrets; - try { - memberSecrets = splitSecret(group.memberThreshold(), group.memberCount(), groupSecret, randomGenerator); - } catch (e) { - if (e instanceof ShamirError) throw SSKRError.fromShamirError(e); - throw e; - } - const memberSSKRShares = memberSecrets.map((memberSecret, memberIndex) => { - const secret = Secret.new(memberSecret); - return new SSKRShare(identifier, groupIndex, spec.groupThreshold(), spec.groupCount(), memberIndex, group.memberThreshold(), secret); - }); - groupsShares.push(memberSSKRShares); - } - return groupsShares; -} -function combineShares(shares) { - let identifier = 0; - let groupThreshold = 0; - let groupCount = 0; - if (shares.length === 0) throw new SSKRError("SharesEmpty"); - let nextGroup = 0; - const groups = []; - let secretLen = 0; - for (let i = 0; i < shares.length; i++) { - const share = shares[i]; - if (i === 0) { - identifier = share.identifier(); - groupCount = share.groupCount(); - groupThreshold = share.groupThreshold(); - secretLen = share.value().len(); - } else if (share.identifier() !== identifier || share.groupThreshold() !== groupThreshold || share.groupCount() !== groupCount || share.value().len() !== secretLen) throw new SSKRError("ShareSetInvalid"); - let groupFound = false; - for (const group of groups) if (share.groupIndex() === group.groupIndex) { - groupFound = true; - if (share.memberThreshold() !== group.memberThreshold) throw new SSKRError("MemberThresholdInvalid"); - for (const memberIndex of group.memberIndexes) if (share.memberIndex() === memberIndex) throw new SSKRError("DuplicateMemberIndex"); - if (group.memberIndexes.length < group.memberThreshold) { - group.memberIndexes.push(share.memberIndex()); - group.memberShares.push(share.value().clone()); - } - } - if (!groupFound) { - const g = { - groupIndex: share.groupIndex(), - memberThreshold: share.memberThreshold(), - memberIndexes: [share.memberIndex()], - memberShares: [share.value().clone()] - }; - groups.push(g); - nextGroup++; - } - } - if (nextGroup < groupThreshold) throw new SSKRError("NotEnoughGroups"); - const masterIndexes = []; - const masterShares = []; - for (const group of groups) { - if (group.memberIndexes.length < group.memberThreshold) continue; - try { - const memberSharesData = group.memberShares.map((s) => s.getData()); - const groupSecret = recoverSecret(group.memberIndexes, memberSharesData); - masterIndexes.push(group.groupIndex); - masterShares.push(groupSecret); - } catch (e) { - if (e instanceof ShamirError) continue; - throw e; - } - if (masterIndexes.length === groupThreshold) break; - } - if (masterIndexes.length < groupThreshold) throw new SSKRError("NotEnoughGroups"); - let masterSecretData; - try { - masterSecretData = recoverSecret(masterIndexes, masterShares); - } catch (e) { - if (e instanceof ShamirError) throw SSKRError.fromShamirError(e); - throw e; - } - return Secret.new(masterSecretData); -} -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -*/ -/** -* The minimum length of a secret. -*/ -const MIN_SECRET_LEN = 16; -/** -* The maximum length of a secret. -*/ -const MAX_SECRET_LEN = 32; -//#endregion -//#region tests/baseline/node_modules/@bcts/components/dist/index.mjs -/** -* Error type for cryptographic and component operations. -* -* This class provides full structural parity with the Rust Error enum, -* including: -* - An `errorKind` property for programmatic error type checking -* - Structured `errorData` for accessing error-specific fields -* - Factory methods matching Rust's impl block -*/ -var CryptoError = class CryptoError extends Error { - /** The error kind for programmatic type checking */ - errorKind; - /** Structured error data matching Rust's error variants */ - errorData; - constructor(message, errorData) { - super(message); - this.name = "CryptoError"; - this.errorKind = errorData.kind; - this.errorData = errorData; - const ErrorWithStackTrace = Error; - if (typeof ErrorWithStackTrace.captureStackTrace === "function") ErrorWithStackTrace.captureStackTrace(this, CryptoError); - } - /** - * Create an invalid size error. - * - * Rust equivalent: `Error::InvalidSize { data_type, expected, actual }` - * - * @param expected - The expected size - * @param actual - The actual size received - */ - static invalidSize(expected, actual) { - return CryptoError.invalidSizeForType("data", expected, actual); - } - /** - * Create an invalid size error with a data type name. - * - * Rust equivalent: `Error::invalid_size(data_type, expected, actual)` - * - * @param dataType - The name of the data type - * @param expected - The expected size - * @param actual - The actual size received - */ - static invalidSizeForType(dataType, expected, actual) { - return new CryptoError(`invalid ${dataType} size: expected ${expected}, got ${actual}`, { - kind: "InvalidSize", - dataType, - expected, - actual - }); - } - /** - * Create an invalid data error. - * - * @param message - Description of what's invalid - */ - static invalidData(message) { - return CryptoError.invalidDataForType("data", message); - } - /** - * Create an invalid data error with a data type name. - * - * Rust equivalent: `Error::invalid_data(data_type, reason)` - * - * @param dataType - The name of the data type - * @param reason - The reason the data is invalid - */ - static invalidDataForType(dataType, reason) { - return new CryptoError(`invalid ${dataType}: ${reason}`, { - kind: "InvalidData", - dataType, - reason - }); - } - /** - * Create a data too short error. - * - * Rust equivalent: `Error::data_too_short(data_type, minimum, actual)` - * - * @param dataType - The name of the data type - * @param minimum - The minimum required size - * @param actual - The actual size received - */ - static dataTooShort(dataType, minimum, actual) { - return new CryptoError(`data too short: ${dataType} expected at least ${minimum}, got ${actual}`, { - kind: "DataTooShort", - dataType, - minimum, - actual - }); - } - /** - * Create an invalid format error. - * - * @param message - Description of the format error - */ - static invalidFormat(message) { - return CryptoError.invalidDataForType("format", message); - } - /** - * Create an invalid input error. - * - * @param message - Description of the invalid input - */ - static invalidInput(message) { - return CryptoError.invalidDataForType("input", message); - } - /** - * Create a cryptographic operation failed error. - * - * Rust equivalent: `Error::crypto(msg)` - * - * @param message - Description of the failure - */ - static cryptoOperation(message) { - return CryptoError.crypto(message); - } - /** - * Create a crypto error. - * - * Rust equivalent: `Error::Crypto(msg)` - * - * @param message - Description of the failure - */ - static crypto(message) { - return new CryptoError(`cryptographic operation failed: ${message}`, { - kind: "Crypto", - message - }); - } - /** - * Create a post-quantum cryptography error. - * - * Rust equivalent: `Error::post_quantum(msg)` - * - * @param message - Description of the failure - */ - static postQuantum(message) { - return new CryptoError(`post-quantum cryptography error: ${message}`, { - kind: "PostQuantum", - message - }); - } - /** - * Create a signature level mismatch error. - * - * Rust equivalent: `Error::LevelMismatch` - */ - static levelMismatch() { - return new CryptoError("signature level does not match key level", { kind: "LevelMismatch" }); - } - /** - * Create a CBOR error. - * - * Rust equivalent: `Error::Cbor(err)` - * - * @param message - Description of the CBOR error - */ - static cbor(message) { - return new CryptoError(`CBOR error: ${message}`, { - kind: "Cbor", - message - }); - } - /** - * Create a hex decoding error. - * - * Rust equivalent: `Error::Hex(err)` - * - * @param message - Description of the hex error - */ - static hex(message) { - return new CryptoError(`hex decoding error: ${message}`, { - kind: "Hex", - message - }); - } - /** - * Create a UTF-8 conversion error. - * - * Rust equivalent: `Error::Utf8(err)` - * - * @param message - Description of the UTF-8 error - */ - static utf8(message) { - return new CryptoError(`UTF-8 conversion error: ${message}`, { - kind: "Utf8", - message - }); - } - /** - * Create a compression error. - * - * Rust equivalent: `Error::compression(msg)` - * - * @param message - Description of the compression error - */ - static compression(message) { - return new CryptoError(`compression error: ${message}`, { - kind: "Compression", - message - }); - } - /** - * Create a URI parsing error. - * - * Rust equivalent: `Error::Uri(err)` - * - * @param message - Description of the URI error - */ - static uri(message) { - return new CryptoError(`invalid URI: ${message}`, { - kind: "Uri", - message - }); - } - /** - * Create an SSKR error. - * - * Rust equivalent: `Error::Sskr(err)` - * - * @param message - Description of the SSKR error - */ - static sskr(message) { - return new CryptoError(`SSKR error: ${message}`, { - kind: "Sskr", - message - }); - } - /** - * Create an SSH operation error. - * - * Rust equivalent: `Error::ssh(msg)` - * - * @param message - Description of the SSH error - */ - static ssh(message) { - return new CryptoError(`SSH operation failed: ${message}`, { - kind: "Ssh", - message - }); - } - /** - * Create an SSH agent error. - * - * Rust equivalent: `Error::ssh_agent(msg)` - * - * @param message - Description of the SSH agent error - */ - static sshAgent(message) { - return new CryptoError(`SSH agent error: ${message}`, { - kind: "SshAgent", - message - }); - } - /** - * Create an SSH agent client error. - * - * Rust equivalent: `Error::ssh_agent_client(msg)` - * - * @param message - Description of the SSH agent client error - */ - static sshAgentClient(message) { - return new CryptoError(`SSH agent client error: ${message}`, { - kind: "SshAgentClient", - message - }); - } - /** - * Create an environment variable error. - * - * Rust equivalent: `Error::Env(err)` - * - * @param message - Description of the environment error - */ - static env(message) { - return new CryptoError(`environment variable error: ${message}`, { - kind: "Env", - message - }); - } - /** - * Create a general error with a custom message. - * - * Rust equivalent: `Error::general(msg)` / `Error::General(msg)` - * - * @param message - The error message - */ - static general(message) { - return new CryptoError(message, { - kind: "General", - message - }); - } - /** - * Check if this error is of a specific kind. - * - * @param kind - The error kind to check - */ - isKind(kind) { - return this.errorKind === kind; - } - /** - * Check if this is an InvalidSize error. - */ - isInvalidSize() { - return this.errorKind === "InvalidSize"; - } - /** - * Check if this is an InvalidData error. - */ - isInvalidData() { - return this.errorKind === "InvalidData"; - } - /** - * Check if this is a DataTooShort error. - */ - isDataTooShort() { - return this.errorKind === "DataTooShort"; - } - /** - * Check if this is a Crypto error. - */ - isCrypto() { - return this.errorKind === "Crypto"; - } - /** - * Check if this is a Cbor error. - */ - isCbor() { - return this.errorKind === "Cbor"; - } - /** - * Check if this is an Sskr error. - */ - isSskr() { - return this.errorKind === "Sskr"; - } - /** - * Check if this is an Ssh error. - */ - isSsh() { - return this.errorKind === "Ssh"; - } - /** - * Check if this is a Uri error. - */ - isUri() { - return this.errorKind === "Uri"; - } - /** - * Check if this is a Compression error. - */ - isCompression() { - return this.errorKind === "Compression"; - } - /** - * Check if this is a PostQuantum error. - */ - isPostQuantum() { - return this.errorKind === "PostQuantum"; - } - /** - * Check if this is a LevelMismatch error. - */ - isLevelMismatch() { - return this.errorKind === "LevelMismatch"; - } - /** - * Check if this is an SshAgent error. - */ - isSshAgent() { - return this.errorKind === "SshAgent"; - } - /** - * Check if this is a Hex error. - */ - isHex() { - return this.errorKind === "Hex"; - } - /** - * Check if this is a Utf8 error. - */ - isUtf8() { - return this.errorKind === "Utf8"; - } - /** - * Check if this is an Env error. - */ - isEnv() { - return this.errorKind === "Env"; - } - /** - * Check if this is an SshAgentClient error. - */ - isSshAgentClient() { - return this.errorKind === "SshAgentClient"; - } - /** - * Check if this is a General error. - */ - isGeneral() { - return this.errorKind === "General"; - } -}; -/** -* Type guard to check if an object implements the Encrypter interface. -*/ -function isEncrypter(obj) { - return typeof obj === "object" && obj !== null && "encapsulationPublicKey" in obj && typeof obj.encapsulationPublicKey === "function" && "encapsulateNewSharedSecret" in obj && typeof obj.encapsulateNewSharedSecret === "function"; -} -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -* -* Utility functions for byte array conversions and comparisons. -* -* These functions provide cross-platform support for common byte manipulation -* operations needed in cryptographic and encoding contexts. -* -* @packageDocumentation -*/ -/** -* Convert a Uint8Array to a lowercase hexadecimal string. -* -* @param data - The byte array to convert -* @returns A lowercase hex string representation (2 characters per byte) -* -* @example -* ```typescript -* const bytes = new Uint8Array([0xde, 0xad, 0xbe, 0xef]); -* bytesToHex(bytes); // "deadbeef" -* ``` -*/ -function bytesToHex$1(data) { - return Array.from(data).map((b) => b.toString(16).padStart(2, "0")).join(""); -} -/** -* Convert a hexadecimal string to a Uint8Array. -* -* @param hex - A hex string (must have even length, case-insensitive) -* @returns The decoded byte array -* @throws {Error} If the hex string has odd length or contains invalid characters -* -* @example -* ```typescript -* hexToBytes("deadbeef"); // Uint8Array([0xde, 0xad, 0xbe, 0xef]) -* hexToBytes("DEADBEEF"); // Uint8Array([0xde, 0xad, 0xbe, 0xef]) -* hexToBytes("xyz"); // throws Error: Invalid hex string -* ``` -*/ -function hexToBytes(hex) { - if (hex.length % 2 !== 0) throw new Error(`Hex string must have even length, got ${hex.length}`); - if (!/^[0-9A-Fa-f]*$/.test(hex)) throw new Error("Invalid hex string: contains non-hexadecimal characters"); - const data = new Uint8Array(hex.length / 2); - for (let i = 0; i < hex.length; i += 2) data[i / 2] = parseInt(hex.substring(i, i + 2), 16); - return data; -} -/** -* Convert a Uint8Array to a base64-encoded string. -* -* This function works in both browser and Node.js environments. -* Uses btoa which is available in browsers and Node.js 16+. -* -* @param data - The byte array to encode -* @returns A base64-encoded string -* -* @example -* ```typescript -* const bytes = new Uint8Array([72, 101, 108, 108, 111]); // "Hello" -* toBase64(bytes); // "SGVsbG8=" -* ``` -*/ -function toBase64$1(data) { - let binary = ""; - for (const byte of data) binary += String.fromCharCode(byte); - return btoa(binary); -} -/** -* Compare two Uint8Arrays for equality using constant-time comparison. -* -* This function is designed to be resistant to timing attacks by always -* comparing all bytes regardless of where a difference is found. The -* comparison time depends only on the length of the arrays, not on where -* they differ. -* -* **Security Note**: If the arrays have different lengths, this function -* returns `false` immediately, which does leak length information. For -* cryptographic uses where length should also be secret, ensure both -* arrays are the same length before comparison. -* -* @param a - First byte array -* @param b - Second byte array -* @returns `true` if both arrays have the same length and identical contents -* -* @example -* ```typescript -* const key1 = new Uint8Array([1, 2, 3, 4]); -* const key2 = new Uint8Array([1, 2, 3, 4]); -* const key3 = new Uint8Array([1, 2, 3, 5]); -* -* bytesEqual(key1, key2); // true -* bytesEqual(key1, key3); // false -* ``` -*/ -function bytesEqual$1(a, b) { - if (a.length !== b.length) return false; - let result = 0; - for (let i = 0; i < a.length; i++) result |= a[i] ^ b[i]; - return result === 0; -} -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -* -* A CBOR-tagged container for UTF-8 JSON text. -* -* Ported from bc-components-rust/src/json.rs -* -* The `JSON` type wraps UTF-8 JSON text as a CBOR byte string with tag 262. -* This allows JSON data to be embedded within CBOR structures while -* maintaining type information through the tag. -* -* This implementation does not validate that the contained data is well-formed -* JSON. It simply provides a type-safe wrapper around byte data that is -* intended to contain JSON text. -* -* # CBOR Serialization -* -* `JSON` implements the CBOR tagged encoding interfaces, which means it can be -* serialized to and deserialized from CBOR with tag 262 (`TAG_JSON`). -* -* @example -* ```typescript -* import { JSON } from '@bcts/components'; -* -* // Create JSON from a string -* const json = JSON.fromString('{"key": "value"}'); -* console.log(json.asStr()); // {"key": "value"} -* -* // Create JSON from bytes -* const json2 = JSON.fromData(new TextEncoder().encode('[1, 2, 3]')); -* console.log(json2.len()); // 9 -* ``` -*/ -/** -* A CBOR-tagged container for UTF-8 JSON text. -* -* Wraps UTF-8 JSON text as a CBOR byte string with tag 262. -* This allows JSON data to be embedded within CBOR structures while -* maintaining type information through the tag. -*/ -var JSON$1 = class JSON { - _data; - constructor(data) { - this._data = new Uint8Array(data); - } - /** - * Create a new JSON instance from byte data. - */ - static fromData(data) { - return new JSON(data); - } - /** - * Create a new JSON instance from a string. - */ - static fromString(s) { - const encoder = new TextEncoder(); - return new JSON(encoder.encode(s)); - } - /** - * Create a new JSON instance from a hexadecimal string. - */ - static fromHex(hex) { - return new JSON(hexToBytes(hex)); - } - /** - * Return the length of the JSON data in bytes. - */ - len() { - return this._data.length; - } - /** - * Return true if the JSON data is empty. - */ - isEmpty() { - return this._data.length === 0; - } - /** - * Return the data as a byte slice. - */ - asBytes() { - return new Uint8Array(this._data); - } - /** - * Return the data as a UTF-8 string slice. - * - * @throws Error if the data is not valid UTF-8. - */ - asStr() { - return new TextDecoder("utf-8", { fatal: true }).decode(this._data); - } - /** - * Return the data as a hexadecimal string. - */ - hex() { - return bytesToHex$1(this._data); - } - /** - * Return a copy of the underlying data. - */ - toData() { - return new Uint8Array(this._data); - } - /** - * Compare with another JSON. - */ - equals(other) { - if (this._data.length !== other._data.length) return false; - for (let i = 0; i < this._data.length; i++) if (this._data[i] !== other._data[i]) return false; - return true; - } - /** - * Get string representation. - */ - toString() { - return `JSON(${this.asStr()})`; - } - /** - * Returns the CBOR tags associated with JSON. - */ - cborTags() { - return tagsForValues([JSON$2.value]); - } - /** - * Returns the untagged CBOR encoding (as a byte string). - */ - untaggedCbor() { - return toByteString(this._data); - } - /** - * Returns the tagged CBOR encoding. - */ - taggedCbor() { - return createTaggedCbor(this); - } - /** - * Returns the tagged value in CBOR binary representation. - */ - taggedCborData() { - return this.taggedCbor().toData(); - } - /** - * Creates a JSON by decoding it from untagged CBOR. - */ - fromUntaggedCbor(cborValue) { - const data = expectBytes(cborValue); - return JSON.fromData(data); - } - /** - * Creates a JSON by decoding it from tagged CBOR. - */ - fromTaggedCbor(cborValue) { - validateTag(cborValue, this.cborTags()); - const content = extractTaggedContent(cborValue); - return this.fromUntaggedCbor(content); - } - /** - * Static method to decode from tagged CBOR. - */ - static fromTaggedCbor(cborValue) { - return JSON.fromString("").fromTaggedCbor(cborValue); - } - /** - * Static method to decode from tagged CBOR binary data. - */ - static fromTaggedCborData(data) { - const cborValue = decodeCbor(data); - return JSON.fromTaggedCbor(cborValue); - } - /** - * Static method to decode from untagged CBOR binary data. - */ - static fromUntaggedCborData(data) { - const cborValue = decodeCbor(data); - return JSON.fromString("").fromUntaggedCbor(cborValue); - } -}; -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -* -* SHA-256 cryptographic digest (32 bytes) -* -* Ported from bc-components-rust/src/digest.rs -* -* A `Digest` represents the cryptographic hash of some data. In this -* implementation, SHA-256 is used, which produces a 32-byte hash value. -* Digests are used throughout the crate for data verification and as unique -* identifiers derived from data. -* -* # CBOR Serialization -* -* `Digest` implements the CBOR tagged encoding interfaces, which means it can be -* serialized to and deserialized from CBOR with a specific tag (TAG_DIGEST = 40001). -* -* # UR Serialization -* -* When serialized as a Uniform Resource (UR), a `Digest` is represented as a -* binary blob with the type "digest". -* -* @example -* ```typescript -* import { Digest } from '@bcts/components'; -* -* // Create a digest from a string -* const data = new TextEncoder().encode("hello world"); -* const digest = Digest.fromImage(data); -* -* // Validate that the digest matches the original data -* console.log(digest.validate(data)); // true -* -* // Create a digest from a hex string -* const hexString = "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"; -* const digest2 = Digest.fromHex(hexString); -* -* // Retrieve the digest as hex -* console.log(digest2.hex()); // b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9 -* ``` -*/ -var Digest = class Digest { - static DIGEST_SIZE = 32; - _data; - constructor(data) { - if (data.length !== Digest.DIGEST_SIZE) throw CryptoError.invalidSize(Digest.DIGEST_SIZE, data.length); - this._data = new Uint8Array(data); - } - /** - * Get the digest data. - */ - data() { - return this._data; - } - /** - * Create a Digest from a 32-byte array. - */ - static fromData(data) { - return new Digest(new Uint8Array(data)); - } - /** - * Create a Digest from data, validating the length. - * Alias for fromData for compatibility with Rust API. - */ - static fromDataRef(data) { - return Digest.fromData(data); - } - /** - * Create a Digest from hex string. - * - * @throws Error if the hex string is not exactly 64 characters. - */ - static fromHex(hex) { - return new Digest(hexToBytes(hex)); - } - /** - * Compute SHA-256 digest of data (called "image" in Rust). - * - * @param image - The data to hash - */ - static fromImage(image) { - const hashData = sha256$1(image); - return new Digest(new Uint8Array(hashData)); - } - /** - * Compute SHA-256 digest from multiple data parts. - * - * The parts are concatenated and then hashed. - * - * @param imageParts - Array of byte arrays to concatenate and hash - */ - static fromImageParts(imageParts) { - const totalLength = imageParts.reduce((sum, part) => sum + part.length, 0); - const buf = new Uint8Array(totalLength); - let offset = 0; - for (const part of imageParts) { - buf.set(part, offset); - offset += part.length; - } - return Digest.fromImage(buf); - } - /** - * Compute SHA-256 digest from an array of Digests. - * - * The digest bytes are concatenated and then hashed. - * - * @param digests - Array of Digests to combine - */ - static fromDigests(digests) { - const buf = new Uint8Array(digests.length * Digest.DIGEST_SIZE); - let offset = 0; - for (const digest of digests) { - buf.set(digest._data, offset); - offset += Digest.DIGEST_SIZE; - } - return Digest.fromImage(buf); - } - /** - * Compute SHA-256 digest of data (legacy alias for fromImage). - * @deprecated Use fromImage instead - */ - static hash(data) { - return Digest.fromImage(data); - } - /** - * Get the raw digest bytes as a copy. - */ - toData() { - return new Uint8Array(this._data); - } - /** - * Get a reference to the raw digest bytes. - */ - asBytes() { - return this._data; - } - /** - * Get hex string representation. - */ - hex() { - return bytesToHex$1(this._data); - } - /** - * Get hex string representation (alias for hex()). - */ - toHex() { - return this.hex(); - } - /** - * Get base64 representation. - */ - toBase64() { - return toBase64$1(this._data); - } - /** - * Get the first four bytes of the digest as a hexadecimal string. - * Useful for short descriptions. - */ - shortDescription() { - return bytesToHex$1(this._data.slice(0, 4)); - } - /** - * Validate the digest against the given image. - * - * The image is hashed with SHA-256 and compared to this digest. - * @returns `true` if the digest matches the image. - */ - validate(image) { - return this.equals(Digest.fromImage(image)); - } - /** - * Compare with another Digest. - */ - equals(other) { - if (this._data.length !== other._data.length) return false; - for (let i = 0; i < this._data.length; i++) if (this._data[i] !== other._data[i]) return false; - return true; - } - /** - * Compare digests lexicographically. - */ - compare(other) { - for (let i = 0; i < this._data.length; i++) { - const a = this._data[i]; - const b = other._data[i]; - if (a < b) return -1; - if (a > b) return 1; - } - return 0; - } - /** - * Get string representation. - */ - toString() { - return `Digest(${this.hex()})`; - } - /** - * A Digest is its own digest provider - returns itself. - */ - digest() { - return this; - } - /** - * Returns the CBOR tags associated with Digest. - */ - cborTags() { - return tagsForValues([DIGEST.value]); - } - /** - * Returns the untagged CBOR encoding (as a byte string). - */ - untaggedCbor() { - return toByteString(this._data); - } - /** - * Returns the tagged CBOR encoding. - */ - taggedCbor() { - return createTaggedCbor(this); - } - /** - * Returns the tagged value in CBOR binary representation. - */ - taggedCborData() { - return this.taggedCbor().toData(); - } - /** - * Creates a Digest by decoding it from untagged CBOR. - */ - fromUntaggedCbor(cbor) { - const data = expectBytes(cbor); - return Digest.fromData(data); - } - /** - * Creates a Digest by decoding it from tagged CBOR. - */ - fromTaggedCbor(cbor) { - validateTag(cbor, this.cborTags()); - const content = extractTaggedContent(cbor); - return this.fromUntaggedCbor(content); - } - /** - * Static method to decode from tagged CBOR. - */ - static fromTaggedCbor(cbor) { - return new Digest(new Uint8Array(Digest.DIGEST_SIZE)).fromTaggedCbor(cbor); - } - /** - * Static method to decode from tagged CBOR binary data. - */ - static fromTaggedCborData(data) { - const cbor = decodeCbor(data); - return Digest.fromTaggedCbor(cbor); - } - /** - * Static method to decode from untagged CBOR binary data. - */ - static fromUntaggedCborData(data) { - const cbor = decodeCbor(data); - const bytes = expectBytes(cbor); - return Digest.fromData(bytes); - } - /** - * Returns the UR representation of the Digest. - * Note: URs use untagged CBOR since the type is conveyed by the UR type itself. - */ - ur() { - return UR.new("digest", this.untaggedCbor()); - } - /** - * Returns the UR string representation. - */ - urString() { - return this.ur().string(); - } - /** - * Creates a Digest from a UR. - */ - static fromUR(ur) { - ur.checkType("digest"); - return new Digest(new Uint8Array(Digest.DIGEST_SIZE)).fromUntaggedCbor(ur.cbor()); - } - /** - * Creates a Digest from a UR string. - */ - static fromURString(urString) { - const ur = UR.fromURString(urString); - return Digest.fromUR(ur); - } - /** - * Validate the given data against the digest, if any. - * - * Returns `true` if the digest is `undefined` or if the digest matches the - * image's digest. Returns `false` if the digest does not match. - */ - static validateOpt(image, digest) { - if (digest === void 0) return true; - return digest.validate(image); - } -}; -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -* -* A compressed binary object with integrity verification. -* -* Ported from bc-components-rust/src/compressed.rs -* -* `Compressed` provides a way to efficiently store and transmit binary data -* using the DEFLATE compression algorithm. It includes built-in integrity -* verification through a CRC32 checksum and optional cryptographic digest. -* -* The compression is implemented using the raw DEFLATE format as described in -* [IETF RFC 1951](https://www.ietf.org/rfc/rfc1951.txt). -* -* Features: -* - Automatic compression with configurable compression level -* - Integrity verification via CRC32 checksum -* - Optional cryptographic digest for content identification -* - Smart behavior for small data (stores decompressed if compression would -* increase size) -* - CBOR serialization/deserialization support -* -* @example -* ```typescript -* import { Compressed } from '@bcts/components'; -* -* // Compress a string -* const data = new TextEncoder().encode( -* "This is a longer string that should compress well with repeated patterns." -* ); -* const compressed = Compressed.fromDecompressedData(data); -* -* // The compressed size should be smaller than the original -* console.log(compressed.compressionRatio()); // < 1.0 -* -* // We can recover the original data -* const decompressed = compressed.decompress(); -* ``` -*/ -/** -* A compressed binary object with integrity verification. -* -* Uses DEFLATE compression with CRC32 checksums for integrity verification. -* Optionally includes a cryptographic digest for content identification. -*/ -var Compressed = class Compressed { - /** CRC32 checksum of the decompressed data for integrity verification */ - _checksum; - /** Size of the original decompressed data in bytes */ - _decompressedSize; - /** The compressed data (or original data if compression is ineffective) */ - _compressedData; - /** Optional cryptographic digest of the content */ - _digest; - constructor(checksum, decompressedSize, compressedData, digest) { - if (compressedData.length > decompressedSize) throw CryptoError.cryptoOperation("compressed data is larger than decompressed size"); - this._checksum = checksum; - this._decompressedSize = decompressedSize; - this._compressedData = new Uint8Array(compressedData); - this._digest = digest; - } - /** - * Creates a new `Compressed` object with the specified parameters. - * - * This is a low-level constructor that allows direct creation of a - * `Compressed` object without performing compression. It's primarily - * intended for deserialization or when working with pre-compressed data. - * - * @param checksum - CRC32 checksum of the decompressed data - * @param decompressedSize - Size of the original decompressed data in bytes - * @param compressedData - The compressed data bytes - * @param digest - Optional cryptographic digest of the content - * @returns A new `Compressed` object - * @throws CryptoError if the compressed data is larger than the decompressed size - */ - static new(checksum, decompressedSize, compressedData, digest) { - return new Compressed(checksum, decompressedSize, compressedData, digest); - } - /** - * Creates a new `Compressed` object by compressing the provided data. - * - * This is the primary method for creating compressed data. It automatically - * handles compression using the DEFLATE algorithm with compression level 6. - * - * If the compressed data would be larger than the original data (which can - * happen with small or already compressed inputs), the original data is - * stored instead. - * - * @param decompressedData - The original data to compress - * @param digest - Optional cryptographic digest of the content - * @returns A new `Compressed` object containing the compressed (or original) data - */ - static fromDecompressedData(decompressedData, digest) { - const compressedData = deflateRaw(decompressedData, { level: 6 }); - const checksum = hash_exports.crc32(decompressedData); - const decompressedSize = decompressedData.length; - const compressedSize = compressedData.length; - if (compressedSize !== 0 && compressedSize < decompressedSize) return new Compressed(checksum, decompressedSize, compressedData, digest); - else return new Compressed(checksum, decompressedSize, new Uint8Array(decompressedData), digest); - } - /** - * Decompresses and returns the original decompressed data. - * - * This method performs the reverse of the compression process, restoring - * the original data. It also verifies the integrity of the data using the - * stored checksum. - * - * @returns The decompressed data - * @throws CryptoError if the compressed data is corrupt or checksum doesn't match - */ - decompress() { - if (this._compressedData.length >= this._decompressedSize) return new Uint8Array(this._compressedData); - try { - const decompressedData = inflateRaw(this._compressedData); - if (hash_exports.crc32(decompressedData) !== this._checksum) throw CryptoError.cryptoOperation("compressed data checksum mismatch"); - return decompressedData; - } catch (e) { - if (e instanceof CryptoError) throw e; - throw CryptoError.cryptoOperation("corrupt compressed data"); - } - } - /** - * Returns the size of the compressed data in bytes. - */ - compressedSize() { - return this._compressedData.length; - } - /** - * Returns the size of the decompressed data in bytes. - */ - decompressedSize() { - return this._decompressedSize; - } - /** - * Returns the CRC32 checksum of the decompressed data. - */ - checksum() { - return this._checksum; - } - /** - * Returns the compression ratio of the data. - * - * The compression ratio is calculated as (compressed size) / (decompressed size), - * so lower values indicate better compression. - * - * @returns A floating-point value representing the compression ratio. - * - Values less than 1.0 indicate effective compression - * - Values equal to 1.0 indicate no compression was applied - * - Values of NaN can occur if the decompressed size is zero - */ - compressionRatio() { - return this._compressedData.length / this._decompressedSize; - } - /** - * Returns the digest of the compressed data, if available. - * - * @returns The `Digest` associated with this compressed data, or undefined if none. - */ - digestOpt() { - return this._digest; - } - /** - * Returns whether this compressed data has an associated digest. - */ - hasDigest() { - return this._digest !== void 0; - } - /** - * Returns the cryptographic digest associated with this compressed data. - * - * @returns A `Digest` - * @throws Error if there is no digest associated with this compressed data - */ - digest() { - if (this._digest === void 0) throw new Error("No digest associated with this compressed data"); - return this._digest; - } - /** - * Compare with another Compressed. - */ - equals(other) { - if (this._checksum !== other._checksum) return false; - if (this._decompressedSize !== other._decompressedSize) return false; - if (this._compressedData.length !== other._compressedData.length) return false; - for (let i = 0; i < this._compressedData.length; i++) if (this._compressedData[i] !== other._compressedData[i]) return false; - return true; - } - /** - * Get string representation. - */ - toString() { - const checksumHex = bytesToHex$1(new Uint8Array([ - this._checksum >>> 24 & 255, - this._checksum >>> 16 & 255, - this._checksum >>> 8 & 255, - this._checksum & 255 - ])); - const digestStr = this._digest?.shortDescription() ?? "None"; - return `Compressed(checksum: ${checksumHex}, size: ${this.compressedSize()}/${this._decompressedSize}, ratio: ${this.compressionRatio().toFixed(2)}, digest: ${digestStr})`; - } - /** - * Returns the CBOR tags associated with Compressed. - */ - cborTags() { - return tagsForValues([COMPRESSED.value]); - } - /** - * Returns the untagged CBOR encoding (as an array). - * - * Format: - * ``` - * [ - * checksum: uint, - * decompressed_size: uint, - * compressed_data: bytes, - * digest?: Digest // Optional - * ] - * ``` - */ - untaggedCbor() { - const elements = [ - this._checksum >>> 0, - this._decompressedSize, - toByteString(this._compressedData) - ]; - if (this._digest !== void 0) elements.push(this._digest.taggedCbor()); - return cbor(elements); - } - /** - * Returns the tagged CBOR encoding. - */ - taggedCbor() { - return createTaggedCbor(this); - } - /** - * Returns the tagged value in CBOR binary representation. - */ - taggedCborData() { - return this.taggedCbor().toData(); - } - /** - * Creates a Compressed by decoding it from untagged CBOR. - */ - fromUntaggedCbor(cborValue) { - const elements = expectArray(cborValue); - if (elements.length < 3 || elements.length > 4) throw CryptoError.invalidData("invalid number of elements in compressed"); - const checksum = expectInteger(elements[0]); - const decompressedSize = expectInteger(elements[1]); - const compressedData = expectBytes(elements[2]); - let digest; - if (elements.length === 4) digest = Digest.fromTaggedCbor(elements[3]); - return Compressed.new(Number(checksum), Number(decompressedSize), compressedData, digest); - } - /** - * Creates a Compressed by decoding it from tagged CBOR. - */ - fromTaggedCbor(cborValue) { - validateTag(cborValue, this.cborTags()); - const content = extractTaggedContent(cborValue); - return this.fromUntaggedCbor(content); - } - /** - * Static method to decode from tagged CBOR. - */ - static fromTaggedCbor(cborValue) { - return Compressed.fromDecompressedData(/* @__PURE__ */ new Uint8Array(0)).fromTaggedCbor(cborValue); - } - /** - * Static method to decode from tagged CBOR binary data. - */ - static fromTaggedCborData(data) { - const cborValue = decodeCbor(data); - return Compressed.fromTaggedCbor(cborValue); - } - /** - * Static method to decode from untagged CBOR binary data. - */ - static fromUntaggedCborData(data) { - const cborValue = decodeCbor(data); - return Compressed.fromDecompressedData(/* @__PURE__ */ new Uint8Array(0)).fromUntaggedCbor(cborValue); - } -}; -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -* -* A deterministic random number generator based on HKDF-HMAC-SHA256. -* -* Ported from bc-components-rust/src/hkdf_rng.rs -* -* `HKDFRng` uses the HMAC-based Key Derivation Function (HKDF) to generate -* deterministic random numbers from a combination of key material and salt. It -* serves as a key-stretching mechanism that can produce an arbitrary amount of -* random-looking bytes from a single seed. -* -* Since it produces deterministic output based on the same inputs, it's useful -* for situations where repeatable randomness is required, such as in testing -* or when deterministically deriving keys from a master seed. -* -* Security considerations: -* - The security of the generator depends on the entropy and secrecy of the -* key material -* - The same key material and salt will always produce the same sequence -* - Use a secure random seed for cryptographic applications -* - Never reuse the same HKDFRng instance for different purposes -* -* The implementation automatically handles buffer management, fetching new -* data using HKDF as needed with an incrementing counter to ensure unique -* output for each request. -* -* @example -* ```typescript -* import { HKDFRng } from '@bcts/components'; -* -* // Create an HKDF-based RNG -* const rng = HKDFRng.new(new TextEncoder().encode("my secure seed"), "wallet-derivation"); -* -* // Generate two u32 values -* const random1 = rng.nextU32(); -* const random2 = rng.nextU32(); -* -* // The same seed and salt will always produce the same sequence -* const rng2 = HKDFRng.new(new TextEncoder().encode("my secure seed"), "wallet-derivation"); -* console.log(random1 === rng2.nextU32()); // true -* console.log(random2 === rng2.nextU32()); // true -* ``` -*/ -const DEFAULT_PAGE_LENGTH = 32; -/** -* A deterministic random number generator based on HKDF-HMAC-SHA256. -* -* Implements the RandomNumberGenerator interface from @bcts/rand. -*/ -var HKDFRng = class HKDFRng { - /** Internal buffer of generated bytes */ - _buffer; - /** Current position in the buffer */ - _position; - /** Source key material (seed) */ - _keyMaterial; - /** Salt value to combine with the key material */ - _salt; - /** Length of each "page" of generated data */ - _pageLength; - /** Current page index */ - _pageIndex; - constructor(keyMaterial, salt, pageLength) { - this._buffer = /* @__PURE__ */ new Uint8Array(0); - this._position = 0; - this._keyMaterial = new Uint8Array(keyMaterial); - this._salt = salt; - this._pageLength = pageLength; - this._pageIndex = 0; - } - /** - * Creates a new `HKDFRng` with a custom page length. - * - * @param keyMaterial - The seed material to derive random numbers from - * @param salt - A salt value to mix with the key material - * @param pageLength - The number of bytes to generate in each HKDF call - * @returns A new `HKDFRng` instance configured with the specified parameters - */ - static newWithPageLength(keyMaterial, salt, pageLength) { - return new HKDFRng(keyMaterial, salt, pageLength); - } - /** - * Creates a new `HKDFRng` with the default page length of 32 bytes. - * - * @param keyMaterial - The seed material to derive random numbers from - * @param salt - A salt value to mix with the key material - * @returns A new `HKDFRng` instance configured with the specified key material and salt - */ - static new(keyMaterial, salt) { - return HKDFRng.newWithPageLength(keyMaterial, salt, DEFAULT_PAGE_LENGTH); - } - /** - * Refills the internal buffer with new deterministic random bytes. - * - * This method is called automatically when the internal buffer is exhausted. - * It uses HKDF-HMAC-SHA256 to generate a new page of random bytes using the - * key material, salt, and current page index. - */ - fillBuffer() { - const saltString = `${this._salt}-${this._pageIndex}`; - const encoder = new TextEncoder(); - this._buffer = hkdfHmacSha256$1(this._keyMaterial, encoder.encode(saltString), this._pageLength); - this._position = 0; - this._pageIndex += 1; - } - /** - * Generates the specified number of deterministic random bytes. - * - * @param length - The number of bytes to generate - * @returns A Uint8Array containing the requested number of deterministic random bytes - */ - nextBytes(length) { - const result = []; - while (result.length < length) { - if (this._position >= this._buffer.length) this.fillBuffer(); - const remaining = length - result.length; - const available = this._buffer.length - this._position; - const take = Math.min(remaining, available); - for (let i = 0; i < take; i++) result.push(this._buffer[this._position + i]); - this._position += take; - } - return new Uint8Array(result); - } - /** - * Generates deterministic random bytes. - * - * @param length - The number of bytes to generate - * @returns A Uint8Array of random bytes - */ - randomData(length) { - return this.nextBytes(length); - } - /** - * Fills the provided buffer with deterministic random bytes. - * - * @param dest - The buffer to fill with random bytes - */ - fillBytes(dest) { - const bytes = this.nextBytes(dest.length); - dest.set(bytes); - } - /** - * Generates a random `u32` value. - * - * @returns A deterministic random 32-bit unsigned integer - */ - nextU32() { - const bytes = this.nextBytes(4); - return (bytes[0] | bytes[1] << 8 | bytes[2] << 16 | bytes[3] << 24) >>> 0; - } - /** - * Generates a random `u64` value. - * - * Note: JavaScript numbers can only safely represent integers up to 2^53 - 1, - * so this returns a BigInt for full 64-bit precision. - * - * @returns A deterministic random 64-bit unsigned integer as BigInt - */ - nextU64() { - const bytes = this.nextBytes(8); - let result = BigInt(0); - for (let i = 7; i >= 0; i--) result = result << BigInt(8) | BigInt(bytes[i]); - return result; - } - /** - * Attempts to fill the provided buffer with random bytes. - * This implementation never fails. - * - * @param dest - The buffer to fill with random bytes - */ - tryFillBytes(dest) { - this.fillBytes(dest); - } - /** - * Fills the provided buffer with deterministic random bytes. - * Alias for fillBytes for interface compatibility. - * - * @param data - The buffer to fill with random bytes - */ - fillRandomData(data) { - this.fillBytes(data); - } - /** - * Returns the key material (for testing purposes). - */ - getKeyMaterial() { - return new Uint8Array(this._keyMaterial); - } - /** - * Returns the salt (for testing purposes). - */ - getSalt() { - return this._salt; - } - /** - * Returns the page length (for testing purposes). - */ - getPageLength() { - return this._pageLength; - } - /** - * Returns the current page index (for testing purposes). - */ - getPageIndex() { - return this._pageIndex; - } -}; -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -* -* A random nonce ("number used once"). -* -* Ported from bc-components-rust/src/nonce.rs -* -* A `Nonce` is a cryptographic primitive consisting of a random or -* pseudo-random number that is used only once in a cryptographic -* communication. Nonces are often used in authentication protocols, encryption -* algorithms, and digital signatures to prevent replay attacks and ensure -* the uniqueness of encrypted messages. -* -* In this implementation, a `Nonce` is a 12-byte random value. The size is -* chosen to be sufficiently large to prevent collisions while remaining -* efficient for storage and transmission. -* -* # CBOR Serialization -* -* `Nonce` implements the CBOR tagged encoding interfaces, which means it can be -* serialized to and deserialized from CBOR with a specific tag (TAG_NONCE = 40014). -* -* # UR Serialization -* -* When serialized as a Uniform Resource (UR), a `Nonce` is represented as a -* binary blob with the type "nonce". -* -* # Common Uses -* -* - In authenticated encryption schemes like AES-GCM or ChaCha20-Poly1305 -* - For initializing counters in counter-mode block ciphers -* - In challenge-response authentication protocols -* - To prevent replay attacks in secure communications -* -* @example -* ```typescript -* import { Nonce } from '@bcts/components'; -* -* // Generate a new random nonce -* const nonce = Nonce.new(); -* -* // Create a nonce from a byte array -* const data = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); -* const nonce2 = Nonce.fromData(data); -* -* // Access the nonce data -* const nonceData = nonce2.data(); -* ``` -*/ -var Nonce = class Nonce { - static NONCE_SIZE = 12; - _data; - constructor(data) { - if (data.length !== Nonce.NONCE_SIZE) throw CryptoError.invalidSize(Nonce.NONCE_SIZE, data.length); - this._data = new Uint8Array(data); - } - /** - * Create a new random nonce. - */ - static new() { - const rng = new SecureRandomNumberGenerator(); - return new Nonce(rng.randomData(Nonce.NONCE_SIZE)); - } - /** - * Create a new random nonce (alias for compatibility). - */ - static random() { - return Nonce.new(); - } - /** - * Restores a nonce from data. - */ - static fromData(data) { - return new Nonce(new Uint8Array(data)); - } - /** - * Restores a nonce from data (validates length). - */ - static fromDataRef(data) { - if (data.length !== Nonce.NONCE_SIZE) throw CryptoError.invalidSize(Nonce.NONCE_SIZE, data.length); - return Nonce.fromData(data); - } - /** - * Create a Nonce from raw bytes (legacy alias). - */ - static from(data) { - return Nonce.fromData(data); - } - /** - * Create a new nonce from the given hexadecimal string. - * - * @throws Error if the string is not exactly 24 hexadecimal digits. - */ - static fromHex(hex) { - return new Nonce(hexToBytes(hex)); - } - /** - * Generate a random nonce using provided RNG. - */ - static randomUsing(rng) { - return new Nonce(rng.randomData(Nonce.NONCE_SIZE)); - } - /** - * Get the data of the nonce. - */ - data() { - return this._data; - } - /** - * Get the nonce as a byte slice. - */ - asBytes() { - return this._data; - } - /** - * Get the raw nonce bytes as a copy. - */ - toData() { - return new Uint8Array(this._data); - } - /** - * The data as a hexadecimal string. - */ - hex() { - return bytesToHex$1(this._data); - } - /** - * Get hex string representation (alias for hex()). - */ - toHex() { - return this.hex(); - } - /** - * Get base64 representation. - */ - toBase64() { - return toBase64$1(this._data); - } - /** - * Compare with another Nonce. - */ - equals(other) { - if (this._data.length !== other._data.length) return false; - for (let i = 0; i < this._data.length; i++) if (this._data[i] !== other._data[i]) return false; - return true; - } - /** - * Get string representation. - */ - toString() { - return `Nonce(${this.hex()})`; - } - /** - * Returns the CBOR tags associated with Nonce. - */ - cborTags() { - return tagsForValues([NONCE.value]); - } - /** - * Returns the untagged CBOR encoding (as a byte string). - */ - untaggedCbor() { - return toByteString(this._data); - } - /** - * Returns the tagged CBOR encoding. - */ - taggedCbor() { - return createTaggedCbor(this); - } - /** - * Returns the tagged value in CBOR binary representation. - */ - taggedCborData() { - return this.taggedCbor().toData(); - } - /** - * Creates a Nonce by decoding it from untagged CBOR. - */ - fromUntaggedCbor(cbor) { - const data = expectBytes(cbor); - return Nonce.fromDataRef(data); - } - /** - * Creates a Nonce by decoding it from tagged CBOR. - */ - fromTaggedCbor(cbor) { - validateTag(cbor, this.cborTags()); - const content = extractTaggedContent(cbor); - return this.fromUntaggedCbor(content); - } - /** - * Static method to decode from tagged CBOR. - */ - static fromTaggedCbor(cbor) { - return new Nonce(new Uint8Array(Nonce.NONCE_SIZE)).fromTaggedCbor(cbor); - } - /** - * Static method to decode from tagged CBOR binary data. - */ - static fromTaggedCborData(data) { - const cbor = decodeCbor(data); - return Nonce.fromTaggedCbor(cbor); - } - /** - * Static method to decode from untagged CBOR binary data. - */ - static fromUntaggedCborData(data) { - const cbor = decodeCbor(data); - const bytes = expectBytes(cbor); - return Nonce.fromDataRef(bytes); - } - /** - * Returns the UR representation of the Nonce. - * Note: URs use untagged CBOR since the type is conveyed by the UR type itself. - */ - ur() { - return UR.new("nonce", this.untaggedCbor()); - } - /** - * Returns the UR string representation. - */ - urString() { - return this.ur().string(); - } - /** - * Creates a Nonce from a UR. - */ - static fromUR(ur) { - ur.checkType("nonce"); - return new Nonce(new Uint8Array(Nonce.NONCE_SIZE)).fromUntaggedCbor(ur.cbor()); - } - /** - * Creates a Nonce from a UR string. - */ - static fromURString(urString) { - const ur = UR.fromURString(urString); - return Nonce.fromUR(ur); - } -}; -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -* -* Random salt used to decorrelate other information. -* -* Ported from bc-components-rust/src/salt.rs -* -* A `Salt` is a cryptographic primitive consisting of random data that is used -* to modify the output of a cryptographic function. Salts are primarily used -* in password hashing to defend against dictionary attacks, rainbow table -* attacks, and pre-computation attacks. They are also used in other -* cryptographic contexts to ensure uniqueness and prevent correlation between -* different parts of a cryptosystem. -* -* Unlike a `Nonce` which has a fixed size, a `Salt` in this implementation can -* have a variable length (minimum 8 bytes). Different salt creation methods -* are provided to generate salts of appropriate sizes for different use cases. -* -* # Minimum Size Requirement -* -* For security reasons, salts must be at least 8 bytes long. Attempting to -* create a salt with fewer than 8 bytes will result in an error. -* -* # CBOR Serialization -* -* `Salt` implements the CBOR tagged encoding interfaces, which means it can be -* serialized to and deserialized from CBOR with a specific tag (TAG_SALT = 40018). -* -* # UR Serialization -* -* When serialized as a Uniform Resource (UR), a `Salt` is represented as a -* binary blob with the type "salt". -* -* # Common Uses -* -* - Password hashing and key derivation functions -* - Preventing correlation in cryptographic protocols -* - Randomizing data before encryption to prevent pattern recognition -* - Adding entropy to improve security in various cryptographic functions -* -* @example -* ```typescript -* import { Salt } from '@bcts/components'; -* -* // Generate a salt with 16 bytes -* const salt = Salt.newWithLen(16); -* console.log(salt.len()); // 16 -* -* // Generate a salt proportional to 100 bytes of data -* const salt2 = Salt.newForSize(100); -* -* // Generate a salt with length between 16 and 32 bytes -* const salt3 = Salt.newInRange(16, 32); -* ``` -*/ -const MIN_SALT_SIZE$1 = 8; -var Salt = class Salt { - _data; - constructor(data) { - this._data = new Uint8Array(data); - } - /** - * Create a new salt from data. - * Note: Does not validate minimum size to allow for CBOR deserialization. - */ - static fromData(data) { - return new Salt(new Uint8Array(data)); - } - /** - * Create a Salt from raw bytes (legacy alias). - */ - static from(data) { - return Salt.fromData(data); - } - /** - * Create a new salt from the given hexadecimal string. - */ - static fromHex(hex) { - return Salt.fromData(hexToBytes(hex)); - } - /** - * Create a specific number of bytes of salt. - * - * @throws Error if the number of bytes is less than 8. - */ - static newWithLen(count) { - const rng = new SecureRandomNumberGenerator(); - return Salt.newWithLenUsing(count, rng); - } - /** - * Create a specific number of bytes of salt using provided RNG. - * - * @throws Error if the number of bytes is less than 8. - */ - static newWithLenUsing(count, rng) { - if (count < MIN_SALT_SIZE$1) throw CryptoError.dataTooShort("salt", MIN_SALT_SIZE$1, count); - return new Salt(rng.randomData(count)); - } - /** - * Create a number of bytes of salt chosen randomly from the given range. - * - * @throws Error if the minimum number of bytes is less than 8. - */ - static newInRange(minSize, maxSize) { - if (minSize < MIN_SALT_SIZE$1) throw CryptoError.dataTooShort("salt", MIN_SALT_SIZE$1, minSize); - const rng = new SecureRandomNumberGenerator(); - return Salt.newInRangeUsing(minSize, maxSize, rng); - } - /** - * Create a number of bytes of salt chosen randomly from the given range using provided RNG. - * - * @throws Error if the minimum number of bytes is less than 8. - */ - static newInRangeUsing(minSize, maxSize, rng) { - if (minSize < MIN_SALT_SIZE$1) throw CryptoError.dataTooShort("salt", MIN_SALT_SIZE$1, minSize); - const count = rngNextInClosedRangeI32(rng, minSize, maxSize); - return Salt.newWithLenUsing(count, rng); - } - /** - * Create a number of bytes of salt generally proportionate to the size of - * the object being salted. - */ - static newForSize(size) { - const rng = new SecureRandomNumberGenerator(); - return Salt.newForSizeUsing(size, rng); - } - /** - * Create a number of bytes of salt generally proportionate to the size of - * the object being salted using provided RNG. - */ - static newForSizeUsing(size, rng) { - const count = size; - const minSize = Math.max(MIN_SALT_SIZE$1, Math.ceil(count * .05)); - const maxSize = Math.max(minSize + 8, Math.ceil(count * .25)); - return Salt.newInRangeUsing(minSize, maxSize, rng); - } - /** - * Generate a random salt with specified size (legacy alias for newWithLen). - */ - static random(size = 16) { - return Salt.newWithLen(size); - } - /** - * Generate a random salt with specified size using provided RNG (legacy alias). - */ - static randomUsing(rng, size = 16) { - return Salt.newWithLenUsing(size, rng); - } - /** - * Generate a proportionally-sized salt (legacy alias for newForSize). - */ - static proportional(dataSize) { - return Salt.newForSize(dataSize); - } - /** - * Return the length of the salt. - */ - len() { - return this._data.length; - } - /** - * Return the length of the salt (alias for len). - */ - size() { - return this.len(); - } - /** - * Return true if the salt is empty (this is not recommended). - */ - isEmpty() { - return this._data.length === 0; - } - /** - * Return the data of the salt. - */ - asBytes() { - return this._data; - } - /** - * Get the raw salt bytes as a copy. - */ - toData() { - return new Uint8Array(this._data); - } - /** - * The data as a hexadecimal string. - */ - hex() { - return bytesToHex$1(this._data); - } - /** - * Get hex string representation (alias for hex()). - */ - toHex() { - return this.hex(); - } - /** - * Get base64 representation. - */ - toBase64() { - return toBase64$1(this._data); - } - /** - * Compare with another Salt. - */ - equals(other) { - if (this._data.length !== other._data.length) return false; - for (let i = 0; i < this._data.length; i++) if (this._data[i] !== other._data[i]) return false; - return true; - } - /** - * Get string representation showing the salt's length. - */ - toString() { - return `Salt(${this.len()})`; - } - /** - * Returns the CBOR tags associated with Salt. - */ - cborTags() { - return tagsForValues([SALT$2.value]); - } - /** - * Returns the untagged CBOR encoding (as a byte string). - */ - untaggedCbor() { - return toByteString(this._data); - } - /** - * Returns the tagged CBOR encoding. - */ - taggedCbor() { - return createTaggedCbor(this); - } - /** - * Returns the tagged value in CBOR binary representation. - */ - taggedCborData() { - return this.taggedCbor().toData(); - } - /** - * Creates a Salt by decoding it from untagged CBOR. - */ - fromUntaggedCbor(cbor) { - const data = expectBytes(cbor); - return Salt.fromData(data); - } - /** - * Creates a Salt by decoding it from tagged CBOR. - */ - fromTaggedCbor(cbor) { - validateTag(cbor, this.cborTags()); - const content = extractTaggedContent(cbor); - return this.fromUntaggedCbor(content); - } - /** - * Static method to decode from tagged CBOR. - */ - static fromTaggedCbor(cbor) { - return new Salt(/* @__PURE__ */ new Uint8Array(0)).fromTaggedCbor(cbor); - } - /** - * Static method to decode from tagged CBOR binary data. - */ - static fromTaggedCborData(data) { - const cbor = decodeCbor(data); - return Salt.fromTaggedCbor(cbor); - } - /** - * Static method to decode from untagged CBOR binary data. - */ - static fromUntaggedCborData(data) { - const cbor = decodeCbor(data); - const bytes = expectBytes(cbor); - return Salt.fromData(bytes); - } - /** - * Returns the UR representation of the Salt. - * Note: URs use untagged CBOR since the type is conveyed by the UR type itself. - */ - ur() { - return UR.new("salt", this.untaggedCbor()); - } - /** - * Returns the UR string representation. - */ - urString() { - return this.ur().string(); - } - /** - * Creates a Salt from a UR. - */ - static fromUR(ur) { - ur.checkType("salt"); - return new Salt(/* @__PURE__ */ new Uint8Array(0)).fromUntaggedCbor(ur.cbor()); - } - /** - * Creates a Salt from a UR string. - */ - static fromURString(urString) { - const ur = UR.fromURString(urString); - return Salt.fromUR(ur); - } -}; -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -* -* Cryptographic seed with optional metadata (minimum 16 bytes) -* Ported from bc-components-rust/src/seed.rs -* -* A `Seed` is a source of entropy used to generate cryptographic keys in a -* deterministic manner. Unlike randomly generated keys, seed-derived keys can -* be recreated if you have the original seed, making them useful for backup -* and recovery scenarios. -* -* This implementation of `Seed` includes the random seed data as well as -* optional metadata: -* - A name (for identifying the seed) -* - A note (for storing additional information) -* - A creation date -* -* The minimum seed length is 16 bytes to ensure sufficient security and -* entropy. -* -* # CBOR Serialization -* -* `Seed` implements the CBOR tagged encoding interfaces, which means it can be -* serialized to and deserialized from CBOR with specific tags. The tags used -* are `TAG_SEED` (40300) and the older `TAG_SEED_V1` (300) for backward compatibility. -* -* When serialized to CBOR, a `Seed` is represented as a map with the following -* keys: -* - 1: The seed data (required) -* - 2: The creation date (optional) -* - 3: The name (optional, omitted if empty) -* - 4: The note (optional, omitted if empty) -* -* # UR Serialization -* -* When serialized as a Uniform Resource (UR), a `Seed` is represented with the -* type "seed". -*/ -var Seed = class Seed { - /** - * Minimum seed length in bytes (matches Rust MIN_SEED_LENGTH). - */ - static MIN_SEED_LENGTH = 16; - _data; - _name; - _note; - _creationDate; - constructor(data, name, note, creationDate) { - if (data.length < Seed.MIN_SEED_LENGTH) throw CryptoError.dataTooShort("seed", Seed.MIN_SEED_LENGTH, data.length); - this._data = new Uint8Array(data); - this._name = name ?? ""; - this._note = note ?? ""; - this._creationDate = creationDate; - } - /** - * Create a new random seed with default length (16 bytes). - * - * Rust equivalent: `Seed::new()` - */ - static new() { - return Seed.newWithLen(Seed.MIN_SEED_LENGTH); - } - /** - * Create a new random seed with a specified length. - * - * Rust equivalent: `Seed::new_with_len(count)` - * - * @param count - Number of bytes (must be >= 16) - * @throws CryptoError if count < 16 - */ - static newWithLen(count) { - const rng = new SecureRandomNumberGenerator(); - return Seed.newWithLenUsing(count, rng); - } - /** - * Create a new random seed with a specified length using provided RNG. - * - * Rust equivalent: `Seed::new_with_len_using(count, rng)` - * - * @param count - Number of bytes (must be >= 16) - * @param rng - Random number generator - * @throws CryptoError if count < 16 - */ - static newWithLenUsing(count, rng) { - const data = rng.randomData(count); - return Seed.newOpt(data, void 0, void 0, void 0); - } - /** - * Create a new seed from data and optional metadata. - * - * Rust equivalent: `Seed::new_opt(data, name, note, creation_date)` - * - * @param data - Seed bytes (must be >= 16 bytes) - * @param name - Optional name for the seed - * @param note - Optional note for the seed - * @param creationDate - Optional creation date - * @throws CryptoError if data < 16 bytes - */ - static newOpt(data, name, note, creationDate) { - return new Seed(data, name, note, creationDate); - } - /** - * Create a Seed from raw bytes with optional metadata. - * - * Note: The input data is copied to prevent external mutation of the seed's internal state. - * - * @param data - Seed bytes (must be >= 16 bytes) - * @param metadata - Optional metadata object - */ - static from(data, metadata) { - return new Seed(new Uint8Array(data), metadata?.name, metadata?.note, metadata?.createdAt); - } - /** - * Create a Seed from hex string with optional metadata. - * - * @param hex - Hex string representing seed bytes - * @param metadata - Optional metadata object - */ - static fromHex(hex, metadata) { - return Seed.from(hexToBytes(hex), metadata); - } - /** - * Generate a random seed with specified size (default 32 bytes). - * - * Convenience method that wraps `newWithLen()`. - * - * @param size - Number of bytes (must be >= 16, default 32) - * @param metadata - Optional metadata object - */ - static random(size = 32, metadata) { - const seed = Seed.newWithLen(size); - if (metadata?.name !== void 0) seed.setName(metadata.name); - if (metadata?.note !== void 0) seed.setNote(metadata.note); - if (metadata?.createdAt !== void 0) seed.setCreationDate(metadata.createdAt); - return seed; - } - /** - * Generate a random seed using provided RNG. - * - * Convenience method that wraps `newWithLenUsing()`. - * - * @param rng - Random number generator - * @param size - Number of bytes (must be >= 16, default 32) - * @param metadata - Optional metadata object - */ - static randomUsing(rng, size = 32, metadata) { - const seed = Seed.newWithLenUsing(size, rng); - if (metadata?.name !== void 0) seed.setName(metadata.name); - if (metadata?.note !== void 0) seed.setNote(metadata.note); - if (metadata?.createdAt !== void 0) seed.setCreationDate(metadata.createdAt); - return seed; - } - /** - * Return the data of the seed as a reference to the internal bytes. - * - * Rust equivalent: `seed.as_bytes()` - * - * Note: Returns a reference to internal data. For a copy, use `toData()`. - */ - asBytes() { - return this._data; - } - /** - * Get the raw seed bytes (copy). - * - * Note: Returns a copy to prevent external mutation of the seed's internal state. - */ - toData() { - return new Uint8Array(this._data); - } - /** - * Get hex string representation. - */ - toHex() { - return bytesToHex$1(this._data); - } - /** - * Get base64 representation. - */ - toBase64() { - return toBase64$1(this._data); - } - /** - * Get seed size in bytes. - */ - size() { - return this._data.length; - } - /** - * Return the name of the seed. - * - * Rust equivalent: `seed.name()` - returns empty string if not set. - */ - name() { - return this._name; - } - /** - * Set the name of the seed. - * - * Rust equivalent: `seed.set_name(name)` - */ - setName(name) { - this._name = name; - } - /** - * Return the note of the seed. - * - * Rust equivalent: `seed.note()` - returns empty string if not set. - */ - note() { - return this._note; - } - /** - * Set the note of the seed. - * - * Rust equivalent: `seed.set_note(note)` - */ - setNote(note) { - this._note = note; - } - /** - * Return the creation date of the seed. - * - * Rust equivalent: `seed.creation_date()` - */ - creationDate() { - return this._creationDate; - } - /** - * Set the creation date of the seed. - * - * Rust equivalent: `seed.set_creation_date(date)` - */ - setCreationDate(creationDate) { - this._creationDate = creationDate; - } - /** - * Return the creation date of the seed (alias for creationDate). - * - * @deprecated Use `creationDate()` for Rust API parity. - */ - createdAt() { - return this.creationDate(); - } - /** - * Set the creation date of the seed (alias for setCreationDate). - * - * @deprecated Use `setCreationDate()` for Rust API parity. - */ - setCreatedAt(date) { - this.setCreationDate(date); - } - /** - * Get metadata as an object. - * - * TypeScript convenience method - returns a snapshot of current metadata. - */ - getMetadata() { - const metadata = {}; - if (this._name.length > 0) metadata.name = this._name; - if (this._note.length > 0) metadata.note = this._note; - if (this._creationDate !== void 0) metadata.createdAt = this._creationDate; - return metadata; - } - /** - * Compare with another Seed. - */ - equals(other) { - if (this._data.length !== other._data.length) return false; - for (let i = 0; i < this._data.length; i++) if (this._data[i] !== other._data[i]) return false; - return true; - } - /** - * Get string representation. - */ - toString() { - return `Seed(${this.toHex().substring(0, 16)}..., ${this.size()} bytes)`; - } - /** - * Returns unique data from which cryptographic keys can be derived. - * - * This implementation returns a copy of the seed data, which can be used - * as entropy for deriving private keys in various cryptographic schemes. - * - * @returns A Uint8Array containing the seed data - */ - privateKeyData() { - return this.toData(); - } - /** - * Returns the CBOR tags associated with Seed. - * Includes TAG_SEED (40300) and TAG_SEED_V1 (300) for backward compatibility. - */ - cborTags() { - return tagsForValues([SEED.value, SEED_V1.value]); - } - /** - * Returns the untagged CBOR encoding (as a map). - * Map keys: - * - 1: seed data (required) - * - 2: creation date (optional) - * - 3: name (optional, omitted if empty) - * - 4: note (optional, omitted if empty) - */ - untaggedCbor() { - const map = CborMap.new(); - map.insert(1, toByteString(this._data)); - if (this._creationDate !== void 0) { - const cborDate = CborDate.fromDatetime(this._creationDate); - map.insert(2, cborDate.taggedCbor()); - } - if (this._name.length > 0) map.insert(3, this._name); - if (this._note.length > 0) map.insert(4, this._note); - return cbor(map); - } - /** - * Returns the tagged CBOR encoding. - */ - taggedCbor() { - return createTaggedCbor(this); - } - /** - * Returns the tagged value in CBOR binary representation. - */ - taggedCborData() { - return this.taggedCbor().toData(); - } - /** - * Creates a Seed by decoding it from untagged CBOR. - */ - fromUntaggedCbor(cborValue) { - const map = expectMap(cborValue); - const data = map.extract(1); - if (data.length === 0) throw CryptoError.invalidData("Seed data is empty"); - let creationDate; - const dateValue = map.get(2); - if (dateValue !== void 0) creationDate = CborDate.fromTaggedCbor(cbor(dateValue)).datetime(); - const name = map.get(3); - const note = map.get(4); - return Seed.newOpt(new Uint8Array(data), name, note, creationDate); - } - /** - * Creates a Seed by decoding it from tagged CBOR. - */ - fromTaggedCbor(cbor) { - validateTag(cbor, this.cborTags()); - const content = extractTaggedContent(cbor); - return this.fromUntaggedCbor(content); - } - /** - * Static method to decode from tagged CBOR. - */ - static fromTaggedCbor(cborValue) { - return Seed.new().fromTaggedCbor(cborValue); - } - /** - * Static method to decode from tagged CBOR binary data. - */ - static fromTaggedCborData(data) { - const cborValue = decodeCbor(data); - return Seed.fromTaggedCbor(cborValue); - } - /** - * Static method to decode from untagged CBOR binary data. - */ - static fromUntaggedCborData(data) { - const cborValue = decodeCbor(data); - return Seed.new().fromUntaggedCbor(cborValue); - } - /** - * Returns the UR representation of the Seed. - * Note: URs use untagged CBOR since the type is conveyed by the UR type itself. - */ - ur() { - return UR.new("seed", this.untaggedCbor()); - } - /** - * Returns the UR string representation. - */ - urString() { - return this.ur().string(); - } - /** - * Creates a Seed from a UR. - */ - static fromUR(ur) { - ur.checkType("seed"); - return Seed.new().fromUntaggedCbor(ur.cbor()); - } - /** - * Creates a Seed from a UR string. - */ - static fromURString(urString) { - const ur = UR.fromURString(urString); - return Seed.fromUR(ur); - } -}; -/** -* A globally unique reference to a globally unique object. -* -* Internally stores 32 raw bytes (matches Rust's `Reference([u8; 32])`). -* Most callers obtain a `Reference` via `fromDigest`, but `XID` (and similar -* content-addressable types whose bytes _are_ the reference) construct -* via `fromData` directly. -*/ -var Reference = class Reference { - /** Reference data size in bytes — matches Rust `Reference::REFERENCE_SIZE`. */ - static REFERENCE_SIZE = 32; - _data; - constructor(data) { - this._data = data; - } - /** Create a Reference from exactly 32 bytes. Mirrors Rust `Reference::from_data`. */ - static fromData(data) { - if (data.length !== Reference.REFERENCE_SIZE) throw CryptoError.invalidSize(Reference.REFERENCE_SIZE, data.length); - return new Reference(new Uint8Array(data)); - } - /** Alias of `fromData` for parity with Rust `from_data_ref`. */ - static fromDataRef(data) { - return Reference.fromData(data); - } - /** Create a Reference from a Digest's underlying bytes. */ - static fromDigest(digest) { - return new Reference(new Uint8Array(digest.toData())); - } - /** Backwards-compatible alias of `fromDigest`. */ - static from(digest) { - return Reference.fromDigest(digest); - } - /** Create a Reference from a 64-character hex string. */ - static fromHex(hex) { - return Reference.fromData(hexToBytes(hex)); - } - /** - * Create a Reference whose bytes are the SHA-256 digest of the input. - * - * @deprecated Prefer `Reference.fromDigest(Digest.fromImage(data))` for - * clarity, or `Reference.fromData(data)` if `data` is already 32 bytes - * that should be wrapped without hashing (matches Rust `from_data`). - */ - static hash(data) { - return Reference.fromDigest(Digest.fromImage(data)); - } - /** Returns the 32 reference bytes (copy). */ - data() { - return new Uint8Array(this._data); - } - /** Alias of `data()`. */ - asBytes() { - return this.data(); - } - /** Returns a `Digest` constructed from these 32 bytes (no hashing). */ - getDigest() { - return Digest.fromData(this._data); - } - /** The full 64-character lowercase hex of the reference. */ - refHex() { - return bytesToHex$1(this._data); - } - /** The first 4 bytes of the reference. */ - refDataShort() { - return this._data.slice(0, 4); - } - /** The first 4 bytes of the reference, as 8 lowercase hex characters. */ - refHexShort() { - return bytesToHex$1(this._data.slice(0, 4)); - } - /** - * The first 4 bytes as upper-case bytewords identifier. - * - * @param prefix - Optional prefix prepended with a single space. - */ - bytewordsIdentifier(prefix) { - const s = encodeBytewordsIdentifier(this.refDataShort()).toUpperCase(); - return prefix !== void 0 ? `${prefix} ${s}` : s; - } - /** - * The first 4 bytes as upper-case bytemojis identifier. - * - * @param prefix - Optional prefix prepended with a single space. - */ - bytemojiIdentifier(prefix) { - const s = encodeBytemojisIdentifier(this.refDataShort()).toUpperCase(); - return prefix !== void 0 ? `${prefix} ${s}` : s; - } - /** Backwards-compatible alias of `refHex()`. */ - toHex() { - return this.refHex(); - } - /** Backwards-compatible alias of `refHex()`. */ - fullReference() { - return this.refHex(); - } - /** Returns the 32 raw bytes encoded as base64. */ - toBase64() { - return toBase64$1(this._data); - } - /** - * Returns a short representation of this reference in the requested format. - * - * Mirrors the legacy TS API; new code should prefer `refHexShort`, - * `bytewordsIdentifier`, or `bytemojiIdentifier` directly. - */ - shortReference(format = "hex") { - switch (format) { - case "hex": return this.refHexShort(); - case "bytewords": return encodeBytewordsIdentifier(this.refDataShort()); - case "bytemojis": return encodeBytemojisIdentifier(this.refDataShort()); - default: { - const _exhaustive = format; - throw CryptoError.invalidFormat(`Unknown reference format: ${String(_exhaustive)}`); - } - } - } - /** A Reference to this Reference (matches Rust's blanket `ReferenceProvider` impl). */ - reference() { - return Reference.fromDigest(this.digest()); - } - /** - * SHA-256 of `taggedCbor().toCborData()`. - * - * Matches Rust's `DigestProvider for Reference` — - * `Digest::from_image(self.tagged_cbor().to_cbor_data())`. - */ - digest() { - return Digest.fromImage(this.taggedCborData()); - } - cborTags() { - return tagsForValues([REFERENCE.value]); - } - /** Untagged CBOR — a single byte string of the 32 raw bytes. */ - untaggedCbor() { - return toByteString(this._data); - } - taggedCbor() { - return createTaggedCbor(this); - } - taggedCborData() { - return this.taggedCbor().toData(); - } - fromUntaggedCbor(cbor) { - return Reference.fromData(expectBytes(cbor)); - } - fromTaggedCbor(cbor) { - validateTag(cbor, this.cborTags()); - return this.fromUntaggedCbor(extractTaggedContent(cbor)); - } - static fromTaggedCbor(cbor) { - return new Reference(new Uint8Array(Reference.REFERENCE_SIZE)).fromTaggedCbor(cbor); - } - static fromTaggedCborData(data) { - return Reference.fromTaggedCbor(decodeCbor(data)); - } - static fromUntaggedCborData(data) { - return new Reference(new Uint8Array(Reference.REFERENCE_SIZE)).fromUntaggedCbor(decodeCbor(data)); - } - static UR_TYPE = "reference"; - /** UR representation — `ur:reference/...`, untagged CBOR payload. */ - ur() { - return UR.new(Reference.UR_TYPE, this.untaggedCbor()); - } - urString() { - return this.ur().string(); - } - static fromUR(ur) { - ur.checkType(Reference.UR_TYPE); - return new Reference(new Uint8Array(Reference.REFERENCE_SIZE)).fromUntaggedCbor(ur.cbor()); - } - static fromURString(s) { - return Reference.fromUR(UR.fromURString(s)); - } - equals(other) { - if (this._data.length !== other._data.length) return false; - for (let i = 0; i < this._data.length; i++) if (this._data[i] !== other._data[i]) return false; - return true; - } - /** Debug-style representation: `Reference(<8-hex-prefix>)`. */ - toString() { - return `Reference(${this.refHexShort()})`; - } -}; -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -* -* An "Apparently Random Identifier" (ARID) -* -* Ported from bc-components-rust/src/id/arid.rs -* -* An ARID is a cryptographically strong, universally unique identifier with -* the following properties: -* - Non-correlatability: The sequence of bits cannot be correlated with its -* referent or any other ARID -* - Neutral semantics: Contains no inherent type information -* - Open generation: Any method of generation is allowed as long as it -* produces statistically random bits -* - Minimum strength: Must be 256 bits (32 bytes) in length -* - Cryptographic suitability: Can be used as inputs to cryptographic -* constructs -* -* Unlike digests/hashes which identify a fixed, immutable state of data, ARIDs -* can serve as stable identifiers for mutable data structures. -* -* ARIDs should not be confused with or cast to/from other identifier types -* (like UUIDs), used as nonces, keys, or cryptographic seeds. -* -* As defined in [BCR-2022-002](https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2022-002-arid.md). -* -* # CBOR Serialization -* -* `ARID` implements the CBOR tagged encoding interfaces, which means it can be -* serialized to and deserialized from CBOR with a specific tag (TAG_ARID = 40012). -* -* # UR Serialization -* -* When serialized as a Uniform Resource (UR), an `ARID` is represented as a -* binary blob with the type "arid". -* -* @example -* ```typescript -* import { ARID } from '@bcts/components'; -* -* // Create a new random ARID -* const arid = ARID.new(); -* -* // Create an ARID from a hex string -* const arid2 = ARID.fromHex("..."); -* -* // Get the ARID as hex -* console.log(arid.hex()); -* ``` -*/ -var ARID = class ARID { - static ARID_SIZE = 32; - _data; - constructor(data) { - if (data.length !== ARID.ARID_SIZE) throw CryptoError.invalidSize(ARID.ARID_SIZE, data.length); - this._data = new Uint8Array(data); - } - /** - * Create a new random ARID. - */ - static new() { - const rng = new SecureRandomNumberGenerator(); - return new ARID(rng.randomData(ARID.ARID_SIZE)); - } - /** - * Create a new random ARID (alias for new()). - */ - static random() { - return ARID.new(); - } - /** - * Restore an ARID from a fixed-size array of bytes. - */ - static fromData(data) { - return new ARID(new Uint8Array(data)); - } - /** - * Create a new ARID from a reference to an array of bytes. - */ - static fromDataRef(data) { - if (data.length !== ARID.ARID_SIZE) throw CryptoError.invalidSize(ARID.ARID_SIZE, data.length); - return ARID.fromData(data); - } - /** - * Create an ARID from raw bytes (legacy alias). - */ - static from(data) { - return ARID.fromData(data); - } - /** - * Create a new ARID from the given hexadecimal string. - * - * @throws Error if the string is not exactly 64 hexadecimal digits. - */ - static fromHex(hex) { - return new ARID(hexToBytes(hex)); - } - /** - * Get the data of the ARID as an array of bytes. - */ - data() { - return this._data; - } - /** - * Get the data of the ARID as a byte slice. - */ - asBytes() { - return this._data; - } - /** - * Get the raw ARID bytes as a copy. - */ - toData() { - return new Uint8Array(this._data); - } - /** - * The data as a hexadecimal string. - */ - hex() { - return bytesToHex$1(this._data); - } - /** - * Get hex string representation (alias for hex()). - */ - toHex() { - return this.hex(); - } - /** - * Get base64 representation. - */ - toBase64() { - return toBase64$1(this._data); - } - /** - * The first four bytes of the ARID as a hexadecimal string. - */ - shortDescription() { - return bytesToHex$1(this._data.slice(0, 4)); - } - /** - * Compare with another ARID. - */ - equals(other) { - if (this._data.length !== other._data.length) return false; - for (let i = 0; i < this._data.length; i++) if (this._data[i] !== other._data[i]) return false; - return true; - } - /** - * Compare ARIDs lexicographically. - */ - compare(other) { - for (let i = 0; i < this._data.length; i++) { - const a = this._data[i]; - const b = other._data[i]; - if (a < b) return -1; - if (a > b) return 1; - } - return 0; - } - /** - * Get string representation. - */ - toString() { - return `ARID(${this.hex()})`; - } - /** - * Returns the CBOR tags associated with ARID. - */ - cborTags() { - return tagsForValues([ARID$1.value]); - } - /** - * Returns the untagged CBOR encoding (as a byte string). - */ - untaggedCbor() { - return toByteString(this._data); - } - /** - * Returns the tagged CBOR encoding. - */ - taggedCbor() { - return createTaggedCbor(this); - } - /** - * Returns the tagged value in CBOR binary representation. - */ - taggedCborData() { - return this.taggedCbor().toData(); - } - /** - * Creates an ARID by decoding it from untagged CBOR. - */ - fromUntaggedCbor(cbor) { - const data = expectBytes(cbor); - return ARID.fromDataRef(data); - } - /** - * Creates an ARID by decoding it from tagged CBOR. - */ - fromTaggedCbor(cbor) { - validateTag(cbor, this.cborTags()); - const content = extractTaggedContent(cbor); - return this.fromUntaggedCbor(content); - } - /** - * Static method to decode from tagged CBOR. - */ - static fromTaggedCbor(cbor) { - return new ARID(new Uint8Array(ARID.ARID_SIZE)).fromTaggedCbor(cbor); - } - /** - * Static method to decode from tagged CBOR binary data. - */ - static fromTaggedCborData(data) { - const cbor = decodeCbor(data); - return ARID.fromTaggedCbor(cbor); - } - /** - * Static method to decode from untagged CBOR binary data. - */ - static fromUntaggedCborData(data) { - const cbor = decodeCbor(data); - const bytes = expectBytes(cbor); - return ARID.fromDataRef(bytes); - } - /** - * Returns the UR representation of the ARID. - * Note: URs use untagged CBOR since the type is conveyed by the UR type itself. - */ - ur() { - return UR.new("arid", this.untaggedCbor()); - } - /** - * Returns the UR string representation. - */ - urString() { - return this.ur().string(); - } - /** - * Creates an ARID from a UR. - */ - static fromUR(ur) { - ur.checkType("arid"); - return new ARID(new Uint8Array(ARID.ARID_SIZE)).fromUntaggedCbor(ur.cbor()); - } - /** - * Creates an ARID from a UR string. - */ - static fromURString(urString) { - const ur = UR.fromURString(urString); - return ARID.fromUR(ur); - } - /** - * Alias for fromURString for Rust API compatibility. - */ - static fromUrString(urString) { - return ARID.fromURString(urString); - } -}; -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -* -* Universally Unique Identifier (UUID) - 16-byte identifier -* -* UUIDs are 128-bit (16-byte) identifiers that are designed to be unique -* across space and time. This implementation creates type 4 (random) UUIDs, -* following the UUID specification: -* -* - Version field (bits 48-51) is set to 4, indicating a random UUID -* - Variant field (bits 64-65) is set to 2, indicating RFC 4122/DCE 1.1 UUID -* variant -* -* Unlike ARIDs, UUIDs: -* - Are shorter (128 bits vs 256 bits) -* - Contain version and variant metadata within the identifier -* - Have a canonical string representation with 5 groups separated by hyphens -* -* The canonical textual representation of a UUID takes the form: -* `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx` where each `x` is a hexadecimal digit. -* -* # CBOR Serialization -* -* `UUID` is serialized to CBOR with tag 37 (standard UUID tag). -* -* # UR Serialization -* -* When serialized as a Uniform Resource (UR), a `UUID` is represented with the -* type "uuid". -*/ -const UUID_SIZE = 16; -var UUID = class UUID { - static UUID_SIZE = UUID_SIZE; - _data; - constructor(data) { - if (data.length !== UUID_SIZE) throw CryptoError.invalidSize(UUID_SIZE, data.length); - this._data = new Uint8Array(data); - } - /** - * Create a new random UUID (v4). - */ - static new() { - return UUID.random(); - } - /** - * Create a UUID from raw bytes. - */ - static fromData(data) { - return new UUID(new Uint8Array(data)); - } - /** - * Restores a UUID from data (validates length). - */ - static fromDataRef(data) { - if (data.length !== UUID_SIZE) throw CryptoError.invalidSize(UUID_SIZE, data.length); - return UUID.fromData(data); - } - /** - * Create a UUID from raw bytes (legacy alias). - */ - static from(data) { - return UUID.fromData(data); - } - /** - * Create a UUID from hex string (32 hex chars) - */ - static fromHex(hex) { - if (hex.length !== 32) throw CryptoError.invalidFormat(`UUID hex must be 32 characters, got ${hex.length}`); - const data = /* @__PURE__ */ new Uint8Array(16); - for (let i = 0; i < 16; i++) data[i] = parseInt(hex.substring(i * 2, i * 2 + 2), 16); - return new UUID(data); - } - /** - * Create a UUID from string representation (standard UUID format) - * Format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - */ - static fromString(uuidString) { - if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(uuidString)) throw CryptoError.invalidFormat(`Invalid UUID format: ${uuidString}`); - const hex = uuidString.replace(/-/g, ""); - return UUID.fromHex(hex); - } - /** - * Generate a random UUID (v4) - */ - static random() { - const data = new Uint8Array(UUID_SIZE); - globalThis.crypto.getRandomValues(data); - data[6] = data[6] & 15 | 64; - data[8] = data[8] & 63 | 128; - return new UUID(data); - } - /** - * Get the data of the UUID. - */ - data() { - return this._data; - } - /** - * Get the UUID as a byte slice. - */ - asBytes() { - return this._data; - } - /** - * Get the raw UUID bytes as a copy. - */ - toData() { - return new Uint8Array(this._data); - } - /** - * Get hex string representation (lowercase, matching Rust implementation). - */ - hex() { - return bytesToHex$1(this._data); - } - /** - * Get hex string representation (alias for hex()). - */ - toHex() { - return this.hex(); - } - /** - * Get standard UUID string representation. - * Format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - */ - toString() { - const hex = this.toHex(); - return `${hex.substring(0, 8)}-${hex.substring(8, 12)}-${hex.substring(12, 16)}-${hex.substring(16, 20)}-${hex.substring(20)}`; - } - /** - * Get base64 representation. - */ - toBase64() { - return toBase64$1(this._data); - } - /** - * Compare with another UUID. - */ - equals(other) { - if (this._data.length !== other._data.length) return false; - for (let i = 0; i < this._data.length; i++) if (this._data[i] !== other._data[i]) return false; - return true; - } - /** - * Returns the CBOR tags associated with UUID. - */ - cborTags() { - return tagsForValues([UUID$1.value]); - } - /** - * Returns the untagged CBOR encoding (as a byte string). - */ - untaggedCbor() { - return toByteString(this._data); - } - /** - * Returns the tagged CBOR encoding. - */ - taggedCbor() { - return createTaggedCbor(this); - } - /** - * Returns the tagged value in CBOR binary representation. - */ - taggedCborData() { - return this.taggedCbor().toData(); - } - /** - * Creates a UUID by decoding it from untagged CBOR. - */ - fromUntaggedCbor(cbor) { - const data = expectBytes(cbor); - return UUID.fromDataRef(data); - } - /** - * Creates a UUID by decoding it from tagged CBOR. - */ - fromTaggedCbor(cbor) { - validateTag(cbor, this.cborTags()); - const content = extractTaggedContent(cbor); - return this.fromUntaggedCbor(content); - } - /** - * Static method to decode from tagged CBOR. - */ - static fromTaggedCbor(cbor) { - return new UUID(new Uint8Array(UUID_SIZE)).fromTaggedCbor(cbor); - } - /** - * Static method to decode from tagged CBOR binary data. - */ - static fromTaggedCborData(data) { - const cbor = decodeCbor(data); - return UUID.fromTaggedCbor(cbor); - } - /** - * Static method to decode from untagged CBOR binary data. - */ - static fromUntaggedCborData(data) { - const cbor = decodeCbor(data); - const bytes = expectBytes(cbor); - return UUID.fromDataRef(bytes); - } - /** - * Returns the UR representation of the UUID. - * Note: URs use untagged CBOR since the type is conveyed by the UR type itself. - */ - ur() { - return UR.new("uuid", this.untaggedCbor()); - } - /** - * Returns the UR string representation. - */ - urString() { - return this.ur().string(); - } - /** - * Creates a UUID from a UR. - */ - static fromUR(ur) { - ur.checkType("uuid"); - return new UUID(new Uint8Array(UUID_SIZE)).fromUntaggedCbor(ur.cbor()); - } - /** - * Creates a UUID from a UR string. - */ - static fromURString(urString) { - const ur = UR.fromURString(urString); - return UUID.fromUR(ur); - } -}; -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -* -* eXtensible Identifier (XID) - 32-byte identifier bound to a public key -* -* A XID is a unique 32-byte identifier for a subject entity (person, -* organization, device, or any other entity). XIDs have the following -* characteristics: -* -* - They're cryptographically tied to a public key at inception (the -* "inception key") -* - They remain stable throughout their lifecycle even as their keys and -* permissions change -* - They can be extended to XID documents containing keys, endpoints, -* permissions, and delegation info -* - They support key rotation and multiple verification schemes -* - They allow for delegation of specific permissions to other entities -* - They can include resolution methods to locate and verify the XID document -* -* A XID is created by taking the SHA-256 hash of the CBOR encoding of a public -* signing key. This ensures the XID is cryptographically tied to the key. -* -* As defined in [BCR-2024-010](https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2024-010-xid.md). -* -* # CBOR Serialization -* -* `XID` is serialized to CBOR with tag 40024 (standard XID tag). -* -* # UR Serialization -* -* When serialized as a Uniform Resource (UR), a `XID` is represented with the -* type "xid". -*/ -/** -* XID prefix glyph for the upper-case bytewords/bytemoji identifier. -* -* Exported as the single source of truth so dependent packages (`@bcts/xid`, -* `@bcts/envelope`, etc.) don't redefine the literal `"🅧"`. -*/ -const XID_PREFIX = "🅧"; -const XID_SIZE = 32; -var XID = class XID { - static XID_SIZE = XID_SIZE; - _data; - constructor(data) { - if (data.length !== XID_SIZE) throw CryptoError.invalidSize(XID_SIZE, data.length); - this._data = new Uint8Array(data); - } - /** - * Create a new XID from data. - */ - static fromData(data) { - return new XID(new Uint8Array(data)); - } - /** - * Create a new XID from data (validates length). - * - * Returns error if the data is not the correct length. - */ - static fromDataRef(data) { - if (data.length !== XID_SIZE) throw CryptoError.invalidSize(XID_SIZE, data.length); - return XID.fromData(data); - } - /** - * Create an XID from raw bytes (legacy alias). - */ - static from(data) { - return XID.fromData(data); - } - /** - * Create an XID from hex string (64 hex characters). - */ - static fromHex(hex) { - if (hex.length !== 64) throw CryptoError.invalidFormat(`XID hex must be 64 characters, got ${hex.length}`); - const data = /* @__PURE__ */ new Uint8Array(32); - for (let i = 0; i < 32; i++) data[i] = parseInt(hex.substring(i * 2, i * 2 + 2), 16); - return new XID(data); - } - /** - * Generate a random XID (for testing purposes). - * - * Note: In practice, XIDs should be created from the SHA-256 hash of a - * public signing key's CBOR encoding. - */ - static random() { - const data = new Uint8Array(XID_SIZE); - const crypto = globalThis.crypto; - if (crypto !== void 0 && typeof crypto.getRandomValues === "function") crypto.getRandomValues(data); - else for (let i = 0; i < XID_SIZE; i++) data[i] = Math.floor(Math.random() * 256); - return new XID(data); - } - /** - * Create a new XID from the given public key (the "genesis key"). - * - * The XID is the SHA-256 digest of the CBOR encoding of the public key. - * This matches Rust's `XID::new(genesis_key: impl AsRef)`. - */ - static newFromSigningKey(signingPublicKey) { - const keyCborData = signingPublicKey.taggedCborData(); - const digest = Digest.fromImage(keyCborData); - return XID.fromData(digest.toData()); - } - /** - * Mirror of Rust's `From<&SigningPublicKey> for XID`. - * Equivalent to {@link newFromSigningKey}; provided for API parity. - */ - static fromSigningPublicKey(signingPublicKey) { - return XID.newFromSigningKey(signingPublicKey); - } - /** - * Mirror of Rust's `From<&PublicKeys> for XID`. - * The XID is derived from the bundle's signing public key. - */ - static fromPublicKeys(publicKeys) { - return XID.newFromSigningKey(publicKeys.signingPublicKey()); - } - /** - * Mirror of Rust's `From<&PrivateKeyBase> for XID` (secp256k1 feature). - * The XID is derived from the schnorr signing public key. - */ - static fromPrivateKeyBase(base) { - return XID.newFromSigningKey(base.schnorrSigningPrivateKey().publicKey()); - } - /** - * Mirror of Rust's `TryFrom<&SigningPrivateKey> for XID`. - * The XID is derived from the corresponding public key. - */ - static tryFromSigningPrivateKey(signingPrivateKey) { - return XID.newFromSigningKey(signingPrivateKey.publicKey()); - } - /** - * Validate the XID against the given public key. - * - * Returns true if the SHA-256 hash of the key's CBOR encoding matches - * the XID data. This matches Rust's `XID::validate(&self, key: &SigningPublicKey)`. - */ - validate(signingPublicKey) { - const keyData = signingPublicKey.taggedCborData(); - const digest = Digest.fromImage(keyData); - return this.equals(XID.fromData(digest.toData())); - } - /** - * Return the data of the XID. - */ - data() { - return this._data; - } - /** - * Get the data of the XID as a byte slice. - */ - asBytes() { - return this._data; - } - /** - * Get a copy of the raw XID bytes. - */ - toData() { - return new Uint8Array(this._data); - } - /** - * Get hex string representation (lowercase, matching Rust implementation). - */ - toHex() { - return bytesToHex$1(this._data); - } - /** - * Get base64 representation. - */ - toBase64() { - return toBase64$1(this._data); - } - /** - * Get short description (first 4 bytes) as hex. - */ - shortDescription() { - return bytesToHex$1(this._data.slice(0, 4)); - } - /** - * Get short reference (first 4 bytes) as hex (alias for shortDescription). - */ - shortReference() { - return this.shortDescription(); - } - /** - * Get the first four bytes of the XID as upper-case ByteWords. - * - * @param prefix - If true, prepends the XID prefix "🅧 " - * @returns Space-separated uppercase bytewords, e.g., "🅧 URGE DICE GURU IRIS" - */ - bytewordsIdentifier(prefix = false) { - const words = encodeBytewordsIdentifier(this._data.slice(0, 4)).toUpperCase(); - return prefix ? `${XID_PREFIX} ${words}` : words; - } - /** - * Get the first four bytes of the XID as Bytemoji. - * - * @param prefix - If true, prepends the XID prefix "🅧 " - * @returns Space-separated emojis, e.g., "🅧 🐻 😻 🍞 💐" - */ - bytemojisIdentifier(prefix = false) { - const emojis = encodeBytemojisIdentifier(this._data.slice(0, 4)); - return prefix ? `${XID_PREFIX} ${emojis}` : emojis; - } - /** - * XIDProvider impl — returns this XID. - * - * Mirrors Rust's blanket `impl XIDProvider for XID`. - */ - xid() { - return this; - } - /** - * ReferenceProvider impl — produces a Reference whose 32 bytes are the - * raw XID data. - * - * Mirrors Rust's `impl ReferenceProvider for XID { fn reference(&self) -> - * Reference { Reference::from_data(*self.data()) } }` — note this is a - * direct wrap, not a SHA-256 hash of the XID. - */ - reference() { - return Reference.fromData(this._data); - } - /** - * Compare with another XID. - */ - equals(other) { - if (this._data.length !== other._data.length) return false; - for (let i = 0; i < this._data.length; i++) if (this._data[i] !== other._data[i]) return false; - return true; - } - /** - * Get string representation (short format, matching Rust Display). - * Uses first 4 bytes of the XID as hex, e.g., "XID(71274df1)". - */ - toString() { - return `XID(${this.shortDescription()})`; - } - /** - * Returns the CBOR tags associated with XID. - */ - cborTags() { - return tagsForValues([XID$1.value]); - } - /** - * Returns the untagged CBOR encoding (as a byte string). - */ - untaggedCbor() { - return toByteString(this._data); - } - /** - * Returns the tagged CBOR encoding. - */ - taggedCbor() { - return createTaggedCbor(this); - } - /** - * Returns the tagged value in CBOR binary representation. - */ - taggedCborData() { - return this.taggedCbor().toData(); - } - /** - * Creates a XID by decoding it from untagged CBOR. - */ - fromUntaggedCbor(cbor) { - const data = expectBytes(cbor); - return XID.fromDataRef(data); - } - /** - * Creates a XID by decoding it from tagged CBOR. - */ - fromTaggedCbor(cbor) { - validateTag(cbor, this.cborTags()); - const content = extractTaggedContent(cbor); - return this.fromUntaggedCbor(content); - } - /** - * Static method to decode from tagged CBOR. - */ - static fromTaggedCbor(cbor) { - return new XID(new Uint8Array(XID_SIZE)).fromTaggedCbor(cbor); - } - /** - * Static method to decode from tagged CBOR binary data. - */ - static fromTaggedCborData(data) { - const cbor = decodeCbor(data); - return XID.fromTaggedCbor(cbor); - } - /** - * Static method to decode from untagged CBOR binary data. - */ - static fromUntaggedCborData(data) { - const cbor = decodeCbor(data); - const bytes = expectBytes(cbor); - return XID.fromDataRef(bytes); - } - /** - * Returns the UR representation of the XID. - * Note: URs use untagged CBOR since the type is conveyed by the UR type itself. - */ - ur() { - return UR.new("xid", this.untaggedCbor()); - } - /** - * Returns the UR string representation. - */ - urString() { - return this.ur().string(); - } - /** - * Creates a XID from a UR. - */ - static fromUR(ur) { - ur.checkType("xid"); - return new XID(new Uint8Array(XID_SIZE)).fromUntaggedCbor(ur.cbor()); - } - /** - * Creates a XID from a UR string. - */ - static fromURString(urString) { - const ur = UR.fromURString(urString); - return XID.fromUR(ur); - } -}; -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -* -* Uniform Resource Identifier (URI) - String-based identifier -* -* A URI is a string of characters that unambiguously identifies a particular -* resource. This implementation validates URIs using the URL API to ensure -* conformance to RFC 3986. -* -* URIs are commonly used for: -* - Web addresses (URLs like "https://example.com") -* - Resource identifiers in various protocols -* - Namespace identifiers -* - References to resources in distributed systems -* -* # CBOR Serialization -* -* `URI` is serialized to CBOR with tag 32 (standard URI tag). -* -* # UR Serialization -* -* When serialized as a Uniform Resource (UR), a `URI` is represented with the -* type "url". -*/ -var URI = class URI { - _uri; - constructor(uri) { - this._uri = uri; - } - /** - * Creates a new `URI` from a string with validation. - */ - static new(uri) { - try { - new URL(uri); - return new URI(uri); - } catch { - throw CryptoError.invalidData("URI: invalid URI format"); - } - } - /** - * Create a URI from string (legacy alias). - */ - static from(uri) { - return URI.new(uri); - } - /** - * Parse a URI string (alias for new()). - */ - static parse(uriString) { - return URI.new(uriString); - } - /** - * Get the URI as a string reference. - */ - asRef() { - return this._uri; - } - /** - * Get the URI string. - */ - toString() { - return this._uri; - } - /** - * Get the URI string (alias). - */ - toURI() { - return this._uri; - } - /** - * Get the raw URI string. - */ - getRaw() { - return this._uri; - } - /** - * Get scheme (e.g., "http", "https", "urn"). - */ - scheme() { - const match = /^([a-z][a-z0-9+.-]*):\/?\/?/i.exec(this._uri); - return match !== null ? match[1] : null; - } - /** - * Get path component. - */ - path() { - try { - return new URL(this._uri).pathname; - } catch { - return this._uri.replace(/^[a-z][a-z0-9+.-]*:\/?\/?/i, ""); - } - } - /** - * Check if URI is absolute (has a scheme). - */ - isAbsolute() { - return /^[a-z][a-z0-9+.-]*:/i.test(this._uri); - } - /** - * Check if URI is relative. - */ - isRelative() { - return !this.isAbsolute(); - } - /** - * Compare with another URI. - */ - equals(other) { - return this._uri === other._uri; - } - /** - * Check if URI starts with given prefix. - */ - startsWith(prefix) { - return this._uri.startsWith(prefix); - } - /** - * Get base64 representation of the URI string. - */ - toBase64() { - return toBase64$1(new TextEncoder().encode(this._uri)); - } - /** - * Get the length of the URI string. - */ - length() { - return this._uri.length; - } - /** - * Returns the CBOR tags associated with URI. - */ - cborTags() { - return tagsForValues([URI$1.value]); - } - /** - * Returns the untagged CBOR encoding (as a text string). - */ - untaggedCbor() { - return cbor(this._uri); - } - /** - * Returns the tagged CBOR encoding. - */ - taggedCbor() { - return createTaggedCbor(this); - } - /** - * Returns the tagged value in CBOR binary representation. - */ - taggedCborData() { - return this.taggedCbor().toData(); - } - /** - * Creates a URI by decoding it from untagged CBOR. - */ - fromUntaggedCbor(cborValue) { - const text = expectText(cborValue); - return URI.new(text); - } - /** - * Creates a URI by decoding it from tagged CBOR. - */ - fromTaggedCbor(cborValue) { - validateTag(cborValue, this.cborTags()); - const content = extractTaggedContent(cborValue); - return this.fromUntaggedCbor(content); - } - /** - * Static method to decode from tagged CBOR. - */ - static fromTaggedCbor(cborValue) { - return new URI("https://placeholder.invalid").fromTaggedCbor(cborValue); - } - /** - * Static method to decode from tagged CBOR binary data. - */ - static fromTaggedCborData(data) { - const cborValue = decodeCbor(data); - return URI.fromTaggedCbor(cborValue); - } - /** - * Static method to decode from untagged CBOR binary data. - */ - static fromUntaggedCborData(data) { - const cborValue = decodeCbor(data); - const text = expectText(cborValue); - return URI.new(text); - } - /** - * Returns the UR representation of the URI. - * Note: URs use untagged CBOR since the type is conveyed by the UR type itself. - */ - ur() { - return UR.new("url", this.untaggedCbor()); - } - /** - * Returns the UR string representation. - */ - urString() { - return this.ur().string(); - } - /** - * Creates a URI from a UR. - */ - static fromUR(ur) { - ur.checkType("url"); - return new URI("https://placeholder.invalid").fromUntaggedCbor(ur.cbor()); - } - /** - * Creates a URI from a UR string. - */ - static fromURString(urString) { - const ur = UR.fromURString(urString); - return URI.fromUR(ur); - } -}; -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -* -* Ed25519 public key for EdDSA signature verification (32 bytes) -* Ported from bc-components-rust/src/ed25519/ed25519_public_key.rs -*/ -var Ed25519PublicKey = class Ed25519PublicKey { - _data; - constructor(data) { - if (data.length !== 32) throw CryptoError.invalidSize(32, data.length); - this._data = new Uint8Array(data); - } - /** - * Create an Ed25519PublicKey from raw bytes (32 bytes). - */ - static from(data) { - return new Ed25519PublicKey(data); - } - /** - * Mirror of Rust `Ed25519PublicKey::from_data` — exact-length copy. - */ - static fromData(data) { - return new Ed25519PublicKey(data); - } - /** - * Mirror of Rust `Ed25519PublicKey::from_data_ref` — validates length. - */ - static fromDataRef(data) { - if (data.length !== 32) throw CryptoError.invalidSize(32, data.length); - return new Ed25519PublicKey(data); - } - /** - * Create an Ed25519PublicKey from hex string. - */ - static fromHex(hex) { - return new Ed25519PublicKey(hexToBytes(hex)); - } - /** Returns the 32 raw public key bytes (copy). */ - data() { - return new Uint8Array(this._data); - } - /** Alias of {@link data}. */ - asBytes() { - return this.data(); - } - /** Backwards-compatible alias of {@link data}. */ - toData() { - return this.data(); - } - /** - * Get hex string representation - */ - toHex() { - return bytesToHex$1(this._data); - } - /** - * Get base64 representation - */ - toBase64() { - return toBase64$1(this._data); - } - /** - * Verify a signature using Ed25519 - */ - verify(message, signature) { - try { - if (signature.length !== 64) throw CryptoError.invalidSize(64, signature.length); - return ed25519Verify(this._data, message, signature); - } catch (e) { - throw CryptoError.cryptoOperation(`Ed25519 verification failed: ${String(e)}`); - } - } - /** - * Compare with another Ed25519PublicKey - */ - equals(other) { - if (this._data.length !== other._data.length) return false; - for (let i = 0; i < this._data.length; i++) if (this._data[i] !== other._data[i]) return false; - return true; - } - /** - * Get string representation. - * - * Mirrors Rust `Display for Ed25519PublicKey` - * (`bc-components-rust/src/ed25519/ed25519_public_key.rs`): - * `Ed25519PublicKey()` - * where the reference is computed from the **raw 32-byte data** - * (not tagged CBOR) — same pattern as SchnorrPublicKey. - */ - toString() { - return `Ed25519PublicKey(${Digest.fromImage(this._data).shortDescription()})`; - } -}; -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -* -* Ed25519 private key for EdDSA signatures (32 bytes seed) -* Ported from bc-components-rust/src/ed25519_private_key.rs -*/ -var Ed25519PrivateKey = class Ed25519PrivateKey { - seed; - _publicKey; - constructor(seed) { - if (seed.length !== 32) throw CryptoError.invalidSize(32, seed.length); - this.seed = new Uint8Array(seed); - } - /** - * Create an Ed25519PrivateKey from seed (32 bytes) - */ - static from(seed) { - return new Ed25519PrivateKey(new Uint8Array(seed)); - } - /** - * Create an Ed25519PrivateKey from hex string (64 hex characters) - */ - static fromHex(hex) { - return new Ed25519PrivateKey(hexToBytes(hex)); - } - /** - * Generate a random Ed25519PrivateKey - */ - static random() { - const rng = new SecureRandomNumberGenerator(); - return new Ed25519PrivateKey(rng.randomData(32)); - } - /** - * Generate a random Ed25519PrivateKey using provided RNG - */ - static randomUsing(rng) { - return new Ed25519PrivateKey(rng.randomData(32)); - } - /** - * Derives an Ed25519 private key from the given key material via - * HKDF-SHA-256 with salt `"signing"` and empty info (matches Rust - * `bc_crypto::derive_signing_private_key`). - */ - static deriveFromKeyMaterial(keyMaterial) { - return new Ed25519PrivateKey(deriveSigningPrivateKey(keyMaterial)); - } - /** - * Get the raw seed bytes (32 bytes). - */ - data() { - return new Uint8Array(this.seed); - } - /** Alias of {@link data}. */ - asBytes() { - return this.data(); - } - /** Backwards-compatible alias of {@link data}. */ - toData() { - return this.data(); - } - /** - * Get hex string representation of the seed - */ - toHex() { - return bytesToHex$1(this.seed); - } - /** - * Get base64 representation of the seed - */ - toBase64() { - return toBase64$1(this.seed); - } - /** - * Derive the corresponding public key - */ - publicKey() { - if (this._publicKey === void 0) { - const publicKeyBytes = ed25519PublicKeyFromPrivateKey(this.seed); - this._publicKey = Ed25519PublicKey.from(publicKeyBytes); - } - return this._publicKey; - } - /** - * Sign a message using Ed25519 - */ - sign(message) { - try { - const signature = ed25519Sign(this.seed, message); - return new Uint8Array(signature); - } catch (e) { - throw CryptoError.cryptoOperation(`Ed25519 signing failed: ${String(e)}`); - } - } - /** - * Compare with another Ed25519PrivateKey - */ - equals(other) { - if (this.seed.length !== other.seed.length) return false; - for (let i = 0; i < this.seed.length; i++) if (this.seed[i] !== other.seed[i]) return false; - return true; - } - /** - * Get string representation - */ - toString() { - return `Ed25519PrivateKey(${this.toHex().substring(0, 16)}...)`; - } -}; -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -* -* Sr25519PublicKey - Public key for Schnorr signatures over Ristretto25519 -* -* SR25519 is the signature scheme used by Polkadot/Substrate. -* It is based on Schnorr signatures over the Ristretto group. -* -* Note: SR25519 uses the SigningPublicKey CBOR tag (40022) with discriminator 3. -* -* Ported from bc-components-rust/src/sr25519/sr25519_public_key.rs -*/ -/** -* Sr25519PublicKey - Public key for Schnorr signatures over Ristretto25519. -* -* This is the signature scheme used by Polkadot/Substrate. -*/ -var Sr25519PublicKey = class Sr25519PublicKey { - _data; - constructor(data) { - if (data.length !== 32) throw new Error(`Sr25519PublicKey must be 32 bytes, got ${data.length}`); - this._data = new Uint8Array(data); - } - /** - * Create an Sr25519 public key from raw bytes. - */ - static from(data) { - return new Sr25519PublicKey(data); - } - /** - * Create an Sr25519 public key from a hex string. - */ - static fromHex(hex) { - const matches = hex.match(/.{1,2}/g); - if (matches === null) throw new Error("Invalid hex string"); - const data = new Uint8Array(matches.map((byte) => parseInt(byte, 16))); - return Sr25519PublicKey.from(data); - } - /** - * Returns the raw key bytes. - */ - toData() { - return new Uint8Array(this._data); - } - /** - * Returns the raw key bytes (alias for toData). - */ - asBytes() { - return this._data; - } - /** - * Returns the hex representation of the key. - */ - toHex() { - return bytesToHex$1(this._data); - } - /** - * Verify a signature using the default "substrate" context. - * - * @param signature - The 64-byte signature - * @param message - The message that was signed - * @returns true if the signature is valid - */ - verify(signature, message) { - return this.verifyWithContext(signature, message, SR25519_DEFAULT_CONTEXT); - } - /** - * Verify a signature using a custom context. - * - * The underlying `@scure/sr25519` library hard-codes the `"substrate"` - * signing context. To avoid silently accepting/rejecting cross-platform - * signatures, this method throws when called with any other context — - * matching the symmetric guard in `Sr25519PrivateKey.signWithContext`. - * - * @param signature - The 64-byte signature - * @param message - The message that was signed - * @param context - The signing context (must equal `SR25519_DEFAULT_CONTEXT`) - * @returns true if the signature is valid - * @throws CryptoError if `context` is not the substrate default - */ - verifyWithContext(signature, message, context) { - if (!bytesEqual$1(context, SR25519_DEFAULT_CONTEXT)) throw CryptoError.cryptoOperation("Sr25519: only the default substrate context is supported by the underlying library"); - try { - return verify(message, signature, this._data); - } catch { - return false; - } - } - /** - * Compare with another Sr25519PublicKey. - */ - equals(other) { - if (this._data.length !== other._data.length) return false; - for (let i = 0; i < this._data.length; i++) if (this._data[i] !== other._data[i]) return false; - return true; - } - /** - * Get string representation. - */ - toString() { - return `Sr25519PublicKey(${bytesToHex$1(this._data).substring(0, 16)}...)`; - } -}; -/** Default signing context (Substrate/Polkadot compatible) */ -const SR25519_DEFAULT_CONTEXT = new TextEncoder().encode("substrate"); -/** -* Sr25519PrivateKey - Private key for Schnorr signatures over Ristretto25519. -* -* This is the signature scheme used by Polkadot/Substrate. -*/ -var Sr25519PrivateKey = class Sr25519PrivateKey { - _seed; - _cachedPublicKey; - constructor(seed) { - if (seed.length !== 32) throw new Error(`Sr25519PrivateKey seed must be 32 bytes, got ${seed.length}`); - this._seed = new Uint8Array(seed); - } - /** - * Create a new random Sr25519 private key. - */ - static random() { - const rng = new SecureRandomNumberGenerator(); - return Sr25519PrivateKey.randomUsing(rng); - } - /** - * Create a new random Sr25519 private key using the provided RNG. - */ - static randomUsing(rng) { - const seed = rng.randomData(32); - return new Sr25519PrivateKey(seed); - } - /** - * Create an Sr25519 private key from a 32-byte seed. - */ - static fromSeed(seed) { - return new Sr25519PrivateKey(seed); - } - /** - * Create an Sr25519 private key from raw data. - * Alias for fromSeed. - */ - static from(data) { - return Sr25519PrivateKey.fromSeed(data); - } - /** - * Create an Sr25519 private key from a hex string. - */ - static fromHex(hex) { - const matches = hex.match(/.{1,2}/g); - if (matches === null) throw new Error("Invalid hex string"); - const data = new Uint8Array(matches.map((byte) => parseInt(byte, 16))); - return Sr25519PrivateKey.fromSeed(data); - } - /** - * Derive an Sr25519 private key from arbitrary key material using BLAKE2b. - * - * @param keyMaterial - Arbitrary bytes to derive the key from - * @returns A new Sr25519 private key - */ - static deriveFromKeyMaterial(keyMaterial) { - const seed = blake2b(keyMaterial, { dkLen: 32 }); - return new Sr25519PrivateKey(seed); - } - /** - * Generate a keypair and return both private and public keys. - * - * @returns Tuple of [privateKey, publicKey] - */ - static keypair() { - const privateKey = Sr25519PrivateKey.random(); - return [privateKey, privateKey.publicKey()]; - } - /** - * Generate a keypair using the provided RNG. - * - * @param rng - Random number generator - * @returns Tuple of [privateKey, publicKey] - */ - static keypairUsing(rng) { - const privateKey = Sr25519PrivateKey.randomUsing(rng); - return [privateKey, privateKey.publicKey()]; - } - /** - * Returns the raw seed bytes. - */ - toData() { - return new Uint8Array(this._seed); - } - /** - * Returns the raw seed bytes (alias for toData). - */ - asBytes() { - return this._seed; - } - /** - * Returns the hex representation of the seed. - */ - toHex() { - return bytesToHex$1(this._seed); - } - /** - * Derives the corresponding public key. - */ - publicKey() { - if (this._cachedPublicKey === void 0) { - const pubKeyBytes = getPublicKey(secretFromSeed(this._seed)); - this._cachedPublicKey = Sr25519PublicKey.from(pubKeyBytes); - } - return this._cachedPublicKey; - } - /** - * Sign a message using the default "substrate" context. - * - * @param message - The message to sign - * @returns 64-byte signature - */ - sign(message) { - return this.signWithContext(message, SR25519_DEFAULT_CONTEXT); - } - /** - * Sign a message using a custom context. - * - * The underlying `@scure/sr25519` library hard-codes the `"substrate"` - * signing context. Calling with any other context byte-slice would - * silently produce a non-cross-platform signature, so we fail loudly - * instead — callers must use the substrate default until a - * context-aware library is wired in. - * - * @param message - The message to sign - * @param context - The signing context (must equal `SR25519_DEFAULT_CONTEXT`) - * @returns 64-byte signature - * @throws CryptoError if `context` is not the substrate default - */ - signWithContext(message, context) { - if (!bytesEqual$1(context, SR25519_DEFAULT_CONTEXT)) throw CryptoError.cryptoOperation("Sr25519: only the default substrate context is supported by the underlying library"); - return sign(secretFromSeed(this._seed), message); - } - /** - * Compare with another Sr25519PrivateKey. - */ - equals(other) { - if (this._seed.length !== other._seed.length) return false; - for (let i = 0; i < this._seed.length; i++) if (this._seed[i] !== other._seed[i]) return false; - return true; - } - /** - * Get string representation (truncated for security). - */ - toString() { - return `Sr25519PrivateKey(${bytesToHex$1(this._seed).substring(0, 8)}...)`; - } -}; -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -* -* EC uncompressed public key for ECDSA (secp256k1, 65 bytes) -* -* An `ECUncompressedPublicKey` is a 65-byte uncompressed representation of a -* public key on the secp256k1 curve. The first byte is 0x04 (uncompressed prefix), -* followed by the 32-byte x-coordinate and 32-byte y-coordinate. -* -* While compressed public keys (33 bytes) are preferred for space efficiency, -* uncompressed keys are sometimes needed for compatibility with legacy systems. -* -* # CBOR Serialization -* -* `ECUncompressedPublicKey` is serialized to CBOR with tags 40306 (or legacy 306). -* -* The format is a map: -* ``` -* #6.40306({ -* 3: h'<65-byte-uncompressed-public-key>' // key data -* }) -* ``` -* -* Ported from bc-components-rust/src/ec_key/ec_uncompressed_public_key.rs -*/ -var ECUncompressedPublicKey = class ECUncompressedPublicKey { - static KEY_SIZE = 65; - _data; - constructor(data) { - if (data.length !== 65) throw CryptoError.invalidSize(65, data.length); - this._data = new Uint8Array(data); - } - /** - * Restore an ECUncompressedPublicKey from a fixed-size array of bytes. - */ - static fromData(data) { - return new ECUncompressedPublicKey(new Uint8Array(data)); - } - /** - * Restore an ECUncompressedPublicKey from a reference to an array of bytes. - * Validates the length. - */ - static fromDataRef(data) { - if (data.length !== 65) throw CryptoError.invalidSize(65, data.length); - return ECUncompressedPublicKey.fromData(data); - } - /** - * Create an ECUncompressedPublicKey from raw bytes (legacy alias). - */ - static from(data) { - return ECUncompressedPublicKey.fromData(data); - } - /** - * Restore an ECUncompressedPublicKey from a hex string. - */ - static fromHex(hex) { - return ECUncompressedPublicKey.fromData(hexToBytes(hex)); - } - /** - * Get a reference to the fixed-size array of bytes. - */ - data() { - return this._data; - } - /** - * Get the raw public key bytes (copy). - */ - toData() { - return new Uint8Array(this._data); - } - /** - * Get hex string representation. - */ - hex() { - return bytesToHex$1(this._data); - } - /** - * Get hex string representation (alias for hex()). - */ - toHex() { - return this.hex(); - } - /** - * Get base64 representation. - */ - toBase64() { - return toBase64$1(this._data); - } - /** - * Convert to compressed public key format. - * Note: Returns the compressed bytes. To get ECPublicKey, use the ec-public-key module. - */ - compressedData() { - return ecdsaCompressPublicKey(this._data); - } - /** - * Compare with another ECUncompressedPublicKey. - */ - equals(other) { - if (this._data.length !== other._data.length) return false; - for (let i = 0; i < this._data.length; i++) if (this._data[i] !== other._data[i]) return false; - return true; - } - /** - * Get string representation. - */ - toString() { - return `ECUncompressedPublicKey(${this.toHex().substring(0, 16)}...)`; - } - /** - * Returns the CBOR tags associated with ECUncompressedPublicKey. - */ - cborTags() { - return tagsForValues([EC_KEY.value, EC_KEY_V1.value]); - } - /** - * Returns the untagged CBOR encoding. - * - * Format: { 3: h'<65-byte-key>' } - */ - untaggedCbor() { - const map = /* @__PURE__ */ new Map(); - map.set(3, toByteString(this._data)); - return cbor(map); - } - /** - * Returns the tagged CBOR encoding. - */ - taggedCbor() { - return createTaggedCbor(this); - } - /** - * Returns the tagged value in CBOR binary representation. - */ - taggedCborData() { - return this.taggedCbor().toData(); - } - /** - * Creates an ECUncompressedPublicKey by decoding it from untagged CBOR. - * - * Format: { 3: h'<65-byte-key>' } - */ - fromUntaggedCbor(cborValue) { - const map = expectMap(cborValue); - if (map.get(2) === true) throw new Error("Expected ECUncompressedPublicKey but found private key"); - const keyData = map.extract(3); - if (keyData === void 0 || keyData.length === 0) throw new Error("ECUncompressedPublicKey CBOR must have key 3 (data)"); - return ECUncompressedPublicKey.fromDataRef(keyData); - } - /** - * Creates an ECUncompressedPublicKey by decoding it from tagged CBOR. - */ - fromTaggedCbor(cborValue) { - validateTag(cborValue, this.cborTags()); - const content = extractTaggedContent(cborValue); - return this.fromUntaggedCbor(content); - } - /** - * Static method to decode from tagged CBOR. - */ - static fromTaggedCbor(cborValue) { - return new ECUncompressedPublicKey(/* @__PURE__ */ new Uint8Array(65)).fromTaggedCbor(cborValue); - } - /** - * Static method to decode from tagged CBOR binary data. - */ - static fromTaggedCborData(data) { - const cborValue = decodeCbor(data); - return ECUncompressedPublicKey.fromTaggedCbor(cborValue); - } - /** - * Static method to decode from untagged CBOR binary data. - */ - static fromUntaggedCborData(data) { - const cborValue = decodeCbor(data); - return new ECUncompressedPublicKey(/* @__PURE__ */ new Uint8Array(65)).fromUntaggedCbor(cborValue); - } - /** - * Returns the UR representation of the ECUncompressedPublicKey. - * Note: URs use untagged CBOR since the type is conveyed by the UR type itself. - */ - ur() { - const name = EC_KEY.name; - if (name === void 0) throw new Error("TAG_EC_KEY.name is undefined"); - return UR.new(name, this.untaggedCbor()); - } - /** - * Returns the UR string representation. - */ - urString() { - return this.ur().string(); - } - /** - * Creates an ECUncompressedPublicKey from a UR. - */ - static fromUR(ur) { - const name = EC_KEY.name; - if (name === void 0) throw new Error("TAG_EC_KEY.name is undefined"); - ur.checkType(name); - return new ECUncompressedPublicKey(/* @__PURE__ */ new Uint8Array(65)).fromUntaggedCbor(ur.cbor()); - } - /** - * Creates an ECUncompressedPublicKey from a UR string. - */ - static fromURString(urString) { - const ur = UR.fromURString(urString); - return ECUncompressedPublicKey.fromUR(ur); - } -}; -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -* -* EC compressed public key for ECDSA verification (secp256k1, 33 bytes) -* -* An `ECPublicKey` is a 33-byte compressed representation of a public key on -* the secp256k1 curve. The first byte is a prefix (0x02 or 0x03) that -* indicates the parity of the y-coordinate, followed by the 32-byte -* x-coordinate. -* -* These public keys are used to: -* - Verify ECDSA signatures -* - Identify the owner of a private key without revealing the private key -* -* # CBOR Serialization -* -* `ECPublicKey` is serialized to CBOR with tags 40306 (or legacy 306). -* -* The format is a map: -* ``` -* #6.40306({ -* 3: h'<33-byte-public-key>' // key data (no key 2 means public key) -* }) -* ``` -* -* Ported from bc-components-rust/src/ec_key/ec_public_key.rs -*/ -var ECPublicKey = class ECPublicKey { - static KEY_SIZE = 33; - _data; - constructor(data) { - if (data.length !== 33) throw CryptoError.invalidSize(33, data.length); - this._data = new Uint8Array(data); - } - /** - * Restore an ECPublicKey from a fixed-size array of bytes. - */ - static fromData(data) { - return new ECPublicKey(new Uint8Array(data)); - } - /** - * Restore an ECPublicKey from a reference to an array of bytes. - * Validates the length. - */ - static fromDataRef(data) { - if (data.length !== 33) throw CryptoError.invalidSize(33, data.length); - return ECPublicKey.fromData(data); - } - /** - * Create an ECPublicKey from raw bytes (legacy alias). - */ - static from(data) { - return ECPublicKey.fromData(data); - } - /** - * Restore an ECPublicKey from a hex string. - */ - static fromHex(hex) { - return ECPublicKey.fromData(hexToBytes(hex)); - } - /** - * Get a reference to the fixed-size array of bytes. - */ - data() { - return this._data; - } - /** - * Get the raw public key bytes (copy). - */ - toData() { - return new Uint8Array(this._data); - } - /** - * Get hex string representation. - */ - hex() { - return bytesToHex$1(this._data); - } - /** - * Get hex string representation (alias for hex()). - */ - toHex() { - return this.hex(); - } - /** - * Get base64 representation. - */ - toBase64() { - return toBase64$1(this._data); - } - /** - * Returns the compressed public key (self). - * - * This method implements the ECKey interface. Since ECPublicKey is already - * a compressed public key, this returns itself. - */ - publicKey() { - return this; - } - /** - * Convert this compressed public key to uncompressed format. - */ - uncompressedPublicKey() { - const uncompressed = ecdsaDecompressPublicKey(this._data); - return ECUncompressedPublicKey.fromData(uncompressed); - } - /** - * Verify an ECDSA signature. - * - * @param signature - The 64-byte signature to verify - * @param message - The message that was signed - * @returns true if the signature is valid - */ - verify(signature, message) { - try { - return ecdsaVerify(this._data, signature, message); - } catch { - return false; - } - } - /** - * Compare with another ECPublicKey. - */ - equals(other) { - if (this._data.length !== other._data.length) return false; - for (let i = 0; i < this._data.length; i++) if (this._data[i] !== other._data[i]) return false; - return true; - } - /** - * Get string representation. - */ - toString() { - return `ECPublicKey(${this.toHex().substring(0, 16)}...)`; - } - /** - * Returns the CBOR tags associated with ECPublicKey. - */ - cborTags() { - return tagsForValues([EC_KEY.value, EC_KEY_V1.value]); - } - /** - * Returns the untagged CBOR encoding. - * - * Format: { 3: h'<33-byte-key>' } - * Note: No key 2 indicates this is a public key - */ - untaggedCbor() { - const map = /* @__PURE__ */ new Map(); - map.set(3, toByteString(this._data)); - return cbor(map); - } - /** - * Returns the tagged CBOR encoding. - */ - taggedCbor() { - return createTaggedCbor(this); - } - /** - * Returns the tagged value in CBOR binary representation. - */ - taggedCborData() { - return this.taggedCbor().toData(); - } - /** - * Creates an ECPublicKey by decoding it from untagged CBOR. - * - * Format: { 3: h'<33-byte-key>' } - */ - fromUntaggedCbor(cborValue) { - const map = expectMap(cborValue); - if (map.get(2) === true) throw new Error("Expected ECPublicKey but found private key (key 2 is true)"); - const keyData = map.extract(3); - if (keyData === void 0 || keyData.length === 0) throw new Error("ECPublicKey CBOR must have key 3 (data)"); - return ECPublicKey.fromDataRef(keyData); - } - /** - * Creates an ECPublicKey by decoding it from tagged CBOR. - */ - fromTaggedCbor(cborValue) { - validateTag(cborValue, this.cborTags()); - const content = extractTaggedContent(cborValue); - return this.fromUntaggedCbor(content); - } - /** - * Static method to decode from tagged CBOR. - */ - static fromTaggedCbor(cborValue) { - return new ECPublicKey(/* @__PURE__ */ new Uint8Array(33)).fromTaggedCbor(cborValue); - } - /** - * Static method to decode from tagged CBOR binary data. - */ - static fromTaggedCborData(data) { - const cborValue = decodeCbor(data); - return ECPublicKey.fromTaggedCbor(cborValue); - } - /** - * Static method to decode from untagged CBOR binary data. - */ - static fromUntaggedCborData(data) { - const cborValue = decodeCbor(data); - return new ECPublicKey(/* @__PURE__ */ new Uint8Array(33)).fromUntaggedCbor(cborValue); - } - /** - * Returns the UR representation of the ECPublicKey. - * Note: URs use untagged CBOR since the type is conveyed by the UR type itself. - */ - ur() { - const name = EC_KEY.name; - if (name === void 0) throw new Error("TAG_EC_KEY.name is undefined"); - return UR.new(name, this.untaggedCbor()); - } - /** - * Returns the UR string representation. - */ - urString() { - return this.ur().string(); - } - /** - * Creates an ECPublicKey from a UR. - */ - static fromUR(ur) { - const name = EC_KEY.name; - if (name === void 0) throw new Error("TAG_EC_KEY.name is undefined"); - ur.checkType(name); - return new ECPublicKey(/* @__PURE__ */ new Uint8Array(33)).fromUntaggedCbor(ur.cbor()); - } - /** - * Creates an ECPublicKey from a UR string. - */ - static fromURString(urString) { - const ur = UR.fromURString(urString); - return ECPublicKey.fromUR(ur); - } -}; -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -* -* Schnorr (x-only) public key for BIP-340 signatures (secp256k1, 32 bytes) -* -* A `SchnorrPublicKey` is a 32-byte "x-only" public key used with the BIP-340 -* Schnorr signature scheme. Unlike compressed ECDSA public keys (33 bytes) -* that include a prefix byte indicating the parity of the y-coordinate, -* Schnorr public keys only contain the x-coordinate of the elliptic curve -* point. -* -* Schnorr signatures offer several advantages over traditional ECDSA -* signatures: -* - Linearity: Enables key and signature aggregation -* - Non-malleability: Prevents third parties from modifying signatures -* - Smaller size: Signatures are 64 bytes vs 70-72 bytes for ECDSA -* - Better privacy: Makes different multisig policies indistinguishable -* -* Schnorr signatures were introduced to Bitcoin via the Taproot upgrade -* (BIP-340). -* -* Note: SchnorrPublicKey does not have CBOR serialization in the Rust -* implementation, so we keep it simple here. -* -* Ported from bc-components-rust/src/ec_key/schnorr_public_key.rs -*/ -var SchnorrPublicKey = class SchnorrPublicKey { - static KEY_SIZE = 32; - _data; - constructor(data) { - if (data.length !== 32) throw CryptoError.invalidSize(32, data.length); - this._data = new Uint8Array(data); - } - /** - * Restore a SchnorrPublicKey from a fixed-size array of bytes. - */ - static fromData(data) { - return new SchnorrPublicKey(new Uint8Array(data)); - } - /** - * Restore a SchnorrPublicKey from a reference to an array of bytes. - * Validates the length. - */ - static fromDataRef(data) { - if (data.length !== 32) throw CryptoError.invalidSize(32, data.length); - return SchnorrPublicKey.fromData(data); - } - /** - * Create a SchnorrPublicKey from raw bytes (legacy alias). - */ - static from(data) { - return SchnorrPublicKey.fromData(data); - } - /** - * Restore a SchnorrPublicKey from a hex string. - */ - static fromHex(hex) { - return SchnorrPublicKey.fromData(hexToBytes(hex)); - } - /** - * Get a reference to the fixed-size array of bytes. - */ - data() { - return this._data; - } - /** - * Get the raw public key bytes (copy). - */ - toData() { - return new Uint8Array(this._data); - } - /** - * Get hex string representation. - */ - hex() { - return bytesToHex$1(this._data); - } - /** - * Get hex string representation (alias for hex()). - */ - toHex() { - return this.hex(); - } - /** - * Get base64 representation. - */ - toBase64() { - return toBase64$1(this._data); - } - /** - * Verify a Schnorr signature (BIP-340). - * - * @param signature - The 64-byte signature to verify - * @param message - The message that was signed - * @returns true if the signature is valid - */ - schnorrVerify(signature, message) { - try { - return schnorrVerify(this._data, signature, message); - } catch { - return false; - } - } - /** - * Compare with another SchnorrPublicKey. - */ - equals(other) { - if (this._data.length !== other._data.length) return false; - for (let i = 0; i < this._data.length; i++) if (this._data[i] !== other._data[i]) return false; - return true; - } - /** - * Get string representation. - * - * Mirrors Rust `Display for SchnorrPublicKey` - * (`bc-components-rust/src/ec_key/schnorr_public_key.rs:116-120`) - * — the reference is computed from the **raw 32-byte key data** - * (not the tagged-CBOR form): `Reference::from_digest(Digest::from_image(self.data()))`. - * `ref_hex_short()` returns the first 8 hex chars of that - * reference's binary form (= SHA-256(data)[0..4]). - */ - toString() { - return `SchnorrPublicKey(${Digest.fromImage(this._data).shortDescription()})`; - } -}; -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -* -* EC private key for ECDSA and Schnorr signatures (secp256k1, 32 bytes) -* -* An `ECPrivateKey` is a 32-byte secret value that can be used to: -* - Generate its corresponding public key -* - Sign messages using the ECDSA signature scheme -* - Sign messages using the Schnorr signature scheme (BIP-340) -* -* These keys use the secp256k1 curve, which is the same curve used in Bitcoin -* and other cryptocurrencies. -* -* # CBOR Serialization -* -* `ECPrivateKey` is serialized to CBOR with tags 40306 (or legacy 306). -* -* The format is a map: -* ``` -* #6.40306({ -* 2: true, // indicates private key -* 3: h'<32-byte-private-key>' // key data -* }) -* ``` -* -* Ported from bc-components-rust/src/ec_key/ec_private_key.rs -*/ -var ECPrivateKey = class ECPrivateKey { - static KEY_SIZE = 32; - _data; - _publicKey; - _schnorrPublicKey; - constructor(data) { - if (data.length !== 32) throw CryptoError.invalidSize(32, data.length); - this._data = new Uint8Array(data); - } - /** - * Generate a new random ECPrivateKey. - */ - static new() { - return ECPrivateKey.random(); - } - /** - * Generate a new random ECPrivateKey. - */ - static random() { - const rng = new SecureRandomNumberGenerator(); - return ECPrivateKey.newUsing(rng); - } - /** - * Generate a new random ECPrivateKey using provided RNG. - */ - static newUsing(rng) { - return new ECPrivateKey(rng.randomData(32)); - } - /** - * Generate a new random ECPrivateKey and corresponding ECPublicKey. - */ - static keypair() { - const privateKey = ECPrivateKey.new(); - return [privateKey, privateKey.publicKey()]; - } - /** - * Generate a new random ECPrivateKey and corresponding ECPublicKey - * using the given random number generator. - */ - static keypairUsing(rng) { - const privateKey = ECPrivateKey.newUsing(rng); - return [privateKey, privateKey.publicKey()]; - } - /** - * Derive an ECPrivateKey from the given key material. - * - * @param keyMaterial - The key material to derive from - * @returns A new ECPrivateKey derived from the key material - */ - static deriveFromKeyMaterial(keyMaterial) { - return new ECPrivateKey(ecdsaDerivePrivateKey(keyMaterial)); - } - /** - * Restore an ECPrivateKey from a fixed-size array of bytes. - */ - static fromData(data) { - return new ECPrivateKey(new Uint8Array(data)); - } - /** - * Restore an ECPrivateKey from a reference to an array of bytes. - * Validates the length. - */ - static fromDataRef(data) { - if (data.length !== 32) throw CryptoError.invalidSize(32, data.length); - return ECPrivateKey.fromData(data); - } - /** - * Create an ECPrivateKey from raw bytes (legacy alias). - */ - static from(data) { - return ECPrivateKey.fromData(data); - } - /** - * Restore an ECPrivateKey from a hex string. - */ - static fromHex(hex) { - return ECPrivateKey.fromData(hexToBytes(hex)); - } - /** - * Get a reference to the fixed-size array of bytes. - */ - data() { - return this._data; - } - /** - * Get the raw private key bytes (copy). - */ - toData() { - return new Uint8Array(this._data); - } - /** - * Get hex string representation. - */ - hex() { - return bytesToHex$1(this._data); - } - /** - * Get hex string representation (alias for hex()). - */ - toHex() { - return this.hex(); - } - /** - * Get base64 representation. - */ - toBase64() { - return toBase64$1(this._data); - } - /** - * Get the ECPublicKey (compressed) corresponding to this ECPrivateKey. - */ - publicKey() { - if (this._publicKey === void 0) { - const publicKeyBytes = ecdsaPublicKeyFromPrivateKey(this._data); - this._publicKey = ECPublicKey.fromData(publicKeyBytes); - } - return this._publicKey; - } - /** - * Get the SchnorrPublicKey (x-only) corresponding to this ECPrivateKey. - */ - schnorrPublicKey() { - if (this._schnorrPublicKey === void 0) { - const publicKeyBytes = schnorrPublicKeyFromPrivateKey(this._data); - this._schnorrPublicKey = SchnorrPublicKey.fromData(publicKeyBytes); - } - return this._schnorrPublicKey; - } - /** - * Sign a message using ECDSA. - * - * @param message - The message to sign - * @returns A 64-byte signature - */ - ecdsaSign(message) { - try { - return ecdsaSign(this._data, message); - } catch (e) { - throw CryptoError.cryptoOperation(`ECDSA signing failed: ${String(e)}`); - } - } - /** - * Sign a message using Schnorr signature (BIP-340). - * - * @param message - The message to sign - * @returns A 64-byte signature - */ - schnorrSign(message) { - try { - return schnorrSign(this._data, message); - } catch (e) { - throw CryptoError.cryptoOperation(`Schnorr signing failed: ${String(e)}`); - } - } - /** - * Sign a message using Schnorr signature with custom RNG. - * - * @param message - The message to sign - * @param rng - Random number generator for auxiliary randomness - * @returns A 64-byte signature - */ - schnorrSignUsing(message, rng) { - try { - return schnorrSignUsing(this._data, message, rng); - } catch (e) { - throw CryptoError.cryptoOperation(`Schnorr signing failed: ${String(e)}`); - } - } - /** - * Compare with another ECPrivateKey. - */ - equals(other) { - if (this._data.length !== other._data.length) return false; - for (let i = 0; i < this._data.length; i++) if (this._data[i] !== other._data[i]) return false; - return true; - } - /** - * Get string representation. - */ - toString() { - return `ECPrivateKey(${this.toHex().substring(0, 16)}...)`; - } - /** - * Returns the CBOR tags associated with ECPrivateKey. - */ - cborTags() { - return tagsForValues([EC_KEY.value, EC_KEY_V1.value]); - } - /** - * Returns the untagged CBOR encoding. - * - * Format: { 2: true, 3: h'<32-byte-key>' } - */ - untaggedCbor() { - const map = /* @__PURE__ */ new Map(); - map.set(2, true); - map.set(3, toByteString(this._data)); - return cbor(map); - } - /** - * Returns the tagged CBOR encoding. - */ - taggedCbor() { - return createTaggedCbor(this); - } - /** - * Returns the tagged value in CBOR binary representation. - */ - taggedCborData() { - return this.taggedCbor().toData(); - } - /** - * Creates an ECPrivateKey by decoding it from untagged CBOR. - * - * Format: { 2: true, 3: h'<32-byte-key>' } - */ - fromUntaggedCbor(cborValue) { - const map = expectMap(cborValue); - if (map.get(2) !== true) throw new Error("ECPrivateKey CBOR must have key 2 set to true"); - const keyData = map.extract(3); - if (keyData === void 0 || keyData.length === 0) throw new Error("ECPrivateKey CBOR must have key 3 (data)"); - return ECPrivateKey.fromDataRef(keyData); - } - /** - * Creates an ECPrivateKey by decoding it from tagged CBOR. - */ - fromTaggedCbor(cborValue) { - validateTag(cborValue, this.cborTags()); - const content = extractTaggedContent(cborValue); - return this.fromUntaggedCbor(content); - } - /** - * Static method to decode from tagged CBOR. - */ - static fromTaggedCbor(cborValue) { - return new ECPrivateKey(/* @__PURE__ */ new Uint8Array(32)).fromTaggedCbor(cborValue); - } - /** - * Static method to decode from tagged CBOR binary data. - */ - static fromTaggedCborData(data) { - const cborValue = decodeCbor(data); - return ECPrivateKey.fromTaggedCbor(cborValue); - } - /** - * Static method to decode from untagged CBOR binary data. - */ - static fromUntaggedCborData(data) { - const cborValue = decodeCbor(data); - return new ECPrivateKey(/* @__PURE__ */ new Uint8Array(32)).fromUntaggedCbor(cborValue); - } - /** - * Returns the UR representation of the ECPrivateKey. - * Note: URs use untagged CBOR since the type is conveyed by the UR type itself. - */ - ur() { - const name = EC_KEY.name; - if (name === void 0) throw new Error("TAG_EC_KEY.name is undefined"); - return UR.new(name, this.untaggedCbor()); - } - /** - * Returns the UR string representation. - */ - urString() { - return this.ur().string(); - } - /** - * Creates an ECPrivateKey from a UR. - */ - static fromUR(ur) { - const name = EC_KEY.name; - if (name === void 0) throw new Error("TAG_EC_KEY.name is undefined"); - ur.checkType(name); - return new ECPrivateKey(/* @__PURE__ */ new Uint8Array(32)).fromUntaggedCbor(ur.cbor()); - } - /** - * Creates an ECPrivateKey from a UR string. - */ - static fromURString(urString) { - const ur = UR.fromURString(urString); - return ECPrivateKey.fromUR(ur); - } -}; -/** -* Key sizes for each ML-DSA security level. -*/ -const MLDSA_KEY_SIZES = { - [2]: { - privateKey: 2560, - publicKey: 1312, - signature: 2420 - }, - [3]: { - privateKey: 4032, - publicKey: 1952, - signature: 3309 - }, - [5]: { - privateKey: 4896, - publicKey: 2592, - signature: 4627 - } -}; -/** -* Get the private key size for a given ML-DSA level. -*/ -function mldsaPrivateKeySize(level) { - return MLDSA_KEY_SIZES[level].privateKey; -} -/** -* Get the public key size for a given ML-DSA level. -*/ -function mldsaPublicKeySize(level) { - return MLDSA_KEY_SIZES[level].publicKey; -} -/** -* Get the signature size for a given ML-DSA level. -*/ -function mldsaSignatureSize(level) { - return MLDSA_KEY_SIZES[level].signature; -} -/** -* Convert an ML-DSA level to its string representation. -*/ -function mldsaLevelToString(level) { - switch (level) { - case 2: return "MLDSA44"; - case 3: return "MLDSA65"; - case 5: return "MLDSA87"; - } -} -/** -* Parse an ML-DSA level from its numeric value. -*/ -function mldsaLevelFromValue(value) { - switch (value) { - case 2: return 2; - case 3: return 3; - case 5: return 5; - default: throw new Error(`Invalid MLDSA level value: ${value}`); - } -} -/** -* Generate an ML-DSA keypair using a provided RNG. -* -* @param level - The ML-DSA security level -* @param rng - Random number generator -* @returns Object containing publicKey and secretKey bytes -*/ -function mldsaGenerateKeypairUsing(level, rng) { - const seed = rng.randomData(32); - switch (level) { - case 2: { - const keypair = ml_dsa44.keygen(seed); - return { - publicKey: keypair.publicKey, - secretKey: keypair.secretKey - }; - } - case 3: { - const keypair = ml_dsa65.keygen(seed); - return { - publicKey: keypair.publicKey, - secretKey: keypair.secretKey - }; - } - case 5: { - const keypair = ml_dsa87.keygen(seed); - return { - publicKey: keypair.publicKey, - secretKey: keypair.secretKey - }; - } - } -} -/** -* Sign a message using ML-DSA. -* -* @param level - The ML-DSA security level -* @param secretKey - The secret key bytes -* @param message - The message to sign -* @returns The signature bytes -*/ -function mldsaSign(level, secretKey, message) { - switch (level) { - case 2: return ml_dsa44.sign(message, secretKey); - case 3: return ml_dsa65.sign(message, secretKey); - case 5: return ml_dsa87.sign(message, secretKey); - } -} -/** -* Verify a signature using ML-DSA. -* -* @param level - The ML-DSA security level -* @param publicKey - The public key bytes -* @param message - The message that was signed -* @param signature - The signature to verify -* @returns True if the signature is valid -*/ -function mldsaVerify(level, publicKey, message, signature) { - try { - switch (level) { - case 2: return ml_dsa44.verify(signature, message, publicKey); - case 3: return ml_dsa65.verify(signature, message, publicKey); - case 5: return ml_dsa87.verify(signature, message, publicKey); - } - } catch { - return false; - } -} -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -* -* MLDSAPublicKey - ML-DSA Public Key for post-quantum signature verification -* -* MLDSAPublicKey wraps an ML-DSA public key for verifying signatures. -* It supports all three security levels (MLDSA44, MLDSA65, MLDSA87). -* -* # CBOR Serialization -* -* MLDSAPublicKey is serialized with tag 40104: -* ``` -* #6.40104([level, h'']) -* ``` -* -* # UR Serialization -* -* UR type: `mldsa-public-key` -* -* Ported from bc-components-rust/src/mldsa/mldsa_public_key.rs -*/ -/** -* MLDSAPublicKey - Post-quantum signature verification key using ML-DSA. -*/ -var MLDSAPublicKey = class MLDSAPublicKey { - _level; - _data; - constructor(level, data) { - const expectedSize = mldsaPublicKeySize(level); - if (data.length !== expectedSize) throw new Error(`MLDSAPublicKey (${mldsaLevelToString(level)}) must be ${expectedSize} bytes, got ${data.length}`); - this._level = level; - this._data = new Uint8Array(data); - } - /** - * Create an MLDSAPublicKey from raw bytes. - * - * @param level - The ML-DSA security level - * @param data - The public key bytes - */ - static fromBytes(level, data) { - return new MLDSAPublicKey(level, data); - } - /** - * Returns the security level of this key. - */ - level() { - return this._level; - } - /** - * Returns the raw key bytes. - */ - asBytes() { - return this._data; - } - /** - * Returns a copy of the raw key bytes. - */ - data() { - return new Uint8Array(this._data); - } - /** - * Returns the size of the key in bytes. - */ - size() { - return this._data.length; - } - /** - * Verify a signature against a message. - * - * @param signature - The ML-DSA signature to verify - * @param message - The message that was signed - * @returns True if the signature is valid - */ - verify(signature, message) { - if (signature.level() !== this._level) return false; - return mldsaVerify(this._level, this._data, message, signature.asBytes()); - } - /** - * Compare with another MLDSAPublicKey. - */ - equals(other) { - if (this._level !== other._level) return false; - if (this._data.length !== other._data.length) return false; - for (let i = 0; i < this._data.length; i++) if (this._data[i] !== other._data[i]) return false; - return true; - } - /** - * Get string representation. - */ - toString() { - const hex = bytesToHex$1(this._data); - return `MLDSAPublicKey(${mldsaLevelToString(this._level)}, ${hex.substring(0, 16)}...)`; - } - /** - * Returns the CBOR tags associated with MLDSAPublicKey. - */ - cborTags() { - return tagsForValues([MLDSA_PUBLIC_KEY.value]); - } - /** - * Returns the untagged CBOR encoding. - * - * Format: [level, key_bytes] - */ - untaggedCbor() { - return cbor([this._level, this._data]); - } - /** - * Returns the tagged CBOR encoding. - */ - taggedCbor() { - return createTaggedCbor(this); - } - /** - * Returns the tagged value in CBOR binary representation. - */ - taggedCborData() { - return this.taggedCbor().toData(); - } - /** - * Creates an MLDSAPublicKey by decoding it from untagged CBOR. - */ - fromUntaggedCbor(cborValue) { - const elements = expectArray(cborValue); - if (elements.length !== 2) throw new Error(`MLDSAPublicKey CBOR must have 2 elements, got ${elements.length}`); - const level = mldsaLevelFromValue(Number(expectInteger(elements[0]))); - const data = expectBytes(elements[1]); - return MLDSAPublicKey.fromBytes(level, data); - } - /** - * Creates an MLDSAPublicKey by decoding it from tagged CBOR. - */ - fromTaggedCbor(cborValue) { - validateTag(cborValue, this.cborTags()); - const content = extractTaggedContent(cborValue); - return this.fromUntaggedCbor(content); - } - /** - * Static method to decode from tagged CBOR. - */ - static fromTaggedCbor(cborValue) { - const dummyData = new Uint8Array(mldsaPublicKeySize(2)); - return new MLDSAPublicKey(2, dummyData).fromTaggedCbor(cborValue); - } - /** - * Static method to decode from tagged CBOR binary data. - */ - static fromTaggedCborData(data) { - const cborValue = decodeCbor(data); - return MLDSAPublicKey.fromTaggedCbor(cborValue); - } - /** - * Static method to decode from untagged CBOR binary data. - */ - static fromUntaggedCborData(data) { - const cborValue = decodeCbor(data); - const dummyData = new Uint8Array(mldsaPublicKeySize(2)); - return new MLDSAPublicKey(2, dummyData).fromUntaggedCbor(cborValue); - } - /** - * Returns the UR representation. - */ - ur() { - const name = MLDSA_PUBLIC_KEY.name; - if (name === void 0) throw new Error("MLDSA_PUBLIC_KEY tag name is undefined"); - return UR.new(name, this.untaggedCbor()); - } - /** - * Returns the UR string representation. - */ - urString() { - return this.ur().string(); - } - /** - * Creates an MLDSAPublicKey from a UR. - */ - static fromUR(ur) { - if (ur.urTypeStr() !== MLDSA_PUBLIC_KEY.name) throw new Error(`Expected UR type ${MLDSA_PUBLIC_KEY.name}, got ${ur.urTypeStr()}`); - const dummyData = new Uint8Array(mldsaPublicKeySize(2)); - return new MLDSAPublicKey(2, dummyData).fromUntaggedCbor(ur.cbor()); - } - /** - * Creates an MLDSAPublicKey from a UR string. - */ - static fromURString(urString) { - const ur = UR.fromURString(urString); - return MLDSAPublicKey.fromUR(ur); - } -}; -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -* -* MLDSASignature - ML-DSA Digital Signature -* -* MLDSASignature wraps an ML-DSA signature for serialization and verification. -* It supports all three security levels (MLDSA44, MLDSA65, MLDSA87). -* -* # CBOR Serialization -* -* MLDSASignature is serialized with tag 40105: -* ``` -* #6.40105([level, h'']) -* ``` -* -* # UR Serialization -* -* UR type: `mldsa-signature` -* -* Ported from bc-components-rust/src/mldsa/mldsa_signature.rs -*/ -/** -* MLDSASignature - Post-quantum digital signature using ML-DSA. -*/ -var MLDSASignature = class MLDSASignature { - _level; - _data; - constructor(level, data) { - const expectedSize = mldsaSignatureSize(level); - if (data.length !== expectedSize) throw new Error(`MLDSASignature (${mldsaLevelToString(level)}) must be ${expectedSize} bytes, got ${data.length}`); - this._level = level; - this._data = new Uint8Array(data); - } - /** - * Create an MLDSASignature from raw bytes. - * - * @param level - The ML-DSA security level - * @param data - The signature bytes - */ - static fromBytes(level, data) { - return new MLDSASignature(level, data); - } - /** - * Returns the security level of this signature. - */ - level() { - return this._level; - } - /** - * Returns the raw signature bytes. - */ - asBytes() { - return this._data; - } - /** - * Returns a copy of the raw signature bytes. - */ - data() { - return new Uint8Array(this._data); - } - /** - * Returns the size of the signature in bytes. - */ - size() { - return this._data.length; - } - /** - * Compare with another MLDSASignature. - */ - equals(other) { - if (this._level !== other._level) return false; - if (this._data.length !== other._data.length) return false; - for (let i = 0; i < this._data.length; i++) if (this._data[i] !== other._data[i]) return false; - return true; - } - /** - * Get string representation. - */ - toString() { - const hex = bytesToHex$1(this._data); - return `MLDSASignature(${mldsaLevelToString(this._level)}, ${hex.substring(0, 16)}...)`; - } - /** - * Returns the CBOR tags associated with MLDSASignature. - */ - cborTags() { - return tagsForValues([MLDSA_SIGNATURE.value]); - } - /** - * Returns the untagged CBOR encoding. - * - * Format: [level, signature_bytes] - */ - untaggedCbor() { - return cbor([this._level, this._data]); - } - /** - * Returns the tagged CBOR encoding. - */ - taggedCbor() { - return createTaggedCbor(this); - } - /** - * Returns the tagged value in CBOR binary representation. - */ - taggedCborData() { - return this.taggedCbor().toData(); - } - /** - * Creates an MLDSASignature by decoding it from untagged CBOR. - */ - fromUntaggedCbor(cborValue) { - const elements = expectArray(cborValue); - if (elements.length !== 2) throw new Error(`MLDSASignature CBOR must have 2 elements, got ${elements.length}`); - const level = mldsaLevelFromValue(Number(expectInteger(elements[0]))); - const data = expectBytes(elements[1]); - return MLDSASignature.fromBytes(level, data); - } - /** - * Creates an MLDSASignature by decoding it from tagged CBOR. - */ - fromTaggedCbor(cborValue) { - validateTag(cborValue, this.cborTags()); - const content = extractTaggedContent(cborValue); - return this.fromUntaggedCbor(content); - } - /** - * Static method to decode from tagged CBOR. - */ - static fromTaggedCbor(cborValue) { - const dummyData = new Uint8Array(mldsaSignatureSize(2)); - return new MLDSASignature(2, dummyData).fromTaggedCbor(cborValue); - } - /** - * Static method to decode from tagged CBOR binary data. - */ - static fromTaggedCborData(data) { - const cborValue = decodeCbor(data); - return MLDSASignature.fromTaggedCbor(cborValue); - } - /** - * Static method to decode from untagged CBOR binary data. - */ - static fromUntaggedCborData(data) { - const cborValue = decodeCbor(data); - const dummyData = new Uint8Array(mldsaSignatureSize(2)); - return new MLDSASignature(2, dummyData).fromUntaggedCbor(cborValue); - } - /** - * Returns the UR representation. - */ - ur() { - const name = MLDSA_SIGNATURE.name; - if (name === void 0) throw new Error("MLDSA_SIGNATURE tag name is undefined"); - return UR.new(name, this.untaggedCbor()); - } - /** - * Returns the UR string representation. - */ - urString() { - return this.ur().string(); - } - /** - * Creates an MLDSASignature from a UR. - */ - static fromUR(ur) { - if (ur.urTypeStr() !== MLDSA_SIGNATURE.name) throw new Error(`Expected UR type ${MLDSA_SIGNATURE.name}, got ${ur.urTypeStr()}`); - const dummyData = new Uint8Array(mldsaSignatureSize(2)); - return new MLDSASignature(2, dummyData).fromUntaggedCbor(ur.cbor()); - } - /** - * Creates an MLDSASignature from a UR string. - */ - static fromURString(urString) { - const ur = UR.fromURString(urString); - return MLDSASignature.fromUR(ur); - } -}; -/** -* Copyright © 2023-2026 Blockchain Commons, LLC -* Copyright © 2025-2026 Parity Technologies -* -* -* MLDSAPrivateKey - ML-DSA Private Key for post-quantum digital signatures -* -* MLDSAPrivateKey wraps an ML-DSA secret key for signing messages. -* It supports all three security levels (MLDSA44, MLDSA65, MLDSA87). -* -* # CBOR Serialization -* -* MLDSAPrivateKey is serialized with tag 40103: -* ``` -* #6.40103([level, h'']) -* ``` -* -* # UR Serialization -* -* UR type: `mldsa-private-key` -* -* Ported from bc-components-rust/src/mldsa/mldsa_private_key.rs -*/ -/** -* MLDSAPrivateKey - Post-quantum signing private key using ML-DSA. -*/ -var MLDSAPrivateKey = class MLDSAPrivateKey { - _level; - _data; - constructor(level, data) { - const expectedSize = mldsaPrivateKeySize(level); - if (data.length !== expectedSize) throw new Error(`MLDSAPrivateKey (${mldsaLevelToString(level)}) must be ${expectedSize} bytes, got ${data.length}`); - this._level = level; - this._data = new Uint8Array(data); - } - /** - * Generate a new random MLDSAPrivateKey with the specified security level. - * - * @param level - The ML-DSA security level (default: MLDSA65) - */ - static new(level = 3) { - const rng = new SecureRandomNumberGenerator(); - return MLDSAPrivateKey.newUsing(level, rng); - } - /** - * Generate a new random MLDSAPrivateKey using the provided RNG. - * - * @param level - The ML-DSA security level - * @param rng - Random number generator - */ - static newUsing(level, rng) { - const keypair = mldsaGenerateKeypairUsing(level, rng); - return new MLDSAPrivateKey(level, keypair.secretKey); - } - /** - * Create an MLDSAPrivateKey from raw bytes. - * - * @param level - The ML-DSA security level - * @param data - The private key bytes - */ - static fromBytes(level, data) { - return new MLDSAPrivateKey(level, data); - } - /** - * Generate a keypair and return both private and public keys. - * - * @param level - The ML-DSA security level (default: MLDSA65) - * @returns Tuple of [privateKey, publicKey] - */ - static keypair(level = 3) { - const rng = new SecureRandomNumberGenerator(); - return MLDSAPrivateKey.keypairUsing(level, rng); - } - /** - * Generate a keypair using the provided RNG. - * - * @param level - The ML-DSA security level - * @param rng - Random number generator - * @returns Tuple of [privateKey, publicKey] - */ - static keypairUsing(level, rng) { - const keypairData = mldsaGenerateKeypairUsing(level, rng); - return [new MLDSAPrivateKey(level, keypairData.secretKey), MLDSAPublicKey.fromBytes(level, keypairData.publicKey)]; - } - /** - * Returns the security level of this key. - */ - level() { - return this._level; - } - /** - * Returns the raw key bytes. - */ - asBytes() { - return this._data; - } - /** - * Returns a copy of the raw key bytes. - */ - data() { - return new Uint8Array(this._data); - } - /** - * Returns the size of the key in bytes. - */ - size() { - return this._data.length; - } - /** - * Sign a message with this private key. - * - * @param message - The message to sign - * @returns The ML-DSA signature - */ - sign(message) { - const sigBytes = mldsaSign(this._level, this._data, message); - return MLDSASignature.fromBytes(this._level, sigBytes); - } - /** - * Derive the public key from this private key. - * - * Note: ML-DSA doesn't have a direct derivation method, so we need to - * regenerate the keypair from seed. For now, we extract from the secret key - * structure (the public key is embedded in the secret key for ML-DSA). - */ - publicKey() { - throw new Error("MLDSAPrivateKey.publicKey() is not supported. Use MLDSAPrivateKey.keypair() to generate both keys together."); - } - /** - * Compare with another MLDSAPrivateKey. - */ - equals(other) { - if (this._level !== other._level) return false; - if (this._data.length !== other._data.length) return false; - for (let i = 0; i < this._data.length; i++) if (this._data[i] !== other._data[i]) return false; - return true; - } - /** - * Get string representation (truncated for security). - */ - toString() { - const hex = bytesToHex$1(this._data); - return `MLDSAPrivateKey(${mldsaLevelToString(this._level)}, ${hex.substring(0, 8)}...)`; - } - /** - * Returns the CBOR tags associated with MLDSAPrivateKey. - */ - cborTags() { - return tagsForValues([MLDSA_PRIVATE_KEY.value]); - } - /** - * Returns the untagged CBOR encoding. - * - * Format: [level, key_bytes] - */ - untaggedCbor() { - return cbor([this._level, this._data]); - } - /** - * Returns the tagged CBOR encoding. - */ - taggedCbor() { - return createTaggedCbor(this); - } - /** - * Returns the tagged value in CBOR binary representation. - */ - taggedCborData() { - return this.taggedCbor().toData(); - } - /** - * Creates an MLDSAPrivateKey by decoding it from untagged CBOR. - */ - fromUntaggedCbor(cborValue) { - const elements = expectArray(cborValue); - if (elements.length !== 2) throw new Error(`MLDSAPrivateKey CBOR must have 2 elements, got ${elements.length}`); - const level = mldsaLevelFromValue(Number(expectInteger(elements[0]))); - const data = expectBytes(elements[1]); - return MLDSAPrivateKey.fromBytes(level, data); - } - /** - * Creates an MLDSAPrivateKey by decoding it from tagged CBOR. - */ - fromTaggedCbor(cborValue) { - validateTag(cborValue, this.cborTags()); - const content = extractTaggedContent(cborValue); - return this.fromUntaggedCbor(content); - } - /** - * Static method to decode from tagged CBOR. - */ - static fromTaggedCbor(cborValue) { - const dummyData = new Uint8Array(mldsaPrivateKeySize(2)); - return new MLDSAPrivateKey(2, dummyData).fromTaggedCbor(cborValue); - } - /** - * Static method to decode from tagged CBOR binary data. - */ - static fromTaggedCborData(data) { - const cborValue = decodeCbor(data); - return MLDSAPrivateKey.fromTaggedCbor(cborValue); - } - /** - * Static method to decode from untagged CBOR binary data. - */ - static fromUntaggedCborData(data) { - const cborValue = decodeCbor(data); - const dummyData = new Uint8Array(mldsaPrivateKeySize(2)); - return new MLDSAPrivateKey(2, dummyData).fromUntaggedCbor(cborValue); - } - /** - * Returns the UR representation. - */ - ur() { - const name = MLDSA_PRIVATE_KEY.name; - if (name === void 0) throw new Error("MLDSA_PRIVATE_KEY tag name is undefined"); - return UR.new(name, this.untaggedCbor()); - } - /** - * Returns the UR string representation. - */ - urString() { - return this.ur().string(); - } - /** - * Creates an MLDSAPrivateKey from a UR. - */ - static fromUR(ur) { - if (ur.urTypeStr() !== MLDSA_PRIVATE_KEY.name) throw new Error(`Expected UR type ${MLDSA_PRIVATE_KEY.name}, got ${ur.urTypeStr()}`); - const dummyData = new Uint8Array(mldsaPrivateKeySize(2)); - return new MLDSAPrivateKey(2, dummyData).fromUntaggedCbor(ur.cbor()); - } - /** - * Creates an MLDSAPrivateKey from a UR string. - */ - static fromURString(urString) { - const ur = UR.fromURString(urString); - return MLDSAPrivateKey.fromUR(ur); - } -}; -/** -* Copyright © 2025-2026 Parity Technologies -* -* RFC 4251/4253 length-prefixed wire format primitives used by every OpenSSH -* binary blob (key bodies, signature blobs, SSHSIG, etc.). -* -* Mirrors what Rust's `ssh-encoding` crate (transitive dep of `ssh-key`) -* produces byte-for-byte, so encodes here round-trip with bytes Rust emits. -* -* Spec references: -* - RFC 4251 §5 (data types: byte, boolean, uint32, uint64, string, mpint, -* name-list) -* - RFC 4253 §6.6 (key/signature framing uses the same primitives) -*/ -const MAX_UINT32 = 4294967295; -var SshBufferReader = class { - bytes; - view; - offset; - constructor(bytes) { - this.bytes = bytes; - this.view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength); - this.offset = 0; - } - position() { - return this.offset; - } - remaining() { - return this.bytes.length - this.offset; - } - isAtEnd() { - return this.offset >= this.bytes.length; - } - requireBytes(n, what) { - if (this.offset + n > this.bytes.length) throw new Error(`SshBuffer: not enough bytes for ${what} (need ${n}, have ${this.bytes.length - this.offset})`); - } - readByte() { - this.requireBytes(1, "byte"); - return this.bytes[this.offset++]; - } - readBoolean() { - return this.readByte() !== 0; - } - readUint32() { - this.requireBytes(4, "uint32"); - const v = this.view.getUint32(this.offset, false); - this.offset += 4; - return v; - } - /** Read a length-prefixed string as raw bytes (no UTF-8 decoding). */ - readString() { - const len = this.readUint32(); - this.requireBytes(len, "string body"); - const start = this.bytes.byteOffset + this.offset; - const slice = new Uint8Array(this.bytes.buffer.slice(start, start + len)); - this.offset += len; - return slice; - } - /** Read a length-prefixed string as UTF-8 text. */ - readStringUtf8() { - return new TextDecoder("utf-8", { fatal: true }).decode(this.readString()); - } - /** - * Read an `mpint` (RFC 4251 §5) — two's-complement big-endian integer with - * optional 0x00 sign byte. We surface the raw bytes verbatim so callers can - * decide how to strip the sign byte for unsigned coordinate values. - */ - readMpint() { - return this.readString(); - } - /** Read a name-list (RFC 4251 §5) — a string of comma-separated US-ASCII names. */ - readNameList() { - const text = this.readStringUtf8(); - return text.length === 0 ? [] : text.split(","); - } -}; -var SshBufferWriter = class { - chunks = []; - size = 0; - writeByte(b) { - if (b < 0 || b > 255 || !Number.isInteger(b)) throw new Error(`SshBuffer: byte out of range: ${b}`); - const buf = /* @__PURE__ */ new Uint8Array(1); - buf[0] = b; - this.chunks.push(buf); - this.size += 1; - return this; - } - writeBoolean(v) { - return this.writeByte(v ? 1 : 0); - } - writeUint32(v) { - if (v < 0 || v > MAX_UINT32 || !Number.isInteger(v)) throw new Error(`SshBuffer: uint32 out of range: ${v}`); - const buf = /* @__PURE__ */ new Uint8Array(4); - new DataView(buf.buffer).setUint32(0, v, false); - this.chunks.push(buf); - this.size += 4; - return this; - } - /** Write a length-prefixed byte string. */ - writeString(bytes) { - this.writeUint32(bytes.length); - this.chunks.push(bytes); - this.size += bytes.length; - return this; - } - /** Write a length-prefixed UTF-8 string. */ - writeStringUtf8(text) { - return this.writeString(new TextEncoder().encode(text)); - } - /** - * Write an `mpint` (RFC 4251 §5). - * - * Two's complement big-endian. For *positive* values (which is all we - * handle — EC coordinates, SSH public-key parameters), if the most - * significant byte has the high bit set, a leading 0x00 must be added so - * the value is not interpreted as negative. Leading zeros are otherwise - * stripped. Zero is encoded as an empty string (length 0). - */ - writeMpintUnsigned(bytes) { - let start = 0; - while (start < bytes.length && bytes[start] === 0) start++; - if (start === bytes.length) return this.writeString(/* @__PURE__ */ new Uint8Array(0)); - const needsSignByte = (bytes[start] & 128) !== 0; - const len = bytes.length - start + (needsSignByte ? 1 : 0); - const out = new Uint8Array(len); - if (needsSignByte) { - out[0] = 0; - out.set(bytes.subarray(start), 1); - } else out.set(bytes.subarray(start), 0); - return this.writeString(out); - } - writeNameList(names) { - return this.writeStringUtf8(names.join(",")); - } - /** Append a raw blob without length-prefixing it. */ - writeRaw(bytes) { - this.chunks.push(bytes); - this.size += bytes.length; - return this; - } - bytes() { - const out = new Uint8Array(this.size); - let pos = 0; - for (const chunk of this.chunks) { - out.set(chunk, pos); - pos += chunk.length; - } - return out; - } -}; -/** -* Strip an optional leading 0x00 sign byte from an unsigned mpint. -* -* RFC 4251 §5 mpints are two's-complement, so positive values whose -* MSB is set carry a leading 0x00. EC curve coordinate bytes never need -* the sign byte once stripped. -*/ -function stripMpintSignByte(bytes) { - if (bytes.length > 0 && bytes[0] === 0) return bytes.subarray(1); - return bytes; -} -/** -* Pad an unsigned big-endian byte sequence to an exact length, throwing -* if the input is longer than `len`. Used for fixed-width EC coordinates. -*/ -function padLeftToLength(bytes, len) { - if (bytes.length === len) return bytes; - if (bytes.length > len) throw new Error(`padLeftToLength: input ${bytes.length} > target ${len}`); - const out = new Uint8Array(len); - out.set(bytes, len - bytes.length); - return out; -} -/** -* Copyright © 2025-2026 Parity Technologies -* -* Minimal PEM (RFC 7468 §3) reader/writer with the byte-shape conventions -* used by Rust `ssh-key` 0.6.7: -* -* - Wrap base64 at **70 columns** for OpenSSH private keys -* (`pem-rfc7468` default for that format). -* - Wrap base64 at **76 columns** for SSHSIG (`PROTOCOL.sshsig` rubric). -* - LF newlines (matches `LineEnding::LF`, which is the rubric used for -* all parity fixtures in `bc-components-rust/src/lib.rs`). -* - Trailing newline after the END line. -*/ -const BEGIN = "-----BEGIN "; -const END = "-----END "; -const SUFFIX = "-----"; -/** -* Parse a single PEM block. Tolerant of CRLF, trailing whitespace, leading -* whitespace lines and `Proc-Type` / `DEK-Info` headers (the SSHSIG/OpenSSH -* formats don't use those, but we ignore them to be robust). -*/ -function parsePem(text, expectedLabel) { - const lines = text.split(/\r?\n/); - let i = 0; - while (i < lines.length && lines[i].trim() === "") i++; - if (i >= lines.length) throw new Error("PEM: empty input"); - const beginLine = lines[i]; - if (!beginLine.startsWith(BEGIN) || !beginLine.endsWith(SUFFIX)) throw new Error(`PEM: expected '-----BEGIN