@nori-zk/proof-conversion-utils 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -14,6 +14,8 @@ This package provides utilities to assist witness creation and alpha-beta pairin
14
14
 
15
15
  ## TypeScript API
16
16
 
17
+ --------------------------------------------------------------------------------------------
18
+
17
19
  ### Types
18
20
 
19
21
  #### `AffinePoint2d`
@@ -244,7 +246,6 @@ interface SnarkjsVK {
244
246
  vk_beta_2: [[string, string], [string, string], [string, string]];
245
247
  vk_gamma_2: [[string, string], [string, string], [string, string]];
246
248
  vk_delta_2: [[string, string], [string, string], [string, string]];
247
- vk_alphabeta_12: [[string, string], [string, string], [string, string]];
248
249
  IC: Array<[string, string, string]>;
249
250
  }
250
251
  ```
@@ -305,74 +306,212 @@ export interface SP1ProofWithPublicValues {
305
306
  }
306
307
  ```
307
308
 
309
+ --------------------------------------------------------------------------------------------
310
+
308
311
  ### Functions
309
312
 
310
- #### `compute_pairing(input: PairingInput): Field12`
313
+ #### `compute_aux_witness`
311
314
 
312
- Computes a pairing for a verification key.
315
+ ```typescript
316
+ export function compute_aux_witness(input: Field12): AuxWitness;
317
+ ```
318
+
319
+ Computes the auxiliary witness from a Miller loop output.
320
+
321
+ **What This Does**
322
+
323
+ Takes a 12-element field value (the result of a Miller loop pairing computation)
324
+ and computes the auxiliary witness needed for efficient verification.
325
+
326
+ The Miller loop is the first step of pairing-based verification. Its output
327
+ needs further processing (final exponentiation), which is expensive. The
328
+ auxiliary witness provides precomputed hints that make this step efficient.
329
+
330
+ **Input**
331
+
332
+ A JS object matching `Field12` structure (12 string fields: g00-g21, h00-h21).
313
333
 
314
- Takes two curve points (alpha and beta from the trusted setup) and computes their pairing using the Miller loop algorithm. The result is a 12-element field value that gets stored in the verification key.
334
+ **Output**
335
+
336
+ Return a JS object matching `AuxWitness` structure containing:
337
+ - `c`: A 12-element field value
338
+ - `shift_power`: "0", "1", or "2"
339
+
340
+ **Error**
341
+
342
+ Throws a JsError if the input is not a valid Miller loop output (fails internal assertion).
343
+
344
+ #### `compute_pairing`
315
345
 
316
346
  ```typescript
317
- const result = compute_pairing({
318
- alpha: { x: '...', y: '...' },
319
- beta: { x_c0: '...', x_c1: '...', y_c0: '...', y_c1: '...' }
320
- });
347
+ export function compute_pairing(input: PairingInput): Field12;
321
348
  ```
322
349
 
323
- #### `compute_aux_witness(input: Field12): AuxWitness`
350
+ Computes a pairing for a verification key.
324
351
 
325
- Computes the auxiliary witness from a Miller loop output.
352
+ **What This Does**
353
+
354
+ Takes two curve points (alpha and beta from the trusted setup) and computes
355
+ their pairing using the Miller loop algorithm. The result is a 12-element
356
+ field value that gets stored in the verification key.
357
+
358
+ This pairing e(alpha, beta) is constant for a given verification key, so it's
359
+ precomputed once and reused for all proof verifications.
360
+
361
+ **Input**
362
+
363
+ A JS object matching `PairingInput` structure:
364
+ - `alpha`: An `AffinePoint2d` with `x` and `y` fields
365
+ - `beta`: A `ComplexAffinePoint2d` with `x_c0`, `x_c1`, `y_c0`, `y_c1` fields
326
366
 
327
- Takes a 12-element field value (the result of a Miller loop pairing computation) and computes the auxiliary witness needed for efficient verification.
367
+ **Output**
368
+
369
+ Returns a JS object matching `Field12` structure (12 string fields: g00-g21, h00-h21).
370
+
371
+ **Errors**
372
+
373
+ Throws a JS error if input parsing or coordinate conversion fails.
374
+
375
+ #### `convert_snarkjs_groth16_to_o1js`
328
376
 
329
377
  ```typescript
330
- const auxWitness = compute_aux_witness({
331
- g00: '...', g01: '...', g10: '...', g11: '...', g20: '...', g21: '...',
332
- h00: '...', h01: '...', h10: '...', h11: '...', h20: '...', h21: '...'
333
- });
378
+ export function convert_snarkjs_groth16_to_o1js(proof: SnarkjsProof, public_inputs: string[], vk: SnarkjsVK): O1jsGroth16;
334
379
  ```
335
380
 
336
- #### `convert_snarkjs_groth16_to_o1js(proof: SnarkjsProof, public_inputs: string[], vk: SnarkjsVK): O1jsGroth16`
381
+ Converts a snarkjs/circom Groth16 proof and verification key to o1js format.
337
382
 
338
- Converts a SnarkJS/Circom Groth16 proof and verification key to o1js format.
383
+ This function takes Groth16 proofs generated by snarkjs (the JavaScript implementation
384
+ of Groth16 commonly used with circom circuits) and converts them to o1js format for
385
+ verification in Mina Protocol zkApps.
339
386
 
340
- This function takes Groth16 proofs generated by snarkjs (the JavaScript implementation of Groth16 commonly used with circom circuits) and converts them to o1js format for verification in Mina Protocol zkApps.
387
+ **Conversion Details**
341
388
 
342
- **Key Conversions:**
343
- - The A point (`pi_a`) is negated for o1js compatibility
344
- - Points are converted from projective coordinates to affine form
345
- - The `alpha_beta` pairing e(α, β) is precomputed
346
- - Supports up to 6 public inputs
389
+ **Proof Conversion**
390
+ - The A point (`pi_a`) is **negated** for o1js compatibility. The o1js verification
391
+ equation uses `-A` rather than `A` in the pairing check.
392
+ - Points are converted from projective coordinates (with z component) to affine form.
393
+ - The B point is a G2 point with complex coordinates (x_c0, x_c1, y_c0, y_c1).
394
+ - The C point is a G1 point with simple coordinates (x, y).
347
395
 
348
- ```typescript
349
- import { convert_snarkjs_groth16_to_o1js } from '@nori-zk/proof-conversion-utils';
396
+ **Verification Key Conversion**
397
+ - All curve points are converted from projective to affine form.
398
+ - The `alpha_beta` pairing e(α, β) is computed using arkworks `multi_miller_loop`.
399
+ This is a constant for each VK and is precomputed to save verification time.
400
+ - A hardcoded `w27` (27th root of unity) is added for pairing optimizations.
401
+ See https://eprint.iacr.org/2024/640 for the optimization technique.
402
+ - IC (input commitment) points are mapped to ic0-ic6 fields.
350
403
 
351
- const o1jsFormat = convert_snarkjs_groth16_to_o1js(
352
- snarkjsProof,
353
- ['123', '456'], // Public inputs as strings
354
- snarkjsVK
355
- );
356
- ```
404
+ **Validation**
405
+ - The `nPublic` field in the VK must match the number of public inputs provided.
406
+ - The IC array length must equal nPublic + 1 (ic0 is the constant term).
357
407
 
358
- #### `convert_sp1_groth16_to_o1js(sp1_proof: SP1ProofWithPublicValues): O1jsGroth16`
408
+ **Input Format**
359
409
 
360
- Converts an SP1 Groth16 proof to o1js format.
410
+ - `proof`: snarkjs proof JSON object with:
411
+ - `pi_a`: `[x, y, z]` - A point in G1 projective coordinates
412
+ - `pi_b`: `[[x_c0, x_c1], [y_c0, y_c1], [z_c0, z_c1]]` - B point in G2 projective
413
+ - `pi_c`: `[x, y, z]` - C point in G1 projective coordinates
361
414
 
362
- This function takes Groth16 proofs generated by SP1 (Succinct's zkVM) and converts them to o1js format for verification in Mina Protocol zkApps. SP1 uses gnark's Groth16 implementation internally.
415
+ - `public_inputs`: Array of public input strings as decimal numbers, e.g., `["123", "456"]`.
416
+ Maximum 6 public inputs are supported.
363
417
 
364
- **Key Features:**
365
- - Automatically decompresses gnark-formatted proof bytes
366
- - Uses the embedded SP1 v5.0.0 verification key (all SP1 Groth16 proofs use the same VK)
367
- - Negates the A point for o1js compatibility
368
- - SP1 Groth16 proofs always have exactly 2 public inputs (vkey_hash and public_values_hash)
418
+ - `vk`: snarkjs verification key JSON object with:
419
+ - `nPublic`: Number of public inputs
420
+ - `vk_alpha_1`: Alpha point (G1 projective)
421
+ - `vk_beta_2`: Beta point (G2 projective)
422
+ - `vk_gamma_2`: Gamma point (G2 projective)
423
+ - `vk_delta_2`: Delta point (G2 projective)
424
+ - `IC`: Array of IC points (G1 projective), length = nPublic + 1
369
425
 
370
- ```typescript
371
- import { convert_sp1_groth16_to_o1js } from '@nori-zk/proof-conversion-utils';
426
+ **Output Format**
427
+
428
+ Returns a JS object matching `O1jsGroth16` containing:
429
+
430
+ - `proof`: o1js-formatted proof with:
431
+ - `negA`: Negated A point `{x, y}` as decimal strings
432
+ - `B`: B point `{x_c0, x_c1, y_c0, y_c1}` as decimal strings
433
+ - `C`: C point `{x, y}` as decimal strings
434
+ - `pi1` through `pi6`: Public inputs (only present if provided)
435
+
436
+ - `vk`: o1js-formatted verification key with:
437
+ - `alpha`, `beta`, `gamma`, `delta`: Curve points
438
+ - `alpha_beta`: Precomputed pairing as 12-element Fq12 field
439
+ - `w27`: 27th root of unity as 12-element Fq12 field
440
+ - `ic0` through `ic6`: Input commitment points (only present if in VK)
441
+
442
+ **Errors**
372
443
 
373
- const o1jsFormat = convert_sp1_groth16_to_o1js(sp1Proof);
444
+ Throws a JsError error if:
445
+ - Input JSON parsing fails (invalid structure or types)
446
+ - VK validation fails (`nPublic` doesn't match public inputs count, wrong IC length)
447
+ - Point coordinate parsing fails (invalid field element strings)
448
+ - More than 6 public inputs are provided
449
+
450
+ #### `convert_sp1_groth16_to_o1js`
451
+
452
+ ```typescript
453
+ export function convert_sp1_groth16_to_o1js(sp1_proof: SP1ProofWithPublicValues): O1jsGroth16;
374
454
  ```
375
455
 
456
+ Converts an SP1 Groth16 proof to o1js format.
457
+
458
+ This function takes Groth16 proofs generated by SP1 (Succinct's zkVM) and converts
459
+ them to o1js format for verification in Mina Protocol zkApps. SP1 uses gnark's
460
+ Groth16 implementation internally, which produces proofs in a compressed format
461
+ that must be decompressed before conversion.
462
+
463
+ **Conversion Details**
464
+
465
+ **Proof Extraction & Decompression**
466
+ - The `encoded_proof` field contains hex-encoded gnark proof bytes.
467
+ - The first 4 bytes of the proof are a vkey hash prefix (skipped during parsing).
468
+ - gnark uses a compressed point format that differs from arkworks. This function
469
+ decompresses G1 and G2 points using endianness conversion and flag translation.
470
+ - The decompression follows the gnark → arkworks conversion from sp1-sui.
471
+
472
+ **Proof Conversion**
473
+ - The A point is **negated** for o1js compatibility. The o1js verification
474
+ equation uses `-A` rather than `A` in the pairing check.
475
+ - SP1 Groth16 proofs have exactly 2 public inputs (vkey_hash and public_values_hash).
476
+
477
+ **Verification Key**
478
+ - All SP1 v5.0.0 Groth16 proofs use the **same verification key**. This VK is
479
+ embedded in the library (`GROTH16_VK_5_0_0_BYTES`) and loaded automatically.
480
+ - The VK is decompressed from gnark format to arkworks format.
481
+ - The `alpha_beta` pairing e(α, β) is computed and included in the output.
482
+ - The hardcoded `w27` (27th root of unity) is added for pairing optimizations.
483
+
484
+ **Input Format**
485
+
486
+ - `sp1_proof`: SP1ProofWithPublicValues JSON shim object representation
487
+ - FIXME write an example here!
488
+
489
+ **Output Format**
490
+
491
+ Returns a JS object `O1jsGroth16` containing:
492
+
493
+ - `proof`: o1js-formatted proof with:
494
+ - `negA`: Negated A point `{x, y}` as decimal strings
495
+ - `B`: B point `{x_c0, x_c1, y_c0, y_c1}` as decimal strings
496
+ - `C`: C point `{x, y}` as decimal strings
497
+ - `pi1`: First public input (vkey_hash)
498
+ - `pi2`: Second public input (public_values_hash)
499
+
500
+ - `vk`: o1js-formatted SP1 v5.0.0 verification key with:
501
+ - `alpha`, `beta`, `gamma`, `delta`: Curve points
502
+ - `alpha_beta`: Precomputed pairing as 12-element Fq12 field
503
+ - `w27`: 27th root of unity as 12-element Fq12 field
504
+ - `ic0`, `ic1`, `ic2`: Input commitment points (SP1 VK has 3 IC points)
505
+
506
+ **Errors**
507
+
508
+ Throws a JsError error if:
509
+ - Input JSON parsing fails (invalid structure or types)
510
+ - Proof is not the `Groth16` variant (e.g., it's a PLONK proof)
511
+ - Proof is empty (mock proof - not supported)
512
+ - Hex decoding of `encoded_proof` fails
513
+ - gnark point decompression fails (invalid curve points)
514
+
376
515
  ## Usage Examples
377
516
 
378
517
  ### Converting SnarkJS Proof
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nori-zk/proof-conversion-utils",
3
3
  "type": "module",
4
- "version": "0.5.0",
4
+ "version": "0.5.1",
5
5
  "license": "Apache-2.0",
6
6
  "publishConfig": {
7
7
  "registry": "https://registry.npmjs.org/",
@@ -297,9 +297,9 @@ export interface SP1PublicValues {
297
297
  * - `c`: A 12-element field value
298
298
  * - `shift_power`: "0", "1", or "2"
299
299
  *
300
- * # Panics
300
+ * # Error
301
301
  *
302
- * Panics if the input is not a valid Miller loop output (fails internal assertion).
302
+ * Returns a JsError if the input is not a valid Miller loop output (fails internal assertion).
303
303
  */
304
304
  export function compute_aux_witness(input: Field12): AuxWitness;
305
305
 
@@ -20,9 +20,9 @@
20
20
  * - `c`: A 12-element field value
21
21
  * - `shift_power`: "0", "1", or "2"
22
22
  *
23
- * # Panics
23
+ * # Error
24
24
  *
25
- * Panics if the input is not a valid Miller loop output (fails internal assertion).
25
+ * Returns a JsError if the input is not a valid Miller loop output (fails internal assertion).
26
26
  * @param {Field12} input
27
27
  * @returns {AuxWitness}
28
28
  */
Binary file