@zanii/redact 0.1.1 → 0.1.3

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/README.md CHANGED
@@ -41,6 +41,8 @@ SPEC.md §12).
41
41
 
42
42
  ## Changelog
43
43
 
44
+ - **0.1.3** — Range proofs (via @zanii/zk), field-in-set proofs, predicates over disclosures and ranges, nested JSON commitments, provably redacted documents, SD-JWT export/verify/present, disclosure log, expiring grants, role-based auditor views, LLM-safe context.
45
+ - **0.1.2** — now depends on `@zanii/core` 0.5 (protocol 1.2), so it shares one core with `@zanii/sdk` 0.5 instead of pulling in a second, older copy. No API change.
44
46
  - **0.1.0** — initial release: `commit`, `disclose`, `verifyDisclosure`.
45
47
 
46
48
  ## License
@@ -0,0 +1,157 @@
1
+ import { type RiskLevel, type SignedObject } from '@zanii/core';
2
+ import { type CommittedSet, type MembershipProof, type ThresholdAnchor, type ThresholdProof, type ThresholdSecret } from '@zanii/zk';
3
+ import { type CommitResult, type Disclosure, type RedactEnvelope } from './index.js';
4
+ export interface RangeAnchors {
5
+ field: string;
6
+ /** Upper bound of the scale (e.g. 150 for age); proofs of "at most" count down from it. */
7
+ bound: number;
8
+ lo: ThresholdAnchor;
9
+ hi: ThresholdAnchor;
10
+ }
11
+ /**
12
+ * Issuer side: anchors for a numeric field so the holder can later prove min <= value <= max
13
+ * without revealing it. Commit or sign `anchors` (e.g. as a committed field); give `secret` to the holder.
14
+ */
15
+ export declare function rangeAnchors(field: string, value: number, bound: number): {
16
+ anchors: RangeAnchors;
17
+ secret: {
18
+ lo: ThresholdSecret;
19
+ hi: ThresholdSecret;
20
+ };
21
+ };
22
+ export interface RangeProof {
23
+ field: string;
24
+ min: number;
25
+ max: number;
26
+ lo: ThresholdProof;
27
+ hi: ThresholdProof;
28
+ }
29
+ /** Holder side: prove min <= value <= max. Throws if the value is outside. */
30
+ export declare function proveRange(anchors: RangeAnchors, secret: {
31
+ lo: ThresholdSecret;
32
+ hi: ThresholdSecret;
33
+ }, min: number, max: number): RangeProof;
34
+ export declare function verifyRange(anchors: RangeAnchors, p: RangeProof): boolean;
35
+ /**
36
+ * Show that a committed field's value is in a committed set (an allow-list, the eligible ids),
37
+ * revealing that value but nothing else of the set or the other fields.
38
+ */
39
+ export declare function proveFieldInSet(result: CommitResult, key: string, set: CommittedSet): {
40
+ disclosure: Disclosure;
41
+ membership: MembershipProof;
42
+ };
43
+ export declare function verifyFieldInSet(p: {
44
+ disclosure: Disclosure;
45
+ membership: MembershipProof;
46
+ }, envelope: RedactEnvelope, setRoot: string): boolean;
47
+ export type Predicate = {
48
+ all: Predicate[];
49
+ } | {
50
+ any: Predicate[];
51
+ } | {
52
+ field: string;
53
+ op: 'eq' | 'neq' | 'in';
54
+ value: unknown;
55
+ } | {
56
+ field: string;
57
+ op: 'gte' | 'lte';
58
+ value: number;
59
+ };
60
+ /**
61
+ * Evaluate a predicate over verified disclosures (and range proofs, which satisfy gte/lte without
62
+ * revealing the value). Unverifiable or missing fields make their clause false.
63
+ */
64
+ export declare function evaluatePredicate(expr: Predicate, envelope: RedactEnvelope, evidence: {
65
+ disclosures?: Disclosure[];
66
+ ranges?: Array<{
67
+ anchors: RangeAnchors;
68
+ proof: RangeProof;
69
+ }>;
70
+ }): boolean;
71
+ /** Flatten JSON to RFC 6901 pointers -> leaf values (empty objects and arrays are kept as leaves). */
72
+ export declare function flattenJson(value: unknown, prefix?: string): Record<string, unknown>;
73
+ /** Commit to every leaf of a JSON document, keyed by its JSON pointer (e.g. `/customer/address/city`). */
74
+ export declare function nestedCommit(json: Record<string, unknown>): CommitResult;
75
+ /** Commit to a document split into segments (pages, paragraphs, clauses). You do the splitting, e.g. per PDF page. */
76
+ export declare function commitDocument(segments: string[]): CommitResult;
77
+ /** Release a redacted copy: the kept segments with proofs; the rest are provably the committed ones, hidden. */
78
+ export declare function redactDocument(result: CommitResult, keep: number[]): {
79
+ envelope: RedactEnvelope;
80
+ disclosures: Disclosure[];
81
+ };
82
+ /** Rebuild the redacted view: verified segments in place, `null` where redacted; fails on any bad proof. */
83
+ export declare function verifyRedactedDocument(doc: {
84
+ envelope: RedactEnvelope;
85
+ disclosures: Disclosure[];
86
+ }): {
87
+ ok: boolean;
88
+ bad: string[];
89
+ segments: (string | null)[];
90
+ };
91
+ /**
92
+ * Export fields as an SD-JWT (IETF draft format: `<issuer-jwt>~<disclosure>~...~`), signed EdDSA
93
+ * with the issuer's did:key. Every field is selectively disclosable.
94
+ */
95
+ export declare function sdJwtExport(fields: Record<string, unknown>, issuerPrivateKey: Uint8Array, opts?: {
96
+ iat?: number;
97
+ vct?: string;
98
+ }): string;
99
+ /** Verify an SD-JWT from `sdJwtExport` (issuer signature, every presented disclosure listed) and return the disclosed claims. */
100
+ export declare function verifySdJwt(token: string): {
101
+ ok: boolean;
102
+ issuer?: string;
103
+ claims: Record<string, unknown>;
104
+ reason?: string;
105
+ };
106
+ /** Present only some claims of an SD-JWT: keeps the issuer JWT and the chosen disclosures. */
107
+ export declare function presentSdJwt(token: string, keys: string[]): string;
108
+ interface Recorder {
109
+ record(fields: {
110
+ target: string;
111
+ payload: unknown;
112
+ risk?: RiskLevel;
113
+ }): Promise<unknown>;
114
+ }
115
+ /** Record who was shown which fields, why, as a receipt (names and root only, never the values). */
116
+ export declare function logDisclosure(agent: Recorder, input: {
117
+ recipient: string;
118
+ purpose: string;
119
+ disclosures: Disclosure[];
120
+ }): Promise<unknown>;
121
+ export type DisclosureGrant = SignedObject<{
122
+ v: 1;
123
+ type: 'redact.grant';
124
+ recipient: string;
125
+ exp: string;
126
+ root: string;
127
+ disclosures: Disclosure[];
128
+ }>;
129
+ /** Wrap disclosures in a grant for one recipient that expires. Signed by the holder. */
130
+ export declare function grantDisclosure(disclosures: Disclosure[], opts: {
131
+ recipient: string;
132
+ exp: string;
133
+ }, holderPrivateKey: Uint8Array): DisclosureGrant;
134
+ export declare function verifyGrant(g: DisclosureGrant, envelope: RedactEnvelope, opts: {
135
+ recipient: string;
136
+ now?: string;
137
+ }): {
138
+ ok: boolean;
139
+ reasons: string[];
140
+ };
141
+ export type RevealPolicy = Record<string, string[]>;
142
+ /** Disclosures for a role (e.g. `regulator` sees more than `counterparty`). Unknown roles see nothing. */
143
+ export declare function auditorView(result: CommitResult, policy: RevealPolicy, role: string): Disclosure[];
144
+ /**
145
+ * Context for a language model holding only the fields a role may see, each with its proof,
146
+ * and the names of what was withheld. The model never receives the withheld values.
147
+ */
148
+ export declare function llmSafeContext(result: CommitResult, policy: RevealPolicy, role: string): {
149
+ context: {
150
+ [k: string]: unknown;
151
+ };
152
+ text: string;
153
+ proofs: Disclosure[];
154
+ withheld: string[];
155
+ };
156
+ export {};
157
+ //# sourceMappingURL=advanced.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"advanced.d.ts","sourceRoot":"","sources":["../src/advanced.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,183 @@
1
+ /**
2
+ * Selective disclosure, further: range proofs (hash-chain, via @zanii/zk), set
3
+ * membership, predicates over disclosed fields, nested JSON commitments, redacted
4
+ * documents with a provably unchanged remainder, SD-JWT export, a disclosure log,
5
+ * expiring grants, role-based auditor views and LLM-safe context.
6
+ */
7
+ import { createHash, createPrivateKey, createPublicKey, randomBytes, sign as edSign, verify as edVerify } from 'node:crypto';
8
+ import { didFromPublicKey, publicKeyFromDid, signObject, verifySignedObject } from '@zanii/core';
9
+ import { proveAtLeast, proveMembership, thresholdChain, verifyAtLeast, verifyMembership } from '@zanii/zk';
10
+ import { commit, disclose, verifyDisclosure } from './index.js';
11
+ /**
12
+ * Issuer side: anchors for a numeric field so the holder can later prove min <= value <= max
13
+ * without revealing it. Commit or sign `anchors` (e.g. as a committed field); give `secret` to the holder.
14
+ */
15
+ export function rangeAnchors(field, value, bound) {
16
+ if (!Number.isInteger(value) || value < 0 || value > bound)
17
+ throw new Error(`redact: ${field} must be an integer in 0..${bound}`);
18
+ const lo = thresholdChain(value, `${field}/lo`);
19
+ const hi = thresholdChain(bound - value, `${field}/hi`);
20
+ return { anchors: { field, bound, lo: lo.anchor, hi: hi.anchor }, secret: { lo: lo.secret, hi: hi.secret } };
21
+ }
22
+ /** Holder side: prove min <= value <= max. Throws if the value is outside. */
23
+ export function proveRange(anchors, secret, min, max) {
24
+ return { field: anchors.field, min, max, lo: proveAtLeast(secret.lo, `${anchors.field}/lo`, min), hi: proveAtLeast(secret.hi, `${anchors.field}/hi`, anchors.bound - max) };
25
+ }
26
+ export function verifyRange(anchors, p) {
27
+ return p.field === anchors.field && p.min <= p.max && p.lo.threshold === p.min && p.hi.threshold === anchors.bound - p.max && verifyAtLeast(anchors.lo, p.lo) && verifyAtLeast(anchors.hi, p.hi);
28
+ }
29
+ /**
30
+ * Show that a committed field's value is in a committed set (an allow-list, the eligible ids),
31
+ * revealing that value but nothing else of the set or the other fields.
32
+ */
33
+ export function proveFieldInSet(result, key, set) {
34
+ const d = disclose(result, key);
35
+ return { disclosure: d, membership: proveMembership(set, String(d.value)) };
36
+ }
37
+ export function verifyFieldInSet(p, envelope, setRoot) {
38
+ return verifyDisclosure(p.disclosure, envelope) && p.membership.item === String(p.disclosure.value) && verifyMembership(setRoot, p.membership);
39
+ }
40
+ /**
41
+ * Evaluate a predicate over verified disclosures (and range proofs, which satisfy gte/lte without
42
+ * revealing the value). Unverifiable or missing fields make their clause false.
43
+ */
44
+ export function evaluatePredicate(expr, envelope, evidence) {
45
+ if ('all' in expr)
46
+ return expr.all.every((e) => evaluatePredicate(e, envelope, evidence));
47
+ if ('any' in expr)
48
+ return expr.any.some((e) => evaluatePredicate(e, envelope, evidence));
49
+ if (expr.op === 'gte' || expr.op === 'lte') {
50
+ const viaRange = (evidence.ranges ?? []).some(({ anchors, proof }) => anchors.field === expr.field && verifyRange(anchors, proof) && (expr.op === 'gte' ? proof.min >= expr.value : proof.max <= expr.value));
51
+ if (viaRange)
52
+ return true;
53
+ }
54
+ const d = (evidence.disclosures ?? []).find((x) => x.key === expr.field && verifyDisclosure(x, envelope));
55
+ if (!d)
56
+ return false;
57
+ const v = d.value;
58
+ switch (expr.op) {
59
+ case 'eq': return JSON.stringify(v) === JSON.stringify(expr.value);
60
+ case 'neq': return JSON.stringify(v) !== JSON.stringify(expr.value);
61
+ case 'in': return Array.isArray(expr.value) && expr.value.some((x) => JSON.stringify(x) === JSON.stringify(v));
62
+ case 'gte': return typeof v === 'number' && v >= expr.value;
63
+ case 'lte': return typeof v === 'number' && v <= expr.value;
64
+ }
65
+ }
66
+ // ------------------------------------------------------------------------------ //
67
+ // Nested JSON and documents
68
+ // ------------------------------------------------------------------------------ //
69
+ const escapePointer = (s) => s.replace(/~/g, '~0').replace(/\//g, '~1');
70
+ /** Flatten JSON to RFC 6901 pointers -> leaf values (empty objects and arrays are kept as leaves). */
71
+ export function flattenJson(value, prefix = '') {
72
+ if (value !== null && typeof value === 'object' && Object.keys(value).length > 0) {
73
+ return Object.assign({}, ...Object.entries(value).map(([k, v]) => flattenJson(v, `${prefix}/${escapePointer(k)}`)));
74
+ }
75
+ return { [prefix || '/']: value };
76
+ }
77
+ /** Commit to every leaf of a JSON document, keyed by its JSON pointer (e.g. `/customer/address/city`). */
78
+ export function nestedCommit(json) {
79
+ return commit(flattenJson(json));
80
+ }
81
+ /** Commit to a document split into segments (pages, paragraphs, clauses). You do the splitting, e.g. per PDF page. */
82
+ export function commitDocument(segments) {
83
+ if (segments.length === 0)
84
+ throw new Error('redact: a document needs at least one segment');
85
+ return commit(Object.fromEntries(segments.map((s, i) => [`seg/${String(i).padStart(6, '0')}`, s])));
86
+ }
87
+ /** Release a redacted copy: the kept segments with proofs; the rest are provably the committed ones, hidden. */
88
+ export function redactDocument(result, keep) {
89
+ const keys = new Set(keep.map((i) => `seg/${String(i).padStart(6, '0')}`));
90
+ return { envelope: result.envelope, disclosures: result.envelope.keys.filter((k) => keys.has(k)).map((k) => disclose(result, k)) };
91
+ }
92
+ /** Rebuild the redacted view: verified segments in place, `null` where redacted; fails on any bad proof. */
93
+ export function verifyRedactedDocument(doc) {
94
+ const byKey = new Map(doc.disclosures.map((d) => [d.key, d]));
95
+ const bad = doc.disclosures.filter((d) => !verifyDisclosure(d, doc.envelope)).map((d) => d.key);
96
+ return { ok: bad.length === 0, bad, segments: doc.envelope.keys.map((k) => (byKey.has(k) && !bad.includes(k) ? byKey.get(k).value : null)) };
97
+ }
98
+ // ------------------------------------------------------------------------------ //
99
+ // SD-JWT
100
+ // ------------------------------------------------------------------------------ //
101
+ const b64u = (b) => Buffer.from(b).toString('base64url');
102
+ const PKCS8 = Buffer.from('302e020100300506032b657004220420', 'hex');
103
+ const SPKI = Buffer.from('302a300506032b6570032100', 'hex');
104
+ /**
105
+ * Export fields as an SD-JWT (IETF draft format: `<issuer-jwt>~<disclosure>~...~`), signed EdDSA
106
+ * with the issuer's did:key. Every field is selectively disclosable.
107
+ */
108
+ export function sdJwtExport(fields, issuerPrivateKey, opts = {}) {
109
+ const key = createPrivateKey({ key: Buffer.concat([PKCS8, Buffer.from(issuerPrivateKey)]), format: 'der', type: 'pkcs8' });
110
+ const iss = didFromPublicKey(new Uint8Array(createPublicKey(key).export({ format: 'der', type: 'spki' }).subarray(SPKI.length))); // a KeyObject; @types/node omits that overload
111
+ const disclosures = Object.entries(fields).map(([k, v]) => b64u(JSON.stringify([randomBytes(16).toString('base64url'), k, v])));
112
+ const payload = { iss, iat: opts.iat ?? Math.floor(Date.now() / 1000), ...(opts.vct ? { vct: opts.vct } : {}), _sd_alg: 'sha-256', _sd: disclosures.map((d) => createHash('sha256').update(d).digest('base64url')).sort() };
113
+ const signingInput = `${b64u(JSON.stringify({ alg: 'EdDSA', typ: 'vc+sd-jwt' }))}.${b64u(JSON.stringify(payload))}`;
114
+ return `${signingInput}.${b64u(edSign(null, Buffer.from(signingInput), key))}~${disclosures.map((d) => `${d}~`).join('')}`;
115
+ }
116
+ /** Verify an SD-JWT from `sdJwtExport` (issuer signature, every presented disclosure listed) and return the disclosed claims. */
117
+ export function verifySdJwt(token) {
118
+ try {
119
+ const [jwt, ...rest] = token.split('~');
120
+ const [h, p, s] = jwt.split('.');
121
+ const payload = JSON.parse(Buffer.from(p, 'base64url').toString());
122
+ const pub = publicKeyFromDid(payload.iss);
123
+ if (!pub)
124
+ return { ok: false, claims: {}, reason: 'issuer is not a did:key' };
125
+ const key = createPublicKey({ key: Buffer.concat([SPKI, Buffer.from(pub)]), format: 'der', type: 'spki' });
126
+ if (!edVerify(null, Buffer.from(`${h}.${p}`), key, Buffer.from(s, 'base64url')))
127
+ return { ok: false, claims: {}, reason: 'bad issuer signature' };
128
+ const claims = {};
129
+ for (const d of rest.filter(Boolean)) {
130
+ if (!payload._sd.includes(createHash('sha256').update(d).digest('base64url')))
131
+ return { ok: false, claims: {}, reason: 'a disclosure is not in the signed digests' };
132
+ const [, k, v] = JSON.parse(Buffer.from(d, 'base64url').toString());
133
+ claims[k] = v;
134
+ }
135
+ return { ok: true, issuer: payload.iss, claims };
136
+ }
137
+ catch {
138
+ return { ok: false, claims: {}, reason: 'malformed SD-JWT' };
139
+ }
140
+ }
141
+ /** Present only some claims of an SD-JWT: keeps the issuer JWT and the chosen disclosures. */
142
+ export function presentSdJwt(token, keys) {
143
+ const [jwt, ...rest] = token.split('~');
144
+ const keep = rest.filter(Boolean).filter((d) => keys.includes(JSON.parse(Buffer.from(d, 'base64url').toString())[1]));
145
+ return `${jwt}~${keep.map((d) => `${d}~`).join('')}`;
146
+ }
147
+ /** Record who was shown which fields, why, as a receipt (names and root only, never the values). */
148
+ export function logDisclosure(agent, input) {
149
+ return agent.record({ target: 'redact.disclosed', risk: 'medium', payload: { recipient: input.recipient, purpose: input.purpose, root: input.disclosures[0]?.root ?? null, keys: input.disclosures.map((d) => d.key) } });
150
+ }
151
+ /** Wrap disclosures in a grant for one recipient that expires. Signed by the holder. */
152
+ export function grantDisclosure(disclosures, opts, holderPrivateKey) {
153
+ if (Number.isNaN(Date.parse(opts.exp)))
154
+ throw new Error('redact: exp must be an ISO timestamp');
155
+ return signObject({ v: 1, type: 'redact.grant', recipient: opts.recipient, exp: opts.exp, root: disclosures[0]?.root ?? '', disclosures }, holderPrivateKey);
156
+ }
157
+ export function verifyGrant(g, envelope, opts) {
158
+ const reasons = [];
159
+ if (!verifySignedObject(g))
160
+ reasons.push('grant signature invalid');
161
+ if (g.recipient !== opts.recipient)
162
+ reasons.push('grant is for another recipient');
163
+ if ((opts.now ?? new Date().toISOString()) >= g.exp)
164
+ reasons.push('grant expired');
165
+ if (g.disclosures.some((d) => !verifyDisclosure(d, envelope)))
166
+ reasons.push('a disclosure does not verify');
167
+ return { ok: reasons.length === 0, reasons };
168
+ }
169
+ /** Disclosures for a role (e.g. `regulator` sees more than `counterparty`). Unknown roles see nothing. */
170
+ export function auditorView(result, policy, role) {
171
+ return (policy[role] ?? []).filter((k) => result.envelope.keys.includes(k)).map((k) => disclose(result, k));
172
+ }
173
+ /**
174
+ * Context for a language model holding only the fields a role may see, each with its proof,
175
+ * and the names of what was withheld. The model never receives the withheld values.
176
+ */
177
+ export function llmSafeContext(result, policy, role) {
178
+ const disclosures = auditorView(result, policy, role);
179
+ const shown = new Set(disclosures.map((d) => d.key));
180
+ const context = Object.fromEntries(result.envelope.keys.map((k) => [k, shown.has(k) ? result.secrets.fields[k].value : '[withheld]']));
181
+ return { context, text: JSON.stringify(context), proofs: disclosures, withheld: result.envelope.keys.filter((k) => !shown.has(k)) };
182
+ }
183
+ //# sourceMappingURL=advanced.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"advanced.js","sourceRoot":"","sources":["../src/advanced.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -44,4 +44,5 @@ export declare function disclose(result: CommitResult, key: string): Disclosure;
44
44
  * true only if the revealed `(key, value)` is provably one of the committed fields.
45
45
  */
46
46
  export declare function verifyDisclosure(d: Disclosure, envelope: RedactEnvelope): boolean;
47
+ export * from './advanced.js';
47
48
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAwBA,iGAAiG;AACjG,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,OAAO,CAAC;IACb,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,8EAA8E;IAC9E,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,cAAc,CAAC;IACzB,OAAO,EAAE,aAAa,CAAC;CACxB;AAED,yFAAyF;AACzF,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,kBAAkB,CAAC;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,YAAY,CAYpE;AAED,gDAAgD;AAChD,wBAAgB,QAAQ,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,GAAG,UAAU,CAMtE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,cAAc,GAAG,OAAO,CAWjF"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAwBA,iGAAiG;AACjG,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,OAAO,CAAC;IACb,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,8EAA8E;IAC9E,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,cAAc,CAAC;IACzB,OAAO,EAAE,aAAa,CAAC;CACxB;AAED,yFAAyF;AACzF,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,kBAAkB,CAAC;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,YAAY,CAYpE;AAED,gDAAgD;AAChD,wBAAgB,QAAQ,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,GAAG,UAAU,CAMtE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,cAAc,GAAG,OAAO,CAWjF;AACD,cAAc,eAAe,CAAC"}
package/dist/index.js CHANGED
@@ -66,4 +66,5 @@ export function verifyDisclosure(d, envelope) {
66
66
  return false;
67
67
  }
68
68
  }
69
+ export * from './advanced.js';
69
70
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zanii/redact",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Selective disclosure for Zanii receipts - prove an agent acted on specific data without revealing the rest, via salted field commitments and Merkle inclusion proofs.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://ledger.zanii.agency",
@@ -31,7 +31,8 @@
31
31
  "vitest": "^3.0.9"
32
32
  },
33
33
  "dependencies": {
34
- "@zanii/core": "^0.4.0"
34
+ "@zanii/core": "^0.5.4",
35
+ "@zanii/zk": "^0.1.0"
35
36
  },
36
37
  "scripts": {
37
38
  "build": "tsc -p tsconfig.build.json",
@@ -0,0 +1,228 @@
1
+ /**
2
+ * Selective disclosure, further: range proofs (hash-chain, via @zanii/zk), set
3
+ * membership, predicates over disclosed fields, nested JSON commitments, redacted
4
+ * documents with a provably unchanged remainder, SD-JWT export, a disclosure log,
5
+ * expiring grants, role-based auditor views and LLM-safe context.
6
+ */
7
+ import { createHash, createPrivateKey, createPublicKey, randomBytes, sign as edSign, verify as edVerify } from 'node:crypto';
8
+ import { didFromPublicKey, publicKeyFromDid, signObject, verifySignedObject, type RiskLevel, type SignedObject } from '@zanii/core';
9
+ import { proveAtLeast, proveMembership, thresholdChain, verifyAtLeast, verifyMembership, type CommittedSet, type MembershipProof, type ThresholdAnchor, type ThresholdProof, type ThresholdSecret } from '@zanii/zk';
10
+ import { commit, disclose, verifyDisclosure, type CommitResult, type Disclosure, type RedactEnvelope } from './index.js';
11
+
12
+ // ------------------------------------------------------------------------------ //
13
+ // Ranges, sets, predicates
14
+ // ------------------------------------------------------------------------------ //
15
+
16
+ export interface RangeAnchors {
17
+ field: string;
18
+ /** Upper bound of the scale (e.g. 150 for age); proofs of "at most" count down from it. */
19
+ bound: number;
20
+ lo: ThresholdAnchor;
21
+ hi: ThresholdAnchor;
22
+ }
23
+
24
+ /**
25
+ * Issuer side: anchors for a numeric field so the holder can later prove min <= value <= max
26
+ * without revealing it. Commit or sign `anchors` (e.g. as a committed field); give `secret` to the holder.
27
+ */
28
+ export function rangeAnchors(field: string, value: number, bound: number): { anchors: RangeAnchors; secret: { lo: ThresholdSecret; hi: ThresholdSecret } } {
29
+ if (!Number.isInteger(value) || value < 0 || value > bound) throw new Error(`redact: ${field} must be an integer in 0..${bound}`);
30
+ const lo = thresholdChain(value, `${field}/lo`);
31
+ const hi = thresholdChain(bound - value, `${field}/hi`);
32
+ return { anchors: { field, bound, lo: lo.anchor, hi: hi.anchor }, secret: { lo: lo.secret, hi: hi.secret } };
33
+ }
34
+
35
+ export interface RangeProof {
36
+ field: string;
37
+ min: number;
38
+ max: number;
39
+ lo: ThresholdProof;
40
+ hi: ThresholdProof;
41
+ }
42
+
43
+ /** Holder side: prove min <= value <= max. Throws if the value is outside. */
44
+ export function proveRange(anchors: RangeAnchors, secret: { lo: ThresholdSecret; hi: ThresholdSecret }, min: number, max: number): RangeProof {
45
+ return { field: anchors.field, min, max, lo: proveAtLeast(secret.lo, `${anchors.field}/lo`, min), hi: proveAtLeast(secret.hi, `${anchors.field}/hi`, anchors.bound - max) };
46
+ }
47
+
48
+ export function verifyRange(anchors: RangeAnchors, p: RangeProof): boolean {
49
+ return p.field === anchors.field && p.min <= p.max && p.lo.threshold === p.min && p.hi.threshold === anchors.bound - p.max && verifyAtLeast(anchors.lo, p.lo) && verifyAtLeast(anchors.hi, p.hi);
50
+ }
51
+
52
+ /**
53
+ * Show that a committed field's value is in a committed set (an allow-list, the eligible ids),
54
+ * revealing that value but nothing else of the set or the other fields.
55
+ */
56
+ export function proveFieldInSet(result: CommitResult, key: string, set: CommittedSet): { disclosure: Disclosure; membership: MembershipProof } {
57
+ const d = disclose(result, key);
58
+ return { disclosure: d, membership: proveMembership(set, String(d.value)) };
59
+ }
60
+
61
+ export function verifyFieldInSet(p: { disclosure: Disclosure; membership: MembershipProof }, envelope: RedactEnvelope, setRoot: string): boolean {
62
+ return verifyDisclosure(p.disclosure, envelope) && p.membership.item === String(p.disclosure.value) && verifyMembership(setRoot, p.membership);
63
+ }
64
+
65
+ export type Predicate =
66
+ | { all: Predicate[] }
67
+ | { any: Predicate[] }
68
+ | { field: string; op: 'eq' | 'neq' | 'in'; value: unknown }
69
+ | { field: string; op: 'gte' | 'lte'; value: number };
70
+
71
+ /**
72
+ * Evaluate a predicate over verified disclosures (and range proofs, which satisfy gte/lte without
73
+ * revealing the value). Unverifiable or missing fields make their clause false.
74
+ */
75
+ export function evaluatePredicate(expr: Predicate, envelope: RedactEnvelope, evidence: { disclosures?: Disclosure[]; ranges?: Array<{ anchors: RangeAnchors; proof: RangeProof }> }): boolean {
76
+ if ('all' in expr) return expr.all.every((e) => evaluatePredicate(e, envelope, evidence));
77
+ if ('any' in expr) return expr.any.some((e) => evaluatePredicate(e, envelope, evidence));
78
+ if (expr.op === 'gte' || expr.op === 'lte') {
79
+ const viaRange = (evidence.ranges ?? []).some(({ anchors, proof }) => anchors.field === expr.field && verifyRange(anchors, proof) && (expr.op === 'gte' ? proof.min >= expr.value : proof.max <= expr.value));
80
+ if (viaRange) return true;
81
+ }
82
+ const d = (evidence.disclosures ?? []).find((x) => x.key === expr.field && verifyDisclosure(x, envelope));
83
+ if (!d) return false;
84
+ const v = d.value;
85
+ switch (expr.op) {
86
+ case 'eq': return JSON.stringify(v) === JSON.stringify(expr.value);
87
+ case 'neq': return JSON.stringify(v) !== JSON.stringify(expr.value);
88
+ case 'in': return Array.isArray(expr.value) && expr.value.some((x) => JSON.stringify(x) === JSON.stringify(v));
89
+ case 'gte': return typeof v === 'number' && v >= expr.value;
90
+ case 'lte': return typeof v === 'number' && v <= expr.value;
91
+ }
92
+ }
93
+
94
+ // ------------------------------------------------------------------------------ //
95
+ // Nested JSON and documents
96
+ // ------------------------------------------------------------------------------ //
97
+
98
+ const escapePointer = (s: string) => s.replace(/~/g, '~0').replace(/\//g, '~1');
99
+
100
+ /** Flatten JSON to RFC 6901 pointers -> leaf values (empty objects and arrays are kept as leaves). */
101
+ export function flattenJson(value: unknown, prefix = ''): Record<string, unknown> {
102
+ if (value !== null && typeof value === 'object' && Object.keys(value).length > 0) {
103
+ return Object.assign({}, ...Object.entries(value).map(([k, v]) => flattenJson(v, `${prefix}/${escapePointer(k)}`)));
104
+ }
105
+ return { [prefix || '/']: value };
106
+ }
107
+
108
+ /** Commit to every leaf of a JSON document, keyed by its JSON pointer (e.g. `/customer/address/city`). */
109
+ export function nestedCommit(json: Record<string, unknown>): CommitResult {
110
+ return commit(flattenJson(json));
111
+ }
112
+
113
+ /** Commit to a document split into segments (pages, paragraphs, clauses). You do the splitting, e.g. per PDF page. */
114
+ export function commitDocument(segments: string[]): CommitResult {
115
+ if (segments.length === 0) throw new Error('redact: a document needs at least one segment');
116
+ return commit(Object.fromEntries(segments.map((s, i) => [`seg/${String(i).padStart(6, '0')}`, s])));
117
+ }
118
+
119
+ /** Release a redacted copy: the kept segments with proofs; the rest are provably the committed ones, hidden. */
120
+ export function redactDocument(result: CommitResult, keep: number[]) {
121
+ const keys = new Set(keep.map((i) => `seg/${String(i).padStart(6, '0')}`));
122
+ return { envelope: result.envelope, disclosures: result.envelope.keys.filter((k) => keys.has(k)).map((k) => disclose(result, k)) };
123
+ }
124
+
125
+ /** Rebuild the redacted view: verified segments in place, `null` where redacted; fails on any bad proof. */
126
+ export function verifyRedactedDocument(doc: { envelope: RedactEnvelope; disclosures: Disclosure[] }) {
127
+ const byKey = new Map(doc.disclosures.map((d) => [d.key, d]));
128
+ const bad = doc.disclosures.filter((d) => !verifyDisclosure(d, doc.envelope)).map((d) => d.key);
129
+ return { ok: bad.length === 0, bad, segments: doc.envelope.keys.map((k) => (byKey.has(k) && !bad.includes(k) ? (byKey.get(k)!.value as string) : null)) };
130
+ }
131
+
132
+ // ------------------------------------------------------------------------------ //
133
+ // SD-JWT
134
+ // ------------------------------------------------------------------------------ //
135
+
136
+ const b64u = (b: Buffer | string) => Buffer.from(b).toString('base64url');
137
+ const PKCS8 = Buffer.from('302e020100300506032b657004220420', 'hex');
138
+ const SPKI = Buffer.from('302a300506032b6570032100', 'hex');
139
+
140
+ /**
141
+ * Export fields as an SD-JWT (IETF draft format: `<issuer-jwt>~<disclosure>~...~`), signed EdDSA
142
+ * with the issuer's did:key. Every field is selectively disclosable.
143
+ */
144
+ export function sdJwtExport(fields: Record<string, unknown>, issuerPrivateKey: Uint8Array, opts: { iat?: number; vct?: string } = {}): string {
145
+ const key = createPrivateKey({ key: Buffer.concat([PKCS8, Buffer.from(issuerPrivateKey)]), format: 'der', type: 'pkcs8' });
146
+ const iss = didFromPublicKey(new Uint8Array(createPublicKey(key as unknown as string).export({ format: 'der', type: 'spki' }).subarray(SPKI.length))); // a KeyObject; @types/node omits that overload
147
+ const disclosures = Object.entries(fields).map(([k, v]) => b64u(JSON.stringify([randomBytes(16).toString('base64url'), k, v])));
148
+ const payload = { iss, iat: opts.iat ?? Math.floor(Date.now() / 1000), ...(opts.vct ? { vct: opts.vct } : {}), _sd_alg: 'sha-256', _sd: disclosures.map((d) => createHash('sha256').update(d).digest('base64url')).sort() };
149
+ const signingInput = `${b64u(JSON.stringify({ alg: 'EdDSA', typ: 'vc+sd-jwt' }))}.${b64u(JSON.stringify(payload))}`;
150
+ return `${signingInput}.${b64u(edSign(null, Buffer.from(signingInput), key))}~${disclosures.map((d) => `${d}~`).join('')}`;
151
+ }
152
+
153
+ /** Verify an SD-JWT from `sdJwtExport` (issuer signature, every presented disclosure listed) and return the disclosed claims. */
154
+ export function verifySdJwt(token: string): { ok: boolean; issuer?: string; claims: Record<string, unknown>; reason?: string } {
155
+ try {
156
+ const [jwt, ...rest] = token.split('~');
157
+ const [h, p, s] = jwt!.split('.');
158
+ const payload = JSON.parse(Buffer.from(p!, 'base64url').toString()) as { iss: string; _sd: string[] };
159
+ const pub = publicKeyFromDid(payload.iss);
160
+ if (!pub) return { ok: false, claims: {}, reason: 'issuer is not a did:key' };
161
+ const key = createPublicKey({ key: Buffer.concat([SPKI, Buffer.from(pub)]), format: 'der', type: 'spki' });
162
+ if (!edVerify(null, Buffer.from(`${h}.${p}`), key, Buffer.from(s!, 'base64url'))) return { ok: false, claims: {}, reason: 'bad issuer signature' };
163
+ const claims: Record<string, unknown> = {};
164
+ for (const d of rest.filter(Boolean)) {
165
+ if (!payload._sd.includes(createHash('sha256').update(d).digest('base64url'))) return { ok: false, claims: {}, reason: 'a disclosure is not in the signed digests' };
166
+ const [, k, v] = JSON.parse(Buffer.from(d, 'base64url').toString()) as [string, string, unknown];
167
+ claims[k] = v;
168
+ }
169
+ return { ok: true, issuer: payload.iss, claims };
170
+ } catch {
171
+ return { ok: false, claims: {}, reason: 'malformed SD-JWT' };
172
+ }
173
+ }
174
+
175
+ /** Present only some claims of an SD-JWT: keeps the issuer JWT and the chosen disclosures. */
176
+ export function presentSdJwt(token: string, keys: string[]): string {
177
+ const [jwt, ...rest] = token.split('~');
178
+ const keep = rest.filter(Boolean).filter((d) => keys.includes((JSON.parse(Buffer.from(d, 'base64url').toString()) as unknown[])[1] as string));
179
+ return `${jwt}~${keep.map((d) => `${d}~`).join('')}`;
180
+ }
181
+
182
+ // ------------------------------------------------------------------------------ //
183
+ // Logs, grants, views
184
+ // ------------------------------------------------------------------------------ //
185
+
186
+ interface Recorder {
187
+ record(fields: { target: string; payload: unknown; risk?: RiskLevel }): Promise<unknown>;
188
+ }
189
+
190
+ /** Record who was shown which fields, why, as a receipt (names and root only, never the values). */
191
+ export function logDisclosure(agent: Recorder, input: { recipient: string; purpose: string; disclosures: Disclosure[] }) {
192
+ return agent.record({ target: 'redact.disclosed', risk: 'medium', payload: { recipient: input.recipient, purpose: input.purpose, root: input.disclosures[0]?.root ?? null, keys: input.disclosures.map((d) => d.key) } });
193
+ }
194
+
195
+ export type DisclosureGrant = SignedObject<{ v: 1; type: 'redact.grant'; recipient: string; exp: string; root: string; disclosures: Disclosure[] }>;
196
+
197
+ /** Wrap disclosures in a grant for one recipient that expires. Signed by the holder. */
198
+ export function grantDisclosure(disclosures: Disclosure[], opts: { recipient: string; exp: string }, holderPrivateKey: Uint8Array): DisclosureGrant {
199
+ if (Number.isNaN(Date.parse(opts.exp))) throw new Error('redact: exp must be an ISO timestamp');
200
+ return signObject({ v: 1 as const, type: 'redact.grant' as const, recipient: opts.recipient, exp: opts.exp, root: disclosures[0]?.root ?? '', disclosures }, holderPrivateKey);
201
+ }
202
+
203
+ export function verifyGrant(g: DisclosureGrant, envelope: RedactEnvelope, opts: { recipient: string; now?: string }) {
204
+ const reasons: string[] = [];
205
+ if (!verifySignedObject(g)) reasons.push('grant signature invalid');
206
+ if (g.recipient !== opts.recipient) reasons.push('grant is for another recipient');
207
+ if ((opts.now ?? new Date().toISOString()) >= g.exp) reasons.push('grant expired');
208
+ if (g.disclosures.some((d) => !verifyDisclosure(d, envelope))) reasons.push('a disclosure does not verify');
209
+ return { ok: reasons.length === 0, reasons };
210
+ }
211
+
212
+ export type RevealPolicy = Record<string, string[]>;
213
+
214
+ /** Disclosures for a role (e.g. `regulator` sees more than `counterparty`). Unknown roles see nothing. */
215
+ export function auditorView(result: CommitResult, policy: RevealPolicy, role: string): Disclosure[] {
216
+ return (policy[role] ?? []).filter((k) => result.envelope.keys.includes(k)).map((k) => disclose(result, k));
217
+ }
218
+
219
+ /**
220
+ * Context for a language model holding only the fields a role may see, each with its proof,
221
+ * and the names of what was withheld. The model never receives the withheld values.
222
+ */
223
+ export function llmSafeContext(result: CommitResult, policy: RevealPolicy, role: string) {
224
+ const disclosures = auditorView(result, policy, role);
225
+ const shown = new Set(disclosures.map((d) => d.key));
226
+ const context = Object.fromEntries(result.envelope.keys.map((k) => [k, shown.has(k) ? result.secrets.fields[k]!.value : '[withheld]']));
227
+ return { context, text: JSON.stringify(context), proofs: disclosures, withheld: result.envelope.keys.filter((k) => !shown.has(k)) };
228
+ }
package/src/index.ts CHANGED
@@ -99,3 +99,4 @@ export function verifyDisclosure(d: Disclosure, envelope: RedactEnvelope): boole
99
99
  return false;
100
100
  }
101
101
  }
102
+ export * from './advanced.js';