@izi-noir/sdk 0.1.13 → 0.1.14

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
@@ -146,6 +146,8 @@ var init_R1csBuilder = __esm({
146
146
  // Fr modulus = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001
147
147
  // -1 mod Fr = Fr - 1
148
148
  NEG_ONE = "0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000";
149
+ // Number of bits for range checks (64 bits handles values up to ~18 quintillion)
150
+ COMPARISON_BITS = 64;
149
151
  /**
150
152
  * Build R1CS definition from the parsed circuit
151
153
  */
@@ -255,13 +257,18 @@ var init_R1csBuilder = __esm({
255
257
  throw new Error(
256
258
  `Arithmetic operator ${operator} must be part of an equality assertion. Use: assert(a ${operator} b == c)`
257
259
  );
258
- case "<":
260
+ case ">=":
261
+ this.processGreaterThanOrEqual(left, right);
262
+ break;
259
263
  case ">":
264
+ this.processGreaterThan(left, right);
265
+ break;
260
266
  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
- );
267
+ this.processGreaterThanOrEqual(right, left);
268
+ break;
269
+ case "<":
270
+ this.processGreaterThan(right, left);
271
+ break;
265
272
  case "&":
266
273
  case "|":
267
274
  throw new Error(
@@ -368,6 +375,83 @@ var init_R1csBuilder = __esm({
368
375
  // = c
369
376
  });
370
377
  }
378
+ /**
379
+ * Process greater than or equal: assert(a >= b)
380
+ * Uses bit decomposition to prove that a - b is non-negative.
381
+ *
382
+ * The approach:
383
+ * 1. Create diff = a - b
384
+ * 2. Decompose diff into COMPARISON_BITS bits
385
+ * 3. For each bit: bit_i * (1 - bit_i) = 0 (ensures 0 or 1)
386
+ * 4. Sum of bits * powers of 2 = diff
387
+ *
388
+ * If decomposition succeeds, diff is in [0, 2^COMPARISON_BITS - 1], so a >= b
389
+ */
390
+ processGreaterThanOrEqual(left, right) {
391
+ const leftIdx = this.getOrCreateWitness(left);
392
+ const rightIdx = this.getOrCreateWitness(right);
393
+ const diffIdx = this.nextWitnessIdx++;
394
+ this.constraints.push({
395
+ a: [
396
+ ["0x1", leftIdx],
397
+ [this.NEG_ONE, rightIdx]
398
+ ],
399
+ b: [["0x1", 0]],
400
+ // * 1
401
+ c: [["0x1", diffIdx]]
402
+ });
403
+ this.addBitDecompositionConstraints(diffIdx);
404
+ }
405
+ /**
406
+ * Process greater than: assert(a > b)
407
+ * Equivalent to assert(a - b - 1 >= 0), or assert(a >= b + 1)
408
+ */
409
+ processGreaterThan(left, right) {
410
+ const leftIdx = this.getOrCreateWitness(left);
411
+ const rightIdx = this.getOrCreateWitness(right);
412
+ const diffIdx = this.nextWitnessIdx++;
413
+ this.constraints.push({
414
+ a: [
415
+ ["0x1", leftIdx],
416
+ [this.NEG_ONE, rightIdx],
417
+ [this.NEG_ONE, 0]
418
+ // -1 (using w_0 = 1)
419
+ ],
420
+ b: [["0x1", 0]],
421
+ // * 1
422
+ c: [["0x1", diffIdx]]
423
+ });
424
+ this.addBitDecompositionConstraints(diffIdx);
425
+ }
426
+ /**
427
+ * Add bit decomposition constraints for a value.
428
+ * Creates COMPARISON_BITS witnesses for the bits and constrains:
429
+ * 1. Each bit is 0 or 1: bit * (1 - bit) = 0
430
+ * 2. Sum of bits * 2^i = value
431
+ */
432
+ addBitDecompositionConstraints(valueIdx) {
433
+ const bitIndices = [];
434
+ for (let i = 0; i < this.COMPARISON_BITS; i++) {
435
+ const bitIdx = this.nextWitnessIdx++;
436
+ bitIndices.push(bitIdx);
437
+ this.constraints.push({
438
+ a: [["0x1", bitIdx]],
439
+ b: [["0x1", bitIdx]],
440
+ c: [["0x1", bitIdx]]
441
+ });
442
+ }
443
+ const sumTerms = [];
444
+ for (let i = 0; i < this.COMPARISON_BITS; i++) {
445
+ const coeff = (1n << BigInt(i)).toString(16);
446
+ sumTerms.push([`0x${coeff}`, bitIndices[i]]);
447
+ }
448
+ this.constraints.push({
449
+ a: sumTerms,
450
+ b: [["0x1", 0]],
451
+ // * 1
452
+ c: [["0x1", valueIdx]]
453
+ });
454
+ }
371
455
  /**
372
456
  * Process a variable declaration: let x = expr
373
457
  * Creates a new witness for x and adds constraint if needed
package/dist/index.d.cts CHANGED
@@ -108,6 +108,7 @@ declare class R1csBuilder {
108
108
  private publicIndices;
109
109
  private privateIndices;
110
110
  private readonly NEG_ONE;
111
+ private readonly COMPARISON_BITS;
111
112
  constructor(parsedCircuit: ParsedCircuit);
112
113
  /**
113
114
  * Build R1CS definition from the parsed circuit
@@ -156,6 +157,31 @@ declare class R1csBuilder {
156
157
  * R1CS: (a - b) * 1 = c
157
158
  */
158
159
  private processSubtractionEquality;
160
+ /**
161
+ * Process greater than or equal: assert(a >= b)
162
+ * Uses bit decomposition to prove that a - b is non-negative.
163
+ *
164
+ * The approach:
165
+ * 1. Create diff = a - b
166
+ * 2. Decompose diff into COMPARISON_BITS bits
167
+ * 3. For each bit: bit_i * (1 - bit_i) = 0 (ensures 0 or 1)
168
+ * 4. Sum of bits * powers of 2 = diff
169
+ *
170
+ * If decomposition succeeds, diff is in [0, 2^COMPARISON_BITS - 1], so a >= b
171
+ */
172
+ private processGreaterThanOrEqual;
173
+ /**
174
+ * Process greater than: assert(a > b)
175
+ * Equivalent to assert(a - b - 1 >= 0), or assert(a >= b + 1)
176
+ */
177
+ private processGreaterThan;
178
+ /**
179
+ * Add bit decomposition constraints for a value.
180
+ * Creates COMPARISON_BITS witnesses for the bits and constrains:
181
+ * 1. Each bit is 0 or 1: bit * (1 - bit) = 0
182
+ * 2. Sum of bits * 2^i = value
183
+ */
184
+ private addBitDecompositionConstraints;
159
185
  /**
160
186
  * Process a variable declaration: let x = expr
161
187
  * Creates a new witness for x and adds constraint if needed
package/dist/index.d.ts CHANGED
@@ -108,6 +108,7 @@ declare class R1csBuilder {
108
108
  private publicIndices;
109
109
  private privateIndices;
110
110
  private readonly NEG_ONE;
111
+ private readonly COMPARISON_BITS;
111
112
  constructor(parsedCircuit: ParsedCircuit);
112
113
  /**
113
114
  * Build R1CS definition from the parsed circuit
@@ -156,6 +157,31 @@ declare class R1csBuilder {
156
157
  * R1CS: (a - b) * 1 = c
157
158
  */
158
159
  private processSubtractionEquality;
160
+ /**
161
+ * Process greater than or equal: assert(a >= b)
162
+ * Uses bit decomposition to prove that a - b is non-negative.
163
+ *
164
+ * The approach:
165
+ * 1. Create diff = a - b
166
+ * 2. Decompose diff into COMPARISON_BITS bits
167
+ * 3. For each bit: bit_i * (1 - bit_i) = 0 (ensures 0 or 1)
168
+ * 4. Sum of bits * powers of 2 = diff
169
+ *
170
+ * If decomposition succeeds, diff is in [0, 2^COMPARISON_BITS - 1], so a >= b
171
+ */
172
+ private processGreaterThanOrEqual;
173
+ /**
174
+ * Process greater than: assert(a > b)
175
+ * Equivalent to assert(a - b - 1 >= 0), or assert(a >= b + 1)
176
+ */
177
+ private processGreaterThan;
178
+ /**
179
+ * Add bit decomposition constraints for a value.
180
+ * Creates COMPARISON_BITS witnesses for the bits and constrains:
181
+ * 1. Each bit is 0 or 1: bit * (1 - bit) = 0
182
+ * 2. Sum of bits * 2^i = value
183
+ */
184
+ private addBitDecompositionConstraints;
159
185
  /**
160
186
  * Process a variable declaration: let x = expr
161
187
  * Creates a new witness for x and adds constraint if needed
package/dist/index.js CHANGED
@@ -124,6 +124,8 @@ var init_R1csBuilder = __esm({
124
124
  // Fr modulus = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001
125
125
  // -1 mod Fr = Fr - 1
126
126
  NEG_ONE = "0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000";
127
+ // Number of bits for range checks (64 bits handles values up to ~18 quintillion)
128
+ COMPARISON_BITS = 64;
127
129
  /**
128
130
  * Build R1CS definition from the parsed circuit
129
131
  */
@@ -233,13 +235,18 @@ var init_R1csBuilder = __esm({
233
235
  throw new Error(
234
236
  `Arithmetic operator ${operator} must be part of an equality assertion. Use: assert(a ${operator} b == c)`
235
237
  );
236
- case "<":
238
+ case ">=":
239
+ this.processGreaterThanOrEqual(left, right);
240
+ break;
237
241
  case ">":
242
+ this.processGreaterThan(left, right);
243
+ break;
238
244
  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
- );
245
+ this.processGreaterThanOrEqual(right, left);
246
+ break;
247
+ case "<":
248
+ this.processGreaterThan(right, left);
249
+ break;
243
250
  case "&":
244
251
  case "|":
245
252
  throw new Error(
@@ -346,6 +353,83 @@ var init_R1csBuilder = __esm({
346
353
  // = c
347
354
  });
348
355
  }
356
+ /**
357
+ * Process greater than or equal: assert(a >= b)
358
+ * Uses bit decomposition to prove that a - b is non-negative.
359
+ *
360
+ * The approach:
361
+ * 1. Create diff = a - b
362
+ * 2. Decompose diff into COMPARISON_BITS bits
363
+ * 3. For each bit: bit_i * (1 - bit_i) = 0 (ensures 0 or 1)
364
+ * 4. Sum of bits * powers of 2 = diff
365
+ *
366
+ * If decomposition succeeds, diff is in [0, 2^COMPARISON_BITS - 1], so a >= b
367
+ */
368
+ processGreaterThanOrEqual(left, right) {
369
+ const leftIdx = this.getOrCreateWitness(left);
370
+ const rightIdx = this.getOrCreateWitness(right);
371
+ const diffIdx = this.nextWitnessIdx++;
372
+ this.constraints.push({
373
+ a: [
374
+ ["0x1", leftIdx],
375
+ [this.NEG_ONE, rightIdx]
376
+ ],
377
+ b: [["0x1", 0]],
378
+ // * 1
379
+ c: [["0x1", diffIdx]]
380
+ });
381
+ this.addBitDecompositionConstraints(diffIdx);
382
+ }
383
+ /**
384
+ * Process greater than: assert(a > b)
385
+ * Equivalent to assert(a - b - 1 >= 0), or assert(a >= b + 1)
386
+ */
387
+ processGreaterThan(left, right) {
388
+ const leftIdx = this.getOrCreateWitness(left);
389
+ const rightIdx = this.getOrCreateWitness(right);
390
+ const diffIdx = this.nextWitnessIdx++;
391
+ this.constraints.push({
392
+ a: [
393
+ ["0x1", leftIdx],
394
+ [this.NEG_ONE, rightIdx],
395
+ [this.NEG_ONE, 0]
396
+ // -1 (using w_0 = 1)
397
+ ],
398
+ b: [["0x1", 0]],
399
+ // * 1
400
+ c: [["0x1", diffIdx]]
401
+ });
402
+ this.addBitDecompositionConstraints(diffIdx);
403
+ }
404
+ /**
405
+ * Add bit decomposition constraints for a value.
406
+ * Creates COMPARISON_BITS witnesses for the bits and constrains:
407
+ * 1. Each bit is 0 or 1: bit * (1 - bit) = 0
408
+ * 2. Sum of bits * 2^i = value
409
+ */
410
+ addBitDecompositionConstraints(valueIdx) {
411
+ const bitIndices = [];
412
+ for (let i = 0; i < this.COMPARISON_BITS; i++) {
413
+ const bitIdx = this.nextWitnessIdx++;
414
+ bitIndices.push(bitIdx);
415
+ this.constraints.push({
416
+ a: [["0x1", bitIdx]],
417
+ b: [["0x1", bitIdx]],
418
+ c: [["0x1", bitIdx]]
419
+ });
420
+ }
421
+ const sumTerms = [];
422
+ for (let i = 0; i < this.COMPARISON_BITS; i++) {
423
+ const coeff = (1n << BigInt(i)).toString(16);
424
+ sumTerms.push([`0x${coeff}`, bitIndices[i]]);
425
+ }
426
+ this.constraints.push({
427
+ a: sumTerms,
428
+ b: [["0x1", 0]],
429
+ // * 1
430
+ c: [["0x1", valueIdx]]
431
+ });
432
+ }
349
433
  /**
350
434
  * Process a variable declaration: let x = expr
351
435
  * Creates a new witness for x and adds constraint if needed
@@ -49,6 +49,8 @@ var init_R1csBuilder = __esm({
49
49
  // Fr modulus = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001
50
50
  // -1 mod Fr = Fr - 1
51
51
  NEG_ONE = "0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000";
52
+ // Number of bits for range checks (64 bits handles values up to ~18 quintillion)
53
+ COMPARISON_BITS = 64;
52
54
  /**
53
55
  * Build R1CS definition from the parsed circuit
54
56
  */
@@ -158,13 +160,18 @@ var init_R1csBuilder = __esm({
158
160
  throw new Error(
159
161
  `Arithmetic operator ${operator} must be part of an equality assertion. Use: assert(a ${operator} b == c)`
160
162
  );
161
- case "<":
163
+ case ">=":
164
+ this.processGreaterThanOrEqual(left, right);
165
+ break;
162
166
  case ">":
167
+ this.processGreaterThan(left, right);
168
+ break;
163
169
  case "<=":
164
- case ">=":
165
- throw new Error(
166
- `Comparison operators (${operator}) require range proofs which are not yet supported. Use the Barretenberg backend for comparison operations.`
167
- );
170
+ this.processGreaterThanOrEqual(right, left);
171
+ break;
172
+ case "<":
173
+ this.processGreaterThan(right, left);
174
+ break;
168
175
  case "&":
169
176
  case "|":
170
177
  throw new Error(
@@ -271,6 +278,83 @@ var init_R1csBuilder = __esm({
271
278
  // = c
272
279
  });
273
280
  }
281
+ /**
282
+ * Process greater than or equal: assert(a >= b)
283
+ * Uses bit decomposition to prove that a - b is non-negative.
284
+ *
285
+ * The approach:
286
+ * 1. Create diff = a - b
287
+ * 2. Decompose diff into COMPARISON_BITS bits
288
+ * 3. For each bit: bit_i * (1 - bit_i) = 0 (ensures 0 or 1)
289
+ * 4. Sum of bits * powers of 2 = diff
290
+ *
291
+ * If decomposition succeeds, diff is in [0, 2^COMPARISON_BITS - 1], so a >= b
292
+ */
293
+ processGreaterThanOrEqual(left, right) {
294
+ const leftIdx = this.getOrCreateWitness(left);
295
+ const rightIdx = this.getOrCreateWitness(right);
296
+ const diffIdx = this.nextWitnessIdx++;
297
+ this.constraints.push({
298
+ a: [
299
+ ["0x1", leftIdx],
300
+ [this.NEG_ONE, rightIdx]
301
+ ],
302
+ b: [["0x1", 0]],
303
+ // * 1
304
+ c: [["0x1", diffIdx]]
305
+ });
306
+ this.addBitDecompositionConstraints(diffIdx);
307
+ }
308
+ /**
309
+ * Process greater than: assert(a > b)
310
+ * Equivalent to assert(a - b - 1 >= 0), or assert(a >= b + 1)
311
+ */
312
+ processGreaterThan(left, right) {
313
+ const leftIdx = this.getOrCreateWitness(left);
314
+ const rightIdx = this.getOrCreateWitness(right);
315
+ const diffIdx = this.nextWitnessIdx++;
316
+ this.constraints.push({
317
+ a: [
318
+ ["0x1", leftIdx],
319
+ [this.NEG_ONE, rightIdx],
320
+ [this.NEG_ONE, 0]
321
+ // -1 (using w_0 = 1)
322
+ ],
323
+ b: [["0x1", 0]],
324
+ // * 1
325
+ c: [["0x1", diffIdx]]
326
+ });
327
+ this.addBitDecompositionConstraints(diffIdx);
328
+ }
329
+ /**
330
+ * Add bit decomposition constraints for a value.
331
+ * Creates COMPARISON_BITS witnesses for the bits and constrains:
332
+ * 1. Each bit is 0 or 1: bit * (1 - bit) = 0
333
+ * 2. Sum of bits * 2^i = value
334
+ */
335
+ addBitDecompositionConstraints(valueIdx) {
336
+ const bitIndices = [];
337
+ for (let i = 0; i < this.COMPARISON_BITS; i++) {
338
+ const bitIdx = this.nextWitnessIdx++;
339
+ bitIndices.push(bitIdx);
340
+ this.constraints.push({
341
+ a: [["0x1", bitIdx]],
342
+ b: [["0x1", bitIdx]],
343
+ c: [["0x1", bitIdx]]
344
+ });
345
+ }
346
+ const sumTerms = [];
347
+ for (let i = 0; i < this.COMPARISON_BITS; i++) {
348
+ const coeff = (1n << BigInt(i)).toString(16);
349
+ sumTerms.push([`0x${coeff}`, bitIndices[i]]);
350
+ }
351
+ this.constraints.push({
352
+ a: sumTerms,
353
+ b: [["0x1", 0]],
354
+ // * 1
355
+ c: [["0x1", valueIdx]]
356
+ });
357
+ }
274
358
  /**
275
359
  * Process a variable declaration: let x = expr
276
360
  * Creates a new witness for x and adds constraint if needed
@@ -27,6 +27,8 @@ var init_R1csBuilder = __esm({
27
27
  // Fr modulus = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001
28
28
  // -1 mod Fr = Fr - 1
29
29
  NEG_ONE = "0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000";
30
+ // Number of bits for range checks (64 bits handles values up to ~18 quintillion)
31
+ COMPARISON_BITS = 64;
30
32
  /**
31
33
  * Build R1CS definition from the parsed circuit
32
34
  */
@@ -136,13 +138,18 @@ var init_R1csBuilder = __esm({
136
138
  throw new Error(
137
139
  `Arithmetic operator ${operator} must be part of an equality assertion. Use: assert(a ${operator} b == c)`
138
140
  );
139
- case "<":
141
+ case ">=":
142
+ this.processGreaterThanOrEqual(left, right);
143
+ break;
140
144
  case ">":
145
+ this.processGreaterThan(left, right);
146
+ break;
141
147
  case "<=":
142
- case ">=":
143
- throw new Error(
144
- `Comparison operators (${operator}) require range proofs which are not yet supported. Use the Barretenberg backend for comparison operations.`
145
- );
148
+ this.processGreaterThanOrEqual(right, left);
149
+ break;
150
+ case "<":
151
+ this.processGreaterThan(right, left);
152
+ break;
146
153
  case "&":
147
154
  case "|":
148
155
  throw new Error(
@@ -249,6 +256,83 @@ var init_R1csBuilder = __esm({
249
256
  // = c
250
257
  });
251
258
  }
259
+ /**
260
+ * Process greater than or equal: assert(a >= b)
261
+ * Uses bit decomposition to prove that a - b is non-negative.
262
+ *
263
+ * The approach:
264
+ * 1. Create diff = a - b
265
+ * 2. Decompose diff into COMPARISON_BITS bits
266
+ * 3. For each bit: bit_i * (1 - bit_i) = 0 (ensures 0 or 1)
267
+ * 4. Sum of bits * powers of 2 = diff
268
+ *
269
+ * If decomposition succeeds, diff is in [0, 2^COMPARISON_BITS - 1], so a >= b
270
+ */
271
+ processGreaterThanOrEqual(left, right) {
272
+ const leftIdx = this.getOrCreateWitness(left);
273
+ const rightIdx = this.getOrCreateWitness(right);
274
+ const diffIdx = this.nextWitnessIdx++;
275
+ this.constraints.push({
276
+ a: [
277
+ ["0x1", leftIdx],
278
+ [this.NEG_ONE, rightIdx]
279
+ ],
280
+ b: [["0x1", 0]],
281
+ // * 1
282
+ c: [["0x1", diffIdx]]
283
+ });
284
+ this.addBitDecompositionConstraints(diffIdx);
285
+ }
286
+ /**
287
+ * Process greater than: assert(a > b)
288
+ * Equivalent to assert(a - b - 1 >= 0), or assert(a >= b + 1)
289
+ */
290
+ processGreaterThan(left, right) {
291
+ const leftIdx = this.getOrCreateWitness(left);
292
+ const rightIdx = this.getOrCreateWitness(right);
293
+ const diffIdx = this.nextWitnessIdx++;
294
+ this.constraints.push({
295
+ a: [
296
+ ["0x1", leftIdx],
297
+ [this.NEG_ONE, rightIdx],
298
+ [this.NEG_ONE, 0]
299
+ // -1 (using w_0 = 1)
300
+ ],
301
+ b: [["0x1", 0]],
302
+ // * 1
303
+ c: [["0x1", diffIdx]]
304
+ });
305
+ this.addBitDecompositionConstraints(diffIdx);
306
+ }
307
+ /**
308
+ * Add bit decomposition constraints for a value.
309
+ * Creates COMPARISON_BITS witnesses for the bits and constrains:
310
+ * 1. Each bit is 0 or 1: bit * (1 - bit) = 0
311
+ * 2. Sum of bits * 2^i = value
312
+ */
313
+ addBitDecompositionConstraints(valueIdx) {
314
+ const bitIndices = [];
315
+ for (let i = 0; i < this.COMPARISON_BITS; i++) {
316
+ const bitIdx = this.nextWitnessIdx++;
317
+ bitIndices.push(bitIdx);
318
+ this.constraints.push({
319
+ a: [["0x1", bitIdx]],
320
+ b: [["0x1", bitIdx]],
321
+ c: [["0x1", bitIdx]]
322
+ });
323
+ }
324
+ const sumTerms = [];
325
+ for (let i = 0; i < this.COMPARISON_BITS; i++) {
326
+ const coeff = (1n << BigInt(i)).toString(16);
327
+ sumTerms.push([`0x${coeff}`, bitIndices[i]]);
328
+ }
329
+ this.constraints.push({
330
+ a: sumTerms,
331
+ b: [["0x1", 0]],
332
+ // * 1
333
+ c: [["0x1", valueIdx]]
334
+ });
335
+ }
252
336
  /**
253
337
  * Process a variable declaration: let x = expr
254
338
  * Creates a new witness for x and adds constraint if needed
@@ -146,6 +146,8 @@ var init_R1csBuilder = __esm({
146
146
  // Fr modulus = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001
147
147
  // -1 mod Fr = Fr - 1
148
148
  NEG_ONE = "0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000";
149
+ // Number of bits for range checks (64 bits handles values up to ~18 quintillion)
150
+ COMPARISON_BITS = 64;
149
151
  /**
150
152
  * Build R1CS definition from the parsed circuit
151
153
  */
@@ -255,13 +257,18 @@ var init_R1csBuilder = __esm({
255
257
  throw new Error(
256
258
  `Arithmetic operator ${operator} must be part of an equality assertion. Use: assert(a ${operator} b == c)`
257
259
  );
258
- case "<":
260
+ case ">=":
261
+ this.processGreaterThanOrEqual(left, right);
262
+ break;
259
263
  case ">":
264
+ this.processGreaterThan(left, right);
265
+ break;
260
266
  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
- );
267
+ this.processGreaterThanOrEqual(right, left);
268
+ break;
269
+ case "<":
270
+ this.processGreaterThan(right, left);
271
+ break;
265
272
  case "&":
266
273
  case "|":
267
274
  throw new Error(
@@ -368,6 +375,83 @@ var init_R1csBuilder = __esm({
368
375
  // = c
369
376
  });
370
377
  }
378
+ /**
379
+ * Process greater than or equal: assert(a >= b)
380
+ * Uses bit decomposition to prove that a - b is non-negative.
381
+ *
382
+ * The approach:
383
+ * 1. Create diff = a - b
384
+ * 2. Decompose diff into COMPARISON_BITS bits
385
+ * 3. For each bit: bit_i * (1 - bit_i) = 0 (ensures 0 or 1)
386
+ * 4. Sum of bits * powers of 2 = diff
387
+ *
388
+ * If decomposition succeeds, diff is in [0, 2^COMPARISON_BITS - 1], so a >= b
389
+ */
390
+ processGreaterThanOrEqual(left, right) {
391
+ const leftIdx = this.getOrCreateWitness(left);
392
+ const rightIdx = this.getOrCreateWitness(right);
393
+ const diffIdx = this.nextWitnessIdx++;
394
+ this.constraints.push({
395
+ a: [
396
+ ["0x1", leftIdx],
397
+ [this.NEG_ONE, rightIdx]
398
+ ],
399
+ b: [["0x1", 0]],
400
+ // * 1
401
+ c: [["0x1", diffIdx]]
402
+ });
403
+ this.addBitDecompositionConstraints(diffIdx);
404
+ }
405
+ /**
406
+ * Process greater than: assert(a > b)
407
+ * Equivalent to assert(a - b - 1 >= 0), or assert(a >= b + 1)
408
+ */
409
+ processGreaterThan(left, right) {
410
+ const leftIdx = this.getOrCreateWitness(left);
411
+ const rightIdx = this.getOrCreateWitness(right);
412
+ const diffIdx = this.nextWitnessIdx++;
413
+ this.constraints.push({
414
+ a: [
415
+ ["0x1", leftIdx],
416
+ [this.NEG_ONE, rightIdx],
417
+ [this.NEG_ONE, 0]
418
+ // -1 (using w_0 = 1)
419
+ ],
420
+ b: [["0x1", 0]],
421
+ // * 1
422
+ c: [["0x1", diffIdx]]
423
+ });
424
+ this.addBitDecompositionConstraints(diffIdx);
425
+ }
426
+ /**
427
+ * Add bit decomposition constraints for a value.
428
+ * Creates COMPARISON_BITS witnesses for the bits and constrains:
429
+ * 1. Each bit is 0 or 1: bit * (1 - bit) = 0
430
+ * 2. Sum of bits * 2^i = value
431
+ */
432
+ addBitDecompositionConstraints(valueIdx) {
433
+ const bitIndices = [];
434
+ for (let i = 0; i < this.COMPARISON_BITS; i++) {
435
+ const bitIdx = this.nextWitnessIdx++;
436
+ bitIndices.push(bitIdx);
437
+ this.constraints.push({
438
+ a: [["0x1", bitIdx]],
439
+ b: [["0x1", bitIdx]],
440
+ c: [["0x1", bitIdx]]
441
+ });
442
+ }
443
+ const sumTerms = [];
444
+ for (let i = 0; i < this.COMPARISON_BITS; i++) {
445
+ const coeff = (1n << BigInt(i)).toString(16);
446
+ sumTerms.push([`0x${coeff}`, bitIndices[i]]);
447
+ }
448
+ this.constraints.push({
449
+ a: sumTerms,
450
+ b: [["0x1", 0]],
451
+ // * 1
452
+ c: [["0x1", valueIdx]]
453
+ });
454
+ }
371
455
  /**
372
456
  * Process a variable declaration: let x = expr
373
457
  * Creates a new witness for x and adds constraint if needed
@@ -124,6 +124,8 @@ var init_R1csBuilder = __esm({
124
124
  // Fr modulus = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001
125
125
  // -1 mod Fr = Fr - 1
126
126
  NEG_ONE = "0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000";
127
+ // Number of bits for range checks (64 bits handles values up to ~18 quintillion)
128
+ COMPARISON_BITS = 64;
127
129
  /**
128
130
  * Build R1CS definition from the parsed circuit
129
131
  */
@@ -233,13 +235,18 @@ var init_R1csBuilder = __esm({
233
235
  throw new Error(
234
236
  `Arithmetic operator ${operator} must be part of an equality assertion. Use: assert(a ${operator} b == c)`
235
237
  );
236
- case "<":
238
+ case ">=":
239
+ this.processGreaterThanOrEqual(left, right);
240
+ break;
237
241
  case ">":
242
+ this.processGreaterThan(left, right);
243
+ break;
238
244
  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
- );
245
+ this.processGreaterThanOrEqual(right, left);
246
+ break;
247
+ case "<":
248
+ this.processGreaterThan(right, left);
249
+ break;
243
250
  case "&":
244
251
  case "|":
245
252
  throw new Error(
@@ -346,6 +353,83 @@ var init_R1csBuilder = __esm({
346
353
  // = c
347
354
  });
348
355
  }
356
+ /**
357
+ * Process greater than or equal: assert(a >= b)
358
+ * Uses bit decomposition to prove that a - b is non-negative.
359
+ *
360
+ * The approach:
361
+ * 1. Create diff = a - b
362
+ * 2. Decompose diff into COMPARISON_BITS bits
363
+ * 3. For each bit: bit_i * (1 - bit_i) = 0 (ensures 0 or 1)
364
+ * 4. Sum of bits * powers of 2 = diff
365
+ *
366
+ * If decomposition succeeds, diff is in [0, 2^COMPARISON_BITS - 1], so a >= b
367
+ */
368
+ processGreaterThanOrEqual(left, right) {
369
+ const leftIdx = this.getOrCreateWitness(left);
370
+ const rightIdx = this.getOrCreateWitness(right);
371
+ const diffIdx = this.nextWitnessIdx++;
372
+ this.constraints.push({
373
+ a: [
374
+ ["0x1", leftIdx],
375
+ [this.NEG_ONE, rightIdx]
376
+ ],
377
+ b: [["0x1", 0]],
378
+ // * 1
379
+ c: [["0x1", diffIdx]]
380
+ });
381
+ this.addBitDecompositionConstraints(diffIdx);
382
+ }
383
+ /**
384
+ * Process greater than: assert(a > b)
385
+ * Equivalent to assert(a - b - 1 >= 0), or assert(a >= b + 1)
386
+ */
387
+ processGreaterThan(left, right) {
388
+ const leftIdx = this.getOrCreateWitness(left);
389
+ const rightIdx = this.getOrCreateWitness(right);
390
+ const diffIdx = this.nextWitnessIdx++;
391
+ this.constraints.push({
392
+ a: [
393
+ ["0x1", leftIdx],
394
+ [this.NEG_ONE, rightIdx],
395
+ [this.NEG_ONE, 0]
396
+ // -1 (using w_0 = 1)
397
+ ],
398
+ b: [["0x1", 0]],
399
+ // * 1
400
+ c: [["0x1", diffIdx]]
401
+ });
402
+ this.addBitDecompositionConstraints(diffIdx);
403
+ }
404
+ /**
405
+ * Add bit decomposition constraints for a value.
406
+ * Creates COMPARISON_BITS witnesses for the bits and constrains:
407
+ * 1. Each bit is 0 or 1: bit * (1 - bit) = 0
408
+ * 2. Sum of bits * 2^i = value
409
+ */
410
+ addBitDecompositionConstraints(valueIdx) {
411
+ const bitIndices = [];
412
+ for (let i = 0; i < this.COMPARISON_BITS; i++) {
413
+ const bitIdx = this.nextWitnessIdx++;
414
+ bitIndices.push(bitIdx);
415
+ this.constraints.push({
416
+ a: [["0x1", bitIdx]],
417
+ b: [["0x1", bitIdx]],
418
+ c: [["0x1", bitIdx]]
419
+ });
420
+ }
421
+ const sumTerms = [];
422
+ for (let i = 0; i < this.COMPARISON_BITS; i++) {
423
+ const coeff = (1n << BigInt(i)).toString(16);
424
+ sumTerms.push([`0x${coeff}`, bitIndices[i]]);
425
+ }
426
+ this.constraints.push({
427
+ a: sumTerms,
428
+ b: [["0x1", 0]],
429
+ // * 1
430
+ c: [["0x1", valueIdx]]
431
+ });
432
+ }
349
433
  /**
350
434
  * Process a variable declaration: let x = expr
351
435
  * Creates a new witness for x and adds constraint if needed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@izi-noir/sdk",
3
- "version": "0.1.13",
3
+ "version": "0.1.14",
4
4
  "description": "Write ZK circuits in JavaScript/TypeScript, generate Noir code and proofs automatically",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",