@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.cjs CHANGED
@@ -67,7 +67,9 @@ var init_Barretenberg = __esm({
67
67
  import_noir_js = require("@noir-lang/noir_js");
68
68
  import_bb = require("@aztec/bb.js");
69
69
  Barretenberg = class {
70
- async compile(noirCode) {
70
+ // Note: options parameter is accepted but not used - Barretenberg uses Noir's ACIR directly
71
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
72
+ async compile(noirCode, _options) {
71
73
  const { basePath, cleanup } = await createTempDir();
72
74
  const fm = (0, import_noir_wasm.createFileManager)(basePath);
73
75
  const nargoToml = `[package]
@@ -125,6 +127,378 @@ authors = [""]
125
127
  }
126
128
  });
127
129
 
130
+ // src/infra/provingSystems/R1csBuilder.ts
131
+ var R1csBuilder;
132
+ var init_R1csBuilder = __esm({
133
+ "src/infra/provingSystems/R1csBuilder.ts"() {
134
+ "use strict";
135
+ R1csBuilder = class {
136
+ constructor(parsedCircuit) {
137
+ this.parsedCircuit = parsedCircuit;
138
+ }
139
+ constraints = [];
140
+ witnessMap = /* @__PURE__ */ new Map();
141
+ nextWitnessIdx = 1;
142
+ // w_0 = 1 is reserved
143
+ publicIndices = [];
144
+ privateIndices = [];
145
+ // BN254 scalar field modulus - 1 (for representing -1)
146
+ // Fr modulus = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001
147
+ // -1 mod Fr = Fr - 1
148
+ NEG_ONE = "0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000";
149
+ /**
150
+ * Build R1CS definition from the parsed circuit
151
+ */
152
+ build() {
153
+ this.registerInputs();
154
+ for (const stmt of this.parsedCircuit.statements) {
155
+ this.processStatement(stmt);
156
+ }
157
+ return {
158
+ num_witnesses: this.nextWitnessIdx,
159
+ public_inputs: this.publicIndices,
160
+ private_inputs: this.privateIndices,
161
+ constraints: this.constraints
162
+ };
163
+ }
164
+ /**
165
+ * Get the witness index for an input parameter name
166
+ */
167
+ getWitnessIndex(name) {
168
+ return this.witnessMap.get(name);
169
+ }
170
+ /**
171
+ * Register all circuit inputs as witnesses
172
+ * IMPORTANT: Noir orders witnesses as private first, then public
173
+ * We must match this order for the witness values to align correctly
174
+ */
175
+ registerInputs() {
176
+ for (const param of this.parsedCircuit.privateParams) {
177
+ const idx = this.nextWitnessIdx++;
178
+ this.witnessMap.set(param.name, idx);
179
+ this.privateIndices.push(idx);
180
+ }
181
+ for (const param of this.parsedCircuit.publicParams) {
182
+ const idx = this.nextWitnessIdx++;
183
+ this.witnessMap.set(param.name, idx);
184
+ this.publicIndices.push(idx);
185
+ }
186
+ }
187
+ /**
188
+ * Process a single statement and generate constraints
189
+ */
190
+ processStatement(stmt) {
191
+ switch (stmt.kind) {
192
+ case "assert":
193
+ this.processAssert(stmt.condition);
194
+ break;
195
+ case "variable_declaration":
196
+ this.processVariableDecl(stmt.name, stmt.initializer);
197
+ break;
198
+ case "assignment":
199
+ this.processAssignment(stmt.target, stmt.value);
200
+ break;
201
+ case "if_statement":
202
+ for (const s of stmt.consequent) {
203
+ this.processStatement(s);
204
+ }
205
+ if (stmt.alternate) {
206
+ for (const s of stmt.alternate) {
207
+ this.processStatement(s);
208
+ }
209
+ }
210
+ break;
211
+ case "for_statement":
212
+ throw new Error(
213
+ "For loops are not yet supported in R1CS generation. Use the Barretenberg backend for complex circuits."
214
+ );
215
+ }
216
+ }
217
+ /**
218
+ * Process an assert statement
219
+ * The condition must evaluate to true for a valid proof
220
+ */
221
+ processAssert(condition) {
222
+ if (condition.kind === "binary") {
223
+ this.processBinaryAssert(condition);
224
+ } else if (condition.kind === "identifier") {
225
+ const idx = this.getOrCreateWitness(condition);
226
+ this.constraints.push({
227
+ a: [["0x1", idx]],
228
+ b: [["0x1", 0]],
229
+ // * 1
230
+ c: [["0x1", 0]]
231
+ // = 1 (w_0)
232
+ });
233
+ } else {
234
+ throw new Error(`Unsupported assert condition kind: ${condition.kind}`);
235
+ }
236
+ }
237
+ /**
238
+ * Process a binary expression in an assert
239
+ */
240
+ processBinaryAssert(expr) {
241
+ const { left, operator, right } = expr;
242
+ switch (operator) {
243
+ case "==":
244
+ this.processEquality(left, right);
245
+ break;
246
+ case "!=":
247
+ throw new Error(
248
+ "Inequality (!=) is not yet supported in R1CS. Use equality (==) instead."
249
+ );
250
+ case "+":
251
+ case "-":
252
+ case "*":
253
+ case "/":
254
+ case "%":
255
+ throw new Error(
256
+ `Arithmetic operator ${operator} must be part of an equality assertion. Use: assert(a ${operator} b == c)`
257
+ );
258
+ case "<":
259
+ case ">":
260
+ case "<=":
261
+ case ">=":
262
+ throw new Error(
263
+ `Comparison operators (${operator}) require range proofs which are not yet supported. Use the Barretenberg backend for comparison operations.`
264
+ );
265
+ case "&":
266
+ case "|":
267
+ throw new Error(
268
+ `Logical operator ${operator} is not yet supported in R1CS.`
269
+ );
270
+ default:
271
+ throw new Error(`Unsupported operator in assert: ${operator}`);
272
+ }
273
+ }
274
+ /**
275
+ * Process an equality assertion: assert(left == right)
276
+ */
277
+ processEquality(left, right) {
278
+ if (left.kind === "binary" && left.operator === "*") {
279
+ this.processMultiplicationEquality(left.left, left.right, right);
280
+ return;
281
+ }
282
+ if (right.kind === "binary" && right.operator === "*") {
283
+ this.processMultiplicationEquality(right.left, right.right, left);
284
+ return;
285
+ }
286
+ if (left.kind === "binary" && left.operator === "+") {
287
+ this.processAdditionEquality(left.left, left.right, right);
288
+ return;
289
+ }
290
+ if (right.kind === "binary" && right.operator === "+") {
291
+ this.processAdditionEquality(right.left, right.right, left);
292
+ return;
293
+ }
294
+ if (left.kind === "binary" && left.operator === "-") {
295
+ this.processSubtractionEquality(left.left, left.right, right);
296
+ return;
297
+ }
298
+ if (right.kind === "binary" && right.operator === "-") {
299
+ this.processSubtractionEquality(right.left, right.right, left);
300
+ return;
301
+ }
302
+ const leftIdx = this.getOrCreateWitness(left);
303
+ const rightIdx = this.getOrCreateWitness(right);
304
+ this.constraints.push({
305
+ a: [
306
+ ["0x1", leftIdx],
307
+ [this.NEG_ONE, rightIdx]
308
+ ],
309
+ // a - b
310
+ b: [["0x1", 0]],
311
+ // * 1 (w_0 = 1)
312
+ c: []
313
+ // = 0
314
+ });
315
+ }
316
+ /**
317
+ * Process multiplication equality: assert(a * b == c)
318
+ * R1CS: a * b = c
319
+ */
320
+ processMultiplicationEquality(left, right, result) {
321
+ const leftIdx = this.getOrCreateWitness(left);
322
+ const rightIdx = this.getOrCreateWitness(right);
323
+ const resultIdx = this.getOrCreateWitness(result);
324
+ this.constraints.push({
325
+ a: [["0x1", leftIdx]],
326
+ b: [["0x1", rightIdx]],
327
+ c: [["0x1", resultIdx]]
328
+ });
329
+ }
330
+ /**
331
+ * Process addition equality: assert(a + b == c)
332
+ * R1CS: (a + b - c) * 1 = 0
333
+ * Which is: (a + b) * 1 = c
334
+ */
335
+ processAdditionEquality(left, right, result) {
336
+ const leftIdx = this.getOrCreateWitness(left);
337
+ const rightIdx = this.getOrCreateWitness(right);
338
+ const resultIdx = this.getOrCreateWitness(result);
339
+ this.constraints.push({
340
+ a: [
341
+ ["0x1", leftIdx],
342
+ ["0x1", rightIdx]
343
+ ],
344
+ // a + b
345
+ b: [["0x1", 0]],
346
+ // * 1
347
+ c: [["0x1", resultIdx]]
348
+ // = c
349
+ });
350
+ }
351
+ /**
352
+ * Process subtraction equality: assert(a - b == c)
353
+ * R1CS: (a - b) * 1 = c
354
+ */
355
+ processSubtractionEquality(left, right, result) {
356
+ const leftIdx = this.getOrCreateWitness(left);
357
+ const rightIdx = this.getOrCreateWitness(right);
358
+ const resultIdx = this.getOrCreateWitness(result);
359
+ this.constraints.push({
360
+ a: [
361
+ ["0x1", leftIdx],
362
+ [this.NEG_ONE, rightIdx]
363
+ ],
364
+ // a - b
365
+ b: [["0x1", 0]],
366
+ // * 1
367
+ c: [["0x1", resultIdx]]
368
+ // = c
369
+ });
370
+ }
371
+ /**
372
+ * Process a variable declaration: let x = expr
373
+ * Creates a new witness for x and adds constraint if needed
374
+ */
375
+ processVariableDecl(name, initializer) {
376
+ const varIdx = this.nextWitnessIdx++;
377
+ this.witnessMap.set(name, varIdx);
378
+ if (initializer.kind === "identifier") {
379
+ const initIdx = this.getOrCreateWitness(initializer);
380
+ this.constraints.push({
381
+ a: [
382
+ ["0x1", varIdx],
383
+ [this.NEG_ONE, initIdx]
384
+ ],
385
+ b: [["0x1", 0]],
386
+ c: []
387
+ });
388
+ } else if (initializer.kind === "literal") {
389
+ } else if (initializer.kind === "binary") {
390
+ this.processVariableInitBinary(varIdx, initializer);
391
+ } else {
392
+ throw new Error(
393
+ `Unsupported initializer kind for variable declaration: ${initializer.kind}`
394
+ );
395
+ }
396
+ }
397
+ /**
398
+ * Process a binary expression as variable initializer
399
+ */
400
+ processVariableInitBinary(varIdx, expr) {
401
+ const { left, operator, right } = expr;
402
+ const leftIdx = this.getOrCreateWitness(left);
403
+ const rightIdx = this.getOrCreateWitness(right);
404
+ switch (operator) {
405
+ case "*":
406
+ this.constraints.push({
407
+ a: [["0x1", leftIdx]],
408
+ b: [["0x1", rightIdx]],
409
+ c: [["0x1", varIdx]]
410
+ });
411
+ break;
412
+ case "+":
413
+ this.constraints.push({
414
+ a: [
415
+ ["0x1", leftIdx],
416
+ ["0x1", rightIdx]
417
+ ],
418
+ b: [["0x1", 0]],
419
+ c: [["0x1", varIdx]]
420
+ });
421
+ break;
422
+ case "-":
423
+ this.constraints.push({
424
+ a: [
425
+ ["0x1", leftIdx],
426
+ [this.NEG_ONE, rightIdx]
427
+ ],
428
+ b: [["0x1", 0]],
429
+ c: [["0x1", varIdx]]
430
+ });
431
+ break;
432
+ default:
433
+ throw new Error(
434
+ `Unsupported operator in variable initializer: ${operator}`
435
+ );
436
+ }
437
+ }
438
+ /**
439
+ * Process an assignment: x = expr
440
+ * Updates the witness mapping
441
+ */
442
+ processAssignment(target, value) {
443
+ const existingIdx = this.witnessMap.get(target);
444
+ if (existingIdx === void 0) {
445
+ throw new Error(`Assignment to undeclared variable: ${target}`);
446
+ }
447
+ if (value.kind === "identifier") {
448
+ const valueIdx = this.getOrCreateWitness(value);
449
+ this.constraints.push({
450
+ a: [
451
+ ["0x1", existingIdx],
452
+ [this.NEG_ONE, valueIdx]
453
+ ],
454
+ b: [["0x1", 0]],
455
+ c: []
456
+ });
457
+ } else if (value.kind === "binary") {
458
+ this.processVariableInitBinary(existingIdx, value);
459
+ }
460
+ }
461
+ /**
462
+ * Get or create a witness index for an expression
463
+ */
464
+ getOrCreateWitness(expr) {
465
+ if (expr.kind === "identifier") {
466
+ const existing = this.witnessMap.get(expr.name);
467
+ if (existing !== void 0) {
468
+ return existing;
469
+ }
470
+ const idx = this.nextWitnessIdx++;
471
+ this.witnessMap.set(expr.name, idx);
472
+ return idx;
473
+ }
474
+ if (expr.kind === "literal") {
475
+ const idx = this.nextWitnessIdx++;
476
+ return idx;
477
+ }
478
+ if (expr.kind === "binary") {
479
+ const idx = this.nextWitnessIdx++;
480
+ this.processVariableInitBinary(idx, expr);
481
+ return idx;
482
+ }
483
+ if (expr.kind === "unary") {
484
+ const operandIdx = this.getOrCreateWitness(expr.operand);
485
+ if (expr.operator === "-") {
486
+ const idx = this.nextWitnessIdx++;
487
+ this.constraints.push({
488
+ a: [[this.NEG_ONE, operandIdx]],
489
+ b: [["0x1", 0]],
490
+ c: [["0x1", idx]]
491
+ });
492
+ return idx;
493
+ }
494
+ throw new Error(`Unsupported unary operator: ${expr.operator}`);
495
+ }
496
+ throw new Error(`Unsupported expression kind: ${expr.kind}`);
497
+ }
498
+ };
499
+ }
500
+ });
501
+
128
502
  // src/infra/provingSystems/ArkworksWasm.ts
129
503
  var ArkworksWasm_exports = {};
130
504
  __export(ArkworksWasm_exports, {
@@ -258,6 +632,7 @@ var init_ArkworksWasm = __esm({
258
632
  import_noir_wasm2 = require("@noir-lang/noir_wasm");
259
633
  import_noir_js2 = require("@noir-lang/noir_js");
260
634
  import_acvm_js = require("@noir-lang/acvm_js");
635
+ init_R1csBuilder();
261
636
  import_meta = {};
262
637
  wasmModule = null;
263
638
  wasmInitPromise2 = null;
@@ -272,8 +647,11 @@ var init_ArkworksWasm = __esm({
272
647
  }
273
648
  /**
274
649
  * Compile Noir code to a circuit with ACIR for Groth16 proving
650
+ *
651
+ * @param noirCode - The Noir source code to compile
652
+ * @param options - Optional compilation options including ParsedCircuit for dynamic R1CS
275
653
  */
276
- async compile(noirCode) {
654
+ async compile(noirCode, options) {
277
655
  const wasm = await initWasm();
278
656
  const { basePath, cleanup } = await createTempDir2();
279
657
  const fm = (0, import_noir_wasm2.createFileManager)(basePath);
@@ -298,36 +676,52 @@ authors = [""]
298
676
  throw new Error("Compilation failed: no bytecode generated");
299
677
  }
300
678
  const parameters = compiled.abi.parameters;
301
- const publicR1csIndices = [];
302
- const privateR1csIndices = [];
679
+ let r1cs;
303
680
  const witnessIndexMapping = /* @__PURE__ */ new Map();
304
- parameters.forEach((p, noirIndex) => {
305
- const r1csIndex = noirIndex + 1;
306
- witnessIndexMapping.set(noirIndex, r1csIndex);
307
- if (p.visibility === "public") {
308
- publicR1csIndices.push(r1csIndex);
309
- } else if (p.visibility === "private") {
310
- privateR1csIndices.push(r1csIndex);
311
- }
312
- });
313
- const r1cs = {
314
- num_witnesses: parameters.length + 1,
315
- // +1 for w_0
316
- public_inputs: publicR1csIndices,
317
- private_inputs: privateR1csIndices,
318
- constraints: []
319
- };
320
- if (privateR1csIndices.length === 1 && publicR1csIndices.length === 1) {
321
- const privateIdx = privateR1csIndices[0];
322
- const publicIdx = publicR1csIndices[0];
323
- r1cs.constraints.push({
324
- a: [["0x1", privateIdx]],
325
- // secret
326
- b: [["0x1", privateIdx]],
327
- // secret
328
- c: [["0x1", publicIdx]]
329
- // expected
681
+ if (options?.parsedCircuit) {
682
+ const builder = new R1csBuilder(options.parsedCircuit);
683
+ r1cs = builder.build();
684
+ parameters.forEach((p, noirIndex) => {
685
+ const r1csIndex = noirIndex + 1;
686
+ witnessIndexMapping.set(noirIndex, r1csIndex);
687
+ });
688
+ console.log("=== R1CS BUILDER DEBUG ===");
689
+ console.log("ParsedCircuit publicParams:", options.parsedCircuit.publicParams);
690
+ console.log("ParsedCircuit privateParams:", options.parsedCircuit.privateParams);
691
+ console.log("ParsedCircuit statements:", JSON.stringify(options.parsedCircuit.statements, null, 2));
692
+ console.log("Generated R1CS:", JSON.stringify(r1cs, null, 2));
693
+ console.log("==========================");
694
+ } else {
695
+ const publicR1csIndices = [];
696
+ const privateR1csIndices = [];
697
+ parameters.forEach((p, noirIndex) => {
698
+ const r1csIndex = noirIndex + 1;
699
+ witnessIndexMapping.set(noirIndex, r1csIndex);
700
+ if (p.visibility === "public") {
701
+ publicR1csIndices.push(r1csIndex);
702
+ } else if (p.visibility === "private") {
703
+ privateR1csIndices.push(r1csIndex);
704
+ }
330
705
  });
706
+ r1cs = {
707
+ num_witnesses: parameters.length + 1,
708
+ public_inputs: publicR1csIndices,
709
+ private_inputs: privateR1csIndices,
710
+ constraints: []
711
+ };
712
+ if (privateR1csIndices.length === 1 && publicR1csIndices.length === 1) {
713
+ const privateIdx = privateR1csIndices[0];
714
+ const publicIdx = publicR1csIndices[0];
715
+ r1cs.constraints.push({
716
+ a: [["0x1", privateIdx]],
717
+ b: [["0x1", privateIdx]],
718
+ c: [["0x1", publicIdx]]
719
+ });
720
+ }
721
+ console.log("=== R1CS HARDCODED DEBUG ===");
722
+ console.log("Using hardcoded R1CS pattern (no ParsedCircuit provided)");
723
+ console.log("R1CS:", JSON.stringify(r1cs, null, 2));
724
+ console.log("============================");
331
725
  }
332
726
  const r1csJson = JSON.stringify(r1cs);
333
727
  let provingKey;
@@ -344,7 +738,7 @@ authors = [""]
344
738
  }
345
739
  }
346
740
  const acirJson = JSON.stringify({
347
- functions: [{ current_witness_index: parameters.length, opcodes: [], private_parameters: privateR1csIndices, public_parameters: { witnesses: publicR1csIndices }, return_values: { witnesses: [] } }]
741
+ functions: [{ current_witness_index: parameters.length, opcodes: [], private_parameters: r1cs.private_inputs, public_parameters: { witnesses: r1cs.public_inputs }, return_values: { witnesses: [] } }]
348
742
  });
349
743
  const arkworksCircuit = {
350
744
  ...compiled,
@@ -580,6 +974,7 @@ __export(index_exports, {
580
974
  Network: () => Network,
581
975
  OffchainVerifier: () => OffchainVerifier,
582
976
  Provider: () => Provider,
977
+ R1csBuilder: () => R1csBuilder,
583
978
  SolanaFormatter: () => SolanaFormatter,
584
979
  SolanaTransactionBuilder: () => SolanaTransactionBuilder,
585
980
  VkDeploymentManager: () => VkDeploymentManager,
@@ -1193,16 +1588,20 @@ var IziNoir = class _IziNoir {
1193
1588
  * After compile(), the verifying key is available via `this.vk`.
1194
1589
  *
1195
1590
  * @param noirCode - The Noir source code to compile
1591
+ * @param options - Optional compilation options including ParsedCircuit for dynamic R1CS
1196
1592
  * @returns CompileResult with circuit and verifying key
1197
1593
  *
1198
1594
  * @example
1199
1595
  * ```typescript
1596
+ * // Basic usage
1200
1597
  * const { circuit, verifyingKey } = await izi.compile(noirCode);
1201
- * console.log('VK:', izi.vk); // Available immediately after compile
1598
+ *
1599
+ * // With ParsedCircuit for dynamic R1CS generation
1600
+ * const { circuit } = await izi.compile(noirCode, { parsedCircuit });
1202
1601
  * ```
1203
1602
  */
1204
- async compile(noirCode) {
1205
- this.compiledCircuit = await this.provingSystem.compile(noirCode);
1603
+ async compile(noirCode, options) {
1604
+ this.compiledCircuit = await this.provingSystem.compile(noirCode, options);
1206
1605
  const vk = await this.extractVerifyingKey(this.compiledCircuit);
1207
1606
  if (vk) {
1208
1607
  this._verifyingKey = vk;
@@ -1625,6 +2024,7 @@ Check on explorer: ${getExplorerTxUrl(this._network, signature)}`
1625
2024
  init_SolanaFormatter();
1626
2025
  init_Barretenberg();
1627
2026
  init_ArkworksWasm();
2027
+ init_R1csBuilder();
1628
2028
 
1629
2029
  // src/infra/parser/AcornParser.ts
1630
2030
  var acorn = __toESM(require("acorn"), 1);
@@ -3169,6 +3569,7 @@ function defineConfig(config) {
3169
3569
  Network,
3170
3570
  OffchainVerifier,
3171
3571
  Provider,
3572
+ R1csBuilder,
3172
3573
  SolanaFormatter,
3173
3574
  SolanaTransactionBuilder,
3174
3575
  VkDeploymentManager,