EllipticCurveGF2m.hpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. #pragma once
  2. #include <stddef.h>
  3. #include <stdint.h>
  4. #include <stdexcept>
  5. #include <algorithm>
  6. #include "BigInteger.hpp"
  7. template<typename __FieldType>
  8. class EllipticCurveGF2m {
  9. private:
  10. // y^2 + xy = x^3 + Ax^2 + B
  11. __FieldType _A;
  12. __FieldType _B;
  13. void _VerifyParameters() const {
  14. if (_B.IsZero()) {
  15. throw std::invalid_argument("B cannot be zero.");
  16. }
  17. }
  18. public:
  19. class Point {
  20. friend EllipticCurveGF2m<__FieldType>;
  21. private:
  22. const EllipticCurveGF2m<__FieldType>& _Curve;
  23. __FieldType _X;
  24. __FieldType _Y;
  25. void _VerifyParameters() const {
  26. auto Left = _Y.SquareValue() + _X * _Y;
  27. auto Right = (_X + _Curve._A) * _X.SquareValue() + _Curve._B;
  28. if (Left != Right) {
  29. throw std::invalid_argument("New point is not on the curve specified.");
  30. }
  31. }
  32. public:
  33. Point(const EllipticCurveGF2m<__FieldType>& Curve) noexcept :
  34. _Curve(Curve) {}
  35. Point(const EllipticCurveGF2m<__FieldType>& Curve, const void* pbX, size_t cbX, const void* pbY, size_t cbY) :
  36. _Curve(Curve),
  37. _X(pbX, cbX),
  38. _Y(pbY, cbY)
  39. {
  40. _VerifyParameters();
  41. }
  42. Point(const EllipticCurveGF2m<__FieldType>& Curve, const __FieldType& X, const __FieldType& Y) :
  43. _Curve(Curve), _X(X), _Y(Y)
  44. {
  45. _VerifyParameters();
  46. }
  47. Point operator-() const noexcept {
  48. return Point(_X, _X + _Y);
  49. }
  50. Point& operator=(const Point& Other) {
  51. if (&_Curve == &Other._Curve || _Curve == Other._Curve) {
  52. _X = Other._X;
  53. _Y = Other._Y;
  54. return *this;
  55. } else {
  56. throw std::invalid_argument("Not on the same curve.");
  57. }
  58. }
  59. bool operator==(const Point& Other) const noexcept {
  60. if (&_Curve == &Other._Curve || _Curve == Other._Curve) {
  61. return _X == Other._X && _Y == Other._Y;
  62. } else {
  63. return false;
  64. }
  65. }
  66. bool operator!=(const Point& Other) const noexcept {
  67. if (&_Curve == &Other._Curve || _Curve == Other._Curve) {
  68. return _X != Other._X || _Y != Other._Y;
  69. } else {
  70. return true;
  71. }
  72. }
  73. const __FieldType& GetX() const noexcept {
  74. return _X;
  75. }
  76. const __FieldType& GetY() const noexcept {
  77. return _Y;
  78. }
  79. bool IsAtInfinity() const noexcept {
  80. return _X.IsZero() && _Y.IsZero();
  81. }
  82. Point& Double() noexcept {
  83. if (IsAtInfinity() == false) {
  84. auto m = _Y / _X + _X;
  85. // NewX = m ^ 2 + m + a
  86. __FieldType NewX = m.SquareValue();
  87. NewX += m;
  88. NewX += _Curve._A;
  89. // NewY = X ^ 2 + (m + 1) * NewX
  90. _Y = m.AddOne();
  91. _Y *= NewX;
  92. _Y += _X.Square();
  93. _X = NewX;
  94. }
  95. return *this;
  96. }
  97. Point ValueOfDouble() const noexcept {
  98. Point Result(_Curve);
  99. if (IsAtInfinity() == false) {
  100. // m = X + Y / X
  101. auto m = _Y / _X + _X;
  102. // NewX = m ^ 2 + m + a
  103. Result._X = m.SquareValue();
  104. Result._X += m;
  105. Result._X += _Curve._A;
  106. // NewY = X ^ 2 + (m + 1) * NewX
  107. Result._Y = m.AddOne();
  108. Result._Y *= Result._X;
  109. Result._Y += _X.SquareValue();
  110. }
  111. return Result;
  112. }
  113. Point operator+(const Point& Other) const {
  114. if (&_Curve == &Other._Curve || _Curve == Other._Curve) {
  115. if (IsAtInfinity()) {
  116. return Other;
  117. } else {
  118. if (this == &Other || _X == Other._X) {
  119. return ValueOfDouble();
  120. } else {
  121. Point Result(_Curve);
  122. // m = (Y0 + Y1) / (X0 + X1)
  123. auto m = (_Y + Other._Y) / (_X + Other._X);
  124. // NewX = m ^ 2 + m + X0 + X1 + a
  125. Result._X = m.SquareValue();
  126. Result._X += m;
  127. Result._X += _X;
  128. Result._X += Other._X;
  129. Result._X += _Curve._A;
  130. // NewY = m * (X0 + NewX) + NewX + Y0
  131. Result._Y = _X + Result._X;
  132. Result._Y *= m;
  133. Result._Y += Result._X;
  134. Result._Y += _Y;
  135. return Result;
  136. }
  137. }
  138. } else {
  139. throw std::invalid_argument("Not on the same curve.");
  140. }
  141. }
  142. Point& operator+=(const Point& Other) {
  143. if (&_Curve == &Other._Curve || _Curve == Other._Curve) {
  144. if (IsAtInfinity()) {
  145. _X = Other._X;
  146. _Y = Other._Y;
  147. } else {
  148. if (this == &Other || _X == Other._X) {
  149. Double();
  150. } else {
  151. Point Result(_Curve);
  152. // m = (Y0 + Y1) / (X0 + X1)
  153. auto m = (_Y + Other._Y) / (_X + Other._X);
  154. // NewX = m ^ 2 + m + X0 + X1 + a
  155. __FieldType NewX = m.SquareValue();
  156. NewX += m;
  157. NewX += _X;
  158. NewX += Other._X;
  159. NewX += _Curve._A;
  160. // NewY = m * (X0 + NewX) + NewX + Y0
  161. _X += NewX;
  162. _X *= m;
  163. _X += NewX;
  164. _Y += _X;
  165. _X = NewX;
  166. }
  167. }
  168. return *this;
  169. } else {
  170. throw std::invalid_argument("Not on the same curve.");
  171. }
  172. }
  173. Point operator-(const Point& Other) const {
  174. Point Result = -Other;
  175. Result += *this;
  176. return Result;
  177. }
  178. Point& operator-=(const Point& Other) {
  179. return *this += -Other;
  180. }
  181. Point operator*(const BigInteger N) const noexcept {
  182. Point Result(_Curve);
  183. Point temp(*this);
  184. size_t bit_length = N.BitLength();
  185. for (size_t i = 0; i < bit_length; ++i) {
  186. if (N.TestBit(i) == true)
  187. Result += temp;
  188. temp.Double();
  189. }
  190. return Result;
  191. }
  192. Point operator*=(const BigInteger N) noexcept {
  193. Point Result(_Curve);
  194. size_t bit_length = N.BitLength();
  195. for (size_t i = 0; i < bit_length; ++i) {
  196. if (N.TestBit(i) == true)
  197. Result += *this;
  198. Double();
  199. }
  200. *this = Result;
  201. }
  202. // SEC 1: Elliptic Curve Cryptography
  203. // 2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion
  204. std::vector<uint8_t> Dump() const noexcept {
  205. if (IsAtInfinity()) {
  206. std::vector<uint8_t> bytes = { 0x00 };
  207. return bytes;
  208. } else {
  209. std::vector<uint8_t> bytes = { 0x04 };
  210. std::vector<uint8_t> xbytes = _X.Dump();
  211. std::vector<uint8_t> ybytes = _Y.Dump();
  212. std::reverse(xbytes.begin(), xbytes.end()); // to big endian
  213. std::reverse(ybytes.begin(), ybytes.end()); // to big endian
  214. bytes.insert(bytes.end(), xbytes.begin(), xbytes.end());
  215. bytes.insert(bytes.end(), ybytes.begin(), ybytes.end());
  216. return bytes;
  217. }
  218. }
  219. // SEC 1: Elliptic Curve Cryptography
  220. // 2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion
  221. std::vector<uint8_t> DumpCompressed() const noexcept {
  222. if (IsAtInfinity()) {
  223. std::vector<uint8_t> bytes = { 0x00 };
  224. return bytes;
  225. } else {
  226. std::vector<uint8_t> bytes(1);
  227. std::vector<uint8_t> xbytes = _X.Dump();
  228. std::vector<uint8_t> zbytes = (_Y / _X).Dump();
  229. if (zbytes[0] & 1) {
  230. bytes[0] = 0x03;
  231. } else {
  232. bytes[0] = 0x02;
  233. }
  234. std::reverse(xbytes.begin(), xbytes.end()); // to big endian
  235. bytes.insert(bytes.end(), xbytes.begin(), xbytes.end());
  236. return bytes;
  237. }
  238. }
  239. };
  240. EllipticCurveGF2m(const __FieldType& A, const __FieldType& B) : _A(A), _B(B) {
  241. _VerifyParameters();
  242. }
  243. EllipticCurveGF2m(const void* pbA, size_t cbA, const void* pbB, size_t cbB) : _A(pbA, cbA), _B(pbB, cbB) {
  244. _VerifyParameters();
  245. }
  246. bool operator==(const EllipticCurveGF2m<__FieldType>& Other) const noexcept {
  247. return _A == Other._A && _B == Other._B;
  248. }
  249. bool operator!=(const EllipticCurveGF2m<__FieldType>& Other) const noexcept {
  250. return _A != Other._A || _B != Other._B;
  251. }
  252. Point GetInfinityPoint() const noexcept {
  253. return Point(*this);
  254. }
  255. Point GetPoint(const __FieldType& X, const __FieldType& Y) const {
  256. return Point(*this, X, Y);
  257. }
  258. Point GetPoint(const void* pbX, size_t cbX, const void* pbY, size_t cbY) const {
  259. return Point(*this, pbX, cbX, pbY, cbY);
  260. }
  261. };