<...>
I am celebrating this post because today the patent covering this idea has finally expired, and this is going to be activated in the next bitcoin core release.
Thank you to all the great minds who contributed to this.
Link
Cheers Hal et al.
It was the Bitcointalk forum that inspired us to create Bitcointalksearch.org - Bitcointalk is an excellent site that should be the default page for anybody dealing in cryptocurrency, since it is a virtual gold-mine of data. However, our experience and user feedback led us create our site; Bitcointalk's search is slow, and difficult to get the results you need, because you need to log in first to find anything useful - furthermore, there are rate limiters for their search functionality.
The aim of our project is to create a faster website that yields more results and faster without having to create an account and eliminate the need to log in - your personal data, therefore, will never be in jeopardy since we are not asking for any of your data and you don't need to provide them to use our site with all of its capabilities.
We created this website with the sole purpose of users being able to search quickly and efficiently in the field of cryptocurrency so they will have access to the latest and most accurate information and thereby assisting the crypto-community at large.
#include
#include
#include
#include
#include
#define REPS 1000
// Split a secp256k1 exponent k into two smaller ones k1 and k2 such that for any point Y,
// k*Y = k1*Y + k2*Y', where Y' = lambda*Y is very fast
static int
splitk (BIGNUM *bnk1, BIGNUM *bnk2, const BIGNUM *bnk, const BIGNUM *bnn, BN_CTX *ctx)
{
BIGNUM *bnc1 = BN_new();
BIGNUM *bnc2 = BN_new();
BIGNUM *bnt1 = BN_new();
BIGNUM *bnt2 = BN_new();
BIGNUM *bnn2 = BN_new();
static unsigned char a1b2[] = {
0x30, 0x86, 0xd2, 0x21, 0xa7, 0xd4, 0x6b, 0xcd,
0xe8, 0x6c, 0x90, 0xe4, 0x92, 0x84, 0xeb, 0x15,
};
static unsigned char b1m[] = {
0xe4, 0x43, 0x7e, 0xd6, 0x01, 0x0e, 0x88, 0x28,
0x6f, 0x54, 0x7f, 0xa9, 0x0a, 0xbf, 0xe4, 0xc3,
};
static unsigned char a2[] = {
0x01, 0x14, 0xca, 0x50, 0xf7, 0xa8, 0xe2, 0xf3,
0xf6, 0x57, 0xc1, 0x10, 0x8d, 0x9d, 0x44, 0xcf,
0xd8,
};
BIGNUM *bna1b2 = BN_bin2bn(a1b2, sizeof(a1b2), NULL);
BIGNUM *bnb1m = BN_bin2bn(b1m, sizeof(b1m), NULL);
BIGNUM *bna2 = BN_bin2bn(a2, sizeof(a2), NULL);
BN_rshift1(bnn2, bnn);
BN_mul(bnc1, bnk, bna1b2, ctx);
BN_add(bnc1, bnc1, bnn2);
BN_div(bnc1, NULL, bnc1, bnn, ctx);
BN_mul(bnc2, bnk, bnb1m, ctx);
BN_add(bnc2, bnc2, bnn2);
BN_div(bnc2, NULL, bnc2, bnn, ctx);
BN_mul(bnt1, bnc1, bna1b2, ctx);
BN_mul(bnt2, bnc2, bna2, ctx);
BN_add(bnt1, bnt1, bnt2);
BN_sub(bnk1, bnk, bnt1);
BN_mul(bnt1, bnc1, bnb1m, ctx);
BN_mul(bnt2, bnc2, bna1b2, ctx);
BN_sub(bnk2, bnt1, bnt2);
BN_free(bnc1);
BN_free(bnc2);
BN_free(bnt1);
BN_free(bnt2);
BN_free(bnn2);
BN_free(bna1b2);
BN_free(bnb1m);
BN_free(bna2);
return 0;
}
static int
secp256k1Verify(const unsigned char hash[32], const unsigned char *dersig, size_t sigsize, const EC_KEY *pkey)
{
int rslt = 0;;
const EC_GROUP *group = EC_KEY_get0_group(pkey);
const EC_POINT *Y = EC_KEY_get0_public_key(pkey);
const EC_POINT *G = EC_GROUP_get0_generator(group);
EC_POINT *Glam = EC_POINT_new(group);
EC_POINT *Ylam = EC_POINT_new(group);
EC_POINT *R = EC_POINT_new(group);
const EC_POINT *Points[3];
const BIGNUM *bnexps[3];
BIGNUM *bnp = BN_new();
BIGNUM *bnn = BN_new();
BIGNUM *bnx = BN_new();
BIGNUM *bny = BN_new();
BIGNUM *bnk = BN_new();
BIGNUM *bnk1 = BN_new();
BIGNUM *bnk2 = BN_new();
BIGNUM *bnk1a = BN_new();
BIGNUM *bnk2a = BN_new();
BIGNUM *bnsinv = BN_new();
BIGNUM *bnh = BN_bin2bn(hash, 32, NULL);
static unsigned char beta[] = {
0x7a, 0xe9, 0x6a, 0x2b, 0x65, 0x7c, 0x07, 0x10,
0x6e, 0x64, 0x47, 0x9e, 0xac, 0x34, 0x34, 0xe9,
0x9c, 0xf0, 0x49, 0x75, 0x12, 0xf5, 0x89, 0x95,
0xc1, 0x39, 0x6c, 0x28, 0x71, 0x95, 0x01, 0xee,
};
BIGNUM *bnbeta = BN_bin2bn(beta, 32, NULL);
BN_CTX *ctx = BN_CTX_new();
ECDSA_SIG *sig = d2i_ECDSA_SIG(NULL, &dersig, sigsize);
if (sig == NULL)
goto done;
EC_GROUP_get_curve_GFp(group, bnp, NULL, NULL, ctx);
EC_GROUP_get_order(group, bnn, ctx);
if (BN_is_zero(sig->r) || BN_is_negative(sig->r) || BN_ucmp(sig->r, bnn) >= 0
|| BN_is_zero(sig->s) || BN_is_negative(sig->s) || BN_ucmp(sig->s, bnn) >= 0)
goto done;
EC_POINT_get_affine_coordinates_GFp(group, G, bnx, bny, ctx);
BN_mod_mul(bnx, bnx, bnbeta, bnp, ctx);
EC_POINT_set_affine_coordinates_GFp(group, Glam, bnx, bny, ctx);
EC_POINT_get_affine_coordinates_GFp(group, Y, bnx, bny, ctx);
BN_mod_mul(bnx, bnx, bnbeta, bnp, ctx);
EC_POINT_set_affine_coordinates_GFp(group, Ylam, bnx, bny, ctx);
Points[0] = Glam;
Points[1] = Y;
Points[2] = Ylam;
BN_mod_inverse(bnsinv, sig->s, bnn, ctx);
BN_mod_mul(bnk, bnh, bnsinv, bnn, ctx);
splitk(bnk1, bnk2, bnk, bnn, ctx);
bnexps[0] = bnk2;
BN_mod_mul(bnk, sig->r, bnsinv, bnn, ctx);
splitk(bnk1a, bnk2a, bnk, bnn, ctx);
bnexps[1] = bnk1a;
bnexps[2] = bnk2a;
EC_POINTs_mul(group, R, bnk1, 3, Points, bnexps, ctx);
EC_POINT_get_affine_coordinates_GFp(group, R, bnx, NULL, ctx);
BN_mod(bnx, bnx, bnn, ctx);
rslt = (BN_cmp(bnx, sig->r) == 0);
ECDSA_SIG_free(sig);
done:
EC_POINT_free(Glam);
EC_POINT_free(Ylam);
EC_POINT_free(R);
BN_free(bnp);
BN_free(bnn);
BN_free(bnx);
BN_free(bny);
BN_free(bnk);
BN_free(bnk1);
BN_free(bnk2);
BN_free(bnk1a);
BN_free(bnk2a);
BN_free(bnsinv);
BN_free(bnh);
BN_free(bnbeta);
BN_CTX_free(ctx);
return rslt;
}
main()
{
EC_KEY *pkey;
EC_GROUP *group;
const EC_POINT *ecpub;
unsigned char sig[100];
unsigned siglen = sizeof(sig);
unsigned char hash[32];
struct timeval tv1, tv2;
double time1, time2;
int i;
int rslt;
ENGINE_load_builtin_engines();
CRYPTO_malloc_init();
group = EC_GROUP_new_by_curve_name(NID_secp256k1);
pkey=EC_KEY_new();
EC_KEY_set_group(pkey,group);
EC_KEY_generate_key(pkey);
ecpub = EC_KEY_get0_public_key(pkey);
ECDSA_sign(0, hash, 32, sig, &siglen, pkey);
rslt = ECDSA_verify(0, hash, 32, sig, siglen, pkey);
printf("rslt = %d\n", rslt);
rslt = secp256k1Verify(hash, sig, siglen, pkey);
printf("rslt = %d\n", rslt);
hash[0]++;
rslt = ECDSA_verify(0, hash, 32, sig, siglen, pkey);
printf("rslt = %d\n", rslt);
rslt = secp256k1Verify(hash, sig, siglen, pkey);
printf("rslt = %d\n", rslt);
hash[0]--;
gettimeofday(&tv1, NULL);
for(i=0; irslt = ECDSA_verify(0, hash, 32, sig, siglen, pkey);
}
gettimeofday(&tv2, NULL);
printf("rslt = %d\n", rslt);
time1 = (tv2.tv_sec - tv1.tv_sec + (tv2.tv_usec - tv1.tv_usec)/1000000.) / REPS;
printf("time: %g\n", time1);
gettimeofday(&tv1, NULL);
for(i=0; irslt = secp256k1Verify(hash, sig, siglen, pkey);
}
gettimeofday(&tv2, NULL);
printf("rslt = %d\n", rslt);
time2 = (tv2.tv_sec - tv1.tv_sec + (tv2.tv_usec - tv1.tv_usec)/1000000.) / REPS;
printf("time: %g\n", time2);
printf("%f%% speedup\n", (time1-time2)/time1);
exit(0);
}