From 39c34cb7605d5bdfa1a99891b1304d99b65e6f39 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Mon, 12 Jun 2023 23:53:59 +0000 Subject: [PATCH 01/53] Vendor import unsafe_target_features as curve25519-dalek-derive Co-authored-by: Jan Bujak --- vendor/curve25519-dalek-derive/.gitignore | 2 + vendor/curve25519-dalek-derive/Cargo.toml | 20 + vendor/curve25519-dalek-derive/LICENSE-APACHE | 201 ++++++++ vendor/curve25519-dalek-derive/LICENSE-MIT | 23 + vendor/curve25519-dalek-derive/README.md | 191 +++++++ vendor/curve25519-dalek-derive/src/lib.rs | 466 ++++++++++++++++++ vendor/curve25519-dalek-derive/tests/tests.rs | 151 ++++++ 7 files changed, 1054 insertions(+) create mode 100644 vendor/curve25519-dalek-derive/.gitignore create mode 100644 vendor/curve25519-dalek-derive/Cargo.toml create mode 100644 vendor/curve25519-dalek-derive/LICENSE-APACHE create mode 100644 vendor/curve25519-dalek-derive/LICENSE-MIT create mode 100644 vendor/curve25519-dalek-derive/README.md create mode 100644 vendor/curve25519-dalek-derive/src/lib.rs create mode 100644 vendor/curve25519-dalek-derive/tests/tests.rs diff --git a/vendor/curve25519-dalek-derive/.gitignore b/vendor/curve25519-dalek-derive/.gitignore new file mode 100644 index 000000000..4fffb2f89 --- /dev/null +++ b/vendor/curve25519-dalek-derive/.gitignore @@ -0,0 +1,2 @@ +/target +/Cargo.lock diff --git a/vendor/curve25519-dalek-derive/Cargo.toml b/vendor/curve25519-dalek-derive/Cargo.toml new file mode 100644 index 000000000..753de472f --- /dev/null +++ b/vendor/curve25519-dalek-derive/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "unsafe_target_feature" +version = "0.1.1" +edition = "2021" + +authors = ["Jan Bujak "] +repository = "https://github.com/koute/unsafe_target_feature" +homepage = "https://github.com/koute/unsafe_target_feature" +documentation = "https://docs.rs/unsafe_target_feature/*/unsafe_target_feature/" +license = "MIT/Apache-2.0" +readme = "README.md" +description = "A more convenient #[target_feature] replacement" + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "1.0.53" +quote = "1.0.26" +syn = { version = "2.0.8", features = ["full"] } diff --git a/vendor/curve25519-dalek-derive/LICENSE-APACHE b/vendor/curve25519-dalek-derive/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/vendor/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/vendor/curve25519-dalek-derive/LICENSE-MIT b/vendor/curve25519-dalek-derive/LICENSE-MIT new file mode 100644 index 000000000..31aa79387 --- /dev/null +++ b/vendor/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/vendor/curve25519-dalek-derive/README.md b/vendor/curve25519-dalek-derive/README.md new file mode 100644 index 000000000..2b9428690 --- /dev/null +++ b/vendor/curve25519-dalek-derive/README.md @@ -0,0 +1,191 @@ +# A more convenient `#[target_feature]` replacement + +To get good performance out of SIMD everything on the SIMD codepath must be inlined. +With how SIMD is currently implemented in Rust one of two things have to be true for +a function using SIMD to be inlinable: (and this includes the SIMD intrinsics themselves) + + a) The whole program has to be compiled with the relevant `-C target-cpu` or `-C target-feature` flags. + + b) SIMD support must be automatically detected at runtime, and every function on the SIMD codepath must be marked with `#[target_feature]`. + +Both have their downsides. Setting the `target-cpu` or `target-features` makes the resulting binary +incompatible with older CPUs, while using `#[target_feature]` is incredibly inconvenient. + +This crate is meant to make `#[target_feature]` less painful to use. + +## Problems with `#[target_feature]` + +When we're not compiling with the relevant `target-cpu`/`target-feature` flags everything on +the SIMD codepath must be marked with the `#[target_feature]` attribute. This is not a problem +when all of your SIMD code is neatly encapsulated inside of a single function, but once you start +to build out more elaborate abstractions it starts to become painful to use. + + * It can only be used on `unsafe` functions, so everything on your SIMD codepath now has to be `unsafe`. + + In theory this is nice - these functions require the relevant SIMD instructions to be present at runtime, + so calling them without checking is obviously unsafe! But in practice this is rarely what you want. When + you build an abstraction over SIMD code you usually want to assume that *internally* within your module + all of the necessary SIMD instructions are available, and you only want to check this at the boundaries + when you're first entering your module. You do *not* want to infect everything *inside* of the module with + `unsafe` since you've already checked this invariant at the module's API boundary. + + * It cannot be used on non-`unsafe` trait methods. + + If you're implementing a trait, say for example `std::ops::Add`, then you cannot mark the method `unsafe` + unless the original trait also has it marked as `unsafe`, and usually it doesn't. + + * It makes it impossible to abstract over a given SIMD instruction set using a trait. + + For example, let's assume you want to abstract over which SIMD instructions you use using a trait in the following way: + + ```rust + trait Backend { + unsafe fn sum(input: &[u32]) -> u32; + } + + struct AVX; + impl Backend for AVX { + #[target_feature(enable = "avx")] + unsafe fn sum(xs: &[u32]) -> u32 { + // ... + todo!(); + } + } + + struct AVX2; + impl Backend for AVX2 { + #[target_feature(enable = "avx2")] + unsafe fn sum(xs: &[u32]) -> u32 { + // ... + todo!(); + } + } + + // And now you want a have function which calls into that trait: + unsafe fn do_calculations(xs: &[u32]) -> u32 where B: Backend { + let value = B::sum(xs); + // ...do some more calculations here... + value + } + ``` + + We have a problem here. This has to be marked with `#[target_feature]`, and that has to specify the concrete + feature flag for a given SIMD instruction set, but this function is generic so we can't do that! + +## How does this crate make it better? + +### You can now mark safe functions with `#[target_feature]` + +This crate exposes an `#[unsafe_target_feature]` macro which works just like `#[target_feature]` except +it moves the `unsafe` from the function prototype into the macro name, and can be used on safe functions. + +```rust,compile_fail +// ERROR: `#[target_feature(..)]` can only be applied to `unsafe` functions +#[target_feature(enable = "avx2")] +fn func() {} +``` + +```rust +// It works, but must be `unsafe` +#[target_feature(enable = "avx2")] +unsafe fn func() {} +``` + +```rust +use unsafe_target_feature::unsafe_target_feature; + +// No `unsafe` on the function itself! +#[unsafe_target_feature("avx2")] +fn func() {} +``` + +It can also be used to mark functions inside of impls: + +```rust,compile_fail +struct S; + +impl core::ops::Add for S { + type Output = S; + // ERROR: method `add` has an incompatible type for trait + #[target_feature(enable = "avx2")] + unsafe fn add(self, rhs: S) -> S { + S + } +} +``` + +```rust +use unsafe_target_feature::unsafe_target_feature; + +struct S; + +#[unsafe_target_feature("avx2")] +impl core::ops::Add for S { + type Output = S; + // No `unsafe` on the function itself! + fn add(self, rhs: S) -> S { + S + } +} + +``` + +### You can generate specialized copies of a module for each target feature + +```rust +use unsafe_target_feature::unsafe_target_feature_specialize; + +#[unsafe_target_feature_specialize("sse2", "avx2", conditional("avx512ifma", nightly))] +mod simd { + #[for_target_feature("sse2")] + pub const CONSTANT: u32 = 1; + + #[for_target_feature("avx2")] + pub const CONSTANT: u32 = 2; + + #[for_target_feature("avx512ifma")] + pub const CONSTANT: u32 = 3; + + pub fn func() { /* ... */ } +} + +fn entry_point() { + #[cfg(nightly)] + if std::is_x86_feature_detected!("avx512ifma") { + return simd_avx512ifma::func(); + } + + if std::is_x86_feature_detected!("avx2") { + return simd_avx2::func(); + } + + if std::is_x86_feature_detected!("sse2") { + return simd_sse2::func(); + } + + unimplemented!(); +} +``` + +## How to use `#[unsafe_target_feature]`? + + - Can be used on `fn`s, `impl`s and `mod`s. + - When used on a function will only apply to that function; it won't apply to any nested functions, traits, mods, etc. + - When used on an `impl` will only apply to all of the functions directly defined inside of that `impl`. + - When used on a `mod` will only apply to all of the `fn`s and `impl`s directly defined inside of that `mod`. + - Cannot be used on methods which use `self` or `Self`; instead use it on the `impl` in which the method is defined. + +## License + +Licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or ) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or ) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/vendor/curve25519-dalek-derive/src/lib.rs b/vendor/curve25519-dalek-derive/src/lib.rs new file mode 100644 index 000000000..53877493e --- /dev/null +++ b/vendor/curve25519-dalek-derive/src/lib.rs @@ -0,0 +1,466 @@ +#![doc = include_str!("../README.md")] + +use proc_macro::TokenStream; +use proc_macro2::TokenStream as TokenStream2; +use syn::spanned::Spanned; + +macro_rules! unsupported_if_some { + ($value:expr) => { + if let Some(value) = $value { + return syn::Error::new(value.span(), "unsupported by #[unsafe_target_feature(...)]") + .into_compile_error() + .into(); + } + }; +} + +macro_rules! unsupported { + ($value: expr) => { + return syn::Error::new( + $value.span(), + "unsupported by #[unsafe_target_feature(...)]", + ) + .into_compile_error() + .into() + }; +} + +mod kw { + syn::custom_keyword!(conditional); +} + +enum SpecializeArg { + LitStr(syn::LitStr), + Conditional(Conditional), +} + +impl SpecializeArg { + fn lit(&self) -> &syn::LitStr { + match self { + SpecializeArg::LitStr(lit) => lit, + SpecializeArg::Conditional(conditional) => &conditional.lit, + } + } + + fn condition(&self) -> Option<&TokenStream2> { + match self { + SpecializeArg::LitStr(..) => None, + SpecializeArg::Conditional(conditional) => Some(&conditional.attr), + } + } +} + +struct Conditional { + lit: syn::LitStr, + attr: TokenStream2, +} + +impl syn::parse::Parse for Conditional { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let lit = input.parse()?; + input.parse::()?; + let attr = input.parse()?; + + Ok(Conditional { lit, attr }) + } +} + +impl syn::parse::Parse for SpecializeArg { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let lookahead = input.lookahead1(); + if lookahead.peek(kw::conditional) { + input.parse::()?; + + let content; + syn::parenthesized!(content in input); + + let conditional = content.parse()?; + Ok(SpecializeArg::Conditional(conditional)) + } else { + Ok(SpecializeArg::LitStr(input.parse()?)) + } + } +} + +struct SpecializeArgs(syn::punctuated::Punctuated); + +impl syn::parse::Parse for SpecializeArgs { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + Ok(Self(syn::punctuated::Punctuated::parse_terminated(input)?)) + } +} + +#[proc_macro_attribute] +pub fn unsafe_target_feature(attributes: TokenStream, input: TokenStream) -> TokenStream { + let attributes = syn::parse_macro_input!(attributes as syn::LitStr); + let item = syn::parse_macro_input!(input as syn::Item); + process_item(&attributes, item, true) +} + +#[proc_macro_attribute] +pub fn unsafe_target_feature_specialize( + attributes: TokenStream, + input: TokenStream, +) -> TokenStream { + let attributes = syn::parse_macro_input!(attributes as SpecializeArgs); + let item_mod = syn::parse_macro_input!(input as syn::ItemMod); + + let mut out = Vec::new(); + for attributes in attributes.0 { + let features: Vec<_> = attributes + .lit() + .value() + .split(",") + .map(|feature| feature.replace(" ", "")) + .collect(); + let name = format!("{}_{}", item_mod.ident, features.join("_")); + let ident = syn::Ident::new(&name, item_mod.ident.span()); + let mut attrs = item_mod.attrs.clone(); + if let Some(condition) = attributes.condition() { + attrs.push(syn::Attribute { + pound_token: Default::default(), + style: syn::AttrStyle::Outer, + bracket_token: Default::default(), + meta: syn::Meta::List(syn::MetaList { + path: syn::Ident::new("cfg", attributes.lit().span()).into(), + delimiter: syn::MacroDelimiter::Paren(Default::default()), + tokens: condition.clone(), + }), + }); + } + + let item_mod = process_mod( + attributes.lit(), + syn::ItemMod { + attrs, + ident, + ..item_mod.clone() + }, + Some(features), + ); + + out.push(item_mod); + } + + quote::quote! { + #(#out)* + } + .into() +} + +fn process_item(attributes: &syn::LitStr, item: syn::Item, strict: bool) -> TokenStream { + match item { + syn::Item::Fn(function) => process_function(attributes, function, None), + syn::Item::Impl(item_impl) => process_impl(attributes, item_impl), + syn::Item::Mod(item_mod) => process_mod(attributes, item_mod, None).into(), + item => { + if strict { + unsupported!(item) + } else { + quote::quote! { #item }.into() + } + } + } +} + +fn process_mod( + attributes: &syn::LitStr, + mut item_mod: syn::ItemMod, + spec_features: Option>, +) -> TokenStream2 { + if let Some((_, ref mut content)) = item_mod.content { + 'next_item: for item in content { + if let Some(ref spec_features) = spec_features { + match item { + syn::Item::Const(syn::ItemConst { ref mut attrs, .. }) + | syn::Item::Enum(syn::ItemEnum { ref mut attrs, .. }) + | syn::Item::ExternCrate(syn::ItemExternCrate { ref mut attrs, .. }) + | syn::Item::Fn(syn::ItemFn { ref mut attrs, .. }) + | syn::Item::ForeignMod(syn::ItemForeignMod { ref mut attrs, .. }) + | syn::Item::Impl(syn::ItemImpl { ref mut attrs, .. }) + | syn::Item::Macro(syn::ItemMacro { ref mut attrs, .. }) + | syn::Item::Mod(syn::ItemMod { ref mut attrs, .. }) + | syn::Item::Static(syn::ItemStatic { ref mut attrs, .. }) + | syn::Item::Struct(syn::ItemStruct { ref mut attrs, .. }) + | syn::Item::Trait(syn::ItemTrait { ref mut attrs, .. }) + | syn::Item::TraitAlias(syn::ItemTraitAlias { ref mut attrs, .. }) + | syn::Item::Type(syn::ItemType { ref mut attrs, .. }) + | syn::Item::Union(syn::ItemUnion { ref mut attrs, .. }) + | syn::Item::Use(syn::ItemUse { ref mut attrs, .. }) => { + let mut index = 0; + while index < attrs.len() { + let attr = &attrs[index]; + if matches!(attr.style, syn::AttrStyle::Outer) { + match attr.meta { + syn::Meta::List(ref list) + if is_path_eq(&list.path, "for_target_feature") => + { + let feature: syn::LitStr = match list.parse_args() { + Ok(feature) => feature, + Err(error) => { + return error.into_compile_error(); + } + }; + + let feature = feature.value(); + if !spec_features + .iter() + .any(|enabled_feature| feature == *enabled_feature) + { + *item = syn::Item::Verbatim(Default::default()); + continue 'next_item; + } + + attrs.remove(index); + continue; + } + _ => {} + } + } + + index += 1; + continue; + } + } + _ => { + unsupported!(item_mod); + } + } + } + + *item = syn::Item::Verbatim( + process_item( + attributes, + std::mem::replace(item, syn::Item::Verbatim(Default::default())), + false, + ) + .into(), + ); + } + } + + quote::quote! { + #item_mod + } +} + +fn process_impl(attributes: &syn::LitStr, mut item_impl: syn::ItemImpl) -> TokenStream { + unsupported_if_some!(item_impl.defaultness); + unsupported_if_some!(item_impl.unsafety); + + let mut items = Vec::new(); + for item in item_impl.items.drain(..) { + match item { + syn::ImplItem::Fn(function) => { + unsupported_if_some!(function.defaultness); + let function = syn::ItemFn { + attrs: function.attrs, + vis: function.vis, + sig: function.sig, + block: Box::new(function.block), + }; + let output_item = process_function( + attributes, + function, + Some((item_impl.generics.clone(), item_impl.self_ty.clone())), + ); + items.push(syn::ImplItem::Verbatim(output_item.into())); + } + item => items.push(item), + } + } + + item_impl.items = items; + quote::quote! { + #item_impl + } + .into() +} + +fn is_path_eq(path: &syn::Path, ident: &str) -> bool { + let segments: Vec<_> = ident.split("::").collect(); + path.segments.len() == segments.len() + && path + .segments + .iter() + .zip(segments.iter()) + .all(|(segment, expected)| segment.ident == expected && segment.arguments.is_none()) +} + +fn process_function( + attributes: &syn::LitStr, + function: syn::ItemFn, + outer: Option<(syn::Generics, Box)>, +) -> TokenStream { + if function.sig.unsafety.is_some() { + return quote::quote! { + #[target_feature(enable = #attributes)] + #function + } + .into(); + } + + unsupported_if_some!(function.sig.constness); + unsupported_if_some!(function.sig.asyncness); + unsupported_if_some!(function.sig.abi); + unsupported_if_some!(function.sig.variadic); + + let function_visibility = function.vis; + let function_name = function.sig.ident; + let function_return = function.sig.output; + let function_inner_name = + syn::Ident::new(&format!("_impl_{}", function_name), function_name.span()); + let function_args = function.sig.inputs; + let function_body = function.block; + let mut function_call_args = Vec::new(); + let mut function_args_outer = Vec::new(); + let mut function_args_inner = Vec::new(); + for (index, arg) in function_args.iter().enumerate() { + match arg { + syn::FnArg::Receiver(receiver) => { + unsupported_if_some!(receiver.attrs.first()); + unsupported_if_some!(receiver.colon_token); + + if outer.is_none() { + return syn::Error::new(receiver.span(), "unsupported by #[unsafe_target_feature(...)]; put the attribute on the outer `impl`").into_compile_error().into(); + } + + function_args_inner.push(syn::FnArg::Receiver(receiver.clone())); + function_args_outer.push(syn::FnArg::Receiver(receiver.clone())); + function_call_args.push(syn::Ident::new("self", receiver.self_token.span())); + } + syn::FnArg::Typed(ty) => { + unsupported_if_some!(ty.attrs.first()); + + match &*ty.pat { + syn::Pat::Ident(pat_ident) => { + unsupported_if_some!(pat_ident.attrs.first()); + + function_args_inner.push(arg.clone()); + function_args_outer.push(syn::FnArg::Typed(syn::PatType { + attrs: Vec::new(), + pat: Box::new(syn::Pat::Ident(syn::PatIdent { + attrs: Vec::new(), + by_ref: None, + mutability: None, + ident: pat_ident.ident.clone(), + subpat: None, + })), + colon_token: ty.colon_token, + ty: ty.ty.clone(), + })); + function_call_args.push(pat_ident.ident.clone()); + } + syn::Pat::Wild(pat_wild) => { + unsupported_if_some!(pat_wild.attrs.first()); + + let ident = syn::Ident::new( + &format!("__arg_{}__", index), + pat_wild.underscore_token.span(), + ); + function_args_inner.push(arg.clone()); + function_args_outer.push(syn::FnArg::Typed(syn::PatType { + attrs: Vec::new(), + pat: Box::new(syn::Pat::Ident(syn::PatIdent { + attrs: Vec::new(), + by_ref: None, + mutability: None, + ident: ident.clone(), + subpat: None, + })), + colon_token: ty.colon_token, + ty: ty.ty.clone(), + })); + function_call_args.push(ident); + } + _ => unsupported!(arg), + } + } + } + } + + let mut maybe_inline = quote::quote! {}; + let mut maybe_outer_attributes = Vec::new(); + let mut maybe_cfg = quote::quote! {}; + for attribute in function.attrs { + match &attribute.meta { + syn::Meta::Path(path) if is_path_eq(path, "inline") => { + maybe_inline = quote::quote! { #[inline] }; + } + syn::Meta::Path(path) if is_path_eq(path, "test") => { + maybe_outer_attributes.push(attribute); + maybe_cfg = quote::quote! { #[cfg(target_feature = #attributes)] }; + } + syn::Meta::List(syn::MetaList { path, tokens, .. }) + if is_path_eq(path, "inline") && tokens.to_string() == "always" => + { + maybe_inline = quote::quote! { #[inline] }; + } + syn::Meta::NameValue(syn::MetaNameValue { path, .. }) if is_path_eq(path, "doc") => { + maybe_outer_attributes.push(attribute); + } + syn::Meta::List(syn::MetaList { path, .. }) + if is_path_eq(path, "cfg") + || is_path_eq(path, "allow") + || is_path_eq(path, "deny") => + { + maybe_outer_attributes.push(attribute); + } + syn::Meta::Path(path) if is_path_eq(path, "rustfmt::skip") => { + maybe_outer_attributes.push(attribute); + } + _ => unsupported!(attribute), + } + } + + let (fn_impl_generics, fn_ty_generics, fn_where_clause) = + function.sig.generics.split_for_impl(); + let fn_call_generics = fn_ty_generics.as_turbofish(); + + if let Some((generics, self_ty)) = outer { + let (outer_impl_generics, outer_ty_generics, outer_where_clause) = + generics.split_for_impl(); + let trait_ident = + syn::Ident::new(&format!("__Impl_{}__", function_name), function_name.span()); + let item_trait = quote::quote! { + #[allow(non_camel_case_types)] + trait #trait_ident #outer_impl_generics #outer_where_clause { + unsafe fn #function_inner_name #fn_impl_generics (#(#function_args_outer),*) #function_return #fn_where_clause; + } + }; + + let item_trait_impl = quote::quote! { + impl #outer_impl_generics #trait_ident #outer_ty_generics for #self_ty #outer_where_clause { + #[target_feature(enable = #attributes)] + #maybe_inline + unsafe fn #function_inner_name #fn_impl_generics (#(#function_args_inner),*) #function_return #fn_where_clause #function_body + } + }; + + quote::quote! { + #[inline(always)] + #(#maybe_outer_attributes)* + #function_visibility fn #function_name #fn_impl_generics (#(#function_args_outer),*) #function_return #fn_where_clause { + #item_trait + #item_trait_impl + unsafe { + ::#function_inner_name #fn_call_generics (#(#function_call_args),*) + } + } + }.into() + } else { + quote::quote! { + #[inline(always)] + #maybe_cfg + #(#maybe_outer_attributes)* + #function_visibility fn #function_name #fn_impl_generics (#(#function_args_outer),*) #function_return #fn_where_clause { + #[target_feature(enable = #attributes)] + #maybe_inline + unsafe fn #function_inner_name #fn_impl_generics (#(#function_args_inner),*) #function_return #fn_where_clause #function_body + unsafe { + #function_inner_name #fn_call_generics (#(#function_call_args),*) + } + } + }.into() + } +} diff --git a/vendor/curve25519-dalek-derive/tests/tests.rs b/vendor/curve25519-dalek-derive/tests/tests.rs new file mode 100644 index 000000000..106a520f3 --- /dev/null +++ b/vendor/curve25519-dalek-derive/tests/tests.rs @@ -0,0 +1,151 @@ +#![allow(dead_code)] +#![allow(unused_imports)] + +use unsafe_target_feature::{unsafe_target_feature, unsafe_target_feature_specialize}; + +#[unsafe_target_feature("sse2")] +/// A doc comment. +fn function(a: u32, b: u32) -> u32 { + a - b +} + +#[unsafe_target_feature("sse2")] +fn function_with_const_arg(b: u32) -> u32 { + N - b +} + +#[unsafe_target_feature("sse2")] +fn function_with_where_clause(a: T, b: T) -> T::Output +where + T: Copy + core::ops::Sub, +{ + a - b +} + +#[unsafe_target_feature("sse2")] +#[cfg(feature = "dummy")] +fn function_with_cfg() {} + +#[unsafe_target_feature("sse2")] +#[rustfmt::skip] +fn function_with_rustfmt_skip() {} + +struct Struct { + a: u32, +} + +#[unsafe_target_feature("sse2")] +impl Struct { + #[allow(unused_mut)] + fn member_function(&self, mut b: u32) -> u32 { + self.a - b + } + + fn member_function_with_const_arg(self) -> u32 { + self.a - N + } + + #[cfg(feature = "dummy")] + fn member_function_with_cfg() {} +} + +struct StructWithGenerics +where + T: Copy + core::ops::Sub, +{ + a: T, +} + +#[unsafe_target_feature("sse2")] +impl StructWithGenerics +where + T: Copy + core::ops::Sub, +{ + #[inline] + fn member_function(&self, b: T) -> T::Output { + self.a - b + } +} + +struct StructWithGenericsNoWhere { + a: T, +} + +#[unsafe_target_feature("sse2")] +impl StructWithGenericsNoWhere { + #[inline(always)] + fn member_function(&self, b: T) -> T::Output { + self.a - b + } +} + +#[unsafe_target_feature("sse2")] +#[allow(dead_code)] +impl<'a> From<&'a Struct> for () { + fn from(_: &'a Struct) -> Self { + () + } +} + +#[unsafe_target_feature("sse2")] +mod inner { + fn inner_function(a: u32, b: u32) -> u32 { + a - b + } +} + +#[unsafe_target_feature_specialize("sse2", "avx2", conditional("avx512ifma", disabled))] +mod inner_spec { + use std; + + #[for_target_feature("sse2")] + const CONST: u32 = 1; + + #[for_target_feature("avx2")] + const CONST: u32 = 2; + + pub fn spec_function(a: u32, b: u32) -> u32 { + a - b - CONST + } + + #[for_target_feature("sse2")] + const IS_AVX2: bool = false; + + #[for_target_feature("avx2")] + const IS_AVX2: bool = true; + + #[test] + fn test_specialized() { + assert!(!IS_AVX2); + } + + #[cfg(test)] + mod tests { + #[test] + fn test_specialized_inner() { + assert!(!super::IS_AVX2); + } + } +} + +#[unsafe_target_feature("sse2")] +#[test] +fn test_sse2_only() {} + +#[unsafe_target_feature("avx2")] +#[test] +fn test_avx2_only() { + compile_error!(); +} + +#[test] +fn test_function() { + assert_eq!(function(10, 3), 7); + assert_eq!(function_with_where_clause(10, 3), 7); + assert_eq!(function_with_const_arg::<10>(3), 7); + assert_eq!(Struct { a: 10 }.member_function(3), 7); + assert_eq!(StructWithGenerics { a: 10 }.member_function(3), 7); + assert_eq!(StructWithGenericsNoWhere { a: 10 }.member_function(3), 7); + assert_eq!(inner_spec_sse2::spec_function(10, 3), 6); + assert_eq!(inner_spec_avx2::spec_function(10, 3), 5); +} From 31511c2f686c398e5c6911b0f086e2bd8317e8c9 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Tue, 13 Jun 2023 00:00:43 +0000 Subject: [PATCH 02/53] Rename vendored unsafe_target_features to curve25519-dalek-derive --- vendor/curve25519-dalek-derive/Cargo.toml | 13 ++++++------- vendor/curve25519-dalek-derive/README.md | 6 +++--- vendor/curve25519-dalek-derive/tests/tests.rs | 2 +- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/vendor/curve25519-dalek-derive/Cargo.toml b/vendor/curve25519-dalek-derive/Cargo.toml index 753de472f..11c875ebf 100644 --- a/vendor/curve25519-dalek-derive/Cargo.toml +++ b/vendor/curve25519-dalek-derive/Cargo.toml @@ -1,15 +1,14 @@ [package] -name = "unsafe_target_feature" -version = "0.1.1" +name = "curve25519-dalek-derive" +version = "0.1.0" edition = "2021" -authors = ["Jan Bujak "] -repository = "https://github.com/koute/unsafe_target_feature" -homepage = "https://github.com/koute/unsafe_target_feature" -documentation = "https://docs.rs/unsafe_target_feature/*/unsafe_target_feature/" +repository = "https://github.com/dalek-cryptography/curve25519-dalek" +homepage = "https://github.com/dalek-cryptography/curve25519-dalek" +documentation = "https://docs.rs/curve25519-dalek-derive" license = "MIT/Apache-2.0" readme = "README.md" -description = "A more convenient #[target_feature] replacement" +description = "curve25519-dalek Derives" [lib] proc-macro = true diff --git a/vendor/curve25519-dalek-derive/README.md b/vendor/curve25519-dalek-derive/README.md index 2b9428690..7f52d440d 100644 --- a/vendor/curve25519-dalek-derive/README.md +++ b/vendor/curve25519-dalek-derive/README.md @@ -92,7 +92,7 @@ unsafe fn func() {} ``` ```rust -use unsafe_target_feature::unsafe_target_feature; +use curve25519_dalek_derive::unsafe_target_feature; // No `unsafe` on the function itself! #[unsafe_target_feature("avx2")] @@ -115,7 +115,7 @@ impl core::ops::Add for S { ``` ```rust -use unsafe_target_feature::unsafe_target_feature; +use curve25519_dalek_derive::unsafe_target_feature; struct S; @@ -133,7 +133,7 @@ impl core::ops::Add for S { ### You can generate specialized copies of a module for each target feature ```rust -use unsafe_target_feature::unsafe_target_feature_specialize; +use curve25519_dalek_derive::unsafe_target_feature_specialize; #[unsafe_target_feature_specialize("sse2", "avx2", conditional("avx512ifma", nightly))] mod simd { diff --git a/vendor/curve25519-dalek-derive/tests/tests.rs b/vendor/curve25519-dalek-derive/tests/tests.rs index 106a520f3..2ccd237e6 100644 --- a/vendor/curve25519-dalek-derive/tests/tests.rs +++ b/vendor/curve25519-dalek-derive/tests/tests.rs @@ -1,7 +1,7 @@ #![allow(dead_code)] #![allow(unused_imports)] -use unsafe_target_feature::{unsafe_target_feature, unsafe_target_feature_specialize}; +use curve25519_dalek_derive::{unsafe_target_feature, unsafe_target_feature_specialize}; #[unsafe_target_feature("sse2")] /// A doc comment. From 4c658622b5a22ff0e438ebb53b239a18a1900a2b Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Tue, 13 Jun 2023 00:05:32 +0000 Subject: [PATCH 03/53] Plumb curve25519_dalek to curve25519_dalek_derive --- Cargo.toml | 14 +++----------- src/backend/vector/avx2/edwards.rs | 2 +- src/backend/vector/avx2/field.rs | 2 +- src/backend/vector/ifma/edwards.rs | 2 +- src/backend/vector/ifma/field.rs | 2 +- src/backend/vector/packed_simd.rs | 2 +- 6 files changed, 8 insertions(+), 16 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 33bbb29a5..bb3f479e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,7 +53,6 @@ digest = { version = "0.10", default-features = false, optional = true } subtle = { version = "2.3.0", default-features = false } serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] } zeroize = { version = "1", default-features = false, optional = true } -unsafe_target_feature = { version = "= 0.1.1", optional = true } [target.'cfg(target_arch = "x86_64")'.dependencies] cpufeatures = "0.2.6" @@ -62,20 +61,13 @@ cpufeatures = "0.2.6" fiat-crypto = "0.1.19" [features] -default = ["alloc", "precomputed-tables", "zeroize", "simd"] +default = ["alloc", "precomputed-tables", "zeroize"] alloc = ["zeroize?/alloc"] precomputed-tables = [] legacy_compatibility = [] -# Whether to allow the use of the AVX2 SIMD backend. -simd_avx2 = ["unsafe_target_feature"] - -# Whether to allow the use of the AVX512 SIMD backend. -# (Note: This requires Rust nightly; on Rust stable this feature will be ignored.) -simd_avx512 = ["unsafe_target_feature"] - -# A meta-feature to allow all SIMD backends to be used. -simd = ["simd_avx2", "simd_avx512"] +[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 = "vendor/curve25519-dalek-derive" } [profile.dev] opt-level = 2 diff --git a/src/backend/vector/avx2/edwards.rs b/src/backend/vector/avx2/edwards.rs index 7bb58b1ee..56d0835bb 100644 --- a/src/backend/vector/avx2/edwards.rs +++ b/src/backend/vector/avx2/edwards.rs @@ -41,7 +41,7 @@ use core::ops::{Add, Neg, Sub}; use subtle::Choice; use subtle::ConditionallySelectable; -use unsafe_target_feature::unsafe_target_feature; +use curve25519_dalek_derive::unsafe_target_feature; use crate::edwards; use crate::window::{LookupTable, NafLookupTable5}; diff --git a/src/backend/vector/avx2/field.rs b/src/backend/vector/avx2/field.rs index bdb55efa5..b593cdc5b 100644 --- a/src/backend/vector/avx2/field.rs +++ b/src/backend/vector/avx2/field.rs @@ -48,7 +48,7 @@ use crate::backend::vector::avx2::constants::{ P_TIMES_16_HI, P_TIMES_16_LO, P_TIMES_2_HI, P_TIMES_2_LO, }; -use unsafe_target_feature::unsafe_target_feature; +use curve25519_dalek_derive::unsafe_target_feature; /// Unpack 32-bit lanes into 64-bit lanes: /// ```ascii,no_run diff --git a/src/backend/vector/ifma/edwards.rs b/src/backend/vector/ifma/edwards.rs index ccfe092c8..f8605fe52 100644 --- a/src/backend/vector/ifma/edwards.rs +++ b/src/backend/vector/ifma/edwards.rs @@ -16,7 +16,7 @@ use core::ops::{Add, Neg, Sub}; use subtle::Choice; use subtle::ConditionallySelectable; -use unsafe_target_feature::unsafe_target_feature; +use curve25519_dalek_derive::unsafe_target_feature; use crate::edwards; use crate::window::{LookupTable, NafLookupTable5}; diff --git a/src/backend/vector/ifma/field.rs b/src/backend/vector/ifma/field.rs index 5928e14a2..fa8ce2dd9 100644 --- a/src/backend/vector/ifma/field.rs +++ b/src/backend/vector/ifma/field.rs @@ -16,7 +16,7 @@ use core::ops::{Add, Mul, Neg}; use crate::backend::serial::u64::field::FieldElement51; -use unsafe_target_feature::unsafe_target_feature; +use curve25519_dalek_derive::unsafe_target_feature; /// A wrapper around `vpmadd52luq` that works on `u64x4`. #[unsafe_target_feature("avx512ifma,avx512vl")] diff --git a/src/backend/vector/packed_simd.rs b/src/backend/vector/packed_simd.rs index 6ab5dcc9c..fe83b1865 100644 --- a/src/backend/vector/packed_simd.rs +++ b/src/backend/vector/packed_simd.rs @@ -11,7 +11,7 @@ //! by the callers of this code. use core::ops::{Add, AddAssign, BitAnd, BitAndAssign, BitXor, BitXorAssign, Sub}; -use unsafe_target_feature::unsafe_target_feature; +use curve25519_dalek_derive::unsafe_target_feature; macro_rules! impl_shared { ( From 6c78bcb38820cfa2e8b09a214c1b27da2df852e9 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Tue, 13 Jun 2023 10:28:00 +0000 Subject: [PATCH 04/53] Adjust CI for simd feature-less --- .github/workflows/rust.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 45aa87b0f..219f589e1 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -66,11 +66,12 @@ jobs: # 1) build all of the x86_64 SIMD code, # 2) run all of the SIMD-specific tests that the test runner supports, # 3) run all of the normal tests using the best available SIMD backend. + # This should automatically pick up the simd backend in a x84_64 runner RUSTFLAGS: '-C target_cpu=native' - run: cargo test --features simd --target x86_64-unknown-linux-gnu + run: cargo test --target x86_64-unknown-linux-gnu test-simd-avx2: - name: Test simd backend (avx2) + name: Test simd backend runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -78,8 +79,10 @@ jobs: - env: # This will run AVX2-specific tests and run all of the normal tests # with the AVX2 backend, even if the runner supports AVX512. + # 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,simd_avx2 --target x86_64-unknown-linux-gnu + run: cargo test --no-default-features --features alloc,precomputed-tables,zeroize --target x86_64-unknown-linux-gnu build-docs: name: Build docs From 96107fcc84e2a61374029ee8288010e34d52a9f3 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Tue, 13 Jun 2023 10:35:13 +0000 Subject: [PATCH 05/53] Remove feature gates from avx2/ifma --- src/backend/vector/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/backend/vector/mod.rs b/src/backend/vector/mod.rs index d720f4acb..2839dca45 100644 --- a/src/backend/vector/mod.rs +++ b/src/backend/vector/mod.rs @@ -14,10 +14,9 @@ #[allow(missing_docs)] pub mod packed_simd; -#[cfg(feature = "simd_avx2")] pub mod avx2; -#[cfg(all(feature = "simd_avx512", nightly))] +#[cfg(nightly)] pub mod ifma; pub mod scalar_mul; From 1aa5038de221c1513cb9f2696431176c03456cd8 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Tue, 13 Jun 2023 11:14:07 +0000 Subject: [PATCH 06/53] De-plub rest of the redundant featuresets --- src/backend/mod.rs | 85 ++++++++++--------- src/backend/vector/scalar_mul/pippenger.rs | 6 +- .../vector/scalar_mul/precomputed_straus.rs | 6 +- src/backend/vector/scalar_mul/straus.rs | 6 +- .../vector/scalar_mul/variable_base.rs | 6 +- .../vector/scalar_mul/vartime_double_base.rs | 6 +- src/lib.rs | 10 +-- 7 files changed, 64 insertions(+), 61 deletions(-) diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 18c8c2251..f7b6891e6 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -41,9 +41,10 @@ pub mod serial; #[cfg(all( target_arch = "x86_64", - any(feature = "simd_avx2", all(feature = "simd_avx512", nightly)), + nightly, curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial") ))] pub mod vector; @@ -51,16 +52,17 @@ pub mod vector; enum BackendKind { #[cfg(all( target_arch = "x86_64", - feature = "simd_avx2", curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial") ))] Avx2, #[cfg(all( target_arch = "x86_64", - all(feature = "simd_avx512", nightly), + nightly, curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial") ))] Avx512, Serial, @@ -70,9 +72,10 @@ enum BackendKind { fn get_selected_backend() -> BackendKind { #[cfg(all( target_arch = "x86_64", - all(feature = "simd_avx512", nightly), + nightly, curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial") ))] { cpufeatures::new!(cpuid_avx512, "avx512ifma", "avx512vl"); @@ -84,9 +87,9 @@ fn get_selected_backend() -> BackendKind { #[cfg(all( target_arch = "x86_64", - feature = "simd_avx2", curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial") ))] { cpufeatures::new!(cpuid_avx2, "avx2"); @@ -110,10 +113,10 @@ where use crate::traits::VartimeMultiscalarMul; match get_selected_backend() { - #[cfg(all(target_arch = "x86_64", feature = "simd_avx2", curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat")))] + #[cfg(all(target_arch = "x86_64", curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat"), not(curve25519_dalek_backend = "serial")))] BackendKind::Avx2 => self::vector::scalar_mul::pippenger::spec_avx2::Pippenger::optional_multiscalar_mul::(scalars, points), - #[cfg(all(target_arch = "x86_64", all(feature = "simd_avx512", nightly), curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat")))] + #[cfg(all(target_arch = "x86_64", nightly, curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat"), not(curve25519_dalek_backend = "serial")))] BackendKind::Avx512 => self::vector::scalar_mul::pippenger::spec_avx512ifma_avx512vl::Pippenger::optional_multiscalar_mul::(scalars, points), BackendKind::Serial => @@ -125,16 +128,17 @@ where pub(crate) enum VartimePrecomputedStraus { #[cfg(all( target_arch = "x86_64", - feature = "simd_avx2", curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial") ))] Avx2(self::vector::scalar_mul::precomputed_straus::spec_avx2::VartimePrecomputedStraus), #[cfg(all( target_arch = "x86_64", - all(feature = "simd_avx512", nightly), + nightly, curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial") ))] Avx512ifma( self::vector::scalar_mul::precomputed_straus::spec_avx512ifma_avx512vl::VartimePrecomputedStraus, @@ -152,10 +156,10 @@ impl VartimePrecomputedStraus { use crate::traits::VartimePrecomputedMultiscalarMul; match get_selected_backend() { - #[cfg(all(target_arch = "x86_64", feature = "simd_avx2", curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat")))] + #[cfg(all(target_arch = "x86_64", curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat"), not(curve25519_dalek_backend = "serial")))] BackendKind::Avx2 => VartimePrecomputedStraus::Avx2(self::vector::scalar_mul::precomputed_straus::spec_avx2::VartimePrecomputedStraus::new(static_points)), - #[cfg(all(target_arch = "x86_64", all(feature = "simd_avx512", nightly), curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat")))] + #[cfg(all(target_arch = "x86_64", nightly, curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat"), not(curve25519_dalek_backend = "serial")))] BackendKind::Avx512 => VartimePrecomputedStraus::Avx512ifma(self::vector::scalar_mul::precomputed_straus::spec_avx512ifma_avx512vl::VartimePrecomputedStraus::new(static_points)), BackendKind::Serial => @@ -181,9 +185,9 @@ impl VartimePrecomputedStraus { match self { #[cfg(all( target_arch = "x86_64", - feature = "simd_avx2", curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial"), ))] VartimePrecomputedStraus::Avx2(inner) => inner.optional_mixed_multiscalar_mul( static_scalars, @@ -192,9 +196,10 @@ impl VartimePrecomputedStraus { ), #[cfg(all( target_arch = "x86_64", - all(feature = "simd_avx512", nightly), + nightly, curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial"), ))] VartimePrecomputedStraus::Avx512ifma(inner) => inner.optional_mixed_multiscalar_mul( static_scalars, @@ -224,9 +229,9 @@ where match get_selected_backend() { #[cfg(all( target_arch = "x86_64", - feature = "simd_avx2", curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial"), ))] BackendKind::Avx2 => { self::vector::scalar_mul::straus::spec_avx2::Straus::multiscalar_mul::( @@ -235,9 +240,10 @@ where } #[cfg(all( target_arch = "x86_64", - all(feature = "simd_avx512", nightly), + nightly, curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial"), ))] BackendKind::Avx512 => { self::vector::scalar_mul::straus::spec_avx512ifma_avx512vl::Straus::multiscalar_mul::< @@ -264,9 +270,9 @@ where match get_selected_backend() { #[cfg(all( target_arch = "x86_64", - feature = "simd_avx2", curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial"), ))] BackendKind::Avx2 => { self::vector::scalar_mul::straus::spec_avx2::Straus::optional_multiscalar_mul::( @@ -275,9 +281,10 @@ where } #[cfg(all( target_arch = "x86_64", - all(feature = "simd_avx512", nightly), + nightly, curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial") ))] BackendKind::Avx512 => { self::vector::scalar_mul::straus::spec_avx512ifma_avx512vl::Straus::optional_multiscalar_mul::< @@ -298,16 +305,17 @@ pub fn variable_base_mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint match get_selected_backend() { #[cfg(all( target_arch = "x86_64", - feature = "simd_avx2", curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial") ))] BackendKind::Avx2 => self::vector::scalar_mul::variable_base::spec_avx2::mul(point, scalar), #[cfg(all( target_arch = "x86_64", - all(feature = "simd_avx512", nightly), + nightly, curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial") ))] BackendKind::Avx512 => { self::vector::scalar_mul::variable_base::spec_avx512ifma_avx512vl::mul(point, scalar) @@ -322,16 +330,17 @@ pub fn vartime_double_base_mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> Edwa match get_selected_backend() { #[cfg(all( target_arch = "x86_64", - feature = "simd_avx2", curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial") ))] BackendKind::Avx2 => self::vector::scalar_mul::vartime_double_base::spec_avx2::mul(a, A, b), #[cfg(all( target_arch = "x86_64", - all(feature = "simd_avx512", nightly), + nightly, curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial") ))] BackendKind::Avx512 => { self::vector::scalar_mul::vartime_double_base::spec_avx512ifma_avx512vl::mul(a, A, b) diff --git a/src/backend/vector/scalar_mul/pippenger.rs b/src/backend/vector/scalar_mul/pippenger.rs index b00cb87c5..099f4f5e7 100644 --- a/src/backend/vector/scalar_mul/pippenger.rs +++ b/src/backend/vector/scalar_mul/pippenger.rs @@ -9,9 +9,9 @@ #![allow(non_snake_case)] -#[unsafe_target_feature::unsafe_target_feature_specialize( - conditional("avx2", feature = "simd_avx2"), - conditional("avx512ifma,avx512vl", all(feature = "simd_avx512", nightly)) +#[curve25519_dalek_derive::unsafe_target_feature_specialize( + "avx2", + conditional("avx512ifma,avx512vl", nightly) )] pub mod spec { diff --git a/src/backend/vector/scalar_mul/precomputed_straus.rs b/src/backend/vector/scalar_mul/precomputed_straus.rs index 8c45c29cf..515b4040c 100644 --- a/src/backend/vector/scalar_mul/precomputed_straus.rs +++ b/src/backend/vector/scalar_mul/precomputed_straus.rs @@ -11,9 +11,9 @@ #![allow(non_snake_case)] -#[unsafe_target_feature::unsafe_target_feature_specialize( - conditional("avx2", feature = "simd_avx2"), - conditional("avx512ifma,avx512vl", all(feature = "simd_avx512", nightly)) +#[curve25519_dalek_derive::unsafe_target_feature_specialize( + "avx2", + conditional("avx512ifma,avx512vl", nightly) )] pub mod spec { diff --git a/src/backend/vector/scalar_mul/straus.rs b/src/backend/vector/scalar_mul/straus.rs index 046bcd14c..097634c19 100644 --- a/src/backend/vector/scalar_mul/straus.rs +++ b/src/backend/vector/scalar_mul/straus.rs @@ -11,9 +11,9 @@ #![allow(non_snake_case)] -#[unsafe_target_feature::unsafe_target_feature_specialize( - conditional("avx2", feature = "simd_avx2"), - conditional("avx512ifma,avx512vl", all(feature = "simd_avx512", nightly)) +#[curve25519_dalek_derive::unsafe_target_feature_specialize( + "avx2", + conditional("avx512ifma,avx512vl", nightly) )] pub mod spec { diff --git a/src/backend/vector/scalar_mul/variable_base.rs b/src/backend/vector/scalar_mul/variable_base.rs index 2da479926..9f924f286 100644 --- a/src/backend/vector/scalar_mul/variable_base.rs +++ b/src/backend/vector/scalar_mul/variable_base.rs @@ -1,8 +1,8 @@ #![allow(non_snake_case)] -#[unsafe_target_feature::unsafe_target_feature_specialize( - conditional("avx2", feature = "simd_avx2"), - conditional("avx512ifma,avx512vl", all(feature = "simd_avx512", nightly)) +#[curve25519_dalek_derive::unsafe_target_feature_specialize( + "avx2", + conditional("avx512ifma,avx512vl", nightly) )] pub mod spec { diff --git a/src/backend/vector/scalar_mul/vartime_double_base.rs b/src/backend/vector/scalar_mul/vartime_double_base.rs index 191572bb1..ea2af8ad4 100644 --- a/src/backend/vector/scalar_mul/vartime_double_base.rs +++ b/src/backend/vector/scalar_mul/vartime_double_base.rs @@ -11,9 +11,9 @@ #![allow(non_snake_case)] -#[unsafe_target_feature::unsafe_target_feature_specialize( - conditional("avx2", feature = "simd_avx2"), - conditional("avx512ifma,avx512vl", all(feature = "simd_avx512", nightly)) +#[curve25519_dalek_derive::unsafe_target_feature_specialize( + "avx2", + conditional("avx512ifma,avx512vl", nightly) )] pub mod spec { diff --git a/src/lib.rs b/src/lib.rs index f4d1d8223..0d8e41bfa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,14 +10,8 @@ // - Henry de Valence #![no_std] -#![cfg_attr( - all(target_arch = "x86_64", feature = "simd_avx512", nightly), - feature(stdsimd) -)] -#![cfg_attr( - all(target_arch = "x86_64", feature = "simd_avx512", nightly), - feature(avx512_target_feature) -)] +#![cfg_attr(all(target_arch = "x86_64", nightly), feature(stdsimd))] +#![cfg_attr(all(target_arch = "x86_64", nightly), feature(avx512_target_feature))] #![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg, doc_cfg_hide))] #![cfg_attr(docsrs, doc(cfg_hide(docsrs)))] #![cfg_attr(allow_unused_unsafe, allow(unused_unsafe))] From 90e92fd3e629d7a1ed72c3a868ab64e414f5d19d Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Tue, 13 Jun 2023 11:23:32 +0000 Subject: [PATCH 07/53] mod vector does not depend on nightly --- src/backend/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/backend/mod.rs b/src/backend/mod.rs index f7b6891e6..11b9cf3f5 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -41,7 +41,6 @@ pub mod serial; #[cfg(all( target_arch = "x86_64", - nightly, curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat"), not(curve25519_dalek_backend = "serial") From 8dd4800af82b38b046ed53abb2b774379f3203ee Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Tue, 13 Jun 2023 11:29:55 +0000 Subject: [PATCH 08/53] Found the missing zeroize feature gate --- src/backend/vector/scalar_mul/straus.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/backend/vector/scalar_mul/straus.rs b/src/backend/vector/scalar_mul/straus.rs index 097634c19..413e6fd9a 100644 --- a/src/backend/vector/scalar_mul/straus.rs +++ b/src/backend/vector/scalar_mul/straus.rs @@ -22,6 +22,7 @@ pub mod spec { use core::borrow::Borrow; use core::cmp::Ordering; + #[cfg(feature = "zeroize")] use zeroize::Zeroizing; #[for_target_feature("avx2")] @@ -67,12 +68,13 @@ pub mod spec { .map(|s| s.borrow().as_radix_16()) .collect(); // Pass ownership to a `Zeroizing` wrapper - let scalar_digits = Zeroizing::new(scalar_digits_vec); + #[cfg(feature = "zeroize")] + let scalar_digits_vec = Zeroizing::new(scalar_digits_vec); let mut Q = ExtendedPoint::identity(); for j in (0..64).rev() { Q = Q.mul_by_pow_2(4); - let it = scalar_digits.iter().zip(lookup_tables.iter()); + let it = scalar_digits_vec.iter().zip(lookup_tables.iter()); for (s_i, lookup_table_i) in it { // Q = Q + s_{i,j} * P_i Q = &Q + &lookup_table_i.select(s_i[j]); From 7b68f1e810a242994446960ab743be16c263f099 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Tue, 13 Jun 2023 12:33:29 +0000 Subject: [PATCH 09/53] Fix cfg relay via build.rs --- build.rs | 26 ++++++++++++++++++++++++++ src/backend/mod.rs | 2 +- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/build.rs b/build.rs index 04f4d9ca3..0ad6b5248 100644 --- a/build.rs +++ b/build.rs @@ -3,6 +3,7 @@ #![deny(clippy::unwrap_used, dead_code)] #[allow(non_camel_case_types)] +#[derive(PartialEq, Debug)] enum DalekBits { Dalek32, Dalek64, @@ -34,6 +35,31 @@ fn main() { // so for those we want to apply the `#[allow(unused_unsafe)]` attribute to get rid of that warning. println!("cargo:rustc-cfg=allow_unused_unsafe"); } + + let target_arch = match std::env::var("CARGO_CFG_TARGET_ARCH") { + Ok(arch) => arch, + _ => "".to_string(), + }; + + // Backend override + let curve25519_dalek_backend = + match std::env::var("CARGO_CFG_CURVE25519_DALEK_BACKEND").as_deref() { + Ok("fiat") => "fiat", + Ok("serial") => "serial", + Ok("simd") => { + // simd override is not guaranteed as: + // simd can only be enabled on x86_64 & 64bit target_pointer_width + if target_arch == "x84_64" && curve25519_dalek_bits == DalekBits::Dalek64 { + "simd" + // fallback to auto + } else { + "auto" + } + } + // default auto + _ => "auto", + }; + println!("cargo:rustc-cfg=curve25519_dalek_backend=\"{curve25519_dalek_backend}\""); } // Deterministic cfg(curve25519_dalek_bits) when this is not explicitly set. diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 11b9cf3f5..0d44dc5d1 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -43,7 +43,7 @@ pub mod serial; target_arch = "x86_64", curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial") + not(curve25519_dalek_backend = "serial"), ))] pub mod vector; From b530a2aae5192cdf2869933c392cb88d78a969e9 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Tue, 13 Jun 2023 12:59:56 +0000 Subject: [PATCH 10/53] Add buildtime compile diagnostics about backend selection --- src/diagnostics.rs | 25 +++++++++++++++++++++++++ src/lib.rs | 4 ++++ 2 files changed, 29 insertions(+) create mode 100644 src/diagnostics.rs diff --git a/src/diagnostics.rs b/src/diagnostics.rs new file mode 100644 index 000000000..ade1af90e --- /dev/null +++ b/src/diagnostics.rs @@ -0,0 +1,25 @@ +//! Build time diagnostics + +// auto is assumed or selected +#[cfg(curve25519_dalek_backend = "auto")] +compile_error!("curve25519_dalek_backend is 'auto'"); + +// fiat was overriden +#[cfg(curve25519_dalek_backend = "fiat")] +compile_error!("curve25519_dalek_backend is 'fiat'"); + +// serial was assumed or overriden +#[cfg(curve25519_dalek_backend = "serial")] +compile_error!("curve25519_dalek_backend is 'serial'"); + +// simd was assumed over overriden +#[cfg(curve25519_dalek_backend = "simd")] +compile_error!("curve25519_dalek_backed is 'simd'"); + +// 32 bits target_pointer_width was assumed or overriden +#[cfg(curve25519_dalek_bits = "32")] +compile_error!("curve25519_dalek_bits is '32'"); + +// 64 bits target_pointer_width was assumed or overriden +#[cfg(curve25519_dalek_bits = "64")] +compile_error!("curve25519_dalek_bits is '64'"); diff --git a/src/lib.rs b/src/lib.rs index 0d8e41bfa..09cb5b191 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -86,3 +86,7 @@ pub(crate) mod window; pub use crate::{ edwards::EdwardsPoint, montgomery::MontgomeryPoint, ristretto::RistrettoPoint, scalar::Scalar, }; + +// Build time diagnostics for validation +#[cfg(curve25519_dalek_diagnostics = "build")] +mod diagnostics; From 6af3d030126450978c46ec66b50109ec7336ccd1 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Tue, 13 Jun 2023 13:10:33 +0000 Subject: [PATCH 11/53] simd override fix --- build.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/build.rs b/build.rs index 0ad6b5248..6d09d109b 100644 --- a/build.rs +++ b/build.rs @@ -49,10 +49,11 @@ fn main() { Ok("simd") => { // simd override is not guaranteed as: // simd can only be enabled on x86_64 & 64bit target_pointer_width - if target_arch == "x84_64" && curve25519_dalek_bits == DalekBits::Dalek64 { + if target_arch == "x86_64" && curve25519_dalek_bits == DalekBits::Dalek64 { "simd" - // fallback to auto + // fallback to auto with a warning } else { + println!("cargo:warning=Could not override curve25519_dalek_backend to simd - defaulting to auto"); "auto" } } From 992324117f285904e8026385443f0667177d9bf6 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Tue, 13 Jun 2023 13:10:48 +0000 Subject: [PATCH 12/53] fmt --- build.rs | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/build.rs b/build.rs index 6d09d109b..58ab10e58 100644 --- a/build.rs +++ b/build.rs @@ -42,24 +42,25 @@ fn main() { }; // Backend override - let curve25519_dalek_backend = - match std::env::var("CARGO_CFG_CURVE25519_DALEK_BACKEND").as_deref() { - Ok("fiat") => "fiat", - Ok("serial") => "serial", - Ok("simd") => { - // simd override is not guaranteed as: - // simd can only be enabled on x86_64 & 64bit target_pointer_width - if target_arch == "x86_64" && curve25519_dalek_bits == DalekBits::Dalek64 { - "simd" - // fallback to auto with a warning - } else { - println!("cargo:warning=Could not override curve25519_dalek_backend to simd - defaulting to auto"); - "auto" - } + let curve25519_dalek_backend = match std::env::var("CARGO_CFG_CURVE25519_DALEK_BACKEND") + .as_deref() + { + Ok("fiat") => "fiat", + Ok("serial") => "serial", + Ok("simd") => { + // simd override is not guaranteed as: + // simd can only be enabled on x86_64 & 64bit target_pointer_width + if target_arch == "x86_64" && curve25519_dalek_bits == DalekBits::Dalek64 { + "simd" + // fallback to auto with a warning + } else { + println!("cargo:warning=Could not override curve25519_dalek_backend to simd - defaulting to auto"); + "auto" } - // default auto - _ => "auto", - }; + } + // default auto + _ => "auto", + }; println!("cargo:rustc-cfg=curve25519_dalek_backend=\"{curve25519_dalek_backend}\""); } From 1933ca9a1dee743efbf7dac009b891e17525ea74 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Tue, 13 Jun 2023 13:26:11 +0000 Subject: [PATCH 13/53] Empty From ead53fb06e5e14edebec4078bee6b6b9b5840167 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Tue, 13 Jun 2023 13:34:11 +0000 Subject: [PATCH 14/53] Fix diagnostics typo --- src/diagnostics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index ade1af90e..d5becef67 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -14,7 +14,7 @@ compile_error!("curve25519_dalek_backend is 'serial'"); // simd was assumed over overriden #[cfg(curve25519_dalek_backend = "simd")] -compile_error!("curve25519_dalek_backed is 'simd'"); +compile_error!("curve25519_dalek_backend is 'simd'"); // 32 bits target_pointer_width was assumed or overriden #[cfg(curve25519_dalek_bits = "32")] From 47adb223b95ddd973e754d6aa5e624a6bab8be09 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Tue, 13 Jun 2023 14:04:00 +0000 Subject: [PATCH 15/53] Move curve25519-dalek-derive to top level --- Cargo.toml | 2 +- .../.gitignore | 0 .../Cargo.toml | 0 .../LICENSE-APACHE | 0 .../LICENSE-MIT | 0 .../README.md | 0 .../src/lib.rs | 0 .../tests/tests.rs | 0 8 files changed, 1 insertion(+), 1 deletion(-) rename {vendor/curve25519-dalek-derive => curve25519-dalek-derive}/.gitignore (100%) rename {vendor/curve25519-dalek-derive => curve25519-dalek-derive}/Cargo.toml (100%) rename {vendor/curve25519-dalek-derive => curve25519-dalek-derive}/LICENSE-APACHE (100%) rename {vendor/curve25519-dalek-derive => curve25519-dalek-derive}/LICENSE-MIT (100%) rename {vendor/curve25519-dalek-derive => curve25519-dalek-derive}/README.md (100%) rename {vendor/curve25519-dalek-derive => curve25519-dalek-derive}/src/lib.rs (100%) rename {vendor/curve25519-dalek-derive => curve25519-dalek-derive}/tests/tests.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index bb3f479e9..72952b9bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,7 +67,7 @@ precomputed-tables = [] legacy_compatibility = [] [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 = "vendor/curve25519-dalek-derive" } +curve25519-dalek-derive = { version = "0.1", path = "curve25519-dalek-derive" } [profile.dev] opt-level = 2 diff --git a/vendor/curve25519-dalek-derive/.gitignore b/curve25519-dalek-derive/.gitignore similarity index 100% rename from vendor/curve25519-dalek-derive/.gitignore rename to curve25519-dalek-derive/.gitignore diff --git a/vendor/curve25519-dalek-derive/Cargo.toml b/curve25519-dalek-derive/Cargo.toml similarity index 100% rename from vendor/curve25519-dalek-derive/Cargo.toml rename to curve25519-dalek-derive/Cargo.toml diff --git a/vendor/curve25519-dalek-derive/LICENSE-APACHE b/curve25519-dalek-derive/LICENSE-APACHE similarity index 100% rename from vendor/curve25519-dalek-derive/LICENSE-APACHE rename to curve25519-dalek-derive/LICENSE-APACHE diff --git a/vendor/curve25519-dalek-derive/LICENSE-MIT b/curve25519-dalek-derive/LICENSE-MIT similarity index 100% rename from vendor/curve25519-dalek-derive/LICENSE-MIT rename to curve25519-dalek-derive/LICENSE-MIT diff --git a/vendor/curve25519-dalek-derive/README.md b/curve25519-dalek-derive/README.md similarity index 100% rename from vendor/curve25519-dalek-derive/README.md rename to curve25519-dalek-derive/README.md diff --git a/vendor/curve25519-dalek-derive/src/lib.rs b/curve25519-dalek-derive/src/lib.rs similarity index 100% rename from vendor/curve25519-dalek-derive/src/lib.rs rename to curve25519-dalek-derive/src/lib.rs diff --git a/vendor/curve25519-dalek-derive/tests/tests.rs b/curve25519-dalek-derive/tests/tests.rs similarity index 100% rename from vendor/curve25519-dalek-derive/tests/tests.rs rename to curve25519-dalek-derive/tests/tests.rs From e367aaa34ad593990f4f9185cba416aa3e2fe608 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Tue, 13 Jun 2023 14:06:31 +0000 Subject: [PATCH 16/53] Remove .gitignore from curve25519-dalek-derive --- curve25519-dalek-derive/.gitignore | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 curve25519-dalek-derive/.gitignore diff --git a/curve25519-dalek-derive/.gitignore b/curve25519-dalek-derive/.gitignore deleted file mode 100644 index 4fffb2f89..000000000 --- a/curve25519-dalek-derive/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target -/Cargo.lock From 1ffbb712ec686c50d4e4371db3a836f7be295d7f Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Tue, 13 Jun 2023 14:10:32 +0000 Subject: [PATCH 17/53] Update .gitignore for subdirs --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 7acc1af24..ca2d72c6d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ +*/target/* target Cargo.lock +*/Cargo.lock *~ \#* From 20b91492af11fd9d3671cbd503552f242cd6fca2 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Tue, 13 Jun 2023 14:18:47 +0000 Subject: [PATCH 18/53] Re-label CI desc for simd --- .github/workflows/rust.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 219f589e1..8c39a113c 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -55,8 +55,8 @@ jobs: - run: cargo build --target thumbv7em-none-eabi --release - run: cargo build --target thumbv7em-none-eabi --release --features serde - test-simd-native: - name: Test simd backend (native) + test-simd-nightly: + name: Test simd backend (nightly) runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -70,8 +70,8 @@ jobs: RUSTFLAGS: '-C target_cpu=native' run: cargo test --target x86_64-unknown-linux-gnu - test-simd-avx2: - name: Test simd backend + test-simd-stable: + name: Test simd backend (stable) runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 From ffdefaf7551f7e2004e2e3a22ce23540604c24bf Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Tue, 13 Jun 2023 14:25:24 +0000 Subject: [PATCH 19/53] Separate fiat from test default and add serial override test --- .github/workflows/rust.yml | 39 +++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 8c39a113c..22c887b06 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -11,7 +11,7 @@ env: RUSTFLAGS: '-D warnings' jobs: - test: + test-auto: runs-on: ubuntu-latest strategy: matrix: @@ -38,10 +38,47 @@ jobs: - run: cargo test --target ${{ matrix.target }} --features digest - run: cargo test --target ${{ matrix.target }} --features rand_core - run: cargo test --target ${{ matrix.target }} --features serde + + test-fiat: + runs-on: ubuntu-latest + strategy: + matrix: + include: + # 32-bit target + - target: i686-unknown-linux-gnu + deps: sudo apt update && sudo apt install gcc-multilib + + # 64-bit target + - target: x86_64-unknown-linux-gnu + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - run: rustup target add ${{ matrix.target }} + - run: ${{ matrix.deps }} - env: RUSTFLAGS: '--cfg curve25519_dalek_backend="fiat"' run: cargo test --target ${{ matrix.target }} + test-serial: + runs-on: ubuntu-latest + strategy: + matrix: + include: + # 32-bit target + - target: i686-unknown-linux-gnu + deps: sudo apt update && sudo apt install gcc-multilib + + # 64-bit target + - target: x86_64-unknown-linux-gnu + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - run: rustup target add ${{ matrix.target }} + - run: ${{ matrix.deps }} + - env: + RUSTFLAGS: '--cfg curve25519_dalek_backend="serial"' + run: cargo test --target ${{ matrix.target }} + build-nostd: name: Build on no_std target (thumbv7em-none-eabi) runs-on: ubuntu-latest From 2b8f0aebb6e62a1b36cf308799ebecaed7446868 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Tue, 13 Jun 2023 15:19:35 +0000 Subject: [PATCH 20/53] Add build script tests --- .github/workflows/rust.yml | 11 ++++++ .gitignore | 2 +- tests/build_tests.sh | 70 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 1 deletion(-) create mode 100755 tests/build_tests.sh diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 22c887b06..77d38581c 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -79,6 +79,17 @@ jobs: RUSTFLAGS: '--cfg curve25519_dalek_backend="serial"' run: cargo test --target ${{ matrix.target }} + build-script: + name: Test Build Script + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: stable + targets: wasm32-unknown-unknown,x86_64-unknown-linux-gnu,i686-unknown-linux-gnu + - run: bash tests/build_tests.sh + build-nostd: name: Build on no_std target (thumbv7em-none-eabi) runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index ca2d72c6d..6eea85527 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ target Cargo.lock */Cargo.lock - +build*.txt *~ \#* .\#* diff --git a/tests/build_tests.sh b/tests/build_tests.sh new file mode 100755 index 000000000..67de75341 --- /dev/null +++ b/tests/build_tests.sh @@ -0,0 +1,70 @@ +#!/bin/bash + +function match_and_report() { + PATTERN=$1 + FILE=$2 + + if grep -q "$PATTERN" "$FILE"; then + echo build OK "$FILE" : "$PATTERN" + else + echo build ERROR "$FILE" : "$PATTERN" + echo ">>>>>>>>>>>>>>>>>>>>>>>>>>" + cat "$FILE" + echo "<<<<<<<<<<<<<<<<<<<<<<<<<<" + exit 1 + fi +} + +# Assuming naively 64 bit host +OUT=build_default.txt +env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\"" cargo build > "$OUT" 2>&1 +match_and_report "curve25519_dalek_backend is 'auto'" "$OUT" +match_and_report "curve25519_dalek_bits is '64'" "$OUT" + +# Override to 32 bits assuming naively 64 bit build host +OUT=build_default_32.txt +env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\" --cfg curve25519_dalek_bits=\"32\"" cargo build > "$OUT" 2>&1 +match_and_report "curve25519_dalek_backend is 'auto'" "$OUT" +match_and_report "curve25519_dalek_bits is '32'" "$OUT" + +# Override to 64 bits on 32 bit target +OUT=build_default_64_on_32.txt +env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\" --cfg curve25519_dalek_bits=\"64\"" cargo build --target i686-unknown-linux-gnu > "$OUT" 2>&1 +match_and_report "curve25519_dalek_backend is 'auto'" "$OUT" +match_and_report "curve25519_dalek_bits is '64'" "$OUT" + +# 32 bit target default +OUT=build_default_32.txt +env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\"" cargo build --target i686-unknown-linux-gnu > "$OUT" 2>&1 +match_and_report "curve25519_dalek_backend is 'auto'" "$OUT" +match_and_report "curve25519_dalek_bits is '32'" "$OUT" + +# wasm 32 bit target default +OUT=build_default_wasm_32.txt +env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\"" cargo build --target wasm32-unknown-unknown > "$OUT" 2>&1 +match_and_report "curve25519_dalek_backend is 'auto'" "$OUT" +match_and_report "curve25519_dalek_bits is '32'" "$OUT" + +# fiat override with default 64 bit naive host assumption +OUT=build_fiat_64.txt +env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\" --cfg curve25519_dalek_backend=\"fiat\"" cargo build > "$OUT" 2>&1 +match_and_report "curve25519_dalek_backend is 'fiat'" "$OUT" +match_and_report "curve25519_dalek_bits is '64'" "$OUT" + +# fiat 32 bit override +OUT=build_fiat_32.txt +env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\" --cfg curve25519_dalek_backend=\"fiat\" --cfg curve25519_dalek_bits=\"32\"" cargo build > "$OUT" 2>&1 +match_and_report "curve25519_dalek_backend is 'fiat'" "$OUT" +match_and_report "curve25519_dalek_bits is '32'" "$OUT" + +# serial override with default 64 bit naive host assumption +OUT=build_serial_64.txt +env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\" --cfg curve25519_dalek_backend=\"serial\"" cargo build > "$OUT" 2>&1 +match_and_report "curve25519_dalek_backend is 'serial'" "$OUT" +match_and_report "curve25519_dalek_bits is '64'" "$OUT" + +# serial 32 bit override +OUT=build_serial_32.txt +env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\" --cfg curve25519_dalek_backend=\"serial\" --cfg curve25519_dalek_bits=\"32\"" cargo build > "$OUT" 2>&1 +match_and_report "curve25519_dalek_backend is 'serial'" "$OUT" +match_and_report "curve25519_dalek_bits is '32'" "$OUT" From 175bc67ee0b8500b8391b67b0ff80c13af4dab6c Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Tue, 13 Jun 2023 15:25:09 +0000 Subject: [PATCH 21/53] Documentation changes --- README.md | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 12100691d..ed9e2ebf3 100644 --- a/README.md +++ b/README.md @@ -53,9 +53,6 @@ curve25519-dalek = "4.0.0-rc.2" | `alloc` | ✓ | Enables Edwards and Ristretto multiscalar multiplication, batch scalar inversion, and batch Ristretto double-and-compress. Also enables `zeroize`. | | `zeroize` | ✓ | Enables [`Zeroize`][zeroize-trait] for all scalar and curve point types. | | `precomputed-tables` | ✓ | Includes precomputed basepoint multiplication tables. This speeds up `EdwardsPoint::mul_base` and `RistrettoPoint::mul_base` by ~4x, at the cost of ~30KB added to the code size. | -| `simd_avx2` | ✓ | Allows the AVX2 SIMD backend to be used, if available. | -| `simd_avx512` | ✓ | Allows the AVX512 SIMD backend to be used, if available. | -| `simd` | ✓ | Allows every SIMD backend to be used, if available. | | `rand_core` | | Enables `Scalar::random` and `RistrettoPoint::random`. This is an optional dependency whose version is not subject to SemVer. See [below](#public-api-semver-exemptions) for more details. | | `digest` | | Enables `RistrettoPoint::{from_hash, hash_from_bytes}` and `Scalar::{from_hash, hash_from_bytes}`. This is an optional dependency whose version is not subject to SemVer. See [below](#public-api-semver-exemptions) for more details. | | `serde` | | Enables `serde` serialization/deserialization for all the point and scalar types. | @@ -98,17 +95,18 @@ See tracking issue: [curve25519-dalek/issues/521](https://github.com/dalek-crypt Curve arithmetic is implemented and used by selecting one of the following backends: -| Backend | Implementation | Target backends | -| :--- | :--- | :--- | -| `[default]` | Automatic runtime backend selection (either serial or SIMD) | `u32`
`u64`
`avx2`
`avx512` | -| `fiat` | Formally verified field arithmetic from [fiat-crypto] | `fiat_u32`
`fiat_u64` | +| Backend | Selection | Implementation | Target backends | +| :--- | :--- | :--- | :--- | +| `serial` | Automatic | serial software | `u32`
`u64` | +| `fiat` | Manual | Formally verified field arithmetic from [fiat-crypto] | `fiat_u32`
`fiat_u64` | +| `simd` | Automatic | Intel AVX2 / AVX512 IFMA accelerated backend | `avx2`
`avx512` | -To choose a backend other than the `[default]` backend, set the +To override a backend other than the automaticlaly selected backend, set the environment variable: ```sh RUSTFLAGS='--cfg curve25519_dalek_backend="BACKEND"' ``` -where `BACKEND` is `fiat`. Equivalently, you can write to +Equivalently, you can write to `~/.cargo/config`: ```toml [build] From b4114cc2b2ecae337c0dcfa963619d46643fdf9b Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Tue, 13 Jun 2023 15:28:27 +0000 Subject: [PATCH 22/53] Fix build test --- tests/build_tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/build_tests.sh b/tests/build_tests.sh index 67de75341..f49af5c4f 100755 --- a/tests/build_tests.sh +++ b/tests/build_tests.sh @@ -34,7 +34,7 @@ match_and_report "curve25519_dalek_backend is 'auto'" "$OUT" match_and_report "curve25519_dalek_bits is '64'" "$OUT" # 32 bit target default -OUT=build_default_32.txt +OUT=build_default_32_on_32.txt env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\"" cargo build --target i686-unknown-linux-gnu > "$OUT" 2>&1 match_and_report "curve25519_dalek_backend is 'auto'" "$OUT" match_and_report "curve25519_dalek_bits is '32'" "$OUT" From 07d07559fb7eee8a2d06355869b387637399ef4c Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Tue, 13 Jun 2023 15:33:55 +0000 Subject: [PATCH 23/53] Ensure no incremental compilation for build script tests --- tests/build_tests.sh | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/tests/build_tests.sh b/tests/build_tests.sh index f49af5c4f..4bca6ecd7 100755 --- a/tests/build_tests.sh +++ b/tests/build_tests.sh @@ -16,55 +16,64 @@ function match_and_report() { } # Assuming naively 64 bit host -OUT=build_default.txt +cargo clean +OUT=build_1.txt env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\"" cargo build > "$OUT" 2>&1 match_and_report "curve25519_dalek_backend is 'auto'" "$OUT" match_and_report "curve25519_dalek_bits is '64'" "$OUT" # Override to 32 bits assuming naively 64 bit build host -OUT=build_default_32.txt +cargo clean +OUT=build_2.txt env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\" --cfg curve25519_dalek_bits=\"32\"" cargo build > "$OUT" 2>&1 match_and_report "curve25519_dalek_backend is 'auto'" "$OUT" match_and_report "curve25519_dalek_bits is '32'" "$OUT" # Override to 64 bits on 32 bit target -OUT=build_default_64_on_32.txt +cargo clean +OUT=build_3.txt env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\" --cfg curve25519_dalek_bits=\"64\"" cargo build --target i686-unknown-linux-gnu > "$OUT" 2>&1 match_and_report "curve25519_dalek_backend is 'auto'" "$OUT" match_and_report "curve25519_dalek_bits is '64'" "$OUT" # 32 bit target default -OUT=build_default_32_on_32.txt +cargo clean +OUT=build_4.txt env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\"" cargo build --target i686-unknown-linux-gnu > "$OUT" 2>&1 match_and_report "curve25519_dalek_backend is 'auto'" "$OUT" match_and_report "curve25519_dalek_bits is '32'" "$OUT" # wasm 32 bit target default -OUT=build_default_wasm_32.txt +cargo clean +OUT=build_5.txt env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\"" cargo build --target wasm32-unknown-unknown > "$OUT" 2>&1 match_and_report "curve25519_dalek_backend is 'auto'" "$OUT" match_and_report "curve25519_dalek_bits is '32'" "$OUT" # fiat override with default 64 bit naive host assumption -OUT=build_fiat_64.txt +cargo clean +OUT=build_6.txt env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\" --cfg curve25519_dalek_backend=\"fiat\"" cargo build > "$OUT" 2>&1 match_and_report "curve25519_dalek_backend is 'fiat'" "$OUT" match_and_report "curve25519_dalek_bits is '64'" "$OUT" # fiat 32 bit override -OUT=build_fiat_32.txt +cargo clean +OUT=build_7.txt env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\" --cfg curve25519_dalek_backend=\"fiat\" --cfg curve25519_dalek_bits=\"32\"" cargo build > "$OUT" 2>&1 match_and_report "curve25519_dalek_backend is 'fiat'" "$OUT" match_and_report "curve25519_dalek_bits is '32'" "$OUT" # serial override with default 64 bit naive host assumption -OUT=build_serial_64.txt +cargo clean +OUT=build_8.txt env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\" --cfg curve25519_dalek_backend=\"serial\"" cargo build > "$OUT" 2>&1 match_and_report "curve25519_dalek_backend is 'serial'" "$OUT" match_and_report "curve25519_dalek_bits is '64'" "$OUT" # serial 32 bit override -OUT=build_serial_32.txt +cargo clean +OUT=build_9.txt env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\" --cfg curve25519_dalek_backend=\"serial\" --cfg curve25519_dalek_bits=\"32\"" cargo build > "$OUT" 2>&1 match_and_report "curve25519_dalek_backend is 'serial'" "$OUT" match_and_report "curve25519_dalek_bits is '32'" "$OUT" From a3d3c65f9c4c04f2984a64351a6f10aff9cd8028 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Tue, 13 Jun 2023 15:38:02 +0000 Subject: [PATCH 24/53] Remove redundant LICENSE from derive crate --- curve25519-dalek-derive/LICENSE-APACHE | 201 ------------------------- curve25519-dalek-derive/LICENSE-MIT | 23 --- 2 files changed, 224 deletions(-) delete mode 100644 curve25519-dalek-derive/LICENSE-APACHE delete mode 100644 curve25519-dalek-derive/LICENSE-MIT diff --git a/curve25519-dalek-derive/LICENSE-APACHE b/curve25519-dalek-derive/LICENSE-APACHE deleted file mode 100644 index 16fe87b06..000000000 --- a/curve25519-dalek-derive/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - 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 deleted file mode 100644 index 31aa79387..000000000 --- a/curve25519-dalek-derive/LICENSE-MIT +++ /dev/null @@ -1,23 +0,0 @@ -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. From eeb4b6c5cb9de836f0de19017c2a47a4bda2548b Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Fri, 16 Jun 2023 13:37:46 +0000 Subject: [PATCH 25/53] Clean up backend selection doc further --- README.md | 57 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index ed9e2ebf3..a8d51d877 100644 --- a/README.md +++ b/README.md @@ -87,22 +87,30 @@ latest breaking changes in high level are below: This release also does a lot of dependency updates and relaxations to unblock upstream build issues. -### 4.0.0 - Open Breaking Changes +# Backends -See tracking issue: [curve25519-dalek/issues/521](https://github.com/dalek-cryptography/curve25519-dalek/issues/521) +Curve arithmetic is implemented and used by one of the following backends: -# Backends +| Backend | Selection | Implementation | Bits / Word sizes | +| :--- | :--- | :--- | :--- | +| `serial` | Automatic | serial software | `32`
`64` | +| `fiat` | Manual | Formally verified field arithmetic from [fiat-crypto] | `32`
`64` | +| `simd` | Automatic | Intel AVX2 / AVX512 IFMA accelerated backend | `64` only | -Curve arithmetic is implemented and used by selecting one of the following backends: +## Automatic Backend Selection -| Backend | Selection | Implementation | Target backends | -| :--- | :--- | :--- | :--- | -| `serial` | Automatic | serial software | `u32`
`u64` | -| `fiat` | Manual | Formally verified field arithmetic from [fiat-crypto] | `fiat_u32`
`fiat_u64` | -| `simd` | Automatic | Intel AVX2 / AVX512 IFMA accelerated backend | `avx2`
`avx512` | +Currently on the intel `x86_64` platforms with `64` bit word size, the backend +selection is automatic between the `simd` and `serial` backends where `simd` is +selected if the AVX instruction set is detected available on the target CPU. -To override a backend other than the automaticlaly selected backend, set the -environment variable: +The `simd` may also require nightly compiler for AVX512 - see [SIMD backend](#SIMD backend). + +In the future `simd` backend may be extended to cover more instruction sets and +this change will be non-breaking since this is considered implementation detail. + +## Manual Backend Override + +The backend can be potentially overriden by setting an environment variable: ```sh RUSTFLAGS='--cfg curve25519_dalek_backend="BACKEND"' ``` @@ -115,26 +123,31 @@ rustflags = ['--cfg=curve25519_dalek_backend="BACKEND"'] More info [here](https://doc.rust-lang.org/cargo/reference/config.html#buildrustflags). Note for contributors: The target backends are not entirely independent of each -other. The SIMD backend directly depends on parts of the the `u64` backend to +other. The [SIMD backend](#SIMD backend) directly depends on parts of the the `u64` backend to function. -## Word size for serial backends +## Bits / Word size + +`curve25519-dalek` will automatically choose the word size for the `fiat` and +`serial` backends, based on the build target. + +For example, building for a 64-bit machine, the default `u64` target backend is +automatically chosen when the `serial` backend is selected, and `fiat_u64` is +chosen when the `fiat backend is selected. -`curve25519-dalek` will automatically choose the word size for the `[default]` -and `fiat` serial backends, based on the build target. For example, building -for a 64-bit machine, the default `u64` target backend is automatically chosen -when the `[default]` backend is selected, and `fiat_u64` is chosen when the -`fiat backend is selected. +In some targets it might be required to override the word size for better +performance. -Backend word size can be overridden for `[default]` and `fiat` by setting the +Backend word size can be overridden for `serial` and `fiat` by setting the environment variable: ```sh RUSTFLAGS='--cfg curve25519_dalek_bits="SIZE"' ``` -where `SIZE` is `32` or `64`. As in the above section, this can also be placed +`SIZE` is `32` or `64`. As in the above section, this can also be placed in `~/.cargo/config`. -**NOTE:** Using a word size of 32 will automatically disable SIMD support. +**NOTE:** Using a word size of 32 will automatically prevent SIMD auto-detection +and support as this backend requires the 64 bit word size. ### Cross-compilation @@ -147,7 +160,7 @@ $ rustup target add i686-unknown-linux-gnu $ cargo build --target i686-unknown-linux-gnu ``` -## SIMD target backends +## SIMD backend The SIMD target backend selection is done automatically at runtime depending on the available CPU features, provided the appropriate feature flag is enabled. From ee82d44050553da3cee8d61e0d051b47c43d4b7f Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Fri, 16 Jun 2023 13:38:34 +0000 Subject: [PATCH 26/53] Better table column format --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a8d51d877..d686f71c3 100644 --- a/README.md +++ b/README.md @@ -93,8 +93,8 @@ Curve arithmetic is implemented and used by one of the following backends: | Backend | Selection | Implementation | Bits / Word sizes | | :--- | :--- | :--- | :--- | -| `serial` | Automatic | serial software | `32`
`64` | -| `fiat` | Manual | Formally verified field arithmetic from [fiat-crypto] | `32`
`64` | +| `serial` | Automatic | serial software | `32` and `64` | +| `fiat` | Manual | Formally verified field arithmetic from [fiat-crypto] | `32` and `64` | | `simd` | Automatic | Intel AVX2 / AVX512 IFMA accelerated backend | `64` only | ## Automatic Backend Selection From 1275f26a844454ab0c0f4de4c94450ad6003cdce Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Fri, 16 Jun 2023 13:41:47 +0000 Subject: [PATCH 27/53] Wording fix --- README.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index d686f71c3..254737702 100644 --- a/README.md +++ b/README.md @@ -100,13 +100,15 @@ Curve arithmetic is implemented and used by one of the following backends: ## Automatic Backend Selection Currently on the intel `x86_64` platforms with `64` bit word size, the backend -selection is automatic between the `simd` and `serial` backends where `simd` is -selected if the AVX instruction set is detected available on the target CPU. +selection is automatic between the `simd` and `serial` backends. -The `simd` may also require nightly compiler for AVX512 - see [SIMD backend](#SIMD backend). +The `simd` backend may be automatically selected if the AVX instruction set is +detected available on the target CPU. + +The `simd` may also require nightly compiler for AVX512 - see [SIMD backend]. In the future `simd` backend may be extended to cover more instruction sets and -this change will be non-breaking since this is considered implementation detail. +this change will be non-breaking as this is considered as implementation detail. ## Manual Backend Override @@ -123,7 +125,7 @@ rustflags = ['--cfg=curve25519_dalek_backend="BACKEND"'] More info [here](https://doc.rust-lang.org/cargo/reference/config.html#buildrustflags). Note for contributors: The target backends are not entirely independent of each -other. The [SIMD backend](#SIMD backend) directly depends on parts of the the `u64` backend to +other. The [SIMD backend] directly depends on parts of the the `u64` backend to function. ## Bits / Word size @@ -337,3 +339,4 @@ contributions. [semver]: https://semver.org/spec/v2.0.0.html [rngcorestd]: https://github.com/rust-random/rand/tree/7aa25d577e2df84a5156f824077bb7f6bdf28d97/rand_core#crate-features [zeroize-trait]: https://docs.rs/zeroize/latest/zeroize/trait.Zeroize.html +[SIMD backend]: #SIMD backend From 4c9ef40559431db051e906b66c348ca5af38ec91 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Fri, 16 Jun 2023 13:47:09 +0000 Subject: [PATCH 28/53] Relative and wording fix --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 254737702..45f78be62 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,9 @@ selection is automatic between the `simd` and `serial` backends. The `simd` backend may be automatically selected if the AVX instruction set is detected available on the target CPU. +The automatic selection between `serial` and `simd` does not happen on any other +platform currently and will default to `serial` software implementation. + The `simd` may also require nightly compiler for AVX512 - see [SIMD backend]. In the future `simd` backend may be extended to cover more instruction sets and @@ -339,4 +342,4 @@ contributions. [semver]: https://semver.org/spec/v2.0.0.html [rngcorestd]: https://github.com/rust-random/rand/tree/7aa25d577e2df84a5156f824077bb7f6bdf28d97/rand_core#crate-features [zeroize-trait]: https://docs.rs/zeroize/latest/zeroize/trait.Zeroize.html -[SIMD backend]: #SIMD backend +[SIMD backend]: README.md#SIMD backend From cf013ec08624cc20129abaa16950758c46307fb6 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Fri, 16 Jun 2023 13:50:07 +0000 Subject: [PATCH 29/53] Relative links are mess --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 45f78be62..273883e09 100644 --- a/README.md +++ b/README.md @@ -342,4 +342,4 @@ contributions. [semver]: https://semver.org/spec/v2.0.0.html [rngcorestd]: https://github.com/rust-random/rand/tree/7aa25d577e2df84a5156f824077bb7f6bdf28d97/rand_core#crate-features [zeroize-trait]: https://docs.rs/zeroize/latest/zeroize/trait.Zeroize.html -[SIMD backend]: README.md#SIMD backend +[SIMD backend]: #-simd-backend From 1c34768439810892a94dd595311e9f9cebb9b5ca Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Fri, 16 Jun 2023 13:50:46 +0000 Subject: [PATCH 30/53] Relative link mess --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 273883e09..e859f9b9e 100644 --- a/README.md +++ b/README.md @@ -342,4 +342,4 @@ contributions. [semver]: https://semver.org/spec/v2.0.0.html [rngcorestd]: https://github.com/rust-random/rand/tree/7aa25d577e2df84a5156f824077bb7f6bdf28d97/rand_core#crate-features [zeroize-trait]: https://docs.rs/zeroize/latest/zeroize/trait.Zeroize.html -[SIMD backend]: #-simd-backend +[SIMD backend]: #simd-backend From cf9ba9ea40fac94529636838e4ed332da2e30493 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Fri, 16 Jun 2023 13:53:17 +0000 Subject: [PATCH 31/53] Vector needs to be included for docsrs --- src/backend/mod.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 0d44dc5d1..18d1064f4 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -39,11 +39,14 @@ use crate::Scalar; pub mod serial; -#[cfg(all( - target_arch = "x86_64", - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial"), +#[cfg(any( + docsrs, + all( + target_arch = "x86_64", + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial"), + ) ))] pub mod vector; From 731ff483664420c29a12101df9dec0fcd357bfd9 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Fri, 16 Jun 2023 13:54:35 +0000 Subject: [PATCH 32/53] docsrs is assumed AVX2 capable so this is not needed. Revert "Vector needs to be included for docsrs" This reverts commit cf9ba9ea40fac94529636838e4ed332da2e30493. --- src/backend/mod.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 18d1064f4..0d44dc5d1 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -39,14 +39,11 @@ use crate::Scalar; pub mod serial; -#[cfg(any( - docsrs, - all( - target_arch = "x86_64", - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial"), - ) +#[cfg(all( + target_arch = "x86_64", + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial"), ))] pub mod vector; From c2f219c7645b412b74015a69b7b7ff4bf77f0118 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Fri, 16 Jun 2023 14:01:58 +0000 Subject: [PATCH 33/53] Reduce confusing implementation detail from pub doc --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e859f9b9e..486047fcb 100644 --- a/README.md +++ b/README.md @@ -128,7 +128,7 @@ rustflags = ['--cfg=curve25519_dalek_backend="BACKEND"'] More info [here](https://doc.rust-lang.org/cargo/reference/config.html#buildrustflags). Note for contributors: The target backends are not entirely independent of each -other. The [SIMD backend] directly depends on parts of the the `u64` backend to +other. The [SIMD backend] directly depends on parts of the serial backend to function. ## Bits / Word size @@ -136,9 +136,8 @@ function. `curve25519-dalek` will automatically choose the word size for the `fiat` and `serial` backends, based on the build target. -For example, building for a 64-bit machine, the default `u64` target backend is -automatically chosen when the `serial` backend is selected, and `fiat_u64` is -chosen when the `fiat backend is selected. +For example, building for a 64-bit machine, the default 64 bit word size is +automatically chosen when either the `serial` or `fiat` backend is selected. In some targets it might be required to override the word size for better performance. From 4fe1079f0ec940af8cde92cc090fa22c9b8c9cd1 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Fri, 16 Jun 2023 14:03:00 +0000 Subject: [PATCH 34/53] Target not platform --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 486047fcb..7c53f9481 100644 --- a/README.md +++ b/README.md @@ -99,7 +99,7 @@ Curve arithmetic is implemented and used by one of the following backends: ## Automatic Backend Selection -Currently on the intel `x86_64` platforms with `64` bit word size, the backend +Currently on the intel `x86_64` targets with `64` bit word size, the backend selection is automatic between the `simd` and `serial` backends. The `simd` backend may be automatically selected if the AVX instruction set is From 35b3cef4ddac381c54b5585a4ce9c174e4a34a7f Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Fri, 16 Jun 2023 14:10:37 +0000 Subject: [PATCH 35/53] Reduce gates in enum and allow dead_code in it --- src/backend/mod.rs | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 0d44dc5d1..8fae8fe01 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -49,20 +49,9 @@ pub mod vector; #[derive(Copy, Clone)] enum BackendKind { - #[cfg(all( - target_arch = "x86_64", - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial") - ))] + #[allow(dead_code)] Avx2, - #[cfg(all( - target_arch = "x86_64", - nightly, - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial") - ))] + #[allow(dead_code)] Avx512, Serial, } From 95dfca05658e2720513ba0738444ea47f3cc71a2 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Fri, 16 Jun 2023 14:12:45 +0000 Subject: [PATCH 36/53] The enum needs to be gated for now. Revert "Reduce gates in enum and allow dead_code in it" This reverts commit 35b3cef4ddac381c54b5585a4ce9c174e4a34a7f. --- src/backend/mod.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 8fae8fe01..0d44dc5d1 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -49,9 +49,20 @@ pub mod vector; #[derive(Copy, Clone)] enum BackendKind { - #[allow(dead_code)] + #[cfg(all( + target_arch = "x86_64", + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial") + ))] Avx2, - #[allow(dead_code)] + #[cfg(all( + target_arch = "x86_64", + nightly, + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial") + ))] Avx512, Serial, } From dc507b794b7d115ea47de43912404c19f90525bb Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Fri, 16 Jun 2023 16:14:46 +0000 Subject: [PATCH 37/53] Default backend is serial not auto --- build.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build.rs b/build.rs index 58ab10e58..70182073e 100644 --- a/build.rs +++ b/build.rs @@ -54,12 +54,12 @@ fn main() { "simd" // fallback to auto with a warning } else { - println!("cargo:warning=Could not override curve25519_dalek_backend to simd - defaulting to auto"); - "auto" + println!("cargo:warning=Could not override curve25519_dalek_backend to simd - defaulting to serial"); + "serial" } } - // default auto - _ => "auto", + // default serial + _ => "serial", }; println!("cargo:rustc-cfg=curve25519_dalek_backend=\"{curve25519_dalek_backend}\""); } From 0bc5de2170933b7aaf0315f993f6c3d7550a7cc5 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Fri, 16 Jun 2023 16:20:50 +0000 Subject: [PATCH 38/53] Adjust build script tests to serial not auto default --- build.rs | 2 +- tests/build_tests.sh | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build.rs b/build.rs index 70182073e..57295f044 100644 --- a/build.rs +++ b/build.rs @@ -52,7 +52,7 @@ fn main() { // simd can only be enabled on x86_64 & 64bit target_pointer_width if target_arch == "x86_64" && curve25519_dalek_bits == DalekBits::Dalek64 { "simd" - // fallback to auto with a warning + // fallback to serial with a warning } else { println!("cargo:warning=Could not override curve25519_dalek_backend to simd - defaulting to serial"); "serial" diff --git a/tests/build_tests.sh b/tests/build_tests.sh index 4bca6ecd7..0380915f0 100755 --- a/tests/build_tests.sh +++ b/tests/build_tests.sh @@ -19,35 +19,35 @@ function match_and_report() { cargo clean OUT=build_1.txt env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\"" cargo build > "$OUT" 2>&1 -match_and_report "curve25519_dalek_backend is 'auto'" "$OUT" +match_and_report "curve25519_dalek_backend is 'serial'" "$OUT" match_and_report "curve25519_dalek_bits is '64'" "$OUT" # Override to 32 bits assuming naively 64 bit build host cargo clean OUT=build_2.txt env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\" --cfg curve25519_dalek_bits=\"32\"" cargo build > "$OUT" 2>&1 -match_and_report "curve25519_dalek_backend is 'auto'" "$OUT" +match_and_report "curve25519_dalek_backend is 'serial'" "$OUT" match_and_report "curve25519_dalek_bits is '32'" "$OUT" # Override to 64 bits on 32 bit target cargo clean OUT=build_3.txt env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\" --cfg curve25519_dalek_bits=\"64\"" cargo build --target i686-unknown-linux-gnu > "$OUT" 2>&1 -match_and_report "curve25519_dalek_backend is 'auto'" "$OUT" +match_and_report "curve25519_dalek_backend is 'serial'" "$OUT" match_and_report "curve25519_dalek_bits is '64'" "$OUT" # 32 bit target default cargo clean OUT=build_4.txt env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\"" cargo build --target i686-unknown-linux-gnu > "$OUT" 2>&1 -match_and_report "curve25519_dalek_backend is 'auto'" "$OUT" +match_and_report "curve25519_dalek_backend is 'serial'" "$OUT" match_and_report "curve25519_dalek_bits is '32'" "$OUT" # wasm 32 bit target default cargo clean OUT=build_5.txt env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\"" cargo build --target wasm32-unknown-unknown > "$OUT" 2>&1 -match_and_report "curve25519_dalek_backend is 'auto'" "$OUT" +match_and_report "curve25519_dalek_backend is 'serial'" "$OUT" match_and_report "curve25519_dalek_bits is '32'" "$OUT" # fiat override with default 64 bit naive host assumption From b11fa4d3f7d1ed476df82f059b2cf77fe5ea9cae Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Sat, 17 Jun 2023 06:54:29 +0000 Subject: [PATCH 39/53] Fix simd default on backend --- build.rs | 14 +++++++++++--- tests/build_tests.sh | 2 +- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/build.rs b/build.rs index 57295f044..d9e3e758c 100644 --- a/build.rs +++ b/build.rs @@ -50,7 +50,7 @@ fn main() { Ok("simd") => { // simd override is not guaranteed as: // simd can only be enabled on x86_64 & 64bit target_pointer_width - if target_arch == "x86_64" && curve25519_dalek_bits == DalekBits::Dalek64 { + if is_capable_simd(&target_arch, curve25519_dalek_bits) { "simd" // fallback to serial with a warning } else { @@ -58,12 +58,20 @@ fn main() { "serial" } } - // default serial - _ => "serial", + // default between serial / simd (if potentially capable) + _ => match is_capable_simd(&target_arch, curve25519_dalek_bits) { + true => "simd", + false => "serial", + }, }; println!("cargo:rustc-cfg=curve25519_dalek_backend=\"{curve25519_dalek_backend}\""); } +// Is the target arch & curve25519_dalek_bits potentially simd capable ? +fn is_capable_simd(arch: &str, bits: DalekBits) -> bool { + arch == "x86_64" && bits == DalekBits::Dalek64 +} + // Deterministic cfg(curve25519_dalek_bits) when this is not explicitly set. mod deterministic { diff --git a/tests/build_tests.sh b/tests/build_tests.sh index 0380915f0..3c5616ca9 100755 --- a/tests/build_tests.sh +++ b/tests/build_tests.sh @@ -19,7 +19,7 @@ function match_and_report() { cargo clean OUT=build_1.txt env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\"" cargo build > "$OUT" 2>&1 -match_and_report "curve25519_dalek_backend is 'serial'" "$OUT" +match_and_report "curve25519_dalek_backend is 'simd'" "$OUT" match_and_report "curve25519_dalek_bits is '64'" "$OUT" # Override to 32 bits assuming naively 64 bit build host From f41ab86da454d6dfa3946771011f441e0f2e9a93 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Sat, 17 Jun 2023 07:00:19 +0000 Subject: [PATCH 40/53] Fix wording about instruction sets --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7c53f9481..7e4d319dc 100644 --- a/README.md +++ b/README.md @@ -102,14 +102,12 @@ Curve arithmetic is implemented and used by one of the following backends: Currently on the intel `x86_64` targets with `64` bit word size, the backend selection is automatic between the `simd` and `serial` backends. -The `simd` backend may be automatically selected if the AVX instruction set is -detected available on the target CPU. +The `simd` backend is automatically selected if the needed instruction set is +detected available on the target CPU - see more from [SIMD backend]. The automatic selection between `serial` and `simd` does not happen on any other platform currently and will default to `serial` software implementation. -The `simd` may also require nightly compiler for AVX512 - see [SIMD backend]. - In the future `simd` backend may be extended to cover more instruction sets and this change will be non-breaking as this is considered as implementation detail. From edeb5c273e0a85010956373c4af1c83974782b5a Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Sat, 17 Jun 2023 07:07:40 +0000 Subject: [PATCH 41/53] Disable simd related features unless simd was determined via build --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 09cb5b191..df16087dd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,8 +10,8 @@ // - Henry de Valence #![no_std] -#![cfg_attr(all(target_arch = "x86_64", nightly), feature(stdsimd))] -#![cfg_attr(all(target_arch = "x86_64", nightly), feature(avx512_target_feature))] +#![cfg_attr(all(curve25519_dalek_backend = "simd", target_arch = "x86_64", nightly), feature(stdsimd))] +#![cfg_attr(all(curve25519_dalek_backend = "simd", target_arch = "x86_64", nightly), feature(avx512_target_feature))] #![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg, doc_cfg_hide))] #![cfg_attr(docsrs, doc(cfg_hide(docsrs)))] #![cfg_attr(allow_unused_unsafe, allow(unused_unsafe))] From 840f8e59806bf1f796e7b6efeb5450aa906079df Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Sat, 17 Jun 2023 07:09:18 +0000 Subject: [PATCH 42/53] Play the fmt game --- src/lib.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index df16087dd..0a0638fbb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,8 +10,14 @@ // - Henry de Valence #![no_std] -#![cfg_attr(all(curve25519_dalek_backend = "simd", target_arch = "x86_64", nightly), feature(stdsimd))] -#![cfg_attr(all(curve25519_dalek_backend = "simd", target_arch = "x86_64", nightly), feature(avx512_target_feature))] +#![cfg_attr( + all(curve25519_dalek_backend = "simd", target_arch = "x86_64", nightly), + feature(stdsimd) +)] +#![cfg_attr( + all(curve25519_dalek_backend = "simd", target_arch = "x86_64", nightly), + feature(avx512_target_feature) +)] #![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg, doc_cfg_hide))] #![cfg_attr(docsrs, doc(cfg_hide(docsrs)))] #![cfg_attr(allow_unused_unsafe, allow(unused_unsafe))] From b87ad6b9f897e69c364e4bc6e4aa4aee9439c467 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Sat, 17 Jun 2023 07:25:10 +0000 Subject: [PATCH 43/53] Simply backend gates via build --- src/backend/mod.rs | 135 +++++++-------------------------------------- 1 file changed, 21 insertions(+), 114 deletions(-) diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 0d44dc5d1..4424e0a53 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -39,43 +39,21 @@ use crate::Scalar; pub mod serial; -#[cfg(all( - target_arch = "x86_64", - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial"), -))] +#[cfg(curve25519_dalek_backend = "simd")] pub mod vector; #[derive(Copy, Clone)] enum BackendKind { - #[cfg(all( - target_arch = "x86_64", - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial") - ))] + #[cfg(curve25519_dalek_backend = "simd")] Avx2, - #[cfg(all( - target_arch = "x86_64", - nightly, - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial") - ))] + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] Avx512, Serial, } #[inline] fn get_selected_backend() -> BackendKind { - #[cfg(all( - target_arch = "x86_64", - nightly, - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial") - ))] + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] { cpufeatures::new!(cpuid_avx512, "avx512ifma", "avx512vl"); let token_avx512: cpuid_avx512::InitToken = cpuid_avx512::init(); @@ -84,12 +62,7 @@ fn get_selected_backend() -> BackendKind { } } - #[cfg(all( - target_arch = "x86_64", - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial") - ))] + #[cfg(curve25519_dalek_backend = "simd")] { cpufeatures::new!(cpuid_avx2, "avx2"); let token_avx2: cpuid_avx2::InitToken = cpuid_avx2::init(); @@ -112,10 +85,10 @@ where use crate::traits::VartimeMultiscalarMul; match get_selected_backend() { - #[cfg(all(target_arch = "x86_64", curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat"), not(curve25519_dalek_backend = "serial")))] + #[cfg(curve25519_dalek_backend = "simd")] BackendKind::Avx2 => self::vector::scalar_mul::pippenger::spec_avx2::Pippenger::optional_multiscalar_mul::(scalars, points), - #[cfg(all(target_arch = "x86_64", nightly, curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat"), not(curve25519_dalek_backend = "serial")))] + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] BackendKind::Avx512 => self::vector::scalar_mul::pippenger::spec_avx512ifma_avx512vl::Pippenger::optional_multiscalar_mul::(scalars, points), BackendKind::Serial => @@ -125,20 +98,9 @@ where #[cfg(feature = "alloc")] pub(crate) enum VartimePrecomputedStraus { - #[cfg(all( - target_arch = "x86_64", - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial") - ))] + #[cfg(curve25519_dalek_backend = "simd")] Avx2(self::vector::scalar_mul::precomputed_straus::spec_avx2::VartimePrecomputedStraus), - #[cfg(all( - target_arch = "x86_64", - nightly, - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial") - ))] + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] Avx512ifma( self::vector::scalar_mul::precomputed_straus::spec_avx512ifma_avx512vl::VartimePrecomputedStraus, ), @@ -155,10 +117,10 @@ impl VartimePrecomputedStraus { use crate::traits::VartimePrecomputedMultiscalarMul; match get_selected_backend() { - #[cfg(all(target_arch = "x86_64", curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat"), not(curve25519_dalek_backend = "serial")))] + #[cfg(curve25519_dalek_backend = "simd")] BackendKind::Avx2 => VartimePrecomputedStraus::Avx2(self::vector::scalar_mul::precomputed_straus::spec_avx2::VartimePrecomputedStraus::new(static_points)), - #[cfg(all(target_arch = "x86_64", nightly, curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat"), not(curve25519_dalek_backend = "serial")))] + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] BackendKind::Avx512 => VartimePrecomputedStraus::Avx512ifma(self::vector::scalar_mul::precomputed_straus::spec_avx512ifma_avx512vl::VartimePrecomputedStraus::new(static_points)), BackendKind::Serial => @@ -182,24 +144,13 @@ impl VartimePrecomputedStraus { use crate::traits::VartimePrecomputedMultiscalarMul; match self { - #[cfg(all( - target_arch = "x86_64", - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial"), - ))] + #[cfg(curve25519_dalek_backend = "simd")] VartimePrecomputedStraus::Avx2(inner) => inner.optional_mixed_multiscalar_mul( static_scalars, dynamic_scalars, dynamic_points, ), - #[cfg(all( - target_arch = "x86_64", - nightly, - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial"), - ))] + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] VartimePrecomputedStraus::Avx512ifma(inner) => inner.optional_mixed_multiscalar_mul( static_scalars, dynamic_scalars, @@ -226,24 +177,13 @@ where use crate::traits::MultiscalarMul; match get_selected_backend() { - #[cfg(all( - target_arch = "x86_64", - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial"), - ))] + #[cfg(curve25519_dalek_backend = "simd")] BackendKind::Avx2 => { self::vector::scalar_mul::straus::spec_avx2::Straus::multiscalar_mul::( scalars, points, ) } - #[cfg(all( - target_arch = "x86_64", - nightly, - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial"), - ))] + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] BackendKind::Avx512 => { self::vector::scalar_mul::straus::spec_avx512ifma_avx512vl::Straus::multiscalar_mul::< I, @@ -267,24 +207,13 @@ where use crate::traits::VartimeMultiscalarMul; match get_selected_backend() { - #[cfg(all( - target_arch = "x86_64", - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial"), - ))] + #[cfg(curve25519_dalek_backend = "simd")] BackendKind::Avx2 => { self::vector::scalar_mul::straus::spec_avx2::Straus::optional_multiscalar_mul::( scalars, points, ) } - #[cfg(all( - target_arch = "x86_64", - nightly, - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial") - ))] + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] BackendKind::Avx512 => { self::vector::scalar_mul::straus::spec_avx512ifma_avx512vl::Straus::optional_multiscalar_mul::< I, @@ -302,20 +231,9 @@ where /// Perform constant-time, variable-base scalar multiplication. pub fn variable_base_mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint { match get_selected_backend() { - #[cfg(all( - target_arch = "x86_64", - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial") - ))] + #[cfg(curve25519_dalek_backend = "simd")] BackendKind::Avx2 => self::vector::scalar_mul::variable_base::spec_avx2::mul(point, scalar), - #[cfg(all( - target_arch = "x86_64", - nightly, - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial") - ))] + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] BackendKind::Avx512 => { self::vector::scalar_mul::variable_base::spec_avx512ifma_avx512vl::mul(point, scalar) } @@ -327,20 +245,9 @@ pub fn variable_base_mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint #[allow(non_snake_case)] pub fn vartime_double_base_mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint { match get_selected_backend() { - #[cfg(all( - target_arch = "x86_64", - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial") - ))] + #[cfg(curve25519_dalek_backend = "simd")] BackendKind::Avx2 => self::vector::scalar_mul::vartime_double_base::spec_avx2::mul(a, A, b), - #[cfg(all( - target_arch = "x86_64", - nightly, - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial") - ))] + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] BackendKind::Avx512 => { self::vector::scalar_mul::vartime_double_base::spec_avx512ifma_avx512vl::mul(a, A, b) } From 2755aa3cf7a59900d5c5adaa4cbe6e7ead4e5b60 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Sat, 17 Jun 2023 08:06:08 +0000 Subject: [PATCH 44/53] Revert "Simply backend gates via build" This reverts commit b87ad6b9f897e69c364e4bc6e4aa4aee9439c467. When --cfg curve25519_dalek_backend="simd" is chosen it cannot be overriden as "serial" in build.rs and will result in both selected --- src/backend/mod.rs | 135 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 114 insertions(+), 21 deletions(-) diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 4424e0a53..0d44dc5d1 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -39,21 +39,43 @@ use crate::Scalar; pub mod serial; -#[cfg(curve25519_dalek_backend = "simd")] +#[cfg(all( + target_arch = "x86_64", + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial"), +))] pub mod vector; #[derive(Copy, Clone)] enum BackendKind { - #[cfg(curve25519_dalek_backend = "simd")] + #[cfg(all( + target_arch = "x86_64", + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial") + ))] Avx2, - #[cfg(all(curve25519_dalek_backend = "simd", nightly))] + #[cfg(all( + target_arch = "x86_64", + nightly, + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial") + ))] Avx512, Serial, } #[inline] fn get_selected_backend() -> BackendKind { - #[cfg(all(curve25519_dalek_backend = "simd", nightly))] + #[cfg(all( + target_arch = "x86_64", + nightly, + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial") + ))] { cpufeatures::new!(cpuid_avx512, "avx512ifma", "avx512vl"); let token_avx512: cpuid_avx512::InitToken = cpuid_avx512::init(); @@ -62,7 +84,12 @@ fn get_selected_backend() -> BackendKind { } } - #[cfg(curve25519_dalek_backend = "simd")] + #[cfg(all( + target_arch = "x86_64", + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial") + ))] { cpufeatures::new!(cpuid_avx2, "avx2"); let token_avx2: cpuid_avx2::InitToken = cpuid_avx2::init(); @@ -85,10 +112,10 @@ where use crate::traits::VartimeMultiscalarMul; match get_selected_backend() { - #[cfg(curve25519_dalek_backend = "simd")] + #[cfg(all(target_arch = "x86_64", curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat"), not(curve25519_dalek_backend = "serial")))] BackendKind::Avx2 => self::vector::scalar_mul::pippenger::spec_avx2::Pippenger::optional_multiscalar_mul::(scalars, points), - #[cfg(all(curve25519_dalek_backend = "simd", nightly))] + #[cfg(all(target_arch = "x86_64", nightly, curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat"), not(curve25519_dalek_backend = "serial")))] BackendKind::Avx512 => self::vector::scalar_mul::pippenger::spec_avx512ifma_avx512vl::Pippenger::optional_multiscalar_mul::(scalars, points), BackendKind::Serial => @@ -98,9 +125,20 @@ where #[cfg(feature = "alloc")] pub(crate) enum VartimePrecomputedStraus { - #[cfg(curve25519_dalek_backend = "simd")] + #[cfg(all( + target_arch = "x86_64", + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial") + ))] Avx2(self::vector::scalar_mul::precomputed_straus::spec_avx2::VartimePrecomputedStraus), - #[cfg(all(curve25519_dalek_backend = "simd", nightly))] + #[cfg(all( + target_arch = "x86_64", + nightly, + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial") + ))] Avx512ifma( self::vector::scalar_mul::precomputed_straus::spec_avx512ifma_avx512vl::VartimePrecomputedStraus, ), @@ -117,10 +155,10 @@ impl VartimePrecomputedStraus { use crate::traits::VartimePrecomputedMultiscalarMul; match get_selected_backend() { - #[cfg(curve25519_dalek_backend = "simd")] + #[cfg(all(target_arch = "x86_64", curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat"), not(curve25519_dalek_backend = "serial")))] BackendKind::Avx2 => VartimePrecomputedStraus::Avx2(self::vector::scalar_mul::precomputed_straus::spec_avx2::VartimePrecomputedStraus::new(static_points)), - #[cfg(all(curve25519_dalek_backend = "simd", nightly))] + #[cfg(all(target_arch = "x86_64", nightly, curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat"), not(curve25519_dalek_backend = "serial")))] BackendKind::Avx512 => VartimePrecomputedStraus::Avx512ifma(self::vector::scalar_mul::precomputed_straus::spec_avx512ifma_avx512vl::VartimePrecomputedStraus::new(static_points)), BackendKind::Serial => @@ -144,13 +182,24 @@ impl VartimePrecomputedStraus { use crate::traits::VartimePrecomputedMultiscalarMul; match self { - #[cfg(curve25519_dalek_backend = "simd")] + #[cfg(all( + target_arch = "x86_64", + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial"), + ))] VartimePrecomputedStraus::Avx2(inner) => inner.optional_mixed_multiscalar_mul( static_scalars, dynamic_scalars, dynamic_points, ), - #[cfg(all(curve25519_dalek_backend = "simd", nightly))] + #[cfg(all( + target_arch = "x86_64", + nightly, + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial"), + ))] VartimePrecomputedStraus::Avx512ifma(inner) => inner.optional_mixed_multiscalar_mul( static_scalars, dynamic_scalars, @@ -177,13 +226,24 @@ where use crate::traits::MultiscalarMul; match get_selected_backend() { - #[cfg(curve25519_dalek_backend = "simd")] + #[cfg(all( + target_arch = "x86_64", + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial"), + ))] BackendKind::Avx2 => { self::vector::scalar_mul::straus::spec_avx2::Straus::multiscalar_mul::( scalars, points, ) } - #[cfg(all(curve25519_dalek_backend = "simd", nightly))] + #[cfg(all( + target_arch = "x86_64", + nightly, + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial"), + ))] BackendKind::Avx512 => { self::vector::scalar_mul::straus::spec_avx512ifma_avx512vl::Straus::multiscalar_mul::< I, @@ -207,13 +267,24 @@ where use crate::traits::VartimeMultiscalarMul; match get_selected_backend() { - #[cfg(curve25519_dalek_backend = "simd")] + #[cfg(all( + target_arch = "x86_64", + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial"), + ))] BackendKind::Avx2 => { self::vector::scalar_mul::straus::spec_avx2::Straus::optional_multiscalar_mul::( scalars, points, ) } - #[cfg(all(curve25519_dalek_backend = "simd", nightly))] + #[cfg(all( + target_arch = "x86_64", + nightly, + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial") + ))] BackendKind::Avx512 => { self::vector::scalar_mul::straus::spec_avx512ifma_avx512vl::Straus::optional_multiscalar_mul::< I, @@ -231,9 +302,20 @@ where /// Perform constant-time, variable-base scalar multiplication. pub fn variable_base_mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint { match get_selected_backend() { - #[cfg(curve25519_dalek_backend = "simd")] + #[cfg(all( + target_arch = "x86_64", + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial") + ))] BackendKind::Avx2 => self::vector::scalar_mul::variable_base::spec_avx2::mul(point, scalar), - #[cfg(all(curve25519_dalek_backend = "simd", nightly))] + #[cfg(all( + target_arch = "x86_64", + nightly, + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial") + ))] BackendKind::Avx512 => { self::vector::scalar_mul::variable_base::spec_avx512ifma_avx512vl::mul(point, scalar) } @@ -245,9 +327,20 @@ pub fn variable_base_mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint #[allow(non_snake_case)] pub fn vartime_double_base_mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint { match get_selected_backend() { - #[cfg(curve25519_dalek_backend = "simd")] + #[cfg(all( + target_arch = "x86_64", + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial") + ))] BackendKind::Avx2 => self::vector::scalar_mul::vartime_double_base::spec_avx2::mul(a, A, b), - #[cfg(all(curve25519_dalek_backend = "simd", nightly))] + #[cfg(all( + target_arch = "x86_64", + nightly, + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial") + ))] BackendKind::Avx512 => { self::vector::scalar_mul::vartime_double_base::spec_avx512ifma_avx512vl::mul(a, A, b) } From 9c42cc9cde60516caccab9c6a09510fc2a0ed88d Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Sat, 17 Jun 2023 08:12:02 +0000 Subject: [PATCH 45/53] Correct gating for feature enable --- src/lib.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0a0638fbb..17f5850e0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,11 +11,21 @@ #![no_std] #![cfg_attr( - all(curve25519_dalek_backend = "simd", target_arch = "x86_64", nightly), + all( + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial"), + target_arch = "x86_64", + nightly + ), feature(stdsimd) )] #![cfg_attr( - all(curve25519_dalek_backend = "simd", target_arch = "x86_64", nightly), + all( + not(curve25519_dalek_backend = "fiat"), + not(curve25519_dalek_backend = "serial"), + target_arch = "x86_64", + nightly + ), feature(avx512_target_feature) )] #![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg, doc_cfg_hide))] From 91d0d6d88ead04c08d9d4df9c0bafe8abcb616cd Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Sat, 17 Jun 2023 08:33:17 +0000 Subject: [PATCH 46/53] Add note and test about the override warning when unsuccesfull --- build.rs | 7 ++++++- tests/build_tests.sh | 13 +++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/build.rs b/build.rs index d9e3e758c..8e9f79b0a 100644 --- a/build.rs +++ b/build.rs @@ -41,7 +41,12 @@ fn main() { _ => "".to_string(), }; - // Backend override + // Backend overrides + // NOTE: If someone provides cfg(curve25519_dalek_backend) this may end up + // as an additional entry where the gating has to be done via negative not() + // e.g. on wasm32 target may be both "serial" and "simd" if tries override w/ + // "simd" since the logic here adds "serial" due to target not being "simd" + // capable - correct way to gate it so gate via all(not(other1), not(other2) let curve25519_dalek_backend = match std::env::var("CARGO_CFG_CURVE25519_DALEK_BACKEND") .as_deref() { diff --git a/tests/build_tests.sh b/tests/build_tests.sh index 3c5616ca9..71f05350b 100755 --- a/tests/build_tests.sh +++ b/tests/build_tests.sh @@ -50,6 +50,19 @@ env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\"" cargo build --targe match_and_report "curve25519_dalek_backend is 'serial'" "$OUT" match_and_report "curve25519_dalek_bits is '32'" "$OUT" +# wasm 32 bit target default +# Attempted override w/ "simd" should result "serial" addition +cargo clean +OUT=build_5_1.txt +env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\" --cfg curve25519_dalek_backend=\"simd\"" cargo build --target wasm32-unknown-unknown > "$OUT" 2>&1 +# this is the cargo behaviour - it adds two entries so gating is via all(not()) +# e.g. simd must be gated via all(not(curve25519_dalek_backend = "serial") +fiat +# TODO: maybe this could be a compile error instead ? +match_and_report "warning: Could not override curve25519_dalek_backend to simd - defaulting to serial" "$OUT" +match_and_report "curve25519_dalek_backend is 'serial'" "$OUT" +match_and_report "curve25519_dalek_backend is 'simd'" "$OUT" +match_and_report "curve25519_dalek_bits is '32'" "$OUT" + # fiat override with default 64 bit naive host assumption cargo clean OUT=build_6.txt From 1ac7b2c96ce302bf98ad2db08548a6db647a32c5 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Sat, 17 Jun 2023 08:54:25 +0000 Subject: [PATCH 47/53] Reduce complexity in build gating via compile_error --- README.md | 5 +- build.rs | 19 ++---- src/backend/mod.rs | 135 +++++++------------------------------------ src/lib.rs | 17 +----- tests/build_tests.sh | 9 +-- 5 files changed, 34 insertions(+), 151 deletions(-) diff --git a/README.md b/README.md index 7e4d319dc..53940a43c 100644 --- a/README.md +++ b/README.md @@ -148,8 +148,9 @@ RUSTFLAGS='--cfg curve25519_dalek_bits="SIZE"' `SIZE` is `32` or `64`. As in the above section, this can also be placed in `~/.cargo/config`. -**NOTE:** Using a word size of 32 will automatically prevent SIMD auto-detection -and support as this backend requires the 64 bit word size. +**NOTE:** Using a word size of 32 will automatically prevent [SIMD backend] +selection as it requires the 64 bit word size and will result a compile error +if simd is attempted as a a manual backend override in this case. ### Cross-compilation diff --git a/build.rs b/build.rs index 8e9f79b0a..5ab4fe33e 100644 --- a/build.rs +++ b/build.rs @@ -41,26 +41,19 @@ fn main() { _ => "".to_string(), }; - // Backend overrides - // NOTE: If someone provides cfg(curve25519_dalek_backend) this may end up - // as an additional entry where the gating has to be done via negative not() - // e.g. on wasm32 target may be both "serial" and "simd" if tries override w/ - // "simd" since the logic here adds "serial" due to target not being "simd" - // capable - correct way to gate it so gate via all(not(other1), not(other2) + // Backend overrides / defaults let curve25519_dalek_backend = match std::env::var("CARGO_CFG_CURVE25519_DALEK_BACKEND") .as_deref() { Ok("fiat") => "fiat", Ok("serial") => "serial", Ok("simd") => { - // simd override is not guaranteed as: // simd can only be enabled on x86_64 & 64bit target_pointer_width - if is_capable_simd(&target_arch, curve25519_dalek_bits) { - "simd" - // fallback to serial with a warning - } else { - println!("cargo:warning=Could not override curve25519_dalek_backend to simd - defaulting to serial"); - "serial" + match is_capable_simd(&target_arch, curve25519_dalek_bits) { + true => "simd", + // If override is not possible this should result to compile error + // mere fallback with a warning would require all(not()) gating + false => panic!("cargo:error=Could not override curve25519_dalek_backend to simd"), } } // default between serial / simd (if potentially capable) diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 0d44dc5d1..4424e0a53 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -39,43 +39,21 @@ use crate::Scalar; pub mod serial; -#[cfg(all( - target_arch = "x86_64", - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial"), -))] +#[cfg(curve25519_dalek_backend = "simd")] pub mod vector; #[derive(Copy, Clone)] enum BackendKind { - #[cfg(all( - target_arch = "x86_64", - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial") - ))] + #[cfg(curve25519_dalek_backend = "simd")] Avx2, - #[cfg(all( - target_arch = "x86_64", - nightly, - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial") - ))] + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] Avx512, Serial, } #[inline] fn get_selected_backend() -> BackendKind { - #[cfg(all( - target_arch = "x86_64", - nightly, - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial") - ))] + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] { cpufeatures::new!(cpuid_avx512, "avx512ifma", "avx512vl"); let token_avx512: cpuid_avx512::InitToken = cpuid_avx512::init(); @@ -84,12 +62,7 @@ fn get_selected_backend() -> BackendKind { } } - #[cfg(all( - target_arch = "x86_64", - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial") - ))] + #[cfg(curve25519_dalek_backend = "simd")] { cpufeatures::new!(cpuid_avx2, "avx2"); let token_avx2: cpuid_avx2::InitToken = cpuid_avx2::init(); @@ -112,10 +85,10 @@ where use crate::traits::VartimeMultiscalarMul; match get_selected_backend() { - #[cfg(all(target_arch = "x86_64", curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat"), not(curve25519_dalek_backend = "serial")))] + #[cfg(curve25519_dalek_backend = "simd")] BackendKind::Avx2 => self::vector::scalar_mul::pippenger::spec_avx2::Pippenger::optional_multiscalar_mul::(scalars, points), - #[cfg(all(target_arch = "x86_64", nightly, curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat"), not(curve25519_dalek_backend = "serial")))] + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] BackendKind::Avx512 => self::vector::scalar_mul::pippenger::spec_avx512ifma_avx512vl::Pippenger::optional_multiscalar_mul::(scalars, points), BackendKind::Serial => @@ -125,20 +98,9 @@ where #[cfg(feature = "alloc")] pub(crate) enum VartimePrecomputedStraus { - #[cfg(all( - target_arch = "x86_64", - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial") - ))] + #[cfg(curve25519_dalek_backend = "simd")] Avx2(self::vector::scalar_mul::precomputed_straus::spec_avx2::VartimePrecomputedStraus), - #[cfg(all( - target_arch = "x86_64", - nightly, - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial") - ))] + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] Avx512ifma( self::vector::scalar_mul::precomputed_straus::spec_avx512ifma_avx512vl::VartimePrecomputedStraus, ), @@ -155,10 +117,10 @@ impl VartimePrecomputedStraus { use crate::traits::VartimePrecomputedMultiscalarMul; match get_selected_backend() { - #[cfg(all(target_arch = "x86_64", curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat"), not(curve25519_dalek_backend = "serial")))] + #[cfg(curve25519_dalek_backend = "simd")] BackendKind::Avx2 => VartimePrecomputedStraus::Avx2(self::vector::scalar_mul::precomputed_straus::spec_avx2::VartimePrecomputedStraus::new(static_points)), - #[cfg(all(target_arch = "x86_64", nightly, curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat"), not(curve25519_dalek_backend = "serial")))] + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] BackendKind::Avx512 => VartimePrecomputedStraus::Avx512ifma(self::vector::scalar_mul::precomputed_straus::spec_avx512ifma_avx512vl::VartimePrecomputedStraus::new(static_points)), BackendKind::Serial => @@ -182,24 +144,13 @@ impl VartimePrecomputedStraus { use crate::traits::VartimePrecomputedMultiscalarMul; match self { - #[cfg(all( - target_arch = "x86_64", - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial"), - ))] + #[cfg(curve25519_dalek_backend = "simd")] VartimePrecomputedStraus::Avx2(inner) => inner.optional_mixed_multiscalar_mul( static_scalars, dynamic_scalars, dynamic_points, ), - #[cfg(all( - target_arch = "x86_64", - nightly, - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial"), - ))] + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] VartimePrecomputedStraus::Avx512ifma(inner) => inner.optional_mixed_multiscalar_mul( static_scalars, dynamic_scalars, @@ -226,24 +177,13 @@ where use crate::traits::MultiscalarMul; match get_selected_backend() { - #[cfg(all( - target_arch = "x86_64", - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial"), - ))] + #[cfg(curve25519_dalek_backend = "simd")] BackendKind::Avx2 => { self::vector::scalar_mul::straus::spec_avx2::Straus::multiscalar_mul::( scalars, points, ) } - #[cfg(all( - target_arch = "x86_64", - nightly, - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial"), - ))] + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] BackendKind::Avx512 => { self::vector::scalar_mul::straus::spec_avx512ifma_avx512vl::Straus::multiscalar_mul::< I, @@ -267,24 +207,13 @@ where use crate::traits::VartimeMultiscalarMul; match get_selected_backend() { - #[cfg(all( - target_arch = "x86_64", - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial"), - ))] + #[cfg(curve25519_dalek_backend = "simd")] BackendKind::Avx2 => { self::vector::scalar_mul::straus::spec_avx2::Straus::optional_multiscalar_mul::( scalars, points, ) } - #[cfg(all( - target_arch = "x86_64", - nightly, - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial") - ))] + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] BackendKind::Avx512 => { self::vector::scalar_mul::straus::spec_avx512ifma_avx512vl::Straus::optional_multiscalar_mul::< I, @@ -302,20 +231,9 @@ where /// Perform constant-time, variable-base scalar multiplication. pub fn variable_base_mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint { match get_selected_backend() { - #[cfg(all( - target_arch = "x86_64", - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial") - ))] + #[cfg(curve25519_dalek_backend = "simd")] BackendKind::Avx2 => self::vector::scalar_mul::variable_base::spec_avx2::mul(point, scalar), - #[cfg(all( - target_arch = "x86_64", - nightly, - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial") - ))] + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] BackendKind::Avx512 => { self::vector::scalar_mul::variable_base::spec_avx512ifma_avx512vl::mul(point, scalar) } @@ -327,20 +245,9 @@ pub fn variable_base_mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint #[allow(non_snake_case)] pub fn vartime_double_base_mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint { match get_selected_backend() { - #[cfg(all( - target_arch = "x86_64", - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial") - ))] + #[cfg(curve25519_dalek_backend = "simd")] BackendKind::Avx2 => self::vector::scalar_mul::vartime_double_base::spec_avx2::mul(a, A, b), - #[cfg(all( - target_arch = "x86_64", - nightly, - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial") - ))] + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] BackendKind::Avx512 => { self::vector::scalar_mul::vartime_double_base::spec_avx512ifma_avx512vl::mul(a, A, b) } diff --git a/src/lib.rs b/src/lib.rs index 17f5850e0..98d79ae1f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,22 +10,9 @@ // - Henry de Valence #![no_std] +#![cfg_attr(all(curve25519_dalek_backend = "simd", nightly), feature(stdsimd))] #![cfg_attr( - all( - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial"), - target_arch = "x86_64", - nightly - ), - feature(stdsimd) -)] -#![cfg_attr( - all( - not(curve25519_dalek_backend = "fiat"), - not(curve25519_dalek_backend = "serial"), - target_arch = "x86_64", - nightly - ), + all(curve25519_dalek_backend = "simd", nightly), feature(avx512_target_feature) )] #![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg, doc_cfg_hide))] diff --git a/tests/build_tests.sh b/tests/build_tests.sh index 71f05350b..4c66e26ef 100755 --- a/tests/build_tests.sh +++ b/tests/build_tests.sh @@ -55,13 +55,8 @@ match_and_report "curve25519_dalek_bits is '32'" "$OUT" cargo clean OUT=build_5_1.txt env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\" --cfg curve25519_dalek_backend=\"simd\"" cargo build --target wasm32-unknown-unknown > "$OUT" 2>&1 -# this is the cargo behaviour - it adds two entries so gating is via all(not()) -# e.g. simd must be gated via all(not(curve25519_dalek_backend = "serial") +fiat -# TODO: maybe this could be a compile error instead ? -match_and_report "warning: Could not override curve25519_dalek_backend to simd - defaulting to serial" "$OUT" -match_and_report "curve25519_dalek_backend is 'serial'" "$OUT" -match_and_report "curve25519_dalek_backend is 'simd'" "$OUT" -match_and_report "curve25519_dalek_bits is '32'" "$OUT" +# This ovveride should fail the compilation since "simd" is not available +match_and_report "Could not override curve25519_dalek_backend to simd" "$OUT" # fiat override with default 64 bit naive host assumption cargo clean From 770a394e62ec2742858dcca89d22606504c3b54a Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Sat, 17 Jun 2023 08:56:51 +0000 Subject: [PATCH 48/53] Doc typo --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 53940a43c..1f821cedf 100644 --- a/README.md +++ b/README.md @@ -149,8 +149,8 @@ RUSTFLAGS='--cfg curve25519_dalek_bits="SIZE"' in `~/.cargo/config`. **NOTE:** Using a word size of 32 will automatically prevent [SIMD backend] -selection as it requires the 64 bit word size and will result a compile error -if simd is attempted as a a manual backend override in this case. +selection as this requires the 64 bit word size and will result a compile error +if simd is attempted as a manual backend override. ### Cross-compilation From 2eb2b173205dd22b85d96bd4d664f578676aac87 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Sat, 17 Jun 2023 10:01:56 +0000 Subject: [PATCH 49/53] Cosmetic panic error message fix --- build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.rs b/build.rs index 5ab4fe33e..0459f466d 100644 --- a/build.rs +++ b/build.rs @@ -53,7 +53,7 @@ fn main() { true => "simd", // If override is not possible this should result to compile error // mere fallback with a warning would require all(not()) gating - false => panic!("cargo:error=Could not override curve25519_dalek_backend to simd"), + false => panic!("Could not override curve25519_dalek_backend to simd"), } } // default between serial / simd (if potentially capable) From 8bf3439d6f9db427c8fe6fc2752246e210e91b3f Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Sat, 17 Jun 2023 10:10:27 +0000 Subject: [PATCH 50/53] Play the fmt game again --- build.rs | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/build.rs b/build.rs index 0459f466d..29a69f5fa 100644 --- a/build.rs +++ b/build.rs @@ -42,26 +42,25 @@ fn main() { }; // Backend overrides / defaults - let curve25519_dalek_backend = match std::env::var("CARGO_CFG_CURVE25519_DALEK_BACKEND") - .as_deref() - { - Ok("fiat") => "fiat", - Ok("serial") => "serial", - Ok("simd") => { - // simd can only be enabled on x86_64 & 64bit target_pointer_width - match is_capable_simd(&target_arch, curve25519_dalek_bits) { - true => "simd", - // If override is not possible this should result to compile error - // mere fallback with a warning would require all(not()) gating - false => panic!("Could not override curve25519_dalek_backend to simd"), + let curve25519_dalek_backend = + match std::env::var("CARGO_CFG_CURVE25519_DALEK_BACKEND").as_deref() { + Ok("fiat") => "fiat", + Ok("serial") => "serial", + Ok("simd") => { + // simd can only be enabled on x86_64 & 64bit target_pointer_width + match is_capable_simd(&target_arch, curve25519_dalek_bits) { + true => "simd", + // If override is not possible this should result to compile error + // mere fallback with a warning would require all(not()) gating + false => panic!("Could not override curve25519_dalek_backend to simd"), + } } - } - // default between serial / simd (if potentially capable) - _ => match is_capable_simd(&target_arch, curve25519_dalek_bits) { - true => "simd", - false => "serial", - }, - }; + // default between serial / simd (if potentially capable) + _ => match is_capable_simd(&target_arch, curve25519_dalek_bits) { + true => "simd", + false => "serial", + }, + }; println!("cargo:rustc-cfg=curve25519_dalek_backend=\"{curve25519_dalek_backend}\""); } From 1671d80ada42ddb7b36d6e41ce193fb9fd9173cf Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Sat, 17 Jun 2023 11:58:08 +0000 Subject: [PATCH 51/53] Refer to issue/532 around intended compile_error --- build.rs | 4 ++-- tests/build_tests.sh | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/build.rs b/build.rs index 29a69f5fa..92d2802cd 100644 --- a/build.rs +++ b/build.rs @@ -50,8 +50,8 @@ fn main() { // simd can only be enabled on x86_64 & 64bit target_pointer_width match is_capable_simd(&target_arch, curve25519_dalek_bits) { true => "simd", - // If override is not possible this should result to compile error - // mere fallback with a warning would require all(not()) gating + // If override is not possible this must result to compile error + // See: issues/532 false => panic!("Could not override curve25519_dalek_backend to simd"), } } diff --git a/tests/build_tests.sh b/tests/build_tests.sh index 4c66e26ef..c8a47397a 100755 --- a/tests/build_tests.sh +++ b/tests/build_tests.sh @@ -55,7 +55,8 @@ match_and_report "curve25519_dalek_bits is '32'" "$OUT" cargo clean OUT=build_5_1.txt env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\" --cfg curve25519_dalek_backend=\"simd\"" cargo build --target wasm32-unknown-unknown > "$OUT" 2>&1 -# This ovveride should fail the compilation since "simd" is not available +# This ovveride must fail the compilation since "simd" is not available +# See: issues/532 match_and_report "Could not override curve25519_dalek_backend to simd" "$OUT" # fiat override with default 64 bit naive host assumption From 1bcbda58f1285493ebf0f2f659c440ef6eee1f78 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Sat, 17 Jun 2023 11:59:23 +0000 Subject: [PATCH 52/53] Squash annoying typo --- tests/build_tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/build_tests.sh b/tests/build_tests.sh index c8a47397a..ac6e7819d 100755 --- a/tests/build_tests.sh +++ b/tests/build_tests.sh @@ -55,7 +55,7 @@ match_and_report "curve25519_dalek_bits is '32'" "$OUT" cargo clean OUT=build_5_1.txt env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\" --cfg curve25519_dalek_backend=\"simd\"" cargo build --target wasm32-unknown-unknown > "$OUT" 2>&1 -# This ovveride must fail the compilation since "simd" is not available +# This overide must fail the compilation since "simd" is not available # See: issues/532 match_and_report "Could not override curve25519_dalek_backend to simd" "$OUT" From 919c8b46e62d8a1f16ce8e773c27a46838756004 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Tue, 20 Jun 2023 00:26:12 -0400 Subject: [PATCH 53/53] Some README cleanup --- README.md | 53 +++++++++++++++++------------------------------------ 1 file changed, 17 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 1f821cedf..cd83e9253 100644 --- a/README.md +++ b/README.md @@ -91,29 +91,19 @@ This release also does a lot of dependency updates and relaxations to unblock up Curve arithmetic is implemented and used by one of the following backends: -| Backend | Selection | Implementation | Bits / Word sizes | -| :--- | :--- | :--- | :--- | -| `serial` | Automatic | serial software | `32` and `64` | -| `fiat` | Manual | Formally verified field arithmetic from [fiat-crypto] | `32` and `64` | -| `simd` | Automatic | Intel AVX2 / AVX512 IFMA accelerated backend | `64` only | +| Backend | Selection | Implementation | Bits / Word sizes | +| :--- | :--- | :--- | :--- | +| `serial` | Automatic | An optimized, non-parllel implementation | `32` and `64` | +| `fiat` | Manual | Formally verified field arithmetic from [fiat-crypto] | `32` and `64` | +| `simd` | Automatic | Intel AVX2 / AVX512 IFMA accelerated backend | `64` only | -## Automatic Backend Selection +At runtime, `curve25519-dalek` selects an arithmetic backend from the set of backends it was compiled to support. For Intel x86-64 targets, unless otherwise specified, it will build itself with `simd` support, and default to `serial` at runtime if the appropriate CPU features aren't detected. See [SIMD backend] for more details. -Currently on the intel `x86_64` targets with `64` bit word size, the backend -selection is automatic between the `simd` and `serial` backends. - -The `simd` backend is automatically selected if the needed instruction set is -detected available on the target CPU - see more from [SIMD backend]. - -The automatic selection between `serial` and `simd` does not happen on any other -platform currently and will default to `serial` software implementation. - -In the future `simd` backend may be extended to cover more instruction sets and -this change will be non-breaking as this is considered as implementation detail. +In the future, `simd` backend may be extended to cover more instruction sets. This change will be non-breaking as this is considered as implementation detail. ## Manual Backend Override -The backend can be potentially overriden by setting an environment variable: +You can force the crate to compile with specific backend support, e.g., `serial` for x86-64 targets to save code size, or `fiat` to force the runtime to use verified code. To do this, set the environment variable: ```sh RUSTFLAGS='--cfg curve25519_dalek_backend="BACKEND"' ``` @@ -133,13 +123,11 @@ function. `curve25519-dalek` will automatically choose the word size for the `fiat` and `serial` backends, based on the build target. - For example, building for a 64-bit machine, the default 64 bit word size is automatically chosen when either the `serial` or `fiat` backend is selected. In some targets it might be required to override the word size for better performance. - Backend word size can be overridden for `serial` and `fiat` by setting the environment variable: ```sh @@ -148,15 +136,11 @@ RUSTFLAGS='--cfg curve25519_dalek_bits="SIZE"' `SIZE` is `32` or `64`. As in the above section, this can also be placed in `~/.cargo/config`. -**NOTE:** Using a word size of 32 will automatically prevent [SIMD backend] -selection as this requires the 64 bit word size and will result a compile error -if simd is attempted as a manual backend override. +Note: The [SIMD backend] requires a word size of 64 bits. Attempting to set bits=32 and backend=`simd` will yield a compile error. ### Cross-compilation -Because backend selection is done by target, cross-compiling will select the -correct word size automatically. For example, on an x86-64 Linux machine, -`curve25519-dalek` will use the `u32` target backend if the following is run: +Because backend selection is done by target, cross-compiling will select the correct word size automatically. For example, if a x86-64 Linux machine runs the following commands, `curve25519-dalek` will be compiled with the 32-bit `serial` backend. ```console $ sudo apt install gcc-multilib # (or whatever package manager you use) $ rustup target add i686-unknown-linux-gnu @@ -165,19 +149,16 @@ $ cargo build --target i686-unknown-linux-gnu ## SIMD backend -The SIMD target backend selection is done automatically at runtime depending -on the available CPU features, provided the appropriate feature flag is enabled. +The specific SIMD backend (AVX512 / AVX2 / `serial` default) is selected automatically at runtime, depending on the currently available CPU features, and whether Rust nightly is being used for compilation. The precise conditions are specified below. -You can also specify an appropriate `-C target_feature` to build a binary -which assumes the required SIMD instructions are always available. +For a given CPU feature, you can also specify an appropriate `-C target_feature` to build a binary which assumes the required SIMD instructions are always available. Don't do this if you don't have a good reason. -| Backend | Feature flag | `RUSTFLAGS` | Requires nightly? | -| :--- | :--- | :--- | :--- | -| avx2 | `simd_avx2` | `-C target_feature=+avx2` | no | -| avx512 | `simd_avx512` | `-C target_feature=+avx512ifma,+avx512vl` | yes | +| Backend | `RUSTFLAGS` | Requires nightly? | +| :--- | :--- | :--- | +| avx2 | `-C target_feature=+avx2` | no | +| avx512 | `-C target_feature=+avx512ifma,+avx512vl` | yes | -The AVX512 backend requires Rust nightly. When compiled on a non-nightly -compiler it will always be disabled. +If compiled on a non-nightly compiler, `curve25519-dalek` will not include AVX512 code, and therefore will never select it at runtime. # Documentation