diff --git a/ed448-goldilocks/src/decaf/points.rs b/ed448-goldilocks/src/decaf/points.rs index a090cb30a..7683b0c4b 100644 --- a/ed448-goldilocks/src/decaf/points.rs +++ b/ed448-goldilocks/src/decaf/points.rs @@ -535,43 +535,32 @@ impl CompressedDecaf { /// Decompress a point if it is valid pub fn decompress(&self) -> CtOption { - let s = FieldElement::from_bytes(&self.0); - //XX: Check for canonical encoding and sign, - // Copied this check from Dalek: The From_bytes function does not throw an error, if the bytes exceed the prime. - // However, to_bytes reduces the Field element before serialising - // So we can use to_bytes -> from_bytes and if the representations are the same, then the element was already in reduced form - let s_bytes_check = s.to_bytes(); - let s_encoding_is_canonical = s_bytes_check[..].ct_eq(&self.0); - let s_is_negative = s.is_negative(); - // if s_encoding_is_canonical.unwrap_u8() == 0u8 || s.is_negative().unwrap_u8() == 1u8 { - // return None; - // } - - let ss = s.square(); - let u1 = FieldElement::ONE - ss; - let u2 = FieldElement::ONE + ss; - let u1_sqr = u1.square(); - - let v = ss * (FieldElement::NEG_FOUR_TIMES_TWISTED_D) + u1_sqr; // XXX: constantify please - - let (I, ok) = (v * u1_sqr).inverse_square_root(); - - let Dx = I * u1; - let Dxs = s.double() * Dx; - - let mut X = (Dxs * I) * v; - let k = Dxs * FieldElement::DECAF_FACTOR; - X.conditional_negate(k.is_negative()); - - let Y = Dx * u2; - let Z = FieldElement::ONE; - let T = X * Y; - let pt = ExtendedPoint { X, Y, Z, T }; - - CtOption::new( - DecafPoint(pt), - ok & pt.is_on_curve() & s_encoding_is_canonical & !s_is_negative, - ) + FieldElement::from_repr(&self.0).and_then(|s| { + let s_is_negative = s.is_negative(); + + let ss = s.square(); + let u1 = FieldElement::ONE - ss; + let u2 = FieldElement::ONE + ss; + let u1_sqr = u1.square(); + + let v = ss * (FieldElement::NEG_FOUR_TIMES_TWISTED_D) + u1_sqr; // XXX: constantify please + + let (I, ok) = (v * u1_sqr).inverse_square_root(); + + let Dx = I * u1; + let Dxs = s.double() * Dx; + + let mut X = (Dxs * I) * v; + let k = Dxs * FieldElement::DECAF_FACTOR; + X.conditional_negate(k.is_negative()); + + let Y = Dx * u2; + let Z = FieldElement::ONE; + let T = X * Y; + let pt = ExtendedPoint { X, Y, Z, T }; + + CtOption::new(DecafPoint(pt), ok & pt.is_on_curve() & !s_is_negative) + }) } /// Get the bytes of this compressed point diff --git a/ed448-goldilocks/src/edwards/affine.rs b/ed448-goldilocks/src/edwards/affine.rs index 9aadffdc4..c9374381b 100644 --- a/ed448-goldilocks/src/edwards/affine.rs +++ b/ed448-goldilocks/src/edwards/affine.rs @@ -391,25 +391,24 @@ impl CompressedEdwardsY { pub fn decompress_unchecked(&self) -> CtOption { // Safe to unwrap here as the underlying data structure is a slice let (sign, b) = self.0.split_last().expect("slice is non-empty"); + let b_bytes = b.try_into().expect("slice is the right size"); - let mut y_bytes: [u8; 56] = [0; 56]; - y_bytes.copy_from_slice(b); + FieldElement::from_repr(b_bytes).and_then(|y| { + // Recover x using y + let yy = y.square(); + let dyy = FieldElement::EDWARDS_D * yy; + let numerator = FieldElement::ONE - yy; + let denominator = FieldElement::ONE - dyy; - // Recover x using y - let y = FieldElement::from_bytes(&y_bytes); - let yy = y.square(); - let dyy = FieldElement::EDWARDS_D * yy; - let numerator = FieldElement::ONE - yy; - let denominator = FieldElement::ONE - dyy; + let (mut x, is_res) = FieldElement::sqrt_ratio(&numerator, &denominator); - let (mut x, is_res) = FieldElement::sqrt_ratio(&numerator, &denominator); + // Compute correct sign of x + let compressed_sign_bit = Choice::from(sign >> 7); + let is_negative = x.is_negative(); + x.conditional_negate(compressed_sign_bit ^ is_negative); - // Compute correct sign of x - let compressed_sign_bit = Choice::from(sign >> 7); - let is_negative = x.is_negative(); - x.conditional_negate(compressed_sign_bit ^ is_negative); - - CtOption::new(AffinePoint { x, y }, is_res) + CtOption::new(AffinePoint { x, y }, is_res) + }) } /// Attempt to decompress to an `AffinePoint`.