summaryrefslogtreecommitdiff
path: root/src/crypto/fipsmodule/ec
diff options
context:
space:
mode:
authorDavid Benjamin <davidben@google.com>2023-06-24 19:37:56 -0400
committerDavid Benjamin <davidben@google.com>2023-07-18 15:01:01 -0400
commitdd6fc180c92d5e54a62f470755b241b7e320e3b8 (patch)
tree9e04b07f3bc8e7745b4e920bb679379b3b5416ca /src/crypto/fipsmodule/ec
parent4ab445e7200907972f8de2f54e1c5d73e0fc4ed7 (diff)
downloadboringssl-dd6fc180c92d5e54a62f470755b241b7e320e3b8.tar.gz
external/boringssl: Sync to 26ecb2a275ca7444d10899b8a3fe76d84831fca4.
For now, I've omitted the experimental new PKI library, as it's not yet ready for Android to use. I've also updated the script to automate the workaround for b/291253039. This includes the following changes: https://boringssl.googlesource.com/boringssl/+log/32b51305debe43e38e7bf2c2b13c4ebf3b474e80..26ecb2a275ca7444d10899b8a3fe76d84831fca4 * Add combined source lists to the other generators * Remove old style asm source lists for GN and Bazel Update-Note: I believe all GN and Bazel consumers have been migrated to the new style of asm source list, so this change should be a no-op. If any remain that still need the old ones, either migrate them to crypto_sources_asm and crypto_sources_nasm, or let us know. * Clarify what __TRUSTY__ and OPENSSL_NANOLIBC are * Temporarily disable the Trusty CRYPTO_sysrand implementation * Fix aarch64 build with GCC * Fix error condition in new iOS CRYPTO_sysrand * Make the old sk_* functions into full functions * Move file_test_gtest.cc to CRYPTO_TEST_SOURCES for now * Use constant curve-specific groups whenever possible * [acvptool] skip connection to the server if input json or regdump is on * Entropy changes for trusty and windows. Update-Note: Prior to API version 24, Trusty maintained their own CRYPTO_sysrand implementations outside of the BoringSSL tree. With this change they are not expected to provide CRYPTO_sysrand, it is maintained inside the BoringSSL tree. * Use std::make_unique when possible * Make built-in curves static. * Update the documentation of RAND_cleanup * Resolve an old TODO in TestState::Deserialize * Fix truncation warnings with the iteration count * sync pki to chrome 6e6fa5a08b94199de10eea22845963baf548628b * Fix spelling nits * Clear some size_t truncations * Add Intel Indirect Branch Tracking support. * Embed the generator into EC_GROUP * Const-correct a handful of time functions * Don't include stdalign.h in refcount.c * Fuchsia has getentropy() via musl - use it and drop the custom file * Remove remnants of malloc.cc * Embed BN_MONT_CTX into EC_GROUP. * Move to preferring getentropy() for system provided entropy Update-Note: Non-macOS Apple platforms now use CCRandomGenerateBytes instead of /dev/urandom. Linux behavior remains unchanged. Platforms which were not explicitly supported with a different codepath will also switch from /dev/urandom to getentropy. If your platform specifically requires /dev/urandom, let us know.know * Use sources.cmake for the bssl tool * Fix Android shared library tests * Use sources.cmake for the test_support library Update-Note: If something odd happens with the test_support library in downstream builds, this CL is probably to blame. * Use sources.cmake for test binaries Update-Note: In the standalone CMake build, build/crypto/crypto_test is now build/crypto_test, etc. For now, the build still copies the outputs to the subdirectories (it's cheap and avoids some workflow turbulence), but I'm thinking we keep that for six months or so and then remove it. * Don't store a redundant copy of the EC_GROUP field modulus * Revert "Build with C11 on MSVC in the standalone Bazel build" * Configure explicitly whether to shard tests * Use sources.cmake for pki and pki_test * Remove field_minus_order from EC_GROUP. * Use file(STRINGS) to read go_tests.txt * Use individual files for lists of source files. * Sync pki to chrome 28e4a1b838b2ffbf9e2151ae5fcfffe5ab0ffac0 * Build with C11 on MSVC in the standalone Bazel build * Replace byteBuilder and byteReader with cryptobyte * Don't store a redundant copy of the order in EC_GROUP * Make the curve compat APIs into real functions * Add pki test files for android, adapt PathService fillin. * Remove some unused fields * Temporarily add sk_new_null, etc., wrappers in bssl-sys * Fix libpki build * Fix the Windows fuzzer build * Consistently include BTI markers in every assembly file * Use ProcessPrng instead of RtlGenRandom on Windows * Bring in the core of chromium certificate verifier as libpki * Slightly tidy BIO_C_SET_FILENAME logic * Credit CryptOpt in third_party/fiat/README.md * Start recognizing the OPENSSL_NANOLIBC define * Use a single TCP server port in runner * Simplify shimProcess accept and wait * Turn SocketCloser in bssl_shim into a proper owning type * Pass IPv6 vs IPv4 down to the shim * Add more tests for recognizing explicit forms of built-in curves * Log failure to create SSL objects in handshakers * Remove -D__ASSEMBLER__=1 when shelling out to the preprocessor * Remove p > q normalization in RSA keys * Implement BN_MONT_CTX_new_consttime with Montgomery reduction * Make bn_mod_lshift_consttime faster * Fix tests on Arm when NEON is unavailable * Fix fiat asm .private_extern declaration on Apple platforms * Don't expose EVP_PKEY internal representation through EVP_PKEY_assign * Add memcmp binding to bssl-crypto * Remove CRYPTO_MUTEX from public headers * Make RSA opaque Update-Note: Accessing the RSA struct directly is no longer supported. Use accessors instead. * Add target attributes to curve25519_64_adx.h * Add ASN1_TIME_set_string_X509 * Don't allow timezone offsets in ASN1_UTCTIME_set_string Update-Note: ASN1_UTCTIME_set_string and ASN1_TIME_set_string will no longer accept times with timezone offsets, which is forbidden by RFC 5280. These functions are used when minting new certificates, rather than parsing them. The parsing behavior is unchanged by this CL. * Add SSL_CIPHER_get_handshake_digest Update-Note: This change is backwards-compatible, but we should update the QUIC code to use this new function when OPENSSL_API_VERSION is high enough. It has the benefit of not pulling in random other hash functions like MD4. * Const-correct a few X509_PURPOSE and X509_TRUST functions * Tidy bssl-crypto documentation * Avoid another NULL+0 in BIO_s_mem * Remove a layer of indirection from fiat curve25519 assembly * Fix the combined asm source lists in generate_build_files.py * Update build tools * Give up on qsort for sk_FOO_sort * Remove a pointer indirection in STACK_OF(T) comparisons * Add fiat_curve25519_adx.S to generate_build_files.py * Prefix the private stack functions * Add .type, .hidden, and .size to the new fiat ADX assembly * Use ADX asm for Curve25519 base-point multiplication * Make DSA opaque Update-Note: Accessing the DSA struct directly is no longer supported. Use accessors instead. * Add saturated X25519 for x86_64+ADX running Linux * Handle ChaCha20 counter overflow consistently * Use packed representation for large Curve25519 table * Add SHA256 and SHA512 bindings to bssl-crypto * Make BN_mod_inverse() deal with repeated arguments * Remove BN_DEC_FMT2 and test the others * Define TLSEXT_nid_unknown * Constant-time test that X25519 has a single path. * Add a value barrier when checking for point doubling. * Align NIDs vs group IDs in TLS group APIs * Align remaining TLS ECDH APIs on "group" terminology * Align on using the "group" over "curve" for ECDH in TLS * Remove SSL_CIPHER_get_value Update-Note: SSL_CIPHER_get_value was our original name for the function. OpenSSL later called it SSL_CIPHER_get_protocol_id. I believe all external callers have since been updated to use the new function. (If I missed a few stragglers, replace with SSL_CIPHER_get_protocol_id to fix.) * add rust bindings for ed25519 * Add an ABI test for x25519_NEON * Add constant-time validation for curve25519 * Add prefetch to aes_hw_ctr32_encrypt_blocks * Remove variable expansion from CONF fuzzer Update-Note: NCONF_load and NCONF_load_bio no longer support the $foo variable expansion syntax. If you are using these functions in your project, remove them. * Remove some unreachable character types in the CONF parser * Remove some unnecessary NULL checks in conf.c. * Test the CONF parser more extensively * Miscellaneous size_t truncation fixes * Add int casts as needed around STACK_OF(T) sizes and indices * Bound STACK_OF(T) sizes by int * acvptool: clean up better. * Avoid locks in CRYPTO_free_ex_data * Disable TLS_RSA_WITH_3DES_EDE_CBC_SHA by default Update-Note: This CL disables TLS_RSA_WITH_3DES_EDE_CBC_SHA by default. Specifically, it will not be included unless explicitly listed in the cipher config, as "TLS_RSA_WITH_3DES_EDE_CBC_SHA", its legacy OpenSSL name "DES-CBC3-SHA", or the alias "3DES". To restore it, add one of the above to your cipher config. * Don't include <stdatomic.h> in C++ * Add a comment about the Chromium sandbox for macOS sysctls * Update hkdf.c to avoid potentially vulnerable code pattern. * Fix RAND_enable_fork_unsafe_buffering when called after fork * Add a thread test for ex_data * Remove read locks from PRNG steady state * Add an atomics library to crypto/internal.h * Remove the lock-based atomics fallback Update-Note: On non-Windows platforms, we now require C11 atomics support. Note we already require C11 itself. If this affects your build, get in touch with BoringSSL maintainers. * Use Windows Interlocked* APIs for refcounts when C11 isn't available * Reject RSA keys under 512 bits Update-Note: We no longer accept 511-bit RSA and below. If you run into this, update test keys to more modern sizes as we plan to raise the limit beyond 512-bit RSA in the future. 512-bit RSA was factored in 1999, so keys at or near this limit have been obsolete for a very, very long time. * Check public components in freeze_private_key Update-Note: Manually constructed RSA private keys with invalid n or e will now fail private key operations. Such keys would always fail at public key operations (so the signatures would never verify). They also already failed RSA_check_key and parsing. * Remove now redundant RSA test * Add documentation for X509_STORE_CTX_set_verify_cb and friends * Add a multi-threaded mode to bssl speed * Use a helper function to implement get_all_foo_names functions. * Cap the input size to the conf fuzzer * acvptool: implement pipelining. * Update googletest * Update build tools * OpenBSD Support Update-Note: Additionally, BoringSSL now requires macOS 10.12 or later for getentropy support. This is consistent with https://github.com/google/oss-policies-info/blob/main/foundational-cxx-support-matrix.md * Remove unions in BLAKE2b implementation * Bump the minimum supported MSVC version to VS2019 Update-Note: BoringSSL now requires VS2019 or later and no longer supports VS2017. VS2017 has been past its "mainstream end date" for over a year now, per https://learn.microsoft.com/en-us/lifecycle/products/visual-studio-2017 * Add APIs to query a list of possible strings for TLS features * Add back support for TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 * Fix PKCS8Test to not rely on RSA-512 * Add a more general mechanism for deprecating TLS ciphers * Add APIs to support RSA keys with large e. * Remove unions in GCM implementation * Rename EC_RAW_POINT to EC_JACOBIAN * Clarify that X25519 also supports EVP_PKEY_new_raw_private_key, etc * Align Kyber names with draft-tls-westerbaan-xyber768d00 Update-Note: Update references to NID_X25519Kyber768 to NID_X25519Kyber768Draft00. For now, the old name is available as an alias. * Remove unions in polyval implementation * Remove H from GCM128_KEY * Don't make assumptions about GCM128_CONTEXT layout in aesni-gcm-x86_64.pl * Don't make assumptions about GCM128_CONTEXT layout in aesv8-gcm-armv8.pl * Implement the AuthEncap/AuthDecap HPKE modes * Update references to draft-irtf-cfrg-gcmsiv * Replace interface{} with any * Add new APIs for creating RSA keys * Disable BlindingCacheConcurrency on FreeBSD. * Add Kyber to runner tests * Invalidated cached RSA, DH, and DSA state when changing keys * Support WPA 3.1 "enterprise" mode. * runner: Remove an unnecessary use of AllCurves * Move the old SPKAC types to their own section * Remove unimplemented SSL BIO_ctrl values Update-Note: I found no code using those symbols (that we build). If anything was, they most likely were broken. Now they'll fail to build and the brokenness will be more obvious. (If we find something needs it, we can always go back and implement them.) * Don't copy all of bssl-sys into the CMake build directory * Remove go:build ignore from convert_wycheproof * X509_sign, etc., should return the length of the signature on success * Add some missing includes * Specify the TLS cipher order more straightforwardly * Squeeze a block at a time when computing the matrix in Kyber * Align TRUST_TOKEN_pst_v1_voprf with draft-21 of VOPRF * Re-add go:build ignore lines * Move convert_wycheproof into its own package * Allow passing extra flags to BoGo shim * Remove TLS_RSA_WITH_NULL_SHA Update-Note: TLS_RSA_WITH_NULL_SHA is no longer available. Nothing should be enabling it anymore. Callers using SSL_CTX_set_strict_cipher_list instead of SSL_CTX_set_cipher_list will notice if they're affected very quickly, because the functino will fail if this cipher is referenced. As a deprecated cipher suite, this cipher was already unavailable unless explicitly named, so if your configuration doesn't say "TLS_RSA_WITH_NULL_SHA" or "NULL-SHA", you were not using this cipher. * Only rerun bindgen when its dependencies change * Add mechanism for deprecated declarations. Update-Note: We are starting to mark some functions in boringssl as deprecated declarations which will cause the compiler to emit warnings if they are used. The intention is both to prevent accidental use in new code, and to to call attention to call sites in existing code so that the documentation for the deprecated function can be revisted and appropriate action taken. * Spell includes in wrapper.h like the rest of the project * Replace sort.Sort with sort.Slice * Fix allowlist regex in bindgen invocation * Update docs to recommend a much more convenient CMake invocation * Trim some unused XN_FLAG_* values Update-Note: Some seemingly unused XN_FLAG_* values were removed. If some project fails to build, we can put them back but one shouldn't be using this function in the first place. * Remove --size_t-is-usize from bindgen call * Clarify in ssl.h documentation not to use the verify callback * Move the X509 time functions under "Convenience functions" * Remove the X509at_* functions * Organize X509_ATTRIBUTE functions into sections. * Document a pile of X509 print functions * Generate 64-bit Curve25519 and P256 code for MSVC Test: treehugger Change-Id: Id9645b0bcd5e353e64777d1596cd91c7767b11fa
Diffstat (limited to 'src/crypto/fipsmodule/ec')
-rwxr-xr-xsrc/crypto/fipsmodule/ec/asm/p256-x86_64-asm.pl12
-rw-r--r--src/crypto/fipsmodule/ec/asm/p256_beeu-x86_64-asm.pl1
-rw-r--r--src/crypto/fipsmodule/ec/builtin_curves.h277
-rw-r--r--src/crypto/fipsmodule/ec/ec.c632
-rw-r--r--src/crypto/fipsmodule/ec/ec_key.c8
-rw-r--r--src/crypto/fipsmodule/ec/ec_montgomery.c95
-rw-r--r--src/crypto/fipsmodule/ec/ec_test.cc163
-rw-r--r--src/crypto/fipsmodule/ec/felem.c30
-rw-r--r--src/crypto/fipsmodule/ec/internal.h240
-rw-r--r--src/crypto/fipsmodule/ec/make_tables.go322
-rw-r--r--src/crypto/fipsmodule/ec/oct.c35
-rw-r--r--src/crypto/fipsmodule/ec/p224-64.c34
-rw-r--r--src/crypto/fipsmodule/ec/p256-nistz.c57
-rw-r--r--src/crypto/fipsmodule/ec/p256-nistz_test.cc13
-rw-r--r--src/crypto/fipsmodule/ec/p256.c42
-rw-r--r--src/crypto/fipsmodule/ec/scalar.c48
-rw-r--r--src/crypto/fipsmodule/ec/simple.c58
-rw-r--r--src/crypto/fipsmodule/ec/simple_mul.c62
-rw-r--r--src/crypto/fipsmodule/ec/wnaf.c32
19 files changed, 1146 insertions, 1015 deletions
diff --git a/src/crypto/fipsmodule/ec/asm/p256-x86_64-asm.pl b/src/crypto/fipsmodule/ec/asm/p256-x86_64-asm.pl
index 0701996d..b6e03845 100755
--- a/src/crypto/fipsmodule/ec/asm/p256-x86_64-asm.pl
+++ b/src/crypto/fipsmodule/ec/asm/p256-x86_64-asm.pl
@@ -98,6 +98,7 @@ $code.=<<___;
.align 32
ecp_nistz256_neg:
.cfi_startproc
+ _CET_ENDBR
push %r12
.cfi_push %r12
push %r13
@@ -166,6 +167,7 @@ $code.=<<___;
.align 32
ecp_nistz256_ord_mul_mont:
.cfi_startproc
+ _CET_ENDBR
___
$code.=<<___ if ($addx);
leaq OPENSSL_ia32cap_P(%rip), %rcx
@@ -497,6 +499,7 @@ $code.=<<___;
.align 32
ecp_nistz256_ord_sqr_mont:
.cfi_startproc
+ _CET_ENDBR
___
$code.=<<___ if ($addx);
leaq OPENSSL_ia32cap_P(%rip), %rcx
@@ -1247,6 +1250,7 @@ $code.=<<___;
.align 32
ecp_nistz256_mul_mont:
.cfi_startproc
+ _CET_ENDBR
___
$code.=<<___ if ($addx);
leaq OPENSSL_ia32cap_P(%rip), %rcx
@@ -1549,6 +1553,7 @@ __ecp_nistz256_mul_montq:
.align 32
ecp_nistz256_sqr_mont:
.cfi_startproc
+ _CET_ENDBR
___
$code.=<<___ if ($addx);
leaq OPENSSL_ia32cap_P(%rip), %rcx
@@ -2098,6 +2103,7 @@ $code.=<<___;
.align 32
ecp_nistz256_select_w5:
.cfi_startproc
+ _CET_ENDBR
___
$code.=<<___ if ($avx>1);
leaq OPENSSL_ia32cap_P(%rip), %rax
@@ -2198,6 +2204,7 @@ $code.=<<___;
.align 32
ecp_nistz256_select_w7:
.cfi_startproc
+ _CET_ENDBR
___
$code.=<<___ if ($avx>1);
leaq OPENSSL_ia32cap_P(%rip), %rax
@@ -2403,6 +2410,7 @@ $code.=<<___;
ecp_nistz256_avx2_select_w7:
.cfi_startproc
.Lavx2_select_w7:
+ _CET_ENDBR
vzeroupper
___
$code.=<<___ if ($win64);
@@ -2514,6 +2522,7 @@ $code.=<<___;
.type ecp_nistz256_avx2_select_w7,\@function,3
.align 32
ecp_nistz256_avx2_select_w7:
+ _CET_ENDBR
.byte 0x0f,0x0b # ud2
ret
.size ecp_nistz256_avx2_select_w7,.-ecp_nistz256_avx2_select_w7
@@ -2718,6 +2727,7 @@ $code.=<<___;
.align 32
ecp_nistz256_point_double:
.cfi_startproc
+ _CET_ENDBR
___
$code.=<<___ if ($addx);
leaq OPENSSL_ia32cap_P(%rip), %rcx
@@ -2970,6 +2980,7 @@ $code.=<<___;
.align 32
ecp_nistz256_point_add:
.cfi_startproc
+ _CET_ENDBR
___
$code.=<<___ if ($addx);
leaq OPENSSL_ia32cap_P(%rip), %rcx
@@ -3368,6 +3379,7 @@ $code.=<<___;
.align 32
ecp_nistz256_point_add_affine:
.cfi_startproc
+ _CET_ENDBR
___
$code.=<<___ if ($addx);
leaq OPENSSL_ia32cap_P(%rip), %rcx
diff --git a/src/crypto/fipsmodule/ec/asm/p256_beeu-x86_64-asm.pl b/src/crypto/fipsmodule/ec/asm/p256_beeu-x86_64-asm.pl
index b9ec96da..1600d4ca 100644
--- a/src/crypto/fipsmodule/ec/asm/p256_beeu-x86_64-asm.pl
+++ b/src/crypto/fipsmodule/ec/asm/p256_beeu-x86_64-asm.pl
@@ -154,6 +154,7 @@ $code.=<<___;
.align 32
beeu_mod_inverse_vartime:
.cfi_startproc
+ _CET_ENDBR
push %rbp
.cfi_push rbp
push %r12
diff --git a/src/crypto/fipsmodule/ec/builtin_curves.h b/src/crypto/fipsmodule/ec/builtin_curves.h
new file mode 100644
index 00000000..0b489ab5
--- /dev/null
+++ b/src/crypto/fipsmodule/ec/builtin_curves.h
@@ -0,0 +1,277 @@
+/* Copyright (c) 2023, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+// This file is generated by make_tables.go.
+
+// P-224
+OPENSSL_UNUSED static const uint64_t kP224FieldN0 = 0xffffffffffffffff;
+OPENSSL_UNUSED static const uint64_t kP224OrderN0 = 0xd6e242706a1fc2eb;
+#if defined(OPENSSL_64_BIT)
+OPENSSL_UNUSED static const uint64_t kP224Field[] = {
+ 0x0000000000000001, 0xffffffff00000000, 0xffffffffffffffff,
+ 0x00000000ffffffff};
+OPENSSL_UNUSED static const uint64_t kP224Order[] = {
+ 0x13dd29455c5c2a3d, 0xffff16a2e0b8f03e, 0xffffffffffffffff,
+ 0x00000000ffffffff};
+OPENSSL_UNUSED static const uint64_t kP224B[] = {
+ 0x270b39432355ffb4, 0x5044b0b7d7bfd8ba, 0x0c04b3abf5413256,
+ 0x00000000b4050a85};
+OPENSSL_UNUSED static const uint64_t kP224GX[] = {
+ 0x343280d6115c1d21, 0x4a03c1d356c21122, 0x6bb4bf7f321390b9,
+ 0x00000000b70e0cbd};
+OPENSSL_UNUSED static const uint64_t kP224GY[] = {
+ 0x44d5819985007e34, 0xcd4375a05a074764, 0xb5f723fb4c22dfe6,
+ 0x00000000bd376388};
+OPENSSL_UNUSED static const uint64_t kP224FieldR[] = {
+ 0xffffffff00000000, 0xffffffffffffffff, 0x0000000000000000,
+ 0x0000000000000000};
+OPENSSL_UNUSED static const uint64_t kP224FieldRR[] = {
+ 0xffffffff00000001, 0xffffffff00000000, 0xfffffffe00000000,
+ 0x00000000ffffffff};
+OPENSSL_UNUSED static const uint64_t kP224OrderRR[] = {
+ 0x29947a695f517d15, 0xabc8ff5931d63f4b, 0x6ad15f7cd9714856,
+ 0x00000000b1e97961};
+OPENSSL_UNUSED static const uint64_t kP224MontB[] = {
+ 0xe768cdf663c059cd, 0x107ac2f3ccf01310, 0x3dceba98c8528151,
+ 0x000000007fc02f93};
+OPENSSL_UNUSED static const uint64_t kP224MontGX[] = {
+ 0xbc9052266d0a4aea, 0x852597366018bfaa, 0x6dd3af9bf96bec05,
+ 0x00000000a21b5e60};
+OPENSSL_UNUSED static const uint64_t kP224MontGY[] = {
+ 0x2edca1e5eff3ede8, 0xf8cd672b05335a6b, 0xaea9c5ae03dfe878,
+ 0x00000000614786f1};
+#elif defined(OPENSSL_32_BIT)
+OPENSSL_UNUSED static const uint32_t kP224Field[] = {
+ 0x00000001, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff};
+OPENSSL_UNUSED static const uint32_t kP224Order[] = {
+ 0x5c5c2a3d, 0x13dd2945, 0xe0b8f03e, 0xffff16a2, 0xffffffff, 0xffffffff,
+ 0xffffffff};
+OPENSSL_UNUSED static const uint32_t kP224B[] = {
+ 0x2355ffb4, 0x270b3943, 0xd7bfd8ba, 0x5044b0b7, 0xf5413256, 0x0c04b3ab,
+ 0xb4050a85};
+OPENSSL_UNUSED static const uint32_t kP224GX[] = {
+ 0x115c1d21, 0x343280d6, 0x56c21122, 0x4a03c1d3, 0x321390b9, 0x6bb4bf7f,
+ 0xb70e0cbd};
+OPENSSL_UNUSED static const uint32_t kP224GY[] = {
+ 0x85007e34, 0x44d58199, 0x5a074764, 0xcd4375a0, 0x4c22dfe6, 0xb5f723fb,
+ 0xbd376388};
+OPENSSL_UNUSED static const uint32_t kP224FieldR[] = {
+ 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000};
+OPENSSL_UNUSED static const uint32_t kP224FieldRR[] = {
+ 0x00000001, 0x00000000, 0x00000000, 0xfffffffe, 0xffffffff, 0xffffffff,
+ 0x00000000};
+OPENSSL_UNUSED static const uint32_t kP224OrderRR[] = {
+ 0x3ad01289, 0x6bdaae6c, 0x97a54552, 0x6ad09d91, 0xb1e97961, 0x1822bc47,
+ 0xd4baa4cf};
+OPENSSL_UNUSED static const uint32_t kP224MontB[] = {
+ 0xe768cdf7, 0xccf01310, 0x743b1cc0, 0xc8528150, 0x3dceba98, 0x7fc02f93,
+ 0x9c3fa633};
+OPENSSL_UNUSED static const uint32_t kP224MontGX[] = {
+ 0xbc905227, 0x6018bfaa, 0xf22fe220, 0xf96bec04, 0x6dd3af9b, 0xa21b5e60,
+ 0x92f5b516};
+OPENSSL_UNUSED static const uint32_t kP224MontGY[] = {
+ 0x2edca1e6, 0x05335a6b, 0xe8c15513, 0x03dfe878, 0xaea9c5ae, 0x614786f1,
+ 0x100c1218};
+#else
+#error "unknown word size"
+#endif
+
+// P-256
+OPENSSL_UNUSED static const uint64_t kP256FieldN0 = 0x0000000000000001;
+OPENSSL_UNUSED static const uint64_t kP256OrderN0 = 0xccd1c8aaee00bc4f;
+#if defined(OPENSSL_64_BIT)
+OPENSSL_UNUSED static const uint64_t kP256Field[] = {
+ 0xffffffffffffffff, 0x00000000ffffffff, 0x0000000000000000,
+ 0xffffffff00000001};
+OPENSSL_UNUSED static const uint64_t kP256Order[] = {
+ 0xf3b9cac2fc632551, 0xbce6faada7179e84, 0xffffffffffffffff,
+ 0xffffffff00000000};
+OPENSSL_UNUSED static const uint64_t kP256FieldR[] = {
+ 0x0000000000000001, 0xffffffff00000000, 0xffffffffffffffff,
+ 0x00000000fffffffe};
+OPENSSL_UNUSED static const uint64_t kP256FieldRR[] = {
+ 0x0000000000000003, 0xfffffffbffffffff, 0xfffffffffffffffe,
+ 0x00000004fffffffd};
+OPENSSL_UNUSED static const uint64_t kP256OrderRR[] = {
+ 0x83244c95be79eea2, 0x4699799c49bd6fa6, 0x2845b2392b6bec59,
+ 0x66e12d94f3d95620};
+OPENSSL_UNUSED static const uint64_t kP256MontB[] = {
+ 0xd89cdf6229c4bddf, 0xacf005cd78843090, 0xe5a220abf7212ed6,
+ 0xdc30061d04874834};
+OPENSSL_UNUSED static const uint64_t kP256MontGX[] = {
+ 0x79e730d418a9143c, 0x75ba95fc5fedb601, 0x79fb732b77622510,
+ 0x18905f76a53755c6};
+OPENSSL_UNUSED static const uint64_t kP256MontGY[] = {
+ 0xddf25357ce95560a, 0x8b4ab8e4ba19e45c, 0xd2e88688dd21f325,
+ 0x8571ff1825885d85};
+#elif defined(OPENSSL_32_BIT)
+OPENSSL_UNUSED static const uint32_t kP256Field[] = {
+ 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000001, 0xffffffff};
+OPENSSL_UNUSED static const uint32_t kP256Order[] = {
+ 0xfc632551, 0xf3b9cac2, 0xa7179e84, 0xbce6faad, 0xffffffff, 0xffffffff,
+ 0x00000000, 0xffffffff};
+OPENSSL_UNUSED static const uint32_t kP256FieldR[] = {
+ 0x00000001, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xfffffffe, 0x00000000};
+OPENSSL_UNUSED static const uint32_t kP256FieldRR[] = {
+ 0x00000003, 0x00000000, 0xffffffff, 0xfffffffb, 0xfffffffe, 0xffffffff,
+ 0xfffffffd, 0x00000004};
+OPENSSL_UNUSED static const uint32_t kP256OrderRR[] = {
+ 0xbe79eea2, 0x83244c95, 0x49bd6fa6, 0x4699799c, 0x2b6bec59, 0x2845b239,
+ 0xf3d95620, 0x66e12d94};
+OPENSSL_UNUSED static const uint32_t kP256MontB[] = {
+ 0x29c4bddf, 0xd89cdf62, 0x78843090, 0xacf005cd, 0xf7212ed6, 0xe5a220ab,
+ 0x04874834, 0xdc30061d};
+OPENSSL_UNUSED static const uint32_t kP256MontGX[] = {
+ 0x18a9143c, 0x79e730d4, 0x5fedb601, 0x75ba95fc, 0x77622510, 0x79fb732b,
+ 0xa53755c6, 0x18905f76};
+OPENSSL_UNUSED static const uint32_t kP256MontGY[] = {
+ 0xce95560a, 0xddf25357, 0xba19e45c, 0x8b4ab8e4, 0xdd21f325, 0xd2e88688,
+ 0x25885d85, 0x8571ff18};
+#else
+#error "unknown word size"
+#endif
+
+// P-384
+OPENSSL_UNUSED static const uint64_t kP384FieldN0 = 0x0000000100000001;
+OPENSSL_UNUSED static const uint64_t kP384OrderN0 = 0x6ed46089e88fdc45;
+#if defined(OPENSSL_64_BIT)
+OPENSSL_UNUSED static const uint64_t kP384Field[] = {
+ 0x00000000ffffffff, 0xffffffff00000000, 0xfffffffffffffffe,
+ 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+OPENSSL_UNUSED static const uint64_t kP384Order[] = {
+ 0xecec196accc52973, 0x581a0db248b0a77a, 0xc7634d81f4372ddf,
+ 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};
+OPENSSL_UNUSED static const uint64_t kP384FieldR[] = {
+ 0xffffffff00000001, 0x00000000ffffffff, 0x0000000000000001,
+ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000};
+OPENSSL_UNUSED static const uint64_t kP384FieldRR[] = {
+ 0xfffffffe00000001, 0x0000000200000000, 0xfffffffe00000000,
+ 0x0000000200000000, 0x0000000000000001, 0x0000000000000000};
+OPENSSL_UNUSED static const uint64_t kP384OrderRR[] = {
+ 0x2d319b2419b409a9, 0xff3d81e5df1aa419, 0xbc3e483afcb82947,
+ 0xd40d49174aab1cc5, 0x3fb05b7a28266895, 0x0c84ee012b39bf21};
+OPENSSL_UNUSED static const uint64_t kP384MontB[] = {
+ 0x081188719d412dcc, 0xf729add87a4c32ec, 0x77f2209b1920022e,
+ 0xe3374bee94938ae2, 0xb62b21f41f022094, 0xcd08114b604fbff9};
+OPENSSL_UNUSED static const uint64_t kP384MontGX[] = {
+ 0x3dd0756649c0b528, 0x20e378e2a0d6ce38, 0x879c3afc541b4d6e,
+ 0x6454868459a30eff, 0x812ff723614ede2b, 0x4d3aadc2299e1513};
+OPENSSL_UNUSED static const uint64_t kP384MontGY[] = {
+ 0x23043dad4b03a4fe, 0xa1bfa8bf7bb4a9ac, 0x8bade7562e83b050,
+ 0xc6c3521968f4ffd9, 0xdd8002263969a840, 0x2b78abc25a15c5e9};
+#elif defined(OPENSSL_32_BIT)
+OPENSSL_UNUSED static const uint32_t kP384Field[] = {
+ 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xfffffffe, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff};
+OPENSSL_UNUSED static const uint32_t kP384Order[] = {
+ 0xccc52973, 0xecec196a, 0x48b0a77a, 0x581a0db2, 0xf4372ddf, 0xc7634d81,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff};
+OPENSSL_UNUSED static const uint32_t kP384FieldR[] = {
+ 0x00000001, 0xffffffff, 0xffffffff, 0x00000000, 0x00000001, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000};
+OPENSSL_UNUSED static const uint32_t kP384FieldRR[] = {
+ 0x00000001, 0xfffffffe, 0x00000000, 0x00000002, 0x00000000, 0xfffffffe,
+ 0x00000000, 0x00000002, 0x00000001, 0x00000000, 0x00000000, 0x00000000};
+OPENSSL_UNUSED static const uint32_t kP384OrderRR[] = {
+ 0x19b409a9, 0x2d319b24, 0xdf1aa419, 0xff3d81e5, 0xfcb82947, 0xbc3e483a,
+ 0x4aab1cc5, 0xd40d4917, 0x28266895, 0x3fb05b7a, 0x2b39bf21, 0x0c84ee01};
+OPENSSL_UNUSED static const uint32_t kP384MontB[] = {
+ 0x9d412dcc, 0x08118871, 0x7a4c32ec, 0xf729add8, 0x1920022e, 0x77f2209b,
+ 0x94938ae2, 0xe3374bee, 0x1f022094, 0xb62b21f4, 0x604fbff9, 0xcd08114b};
+OPENSSL_UNUSED static const uint32_t kP384MontGX[] = {
+ 0x49c0b528, 0x3dd07566, 0xa0d6ce38, 0x20e378e2, 0x541b4d6e, 0x879c3afc,
+ 0x59a30eff, 0x64548684, 0x614ede2b, 0x812ff723, 0x299e1513, 0x4d3aadc2};
+OPENSSL_UNUSED static const uint32_t kP384MontGY[] = {
+ 0x4b03a4fe, 0x23043dad, 0x7bb4a9ac, 0xa1bfa8bf, 0x2e83b050, 0x8bade756,
+ 0x68f4ffd9, 0xc6c35219, 0x3969a840, 0xdd800226, 0x5a15c5e9, 0x2b78abc2};
+#else
+#error "unknown word size"
+#endif
+
+// P-521
+OPENSSL_UNUSED static const uint64_t kP521FieldN0 = 0x0000000000000001;
+OPENSSL_UNUSED static const uint64_t kP521OrderN0 = 0x1d2f5ccd79a995c7;
+#if defined(OPENSSL_64_BIT)
+OPENSSL_UNUSED static const uint64_t kP521Field[] = {
+ 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
+ 0xffffffffffffffff, 0xffffffffffffffff, 0x00000000000001ff};
+OPENSSL_UNUSED static const uint64_t kP521Order[] = {
+ 0xbb6fb71e91386409, 0x3bb5c9b8899c47ae, 0x7fcc0148f709a5d0,
+ 0x51868783bf2f966b, 0xfffffffffffffffa, 0xffffffffffffffff,
+ 0xffffffffffffffff, 0xffffffffffffffff, 0x00000000000001ff};
+OPENSSL_UNUSED static const uint64_t kP521FieldR[] = {
+ 0x0080000000000000, 0x0000000000000000, 0x0000000000000000,
+ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
+ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000};
+OPENSSL_UNUSED static const uint64_t kP521FieldRR[] = {
+ 0x0000000000000000, 0x0000400000000000, 0x0000000000000000,
+ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
+ 0x0000000000000000, 0x0000000000000000, 0x0000000000000000};
+OPENSSL_UNUSED static const uint64_t kP521OrderRR[] = {
+ 0x137cd04dcf15dd04, 0xf707badce5547ea3, 0x12a78d38794573ff,
+ 0xd3721ef557f75e06, 0xdd6e23d82e49c7db, 0xcff3d142b7756e3e,
+ 0x5bcc6d61a8e567bc, 0x2d8e03d1492d0d45, 0x000000000000003d};
+OPENSSL_UNUSED static const uint64_t kP521MontB[] = {
+ 0x8014654fae586387, 0x78f7a28fea35a81f, 0x839ab9efc41e961a,
+ 0xbd8b29605e9dd8df, 0xf0ab0c9ca8f63f49, 0xf9dc5a44c8c77884,
+ 0x77516d392dccd98a, 0x0fc94d10d05b42a0, 0x000000000000004d};
+OPENSSL_UNUSED static const uint64_t kP521MontGX[] = {
+ 0xb331a16381adc101, 0x4dfcbf3f18e172de, 0x6f19a459e0c2b521,
+ 0x947f0ee093d17fd4, 0xdd50a5af3bf7f3ac, 0x90fc1457b035a69e,
+ 0x214e32409c829fda, 0xe6cf1f65b311cada, 0x0000000000000074};
+OPENSSL_UNUSED static const uint64_t kP521MontGY[] = {
+ 0x28460e4a5a9e268e, 0x20445f4a3b4fe8b3, 0xb09a9e3843513961,
+ 0x2062a85c809fd683, 0x164bf7394caf7a13, 0x340bd7de8b939f33,
+ 0xeccc7aa224abcda2, 0x022e452fda163e8d, 0x00000000000001e0};
+#elif defined(OPENSSL_32_BIT)
+OPENSSL_UNUSED static const uint32_t kP521Field[] = {
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x000001ff};
+OPENSSL_UNUSED static const uint32_t kP521Order[] = {
+ 0x91386409, 0xbb6fb71e, 0x899c47ae, 0x3bb5c9b8, 0xf709a5d0, 0x7fcc0148,
+ 0xbf2f966b, 0x51868783, 0xfffffffa, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x000001ff};
+OPENSSL_UNUSED static const uint32_t kP521FieldR[] = {
+ 0x00800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000};
+OPENSSL_UNUSED static const uint32_t kP521FieldRR[] = {
+ 0x00000000, 0x00004000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000};
+OPENSSL_UNUSED static const uint32_t kP521OrderRR[] = {
+ 0x61c64ca7, 0x1163115a, 0x4374a642, 0x18354a56, 0x0791d9dc, 0x5d4dd6d3,
+ 0xd3402705, 0x4fb35b72, 0xb7756e3a, 0xcff3d142, 0xa8e567bc, 0x5bcc6d61,
+ 0x492d0d45, 0x2d8e03d1, 0x8c44383d, 0x5b5a3afe, 0x0000019a};
+OPENSSL_UNUSED static const uint32_t kP521MontB[] = {
+ 0x8014654f, 0xea35a81f, 0x78f7a28f, 0xc41e961a, 0x839ab9ef, 0x5e9dd8df,
+ 0xbd8b2960, 0xa8f63f49, 0xf0ab0c9c, 0xc8c77884, 0xf9dc5a44, 0x2dccd98a,
+ 0x77516d39, 0xd05b42a0, 0x0fc94d10, 0xb0c70e4d, 0x0000015c};
+OPENSSL_UNUSED static const uint32_t kP521MontGX[] = {
+ 0xb331a163, 0x18e172de, 0x4dfcbf3f, 0xe0c2b521, 0x6f19a459, 0x93d17fd4,
+ 0x947f0ee0, 0x3bf7f3ac, 0xdd50a5af, 0xb035a69e, 0x90fc1457, 0x9c829fda,
+ 0x214e3240, 0xb311cada, 0xe6cf1f65, 0x5b820274, 0x00000103};
+OPENSSL_UNUSED static const uint32_t kP521MontGY[] = {
+ 0x28460e4a, 0x3b4fe8b3, 0x20445f4a, 0x43513961, 0xb09a9e38, 0x809fd683,
+ 0x2062a85c, 0x4caf7a13, 0x164bf739, 0x8b939f33, 0x340bd7de, 0x24abcda2,
+ 0xeccc7aa2, 0xda163e8d, 0x022e452f, 0x3c4d1de0, 0x000000b5};
+#else
+#error "unknown word size"
+#endif
diff --git a/src/crypto/fipsmodule/ec/ec.c b/src/crypto/fipsmodule/ec/ec.c
index 61ecc1f3..00587a1f 100644
--- a/src/crypto/fipsmodule/ec/ec.c
+++ b/src/crypto/fipsmodule/ec/ec.c
@@ -80,270 +80,147 @@
#include "../bn/internal.h"
#include "../delocate.h"
+#include "builtin_curves.h"
-static void ec_point_free(EC_POINT *point, int free_group);
-
-static const uint8_t kP224Params[6 * 28] = {
- // p = 2^224 - 2^96 + 1
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x01,
- // a
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFE,
- // b
- 0xB4, 0x05, 0x0A, 0x85, 0x0C, 0x04, 0xB3, 0xAB, 0xF5, 0x41, 0x32, 0x56,
- 0x50, 0x44, 0xB0, 0xB7, 0xD7, 0xBF, 0xD8, 0xBA, 0x27, 0x0B, 0x39, 0x43,
- 0x23, 0x55, 0xFF, 0xB4,
- // x
- 0xB7, 0x0E, 0x0C, 0xBD, 0x6B, 0xB4, 0xBF, 0x7F, 0x32, 0x13, 0x90, 0xB9,
- 0x4A, 0x03, 0xC1, 0xD3, 0x56, 0xC2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xD6,
- 0x11, 0x5C, 0x1D, 0x21,
- // y
- 0xbd, 0x37, 0x63, 0x88, 0xb5, 0xf7, 0x23, 0xfb, 0x4c, 0x22, 0xdf, 0xe6,
- 0xcd, 0x43, 0x75, 0xa0, 0x5a, 0x07, 0x47, 0x64, 0x44, 0xd5, 0x81, 0x99,
- 0x85, 0x00, 0x7e, 0x34,
- // order
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0x16, 0xA2, 0xE0, 0xB8, 0xF0, 0x3E, 0x13, 0xDD, 0x29, 0x45,
- 0x5C, 0x5C, 0x2A, 0x3D,
-};
-
-static const uint8_t kP256Params[6 * 32] = {
- // p = 2^256 - 2^224 + 2^192 + 2^96 - 1
- 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- // a
- 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC,
- // b
- 0x5A, 0xC6, 0x35, 0xD8, 0xAA, 0x3A, 0x93, 0xE7, 0xB3, 0xEB, 0xBD, 0x55,
- 0x76, 0x98, 0x86, 0xBC, 0x65, 0x1D, 0x06, 0xB0, 0xCC, 0x53, 0xB0, 0xF6,
- 0x3B, 0xCE, 0x3C, 0x3E, 0x27, 0xD2, 0x60, 0x4B,
- // x
- 0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47, 0xF8, 0xBC, 0xE6, 0xE5,
- 0x63, 0xA4, 0x40, 0xF2, 0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33, 0xA0,
- 0xF4, 0xA1, 0x39, 0x45, 0xD8, 0x98, 0xC2, 0x96,
- // y
- 0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, 0x8e, 0xe7, 0xeb, 0x4a,
- 0x7c, 0x0f, 0x9e, 0x16, 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce,
- 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5,
- // order
- 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84,
- 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51,
-};
-
-static const uint8_t kP384Params[6 * 48] = {
- // p = 2^384 - 2^128 - 2^96 + 2^32 - 1
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
- // a
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFC,
- // b
- 0xB3, 0x31, 0x2F, 0xA7, 0xE2, 0x3E, 0xE7, 0xE4, 0x98, 0x8E, 0x05, 0x6B,
- 0xE3, 0xF8, 0x2D, 0x19, 0x18, 0x1D, 0x9C, 0x6E, 0xFE, 0x81, 0x41, 0x12,
- 0x03, 0x14, 0x08, 0x8F, 0x50, 0x13, 0x87, 0x5A, 0xC6, 0x56, 0x39, 0x8D,
- 0x8A, 0x2E, 0xD1, 0x9D, 0x2A, 0x85, 0xC8, 0xED, 0xD3, 0xEC, 0x2A, 0xEF,
- // x
- 0xAA, 0x87, 0xCA, 0x22, 0xBE, 0x8B, 0x05, 0x37, 0x8E, 0xB1, 0xC7, 0x1E,
- 0xF3, 0x20, 0xAD, 0x74, 0x6E, 0x1D, 0x3B, 0x62, 0x8B, 0xA7, 0x9B, 0x98,
- 0x59, 0xF7, 0x41, 0xE0, 0x82, 0x54, 0x2A, 0x38, 0x55, 0x02, 0xF2, 0x5D,
- 0xBF, 0x55, 0x29, 0x6C, 0x3A, 0x54, 0x5E, 0x38, 0x72, 0x76, 0x0A, 0xB7,
- // y
- 0x36, 0x17, 0xde, 0x4a, 0x96, 0x26, 0x2c, 0x6f, 0x5d, 0x9e, 0x98, 0xbf,
- 0x92, 0x92, 0xdc, 0x29, 0xf8, 0xf4, 0x1d, 0xbd, 0x28, 0x9a, 0x14, 0x7c,
- 0xe9, 0xda, 0x31, 0x13, 0xb5, 0xf0, 0xb8, 0xc0, 0x0a, 0x60, 0xb1, 0xce,
- 0x1d, 0x7e, 0x81, 0x9d, 0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5f,
- // order
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xC7, 0x63, 0x4D, 0x81, 0xF4, 0x37, 0x2D, 0xDF, 0x58, 0x1A, 0x0D, 0xB2,
- 0x48, 0xB0, 0xA7, 0x7A, 0xEC, 0xEC, 0x19, 0x6A, 0xCC, 0xC5, 0x29, 0x73,
-};
-
-static const uint8_t kP521Params[6 * 66] = {
- // p = 2^521 - 1
- 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- // a
- 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC,
- // b
- 0x00, 0x51, 0x95, 0x3E, 0xB9, 0x61, 0x8E, 0x1C, 0x9A, 0x1F, 0x92, 0x9A,
- 0x21, 0xA0, 0xB6, 0x85, 0x40, 0xEE, 0xA2, 0xDA, 0x72, 0x5B, 0x99, 0xB3,
- 0x15, 0xF3, 0xB8, 0xB4, 0x89, 0x91, 0x8E, 0xF1, 0x09, 0xE1, 0x56, 0x19,
- 0x39, 0x51, 0xEC, 0x7E, 0x93, 0x7B, 0x16, 0x52, 0xC0, 0xBD, 0x3B, 0xB1,
- 0xBF, 0x07, 0x35, 0x73, 0xDF, 0x88, 0x3D, 0x2C, 0x34, 0xF1, 0xEF, 0x45,
- 0x1F, 0xD4, 0x6B, 0x50, 0x3F, 0x00,
- // x
- 0x00, 0xC6, 0x85, 0x8E, 0x06, 0xB7, 0x04, 0x04, 0xE9, 0xCD, 0x9E, 0x3E,
- 0xCB, 0x66, 0x23, 0x95, 0xB4, 0x42, 0x9C, 0x64, 0x81, 0x39, 0x05, 0x3F,
- 0xB5, 0x21, 0xF8, 0x28, 0xAF, 0x60, 0x6B, 0x4D, 0x3D, 0xBA, 0xA1, 0x4B,
- 0x5E, 0x77, 0xEF, 0xE7, 0x59, 0x28, 0xFE, 0x1D, 0xC1, 0x27, 0xA2, 0xFF,
- 0xA8, 0xDE, 0x33, 0x48, 0xB3, 0xC1, 0x85, 0x6A, 0x42, 0x9B, 0xF9, 0x7E,
- 0x7E, 0x31, 0xC2, 0xE5, 0xBD, 0x66,
- // y
- 0x01, 0x18, 0x39, 0x29, 0x6a, 0x78, 0x9a, 0x3b, 0xc0, 0x04, 0x5c, 0x8a,
- 0x5f, 0xb4, 0x2c, 0x7d, 0x1b, 0xd9, 0x98, 0xf5, 0x44, 0x49, 0x57, 0x9b,
- 0x44, 0x68, 0x17, 0xaf, 0xbd, 0x17, 0x27, 0x3e, 0x66, 0x2c, 0x97, 0xee,
- 0x72, 0x99, 0x5e, 0xf4, 0x26, 0x40, 0xc5, 0x50, 0xb9, 0x01, 0x3f, 0xad,
- 0x07, 0x61, 0x35, 0x3c, 0x70, 0x86, 0xa2, 0x72, 0xc2, 0x40, 0x88, 0xbe,
- 0x94, 0x76, 0x9f, 0xd1, 0x66, 0x50,
- // order
- 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFA, 0x51, 0x86,
- 0x87, 0x83, 0xBF, 0x2F, 0x96, 0x6B, 0x7F, 0xCC, 0x01, 0x48, 0xF7, 0x09,
- 0xA5, 0xD0, 0x3B, 0xB5, 0xC9, 0xB8, 0x89, 0x9C, 0x47, 0xAE, 0xBB, 0x6F,
- 0xB7, 0x1E, 0x91, 0x38, 0x64, 0x09,
-};
-
-DEFINE_METHOD_FUNCTION(struct built_in_curves, OPENSSL_built_in_curves) {
- // 1.3.132.0.35
- static const uint8_t kOIDP521[] = {0x2b, 0x81, 0x04, 0x00, 0x23};
- out->curves[0].nid = NID_secp521r1;
- out->curves[0].oid = kOIDP521;
- out->curves[0].oid_len = sizeof(kOIDP521);
- out->curves[0].comment = "NIST P-521";
- out->curves[0].param_len = 66;
- out->curves[0].params = kP521Params;
- out->curves[0].method = EC_GFp_mont_method();
- // 1.3.132.0.34
- static const uint8_t kOIDP384[] = {0x2b, 0x81, 0x04, 0x00, 0x22};
- out->curves[1].nid = NID_secp384r1;
- out->curves[1].oid = kOIDP384;
- out->curves[1].oid_len = sizeof(kOIDP384);
- out->curves[1].comment = "NIST P-384";
- out->curves[1].param_len = 48;
- out->curves[1].params = kP384Params;
- out->curves[1].method = EC_GFp_mont_method();
+static void ec_point_free(EC_POINT *point, int free_group);
- // 1.2.840.10045.3.1.7
- static const uint8_t kOIDP256[] = {0x2a, 0x86, 0x48, 0xce,
- 0x3d, 0x03, 0x01, 0x07};
- out->curves[2].nid = NID_X9_62_prime256v1;
- out->curves[2].oid = kOIDP256;
- out->curves[2].oid_len = sizeof(kOIDP256);
- out->curves[2].comment = "NIST P-256";
- out->curves[2].param_len = 32;
- out->curves[2].params = kP256Params;
- out->curves[2].method =
-#if !defined(OPENSSL_NO_ASM) && \
- (defined(OPENSSL_X86_64) || defined(OPENSSL_AARCH64)) && \
- !defined(OPENSSL_SMALL)
- EC_GFp_nistz256_method();
+static void ec_group_init_static_mont(BN_MONT_CTX *mont, size_t num_words,
+ const BN_ULONG *modulus,
+ const BN_ULONG *rr, uint64_t n0) {
+ bn_set_static_words(&mont->N, modulus, num_words);
+ bn_set_static_words(&mont->RR, rr, num_words);
+#if defined(OPENSSL_64_BIT)
+ mont->n0[0] = n0;
+#elif defined(OPENSSL_32_BIT)
+ mont->n0[0] = (uint32_t)n0;
+ mont->n0[1] = (uint32_t)(n0 >> 32);
#else
- EC_GFp_nistp256_method();
+#error "unknown word length"
#endif
+}
+static void ec_group_set_a_minus3(EC_GROUP *group) {
+ const EC_FELEM *one = ec_felem_one(group);
+ group->a_is_minus3 = 1;
+ ec_felem_neg(group, &group->a, one);
+ ec_felem_sub(group, &group->a, &group->a, one);
+ ec_felem_sub(group, &group->a, &group->a, one);
+}
+
+DEFINE_METHOD_FUNCTION(EC_GROUP, EC_group_p224) {
+ out->curve_name = NID_secp224r1;
+ out->comment = "NIST P-224";
// 1.3.132.0.33
static const uint8_t kOIDP224[] = {0x2b, 0x81, 0x04, 0x00, 0x21};
- out->curves[3].nid = NID_secp224r1;
- out->curves[3].oid = kOIDP224;
- out->curves[3].oid_len = sizeof(kOIDP224);
- out->curves[3].comment = "NIST P-224";
- out->curves[3].param_len = 28;
- out->curves[3].params = kP224Params;
- out->curves[3].method =
+ OPENSSL_memcpy(out->oid, kOIDP224, sizeof(kOIDP224));
+ out->oid_len = sizeof(kOIDP224);
+
+ ec_group_init_static_mont(&out->field, OPENSSL_ARRAY_SIZE(kP224Field),
+ kP224Field, kP224FieldRR, kP224FieldN0);
+ ec_group_init_static_mont(&out->order, OPENSSL_ARRAY_SIZE(kP224Order),
+ kP224Order, kP224OrderRR, kP224OrderN0);
+
#if defined(BORINGSSL_HAS_UINT128) && !defined(OPENSSL_SMALL)
- EC_GFp_nistp224_method();
+ out->meth = EC_GFp_nistp224_method();
+ OPENSSL_memcpy(out->generator.raw.X.words, kP224GX, sizeof(kP224GX));
+ OPENSSL_memcpy(out->generator.raw.Y.words, kP224GY, sizeof(kP224GY));
+ out->generator.raw.Z.words[0] = 1;
+ OPENSSL_memcpy(out->b.words, kP224B, sizeof(kP224B));
#else
- EC_GFp_mont_method();
+ out->meth = EC_GFp_mont_method();
+ OPENSSL_memcpy(out->generator.raw.X.words, kP224MontGX, sizeof(kP224MontGX));
+ OPENSSL_memcpy(out->generator.raw.Y.words, kP224MontGY, sizeof(kP224MontGY));
+ OPENSSL_memcpy(out->generator.raw.Z.words, kP224FieldR, sizeof(kP224FieldR));
+ OPENSSL_memcpy(out->b.words, kP224MontB, sizeof(kP224MontB));
#endif
-}
-
-EC_GROUP *ec_group_new(const EC_METHOD *meth) {
- EC_GROUP *ret;
-
- if (meth == NULL) {
- OPENSSL_PUT_ERROR(EC, EC_R_SLOT_FULL);
- return NULL;
- }
-
- if (meth->group_init == 0) {
- OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
- return NULL;
- }
-
- ret = OPENSSL_malloc(sizeof(EC_GROUP));
- if (ret == NULL) {
- return NULL;
- }
- OPENSSL_memset(ret, 0, sizeof(EC_GROUP));
+ out->generator.group = out;
- ret->references = 1;
- ret->meth = meth;
- BN_init(&ret->order);
-
- if (!meth->group_init(ret)) {
- OPENSSL_free(ret);
- return NULL;
- }
-
- return ret;
+ ec_group_set_a_minus3(out);
+ out->has_order = 1;
+ out->field_greater_than_order = 1;
}
-static int ec_group_set_generator(EC_GROUP *group, const EC_AFFINE *generator,
- const BIGNUM *order) {
- assert(group->generator == NULL);
-
- if (!BN_copy(&group->order, order)) {
- return 0;
- }
- // Store the order in minimal form, so it can be used with |BN_ULONG| arrays.
- bn_set_minimal_width(&group->order);
+DEFINE_METHOD_FUNCTION(EC_GROUP, EC_group_p256) {
+ out->curve_name = NID_X9_62_prime256v1;
+ out->comment = "NIST P-256";
+ // 1.2.840.10045.3.1.7
+ static const uint8_t kOIDP256[] = {0x2a, 0x86, 0x48, 0xce,
+ 0x3d, 0x03, 0x01, 0x07};
+ OPENSSL_memcpy(out->oid, kOIDP256, sizeof(kOIDP256));
+ out->oid_len = sizeof(kOIDP256);
- BN_MONT_CTX_free(group->order_mont);
- group->order_mont = BN_MONT_CTX_new_for_modulus(&group->order, NULL);
- if (group->order_mont == NULL) {
- return 0;
- }
+ ec_group_init_static_mont(&out->field, OPENSSL_ARRAY_SIZE(kP256Field),
+ kP256Field, kP256FieldRR, kP256FieldN0);
+ ec_group_init_static_mont(&out->order, OPENSSL_ARRAY_SIZE(kP256Order),
+ kP256Order, kP256OrderRR, kP256OrderN0);
- group->field_greater_than_order = BN_cmp(&group->field, order) > 0;
- if (group->field_greater_than_order) {
- BIGNUM tmp;
- BN_init(&tmp);
- int ok =
- BN_sub(&tmp, &group->field, order) &&
- bn_copy_words(group->field_minus_order.words, group->field.width, &tmp);
- BN_free(&tmp);
- if (!ok) {
- return 0;
- }
- }
-
- group->generator = EC_POINT_new(group);
- if (group->generator == NULL) {
- return 0;
- }
- ec_affine_to_jacobian(group, &group->generator->raw, generator);
- assert(ec_felem_equal(group, &group->one, &group->generator->raw.Z));
+#if !defined(OPENSSL_NO_ASM) && \
+ (defined(OPENSSL_X86_64) || defined(OPENSSL_AARCH64)) && \
+ !defined(OPENSSL_SMALL)
+ out->meth = EC_GFp_nistz256_method();
+#else
+ out->meth = EC_GFp_nistp256_method();
+#endif
+ out->generator.group = out;
+ OPENSSL_memcpy(out->generator.raw.X.words, kP256MontGX, sizeof(kP256MontGX));
+ OPENSSL_memcpy(out->generator.raw.Y.words, kP256MontGY, sizeof(kP256MontGY));
+ OPENSSL_memcpy(out->generator.raw.Z.words, kP256FieldR, sizeof(kP256FieldR));
+ OPENSSL_memcpy(out->b.words, kP256MontB, sizeof(kP256MontB));
+
+ ec_group_set_a_minus3(out);
+ out->has_order = 1;
+ out->field_greater_than_order = 1;
+}
- // Avoid a reference cycle. |group->generator| does not maintain an owning
- // pointer to |group|.
- int is_zero = CRYPTO_refcount_dec_and_test_zero(&group->references);
+DEFINE_METHOD_FUNCTION(EC_GROUP, EC_group_p384) {
+ out->curve_name = NID_secp384r1;
+ out->comment = "NIST P-384";
+ // 1.3.132.0.34
+ static const uint8_t kOIDP384[] = {0x2b, 0x81, 0x04, 0x00, 0x22};
+ OPENSSL_memcpy(out->oid, kOIDP384, sizeof(kOIDP384));
+ out->oid_len = sizeof(kOIDP384);
+
+ ec_group_init_static_mont(&out->field, OPENSSL_ARRAY_SIZE(kP384Field),
+ kP384Field, kP384FieldRR, kP384FieldN0);
+ ec_group_init_static_mont(&out->order, OPENSSL_ARRAY_SIZE(kP384Order),
+ kP384Order, kP384OrderRR, kP384OrderN0);
+
+ out->meth = EC_GFp_mont_method();
+ out->generator.group = out;
+ OPENSSL_memcpy(out->generator.raw.X.words, kP384MontGX, sizeof(kP384MontGX));
+ OPENSSL_memcpy(out->generator.raw.Y.words, kP384MontGY, sizeof(kP384MontGY));
+ OPENSSL_memcpy(out->generator.raw.Z.words, kP384FieldR, sizeof(kP384FieldR));
+ OPENSSL_memcpy(out->b.words, kP384MontB, sizeof(kP384MontB));
+
+ ec_group_set_a_minus3(out);
+ out->has_order = 1;
+ out->field_greater_than_order = 1;
+}
- assert(!is_zero);
- (void)is_zero;
- return 1;
+DEFINE_METHOD_FUNCTION(EC_GROUP, EC_group_p521) {
+ out->curve_name = NID_secp521r1;
+ out->comment = "NIST P-521";
+ // 1.3.132.0.35
+ static const uint8_t kOIDP521[] = {0x2b, 0x81, 0x04, 0x00, 0x23};
+ OPENSSL_memcpy(out->oid, kOIDP521, sizeof(kOIDP521));
+ out->oid_len = sizeof(kOIDP521);
+
+ ec_group_init_static_mont(&out->field, OPENSSL_ARRAY_SIZE(kP521Field),
+ kP521Field, kP521FieldRR, kP521FieldN0);
+ ec_group_init_static_mont(&out->order, OPENSSL_ARRAY_SIZE(kP521Order),
+ kP521Order, kP521OrderRR, kP521OrderN0);
+
+ out->meth = EC_GFp_mont_method();
+ out->generator.group = out;
+ OPENSSL_memcpy(out->generator.raw.X.words, kP521MontGX, sizeof(kP521MontGX));
+ OPENSSL_memcpy(out->generator.raw.Y.words, kP521MontGY, sizeof(kP521MontGY));
+ OPENSSL_memcpy(out->generator.raw.Z.words, kP521FieldR, sizeof(kP521FieldR));
+ OPENSSL_memcpy(out->b.words, kP521MontB, sizeof(kP521MontB));
+
+ ec_group_set_a_minus3(out);
+ out->has_order = 1;
+ out->field_greater_than_order = 1;
}
EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, const BIGNUM *a,
@@ -373,9 +250,17 @@ EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, const BIGNUM *a,
goto err;
}
- ret = ec_group_new(EC_GFp_mont_method());
- if (ret == NULL ||
- !ret->meth->group_set_curve(ret, p, a_reduced, b_reduced, ctx)) {
+ ret = OPENSSL_malloc(sizeof(EC_GROUP));
+ if (ret == NULL) {
+ return NULL;
+ }
+ OPENSSL_memset(ret, 0, sizeof(EC_GROUP));
+ ret->references = 1;
+ ret->meth = EC_GFp_mont_method();
+ bn_mont_ctx_init(&ret->field);
+ bn_mont_ctx_init(&ret->order);
+ ret->generator.group = ret;
+ if (!ec_GFp_simple_group_set_curve(ret, p, a_reduced, b_reduced, ctx)) {
EC_GROUP_free(ret);
ret = NULL;
goto err;
@@ -389,7 +274,7 @@ err:
int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator,
const BIGNUM *order, const BIGNUM *cofactor) {
- if (group->curve_name != NID_undef || group->generator != NULL ||
+ if (group->curve_name != NID_undef || group->has_order ||
generator->group != group) {
// |EC_GROUP_set_generator| may only be used with |EC_GROUP|s returned by
// |EC_GROUP_new_curve_GFp| and may only used once on each group.
@@ -421,17 +306,22 @@ int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator,
!BN_lshift1(tmp, order)) {
goto err;
}
- if (BN_cmp(tmp, &group->field) <= 0) {
+ if (BN_cmp(tmp, &group->field.N) <= 0) {
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_GROUP_ORDER);
goto err;
}
EC_AFFINE affine;
if (!ec_jacobian_to_affine(group, &affine, &generator->raw) ||
- !ec_group_set_generator(group, &affine, order)) {
+ !BN_MONT_CTX_set(&group->order, order, NULL)) {
goto err;
}
+ group->field_greater_than_order = BN_cmp(&group->field.N, order) > 0;
+ group->generator.raw.X = affine.X;
+ group->generator.raw.Y = affine.Y;
+ // |raw.Z| was set to 1 by |EC_GROUP_new_curve_GFp|.
+ group->has_order = 1;
ret = 1;
err:
@@ -439,114 +329,20 @@ err:
return ret;
}
-static EC_GROUP *ec_group_new_from_data(const struct built_in_curve *curve) {
- EC_GROUP *group = NULL;
- BIGNUM *p = NULL, *a = NULL, *b = NULL, *order = NULL;
- int ok = 0;
-
- BN_CTX *ctx = BN_CTX_new();
- if (ctx == NULL) {
- goto err;
- }
-
- const unsigned param_len = curve->param_len;
- const uint8_t *params = curve->params;
-
- if (!(p = BN_bin2bn(params + 0 * param_len, param_len, NULL)) ||
- !(a = BN_bin2bn(params + 1 * param_len, param_len, NULL)) ||
- !(b = BN_bin2bn(params + 2 * param_len, param_len, NULL)) ||
- !(order = BN_bin2bn(params + 5 * param_len, param_len, NULL))) {
- OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
- goto err;
- }
-
- group = ec_group_new(curve->method);
- if (group == NULL ||
- !group->meth->group_set_curve(group, p, a, b, ctx)) {
- OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB);
- goto err;
- }
-
- EC_AFFINE G;
- EC_FELEM x, y;
- if (!ec_felem_from_bytes(group, &x, params + 3 * param_len, param_len) ||
- !ec_felem_from_bytes(group, &y, params + 4 * param_len, param_len) ||
- !ec_point_set_affine_coordinates(group, &G, &x, &y)) {
- goto err;
- }
-
- if (!ec_group_set_generator(group, &G, order)) {
- goto err;
- }
-
- ok = 1;
-
-err:
- if (!ok) {
- EC_GROUP_free(group);
- group = NULL;
- }
- BN_CTX_free(ctx);
- BN_free(p);
- BN_free(a);
- BN_free(b);
- BN_free(order);
- return group;
-}
-
-// Built-in groups are allocated lazily and static once allocated.
-// TODO(davidben): Make these actually static. https://crbug.com/boringssl/20.
-struct built_in_groups_st {
- EC_GROUP *groups[OPENSSL_NUM_BUILT_IN_CURVES];
-};
-DEFINE_BSS_GET(struct built_in_groups_st, built_in_groups)
-DEFINE_STATIC_MUTEX(built_in_groups_lock)
-
EC_GROUP *EC_GROUP_new_by_curve_name(int nid) {
- struct built_in_groups_st *groups = built_in_groups_bss_get();
- EC_GROUP **group_ptr = NULL;
- const struct built_in_curves *const curves = OPENSSL_built_in_curves();
- const struct built_in_curve *curve = NULL;
- for (size_t i = 0; i < OPENSSL_NUM_BUILT_IN_CURVES; i++) {
- if (curves->curves[i].nid == nid) {
- curve = &curves->curves[i];
- group_ptr = &groups->groups[i];
- break;
- }
- }
-
- if (curve == NULL) {
- OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP);
- return NULL;
- }
-
- CRYPTO_STATIC_MUTEX_lock_read(built_in_groups_lock_bss_get());
- EC_GROUP *ret = *group_ptr;
- CRYPTO_STATIC_MUTEX_unlock_read(built_in_groups_lock_bss_get());
- if (ret != NULL) {
- return ret;
- }
-
- ret = ec_group_new_from_data(curve);
- if (ret == NULL) {
- return NULL;
- }
-
- EC_GROUP *to_free = NULL;
- CRYPTO_STATIC_MUTEX_lock_write(built_in_groups_lock_bss_get());
- if (*group_ptr == NULL) {
- *group_ptr = ret;
- // Filling in |ret->curve_name| makes |EC_GROUP_free| and |EC_GROUP_dup|
- // into no-ops. At this point, |ret| is considered static.
- ret->curve_name = nid;
- } else {
- to_free = ret;
- ret = *group_ptr;
+ switch (nid) {
+ case NID_secp224r1:
+ return (EC_GROUP *)EC_group_p224();
+ case NID_X9_62_prime256v1:
+ return (EC_GROUP *)EC_group_p256();
+ case NID_secp384r1:
+ return (EC_GROUP *)EC_group_p384();
+ case NID_secp521r1:
+ return (EC_GROUP *)EC_group_p521();
+ default:
+ OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP);
+ return NULL;
}
- CRYPTO_STATIC_MUTEX_unlock_write(built_in_groups_lock_bss_get());
-
- EC_GROUP_free(to_free);
- return ret;
}
void EC_GROUP_free(EC_GROUP *group) {
@@ -557,14 +353,8 @@ void EC_GROUP_free(EC_GROUP *group) {
return;
}
- if (group->meth->group_finish != NULL) {
- group->meth->group_finish(group);
- }
-
- ec_point_free(group->generator, 0 /* don't free group */);
- BN_free(&group->order);
- BN_MONT_CTX_free(group->order_mont);
-
+ bn_mont_ctx_cleanup(&group->order);
+ bn_mont_ctx_cleanup(&group->field);
OPENSSL_free(group);
}
@@ -599,23 +389,22 @@ int EC_GROUP_cmp(const EC_GROUP *a, const EC_GROUP *b, BN_CTX *ignored) {
// structure. If |a| or |b| is incomplete (due to legacy OpenSSL mistakes,
// custom curve construction is sadly done in two parts) but otherwise not the
// same object, we consider them always unequal.
- return a->meth != b->meth ||
- a->generator == NULL ||
- b->generator == NULL ||
- BN_cmp(&a->order, &b->order) != 0 ||
- BN_cmp(&a->field, &b->field) != 0 ||
- !ec_felem_equal(a, &a->a, &b->a) ||
+ return a->meth != b->meth || //
+ !a->has_order || !b->has_order ||
+ BN_cmp(&a->order.N, &b->order.N) != 0 ||
+ BN_cmp(&a->field.N, &b->field.N) != 0 ||
+ !ec_felem_equal(a, &a->a, &b->a) || //
!ec_felem_equal(a, &a->b, &b->b) ||
- !ec_GFp_simple_points_equal(a, &a->generator->raw, &b->generator->raw);
+ !ec_GFp_simple_points_equal(a, &a->generator.raw, &b->generator.raw);
}
const EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *group) {
- return group->generator;
+ return group->has_order ? &group->generator : NULL;
}
const BIGNUM *EC_GROUP_get0_order(const EC_GROUP *group) {
- assert(!BN_is_zero(&group->order));
- return &group->order;
+ assert(group->has_order);
+ return &group->order.N;
}
int EC_GROUP_get_order(const EC_GROUP *group, BIGNUM *order, BN_CTX *ctx) {
@@ -626,7 +415,7 @@ int EC_GROUP_get_order(const EC_GROUP *group, BIGNUM *order, BN_CTX *ctx) {
}
int EC_GROUP_order_bits(const EC_GROUP *group) {
- return BN_num_bits(&group->order);
+ return BN_num_bits(&group->order.N);
}
int EC_GROUP_get_cofactor(const EC_GROUP *group, BIGNUM *cofactor,
@@ -643,7 +432,7 @@ int EC_GROUP_get_curve_GFp(const EC_GROUP *group, BIGNUM *out_p, BIGNUM *out_a,
int EC_GROUP_get_curve_name(const EC_GROUP *group) { return group->curve_name; }
unsigned EC_GROUP_get_degree(const EC_GROUP *group) {
- return BN_num_bits(&group->field);
+ return BN_num_bits(&group->field.N);
}
const char *EC_curve_nid2nist(int nid) {
@@ -801,20 +590,20 @@ int EC_POINT_get_affine_coordinates(const EC_GROUP *group,
return EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx);
}
-void ec_affine_to_jacobian(const EC_GROUP *group, EC_RAW_POINT *out,
+void ec_affine_to_jacobian(const EC_GROUP *group, EC_JACOBIAN *out,
const EC_AFFINE *p) {
out->X = p->X;
out->Y = p->Y;
- out->Z = group->one;
+ out->Z = *ec_felem_one(group);
}
int ec_jacobian_to_affine(const EC_GROUP *group, EC_AFFINE *out,
- const EC_RAW_POINT *p) {
+ const EC_JACOBIAN *p) {
return group->meth->point_get_affine_coordinates(group, p, &out->X, &out->Y);
}
int ec_jacobian_to_affine_batch(const EC_GROUP *group, EC_AFFINE *out,
- const EC_RAW_POINT *in, size_t num) {
+ const EC_JACOBIAN *in, size_t num) {
if (group->meth->jacobian_to_affine_batch == NULL) {
OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
@@ -842,10 +631,9 @@ int ec_point_set_affine_coordinates(const EC_GROUP *group, EC_AFFINE *out,
// return value by setting a known safe value. Note this may not be possible
// if the caller is in the process of constructing an arbitrary group and
// the generator is missing.
- if (group->generator != NULL) {
- assert(ec_felem_equal(group, &group->one, &group->generator->raw.Z));
- out->X = group->generator->raw.X;
- out->Y = group->generator->raw.Y;
+ if (group->has_order) {
+ out->X = group->generator.raw.X;
+ out->Y = group->generator.raw.Y;
}
return 0;
}
@@ -931,11 +719,10 @@ static int arbitrary_bignum_to_scalar(const EC_GROUP *group, EC_SCALAR *out,
ERR_clear_error();
// This is an unusual input, so we do not guarantee constant-time processing.
- const BIGNUM *order = &group->order;
BN_CTX_start(ctx);
BIGNUM *tmp = BN_CTX_get(ctx);
int ok = tmp != NULL &&
- BN_nnmod(tmp, in, order, ctx) &&
+ BN_nnmod(tmp, in, EC_GROUP_get0_order(group), ctx) &&
ec_bignum_to_scalar(group, out, tmp);
BN_CTX_end(ctx);
return ok;
@@ -990,13 +777,13 @@ int ec_point_mul_no_self_test(const EC_GROUP *group, EC_POINT *r,
if (p_scalar != NULL) {
EC_SCALAR scalar;
- EC_RAW_POINT tmp;
+ EC_JACOBIAN tmp;
if (!arbitrary_bignum_to_scalar(group, &scalar, p_scalar, ctx) ||
!ec_point_mul_scalar(group, &tmp, &p->raw, &scalar)) {
goto err;
}
if (g_scalar == NULL) {
- OPENSSL_memcpy(&r->raw, &tmp, sizeof(EC_RAW_POINT));
+ OPENSSL_memcpy(&r->raw, &tmp, sizeof(EC_JACOBIAN));
} else {
group->meth->add(group, &r->raw, &r->raw, &tmp);
}
@@ -1016,8 +803,8 @@ int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar,
return ec_point_mul_no_self_test(group, r, g_scalar, p, p_scalar, ctx);
}
-int ec_point_mul_scalar_public(const EC_GROUP *group, EC_RAW_POINT *r,
- const EC_SCALAR *g_scalar, const EC_RAW_POINT *p,
+int ec_point_mul_scalar_public(const EC_GROUP *group, EC_JACOBIAN *r,
+ const EC_SCALAR *g_scalar, const EC_JACOBIAN *p,
const EC_SCALAR *p_scalar) {
if (g_scalar == NULL || p_scalar == NULL || p == NULL) {
OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
@@ -1032,9 +819,9 @@ int ec_point_mul_scalar_public(const EC_GROUP *group, EC_RAW_POINT *r,
return 1;
}
-int ec_point_mul_scalar_public_batch(const EC_GROUP *group, EC_RAW_POINT *r,
+int ec_point_mul_scalar_public_batch(const EC_GROUP *group, EC_JACOBIAN *r,
const EC_SCALAR *g_scalar,
- const EC_RAW_POINT *points,
+ const EC_JACOBIAN *points,
const EC_SCALAR *scalars, size_t num) {
if (group->meth->mul_public_batch == NULL) {
OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
@@ -1045,8 +832,8 @@ int ec_point_mul_scalar_public_batch(const EC_GROUP *group, EC_RAW_POINT *r,
num);
}
-int ec_point_mul_scalar(const EC_GROUP *group, EC_RAW_POINT *r,
- const EC_RAW_POINT *p, const EC_SCALAR *scalar) {
+int ec_point_mul_scalar(const EC_GROUP *group, EC_JACOBIAN *r,
+ const EC_JACOBIAN *p, const EC_SCALAR *scalar) {
if (p == NULL || scalar == NULL) {
OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
return 0;
@@ -1064,7 +851,7 @@ int ec_point_mul_scalar(const EC_GROUP *group, EC_RAW_POINT *r,
return 1;
}
-int ec_point_mul_scalar_base(const EC_GROUP *group, EC_RAW_POINT *r,
+int ec_point_mul_scalar_base(const EC_GROUP *group, EC_JACOBIAN *r,
const EC_SCALAR *scalar) {
if (scalar == NULL) {
OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
@@ -1074,8 +861,10 @@ int ec_point_mul_scalar_base(const EC_GROUP *group, EC_RAW_POINT *r,
group->meth->mul_base(group, r, scalar);
// Check the result is on the curve to defend against fault attacks or bugs.
- // This has negligible cost compared to the multiplication.
- if (!ec_GFp_simple_is_on_curve(group, r)) {
+ // This has negligible cost compared to the multiplication. This can only
+ // happen on bug or CPU fault, so it okay to leak this. The alternative would
+ // be to proceed with bad data.
+ if (!constant_time_declassify_int(ec_GFp_simple_is_on_curve(group, r))) {
OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
return 0;
}
@@ -1083,10 +872,10 @@ int ec_point_mul_scalar_base(const EC_GROUP *group, EC_RAW_POINT *r,
return 1;
}
-int ec_point_mul_scalar_batch(const EC_GROUP *group, EC_RAW_POINT *r,
- const EC_RAW_POINT *p0, const EC_SCALAR *scalar0,
- const EC_RAW_POINT *p1, const EC_SCALAR *scalar1,
- const EC_RAW_POINT *p2,
+int ec_point_mul_scalar_batch(const EC_GROUP *group, EC_JACOBIAN *r,
+ const EC_JACOBIAN *p0, const EC_SCALAR *scalar0,
+ const EC_JACOBIAN *p1, const EC_SCALAR *scalar1,
+ const EC_JACOBIAN *p2,
const EC_SCALAR *scalar2) {
if (group->meth->mul_batch == NULL) {
OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
@@ -1106,7 +895,7 @@ int ec_point_mul_scalar_batch(const EC_GROUP *group, EC_RAW_POINT *r,
}
int ec_init_precomp(const EC_GROUP *group, EC_PRECOMP *out,
- const EC_RAW_POINT *p) {
+ const EC_JACOBIAN *p) {
if (group->meth->init_precomp == NULL) {
OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
@@ -1115,7 +904,7 @@ int ec_init_precomp(const EC_GROUP *group, EC_PRECOMP *out,
return group->meth->init_precomp(group, out, p);
}
-int ec_point_mul_scalar_precomp(const EC_GROUP *group, EC_RAW_POINT *r,
+int ec_point_mul_scalar_precomp(const EC_GROUP *group, EC_JACOBIAN *r,
const EC_PRECOMP *p0, const EC_SCALAR *scalar0,
const EC_PRECOMP *p1, const EC_SCALAR *scalar1,
const EC_PRECOMP *p2,
@@ -1137,8 +926,8 @@ int ec_point_mul_scalar_precomp(const EC_GROUP *group, EC_RAW_POINT *r,
return 1;
}
-void ec_point_select(const EC_GROUP *group, EC_RAW_POINT *out, BN_ULONG mask,
- const EC_RAW_POINT *a, const EC_RAW_POINT *b) {
+void ec_point_select(const EC_GROUP *group, EC_JACOBIAN *out, BN_ULONG mask,
+ const EC_JACOBIAN *a, const EC_JACOBIAN *b) {
ec_felem_select(group, &out->X, mask, &a->X, &b->X);
ec_felem_select(group, &out->Y, mask, &a->Y, &b->Y);
ec_felem_select(group, &out->Z, mask, &a->Z, &b->Z);
@@ -1159,13 +948,13 @@ void ec_precomp_select(const EC_GROUP *group, EC_PRECOMP *out, BN_ULONG mask,
}
}
-int ec_cmp_x_coordinate(const EC_GROUP *group, const EC_RAW_POINT *p,
+int ec_cmp_x_coordinate(const EC_GROUP *group, const EC_JACOBIAN *p,
const EC_SCALAR *r) {
return group->meth->cmp_x_coordinate(group, p, r);
}
int ec_get_x_coordinate_as_scalar(const EC_GROUP *group, EC_SCALAR *out,
- const EC_RAW_POINT *p) {
+ const EC_JACOBIAN *p) {
uint8_t bytes[EC_MAX_BYTES];
size_t len;
if (!ec_get_x_coordinate_as_bytes(group, bytes, &len, sizeof(bytes), p)) {
@@ -1191,7 +980,7 @@ int ec_get_x_coordinate_as_scalar(const EC_GROUP *group, EC_SCALAR *out,
//
// Additionally, one can manually check this property for built-in curves. It
// is enforced for legacy custom curves in |EC_GROUP_set_generator|.
- const BIGNUM *order = &group->order;
+ const BIGNUM *order = EC_GROUP_get0_order(group);
BN_ULONG words[EC_MAX_WORDS + 1] = {0};
bn_big_endian_to_words(words, order->width + 1, bytes, len);
bn_reduce_once(out->words, words, /*carry=*/words[order->width], order->d,
@@ -1201,8 +990,8 @@ int ec_get_x_coordinate_as_scalar(const EC_GROUP *group, EC_SCALAR *out,
int ec_get_x_coordinate_as_bytes(const EC_GROUP *group, uint8_t *out,
size_t *out_len, size_t max_out,
- const EC_RAW_POINT *p) {
- size_t len = BN_num_bytes(&group->field);
+ const EC_JACOBIAN *p) {
+ size_t len = BN_num_bytes(&group->field.N);
assert(len <= EC_MAX_BYTES);
if (max_out < len) {
OPENSSL_PUT_ERROR(EC, EC_R_BUFFER_TOO_SMALL);
@@ -1219,9 +1008,9 @@ int ec_get_x_coordinate_as_bytes(const EC_GROUP *group, uint8_t *out,
return 1;
}
-void ec_set_to_safe_point(const EC_GROUP *group, EC_RAW_POINT *out) {
- if (group->generator != NULL) {
- ec_GFp_simple_point_copy(out, &group->generator->raw);
+void ec_set_to_safe_point(const EC_GROUP *group, EC_JACOBIAN *out) {
+ if (group->has_order) {
+ ec_GFp_simple_point_copy(out, &group->generator.raw);
} else {
// The generator can be missing if the caller is in the process of
// constructing an arbitrary group. In this case, we give up and use the
@@ -1253,16 +1042,3 @@ void EC_GROUP_set_point_conversion_form(EC_GROUP *group,
abort();
}
}
-
-size_t EC_get_builtin_curves(EC_builtin_curve *out_curves,
- size_t max_num_curves) {
- const struct built_in_curves *const curves = OPENSSL_built_in_curves();
-
- for (size_t i = 0; i < max_num_curves && i < OPENSSL_NUM_BUILT_IN_CURVES;
- i++) {
- out_curves[i].comment = curves->curves[i].comment;
- out_curves[i].nid = curves->curves[i].nid;
- }
-
- return OPENSSL_NUM_BUILT_IN_CURVES;
-}
diff --git a/src/crypto/fipsmodule/ec/ec_key.c b/src/crypto/fipsmodule/ec/ec_key.c
index e427e3c5..90a4404c 100644
--- a/src/crypto/fipsmodule/ec/ec_key.c
+++ b/src/crypto/fipsmodule/ec/ec_key.c
@@ -93,8 +93,8 @@ static EC_WRAPPED_SCALAR *ec_wrapped_scalar_new(const EC_GROUP *group) {
OPENSSL_memset(wrapped, 0, sizeof(EC_WRAPPED_SCALAR));
wrapped->bignum.d = wrapped->scalar.words;
- wrapped->bignum.width = group->order.width;
- wrapped->bignum.dmax = group->order.width;
+ wrapped->bignum.width = group->order.N.width;
+ wrapped->bignum.dmax = group->order.N.width;
wrapped->bignum.flags = BN_FLG_STATIC_DATA;
return wrapped;
}
@@ -311,7 +311,7 @@ int EC_KEY_check_key(const EC_KEY *eckey) {
// NOTE: this is a FIPS pair-wise consistency check for the ECDH case. See SP
// 800-56Ar3, page 36.
if (eckey->priv_key != NULL) {
- EC_RAW_POINT point;
+ EC_JACOBIAN point;
if (!ec_point_mul_scalar_base(eckey->group, &point,
&eckey->priv_key->scalar)) {
OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB);
@@ -485,7 +485,7 @@ int EC_KEY_generate_key(EC_KEY *key) {
}
// Check that the group order is FIPS compliant (FIPS 186-4 B.4.2).
- if (BN_num_bits(EC_GROUP_get0_order(key->group)) < 160) {
+ if (EC_GROUP_order_bits(key->group) < 160) {
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_GROUP_ORDER);
return 0;
}
diff --git a/src/crypto/fipsmodule/ec/ec_montgomery.c b/src/crypto/fipsmodule/ec/ec_montgomery.c
index f458df9c..92289a5e 100644
--- a/src/crypto/fipsmodule/ec/ec_montgomery.c
+++ b/src/crypto/fipsmodule/ec/ec_montgomery.c
@@ -76,67 +76,35 @@
#include "internal.h"
-int ec_GFp_mont_group_init(EC_GROUP *group) {
- int ok;
-
- ok = ec_GFp_simple_group_init(group);
- group->mont = NULL;
- return ok;
-}
-
-void ec_GFp_mont_group_finish(EC_GROUP *group) {
- BN_MONT_CTX_free(group->mont);
- group->mont = NULL;
- ec_GFp_simple_group_finish(group);
-}
-
-int ec_GFp_mont_group_set_curve(EC_GROUP *group, const BIGNUM *p,
- const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) {
- BN_MONT_CTX_free(group->mont);
- group->mont = BN_MONT_CTX_new_for_modulus(p, ctx);
- if (group->mont == NULL) {
- OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
- return 0;
- }
-
- if (!ec_GFp_simple_group_set_curve(group, p, a, b, ctx)) {
- BN_MONT_CTX_free(group->mont);
- group->mont = NULL;
- return 0;
- }
-
- return 1;
-}
-
static void ec_GFp_mont_felem_to_montgomery(const EC_GROUP *group,
EC_FELEM *out, const EC_FELEM *in) {
- bn_to_montgomery_small(out->words, in->words, group->field.width,
- group->mont);
+ bn_to_montgomery_small(out->words, in->words, group->field.N.width,
+ &group->field);
}
static void ec_GFp_mont_felem_from_montgomery(const EC_GROUP *group,
EC_FELEM *out,
const EC_FELEM *in) {
- bn_from_montgomery_small(out->words, group->field.width, in->words,
- group->field.width, group->mont);
+ bn_from_montgomery_small(out->words, group->field.N.width, in->words,
+ group->field.N.width, &group->field);
}
static void ec_GFp_mont_felem_inv0(const EC_GROUP *group, EC_FELEM *out,
const EC_FELEM *a) {
- bn_mod_inverse0_prime_mont_small(out->words, a->words, group->field.width,
- group->mont);
+ bn_mod_inverse0_prime_mont_small(out->words, a->words, group->field.N.width,
+ &group->field);
}
void ec_GFp_mont_felem_mul(const EC_GROUP *group, EC_FELEM *r,
const EC_FELEM *a, const EC_FELEM *b) {
- bn_mod_mul_montgomery_small(r->words, a->words, b->words, group->field.width,
- group->mont);
+ bn_mod_mul_montgomery_small(r->words, a->words, b->words,
+ group->field.N.width, &group->field);
}
void ec_GFp_mont_felem_sqr(const EC_GROUP *group, EC_FELEM *r,
const EC_FELEM *a) {
- bn_mod_mul_montgomery_small(r->words, a->words, a->words, group->field.width,
- group->mont);
+ bn_mod_mul_montgomery_small(r->words, a->words, a->words,
+ group->field.N.width, &group->field);
}
void ec_GFp_mont_felem_to_bytes(const EC_GROUP *group, uint8_t *out,
@@ -159,8 +127,8 @@ int ec_GFp_mont_felem_from_bytes(const EC_GROUP *group, EC_FELEM *out,
void ec_GFp_mont_felem_reduce(const EC_GROUP *group, EC_FELEM *out,
const BN_ULONG *words, size_t num) {
// Convert "from" Montgomery form so the value is reduced mod p.
- bn_from_montgomery_small(out->words, group->field.width, words, num,
- group->mont);
+ bn_from_montgomery_small(out->words, group->field.N.width, words, num,
+ &group->field);
// Convert "to" Montgomery form to remove the R^-1 factor added.
ec_GFp_mont_felem_to_montgomery(group, out, out);
// Convert to Montgomery form to match this implementation's representation.
@@ -170,14 +138,15 @@ void ec_GFp_mont_felem_reduce(const EC_GROUP *group, EC_FELEM *out,
void ec_GFp_mont_felem_exp(const EC_GROUP *group, EC_FELEM *out,
const EC_FELEM *a, const BN_ULONG *exp,
size_t num_exp) {
- bn_mod_exp_mont_small(out->words, a->words, group->field.width, exp, num_exp,
- group->mont);
+ bn_mod_exp_mont_small(out->words, a->words, group->field.N.width, exp,
+ num_exp, &group->field);
}
static int ec_GFp_mont_point_get_affine_coordinates(const EC_GROUP *group,
- const EC_RAW_POINT *point,
+ const EC_JACOBIAN *point,
EC_FELEM *x, EC_FELEM *y) {
- if (ec_GFp_simple_is_at_infinity(group, point)) {
+ if (constant_time_declassify_int(
+ ec_GFp_simple_is_at_infinity(group, point))) {
OPENSSL_PUT_ERROR(EC, EC_R_POINT_AT_INFINITY);
return 0;
}
@@ -202,7 +171,7 @@ static int ec_GFp_mont_point_get_affine_coordinates(const EC_GROUP *group,
static int ec_GFp_mont_jacobian_to_affine_batch(const EC_GROUP *group,
EC_AFFINE *out,
- const EC_RAW_POINT *in,
+ const EC_JACOBIAN *in,
size_t num) {
if (num == 0) {
return 1;
@@ -246,8 +215,8 @@ static int ec_GFp_mont_jacobian_to_affine_batch(const EC_GROUP *group,
return 1;
}
-void ec_GFp_mont_add(const EC_GROUP *group, EC_RAW_POINT *out,
- const EC_RAW_POINT *a, const EC_RAW_POINT *b) {
+void ec_GFp_mont_add(const EC_GROUP *group, EC_JACOBIAN *out,
+ const EC_JACOBIAN *a, const EC_JACOBIAN *b) {
if (a == b) {
ec_GFp_mont_dbl(group, out, a);
return;
@@ -317,7 +286,7 @@ void ec_GFp_mont_add(const EC_GROUP *group, EC_RAW_POINT *out,
// This case will never occur in the constant-time |ec_GFp_mont_mul|.
BN_ULONG is_nontrivial_double = ~xneq & ~yneq & z1nz & z2nz;
- if (is_nontrivial_double) {
+ if (constant_time_declassify_w(is_nontrivial_double)) {
ec_GFp_mont_dbl(group, out, a);
return;
}
@@ -357,8 +326,8 @@ void ec_GFp_mont_add(const EC_GROUP *group, EC_RAW_POINT *out,
ec_felem_select(group, &out->Z, z2nz, &z_out, &a->Z);
}
-void ec_GFp_mont_dbl(const EC_GROUP *group, EC_RAW_POINT *r,
- const EC_RAW_POINT *a) {
+void ec_GFp_mont_dbl(const EC_GROUP *group, EC_JACOBIAN *r,
+ const EC_JACOBIAN *a) {
if (group->a_is_minus3) {
// The method is taken from:
// http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b
@@ -453,10 +422,10 @@ void ec_GFp_mont_dbl(const EC_GROUP *group, EC_RAW_POINT *r,
}
static int ec_GFp_mont_cmp_x_coordinate(const EC_GROUP *group,
- const EC_RAW_POINT *p,
+ const EC_JACOBIAN *p,
const EC_SCALAR *r) {
if (!group->field_greater_than_order ||
- group->field.width != group->order.width) {
+ group->field.N.width != group->order.N.width) {
// Do not bother optimizing this case. p > order in all commonly-used
// curves.
return ec_GFp_simple_cmp_x_coordinate(group, p, r);
@@ -472,7 +441,7 @@ static int ec_GFp_mont_cmp_x_coordinate(const EC_GROUP *group,
EC_FELEM r_Z2, Z2_mont, X;
ec_GFp_mont_felem_mul(group, &Z2_mont, &p->Z, &p->Z);
// r < order < p, so this is valid.
- OPENSSL_memcpy(r_Z2.words, r->words, group->field.width * sizeof(BN_ULONG));
+ OPENSSL_memcpy(r_Z2.words, r->words, group->field.N.width * sizeof(BN_ULONG));
ec_GFp_mont_felem_mul(group, &r_Z2, &r_Z2, &Z2_mont);
ec_GFp_mont_felem_from_montgomery(group, &X, &p->X);
@@ -484,10 +453,11 @@ static int ec_GFp_mont_cmp_x_coordinate(const EC_GROUP *group,
// Therefore there is a small possibility, less than 1/2^128, that group_order
// < p.x < P. in that case we need not only to compare against |r| but also to
// compare against r+group_order.
- if (bn_less_than_words(r->words, group->field_minus_order.words,
- group->field.width)) {
- // We can ignore the carry because: r + group_order < p < 2^256.
- bn_add_words(r_Z2.words, r->words, group->order.d, group->field.width);
+ BN_ULONG carry = bn_add_words(r_Z2.words, r->words, group->order.N.d,
+ group->field.N.width);
+ if (carry == 0 &&
+ bn_less_than_words(r_Z2.words, group->field.N.d, group->field.N.width)) {
+ // r + group_order < p, so compare (r + group_order) * Z^2 against X.
ec_GFp_mont_felem_mul(group, &r_Z2, &r_Z2, &Z2_mont);
if (ec_felem_equal(group, &r_Z2, &X)) {
return 1;
@@ -498,9 +468,6 @@ static int ec_GFp_mont_cmp_x_coordinate(const EC_GROUP *group,
}
DEFINE_METHOD_FUNCTION(EC_METHOD, EC_GFp_mont_method) {
- out->group_init = ec_GFp_mont_group_init;
- out->group_finish = ec_GFp_mont_group_finish;
- out->group_set_curve = ec_GFp_mont_group_set_curve;
out->point_get_affine_coordinates = ec_GFp_mont_point_get_affine_coordinates;
out->jacobian_to_affine_batch = ec_GFp_mont_jacobian_to_affine_batch;
out->add = ec_GFp_mont_add;
diff --git a/src/crypto/fipsmodule/ec/ec_test.cc b/src/crypto/fipsmodule/ec/ec_test.cc
index 9ccc54b7..75e11f84 100644
--- a/src/crypto/fipsmodule/ec/ec_test.cc
+++ b/src/crypto/fipsmodule/ec/ec_test.cc
@@ -430,11 +430,8 @@ TEST(ECTest, SetKeyWithoutGroup) {
EXPECT_FALSE(EC_KEY_set_private_key(key.get(), BN_value_one()));
// Public keys may not be configured without a group.
- bssl::UniquePtr<EC_GROUP> group(
- EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
- ASSERT_TRUE(group);
- EXPECT_FALSE(
- EC_KEY_set_public_key(key.get(), EC_GROUP_get0_generator(group.get())));
+ EXPECT_FALSE(EC_KEY_set_public_key(key.get(),
+ EC_GROUP_get0_generator(EC_group_p256())));
}
TEST(ECTest, SetNULLKey) {
@@ -454,16 +451,13 @@ TEST(ECTest, SetNULLKey) {
TEST(ECTest, GroupMismatch) {
bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(NID_secp384r1));
ASSERT_TRUE(key);
- bssl::UniquePtr<EC_GROUP> p256(
- EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
- ASSERT_TRUE(p256);
// Changing a key's group is invalid.
- EXPECT_FALSE(EC_KEY_set_group(key.get(), p256.get()));
+ EXPECT_FALSE(EC_KEY_set_group(key.get(), EC_group_p256()));
// Configuring a public key with the wrong group is invalid.
- EXPECT_FALSE(
- EC_KEY_set_public_key(key.get(), EC_GROUP_get0_generator(p256.get())));
+ EXPECT_FALSE(EC_KEY_set_public_key(key.get(),
+ EC_GROUP_get0_generator(EC_group_p256())));
}
TEST(ECTest, EmptyKey) {
@@ -531,15 +525,15 @@ TEST(ECTest, BrainpoolP256r1) {
class ECCurveTest : public testing::TestWithParam<int> {
public:
- const EC_GROUP *group() const { return group_.get(); }
+ const EC_GROUP *group() const { return group_; }
void SetUp() override {
- group_.reset(EC_GROUP_new_by_curve_name(GetParam()));
+ group_ = EC_GROUP_new_by_curve_name(GetParam());
ASSERT_TRUE(group_);
}
private:
- bssl::UniquePtr<EC_GROUP> group_;
+ const EC_GROUP *group_;
};
TEST_P(ECCurveTest, SetAffine) {
@@ -995,24 +989,23 @@ static std::string CurveToString(const testing::TestParamInfo<int> &params) {
INSTANTIATE_TEST_SUITE_P(All, ECCurveTest, testing::ValuesIn(AllCurves()),
CurveToString);
-static bssl::UniquePtr<EC_GROUP> GetCurve(FileTest *t, const char *key) {
+static const EC_GROUP *GetCurve(FileTest *t, const char *key) {
std::string curve_name;
if (!t->GetAttribute(&curve_name, key)) {
return nullptr;
}
if (curve_name == "P-224") {
- return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(NID_secp224r1));
+ return EC_group_p224();
}
if (curve_name == "P-256") {
- return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(
- NID_X9_62_prime256v1));
+ return EC_group_p256();
}
if (curve_name == "P-384") {
- return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(NID_secp384r1));
+ return EC_group_p384();
}
if (curve_name == "P-521") {
- return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(NID_secp521r1));
+ return EC_group_p521();
}
t->PrintLine("Unknown curve '%s'", curve_name.c_str());
@@ -1035,7 +1028,7 @@ TEST(ECTest, ScalarBaseMultVectors) {
FileTestGTest("crypto/fipsmodule/ec/ec_scalar_base_mult_tests.txt",
[&](FileTest *t) {
- bssl::UniquePtr<EC_GROUP> group = GetCurve(t, "Curve");
+ const EC_GROUP *group = GetCurve(t, "Curve");
ASSERT_TRUE(group);
bssl::UniquePtr<BIGNUM> n = GetBIGNUM(t, "N");
ASSERT_TRUE(n);
@@ -1051,25 +1044,24 @@ TEST(ECTest, ScalarBaseMultVectors) {
ASSERT_TRUE(py);
auto check_point = [&](const EC_POINT *p) {
if (is_infinity) {
- EXPECT_TRUE(EC_POINT_is_at_infinity(group.get(), p));
+ EXPECT_TRUE(EC_POINT_is_at_infinity(group, p));
} else {
ASSERT_TRUE(EC_POINT_get_affine_coordinates_GFp(
- group.get(), p, px.get(), py.get(), ctx.get()));
+ group, p, px.get(), py.get(), ctx.get()));
EXPECT_EQ(0, BN_cmp(x.get(), px.get()));
EXPECT_EQ(0, BN_cmp(y.get(), py.get()));
}
};
- const EC_POINT *g = EC_GROUP_get0_generator(group.get());
- bssl::UniquePtr<EC_POINT> p(EC_POINT_new(group.get()));
+ const EC_POINT *g = EC_GROUP_get0_generator(group);
+ bssl::UniquePtr<EC_POINT> p(EC_POINT_new(group));
ASSERT_TRUE(p);
// Test single-point multiplication.
- ASSERT_TRUE(EC_POINT_mul(group.get(), p.get(), n.get(), nullptr, nullptr,
+ ASSERT_TRUE(EC_POINT_mul(group, p.get(), n.get(), nullptr, nullptr,
ctx.get()));
check_point(p.get());
- ASSERT_TRUE(
- EC_POINT_mul(group.get(), p.get(), nullptr, g, n.get(), ctx.get()));
+ ASSERT_TRUE(EC_POINT_mul(group, p.get(), nullptr, g, n.get(), ctx.get()));
check_point(p.get());
});
}
@@ -1082,7 +1074,7 @@ TEST(ECTest, DISABLED_ScalarBaseMultVectorsTwoPoint) {
FileTestGTest("crypto/fipsmodule/ec/ec_scalar_base_mult_tests.txt",
[&](FileTest *t) {
- bssl::UniquePtr<EC_GROUP> group = GetCurve(t, "Curve");
+ const EC_GROUP *group = GetCurve(t, "Curve");
ASSERT_TRUE(group);
bssl::UniquePtr<BIGNUM> n = GetBIGNUM(t, "N");
ASSERT_TRUE(n);
@@ -1098,41 +1090,40 @@ TEST(ECTest, DISABLED_ScalarBaseMultVectorsTwoPoint) {
ASSERT_TRUE(py);
auto check_point = [&](const EC_POINT *p) {
if (is_infinity) {
- EXPECT_TRUE(EC_POINT_is_at_infinity(group.get(), p));
+ EXPECT_TRUE(EC_POINT_is_at_infinity(group, p));
} else {
ASSERT_TRUE(EC_POINT_get_affine_coordinates_GFp(
- group.get(), p, px.get(), py.get(), ctx.get()));
+ group, p, px.get(), py.get(), ctx.get()));
EXPECT_EQ(0, BN_cmp(x.get(), px.get()));
EXPECT_EQ(0, BN_cmp(y.get(), py.get()));
}
};
- const EC_POINT *g = EC_GROUP_get0_generator(group.get());
- bssl::UniquePtr<EC_POINT> p(EC_POINT_new(group.get()));
+ const EC_POINT *g = EC_GROUP_get0_generator(group);
+ bssl::UniquePtr<EC_POINT> p(EC_POINT_new(group));
ASSERT_TRUE(p);
bssl::UniquePtr<BIGNUM> a(BN_new()), b(BN_new());
for (int i = -64; i < 64; i++) {
SCOPED_TRACE(i);
ASSERT_TRUE(BN_set_word(a.get(), abs(i)));
if (i < 0) {
- ASSERT_TRUE(BN_sub(a.get(), EC_GROUP_get0_order(group.get()), a.get()));
+ ASSERT_TRUE(BN_sub(a.get(), EC_GROUP_get0_order(group), a.get()));
}
ASSERT_TRUE(BN_copy(b.get(), n.get()));
ASSERT_TRUE(BN_sub(b.get(), b.get(), a.get()));
if (BN_is_negative(b.get())) {
- ASSERT_TRUE(BN_add(b.get(), b.get(), EC_GROUP_get0_order(group.get())));
+ ASSERT_TRUE(BN_add(b.get(), b.get(), EC_GROUP_get0_order(group)));
}
- ASSERT_TRUE(
- EC_POINT_mul(group.get(), p.get(), a.get(), g, b.get(), ctx.get()));
+ ASSERT_TRUE(EC_POINT_mul(group, p.get(), a.get(), g, b.get(), ctx.get()));
check_point(p.get());
EC_SCALAR a_scalar, b_scalar;
- ASSERT_TRUE(ec_bignum_to_scalar(group.get(), &a_scalar, a.get()));
- ASSERT_TRUE(ec_bignum_to_scalar(group.get(), &b_scalar, b.get()));
- ASSERT_TRUE(ec_point_mul_scalar_public(group.get(), &p->raw, &a_scalar,
- &g->raw, &b_scalar));
+ ASSERT_TRUE(ec_bignum_to_scalar(group, &a_scalar, a.get()));
+ ASSERT_TRUE(ec_bignum_to_scalar(group, &b_scalar, b.get()));
+ ASSERT_TRUE(ec_point_mul_scalar_public(group, &p->raw, &a_scalar, &g->raw,
+ &b_scalar));
check_point(p.get());
}
});
@@ -1148,31 +1139,31 @@ static std::vector<uint8_t> HexToBytes(const char *str) {
TEST(ECTest, DeriveFromSecret) {
struct DeriveTest {
- int curve;
+ const EC_GROUP *group;
std::vector<uint8_t> secret;
std::vector<uint8_t> expected_priv;
std::vector<uint8_t> expected_pub;
};
const DeriveTest kDeriveTests[] = {
- {NID_X9_62_prime256v1, HexToBytes(""),
+ {EC_group_p256(), HexToBytes(""),
HexToBytes(
"b98a86a71efb51ebdac4759937b977e9b0c05224675bb2b6a58ba306e237f4b8"),
HexToBytes(
"04fbe6cab439918e00231a2ff073cdc25823998864a9eb36f809095a1a919ece875"
"a145803fbe89a6cde53936e3c6d9c253ed3d38f5f58cae455c27e95645ceda9")},
- {NID_X9_62_prime256v1, HexToBytes("123456"),
+ {EC_group_p256(), HexToBytes("123456"),
HexToBytes(
"44a72bc62087b88e5ab7126766177ed0d8f1ed09ad066cd746527fc201105a7e"),
HexToBytes(
"04ec0555cd76e991fef7f5504343937d0f38696db3360a4854052cb0d84a377a5a0"
"ff64c352755c28692b4ae085c2b817db9a1eddbd22e9cf39c12751e0870791b")},
- {NID_X9_62_prime256v1, HexToBytes("00000000000000000000000000000000"),
+ {EC_group_p256(), HexToBytes("00000000000000000000000000000000"),
HexToBytes(
"7ca1e2c83e6a5f2c1b3e7d58180226f269930c4b9fbe2a275096079630b7c57d"),
HexToBytes(
"0442ef70c8fc0fbe383ed0a0da36f39f9a590f3feebc07863cc858c9a8ef0465731"
"0408c249bd4d61929c54b71ffe056e6b4fa1eb537039b43d1c175f0ceab0f89")},
- {NID_X9_62_prime256v1,
+ {EC_group_p256(),
HexToBytes(
"de9c9b35543aaa0fba039e34e8ca9695da3225c7161c9e3a8c70356cac28c780"),
HexToBytes(
@@ -1180,7 +1171,7 @@ TEST(ECTest, DeriveFromSecret) {
HexToBytes(
"046741f806b593bf3a3d4a9d76bdcb9b0d7874633cbea8f42c05e78561f7e8ec362"
"b9b6f1913ded796fbdafe7f210cea897ac22a4e580c06a60f2659fd09f1830f")},
- {NID_secp384r1, HexToBytes("123456"),
+ {EC_group_p384(), HexToBytes("123456"),
HexToBytes("95cd90d548997de090c7622708eccb7edc1b1bd78d2422235ad97406dada"
"076555309da200096f6e4b36c46002beee89"),
HexToBytes(
@@ -1191,13 +1182,12 @@ TEST(ECTest, DeriveFromSecret) {
for (const auto &test : kDeriveTests) {
SCOPED_TRACE(Bytes(test.secret));
- bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(test.curve));
- ASSERT_TRUE(group);
+
bssl::UniquePtr<EC_KEY> key(EC_KEY_derive_from_secret(
- group.get(), test.secret.data(), test.secret.size()));
+ test.group, test.secret.data(), test.secret.size()));
ASSERT_TRUE(key);
- std::vector<uint8_t> priv(BN_num_bytes(EC_GROUP_get0_order(group.get())));
+ std::vector<uint8_t> priv(BN_num_bytes(EC_GROUP_get0_order(test.group)));
ASSERT_TRUE(BN_bn2bin_padded(priv.data(), priv.size(),
EC_KEY_get0_private_key(key.get())));
EXPECT_EQ(Bytes(priv), Bytes(test.expected_priv));
@@ -1226,33 +1216,33 @@ TEST(ECTest, HashToCurve) {
int (*hash_to_curve)(const EC_GROUP *group, EC_POINT *out,
const uint8_t *dst, size_t dst_len, const uint8_t *msg,
size_t msg_len);
- int curve_nid;
+ const EC_GROUP *group;
const char *dst;
const char *msg;
const char *x_hex;
const char *y_hex;
};
- static const HashToCurveTest kTests[] = {
+ const HashToCurveTest kTests[] = {
// See draft-irtf-cfrg-hash-to-curve-16, appendix J.1.1.
- {&EC_hash_to_curve_p256_xmd_sha256_sswu, NID_X9_62_prime256v1,
+ {&EC_hash_to_curve_p256_xmd_sha256_sswu, EC_group_p256(),
"QUUX-V01-CS02-with-P256_XMD:SHA-256_SSWU_RO_", "",
"2c15230b26dbc6fc9a37051158c95b79656e17a1a920b11394ca91"
"c44247d3e4",
"8a7a74985cc5c776cdfe4b1f19884970453912e9d31528c060be9a"
"b5c43e8415"},
- {&EC_hash_to_curve_p256_xmd_sha256_sswu, NID_X9_62_prime256v1,
+ {&EC_hash_to_curve_p256_xmd_sha256_sswu, EC_group_p256(),
"QUUX-V01-CS02-with-P256_XMD:SHA-256_SSWU_RO_", "abc",
"0bb8b87485551aa43ed54f009230450b492fead5f1cc91658775da"
"c4a3388a0f",
"5c41b3d0731a27a7b14bc0bf0ccded2d8751f83493404c84a88e71"
"ffd424212e"},
- {&EC_hash_to_curve_p256_xmd_sha256_sswu, NID_X9_62_prime256v1,
+ {&EC_hash_to_curve_p256_xmd_sha256_sswu, EC_group_p256(),
"QUUX-V01-CS02-with-P256_XMD:SHA-256_SSWU_RO_", "abcdef0123456789",
"65038ac8f2b1def042a5df0b33b1f4eca6bff7cb0f9c6c15268118"
"64e544ed80",
"cad44d40a656e7aff4002a8de287abc8ae0482b5ae825822bb870d"
"6df9b56ca3"},
- {&EC_hash_to_curve_p256_xmd_sha256_sswu, NID_X9_62_prime256v1,
+ {&EC_hash_to_curve_p256_xmd_sha256_sswu, EC_group_p256(),
"QUUX-V01-CS02-with-P256_XMD:SHA-256_SSWU_RO_",
"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"
"qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"
@@ -1261,7 +1251,7 @@ TEST(ECTest, HashToCurve) {
"3dc65a0b5d",
"98f8df449a072c4721d241a3b1236d3caccba603f916ca680f4539"
"d2bfb3c29e"},
- {&EC_hash_to_curve_p256_xmd_sha256_sswu, NID_X9_62_prime256v1,
+ {&EC_hash_to_curve_p256_xmd_sha256_sswu, EC_group_p256(),
"QUUX-V01-CS02-with-P256_XMD:SHA-256_SSWU_RO_",
"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
@@ -1279,25 +1269,25 @@ TEST(ECTest, HashToCurve) {
"2b0f4757dc"},
// See draft-irtf-cfrg-hash-to-curve-07, appendix G.2.1.
- {hash_to_curve_p384_sha512_draft07, NID_secp384r1,
+ {hash_to_curve_p384_sha512_draft07, EC_group_p384(),
"P384_XMD:SHA-512_SSWU_RO_TESTGEN", "",
"2fc0b9efdd63a8e43b4db88dc12f03c798f6fd91bccac0c9096185"
"4386e58fdc54fc2a01f0f358759054ce1f9b762025",
"949b936fabb72cdb02cd7980b86cb6a3adf286658e81301648851d"
"b8a49d9bec00ccb57698d559fc5960fa5030a8e54b"},
- {hash_to_curve_p384_sha512_draft07, NID_secp384r1,
+ {hash_to_curve_p384_sha512_draft07, EC_group_p384(),
"P384_XMD:SHA-512_SSWU_RO_TESTGEN", "abc",
"4f3338035391e8ce8ce40c974136f0edc97f392ffd44a643338741"
"8ed1b8c2603487e1688ec151f048fbc6b2c138c92f",
"152b90aef6558be328a3168855fb1906452e7167b0f7c8a56ff9d4"
"fa87d6fb522cdf8e409db54418b2c764fd26260757"},
- {hash_to_curve_p384_sha512_draft07, NID_secp384r1,
+ {hash_to_curve_p384_sha512_draft07, EC_group_p384(),
"P384_XMD:SHA-512_SSWU_RO_TESTGEN", "abcdef0123456789",
"e9e5d7ac397e123d060ad44301cbc8eb972f6e64ebcff29dcc9b9a"
"10357902aace2240c580fec85e5b427d98b4e80703",
"916cb8963521ad75105be43cc4148e5a5bbb4fcf107f1577e4f7fa"
"3ca58cd786aa76890c8e687d2353393bc16c78ec4d"},
- {hash_to_curve_p384_sha512_draft07, NID_secp384r1,
+ {hash_to_curve_p384_sha512_draft07, EC_group_p384(),
"P384_XMD:SHA-512_SSWU_RO_TESTGEN",
"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
@@ -1319,17 +1309,15 @@ TEST(ECTest, HashToCurve) {
SCOPED_TRACE(test.dst);
SCOPED_TRACE(test.msg);
- bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(test.curve_nid));
- ASSERT_TRUE(group);
- bssl::UniquePtr<EC_POINT> p(EC_POINT_new(group.get()));
+ bssl::UniquePtr<EC_POINT> p(EC_POINT_new(test.group));
ASSERT_TRUE(p);
ASSERT_TRUE(test.hash_to_curve(
- group.get(), p.get(), reinterpret_cast<const uint8_t *>(test.dst),
+ test.group, p.get(), reinterpret_cast<const uint8_t *>(test.dst),
strlen(test.dst), reinterpret_cast<const uint8_t *>(test.msg),
strlen(test.msg)));
std::vector<uint8_t> buf;
- ASSERT_TRUE(EncodeECPoint(&buf, group.get(), p.get(),
+ ASSERT_TRUE(EncodeECPoint(&buf, test.group, p.get(),
POINT_CONVERSION_UNCOMPRESSED));
size_t field_len = (buf.size() - 1) / 2;
EXPECT_EQ(test.x_hex,
@@ -1339,32 +1327,28 @@ TEST(ECTest, HashToCurve) {
}
// hash-to-curve functions should check for the wrong group.
- bssl::UniquePtr<EC_GROUP> p224(EC_GROUP_new_by_curve_name(NID_secp224r1));
- ASSERT_TRUE(p224);
- bssl::UniquePtr<EC_GROUP> p384(EC_GROUP_new_by_curve_name(NID_secp384r1));
- ASSERT_TRUE(p384);
- EC_RAW_POINT raw;
- bssl::UniquePtr<EC_POINT> p_p384(EC_POINT_new(p384.get()));
+ EC_JACOBIAN raw;
+ bssl::UniquePtr<EC_POINT> p_p384(EC_POINT_new(EC_group_p384()));
ASSERT_TRUE(p_p384);
- bssl::UniquePtr<EC_POINT> p_p224(EC_POINT_new(p224.get()));
+ bssl::UniquePtr<EC_POINT> p_p224(EC_POINT_new(EC_group_p224()));
ASSERT_TRUE(p_p224);
static const uint8_t kDST[] = {0, 1, 2, 3};
static const uint8_t kMessage[] = {4, 5, 6, 7};
EXPECT_FALSE(ec_hash_to_curve_p384_xmd_sha384_sswu(
- p224.get(), &raw, kDST, sizeof(kDST), kMessage, sizeof(kMessage)));
+ EC_group_p224(), &raw, kDST, sizeof(kDST), kMessage, sizeof(kMessage)));
EXPECT_FALSE(EC_hash_to_curve_p384_xmd_sha384_sswu(
- p224.get(), p_p224.get(), kDST, sizeof(kDST), kMessage,
+ EC_group_p224(), p_p224.get(), kDST, sizeof(kDST), kMessage,
sizeof(kMessage)));
EXPECT_FALSE(EC_hash_to_curve_p384_xmd_sha384_sswu(
- p224.get(), p_p384.get(), kDST, sizeof(kDST), kMessage,
+ EC_group_p224(), p_p384.get(), kDST, sizeof(kDST), kMessage,
sizeof(kMessage)));
EXPECT_FALSE(EC_hash_to_curve_p384_xmd_sha384_sswu(
- p384.get(), p_p224.get(), kDST, sizeof(kDST), kMessage,
+ EC_group_p384(), p_p224.get(), kDST, sizeof(kDST), kMessage,
sizeof(kMessage)));
// Zero-length DSTs are not allowed.
EXPECT_FALSE(ec_hash_to_curve_p384_xmd_sha384_sswu(
- p384.get(), &raw, nullptr, 0, kMessage, sizeof(kMessage)));
+ EC_group_p384(), &raw, nullptr, 0, kMessage, sizeof(kMessage)));
}
TEST(ECTest, HashToScalar) {
@@ -1372,21 +1356,21 @@ TEST(ECTest, HashToScalar) {
int (*hash_to_scalar)(const EC_GROUP *group, EC_SCALAR *out,
const uint8_t *dst, size_t dst_len,
const uint8_t *msg, size_t msg_len);
- int curve_nid;
+ const EC_GROUP *group;
const char *dst;
const char *msg;
const char *result_hex;
};
- static const HashToScalarTest kTests[] = {
- {&ec_hash_to_scalar_p384_xmd_sha512_draft07, NID_secp384r1,
+ const HashToScalarTest kTests[] = {
+ {&ec_hash_to_scalar_p384_xmd_sha512_draft07, EC_group_p384(),
"P384_XMD:SHA-512_SCALAR_TEST", "",
"9687acc2de56c3cf94c0e05b6811a21aa480092254ec0532bdce63"
"140ecd340f09dc2d45d77e21fb0aa76f7707b8a676"},
- {&ec_hash_to_scalar_p384_xmd_sha512_draft07, NID_secp384r1,
+ {&ec_hash_to_scalar_p384_xmd_sha512_draft07, EC_group_p384(),
"P384_XMD:SHA-512_SCALAR_TEST", "abcdef0123456789",
"8f8076022a68233cbcecaceae68c2068f132724f001caa78619eff"
"1ffc58fa871db73fe9034fc9cf853c384ed34b5666"},
- {&ec_hash_to_scalar_p384_xmd_sha512_draft07, NID_secp384r1,
+ {&ec_hash_to_scalar_p384_xmd_sha512_draft07, EC_group_p384(),
"P384_XMD:SHA-512_SCALAR_TEST",
"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
@@ -1406,25 +1390,22 @@ TEST(ECTest, HashToScalar) {
SCOPED_TRACE(test.dst);
SCOPED_TRACE(test.msg);
- bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(test.curve_nid));
- ASSERT_TRUE(group);
EC_SCALAR scalar;
ASSERT_TRUE(test.hash_to_scalar(
- group.get(), &scalar, reinterpret_cast<const uint8_t *>(test.dst),
+ test.group, &scalar, reinterpret_cast<const uint8_t *>(test.dst),
strlen(test.dst), reinterpret_cast<const uint8_t *>(test.msg),
strlen(test.msg)));
uint8_t buf[EC_MAX_BYTES];
size_t len;
- ec_scalar_to_bytes(group.get(), buf, &len, &scalar);
+ ec_scalar_to_bytes(test.group, buf, &len, &scalar);
EXPECT_EQ(test.result_hex, EncodeHex(bssl::MakeConstSpan(buf, len)));
}
// hash-to-scalar functions should check for the wrong group.
- bssl::UniquePtr<EC_GROUP> p224(EC_GROUP_new_by_curve_name(NID_secp224r1));
- ASSERT_TRUE(p224);
EC_SCALAR scalar;
static const uint8_t kDST[] = {0, 1, 2, 3};
static const uint8_t kMessage[] = {4, 5, 6, 7};
EXPECT_FALSE(ec_hash_to_scalar_p384_xmd_sha512_draft07(
- p224.get(), &scalar, kDST, sizeof(kDST), kMessage, sizeof(kMessage)));
+ EC_group_p224(), &scalar, kDST, sizeof(kDST), kMessage,
+ sizeof(kMessage)));
}
diff --git a/src/crypto/fipsmodule/ec/felem.c b/src/crypto/fipsmodule/ec/felem.c
index e462514c..60648195 100644
--- a/src/crypto/fipsmodule/ec/felem.c
+++ b/src/crypto/fipsmodule/ec/felem.c
@@ -23,12 +23,16 @@
#include "../../internal.h"
+const EC_FELEM *ec_felem_one(const EC_GROUP *group) {
+ // We reuse generator.Z as a cache for 1 in the field.
+ return &group->generator.raw.Z;
+}
+
int ec_bignum_to_felem(const EC_GROUP *group, EC_FELEM *out, const BIGNUM *in) {
uint8_t bytes[EC_MAX_BYTES];
- size_t len = BN_num_bytes(&group->field);
+ size_t len = BN_num_bytes(&group->field.N);
assert(sizeof(bytes) >= len);
- if (BN_is_negative(in) ||
- BN_cmp(in, &group->field) >= 0 ||
+ if (BN_is_negative(in) || BN_cmp(in, &group->field.N) >= 0 ||
!BN_bn2bin_padded(bytes, len, in)) {
OPENSSL_PUT_ERROR(EC, EC_R_COORDINATES_OUT_OF_RANGE);
return 0;
@@ -57,11 +61,11 @@ int ec_felem_from_bytes(const EC_GROUP *group, EC_FELEM *out, const uint8_t *in,
void ec_felem_neg(const EC_GROUP *group, EC_FELEM *out, const EC_FELEM *a) {
// -a is zero if a is zero and p-a otherwise.
BN_ULONG mask = ec_felem_non_zero_mask(group, a);
- BN_ULONG borrow =
- bn_sub_words(out->words, group->field.d, a->words, group->field.width);
+ BN_ULONG borrow = bn_sub_words(out->words, group->field.N.d, a->words,
+ group->field.N.width);
assert(borrow == 0);
(void)borrow;
- for (int i = 0; i < group->field.width; i++) {
+ for (int i = 0; i < group->field.N.width; i++) {
out->words[i] &= mask;
}
}
@@ -69,20 +73,20 @@ void ec_felem_neg(const EC_GROUP *group, EC_FELEM *out, const EC_FELEM *a) {
void ec_felem_add(const EC_GROUP *group, EC_FELEM *out, const EC_FELEM *a,
const EC_FELEM *b) {
EC_FELEM tmp;
- bn_mod_add_words(out->words, a->words, b->words, group->field.d, tmp.words,
- group->field.width);
+ bn_mod_add_words(out->words, a->words, b->words, group->field.N.d, tmp.words,
+ group->field.N.width);
}
void ec_felem_sub(const EC_GROUP *group, EC_FELEM *out, const EC_FELEM *a,
const EC_FELEM *b) {
EC_FELEM tmp;
- bn_mod_sub_words(out->words, a->words, b->words, group->field.d, tmp.words,
- group->field.width);
+ bn_mod_sub_words(out->words, a->words, b->words, group->field.N.d, tmp.words,
+ group->field.N.width);
}
BN_ULONG ec_felem_non_zero_mask(const EC_GROUP *group, const EC_FELEM *a) {
BN_ULONG mask = 0;
- for (int i = 0; i < group->field.width; i++) {
+ for (int i = 0; i < group->field.N.width; i++) {
mask |= a->words[i];
}
return ~constant_time_is_zero_w(mask);
@@ -90,11 +94,11 @@ BN_ULONG ec_felem_non_zero_mask(const EC_GROUP *group, const EC_FELEM *a) {
void ec_felem_select(const EC_GROUP *group, EC_FELEM *out, BN_ULONG mask,
const EC_FELEM *a, const EC_FELEM *b) {
- bn_select_words(out->words, mask, a->words, b->words, group->field.width);
+ bn_select_words(out->words, mask, a->words, b->words, group->field.N.width);
}
int ec_felem_equal(const EC_GROUP *group, const EC_FELEM *a,
const EC_FELEM *b) {
return CRYPTO_memcmp(a->words, b->words,
- group->field.width * sizeof(BN_ULONG)) == 0;
+ group->field.N.width * sizeof(BN_ULONG)) == 0;
}
diff --git a/src/crypto/fipsmodule/ec/internal.h b/src/crypto/fipsmodule/ec/internal.h
index 3b6fa4a4..f2cb69bf 100644
--- a/src/crypto/fipsmodule/ec/internal.h
+++ b/src/crypto/fipsmodule/ec/internal.h
@@ -197,6 +197,9 @@ typedef struct {
BN_ULONG words[EC_MAX_WORDS];
} EC_FELEM;
+// ec_felem_one returns one in |group|'s field.
+const EC_FELEM *ec_felem_one(const EC_GROUP *group);
+
// ec_bignum_to_felem converts |in| to an |EC_FELEM|. It returns one on success
// and zero if |in| is out of range.
int ec_bignum_to_felem(const EC_GROUP *group, EC_FELEM *out, const BIGNUM *in);
@@ -243,16 +246,14 @@ int ec_felem_equal(const EC_GROUP *group, const EC_FELEM *a, const EC_FELEM *b);
// Points.
//
// Points may represented in affine coordinates as |EC_AFFINE| or Jacobian
-// coordinates as |EC_RAW_POINT|. Affine coordinates directly represent a
+// coordinates as |EC_JACOBIAN|. Affine coordinates directly represent a
// point on the curve, but point addition over affine coordinates requires
// costly field inversions, so arithmetic is done in Jacobian coordinates.
// Converting from affine to Jacobian is cheap, while converting from Jacobian
// to affine costs a field inversion. (Jacobian coordinates amortize the field
// inversions needed in a sequence of point operations.)
-//
-// TODO(davidben): Rename |EC_RAW_POINT| to |EC_JACOBIAN|.
-// An EC_RAW_POINT represents an elliptic curve point in Jacobian coordinates.
+// An EC_JACOBIAN represents an elliptic curve point in Jacobian coordinates.
// Unlike |EC_POINT|, it is a plain struct which can be stack-allocated and
// needs no cleanup. It is specific to an |EC_GROUP| and must not be mixed
// between groups.
@@ -260,7 +261,7 @@ typedef struct {
// X, Y, and Z are Jacobian projective coordinates. They represent
// (X/Z^2, Y/Z^3) if Z != 0 and the point at infinity otherwise.
EC_FELEM X, Y, Z;
-} EC_RAW_POINT;
+} EC_JACOBIAN;
// An EC_AFFINE represents an elliptic curve point in affine coordinates.
// coordinates. Note the point at infinity cannot be represented in affine
@@ -271,7 +272,7 @@ typedef struct {
// ec_affine_to_jacobian converts |p| to Jacobian form and writes the result to
// |*out|. This operation is very cheap and only costs a few copies.
-void ec_affine_to_jacobian(const EC_GROUP *group, EC_RAW_POINT *out,
+void ec_affine_to_jacobian(const EC_GROUP *group, EC_JACOBIAN *out,
const EC_AFFINE *p);
// ec_jacobian_to_affine converts |p| to affine form and writes the result to
@@ -282,7 +283,7 @@ void ec_affine_to_jacobian(const EC_GROUP *group, EC_RAW_POINT *out,
// If only extracting the x-coordinate, use |ec_get_x_coordinate_*| which is
// slightly faster.
OPENSSL_EXPORT int ec_jacobian_to_affine(const EC_GROUP *group, EC_AFFINE *out,
- const EC_RAW_POINT *p);
+ const EC_JACOBIAN *p);
// ec_jacobian_to_affine_batch converts |num| points in |in| from Jacobian
// coordinates to affine coordinates and writes the results to |out|. It returns
@@ -291,7 +292,7 @@ OPENSSL_EXPORT int ec_jacobian_to_affine(const EC_GROUP *group, EC_AFFINE *out,
// This function is not implemented for all curves. Add implementations as
// needed.
int ec_jacobian_to_affine_batch(const EC_GROUP *group, EC_AFFINE *out,
- const EC_RAW_POINT *in, size_t num);
+ const EC_JACOBIAN *in, size_t num);
// ec_point_set_affine_coordinates sets |out|'s to a point with affine
// coordinates |x| and |y|. It returns one if the point is on the curve and
@@ -309,12 +310,12 @@ int ec_point_mul_no_self_test(const EC_GROUP *group, EC_POINT *r,
// ec_point_mul_scalar sets |r| to |p| * |scalar|. Both inputs are considered
// secret.
-int ec_point_mul_scalar(const EC_GROUP *group, EC_RAW_POINT *r,
- const EC_RAW_POINT *p, const EC_SCALAR *scalar);
+int ec_point_mul_scalar(const EC_GROUP *group, EC_JACOBIAN *r,
+ const EC_JACOBIAN *p, const EC_SCALAR *scalar);
// ec_point_mul_scalar_base sets |r| to generator * |scalar|. |scalar| is
// treated as secret.
-int ec_point_mul_scalar_base(const EC_GROUP *group, EC_RAW_POINT *r,
+int ec_point_mul_scalar_base(const EC_GROUP *group, EC_JACOBIAN *r,
const EC_SCALAR *scalar);
// ec_point_mul_scalar_batch sets |r| to |p0| * |scalar0| + |p1| * |scalar1| +
@@ -335,10 +336,10 @@ int ec_point_mul_scalar_base(const EC_GROUP *group, EC_RAW_POINT *r,
// none. If generalizing to tuned curves, this may be useful. However, we still
// must double up to the least efficient input, so precomputed tables can only
// save table setup and allow a wider window size.
-int ec_point_mul_scalar_batch(const EC_GROUP *group, EC_RAW_POINT *r,
- const EC_RAW_POINT *p0, const EC_SCALAR *scalar0,
- const EC_RAW_POINT *p1, const EC_SCALAR *scalar1,
- const EC_RAW_POINT *p2, const EC_SCALAR *scalar2);
+int ec_point_mul_scalar_batch(const EC_GROUP *group, EC_JACOBIAN *r,
+ const EC_JACOBIAN *p0, const EC_SCALAR *scalar0,
+ const EC_JACOBIAN *p1, const EC_SCALAR *scalar1,
+ const EC_JACOBIAN *p2, const EC_SCALAR *scalar2);
#define EC_MONT_PRECOMP_COMB_SIZE 5
@@ -357,7 +358,7 @@ typedef union {
// This function is not implemented for all curves. Add implementations as
// needed.
int ec_init_precomp(const EC_GROUP *group, EC_PRECOMP *out,
- const EC_RAW_POINT *p);
+ const EC_JACOBIAN *p);
// ec_point_mul_scalar_precomp sets |r| to |p0| * |scalar0| + |p1| * |scalar1| +
// |p2| * |scalar2|. |p1| or |p2| may be NULL to skip the corresponding term.
@@ -381,7 +382,7 @@ int ec_init_precomp(const EC_GROUP *group, EC_PRECOMP *out,
// none. If generalizing to tuned curves, we should add a parameter for the base
// point and arrange for the generic implementation to have base point tables
// available.
-int ec_point_mul_scalar_precomp(const EC_GROUP *group, EC_RAW_POINT *r,
+int ec_point_mul_scalar_precomp(const EC_GROUP *group, EC_JACOBIAN *r,
const EC_PRECOMP *p0, const EC_SCALAR *scalar0,
const EC_PRECOMP *p1, const EC_SCALAR *scalar1,
const EC_PRECOMP *p2, const EC_SCALAR *scalar2);
@@ -390,9 +391,9 @@ int ec_point_mul_scalar_precomp(const EC_GROUP *group, EC_RAW_POINT *r,
// generator * |g_scalar| + |p| * |p_scalar|. It assumes that the inputs are
// public so there is no concern about leaking their values through timing.
OPENSSL_EXPORT int ec_point_mul_scalar_public(const EC_GROUP *group,
- EC_RAW_POINT *r,
+ EC_JACOBIAN *r,
const EC_SCALAR *g_scalar,
- const EC_RAW_POINT *p,
+ const EC_JACOBIAN *p,
const EC_SCALAR *p_scalar);
// ec_point_mul_scalar_public_batch sets |r| to the sum of generator *
@@ -403,15 +404,15 @@ OPENSSL_EXPORT int ec_point_mul_scalar_public(const EC_GROUP *group,
//
// This function is not implemented for all curves. Add implementations as
// needed.
-int ec_point_mul_scalar_public_batch(const EC_GROUP *group, EC_RAW_POINT *r,
+int ec_point_mul_scalar_public_batch(const EC_GROUP *group, EC_JACOBIAN *r,
const EC_SCALAR *g_scalar,
- const EC_RAW_POINT *points,
+ const EC_JACOBIAN *points,
const EC_SCALAR *scalars, size_t num);
// ec_point_select, in constant time, sets |out| to |a| if |mask| is all ones
// and |b| if |mask| is all zeros.
-void ec_point_select(const EC_GROUP *group, EC_RAW_POINT *out, BN_ULONG mask,
- const EC_RAW_POINT *a, const EC_RAW_POINT *b);
+void ec_point_select(const EC_GROUP *group, EC_JACOBIAN *out, BN_ULONG mask,
+ const EC_JACOBIAN *a, const EC_JACOBIAN *b);
// ec_affine_select behaves like |ec_point_select| but acts on affine points.
void ec_affine_select(const EC_GROUP *group, EC_AFFINE *out, BN_ULONG mask,
@@ -423,15 +424,15 @@ void ec_precomp_select(const EC_GROUP *group, EC_PRECOMP *out, BN_ULONG mask,
// ec_cmp_x_coordinate compares the x (affine) coordinate of |p|, mod the group
// order, with |r|. It returns one if the values match and zero if |p| is the
-// point at infinity of the values do not match.
-int ec_cmp_x_coordinate(const EC_GROUP *group, const EC_RAW_POINT *p,
+// point at infinity of the values do not match. |p| is treated as public.
+int ec_cmp_x_coordinate(const EC_GROUP *group, const EC_JACOBIAN *p,
const EC_SCALAR *r);
// ec_get_x_coordinate_as_scalar sets |*out| to |p|'s x-coordinate, modulo
// |group->order|. It returns one on success and zero if |p| is the point at
// infinity.
int ec_get_x_coordinate_as_scalar(const EC_GROUP *group, EC_SCALAR *out,
- const EC_RAW_POINT *p);
+ const EC_JACOBIAN *p);
// ec_get_x_coordinate_as_bytes writes |p|'s affine x-coordinate to |out|, which
// must have at must |max_out| bytes. It sets |*out_len| to the number of bytes
@@ -439,7 +440,7 @@ int ec_get_x_coordinate_as_scalar(const EC_GROUP *group, EC_SCALAR *out,
// field. This function returns one on success and zero on failure.
int ec_get_x_coordinate_as_bytes(const EC_GROUP *group, uint8_t *out,
size_t *out_len, size_t max_out,
- const EC_RAW_POINT *p);
+ const EC_JACOBIAN *p);
// ec_point_byte_len returns the number of bytes in the byte representation of
// a non-infinity point in |group|, encoded according to |form|, or zero if
@@ -463,67 +464,63 @@ int ec_point_from_uncompressed(const EC_GROUP *group, EC_AFFINE *out,
// ec_set_to_safe_point sets |out| to an arbitrary point on |group|, either the
// generator or the point at infinity. This is used to guard against callers of
// external APIs not checking the return value.
-void ec_set_to_safe_point(const EC_GROUP *group, EC_RAW_POINT *out);
+void ec_set_to_safe_point(const EC_GROUP *group, EC_JACOBIAN *out);
// ec_affine_jacobian_equal returns one if |a| and |b| represent the same point
// and zero otherwise. It treats both inputs as secret.
int ec_affine_jacobian_equal(const EC_GROUP *group, const EC_AFFINE *a,
- const EC_RAW_POINT *b);
+ const EC_JACOBIAN *b);
// Implementation details.
struct ec_method_st {
- int (*group_init)(EC_GROUP *);
- void (*group_finish)(EC_GROUP *);
- int (*group_set_curve)(EC_GROUP *, const BIGNUM *p, const BIGNUM *a,
- const BIGNUM *b, BN_CTX *);
-
// point_get_affine_coordinates sets |*x| and |*y| to the affine coordinates
// of |p|. Either |x| or |y| may be NULL to omit it. It returns one on success
- // and zero if |p| is the point at infinity.
- int (*point_get_affine_coordinates)(const EC_GROUP *, const EC_RAW_POINT *p,
+ // and zero if |p| is the point at infinity. It leaks whether |p| was the
+ // point at infinity, but otherwise treats |p| as secret.
+ int (*point_get_affine_coordinates)(const EC_GROUP *, const EC_JACOBIAN *p,
EC_FELEM *x, EC_FELEM *y);
// jacobian_to_affine_batch implements |ec_jacobian_to_affine_batch|.
int (*jacobian_to_affine_batch)(const EC_GROUP *group, EC_AFFINE *out,
- const EC_RAW_POINT *in, size_t num);
+ const EC_JACOBIAN *in, size_t num);
// add sets |r| to |a| + |b|.
- void (*add)(const EC_GROUP *group, EC_RAW_POINT *r, const EC_RAW_POINT *a,
- const EC_RAW_POINT *b);
+ void (*add)(const EC_GROUP *group, EC_JACOBIAN *r, const EC_JACOBIAN *a,
+ const EC_JACOBIAN *b);
// dbl sets |r| to |a| + |a|.
- void (*dbl)(const EC_GROUP *group, EC_RAW_POINT *r, const EC_RAW_POINT *a);
+ void (*dbl)(const EC_GROUP *group, EC_JACOBIAN *r, const EC_JACOBIAN *a);
// mul sets |r| to |scalar|*|p|.
- void (*mul)(const EC_GROUP *group, EC_RAW_POINT *r, const EC_RAW_POINT *p,
+ void (*mul)(const EC_GROUP *group, EC_JACOBIAN *r, const EC_JACOBIAN *p,
const EC_SCALAR *scalar);
// mul_base sets |r| to |scalar|*generator.
- void (*mul_base)(const EC_GROUP *group, EC_RAW_POINT *r,
+ void (*mul_base)(const EC_GROUP *group, EC_JACOBIAN *r,
const EC_SCALAR *scalar);
// mul_batch implements |ec_mul_scalar_batch|.
- void (*mul_batch)(const EC_GROUP *group, EC_RAW_POINT *r,
- const EC_RAW_POINT *p0, const EC_SCALAR *scalar0,
- const EC_RAW_POINT *p1, const EC_SCALAR *scalar1,
- const EC_RAW_POINT *p2, const EC_SCALAR *scalar2);
+ void (*mul_batch)(const EC_GROUP *group, EC_JACOBIAN *r,
+ const EC_JACOBIAN *p0, const EC_SCALAR *scalar0,
+ const EC_JACOBIAN *p1, const EC_SCALAR *scalar1,
+ const EC_JACOBIAN *p2, const EC_SCALAR *scalar2);
// mul_public sets |r| to |g_scalar|*generator + |p_scalar|*|p|. It assumes
// that the inputs are public so there is no concern about leaking their
// values through timing.
//
// This function may be omitted if |mul_public_batch| is provided.
- void (*mul_public)(const EC_GROUP *group, EC_RAW_POINT *r,
- const EC_SCALAR *g_scalar, const EC_RAW_POINT *p,
+ void (*mul_public)(const EC_GROUP *group, EC_JACOBIAN *r,
+ const EC_SCALAR *g_scalar, const EC_JACOBIAN *p,
const EC_SCALAR *p_scalar);
// mul_public_batch implements |ec_point_mul_scalar_public_batch|.
- int (*mul_public_batch)(const EC_GROUP *group, EC_RAW_POINT *r,
- const EC_SCALAR *g_scalar, const EC_RAW_POINT *points,
+ int (*mul_public_batch)(const EC_GROUP *group, EC_JACOBIAN *r,
+ const EC_SCALAR *g_scalar, const EC_JACOBIAN *points,
const EC_SCALAR *scalars, size_t num);
// init_precomp implements |ec_init_precomp|.
int (*init_precomp)(const EC_GROUP *group, EC_PRECOMP *out,
- const EC_RAW_POINT *p);
+ const EC_JACOBIAN *p);
// mul_precomp implements |ec_point_mul_scalar_precomp|.
- void (*mul_precomp)(const EC_GROUP *group, EC_RAW_POINT *r,
+ void (*mul_precomp)(const EC_GROUP *group, EC_JACOBIAN *r,
const EC_PRECOMP *p0, const EC_SCALAR *scalar0,
const EC_PRECOMP *p1, const EC_SCALAR *scalar1,
const EC_PRECOMP *p2, const EC_SCALAR *scalar2);
@@ -583,78 +580,72 @@ struct ec_method_st {
// cmp_x_coordinate compares the x (affine) coordinate of |p|, mod the group
// order, with |r|. It returns one if the values match and zero if |p| is the
// point at infinity of the values do not match.
- int (*cmp_x_coordinate)(const EC_GROUP *group, const EC_RAW_POINT *p,
+ int (*cmp_x_coordinate)(const EC_GROUP *group, const EC_JACOBIAN *p,
const EC_SCALAR *r);
} /* EC_METHOD */;
const EC_METHOD *EC_GFp_mont_method(void);
+struct ec_point_st {
+ // group is an owning reference to |group|, unless this is
+ // |group->generator|.
+ EC_GROUP *group;
+ // raw is the group-specific point data. Functions that take |EC_POINT|
+ // typically check consistency with |EC_GROUP| while functions that take
+ // |EC_JACOBIAN| do not. Thus accesses to this field should be externally
+ // checked for consistency.
+ EC_JACOBIAN raw;
+} /* EC_POINT */;
+
struct ec_group_st {
const EC_METHOD *meth;
// Unlike all other |EC_POINT|s, |generator| does not own |generator->group|
// to avoid a reference cycle. Additionally, Z is guaranteed to be one, so X
- // and Y are suitable for use as an |EC_AFFINE|.
- EC_POINT *generator;
- BIGNUM order;
+ // and Y are suitable for use as an |EC_AFFINE|. Before |has_order| is set, Z
+ // is one, but X and Y are uninitialized.
+ EC_POINT generator;
- int curve_name; // optional NID for named curve
+ BN_MONT_CTX order;
+ BN_MONT_CTX field;
- BN_MONT_CTX *order_mont; // data for ECDSA inverse
-
- // The following members are handled by the method functions,
- // even if they appear generic
+ EC_FELEM a, b; // Curve coefficients.
- BIGNUM field; // For curves over GF(p), this is the modulus.
+ // comment is a human-readable string describing the curve.
+ const char *comment;
- EC_FELEM a, b; // Curve coefficients.
+ int curve_name; // optional NID for named curve
+ uint8_t oid[9];
+ uint8_t oid_len;
// a_is_minus3 is one if |a| is -3 mod |field| and zero otherwise. Point
// arithmetic is optimized for -3.
int a_is_minus3;
+ // has_order is one if |generator| and |order| have been initialized.
+ int has_order;
+
// field_greater_than_order is one if |field| is greate than |order| and zero
// otherwise.
int field_greater_than_order;
- // field_minus_order, if |field_greater_than_order| is true, is |field| minus
- // |order| represented as an |EC_FELEM|. Otherwise, it is zero.
- //
- // Note: unlike |EC_FELEM|s used as intermediate values internal to the
- // |EC_METHOD|, this value is not encoded in Montgomery form.
- EC_FELEM field_minus_order;
-
CRYPTO_refcount_t references;
-
- BN_MONT_CTX *mont; // Montgomery structure.
-
- EC_FELEM one; // The value one.
} /* EC_GROUP */;
-struct ec_point_st {
- // group is an owning reference to |group|, unless this is
- // |group->generator|.
- EC_GROUP *group;
- // raw is the group-specific point data. Functions that take |EC_POINT|
- // typically check consistency with |EC_GROUP| while functions that take
- // |EC_RAW_POINT| do not. Thus accesses to this field should be externally
- // checked for consistency.
- EC_RAW_POINT raw;
-} /* EC_POINT */;
-
-EC_GROUP *ec_group_new(const EC_METHOD *meth);
+EC_GROUP *ec_group_new(const EC_METHOD *meth, const BIGNUM *p, const BIGNUM *a,
+ const BIGNUM *b, BN_CTX *ctx);
-void ec_GFp_mont_mul(const EC_GROUP *group, EC_RAW_POINT *r,
- const EC_RAW_POINT *p, const EC_SCALAR *scalar);
-void ec_GFp_mont_mul_base(const EC_GROUP *group, EC_RAW_POINT *r,
+void ec_GFp_mont_mul(const EC_GROUP *group, EC_JACOBIAN *r,
+ const EC_JACOBIAN *p, const EC_SCALAR *scalar);
+void ec_GFp_mont_mul_base(const EC_GROUP *group, EC_JACOBIAN *r,
const EC_SCALAR *scalar);
-void ec_GFp_mont_mul_batch(const EC_GROUP *group, EC_RAW_POINT *r,
- const EC_RAW_POINT *p0, const EC_SCALAR *scalar0,
- const EC_RAW_POINT *p1, const EC_SCALAR *scalar1,
- const EC_RAW_POINT *p2, const EC_SCALAR *scalar2);
+void ec_GFp_mont_mul_batch(const EC_GROUP *group, EC_JACOBIAN *r,
+ const EC_JACOBIAN *p0, const EC_SCALAR *scalar0,
+ const EC_JACOBIAN *p1, const EC_SCALAR *scalar1,
+ const EC_JACOBIAN *p2, const EC_SCALAR *scalar2);
int ec_GFp_mont_init_precomp(const EC_GROUP *group, EC_PRECOMP *out,
- const EC_RAW_POINT *p);
-void ec_GFp_mont_mul_precomp(const EC_GROUP *group, EC_RAW_POINT *r,
+ const EC_JACOBIAN *p);
+void ec_GFp_mont_mul_precomp(const EC_GROUP *group, EC_JACOBIAN *r,
const EC_PRECOMP *p0, const EC_SCALAR *scalar0,
const EC_PRECOMP *p1, const EC_SCALAR *scalar1,
const EC_PRECOMP *p2, const EC_SCALAR *scalar2);
@@ -675,29 +666,27 @@ void ec_GFp_mont_felem_exp(const EC_GROUP *group, EC_FELEM *out,
void ec_compute_wNAF(const EC_GROUP *group, int8_t *out,
const EC_SCALAR *scalar, size_t bits, int w);
-int ec_GFp_mont_mul_public_batch(const EC_GROUP *group, EC_RAW_POINT *r,
+int ec_GFp_mont_mul_public_batch(const EC_GROUP *group, EC_JACOBIAN *r,
const EC_SCALAR *g_scalar,
- const EC_RAW_POINT *points,
+ const EC_JACOBIAN *points,
const EC_SCALAR *scalars, size_t num);
// method functions in simple.c
-int ec_GFp_simple_group_init(EC_GROUP *);
-void ec_GFp_simple_group_finish(EC_GROUP *);
int ec_GFp_simple_group_set_curve(EC_GROUP *, const BIGNUM *p, const BIGNUM *a,
const BIGNUM *b, BN_CTX *);
int ec_GFp_simple_group_get_curve(const EC_GROUP *, BIGNUM *p, BIGNUM *a,
BIGNUM *b);
-void ec_GFp_simple_point_init(EC_RAW_POINT *);
-void ec_GFp_simple_point_copy(EC_RAW_POINT *, const EC_RAW_POINT *);
-void ec_GFp_simple_point_set_to_infinity(const EC_GROUP *, EC_RAW_POINT *);
-void ec_GFp_mont_add(const EC_GROUP *, EC_RAW_POINT *r, const EC_RAW_POINT *a,
- const EC_RAW_POINT *b);
-void ec_GFp_mont_dbl(const EC_GROUP *, EC_RAW_POINT *r, const EC_RAW_POINT *a);
-void ec_GFp_simple_invert(const EC_GROUP *, EC_RAW_POINT *);
-int ec_GFp_simple_is_at_infinity(const EC_GROUP *, const EC_RAW_POINT *);
-int ec_GFp_simple_is_on_curve(const EC_GROUP *, const EC_RAW_POINT *);
-int ec_GFp_simple_points_equal(const EC_GROUP *, const EC_RAW_POINT *a,
- const EC_RAW_POINT *b);
+void ec_GFp_simple_point_init(EC_JACOBIAN *);
+void ec_GFp_simple_point_copy(EC_JACOBIAN *, const EC_JACOBIAN *);
+void ec_GFp_simple_point_set_to_infinity(const EC_GROUP *, EC_JACOBIAN *);
+void ec_GFp_mont_add(const EC_GROUP *, EC_JACOBIAN *r, const EC_JACOBIAN *a,
+ const EC_JACOBIAN *b);
+void ec_GFp_mont_dbl(const EC_GROUP *, EC_JACOBIAN *r, const EC_JACOBIAN *a);
+void ec_GFp_simple_invert(const EC_GROUP *, EC_JACOBIAN *);
+int ec_GFp_simple_is_at_infinity(const EC_GROUP *, const EC_JACOBIAN *);
+int ec_GFp_simple_is_on_curve(const EC_GROUP *, const EC_JACOBIAN *);
+int ec_GFp_simple_points_equal(const EC_GROUP *, const EC_JACOBIAN *a,
+ const EC_JACOBIAN *b);
void ec_simple_scalar_inv0_montgomery(const EC_GROUP *group, EC_SCALAR *r,
const EC_SCALAR *a);
@@ -705,7 +694,7 @@ int ec_simple_scalar_to_montgomery_inv_vartime(const EC_GROUP *group,
EC_SCALAR *r,
const EC_SCALAR *a);
-int ec_GFp_simple_cmp_x_coordinate(const EC_GROUP *group, const EC_RAW_POINT *p,
+int ec_GFp_simple_cmp_x_coordinate(const EC_GROUP *group, const EC_JACOBIAN *p,
const EC_SCALAR *r);
void ec_GFp_simple_felem_to_bytes(const EC_GROUP *group, uint8_t *out,
@@ -714,10 +703,6 @@ int ec_GFp_simple_felem_from_bytes(const EC_GROUP *group, EC_FELEM *out,
const uint8_t *in, size_t len);
// method functions in montgomery.c
-int ec_GFp_mont_group_init(EC_GROUP *);
-int ec_GFp_mont_group_set_curve(EC_GROUP *, const BIGNUM *p, const BIGNUM *a,
- const BIGNUM *b, BN_CTX *);
-void ec_GFp_mont_group_finish(EC_GROUP *);
void ec_GFp_mont_felem_mul(const EC_GROUP *, EC_FELEM *r, const EC_FELEM *a,
const EC_FELEM *b);
void ec_GFp_mont_felem_sqr(const EC_GROUP *, EC_FELEM *r, const EC_FELEM *a);
@@ -763,31 +748,6 @@ struct ec_key_st {
CRYPTO_EX_DATA ex_data;
} /* EC_KEY */;
-struct built_in_curve {
- int nid;
- const uint8_t *oid;
- uint8_t oid_len;
- // comment is a human-readable string describing the curve.
- const char *comment;
- // param_len is the number of bytes needed to store a field element.
- uint8_t param_len;
- // params points to an array of 6*|param_len| bytes which hold the field
- // elements of the following (in big-endian order): prime, a, b, generator x,
- // generator y, order.
- const uint8_t *params;
- const EC_METHOD *method;
-};
-
-#define OPENSSL_NUM_BUILT_IN_CURVES 4
-
-struct built_in_curves {
- struct built_in_curve curves[OPENSSL_NUM_BUILT_IN_CURVES];
-};
-
-// OPENSSL_built_in_curves returns a pointer to static information about
-// standard curves. The array is terminated with an entry where |nid| is
-// |NID_undef|.
-const struct built_in_curves *OPENSSL_built_in_curves(void);
#if defined(__cplusplus)
} // extern C
diff --git a/src/crypto/fipsmodule/ec/make_tables.go b/src/crypto/fipsmodule/ec/make_tables.go
index 120c40bd..30535f5f 100644
--- a/src/crypto/fipsmodule/ec/make_tables.go
+++ b/src/crypto/fipsmodule/ec/make_tables.go
@@ -17,14 +17,21 @@
package main
import (
+ "bytes"
"crypto/elliptic"
"fmt"
"io"
"math/big"
"os"
+ "strings"
)
func main() {
+ if err := writeBuiltinCurves("builtin_curves.h"); err != nil {
+ fmt.Fprintf(os.Stderr, "Error writing builtin_curves.h: %s\n", err)
+ os.Exit(1)
+ }
+
if err := writeP256NistzTable("p256-nistz-table.h"); err != nil {
fmt.Fprintf(os.Stderr, "Error writing p256-nistz-table.h: %s\n", err)
os.Exit(1)
@@ -36,6 +43,120 @@ func main() {
}
}
+func writeBuiltinCurves(path string) error {
+ f, err := os.Create(path)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ w := &columnWriter{w: f}
+
+ const fileHeader = `/* Copyright (c) 2023, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+// This file is generated by make_tables.go.
+`
+ if _, err := io.WriteString(w, fileHeader); err != nil {
+ return err
+ }
+ // P-224 is the only curve where we have a non-Montgomery implementation.
+ if err := writeCurveData(w, elliptic.P224(), true); err != nil {
+ return err
+ }
+ if err := writeCurveData(w, elliptic.P256(), false); err != nil {
+ return err
+ }
+ if err := writeCurveData(w, elliptic.P384(), false); err != nil {
+ return err
+ }
+ if err := writeCurveData(w, elliptic.P521(), false); err != nil {
+ return err
+ }
+ return nil
+}
+
+func writeCurveData(w *columnWriter, curve elliptic.Curve, includeNonMontgomery bool) error {
+ params := curve.Params()
+ if _, err := fmt.Fprintf(w, "\n// %s\n", params.Name); err != nil {
+ return err
+ }
+
+ cName := strings.Replace(params.Name, "-", "", -1)
+ writeDecls := func(bits int) error {
+ if err := writeDecl(w, curve, bits, fmt.Sprintf("k%sField", cName), params.P); err != nil {
+ return err
+ }
+ if err := writeDecl(w, curve, bits, fmt.Sprintf("k%sOrder", cName), params.N); err != nil {
+ return err
+ }
+ if includeNonMontgomery {
+ if err := writeDecl(w, curve, bits, fmt.Sprintf("k%sB", cName), params.B); err != nil {
+ return err
+ }
+ if err := writeDecl(w, curve, bits, fmt.Sprintf("k%sGX", cName), params.Gx); err != nil {
+ return err
+ }
+ if err := writeDecl(w, curve, bits, fmt.Sprintf("k%sGY", cName), params.Gy); err != nil {
+ return err
+ }
+ }
+ if err := writeDecl(w, curve, bits, fmt.Sprintf("k%sFieldR", cName), montgomeryR(params.P, bits)); err != nil {
+ return err
+ }
+ if err := writeDecl(w, curve, bits, fmt.Sprintf("k%sFieldRR", cName), montgomeryRR(params.P, bits)); err != nil {
+ return err
+ }
+ if err := writeDecl(w, curve, bits, fmt.Sprintf("k%sOrderRR", cName), montgomeryRR(params.N, bits)); err != nil {
+ return err
+ }
+ if err := writeDecl(w, curve, bits, fmt.Sprintf("k%sMontB", cName), toMontgomery(params.B, params.P, bits)); err != nil {
+ return err
+ }
+ if err := writeDecl(w, curve, bits, fmt.Sprintf("k%sMontGX", cName), toMontgomery(params.Gx, params.P, bits)); err != nil {
+ return err
+ }
+ if err := writeDecl(w, curve, bits, fmt.Sprintf("k%sMontGY", cName), toMontgomery(params.Gy, params.P, bits)); err != nil {
+ return err
+ }
+ return nil
+ }
+
+ if _, err := fmt.Fprintf(w, "OPENSSL_UNUSED static const uint64_t k%sFieldN0 = 0x%016x;\n", cName, montgomeryN0(params.P)); err != nil {
+ return err
+ }
+ if _, err := fmt.Fprintf(w, "OPENSSL_UNUSED static const uint64_t k%sOrderN0 = 0x%016x;\n", cName, montgomeryN0(params.N)); err != nil {
+ return err
+ }
+
+ if _, err := io.WriteString(w, "#if defined(OPENSSL_64_BIT)\n"); err != nil {
+ return err
+ }
+ if err := writeDecls(64); err != nil {
+ return err
+ }
+ if _, err := io.WriteString(w, "#elif defined(OPENSSL_32_BIT)\n"); err != nil {
+ return err
+ }
+ if err := writeDecls(32); err != nil {
+ return err
+ }
+ if _, err := io.WriteString(w, "#else\n#error \"unknown word size\"\n#endif\n"); err != nil {
+ return err
+ }
+ return nil
+}
+
func writeP256NistzTable(path string) error {
curve := elliptic.P256()
tables := make([][][2]*big.Int, 0, 37)
@@ -49,6 +170,7 @@ func writeP256NistzTable(path string) error {
return err
}
defer f.Close()
+ w := &columnWriter{w: f}
const fileHeader = `/*
* Copyright 2014-2016 The OpenSSL Project Authors. All Rights Reserved.
@@ -75,13 +197,13 @@ func writeP256NistzTable(path string) error {
// This file is generated by make_tables.go.
static const alignas(4096) PRECOMP256_ROW ecp_nistz256_precomputed[37] = `
- if _, err := f.WriteString(fileHeader); err != nil {
+ if _, err := io.WriteString(w, fileHeader); err != nil {
return err
}
- if err := writeTables(f, curve, tables, true, 4, writeBNMont); err != nil {
+ if err := writeTables(w, curve, tables, writeBNMont); err != nil {
return err
}
- if _, err := f.WriteString(";\n"); err != nil {
+ if _, err := io.WriteString(w, ";\n"); err != nil {
return err
}
@@ -100,6 +222,7 @@ func writeP256Table(path string) error {
return err
}
defer f.Close()
+ w := &columnWriter{w: f}
const fileHeader = `/* Copyright (c) 2020, Google Inc.
*
@@ -155,19 +278,19 @@ func writeP256Table(path string) error {
// fiat_p256_g_pre_comp is the table of precomputed base points
#if defined(OPENSSL_64_BIT)
static const fiat_p256_felem fiat_p256_g_pre_comp[2][15][2] = `
- if _, err := f.WriteString(fileHeader); err != nil {
+ if _, err := io.WriteString(w, fileHeader); err != nil {
return err
}
- if err := writeTables(f, curve, tables, true, 4, writeU64Mont); err != nil {
+ if err := writeTables(w, curve, tables, writeU64Mont); err != nil {
return err
}
- if _, err := f.WriteString(";\n#else\nstatic const fiat_p256_felem fiat_p256_g_pre_comp[2][15][2] = "); err != nil {
+ if _, err := io.WriteString(w, ";\n#else\nstatic const fiat_p256_felem fiat_p256_g_pre_comp[2][15][2] = "); err != nil {
return err
}
- if err := writeTables(f, curve, tables, true, 4, writeU32Mont); err != nil {
+ if err := writeTables(w, curve, tables, writeU32Mont); err != nil {
return err
}
- if _, err := f.WriteString(";\n#endif\n"); err != nil {
+ if _, err := io.WriteString(w, ";\n#endif\n"); err != nil {
return err
}
@@ -223,20 +346,38 @@ func makeComb(curve elliptic.Curve, stride, size, shift int) [][2]*big.Int {
return ret
}
-// toMontgomery sets n to be n×R mod p, where R is the Montgomery factor.
-func toMontgomery(curve elliptic.Curve, n *big.Int) *big.Int {
- params := curve.Params()
+func montgomeryR(p *big.Int, wordSize int) *big.Int {
// R is the bit width of p, rounded up to word size.
- rounded64 := 64 * ((params.BitSize + 63) / 64)
- rounded32 := 32 * ((params.BitSize + 31) / 32)
- if rounded64 != rounded32 {
- panic(fmt.Sprintf("Montgomery form for %s is inconsistent between 32-bit and 64-bit", params.Name))
- }
+ rounded := wordSize * ((p.BitLen() + wordSize - 1) / wordSize)
R := new(big.Int).SetInt64(1)
- R.Lsh(R, uint(rounded64))
+ R.Lsh(R, uint(rounded))
+ R.Mod(R, p)
+ return R
+}
+
+func montgomeryRR(p *big.Int, wordSize int) *big.Int {
+ R := montgomeryR(p, wordSize)
+ R.Mul(R, R)
+ R.Mod(R, p)
+ return R
+}
- ret := new(big.Int).Mul(n, R)
- ret.Mod(ret, params.P)
+func montgomeryN0(p *big.Int) uint64 {
+ two64 := new(big.Int)
+ two64 = two64.SetBit(two64, 64, 1)
+ n0 := new(big.Int).Neg(p)
+ n0 = n0.ModInverse(n0, two64)
+ if !n0.IsUint64() {
+ panic("n0 should fit in uint64")
+ }
+ return n0.Uint64()
+}
+
+// toMontgomery returns n×R mod p, where R is the Montgomery factor.
+func toMontgomery(n, p *big.Int, wordSize int) *big.Int {
+ ret := montgomeryR(p, wordSize)
+ ret.Mul(ret, n)
+ ret.Mod(ret, p)
return ret
}
@@ -251,17 +392,35 @@ func bigIntToU64s(curve elliptic.Curve, n *big.Int) []uint64 {
return ret
}
-func bigIntToU32s(curve elliptic.Curve, n *big.Int) []uint64 {
+func bigIntToU32s(curve elliptic.Curve, n *big.Int) []uint32 {
words := (curve.Params().BitSize + 31) / 32
- ret := make([]uint64, words)
+ ret := make([]uint32, words)
bytes := n.Bytes()
for i, b := range bytes {
i = len(bytes) - i - 1
- ret[i/4] |= uint64(b) << (8 * (i % 4))
+ ret[i/4] |= uint32(b) << (8 * (i % 4))
}
return ret
}
+// A columnWriter is an io.Writer that tracks the number of columns in the
+// current line.
+type columnWriter struct {
+ w io.Writer
+ column int
+}
+
+func (c *columnWriter) Write(p []byte) (n int, err error) {
+ n, err = c.w.Write(p)
+ idx := bytes.LastIndexByte(p[:n], '\n')
+ if idx < 0 {
+ c.column += n
+ } else {
+ c.column = n - idx - 1
+ }
+ return
+}
+
func writeIndent(w io.Writer, indent int) error {
for i := 0; i < indent; i++ {
if _, err := io.WriteString(w, " "); err != nil {
@@ -271,17 +430,29 @@ func writeIndent(w io.Writer, indent int) error {
return nil
}
-func writeWords(w io.Writer, words []uint64, wrap, indent int, format func(uint64) string) error {
+func writeWordsBraced[Word any](w *columnWriter, words []Word, format func(Word) string) error {
if _, err := io.WriteString(w, "{"); err != nil {
return err
}
+ if err := writeWords(w, words, format); err != nil {
+ return err
+ }
+ if _, err := io.WriteString(w, "}"); err != nil {
+ return err
+ }
+ return nil
+}
+
+func writeWords[Word any](w *columnWriter, words []Word, format func(Word) string) error {
+ indent := w.column
for i, word := range words {
+ str := format(word)
if i > 0 {
- if i%wrap == 0 {
+ if w.column+1+len(str) > 80 {
if _, err := io.WriteString(w, ",\n"); err != nil {
return err
}
- if err := writeIndent(w, indent+1); err != nil {
+ if err := writeIndent(w, indent); err != nil {
return err
}
} else {
@@ -290,56 +461,72 @@ func writeWords(w io.Writer, words []uint64, wrap, indent int, format func(uint6
}
}
}
- if _, err := io.WriteString(w, format(word)); err != nil {
+ if _, err := io.WriteString(w, str); err != nil {
return err
}
}
- if _, err := io.WriteString(w, "}"); err != nil {
+ return nil
+}
+
+func writeDecl(w *columnWriter, curve elliptic.Curve, bits int, decl string, n *big.Int) error {
+ if _, err := fmt.Fprintf(w, "OPENSSL_UNUSED static const uint%d_t %s[] = {\n ", bits, decl); err != nil {
+ return err
+ }
+ if bits == 32 {
+ if err := writeWords(w, bigIntToU32s(curve, n), formatU32); err != nil {
+ return err
+ }
+ } else if bits == 64 {
+ if err := writeWords(w, bigIntToU64s(curve, n), formatU64); err != nil {
+ return err
+ }
+ } else {
+ panic("unknown bit count")
+ }
+ if _, err := fmt.Fprintf(w, "};\n"); err != nil {
return err
}
return nil
}
-func writeBNMont(w io.Writer, curve elliptic.Curve, n *big.Int, indent int) error {
- n = toMontgomery(curve, n)
- return writeWords(w, bigIntToU64s(curve, n), 2, indent, func(word uint64) string {
- return fmt.Sprintf("TOBN(0x%08x, 0x%08x)", uint32(word>>32), uint32(word))
- })
+func formatBN(word uint64) string {
+ return fmt.Sprintf("TOBN(0x%08x, 0x%08x)", uint32(word>>32), uint32(word))
}
-func writeU64Mont(w io.Writer, curve elliptic.Curve, n *big.Int, indent int) error {
- n = toMontgomery(curve, n)
- return writeWords(w, bigIntToU64s(curve, n), 3, indent, func(word uint64) string {
- return fmt.Sprintf("0x%016x", word)
- })
+func formatU64(word uint64) string {
+ return fmt.Sprintf("0x%016x", word)
}
-func writeU32Mont(w io.Writer, curve elliptic.Curve, n *big.Int, indent int) error {
- n = toMontgomery(curve, n)
- return writeWords(w, bigIntToU32s(curve, n), 6, indent, func(word uint64) string {
- if word >= 1<<32 {
- panic(fmt.Sprintf("word too large: 0x%x", word))
- }
- return fmt.Sprintf("0x%08x", word)
- })
+func formatU32(word uint32) string {
+ return fmt.Sprintf("0x%08x", word)
+}
+
+func writeBNMont(w *columnWriter, curve elliptic.Curve, n *big.Int) error {
+ n32 := toMontgomery(n, curve.Params().P, 32)
+ n64 := toMontgomery(n, curve.Params().P, 64)
+ if n32.Cmp(n64) != 0 {
+ panic(fmt.Sprintf("Montgomery form for %s is inconsistent between 32-bit and 64-bit", curve.Params().Name))
+ }
+ return writeWordsBraced(w, bigIntToU64s(curve, n64), formatBN)
}
-type writeBigIntFunc func(w io.Writer, curve elliptic.Curve, n *big.Int, indent int) error
+func writeU64Mont(w *columnWriter, curve elliptic.Curve, n *big.Int) error {
+ n = toMontgomery(n, curve.Params().P, 64)
+ return writeWordsBraced(w, bigIntToU64s(curve, n), formatU64)
+}
+
+func writeU32Mont(w *columnWriter, curve elliptic.Curve, n *big.Int) error {
+ n = toMontgomery(n, curve.Params().P, 32)
+ return writeWordsBraced(w, bigIntToU32s(curve, n), formatU32)
+}
-func writeTable(w io.Writer, curve elliptic.Curve, table [][2]*big.Int, isRoot bool, indent int, writeBigInt writeBigIntFunc) error {
+type writeBigIntFunc func(w *columnWriter, curve elliptic.Curve, n *big.Int) error
+
+func writeTable(w *columnWriter, curve elliptic.Curve, table [][2]*big.Int, writeBigInt writeBigIntFunc) error {
if _, err := io.WriteString(w, "{"); err != nil {
return err
}
- if isRoot {
- if _, err := io.WriteString(w, "\n"); err != nil {
- return err
- }
- if err := writeIndent(w, indent); err != nil {
- return err
- }
- } else {
- indent++
- }
+ indent := w.column
for i, point := range table {
if i != 0 {
if _, err := io.WriteString(w, ",\n"); err != nil {
@@ -352,7 +539,7 @@ func writeTable(w io.Writer, curve elliptic.Curve, table [][2]*big.Int, isRoot b
if _, err := io.WriteString(w, "{"); err != nil {
return err
}
- if err := writeBigInt(w, curve, point[0], indent+1); err != nil {
+ if err := writeBigInt(w, curve, point[0]); err != nil {
return err
}
if _, err := io.WriteString(w, ",\n"); err != nil {
@@ -361,7 +548,7 @@ func writeTable(w io.Writer, curve elliptic.Curve, table [][2]*big.Int, isRoot b
if err := writeIndent(w, indent+1); err != nil {
return err
}
- if err := writeBigInt(w, curve, point[1], indent+1); err != nil {
+ if err := writeBigInt(w, curve, point[1]); err != nil {
return err
}
if _, err := io.WriteString(w, "}"); err != nil {
@@ -374,20 +561,11 @@ func writeTable(w io.Writer, curve elliptic.Curve, table [][2]*big.Int, isRoot b
return nil
}
-func writeTables(w io.Writer, curve elliptic.Curve, tables [][][2]*big.Int, isRoot bool, indent int, writeBigInt writeBigIntFunc) error {
- if _, err := io.WriteString(w, "{"); err != nil {
+func writeTables(w *columnWriter, curve elliptic.Curve, tables [][][2]*big.Int, writeBigInt writeBigIntFunc) error {
+ if _, err := io.WriteString(w, "{\n "); err != nil {
return err
}
- if isRoot {
- if _, err := io.WriteString(w, "\n"); err != nil {
- return err
- }
- if err := writeIndent(w, indent); err != nil {
- return err
- }
- } else {
- indent++
- }
+ indent := w.column
for i, table := range tables {
if i != 0 {
if _, err := io.WriteString(w, ",\n"); err != nil {
@@ -397,7 +575,7 @@ func writeTables(w io.Writer, curve elliptic.Curve, tables [][][2]*big.Int, isRo
return err
}
}
- if err := writeTable(w, curve, table, false, indent, writeBigInt); err != nil {
+ if err := writeTable(w, curve, table, writeBigInt); err != nil {
return err
}
}
diff --git a/src/crypto/fipsmodule/ec/oct.c b/src/crypto/fipsmodule/ec/oct.c
index eb77643c..6cb84f5b 100644
--- a/src/crypto/fipsmodule/ec/oct.c
+++ b/src/crypto/fipsmodule/ec/oct.c
@@ -80,7 +80,7 @@ size_t ec_point_byte_len(const EC_GROUP *group, point_conversion_form_t form) {
return 0;
}
- const size_t field_len = BN_num_bytes(&group->field);
+ const size_t field_len = BN_num_bytes(&group->field.N);
size_t output_len = 1 /* type byte */ + field_len;
if (form == POINT_CONVERSION_UNCOMPRESSED) {
// Uncompressed points have a second coordinate.
@@ -100,11 +100,11 @@ size_t ec_point_to_bytes(const EC_GROUP *group, const EC_AFFINE *point,
size_t field_len;
ec_felem_to_bytes(group, buf + 1, &field_len, &point->X);
- assert(field_len == BN_num_bytes(&group->field));
+ assert(field_len == BN_num_bytes(&group->field.N));
if (form == POINT_CONVERSION_UNCOMPRESSED) {
ec_felem_to_bytes(group, buf + 1 + field_len, &field_len, &point->Y);
- assert(field_len == BN_num_bytes(&group->field));
+ assert(field_len == BN_num_bytes(&group->field.N));
buf[0] = form;
} else {
uint8_t y_buf[EC_MAX_BYTES];
@@ -117,7 +117,7 @@ size_t ec_point_to_bytes(const EC_GROUP *group, const EC_AFFINE *point,
int ec_point_from_uncompressed(const EC_GROUP *group, EC_AFFINE *out,
const uint8_t *in, size_t len) {
- const size_t field_len = BN_num_bytes(&group->field);
+ const size_t field_len = BN_num_bytes(&group->field.N);
if (len != 1 + 2 * field_len || in[0] != POINT_CONVERSION_UNCOMPRESSED) {
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_ENCODING);
return 0;
@@ -155,7 +155,7 @@ static int ec_GFp_simple_oct2point(const EC_GROUP *group, EC_POINT *point,
}
const int y_bit = form & 1;
- const size_t field_len = BN_num_bytes(&group->field);
+ const size_t field_len = BN_num_bytes(&group->field.N);
form = form & ~1u;
if (form != POINT_CONVERSION_COMPRESSED ||
len != 1 /* type byte */ + field_len) {
@@ -182,7 +182,7 @@ static int ec_GFp_simple_oct2point(const EC_GROUP *group, EC_POINT *point,
if (x == NULL || !BN_bin2bn(buf + 1, field_len, x)) {
goto err;
}
- if (BN_ucmp(x, &group->field) >= 0) {
+ if (BN_ucmp(x, &group->field.N) >= 0) {
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_ENCODING);
goto err;
}
@@ -260,7 +260,8 @@ int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *group,
return 0;
}
- if (BN_is_negative(x) || BN_cmp(x, &group->field) >= 0) {
+ const BIGNUM *field = &group->field.N;
+ if (BN_is_negative(x) || BN_cmp(x, field) >= 0) {
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_COMPRESSED_POINT);
return 0;
}
@@ -295,31 +296,31 @@ int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *group,
// so y is one of the square roots of x^3 + a*x + b.
// tmp1 := x^3
- if (!BN_mod_sqr(tmp2, x, &group->field, ctx) ||
- !BN_mod_mul(tmp1, tmp2, x, &group->field, ctx)) {
+ if (!BN_mod_sqr(tmp2, x, field, ctx) ||
+ !BN_mod_mul(tmp1, tmp2, x, field, ctx)) {
goto err;
}
// tmp1 := tmp1 + a*x
if (group->a_is_minus3) {
- if (!bn_mod_lshift1_consttime(tmp2, x, &group->field, ctx) ||
- !bn_mod_add_consttime(tmp2, tmp2, x, &group->field, ctx) ||
- !bn_mod_sub_consttime(tmp1, tmp1, tmp2, &group->field, ctx)) {
+ if (!bn_mod_lshift1_consttime(tmp2, x, field, ctx) ||
+ !bn_mod_add_consttime(tmp2, tmp2, x, field, ctx) ||
+ !bn_mod_sub_consttime(tmp1, tmp1, tmp2, field, ctx)) {
goto err;
}
} else {
- if (!BN_mod_mul(tmp2, a, x, &group->field, ctx) ||
- !bn_mod_add_consttime(tmp1, tmp1, tmp2, &group->field, ctx)) {
+ if (!BN_mod_mul(tmp2, a, x, field, ctx) ||
+ !bn_mod_add_consttime(tmp1, tmp1, tmp2, field, ctx)) {
goto err;
}
}
// tmp1 := tmp1 + b
- if (!bn_mod_add_consttime(tmp1, tmp1, b, &group->field, ctx)) {
+ if (!bn_mod_add_consttime(tmp1, tmp1, b, field, ctx)) {
goto err;
}
- if (!BN_mod_sqrt(y, tmp1, &group->field, ctx)) {
+ if (!BN_mod_sqrt(y, tmp1, field, ctx)) {
uint32_t err = ERR_peek_last_error();
if (ERR_GET_LIB(err) == ERR_LIB_BN &&
ERR_GET_REASON(err) == BN_R_NOT_A_SQUARE) {
@@ -336,7 +337,7 @@ int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *group,
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_COMPRESSION_BIT);
goto err;
}
- if (!BN_usub(y, &group->field, y)) {
+ if (!BN_usub(y, field, y)) {
goto err;
}
}
diff --git a/src/crypto/fipsmodule/ec/p224-64.c b/src/crypto/fipsmodule/ec/p224-64.c
index 0f51970d..9d0242c6 100644
--- a/src/crypto/fipsmodule/ec/p224-64.c
+++ b/src/crypto/fipsmodule/ec/p224-64.c
@@ -734,8 +734,8 @@ static void p224_point_add(p224_felem x3, p224_felem y3, p224_felem z3,
// tmp[i] < 2^116 + 2^64 + 8 < 2^117
p224_felem_reduce(ftmp, tmp);
- // the formulae are incorrect if the points are equal
- // so we check for this and do doubling if this happens
+ // The formulae are incorrect if the points are equal, so we check for this
+ // and do doubling if this happens.
x_equal = p224_felem_is_zero(ftmp);
y_equal = p224_felem_is_zero(ftmp3);
z1_is_zero = p224_felem_is_zero(z1);
@@ -743,7 +743,7 @@ static void p224_point_add(p224_felem x3, p224_felem y3, p224_felem z3,
// In affine coordinates, (X_1, Y_1) == (X_2, Y_2)
p224_limb is_nontrivial_double =
x_equal & y_equal & (1 - z1_is_zero) & (1 - z2_is_zero);
- if (is_nontrivial_double) {
+ if (constant_time_declassify_w(is_nontrivial_double)) {
p224_point_double(x3, y3, z3, x1, y1, z1);
return;
}
@@ -860,9 +860,10 @@ static crypto_word_t p224_get_bit(const EC_SCALAR *in, size_t i) {
// Takes the Jacobian coordinates (X, Y, Z) of a point and returns
// (X', Y') = (X/Z^2, Y/Z^3)
static int ec_GFp_nistp224_point_get_affine_coordinates(
- const EC_GROUP *group, const EC_RAW_POINT *point, EC_FELEM *x,
+ const EC_GROUP *group, const EC_JACOBIAN *point, EC_FELEM *x,
EC_FELEM *y) {
- if (ec_GFp_simple_is_at_infinity(group, point)) {
+ if (constant_time_declassify_int(
+ ec_GFp_simple_is_at_infinity(group, point))) {
OPENSSL_PUT_ERROR(EC, EC_R_POINT_AT_INFINITY);
return 0;
}
@@ -895,8 +896,8 @@ static int ec_GFp_nistp224_point_get_affine_coordinates(
return 1;
}
-static void ec_GFp_nistp224_add(const EC_GROUP *group, EC_RAW_POINT *r,
- const EC_RAW_POINT *a, const EC_RAW_POINT *b) {
+static void ec_GFp_nistp224_add(const EC_GROUP *group, EC_JACOBIAN *r,
+ const EC_JACOBIAN *a, const EC_JACOBIAN *b) {
p224_felem x1, y1, z1, x2, y2, z2;
p224_generic_to_felem(x1, &a->X);
p224_generic_to_felem(y1, &a->Y);
@@ -911,8 +912,8 @@ static void ec_GFp_nistp224_add(const EC_GROUP *group, EC_RAW_POINT *r,
p224_felem_to_generic(&r->Z, z1);
}
-static void ec_GFp_nistp224_dbl(const EC_GROUP *group, EC_RAW_POINT *r,
- const EC_RAW_POINT *a) {
+static void ec_GFp_nistp224_dbl(const EC_GROUP *group, EC_JACOBIAN *r,
+ const EC_JACOBIAN *a) {
p224_felem x, y, z;
p224_generic_to_felem(x, &a->X);
p224_generic_to_felem(y, &a->Y);
@@ -925,7 +926,7 @@ static void ec_GFp_nistp224_dbl(const EC_GROUP *group, EC_RAW_POINT *r,
}
static void ec_GFp_nistp224_make_precomp(p224_felem out[17][3],
- const EC_RAW_POINT *p) {
+ const EC_JACOBIAN *p) {
OPENSSL_memset(out[0], 0, sizeof(p224_felem) * 3);
p224_generic_to_felem(out[1][0], &p->X);
@@ -943,8 +944,8 @@ static void ec_GFp_nistp224_make_precomp(p224_felem out[17][3],
}
}
-static void ec_GFp_nistp224_point_mul(const EC_GROUP *group, EC_RAW_POINT *r,
- const EC_RAW_POINT *p,
+static void ec_GFp_nistp224_point_mul(const EC_GROUP *group, EC_JACOBIAN *r,
+ const EC_JACOBIAN *p,
const EC_SCALAR *scalar) {
p224_felem p_pre_comp[17][3];
ec_GFp_nistp224_make_precomp(p_pre_comp, p);
@@ -992,7 +993,7 @@ static void ec_GFp_nistp224_point_mul(const EC_GROUP *group, EC_RAW_POINT *r,
}
static void ec_GFp_nistp224_point_mul_base(const EC_GROUP *group,
- EC_RAW_POINT *r,
+ EC_JACOBIAN *r,
const EC_SCALAR *scalar) {
// Set nq to the point at infinity.
p224_felem nq[3], tmp[3];
@@ -1039,9 +1040,9 @@ static void ec_GFp_nistp224_point_mul_base(const EC_GROUP *group,
}
static void ec_GFp_nistp224_point_mul_public(const EC_GROUP *group,
- EC_RAW_POINT *r,
+ EC_JACOBIAN *r,
const EC_SCALAR *g_scalar,
- const EC_RAW_POINT *p,
+ const EC_JACOBIAN *p,
const EC_SCALAR *p_scalar) {
// TODO(davidben): If P-224 ECDSA verify performance ever matters, using
// |ec_compute_wNAF| for |p_scalar| would likely be an easy improvement.
@@ -1141,9 +1142,6 @@ static void ec_GFp_nistp224_felem_sqr(const EC_GROUP *group, EC_FELEM *r,
}
DEFINE_METHOD_FUNCTION(EC_METHOD, EC_GFp_nistp224_method) {
- out->group_init = ec_GFp_simple_group_init;
- out->group_finish = ec_GFp_simple_group_finish;
- out->group_set_curve = ec_GFp_simple_group_set_curve;
out->point_get_affine_coordinates =
ec_GFp_nistp224_point_get_affine_coordinates;
out->add = ec_GFp_nistp224_add;
diff --git a/src/crypto/fipsmodule/ec/p256-nistz.c b/src/crypto/fipsmodule/ec/p256-nistz.c
index c56222b4..cf099638 100644
--- a/src/crypto/fipsmodule/ec/p256-nistz.c
+++ b/src/crypto/fipsmodule/ec/p256-nistz.c
@@ -187,11 +187,11 @@ static void ecp_nistz256_mod_inverse_sqr_mont(BN_ULONG r[P256_LIMBS],
// r = p * p_scalar
static void ecp_nistz256_windowed_mul(const EC_GROUP *group, P256_POINT *r,
- const EC_RAW_POINT *p,
+ const EC_JACOBIAN *p,
const EC_SCALAR *p_scalar) {
assert(p != NULL);
assert(p_scalar != NULL);
- assert(group->field.width == P256_LIMBS);
+ assert(group->field.N.width == P256_LIMBS);
static const size_t kWindowSize = 5;
static const crypto_word_t kMask = (1 << (5 /* kWindowSize */ + 1)) - 1;
@@ -208,7 +208,7 @@ static void ecp_nistz256_windowed_mul(const EC_GROUP *group, P256_POINT *r,
// not stored. All other values are actually stored with an offset of -1 in
// table.
P256_POINT *row = table;
- assert(group->field.width == P256_LIMBS);
+ assert(group->field.N.width == P256_LIMBS);
OPENSSL_memcpy(row[1 - 1].X, p->X.words, P256_LIMBS * sizeof(BN_ULONG));
OPENSSL_memcpy(row[1 - 1].Y, p->Y.words, P256_LIMBS * sizeof(BN_ULONG));
OPENSSL_memcpy(row[1 - 1].Z, p->Z.words, P256_LIMBS * sizeof(BN_ULONG));
@@ -299,19 +299,19 @@ static crypto_word_t calc_wvalue(size_t *index, const uint8_t p_str[33]) {
return booth_recode_w7(wvalue);
}
-static void ecp_nistz256_point_mul(const EC_GROUP *group, EC_RAW_POINT *r,
- const EC_RAW_POINT *p,
+static void ecp_nistz256_point_mul(const EC_GROUP *group, EC_JACOBIAN *r,
+ const EC_JACOBIAN *p,
const EC_SCALAR *scalar) {
alignas(32) P256_POINT out;
ecp_nistz256_windowed_mul(group, &out, p, scalar);
- assert(group->field.width == P256_LIMBS);
+ assert(group->field.N.width == P256_LIMBS);
OPENSSL_memcpy(r->X.words, out.X, P256_LIMBS * sizeof(BN_ULONG));
OPENSSL_memcpy(r->Y.words, out.Y, P256_LIMBS * sizeof(BN_ULONG));
OPENSSL_memcpy(r->Z.words, out.Z, P256_LIMBS * sizeof(BN_ULONG));
}
-static void ecp_nistz256_point_mul_base(const EC_GROUP *group, EC_RAW_POINT *r,
+static void ecp_nistz256_point_mul_base(const EC_GROUP *group, EC_JACOBIAN *r,
const EC_SCALAR *scalar) {
uint8_t p_str[33];
OPENSSL_memcpy(p_str, scalar->words, 32);
@@ -349,16 +349,16 @@ static void ecp_nistz256_point_mul_base(const EC_GROUP *group, EC_RAW_POINT *r,
ecp_nistz256_point_add_affine(&p, &p, &t);
}
- assert(group->field.width == P256_LIMBS);
+ assert(group->field.N.width == P256_LIMBS);
OPENSSL_memcpy(r->X.words, p.X, P256_LIMBS * sizeof(BN_ULONG));
OPENSSL_memcpy(r->Y.words, p.Y, P256_LIMBS * sizeof(BN_ULONG));
OPENSSL_memcpy(r->Z.words, p.Z, P256_LIMBS * sizeof(BN_ULONG));
}
static void ecp_nistz256_points_mul_public(const EC_GROUP *group,
- EC_RAW_POINT *r,
+ EC_JACOBIAN *r,
const EC_SCALAR *g_scalar,
- const EC_RAW_POINT *p_,
+ const EC_JACOBIAN *p_,
const EC_SCALAR *p_scalar) {
assert(p_ != NULL && p_scalar != NULL && g_scalar != NULL);
@@ -413,22 +413,23 @@ static void ecp_nistz256_points_mul_public(const EC_GROUP *group,
ecp_nistz256_windowed_mul(group, &tmp, p_, p_scalar);
ecp_nistz256_point_add(&p, &p, &tmp);
- assert(group->field.width == P256_LIMBS);
+ assert(group->field.N.width == P256_LIMBS);
OPENSSL_memcpy(r->X.words, p.X, P256_LIMBS * sizeof(BN_ULONG));
OPENSSL_memcpy(r->Y.words, p.Y, P256_LIMBS * sizeof(BN_ULONG));
OPENSSL_memcpy(r->Z.words, p.Z, P256_LIMBS * sizeof(BN_ULONG));
}
static int ecp_nistz256_get_affine(const EC_GROUP *group,
- const EC_RAW_POINT *point, EC_FELEM *x,
+ const EC_JACOBIAN *point, EC_FELEM *x,
EC_FELEM *y) {
- if (ec_GFp_simple_is_at_infinity(group, point)) {
+ if (constant_time_declassify_int(
+ ec_GFp_simple_is_at_infinity(group, point))) {
OPENSSL_PUT_ERROR(EC, EC_R_POINT_AT_INFINITY);
return 0;
}
BN_ULONG z_inv2[P256_LIMBS];
- assert(group->field.width == P256_LIMBS);
+ assert(group->field.N.width == P256_LIMBS);
ecp_nistz256_mod_inverse_sqr_mont(z_inv2, point->Z.words);
if (x != NULL) {
@@ -444,8 +445,8 @@ static int ecp_nistz256_get_affine(const EC_GROUP *group,
return 1;
}
-static void ecp_nistz256_add(const EC_GROUP *group, EC_RAW_POINT *r,
- const EC_RAW_POINT *a_, const EC_RAW_POINT *b_) {
+static void ecp_nistz256_add(const EC_GROUP *group, EC_JACOBIAN *r,
+ const EC_JACOBIAN *a_, const EC_JACOBIAN *b_) {
P256_POINT a, b;
OPENSSL_memcpy(a.X, a_->X.words, P256_LIMBS * sizeof(BN_ULONG));
OPENSSL_memcpy(a.Y, a_->Y.words, P256_LIMBS * sizeof(BN_ULONG));
@@ -459,8 +460,8 @@ static void ecp_nistz256_add(const EC_GROUP *group, EC_RAW_POINT *r,
OPENSSL_memcpy(r->Z.words, a.Z, P256_LIMBS * sizeof(BN_ULONG));
}
-static void ecp_nistz256_dbl(const EC_GROUP *group, EC_RAW_POINT *r,
- const EC_RAW_POINT *a_) {
+static void ecp_nistz256_dbl(const EC_GROUP *group, EC_JACOBIAN *r,
+ const EC_JACOBIAN *a_) {
P256_POINT a;
OPENSSL_memcpy(a.X, a_->X.words, P256_LIMBS * sizeof(BN_ULONG));
OPENSSL_memcpy(a.Y, a_->Y.words, P256_LIMBS * sizeof(BN_ULONG));
@@ -562,8 +563,8 @@ static int ecp_nistz256_scalar_to_montgomery_inv_vartime(const EC_GROUP *group,
}
#endif
- assert(group->order.width == P256_LIMBS);
- if (!beeu_mod_inverse_vartime(out->words, in->words, group->order.d)) {
+ assert(group->order.N.width == P256_LIMBS);
+ if (!beeu_mod_inverse_vartime(out->words, in->words, group->order.N.d)) {
return 0;
}
@@ -573,14 +574,14 @@ static int ecp_nistz256_scalar_to_montgomery_inv_vartime(const EC_GROUP *group,
}
static int ecp_nistz256_cmp_x_coordinate(const EC_GROUP *group,
- const EC_RAW_POINT *p,
+ const EC_JACOBIAN *p,
const EC_SCALAR *r) {
if (ec_GFp_simple_is_at_infinity(group, p)) {
return 0;
}
- assert(group->order.width == P256_LIMBS);
- assert(group->field.width == P256_LIMBS);
+ assert(group->order.N.width == P256_LIMBS);
+ assert(group->field.N.width == P256_LIMBS);
// We wish to compare X/Z^2 with r. This is equivalent to comparing X with
// r*Z^2. Note that X and Z are represented in Montgomery form, while r is
@@ -598,10 +599,9 @@ static int ecp_nistz256_cmp_x_coordinate(const EC_GROUP *group,
// Therefore there is a small possibility, less than 1/2^128, that group_order
// < p.x < P. in that case we need not only to compare against |r| but also to
// compare against r+group_order.
- if (bn_less_than_words(r->words, group->field_minus_order.words,
- P256_LIMBS)) {
- // We can ignore the carry because: r + group_order < p < 2^256.
- bn_add_words(r_Z2, r->words, group->order.d, P256_LIMBS);
+ BN_ULONG carry = bn_add_words(r_Z2, r->words, group->order.N.d, P256_LIMBS);
+ if (carry == 0 && bn_less_than_words(r_Z2, group->field.N.d, P256_LIMBS)) {
+ // r + group_order < p, so compare (r + group_order) * Z^2 against X.
ecp_nistz256_mul_mont(r_Z2, r_Z2, Z2_mont);
if (OPENSSL_memcmp(r_Z2, X, sizeof(r_Z2)) == 0) {
return 1;
@@ -612,9 +612,6 @@ static int ecp_nistz256_cmp_x_coordinate(const EC_GROUP *group,
}
DEFINE_METHOD_FUNCTION(EC_METHOD, EC_GFp_nistz256_method) {
- out->group_init = ec_GFp_mont_group_init;
- out->group_finish = ec_GFp_mont_group_finish;
- out->group_set_curve = ec_GFp_mont_group_set_curve;
out->point_get_affine_coordinates = ecp_nistz256_get_affine;
out->add = ecp_nistz256_add;
out->dbl = ecp_nistz256_dbl;
diff --git a/src/crypto/fipsmodule/ec/p256-nistz_test.cc b/src/crypto/fipsmodule/ec/p256-nistz_test.cc
index a53d94ee..56eed08a 100644
--- a/src/crypto/fipsmodule/ec/p256-nistz_test.cc
+++ b/src/crypto/fipsmodule/ec/p256-nistz_test.cc
@@ -109,13 +109,10 @@ TEST(P256_NistzTest, BEEU) {
}
#endif
- bssl::UniquePtr<EC_GROUP> group(
- EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
- ASSERT_TRUE(group);
-
+ const EC_GROUP *group = EC_group_p256();
BN_ULONG order_words[P256_LIMBS];
ASSERT_TRUE(
- bn_copy_words(order_words, P256_LIMBS, EC_GROUP_get0_order(group.get())));
+ bn_copy_words(order_words, P256_LIMBS, EC_GROUP_get0_order(group)));
BN_ULONG in[P256_LIMBS], out[P256_LIMBS];
EC_SCALAR in_scalar, out_scalar, result;
@@ -154,9 +151,9 @@ TEST(P256_NistzTest, BEEU) {
// Calculate out*in and confirm that it equals one, modulo the order.
OPENSSL_memcpy(in_scalar.words, in, sizeof(in));
OPENSSL_memcpy(out_scalar.words, out, sizeof(out));
- ec_scalar_to_montgomery(group.get(), &in_scalar, &in_scalar);
- ec_scalar_to_montgomery(group.get(), &out_scalar, &out_scalar);
- ec_scalar_mul_montgomery(group.get(), &result, &in_scalar, &out_scalar);
+ ec_scalar_to_montgomery(group, &in_scalar, &in_scalar);
+ ec_scalar_to_montgomery(group, &out_scalar, &out_scalar);
+ ec_scalar_mul_montgomery(group, &result, &in_scalar, &out_scalar);
EXPECT_EQ(0, OPENSSL_memcmp(kOneMont, &result, sizeof(kOneMont)));
diff --git a/src/crypto/fipsmodule/ec/p256.c b/src/crypto/fipsmodule/ec/p256.c
index cd2b6fc0..e532e2fd 100644
--- a/src/crypto/fipsmodule/ec/p256.c
+++ b/src/crypto/fipsmodule/ec/p256.c
@@ -324,7 +324,7 @@ static void fiat_p256_point_add(fiat_p256_felem x3, fiat_p256_felem y3,
fiat_p256_limb_t is_nontrivial_double = constant_time_is_zero_w(xneq | yneq) &
~constant_time_is_zero_w(z1nz) &
~constant_time_is_zero_w(z2nz);
- if (is_nontrivial_double) {
+ if (constant_time_declassify_w(is_nontrivial_double)) {
fiat_p256_point_double(x3, y3, z3, x1, y1, z1);
return;
}
@@ -414,9 +414,10 @@ static crypto_word_t fiat_p256_get_bit(const EC_SCALAR *in, int i) {
// Takes the Jacobian coordinates (X, Y, Z) of a point and returns (X', Y') =
// (X/Z^2, Y/Z^3).
static int ec_GFp_nistp256_point_get_affine_coordinates(
- const EC_GROUP *group, const EC_RAW_POINT *point, EC_FELEM *x_out,
+ const EC_GROUP *group, const EC_JACOBIAN *point, EC_FELEM *x_out,
EC_FELEM *y_out) {
- if (ec_GFp_simple_is_at_infinity(group, point)) {
+ if (constant_time_declassify_int(
+ ec_GFp_simple_is_at_infinity(group, point))) {
OPENSSL_PUT_ERROR(EC, EC_R_POINT_AT_INFINITY);
return 0;
}
@@ -444,8 +445,8 @@ static int ec_GFp_nistp256_point_get_affine_coordinates(
return 1;
}
-static void ec_GFp_nistp256_add(const EC_GROUP *group, EC_RAW_POINT *r,
- const EC_RAW_POINT *a, const EC_RAW_POINT *b) {
+static void ec_GFp_nistp256_add(const EC_GROUP *group, EC_JACOBIAN *r,
+ const EC_JACOBIAN *a, const EC_JACOBIAN *b) {
fiat_p256_felem x1, y1, z1, x2, y2, z2;
fiat_p256_from_generic(x1, &a->X);
fiat_p256_from_generic(y1, &a->Y);
@@ -460,8 +461,8 @@ static void ec_GFp_nistp256_add(const EC_GROUP *group, EC_RAW_POINT *r,
fiat_p256_to_generic(&r->Z, z1);
}
-static void ec_GFp_nistp256_dbl(const EC_GROUP *group, EC_RAW_POINT *r,
- const EC_RAW_POINT *a) {
+static void ec_GFp_nistp256_dbl(const EC_GROUP *group, EC_JACOBIAN *r,
+ const EC_JACOBIAN *a) {
fiat_p256_felem x, y, z;
fiat_p256_from_generic(x, &a->X);
fiat_p256_from_generic(y, &a->Y);
@@ -472,8 +473,8 @@ static void ec_GFp_nistp256_dbl(const EC_GROUP *group, EC_RAW_POINT *r,
fiat_p256_to_generic(&r->Z, z);
}
-static void ec_GFp_nistp256_point_mul(const EC_GROUP *group, EC_RAW_POINT *r,
- const EC_RAW_POINT *p,
+static void ec_GFp_nistp256_point_mul(const EC_GROUP *group, EC_JACOBIAN *r,
+ const EC_JACOBIAN *p,
const EC_SCALAR *scalar) {
fiat_p256_felem p_pre_comp[17][3];
OPENSSL_memset(&p_pre_comp, 0, sizeof(p_pre_comp));
@@ -540,7 +541,7 @@ static void ec_GFp_nistp256_point_mul(const EC_GROUP *group, EC_RAW_POINT *r,
}
static void ec_GFp_nistp256_point_mul_base(const EC_GROUP *group,
- EC_RAW_POINT *r,
+ EC_JACOBIAN *r,
const EC_SCALAR *scalar) {
// Set nq to the point at infinity.
fiat_p256_felem nq[3] = {{0}, {0}, {0}}, tmp[3];
@@ -588,9 +589,9 @@ static void ec_GFp_nistp256_point_mul_base(const EC_GROUP *group,
}
static void ec_GFp_nistp256_point_mul_public(const EC_GROUP *group,
- EC_RAW_POINT *r,
+ EC_JACOBIAN *r,
const EC_SCALAR *g_scalar,
- const EC_RAW_POINT *p,
+ const EC_JACOBIAN *p,
const EC_SCALAR *p_scalar) {
#define P256_WSIZE_PUBLIC 4
// Precompute multiples of |p|. p_pre_comp[i] is (2*i+1) * |p|.
@@ -680,7 +681,7 @@ static void ec_GFp_nistp256_point_mul_public(const EC_GROUP *group,
}
static int ec_GFp_nistp256_cmp_x_coordinate(const EC_GROUP *group,
- const EC_RAW_POINT *p,
+ const EC_JACOBIAN *p,
const EC_SCALAR *r) {
if (ec_GFp_simple_is_at_infinity(group, p)) {
return 0;
@@ -709,12 +710,12 @@ static int ec_GFp_nistp256_cmp_x_coordinate(const EC_GROUP *group,
// Therefore there is a small possibility, less than 1/2^128, that group_order
// < p.x < P. in that case we need not only to compare against |r| but also to
// compare against r+group_order.
- assert(group->field.width == group->order.width);
- if (bn_less_than_words(r->words, group->field_minus_order.words,
- group->field.width)) {
- // We can ignore the carry because: r + group_order < p < 2^256.
- EC_FELEM tmp;
- bn_add_words(tmp.words, r->words, group->order.d, group->order.width);
+ assert(group->field.N.width == group->order.N.width);
+ EC_FELEM tmp;
+ BN_ULONG carry =
+ bn_add_words(tmp.words, r->words, group->order.N.d, group->field.N.width);
+ if (carry == 0 &&
+ bn_less_than_words(tmp.words, group->field.N.d, group->field.N.width)) {
fiat_p256_from_generic(r_Z2, &tmp);
fiat_p256_mul(r_Z2, r_Z2, Z2_mont);
if (OPENSSL_memcmp(&r_Z2, &X, sizeof(r_Z2)) == 0) {
@@ -726,9 +727,6 @@ static int ec_GFp_nistp256_cmp_x_coordinate(const EC_GROUP *group,
}
DEFINE_METHOD_FUNCTION(EC_METHOD, EC_GFp_nistp256_method) {
- out->group_init = ec_GFp_mont_group_init;
- out->group_finish = ec_GFp_mont_group_finish;
- out->group_set_curve = ec_GFp_mont_group_set_curve;
out->point_get_affine_coordinates =
ec_GFp_nistp256_point_get_affine_coordinates;
out->add = ec_GFp_nistp256_add;
diff --git a/src/crypto/fipsmodule/ec/scalar.c b/src/crypto/fipsmodule/ec/scalar.c
index 036049e0..a86ee0fb 100644
--- a/src/crypto/fipsmodule/ec/scalar.c
+++ b/src/crypto/fipsmodule/ec/scalar.c
@@ -23,8 +23,8 @@
int ec_bignum_to_scalar(const EC_GROUP *group, EC_SCALAR *out,
const BIGNUM *in) {
- if (!bn_copy_words(out->words, group->order.width, in) ||
- !bn_less_than_words(out->words, group->order.d, group->order.width)) {
+ if (!bn_copy_words(out->words, group->order.N.width, in) ||
+ !bn_less_than_words(out->words, group->order.N.d, group->order.N.width)) {
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_SCALAR);
return 0;
}
@@ -34,12 +34,12 @@ int ec_bignum_to_scalar(const EC_GROUP *group, EC_SCALAR *out,
int ec_scalar_equal_vartime(const EC_GROUP *group, const EC_SCALAR *a,
const EC_SCALAR *b) {
return OPENSSL_memcmp(a->words, b->words,
- group->order.width * sizeof(BN_ULONG)) == 0;
+ group->order.N.width * sizeof(BN_ULONG)) == 0;
}
int ec_scalar_is_zero(const EC_GROUP *group, const EC_SCALAR *a) {
BN_ULONG mask = 0;
- for (int i = 0; i < group->order.width; i++) {
+ for (int i = 0; i < group->order.N.width; i++) {
mask |= a->words[i];
}
return mask == 0;
@@ -47,27 +47,27 @@ int ec_scalar_is_zero(const EC_GROUP *group, const EC_SCALAR *a) {
int ec_random_nonzero_scalar(const EC_GROUP *group, EC_SCALAR *out,
const uint8_t additional_data[32]) {
- return bn_rand_range_words(out->words, 1, group->order.d, group->order.width,
- additional_data);
+ return bn_rand_range_words(out->words, 1, group->order.N.d,
+ group->order.N.width, additional_data);
}
void ec_scalar_to_bytes(const EC_GROUP *group, uint8_t *out, size_t *out_len,
const EC_SCALAR *in) {
- size_t len = BN_num_bytes(&group->order);
- bn_words_to_big_endian(out, len, in->words, group->order.width);
+ size_t len = BN_num_bytes(&group->order.N);
+ bn_words_to_big_endian(out, len, in->words, group->order.N.width);
*out_len = len;
}
int ec_scalar_from_bytes(const EC_GROUP *group, EC_SCALAR *out,
const uint8_t *in, size_t len) {
- if (len != BN_num_bytes(&group->order)) {
+ if (len != BN_num_bytes(&group->order.N)) {
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_SCALAR);
return 0;
}
- bn_big_endian_to_words(out->words, group->order.width, in, len);
+ bn_big_endian_to_words(out->words, group->order.N.width, in, len);
- if (!bn_less_than_words(out->words, group->order.d, group->order.width)) {
+ if (!bn_less_than_words(out->words, group->order.N.d, group->order.N.width)) {
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_SCALAR);
return 0;
}
@@ -78,15 +78,15 @@ int ec_scalar_from_bytes(const EC_GROUP *group, EC_SCALAR *out,
void ec_scalar_reduce(const EC_GROUP *group, EC_SCALAR *out,
const BN_ULONG *words, size_t num) {
// Convert "from" Montgomery form so the value is reduced modulo the order.
- bn_from_montgomery_small(out->words, group->order.width, words, num,
- group->order_mont);
+ bn_from_montgomery_small(out->words, group->order.N.width, words, num,
+ &group->order);
// Convert "to" Montgomery form to remove the R^-1 factor added.
ec_scalar_to_montgomery(group, out, out);
}
void ec_scalar_add(const EC_GROUP *group, EC_SCALAR *r, const EC_SCALAR *a,
const EC_SCALAR *b) {
- const BIGNUM *order = &group->order;
+ const BIGNUM *order = &group->order.N;
BN_ULONG tmp[EC_MAX_WORDS];
bn_mod_add_words(r->words, a->words, b->words, order->d, tmp, order->width);
OPENSSL_cleanse(tmp, sizeof(tmp));
@@ -94,7 +94,7 @@ void ec_scalar_add(const EC_GROUP *group, EC_SCALAR *r, const EC_SCALAR *a,
void ec_scalar_sub(const EC_GROUP *group, EC_SCALAR *r, const EC_SCALAR *a,
const EC_SCALAR *b) {
- const BIGNUM *order = &group->order;
+ const BIGNUM *order = &group->order.N;
BN_ULONG tmp[EC_MAX_WORDS];
bn_mod_sub_words(r->words, a->words, b->words, order->d, tmp, order->width);
OPENSSL_cleanse(tmp, sizeof(tmp));
@@ -108,35 +108,35 @@ void ec_scalar_neg(const EC_GROUP *group, EC_SCALAR *r, const EC_SCALAR *a) {
void ec_scalar_select(const EC_GROUP *group, EC_SCALAR *out, BN_ULONG mask,
const EC_SCALAR *a, const EC_SCALAR *b) {
- const BIGNUM *order = &group->order;
+ const BIGNUM *order = &group->order.N;
bn_select_words(out->words, mask, a->words, b->words, order->width);
}
void ec_scalar_to_montgomery(const EC_GROUP *group, EC_SCALAR *r,
const EC_SCALAR *a) {
- const BIGNUM *order = &group->order;
- bn_to_montgomery_small(r->words, a->words, order->width, group->order_mont);
+ const BIGNUM *order = &group->order.N;
+ bn_to_montgomery_small(r->words, a->words, order->width, &group->order);
}
void ec_scalar_from_montgomery(const EC_GROUP *group, EC_SCALAR *r,
const EC_SCALAR *a) {
- const BIGNUM *order = &group->order;
+ const BIGNUM *order = &group->order.N;
bn_from_montgomery_small(r->words, order->width, a->words, order->width,
- group->order_mont);
+ &group->order);
}
void ec_scalar_mul_montgomery(const EC_GROUP *group, EC_SCALAR *r,
const EC_SCALAR *a, const EC_SCALAR *b) {
- const BIGNUM *order = &group->order;
+ const BIGNUM *order = &group->order.N;
bn_mod_mul_montgomery_small(r->words, a->words, b->words, order->width,
- group->order_mont);
+ &group->order);
}
void ec_simple_scalar_inv0_montgomery(const EC_GROUP *group, EC_SCALAR *r,
const EC_SCALAR *a) {
- const BIGNUM *order = &group->order;
+ const BIGNUM *order = &group->order.N;
bn_mod_inverse0_prime_mont_small(r->words, a->words, order->width,
- group->order_mont);
+ &group->order);
}
int ec_simple_scalar_to_montgomery_inv_vartime(const EC_GROUP *group,
diff --git a/src/crypto/fipsmodule/ec/simple.c b/src/crypto/fipsmodule/ec/simple.c
index 58d8121b..406e108b 100644
--- a/src/crypto/fipsmodule/ec/simple.c
+++ b/src/crypto/fipsmodule/ec/simple.c
@@ -88,16 +88,6 @@
// used, it is a Montgomery representation (i.e. 'encoding' means multiplying
// by some factor R).
-int ec_GFp_simple_group_init(EC_GROUP *group) {
- BN_init(&group->field);
- group->a_is_minus3 = 0;
- return 1;
-}
-
-void ec_GFp_simple_group_finish(EC_GROUP *group) {
- BN_free(&group->field);
-}
-
int ec_GFp_simple_group_set_curve(EC_GROUP *group, const BIGNUM *p,
const BIGNUM *a, const BIGNUM *b,
BN_CTX *ctx) {
@@ -114,17 +104,11 @@ int ec_GFp_simple_group_set_curve(EC_GROUP *group, const BIGNUM *p,
goto err;
}
- // group->field
- if (!BN_copy(&group->field, p)) {
- goto err;
- }
- BN_set_negative(&group->field, 0);
- // Store the field in minimal form, so it can be used with |BN_ULONG| arrays.
- bn_set_minimal_width(&group->field);
-
- if (!ec_bignum_to_felem(group, &group->a, a) ||
+ if (!BN_MONT_CTX_set(&group->field, p, ctx) ||
+ !ec_bignum_to_felem(group, &group->a, a) ||
!ec_bignum_to_felem(group, &group->b, b) ||
- !ec_bignum_to_felem(group, &group->one, BN_value_one())) {
+ // Reuse Z from the generator to cache the value one.
+ !ec_bignum_to_felem(group, &group->generator.raw.Z, BN_value_one())) {
goto err;
}
@@ -133,7 +117,7 @@ int ec_GFp_simple_group_set_curve(EC_GROUP *group, const BIGNUM *p,
!BN_add_word(tmp, 3)) {
goto err;
}
- group->a_is_minus3 = (0 == BN_cmp(tmp, &group->field));
+ group->a_is_minus3 = (0 == BN_cmp(tmp, &group->field.N));
ret = 1;
@@ -144,7 +128,7 @@ err:
int ec_GFp_simple_group_get_curve(const EC_GROUP *group, BIGNUM *p, BIGNUM *a,
BIGNUM *b) {
- if ((p != NULL && !BN_copy(p, &group->field)) ||
+ if ((p != NULL && !BN_copy(p, &group->field.N)) ||
(a != NULL && !ec_felem_to_bignum(group, a, &group->a)) ||
(b != NULL && !ec_felem_to_bignum(group, b, &group->b))) {
return 0;
@@ -152,36 +136,36 @@ int ec_GFp_simple_group_get_curve(const EC_GROUP *group, BIGNUM *p, BIGNUM *a,
return 1;
}
-void ec_GFp_simple_point_init(EC_RAW_POINT *point) {
+void ec_GFp_simple_point_init(EC_JACOBIAN *point) {
OPENSSL_memset(&point->X, 0, sizeof(EC_FELEM));
OPENSSL_memset(&point->Y, 0, sizeof(EC_FELEM));
OPENSSL_memset(&point->Z, 0, sizeof(EC_FELEM));
}
-void ec_GFp_simple_point_copy(EC_RAW_POINT *dest, const EC_RAW_POINT *src) {
+void ec_GFp_simple_point_copy(EC_JACOBIAN *dest, const EC_JACOBIAN *src) {
OPENSSL_memcpy(&dest->X, &src->X, sizeof(EC_FELEM));
OPENSSL_memcpy(&dest->Y, &src->Y, sizeof(EC_FELEM));
OPENSSL_memcpy(&dest->Z, &src->Z, sizeof(EC_FELEM));
}
void ec_GFp_simple_point_set_to_infinity(const EC_GROUP *group,
- EC_RAW_POINT *point) {
+ EC_JACOBIAN *point) {
// Although it is strictly only necessary to zero Z, we zero the entire point
// in case |point| was stack-allocated and yet to be initialized.
ec_GFp_simple_point_init(point);
}
-void ec_GFp_simple_invert(const EC_GROUP *group, EC_RAW_POINT *point) {
+void ec_GFp_simple_invert(const EC_GROUP *group, EC_JACOBIAN *point) {
ec_felem_neg(group, &point->Y, &point->Y);
}
int ec_GFp_simple_is_at_infinity(const EC_GROUP *group,
- const EC_RAW_POINT *point) {
+ const EC_JACOBIAN *point) {
return ec_felem_non_zero_mask(group, &point->Z) == 0;
}
int ec_GFp_simple_is_on_curve(const EC_GROUP *group,
- const EC_RAW_POINT *point) {
+ const EC_JACOBIAN *point) {
// We have a curve defined by a Weierstrass equation
// y^2 = x^3 + a*x + b.
// The point to consider is given in Jacobian projective coordinates
@@ -237,8 +221,8 @@ int ec_GFp_simple_is_on_curve(const EC_GROUP *group,
return 1 & ~(not_infinity & not_equal);
}
-int ec_GFp_simple_points_equal(const EC_GROUP *group, const EC_RAW_POINT *a,
- const EC_RAW_POINT *b) {
+int ec_GFp_simple_points_equal(const EC_GROUP *group, const EC_JACOBIAN *a,
+ const EC_JACOBIAN *b) {
// This function is implemented in constant-time for two reasons. First,
// although EC points are usually public, their Jacobian Z coordinates may be
// secret, or at least are not obviously public. Second, more complex
@@ -285,7 +269,7 @@ int ec_GFp_simple_points_equal(const EC_GROUP *group, const EC_RAW_POINT *a,
}
int ec_affine_jacobian_equal(const EC_GROUP *group, const EC_AFFINE *a,
- const EC_RAW_POINT *b) {
+ const EC_JACOBIAN *b) {
// If |b| is not infinity, we have to decide whether
// (X_a, Y_a) = (X_b/Z_b^2, Y_b/Z_b^3),
// or equivalently, whether
@@ -314,7 +298,7 @@ int ec_affine_jacobian_equal(const EC_GROUP *group, const EC_AFFINE *a,
return equal & 1;
}
-int ec_GFp_simple_cmp_x_coordinate(const EC_GROUP *group, const EC_RAW_POINT *p,
+int ec_GFp_simple_cmp_x_coordinate(const EC_GROUP *group, const EC_JACOBIAN *p,
const EC_SCALAR *r) {
if (ec_GFp_simple_is_at_infinity(group, p)) {
// |ec_get_x_coordinate_as_scalar| will check this internally, but this way
@@ -329,21 +313,21 @@ int ec_GFp_simple_cmp_x_coordinate(const EC_GROUP *group, const EC_RAW_POINT *p,
void ec_GFp_simple_felem_to_bytes(const EC_GROUP *group, uint8_t *out,
size_t *out_len, const EC_FELEM *in) {
- size_t len = BN_num_bytes(&group->field);
- bn_words_to_big_endian(out, len, in->words, group->field.width);
+ size_t len = BN_num_bytes(&group->field.N);
+ bn_words_to_big_endian(out, len, in->words, group->field.N.width);
*out_len = len;
}
int ec_GFp_simple_felem_from_bytes(const EC_GROUP *group, EC_FELEM *out,
const uint8_t *in, size_t len) {
- if (len != BN_num_bytes(&group->field)) {
+ if (len != BN_num_bytes(&group->field.N)) {
OPENSSL_PUT_ERROR(EC, EC_R_DECODE_ERROR);
return 0;
}
- bn_big_endian_to_words(out->words, group->field.width, in, len);
+ bn_big_endian_to_words(out->words, group->field.N.width, in, len);
- if (!bn_less_than_words(out->words, group->field.d, group->field.width)) {
+ if (!bn_less_than_words(out->words, group->field.N.d, group->field.N.width)) {
OPENSSL_PUT_ERROR(EC, EC_R_DECODE_ERROR);
return 0;
}
diff --git a/src/crypto/fipsmodule/ec/simple_mul.c b/src/crypto/fipsmodule/ec/simple_mul.c
index 024155d9..3ec0b121 100644
--- a/src/crypto/fipsmodule/ec/simple_mul.c
+++ b/src/crypto/fipsmodule/ec/simple_mul.c
@@ -21,14 +21,14 @@
#include "../../internal.h"
-void ec_GFp_mont_mul(const EC_GROUP *group, EC_RAW_POINT *r,
- const EC_RAW_POINT *p, const EC_SCALAR *scalar) {
+void ec_GFp_mont_mul(const EC_GROUP *group, EC_JACOBIAN *r,
+ const EC_JACOBIAN *p, const EC_SCALAR *scalar) {
// This is a generic implementation for uncommon curves that not do not
// warrant a tuned one. It uses unsigned digits so that the doubling case in
// |ec_GFp_mont_add| is always unreachable, erring on safety and simplicity.
// Compute a table of the first 32 multiples of |p| (including infinity).
- EC_RAW_POINT precomp[32];
+ EC_JACOBIAN precomp[32];
ec_GFp_simple_point_set_to_infinity(group, &precomp[0]);
ec_GFp_simple_point_copy(&precomp[1], p);
for (size_t j = 2; j < OPENSSL_ARRAY_SIZE(precomp); j++) {
@@ -40,7 +40,7 @@ void ec_GFp_mont_mul(const EC_GROUP *group, EC_RAW_POINT *r,
}
// Divide bits in |scalar| into windows.
- unsigned bits = BN_num_bits(&group->order);
+ unsigned bits = EC_GROUP_order_bits(group);
int r_is_at_infinity = 1;
for (unsigned i = bits - 1; i < bits; i--) {
if (!r_is_at_infinity) {
@@ -48,7 +48,7 @@ void ec_GFp_mont_mul(const EC_GROUP *group, EC_RAW_POINT *r,
}
if (i % 5 == 0) {
// Compute the next window value.
- const size_t width = group->order.width;
+ const size_t width = group->order.N.width;
uint8_t window = bn_is_bit_set_words(scalar->words, width, i + 4) << 4;
window |= bn_is_bit_set_words(scalar->words, width, i + 3) << 3;
window |= bn_is_bit_set_words(scalar->words, width, i + 2) << 2;
@@ -56,8 +56,8 @@ void ec_GFp_mont_mul(const EC_GROUP *group, EC_RAW_POINT *r,
window |= bn_is_bit_set_words(scalar->words, width, i);
// Select the entry in constant-time.
- EC_RAW_POINT tmp;
- OPENSSL_memset(&tmp, 0, sizeof(EC_RAW_POINT));
+ EC_JACOBIAN tmp;
+ OPENSSL_memset(&tmp, 0, sizeof(EC_JACOBIAN));
for (size_t j = 0; j < OPENSSL_ARRAY_SIZE(precomp); j++) {
BN_ULONG mask = constant_time_eq_w(j, window);
ec_point_select(group, &tmp, mask, &precomp[j], &tmp);
@@ -76,13 +76,13 @@ void ec_GFp_mont_mul(const EC_GROUP *group, EC_RAW_POINT *r,
}
}
-void ec_GFp_mont_mul_base(const EC_GROUP *group, EC_RAW_POINT *r,
+void ec_GFp_mont_mul_base(const EC_GROUP *group, EC_JACOBIAN *r,
const EC_SCALAR *scalar) {
- ec_GFp_mont_mul(group, r, &group->generator->raw, scalar);
+ ec_GFp_mont_mul(group, r, &group->generator.raw, scalar);
}
-static void ec_GFp_mont_batch_precomp(const EC_GROUP *group, EC_RAW_POINT *out,
- size_t num, const EC_RAW_POINT *p) {
+static void ec_GFp_mont_batch_precomp(const EC_GROUP *group, EC_JACOBIAN *out,
+ size_t num, const EC_JACOBIAN *p) {
assert(num > 1);
ec_GFp_simple_point_set_to_infinity(group, &out[0]);
ec_GFp_simple_point_copy(&out[1], p);
@@ -96,10 +96,10 @@ static void ec_GFp_mont_batch_precomp(const EC_GROUP *group, EC_RAW_POINT *out,
}
static void ec_GFp_mont_batch_get_window(const EC_GROUP *group,
- EC_RAW_POINT *out,
- const EC_RAW_POINT precomp[17],
+ EC_JACOBIAN *out,
+ const EC_JACOBIAN precomp[17],
const EC_SCALAR *scalar, unsigned i) {
- const size_t width = group->order.width;
+ const size_t width = group->order.N.width;
uint8_t window = bn_is_bit_set_words(scalar->words, width, i + 4) << 5;
window |= bn_is_bit_set_words(scalar->words, width, i + 3) << 4;
window |= bn_is_bit_set_words(scalar->words, width, i + 2) << 3;
@@ -112,7 +112,7 @@ static void ec_GFp_mont_batch_get_window(const EC_GROUP *group,
ec_GFp_nistp_recode_scalar_bits(&sign, &digit, window);
// Select the entry in constant-time.
- OPENSSL_memset(out, 0, sizeof(EC_RAW_POINT));
+ OPENSSL_memset(out, 0, sizeof(EC_JACOBIAN));
for (size_t j = 0; j < 17; j++) {
BN_ULONG mask = constant_time_eq_w(j, digit);
ec_point_select(group, out, mask, &precomp[j], out);
@@ -126,11 +126,11 @@ static void ec_GFp_mont_batch_get_window(const EC_GROUP *group,
ec_felem_select(group, &out->Y, sign_mask, &neg_Y, &out->Y);
}
-void ec_GFp_mont_mul_batch(const EC_GROUP *group, EC_RAW_POINT *r,
- const EC_RAW_POINT *p0, const EC_SCALAR *scalar0,
- const EC_RAW_POINT *p1, const EC_SCALAR *scalar1,
- const EC_RAW_POINT *p2, const EC_SCALAR *scalar2) {
- EC_RAW_POINT precomp[3][17];
+void ec_GFp_mont_mul_batch(const EC_GROUP *group, EC_JACOBIAN *r,
+ const EC_JACOBIAN *p0, const EC_SCALAR *scalar0,
+ const EC_JACOBIAN *p1, const EC_SCALAR *scalar1,
+ const EC_JACOBIAN *p2, const EC_SCALAR *scalar2) {
+ EC_JACOBIAN precomp[3][17];
ec_GFp_mont_batch_precomp(group, precomp[0], 17, p0);
ec_GFp_mont_batch_precomp(group, precomp[1], 17, p1);
if (p2 != NULL) {
@@ -138,14 +138,14 @@ void ec_GFp_mont_mul_batch(const EC_GROUP *group, EC_RAW_POINT *r,
}
// Divide bits in |scalar| into windows.
- unsigned bits = BN_num_bits(&group->order);
+ unsigned bits = EC_GROUP_order_bits(group);
int r_is_at_infinity = 1;
for (unsigned i = bits; i <= bits; i--) {
if (!r_is_at_infinity) {
ec_GFp_mont_dbl(group, r, r);
}
if (i % 5 == 0) {
- EC_RAW_POINT tmp;
+ EC_JACOBIAN tmp;
ec_GFp_mont_batch_get_window(group, &tmp, precomp[0], scalar0, i);
if (r_is_at_infinity) {
ec_GFp_simple_point_copy(r, &tmp);
@@ -169,18 +169,18 @@ void ec_GFp_mont_mul_batch(const EC_GROUP *group, EC_RAW_POINT *r,
}
static unsigned ec_GFp_mont_comb_stride(const EC_GROUP *group) {
- return (BN_num_bits(&group->field) + EC_MONT_PRECOMP_COMB_SIZE - 1) /
+ return (EC_GROUP_get_degree(group) + EC_MONT_PRECOMP_COMB_SIZE - 1) /
EC_MONT_PRECOMP_COMB_SIZE;
}
int ec_GFp_mont_init_precomp(const EC_GROUP *group, EC_PRECOMP *out,
- const EC_RAW_POINT *p) {
+ const EC_JACOBIAN *p) {
// comb[i - 1] stores the ith element of the comb. That is, if i is
// b4 * 2^4 + b3 * 2^3 + ... + b0 * 2^0, it stores k * |p|, where k is
// b4 * 2^(4*stride) + b3 * 2^(3*stride) + ... + b0 * 2^(0*stride). stride
// here is |ec_GFp_mont_comb_stride|. We store at index i - 1 because the 0th
// comb entry is always infinity.
- EC_RAW_POINT comb[(1 << EC_MONT_PRECOMP_COMB_SIZE) - 1];
+ EC_JACOBIAN comb[(1 << EC_MONT_PRECOMP_COMB_SIZE) - 1];
unsigned stride = ec_GFp_mont_comb_stride(group);
// We compute the comb sequentially by the highest set bit. Initially, all
@@ -209,10 +209,10 @@ int ec_GFp_mont_init_precomp(const EC_GROUP *group, EC_PRECOMP *out,
}
static void ec_GFp_mont_get_comb_window(const EC_GROUP *group,
- EC_RAW_POINT *out,
+ EC_JACOBIAN *out,
const EC_PRECOMP *precomp,
const EC_SCALAR *scalar, unsigned i) {
- const size_t width = group->order.width;
+ const size_t width = group->order.N.width;
unsigned stride = ec_GFp_mont_comb_stride(group);
// Select the bits corresponding to the comb shifted up by |i|.
unsigned window = 0;
@@ -223,17 +223,17 @@ static void ec_GFp_mont_get_comb_window(const EC_GROUP *group,
// Select precomp->comb[window - 1]. If |window| is zero, |match| will always
// be zero, which will leave |out| at infinity.
- OPENSSL_memset(out, 0, sizeof(EC_RAW_POINT));
+ OPENSSL_memset(out, 0, sizeof(EC_JACOBIAN));
for (unsigned j = 0; j < OPENSSL_ARRAY_SIZE(precomp->comb); j++) {
BN_ULONG match = constant_time_eq_w(window, j + 1);
ec_felem_select(group, &out->X, match, &precomp->comb[j].X, &out->X);
ec_felem_select(group, &out->Y, match, &precomp->comb[j].Y, &out->Y);
}
BN_ULONG is_infinity = constant_time_is_zero_w(window);
- ec_felem_select(group, &out->Z, is_infinity, &out->Z, &group->one);
+ ec_felem_select(group, &out->Z, is_infinity, &out->Z, ec_felem_one(group));
}
-void ec_GFp_mont_mul_precomp(const EC_GROUP *group, EC_RAW_POINT *r,
+void ec_GFp_mont_mul_precomp(const EC_GROUP *group, EC_JACOBIAN *r,
const EC_PRECOMP *p0, const EC_SCALAR *scalar0,
const EC_PRECOMP *p1, const EC_SCALAR *scalar1,
const EC_PRECOMP *p2, const EC_SCALAR *scalar2) {
@@ -244,7 +244,7 @@ void ec_GFp_mont_mul_precomp(const EC_GROUP *group, EC_RAW_POINT *r,
ec_GFp_mont_dbl(group, r, r);
}
- EC_RAW_POINT tmp;
+ EC_JACOBIAN tmp;
ec_GFp_mont_get_comb_window(group, &tmp, p0, scalar0, i);
if (r_is_at_infinity) {
ec_GFp_simple_point_copy(r, &tmp);
diff --git a/src/crypto/fipsmodule/ec/wnaf.c b/src/crypto/fipsmodule/ec/wnaf.c
index ce0d4b8b..f5214b24 100644
--- a/src/crypto/fipsmodule/ec/wnaf.c
+++ b/src/crypto/fipsmodule/ec/wnaf.c
@@ -138,8 +138,8 @@ void ec_compute_wNAF(const EC_GROUP *group, int8_t *out,
// we shift and add at most one copy of |bit|, this will continue to hold
// afterwards.
window_val >>= 1;
- window_val +=
- bit * bn_is_bit_set_words(scalar->words, group->order.width, j + w + 1);
+ window_val += bit * bn_is_bit_set_words(scalar->words, group->order.N.width,
+ j + w + 1);
assert(window_val <= next_bit);
}
@@ -148,18 +148,18 @@ void ec_compute_wNAF(const EC_GROUP *group, int8_t *out,
}
// compute_precomp sets |out[i]| to (2*i+1)*p, for i from 0 to |len|.
-static void compute_precomp(const EC_GROUP *group, EC_RAW_POINT *out,
- const EC_RAW_POINT *p, size_t len) {
+static void compute_precomp(const EC_GROUP *group, EC_JACOBIAN *out,
+ const EC_JACOBIAN *p, size_t len) {
ec_GFp_simple_point_copy(&out[0], p);
- EC_RAW_POINT two_p;
+ EC_JACOBIAN two_p;
ec_GFp_mont_dbl(group, &two_p, p);
for (size_t i = 1; i < len; i++) {
ec_GFp_mont_add(group, &out[i], &out[i - 1], &two_p);
}
}
-static void lookup_precomp(const EC_GROUP *group, EC_RAW_POINT *out,
- const EC_RAW_POINT *precomp, int digit) {
+static void lookup_precomp(const EC_GROUP *group, EC_JACOBIAN *out,
+ const EC_JACOBIAN *precomp, int digit) {
if (digit < 0) {
digit = -digit;
ec_GFp_simple_point_copy(out, &precomp[digit >> 1]);
@@ -179,20 +179,20 @@ static void lookup_precomp(const EC_GROUP *group, EC_RAW_POINT *out,
// avoid a malloc.
#define EC_WNAF_STACK 3
-int ec_GFp_mont_mul_public_batch(const EC_GROUP *group, EC_RAW_POINT *r,
+int ec_GFp_mont_mul_public_batch(const EC_GROUP *group, EC_JACOBIAN *r,
const EC_SCALAR *g_scalar,
- const EC_RAW_POINT *points,
+ const EC_JACOBIAN *points,
const EC_SCALAR *scalars, size_t num) {
- size_t bits = BN_num_bits(&group->order);
+ size_t bits = EC_GROUP_order_bits(group);
size_t wNAF_len = bits + 1;
int ret = 0;
int8_t wNAF_stack[EC_WNAF_STACK][EC_MAX_BYTES * 8 + 1];
int8_t (*wNAF_alloc)[EC_MAX_BYTES * 8 + 1] = NULL;
int8_t (*wNAF)[EC_MAX_BYTES * 8 + 1];
- EC_RAW_POINT precomp_stack[EC_WNAF_STACK][EC_WNAF_TABLE_SIZE];
- EC_RAW_POINT (*precomp_alloc)[EC_WNAF_TABLE_SIZE] = NULL;
- EC_RAW_POINT (*precomp)[EC_WNAF_TABLE_SIZE];
+ EC_JACOBIAN precomp_stack[EC_WNAF_STACK][EC_WNAF_TABLE_SIZE];
+ EC_JACOBIAN (*precomp_alloc)[EC_WNAF_TABLE_SIZE] = NULL;
+ EC_JACOBIAN (*precomp)[EC_WNAF_TABLE_SIZE];
if (num <= EC_WNAF_STACK) {
wNAF = wNAF_stack;
precomp = precomp_stack;
@@ -212,9 +212,9 @@ int ec_GFp_mont_mul_public_batch(const EC_GROUP *group, EC_RAW_POINT *r,
}
int8_t g_wNAF[EC_MAX_BYTES * 8 + 1];
- EC_RAW_POINT g_precomp[EC_WNAF_TABLE_SIZE];
+ EC_JACOBIAN g_precomp[EC_WNAF_TABLE_SIZE];
assert(wNAF_len <= OPENSSL_ARRAY_SIZE(g_wNAF));
- const EC_RAW_POINT *g = &group->generator->raw;
+ const EC_JACOBIAN *g = &group->generator.raw;
if (g_scalar != NULL) {
ec_compute_wNAF(group, g_wNAF, g_scalar, bits, EC_WNAF_WINDOW_BITS);
compute_precomp(group, g_precomp, g, EC_WNAF_TABLE_SIZE);
@@ -226,7 +226,7 @@ int ec_GFp_mont_mul_public_batch(const EC_GROUP *group, EC_RAW_POINT *r,
compute_precomp(group, precomp[i], &points[i], EC_WNAF_TABLE_SIZE);
}
- EC_RAW_POINT tmp;
+ EC_JACOBIAN tmp;
int r_is_at_infinity = 1;
for (size_t k = wNAF_len - 1; k < wNAF_len; k--) {
if (!r_is_at_infinity) {