### Cross-compilation Example Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/curve25519-dalek/README.md Example of cross-compiling for a 32-bit target to utilize the 32-bit serial backend. ```console sudo apt install gcc-multilib # (or whatever package manager you use) rustup target add i686-unknown-linux-gnu cargo build --target i686-unknown-linux-gnu ``` -------------------------------- ### Implementing Trait with Target Feature Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/curve25519-dalek-derive/README.md This example demonstrates how `#[target_feature]` can be used within a trait implementation for specific SIMD instruction sets like AVX. ```rust trait Backend { unsafe fn sum(input: &[u32]) -> u32; } struct AVX; # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] impl Backend for AVX { #[target_feature(enable = "avx")] unsafe fn sum(xs: &[u32]) -> u32 { // ... todo!(); } } struct AVX2; # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] impl Backend for AVX2 { #[target_feature(enable = "avx2")] unsafe fn sum(xs: &[u32]) -> u32 { // ... 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 } ``` -------------------------------- ### Run Benchmarks with Batch Feature Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/ed25519-dalek/README.md Execute benchmarks using criterion.rs, enabling the 'batch' feature for enhanced performance testing. This command assumes you have Rust and Cargo installed. ```sh cargo bench --features "batch" ``` -------------------------------- ### Using `unsafe_target_feature` Macro Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/curve25519-dalek-derive/README.md This example demonstrates the `unsafe_target_feature` macro from the curve25519-dalek-derive crate, which allows marking safe functions with target features without requiring the function itself to be unsafe. ```rust use curve25519_dalek_derive::unsafe_target_feature; // No `unsafe` on the function itself! # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] #[unsafe_target_feature("avx2")] fn func() {} ``` -------------------------------- ### Trait Implementation with `#[target_feature]` (Compile Fail) Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/curve25519-dalek-derive/README.md This example illustrates a compile-time error that occurs when trying to apply `#[target_feature]` to a method within a trait implementation that is not marked as unsafe in the original trait definition. ```rust 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 } } ``` -------------------------------- ### Build Regular Documentation Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/curve25519-dalek/README.md Use this command to build the standard documentation for the curve25519-dalek library. ```sh make doc ``` -------------------------------- ### Build Internal Documentation Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/curve25519-dalek/README.md Use this command to build documentation that includes private items for the curve25519-dalek library. ```sh make doc-internal ``` -------------------------------- ### Manual Backend Selection in Cargo Config Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/curve25519-dalek/README.md Alternatively, configure the backend selection in ~/.cargo/config. Replace BACKEND with the desired backend. ```toml [build] rustflags = ['--cfg=curve25519_dalek_backend="BACKEND"'] ``` -------------------------------- ### Manual Backend Selection Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/curve25519-dalek/README.md Force the crate to compile with specific backend support using RUSTFLAGS. Replace BACKEND with the desired backend (e.g., 'serial', 'fiat', 'simd', 'avx512'). ```sh RUSTFLAGS='--cfg curve25519_dalek_backend="BACKEND"' ``` -------------------------------- ### Run Benchmarks with Criterion.rs Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/curve25519-dalek/README.md Execute performance benchmarks using the criterion.rs framework. Ensure the 'rand_core' feature is enabled for benchmarking. ```sh cargo bench --features "rand_core" ``` ```sh export RUSTFLAGS='-C target_cpu=native' ``` ```sh cargo +nightly bench --features "rand_core" ``` -------------------------------- ### Entry Point for SIMD Feature Detection Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/curve25519-dalek-derive/README.md An entry point function that detects available x86 CPU features at runtime and calls the appropriate SIMD-optimized function. It prioritizes newer features like AVX512IFMA. ```rust #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 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!(); } ``` -------------------------------- ### Run Benchmarks with Native Target CPU Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/ed25519-dalek/README.md Run benchmarks using the nightly toolchain and setting RUSTFLAGS to target the native CPU. This optimizes for the specific architecture of the machine running the benchmarks. ```sh export RUSTFLAGS='-C target_cpu=native' cargo +nightly bench --features "batch" ``` -------------------------------- ### HWCD'08 Unified Addition Algorithm Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/curve25519-dalek/docs/parallel-formulas.md This table presents the parallel operations for the unified addition algorithm as described in the HWCD paper. It shows the steps for adding two points in parallel. ```pseudocode \( R_1 \gets Y_1 - X_1 \) | \( R_2 \gets Y_2 - X_2 \) | \( R_3 \gets Y_1 + X_1 \) | \( R_4 \gets Y_2 + X_2 \) \ \( R_5 \gets R_1 R_2 \) | \( R_6 \gets R_3 R_4 \) | \( R_7 \gets T_1 T_2 \) | \( R_8 \gets Z_1 Z_2 \) \ idle | idle | \( R_7 \gets k R_7 \) | \( R_8 \gets 2 R_8 \) \ \( R_1 \gets R_6 - R_5 \) | \( R_2 \gets R_8 - R_7 \) | \( R_3 \gets R_8 + R_7 \) | \( R_4 \gets R_6 + R_5 \) \ \( X_3 \gets R_1 R_2 \) | \( Y_3 \gets R_3 R_4 \) | \( Z_3 \gets R_1 R_4 \) | \( T_3 \gets R_2 R_3 \) | ``` -------------------------------- ### Generate Alice's Ephemeral Keys Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/x25519-dalek/README.md Generates Alice's ephemeral secret and public keys using EphemeralSecret::random() and PublicKey::from(). ```rust use x25519_dalek::{EphemeralSecret, PublicKey}; let alice_secret = EphemeralSecret::random(); let alice_public = PublicKey::from(&alice_secret); ``` -------------------------------- ### Generate Bob's Ephemeral Keys Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/x25519-dalek/README.md Generates Bob's ephemeral secret and public keys using EphemeralSecret::random() and PublicKey::from(). This is a parallel operation to Alice's key generation. ```rust # use x25519_dalek::{EphemeralSecret, PublicKey}; let bob_secret = EphemeralSecret::random(); let bob_public = PublicKey::from(&bob_secret); ``` -------------------------------- ### Field Element Doubling Formulas (Overflow Avoidance) Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/curve25519-dalek/docs/avx2-notes.md Demonstrates the modified doubling formulas that avoid overflow by flipping the sign of S_4 during squaring. This adjustment ensures that all intermediate products remain within acceptable bounds for AVX2 multiplication. ```text X_3 &←& S_8 S_9 ↔ (2.33, 1.60) \\ Y_3 &←& S_5 S_6 ↔ (1.01, 1.60) \\ Z_3 &←& S_8 S_6 ↔ (2.33, 1.60) \\ T_3 &←& S_5 S_9 ↔ (1.01, 1.60) ``` -------------------------------- ### HWCD'08 Doubling Formula Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/curve25519-dalek/docs/parallel-formulas.md This table outlines the parallel operations for a point doubling formula as presented in the HWCD paper. It details the steps and costs associated with each processor. ```pseudocode Processor 1 | Processor 2 | Processor 3 | Processor 4 \ --------------------------------|--------------------------------|--------------------------------|--------------------------------\ idle | idle | idle | \( R_1 \gets X_1 + Y_1 \) \ \( R_2 \gets X_1^2 \) | \( R_3 \gets Y_1^2 \) | \( R_4 \gets Z_1^2 \) | \( R_5 \gets R_1^2 \) \ \( R_6 \gets R_2 + R_3 \) | \( R_7 \gets R_2 - R_3 \) | \( R_4 \gets 2 R_4 \) | idle \ idle | \( R_1 \gets R_4 + R_7 \) | idle | \( R_2 \gets R_6 - R_5 \) \ \( X_3 \gets R_1 R_2 \) | \( Y_3 \gets R_6 R_7 \) | \( T_3 \gets R_2 R_6 \) | \( Z_3 \gets R_1 R_7 \) | ``` -------------------------------- ### Point Readdition Formulas Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/curve25519-dalek/docs/parallel-formulas.md Formulas for re-adding a point P2 to a point P1, involving precomputation of curve constants. This method has the same cost as a standard addition. ```math (S_2' &&,&& S_3' &&,&& Z_2' &&,&& T_2') Gets (d_2 * (Y_2 - X_2) &&,&& d_2 * (Y_1 + X_1) &&,&& 2*d_2 * Z_2 &&,&& 2*d_1 * T_2). ``` ```math (S_0 &&,&& S_1 &&,&& Z_1 &&,&& T_1) Gets (Y_1 - X_1 &&,&& Y_1 + X_1 &&,&& Z_1 &&,&& T_1) ``` ```math (S_8 &&,&& S_9 &&,&& S_10 &&,&& S_11 ) Gets (S_0 * S_2' &&,&& S_1 * S_3' &&,&& Z_1 * Z_2' &&,&& T_1 * T_2') ``` ```math (S_{12} &&,&& S_{13} &&,&& S_{14} &&,&& S_{15}) Gets (S_9 - S_8&&,&& S_9 + S_8&&,&& S_{10} - S_{11}&&,&& S_{10} + S_{11}) ``` ```math (X_3&&,&& Y_3&&,&& Z_3&&,&& T_3) Gets (S_{12} * S_{14}&&,&& S_{15} * S_{13}&&,&& S_{15} * S_{14}&&,&& S_{12} * S_{13}) ``` -------------------------------- ### Field Element Doubling Formulas (Overflow Analysis) Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/curve25519-dalek/docs/avx2-notes.md Presents the non-parallel portion of the doubling formulas and the resulting bit-excesses before and after multiplication. It highlights the overflow issue when computing products like S_8 * S_9. ```text (S_5 &&,&& S_6 &&,&& S_8 &&,&& S_9 ) gets (S_1 + S_2 &&,&& S_1 - S_2 &&,&& S_1 + 2S_3 - S_2 &&,&& S_1 + S_2 - S_4) ``` ```text X_3 &←& S_8 S_9 ↔ (2.33, 2.01) \\ Y_3 &←& S_5 S_6 ↔ (1.01, 1.60) \\ Z_3 &←& S_8 S_6 ↔ (2.33, 1.60) \\ T_3 &←& S_5 S_9 ↔ (1.01, 2.01) ``` -------------------------------- ### Point Doubling Formulas Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/curve25519-dalek/docs/parallel-formulas.md Formulas for doubling a point P, involving squaring and a chain of additions. These formulas are less regular than readdition formulas. ```math (X_1 &&,&& Y_1 &&,&& Z_1 &&,&& S_0) Gets (X_1 &&,&& Y_1 &&,&& Z_1 &&,&& X_1 + Y_1) ``` ```math (S_1 &&,&& S_2 &&,&& S_3 &&,&& S_4 ) Gets (X_1^2 &&,&& Y_1^2&&,&& Z_1^2 &&,&& S_0^2) ``` ```math (S_5 &&,&& S_6 &&,&& S_8 &&,&& S_9 ) Gets (S_1 + S_2 &&,&& S_1 - S_2 &&,&& S_1 + 2*S_3 - S_2 &&,&& S_1 + S_2 - S_4) ``` ```math (X_3 &&,&& Y_3 &&,&& Z_3 &&,&& T_3 ) Gets (S_8 * S_9 &&,&& S_5 * S_6 &&,&& S_8 * S_6 &&,&& S_5 * S_9) ``` -------------------------------- ### Target Feature Flags for SIMD Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/curve25519-dalek/README.md Specify target features for SIMD backends. Use AVX2 for non-nightly builds, and AVX512 flags for nightly builds if required. ```sh -C target_feature=+avx2 ``` ```sh -C target_feature=+avx512ifma,+avx512vl ``` -------------------------------- ### Implementing Trait with `unsafe_target_feature` Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/curve25519-dalek-derive/README.md This code shows how to use the `unsafe_target_feature` macro within a trait implementation, allowing the method to be safe while still enabling specific SIMD features. ```rust use curve25519_dalek_derive::unsafe_target_feature; struct S; # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] #[unsafe_target_feature("avx2")] impl core::ops::Add for S { type Output = S; // No `unsafe` on the function itself! fn add(self, rhs: S) -> S { S } } ``` -------------------------------- ### Alice Computes Shared Secret Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/x25519-dalek/README.md Alice computes the shared secret using her ephemeral secret key and Bob's public key. ```rust use getrandom::{SysRng, rand_core::UnwrapErr}; use x25519_dalek::{EphemeralSecret, PublicKey}; let mut rng = UnwrapErr(SysRng); let alice_secret = EphemeralSecret::random_from_rng(&mut rng); let alice_public = PublicKey::from(&alice_secret); let bob_secret = EphemeralSecret::random_from_rng(&mut rng); let bob_public = PublicKey::from(&bob_secret); let alice_shared_secret = alice_secret.diffie_hellman(&bob_public); ``` -------------------------------- ### Override Backend Word Size Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/curve25519-dalek/README.md Override the word size for 'serial' and 'fiat' backends using RUSTFLAGS. SIZE can be '32' or '64'. ```sh RUSTFLAGS='--cfg curve25519_dalek_bits="SIZE"' ``` -------------------------------- ### AVX2 Data Layout for Field Elements Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/curve25519-dalek/docs/avx2-notes.md Shows the pre-shuffled data layout for a vector of four field elements, enabling efficient unpacking of 32-bit limbs into 64-bit lanes for AVX2 multiplication. This layout is designed to work with `vpunpck[lh]dq` instructions. ```text (a0 b0 a1 b1 c0 d0 c1 d1) (a2 b2 a3 b3 c2 d2 c3 d3) (a4 b4 a5 b5 c4 d4 c5 d5) (a6 b6 a7 b7 c6 d6 c7 d7) (a8 b8 a9 b9 c8 d8 c9 d9) ``` -------------------------------- ### Bob Computes Shared Secret Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/x25519-dalek/README.md Bob computes the shared secret using his ephemeral secret key and Alice's public key. This should result in the same shared secret as Alice computed. ```rust use getrandom::{SysRng, rand_core::UnwrapErr}; use x25519_dalek::{EphemeralSecret, PublicKey}; let mut rng = UnwrapErr(SysRng); let alice_secret = EphemeralSecret::random_from_rng(&mut rng); let alice_public = PublicKey::from(&alice_secret); let bob_secret = EphemeralSecret::random_from_rng(&mut rng); let bob_public = PublicKey::from(&bob_secret); let bob_shared_secret = bob_secret.diffie_hellman(&alice_public); ``` -------------------------------- ### Specify Version Range in Cargo.toml Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/curve25519-dalek/README.md Use a version range for curve25519-dalek in Cargo.toml when opting into SemVer-exempted features. ```toml curve25519-dalek = ">= 5.0, < 5.2" ``` -------------------------------- ### AVX2 Vectorized Field Element Multiplication Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/curve25519-dalek/docs/avx2-notes.md Illustrates the concept of 4-wide multiplication using AVX2 lanes, where each 64-bit lane handles one field element's multiplication. This requires specific data shuffling for efficient unpacking. ```text (a1 ?? b1 ?? c1 ?? d1 ??) (a2 ?? b2 ?? c2 ?? d2 ??) (a1*a2 b1*b2 c1*c2 d1*d2) ``` -------------------------------- ### Add curve25519-dalek to Cargo.toml Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/curve25519-dalek/README.md Add this to your project's Cargo.toml to include curve25519-dalek as a dependency. ```toml curve25519-dalek = "5.0.0" ``` -------------------------------- ### Add x25519-dalek to Cargo.toml Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/x25519-dalek/README.md Add this to your project's Cargo.toml to include the x25519-dalek crate. ```toml [dependencies] x25519-dalek = "3.0.0" ``` -------------------------------- ### Verify Shared Secrets Match Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/x25519-dalek/README.md Asserts that the shared secrets computed by Alice and Bob are identical by comparing their byte representations. ```rust use getrandom::{SysRng, rand_core::UnwrapErr}; use x25519_dalek::{EphemeralSecret, PublicKey}; let mut rng = UnwrapErr(SysRng); let alice_secret = EphemeralSecret::random_from_rng(&mut rng); let alice_public = PublicKey::from(&alice_secret); let bob_secret = EphemeralSecret::random_from_rng(&mut rng); let bob_public = PublicKey::from(&bob_secret); let alice_shared_secret = alice_secret.diffie_hellman(&bob_public); let bob_shared_secret = bob_secret.diffie_hellman(&alice_public); assert_eq!(alice_shared_secret.as_bytes(), bob_shared_secret.as_bytes()); ``` -------------------------------- ### Specializing Modules with `unsafe_target_feature_specialize` Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/curve25519-dalek-derive/README.md This snippet shows the usage of the `unsafe_target_feature_specialize` macro, which is used to generate specialized copies of a module for each target feature. ```rust use curve25519_dalek_derive::unsafe_target_feature_specialize; ``` -------------------------------- ### Modified Parallel Addition Formula Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/curve25519-dalek/docs/parallel-formulas.md This section details a modified parallel addition formula designed for SIMD efficiency. It uses temporary variables S_i and involves multiplications by curve constants d_1 and d_2. ```pseudocode (S_0 &&,&& S_1 &&,&& S_2 &&,&& S_3 ) &← (Y_1 - X_1&&,&& Y_1 + X_1&&,&& Y_2 - X_2&&,&& Y_2 + X_2) (S_4 &&,&& S_5 &&,&& S_6 &&,&& S_7 ) &← (S_0 \cdot S_2&&,&& S_1 \cdot S_3&&,&& Z_1 \cdot Z_2&&,&& T_1 \cdot T_2) (S_8 &&,&& S_9 &&,&& S_{10} &&,&& S_{11} ) &← (d_2 \cdot S_4 &&,&& d_2 \cdot S_5 &&,&& 2 d_2 \cdot S_6 &&,&& 2 d_1 \cdot S_7 ) (S_{12} &&,&& S_{13} &&,&& S_{14} &&,&& S_{15}) &← (S_9 - S_8&&,&& S_9 + S_8&&,&& S_{10} - S_{11}&&,&& S_{10} + S_{11}) (X_3&&,&& Y_3&&,&& Z_3&&,&& T_3) &← (S_{12} \cdot S_{14}&&,&& S_{15} \cdot S_{13}&&,&& S_{15} \cdot S_{14}&&,&& S_{12} \cdot S_{13}) ``` -------------------------------- ### Disable Default Features with Cargo CLI Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/curve25519-dalek/README.md Use the '--no-default-features' flag when running cargo to exclude default features for curve25519-dalek. ```bash cargo build --no-default-features ``` -------------------------------- ### Conditional SIMD Module Definition Source: https://github.com/dalek-cryptography/curve25519-dalek/blob/main/curve25519-dalek-derive/README.md Defines a module with constants specialized for different x86 target features (SSE2, AVX2, AVX512IFMA). This allows the compiler to select the most performant implementation based on the CPU. ```rust #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] #[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() { /* ... */ } } ```