@@ -386,4 +386,199 @@ int secp256k1_bulletproofs_pp_rangeproof_norm_product_prove(
386
386
* proof_len = start_idx + 64 ;
387
387
return 1 ;
388
388
}
389
+
390
+ typedef struct ec_mult_verify_cb_data1 {
391
+ const unsigned char * proof ;
392
+ const secp256k1_ge * commit ;
393
+ const secp256k1_scalar * challenges ;
394
+ } ec_mult_verify_cb_data1 ;
395
+
396
+ static int ec_mult_verify_cb1 (secp256k1_scalar * sc , secp256k1_ge * pt , size_t idx , void * cbdata ) {
397
+ ec_mult_verify_cb_data1 * data = (ec_mult_verify_cb_data1 * ) cbdata ;
398
+ if (idx == 0 ) {
399
+ * pt = * data -> commit ;
400
+ secp256k1_scalar_set_int (sc , 1 );
401
+ return 1 ;
402
+ }
403
+ idx -= 1 ;
404
+ if (idx % 2 == 0 ) {
405
+ unsigned char pk_buf [33 ];
406
+ idx /= 2 ;
407
+ * sc = data -> challenges [idx ];
408
+ pk_buf [0 ] = 2 | (data -> proof [65 * idx ] >> 1 );
409
+ memcpy (& pk_buf [1 ], & data -> proof [65 * idx + 1 ], 32 );
410
+ if (!secp256k1_eckey_pubkey_parse (pt , pk_buf , sizeof (pk_buf ))) {
411
+ return 0 ;
412
+ }
413
+ } else {
414
+ unsigned char pk_buf [33 ];
415
+ secp256k1_scalar neg_one ;
416
+ idx /= 2 ;
417
+ secp256k1_scalar_set_int (& neg_one , 1 );
418
+ secp256k1_scalar_negate (& neg_one , & neg_one );
419
+ * sc = data -> challenges [idx ];
420
+ secp256k1_scalar_sqr (sc , sc );
421
+ secp256k1_scalar_add (sc , sc , & neg_one ); /* Ignore overflow */
422
+ pk_buf [0 ] = 2 | data -> proof [65 * idx ];
423
+ memcpy (& pk_buf [1 ], & data -> proof [65 * idx + 33 ], 32 );
424
+ if (!secp256k1_eckey_pubkey_parse (pt , pk_buf , sizeof (pk_buf ))) {
425
+ return 0 ;
426
+ }
427
+ }
428
+ return 1 ;
429
+ }
430
+
431
+ typedef struct ec_mult_verify_cb_data2 {
432
+ const secp256k1_scalar * s_g ;
433
+ const secp256k1_scalar * s_h ;
434
+ const secp256k1_ge * g_vec ;
435
+ size_t g_vec_len ;
436
+ } ec_mult_verify_cb_data2 ;
437
+
438
+ static int ec_mult_verify_cb2 (secp256k1_scalar * sc , secp256k1_ge * pt , size_t idx , void * cbdata ) {
439
+ ec_mult_verify_cb_data2 * data = (ec_mult_verify_cb_data2 * ) cbdata ;
440
+ if (idx < data -> g_vec_len ) {
441
+ * sc = data -> s_g [idx ];
442
+ } else {
443
+ * sc = data -> s_h [idx - data -> g_vec_len ];
444
+ }
445
+ * pt = data -> g_vec [idx ];
446
+ return 1 ;
447
+ }
448
+
449
+ /* Verify the proof */
450
+ int secp256k1_bulletproofs_pp_rangeproof_norm_product_verify (
451
+ const secp256k1_context * ctx ,
452
+ secp256k1_scratch_space * scratch ,
453
+ unsigned char * proof ,
454
+ size_t proof_len ,
455
+ unsigned char * transcript_hash32 ,
456
+ const secp256k1_scalar * r_ch ,
457
+ secp256k1_bulletproofs_generators * g_vec ,
458
+ size_t g_len ,
459
+ secp256k1_scalar * c_vec ,
460
+ size_t c_vec_len ,
461
+ const secp256k1_ge * commit
462
+ ) {
463
+ secp256k1_scalar q , r , v , n , l , r_inv , h_c ;
464
+ secp256k1_scalar * es , * s_g , * s_h , * r_inv_pows ;
465
+ secp256k1_gej res1 , res2 ;
466
+ size_t i = 0 , scratch_checkpoint ;
467
+ int overflow ;
468
+ secp256k1_sha256 sha256 ;
469
+ unsigned char ser_commit [33 ];
470
+ size_t log_n = secp256k1_log2 (g_len ), log_m = secp256k1_log2 (c_vec_len );
471
+ size_t n_rounds = log_n > log_m ? log_n : log_m ;
472
+ size_t h_len = c_vec_len ;
473
+
474
+ if (g_vec -> n != (h_len + g_len ) || (proof_len != 65 * n_rounds + 64 )) {
475
+ return 0 ;
476
+ }
477
+
478
+ if (!secp256k1_check_power_of_two (g_len ) || !secp256k1_check_power_of_two (h_len )) {
479
+ return 0 ;
480
+ }
481
+
482
+ secp256k1_scalar_set_b32 (& n , & proof [n_rounds * 65 ], & overflow ); /* n */
483
+ if (overflow ) return 0 ;
484
+ secp256k1_scalar_set_b32 (& l , & proof [n_rounds * 65 + 32 ], & overflow ); /* l */
485
+ if (overflow ) return 0 ;
486
+ if (secp256k1_scalar_is_zero (r_ch )) return 0 ;
487
+
488
+ /* Compute powers of q_inv. Later used in g_factor computations*/
489
+ r = * r_ch ;
490
+ secp256k1_scalar_inverse_var (& r_inv , & r );
491
+ scratch_checkpoint = secp256k1_scratch_checkpoint (& ctx -> error_callback , scratch );
492
+
493
+ r_inv_pows = (secp256k1_scalar * )secp256k1_scratch_alloc (& ctx -> error_callback , scratch , log_n * sizeof (secp256k1_scalar ));
494
+ secp256k1_bulletproofs_powers_of_r (r_inv_pows , & r_inv , log_n );
495
+
496
+ secp256k1_sha256_initialize (& sha256 );
497
+ secp256k1_sha256_write (& sha256 , transcript_hash32 , 32 );
498
+ ser_commit [0 ] = 0x02 | secp256k1_fe_is_odd (& commit -> y );
499
+ secp256k1_fe_get_b32 (& ser_commit [1 ], & commit -> x );
500
+ secp256k1_sha256_write (& sha256 , ser_commit , 33 );
501
+ secp256k1_sha256_finalize (& sha256 , transcript_hash32 );
502
+
503
+ for (i = 0 ; i < log_n ; i ++ ) {
504
+ secp256k1_scalar_sqr (& r , & r );
505
+ }
506
+
507
+ /* Collect the challenges in a new vector */
508
+ es = (secp256k1_scalar * )secp256k1_scratch_alloc (& ctx -> error_callback , scratch , n_rounds * sizeof (secp256k1_scalar ));
509
+ s_g = (secp256k1_scalar * )secp256k1_scratch_alloc (& ctx -> error_callback , scratch , g_len * sizeof (secp256k1_scalar ));
510
+ s_h = (secp256k1_scalar * )secp256k1_scratch_alloc (& ctx -> error_callback , scratch , h_len * sizeof (secp256k1_scalar ));
511
+ if (es == NULL || s_g == NULL || s_h == NULL ) {
512
+ secp256k1_scratch_apply_checkpoint (& ctx -> error_callback , scratch , scratch_checkpoint );
513
+ return 0 ;
514
+ }
515
+
516
+ for (i = 0 ; i < n_rounds ; i ++ ) {
517
+ secp256k1_scalar e ;
518
+ secp256k1_sha256_initialize (& sha256 );
519
+ secp256k1_sha256_write (& sha256 , transcript_hash32 , 32 );
520
+ secp256k1_sha256_write (& sha256 , & proof [i * 65 ], 65 );
521
+ secp256k1_sha256_finalize (& sha256 , transcript_hash32 );
522
+ /* Ignore overflow, output of an hash function will fall in curve order with high probability*/
523
+ secp256k1_scalar_set_b32 (& e , transcript_hash32 , & overflow );
524
+ es [i ] = e ;
525
+ }
526
+ /* s_g[0] = n * r^(n - 1) = n * (r)^n * r_inv = n * q * r_inv */
527
+ secp256k1_scalar_mul (& s_g [0 ], & n , & r );
528
+ secp256k1_scalar_mul (& s_g [0 ], & s_g [0 ], & r_inv );
529
+ for (i = 1 ; i < g_len ; i ++ ) {
530
+ size_t log_i = secp256k1_log2 (i );
531
+ size_t nearest_pow_of_two = (size_t )1 << log_i ;
532
+ secp256k1_scalar_mul (& s_g [i ], & s_g [i - nearest_pow_of_two ], & es [log_i ]);
533
+ secp256k1_scalar_mul (& s_g [i ], & s_g [i ], & r_inv_pows [log_i ]);
534
+ }
535
+ s_h [0 ] = l ;
536
+ secp256k1_scalar_set_int (& h_c , 0 );
537
+ for (i = 1 ; i < h_len ; i ++ ) {
538
+ size_t log_i = secp256k1_log2 (i );
539
+ size_t nearest_pow_of_two = (size_t )1 << log_i ;
540
+ secp256k1_scalar_mul (& s_h [i ], & s_h [i - nearest_pow_of_two ], & es [log_i ]);
541
+ }
542
+ secp256k1_scalar_inner_product (& h_c , c_vec , 0 /* a_offset */ , s_h , 0 /* b_offset */ , 1 /* step */ , h_len );
543
+ /* Compute v = n*n*q + l*h_c*/
544
+ secp256k1_scalar_sqr (& q , & r );
545
+ secp256k1_scalar_mul (& v , & n , & n );
546
+ secp256k1_scalar_mul (& v , & v , & q );
547
+ secp256k1_scalar_add (& v , & v , & h_c );
548
+
549
+ {
550
+ ec_mult_verify_cb_data1 data ;
551
+ secp256k1_gej temp1 , temp2 ;
552
+ secp256k1_scalar one ;
553
+ data .proof = proof ;
554
+ data .commit = commit ;
555
+ data .challenges = es ;
556
+
557
+ secp256k1_gej_set_ge (& temp2 , commit );
558
+ secp256k1_scalar_set_int (& one , 1 );
559
+ secp256k1_ecmult (& temp1 , & temp2 , & one , NULL );
560
+
561
+ if (!secp256k1_ecmult_multi_var (& ctx -> error_callback , scratch , & res1 , NULL , ec_mult_verify_cb1 , & data , 2 * n_rounds + 1 )) {
562
+ return 0 ;
563
+ }
564
+ }
565
+ {
566
+ ec_mult_verify_cb_data2 data ;
567
+ data .g_vec = g_vec -> gens ;
568
+ data .g_vec_len = g_len ;
569
+ data .s_g = s_g ;
570
+ data .s_h = s_h ;
571
+
572
+ if (!secp256k1_ecmult_multi_var (& ctx -> error_callback , scratch , & res2 , & v , ec_mult_verify_cb2 , & data , g_len + h_len )) {
573
+ return 0 ;
574
+ }
575
+ }
576
+
577
+ secp256k1_scratch_apply_checkpoint (& ctx -> error_callback , scratch , scratch_checkpoint );
578
+
579
+ /* res1 and res2 should be equal. Could not find a simpler way to compare them */
580
+ secp256k1_gej_neg (& res1 , & res1 );
581
+ secp256k1_gej_add_var (& res1 , & res1 , & res2 , NULL );
582
+ return secp256k1_gej_is_infinity (& res1 );
583
+ }
389
584
#endif
0 commit comments