From e07ec024709796a3554512f1be2232b15b8e11e0 Mon Sep 17 00:00:00 2001 From: Michiel Visser Date: Fri, 18 Mar 2022 19:18:29 +0100 Subject: [PATCH] LibCrypto: Move all elliptic curve private methods into .cpp All the elliptic curve implementations had a long list of private methods which were all stored in a single .cpp file. Now we simply use static methods instead. --- .../Libraries/LibCrypto/Curves/SECP256r1.cpp | 34 ++-- .../Libraries/LibCrypto/Curves/SECP256r1.h | 23 --- .../Libraries/LibCrypto/Curves/X25519.cpp | 137 ++++++++-------- Userland/Libraries/LibCrypto/Curves/X25519.h | 24 +-- Userland/Libraries/LibCrypto/Curves/X448.cpp | 149 +++++++++--------- Userland/Libraries/LibCrypto/Curves/X448.h | 24 +-- 6 files changed, 171 insertions(+), 220 deletions(-) diff --git a/Userland/Libraries/LibCrypto/Curves/SECP256r1.cpp b/Userland/Libraries/LibCrypto/Curves/SECP256r1.cpp index 6a77dfb364..c937653f4c 100644 --- a/Userland/Libraries/LibCrypto/Curves/SECP256r1.cpp +++ b/Userland/Libraries/LibCrypto/Curves/SECP256r1.cpp @@ -14,6 +14,14 @@ namespace Crypto::Curves { +static constexpr u256 REDUCE_PRIME { u128 { 0x0000000000000001ull, 0xffffffff00000000ull }, u128 { 0xffffffffffffffffull, 0x00000000fffffffe } }; +static constexpr u256 REDUCE_ORDER { u128 { 0x0c46353d039cdaafull, 0x4319055258e8617bull }, u128 { 0x0000000000000000ull, 0x00000000ffffffff } }; +static constexpr u256 PRIME_INVERSE_MOD_R { u128 { 0x0000000000000001ull, 0x0000000100000000ull }, u128 { 0x0000000000000000ull, 0xffffffff00000002ull } }; +static constexpr u256 PRIME { u128 { 0xffffffffffffffffull, 0x00000000ffffffffull }, u128 { 0x0000000000000000ull, 0xffffffff00000001ull } }; +static constexpr u256 R2_MOD_PRIME { u128 { 0x0000000000000003ull, 0xfffffffbffffffffull }, u128 { 0xfffffffffffffffeull, 0x00000004fffffffdull } }; +static constexpr u256 ONE { 1u }; +static constexpr u256 B_MONTGOMERY { u128 { 0xd89cdf6229c4bddfull, 0xacf005cd78843090ull }, u128 { 0xe5a220abf7212ed6ull, 0xdc30061d04874834ull } }; + static u256 import_big_endian(ReadonlyBytes data) { VERIFY(data.size() == 32); @@ -53,7 +61,7 @@ static u512 multiply(u256 const& left, u256 const& right) return { result.low, result.high }; } -u256 SECP256r1::modular_reduce(u256 const& value) +static u256 modular_reduce(u256 const& value) { // Add -prime % 2^256 = 2^224-2^192-2^96+1 bool carry = false; @@ -63,7 +71,7 @@ u256 SECP256r1::modular_reduce(u256 const& value) return select(value, other, carry); } -u256 SECP256r1::modular_reduce_order(u256 const& value) +static u256 modular_reduce_order(u256 const& value) { // Add -order % 2^256 bool carry = false; @@ -73,7 +81,7 @@ u256 SECP256r1::modular_reduce_order(u256 const& value) return select(value, other, carry); } -u256 SECP256r1::modular_add(u256 const& left, u256 const& right, bool carry_in) +static u256 modular_add(u256 const& left, u256 const& right, bool carry_in = false) { bool carry = carry_in; u256 output = left.addc(right, carry); @@ -90,7 +98,7 @@ u256 SECP256r1::modular_add(u256 const& left, u256 const& right, bool carry_in) return output + addend; } -u256 SECP256r1::modular_sub(u256 const& left, u256 const& right) +static u256 modular_sub(u256 const& left, u256 const& right) { bool borrow = false; u256 output = left.subc(right, borrow); @@ -107,7 +115,7 @@ u256 SECP256r1::modular_sub(u256 const& left, u256 const& right) return output - sub; } -u256 SECP256r1::modular_multiply(u256 const& left, u256 const& right) +static u256 modular_multiply(u256 const& left, u256 const& right) { // Modular multiplication using the Montgomery method: https://en.wikipedia.org/wiki/Montgomery_modular_multiplication // This requires that the inputs to this function are in Montgomery form. @@ -129,22 +137,22 @@ u256 SECP256r1::modular_multiply(u256 const& left, u256 const& right) return modular_add(mult.high(), mp.high(), carry); } -u256 SECP256r1::modular_square(u256 const& value) +static u256 modular_square(u256 const& value) { return modular_multiply(value, value); } -u256 SECP256r1::to_montgomery(u256 const& value) +static u256 to_montgomery(u256 const& value) { return modular_multiply(value, R2_MOD_PRIME); } -u256 SECP256r1::from_montgomery(u256 const& value) +static u256 from_montgomery(u256 const& value) { return modular_multiply(value, ONE); } -u256 SECP256r1::modular_inverse(u256 const& value) +static u256 modular_inverse(u256 const& value) { // Modular inverse modulo the curve prime can be computed using Fermat's little theorem: a^(p-2) mod p = a^-1 mod p. // Calculating a^(p-2) mod p can be done using the square-and-multiply exponentiation method, as p-2 is constant. @@ -193,7 +201,7 @@ u256 SECP256r1::modular_inverse(u256 const& value) return result; } -void SECP256r1::point_double(JacobianPoint& output_point, JacobianPoint const& point) +static void point_double(JacobianPoint& output_point, JacobianPoint const& point) { // Based on "Point Doubling" from http://point-at-infinity.org/ecc/Prime_Curve_Jacobian_Coordinates.html @@ -247,7 +255,7 @@ void SECP256r1::point_double(JacobianPoint& output_point, JacobianPoint const& p output_point.z = zp; } -void SECP256r1::point_add(JacobianPoint& output_point, JacobianPoint const& point_a, JacobianPoint const& point_b) +static void point_add(JacobianPoint& output_point, JacobianPoint const& point_a, JacobianPoint const& point_b) { // Based on "Point Addition" from http://point-at-infinity.org/ecc/Prime_Curve_Jacobian_Coordinates.html if (point_a.x.is_zero_constant_time() && point_a.y.is_zero_constant_time() && point_a.z.is_zero_constant_time()) { @@ -314,7 +322,7 @@ void SECP256r1::point_add(JacobianPoint& output_point, JacobianPoint const& poin output_point.z = z3; } -void SECP256r1::convert_jacobian_to_affine(JacobianPoint& point) +static void convert_jacobian_to_affine(JacobianPoint& point) { u256 temp; // X' = X/Z^2 @@ -328,7 +336,7 @@ void SECP256r1::convert_jacobian_to_affine(JacobianPoint& point) point.y = modular_multiply(point.y, temp); } -bool SECP256r1::is_point_on_curve(JacobianPoint const& point) +static bool is_point_on_curve(JacobianPoint const& point) { // This check requires the point to be in Montgomery form, with Z=1 u256 temp, temp2; diff --git a/Userland/Libraries/LibCrypto/Curves/SECP256r1.h b/Userland/Libraries/LibCrypto/Curves/SECP256r1.h index aaaf722d57..a07b288aee 100644 --- a/Userland/Libraries/LibCrypto/Curves/SECP256r1.h +++ b/Userland/Libraries/LibCrypto/Curves/SECP256r1.h @@ -25,29 +25,6 @@ public: ErrorOr generate_public_key(ReadonlyBytes a) override; ErrorOr compute_coordinate(ReadonlyBytes scalar_bytes, ReadonlyBytes point_bytes) override; ErrorOr derive_premaster_key(ReadonlyBytes shared_point) override; - -private: - static u256 modular_reduce(u256 const& value); - static u256 modular_reduce_order(u256 const& value); - static u256 modular_add(u256 const& left, u256 const& right, bool carry_in = false); - static u256 modular_sub(u256 const& left, u256 const& right); - static u256 modular_multiply(u256 const& left, u256 const& right); - static u256 modular_square(u256 const& value); - static u256 to_montgomery(u256 const& value); - static u256 from_montgomery(u256 const& value); - static u256 modular_inverse(u256 const& value); - static void point_double(JacobianPoint& output_point, JacobianPoint const& point); - static void point_add(JacobianPoint& output_point, JacobianPoint const& point_a, JacobianPoint const& point_b); - static void convert_jacobian_to_affine(JacobianPoint& point); - static bool is_point_on_curve(JacobianPoint const& point); - - static constexpr u256 REDUCE_PRIME { u128 { 0x0000000000000001ull, 0xffffffff00000000ull }, u128 { 0xffffffffffffffffull, 0x00000000fffffffe } }; - static constexpr u256 REDUCE_ORDER { u128 { 0x0c46353d039cdaafull, 0x4319055258e8617bull }, u128 { 0x0000000000000000ull, 0x00000000ffffffff } }; - static constexpr u256 PRIME_INVERSE_MOD_R { u128 { 0x0000000000000001ull, 0x0000000100000000ull }, u128 { 0x0000000000000000ull, 0xffffffff00000002ull } }; - static constexpr u256 PRIME { u128 { 0xffffffffffffffffull, 0x00000000ffffffffull }, u128 { 0x0000000000000000ull, 0xffffffff00000001ull } }; - static constexpr u256 R2_MOD_PRIME { u128 { 0x0000000000000003ull, 0xfffffffbffffffffull }, u128 { 0xfffffffffffffffeull, 0x00000004fffffffdull } }; - static constexpr u256 ONE { 1u }; - static constexpr u256 B_MONTGOMERY { u128 { 0xd89cdf6229c4bddfull, 0xacf005cd78843090ull }, u128 { 0xe5a220abf7212ed6ull, 0xdc30061d04874834ull } }; }; } diff --git a/Userland/Libraries/LibCrypto/Curves/X25519.cpp b/Userland/Libraries/LibCrypto/Curves/X25519.cpp index f4c0374dfd..faa98f4e8b 100644 --- a/Userland/Libraries/LibCrypto/Curves/X25519.cpp +++ b/Userland/Libraries/LibCrypto/Curves/X25519.cpp @@ -11,19 +11,24 @@ namespace Crypto::Curves { -void X25519::import_state(u32* state, ReadonlyBytes data) +static constexpr u8 BITS = 255; +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 < X25519::WORDS; i++) { + 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); } } -ErrorOr X25519::export_state(u32* data) +static ErrorOr export_state(u32* data) { - auto buffer = TRY(ByteBuffer::create_uninitialized(X25519::BYTES)); + auto buffer = TRY(ByteBuffer::create_uninitialized(BYTES)); - for (auto i = 0; i < X25519::WORDS; i++) { + 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); } @@ -31,49 +36,68 @@ ErrorOr X25519::export_state(u32* data) return buffer; } -void X25519::select(u32* state, u32* a, u32* b, u32 condition) +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 < X25519::WORDS; i++) { + for (auto i = 0; i < WORDS; i++) { state[i] = (a[i] & mask) | (b[i] & ~mask); } } -void X25519::set(u32* state, u32 value) +static void set(u32* state, u32 value) { state[0] = value; - for (auto i = 1; i < X25519::WORDS; i++) { + for (auto i = 1; i < WORDS; i++) { state[i] = 0; } } -void X25519::copy(u32* state, u32* value) +static void copy(u32* state, u32* value) { - for (auto i = 0; i < X25519::WORDS; i++) { + for (auto i = 0; i < WORDS; i++) { state[i] = value[i]; } } -void X25519::conditional_swap(u32* first, u32* second, u32 condition) +static void conditional_swap(u32* first, u32* second, u32 condition) { u32 mask = ~condition + 1; - for (auto i = 0; i < X25519::WORDS; i++) { + for (auto i = 0; i < WORDS; i++) { u32 temp = mask & (first[i] ^ second[i]); first[i] ^= temp; second[i] ^= temp; } } -void X25519::modular_multiply_single(u32* state, u32* first, u32 second) +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[X25519::WORDS]; + u32 output[WORDS]; - for (auto i = 0; i < X25519::WORDS; i++) { + for (auto i = 0; i < WORDS; i++) { temp += (u64)first[i] * second; output[i] = temp & 0xFFFFFFFF; temp >>= 32; @@ -87,7 +111,7 @@ void X25519::modular_multiply_single(u32* state, u32* first, u32 second) output[7] &= 0x7FFFFFFF; // Fast modular reduction - for (auto i = 0; i < X25519::WORDS; i++) { + for (auto i = 0; i < WORDS; i++) { temp += output[i]; output[i] = temp & 0xFFFFFFFF; temp >>= 32; @@ -96,29 +120,23 @@ void X25519::modular_multiply_single(u32* state, u32* first, u32 second) modular_reduce(state, output); } -void X25519::modular_square(u32* state, u32* value) -{ - // Compute R = (A ^ 2) mod p - modular_multiply(state, value, value); -} - -void X25519::modular_multiply(u32* state, u32* first, u32* second) +static void modular_multiply(u32* state, u32* first, u32* second) { // Compute R = (A * B) mod p u64 temp = 0; u64 carry = 0; - u32 output[X25519::WORDS * 2]; + u32 output[WORDS * 2]; // Comba's method for (auto i = 0; i < 16; i++) { - if (i < X25519::WORDS) { + 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 < X25519::WORDS; j++) { + for (auto j = i - 7; j < WORDS; j++) { temp += (u64)first[j] * second[i - j]; carry += temp >> 32; temp &= 0xFFFFFFFF; @@ -136,7 +154,7 @@ void X25519::modular_multiply(u32* state, u32* first, u32* second) output[7] &= 0x7FFFFFFF; // Fast modular reduction 1st pass - for (auto i = 0; i < X25519::WORDS; i++) { + for (auto i = 0; i < WORDS; i++) { temp += output[i]; temp += (u64)output[i + 8] * 38; output[i] = temp & 0xFFFFFFFF; @@ -151,7 +169,7 @@ void X25519::modular_multiply(u32* state, u32* first, u32* second) output[7] &= 0x7FFFFFFF; // Fast modular reduction 2nd pass - for (auto i = 0; i < X25519::WORDS; i++) { + for (auto i = 0; i < WORDS; i++) { temp += output[i]; output[i] = temp & 0xFFFFFFFF; temp >>= 32; @@ -160,11 +178,17 @@ void X25519::modular_multiply(u32* state, u32* first, u32* second) modular_reduce(state, output); } -void X25519::modular_add(u32* state, u32* first, u32* second) +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 < X25519::WORDS; i++) { + for (auto i = 0; i < WORDS; i++) { temp += first[i]; temp += second[i]; state[i] = temp & 0xFFFFFFFF; @@ -174,11 +198,11 @@ void X25519::modular_add(u32* state, u32* first, u32* second) modular_reduce(state, state); } -void X25519::modular_subtract(u32* state, u32* first, u32* second) +static void modular_subtract(u32* state, u32* first, u32* second) { // R = (A - B) mod p i64 temp = -19; - for (auto i = 0; i < X25519::WORDS; i++) { + for (auto i = 0; i < WORDS; i++) { temp += first[i]; temp -= second[i]; state[i] = temp & 0xFFFFFFFF; @@ -191,26 +215,7 @@ void X25519::modular_subtract(u32* state, u32* first, u32* second) modular_reduce(state, state); } -void X25519::modular_reduce(u32* state, u32* data) -{ - // R = A mod p - u64 temp = 19; - u32 other[X25519::WORDS]; - - for (auto i = 0; i < X25519::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 X25519::to_power_of_2n(u32* state, u32* value, u8 n) +static void to_power_of_2n(u32* state, u32* value, u8 n) { // compute R = (A ^ (2^n)) mod p modular_square(state, value); @@ -219,11 +224,11 @@ void X25519::to_power_of_2n(u32* state, u32* value, u8 n) } } -void X25519::modular_multiply_inverse(u32* state, u32* value) +static void modular_multiply_inverse(u32* state, u32* value) { // Compute R = A^-1 mod p - u32 u[X25519::WORDS]; - u32 v[X25519::WORDS]; + u32 u[WORDS]; + u32 v[WORDS]; // Fermat's little theorem modular_square(u, value); @@ -276,14 +281,14 @@ ErrorOr X25519::generate_public_key(ReadonlyBytes a) // https://datatracker.ietf.org/doc/html/rfc7748#section-5 ErrorOr X25519::compute_coordinate(ReadonlyBytes input_k, ReadonlyBytes input_u) { - u32 k[X25519::WORDS] {}; - u32 u[X25519::WORDS] {}; - u32 x1[X25519::WORDS] {}; - u32 x2[X25519::WORDS] {}; - u32 z1[X25519::WORDS] {}; - u32 z2[X25519::WORDS] {}; - u32 t1[X25519::WORDS] {}; - u32 t2[X25519::WORDS] {}; + u32 k[WORDS] {}; + u32 u[WORDS] {}; + u32 x1[WORDS] {}; + u32 x2[WORDS] {}; + u32 z1[WORDS] {}; + u32 z2[WORDS] {}; + u32 t1[WORDS] {}; + u32 t2[WORDS] {}; // Copy input to internal state import_state(k, input_k); @@ -310,8 +315,8 @@ ErrorOr X25519::compute_coordinate(ReadonlyBytes input_k, ReadonlyBy // Montgomery ladder u32 swap = 0; - for (auto i = X25519::BITS - 1; i >= 0; i--) { - u32 b = (k[i / X25519::BYTES] >> (i % X25519::BYTES)) & 1; + for (auto i = BITS - 1; i >= 0; i--) { + u32 b = (k[i / BYTES] >> (i % BYTES)) & 1; conditional_swap(x1, x2, swap ^ b); conditional_swap(z1, z2, swap ^ b); diff --git a/Userland/Libraries/LibCrypto/Curves/X25519.h b/Userland/Libraries/LibCrypto/Curves/X25519.h index 1950f48531..93609beb25 100644 --- a/Userland/Libraries/LibCrypto/Curves/X25519.h +++ b/Userland/Libraries/LibCrypto/Curves/X25519.h @@ -12,34 +12,12 @@ namespace Crypto::Curves { class X25519 : public EllipticCurve { - - static constexpr u8 BITS = 255; - static constexpr u8 BYTES = 32; - static constexpr u8 WORDS = 8; - static constexpr u32 A24 = 121666; - public: - size_t key_size() override { return BYTES; } + size_t key_size() override { return 32; } ErrorOr generate_private_key() override; ErrorOr generate_public_key(ReadonlyBytes a) override; ErrorOr compute_coordinate(ReadonlyBytes a, ReadonlyBytes b) override; ErrorOr derive_premaster_key(ReadonlyBytes shared_point) override; - -private: - static void import_state(u32* state, ReadonlyBytes data); - static ErrorOr export_state(u32* data); - static void select(u32* state, u32* a, u32* b, u32 condition); - static void set(u32* state, u32 value); - static void copy(u32* state, u32* value); - static void conditional_swap(u32* first, u32* second, u32 condition); - static void modular_multiply_single(u32* state, u32* first, u32 second); - static void modular_square(u32* state, u32* value); - static void modular_multiply(u32* state, u32* first, u32* second); - static void modular_add(u32* state, u32* first, u32* second); - static void modular_subtract(u32* state, u32* first, u32* second); - static void modular_reduce(u32* state, u32* data); - static void to_power_of_2n(u32* state, u32* value, u8 n); - static void modular_multiply_inverse(u32* state, u32* value); }; } diff --git a/Userland/Libraries/LibCrypto/Curves/X448.cpp b/Userland/Libraries/LibCrypto/Curves/X448.cpp index d648ab6463..6410a2d780 100644 --- a/Userland/Libraries/LibCrypto/Curves/X448.cpp +++ b/Userland/Libraries/LibCrypto/Curves/X448.cpp @@ -11,19 +11,24 @@ namespace Crypto::Curves { -void X448::import_state(u32* state, ReadonlyBytes data) +static constexpr u16 BITS = 448; +static constexpr u8 BYTES = 56; +static constexpr u8 WORDS = 14; +static constexpr u32 A24 = 39082; + +static void import_state(u32* state, ReadonlyBytes data) { - for (auto i = 0; i < X448::WORDS; i++) { + 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); } } -ErrorOr X448::export_state(u32* data) +static ErrorOr export_state(u32* data) { - auto buffer = TRY(ByteBuffer::create_uninitialized(X448::BYTES)); + auto buffer = TRY(ByteBuffer::create_uninitialized(BYTES)); - for (auto i = 0; i < X448::WORDS; i++) { + 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); } @@ -31,50 +36,74 @@ ErrorOr X448::export_state(u32* data) return buffer; } -void X448::select(u32* state, u32* a, u32* b, u32 condition) +static void select(u32* state, u32* a, u32* b, u32 condition) { // If B < (2^448 - 2^224 + 1) then R = B, else R = A u32 mask = condition - 1; - for (auto i = 0; i < X448::WORDS; i++) { + for (auto i = 0; i < WORDS; i++) { state[i] = (a[i] & mask) | (b[i] & ~mask); } } -void X448::set(u32* state, u32 value) +static void set(u32* state, u32 value) { state[0] = value; - for (auto i = 1; i < X448::WORDS; i++) { + for (auto i = 1; i < WORDS; i++) { state[i] = 0; } } -void X448::copy(u32* state, u32* value) +static void copy(u32* state, u32* value) { - for (auto i = 0; i < X448::WORDS; i++) { + for (auto i = 0; i < WORDS; i++) { state[i] = value[i]; } } -void X448::conditional_swap(u32* first, u32* second, u32 condition) +static void conditional_swap(u32* first, u32* second, u32 condition) { u32 mask = ~condition + 1; - for (auto i = 0; i < X448::WORDS; i++) { + for (auto i = 0; i < WORDS; i++) { u32 temp = mask & (first[i] ^ second[i]); first[i] ^= temp; second[i] ^= temp; } } -void X448::modular_multiply_single(u32* state, u32* first, u32 second) +static void modular_reduce(u32* state, u32* data, u32 a_high) +{ + u64 temp = 1; + u32 other[WORDS]; + + // Compute B = A - (2^448 - 2^224 - 1) + for (auto i = 0; i < WORDS / 2; i++) { + temp += data[i]; + other[i] = temp & 0xFFFFFFFF; + temp >>= 32; + } + + temp += 1; + + for (auto i = 7; i < WORDS; i++) { + temp += data[i]; + other[i] = temp & 0xFFFFFFFF; + temp >>= 32; + } + + auto condition = (a_high + (u32)temp - 1) & 1; + select(state, other, data, condition); +} + +static void modular_multiply_single(u32* state, u32* first, u32 second) { // Compute R = (A * B) mod p u64 temp = 0; u64 carry = 0; - u32 output[X448::WORDS]; + u32 output[WORDS]; - for (auto i = 0; i < X448::WORDS; i++) { + for (auto i = 0; i < WORDS; i++) { temp += (u64)first[i] * second; output[i] = temp & 0xFFFFFFFF; temp >>= 32; @@ -82,14 +111,14 @@ void X448::modular_multiply_single(u32* state, u32* first, u32 second) // Fast modular reduction carry = temp; - for (auto i = 0; i < X448::WORDS / 2; i++) { + for (auto i = 0; i < WORDS / 2; i++) { temp += output[i]; output[i] = temp & 0xFFFFFFFF; temp >>= 32; } temp += carry; - for (auto i = X448::WORDS / 2; i < X448::WORDS; i++) { + for (auto i = WORDS / 2; i < WORDS; i++) { temp += output[i]; output[i] = temp & 0xFFFFFFFF; temp >>= 32; @@ -98,22 +127,16 @@ void X448::modular_multiply_single(u32* state, u32* first, u32 second) modular_reduce(state, output, (u32)temp); } -void X448::modular_square(u32* state, u32* value) -{ - // Compute R = (A ^ 2) mod p - modular_multiply(state, value, value); -} - -void X448::modular_multiply(u32* state, u32* first, u32* second) +static void modular_multiply(u32* state, u32* first, u32* second) { // Compute R = (A * B) mod p u64 temp = 0; u64 carry = 0; - u32 output[X448::WORDS * 2]; + u32 output[WORDS * 2]; // Comba's method - for (auto i = 0; i < X448::WORDS * 2; i++) { + for (auto i = 0; i < WORDS * 2; i++) { if (i < 14) { for (auto j = 0; j <= i; j++) { temp += (u64)first[j] * second[i - j]; @@ -121,7 +144,7 @@ void X448::modular_multiply(u32* state, u32* first, u32* second) temp &= 0xFFFFFFFF; } } else { - for (auto j = i - 13; j < X448::WORDS; j++) { + for (auto j = i - 13; j < WORDS; j++) { temp += (u64)first[j] * second[i - j]; carry += temp >> 32; temp &= 0xFFFFFFFF; @@ -135,7 +158,7 @@ void X448::modular_multiply(u32* state, u32* first, u32* second) // Fast modular reduction (first pass) temp = 0; - for (auto i = 0; i < X448::WORDS / 2; i++) { + for (auto i = 0; i < WORDS / 2; i++) { temp += output[i]; temp += output[i + 14]; temp += output[i + 21]; @@ -143,7 +166,7 @@ void X448::modular_multiply(u32* state, u32* first, u32* second) temp >>= 32; } - for (auto i = X448::WORDS / 2; i < X448::WORDS; i++) { + for (auto i = WORDS / 2; i < WORDS; i++) { temp += output[i]; temp += output[i + 7]; temp += output[i + 14]; @@ -154,14 +177,14 @@ void X448::modular_multiply(u32* state, u32* first, u32* second) // Fast modular reduction (second pass) carry = temp; - for (auto i = 0; i < X448::WORDS / 2; i++) { + for (auto i = 0; i < WORDS / 2; i++) { temp += output[i]; output[i] = temp & 0xFFFFFFFF; temp >>= 32; } temp += carry; - for (auto i = X448::WORDS / 2; i < X448::WORDS; i++) { + for (auto i = WORDS / 2; i < WORDS; i++) { temp += output[i]; output[i] = temp & 0xFFFFFFFF; temp >>= 32; @@ -170,12 +193,18 @@ void X448::modular_multiply(u32* state, u32* first, u32* second) modular_reduce(state, output, (u32)temp); } -void X448::modular_add(u32* state, u32* first, u32* second) +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) { u64 temp = 0; // Compute R = A + B - for (auto i = 0; i < X448::WORDS; i++) { + for (auto i = 0; i < WORDS; i++) { temp += first[i]; temp += second[i]; state[i] = temp & 0xFFFFFFFF; @@ -185,7 +214,7 @@ void X448::modular_add(u32* state, u32* first, u32* second) modular_reduce(state, state, (u32)temp); } -void X448::modular_subtract(u32* state, u32* first, u32* second) +static void modular_subtract(u32* state, u32* first, u32* second) { i64 temp = -1; @@ -211,31 +240,7 @@ void X448::modular_subtract(u32* state, u32* first, u32* second) modular_reduce(state, state, (u32)temp); } -void X448::modular_reduce(u32* state, u32* data, u32 a_high) -{ - u64 temp = 1; - u32 other[X448::WORDS]; - - // Compute B = A - (2^448 - 2^224 - 1) - for (auto i = 0; i < X448::WORDS / 2; i++) { - temp += data[i]; - other[i] = temp & 0xFFFFFFFF; - temp >>= 32; - } - - temp += 1; - - for (auto i = 7; i < X448::WORDS; i++) { - temp += data[i]; - other[i] = temp & 0xFFFFFFFF; - temp >>= 32; - } - - auto condition = (a_high + (u32)temp - 1) & 1; - select(state, other, data, condition); -} - -void X448::to_power_of_2n(u32* state, u32* value, u8 n) +static void to_power_of_2n(u32* state, u32* value, u8 n) { // Compute R = (A ^ (2^n)) mod p modular_square(state, value); @@ -244,11 +249,11 @@ void X448::to_power_of_2n(u32* state, u32* value, u8 n) } } -void X448::modular_multiply_inverse(u32* state, u32* value) +static void modular_multiply_inverse(u32* state, u32* value) { // Compute R = A^-1 mod p - u32 u[X448::WORDS]; - u32 v[X448::WORDS]; + u32 u[WORDS]; + u32 v[WORDS]; modular_square(u, value); modular_multiply(u, u, value); @@ -299,14 +304,14 @@ ErrorOr X448::generate_public_key(ReadonlyBytes a) // https://datatracker.ietf.org/doc/html/rfc7748#section-5 ErrorOr X448::compute_coordinate(ReadonlyBytes input_k, ReadonlyBytes input_u) { - u32 k[X448::WORDS] {}; - u32 u[X448::WORDS] {}; - u32 x1[X448::WORDS] {}; - u32 x2[X448::WORDS] {}; - u32 z1[X448::WORDS] {}; - u32 z2[X448::WORDS] {}; - u32 t1[X448::WORDS] {}; - u32 t2[X448::WORDS] {}; + u32 k[WORDS] {}; + u32 u[WORDS] {}; + u32 x1[WORDS] {}; + u32 x2[WORDS] {}; + u32 z1[WORDS] {}; + u32 z2[WORDS] {}; + u32 t1[WORDS] {}; + u32 t2[WORDS] {}; // Copy input to internal state import_state(k, input_k); @@ -329,7 +334,7 @@ ErrorOr X448::compute_coordinate(ReadonlyBytes input_k, ReadonlyByte // Montgomery ladder u32 swap = 0; - for (auto i = X448::BITS - 1; i >= 0; i--) { + for (auto i = BITS - 1; i >= 0; i--) { u32 b = (k[i / 32] >> (i % 32)) & 1; conditional_swap(x1, x2, swap ^ b); diff --git a/Userland/Libraries/LibCrypto/Curves/X448.h b/Userland/Libraries/LibCrypto/Curves/X448.h index f6d18a5cc4..bd613e5251 100644 --- a/Userland/Libraries/LibCrypto/Curves/X448.h +++ b/Userland/Libraries/LibCrypto/Curves/X448.h @@ -12,34 +12,12 @@ namespace Crypto::Curves { class X448 : public EllipticCurve { - - static constexpr u16 BITS = 448; - static constexpr u8 BYTES = 56; - static constexpr u8 WORDS = 14; - static constexpr u32 A24 = 39082; - public: - size_t key_size() override { return BYTES; } + size_t key_size() override { return 56; } ErrorOr generate_private_key() override; ErrorOr generate_public_key(ReadonlyBytes a) override; ErrorOr compute_coordinate(ReadonlyBytes a, ReadonlyBytes b) override; ErrorOr derive_premaster_key(ReadonlyBytes shared_point) override; - -private: - static void import_state(u32* state, ReadonlyBytes data); - static ErrorOr export_state(u32* data); - static void select(u32* state, u32* a, u32* b, u32 condition); - static void set(u32* state, u32 value); - static void copy(u32* state, u32* value); - static void conditional_swap(u32* first, u32* second, u32 condition); - static void modular_multiply_single(u32* state, u32* first, u32 second); - static void modular_square(u32* state, u32* value); - static void modular_multiply(u32* state, u32* first, u32* second); - static void modular_add(u32* state, u32* first, u32* second); - static void modular_subtract(u32* state, u32* first, u32* second); - static void modular_reduce(u32* state, u32* data, u32 data_high); - static void to_power_of_2n(u32* state, u32* value, u8 n); - static void modular_multiply_inverse(u32* state, u32* value); }; }