@@ -437,8 +437,27 @@ static int secp256k1_ecmult_strauss_batch_single(const secp256k1_callback* error
437437 return secp256k1_ecmult_strauss_batch (error_callback , scratch , r , inp_g_sc , cb , cbdata , n , 0 );
438438}
439439
440+ /* Returns the maximum number of points in addition to G that can be used with a
441+ * given scratch space. If a scratch space has exactly
442+ * `strauss_scratch_size(n_points)` left, then
443+ * `strauss_max_points(cb, scratch) = n_points`. */
440444static size_t secp256k1_strauss_max_points (const secp256k1_callback * error_callback , secp256k1_scratch * scratch ) {
441- return secp256k1_scratch_max_allocation (error_callback , scratch , STRAUSS_SCRATCH_OBJECTS ) / secp256k1_strauss_scratch_size (1 );
445+ /* Call max_allocation with 0 objects because otherwise it would assume
446+ * worst case padding but in this function we want to be exact. */
447+ size_t max_alloc = secp256k1_scratch_max_allocation (error_callback , scratch , 0 );
448+ size_t unpadded_single_size = secp256k1_strauss_scratch_size_raw (1 , 0 );
449+ size_t n_points = max_alloc / unpadded_single_size ;
450+ if (n_points > 0
451+ && max_alloc < secp256k1_strauss_scratch_size (n_points )) {
452+ /* If there's not enough space after alignment is taken into
453+ * account, it suffices to decrease n_points by one. This is because
454+ * the maximum padding required is less than an entry. */
455+ n_points -= 1 ;
456+ VERIFY_CHECK (max_alloc >= secp256k1_strauss_scratch_size (n_points ));
457+ VERIFY_CHECK (max_alloc - secp256k1_scratch_max_allocation (error_callback , scratch , STRAUSS_SCRATCH_OBJECTS ) < unpadded_single_size );
458+ }
459+
460+ return n_points ;
442461}
443462
444463/** Convert a number to WNAF notation.
@@ -801,13 +820,17 @@ static int secp256k1_ecmult_pippenger_batch_single(const secp256k1_callback* err
801820 return secp256k1_ecmult_pippenger_batch (error_callback , scratch , r , inp_g_sc , cb , cbdata , n , 0 );
802821}
803822
804- /**
805- * Returns the maximum number of points in addition to G that can be used with
806- * a given scratch space. The function ensures that fewer points may also be
807- * used.
823+ /* Returns the (near) maximum number of points in addition to G that can be
824+ * used with a given scratch space. It may not return the actual maximum number
825+ * of points possible. Otherwise, fewer points would not fit into the scratch
826+ * space in general. If a scratch space has exactly
827+ * `pippenger_scratch_size(n_points)` left, then
828+ * `pippenger_max_points(cb, scratch) <= n_points`.
808829 */
809830static size_t secp256k1_pippenger_max_points (const secp256k1_callback * error_callback , secp256k1_scratch * scratch ) {
810- size_t max_alloc = secp256k1_scratch_max_allocation (error_callback , scratch , PIPPENGER_SCRATCH_OBJECTS );
831+ /* Call max_allocation with 0 objects because otherwise it would assume
832+ * worst case padding but in this function we want to be exact. */
833+ size_t max_alloc = secp256k1_scratch_max_allocation (error_callback , scratch , 0 );
811834 int bucket_window ;
812835 size_t res = 0 ;
813836
@@ -828,6 +851,20 @@ static size_t secp256k1_pippenger_max_points(const secp256k1_callback* error_cal
828851 /* Compute an upper bound for the number excluding the base point G.
829852 * It's an upper bound because alignment is not taken into account. */
830853 n_points = space_for_points / entry_size - 1 ;
854+ /* Compute an upper bound for the number of points after subtracting
855+ * space for the base point G. It's an upper bound because alignment is
856+ * not taken into account. */
857+ n_points = (space_for_points - entry_size )/entry_size ;
858+ if (n_points > 0
859+ && space_for_points < secp256k1_pippenger_scratch_size_points (n_points , bucket_window , 1 )) {
860+ /* If there's not enough space after alignment is taken into
861+ * account, it suffices to decrease n_points by one. This is because
862+ * the maximum padding required is less than an entry. */
863+ n_points -= 1 ;
864+ VERIFY_CHECK (max_alloc - secp256k1_scratch_max_allocation (error_callback , scratch , PIPPENGER_SCRATCH_OBJECTS ) < entry_size );
865+ VERIFY_CHECK (space_for_points >= secp256k1_pippenger_scratch_size_points (n_points , bucket_window , 1 ));
866+ }
867+
831868 n_points = n_points > max_points ? max_points : n_points ;
832869 if (n_points > res ) {
833870 res = n_points ;
0 commit comments