src/signature.rs (143 lines of code) (raw):

// -*- mode: rust; -*- // // This file is part of ed25519-dalek. // Copyright (c) 2017-2019 isis lovecruft // See LICENSE for licensing information. // // Authors: // - isis agora lovecruft <isis@patternsinthevoid.net> //! An ed25519 signature. use core::convert::TryFrom; use core::fmt::Debug; use curve25519_dalek_fiat::edwards::CompressedEdwardsY; use curve25519_dalek_fiat::scalar::Scalar; use ed25519::signature::Signature as _; use crate::constants::*; use crate::errors::*; /// An ed25519 signature. /// /// # Note /// /// These signatures, unlike the ed25519 signature reference implementation, are /// "detached"—that is, they do **not** include a copy of the message which has /// been signed. #[allow(non_snake_case)] #[derive(Copy, Eq, PartialEq)] pub(crate) struct InternalSignature { /// `R` is an `EdwardsPoint`, formed by using an hash function with /// 512-bits output to produce the digest of: /// /// - the nonce half of the `ExpandedSecretKey`, and /// - the message to be signed. /// /// This digest is then interpreted as a `Scalar` and reduced into an /// element in ℤ/lℤ. The scalar is then multiplied by the distinguished /// basepoint to produce `R`, and `EdwardsPoint`. pub(crate) R: CompressedEdwardsY, /// `s` is a `Scalar`, formed by using an hash function with 512-bits output /// to produce the digest of: /// /// - the `r` portion of this `Signature`, /// - the `PublicKey` which should be used to verify this `Signature`, and /// - the message to be signed. /// /// This digest is then interpreted as a `Scalar` and reduced into an /// element in ℤ/lℤ. pub(crate) s: Scalar, } impl Clone for InternalSignature { fn clone(&self) -> Self { *self } } impl Debug for InternalSignature { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { write!(f, "Signature( R: {:?}, s: {:?} )", &self.R, &self.s) } } #[cfg(feature = "legacy_compatibility")] #[inline(always)] fn check_scalar(bytes: [u8; 32]) -> Result<Scalar, SignatureError> { // The highest 3 bits must not be set. No other checking for the // remaining 2^253 - 2^252 + 27742317777372353535851937790883648493 // potential non-reduced scalars is performed. // // This is compatible with ed25519-donna and libsodium when // -DED25519_COMPAT is NOT specified. if bytes[31] & 224 != 0 { return Err(InternalError::ScalarFormatError.into()); } Ok(Scalar::from_bits(bytes)) } #[cfg(not(feature = "legacy_compatibility"))] #[inline(always)] fn check_scalar(bytes: [u8; 32]) -> Result<Scalar, SignatureError> { // Since this is only used in signature deserialisation (i.e. upon // verification), we can do a "succeed fast" trick by checking that the most // significant 4 bits are unset. If they are unset, we can succeed fast // because we are guaranteed that the scalar is fully reduced. However, if // the 4th most significant bit is set, we must do the full reduction check, // as the order of the basepoint is roughly a 2^(252.5) bit number. // // This succeed-fast trick should succeed for roughly half of all scalars. if bytes[31] & 240 == 0 { return Ok(Scalar::from_bits(bytes)) } match Scalar::from_canonical_bytes(bytes) { None => return Err(InternalError::ScalarFormatError.into()), Some(x) => return Ok(x), }; } impl InternalSignature { /// Convert this `Signature` to a byte array. #[inline] pub fn to_bytes(&self) -> [u8; SIGNATURE_LENGTH] { let mut signature_bytes: [u8; SIGNATURE_LENGTH] = [0u8; SIGNATURE_LENGTH]; signature_bytes[..32].copy_from_slice(&self.R.as_bytes()[..]); signature_bytes[32..].copy_from_slice(&self.s.as_bytes()[..]); signature_bytes } /// Construct a `Signature` from a slice of bytes. /// /// # Scalar Malleability Checking /// /// As originally specified in the ed25519 paper (cf. the "Malleability" /// section of the README in this repo), no checks whatsoever were performed /// for signature malleability. /// /// Later, a semi-functional, hacky check was added to most libraries to /// "ensure" that the scalar portion, `s`, of the signature was reduced `mod /// \ell`, the order of the basepoint: /// /// ```ignore /// if signature.s[31] & 224 != 0 { /// return Err(); /// } /// ``` /// /// This bit-twiddling ensures that the most significant three bits of the /// scalar are not set: /// /// ```python,ignore /// >>> 0b00010000 & 224 /// 0 /// >>> 0b00100000 & 224 /// 32 /// >>> 0b01000000 & 224 /// 64 /// >>> 0b10000000 & 224 /// 128 /// ``` /// /// However, this check is hacky and insufficient to check that the scalar is /// fully reduced `mod \ell = 2^252 + 27742317777372353535851937790883648493` as /// it leaves us with a guanteed bound of 253 bits. This means that there are /// `2^253 - 2^252 + 2774231777737235353585193779088364849311` remaining scalars /// which could cause malleabilllity. /// /// RFC8032 [states](https://tools.ietf.org/html/rfc8032#section-5.1.7): /// /// > To verify a signature on a message M using public key A, [...] /// > first split the signature into two 32-octet halves. Decode the first /// > half as a point R, and the second half as an integer S, in the range /// > 0 <= s < L. Decode the public key A as point A'. If any of the /// > decodings fail (including S being out of range), the signature is /// > invalid. /// /// However, by the time this was standardised, most libraries in use were /// only checking the most significant three bits. (See also the /// documentation for `PublicKey.verify_strict`.) #[inline] pub fn from_bytes(bytes: &[u8]) -> Result<InternalSignature, SignatureError> { if bytes.len() != SIGNATURE_LENGTH { return Err(InternalError::BytesLengthError { name: "Signature", length: SIGNATURE_LENGTH, }.into()); } let mut lower: [u8; 32] = [0u8; 32]; let mut upper: [u8; 32] = [0u8; 32]; lower.copy_from_slice(&bytes[..32]); upper.copy_from_slice(&bytes[32..]); let s: Scalar; match check_scalar(upper) { Ok(x) => s = x, Err(x) => return Err(x), } Ok(InternalSignature { R: CompressedEdwardsY(lower), s: s, }) } } impl TryFrom<&ed25519::Signature> for InternalSignature { type Error = SignatureError; fn try_from(sig: &ed25519::Signature) -> Result<InternalSignature, SignatureError> { InternalSignature::from_bytes(sig.as_bytes()) } } impl From<InternalSignature> for ed25519::Signature { fn from(sig: InternalSignature) -> ed25519::Signature { ed25519::Signature::from_bytes(&sig.to_bytes()).unwrap() } }