bool verifyDigest (PublicKey const& publicKey, uint256 const& digest, Slice const& sig, bool mustBeFullyCanonical) { if (publicKeyType(publicKey) != KeyType::secp256k1) LogicError("sign: secp256k1 required for digest signing"); auto const canonicality = ecdsaCanonicality(sig); if (! canonicality) return false; if (mustBeFullyCanonical && (*canonicality != ECDSACanonicality::fullyCanonical)) return false; secp256k1_pubkey pubkey_imp; if(secp256k1_ec_pubkey_parse( secp256k1Context(), &pubkey_imp, reinterpret_cast<unsigned char const*>( publicKey.data()), publicKey.size()) != 1) return false; secp256k1_ecdsa_signature sig_imp; if(secp256k1_ecdsa_signature_parse_der( secp256k1Context(), &sig_imp, reinterpret_cast<unsigned char const*>( sig.data()), sig.size()) != 1) return false; if (*canonicality != ECDSACanonicality::fullyCanonical) { secp256k1_ecdsa_signature sig_norm; if(secp256k1_ecdsa_signature_normalize( secp256k1Context(), &sig_norm, &sig_imp) != 1) return false; return secp256k1_ecdsa_verify( secp256k1Context(), &sig_norm, reinterpret_cast<unsigned char const*>( digest.data()), &pubkey_imp) == 1; } return secp256k1_ecdsa_verify( secp256k1Context(), &sig_imp, reinterpret_cast<unsigned char const*>( digest.data()), &pubkey_imp) == 1; }
SECP256K1_API jint JNICALL Java_org_commercium_NativeSecp256k1_secp256k1_1ecdsa_1verify (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint siglen, jint publen) { secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); const unsigned char* sigdata = { (unsigned char*) (data + 32) }; const unsigned char* pubdata = { (unsigned char*) (data + siglen + 32) }; secp256k1_ecdsa_signature sig; secp256k1_pubkey pubkey; int ret = secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigdata, siglen); if( ret ) { ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen); if( ret ) { ret = secp256k1_ecdsa_verify(ctx, &sig, data, &pubkey); } } (void)classObject; return ret; }
void test_exhaustive_recovery_verify(const secp256k1_context *ctx, const secp256k1_ge *group, int order) { /* This is essentially a copy of test_exhaustive_verify, with recovery added */ int s, r, msg, key; for (s = 1; s < order; s++) { for (r = 1; r < order; r++) { for (msg = 1; msg < order; msg++) { for (key = 1; key < order; key++) { secp256k1_ge nonconst_ge; secp256k1_ecdsa_recoverable_signature rsig; secp256k1_ecdsa_signature sig; secp256k1_pubkey pk; secp256k1_scalar sk_s, msg_s, r_s, s_s; secp256k1_scalar s_times_k_s, msg_plus_r_times_sk_s; int recid = 0; int k, should_verify; unsigned char msg32[32]; secp256k1_scalar_set_int(&s_s, s); secp256k1_scalar_set_int(&r_s, r); secp256k1_scalar_set_int(&msg_s, msg); secp256k1_scalar_set_int(&sk_s, key); secp256k1_scalar_get_b32(msg32, &msg_s); /* Verify by hand */ /* Run through every k value that gives us this r and check that *one* works. * Note there could be none, there could be multiple, ECDSA is weird. */ should_verify = 0; for (k = 0; k < order; k++) { secp256k1_scalar check_x_s; r_from_k(&check_x_s, group, k); if (r_s == check_x_s) { secp256k1_scalar_set_int(&s_times_k_s, k); secp256k1_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s); secp256k1_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s); secp256k1_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s); should_verify |= secp256k1_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s); } } /* nb we have a "high s" rule */ should_verify &= !secp256k1_scalar_is_high(&s_s); /* We would like to try recovering the pubkey and checking that it matches, * but pubkey recovery is impossible in the exhaustive tests (the reason * being that there are 12 nonzero r values, 12 nonzero points, and no * overlap between the sets, so there are no valid signatures). */ /* Verify by converting to a standard signature and calling verify */ secp256k1_ecdsa_recoverable_signature_save(&rsig, &r_s, &s_s, recid); secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig); memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge)); secp256k1_pubkey_save(&pk, &nonconst_ge); CHECK(should_verify == secp256k1_ecdsa_verify(ctx, &sig, msg32, &pk)); } } } } }
bool verify_signature(const ec_point& public_key, hash_digest hash, const endorsement& signature) { init.init(); return 1 == secp256k1_ecdsa_verify(hash.data(), hash.size(), signature.data(), signature.size(), public_key.data(), public_key.size() ); }
JNIEXPORT jint JNICALL Java_org_cryptomailcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify (JNIEnv* env, jclass classObject, jobject byteBufferObject) { unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); int sigLen = *((int*)(data + 32)); int pubLen = *((int*)(data + 32 + 4)); return secp256k1_ecdsa_verify(data, 32, data+32+8, sigLen, data+32+8+sigLen, pubLen); }
jniexport jint jnicall java_org_moorecoin_nativesecp256k1_secp256k1_1ecdsa_1verify (jnienv* env, jclass classobject, jobject bytebufferobject) { unsigned char* data = (unsigned char*) (*env)->getdirectbufferaddress(env, bytebufferobject); int siglen = *((int*)(data + 32)); int publen = *((int*)(data + 32 + 4)); return secp256k1_ecdsa_verify(data, 32, data+32+8, siglen, data+32+8+siglen, publen); }
bool verify_signature(const ec_point& public_key, hash_digest hash, const data_chunk& signature) { std::reverse(hash.begin(), hash.end()); init.init(); return 1 == secp256k1_ecdsa_verify( hash.data(), hash.size(), signature.data(), signature.size(), public_key.data(), public_key.size() ); }
bool verify_signature(const secp256k1_context* context, const secp256k1_pubkey point, const hash_digest& hash, const ec_signature& signature) { // Copy to avoid exposing external types. secp256k1_ecdsa_signature parsed; std::copy(signature.begin(), signature.end(), std::begin(parsed.data)); // secp256k1_ecdsa_verify rejects non-normalized (low-s) signatures, but // bitcoin does not have such a limitation, so we always normalize. secp256k1_ecdsa_signature normal; secp256k1_ecdsa_signature_normalize(context, &normal, &parsed); return secp256k1_ecdsa_verify(context, &normal, hash.data(), &point) == 1; }
void test_exhaustive_verify(const secp256k1_context *ctx, const secp256k1_ge *group, int order) { int s, r, msg, key; for (s = 1; s < order; s++) { for (r = 1; r < order; r++) { for (msg = 1; msg < order; msg++) { for (key = 1; key < order; key++) { secp256k1_ge nonconst_ge; secp256k1_ecdsa_signature sig; secp256k1_pubkey pk; secp256k1_scalar sk_s, msg_s, r_s, s_s; secp256k1_scalar s_times_k_s, msg_plus_r_times_sk_s; int k, should_verify; unsigned char msg32[32]; secp256k1_scalar_set_int(&s_s, s); secp256k1_scalar_set_int(&r_s, r); secp256k1_scalar_set_int(&msg_s, msg); secp256k1_scalar_set_int(&sk_s, key); /* Verify by hand */ /* Run through every k value that gives us this r and check that *one* works. * Note there could be none, there could be multiple, ECDSA is weird. */ should_verify = 0; for (k = 0; k < order; k++) { secp256k1_scalar check_x_s; r_from_k(&check_x_s, group, k); if (r_s == check_x_s) { secp256k1_scalar_set_int(&s_times_k_s, k); secp256k1_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s); secp256k1_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s); secp256k1_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s); should_verify |= secp256k1_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s); } } /* nb we have a "high s" rule */ should_verify &= !secp256k1_scalar_is_high(&s_s); /* Verify by calling verify */ secp256k1_ecdsa_signature_save(&sig, &r_s, &s_s); memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge)); secp256k1_pubkey_save(&pk, &nonconst_ge); secp256k1_scalar_get_b32(msg32, &msg_s); CHECK(should_verify == secp256k1_ecdsa_verify(ctx, &sig, msg32, &pk)); } } } } }
bool ecc_verify_sig(const uint8_t *public_key, int compressed, const uint8_t *hash, unsigned char *sigder, size_t siglen) { assert(secp256k1_ctx); secp256k1_ecdsa_signature sig; secp256k1_pubkey pubkey; if (!secp256k1_ec_pubkey_parse(secp256k1_ctx, &pubkey, public_key, compressed ? 33 : 65)) return false; if (!secp256k1_ecdsa_signature_parse_der(secp256k1_ctx, &sig, sigder, siglen)) return false; return secp256k1_ecdsa_verify(secp256k1_ctx, &sig, hash, &pubkey); }
bool check_signed_hash(secp256k1_context *secpctx, const struct sha256_double *hash, const struct signature *signature, const struct pubkey *key) { int ret; #ifdef USE_SCHNORR ret = secp256k1_schnorr_verify(secpctx, signature->schnorr, hash->sha.u.u8, &key->pubkey); #else ret = secp256k1_ecdsa_verify(secpctx, &signature->sig, hash->sha.u.u8, &key->pubkey); #endif return ret == 1; }
static void benchmark_verify(void* arg) { int i; benchmark_verify_t* data = (benchmark_verify_t*)arg; for (i = 0; i < 20000; i++) { secp256k1_pubkey_t pubkey; secp256k1_ecdsa_signature_t sig; data->sig[data->siglen - 1] ^= (i & 0xFF); data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pubkey, data->pubkey, data->pubkeylen) == 1); CHECK(secp256k1_ecdsa_signature_parse_der(data->ctx, &sig, data->sig, data->siglen) == 1); CHECK(secp256k1_ecdsa_verify(data->ctx, &sig, data->msg, &pubkey) == (i == 0)); data->sig[data->siglen - 1] ^= (i & 0xFF); data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); } }
bool bp_verify(const struct bp_key *key, const void *data, size_t data_len, const void *sig_, size_t sig_len) { if (32 != data_len) { return false; } secp256k1_ecdsa_signature sig; secp256k1_context *ctx = get_secp256k1_context(); if (!ctx) { return false; } if (ecdsa_signature_parse_der_lax(ctx, &sig, sig_, sig_len)) { secp256k1_ecdsa_signature_normalize(ctx, &sig, &sig); return secp256k1_ecdsa_verify(ctx, &sig, data, &key->pubkey); } return false; }
bool verify_signature(data_slice point, const hash_digest& hash, const ec_signature& signature) { // Copy to avoid exposing external types. secp256k1_ecdsa_signature parsed; std::copy(signature.begin(), signature.end(), std::begin(parsed.data)); // secp256k1_ecdsa_verify rejects non-normalized (low-s) signatures, but // bitcoin does not have such a limitation, so we always normalize. secp256k1_ecdsa_signature normal; const auto context = verification.context(); secp256k1_ecdsa_signature_normalize(context, &normal, &parsed); // This uses a data slice and calls secp256k1_ec_pubkey_parse() in place of // parse() so that we can support the der_verify data_chunk optimization. secp256k1_pubkey pubkey; const auto size = point.size(); return secp256k1_ec_pubkey_parse(context, &pubkey, point.data(), size) == 1 && secp256k1_ecdsa_verify(context, &normal, hash.data(), &pubkey) == 1; }
bool Sec256DsaEx::VerifyHashSig(RCSpan hash, const Sec256SignatureEx& sig) { return secp256k1_ecdsa_verify(g_sec256Ctx, &sig.m_sig, hash.data(), &m_pubkey); }
/* Tests several edge cases. */ void test_ecdsa_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 0. */ 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 }; unsigned char pubkey[65]; int pubkeylen = 65; CHECK(!secp256k1_ecdsa_recover_compact(msg32, 32, sig64, pubkey, &pubkeylen, 0, 0)); CHECK(secp256k1_ecdsa_recover_compact(msg32, 32, sig64, pubkey, &pubkeylen, 0, 1)); CHECK(!secp256k1_ecdsa_recover_compact(msg32, 32, sig64, pubkey, &pubkeylen, 0, 2)); CHECK(!secp256k1_ecdsa_recover_compact(msg32, 32, sig64, pubkey, &pubkeylen, 0, 3)); /* 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, }; unsigned char pubkeyb[33]; int pubkeyblen = 33; for (int recid = 0; recid < 4; recid++) { /* (4,4) encoded in DER. */ unsigned char sigbder[8] = {0x30, 0x06, 0x02, 0x01, 0x04, 0x02, 0x01, 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(secp256k1_ecdsa_recover_compact(msg32, 32, sigb64, pubkeyb, &pubkeyblen, 1, recid)); CHECK(secp256k1_ecdsa_verify(msg32, 32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == 1); for (int recid2 = 0; recid2 < 4; recid2++) { unsigned char pubkey2b[33]; int pubkey2blen = 33; CHECK(secp256k1_ecdsa_recover_compact(msg32, 32, sigb64, pubkey2b, &pubkey2blen, 1, recid2)); /* Verifying with (order + r,4) should always fail. */ CHECK(secp256k1_ecdsa_verify(msg32, 32, sigbderlong, sizeof(sigbderlong), pubkey2b, pubkey2blen) != 1); } /* Damage signature. */ sigbder[7]++; CHECK(secp256k1_ecdsa_verify(msg32, 32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == 0); } /* Test the case where ECDSA recomputes a point that is infinity. */ { secp256k1_ecdsa_sig_t sig; secp256k1_scalar_set_int(&sig.s, 1); secp256k1_scalar_negate(&sig.s, &sig.s); secp256k1_scalar_inverse(&sig.s, &sig.s); secp256k1_scalar_set_int(&sig.r, 1); secp256k1_gej_t keyj; secp256k1_ecmult_gen(&keyj, &sig.r); secp256k1_ge_t key; secp256k1_ge_set_gej(&key, &keyj); secp256k1_scalar_t msg = sig.s; CHECK(secp256k1_ecdsa_sig_verify(&sig, &key, &msg) == 0); } /* 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, }; unsigned char pubkeyc[65]; int pubkeyclen = 65; CHECK(secp256k1_ecdsa_recover_compact(msg32, 32, sigc64, pubkeyc, &pubkeyclen, 0, 0) == 1); CHECK(secp256k1_ecdsa_verify(msg32, 32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 1); sigcder[4] = 0; sigc64[31] = 0; CHECK(secp256k1_ecdsa_recover_compact(msg32, 32, sigc64, pubkeyb, &pubkeyblen, 1, 0) == 0); CHECK(secp256k1_ecdsa_verify(msg32, 32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 0); sigcder[4] = 1; sigcder[7] = 0; sigc64[31] = 1; sigc64[63] = 0; CHECK(secp256k1_ecdsa_recover_compact(msg32, 32, sigc64, pubkeyb, &pubkeyblen, 1, 0) == 0); CHECK(secp256k1_ecdsa_verify(msg32, 32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 0); } }
void test_ecdsa_end_to_end(void) { unsigned char privkey[32]; unsigned char message[32]; /* Generate a random key and message. */ { secp256k1_scalar_t msg, key; random_scalar_order_test(&msg); random_scalar_order_test(&key); secp256k1_scalar_get_b32(privkey, &key); secp256k1_scalar_get_b32(message, &msg); } /* Construct and verify corresponding public key. */ CHECK(secp256k1_ec_seckey_verify(privkey) == 1); unsigned char pubkey[65]; int pubkeylen = 65; CHECK(secp256k1_ec_pubkey_create(pubkey, &pubkeylen, privkey, secp256k1_rand32() % 2) == 1); CHECK(secp256k1_ec_pubkey_verify(pubkey, pubkeylen)); /* Verify private key import and export. */ unsigned char seckey[300]; int seckeylen = 300; CHECK(secp256k1_ec_privkey_export(privkey, seckey, &seckeylen, secp256k1_rand32() % 2) == 1); unsigned char privkey2[32]; CHECK(secp256k1_ec_privkey_import(privkey2, seckey, seckeylen) == 1); CHECK(memcmp(privkey, privkey2, 32) == 0); /* Optionally tweak the keys using addition. */ if (secp256k1_rand32() % 3 == 0) { unsigned char rnd[32]; secp256k1_rand256_test(rnd); int ret1 = secp256k1_ec_privkey_tweak_add(privkey, rnd); int ret2 = secp256k1_ec_pubkey_tweak_add(pubkey, pubkeylen, rnd); CHECK(ret1 == ret2); if (ret1 == 0) return; unsigned char pubkey2[65]; int pubkeylen2 = 65; CHECK(secp256k1_ec_pubkey_create(pubkey2, &pubkeylen2, privkey, pubkeylen == 33) == 1); CHECK(memcmp(pubkey, pubkey2, pubkeylen) == 0); } /* Optionally tweak the keys using multiplication. */ if (secp256k1_rand32() % 3 == 0) { unsigned char rnd[32]; secp256k1_rand256_test(rnd); int ret1 = secp256k1_ec_privkey_tweak_mul(privkey, rnd); int ret2 = secp256k1_ec_pubkey_tweak_mul(pubkey, pubkeylen, rnd); CHECK(ret1 == ret2); if (ret1 == 0) return; unsigned char pubkey2[65]; int pubkeylen2 = 65; CHECK(secp256k1_ec_pubkey_create(pubkey2, &pubkeylen2, privkey, pubkeylen == 33) == 1); CHECK(memcmp(pubkey, pubkey2, pubkeylen) == 0); } /* Sign. */ unsigned char signature[72]; int signaturelen = 72; while(1) { unsigned char rnd[32]; secp256k1_rand256_test(rnd); if (secp256k1_ecdsa_sign(message, 32, signature, &signaturelen, privkey, rnd) == 1) { break; } } /* Verify. */ CHECK(secp256k1_ecdsa_verify(message, 32, signature, signaturelen, pubkey, pubkeylen) == 1); /* Destroy signature and verify again. */ signature[signaturelen - 1 - secp256k1_rand32() % 20] += 1 + (secp256k1_rand32() % 255); CHECK(secp256k1_ecdsa_verify(message, 32, signature, signaturelen, pubkey, pubkeylen) != 1); /* Compact sign. */ unsigned char csignature[64]; int recid = 0; while(1) { unsigned char rnd[32]; secp256k1_rand256_test(rnd); if (secp256k1_ecdsa_sign_compact(message, 32, csignature, privkey, rnd, &recid) == 1) { break; } } /* Recover. */ unsigned char recpubkey[65]; int recpubkeylen = 0; CHECK(secp256k1_ecdsa_recover_compact(message, 32, csignature, recpubkey, &recpubkeylen, pubkeylen == 33, recid) == 1); CHECK(recpubkeylen == pubkeylen); CHECK(memcmp(pubkey, recpubkey, pubkeylen) == 0); /* Destroy signature and verify again. */ csignature[secp256k1_rand32() % 64] += 1 + (secp256k1_rand32() % 255); CHECK(secp256k1_ecdsa_recover_compact(message, 32, csignature, recpubkey, &recpubkeylen, pubkeylen == 33, recid) != 1 || memcmp(pubkey, recpubkey, pubkeylen) != 0); CHECK(recpubkeylen == pubkeylen); }