Skip to content

Commit dbc3ddd

Browse files
committed
Merge bitcoin#513: Increase sparsity of pippenger fixed window naf representation
ec0a7b3 Don't touch leading zeros in wnaf_fixed. (Jonas Nick) 9e36d1b Fix bug in wnaf_fixed where the wnaf array is not completely zeroed when given a 0 scalar. (Jonas Nick) 96f68a0 Don't invert scalar in wnaf_fixed when it is even because a caller might intentionally give a scalar with many leading zeros. (Jonas Nick) 6dbb007 Increase sparsity of pippenger fixed window naf representation (Jonas Nick) Pull request description: Fixes bitcoin#506 Tree-SHA512: 49a237a7d09c0c376ba4e6b1f522b9aff2517e420dfef9df810fd5ba920e0b98be8fe3f730b32e41b4aef475bc4cf3b13220024bd8d6f40c2744e6f392ff97a8
2 parents fb9271d + ec0a7b3 commit dbc3ddd

File tree

2 files changed

+92
-32
lines changed

2 files changed

+92
-32
lines changed

src/ecmult_impl.h

+38-27
Original file line numberDiff line numberDiff line change
@@ -563,53 +563,66 @@ static size_t secp256k1_strauss_max_points(secp256k1_scratch *scratch) {
563563
* It has the following guarantees:
564564
* - each wnaf[i] is either 0 or an odd integer between -(1 << w) and (1 << w)
565565
* - the number of words set is always WNAF_SIZE(w)
566-
* - the returned skew is 0 without endomorphism, or 0 or 1 with endomorphism
566+
* - the returned skew is 0 or 1
567567
*/
568568
static int secp256k1_wnaf_fixed(int *wnaf, const secp256k1_scalar *s, int w) {
569-
int sign = 0;
570569
int skew = 0;
571-
int pos = 1;
572-
#ifndef USE_ENDOMORPHISM
573-
secp256k1_scalar neg_s;
574-
#endif
570+
int pos;
571+
int max_pos;
572+
int last_w;
575573
const secp256k1_scalar *work = s;
576574

577575
if (secp256k1_scalar_is_zero(s)) {
578-
while (pos * w < WNAF_BITS) {
576+
for (pos = 0; pos < WNAF_SIZE(w); pos++) {
579577
wnaf[pos] = 0;
580-
++pos;
581578
}
582579
return 0;
583580
}
584581

585582
if (secp256k1_scalar_is_even(s)) {
586-
#ifdef USE_ENDOMORPHISM
587583
skew = 1;
588-
#else
589-
secp256k1_scalar_negate(&neg_s, s);
590-
work = &neg_s;
591-
sign = -1;
592-
#endif
593584
}
594585

595-
wnaf[0] = (secp256k1_scalar_get_bits_var(work, 0, w) + skew + sign) ^ sign;
586+
wnaf[0] = secp256k1_scalar_get_bits_var(work, 0, w) + skew;
587+
/* Compute last window size. Relevant when window size doesn't divide the
588+
* number of bits in the scalar */
589+
last_w = WNAF_BITS - (WNAF_SIZE(w) - 1) * w;
596590

597-
while (pos * w < WNAF_BITS) {
598-
int now = w;
599-
int val;
600-
if (now + pos * w > WNAF_BITS) {
601-
now = WNAF_BITS - pos * w;
591+
/* Store the position of the first nonzero word in max_pos to allow
592+
* skipping leading zeros when calculating the wnaf. */
593+
for (pos = WNAF_SIZE(w) - 1; pos > 0; pos--) {
594+
int val = secp256k1_scalar_get_bits_var(work, pos * w, pos == WNAF_SIZE(w)-1 ? last_w : w);
595+
if(val != 0) {
596+
break;
602597
}
603-
val = secp256k1_scalar_get_bits_var(work, pos * w, now);
598+
wnaf[pos] = 0;
599+
}
600+
max_pos = pos;
601+
pos = 1;
602+
603+
while (pos <= max_pos) {
604+
int val = secp256k1_scalar_get_bits_var(work, pos * w, pos == WNAF_SIZE(w)-1 ? last_w : w);
604605
if ((val & 1) == 0) {
605-
wnaf[pos - 1] -= ((1 << w) + sign) ^ sign;
606-
wnaf[pos] = (val + 1 + sign) ^ sign;
606+
wnaf[pos - 1] -= (1 << w);
607+
wnaf[pos] = (val + 1);
607608
} else {
608-
wnaf[pos] = (val + sign) ^ sign;
609+
wnaf[pos] = val;
610+
}
611+
/* Set a coefficient to zero if it is 1 or -1 and the proceeding digit
612+
* is strictly negative or strictly positive respectively. Only change
613+
* coefficients at previous positions because above code assumes that
614+
* wnaf[pos - 1] is odd.
615+
*/
616+
if (pos >= 2 && ((wnaf[pos - 1] == 1 && wnaf[pos - 2] < 0) || (wnaf[pos - 1] == -1 && wnaf[pos - 2] > 0))) {
617+
if (wnaf[pos - 1] == 1) {
618+
wnaf[pos - 2] += 1 << w;
619+
} else {
620+
wnaf[pos - 2] -= 1 << w;
621+
}
622+
wnaf[pos - 1] = 0;
609623
}
610624
++pos;
611625
}
612-
VERIFY_CHECK(pos == WNAF_SIZE(w));
613626

614627
return skew;
615628
}
@@ -665,7 +678,6 @@ static int secp256k1_ecmult_pippenger_wnaf(secp256k1_gej *buckets, int bucket_wi
665678
secp256k1_ge tmp;
666679
int idx;
667680

668-
#ifdef USE_ENDOMORPHISM
669681
if (i == 0) {
670682
/* correct for wnaf skew */
671683
int skew = point_state.skew_na;
@@ -674,7 +686,6 @@ static int secp256k1_ecmult_pippenger_wnaf(secp256k1_gej *buckets, int bucket_wi
674686
secp256k1_gej_add_ge_var(&buckets[0], &buckets[0], &tmp, NULL);
675687
}
676688
}
677-
#endif
678689
if (n > 0) {
679690
idx = (n - 1)/2;
680691
secp256k1_gej_add_ge_var(&buckets[idx], &buckets[idx], &pt[point_state.input_pos], NULL);

src/tests.c

+54-5
Original file line numberDiff line numberDiff line change
@@ -3022,8 +3022,7 @@ void test_fixed_wnaf(const secp256k1_scalar *number, int w) {
30223022
for (i = WNAF_SIZE(w)-1; i >= 0; --i) {
30233023
secp256k1_scalar t;
30243024
int v = wnaf[i];
3025-
CHECK(v != 0); /* check nonzero */
3026-
CHECK(v & 1); /* check parity */
3025+
CHECK(v == 0 || v & 1); /* check parity */
30273026
CHECK(v > -(1 << w)); /* check range above */
30283027
CHECK(v < (1 << w)); /* check range below */
30293028

@@ -3041,20 +3040,70 @@ void test_fixed_wnaf(const secp256k1_scalar *number, int w) {
30413040
CHECK(secp256k1_scalar_eq(&x, &num));
30423041
}
30433042

3044-
void test_fixed_wnaf_zero(int w) {
3043+
/* Checks that the first 8 elements of wnaf are equal to wnaf_expected and the
3044+
* rest is 0.*/
3045+
void test_fixed_wnaf_small_helper(int *wnaf, int *wnaf_expected, int w) {
3046+
int i;
3047+
for (i = WNAF_SIZE(w)-1; i >= 8; --i) {
3048+
CHECK(wnaf[i] == 0);
3049+
}
3050+
for (i = 7; i >= 0; --i) {
3051+
CHECK(wnaf[i] == wnaf_expected[i]);
3052+
}
3053+
}
3054+
3055+
void test_fixed_wnaf_small(void) {
3056+
int w = 4;
30453057
int wnaf[256] = {0};
30463058
int i;
30473059
int skew;
30483060
secp256k1_scalar num;
30493061

30503062
secp256k1_scalar_set_int(&num, 0);
30513063
skew = secp256k1_wnaf_fixed(wnaf, &num, w);
3052-
30533064
for (i = WNAF_SIZE(w)-1; i >= 0; --i) {
30543065
int v = wnaf[i];
30553066
CHECK(v == 0);
30563067
}
30573068
CHECK(skew == 0);
3069+
3070+
secp256k1_scalar_set_int(&num, 1);
3071+
skew = secp256k1_wnaf_fixed(wnaf, &num, w);
3072+
for (i = WNAF_SIZE(w)-1; i >= 1; --i) {
3073+
int v = wnaf[i];
3074+
CHECK(v == 0);
3075+
}
3076+
CHECK(wnaf[0] == 1);
3077+
CHECK(skew == 0);
3078+
3079+
{
3080+
int wnaf_expected[8] = { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf };
3081+
secp256k1_scalar_set_int(&num, 0xffffffff);
3082+
skew = secp256k1_wnaf_fixed(wnaf, &num, w);
3083+
test_fixed_wnaf_small_helper(wnaf, wnaf_expected, w);
3084+
CHECK(skew == 0);
3085+
}
3086+
{
3087+
int wnaf_expected[8] = { -1, -1, -1, -1, -1, -1, -1, 0xf };
3088+
secp256k1_scalar_set_int(&num, 0xeeeeeeee);
3089+
skew = secp256k1_wnaf_fixed(wnaf, &num, w);
3090+
test_fixed_wnaf_small_helper(wnaf, wnaf_expected, w);
3091+
CHECK(skew == 1);
3092+
}
3093+
{
3094+
int wnaf_expected[8] = { 1, 0, 1, 0, 1, 0, 1, 0 };
3095+
secp256k1_scalar_set_int(&num, 0x01010101);
3096+
skew = secp256k1_wnaf_fixed(wnaf, &num, w);
3097+
test_fixed_wnaf_small_helper(wnaf, wnaf_expected, w);
3098+
CHECK(skew == 0);
3099+
}
3100+
{
3101+
int wnaf_expected[8] = { -0xf, 0, 0xf, -0xf, 0, 0xf, 1, 0 };
3102+
secp256k1_scalar_set_int(&num, 0x01ef1ef1);
3103+
skew = secp256k1_wnaf_fixed(wnaf, &num, w);
3104+
test_fixed_wnaf_small_helper(wnaf, wnaf_expected, w);
3105+
CHECK(skew == 0);
3106+
}
30583107
}
30593108

30603109
void run_wnaf(void) {
@@ -3068,7 +3117,7 @@ void run_wnaf(void) {
30683117
n.d[0] = 2;
30693118
test_constant_wnaf(&n, 4);
30703119
/* Test 0 */
3071-
test_fixed_wnaf_zero(4);
3120+
test_fixed_wnaf_small();
30723121
/* Random tests */
30733122
for (i = 0; i < count; i++) {
30743123
random_scalar_order(&n);

0 commit comments

Comments
 (0)