/src/serenity/Userland/Libraries/LibCrypto/Curves/SECPxxxr1.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2023, Michiel Visser <opensource@webmichiel.nl> |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #pragma once |
8 | | |
9 | | #include <AK/ByteBuffer.h> |
10 | | #include <AK/Endian.h> |
11 | | #include <AK/MemoryStream.h> |
12 | | #include <AK/Random.h> |
13 | | #include <AK/StdLibExtras.h> |
14 | | #include <AK/StringView.h> |
15 | | #include <AK/UFixedBigInt.h> |
16 | | #include <AK/UFixedBigIntDivision.h> |
17 | | #include <LibCrypto/ASN1/DER.h> |
18 | | #include <LibCrypto/Curves/EllipticCurve.h> |
19 | | |
20 | | namespace Crypto::Curves { |
21 | | |
22 | | struct SECPxxxr1CurveParameters { |
23 | | StringView prime; |
24 | | StringView a; |
25 | | StringView b; |
26 | | StringView order; |
27 | | StringView generator_point; |
28 | | }; |
29 | | |
30 | | template<size_t bit_size, SECPxxxr1CurveParameters const& CURVE_PARAMETERS> |
31 | | class SECPxxxr1 : public EllipticCurve { |
32 | | private: |
33 | | using StorageType = AK::UFixedBigInt<bit_size>; |
34 | | using StorageTypeX2 = AK::UFixedBigInt<bit_size * 2>; |
35 | | |
36 | | struct JacobianPoint { |
37 | | StorageType x; |
38 | | StorageType y; |
39 | | StorageType z; |
40 | | }; |
41 | | |
42 | | // Curve parameters |
43 | | static constexpr size_t KEY_BIT_SIZE = bit_size; |
44 | | static constexpr size_t KEY_BYTE_SIZE = KEY_BIT_SIZE / 8; |
45 | | static constexpr size_t POINT_BYTE_SIZE = 1 + 2 * KEY_BYTE_SIZE; |
46 | | |
47 | | static constexpr StorageType make_unsigned_fixed_big_int_from_string(StringView str) |
48 | 0 | { |
49 | 0 | StorageType result { 0 }; |
50 | 0 | for (auto c : str) { |
51 | 0 | if (c == '_') |
52 | 0 | continue; |
53 | 0 |
|
54 | 0 | result <<= 4; |
55 | 0 | result |= parse_ascii_hex_digit(c); |
56 | 0 | } |
57 | 0 | return result; |
58 | 0 | } Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::make_unsigned_fixed_big_int_from_string(AK::StringView) Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::make_unsigned_fixed_big_int_from_string(AK::StringView) |
59 | | |
60 | | static constexpr StorageType PRIME = make_unsigned_fixed_big_int_from_string(CURVE_PARAMETERS.prime); |
61 | | static constexpr StorageType A = make_unsigned_fixed_big_int_from_string(CURVE_PARAMETERS.a); |
62 | | static constexpr StorageType B = make_unsigned_fixed_big_int_from_string(CURVE_PARAMETERS.b); |
63 | | static constexpr StorageType ORDER = make_unsigned_fixed_big_int_from_string(CURVE_PARAMETERS.order); |
64 | | |
65 | | static constexpr Array<u8, POINT_BYTE_SIZE> make_generator_point_bytes(StringView generator_point) |
66 | 0 | { |
67 | 0 | Array<u8, POINT_BYTE_SIZE> buf_array { 0 }; |
68 | 0 |
|
69 | 0 | auto it = generator_point.begin(); |
70 | 0 | for (size_t i = 0; i < POINT_BYTE_SIZE; i++) { |
71 | 0 | if (it == CURVE_PARAMETERS.generator_point.end()) |
72 | 0 | break; |
73 | 0 |
|
74 | 0 | while (*it == '_') { |
75 | 0 | it++; |
76 | 0 | } |
77 | 0 |
|
78 | 0 | buf_array[i] = parse_ascii_hex_digit(*it) * 16; |
79 | 0 | it++; |
80 | 0 | if (it == CURVE_PARAMETERS.generator_point.end()) |
81 | 0 | break; |
82 | 0 |
|
83 | 0 | buf_array[i] += parse_ascii_hex_digit(*it); |
84 | 0 | it++; |
85 | 0 | } |
86 | 0 |
|
87 | 0 | return buf_array; |
88 | 0 | } Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::make_generator_point_bytes(AK::StringView) Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::make_generator_point_bytes(AK::StringView) |
89 | | |
90 | | static constexpr Array<u8, POINT_BYTE_SIZE> GENERATOR_POINT = make_generator_point_bytes(CURVE_PARAMETERS.generator_point); |
91 | | |
92 | | // Check that the generator point starts with 0x04 |
93 | | static_assert(GENERATOR_POINT[0] == 0x04); |
94 | | |
95 | | static constexpr StorageType calculate_modular_inverse_mod_r(StorageType value) |
96 | 0 | { |
97 | 0 | // Calculate the modular multiplicative inverse of value mod 2^bit_size using the extended euclidean algorithm |
98 | 0 | using StorageTypeP1 = AK::UFixedBigInt<bit_size + 1>; |
99 | 0 |
|
100 | 0 | StorageTypeP1 old_r = value; |
101 | 0 | StorageTypeP1 r = static_cast<StorageTypeP1>(1u) << KEY_BIT_SIZE; |
102 | 0 | StorageTypeP1 old_s = 1u; |
103 | 0 | StorageTypeP1 s = 0u; |
104 | 0 |
|
105 | 0 | while (!r.is_zero_constant_time()) { |
106 | 0 | StorageTypeP1 r_save = r; |
107 | 0 | StorageTypeP1 quotient = old_r.div_mod(r, r); |
108 | 0 | old_r = r_save; |
109 | 0 |
|
110 | 0 | StorageTypeP1 s_save = s; |
111 | 0 | s = old_s - quotient * s; |
112 | 0 | old_s = s_save; |
113 | 0 | } |
114 | 0 |
|
115 | 0 | return static_cast<StorageType>(old_s); |
116 | 0 | } Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::calculate_modular_inverse_mod_r(AK::Detail::UFixedBigInt<256ul, AK::Detail::StaticStorage<false, 256ul> >) Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::calculate_modular_inverse_mod_r(AK::Detail::UFixedBigInt<384ul, AK::Detail::StaticStorage<false, 384ul> >) |
117 | | |
118 | | static constexpr StorageType calculate_r2_mod(StorageType modulus) |
119 | 0 | { |
120 | 0 | // Calculate the value of R^2 mod modulus, where R = 2^bit_size |
121 | 0 | using StorageTypeX2P1 = AK::UFixedBigInt<bit_size * 2 + 1>; |
122 | 0 |
|
123 | 0 | StorageTypeX2P1 r2 = static_cast<StorageTypeX2P1>(1u) << (2 * KEY_BIT_SIZE); |
124 | 0 | return r2 % modulus; |
125 | 0 | } Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::calculate_r2_mod(AK::Detail::UFixedBigInt<256ul, AK::Detail::StaticStorage<false, 256ul> >) Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::calculate_r2_mod(AK::Detail::UFixedBigInt<384ul, AK::Detail::StaticStorage<false, 384ul> >) |
126 | | |
127 | | // Verify that A = -3 mod p, which is required for some optimizations |
128 | | static_assert(A == PRIME - 3); |
129 | | |
130 | | // Precomputed helper values for reduction and Montgomery multiplication |
131 | | static constexpr StorageType REDUCE_PRIME = StorageType { 0 } - PRIME; |
132 | | static constexpr StorageType REDUCE_ORDER = StorageType { 0 } - ORDER; |
133 | | static constexpr StorageType PRIME_INVERSE_MOD_R = StorageType { 0 } - calculate_modular_inverse_mod_r(PRIME); |
134 | | static constexpr StorageType ORDER_INVERSE_MOD_R = StorageType { 0 } - calculate_modular_inverse_mod_r(ORDER); |
135 | | static constexpr StorageType R2_MOD_PRIME = calculate_r2_mod(PRIME); |
136 | | static constexpr StorageType R2_MOD_ORDER = calculate_r2_mod(ORDER); |
137 | | |
138 | | public: |
139 | 0 | size_t key_size() override { return POINT_BYTE_SIZE; } Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::key_size() Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::key_size() |
140 | | |
141 | | ErrorOr<ByteBuffer> generate_private_key() override |
142 | 0 | { |
143 | 0 | auto buffer = TRY(ByteBuffer::create_uninitialized(KEY_BYTE_SIZE)); |
144 | 0 | fill_with_random(buffer); |
145 | 0 | return buffer; |
146 | 0 | } Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::generate_private_key() Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::generate_private_key() |
147 | | |
148 | | ErrorOr<ByteBuffer> generate_public_key(ReadonlyBytes a) override |
149 | 0 | { |
150 | 0 | return compute_coordinate(a, GENERATOR_POINT); |
151 | 0 | } Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::generate_public_key(AK::Span<unsigned char const>) Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::generate_public_key(AK::Span<unsigned char const>) |
152 | | |
153 | | ErrorOr<ByteBuffer> compute_coordinate(ReadonlyBytes scalar_bytes, ReadonlyBytes point_bytes) override |
154 | 0 | { |
155 | 0 | AK::FixedMemoryStream scalar_stream { scalar_bytes }; |
156 | 0 | AK::FixedMemoryStream point_stream { point_bytes }; |
157 | |
|
158 | 0 | StorageType scalar = TRY(scalar_stream.read_value<BigEndian<StorageType>>()); |
159 | 0 | JacobianPoint point = TRY(read_uncompressed_point(point_stream)); |
160 | 0 | JacobianPoint result = TRY(compute_coordinate_internal(scalar, point)); |
161 | | |
162 | | // Export the values into an output buffer |
163 | 0 | auto buf = TRY(ByteBuffer::create_uninitialized(POINT_BYTE_SIZE)); |
164 | 0 | AK::FixedMemoryStream buf_stream { buf.bytes() }; |
165 | 0 | TRY(buf_stream.write_value<u8>(0x04)); |
166 | 0 | TRY(buf_stream.write_value<BigEndian<StorageType>>(result.x)); |
167 | 0 | TRY(buf_stream.write_value<BigEndian<StorageType>>(result.y)); |
168 | 0 | return buf; |
169 | 0 | } Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::compute_coordinate(AK::Span<unsigned char const>, AK::Span<unsigned char const>) Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::compute_coordinate(AK::Span<unsigned char const>, AK::Span<unsigned char const>) |
170 | | |
171 | | ErrorOr<ByteBuffer> derive_premaster_key(ReadonlyBytes shared_point) override |
172 | 0 | { |
173 | 0 | VERIFY(shared_point.size() == POINT_BYTE_SIZE); |
174 | 0 | VERIFY(shared_point[0] == 0x04); |
175 | | |
176 | 0 | ByteBuffer premaster_key = TRY(ByteBuffer::create_uninitialized(KEY_BYTE_SIZE)); |
177 | 0 | premaster_key.overwrite(0, shared_point.data() + 1, KEY_BYTE_SIZE); |
178 | 0 | return premaster_key; |
179 | 0 | } Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::derive_premaster_key(AK::Span<unsigned char const>) Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::derive_premaster_key(AK::Span<unsigned char const>) |
180 | | |
181 | | ErrorOr<bool> verify(ReadonlyBytes hash, ReadonlyBytes pubkey, ReadonlyBytes signature) |
182 | 0 | { |
183 | 0 | Crypto::ASN1::Decoder asn1_decoder(signature); |
184 | 0 | TRY(asn1_decoder.enter()); |
185 | | |
186 | 0 | auto r_bigint = TRY(asn1_decoder.read<Crypto::UnsignedBigInteger>(Crypto::ASN1::Class::Universal, Crypto::ASN1::Kind::Integer)); |
187 | 0 | auto s_bigint = TRY(asn1_decoder.read<Crypto::UnsignedBigInteger>(Crypto::ASN1::Class::Universal, Crypto::ASN1::Kind::Integer)); |
188 | | |
189 | 0 | size_t expected_word_count = KEY_BIT_SIZE / 32; |
190 | 0 | if (r_bigint.length() < expected_word_count || s_bigint.length() < expected_word_count) { |
191 | 0 | return false; |
192 | 0 | } |
193 | | |
194 | 0 | StorageType r = 0u; |
195 | 0 | StorageType s = 0u; |
196 | 0 | for (size_t i = 0; i < (KEY_BIT_SIZE / 32); i++) { |
197 | 0 | StorageType rr = r_bigint.words()[i]; |
198 | 0 | StorageType ss = s_bigint.words()[i]; |
199 | 0 | r |= (rr << (i * 32)); |
200 | 0 | s |= (ss << (i * 32)); |
201 | 0 | } |
202 | | |
203 | | // z is the hash |
204 | 0 | StorageType z = 0u; |
205 | 0 | for (uint8_t byte : hash) { |
206 | 0 | z <<= 8; |
207 | 0 | z |= byte; |
208 | 0 | } |
209 | |
|
210 | 0 | AK::FixedMemoryStream pubkey_stream { pubkey }; |
211 | 0 | JacobianPoint pubkey_point = TRY(read_uncompressed_point(pubkey_stream)); |
212 | | |
213 | 0 | StorageType r_mo = to_montgomery_order(r); |
214 | 0 | StorageType s_mo = to_montgomery_order(s); |
215 | 0 | StorageType z_mo = to_montgomery_order(z); |
216 | |
|
217 | 0 | StorageType s_inv = modular_inverse_order(s_mo); |
218 | |
|
219 | 0 | StorageType u1 = modular_multiply_order(z_mo, s_inv); |
220 | 0 | StorageType u2 = modular_multiply_order(r_mo, s_inv); |
221 | |
|
222 | 0 | u1 = from_montgomery_order(u1); |
223 | 0 | u2 = from_montgomery_order(u2); |
224 | |
|
225 | 0 | JacobianPoint point1 = TRY(generate_public_key_internal(u1)); |
226 | 0 | JacobianPoint point2 = TRY(compute_coordinate_internal(u2, pubkey_point)); |
227 | | |
228 | | // Convert the input point into Montgomery form |
229 | 0 | point1.x = to_montgomery(point1.x); |
230 | 0 | point1.y = to_montgomery(point1.y); |
231 | 0 | point1.z = to_montgomery(point1.z); |
232 | |
|
233 | 0 | VERIFY(is_point_on_curve(point1)); |
234 | | |
235 | | // Convert the input point into Montgomery form |
236 | 0 | point2.x = to_montgomery(point2.x); |
237 | 0 | point2.y = to_montgomery(point2.y); |
238 | 0 | point2.z = to_montgomery(point2.z); |
239 | |
|
240 | 0 | VERIFY(is_point_on_curve(point2)); |
241 | | |
242 | 0 | JacobianPoint result = point_add(point1, point2); |
243 | | |
244 | | // Convert from Jacobian coordinates back to Affine coordinates |
245 | 0 | convert_jacobian_to_affine(result); |
246 | | |
247 | | // Make sure the resulting point is on the curve |
248 | 0 | VERIFY(is_point_on_curve(result)); |
249 | | |
250 | | // Convert the result back from Montgomery form |
251 | 0 | result.x = from_montgomery(result.x); |
252 | 0 | result.y = from_montgomery(result.y); |
253 | | // Final modular reduction on the coordinates |
254 | 0 | result.x = modular_reduce(result.x); |
255 | 0 | result.y = modular_reduce(result.y); |
256 | |
|
257 | 0 | return r.is_equal_to_constant_time(result.x); |
258 | 0 | } Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::verify(AK::Span<unsigned char const>, AK::Span<unsigned char const>, AK::Span<unsigned char const>) Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::verify(AK::Span<unsigned char const>, AK::Span<unsigned char const>, AK::Span<unsigned char const>) |
259 | | |
260 | | private: |
261 | | ErrorOr<JacobianPoint> generate_public_key_internal(StorageType a) |
262 | 0 | { |
263 | 0 | AK::FixedMemoryStream generator_point_stream { GENERATOR_POINT }; |
264 | 0 | JacobianPoint point = TRY(read_uncompressed_point(generator_point_stream)); |
265 | 0 | return compute_coordinate_internal(a, point); |
266 | 0 | } Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::generate_public_key_internal(AK::Detail::UFixedBigInt<256ul, AK::Detail::StaticStorage<false, 256ul> >) Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::generate_public_key_internal(AK::Detail::UFixedBigInt<384ul, AK::Detail::StaticStorage<false, 384ul> >) |
267 | | |
268 | | ErrorOr<JacobianPoint> compute_coordinate_internal(StorageType scalar, JacobianPoint point) |
269 | 0 | { |
270 | | // FIXME: This will slightly bias the distribution of client secrets |
271 | 0 | scalar = modular_reduce_order(scalar); |
272 | 0 | if (scalar.is_zero_constant_time()) |
273 | 0 | return Error::from_string_literal("SECPxxxr1: scalar is zero"); |
274 | | |
275 | | // Convert the input point into Montgomery form |
276 | 0 | point.x = to_montgomery(point.x); |
277 | 0 | point.y = to_montgomery(point.y); |
278 | 0 | point.z = to_montgomery(point.z); |
279 | | |
280 | | // Check that the point is on the curve |
281 | 0 | if (!is_point_on_curve(point)) |
282 | 0 | return Error::from_string_literal("SECPxxxr1: point is not on the curve"); |
283 | | |
284 | 0 | JacobianPoint result { 0, 0, 0 }; |
285 | 0 | JacobianPoint temp_result { 0, 0, 0 }; |
286 | | |
287 | | // Calculate the scalar times point multiplication in constant time |
288 | 0 | for (size_t i = 0; i < KEY_BIT_SIZE; i++) { |
289 | 0 | temp_result = point_add(result, point); |
290 | |
|
291 | 0 | auto condition = (scalar & 1u) == 1u; |
292 | 0 | result.x = select(result.x, temp_result.x, condition); |
293 | 0 | result.y = select(result.y, temp_result.y, condition); |
294 | 0 | result.z = select(result.z, temp_result.z, condition); |
295 | |
|
296 | 0 | point = point_double(point); |
297 | 0 | scalar >>= 1u; |
298 | 0 | } |
299 | | |
300 | | // Convert from Jacobian coordinates back to Affine coordinates |
301 | 0 | convert_jacobian_to_affine(result); |
302 | | |
303 | | // Make sure the resulting point is on the curve |
304 | 0 | VERIFY(is_point_on_curve(result)); |
305 | | |
306 | | // Convert the result back from Montgomery form |
307 | 0 | result.x = from_montgomery(result.x); |
308 | 0 | result.y = from_montgomery(result.y); |
309 | 0 | result.z = from_montgomery(result.z); |
310 | | // Final modular reduction on the coordinates |
311 | 0 | result.x = modular_reduce(result.x); |
312 | 0 | result.y = modular_reduce(result.y); |
313 | 0 | result.z = modular_reduce(result.z); |
314 | |
|
315 | 0 | return result; |
316 | 0 | } Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::compute_coordinate_internal(AK::Detail::UFixedBigInt<256ul, AK::Detail::StaticStorage<false, 256ul> >, Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::JacobianPoint) Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::compute_coordinate_internal(AK::Detail::UFixedBigInt<384ul, AK::Detail::StaticStorage<false, 384ul> >, Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::JacobianPoint) |
317 | | |
318 | | static ErrorOr<JacobianPoint> read_uncompressed_point(Stream& stream) |
319 | 0 | { |
320 | | // Make sure the point is uncompressed |
321 | 0 | if (TRY(stream.read_value<u8>()) != 0x04) |
322 | 0 | return Error::from_string_literal("SECPxxxr1: point is not uncompressed format"); |
323 | | |
324 | 0 | JacobianPoint point { |
325 | 0 | TRY(stream.read_value<BigEndian<StorageType>>()), |
326 | 0 | TRY(stream.read_value<BigEndian<StorageType>>()), |
327 | 0 | 1u, |
328 | 0 | }; |
329 | | |
330 | 0 | return point; |
331 | 0 | } Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::read_uncompressed_point(AK::Stream&) Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::read_uncompressed_point(AK::Stream&) |
332 | | |
333 | | constexpr StorageType select(StorageType const& left, StorageType const& right, bool condition) |
334 | 0 | { |
335 | | // If condition = 0 return left else right |
336 | 0 | StorageType mask = static_cast<StorageType>(condition) - 1; |
337 | 0 | AK::taint_for_optimizer(mask); |
338 | |
|
339 | 0 | return (left & mask) | (right & ~mask); |
340 | 0 | } Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::select(AK::Detail::UFixedBigInt<256ul, AK::Detail::StaticStorage<false, 256ul> > const&, AK::Detail::UFixedBigInt<256ul, AK::Detail::StaticStorage<false, 256ul> > const&, bool) Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::select(AK::Detail::UFixedBigInt<384ul, AK::Detail::StaticStorage<false, 384ul> > const&, AK::Detail::UFixedBigInt<384ul, AK::Detail::StaticStorage<false, 384ul> > const&, bool) |
341 | | |
342 | | constexpr StorageType modular_reduce(StorageType const& value) |
343 | 0 | { |
344 | | // Add -prime % 2^KEY_BIT_SIZE |
345 | 0 | bool carry = false; |
346 | 0 | StorageType other = value.addc(REDUCE_PRIME, carry); |
347 | | |
348 | | // Check for overflow |
349 | 0 | return select(value, other, carry); |
350 | 0 | } Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::modular_reduce(AK::Detail::UFixedBigInt<256ul, AK::Detail::StaticStorage<false, 256ul> > const&) Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::modular_reduce(AK::Detail::UFixedBigInt<384ul, AK::Detail::StaticStorage<false, 384ul> > const&) |
351 | | |
352 | | constexpr StorageType modular_reduce_order(StorageType const& value) |
353 | 0 | { |
354 | | // Add -order % 2^KEY_BIT_SIZE |
355 | 0 | bool carry = false; |
356 | 0 | StorageType other = value.addc(REDUCE_ORDER, carry); |
357 | | |
358 | | // Check for overflow |
359 | 0 | return select(value, other, carry); |
360 | 0 | } Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::modular_reduce_order(AK::Detail::UFixedBigInt<256ul, AK::Detail::StaticStorage<false, 256ul> > const&) Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::modular_reduce_order(AK::Detail::UFixedBigInt<384ul, AK::Detail::StaticStorage<false, 384ul> > const&) |
361 | | |
362 | | constexpr StorageType modular_add(StorageType const& left, StorageType const& right, bool carry_in = false) |
363 | 0 | { |
364 | 0 | bool carry = carry_in; |
365 | 0 | StorageType output = left.addc(right, carry); |
366 | | |
367 | | // If there is a carry, subtract p by adding 2^KEY_BIT_SIZE - p |
368 | 0 | StorageType addend = select(0u, REDUCE_PRIME, carry); |
369 | 0 | carry = false; |
370 | 0 | output = output.addc(addend, carry); |
371 | | |
372 | | // If there is still a carry, subtract p by adding 2^KEY_BIT_SIZE - p |
373 | 0 | addend = select(0u, REDUCE_PRIME, carry); |
374 | 0 | return output + addend; |
375 | 0 | } Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::modular_add(AK::Detail::UFixedBigInt<256ul, AK::Detail::StaticStorage<false, 256ul> > const&, AK::Detail::UFixedBigInt<256ul, AK::Detail::StaticStorage<false, 256ul> > const&, bool) Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::modular_add(AK::Detail::UFixedBigInt<384ul, AK::Detail::StaticStorage<false, 384ul> > const&, AK::Detail::UFixedBigInt<384ul, AK::Detail::StaticStorage<false, 384ul> > const&, bool) |
376 | | |
377 | | constexpr StorageType modular_sub(StorageType const& left, StorageType const& right) |
378 | 0 | { |
379 | 0 | bool borrow = false; |
380 | 0 | StorageType output = left.subc(right, borrow); |
381 | | |
382 | | // If there is a borrow, add p by subtracting 2^KEY_BIT_SIZE - p |
383 | 0 | StorageType sub = select(0u, REDUCE_PRIME, borrow); |
384 | 0 | borrow = false; |
385 | 0 | output = output.subc(sub, borrow); |
386 | | |
387 | | // If there is still a borrow, add p by subtracting 2^KEY_BIT_SIZE - p |
388 | 0 | sub = select(0u, REDUCE_PRIME, borrow); |
389 | 0 | return output - sub; |
390 | 0 | } Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::modular_sub(AK::Detail::UFixedBigInt<256ul, AK::Detail::StaticStorage<false, 256ul> > const&, AK::Detail::UFixedBigInt<256ul, AK::Detail::StaticStorage<false, 256ul> > const&) Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::modular_sub(AK::Detail::UFixedBigInt<384ul, AK::Detail::StaticStorage<false, 384ul> > const&, AK::Detail::UFixedBigInt<384ul, AK::Detail::StaticStorage<false, 384ul> > const&) |
391 | | |
392 | | constexpr StorageType modular_multiply(StorageType const& left, StorageType const& right) |
393 | 0 | { |
394 | | // Modular multiplication using the Montgomery method: https://en.wikipedia.org/wiki/Montgomery_modular_multiplication |
395 | | // This requires that the inputs to this function are in Montgomery form. |
396 | | |
397 | | // T = left * right |
398 | 0 | StorageTypeX2 mult = left.wide_multiply(right); |
399 | 0 | StorageType mult_mod_r = static_cast<StorageType>(mult); |
400 | | |
401 | | // m = ((T mod R) * curve_p') |
402 | 0 | StorageType m = mult_mod_r * PRIME_INVERSE_MOD_R; |
403 | | |
404 | | // mp = (m mod R) * curve_p |
405 | 0 | StorageTypeX2 mp = m.wide_multiply(PRIME); |
406 | | |
407 | | // t = (T + mp) |
408 | 0 | bool carry = false; |
409 | 0 | mult_mod_r.addc(static_cast<StorageType>(mp), carry); |
410 | | |
411 | | // output = t / R |
412 | 0 | StorageType mult_high = static_cast<StorageType>(mult >> KEY_BIT_SIZE); |
413 | 0 | StorageType mp_high = static_cast<StorageType>(mp >> KEY_BIT_SIZE); |
414 | 0 | return modular_add(mult_high, mp_high, carry); |
415 | 0 | } Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::modular_multiply(AK::Detail::UFixedBigInt<256ul, AK::Detail::StaticStorage<false, 256ul> > const&, AK::Detail::UFixedBigInt<256ul, AK::Detail::StaticStorage<false, 256ul> > const&) Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::modular_multiply(AK::Detail::UFixedBigInt<384ul, AK::Detail::StaticStorage<false, 384ul> > const&, AK::Detail::UFixedBigInt<384ul, AK::Detail::StaticStorage<false, 384ul> > const&) |
416 | | |
417 | | constexpr StorageType modular_square(StorageType const& value) |
418 | 0 | { |
419 | 0 | return modular_multiply(value, value); |
420 | 0 | } Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::modular_square(AK::Detail::UFixedBigInt<256ul, AK::Detail::StaticStorage<false, 256ul> > const&) Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::modular_square(AK::Detail::UFixedBigInt<384ul, AK::Detail::StaticStorage<false, 384ul> > const&) |
421 | | |
422 | | constexpr StorageType to_montgomery(StorageType const& value) |
423 | 0 | { |
424 | 0 | return modular_multiply(value, R2_MOD_PRIME); |
425 | 0 | } Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::to_montgomery(AK::Detail::UFixedBigInt<256ul, AK::Detail::StaticStorage<false, 256ul> > const&) Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::to_montgomery(AK::Detail::UFixedBigInt<384ul, AK::Detail::StaticStorage<false, 384ul> > const&) |
426 | | |
427 | | constexpr StorageType from_montgomery(StorageType const& value) |
428 | 0 | { |
429 | 0 | return modular_multiply(value, 1u); |
430 | 0 | } Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::from_montgomery(AK::Detail::UFixedBigInt<256ul, AK::Detail::StaticStorage<false, 256ul> > const&) Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::from_montgomery(AK::Detail::UFixedBigInt<384ul, AK::Detail::StaticStorage<false, 384ul> > const&) |
431 | | |
432 | | constexpr StorageType modular_inverse(StorageType const& value) |
433 | 0 | { |
434 | | // Modular inverse modulo the curve prime can be computed using Fermat's little theorem: a^(p-2) mod p = a^-1 mod p. |
435 | | // Calculating a^(p-2) mod p can be done using the square-and-multiply exponentiation method, as p-2 is constant. |
436 | 0 | StorageType base = value; |
437 | 0 | StorageType result = to_montgomery(1u); |
438 | 0 | StorageType prime_minus_2 = PRIME - 2u; |
439 | |
|
440 | 0 | for (size_t i = 0; i < KEY_BIT_SIZE; i++) { |
441 | 0 | if ((prime_minus_2 & 1u) == 1u) { |
442 | 0 | result = modular_multiply(result, base); |
443 | 0 | } |
444 | 0 | base = modular_square(base); |
445 | 0 | prime_minus_2 >>= 1u; |
446 | 0 | } |
447 | |
|
448 | 0 | return result; |
449 | 0 | } Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::modular_inverse(AK::Detail::UFixedBigInt<256ul, AK::Detail::StaticStorage<false, 256ul> > const&) Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::modular_inverse(AK::Detail::UFixedBigInt<384ul, AK::Detail::StaticStorage<false, 384ul> > const&) |
450 | | |
451 | | constexpr StorageType modular_add_order(StorageType const& left, StorageType const& right, bool carry_in = false) |
452 | 0 | { |
453 | 0 | bool carry = carry_in; |
454 | 0 | StorageType output = left.addc(right, carry); |
455 | | |
456 | | // If there is a carry, subtract n by adding 2^KEY_BIT_SIZE - n |
457 | 0 | StorageType addend = select(0u, REDUCE_ORDER, carry); |
458 | 0 | carry = false; |
459 | 0 | output = output.addc(addend, carry); |
460 | | |
461 | | // If there is still a carry, subtract n by adding 2^KEY_BIT_SIZE - n |
462 | 0 | addend = select(0u, REDUCE_ORDER, carry); |
463 | 0 | return output + addend; |
464 | 0 | } Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::modular_add_order(AK::Detail::UFixedBigInt<256ul, AK::Detail::StaticStorage<false, 256ul> > const&, AK::Detail::UFixedBigInt<256ul, AK::Detail::StaticStorage<false, 256ul> > const&, bool) Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::modular_add_order(AK::Detail::UFixedBigInt<384ul, AK::Detail::StaticStorage<false, 384ul> > const&, AK::Detail::UFixedBigInt<384ul, AK::Detail::StaticStorage<false, 384ul> > const&, bool) |
465 | | |
466 | | constexpr StorageType modular_multiply_order(StorageType const& left, StorageType const& right) |
467 | 0 | { |
468 | | // Modular multiplication using the Montgomery method: https://en.wikipedia.org/wiki/Montgomery_modular_multiplication |
469 | | // This requires that the inputs to this function are in Montgomery form. |
470 | | |
471 | | // T = left * right |
472 | 0 | StorageTypeX2 mult = left.wide_multiply(right); |
473 | 0 | StorageType mult_mod_r = static_cast<StorageType>(mult); |
474 | | |
475 | | // m = ((T mod R) * curve_n') |
476 | 0 | StorageType m = mult_mod_r * ORDER_INVERSE_MOD_R; |
477 | | |
478 | | // mp = (m mod R) * curve_n |
479 | 0 | StorageTypeX2 mp = m.wide_multiply(ORDER); |
480 | | |
481 | | // t = (T + mp) |
482 | 0 | bool carry = false; |
483 | 0 | mult_mod_r.addc(static_cast<StorageType>(mp), carry); |
484 | | |
485 | | // output = t / R |
486 | 0 | StorageType mult_high = static_cast<StorageType>(mult >> KEY_BIT_SIZE); |
487 | 0 | StorageType mp_high = static_cast<StorageType>(mp >> KEY_BIT_SIZE); |
488 | 0 | return modular_add_order(mult_high, mp_high, carry); |
489 | 0 | } Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::modular_multiply_order(AK::Detail::UFixedBigInt<256ul, AK::Detail::StaticStorage<false, 256ul> > const&, AK::Detail::UFixedBigInt<256ul, AK::Detail::StaticStorage<false, 256ul> > const&) Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::modular_multiply_order(AK::Detail::UFixedBigInt<384ul, AK::Detail::StaticStorage<false, 384ul> > const&, AK::Detail::UFixedBigInt<384ul, AK::Detail::StaticStorage<false, 384ul> > const&) |
490 | | |
491 | | constexpr StorageType modular_square_order(StorageType const& value) |
492 | 0 | { |
493 | 0 | return modular_multiply_order(value, value); |
494 | 0 | } Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::modular_square_order(AK::Detail::UFixedBigInt<256ul, AK::Detail::StaticStorage<false, 256ul> > const&) Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::modular_square_order(AK::Detail::UFixedBigInt<384ul, AK::Detail::StaticStorage<false, 384ul> > const&) |
495 | | |
496 | | constexpr StorageType to_montgomery_order(StorageType const& value) |
497 | 0 | { |
498 | 0 | return modular_multiply_order(value, R2_MOD_ORDER); |
499 | 0 | } Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::to_montgomery_order(AK::Detail::UFixedBigInt<256ul, AK::Detail::StaticStorage<false, 256ul> > const&) Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::to_montgomery_order(AK::Detail::UFixedBigInt<384ul, AK::Detail::StaticStorage<false, 384ul> > const&) |
500 | | |
501 | | constexpr StorageType from_montgomery_order(StorageType const& value) |
502 | 0 | { |
503 | 0 | return modular_multiply_order(value, 1u); |
504 | 0 | } Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::from_montgomery_order(AK::Detail::UFixedBigInt<256ul, AK::Detail::StaticStorage<false, 256ul> > const&) Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::from_montgomery_order(AK::Detail::UFixedBigInt<384ul, AK::Detail::StaticStorage<false, 384ul> > const&) |
505 | | |
506 | | constexpr StorageType modular_inverse_order(StorageType const& value) |
507 | 0 | { |
508 | | // Modular inverse modulo the curve order can be computed using Fermat's little theorem: a^(n-2) mod n = a^-1 mod n. |
509 | | // Calculating a^(n-2) mod n can be done using the square-and-multiply exponentiation method, as n-2 is constant. |
510 | 0 | StorageType base = value; |
511 | 0 | StorageType result = to_montgomery_order(1u); |
512 | 0 | StorageType order_minus_2 = ORDER - 2u; |
513 | |
|
514 | 0 | for (size_t i = 0; i < KEY_BIT_SIZE; i++) { |
515 | 0 | if ((order_minus_2 & 1u) == 1u) { |
516 | 0 | result = modular_multiply_order(result, base); |
517 | 0 | } |
518 | 0 | base = modular_square_order(base); |
519 | 0 | order_minus_2 >>= 1u; |
520 | 0 | } |
521 | |
|
522 | 0 | return result; |
523 | 0 | } Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::modular_inverse_order(AK::Detail::UFixedBigInt<256ul, AK::Detail::StaticStorage<false, 256ul> > const&) Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::modular_inverse_order(AK::Detail::UFixedBigInt<384ul, AK::Detail::StaticStorage<false, 384ul> > const&) |
524 | | |
525 | | JacobianPoint point_double(JacobianPoint const& point) |
526 | 0 | { |
527 | | // Based on "Point Doubling" from http://point-at-infinity.org/ecc/Prime_Curve_Jacobian_Coordinates.html |
528 | | |
529 | | // if (Y == 0) |
530 | | // return POINT_AT_INFINITY |
531 | 0 | if (point.y.is_zero_constant_time()) { |
532 | 0 | VERIFY_NOT_REACHED(); |
533 | 0 | } |
534 | | |
535 | 0 | StorageType temp; |
536 | | |
537 | | // Y2 = Y^2 |
538 | 0 | StorageType y2 = modular_square(point.y); |
539 | | |
540 | | // S = 4*X*Y2 |
541 | 0 | StorageType s = modular_multiply(point.x, y2); |
542 | 0 | s = modular_add(s, s); |
543 | 0 | s = modular_add(s, s); |
544 | | |
545 | | // M = 3*X^2 + a*Z^4 = 3*(X + Z^2)*(X - Z^2) |
546 | | // This specific equation from https://github.com/earlephilhower/bearssl-esp8266/blob/6105635531027f5b298aa656d44be2289b2d434f/src/ec/ec_p256_m64.c#L811-L816 |
547 | | // This simplification only works because a = -3 mod p |
548 | 0 | temp = modular_square(point.z); |
549 | 0 | StorageType m = modular_add(point.x, temp); |
550 | 0 | temp = modular_sub(point.x, temp); |
551 | 0 | m = modular_multiply(m, temp); |
552 | 0 | temp = modular_add(m, m); |
553 | 0 | m = modular_add(m, temp); |
554 | | |
555 | | // X' = M^2 - 2*S |
556 | 0 | StorageType xp = modular_square(m); |
557 | 0 | xp = modular_sub(xp, s); |
558 | 0 | xp = modular_sub(xp, s); |
559 | | |
560 | | // Y' = M*(S - X') - 8*Y2^2 |
561 | 0 | StorageType yp = modular_sub(s, xp); |
562 | 0 | yp = modular_multiply(yp, m); |
563 | 0 | temp = modular_square(y2); |
564 | 0 | temp = modular_add(temp, temp); |
565 | 0 | temp = modular_add(temp, temp); |
566 | 0 | temp = modular_add(temp, temp); |
567 | 0 | yp = modular_sub(yp, temp); |
568 | | |
569 | | // Z' = 2*Y*Z |
570 | 0 | StorageType zp = modular_multiply(point.y, point.z); |
571 | 0 | zp = modular_add(zp, zp); |
572 | | |
573 | | // return (X', Y', Z') |
574 | 0 | return JacobianPoint { xp, yp, zp }; |
575 | 0 | } Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::point_double(Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::JacobianPoint const&) Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::point_double(Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::JacobianPoint const&) |
576 | | |
577 | | JacobianPoint point_add(JacobianPoint const& point_a, JacobianPoint const& point_b) |
578 | 0 | { |
579 | | // Based on "Point Addition" from http://point-at-infinity.org/ecc/Prime_Curve_Jacobian_Coordinates.html |
580 | 0 | if (point_a.x.is_zero_constant_time() && point_a.y.is_zero_constant_time() && point_a.z.is_zero_constant_time()) { |
581 | 0 | return point_b; |
582 | 0 | } |
583 | | |
584 | 0 | StorageType temp; |
585 | |
|
586 | 0 | temp = modular_square(point_b.z); |
587 | | // U1 = X1*Z2^2 |
588 | 0 | StorageType u1 = modular_multiply(point_a.x, temp); |
589 | | // S1 = Y1*Z2^3 |
590 | 0 | StorageType s1 = modular_multiply(point_a.y, temp); |
591 | 0 | s1 = modular_multiply(s1, point_b.z); |
592 | |
|
593 | 0 | temp = modular_square(point_a.z); |
594 | | // U2 = X2*Z1^2 |
595 | 0 | StorageType u2 = modular_multiply(point_b.x, temp); |
596 | | // S2 = Y2*Z1^3 |
597 | 0 | StorageType s2 = modular_multiply(point_b.y, temp); |
598 | 0 | s2 = modular_multiply(s2, point_a.z); |
599 | | |
600 | | // if (U1 == U2) |
601 | | // if (S1 != S2) |
602 | | // return POINT_AT_INFINITY |
603 | | // else |
604 | | // return POINT_DOUBLE(X1, Y1, Z1) |
605 | 0 | if (u1.is_equal_to_constant_time(u2)) { |
606 | 0 | if (s1.is_equal_to_constant_time(s2)) { |
607 | 0 | return point_double(point_a); |
608 | 0 | } else { |
609 | 0 | VERIFY_NOT_REACHED(); |
610 | 0 | } |
611 | 0 | } |
612 | | |
613 | | // H = U2 - U1 |
614 | 0 | StorageType h = modular_sub(u2, u1); |
615 | 0 | StorageType h2 = modular_square(h); |
616 | 0 | StorageType h3 = modular_multiply(h2, h); |
617 | | // R = S2 - S1 |
618 | 0 | StorageType r = modular_sub(s2, s1); |
619 | | // X3 = R^2 - H^3 - 2*U1*H^2 |
620 | 0 | StorageType x3 = modular_square(r); |
621 | 0 | x3 = modular_sub(x3, h3); |
622 | 0 | temp = modular_multiply(u1, h2); |
623 | 0 | temp = modular_add(temp, temp); |
624 | 0 | x3 = modular_sub(x3, temp); |
625 | | // Y3 = R*(U1*H^2 - X3) - S1*H^3 |
626 | 0 | StorageType y3 = modular_multiply(u1, h2); |
627 | 0 | y3 = modular_sub(y3, x3); |
628 | 0 | y3 = modular_multiply(y3, r); |
629 | 0 | temp = modular_multiply(s1, h3); |
630 | 0 | y3 = modular_sub(y3, temp); |
631 | | // Z3 = H*Z1*Z2 |
632 | 0 | StorageType z3 = modular_multiply(h, point_a.z); |
633 | 0 | z3 = modular_multiply(z3, point_b.z); |
634 | | // return (X3, Y3, Z3) |
635 | 0 | return JacobianPoint { x3, y3, z3 }; |
636 | 0 | } Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::point_add(Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::JacobianPoint const&, Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::JacobianPoint const&) Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::point_add(Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::JacobianPoint const&, Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::JacobianPoint const&) |
637 | | |
638 | | void convert_jacobian_to_affine(JacobianPoint& point) |
639 | 0 | { |
640 | 0 | StorageType temp; |
641 | | // X' = X/Z^2 |
642 | 0 | temp = modular_square(point.z); |
643 | 0 | temp = modular_inverse(temp); |
644 | 0 | point.x = modular_multiply(point.x, temp); |
645 | | // Y' = Y/Z^3 |
646 | 0 | temp = modular_square(point.z); |
647 | 0 | temp = modular_multiply(temp, point.z); |
648 | 0 | temp = modular_inverse(temp); |
649 | 0 | point.y = modular_multiply(point.y, temp); |
650 | | // Z' = 1 |
651 | 0 | point.z = to_montgomery(1u); |
652 | 0 | } Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::convert_jacobian_to_affine(Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::JacobianPoint&) Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::convert_jacobian_to_affine(Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::JacobianPoint&) |
653 | | |
654 | | bool is_point_on_curve(JacobianPoint const& point) |
655 | 0 | { |
656 | | // This check requires the point to be in Montgomery form, with Z=1 |
657 | 0 | StorageType temp, temp2; |
658 | | |
659 | | // Calulcate Y^2 - X^3 - a*X - b = Y^2 - X^3 + 3*X - b |
660 | 0 | temp = modular_square(point.y); |
661 | 0 | temp2 = modular_square(point.x); |
662 | 0 | temp2 = modular_multiply(temp2, point.x); |
663 | 0 | temp = modular_sub(temp, temp2); |
664 | 0 | temp = modular_add(temp, point.x); |
665 | 0 | temp = modular_add(temp, point.x); |
666 | 0 | temp = modular_add(temp, point.x); |
667 | 0 | temp = modular_sub(temp, to_montgomery(B)); |
668 | 0 | temp = modular_reduce(temp); |
669 | |
|
670 | 0 | return temp.is_zero_constant_time() && point.z.is_equal_to_constant_time(to_montgomery(1u)); |
671 | 0 | } Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::is_point_on_curve(Crypto::Curves::SECPxxxr1<256ul, Crypto::Curves::SECP256r1_CURVE_PARAMETERS>::JacobianPoint const&) Unexecuted instantiation: CryptoAlgorithms.cpp:Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::is_point_on_curve(Crypto::Curves::SECPxxxr1<384ul, Crypto::Curves::SECP384r1_CURVE_PARAMETERS>::JacobianPoint const&) |
672 | | }; |
673 | | |
674 | | // SECP256r1 curve |
675 | | static constexpr SECPxxxr1CurveParameters SECP256r1_CURVE_PARAMETERS { |
676 | | .prime = "FFFFFFFF_00000001_00000000_00000000_00000000_FFFFFFFF_FFFFFFFF_FFFFFFFF"sv, |
677 | | .a = "FFFFFFFF_00000001_00000000_00000000_00000000_FFFFFFFF_FFFFFFFF_FFFFFFFC"sv, |
678 | | .b = "5AC635D8_AA3A93E7_B3EBBD55_769886BC_651D06B0_CC53B0F6_3BCE3C3E_27D2604B"sv, |
679 | | .order = "FFFFFFFF_00000000_FFFFFFFF_FFFFFFFF_BCE6FAAD_A7179E84_F3B9CAC2_FC632551"sv, |
680 | | .generator_point = "04_6B17D1F2_E12C4247_F8BCE6E5_63A440F2_77037D81_2DEB33A0_F4A13945_D898C296_4FE342E2_FE1A7F9B_8EE7EB4A_7C0F9E16_2BCE3357_6B315ECE_CBB64068_37BF51F5"sv, |
681 | | }; |
682 | | using SECP256r1 = SECPxxxr1<256, SECP256r1_CURVE_PARAMETERS>; |
683 | | |
684 | | // SECP384r1 curve |
685 | | static constexpr SECPxxxr1CurveParameters SECP384r1_CURVE_PARAMETERS { |
686 | | .prime = "FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFE_FFFFFFFF_00000000_00000000_FFFFFFFF"sv, |
687 | | .a = "FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFE_FFFFFFFF_00000000_00000000_FFFFFFFC"sv, |
688 | | .b = "B3312FA7_E23EE7E4_988E056B_E3F82D19_181D9C6E_FE814112_0314088F_5013875A_C656398D_8A2ED19D_2A85C8ED_D3EC2AEF"sv, |
689 | | .order = "FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_C7634D81_F4372DDF_581A0DB2_48B0A77A_ECEC196A_CCC52973"sv, |
690 | | .generator_point = "04_AA87CA22_BE8B0537_8EB1C71E_F320AD74_6E1D3B62_8BA79B98_59F741E0_82542A38_5502F25D_BF55296C_3A545E38_72760AB7_3617DE4A_96262C6F_5D9E98BF_9292DC29_F8F41DBD_289A147C_E9DA3113_B5F0B8C0_0A60B1CE_1D7E819D_7A431D7C_90EA0E5F"sv, |
691 | | }; |
692 | | using SECP384r1 = SECPxxxr1<384, SECP384r1_CURVE_PARAMETERS>; |
693 | | |
694 | | } |