From 6ce6519287cefcaa19db4137be1c1f628feb98fc Mon Sep 17 00:00:00 2001 From: Cheng XU Date: Mon, 21 Sep 2020 19:16:01 -0700 Subject: [PATCH 1/9] fix serde in no_std --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 94d9f96..837a0e8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ merlin = { version = "2", default-features = false, optional = true } rand = { version = "0.7", default-features = false, optional = true } rand_core = { version = "0.5", default-features = false, optional = true } serde_crate = { package = "serde", version = "1.0", default-features = false, optional = true } -serde_bytes = { version = "0.11", optional = true } +serde_bytes = { version = "0.11", default-features = false, features = ["alloc"], optional = true } sha2 = { version = "0.9", default-features = false } zeroize = { version = "1", default-features = false, features = ["zeroize_derive"] } From da6c7e114f464d270079960556517e2ea6ea9ffb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Wed, 14 Oct 2020 15:13:34 -0400 Subject: [PATCH 2/9] [test-only] Add test showing the non-repudiation property of the signature verifications used in `PublicKey::verify` and `PublicKey::verify_strict`. This PR is a follow-up of #98, which aims to demonstrate the issue brought by small-order public keys. It shows an example of crafting a (public_key, signature) that verifies against two distinct messages using `verify`, but fails using `verify_strict`. This has consequences on the possibility to repudiate a signed contract of blockchain transactions. For more details, see: https://eprint.iacr.org/2020/1244 Joint work with @kchalkias @valerini --- tests/ed25519.rs | 74 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/tests/ed25519.rs b/tests/ed25519.rs index 696e287..0a403be 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -28,7 +28,10 @@ use sha2::Sha512; #[cfg(test)] mod vectors { + use curve25519_dalek::{edwards::EdwardsPoint, scalar::Scalar}; use ed25519::signature::Signature as _; + use sha2::{digest::Digest, Sha512}; + use std::convert::TryFrom; use std::io::BufReader; use std::io::BufRead; @@ -112,6 +115,77 @@ mod vectors { assert!(keypair.verify_prehashed(prehash_for_verifying, None, &sig2).is_ok(), "Could not verify ed25519ph signature!"); } + + // Taken from curve25519_dalek::constants::EIGHT_TORSION[4] + const EIGHT_TORSION_4: [u8; 32] = [ + 236, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127, + ]; + + fn compute_hram(message: &[u8], pub_key: &EdwardsPoint, signature_r: &EdwardsPoint) -> Scalar { + let k_bytes = Sha512::default() + .chain(&signature_r.compress().as_bytes()) + .chain(&pub_key.compress().as_bytes()[..]) + .chain(&message); + let mut k_output = [0u8; 64]; + k_output.copy_from_slice(k_bytes.finalize().as_slice()); + Scalar::from_bytes_mod_order_wide(&k_output) + } + + fn serialize_signature(r: &EdwardsPoint, s: &Scalar) -> Vec { + [&r.compress().as_bytes()[..], &s.as_bytes()[..]].concat() + } + + #[test] + fn repudiation() { + use curve25519_dalek::traits::IsIdentity; + use std::ops::Neg; + + let message1 = b"Send 100 USD to Alice"; + let message2 = b"Send 100000 USD to Alice"; + + // Pick a random Scalar + fn non_null_scalar() -> Scalar { + let mut rng = rand::rngs::OsRng; + let mut s_candidate = Scalar::random(&mut rng); + while s_candidate == Scalar::zero() { + s_candidate = Scalar::random(&mut rng); + } + s_candidate + } + let mut s: Scalar = non_null_scalar(); + + fn pick_r_and_pubkey(s: Scalar) -> (EdwardsPoint, EdwardsPoint) { + let r0 = s * curve25519_dalek::constants::ED25519_BASEPOINT_POINT; + // Pick a torsion point of order 2 + let pub_key = curve25519_dalek::edwards::CompressedEdwardsY(EIGHT_TORSION_4) + .decompress() + .unwrap(); + let r = r0 + pub_key.neg(); + (r, pub_key) + } + + let (mut r, mut pub_key) = pick_r_and_pubkey(s); + + while !(pub_key.neg() + compute_hram(message1, &pub_key, &r) * pub_key).is_identity() + || !(pub_key.neg() + compute_hram(message2, &pub_key, &r) * pub_key).is_identity() + { + s = non_null_scalar(); + let key = pick_r_and_pubkey(s); + r = key.0; + pub_key = key.1; + } + + let signature = serialize_signature(&r, &s); + let pk = PublicKey::from_bytes(&pub_key.compress().as_bytes()[..]).unwrap(); + let sig = Signature::try_from(&signature[..]).unwrap(); + // The same signature verifies for both messages + assert!(pk.verify(message1, &sig).is_ok() && pk.verify(message2, &sig).is_ok()); + // But not with a strict signature: verify_strict refuses small order keys + assert!( + pk.verify_strict(message1, &sig).is_err() || pk.verify_strict(message2, &sig).is_err() + ); + } } #[cfg(test)] From ce5ff276814aa508030d0c9ff296b1fffc180635 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 28 Oct 2020 00:04:15 +0000 Subject: [PATCH 3/9] Make serde_bytes/alloc dependent on alloc feature. Fixup for PR #149. --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 837a0e8..7be49e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ merlin = { version = "2", default-features = false, optional = true } rand = { version = "0.7", default-features = false, optional = true } rand_core = { version = "0.5", default-features = false, optional = true } serde_crate = { package = "serde", version = "1.0", default-features = false, optional = true } -serde_bytes = { version = "0.11", default-features = false, features = ["alloc"], optional = true } +serde_bytes = { version = "0.11", default-features = false, optional = true } sha2 = { version = "0.9", default-features = false } zeroize = { version = "1", default-features = false, features = ["zeroize_derive"] } @@ -51,7 +51,7 @@ harness = false [features] default = ["std", "rand", "u64_backend"] std = ["curve25519-dalek/std", "ed25519/std", "serde_crate/std", "sha2/std", "rand/std"] -alloc = ["curve25519-dalek/alloc", "rand/alloc", "zeroize/alloc"] +alloc = ["curve25519-dalek/alloc", "rand/alloc", "serde_bytes/alloc", "zeroize/alloc"] nightly = ["curve25519-dalek/nightly"] serde = ["serde_crate", "serde_bytes", "ed25519/serde"] batch = ["merlin", "rand"] From bbb8869550084adf5b5762e82b232da398af1662 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 2 Nov 2020 23:57:09 +0000 Subject: [PATCH 4/9] Fix std builds when serde is enabled. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 7be49e4..08ee320 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,7 +50,7 @@ harness = false [features] default = ["std", "rand", "u64_backend"] -std = ["curve25519-dalek/std", "ed25519/std", "serde_crate/std", "sha2/std", "rand/std"] +std = ["curve25519-dalek/std", "ed25519/std", "serde_bytes/std", "serde_crate/std", "sha2/std", "rand/std"] alloc = ["curve25519-dalek/alloc", "rand/alloc", "serde_bytes/alloc", "zeroize/alloc"] nightly = ["curve25519-dalek/nightly"] serde = ["serde_crate", "serde_bytes", "ed25519/serde"] From c12cf4862388cbe801e195e8a218ff70da96b028 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Mon, 3 May 2021 16:26:11 -0700 Subject: [PATCH 5/9] Threads the fiat_{u64,u32}_backend features in the feature set This allows the fiat backends introduced in [curve25519-dalek/#342](https://github.com/dalek-cryptography/curve25519-dalek/pull/342) to be used from an ed25519 import without cumbersome overrides. --- Cargo.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 94d9f96..78591d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,4 +62,6 @@ asm = ["sha2/asm"] legacy_compatibility = [] u64_backend = ["curve25519-dalek/u64_backend"] u32_backend = ["curve25519-dalek/u32_backend"] +fiat_u64_backend = ["curve25519-dalek/fiat_u64_backend"] +fiat_u32_backend = ["curve25519-dalek/fiat_u32_backend"] simd_backend = ["curve25519-dalek/simd_backend"] From 29932412f8d05f9d49c6ca6aea0dc34b84d8c580 Mon Sep 17 00:00:00 2001 From: Matteo Monti Date: Sat, 29 May 2021 17:38:14 +0200 Subject: [PATCH 6/9] Update README.md Fixes minor typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 49766fb..fabd832 100644 --- a/README.md +++ b/README.md @@ -124,7 +124,7 @@ However, if you require this, please see the documentation for the `verify_strict()` function, which does the full checks for the group elements. This functionality is available by default. -If for some reason—although we strongely advise you not to—you need to conform +If for some reason—although we strongly advise you not to—you need to conform to the original specification of ed25519 signatures as in the excerpt from the paper above, you can disable scalar malleability checking via `--features='legacy_compatibility'`. **WE STRONGLY ADVISE AGAINST THIS.** From d94b0f52dc92bcb597bd01dcd163b85979e2a1ed Mon Sep 17 00:00:00 2001 From: gbaranski Date: Sun, 1 Aug 2021 18:29:28 +0200 Subject: [PATCH 7/9] fix: remove rust-analyzer breaking line --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 88dfc93..6749e55 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -235,7 +235,6 @@ #![warn(future_incompatible)] #![deny(missing_docs)] // refuse to compile if documentation is missing -#![cfg(not(test))] #![forbid(unsafe_code)] #[cfg(any(feature = "std", test))] From c5fb9325615eaa1f4cbeb3175d1ab7ee0563b113 Mon Sep 17 00:00:00 2001 From: gbaranski Date: Sun, 1 Aug 2021 19:28:40 +0200 Subject: [PATCH 8/9] fix: stop forbidding unsafe in tests --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 6749e55..c8ee87d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -235,7 +235,7 @@ #![warn(future_incompatible)] #![deny(missing_docs)] // refuse to compile if documentation is missing -#![forbid(unsafe_code)] +#![cfg_attr(not(test), forbid(unsafe_code))] #[cfg(any(feature = "std", test))] #[macro_use] From 10cef4982421c7bc062df510d5e6ee15b05f75e3 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Sep 2021 00:45:42 +0000 Subject: [PATCH 9/9] Add CI via Github actions. --- .github/workflows/rust.yml | 131 +++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 +- 2 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/rust.yml diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml new file mode 100644 index 0000000..79571cc --- /dev/null +++ b/.github/workflows/rust.yml @@ -0,0 +1,131 @@ +name: Rust + +on: + push: + branches: [ '*' ] + pull_request: + branches: [ main, develop ] + +env: + CARGO_TERM_COLOR: always + +jobs: + test-u32: + name: Test u32 backend + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + - uses: actions-rs/cargo@v1 + with: + command: test + args: --no-default-features --features "std u32_backend" + + test-u64: + name: Test u64 backend + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + - uses: actions-rs/cargo@v1 + with: + command: test + args: --no-default-features --features "std u64_backend" + + test-simd: + name: Test simd backend (nightly) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: nightly + override: true + - uses: actions-rs/cargo@v1 + with: + command: test + args: --no-default-features --features "std nightly simd_backend" + + test-defaults-serde: + name: Test default feature selection and serde + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + - uses: actions-rs/cargo@v1 + with: + command: test + args: --features "serde" + + test-alloc-u32: + name: Test no_std+alloc with u32 backend + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + - uses: actions-rs/cargo@v1 + with: + command: test + args: --lib --no-default-features --features "alloc u32_backend" + + test-batch-deterministic: + name: Test deterministic batch verification + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + - uses: actions-rs/cargo@v1 + with: + command: test + args: --features "batch_deterministic" + + msrv: + name: Current MSRV is 1.41 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: 1.41 + override: true + - uses: actions-rs/cargo@v1 + with: + command: build + + bench: + name: Check that benchmarks compile + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + - uses: actions-rs/cargo@v1 + with: + command: bench + # This filter selects no benchmarks, so we don't run any, only build them. + args: --features "batch" "DONTRUNBENCHMARKS" diff --git a/Cargo.toml b/Cargo.toml index 48bb609..053c2a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,7 @@ rand_core = { version = "0.5", default-features = false, optional = true } serde_crate = { package = "serde", version = "1.0", default-features = false, optional = true } serde_bytes = { version = "0.11", default-features = false, optional = true } sha2 = { version = "0.9", default-features = false } -zeroize = { version = "1", default-features = false, features = ["zeroize_derive"] } +zeroize = { version = "~1.3", default-features = false, features = ["zeroize_derive"] } [dev-dependencies] hex = "^0.4"