diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index d1094a6..befdb39 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -26,13 +26,19 @@ jobs: - uses: dtolnay/rust-toolchain@stable - run: rustup target add ${{ matrix.target }} - run: ${{ matrix.deps }} - - run: cargo test --target ${{ matrix.target }} --no-default-features --lib + - run: cargo test --target ${{ matrix.target }} --no-default-features --lib --tests - run: cargo test --target ${{ matrix.target }} --no-default-features --features alloc --lib + - run: cargo test --target ${{ matrix.target }} --no-default-features --features fast --lib + - run: cargo test --target ${{ matrix.target }} --no-default-features --features rand_core --lib --tests + - run: cargo test --target ${{ matrix.target }} --no-default-features --features alloc,rand_core --lib --tests + - run: cargo test --target ${{ matrix.target }} --no-default-features --features fast,rand_core --lib --tests + - run: cargo test --target ${{ matrix.target }} --no-default-features --features alloc,fast,rand_core --lib --tests - run: cargo test --target ${{ matrix.target }} - run: cargo test --target ${{ matrix.target }} --features batch - - run: cargo test --target ${{ matrix.target }} --features "digest rand_core" + - run: cargo test --target ${{ matrix.target }} --features digest,rand_core - run: cargo test --target ${{ matrix.target }} --features serde - run: cargo test --target ${{ matrix.target }} --features pem + - run: cargo test --target ${{ matrix.target }} --all-features build-simd: name: Test simd backend (nightly) diff --git a/Cargo.lock b/Cargo.lock index 877eb1a..207bfff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -240,7 +240,7 @@ dependencies = [ [[package]] name = "curve25519-dalek" version = "4.0.0-pre.5" -source = "git+https://github.com/dalek-cryptography/curve25519-dalek.git#83f6b149d33c37b8997316cb7a87d8d247b75c3e" +source = "git+https://github.com/dalek-cryptography/curve25519-dalek.git#3effd73307a606e44469a425974f0b7b0eb85899" dependencies = [ "cfg-if", "digest", diff --git a/Cargo.toml b/Cargo.toml index e41609d..064be79 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,12 +51,13 @@ harness = false required-features = ["rand_core"] [features] -default = ["std", "zeroize"] +default = ["fast", "std", "zeroize"] alloc = ["curve25519-dalek/alloc", "ed25519/alloc", "serde?/alloc", "zeroize/alloc"] std = ["alloc", "ed25519/std", "serde?/std", "sha2/std"] asm = ["sha2/asm"] batch = ["alloc", "merlin", "rand_core"] +fast = ["curve25519-dalek/precomputed-tables"] digest = [] # This features turns off stricter checking for scalar malleability in signatures legacy_compatibility = [] diff --git a/src/verifying.rs b/src/verifying.rs index 7879e20..e11d47e 100644 --- a/src/verifying.rs +++ b/src/verifying.rs @@ -169,7 +169,8 @@ impl VerifyingKey { VerifyingKey(compressed, point) } - // A helper function that computes H(R || A || M) as well as its prehashed version + // A helper function that computes H(R || A || M). If `context.is_some()`, this does the + // prehashed variant of the computation using its contents. #[allow(non_snake_case)] fn compute_challenge( context: Option<&[u8]>, @@ -191,6 +192,22 @@ impl VerifyingKey { Scalar::from_hash(h) } + // Helper function for verification. Computes the _expected_ R component of the signature. The + // caller compares this to the real R component. If `context.is_some()`, this does the + // prehashed variant of the computation using its contents. + #[allow(non_snake_case)] + fn recompute_r( + &self, + context: Option<&[u8]>, + signature: &InternalSignature, + M: &[u8], + ) -> EdwardsPoint { + let k = Self::compute_challenge(context, &signature.R, &self.0, M); + let minus_A: EdwardsPoint = -self.1; + // Recall the (non-batched) verification equation: -[k]A + [s]B = R + EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s) + } + /// Verify a `signature` on a `prehashed_message` using the Ed25519ph algorithm. /// /// # Inputs @@ -226,17 +243,10 @@ impl VerifyingKey { "The context must not be longer than 255 octets." ); - let minus_A: EdwardsPoint = -self.1; - let k = Self::compute_challenge( - Some(ctx), - &signature.R, - &self.0, - prehashed_message.finalize().as_slice(), - ); - let R: EdwardsPoint = - EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); + let message = prehashed_message.finalize(); + let expected_R = self.recompute_r(Some(ctx), &signature, &message); - if R.compress() == signature.R { + if expected_R.compress() == signature.R { Ok(()) } else { Err(InternalError::Verify.into()) @@ -323,12 +333,8 @@ impl VerifyingKey { return Err(InternalError::Verify.into()); } - let minus_A: EdwardsPoint = -self.1; - let k = Self::compute_challenge(None, &signature.R, &self.0, message); - let R: EdwardsPoint = - EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); - - if R == signature_R { + let expected_R = self.recompute_r(None, &signature, message); + if expected_R == signature_R { Ok(()) } else { Err(InternalError::Verify.into()) @@ -381,16 +387,10 @@ impl VerifyingKey { return Err(InternalError::Verify.into()); } - let minus_A: EdwardsPoint = -self.1; - let k = Self::compute_challenge( - Some(ctx), - &signature.R, - &self.0, - prehashed_message.finalize().as_slice(), - ); - let R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); + let message = prehashed_message.finalize(); + let expected_R = self.recompute_r(Some(ctx), &signature, &message); - if R == signature_R { + if expected_R == signature_R { Ok(()) } else { Err(InternalError::Verify.into()) @@ -408,12 +408,8 @@ impl Verifier for VerifyingKey { fn verify(&self, message: &[u8], signature: &ed25519::Signature) -> Result<(), SignatureError> { let signature = InternalSignature::try_from(signature)?; - let minus_A: EdwardsPoint = -self.1; - let k = Self::compute_challenge(None, &signature.R, &self.0, message); - let R: EdwardsPoint = - EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); - - if R.compress() == signature.R { + let expected_R = self.recompute_r(None, &signature, message); + if expected_R.compress() == signature.R { Ok(()) } else { Err(InternalError::Verify.into())