From 3862e120468513ab7faa50afe5d8775fc678f25a Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Thu, 5 Dec 2019 09:22:57 -0800 Subject: [PATCH] ed25519: Perform partial reduction check on `Signature` Ensures that the three highest bits of the `s` scalar component of an Ed25519 signature are unset. This doesn't ensure that `s` is fully reduced (which would require a full reduction check in the event that the 4th most significant bit is set), however it will catch a number of invalid signatures relatively cheaply. Inspired by: https://github.com/dalek-cryptography/ed25519-dalek/pull/99 --- ed25519/src/lib.rs | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/ed25519/src/lib.rs b/ed25519/src/lib.rs index a39f643..8e18c14 100644 --- a/ed25519/src/lib.rs +++ b/ed25519/src/lib.rs @@ -90,16 +90,25 @@ impl<'a> TryFrom<&'a [u8]> for Signature { type Error = Error; fn try_from(bytes: &'a [u8]) -> Result { - // can't use `try_from` ourselves here because core array types only - // have TryFrom trait implementations for lengths 0..=32 - // TODO(tarcieri): switch to `TryFrom` after const generics are available - if bytes.len() == SIGNATURE_LENGTH { - let mut arr = [0u8; SIGNATURE_LENGTH]; - arr.copy_from_slice(bytes); - Ok(Signature(arr)) - } else { - Err(Error::new()) + if bytes.len() != SIGNATURE_LENGTH { + return Err(Error::new()); } + + // Perform a partial reduction check on the signature's `s` scalar. + // When properly reduced, at least the three highest bits of the scalar + // will be unset so as to fit within the order of ~2^(252.5). + // + // This doesn't ensure that `s` is fully reduced (which would require a + // full reduction check in the event that the 4th most significant bit + // is set), however it will catch a number of invalid signatures + // relatively inexpensively. + if bytes[SIGNATURE_LENGTH - 1] & 0b1110_0000 != 0 { + return Err(Error::new()); + } + + let mut arr = [0u8; SIGNATURE_LENGTH]; + arr.copy_from_slice(bytes); + Ok(Signature(arr)) } }