Skip to content

Commit

Permalink
Add on-by-default fast crate feature for gating basepoint tables (#251
Browse files Browse the repository at this point in the history
)

* Add on-by-default `fast` crate feature

Disabling the feature reduces overall code size at the cost of
performance, which is useful for e.g. embedded users.

This feature transitively enables the `basepoint-tables` feature in
`curve25519-dalek` where the basepoint tables are actually defined.

* Consolidated a lot of verification code

* Bump `curve25519-dalek`; use `precomputed-tables` feature

The feature name changed in dalek-cryptography/curve25519-dalek#499

Co-authored-by: Michael Rosenberg <[email protected]>
  • Loading branch information
tarcieri and rozbb authored Jan 20, 2023
1 parent 431e699 commit f61e9dc
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 36 deletions.
10 changes: 8 additions & 2 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 = []
Expand Down
60 changes: 28 additions & 32 deletions src/verifying.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]>,
Expand All @@ -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
Expand Down Expand Up @@ -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())
Expand Down Expand Up @@ -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())
Expand Down Expand Up @@ -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())
Expand All @@ -408,12 +408,8 @@ impl Verifier<ed25519::Signature> 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())
Expand Down

0 comments on commit f61e9dc

Please sign in to comment.