@optimystic/quereus-plugin-crypto 0.13.5 → 0.16.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -4,31 +4,79 @@
4
4
  * Idiomatic ES module exports with base64url as default encoding.
5
5
  * All functions accept and return base64url strings by default for SQL compatibility.
6
6
  */
7
- type HashAlgorithm$1 = 'sha256' | 'sha512' | 'blake3';
8
- type CurveType$2 = 'secp256k1' | 'p256' | 'ed25519';
7
+ type HashAlgorithm = 'sha256' | 'sha512' | 'blake3';
8
+ type CurveType = 'secp256k1' | 'p256' | 'ed25519';
9
9
  type Encoding = 'base64url' | 'base64' | 'hex' | 'utf8' | 'bytes';
10
+ /** Encodings valid for hash *output* (no 'utf8' — a digest is not UTF-8 text). */
11
+ type OutputEncoding = 'base64url' | 'base64' | 'hex' | 'bytes';
12
+ /** A single value in a multi-field digest. Mirrors the SQL value space. */
13
+ type DigestField = string | number | bigint | boolean | Uint8Array | null | undefined | {
14
+ readonly [key: string]: unknown;
15
+ } | readonly unknown[];
16
+ /** A resolved hash function: raw bytes in, digest bytes out. */
17
+ type DigestHasher = (input: Uint8Array) => Uint8Array;
18
+ /** A resolved output encoder: digest bytes in, encoded form out. */
19
+ type OutputEncoder = (bytes: Uint8Array) => string | Uint8Array;
20
+ /**
21
+ * Resolve a hash algorithm name to its hasher. Throws on unknown algorithm.
22
+ * Call once (e.g. at plugin registration) and capture the result so the digest
23
+ * hot path performs no per-call algorithm branching.
24
+ */
25
+ declare function resolveHasher(algorithm: HashAlgorithm): DigestHasher;
26
+ /**
27
+ * Resolve an output encoding name to its encoder. Throws on unknown encoding.
28
+ */
29
+ declare function resolveOutputEncoder(encoding: OutputEncoding): OutputEncoder;
30
+ /**
31
+ * Canonically encode an ordered tuple of fields into bytes such that distinct
32
+ * tuples never collide (injective framing).
33
+ *
34
+ * Layout: `version ‖ field*` where each field is `tag ‖ varint(len) ‖ payload`
35
+ * (NULL is a bare tag). Properties:
36
+ * - order-preserving and arity-safe (self-delimiting fields → uniquely decodable),
37
+ * - NULL distinguishable from empty string,
38
+ * - type distinguishable (INTEGER 123 ≠ TEXT '123' ≠ BOOL true ≠ BLOB),
39
+ * - delimiter-safe (a separator inside a string is just payload under its length).
40
+ *
41
+ * Replicability notes:
42
+ * - Integer `number` and `bigint` of equal value encode identically (both via
43
+ * `BigInt(...).toString()`); a non-integer REAL uses ECMAScript `Number::toString`
44
+ * (deterministic across JS engines, but not guaranteed across other languages).
45
+ * - INT vs REAL is derived from the JS value, not SQL affinity: an integer-valued
46
+ * REAL (e.g. 2.0 → number 2) encodes as INTEGER, so INTEGER 2 and REAL 2.0 collide.
47
+ * - A native JSON object/array field must contain only valid JSON (no `undefined`,
48
+ * non-finite numbers, `bigint`, or non-plain objects) — otherwise it throws.
49
+ */
50
+ declare function encodeFields(fields: readonly DigestField[]): Uint8Array;
10
51
  /**
11
- * Compute hash digest of input data
52
+ * Low-level multi-field digest: canonically encode the fields, then hash and
53
+ * encode with the supplied (pre-resolved) hasher/encoder. No per-call branching
54
+ * on algorithm or encoding — resolve once via {@link resolveHasher} /
55
+ * {@link resolveOutputEncoder} and reuse.
56
+ */
57
+ declare function digestFields(fields: readonly DigestField[], hasher: DigestHasher, encode: OutputEncoder): string | Uint8Array;
58
+ /**
59
+ * Compute an injective digest over an ordered tuple of fields.
12
60
  *
13
- * @param data - Data to hash (base64url string or Uint8Array)
61
+ * @param fields - Ordered tuple of values to hash (any SQL value type)
14
62
  * @param algorithm - Hash algorithm (default: 'sha256')
15
- * @param inputEncoding - Encoding of input string (default: 'base64url')
16
- * @param outputEncoding - Encoding of output (default: 'base64url')
17
- * @returns Hash digest in specified encoding
63
+ * @param encoding - Output encoding (default: 'base64url')
64
+ * @returns Hash digest in the specified encoding
18
65
  *
19
66
  * @example
20
67
  * ```typescript
21
- * // Hash UTF-8 text, output as base64url
22
- * const hash = digest('hello world', 'sha256', 'utf8');
68
+ * // Hash a tuple of fields — distinct tuples never collide
69
+ * const h = digest(['alice', 42, null, true]);
23
70
  *
24
- * // Hash base64url data with SHA-512
25
- * const hash2 = digest('SGVsbG8', 'sha512');
26
- *
27
- * // Get raw bytes
28
- * const bytes = digest('data', 'blake3', 'utf8', 'bytes');
71
+ * // Pick algorithm / output encoding
72
+ * const h512 = digest(['a', 'b'], 'sha512', 'hex');
29
73
  * ```
74
+ *
75
+ * Note: this is a *framed* digest, not a bare hash of raw bytes —
76
+ * `digest(['hello'])` is not `sha256("hello")`. Use `hashMod` for sharding a
77
+ * single value.
30
78
  */
31
- declare function digest(data: string | Uint8Array, algorithm?: HashAlgorithm$1, inputEncoding?: Encoding, outputEncoding?: Encoding): string | Uint8Array;
79
+ declare function digest(fields: readonly DigestField[], algorithm?: HashAlgorithm, encoding?: OutputEncoding): string | Uint8Array;
32
80
  /**
33
81
  * Hash data and return modulo of specified bit length
34
82
  * Useful for generating fixed-size hash values (e.g., 16-bit, 32-bit)
@@ -48,7 +96,7 @@ declare function digest(data: string | Uint8Array, algorithm?: HashAlgorithm$1,
48
96
  * const hash32 = hashMod('world', 32, 'sha256', 'utf8');
49
97
  * ```
50
98
  */
51
- declare function hashMod(data: string | Uint8Array, bits: number, algorithm?: HashAlgorithm$1, inputEncoding?: Encoding): number;
99
+ declare function hashMod(data: string | Uint8Array, bits: number, algorithm?: HashAlgorithm, inputEncoding?: Encoding): number;
52
100
  /**
53
101
  * Sign data with a private key
54
102
  *
@@ -69,7 +117,7 @@ declare function hashMod(data: string | Uint8Array, bits: number, algorithm?: Ha
69
117
  * const sig2 = sign(hashData, privateKey, 'ed25519');
70
118
  * ```
71
119
  */
72
- declare function sign(data: string | Uint8Array, privateKey: string | Uint8Array, curve?: CurveType$2, inputEncoding?: Encoding, keyEncoding?: Encoding, outputEncoding?: Encoding): string | Uint8Array;
120
+ declare function sign(data: string | Uint8Array, privateKey: string | Uint8Array, curve?: CurveType, inputEncoding?: Encoding, keyEncoding?: Encoding, outputEncoding?: Encoding): string | Uint8Array;
73
121
  /**
74
122
  * Verify a signature
75
123
  *
@@ -91,7 +139,7 @@ declare function sign(data: string | Uint8Array, privateKey: string | Uint8Array
91
139
  * const isValid2 = verify(hashData, signature, publicKey, 'ed25519');
92
140
  * ```
93
141
  */
94
- declare function verify(data: string | Uint8Array, signature: string | Uint8Array, publicKey: string | Uint8Array, curve?: CurveType$2, inputEncoding?: Encoding, sigEncoding?: Encoding, keyEncoding?: Encoding): boolean;
142
+ declare function verify(data: string | Uint8Array, signature: string | Uint8Array, publicKey: string | Uint8Array, curve?: CurveType, inputEncoding?: Encoding, sigEncoding?: Encoding, keyEncoding?: Encoding): boolean;
95
143
  /**
96
144
  * Generate cryptographically secure random bytes
97
145
  *
@@ -103,215 +151,193 @@ declare function randomBytes(bits?: number, encoding?: Encoding): string | Uint8
103
151
  /**
104
152
  * Generate a random private key
105
153
  */
106
- declare function generatePrivateKey(curve?: CurveType$2, encoding?: Encoding): string | Uint8Array;
154
+ declare function generatePrivateKey(curve?: CurveType, encoding?: Encoding): string | Uint8Array;
107
155
  /**
108
156
  * Get public key from private key
109
157
  */
110
- declare function getPublicKey(privateKey: string | Uint8Array, curve?: CurveType$2, keyEncoding?: Encoding, outputEncoding?: Encoding): string | Uint8Array;
158
+ declare function getPublicKey(privateKey: string | Uint8Array, curve?: CurveType, keyEncoding?: Encoding, outputEncoding?: Encoding): string | Uint8Array;
111
159
 
112
160
  /**
113
- * Digest Function for Quereus
161
+ * Self-describing content identifiers (CIDv1) for Quereus.
114
162
  *
115
- * Computes the hash of all arguments combined.
116
- * Uses SHA-256 from @noble/hashes for portable implementation.
117
- * Compatible with React Native and all JS environments.
118
- */
119
- /**
120
- * Hash algorithm options
121
- */
122
- type HashAlgorithm = 'sha256' | 'sha512' | 'blake3';
123
- /**
124
- * Input type for digest function - can be string, Uint8Array, or number
125
- */
126
- type DigestInput$1 = string | Uint8Array | number | boolean | null | undefined;
127
- /**
128
- * Options for the digest function
129
- */
130
- interface DigestOptions {
131
- /** Hash algorithm to use (default: sha256) */
132
- algorithm?: HashAlgorithm;
133
- /** Output format (default: uint8array) */
134
- output?: 'uint8array' | 'hex';
135
- }
136
- /**
137
- * Computes the hash of all arguments
163
+ * Where {@link ./crypto.ts | digest} emits a *bare* hash (raw digest bytes in
164
+ * some text encoding), this module emits an interoperable, self-describing
165
+ * CIDv1:
138
166
  *
139
- * @param {...DigestInput} args - Variable number of arguments to hash
140
- * @returns {Uint8Array} The computed hash as a Uint8Array
141
- *
142
- * @example
143
- * ```typescript
144
- * // Hash a string
145
- * const hash1 = Digest('hello world');
146
- *
147
- * // Hash multiple arguments
148
- * const hash2 = Digest('user:', 123, 'session');
149
- *
150
- * // Hash with specific algorithm
151
- * const hash3 = Digest.withOptions({ algorithm: 'sha512' })('data1', 'data2');
152
- *
153
- * // Get hex output
154
- * const hexHash = Digest.withOptions({ output: 'hex' })('hello');
155
167
  * ```
168
+ * CIDv1 = multibase( version ‖ multicodec(content-type) ‖ multihash )
169
+ * multihash = hashFnCode ‖ digestLength ‖ digestBytes
170
+ * ```
171
+ *
172
+ * The value carries its own multibase, multicodec (content type), and multihash
173
+ * (hash algorithm + length), so a consumer can decode it without out-of-band
174
+ * knowledge, and an algorithm migration (e.g. sha2-256 → another hash) is
175
+ * unambiguous because the hash code is recorded *in the value*.
176
+ *
177
+ * All framing/parsing comes from the audited `multiformats` library — there is
178
+ * no bespoke byte-pushing here. The actual hashing reuses the same synchronous,
179
+ * cross-platform `@noble/hashes` functions the rest of the plugin uses (via
180
+ * {@link resolveHasher}), so the output is byte-identical to the CID an external
181
+ * content-addressed store (IPFS/IPLD) computes for the same bytes:
182
+ * `cid(utf8('hello world'))` === `bafkreifzjut3te2nhyekklss27nh3k72ysco7y32koao5eei66wof36n5e`.
156
183
  */
157
- declare function Digest(...args: DigestInput$1[]): Uint8Array;
158
- declare namespace Digest {
159
- var withOptions: (options: DigestOptions) => (...args: DigestInput$1[]) => string | Uint8Array<ArrayBufferLike>;
160
- var sha256: (...args: DigestInput$1[]) => Uint8Array;
161
- var sha512: (...args: DigestInput$1[]) => Uint8Array;
162
- var blake3: (...args: DigestInput$1[]) => Uint8Array;
163
- var hex: (...args: DigestInput$1[]) => string;
164
- var sha256Hex: (...args: DigestInput$1[]) => string;
165
- var sha512Hex: (...args: DigestInput$1[]) => string;
166
- var blake3Hex: (...args: DigestInput$1[]) => string;
184
+ /** Content-type multicodec selectable for the CID. Extensible. */
185
+ type Multicodec = 'raw' | 'dag-cbor';
186
+ /** Hash-algorithm multihash code selectable for the CID. */
187
+ type MultihashCode = 'sha2-256' | 'sha2-512' | 'blake3';
188
+ /** Multibase the CID string is rendered in. */
189
+ type Multibase = 'base32' | 'base58btc' | 'base64url' | 'base16';
190
+ /** Parsed parts of a CIDv1 (or CIDv0), as returned by {@link cidDecode}. */
191
+ interface CidParts {
192
+ /** CID version (1 for the values this module produces; 0 for legacy CIDv0). */
193
+ readonly version: number;
194
+ /** Content-type codec name when recognized, else the raw multicodec number. */
195
+ readonly codec: Multicodec | number;
196
+ /** Hash-algorithm code name when recognized, else the raw multihash number. */
197
+ readonly hashCode: MultihashCode | number;
198
+ /** Raw digest bytes (without the multihash code/length prefix). */
199
+ readonly digest: Uint8Array;
167
200
  }
168
-
169
201
  /**
170
- * Sign Function for Quereus
202
+ * Frame an **already-computed** digest as a CIDv1 string. The caller asserts
203
+ * which `hash` produced the digest; the digest length is validated against that
204
+ * hash so a mismatched assertion is rejected rather than silently mis-framed.
171
205
  *
172
- * Returns the signature for the given payload using an ECC private key.
173
- * Uses secp256k1 from @noble/curves for portable implementation.
174
- * Compatible with React Native and all JS environments.
175
- */
176
- /**
177
- * Supported elliptic curve types
178
- */
179
- type CurveType$1 = 'secp256k1' | 'p256' | 'ed25519';
180
- /**
181
- * Private key input - can be Uint8Array, hex string, or bigint
182
- */
183
- type PrivateKeyInput = Uint8Array | string | bigint;
184
- /**
185
- * Digest input - can be Uint8Array or hex string
206
+ * Use this to turn an existing field-tuple digest into a CID without re-hashing,
207
+ * e.g. `cidV1(digest(fields, 'sha256', 'bytes'), 'sha2-256')`.
208
+ *
209
+ * @param digest - Raw digest bytes (no multihash prefix).
210
+ * @param hash - The multihash code asserting which algorithm produced `digest`.
211
+ * @param codec - Content-type multicodec (default `'raw'`).
212
+ * @param base - Multibase to render in (default `'base32'`, the IPFS canonical).
186
213
  */
187
- type DigestInput = Uint8Array | string;
214
+ declare function cidV1(digest: Uint8Array, hash: MultihashCode, codec?: Multicodec, base?: Multibase): string;
188
215
  /**
189
- * Signature output format options
216
+ * Hash `data`, wrap the digest as a multihash, frame it as a CIDv1, and encode
217
+ * in `base`. The result is the same interoperable address an IPFS/IPLD store
218
+ * computes for the same bytes (for the matching codec/hash).
219
+ *
220
+ * @param data - The content bytes to address.
221
+ * @param codec - Content-type multicodec (default `'raw'`).
222
+ * @param hash - Hash algorithm (default `'sha2-256'`).
223
+ * @param base - Multibase to render in (default `'base32'`, the IPFS canonical).
190
224
  */
191
- type SignatureFormat = 'uint8array' | 'hex' | 'compact' | 'der';
225
+ declare function cid(data: Uint8Array, codec?: Multicodec, hash?: MultihashCode, base?: Multibase): string;
192
226
  /**
193
- * Options for the Sign function
227
+ * Parse a CID string back into its parts, for schema validation and migration.
228
+ * Recognized codec/hash codes are returned as friendly names; unrecognized ones
229
+ * as their raw numbers. Throws cleanly on malformed input (delegated to
230
+ * `multiformats`), never silently mis-framing.
194
231
  */
195
- interface SignOptions {
196
- /** Elliptic curve to use (default: secp256k1) */
197
- curve?: CurveType$1;
198
- /** Output format for signature (default: uint8array) */
199
- format?: SignatureFormat;
200
- /** Additional entropy for signatures (hedged signatures) */
201
- extraEntropy?: boolean | Uint8Array;
202
- /** Use low-S canonical signatures (default: true) */
203
- lowS?: boolean;
204
- }
232
+ declare function cidDecode(value: string): CidParts;
233
+
205
234
  /**
206
- * Sign a digest using the specified private key and curve
235
+ * Salted-leaf SET COMMITMENT for per-attribute selective disclosure.
207
236
  *
208
- * @param {DigestInput} digest - The digest/hash to sign
209
- * @param {PrivateKeyInput} privateKey - The private key to use for signing
210
- * @param {SignOptions} [options] - Optional signing parameters
211
- * @returns {Uint8Array | string} The signature in the requested format
237
+ * An authority commits to a whole set of attributes as a single root value (which
238
+ * it signs / persists), then later reveals only a chosen *subset* to a recipient
239
+ * with a proof that the revealed values are genuinely the committed ones — without
240
+ * leaking the values of the withheld attributes. A flat `digest(whole set)` cannot
241
+ * do this (verifying one field needs the whole pre-image, so it is all-or-nothing);
242
+ * this construction supports *partial opening*.
243
+ *
244
+ * ## Construction (flat salted-leaf set commitment, NOT a Merkle tree)
245
+ *
246
+ * Each disclosable attribute is a salted leaf, and the commitment (root) is the
247
+ * digest of all leaf digests in canonical order:
212
248
  *
213
- * @example
214
- * ```typescript
215
- * // Basic usage with secp256k1
216
- * const digest = new Uint8Array(32).fill(1); // Your hash here
217
- * const privateKey = 'a'.repeat(64); // Your private key hex
218
- * const signature = Sign(digest, privateKey);
219
- *
220
- * // With specific curve and format
221
- * const sig = Sign(digest, privateKey, {
222
- * curve: 'p256',
223
- * format: 'hex'
224
- * });
225
- *
226
- * // With hedged signatures for extra security
227
- * const hedgedSig = Sign(digest, privateKey, {
228
- * extraEntropy: true
229
- * });
230
249
  * ```
231
- */
232
- declare function Sign(digest: DigestInput, privateKey: PrivateKeyInput, options?: SignOptions): Uint8Array | string;
233
- declare namespace Sign {
234
- var secp256k1: (digest: DigestInput, privateKey: PrivateKeyInput, options?: Omit<SignOptions, "curve">) => string | Uint8Array<ArrayBufferLike>;
235
- var p256: (digest: DigestInput, privateKey: PrivateKeyInput, options?: Omit<SignOptions, "curve">) => string | Uint8Array<ArrayBufferLike>;
236
- var ed25519: (digest: DigestInput, privateKey: PrivateKeyInput, options?: Omit<SignOptions, "curve">) => string | Uint8Array<ArrayBufferLike>;
237
- var generatePrivateKey: (curve?: CurveType$1) => Uint8Array;
238
- var getPublicKey: (privateKey: PrivateKeyInput, curve?: CurveType$1) => Uint8Array;
239
- }
240
-
241
- /**
242
- * SignatureValid Function for Quereus
250
+ * leafDigest = digest([SD_LEAF_DOMAIN_V1, name, value, salt]) // raw digest bytes
251
+ * root = digest([SD_SET_DOMAIN_V1, sortedLeaf_0, sortedLeaf_1, ...])
252
+ * ```
243
253
  *
244
- * Returns true if the ECC signature is valid for the given digest and public key.
245
- * Uses @noble/curves for portable implementation.
246
- * Compatible with React Native and all JS environments.
254
+ * Both layers compose on the existing canonical {@link encodeFields} framing
255
+ * (injective, type-tagged, length-prefixed, replicable) — the same layering the CID
256
+ * work uses so a *generic* salted-set primitive is simultaneously reusable and
257
+ * fully DB-enforceable. This is the same shape the IETF SD-JWT standard settled on
258
+ * (flat salted hashes, not a tree); we are NOT wire-compatible with SD-JWT (we reuse
259
+ * Optimystic's own `encodeFields` framing for cross-peer replicability) — SD-JWT is
260
+ * cited only as conceptual precedent that the smaller construction is the right one.
261
+ *
262
+ * Voter selective-disclosure field sets are small (a handful to a few dozen fields),
263
+ * so a tree's only advantage — O(log n) proof size — is marginal, while a tree drags
264
+ * in real footguns we would have to hand-roll and pin (arity, odd-node handling /
265
+ * the CVE-2012-2459 duplicate-leaf forgery class, leaf-vs-internal domain separation,
266
+ * and a separate audit-path proof format). A flat construction avoids all of them.
267
+ *
268
+ * ## Why these specific choices
269
+ *
270
+ * - **`name` is hashed into the leaf** so a disclosed `(value, salt)` proof cannot be
271
+ * replayed against a different attribute slot (e.g. presenting an `over18=true`
272
+ * proof as the `citizen` field). The binding is free given `encodeFields` framing.
273
+ * - **`salt` is per-leaf and mandatory** — low-entropy attributes (DOB, booleans, ZIP)
274
+ * are brute-forceable from a bare hash, and independent salts also defeat cross-
275
+ * registrant equality correlation. Salts come from `random_bytes` (≥128 bits).
276
+ * - **Canonical order is by raw leaf-digest bytes (lexicographic), and this is FORCED,
277
+ * not a preference.** In a disclosure the verifier learns the *names* of only the
278
+ * disclosed leaves; the withheld leaves arrive as opaque digests with no name. So the
279
+ * verifier can re-derive the root only if the ordering key is something it holds for
280
+ * *every* leaf — the leaf digest itself. Sorting by name would be unverifiable for
281
+ * hidden leaves. Do NOT "tidy" this into a name sort.
282
+ * - Sort is over **raw digest bytes**, never over encoded strings — an encoding-
283
+ * dependent ordering would break cross-peer agreement. Output encoding applies only
284
+ * to the final root.
285
+ *
286
+ * Because leaf and root reuse `encodeFields`, a future `DIGEST_FORMAT_V1` bump changes
287
+ * `setCommit` output too; this coupling is intentional (one canonical framing).
247
288
  */
289
+
290
+ /** One disclosable attribute. `value` spans the SQL value space ({@link DigestField}). */
291
+ interface SaltedLeaf {
292
+ readonly name: string;
293
+ readonly value: DigestField;
294
+ /** base64url text (e.g. from `random_bytes`) or raw bytes. Mandatory, non-empty. */
295
+ readonly salt: string | Uint8Array;
296
+ }
297
+ /** A disclosure payload sent to a recipient. */
298
+ interface SetDisclosure {
299
+ /** The opened `(name, value, salt)` triples. */
300
+ readonly disclosed: readonly SaltedLeaf[];
301
+ /** Opaque leaf digests (base64url) of the withheld leaves — no name, no value, no salt. */
302
+ readonly hidden: readonly string[];
303
+ }
248
304
  /**
249
- * Supported elliptic curve types
305
+ * Raw leaf digest bytes for one salted leaf: `digest([SD_LEAF_DOMAIN_V1, name,
306
+ * value, salt])`. Domain-separated (can never equal a root) and name-bound (a
307
+ * `(value, salt)` proof cannot be replayed under another attribute name). THROWS on
308
+ * a missing/empty salt.
250
309
  */
251
- type CurveType = 'secp256k1' | 'p256' | 'ed25519';
310
+ declare function leafDigest(leaf: SaltedLeaf, hasher: DigestHasher): Uint8Array;
252
311
  /**
253
- * Input types that can be Uint8Array or hex string
312
+ * Commit to a SET of salted leaves a single root (the signed/persisted value).
313
+ * Sorts leaves by raw leaf-digest bytes, then digests them under `SD_SET_DOMAIN_V1`.
314
+ * Like `digest`, this emits a BARE digest — apply `cid()` on top for the self-
315
+ * describing column representation (`cid(set_commit(...))`).
316
+ *
317
+ * The empty set is well-defined (the digest of `[SD_SET_DOMAIN_V1]`), not an error.
318
+ * THROWS on a duplicate `name` or a missing/empty `salt` (invalid states made
319
+ * impossible). Resolve `hasher`/`encode` once and reuse — no per-call branching.
254
320
  */
255
- type BytesInput = Uint8Array | string;
321
+ declare function setCommit(leaves: readonly SaltedLeaf[], hasher?: DigestHasher, encode?: OutputEncoder): string | Uint8Array;
256
322
  /**
257
- * Options for signature verification
323
+ * Split a leaf set into the revealed `(name, value, salt)` triples plus the opaque
324
+ * leaf digests (base64url) of the rest. Withheld `value`/`salt` never appear in the
325
+ * output. Names in `revealNames` that match no leaf are simply not disclosed.
326
+ * THROWS on a duplicate `name` or a missing/empty salt of a withheld leaf.
258
327
  */
259
- interface VerifyOptions {
260
- /** Elliptic curve to use (default: secp256k1) */
261
- curve?: CurveType;
262
- /** Signature format (default: auto-detect) */
263
- signatureFormat?: 'compact' | 'der' | 'raw';
264
- /** Allow malleable signatures (default: false for ECDSA, true for EdDSA) */
265
- allowMalleableSignatures?: boolean;
266
- }
328
+ declare function setDisclose(leaves: readonly SaltedLeaf[], revealNames: readonly string[], hasher?: DigestHasher): SetDisclosure;
267
329
  /**
268
- * Verify if an ECC signature is valid
269
- *
270
- * @param {BytesInput} digest - The digest/hash that was signed
271
- * @param {BytesInput} signature - The signature to verify
272
- * @param {BytesInput} publicKey - The public key to verify against
273
- * @param {VerifyOptions} [options] - Optional verification parameters
274
- * @returns {boolean} True if the signature is valid, false otherwise
275
- *
276
- * @example
277
- * ```typescript
278
- * // Basic usage with secp256k1
279
- * const isValid = SignatureValid(digest, signature, publicKey);
280
- *
281
- * // With specific curve
282
- * const isValid = SignatureValid(digest, signature, publicKey, {
283
- * curve: 'p256'
284
- * });
285
- *
286
- * // With specific signature format
287
- * const isValid = SignatureValid(digest, signature, publicKey, {
288
- * curve: 'secp256k1',
289
- * signatureFormat: 'der'
290
- * });
291
- *
292
- * // Allow malleable signatures
293
- * const isValid = SignatureValid(digest, signature, publicKey, {
294
- * allowMalleableSignatures: true
295
- * });
296
- * ```
330
+ * Verify a disclosure against a signed root. Recomputes the disclosed leaves'
331
+ * digests, unions them with the supplied hidden digests, sorts by bytes, recomputes
332
+ * the root, and compares to `root`. This reconstructs the ENTIRE root, so it proves
333
+ * the disclosed leaves belong to *exactly* this committed set — the holder cannot
334
+ * add, drop, or swap a leaf (the leaf count is bound too).
335
+ *
336
+ * `encode` is how the signed `root` is rendered (so the recomputed root is encoded
337
+ * the same way before comparison); for a `Uint8Array` root the raw bytes are compared
338
+ * directly. Returns `false` on mismatch or malformed input — mirroring `verify`'s
339
+ * forgiving contract rather than throwing.
297
340
  */
298
- declare function SignatureValid(digest: BytesInput, signature: BytesInput, publicKey: BytesInput, options?: VerifyOptions): boolean;
299
- declare namespace SignatureValid {
300
- var secp256k1: (digest: BytesInput, signature: BytesInput, publicKey: BytesInput, options?: Omit<VerifyOptions, "curve">) => boolean;
301
- var p256: (digest: BytesInput, signature: BytesInput, publicKey: BytesInput, options?: Omit<VerifyOptions, "curve">) => boolean;
302
- var ed25519: (digest: BytesInput, signature: BytesInput, publicKey: BytesInput, options?: Omit<VerifyOptions, "curve">) => boolean;
303
- var batch: (verifications: Array<{
304
- digest: BytesInput;
305
- signature: BytesInput;
306
- publicKey: BytesInput;
307
- options?: VerifyOptions;
308
- }>) => boolean[];
309
- var detailed: (digest: BytesInput, signature: BytesInput, publicKey: BytesInput, options?: VerifyOptions) => {
310
- valid: boolean;
311
- curve: CurveType;
312
- signatureFormat: string;
313
- error?: string;
314
- };
315
- }
341
+ declare function setVerify(root: string | Uint8Array, disclosure: SetDisclosure, hasher?: DigestHasher, encode?: OutputEncoder): boolean;
316
342
 
317
- export { type BytesInput, type CurveType$2 as CurveType, Digest, type DigestInput$1 as DigestInput, type DigestOptions, type Encoding, type HashAlgorithm$1 as HashAlgorithm, type PrivateKeyInput, Sign, type SignOptions, SignatureValid, type VerifyOptions, digest, generatePrivateKey, getPublicKey, hashMod, randomBytes, sign, verify };
343
+ export { type CidParts, type CurveType, type DigestField, type DigestHasher, type Encoding, type HashAlgorithm, type Multibase, type Multicodec, type MultihashCode, type OutputEncoder, type OutputEncoding, type SaltedLeaf, type SetDisclosure, cid, cidDecode, cidV1, digest, digestFields, encodeFields, generatePrivateKey, getPublicKey, hashMod, leafDigest, randomBytes, resolveHasher, resolveOutputEncoder, setCommit, setDisclose, setVerify, sign, verify };