How to resolve the algorithm Elliptic curve arithmetic step by step in the C++ programming language
How to resolve the algorithm Elliptic curve arithmetic step by step in the C++ programming language
Table of Contents
Problem Statement
Elliptic curves are sometimes used in cryptography as a way to perform digital signatures.
The purpose of this task is to implement a simplified (without modular arithmetic) version of the elliptic curve arithmetic which is required by the elliptic curve DSA protocol.
In a nutshell, an elliptic curve is a bi-dimensional curve defined by the following relation between the x and y coordinates of any point on the curve:
a and b are arbitrary parameters that define the specific curve which is used.
For this particular task, we'll use the following parameters:
The most interesting thing about elliptic curves is the fact that it is possible to define a group structure on it.
To do so we define an internal composition rule with an additive notation +, such that for any three distinct points P, Q and R on the curve, whenever these points are aligned, we have:
Here 0 (zero) is the infinity point, for which the x and y values are not defined. It's basically the same kind of point which defines the horizon in projective geometry.
We'll also assume here that this infinity point is unique and defines the neutral element of the addition.
This was not the definition of the addition, but only its desired property. For a more accurate definition, we proceed as such:
Given any three aligned points P, Q and R, we define the sum S = P + Q as the point (possibly the infinity point) such that S, R and the infinity point are aligned.
Considering the symmetry of the curve around the x-axis, it's easy to convince oneself that two points S and R can be aligned with the infinity point if and only if S and R are symmetric of one another towards the x-axis (because in that case there is no other candidate than the infinity point to complete the alignment triplet).
S is thus defined as the symmetric of R towards the x axis.
The task consists in defining the addition which, for any two points of the curve, returns the sum of these two points. You will pick two random points on the curve, compute their sum and show that the symmetric of the sum is aligned with the two initial points.
You will use the a and b parameters of secp256k1, i.e. respectively zero and seven.
Hint: You might need to define a "doubling" function, that returns P+P for any given point P.
Extra credit: define the full elliptic curve arithmetic (still not modular, though) by defining a "multiply" function that returns,
for any point P and integer n, the point P + P + ... + P (n times).
Let's start with the solution:
Step by Step solution about How to resolve the algorithm Elliptic curve arithmetic step by step in the C++ programming language
The code implements a few functions over an elliptic curve.
The curve used is the one defined by the equation y^2 = x^3 + 7
, and the curve is defined on the set of real numbers.
The curve is implemented using the Weierstrass form, which consists of a cubic equation.
The code implements the following operations:
- Point addition: the addition of two points on the curve is defined as the point of intersection of the line joining the two points with the curve.
- Point subtraction: the subtraction of two points on the curve is defined as the point of intersection of the line joining the two points with the curve.
- Point multiplication: the multiplication of a point on the curve by an integer n is defined as the addition of the point to itself n times.
- Point doubling: the doubling of a point on the curve is defined as the addition of the point to itself.
- Point negation: the negation of a point on the curve is defined as the point with the same x-coordinate and the opposite y-coordinate.
- Point comparison: the comparison of two points on the curve is defined as the comparison of their x-coordinates.
- Point printing: the printing of a point on the curve is defined as the printing of its x-coordinate and y-coordinate.
- Point zero: the zero point on the curve is defined as the point with x-coordinate 0 and y-coordinate
ZeroThreshold * 1.01
. - Point initialization: the initialization of a point on the curve is defined as the setting of its x-coordinate and y-coordinate to 0 and
ZeroThreshold * 1.01
, respectively. - Point constructor: the constructor of a point on the curve is defined as the setting of its x-coordinate and y-coordinate to the given values.
- Operator overloading: the operator overloading is defined as the implementation of the addition, subtraction, multiplication, negation, comparison, printing and initialization operations.
- Main function: the main function is defined as the execution of the following code:
- The declaration of two points on the curve, a and b, with x-coordinates 1 and 2, respectively.
- The printing of the points a and b.
- The declaration of a point on the curve, c, as the addition of the points a and b.
- The printing of the point c.
- The printing of the point a + b - c.
- The printing of the point a + b - (b + a).
- The printing of the point a + a + a + a + a - 5 * a.
- The printing of the point a * 12345.
- The printing of the point a * -12345.
- The printing of the point a * 12345 + a * -12345.
- The printing of the point a * 12345 - (a * 12000 + a * 345).
- The printing of the point a * 12345 - (a * 12001 + a * 345).
- The declaration of a point on the curve, g, as the zero point.
- The printing of the point g.
- The printing of the point g += a.
- The printing of the point g += zero.
- The printing of the point g += b.
- The printing of the point b + b - b * 2.
- The declaration of a point on the curve, special, with x-coordinate 0.
- The printing of the point special.
- The printing of the point special *= 2.
Source code in the cpp programming language
#include <cmath>
#include <iostream>
using namespace std;
// define a type for the points on the elliptic curve that behaves
// like a built in type.
class EllipticPoint
{
double m_x, m_y;
static constexpr double ZeroThreshold = 1e20;
static constexpr double B = 7; // the 'b' in y^2 = x^3 + a * x + b
// 'a' is 0
void Double() noexcept
{
if(IsZero())
{
// doubling zero is still zero
return;
}
// based on the property of the curve, the line going through the
// current point and the negative doubled point is tangent to the
// curve at the current point. wikipedia has a nice diagram.
if(m_y == 0)
{
// at this point the tangent to the curve is vertical.
// this point doubled is 0
*this = EllipticPoint();
}
else
{
double L = (3 * m_x * m_x) / (2 * m_y);
double newX = L * L - 2 * m_x;
m_y = L * (m_x - newX) - m_y;
m_x = newX;
}
}
public:
friend std::ostream& operator<<(std::ostream&, const EllipticPoint&);
// Create a point that is initialized to Zero
constexpr EllipticPoint() noexcept : m_x(0), m_y(ZeroThreshold * 1.01) {}
// Create a point based on the yCoordiante. For a curve with a = 0 and b = 7
// there is only one x for each y
explicit EllipticPoint(double yCoordinate) noexcept
{
m_y = yCoordinate;
m_x = cbrt(m_y * m_y - B);
}
// Check if the point is 0
bool IsZero() const noexcept
{
// when the elliptic point is at 0, y = +/- infinity
bool isNotZero = abs(m_y) < ZeroThreshold;
return !isNotZero;
}
// make a negative version of the point (p = -q)
EllipticPoint operator-() const noexcept
{
EllipticPoint negPt;
negPt.m_x = m_x;
negPt.m_y = -m_y;
return negPt;
}
// add a point to this one ( p+=q )
EllipticPoint& operator+=(const EllipticPoint& rhs) noexcept
{
if(IsZero())
{
*this = rhs;
}
else if (rhs.IsZero())
{
// since rhs is zero this point does not need to be
// modified
}
else
{
double L = (rhs.m_y - m_y) / (rhs.m_x - m_x);
if(isfinite(L))
{
double newX = L * L - m_x - rhs.m_x;
m_y = L * (m_x - newX) - m_y;
m_x = newX;
}
else
{
if(signbit(m_y) != signbit(rhs.m_y))
{
// in this case rhs == -lhs, the result should be 0
*this = EllipticPoint();
}
else
{
// in this case rhs == lhs.
Double();
}
}
}
return *this;
}
// subtract a point from this one (p -= q)
EllipticPoint& operator-=(const EllipticPoint& rhs) noexcept
{
*this+= -rhs;
return *this;
}
// multiply the point by an integer (p *= 3)
EllipticPoint& operator*=(int rhs) noexcept
{
EllipticPoint r;
EllipticPoint p = *this;
if(rhs < 0)
{
// change p * -rhs to -p * rhs
rhs = -rhs;
p = -p;
}
for (int i = 1; i <= rhs; i <<= 1)
{
if (i & rhs) r += p;
p.Double();
}
*this = r;
return *this;
}
};
// add points (p + q)
inline EllipticPoint operator+(EllipticPoint lhs, const EllipticPoint& rhs) noexcept
{
lhs += rhs;
return lhs;
}
// subtract points (p - q)
inline EllipticPoint operator-(EllipticPoint lhs, const EllipticPoint& rhs) noexcept
{
lhs += -rhs;
return lhs;
}
// multiply by an integer (p * 3)
inline EllipticPoint operator*(EllipticPoint lhs, const int rhs) noexcept
{
lhs *= rhs;
return lhs;
}
// multiply by an integer (3 * p)
inline EllipticPoint operator*(const int lhs, EllipticPoint rhs) noexcept
{
rhs *= lhs;
return rhs;
}
// print the point
ostream& operator<<(ostream& os, const EllipticPoint& pt)
{
if(pt.IsZero()) cout << "(Zero)\n";
else cout << "(" << pt.m_x << ", " << pt.m_y << ")\n";
return os;
}
int main(void) {
const EllipticPoint a(1), b(2);
cout << "a = " << a;
cout << "b = " << b;
const EllipticPoint c = a + b;
cout << "c = a + b = " << c;
cout << "a + b - c = " << a + b - c;
cout << "a + b - (b + a) = " << a + b - (b + a) << "\n";
cout << "a + a + a + a + a - 5 * a = " << a + a + a + a + a - 5 * a;
cout << "a * 12345 = " << a * 12345;
cout << "a * -12345 = " << a * -12345;
cout << "a * 12345 + a * -12345 = " << a * 12345 + a * -12345;
cout << "a * 12345 - (a * 12000 + a * 345) = " << a * 12345 - (a * 12000 + a * 345);
cout << "a * 12345 - (a * 12001 + a * 345) = " << a * 12345 - (a * 12000 + a * 344) << "\n";
const EllipticPoint zero;
EllipticPoint g;
cout << "g = zero = " << g;
cout << "g += a = " << (g+=a);
cout << "g += zero = " << (g+=zero);
cout << "g += b = " << (g+=b);
cout << "b + b - b * 2 = " << (b + b - b * 2) << "\n";
EllipticPoint special(0); // the point where the curve crosses the x-axis
cout << "special = " << special; // this has the minimum possible value for x
cout << "special *= 2 = " << (special*=2); // doubling it gives zero
return 0;
}
You may also check:How to resolve the algorithm Pig the dice game step by step in the AutoHotkey programming language
You may also check:How to resolve the algorithm Create an HTML table step by step in the M2000 Interpreter programming language
You may also check:How to resolve the algorithm Babbage problem step by step in the Smalltalk programming language
You may also check:How to resolve the algorithm Create a file step by step in the Arturo programming language
You may also check:How to resolve the algorithm Ramer-Douglas-Peucker line simplification step by step in the Racket programming language