ec.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. // Copyright 2010 Dolphin Emulator Project
  2. // Copyright 2007,2008 Segher Boessenkool <segher@kernel.crashing.org>
  3. // SPDX-License-Identifier: GPL-2.0-or-later
  4. #include "Common/Crypto/ec.h"
  5. #include <algorithm>
  6. #include <cstring>
  7. #include "Common/Crypto/bn.h"
  8. #include "Common/Inline.h"
  9. #include "Common/Random.h"
  10. #include "Common/StringUtil.h"
  11. namespace Common::ec
  12. {
  13. static const u8 square[16] = {0x00, 0x01, 0x04, 0x05, 0x10, 0x11, 0x14, 0x15,
  14. 0x40, 0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55};
  15. struct Elt;
  16. static Elt operator*(const Elt& a, const Elt& b);
  17. struct Elt
  18. {
  19. bool IsZero() const
  20. {
  21. return std::ranges::all_of(data, [](u8 b) { return b == 0; });
  22. }
  23. void MulX()
  24. {
  25. u8 carry = data[0] & 1;
  26. u8 x = 0;
  27. for (std::size_t i = 0; i < data.size() - 1; i++)
  28. {
  29. u8 y = data[i + 1];
  30. data[i] = x ^ (y >> 7);
  31. x = y << 1;
  32. }
  33. data[29] = x ^ carry;
  34. data[20] ^= carry << 2;
  35. }
  36. Elt Square() const
  37. {
  38. std::array<u8, 60> wide;
  39. for (std::size_t i = 0; i < data.size(); i++)
  40. {
  41. wide[2 * i] = square[data[i] >> 4];
  42. wide[2 * i + 1] = square[data[i] & 15];
  43. }
  44. for (std::size_t i = 0; i < data.size(); i++)
  45. {
  46. u8 x = wide[i];
  47. wide[i + 19] ^= x >> 7;
  48. wide[i + 20] ^= x << 1;
  49. wide[i + 29] ^= x >> 1;
  50. wide[i + 30] ^= x << 7;
  51. }
  52. u8 x = wide[30] & ~1;
  53. wide[49] ^= x >> 7;
  54. wide[50] ^= x << 1;
  55. wide[59] ^= x >> 1;
  56. wide[30] &= 1;
  57. Elt result;
  58. std::copy(wide.cbegin() + 30, wide.cend(), result.data.begin());
  59. return result;
  60. }
  61. Elt ItohTsujii(const Elt& b, std::size_t j) const
  62. {
  63. Elt t = *this;
  64. while (j--)
  65. t = t.Square();
  66. return t * b;
  67. }
  68. Elt Inv() const
  69. {
  70. Elt t = ItohTsujii(*this, 1);
  71. Elt s = t.ItohTsujii(*this, 1);
  72. t = s.ItohTsujii(s, 3);
  73. s = t.ItohTsujii(*this, 1);
  74. t = s.ItohTsujii(s, 7);
  75. s = t.ItohTsujii(t, 14);
  76. t = s.ItohTsujii(*this, 1);
  77. s = t.ItohTsujii(t, 29);
  78. t = s.ItohTsujii(s, 58);
  79. s = t.ItohTsujii(t, 116);
  80. return s.Square();
  81. }
  82. std::array<u8, 30> data{};
  83. };
  84. static Elt operator+(const Elt& a, const Elt& b)
  85. {
  86. Elt d;
  87. for (std::size_t i = 0; i < std::tuple_size<decltype(Elt::data)>{}; i++)
  88. d.data[i] = a.data[i] ^ b.data[i];
  89. return d;
  90. }
  91. static Elt operator*(const Elt& a, const Elt& b)
  92. {
  93. Elt d;
  94. std::size_t i = 0;
  95. u8 mask = 1;
  96. for (std::size_t n = 0; n < 233; n++)
  97. {
  98. d.MulX();
  99. if ((a.data[i] & mask) != 0)
  100. d = d + b;
  101. mask >>= 1;
  102. if (mask == 0)
  103. {
  104. mask = 0x80;
  105. i++;
  106. }
  107. }
  108. return d;
  109. }
  110. static Elt operator/(const Elt& dividend, const Elt& divisor)
  111. {
  112. return dividend * divisor.Inv();
  113. }
  114. struct Point
  115. {
  116. Point() = default;
  117. constexpr explicit Point(Elt x, Elt y) : m_data{{std::move(x), std::move(y)}} {}
  118. explicit Point(const u8* data) { std::copy_n(data, sizeof(m_data), Data()); }
  119. bool IsZero() const { return X().IsZero() && Y().IsZero(); }
  120. Elt& X() { return m_data[0]; }
  121. Elt& Y() { return m_data[1]; }
  122. u8* Data() { return m_data[0].data.data(); }
  123. const Elt& X() const { return m_data[0]; }
  124. const Elt& Y() const { return m_data[1]; }
  125. const u8* Data() const { return m_data[0].data.data(); }
  126. Point Double() const
  127. {
  128. Point r;
  129. if (X().IsZero())
  130. return r;
  131. const auto s = Y() / X() + X();
  132. r.X() = s.Square() + s;
  133. r.X().data[29] ^= 1;
  134. r.Y() = s * r.X() + r.X() + X().Square();
  135. return r;
  136. }
  137. private:
  138. std::array<Elt, 2> m_data{};
  139. static_assert(sizeof(decltype(m_data)) == 60, "Wrong size for m_data");
  140. };
  141. // y**2 + x*y = x**3 + x + b
  142. [[maybe_unused]] static const u8 ec_b[30] = {
  143. 0x00, 0x66, 0x64, 0x7e, 0xde, 0x6c, 0x33, 0x2c, 0x7f, 0x8c, 0x09, 0x23, 0xbb, 0x58, 0x21,
  144. 0x3b, 0x33, 0x3b, 0x20, 0xe9, 0xce, 0x42, 0x81, 0xfe, 0x11, 0x5f, 0x7d, 0x8f, 0x90, 0xad};
  145. // order of the addition group of points
  146. static const u8 ec_N[30] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  147. 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0xe9, 0x74, 0xe7, 0x2f,
  148. 0x8a, 0x69, 0x22, 0x03, 0x1d, 0x26, 0x03, 0xcf, 0xe0, 0xd7};
  149. // base point
  150. constexpr Point ec_G{
  151. {{{0x00, 0xfa, 0xc9, 0xdf, 0xcb, 0xac, 0x83, 0x13, 0xbb, 0x21, 0x39, 0xf1, 0xbb, 0x75, 0x5f,
  152. 0xef, 0x65, 0xbc, 0x39, 0x1f, 0x8b, 0x36, 0xf8, 0xf8, 0xeb, 0x73, 0x71, 0xfd, 0x55, 0x8b}}},
  153. {{{0x01, 0x00, 0x6a, 0x08, 0xa4, 0x19, 0x03, 0x35, 0x06, 0x78, 0xe5, 0x85, 0x28, 0xbe, 0xbf,
  154. 0x8a, 0x0b, 0xef, 0xf8, 0x67, 0xa7, 0xca, 0x36, 0x71, 0x6f, 0x7e, 0x01, 0xf8, 0x10, 0x52}}}};
  155. static Point operator+(const Point& a, const Point& b)
  156. {
  157. if (a.IsZero())
  158. return b;
  159. if (b.IsZero())
  160. return a;
  161. Elt u = a.X() + b.X();
  162. if (u.IsZero())
  163. {
  164. u = a.Y() + b.Y();
  165. if (u.IsZero())
  166. return a.Double();
  167. return Point{};
  168. }
  169. const Elt s = (a.Y() + b.Y()) / u;
  170. Elt t = s.Square() + s + b.X();
  171. t.data[29] ^= 1;
  172. const Elt rx = t + a.X();
  173. const Elt ry = s * t + a.Y() + rx;
  174. return Point{rx, ry};
  175. }
  176. static Point operator*(const u8* a, const Point& b)
  177. {
  178. Point d;
  179. for (std::size_t i = 0; i < 30; i++)
  180. {
  181. for (u8 mask = 0x80; mask != 0; mask >>= 1)
  182. {
  183. d = d.Double();
  184. if ((a[i] & mask) != 0)
  185. d = d + b;
  186. }
  187. }
  188. return d;
  189. }
  190. Signature Sign(const u8* key, const u8* hash)
  191. {
  192. u8 e[30]{};
  193. memcpy(e + 10, hash, 20);
  194. u8 m[30];
  195. do
  196. {
  197. // Generate 240 bits and keep 233.
  198. Common::Random::Generate(m, sizeof(m));
  199. m[0] &= 1;
  200. } while (bn_compare(m, ec_N, sizeof(m)) >= 0);
  201. Elt r = (m * ec_G).X();
  202. if (bn_compare(r.data.data(), ec_N, 30) >= 0)
  203. bn_sub_modulus(r.data.data(), ec_N, 30);
  204. // S = m**-1*(e + Rk) (mod N)
  205. u8 kk[30];
  206. std::copy_n(key, sizeof(kk), kk);
  207. if (bn_compare(kk, ec_N, sizeof(kk)) >= 0)
  208. bn_sub_modulus(kk, ec_N, sizeof(kk));
  209. Elt s;
  210. bn_mul(s.data.data(), r.data.data(), kk, ec_N, 30);
  211. bn_add(kk, s.data.data(), e, ec_N, sizeof(kk));
  212. u8 minv[30];
  213. bn_inv(minv, m, ec_N, sizeof(minv));
  214. bn_mul(s.data.data(), minv, kk, ec_N, 30);
  215. Signature signature;
  216. std::ranges::copy(r.data, signature.begin());
  217. std::ranges::copy(s.data, signature.begin() + 30);
  218. return signature;
  219. }
  220. bool VerifySignature(const u8* public_key, const u8* signature, const u8* hash)
  221. {
  222. const u8* R = signature;
  223. const u8* S = signature + 30;
  224. u8 Sinv[30];
  225. bn_inv(Sinv, S, ec_N, 30);
  226. u8 e[30]{};
  227. memcpy(e + 10, hash, 20);
  228. u8 w1[30], w2[30];
  229. bn_mul(w1, e, Sinv, ec_N, 30);
  230. bn_mul(w2, R, Sinv, ec_N, 30);
  231. Point r1 = w1 * ec_G + w2 * Point{public_key};
  232. auto& rx = r1.X().data;
  233. if (bn_compare(rx.data(), ec_N, 30) >= 0)
  234. bn_sub_modulus(rx.data(), ec_N, 30);
  235. return (bn_compare(rx.data(), R, 30) == 0);
  236. }
  237. PublicKey PrivToPub(const u8* key)
  238. {
  239. const Point data = key * ec_G;
  240. PublicKey result;
  241. std::copy_n(data.Data(), result.size(), result.begin());
  242. return result;
  243. }
  244. std::array<u8, 60> ComputeSharedSecret(const u8* private_key, const u8* public_key)
  245. {
  246. std::array<u8, 60> shared_secret;
  247. const Point data = private_key * Point{public_key};
  248. std::copy_n(data.Data(), shared_secret.size(), shared_secret.begin());
  249. return shared_secret;
  250. }
  251. } // namespace Common::ec