SECP256r1.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. /*
  2. * Copyright (c) 2022, Michiel Visser <opensource@webmichiel.nl>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/ByteReader.h>
  7. #include <AK/Endian.h>
  8. #include <AK/Random.h>
  9. #include <AK/StringBuilder.h>
  10. #include <AK/UFixedBigInt.h>
  11. #include <LibCrypto/Curves/SECP256r1.h>
  12. namespace Crypto::Curves {
  13. static constexpr u256 REDUCE_PRIME { u128 { 0x0000000000000001ull, 0xffffffff00000000ull }, u128 { 0xffffffffffffffffull, 0x00000000fffffffe } };
  14. static constexpr u256 REDUCE_ORDER { u128 { 0x0c46353d039cdaafull, 0x4319055258e8617bull }, u128 { 0x0000000000000000ull, 0x00000000ffffffff } };
  15. static constexpr u256 PRIME_INVERSE_MOD_R { u128 { 0x0000000000000001ull, 0x0000000100000000ull }, u128 { 0x0000000000000000ull, 0xffffffff00000002ull } };
  16. static constexpr u256 PRIME { u128 { 0xffffffffffffffffull, 0x00000000ffffffffull }, u128 { 0x0000000000000000ull, 0xffffffff00000001ull } };
  17. static constexpr u256 R2_MOD_PRIME { u128 { 0x0000000000000003ull, 0xfffffffbffffffffull }, u128 { 0xfffffffffffffffeull, 0x00000004fffffffdull } };
  18. static constexpr u256 ONE { 1u };
  19. static constexpr u256 B_MONTGOMERY { u128 { 0xd89cdf6229c4bddfull, 0xacf005cd78843090ull }, u128 { 0xe5a220abf7212ed6ull, 0xdc30061d04874834ull } };
  20. static u256 import_big_endian(ReadonlyBytes data)
  21. {
  22. VERIFY(data.size() == 32);
  23. u64 d = AK::convert_between_host_and_big_endian(ByteReader::load64(data.offset_pointer(0 * sizeof(u64))));
  24. u64 c = AK::convert_between_host_and_big_endian(ByteReader::load64(data.offset_pointer(1 * sizeof(u64))));
  25. u64 b = AK::convert_between_host_and_big_endian(ByteReader::load64(data.offset_pointer(2 * sizeof(u64))));
  26. u64 a = AK::convert_between_host_and_big_endian(ByteReader::load64(data.offset_pointer(3 * sizeof(u64))));
  27. return u256 { u128 { a, b }, u128 { c, d } };
  28. }
  29. static void export_big_endian(u256 const& value, Bytes data)
  30. {
  31. u64 a = AK::convert_between_host_and_big_endian(value.low().low());
  32. u64 b = AK::convert_between_host_and_big_endian(value.low().high());
  33. u64 c = AK::convert_between_host_and_big_endian(value.high().low());
  34. u64 d = AK::convert_between_host_and_big_endian(value.high().high());
  35. ByteReader::store(data.offset_pointer(0 * sizeof(u64)), d);
  36. ByteReader::store(data.offset_pointer(1 * sizeof(u64)), c);
  37. ByteReader::store(data.offset_pointer(2 * sizeof(u64)), b);
  38. ByteReader::store(data.offset_pointer(3 * sizeof(u64)), a);
  39. }
  40. static u256 select(u256 const& left, u256 const& right, bool condition)
  41. {
  42. // If condition = 0 return left else right
  43. u256 mask = (u256)condition - 1;
  44. return (left & mask) | (right & ~mask);
  45. }
  46. static u512 multiply(u256 const& left, u256 const& right)
  47. {
  48. return left.wide_multiply(right);
  49. }
  50. static u256 modular_reduce(u256 const& value)
  51. {
  52. // Add -prime % 2^256 = 2^224-2^192-2^96+1
  53. bool carry = false;
  54. u256 other = value.addc(REDUCE_PRIME, carry);
  55. // Check for overflow
  56. return select(value, other, carry);
  57. }
  58. static u256 modular_reduce_order(u256 const& value)
  59. {
  60. // Add -order % 2^256
  61. bool carry = false;
  62. u256 other = value.addc(REDUCE_ORDER, carry);
  63. // Check for overflow
  64. return select(value, other, carry);
  65. }
  66. static u256 modular_add(u256 const& left, u256 const& right, bool carry_in = false)
  67. {
  68. bool carry = carry_in;
  69. u256 output = left.addc(right, carry);
  70. // If there is left carry, subtract p by adding 2^256 - p
  71. u64 t = carry;
  72. carry = false;
  73. u256 addend { u128 { t, -(t << 32) }, u128 { -t, (t << 32) - (t << 1) } };
  74. output = output.addc(addend, carry);
  75. // If there is still left carry, subtract p by adding 2^256 - p
  76. t = carry;
  77. addend = { u128 { t, -(t << 32) }, u128 { -t, (t << 32) - (t << 1) } };
  78. return output + addend;
  79. }
  80. static u256 modular_sub(u256 const& left, u256 const& right)
  81. {
  82. bool borrow = false;
  83. u256 output = left.subc(right, borrow);
  84. // If there is left borrow, add p by subtracting 2^256 - p
  85. u64 t = borrow;
  86. borrow = false;
  87. u256 sub { u128 { t, -(t << 32) }, u128 { -t, (t << 32) - (t << 1) } };
  88. output = output.subc(sub, borrow);
  89. // If there is still left borrow, add p by subtracting 2^256 - p
  90. t = borrow;
  91. sub = { u128 { t, -(t << 32) }, u128 { -t, (t << 32) - (t << 1) } };
  92. return output - sub;
  93. }
  94. static u256 modular_multiply(u256 const& left, u256 const& right)
  95. {
  96. // Modular multiplication using the Montgomery method: https://en.wikipedia.org/wiki/Montgomery_modular_multiplication
  97. // This requires that the inputs to this function are in Montgomery form.
  98. // T = left * right
  99. u512 mult = multiply(left, right);
  100. // m = ((T mod R) * curve_p')
  101. u512 m = multiply(mult.low(), PRIME_INVERSE_MOD_R);
  102. // mp = (m mod R) * curve_p
  103. u512 mp = multiply(m.low(), PRIME);
  104. // t = (T + mp)
  105. bool carry = false;
  106. mult.low().addc(mp.low(), carry);
  107. // output = t / R
  108. return modular_add(mult.high(), mp.high(), carry);
  109. }
  110. static u256 modular_square(u256 const& value)
  111. {
  112. return modular_multiply(value, value);
  113. }
  114. static u256 to_montgomery(u256 const& value)
  115. {
  116. return modular_multiply(value, R2_MOD_PRIME);
  117. }
  118. static u256 from_montgomery(u256 const& value)
  119. {
  120. return modular_multiply(value, ONE);
  121. }
  122. static u256 modular_inverse(u256 const& value)
  123. {
  124. // Modular inverse modulo the curve prime can be computed using Fermat's little theorem: a^(p-2) mod p = a^-1 mod p.
  125. // Calculating a^(p-2) mod p can be done using the square-and-multiply exponentiation method, as p-2 is constant.
  126. //
  127. // p-2 = 2^256 - 2^224 + 2^192 + 2^96 - 3, or written as binary:
  128. // 1111111111111111111111111111111100000000000000000000000000000001
  129. // 0000000000000000000000000000000000000000000000000000000000000000
  130. // 0000000000000000000000000000000011111111111111111111111111111111
  131. // 1111111111111111111111111111111111111111111111111111111111111101
  132. u256 base = value;
  133. // 1
  134. u256 result = value;
  135. base = modular_square(base);
  136. // 0
  137. base = modular_square(base);
  138. // 94*1
  139. for (auto i = 0; i < 94; i++) {
  140. result = modular_multiply(result, base);
  141. base = modular_square(base);
  142. }
  143. // 96*0
  144. for (auto i = 0; i < 96; i++) {
  145. base = modular_square(base);
  146. }
  147. // 1
  148. result = modular_multiply(result, base);
  149. base = modular_square(base);
  150. // 31*0
  151. for (auto i = 0; i < 31; i++) {
  152. base = modular_square(base);
  153. }
  154. // 32*1
  155. for (auto i = 0; i < 32; i++) {
  156. result = modular_multiply(result, base);
  157. base = modular_square(base);
  158. }
  159. return result;
  160. }
  161. static void point_double(JacobianPoint& output_point, JacobianPoint const& point)
  162. {
  163. // Based on "Point Doubling" from http://point-at-infinity.org/ecc/Prime_Curve_Jacobian_Coordinates.html
  164. // if (Y == 0)
  165. // return POINT_AT_INFINITY
  166. if (point.y.is_zero_constant_time()) {
  167. VERIFY_NOT_REACHED();
  168. }
  169. u256 temp;
  170. // Y2 = Y^2
  171. u256 y2 = modular_square(point.y);
  172. // S = 4*X*Y2
  173. u256 s = modular_multiply(point.x, y2);
  174. s = modular_add(s, s);
  175. s = modular_add(s, s);
  176. // M = 3*X^2 + a*Z^4 = 3*(X + Z^2)*(X - Z^2)
  177. // This specific equation from https://github.com/earlephilhower/bearssl-esp8266/blob/6105635531027f5b298aa656d44be2289b2d434f/src/ec/ec_p256_m64.c#L811-L816
  178. // This simplification only works because a = -3 mod p
  179. temp = modular_square(point.z);
  180. u256 m = modular_add(point.x, temp);
  181. temp = modular_sub(point.x, temp);
  182. m = modular_multiply(m, temp);
  183. temp = modular_add(m, m);
  184. m = modular_add(m, temp);
  185. // X' = M^2 - 2*S
  186. u256 xp = modular_square(m);
  187. xp = modular_sub(xp, s);
  188. xp = modular_sub(xp, s);
  189. // Y' = M*(S - X') - 8*Y2^2
  190. u256 yp = modular_sub(s, xp);
  191. yp = modular_multiply(yp, m);
  192. temp = modular_square(y2);
  193. temp = modular_add(temp, temp);
  194. temp = modular_add(temp, temp);
  195. temp = modular_add(temp, temp);
  196. yp = modular_sub(yp, temp);
  197. // Z' = 2*Y*Z
  198. u256 zp = modular_multiply(point.y, point.z);
  199. zp = modular_add(zp, zp);
  200. // return (X', Y', Z')
  201. output_point.x = xp;
  202. output_point.y = yp;
  203. output_point.z = zp;
  204. }
  205. static void point_add(JacobianPoint& output_point, JacobianPoint const& point_a, JacobianPoint const& point_b)
  206. {
  207. // Based on "Point Addition" from http://point-at-infinity.org/ecc/Prime_Curve_Jacobian_Coordinates.html
  208. if (point_a.x.is_zero_constant_time() && point_a.y.is_zero_constant_time() && point_a.z.is_zero_constant_time()) {
  209. output_point.x = point_b.x;
  210. output_point.y = point_b.y;
  211. output_point.z = point_b.z;
  212. return;
  213. }
  214. u256 temp;
  215. temp = modular_square(point_b.z);
  216. // U1 = X1*Z2^2
  217. u256 u1 = modular_multiply(point_a.x, temp);
  218. // S1 = Y1*Z2^3
  219. u256 s1 = modular_multiply(point_a.y, temp);
  220. s1 = modular_multiply(s1, point_b.z);
  221. temp = modular_square(point_a.z);
  222. // U2 = X2*Z1^2
  223. u256 u2 = modular_multiply(point_b.x, temp);
  224. // S2 = Y2*Z1^3
  225. u256 s2 = modular_multiply(point_b.y, temp);
  226. s2 = modular_multiply(s2, point_a.z);
  227. // if (U1 == U2)
  228. // if (S1 != S2)
  229. // return POINT_AT_INFINITY
  230. // else
  231. // return POINT_DOUBLE(X1, Y1, Z1)
  232. if (u1.is_equal_to_constant_time(u2)) {
  233. if (s1.is_equal_to_constant_time(s2)) {
  234. point_double(output_point, point_a);
  235. return;
  236. } else {
  237. VERIFY_NOT_REACHED();
  238. }
  239. }
  240. // H = U2 - U1
  241. u256 h = modular_sub(u2, u1);
  242. u256 h2 = modular_square(h);
  243. u256 h3 = modular_multiply(h2, h);
  244. // R = S2 - S1
  245. u256 r = modular_sub(s2, s1);
  246. // X3 = R^2 - H^3 - 2*U1*H^2
  247. u256 x3 = modular_square(r);
  248. x3 = modular_sub(x3, h3);
  249. temp = modular_multiply(u1, h2);
  250. temp = modular_add(temp, temp);
  251. x3 = modular_sub(x3, temp);
  252. // Y3 = R*(U1*H^2 - X3) - S1*H^3
  253. u256 y3 = modular_multiply(u1, h2);
  254. y3 = modular_sub(y3, x3);
  255. y3 = modular_multiply(y3, r);
  256. temp = modular_multiply(s1, h3);
  257. y3 = modular_sub(y3, temp);
  258. // Z3 = H*Z1*Z2
  259. u256 z3 = modular_multiply(h, point_a.z);
  260. z3 = modular_multiply(z3, point_b.z);
  261. // return (X3, Y3, Z3)
  262. output_point.x = x3;
  263. output_point.y = y3;
  264. output_point.z = z3;
  265. }
  266. static void convert_jacobian_to_affine(JacobianPoint& point)
  267. {
  268. u256 temp;
  269. // X' = X/Z^2
  270. temp = modular_square(point.z);
  271. temp = modular_inverse(temp);
  272. point.x = modular_multiply(point.x, temp);
  273. // Y' = Y/Z^3
  274. temp = modular_square(point.z);
  275. temp = modular_multiply(temp, point.z);
  276. temp = modular_inverse(temp);
  277. point.y = modular_multiply(point.y, temp);
  278. }
  279. static bool is_point_on_curve(JacobianPoint const& point)
  280. {
  281. // This check requires the point to be in Montgomery form, with Z=1
  282. u256 temp, temp2;
  283. // Calulcate Y^2 - X^3 - a*X - b = Y^2 - X^3 + 3*X - b
  284. temp = modular_square(point.y);
  285. temp2 = modular_square(point.x);
  286. temp2 = modular_multiply(temp2, point.x);
  287. temp = modular_sub(temp, temp2);
  288. temp = modular_add(temp, point.x);
  289. temp = modular_add(temp, point.x);
  290. temp = modular_add(temp, point.x);
  291. temp = modular_sub(temp, B_MONTGOMERY);
  292. temp = modular_reduce(temp);
  293. return temp.is_zero_constant_time();
  294. }
  295. ErrorOr<ByteBuffer> SECP256r1::generate_private_key()
  296. {
  297. auto buffer = TRY(ByteBuffer::create_uninitialized(32));
  298. fill_with_random(buffer);
  299. return buffer;
  300. }
  301. ErrorOr<ByteBuffer> SECP256r1::generate_public_key(ReadonlyBytes a)
  302. {
  303. // clang-format off
  304. u8 generator_bytes[65] {
  305. 0x04,
  306. 0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47, 0xF8, 0xBC, 0xE6, 0xE5, 0x63, 0xA4, 0x40, 0xF2,
  307. 0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33, 0xA0, 0xF4, 0xA1, 0x39, 0x45, 0xD8, 0x98, 0xC2, 0x96,
  308. 0x4F, 0xE3, 0x42, 0xE2, 0xFE, 0x1A, 0x7F, 0x9B, 0x8E, 0xE7, 0xEB, 0x4A, 0x7C, 0x0F, 0x9E, 0x16,
  309. 0x2B, 0xCE, 0x33, 0x57, 0x6B, 0x31, 0x5E, 0xCE, 0xCB, 0xB6, 0x40, 0x68, 0x37, 0xBF, 0x51, 0xF5,
  310. };
  311. // clang-format on
  312. return compute_coordinate(a, { generator_bytes, 65 });
  313. }
  314. ErrorOr<ByteBuffer> SECP256r1::compute_coordinate(ReadonlyBytes scalar_bytes, ReadonlyBytes point_bytes)
  315. {
  316. VERIFY(scalar_bytes.size() == 32);
  317. u256 scalar = import_big_endian(scalar_bytes);
  318. // FIXME: This will slightly bias the distribution of client secrets
  319. scalar = modular_reduce_order(scalar);
  320. if (scalar.is_zero_constant_time())
  321. return Error::from_string_literal("SECP256r1: scalar is zero");
  322. // Make sure the point is uncompressed
  323. if (point_bytes.size() != 65 || point_bytes[0] != 0x04)
  324. return Error::from_string_literal("SECP256r1: point is not uncompressed format");
  325. JacobianPoint point {
  326. import_big_endian(point_bytes.slice(1, 32)),
  327. import_big_endian(point_bytes.slice(33, 32)),
  328. 1u,
  329. };
  330. // Convert the input point into Montgomery form
  331. point.x = to_montgomery(point.x);
  332. point.y = to_montgomery(point.y);
  333. point.z = to_montgomery(point.z);
  334. // Check that the point is on the curve
  335. if (!is_point_on_curve(point))
  336. return Error::from_string_literal("SECP256r1: point is not on the curve");
  337. JacobianPoint result;
  338. JacobianPoint temp_result;
  339. // Calculate the scalar times point multiplication in constant time
  340. for (auto i = 0; i < 256; i++) {
  341. point_add(temp_result, result, point);
  342. auto condition = (scalar & 1u) == 1u;
  343. result.x = select(result.x, temp_result.x, condition);
  344. result.y = select(result.y, temp_result.y, condition);
  345. result.z = select(result.z, temp_result.z, condition);
  346. point_double(point, point);
  347. scalar >>= 1u;
  348. }
  349. // Convert from Jacobian coordinates back to Affine coordinates
  350. convert_jacobian_to_affine(result);
  351. // Make sure the resulting point is on the curve
  352. VERIFY(is_point_on_curve(result));
  353. // Convert the result back from Montgomery form
  354. result.x = from_montgomery(result.x);
  355. result.y = from_montgomery(result.y);
  356. // Final modular reduction on the coordinates
  357. result.x = modular_reduce(result.x);
  358. result.y = modular_reduce(result.y);
  359. // Export the values into an output buffer
  360. auto buf = TRY(ByteBuffer::create_uninitialized(65));
  361. buf[0] = 0x04;
  362. export_big_endian(result.x, buf.bytes().slice(1, 32));
  363. export_big_endian(result.y, buf.bytes().slice(33, 32));
  364. return buf;
  365. }
  366. ErrorOr<ByteBuffer> SECP256r1::derive_premaster_key(ReadonlyBytes shared_point)
  367. {
  368. VERIFY(shared_point.size() == 65);
  369. VERIFY(shared_point[0] == 0x04);
  370. ByteBuffer premaster_key = TRY(ByteBuffer::create_uninitialized(32));
  371. premaster_key.overwrite(0, shared_point.data() + 1, 32);
  372. return premaster_key;
  373. }
  374. }