@@ -732,9 +732,29 @@ static int secp256k1_ecmult_strauss_batch(const secp256k1_callback* error_callba
732
732
static int secp256k1_ecmult_strauss_batch_single (const secp256k1_callback * error_callback , const secp256k1_ecmult_context * actx , secp256k1_scratch * scratch , secp256k1_gej * r , const secp256k1_scalar * inp_g_sc , secp256k1_ecmult_multi_callback cb , void * cbdata , size_t n ) {
733
733
return secp256k1_ecmult_strauss_batch (error_callback , actx , scratch , r , inp_g_sc , cb , cbdata , n , 0 );
734
734
}
735
-
735
+ /**
736
+ * Returns the maximum number of points in addition to G that can be used with
737
+ * a given scratch space. For a given number of points, calling this function
738
+ * with a scratch space with strauss_scratch_size left will return the given
739
+ * number.
740
+ */
736
741
static size_t secp256k1_strauss_max_points (const secp256k1_callback * error_callback , secp256k1_scratch * scratch ) {
737
- return secp256k1_scratch_max_allocation (error_callback , scratch , STRAUSS_SCRATCH_OBJECTS ) / secp256k1_strauss_scratch_size (1 );
742
+ /* Call max_allocation with 0 objects because otherwise it would assume
743
+ * worst case padding but in this function we want to be exact. */
744
+ size_t max_alloc = secp256k1_scratch_max_allocation (error_callback , scratch , 0 );
745
+ size_t unpadded_single_size = secp256k1_strauss_scratch_size_raw (1 , 0 );
746
+ size_t n_points = max_alloc / unpadded_single_size ;
747
+ if (n_points > 0
748
+ && max_alloc < secp256k1_strauss_scratch_size (n_points )) {
749
+ /* If there's not enough space after alignment is taken into
750
+ * account, it suffices to decrease n_points by one. This is because
751
+ * the maximum padding required is less than an entry. */
752
+ n_points -= 1 ;
753
+ VERIFY_CHECK (max_alloc >= secp256k1_strauss_scratch_size (n_points ));
754
+ VERIFY_CHECK (max_alloc - secp256k1_scratch_max_allocation (error_callback , scratch , STRAUSS_SCRATCH_OBJECTS ) < unpadded_single_size );
755
+ }
756
+
757
+ return n_points ;
738
758
}
739
759
740
760
/** Convert a number to WNAF notation.
@@ -1151,12 +1171,17 @@ static int secp256k1_ecmult_pippenger_batch_single(const secp256k1_callback* err
1151
1171
}
1152
1172
1153
1173
/**
1154
- * Returns the maximum number of points in addition to G that can be used with
1155
- * a given scratch space. The function ensures that fewer points may also be
1156
- * used.
1174
+ * Returns the (near) maximum number of points in addition to G that can be
1175
+ * used with a given scratch space. It may not return the actual maximum number
1176
+ * of points possible. Otherwise, fewer points would not fit into the scratch
1177
+ * space in general. For a given number of points, calling this function with a
1178
+ * scratch space with pippenger_scratch_size left will return less than or
1179
+ * equal than the given number.
1157
1180
*/
1158
1181
static size_t secp256k1_pippenger_max_points (const secp256k1_callback * error_callback , secp256k1_scratch * scratch ) {
1159
- size_t max_alloc = secp256k1_scratch_max_allocation (error_callback , scratch , PIPPENGER_SCRATCH_OBJECTS );
1182
+ /* Call max_allocation with 0 objects because otherwise it would assume
1183
+ * worst case padding but in this function we want to be exact. */
1184
+ size_t max_alloc = secp256k1_scratch_max_allocation (error_callback , scratch , 0 );
1160
1185
int bucket_window ;
1161
1186
size_t res = 0 ;
1162
1187
@@ -1174,7 +1199,20 @@ static size_t secp256k1_pippenger_max_points(const secp256k1_callback* error_cal
1174
1199
}
1175
1200
space_for_points = max_alloc - space_constant ;
1176
1201
1202
+ /* Compute an upper bound for the number of points after subtracting
1203
+ * space for the base point G. It's an upper bound because alignment is
1204
+ * not taken into account. */
1177
1205
n_points = (space_for_points - entry_size )/entry_size ;
1206
+ if (n_points > 0
1207
+ && space_for_points < secp256k1_pippenger_scratch_size_points (n_points , bucket_window , 1 )) {
1208
+ /* If there's not enough space after alignment is taken into
1209
+ * account, it suffices to decrease n_points by one. This is because
1210
+ * the maximum padding required is less than an entry. */
1211
+ n_points -= 1 ;
1212
+ VERIFY_CHECK (max_alloc - secp256k1_scratch_max_allocation (error_callback , scratch , PIPPENGER_SCRATCH_OBJECTS ) < entry_size );
1213
+ VERIFY_CHECK (space_for_points >= secp256k1_pippenger_scratch_size_points (n_points , bucket_window , 1 ));
1214
+ }
1215
+
1178
1216
n_points = n_points > max_points ? max_points : n_points ;
1179
1217
if (n_points > res ) {
1180
1218
res = n_points ;
0 commit comments