]> Git Repo - secp256k1.git/commitdiff
Merge #741: Remove unnecessary sign variable from wnaf_const
authorTim Ruffing <[email protected]>
Sun, 26 Jul 2020 10:18:17 +0000 (12:18 +0200)
committerTim Ruffing <[email protected]>
Sun, 26 Jul 2020 10:21:14 +0000 (12:21 +0200)
37dba329c6cb0f7a4228a11dc26aa3a342a3a5d0 Remove unnecessary sign variable from wnaf_const (Jonas Nick)
6bb0b77e158fc2f9e56e4b65b08bcb660d4c588b Fix test_constant_wnaf for -1 and add a test for it. (Jonas Nick)

Pull request description:

  There currently is a single branch in the `ecmul_const` function that is not being exercised by the tests. This branch is unreachable and therefore I'm suggesting to remove it.

  For your convenience the paper the wnaf algorithm can be found [here (The Width-w NAF Method Provides Small Memory and Fast Elliptic Scalar Multiplications Secure against Side Channel Attacks)](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.563.1267&rep=rep1&type=pdf). Similarly, unless I'm missing something important, I don't see how their algorithm needs to consider `sign(u[i-1])` unless `d` can be negative - which doesn't make much sense to me either.

ACKs for top commit:
  real-or-random:
    ACK 37dba329c6cb0f7a4228a11dc26aa3a342a3a5d0 I verified the correctness of the change and claimed invariant by manual inspection. I tested the code, both with 32bit and 64bit scalars.

Tree-SHA512: 9db45f76bd881d00a81923b6d2ae1c3e0f49a82a5d55347f01e1ce4e924d9a3bf55483a0697f25039c327e33edca6796ba3205c068d9f2f99aa5d655e46b15be

1  2 
src/ecmult_const_impl.h
src/tests.c

diff --combined src/ecmult_const_impl.h
index 6d6d354aa4e1aa4583af6f9591800c5618c48fa1,0c26b1e767e2cab84df74dfd147ec1d848974abe..e28cdce7c166e5f18858e4687a33849233cbdec8
@@@ -14,7 -14,7 +14,7 @@@
  
  /* This is like `ECMULT_TABLE_GET_GE` but is constant time */
  #define ECMULT_CONST_TABLE_GET_GE(r,pre,n,w) do { \
 -    int m; \
 +    int m = 0; \
      /* Extract the sign-bit for a constant time absolute-value. */ \
      int mask = (n) >> (sizeof(n) * CHAR_BIT - 1); \
      int abs_n = ((n) + mask) ^ mask; \
      VERIFY_CHECK((n) <=  ((1 << ((w)-1)) - 1)); \
      VERIFY_SETUP(secp256k1_fe_clear(&(r)->x)); \
      VERIFY_SETUP(secp256k1_fe_clear(&(r)->y)); \
 -    for (m = 0; m < ECMULT_TABLE_SIZE(w); m++) { \
 +    /* Unconditionally set r->x = (pre)[m].x. r->y = (pre)[m].y. because it's either the correct one \
 +     * or will get replaced in the later iterations, this is needed to make sure `r` is initialized. */ \
 +    (r)->x = (pre)[m].x; \
 +    (r)->y = (pre)[m].y; \
 +    for (m = 1; m < ECMULT_TABLE_SIZE(w); m++) { \
          /* This loop is used to avoid secret data in array indices. See
           * the comment in ecmult_gen_impl.h for rationale. */ \
          secp256k1_fe_cmov(&(r)->x, &(pre)[m].x, m == idx_n); \
@@@ -50,7 -46,7 +50,7 @@@
   *
   *  Adapted from `The Width-w NAF Method Provides Small Memory and Fast Elliptic Scalar
   *  Multiplications Secure against Side Channel Attacks`, Okeya and Tagaki. M. Joye (Ed.)
 - *  CT-RSA 2003, LNCS 2612, pp. 328-443, 2003. Springer-Verlagy Berlin Heidelberg 2003
 + *  CT-RSA 2003, LNCS 2612, pp. 328-443, 2003. Springer-Verlag Berlin Heidelberg 2003
   *
   *  Numbers reference steps of `Algorithm SPA-resistant Width-w NAF with Odd Scalar` on pp. 335
   */
@@@ -105,16 -101,22 +105,22 @@@ static int secp256k1_wnaf_const(int *wn
      /* 4 */
      u_last = secp256k1_scalar_shr_int(&s, w);
      do {
-         int sign;
          int even;
  
          /* 4.1 4.4 */
          u = secp256k1_scalar_shr_int(&s, w);
          /* 4.2 */
          even = ((u & 1) == 0);
-         sign = 2 * (u_last > 0) - 1;
-         u += sign * even;
-         u_last -= sign * even * (1 << w);
+         /* In contrast to the original algorithm, u_last is always > 0 and
+          * therefore we do not need to check its sign. In particular, it's easy
+          * to see that u_last is never < 0 because u is never < 0. Moreover,
+          * u_last is never = 0 because u is never even after a loop
+          * iteration. The same holds analogously for the initial value of
+          * u_last (in the first loop iteration). */
+         VERIFY_CHECK(u_last > 0);
+         VERIFY_CHECK((u_last & 1) == 1);
+         u += even;
+         u_last -= even * (1 << w);
  
          /* 4.3, adapted for global sign change */
          wnaf[word++] = u_last * global_sign;
diff --combined src/tests.c
index b07a8e6dd03ea5559f9056671cbc4608db1b3833,1040b6e508df8608ecdc1d95c53e9f5a7819fcd0..541bd65e6261a4894ac7dc0711e3c528738d5205
@@@ -32,6 -32,17 +32,6 @@@ void ECDSA_SIG_get0(const ECDSA_SIG *si
  #include "contrib/lax_der_parsing.c"
  #include "contrib/lax_der_privatekey_parsing.c"
  
 -#if !defined(VG_CHECK)
 -# if defined(VALGRIND)
 -#  include <valgrind/memcheck.h>
 -#  define VG_UNDEF(x,y) VALGRIND_MAKE_MEM_UNDEFINED((x),(y))
 -#  define VG_CHECK(x,y) VALGRIND_CHECK_MEM_IS_DEFINED((x),(y))
 -# else
 -#  define VG_UNDEF(x,y)
 -#  define VG_CHECK(x,y)
 -# endif
 -#endif
 -
  static int count = 64;
  static secp256k1_context *ctx = NULL;
  
@@@ -129,12 -140,6 +129,12 @@@ void random_scalar_order(secp256k1_scal
      } while(1);
  }
  
 +void random_scalar_order_b32(unsigned char *b32) {
 +    secp256k1_scalar num;
 +    random_scalar_order(&num);
 +    secp256k1_scalar_get_b32(b32, &num);
 +}
 +
  void run_context_tests(int use_prealloc) {
      secp256k1_pubkey pubkey;
      secp256k1_pubkey zero_pubkey;
@@@ -1072,31 -1077,11 +1072,31 @@@ void scalar_test(void) 
  
  }
  
 +void run_scalar_set_b32_seckey_tests(void) {
 +    unsigned char b32[32];
 +    secp256k1_scalar s1;
 +    secp256k1_scalar s2;
 +
 +    /* Usually set_b32 and set_b32_seckey give the same result */
 +    random_scalar_order_b32(b32);
 +    secp256k1_scalar_set_b32(&s1, b32, NULL);
 +    CHECK(secp256k1_scalar_set_b32_seckey(&s2, b32) == 1);
 +    CHECK(secp256k1_scalar_eq(&s1, &s2) == 1);
 +
 +    memset(b32, 0, sizeof(b32));
 +    CHECK(secp256k1_scalar_set_b32_seckey(&s2, b32) == 0);
 +    memset(b32, 0xFF, sizeof(b32));
 +    CHECK(secp256k1_scalar_set_b32_seckey(&s2, b32) == 0);
 +}
 +
  void run_scalar_tests(void) {
      int i;
      for (i = 0; i < 128 * count; i++) {
          scalar_test();
      }
 +    for (i = 0; i < count; i++) {
 +        run_scalar_set_b32_seckey_tests();
 +    }
  
      {
          /* (-1)+1 should be zero. */
  
  #ifndef USE_NUM_NONE
      {
 -        /* A scalar with value of the curve order should be 0. */
 +        /* Test secp256k1_scalar_set_b32 boundary conditions */
          secp256k1_num order;
 -        secp256k1_scalar zero;
 +        secp256k1_scalar scalar;
          unsigned char bin[32];
 +        unsigned char bin_tmp[32];
          int overflow = 0;
 +        /* 2^256-1 - order */
 +        static const secp256k1_scalar all_ones_minus_order = SECP256K1_SCALAR_CONST(
 +            0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000001UL,
 +            0x45512319UL, 0x50B75FC4UL, 0x402DA173UL, 0x2FC9BEBEUL
 +        );
 +
 +        /* A scalar set to 0s should be 0. */
 +        memset(bin, 0, 32);
 +        secp256k1_scalar_set_b32(&scalar, bin, &overflow);
 +        CHECK(overflow == 0);
 +        CHECK(secp256k1_scalar_is_zero(&scalar));
 +
 +        /* A scalar with value of the curve order should be 0. */
          secp256k1_scalar_order_get_num(&order);
          secp256k1_num_get_bin(bin, 32, &order);
 -        secp256k1_scalar_set_b32(&zero, bin, &overflow);
 +        secp256k1_scalar_set_b32(&scalar, bin, &overflow);
          CHECK(overflow == 1);
 -        CHECK(secp256k1_scalar_is_zero(&zero));
 +        CHECK(secp256k1_scalar_is_zero(&scalar));
 +
 +        /* A scalar with value of the curve order minus one should not overflow. */
 +        bin[31] -= 1;
 +        secp256k1_scalar_set_b32(&scalar, bin, &overflow);
 +        CHECK(overflow == 0);
 +        secp256k1_scalar_get_b32(bin_tmp, &scalar);
 +        CHECK(memcmp(bin, bin_tmp, 32) == 0);
 +
 +        /* A scalar set to all 1s should overflow. */
 +        memset(bin, 0xFF, 32);
 +        secp256k1_scalar_set_b32(&scalar, bin, &overflow);
 +        CHECK(overflow == 1);
 +        CHECK(secp256k1_scalar_eq(&scalar, &all_ones_minus_order));
      }
  #endif
  
@@@ -2967,16 -2925,14 +2967,16 @@@ void test_ecmult_multi(secp256k1_scratc
  
  void test_ecmult_multi_batch_single(secp256k1_ecmult_multi_func ecmult_multi) {
      secp256k1_scalar szero;
 -    secp256k1_scalar sc[32];
 -    secp256k1_ge pt[32];
 +    secp256k1_scalar sc;
 +    secp256k1_ge pt;
      secp256k1_gej r;
      ecmult_multi_data data;
      secp256k1_scratch *scratch_empty;
  
 -    data.sc = sc;
 -    data.pt = pt;
 +    random_group_element_test(&pt);
 +    random_scalar_order(&sc);
 +    data.sc = &sc;
 +    data.pt = &pt;
      secp256k1_scalar_set_int(&szero, 0);
  
      /* Try to multiply 1 point, but scratch space is empty.*/
@@@ -3120,7 -3076,7 +3120,7 @@@ void test_ecmult_multi_batching(void) 
      data.pt = pt;
      secp256k1_gej_neg(&r2, &r2);
  
 -    /* Test with empty scratch space. It should compute the correct result using 
 +    /* Test with empty scratch space. It should compute the correct result using
       * ecmult_mult_simple algorithm which doesn't require a scratch space. */
      scratch = secp256k1_scratch_create(&ctx->error_callback, 0);
      CHECK(secp256k1_ecmult_multi_var(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, n_points));
@@@ -3234,6 -3190,7 +3234,7 @@@ void test_constant_wnaf(const secp256k1
      int skew;
      int bits = 256;
      secp256k1_scalar num = *number;
+     secp256k1_scalar scalar_skew;
  
      secp256k1_scalar_set_int(&x, 0);
      secp256k1_scalar_set_int(&shift, 1 << w);
          secp256k1_scalar_add(&x, &x, &t);
      }
      /* Skew num because when encoding numbers as odd we use an offset */
-     secp256k1_scalar_cadd_bit(&num, skew == 2, 1);
+     secp256k1_scalar_set_int(&scalar_skew, 1 << (skew == 2));
+     secp256k1_scalar_add(&num, &num, &scalar_skew);
      CHECK(secp256k1_scalar_eq(&x, &num));
  }
  
@@@ -3376,13 -3334,32 +3378,32 @@@ void run_wnaf(void) 
      int i;
      secp256k1_scalar n = {{0}};
  
+     test_constant_wnaf(&n, 4);
      /* Sanity check: 1 and 2 are the smallest odd and even numbers and should
       *               have easier-to-diagnose failure modes  */
      n.d[0] = 1;
      test_constant_wnaf(&n, 4);
      n.d[0] = 2;
      test_constant_wnaf(&n, 4);
-     /* Test 0 */
+     /* Test -1, because it's a special case in wnaf_const */
+     n = secp256k1_scalar_one;
+     secp256k1_scalar_negate(&n, &n);
+     test_constant_wnaf(&n, 4);
+     /* Test -2, which may not lead to overflows in wnaf_const */
+     secp256k1_scalar_add(&n, &secp256k1_scalar_one, &secp256k1_scalar_one);
+     secp256k1_scalar_negate(&n, &n);
+     test_constant_wnaf(&n, 4);
+     /* Test (1/2) - 1 = 1/-2 and 1/2 = (1/-2) + 1
+        as corner cases of negation handling in wnaf_const */
+     secp256k1_scalar_inverse(&n, &n);
+     test_constant_wnaf(&n, 4);
+     secp256k1_scalar_add(&n, &n, &secp256k1_scalar_one);
+     test_constant_wnaf(&n, 4);
+     /* Test 0 for fixed wnaf */
      test_fixed_wnaf_small();
      /* Random tests */
      for (i = 0; i < count; i++) {
@@@ -3980,57 -3957,37 +4001,57 @@@ void run_eckey_edge_case_test(void) 
      pubkey_negone = pubkey;
      /* Tweak of zero leaves the value unchanged. */
      memset(ctmp2, 0, 32);
 -    CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, ctmp2) == 1);
 +    CHECK(secp256k1_ec_seckey_tweak_add(ctx, ctmp, ctmp2) == 1);
      CHECK(memcmp(orderc, ctmp, 31) == 0 && ctmp[31] == 0x40);
      memcpy(&pubkey2, &pubkey, sizeof(pubkey));
      CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1);
      CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0);
      /* Multiply tweak of zero zeroizes the output. */
 -    CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, ctmp2) == 0);
 +    CHECK(secp256k1_ec_seckey_tweak_mul(ctx, ctmp, ctmp2) == 0);
      CHECK(memcmp(zeros, ctmp, 32) == 0);
      CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, ctmp2) == 0);
      CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0);
      memcpy(&pubkey, &pubkey2, sizeof(pubkey));
 -    /* Overflowing key tweak zeroizes. */
 +    /* If seckey_tweak_add or seckey_tweak_mul are called with an overflowing
 +    seckey, the seckey is zeroized. */
 +    memcpy(ctmp, orderc, 32);
 +    memset(ctmp2, 0, 32);
 +    ctmp2[31] = 0x01;
 +    CHECK(secp256k1_ec_seckey_verify(ctx, ctmp2) == 1);
 +    CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0);
 +    CHECK(secp256k1_ec_seckey_tweak_add(ctx, ctmp, ctmp2) == 0);
 +    CHECK(memcmp(zeros, ctmp, 32) == 0);
 +    memcpy(ctmp, orderc, 32);
 +    CHECK(secp256k1_ec_seckey_tweak_mul(ctx, ctmp, ctmp2) == 0);
 +    CHECK(memcmp(zeros, ctmp, 32) == 0);
 +    /* If seckey_tweak_add or seckey_tweak_mul are called with an overflowing
 +    tweak, the seckey is zeroized. */
      memcpy(ctmp, orderc, 32);
      ctmp[31] = 0x40;
 -    CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, orderc) == 0);
 +    CHECK(secp256k1_ec_seckey_tweak_add(ctx, ctmp, orderc) == 0);
      CHECK(memcmp(zeros, ctmp, 32) == 0);
      memcpy(ctmp, orderc, 32);
      ctmp[31] = 0x40;
 -    CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, orderc) == 0);
 +    CHECK(secp256k1_ec_seckey_tweak_mul(ctx, ctmp, orderc) == 0);
      CHECK(memcmp(zeros, ctmp, 32) == 0);
      memcpy(ctmp, orderc, 32);
      ctmp[31] = 0x40;
 +    /* If pubkey_tweak_add or pubkey_tweak_mul are called with an overflowing
 +    tweak, the pubkey is zeroized. */
      CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, orderc) == 0);
      CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0);
      memcpy(&pubkey, &pubkey2, sizeof(pubkey));
      CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, orderc) == 0);
      CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0);
      memcpy(&pubkey, &pubkey2, sizeof(pubkey));
 -    /* Private key tweaks results in a key of zero. */
 +    /* If the resulting key in secp256k1_ec_seckey_tweak_add and
 +     * secp256k1_ec_pubkey_tweak_add is 0 the functions fail and in the latter
 +     * case the pubkey is zeroized. */
 +    memcpy(ctmp, orderc, 32);
 +    ctmp[31] = 0x40;
 +    memset(ctmp2, 0, 32);
      ctmp2[31] = 1;
 -    CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp2, ctmp) == 0);
 +    CHECK(secp256k1_ec_seckey_tweak_add(ctx, ctmp2, ctmp) == 0);
      CHECK(memcmp(zeros, ctmp2, 32) == 0);
      ctmp2[31] = 1;
      CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 0);
      memcpy(&pubkey, &pubkey2, sizeof(pubkey));
      /* Tweak computation wraps and results in a key of 1. */
      ctmp2[31] = 2;
 -    CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp2, ctmp) == 1);
 +    CHECK(secp256k1_ec_seckey_tweak_add(ctx, ctmp2, ctmp) == 1);
      CHECK(memcmp(ctmp2, zeros, 31) == 0 && ctmp2[31] == 1);
      ctmp2[31] = 2;
      CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1);
      CHECK(ecount == 2);
      ecount = 0;
      memset(ctmp2, 0, 32);
 -    CHECK(secp256k1_ec_privkey_tweak_add(ctx, NULL, ctmp2) == 0);
 +    CHECK(secp256k1_ec_seckey_tweak_add(ctx, NULL, ctmp2) == 0);
      CHECK(ecount == 1);
 -    CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, NULL) == 0);
 +    CHECK(secp256k1_ec_seckey_tweak_add(ctx, ctmp, NULL) == 0);
      CHECK(ecount == 2);
      ecount = 0;
      memset(ctmp2, 0, 32);
      ctmp2[31] = 1;
 -    CHECK(secp256k1_ec_privkey_tweak_mul(ctx, NULL, ctmp2) == 0);
 +    CHECK(secp256k1_ec_seckey_tweak_mul(ctx, NULL, ctmp2) == 0);
      CHECK(ecount == 1);
 -    CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, NULL) == 0);
 +    CHECK(secp256k1_ec_seckey_tweak_mul(ctx, ctmp, NULL) == 0);
      CHECK(ecount == 2);
      ecount = 0;
      CHECK(secp256k1_ec_pubkey_create(ctx, NULL, ctmp) == 0);
      secp256k1_context_set_illegal_callback(ctx, NULL, NULL);
  }
  
 +void run_eckey_negate_test(void) {
 +    unsigned char seckey[32];
 +    unsigned char seckey_tmp[32];
 +
 +    random_scalar_order_b32(seckey);
 +    memcpy(seckey_tmp, seckey, 32);
 +
 +    /* Verify negation changes the key and changes it back */
 +    CHECK(secp256k1_ec_seckey_negate(ctx, seckey) == 1);
 +    CHECK(memcmp(seckey, seckey_tmp, 32) != 0);
 +    CHECK(secp256k1_ec_seckey_negate(ctx, seckey) == 1);
 +    CHECK(memcmp(seckey, seckey_tmp, 32) == 0);
 +
 +    /* Check that privkey alias gives same result */
 +    CHECK(secp256k1_ec_seckey_negate(ctx, seckey) == 1);
 +    CHECK(secp256k1_ec_privkey_negate(ctx, seckey_tmp) == 1);
 +    CHECK(memcmp(seckey, seckey_tmp, 32) == 0);
 +
 +    /* Negating all 0s fails */
 +    memset(seckey, 0, 32);
 +    memset(seckey_tmp, 0, 32);
 +    CHECK(secp256k1_ec_seckey_negate(ctx, seckey) == 0);
 +    /* Check that seckey is not modified */
 +    CHECK(memcmp(seckey, seckey_tmp, 32) == 0);
 +
 +    /* Negating an overflowing seckey fails and the seckey is zeroed. In this
 +     * test, the seckey has 16 random bytes to ensure that ec_seckey_negate
 +     * doesn't just set seckey to a constant value in case of failure. */
 +    random_scalar_order_b32(seckey);
 +    memset(seckey, 0xFF, 16);
 +    memset(seckey_tmp, 0, 32);
 +    CHECK(secp256k1_ec_seckey_negate(ctx, seckey) == 0);
 +    CHECK(memcmp(seckey, seckey_tmp, 32) == 0);
 +}
 +
  void random_sign(secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *key, const secp256k1_scalar *msg, int *recid) {
      secp256k1_scalar nonce;
      do {
@@@ -4342,22 -4264,15 +4363,22 @@@ void test_ecdsa_end_to_end(void) 
      if (secp256k1_rand_int(3) == 0) {
          int ret1;
          int ret2;
 +        int ret3;
          unsigned char rnd[32];
 +        unsigned char privkey_tmp[32];
          secp256k1_pubkey pubkey2;
          secp256k1_rand256_test(rnd);
 -        ret1 = secp256k1_ec_privkey_tweak_add(ctx, privkey, rnd);
 +        memcpy(privkey_tmp, privkey, 32);
 +        ret1 = secp256k1_ec_seckey_tweak_add(ctx, privkey, rnd);
          ret2 = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, rnd);
 +        /* Check that privkey alias gives same result */
 +        ret3 = secp256k1_ec_privkey_tweak_add(ctx, privkey_tmp, rnd);
          CHECK(ret1 == ret2);
 +        CHECK(ret2 == ret3);
          if (ret1 == 0) {
              return;
          }
 +        CHECK(memcmp(privkey, privkey_tmp, 32) == 0);
          CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, privkey) == 1);
          CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0);
      }
      if (secp256k1_rand_int(3) == 0) {
          int ret1;
          int ret2;
 +        int ret3;
          unsigned char rnd[32];
 +        unsigned char privkey_tmp[32];
          secp256k1_pubkey pubkey2;
          secp256k1_rand256_test(rnd);
 -        ret1 = secp256k1_ec_privkey_tweak_mul(ctx, privkey, rnd);
 +        memcpy(privkey_tmp, privkey, 32);
 +        ret1 = secp256k1_ec_seckey_tweak_mul(ctx, privkey, rnd);
          ret2 = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, rnd);
 +        /* Check that privkey alias gives same result */
 +        ret3 = secp256k1_ec_privkey_tweak_mul(ctx, privkey_tmp, rnd);
          CHECK(ret1 == ret2);
 +        CHECK(ret2 == ret3);
          if (ret1 == 0) {
              return;
          }
 +        CHECK(memcmp(privkey, privkey_tmp, 32) == 0);
          CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, privkey) == 1);
          CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0);
      }
@@@ -5294,161 -5202,6 +5315,161 @@@ void run_memczero_test(void) 
      CHECK(memcmp(buf1, buf2, sizeof(buf1)) == 0);
  }
  
 +void int_cmov_test(void) {
 +    int r = INT_MAX;
 +    int a = 0;
 +
 +    secp256k1_int_cmov(&r, &a, 0);
 +    CHECK(r == INT_MAX);
 +
 +    r = 0; a = INT_MAX;
 +    secp256k1_int_cmov(&r, &a, 1);
 +    CHECK(r == INT_MAX);
 +
 +    a = 0;
 +    secp256k1_int_cmov(&r, &a, 1);
 +    CHECK(r == 0);
 +
 +    a = 1;
 +    secp256k1_int_cmov(&r, &a, 1);
 +    CHECK(r == 1);
 +
 +    r = 1; a = 0;
 +    secp256k1_int_cmov(&r, &a, 0);
 +    CHECK(r == 1);
 +
 +}
 +
 +void fe_cmov_test(void) {
 +    static const secp256k1_fe zero = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0);
 +    static const secp256k1_fe one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1);
 +    static const secp256k1_fe max = SECP256K1_FE_CONST(
 +        0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL,
 +        0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL
 +    );
 +    secp256k1_fe r = max;
 +    secp256k1_fe a = zero;
 +
 +    secp256k1_fe_cmov(&r, &a, 0);
 +    CHECK(memcmp(&r, &max, sizeof(r)) == 0);
 +
 +    r = zero; a = max;
 +    secp256k1_fe_cmov(&r, &a, 1);
 +    CHECK(memcmp(&r, &max, sizeof(r)) == 0);
 +
 +    a = zero;
 +    secp256k1_fe_cmov(&r, &a, 1);
 +    CHECK(memcmp(&r, &zero, sizeof(r)) == 0);
 +
 +    a = one;
 +    secp256k1_fe_cmov(&r, &a, 1);
 +    CHECK(memcmp(&r, &one, sizeof(r)) == 0);
 +
 +    r = one; a = zero;
 +    secp256k1_fe_cmov(&r, &a, 0);
 +    CHECK(memcmp(&r, &one, sizeof(r)) == 0);
 +}
 +
 +void fe_storage_cmov_test(void) {
 +    static const secp256k1_fe_storage zero = SECP256K1_FE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 0);
 +    static const secp256k1_fe_storage one = SECP256K1_FE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 1);
 +    static const secp256k1_fe_storage max = SECP256K1_FE_STORAGE_CONST(
 +        0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL,
 +        0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL
 +    );
 +    secp256k1_fe_storage r = max;
 +    secp256k1_fe_storage a = zero;
 +
 +    secp256k1_fe_storage_cmov(&r, &a, 0);
 +    CHECK(memcmp(&r, &max, sizeof(r)) == 0);
 +
 +    r = zero; a = max;
 +    secp256k1_fe_storage_cmov(&r, &a, 1);
 +    CHECK(memcmp(&r, &max, sizeof(r)) == 0);
 +
 +    a = zero;
 +    secp256k1_fe_storage_cmov(&r, &a, 1);
 +    CHECK(memcmp(&r, &zero, sizeof(r)) == 0);
 +
 +    a = one;
 +    secp256k1_fe_storage_cmov(&r, &a, 1);
 +    CHECK(memcmp(&r, &one, sizeof(r)) == 0);
 +
 +    r = one; a = zero;
 +    secp256k1_fe_storage_cmov(&r, &a, 0);
 +    CHECK(memcmp(&r, &one, sizeof(r)) == 0);
 +}
 +
 +void scalar_cmov_test(void) {
 +    static const secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0);
 +    static const secp256k1_scalar one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1);
 +    static const secp256k1_scalar max = SECP256K1_SCALAR_CONST(
 +        0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL,
 +        0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL
 +    );
 +    secp256k1_scalar r = max;
 +    secp256k1_scalar a = zero;
 +
 +    secp256k1_scalar_cmov(&r, &a, 0);
 +    CHECK(memcmp(&r, &max, sizeof(r)) == 0);
 +
 +    r = zero; a = max;
 +    secp256k1_scalar_cmov(&r, &a, 1);
 +    CHECK(memcmp(&r, &max, sizeof(r)) == 0);
 +
 +    a = zero;
 +    secp256k1_scalar_cmov(&r, &a, 1);
 +    CHECK(memcmp(&r, &zero, sizeof(r)) == 0);
 +
 +    a = one;
 +    secp256k1_scalar_cmov(&r, &a, 1);
 +    CHECK(memcmp(&r, &one, sizeof(r)) == 0);
 +
 +    r = one; a = zero;
 +    secp256k1_scalar_cmov(&r, &a, 0);
 +    CHECK(memcmp(&r, &one, sizeof(r)) == 0);
 +}
 +
 +void ge_storage_cmov_test(void) {
 +    static const secp256k1_ge_storage zero = SECP256K1_GE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
 +    static const secp256k1_ge_storage one = SECP256K1_GE_STORAGE_CONST(0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1);
 +    static const secp256k1_ge_storage max = SECP256K1_GE_STORAGE_CONST(
 +        0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL,
 +        0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL,
 +        0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL,
 +        0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL
 +    );
 +    secp256k1_ge_storage r = max;
 +    secp256k1_ge_storage a = zero;
 +
 +    secp256k1_ge_storage_cmov(&r, &a, 0);
 +    CHECK(memcmp(&r, &max, sizeof(r)) == 0);
 +
 +    r = zero; a = max;
 +    secp256k1_ge_storage_cmov(&r, &a, 1);
 +    CHECK(memcmp(&r, &max, sizeof(r)) == 0);
 +
 +    a = zero;
 +    secp256k1_ge_storage_cmov(&r, &a, 1);
 +    CHECK(memcmp(&r, &zero, sizeof(r)) == 0);
 +
 +    a = one;
 +    secp256k1_ge_storage_cmov(&r, &a, 1);
 +    CHECK(memcmp(&r, &one, sizeof(r)) == 0);
 +
 +    r = one; a = zero;
 +    secp256k1_ge_storage_cmov(&r, &a, 0);
 +    CHECK(memcmp(&r, &one, sizeof(r)) == 0);
 +}
 +
 +void run_cmov_tests(void) {
 +    int_cmov_test();
 +    fe_cmov_test();
 +    fe_storage_cmov_test();
 +    scalar_cmov_test();
 +    ge_storage_cmov_test();
 +}
 +
  int main(int argc, char **argv) {
      unsigned char seed16[16] = {0};
      unsigned char run32[32] = {0};
      /* EC key edge cases */
      run_eckey_edge_case_test();
  
 +    /* EC key arithmetic test */
 +    run_eckey_negate_test();
 +
  #ifdef ENABLE_MODULE_ECDH
      /* ecdh tests */
      run_ecdh_tests();
      /* util tests */
      run_memczero_test();
  
 +    run_cmov_tests();
 +
      secp256k1_rand256(run32);
      printf("random run = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", run32[0], run32[1], run32[2], run32[3], run32[4], run32[5], run32[6], run32[7], run32[8], run32[9], run32[10], run32[11], run32[12], run32[13], run32[14], run32[15]);
  
This page took 0.059071 seconds and 4 git commands to generate.