diff --git a/.github/workflows/curve25519-dalek.yml b/.github/workflows/curve25519-dalek.yml index 04ec5423d..1fb13aa3e 100644 --- a/.github/workflows/curve25519-dalek.yml +++ b/.github/workflows/curve25519-dalek.yml @@ -127,17 +127,16 @@ jobs: # This should automatically pick up the simd backend in a x86_64 runner # It should pick AVX2 due to stable toolchain used since AVX512 requires nigthly RUSTFLAGS: '-C target_feature=+avx2' - run: cargo test --no-default-features --features alloc,precomputed-tables,zeroize --target x86_64-unknown-linux-gnu + run: cargo test --no-default-features --features alloc,precomputed-tables,zeroize,group-bits --target x86_64-unknown-linux-gnu msrv: name: Current MSRV is 1.60.0 runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - # First run `cargo +nightly -Z minimal-verisons check` in order to get a - # Cargo.lock with the oldest possible deps + # Re-resolve Cargo.lock with minimal versions - uses: dtolnay/rust-toolchain@nightly - - run: cargo -Z minimal-versions check --no-default-features --features serde + - run: cargo update -Z minimal-versions # Now check that `cargo build` works with respect to the oldest possible # deps and the stated MSRV - uses: dtolnay/rust-toolchain@1.60.0 diff --git a/.github/workflows/ed25519-dalek.yml b/.github/workflows/ed25519-dalek.yml index 4fb4c15b5..a49d83450 100644 --- a/.github/workflows/ed25519-dalek.yml +++ b/.github/workflows/ed25519-dalek.yml @@ -24,10 +24,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - # Now run `cargo +nightly -Z minimal-verisons check` in order to get a - # Cargo.lock with the oldest possible deps + # Re-resolve Cargo.lock with minimal versions - uses: dtolnay/rust-toolchain@nightly - - run: cargo -Z minimal-versions check --no-default-features --features serde + - run: cargo update -Z minimal-versions # Now check that `cargo build` works with respect to the oldest possible # deps and the stated MSRV - uses: dtolnay/rust-toolchain@1.60.0 diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml index 09d1cfa0e..b8e44dc50 100644 --- a/.github/workflows/workspace.yml +++ b/.github/workflows/workspace.yml @@ -85,7 +85,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@nightly + - uses: dtolnay/rust-toolchain@1.73.0 with: components: clippy - run: cargo clippy --target x86_64-unknown-linux-gnu --all-features diff --git a/.github/workflows/x25519-dalek.yml b/.github/workflows/x25519-dalek.yml index 838b0d063..0ece0dcd1 100644 --- a/.github/workflows/x25519-dalek.yml +++ b/.github/workflows/x25519-dalek.yml @@ -24,10 +24,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - # Now run `cargo +nightly -Z minimal-verisons check` in order to get a - # Cargo.lock with the oldest possible deps + # Re-resolve Cargo.lock with minimal versions - uses: dtolnay/rust-toolchain@nightly - - run: cargo -Z minimal-versions check --no-default-features --features serde + - run: cargo update -Z minimal-versions # Now check that `cargo build` works with respect to the oldest possible # deps and the stated MSRV - uses: dtolnay/rust-toolchain@1.60.0 diff --git a/README.md b/README.md index bbc51d515..aced37391 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,6 @@ # Dalek elliptic curve cryptography This repo contains pure-Rust crates for elliptic curve cryptography: -[![curve25519 Rust]()](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/curve25519-dalek.yml) | Crate | Description | Crates.io | Docs | CI | -------------------------------------------|----------------|-----------|------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- diff --git a/curve25519-dalek-derive/CHANGELOG.md b/curve25519-dalek-derive/CHANGELOG.md new file mode 100644 index 000000000..8a0915b84 --- /dev/null +++ b/curve25519-dalek-derive/CHANGELOG.md @@ -0,0 +1,8 @@ +# Changelog + +Entries are listed in reverse chronological order per undeprecated +major series. + +### 0.1.1 + +* Copied over license files from [original](https://github.com/koute/unsafe_target_feature/tree/389ae00d34cf0ff589cb8d9b38a85ae1b05ebfdc) repo diff --git a/curve25519-dalek-derive/Cargo.toml b/curve25519-dalek-derive/Cargo.toml index 17e6d0f59..938144a0f 100644 --- a/curve25519-dalek-derive/Cargo.toml +++ b/curve25519-dalek-derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "curve25519-dalek-derive" -version = "0.1.0" +version = "0.1.1" edition = "2021" repository = "https://github.com/dalek-cryptography/curve25519-dalek" diff --git a/curve25519-dalek-derive/LICENSE-APACHE b/curve25519-dalek-derive/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/curve25519-dalek-derive/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/curve25519-dalek-derive/LICENSE-MIT b/curve25519-dalek-derive/LICENSE-MIT new file mode 100644 index 000000000..31aa79387 --- /dev/null +++ b/curve25519-dalek-derive/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/curve25519-dalek-derive/README.md b/curve25519-dalek-derive/README.md index 7f52d440d..69bde71c3 100644 --- a/curve25519-dalek-derive/README.md +++ b/curve25519-dalek-derive/README.md @@ -44,6 +44,7 @@ to build out more elaborate abstractions it starts to become painful to use. } struct AVX; + # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] impl Backend for AVX { #[target_feature(enable = "avx")] unsafe fn sum(xs: &[u32]) -> u32 { @@ -53,6 +54,7 @@ to build out more elaborate abstractions it starts to become painful to use. } struct AVX2; + # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] impl Backend for AVX2 { #[target_feature(enable = "avx2")] unsafe fn sum(xs: &[u32]) -> u32 { @@ -87,6 +89,7 @@ fn func() {} ```rust // It works, but must be `unsafe` +# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] #[target_feature(enable = "avx2")] unsafe fn func() {} ``` @@ -95,6 +98,7 @@ unsafe fn func() {} use curve25519_dalek_derive::unsafe_target_feature; // No `unsafe` on the function itself! +# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] #[unsafe_target_feature("avx2")] fn func() {} ``` @@ -119,6 +123,7 @@ use curve25519_dalek_derive::unsafe_target_feature; struct S; +# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] #[unsafe_target_feature("avx2")] impl core::ops::Add for S { type Output = S; @@ -135,6 +140,7 @@ impl core::ops::Add for S { ```rust use curve25519_dalek_derive::unsafe_target_feature_specialize; +# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] #[unsafe_target_feature_specialize("sse2", "avx2", conditional("avx512ifma", nightly))] mod simd { #[for_target_feature("sse2")] @@ -149,6 +155,7 @@ mod simd { pub fn func() { /* ... */ } } +# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn entry_point() { #[cfg(nightly)] if std::is_x86_feature_detected!("avx512ifma") { @@ -179,8 +186,8 @@ fn entry_point() { Licensed under either of - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or ) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or ) + * Apache License, Version 2.0, [LICENSE-APACHE](LICENSE-APACHE) + * MIT license ([LICENSE-MIT](LICENSE-MIT)) at your option. diff --git a/curve25519-dalek-derive/tests/tests.rs b/curve25519-dalek-derive/tests/tests.rs index 1516b3527..dce30c864 100644 --- a/curve25519-dalek-derive/tests/tests.rs +++ b/curve25519-dalek-derive/tests/tests.rs @@ -23,10 +23,6 @@ where a - b } -#[unsafe_target_feature("sse2")] -#[cfg(feature = "dummy")] -fn function_with_cfg() {} - #[unsafe_target_feature("sse2")] #[rustfmt::skip] fn function_with_rustfmt_skip() {} @@ -45,9 +41,6 @@ impl Struct { fn member_function_with_const_arg(self) -> u32 { self.a - N } - - #[cfg(feature = "dummy")] - fn member_function_with_cfg() {} } struct StructWithGenerics @@ -93,7 +86,7 @@ mod inner { } } -#[unsafe_target_feature_specialize("sse2", "avx2", conditional("avx512ifma", disabled))] +#[unsafe_target_feature_specialize("sse2", "avx2")] mod inner_spec { #[for_target_feature("sse2")] const CONST: u32 = 1; diff --git a/curve25519-dalek/CHANGELOG.md b/curve25519-dalek/CHANGELOG.md index 0b5c3ab9e..a4c8452cc 100644 --- a/curve25519-dalek/CHANGELOG.md +++ b/curve25519-dalek/CHANGELOG.md @@ -5,6 +5,15 @@ major series. ## 4.x series +### 4.1.2 + +* Fix nightly SIMD build + +### 4.1.1 + +* Mark `constants::BASEPOINT_ORDER` deprecated from pub API +* Add implementation for `PrimeFieldBits`, behind the `group-bits` feature flag. + ### 4.1.0 * Add arbitrary integer multiplication with `MontgomeryPoint::mul_bits_be` @@ -118,7 +127,7 @@ major series. ### 2.1.2 -* Multiple documenation typo fixes. +* Multiple documentation typo fixes. * Fix `alloc` feature working with stable rust. ### 2.1.1 diff --git a/curve25519-dalek/Cargo.toml b/curve25519-dalek/Cargo.toml index 2096b31d9..ac740eba5 100644 --- a/curve25519-dalek/Cargo.toml +++ b/curve25519-dalek/Cargo.toml @@ -4,7 +4,7 @@ name = "curve25519-dalek" # - update CHANGELOG # - update README if required by semver # - if README was updated, also update module documentation in src/lib.rs -version = "4.1.0" +version = "4.1.2" edition = "2021" rust-version = "1.60.0" authors = ["Isis Lovecruft ", @@ -27,7 +27,7 @@ rustdoc-args = [ "--html-in-header", "docs/assets/rustdoc-include-katex-header.html", "--cfg", "docsrs", ] -features = ["serde", "rand_core", "digest", "legacy_compatibility"] +features = ["serde", "rand_core", "digest", "legacy_compatibility", "group-bits"] [dev-dependencies] sha2 = { version = "0.10", default-features = false } @@ -36,7 +36,6 @@ rand = "0.8" rand_core = { version = "0.6", default-features = false, features = ["getrandom"] } [build-dependencies] -platforms = "3.0.2" rustc_version = "0.4.0" [[bench]] @@ -46,6 +45,7 @@ required-features = ["alloc", "rand_core"] [dependencies] cfg-if = "1" +ff = { version = "0.13", default-features = false, optional = true } group = { version = "0.13", default-features = false, optional = true } hex = "0.4.2" rand_core = { version = "0.6.4", default-features = false, optional = true } @@ -73,6 +73,7 @@ alloc = ["zeroize?/alloc"] precomputed-tables = [] legacy_compatibility = [] group = ["dep:group", "rand_core"] +group-bits = ["group", "ff/bits"] [target.'cfg(all(not(curve25519_dalek_backend = "fiat"), not(curve25519_dalek_backend = "serial"), target_arch = "x86_64"))'.dependencies] curve25519-dalek-derive = { version = "0.1", path = "../curve25519-dalek-derive" } diff --git a/curve25519-dalek/build.rs b/curve25519-dalek/build.rs index d23920260..97fa28524 100644 --- a/curve25519-dalek/build.rs +++ b/curve25519-dalek/build.rs @@ -9,17 +9,31 @@ enum DalekBits { Dalek64, } +use std::fmt::Formatter; + +impl std::fmt::Display for DalekBits { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { + let w_bits = match self { + DalekBits::Dalek32 => "32", + DalekBits::Dalek64 => "64", + }; + write!(f, "{}", w_bits) + } +} + fn main() { + let target_arch = match std::env::var("CARGO_CFG_TARGET_ARCH") { + Ok(arch) => arch, + _ => "".to_string(), + }; + let curve25519_dalek_bits = match std::env::var("CARGO_CFG_CURVE25519_DALEK_BITS").as_deref() { Ok("32") => DalekBits::Dalek32, Ok("64") => DalekBits::Dalek64, - _ => deterministic::determine_curve25519_dalek_bits(), + _ => deterministic::determine_curve25519_dalek_bits(&target_arch), }; - match curve25519_dalek_bits { - DalekBits::Dalek64 => println!("cargo:rustc-cfg=curve25519_dalek_bits=\"64\""), - DalekBits::Dalek32 => println!("cargo:rustc-cfg=curve25519_dalek_bits=\"32\""), - } + println!("cargo:rustc-cfg=curve25519_dalek_bits=\"{curve25519_dalek_bits}\""); if rustc_version::version_meta() .expect("failed to detect rustc version") @@ -36,11 +50,6 @@ fn main() { println!("cargo:rustc-cfg=allow_unused_unsafe"); } - let target_arch = match std::env::var("CARGO_CFG_TARGET_ARCH") { - Ok(arch) => arch, - _ => "".to_string(), - }; - // Backend overrides / defaults let curve25519_dalek_backend = match std::env::var("CARGO_CFG_CURVE25519_DALEK_BACKEND").as_deref() { @@ -74,11 +83,12 @@ mod deterministic { use super::*; - // Standard Cargo TARGET environment variable of triplet is required - static ERR_MSG_NO_TARGET: &str = "Standard Cargo TARGET environment variable is not set"; + // Custom Rust non-cargo build tooling needs to set CARGO_CFG_TARGET_POINTER_WIDTH + static ERR_MSG_NO_POINTER_WIDTH: &str = + "Standard Cargo TARGET_POINTER_WIDTH environment variable is not set."; - // Custom Non-Rust standard target platforms require explicit settings. - static ERR_MSG_NO_PLATFORM: &str = "Unknown Rust target platform."; + // When either non-32 or 64 TARGET_POINTER_WIDTH detected + static ERR_MSG_UNKNOWN_POINTER_WIDTH: &str = "Unknown TARGET_POINTER_WIDTH detected."; // Warning when the curve25519_dalek_bits cannot be determined fn determine_curve25519_dalek_bits_warning(cause: &str) { @@ -86,43 +96,30 @@ mod deterministic { } // Determine the curve25519_dalek_bits based on Rust standard TARGET triplet - pub(super) fn determine_curve25519_dalek_bits() -> DalekBits { - use platforms::target::PointerWidth; - - // TARGET environment is supplied by Cargo - // https://doc.rust-lang.org/cargo/reference/environment-variables.html - let target_triplet = match std::env::var("TARGET") { - Ok(t) => t, + pub(super) fn determine_curve25519_dalek_bits(target_arch: &String) -> DalekBits { + let target_pointer_width = match std::env::var("CARGO_CFG_TARGET_POINTER_WIDTH") { + Ok(pw) => pw, Err(_) => { - determine_curve25519_dalek_bits_warning(ERR_MSG_NO_TARGET); - return DalekBits::Dalek32; - } - }; - - // platforms crate is the source of truth used to determine the platform - let platform = match platforms::Platform::find(&target_triplet) { - Some(p) => p, - None => { - if target_triplet != "riscv32im-risc0-zkvm-elf" { - determine_curve25519_dalek_bits_warning(ERR_MSG_NO_PLATFORM); - } + determine_curve25519_dalek_bits_warning(ERR_MSG_NO_POINTER_WIDTH); return DalekBits::Dalek32; } }; #[allow(clippy::match_single_binding)] - match platform.target_arch { + match &target_arch { //Issues: 449 and 456 + //TODO: When adding arch defaults use proper types not String match //TODO(Arm): Needs tests + benchmarks to back this up - //platforms::target::Arch::Arm => DalekBits::Dalek64, //TODO(Wasm32): Needs tests + benchmarks to back this up - //platforms::target::Arch::Wasm32 => DalekBits::Dalek64, - _ => match platform.target_pointer_width { - PointerWidth::U64 => DalekBits::Dalek64, - PointerWidth::U32 => DalekBits::Dalek32, + _ => match target_pointer_width.as_ref() { + "64" => DalekBits::Dalek64, + "32" => DalekBits::Dalek32, // Intended default solely for non-32/64 target pointer widths // Otherwise known target platforms only. - _ => DalekBits::Dalek32, + _ => { + determine_curve25519_dalek_bits_warning(ERR_MSG_UNKNOWN_POINTER_WIDTH); + DalekBits::Dalek32 + } }, } } diff --git a/curve25519-dalek/docs/ifma-notes.md b/curve25519-dalek/docs/ifma-notes.md index c6fd3b3a8..faf89280a 100644 --- a/curve25519-dalek/docs/ifma-notes.md +++ b/curve25519-dalek/docs/ifma-notes.md @@ -351,7 +351,7 @@ This computation requires 25 `vpmadd52luq` and 25 `vpmadd52huq` operations. For 256-bit vectors, IFMA operations execute on an i3-8121U with latency 4 cycles, throughput 0.5 cycles, so executing 50 instructions requires 25 cycles' worth of throughput. Accumulating -terms with coefficient \\(1\\) and \\(2\\) seperately means that the +terms with coefficient \\(1\\) and \\(2\\) separately means that the longest dependency chain has length 5, so the critical path has length 20 cycles and the bottleneck is throughput. diff --git a/curve25519-dalek/src/backend/mod.rs b/curve25519-dalek/src/backend/mod.rs index 4424e0a53..9ad1dd3de 100644 --- a/curve25519-dalek/src/backend/mod.rs +++ b/curve25519-dalek/src/backend/mod.rs @@ -87,24 +87,24 @@ where match get_selected_backend() { #[cfg(curve25519_dalek_backend = "simd")] BackendKind::Avx2 => - self::vector::scalar_mul::pippenger::spec_avx2::Pippenger::optional_multiscalar_mul::(scalars, points), + vector::scalar_mul::pippenger::spec_avx2::Pippenger::optional_multiscalar_mul::(scalars, points), #[cfg(all(curve25519_dalek_backend = "simd", nightly))] BackendKind::Avx512 => - self::vector::scalar_mul::pippenger::spec_avx512ifma_avx512vl::Pippenger::optional_multiscalar_mul::(scalars, points), + vector::scalar_mul::pippenger::spec_avx512ifma_avx512vl::Pippenger::optional_multiscalar_mul::(scalars, points), BackendKind::Serial => - self::serial::scalar_mul::pippenger::Pippenger::optional_multiscalar_mul::(scalars, points), + serial::scalar_mul::pippenger::Pippenger::optional_multiscalar_mul::(scalars, points), } } #[cfg(feature = "alloc")] pub(crate) enum VartimePrecomputedStraus { #[cfg(curve25519_dalek_backend = "simd")] - Avx2(self::vector::scalar_mul::precomputed_straus::spec_avx2::VartimePrecomputedStraus), + Avx2(vector::scalar_mul::precomputed_straus::spec_avx2::VartimePrecomputedStraus), #[cfg(all(curve25519_dalek_backend = "simd", nightly))] Avx512ifma( - self::vector::scalar_mul::precomputed_straus::spec_avx512ifma_avx512vl::VartimePrecomputedStraus, + vector::scalar_mul::precomputed_straus::spec_avx512ifma_avx512vl::VartimePrecomputedStraus, ), - Scalar(self::serial::scalar_mul::precomputed_straus::VartimePrecomputedStraus), + Scalar(serial::scalar_mul::precomputed_straus::VartimePrecomputedStraus), } #[cfg(feature = "alloc")] @@ -119,12 +119,12 @@ impl VartimePrecomputedStraus { match get_selected_backend() { #[cfg(curve25519_dalek_backend = "simd")] BackendKind::Avx2 => - VartimePrecomputedStraus::Avx2(self::vector::scalar_mul::precomputed_straus::spec_avx2::VartimePrecomputedStraus::new(static_points)), + VartimePrecomputedStraus::Avx2(vector::scalar_mul::precomputed_straus::spec_avx2::VartimePrecomputedStraus::new(static_points)), #[cfg(all(curve25519_dalek_backend = "simd", nightly))] BackendKind::Avx512 => - VartimePrecomputedStraus::Avx512ifma(self::vector::scalar_mul::precomputed_straus::spec_avx512ifma_avx512vl::VartimePrecomputedStraus::new(static_points)), + VartimePrecomputedStraus::Avx512ifma(vector::scalar_mul::precomputed_straus::spec_avx512ifma_avx512vl::VartimePrecomputedStraus::new(static_points)), BackendKind::Serial => - VartimePrecomputedStraus::Scalar(self::serial::scalar_mul::precomputed_straus::VartimePrecomputedStraus::new(static_points)) + VartimePrecomputedStraus::Scalar(serial::scalar_mul::precomputed_straus::VartimePrecomputedStraus::new(static_points)) } } @@ -179,19 +179,16 @@ where match get_selected_backend() { #[cfg(curve25519_dalek_backend = "simd")] BackendKind::Avx2 => { - self::vector::scalar_mul::straus::spec_avx2::Straus::multiscalar_mul::( - scalars, points, - ) + vector::scalar_mul::straus::spec_avx2::Straus::multiscalar_mul::(scalars, points) } #[cfg(all(curve25519_dalek_backend = "simd", nightly))] BackendKind::Avx512 => { - self::vector::scalar_mul::straus::spec_avx512ifma_avx512vl::Straus::multiscalar_mul::< - I, - J, - >(scalars, points) + vector::scalar_mul::straus::spec_avx512ifma_avx512vl::Straus::multiscalar_mul::( + scalars, points, + ) } BackendKind::Serial => { - self::serial::scalar_mul::straus::Straus::multiscalar_mul::(scalars, points) + serial::scalar_mul::straus::Straus::multiscalar_mul::(scalars, points) } } } @@ -209,21 +206,19 @@ where match get_selected_backend() { #[cfg(curve25519_dalek_backend = "simd")] BackendKind::Avx2 => { - self::vector::scalar_mul::straus::spec_avx2::Straus::optional_multiscalar_mul::( + vector::scalar_mul::straus::spec_avx2::Straus::optional_multiscalar_mul::( scalars, points, ) } #[cfg(all(curve25519_dalek_backend = "simd", nightly))] BackendKind::Avx512 => { - self::vector::scalar_mul::straus::spec_avx512ifma_avx512vl::Straus::optional_multiscalar_mul::< + vector::scalar_mul::straus::spec_avx512ifma_avx512vl::Straus::optional_multiscalar_mul::< I, J, >(scalars, points) } BackendKind::Serial => { - self::serial::scalar_mul::straus::Straus::optional_multiscalar_mul::( - scalars, points, - ) + serial::scalar_mul::straus::Straus::optional_multiscalar_mul::(scalars, points) } } } @@ -232,12 +227,12 @@ where pub fn variable_base_mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint { match get_selected_backend() { #[cfg(curve25519_dalek_backend = "simd")] - BackendKind::Avx2 => self::vector::scalar_mul::variable_base::spec_avx2::mul(point, scalar), + BackendKind::Avx2 => vector::scalar_mul::variable_base::spec_avx2::mul(point, scalar), #[cfg(all(curve25519_dalek_backend = "simd", nightly))] BackendKind::Avx512 => { - self::vector::scalar_mul::variable_base::spec_avx512ifma_avx512vl::mul(point, scalar) + vector::scalar_mul::variable_base::spec_avx512ifma_avx512vl::mul(point, scalar) } - BackendKind::Serial => self::serial::scalar_mul::variable_base::mul(point, scalar), + BackendKind::Serial => serial::scalar_mul::variable_base::mul(point, scalar), } } @@ -246,11 +241,11 @@ pub fn variable_base_mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint pub fn vartime_double_base_mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint { match get_selected_backend() { #[cfg(curve25519_dalek_backend = "simd")] - BackendKind::Avx2 => self::vector::scalar_mul::vartime_double_base::spec_avx2::mul(a, A, b), + BackendKind::Avx2 => vector::scalar_mul::vartime_double_base::spec_avx2::mul(a, A, b), #[cfg(all(curve25519_dalek_backend = "simd", nightly))] BackendKind::Avx512 => { - self::vector::scalar_mul::vartime_double_base::spec_avx512ifma_avx512vl::mul(a, A, b) + vector::scalar_mul::vartime_double_base::spec_avx512ifma_avx512vl::mul(a, A, b) } - BackendKind::Serial => self::serial::scalar_mul::vartime_double_base::mul(a, A, b), + BackendKind::Serial => serial::scalar_mul::vartime_double_base::mul(a, A, b), } } diff --git a/curve25519-dalek/src/backend/serial/curve_models/mod.rs b/curve25519-dalek/src/backend/serial/curve_models/mod.rs index 0410d18a2..c6ac65647 100644 --- a/curve25519-dalek/src/backend/serial/curve_models/mod.rs +++ b/curve25519-dalek/src/backend/serial/curve_models/mod.rs @@ -567,7 +567,7 @@ impl<'a> Neg for &'a AffineNielsPoint { // ------------------------------------------------------------------------ impl Debug for ProjectivePoint { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!( f, "ProjectivePoint{{\n\tX: {:?},\n\tY: {:?},\n\tZ: {:?}\n}}", @@ -577,7 +577,7 @@ impl Debug for ProjectivePoint { } impl Debug for CompletedPoint { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!( f, "CompletedPoint{{\n\tX: {:?},\n\tY: {:?},\n\tZ: {:?},\n\tT: {:?}\n}}", @@ -587,7 +587,7 @@ impl Debug for CompletedPoint { } impl Debug for AffineNielsPoint { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!( f, "AffineNielsPoint{{\n\ty_plus_x: {:?},\n\ty_minus_x: {:?},\n\txy2d: {:?}\n}}", @@ -597,7 +597,7 @@ impl Debug for AffineNielsPoint { } impl Debug for ProjectiveNielsPoint { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "ProjectiveNielsPoint{{\n\tY_plus_X: {:?},\n\tY_minus_X: {:?},\n\tZ: {:?},\n\tT2d: {:?}\n}}", &self.Y_plus_X, &self.Y_minus_X, &self.Z, &self.T2d) } diff --git a/curve25519-dalek/src/backend/serial/fiat_u32/field.rs b/curve25519-dalek/src/backend/serial/fiat_u32/field.rs index 94e1f6d36..97695c383 100644 --- a/curve25519-dalek/src/backend/serial/fiat_u32/field.rs +++ b/curve25519-dalek/src/backend/serial/fiat_u32/field.rs @@ -58,7 +58,7 @@ use fiat_crypto::curve25519_32::*; pub struct FieldElement2625(pub(crate) fiat_25519_tight_field_element); impl Debug for FieldElement2625 { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "FieldElement2625({:?})", &(self.0).0[..]) } } diff --git a/curve25519-dalek/src/backend/serial/fiat_u64/field.rs b/curve25519-dalek/src/backend/serial/fiat_u64/field.rs index c871b55c2..2a022e23e 100644 --- a/curve25519-dalek/src/backend/serial/fiat_u64/field.rs +++ b/curve25519-dalek/src/backend/serial/fiat_u64/field.rs @@ -47,7 +47,7 @@ use fiat_crypto::curve25519_64::*; pub struct FieldElement51(pub(crate) fiat_25519_tight_field_element); impl Debug for FieldElement51 { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "FieldElement51({:?})", &(self.0).0[..]) } } diff --git a/curve25519-dalek/src/backend/serial/scalar_mul/pippenger.rs b/curve25519-dalek/src/backend/serial/scalar_mul/pippenger.rs index 9af39e599..f60d9b953 100644 --- a/curve25519-dalek/src/backend/serial/scalar_mul/pippenger.rs +++ b/curve25519-dalek/src/backend/serial/scalar_mul/pippenger.rs @@ -164,7 +164,6 @@ impl VartimeMultiscalarMul for Pippenger { mod test { use super::*; use crate::constants; - use crate::scalar::Scalar; #[test] fn test_vartime_pippenger() { diff --git a/curve25519-dalek/src/backend/serial/u32/field.rs b/curve25519-dalek/src/backend/serial/u32/field.rs index 4e0b2133b..7319288a0 100644 --- a/curve25519-dalek/src/backend/serial/u32/field.rs +++ b/curve25519-dalek/src/backend/serial/u32/field.rs @@ -54,7 +54,7 @@ use zeroize::Zeroize; pub struct FieldElement2625(pub(crate) [u32; 10]); impl Debug for FieldElement2625 { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "FieldElement2625({:?})", &self.0[..]) } } diff --git a/curve25519-dalek/src/backend/serial/u32/scalar.rs b/curve25519-dalek/src/backend/serial/u32/scalar.rs index c251e8bbe..2d135d1d4 100644 --- a/curve25519-dalek/src/backend/serial/u32/scalar.rs +++ b/curve25519-dalek/src/backend/serial/u32/scalar.rs @@ -24,7 +24,7 @@ use crate::constants; pub struct Scalar29(pub [u32; 9]); impl Debug for Scalar29 { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "Scalar29: {:?}", &self.0[..]) } } diff --git a/curve25519-dalek/src/backend/serial/u64/field.rs b/curve25519-dalek/src/backend/serial/u64/field.rs index 9659effa1..1263d23e4 100644 --- a/curve25519-dalek/src/backend/serial/u64/field.rs +++ b/curve25519-dalek/src/backend/serial/u64/field.rs @@ -43,7 +43,7 @@ use zeroize::Zeroize; pub struct FieldElement51(pub(crate) [u64; 5]); impl Debug for FieldElement51 { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "FieldElement51({:?})", &self.0[..]) } } diff --git a/curve25519-dalek/src/backend/serial/u64/scalar.rs b/curve25519-dalek/src/backend/serial/u64/scalar.rs index dab80cdce..1cc2df4a0 100644 --- a/curve25519-dalek/src/backend/serial/u64/scalar.rs +++ b/curve25519-dalek/src/backend/serial/u64/scalar.rs @@ -25,7 +25,7 @@ use crate::constants; pub struct Scalar52(pub [u64; 5]); impl Debug for Scalar52 { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "Scalar52: {:?}", &self.0[..]) } } diff --git a/curve25519-dalek/src/backend/vector/avx2/edwards.rs b/curve25519-dalek/src/backend/vector/avx2/edwards.rs index cf6691e83..fd70d7d2f 100644 --- a/curve25519-dalek/src/backend/vector/avx2/edwards.rs +++ b/curve25519-dalek/src/backend/vector/avx2/edwards.rs @@ -35,7 +35,6 @@ #![allow(non_snake_case)] -use core::convert::From; use core::ops::{Add, Neg, Sub}; use subtle::Choice; diff --git a/curve25519-dalek/src/constants.rs b/curve25519-dalek/src/constants.rs index 9e0e091cc..d2ed71401 100644 --- a/curve25519-dalek/src/constants.rs +++ b/curve25519-dalek/src/constants.rs @@ -8,24 +8,7 @@ // Authors: // - isis agora lovecruft // - Henry de Valence - //! Various constants, such as the Ristretto and Ed25519 basepoints. -//! -//! Most of the constants are given with -//! `LONG_DESCRIPTIVE_UPPER_CASE_NAMES`, but they can be brought into -//! scope using a `let` binding: -//! -#![cfg_attr(feature = "precomputed-tables", doc = "```")] -#![cfg_attr(not(feature = "precomputed-tables"), doc = "```ignore")] -//! use curve25519_dalek::constants; -//! use curve25519_dalek::traits::IsIdentity; -//! -//! let B = constants::RISTRETTO_BASEPOINT_TABLE; -//! let l = &constants::BASEPOINT_ORDER; -//! -//! let A = l * B; -//! assert!(A.is_identity()); -//! ``` #![allow(non_snake_case)] @@ -88,7 +71,10 @@ pub const RISTRETTO_BASEPOINT_POINT: RistrettoPoint = RistrettoPoint(ED25519_BAS /// $$ /// \ell = 2^\{252\} + 27742317777372353535851937790883648493. /// $$ -pub const BASEPOINT_ORDER: Scalar = Scalar { +#[deprecated(since = "4.1.1", note = "Should not have been in public API")] +pub const BASEPOINT_ORDER: Scalar = BASEPOINT_ORDER_PRIVATE; + +pub(crate) const BASEPOINT_ORDER_PRIVATE: Scalar = Scalar { bytes: [ 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, diff --git a/curve25519-dalek/src/edwards.rs b/curve25519-dalek/src/edwards.rs index e7f6d4b54..856fac12f 100644 --- a/curve25519-dalek/src/edwards.rs +++ b/curve25519-dalek/src/edwards.rs @@ -96,7 +96,6 @@ use core::array::TryFromSliceError; use core::borrow::Borrow; use core::fmt::Debug; -use core::iter::Iterator; use core::iter::Sum; use core::ops::{Add, Neg, Sub}; use core::ops::{AddAssign, SubAssign}; @@ -110,10 +109,12 @@ use digest::{generic_array::typenum::U64, Digest}; #[cfg(feature = "group")] use { group::{cofactor::CofactorGroup, prime::PrimeGroup, GroupEncoding}, - rand_core::RngCore, subtle::CtOption, }; +#[cfg(feature = "group")] +use rand_core::RngCore; + use subtle::Choice; use subtle::ConditionallyNegatable; use subtle::ConditionallySelectable; @@ -170,7 +171,7 @@ impl ConstantTimeEq for CompressedEdwardsY { } impl Debug for CompressedEdwardsY { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "CompressedEdwardsY: {:?}", self.as_bytes()) } } @@ -258,7 +259,7 @@ impl TryFrom<&[u8]> for CompressedEdwardsY { #[cfg(feature = "serde")] use serde::de::Visitor; #[cfg(feature = "serde")] -use serde::{self, Deserialize, Deserializer, Serialize, Serializer}; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "serde")] impl Serialize for EdwardsPoint { @@ -301,7 +302,7 @@ impl<'de> Deserialize<'de> for EdwardsPoint { impl<'de> Visitor<'de> for EdwardsPointVisitor { type Value = EdwardsPoint; - fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { formatter.write_str("a valid point in Edwards y + sign format") } @@ -337,7 +338,7 @@ impl<'de> Deserialize<'de> for CompressedEdwardsY { impl<'de> Visitor<'de> for CompressedEdwardsYVisitor { type Value = CompressedEdwardsY; - fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { formatter.write_str("32 bytes of data") } @@ -1052,7 +1053,7 @@ macro_rules! impl_basepoint_table { } impl Debug for $name { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "{:?}([\n", stringify!($name))?; for i in 0..32 { write!(f, "\t{:?},\n", &self.0[i])?; @@ -1254,7 +1255,7 @@ impl EdwardsPoint { /// assert_eq!((P+Q).is_torsion_free(), false); /// ``` pub fn is_torsion_free(&self) -> bool { - (self * constants::BASEPOINT_ORDER).is_identity() + (self * constants::BASEPOINT_ORDER_PRIVATE).is_identity() } } @@ -1263,7 +1264,7 @@ impl EdwardsPoint { // ------------------------------------------------------------------------ impl Debug for EdwardsPoint { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!( f, "EdwardsPoint{{\n\tX: {:?},\n\tY: {:?},\n\tZ: {:?},\n\tT: {:?}\n}}", @@ -1580,7 +1581,7 @@ impl CofactorGroup for EdwardsPoint { } fn is_torsion_free(&self) -> Choice { - (self * constants::BASEPOINT_ORDER).ct_eq(&Self::identity()) + (self * constants::BASEPOINT_ORDER_PRIVATE).ct_eq(&Self::identity()) } } @@ -1591,8 +1592,10 @@ impl CofactorGroup for EdwardsPoint { #[cfg(test)] mod test { use super::*; - use crate::{field::FieldElement, scalar::Scalar}; - use subtle::ConditionallySelectable; + + // If `group` is set, then this is already imported in super + #[cfg(not(feature = "group"))] + use rand_core::RngCore; #[cfg(feature = "alloc")] use alloc::vec::Vec; @@ -1600,8 +1603,6 @@ mod test { #[cfg(feature = "precomputed-tables")] use crate::constants::ED25519_BASEPOINT_TABLE; - use rand_core::RngCore; - /// X coordinate of the basepoint. /// = 15112221349535400772501151409588531511454012693041857206046113283949847762202 static BASE_X_COORD_BYTES: [u8; 32] = [ @@ -1769,7 +1770,7 @@ mod test { /// Test that multiplication by the basepoint order kills the basepoint #[test] fn basepoint_mult_by_basepoint_order() { - let should_be_id = EdwardsPoint::mul_base(&constants::BASEPOINT_ORDER); + let should_be_id = EdwardsPoint::mul_base(&constants::BASEPOINT_ORDER_PRIVATE); assert!(should_be_id.is_identity()); } diff --git a/curve25519-dalek/src/field.rs b/curve25519-dalek/src/field.rs index 92ea72d09..8510f700f 100644 --- a/curve25519-dalek/src/field.rs +++ b/curve25519-dalek/src/field.rs @@ -25,8 +25,6 @@ #![allow(unused_qualifications)] -use core::cmp::{Eq, PartialEq}; - use cfg_if::cfg_if; use subtle::Choice; @@ -39,11 +37,6 @@ use crate::constants; cfg_if! { if #[cfg(curve25519_dalek_backend = "fiat")] { - #[cfg(curve25519_dalek_bits = "32")] - pub use backend::serial::fiat_u32::field::*; - #[cfg(curve25519_dalek_bits = "64")] - pub use backend::serial::fiat_u64::field::*; - /// A `FieldElement` represents an element of the field /// \\( \mathbb Z / (2\^{255} - 19)\\). /// @@ -52,7 +45,7 @@ cfg_if! { /// /// Using formally-verified field arithmetic from fiat-crypto. #[cfg(curve25519_dalek_bits = "32")] - pub type FieldElement = backend::serial::fiat_u32::field::FieldElement2625; + pub(crate) type FieldElement = backend::serial::fiat_u32::field::FieldElement2625; /// A `FieldElement` represents an element of the field /// \\( \mathbb Z / (2\^{255} - 19)\\). @@ -62,10 +55,8 @@ cfg_if! { /// /// Using formally-verified field arithmetic from fiat-crypto. #[cfg(curve25519_dalek_bits = "64")] - pub type FieldElement = backend::serial::fiat_u64::field::FieldElement51; + pub(crate) type FieldElement = backend::serial::fiat_u64::field::FieldElement51; } else if #[cfg(curve25519_dalek_bits = "64")] { - pub use crate::backend::serial::u64::field::*; - /// A `FieldElement` represents an element of the field /// \\( \mathbb Z / (2\^{255} - 19)\\). /// @@ -80,14 +71,12 @@ cfg_if! { /// implementations. pub type FieldElement = backend::serial::risc0::field::FieldElementR0; } else { - pub use backend::serial::u32::field::*; - /// A `FieldElement` represents an element of the field /// \\( \mathbb Z / (2\^{255} - 19)\\). /// /// The `FieldElement` type is an alias for one of the platform-specific /// implementations. - pub type FieldElement = backend::serial::u32::field::FieldElement2625; + pub(crate) type FieldElement = backend::serial::u32::field::FieldElement2625; } } @@ -116,7 +105,7 @@ impl FieldElement { /// # Return /// /// If negative, return `Choice(1)`. Otherwise, return `Choice(0)`. - pub fn is_negative(&self) -> Choice { + pub(crate) fn is_negative(&self) -> Choice { let bytes = self.as_bytes(); (bytes[0] & 1).into() } @@ -126,7 +115,7 @@ impl FieldElement { /// # Return /// /// If zero, return `Choice(1)`. Otherwise, return `Choice(0)`. - pub fn is_zero(&self) -> Choice { + pub(crate) fn is_zero(&self) -> Choice { let zero = [0u8; 32]; let bytes = self.as_bytes(); @@ -172,11 +161,11 @@ impl FieldElement { (t19, t3) } - /// Given a slice of public `FieldElements`, replace each with its inverse. + /// Given a slice of pub(crate)lic `FieldElements`, replace each with its inverse. /// /// When an input `FieldElement` is zero, its value is unchanged. #[cfg(feature = "alloc")] - pub fn batch_invert(inputs: &mut [FieldElement]) { + pub(crate) fn batch_invert(inputs: &mut [FieldElement]) { // Montgomery’s Trick and Fast Implementation of Masked AES // Genelle, Prouff and Quisquater // Section 3.2 @@ -221,7 +210,7 @@ impl FieldElement { /// This function returns zero on input zero. #[rustfmt::skip] // keep alignment of explanatory comments #[allow(clippy::let_and_return)] - pub fn invert(&self) -> FieldElement { + pub(crate) fn invert(&self) -> FieldElement { // The bits of p-2 = 2^255 -19 -2 are 11010111111...11. // // nonzero bits of exponent @@ -258,7 +247,7 @@ impl FieldElement { /// - `(Choice(0), zero) ` if `v` is zero and `u` is nonzero; /// - `(Choice(0), +sqrt(i*u/v))` if `u/v` is nonsquare (so `i*u/v` is square). /// - pub fn sqrt_ratio_i(u: &FieldElement, v: &FieldElement) -> (Choice, FieldElement) { + pub(crate) fn sqrt_ratio_i(u: &FieldElement, v: &FieldElement) -> (Choice, FieldElement) { // Using the same trick as in ed25519 decoding, we merge the // inversion, the square root, and the square test as follows. // @@ -318,7 +307,7 @@ impl FieldElement { /// - `(Choice(0), zero) ` if `self` is zero; /// - `(Choice(0), +sqrt(i/self)) ` if `self` is a nonzero nonsquare; /// - pub fn invsqrt(&self) -> (Choice, FieldElement) { + pub(crate) fn invsqrt(&self) -> (Choice, FieldElement) { FieldElement::sqrt_ratio_i(&FieldElement::ONE, self) } } @@ -326,7 +315,6 @@ impl FieldElement { #[cfg(test)] mod test { use crate::field::*; - use subtle::ConditionallyNegatable; /// Random element a of GF(2^255-19), from Sage /// a = 1070314506888354081329385823235218444233221\ diff --git a/curve25519-dalek/src/lib.rs b/curve25519-dalek/src/lib.rs index 9097a9a8f..fecfe888c 100644 --- a/curve25519-dalek/src/lib.rs +++ b/curve25519-dalek/src/lib.rs @@ -10,7 +10,14 @@ // - Henry de Valence #![no_std] -#![cfg_attr(all(curve25519_dalek_backend = "simd", nightly), feature(stdsimd))] +#![cfg_attr( + all( + curve25519_dalek_backend = "simd", + nightly, + any(target_arch = "x86", target_arch = "x86_64") + ), + feature(stdarch_x86_avx512) +)] #![cfg_attr( all(curve25519_dalek_backend = "simd", nightly), feature(avx512_target_feature) @@ -35,6 +42,8 @@ unused_lifetimes, unused_qualifications )] +// Requires MSRV 1.77 as it does not allow build.rs gating +#![allow(unexpected_cfgs)] //------------------------------------------------------------------------ // External dependencies: diff --git a/curve25519-dalek/src/ristretto.rs b/curve25519-dalek/src/ristretto.rs index dec7ae067..c9d16aba3 100644 --- a/curve25519-dalek/src/ristretto.rs +++ b/curve25519-dalek/src/ristretto.rs @@ -364,7 +364,7 @@ impl TryFrom<&[u8]> for CompressedRistretto { #[cfg(feature = "serde")] use serde::de::Visitor; #[cfg(feature = "serde")] -use serde::{self, Deserialize, Deserializer, Serialize, Serializer}; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "serde")] impl Serialize for RistrettoPoint { @@ -407,7 +407,7 @@ impl<'de> Deserialize<'de> for RistrettoPoint { impl<'de> Visitor<'de> for RistrettoPointVisitor { type Value = RistrettoPoint; - fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { formatter.write_str("a valid point in Ristretto format") } @@ -443,7 +443,7 @@ impl<'de> Deserialize<'de> for CompressedRistretto { impl<'de> Visitor<'de> for CompressedRistrettoVisitor { type Value = CompressedRistretto; - fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { formatter.write_str("32 bytes of data") } @@ -1155,13 +1155,13 @@ impl ConditionallySelectable for RistrettoPoint { // ------------------------------------------------------------------------ impl Debug for CompressedRistretto { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "CompressedRistretto: {:?}", self.as_bytes()) } } impl Debug for RistrettoPoint { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { let coset = self.coset4(); write!( f, @@ -1277,8 +1277,6 @@ impl Zeroize for RistrettoPoint { mod test { use super::*; use crate::edwards::CompressedEdwardsY; - use crate::scalar::Scalar; - use crate::traits::Identity; use rand_core::OsRng; diff --git a/curve25519-dalek/src/scalar.rs b/curve25519-dalek/src/scalar.rs index cea64fde1..77784313b 100644 --- a/curve25519-dalek/src/scalar.rs +++ b/curve25519-dalek/src/scalar.rs @@ -112,8 +112,6 @@ //! has been enabled. use core::borrow::Borrow; -use core::cmp::{Eq, PartialEq}; -use core::convert::TryInto; use core::fmt::Debug; use core::iter::{Product, Sum}; use core::ops::Index; @@ -125,10 +123,12 @@ use core::ops::{Sub, SubAssign}; use cfg_if::cfg_if; #[cfg(feature = "group")] -use { - group::ff::{Field, FromUniformBytes, PrimeField}, - rand_core::RngCore, -}; +use group::ff::{Field, FromUniformBytes, PrimeField}; +#[cfg(feature = "group-bits")] +use group::ff::{FieldBits, PrimeFieldBits}; + +#[cfg(any(test, feature = "group"))] +use rand_core::RngCore; #[cfg(any(test, feature = "rand_core"))] use rand_core::CryptoRngCore; @@ -292,7 +292,7 @@ impl Scalar { } impl Debug for Scalar { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "Scalar{{\n\tbytes: {:?},\n}}", &self.bytes) } } @@ -413,7 +413,7 @@ impl ConditionallySelectable for Scalar { #[cfg(feature = "serde")] use serde::de::Visitor; #[cfg(feature = "serde")] -use serde::{self, Deserialize, Deserializer, Serialize, Serializer}; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "serde")] #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] @@ -443,7 +443,7 @@ impl<'de> Deserialize<'de> for Scalar { impl<'de> Visitor<'de> for ScalarVisitor { type Value = Scalar; - fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { formatter.write_str( "a sequence of 32 bytes whose little-endian interpretation is less than the \ basepoint order ℓ", @@ -844,7 +844,7 @@ impl Scalar { } #[cfg(feature = "zeroize")] - zeroize::Zeroize::zeroize(&mut scratch); + Zeroize::zeroize(&mut scratch); ret } @@ -1254,10 +1254,12 @@ impl Field for Scalar { } fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { + #[allow(unused_qualifications)] group::ff::helpers::sqrt_ratio_generic(num, div) } fn sqrt(&self) -> CtOption { + #[allow(unused_qualifications)] group::ff::helpers::sqrt_tonelli_shanks( self, [ @@ -1342,6 +1344,19 @@ impl PrimeField for Scalar { }; } +#[cfg(feature = "group-bits")] +impl PrimeFieldBits for Scalar { + type ReprBits = [u8; 32]; + + fn to_le_bits(&self) -> FieldBits { + self.to_repr().into() + } + + fn char_le_bits() -> FieldBits { + constants::BASEPOINT_ORDER_PRIVATE.to_bytes().into() + } +} + #[cfg(feature = "group")] impl FromUniformBytes<64> for Scalar { fn from_uniform_bytes(bytes: &[u8; 64]) -> Self { @@ -1405,8 +1420,6 @@ pub(crate) mod test { #[cfg(feature = "alloc")] use alloc::vec::Vec; - use rand::RngCore; - /// x = 2238329342913194256032495932344128051776374960164957527413114840482143558222 pub static X: Scalar = Scalar { bytes: [ diff --git a/curve25519-dalek/src/traits.rs b/curve25519-dalek/src/traits.rs index a12592b86..322787db5 100644 --- a/curve25519-dalek/src/traits.rs +++ b/curve25519-dalek/src/traits.rs @@ -15,9 +15,8 @@ use core::borrow::Borrow; -use subtle; - use crate::scalar::{clamp_integer, Scalar}; +use subtle::ConstantTimeEq; // ------------------------------------------------------------------------ // Public Traits @@ -41,7 +40,7 @@ pub trait IsIdentity { /// constructor. impl IsIdentity for T where - T: subtle::ConstantTimeEq + Identity, + T: ConstantTimeEq + Identity, { fn is_identity(&self) -> bool { self.ct_eq(&T::identity()).into() @@ -409,6 +408,7 @@ pub trait VartimePrecomputedMultiscalarMul: Sized { /// This trait is only for debugging/testing, since it should be /// impossible for a `curve25519-dalek` user to construct an invalid /// point. +#[allow(dead_code)] pub(crate) trait ValidityCheck { /// Checks whether the point is on the curve. Not CT. fn is_valid(&self) -> bool; diff --git a/curve25519-dalek/src/window.rs b/curve25519-dalek/src/window.rs index 8c575ee04..43c4b3abb 100644 --- a/curve25519-dalek/src/window.rs +++ b/curve25519-dalek/src/window.rs @@ -83,7 +83,7 @@ macro_rules! impl_lookup_table { } impl Debug for $name { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "{:?}(", stringify!($name))?; for x in self.0.iter() { @@ -193,7 +193,7 @@ impl NafLookupTable5 { } impl Debug for NafLookupTable5 { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "NafLookupTable5({:?})", self.0) } } @@ -240,7 +240,7 @@ impl NafLookupTable8 { #[cfg(any(feature = "precomputed-tables", feature = "alloc"))] impl Debug for NafLookupTable8 { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { writeln!(f, "NafLookupTable8([")?; for i in 0..64 { writeln!(f, "\t{:?},", &self.0[i])?; diff --git a/ed25519-dalek/CHANGELOG.md b/ed25519-dalek/CHANGELOG.md index c3fc94a5c..9d1b65e6b 100644 --- a/ed25519-dalek/CHANGELOG.md +++ b/ed25519-dalek/CHANGELOG.md @@ -6,8 +6,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 Entries are listed in reverse chronological order per undeprecated major series. +# Unreleased + # 2.x series +## 2.1.1 + +* Fix nightly SIMD build + +## 2.1.0 + +* Add `SigningKey::to_scalar_bytes` for getting the unclamped scalar from a signing key +* Loosened `signature` dependency to allow version 2.2 + ## 2.0.0 ### Breaking changes diff --git a/ed25519-dalek/Cargo.toml b/ed25519-dalek/Cargo.toml index c8e2439cf..cdc4d0a53 100644 --- a/ed25519-dalek/Cargo.toml +++ b/ed25519-dalek/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "2.0.0" +version = "2.1.1" edition = "2021" authors = [ "isis lovecruft ", @@ -28,7 +28,7 @@ features = ["batch", "digest", "hazmat", "pem", "serde"] [dependencies] curve25519-dalek = { version = "4", path = "../curve25519-dalek", default-features = false, features = ["digest"] } ed25519 = { version = ">=2.2, <2.3", default-features = false } -signature = { version = ">=2.0, <2.1", optional = true, default-features = false } +signature = { version = ">=2.0, <2.3", optional = true, default-features = false } sha2 = { version = "0.10", default-features = false } subtle = { version = "2.3.0", default-features = false } @@ -40,6 +40,7 @@ zeroize = { version = "1.5", default-features = false, optional = true } [dev-dependencies] curve25519-dalek = { version = "4", path = "../curve25519-dalek", default-features = false, features = ["digest", "rand_core"] } +x25519-dalek = { version = "2", path = "../x25519-dalek", default-features = false, features = ["static_secrets"] } blake2 = "0.10" sha3 = "0.10" hex = "0.4" diff --git a/ed25519-dalek/README.md b/ed25519-dalek/README.md index 7524395d0..dbb14b00b 100644 --- a/ed25519-dalek/README.md +++ b/ed25519-dalek/README.md @@ -31,7 +31,7 @@ This crate is `#[no_std]` compatible with `default-features = false`. # Major Changes -See [CHANGELOG.md](CHANGELOG.md) for a list of changes made in past version of this crate. +See [CHANGELOG.md](CHANGELOG.md) for a list of changes made in past versions of this crate. ## Breaking Changes in 2.0.0 @@ -43,7 +43,7 @@ See [CHANGELOG.md](CHANGELOG.md) for a list of changes made in past version of t * Make `rand_core` an optional dependency * Adopt [curve25519-backend selection](https://github.com/dalek-cryptography/curve25519-dalek/#backends) over features * Make all batch verification deterministic remove `batch_deterministic` ([#256](https://github.com/dalek-cryptography/ed25519-dalek/pull/256)) -* Remove `ExpandedSecretKey` API ((#205)[https://github.com/dalek-cryptography/ed25519-dalek/pull/205]) +* Remove `ExpandedSecretKey` API ([#205](https://github.com/dalek-cryptography/ed25519-dalek/pull/205)) * Rename `Keypair` → `SigningKey` and `PublicKey` → `VerifyingKey` * Make `hazmat` feature to expose, `ExpandedSecretKey`, `raw_sign()`, `raw_sign_prehashed()`, `raw_verify()`, and `raw_verify_prehashed()` @@ -63,7 +63,7 @@ SemVer exemptions are outlined below for MSRV and public API. | 2.x | 1.60 | | 1.x | 1.41 | -From 2.x and on, MSRV changes will be accompanied by a minor version bump. +From 2.x onwards, MSRV changes will be accompanied by a minor version bump. ## Public API SemVer Exemptions @@ -130,7 +130,7 @@ Backend selection details and instructions can be found in the [curve25519-dalek # Contributing -See [CONTRIBUTING.md](CONTRIBUTING.md) +See [CONTRIBUTING.md](../CONTRIBUTING.md) # Batch Signature Verification diff --git a/ed25519-dalek/src/batch.rs b/ed25519-dalek/src/batch.rs index ed2618d6c..fa79677d5 100644 --- a/ed25519-dalek/src/batch.rs +++ b/ed25519-dalek/src/batch.rs @@ -11,7 +11,6 @@ use alloc::vec::Vec; -use core::convert::TryFrom; use core::iter::once; use curve25519_dalek::constants; diff --git a/ed25519-dalek/src/lib.rs b/ed25519-dalek/src/lib.rs index a7cfac488..21d8737ba 100644 --- a/ed25519-dalek/src/lib.rs +++ b/ed25519-dalek/src/lib.rs @@ -21,6 +21,7 @@ #![cfg_attr(feature = "rand_core", doc = "```")] #![cfg_attr(not(feature = "rand_core"), doc = "```ignore")] //! # fn main() { +//! // $ cargo add ed25519_dalek --features rand_core //! use rand::rngs::OsRng; //! use ed25519_dalek::SigningKey; //! use ed25519_dalek::Signature; diff --git a/ed25519-dalek/src/signature.rs b/ed25519-dalek/src/signature.rs index 36174c8d6..af8276834 100644 --- a/ed25519-dalek/src/signature.rs +++ b/ed25519-dalek/src/signature.rs @@ -9,7 +9,6 @@ //! An ed25519 signature. -use core::convert::TryFrom; use core::fmt::Debug; use curve25519_dalek::edwards::CompressedEdwardsY; @@ -58,7 +57,7 @@ impl Clone for InternalSignature { } impl Debug for InternalSignature { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "Signature( R: {:?}, s: {:?} )", &self.R, &self.s) } } diff --git a/ed25519-dalek/src/signing.rs b/ed25519-dalek/src/signing.rs index fad45f706..8999f50d2 100644 --- a/ed25519-dalek/src/signing.rs +++ b/ed25519-dalek/src/signing.rs @@ -9,6 +9,8 @@ //! ed25519 signing keys. +use core::fmt::Debug; + #[cfg(feature = "pkcs8")] use ed25519::pkcs8; @@ -58,7 +60,7 @@ pub type SecretKey = [u8; SECRET_KEY_LENGTH]; // Invariant: `verifying_key` is always the public key of // `secret_key`. This prevents the signing function oracle attack // described in https://github.com/MystenLabs/ed25519-unsafe-libs -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct SigningKey { /// The secret half of this signing key. pub(crate) secret_key: SecretKey, @@ -129,7 +131,7 @@ impl SigningKey { /// # Returns /// /// A `Result` whose okay value is an EdDSA [`SigningKey`] or whose error value - /// is an `SignatureError` describing the error that occurred. + /// is a `SignatureError` describing the error that occurred. #[inline] pub fn from_keypair_bytes(bytes: &[u8; 64]) -> Result { let (secret_key, verifying_key) = bytes.split_at(SECRET_KEY_LENGTH); @@ -481,15 +483,43 @@ impl SigningKey { self.verifying_key.verify_strict(message, signature) } - /// Convert this signing key into a byte representation of a(n) (unreduced) Curve25519 scalar. + /// Convert this signing key into a byte representation of an unreduced, unclamped Curve25519 + /// scalar. This is NOT the same thing as `self.to_scalar().to_bytes()`, since `to_scalar()` + /// performs a clamping step, which changes the value of the resulting scalar. /// /// This can be used for performing X25519 Diffie-Hellman using Ed25519 keys. The bytes output - /// by this function are a valid secret key for the X25519 public key given by - /// `self.verifying_key().to_montgomery()`. + /// by this function are a valid corresponding [`StaticSecret`](https://docs.rs/x25519-dalek/2.0.0/x25519_dalek/struct.StaticSecret.html#impl-From%3C%5Bu8;+32%5D%3E-for-StaticSecret) + /// for the X25519 public key given by `self.verifying_key().to_montgomery()`. + /// + /// # Note + /// + /// We do NOT recommend using a signing/verifying key for encryption. Signing keys are usually + /// long-term keys, while keys used for key exchange should rather be ephemeral. If you can + /// help it, use a separate key for encryption. + /// + /// For more information on the security of systems which use the same keys for both signing + /// and Diffie-Hellman, see the paper + /// [On using the same key pair for Ed25519 and an X25519 based KEM](https://eprint.iacr.org/2021/509). + pub fn to_scalar_bytes(&self) -> [u8; 32] { + // Per the spec, the ed25519 secret key sk is expanded to + // (scalar_bytes, hash_prefix) = SHA-512(sk) + // where the two outputs are both 32 bytes. scalar_bytes is what we return. Its clamped and + // reduced form is what we use for signing (see impl ExpandedSecretKey) + let mut buf = [0u8; 32]; + let scalar_and_hash_prefix = Sha512::default().chain_update(self.secret_key).finalize(); + buf.copy_from_slice(&scalar_and_hash_prefix[..32]); + buf + } + + /// Convert this signing key into a Curve25519 scalar. This is computed by clamping and + /// reducing the output of [`Self::to_scalar_bytes`]. + /// + /// This can be used anywhere where a Curve25519 scalar is used as a private key, e.g., in + /// [`crypto_box`](https://docs.rs/crypto_box/0.9.1/crypto_box/struct.SecretKey.html#impl-From%3CScalar%3E-for-SecretKey). /// /// # Note /// - /// We do NOT recommend this usage of a signing/verifying key. Signing keys are usually + /// We do NOT recommend using a signing/verifying key for encryption. Signing keys are usually /// long-term keys, while keys used for key exchange should rather be ephemeral. If you can /// help it, use a separate key for encryption. /// @@ -497,6 +527,11 @@ impl SigningKey { /// and Diffie-Hellman, see the paper /// [On using the same key pair for Ed25519 and an X25519 based KEM](https://eprint.iacr.org/2021/509). pub fn to_scalar(&self) -> Scalar { + // Per the spec, the ed25519 secret key sk is expanded to + // (scalar_bytes, hash_prefix) = SHA-512(sk) + // where the two outputs are both 32 bytes. To use for signing, scalar_bytes must be + // clamped and reduced (see ExpandedSecretKey::from_bytes). We return the clamped and + // reduced form. ExpandedSecretKey::from(&self.secret_key).scalar } } @@ -507,6 +542,14 @@ impl AsRef for SigningKey { } } +impl Debug for SigningKey { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("SigningKey") + .field("verifying_key", &self.verifying_key) + .finish_non_exhaustive() // avoids printing `secret_key` + } +} + impl KeypairRef for SigningKey { type VerifyingKey = VerifyingKey; } @@ -699,14 +742,11 @@ impl<'d> Deserialize<'d> for SigningKey { impl<'de> serde::de::Visitor<'de> for SigningKeyVisitor { type Value = SigningKey; - fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(formatter, concat!("An ed25519 signing (private) key")) } - fn visit_borrowed_bytes( - self, - bytes: &'de [u8], - ) -> Result { + fn visit_bytes(self, bytes: &[u8]) -> Result { SigningKey::try_from(bytes).map_err(E::custom) } diff --git a/ed25519-dalek/src/verifying.rs b/ed25519-dalek/src/verifying.rs index 29f8a4d14..246951b44 100644 --- a/ed25519-dalek/src/verifying.rs +++ b/ed25519-dalek/src/verifying.rs @@ -9,7 +9,6 @@ //! ed25519 public keys. -use core::convert::TryFrom; use core::fmt::Debug; use core::hash::{Hash, Hasher}; @@ -505,6 +504,11 @@ impl VerifyingKey { pub fn to_montgomery(&self) -> MontgomeryPoint { self.point.to_montgomery() } + + /// Return this verifying key in Edwards form. + pub fn to_edwards(&self) -> EdwardsPoint { + self.point + } } impl Verifier for VerifyingKey { @@ -563,6 +567,12 @@ impl TryFrom<&[u8]> for VerifyingKey { } } +impl From for EdwardsPoint { + fn from(vk: VerifyingKey) -> EdwardsPoint { + vk.point + } +} + #[cfg(all(feature = "alloc", feature = "pkcs8"))] impl pkcs8::EncodePublicKey for VerifyingKey { fn to_public_key_der(&self) -> pkcs8::spki::Result { @@ -632,14 +642,11 @@ impl<'d> Deserialize<'d> for VerifyingKey { impl<'de> serde::de::Visitor<'de> for VerifyingKeyVisitor { type Value = VerifyingKey; - fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(formatter, concat!("An ed25519 verifying (public) key")) } - fn visit_borrowed_bytes( - self, - bytes: &'de [u8], - ) -> Result { + fn visit_bytes(self, bytes: &[u8]) -> Result { VerifyingKey::try_from(bytes).map_err(E::custom) } diff --git a/ed25519-dalek/tests/ed25519.rs b/ed25519-dalek/tests/ed25519.rs index 6c8b559eb..208f0271f 100644 --- a/ed25519-dalek/tests/ed25519.rs +++ b/ed25519-dalek/tests/ed25519.rs @@ -27,6 +27,8 @@ mod vectors { scalar::Scalar, traits::IsIdentity, }; + + #[cfg(not(feature = "digest"))] use sha2::{digest::Digest, Sha512}; use std::{ @@ -280,8 +282,6 @@ mod vectors { mod integrations { use super::*; use rand::rngs::OsRng; - #[cfg(feature = "digest")] - use sha2::Sha512; use std::collections::HashMap; #[test] @@ -451,6 +451,29 @@ mod integrations { assert_eq!(v, "Second public key"); assert_eq!(m.len(), 2usize); } + + #[test] + fn montgomery_and_edwards_conversion() { + let mut rng = rand::rngs::OsRng; + let signing_key = SigningKey::generate(&mut rng); + let verifying_key = signing_key.verifying_key(); + + let ed = verifying_key.to_edwards(); + + // Check that to_edwards and From return same result: + assert_eq!(ed, curve25519_dalek::EdwardsPoint::from(verifying_key)); + + // The verifying key serialization is simply the compressed Edwards point + assert_eq!(verifying_key.to_bytes(), ed.compress().0); + + // Check that modulo sign, to_montgomery().to_edwards() returns the original point + let monty = verifying_key.to_montgomery(); + let via_monty0 = monty.to_edwards(0).unwrap(); + let via_monty1 = monty.to_edwards(1).unwrap(); + + assert!(via_monty0 != via_monty1); + assert!(ed == via_monty0 || ed == via_monty1); + } } #[cfg(all(test, feature = "serde"))] diff --git a/ed25519-dalek/tests/validation_criteria.rs b/ed25519-dalek/tests/validation_criteria.rs index 75a02f4bb..c4270d03a 100644 --- a/ed25519-dalek/tests/validation_criteria.rs +++ b/ed25519-dalek/tests/validation_criteria.rs @@ -22,7 +22,7 @@ const VERIFY_ALLOWED_EDGECASES: &[Flag] = &[ const VERIFY_STRICT_ALLOWED_EDGECASES: &[Flag] = &[Flag::LowOrderComponentA, Flag::LowOrderComponentR]; -/// Each variant describes a specfiic edge case that can occur in an Ed25519 signature. Refer to +/// Each variant describes a specific edge case that can occur in an Ed25519 signature. Refer to /// the test vector [README][] for more info. /// /// [README]: https://github.com/C2SP/CCTV/blob/5ea85644bd035c555900a2f707f7e4c31ea65ced/ed25519vectors/README.md diff --git a/ed25519-dalek/tests/x25519.rs b/ed25519-dalek/tests/x25519.rs index 48dab2784..11e72a804 100644 --- a/ed25519-dalek/tests/x25519.rs +++ b/ed25519-dalek/tests/x25519.rs @@ -4,63 +4,77 @@ use curve25519_dalek::scalar::{clamp_integer, Scalar}; use ed25519_dalek::SigningKey; use hex_literal::hex; use sha2::{Digest, Sha512}; - -/// Helper function to return the bytes corresponding to the input bytes after being clamped and -/// reduced mod 2^255 - 19 -fn clamp_and_reduce(bytes: &[u8]) -> [u8; 32] { - assert_eq!(bytes.len(), 32); - Scalar::from_bytes_mod_order(clamp_integer(bytes.try_into().unwrap())).to_bytes() -} +use x25519_dalek::{PublicKey as XPublicKey, StaticSecret as XStaticSecret}; /// Tests that X25519 Diffie-Hellman works when using keys converted from Ed25519. // TODO: generate test vectors using another implementation of Ed25519->X25519 #[test] fn ed25519_to_x25519_dh() { // Keys from RFC8032 test vectors (from section 7.1) - let ed25519_secret_key_a = - hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); - let ed25519_secret_key_b = - hex!("4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb"); + let ed_secret_key_a = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); + let ed_secret_key_b = hex!("4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb"); + + let ed_signing_key_a = SigningKey::from_bytes(&ed_secret_key_a); + let ed_signing_key_b = SigningKey::from_bytes(&ed_secret_key_b); - let ed25519_signing_key_a = SigningKey::from_bytes(&ed25519_secret_key_a); - let ed25519_signing_key_b = SigningKey::from_bytes(&ed25519_secret_key_b); + // Create an x25519 static secret from the ed25519 signing key + let scalar_bytes_a = ed_signing_key_a.to_scalar_bytes(); + let scalar_bytes_b = ed_signing_key_b.to_scalar_bytes(); + let x_static_secret_a = XStaticSecret::from(scalar_bytes_a); + let x_static_secret_b = XStaticSecret::from(scalar_bytes_b); - let scalar_a = ed25519_signing_key_a.to_scalar(); - let scalar_b = ed25519_signing_key_b.to_scalar(); + // Compute the secret scalars too + let scalar_a = ed_signing_key_a.to_scalar(); + let scalar_b = ed_signing_key_b.to_scalar(); // Compare the scalar bytes to the first 32 bytes of SHA-512(secret_key). We have to clamp and // reduce the SHA-512 output because that's what the spec does before using the scalars for // anything. + assert_eq!(scalar_bytes_a, &Sha512::digest(ed_secret_key_a)[..32]); + assert_eq!(scalar_bytes_b, &Sha512::digest(ed_secret_key_b)[..32]); + + // Compare the scalar with the clamped and reduced scalar bytes assert_eq!( - scalar_a.to_bytes(), - clamp_and_reduce(&Sha512::digest(ed25519_secret_key_a)[..32]), + scalar_a, + Scalar::from_bytes_mod_order(clamp_integer(scalar_bytes_a)) ); assert_eq!( - scalar_b.to_bytes(), - clamp_and_reduce(&Sha512::digest(ed25519_secret_key_b)[..32]), + scalar_b, + Scalar::from_bytes_mod_order(clamp_integer(scalar_bytes_b)) ); - let x25519_public_key_a = ed25519_signing_key_a.verifying_key().to_montgomery(); - let x25519_public_key_b = ed25519_signing_key_b.verifying_key().to_montgomery(); - + let x_public_key_a = XPublicKey::from(&x_static_secret_a); + let x_public_key_b = XPublicKey::from(&x_static_secret_b); assert_eq!( - x25519_public_key_a.to_bytes(), + x_public_key_a.to_bytes(), hex!("d85e07ec22b0ad881537c2f44d662d1a143cf830c57aca4305d85c7a90f6b62e") ); assert_eq!( - x25519_public_key_b.to_bytes(), + x_public_key_b.to_bytes(), hex!("25c704c594b88afc00a76b69d1ed2b984d7e22550f3ed0802d04fbcd07d38d47") ); + // Test the claim made in the comments of SigningKey::to_scalar_bytes, i.e., that the resulting + // scalar is a valid private key for the x25519 pubkey represented by + // `sk.verifying_key().to_montgomery()` + assert_eq!( + ed_signing_key_a.verifying_key().to_montgomery().as_bytes(), + x_public_key_a.as_bytes() + ); + assert_eq!( + ed_signing_key_b.verifying_key().to_montgomery().as_bytes(), + x_public_key_b.as_bytes() + ); + + // Check that Diffie-Hellman works let expected_shared_secret = hex!("5166f24a6918368e2af831a4affadd97af0ac326bdf143596c045967cc00230e"); - assert_eq!( - (x25519_public_key_a * scalar_b).to_bytes(), - expected_shared_secret + x_static_secret_a.diffie_hellman(&x_public_key_b).to_bytes(), + expected_shared_secret, ); assert_eq!( - (x25519_public_key_b * scalar_a).to_bytes(), - expected_shared_secret + x_static_secret_b.diffie_hellman(&x_public_key_a).to_bytes(), + expected_shared_secret, ); } diff --git a/x25519-dalek/CHANGELOG.md b/x25519-dalek/CHANGELOG.md index d2c337c03..10e1a5454 100644 --- a/x25519-dalek/CHANGELOG.md +++ b/x25519-dalek/CHANGELOG.md @@ -6,6 +6,10 @@ Entries are listed in reverse chronological order. * Note: All `x255919-dalek` 2.x releases are in sync with the underlying `curve25519-dalek` 4.x releases. +## 2.0.1 + +* Fix nightly SIMD build + ## 2.0.0-rc.3 * `StaticSecret` serialization and `to_bytes()` no longer returns clamped integers. Clamping is still always done during scalar-point multiplication. diff --git a/x25519-dalek/Cargo.toml b/x25519-dalek/Cargo.toml index e41461853..4169c55a4 100644 --- a/x25519-dalek/Cargo.toml +++ b/x25519-dalek/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # - update html_root_url # - update CHANGELOG # - if any changes were made to README.md, mirror them in src/lib.rs docs -version = "2.0.0" +version = "2.0.1" authors = [ "Isis Lovecruft ", "DebugSteven ", diff --git a/x25519-dalek/src/lib.rs b/x25519-dalek/src/lib.rs index 9a5fc1938..7886eeaa5 100644 --- a/x25519-dalek/src/lib.rs +++ b/x25519-dalek/src/lib.rs @@ -15,7 +15,6 @@ // README.md as the crate documentation. #![no_std] -#![cfg_attr(feature = "bench", feature(test))] #![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg, doc_cfg_hide))] #![cfg_attr(docsrs, doc(cfg_hide(docsrs)))] #![deny(missing_docs)]