diff --git a/bellman/src/groth16/mod.rs b/bellman/src/groth16/mod.rs index 1c50bcb41..8f5d7d4ee 100644 --- a/bellman/src/groth16/mod.rs +++ b/bellman/src/groth16/mod.rs @@ -46,14 +46,18 @@ impl Proof { } pub fn read(mut reader: R) -> io::Result { - let mut g1_repr = ::Compressed::empty(); - let mut g2_repr = ::Compressed::empty(); + let read_g1 = |reader: &mut R| -> io::Result { + let mut g1_repr = ::Compressed::empty(); + reader.read_exact(g1_repr.as_mut())?; - reader.read_exact(g1_repr.as_mut())?; - let a = g1_repr - .into_affine() - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| { + let affine = E::G1Affine::from_compressed(&g1_repr); + let affine = if affine.is_some().into() { + Ok(affine.unwrap()) + } else { + Err(io::Error::new(io::ErrorKind::InvalidData, "invalid G1")) + }; + + affine.and_then(|e| { if e.is_identity().into() { Err(io::Error::new( io::ErrorKind::InvalidData, @@ -62,13 +66,21 @@ impl Proof { } else { Ok(e) } - })?; + }) + }; - reader.read_exact(g2_repr.as_mut())?; - let b = g2_repr - .into_affine() - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| { + let read_g2 = |reader: &mut R| -> io::Result { + let mut g2_repr = ::Compressed::empty(); + reader.read_exact(g2_repr.as_mut())?; + + let affine = E::G2Affine::from_compressed(&g2_repr); + let affine = if affine.is_some().into() { + Ok(affine.unwrap()) + } else { + Err(io::Error::new(io::ErrorKind::InvalidData, "invalid G2")) + }; + + affine.and_then(|e| { if e.is_identity().into() { Err(io::Error::new( io::ErrorKind::InvalidData, @@ -77,22 +89,12 @@ impl Proof { } else { Ok(e) } - })?; + }) + }; - reader.read_exact(g1_repr.as_mut())?; - let c = g1_repr - .into_affine() - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| { - if e.is_identity().into() { - Err(io::Error::new( - io::ErrorKind::InvalidData, - "point at infinity", - )) - } else { - Ok(e) - } - })?; + let a = read_g1(&mut reader)?; + let b = read_g2(&mut reader)?; + let c = read_g1(&mut reader)?; Ok(Proof { a, b, c }) } @@ -155,58 +157,52 @@ impl VerifyingKey { } pub fn read(mut reader: R) -> io::Result { - let mut g1_repr = ::Uncompressed::empty(); - let mut g2_repr = ::Uncompressed::empty(); + let read_g1 = |reader: &mut R| -> io::Result { + let mut g1_repr = ::Uncompressed::empty(); + reader.read_exact(g1_repr.as_mut())?; - reader.read_exact(g1_repr.as_mut())?; - let alpha_g1 = g1_repr - .into_affine() - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + let affine = E::G1Affine::from_uncompressed(&g1_repr); + if affine.is_some().into() { + Ok(affine.unwrap()) + } else { + Err(io::Error::new(io::ErrorKind::InvalidData, "invalid G1")) + } + }; - reader.read_exact(g1_repr.as_mut())?; - let beta_g1 = g1_repr - .into_affine() - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + let read_g2 = |reader: &mut R| -> io::Result { + let mut g2_repr = ::Uncompressed::empty(); + reader.read_exact(g2_repr.as_mut())?; - reader.read_exact(g2_repr.as_mut())?; - let beta_g2 = g2_repr - .into_affine() - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + let affine = E::G2Affine::from_uncompressed(&g2_repr); + if affine.is_some().into() { + Ok(affine.unwrap()) + } else { + Err(io::Error::new(io::ErrorKind::InvalidData, "invalid G2")) + } + }; - reader.read_exact(g2_repr.as_mut())?; - let gamma_g2 = g2_repr - .into_affine() - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; - - reader.read_exact(g1_repr.as_mut())?; - let delta_g1 = g1_repr - .into_affine() - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; - - reader.read_exact(g2_repr.as_mut())?; - let delta_g2 = g2_repr - .into_affine() - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + let alpha_g1 = read_g1(&mut reader)?; + let beta_g1 = read_g1(&mut reader)?; + let beta_g2 = read_g2(&mut reader)?; + let gamma_g2 = read_g2(&mut reader)?; + let delta_g1 = read_g1(&mut reader)?; + let delta_g2 = read_g2(&mut reader)?; let ic_len = reader.read_u32::()? as usize; let mut ic = vec![]; for _ in 0..ic_len { - reader.read_exact(g1_repr.as_mut())?; - let g1 = g1_repr - .into_affine() - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| { - if e.is_identity().into() { - Err(io::Error::new( - io::ErrorKind::InvalidData, - "point at infinity", - )) - } else { - Ok(e) - } - })?; + let g1 = read_g1(&mut reader).and_then(|e| { + if e.is_identity().into() { + Err(io::Error::new( + io::ErrorKind::InvalidData, + "point at infinity", + )) + } else { + Ok(e) + } + })?; ic.push(g1); } @@ -296,13 +292,19 @@ impl Parameters { let mut repr = ::Uncompressed::empty(); reader.read_exact(repr.as_mut())?; - if checked { - repr.into_affine() + let affine = if checked { + E::G1Affine::from_uncompressed(&repr) } else { - repr.into_affine_unchecked() - } - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| { + E::G1Affine::from_uncompressed_unchecked(&repr) + }; + + let affine = if affine.is_some().into() { + Ok(affine.unwrap()) + } else { + Err(io::Error::new(io::ErrorKind::InvalidData, "invalid G1")) + }; + + affine.and_then(|e| { if e.is_identity().into() { Err(io::Error::new( io::ErrorKind::InvalidData, @@ -318,13 +320,19 @@ impl Parameters { let mut repr = ::Uncompressed::empty(); reader.read_exact(repr.as_mut())?; - if checked { - repr.into_affine() + let affine = if checked { + E::G2Affine::from_uncompressed(&repr) } else { - repr.into_affine_unchecked() - } - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| { + E::G2Affine::from_uncompressed_unchecked(&repr) + }; + + let affine = if affine.is_some().into() { + Ok(affine.unwrap()) + } else { + Err(io::Error::new(io::ErrorKind::InvalidData, "invalid G2")) + }; + + affine.and_then(|e| { if e.is_identity().into() { Err(io::Error::new( io::ErrorKind::InvalidData, diff --git a/bellman/src/groth16/tests/dummy_engine.rs b/bellman/src/groth16/tests/dummy_engine.rs index cbfcb7eaa..b85c65f70 100644 --- a/bellman/src/groth16/tests/dummy_engine.rs +++ b/bellman/src/groth16/tests/dummy_engine.rs @@ -1,5 +1,5 @@ use ff::{Field, PrimeField, ScalarEngine}; -use group::{CurveAffine, CurveProjective, EncodedPoint, Group, GroupDecodingError, PrimeGroup}; +use group::{CurveAffine, CurveProjective, EncodedPoint, Group, PrimeGroup}; use pairing::{Engine, PairingCurveAffine}; use rand_core::RngCore; @@ -443,14 +443,6 @@ impl EncodedPoint for FakePoint { unimplemented!() } - fn into_affine(&self) -> Result { - unimplemented!() - } - - fn into_affine_unchecked(&self) -> Result { - unimplemented!() - } - fn from_affine(_: Self::Affine) -> Self { unimplemented!() } @@ -478,6 +470,22 @@ impl CurveAffine for Fr { fn into_projective(&self) -> Self::Projective { *self } + + fn from_compressed(_bytes: &Self::Compressed) -> CtOption { + unimplemented!() + } + + fn from_compressed_unchecked(_bytes: &Self::Compressed) -> CtOption { + unimplemented!() + } + + fn from_uncompressed(_bytes: &Self::Uncompressed) -> CtOption { + unimplemented!() + } + + fn from_uncompressed_unchecked(_bytes: &Self::Uncompressed) -> CtOption { + unimplemented!() + } } impl PairingCurveAffine for Fr { diff --git a/group/src/lib.rs b/group/src/lib.rs index adc47caf6..dac6f474e 100644 --- a/group/src/lib.rs +++ b/group/src/lib.rs @@ -3,11 +3,10 @@ use ff::{Field, PrimeField}; use rand::RngCore; -use std::error::Error; use std::fmt; use std::iter::Sum; use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; -use subtle::Choice; +use subtle::{Choice, CtOption}; pub mod tests; @@ -155,12 +154,34 @@ pub trait CurveAffine: /// Converts this element into its affine representation. fn into_projective(&self) -> Self::Projective; + /// Attempts to deserialize an element from its compressed encoding. + fn from_compressed(bytes: &Self::Compressed) -> CtOption; + + /// Attempts to deserialize a compressed element, not checking if the element is in + /// the correct subgroup. + /// + /// **This is dangerous to call unless you trust the bytes you are reading; otherwise, + /// API invariants may be broken.** Please consider using + /// [`CurveAffine::from_compressed`] instead. + fn from_compressed_unchecked(bytes: &Self::Compressed) -> CtOption; + /// Converts this element into its compressed encoding, so long as it's not /// the point at infinity. fn into_compressed(&self) -> Self::Compressed { ::from_affine(*self) } + /// Attempts to deserialize an element from its uncompressed encoding. + fn from_uncompressed(bytes: &Self::Uncompressed) -> CtOption; + + /// Attempts to deserialize an uncompressed element, not checking if the element is in + /// the correct subgroup. + /// + /// **This is dangerous to call unless you trust the bytes you are reading; otherwise, + /// API invariants may be broken.** Please consider using + /// [`CurveAffine::from_uncompressed`] instead. + fn from_uncompressed_unchecked(bytes: &Self::Uncompressed) -> CtOption; + /// Converts this element into its uncompressed encoding, so long as it's not /// the point at infinity. fn into_uncompressed(&self) -> Self::Uncompressed { @@ -180,60 +201,7 @@ pub trait EncodedPoint: /// Returns the number of bytes consumed by this representation. fn size() -> usize; - /// Converts an `EncodedPoint` into a `CurveAffine` element, - /// if the encoding represents a valid element. - fn into_affine(&self) -> Result; - - /// Converts an `EncodedPoint` into a `CurveAffine` element, - /// without guaranteeing that the encoding represents a valid - /// element. This is useful when the caller knows the encoding is - /// valid already. - /// - /// If the encoding is invalid, this can break API invariants, - /// so caution is strongly encouraged. - fn into_affine_unchecked(&self) -> Result; - /// Creates an `EncodedPoint` from an affine point, as long as the /// point is not the point at infinity. fn from_affine(affine: Self::Affine) -> Self; } - -/// An error that may occur when trying to decode an `EncodedPoint`. -#[derive(Debug)] -pub enum GroupDecodingError { - /// The coordinate(s) do not lie on the curve. - NotOnCurve, - /// The element is not part of the r-order subgroup. - NotInSubgroup, - /// One of the coordinates could not be decoded - CoordinateDecodingError(&'static str), - /// The compression mode of the encoded element was not as expected - UnexpectedCompressionMode, - /// The encoding contained bits that should not have been set - UnexpectedInformation, -} - -impl Error for GroupDecodingError { - fn description(&self) -> &str { - match *self { - GroupDecodingError::NotOnCurve => "coordinate(s) do not lie on the curve", - GroupDecodingError::NotInSubgroup => "the element is not part of an r-order subgroup", - GroupDecodingError::CoordinateDecodingError(..) => "coordinate(s) could not be decoded", - GroupDecodingError::UnexpectedCompressionMode => { - "encoding has unexpected compression mode" - } - GroupDecodingError::UnexpectedInformation => "encoding has unexpected information", - } - } -} - -impl fmt::Display for GroupDecodingError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - match *self { - GroupDecodingError::CoordinateDecodingError(description) => { - write!(f, "{} decoding error", description) - } - _ => write!(f, "{}", self.description()), - } - } -} diff --git a/group/src/tests/mod.rs b/group/src/tests/mod.rs index 36f2f261c..53fb48381 100644 --- a/group/src/tests/mod.rs +++ b/group/src/tests/mod.rs @@ -3,7 +3,7 @@ use rand::SeedableRng; use rand_xorshift::XorShiftRng; use std::ops::{Mul, Neg}; -use crate::{CurveAffine, CurveProjective, EncodedPoint}; +use crate::{CurveAffine, CurveProjective}; pub fn curve_tests() { let mut rng = XorShiftRng::from_seed([ @@ -405,18 +405,12 @@ fn random_encoding_tests() { ]); assert_eq!( - G::Affine::identity() - .into_uncompressed() - .into_affine() - .unwrap(), + G::Affine::from_uncompressed(&G::Affine::identity().into_uncompressed()).unwrap(), G::Affine::identity() ); assert_eq!( - G::Affine::identity() - .into_compressed() - .into_affine() - .unwrap(), + G::Affine::from_compressed(&G::Affine::identity().into_compressed()).unwrap(), G::Affine::identity() ); @@ -424,17 +418,17 @@ fn random_encoding_tests() { let mut r = G::random(&mut rng).into_affine(); let uncompressed = r.into_uncompressed(); - let de_uncompressed = uncompressed.into_affine().unwrap(); + let de_uncompressed = G::Affine::from_uncompressed(&uncompressed).unwrap(); assert_eq!(de_uncompressed, r); let compressed = r.into_compressed(); - let de_compressed = compressed.into_affine().unwrap(); + let de_compressed = G::Affine::from_compressed(&compressed).unwrap(); assert_eq!(de_compressed, r); r = r.neg(); let compressed = r.into_compressed(); - let de_compressed = compressed.into_affine().unwrap(); + let de_compressed = G::Affine::from_compressed(&compressed).unwrap(); assert_eq!(de_compressed, r); } } diff --git a/pairing/src/bls12_381/ec.rs b/pairing/src/bls12_381/ec.rs index 0db08432c..82b080e40 100644 --- a/pairing/src/bls12_381/ec.rs +++ b/pairing/src/bls12_381/ec.rs @@ -17,6 +17,12 @@ macro_rules! curve_impl { pub(crate) infinity: bool, } + impl Default for $affine { + fn default() -> Self { + Self::identity() + } + } + impl ::std::fmt::Display for $affine { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { if self.infinity { @@ -27,6 +33,21 @@ macro_rules! curve_impl { } } + impl ::subtle::ConditionallySelectable for $affine { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + $affine { + x: $basefield::conditional_select(&a.x, &b.x, choice), + y: $basefield::conditional_select(&a.y, &b.y, choice), + // Obviously not constant-time, but this code will be replaced. + infinity: if choice.into() { + b.infinity + } else { + a.infinity + }, + } + } + } + #[derive(Copy, Clone, Debug, Eq)] pub struct $projective { pub(crate) x: $basefield, @@ -203,6 +224,53 @@ macro_rules! curve_impl { fn into_projective(&self) -> $projective { (*self).into() } + + fn from_compressed(bytes: &Self::Compressed) -> CtOption { + Self::from_compressed_unchecked(bytes).and_then(|affine| { + // NB: Decompression guarantees that it is on the curve already. + CtOption::new( + affine, + Choice::from(if affine.is_in_correct_subgroup_assuming_on_curve() { + 1 + } else { + 0 + }), + ) + }) + } + + fn from_compressed_unchecked(bytes: &Self::Compressed) -> CtOption { + if let Ok(p) = bytes.into_affine_unchecked() { + CtOption::new(p, Choice::from(1)) + } else { + CtOption::new(Self::identity(), Choice::from(0)) + } + } + + fn from_uncompressed(bytes: &Self::Uncompressed) -> CtOption { + Self::from_uncompressed_unchecked(bytes).and_then(|affine| { + CtOption::new( + affine, + Choice::from( + if affine.is_on_curve() + && affine.is_in_correct_subgroup_assuming_on_curve() + { + 1 + } else { + 0 + }, + ), + ) + }) + } + + fn from_uncompressed_unchecked(bytes: &Self::Uncompressed) -> CtOption { + if let Ok(p) = bytes.into_affine_unchecked() { + CtOption::new(p, Choice::from(1)) + } else { + CtOption::new(Self::identity(), Choice::from(0)) + } + } } impl PairingCurveAffine for $affine { @@ -788,14 +856,52 @@ macro_rules! curve_impl { }; } +use std::error::Error; +use std::fmt; + +/// An error that may occur when trying to decode an `EncodedPoint`. +#[derive(Debug)] +enum GroupDecodingError { + /// The coordinate(s) do not lie on the curve. + NotOnCurve, + /// One of the coordinates could not be decoded + CoordinateDecodingError(&'static str), + /// The compression mode of the encoded element was not as expected + UnexpectedCompressionMode, + /// The encoding contained bits that should not have been set + UnexpectedInformation, +} + +impl Error for GroupDecodingError { + fn description(&self) -> &str { + match *self { + GroupDecodingError::NotOnCurve => "coordinate(s) do not lie on the curve", + GroupDecodingError::CoordinateDecodingError(..) => "coordinate(s) could not be decoded", + GroupDecodingError::UnexpectedCompressionMode => { + "encoding has unexpected compression mode" + } + GroupDecodingError::UnexpectedInformation => "encoding has unexpected information", + } + } +} + +impl fmt::Display for GroupDecodingError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + match *self { + GroupDecodingError::CoordinateDecodingError(description) => { + write!(f, "{} decoding error", description) + } + _ => write!(f, "{}", self.description()), + } + } +} + pub mod g1 { use super::super::{Fq, Fq12, FqRepr, Fr}; - use super::g2::G2Affine; + use super::{g2::G2Affine, GroupDecodingError}; use crate::{Engine, PairingCurveAffine}; use ff::{BitIterator, Field, PrimeField}; - use group::{ - CurveAffine, CurveProjective, EncodedPoint, Group, GroupDecodingError, PrimeGroup, - }; + use group::{CurveAffine, CurveProjective, EncodedPoint, Group, PrimeGroup}; use rand_core::RngCore; use std::fmt; use std::ops::{AddAssign, MulAssign, Neg, SubAssign}; @@ -834,26 +940,7 @@ pub mod g1 { } } - impl EncodedPoint for G1Uncompressed { - type Affine = G1Affine; - - fn empty() -> Self { - G1Uncompressed([0; 96]) - } - fn size() -> usize { - 96 - } - fn into_affine(&self) -> Result { - let affine = self.into_affine_unchecked()?; - - if !affine.is_on_curve() { - Err(GroupDecodingError::NotOnCurve) - } else if !affine.is_in_correct_subgroup_assuming_on_curve() { - Err(GroupDecodingError::NotInSubgroup) - } else { - Ok(affine) - } - } + impl G1Uncompressed { fn into_affine_unchecked(&self) -> Result { // Create a copy of this representation. let mut copy = self.0; @@ -904,6 +991,17 @@ pub mod g1 { }) } } + } + + impl EncodedPoint for G1Uncompressed { + type Affine = G1Affine; + + fn empty() -> Self { + G1Uncompressed([0; 96]) + } + fn size() -> usize { + 96 + } fn from_affine(affine: G1Affine) -> Self { let mut res = Self::empty(); @@ -941,26 +1039,7 @@ pub mod g1 { } } - impl EncodedPoint for G1Compressed { - type Affine = G1Affine; - - fn empty() -> Self { - G1Compressed([0; 48]) - } - fn size() -> usize { - 48 - } - fn into_affine(&self) -> Result { - let affine = self.into_affine_unchecked()?; - - // NB: Decompression guarantees that it is on the curve already. - - if !affine.is_in_correct_subgroup_assuming_on_curve() { - Err(GroupDecodingError::NotInSubgroup) - } else { - Ok(affine) - } - } + impl G1Compressed { fn into_affine_unchecked(&self) -> Result { // Create a copy of this representation. let mut copy = self.0; @@ -1001,6 +1080,17 @@ pub mod g1 { } } } + } + + impl EncodedPoint for G1Compressed { + type Affine = G1Affine; + + fn empty() -> Self { + G1Compressed([0; 48]) + } + fn size() -> usize { + 48 + } fn from_affine(affine: G1Affine) -> Self { let mut res = Self::empty(); @@ -1400,12 +1490,10 @@ pub mod g1 { pub mod g2 { use super::super::{Fq, Fq12, Fq2, FqRepr, Fr}; - use super::g1::G1Affine; + use super::{g1::G1Affine, GroupDecodingError}; use crate::{Engine, PairingCurveAffine}; use ff::{BitIterator, Field, PrimeField}; - use group::{ - CurveAffine, CurveProjective, EncodedPoint, Group, GroupDecodingError, PrimeGroup, - }; + use group::{CurveAffine, CurveProjective, EncodedPoint, Group, PrimeGroup}; use rand_core::RngCore; use std::fmt; use std::ops::{AddAssign, MulAssign, Neg, SubAssign}; @@ -1444,26 +1532,7 @@ pub mod g2 { } } - impl EncodedPoint for G2Uncompressed { - type Affine = G2Affine; - - fn empty() -> Self { - G2Uncompressed([0; 192]) - } - fn size() -> usize { - 192 - } - fn into_affine(&self) -> Result { - let affine = self.into_affine_unchecked()?; - - if !affine.is_on_curve() { - Err(GroupDecodingError::NotOnCurve) - } else if !affine.is_in_correct_subgroup_assuming_on_curve() { - Err(GroupDecodingError::NotInSubgroup) - } else { - Ok(affine) - } - } + impl G2Uncompressed { fn into_affine_unchecked(&self) -> Result { // Create a copy of this representation. let mut copy = self.0; @@ -1526,6 +1595,17 @@ pub mod g2 { }) } } + } + + impl EncodedPoint for G2Uncompressed { + type Affine = G2Affine; + + fn empty() -> Self { + G2Uncompressed([0; 192]) + } + fn size() -> usize { + 192 + } fn from_affine(affine: G2Affine) -> Self { let mut res = Self::empty(); @@ -1565,26 +1645,7 @@ pub mod g2 { } } - impl EncodedPoint for G2Compressed { - type Affine = G2Affine; - - fn empty() -> Self { - G2Compressed([0; 96]) - } - fn size() -> usize { - 96 - } - fn into_affine(&self) -> Result { - let affine = self.into_affine_unchecked()?; - - // NB: Decompression guarantees that it is on the curve already. - - if !affine.is_in_correct_subgroup_assuming_on_curve() { - Err(GroupDecodingError::NotInSubgroup) - } else { - Ok(affine) - } - } + impl G2Compressed { fn into_affine_unchecked(&self) -> Result { // Create a copy of this representation. let mut copy = self.0; @@ -1640,6 +1701,17 @@ pub mod g2 { } } } + } + + impl EncodedPoint for G2Compressed { + type Affine = G2Affine; + + fn empty() -> Self { + G2Compressed([0; 96]) + } + fn size() -> usize { + 96 + } fn from_affine(affine: G2Affine) -> Self { let mut res = Self::empty(); diff --git a/pairing/src/bls12_381/tests/mod.rs b/pairing/src/bls12_381/tests/mod.rs index 7bd819a69..815c2bb4f 100644 --- a/pairing/src/bls12_381/tests/mod.rs +++ b/pairing/src/bls12_381/tests/mod.rs @@ -1,5 +1,5 @@ use ff::PrimeField; -use group::{CurveAffine, CurveProjective, EncodedPoint, Group, GroupDecodingError}; +use group::{CurveAffine, CurveProjective, EncodedPoint, Group}; use super::*; use crate::*; @@ -55,7 +55,7 @@ fn test_pairing_result_against_relic() { }); } -fn test_vectors>(expected: &[u8]) { +fn uncompressed_test_vectors(expected: &[u8]) { let mut e = G::identity(); let mut v = vec![]; @@ -63,13 +63,41 @@ fn test_vectors>(expecte let mut expected = expected; for _ in 0..1000 { let e_affine = e.into_affine(); - let encoded = E::from_affine(e_affine); + let encoded = ::Uncompressed::from_affine(e_affine); v.extend_from_slice(encoded.as_ref()); - let mut decoded = E::empty(); - decoded.as_mut().copy_from_slice(&expected[0..E::size()]); - expected = &expected[E::size()..]; - let decoded = decoded.into_affine().unwrap(); + let mut decoded = ::Uncompressed::empty(); + decoded + .as_mut() + .copy_from_slice(&expected[0..::Uncompressed::size()]); + expected = &expected[::Uncompressed::size()..]; + let decoded = G::Affine::from_uncompressed(&decoded).unwrap(); + assert_eq!(e_affine, decoded); + + e.add_assign(&G::generator()); + } + } + + assert_eq!(&v[..], expected); +} + +fn compressed_test_vectors(expected: &[u8]) { + let mut e = G::identity(); + + let mut v = vec![]; + { + let mut expected = expected; + for _ in 0..1000 { + let e_affine = e.into_affine(); + let encoded = ::Compressed::from_affine(e_affine); + v.extend_from_slice(encoded.as_ref()); + + let mut decoded = ::Compressed::empty(); + decoded + .as_mut() + .copy_from_slice(&expected[0..::Compressed::size()]); + expected = &expected[::Compressed::size()..]; + let decoded = G::Affine::from_compressed(&decoded).unwrap(); assert_eq!(e_affine, decoded); e.add_assign(&G::generator()); @@ -81,22 +109,22 @@ fn test_vectors>(expecte #[test] fn test_g1_uncompressed_valid_vectors() { - test_vectors::(include_bytes!("g1_uncompressed_valid_test_vectors.dat")); + uncompressed_test_vectors::(include_bytes!("g1_uncompressed_valid_test_vectors.dat")); } #[test] fn test_g1_compressed_valid_vectors() { - test_vectors::(include_bytes!("g1_compressed_valid_test_vectors.dat")); + compressed_test_vectors::(include_bytes!("g1_compressed_valid_test_vectors.dat")); } #[test] fn test_g2_uncompressed_valid_vectors() { - test_vectors::(include_bytes!("g2_uncompressed_valid_test_vectors.dat")); + uncompressed_test_vectors::(include_bytes!("g2_uncompressed_valid_test_vectors.dat")); } #[test] fn test_g2_compressed_valid_vectors() { - test_vectors::(include_bytes!("g2_compressed_valid_test_vectors.dat")); + compressed_test_vectors::(include_bytes!("g2_compressed_valid_test_vectors.dat")); } #[test] @@ -107,7 +135,7 @@ fn test_g1_uncompressed_invalid_vectors() { { let mut z = z; z.as_mut()[0] |= 0b1000_0000; - if let Err(GroupDecodingError::UnexpectedCompressionMode) = z.into_affine() { + if G1Affine::from_uncompressed(&z).is_none().into() { // :) } else { panic!("should have rejected the point because we expected an uncompressed point"); @@ -117,7 +145,7 @@ fn test_g1_uncompressed_invalid_vectors() { { let mut z = z; z.as_mut()[0] |= 0b0010_0000; - if let Err(GroupDecodingError::UnexpectedInformation) = z.into_affine() { + if G1Affine::from_uncompressed(&z).is_none().into() { // :) } else { panic!("should have rejected the point because the parity bit should not be set if the point is at infinity"); @@ -127,7 +155,7 @@ fn test_g1_uncompressed_invalid_vectors() { for i in 0..G1Uncompressed::size() { let mut z = z; z.as_mut()[i] |= 0b0000_0001; - if let Err(GroupDecodingError::UnexpectedInformation) = z.into_affine() { + if G1Affine::from_uncompressed(&z).is_none().into() { // :) } else { panic!("should have rejected the point because the coordinates should be zeroes at the point at infinity"); @@ -140,7 +168,7 @@ fn test_g1_uncompressed_invalid_vectors() { { let mut o = o; o.as_mut()[0] |= 0b1000_0000; - if let Err(GroupDecodingError::UnexpectedCompressionMode) = o.into_affine() { + if G1Affine::from_uncompressed(&o).is_none().into() { // :) } else { panic!("should have rejected the point because we expected an uncompressed point"); @@ -153,8 +181,8 @@ fn test_g1_uncompressed_invalid_vectors() { let mut o = o; o.as_mut()[..48].copy_from_slice(m.as_ref()); - if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() { - assert_eq!(coordinate, "x coordinate"); + if G1Affine::from_uncompressed(&o).is_none().into() { + // x coordinate } else { panic!("should have rejected the point") } @@ -164,8 +192,8 @@ fn test_g1_uncompressed_invalid_vectors() { let mut o = o; o.as_mut()[48..].copy_from_slice(m.as_ref()); - if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() { - assert_eq!(coordinate, "y coordinate"); + if G1Affine::from_uncompressed(&o).is_none().into() { + // y coordinate } else { panic!("should have rejected the point") } @@ -177,7 +205,7 @@ fn test_g1_uncompressed_invalid_vectors() { let mut o = o; o.as_mut()[..48].copy_from_slice(m.as_ref()); - if let Err(GroupDecodingError::NotOnCurve) = o.into_affine() { + if G1Affine::from_uncompressed(&o).is_none().into() { // :) } else { panic!("should have rejected the point because it isn't on the curve") @@ -201,7 +229,7 @@ fn test_g1_uncompressed_invalid_vectors() { o.as_mut()[..48].copy_from_slice(x.to_repr().as_ref()); o.as_mut()[48..].copy_from_slice(y.to_repr().as_ref()); - if let Err(GroupDecodingError::NotInSubgroup) = o.into_affine() { + if G1Affine::from_uncompressed(&o).is_none().into() { break; } else { panic!( @@ -223,7 +251,7 @@ fn test_g2_uncompressed_invalid_vectors() { { let mut z = z; z.as_mut()[0] |= 0b1000_0000; - if let Err(GroupDecodingError::UnexpectedCompressionMode) = z.into_affine() { + if G2Affine::from_uncompressed(&z).is_none().into() { // :) } else { panic!("should have rejected the point because we expected an uncompressed point"); @@ -233,7 +261,7 @@ fn test_g2_uncompressed_invalid_vectors() { { let mut z = z; z.as_mut()[0] |= 0b0010_0000; - if let Err(GroupDecodingError::UnexpectedInformation) = z.into_affine() { + if G2Affine::from_uncompressed(&z).is_none().into() { // :) } else { panic!("should have rejected the point because the parity bit should not be set if the point is at infinity"); @@ -243,7 +271,7 @@ fn test_g2_uncompressed_invalid_vectors() { for i in 0..G2Uncompressed::size() { let mut z = z; z.as_mut()[i] |= 0b0000_0001; - if let Err(GroupDecodingError::UnexpectedInformation) = z.into_affine() { + if G2Affine::from_uncompressed(&z).is_none().into() { // :) } else { panic!("should have rejected the point because the coordinates should be zeroes at the point at infinity"); @@ -256,7 +284,7 @@ fn test_g2_uncompressed_invalid_vectors() { { let mut o = o; o.as_mut()[0] |= 0b1000_0000; - if let Err(GroupDecodingError::UnexpectedCompressionMode) = o.into_affine() { + if G2Affine::from_uncompressed(&o).is_none().into() { // :) } else { panic!("should have rejected the point because we expected an uncompressed point"); @@ -269,8 +297,8 @@ fn test_g2_uncompressed_invalid_vectors() { let mut o = o; o.as_mut()[..48].copy_from_slice(m.as_ref()); - if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() { - assert_eq!(coordinate, "x coordinate (c1)"); + if G2Affine::from_uncompressed(&o).is_none().into() { + // x coordinate (c1) } else { panic!("should have rejected the point") } @@ -280,8 +308,8 @@ fn test_g2_uncompressed_invalid_vectors() { let mut o = o; o.as_mut()[48..96].copy_from_slice(m.as_ref()); - if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() { - assert_eq!(coordinate, "x coordinate (c0)"); + if G2Affine::from_uncompressed(&o).is_none().into() { + // x coordinate (c0) } else { panic!("should have rejected the point") } @@ -291,8 +319,8 @@ fn test_g2_uncompressed_invalid_vectors() { let mut o = o; o.as_mut()[96..144].copy_from_slice(m.as_ref()); - if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() { - assert_eq!(coordinate, "y coordinate (c1)"); + if G2Affine::from_uncompressed(&o).is_none().into() { + // y coordinate (c1) } else { panic!("should have rejected the point") } @@ -302,8 +330,8 @@ fn test_g2_uncompressed_invalid_vectors() { let mut o = o; o.as_mut()[144..].copy_from_slice(m.as_ref()); - if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() { - assert_eq!(coordinate, "y coordinate (c0)"); + if G2Affine::from_uncompressed(&o).is_none().into() { + // y coordinate (c0) } else { panic!("should have rejected the point") } @@ -316,7 +344,7 @@ fn test_g2_uncompressed_invalid_vectors() { o.as_mut()[..48].copy_from_slice(m.as_ref()); o.as_mut()[48..96].copy_from_slice(m.as_ref()); - if let Err(GroupDecodingError::NotOnCurve) = o.into_affine() { + if G2Affine::from_uncompressed(&o).is_none().into() { // :) } else { panic!("should have rejected the point because it isn't on the curve") @@ -345,7 +373,7 @@ fn test_g2_uncompressed_invalid_vectors() { o.as_mut()[96..144].copy_from_slice(y.c1.to_repr().as_ref()); o.as_mut()[144..].copy_from_slice(y.c0.to_repr().as_ref()); - if let Err(GroupDecodingError::NotInSubgroup) = o.into_affine() { + if G2Affine::from_uncompressed(&o).is_none().into() { break; } else { panic!( @@ -367,7 +395,7 @@ fn test_g1_compressed_invalid_vectors() { { let mut z = z; z.as_mut()[0] &= 0b0111_1111; - if let Err(GroupDecodingError::UnexpectedCompressionMode) = z.into_affine() { + if G1Affine::from_compressed(&z).is_none().into() { // :) } else { panic!("should have rejected the point because we expected a compressed point"); @@ -377,7 +405,7 @@ fn test_g1_compressed_invalid_vectors() { { let mut z = z; z.as_mut()[0] |= 0b0010_0000; - if let Err(GroupDecodingError::UnexpectedInformation) = z.into_affine() { + if G1Affine::from_compressed(&z).is_none().into() { // :) } else { panic!("should have rejected the point because the parity bit should not be set if the point is at infinity"); @@ -387,7 +415,7 @@ fn test_g1_compressed_invalid_vectors() { for i in 0..G1Compressed::size() { let mut z = z; z.as_mut()[i] |= 0b0000_0001; - if let Err(GroupDecodingError::UnexpectedInformation) = z.into_affine() { + if G1Affine::from_compressed(&z).is_none().into() { // :) } else { panic!("should have rejected the point because the coordinates should be zeroes at the point at infinity"); @@ -400,7 +428,7 @@ fn test_g1_compressed_invalid_vectors() { { let mut o = o; o.as_mut()[0] &= 0b0111_1111; - if let Err(GroupDecodingError::UnexpectedCompressionMode) = o.into_affine() { + if G1Affine::from_compressed(&o).is_none().into() { // :) } else { panic!("should have rejected the point because we expected a compressed point"); @@ -414,8 +442,8 @@ fn test_g1_compressed_invalid_vectors() { o.as_mut()[..48].copy_from_slice(m.as_ref()); o.as_mut()[0] |= 0b1000_0000; - if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() { - assert_eq!(coordinate, "x coordinate"); + if G1Affine::from_compressed(&o).is_none().into() { + // x coordinate } else { panic!("should have rejected the point") } @@ -436,7 +464,7 @@ fn test_g1_compressed_invalid_vectors() { o.as_mut().copy_from_slice(x.to_repr().as_ref()); o.as_mut()[0] |= 0b1000_0000; - if let Err(GroupDecodingError::NotOnCurve) = o.into_affine() { + if G1Affine::from_compressed(&o).is_none().into() { break; } else { panic!("should have rejected the point because it isn't on the curve") @@ -459,7 +487,7 @@ fn test_g1_compressed_invalid_vectors() { o.as_mut().copy_from_slice(x.to_repr().as_ref()); o.as_mut()[0] |= 0b1000_0000; - if let Err(GroupDecodingError::NotInSubgroup) = o.into_affine() { + if G1Affine::from_compressed(&o).is_none().into() { break; } else { panic!( @@ -481,7 +509,7 @@ fn test_g2_compressed_invalid_vectors() { { let mut z = z; z.as_mut()[0] &= 0b0111_1111; - if let Err(GroupDecodingError::UnexpectedCompressionMode) = z.into_affine() { + if G2Affine::from_compressed(&z).is_none().into() { // :) } else { panic!("should have rejected the point because we expected a compressed point"); @@ -491,7 +519,7 @@ fn test_g2_compressed_invalid_vectors() { { let mut z = z; z.as_mut()[0] |= 0b0010_0000; - if let Err(GroupDecodingError::UnexpectedInformation) = z.into_affine() { + if G2Affine::from_compressed(&z).is_none().into() { // :) } else { panic!("should have rejected the point because the parity bit should not be set if the point is at infinity"); @@ -501,7 +529,7 @@ fn test_g2_compressed_invalid_vectors() { for i in 0..G2Compressed::size() { let mut z = z; z.as_mut()[i] |= 0b0000_0001; - if let Err(GroupDecodingError::UnexpectedInformation) = z.into_affine() { + if G2Affine::from_compressed(&z).is_none().into() { // :) } else { panic!("should have rejected the point because the coordinates should be zeroes at the point at infinity"); @@ -514,7 +542,7 @@ fn test_g2_compressed_invalid_vectors() { { let mut o = o; o.as_mut()[0] &= 0b0111_1111; - if let Err(GroupDecodingError::UnexpectedCompressionMode) = o.into_affine() { + if G2Affine::from_compressed(&o).is_none().into() { // :) } else { panic!("should have rejected the point because we expected a compressed point"); @@ -528,8 +556,8 @@ fn test_g2_compressed_invalid_vectors() { o.as_mut()[..48].copy_from_slice(m.as_ref()); o.as_mut()[0] |= 0b1000_0000; - if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() { - assert_eq!(coordinate, "x coordinate (c1)"); + if G2Affine::from_compressed(&o).is_none().into() { + // x coordinate (c1) } else { panic!("should have rejected the point") } @@ -540,8 +568,8 @@ fn test_g2_compressed_invalid_vectors() { o.as_mut()[48..96].copy_from_slice(m.as_ref()); o.as_mut()[0] |= 0b1000_0000; - if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() { - assert_eq!(coordinate, "x coordinate (c0)"); + if G2Affine::from_compressed(&o).is_none().into() { + // x coordinate (c0) } else { panic!("should have rejected the point") } @@ -569,7 +597,7 @@ fn test_g2_compressed_invalid_vectors() { o.as_mut()[48..].copy_from_slice(x.c0.to_repr().as_ref()); o.as_mut()[0] |= 0b1000_0000; - if let Err(GroupDecodingError::NotOnCurve) = o.into_affine() { + if G2Affine::from_compressed(&o).is_none().into() { break; } else { panic!("should have rejected the point because it isn't on the curve") @@ -599,7 +627,7 @@ fn test_g2_compressed_invalid_vectors() { o.as_mut()[48..].copy_from_slice(x.c0.to_repr().as_ref()); o.as_mut()[0] |= 0b1000_0000; - if let Err(GroupDecodingError::NotInSubgroup) = o.into_affine() { + if G2Affine::from_compressed(&o).is_none().into() { break; } else { panic!(