出于教学目的,我尝试用 C++ 实现基本的 ECDSA 算法(并在非基于性能的离线程序中适度使用)。我尝试以编程方式使用基本方法来实现这一点,但它一直没有奏效,我不得不通过推迟这个特定模型来消除它。
我最近被提醒我没有展示这个,所以我决定寻求帮助。
椭圆曲线名称我做错了什么。有人,任何人,请教我如何以及为什么这不起作用。
是不是错误实现了mod反函数? 还是十进制转二进制的函数? 或者在循环的二进制字符中调用 ADD() 或 DOUBLE()?
我做错了什么?
我使用私钥的已知公钥输出,其值为
112757557418114203588093402336452206775565751179231977388358956335153294300646
.
Expected PublicKey =
x: 338862860998134191820545952520423482146950914608322024530631065951421850289,
y: 95297529534878812336940782639534071162224996323592980142550971823499987176;
BigInteger 实现库源代码 bigint-2010.04.30.zip
所有使用的自定义函数都在代码中添加。
附言 在尝试生成签名和校验和哈希时,我也遇到了类似的错误计算。 非常感谢使这段代码工作的任何帮助。
#include "bignum_def.h"
#include <vector> // Include vector header file
#include <sstream> // Include sstream header file
using std::cout; // enables you to call as "cout" instead of "std::cout"
using std::string; // enables you to call as "string" instead of "std::string"
using std::stringstream; // enables you to call as "stringstream" instead of "std::stringstream"
using std::vector; // enables you to call as "vector" instead of "std::vector"
// GLOBAL Variables
BigInteger p = stringToBigInteger("1157920892316195423570985008687907853269984665640564039457584007908834671663");
BigInteger n = stringToBigInteger("11579208923161954235709850086879078528375642790904382605163141518161494337");
BigInteger G_X = stringToBigInteger("55066263022236695787188951685343262506034537775941755001860389116729240");
BigInteger G_Y = stringToBigInteger("32670510020758816978083085130507043184471238065924327593890433575382424");
BigInteger Gxy = stringToBigInteger("5506626302223669578718895168534326250603453777594175500186038911672924032670510020758816978083085130507043184471238065924327593890433575382424");
BigInteger expected_x = stringToBigInteger("338862860998134191820545952520423482146950914608322024530631065951421850289");
BigInteger expected_y = stringToBigInteger("95297529534878812336940782639534071162224996323592980142550971823499987176");
BigInteger Pub_xy = stringToBigInteger("33886286099813419182054595252042348214695091460832202453063106595142185028995297529534878812336940782639534071162224996323592980142550971823499987176");
// Function Prototypes
void Multiply(BigInteger PRIVATEKEY, vector<BigInteger> &PUBLICKEY);
BigInteger Inverse(BigInteger a, BigInteger m);
void Double(BigInteger &x, BigInteger &y);
void ADD(BigInteger &Point1_x, BigInteger &Point1_y, BigInteger Point2_x, BigInteger Point2_y);
BigInteger BigInteger_power(BigInteger n, BigInteger e)
{
BigInteger x = n; // declare uint32_t decimal variable and assign the value of base number to it
if (e == 0) // if exponent value is 0
return n; // No need for loop, return 1
if (n == 0) // if base value is 0
return 1; // No need for loop, return 0
for (BigInteger b = 1; b < e; b++) // for exponent value starting from an offset of 1
n = n*x; // base value * base value
return n; // return value
}
string BigToLittleAlphabets(string data)
{
for (int i = 0; i < data.size(); i++)
{
if (data[i] == 'A')
data[i] = 'a';
if (data[i] == 'B')
data[i] = 'b';
if (data[i] == 'C')
data[i] = 'c';
if (data[i] == 'D')
data[i] = 'd';
if (data[i] == 'E')
data[i] = 'e';
if (data[i] == 'F')
data[i] = 'f';
}
return data;
}
string IntegerToHex(BigInteger num)
{
vector<char> arr;
string cache;
int i = 0;
if (num == 0)
{
stringstream cs;
cs << num;
cs >> cache;
cs.clear();
return cache;
}
while(num != 0)
{
int temp = 0;
temp = (num % 16).toUnsignedInt();
if(temp < 10)
{
arr.push_back(temp + 48);
i++;
}
else
{
arr.push_back(temp + 55);
i++;
}
num = num/16;
}
for(int j = i-1; j >= 0; j--)
cache += arr[j]; // cache+= arr[j];
// ENSURE 64 character hexadecimal output
if ((cache.length() < 65) && (cache.length() != 64))
{
int mz = 64 - cache.length();
for (int i = 0; i < mz; ++i)
cache = "0" + cache; // pad beginning of hex with 0 as it has no significant value to current hex value
}
return BigToLittleAlphabets(cache);
// return cache;
} // 03:50PM 18/09/2022
string BigInteger2String(BigInteger value)
{
string dd; // string variable declaration
stringstream ss; // stream object initialization
ss << value; // stream data into object
ss >> dd; // stream data into string variable
ss.clear(); // clear stream object
return dd; // return value
}
string DecimalToBinary_Backwards(BigInteger num)
{
BigInteger n, div = 2; // declare BigInteger variable
string bin = "", temp; // declare string variables
while(num > 0) // while num is not equal to 0
{
n = num % div; // mod value by 2 and store remainder
num = num / div; // divide by 2 yo update but simultaneously decrease num
temp += BigInteger2String(n); // convert to string and concatenate within string
}
return temp; // return value
}
BigInteger Inverse(BigInteger a, BigInteger m) // 1st implementation of mod inverse function
{
BigInteger prevy(0), y(1), q, m_orig = m, der(0);
// m = p;
if (a < 0)
a = a % m;
while(a > 1)
{
q = m/a;
y = (prevy-q)*y;
prevy = y;
a = m % a;
m = a;
}
der = y % m_orig;
return der;
}
// which mod inverse implementation is correct?
BigInteger modInverse(BigInteger a, BigInteger m) // 2nd implementation of mod inverse function
{
BigInteger m0 = m;
BigInteger y = 0, x = 1;
if (m == 1)
return 0;
while (a > 1)
{
BigInteger q = a / m; // q is quotient
BigInteger t = m;
m = a % m, a = t; // m is remainder now, process same as Euclid's algo
t = y;
// Update y and x
y = x - q * y;
x = t;
}
// Make x positive
if (x < 0)
x += m0;
return x;
}
void Double(BigInteger &x, BigInteger &y)
{
BigInteger _2(2), _3(3);
BigInteger slope = _3 * (BigInteger_power(x, _2) * Inverse((_2*y), p)) % p;
cout << "DOUBLE Slope = " << slope << "\n\n";
BigInteger X = (BigInteger_power(slope, _2) - (_2 * x)) % p;
BigInteger Y = ((slope * x) - X - y) % p;
x = X, y = Y; // update values
}
void ADD(BigInteger &Point1_x, BigInteger &Point1_y, BigInteger Point2_x, BigInteger Point2_y)
{
string h = BigInteger2String(Point1_x) + BigInteger2String(Point1_y);
string k = BigInteger2String(Point2_x) + BigInteger2String(Point2_y);
BigInteger a = String_2_BigInteger(h), b = String_2_BigInteger(k);
if (a == b)
Double(Point1_x, Point1_y);
else
{
BigInteger _2(2);
BigInteger slope = (Point1_y - (Point2_y * Inverse(Point1_x-Point2_x, p))) % p;
cout << "ADD Slope = " << slope << "\n\n";
BigInteger X = ((BigInteger_power(slope, _2) - Point1_x) - Point2_x) % p;
BigInteger Y = ((slope * Point1_x) - X - Point1_y) % p;
Point1_x = X, Point1_y = Y; // update values
}
}
void Multiply(BigInteger PRIVATEKEY, vector<BigInteger> &PUBLICKEY)
{
BigInteger XX = G_X, YY = G_Y; // XX and YY are updated within each curve function call
string binaryVerse = DecimalToBinary_Backwards(PRIVATEKEY);
cout << "Binary of privateKey = " << binaryVerse << "\n\n"; // FOR DEBUGGING PURPOSE ONLY!!
int IterationLength = binaryVerse.length();
for (int i = 1; i < IterationLength; ++i)
{
if (binaryVerse[i] == '0')
Double(XX, YY);
else if (binaryVerse[i] == '1')
{
// Double(XX, YY);
ADD(XX, YY, G_X, G_Y);
// Double(XX, YY);
}
}
PUBLICKEY.clear();
PUBLICKEY.push_back(XX); // Update vector with calculated publicKey Decimal
PUBLICKEY.push_back(YY); // Update vector with calculated publicKey Decimal values
cout << "Public Key x : " << XX << ", \nPublic Key y : " << YY << "\n\n";
}
int main(int argc, char const *argv[])
{
vector<BigInteger> ZEN;
BigInteger pk = String_2_BigInteger("112757557418114203588093402336452206775565751179231977388358956335153294300646");
Multiply(pk, ZEN);
cout << "Hexadecimal PublicKey x : " << IntegerToHex(ZEN[0]) << ", \nHexadecimal PublicKey y : " << IntegerToHex(ZEN[1]) << "\n\n";
return 0;
}