@zanii/train 0.1.0 → 0.2.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA4BA,yFAAyF;AACzF,UAAU,IAAI;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,gBAAgB;IAC/B,CAAC,EAAE,CAAC,CAAC;IACL,IAAI,EAAE,mBAAmB,CAAC;IAC1B,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB;AAmBD,+FAA+F;AAC/F,wBAAgB,aAAa,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,gBAAgB,CAa5G;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAExD;AAED,0FAA0F;AAC1F,wBAAgB,eAAe,CAAC,CAAC,EAAE,gBAAgB,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAEzG;AAQD,MAAM,WAAW,YAAY;IAC3B,CAAC,EAAE,CAAC,CAAC;IACL,IAAI,EAAE,kBAAkB,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,6BAA6B;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,wDAAwD;IACxD,GAAG,EAAE,IAAI,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,CAAC,EAAE,CAAC,CAAC;IACL,IAAI,EAAE,qBAAqB,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,yFAAyF;AACzF,wBAAgB,YAAY,CAAC,CAAC,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,YAAY,CAQ3F;AAED,iFAAiF;AACjF,wBAAgB,eAAe,CAAC,CAAC,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,eAAe,CAMjG;AAED,6FAA6F;AAC7F,wBAAgB,aAAa,CAAC,KAAK,EAAE,YAAY,GAAG,SAAS,EAAE,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAO3F;AAED,oDAAoD;AACpD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,eAAe,GAAG,SAAS,EAAE,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAKjG"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA2BA,yFAAyF;AACzF,UAAU,IAAI;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,gBAAgB;IAC/B,CAAC,EAAE,CAAC,CAAC;IACL,IAAI,EAAE,mBAAmB,CAAC;IAC1B,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB;AA8BD,+FAA+F;AAC/F,wBAAgB,aAAa,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,gBAAgB,CAa5G;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAExD;AAED,0FAA0F;AAC1F,wBAAgB,eAAe,CAAC,CAAC,EAAE,gBAAgB,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAEzG;AAQD,MAAM,WAAW,YAAY;IAC3B,CAAC,EAAE,CAAC,CAAC;IACL,IAAI,EAAE,kBAAkB,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,6BAA6B;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,wDAAwD;IACxD,GAAG,EAAE,IAAI,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,CAAC,EAAE,CAAC,CAAC;IACL,IAAI,EAAE,qBAAqB,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,yFAAyF;AACzF,wBAAgB,YAAY,CAAC,CAAC,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,YAAY,CAS3F;AAED,iFAAiF;AACjF,wBAAgB,eAAe,CAAC,CAAC,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,eAAe,CAMjG;AAED,6FAA6F;AAC7F,wBAAgB,aAAa,CAAC,KAAK,EAAE,YAAY,GAAG,SAAS,EAAE,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAY3F;AAED,oDAAoD;AACpD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,eAAe,GAAG,SAAS,EAAE,CAAC,EAAE,gBAAgB,GAAG,OAAO,CASjG"}
package/dist/index.js CHANGED
@@ -23,13 +23,25 @@
23
23
  * The manifest commits refs (`hmac:v1:…` / `sha256:…`), never content.
24
24
  */
25
25
  import { bytesToHex, hexToBytes } from '@noble/hashes/utils';
26
- import { sha256 } from '@noble/hashes/sha256';
27
26
  import { canonicalBytes, inclusionProof, jcsHash, leafHash, merkleRoot, verifyInclusion } from '@zanii/core';
27
+ // Refs must sort identically in JS (UTF-16 code units) and Python (code points), and sit
28
+ // strictly between the sentinels '' and '￿' (U+FFFF) — so: non-empty, BMP-only.
29
+ function assertRef(r) {
30
+ if (typeof r !== 'string' || r.length === 0)
31
+ throw new Error('refs must be non-empty strings');
32
+ for (const c of r) {
33
+ if (c.codePointAt(0) >= 0xffff)
34
+ throw new Error(`ref contains a code point >= U+FFFF (breaks the sorted-Merkle sentinel): ${JSON.stringify(r)}`);
35
+ }
36
+ }
28
37
  /** Sorted, de-duplicated member refs → the adjacency leaves that get Merkle-committed. */
29
38
  function pairsOf(refs) {
39
+ for (const r of refs)
40
+ assertRef(r);
30
41
  const sorted = [...new Set(refs)].sort();
42
+ // the empty set is one full sentinel-to-sentinel gap — absence is trivially provable
31
43
  if (sorted.length === 0)
32
- return [];
44
+ return [{ lo: '', hi: '￿' }];
33
45
  const pairs = [];
34
46
  // sentinel-bounded gaps so the smallest/largest members are covered too
35
47
  pairs.push({ lo: '', hi: sorted[0] });
@@ -48,7 +60,7 @@ export function buildManifest(fields) {
48
60
  if (Number.isNaN(Date.parse(fields.createdAt)))
49
61
  throw new Error('createdAt must be an ISO timestamp');
50
62
  const pairs = pairsOf(fields.refs);
51
- const root = pairs.length ? bytesToHex(merkleRoot(pairs.map(pairLeaf))) : bytesToHex(sha256(new Uint8Array(0)));
63
+ const root = bytesToHex(merkleRoot(pairs.map(pairLeaf)));
52
64
  return {
53
65
  v: 1,
54
66
  type: 'training.manifest',
@@ -71,6 +83,7 @@ const inclusionPath = (index, leaves) => inclusionProof(index, leaves).map(bytes
71
83
  const verifyPath = (leaf, index, size, path, root) => verifyInclusion(leaf, index, size, path.map(hexToBytes), root);
72
84
  /** Build a proof that `ref` is ABSENT from the training set. Throws if it is present. */
73
85
  export function proveAbsence(m, refs, ref) {
86
+ assertRef(ref);
74
87
  const sorted = [...new Set(refs)].sort();
75
88
  if (sorted.includes(ref))
76
89
  throw new Error(`ref is PRESENT — cannot prove absence`);
@@ -92,22 +105,33 @@ export function proveMembership(m, refs, ref) {
92
105
  }
93
106
  /** Verify a subject-absence proof against a manifest — offline, no trust in the operator. */
94
107
  export function verifyAbsence(proof, m) {
95
- const p = proof ?? {};
96
- if (p.v !== 1 || p.type !== 'training.absence' || p.run_id !== m.run_id)
97
- return false;
98
- if (!(p.gap.lo < p.ref && p.ref < p.gap.hi))
99
- return false; // the gap must actually cover the ref
100
- if (p.gap.lo === p.gap.hi)
101
- return false; // a member leaf is not a gap
102
- const root = hexToBytes(m.root.replace('sha256:', ''));
103
- return verifyPath(pairLeaf(p.gap), p.index, p.size, p.path, root);
108
+ try {
109
+ const p = proof ?? {};
110
+ if (p.v !== 1 || p.type !== 'training.absence' || p.run_id !== m.run_id)
111
+ return false;
112
+ const gap = p.gap ?? {};
113
+ if (!(gap.lo < p.ref && p.ref < gap.hi))
114
+ return false; // the gap must actually cover the ref
115
+ if (gap.lo === gap.hi)
116
+ return false; // a member leaf is not a gap
117
+ const root = hexToBytes(m.root.replace('sha256:', ''));
118
+ return verifyPath(pairLeaf(gap), p.index, p.size, p.path, root);
119
+ }
120
+ catch {
121
+ return false; // malformed proof (bad hex, missing fields) is a failed verification, not a crash
122
+ }
104
123
  }
105
124
  /** Verify a membership proof against a manifest. */
106
125
  export function verifyMembership(proof, m) {
107
- const p = proof ?? {};
108
- if (p.v !== 1 || p.type !== 'training.membership' || p.run_id !== m.run_id)
126
+ try {
127
+ const p = proof ?? {};
128
+ if (p.v !== 1 || p.type !== 'training.membership' || p.run_id !== m.run_id)
129
+ return false;
130
+ const root = hexToBytes(m.root.replace('sha256:', ''));
131
+ return verifyPath(pairLeaf({ lo: p.ref, hi: p.ref }), p.index, p.size, p.path, root);
132
+ }
133
+ catch {
109
134
  return false;
110
- const root = hexToBytes(m.root.replace('sha256:', ''));
111
- return verifyPath(pairLeaf({ lo: p.ref, hi: p.ref }), p.index, p.size, p.path, root);
135
+ }
112
136
  }
113
137
  //# 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/train",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "Training-data provenance: hash a training set into a sorted-Merkle manifest, then PROVE a named subject's data was absent from a real training run - a non-membership proof anyone can check offline. 'It was never used to train a model' becomes a yes, not a promise. Proves what was recorded went in; cannot prove an off-manifest copy didn't (state the enclave boundary).",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://ledger.zanii.agency",
@@ -32,7 +32,7 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "@noble/hashes": "^1.7.1",
35
- "@zanii/core": "0.4.0"
35
+ "@zanii/core": "^0.5.2"
36
36
  },
37
37
  "scripts": {
38
38
  "build": "tsc -p tsconfig.build.json",
package/src/index.ts CHANGED
@@ -23,7 +23,6 @@
23
23
  * The manifest commits refs (`hmac:v1:…` / `sha256:…`), never content.
24
24
  */
25
25
  import { bytesToHex, hexToBytes } from '@noble/hashes/utils';
26
- import { sha256 } from '@noble/hashes/sha256';
27
26
  import { canonicalBytes, inclusionProof, jcsHash, leafHash, merkleRoot, verifyInclusion } from '@zanii/core';
28
27
 
29
28
  /** One committed gap between two adjacent sorted refs. A member leaf has `lo === hi`. */
@@ -44,10 +43,21 @@ export interface TrainingManifest {
44
43
  created_at: string;
45
44
  }
46
45
 
46
+ // Refs must sort identically in JS (UTF-16 code units) and Python (code points), and sit
47
+ // strictly between the sentinels '' and '￿' (U+FFFF) — so: non-empty, BMP-only.
48
+ function assertRef(r: string): void {
49
+ if (typeof r !== 'string' || r.length === 0) throw new Error('refs must be non-empty strings');
50
+ for (const c of r) {
51
+ if (c.codePointAt(0)! >= 0xffff) throw new Error(`ref contains a code point >= U+FFFF (breaks the sorted-Merkle sentinel): ${JSON.stringify(r)}`);
52
+ }
53
+ }
54
+
47
55
  /** Sorted, de-duplicated member refs → the adjacency leaves that get Merkle-committed. */
48
56
  function pairsOf(refs: string[]): Pair[] {
57
+ for (const r of refs) assertRef(r);
49
58
  const sorted = [...new Set(refs)].sort();
50
- if (sorted.length === 0) return [];
59
+ // the empty set is one full sentinel-to-sentinel gap — absence is trivially provable
60
+ if (sorted.length === 0) return [{ lo: '', hi: '￿' }];
51
61
  const pairs: Pair[] = [];
52
62
  // sentinel-bounded gaps so the smallest/largest members are covered too
53
63
  pairs.push({ lo: '', hi: sorted[0]! });
@@ -66,7 +76,7 @@ export function buildManifest(fields: { runId: string; refs: string[]; createdAt
66
76
  if (!fields.runId) throw new Error('runId is required');
67
77
  if (Number.isNaN(Date.parse(fields.createdAt))) throw new Error('createdAt must be an ISO timestamp');
68
78
  const pairs = pairsOf(fields.refs);
69
- const root = pairs.length ? bytesToHex(merkleRoot(pairs.map(pairLeaf))) : bytesToHex(sha256(new Uint8Array(0)));
79
+ const root = bytesToHex(merkleRoot(pairs.map(pairLeaf)));
70
80
  return {
71
81
  v: 1,
72
82
  type: 'training.manifest',
@@ -117,6 +127,7 @@ export interface MembershipProof {
117
127
 
118
128
  /** Build a proof that `ref` is ABSENT from the training set. Throws if it is present. */
119
129
  export function proveAbsence(m: TrainingManifest, refs: string[], ref: string): AbsenceProof {
130
+ assertRef(ref);
120
131
  const sorted = [...new Set(refs)].sort();
121
132
  if (sorted.includes(ref)) throw new Error(`ref is PRESENT — cannot prove absence`);
122
133
  const pairs = pairsOf(refs);
@@ -137,18 +148,27 @@ export function proveMembership(m: TrainingManifest, refs: string[], ref: string
137
148
 
138
149
  /** Verify a subject-absence proof against a manifest — offline, no trust in the operator. */
139
150
  export function verifyAbsence(proof: AbsenceProof | undefined, m: TrainingManifest): boolean {
140
- const p = proof ?? ({} as AbsenceProof);
141
- if (p.v !== 1 || p.type !== 'training.absence' || p.run_id !== m.run_id) return false;
142
- if (!(p.gap.lo < p.ref && p.ref < p.gap.hi)) return false; // the gap must actually cover the ref
143
- if (p.gap.lo === p.gap.hi) return false; // a member leaf is not a gap
144
- const root = hexToBytes(m.root.replace('sha256:', ''));
145
- return verifyPath(pairLeaf(p.gap), p.index, p.size, p.path, root);
151
+ try {
152
+ const p = proof ?? ({} as AbsenceProof);
153
+ if (p.v !== 1 || p.type !== 'training.absence' || p.run_id !== m.run_id) return false;
154
+ const gap = p.gap ?? ({} as Pair);
155
+ if (!(gap.lo < p.ref && p.ref < gap.hi)) return false; // the gap must actually cover the ref
156
+ if (gap.lo === gap.hi) return false; // a member leaf is not a gap
157
+ const root = hexToBytes(m.root.replace('sha256:', ''));
158
+ return verifyPath(pairLeaf(gap), p.index, p.size, p.path, root);
159
+ } catch {
160
+ return false; // malformed proof (bad hex, missing fields) is a failed verification, not a crash
161
+ }
146
162
  }
147
163
 
148
164
  /** Verify a membership proof against a manifest. */
149
165
  export function verifyMembership(proof: MembershipProof | undefined, m: TrainingManifest): boolean {
150
- const p = proof ?? ({} as MembershipProof);
151
- if (p.v !== 1 || p.type !== 'training.membership' || p.run_id !== m.run_id) return false;
152
- const root = hexToBytes(m.root.replace('sha256:', ''));
153
- return verifyPath(pairLeaf({ lo: p.ref, hi: p.ref }), p.index, p.size, p.path, root);
166
+ try {
167
+ const p = proof ?? ({} as MembershipProof);
168
+ if (p.v !== 1 || p.type !== 'training.membership' || p.run_id !== m.run_id) return false;
169
+ const root = hexToBytes(m.root.replace('sha256:', ''));
170
+ return verifyPath(pairLeaf({ lo: p.ref, hi: p.ref }), p.index, p.size, p.path, root);
171
+ } catch {
172
+ return false;
173
+ }
154
174
  }