n
is large enough then some or all multiplications could be skipped or the function could end up in an infinite loop. This PR adds two checks to prevent n
from wrapping around.
n
is large enough then some or all multiplications could be skipped or the function could end up in an infinite loop. This PR adds two checks to prevent n
from wrapping around.
982+ }
983+ /* Check overflow */
984+ if (n > (size_t)-1 - (max_points-1)) {
985+ return 0;
986+ }
987+ *n_batches = (n + max_points-1) / max_points;
0 *n_batches = (n + (max_points-1)) / max_points;
you could also CHECK/VERIFY that *n_batches != 0
here. As I understand it, this can only happen if n == 0
and then this function won’t be called currently.
987+ *n_batches = (n + max_points-1) / max_points;
988+ /* Check overflow */
989+ if (n > (size_t)-1 - (*n_batches-1)) {
990+ return 0;
991+ }
992+ *n_batch_points = (n + *n_batches-1) / *n_batches;
0 *n_batch_points = (n + (*n_batches-1)) / *n_batches;
971@@ -972,12 +972,32 @@ static size_t secp256k1_pippenger_max_points(secp256k1_scratch *scratch) {
972 return res;
973 }
974
975+/* Compute the number and size of batches given the maximum number of points in a batch and the
976+ * total number of points */
977+static int secp256k1_ecmult_multi_batch_size_helper(size_t *n_batches, size_t *n_batch_points, size_t max_points, size_t n) {
978+ if (max_points == 0) {
979+ return 0;
980+ } else if (max_points > ECMULT_MAX_POINTS_PER_BATCH) {
else
?
980+ }
981+ if (max_points > ECMULT_MAX_POINTS_PER_BATCH) {
982+ max_points = ECMULT_MAX_POINTS_PER_BATCH;
983+ }
984+ /* Check overflow */
985+ if (n > (size_t)-1 - (max_points-1)) {
size_t(-1)
to @jonasnick in the Schnorr signature PR: #558#pullrequestreview-165077679 Maybe that’s why @apoelstra used it in #557 too…
(size_t)-1
with MAX_SIZE
This seems fine, though you could also avoid the overflow checks entirely with
0n_batches = 1 + (n-1)/max_points;
1n_batch_points = 1 + (n-1)/n_batches;
This should work in all cases since n
is guaranteed to be > 0
.
I rewrote this PR with @jimpo’s suggestion. I think this is better because the previous code was complex enough that we missed a potential bug [0] and the new code doesn’t have unnecessary return 0’s. Because n = SIZE_MAX
is now actually possible I had to rewrite the tests to directly test the batch_size_helper.
[0] if (n_batches == 0 || n > SIZE_MAX - (*n_batches-1)) {
(first asterisk missing)