text: /**********************************************************************
   * Copyright (c) 2013-2015 Pieter Wuille                              *
   * Distributed under the MIT software license, see the accompanying   *
   * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
   **********************************************************************/
  
  #ifndef SECP256K1_MODULE_RECOVERY_TESTS_H
  #define SECP256K1_MODULE_RECOVERY_TESTS_H
  
  static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {
      (void) msg32;
      (void) key32;
      (void) algo16;
      (void) data;
  
      /* On the first run, return 0 to force a second run */
      if (counter == 0) {
          memset(nonce32, 0, 32);
          return 1;
      }
      /* On the second run, return an overflow to force a third run */
      if (counter == 1) {
          memset(nonce32, 0xff, 32);
          return 1;
      }
      /* On the next run, return a valid nonce, but flip a coin as to whether or not to fail signing. */
      memset(nonce32, 1, 32);
      return rustsecp256k1zkp_v0_2_0_testrand_bits(1);
  }
  
  void test_ecdsa_recovery_api(void) {
      /* Setup contexts that just count errors */
      rustsecp256k1zkp_v0_2_0_context *none = rustsecp256k1zkp_v0_2_0_context_create(SECP256K1_CONTEXT_NONE);
      rustsecp256k1zkp_v0_2_0_context *sign = rustsecp256k1zkp_v0_2_0_context_create(SECP256K1_CONTEXT_SIGN);
      rustsecp256k1zkp_v0_2_0_context *vrfy = rustsecp256k1zkp_v0_2_0_context_create(SECP256K1_CONTEXT_VERIFY);
      rustsecp256k1zkp_v0_2_0_context *both = rustsecp256k1zkp_v0_2_0_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
      rustsecp256k1zkp_v0_2_0_pubkey pubkey;
      rustsecp256k1zkp_v0_2_0_pubkey recpubkey;
      rustsecp256k1zkp_v0_2_0_ecdsa_signature normal_sig;
      rustsecp256k1zkp_v0_2_0_ecdsa_recoverable_signature recsig;
      unsigned char privkey[32] = { 1 };
      unsigned char message[32] = { 2 };
      int32_t ecount = 0;
      int recid = 0;
      unsigned char sig[74];
      unsigned char zero_privkey[32] = { 0 };
      unsigned char over_privkey[32] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
                                         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
                                         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
                                         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
  
      rustsecp256k1zkp_v0_2_0_context_set_error_callback(none, counting_illegal_callback_fn, &ecount);
      rustsecp256k1zkp_v0_2_0_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount);
      rustsecp256k1zkp_v0_2_0_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount);
      rustsecp256k1zkp_v0_2_0_context_set_error_callback(both, counting_illegal_callback_fn, &ecount);
      rustsecp256k1zkp_v0_2_0_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
      rustsecp256k1zkp_v0_2_0_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount);
      rustsecp256k1zkp_v0_2_0_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);
      rustsecp256k1zkp_v0_2_0_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount);
  
      /* Construct and verify corresponding public key. */
      CHECK(rustsecp256k1zkp_v0_2_0_ec_seckey_verify(ctx, privkey) == 1);
      CHECK(rustsecp256k1zkp_v0_2_0_ec_pubkey_create(ctx, &pubkey, privkey) == 1);
  
      /* Check bad contexts and NULLs for signing */
      ecount = 0;
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_sign_recoverable(none, &recsig, message, privkey, NULL, NULL) == 0);
      CHECK(ecount == 1);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_sign_recoverable(sign, &recsig, message, privkey, NULL, NULL) == 1);
      CHECK(ecount == 1);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_sign_recoverable(vrfy, &recsig, message, privkey, NULL, NULL) == 0);
      CHECK(ecount == 2);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1);
      CHECK(ecount == 2);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_sign_recoverable(both, NULL, message, privkey, NULL, NULL) == 0);
      CHECK(ecount == 3);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_sign_recoverable(both, &recsig, NULL, privkey, NULL, NULL) == 0);
      CHECK(ecount == 4);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_sign_recoverable(both, &recsig, message, NULL, NULL, NULL) == 0);
      CHECK(ecount == 5);
      /* This will fail or succeed randomly, and in either case will not ARG_CHECK failure */
      rustsecp256k1zkp_v0_2_0_ecdsa_sign_recoverable(both, &recsig, message, privkey, recovery_test_nonce_function, NULL);
      CHECK(ecount == 5);
      /* These will all fail, but not in ARG_CHECK way */
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_sign_recoverable(both, &recsig, message, zero_privkey, NULL, NULL) == 0);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_sign_recoverable(both, &recsig, message, over_privkey, NULL, NULL) == 0);
      /* This one will succeed. */
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1);
      CHECK(ecount == 5);
  
      /* Check signing with a goofy nonce function */
  
      /* Check bad contexts and NULLs for recovery */
      ecount = 0;
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recover(none, &recpubkey, &recsig, message) == 0);
      CHECK(ecount == 1);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recover(sign, &recpubkey, &recsig, message) == 0);
      CHECK(ecount == 2);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recover(vrfy, &recpubkey, &recsig, message) == 1);
      CHECK(ecount == 2);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recover(both, &recpubkey, &recsig, message) == 1);
      CHECK(ecount == 2);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recover(both, NULL, &recsig, message) == 0);
      CHECK(ecount == 3);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recover(both, &recpubkey, NULL, message) == 0);
      CHECK(ecount == 4);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recover(both, &recpubkey, &recsig, NULL) == 0);
      CHECK(ecount == 5);
  
      /* Check NULLs for conversion */
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_sign(both, &normal_sig, message, privkey, NULL, NULL) == 1);
      ecount = 0;
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recoverable_signature_convert(both, NULL, &recsig) == 0);
      CHECK(ecount == 1);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recoverable_signature_convert(both, &normal_sig, NULL) == 0);
      CHECK(ecount == 2);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recoverable_signature_convert(both, &normal_sig, &recsig) == 1);
  
      /* Check NULLs for de/serialization */
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1);
      ecount = 0;
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recoverable_signature_serialize_compact(both, NULL, &recid, &recsig) == 0);
      CHECK(ecount == 1);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recoverable_signature_serialize_compact(both, sig, NULL, &recsig) == 0);
      CHECK(ecount == 2);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, NULL) == 0);
      CHECK(ecount == 3);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, &recsig) == 1);
  
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recoverable_signature_parse_compact(both, NULL, sig, recid) == 0);
      CHECK(ecount == 4);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recoverable_signature_parse_compact(both, &recsig, NULL, recid) == 0);
      CHECK(ecount == 5);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, -1) == 0);
      CHECK(ecount == 6);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, 5) == 0);
      CHECK(ecount == 7);
      /* overflow in signature will fail but not affect ecount */
      memcpy(sig, over_privkey, 32);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, recid) == 0);
      CHECK(ecount == 7);
  
      /* cleanup */
      rustsecp256k1zkp_v0_2_0_context_destroy(none);
      rustsecp256k1zkp_v0_2_0_context_destroy(sign);
      rustsecp256k1zkp_v0_2_0_context_destroy(vrfy);
      rustsecp256k1zkp_v0_2_0_context_destroy(both);
  }
  
  void test_ecdsa_recovery_end_to_end(void) {
      unsigned char extra[32] = {0x00};
      unsigned char privkey[32];
      unsigned char message[32];
      rustsecp256k1zkp_v0_2_0_ecdsa_signature signature[5];
      rustsecp256k1zkp_v0_2_0_ecdsa_recoverable_signature rsignature[5];
      unsigned char sig[74];
      rustsecp256k1zkp_v0_2_0_pubkey pubkey;
      rustsecp256k1zkp_v0_2_0_pubkey recpubkey;
      int recid = 0;
  
      /* Generate a random key and message. */
      {
          rustsecp256k1zkp_v0_2_0_scalar msg, key;
          random_scalar_order_test(&msg);
          random_scalar_order_test(&key);
          rustsecp256k1zkp_v0_2_0_scalar_get_b32(privkey, &key);
          rustsecp256k1zkp_v0_2_0_scalar_get_b32(message, &msg);
      }
  
      /* Construct and verify corresponding public key. */
      CHECK(rustsecp256k1zkp_v0_2_0_ec_seckey_verify(ctx, privkey) == 1);
      CHECK(rustsecp256k1zkp_v0_2_0_ec_pubkey_create(ctx, &pubkey, privkey) == 1);
  
      /* Serialize/parse compact and verify/recover. */
      extra[0] = 0;
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_sign_recoverable(ctx, &rsignature[0], message, privkey, NULL, NULL) == 1);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_sign(ctx, &signature[0], message, privkey, NULL, NULL) == 1);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_sign_recoverable(ctx, &rsignature[4], message, privkey, NULL, NULL) == 1);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_sign_recoverable(ctx, &rsignature[1], message, privkey, NULL, extra) == 1);
      extra[31] = 1;
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_sign_recoverable(ctx, &rsignature[2], message, privkey, NULL, extra) == 1);
      extra[31] = 0;
      extra[0] = 1;
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_sign_recoverable(ctx, &rsignature[3], message, privkey, NULL, extra) == 1);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1);
      CHECK(rustsecp256k1zkp_v0_2_0_memcmp_var(&signature[4], &signature[0], 64) == 0);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1);
      memset(&rsignature[4], 0, sizeof(rsignature[4]));
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1);
      /* Parse compact (with recovery id) and recover. */
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 1);
      CHECK(rustsecp256k1zkp_v0_2_0_memcmp_var(&pubkey, &recpubkey, sizeof(pubkey)) == 0);
      /* Serialize/destroy/parse signature and verify again. */
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1);
      sig[rustsecp256k1zkp_v0_2_0_testrand_bits(6)] += 1 + rustsecp256k1zkp_v0_2_0_testrand_int(255);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1);
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 0);
      /* Recover again */
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 0 ||
            rustsecp256k1zkp_v0_2_0_memcmp_var(&pubkey, &recpubkey, sizeof(pubkey)) != 0);
  }
  
  /* Tests several edge cases. */
  void test_ecdsa_recovery_edge_cases(void) {
      const unsigned char msg32[32] = {
          'T', 'h', 'i', 's', ' ', 'i', 's', ' ',
          'a', ' ', 'v', 'e', 'r', 'y', ' ', 's',
          'e', 'c', 'r', 'e', 't', ' ', 'm', 'e',
          's', 's', 'a', 'g', 'e', '.', '.', '.'
      };
      const unsigned char sig64[64] = {
          /* Generated by signing the above message with nonce 'This is the nonce we will use...'
           * and secret key 0 (which is not valid), resulting in recid 1. */
          0x67, 0xCB, 0x28, 0x5F, 0x9C, 0xD1, 0x94, 0xE8,
          0x40, 0xD6, 0x29, 0x39, 0x7A, 0xF5, 0x56, 0x96,
          0x62, 0xFD, 0xE4, 0x46, 0x49, 0x99, 0x59, 0x63,
          0x17, 0x9A, 0x7D, 0xD1, 0x7B, 0xD2, 0x35, 0x32,
          0x4B, 0x1B, 0x7D, 0xF3, 0x4C, 0xE1, 0xF6, 0x8E,
          0x69, 0x4F, 0xF6, 0xF1, 0x1A, 0xC7, 0x51, 0xDD,
          0x7D, 0xD7, 0x3E, 0x38, 0x7E, 0xE4, 0xFC, 0x86,
          0x6E, 0x1B, 0xE8, 0xEC, 0xC7, 0xDD, 0x95, 0x57
      };
      rustsecp256k1zkp_v0_2_0_pubkey pubkey;
      /* signature (r,s) = (4,4), which can be recovered with all 4 recids. */
      const unsigned char sigb64[64] = {
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
      };
      rustsecp256k1zkp_v0_2_0_pubkey pubkeyb;
      rustsecp256k1zkp_v0_2_0_ecdsa_recoverable_signature rsig;
      rustsecp256k1zkp_v0_2_0_ecdsa_signature sig;
      int recid;
  
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 0));
      CHECK(!rustsecp256k1zkp_v0_2_0_ecdsa_recover(ctx, &pubkey, &rsig, msg32));
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 1));
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recover(ctx, &pubkey, &rsig, msg32));
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 2));
      CHECK(!rustsecp256k1zkp_v0_2_0_ecdsa_recover(ctx, &pubkey, &rsig, msg32));
      CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 3));
      CHECK(!rustsecp256k1zkp_v0_2_0_ecdsa_recover(ctx, &pubkey, &rsig, msg32));
  
      for (recid = 0; recid < 4; recid++) {
          int i;
          int recid2;
          /* (4,4) encoded in DER. */
          unsigned char sigbder[8] = {0x30, 0x06, 0x02, 0x01, 0x04, 0x02, 0x01, 0x04};
          unsigned char sigcder_zr[7] = {0x30, 0x05, 0x02, 0x00, 0x02, 0x01, 0x01};
          unsigned char sigcder_zs[7] = {0x30, 0x05, 0x02, 0x01, 0x01, 0x02, 0x00};
          unsigned char sigbderalt1[39] = {
              0x30, 0x25, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x04,
          };
          unsigned char sigbderalt2[39] = {
              0x30, 0x25, 0x02, 0x01, 0x04, 0x02, 0x20, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
          };
          unsigned char sigbderalt3[40] = {
              0x30, 0x26, 0x02, 0x21, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x04,
          };
          unsigned char sigbderalt4[40] = {
              0x30, 0x26, 0x02, 0x01, 0x04, 0x02, 0x21, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
          };
          /* (order + r,4) encoded in DER. */
          unsigned char sigbderlong[40] = {
              0x30, 0x26, 0x02, 0x21, 0x00, 0xFF, 0xFF, 0xFF,
              0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
              0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC,
              0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E,
              0x8C, 0xD0, 0x36, 0x41, 0x45, 0x02, 0x01, 0x04
          };
          CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid) == 1);
          CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 1);
          CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1);
          CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 1);
          for (recid2 = 0; recid2 < 4; recid2++) {
              rustsecp256k1zkp_v0_2_0_pubkey pubkey2b;
              CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid2) == 1);
              CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recover(ctx, &pubkey2b, &rsig, msg32) == 1);
              /* Verifying with (order + r,4) should always fail. */
              CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_signature_parse_der(ctx, &sig, sigbderlong, sizeof(sigbderlong)) == 1);
              CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0);
          }
          /* DER parsing tests. */
          /* Zero length r/s. */
          CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_signature_parse_der(ctx, &sig, sigcder_zr, sizeof(sigcder_zr)) == 0);
          CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_signature_parse_der(ctx, &sig, sigcder_zs, sizeof(sigcder_zs)) == 0);
          /* Leading zeros. */
          CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_signature_parse_der(ctx, &sig, sigbderalt1, sizeof(sigbderalt1)) == 0);
          CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_signature_parse_der(ctx, &sig, sigbderalt2, sizeof(sigbderalt2)) == 0);
          CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 0);
          CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 0);
          sigbderalt3[4] = 1;
          CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 1);
          CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0);
          sigbderalt4[7] = 1;
          CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 1);
          CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0);
          /* Damage signature. */
          sigbder[7]++;
          CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1);
          CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0);
          sigbder[7]--;
          CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_signature_parse_der(ctx, &sig, sigbder, 6) == 0);
          CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder) - 1) == 0);
          for(i = 0; i < 8; i++) {
              int c;
              unsigned char orig = sigbder[i];
              /*Try every single-byte change.*/
              for (c = 0; c < 256; c++) {
                  if (c == orig ) {
                      continue;
                  }
                  sigbder[i] = c;
                  CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 0 || rustsecp256k1zkp_v0_2_0_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0);
              }
              sigbder[i] = orig;
          }
      }
  
      /* Test r/s equal to zero */
      {
          /* (1,1) encoded in DER. */
          unsigned char sigcder[8] = {0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01};
          unsigned char sigc64[64] = {
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
          };
          rustsecp256k1zkp_v0_2_0_pubkey pubkeyc;
          CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1);
          CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recover(ctx, &pubkeyc, &rsig, msg32) == 1);
          CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1);
          CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 1);
          sigcder[4] = 0;
          sigc64[31] = 0;
          CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1);
          CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 0);
          CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1);
          CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 0);
          sigcder[4] = 1;
          sigcder[7] = 0;
          sigc64[31] = 1;
          sigc64[63] = 0;
          CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1);
          CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 0);
          CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1);
          CHECK(rustsecp256k1zkp_v0_2_0_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 0);
      }
  }
  
  void run_recovery_tests(void) {
      int i;
      for (i = 0; i < count; i++) {
          test_ecdsa_recovery_api();
      }
      for (i = 0; i < 64*count; i++) {
          test_ecdsa_recovery_end_to_end();
      }
      test_ecdsa_recovery_edge_cases();
  }
  
  #endif /* SECP256K1_MODULE_RECOVERY_TESTS_H */
  