@grizzlycbg/asset-signer
v0.2.0
Published
Isomorphic asset signing and offline signature verification for the Grizzly platform. No native bindings, no node: builtins — runs in Node, browsers, and workers.
Maintainers
Readme
@grizzlycbg/asset-signer
The isomorphic signing core of the Grizzly platform. It defines the signature wire format, the
crypto-agile provider interface, and the AssetSigner that both signs and verifies a signed
asset. It runs unchanged in Node, a browser, or a worker — its only dependency is
@noble/hashes, and it imports no node: builtins.
Most applications do not use this package directly. Reach for:
@grizzlycbg/asset-verify— to verify signed assets offline (the common case).@grizzlycbg/grizzly-sdk— to encrypt/decrypt/sign against a Grizzly backend.
Use @grizzlycbg/asset-signer directly only when you are building signing or verification logic and
need the primitives themselves.
Why it exists
A Grizzly asset is signed with a short-lived Intermediate Signing Key (ISK) that chains to a KeyRing's Root Signing Key (RRSK) via an embedded certificate. Given the ring's public keyset, anyone can verify the chain — asset signature → intermediate cert → ring root — with no access to the Grizzly backend and no private keys.
Signing and verification live in the same package on purpose: the to-be-signed bytes are produced
by one function (assetTbs) shared by both paths. Splitting them across packages is how a verifier
drifts from a signer and starts accepting what it should reject — the exact failure class this
package is built to prevent.
What's inside
| Export | Purpose |
|---|---|
| AssetSigner | Signs an asset with an ISK (sign) and verifies a SignedAsset against a ring keyset (verify). verify never throws — it returns { success, message }. |
| SignatureProvider, SignatureRegistry | The crypto-agile seam. One provider per component algorithm; a registry composes them into a hybrid suite. |
| SignedAsset, IntermediateCert, SigningKeysetEntry, … | The signature wire types, kept dependency-free (raw base64url strings) so a cert verifies offline. |
| canonical, signingKeyFingerprint | Deterministic canonical-JSON encoding and the content-addressed id for a signing keyset. Shared by every party so ids never drift. |
| SigningPausedError, AsymUnavailableError, SigningRequiredError + guards | Typed signing errors with a wire-code discriminant, so clients can branch on an encrypt failure across serialization boundaries. |
Crypto agility
AssetSigner never hardcodes an algorithm — it holds a SignatureRegistry of one
SignatureProvider per component. The default suite is hybrid:ed25519+ml-dsa-65, where every
component must verify (AND-verify), so the signature survives a classical or a post-quantum break.
The providers themselves live in sibling packages so this one stays free of native and PQC code:
@grizzlycbg/pqc-native— Node/OpenSSL providers (server-side throughput).@grizzlycbg/pqc-noble— pure-JS providers (browser / offline verifiers).
A signature produced under one backend verifies under the other — they are byte-for-byte compatible.
Browser safety (a maintained invariant)
This package must remain bundleable for the browser. Two rules keep it that way:
- Never import a
node:builtin — or anything that transitively does, notably@grizzlycbg/core, whose barrel pulls innode:crypto/node:stream. - Never export a Node-only provider from the barrel. The build is CommonJS, so a top-level
requirecannot be tree-shaken away — one such export re-breaks every browser consumer. Thenode:cryptoed25519 provider deliberately lives in@grizzlycbg/pqc-native, not here.
License
ISC © Cyber Bear Group
