@fluxpointstudios/orynq-sdk-midnight-prover 0.1.0

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.
Files changed (82) hide show
  1. package/LICENSE +21 -0
  2. package/dist/index.d.ts +78 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +89 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/linking/cardano-anchor-link.d.ts +250 -0
  7. package/dist/linking/cardano-anchor-link.d.ts.map +1 -0
  8. package/dist/linking/cardano-anchor-link.js +447 -0
  9. package/dist/linking/cardano-anchor-link.js.map +1 -0
  10. package/dist/linking/index.d.ts +33 -0
  11. package/dist/linking/index.d.ts.map +1 -0
  12. package/dist/linking/index.js +31 -0
  13. package/dist/linking/index.js.map +1 -0
  14. package/dist/linking/proof-publication.d.ts +217 -0
  15. package/dist/linking/proof-publication.d.ts.map +1 -0
  16. package/dist/linking/proof-publication.js +385 -0
  17. package/dist/linking/proof-publication.js.map +1 -0
  18. package/dist/midnight/index.d.ts +30 -0
  19. package/dist/midnight/index.d.ts.map +1 -0
  20. package/dist/midnight/index.js +27 -0
  21. package/dist/midnight/index.js.map +1 -0
  22. package/dist/midnight/proof-server-client.d.ts +236 -0
  23. package/dist/midnight/proof-server-client.d.ts.map +1 -0
  24. package/dist/midnight/proof-server-client.js +422 -0
  25. package/dist/midnight/proof-server-client.js.map +1 -0
  26. package/dist/midnight/public-inputs.d.ts +134 -0
  27. package/dist/midnight/public-inputs.d.ts.map +1 -0
  28. package/dist/midnight/public-inputs.js +338 -0
  29. package/dist/midnight/public-inputs.js.map +1 -0
  30. package/dist/midnight/witness-builder.d.ts +119 -0
  31. package/dist/midnight/witness-builder.d.ts.map +1 -0
  32. package/dist/midnight/witness-builder.js +238 -0
  33. package/dist/midnight/witness-builder.js.map +1 -0
  34. package/dist/proofs/hash-chain-proof.d.ts +171 -0
  35. package/dist/proofs/hash-chain-proof.d.ts.map +1 -0
  36. package/dist/proofs/hash-chain-proof.js +437 -0
  37. package/dist/proofs/hash-chain-proof.js.map +1 -0
  38. package/dist/proofs/index.d.ts +35 -0
  39. package/dist/proofs/index.d.ts.map +1 -0
  40. package/dist/proofs/index.js +34 -0
  41. package/dist/proofs/index.js.map +1 -0
  42. package/dist/proofs/policy-compliance-proof.d.ts +165 -0
  43. package/dist/proofs/policy-compliance-proof.d.ts.map +1 -0
  44. package/dist/proofs/policy-compliance-proof.js +514 -0
  45. package/dist/proofs/policy-compliance-proof.js.map +1 -0
  46. package/dist/proofs/selective-disclosure.d.ts +213 -0
  47. package/dist/proofs/selective-disclosure.d.ts.map +1 -0
  48. package/dist/proofs/selective-disclosure.js +629 -0
  49. package/dist/proofs/selective-disclosure.js.map +1 -0
  50. package/dist/prover-interface.d.ts +288 -0
  51. package/dist/prover-interface.d.ts.map +1 -0
  52. package/dist/prover-interface.js +114 -0
  53. package/dist/prover-interface.js.map +1 -0
  54. package/dist/prover.d.ts +163 -0
  55. package/dist/prover.d.ts.map +1 -0
  56. package/dist/prover.js +417 -0
  57. package/dist/prover.js.map +1 -0
  58. package/dist/types.d.ts +410 -0
  59. package/dist/types.d.ts.map +1 -0
  60. package/dist/types.js +128 -0
  61. package/dist/types.js.map +1 -0
  62. package/package.json +59 -0
  63. package/src/__tests__/hash-chain-proof.test.ts +709 -0
  64. package/src/__tests__/midnight-prover.test.ts +716 -0
  65. package/src/__tests__/policy-compliance.test.ts +567 -0
  66. package/src/__tests__/proof-publication.test.ts +644 -0
  67. package/src/__tests__/selective-disclosure.test.ts +921 -0
  68. package/src/index.ts +260 -0
  69. package/src/linking/cardano-anchor-link.ts +682 -0
  70. package/src/linking/index.ts +58 -0
  71. package/src/linking/proof-publication.ts +557 -0
  72. package/src/midnight/index.ts +73 -0
  73. package/src/midnight/proof-server-client.ts +595 -0
  74. package/src/midnight/public-inputs.ts +590 -0
  75. package/src/midnight/witness-builder.ts +341 -0
  76. package/src/proofs/hash-chain-proof.ts +610 -0
  77. package/src/proofs/index.ts +77 -0
  78. package/src/proofs/policy-compliance-proof.ts +717 -0
  79. package/src/proofs/selective-disclosure.ts +839 -0
  80. package/src/prover-interface.ts +410 -0
  81. package/src/prover.ts +537 -0
  82. package/src/types.ts +551 -0
@@ -0,0 +1,165 @@
1
+ /**
2
+ * @fileoverview Policy compliance proof generation and verification.
3
+ *
4
+ * Location: packages/midnight-prover/src/proofs/policy-compliance-proof.ts
5
+ *
6
+ * Summary:
7
+ * This module implements the PolicyComplianceProver class which generates ZK proofs
8
+ * demonstrating that content complies with a specified policy without revealing the
9
+ * actual content. The prover evaluates policy rules (blocklist, allowlist, regex,
10
+ * classifier) against content hashes and produces a proof of compliance.
11
+ *
12
+ * Usage:
13
+ * - Used by the MidnightProver to generate policy compliance proofs
14
+ * - Integrates with the types defined in ../types.ts
15
+ * - Binds proofs to Cardano anchor transactions for cross-chain verification
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * import { PolicyComplianceProver } from './policy-compliance-proof.js';
20
+ *
21
+ * const prover = new PolicyComplianceProver();
22
+ *
23
+ * const proof = await prover.generateProof({
24
+ * promptHash: 'abc123...',
25
+ * outputHash: 'def456...',
26
+ * policy: { id: 'policy-1', version: '1.0.0', rules: [...] },
27
+ * cardanoAnchorTxHash: 'txhash...',
28
+ * });
29
+ *
30
+ * const isValid = await prover.verifyProof(proof);
31
+ * ```
32
+ */
33
+ import type { PolicyInput, PolicyProof, ContentPolicy, PolicyRule } from "../types.js";
34
+ /**
35
+ * Result of evaluating a single policy rule.
36
+ */
37
+ export interface RuleEvaluationResult {
38
+ rule: PolicyRule;
39
+ passed: boolean;
40
+ message: string;
41
+ }
42
+ /**
43
+ * Result of evaluating all policy rules.
44
+ */
45
+ export interface PolicyEvaluationResult {
46
+ compliant: boolean;
47
+ ruleResults: RuleEvaluationResult[];
48
+ evaluationTimeMs: number;
49
+ }
50
+ /**
51
+ * Options for the PolicyComplianceProver.
52
+ */
53
+ export interface PolicyComplianceProverOptions {
54
+ /**
55
+ * Enable debug logging.
56
+ */
57
+ debug?: boolean;
58
+ /**
59
+ * Custom rule evaluators for extending policy rule types.
60
+ */
61
+ customEvaluators?: Map<string, RuleEvaluator>;
62
+ }
63
+ /**
64
+ * Function type for evaluating a policy rule.
65
+ */
66
+ export type RuleEvaluator = (rule: PolicyRule, promptHash: string, outputHash: string) => Promise<RuleEvaluationResult>;
67
+ /**
68
+ * PolicyComplianceProver generates and verifies ZK proofs of policy compliance.
69
+ *
70
+ * This prover evaluates content against policy rules and produces a proof
71
+ * that the content complies (or not) without revealing the actual content.
72
+ * Only content hashes and policy identifiers are exposed in public inputs.
73
+ *
74
+ * Supported rule types:
75
+ * - blocklist: Content must not match blocked patterns
76
+ * - allowlist: Content must match at least one allowed pattern
77
+ * - regex: Content must (not) match a regex pattern
78
+ * - classifier: Content must pass ML classification threshold
79
+ *
80
+ * @example
81
+ * ```typescript
82
+ * const prover = new PolicyComplianceProver();
83
+ * const proof = await prover.generateProof(input);
84
+ * console.log(proof.publicInputs.compliant); // true or false
85
+ * ```
86
+ */
87
+ export declare class PolicyComplianceProver {
88
+ private readonly debug;
89
+ private readonly evaluators;
90
+ /**
91
+ * Create a new PolicyComplianceProver instance.
92
+ *
93
+ * @param options - Configuration options
94
+ */
95
+ constructor(options?: PolicyComplianceProverOptions);
96
+ /**
97
+ * Generate a policy compliance proof.
98
+ *
99
+ * This method evaluates the content against all policy rules and generates
100
+ * a ZK proof of the compliance result. The proof binds to the Cardano
101
+ * anchor transaction for cross-chain verification.
102
+ *
103
+ * @param input - Policy compliance input
104
+ * @returns Promise resolving to the policy proof
105
+ * @throws MidnightProverException on validation or generation failure
106
+ */
107
+ generateProof(input: PolicyInput): Promise<PolicyProof>;
108
+ /**
109
+ * Verify a policy compliance proof.
110
+ *
111
+ * This method verifies the cryptographic validity of the proof and
112
+ * checks that public inputs are consistent.
113
+ *
114
+ * @param proof - The policy proof to verify
115
+ * @returns Promise resolving to true if valid
116
+ */
117
+ verifyProof(proof: PolicyProof): Promise<boolean>;
118
+ /**
119
+ * Evaluate all policy rules against content.
120
+ *
121
+ * @param policy - The policy to evaluate
122
+ * @param promptHash - Hash of prompt content
123
+ * @param outputHash - Hash of output content
124
+ * @returns Evaluation result with rule-by-rule breakdown
125
+ */
126
+ evaluatePolicy(policy: ContentPolicy, promptHash: string, outputHash: string): Promise<PolicyEvaluationResult>;
127
+ /**
128
+ * Register a custom rule evaluator.
129
+ *
130
+ * @param type - Rule type identifier
131
+ * @param evaluator - Evaluation function
132
+ */
133
+ registerEvaluator(type: string, evaluator: RuleEvaluator): void;
134
+ /**
135
+ * Validate policy input.
136
+ */
137
+ private validateInput;
138
+ /**
139
+ * Generate mock proof bytes.
140
+ * In a real implementation, this would call the Midnight proof server.
141
+ */
142
+ private generateProofBytes;
143
+ /**
144
+ * Verify mock proof bytes.
145
+ * In a real implementation, this would cryptographically verify the proof
146
+ * against the public inputs using the ZK verifier.
147
+ */
148
+ private verifyProofBytes;
149
+ /**
150
+ * Generate proof ID from public inputs.
151
+ */
152
+ private generateProofId;
153
+ /**
154
+ * Convert hex string to bytes.
155
+ */
156
+ private hexToBytes;
157
+ }
158
+ /**
159
+ * Create a new PolicyComplianceProver instance.
160
+ *
161
+ * @param options - Configuration options
162
+ * @returns New prover instance
163
+ */
164
+ export declare function createPolicyComplianceProver(options?: PolicyComplianceProverOptions): PolicyComplianceProver;
165
+ //# sourceMappingURL=policy-compliance-proof.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy-compliance-proof.d.ts","sourceRoot":"","sources":["../../src/proofs/policy-compliance-proof.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAOH,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EAEX,aAAa,EACb,UAAU,EACX,MAAM,aAAa,CAAC;AAWrB;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,oBAAoB,EAAE,CAAC;IACpC,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,6BAA6B;IAC5C;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB;;OAEG;IACH,gBAAgB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;CAC/C;AAED;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,CAC1B,IAAI,EAAE,UAAU,EAChB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,KACf,OAAO,CAAC,oBAAoB,CAAC,CAAC;AA0NnC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAU;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA6B;IAExD;;;;OAIG;gBACS,OAAO,GAAE,6BAAkC;IAmBvD;;;;;;;;;;OAUG;IACG,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IAyD7D;;;;;;;;OAQG;IACG,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;IAgDvD;;;;;;;OAOG;IACG,cAAc,CAClB,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,sBAAsB,CAAC;IAiClC;;;;;OAKG;IACH,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,GAAG,IAAI;IAQ/D;;OAEG;IACH,OAAO,CAAC,aAAa;IA4CrB;;;OAGG;YACW,kBAAkB;IAkDhC;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IA2BxB;;OAEG;YACW,eAAe;IAS7B;;OAEG;IACH,OAAO,CAAC,UAAU;CAOnB;AAMD;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,CAAC,EAAE,6BAA6B,GACtC,sBAAsB,CAExB"}
@@ -0,0 +1,514 @@
1
+ /**
2
+ * @fileoverview Policy compliance proof generation and verification.
3
+ *
4
+ * Location: packages/midnight-prover/src/proofs/policy-compliance-proof.ts
5
+ *
6
+ * Summary:
7
+ * This module implements the PolicyComplianceProver class which generates ZK proofs
8
+ * demonstrating that content complies with a specified policy without revealing the
9
+ * actual content. The prover evaluates policy rules (blocklist, allowlist, regex,
10
+ * classifier) against content hashes and produces a proof of compliance.
11
+ *
12
+ * Usage:
13
+ * - Used by the MidnightProver to generate policy compliance proofs
14
+ * - Integrates with the types defined in ../types.ts
15
+ * - Binds proofs to Cardano anchor transactions for cross-chain verification
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * import { PolicyComplianceProver } from './policy-compliance-proof.js';
20
+ *
21
+ * const prover = new PolicyComplianceProver();
22
+ *
23
+ * const proof = await prover.generateProof({
24
+ * promptHash: 'abc123...',
25
+ * outputHash: 'def456...',
26
+ * policy: { id: 'policy-1', version: '1.0.0', rules: [...] },
27
+ * cardanoAnchorTxHash: 'txhash...',
28
+ * });
29
+ *
30
+ * const isValid = await prover.verifyProof(proof);
31
+ * ```
32
+ */
33
+ import { sha256StringHex, canonicalize, } from "@fluxpointstudios/orynq-sdk-core/utils";
34
+ import { MidnightProverError, MidnightProverException, } from "../types.js";
35
+ // =============================================================================
36
+ // DOMAIN PREFIXES
37
+ // =============================================================================
38
+ /**
39
+ * Domain separation prefixes for policy compliance proofs.
40
+ */
41
+ const POLICY_DOMAIN_PREFIXES = {
42
+ proof: "poi-prover:policy:v1|",
43
+ witness: "poi-prover:policy-witness:v1|",
44
+ publicInput: "poi-prover:policy-input:v1|",
45
+ };
46
+ // =============================================================================
47
+ // DEFAULT RULE EVALUATORS
48
+ // =============================================================================
49
+ /**
50
+ * Default evaluator for blocklist rules.
51
+ * In ZK context, this simulates checking content hashes against a blocklist.
52
+ *
53
+ * @param rule - The blocklist rule to evaluate
54
+ * @param promptHash - Hash of the prompt content
55
+ * @param outputHash - Hash of the output content
56
+ * @returns Evaluation result
57
+ */
58
+ async function evaluateBlocklistRule(rule, promptHash, outputHash) {
59
+ // In a real ZK implementation, this would use a Bloom filter or
60
+ // commitment scheme to check against the blocklist without revealing items.
61
+ // For mock purposes, we simulate by checking if hashes match blocklist patterns.
62
+ const blockedHashes = rule.params.blockedHashes ?? [];
63
+ const target = rule.target;
64
+ let passed = true;
65
+ let message = "Content does not match any blocked patterns";
66
+ if (target === "prompt" || target === "both") {
67
+ if (blockedHashes.includes(promptHash)) {
68
+ passed = false;
69
+ message = "Prompt matches blocked pattern";
70
+ }
71
+ }
72
+ if (passed && (target === "output" || target === "both")) {
73
+ if (blockedHashes.includes(outputHash)) {
74
+ passed = false;
75
+ message = "Output matches blocked pattern";
76
+ }
77
+ }
78
+ return { rule, passed, message };
79
+ }
80
+ /**
81
+ * Default evaluator for allowlist rules.
82
+ * Content must match at least one allowed pattern.
83
+ *
84
+ * @param rule - The allowlist rule to evaluate
85
+ * @param promptHash - Hash of the prompt content
86
+ * @param outputHash - Hash of the output content
87
+ * @returns Evaluation result
88
+ */
89
+ async function evaluateAllowlistRule(rule, promptHash, outputHash) {
90
+ // In a real ZK implementation, this would verify membership in an
91
+ // allowed set using accumulator proofs or similar techniques.
92
+ const allowedHashes = rule.params.allowedHashes ?? [];
93
+ const requireAllMatch = rule.params.requireAllMatch ?? false;
94
+ const target = rule.target;
95
+ // If allowedHashes is empty, everything is allowed (permissive default)
96
+ if (allowedHashes.length === 0) {
97
+ return { rule, passed: true, message: "No allowlist constraints (permissive)" };
98
+ }
99
+ let promptAllowed = true;
100
+ let outputAllowed = true;
101
+ if (target === "prompt" || target === "both") {
102
+ promptAllowed = allowedHashes.some((hash) => promptHash.startsWith(hash));
103
+ }
104
+ if (target === "output" || target === "both") {
105
+ outputAllowed = allowedHashes.some((hash) => outputHash.startsWith(hash));
106
+ }
107
+ const passed = requireAllMatch
108
+ ? promptAllowed && outputAllowed
109
+ : promptAllowed || outputAllowed;
110
+ const message = passed
111
+ ? "Content matches allowlist criteria"
112
+ : "Content does not match any allowed patterns";
113
+ return { rule, passed, message };
114
+ }
115
+ /**
116
+ * Default evaluator for regex rules.
117
+ * Simulates regex pattern matching in ZK context.
118
+ *
119
+ * @param rule - The regex rule to evaluate
120
+ * @param promptHash - Hash of the prompt content
121
+ * @param outputHash - Hash of the output content
122
+ * @returns Evaluation result
123
+ */
124
+ async function evaluateRegexRule(rule, promptHash, outputHash) {
125
+ // In a real ZK implementation, regex matching would be done on
126
+ // the actual content as a private witness. The circuit would
127
+ // verify the regex match and output a boolean commitment.
128
+ // Here we simulate by checking pattern hash signatures.
129
+ const patternHash = rule.params.patternHash ?? "";
130
+ const isBlockPattern = rule.params.isBlockPattern ?? true;
131
+ const target = rule.target;
132
+ // Simulate pattern matching by checking if content hash contains pattern signature
133
+ let matchFound = false;
134
+ const hashesToCheck = [];
135
+ if (target === "prompt" || target === "both") {
136
+ hashesToCheck.push(promptHash);
137
+ }
138
+ if (target === "output" || target === "both") {
139
+ hashesToCheck.push(outputHash);
140
+ }
141
+ // Simulate: pattern matches if any hash shares prefix with pattern hash
142
+ for (const hash of hashesToCheck) {
143
+ if (patternHash && hash.slice(0, 8) === patternHash.slice(0, 8)) {
144
+ matchFound = true;
145
+ break;
146
+ }
147
+ }
148
+ // For block patterns, passing means no match; for allow patterns, passing means match
149
+ const passed = isBlockPattern ? !matchFound : matchFound;
150
+ const message = isBlockPattern
151
+ ? passed
152
+ ? "Content does not match blocked regex pattern"
153
+ : "Content matches blocked regex pattern"
154
+ : passed
155
+ ? "Content matches required regex pattern"
156
+ : "Content does not match required regex pattern";
157
+ return { rule, passed, message };
158
+ }
159
+ /**
160
+ * Default evaluator for classifier rules.
161
+ * Simulates ML classifier evaluation in ZK context.
162
+ *
163
+ * @param rule - The classifier rule to evaluate
164
+ * @param promptHash - Hash of the prompt content
165
+ * @param outputHash - Hash of the output content
166
+ * @returns Evaluation result
167
+ */
168
+ async function evaluateClassifierRule(rule, promptHash, outputHash) {
169
+ // In a real ZK implementation (zkML), this would run a neural network
170
+ // classifier circuit on the content and produce a proof of the
171
+ // classification result. This is extremely expensive and limited
172
+ // to small models.
173
+ // Here we simulate with deterministic hash-based classification.
174
+ const classifierId = rule.params.classifierId ?? "default";
175
+ const threshold = rule.params.threshold ?? 0.5;
176
+ const target = rule.target;
177
+ // Simulate classification score based on hash
178
+ const hashesToClassify = [];
179
+ if (target === "prompt" || target === "both") {
180
+ hashesToClassify.push(promptHash);
181
+ }
182
+ if (target === "output" || target === "both") {
183
+ hashesToClassify.push(outputHash);
184
+ }
185
+ // Deterministic "classification" based on hash bytes
186
+ let simulatedScore = 0;
187
+ for (const hash of hashesToClassify) {
188
+ // Use first 4 bytes of hash as a pseudo-random score
189
+ const hashBytes = hash.slice(0, 8);
190
+ const numericValue = parseInt(hashBytes, 16);
191
+ simulatedScore += (numericValue % 100) / 100;
192
+ }
193
+ simulatedScore = simulatedScore / hashesToClassify.length;
194
+ const passed = simulatedScore >= threshold;
195
+ const message = passed
196
+ ? `Classifier '${classifierId}' score ${simulatedScore.toFixed(2)} meets threshold ${threshold}`
197
+ : `Classifier '${classifierId}' score ${simulatedScore.toFixed(2)} below threshold ${threshold}`;
198
+ return { rule, passed, message };
199
+ }
200
+ // =============================================================================
201
+ // POLICY COMPLIANCE PROVER
202
+ // =============================================================================
203
+ /**
204
+ * PolicyComplianceProver generates and verifies ZK proofs of policy compliance.
205
+ *
206
+ * This prover evaluates content against policy rules and produces a proof
207
+ * that the content complies (or not) without revealing the actual content.
208
+ * Only content hashes and policy identifiers are exposed in public inputs.
209
+ *
210
+ * Supported rule types:
211
+ * - blocklist: Content must not match blocked patterns
212
+ * - allowlist: Content must match at least one allowed pattern
213
+ * - regex: Content must (not) match a regex pattern
214
+ * - classifier: Content must pass ML classification threshold
215
+ *
216
+ * @example
217
+ * ```typescript
218
+ * const prover = new PolicyComplianceProver();
219
+ * const proof = await prover.generateProof(input);
220
+ * console.log(proof.publicInputs.compliant); // true or false
221
+ * ```
222
+ */
223
+ export class PolicyComplianceProver {
224
+ debug;
225
+ evaluators;
226
+ /**
227
+ * Create a new PolicyComplianceProver instance.
228
+ *
229
+ * @param options - Configuration options
230
+ */
231
+ constructor(options = {}) {
232
+ this.debug = options.debug ?? false;
233
+ // Initialize with default evaluators
234
+ this.evaluators = new Map([
235
+ ["blocklist", evaluateBlocklistRule],
236
+ ["allowlist", evaluateAllowlistRule],
237
+ ["regex", evaluateRegexRule],
238
+ ["classifier", evaluateClassifierRule],
239
+ ]);
240
+ // Add custom evaluators if provided
241
+ if (options.customEvaluators) {
242
+ for (const [type, evaluator] of options.customEvaluators) {
243
+ this.evaluators.set(type, evaluator);
244
+ }
245
+ }
246
+ }
247
+ /**
248
+ * Generate a policy compliance proof.
249
+ *
250
+ * This method evaluates the content against all policy rules and generates
251
+ * a ZK proof of the compliance result. The proof binds to the Cardano
252
+ * anchor transaction for cross-chain verification.
253
+ *
254
+ * @param input - Policy compliance input
255
+ * @returns Promise resolving to the policy proof
256
+ * @throws MidnightProverException on validation or generation failure
257
+ */
258
+ async generateProof(input) {
259
+ const startTime = performance.now();
260
+ // Validate input
261
+ this.validateInput(input);
262
+ if (this.debug) {
263
+ console.log("[PolicyComplianceProver] Generating proof for policy:", input.policy.id);
264
+ }
265
+ // Evaluate policy rules
266
+ const evaluationResult = await this.evaluatePolicy(input.policy, input.promptHash, input.outputHash);
267
+ // Generate proof bytes (mock implementation)
268
+ const proofBytes = await this.generateProofBytes(input, evaluationResult);
269
+ const endTime = performance.now();
270
+ const provingTimeMs = Math.round(endTime - startTime);
271
+ // Construct public inputs
272
+ const publicInputs = {
273
+ promptHash: input.promptHash,
274
+ policyId: input.policy.id,
275
+ policyVersion: input.policy.version,
276
+ compliant: evaluationResult.compliant,
277
+ cardanoAnchorTxHash: input.cardanoAnchorTxHash,
278
+ };
279
+ // Generate proof ID
280
+ const proofId = await this.generateProofId(publicInputs);
281
+ const proof = {
282
+ proofType: "policy-compliance",
283
+ proofId,
284
+ proof: proofBytes,
285
+ createdAt: new Date().toISOString(),
286
+ provingTimeMs,
287
+ proofSizeBytes: proofBytes.length,
288
+ publicInputs,
289
+ };
290
+ if (this.debug) {
291
+ console.log("[PolicyComplianceProver] Proof generated:", {
292
+ proofId,
293
+ compliant: evaluationResult.compliant,
294
+ provingTimeMs,
295
+ ruleCount: input.policy.rules.length,
296
+ });
297
+ }
298
+ return proof;
299
+ }
300
+ /**
301
+ * Verify a policy compliance proof.
302
+ *
303
+ * This method verifies the cryptographic validity of the proof and
304
+ * checks that public inputs are consistent.
305
+ *
306
+ * @param proof - The policy proof to verify
307
+ * @returns Promise resolving to true if valid
308
+ */
309
+ async verifyProof(proof) {
310
+ try {
311
+ // Validate proof structure
312
+ if (proof.proofType !== "policy-compliance") {
313
+ return false;
314
+ }
315
+ if (!proof.proof || proof.proof.length === 0) {
316
+ return false;
317
+ }
318
+ // Validate public inputs
319
+ const { publicInputs } = proof;
320
+ if (!publicInputs.promptHash || publicInputs.promptHash.length !== 64) {
321
+ return false;
322
+ }
323
+ if (!publicInputs.policyId || publicInputs.policyId.length === 0) {
324
+ return false;
325
+ }
326
+ if (!publicInputs.policyVersion || publicInputs.policyVersion.length === 0) {
327
+ return false;
328
+ }
329
+ if (!publicInputs.cardanoAnchorTxHash || publicInputs.cardanoAnchorTxHash.length === 0) {
330
+ return false;
331
+ }
332
+ if (typeof publicInputs.compliant !== "boolean") {
333
+ return false;
334
+ }
335
+ // Verify proof ID matches public inputs
336
+ const expectedProofId = await this.generateProofId(publicInputs);
337
+ if (proof.proofId !== expectedProofId) {
338
+ return false;
339
+ }
340
+ // Verify proof bytes contain expected structure
341
+ // In a real implementation, this would verify the ZK proof cryptographically
342
+ const proofValid = this.verifyProofBytes(proof.proof, publicInputs);
343
+ return proofValid;
344
+ }
345
+ catch (error) {
346
+ if (this.debug) {
347
+ console.error("[PolicyComplianceProver] Verification error:", error);
348
+ }
349
+ return false;
350
+ }
351
+ }
352
+ /**
353
+ * Evaluate all policy rules against content.
354
+ *
355
+ * @param policy - The policy to evaluate
356
+ * @param promptHash - Hash of prompt content
357
+ * @param outputHash - Hash of output content
358
+ * @returns Evaluation result with rule-by-rule breakdown
359
+ */
360
+ async evaluatePolicy(policy, promptHash, outputHash) {
361
+ const startTime = performance.now();
362
+ const ruleResults = [];
363
+ for (const rule of policy.rules) {
364
+ const evaluator = this.evaluators.get(rule.type);
365
+ if (!evaluator) {
366
+ throw new MidnightProverException(MidnightProverError.INVALID_INPUT, `Unknown rule type: ${rule.type}`);
367
+ }
368
+ const result = await evaluator(rule, promptHash, outputHash);
369
+ ruleResults.push(result);
370
+ if (this.debug) {
371
+ console.log(`[PolicyComplianceProver] Rule ${rule.type}:`, result.message);
372
+ }
373
+ }
374
+ const endTime = performance.now();
375
+ // Policy is compliant only if all rules pass
376
+ const compliant = ruleResults.every((r) => r.passed);
377
+ return {
378
+ compliant,
379
+ ruleResults,
380
+ evaluationTimeMs: Math.round(endTime - startTime),
381
+ };
382
+ }
383
+ /**
384
+ * Register a custom rule evaluator.
385
+ *
386
+ * @param type - Rule type identifier
387
+ * @param evaluator - Evaluation function
388
+ */
389
+ registerEvaluator(type, evaluator) {
390
+ this.evaluators.set(type, evaluator);
391
+ }
392
+ // ===========================================================================
393
+ // PRIVATE METHODS
394
+ // ===========================================================================
395
+ /**
396
+ * Validate policy input.
397
+ */
398
+ validateInput(input) {
399
+ if (!input.promptHash || input.promptHash.length !== 64) {
400
+ throw new MidnightProverException(MidnightProverError.INVALID_INPUT, "Invalid prompt hash: must be 64-character hex string");
401
+ }
402
+ if (!input.outputHash || input.outputHash.length !== 64) {
403
+ throw new MidnightProverException(MidnightProverError.INVALID_INPUT, "Invalid output hash: must be 64-character hex string");
404
+ }
405
+ if (!input.policy) {
406
+ throw new MidnightProverException(MidnightProverError.MISSING_REQUIRED_FIELD, "Policy is required");
407
+ }
408
+ if (!input.policy.id || input.policy.id.length === 0) {
409
+ throw new MidnightProverException(MidnightProverError.INVALID_INPUT, "Policy ID is required");
410
+ }
411
+ if (!input.policy.version || input.policy.version.length === 0) {
412
+ throw new MidnightProverException(MidnightProverError.INVALID_INPUT, "Policy version is required");
413
+ }
414
+ if (!input.cardanoAnchorTxHash || input.cardanoAnchorTxHash.length === 0) {
415
+ throw new MidnightProverException(MidnightProverError.MISSING_REQUIRED_FIELD, "Cardano anchor transaction hash is required");
416
+ }
417
+ }
418
+ /**
419
+ * Generate mock proof bytes.
420
+ * In a real implementation, this would call the Midnight proof server.
421
+ */
422
+ async generateProofBytes(input, evaluation) {
423
+ // Construct witness data (private inputs)
424
+ const witnessData = canonicalize({
425
+ promptHash: input.promptHash,
426
+ outputHash: input.outputHash,
427
+ policyId: input.policy.id,
428
+ policyVersion: input.policy.version,
429
+ rules: input.policy.rules,
430
+ compliant: evaluation.compliant,
431
+ cardanoAnchorTxHash: input.cardanoAnchorTxHash,
432
+ });
433
+ // Generate witness hash
434
+ const witnessHash = await sha256StringHex(POLICY_DOMAIN_PREFIXES.witness + witnessData);
435
+ // Construct public input commitment
436
+ const publicInputData = canonicalize({
437
+ promptHash: input.promptHash,
438
+ policyId: input.policy.id,
439
+ policyVersion: input.policy.version,
440
+ compliant: evaluation.compliant,
441
+ cardanoAnchorTxHash: input.cardanoAnchorTxHash,
442
+ });
443
+ const publicInputHash = await sha256StringHex(POLICY_DOMAIN_PREFIXES.publicInput + publicInputData);
444
+ // Generate mock proof: commitment to witness + public inputs
445
+ const proofCommitment = await sha256StringHex(POLICY_DOMAIN_PREFIXES.proof + witnessHash + "|" + publicInputHash);
446
+ // Construct proof bytes: version (1 byte) + commitment (32 bytes) + witness hash (32 bytes)
447
+ const proofBytes = new Uint8Array(65);
448
+ proofBytes[0] = 0x01; // Version 1
449
+ // Copy commitment hash
450
+ const commitmentBytes = this.hexToBytes(proofCommitment);
451
+ proofBytes.set(commitmentBytes, 1);
452
+ // Copy witness hash
453
+ const witnessBytes = this.hexToBytes(witnessHash);
454
+ proofBytes.set(witnessBytes, 33);
455
+ return proofBytes;
456
+ }
457
+ /**
458
+ * Verify mock proof bytes.
459
+ * In a real implementation, this would cryptographically verify the proof
460
+ * against the public inputs using the ZK verifier.
461
+ */
462
+ verifyProofBytes(proofBytes, _publicInputs) {
463
+ // Check minimum proof size
464
+ if (proofBytes.length < 65) {
465
+ return false;
466
+ }
467
+ // Check version byte
468
+ if (proofBytes[0] !== 0x01) {
469
+ return false;
470
+ }
471
+ // Note: _publicInputs would be used in real ZK verification
472
+ // Extract commitment from proof and verify structure is valid
473
+ const commitmentBytes = proofBytes.slice(1, 33);
474
+ const witnessHashBytes = proofBytes.slice(33, 65);
475
+ // Verify both are non-zero (basic sanity check)
476
+ const commitmentNonZero = commitmentBytes.some((b) => b !== 0);
477
+ const witnessNonZero = witnessHashBytes.some((b) => b !== 0);
478
+ return commitmentNonZero && witnessNonZero;
479
+ }
480
+ /**
481
+ * Generate proof ID from public inputs.
482
+ */
483
+ async generateProofId(publicInputs) {
484
+ const data = canonicalize({
485
+ type: "policy-compliance",
486
+ ...publicInputs,
487
+ });
488
+ const hash = await sha256StringHex(data);
489
+ return `policy-proof-${hash.slice(0, 16)}`;
490
+ }
491
+ /**
492
+ * Convert hex string to bytes.
493
+ */
494
+ hexToBytes(hex) {
495
+ const bytes = new Uint8Array(hex.length / 2);
496
+ for (let i = 0; i < hex.length; i += 2) {
497
+ bytes[i / 2] = parseInt(hex.slice(i, i + 2), 16);
498
+ }
499
+ return bytes;
500
+ }
501
+ }
502
+ // =============================================================================
503
+ // FACTORY FUNCTION
504
+ // =============================================================================
505
+ /**
506
+ * Create a new PolicyComplianceProver instance.
507
+ *
508
+ * @param options - Configuration options
509
+ * @returns New prover instance
510
+ */
511
+ export function createPolicyComplianceProver(options) {
512
+ return new PolicyComplianceProver(options);
513
+ }
514
+ //# sourceMappingURL=policy-compliance-proof.js.map