diff options
author | stelar7 <dudedbz@gmail.com> | 2022-04-16 11:33:09 +0200 |
---|---|---|
committer | Ali Mohammad Pur <Ali.mpfard@gmail.com> | 2022-05-12 23:47:13 +0430 |
commit | 9aaeaf8a22947c0991daab344bae14f06e84aa36 (patch) | |
tree | 1cd858bb559d9951dd8cfba0c310bf3ee0c83903 /Userland/Libraries/LibCrypto/Curves | |
parent | 6a7d3006d74b9c47207c94a1b0d3e5035a57b6a8 (diff) | |
download | serenity-9aaeaf8a22947c0991daab344bae14f06e84aa36.zip |
LibCrypto: Move Curve25519 related code into separate file
Diffstat (limited to 'Userland/Libraries/LibCrypto/Curves')
-rw-r--r-- | Userland/Libraries/LibCrypto/Curves/Curve25519.cpp | 360 | ||||
-rw-r--r-- | Userland/Libraries/LibCrypto/Curves/Curve25519.h | 73 | ||||
-rw-r--r-- | Userland/Libraries/LibCrypto/Curves/X25519.cpp | 299 |
3 files changed, 465 insertions, 267 deletions
diff --git a/Userland/Libraries/LibCrypto/Curves/Curve25519.cpp b/Userland/Libraries/LibCrypto/Curves/Curve25519.cpp new file mode 100644 index 0000000000..5651598ae1 --- /dev/null +++ b/Userland/Libraries/LibCrypto/Curves/Curve25519.cpp @@ -0,0 +1,360 @@ +/* + * Copyright (c) 2022, stelar7 <dudedbz@gmail.com> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <AK/Endian.h> +#include <AK/Types.h> +#include <LibCrypto/Curves/Curve25519.h> + +namespace Crypto::Curves { + +void Curve25519::set(u32* state, u32 value) +{ + state[0] = value; + + for (auto i = 1; i < WORDS; i++) { + state[i] = 0; + } +} + +void Curve25519::modular_square(u32* state, u32 const* value) +{ + // Compute R = (A ^ 2) mod p + modular_multiply(state, value, value); +} + +void Curve25519::modular_subtract(u32* state, u32 const* first, u32 const* second) +{ + // R = (A - B) mod p + i64 temp = -19; + for (auto i = 0; i < WORDS; i++) { + temp += first[i]; + temp -= second[i]; + state[i] = temp & 0xFFFFFFFF; + temp >>= 32; + } + + // Compute R = A + (2^255 - 19) - B + state[7] += 0x80000000; + + modular_reduce(state, state); +} + +void Curve25519::modular_add(u32* state, u32 const* first, u32 const* second) +{ + // R = (A + B) mod p + u64 temp = 0; + for (auto i = 0; i < WORDS; i++) { + temp += first[i]; + temp += second[i]; + state[i] = temp & 0xFFFFFFFF; + temp >>= 32; + } + + modular_reduce(state, state); +} + +void Curve25519::modular_multiply(u32* state, u32 const* first, u32 const* second) +{ + // Compute R = (A * B) mod p + u64 temp = 0; + u64 carry = 0; + u32 output[WORDS * 2]; + + // Comba's method + for (auto i = 0; i < 16; i++) { + if (i < WORDS) { + for (auto j = 0; j <= i; j++) { + temp += (u64)first[j] * second[i - j]; + carry += temp >> 32; + temp &= 0xFFFFFFFF; + } + } else { + for (auto j = i - 7; j < WORDS; j++) { + temp += (u64)first[j] * second[i - j]; + carry += temp >> 32; + temp &= 0xFFFFFFFF; + } + } + + output[i] = temp & 0xFFFFFFFF; + temp = carry & 0xFFFFFFFF; + carry >>= 32; + } + + // Reduce bit 255 (2^255 = 19 mod p) + temp = (output[7] >> 31) * 19; + // Mask the most significant bit + output[7] &= 0x7FFFFFFF; + + // Fast modular reduction 1st pass + for (auto i = 0; i < WORDS; i++) { + temp += output[i]; + temp += (u64)output[i + 8] * 38; + output[i] = temp & 0xFFFFFFFF; + temp >>= 32; + } + + // Reduce bit 256 (2^256 = 38 mod p) + temp *= 38; + // Reduce bit 255 (2^255 = 19 mod p) + temp += (output[7] >> 31) * 19; + // Mask the most significant bit + output[7] &= 0x7FFFFFFF; + + // Fast modular reduction 2nd pass + for (auto i = 0; i < WORDS; i++) { + temp += output[i]; + output[i] = temp & 0xFFFFFFFF; + temp >>= 32; + } + + modular_reduce(state, output); +} + +void Curve25519::export_state(u32* state, u8* output) +{ + for (u32 i = 0; i < WORDS; i++) { + state[i] = AK::convert_between_host_and_little_endian(state[i]); + } + + memcpy(output, state, BYTES); +} + +void Curve25519::import_state(u32* state, u8 const* data) +{ + memcpy(state, data, BYTES); + for (u32 i = 0; i < WORDS; i++) { + state[i] = AK::convert_between_host_and_little_endian(state[i]); + } +} + +void Curve25519::modular_subtract_single(u32* r, u32 const* a, u32 b) +{ + i64 temp = -19; + temp -= b; + + // Compute R = A - 19 - B + for (u32 i = 0; i < 8; i++) { + temp += a[i]; + r[i] = temp & 0xFFFFFFFF; + temp >>= 32; + } + + // Compute R = A + (2^255 - 19) - B + r[7] += 0x80000000; + modular_reduce(r, r); +} + +void Curve25519::modular_add_single(u32* state, u32 const* first, u32 second) +{ + u64 temp = second; + + // Compute R = A + B + for (u32 i = 0; i < 8; i++) { + temp += first[i]; + state[i] = temp & 0xFFFFFFFF; + temp >>= 32; + } + + modular_reduce(state, state); +} + +u32 Curve25519::modular_square_root(u32* r, u32 const* a, u32 const* b) +{ + u32 c[8]; + u32 u[8]; + u32 v[8]; + + // To compute the square root of (A / B), the first step is to compute the candidate root x = (A / B)^((p+3)/8) + modular_square(v, b); + modular_multiply(v, v, b); + modular_square(v, v); + modular_multiply(v, v, b); + modular_multiply(c, a, v); + modular_square(u, c); + modular_multiply(u, u, c); + modular_square(u, u); + modular_multiply(v, u, c); + to_power_of_2n(u, v, 3); + modular_multiply(u, u, v); + modular_square(u, u); + modular_multiply(v, u, c); + to_power_of_2n(u, v, 7); + modular_multiply(u, u, v); + modular_square(u, u); + modular_multiply(v, u, c); + to_power_of_2n(u, v, 15); + modular_multiply(u, u, v); + modular_square(u, u); + modular_multiply(v, u, c); + to_power_of_2n(u, v, 31); + modular_multiply(v, u, v); + to_power_of_2n(u, v, 62); + modular_multiply(u, u, v); + modular_square(u, u); + modular_multiply(v, u, c); + to_power_of_2n(u, v, 125); + modular_multiply(u, u, v); + modular_square(u, u); + modular_square(u, u); + modular_multiply(u, u, c); + + // The first candidate root is U = A * B^3 * (A * B^7)^((p - 5) / 8) + modular_multiply(u, u, a); + modular_square(v, b); + modular_multiply(v, v, b); + modular_multiply(u, u, v); + + // The second candidate root is V = U * sqrt(-1) + modular_multiply(v, u, SQRT_MINUS_1); + + modular_square(c, u); + modular_multiply(c, c, b); + + // Check whether B * U^2 = A + u32 first_comparison = compare(c, a); + + modular_square(c, v); + modular_multiply(c, c, b); + + // Check whether B * V^2 = A + u32 second_comparison = compare(c, a); + + // Select the first or the second candidate root + select(r, u, v, first_comparison); + + // Return 0 if the square root exists + return first_comparison & second_comparison; +} + +u32 Curve25519::compare(u32 const* a, u32 const* b) +{ + u32 mask = 0; + for (u32 i = 0; i < 8; i++) { + mask |= a[i] ^ b[i]; + } + + // Return 0 if A = B, else 1 + return ((u32)(mask | (~mask + 1))) >> 31; +} + +void Curve25519::modular_reduce(u32* state, u32 const* data) +{ + // R = A mod p + u64 temp = 19; + u32 other[WORDS]; + + for (auto i = 0; i < WORDS; i++) { + temp += data[i]; + other[i] = temp & 0xFFFFFFFF; + temp >>= 32; + } + + // Compute B = A - (2^255 - 19) + other[7] -= 0x80000000; + + u32 mask = (other[7] & 0x80000000) >> 31; + select(state, other, data, mask); +} + +void Curve25519::to_power_of_2n(u32* state, u32 const* value, u8 n) +{ + // Pre-compute (A ^ 2) mod p + modular_square(state, value); + + // Compute R = (A ^ (2^n)) mod p + for (u32 i = 1; i < n; i++) { + modular_square(state, state); + } +} + +void Curve25519::select(u32* state, u32 const* a, u32 const* b, u32 condition) +{ + // If B < (2^255 - 19) then R = B, else R = A + u32 mask = condition - 1; + + for (auto i = 0; i < WORDS; i++) { + state[i] = (a[i] & mask) | (b[i] & ~mask); + } +} + +void Curve25519::copy(u32* state, u32 const* value) +{ + for (auto i = 0; i < WORDS; i++) { + state[i] = value[i]; + } +} + +void Curve25519::modular_multiply_inverse(u32* state, u32 const* value) +{ + // Compute R = A^-1 mod p + u32 u[WORDS]; + u32 v[WORDS]; + + // Fermat's little theorem + modular_square(u, value); + modular_multiply(u, u, value); + modular_square(u, u); + modular_multiply(v, u, value); + to_power_of_2n(u, v, 3); + modular_multiply(u, u, v); + modular_square(u, u); + modular_multiply(v, u, value); + to_power_of_2n(u, v, 7); + modular_multiply(u, u, v); + modular_square(u, u); + modular_multiply(v, u, value); + to_power_of_2n(u, v, 15); + modular_multiply(u, u, v); + modular_square(u, u); + modular_multiply(v, u, value); + to_power_of_2n(u, v, 31); + modular_multiply(v, u, v); + to_power_of_2n(u, v, 62); + modular_multiply(u, u, v); + modular_square(u, u); + modular_multiply(v, u, value); + to_power_of_2n(u, v, 125); + modular_multiply(u, u, v); + modular_square(u, u); + modular_square(u, u); + modular_multiply(u, u, value); + modular_square(u, u); + modular_square(u, u); + modular_multiply(u, u, value); + modular_square(u, u); + modular_multiply(state, u, value); +} + +void Curve25519::modular_multiply_single(u32* state, u32 const* first, u32 second) +{ + // Compute R = (A * B) mod p + u64 temp = 0; + u32 output[WORDS]; + + for (auto i = 0; i < WORDS; i++) { + temp += (u64)first[i] * second; + output[i] = temp & 0xFFFFFFFF; + temp >>= 32; + } + + // Reduce bit 256 (2^256 = 38 mod p) + temp *= 38; + // Reduce bit 255 (2^255 = 19 mod p) + temp += (output[7] >> 31) * 19; + // Mask the most significant bit + output[7] &= 0x7FFFFFFF; + + // Fast modular reduction + for (auto i = 0; i < WORDS; i++) { + temp += output[i]; + output[i] = temp & 0xFFFFFFFF; + temp >>= 32; + } + + modular_reduce(state, output); +} +} diff --git a/Userland/Libraries/LibCrypto/Curves/Curve25519.h b/Userland/Libraries/LibCrypto/Curves/Curve25519.h new file mode 100644 index 0000000000..eb4d32e0de --- /dev/null +++ b/Userland/Libraries/LibCrypto/Curves/Curve25519.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2022, stelar7 <dudedbz@gmail.com> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/Random.h> + +namespace Crypto::Curves { + +class Curve25519 { +public: + static constexpr u8 BASE_POINT_L_ORDER[33] { + 0xED, 0xD3, 0xF5, 0x5C, 0x1A, 0x63, 0x12, 0x58, + 0xD6, 0x9C, 0xF7, 0xA2, 0xDE, 0xF9, 0xDE, 0x14, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00 + }; + + static constexpr u32 CURVE_D[8] { + 0x135978A3, 0x75EB4DCA, 0x4141D8AB, 0x00700A4D, + 0x7779E898, 0x8CC74079, 0x2B6FFE73, 0x52036CEE + }; + + static constexpr u32 CURVE_D_2[8] { + 0x26B2F159, 0xEBD69B94, 0x8283B156, 0x00E0149A, + 0xEEF3D130, 0x198E80F2, 0x56DFFCE7, 0x2406D9DC + }; + + static constexpr u32 ZERO[8] { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 + }; + + static constexpr u32 SQRT_MINUS_1[8] { + 0x4A0EA0B0, 0xC4EE1B27, 0xAD2FE478, 0x2F431806, + 0x3DFBD7A7, 0x2B4D0099, 0x4FC1DF0B, 0x2B832480 + }; + + static constexpr u8 BARRETT_REDUCTION_QUOTIENT[33] { + 0x1B, 0x13, 0x2C, 0x0A, 0xA3, 0xE5, 0x9C, 0xED, + 0xA7, 0x29, 0x63, 0x08, 0x5D, 0x21, 0x06, 0x21, + 0xEB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x0F + }; + + static constexpr u8 BITS = 255; + static constexpr u8 BYTES = 32; + static constexpr u8 WORDS = 8; + static constexpr u32 A24 = 121666; + + static void set(u32* a, u32 b); + static void select(u32* r, u32 const* a, u32 const* b, u32 c); + static void copy(u32* a, u32 const* b); + static void modular_square(u32* r, u32 const* a); + static void modular_subtract(u32* r, u32 const* a, u32 const* b); + static void modular_reduce(u32* r, u32 const* a); + static void modular_add(u32* r, u32 const* a, u32 const* b); + static void modular_multiply(u32* r, u32 const* a, u32 const* b); + static void modular_multiply_inverse(u32* r, u32 const* a); + static void to_power_of_2n(u32* r, u32 const* a, u8 n); + static void export_state(u32* a, u8* data); + static void import_state(u32* a, u8 const* data); + static void modular_subtract_single(u32* r, u32 const* a, u32 b); + static void modular_multiply_single(u32* r, u32 const* a, u32 b); + static void modular_add_single(u32* r, u32 const* a, u32 b); + static u32 modular_square_root(u32* r, u32 const* a, u32 const* b); + static u32 compare(u32 const* a, u32 const* b); +}; +} diff --git a/Userland/Libraries/LibCrypto/Curves/X25519.cpp b/Userland/Libraries/LibCrypto/Curves/X25519.cpp index faa98f4e8b..07c2ffd300 100644 --- a/Userland/Libraries/LibCrypto/Curves/X25519.cpp +++ b/Userland/Libraries/LibCrypto/Curves/X25519.cpp @@ -7,6 +7,7 @@ #include <AK/ByteReader.h> #include <AK/Endian.h> #include <AK/Random.h> +#include <LibCrypto/Curves/Curve25519.h> #include <LibCrypto/Curves/X25519.h> namespace Crypto::Curves { @@ -16,52 +17,6 @@ static constexpr u8 BYTES = 32; static constexpr u8 WORDS = 8; static constexpr u32 A24 = 121666; -static void import_state(u32* state, ReadonlyBytes data) -{ - for (auto i = 0; i < WORDS; i++) { - u32 value = ByteReader::load32(data.offset_pointer(sizeof(u32) * i)); - state[i] = AK::convert_between_host_and_little_endian(value); - } -} - -static ErrorOr<ByteBuffer> export_state(u32* data) -{ - auto buffer = TRY(ByteBuffer::create_uninitialized(BYTES)); - - for (auto i = 0; i < WORDS; i++) { - u32 value = AK::convert_between_host_and_little_endian(data[i]); - ByteReader::store(buffer.offset_pointer(sizeof(u32) * i), value); - } - - return buffer; -} - -static void select(u32* state, u32* a, u32* b, u32 condition) -{ - // If B < (2^255 - 19) then R = B, else R = A - u32 mask = condition - 1; - - for (auto i = 0; i < WORDS; i++) { - state[i] = (a[i] & mask) | (b[i] & ~mask); - } -} - -static void set(u32* state, u32 value) -{ - state[0] = value; - - for (auto i = 1; i < WORDS; i++) { - state[i] = 0; - } -} - -static void copy(u32* state, u32* value) -{ - for (auto i = 0; i < WORDS; i++) { - state[i] = value[i]; - } -} - static void conditional_swap(u32* first, u32* second, u32 condition) { u32 mask = ~condition + 1; @@ -72,199 +27,6 @@ static void conditional_swap(u32* first, u32* second, u32 condition) } } -static void modular_reduce(u32* state, u32* data) -{ - // R = A mod p - u64 temp = 19; - u32 other[WORDS]; - - for (auto i = 0; i < WORDS; i++) { - temp += data[i]; - other[i] = temp & 0xFFFFFFFF; - temp >>= 32; - } - - // Compute B = A - (2^255 - 19) - other[7] -= 0x80000000; - - u32 mask = (other[7] & 0x80000000) >> 31; - select(state, other, data, mask); -} - -static void modular_multiply_single(u32* state, u32* first, u32 second) -{ - // Compute R = (A * B) mod p - u64 temp = 0; - u32 output[WORDS]; - - for (auto i = 0; i < WORDS; i++) { - temp += (u64)first[i] * second; - output[i] = temp & 0xFFFFFFFF; - temp >>= 32; - } - - // Reduce bit 256 (2^256 = 38 mod p) - temp *= 38; - // Reduce bit 255 (2^255 = 19 mod p) - temp += (output[7] >> 31) * 19; - // Mask the most significant bit - output[7] &= 0x7FFFFFFF; - - // Fast modular reduction - for (auto i = 0; i < WORDS; i++) { - temp += output[i]; - output[i] = temp & 0xFFFFFFFF; - temp >>= 32; - } - - modular_reduce(state, output); -} - -static void modular_multiply(u32* state, u32* first, u32* second) -{ - // Compute R = (A * B) mod p - u64 temp = 0; - u64 carry = 0; - u32 output[WORDS * 2]; - - // Comba's method - for (auto i = 0; i < 16; i++) { - if (i < WORDS) { - for (auto j = 0; j <= i; j++) { - temp += (u64)first[j] * second[i - j]; - carry += temp >> 32; - temp &= 0xFFFFFFFF; - } - } else { - for (auto j = i - 7; j < WORDS; j++) { - temp += (u64)first[j] * second[i - j]; - carry += temp >> 32; - temp &= 0xFFFFFFFF; - } - } - - output[i] = temp & 0xFFFFFFFF; - temp = carry & 0xFFFFFFFF; - carry >>= 32; - } - - // Reduce bit 255 (2^255 = 19 mod p) - temp = (output[7] >> 31) * 19; - // Mask the most significant bit - output[7] &= 0x7FFFFFFF; - - // Fast modular reduction 1st pass - for (auto i = 0; i < WORDS; i++) { - temp += output[i]; - temp += (u64)output[i + 8] * 38; - output[i] = temp & 0xFFFFFFFF; - temp >>= 32; - } - - // Reduce bit 256 (2^256 = 38 mod p) - temp *= 38; - // Reduce bit 255 (2^255 = 19 mod p) - temp += (output[7] >> 31) * 19; - // Mask the most significant bit - output[7] &= 0x7FFFFFFF; - - // Fast modular reduction 2nd pass - for (auto i = 0; i < WORDS; i++) { - temp += output[i]; - output[i] = temp & 0xFFFFFFFF; - temp >>= 32; - } - - modular_reduce(state, output); -} - -static void modular_square(u32* state, u32* value) -{ - // Compute R = (A ^ 2) mod p - modular_multiply(state, value, value); -} - -static void modular_add(u32* state, u32* first, u32* second) -{ - // R = (A + B) mod p - u64 temp = 0; - for (auto i = 0; i < WORDS; i++) { - temp += first[i]; - temp += second[i]; - state[i] = temp & 0xFFFFFFFF; - temp >>= 32; - } - - modular_reduce(state, state); -} - -static void modular_subtract(u32* state, u32* first, u32* second) -{ - // R = (A - B) mod p - i64 temp = -19; - for (auto i = 0; i < WORDS; i++) { - temp += first[i]; - temp -= second[i]; - state[i] = temp & 0xFFFFFFFF; - temp >>= 32; - } - - // Compute R = A + (2^255 - 19) - B - state[7] += 0x80000000; - - modular_reduce(state, state); -} - -static void to_power_of_2n(u32* state, u32* value, u8 n) -{ - // compute R = (A ^ (2^n)) mod p - modular_square(state, value); - for (auto i = 1; i < n; i++) { - modular_square(state, state); - } -} - -static void modular_multiply_inverse(u32* state, u32* value) -{ - // Compute R = A^-1 mod p - u32 u[WORDS]; - u32 v[WORDS]; - - // Fermat's little theorem - modular_square(u, value); - modular_multiply(u, u, value); - modular_square(u, u); - modular_multiply(v, u, value); - to_power_of_2n(u, v, 3); - modular_multiply(u, u, v); - modular_square(u, u); - modular_multiply(v, u, value); - to_power_of_2n(u, v, 7); - modular_multiply(u, u, v); - modular_square(u, u); - modular_multiply(v, u, value); - to_power_of_2n(u, v, 15); - modular_multiply(u, u, v); - modular_square(u, u); - modular_multiply(v, u, value); - to_power_of_2n(u, v, 31); - modular_multiply(v, u, v); - to_power_of_2n(u, v, 62); - modular_multiply(u, u, v); - modular_square(u, u); - modular_multiply(v, u, value); - to_power_of_2n(u, v, 125); - modular_multiply(u, u, v); - modular_square(u, u); - modular_square(u, u); - modular_multiply(u, u, value); - modular_square(u, u); - modular_square(u, u); - modular_multiply(u, u, value); - modular_square(u, u); - modular_multiply(state, u, value); -} - ErrorOr<ByteBuffer> X25519::generate_private_key() { auto buffer = TRY(ByteBuffer::create_uninitialized(BYTES)); @@ -291,7 +53,7 @@ ErrorOr<ByteBuffer> X25519::compute_coordinate(ReadonlyBytes input_k, ReadonlyBy u32 t2[WORDS] {}; // Copy input to internal state - import_state(k, input_k); + Curve25519::import_state(k, input_k.data()); // Set the three least significant bits of the first byte and the most significant bit of the last to zero, // set the second most significant bit of the last byte to 1 @@ -300,18 +62,18 @@ ErrorOr<ByteBuffer> X25519::compute_coordinate(ReadonlyBytes input_k, ReadonlyBy k[7] |= 0x40000000; // Copy coordinate to internal state - import_state(u, input_u); + Curve25519::import_state(u, input_u.data()); // mask the most significant bit in the final byte. u[7] &= 0x7FFFFFFF; // Implementations MUST accept non-canonical values and process them as // if they had been reduced modulo the field prime. - modular_reduce(u, u); + Curve25519::modular_reduce(u, u); - set(x1, 1); - set(z1, 0); - copy(x2, u); - set(z2, 1); + Curve25519::set(x1, 1); + Curve25519::set(z1, 0); + Curve25519::copy(x2, u); + Curve25519::set(z2, 1); // Montgomery ladder u32 swap = 0; @@ -323,35 +85,38 @@ ErrorOr<ByteBuffer> X25519::compute_coordinate(ReadonlyBytes input_k, ReadonlyBy swap = b; - modular_add(t1, x2, z2); - modular_subtract(x2, x2, z2); - modular_add(z2, x1, z1); - modular_subtract(x1, x1, z1); - modular_multiply(t1, t1, x1); - modular_multiply(x2, x2, z2); - modular_square(z2, z2); - modular_square(x1, x1); - modular_subtract(t2, z2, x1); - modular_multiply_single(z1, t2, A24); - modular_add(z1, z1, x1); - modular_multiply(z1, z1, t2); - modular_multiply(x1, x1, z2); - modular_subtract(z2, t1, x2); - modular_square(z2, z2); - modular_multiply(z2, z2, u); - modular_add(x2, x2, t1); - modular_square(x2, x2); + Curve25519::modular_add(t1, x2, z2); + Curve25519::modular_subtract(x2, x2, z2); + Curve25519::modular_add(z2, x1, z1); + Curve25519::modular_subtract(x1, x1, z1); + Curve25519::modular_multiply(t1, t1, x1); + Curve25519::modular_multiply(x2, x2, z2); + Curve25519::modular_square(z2, z2); + Curve25519::modular_square(x1, x1); + Curve25519::modular_subtract(t2, z2, x1); + Curve25519::modular_multiply_single(z1, t2, A24); + Curve25519::modular_add(z1, z1, x1); + Curve25519::modular_multiply(z1, z1, t2); + Curve25519::modular_multiply(x1, x1, z2); + Curve25519::modular_subtract(z2, t1, x2); + Curve25519::modular_square(z2, z2); + Curve25519::modular_multiply(z2, z2, u); + Curve25519::modular_add(x2, x2, t1); + Curve25519::modular_square(x2, x2); } conditional_swap(x1, x2, swap); conditional_swap(z1, z2, swap); // Retrieve affine representation - modular_multiply_inverse(u, z1); - modular_multiply(u, u, x1); + Curve25519::modular_multiply_inverse(u, z1); + Curve25519::modular_multiply(u, u, x1); // Encode state for export - return export_state(u); + auto buffer = TRY(ByteBuffer::create_uninitialized(BYTES)); + Curve25519::export_state(u, buffer.data()); + + return buffer; } ErrorOr<ByteBuffer> X25519::derive_premaster_key(ReadonlyBytes shared_point) |