anza-cryptography-source/curve25519/solana-ed25519
mrwulf 5f8e70e636 Aeneas-compat: decompress step_2 negate-then-conditional-assign
Same documented rewrite as FieldElement::sqrt_ratio_i: semantically
identical and still constant-time, but avoids subtle's
ConditionallyNegatable blanket impl, which the verification toolchain
cannot translate. Unblocks extracting decompress for the phase-2 full
point-level lift.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 01:41:56 +02:00
..
benches ci: check each feature individually (#18) 2026-05-20 10:23:03 +08:00
docs refactor and merge curve and ed crates (#6) 2026-03-26 08:09:10 -04:00
examples refactor and merge curve and ed crates (#6) 2026-03-26 08:09:10 -04:00
src Aeneas-compat: decompress step_2 negate-then-conditional-assign 2026-07-06 01:41:56 +02:00
tests refactor and merge curve and ed crates (#6) 2026-03-26 08:09:10 -04:00
vendor refactor and merge curve and ed crates (#6) 2026-03-26 08:09:10 -04:00
ACKNOWLEDGEMENTS.md refactor and merge curve and ed crates (#6) 2026-03-26 08:09:10 -04:00
build.rs refactor and merge curve and ed crates (#6) 2026-03-26 08:09:10 -04:00
Cargo.toml Aeneas-compat: verified-verification entry points + serial-pin cfg 2026-07-04 23:00:06 +02:00
CHANGELOG_dalek.md refactor and merge curve and ed crates (#6) 2026-03-26 08:09:10 -04:00
LICENSE refactor and merge curve and ed crates (#6) 2026-03-26 08:09:10 -04:00
Makefile refactor and merge curve and ed crates (#6) 2026-03-26 08:09:10 -04:00
README.md [ed25519] improve docs (#47) 2026-06-11 22:10:13 -04:00
README_dalek.md refactor and merge curve and ed crates (#6) 2026-03-26 08:09:10 -04:00
README_zebra.md [ed25519] improve docs (#47) 2026-06-11 22:10:13 -04:00

curve25519 (solana-ed25519)

A pure-Rust implementation of group operations on Ristretto and Curve25519, forked from curve25519-dalek with HEEA scalar decomposition and a reduced backend set.

For the original curve25519-dalek documentation see README_dalek.md.

This crate is part of the cryptography workspace.


Changes from curve25519-dalek

HEEA Scalar Decomposition

A new HEEADecomposition trait and implementation have been added in:

Given a 256-bit hash scalar h, heea_decompose returns (ρ, τ, flip_h) such that:

flip_h = false:  ρ ≡  τ·h  (mod )
flip_h = true:   ρ ≡ -τ·h  (mod )

This allows verification of sB = R + hA to be rewritten as a 4-point MSM over ~128-bit scalars, reducing the number of point doublings required and yielding roughly ~15% faster verification in practice.

See the TCHES 2025 paper for the full algorithm description.

Reduced Backends

Only the following backends are maintained in this fork:

Backend Selection Notes
serial Automatic fallback Pure Rust, 64-bit word size on 64-bit targets
simd / AVX2 Runtime on x86-64 Vectorised 4-wide field arithmetic
CUDA Opt-in (curve25519-cuda crate) GPU MSM via SPPARK/BLST

The fiat (formally-verified fiat-crypto) and unstable_avx512 backends present in upstream have been removed.


Ed25519 Signatures (ed_sigs)

This crate includes a ZIP-215-compliant Ed25519 signature implementation in the ed_sigs module, forked from ed25519-zebra and extended with HEEA-accelerated verification.

For the original ed25519-zebra documentation see README_zebra.md.

verify_zebra: fast-path signature verification

VerificationKey::verify_zebra is the HEEA implementation used by the default VerificationKey::verify method. Both accept the same arguments and produce identical ZIP-215 results.

The HEEA method (TCHES 2025) transforms the standard 2-point MSM:

[8][s]B = [8]R + [8][h]A     (standard)

into a 4-point MSM over half-size (~128-bit) scalars:

flip_h = false:  τs_lo·B + τs_hi·(2¹²⁸·B) = τ·R + ρ·A
flip_h = true:   τs_lo·B + τs_hi·(2¹²⁸·B) = τ·R - ρ·A

where ρ ≡ τ·h (mod ) when flip_h is false, ρ ≡ -τ·h (mod ) when flip_h is true, and τs = τs_hi·2¹²⁸ + τs_lo. All four scalars are ≤128 bits and the two basepoints (B and 2¹²⁸B) use precomputed lookup tables, giving approximately ~15% faster verification compared to the standard path.

ZIP 215

ZIP-215-compliant Ed25519 validation rules are fully preserved from ed25519-zebra:

  • Non-canonical point encodings are accepted for A and R.
  • s must be a canonical integer less than the group order .
  • The cofactor-cleared equation [8][s]B = [8]R + [8][h]A is used (not the RFC 8032 variant).

See ZIP 215 for full details.


Use

curve25519 = { package = "solana-ed25519", git = "https://github.com/anza-xyz/cryptography" }

Ed25519 signing and verification

use core::convert::TryFrom;
use curve25519::ed_sigs::{SigningKey, VerificationKey};

let msg = b"curve25519-sol";

// Generate key and sign
let sk = SigningKey::from_bytes(&[1u8; 32]);
let sig = sk.sign(msg);
let vk = VerificationKey::from(&sk);

// Standard ZIP-215 verification with heea acceleration
vk.verify(&sig, msg).expect("valid signature");

Batch verification

use curve25519::ed_sigs::batch;

let mut verifier = batch::Verifier::new();
for (vk_bytes, sig, msg) in items {
    verifier.queue((vk_bytes, sig, msg));
}
verifier.verify(rand::thread_rng()).expect("all valid");

HEEA decomposition example

use curve25519::traits::HEEADecomposition;
use curve25519::scalar::Scalar;
use sha2::{Sha512, Digest};

// h is a typical 256-bit hash scalar
let h = Scalar::from_hash(Sha512::new().chain_update(b"some message"));

// Decompose into two ~128-bit scalars
let (rho, tau, flip_h) = h.heea_decompose();
// flip_h == false: rho ≡  tau·h  (mod )
// flip_h == true:  rho ≡ -tau·h  (mod )

Feature Flags

Feature Default? Description
alloc Multiscalar multiplication, batch inversion, batch compress, and the Ed25519 batch module.
zeroize Zeroize for all scalar and point types.
precomputed-tables Precomputed basepoint tables (~400 KB, ~4× faster basepoint mul).
rand_core Scalar::random, RistrettoPoint::random, SigningKey::new, and randomized batch verification.
digest Hash-to-curve, Scalar::from_hash, and Ed25519 hashing.
std Enables std::error::Error impl on ed_sigs::Error.
serde Serialization for all point, scalar, and key types.
pkcs8 PKCS#8 DER encoding/decoding for Ed25519 keys.
pem PEM encoding/decoding for Ed25519 keys (requires pkcs8).
legacy_compatibility Scalar::from_bits (broken arithmetic, use only if required).
group group and ff crate trait impls.
group-bits ff::PrimeFieldBits for Scalar.
lizard Bytestring-to-Ristretto-point injection.

Backends

Serial (default)

Pure-Rust, available on all targets. 64-bit arithmetic on 64-bit platforms.

AVX2 (automatic on x86-64)

Runtime CPU-feature detection via cpufeatures. 4-wide vectorised field elements in radix-25.5 representation. Automatically selected when the CPU supports AVX2; falls through to serial otherwise.

To hard-code AVX2 at compile time:

RUSTFLAGS='-C target-feature=+avx2' cargo build --release

CUDA (opt-in)

See the curve25519-cuda crate. Provides GPU-accelerated multi-scalar multiplication using the SPPARK library.


Safety

All point types enforce validity invariants at the type level (no invalid EdwardsPoint can be constructed). All secret-operand operations use constant-time logic via the [subtle] crate. Variable-time functions are explicitly marked vartime.

The SIMD backend uses unsafe internally for SIMD intrinsics, guarded by runtime CPU-feature checks.


MSRV

Rust 1.85.0 (Edition 2024).


References