diff --git a/Cargo.lock b/Cargo.lock index 950df211..aafa185d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -45,7 +45,7 @@ dependencies = [ [[package]] name = "elliptic-curve" version = "0.5.0-pre" -source = "git+https://github.com/RustCrypto/traits#9bab4e821421e384096e86e92278ef20fb8f4621" +source = "git+https://github.com/RustCrypto/traits#048fb8f85a9b4cbbb29a2302a9a3fc596526fdcf" dependencies = [ "generic-array", "rand_core", diff --git a/ecdsa/src/lib.rs b/ecdsa/src/lib.rs index 41b7d647..d2adbedb 100644 --- a/ecdsa/src/lib.rs +++ b/ecdsa/src/lib.rs @@ -62,7 +62,7 @@ use core::{ fmt::{self, Debug}, ops::Add, }; -use elliptic_curve::ElementBytes; +use elliptic_curve::{Arithmetic, ElementBytes, FromBytes}; use generic_array::{typenum::Unsigned, ArrayLength, GenericArray}; /// Size of a fixed sized signature for the given elliptic curve. @@ -139,6 +139,32 @@ where } } +impl Signature +where + C: Curve + Arithmetic, + C::Scalar: NormalizeLow, + SignatureSize: ArrayLength, +{ + /// Normalize signature into "low S" form as described in + /// [BIP 0062: Dealing with Malleability][1]. + /// + /// [1]: https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki + pub fn normalize_s(&mut self) -> Result<(), Error> { + let s_bytes = GenericArray::from_mut_slice(&mut self.bytes[C::ElementSize::to_usize()..]); + let s_option = C::Scalar::from_bytes(s_bytes); + + // Not constant time, but we're operating on public values + if s_option.is_some().into() { + let mut s = s_option.unwrap(); + s.normalize_low(); + s_bytes.copy_from_slice(&s.into()); + Ok(()) + } else { + Err(Error::new()) + } + } +} + impl signature::Signature for Signature where SignatureSize: ArrayLength, @@ -206,3 +232,13 @@ where Signature { bytes } } } + +/// Normalize a scalar (i.e. ECDSA S) to the lower half the field, as described +/// in [BIP 0062: Dealing with Malleability][1]. +/// +/// [1]: https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki +pub trait NormalizeLow { + /// Normalize scalar to the lower half of the field (i.e. negate it if it's + /// larger than half the curve's order) + fn normalize_low(&mut self); +}