Merge bitcoin/bitcoin#26691: Update secp256k1 subtree to libsecp256k1 version 0.2.0

2022917223 Add secp256k1_selftest call (Pieter Wuille)
3bfca788b0 Remove explicit enabling of default modules (Pieter Wuille)
4462cb0498 Adapt to libsecp256k1 API changes (Pieter Wuille)
9d47e7b71b Squashed 'src/secp256k1/' changes from 44c2452fd3..21ffe4b22a (Pieter Wuille)

Pull request description:

  Now that libsecp256k1 has a release (https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2022-December/021271.html), update the subtree to match it.

  The changes themselves are not very impactful for Bitcoin Core, but include:
  * It's no longer needed to specify whether contexts are for signing or verification or both (all contexts support everything), so make use of that in this PR.
  * Verification operations can use the static context now, removing the need for some infrastructure in pubkey.cpp to make sure a context exists.
  * Most modules are now enabled by default, so we can drop explicit enabling for them.
  * CI improvements (in particular, MSVC and more recent MacOS)
  * Introduction of an internal int128 type, which has no effect for GCC/Clang builds, but enables 128-bit multiplication in MSVC, giving a ~20% speedup there (but still slower than GCC/Clang).
  * Release process changes (process documentation, changelog, ...).

ACKs for top commit:
  Sjors:
    ACK 2022917223, but 4462cb0498 could use more eyes on it.
  achow101:
    ACK 2022917223
  jonasnick:
    utACK 2022917223

Tree-SHA512: 8a9fe28852abe74abd6f96fef16a94d5a427b1d99bff4caab1699014d24698aab9b966a5364a46ed1001c07a7c1d825154ed4e6557c7decce952b77330a8616b
This commit is contained in:
fanquake 2023-01-13 09:35:28 +00:00
commit 07c54de550
No known key found for this signature in database
GPG Key ID: 2EEB9F5CC09526C1
91 changed files with 2086 additions and 1199 deletions

View File

@ -14,7 +14,7 @@
</ItemGroup>
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>ENABLE_MODULE_ECDH;ENABLE_MODULE_RECOVERY;ENABLE_MODULE_EXTRAKEYS;ENABLE_MODULE_SCHNORRSIG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>ENABLE_MODULE_RECOVERY;ENABLE_MODULE_EXTRAKEYS;ENABLE_MODULE_SCHNORRSIG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\src\secp256k1;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4146;4244;4267;4334</DisableSpecificWarnings>
</ClCompile>

View File

@ -2012,7 +2012,7 @@ LIBS_TEMP="$LIBS"
unset LIBS
LIBS="$LIBS_TEMP"
ac_configure_args="${ac_configure_args} --disable-shared --with-pic --enable-benchmark=no --enable-module-recovery --enable-module-schnorrsig"
ac_configure_args="${ac_configure_args} --disable-shared --with-pic --enable-benchmark=no --enable-module-recovery --disable-module-ecdh"
AC_CONFIG_SUBDIRS([src/secp256k1])
AC_OUTPUT

View File

@ -18,7 +18,6 @@
// (https://github.com/bitcoin/bitcoin/issues/7883#issuecomment-224807484)
static void CCoinsCaching(benchmark::Bench& bench)
{
const ECCVerifyHandle verify_handle;
ECC_Start();
FillableSigningProvider keystore;

View File

@ -25,7 +25,6 @@ static void CCheckQueueSpeedPrevectorJob(benchmark::Bench& bench)
// We shouldn't ever be running with the checkqueue on a single core machine.
if (GetNumCores() <= 1) return;
const ECCVerifyHandle verify_handle;
ECC_Start();
struct PrevectorJob {

View File

@ -13,7 +13,6 @@
static void ExpandDescriptor(benchmark::Bench& bench)
{
const ECCVerifyHandle verify_handle;
ECC_Start();
const auto desc_str = "sh(wsh(multi(16,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232)))";

View File

@ -18,7 +18,6 @@
// modified to measure performance of other types of scripts.
static void VerifyScriptBench(benchmark::Bench& bench)
{
const ECCVerifyHandle verify_handle;
ECC_Start();
const uint32_t flags{SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH};

View File

@ -681,8 +681,6 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
class Secp256k1Init
{
ECCVerifyHandle globalVerifyHandle;
public:
Secp256k1Init() {
ECC_Start();

View File

@ -130,7 +130,6 @@ MAIN_FUNCTION
return EXIT_FAILURE;
}
ECCVerifyHandle globalVerifyHandle;
ECC_Start();
if (!wallet::WalletTool::ExecuteWalletToolFunc(args, command->command)) {
return EXIT_FAILURE;

View File

@ -21,12 +21,10 @@ Context::Context()
LogPrintf("Using the '%s' SHA256 implementation\n", sha256_algo);
RandomInit();
ECC_Start();
ecc_verify_handle.reset(new ECCVerifyHandle());
}
Context::~Context()
{
ecc_verify_handle.reset();
ECC_Stop();
}

View File

@ -7,8 +7,6 @@
#include <memory>
class ECCVerifyHandle;
namespace kernel {
//! Context struct holding the kernel library's logically global state, and
//! passed to external libbitcoin_kernel functions which need access to this
@ -18,8 +16,6 @@ namespace kernel {
//! State stored directly in this struct should be simple. More complex state
//! should be stored to std::unique_ptr members pointing to opaque types.
struct Context {
std::unique_ptr<ECCVerifyHandle> ecc_verify_handle;
//! Declare default constructor and destructor that are not inline, so code
//! instantiating the kernel::Context struct doesn't need to #include class
//! definitions for all the unique_ptr members.

View File

@ -233,7 +233,7 @@ bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig, bool gr
secp256k1_pubkey pk;
ret = secp256k1_ec_pubkey_create(secp256k1_context_sign, &pk, begin());
assert(ret);
ret = secp256k1_ecdsa_verify(GetVerifyContext(), &sig, hash.begin(), &pk);
ret = secp256k1_ecdsa_verify(secp256k1_context_static, &sig, hash.begin(), &pk);
assert(ret);
return true;
}
@ -268,9 +268,9 @@ bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig)
secp256k1_pubkey epk, rpk;
ret = secp256k1_ec_pubkey_create(secp256k1_context_sign, &epk, begin());
assert(ret);
ret = secp256k1_ecdsa_recover(GetVerifyContext(), &rpk, &rsig, hash.begin());
ret = secp256k1_ecdsa_recover(secp256k1_context_static, &rpk, &rsig, hash.begin());
assert(ret);
ret = secp256k1_ec_pubkey_cmp(GetVerifyContext(), &epk, &rpk);
ret = secp256k1_ec_pubkey_cmp(secp256k1_context_static, &epk, &rpk);
assert(ret == 0);
return true;
}
@ -286,14 +286,14 @@ bool CKey::SignSchnorr(const uint256& hash, Span<unsigned char> sig, const uint2
unsigned char pubkey_bytes[32];
if (!secp256k1_xonly_pubkey_serialize(secp256k1_context_sign, pubkey_bytes, &pubkey)) return false;
uint256 tweak = XOnlyPubKey(pubkey_bytes).ComputeTapTweakHash(merkle_root->IsNull() ? nullptr : merkle_root);
if (!secp256k1_keypair_xonly_tweak_add(GetVerifyContext(), &keypair, tweak.data())) return false;
if (!secp256k1_keypair_xonly_tweak_add(secp256k1_context_static, &keypair, tweak.data())) return false;
}
bool ret = secp256k1_schnorrsig_sign32(secp256k1_context_sign, sig.data(), hash.data(), &keypair, aux.data());
if (ret) {
// Additional verification step to prevent using a potentially corrupted signature
secp256k1_xonly_pubkey pubkey_verify;
ret = secp256k1_keypair_xonly_pub(GetVerifyContext(), &pubkey_verify, nullptr, &keypair);
ret &= secp256k1_schnorrsig_verify(GetVerifyContext(), sig.data(), hash.begin(), 32, &pubkey_verify);
ret = secp256k1_keypair_xonly_pub(secp256k1_context_static, &pubkey_verify, nullptr, &keypair);
ret &= secp256k1_schnorrsig_verify(secp256k1_context_static, sig.data(), hash.begin(), 32, &pubkey_verify);
}
if (!ret) memory_cleanse(sig.data(), sig.size());
memory_cleanse(&keypair, sizeof(keypair));
@ -392,7 +392,7 @@ bool ECC_InitSanityCheck() {
void ECC_Start() {
assert(secp256k1_context_sign == nullptr);
secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
assert(ctx != nullptr);
{

View File

@ -16,10 +16,16 @@
#include <algorithm>
#include <cassert>
namespace
namespace {
struct Secp256k1SelfTester
{
/* Global secp256k1_context object used for verification. */
secp256k1_context* secp256k1_context_verify = nullptr;
Secp256k1SelfTester() {
/* Run libsecp256k1 self-test before using the secp256k1_context_static. */
secp256k1_selftest();
}
} SECP256K1_SELFTESTER;
} // namespace
/** This function is taken from the libsecp256k1 distribution and implements
@ -32,7 +38,7 @@ secp256k1_context* secp256k1_context_verify = nullptr;
* strict DER before being passed to this module, and we know it supports all
* violations present in the blockchain before that point.
*/
int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) {
int ecdsa_signature_parse_der_lax(secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) {
size_t rpos, rlen, spos, slen;
size_t pos = 0;
size_t lenbyte;
@ -40,7 +46,7 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_
int overflow = 0;
/* Hack to initialize sig with a correctly-parsed but invalid signature. */
secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig);
secp256k1_ecdsa_signature_parse_compact(secp256k1_context_static, sig, tmpsig);
/* Sequence tag byte */
if (pos == inputlen || input[pos] != 0x30) {
@ -163,13 +169,13 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_
}
if (!overflow) {
overflow = !secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig);
overflow = !secp256k1_ecdsa_signature_parse_compact(secp256k1_context_static, sig, tmpsig);
}
if (overflow) {
/* Overwrite the result again with a correctly-parsed but invalid
signature if parsing failed. */
memset(tmpsig, 0, 64);
secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig);
secp256k1_ecdsa_signature_parse_compact(secp256k1_context_static, sig, tmpsig);
}
return 1;
}
@ -200,15 +206,15 @@ std::vector<CKeyID> XOnlyPubKey::GetKeyIDs() const
bool XOnlyPubKey::IsFullyValid() const
{
secp256k1_xonly_pubkey pubkey;
return secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &pubkey, m_keydata.data());
return secp256k1_xonly_pubkey_parse(secp256k1_context_static, &pubkey, m_keydata.data());
}
bool XOnlyPubKey::VerifySchnorr(const uint256& msg, Span<const unsigned char> sigbytes) const
{
assert(sigbytes.size() == 64);
secp256k1_xonly_pubkey pubkey;
if (!secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &pubkey, m_keydata.data())) return false;
return secp256k1_schnorrsig_verify(secp256k1_context_verify, sigbytes.data(), msg.begin(), 32, &pubkey);
if (!secp256k1_xonly_pubkey_parse(secp256k1_context_static, &pubkey, m_keydata.data())) return false;
return secp256k1_schnorrsig_verify(secp256k1_context_static, sigbytes.data(), msg.begin(), 32, &pubkey);
}
static const HashWriter HASHER_TAPTWEAK{TaggedHash("TapTweak")};
@ -227,23 +233,23 @@ uint256 XOnlyPubKey::ComputeTapTweakHash(const uint256* merkle_root) const
bool XOnlyPubKey::CheckTapTweak(const XOnlyPubKey& internal, const uint256& merkle_root, bool parity) const
{
secp256k1_xonly_pubkey internal_key;
if (!secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &internal_key, internal.data())) return false;
if (!secp256k1_xonly_pubkey_parse(secp256k1_context_static, &internal_key, internal.data())) return false;
uint256 tweak = internal.ComputeTapTweakHash(&merkle_root);
return secp256k1_xonly_pubkey_tweak_add_check(secp256k1_context_verify, m_keydata.begin(), parity, &internal_key, tweak.begin());
return secp256k1_xonly_pubkey_tweak_add_check(secp256k1_context_static, m_keydata.begin(), parity, &internal_key, tweak.begin());
}
std::optional<std::pair<XOnlyPubKey, bool>> XOnlyPubKey::CreateTapTweak(const uint256* merkle_root) const
{
secp256k1_xonly_pubkey base_point;
if (!secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &base_point, data())) return std::nullopt;
if (!secp256k1_xonly_pubkey_parse(secp256k1_context_static, &base_point, data())) return std::nullopt;
secp256k1_pubkey out;
uint256 tweak = ComputeTapTweakHash(merkle_root);
if (!secp256k1_xonly_pubkey_tweak_add(secp256k1_context_verify, &out, &base_point, tweak.data())) return std::nullopt;
if (!secp256k1_xonly_pubkey_tweak_add(secp256k1_context_static, &out, &base_point, tweak.data())) return std::nullopt;
int parity = -1;
std::pair<XOnlyPubKey, bool> ret;
secp256k1_xonly_pubkey out_xonly;
if (!secp256k1_xonly_pubkey_from_pubkey(secp256k1_context_verify, &out_xonly, &parity, &out)) return std::nullopt;
secp256k1_xonly_pubkey_serialize(secp256k1_context_verify, ret.first.begin(), &out_xonly);
if (!secp256k1_xonly_pubkey_from_pubkey(secp256k1_context_static, &out_xonly, &parity, &out)) return std::nullopt;
secp256k1_xonly_pubkey_serialize(secp256k1_context_static, ret.first.begin(), &out_xonly);
assert(parity == 0 || parity == 1);
ret.second = parity;
return ret;
@ -255,17 +261,16 @@ bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchS
return false;
secp256k1_pubkey pubkey;
secp256k1_ecdsa_signature sig;
assert(secp256k1_context_verify && "secp256k1_context_verify must be initialized to use CPubKey.");
if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, vch, size())) {
if (!secp256k1_ec_pubkey_parse(secp256k1_context_static, &pubkey, vch, size())) {
return false;
}
if (!ecdsa_signature_parse_der_lax(secp256k1_context_verify, &sig, vchSig.data(), vchSig.size())) {
if (!ecdsa_signature_parse_der_lax(&sig, vchSig.data(), vchSig.size())) {
return false;
}
/* libsecp256k1's ECDSA verification requires lower-S signatures, which have
* not historically been enforced in Bitcoin, so normalize them first. */
secp256k1_ecdsa_signature_normalize(secp256k1_context_verify, &sig, &sig);
return secp256k1_ecdsa_verify(secp256k1_context_verify, &sig, hash.begin(), &pubkey);
secp256k1_ecdsa_signature_normalize(secp256k1_context_static, &sig, &sig);
return secp256k1_ecdsa_verify(secp256k1_context_static, &sig, hash.begin(), &pubkey);
}
bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) {
@ -275,16 +280,15 @@ bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector<unsigned cha
bool fComp = ((vchSig[0] - 27) & 4) != 0;
secp256k1_pubkey pubkey;
secp256k1_ecdsa_recoverable_signature sig;
assert(secp256k1_context_verify && "secp256k1_context_verify must be initialized to use CPubKey.");
if (!secp256k1_ecdsa_recoverable_signature_parse_compact(secp256k1_context_verify, &sig, &vchSig[1], recid)) {
if (!secp256k1_ecdsa_recoverable_signature_parse_compact(secp256k1_context_static, &sig, &vchSig[1], recid)) {
return false;
}
if (!secp256k1_ecdsa_recover(secp256k1_context_verify, &pubkey, &sig, hash.begin())) {
if (!secp256k1_ecdsa_recover(secp256k1_context_static, &pubkey, &sig, hash.begin())) {
return false;
}
unsigned char pub[SIZE];
size_t publen = SIZE;
secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, fComp ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);
secp256k1_ec_pubkey_serialize(secp256k1_context_static, pub, &publen, &pubkey, fComp ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);
Set(pub, pub + publen);
return true;
}
@ -293,21 +297,19 @@ bool CPubKey::IsFullyValid() const {
if (!IsValid())
return false;
secp256k1_pubkey pubkey;
assert(secp256k1_context_verify && "secp256k1_context_verify must be initialized to use CPubKey.");
return secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, vch, size());
return secp256k1_ec_pubkey_parse(secp256k1_context_static, &pubkey, vch, size());
}
bool CPubKey::Decompress() {
if (!IsValid())
return false;
secp256k1_pubkey pubkey;
assert(secp256k1_context_verify && "secp256k1_context_verify must be initialized to use CPubKey.");
if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, vch, size())) {
if (!secp256k1_ec_pubkey_parse(secp256k1_context_static, &pubkey, vch, size())) {
return false;
}
unsigned char pub[SIZE];
size_t publen = SIZE;
secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, SECP256K1_EC_UNCOMPRESSED);
secp256k1_ec_pubkey_serialize(secp256k1_context_static, pub, &publen, &pubkey, SECP256K1_EC_UNCOMPRESSED);
Set(pub, pub + publen);
return true;
}
@ -320,16 +322,15 @@ bool CPubKey::Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChi
BIP32Hash(cc, nChild, *begin(), begin()+1, out);
memcpy(ccChild.begin(), out+32, 32);
secp256k1_pubkey pubkey;
assert(secp256k1_context_verify && "secp256k1_context_verify must be initialized to use CPubKey.");
if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, vch, size())) {
if (!secp256k1_ec_pubkey_parse(secp256k1_context_static, &pubkey, vch, size())) {
return false;
}
if (!secp256k1_ec_pubkey_tweak_add(secp256k1_context_verify, &pubkey, out)) {
if (!secp256k1_ec_pubkey_tweak_add(secp256k1_context_static, &pubkey, out)) {
return false;
}
unsigned char pub[COMPRESSED_SIZE];
size_t publen = COMPRESSED_SIZE;
secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, SECP256K1_EC_COMPRESSED);
secp256k1_ec_pubkey_serialize(secp256k1_context_static, pub, &publen, &pubkey, SECP256K1_EC_COMPRESSED);
pubkeyChild.Set(pub, pub + publen);
return true;
}
@ -375,35 +376,8 @@ bool CExtPubKey::Derive(CExtPubKey &out, unsigned int _nChild) const {
/* static */ bool CPubKey::CheckLowS(const std::vector<unsigned char>& vchSig) {
secp256k1_ecdsa_signature sig;
assert(secp256k1_context_verify && "secp256k1_context_verify must be initialized to use CPubKey.");
if (!ecdsa_signature_parse_der_lax(secp256k1_context_verify, &sig, vchSig.data(), vchSig.size())) {
if (!ecdsa_signature_parse_der_lax(&sig, vchSig.data(), vchSig.size())) {
return false;
}
return (!secp256k1_ecdsa_signature_normalize(secp256k1_context_verify, nullptr, &sig));
}
/* static */ int ECCVerifyHandle::refcount = 0;
ECCVerifyHandle::ECCVerifyHandle()
{
if (refcount == 0) {
assert(secp256k1_context_verify == nullptr);
secp256k1_context_verify = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
assert(secp256k1_context_verify != nullptr);
}
refcount++;
}
ECCVerifyHandle::~ECCVerifyHandle()
{
refcount--;
if (refcount == 0) {
assert(secp256k1_context_verify != nullptr);
secp256k1_context_destroy(secp256k1_context_verify);
secp256k1_context_verify = nullptr;
}
}
const secp256k1_context* GetVerifyContext() {
return secp256k1_context_verify;
return (!secp256k1_ecdsa_signature_normalize(secp256k1_context_static, nullptr, &sig));
}

View File

@ -330,21 +330,4 @@ struct CExtPubKey {
[[nodiscard]] bool Derive(CExtPubKey& out, unsigned int nChild) const;
};
/** Users of this module must hold an ECCVerifyHandle. The constructor and
* destructor of these are not allowed to run in parallel, though. */
class ECCVerifyHandle
{
static int refcount;
public:
ECCVerifyHandle();
~ECCVerifyHandle();
};
typedef struct secp256k1_context_struct secp256k1_context;
/** Access to the internal secp256k1 context used for verification. Only intended to be used
* by key.cpp. */
const secp256k1_context* GetVerifyContext();
#endif // BITCOIN_PUBKEY_H

View File

@ -62,12 +62,6 @@ inline int set_error(bitcoinconsensus_error* ret, bitcoinconsensus_error serror)
return 0;
}
struct ECCryptoClosure
{
ECCVerifyHandle handle;
};
ECCryptoClosure instance_of_eccryptoclosure;
} // namespace
/** Check that all specified flags are part of the libconsensus interface. */

View File

@ -26,6 +26,11 @@ env:
# Compile and run the tests
EXAMPLES: yes
# https://cirrus-ci.org/pricing/#compute-credits
credits_snippet: &CREDITS
# Don't use any credits for now.
use_compute_credits: false
cat_logs_snippet: &CAT_LOGS
always:
cat_tests_log_script:
@ -36,7 +41,6 @@ cat_logs_snippet: &CAT_LOGS
- cat valgrind_ctime_test.log || true
cat_bench_log_script:
- cat bench.log || true
on_failure:
cat_config_log_script:
- cat config.log || true
cat_test_env_script:
@ -69,6 +73,7 @@ task:
- env: {WIDEMUL: int64, RECOVERY: yes}
- env: {WIDEMUL: int64, ECDH: yes, SCHNORRSIG: yes}
- env: {WIDEMUL: int128}
- env: {WIDEMUL: int128_struct}
- env: {WIDEMUL: int128, RECOVERY: yes, SCHNORRSIG: yes}
- env: {WIDEMUL: int128, ECDH: yes, SCHNORRSIG: yes}
- env: {WIDEMUL: int128, ASM: x86_64}
@ -107,65 +112,32 @@ task:
<< : *CAT_LOGS
task:
name: "x86_64: macOS Catalina"
name: "arm64: macOS Ventura"
macos_instance:
image: catalina-base
image: ghcr.io/cirruslabs/macos-ventura-base:latest
env:
HOMEBREW_NO_AUTO_UPDATE: 1
HOMEBREW_NO_INSTALL_CLEANUP: 1
# Cirrus gives us a fixed number of 12 virtual CPUs. Not that we even have that many jobs at the moment...
MAKEFLAGS: -j13
# Cirrus gives us a fixed number of 4 virtual CPUs. Not that we even have that many jobs at the moment...
MAKEFLAGS: -j5
matrix:
<< : *ENV_MATRIX
env:
ASM: no
WITH_VALGRIND: no
CTIMETEST: no
matrix:
- env:
CC: gcc-9
CC: gcc
- env:
CC: clang
# Update Command Line Tools
# Uncomment this if the Command Line Tools on the CirrusCI macOS image are too old to brew valgrind.
# See https://apple.stackexchange.com/a/195963 for the implementation.
## update_clt_script:
## - system_profiler SPSoftwareDataType
## - touch /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress
## - |-
## PROD=$(softwareupdate -l | grep "*.*Command Line" | tail -n 1 | awk -F"*" '{print $2}' | sed -e 's/^ *//' | sed 's/Label: //g' | tr -d '\n')
## # For debugging
## - softwareupdate -l && echo "PROD: $PROD"
## - softwareupdate -i "$PROD" --verbose
## - rm /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress
##
brew_valgrind_pre_script:
# Retry a few times because this tends to fail randomly.
- for i in {1..5}; do brew update && break || sleep 15; done
- brew config
- brew tap LouisBrunner/valgrind
# Fetch valgrind source but don't build it yet.
- brew fetch --HEAD LouisBrunner/valgrind/valgrind
brew_valgrind_cache:
# This is $(brew --cellar valgrind) but command substition does not work here.
folder: /usr/local/Cellar/valgrind
# Rebuild cache if ...
fingerprint_script:
# ... macOS version changes:
- sw_vers
# ... brew changes:
- brew config
# ... valgrind changes:
- git -C "$(brew --cache)/valgrind--git" rev-parse HEAD
populate_script:
# If there's no hit in the cache, build and install valgrind.
- brew install --HEAD LouisBrunner/valgrind/valgrind
brew_valgrind_post_script:
# If we have restored valgrind from the cache, tell brew to create symlink to the PATH.
# If we haven't restored from cached (and just run brew install), this is a no-op.
- brew link valgrind
brew_script:
- brew install automake libtool gcc@9
- brew install automake libtool gcc
<< : *MERGE_BASE
test_script:
- ./ci/cirrus.sh
<< : *CAT_LOGS
<< : *CREDITS
task:
name: "s390x (big-endian): Linux (Debian stable, QEMU)"
@ -241,17 +213,63 @@ task:
<< : *CAT_LOGS
task:
name: "x86_64 (mingw32-w64): Windows (Debian stable, Wine)"
<< : *LINUX_CONTAINER
env:
WRAPPER_CMD: wine64-stable
SECP256K1_TEST_ITERS: 16
HOST: x86_64-w64-mingw32
WRAPPER_CMD: wine
WITH_VALGRIND: no
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
CTIMETEST: no
matrix:
- name: "x86_64 (mingw32-w64): Windows (Debian stable, Wine)"
env:
HOST: x86_64-w64-mingw32
- name: "i686 (mingw32-w64): Windows (Debian stable, Wine)"
env:
HOST: i686-w64-mingw32
<< : *MERGE_BASE
test_script:
- ./ci/cirrus.sh
<< : *CAT_LOGS
task:
<< : *LINUX_CONTAINER
env:
WRAPPER_CMD: wine
WERROR_CFLAGS: -WX
WITH_VALGRIND: no
ECDH: yes
RECOVERY: yes
EXPERIMENTAL: yes
SCHNORRSIG: yes
CTIMETEST: no
# Use a MinGW-w64 host to tell ./configure we're building for Windows.
# This will detect some MinGW-w64 tools but then make will need only
# the MSVC tools CC, AR and NM as specified below.
HOST: x86_64-w64-mingw32
CC: /opt/msvc/bin/x64/cl
AR: /opt/msvc/bin/x64/lib
NM: /opt/msvc/bin/x64/dumpbin -symbols -headers
# Set non-essential options that affect the CLI messages here.
# (They depend on the user's taste, so we don't want to set them automatically in configure.ac.)
CFLAGS: -nologo -diagnostics:caret
LDFLAGS: -XCClinker -nologo -XCClinker -diagnostics:caret
matrix:
- name: "x86_64 (MSVC): Windows (Debian stable, Wine)"
- name: "x86_64 (MSVC): Windows (Debian stable, Wine, int128_struct)"
env:
WIDEMUL: int128_struct
- name: "x86_64 (MSVC): Windows (Debian stable, Wine, int128_struct with __(u)mulh)"
env:
WIDEMUL: int128_struct
CPPFLAGS: -DSECP256K1_MSVC_MULH_TEST_OVERRIDE
- name: "i686 (MSVC): Windows (Debian stable, Wine)"
env:
HOST: i686-w64-mingw32
CC: /opt/msvc/bin/x86/cl
AR: /opt/msvc/bin/x86/lib
NM: /opt/msvc/bin/x86/dumpbin -symbols -headers
<< : *MERGE_BASE
test_script:
- ./ci/cirrus.sh
@ -301,14 +319,39 @@ task:
- ./ci/cirrus.sh
<< : *CAT_LOGS
# Memory sanitizers
task:
name: "C++ -fpermissive"
<< : *LINUX_CONTAINER
name: "MSan"
env:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
CTIMETEST: no
CC: clang
SECP256K1_TEST_ITERS: 32
ASM: no
container:
memory: 2G
matrix:
- env:
CFLAGS: "-fsanitize=memory -g"
- env:
ECMULTGENPRECISION: 2
ECMULTWINDOW: 2
CFLAGS: "-fsanitize=memory -g -O3"
<< : *MERGE_BASE
test_script:
- ./ci/cirrus.sh
<< : *CAT_LOGS
task:
name: "C++ -fpermissive (entire project)"
<< : *LINUX_CONTAINER
env:
# ./configure correctly errors out when given CC=g++.
# We hack around this by passing CC=g++ only to make.
CC: gcc
MAKEFLAGS: -j4 CC=g++ CFLAGS=-fpermissive\ -g
CC: g++
CFLAGS: -fpermissive -g
CPPFLAGS: -DSECP256K1_CPLUSPLUS_TEST_OVERRIDE
WERROR_CFLAGS:
ECDH: yes
RECOVERY: yes
@ -318,6 +361,14 @@ task:
- ./ci/cirrus.sh
<< : *CAT_LOGS
task:
name: "C++ (public headers)"
<< : *LINUX_CONTAINER
test_script:
- g++ -Werror include/*.h
- clang -Werror -x c++-header include/*.h
- /opt/msvc/bin/x64/cl.exe -c -WX -TP include/*.h
task:
name: "sage prover"
<< : *LINUX_CONTAINER

View File

@ -13,9 +13,9 @@ schnorr_example
*.so
*.a
*.csv
!.gitignore
*.log
*.trs
*.sage.py
Makefile
configure
@ -34,8 +34,6 @@ libtool
*.lo
*.o
*~
*.log
*.trs
coverage/
coverage.html

View File

@ -0,0 +1,28 @@
# Changelog
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased]
## [0.2.0] - 2022-12-12
### Added
- Added `secp256k1_selftest`, to be used in conjunction with `secp256k1_context_static`.
### Changed
- Enabled modules schnorrsig, extrakeys and ECDH by default in `./configure`.
### Deprecated
- Deprecated context flags `SECP256K1_CONTEXT_VERIFY` and `SECP256K1_CONTEXT_SIGN`. Use `SECP256K1_CONTEXT_NONE` instead.
- Renamed `secp256k1_context_no_precomp` to `secp256k1_context_static`.
### ABI Compatibility
Since this is the first release, we do not compare application binary interfaces.
However, there are unreleased versions of libsecp256k1 that are *not* ABI compatible with this version.
## [0.1.0] - 2013-03-05 to 2021-12-25
This version was in fact never released.
The number was given by the build system since the introduction of autotools in Jan 2014 (ea0fe5a5bf0c04f9cc955b2966b614f5f378c6f6).
Therefore, this version number does not uniquely identify a set of source files.

View File

@ -48,6 +48,12 @@ noinst_HEADERS += src/precomputed_ecmult.h
noinst_HEADERS += src/precomputed_ecmult_gen.h
noinst_HEADERS += src/assumptions.h
noinst_HEADERS += src/util.h
noinst_HEADERS += src/int128.h
noinst_HEADERS += src/int128_impl.h
noinst_HEADERS += src/int128_native.h
noinst_HEADERS += src/int128_native_impl.h
noinst_HEADERS += src/int128_struct.h
noinst_HEADERS += src/int128_struct_impl.h
noinst_HEADERS += src/scratch.h
noinst_HEADERS += src/scratch_impl.h
noinst_HEADERS += src/selftest.h
@ -58,7 +64,6 @@ noinst_HEADERS += src/hash_impl.h
noinst_HEADERS += src/field.h
noinst_HEADERS += src/field_impl.h
noinst_HEADERS += src/bench.h
noinst_HEADERS += src/basic-config.h
noinst_HEADERS += contrib/lax_der_parsing.h
noinst_HEADERS += contrib/lax_der_parsing.c
noinst_HEADERS += contrib/lax_der_privatekey_parsing.h
@ -87,7 +92,7 @@ endif
endif
libsecp256k1_la_SOURCES = src/secp256k1.c
libsecp256k1_la_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES)
libsecp256k1_la_CPPFLAGS = $(SECP_INCLUDES)
libsecp256k1_la_LIBADD = $(SECP_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB)
libsecp256k1_la_LDFLAGS = -no-undefined -version-info $(LIB_VERSION_CURRENT):$(LIB_VERSION_REVISION):$(LIB_VERSION_AGE)
@ -112,7 +117,7 @@ TESTS =
if USE_TESTS
noinst_PROGRAMS += tests
tests_SOURCES = src/tests.c
tests_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
tests_CPPFLAGS = $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
if VALGRIND_ENABLED
tests_CPPFLAGS += -DVALGRIND
noinst_PROGRAMS += valgrind_ctime_test
@ -211,7 +216,15 @@ maintainer-clean-local: clean-precomp
clean-precomp:
rm -f $(PRECOMP)
EXTRA_DIST = autogen.sh SECURITY.md
EXTRA_DIST = autogen.sh CHANGELOG.md SECURITY.md
EXTRA_DIST += doc/release-process.md doc/safegcd_implementation.md
EXTRA_DIST += examples/EXAMPLES_COPYING
EXTRA_DIST += sage/gen_exhaustive_groups.sage
EXTRA_DIST += sage/gen_split_lambda_constants.sage
EXTRA_DIST += sage/group_prover.sage
EXTRA_DIST += sage/prove_group_implementations.sage
EXTRA_DIST += sage/secp256k1_params.sage
EXTRA_DIST += sage/weierstrass_prover.sage
if ENABLE_MODULE_ECDH
include src/modules/ecdh/Makefile.am.include

View File

@ -2,6 +2,8 @@ libsecp256k1
============
[![Build Status](https://api.cirrus-ci.com/github/bitcoin-core/secp256k1.svg?branch=master)](https://cirrus-ci.com/github/bitcoin-core/secp256k1)
![Dependencies: None](https://img.shields.io/badge/dependencies-none-success)
[![irc.libera.chat #secp256k1](https://img.shields.io/badge/irc.libera.chat-%23secp256k1-success)](https://web.libera.chat/#secp256k1)
Optimized C library for ECDSA signatures and secret/public key operations on curve secp256k1.
@ -15,6 +17,7 @@ Features:
* Derandomized ECDSA (via RFC6979 or with a caller provided function.)
* Very efficient implementation.
* Suitable for embedded systems.
* No runtime dependencies.
* Optional module for public key recovery.
* Optional module for ECDH key exchange.
* Optional module for Schnorr signatures according to [BIP-340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki).
@ -72,11 +75,12 @@ To compile optional modules (such as Schnorr signatures), you need to run `./con
Usage examples
-----------
Usage examples can be found in the [examples](examples) directory. To compile them you need to configure with `--enable-examples`.
Usage examples can be found in the [examples](examples) directory. To compile them you need to configure with `--enable-examples`.
* [ECDSA example](examples/ecdsa.c)
* [Schnorr signatures example](examples/schnorr.c)
* [Deriving a shared secret (ECDH) example](examples/ecdh.c)
To compile the Schnorr signature and ECDH examples, you also need to configure with `--enable-module-schnorrsig` and `--enable-module-ecdh`.
To compile the Schnorr signature and ECDH examples, you also need to configure with `--enable-module-schnorrsig` and `--enable-module-ecdh`.
Test coverage
-----------

View File

@ -10,6 +10,7 @@ AC_MSG_RESULT([$has_64bit_asm])
])
AC_DEFUN([SECP_VALGRIND_CHECK],[
AC_MSG_CHECKING([for valgrind support])
if test x"$has_valgrind" != x"yes"; then
CPPFLAGS_TEMP="$CPPFLAGS"
CPPFLAGS="$VALGRIND_CPPFLAGS $CPPFLAGS"
@ -21,6 +22,7 @@ if test x"$has_valgrind" != x"yes"; then
#endif
]])], [has_valgrind=yes; AC_DEFINE(HAVE_VALGRIND,1,[Define this symbol if valgrind is installed, and it supports the host platform])])
fi
AC_MSG_RESULT($has_valgrind)
])
dnl SECP_TRY_APPEND_CFLAGS(flags, VAR)

View File

@ -5,10 +5,47 @@ set -x
export LC_ALL=C
# Print relevant CI environment to allow reproducing the job outside of CI.
print_environment() {
# Turn off -x because it messes up the output
set +x
# There are many ways to print variable names and their content. This one
# does not rely on bash.
for i in WERROR_CFLAGS MAKEFLAGS BUILD \
ECMULTWINDOW ECMULTGENPRECISION ASM WIDEMUL WITH_VALGRIND EXTRAFLAGS \
EXPERIMENTAL ECDH RECOVERY SCHNORRSIG \
SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETEST\
EXAMPLES \
WRAPPER_CMD CC AR NM HOST
do
eval 'printf "%s %s " "$i=\"${'"$i"'}\""'
done
echo "$0"
set -x
}
print_environment
# Start persistent wineserver if necessary.
# This speeds up jobs with many invocations of wine (e.g., ./configure with MSVC) tremendously.
case "$WRAPPER_CMD" in
*wine*)
# This is apparently only reliable when we run a dummy command such as "hh.exe" afterwards.
wineserver -p && wine hh.exe
;;
esac
env >> test_env.log
$CC -v || true
valgrind --version || true
if [ -n "$CC" ]; then
# The MSVC compiler "cl" doesn't understand "-v"
$CC -v || true
fi
if [ "$WITH_VALGRIND" = "yes" ]; then
valgrind --version
fi
if [ -n "$WRAPPER_CMD" ]; then
$WRAPPER_CMD --version
fi
./autogen.sh
@ -63,6 +100,9 @@ then
make precomp
fi
# Shutdown wineserver again
wineserver -k || true
# Check that no repo files have been modified by the build.
# (This fails for example if the precomp files need to be updated in the repo.)
git diff --exit-code

View File

@ -1,15 +1,14 @@
FROM debian:stable
RUN dpkg --add-architecture i386
RUN dpkg --add-architecture s390x
RUN dpkg --add-architecture armhf
RUN dpkg --add-architecture arm64
RUN dpkg --add-architecture ppc64el
RUN apt-get update
RUN dpkg --add-architecture i386 && \
dpkg --add-architecture s390x && \
dpkg --add-architecture armhf && \
dpkg --add-architecture arm64 && \
dpkg --add-architecture ppc64el
# dkpg-dev: to make pkg-config work in cross-builds
# llvm: for llvm-symbolizer, which is used by clang's UBSan for symbolized stack traces
RUN apt-get install --no-install-recommends --no-upgrade -y \
RUN apt-get update && apt-get install --no-install-recommends -y \
git ca-certificates \
make automake libtool pkg-config dpkg-dev valgrind qemu-user \
gcc clang llvm libc6-dbg \
@ -19,8 +18,20 @@ RUN apt-get install --no-install-recommends --no-upgrade -y \
gcc-arm-linux-gnueabihf libc6-dev-armhf-cross libc6-dbg:armhf \
gcc-aarch64-linux-gnu libc6-dev-arm64-cross libc6-dbg:arm64 \
gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross libc6-dbg:ppc64el \
wine gcc-mingw-w64-x86-64 \
gcc-mingw-w64-x86-64-win32 wine64 wine \
gcc-mingw-w64-i686-win32 wine32 \
sagemath
# Run a dummy command in wine to make it set up configuration
RUN wine64-stable xcopy || true
WORKDIR /root
# The "wine" package provides a convience wrapper that we need
RUN apt-get update && apt-get install --no-install-recommends -y \
git ca-certificates wine64 wine python3-simplejson python3-six msitools winbind procps && \
git clone https://github.com/mstorsjo/msvc-wine && \
mkdir /opt/msvc && \
python3 msvc-wine/vsdownload.py --accept-license --dest /opt/msvc Microsoft.VisualStudio.Workload.VCTools && \
msvc-wine/install.sh /opt/msvc
# Initialize the wine environment. Wait until the wineserver process has
# exited before closing the session, to avoid corrupting the wine prefix.
RUN wine64 wineboot --init && \
while (ps -A | grep wineserver) > /dev/null; do sleep 1; done

View File

@ -4,20 +4,20 @@ AC_PREREQ([2.60])
# the API. All changes in experimental modules are treated as
# backwards-compatible and therefore at most increase the minor version.
define(_PKG_VERSION_MAJOR, 0)
define(_PKG_VERSION_MINOR, 1)
define(_PKG_VERSION_BUILD, 0)
define(_PKG_VERSION_IS_RELEASE, false)
define(_PKG_VERSION_MINOR, 2)
define(_PKG_VERSION_PATCH, 0)
define(_PKG_VERSION_IS_RELEASE, true)
# The library version is based on libtool versioning of the ABI. The set of
# rules for updating the version can be found here:
# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
# All changes in experimental modules are treated as if they don't affect the
# interface and therefore only increase the revision.
define(_LIB_VERSION_CURRENT, 0)
define(_LIB_VERSION_CURRENT, 1)
define(_LIB_VERSION_REVISION, 0)
define(_LIB_VERSION_AGE, 0)
AC_INIT([libsecp256k1],m4_join([.], _PKG_VERSION_MAJOR, _PKG_VERSION_MINOR, _PKG_VERSION_BUILD)m4_if(_PKG_VERSION_IS_RELEASE, [true], [], [-pre]),[https://github.com/bitcoin-core/secp256k1/issues],[libsecp256k1],[https://github.com/bitcoin-core/secp256k1])
AC_INIT([libsecp256k1],m4_join([.], _PKG_VERSION_MAJOR, _PKG_VERSION_MINOR, _PKG_VERSION_PATCH)m4_if(_PKG_VERSION_IS_RELEASE, [true], [], [-dev]),[https://github.com/bitcoin-core/secp256k1/issues],[libsecp256k1],[https://github.com/bitcoin-core/secp256k1])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([build-aux/m4])
@ -33,12 +33,14 @@ AM_INIT_AUTOMAKE([1.11.2 foreign subdir-objects])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
AC_PROG_CC
if test x"$ac_cv_prog_cc_c89" = x"no"; then
AC_MSG_ERROR([c89 compiler support required])
fi
AM_PROG_AS
AM_PROG_AR
# Clear some cache variables as a workaround for a bug that appears due to a bad
# interaction between AM_PROG_AR and LT_INIT when combining MSVC's archiver lib.exe.
# https://debbugs.gnu.org/cgi/bugreport.cgi?bug=54421
AS_UNSET(ac_cv_prog_AR)
AS_UNSET(ac_cv_prog_ac_ct_AR)
LT_INIT([win32-dll])
build_windows=no
@ -87,23 +89,35 @@ esac
#
# TODO We should analogously not touch CPPFLAGS and LDFLAGS but currently there are no issues.
AC_DEFUN([SECP_TRY_APPEND_DEFAULT_CFLAGS], [
# Try to append -Werror=unknown-warning-option to CFLAGS temporarily. Otherwise clang will
# not error out if it gets unknown warning flags and the checks here will always succeed
# no matter if clang knows the flag or not.
SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS="$CFLAGS"
SECP_TRY_APPEND_CFLAGS([-Werror=unknown-warning-option], CFLAGS)
# GCC and compatible (incl. clang)
if test "x$GCC" = "xyes"; then
# Try to append -Werror=unknown-warning-option to CFLAGS temporarily. Otherwise clang will
# not error out if it gets unknown warning flags and the checks here will always succeed
# no matter if clang knows the flag or not.
SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS="$CFLAGS"
SECP_TRY_APPEND_CFLAGS([-Werror=unknown-warning-option], CFLAGS)
SECP_TRY_APPEND_CFLAGS([-std=c89 -pedantic -Wno-long-long -Wnested-externs -Wshadow -Wstrict-prototypes -Wundef], $1) # GCC >= 3.0, -Wlong-long is implied by -pedantic.
SECP_TRY_APPEND_CFLAGS([-Wno-overlength-strings], $1) # GCC >= 4.2, -Woverlength-strings is implied by -pedantic.
SECP_TRY_APPEND_CFLAGS([-Wall], $1) # GCC >= 2.95 and probably many other compilers
SECP_TRY_APPEND_CFLAGS([-Wno-unused-function], $1) # GCC >= 3.0, -Wunused-function is implied by -Wall.
SECP_TRY_APPEND_CFLAGS([-Wextra], $1) # GCC >= 3.4, this is the newer name of -W, which we don't use because older GCCs will warn about unused functions.
SECP_TRY_APPEND_CFLAGS([-Wcast-align], $1) # GCC >= 2.95
SECP_TRY_APPEND_CFLAGS([-Wcast-align=strict], $1) # GCC >= 8.0
SECP_TRY_APPEND_CFLAGS([-Wconditional-uninitialized], $1) # Clang >= 3.0 only
SECP_TRY_APPEND_CFLAGS([-fvisibility=hidden], $1) # GCC >= 4.0
SECP_TRY_APPEND_CFLAGS([-std=c89 -pedantic -Wno-long-long -Wnested-externs -Wshadow -Wstrict-prototypes -Wundef], $1) # GCC >= 3.0, -Wlong-long is implied by -pedantic.
SECP_TRY_APPEND_CFLAGS([-Wno-overlength-strings], $1) # GCC >= 4.2, -Woverlength-strings is implied by -pedantic.
SECP_TRY_APPEND_CFLAGS([-Wall], $1) # GCC >= 2.95 and probably many other compilers
SECP_TRY_APPEND_CFLAGS([-Wno-unused-function], $1) # GCC >= 3.0, -Wunused-function is implied by -Wall.
SECP_TRY_APPEND_CFLAGS([-Wextra], $1) # GCC >= 3.4, this is the newer name of -W, which we don't use because older GCCs will warn about unused functions.
SECP_TRY_APPEND_CFLAGS([-Wcast-align], $1) # GCC >= 2.95
SECP_TRY_APPEND_CFLAGS([-Wcast-align=strict], $1) # GCC >= 8.0
SECP_TRY_APPEND_CFLAGS([-Wconditional-uninitialized], $1) # Clang >= 3.0 only
SECP_TRY_APPEND_CFLAGS([-fvisibility=hidden], $1) # GCC >= 4.0
CFLAGS="$SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS"
CFLAGS="$SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS"
fi
# MSVC
# Assume MSVC if we're building for Windows but not with GCC or compatible;
# libtool makes the same assumption internally.
# Note that "/opt" and "-opt" are equivalent for MSVC; we use "-opt" because "/opt" looks like a path.
if test x"$GCC" != x"yes" && test x"$build_windows" = x"yes"; then
SECP_TRY_APPEND_CFLAGS([-W2 -wd4146], $1) # Moderate warning level, disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned"
SECP_TRY_APPEND_CFLAGS([-external:anglebrackets -external:W0], $1) # Suppress warnings from #include <...> files
fi
])
SECP_TRY_APPEND_DEFAULT_CFLAGS(SECP_CFLAGS)
@ -141,27 +155,31 @@ AC_ARG_ENABLE(examples,
[SECP_SET_DEFAULT([enable_examples], [no], [yes])])
AC_ARG_ENABLE(module_ecdh,
AS_HELP_STRING([--enable-module-ecdh],[enable ECDH module [default=no]]), [],
[SECP_SET_DEFAULT([enable_module_ecdh], [no], [yes])])
AS_HELP_STRING([--enable-module-ecdh],[enable ECDH module [default=yes]]), [],
[SECP_SET_DEFAULT([enable_module_ecdh], [yes], [yes])])
AC_ARG_ENABLE(module_recovery,
AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module [default=no]]), [],
[SECP_SET_DEFAULT([enable_module_recovery], [no], [yes])])
AC_ARG_ENABLE(module_extrakeys,
AS_HELP_STRING([--enable-module-extrakeys],[enable extrakeys module [default=no]]), [],
[SECP_SET_DEFAULT([enable_module_extrakeys], [no], [yes])])
AS_HELP_STRING([--enable-module-extrakeys],[enable extrakeys module [default=yes]]), [],
[SECP_SET_DEFAULT([enable_module_extrakeys], [yes], [yes])])
AC_ARG_ENABLE(module_schnorrsig,
AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module [default=no]]), [],
[SECP_SET_DEFAULT([enable_module_schnorrsig], [no], [yes])])
AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module [default=yes]]), [],
[SECP_SET_DEFAULT([enable_module_schnorrsig], [yes], [yes])])
AC_ARG_ENABLE(external_default_callbacks,
AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]), [],
[SECP_SET_DEFAULT([enable_external_default_callbacks], [no], [no])])
# Test-only override of the (autodetected by the C code) "widemul" setting.
# Legal values are int64 (for [u]int64_t), int128 (for [unsigned] __int128), and auto (the default).
# Legal values are:
# * int64 (for [u]int64_t),
# * int128 (for [unsigned] __int128),
# * int128_struct (for int128 implemented as a structure),
# * and auto (the default).
AC_ARG_WITH([test-override-wide-multiply], [] ,[set_widemul=$withval], [set_widemul=auto])
AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto],
@ -271,6 +289,9 @@ fi
# Select wide multiplication implementation
case $set_widemul in
int128_struct)
AC_DEFINE(USE_FORCE_WIDEMUL_INT128_STRUCT, 1, [Define this symbol to force the use of the structure for simulating (unsigned) int128 based wide multiplication])
;;
int128)
AC_DEFINE(USE_FORCE_WIDEMUL_INT128, 1, [Define this symbol to force the use of the (unsigned) __int128 based wide multiplication implementation])
;;
@ -326,7 +347,9 @@ if test x"$enable_valgrind" = x"yes"; then
SECP_INCLUDES="$SECP_INCLUDES $VALGRIND_CPPFLAGS"
fi
# Add -Werror and similar flags passed from the outside (for testing, e.g., in CI)
# Add -Werror and similar flags passed from the outside (for testing, e.g., in CI).
# We don't want to set the user variable CFLAGS in CI because this would disable
# autoconf's logic for setting default CFLAGS, which we would like to test in CI.
SECP_CFLAGS="$SECP_CFLAGS $WERROR_CFLAGS"
###

View File

@ -43,8 +43,7 @@ extern "C" {
/** Export a private key in DER format.
*
* Returns: 1 if the private key was valid.
* Args: ctx: pointer to a context object, initialized for signing (cannot
* be NULL)
* Args: ctx: pointer to a context object (not secp256k1_context_static).
* Out: privkey: pointer to an array for storing the private key in BER.
* Should have space for 279 bytes, and cannot be NULL.
* privkeylen: Pointer to an int where the length of the private key in

View File

@ -1,12 +0,0 @@
# Changelog
This file is currently only a template for future use.
Each change falls into one of the following categories: Added, Changed, Deprecated, Removed, Fixed or Security.
## [Unreleased]
## [MAJOR.MINOR.PATCH] - YYYY-MM-DD
### Added/Changed/Deprecated/Removed/Fixed/Security
- [Title with link to Pull Request](https://link-to-pr)

View File

@ -1,14 +1,52 @@
# Release Process
1. Open PR to master that
1. adds release notes to `doc/CHANGELOG.md` and
2. if this is **not** a patch release, updates `_PKG_VERSION_{MAJOR,MINOR}` and `_LIB_VERSIONS_*` in `configure.ac`
2. After the PR is merged,
* if this is **not** a patch release, create a release branch with name `MAJOR.MINOR`.
Make sure that the branch contains the right commits.
Create commit on the release branch that sets `_PKG_VERSION_IS_RELEASE` in `configure.ac` to `true`.
* if this **is** a patch release, open a pull request with the bugfixes to the `MAJOR.MINOR` branch.
Also include the release note commit bump `_PKG_VERSION_BUILD` and `_LIB_VERSIONS_*` in `configure.ac`.
4. Tag the commit with `git tag -s vMAJOR.MINOR.PATCH`.
5. Push branch and tag with `git push origin --tags`.
6. Create a new GitHub release with a link to the corresponding entry in `doc/CHANGELOG.md`.
This document outlines the process for releasing versions of the form `$MAJOR.$MINOR.$PATCH`.
We distinguish between two types of releases: *regular* and *maintenance* releases.
Regular releases are releases of a new major or minor version as well as patches of the most recent release.
Maintenance releases, on the other hand, are required for patches of older releases.
You should coordinate with the other maintainers on the release date, if possible.
This date will be part of the release entry in [CHANGELOG.md](../CHANGELOG.md) and it should match the dates of the remaining steps in the release process (including the date of the tag and the GitHub release).
It is best if the maintainers are present during the release, so they can help ensure that the process is followed correctly and, in the case of a regular release, they are aware that they should not modify the master branch between merging the PR in step 1 and the PR in step 3.
This process also assumes that there will be no minor releases for old major releases.
## Regular release
1. Open a PR to the master branch with a commit (using message `"release: prepare for $MAJOR.$MINOR.$PATCH"`, for example) that
* finalizes the release notes in [CHANGELOG.md](../CHANGELOG.md) (make sure to include an entry for `### ABI Compatibility`) and
* updates `_PKG_VERSION_*`, `_LIB_VERSION_*`, and sets `_PKG_VERSION_IS_RELEASE` to `true` in `configure.ac`.
2. After the PR is merged, tag the commit and push it:
```
RELEASE_COMMIT=<merge commit of step 1>
git tag -s v$MAJOR.$MINOR.$PATCH -m "libsecp256k1 $MAJOR.$MINOR.$PATCH" $RELEASE_COMMIT
git push git@github.com:bitcoin-core/secp256k1.git v$MAJOR.$MINOR.$PATCH
```
3. Open a PR to the master branch with a commit (using message `"release: bump version after $MAJOR.$MINOR.$PATCH"`, for example) that sets `_PKG_VERSION_IS_RELEASE` to `false` and `_PKG_VERSION_PATCH` to `$PATCH + 1` and increases `_LIB_VERSION_REVISION`. If other maintainers are not present to approve the PR, it can be merged without ACKs.
4. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md).
## Maintenance release
Note that bugfixes only need to be backported to releases for which no compatible release without the bug exists.
1. If `$PATCH = 1`, create maintenance branch `$MAJOR.$MINOR`:
```
git checkout -b $MAJOR.$MINOR v$MAJOR.$MINOR.0
git push git@github.com:bitcoin-core/secp256k1.git $MAJOR.$MINOR
```
2. Open a pull request to the `$MAJOR.$MINOR` branch that
* includes the bugfixes,
* finalizes the release notes,
* bumps `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac` (with commit message `"release: update PKG_ and LIB_VERSION for $MAJOR.$MINOR.$PATCH"`, for example).
3. After the PRs are merged, update the release branch and tag the commit:
```
git checkout $MAJOR.$MINOR && git pull
git tag -s v$MAJOR.$MINOR.$PATCH -m "libsecp256k1 $MAJOR.$MINOR.$PATCH"
```
4. Push tag:
```
git push git@github.com:bitcoin-core/secp256k1.git v$MAJOR.$MINOR.$PATCH
```
5. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md).
6. Open PR to the master branch that includes a commit (with commit message `"release notes: add $MAJOR.$MINOR.$PATCH"`, for example) that adds release notes to [CHANGELOG.md](../CHANGELOG.md).

View File

@ -30,12 +30,8 @@ int main(void) {
secp256k1_pubkey pubkey1;
secp256k1_pubkey pubkey2;
/* The specification in secp256k1.h states that `secp256k1_ec_pubkey_create`
* needs a context object initialized for signing, which is why we create
* a context with the SECP256K1_CONTEXT_SIGN flag.
* (The docs for `secp256k1_ecdh` don't require any special context, just
* some initialized context) */
secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
/* Before we can call actual API functions, we need to create a "context". */
secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
if (!fill_random(randomize, sizeof(randomize))) {
printf("Failed to generate randomness\n");
return 1;

View File

@ -38,12 +38,8 @@ int main(void) {
int return_val;
secp256k1_pubkey pubkey;
secp256k1_ecdsa_signature sig;
/* The specification in secp256k1.h states that `secp256k1_ec_pubkey_create` needs
* a context object initialized for signing and `secp256k1_ecdsa_verify` needs
* a context initialized for verification, which is why we create a context
* for both signing and verification with the SECP256K1_CONTEXT_SIGN and
* SECP256K1_CONTEXT_VERIFY flags. */
secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
/* Before we can call actual API functions, we need to create a "context". */
secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
if (!fill_random(randomize, sizeof(randomize))) {
printf("Failed to generate randomness\n");
return 1;

View File

@ -30,12 +30,8 @@ int main(void) {
int return_val;
secp256k1_xonly_pubkey pubkey;
secp256k1_keypair keypair;
/* The specification in secp256k1_extrakeys.h states that `secp256k1_keypair_create`
* needs a context object initialized for signing. And in secp256k1_schnorrsig.h
* they state that `secp256k1_schnorrsig_verify` needs a context initialized for
* verification, which is why we create a context for both signing and verification
* with the SECP256K1_CONTEXT_SIGN and SECP256K1_CONTEXT_VERIFY flags. */
secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
/* Before we can call actual API functions, we need to create a "context". */
secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
if (!fill_random(randomize, sizeof(randomize))) {
printf("Failed to generate randomness\n");
return 1;

View File

@ -7,7 +7,7 @@ extern "C" {
#include <stddef.h>
/* Unless explicitly stated all pointer arguments must not be NULL.
/** Unless explicitly stated all pointer arguments must not be NULL.
*
* The following rules specify the order of arguments in API calls:
*
@ -24,15 +24,19 @@ extern "C" {
* 5. Opaque data pointers follow the function pointer they are to be passed to.
*/
/** Opaque data structure that holds context information (precomputed tables etc.).
/** Opaque data structure that holds context information
*
* The purpose of context structures is to cache large precomputed data tables
* that are expensive to construct, and also to maintain the randomization data
* for blinding.
* The primary purpose of context objects is to store randomization data for
* enhanced protection against side-channel leakage. This protection is only
* effective if the context is randomized after its creation. See
* secp256k1_context_create for creation of contexts and
* secp256k1_context_randomize for randomization.
*
* Do not create a new context object for each operation, as construction is
* far slower than all other API calls (~100 times slower than an ECDSA
* verification).
* A secondary purpose of context objects is to store pointers to callback
* functions that the library will call when certain error states arise. See
* secp256k1_context_set_error_callback as well as
* secp256k1_context_set_illegal_callback for details. Future library versions
* may use context objects for additional purposes.
*
* A constructed context can safely be used from multiple threads
* simultaneously, but API calls that take a non-const pointer to a context
@ -45,7 +49,7 @@ extern "C" {
*/
typedef struct secp256k1_context_struct secp256k1_context;
/** Opaque data structure that holds rewriteable "scratch space"
/** Opaque data structure that holds rewritable "scratch space"
*
* The purpose of this structure is to replace dynamic memory allocations,
* because we target architectures where this may not be available. It is
@ -130,7 +134,7 @@ typedef int (*secp256k1_nonce_function)(
# define SECP256K1_INLINE inline
# endif
/** When this header is used at build-time the SECP256K1_BUILD define needs to be set
/* When this header is used at build-time the SECP256K1_BUILD define needs to be set
* to correctly setup export attributes and nullness checks. This is normally done
* by secp256k1.c but to guard against this header being included before secp256k1.c
* has had a chance to set the define (e.g. via test harnesses that just includes
@ -159,9 +163,9 @@ typedef int (*secp256k1_nonce_function)(
# endif
#endif
/**Warning attributes
* NONNULL is not used if SECP256K1_BUILD is set to avoid the compiler optimizing out
* some paranoid null checks. */
/* Warning attributes
* NONNULL is not used if SECP256K1_BUILD is set to avoid the compiler optimizing out
* some paranoid null checks. */
# if defined(__GNUC__) && SECP256K1_GNUC_PREREQ(3, 4)
# define SECP256K1_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__))
# else
@ -173,7 +177,7 @@ typedef int (*secp256k1_nonce_function)(
# define SECP256K1_ARG_NONNULL(_x)
# endif
/** Attribute for marking functions, types, and variables as deprecated */
/* Attribute for marking functions, types, and variables as deprecated */
#if !defined(SECP256K1_BUILD) && defined(__has_attribute)
# if __has_attribute(__deprecated__)
# define SECP256K1_DEPRECATED(_msg) __attribute__ ((__deprecated__(_msg)))
@ -184,22 +188,26 @@ typedef int (*secp256k1_nonce_function)(
# define SECP256K1_DEPRECATED(_msg)
#endif
/** All flags' lower 8 bits indicate what they're for. Do not use directly. */
/* All flags' lower 8 bits indicate what they're for. Do not use directly. */
#define SECP256K1_FLAGS_TYPE_MASK ((1 << 8) - 1)
#define SECP256K1_FLAGS_TYPE_CONTEXT (1 << 0)
#define SECP256K1_FLAGS_TYPE_COMPRESSION (1 << 1)
/** The higher bits contain the actual data. Do not use directly. */
/* The higher bits contain the actual data. Do not use directly. */
#define SECP256K1_FLAGS_BIT_CONTEXT_VERIFY (1 << 8)
#define SECP256K1_FLAGS_BIT_CONTEXT_SIGN (1 << 9)
#define SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY (1 << 10)
#define SECP256K1_FLAGS_BIT_COMPRESSION (1 << 8)
/** Flags to pass to secp256k1_context_create, secp256k1_context_preallocated_size, and
/** Context flags to pass to secp256k1_context_create, secp256k1_context_preallocated_size, and
* secp256k1_context_preallocated_create. */
#define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT)
/** Deprecated context flags. These flags are treated equivalent to SECP256K1_CONTEXT_NONE. */
#define SECP256K1_CONTEXT_VERIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_VERIFY)
#define SECP256K1_CONTEXT_SIGN (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_SIGN)
/* Testing flag. Do not use. */
#define SECP256K1_CONTEXT_DECLASSIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY)
#define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT)
/** Flag to pass to secp256k1_ec_pubkey_serialize. */
#define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION)
@ -212,23 +220,66 @@ typedef int (*secp256k1_nonce_function)(
#define SECP256K1_TAG_PUBKEY_HYBRID_EVEN 0x06
#define SECP256K1_TAG_PUBKEY_HYBRID_ODD 0x07
/** A simple secp256k1 context object with no precomputed tables. These are useful for
* type serialization/parsing functions which require a context object to maintain
* API consistency, but currently do not require expensive precomputations or dynamic
* allocations.
/** A built-in constant secp256k1 context object with static storage duration, to be
* used in conjunction with secp256k1_selftest.
*
* This context object offers *only limited functionality* , i.e., it cannot be used
* for API functions that perform computations involving secret keys, e.g., signing
* and public key generation. If this restriction applies to a specific API function,
* it is mentioned in its documentation. See secp256k1_context_create if you need a
* full context object that supports all functionality offered by the library.
*
* It is highly recommended to call secp256k1_selftest before using this context.
*/
SECP256K1_API extern const secp256k1_context *secp256k1_context_no_precomp;
SECP256K1_API extern const secp256k1_context *secp256k1_context_static;
/** Deprecated alias for secp256k1_context_static. */
SECP256K1_API extern const secp256k1_context *secp256k1_context_no_precomp
SECP256K1_DEPRECATED("Use secp256k1_context_static instead");
/** Perform basic self tests (to be used in conjunction with secp256k1_context_static)
*
* This function performs self tests that detect some serious usage errors and
* similar conditions, e.g., when the library is compiled for the wrong endianness.
* This is a last resort measure to be used in production. The performed tests are
* very rudimentary and are not intended as a replacement for running the test
* binaries.
*
* It is highly recommended to call this before using secp256k1_context_static.
* It is not necessary to call this function before using a context created with
* secp256k1_context_create (or secp256k1_context_preallocated_create), which will
* take care of performing the self tests.
*
* If the tests fail, this function will call the default error handler to abort the
* program (see secp256k1_context_set_error_callback).
*/
SECP256K1_API void secp256k1_selftest(void);
/** Create a secp256k1 context object (in dynamically allocated memory).
*
* This function uses malloc to allocate memory. It is guaranteed that malloc is
* called at most once for every call of this function. If you need to avoid dynamic
* memory allocation entirely, see the functions in secp256k1_preallocated.h.
* memory allocation entirely, see secp256k1_context_static and the functions in
* secp256k1_preallocated.h.
*
* Returns: a newly created context object.
* In: flags: which parts of the context to initialize.
* In: flags: Always set to SECP256K1_CONTEXT_NONE (see below).
*
* See also secp256k1_context_randomize.
* The only valid non-deprecated flag in recent library versions is
* SECP256K1_CONTEXT_NONE, which will create a context sufficient for all functionality
* offered by the library. All other (deprecated) flags will be treated as equivalent
* to the SECP256K1_CONTEXT_NONE flag. Though the flags parameter primarily exists for
* historical reasons, future versions of the library may introduce new flags.
*
* If the context is intended to be used for API functions that perform computations
* involving secret keys, e.g., signing and public key generation, then it is highly
* recommended to call secp256k1_context_randomize on the context before calling
* those API functions. This will provide enhanced protection against side-channel
* leakage, see secp256k1_context_randomize for details.
*
* Do not create a new context object for each operation, as construction and
* randomization can take non-negligible time.
*/
SECP256K1_API secp256k1_context* secp256k1_context_create(
unsigned int flags
@ -308,7 +359,10 @@ SECP256K1_API void secp256k1_context_set_illegal_callback(
) SECP256K1_ARG_NONNULL(1);
/** Set a callback function to be called when an internal consistency check
* fails. The default is crashing.
* fails.
*
* The default callback writes an error message to stderr and calls abort
* to abort the program.
*
* This can only trigger in case of a hardware failure, miscompilation,
* memory corruption, serious bug in the library, or other error would can
@ -426,8 +480,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_cmp(
* encoding is invalid. R and S with value 0 are allowed in the encoding.
*
* After the call, sig will always be initialized. If parsing failed or R or
* S are zero, the resulting sig value is guaranteed to fail validation for any
* message and public key.
* S are zero, the resulting sig value is guaranteed to fail verification for
* any message and public key.
*/
SECP256K1_API int secp256k1_ecdsa_signature_parse_compact(
const secp256k1_context* ctx,
@ -447,7 +501,7 @@ SECP256K1_API int secp256k1_ecdsa_signature_parse_compact(
* encoded numbers are out of range.
*
* After the call, sig will always be initialized. If parsing failed or the
* encoded numbers are out of range, signature validation with it is
* encoded numbers are out of range, signature verification with it is
* guaranteed to fail for every message and public key.
*/
SECP256K1_API int secp256k1_ecdsa_signature_parse_der(
@ -494,7 +548,7 @@ SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact(
*
* Returns: 1: correct signature
* 0: incorrect or unparseable signature
* Args: ctx: a secp256k1 context object, initialized for verification.
* Args: ctx: a secp256k1 context object.
* In: sig: the signature being verified.
* msghash32: the 32-byte message hash being verified.
* The verifier must make sure to apply a cryptographic
@ -511,7 +565,7 @@ SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact(
*
* If you need to accept ECDSA signatures from sources that do not obey this
* rule, apply secp256k1_ecdsa_signature_normalize to the signature prior to
* validation, but be aware that doing so results in malleable signatures.
* verification, but be aware that doing so results in malleable signatures.
*
* For details, see the comments for that function.
*/
@ -582,7 +636,7 @@ SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_def
*
* Returns: 1: signature created
* 0: the nonce generation function failed, or the secret key was invalid.
* Args: ctx: pointer to a context object, initialized for signing.
* Args: ctx: pointer to a context object (not secp256k1_context_static).
* Out: sig: pointer to an array where the signature will be placed.
* In: msghash32: the 32-byte message hash being signed.
* seckey: pointer to a 32-byte secret key.
@ -626,7 +680,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify(
*
* Returns: 1: secret was valid, public key stores.
* 0: secret was invalid, try again.
* Args: ctx: pointer to a context object, initialized for signing.
* Args: ctx: pointer to a context object (not secp256k1_context_static).
* Out: pubkey: pointer to the created public key.
* In: seckey: pointer to a 32-byte secret key.
*/
@ -705,7 +759,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add(
* Returns: 0 if the arguments are invalid or the resulting public key would be
* invalid (only when the tweak is the negation of the corresponding
* secret key). 1 otherwise.
* Args: ctx: pointer to a context object initialized for validation.
* Args: ctx: pointer to a context object.
* In/Out: pubkey: pointer to a public key object. pubkey will be set to an
* invalid value if this function returns 0.
* In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to
@ -750,7 +804,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul(
/** Tweak a public key by multiplying it by a tweak value.
*
* Returns: 0 if the arguments are invalid. 1 otherwise.
* Args: ctx: pointer to a context object initialized for validation.
* Args: ctx: pointer to a context object.
* In/Out: pubkey: pointer to a public key object. pubkey will be set to an
* invalid value if this function returns 0.
* In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to
@ -764,30 +818,41 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Updates the context randomization to protect against side-channel leakage.
* Returns: 1: randomization successfully updated or nothing to randomize
/** Randomizes the context to provide enhanced protection against side-channel leakage.
*
* Returns: 1: randomization successful (or called on copy of secp256k1_context_static)
* 0: error
* Args: ctx: pointer to a context object.
* In: seed32: pointer to a 32-byte random seed (NULL resets to initial state)
*
* While secp256k1 code is written to be constant-time no matter what secret
* values are, it's possible that a future compiler may output code which isn't,
* While secp256k1 code is written and tested to be constant-time no matter what
* secret values are, it is possible that a compiler may output code which is not,
* and also that the CPU may not emit the same radio frequencies or draw the same
* amount power for all values.
* amount of power for all values. Randomization of the context shields against
* side-channel observations which aim to exploit secret-dependent behaviour in
* certain computations which involve secret keys.
*
* This function provides a seed which is combined into the blinding value: that
* blinding value is added before each multiplication (and removed afterwards) so
* that it does not affect function results, but shields against attacks which
* rely on any input-dependent behaviour.
* It is highly recommended to call this function on contexts returned from
* secp256k1_context_create or secp256k1_context_clone (or from the corresponding
* functions in secp256k1_preallocated.h) before using these contexts to call API
* functions that perform computations involving secret keys, e.g., signing and
* public key generation. It is possible to call this function more than once on
* the same context, and doing so before every few computations involving secret
* keys is recommended as a defense-in-depth measure.
*
* This function has currently an effect only on contexts initialized for signing
* because randomization is currently used only for signing. However, this is not
* guaranteed and may change in the future. It is safe to call this function on
* contexts not initialized for signing; then it will have no effect and return 1.
* Currently, the random seed is mainly used for blinding multiplications of a
* secret scalar with the elliptic curve base point. Multiplications of this
* kind are performed by exactly those API functions which are documented to
* require a context that is not the secp256k1_context_static. As a rule of thumb,
* these are all functions which take a secret key (or a keypair) as an input.
* A notable exception to that rule is the ECDH module, which relies on a different
* kind of elliptic curve point multiplication and thus does not benefit from
* enhanced protection against side-channel leakage currently.
*
* You should call this after secp256k1_context_create or
* secp256k1_context_clone (and secp256k1_context_preallocated_create or
* secp256k1_context_clone, resp.), and you may call this repeatedly afterwards.
* It is safe call this function on a copy of secp256k1_context_static in writable
* memory (e.g., obtained via secp256k1_context_clone). In that case, this
* function is guaranteed to return 1, but the call will have no effect because
* the static context (or a copy thereof) is not meant to be randomized.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize(
secp256k1_context* ctx,

View File

@ -108,7 +108,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_from_pubke
* invalid (only when the tweak is the negation of the corresponding
* secret key). 1 otherwise.
*
* Args: ctx: pointer to a context object initialized for verification.
* Args: ctx: pointer to a context object.
* Out: output_pubkey: pointer to a public key to store the result. Will be set
* to an invalid value if this function returns 0.
* In: internal_pubkey: pointer to an x-only pubkey to apply the tweak to.
@ -137,7 +137,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add(
*
* Returns: 0 if the arguments are invalid or the tweaked pubkey is not the
* result of tweaking the internal_pubkey with tweak32. 1 otherwise.
* Args: ctx: pointer to a context object initialized for verification.
* Args: ctx: pointer to a context object.
* In: tweaked_pubkey32: pointer to a serialized xonly_pubkey.
* tweaked_pk_parity: the parity of the tweaked pubkey (whose serialization
* is passed in as tweaked_pubkey32). This must match the
@ -159,7 +159,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add_
*
* Returns: 1: secret was valid, keypair is ready to use
* 0: secret was invalid, try again with a different secret
* Args: ctx: pointer to a context object, initialized for signing.
* Args: ctx: pointer to a context object (not secp256k1_context_static).
* Out: keypair: pointer to the created keypair.
* In: seckey: pointer to a 32-byte secret key.
*/
@ -228,7 +228,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_pub(
* invalid (only when the tweak is the negation of the keypair's
* secret key). 1 otherwise.
*
* Args: ctx: pointer to a context object initialized for verification.
* Args: ctx: pointer to a context object.
* In/Out: keypair: pointer to a keypair to apply the tweak to. Will be set to
* an invalid value if this function returns 0.
* In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according

View File

@ -58,6 +58,8 @@ SECP256K1_API size_t secp256k1_context_preallocated_size(
* bytes, as detailed above.
* flags: which parts of the context to initialize.
*
* See secp256k1_context_create (in secp256k1.h) for further details.
*
* See also secp256k1_context_randomize (in secp256k1.h)
* and secp256k1_context_preallocated_destroy.
*/

View File

@ -72,7 +72,7 @@ SECP256K1_API int secp256k1_ecdsa_recoverable_signature_serialize_compact(
*
* Returns: 1: signature created
* 0: the nonce generation function failed, or the secret key was invalid.
* Args: ctx: pointer to a context object, initialized for signing.
* Args: ctx: pointer to a context object (not secp256k1_context_static).
* Out: sig: pointer to an array where the signature will be placed.
* In: msghash32: the 32-byte message hash being signed.
* seckey: pointer to a 32-byte secret key.
@ -94,7 +94,7 @@ SECP256K1_API int secp256k1_ecdsa_sign_recoverable(
*
* Returns: 1: public key successfully recovered (which guarantees a correct signature).
* 0: otherwise.
* Args: ctx: pointer to a context object, initialized for verification.
* Args: ctx: pointer to a context object.
* Out: pubkey: pointer to the recovered public key.
* In: sig: pointer to initialized signature that supports pubkey recovery.
* msghash32: the 32-byte message hash assumed to be signed.

View File

@ -106,7 +106,7 @@ typedef struct {
* signatures from being valid in multiple contexts by accident.
*
* Returns 1 on success, 0 on failure.
* Args: ctx: pointer to a context object, initialized for signing.
* Args: ctx: pointer to a context object (not secp256k1_context_static).
* Out: sig64: pointer to a 64-byte array to store the serialized signature.
* In: msg32: the 32-byte message being signed.
* keypair: pointer to an initialized keypair.
@ -161,7 +161,7 @@ SECP256K1_API int secp256k1_schnorrsig_sign_custom(
*
* Returns: 1: correct signature
* 0: incorrect signature
* Args: ctx: a secp256k1 context object, initialized for verification.
* Args: ctx: a secp256k1 context object.
* In: sig64: pointer to the 64-byte signature to verify.
* msg: the message being verified. Can only be NULL if msglen is 0.
* msglen: length of the message

View File

@ -10,6 +10,9 @@
#include <limits.h>
#include "util.h"
#if defined(SECP256K1_INT128_NATIVE)
#include "int128_native.h"
#endif
/* This library, like most software, relies on a number of compiler implementation defined (but not undefined)
behaviours. Although the behaviours we require are essentially universal we test them specifically here to
@ -55,7 +58,7 @@ struct secp256k1_assumption_checker {
/* To int64_t. */
((int64_t)(uint64_t)0xB123C456D789E012ULL == (int64_t)-(int64_t)0x4EDC3BA928761FEEULL) &&
#if defined(SECP256K1_WIDEMUL_INT128)
#if defined(SECP256K1_INT128_NATIVE)
((int64_t)(((uint128_t)0xA1234567B8901234ULL << 64) + 0xC5678901D2345678ULL) == (int64_t)-(int64_t)0x3A9876FE2DCBA988ULL) &&
(((int64_t)(int128_t)(((uint128_t)0xB1C2D3E4F5A6B7C8ULL << 64) + 0xD9E0F1A2B3C4D5E6ULL)) == (int64_t)(uint64_t)0xD9E0F1A2B3C4D5E6ULL) &&
(((int64_t)(int128_t)(((uint128_t)0xABCDEF0123456789ULL << 64) + 0x0123456789ABCDEFULL)) == (int64_t)(uint64_t)0x0123456789ABCDEFULL) &&
@ -71,7 +74,7 @@ struct secp256k1_assumption_checker {
((((int16_t)0xE9AC) >> 4) == (int16_t)(uint16_t)0xFE9A) &&
((((int32_t)0x937C918A) >> 9) == (int32_t)(uint32_t)0xFFC9BE48) &&
((((int64_t)0xA8B72231DF9CF4B9ULL) >> 19) == (int64_t)(uint64_t)0xFFFFF516E4463BF3ULL) &&
#if defined(SECP256K1_WIDEMUL_INT128)
#if defined(SECP256K1_INT128_NATIVE)
((((int128_t)(((uint128_t)0xCD833A65684A0DBCULL << 64) + 0xB349312F71EA7637ULL)) >> 39) == (int128_t)(((uint128_t)0xFFFFFFFFFF9B0674ULL << 64) + 0xCAD0941B79669262ULL)) &&
#endif
1) * 2 - 1];

View File

@ -1,17 +0,0 @@
/***********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_BASIC_CONFIG_H
#define SECP256K1_BASIC_CONFIG_H
#ifdef USE_BASIC_CONFIG
#define ECMULT_WINDOW_SIZE 15
#define ECMULT_GEN_PREC_BITS 4
#endif /* USE_BASIC_CONFIG */
#endif /* SECP256K1_BASIC_CONFIG_H */

View File

@ -164,7 +164,7 @@ int main(int argc, char** argv) {
/* Check if the user tries to benchmark optional module without building it */
#ifndef ENABLE_MODULE_ECDH
if (have_flag(argc, argv, "ecdh")) {
if (have_flag(argc, argv, "ecdh")) {
fprintf(stderr, "./bench: ECDH module not enabled.\n");
fprintf(stderr, "Use ./configure --enable-module-ecdh.\n\n");
return 1;
@ -172,7 +172,7 @@ int main(int argc, char** argv) {
#endif
#ifndef ENABLE_MODULE_RECOVERY
if (have_flag(argc, argv, "recover") || have_flag(argc, argv, "ecdsa_recover")) {
if (have_flag(argc, argv, "recover") || have_flag(argc, argv, "ecdsa_recover")) {
fprintf(stderr, "./bench: Public key recovery module not enabled.\n");
fprintf(stderr, "Use ./configure --enable-module-recovery.\n\n");
return 1;
@ -180,15 +180,15 @@ int main(int argc, char** argv) {
#endif
#ifndef ENABLE_MODULE_SCHNORRSIG
if (have_flag(argc, argv, "schnorrsig") || have_flag(argc, argv, "schnorrsig_sign") || have_flag(argc, argv, "schnorrsig_verify")) {
if (have_flag(argc, argv, "schnorrsig") || have_flag(argc, argv, "schnorrsig_sign") || have_flag(argc, argv, "schnorrsig_verify")) {
fprintf(stderr, "./bench: Schnorr signatures module not enabled.\n");
fprintf(stderr, "Use ./configure --enable-module-schnorrsig.\n\n");
return 1;
}
#endif
/* ECDSA verification benchmark */
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
/* ECDSA benchmark */
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
for (i = 0; i < 32; i++) {
data.msg[i] = 1 + i;
@ -206,11 +206,6 @@ int main(int argc, char** argv) {
print_output_table_header_row();
if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "verify") || have_flag(argc, argv, "ecdsa_verify")) run_benchmark("ecdsa_verify", bench_verify, NULL, NULL, &data, 10, iters);
secp256k1_context_destroy(data.ctx);
/* ECDSA signing benchmark */
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "sign") || have_flag(argc, argv, "ecdsa_sign")) run_benchmark("ecdsa_sign", bench_sign_run, bench_sign_setup, NULL, &data, 10, iters);
secp256k1_context_destroy(data.ctx);

View File

@ -7,15 +7,31 @@
#ifndef SECP256K1_BENCH_H
#define SECP256K1_BENCH_H
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "sys/time.h"
#if (defined(_MSC_VER) && _MSC_VER >= 1900)
# include <time.h>
#else
# include "sys/time.h"
#endif
static int64_t gettime_i64(void) {
#if (defined(_MSC_VER) && _MSC_VER >= 1900)
/* C11 way to get wallclock time */
struct timespec tv;
if (!timespec_get(&tv, TIME_UTC)) {
fputs("timespec_get failed!", stderr);
exit(1);
}
return (int64_t)tv.tv_nsec / 1000 + (int64_t)tv.tv_sec * 1000000LL;
#else
struct timeval tv;
gettimeofday(&tv, NULL);
return (int64_t)tv.tv_usec + (int64_t)tv.tv_sec * 1000000LL;
#endif
}
#define FP_EXP (6)

View File

@ -84,9 +84,7 @@ static void bench_ecmult_teardown_helper(bench_data* data, size_t* seckey_offset
}
}
secp256k1_ecmult_gen(&data->ctx->ecmult_gen_ctx, &tmp, &sum_scalars);
secp256k1_gej_neg(&tmp, &tmp);
secp256k1_gej_add_var(&tmp, &tmp, &sum_output, NULL);
CHECK(secp256k1_gej_is_infinity(&tmp));
CHECK(secp256k1_gej_eq_var(&tmp, &sum_output));
}
static void bench_ecmult_setup(void* arg) {
@ -308,7 +306,7 @@ int main(int argc, char **argv) {
}
}
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
scratch_size = secp256k1_strauss_scratch_size(POINTS) + STRAUSS_SCRATCH_OBJECTS*16;
if (!have_flag(argc, argv, "simple")) {
data.scratch = secp256k1_scratch_space_create(data.ctx, scratch_size);

View File

@ -343,19 +343,11 @@ void bench_rfc6979_hmac_sha256(void* arg, int iters) {
}
}
void bench_context_verify(void* arg, int iters) {
void bench_context(void* arg, int iters) {
int i;
(void)arg;
for (i = 0; i < iters; i++) {
secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_VERIFY));
}
}
void bench_context_sign(void* arg, int iters) {
int i;
(void)arg;
for (i = 0; i < iters; i++) {
secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_SIGN));
secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_NONE));
}
}
@ -395,8 +387,7 @@ int main(int argc, char **argv) {
if (d || have_flag(argc, argv, "hash") || have_flag(argc, argv, "hmac")) run_benchmark("hash_hmac_sha256", bench_hmac_sha256, bench_setup, NULL, &data, 10, iters);
if (d || have_flag(argc, argv, "hash") || have_flag(argc, argv, "rng6979")) run_benchmark("hash_rfc6979_hmac_sha256", bench_rfc6979_hmac_sha256, bench_setup, NULL, &data, 10, iters);
if (d || have_flag(argc, argv, "context") || have_flag(argc, argv, "verify")) run_benchmark("context_verify", bench_context_verify, bench_setup, NULL, &data, 10, 1 + iters/1000);
if (d || have_flag(argc, argv, "context") || have_flag(argc, argv, "sign")) run_benchmark("context_sign", bench_context_sign, bench_setup, NULL, &data, 10, 1 + iters/100);
if (d || have_flag(argc, argv, "context")) run_benchmark("context_create", bench_context, bench_setup, NULL, &data, 10, iters);
return 0;
}

View File

@ -11,6 +11,17 @@
#include "scalar.h"
#include "scratch.h"
#ifndef ECMULT_WINDOW_SIZE
# define ECMULT_WINDOW_SIZE 15
# ifdef DEBUG_CONFIG
# pragma message DEBUG_CONFIG_MSG("ECMULT_WINDOW_SIZE undefined, assuming default value")
# endif
#endif
#ifdef DEBUG_CONFIG
# pragma message DEBUG_CONFIG_DEF(ECMULT_WINDOW_SIZE)
#endif
/* Noone will ever need more than a window size of 24. The code might
* be correct for larger values of ECMULT_WINDOW_SIZE but this is not
* tested.

View File

@ -10,9 +10,21 @@
#include "scalar.h"
#include "group.h"
#ifndef ECMULT_GEN_PREC_BITS
# define ECMULT_GEN_PREC_BITS 4
# ifdef DEBUG_CONFIG
# pragma message DEBUG_CONFIG_MSG("ECMULT_GEN_PREC_BITS undefined, assuming default value")
# endif
#endif
#ifdef DEBUG_CONFIG
# pragma message DEBUG_CONFIG_DEF(ECMULT_GEN_PREC_BITS)
#endif
#if ECMULT_GEN_PREC_BITS != 2 && ECMULT_GEN_PREC_BITS != 4 && ECMULT_GEN_PREC_BITS != 8
# error "Set ECMULT_GEN_PREC_BITS to 2, 4 or 8."
#endif
#define ECMULT_GEN_PREC_G(bits) (1 << bits)
#define ECMULT_GEN_PREC_N(bits) (256 / bits)

View File

@ -88,31 +88,31 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
unsigned char nonce32[32];
secp256k1_rfc6979_hmac_sha256 rng;
int overflow;
unsigned char keydata[64] = {0};
unsigned char keydata[64];
if (seed32 == NULL) {
/* When seed is NULL, reset the initial point and blinding value. */
secp256k1_gej_set_ge(&ctx->initial, &secp256k1_ge_const_g);
secp256k1_gej_neg(&ctx->initial, &ctx->initial);
secp256k1_scalar_set_int(&ctx->blind, 1);
return;
}
/* The prior blinding value (if not reset) is chained forward by including it in the hash. */
secp256k1_scalar_get_b32(nonce32, &ctx->blind);
secp256k1_scalar_get_b32(keydata, &ctx->blind);
/** Using a CSPRNG allows a failure free interface, avoids needing large amounts of random data,
* and guards against weak or adversarial seeds. This is a simpler and safer interface than
* asking the caller for blinding values directly and expecting them to retry on failure.
*/
memcpy(keydata, nonce32, 32);
if (seed32 != NULL) {
memcpy(keydata + 32, seed32, 32);
}
secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, seed32 ? 64 : 32);
VERIFY_CHECK(seed32 != NULL);
memcpy(keydata + 32, seed32, 32);
secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, 64);
memset(keydata, 0, sizeof(keydata));
/* Accept unobservably small non-uniformity. */
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
overflow = !secp256k1_fe_set_b32(&s, nonce32);
overflow |= secp256k1_fe_is_zero(&s);
secp256k1_fe_cmov(&s, &secp256k1_fe_one, overflow);
/* Randomize the projection to defend against multiplier sidechannels. */
/* Randomize the projection to defend against multiplier sidechannels.
Do this before our own call to secp256k1_ecmult_gen below. */
secp256k1_gej_rescale(&ctx->initial, &s);
secp256k1_fe_clear(&s);
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
@ -121,6 +121,7 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
secp256k1_scalar_cmov(&b, &secp256k1_scalar_one, secp256k1_scalar_is_zero(&b));
secp256k1_rfc6979_hmac_sha256_finalize(&rng);
memset(nonce32, 0, 32);
/* The random projection in ctx->initial ensures that gb will have a random projection. */
secp256k1_ecmult_gen(ctx, &gb, &b);
secp256k1_scalar_negate(&b, &b);
ctx->blind = b;

View File

@ -200,9 +200,15 @@ static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a,
bit += now;
}
#ifdef VERIFY
CHECK(carry == 0);
while (bit < 256) {
CHECK(secp256k1_scalar_get_bits(&s, bit++, 1) == 0);
{
int verify_bit = bit;
VERIFY_CHECK(carry == 0);
while (verify_bit < 256) {
VERIFY_CHECK(secp256k1_scalar_get_bits(&s, verify_bit, 1) == 0);
verify_bit++;
}
}
#endif
return last_set_bit + 1;

View File

@ -9,14 +9,18 @@
#include <stdint.h>
#include "int128.h"
#ifdef VERIFY
#define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0)
#define VERIFY_BITS_128(x, n) VERIFY_CHECK(secp256k1_u128_check_bits((x), (n)))
#else
#define VERIFY_BITS(x, n) do { } while(0)
#define VERIFY_BITS_128(x, n) do { } while(0)
#endif
SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) {
uint128_t c, d;
secp256k1_uint128 c, d;
uint64_t t3, t4, tx, u0;
uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4];
const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL;
@ -40,121 +44,119 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t
* Note that [x 0 0 0 0 0] = [x*R].
*/
d = (uint128_t)a0 * b[3]
+ (uint128_t)a1 * b[2]
+ (uint128_t)a2 * b[1]
+ (uint128_t)a3 * b[0];
VERIFY_BITS(d, 114);
secp256k1_u128_mul(&d, a0, b[3]);
secp256k1_u128_accum_mul(&d, a1, b[2]);
secp256k1_u128_accum_mul(&d, a2, b[1]);
secp256k1_u128_accum_mul(&d, a3, b[0]);
VERIFY_BITS_128(&d, 114);
/* [d 0 0 0] = [p3 0 0 0] */
c = (uint128_t)a4 * b[4];
VERIFY_BITS(c, 112);
secp256k1_u128_mul(&c, a4, b[4]);
VERIFY_BITS_128(&c, 112);
/* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
d += (uint128_t)R * (uint64_t)c; c >>= 64;
VERIFY_BITS(d, 115);
VERIFY_BITS(c, 48);
secp256k1_u128_accum_mul(&d, R, secp256k1_u128_to_u64(&c)); secp256k1_u128_rshift(&c, 64);
VERIFY_BITS_128(&d, 115);
VERIFY_BITS_128(&c, 48);
/* [(c<<12) 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
t3 = d & M; d >>= 52;
t3 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52);
VERIFY_BITS(t3, 52);
VERIFY_BITS(d, 63);
VERIFY_BITS_128(&d, 63);
/* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
d += (uint128_t)a0 * b[4]
+ (uint128_t)a1 * b[3]
+ (uint128_t)a2 * b[2]
+ (uint128_t)a3 * b[1]
+ (uint128_t)a4 * b[0];
VERIFY_BITS(d, 115);
secp256k1_u128_accum_mul(&d, a0, b[4]);
secp256k1_u128_accum_mul(&d, a1, b[3]);
secp256k1_u128_accum_mul(&d, a2, b[2]);
secp256k1_u128_accum_mul(&d, a3, b[1]);
secp256k1_u128_accum_mul(&d, a4, b[0]);
VERIFY_BITS_128(&d, 115);
/* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
d += (uint128_t)(R << 12) * (uint64_t)c;
VERIFY_BITS(d, 116);
secp256k1_u128_accum_mul(&d, R << 12, secp256k1_u128_to_u64(&c));
VERIFY_BITS_128(&d, 116);
/* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
t4 = d & M; d >>= 52;
t4 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52);
VERIFY_BITS(t4, 52);
VERIFY_BITS(d, 64);
VERIFY_BITS_128(&d, 64);
/* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
tx = (t4 >> 48); t4 &= (M >> 4);
VERIFY_BITS(tx, 4);
VERIFY_BITS(t4, 48);
/* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
c = (uint128_t)a0 * b[0];
VERIFY_BITS(c, 112);
secp256k1_u128_mul(&c, a0, b[0]);
VERIFY_BITS_128(&c, 112);
/* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */
d += (uint128_t)a1 * b[4]
+ (uint128_t)a2 * b[3]
+ (uint128_t)a3 * b[2]
+ (uint128_t)a4 * b[1];
VERIFY_BITS(d, 115);
secp256k1_u128_accum_mul(&d, a1, b[4]);
secp256k1_u128_accum_mul(&d, a2, b[3]);
secp256k1_u128_accum_mul(&d, a3, b[2]);
secp256k1_u128_accum_mul(&d, a4, b[1]);
VERIFY_BITS_128(&d, 115);
/* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
u0 = d & M; d >>= 52;
u0 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52);
VERIFY_BITS(u0, 52);
VERIFY_BITS(d, 63);
VERIFY_BITS_128(&d, 63);
/* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
/* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
u0 = (u0 << 4) | tx;
VERIFY_BITS(u0, 56);
/* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
c += (uint128_t)u0 * (R >> 4);
VERIFY_BITS(c, 115);
secp256k1_u128_accum_mul(&c, u0, R >> 4);
VERIFY_BITS_128(&c, 115);
/* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
r[0] = c & M; c >>= 52;
r[0] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
VERIFY_BITS(r[0], 52);
VERIFY_BITS(c, 61);
VERIFY_BITS_128(&c, 61);
/* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */
c += (uint128_t)a0 * b[1]
+ (uint128_t)a1 * b[0];
VERIFY_BITS(c, 114);
secp256k1_u128_accum_mul(&c, a0, b[1]);
secp256k1_u128_accum_mul(&c, a1, b[0]);
VERIFY_BITS_128(&c, 114);
/* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */
d += (uint128_t)a2 * b[4]
+ (uint128_t)a3 * b[3]
+ (uint128_t)a4 * b[2];
VERIFY_BITS(d, 114);
secp256k1_u128_accum_mul(&d, a2, b[4]);
secp256k1_u128_accum_mul(&d, a3, b[3]);
secp256k1_u128_accum_mul(&d, a4, b[2]);
VERIFY_BITS_128(&d, 114);
/* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
c += (d & M) * R; d >>= 52;
VERIFY_BITS(c, 115);
VERIFY_BITS(d, 62);
secp256k1_u128_accum_mul(&c, secp256k1_u128_to_u64(&d) & M, R); secp256k1_u128_rshift(&d, 52);
VERIFY_BITS_128(&c, 115);
VERIFY_BITS_128(&d, 62);
/* [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
r[1] = c & M; c >>= 52;
r[1] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
VERIFY_BITS(r[1], 52);
VERIFY_BITS(c, 63);
VERIFY_BITS_128(&c, 63);
/* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
c += (uint128_t)a0 * b[2]
+ (uint128_t)a1 * b[1]
+ (uint128_t)a2 * b[0];
VERIFY_BITS(c, 114);
secp256k1_u128_accum_mul(&c, a0, b[2]);
secp256k1_u128_accum_mul(&c, a1, b[1]);
secp256k1_u128_accum_mul(&c, a2, b[0]);
VERIFY_BITS_128(&c, 114);
/* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */
d += (uint128_t)a3 * b[4]
+ (uint128_t)a4 * b[3];
VERIFY_BITS(d, 114);
secp256k1_u128_accum_mul(&d, a3, b[4]);
secp256k1_u128_accum_mul(&d, a4, b[3]);
VERIFY_BITS_128(&d, 114);
/* [d 0 0 t4 t3 c t1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
c += (uint128_t)R * (uint64_t)d; d >>= 64;
VERIFY_BITS(c, 115);
VERIFY_BITS(d, 50);
secp256k1_u128_accum_mul(&c, R, secp256k1_u128_to_u64(&d)); secp256k1_u128_rshift(&d, 64);
VERIFY_BITS_128(&c, 115);
VERIFY_BITS_128(&d, 50);
/* [(d<<12) 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
r[2] = c & M; c >>= 52;
r[2] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
VERIFY_BITS(r[2], 52);
VERIFY_BITS(c, 63);
VERIFY_BITS_128(&c, 63);
/* [(d<<12) 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
c += (uint128_t)(R << 12) * (uint64_t)d + t3;
VERIFY_BITS(c, 100);
secp256k1_u128_accum_mul(&c, R << 12, secp256k1_u128_to_u64(&d));
secp256k1_u128_accum_u64(&c, t3);
VERIFY_BITS_128(&c, 100);
/* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
r[3] = c & M; c >>= 52;
r[3] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
VERIFY_BITS(r[3], 52);
VERIFY_BITS(c, 48);
VERIFY_BITS_128(&c, 48);
/* [t4+c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
c += t4;
VERIFY_BITS(c, 49);
/* [c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
r[4] = c;
r[4] = secp256k1_u128_to_u64(&c) + t4;
VERIFY_BITS(r[4], 49);
/* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
}
SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t *a) {
uint128_t c, d;
secp256k1_uint128 c, d;
uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4];
int64_t t3, t4, tx, u0;
const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL;
@ -170,107 +172,105 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t
* Note that [x 0 0 0 0 0] = [x*R].
*/
d = (uint128_t)(a0*2) * a3
+ (uint128_t)(a1*2) * a2;
VERIFY_BITS(d, 114);
secp256k1_u128_mul(&d, a0*2, a3);
secp256k1_u128_accum_mul(&d, a1*2, a2);
VERIFY_BITS_128(&d, 114);
/* [d 0 0 0] = [p3 0 0 0] */
c = (uint128_t)a4 * a4;
VERIFY_BITS(c, 112);
secp256k1_u128_mul(&c, a4, a4);
VERIFY_BITS_128(&c, 112);
/* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
d += (uint128_t)R * (uint64_t)c; c >>= 64;
VERIFY_BITS(d, 115);
VERIFY_BITS(c, 48);
secp256k1_u128_accum_mul(&d, R, secp256k1_u128_to_u64(&c)); secp256k1_u128_rshift(&c, 64);
VERIFY_BITS_128(&d, 115);
VERIFY_BITS_128(&c, 48);
/* [(c<<12) 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
t3 = d & M; d >>= 52;
t3 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52);
VERIFY_BITS(t3, 52);
VERIFY_BITS(d, 63);
VERIFY_BITS_128(&d, 63);
/* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
a4 *= 2;
d += (uint128_t)a0 * a4
+ (uint128_t)(a1*2) * a3
+ (uint128_t)a2 * a2;
VERIFY_BITS(d, 115);
secp256k1_u128_accum_mul(&d, a0, a4);
secp256k1_u128_accum_mul(&d, a1*2, a3);
secp256k1_u128_accum_mul(&d, a2, a2);
VERIFY_BITS_128(&d, 115);
/* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
d += (uint128_t)(R << 12) * (uint64_t)c;
VERIFY_BITS(d, 116);
secp256k1_u128_accum_mul(&d, R << 12, secp256k1_u128_to_u64(&c));
VERIFY_BITS_128(&d, 116);
/* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
t4 = d & M; d >>= 52;
t4 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52);
VERIFY_BITS(t4, 52);
VERIFY_BITS(d, 64);
VERIFY_BITS_128(&d, 64);
/* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
tx = (t4 >> 48); t4 &= (M >> 4);
VERIFY_BITS(tx, 4);
VERIFY_BITS(t4, 48);
/* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
c = (uint128_t)a0 * a0;
VERIFY_BITS(c, 112);
secp256k1_u128_mul(&c, a0, a0);
VERIFY_BITS_128(&c, 112);
/* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */
d += (uint128_t)a1 * a4
+ (uint128_t)(a2*2) * a3;
VERIFY_BITS(d, 114);
secp256k1_u128_accum_mul(&d, a1, a4);
secp256k1_u128_accum_mul(&d, a2*2, a3);
VERIFY_BITS_128(&d, 114);
/* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
u0 = d & M; d >>= 52;
u0 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52);
VERIFY_BITS(u0, 52);
VERIFY_BITS(d, 62);
VERIFY_BITS_128(&d, 62);
/* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
/* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
u0 = (u0 << 4) | tx;
VERIFY_BITS(u0, 56);
/* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
c += (uint128_t)u0 * (R >> 4);
VERIFY_BITS(c, 113);
secp256k1_u128_accum_mul(&c, u0, R >> 4);
VERIFY_BITS_128(&c, 113);
/* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
r[0] = c & M; c >>= 52;
r[0] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
VERIFY_BITS(r[0], 52);
VERIFY_BITS(c, 61);
VERIFY_BITS_128(&c, 61);
/* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */
a0 *= 2;
c += (uint128_t)a0 * a1;
VERIFY_BITS(c, 114);
secp256k1_u128_accum_mul(&c, a0, a1);
VERIFY_BITS_128(&c, 114);
/* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */
d += (uint128_t)a2 * a4
+ (uint128_t)a3 * a3;
VERIFY_BITS(d, 114);
secp256k1_u128_accum_mul(&d, a2, a4);
secp256k1_u128_accum_mul(&d, a3, a3);
VERIFY_BITS_128(&d, 114);
/* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
c += (d & M) * R; d >>= 52;
VERIFY_BITS(c, 115);
VERIFY_BITS(d, 62);
secp256k1_u128_accum_mul(&c, secp256k1_u128_to_u64(&d) & M, R); secp256k1_u128_rshift(&d, 52);
VERIFY_BITS_128(&c, 115);
VERIFY_BITS_128(&d, 62);
/* [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
r[1] = c & M; c >>= 52;
r[1] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
VERIFY_BITS(r[1], 52);
VERIFY_BITS(c, 63);
VERIFY_BITS_128(&c, 63);
/* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
c += (uint128_t)a0 * a2
+ (uint128_t)a1 * a1;
VERIFY_BITS(c, 114);
secp256k1_u128_accum_mul(&c, a0, a2);
secp256k1_u128_accum_mul(&c, a1, a1);
VERIFY_BITS_128(&c, 114);
/* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */
d += (uint128_t)a3 * a4;
VERIFY_BITS(d, 114);
secp256k1_u128_accum_mul(&d, a3, a4);
VERIFY_BITS_128(&d, 114);
/* [d 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
c += (uint128_t)R * (uint64_t)d; d >>= 64;
VERIFY_BITS(c, 115);
VERIFY_BITS(d, 50);
secp256k1_u128_accum_mul(&c, R, secp256k1_u128_to_u64(&d)); secp256k1_u128_rshift(&d, 64);
VERIFY_BITS_128(&c, 115);
VERIFY_BITS_128(&d, 50);
/* [(d<<12) 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
r[2] = c & M; c >>= 52;
r[2] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
VERIFY_BITS(r[2], 52);
VERIFY_BITS(c, 63);
VERIFY_BITS_128(&c, 63);
/* [(d<<12) 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
c += (uint128_t)(R << 12) * (uint64_t)d + t3;
VERIFY_BITS(c, 100);
secp256k1_u128_accum_mul(&c, R << 12, secp256k1_u128_to_u64(&d));
secp256k1_u128_accum_u64(&c, t3);
VERIFY_BITS_128(&c, 100);
/* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
r[3] = c & M; c >>= 52;
r[3] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
VERIFY_BITS(r[3], 52);
VERIFY_BITS(c, 48);
VERIFY_BITS_128(&c, 48);
/* [t4+c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
c += t4;
VERIFY_BITS(c, 49);
/* [c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
r[4] = c;
r[4] = secp256k1_u128_to_u64(&c) + t4;
VERIFY_BITS(r[4], 49);
/* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
}

View File

@ -23,7 +23,7 @@ typedef struct {
#define SECP256K1_GE_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1}
/** A group element of the secp256k1 curve, in jacobian coordinates.
* Note: For exhastive test mode, sepc256k1 is replaced by a small subgroup of a different curve.
* Note: For exhastive test mode, secp256k1 is replaced by a small subgroup of a different curve.
*/
typedef struct {
secp256k1_fe x; /* actual X: x/z^2 */
@ -97,6 +97,9 @@ static void secp256k1_gej_set_infinity(secp256k1_gej *r);
/** Set a group element (jacobian) equal to another which is given in affine coordinates. */
static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a);
/** Check two group elements (jacobian) for equality in variable time. */
static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b);
/** Compare the X coordinate of a group element (jacobian). */
static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a);

View File

@ -236,6 +236,13 @@ static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a) {
secp256k1_fe_set_int(&r->z, 1);
}
static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b) {
secp256k1_gej tmp;
secp256k1_gej_neg(&tmp, a);
secp256k1_gej_add_var(&tmp, &tmp, b, NULL);
return secp256k1_gej_is_infinity(&tmp);
}
static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a) {
secp256k1_fe r, r2;
VERIFY_CHECK(!a->infinity);

View File

@ -0,0 +1,85 @@
#ifndef SECP256K1_INT128_H
#define SECP256K1_INT128_H
#include "util.h"
#if defined(SECP256K1_WIDEMUL_INT128)
# if defined(SECP256K1_INT128_NATIVE)
# include "int128_native.h"
# elif defined(SECP256K1_INT128_STRUCT)
# include "int128_struct.h"
# else
# error "Please select int128 implementation"
# endif
/* Construct an unsigned 128-bit value from a high and a low 64-bit value. */
static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo);
/* Multiply two unsigned 64-bit values a and b and write the result to r. */
static SECP256K1_INLINE void secp256k1_u128_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b);
/* Multiply two unsigned 64-bit values a and b and add the result to r.
* The final result is taken modulo 2^128.
*/
static SECP256K1_INLINE void secp256k1_u128_accum_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b);
/* Add an unsigned 64-bit value a to r.
* The final result is taken modulo 2^128.
*/
static SECP256K1_INLINE void secp256k1_u128_accum_u64(secp256k1_uint128 *r, uint64_t a);
/* Unsigned (logical) right shift.
* Non-constant time in n.
*/
static SECP256K1_INLINE void secp256k1_u128_rshift(secp256k1_uint128 *r, unsigned int n);
/* Return the low 64-bits of a 128-bit value as an unsigned 64-bit value. */
static SECP256K1_INLINE uint64_t secp256k1_u128_to_u64(const secp256k1_uint128 *a);
/* Return the high 64-bits of a 128-bit value as an unsigned 64-bit value. */
static SECP256K1_INLINE uint64_t secp256k1_u128_hi_u64(const secp256k1_uint128 *a);
/* Write an unsigned 64-bit value to r. */
static SECP256K1_INLINE void secp256k1_u128_from_u64(secp256k1_uint128 *r, uint64_t a);
/* Tests if r is strictly less than to 2^n.
* n must be strictly less than 128.
*/
static SECP256K1_INLINE int secp256k1_u128_check_bits(const secp256k1_uint128 *r, unsigned int n);
/* Construct an signed 128-bit value from a high and a low 64-bit value. */
static SECP256K1_INLINE void secp256k1_i128_load(secp256k1_int128 *r, int64_t hi, uint64_t lo);
/* Multiply two signed 64-bit values a and b and write the result to r. */
static SECP256K1_INLINE void secp256k1_i128_mul(secp256k1_int128 *r, int64_t a, int64_t b);
/* Multiply two signed 64-bit values a and b and add the result to r.
* Overflow or underflow from the addition is undefined behaviour.
*/
static SECP256K1_INLINE void secp256k1_i128_accum_mul(secp256k1_int128 *r, int64_t a, int64_t b);
/* Compute a*d - b*c from signed 64-bit values and write the result to r. */
static SECP256K1_INLINE void secp256k1_i128_det(secp256k1_int128 *r, int64_t a, int64_t b, int64_t c, int64_t d);
/* Signed (arithmetic) right shift.
* Non-constant time in b.
*/
static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned int b);
/* Return the low 64-bits of a 128-bit value interpreted as an signed 64-bit value. */
static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a);
/* Write a signed 64-bit value to r. */
static SECP256K1_INLINE void secp256k1_i128_from_i64(secp256k1_int128 *r, int64_t a);
/* Compare two 128-bit values for equality. */
static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, const secp256k1_int128 *b);
/* Tests if r is equal to 2^n.
* n must be strictly less than 127.
*/
static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n);
#endif
#endif

View File

@ -0,0 +1,18 @@
#ifndef SECP256K1_INT128_IMPL_H
#define SECP256K1_INT128_IMPL_H
#include "util.h"
#include "int128.h"
#if defined(SECP256K1_WIDEMUL_INT128)
# if defined(SECP256K1_INT128_NATIVE)
# include "int128_native_impl.h"
# elif defined(SECP256K1_INT128_STRUCT)
# include "int128_struct_impl.h"
# else
# error "Please select int128 implementation"
# endif
#endif
#endif

View File

@ -0,0 +1,19 @@
#ifndef SECP256K1_INT128_NATIVE_H
#define SECP256K1_INT128_NATIVE_H
#include <stdint.h>
#include "util.h"
#if !defined(UINT128_MAX) && defined(__SIZEOF_INT128__)
SECP256K1_GNUC_EXT typedef unsigned __int128 uint128_t;
SECP256K1_GNUC_EXT typedef __int128 int128_t;
# define UINT128_MAX ((uint128_t)(-1))
# define INT128_MAX ((int128_t)(UINT128_MAX >> 1))
# define INT128_MIN (-INT128_MAX - 1)
/* No (U)INT128_C macros because compilers providing __int128 do not support 128-bit literals. */
#endif
typedef uint128_t secp256k1_uint128;
typedef int128_t secp256k1_int128;
#endif

View File

@ -0,0 +1,87 @@
#ifndef SECP256K1_INT128_NATIVE_IMPL_H
#define SECP256K1_INT128_NATIVE_IMPL_H
#include "int128.h"
static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo) {
*r = (((uint128_t)hi) << 64) + lo;
}
static SECP256K1_INLINE void secp256k1_u128_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) {
*r = (uint128_t)a * b;
}
static SECP256K1_INLINE void secp256k1_u128_accum_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) {
*r += (uint128_t)a * b;
}
static SECP256K1_INLINE void secp256k1_u128_accum_u64(secp256k1_uint128 *r, uint64_t a) {
*r += a;
}
static SECP256K1_INLINE void secp256k1_u128_rshift(secp256k1_uint128 *r, unsigned int n) {
VERIFY_CHECK(n < 128);
*r >>= n;
}
static SECP256K1_INLINE uint64_t secp256k1_u128_to_u64(const secp256k1_uint128 *a) {
return (uint64_t)(*a);
}
static SECP256K1_INLINE uint64_t secp256k1_u128_hi_u64(const secp256k1_uint128 *a) {
return (uint64_t)(*a >> 64);
}
static SECP256K1_INLINE void secp256k1_u128_from_u64(secp256k1_uint128 *r, uint64_t a) {
*r = a;
}
static SECP256K1_INLINE int secp256k1_u128_check_bits(const secp256k1_uint128 *r, unsigned int n) {
VERIFY_CHECK(n < 128);
return (*r >> n == 0);
}
static SECP256K1_INLINE void secp256k1_i128_load(secp256k1_int128 *r, int64_t hi, uint64_t lo) {
*r = (((uint128_t)(uint64_t)hi) << 64) + lo;
}
static SECP256K1_INLINE void secp256k1_i128_mul(secp256k1_int128 *r, int64_t a, int64_t b) {
*r = (int128_t)a * b;
}
static SECP256K1_INLINE void secp256k1_i128_accum_mul(secp256k1_int128 *r, int64_t a, int64_t b) {
int128_t ab = (int128_t)a * b;
VERIFY_CHECK(0 <= ab ? *r <= INT128_MAX - ab : INT128_MIN - ab <= *r);
*r += ab;
}
static SECP256K1_INLINE void secp256k1_i128_det(secp256k1_int128 *r, int64_t a, int64_t b, int64_t c, int64_t d) {
int128_t ad = (int128_t)a * d;
int128_t bc = (int128_t)b * c;
VERIFY_CHECK(0 <= bc ? INT128_MIN + bc <= ad : ad <= INT128_MAX + bc);
*r = ad - bc;
}
static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned int n) {
VERIFY_CHECK(n < 128);
*r >>= n;
}
static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a) {
return *a;
}
static SECP256K1_INLINE void secp256k1_i128_from_i64(secp256k1_int128 *r, int64_t a) {
*r = a;
}
static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, const secp256k1_int128 *b) {
return *a == *b;
}
static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n) {
VERIFY_CHECK(n < 127);
return (*r == (int128_t)1 << n);
}
#endif

View File

@ -0,0 +1,14 @@
#ifndef SECP256K1_INT128_STRUCT_H
#define SECP256K1_INT128_STRUCT_H
#include <stdint.h>
#include "util.h"
typedef struct {
uint64_t lo;
uint64_t hi;
} secp256k1_uint128;
typedef secp256k1_uint128 secp256k1_int128;
#endif

View File

@ -0,0 +1,192 @@
#ifndef SECP256K1_INT128_STRUCT_IMPL_H
#define SECP256K1_INT128_STRUCT_IMPL_H
#include "int128.h"
#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64)) /* MSVC */
# include <intrin.h>
# if defined(_M_ARM64) || defined(SECP256K1_MSVC_MULH_TEST_OVERRIDE)
/* On ARM64 MSVC, use __(u)mulh for the upper half of 64x64 multiplications.
(Define SECP256K1_MSVC_MULH_TEST_OVERRIDE to test this code path on X64,
which supports both __(u)mulh and _umul128.) */
# if defined(SECP256K1_MSVC_MULH_TEST_OVERRIDE)
# pragma message(__FILE__ ": SECP256K1_MSVC_MULH_TEST_OVERRIDE is defined, forcing use of __(u)mulh.")
# endif
static SECP256K1_INLINE uint64_t secp256k1_umul128(uint64_t a, uint64_t b, uint64_t* hi) {
*hi = __umulh(a, b);
return a * b;
}
static SECP256K1_INLINE int64_t secp256k1_mul128(int64_t a, int64_t b, int64_t* hi) {
*hi = __mulh(a, b);
return (uint64_t)a * (uint64_t)b;
}
# else
/* On x84_64 MSVC, use native _(u)mul128 for 64x64->128 multiplications. */
# define secp256k1_umul128 _umul128
# define secp256k1_mul128 _mul128
# endif
#else
/* On other systems, emulate 64x64->128 multiplications using 32x32->64 multiplications. */
static SECP256K1_INLINE uint64_t secp256k1_umul128(uint64_t a, uint64_t b, uint64_t* hi) {
uint64_t ll = (uint64_t)(uint32_t)a * (uint32_t)b;
uint64_t lh = (uint32_t)a * (b >> 32);
uint64_t hl = (a >> 32) * (uint32_t)b;
uint64_t hh = (a >> 32) * (b >> 32);
uint64_t mid34 = (ll >> 32) + (uint32_t)lh + (uint32_t)hl;
*hi = hh + (lh >> 32) + (hl >> 32) + (mid34 >> 32);
return (mid34 << 32) + (uint32_t)ll;
}
static SECP256K1_INLINE int64_t secp256k1_mul128(int64_t a, int64_t b, int64_t* hi) {
uint64_t ll = (uint64_t)(uint32_t)a * (uint32_t)b;
int64_t lh = (uint32_t)a * (b >> 32);
int64_t hl = (a >> 32) * (uint32_t)b;
int64_t hh = (a >> 32) * (b >> 32);
uint64_t mid34 = (ll >> 32) + (uint32_t)lh + (uint32_t)hl;
*hi = hh + (lh >> 32) + (hl >> 32) + (mid34 >> 32);
return (mid34 << 32) + (uint32_t)ll;
}
#endif
static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo) {
r->hi = hi;
r->lo = lo;
}
static SECP256K1_INLINE void secp256k1_u128_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) {
r->lo = secp256k1_umul128(a, b, &r->hi);
}
static SECP256K1_INLINE void secp256k1_u128_accum_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) {
uint64_t lo, hi;
lo = secp256k1_umul128(a, b, &hi);
r->lo += lo;
r->hi += hi + (r->lo < lo);
}
static SECP256K1_INLINE void secp256k1_u128_accum_u64(secp256k1_uint128 *r, uint64_t a) {
r->lo += a;
r->hi += r->lo < a;
}
/* Unsigned (logical) right shift.
* Non-constant time in n.
*/
static SECP256K1_INLINE void secp256k1_u128_rshift(secp256k1_uint128 *r, unsigned int n) {
VERIFY_CHECK(n < 128);
if (n >= 64) {
r->lo = r->hi >> (n-64);
r->hi = 0;
} else if (n > 0) {
r->lo = ((1U * r->hi) << (64-n)) | r->lo >> n;
r->hi >>= n;
}
}
static SECP256K1_INLINE uint64_t secp256k1_u128_to_u64(const secp256k1_uint128 *a) {
return a->lo;
}
static SECP256K1_INLINE uint64_t secp256k1_u128_hi_u64(const secp256k1_uint128 *a) {
return a->hi;
}
static SECP256K1_INLINE void secp256k1_u128_from_u64(secp256k1_uint128 *r, uint64_t a) {
r->hi = 0;
r->lo = a;
}
static SECP256K1_INLINE int secp256k1_u128_check_bits(const secp256k1_uint128 *r, unsigned int n) {
VERIFY_CHECK(n < 128);
return n >= 64 ? r->hi >> (n - 64) == 0
: r->hi == 0 && r->lo >> n == 0;
}
static SECP256K1_INLINE void secp256k1_i128_load(secp256k1_int128 *r, int64_t hi, uint64_t lo) {
r->hi = hi;
r->lo = lo;
}
static SECP256K1_INLINE void secp256k1_i128_mul(secp256k1_int128 *r, int64_t a, int64_t b) {
int64_t hi;
r->lo = (uint64_t)secp256k1_mul128(a, b, &hi);
r->hi = (uint64_t)hi;
}
static SECP256K1_INLINE void secp256k1_i128_accum_mul(secp256k1_int128 *r, int64_t a, int64_t b) {
int64_t hi;
uint64_t lo = (uint64_t)secp256k1_mul128(a, b, &hi);
r->lo += lo;
hi += r->lo < lo;
/* Verify no overflow.
* If r represents a positive value (the sign bit is not set) and the value we are adding is a positive value (the sign bit is not set),
* then we require that the resulting value also be positive (the sign bit is not set).
* Note that (X <= Y) means (X implies Y) when X and Y are boolean values (i.e. 0 or 1).
*/
VERIFY_CHECK((r->hi <= 0x7fffffffffffffffu && (uint64_t)hi <= 0x7fffffffffffffffu) <= (r->hi + (uint64_t)hi <= 0x7fffffffffffffffu));
/* Verify no underflow.
* If r represents a negative value (the sign bit is set) and the value we are adding is a negative value (the sign bit is set),
* then we require that the resulting value also be negative (the sign bit is set).
*/
VERIFY_CHECK((r->hi > 0x7fffffffffffffffu && (uint64_t)hi > 0x7fffffffffffffffu) <= (r->hi + (uint64_t)hi > 0x7fffffffffffffffu));
r->hi += hi;
}
static SECP256K1_INLINE void secp256k1_i128_dissip_mul(secp256k1_int128 *r, int64_t a, int64_t b) {
int64_t hi;
uint64_t lo = (uint64_t)secp256k1_mul128(a, b, &hi);
hi += r->lo < lo;
/* Verify no overflow.
* If r represents a positive value (the sign bit is not set) and the value we are subtracting is a negative value (the sign bit is set),
* then we require that the resulting value also be positive (the sign bit is not set).
*/
VERIFY_CHECK((r->hi <= 0x7fffffffffffffffu && (uint64_t)hi > 0x7fffffffffffffffu) <= (r->hi - (uint64_t)hi <= 0x7fffffffffffffffu));
/* Verify no underflow.
* If r represents a negative value (the sign bit is set) and the value we are subtracting is a positive value (the sign sign bit is not set),
* then we require that the resulting value also be negative (the sign bit is set).
*/
VERIFY_CHECK((r->hi > 0x7fffffffffffffffu && (uint64_t)hi <= 0x7fffffffffffffffu) <= (r->hi - (uint64_t)hi > 0x7fffffffffffffffu));
r->hi -= hi;
r->lo -= lo;
}
static SECP256K1_INLINE void secp256k1_i128_det(secp256k1_int128 *r, int64_t a, int64_t b, int64_t c, int64_t d) {
secp256k1_i128_mul(r, a, d);
secp256k1_i128_dissip_mul(r, b, c);
}
/* Signed (arithmetic) right shift.
* Non-constant time in n.
*/
static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned int n) {
VERIFY_CHECK(n < 128);
if (n >= 64) {
r->lo = (uint64_t)((int64_t)(r->hi) >> (n-64));
r->hi = (uint64_t)((int64_t)(r->hi) >> 63);
} else if (n > 0) {
r->lo = ((1U * r->hi) << (64-n)) | r->lo >> n;
r->hi = (uint64_t)((int64_t)(r->hi) >> n);
}
}
static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a) {
return (int64_t)a->lo;
}
static SECP256K1_INLINE void secp256k1_i128_from_i64(secp256k1_int128 *r, int64_t a) {
r->hi = (uint64_t)(a >> 63);
r->lo = (uint64_t)a;
}
static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, const secp256k1_int128 *b) {
return a->hi == b->hi && a->lo == b->lo;
}
static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n) {
VERIFY_CHECK(n < 127);
return n >= 64 ? r->hi == (uint64_t)1 << (n - 64) && r->lo == 0
: r->hi == 0 && r->lo == (uint64_t)1 << n;
}
#endif

View File

@ -7,10 +7,9 @@
#ifndef SECP256K1_MODINV64_IMPL_H
#define SECP256K1_MODINV64_IMPL_H
#include "int128.h"
#include "modinv64.h"
#include "util.h"
/* This file implements modular inversion based on the paper "Fast constant-time gcd computation and
* modular inversion" by Daniel J. Bernstein and Bo-Yin Yang.
*
@ -18,6 +17,15 @@
* implementation for N=62, using 62-bit signed limbs represented as int64_t.
*/
/* Data type for transition matrices (see section 3 of explanation).
*
* t = [ u v ]
* [ q r ]
*/
typedef struct {
int64_t u, v, q, r;
} secp256k1_modinv64_trans2x2;
#ifdef VERIFY
/* Helper function to compute the absolute value of an int64_t.
* (we don't use abs/labs/llabs as it depends on the int sizes). */
@ -32,15 +40,17 @@ static const secp256k1_modinv64_signed62 SECP256K1_SIGNED62_ONE = {{1}};
/* Compute a*factor and put it in r. All but the top limb in r will be in range [0,2^62). */
static void secp256k1_modinv64_mul_62(secp256k1_modinv64_signed62 *r, const secp256k1_modinv64_signed62 *a, int alen, int64_t factor) {
const int64_t M62 = (int64_t)(UINT64_MAX >> 2);
int128_t c = 0;
secp256k1_int128 c, d;
int i;
secp256k1_i128_from_i64(&c, 0);
for (i = 0; i < 4; ++i) {
if (i < alen) c += (int128_t)a->v[i] * factor;
r->v[i] = (int64_t)c & M62; c >>= 62;
if (i < alen) secp256k1_i128_accum_mul(&c, a->v[i], factor);
r->v[i] = secp256k1_i128_to_i64(&c) & M62; secp256k1_i128_rshift(&c, 62);
}
if (4 < alen) c += (int128_t)a->v[4] * factor;
VERIFY_CHECK(c == (int64_t)c);
r->v[4] = (int64_t)c;
if (4 < alen) secp256k1_i128_accum_mul(&c, a->v[4], factor);
secp256k1_i128_from_i64(&d, secp256k1_i128_to_i64(&c));
VERIFY_CHECK(secp256k1_i128_eq_var(&c, &d));
r->v[4] = secp256k1_i128_to_i64(&c);
}
/* Return -1 for a<b*factor, 0 for a==b*factor, 1 for a>b*factor. A has alen limbs; b has 5. */
@ -60,6 +70,13 @@ static int secp256k1_modinv64_mul_cmp_62(const secp256k1_modinv64_signed62 *a, i
}
return 0;
}
/* Check if the determinant of t is equal to 1 << n. */
static int secp256k1_modinv64_det_check_pow2(const secp256k1_modinv64_trans2x2 *t, unsigned int n) {
secp256k1_int128 a;
secp256k1_i128_det(&a, t->u, t->v, t->q, t->r);
return secp256k1_i128_check_pow2(&a, n);
}
#endif
/* Take as input a signed62 number in range (-2*modulus,modulus), and add a multiple of the modulus
@ -136,15 +153,6 @@ static void secp256k1_modinv64_normalize_62(secp256k1_modinv64_signed62 *r, int6
#endif
}
/* Data type for transition matrices (see section 3 of explanation).
*
* t = [ u v ]
* [ q r ]
*/
typedef struct {
int64_t u, v, q, r;
} secp256k1_modinv64_trans2x2;
/* Compute the transition matrix and eta for 59 divsteps (where zeta=-(delta+1/2)).
* Note that the transformation matrix is scaled by 2^62 and not 2^59.
*
@ -203,13 +211,15 @@ static int64_t secp256k1_modinv64_divsteps_59(int64_t zeta, uint64_t f0, uint64_
t->v = (int64_t)v;
t->q = (int64_t)q;
t->r = (int64_t)r;
#ifdef VERIFY
/* The determinant of t must be a power of two. This guarantees that multiplication with t
* does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which
* will be divided out again). As each divstep's individual matrix has determinant 2, the
* aggregate of 59 of them will have determinant 2^59. Multiplying with the initial
* 8*identity (which has determinant 2^6) means the overall outputs has determinant
* 2^65. */
VERIFY_CHECK((int128_t)t->u * t->r - (int128_t)t->v * t->q == ((int128_t)1) << 65);
VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 65));
#endif
return zeta;
}
@ -286,11 +296,13 @@ static int64_t secp256k1_modinv64_divsteps_62_var(int64_t eta, uint64_t f0, uint
t->v = (int64_t)v;
t->q = (int64_t)q;
t->r = (int64_t)r;
#ifdef VERIFY
/* The determinant of t must be a power of two. This guarantees that multiplication with t
* does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which
* will be divided out again). As each divstep's individual matrix has determinant 2, the
* aggregate of 62 of them will have determinant 2^62. */
VERIFY_CHECK((int128_t)t->u * t->r - (int128_t)t->v * t->q == ((int128_t)1) << 62);
VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 62));
#endif
return eta;
}
@ -307,7 +319,7 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
const int64_t e0 = e->v[0], e1 = e->v[1], e2 = e->v[2], e3 = e->v[3], e4 = e->v[4];
const int64_t u = t->u, v = t->v, q = t->q, r = t->r;
int64_t md, me, sd, se;
int128_t cd, ce;
secp256k1_int128 cd, ce;
#ifdef VERIFY
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, -2) > 0); /* d > -2*modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, 1) < 0); /* d < modulus */
@ -324,54 +336,64 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
md = (u & sd) + (v & se);
me = (q & sd) + (r & se);
/* Begin computing t*[d,e]. */
cd = (int128_t)u * d0 + (int128_t)v * e0;
ce = (int128_t)q * d0 + (int128_t)r * e0;
secp256k1_i128_mul(&cd, u, d0);
secp256k1_i128_accum_mul(&cd, v, e0);
secp256k1_i128_mul(&ce, q, d0);
secp256k1_i128_accum_mul(&ce, r, e0);
/* Correct md,me so that t*[d,e]+modulus*[md,me] has 62 zero bottom bits. */
md -= (modinfo->modulus_inv62 * (uint64_t)cd + md) & M62;
me -= (modinfo->modulus_inv62 * (uint64_t)ce + me) & M62;
md -= (modinfo->modulus_inv62 * (uint64_t)secp256k1_i128_to_i64(&cd) + md) & M62;
me -= (modinfo->modulus_inv62 * (uint64_t)secp256k1_i128_to_i64(&ce) + me) & M62;
/* Update the beginning of computation for t*[d,e]+modulus*[md,me] now md,me are known. */
cd += (int128_t)modinfo->modulus.v[0] * md;
ce += (int128_t)modinfo->modulus.v[0] * me;
secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[0], md);
secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[0], me);
/* Verify that the low 62 bits of the computation are indeed zero, and then throw them away. */
VERIFY_CHECK(((int64_t)cd & M62) == 0); cd >>= 62;
VERIFY_CHECK(((int64_t)ce & M62) == 0); ce >>= 62;
VERIFY_CHECK((secp256k1_i128_to_i64(&cd) & M62) == 0); secp256k1_i128_rshift(&cd, 62);
VERIFY_CHECK((secp256k1_i128_to_i64(&ce) & M62) == 0); secp256k1_i128_rshift(&ce, 62);
/* Compute limb 1 of t*[d,e]+modulus*[md,me], and store it as output limb 0 (= down shift). */
cd += (int128_t)u * d1 + (int128_t)v * e1;
ce += (int128_t)q * d1 + (int128_t)r * e1;
secp256k1_i128_accum_mul(&cd, u, d1);
secp256k1_i128_accum_mul(&cd, v, e1);
secp256k1_i128_accum_mul(&ce, q, d1);
secp256k1_i128_accum_mul(&ce, r, e1);
if (modinfo->modulus.v[1]) { /* Optimize for the case where limb of modulus is zero. */
cd += (int128_t)modinfo->modulus.v[1] * md;
ce += (int128_t)modinfo->modulus.v[1] * me;
secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[1], md);
secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[1], me);
}
d->v[0] = (int64_t)cd & M62; cd >>= 62;
e->v[0] = (int64_t)ce & M62; ce >>= 62;
d->v[0] = secp256k1_i128_to_i64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
e->v[0] = secp256k1_i128_to_i64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
/* Compute limb 2 of t*[d,e]+modulus*[md,me], and store it as output limb 1. */
cd += (int128_t)u * d2 + (int128_t)v * e2;
ce += (int128_t)q * d2 + (int128_t)r * e2;
secp256k1_i128_accum_mul(&cd, u, d2);
secp256k1_i128_accum_mul(&cd, v, e2);
secp256k1_i128_accum_mul(&ce, q, d2);
secp256k1_i128_accum_mul(&ce, r, e2);
if (modinfo->modulus.v[2]) { /* Optimize for the case where limb of modulus is zero. */
cd += (int128_t)modinfo->modulus.v[2] * md;
ce += (int128_t)modinfo->modulus.v[2] * me;
secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[2], md);
secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[2], me);
}
d->v[1] = (int64_t)cd & M62; cd >>= 62;
e->v[1] = (int64_t)ce & M62; ce >>= 62;
d->v[1] = secp256k1_i128_to_i64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
e->v[1] = secp256k1_i128_to_i64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
/* Compute limb 3 of t*[d,e]+modulus*[md,me], and store it as output limb 2. */
cd += (int128_t)u * d3 + (int128_t)v * e3;
ce += (int128_t)q * d3 + (int128_t)r * e3;
secp256k1_i128_accum_mul(&cd, u, d3);
secp256k1_i128_accum_mul(&cd, v, e3);
secp256k1_i128_accum_mul(&ce, q, d3);
secp256k1_i128_accum_mul(&ce, r, e3);
if (modinfo->modulus.v[3]) { /* Optimize for the case where limb of modulus is zero. */
cd += (int128_t)modinfo->modulus.v[3] * md;
ce += (int128_t)modinfo->modulus.v[3] * me;
secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[3], md);
secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[3], me);
}
d->v[2] = (int64_t)cd & M62; cd >>= 62;
e->v[2] = (int64_t)ce & M62; ce >>= 62;
d->v[2] = secp256k1_i128_to_i64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
e->v[2] = secp256k1_i128_to_i64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
/* Compute limb 4 of t*[d,e]+modulus*[md,me], and store it as output limb 3. */
cd += (int128_t)u * d4 + (int128_t)v * e4;
ce += (int128_t)q * d4 + (int128_t)r * e4;
cd += (int128_t)modinfo->modulus.v[4] * md;
ce += (int128_t)modinfo->modulus.v[4] * me;
d->v[3] = (int64_t)cd & M62; cd >>= 62;
e->v[3] = (int64_t)ce & M62; ce >>= 62;
secp256k1_i128_accum_mul(&cd, u, d4);
secp256k1_i128_accum_mul(&cd, v, e4);
secp256k1_i128_accum_mul(&ce, q, d4);
secp256k1_i128_accum_mul(&ce, r, e4);
secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[4], md);
secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[4], me);
d->v[3] = secp256k1_i128_to_i64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
e->v[3] = secp256k1_i128_to_i64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
/* What remains is limb 5 of t*[d,e]+modulus*[md,me]; store it as output limb 4. */
d->v[4] = (int64_t)cd;
e->v[4] = (int64_t)ce;
d->v[4] = secp256k1_i128_to_i64(&cd);
e->v[4] = secp256k1_i128_to_i64(&ce);
#ifdef VERIFY
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, -2) > 0); /* d > -2*modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, 1) < 0); /* d < modulus */
@ -389,36 +411,46 @@ static void secp256k1_modinv64_update_fg_62(secp256k1_modinv64_signed62 *f, secp
const int64_t f0 = f->v[0], f1 = f->v[1], f2 = f->v[2], f3 = f->v[3], f4 = f->v[4];
const int64_t g0 = g->v[0], g1 = g->v[1], g2 = g->v[2], g3 = g->v[3], g4 = g->v[4];
const int64_t u = t->u, v = t->v, q = t->q, r = t->r;
int128_t cf, cg;
secp256k1_int128 cf, cg;
/* Start computing t*[f,g]. */
cf = (int128_t)u * f0 + (int128_t)v * g0;
cg = (int128_t)q * f0 + (int128_t)r * g0;
secp256k1_i128_mul(&cf, u, f0);
secp256k1_i128_accum_mul(&cf, v, g0);
secp256k1_i128_mul(&cg, q, f0);
secp256k1_i128_accum_mul(&cg, r, g0);
/* Verify that the bottom 62 bits of the result are zero, and then throw them away. */
VERIFY_CHECK(((int64_t)cf & M62) == 0); cf >>= 62;
VERIFY_CHECK(((int64_t)cg & M62) == 0); cg >>= 62;
VERIFY_CHECK((secp256k1_i128_to_i64(&cf) & M62) == 0); secp256k1_i128_rshift(&cf, 62);
VERIFY_CHECK((secp256k1_i128_to_i64(&cg) & M62) == 0); secp256k1_i128_rshift(&cg, 62);
/* Compute limb 1 of t*[f,g], and store it as output limb 0 (= down shift). */
cf += (int128_t)u * f1 + (int128_t)v * g1;
cg += (int128_t)q * f1 + (int128_t)r * g1;
f->v[0] = (int64_t)cf & M62; cf >>= 62;
g->v[0] = (int64_t)cg & M62; cg >>= 62;
secp256k1_i128_accum_mul(&cf, u, f1);
secp256k1_i128_accum_mul(&cf, v, g1);
secp256k1_i128_accum_mul(&cg, q, f1);
secp256k1_i128_accum_mul(&cg, r, g1);
f->v[0] = secp256k1_i128_to_i64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
g->v[0] = secp256k1_i128_to_i64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
/* Compute limb 2 of t*[f,g], and store it as output limb 1. */
cf += (int128_t)u * f2 + (int128_t)v * g2;
cg += (int128_t)q * f2 + (int128_t)r * g2;
f->v[1] = (int64_t)cf & M62; cf >>= 62;
g->v[1] = (int64_t)cg & M62; cg >>= 62;
secp256k1_i128_accum_mul(&cf, u, f2);
secp256k1_i128_accum_mul(&cf, v, g2);
secp256k1_i128_accum_mul(&cg, q, f2);
secp256k1_i128_accum_mul(&cg, r, g2);
f->v[1] = secp256k1_i128_to_i64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
g->v[1] = secp256k1_i128_to_i64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
/* Compute limb 3 of t*[f,g], and store it as output limb 2. */
cf += (int128_t)u * f3 + (int128_t)v * g3;
cg += (int128_t)q * f3 + (int128_t)r * g3;
f->v[2] = (int64_t)cf & M62; cf >>= 62;
g->v[2] = (int64_t)cg & M62; cg >>= 62;
secp256k1_i128_accum_mul(&cf, u, f3);
secp256k1_i128_accum_mul(&cf, v, g3);
secp256k1_i128_accum_mul(&cg, q, f3);
secp256k1_i128_accum_mul(&cg, r, g3);
f->v[2] = secp256k1_i128_to_i64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
g->v[2] = secp256k1_i128_to_i64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
/* Compute limb 4 of t*[f,g], and store it as output limb 3. */
cf += (int128_t)u * f4 + (int128_t)v * g4;
cg += (int128_t)q * f4 + (int128_t)r * g4;
f->v[3] = (int64_t)cf & M62; cf >>= 62;
g->v[3] = (int64_t)cg & M62; cg >>= 62;
secp256k1_i128_accum_mul(&cf, u, f4);
secp256k1_i128_accum_mul(&cf, v, g4);
secp256k1_i128_accum_mul(&cg, q, f4);
secp256k1_i128_accum_mul(&cg, r, g4);
f->v[3] = secp256k1_i128_to_i64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
g->v[3] = secp256k1_i128_to_i64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
/* What remains is limb 5 of t*[f,g]; store it as output limb 4. */
f->v[4] = (int64_t)cf;
g->v[4] = (int64_t)cg;
f->v[4] = secp256k1_i128_to_i64(&cf);
g->v[4] = secp256k1_i128_to_i64(&cg);
}
/* Compute (t/2^62) * [f, g], where t is a transition matrix for 62 divsteps.
@ -431,30 +463,34 @@ static void secp256k1_modinv64_update_fg_62_var(int len, secp256k1_modinv64_sign
const int64_t M62 = (int64_t)(UINT64_MAX >> 2);
const int64_t u = t->u, v = t->v, q = t->q, r = t->r;
int64_t fi, gi;
int128_t cf, cg;
secp256k1_int128 cf, cg;
int i;
VERIFY_CHECK(len > 0);
/* Start computing t*[f,g]. */
fi = f->v[0];
gi = g->v[0];
cf = (int128_t)u * fi + (int128_t)v * gi;
cg = (int128_t)q * fi + (int128_t)r * gi;
secp256k1_i128_mul(&cf, u, fi);
secp256k1_i128_accum_mul(&cf, v, gi);
secp256k1_i128_mul(&cg, q, fi);
secp256k1_i128_accum_mul(&cg, r, gi);
/* Verify that the bottom 62 bits of the result are zero, and then throw them away. */
VERIFY_CHECK(((int64_t)cf & M62) == 0); cf >>= 62;
VERIFY_CHECK(((int64_t)cg & M62) == 0); cg >>= 62;
VERIFY_CHECK((secp256k1_i128_to_i64(&cf) & M62) == 0); secp256k1_i128_rshift(&cf, 62);
VERIFY_CHECK((secp256k1_i128_to_i64(&cg) & M62) == 0); secp256k1_i128_rshift(&cg, 62);
/* Now iteratively compute limb i=1..len of t*[f,g], and store them in output limb i-1 (shifting
* down by 62 bits). */
for (i = 1; i < len; ++i) {
fi = f->v[i];
gi = g->v[i];
cf += (int128_t)u * fi + (int128_t)v * gi;
cg += (int128_t)q * fi + (int128_t)r * gi;
f->v[i - 1] = (int64_t)cf & M62; cf >>= 62;
g->v[i - 1] = (int64_t)cg & M62; cg >>= 62;
secp256k1_i128_accum_mul(&cf, u, fi);
secp256k1_i128_accum_mul(&cf, v, gi);
secp256k1_i128_accum_mul(&cg, q, fi);
secp256k1_i128_accum_mul(&cg, r, gi);
f->v[i - 1] = secp256k1_i128_to_i64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
g->v[i - 1] = secp256k1_i128_to_i64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
}
/* What remains is limb (len) of t*[f,g]; store it as output limb (len-1). */
f->v[len - 1] = (int64_t)cf;
g->v[len - 1] = (int64_t)cg;
f->v[len - 1] = secp256k1_i128_to_i64(&cf);
g->v[len - 1] = secp256k1_i128_to_i64(&cg);
}
/* Compute the inverse of x modulo modinfo->modulus, and replace x with it (constant time in x). */

View File

@ -7,7 +7,7 @@
#ifndef SECP256K1_MODULE_ECDH_BENCH_H
#define SECP256K1_MODULE_ECDH_BENCH_H
#include "../include/secp256k1_ecdh.h"
#include "../../../include/secp256k1_ecdh.h"
typedef struct {
secp256k1_context *ctx;

View File

@ -26,7 +26,7 @@ int ecdh_hash_function_custom(unsigned char *output, const unsigned char *x, con
void test_ecdh_api(void) {
/* Setup context that just counts errors */
secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
secp256k1_pubkey point;
unsigned char res[32];
unsigned char s_one[32] = { 0 };

View File

@ -7,8 +7,8 @@
#ifndef SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_H
#define SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_H
#include "src/modules/extrakeys/main_impl.h"
#include "../../../include/secp256k1_extrakeys.h"
#include "main_impl.h"
static void test_exhaustive_extrakeys(const secp256k1_context *ctx, const secp256k1_ge* group) {
secp256k1_keypair keypair[EXHAUSTIVE_TEST_ORDER - 1];

View File

@ -9,11 +9,9 @@
#include "../../../include/secp256k1_extrakeys.h"
static secp256k1_context* api_test_context(int flags, int *ecount) {
secp256k1_context *ctx0 = secp256k1_context_create(flags);
static void set_counting_callbacks(secp256k1_context *ctx0, int *ecount) {
secp256k1_context_set_error_callback(ctx0, counting_illegal_callback_fn, ecount);
secp256k1_context_set_illegal_callback(ctx0, counting_illegal_callback_fn, ecount);
return ctx0;
}
void test_xonly_pubkey(void) {
@ -31,28 +29,25 @@ void test_xonly_pubkey(void) {
int i;
int ecount;
secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount);
secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount);
set_counting_callbacks(ctx, &ecount);
secp256k1_testrand256(sk);
memset(ones32, 0xFF, 32);
secp256k1_testrand256(xy_sk);
CHECK(secp256k1_ec_pubkey_create(sign, &pk, sk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 1);
CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk) == 1);
/* Test xonly_pubkey_from_pubkey */
ecount = 0;
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(sign, &xonly_pk, &pk_parity, &pk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(verify, &xonly_pk, &pk_parity, &pk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, NULL, &pk_parity, &pk) == 0);
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, NULL, &pk_parity, &pk) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, NULL, &pk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, NULL) == 0);
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, NULL, &pk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, NULL) == 0);
CHECK(ecount == 2);
memset(&pk, 0, sizeof(pk));
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 0);
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk) == 0);
CHECK(ecount == 3);
/* Choose a secret key such that the resulting pubkey and xonly_pubkey match. */
@ -78,9 +73,9 @@ void test_xonly_pubkey(void) {
/* Test xonly_pubkey_serialize and xonly_pubkey_parse */
ecount = 0;
CHECK(secp256k1_xonly_pubkey_serialize(none, NULL, &xonly_pk) == 0);
CHECK(secp256k1_xonly_pubkey_serialize(ctx, NULL, &xonly_pk) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_xonly_pubkey_serialize(none, buf32, NULL) == 0);
CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, NULL) == 0);
CHECK(secp256k1_memcmp_var(buf32, zeros64, 32) == 0);
CHECK(ecount == 2);
{
@ -88,20 +83,20 @@ void test_xonly_pubkey(void) {
* special casing. */
secp256k1_xonly_pubkey pk_tmp;
memset(&pk_tmp, 0, sizeof(pk_tmp));
CHECK(secp256k1_xonly_pubkey_serialize(none, buf32, &pk_tmp) == 0);
CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, &pk_tmp) == 0);
}
/* pubkey_load called illegal callback */
CHECK(ecount == 3);
CHECK(secp256k1_xonly_pubkey_serialize(none, buf32, &xonly_pk) == 1);
CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, &xonly_pk) == 1);
ecount = 0;
CHECK(secp256k1_xonly_pubkey_parse(none, NULL, buf32) == 0);
CHECK(secp256k1_xonly_pubkey_parse(ctx, NULL, buf32) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_xonly_pubkey_parse(none, &xonly_pk, NULL) == 0);
CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk, NULL) == 0);
CHECK(ecount == 2);
/* Serialization and parse roundtrip */
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, NULL, &pk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, NULL, &pk) == 1);
CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, &xonly_pk) == 1);
CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk_tmp, buf32) == 1);
CHECK(secp256k1_memcmp_var(&xonly_pk, &xonly_pk_tmp, sizeof(xonly_pk)) == 0);
@ -109,11 +104,11 @@ void test_xonly_pubkey(void) {
/* Test parsing invalid field elements */
memset(&xonly_pk, 1, sizeof(xonly_pk));
/* Overflowing field element */
CHECK(secp256k1_xonly_pubkey_parse(none, &xonly_pk, ones32) == 0);
CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk, ones32) == 0);
CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0);
memset(&xonly_pk, 1, sizeof(xonly_pk));
/* There's no point with x-coordinate 0 on secp256k1 */
CHECK(secp256k1_xonly_pubkey_parse(none, &xonly_pk, zeros64) == 0);
CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk, zeros64) == 0);
CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0);
/* If a random 32-byte string can not be parsed with ec_pubkey_parse
* (because interpreted as X coordinate it does not correspond to a point on
@ -131,10 +126,6 @@ void test_xonly_pubkey(void) {
}
}
CHECK(ecount == 2);
secp256k1_context_destroy(none);
secp256k1_context_destroy(sign);
secp256k1_context_destroy(verify);
}
void test_xonly_pubkey_comparison(void) {
@ -149,29 +140,28 @@ void test_xonly_pubkey_comparison(void) {
secp256k1_xonly_pubkey pk1;
secp256k1_xonly_pubkey pk2;
int ecount = 0;
secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
CHECK(secp256k1_xonly_pubkey_parse(none, &pk1, pk1_ser) == 1);
CHECK(secp256k1_xonly_pubkey_parse(none, &pk2, pk2_ser) == 1);
set_counting_callbacks(ctx, &ecount);
CHECK(secp256k1_xonly_pubkey_cmp(none, NULL, &pk2) < 0);
CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk1, pk1_ser) == 1);
CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk2, pk2_ser) == 1);
CHECK(secp256k1_xonly_pubkey_cmp(ctx, NULL, &pk2) < 0);
CHECK(ecount == 1);
CHECK(secp256k1_xonly_pubkey_cmp(none, &pk1, NULL) > 0);
CHECK(secp256k1_xonly_pubkey_cmp(ctx, &pk1, NULL) > 0);
CHECK(ecount == 2);
CHECK(secp256k1_xonly_pubkey_cmp(none, &pk1, &pk2) < 0);
CHECK(secp256k1_xonly_pubkey_cmp(none, &pk2, &pk1) > 0);
CHECK(secp256k1_xonly_pubkey_cmp(none, &pk1, &pk1) == 0);
CHECK(secp256k1_xonly_pubkey_cmp(none, &pk2, &pk2) == 0);
CHECK(secp256k1_xonly_pubkey_cmp(ctx, &pk1, &pk2) < 0);
CHECK(secp256k1_xonly_pubkey_cmp(ctx, &pk2, &pk1) > 0);
CHECK(secp256k1_xonly_pubkey_cmp(ctx, &pk1, &pk1) == 0);
CHECK(secp256k1_xonly_pubkey_cmp(ctx, &pk2, &pk2) == 0);
CHECK(ecount == 2);
memset(&pk1, 0, sizeof(pk1)); /* illegal pubkey */
CHECK(secp256k1_xonly_pubkey_cmp(none, &pk1, &pk2) < 0);
CHECK(secp256k1_xonly_pubkey_cmp(ctx, &pk1, &pk2) < 0);
CHECK(ecount == 3);
CHECK(secp256k1_xonly_pubkey_cmp(none, &pk1, &pk1) == 0);
CHECK(secp256k1_xonly_pubkey_cmp(ctx, &pk1, &pk1) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_xonly_pubkey_cmp(none, &pk2, &pk1) > 0);
CHECK(secp256k1_xonly_pubkey_cmp(ctx, &pk2, &pk1) > 0);
CHECK(ecount == 6);
secp256k1_context_destroy(none);
}
void test_xonly_pubkey_tweak(void) {
@ -186,39 +176,38 @@ void test_xonly_pubkey_tweak(void) {
int i;
int ecount;
secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount);
secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount);
set_counting_callbacks(ctx, &ecount);
memset(overflows, 0xff, sizeof(overflows));
secp256k1_testrand256(tweak);
secp256k1_testrand256(sk);
CHECK(secp256k1_ec_pubkey_create(ctx, &internal_pk, sk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &internal_xonly_pk, &pk_parity, &internal_pk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &internal_xonly_pk, &pk_parity, &internal_pk) == 1);
ecount = 0;
CHECK(secp256k1_xonly_pubkey_tweak_add(none, &output_pk, &internal_xonly_pk, tweak) == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, tweak) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_xonly_pubkey_tweak_add(sign, &output_pk, &internal_xonly_pk, tweak) == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, tweak) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add(verify, NULL, &internal_xonly_pk, tweak) == 0);
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, tweak) == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, NULL, &internal_xonly_pk, tweak) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, NULL, tweak) == 0);
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, NULL, tweak) == 0);
CHECK(ecount == 2);
/* NULL internal_xonly_pk zeroes the output_pk */
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, NULL) == 0);
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, NULL) == 0);
CHECK(ecount == 3);
/* NULL tweak zeroes the output_pk */
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
/* Invalid tweak zeroes the output_pk */
CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, overflows) == 0);
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, overflows) == 0);
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
/* A zero tweak is fine */
CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, zeros64) == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, zeros64) == 1);
/* Fails if the resulting key was infinity */
for (i = 0; i < count; i++) {
@ -228,8 +217,8 @@ void test_xonly_pubkey_tweak(void) {
secp256k1_scalar_set_b32(&scalar_tweak, sk, NULL);
secp256k1_scalar_negate(&scalar_tweak, &scalar_tweak);
secp256k1_scalar_get_b32(tweak, &scalar_tweak);
CHECK((secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, sk) == 0)
|| (secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 0));
CHECK((secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, sk) == 0)
|| (secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, tweak) == 0));
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
}
@ -237,13 +226,9 @@ void test_xonly_pubkey_tweak(void) {
memset(&internal_xonly_pk, 0, sizeof(internal_xonly_pk));
secp256k1_testrand256(tweak);
ecount = 0;
CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 0);
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, tweak) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
secp256k1_context_destroy(none);
secp256k1_context_destroy(sign);
secp256k1_context_destroy(verify);
}
void test_xonly_pubkey_tweak_check(void) {
@ -260,33 +245,32 @@ void test_xonly_pubkey_tweak_check(void) {
unsigned char tweak[32];
int ecount;
secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount);
secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount);
set_counting_callbacks(ctx, &ecount);
memset(overflows, 0xff, sizeof(overflows));
secp256k1_testrand256(tweak);
secp256k1_testrand256(sk);
CHECK(secp256k1_ec_pubkey_create(ctx, &internal_pk, sk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &internal_xonly_pk, &pk_parity, &internal_pk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &internal_xonly_pk, &pk_parity, &internal_pk) == 1);
ecount = 0;
CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(verify, &output_xonly_pk, &pk_parity, &output_pk) == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, tweak) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &output_xonly_pk, &pk_parity, &output_pk) == 1);
CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, &output_xonly_pk) == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(none, buf32, pk_parity, &internal_xonly_pk, tweak) == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, buf32, pk_parity, &internal_xonly_pk, tweak) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(sign, buf32, pk_parity, &internal_xonly_pk, tweak) == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, buf32, pk_parity, &internal_xonly_pk, tweak) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, buf32, pk_parity, &internal_xonly_pk, tweak) == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, NULL, pk_parity, &internal_xonly_pk, tweak) == 0);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, buf32, pk_parity, &internal_xonly_pk, tweak) == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, NULL, pk_parity, &internal_xonly_pk, tweak) == 0);
CHECK(ecount == 1);
/* invalid pk_parity value */
CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, buf32, 2, &internal_xonly_pk, tweak) == 0);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, buf32, 2, &internal_xonly_pk, tweak) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, buf32, pk_parity, NULL, tweak) == 0);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, buf32, pk_parity, NULL, tweak) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, buf32, pk_parity, &internal_xonly_pk, NULL) == 0);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, buf32, pk_parity, &internal_xonly_pk, NULL) == 0);
CHECK(ecount == 3);
memset(tweak, 1, sizeof(tweak));
@ -307,10 +291,6 @@ void test_xonly_pubkey_tweak_check(void) {
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, overflows) == 0);
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
CHECK(ecount == 3);
secp256k1_context_destroy(none);
secp256k1_context_destroy(sign);
secp256k1_context_destroy(verify);
}
/* Starts with an initial pubkey and recursively creates N_PUBKEYS - 1
@ -356,12 +336,10 @@ void test_keypair(void) {
secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp;
int pk_parity, pk_parity_tmp;
int ecount;
secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount);
secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount);
secp256k1_context *sttc = secp256k1_context_clone(secp256k1_context_no_precomp);
secp256k1_context_set_error_callback(sttc, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(sttc, counting_illegal_callback_fn, &ecount);
secp256k1_context *sttc = secp256k1_context_clone(secp256k1_context_static);
set_counting_callbacks(ctx, &ecount);
set_counting_callbacks(sttc, &ecount);
CHECK(sizeof(zeros96) == sizeof(keypair));
memset(overflows, 0xFF, sizeof(overflows));
@ -369,75 +347,75 @@ void test_keypair(void) {
/* Test keypair_create */
ecount = 0;
secp256k1_testrand256(sk);
CHECK(secp256k1_keypair_create(none, &keypair, sk) == 1);
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) != 0);
CHECK(ecount == 0);
CHECK(secp256k1_keypair_create(verify, &keypair, sk) == 1);
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) != 0);
CHECK(ecount == 0);
CHECK(secp256k1_keypair_create(sign, NULL, sk) == 0);
CHECK(secp256k1_keypair_create(ctx, NULL, sk) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_keypair_create(sign, &keypair, NULL) == 0);
CHECK(secp256k1_keypair_create(ctx, &keypair, NULL) == 0);
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_keypair_create(sign, &keypair, sk) == 1);
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
CHECK(ecount == 2);
CHECK(secp256k1_keypair_create(sttc, &keypair, sk) == 0);
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0);
CHECK(ecount == 3);
/* Invalid secret key */
CHECK(secp256k1_keypair_create(sign, &keypair, zeros96) == 0);
CHECK(secp256k1_keypair_create(ctx, &keypair, zeros96) == 0);
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0);
CHECK(secp256k1_keypair_create(sign, &keypair, overflows) == 0);
CHECK(secp256k1_keypair_create(ctx, &keypair, overflows) == 0);
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0);
/* Test keypair_pub */
ecount = 0;
secp256k1_testrand256(sk);
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
CHECK(secp256k1_keypair_pub(none, &pk, &keypair) == 1);
CHECK(secp256k1_keypair_pub(none, NULL, &keypair) == 0);
CHECK(secp256k1_keypair_pub(ctx, &pk, &keypair) == 1);
CHECK(secp256k1_keypair_pub(ctx, NULL, &keypair) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_keypair_pub(none, &pk, NULL) == 0);
CHECK(secp256k1_keypair_pub(ctx, &pk, NULL) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_memcmp_var(zeros96, &pk, sizeof(pk)) == 0);
/* Using an invalid keypair is fine for keypair_pub */
memset(&keypair, 0, sizeof(keypair));
CHECK(secp256k1_keypair_pub(none, &pk, &keypair) == 1);
CHECK(secp256k1_keypair_pub(ctx, &pk, &keypair) == 1);
CHECK(secp256k1_memcmp_var(zeros96, &pk, sizeof(pk)) == 0);
/* keypair holds the same pubkey as pubkey_create */
CHECK(secp256k1_ec_pubkey_create(sign, &pk, sk) == 1);
CHECK(secp256k1_keypair_create(sign, &keypair, sk) == 1);
CHECK(secp256k1_keypair_pub(none, &pk_tmp, &keypair) == 1);
CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sk) == 1);
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
CHECK(secp256k1_keypair_pub(ctx, &pk_tmp, &keypair) == 1);
CHECK(secp256k1_memcmp_var(&pk, &pk_tmp, sizeof(pk)) == 0);
/** Test keypair_xonly_pub **/
ecount = 0;
secp256k1_testrand256(sk);
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, &keypair) == 1);
CHECK(secp256k1_keypair_xonly_pub(none, NULL, &pk_parity, &keypair) == 0);
CHECK(secp256k1_keypair_xonly_pub(ctx, &xonly_pk, &pk_parity, &keypair) == 1);
CHECK(secp256k1_keypair_xonly_pub(ctx, NULL, &pk_parity, &keypair) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, NULL, &keypair) == 1);
CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, NULL) == 0);
CHECK(secp256k1_keypair_xonly_pub(ctx, &xonly_pk, NULL, &keypair) == 1);
CHECK(secp256k1_keypair_xonly_pub(ctx, &xonly_pk, &pk_parity, NULL) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0);
/* Using an invalid keypair will set the xonly_pk to 0 (first reset
* xonly_pk). */
CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, &keypair) == 1);
CHECK(secp256k1_keypair_xonly_pub(ctx, &xonly_pk, &pk_parity, &keypair) == 1);
memset(&keypair, 0, sizeof(keypair));
CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, &keypair) == 0);
CHECK(secp256k1_keypair_xonly_pub(ctx, &xonly_pk, &pk_parity, &keypair) == 0);
CHECK(secp256k1_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0);
CHECK(ecount == 3);
/** keypair holds the same xonly pubkey as pubkey_create **/
CHECK(secp256k1_ec_pubkey_create(sign, &pk, sk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 1);
CHECK(secp256k1_keypair_create(sign, &keypair, sk) == 1);
CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk_tmp, &pk_parity_tmp, &keypair) == 1);
CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk) == 1);
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
CHECK(secp256k1_keypair_xonly_pub(ctx, &xonly_pk_tmp, &pk_parity_tmp, &keypair) == 1);
CHECK(secp256k1_memcmp_var(&xonly_pk, &xonly_pk_tmp, sizeof(pk)) == 0);
CHECK(pk_parity == pk_parity_tmp);
@ -445,27 +423,23 @@ void test_keypair(void) {
ecount = 0;
secp256k1_testrand256(sk);
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
CHECK(secp256k1_keypair_sec(none, sk_tmp, &keypair) == 1);
CHECK(secp256k1_keypair_sec(none, NULL, &keypair) == 0);
CHECK(secp256k1_keypair_sec(ctx, sk_tmp, &keypair) == 1);
CHECK(secp256k1_keypair_sec(ctx, NULL, &keypair) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_keypair_sec(none, sk_tmp, NULL) == 0);
CHECK(secp256k1_keypair_sec(ctx, sk_tmp, NULL) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0);
/* keypair returns the same seckey it got */
CHECK(secp256k1_keypair_create(sign, &keypair, sk) == 1);
CHECK(secp256k1_keypair_sec(none, sk_tmp, &keypair) == 1);
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
CHECK(secp256k1_keypair_sec(ctx, sk_tmp, &keypair) == 1);
CHECK(secp256k1_memcmp_var(sk, sk_tmp, sizeof(sk_tmp)) == 0);
/* Using an invalid keypair is fine for keypair_seckey */
memset(&keypair, 0, sizeof(keypair));
CHECK(secp256k1_keypair_sec(none, sk_tmp, &keypair) == 1);
CHECK(secp256k1_keypair_sec(ctx, sk_tmp, &keypair) == 1);
CHECK(secp256k1_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0);
secp256k1_context_destroy(none);
secp256k1_context_destroy(sign);
secp256k1_context_destroy(verify);
secp256k1_context_destroy(sttc);
}
@ -477,9 +451,8 @@ void test_keypair_add(void) {
unsigned char tweak[32];
int i;
int ecount = 0;
secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount);
secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount);
set_counting_callbacks(ctx, &ecount);
CHECK(sizeof(zeros96) == sizeof(keypair));
secp256k1_testrand256(sk);
@ -487,14 +460,14 @@ void test_keypair_add(void) {
memset(overflows, 0xFF, 32);
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
CHECK(secp256k1_keypair_xonly_tweak_add(none, &keypair, tweak) == 1);
CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, tweak) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_keypair_xonly_tweak_add(sign, &keypair, tweak) == 1);
CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, tweak) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, tweak) == 1);
CHECK(secp256k1_keypair_xonly_tweak_add(verify, NULL, tweak) == 0);
CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, tweak) == 1);
CHECK(secp256k1_keypair_xonly_tweak_add(ctx, NULL, tweak) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, NULL) == 0);
CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, NULL) == 0);
CHECK(ecount == 2);
/* This does not set the keypair to zeroes */
CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) != 0);
@ -530,18 +503,18 @@ void test_keypair_add(void) {
memset(&keypair, 0, sizeof(keypair));
secp256k1_testrand256(tweak);
ecount = 0;
CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, tweak) == 0);
CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, tweak) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0);
/* Only seckey part of keypair invalid */
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
memset(&keypair, 0, 32);
CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, tweak) == 0);
CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, tweak) == 0);
CHECK(ecount == 2);
/* Only pubkey part of keypair invalid */
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
memset(&keypair.data[32], 0, 64);
CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, tweak) == 0);
CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, tweak) == 0);
CHECK(ecount == 3);
/* Check that the keypair_tweak_add implementation is correct */
@ -570,13 +543,10 @@ void test_keypair_add(void) {
CHECK(secp256k1_memcmp_var(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0);
/* Check that the secret key in the keypair is tweaked correctly */
CHECK(secp256k1_keypair_sec(none, sk32, &keypair) == 1);
CHECK(secp256k1_keypair_sec(ctx, sk32, &keypair) == 1);
CHECK(secp256k1_ec_pubkey_create(ctx, &output_pk_expected, sk32) == 1);
CHECK(secp256k1_memcmp_var(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0);
}
secp256k1_context_destroy(none);
secp256k1_context_destroy(sign);
secp256k1_context_destroy(verify);
}
void run_extrakeys_tests(void) {

View File

@ -7,7 +7,7 @@
#ifndef SECP256K1_MODULE_RECOVERY_BENCH_H
#define SECP256K1_MODULE_RECOVERY_BENCH_H
#include "../include/secp256k1_recovery.h"
#include "../../../include/secp256k1_recovery.h"
typedef struct {
secp256k1_context *ctx;
@ -52,7 +52,7 @@ void run_recovery_bench(int iters, int argc, char** argv) {
bench_recover_data data;
int d = argc == 1;
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "recover") || have_flag(argc, argv, "ecdsa_recover")) run_benchmark("ecdsa_recover", bench_recover, bench_recover_setup, NULL, &data, 10, iters);

View File

@ -7,7 +7,7 @@
#ifndef SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H
#define SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H
#include "src/modules/recovery/main_impl.h"
#include "main_impl.h"
#include "../../../include/secp256k1_recovery.h"
void test_exhaustive_recovery_sign(const secp256k1_context *ctx, const secp256k1_ge *group) {

View File

@ -30,11 +30,7 @@ static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned c
void test_ecdsa_recovery_api(void) {
/* Setup contexts that just count errors */
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
secp256k1_context *sttc = secp256k1_context_clone(secp256k1_context_no_precomp);
secp256k1_context *sttc = secp256k1_context_clone(secp256k1_context_static);
secp256k1_pubkey pubkey;
secp256k1_pubkey recpubkey;
secp256k1_ecdsa_signature normal_sig;
@ -50,15 +46,9 @@ void test_ecdsa_recovery_api(void) {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_error_callback(both, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_error_callback(ctx, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_error_callback(sttc, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(sttc, counting_illegal_callback_fn, &ecount);
/* Construct and verify corresponding public key. */
@ -67,89 +57,73 @@ void test_ecdsa_recovery_api(void) {
/* Check bad contexts and NULLs for signing */
ecount = 0;
CHECK(secp256k1_ecdsa_sign_recoverable(none, &recsig, message, privkey, NULL, NULL) == 1);
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &recsig, message, privkey, NULL, NULL) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_ecdsa_sign_recoverable(sign, &recsig, message, privkey, NULL, NULL) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_ecdsa_sign_recoverable(vrfy, &recsig, message, privkey, NULL, NULL) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_ecdsa_sign_recoverable(both, NULL, message, privkey, NULL, NULL) == 0);
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, NULL, message, privkey, NULL, NULL) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, NULL, privkey, NULL, NULL) == 0);
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &recsig, NULL, privkey, NULL, NULL) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, NULL, NULL, NULL) == 0);
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &recsig, message, NULL, NULL, NULL) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_ecdsa_sign_recoverable(sttc, &recsig, message, privkey, NULL, NULL) == 0);
CHECK(ecount == 4);
/* This will fail or succeed randomly, and in either case will not ARG_CHECK failure */
secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, recovery_test_nonce_function, NULL);
secp256k1_ecdsa_sign_recoverable(ctx, &recsig, message, privkey, recovery_test_nonce_function, NULL);
CHECK(ecount == 4);
/* These will all fail, but not in ARG_CHECK way */
CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, zero_privkey, NULL, NULL) == 0);
CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, over_privkey, NULL, NULL) == 0);
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &recsig, message, zero_privkey, NULL, NULL) == 0);
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &recsig, message, over_privkey, NULL, NULL) == 0);
/* This one will succeed. */
CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1);
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &recsig, message, privkey, NULL, NULL) == 1);
CHECK(ecount == 4);
/* Check signing with a goofy nonce function */
/* Check bad contexts and NULLs for recovery */
ecount = 0;
CHECK(secp256k1_ecdsa_recover(none, &recpubkey, &recsig, message) == 1);
CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &recsig, message) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_ecdsa_recover(sign, &recpubkey, &recsig, message) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_ecdsa_recover(vrfy, &recpubkey, &recsig, message) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_ecdsa_recover(both, &recpubkey, &recsig, message) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_ecdsa_recover(both, NULL, &recsig, message) == 0);
CHECK(secp256k1_ecdsa_recover(ctx, NULL, &recsig, message) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_ecdsa_recover(both, &recpubkey, NULL, message) == 0);
CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, NULL, message) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_ecdsa_recover(both, &recpubkey, &recsig, NULL) == 0);
CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &recsig, NULL) == 0);
CHECK(ecount == 3);
/* Check NULLs for conversion */
CHECK(secp256k1_ecdsa_sign(both, &normal_sig, message, privkey, NULL, NULL) == 1);
CHECK(secp256k1_ecdsa_sign(ctx, &normal_sig, message, privkey, NULL, NULL) == 1);
ecount = 0;
CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, NULL, &recsig) == 0);
CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, NULL, &recsig) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, &normal_sig, NULL) == 0);
CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &normal_sig, NULL) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, &normal_sig, &recsig) == 1);
CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &normal_sig, &recsig) == 1);
/* Check NULLs for de/serialization */
CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1);
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &recsig, message, privkey, NULL, NULL) == 1);
ecount = 0;
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, NULL, &recid, &recsig) == 0);
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, NULL, &recid, &recsig) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, NULL, &recsig) == 0);
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, NULL, &recsig) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, NULL) == 0);
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, NULL) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, &recsig) == 1);
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &recsig) == 1);
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, NULL, sig, recid) == 0);
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, NULL, sig, recid) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, NULL, recid) == 0);
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &recsig, NULL, recid) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, -1) == 0);
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &recsig, sig, -1) == 0);
CHECK(ecount == 6);
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, 5) == 0);
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &recsig, sig, 5) == 0);
CHECK(ecount == 7);
/* overflow in signature will fail but not affect ecount */
memcpy(sig, over_privkey, 32);
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, recid) == 0);
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &recsig, sig, recid) == 0);
CHECK(ecount == 7);
/* cleanup */
secp256k1_context_destroy(none);
secp256k1_context_destroy(sign);
secp256k1_context_destroy(vrfy);
secp256k1_context_destroy(both);
secp256k1_context_destroy(sttc);
}

View File

@ -50,7 +50,7 @@ void run_schnorrsig_bench(int iters, int argc, char** argv) {
bench_schnorrsig_data data;
int d = argc == 1;
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN);
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
data.keypairs = (const secp256k1_keypair **)malloc(iters * sizeof(secp256k1_keypair *));
data.pk = (const unsigned char **)malloc(iters * sizeof(unsigned char *));
data.msgs = (const unsigned char **)malloc(iters * sizeof(unsigned char *));
@ -91,10 +91,12 @@ void run_schnorrsig_bench(int iters, int argc, char** argv) {
free((void *)data.msgs[i]);
free((void *)data.sigs[i]);
}
free(data.keypairs);
free(data.pk);
free(data.msgs);
free(data.sigs);
/* Casting to (void *) avoids a stupid warning in MSVC. */
free((void *)data.keypairs);
free((void *)data.pk);
free((void *)data.msgs);
free((void *)data.sigs);
secp256k1_context_destroy(data.ctx);
}

View File

@ -8,7 +8,7 @@
#define SECP256K1_MODULE_SCHNORRSIG_TESTS_EXHAUSTIVE_H
#include "../../../include/secp256k1_schnorrsig.h"
#include "src/modules/schnorrsig/main_impl.h"
#include "main_impl.h"
static const unsigned char invalid_pubkey_bytes[][32] = {
/* 0 */

View File

@ -128,22 +128,12 @@ void test_schnorrsig_api(void) {
secp256k1_schnorrsig_extraparams invalid_extraparams = {{ 0 }, NULL, NULL};
/** setup **/
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
secp256k1_context *sttc = secp256k1_context_clone(secp256k1_context_no_precomp);
secp256k1_context *sttc = secp256k1_context_clone(secp256k1_context_static);
int ecount;
secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_error_callback(both, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_error_callback(ctx, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_error_callback(sttc, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(sttc, counting_illegal_callback_fn, &ecount);
secp256k1_testrand256(sk1);
@ -160,70 +150,54 @@ void test_schnorrsig_api(void) {
/** main test body **/
ecount = 0;
CHECK(secp256k1_schnorrsig_sign32(none, sig, msg, &keypairs[0], NULL) == 1);
CHECK(secp256k1_schnorrsig_sign32(ctx, sig, msg, &keypairs[0], NULL) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_schnorrsig_sign32(vrfy, sig, msg, &keypairs[0], NULL) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_schnorrsig_sign32(sign, sig, msg, &keypairs[0], NULL) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_schnorrsig_sign32(sign, NULL, msg, &keypairs[0], NULL) == 0);
CHECK(secp256k1_schnorrsig_sign32(ctx, NULL, msg, &keypairs[0], NULL) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_schnorrsig_sign32(sign, sig, NULL, &keypairs[0], NULL) == 0);
CHECK(secp256k1_schnorrsig_sign32(ctx, sig, NULL, &keypairs[0], NULL) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_schnorrsig_sign32(sign, sig, msg, NULL, NULL) == 0);
CHECK(secp256k1_schnorrsig_sign32(ctx, sig, msg, NULL, NULL) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_schnorrsig_sign32(sign, sig, msg, &invalid_keypair, NULL) == 0);
CHECK(secp256k1_schnorrsig_sign32(ctx, sig, msg, &invalid_keypair, NULL) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_schnorrsig_sign32(sttc, sig, msg, &keypairs[0], NULL) == 0);
CHECK(ecount == 5);
ecount = 0;
CHECK(secp256k1_schnorrsig_sign_custom(none, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 1);
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_schnorrsig_sign_custom(vrfy, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_schnorrsig_sign_custom(sign, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_schnorrsig_sign_custom(sign, NULL, msg, sizeof(msg), &keypairs[0], &extraparams) == 0);
CHECK(secp256k1_schnorrsig_sign_custom(ctx, NULL, msg, sizeof(msg), &keypairs[0], &extraparams) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_schnorrsig_sign_custom(sign, sig, NULL, sizeof(msg), &keypairs[0], &extraparams) == 0);
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, NULL, sizeof(msg), &keypairs[0], &extraparams) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_schnorrsig_sign_custom(sign, sig, NULL, 0, &keypairs[0], &extraparams) == 1);
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, NULL, 0, &keypairs[0], &extraparams) == 1);
CHECK(ecount == 2);
CHECK(secp256k1_schnorrsig_sign_custom(sign, sig, msg, sizeof(msg), NULL, &extraparams) == 0);
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), NULL, &extraparams) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_schnorrsig_sign_custom(sign, sig, msg, sizeof(msg), &invalid_keypair, &extraparams) == 0);
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &invalid_keypair, &extraparams) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_schnorrsig_sign_custom(sign, sig, msg, sizeof(msg), &keypairs[0], NULL) == 1);
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypairs[0], NULL) == 1);
CHECK(ecount == 4);
CHECK(secp256k1_schnorrsig_sign_custom(sign, sig, msg, sizeof(msg), &keypairs[0], &invalid_extraparams) == 0);
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypairs[0], &invalid_extraparams) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_schnorrsig_sign_custom(sttc, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 0);
CHECK(ecount == 6);
ecount = 0;
CHECK(secp256k1_schnorrsig_sign32(sign, sig, msg, &keypairs[0], NULL) == 1);
CHECK(secp256k1_schnorrsig_verify(none, sig, msg, sizeof(msg), &pk[0]) == 1);
CHECK(secp256k1_schnorrsig_sign32(ctx, sig, msg, &keypairs[0], NULL) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &pk[0]) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_schnorrsig_verify(sign, sig, msg, sizeof(msg), &pk[0]) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_schnorrsig_verify(vrfy, sig, msg, sizeof(msg), &pk[0]) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_schnorrsig_verify(vrfy, NULL, msg, sizeof(msg), &pk[0]) == 0);
CHECK(secp256k1_schnorrsig_verify(ctx, NULL, msg, sizeof(msg), &pk[0]) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_schnorrsig_verify(vrfy, sig, NULL, sizeof(msg), &pk[0]) == 0);
CHECK(secp256k1_schnorrsig_verify(ctx, sig, NULL, sizeof(msg), &pk[0]) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_schnorrsig_verify(vrfy, sig, NULL, 0, &pk[0]) == 0);
CHECK(secp256k1_schnorrsig_verify(ctx, sig, NULL, 0, &pk[0]) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_schnorrsig_verify(vrfy, sig, msg, sizeof(msg), NULL) == 0);
CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, sizeof(msg), NULL) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_schnorrsig_verify(vrfy, sig, msg, sizeof(msg), &zero_pk) == 0);
CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &zero_pk) == 0);
CHECK(ecount == 4);
secp256k1_context_destroy(none);
secp256k1_context_destroy(sign);
secp256k1_context_destroy(vrfy);
secp256k1_context_destroy(both);
secp256k1_context_destroy(sttc);
}

View File

@ -14,10 +14,13 @@
#endif
#include "../include/secp256k1.h"
#include "assumptions.h"
#include "util.h"
#include "field_impl.h"
#include "group_impl.h"
#include "int128_impl.h"
#include "ecmult.h"
#include "ecmult_compute_table_impl.h"

View File

@ -8,9 +8,12 @@
#include <stdio.h>
#include "../include/secp256k1.h"
#include "assumptions.h"
#include "util.h"
#include "group.h"
#include "int128_impl.h"
#include "ecmult_gen.h"
#include "ecmult_gen_compute_table_impl.h"

View File

@ -7,6 +7,7 @@
#ifndef SECP256K1_SCALAR_REPR_IMPL_H
#define SECP256K1_SCALAR_REPR_IMPL_H
#include "int128.h"
#include "modinv64_impl.h"
/* Limbs of the secp256k1 order. */
@ -69,50 +70,61 @@ SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scal
}
SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, unsigned int overflow) {
uint128_t t;
secp256k1_uint128 t;
VERIFY_CHECK(overflow <= 1);
t = (uint128_t)r->d[0] + overflow * SECP256K1_N_C_0;
r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
t += (uint128_t)r->d[1] + overflow * SECP256K1_N_C_1;
r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
t += (uint128_t)r->d[2] + overflow * SECP256K1_N_C_2;
r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
t += (uint64_t)r->d[3];
r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL;
secp256k1_u128_from_u64(&t, r->d[0]);
secp256k1_u128_accum_u64(&t, overflow * SECP256K1_N_C_0);
r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64);
secp256k1_u128_accum_u64(&t, r->d[1]);
secp256k1_u128_accum_u64(&t, overflow * SECP256K1_N_C_1);
r->d[1] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64);
secp256k1_u128_accum_u64(&t, r->d[2]);
secp256k1_u128_accum_u64(&t, overflow * SECP256K1_N_C_2);
r->d[2] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64);
secp256k1_u128_accum_u64(&t, r->d[3]);
r->d[3] = secp256k1_u128_to_u64(&t);
return overflow;
}
static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {
int overflow;
uint128_t t = (uint128_t)a->d[0] + b->d[0];
r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
t += (uint128_t)a->d[1] + b->d[1];
r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
t += (uint128_t)a->d[2] + b->d[2];
r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
t += (uint128_t)a->d[3] + b->d[3];
r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
overflow = t + secp256k1_scalar_check_overflow(r);
secp256k1_uint128 t;
secp256k1_u128_from_u64(&t, a->d[0]);
secp256k1_u128_accum_u64(&t, b->d[0]);
r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64);
secp256k1_u128_accum_u64(&t, a->d[1]);
secp256k1_u128_accum_u64(&t, b->d[1]);
r->d[1] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64);
secp256k1_u128_accum_u64(&t, a->d[2]);
secp256k1_u128_accum_u64(&t, b->d[2]);
r->d[2] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64);
secp256k1_u128_accum_u64(&t, a->d[3]);
secp256k1_u128_accum_u64(&t, b->d[3]);
r->d[3] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64);
overflow = secp256k1_u128_to_u64(&t) + secp256k1_scalar_check_overflow(r);
VERIFY_CHECK(overflow == 0 || overflow == 1);
secp256k1_scalar_reduce(r, overflow);
return overflow;
}
static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) {
uint128_t t;
secp256k1_uint128 t;
VERIFY_CHECK(bit < 256);
bit += ((uint32_t) flag - 1) & 0x100; /* forcing (bit >> 6) > 3 makes this a noop */
t = (uint128_t)r->d[0] + (((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F));
r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
t += (uint128_t)r->d[1] + (((uint64_t)((bit >> 6) == 1)) << (bit & 0x3F));
r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
t += (uint128_t)r->d[2] + (((uint64_t)((bit >> 6) == 2)) << (bit & 0x3F));
r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64;
t += (uint128_t)r->d[3] + (((uint64_t)((bit >> 6) == 3)) << (bit & 0x3F));
r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL;
secp256k1_u128_from_u64(&t, r->d[0]);
secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F));
r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64);
secp256k1_u128_accum_u64(&t, r->d[1]);
secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 1)) << (bit & 0x3F));
r->d[1] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64);
secp256k1_u128_accum_u64(&t, r->d[2]);
secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 2)) << (bit & 0x3F));
r->d[2] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64);
secp256k1_u128_accum_u64(&t, r->d[3]);
secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 3)) << (bit & 0x3F));
r->d[3] = secp256k1_u128_to_u64(&t);
#ifdef VERIFY
VERIFY_CHECK((t >> 64) == 0);
VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0);
VERIFY_CHECK(secp256k1_u128_hi_u64(&t) == 0);
#endif
}
@ -141,14 +153,19 @@ SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a)
static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) {
uint64_t nonzero = 0xFFFFFFFFFFFFFFFFULL * (secp256k1_scalar_is_zero(a) == 0);
uint128_t t = (uint128_t)(~a->d[0]) + SECP256K1_N_0 + 1;
r->d[0] = t & nonzero; t >>= 64;
t += (uint128_t)(~a->d[1]) + SECP256K1_N_1;
r->d[1] = t & nonzero; t >>= 64;
t += (uint128_t)(~a->d[2]) + SECP256K1_N_2;
r->d[2] = t & nonzero; t >>= 64;
t += (uint128_t)(~a->d[3]) + SECP256K1_N_3;
r->d[3] = t & nonzero;
secp256k1_uint128 t;
secp256k1_u128_from_u64(&t, ~a->d[0]);
secp256k1_u128_accum_u64(&t, SECP256K1_N_0 + 1);
r->d[0] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64);
secp256k1_u128_accum_u64(&t, ~a->d[1]);
secp256k1_u128_accum_u64(&t, SECP256K1_N_1);
r->d[1] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64);
secp256k1_u128_accum_u64(&t, ~a->d[2]);
secp256k1_u128_accum_u64(&t, SECP256K1_N_2);
r->d[2] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64);
secp256k1_u128_accum_u64(&t, ~a->d[3]);
secp256k1_u128_accum_u64(&t, SECP256K1_N_3);
r->d[3] = secp256k1_u128_to_u64(&t) & nonzero;
}
SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) {
@ -172,14 +189,19 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
* if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */
uint64_t mask = !flag - 1;
uint64_t nonzero = (secp256k1_scalar_is_zero(r) != 0) - 1;
uint128_t t = (uint128_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask);
r->d[0] = t & nonzero; t >>= 64;
t += (uint128_t)(r->d[1] ^ mask) + (SECP256K1_N_1 & mask);
r->d[1] = t & nonzero; t >>= 64;
t += (uint128_t)(r->d[2] ^ mask) + (SECP256K1_N_2 & mask);
r->d[2] = t & nonzero; t >>= 64;
t += (uint128_t)(r->d[3] ^ mask) + (SECP256K1_N_3 & mask);
r->d[3] = t & nonzero;
secp256k1_uint128 t;
secp256k1_u128_from_u64(&t, r->d[0] ^ mask);
secp256k1_u128_accum_u64(&t, (SECP256K1_N_0 + 1) & mask);
r->d[0] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64);
secp256k1_u128_accum_u64(&t, r->d[1] ^ mask);
secp256k1_u128_accum_u64(&t, SECP256K1_N_1 & mask);
r->d[1] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64);
secp256k1_u128_accum_u64(&t, r->d[2] ^ mask);
secp256k1_u128_accum_u64(&t, SECP256K1_N_2 & mask);
r->d[2] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64);
secp256k1_u128_accum_u64(&t, r->d[3] ^ mask);
secp256k1_u128_accum_u64(&t, SECP256K1_N_3 & mask);
r->d[3] = secp256k1_u128_to_u64(&t) & nonzero;
return 2 * (mask == 0) - 1;
}
@ -189,9 +211,10 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
#define muladd(a,b) { \
uint64_t tl, th; \
{ \
uint128_t t = (uint128_t)a * b; \
th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \
tl = t; \
secp256k1_uint128 t; \
secp256k1_u128_mul(&t, a, b); \
th = secp256k1_u128_hi_u64(&t); /* at most 0xFFFFFFFFFFFFFFFE */ \
tl = secp256k1_u128_to_u64(&t); \
} \
c0 += tl; /* overflow is handled on the next line */ \
th += (c0 < tl); /* at most 0xFFFFFFFFFFFFFFFF */ \
@ -204,9 +227,10 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
#define muladd_fast(a,b) { \
uint64_t tl, th; \
{ \
uint128_t t = (uint128_t)a * b; \
th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \
tl = t; \
secp256k1_uint128 t; \
secp256k1_u128_mul(&t, a, b); \
th = secp256k1_u128_hi_u64(&t); /* at most 0xFFFFFFFFFFFFFFFE */ \
tl = secp256k1_u128_to_u64(&t); \
} \
c0 += tl; /* overflow is handled on the next line */ \
th += (c0 < tl); /* at most 0xFFFFFFFFFFFFFFFF */ \
@ -484,8 +508,8 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
: "g"(p0), "g"(p1), "g"(p2), "g"(p3), "g"(p4), "D"(r), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1)
: "rax", "rdx", "r8", "r9", "r10", "cc", "memory");
#else
uint128_t c;
uint64_t c0, c1, c2;
secp256k1_uint128 c128;
uint64_t c, c0, c1, c2;
uint64_t n0 = l[4], n1 = l[5], n2 = l[6], n3 = l[7];
uint64_t m0, m1, m2, m3, m4, m5;
uint32_t m6;
@ -542,14 +566,18 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
/* Reduce 258 bits into 256. */
/* r[0..3] = p[0..3] + p[4] * SECP256K1_N_C. */
c = p0 + (uint128_t)SECP256K1_N_C_0 * p4;
r->d[0] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64;
c += p1 + (uint128_t)SECP256K1_N_C_1 * p4;
r->d[1] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64;
c += p2 + (uint128_t)p4;
r->d[2] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64;
c += p3;
r->d[3] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64;
secp256k1_u128_from_u64(&c128, p0);
secp256k1_u128_accum_mul(&c128, SECP256K1_N_C_0, p4);
r->d[0] = secp256k1_u128_to_u64(&c128); secp256k1_u128_rshift(&c128, 64);
secp256k1_u128_accum_u64(&c128, p1);
secp256k1_u128_accum_mul(&c128, SECP256K1_N_C_1, p4);
r->d[1] = secp256k1_u128_to_u64(&c128); secp256k1_u128_rshift(&c128, 64);
secp256k1_u128_accum_u64(&c128, p2);
secp256k1_u128_accum_u64(&c128, p4);
r->d[2] = secp256k1_u128_to_u64(&c128); secp256k1_u128_rshift(&c128, 64);
secp256k1_u128_accum_u64(&c128, p3);
r->d[3] = secp256k1_u128_to_u64(&c128);
c = secp256k1_u128_hi_u64(&c128);
#endif
/* Final reduction of r. */

View File

@ -25,11 +25,11 @@ static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* err
static void secp256k1_scratch_destroy(const secp256k1_callback* error_callback, secp256k1_scratch* scratch) {
if (scratch != NULL) {
VERIFY_CHECK(scratch->alloc_size == 0); /* all checkpoints should be applied */
if (secp256k1_memcmp_var(scratch->magic, "scratch", 8) != 0) {
secp256k1_callback_call(error_callback, "invalid scratch space");
return;
}
VERIFY_CHECK(scratch->alloc_size == 0); /* all checkpoints should be applied */
memset(scratch->magic, 0, sizeof(scratch->magic));
free(scratch);
}

View File

@ -4,6 +4,17 @@
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
/* This is a C project. It should not be compiled with a C++ compiler,
* and we error out if we detect one.
*
* We still want to be able to test the project with a C++ compiler
* because it is still good to know if this will lead to real trouble, so
* there is a possibility to override the check. But be warned that
* compiling with a C++ compiler is not supported. */
#if defined(__cplusplus) && !defined(SECP256K1_CPLUSPLUS_TEST_OVERRIDE)
#error Trying to compile a C project with a C++ compiler.
#endif
#define SECP256K1_BUILD
#include "../include/secp256k1.h"
@ -11,6 +22,7 @@
#include "assumptions.h"
#include "util.h"
#include "field_impl.h"
#include "scalar_impl.h"
#include "group_impl.h"
@ -20,6 +32,7 @@
#include "ecdsa_impl.h"
#include "eckey_impl.h"
#include "hash_impl.h"
#include "int128_impl.h"
#include "scratch_impl.h"
#include "selftest.h"
@ -44,6 +57,8 @@
} \
} while(0)
/* Note that whenever you change the context struct, you must also change the
* context_eq function. */
struct secp256k1_context_struct {
secp256k1_ecmult_gen_context ecmult_gen_ctx;
secp256k1_callback illegal_callback;
@ -51,13 +66,20 @@ struct secp256k1_context_struct {
int declassify;
};
static const secp256k1_context secp256k1_context_no_precomp_ = {
static const secp256k1_context secp256k1_context_static_ = {
{ 0 },
{ secp256k1_default_illegal_callback_fn, 0 },
{ secp256k1_default_error_callback_fn, 0 },
0
};
const secp256k1_context *secp256k1_context_no_precomp = &secp256k1_context_no_precomp_;
const secp256k1_context *secp256k1_context_static = &secp256k1_context_static_;
const secp256k1_context *secp256k1_context_no_precomp = &secp256k1_context_static_;
void secp256k1_selftest(void) {
if (!secp256k1_selftest_passes()) {
secp256k1_callback_call(&default_error_callback, "self test failed");
}
}
size_t secp256k1_context_preallocated_size(unsigned int flags) {
size_t ret = sizeof(secp256k1_context);
@ -83,9 +105,7 @@ secp256k1_context* secp256k1_context_preallocated_create(void* prealloc, unsigne
size_t prealloc_size;
secp256k1_context* ret;
if (!secp256k1_selftest()) {
secp256k1_callback_call(&default_error_callback, "self test failed");
}
secp256k1_selftest();
prealloc_size = secp256k1_context_preallocated_size(flags);
if (prealloc_size == 0) {
@ -137,7 +157,7 @@ secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) {
}
void secp256k1_context_preallocated_destroy(secp256k1_context* ctx) {
ARG_CHECK_NO_RETURN(ctx != secp256k1_context_no_precomp);
ARG_CHECK_NO_RETURN(ctx != secp256k1_context_static);
if (ctx != NULL) {
secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx);
}
@ -151,7 +171,7 @@ void secp256k1_context_destroy(secp256k1_context* ctx) {
}
void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) {
ARG_CHECK_NO_RETURN(ctx != secp256k1_context_no_precomp);
ARG_CHECK_NO_RETURN(ctx != secp256k1_context_static);
if (fun == NULL) {
fun = secp256k1_default_illegal_callback_fn;
}
@ -160,7 +180,7 @@ void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(
}
void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) {
ARG_CHECK_NO_RETURN(ctx != secp256k1_context_no_precomp);
ARG_CHECK_NO_RETURN(ctx != secp256k1_context_static);
if (fun == NULL) {
fun = secp256k1_default_error_callback_fn;
}

View File

@ -25,7 +25,7 @@ static int secp256k1_selftest_sha256(void) {
return secp256k1_memcmp_var(out, output32, 32) == 0;
}
static int secp256k1_selftest(void) {
static int secp256k1_selftest_passes(void) {
return secp256k1_selftest_sha256();
}

View File

@ -26,6 +26,7 @@
#include "modinv32_impl.h"
#ifdef SECP256K1_WIDEMUL_INT128
#include "modinv64_impl.h"
#include "int128_impl.h"
#endif
#define CONDITIONAL_TEST(cnt, nam) if (count < (cnt)) { printf("Skipping %s (iteration count too low)\n", nam); } else
@ -140,6 +141,43 @@ void random_scalar_order_b32(unsigned char *b32) {
secp256k1_scalar_get_b32(b32, &num);
}
void run_selftest_tests(void) {
/* Test public API */
secp256k1_selftest();
}
int ecmult_gen_context_eq(const secp256k1_ecmult_gen_context *a, const secp256k1_ecmult_gen_context *b) {
return a->built == b->built
&& secp256k1_scalar_eq(&a->blind, &b->blind)
&& secp256k1_gej_eq_var(&a->initial, &b->initial);
}
int context_eq(const secp256k1_context *a, const secp256k1_context *b) {
return a->declassify == b->declassify
&& ecmult_gen_context_eq(&a->ecmult_gen_ctx, &b->ecmult_gen_ctx)
&& a->illegal_callback.fn == b->illegal_callback.fn
&& a->illegal_callback.data == b->illegal_callback.
data
&& a->error_callback.fn == b->error_callback.fn
&& a->error_callback.data == b->error_callback.data;
}
void test_deprecated_flags(void) {
unsigned int flags[] = { SECP256K1_CONTEXT_SIGN,
SECP256K1_CONTEXT_VERIFY,
SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY };
int i;
/* Check that a context created with any of the flags in the flags array is
* identical to the NONE context. */
for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); i++) {
secp256k1_context *tmp_ctx;
CHECK(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE) == secp256k1_context_preallocated_size(flags[i]));
tmp_ctx = secp256k1_context_create(flags[i]);
CHECK(context_eq(ctx, tmp_ctx));
secp256k1_context_destroy(tmp_ctx);
}
}
void run_context_tests(int use_prealloc) {
secp256k1_pubkey pubkey;
secp256k1_pubkey zero_pubkey;
@ -147,15 +185,8 @@ void run_context_tests(int use_prealloc) {
unsigned char ctmp[32];
int32_t ecount;
int32_t ecount2;
secp256k1_context *none;
secp256k1_context *sign;
secp256k1_context *vrfy;
secp256k1_context *both;
secp256k1_context *sttc;
void *none_prealloc = NULL;
void *sign_prealloc = NULL;
void *vrfy_prealloc = NULL;
void *both_prealloc = NULL;
void *ctx_prealloc = NULL;
void *sttc_prealloc = NULL;
secp256k1_gej pubj;
@ -163,46 +194,36 @@ void run_context_tests(int use_prealloc) {
secp256k1_scalar msg, key, nonce;
secp256k1_scalar sigr, sigs;
/* Check that deprecated secp256k1_context_no_precomp is an alias to secp256k1_context_static. */
CHECK(secp256k1_context_no_precomp == secp256k1_context_static);
if (use_prealloc) {
none_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE));
sign_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN));
vrfy_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_VERIFY));
both_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY));
sttc_prealloc = malloc(secp256k1_context_preallocated_clone_size(secp256k1_context_no_precomp));
CHECK(none_prealloc != NULL);
CHECK(sign_prealloc != NULL);
CHECK(vrfy_prealloc != NULL);
CHECK(both_prealloc != NULL);
ctx_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE));
CHECK(ctx_prealloc != NULL);
ctx = secp256k1_context_preallocated_create(ctx_prealloc, SECP256K1_CONTEXT_NONE);
sttc_prealloc = malloc(secp256k1_context_preallocated_clone_size(secp256k1_context_static));
CHECK(sttc_prealloc != NULL);
none = secp256k1_context_preallocated_create(none_prealloc, SECP256K1_CONTEXT_NONE);
sign = secp256k1_context_preallocated_create(sign_prealloc, SECP256K1_CONTEXT_SIGN);
vrfy = secp256k1_context_preallocated_create(vrfy_prealloc, SECP256K1_CONTEXT_VERIFY);
both = secp256k1_context_preallocated_create(both_prealloc, SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
sttc = secp256k1_context_preallocated_clone(secp256k1_context_no_precomp, sttc_prealloc);
sttc = secp256k1_context_preallocated_clone(secp256k1_context_static, sttc_prealloc);
} else {
none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
sttc = secp256k1_context_clone(secp256k1_context_no_precomp);
sttc = secp256k1_context_clone(secp256k1_context_static);
ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
}
test_deprecated_flags();
memset(&zero_pubkey, 0, sizeof(zero_pubkey));
ecount = 0;
ecount2 = 10;
secp256k1_context_set_illegal_callback(sttc, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount2);
secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount2);
/* set error callback (to a function that still aborts in case malloc() fails in secp256k1_context_clone() below) */
secp256k1_context_set_error_callback(sign, secp256k1_default_illegal_callback_fn, NULL);
CHECK(sign->error_callback.fn != vrfy->error_callback.fn);
CHECK(sign->error_callback.fn == secp256k1_default_illegal_callback_fn);
secp256k1_context_set_error_callback(ctx, secp256k1_default_illegal_callback_fn, NULL);
CHECK(ctx->error_callback.fn != sttc->error_callback.fn);
CHECK(ctx->error_callback.fn == secp256k1_default_illegal_callback_fn);
/* check if sizes for cloning are consistent */
CHECK(secp256k1_context_preallocated_clone_size(none) == secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE));
CHECK(secp256k1_context_preallocated_clone_size(sign) == secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN));
CHECK(secp256k1_context_preallocated_clone_size(vrfy) == secp256k1_context_preallocated_size(SECP256K1_CONTEXT_VERIFY));
CHECK(secp256k1_context_preallocated_clone_size(both) == secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY));
CHECK(secp256k1_context_preallocated_clone_size(ctx) == secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE));
CHECK(secp256k1_context_preallocated_clone_size(sttc) >= sizeof(secp256k1_context));
/*** clone and destroy all of them to make sure cloning was complete ***/
@ -211,58 +232,31 @@ void run_context_tests(int use_prealloc) {
if (use_prealloc) {
/* clone into a non-preallocated context and then again into a new preallocated one. */
ctx_tmp = none; none = secp256k1_context_clone(none); secp256k1_context_preallocated_destroy(ctx_tmp);
free(none_prealloc); none_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); CHECK(none_prealloc != NULL);
ctx_tmp = none; none = secp256k1_context_preallocated_clone(none, none_prealloc); secp256k1_context_destroy(ctx_tmp);
ctx_tmp = sign; sign = secp256k1_context_clone(sign); secp256k1_context_preallocated_destroy(ctx_tmp);
free(sign_prealloc); sign_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN)); CHECK(sign_prealloc != NULL);
ctx_tmp = sign; sign = secp256k1_context_preallocated_clone(sign, sign_prealloc); secp256k1_context_destroy(ctx_tmp);
ctx_tmp = vrfy; vrfy = secp256k1_context_clone(vrfy); secp256k1_context_preallocated_destroy(ctx_tmp);
free(vrfy_prealloc); vrfy_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_VERIFY)); CHECK(vrfy_prealloc != NULL);
ctx_tmp = vrfy; vrfy = secp256k1_context_preallocated_clone(vrfy, vrfy_prealloc); secp256k1_context_destroy(ctx_tmp);
ctx_tmp = both; both = secp256k1_context_clone(both); secp256k1_context_preallocated_destroy(ctx_tmp);
free(both_prealloc); both_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY)); CHECK(both_prealloc != NULL);
ctx_tmp = both; both = secp256k1_context_preallocated_clone(both, both_prealloc); secp256k1_context_destroy(ctx_tmp);
ctx_tmp = ctx; ctx = secp256k1_context_clone(ctx); secp256k1_context_preallocated_destroy(ctx_tmp);
free(ctx_prealloc); ctx_prealloc = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); CHECK(ctx_prealloc != NULL);
ctx_tmp = ctx; ctx = secp256k1_context_preallocated_clone(ctx, ctx_prealloc); secp256k1_context_destroy(ctx_tmp);
} else {
/* clone into a preallocated context and then again into a new non-preallocated one. */
void *prealloc_tmp;
prealloc_tmp = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE)); CHECK(prealloc_tmp != NULL);
ctx_tmp = none; none = secp256k1_context_preallocated_clone(none, prealloc_tmp); secp256k1_context_destroy(ctx_tmp);
ctx_tmp = none; none = secp256k1_context_clone(none); secp256k1_context_preallocated_destroy(ctx_tmp);
free(prealloc_tmp);
prealloc_tmp = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN)); CHECK(prealloc_tmp != NULL);
ctx_tmp = sign; sign = secp256k1_context_preallocated_clone(sign, prealloc_tmp); secp256k1_context_destroy(ctx_tmp);
ctx_tmp = sign; sign = secp256k1_context_clone(sign); secp256k1_context_preallocated_destroy(ctx_tmp);
free(prealloc_tmp);
prealloc_tmp = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_VERIFY)); CHECK(prealloc_tmp != NULL);
ctx_tmp = vrfy; vrfy = secp256k1_context_preallocated_clone(vrfy, prealloc_tmp); secp256k1_context_destroy(ctx_tmp);
ctx_tmp = vrfy; vrfy = secp256k1_context_clone(vrfy); secp256k1_context_preallocated_destroy(ctx_tmp);
free(prealloc_tmp);
prealloc_tmp = malloc(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY)); CHECK(prealloc_tmp != NULL);
ctx_tmp = both; both = secp256k1_context_preallocated_clone(both, prealloc_tmp); secp256k1_context_destroy(ctx_tmp);
ctx_tmp = both; both = secp256k1_context_clone(both); secp256k1_context_preallocated_destroy(ctx_tmp);
ctx_tmp = ctx; ctx = secp256k1_context_preallocated_clone(ctx, prealloc_tmp); secp256k1_context_destroy(ctx_tmp);
ctx_tmp = ctx; ctx = secp256k1_context_clone(ctx); secp256k1_context_preallocated_destroy(ctx_tmp);
free(prealloc_tmp);
}
}
/* Verify that the error callback makes it across the clone. */
CHECK(sign->error_callback.fn != vrfy->error_callback.fn);
CHECK(sign->error_callback.fn == secp256k1_default_illegal_callback_fn);
CHECK(ctx->error_callback.fn != sttc->error_callback.fn);
CHECK(ctx->error_callback.fn == secp256k1_default_illegal_callback_fn);
/* And that it resets back to default. */
secp256k1_context_set_error_callback(sign, NULL, NULL);
CHECK(vrfy->error_callback.fn == sign->error_callback.fn);
secp256k1_context_set_error_callback(ctx, NULL, NULL);
CHECK(ctx->error_callback.fn == sttc->error_callback.fn);
/*** attempt to use them ***/
random_scalar_order_test(&msg);
random_scalar_order_test(&key);
secp256k1_ecmult_gen(&both->ecmult_gen_ctx, &pubj, &key);
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubj, &key);
secp256k1_ge_set_gej(&pub, &pubj);
/* Verify context-type checking illegal-argument errors. */
@ -270,29 +264,29 @@ void run_context_tests(int use_prealloc) {
CHECK(secp256k1_ec_pubkey_create(sttc, &pubkey, ctmp) == 0);
CHECK(ecount == 1);
VG_UNDEF(&pubkey, sizeof(pubkey));
CHECK(secp256k1_ec_pubkey_create(sign, &pubkey, ctmp) == 1);
CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 1);
VG_CHECK(&pubkey, sizeof(pubkey));
CHECK(secp256k1_ecdsa_sign(sttc, &sig, ctmp, ctmp, NULL, NULL) == 0);
CHECK(ecount == 2);
VG_UNDEF(&sig, sizeof(sig));
CHECK(secp256k1_ecdsa_sign(sign, &sig, ctmp, ctmp, NULL, NULL) == 1);
CHECK(secp256k1_ecdsa_sign(ctx, &sig, ctmp, ctmp, NULL, NULL) == 1);
VG_CHECK(&sig, sizeof(sig));
CHECK(ecount2 == 10);
CHECK(secp256k1_ecdsa_verify(sign, &sig, ctmp, &pubkey) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, &sig, ctmp, &pubkey) == 1);
CHECK(ecount2 == 10);
CHECK(secp256k1_ecdsa_verify(sttc, &sig, ctmp, &pubkey) == 1);
CHECK(ecount == 2);
CHECK(secp256k1_ec_pubkey_tweak_add(sign, &pubkey, ctmp) == 1);
CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp) == 1);
CHECK(ecount2 == 10);
CHECK(secp256k1_ec_pubkey_tweak_add(sttc, &pubkey, ctmp) == 1);
CHECK(ecount == 2);
CHECK(secp256k1_ec_pubkey_tweak_mul(sign, &pubkey, ctmp) == 1);
CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, ctmp) == 1);
CHECK(ecount2 == 10);
CHECK(secp256k1_ec_pubkey_negate(sttc, &pubkey) == 1);
CHECK(ecount == 2);
CHECK(secp256k1_ec_pubkey_negate(sign, &pubkey) == 1);
CHECK(secp256k1_ec_pubkey_negate(ctx, &pubkey) == 1);
CHECK(ecount == 2);
CHECK(secp256k1_ec_pubkey_negate(sign, NULL) == 0);
CHECK(secp256k1_ec_pubkey_negate(ctx, NULL) == 0);
CHECK(ecount2 == 11);
CHECK(secp256k1_ec_pubkey_negate(sttc, &zero_pubkey) == 0);
CHECK(ecount == 3);
@ -302,49 +296,37 @@ void run_context_tests(int use_prealloc) {
CHECK(ecount == 3);
CHECK(secp256k1_context_randomize(sttc, NULL) == 1);
CHECK(ecount == 3);
CHECK(secp256k1_context_randomize(sign, ctmp) == 1);
CHECK(secp256k1_context_randomize(ctx, ctmp) == 1);
CHECK(ecount2 == 11);
CHECK(secp256k1_context_randomize(sign, NULL) == 1);
CHECK(secp256k1_context_randomize(ctx, NULL) == 1);
CHECK(ecount2 == 11);
secp256k1_context_set_illegal_callback(sttc, NULL, NULL);
secp256k1_context_set_illegal_callback(sign, NULL, NULL);
secp256k1_context_set_illegal_callback(ctx, NULL, NULL);
/* obtain a working nonce */
do {
random_scalar_order_test(&nonce);
} while(!secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL));
} while(!secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL));
/* try signing */
CHECK(secp256k1_ecdsa_sig_sign(&sign->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL));
CHECK(secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL));
CHECK(secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL));
/* try verifying */
CHECK(secp256k1_ecdsa_sig_verify(&sigr, &sigs, &pub, &msg));
CHECK(secp256k1_ecdsa_sig_verify(&sigr, &sigs, &pub, &msg));
/* cleanup */
if (use_prealloc) {
secp256k1_context_preallocated_destroy(none);
secp256k1_context_preallocated_destroy(sign);
secp256k1_context_preallocated_destroy(vrfy);
secp256k1_context_preallocated_destroy(both);
secp256k1_context_preallocated_destroy(ctx);
secp256k1_context_preallocated_destroy(sttc);
free(none_prealloc);
free(sign_prealloc);
free(vrfy_prealloc);
free(both_prealloc);
free(ctx_prealloc);
free(sttc_prealloc);
} else {
secp256k1_context_destroy(none);
secp256k1_context_destroy(sign);
secp256k1_context_destroy(vrfy);
secp256k1_context_destroy(both);
secp256k1_context_destroy(ctx);
secp256k1_context_destroy(sttc);
}
/* Defined as no-op. */
secp256k1_context_destroy(NULL);
secp256k1_context_preallocated_destroy(NULL);
}
void run_scratch_tests(void) {
@ -353,83 +335,85 @@ void run_scratch_tests(void) {
int32_t ecount = 0;
size_t checkpoint;
size_t checkpoint_2;
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
secp256k1_scratch_space *scratch;
secp256k1_scratch_space local_scratch;
/* Test public API */
secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount);
ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
scratch = secp256k1_scratch_space_create(none, 1000);
/* Test public API */
secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_error_callback(ctx, counting_illegal_callback_fn, &ecount);
scratch = secp256k1_scratch_space_create(ctx, 1000);
CHECK(scratch != NULL);
CHECK(ecount == 0);
/* Test internal API */
CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 0) == 1000);
CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 1) == 1000 - (ALIGNMENT - 1));
CHECK(secp256k1_scratch_max_allocation(&ctx->error_callback, scratch, 0) == 1000);
CHECK(secp256k1_scratch_max_allocation(&ctx->error_callback, scratch, 1) == 1000 - (ALIGNMENT - 1));
CHECK(scratch->alloc_size == 0);
CHECK(scratch->alloc_size % ALIGNMENT == 0);
/* Allocating 500 bytes succeeds */
checkpoint = secp256k1_scratch_checkpoint(&none->error_callback, scratch);
CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, 500) != NULL);
CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 0) == 1000 - adj_alloc);
CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 1) == 1000 - adj_alloc - (ALIGNMENT - 1));
checkpoint = secp256k1_scratch_checkpoint(&ctx->error_callback, scratch);
CHECK(secp256k1_scratch_alloc(&ctx->error_callback, scratch, 500) != NULL);
CHECK(secp256k1_scratch_max_allocation(&ctx->error_callback, scratch, 0) == 1000 - adj_alloc);
CHECK(secp256k1_scratch_max_allocation(&ctx->error_callback, scratch, 1) == 1000 - adj_alloc - (ALIGNMENT - 1));
CHECK(scratch->alloc_size != 0);
CHECK(scratch->alloc_size % ALIGNMENT == 0);
/* Allocating another 501 bytes fails */
CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, 501) == NULL);
CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 0) == 1000 - adj_alloc);
CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 1) == 1000 - adj_alloc - (ALIGNMENT - 1));
CHECK(secp256k1_scratch_alloc(&ctx->error_callback, scratch, 501) == NULL);
CHECK(secp256k1_scratch_max_allocation(&ctx->error_callback, scratch, 0) == 1000 - adj_alloc);
CHECK(secp256k1_scratch_max_allocation(&ctx->error_callback, scratch, 1) == 1000 - adj_alloc - (ALIGNMENT - 1));
CHECK(scratch->alloc_size != 0);
CHECK(scratch->alloc_size % ALIGNMENT == 0);
/* ...but it succeeds once we apply the checkpoint to undo it */
secp256k1_scratch_apply_checkpoint(&none->error_callback, scratch, checkpoint);
secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, checkpoint);
CHECK(scratch->alloc_size == 0);
CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 0) == 1000);
CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, 500) != NULL);
CHECK(secp256k1_scratch_max_allocation(&ctx->error_callback, scratch, 0) == 1000);
CHECK(secp256k1_scratch_alloc(&ctx->error_callback, scratch, 500) != NULL);
CHECK(scratch->alloc_size != 0);
/* try to apply a bad checkpoint */
checkpoint_2 = secp256k1_scratch_checkpoint(&none->error_callback, scratch);
secp256k1_scratch_apply_checkpoint(&none->error_callback, scratch, checkpoint);
checkpoint_2 = secp256k1_scratch_checkpoint(&ctx->error_callback, scratch);
secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, checkpoint);
CHECK(ecount == 0);
secp256k1_scratch_apply_checkpoint(&none->error_callback, scratch, checkpoint_2); /* checkpoint_2 is after checkpoint */
secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, checkpoint_2); /* checkpoint_2 is after checkpoint */
CHECK(ecount == 1);
secp256k1_scratch_apply_checkpoint(&none->error_callback, scratch, (size_t) -1); /* this is just wildly invalid */
secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, (size_t) -1); /* this is just wildly invalid */
CHECK(ecount == 2);
/* try to use badly initialized scratch space */
secp256k1_scratch_space_destroy(none, scratch);
secp256k1_scratch_space_destroy(ctx, scratch);
memset(&local_scratch, 0, sizeof(local_scratch));
scratch = &local_scratch;
CHECK(!secp256k1_scratch_max_allocation(&none->error_callback, scratch, 0));
CHECK(!secp256k1_scratch_max_allocation(&ctx->error_callback, scratch, 0));
CHECK(ecount == 3);
CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, 500) == NULL);
CHECK(secp256k1_scratch_alloc(&ctx->error_callback, scratch, 500) == NULL);
CHECK(ecount == 4);
secp256k1_scratch_space_destroy(none, scratch);
secp256k1_scratch_space_destroy(ctx, scratch);
CHECK(ecount == 5);
/* Test that large integers do not wrap around in a bad way */
scratch = secp256k1_scratch_space_create(none, 1000);
scratch = secp256k1_scratch_space_create(ctx, 1000);
/* Try max allocation with a large number of objects. Only makes sense if
* ALIGNMENT is greater than 1 because otherwise the objects take no extra
* space. */
CHECK(ALIGNMENT <= 1 || !secp256k1_scratch_max_allocation(&none->error_callback, scratch, (SIZE_MAX / (ALIGNMENT - 1)) + 1));
CHECK(ALIGNMENT <= 1 || !secp256k1_scratch_max_allocation(&ctx->error_callback, scratch, (SIZE_MAX / (ALIGNMENT - 1)) + 1));
/* Try allocating SIZE_MAX to test wrap around which only happens if
* ALIGNMENT > 1, otherwise it returns NULL anyway because the scratch
* space is too small. */
CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, SIZE_MAX) == NULL);
secp256k1_scratch_space_destroy(none, scratch);
CHECK(secp256k1_scratch_alloc(&ctx->error_callback, scratch, SIZE_MAX) == NULL);
secp256k1_scratch_space_destroy(ctx, scratch);
/* cleanup */
secp256k1_scratch_space_destroy(none, NULL); /* no-op */
secp256k1_context_destroy(none);
secp256k1_scratch_space_destroy(ctx, NULL); /* no-op */
secp256k1_context_destroy(ctx);
}
void run_ctz_tests(void) {
static const uint32_t b32[] = {1, 0xffffffff, 0x5e56968f, 0xe0d63129};
static const uint64_t b64[] = {1, 0xffffffffffffffff, 0xbcd02462139b3fc3, 0x98b5f80c769693ef};
@ -697,7 +681,6 @@ void run_rfc6979_hmac_sha256_tests(void) {
void run_tagged_sha256_tests(void) {
int ecount = 0;
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
unsigned char tag[32] = { 0 };
unsigned char msg[32] = { 0 };
unsigned char hash32[32];
@ -708,23 +691,22 @@ void run_tagged_sha256_tests(void) {
0xE2, 0x76, 0x55, 0x9A, 0x3B, 0xDE, 0x55, 0xB3
};
secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount);
/* API test */
CHECK(secp256k1_tagged_sha256(none, hash32, tag, sizeof(tag), msg, sizeof(msg)) == 1);
CHECK(secp256k1_tagged_sha256(none, NULL, tag, sizeof(tag), msg, sizeof(msg)) == 0);
CHECK(secp256k1_tagged_sha256(ctx, hash32, tag, sizeof(tag), msg, sizeof(msg)) == 1);
CHECK(secp256k1_tagged_sha256(ctx, NULL, tag, sizeof(tag), msg, sizeof(msg)) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_tagged_sha256(none, hash32, NULL, 0, msg, sizeof(msg)) == 0);
CHECK(secp256k1_tagged_sha256(ctx, hash32, NULL, 0, msg, sizeof(msg)) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_tagged_sha256(none, hash32, tag, sizeof(tag), NULL, 0) == 0);
CHECK(secp256k1_tagged_sha256(ctx, hash32, tag, sizeof(tag), NULL, 0) == 0);
CHECK(ecount == 3);
/* Static test vector */
memcpy(tag, "tag", 3);
memcpy(msg, "msg", 3);
CHECK(secp256k1_tagged_sha256(none, hash32, tag, 3, msg, 3) == 1);
CHECK(secp256k1_tagged_sha256(ctx, hash32, tag, 3, msg, 3) == 1);
CHECK(secp256k1_memcmp_var(hash32, hash_expected, sizeof(hash32)) == 0);
secp256k1_context_destroy(none);
}
/***** RANDOM TESTS *****/
@ -814,7 +796,8 @@ uint64_t modinv2p64(uint64_t x) {
return w;
}
/* compute out = (a*b) mod m; if b=NULL, treat b=1.
/* compute out = (a*b) mod m; if b=NULL, treat b=1; if m=NULL, treat m=infinity.
*
* Out is a 512-bit number (represented as 32 uint16_t's in LE order). The other
* arguments are 256-bit numbers (represented as 16 uint16_t's in LE order). */
@ -856,45 +839,47 @@ void mulmod256(uint16_t* out, const uint16_t* a, const uint16_t* b, const uint16
}
}
/* Compute the highest set bit in m. */
for (i = 255; i >= 0; --i) {
if ((m[i >> 4] >> (i & 15)) & 1) {
m_bitlen = i;
break;
}
}
/* Try do mul -= m<<i, for i going down to 0, whenever the result is not negative */
for (i = mul_bitlen - m_bitlen; i >= 0; --i) {
uint16_t mul2[32];
int64_t cs;
/* Compute mul2 = mul - m<<i. */
cs = 0; /* accumulator */
for (j = 0; j < 32; ++j) { /* j loops over the output limbs in mul2. */
/* Compute sub: the 16 bits in m that will be subtracted from mul2[j]. */
uint16_t sub = 0;
int p;
for (p = 0; p < 16; ++p) { /* p loops over the bit positions in mul2[j]. */
int bitpos = j * 16 - i + p; /* bitpos is the correspond bit position in m. */
if (bitpos >= 0 && bitpos < 256) {
sub |= ((m[bitpos >> 4] >> (bitpos & 15)) & 1) << p;
}
if (m) {
/* Compute the highest set bit in m. */
for (i = 255; i >= 0; --i) {
if ((m[i >> 4] >> (i & 15)) & 1) {
m_bitlen = i;
break;
}
/* Add mul[j]-sub to accumulator, and shift bottom 16 bits out to mul2[j]. */
cs += mul[j];
cs -= sub;
mul2[j] = (cs & 0xFFFF);
cs >>= 16;
}
/* If remainder of subtraction is 0, set mul = mul2. */
if (cs == 0) {
memcpy(mul, mul2, sizeof(mul));
/* Try do mul -= m<<i, for i going down to 0, whenever the result is not negative */
for (i = mul_bitlen - m_bitlen; i >= 0; --i) {
uint16_t mul2[32];
int64_t cs;
/* Compute mul2 = mul - m<<i. */
cs = 0; /* accumulator */
for (j = 0; j < 32; ++j) { /* j loops over the output limbs in mul2. */
/* Compute sub: the 16 bits in m that will be subtracted from mul2[j]. */
uint16_t sub = 0;
int p;
for (p = 0; p < 16; ++p) { /* p loops over the bit positions in mul2[j]. */
int bitpos = j * 16 - i + p; /* bitpos is the correspond bit position in m. */
if (bitpos >= 0 && bitpos < 256) {
sub |= ((m[bitpos >> 4] >> (bitpos & 15)) & 1) << p;
}
}
/* Add mul[j]-sub to accumulator, and shift bottom 16 bits out to mul2[j]. */
cs += mul[j];
cs -= sub;
mul2[j] = (cs & 0xFFFF);
cs >>= 16;
}
/* If remainder of subtraction is 0, set mul = mul2. */
if (cs == 0) {
memcpy(mul, mul2, sizeof(mul));
}
}
/* Sanity check: test that all limbs higher than m's highest are zero */
for (i = (m_bitlen >> 4) + 1; i < 32; ++i) {
CHECK(mul[i] == 0);
}
}
/* Sanity check: test that all limbs higher than m's highest are zero */
for (i = (m_bitlen >> 4) + 1; i < 32; ++i) {
CHECK(mul[i] == 0);
}
memcpy(out, mul, 32);
}
@ -1710,8 +1695,305 @@ void run_modinv_tests(void) {
}
}
/***** SCALAR TESTS *****/
/***** INT128 TESTS *****/
#ifdef SECP256K1_WIDEMUL_INT128
/* Add two 256-bit numbers (represented as 16 uint16_t's in LE order) together mod 2^256. */
void add256(uint16_t* out, const uint16_t* a, const uint16_t* b) {
int i;
uint32_t carry = 0;
for (i = 0; i < 16; ++i) {
carry += a[i];
carry += b[i];
out[i] = carry;
carry >>= 16;
}
}
/* Negate a 256-bit number (represented as 16 uint16_t's in LE order) mod 2^256. */
void neg256(uint16_t* out, const uint16_t* a) {
int i;
uint32_t carry = 1;
for (i = 0; i < 16; ++i) {
carry += (uint16_t)~a[i];
out[i] = carry;
carry >>= 16;
}
}
/* Right-shift a 256-bit number (represented as 16 uint16_t's in LE order). */
void rshift256(uint16_t* out, const uint16_t* a, int n, int sign_extend) {
uint16_t sign = sign_extend && (a[15] >> 15);
int i, j;
for (i = 15; i >= 0; --i) {
uint16_t v = 0;
for (j = 0; j < 16; ++j) {
int frompos = i*16 + j + n;
if (frompos >= 256) {
v |= sign << j;
} else {
v |= ((uint16_t)((a[frompos >> 4] >> (frompos & 15)) & 1)) << j;
}
}
out[i] = v;
}
}
/* Load a 64-bit unsigned integer into an array of 16 uint16_t's in LE order representing a 256-bit value. */
void load256u64(uint16_t* out, uint64_t v, int is_signed) {
int i;
uint64_t sign = is_signed && (v >> 63) ? UINT64_MAX : 0;
for (i = 0; i < 4; ++i) {
out[i] = v >> (16 * i);
}
for (i = 4; i < 16; ++i) {
out[i] = sign;
}
}
/* Load a 128-bit unsigned integer into an array of 16 uint16_t's in LE order representing a 256-bit value. */
void load256two64(uint16_t* out, uint64_t hi, uint64_t lo, int is_signed) {
int i;
uint64_t sign = is_signed && (hi >> 63) ? UINT64_MAX : 0;
for (i = 0; i < 4; ++i) {
out[i] = lo >> (16 * i);
}
for (i = 4; i < 8; ++i) {
out[i] = hi >> (16 * (i - 4));
}
for (i = 8; i < 16; ++i) {
out[i] = sign;
}
}
/* Check whether the 256-bit value represented by array of 16-bit values is in range -2^127 < v < 2^127. */
int int256is127(const uint16_t* v) {
int all_0 = ((v[7] & 0x8000) == 0), all_1 = ((v[7] & 0x8000) == 0x8000);
int i;
for (i = 8; i < 16; ++i) {
if (v[i] != 0) all_0 = 0;
if (v[i] != 0xffff) all_1 = 0;
}
return all_0 || all_1;
}
void load256u128(uint16_t* out, const secp256k1_uint128* v) {
uint64_t lo = secp256k1_u128_to_u64(v), hi = secp256k1_u128_hi_u64(v);
load256two64(out, hi, lo, 0);
}
void load256i128(uint16_t* out, const secp256k1_int128* v) {
uint64_t lo;
int64_t hi;
secp256k1_int128 c = *v;
lo = secp256k1_i128_to_i64(&c);
secp256k1_i128_rshift(&c, 64);
hi = secp256k1_i128_to_i64(&c);
load256two64(out, hi, lo, 1);
}
void run_int128_test_case(void) {
unsigned char buf[32];
uint64_t v[4];
secp256k1_int128 swa, swz;
secp256k1_uint128 uwa, uwz;
uint64_t ub, uc;
int64_t sb, sc;
uint16_t rswa[16], rswz[32], rswr[32], ruwa[16], ruwz[32], ruwr[32];
uint16_t rub[16], ruc[16], rsb[16], rsc[16];
int i;
/* Generate 32-byte random value. */
secp256k1_testrand256_test(buf);
/* Convert into 4 64-bit integers. */
for (i = 0; i < 4; ++i) {
uint64_t vi = 0;
int j;
for (j = 0; j < 8; ++j) vi = (vi << 8) + buf[8*i + j];
v[i] = vi;
}
/* Convert those into a 128-bit value and two 64-bit values (signed and unsigned). */
secp256k1_u128_load(&uwa, v[1], v[0]);
secp256k1_i128_load(&swa, v[1], v[0]);
ub = v[2];
sb = v[2];
uc = v[3];
sc = v[3];
/* Load those also into 16-bit array representations. */
load256u128(ruwa, &uwa);
load256i128(rswa, &swa);
load256u64(rub, ub, 0);
load256u64(rsb, sb, 1);
load256u64(ruc, uc, 0);
load256u64(rsc, sc, 1);
/* test secp256k1_u128_mul */
mulmod256(ruwr, rub, ruc, NULL);
secp256k1_u128_mul(&uwz, ub, uc);
load256u128(ruwz, &uwz);
CHECK(secp256k1_memcmp_var(ruwr, ruwz, 16) == 0);
/* test secp256k1_u128_accum_mul */
mulmod256(ruwr, rub, ruc, NULL);
add256(ruwr, ruwr, ruwa);
uwz = uwa;
secp256k1_u128_accum_mul(&uwz, ub, uc);
load256u128(ruwz, &uwz);
CHECK(secp256k1_memcmp_var(ruwr, ruwz, 16) == 0);
/* test secp256k1_u128_accum_u64 */
add256(ruwr, rub, ruwa);
uwz = uwa;
secp256k1_u128_accum_u64(&uwz, ub);
load256u128(ruwz, &uwz);
CHECK(secp256k1_memcmp_var(ruwr, ruwz, 16) == 0);
/* test secp256k1_u128_rshift */
rshift256(ruwr, ruwa, uc % 128, 0);
uwz = uwa;
secp256k1_u128_rshift(&uwz, uc % 128);
load256u128(ruwz, &uwz);
CHECK(secp256k1_memcmp_var(ruwr, ruwz, 16) == 0);
/* test secp256k1_u128_to_u64 */
CHECK(secp256k1_u128_to_u64(&uwa) == v[0]);
/* test secp256k1_u128_hi_u64 */
CHECK(secp256k1_u128_hi_u64(&uwa) == v[1]);
/* test secp256k1_u128_from_u64 */
secp256k1_u128_from_u64(&uwz, ub);
load256u128(ruwz, &uwz);
CHECK(secp256k1_memcmp_var(rub, ruwz, 16) == 0);
/* test secp256k1_u128_check_bits */
{
int uwa_bits = 0;
int j;
for (j = 0; j < 128; ++j) {
if (ruwa[j / 16] >> (j % 16)) uwa_bits = 1 + j;
}
for (j = 0; j < 128; ++j) {
CHECK(secp256k1_u128_check_bits(&uwa, j) == (uwa_bits <= j));
}
}
/* test secp256k1_i128_mul */
mulmod256(rswr, rsb, rsc, NULL);
secp256k1_i128_mul(&swz, sb, sc);
load256i128(rswz, &swz);
CHECK(secp256k1_memcmp_var(rswr, rswz, 16) == 0);
/* test secp256k1_i128_accum_mul */
mulmod256(rswr, rsb, rsc, NULL);
add256(rswr, rswr, rswa);
if (int256is127(rswr)) {
swz = swa;
secp256k1_i128_accum_mul(&swz, sb, sc);
load256i128(rswz, &swz);
CHECK(secp256k1_memcmp_var(rswr, rswz, 16) == 0);
}
/* test secp256k1_i128_det */
{
uint16_t rsd[16], rse[16], rst[32];
int64_t sd = v[0], se = v[1];
load256u64(rsd, sd, 1);
load256u64(rse, se, 1);
mulmod256(rst, rsc, rsd, NULL);
neg256(rst, rst);
mulmod256(rswr, rsb, rse, NULL);
add256(rswr, rswr, rst);
secp256k1_i128_det(&swz, sb, sc, sd, se);
load256i128(rswz, &swz);
CHECK(secp256k1_memcmp_var(rswr, rswz, 16) == 0);
}
/* test secp256k1_i128_rshift */
rshift256(rswr, rswa, uc % 127, 1);
swz = swa;
secp256k1_i128_rshift(&swz, uc % 127);
load256i128(rswz, &swz);
CHECK(secp256k1_memcmp_var(rswr, rswz, 16) == 0);
/* test secp256k1_i128_to_i64 */
CHECK((uint64_t)secp256k1_i128_to_i64(&swa) == v[0]);
/* test secp256k1_i128_from_i64 */
secp256k1_i128_from_i64(&swz, sb);
load256i128(rswz, &swz);
CHECK(secp256k1_memcmp_var(rsb, rswz, 16) == 0);
/* test secp256k1_i128_eq_var */
{
int expect = (uc & 1);
swz = swa;
if (!expect) {
/* Make sure swz != swa */
uint64_t v0c = v[0], v1c = v[1];
if (ub & 64) {
v1c ^= (((uint64_t)1) << (ub & 63));
} else {
v0c ^= (((uint64_t)1) << (ub & 63));
}
secp256k1_i128_load(&swz, v1c, v0c);
}
CHECK(secp256k1_i128_eq_var(&swa, &swz) == expect);
}
/* test secp256k1_i128_check_pow2 */
{
int expect = (uc & 1);
int pos = ub % 127;
if (expect) {
/* If expect==1, set swz to exactly (2 << pos). */
uint64_t hi = 0;
uint64_t lo = 0;
if (pos & 64) {
hi = (((uint64_t)1) << (pos & 63));
} else {
lo = (((uint64_t)1) << (pos & 63));
}
secp256k1_i128_load(&swz, hi, lo);
} else {
/* If expect==0, set swz = swa, but update expect=1 if swa happens to equal (2 << pos). */
if (pos & 64) {
if ((v[1] == (((uint64_t)1) << (pos & 63))) && v[0] == 0) expect = 1;
} else {
if ((v[0] == (((uint64_t)1) << (pos & 63))) && v[1] == 0) expect = 1;
}
swz = swa;
}
CHECK(secp256k1_i128_check_pow2(&swz, pos) == expect);
}
}
void run_int128_tests(void) {
{ /* secp256k1_u128_accum_mul */
secp256k1_uint128 res;
/* Check secp256k1_u128_accum_mul overflow */
secp256k1_u128_mul(&res, UINT64_MAX, UINT64_MAX);
secp256k1_u128_accum_mul(&res, UINT64_MAX, UINT64_MAX);
CHECK(secp256k1_u128_to_u64(&res) == 2);
CHECK(secp256k1_u128_hi_u64(&res) == 18446744073709551612U);
}
{ /* secp256k1_u128_accum_mul */
secp256k1_int128 res;
/* Compute INT128_MAX = 2^127 - 1 with secp256k1_i128_accum_mul */
secp256k1_i128_mul(&res, INT64_MAX, INT64_MAX);
secp256k1_i128_accum_mul(&res, INT64_MAX, INT64_MAX);
CHECK(secp256k1_i128_to_i64(&res) == 2);
secp256k1_i128_accum_mul(&res, 4, 9223372036854775807);
secp256k1_i128_accum_mul(&res, 1, 1);
CHECK((uint64_t)secp256k1_i128_to_i64(&res) == UINT64_MAX);
secp256k1_i128_rshift(&res, 64);
CHECK(secp256k1_i128_to_i64(&res) == INT64_MAX);
/* Compute INT128_MIN = - 2^127 with secp256k1_i128_accum_mul */
secp256k1_i128_mul(&res, INT64_MAX, INT64_MIN);
CHECK(secp256k1_i128_to_i64(&res) == INT64_MIN);
secp256k1_i128_accum_mul(&res, INT64_MAX, INT64_MIN);
CHECK(secp256k1_i128_to_i64(&res) == 0);
secp256k1_i128_accum_mul(&res, 2, INT64_MIN);
CHECK(secp256k1_i128_to_i64(&res) == 0);
secp256k1_i128_rshift(&res, 64);
CHECK(secp256k1_i128_to_i64(&res) == INT64_MIN);
}
{
/* Randomized tests. */
int i;
for (i = 0; i < 256 * count; ++i) run_int128_test_case();
}
}
#endif
/***** SCALAR TESTS *****/
void scalar_test(void) {
secp256k1_scalar s;
@ -3562,6 +3844,22 @@ void run_gej(void) {
test_gej_cmov(&a, &b);
test_gej_cmov(&b, &a);
}
/* Tests for secp256k1_gej_eq_var */
for (i = 0; i < count; i++) {
secp256k1_fe fe;
random_gej_test(&a);
random_gej_test(&b);
CHECK(!secp256k1_gej_eq_var(&a, &b));
b = a;
random_field_element_test(&fe);
if (secp256k1_fe_is_zero(&fe)) {
continue;
}
secp256k1_gej_rescale(&a, &fe);
CHECK(secp256k1_gej_eq_var(&a, &b));
}
}
void test_ec_combine(void) {
@ -3767,17 +4065,12 @@ void run_ecmult_chain(void) {
0xB95CBCA2, 0xC77DA786, 0x539BE8FD, 0x53354D2D,
0x3B4F566A, 0xE6580454, 0x07ED6015, 0xEE1B2A88
);
secp256k1_gej_neg(&rp, &rp);
secp256k1_gej_add_var(&rp, &rp, &x, NULL);
CHECK(secp256k1_gej_is_infinity(&rp));
CHECK(secp256k1_gej_eq_var(&rp, &x));
}
}
/* redo the computation, but directly with the resulting ae and ge coefficients: */
secp256k1_ecmult(&x2, &a, &ae, &ge);
secp256k1_gej_neg(&x2, &x2);
secp256k1_gej_add_var(&x2, &x2, &x, NULL);
CHECK(secp256k1_gej_is_infinity(&x2));
CHECK(secp256k1_gej_eq_var(&x, &x2));
}
void test_point_times_order(const secp256k1_gej *point) {
@ -4070,16 +4363,12 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
/* only G scalar */
secp256k1_ecmult(&r2, &ptgj, &szero, &sc[0]);
CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &sc[0], ecmult_multi_callback, &data, 0));
secp256k1_gej_neg(&r2, &r2);
secp256k1_gej_add_var(&r, &r, &r2, NULL);
CHECK(secp256k1_gej_is_infinity(&r));
CHECK(secp256k1_gej_eq_var(&r, &r2));
/* 1-point */
secp256k1_ecmult(&r2, &ptgj, &sc[0], &szero);
CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 1));
secp256k1_gej_neg(&r2, &r2);
secp256k1_gej_add_var(&r, &r, &r2, NULL);
CHECK(secp256k1_gej_is_infinity(&r));
CHECK(secp256k1_gej_eq_var(&r, &r2));
/* Try to multiply 1 point, but callback returns false */
CHECK(!ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_false_callback, &data, 1));
@ -4087,16 +4376,12 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
/* 2-point */
secp256k1_ecmult(&r2, &ptgj, &sc[0], &sc[1]);
CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 2));
secp256k1_gej_neg(&r2, &r2);
secp256k1_gej_add_var(&r, &r, &r2, NULL);
CHECK(secp256k1_gej_is_infinity(&r));
CHECK(secp256k1_gej_eq_var(&r, &r2));
/* 2-point with G scalar */
secp256k1_ecmult(&r2, &ptgj, &sc[0], &sc[1]);
CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &sc[1], ecmult_multi_callback, &data, 1));
secp256k1_gej_neg(&r2, &r2);
secp256k1_gej_add_var(&r, &r, &r2, NULL);
CHECK(secp256k1_gej_is_infinity(&r));
CHECK(secp256k1_gej_eq_var(&r, &r2));
}
/* Check infinite outputs of various forms */
@ -4181,9 +4466,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
secp256k1_ecmult(&r2, &r, &sc[0], &szero);
CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 20));
secp256k1_gej_neg(&r2, &r2);
secp256k1_gej_add_var(&r, &r, &r2, NULL);
CHECK(secp256k1_gej_is_infinity(&r));
CHECK(secp256k1_gej_eq_var(&r, &r2));
}
/* Check random scalars, constant point */
@ -4204,9 +4487,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
secp256k1_gej_set_ge(&p0j, &pt[0]);
secp256k1_ecmult(&r2, &p0j, &rs, &szero);
CHECK(ecmult_multi(&ctx->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 20));
secp256k1_gej_neg(&r2, &r2);
secp256k1_gej_add_var(&r, &r, &r2, NULL);
CHECK(secp256k1_gej_is_infinity(&r));
CHECK(secp256k1_gej_eq_var(&r, &r2));
}
/* Sanity check that zero scalars don't cause problems */
@ -4268,9 +4549,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
secp256k1_ecmult(&expected, &ptgj, &tmp1, &szero);
CHECK(ecmult_multi(&ctx->error_callback, scratch, &actual, &szero, ecmult_multi_callback, &data, 2));
secp256k1_gej_neg(&expected, &expected);
secp256k1_gej_add_var(&actual, &actual, &expected, NULL);
CHECK(secp256k1_gej_is_infinity(&actual));
CHECK(secp256k1_gej_eq_var(&actual, &expected));
}
}
}
@ -4440,9 +4719,7 @@ int test_ecmult_multi_random(secp256k1_scratch *scratch) {
CHECK(ecmult_multi(&ctx->error_callback, scratch, &computed, g_scalar_ptr, ecmult_multi_callback, &data, filled));
mults += num_nonzero + g_nonzero;
/* Compare with expected result. */
secp256k1_gej_neg(&computed, &computed);
secp256k1_gej_add_var(&computed, &computed, &expected, NULL);
CHECK(secp256k1_gej_is_infinity(&computed));
CHECK(secp256k1_gej_eq_var(&computed, &expected));
return mults;
}
@ -5497,7 +5774,7 @@ void run_ec_pubkey_parse_test(void) {
ecount = 0;
VG_UNDEF(&pubkey, sizeof(pubkey));
CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 65) == 1);
CHECK(secp256k1_ec_pubkey_parse(secp256k1_context_no_precomp, &pubkey, pubkeyc, 65) == 1);
CHECK(secp256k1_ec_pubkey_parse(secp256k1_context_static, &pubkey, pubkeyc, 65) == 1);
VG_CHECK(&pubkey, sizeof(pubkey));
CHECK(ecount == 0);
VG_UNDEF(&ge, sizeof(ge));
@ -7083,19 +7360,27 @@ int main(int argc, char **argv) {
secp256k1_testrand_init(argc > 2 ? argv[2] : NULL);
/* initialize */
run_selftest_tests();
run_context_tests(0);
run_context_tests(1);
run_scratch_tests();
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
if (secp256k1_testrand_bits(1)) {
ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
/* Randomize the context only with probability 15/16
to make sure we test without context randomization from time to time.
TODO Reconsider this when recalibrating the tests. */
if (secp256k1_testrand_bits(4)) {
unsigned char rand32[32];
secp256k1_testrand256(rand32);
CHECK(secp256k1_context_randomize(ctx, secp256k1_testrand_bits(1) ? rand32 : NULL));
CHECK(secp256k1_context_randomize(ctx, rand32));
}
run_rand_bits();
run_rand_int();
#ifdef SECP256K1_WIDEMUL_INT128
run_int128_tests();
#endif
run_ctz_tests();
run_modinv_tests();
run_inverse_tests();

View File

@ -342,15 +342,15 @@ void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *grou
}
#ifdef ENABLE_MODULE_RECOVERY
#include "src/modules/recovery/tests_exhaustive_impl.h"
#include "modules/recovery/tests_exhaustive_impl.h"
#endif
#ifdef ENABLE_MODULE_EXTRAKEYS
#include "src/modules/extrakeys/tests_exhaustive_impl.h"
#include "modules/extrakeys/tests_exhaustive_impl.h"
#endif
#ifdef ENABLE_MODULE_SCHNORRSIG
#include "src/modules/schnorrsig/tests_exhaustive_impl.h"
#include "modules/schnorrsig/tests_exhaustive_impl.h"
#endif
int main(int argc, char** argv) {
@ -396,7 +396,7 @@ int main(int argc, char** argv) {
while (count--) {
/* Build context */
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
secp256k1_testrand256(rand32);
CHECK(secp256k1_context_randomize(ctx, rand32));

View File

@ -16,6 +16,11 @@
#include <stdio.h>
#include <limits.h>
#define STR_(x) #x
#define STR(x) STR_(x)
#define DEBUG_CONFIG_MSG(x) "DEBUG_CONFIG: " x
#define DEBUG_CONFIG_DEF(x) DEBUG_CONFIG_MSG(#x "=" STR(x))
typedef struct {
void (*fn)(const char *text, void* data);
const void* data;
@ -225,28 +230,36 @@ static SECP256K1_INLINE void secp256k1_int_cmov(int *r, const int *a, int flag)
*r = (int)(r_masked | a_masked);
}
/* If USE_FORCE_WIDEMUL_{INT128,INT64} is set, use that wide multiplication implementation.
* Otherwise use the presence of __SIZEOF_INT128__ to decide.
*/
#if defined(USE_FORCE_WIDEMUL_INT128)
#if defined(USE_FORCE_WIDEMUL_INT128_STRUCT)
/* If USE_FORCE_WIDEMUL_INT128_STRUCT is set, use int128_struct. */
# define SECP256K1_WIDEMUL_INT128 1
# define SECP256K1_INT128_STRUCT 1
#elif defined(USE_FORCE_WIDEMUL_INT128)
/* If USE_FORCE_WIDEMUL_INT128 is set, use int128. */
# define SECP256K1_WIDEMUL_INT128 1
# define SECP256K1_INT128_NATIVE 1
#elif defined(USE_FORCE_WIDEMUL_INT64)
/* If USE_FORCE_WIDEMUL_INT64 is set, use int64. */
# define SECP256K1_WIDEMUL_INT64 1
#elif defined(UINT128_MAX) || defined(__SIZEOF_INT128__)
/* If a native 128-bit integer type exists, use int128. */
# define SECP256K1_WIDEMUL_INT128 1
# define SECP256K1_INT128_NATIVE 1
#elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64))
/* On 64-bit MSVC targets (x86_64 and arm64), use int128_struct
* (which has special logic to implement using intrinsics on those systems). */
# define SECP256K1_WIDEMUL_INT128 1
# define SECP256K1_INT128_STRUCT 1
#elif SIZE_MAX > 0xffffffff
/* Systems with 64-bit pointers (and thus registers) very likely benefit from
* using 64-bit based arithmetic (even if we need to fall back to 32x32->64 based
* multiplication logic). */
# define SECP256K1_WIDEMUL_INT128 1
# define SECP256K1_INT128_STRUCT 1
#else
/* Lastly, fall back to int64 based arithmetic. */
# define SECP256K1_WIDEMUL_INT64 1
#endif
#if defined(SECP256K1_WIDEMUL_INT128)
# if !defined(UINT128_MAX) && defined(__SIZEOF_INT128__)
SECP256K1_GNUC_EXT typedef unsigned __int128 uint128_t;
SECP256K1_GNUC_EXT typedef __int128 int128_t;
#define UINT128_MAX ((uint128_t)(-1))
#define INT128_MAX ((int128_t)(UINT128_MAX >> 1))
#define INT128_MIN (-INT128_MAX - 1)
/* No (U)INT128_C macros because compilers providing __int128 do not support 128-bit literals. */
# endif
#endif
#ifndef __has_builtin
#define __has_builtin(x) 0

View File

@ -39,9 +39,7 @@ int main(void) {
fprintf(stderr, "Usage: libtool --mode=execute valgrind ./valgrind_ctime_test\n");
return 1;
}
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN
| SECP256K1_CONTEXT_VERIFY
| SECP256K1_CONTEXT_DECLASSIFY);
ctx = secp256k1_context_create(SECP256K1_CONTEXT_DECLASSIFY);
/** In theory, testing with a single secret input should be sufficient:
* If control flow depended on secrets the tool would generate an error.
*/

View File

@ -14,12 +14,7 @@
#include <string>
#include <vector>
void initialize_base_encode_decode()
{
static const ECCVerifyHandle verify_handle;
}
FUZZ_TARGET_INIT(base_encode_decode, initialize_base_encode_decode)
FUZZ_TARGET(base_encode_decode)
{
const std::string random_encoded_string(buffer.begin(), buffer.end());

View File

@ -19,7 +19,6 @@
void initialize_block()
{
static const ECCVerifyHandle verify_handle;
SelectParams(CBaseChainParams::REGTEST);
}

View File

@ -9,7 +9,6 @@
void initialize_descriptor_parse()
{
static const ECCVerifyHandle verify_handle;
ECC_Start();
SelectParams(CBaseChainParams::MAIN);
}

View File

@ -46,9 +46,6 @@ void initialize_deserialize()
{
static const auto testing_setup = MakeNoLogFileContext<>();
g_setup = testing_setup.get();
// Fuzzers using pubkey must hold an ECCVerifyHandle.
static const ECCVerifyHandle verify_handle;
}
#define FUZZ_TARGET_DESERIALIZE(name, code) \

View File

@ -9,12 +9,7 @@
#include <limits>
void initialize_eval_script()
{
static const ECCVerifyHandle verify_handle;
}
FUZZ_TARGET_INIT(eval_script, initialize_eval_script)
FUZZ_TARGET(eval_script)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
const unsigned int flags = fuzzed_data_provider.ConsumeIntegral<unsigned int>();

View File

@ -16,12 +16,7 @@
#include <string>
#include <vector>
void initialize_hex()
{
static const ECCVerifyHandle verify_handle;
}
FUZZ_TARGET_INIT(hex, initialize_hex)
FUZZ_TARGET(hex)
{
const std::string random_hex_string(buffer.begin(), buffer.end());
const std::vector<unsigned char> data = ParseHex(random_hex_string);

View File

@ -27,7 +27,6 @@
void initialize_key()
{
static const ECCVerifyHandle ecc_verify_handle;
ECC_Start();
SelectParams(CBaseChainParams::REGTEST);
}

View File

@ -13,7 +13,6 @@
void initialize_key_io()
{
static const ECCVerifyHandle verify_handle;
ECC_Start();
SelectParams(CBaseChainParams::MAIN);
}

View File

@ -18,7 +18,6 @@
void initialize_message()
{
static const ECCVerifyHandle ecc_verify_handle;
ECC_Start();
SelectParams(CBaseChainParams::REGTEST);
}

View File

@ -13,7 +13,6 @@
void initialize_parse_univalue()
{
static const ECCVerifyHandle verify_handle;
SelectParams(CBaseChainParams::REGTEST);
}

View File

@ -22,12 +22,7 @@ using node::AnalyzePSBT;
using node::PSBTAnalysis;
using node::PSBTInputAnalysis;
void initialize_psbt()
{
static const ECCVerifyHandle verify_handle;
}
FUZZ_TARGET_INIT(psbt, initialize_psbt)
FUZZ_TARGET(psbt)
{
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
PartiallySignedTransaction psbt_mut;

View File

@ -32,9 +32,6 @@
void initialize_script()
{
// Fuzzers using pubkey must hold an ECCVerifyHandle.
static const ECCVerifyHandle verify_handle;
SelectParams(CBaseChainParams::REGTEST);
}

View File

@ -184,10 +184,7 @@ void Test(const std::string& str)
}
}
void test_init()
{
static ECCVerifyHandle handle;
}
void test_init() {}
FUZZ_TARGET_INIT_HIDDEN(script_assets_test_minimizer, test_init, /*hidden=*/true)
{

View File

@ -11,12 +11,7 @@
#include <test/fuzz/fuzz.h>
void initialize_script_flags()
{
static const ECCVerifyHandle verify_handle;
}
FUZZ_TARGET_INIT(script_flags, initialize_script_flags)
FUZZ_TARGET(script_flags)
{
CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION);
try {

View File

@ -26,7 +26,6 @@
void initialize_script_sign()
{
static const ECCVerifyHandle ecc_verify_handle;
ECC_Start();
SelectParams(CBaseChainParams::REGTEST);
}

View File

@ -12,7 +12,7 @@
#include <vector>
bool SigHasLowR(const secp256k1_ecdsa_signature* sig);
int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char* input, size_t inputlen);
int ecdsa_signature_parse_der_lax(secp256k1_ecdsa_signature* sig, const unsigned char* input, size_t inputlen);
FUZZ_TARGET(secp256k1_ecdsa_signature_parse_der_lax)
{
@ -21,13 +21,11 @@ FUZZ_TARGET(secp256k1_ecdsa_signature_parse_der_lax)
if (signature_bytes.data() == nullptr) {
return;
}
secp256k1_context* secp256k1_context_verify = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
secp256k1_ecdsa_signature sig_der_lax;
const bool parsed_der_lax = ecdsa_signature_parse_der_lax(secp256k1_context_verify, &sig_der_lax, signature_bytes.data(), signature_bytes.size()) == 1;
const bool parsed_der_lax = ecdsa_signature_parse_der_lax(&sig_der_lax, signature_bytes.data(), signature_bytes.size()) == 1;
if (parsed_der_lax) {
ECC_Start();
(void)SigHasLowR(&sig_der_lax);
ECC_Stop();
}
secp256k1_context_destroy(secp256k1_context_verify);
}

View File

@ -14,11 +14,6 @@
#include <string>
#include <vector>
void initialize_signature_checker()
{
static const auto verify_handle = std::make_unique<ECCVerifyHandle>();
}
namespace {
class FuzzedSignatureChecker : public BaseSignatureChecker
{
@ -53,7 +48,7 @@ public:
};
} // namespace
FUZZ_TARGET_INIT(signature_checker, initialize_signature_checker)
FUZZ_TARGET(signature_checker)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
const unsigned int flags = fuzzed_data_provider.ConsumeIntegral<unsigned int>();