@izi-noir/sdk 0.1.10 → 0.1.12

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.js CHANGED
@@ -45,7 +45,9 @@ var init_Barretenberg = __esm({
45
45
  "src/infra/provingSystems/Barretenberg.ts"() {
46
46
  "use strict";
47
47
  Barretenberg = class {
48
- async compile(noirCode) {
48
+ // Note: options parameter is accepted but not used - Barretenberg uses Noir's ACIR directly
49
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
50
+ async compile(noirCode, _options) {
49
51
  const { basePath, cleanup } = await createTempDir();
50
52
  const fm = createFileManager(basePath);
51
53
  const nargoToml = `[package]
@@ -103,6 +105,378 @@ authors = [""]
103
105
  }
104
106
  });
105
107
 
108
+ // src/infra/provingSystems/R1csBuilder.ts
109
+ var R1csBuilder;
110
+ var init_R1csBuilder = __esm({
111
+ "src/infra/provingSystems/R1csBuilder.ts"() {
112
+ "use strict";
113
+ R1csBuilder = class {
114
+ constructor(parsedCircuit) {
115
+ this.parsedCircuit = parsedCircuit;
116
+ }
117
+ constraints = [];
118
+ witnessMap = /* @__PURE__ */ new Map();
119
+ nextWitnessIdx = 1;
120
+ // w_0 = 1 is reserved
121
+ publicIndices = [];
122
+ privateIndices = [];
123
+ // BN254 scalar field modulus - 1 (for representing -1)
124
+ // Fr modulus = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001
125
+ // -1 mod Fr = Fr - 1
126
+ NEG_ONE = "0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000";
127
+ /**
128
+ * Build R1CS definition from the parsed circuit
129
+ */
130
+ build() {
131
+ this.registerInputs();
132
+ for (const stmt of this.parsedCircuit.statements) {
133
+ this.processStatement(stmt);
134
+ }
135
+ return {
136
+ num_witnesses: this.nextWitnessIdx,
137
+ public_inputs: this.publicIndices,
138
+ private_inputs: this.privateIndices,
139
+ constraints: this.constraints
140
+ };
141
+ }
142
+ /**
143
+ * Get the witness index for an input parameter name
144
+ */
145
+ getWitnessIndex(name) {
146
+ return this.witnessMap.get(name);
147
+ }
148
+ /**
149
+ * Register all circuit inputs as witnesses
150
+ * IMPORTANT: Noir orders witnesses as private first, then public
151
+ * We must match this order for the witness values to align correctly
152
+ */
153
+ registerInputs() {
154
+ for (const param of this.parsedCircuit.privateParams) {
155
+ const idx = this.nextWitnessIdx++;
156
+ this.witnessMap.set(param.name, idx);
157
+ this.privateIndices.push(idx);
158
+ }
159
+ for (const param of this.parsedCircuit.publicParams) {
160
+ const idx = this.nextWitnessIdx++;
161
+ this.witnessMap.set(param.name, idx);
162
+ this.publicIndices.push(idx);
163
+ }
164
+ }
165
+ /**
166
+ * Process a single statement and generate constraints
167
+ */
168
+ processStatement(stmt) {
169
+ switch (stmt.kind) {
170
+ case "assert":
171
+ this.processAssert(stmt.condition);
172
+ break;
173
+ case "variable_declaration":
174
+ this.processVariableDecl(stmt.name, stmt.initializer);
175
+ break;
176
+ case "assignment":
177
+ this.processAssignment(stmt.target, stmt.value);
178
+ break;
179
+ case "if_statement":
180
+ for (const s of stmt.consequent) {
181
+ this.processStatement(s);
182
+ }
183
+ if (stmt.alternate) {
184
+ for (const s of stmt.alternate) {
185
+ this.processStatement(s);
186
+ }
187
+ }
188
+ break;
189
+ case "for_statement":
190
+ throw new Error(
191
+ "For loops are not yet supported in R1CS generation. Use the Barretenberg backend for complex circuits."
192
+ );
193
+ }
194
+ }
195
+ /**
196
+ * Process an assert statement
197
+ * The condition must evaluate to true for a valid proof
198
+ */
199
+ processAssert(condition) {
200
+ if (condition.kind === "binary") {
201
+ this.processBinaryAssert(condition);
202
+ } else if (condition.kind === "identifier") {
203
+ const idx = this.getOrCreateWitness(condition);
204
+ this.constraints.push({
205
+ a: [["0x1", idx]],
206
+ b: [["0x1", 0]],
207
+ // * 1
208
+ c: [["0x1", 0]]
209
+ // = 1 (w_0)
210
+ });
211
+ } else {
212
+ throw new Error(`Unsupported assert condition kind: ${condition.kind}`);
213
+ }
214
+ }
215
+ /**
216
+ * Process a binary expression in an assert
217
+ */
218
+ processBinaryAssert(expr) {
219
+ const { left, operator, right } = expr;
220
+ switch (operator) {
221
+ case "==":
222
+ this.processEquality(left, right);
223
+ break;
224
+ case "!=":
225
+ throw new Error(
226
+ "Inequality (!=) is not yet supported in R1CS. Use equality (==) instead."
227
+ );
228
+ case "+":
229
+ case "-":
230
+ case "*":
231
+ case "/":
232
+ case "%":
233
+ throw new Error(
234
+ `Arithmetic operator ${operator} must be part of an equality assertion. Use: assert(a ${operator} b == c)`
235
+ );
236
+ case "<":
237
+ case ">":
238
+ case "<=":
239
+ case ">=":
240
+ throw new Error(
241
+ `Comparison operators (${operator}) require range proofs which are not yet supported. Use the Barretenberg backend for comparison operations.`
242
+ );
243
+ case "&":
244
+ case "|":
245
+ throw new Error(
246
+ `Logical operator ${operator} is not yet supported in R1CS.`
247
+ );
248
+ default:
249
+ throw new Error(`Unsupported operator in assert: ${operator}`);
250
+ }
251
+ }
252
+ /**
253
+ * Process an equality assertion: assert(left == right)
254
+ */
255
+ processEquality(left, right) {
256
+ if (left.kind === "binary" && left.operator === "*") {
257
+ this.processMultiplicationEquality(left.left, left.right, right);
258
+ return;
259
+ }
260
+ if (right.kind === "binary" && right.operator === "*") {
261
+ this.processMultiplicationEquality(right.left, right.right, left);
262
+ return;
263
+ }
264
+ if (left.kind === "binary" && left.operator === "+") {
265
+ this.processAdditionEquality(left.left, left.right, right);
266
+ return;
267
+ }
268
+ if (right.kind === "binary" && right.operator === "+") {
269
+ this.processAdditionEquality(right.left, right.right, left);
270
+ return;
271
+ }
272
+ if (left.kind === "binary" && left.operator === "-") {
273
+ this.processSubtractionEquality(left.left, left.right, right);
274
+ return;
275
+ }
276
+ if (right.kind === "binary" && right.operator === "-") {
277
+ this.processSubtractionEquality(right.left, right.right, left);
278
+ return;
279
+ }
280
+ const leftIdx = this.getOrCreateWitness(left);
281
+ const rightIdx = this.getOrCreateWitness(right);
282
+ this.constraints.push({
283
+ a: [
284
+ ["0x1", leftIdx],
285
+ [this.NEG_ONE, rightIdx]
286
+ ],
287
+ // a - b
288
+ b: [["0x1", 0]],
289
+ // * 1 (w_0 = 1)
290
+ c: []
291
+ // = 0
292
+ });
293
+ }
294
+ /**
295
+ * Process multiplication equality: assert(a * b == c)
296
+ * R1CS: a * b = c
297
+ */
298
+ processMultiplicationEquality(left, right, result) {
299
+ const leftIdx = this.getOrCreateWitness(left);
300
+ const rightIdx = this.getOrCreateWitness(right);
301
+ const resultIdx = this.getOrCreateWitness(result);
302
+ this.constraints.push({
303
+ a: [["0x1", leftIdx]],
304
+ b: [["0x1", rightIdx]],
305
+ c: [["0x1", resultIdx]]
306
+ });
307
+ }
308
+ /**
309
+ * Process addition equality: assert(a + b == c)
310
+ * R1CS: (a + b - c) * 1 = 0
311
+ * Which is: (a + b) * 1 = c
312
+ */
313
+ processAdditionEquality(left, right, result) {
314
+ const leftIdx = this.getOrCreateWitness(left);
315
+ const rightIdx = this.getOrCreateWitness(right);
316
+ const resultIdx = this.getOrCreateWitness(result);
317
+ this.constraints.push({
318
+ a: [
319
+ ["0x1", leftIdx],
320
+ ["0x1", rightIdx]
321
+ ],
322
+ // a + b
323
+ b: [["0x1", 0]],
324
+ // * 1
325
+ c: [["0x1", resultIdx]]
326
+ // = c
327
+ });
328
+ }
329
+ /**
330
+ * Process subtraction equality: assert(a - b == c)
331
+ * R1CS: (a - b) * 1 = c
332
+ */
333
+ processSubtractionEquality(left, right, result) {
334
+ const leftIdx = this.getOrCreateWitness(left);
335
+ const rightIdx = this.getOrCreateWitness(right);
336
+ const resultIdx = this.getOrCreateWitness(result);
337
+ this.constraints.push({
338
+ a: [
339
+ ["0x1", leftIdx],
340
+ [this.NEG_ONE, rightIdx]
341
+ ],
342
+ // a - b
343
+ b: [["0x1", 0]],
344
+ // * 1
345
+ c: [["0x1", resultIdx]]
346
+ // = c
347
+ });
348
+ }
349
+ /**
350
+ * Process a variable declaration: let x = expr
351
+ * Creates a new witness for x and adds constraint if needed
352
+ */
353
+ processVariableDecl(name, initializer) {
354
+ const varIdx = this.nextWitnessIdx++;
355
+ this.witnessMap.set(name, varIdx);
356
+ if (initializer.kind === "identifier") {
357
+ const initIdx = this.getOrCreateWitness(initializer);
358
+ this.constraints.push({
359
+ a: [
360
+ ["0x1", varIdx],
361
+ [this.NEG_ONE, initIdx]
362
+ ],
363
+ b: [["0x1", 0]],
364
+ c: []
365
+ });
366
+ } else if (initializer.kind === "literal") {
367
+ } else if (initializer.kind === "binary") {
368
+ this.processVariableInitBinary(varIdx, initializer);
369
+ } else {
370
+ throw new Error(
371
+ `Unsupported initializer kind for variable declaration: ${initializer.kind}`
372
+ );
373
+ }
374
+ }
375
+ /**
376
+ * Process a binary expression as variable initializer
377
+ */
378
+ processVariableInitBinary(varIdx, expr) {
379
+ const { left, operator, right } = expr;
380
+ const leftIdx = this.getOrCreateWitness(left);
381
+ const rightIdx = this.getOrCreateWitness(right);
382
+ switch (operator) {
383
+ case "*":
384
+ this.constraints.push({
385
+ a: [["0x1", leftIdx]],
386
+ b: [["0x1", rightIdx]],
387
+ c: [["0x1", varIdx]]
388
+ });
389
+ break;
390
+ case "+":
391
+ this.constraints.push({
392
+ a: [
393
+ ["0x1", leftIdx],
394
+ ["0x1", rightIdx]
395
+ ],
396
+ b: [["0x1", 0]],
397
+ c: [["0x1", varIdx]]
398
+ });
399
+ break;
400
+ case "-":
401
+ this.constraints.push({
402
+ a: [
403
+ ["0x1", leftIdx],
404
+ [this.NEG_ONE, rightIdx]
405
+ ],
406
+ b: [["0x1", 0]],
407
+ c: [["0x1", varIdx]]
408
+ });
409
+ break;
410
+ default:
411
+ throw new Error(
412
+ `Unsupported operator in variable initializer: ${operator}`
413
+ );
414
+ }
415
+ }
416
+ /**
417
+ * Process an assignment: x = expr
418
+ * Updates the witness mapping
419
+ */
420
+ processAssignment(target, value) {
421
+ const existingIdx = this.witnessMap.get(target);
422
+ if (existingIdx === void 0) {
423
+ throw new Error(`Assignment to undeclared variable: ${target}`);
424
+ }
425
+ if (value.kind === "identifier") {
426
+ const valueIdx = this.getOrCreateWitness(value);
427
+ this.constraints.push({
428
+ a: [
429
+ ["0x1", existingIdx],
430
+ [this.NEG_ONE, valueIdx]
431
+ ],
432
+ b: [["0x1", 0]],
433
+ c: []
434
+ });
435
+ } else if (value.kind === "binary") {
436
+ this.processVariableInitBinary(existingIdx, value);
437
+ }
438
+ }
439
+ /**
440
+ * Get or create a witness index for an expression
441
+ */
442
+ getOrCreateWitness(expr) {
443
+ if (expr.kind === "identifier") {
444
+ const existing = this.witnessMap.get(expr.name);
445
+ if (existing !== void 0) {
446
+ return existing;
447
+ }
448
+ const idx = this.nextWitnessIdx++;
449
+ this.witnessMap.set(expr.name, idx);
450
+ return idx;
451
+ }
452
+ if (expr.kind === "literal") {
453
+ const idx = this.nextWitnessIdx++;
454
+ return idx;
455
+ }
456
+ if (expr.kind === "binary") {
457
+ const idx = this.nextWitnessIdx++;
458
+ this.processVariableInitBinary(idx, expr);
459
+ return idx;
460
+ }
461
+ if (expr.kind === "unary") {
462
+ const operandIdx = this.getOrCreateWitness(expr.operand);
463
+ if (expr.operator === "-") {
464
+ const idx = this.nextWitnessIdx++;
465
+ this.constraints.push({
466
+ a: [[this.NEG_ONE, operandIdx]],
467
+ b: [["0x1", 0]],
468
+ c: [["0x1", idx]]
469
+ });
470
+ return idx;
471
+ }
472
+ throw new Error(`Unsupported unary operator: ${expr.operator}`);
473
+ }
474
+ throw new Error(`Unsupported expression kind: ${expr.kind}`);
475
+ }
476
+ };
477
+ }
478
+ });
479
+
106
480
  // src/infra/provingSystems/ArkworksWasm.ts
107
481
  var ArkworksWasm_exports = {};
108
482
  __export(ArkworksWasm_exports, {
@@ -236,6 +610,7 @@ var wasmModule, wasmInitPromise2, ArkworksWasm;
236
610
  var init_ArkworksWasm = __esm({
237
611
  "src/infra/provingSystems/ArkworksWasm.ts"() {
238
612
  "use strict";
613
+ init_R1csBuilder();
239
614
  wasmModule = null;
240
615
  wasmInitPromise2 = null;
241
616
  ArkworksWasm = class {
@@ -249,8 +624,11 @@ var init_ArkworksWasm = __esm({
249
624
  }
250
625
  /**
251
626
  * Compile Noir code to a circuit with ACIR for Groth16 proving
627
+ *
628
+ * @param noirCode - The Noir source code to compile
629
+ * @param options - Optional compilation options including ParsedCircuit for dynamic R1CS
252
630
  */
253
- async compile(noirCode) {
631
+ async compile(noirCode, options) {
254
632
  const wasm = await initWasm();
255
633
  const { basePath, cleanup } = await createTempDir2();
256
634
  const fm = createFileManager2(basePath);
@@ -275,36 +653,52 @@ authors = [""]
275
653
  throw new Error("Compilation failed: no bytecode generated");
276
654
  }
277
655
  const parameters = compiled.abi.parameters;
278
- const publicR1csIndices = [];
279
- const privateR1csIndices = [];
656
+ let r1cs;
280
657
  const witnessIndexMapping = /* @__PURE__ */ new Map();
281
- parameters.forEach((p, noirIndex) => {
282
- const r1csIndex = noirIndex + 1;
283
- witnessIndexMapping.set(noirIndex, r1csIndex);
284
- if (p.visibility === "public") {
285
- publicR1csIndices.push(r1csIndex);
286
- } else if (p.visibility === "private") {
287
- privateR1csIndices.push(r1csIndex);
288
- }
289
- });
290
- const r1cs = {
291
- num_witnesses: parameters.length + 1,
292
- // +1 for w_0
293
- public_inputs: publicR1csIndices,
294
- private_inputs: privateR1csIndices,
295
- constraints: []
296
- };
297
- if (privateR1csIndices.length === 1 && publicR1csIndices.length === 1) {
298
- const privateIdx = privateR1csIndices[0];
299
- const publicIdx = publicR1csIndices[0];
300
- r1cs.constraints.push({
301
- a: [["0x1", privateIdx]],
302
- // secret
303
- b: [["0x1", privateIdx]],
304
- // secret
305
- c: [["0x1", publicIdx]]
306
- // expected
658
+ if (options?.parsedCircuit) {
659
+ const builder = new R1csBuilder(options.parsedCircuit);
660
+ r1cs = builder.build();
661
+ parameters.forEach((p, noirIndex) => {
662
+ const r1csIndex = noirIndex + 1;
663
+ witnessIndexMapping.set(noirIndex, r1csIndex);
664
+ });
665
+ console.log("=== R1CS BUILDER DEBUG ===");
666
+ console.log("ParsedCircuit publicParams:", options.parsedCircuit.publicParams);
667
+ console.log("ParsedCircuit privateParams:", options.parsedCircuit.privateParams);
668
+ console.log("ParsedCircuit statements:", JSON.stringify(options.parsedCircuit.statements, null, 2));
669
+ console.log("Generated R1CS:", JSON.stringify(r1cs, null, 2));
670
+ console.log("==========================");
671
+ } else {
672
+ const publicR1csIndices = [];
673
+ const privateR1csIndices = [];
674
+ parameters.forEach((p, noirIndex) => {
675
+ const r1csIndex = noirIndex + 1;
676
+ witnessIndexMapping.set(noirIndex, r1csIndex);
677
+ if (p.visibility === "public") {
678
+ publicR1csIndices.push(r1csIndex);
679
+ } else if (p.visibility === "private") {
680
+ privateR1csIndices.push(r1csIndex);
681
+ }
307
682
  });
683
+ r1cs = {
684
+ num_witnesses: parameters.length + 1,
685
+ public_inputs: publicR1csIndices,
686
+ private_inputs: privateR1csIndices,
687
+ constraints: []
688
+ };
689
+ if (privateR1csIndices.length === 1 && publicR1csIndices.length === 1) {
690
+ const privateIdx = privateR1csIndices[0];
691
+ const publicIdx = publicR1csIndices[0];
692
+ r1cs.constraints.push({
693
+ a: [["0x1", privateIdx]],
694
+ b: [["0x1", privateIdx]],
695
+ c: [["0x1", publicIdx]]
696
+ });
697
+ }
698
+ console.log("=== R1CS HARDCODED DEBUG ===");
699
+ console.log("Using hardcoded R1CS pattern (no ParsedCircuit provided)");
700
+ console.log("R1CS:", JSON.stringify(r1cs, null, 2));
701
+ console.log("============================");
308
702
  }
309
703
  const r1csJson = JSON.stringify(r1cs);
310
704
  let provingKey;
@@ -321,7 +715,7 @@ authors = [""]
321
715
  }
322
716
  }
323
717
  const acirJson = JSON.stringify({
324
- functions: [{ current_witness_index: parameters.length, opcodes: [], private_parameters: privateR1csIndices, public_parameters: { witnesses: publicR1csIndices }, return_values: { witnesses: [] } }]
718
+ functions: [{ current_witness_index: parameters.length, opcodes: [], private_parameters: r1cs.private_inputs, public_parameters: { witnesses: r1cs.public_inputs }, return_values: { witnesses: [] } }]
325
719
  });
326
720
  const arkworksCircuit = {
327
721
  ...compiled,
@@ -1125,16 +1519,20 @@ var IziNoir = class _IziNoir {
1125
1519
  * After compile(), the verifying key is available via `this.vk`.
1126
1520
  *
1127
1521
  * @param noirCode - The Noir source code to compile
1522
+ * @param options - Optional compilation options including ParsedCircuit for dynamic R1CS
1128
1523
  * @returns CompileResult with circuit and verifying key
1129
1524
  *
1130
1525
  * @example
1131
1526
  * ```typescript
1527
+ * // Basic usage
1132
1528
  * const { circuit, verifyingKey } = await izi.compile(noirCode);
1133
- * console.log('VK:', izi.vk); // Available immediately after compile
1529
+ *
1530
+ * // With ParsedCircuit for dynamic R1CS generation
1531
+ * const { circuit } = await izi.compile(noirCode, { parsedCircuit });
1134
1532
  * ```
1135
1533
  */
1136
- async compile(noirCode) {
1137
- this.compiledCircuit = await this.provingSystem.compile(noirCode);
1534
+ async compile(noirCode, options) {
1535
+ this.compiledCircuit = await this.provingSystem.compile(noirCode, options);
1138
1536
  const vk = await this.extractVerifyingKey(this.compiledCircuit);
1139
1537
  if (vk) {
1140
1538
  this._verifyingKey = vk;
@@ -1557,6 +1955,7 @@ Check on explorer: ${getExplorerTxUrl(this._network, signature)}`
1557
1955
  init_SolanaFormatter();
1558
1956
  init_Barretenberg();
1559
1957
  init_ArkworksWasm();
1958
+ init_R1csBuilder();
1560
1959
 
1561
1960
  // src/infra/parser/AcornParser.ts
1562
1961
  import * as acorn from "acorn";
@@ -3100,6 +3499,7 @@ export {
3100
3499
  Network,
3101
3500
  OffchainVerifier,
3102
3501
  Provider,
3502
+ R1csBuilder,
3103
3503
  SolanaFormatter,
3104
3504
  SolanaTransactionBuilder,
3105
3505
  VkDeploymentManager,