From f24c60c08d0b42ff055f86acff2f8afcf114a1e2 Mon Sep 17 00:00:00 2001 From: AlbertoBSD Date: Sat, 3 Apr 2021 02:27:40 +0200 Subject: [PATCH] bPtable create by secp256k1 first test --- Makefile | 14 +- keyhunt.c | 235 ++++---- secp256k1/Int.cpp | 1057 +++++++++++++++++++++++++++++++++++ secp256k1/Int.h | 295 ++++++++++ secp256k1/IntGroup.cpp | 58 ++ secp256k1/IntGroup.h | 41 ++ secp256k1/IntMod.cpp | 1169 +++++++++++++++++++++++++++++++++++++++ secp256k1/Point.cpp | 89 +++ secp256k1/Point.h | 46 ++ secp256k1/Random.cpp | 117 ++++ secp256k1/Random.h | 25 + secp256k1/SECP256K1.cpp | 422 ++++++++++++++ secp256k1/SECP256k1.h | 55 ++ secp256k1/test | Bin 0 -> 63208 bytes secp256k1/test.c | 42 ++ secp256k1/util.c | 167 ++++++ secp256k1/util.h | 30 + util.c | 167 ++++++ util.h | 168 +----- 19 files changed, 3920 insertions(+), 277 deletions(-) create mode 100644 secp256k1/Int.cpp create mode 100644 secp256k1/Int.h create mode 100644 secp256k1/IntGroup.cpp create mode 100644 secp256k1/IntGroup.h create mode 100644 secp256k1/IntMod.cpp create mode 100644 secp256k1/Point.cpp create mode 100644 secp256k1/Point.h create mode 100644 secp256k1/Random.cpp create mode 100644 secp256k1/Random.h create mode 100644 secp256k1/SECP256K1.cpp create mode 100644 secp256k1/SECP256k1.h create mode 100755 secp256k1/test create mode 100644 secp256k1/test.c create mode 100644 secp256k1/util.c create mode 100644 secp256k1/util.h create mode 100644 util.c diff --git a/Makefile b/Makefile index c1cfdd2..c18e330 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,19 @@ default: gcc -O3 -c bloom/bloom.c -o bloom.o - gcc -O3 -c sha256/sha256.c -o sha256.o + g++ -O3 -c sha256/sha256.c -o sha256.o gcc -O3 -c base58/base58.c -o base58.o gcc -O3 -c rmd160/rmd160.c -o rmd160.o gcc -O3 -c sha3/sha3.c -o sha3.o gcc -O3 -c xxhash/xxhash.c -o xxhash.o - gcc -O3 -c keyhunt.c -o keyhunt.o -lm - gcc -o keyhunt keyhunt.o base58.o rmd160.o sha256.o bloom.o xxhash.o -lgmp -lm -lpthread - gcc -O3 hexcharstoraw.c -o hexcharstoraw -lm + g++ -O3 -c util.c -o util.o + g++ -m64 -mssse3 -Wno-unused-result -Wno-write-strings -O2 -c secp256k1/Int.cpp -o Int.o + g++ -m64 -mssse3 -Wno-unused-result -Wno-write-strings -O2 -c secp256k1/Point.cpp -o Point.o + g++ -m64 -mssse3 -Wno-unused-result -Wno-write-strings -O2 -c secp256k1/SECP256K1.cpp -o SECP256K1.o + g++ -m64 -mssse3 -Wno-unused-result -Wno-write-strings -O2 -c secp256k1/IntMod.cpp -o IntMod.o + g++ -m64 -mssse3 -Wno-unused-result -Wno-write-strings -O2 -c secp256k1/Random.cpp -o Random.o + g++ -m64 -mssse3 -Wno-unused-result -Wno-write-strings -O2 -c secp256k1/IntGroup.cpp -o IntGroup.o + g++ -o keyhunt keyhunt.c base58.o rmd160.o sha256.o bloom.o xxhash.o util.o Int.o Point.o SECP256K1.o IntMod.o Random.o IntGroup.o -lgmp -lm -lpthread + gcc -O3 hexcharstoraw.c -o hexcharstoraw util.o -lm gcc -o bPfile bPfile.c -lgmp -lm clean: rm -r *.o diff --git a/keyhunt.c b/keyhunt.c index 3aa8f55..6d17e18 100644 --- a/keyhunt.c +++ b/keyhunt.c @@ -18,6 +18,11 @@ email: alberto.bsd@gmail.com #include "sha256/sha256.h" #include "bloom/bloom.h" #include "sha3/sha3.h" + +#include "secp256k1/SECP256k1.h" +#include "secp256k1/Point.h" +#include "secp256k1/Int.h" + #include "util.h" #ifdef WIN32 #include @@ -39,7 +44,7 @@ email: alberto.bsd@gmail.com #define SEARCH_BOTH 2 -struct Point { +struct strPoint { mpz_t x; mpz_t y; }; @@ -88,12 +93,12 @@ const char *EC_constant_N = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD const char *EC_constant_P = "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"; const char *EC_constant_Gx = "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"; const char *EC_constant_Gy = "483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"; -struct Point DoublingG[256]; +struct strPoint DoublingG[256]; -void Point_Doubling(struct Point *P, struct Point *R); -void Point_Addition(struct Point *P, struct Point *Q, struct Point *R); -void Scalar_Multiplication(struct Point P, struct Point *R, mpz_t m); -void Point_Negation(struct Point *A, struct Point *S); +void Point_Doubling(struct strPoint *P, struct strPoint *R); +void Point_Addition(struct strPoint *P, struct strPoint *Q, struct strPoint *R); +void Scalar_Multiplication(struct strPoint P, struct strPoint *R, mpz_t m); +void Point_Negation(struct strPoint *A, struct strPoint *S); int searchbinary(struct address_value *buffer,char *data,int64_t _N); void sleep_ms(int milliseconds); @@ -115,7 +120,7 @@ int64_t bsgs_partition(struct bsgs_xvalue *arr, int64_t n); int bsgs_searchbinary(struct bsgs_xvalue *arr,char *data,int64_t _N,uint64_t *r_value); -int bsgs_secondcheck(mpz_t start_range,uint32_t a,struct Point *target,mpz_t *private); +int bsgs_secondcheck(mpz_t start_range,uint32_t a,struct strPoint *target,mpz_t *privatekey); void *thread_process(void *vargp); void *thread_process_bsgs(void *vargp); @@ -124,7 +129,7 @@ void *thread_bPload(void *vargp); void *thread_bPloadFile(void *vargp); void *thread_pub2rmd(void *vargp); -void init_doublingG(struct Point *P); +void init_doublingG(struct strPoint *P); char *publickeytohashrmd160(char *pkey,int length); char *pubkeytopubaddress(char *pkey,int length); //char *pubkeytopubaddress_eth(char *pkey,int length); @@ -147,7 +152,7 @@ pthread_mutex_t bsgs_thread; struct Elliptic_Curve EC; struct bloom dummybloom; struct bloom bloom; -struct Point G; +struct strPoint G; unsigned int *steps = NULL; unsigned int *ends = NULL; @@ -192,7 +197,7 @@ uint64_t BSGS_BUFFERREGISTERLENGTH = 36; BSGS Variables */ int *bsgs_found; -struct Point *OriginalPointsBSGS; +struct strPoint *OriginalPointsBSGS; struct bsgs_xvalue *bPtable; struct address_value *addressTable; struct bloom bloom_bP[256]; @@ -212,19 +217,22 @@ mpz_t BSGS_M; //M is squareroot(N) mpz_t BSGS_M2; mpz_t TWO; mpz_t MPZAUX; -struct Point BSGS_P; //Original P is actually G, but this P value change over time for calculations -struct Point BSGS_MP; //MP values this is m * P -struct Point BSGS_MP2; //MP values this is m2 * P -struct Point *BSGS_AMP; -struct Point *BSGS_AMP2; +struct strPoint BSGS_P; //Original P is actually G, but this P value change over time for calculations +struct strPoint BSGS_MP; //MP values this is m * P +struct strPoint BSGS_MP2; //MP values this is m2 * P +struct strPoint *BSGS_AMP; +struct strPoint *BSGS_AMP2; -struct Point point_temp,point_temp2; //Temp value for some process +struct strPoint point_temp,point_temp2; //Temp value for some process mpz_t n_range_start; mpz_t n_range_end; mpz_t n_range_diff; mpz_t n_range_aux; + +Secp256K1 *secp; + int main(int argc, char **argv) { char buffer[1024]; char temporal[65]; @@ -242,8 +250,12 @@ int main(int argc, char **argv) { struct bPload *temp; int c; + secp = new Secp256K1(); + secp->Init(); + gmp_randinit_mt(state); - gmp_randseed_ui(state, ((int)clock()) + ((int)time(NULL)) ); + gmp_randseed_ui(state, ((int)clock()) + ((int)time(NULL))); + mpz_init_set_str(EC.p, EC_constant_P, 16); mpz_init_set_str(EC.n, EC_constant_N, 16); mpz_init_set_str(G.x , EC_constant_Gx, 16); @@ -565,7 +577,7 @@ int main(int argc, char **argv) { } N = 0; if(FLAGMODE != MODE_BSGS) { - aux = malloc(1000); + aux =(char*) malloc(1000); if(aux == NULL) { fprintf(stderr,"[E] error malloc()\n"); } @@ -639,17 +651,17 @@ int main(int argc, char **argv) { } fseek(fd,0,SEEK_SET); - printf("[+] Allocating memory for %"PRIu64" elements: %.2f MB\n",N,(double)(((double) sizeof(struct address_value)*N)/(double)1048576)); + printf("[+] Allocating memory for %" PRIu64 " elements: %.2f MB\n",N,(double)(((double) sizeof(struct address_value)*N)/(double)1048576)); i = 0; do { - addressTable = malloc(sizeof(struct address_value)*N); + addressTable = (struct address_value*) malloc(sizeof(struct address_value)*N); i++; } while(addressTable == NULL && i < 10); if(addressTable == NULL) { - fprintf(stderr,"[E] Can't alloc memory for %"PRIu64" elements\n",N); + fprintf(stderr,"[E] Can't alloc memory for %" PRIu64 " elements\n",N); exit(0); } - printf("[+] Initializing bloom filter for %"PRIu64" elements.\n",N); + printf("[+] Initializing bloom filter for %" PRIu64 " elements.\n",N); if(N <= 1000) { if(bloom_init2(&bloom,1000,0.00001) == 1){ fprintf(stderr,"[E] error bloom_init for 10000 elements.\n"); @@ -667,7 +679,7 @@ int main(int argc, char **argv) { i = 0; switch (FLAGMODE) { case MODE_ADDRESS: - aux = malloc(2*MAXLENGTHADDRESS); + aux =(char*) malloc(2*MAXLENGTHADDRESS); if(aux == NULL) { fprintf(stderr,"[E] error malloc()\n"); exit(0); @@ -690,7 +702,7 @@ int main(int argc, char **argv) { break; case MODE_XPOINT: if(FLAGRAWDATA) { - aux = malloc(MAXLENGTHADDRESS); + aux = (char*)malloc(MAXLENGTHADDRESS); if(aux == NULL) { fprintf(stderr,"[E] error malloc()\n"); exit(0); @@ -704,7 +716,7 @@ int main(int argc, char **argv) { } } else { - aux = malloc(5*MAXLENGTHADDRESS); + aux = (char*) malloc(5*MAXLENGTHADDRESS); if(aux == NULL) { fprintf(stderr,"[E] error malloc()\n"); exit(0); @@ -722,7 +734,7 @@ int main(int argc, char **argv) { if(isValidHex(hextemp)) { switch(lenaux) { case 64: /*X value*/ - r = hexs2bin(aux,rawvalue); + r = hexs2bin(aux,(uint8_t*) rawvalue); if(r) { memcpy(addressTable[i].value,rawvalue,20); bloom_add(&bloom,rawvalue,MAXLENGTHADDRESS); @@ -732,7 +744,7 @@ int main(int argc, char **argv) { } break; case 66: /*Compress publickey*/ - r = hexs2bin(aux+2,rawvalue); + r = hexs2bin(aux+2, (uint8_t*)rawvalue); if(r) { memcpy(addressTable[i].value,rawvalue,20); bloom_add(&bloom,rawvalue,MAXLENGTHADDRESS); @@ -744,7 +756,7 @@ int main(int argc, char **argv) { case 130: /* Uncompress publickey length*/ memset(temporal,0,65); memcpy(temporal,aux+2,64); - r = hexs2bin(temporal,rawvalue); + r = hexs2bin(temporal, (uint8_t*) rawvalue); if(r) { memcpy(addressTable[i].value,rawvalue,20); bloom_add(&bloom,rawvalue,MAXLENGTHADDRESS); @@ -775,7 +787,7 @@ int main(int argc, char **argv) { case MODE_PUB2RMD: case MODE_RMD160: if(FLAGRAWDATA) { - aux = malloc(MAXLENGTHADDRESS); + aux = (char*) malloc(MAXLENGTHADDRESS); if(aux == NULL) { fprintf(stderr,"[E] error malloc()\n"); exit(0); @@ -789,7 +801,7 @@ int main(int argc, char **argv) { } } else { - aux = malloc(3*MAXLENGTHADDRESS); + aux = (char*) malloc(3*MAXLENGTHADDRESS); if(aux == NULL) { fprintf(stderr,"[E] error malloc()\n"); exit(0); @@ -831,18 +843,18 @@ int main(int argc, char **argv) { printf("[+] Bloomfilter completed\n"); if(FLAGALREADYSORTED) { printf("[+] File mark already sorted, skipping sort proccess\n"); - printf("[+] %"PRIu64" values were loaded\n",N); + printf("[+] %" PRIu64 " values were loaded\n",N); _sort(addressTable,N); } else { printf("[+] Sorting data\n"); _sort(addressTable,N); - printf("[+] %"PRIu64" values were loaded and sorted\n",N); + printf("[+] %" PRIu64 " values were loaded and sorted\n",N); } } if(FLAGMODE == MODE_BSGS) { DEBUGCOUNT = N_SECUENTIAL_MAX ; - aux = malloc(1024); + aux = (char*) malloc(1024); if(aux == NULL) { fprintf(stderr,"[E] error malloc()\n"); exit(0); @@ -864,10 +876,10 @@ int main(int argc, char **argv) { fprintf(stderr,"[E] There is no valid data in the file\n"); exit(0); } - bsgs_found = calloc(N,sizeof(int)); - OriginalPointsBSGS = malloc(N*sizeof(struct Point)); - pointx_str = malloc(65); - pointy_str = malloc(65); + bsgs_found = (int*) calloc(N,sizeof(int)); + OriginalPointsBSGS = (struct strPoint*) malloc(N*sizeof(struct strPoint)); + pointx_str = (char*) malloc(65); + pointy_str = (char*) malloc(65); if(OriginalPointsBSGS == NULL || pointy_str == NULL || pointx_str == NULL || bsgs_found == NULL) { fprintf(stderr,"[E] error malloc()\n"); exit(0); @@ -1051,7 +1063,7 @@ int main(int argc, char **argv) { bsgs_aux = mpz_get_ui(BSGS_AUX); DEBUGCOUNT = (uint64_t)((uint64_t)bsgs_m * (uint64_t)bsgs_aux); - printf("[+] Setting N up to %"PRIu64".\n",DEBUGCOUNT); + printf("[+] Setting N up to %" PRIu64 ".\n",DEBUGCOUNT); itemsbloom = ((uint64_t)(bsgs_m/256)) > 1000 ? (uint64_t)(bsgs_m/256) : 1000; itemsbloom2 = bsgs_m2 > 1000 ? bsgs_m : 1000; @@ -1076,7 +1088,7 @@ int main(int argc, char **argv) { } } if(continuebloom == 1) { - if(bloom_loadcustom(&bloom_bPx2nd,"bPx2nd") == 1) { + if(bloom_loadcustom(&bloom_bPx2nd,(char*)"bPx2nd") == 1) { continuebloom == 0; } else { @@ -1106,7 +1118,7 @@ int main(int argc, char **argv) { */ for(i=0; i< 256; i++) { if(bloom_init2(&bloom_bP[i],itemsbloom,0.000001) == 1){ - fprintf(stderr,"[E] error bloom_init [%"PRIu64"]\n",i); + fprintf(stderr,"[E] error bloom_init [%" PRIu64 "]\n",i); exit(0); } bloom_bP_totalbytes += bloom_bP[i].bytes; @@ -1133,16 +1145,16 @@ int main(int argc, char **argv) { Scalar_Multiplication(G,&BSGS_MP,BSGS_M); Scalar_Multiplication(G,&BSGS_MP2,BSGS_M2); - printf("[+] Allocating %.1f MB for %"PRIu64" aMP Points\n",(double)(((double)(bsgs_aux*sizeof(struct Point)))/(double)1048576),bsgs_aux); + printf("[+] Allocating %.1f MB for %" PRIu64 " aMP Points\n",(double)(((double)(bsgs_aux*sizeof(struct strPoint)))/(double)1048576),bsgs_aux); i = 0; - BSGS_AMP = malloc((uint64_t)((uint64_t)bsgs_aux*(uint64_t)sizeof(struct Point))); + BSGS_AMP = (struct strPoint*) malloc((uint64_t)((uint64_t)bsgs_aux*(uint64_t)sizeof(struct strPoint))); if(BSGS_AMP == NULL) { printf("[E] error malloc()\n"); exit(0); } - //printf("[+] Allocating %.1f MB for aMP Points (2nd)\n",(float)(((uint64_t)(bsgs_m2*sizeof(struct Point)))/(uint64_t)1048576)); - BSGS_AMP2 = malloc((uint64_t)((uint64_t)bsgs_m2*(uint64_t)sizeof(struct Point))); + //printf("[+] Allocating %.1f MB for aMP Points (2nd)\n",(float)(((uint64_t)(bsgs_m2*sizeof(struct strPoint)))/(uint64_t)1048576)); + BSGS_AMP2 = (struct strPoint*) malloc((uint64_t)((uint64_t)bsgs_m2*(uint64_t)sizeof(struct strPoint))); if(BSGS_AMP2 == NULL) { printf("[E] error malloc()\n"); exit(0); @@ -1185,7 +1197,7 @@ int main(int argc, char **argv) { } } else { - printf("[+] Precalculating %"PRIu64" aMP points\n",bsgs_aux); + printf("[+] Precalculating %" PRIu64 " aMP points\n",bsgs_aux); mpz_set(point_temp.x,BSGS_MP.x); mpz_set(point_temp.y,BSGS_MP.y); for(i = 0; i < bsgs_aux; i++) { @@ -1209,9 +1221,9 @@ int main(int argc, char **argv) { mpz_set(point_temp.x,point_temp2.x); mpz_set(point_temp.y,point_temp2.y); } - printf("[+] Allocating %.2f MB for %"PRIu64 " bP Points\n",(double)((double)((uint64_t)bsgs_m2*(uint64_t)sizeof(struct bsgs_xvalue))/(double)1048576),bsgs_m2); + printf("[+] Allocating %.2f MB for %" PRIu64 " bP Points\n",(double)((double)((uint64_t)bsgs_m2*(uint64_t)sizeof(struct bsgs_xvalue))/(double)1048576),bsgs_m2); //printf("[+] Allocating %.2f MB for bP Points\n",(float)((uint64_t)((uint64_t)bsgs_m*(uint64_t)sizeof(struct bsgs_xvalue))/(uint64_t)1048576)); - bPtable = calloc(bsgs_m2,sizeof(struct bsgs_xvalue)); + bPtable = (struct bsgs_xvalue*) calloc(bsgs_m2,sizeof(struct bsgs_xvalue)); if(bPtable == NULL) { printf("[E] error malloc()\n"); exit(0); @@ -1221,7 +1233,7 @@ int main(int argc, char **argv) { BASE = 0; PERTHREAD = bsgs_m /NTHREADS; PERTHREAD_R = bsgs_m % NTHREADS; - temp = calloc(NTHREADS,sizeof(struct bPload)); + temp = (struct bPload *) calloc(NTHREADS,sizeof(struct bPload)); tid = (pthread_t *) calloc(NTHREADS,sizeof(pthread_t)); if(FLAGPRECALCUTED_P_FILE) { @@ -1284,7 +1296,7 @@ int main(int argc, char **argv) { tid = (pthread_t *) calloc(NTHREADS,sizeof(pthread_t)); DEBUGCOUNT = (uint64_t)((uint64_t)bsgs_m * (uint64_t)bsgs_aux); for(i= 0;i < NTHREADS; i++) { - tt = malloc(sizeof(struct tothread)); + tt = (tothread*) malloc(sizeof(struct tothread)); tt->nt = i; if(FLAGRANDOM) { s = pthread_create(&tid[i],NULL,thread_process_bsgs_random,(void *)tt); @@ -1306,7 +1318,7 @@ int main(int argc, char **argv) { tid = (pthread_t *) calloc(NTHREADS,sizeof(pthread_t)); for(i= 0;i < NTHREADS; i++) { - tt = malloc(sizeof(struct tothread)); + tt = (tothread*) malloc(sizeof(struct tothread)); tt->nt = i; steps[i] = 0; switch(FLAGMODE) { @@ -1329,7 +1341,7 @@ int main(int argc, char **argv) { mpz_init(total); mpz_init(pretotal); mpz_init(debugcount_mpz); - sprintf(temporal,"%"PRIu64,DEBUGCOUNT); + sprintf(temporal,"%" PRIu64 ,DEBUGCOUNT); //printf("[I] Debug count : %s\n",temporal); mpz_set_str(debugcount_mpz,temporal,10); seconds = 0; @@ -1358,10 +1370,10 @@ int main(int argc, char **argv) { mpz_fdiv_q_ui(pretotal,total,seconds); pthread_mutex_lock(&bsgs_thread); if(THREADOUTPUT == 1) { - gmp_sprintf(buffer,"\nTotal %Zu keys in %"PRIu64 " seconds: %Zu keys/s\r",total,seconds,pretotal); + gmp_sprintf(buffer,"\nTotal %Zu keys in %" PRIu64 " seconds: %Zu keys/s\r",total,seconds,pretotal); } else { - gmp_sprintf(buffer,"\rTotal %Zu keys in %"PRIu64" seconds: %Zu keys/s\r",total,seconds,pretotal); + gmp_sprintf(buffer,"\rTotal %Zu keys in %" PRIu64 " seconds: %Zu keys/s\r",total,seconds,pretotal); } printf("%s",buffer); fflush(stdout); @@ -1373,7 +1385,7 @@ int main(int argc, char **argv) { }while(continue_flag); } -void Point_Doubling(struct Point *P, struct Point *R) { +void Point_Doubling(struct strPoint *P, struct strPoint *R) { mpz_t slope, temp; mpz_init(temp); mpz_init(slope); @@ -1400,7 +1412,7 @@ void Point_Doubling(struct Point *P, struct Point *R) { mpz_clear(slope); } -void Point_Addition(struct Point *P, struct Point *Q, struct Point *R) { +void Point_Addition(struct strPoint *P, struct strPoint *Q, struct strPoint *R) { mpz_t PA_temp,PA_slope; mpz_init(PA_temp); mpz_init(PA_slope); @@ -1453,8 +1465,8 @@ void Point_Addition(struct Point *P, struct Point *Q, struct Point *R) { mpz_clear(PA_slope); } -void Scalar_Multiplication(struct Point P, struct Point *R, mpz_t m) { - struct Point SM_T,SM_Q; +void Scalar_Multiplication(struct strPoint P, struct strPoint *R, mpz_t m) { + struct strPoint SM_T,SM_Q; int no_of_bits, i; no_of_bits = mpz_sizeinbase(m, 2); mpz_init_set_ui(SM_Q.x,0); @@ -1482,7 +1494,7 @@ void Scalar_Multiplication(struct Point P, struct Point *R, mpz_t m) { mpz_clear(SM_Q.y); } -void Point_Negation(struct Point *A, struct Point *S) { +void Point_Negation(struct strPoint *A, struct strPoint *S) { mpz_sub(S->y, EC.p, A->y); mpz_set(S->x, A->x); } @@ -1490,7 +1502,7 @@ void Point_Negation(struct Point *A, struct Point *S) { /* Precalculate G Doublings for Scalar_Multiplication */ -void init_doublingG(struct Point *P) { +void init_doublingG(struct strPoint *P) { int i = 0; mpz_init(DoublingG[i].x); mpz_init(DoublingG[i].y); @@ -1527,8 +1539,8 @@ char *pubkeytopubaddress_eth(char *pkey,int length) { */ char *pubkeytopubaddress(char *pkey,int length) { - char *pubaddress = calloc(MAXLENGTHADDRESS+10,1); - char *digest = calloc(60,1); + char *pubaddress = (char*) calloc(MAXLENGTHADDRESS+10,1); + char *digest = (char*) calloc(60,1); size_t pubaddress_size = MAXLENGTHADDRESS+10; if(pubaddress == NULL || digest == NULL) { fprintf(stderr,"error malloc()\n"); @@ -1553,8 +1565,8 @@ char *pubkeytopubaddress(char *pkey,int length) { } char *publickeytohashrmd160(char *pkey,int length) { - char *hash160 = malloc(20); - char *digest = malloc(32); + char *hash160 = (char*) malloc(20); + char *digest = (char*) malloc(32); if(hash160 == NULL || digest == NULL) { fprintf(stderr,"error malloc()\n"); exit(0); @@ -1597,7 +1609,7 @@ int searchbinary(struct address_value *buffer,char *data,int64_t _N) { void *thread_process(void *vargp) { struct tothread *tt; - struct Point R,temporal; + struct strPoint R,temporal; uint64_t count = 0; int r,thread_number,found,continue_flag = 1; char public_key_compressed[33],public_key_uncompressed[65],hexstrpoint[65]; @@ -1679,7 +1691,7 @@ void *thread_process(void *vargp) { if(FLAGVANITY) { if(FLAGSEARCH == SEARCH_UNCOMPRESS || FLAGSEARCH == SEARCH_BOTH){ if(strncmp(public_address_uncompressed,vanity,len_vanity) == 0) { - hextemp = malloc(65); + hextemp = (char*) malloc(65); gmp_sprintf(hextemp,"%0.64Zx",key_mpz); vanityKeys = fopen("vanitykeys.txt","a+"); if(vanityKeys != NULL) { @@ -1692,7 +1704,7 @@ void *thread_process(void *vargp) { } if(FLAGSEARCH == SEARCH_COMPRESS || FLAGSEARCH == SEARCH_BOTH){ if(strncmp(public_address_compressed,vanity,len_vanity) == 0) { - hextemp = malloc(65); + hextemp = (char*) malloc(65); gmp_sprintf(hextemp,"%0.64Zx",key_mpz); vanityKeys = fopen("vanitykeys.txt","a+"); if(vanityKeys != NULL) { @@ -1710,7 +1722,7 @@ void *thread_process(void *vargp) { r = searchbinary(addressTable,public_address_compressed,N); if(r) { found++; - hextemp = malloc(65); + hextemp = (char*) malloc(65); gmp_sprintf(hextemp,"%0.64Zx",key_mpz); public_key_compressed_hex = tohex(public_key_compressed,33); pthread_mutex_lock(&write_keys); @@ -1734,7 +1746,7 @@ void *thread_process(void *vargp) { r = searchbinary(addressTable,public_address_uncompressed,N); if(r) { found++; - hextemp = malloc(65); + hextemp = (char*) malloc(65); gmp_sprintf(hextemp,"%0.64Zx",key_mpz); public_key_uncompressed_hex = tohex(public_key_uncompressed,65); pthread_mutex_lock(&write_keys); @@ -1761,7 +1773,7 @@ void *thread_process(void *vargp) { if(r) { r = searchbinary(addressTable,public_address_uncompressed,N); if(r) { - hextemp = malloc(65); + hextemp = (char*) malloc(65); mpz_get_str(hextemp,16,key_mpz); public_key_uncompressed_hex = tohex(public_key_uncompressed+1,64); pthread_mutex_lock(&write_keys); @@ -1800,7 +1812,7 @@ void *thread_process(void *vargp) { r = searchbinary(addressTable,publickeyhashrmd160_compress,N); if(r) { found++; - hextemp = malloc(65); + hextemp = (char*) malloc(65); gmp_sprintf(hextemp,"%0.64Zx",key_mpz); public_key_compressed_hex = tohex(public_key_compressed,33); pthread_mutex_lock(&write_keys); @@ -1823,7 +1835,7 @@ void *thread_process(void *vargp) { r = searchbinary(addressTable,publickeyhashrmd160_uncompress,N); if(r) { found++; - hextemp = malloc(65); + hextemp = (char*) malloc(65); gmp_sprintf(hextemp,"%0.64Zx",key_mpz); public_key_uncompressed_hex = tohex(public_key_uncompressed,65); pthread_mutex_lock(&write_keys); @@ -1847,7 +1859,7 @@ void *thread_process(void *vargp) { r = searchbinary(addressTable,public_key_compressed+1,N); if(r) { found++; - hextemp = malloc(65); + hextemp = (char*) malloc(65); gmp_sprintf(hextemp,"%0.64Zx",key_mpz); public_key_compressed_hex = tohex(public_key_compressed,33); pthread_mutex_lock(&write_keys); @@ -2124,7 +2136,7 @@ void *thread_process_bsgs(void *vargp) { char *aux_c; mpz_t base_key,keyfound; FILE *filekey; - struct Point base_point,point_aux,point_aux2,point_found,BSGS_S,BSGS_Q,BSGS_Q_AMP; + struct strPoint base_point,point_aux,point_aux2,point_found,BSGS_S,BSGS_Q,BSGS_Q_AMP; uint32_t i,j,k,r,salir,thread_number,bloom_counter =0; tt = (struct tothread *)vargp; thread_number = tt->nt; @@ -2245,7 +2257,7 @@ void *thread_process_bsgs(void *vargp) { mpz_set(base_key,BSGS_CURRENT); mpz_add(BSGS_CURRENT,BSGS_CURRENT,BSGS_N); pthread_mutex_unlock(&bsgs_thread); - if(FLAGDEBUG ) printf("%u of %"PRIu64"\n",bloom_counter,(uint64_t)(bsgs_aux*bsgs_point_number)); + if(FLAGDEBUG ) printf("%u of %" PRIu64 "\n",bloom_counter,(uint64_t)(bsgs_aux*bsgs_point_number)); bloom_counter = 0; } @@ -2272,7 +2284,7 @@ void *thread_process_bsgs_random(void *vargp) { char *aux_c; mpz_t base_key,keyfound; FILE *filekey; - struct Point base_point,point_aux,point_aux2,point_found,BSGS_S,BSGS_Q,BSGS_Q_AMP; + struct strPoint base_point,point_aux,point_aux2,point_found,BSGS_S,BSGS_Q,BSGS_Q_AMP; mpz_t n_range_random; uint32_t i,j,k,r,salir,thread_number,bloom_counter = 0; tt = (struct tothread *)vargp; @@ -2392,7 +2404,7 @@ void *thread_process_bsgs_random(void *vargp) { mpz_urandomm (n_range_random,state,n_range_diff); mpz_add(base_key,n_range_start,n_range_random); pthread_mutex_unlock(&bsgs_thread); - if(FLAGDEBUG ) printf("%u of %"PRIu64"\n",bloom_counter,(uint64_t)(bsgs_aux*bsgs_point_number)); + if(FLAGDEBUG ) printf("%u of %" PRIu64 "\n",bloom_counter,(uint64_t)(bsgs_aux*bsgs_point_number)); bloom_counter = 0; } mpz_clear(BSGS_Q.x); @@ -2418,12 +2430,12 @@ void *thread_process_bsgs_random(void *vargp) { This funtion is made with the especific purpouse to USE a smaller bPTable in RAM. This new and small bPtable is around ~ squareroot( K *squareroot(N)) */ -int bsgs_secondcheck(mpz_t start_range,uint32_t a,struct Point *target,mpz_t *private) { +int bsgs_secondcheck(mpz_t start_range,uint32_t a,struct strPoint *target,mpz_t *privatekey) { uint64_t j = 0; int i = 0,found = 0,r = 0; mpz_t base_key; - struct Point base_point,point_aux; - struct Point BSGS_Q, BSGS_S,BSGS_Q_AMP; + struct strPoint base_point,point_aux; + struct strPoint BSGS_Q, BSGS_S,BSGS_Q_AMP; char pubkey[131],xpoint_str[65],xpoint_raw[32]; mpz_init(base_key); @@ -2461,21 +2473,21 @@ int bsgs_secondcheck(mpz_t start_range,uint32_t a,struct Point *target,mpz_t *pr //printf("bsgs_searchbinary: %s\n",r ? "yes":"no"); //printf("Current i: %u j: %llu, m: %llu\n",i,j,bsgs_m2); if(r) { - mpz_set(*private,BSGS_M2); - mpz_mul_ui(*private,*private,i); - mpz_add_ui(*private,*private,j+1); - mpz_add(*private,*private,base_key); - Scalar_Multiplication(G,&point_aux,*private); - //gmp_printf("private 1: %0.64Zx\n",*private); + mpz_set(*privatekey,BSGS_M2); + mpz_mul_ui(*privatekey,*privatekey,i); + mpz_add_ui(*privatekey,*privatekey,j+1); + mpz_add(*privatekey,*privatekey,base_key); + Scalar_Multiplication(G,&point_aux,*privatekey); + //gmp_printf("privatekey 1: %0.64Zx\n",*privatekey); if(mpz_cmp(point_aux.x,target->x) == 0) { found = 1; } else { - mpz_set(*private,BSGS_M2); - mpz_mul_ui(*private,*private,i); - mpz_sub_ui(*private,*private,j+1); - mpz_add(*private,*private,base_key); - //gmp_printf("private 2: %0.64Zx\n",*private); + mpz_set(*privatekey,BSGS_M2); + mpz_mul_ui(*privatekey,*privatekey,i); + mpz_sub_ui(*privatekey,*privatekey,j+1); + mpz_add(*privatekey,*privatekey,base_key); + //gmp_printf("privatekey 2: %0.64Zx\n",*privatekey); if(mpz_cmp(point_aux.x,target->x) == 0) { found = 1; } @@ -2487,7 +2499,6 @@ int bsgs_secondcheck(mpz_t start_range,uint32_t a,struct Point *target,mpz_t *pr mpz_set(BSGS_S.y,BSGS_Q_AMP.y); i++; }while(i < 20 && !found); - mpz_clear(base_key); mpz_clear(base_point.x); mpz_clear(base_point.y); @@ -2503,27 +2514,25 @@ int bsgs_secondcheck(mpz_t start_range,uint32_t a,struct Point *target,mpz_t *pr } void *thread_bPload(void *vargp) { + char *hextemp; char hexvalue[65],rawvalue[32]; struct bPload *tt; - struct Point P,temp; - mpz_t base; uint32_t j; uint64_t i; + Int keybase; + Point P; tt = (struct bPload *)vargp; - mpz_init(base); - mpz_init(P.x); - mpz_init(P.y); - mpz_init(temp.x); - mpz_init(temp.y); - mpz_set_ui(base,tt->from); - Scalar_Multiplication(G,&P,base); + keybase.SetInt64(tt->from); + P = secp->ComputePublicKey(&keybase); i = tt->from -1; j = tt->from -1; do { - mpz_set(temp.x,P.x); - mpz_set(temp.y,P.y); - gmp_sprintf(hexvalue,"%0.64Zx",P.x); - hexs2bin(hexvalue,(unsigned char*) rawvalue ); + P.x.Get32Bytes((unsigned char*)rawvalue); + /* + hextemp = tohex(rawvalue,32); + printf("%s\n",hextemp); + free(hextemp); + */ if(i < bsgs_m2) { memcpy(bPtable[j].value,rawvalue+16,BSGS_XVALUE_RAM); bPtable[j].index = j; @@ -2531,15 +2540,17 @@ void *thread_bPload(void *vargp) { j++; } bloom_add(&bloom_bP[((uint8_t)rawvalue[0])], rawvalue ,BSGS_BUFFERXPOINTLENGTH); - Point_Addition(&G,&temp,&P); + if(secp->G.equals(P)) { + //printf("Is G\n"); + P = secp->DoubleDirect(P); + } + else { + //printf("Not G\n"); + P = secp->NextKey(P); + } i++; tt->counter++; } while( i < tt->to ); - mpz_clear(base); - mpz_clear(P.x); - mpz_clear(P.y); - mpz_clear(temp.x); - mpz_clear(temp.y); pthread_exit(NULL); } @@ -2558,7 +2569,7 @@ void *thread_bPloadFile(void *vargp) { i = tt->from -1; j = tt->from -1; if(fseek(fd,(uint64_t)(i*32),SEEK_SET) != 0) { - fprintf(stderr,"Can't seek the file at index %"PRIu64", offset %"PRIu64"\n",i,(uint64_t)(i*32)); + fprintf(stderr,"Can't seek the file at index %" PRIu64 ", offset %" PRIu64 "\n",i,(uint64_t)(i*32)); exit(0); } do { @@ -2628,7 +2639,7 @@ void *thread_pub2rmd(void *vargp) { } } if(pub2rmd_continue) { - temphex = malloc(65); + temphex = (char*) malloc(65); gmp_sprintf(temphex,"%0.64Zx",key_mpz); hexs2bin(temphex,pub.X.data8); free(temphex); diff --git a/secp256k1/Int.cpp b/secp256k1/Int.cpp new file mode 100644 index 0000000..bd7d0c5 --- /dev/null +++ b/secp256k1/Int.cpp @@ -0,0 +1,1057 @@ +/* + * This file is part of the BSGS distribution (https://github.com/JeanLucPons/BSGS). + * Copyright (c) 2020 Jean Luc PONS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +#include "Int.h" +#include "IntGroup.h" +#include +#include +#include +#include +#include + +#define MAX(x,y) (((x)>(y))?(x):(y)) +#define MIN(x,y) (((x)<(y))?(x):(y)) + +Int _ONE((uint64_t)1); + + +// ------------------------------------------------ + +Int::Int() { +} + +Int::Int(Int *a) { + if(a) Set(a); + else CLEAR(); +} + +Int::Int(int64_t i64) { + + if (i64 < 0) { + CLEARFF(); + } else { + CLEAR(); + } + bits64[0] = i64; + +} + +Int::Int(uint64_t u64) { + + CLEAR(); + bits64[0] = u64; + +} + +// ------------------------------------------------ + +void Int::CLEAR() { + memset(bits64,0, NB64BLOCK*8); +} + +void Int::CLEARFF() { + memset(bits64, 0xFF, NB64BLOCK * 8); +} + +// ------------------------------------------------ + +void Int::Set(Int *a) { + for (int i = 0; ibits64[i]; +} + +// ------------------------------------------------ + +void Int::Add(Int *a) { + + unsigned char c = 0; + c = _addcarry_u64(c, bits64[0], a->bits64[0], bits64 +0); + c = _addcarry_u64(c, bits64[1], a->bits64[1], bits64 +1); + c = _addcarry_u64(c, bits64[2], a->bits64[2], bits64 +2); + c = _addcarry_u64(c, bits64[3], a->bits64[3], bits64 +3); + c = _addcarry_u64(c, bits64[4], a->bits64[4], bits64 +4); +#if NB64BLOCK > 5 + c = _addcarry_u64(c, bits64[5], a->bits64[5], bits64 +5); + c = _addcarry_u64(c, bits64[6], a->bits64[6], bits64 +6); + c = _addcarry_u64(c, bits64[7], a->bits64[7], bits64 +7); + c = _addcarry_u64(c, bits64[8], a->bits64[8], bits64 +8); +#endif + +} + +// ------------------------------------------------ + +void Int::Add(uint64_t a) { + + unsigned char c = 0; + c = _addcarry_u64(c, bits64[0], a, bits64 + 0); + c = _addcarry_u64(c, bits64[1], 0, bits64 + 1); + c = _addcarry_u64(c, bits64[2], 0, bits64 + 2); + c = _addcarry_u64(c, bits64[3], 0, bits64 + 3); + c = _addcarry_u64(c, bits64[4], 0, bits64 + 4); +#if NB64BLOCK > 5 + c = _addcarry_u64(c, bits64[5], 0, bits64 + 5); + c = _addcarry_u64(c, bits64[6], 0, bits64 + 6); + c = _addcarry_u64(c, bits64[7], 0, bits64 + 7); + c = _addcarry_u64(c, bits64[8], 0, bits64 + 8); +#endif +} + +// ------------------------------------------------ +void Int::AddOne() { + + unsigned char c = 0; + c = _addcarry_u64(c, bits64[0],1, bits64 +0); + c = _addcarry_u64(c, bits64[1],0, bits64 +1); + c = _addcarry_u64(c, bits64[2],0, bits64 +2); + c = _addcarry_u64(c, bits64[3],0, bits64 +3); + c = _addcarry_u64(c, bits64[4],0, bits64 +4); +#if NB64BLOCK > 5 + c = _addcarry_u64(c, bits64[5],0, bits64 +5); + c = _addcarry_u64(c, bits64[6],0, bits64 +6); + c = _addcarry_u64(c, bits64[7],0, bits64 +7); + c = _addcarry_u64(c, bits64[8],0, bits64 +8); +#endif + +} + +// ------------------------------------------------ + +void Int::Add(Int *a,Int *b) { + + unsigned char c = 0; + c = _addcarry_u64(c, b->bits64[0], a->bits64[0], bits64 +0); + c = _addcarry_u64(c, b->bits64[1], a->bits64[1], bits64 +1); + c = _addcarry_u64(c, b->bits64[2], a->bits64[2], bits64 +2); + c = _addcarry_u64(c, b->bits64[3], a->bits64[3], bits64 +3); + c = _addcarry_u64(c, b->bits64[4], a->bits64[4], bits64 +4); +#if NB64BLOCK > 5 + c = _addcarry_u64(c, b->bits64[5], a->bits64[5], bits64 +5); + c = _addcarry_u64(c, b->bits64[6], a->bits64[6], bits64 +6); + c = _addcarry_u64(c, b->bits64[7], a->bits64[7], bits64 +7); + c = _addcarry_u64(c, b->bits64[8], a->bits64[8], bits64 +8); +#endif + +} + +// ------------------------------------------------ + +bool Int::IsGreater(Int *a) { + + int i; + + for(i=NB64BLOCK-1;i>=0;) { + if( a->bits64[i]!= bits64[i] ) + break; + i--; + } + + if(i>=0) { + return bits64[i]>a->bits64[i]; + } else { + return false; + } + +} + +// ------------------------------------------------ + +bool Int::IsLower(Int *a) { + + int i; + + for (i = NB64BLOCK - 1; i >= 0;) { + if (a->bits64[i] != bits64[i]) + break; + i--; + } + + if (i >= 0) { + return bits64[i]bits64[i]; + } else { + return false; + } + +} + +// ------------------------------------------------ + +bool Int::IsGreaterOrEqual(Int *a) { + + Int p; + p.Sub(this,a); + return p.IsPositive(); + +} + +// ------------------------------------------------ + +bool Int::IsLowerOrEqual(Int *a) { + + int i = NB64BLOCK - 1; + + while (i >= 0) { + if (a->bits64[i] != bits64[i]) + break; + i--; +} + + if (i >= 0) { + return bits64[i]bits64[i]; + } else { + return true; + } + +} + +bool Int::IsEqual(Int *a) { + +return + +#if NB64BLOCK > 5 + (bits64[8] == a->bits64[8]) && + (bits64[7] == a->bits64[7]) && + (bits64[6] == a->bits64[6]) && + (bits64[5] == a->bits64[5]) && +#endif + (bits64[4] == a->bits64[4]) && + (bits64[3] == a->bits64[3]) && + (bits64[2] == a->bits64[2]) && + (bits64[1] == a->bits64[1]) && + (bits64[0] == a->bits64[0]); +} + +bool Int::IsOne() { + return IsEqual(&_ONE); +} + +bool Int::IsZero() { +#if NB64BLOCK > 5 + return (bits64[8] | bits64[7] | bits64[6] | bits64[5] | bits64[4] | bits64[3] | bits64[2] | bits64[1] | bits64[0]) == 0; +#else + return (bits64[4] | bits64[3] | bits64[2] | bits64[1] | bits64[0]) == 0; +#endif + +} + + +// ------------------------------------------------ + +void Int::SetInt64(uint64_t value) { + + CLEAR(); + bits64[0]=value; + +} + +// ------------------------------------------------ + +void Int::SetInt32(uint32_t value) { + + CLEAR(); + bits[0]=value; + +} + +// ------------------------------------------------ + +uint32_t Int::GetInt32() { + return bits[0]; +} + +// ------------------------------------------------ + +unsigned char Int::GetByte(int n) { + + unsigned char *bbPtr = (unsigned char *)bits; + return bbPtr[n]; + +} + +void Int::Set32Bytes(unsigned char *bytes) { + + CLEAR(); + uint64_t *ptr = (uint64_t *)bytes; + bits64[3] = _byteswap_uint64(ptr[0]); + bits64[2] = _byteswap_uint64(ptr[1]); + bits64[1] = _byteswap_uint64(ptr[2]); + bits64[0] = _byteswap_uint64(ptr[3]); + +} + +void Int::Get32Bytes(unsigned char *buff) { + + uint64_t *ptr = (uint64_t *)buff; + ptr[3] = _byteswap_uint64(bits64[0]); + ptr[2] = _byteswap_uint64(bits64[1]); + ptr[1] = _byteswap_uint64(bits64[2]); + ptr[0] = _byteswap_uint64(bits64[3]); + +} + +// ------------------------------------------------ + +void Int::SetByte(int n,unsigned char byte) { + + unsigned char *bbPtr = (unsigned char *)bits; + bbPtr[n] = byte; + +} + +// ------------------------------------------------ + +void Int::SetDWord(int n,uint32_t b) { + bits[n] = b; +} + +// ------------------------------------------------ + +void Int::SetQWord(int n, uint64_t b) { + bits64[n] = b; +} + +// ------------------------------------------------ + +void Int::Sub(Int *a) { + + unsigned char c = 0; + c = _subborrow_u64(c, bits64[0], a->bits64[0], bits64 +0); + c = _subborrow_u64(c, bits64[1], a->bits64[1], bits64 +1); + c = _subborrow_u64(c, bits64[2], a->bits64[2], bits64 +2); + c = _subborrow_u64(c, bits64[3], a->bits64[3], bits64 +3); + c = _subborrow_u64(c, bits64[4], a->bits64[4], bits64 +4); +#if NB64BLOCK > 5 + c = _subborrow_u64(c, bits64[5], a->bits64[5], bits64 +5); + c = _subborrow_u64(c, bits64[6], a->bits64[6], bits64 +6); + c = _subborrow_u64(c, bits64[7], a->bits64[7], bits64 +7); + c = _subborrow_u64(c, bits64[8], a->bits64[8], bits64 +8); +#endif + +} + +// ------------------------------------------------ + +void Int::Sub(Int *a,Int *b) { + + unsigned char c = 0; + c = _subborrow_u64(c, a->bits64[0], b->bits64[0], bits64 + 0); + c = _subborrow_u64(c, a->bits64[1], b->bits64[1], bits64 + 1); + c = _subborrow_u64(c, a->bits64[2], b->bits64[2], bits64 + 2); + c = _subborrow_u64(c, a->bits64[3], b->bits64[3], bits64 + 3); + c = _subborrow_u64(c, a->bits64[4], b->bits64[4], bits64 + 4); +#if NB64BLOCK > 5 + c = _subborrow_u64(c, a->bits64[5], b->bits64[5], bits64 + 5); + c = _subborrow_u64(c, a->bits64[6], b->bits64[6], bits64 + 6); + c = _subborrow_u64(c, a->bits64[7], b->bits64[7], bits64 + 7); + c = _subborrow_u64(c, a->bits64[8], b->bits64[8], bits64 + 8); +#endif + +} + +void Int::Sub(uint64_t a) { + + unsigned char c = 0; + c = _subborrow_u64(c, bits64[0], a, bits64 + 0); + c = _subborrow_u64(c, bits64[1], 0, bits64 + 1); + c = _subborrow_u64(c, bits64[2], 0, bits64 + 2); + c = _subborrow_u64(c, bits64[3], 0, bits64 + 3); + c = _subborrow_u64(c, bits64[4], 0, bits64 + 4); +#if NB64BLOCK > 5 + c = _subborrow_u64(c, bits64[5], 0, bits64 + 5); + c = _subborrow_u64(c, bits64[6], 0, bits64 + 6); + c = _subborrow_u64(c, bits64[7], 0, bits64 + 7); + c = _subborrow_u64(c, bits64[8], 0, bits64 + 8); +#endif + +} + +void Int::SubOne() { + + unsigned char c = 0; + c = _subborrow_u64(c, bits64[0], 1, bits64 + 0); + c = _subborrow_u64(c, bits64[1], 0, bits64 + 1); + c = _subborrow_u64(c, bits64[2], 0, bits64 + 2); + c = _subborrow_u64(c, bits64[3], 0, bits64 + 3); + c = _subborrow_u64(c, bits64[4], 0, bits64 + 4); +#if NB64BLOCK > 5 + c = _subborrow_u64(c, bits64[5], 0, bits64 + 5); + c = _subborrow_u64(c, bits64[6], 0, bits64 + 6); + c = _subborrow_u64(c, bits64[7], 0, bits64 + 7); + c = _subborrow_u64(c, bits64[8], 0, bits64 + 8); +#endif + +} + +// ------------------------------------------------ + +bool Int::IsPositive() { + return (int64_t)(bits64[NB64BLOCK - 1])>=0; +} + +// ------------------------------------------------ + +bool Int::IsNegative() { + return (int64_t)(bits64[NB64BLOCK - 1])<0; +} + +// ------------------------------------------------ + +bool Int::IsStrictPositive() { + if( IsPositive() ) + return !IsZero(); + else + return false; +} + +// ------------------------------------------------ + +bool Int::IsEven() { + return (bits[0] & 0x1) == 0; +} + +// ------------------------------------------------ + +bool Int::IsOdd() { + return (bits[0] & 0x1) == 1; +} + +// ------------------------------------------------ + +void Int::Neg() { + + volatile unsigned char c=0; + c = _subborrow_u64(c, 0, bits64[0], bits64 + 0); + c = _subborrow_u64(c, 0, bits64[1], bits64 + 1); + c = _subborrow_u64(c, 0, bits64[2], bits64 + 2); + c = _subborrow_u64(c, 0, bits64[3], bits64 + 3); + c = _subborrow_u64(c, 0, bits64[4], bits64 + 4); +#if NB64BLOCK > 5 + c = _subborrow_u64(c, 0, bits64[5], bits64 + 5); + c = _subborrow_u64(c, 0, bits64[6], bits64 + 6); + c = _subborrow_u64(c, 0, bits64[7], bits64 + 7); + c = _subborrow_u64(c, 0, bits64[8], bits64 + 8); +#endif + +} + +// ------------------------------------------------ + +void Int::ShiftL32Bit() { + + for(int i=NB32BLOCK-1;i>0;i--) { + bits[i]=bits[i-1]; + } + bits[0]=0; + +} + +// ------------------------------------------------ + +void Int::ShiftL64Bit() { + + for (int i = NB64BLOCK-1 ; i>0; i--) { + bits64[i] = bits64[i - 1]; + } + bits64[0] = 0; + +} + +// ------------------------------------------------ + +void Int::ShiftL32BitAndSub(Int *a,int n) { + + Int b; + int i=NB32BLOCK-1; + + for(;i>=n;i--) + b.bits[i] = ~a->bits[i-n]; + for(;i>=0;i--) + b.bits[i] = 0xFFFFFFFF; + + Add(&b); + AddOne(); + +} + +// ------------------------------------------------ + +void Int::ShiftL(uint32_t n) { + + if( n<64 ) { + shiftL((unsigned char)n, bits64); + } else { + uint32_t nb64 = n/64; + uint32_t nb = n%64; + for(uint32_t i=0;ibits64, b, bits64); + +} + +// ------------------------------------------------ + +void Int::Mult(Int *a,Int *b) { + + unsigned char c = 0; + uint64_t h; + uint64_t pr = 0; + uint64_t carryh = 0; + uint64_t carryl = 0; + + bits64[0] = _umul128(a->bits64[0], b->bits64[0], &pr); + + for (int i = 1; i < NB64BLOCK; i++) { + for (int j = 0; j <= i; j++) { + c = _addcarry_u64(c, _umul128(a->bits64[j], b->bits64[i - j], &h), pr, &pr); + c = _addcarry_u64(c, carryl, h, &carryl); + c = _addcarry_u64(c, carryh, 0, &carryh); + } + bits64[i] = pr; + pr = carryl; + carryl = carryh; + carryh = 0; + } + +} + +// ------------------------------------------------ + +void Int::Mult(Int *a,uint32_t b) { + imm_mul(a->bits64, (uint64_t)b, bits64); +} + +// ------------------------------------------------ + +static uint32_t bitLength(uint32_t dw) { + + uint32_t mask = 0x80000000; + uint32_t b=0; + while(b<32 && (mask & dw)==0) { + b++; + mask >>= 1; + } + return b; + +} + +// ------------------------------------------------ + +int Int::GetBitLength() { + + Int t(this); + if(IsNegative()) + t.Neg(); + + int i=NB32BLOCK-1; + while(i>=0 && t.bits[i]==0) i--; + if(i<0) return 0; + return (32-bitLength(t.bits[i])) + i*32; + +} + +// ------------------------------------------------ + +int Int::GetSize() { + + int i=NB32BLOCK-1; + while(i>0 && bits[i]==0) i--; + return i+1; + +} + +// ------------------------------------------------ + +void Int::MultModN(Int *a,Int *b,Int *n) { + + Int r; + Mult(a,b); + Div(n,&r); + Set(&r); + +} + +// ------------------------------------------------ + +void Int::Mod(Int *n) { + + Int r; + Div(n,&r); + Set(&r); + +} + +// ------------------------------------------------ + +int Int::GetLowestBit() { + + // Assume this!=0 + int b=0; + while(GetBit(b)==0) b++; + return b; + +} + +// ------------------------------------------------ + +void Int::MaskByte(int n) { + + for (int i = n; i < NB32BLOCK; i++) + bits[i] = 0; + +} + +// ------------------------------------------------ + +void Int::Abs() { + + if (IsNegative()) + Neg(); + +} + +// ------------------------------------------------ + +void Int::Rand(int nbit) { + + CLEAR(); + + uint32_t nb = nbit/32; + uint32_t leftBit = nbit%32; + uint32_t mask = 1; + mask = (mask << leftBit) - 1; + uint32_t i=0; + for(;iIsGreater(this)) { + if(mod) mod->Set(this); + CLEAR(); + return; + } + + if(a->IsZero()) { + printf("Divide by 0!\n"); + return; + } + + if(IsEqual(a)) { + if(mod) mod->CLEAR(); + Set(&_ONE); + return; + } + + //Division algorithm D (Knuth section 4.3.1) + + Int rem(this); + Int d(a); + Int dq; + CLEAR(); + + // Size + uint32_t dSize = d.GetSize(); + uint32_t tSize = rem.GetSize(); + uint32_t qSize = tSize - dSize + 1; + + // D1 normalize the divisor + uint32_t shift = bitLength(d.bits[dSize-1]); + if (shift > 0) { + d.ShiftL(shift); + rem.ShiftL(shift); + } + + uint32_t _dh = d.bits[dSize-1]; + uint64_t dhLong = _dh; + uint32_t _dl = (dSize>1)?d.bits[dSize-2]:0; + int sb = tSize-1; + + // D2 Initialize j + for(int j=0; j<(int)qSize; j++) { + + // D3 Estimate qhat + uint32_t qhat = 0; + uint32_t qrem = 0; + int skipCorrection = false; + uint32_t nh = rem.bits[sb-j+1]; + uint32_t nm = rem.bits[sb-j]; + + if (nh == _dh) { + qhat = ~0; + qrem = nh + nm; + skipCorrection = qrem < nh; + } else { + uint64_t nChunk = ((uint64_t)nh << 32) | (uint64_t)nm; + qhat = (uint32_t) (nChunk / dhLong); + qrem = (uint32_t) (nChunk % dhLong); + } + + if (qhat == 0) + continue; + + if (!skipCorrection) { + + // Correct qhat + uint64_t nl = (uint64_t)rem.bits[sb-j-1]; + uint64_t rs = ((uint64_t)qrem << 32) | nl; + uint64_t estProduct = (uint64_t)_dl * (uint64_t)(qhat); + + if (estProduct>rs) { + qhat--; + qrem = (uint32_t)(qrem + (uint32_t)dhLong); + if ((uint64_t)qrem >= dhLong) { + estProduct = (uint64_t)_dl * (uint64_t)(qhat); + rs = ((uint64_t)qrem << 32) | nl; + if(estProduct>rs) + qhat--; + } + } + + } + + // D4 Multiply and subtract + dq.Mult(&d,qhat); + rem.ShiftL32BitAndSub(&dq,qSize-j-1); + if( rem.IsNegative() ) { + // Overflow + rem.Add(&d); + qhat--; + } + + bits[qSize-j-1] = qhat; + + } + + if( mod ) { + // Unnormalize remainder + rem.ShiftR(shift); + mod->Set(&rem); + } + +} + +// ------------------------------------------------ + +void Int::GCD(Int *a) { + uint32_t k; + uint32_t b; + Int U(this); + Int V(a); + Int T; + if(U.IsZero()) { + Set(&V); + return; + } + if(V.IsZero()) { + Set(&U); + return; + } + if(U.IsNegative()) U.Neg(); + if(V.IsNegative()) V.Neg(); + k = 0; + while (U.GetBit(k)==0 && V.GetBit(k)==0) + k++; + U.ShiftR(k); + V.ShiftR(k); + if (U.GetBit(0)==1) { + T.Set(&V); + T.Neg(); + } else { + T.Set(&U); + } + do { + if( T.IsNegative() ) { + T.Neg(); + b=0;while(T.GetBit(b)==0) b++; + T.ShiftR(b); + V.Set(&T); + T.Set(&U); + } else { + b=0;while(T.GetBit(b)==0) b++; + T.ShiftR(b); + U.Set(&T); + } + T.Sub(&V); + } while (!T.IsZero()); + // Store gcd + Set(&U); + ShiftL(k); +} + +// ------------------------------------------------ + +void Int::SetBase10(char *value) { + CLEAR(); + Int pw((uint64_t)1); + Int c; + int lgth = (int)strlen(value); + for(int i=lgth-1;i>=0;i--) { + uint32_t id = (uint32_t)(value[i]-'0'); + c.Set(&pw); + c.Mult(id); + Add(&c); + pw.Mult(10); + } + +} + +// ------------------------------------------------ + +void Int::SetBase16(char *value) { + SetBaseN(16,"0123456789ABCDEF",value); +} + +// ------------------------------------------------ + +char* Int::GetBase10() { + return GetBaseN(10,"0123456789"); +} + +// ------------------------------------------------ + +char* Int::GetBase16() { + return GetBaseN(16,"0123456789ABCDEF"); +} + +// ------------------------------------------------ + +char* Int::GetBlockStr() { + char *tmp = (char*) calloc(1,256); + char bStr[256]; + tmp[0] = 0; + for (int i = NB32BLOCK-3; i>=0 ; i--) { + sprintf(bStr, "%08X", bits[i]); + strcat(tmp, bStr); + if(i!=0) strcat(tmp, " "); + } + return tmp; +} + +// ------------------------------------------------ + +char * Int::GetC64Str(int nbDigit) { + char *tmp = (char*) calloc(1,256); + char bStr[256]; + tmp[0] = '{'; + tmp[1] = 0; + for (int i = 0; i< nbDigit; i++) { + if (bits64[i] != 0) { +#ifdef WIN64 + sprintf(bStr, "0x%016I64XULL", bits64[i]); +#else + sprintf(bStr, "0x%" PRIx64 "ULL", bits64[i]); +#endif + } else { + sprintf(bStr, "0ULL"); + } + strcat(tmp, bStr); + if (i != nbDigit -1) strcat(tmp, ","); + } + strcat(tmp,"}"); + return tmp; +} + +// ------------------------------------------------ + +void Int::SetBaseN(int n,char *charset,char *value) { + + CLEAR(); + Int pw((uint64_t)1); + Int nb((uint64_t)n); + Int c; + int lgth = (int)strlen(value); + for(int i=lgth-1;i>=0;i--) { + char *p = strchr(charset,toupper(value[i])); + if(!p) { + printf("Invalid charset !!\n"); + return; + } + int id = (int)(p-charset); + c.SetInt32(id); + c.Mult(&pw); + Add(&c); + pw.Mult(&nb); + } +} + +// ------------------------------------------------ + +char* Int::GetBaseN(int n,char *charset) { + char *ret = (char*) calloc(1,1024); + + Int N(this); + int offset = 0; + int isNegative = N.IsNegative(); + if (isNegative) N.Neg(); + + // TODO: compute max digit + unsigned char digits[1024]; + memset(digits, 0, sizeof(digits)); + + int digitslen = 1; + for (int i = 0; i < NB64BLOCK * 8; i++) { + unsigned int carry = N.GetByte(NB64BLOCK*8 - i - 1); + for (int j = 0; j < digitslen; j++) { + carry += (unsigned int)(digits[j]) << 8; + digits[j] = (unsigned char)(carry % n); + carry /= n; + } + while (carry > 0) { + digits[digitslen++] = (unsigned char)(carry % n); + carry /= n; + } + } + + // reverse + if (isNegative) + ret[offset++] = '-'; + + for (int i = 0; i < digitslen; i++) + ret[offset++] = charset[digits[digitslen - 1 - i]]; + + if (offset == 0) + ret[offset] = '0'; + return ret; +} + +// ------------------------------------------------ + + +int Int::GetBit(uint32_t n) { + uint32_t byte = n>>5; + uint32_t bit = n&31; + uint32_t mask = 1 << bit; + return (bits[byte] & mask)!=0; +} + +// ------------------------------------------------ +char* Int::GetBase2() { + char *ret = (char*) calloc(1,1024); + int k=0; + for(int i=0;i>1; + } + } + ret[k]=0; + return ret; +} diff --git a/secp256k1/Int.h b/secp256k1/Int.h new file mode 100644 index 0000000..7128731 --- /dev/null +++ b/secp256k1/Int.h @@ -0,0 +1,295 @@ +/* + * This file is part of the BSGS distribution (https://github.com/JeanLucPons/BSGS). + * Copyright (c) 2020 Jean Luc PONS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +// Big integer class (Fixed size) + +#ifndef BIGINTH +#define BIGINTH + +#include "Random.h" +#include +#include + +// We need 1 extra block for Knuth div algorithm , Montgomery multiplication and ModInv +#define BISIZE 256 + +#if BISIZE==256 + #define NB64BLOCK 5 + #define NB32BLOCK 10 +#elif BISIZE==512 + #define NB64BLOCK 9 + #define NB32BLOCK 18 +#else + #error Unsuported size +#endif + +class Int { + +public: + + Int(); + Int(int64_t i64); + Int(uint64_t u64); + Int(Int *a); + + // Op + void Add(uint64_t a); + void Add(Int *a); + void Add(Int *a,Int *b); + void AddOne(); + void Sub(uint64_t a); + void Sub(Int *a); + void Sub(Int *a, Int *b); + void SubOne(); + void Mult(Int *a); + void Mult(uint64_t a); + void IMult(int64_t a); + void Mult(Int *a,uint64_t b); + void IMult(Int *a, int64_t b); + void Mult(Int *a,Int *b); + void Div(Int *a,Int *mod = NULL); + void MultModN(Int *a, Int *b, Int *n); + void Neg(); + void Abs(); + + // Right shift (signed) + void ShiftR(uint32_t n); + void ShiftR32Bit(); + void ShiftR64Bit(); + // Left shift + void ShiftL(uint32_t n); + void ShiftL32Bit(); + void ShiftL64Bit(); + + // Comp + bool IsGreater(Int *a); + bool IsGreaterOrEqual(Int *a); + bool IsLowerOrEqual(Int *a); + bool IsLower(Int *a); + bool IsEqual(Int *a); + bool IsZero(); + bool IsOne(); + bool IsStrictPositive(); + bool IsPositive(); + bool IsNegative(); + bool IsEven(); + bool IsOdd(); + + // Modular arithmetic + + // Setup field + // n is the field characteristic + // R used in Montgomery mult (R = 2^size(n)) + // R2 = R^2, R3 = R^3, R4 = R^4 + static void SetupField(Int *n, Int *R = NULL, Int *R2 = NULL, Int *R3 = NULL, Int *R4 = NULL); + static Int *GetR(); // Return R + static Int *GetR2(); // Return R2 + static Int *GetR3(); // Return R3 + static Int *GetR4(); // Return R4 + static Int* GetFieldCharacteristic(); // Return field characteristic + + void GCD(Int *a); // this <- GCD(this,a) + void Mod(Int *n); // this <- this (mod n) + void ModInv(); // this <- this^-1 (mod n) + void MontgomeryMult(Int *a,Int *b); // this <- a*b*R^-1 (mod n) + void MontgomeryMult(Int *a); // this <- this*a*R^-1 (mod n) + void ModAdd(Int *a); // this <- this+a (mod n) [0 +#endif + +static void inline imm_mul(uint64_t *x, uint64_t y, uint64_t *dst) { + + unsigned char c = 0; + uint64_t h, carry; + dst[0] = _umul128(x[0], y, &h); carry = h; + c = _addcarry_u64(c, _umul128(x[1], y, &h), carry, dst + 1); carry = h; + c = _addcarry_u64(c, _umul128(x[2], y, &h), carry, dst + 2); carry = h; + c = _addcarry_u64(c, _umul128(x[3], y, &h), carry, dst + 3); carry = h; + c = _addcarry_u64(c, _umul128(x[4], y, &h), carry, dst + 4); carry = h; +#if NB64BLOCK > 5 + c = _addcarry_u64(c, _umul128(x[5], y, &h), carry, dst + 5); carry = h; + c = _addcarry_u64(c, _umul128(x[6], y, &h), carry, dst + 6); carry = h; + c = _addcarry_u64(c, _umul128(x[7], y, &h), carry, dst + 7); carry = h; + c = _addcarry_u64(c, _umul128(x[8], y, &h), carry, dst + 8); carry = h; +#endif + +} + +static void inline imm_umul(uint64_t *x, uint64_t y, uint64_t *dst) { + + // Assume that x[NB64BLOCK-1] is 0 + unsigned char c = 0; + uint64_t h, carry; + dst[0] = _umul128(x[0], y, &h); carry = h; + c = _addcarry_u64(c, _umul128(x[1], y, &h), carry, dst + 1); carry = h; + c = _addcarry_u64(c, _umul128(x[2], y, &h), carry, dst + 2); carry = h; + c = _addcarry_u64(c, _umul128(x[3], y, &h), carry, dst + 3); carry = h; +#if NB64BLOCK > 5 + c = _addcarry_u64(c, _umul128(x[4], y, &h), carry, dst + 4); carry = h; + c = _addcarry_u64(c, _umul128(x[5], y, &h), carry, dst + 5); carry = h; + c = _addcarry_u64(c, _umul128(x[6], y, &h), carry, dst + 6); carry = h; + c = _addcarry_u64(c, _umul128(x[7], y, &h), carry, dst + 7); carry = h; +#endif + _addcarry_u64(c, 0ULL, carry, dst + (NB64BLOCK - 1)); + +} + +static void inline shiftR(unsigned char n, uint64_t *d) { + + d[0] = __shiftright128(d[0], d[1], n); + d[1] = __shiftright128(d[1], d[2], n); + d[2] = __shiftright128(d[2], d[3], n); + d[3] = __shiftright128(d[3], d[4], n); +#if NB64BLOCK > 5 + d[4] = __shiftright128(d[4], d[5], n); + d[5] = __shiftright128(d[5], d[6], n); + d[6] = __shiftright128(d[6], d[7], n); + d[7] = __shiftright128(d[7], d[8], n); +#endif + d[NB64BLOCK-1] = ((int64_t)d[NB64BLOCK-1]) >> n; + +} + +static void inline shiftL(unsigned char n, uint64_t *d) { + +#if NB64BLOCK > 5 + d[8] = __shiftleft128(d[7], d[8], n); + d[7] = __shiftleft128(d[6], d[7], n); + d[6] = __shiftleft128(d[5], d[6], n); + d[5] = __shiftleft128(d[4], d[5], n); +#endif + d[4] = __shiftleft128(d[3], d[4], n); + d[3] = __shiftleft128(d[2], d[3], n); + d[2] = __shiftleft128(d[1], d[2], n); + d[1] = __shiftleft128(d[0], d[1], n); + d[0] = d[0] << n; + +} + +#endif // BIGINTH diff --git a/secp256k1/IntGroup.cpp b/secp256k1/IntGroup.cpp new file mode 100644 index 0000000..4f1d12b --- /dev/null +++ b/secp256k1/IntGroup.cpp @@ -0,0 +1,58 @@ +/* + * This file is part of the BSGS distribution (https://github.com/JeanLucPons/BSGS). + * Copyright (c) 2020 Jean Luc PONS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +#include "IntGroup.h" + +using namespace std; + +IntGroup::IntGroup(int size) { + this->size = size; + subp = (Int *)malloc(size * sizeof(Int)); +} + +IntGroup::~IntGroup() { + free(subp); +} + +void IntGroup::Set(Int *pts) { + ints = pts; +} + +// Compute modular inversion of the whole group +void IntGroup::ModInv() { + + Int newValue; + Int inverse; + + subp[0].Set(&ints[0]); + for (int i = 1; i < size; i++) { + subp[i].ModMulK1(&subp[i - 1], &ints[i]); + } + + // Do the inversion + inverse.Set(&subp[size - 1]); + inverse.ModInv(); + + for (int i = size - 1; i > 0; i--) { + newValue.ModMulK1(&subp[i - 1], &inverse); + inverse.ModMulK1(&ints[i]); + ints[i].Set(&newValue); + } + + ints[0].Set(&inverse); + +} \ No newline at end of file diff --git a/secp256k1/IntGroup.h b/secp256k1/IntGroup.h new file mode 100644 index 0000000..77a58e0 --- /dev/null +++ b/secp256k1/IntGroup.h @@ -0,0 +1,41 @@ +/* + * This file is part of the BSGS distribution (https://github.com/JeanLucPons/BSGS). + * Copyright (c) 2020 Jean Luc PONS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +#ifndef INTGROUPH +#define INTGROUPH + +#include "Int.h" +#include + +class IntGroup { + +public: + + IntGroup(int size); + ~IntGroup(); + void Set(Int *pts); + void ModInv(); + +private: + + Int *ints; + Int *subp; + int size; + +}; + +#endif // INTGROUPCPUH diff --git a/secp256k1/IntMod.cpp b/secp256k1/IntMod.cpp new file mode 100644 index 0000000..48fb03f --- /dev/null +++ b/secp256k1/IntMod.cpp @@ -0,0 +1,1169 @@ +/* + * This file is part of the BSGS distribution (https://github.com/JeanLucPons/BSGS). + * Copyright (c) 2020 Jean Luc PONS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +#include "Int.h" +#include +#include + +#define MAX(x,y) (((x)>(y))?(x):(y)) +#define MIN(x,y) (((x)<(y))?(x):(y)) + +static Int _P; // Field characteristic +static Int _R; // Montgomery multiplication R +static Int _R2; // Montgomery multiplication R2 +static Int _R3; // Montgomery multiplication R3 +static Int _R4; // Montgomery multiplication R4 +static int32_t Msize; // Montgomery mult size +static uint32_t MM32; // 32bits lsb negative inverse of P +static uint64_t MM64; // 64bits lsb negative inverse of P +#define MSK62 0x3FFFFFFFFFFFFFFF + +extern Int _ONE; + +// ------------------------------------------------ + +void Int::ModAdd(Int *a) { + Int p; + Add(a); + p.Sub(this,&_P); + if(p.IsPositive()) + Set(&p); +} + +// ------------------------------------------------ + +void Int::ModAdd(Int *a, Int *b) { + Int p; + Add(a,b); + p.Sub(this,&_P); + if(p.IsPositive()) + Set(&p); +} + +// ------------------------------------------------ + +void Int::ModDouble() { + Int p; + Add(this); + p.Sub(this,&_P); + if(p.IsPositive()) + Set(&p); +} + +// ------------------------------------------------ + +void Int::ModAdd(uint64_t a) { + Int p; + Add(a); + p.Sub(this,&_P); + if(p.IsPositive()) + Set(&p); +} + +// ------------------------------------------------ + +void Int::ModSub(Int *a) { + Sub(a); + if (IsNegative()) + Add(&_P); +} + +// ------------------------------------------------ + +void Int::ModSub(uint64_t a) { + Sub(a); + if (IsNegative()) + Add(&_P); +} + +// ------------------------------------------------ + +void Int::ModSub(Int *a,Int *b) { + Sub(a,b); + if (IsNegative()) + Add(&_P); +} + +// ------------------------------------------------ + +void Int::ModNeg() { + Neg(); + Add(&_P); +} + +// ------------------------------------------------ + +void Int::ModInv() { + + // Compute modular inverse of this mop _P + // 0 < this < P , P must be odd + // Return 0 if no inverse + + // 256bit + //#define XCD 1 // ~62 kOps/s + //#define BXCD 1 // ~167 kOps/s + //#define MONTGOMERY 1 // ~200 kOps/s + //#define PENK 1 // ~179 kOps/s + #define DRS62 1 // ~365 kOps/s + + Int u(&_P); + Int v(this); + Int r((int64_t)0); + Int s((int64_t)1); + +#ifdef XCD + + Int q, t1, t2, w; + + // Classic XCD + + bool bIterations = true; // Remember odd/even iterations + while (!u.IsZero()) { + // Step X3. Divide and "Subtract" + q.Set(&v); + q.Div(&u, &t2); // q = u / v, t2 = u % v + w.Mult(&q, &r); // w = q * r + t1.Add(&s, &w); // t1 = s + w + + // Swap u,v & r,s + s.Set(&r); + r.Set(&t1); + v.Set(&u); + u.Set(&t2); + + bIterations = !bIterations; + } + + if (!v.IsOne()) { + CLEAR(); + return; + } + + if (!bIterations) { + Set(&_P); + Sub(&s); /* inv = n - u1 */ + } else { + Set(&s); /* inv = u1 */ + } + +#endif + +#ifdef BXCD + +#define SWAP_SUB(x,y) x.Sub(&y);y.Add(&x) + + // Binary XCD loop + + while (!u.IsZero()) { + + if (u.IsEven()) { + + u.ShiftR(1); + if (r.IsOdd()) + r.Add(&_P); + r.ShiftR(1); + + } else { + + SWAP_SUB(u, v); + SWAP_SUB(r, s); + + } + + } + + // v ends with -1 ou 1 + if (!v.IsOne()) { + // v = -1 + s.Neg(); + s.Add(&_P); + v.Neg(); + } + + if (!v.IsOne()) { + CLEAR(); + return; + } + + if (s.IsNegative()) + s.Add(&_P); + + if (s.IsGreaterOrEqual(&_P)) + s.Sub(&_P); + + Set(&s); + +#endif + +#ifdef PENK + + Int x; + Int n2(&_P); + int k = 0; + int T; + int Q = _P.bits[0] & 3; + shiftL(1,n2.bits64); + + // Penk's Algorithm (With DRS2 optimisation) + + while (v.IsEven()) { + + shiftR(1,v.bits64); + if (s.IsEven()) + shiftR(1, s.bits64); + else if (s.IsGreater(&_P)) { + s.Sub(&_P); + shiftR(1, s.bits64); + } else { + s.Add(&_P); + shiftR(1, s.bits64); + } + + } + + while (true) { + + if (u.IsGreater(&v)) { + + if ((u.bits[0] & 2) == (v.bits[0] & 2)) { + u.Sub(&v); + r.Sub(&s); + } else { + u.Add(&v); + r.Add(&s); + } + shiftR(2,u.bits64); + T = r.bits[0] & 3; + if (T == 0) { + shiftR(2,r.bits64); + } else if (T == 2) { + r.Add(&n2); + shiftR(2, r.bits64); + } else if (T == Q) { + r.Sub(&_P); + shiftR(2, r.bits64); + } else { + r.Add(&_P); + shiftR(2, r.bits64); + } + while (u.IsEven()) { + shiftR(1,u.bits64); + if (r.IsEven()) { + shiftR(1, r.bits64); + } else if (r.IsGreater(&_P)) { + r.Sub(&_P); + shiftR(1, r.bits64); + } else { + r.Add(&_P); + shiftR(1, r.bits64); + } + } + + } else { + + if ((u.bits[0] & 2) == (v.bits[0] & 2)) { + v.Sub(&u); + s.Sub(&r); + } else { + v.Add(&u); + s.Add(&r); + } + + if (v.IsZero()) + break; + + shiftR(2, v.bits64); + T = s.bits[0] & 3; + if (T == 0) { + shiftR(2,s.bits64); + } else if (T == 2) { + s.Add(&n2); + shiftR(2, s.bits64); + } else if (T == Q) { + s.Sub(&_P); + shiftR(2, s.bits64); + } else { + s.Add(&_P); + shiftR(2, s.bits64); + } + + while (v.IsEven()) { + shiftR(1, v.bits64); + if (s.IsEven()) { + shiftR(1, s.bits64); + } else if (s.IsGreater(&_P)) { + s.Sub(&_P); + shiftR(1, s.bits64); + } else { + s.Add(&_P); + shiftR(1, s.bits64); + } + } + + } + + } + + if (u.IsGreater(&_ONE)) { + CLEAR(); + return; + } + if (r.IsNegative()) + r.Add(&_P); + Set(&r); + +#endif + +#ifdef MONTGOMERY + + Int x; + int k = 0; + + // Montgomery method + while (v.IsStrictPositive()) { + if (u.IsEven()) { + shiftR(1, u.bits64); + shiftL(1, s.bits64); + } else if (v.IsEven()) { + shiftR(1, v.bits64); + shiftL(1, r.bits64); + } else { + x.Set(&u); + x.Sub(&v); + if (x.IsStrictPositive()) { + shiftR(1, x.bits64); + u.Set(&x); + r.Add(&s); + shiftL(1, s.bits64); + } else { + x.Neg(); + shiftR(1, x.bits64); + v.Set(&x); + s.Add(&r); + shiftL(1, r.bits64); + } + } + k++; + } + + if (r.IsGreater(&_P)) + r.Sub(&_P); + r.Neg(); + r.Add(&_P); + + for (int i = 0; i < k; i++) { + if (r.IsEven()) { + shiftR(1, r.bits64); + } else { + r.Add(&_P); + shiftR(1, r.bits64); + } + } + Set(&r); + +#endif + +#ifdef DRS62 + + // Delayed right shift 62bits + + #define SWAP_ADD(x,y) x+=y;y-=x; + #define SWAP_SUB(x,y) x-=y;y+=x; + #define IS_EVEN(x) ((x&1)==0) + + Int r0_P; + Int s0_P; + Int uu_u; + Int uv_v; + Int vu_u; + Int vv_v; + Int uu_r; + Int uv_s; + Int vu_r; + Int vv_s; + + int64_t bitCount; + int64_t uu, uv, vu, vv; + int64_t v0, u0; + int64_t nb0; + + while (!u.IsZero()) { + + // u' = (uu*u + uv*v) >> bitCount + // v' = (vu*u + vv*v) >> bitCount + // Do not maintain a matrix for r and s, the number of + // 'added P' can be easily calculated + uu = 1; uv = 0; + vu = 0; vv = 1; + + u0 = (int64_t)u.bits64[0]; + v0 = (int64_t)v.bits64[0]; + bitCount = 0; + + // Slightly optimized Binary XCD loop on native signed integers + // Stop at 62 bits to avoid uv matrix overfow and loss of sign bit + while (true) { + + while (IS_EVEN(u0) && bitCount<62) { + + bitCount++; + u0 >>= 1; + vu <<= 1; + vv <<= 1; + + } + + if (bitCount == 62) + break; + + nb0 = (v0 + u0) & 0x3; + if (nb0 == 0) { + SWAP_ADD(uv, vv); + SWAP_ADD(uu, vu); + SWAP_ADD(u0, v0); + } else { + SWAP_SUB(uv, vv); + SWAP_SUB(uu, vu); + SWAP_SUB(u0, v0); + } + + } + + // Now update BigInt variables + + uu_u.IMult(&u,uu); + uv_v.IMult(&v,uv); + + vu_u.IMult(&u,vu); + vv_v.IMult(&v,vv); + + uu_r.IMult(&r,uu); + uv_s.IMult(&s,uv); + + vu_r.IMult(&r,vu); + vv_s.IMult(&s,vv); + + // Compute multiple of P to add to s and r to make them multiple of 2^62 + uint64_t r0 = ((uu_r.bits64[0] + uv_s.bits64[0]) * MM64) & MSK62; + uint64_t s0 = ((vu_r.bits64[0] + vv_s.bits64[0]) * MM64) & MSK62; + r0_P.Mult(&_P,r0); + s0_P.Mult(&_P,s0); + + // u = (uu*u + uv*v) + u.Add(&uu_u,&uv_v); + + // v = (vu*u + vv*v) + v.Add(&vu_u,&vv_v); + + // r = (uu*r + uv*s + r0*P) + r.Add(&uu_r,&uv_s); + r.Add(&r0_P); + + // s = (vu*r + vv*s + s0*P) + s.Add(&vu_r,&vv_s); + s.Add(&s0_P); + + // Right shift all variables by 62bits + shiftR(62, u.bits64); + shiftR(62, v.bits64); + shiftR(62, r.bits64); + shiftR(62, s.bits64); + + } + + // v ends with -1 or 1 + if (v.IsNegative()) { + // V = -1 + v.Neg(); + s.Neg(); + s.Add(&_P); + } + if (!v.IsOne()) { + // No inverse + CLEAR(); + return; + } + + if (s.IsNegative()) + s.Add(&_P); + + if (s.IsGreaterOrEqual(&_P)) + s.Sub(&_P); + + Set(&s); + +#endif + +} + +// ------------------------------------------------ + +void Int::ModExp(Int *e) { + + Int base(this); + SetInt32(1); + uint32_t i = 0; + + uint32_t nbBit = e->GetBitLength(); + for(int i=0;i<(int)nbBit;i++) { + if (e->GetBit(i)) + ModMul(&base); + base.ModMul(&base); + } + +} + +// ------------------------------------------------ + +void Int::ModMul(Int *a) { + + Int p; + p.MontgomeryMult(a, this); + MontgomeryMult(&_R2, &p); + +} + +// ------------------------------------------------ + +void Int::ModSquare(Int *a) { + + Int p; + p.MontgomeryMult(a, a); + MontgomeryMult(&_R2, &p); + +} + +// ------------------------------------------------ + +void Int::ModCube(Int *a) { + + Int p; + Int p2; + p.MontgomeryMult(a, a); + p2.MontgomeryMult(&p, a); + MontgomeryMult(&_R3, &p2); + +} + +// ------------------------------------------------ + +bool Int::HasSqrt() { + + // Euler's criterion + Int e(&_P); + Int a(this); + e.SubOne(); + e.ShiftR(1); + a.ModExp(&e); + + return a.IsOne(); + +} + +// ------------------------------------------------ + +void Int::ModSqrt() { + + if (_P.IsEven()) { + CLEAR(); + return; + } + + if (!HasSqrt()) { + CLEAR(); + return; + } + + if ((_P.bits64[0] & 3) == 3) { + + Int e(&_P); + e.AddOne(); + e.ShiftR(2); + ModExp(&e); + + } else if ((_P.bits64[0] & 3) == 1) { + + int nbBit = _P.GetBitLength(); + + // Tonelli Shanks + uint64_t e=0; + Int S(&_P); + S.SubOne(); + while (S.IsEven()) { + S.ShiftR(1); + e++; + } + + // Search smalest non-qresidue of P + Int q((uint64_t)1); + do { + q.AddOne(); + } while (q.HasSqrt()); + + Int c(&q); + c.ModExp(&S); + + Int t(this); + t.ModExp(&S); + + Int r(this); + Int ex(&S); + ex.AddOne(); + ex.ShiftR(1); + r.ModExp(&ex); + + uint64_t M = e; + while (!t.IsOne()) { + + Int t2(&t); + uint64_t i=0; + while (!t2.IsOne()) { + t2.ModSquare(&t2); + i++; + } + + Int b(&c); + for(uint64_t j=0;jGetSize(); + + // Last digit inversions (Newton's iteration) + { + int64_t x, t; + x = t = (int64_t)n->bits64[0]; + x = x * (2 - t * x); + x = x * (2 - t * x); + x = x * (2 - t * x); + x = x * (2 - t * x); + x = x * (2 - t * x); + MM64 = (uint64_t)(-x); + MM32 = (uint32_t)MM64; + } + _P.Set(n); + + // Size of Montgomery mult (64bits digit) + Msize = nSize/2; + + // Compute few power of R + // R = 2^(64*Msize) mod n + Int Ri; + Ri.MontgomeryMult(&_ONE, &_ONE); // Ri = R^-1 + _R.Set(&Ri); // R = R^-1 + _R2.MontgomeryMult(&Ri, &_ONE); // R2 = R^-2 + _R3.MontgomeryMult(&Ri, &Ri); // R3 = R^-3 + _R4.MontgomeryMult(&_R3, &_ONE); // R4 = R^-4 + + _R.ModInv(); // R = R + _R2.ModInv(); // R2 = R^2 + _R3.ModInv(); // R3 = R^3 + _R4.ModInv(); // R4 = R^4 + + if (R) + R->Set(&_R); + + if (R2) + R2->Set(&_R2); + + if (R3) + R3->Set(&_R3); + + if (R4) + R4->Set(&_R4); + +} +// ------------------------------------------------ + +uint64_t Int::AddC(Int *a) { + + unsigned char c = 0; + c = _addcarry_u64(c, bits64[0], a->bits64[0], bits64 + 0); + c = _addcarry_u64(c, bits64[1], a->bits64[1], bits64 + 1); + c = _addcarry_u64(c, bits64[2], a->bits64[2], bits64 + 2); + c = _addcarry_u64(c, bits64[3], a->bits64[3], bits64 + 3); + c = _addcarry_u64(c, bits64[4], a->bits64[4], bits64 + 4); +#if NB64BLOCK > 5 + c = _addcarry_u64(c, bits64[5], a->bits64[5], bits64 + 5); + c = _addcarry_u64(c, bits64[6], a->bits64[6], bits64 + 6); + c = _addcarry_u64(c, bits64[7], a->bits64[7], bits64 + 7); + c = _addcarry_u64(c, bits64[8], a->bits64[8], bits64 + 8); +#endif + + return c; + +} + +// ------------------------------------------------ + +void Int::AddAndShift(Int *a, Int *b, uint64_t cH) { + + unsigned char c = 0; + c = _addcarry_u64(c, b->bits64[0], a->bits64[0], bits64 + 0); + c = _addcarry_u64(c, b->bits64[1], a->bits64[1], bits64 + 0); + c = _addcarry_u64(c, b->bits64[2], a->bits64[2], bits64 + 1); + c = _addcarry_u64(c, b->bits64[3], a->bits64[3], bits64 + 2); + c = _addcarry_u64(c, b->bits64[4], a->bits64[4], bits64 + 3); +#if NB64BLOCK > 5 + c = _addcarry_u64(c, b->bits64[5], a->bits64[5], bits64 + 4); + c = _addcarry_u64(c, b->bits64[6], a->bits64[6], bits64 + 5); + c = _addcarry_u64(c, b->bits64[7], a->bits64[7], bits64 + 6); + c = _addcarry_u64(c, b->bits64[8], a->bits64[8], bits64 + 7); +#endif + + bits64[NB64BLOCK-1] = c + cH; + +} + +// ------------------------------------------------ +void Int::MontgomeryMult(Int *a) { + + // Compute a*b*R^-1 (mod n), R=2^k (mod n), k = Msize*64 + // a and b must be lower than n + // See SetupField() + + Int t; + Int pr; + Int p; + uint64_t ML; + uint64_t c; + + // i = 0 + imm_umul(a->bits64, bits64[0], pr.bits64); + ML = pr.bits64[0] * MM64; + imm_umul(_P.bits64, ML, p.bits64); + c = pr.AddC(&p); + memcpy(t.bits64, pr.bits64 + 1, 8 * (NB64BLOCK - 1)); + t.bits64[NB64BLOCK - 1] = c; + + for (int i = 1; i < Msize; i++) { + + imm_umul(a->bits64, bits64[i], pr.bits64); + ML = (pr.bits64[0] + t.bits64[0]) * MM64; + imm_umul(_P.bits64, ML, p.bits64); + c = pr.AddC(&p); + t.AddAndShift(&t, &pr, c); + + } + + p.Sub(&t,&_P); + if (p.IsPositive()) + Set(&p); + else + Set(&t); + +} + +void Int::MontgomeryMult(Int *a, Int *b) { + + // Compute a*b*R^-1 (mod n), R=2^k (mod n), k = Msize*64 + // a and b must be lower than n + // See SetupField() + + Int pr; + Int p; + uint64_t ML; + uint64_t c; + + // i = 0 + imm_umul(a->bits64, b->bits64[0], pr.bits64); + ML = pr.bits64[0] * MM64; + imm_umul(_P.bits64, ML, p.bits64); + c = pr.AddC(&p); + memcpy(bits64,pr.bits64 + 1,8*(NB64BLOCK-1)); + bits64[NB64BLOCK-1] = c; + + for (int i = 1; i < Msize; i++) { + + imm_umul(a->bits64, b->bits64[i], pr.bits64); + ML = (pr.bits64[0] + bits64[0]) * MM64; + imm_umul(_P.bits64, ML, p.bits64); + c = pr.AddC(&p); + AddAndShift(this, &pr, c); + + } + + p.Sub(this, &_P); + if (p.IsPositive()) + Set(&p); + +} + + +// SecpK1 specific section ----------------------------------------------------------------------------- + +void Int::ModMulK1(Int *a, Int *b) { + +#ifndef WIN64 +#if (__GNUC__ > 7) || (__GNUC__ == 7 && (__GNUC_MINOR__ > 2)) + unsigned char c; +#else + #warning "GCC lass than 7.3 detected, upgrade gcc to get best perfromance" + volatile unsigned char c; +#endif +#else + unsigned char c; +#endif + + + uint64_t ah, al; + uint64_t t[5]; + uint64_t r512[8]; + r512[5] = 0; + r512[6] = 0; + r512[7] = 0; + + // 256*256 multiplier + imm_umul(a->bits64, b->bits64[0], r512); + imm_umul(a->bits64, b->bits64[1], t); + c = _addcarry_u64(0, r512[1], t[0], r512 + 1); + c = _addcarry_u64(c, r512[2], t[1], r512 + 2); + c = _addcarry_u64(c, r512[3], t[2], r512 + 3); + c = _addcarry_u64(c, r512[4], t[3], r512 + 4); + c = _addcarry_u64(c, r512[5], t[4], r512 + 5); + imm_umul(a->bits64, b->bits64[2], t); + c = _addcarry_u64(0, r512[2], t[0], r512 + 2); + c = _addcarry_u64(c, r512[3], t[1], r512 + 3); + c = _addcarry_u64(c, r512[4], t[2], r512 + 4); + c = _addcarry_u64(c, r512[5], t[3], r512 + 5); + c = _addcarry_u64(c, r512[6], t[4], r512 + 6); + imm_umul(a->bits64, b->bits64[3], t); + c = _addcarry_u64(0, r512[3], t[0], r512 + 3); + c = _addcarry_u64(c, r512[4], t[1], r512 + 4); + c = _addcarry_u64(c, r512[5], t[2], r512 + 5); + c = _addcarry_u64(c, r512[6], t[3], r512 + 6); + c = _addcarry_u64(c, r512[7], t[4], r512 + 7); + + // Reduce from 512 to 320 + imm_umul(r512 + 4, 0x1000003D1ULL, t); + c = _addcarry_u64(0, r512[0], t[0], r512 + 0); + c = _addcarry_u64(c, r512[1], t[1], r512 + 1); + c = _addcarry_u64(c, r512[2], t[2], r512 + 2); + c = _addcarry_u64(c, r512[3], t[3], r512 + 3); + + // Reduce from 320 to 256 + // No overflow possible here t[4]+c<=0x1000003D1ULL + al = _umul128(t[4] + c, 0x1000003D1ULL, &ah); + c = _addcarry_u64(0, r512[0], al, bits64 + 0); + c = _addcarry_u64(c, r512[1], ah, bits64 + 1); + c = _addcarry_u64(c, r512[2], 0ULL, bits64 + 2); + c = _addcarry_u64(c, r512[3], 0ULL, bits64 + 3); + + // Probability of carry here or that this>P is very very unlikely + bits64[4] = 0; + +} + +void Int::ModMulK1(Int *a) { + +#ifndef WIN64 +#if (__GNUC__ > 7) || (__GNUC__ == 7 && (__GNUC_MINOR__ > 2)) + unsigned char c; +#else + #warning "GCC lass than 7.3 detected, upgrade gcc to get best perfromance" + volatile unsigned char c; +#endif +#else + unsigned char c; +#endif + + uint64_t ah, al; + uint64_t t[5]; + uint64_t r512[8]; + r512[5] = 0; + r512[6] = 0; + r512[7] = 0; + + // 256*256 multiplier + imm_umul(a->bits64, bits64[0], r512); + imm_umul(a->bits64, bits64[1], t); + c = _addcarry_u64(0, r512[1], t[0], r512 + 1); + c = _addcarry_u64(c, r512[2], t[1], r512 + 2); + c = _addcarry_u64(c, r512[3], t[2], r512 + 3); + c = _addcarry_u64(c, r512[4], t[3], r512 + 4); + c = _addcarry_u64(c, r512[5], t[4], r512 + 5); + imm_umul(a->bits64, bits64[2], t); + c = _addcarry_u64(0, r512[2], t[0], r512 + 2); + c = _addcarry_u64(c, r512[3], t[1], r512 + 3); + c = _addcarry_u64(c, r512[4], t[2], r512 + 4); + c = _addcarry_u64(c, r512[5], t[3], r512 + 5); + c = _addcarry_u64(c, r512[6], t[4], r512 + 6); + imm_umul(a->bits64, bits64[3], t); + c = _addcarry_u64(0, r512[3], t[0], r512 + 3); + c = _addcarry_u64(c, r512[4], t[1], r512 + 4); + c = _addcarry_u64(c, r512[5], t[2], r512 + 5); + c = _addcarry_u64(c, r512[6], t[3], r512 + 6); + c = _addcarry_u64(c, r512[7], t[4], r512 + 7); + + // Reduce from 512 to 320 + imm_umul(r512 + 4, 0x1000003D1ULL, t); + c = _addcarry_u64(0, r512[0], t[0], r512 + 0); + c = _addcarry_u64(c, r512[1], t[1], r512 + 1); + c = _addcarry_u64(c, r512[2], t[2], r512 + 2); + c = _addcarry_u64(c, r512[3], t[3], r512 + 3); + + // Reduce from 320 to 256 + // No overflow possible here t[4]+c<=0x1000003D1ULL + al = _umul128(t[4] + c, 0x1000003D1ULL, &ah); + c = _addcarry_u64(0, r512[0], al, bits64 + 0); + c = _addcarry_u64(c, r512[1], ah, bits64 + 1); + c = _addcarry_u64(c, r512[2], 0, bits64 + 2); + c = _addcarry_u64(c, r512[3], 0, bits64 + 3); + // Probability of carry here or that this>P is very very unlikely + bits64[4] = 0; + +} + +void Int::ModSquareK1(Int *a) { + +#ifndef WIN64 +#if (__GNUC__ > 7) || (__GNUC__ == 7 && (__GNUC_MINOR__ > 2)) + unsigned char c; +#else + #warning "GCC lass than 7.3 detected, upgrade gcc to get best perfromance" + volatile unsigned char c; +#endif +#else + unsigned char c; +#endif + + uint64_t r512[8]; + uint64_t u10, u11; + uint64_t t1; + uint64_t t2; + uint64_t t[5]; + + + //k=0 + r512[0] = _umul128(a->bits64[0], a->bits64[0], &t[1]); + + //k=1 + t[3] = _umul128(a->bits64[0], a->bits64[1], &t[4]); + c = _addcarry_u64(0, t[3], t[3], &t[3]); + c = _addcarry_u64(c, t[4], t[4], &t[4]); + c = _addcarry_u64(c, 0, 0, &t1); + c = _addcarry_u64(0, t[1], t[3], &t[3]); + c = _addcarry_u64(c, t[4], 0, &t[4]); + c = _addcarry_u64(c, t1, 0, &t1); + r512[1] = t[3]; + + //k=2 + t[0] = _umul128(a->bits64[0], a->bits64[2], &t[1]); + c = _addcarry_u64(0, t[0], t[0], &t[0]); + c = _addcarry_u64(c, t[1], t[1], &t[1]); + c = _addcarry_u64(c, 0, 0, &t2); + + u10 = _umul128(a->bits64[1], a->bits64[1], &u11); + c = _addcarry_u64(0, t[0] , u10, &t[0]); + c = _addcarry_u64(c, t[1] , u11, &t[1]); + c = _addcarry_u64(c, t2 , 0, &t2); + c = _addcarry_u64(0, t[0], t[4], &t[0]); + c = _addcarry_u64(c, t[1], t1, &t[1]); + c = _addcarry_u64(c, t2, 0, &t2); + r512[2] = t[0]; + + //k=3 + t[3] = _umul128(a->bits64[0], a->bits64[3], &t[4]); + u10 = _umul128(a->bits64[1], a->bits64[2], &u11); + + c = _addcarry_u64(0, t[3], u10, &t[3]); + c = _addcarry_u64(c, t[4], u11, &t[4]); + c = _addcarry_u64(c, 0, 0, &t1); + t1 += t1; + c = _addcarry_u64(0, t[3], t[3], &t[3]); + c = _addcarry_u64(c, t[4], t[4], &t[4]); + c = _addcarry_u64(c, t1, 0, &t1); + c = _addcarry_u64(0, t[3], t[1], &t[3]); + c = _addcarry_u64(c, t[4], t2, &t[4]); + c = _addcarry_u64(c, t1, 0, &t1); + r512[3] = t[3]; + + //k=4 + t[0] = _umul128(a->bits64[1], a->bits64[3], &t[1]); + c = _addcarry_u64(0, t[0], t[0], &t[0]); + c = _addcarry_u64(c, t[1], t[1], &t[1]); + c = _addcarry_u64(c, 0, 0, &t2); + + u10 = _umul128(a->bits64[2], a->bits64[2], &u11); + c = _addcarry_u64(0, t[0], u10, &t[0]); + c = _addcarry_u64(c, t[1], u11, &t[1]); + c = _addcarry_u64(c, t2, 0, &t2); + c = _addcarry_u64(0, t[0], t[4], &t[0]); + c = _addcarry_u64(c, t[1], t1, &t[1]); + c = _addcarry_u64(c, t2, 0, &t2); + r512[4] = t[0]; + + //k=5 + t[3] = _umul128(a->bits64[2], a->bits64[3], &t[4]); + c = _addcarry_u64(0, t[3], t[3], &t[3]); + c = _addcarry_u64(c, t[4], t[4], &t[4]); + c = _addcarry_u64(c, 0, 0, &t1); + c = _addcarry_u64(0, t[3], t[1], &t[3]); + c = _addcarry_u64(c, t[4], t2, &t[4]); + c = _addcarry_u64(c, t1, 0, &t1); + r512[5] = t[3]; + + //k=6 + t[0] = _umul128(a->bits64[3], a->bits64[3], &t[1]); + c = _addcarry_u64(0, t[0], t[4], &t[0]); + c = _addcarry_u64(c, t[1], t1, &t[1]); + r512[6] = t[0]; + + //k=7 + r512[7] = t[1]; + + // Reduce from 512 to 320 + // Reduce from 512 to 320 + imm_umul(r512 + 4, 0x1000003D1ULL, t); + c = _addcarry_u64(0, r512[0], t[0], r512 + 0); + c = _addcarry_u64(c, r512[1], t[1], r512 + 1); + c = _addcarry_u64(c, r512[2], t[2], r512 + 2); + c = _addcarry_u64(c, r512[3], t[3], r512 + 3); + + // Reduce from 320 to 256 + // No overflow possible here t[4]+c<=0x1000003D1ULL + u10 = _umul128(t[4] + c, 0x1000003D1ULL, &u11); + c = _addcarry_u64(0, r512[0], u10, bits64 + 0); + c = _addcarry_u64(c, r512[1], u11, bits64 + 1); + c = _addcarry_u64(c, r512[2], 0, bits64 + 2); + c = _addcarry_u64(c, r512[3], 0, bits64 + 3); + // Probability of carry here or that this>P is very very unlikely + bits64[4] = 0; + +} + +static Int _R2o; // R^2 for SecpK1 order modular mult +static uint64_t MM64o = 0x4B0DFF665588B13FULL; // 64bits lsb negative inverse of SecpK1 order +static Int *_O; // SecpK1 order + +void Int::InitK1(Int *order) { + _O = order; + _R2o.SetBase16("9D671CD581C69BC5E697F5E45BCD07C6741496C20E7CF878896CF21467D7D140"); +} + +void Int::ModAddK1order(Int *a, Int *b) { + Add(a,b); + Sub(_O); + if (IsNegative()) + Add(_O); +} + +void Int::ModMulK1order(Int *a) { + + Int t; + Int pr; + Int p; + uint64_t ML; + uint64_t c; + + imm_umul(a->bits64, bits64[0], pr.bits64); + ML = pr.bits64[0] * MM64o; + imm_umul(_O->bits64, ML, p.bits64); + c = pr.AddC(&p); + memcpy(t.bits64, pr.bits64 + 1, 32); + t.bits64[4] = c; + + for (int i = 1; i < 4; i++) { + + imm_umul(a->bits64, bits64[i], pr.bits64); + ML = (pr.bits64[0] + t.bits64[0]) * MM64o; + imm_umul(_O->bits64, ML, p.bits64); + c = pr.AddC(&p); + t.AddAndShift(&t, &pr, c); + + } + + p.Sub(&t, _O); + if (p.IsPositive()) + Set(&p); + else + Set(&t); + + + // Normalize + + imm_umul(_R2o.bits64, bits64[0], pr.bits64); + ML = pr.bits64[0] * MM64o; + imm_umul(_O->bits64, ML, p.bits64); + c = pr.AddC(&p); + memcpy(t.bits64, pr.bits64 + 1, 32); + t.bits64[4] = c; + + for (int i = 1; i < 4; i++) { + + imm_umul(_R2o.bits64, bits64[i], pr.bits64); + ML = (pr.bits64[0] + t.bits64[0]) * MM64o; + imm_umul(_O->bits64, ML, p.bits64); + c = pr.AddC(&p); + t.AddAndShift(&t, &pr, c); + + } + + p.Sub(&t, _O); + if (p.IsPositive()) + Set(&p); + else + Set(&t); + +} diff --git a/secp256k1/Point.cpp b/secp256k1/Point.cpp new file mode 100644 index 0000000..e05e964 --- /dev/null +++ b/secp256k1/Point.cpp @@ -0,0 +1,89 @@ +/* + * This file is part of the BSGS distribution (https://github.com/JeanLucPons/BSGS). + * Copyright (c) 2020 Jean Luc PONS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +#include "Point.h" + +Point::Point() { +} + +Point::Point(const Point &p) { + x.Set((Int *)&p.x); + y.Set((Int *)&p.y); + z.Set((Int *)&p.z); +} + +Point::Point(Int *cx,Int *cy,Int *cz) { + x.Set(cx); + y.Set(cy); + z.Set(cz); +} + +Point::Point(Int *cx, Int *cz) { + x.Set(cx); + z.Set(cz); +} + +void Point::Clear() { + x.SetInt32(0); + y.SetInt32(0); + z.SetInt32(0); +} + +void Point::Set(Int *cx, Int *cy,Int *cz) { + x.Set(cx); + y.Set(cy); + z.Set(cz); +} + +Point::~Point() { +} + +void Point::Set(Point &p) { + x.Set(&p.x); + y.Set(&p.y); +} + +bool Point::isZero() { + return x.IsZero() && y.IsZero(); +} + +void Point::Reduce() { + + Int i(&z); + i.ModInv(); + x.ModMul(&x,&i); + y.ModMul(&y,&i); + z.SetInt32(1); + +} + +bool Point::equals(Point &p) { + return x.IsEqual(&p.x) && y.IsEqual(&p.y) && z.IsEqual(&p.z); +} + +/* +std::string Point::toString() { + + std::string ret; + ret = "X=" + x.GetBase16() + "\n"; + ret += "Y=" + y.GetBase16() + "\n"; + ret += "Z=" + z.GetBase16() + "\n"; + return ret; + +} + +*/ diff --git a/secp256k1/Point.h b/secp256k1/Point.h new file mode 100644 index 0000000..a727ee3 --- /dev/null +++ b/secp256k1/Point.h @@ -0,0 +1,46 @@ +/* + * This file is part of the BSGS distribution (https://github.com/JeanLucPons/BSGS). + * Copyright (c) 2020 Jean Luc PONS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +#ifndef POINTH +#define POINTH + +#include "Int.h" + +class Point { + +public: + + Point(); + Point(Int *cx,Int *cy,Int *cz); + Point(Int *cx, Int *cz); + Point(const Point &p); + ~Point(); + bool isZero(); + bool equals(Point &p); + void Set(Point &p); + void Set(Int *cx, Int *cy,Int *cz); + void Clear(); + void Reduce(); + //std::string toString(); + + Int x; + Int y; + Int z; + +}; + +#endif // POINTH diff --git a/secp256k1/Random.cpp b/secp256k1/Random.cpp new file mode 100644 index 0000000..279c3ec --- /dev/null +++ b/secp256k1/Random.cpp @@ -0,0 +1,117 @@ +/* + * This file is part of the BSGS distribution (https://github.com/JeanLucPons/BSGS). + * Copyright (c) 2020 Jean Luc PONS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +#include "Random.h" + +#define RK_STATE_LEN 624 + +/* State of the RNG */ +typedef struct rk_state_ +{ + unsigned long key[RK_STATE_LEN]; + int pos; +} rk_state; + +rk_state localState; + +/* Maximum generated random value */ +#define RK_MAX 0xFFFFFFFFUL + +void rk_seed(unsigned long seed, rk_state *state) +{ + int pos; + seed &= 0xffffffffUL; + + /* Knuth's PRNG as used in the Mersenne Twister reference implementation */ + for (pos=0; poskey[pos] = seed; + seed = (1812433253UL * (seed ^ (seed >> 30)) + pos + 1) & 0xffffffffUL; + } + + state->pos = RK_STATE_LEN; +} + +/* Magic Mersenne Twister constants */ +#define N 624 +#define M 397 +#define MATRIX_A 0x9908b0dfUL +#define UPPER_MASK 0x80000000UL +#define LOWER_MASK 0x7fffffffUL + +#ifdef WIN32 +// Disable "unary minus operator applied to unsigned type, result still unsigned" warning. +#pragma warning(disable : 4146) +#endif + +/* Slightly optimised reference implementation of the Mersenne Twister */ +inline unsigned long rk_random(rk_state *state) +{ + unsigned long y; + + if (state->pos == RK_STATE_LEN) + { + int i; + + for (i=0;ikey[i] & UPPER_MASK) | (state->key[i+1] & LOWER_MASK); + state->key[i] = state->key[i+M] ^ (y>>1) ^ (-(y & 1) & MATRIX_A); + } + for (;ikey[i] & UPPER_MASK) | (state->key[i+1] & LOWER_MASK); + state->key[i] = state->key[i+(M-N)] ^ (y>>1) ^ (-(y & 1) & MATRIX_A); + } + y = (state->key[N-1] & UPPER_MASK) | (state->key[0] & LOWER_MASK); + state->key[N-1] = state->key[M-1] ^ (y>>1) ^ (-(y & 1) & MATRIX_A); + + state->pos = 0; + } + + y = state->key[state->pos++]; + + /* Tempering */ + y ^= (y >> 11); + y ^= (y << 7) & 0x9d2c5680UL; + y ^= (y << 15) & 0xefc60000UL; + y ^= (y >> 18); + + return y; +} + +inline double rk_double(rk_state *state) +{ + /* shifts : 67108864 = 0x4000000, 9007199254740992 = 0x20000000000000 */ + long a = rk_random(state) >> 5, b = rk_random(state) >> 6; + return (a * 67108864.0 + b) / 9007199254740992.0; +} + +// Initialise the random generator with the specified seed +void rseed(unsigned long seed) { + rk_seed(seed,&localState); + //srand(seed); +} + +unsigned long rndl() { + return rk_random(&localState); +} + +// Returns a uniform distributed double value in the interval ]0,1[ +double rnd() { + return rk_double(&localState); +} diff --git a/secp256k1/Random.h b/secp256k1/Random.h new file mode 100644 index 0000000..cab31ca --- /dev/null +++ b/secp256k1/Random.h @@ -0,0 +1,25 @@ +/* + * This file is part of the BSGS distribution (https://github.com/JeanLucPons/BSGS). + * Copyright (c) 2020 Jean Luc PONS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +#ifndef RANDOM_H +#define RANDOM_H + +double rnd(); +unsigned long rndl(); +void rseed(unsigned long seed); + +#endif diff --git a/secp256k1/SECP256K1.cpp b/secp256k1/SECP256K1.cpp new file mode 100644 index 0000000..997441a --- /dev/null +++ b/secp256k1/SECP256K1.cpp @@ -0,0 +1,422 @@ +/* + * This file is part of the BSGS distribution (https://github.com/JeanLucPons/BSGS). + * Copyright (c) 2020 Jean Luc PONS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +#include +#include +#include "SECP256k1.h" +#include "util.h" + +Secp256K1::Secp256K1() { +} + +void Secp256K1::Init() { + // Prime for the finite field + Int P; + P.SetBase16("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F"); + + // Set up field + Int::SetupField(&P); + + // Generator point and order + G.x.SetBase16("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"); + G.y.SetBase16("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"); + G.z.SetInt32(1); + order.SetBase16("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"); + + Int::InitK1(&order); + + // Compute Generator table + Point N(G); + for(int i = 0; i < 32; i++) { + GTable[i * 256] = N; + N = DoubleDirect(N); + for (int j = 1; j < 255; j++) { + GTable[i * 256 + j] = N; + N = AddDirect(N, GTable[i * 256]); + } + GTable[i * 256 + 255] = N; // Dummy point for check function + } + +} + +Secp256K1::~Secp256K1() { +} + +Point Secp256K1::ComputePublicKey(Int *privKey) { + int i = 0; + uint8_t b; + Point Q; + Q.Clear(); + // Search first significant byte + for (i = 0; i < 32; i++) { + b = privKey->GetByte(i); + if(b) + break; + } + Q = GTable[256 * i + (b-1)]; + i++; + + for(; i < 32; i++) { + b = privKey->GetByte(i); + if(b) + Q = Add2(Q, GTable[256 * i + (b-1)]); + } + Q.Reduce(); + return Q; +} + +Point Secp256K1::NextKey(Point &key) { + // Input key must be reduced and different from G + // in order to use AddDirect + return AddDirect(key,G); +} + +uint8_t Secp256K1::GetByte(char *str, int idx) { + char tmp[3]; + int val; + tmp[0] = str[2 * idx]; + tmp[1] = str[2 * idx + 1]; + tmp[2] = 0; + if (sscanf(tmp, "%X", &val) != 1) { + printf("ParsePublicKeyHex: Error invalid public key specified (unexpected hexadecimal digit)\n"); + exit(-1); + } + return (uint8_t)val; +} + +bool Secp256K1::ParsePublicKeyHex(char *str,Point &ret,bool &isCompressed) { + int len = strlen(str); + ret.Clear(); + if (len < 2) { + printf("ParsePublicKeyHex: Error invalid public key specified (66 or 130 character length)\n"); + return false; + } + uint8_t type = GetByte(str, 0); + switch (type) { + case 0x02: + if (len != 66) { + printf("ParsePublicKeyHex: Error invalid public key specified (66 character length)\n"); + return false; + } + for (int i = 0; i < 32; i++) + ret.x.SetByte(31 - i, GetByte(str, i + 1)); + ret.y = GetY(ret.x, true); + isCompressed = true; + break; + + case 0x03: + if (len != 66) { + printf("ParsePublicKeyHex: Error invalid public key specified (66 character length)\n"); + return false; + } + for (int i = 0; i < 32; i++) + ret.x.SetByte(31 - i, GetByte(str, i + 1)); + ret.y = GetY(ret.x, false); + isCompressed = true; + break; + + case 0x04: + if (len != 130) { + printf("ParsePublicKeyHex: Error invalid public key specified (130 character length)\n"); + exit(-1); + } + for (int i = 0; i < 32; i++) + ret.x.SetByte(31 - i, GetByte(str, i + 1)); + for (int i = 0; i < 32; i++) + ret.y.SetByte(31 - i, GetByte(str, i + 33)); + isCompressed = false; + break; + + default: + printf("ParsePublicKeyHex: Error invalid public key specified (Unexpected prefix (only 02,03 or 04 allowed)\n"); + return false; + } + + ret.z.SetInt32(1); + + if (!EC(ret)) { + printf("ParsePublicKeyHex: Error invalid public key specified (Not lie on elliptic curve)\n"); + return false; + } + + return true; +} + +char* Secp256K1::GetPublicKeyHex(bool compressed, Point &pubKey) { + unsigned char publicKeyBytes[128]; + char *ret; + if (!compressed) { + //Uncompressed public key + publicKeyBytes[0] = 0x4; + pubKey.x.Get32Bytes(publicKeyBytes + 1); + pubKey.y.Get32Bytes(publicKeyBytes + 33); + ret = (char*) tohex((char*)publicKeyBytes,65); + } + else { + // Compressed public key + publicKeyBytes[0] = pubKey.y.IsEven() ? 0x2 : 0x3; + pubKey.x.Get32Bytes(publicKeyBytes + 1); + ret = (char*) tohex((char*)publicKeyBytes,33); + } + return ret; +} + +Point Secp256K1::AddDirect(Point &p1,Point &p2) { + Int _s; + Int _p; + Int dy; + Int dx; + Point r; + r.z.SetInt32(1); + + dy.ModSub(&p2.y,&p1.y); + dx.ModSub(&p2.x,&p1.x); + dx.ModInv(); + _s.ModMulK1(&dy,&dx); // s = (p2.y-p1.y)*inverse(p2.x-p1.x); + + _p.ModSquareK1(&_s); // _p = pow2(s) + + r.x.ModSub(&_p,&p1.x); + r.x.ModSub(&p2.x); // rx = pow2(s) - p1.x - p2.x; + + r.y.ModSub(&p2.x,&r.x); + r.y.ModMulK1(&_s); + r.y.ModSub(&p2.y); // ry = - p2.y - s*(ret.x-p2.x); + + return r; +} + +Point Secp256K1::Add2(Point &p1, Point &p2) { + // P2.z = 1 + Int u; + Int v; + Int u1; + Int v1; + Int vs2; + Int vs3; + Int us2; + Int a; + Int us2w; + Int vs2v2; + Int vs3u2; + Int _2vs2v2; + Point r; + u1.ModMulK1(&p2.y, &p1.z); + v1.ModMulK1(&p2.x, &p1.z); + u.ModSub(&u1, &p1.y); + v.ModSub(&v1, &p1.x); + us2.ModSquareK1(&u); + vs2.ModSquareK1(&v); + vs3.ModMulK1(&vs2, &v); + us2w.ModMulK1(&us2, &p1.z); + vs2v2.ModMulK1(&vs2, &p1.x); + _2vs2v2.ModAdd(&vs2v2, &vs2v2); + a.ModSub(&us2w, &vs3); + a.ModSub(&_2vs2v2); + + r.x.ModMulK1(&v, &a); + + vs3u2.ModMulK1(&vs3, &p1.y); + r.y.ModSub(&vs2v2, &a); + r.y.ModMulK1(&r.y, &u); + r.y.ModSub(&vs3u2); + + r.z.ModMulK1(&vs3, &p1.z); + + return r; +} + +Point Secp256K1::Add(Point &p1,Point &p2) { + Int u; + Int v; + Int u1; + Int u2; + Int v1; + Int v2; + Int vs2; + Int vs3; + Int us2; + Int w; + Int a; + Int us2w; + Int vs2v2; + Int vs3u2; + Int _2vs2v2; + Int x3; + Int vs3y1; + Point r; + + /* + U1 = Y2 * Z1 + U2 = Y1 * Z2 + V1 = X2 * Z1 + V2 = X1 * Z2 + if (V1 == V2) + if (U1 != U2) + return POINT_AT_INFINITY + else + return POINT_DOUBLE(X1, Y1, Z1) + U = U1 - U2 + V = V1 - V2 + W = Z1 * Z2 + A = U ^ 2 * W - V ^ 3 - 2 * V ^ 2 * V2 + X3 = V * A + Y3 = U * (V ^ 2 * V2 - A) - V ^ 3 * U2 + Z3 = V ^ 3 * W + return (X3, Y3, Z3) + */ + + u1.ModMulK1(&p2.y,&p1.z); + u2.ModMulK1(&p1.y,&p2.z); + v1.ModMulK1(&p2.x,&p1.z); + v2.ModMulK1(&p1.x,&p2.z); + u.ModSub(&u1,&u2); + v.ModSub(&v1,&v2); + w.ModMulK1(&p1.z,&p2.z); + us2.ModSquareK1(&u); + vs2.ModSquareK1(&v); + vs3.ModMulK1(&vs2,&v); + us2w.ModMulK1(&us2,&w); + vs2v2.ModMulK1(&vs2,&v2); + _2vs2v2.ModAdd(&vs2v2,&vs2v2); + a.ModSub(&us2w,&vs3); + a.ModSub(&_2vs2v2); + + r.x.ModMulK1(&v,&a); + + vs3u2.ModMulK1(&vs3,&u2); + r.y.ModSub(&vs2v2,&a); + r.y.ModMulK1(&r.y,&u); + r.y.ModSub(&vs3u2); + + r.z.ModMulK1(&vs3,&w); + + return r; +} + +Point Secp256K1::DoubleDirect(Point &p) { + Int _s; + Int _p; + Int a; + Point r; + r.z.SetInt32(1); + _s.ModMulK1(&p.x,&p.x); + _p.ModAdd(&_s,&_s); + _p.ModAdd(&_s); + + a.ModAdd(&p.y,&p.y); + a.ModInv(); + _s.ModMulK1(&_p,&a); // s = (3*pow2(p.x))*inverse(2*p.y); + + _p.ModMulK1(&_s,&_s); + a.ModAdd(&p.x,&p.x); + a.ModNeg(); + r.x.ModAdd(&a,&_p); // rx = pow2(s) + neg(2*p.x); + + a.ModSub(&r.x,&p.x); + + _p.ModMulK1(&a,&_s); + r.y.ModAdd(&_p,&p.y); + r.y.ModNeg(); // ry = neg(p.y + s*(ret.x+neg(p.x))); + return r; +} + +Point Secp256K1::Double(Point &p) { + /* + if (Y == 0) + return POINT_AT_INFINITY + W = a * Z ^ 2 + 3 * X ^ 2 + S = Y * Z + B = X * Y*S + H = W ^ 2 - 8 * B + X' = 2*H*S + Y' = W*(4*B - H) - 8*Y^2*S^2 + Z' = 8*S^3 + return (X', Y', Z') + */ + Int z2; + Int x2; + Int _3x2; + Int w; + Int s; + Int s2; + Int b; + Int _8b; + Int _8y2s2; + Int y2; + Int h; + Point r; + z2.ModSquareK1(&p.z); + z2.SetInt32(0); // a=0 + x2.ModSquareK1(&p.x); + _3x2.ModAdd(&x2,&x2); + _3x2.ModAdd(&x2); + w.ModAdd(&z2,&_3x2); + s.ModMulK1(&p.y,&p.z); + b.ModMulK1(&p.y,&s); + b.ModMulK1(&p.x); + h.ModSquareK1(&w); + _8b.ModAdd(&b,&b); + _8b.ModDouble(); + _8b.ModDouble(); + h.ModSub(&_8b); + r.x.ModMulK1(&h,&s); + r.x.ModAdd(&r.x); + s2.ModSquareK1(&s); + y2.ModSquareK1(&p.y); + _8y2s2.ModMulK1(&y2,&s2); + _8y2s2.ModDouble(); + _8y2s2.ModDouble(); + _8y2s2.ModDouble(); + r.y.ModAdd(&b,&b); + r.y.ModAdd(&r.y,&r.y); + r.y.ModSub(&h); + r.y.ModMulK1(&w); + r.y.ModSub(&_8y2s2); + r.z.ModMulK1(&s2,&s); + r.z.ModDouble(); + r.z.ModDouble(); + r.z.ModDouble(); + return r; +} + +Int Secp256K1::GetY(Int x,bool isEven) { + Int _s; + Int _p; + _s.ModSquareK1(&x); + _p.ModMulK1(&_s,&x); + _p.ModAdd(7); + _p.ModSqrt(); + if(!_p.IsEven() && isEven) { + _p.ModNeg(); + } + else if(_p.IsEven() && !isEven) { + _p.ModNeg(); + } + return _p; +} + +bool Secp256K1::EC(Point &p) { + Int _s; + Int _p; + _s.ModSquareK1(&p.x); + _p.ModMulK1(&_s,&p.x); + _p.ModAdd(7); + _s.ModMulK1(&p.y,&p.y); + _s.ModSub(&_p); + return _s.IsZero(); // ( ((pow2(y) - (pow3(x) + 7)) % P) == 0 ); +} diff --git a/secp256k1/SECP256k1.h b/secp256k1/SECP256k1.h new file mode 100644 index 0000000..0f59283 --- /dev/null +++ b/secp256k1/SECP256k1.h @@ -0,0 +1,55 @@ +/* + * This file is part of the BSGS distribution (https://github.com/JeanLucPons/BSGS). + * Copyright (c) 2020 Jean Luc PONS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +#ifndef SECP256K1H +#define SECP256K1H + +#include "Point.h" +#include + +class Secp256K1 { + +public: + + Secp256K1(); + ~Secp256K1(); + void Init(); + Point ComputePublicKey(Int *privKey); + Point NextKey(Point &key); + bool EC(Point &p); + + char* GetPublicKeyHex(bool compressed, Point &p); + bool ParsePublicKeyHex(char *str,Point &p,bool &isCompressed); + + Point Add(Point &p1, Point &p2); + Point Add2(Point &p1, Point &p2); + Point AddDirect(Point &p1, Point &p2); + Point Double(Point &p); + Point DoubleDirect(Point &p); + + Point G; // Generator + Int order; // Curve order + +private: + + uint8_t GetByte(char *str,int idx); + Int GetY(Int x, bool isEven); + Point GTable[256*32]; // Generator table + +}; + +#endif // SECP256K1H diff --git a/secp256k1/test b/secp256k1/test new file mode 100755 index 0000000000000000000000000000000000000000..8bcb34b95267c46c6f12602959ac929994aabb0d GIT binary patch literal 63208 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 +#include +#include +//#include +#include "SECP256k1.h" +#include "Point.h" +#include "Int.h" + +#include "util.h" + +Secp256K1 *secp; + +int main() { + char dst[32]; + Int key; + char *test; + secp = new Secp256K1(); + key = new Int(); + secp->Init(); + Point punto; + bool parity; + if(secp->ParsePublicKeyHex((char*)"04ceb6cbbcdbdf5ef7150682150f4ce2c6f4807b349827dcdbdd1f2efa885a26302b195386bea3f5f002dc033b92cfc2c9e71b586302b09cfe535e1ff290b1b5ac",punto,parity)) { + test = punto.x.GetBase16(); + printf("%s\n",test); + free(test); + test = punto.y.GetBase16(); + printf("%s\n",test); + free(test); + } + else { + printf("Is not a valid point"); + } + printf("%i\n",sizeof(Point)); + punto.x.Get32Bytes((unsigned char*)dst); + test = tohex(dst,32); + printf("%s\n",test); + free(test); +} diff --git a/secp256k1/util.c b/secp256k1/util.c new file mode 100644 index 0000000..db19c22 --- /dev/null +++ b/secp256k1/util.c @@ -0,0 +1,167 @@ +#include +#include +#include + +#include "util.h" + + +char *ltrim(char *str, const char *seps) { + size_t totrim; + if (seps == NULL) { + seps = "\t\n\v\f\r "; + } + totrim = strspn(str, seps); + if (totrim > 0) { + size_t len = strlen(str); + if (totrim == len) { + str[0] = '\0'; + } + else { + memmove(str, str + totrim, len + 1 - totrim); + } + } + return str; +} + +char *rtrim(char *str, const char *seps) { + int i; + if (seps == NULL) { + seps = "\t\n\v\f\r "; + } + i = strlen(str) - 1; + while (i >= 0 && strchr(seps, str[i]) != NULL) { + str[i] = '\0'; + i--; + } + return str; +} + +char *trim(char *str, const char *seps) { + return ltrim(rtrim(str, seps), seps); +} + +int indexOf(char *s,const char **array,int length_array) { + int index = -1,i,continuar = 1; + for(i = 0; i current < t->n) { + t->current++; + return t->tokens[t->current-1]; + } + else { + return NULL; + } +} +int hasMoreTokens(Tokenizer *t) { + return (t->current < t->n); +} + +void stringtokenizer(char *data,Tokenizer *t) { + char *token; + t->tokens = NULL; + t->n = 0; + t->current = 0; + trim(data,"\t\n\r :"); + token = strtok(data," \t"); + while(token != NULL) { + t->n++; + t->tokens = (char**) realloc(t->tokens,sizeof(char*)*t->n); + if(t->tokens == NULL) { + printf("Out of memory\n"); + exit(0); + } + t->tokens[t->n - 1] = token; + token = strtok(NULL," \t"); + } +} + +void freetokenizer(Tokenizer *t) { + if(t->n > 0) { + free(t->tokens); + } + memset(t,0,sizeof(Tokenizer)); +} + + +/* + Aux function to get the hexvalues of the data +*/ +char *tohex(char *ptr,int length){ + char *buffer; + int offset = 0; + unsigned char c; + buffer = (char *) malloc((length * 2)+1); + for (int i = 0; i = '0' && hex <= '9') { + *out = hex - '0'; + } else if (hex >= 'A' && hex <= 'F') { + *out = hex - 'A' + 10; + } else if (hex >= 'a' && hex <= 'f') { + *out = hex - 'a' + 10; + } else { + return 0; + } + + return 1; +} + +void addItemList(char *data, List *l) { + l->data = (char**) realloc(l->data,sizeof(char*)* (l->n +1)); + l->data[l->n] = data; + l->n++; +} + +int isValidHex(char *data) { + char c; + int len,i,valid = 1; + len = strlen(data); + for(i = 0 ; i < len && valid ;i++ ) { + c = data[i]; + valid = ( (c >= '0' && c <='9') || (c >= 'A' && c <='F' ) || (c >= 'a' && c <='f' ) ); + } + return valid; +} diff --git a/secp256k1/util.h b/secp256k1/util.h new file mode 100644 index 0000000..e785def --- /dev/null +++ b/secp256k1/util.h @@ -0,0 +1,30 @@ +#ifndef CUSTOMUTILH +#define CUSTOMUTILH + +typedef struct str_list { + int n; + char **data; + int *lengths; +}List; + +typedef struct str_tokenizer { + int current; + int n; + char **tokens; +}Tokenizer; + +char *ltrim(char *str, const char *seps); +char *rtrim(char *str, const char *seps); +char *trim(char *str, const char *seps); +int indexOf(char *s,const char **array,int length_array); + +int hexchr2bin(char hex, char *out); +int hexs2bin(char *hex, unsigned char *out); +char *tohex(char *ptr,int length); + +int hasMoreTokens(Tokenizer *t); +char *nextToken(Tokenizer *t); + + + +#endif // CUSTOMUTILH diff --git a/util.c b/util.c new file mode 100644 index 0000000..db19c22 --- /dev/null +++ b/util.c @@ -0,0 +1,167 @@ +#include +#include +#include + +#include "util.h" + + +char *ltrim(char *str, const char *seps) { + size_t totrim; + if (seps == NULL) { + seps = "\t\n\v\f\r "; + } + totrim = strspn(str, seps); + if (totrim > 0) { + size_t len = strlen(str); + if (totrim == len) { + str[0] = '\0'; + } + else { + memmove(str, str + totrim, len + 1 - totrim); + } + } + return str; +} + +char *rtrim(char *str, const char *seps) { + int i; + if (seps == NULL) { + seps = "\t\n\v\f\r "; + } + i = strlen(str) - 1; + while (i >= 0 && strchr(seps, str[i]) != NULL) { + str[i] = '\0'; + i--; + } + return str; +} + +char *trim(char *str, const char *seps) { + return ltrim(rtrim(str, seps), seps); +} + +int indexOf(char *s,const char **array,int length_array) { + int index = -1,i,continuar = 1; + for(i = 0; i current < t->n) { + t->current++; + return t->tokens[t->current-1]; + } + else { + return NULL; + } +} +int hasMoreTokens(Tokenizer *t) { + return (t->current < t->n); +} + +void stringtokenizer(char *data,Tokenizer *t) { + char *token; + t->tokens = NULL; + t->n = 0; + t->current = 0; + trim(data,"\t\n\r :"); + token = strtok(data," \t"); + while(token != NULL) { + t->n++; + t->tokens = (char**) realloc(t->tokens,sizeof(char*)*t->n); + if(t->tokens == NULL) { + printf("Out of memory\n"); + exit(0); + } + t->tokens[t->n - 1] = token; + token = strtok(NULL," \t"); + } +} + +void freetokenizer(Tokenizer *t) { + if(t->n > 0) { + free(t->tokens); + } + memset(t,0,sizeof(Tokenizer)); +} + + +/* + Aux function to get the hexvalues of the data +*/ +char *tohex(char *ptr,int length){ + char *buffer; + int offset = 0; + unsigned char c; + buffer = (char *) malloc((length * 2)+1); + for (int i = 0; i = '0' && hex <= '9') { + *out = hex - '0'; + } else if (hex >= 'A' && hex <= 'F') { + *out = hex - 'A' + 10; + } else if (hex >= 'a' && hex <= 'f') { + *out = hex - 'a' + 10; + } else { + return 0; + } + + return 1; +} + +void addItemList(char *data, List *l) { + l->data = (char**) realloc(l->data,sizeof(char*)* (l->n +1)); + l->data[l->n] = data; + l->n++; +} + +int isValidHex(char *data) { + char c; + int len,i,valid = 1; + len = strlen(data); + for(i = 0 ; i < len && valid ;i++ ) { + c = data[i]; + valid = ( (c >= '0' && c <='9') || (c >= 'A' && c <='F' ) || (c >= 'a' && c <='f' ) ); + } + return valid; +} diff --git a/util.h b/util.h index 75966c5..e9fe60b 100644 --- a/util.h +++ b/util.h @@ -1,3 +1,6 @@ +#ifndef CUSTOMUTILH +#define CUSTOMUTILH + typedef struct str_list { int n; char **data; @@ -22,165 +25,8 @@ char *tohex(char *ptr,int length); int hasMoreTokens(Tokenizer *t); char *nextToken(Tokenizer *t); -char *ltrim(char *str, const char *seps) { - size_t totrim; - if (seps == NULL) { - seps = "\t\n\v\f\r "; - } - totrim = strspn(str, seps); - if (totrim > 0) { - size_t len = strlen(str); - if (totrim == len) { - str[0] = '\0'; - } - else { - memmove(str, str + totrim, len + 1 - totrim); - } - } - return str; -} +int isValidHex(char *data); +void freetokenizer(Tokenizer *t); +void stringtokenizer(char *data,Tokenizer *t); -char *rtrim(char *str, const char *seps) { - int i; - if (seps == NULL) { - seps = "\t\n\v\f\r "; - } - i = strlen(str) - 1; - while (i >= 0 && strchr(seps, str[i]) != NULL) { - str[i] = '\0'; - i--; - } - return str; -} - -char *trim(char *str, const char *seps) { - return ltrim(rtrim(str, seps), seps); -} - -int indexOf(char *s,const char **array,int length_array) { - int index = -1,i,continuar = 1; - for(i = 0; i current < t->n) { - t->current++; - return t->tokens[t->current-1]; - } - else { - return NULL; - } -} -int hasMoreTokens(Tokenizer *t) { - return (t->current < t->n); -} - -void stringtokenizer(char *data,Tokenizer *t) { - char *token; - t->tokens = NULL; - t->n = 0; - t->current = 0; - trim(data,"\t\n\r "); - token = strtok(data," \t:"); - while(token != NULL) { - t->n++; - t->tokens = realloc(t->tokens,sizeof(char*)*t->n); - if(t->tokens == NULL) { - printf("Out of memory\n"); - exit(0); - } - t->tokens[t->n - 1] = token; - token = strtok(NULL," \t"); - } -} - -void freetokenizer(Tokenizer *t) { - if(t->n > 0) { - free(t-> tokens); - } - memset(t,0,sizeof(Tokenizer)); -} - - -/* - Aux function to get the hexvalues of the data -*/ - -char *tohex(char *ptr,int length){ - char *buffer; - int offset = 0; - unsigned char c; - buffer = (char *) malloc((length * 2)+1); - for (int i = 0; i = '0' && hex <= '9') { - *out = hex - '0'; - } else if (hex >= 'A' && hex <= 'F') { - *out = hex - 'A' + 10; - } else if (hex >= 'a' && hex <= 'f') { - *out = hex - 'a' + 10; - } else { - return 0; - } - - return 1; -} - -void addItemList(char *data, List *l) { - l->data = realloc(l->data,sizeof(char*)* (l->n +1)); - l->data[l->n] = data; - l->n++; -} - -int isValidHex(char *data) { - char c; - int len,i,valid = 1; - len = strlen(data); - for(i = 0 ; i < len && valid ;i++ ) { - c = data[i]; - valid = ( (c >= '0' && c <='9') || (c >= 'A' && c <='F' ) || (c >= 'a' && c <='f' ) ); - } - return valid; -} +#endif // CUSTOMUTILH