@@ -386,4 +386,202 @@ int secp256k1_bulletproofs_pp_rangeproof_norm_product_prove(
386386 * proof_len = start_idx + 64 ;
387387 return 1 ;
388388}
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_bulletproofs_pp_log2 (g_len ), log_m = secp256k1_bulletproofs_pp_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+ secp256k1_ge comm = * commit ;
474+
475+ if (g_vec -> n != (h_len + g_len ) || (proof_len != 65 * n_rounds + 64 )) {
476+ return 0 ;
477+ }
478+
479+ if (!secp256k1_check_power_of_two (g_len ) || !secp256k1_check_power_of_two (h_len )) {
480+ return 0 ;
481+ }
482+
483+ secp256k1_scalar_set_b32 (& n , & proof [n_rounds * 65 ], & overflow ); /* n */
484+ if (overflow ) return 0 ;
485+ secp256k1_scalar_set_b32 (& l , & proof [n_rounds * 65 + 32 ], & overflow ); /* l */
486+ if (overflow ) return 0 ;
487+ if (secp256k1_scalar_is_zero (r_ch )) return 0 ;
488+
489+ /* Compute powers of q_inv. Later used in g_factor computations*/
490+ r = * r_ch ;
491+ secp256k1_scalar_inverse_var (& r_inv , & r );
492+ scratch_checkpoint = secp256k1_scratch_checkpoint (& ctx -> error_callback , scratch );
493+
494+ r_inv_pows = (secp256k1_scalar * )secp256k1_scratch_alloc (& ctx -> error_callback , scratch , log_n * sizeof (secp256k1_scalar ));
495+ secp256k1_bulletproofs_powers_of_r (r_inv_pows , & r_inv , log_n );
496+
497+ secp256k1_sha256_initialize (& sha256 );
498+ secp256k1_sha256_write (& sha256 , transcript_hash32 , 32 );
499+ secp256k1_fe_normalize_var (& comm .x );
500+ secp256k1_fe_normalize_var (& comm .y );
501+ ser_commit [0 ] = 0x02 | secp256k1_fe_is_odd (& comm .y );
502+ secp256k1_fe_get_b32 (& ser_commit [1 ], & comm .x );
503+ secp256k1_sha256_write (& sha256 , ser_commit , 33 );
504+ secp256k1_sha256_finalize (& sha256 , transcript_hash32 );
505+
506+ for (i = 0 ; i < log_n ; i ++ ) {
507+ secp256k1_scalar_sqr (& r , & r );
508+ }
509+
510+ /* Collect the challenges in a new vector */
511+ es = (secp256k1_scalar * )secp256k1_scratch_alloc (& ctx -> error_callback , scratch , n_rounds * sizeof (secp256k1_scalar ));
512+ s_g = (secp256k1_scalar * )secp256k1_scratch_alloc (& ctx -> error_callback , scratch , g_len * sizeof (secp256k1_scalar ));
513+ s_h = (secp256k1_scalar * )secp256k1_scratch_alloc (& ctx -> error_callback , scratch , h_len * sizeof (secp256k1_scalar ));
514+ if (es == NULL || s_g == NULL || s_h == NULL ) {
515+ secp256k1_scratch_apply_checkpoint (& ctx -> error_callback , scratch , scratch_checkpoint );
516+ return 0 ;
517+ }
518+
519+ for (i = 0 ; i < n_rounds ; i ++ ) {
520+ secp256k1_scalar e ;
521+ secp256k1_sha256_initialize (& sha256 );
522+ secp256k1_sha256_write (& sha256 , transcript_hash32 , 32 );
523+ secp256k1_sha256_write (& sha256 , & proof [i * 65 ], 65 );
524+ secp256k1_sha256_finalize (& sha256 , transcript_hash32 );
525+ /* Ignore overflow, output of an hash function will fall in curve order with high probability*/
526+ secp256k1_scalar_set_b32 (& e , transcript_hash32 , & overflow );
527+ es [i ] = e ;
528+ }
529+ /* s_g[0] = n * r^(n - 1) = n * (r)^n * r_inv = n * q * r_inv */
530+ secp256k1_scalar_mul (& s_g [0 ], & n , & r );
531+ secp256k1_scalar_mul (& s_g [0 ], & s_g [0 ], & r_inv );
532+ for (i = 1 ; i < g_len ; i ++ ) {
533+ size_t log_i = secp256k1_bulletproofs_pp_log2 (i );
534+ size_t nearest_pow_of_two = (size_t )1 << log_i ;
535+ secp256k1_scalar_mul (& s_g [i ], & s_g [i - nearest_pow_of_two ], & es [log_i ]);
536+ secp256k1_scalar_mul (& s_g [i ], & s_g [i ], & r_inv_pows [log_i ]);
537+ }
538+ s_h [0 ] = l ;
539+ secp256k1_scalar_set_int (& h_c , 0 );
540+ for (i = 1 ; i < h_len ; i ++ ) {
541+ size_t log_i = secp256k1_bulletproofs_pp_log2 (i );
542+ size_t nearest_pow_of_two = (size_t )1 << log_i ;
543+ secp256k1_scalar_mul (& s_h [i ], & s_h [i - nearest_pow_of_two ], & es [log_i ]);
544+ }
545+ secp256k1_scalar_inner_product (& h_c , c_vec , 0 /* a_offset */ , s_h , 0 /* b_offset */ , 1 /* step */ , h_len );
546+ /* Compute v = n*n*q + l*h_c*/
547+ secp256k1_scalar_sqr (& q , & r );
548+ secp256k1_scalar_mul (& v , & n , & n );
549+ secp256k1_scalar_mul (& v , & v , & q );
550+ secp256k1_scalar_add (& v , & v , & h_c );
551+
552+ {
553+ ec_mult_verify_cb_data1 data ;
554+ secp256k1_gej temp1 , temp2 ;
555+ secp256k1_scalar one ;
556+ data .proof = proof ;
557+ data .commit = commit ;
558+ data .challenges = es ;
559+
560+ secp256k1_gej_set_ge (& temp2 , commit );
561+ secp256k1_scalar_set_int (& one , 1 );
562+ secp256k1_ecmult (& temp1 , & temp2 , & one , NULL );
563+
564+ if (!secp256k1_ecmult_multi_var (& ctx -> error_callback , scratch , & res1 , NULL , ec_mult_verify_cb1 , & data , 2 * n_rounds + 1 )) {
565+ return 0 ;
566+ }
567+ }
568+ {
569+ ec_mult_verify_cb_data2 data ;
570+ data .g_vec = g_vec -> gens ;
571+ data .g_vec_len = g_len ;
572+ data .s_g = s_g ;
573+ data .s_h = s_h ;
574+
575+ if (!secp256k1_ecmult_multi_var (& ctx -> error_callback , scratch , & res2 , & v , ec_mult_verify_cb2 , & data , g_len + h_len )) {
576+ return 0 ;
577+ }
578+ }
579+
580+ secp256k1_scratch_apply_checkpoint (& ctx -> error_callback , scratch , scratch_checkpoint );
581+
582+ /* res1 and res2 should be equal. Could not find a simpler way to compare them */
583+ secp256k1_gej_neg (& res1 , & res1 );
584+ secp256k1_gej_add_var (& res1 , & res1 , & res2 , NULL );
585+ return secp256k1_gej_is_infinity (& res1 );
586+ }
389587#endif
0 commit comments