#include <iostream>
#include <NTL/ZZ.h>
#include <NTL/ZZ_p.h>
using namespace std;
using namespace NTL;
const char* PRIME_P =
"6277101735386680763835789423207666416083908700390324961279";
const char* A = "-3";
const char* B =
"2455155546008943817740293915197451784769108058161191238065";
const char* GX =
"602046282375688656758213480587526111916698976636884684818";
const char* GY =
"174050332293622031404857552280219410364023488927386650641";
const char* N =
"6277101735386680763835789423176059013767194773182842284081";
struct Point {
ZZ_p x, y;
bool is_infinity = false;
Point() : is_infinity(true) {}
Point(ZZ_p x, ZZ_p y) : x(x), y(y), is_infinity(false) {}
};
Point point_add(const Point& P, const Point& Q, const ZZ_p& a) {
if (P.is_infinity) return Q;
if (Q.is_infinity) return P;
if (P.x == Q.x && P.y == -Q.y) return Point();
ZZ_p m;
if (P.x == Q.x && P.y == Q.y) {
m = (3 * sqr(P.x) + a) / (2 * P.y);
} else {
m = (Q.y - P.y) / (Q.x - P.x);
}
ZZ_p rx = sqr(m) - P.x - Q.x;
ZZ_p ry = m * (P.x - rx) - P.y;
return Point(rx, ry);
}
Point scalar_mult(const ZZ& k, const Point& P, const ZZ_p& a) {
Point result; // Infinity
Point current = P;
ZZ n = k;
while (n > 0) {
if (n % 2 == 1) {
result = point_add(result, current, a);
}
current = point_add(current, current, a);
n /= 2;
}
return result;
}
int main() {
// Initialize finite field
ZZ p;
conv(p, PRIME_P);
ZZ_p::init(p);
// Define curve parameters
ZZ_p a, b;
conv(a, A);
conv(b, B);
// Base point G
ZZ_p gx, gy;
conv(gx, GX);
conv(gy, GY);
Point G(gx, gy);
// Order of the curve
ZZ n;
conv(n, N);
// Generate private key
ZZ private_key = RandomBnd(n);
// Compute public key
Point public_key = scalar_mult(private_key, G, a);
// Output results
cout << "Private Key: " << private_key << endl;
cout << "Public Key: (" << public_key.x << ", " << public_key.y
<< ")" << endl;
return 0;
}