X25519.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. /*
  2. * Copyright (c) 2022, stelar7 <dudedbz@gmail.com>
  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 <LibCrypto/Curves/Curve25519.h>
  10. #include <LibCrypto/Curves/X25519.h>
  11. namespace Crypto::Curves {
  12. static constexpr u8 BITS = 255;
  13. static constexpr u8 BYTES = 32;
  14. static constexpr u8 WORDS = 8;
  15. static constexpr u32 A24 = 121666;
  16. static void conditional_swap(u32* first, u32* second, u32 condition)
  17. {
  18. u32 mask = ~condition + 1;
  19. for (auto i = 0; i < WORDS; i++) {
  20. u32 temp = mask & (first[i] ^ second[i]);
  21. first[i] ^= temp;
  22. second[i] ^= temp;
  23. }
  24. }
  25. ErrorOr<ByteBuffer> X25519::generate_private_key()
  26. {
  27. auto buffer = TRY(ByteBuffer::create_uninitialized(BYTES));
  28. fill_with_random(buffer);
  29. return buffer;
  30. }
  31. ErrorOr<ByteBuffer> X25519::generate_public_key(ReadonlyBytes a)
  32. {
  33. u8 generator[BYTES] { 9 };
  34. return compute_coordinate(a, { generator, BYTES });
  35. }
  36. // https://datatracker.ietf.org/doc/html/rfc7748#section-5
  37. ErrorOr<ByteBuffer> X25519::compute_coordinate(ReadonlyBytes input_k, ReadonlyBytes input_u)
  38. {
  39. u32 k[WORDS] {};
  40. u32 u[WORDS] {};
  41. u32 x1[WORDS] {};
  42. u32 x2[WORDS] {};
  43. u32 z1[WORDS] {};
  44. u32 z2[WORDS] {};
  45. u32 t1[WORDS] {};
  46. u32 t2[WORDS] {};
  47. // Copy input to internal state
  48. Curve25519::import_state(k, input_k.data());
  49. // Set the three least significant bits of the first byte and the most significant bit of the last to zero,
  50. // set the second most significant bit of the last byte to 1
  51. k[0] &= 0xFFFFFFF8;
  52. k[7] &= 0x7FFFFFFF;
  53. k[7] |= 0x40000000;
  54. // Copy coordinate to internal state
  55. Curve25519::import_state(u, input_u.data());
  56. // mask the most significant bit in the final byte.
  57. u[7] &= 0x7FFFFFFF;
  58. // Implementations MUST accept non-canonical values and process them as
  59. // if they had been reduced modulo the field prime.
  60. Curve25519::modular_reduce(u, u);
  61. Curve25519::set(x1, 1);
  62. Curve25519::set(z1, 0);
  63. Curve25519::copy(x2, u);
  64. Curve25519::set(z2, 1);
  65. // Montgomery ladder
  66. u32 swap = 0;
  67. for (auto i = BITS - 1; i >= 0; i--) {
  68. u32 b = (k[i / BYTES] >> (i % BYTES)) & 1;
  69. conditional_swap(x1, x2, swap ^ b);
  70. conditional_swap(z1, z2, swap ^ b);
  71. swap = b;
  72. Curve25519::modular_add(t1, x2, z2);
  73. Curve25519::modular_subtract(x2, x2, z2);
  74. Curve25519::modular_add(z2, x1, z1);
  75. Curve25519::modular_subtract(x1, x1, z1);
  76. Curve25519::modular_multiply(t1, t1, x1);
  77. Curve25519::modular_multiply(x2, x2, z2);
  78. Curve25519::modular_square(z2, z2);
  79. Curve25519::modular_square(x1, x1);
  80. Curve25519::modular_subtract(t2, z2, x1);
  81. Curve25519::modular_multiply_single(z1, t2, A24);
  82. Curve25519::modular_add(z1, z1, x1);
  83. Curve25519::modular_multiply(z1, z1, t2);
  84. Curve25519::modular_multiply(x1, x1, z2);
  85. Curve25519::modular_subtract(z2, t1, x2);
  86. Curve25519::modular_square(z2, z2);
  87. Curve25519::modular_multiply(z2, z2, u);
  88. Curve25519::modular_add(x2, x2, t1);
  89. Curve25519::modular_square(x2, x2);
  90. }
  91. conditional_swap(x1, x2, swap);
  92. conditional_swap(z1, z2, swap);
  93. // Retrieve affine representation
  94. Curve25519::modular_multiply_inverse(u, z1);
  95. Curve25519::modular_multiply(u, u, x1);
  96. // Encode state for export
  97. auto buffer = TRY(ByteBuffer::create_uninitialized(BYTES));
  98. Curve25519::export_state(u, buffer.data());
  99. return buffer;
  100. }
  101. ErrorOr<ByteBuffer> X25519::derive_premaster_key(ReadonlyBytes shared_point)
  102. {
  103. VERIFY(shared_point.size() == BYTES);
  104. ByteBuffer premaster_key = TRY(ByteBuffer::copy(shared_point));
  105. return premaster_key;
  106. }
  107. }