diff --git a/src/edwards.rs b/src/edwards.rs index 998af8d..d72ec28 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -338,15 +338,20 @@ impl Default for CompressedEdwardsY { impl CompressedEdwardsY { /// Construct a `CompressedEdwardsY` from a slice of bytes. /// - /// # Panics + /// # Returns /// - /// If the input `bytes` slice does not have a length of 32. - pub fn from_slice(bytes: &[u8]) -> CompressedEdwardsY { + /// An `Option` which is `None` if the input `bytes` + /// slice does not have a length of 32. + pub fn from_slice(bytes: &[u8]) -> Option { + if bytes.len() != 32 { + return None; + } + let mut tmp = [0u8; 32]; tmp.copy_from_slice(bytes); - CompressedEdwardsY(tmp) + Some(CompressedEdwardsY(tmp)) } } diff --git a/src/montgomery.rs b/src/montgomery.rs index 4768451..14957d1 100644 --- a/src/montgomery.rs +++ b/src/montgomery.rs @@ -56,6 +56,7 @@ use field::FieldElement; use scalar::Scalar; use traits::Identity; +use traits::ValidityCheck; use subtle::Choice; use subtle::ConditionallySelectable; @@ -93,6 +94,24 @@ impl PartialEq for MontgomeryPoint { impl Eq for MontgomeryPoint {} +impl ValidityCheck for MontgomeryPoint { + /// Decode the \\(u\\)-coordinate field element and re-encode it + /// to its canonical form to check whether the original was valid. + /// + /// There are no other required checks for the Mongomery form of the curve, + /// as every element in \\( \mathbb{F}\_{q} \\) lies either on the curve or + /// its quadratic twist. (cf. ยง5.2 of "Montgomery Curves and Their + /// Arithmetic" by [Costello and Smith][costello-smith].) + /// + /// [costello-smith]: https://eprint.iacr.org/2017/212.pdf + fn is_valid(&self) -> bool { + let maybe_u: FieldElement = FieldElement::from_bytes(&self.0); + let u: [u8; 32] = maybe_u.to_bytes(); + + u.ct_eq(&self.0).into() + } +} + impl Zeroize for MontgomeryPoint { fn zeroize(&mut self) { self.0.zeroize(); @@ -110,6 +129,29 @@ impl MontgomeryPoint { self.0 } + /// Attempt to create a `MontgomeryPoint` from a slice of bytes. + /// + /// # Returns + /// + /// An `Option` which is `None` if the length of the slice + /// of bytes is not 32, or if the bytes did not represent a canonical + /// `FieldElement`. + pub fn from_slice(bytes: &[u8]) -> Option { + if bytes.len() != 32 { + return None; + } + + let mut array = [0u8; 32]; + array.copy_from_slice(&bytes[..32]); + + let P = MontgomeryPoint(array); + + if P.is_valid() { + return Some(P); + } + None + } + /// Attempt to convert to an `EdwardsPoint`, using the supplied /// choice of sign for the `EdwardsPoint`. /// diff --git a/src/ristretto.rs b/src/ristretto.rs index c4b6170..485c01f 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -230,15 +230,20 @@ impl CompressedRistretto { /// Construct a `CompressedRistretto` from a slice of bytes. /// - /// # Panics + /// # Returns /// - /// If the input `bytes` slice does not have a length of 32. - pub fn from_slice(bytes: &[u8]) -> CompressedRistretto { + /// An `Option` which is `None` if the input `bytes` + /// slice does not have a length of 32. + pub fn from_slice(bytes: &[u8]) -> Option { + if bytes.len() != 32 { + return None; + } + let mut tmp = [0u8; 32]; tmp.copy_from_slice(bytes); - CompressedRistretto(tmp) + Some(CompressedRistretto(tmp)) } /// Attempt to decompress to an `RistrettoPoint`.