@@ -692,5 +692,267 @@ static int secp256k1_bulletproofs_pp_rangeproof_prove_impl(
692692 return res ;
693693}
694694
695+ typedef struct secp256k1_bulletproofs_pp_verify_cb_data {
696+ const unsigned char * proof ;
697+ const secp256k1_scalar * g_vec_pub_deltas ;
698+ const secp256k1_scalar * t_pows ;
699+ const secp256k1_scalar * v ;
700+ const secp256k1_ge * asset_genp ;
701+ const secp256k1_ge * commit ;
702+ const secp256k1_ge * g_gens ;
703+ } secp256k1_bulletproofs_pp_verify_cb_data ;
704+
705+ static int secp256k1_bulletproofs_pp_verify_cb (secp256k1_scalar * sc , secp256k1_ge * pt , size_t idx , void * cbdata ) {
706+ secp256k1_bulletproofs_pp_verify_cb_data * data = (secp256k1_bulletproofs_pp_verify_cb_data * ) cbdata ;
707+ switch (idx ) {
708+ case 0 : /* v * asset_genp */
709+ * pt = * data -> asset_genp ;
710+ * sc = * data -> v ;
711+ break ;
712+ case 1 : /* t * M */
713+ if (!secp256k1_eckey_pubkey_parse (pt , data -> proof , 33 )) {
714+ return 0 ;
715+ }
716+ * sc = data -> t_pows [0 ];
717+ break ;
718+ case 2 : /* t^2 D */
719+ if (!secp256k1_eckey_pubkey_parse (pt , & data -> proof [33 ], 33 )) {
720+ return 0 ;
721+ }
722+ * sc = data -> t_pows [1 ];
723+ break ;
724+ case 3 : /* t^3 R */
725+ if (!secp256k1_eckey_pubkey_parse (pt , & data -> proof [33 * 2 ], 33 )) {
726+ return 0 ;
727+ }
728+ * sc = data -> t_pows [2 ];
729+ break ;
730+ case 4 : /* 1. S */
731+ if (!secp256k1_eckey_pubkey_parse (pt , & data -> proof [33 * 3 ], 33 )) {
732+ return 0 ;
733+ }
734+ secp256k1_scalar_set_int (sc , 1 );
735+ break ;
736+ case 5 : /* 2t^5 V(commit) */
737+ * pt = * data -> commit ;
738+ * sc = data -> t_pows [4 ];
739+ secp256k1_scalar_add (sc , sc , sc );
740+ break ;
741+ default :
742+ idx -= 6 ;
743+ * pt = data -> g_gens [idx ];
744+ * sc = data -> g_vec_pub_deltas [idx ];
745+ break ;
746+ }
747+ return 1 ;
748+ }
749+
750+ static int secp256k1_bulletproofs_pp_rangeproof_verify_impl (
751+ const secp256k1_context * ctx ,
752+ secp256k1_scratch_space * scratch ,
753+ const secp256k1_bulletproofs_generators * gens ,
754+ const secp256k1_ge * asset_genp ,
755+ const unsigned char * proof ,
756+ const size_t proof_len ,
757+ const size_t n_bits ,
758+ const size_t digit_base ,
759+ const uint64_t min_value ,
760+ const secp256k1_ge * commitp ,
761+ const unsigned char * extra_commit ,
762+ size_t extra_commit_len
763+ ) {
764+ size_t scratch_checkpoint ;
765+ secp256k1_sha256 transcript ;
766+ size_t num_digits = n_bits / secp256k1_bulletproofs_pp_log2 (digit_base );
767+ size_t h_len = 8 , i ;
768+ size_t g_offset = num_digits > digit_base ? num_digits : digit_base ;
769+ size_t log_n = secp256k1_bulletproofs_pp_log2 (g_offset ), log_m = secp256k1_bulletproofs_pp_log2 (h_len );
770+ size_t n_rounds = log_n > log_m ? log_n : log_m ;
771+ secp256k1_scalar v_g ;
772+ secp256k1_scalar * q_pows , * q_inv_pows , * g_vec_pub_deltas ;
773+ secp256k1_scalar e , q_sqrt , q , q_inv , x , y , t ;
774+ /* To be re-used as c_vec later */
775+ secp256k1_scalar t_pows [8 ];
776+
777+ /* Check proof sizes*/
778+ if (proof_len != 33 * 4 + (65 * n_rounds ) + 64 ) {
779+ return 0 ;
780+ }
781+ if (gens -> n != (g_offset + h_len )) {
782+ return 0 ;
783+ }
784+ if (!secp256k1_check_power_of_two (digit_base ) || !secp256k1_check_power_of_two (num_digits ) || !secp256k1_check_power_of_two (n_bits )) {
785+ return 0 ;
786+ }
787+ if (n_bits > 64 ) {
788+ return 0 ;
789+ }
790+ if (extra_commit_len > 0 && extra_commit == NULL ) {
791+ return 0 ;
792+ }
793+
794+ scratch_checkpoint = secp256k1_scratch_checkpoint (& ctx -> error_callback , scratch );
795+ q_pows = (secp256k1_scalar * )secp256k1_scratch_alloc (& ctx -> error_callback , scratch , g_offset * sizeof (secp256k1_scalar ));
796+ q_inv_pows = (secp256k1_scalar * )secp256k1_scratch_alloc (& ctx -> error_callback , scratch , g_offset * sizeof (secp256k1_scalar ));
797+ g_vec_pub_deltas = (secp256k1_scalar * )secp256k1_scratch_alloc (& ctx -> error_callback , scratch , g_offset * sizeof (secp256k1_scalar ));
798+
799+ if ( q_pows == NULL || q_inv_pows == NULL ) {
800+ secp256k1_scratch_apply_checkpoint (& ctx -> error_callback , scratch , scratch_checkpoint );
801+ return 0 ;
802+ }
803+
804+ /* Obtain the challenges */
805+ secp256k1_bulletproofs_pp_commit_initial_data (
806+ & transcript ,
807+ num_digits ,
808+ digit_base ,
809+ min_value ,
810+ commitp ,
811+ asset_genp ,
812+ extra_commit ,
813+ extra_commit_len
814+ );
815+
816+ /* Verify round 1 */
817+ secp256k1_sha256_write (& transcript , proof , 66 );
818+ secp256k1_bulletproofs_challenge_scalar (& e , & transcript , 0 );
819+
820+ /* Verify round 2 */
821+ secp256k1_sha256_write (& transcript , & proof [33 * 2 ], 33 );
822+ secp256k1_bulletproofs_challenge_scalar (& q_sqrt , & transcript , 0 );
823+ secp256k1_bulletproofs_challenge_scalar (& x , & transcript , 1 );
824+ secp256k1_bulletproofs_challenge_scalar (& y , & transcript , 2 );
825+ secp256k1_scalar_sqr (& q , & q_sqrt );
826+ secp256k1_scalar_inverse_var (& q_inv , & q );
827+
828+ /* Verify round 3 */
829+ secp256k1_sha256_write (& transcript , & proof [33 * 3 ], 33 );
830+ secp256k1_bulletproofs_challenge_scalar (& t , & transcript , 0 );
831+
832+ secp256k1_bulletproofs_pp_rangeproof_powers_of_q (q_pows , & q , g_offset );
833+ secp256k1_bulletproofs_pp_rangeproof_powers_of_q (q_inv_pows , & q_inv , g_offset );
834+
835+ /* Computes from t^1 to t^7, Others unneeded, will be set to 0 later */
836+ secp256k1_bulletproofs_pp_rangeproof_powers_of_q (& t_pows [0 ], & t , 7 );
837+ {
838+ /* g_vec_pub_delta[i] = (b^i*t^3 + (-x)*t^2 + (x/e+i)*t^4)*q_inv^i + e*t^2 */
839+ secp256k1_scalar b_pow_i_t3 , neg_x_t2 , x_t4 , e_t2 , base ;
840+ b_pow_i_t3 = t_pows [2 ];
841+ secp256k1_scalar_negate (& neg_x_t2 , & x );
842+ secp256k1_scalar_mul (& neg_x_t2 , & neg_x_t2 , & t_pows [1 ]);
843+ x_t4 = t_pows [3 ];
844+ secp256k1_scalar_mul (& x_t4 , & x_t4 , & x );
845+ e_t2 = t_pows [1 ];
846+ secp256k1_scalar_mul (& e_t2 , & e_t2 , & e );
847+ secp256k1_scalar_set_int (& base , digit_base );
848+
849+ for (i = 0 ; i < g_offset ; i ++ ) {
850+ secp256k1_scalar_clear (& g_vec_pub_deltas [i ]);
851+ if (i < num_digits ) {
852+ secp256k1_scalar_add (& g_vec_pub_deltas [i ], & b_pow_i_t3 , & neg_x_t2 ); /* g_vec_pub_delta[i] = b^i*t^3 + (-x)*t^2 */
853+ secp256k1_scalar_mul (& b_pow_i_t3 , & b_pow_i_t3 , & base );
854+ }
855+
856+ if (i < digit_base ) {
857+ secp256k1_scalar e_plus_i_inv ;
858+ secp256k1_scalar_set_int (& e_plus_i_inv , i ); /* digit base is less than 2^32, can directly set*/
859+ secp256k1_scalar_add (& e_plus_i_inv , & e_plus_i_inv , & e ); /* (e + i)*/
860+ secp256k1_scalar_inverse_var (& e_plus_i_inv , & e_plus_i_inv ); /* 1/(e +i)*/
861+ secp256k1_scalar_mul (& e_plus_i_inv , & e_plus_i_inv , & x_t4 ); /* xt^4/(e+i) */
862+
863+ secp256k1_scalar_add (& g_vec_pub_deltas [i ], & g_vec_pub_deltas [i ], & e_plus_i_inv ); /*g_vec_pub_delta[i] = b^i*t^3 + (-x)*t^2 + xt^4/(e+i)*/
864+ }
865+
866+ secp256k1_scalar_mul (& g_vec_pub_deltas [i ], & g_vec_pub_deltas [i ], & q_inv_pows [i ]); /* g_vec_pub_delta[i] = (b^i*t^3 + (-x)*t^2 + xt^4/(e+i))*q_inv^i */
867+ if (i < num_digits ) {
868+ secp256k1_scalar_add (& g_vec_pub_deltas [i ], & g_vec_pub_deltas [i ], & e_t2 ); /* g_vec_pub_delta[i] = (b^i*t^3 + (-x)*t^2 + xt^4/(e+i))*q_inv^i + e*t^2 */
869+ }
870+ }
871+ }
872+
873+ {
874+ /* v = 2*t5(<one_vec, q^(i+1)> + <b^i, e> + <b^i, -x*q^-(i+1)>) + x^2t^8(<q^-(i+1)/(e+i), 1/(e+i)>) */
875+ secp256k1_scalar two_t5 , x2_t8 , b_pow_i , neg_x_q_inv_pow_plus_e , e_plus_i_inv , base , v_g1 , v_g2 , sc_min_v ;
876+ secp256k1_scalar_set_int (& two_t5 , 2 );
877+ secp256k1_scalar_mul (& two_t5 , & two_t5 , & t_pows [4 ]);
878+ secp256k1_scalar_mul (& x2_t8 , & t_pows [3 ], & x );
879+ secp256k1_scalar_sqr (& x2_t8 , & x2_t8 );
880+ secp256k1_scalar_set_int (& b_pow_i , 1 );
881+ secp256k1_scalar_clear (& v_g1 );
882+ secp256k1_scalar_clear (& v_g2 );
883+ secp256k1_scalar_set_int (& base , digit_base );
884+
885+ /* Compute v_g1 = 2*t5(<one_vec, q^(i+1)> + <b^i, e> + <b^i, -x*q^-(i+1)>) */
886+ for (i = 0 ; i < num_digits ; i ++ ) {
887+ secp256k1_scalar_add (& v_g1 , & v_g1 , & q_pows [i ]); /* v_g1 = <q^(i+1), 1> */
888+ secp256k1_scalar_negate (& neg_x_q_inv_pow_plus_e , & x ); /* -x */
889+ secp256k1_scalar_mul (& neg_x_q_inv_pow_plus_e , & q_inv_pows [i ], & neg_x_q_inv_pow_plus_e ); /* -x*q^-(i+1) */
890+ secp256k1_scalar_add (& neg_x_q_inv_pow_plus_e , & neg_x_q_inv_pow_plus_e , & e ); /* -x*q^-(i+1) + e */
891+ secp256k1_scalar_mul (& neg_x_q_inv_pow_plus_e , & neg_x_q_inv_pow_plus_e , & b_pow_i ); /* <b^i, -x*q^-(i+1) + e> */
892+ secp256k1_scalar_add (& v_g1 , & v_g1 , & neg_x_q_inv_pow_plus_e ); /* v_g1 = <q^(i+1), 1> + <b^i, -x*q^-(i+1) + e> */
893+ secp256k1_scalar_mul (& b_pow_i , & b_pow_i , & base );
894+ }
895+ secp256k1_scalar_set_int (& sc_min_v , min_value );
896+ secp256k1_scalar_negate (& sc_min_v , & sc_min_v );
897+ secp256k1_scalar_add (& v_g1 , & v_g1 , & sc_min_v ); /* v_g1 = <q^(i+1), 1> + <b^i, -x*q^-(i+1) + e> - min_value */
898+ secp256k1_scalar_mul (& v_g1 , & v_g1 , & two_t5 ); /* v_g1 = 2*t5(<one_vec, q^(i+1)> + <b^i, e> + <b^i, -x*q^-(i+1)> - min_value) */
899+
900+ /* Compute v_g2 = x^2t^8(<q^-(i+1)/(e+i), 1/(e+i)>) */
901+ for (i = 0 ; i < digit_base ; i ++ ) {
902+ secp256k1_scalar_set_int (& e_plus_i_inv , i ); /* digit base is less than 2^32, can directly set*/
903+ secp256k1_scalar_add (& e_plus_i_inv , & e_plus_i_inv , & e ); /* (e + i)*/
904+ secp256k1_scalar_inverse_var (& e_plus_i_inv , & e_plus_i_inv ); /* 1/(e +i)*/
905+ secp256k1_scalar_sqr (& e_plus_i_inv , & e_plus_i_inv ); /* 1/(e +i)^2 */
906+ secp256k1_scalar_mul (& e_plus_i_inv , & e_plus_i_inv , & q_inv_pows [i ]); /* q^-(i+1)/(e+i)^2 */
907+ secp256k1_scalar_add (& v_g2 , & v_g2 , & e_plus_i_inv ); /* v_g2 = <q^-(i+1)/(e+i), 1/(e+i)> */
908+ }
909+ secp256k1_scalar_mul (& v_g2 , & v_g2 , & x2_t8 ); /* v_g2 = x^2t^8(<q^-(i+1)/(e+i), 1/(e+i)>) */
910+ secp256k1_scalar_add (& v_g , & v_g1 , & v_g2 ); /* v_g = v_g1 + v_g2 */
911+ }
912+ /* Ecmult to compute C = S + tM + t^2D + t^3R + 2t^5V + <g_vec_pub_deltas, G_vec> + v_g*A(asset_genP) */
913+ {
914+ secp256k1_bulletproofs_pp_verify_cb_data cb_data ;
915+ secp256k1_gej c_commj ;
916+ secp256k1_ge c_comm ;
917+ size_t num_points ;
918+ cb_data .g_vec_pub_deltas = g_vec_pub_deltas ;
919+ cb_data .v = & v_g ;
920+ cb_data .asset_genp = asset_genp ;
921+ cb_data .commit = commitp ;
922+ cb_data .g_gens = gens -> gens ;
923+ cb_data .proof = proof ;
924+ cb_data .t_pows = t_pows ;
925+ num_points = 6 + g_offset ;
926+
927+ if (!secp256k1_ecmult_multi_var (& ctx -> error_callback , scratch , & c_commj , NULL , secp256k1_bulletproofs_pp_verify_cb , (void * ) & cb_data , num_points )) {
928+ return 0 ;
929+ }
930+
931+ secp256k1_ge_set_gej_var (& c_comm , & c_commj );
932+ /* Make c = y*(T, T^2, T^3, T^4, T^6, T^7, 0, 0) */
933+ t_pows [4 ] = t_pows [5 ];
934+ t_pows [5 ] = t_pows [6 ];
935+ for (i = 0 ; i < 6 ; i ++ ) {
936+ secp256k1_scalar_mul (& t_pows [i ], & t_pows [i ], & y );
937+ }
938+ secp256k1_scalar_clear (& t_pows [6 ]);
939+ secp256k1_scalar_clear (& t_pows [7 ]);
940+
941+ return secp256k1_bulletproofs_pp_rangeproof_norm_product_verify (
942+ ctx ,
943+ scratch ,
944+ & proof [33 * 4 ],
945+ proof_len - 33 * 4 ,
946+ & transcript ,
947+ & q_sqrt ,
948+ gens ,
949+ asset_genp ,
950+ g_offset ,
951+ t_pows ,
952+ 8 ,
953+ & c_comm
954+ );
955+ }
956+ }
695957
696958#endif
0 commit comments