mirror of
https://github.com/albertobsd/keyhunt.git
synced 2025-03-28 18:41:45 +01:00
455 lines
9.7 KiB
C++
455 lines
9.7 KiB
C++
/*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
#include "SECP256k1.h"
|
|
#include "Point.h"
|
|
#include "util.h"
|
|
|
|
Secp256K1::Secp256K1() {
|
|
}
|
|
|
|
void Secp256K1::Init() {
|
|
// Prime for the finite field
|
|
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;
|
|
}
|
|
|
|
Point Secp256K1::Negation(Point &p) {
|
|
Point Q;
|
|
Q.Clear();
|
|
Q.x.Set(&p.x);
|
|
Q.y.Set(&this->P);
|
|
Q.y.Sub(&p.y);
|
|
return Q;
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
char* Secp256K1::GetPublicKeyRaw(bool compressed, Point &pubKey) {
|
|
unsigned char publicKeyBytes[128];
|
|
char *ret = (char*) malloc(65);
|
|
if(ret == NULL) {
|
|
::fprintf(stderr,"Can't alloc memory\n");
|
|
exit(0);
|
|
}
|
|
if (!compressed) {
|
|
//Uncompressed public key
|
|
ret[0] = 0x4;
|
|
pubKey.x.Get32Bytes((unsigned char*) (ret + 1));
|
|
pubKey.y.Get32Bytes((unsigned char*) (ret + 33));
|
|
}
|
|
else {
|
|
// Compressed public key
|
|
ret[0] = pubKey.y.IsEven() ? 0x2 : 0x3;
|
|
pubKey.x.Get32Bytes((unsigned char*) (ret + 1));
|
|
}
|
|
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 );
|
|
}
|