This introduces `secp256k1_context_set_sha256_compression()`, which allows users to provide their own SHA256 block-compression function at runtime. This is useful in setups where the fastest implementation can only be determined dynamically based on the available CPU features, and rebuilding the library is not possible. The callback is installed on the `secp256k1_context` and is then used by all operations that compute SHA256 hashes. As part of the setup, the library performs sanity checks to ensure that the supplied function is equivalent to the default transform. Passing NULL to the callback setter restores the built-in implementation.
162 lines
4.8 KiB
C
162 lines
4.8 KiB
C
/***********************************************************************
|
|
* Distributed under the MIT software license, see the accompanying *
|
|
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
|
***********************************************************************/
|
|
|
|
#ifndef SECP256K1_TESTUTIL_H
|
|
#define SECP256K1_TESTUTIL_H
|
|
|
|
#include "field.h"
|
|
#include "group.h"
|
|
#include "testrand.h"
|
|
#include "util.h"
|
|
|
|
/* Helper for when we need to check that the ctx-provided sha256 compression was called */
|
|
#define DEFINE_SHA256_TRANSFORM_PROBE(name) \
|
|
static int name##_called = 0; \
|
|
static void name(uint32_t *s, const unsigned char *msg, size_t rounds) { \
|
|
name##_called = 1; \
|
|
secp256k1_sha256_transform(s, msg, rounds); \
|
|
s[0] ^= 0xdeadbeef; /* intentional perturbation for testing */ \
|
|
}
|
|
|
|
/* group order of the secp256k1 curve in 32-byte big endian representation */
|
|
static const unsigned char secp256k1_group_order_bytes[32] = {
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
|
|
0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b,
|
|
0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41
|
|
};
|
|
|
|
static void testutil_random_fe(secp256k1_fe *x) {
|
|
unsigned char bin[32];
|
|
do {
|
|
testrand256(bin);
|
|
if (secp256k1_fe_set_b32_limit(x, bin)) {
|
|
return;
|
|
}
|
|
} while(1);
|
|
}
|
|
|
|
static void testutil_random_fe_non_zero(secp256k1_fe *nz) {
|
|
do {
|
|
testutil_random_fe(nz);
|
|
} while (secp256k1_fe_is_zero(nz));
|
|
}
|
|
|
|
static void testutil_random_fe_magnitude(secp256k1_fe *fe, int m) {
|
|
secp256k1_fe zero;
|
|
int n = testrand_int(m + 1);
|
|
secp256k1_fe_normalize(fe);
|
|
if (n == 0) {
|
|
return;
|
|
}
|
|
secp256k1_fe_set_int(&zero, 0);
|
|
secp256k1_fe_negate(&zero, &zero, 0);
|
|
secp256k1_fe_mul_int_unchecked(&zero, n - 1);
|
|
secp256k1_fe_add(fe, &zero);
|
|
#ifdef VERIFY
|
|
CHECK(fe->magnitude == n);
|
|
#endif
|
|
}
|
|
|
|
static void testutil_random_fe_test(secp256k1_fe *x) {
|
|
unsigned char bin[32];
|
|
do {
|
|
testrand256_test(bin);
|
|
if (secp256k1_fe_set_b32_limit(x, bin)) {
|
|
return;
|
|
}
|
|
} while(1);
|
|
}
|
|
|
|
static void testutil_random_fe_non_zero_test(secp256k1_fe *fe) {
|
|
do {
|
|
testutil_random_fe_test(fe);
|
|
} while(secp256k1_fe_is_zero(fe));
|
|
}
|
|
|
|
static void testutil_random_ge_x_magnitude(secp256k1_ge *ge) {
|
|
testutil_random_fe_magnitude(&ge->x, SECP256K1_GE_X_MAGNITUDE_MAX);
|
|
}
|
|
|
|
static void testutil_random_ge_y_magnitude(secp256k1_ge *ge) {
|
|
testutil_random_fe_magnitude(&ge->y, SECP256K1_GE_Y_MAGNITUDE_MAX);
|
|
}
|
|
|
|
static void testutil_random_gej_x_magnitude(secp256k1_gej *gej) {
|
|
testutil_random_fe_magnitude(&gej->x, SECP256K1_GEJ_X_MAGNITUDE_MAX);
|
|
}
|
|
|
|
static void testutil_random_gej_y_magnitude(secp256k1_gej *gej) {
|
|
testutil_random_fe_magnitude(&gej->y, SECP256K1_GEJ_Y_MAGNITUDE_MAX);
|
|
}
|
|
|
|
static void testutil_random_gej_z_magnitude(secp256k1_gej *gej) {
|
|
testutil_random_fe_magnitude(&gej->z, SECP256K1_GEJ_Z_MAGNITUDE_MAX);
|
|
}
|
|
|
|
static void testutil_random_ge_test(secp256k1_ge *ge) {
|
|
secp256k1_fe fe;
|
|
do {
|
|
testutil_random_fe_test(&fe);
|
|
if (secp256k1_ge_set_xo_var(ge, &fe, testrand_bits(1))) {
|
|
secp256k1_fe_normalize(&ge->y);
|
|
break;
|
|
}
|
|
} while(1);
|
|
}
|
|
|
|
static void testutil_random_ge_jacobian_test(secp256k1_gej *gej, const secp256k1_ge *ge) {
|
|
secp256k1_fe z;
|
|
testutil_random_fe_non_zero_test(&z);
|
|
secp256k1_gej_set_ge(gej, ge);
|
|
secp256k1_gej_rescale(gej, &z);
|
|
}
|
|
|
|
static void testutil_random_gej_test(secp256k1_gej *gej) {
|
|
secp256k1_ge ge;
|
|
testutil_random_ge_test(&ge);
|
|
testutil_random_ge_jacobian_test(gej, &ge);
|
|
}
|
|
|
|
static void testutil_random_pubkey_test(secp256k1_pubkey *pk) {
|
|
secp256k1_ge ge;
|
|
testutil_random_ge_test(&ge);
|
|
secp256k1_pubkey_save(pk, &ge);
|
|
}
|
|
|
|
static void testutil_random_scalar_order_test(secp256k1_scalar *num) {
|
|
do {
|
|
unsigned char b32[32];
|
|
int overflow = 0;
|
|
testrand256_test(b32);
|
|
secp256k1_scalar_set_b32(num, b32, &overflow);
|
|
if (overflow || secp256k1_scalar_is_zero(num)) {
|
|
continue;
|
|
}
|
|
break;
|
|
} while(1);
|
|
}
|
|
|
|
static void testutil_random_scalar_order(secp256k1_scalar *num) {
|
|
do {
|
|
unsigned char b32[32];
|
|
int overflow = 0;
|
|
testrand256(b32);
|
|
secp256k1_scalar_set_b32(num, b32, &overflow);
|
|
if (overflow || secp256k1_scalar_is_zero(num)) {
|
|
continue;
|
|
}
|
|
break;
|
|
} while(1);
|
|
}
|
|
|
|
static void testutil_random_scalar_order_b32(unsigned char *b32) {
|
|
secp256k1_scalar num;
|
|
testutil_random_scalar_order(&num);
|
|
secp256k1_scalar_get_b32(b32, &num);
|
|
}
|
|
|
|
#endif /* SECP256K1_TESTUTIL_H */
|