diff --git a/src/bls12_381/ec.rs b/src/bls12_381/ec.rs index 09824c686..973bdbfe7 100644 --- a/src/bls12_381/ec.rs +++ b/src/bls12_381/ec.rs @@ -1,5 +1,6 @@ macro_rules! curve_impl { ( + $name:expr, $projective:ident, $affine:ident, $prepared:ident, @@ -15,6 +16,17 @@ macro_rules! curve_impl { pub(crate) infinity: bool } + impl ::std::fmt::Display for $affine + { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + if self.infinity { + write!(f, "{}(Infinity)", $name) + } else { + write!(f, "{}(x={}, y={})", $name, self.x, self.y) + } + } + } + #[derive(Copy, Clone, Debug, Eq)] pub struct $projective { pub(crate) x: $basefield, @@ -22,6 +34,13 @@ macro_rules! curve_impl { pub(crate) z: $basefield } + impl ::std::fmt::Display for $projective + { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "{}", self.into_affine()) + } + } + impl PartialEq for $projective { fn eq(&self, other: &$projective) -> bool { if self.is_zero() { @@ -111,10 +130,6 @@ macro_rules! curve_impl { self.infinity } - fn is_valid(&self) -> bool { - self.is_on_curve() && self.is_in_correct_subgroup() - } - fn mul::Repr>>(&self, by: S) -> $projective { let mut res = $projective::zero(); @@ -560,12 +575,19 @@ macro_rules! curve_impl { pub mod g1 { use rand::{Rand, Rng}; use super::super::{Fq, Fr, FrRepr, FqRepr}; - use ::{CurveProjective, CurveAffine, PrimeField, SqrtField, PrimeFieldRepr, Field, BitIterator, EncodedPoint}; + use ::{CurveProjective, CurveAffine, PrimeField, SqrtField, PrimeFieldRepr, Field, BitIterator, EncodedPoint, GroupDecodingError}; - curve_impl!(G1, G1Affine, G1Prepared, Fq, Fr, G1Uncompressed, G1Compressed); + curve_impl!("G1", G1, G1Affine, G1Prepared, Fq, Fr, G1Uncompressed, G1Compressed); + #[derive(Copy)] pub struct G1Uncompressed([u8; 96]); + impl Clone for G1Uncompressed { + fn clone(&self) -> G1Uncompressed { + G1Uncompressed(self.0) + } + } + impl AsRef<[u8]> for G1Uncompressed { fn as_ref(&self) -> &[u8] { &self.0 @@ -583,15 +605,24 @@ pub mod g1 { fn empty() -> Self { G1Uncompressed([0; 96]) } fn size() -> usize { 96 } - fn into_affine_unchecked(&self) -> Result { - use byteorder::{ReadBytesExt, BigEndian}; + 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() { + Err(GroupDecodingError::NotInSubgroup) + } else { + Ok(affine) + } + } + fn into_affine_unchecked(&self) -> Result { // Create a copy of this representation. let mut copy = self.0; if copy[0] & (1 << 7) != 0 { // Distinguisher bit is set, but this should be uncompressed! - return Err(()) + return Err(GroupDecodingError::UnexpectedCompressionMode) } if copy[0] & (1 << 6) != 0 { @@ -603,13 +634,13 @@ pub mod g1 { if copy.iter().all(|b| *b == 0) { Ok(G1Affine::zero()) } else { - Err(()) + Err(GroupDecodingError::UnexpectedInformation) } } else { if copy[0] & (1 << 5) != 0 { // The bit indicating the y-coordinate should be lexicographically // largest is set, but this is an uncompressed element. - return Err(()) + return Err(GroupDecodingError::UnexpectedInformation) } // Unset the three most significant bits. @@ -621,25 +652,18 @@ pub mod g1 { { let mut reader = ©[..]; - for b in x.0.iter_mut().rev() { - *b = reader.read_u64::().unwrap(); - } - - for b in y.0.iter_mut().rev() { - *b = reader.read_u64::().unwrap(); - } + x.read_be(&mut reader).unwrap(); + y.read_be(&mut reader).unwrap(); } Ok(G1Affine { - x: Fq::from_repr(x)?, - y: Fq::from_repr(y)?, + x: Fq::from_repr(x).map_err(|e| GroupDecodingError::CoordinateDecodingError("x coordinate", e))?, + y: Fq::from_repr(y).map_err(|e| GroupDecodingError::CoordinateDecodingError("y coordinate", e))?, infinity: false }) } } fn from_affine(affine: G1Affine) -> Self { - use byteorder::{WriteBytesExt, BigEndian}; - let mut res = Self::empty(); if affine.is_zero() { @@ -649,21 +673,23 @@ pub mod g1 { } else { let mut writer = &mut res.0[..]; - for digit in affine.x.into_repr().as_ref().iter().rev() { - writer.write_u64::(*digit).unwrap(); - } - - for digit in affine.y.into_repr().as_ref().iter().rev() { - writer.write_u64::(*digit).unwrap(); - } + affine.x.into_repr().write_be(&mut writer).unwrap(); + affine.y.into_repr().write_be(&mut writer).unwrap(); } res } } + #[derive(Copy)] pub struct G1Compressed([u8; 48]); + impl Clone for G1Compressed { + fn clone(&self) -> G1Compressed { + G1Compressed(self.0) + } + } + impl AsRef<[u8]> for G1Compressed { fn as_ref(&self) -> &[u8] { &self.0 @@ -681,15 +707,24 @@ pub mod g1 { fn empty() -> Self { G1Compressed([0; 48]) } fn size() -> usize { 48 } - fn into_affine_unchecked(&self) -> Result { - use byteorder::{ReadBytesExt, BigEndian}; + 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() { + Err(GroupDecodingError::NotInSubgroup) + } else { + Ok(affine) + } + } + fn into_affine_unchecked(&self) -> Result { // Create a copy of this representation. let mut copy = self.0; if copy[0] & (1 << 7) == 0 { // Distinguisher bit isn't set. - return Err(()) + return Err(GroupDecodingError::UnexpectedCompressionMode) } if copy[0] & (1 << 6) != 0 { @@ -701,7 +736,7 @@ pub mod g1 { if copy.iter().all(|b| *b == 0) { Ok(G1Affine::zero()) } else { - Err(()) + Err(GroupDecodingError::UnexpectedInformation) } } else { // Determine if the intended y coordinate must be greater @@ -716,13 +751,11 @@ pub mod g1 { { let mut reader = ©[..]; - for b in x.0.iter_mut().rev() { - *b = reader.read_u64::().unwrap(); - } + x.read_be(&mut reader).unwrap(); } // Interpret as Fq element. - let x = Fq::from_repr(x)?; + let x = Fq::from_repr(x).map_err(|e| GroupDecodingError::CoordinateDecodingError("x coordinate", e))?; // Compute x^3 + b let mut x3b = x; @@ -747,14 +780,12 @@ pub mod g1 { }, None => { // Point must not be on the curve. - Err(()) + Err(GroupDecodingError::NotOnCurve) } } } } fn from_affine(affine: G1Affine) -> Self { - use byteorder::{WriteBytesExt, BigEndian}; - let mut res = Self::empty(); if affine.is_zero() { @@ -765,9 +796,7 @@ pub mod g1 { { let mut writer = &mut res.0[..]; - for digit in affine.x.into_repr().as_ref().iter().rev() { - writer.write_u64::(*digit).unwrap(); - } + affine.x.into_repr().write_be(&mut writer).unwrap(); } let mut negy = affine.y; @@ -873,7 +902,7 @@ pub mod g1 { infinity: false }; - assert!(!p.is_valid()); + assert!(!p.is_in_correct_subgroup()); let mut g1 = G1::zero(); @@ -895,7 +924,7 @@ pub mod g1 { assert_eq!(i, 4); let g1 = G1Affine::from(g1); - assert!(g1.is_valid()); + assert!(g1.is_in_correct_subgroup()); assert_eq!(g1, G1Affine::one()); break; @@ -918,7 +947,6 @@ pub mod g1 { }; assert!(!p.is_on_curve()); assert!(p.is_in_correct_subgroup()); - assert!(!p.is_valid()); } // Reject point on a twist (b = 3) @@ -930,7 +958,6 @@ pub mod g1 { }; assert!(!p.is_on_curve()); assert!(!p.is_in_correct_subgroup()); - assert!(!p.is_valid()); } // Reject point in an invalid subgroup @@ -943,7 +970,6 @@ pub mod g1 { }; assert!(p.is_on_curve()); assert!(!p.is_in_correct_subgroup()); - assert!(!p.is_valid()); } } @@ -1019,9 +1045,9 @@ pub mod g1 { infinity: false }; - assert!(a.is_valid()); - assert!(b.is_valid()); - assert!(c.is_valid()); + assert!(a.is_on_curve() && a.is_in_correct_subgroup()); + assert!(b.is_on_curve() && b.is_in_correct_subgroup()); + assert!(c.is_on_curve() && c.is_in_correct_subgroup()); let mut tmp1 = a.into_projective(); tmp1.add_assign(&b.into_projective()); @@ -1097,12 +1123,19 @@ pub mod g1 { pub mod g2 { use rand::{Rand, Rng}; use super::super::{Fq2, Fr, Fq, FrRepr, FqRepr}; - use ::{CurveProjective, CurveAffine, PrimeField, SqrtField, PrimeFieldRepr, Field, BitIterator, EncodedPoint}; + use ::{CurveProjective, CurveAffine, PrimeField, SqrtField, PrimeFieldRepr, Field, BitIterator, EncodedPoint, GroupDecodingError}; - curve_impl!(G2, G2Affine, G2Prepared, Fq2, Fr, G2Uncompressed, G2Compressed); + curve_impl!("G2", G2, G2Affine, G2Prepared, Fq2, Fr, G2Uncompressed, G2Compressed); + #[derive(Copy)] pub struct G2Uncompressed([u8; 192]); + impl Clone for G2Uncompressed { + fn clone(&self) -> G2Uncompressed { + G2Uncompressed(self.0) + } + } + impl AsRef<[u8]> for G2Uncompressed { fn as_ref(&self) -> &[u8] { &self.0 @@ -1120,15 +1153,24 @@ pub mod g2 { fn empty() -> Self { G2Uncompressed([0; 192]) } fn size() -> usize { 192 } - fn into_affine_unchecked(&self) -> Result { - use byteorder::{ReadBytesExt, BigEndian}; + 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() { + Err(GroupDecodingError::NotInSubgroup) + } else { + Ok(affine) + } + } + fn into_affine_unchecked(&self) -> Result { // Create a copy of this representation. let mut copy = self.0; if copy[0] & (1 << 7) != 0 { // Distinguisher bit is set, but this should be uncompressed! - return Err(()) + return Err(GroupDecodingError::UnexpectedCompressionMode) } if copy[0] & (1 << 6) != 0 { @@ -1140,13 +1182,13 @@ pub mod g2 { if copy.iter().all(|b| *b == 0) { Ok(G2Affine::zero()) } else { - Err(()) + Err(GroupDecodingError::UnexpectedInformation) } } else { if copy[0] & (1 << 5) != 0 { // The bit indicating the y-coordinate should be lexicographically // largest is set, but this is an uncompressed element. - return Err(()) + return Err(GroupDecodingError::UnexpectedInformation) } // Unset the three most significant bits. @@ -1160,39 +1202,26 @@ pub mod g2 { { let mut reader = ©[..]; - for b in x_c1.0.iter_mut().rev() { - *b = reader.read_u64::().unwrap(); - } - - for b in x_c0.0.iter_mut().rev() { - *b = reader.read_u64::().unwrap(); - } - - for b in y_c1.0.iter_mut().rev() { - *b = reader.read_u64::().unwrap(); - } - - for b in y_c0.0.iter_mut().rev() { - *b = reader.read_u64::().unwrap(); - } + x_c1.read_be(&mut reader).unwrap(); + x_c0.read_be(&mut reader).unwrap(); + y_c1.read_be(&mut reader).unwrap(); + y_c0.read_be(&mut reader).unwrap(); } Ok(G2Affine { x: Fq2 { - c0: Fq::from_repr(x_c0)?, - c1: Fq::from_repr(x_c1)? + c0: Fq::from_repr(x_c0).map_err(|e| GroupDecodingError::CoordinateDecodingError("x coordinate (c0)", e))?, + c1: Fq::from_repr(x_c1).map_err(|e| GroupDecodingError::CoordinateDecodingError("x coordinate (c1)", e))?, }, y: Fq2 { - c0: Fq::from_repr(y_c0)?, - c1: Fq::from_repr(y_c1)? + c0: Fq::from_repr(y_c0).map_err(|e| GroupDecodingError::CoordinateDecodingError("y coordinate (c0)", e))?, + c1: Fq::from_repr(y_c1).map_err(|e| GroupDecodingError::CoordinateDecodingError("y coordinate (c1)", e))?, }, infinity: false }) } } fn from_affine(affine: G2Affine) -> Self { - use byteorder::{WriteBytesExt, BigEndian}; - let mut res = Self::empty(); if affine.is_zero() { @@ -1202,29 +1231,25 @@ pub mod g2 { } else { let mut writer = &mut res.0[..]; - for digit in affine.x.c1.into_repr().as_ref().iter().rev() { - writer.write_u64::(*digit).unwrap(); - } - - for digit in affine.x.c0.into_repr().as_ref().iter().rev() { - writer.write_u64::(*digit).unwrap(); - } - - for digit in affine.y.c1.into_repr().as_ref().iter().rev() { - writer.write_u64::(*digit).unwrap(); - } - - for digit in affine.y.c0.into_repr().as_ref().iter().rev() { - writer.write_u64::(*digit).unwrap(); - } + affine.x.c1.into_repr().write_be(&mut writer).unwrap(); + affine.x.c0.into_repr().write_be(&mut writer).unwrap(); + affine.y.c1.into_repr().write_be(&mut writer).unwrap(); + affine.y.c0.into_repr().write_be(&mut writer).unwrap(); } res } } + #[derive(Copy)] pub struct G2Compressed([u8; 96]); + impl Clone for G2Compressed { + fn clone(&self) -> G2Compressed { + G2Compressed(self.0) + } + } + impl AsRef<[u8]> for G2Compressed { fn as_ref(&self) -> &[u8] { &self.0 @@ -1242,15 +1267,24 @@ pub mod g2 { fn empty() -> Self { G2Compressed([0; 96]) } fn size() -> usize { 96 } - fn into_affine_unchecked(&self) -> Result { - use byteorder::{ReadBytesExt, BigEndian}; + 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() { + Err(GroupDecodingError::NotInSubgroup) + } else { + Ok(affine) + } + } + fn into_affine_unchecked(&self) -> Result { // Create a copy of this representation. let mut copy = self.0; if copy[0] & (1 << 7) == 0 { // Distinguisher bit isn't set. - return Err(()) + return Err(GroupDecodingError::UnexpectedCompressionMode) } if copy[0] & (1 << 6) != 0 { @@ -1262,7 +1296,7 @@ pub mod g2 { if copy.iter().all(|b| *b == 0) { Ok(G2Affine::zero()) } else { - Err(()) + Err(GroupDecodingError::UnexpectedInformation) } } else { // Determine if the intended y coordinate must be greater @@ -1278,19 +1312,14 @@ pub mod g2 { { let mut reader = ©[..]; - for b in x_c1.0.iter_mut().rev() { - *b = reader.read_u64::().unwrap(); - } - - for b in x_c0.0.iter_mut().rev() { - *b = reader.read_u64::().unwrap(); - } + x_c1.read_be(&mut reader).unwrap(); + x_c0.read_be(&mut reader).unwrap(); } // Interpret as Fq element. let x = Fq2 { - c0: Fq::from_repr(x_c0)?, - c1: Fq::from_repr(x_c1)? + c0: Fq::from_repr(x_c0).map_err(|e| GroupDecodingError::CoordinateDecodingError("x coordinate (c0)", e))?, + c1: Fq::from_repr(x_c1).map_err(|e| GroupDecodingError::CoordinateDecodingError("x coordinate (c1)", e))? }; // Compute x^3 + b @@ -1316,14 +1345,12 @@ pub mod g2 { }, None => { // Point must not be on the curve. - Err(()) + Err(GroupDecodingError::NotOnCurve) } } } } fn from_affine(affine: G2Affine) -> Self { - use byteorder::{WriteBytesExt, BigEndian}; - let mut res = Self::empty(); if affine.is_zero() { @@ -1334,13 +1361,8 @@ pub mod g2 { { let mut writer = &mut res.0[..]; - for digit in affine.x.c1.into_repr().as_ref().iter().rev() { - writer.write_u64::(*digit).unwrap(); - } - - for digit in affine.x.c0.into_repr().as_ref().iter().rev() { - writer.write_u64::(*digit).unwrap(); - } + affine.x.c1.into_repr().write_be(&mut writer).unwrap(); + affine.x.c0.into_repr().write_be(&mut writer).unwrap(); } let mut negy = affine.y; @@ -1446,7 +1468,7 @@ pub mod g2 { infinity: false }; - assert!(!p.is_valid()); + assert!(!p.is_in_correct_subgroup()); let mut g2 = G2::zero(); @@ -1468,7 +1490,7 @@ pub mod g2 { assert_eq!(i, 2); let g2 = G2Affine::from(g2); - assert!(g2.is_valid()); + assert!(g2.is_in_correct_subgroup()); assert_eq!(g2, G2Affine::one()); break; @@ -1497,7 +1519,6 @@ pub mod g2 { }; assert!(!p.is_on_curve()); assert!(p.is_in_correct_subgroup()); - assert!(!p.is_valid()); } // Reject point on a twist (b = 2 * (u + 1)) @@ -1515,7 +1536,6 @@ pub mod g2 { }; assert!(!p.is_on_curve()); assert!(!p.is_in_correct_subgroup()); - assert!(!p.is_valid()); } // Reject point in an invalid subgroup @@ -1534,7 +1554,6 @@ pub mod g2 { }; assert!(p.is_on_curve()); assert!(!p.is_in_correct_subgroup()); - assert!(!p.is_valid()); } } diff --git a/src/bls12_381/fq.rs b/src/bls12_381/fq.rs index b7f8198a0..00b040510 100644 --- a/src/bls12_381/fq.rs +++ b/src/bls12_381/fq.rs @@ -1,4 +1,4 @@ -use ::{Field, PrimeField, SqrtField, PrimeFieldRepr}; +use ::{Field, PrimeField, SqrtField, PrimeFieldRepr, PrimeFieldDecodingError}; use std::cmp::Ordering; use super::fq2::Fq2; @@ -192,7 +192,7 @@ pub const FROBENIUS_COEFF_FQ12_C1: [Fq2; 12] = [ // -((2**384) mod q) mod q pub const NEGATIVE_ONE: Fq = Fq(FqRepr([0x43f5fffffffcaaae, 0x32b7fff2ed47fffd, 0x7e83a49a2e99d69, 0xeca8f3318332bb7a, 0xef148d1ea0f4c069, 0x40ab3263eff0206])); -#[derive(Copy, Clone, PartialEq, Eq, Default)] +#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)] pub struct FqRepr(pub [u64; 6]); impl ::rand::Rand for FqRepr { @@ -202,7 +202,7 @@ impl ::rand::Rand for FqRepr { } } -impl ::std::fmt::Debug for FqRepr +impl ::std::fmt::Display for FqRepr { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { try!(write!(f, "0x")); @@ -221,6 +221,13 @@ impl AsRef<[u64]> for FqRepr { } } +impl AsMut<[u64]> for FqRepr { + #[inline(always)] + fn as_mut(&mut self) -> &mut [u64] { + &mut self.0 + } +} + impl From for FqRepr { #[inline(always)] fn from(val: u64) -> FqRepr { @@ -355,7 +362,7 @@ impl PrimeFieldRepr for FqRepr { } } -#[derive(Copy, Clone, PartialEq, Eq)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct Fq(FqRepr); /// `Fq` elements are ordered lexicographically. @@ -373,10 +380,10 @@ impl PartialOrd for Fq { } } -impl ::std::fmt::Debug for Fq +impl ::std::fmt::Display for Fq { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - write!(f, "Fq({:?})", self.into_repr()) + write!(f, "Fq({})", self.into_repr()) } } @@ -401,14 +408,14 @@ impl From for FqRepr { impl PrimeField for Fq { type Repr = FqRepr; - fn from_repr(r: FqRepr) -> Result { + fn from_repr(r: FqRepr) -> Result { let mut r = Fq(r); if r.is_valid() { r.mul_assign(&Fq(R2)); Ok(r) } else { - Err(()) + Err(PrimeFieldDecodingError::NotInField(format!("{}", r.0))) } } @@ -1676,33 +1683,33 @@ fn bench_fq_from_repr(b: &mut ::test::Bencher) { } #[test] -fn test_fq_repr_debug() { +fn test_fq_repr_display() { assert_eq!( - format!("{:?}", FqRepr([0xa956babf9301ea24, 0x39a8f184f3535c7b, 0xb38d35b3f6779585, 0x676cc4eef4c46f2c, 0xb1d4aad87651e694, 0x1947f0d5f4fe325a])), + format!("{}", FqRepr([0xa956babf9301ea24, 0x39a8f184f3535c7b, 0xb38d35b3f6779585, 0x676cc4eef4c46f2c, 0xb1d4aad87651e694, 0x1947f0d5f4fe325a])), "0x1947f0d5f4fe325ab1d4aad87651e694676cc4eef4c46f2cb38d35b3f677958539a8f184f3535c7ba956babf9301ea24".to_string() ); assert_eq!( - format!("{:?}", FqRepr([0xb4171485fd8622dd, 0x864229a6edec7ec5, 0xc57f7bdcf8dfb707, 0x6db7ff0ecea4584a, 0xf8d8578c4a57132d, 0x6eb66d42d9fcaaa])), + format!("{}", FqRepr([0xb4171485fd8622dd, 0x864229a6edec7ec5, 0xc57f7bdcf8dfb707, 0x6db7ff0ecea4584a, 0xf8d8578c4a57132d, 0x6eb66d42d9fcaaa])), "0x06eb66d42d9fcaaaf8d8578c4a57132d6db7ff0ecea4584ac57f7bdcf8dfb707864229a6edec7ec5b4171485fd8622dd".to_string() ); assert_eq!( - format!("{:?}", FqRepr([0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff])), + format!("{}", FqRepr([0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff])), "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".to_string() ); assert_eq!( - format!("{:?}", FqRepr([0, 0, 0, 0, 0, 0])), + format!("{}", FqRepr([0, 0, 0, 0, 0, 0])), "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".to_string() ); } #[test] -fn test_fq_debug() { +fn test_fq_display() { assert_eq!( - format!("{:?}", Fq::from_repr(FqRepr([0xa956babf9301ea24, 0x39a8f184f3535c7b, 0xb38d35b3f6779585, 0x676cc4eef4c46f2c, 0xb1d4aad87651e694, 0x1947f0d5f4fe325a])).unwrap()), + format!("{}", Fq::from_repr(FqRepr([0xa956babf9301ea24, 0x39a8f184f3535c7b, 0xb38d35b3f6779585, 0x676cc4eef4c46f2c, 0xb1d4aad87651e694, 0x1947f0d5f4fe325a])).unwrap()), "Fq(0x1947f0d5f4fe325ab1d4aad87651e694676cc4eef4c46f2cb38d35b3f677958539a8f184f3535c7ba956babf9301ea24)".to_string() ); assert_eq!( - format!("{:?}", Fq::from_repr(FqRepr([0xe28e79396ac2bbf8, 0x413f6f7f06ea87eb, 0xa4b62af4a792a689, 0xb7f89f88f59c1dc5, 0x9a551859b1e43a9a, 0x6c9f5a1060de974])).unwrap()), + format!("{}", Fq::from_repr(FqRepr([0xe28e79396ac2bbf8, 0x413f6f7f06ea87eb, 0xa4b62af4a792a689, 0xb7f89f88f59c1dc5, 0x9a551859b1e43a9a, 0x6c9f5a1060de974])).unwrap()), "Fq(0x06c9f5a1060de9749a551859b1e43a9ab7f89f88f59c1dc5a4b62af4a792a689413f6f7f06ea87ebe28e79396ac2bbf8)".to_string() ); } @@ -1740,6 +1747,6 @@ fn test_fq_ordering() { // FqRepr's ordering is well-tested, but we still need to make sure the Fq // elements aren't being compared in Montgomery form. for i in 0..100 { - assert!(Fq::from_repr(FqRepr::from(i+1)) > Fq::from_repr(FqRepr::from(i))); + assert!(Fq::from_repr(FqRepr::from(i+1)).unwrap() > Fq::from_repr(FqRepr::from(i)).unwrap()); } } diff --git a/src/bls12_381/fq12.rs b/src/bls12_381/fq12.rs index 354045e48..e918505f7 100644 --- a/src/bls12_381/fq12.rs +++ b/src/bls12_381/fq12.rs @@ -11,6 +11,13 @@ pub struct Fq12 { pub c1: Fq6 } +impl ::std::fmt::Display for Fq12 +{ + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "Fq12({} + {} * w)", self.c0, self.c1) + } +} + impl Rand for Fq12 { fn rand(rng: &mut R) -> Self { Fq12 { diff --git a/src/bls12_381/fq2.rs b/src/bls12_381/fq2.rs index ec22782be..a4d8e7c7f 100644 --- a/src/bls12_381/fq2.rs +++ b/src/bls12_381/fq2.rs @@ -11,6 +11,13 @@ pub struct Fq2 { pub c1: Fq } +impl ::std::fmt::Display for Fq2 +{ + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "Fq2({} + {} * u)", self.c0, self.c1) + } +} + /// `Fq2` elements are ordered lexicographically. impl Ord for Fq2 { #[inline(always)] diff --git a/src/bls12_381/fq6.rs b/src/bls12_381/fq6.rs index 1a31497e0..2c62a9237 100644 --- a/src/bls12_381/fq6.rs +++ b/src/bls12_381/fq6.rs @@ -11,6 +11,13 @@ pub struct Fq6 { pub c2: Fq2 } +impl ::std::fmt::Display for Fq6 +{ + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "Fq6({} + {} * v, {} * v^2)", self.c0, self.c1, self.c2) + } +} + impl Rand for Fq6 { fn rand(rng: &mut R) -> Self { Fq6 { diff --git a/src/bls12_381/fr.rs b/src/bls12_381/fr.rs index c5c80b2e2..c321b7660 100644 --- a/src/bls12_381/fr.rs +++ b/src/bls12_381/fr.rs @@ -1,4 +1,4 @@ -use ::{Field, PrimeField, SqrtField, PrimeFieldRepr}; +use ::{Field, PrimeField, SqrtField, PrimeFieldRepr, PrimeFieldDecodingError}; // r = 52435875175126190479447740508185965837690552500527637822603658699938581184513 const MODULUS: FrRepr = FrRepr([0xffffffff00000001, 0x53bda402fffe5bfe, 0x3339d80809a1d805, 0x73eda753299d7d48]); @@ -28,7 +28,7 @@ const S: usize = 32; // 2^s root of unity computed by GENERATOR^t const ROOT_OF_UNITY: FrRepr = FrRepr([0xb9b58d8c5f0e466a, 0x5b1b4c801819d7ec, 0xaf53ae352a31e64, 0x5bf3adda19e9b27b]); -#[derive(Copy, Clone, PartialEq, Eq, Default)] +#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)] pub struct FrRepr(pub [u64; 4]); impl ::rand::Rand for FrRepr { @@ -38,7 +38,7 @@ impl ::rand::Rand for FrRepr { } } -impl ::std::fmt::Debug for FrRepr +impl ::std::fmt::Display for FrRepr { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { try!(write!(f, "0x")); @@ -57,6 +57,13 @@ impl AsRef<[u64]> for FrRepr { } } +impl AsMut<[u64]> for FrRepr { + #[inline(always)] + fn as_mut(&mut self) -> &mut [u64] { + &mut self.0 + } +} + impl From for FrRepr { #[inline(always)] fn from(val: u64) -> FrRepr { @@ -191,13 +198,13 @@ impl PrimeFieldRepr for FrRepr { } } -#[derive(Copy, Clone, PartialEq, Eq)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct Fr(FrRepr); -impl ::std::fmt::Debug for Fr +impl ::std::fmt::Display for Fr { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - write!(f, "Fr({:?})", self.into_repr()) + write!(f, "Fr({})", self.into_repr()) } } @@ -222,14 +229,14 @@ impl From for FrRepr { impl PrimeField for Fr { type Repr = FrRepr; - fn from_repr(r: FrRepr) -> Result { + fn from_repr(r: FrRepr) -> Result { let mut r = Fr(r); if r.is_valid() { r.mul_assign(&Fr(R2)); Ok(r) } else { - Err(()) + Err(PrimeFieldDecodingError::NotInField(format!("{}", r.0))) } } @@ -1388,33 +1395,33 @@ fn bench_fr_from_repr(b: &mut ::test::Bencher) { } #[test] -fn test_fr_repr_debug() { +fn test_fr_repr_display() { assert_eq!( - format!("{:?}", FrRepr([0x2829c242fa826143, 0x1f32cf4dd4330917, 0x932e4e479d168cd9, 0x513c77587f563f64])), + format!("{}", FrRepr([0x2829c242fa826143, 0x1f32cf4dd4330917, 0x932e4e479d168cd9, 0x513c77587f563f64])), "0x513c77587f563f64932e4e479d168cd91f32cf4dd43309172829c242fa826143".to_string() ); assert_eq!( - format!("{:?}", FrRepr([0x25ebe3a3ad3c0c6a, 0x6990e39d092e817c, 0x941f900d42f5658e, 0x44f8a103b38a71e0])), + format!("{}", FrRepr([0x25ebe3a3ad3c0c6a, 0x6990e39d092e817c, 0x941f900d42f5658e, 0x44f8a103b38a71e0])), "0x44f8a103b38a71e0941f900d42f5658e6990e39d092e817c25ebe3a3ad3c0c6a".to_string() ); assert_eq!( - format!("{:?}", FrRepr([0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff])), + format!("{}", FrRepr([0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff])), "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".to_string() ); assert_eq!( - format!("{:?}", FrRepr([0, 0, 0, 0])), + format!("{}", FrRepr([0, 0, 0, 0])), "0x0000000000000000000000000000000000000000000000000000000000000000".to_string() ); } #[test] -fn test_fr_debug() { +fn test_fr_display() { assert_eq!( - format!("{:?}", Fr::from_repr(FrRepr([0xc3cae746a3b5ecc7, 0x185ec8eb3f5b5aee, 0x684499ffe4b9dd99, 0x7c9bba7afb68faa])).unwrap()), + format!("{}", Fr::from_repr(FrRepr([0xc3cae746a3b5ecc7, 0x185ec8eb3f5b5aee, 0x684499ffe4b9dd99, 0x7c9bba7afb68faa])).unwrap()), "Fr(0x07c9bba7afb68faa684499ffe4b9dd99185ec8eb3f5b5aeec3cae746a3b5ecc7)".to_string() ); assert_eq!( - format!("{:?}", Fr::from_repr(FrRepr([0x44c71298ff198106, 0xb0ad10817df79b6a, 0xd034a80a2b74132b, 0x41cf9a1336f50719])).unwrap()), + format!("{}", Fr::from_repr(FrRepr([0x44c71298ff198106, 0xb0ad10817df79b6a, 0xd034a80a2b74132b, 0x41cf9a1336f50719])).unwrap()), "Fr(0x41cf9a1336f50719d034a80a2b74132bb0ad10817df79b6a44c71298ff198106)".to_string() ); } diff --git a/src/bls12_381/tests/mod.rs b/src/bls12_381/tests/mod.rs index 41a54d7c3..08de50832 100644 --- a/src/bls12_381/tests/mod.rs +++ b/src/bls12_381/tests/mod.rs @@ -46,3 +46,508 @@ fn test_g2_compressed_valid_vectors() { test_vectors::(include_bytes!("g2_compressed_valid_test_vectors.dat")); } +#[test] +fn test_g1_uncompressed_invalid_vectors() { + { + let z = G1Affine::zero().into_uncompressed(); + + { + let mut z = z; + z.as_mut()[0] |= 0b1000_0000; + if let Err(GroupDecodingError::UnexpectedCompressionMode) = z.into_affine() { + // :) + } else { + panic!("should have rejected the point because we expected an uncompressed point"); + } + } + + { + let mut z = z; + z.as_mut()[0] |= 0b0010_0000; + if let Err(GroupDecodingError::UnexpectedInformation) = z.into_affine() { + // :) + } else { + panic!("should have rejected the point because the parity bit should not be set if the point is at infinity"); + } + } + + for i in 0..G1Uncompressed::size() { + let mut z = z; + z.as_mut()[i] |= 0b0000_0001; + if let Err(GroupDecodingError::UnexpectedInformation) = z.into_affine() { + // :) + } else { + panic!("should have rejected the point because the coordinates should be zeroes at the point at infinity"); + } + } + } + + let o = G1Affine::one().into_uncompressed(); + + { + let mut o = o; + o.as_mut()[0] |= 0b1000_0000; + if let Err(GroupDecodingError::UnexpectedCompressionMode) = o.into_affine() { + // :) + } else { + panic!("should have rejected the point because we expected an uncompressed point"); + } + } + + let m = Fq::char(); + + { + let mut o = o; + m.write_be(&mut o.as_mut()[0..]).unwrap(); + + if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() { + assert_eq!(coordinate, "x coordinate"); + } else { + panic!("should have rejected the point") + } + } + + { + let mut o = o; + m.write_be(&mut o.as_mut()[48..]).unwrap(); + + if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() { + assert_eq!(coordinate, "y coordinate"); + } else { + panic!("should have rejected the point") + } + } + + { + let m = Fq::zero().into_repr(); + + let mut o = o; + m.write_be(&mut o.as_mut()[0..]).unwrap(); + + if let Err(GroupDecodingError::NotOnCurve) = o.into_affine() { + // :) + } else { + panic!("should have rejected the point because it isn't on the curve") + } + } + + { + let mut o = o; + let mut x = Fq::one(); + + loop { + let mut x3b = x; + x3b.square(); + x3b.mul_assign(&x); + x3b.add_assign(&Fq::from_repr(FqRepr::from(4)).unwrap()); // TODO: perhaps expose coeff_b through API? + + if let Some(y) = x3b.sqrt() { + // We know this is on the curve, but it's likely not going to be in the correct subgroup. + x.into_repr().write_be(&mut o.as_mut()[0..]).unwrap(); + y.into_repr().write_be(&mut o.as_mut()[48..]).unwrap(); + + if let Err(GroupDecodingError::NotInSubgroup) = o.into_affine() { + break + } else { + panic!("should have rejected the point because it isn't in the correct subgroup") + } + } else { + x.add_assign(&Fq::one()); + } + } + } +} + +#[test] +fn test_g2_uncompressed_invalid_vectors() { + { + let z = G2Affine::zero().into_uncompressed(); + + { + let mut z = z; + z.as_mut()[0] |= 0b1000_0000; + if let Err(GroupDecodingError::UnexpectedCompressionMode) = z.into_affine() { + // :) + } else { + panic!("should have rejected the point because we expected an uncompressed point"); + } + } + + { + let mut z = z; + z.as_mut()[0] |= 0b0010_0000; + if let Err(GroupDecodingError::UnexpectedInformation) = z.into_affine() { + // :) + } else { + panic!("should have rejected the point because the parity bit should not be set if the point is at infinity"); + } + } + + for i in 0..G2Uncompressed::size() { + let mut z = z; + z.as_mut()[i] |= 0b0000_0001; + if let Err(GroupDecodingError::UnexpectedInformation) = z.into_affine() { + // :) + } else { + panic!("should have rejected the point because the coordinates should be zeroes at the point at infinity"); + } + } + } + + let o = G2Affine::one().into_uncompressed(); + + { + let mut o = o; + o.as_mut()[0] |= 0b1000_0000; + if let Err(GroupDecodingError::UnexpectedCompressionMode) = o.into_affine() { + // :) + } else { + panic!("should have rejected the point because we expected an uncompressed point"); + } + } + + let m = Fq::char(); + + { + let mut o = o; + m.write_be(&mut o.as_mut()[0..]).unwrap(); + + if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() { + assert_eq!(coordinate, "x coordinate (c1)"); + } else { + panic!("should have rejected the point") + } + } + + { + let mut o = o; + m.write_be(&mut o.as_mut()[48..]).unwrap(); + + if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() { + assert_eq!(coordinate, "x coordinate (c0)"); + } else { + panic!("should have rejected the point") + } + } + + { + let mut o = o; + m.write_be(&mut o.as_mut()[96..]).unwrap(); + + if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() { + assert_eq!(coordinate, "y coordinate (c1)"); + } else { + panic!("should have rejected the point") + } + } + + { + let mut o = o; + m.write_be(&mut o.as_mut()[144..]).unwrap(); + + if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() { + assert_eq!(coordinate, "y coordinate (c0)"); + } else { + panic!("should have rejected the point") + } + } + + { + let m = Fq::zero().into_repr(); + + let mut o = o; + m.write_be(&mut o.as_mut()[0..]).unwrap(); + m.write_be(&mut o.as_mut()[48..]).unwrap(); + + if let Err(GroupDecodingError::NotOnCurve) = o.into_affine() { + // :) + } else { + panic!("should have rejected the point because it isn't on the curve") + } + } + + { + let mut o = o; + let mut x = Fq2::one(); + + loop { + let mut x3b = x; + x3b.square(); + x3b.mul_assign(&x); + x3b.add_assign(&Fq2 { + c0: Fq::from_repr(FqRepr::from(4)).unwrap(), + c1: Fq::from_repr(FqRepr::from(4)).unwrap() + }); // TODO: perhaps expose coeff_b through API? + + if let Some(y) = x3b.sqrt() { + // We know this is on the curve, but it's likely not going to be in the correct subgroup. + x.c1.into_repr().write_be(&mut o.as_mut()[0..]).unwrap(); + x.c0.into_repr().write_be(&mut o.as_mut()[48..]).unwrap(); + y.c1.into_repr().write_be(&mut o.as_mut()[96..]).unwrap(); + y.c0.into_repr().write_be(&mut o.as_mut()[144..]).unwrap(); + + if let Err(GroupDecodingError::NotInSubgroup) = o.into_affine() { + break + } else { + panic!("should have rejected the point because it isn't in the correct subgroup") + } + } else { + x.add_assign(&Fq2::one()); + } + } + } +} + +#[test] +fn test_g1_compressed_invalid_vectors() { + { + let z = G1Affine::zero().into_compressed(); + + { + let mut z = z; + z.as_mut()[0] &= 0b0111_1111; + if let Err(GroupDecodingError::UnexpectedCompressionMode) = z.into_affine() { + // :) + } else { + panic!("should have rejected the point because we expected a compressed point"); + } + } + + { + let mut z = z; + z.as_mut()[0] |= 0b0010_0000; + if let Err(GroupDecodingError::UnexpectedInformation) = z.into_affine() { + // :) + } else { + panic!("should have rejected the point because the parity bit should not be set if the point is at infinity"); + } + } + + for i in 0..G1Compressed::size() { + let mut z = z; + z.as_mut()[i] |= 0b0000_0001; + if let Err(GroupDecodingError::UnexpectedInformation) = z.into_affine() { + // :) + } else { + panic!("should have rejected the point because the coordinates should be zeroes at the point at infinity"); + } + } + } + + let o = G1Affine::one().into_compressed(); + + { + let mut o = o; + o.as_mut()[0] &= 0b0111_1111; + if let Err(GroupDecodingError::UnexpectedCompressionMode) = o.into_affine() { + // :) + } else { + panic!("should have rejected the point because we expected a compressed point"); + } + } + + let m = Fq::char(); + + { + let mut o = o; + m.write_be(&mut o.as_mut()[0..]).unwrap(); + o.as_mut()[0] |= 0b1000_0000; + + if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() { + assert_eq!(coordinate, "x coordinate"); + } else { + panic!("should have rejected the point") + } + } + + { + let mut o = o; + let mut x = Fq::one(); + + loop { + let mut x3b = x; + x3b.square(); + x3b.mul_assign(&x); + x3b.add_assign(&Fq::from_repr(FqRepr::from(4)).unwrap()); // TODO: perhaps expose coeff_b through API? + + if let Some(_) = x3b.sqrt() { + x.add_assign(&Fq::one()); + } else { + x.into_repr().write_be(&mut o.as_mut()[0..]).unwrap(); + o.as_mut()[0] |= 0b1000_0000; + + if let Err(GroupDecodingError::NotOnCurve) = o.into_affine() { + break + } else { + panic!("should have rejected the point because it isn't on the curve") + } + } + } + } + + { + let mut o = o; + let mut x = Fq::one(); + + loop { + let mut x3b = x; + x3b.square(); + x3b.mul_assign(&x); + x3b.add_assign(&Fq::from_repr(FqRepr::from(4)).unwrap()); // TODO: perhaps expose coeff_b through API? + + if let Some(_) = x3b.sqrt() { + // We know this is on the curve, but it's likely not going to be in the correct subgroup. + x.into_repr().write_be(&mut o.as_mut()[0..]).unwrap(); + o.as_mut()[0] |= 0b1000_0000; + + if let Err(GroupDecodingError::NotInSubgroup) = o.into_affine() { + break + } else { + panic!("should have rejected the point because it isn't in the correct subgroup") + } + } else { + x.add_assign(&Fq::one()); + } + } + } +} + +#[test] +fn test_g2_compressed_invalid_vectors() { + { + let z = G2Affine::zero().into_compressed(); + + { + let mut z = z; + z.as_mut()[0] &= 0b0111_1111; + if let Err(GroupDecodingError::UnexpectedCompressionMode) = z.into_affine() { + // :) + } else { + panic!("should have rejected the point because we expected a compressed point"); + } + } + + { + let mut z = z; + z.as_mut()[0] |= 0b0010_0000; + if let Err(GroupDecodingError::UnexpectedInformation) = z.into_affine() { + // :) + } else { + panic!("should have rejected the point because the parity bit should not be set if the point is at infinity"); + } + } + + for i in 0..G2Compressed::size() { + let mut z = z; + z.as_mut()[i] |= 0b0000_0001; + if let Err(GroupDecodingError::UnexpectedInformation) = z.into_affine() { + // :) + } else { + panic!("should have rejected the point because the coordinates should be zeroes at the point at infinity"); + } + } + } + + let o = G2Affine::one().into_compressed(); + + { + let mut o = o; + o.as_mut()[0] &= 0b0111_1111; + if let Err(GroupDecodingError::UnexpectedCompressionMode) = o.into_affine() { + // :) + } else { + panic!("should have rejected the point because we expected a compressed point"); + } + } + + let m = Fq::char(); + + { + let mut o = o; + m.write_be(&mut o.as_mut()[0..]).unwrap(); + o.as_mut()[0] |= 0b1000_0000; + + if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() { + assert_eq!(coordinate, "x coordinate (c1)"); + } else { + panic!("should have rejected the point") + } + } + + { + let mut o = o; + m.write_be(&mut o.as_mut()[48..]).unwrap(); + o.as_mut()[0] |= 0b1000_0000; + + if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() { + assert_eq!(coordinate, "x coordinate (c0)"); + } else { + panic!("should have rejected the point") + } + } + + { + let mut o = o; + let mut x = Fq2 { + c0: Fq::one(), + c1: Fq::one() + }; + + loop { + let mut x3b = x; + x3b.square(); + x3b.mul_assign(&x); + x3b.add_assign(&Fq2 { + c0: Fq::from_repr(FqRepr::from(4)).unwrap(), + c1: Fq::from_repr(FqRepr::from(4)).unwrap(), + }); // TODO: perhaps expose coeff_b through API? + + if let Some(_) = x3b.sqrt() { + x.add_assign(&Fq2::one()); + } else { + x.c1.into_repr().write_be(&mut o.as_mut()[0..]).unwrap(); + x.c0.into_repr().write_be(&mut o.as_mut()[48..]).unwrap(); + o.as_mut()[0] |= 0b1000_0000; + + if let Err(GroupDecodingError::NotOnCurve) = o.into_affine() { + break + } else { + panic!("should have rejected the point because it isn't on the curve") + } + } + } + } + + { + let mut o = o; + let mut x = Fq2 { + c0: Fq::one(), + c1: Fq::one() + }; + + loop { + let mut x3b = x; + x3b.square(); + x3b.mul_assign(&x); + x3b.add_assign(&Fq2 { + c0: Fq::from_repr(FqRepr::from(4)).unwrap(), + c1: Fq::from_repr(FqRepr::from(4)).unwrap(), + }); // TODO: perhaps expose coeff_b through API? + + if let Some(_) = x3b.sqrt() { + // We know this is on the curve, but it's likely not going to be in the correct subgroup. + x.c1.into_repr().write_be(&mut o.as_mut()[0..]).unwrap(); + x.c0.into_repr().write_be(&mut o.as_mut()[48..]).unwrap(); + o.as_mut()[0] |= 0b1000_0000; + + if let Err(GroupDecodingError::NotInSubgroup) = o.into_affine() { + break + } else { + panic!("should have rejected the point because it isn't in the correct subgroup") + } + } else { + x.add_assign(&Fq2::one()); + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs index b3df2a02f..04bde0fc0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,6 +28,8 @@ pub mod bls12_381; pub mod wnaf; use std::fmt; +use std::error::Error; +use std::io::{self, Read, Write}; /// An "engine" is a collection of types (fields, elliptic curve groups, etc.) /// with well-defined relationships. In particular, the G1/G2 curve groups are @@ -91,6 +93,7 @@ pub trait CurveProjective: PartialEq + Send + Sync + fmt::Debug + + fmt::Display + rand::Rand + 'static { @@ -158,6 +161,7 @@ pub trait CurveAffine: Copy + Send + Sync + fmt::Debug + + fmt::Display + PartialEq + Eq + 'static @@ -179,9 +183,6 @@ pub trait CurveAffine: Copy + /// additive identity. fn is_zero(&self) -> bool; - /// Determines if this point is on the curve and in the correct subgroup. - fn is_valid(&self) -> bool; - /// Negates this element. fn negate(&mut self); @@ -213,6 +214,8 @@ pub trait EncodedPoint: Sized + Sync + AsRef<[u8]> + AsMut<[u8]> + + Clone + + Copy + 'static { type Affine: CurveAffine; @@ -224,21 +227,17 @@ pub trait EncodedPoint: Sized + fn size() -> usize; /// Converts an `EncodedPoint` into a `CurveAffine` element, - /// if the point is valid. - fn into_affine(&self) -> Result { - let affine = self.into_affine_unchecked()?; - - if affine.is_valid() { - Ok(affine) - } else { - Err(()) - } - } + /// if the encoding represents a valid element. + fn into_affine(&self) -> Result; /// Converts an `EncodedPoint` into a `CurveAffine` element, - /// without checking if it's a valid point. Caller must be careful - /// when using this, as misuse can violate API invariants. - fn into_affine_unchecked(&self) -> Result; + /// 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. @@ -253,6 +252,7 @@ pub trait Field: Sized + Send + Sync + fmt::Debug + + fmt::Display + 'static + rand::Rand { @@ -333,9 +333,11 @@ pub trait PrimeFieldRepr: Sized + Send + Sync + fmt::Debug + + fmt::Display + 'static + rand::Rand + AsRef<[u64]> + + AsMut<[u64]> + From { /// Subtract another reprensetation from this one, returning the borrow bit. @@ -366,6 +368,96 @@ pub trait PrimeFieldRepr: Sized + /// Performs a leftwise bitshift of this number, effectively multiplying /// it by 2. Overflow is ignored. fn mul2(&mut self); + + /// Writes this `PrimeFieldRepr` as a big endian integer. Always writes + /// `(num_bits` / 8) bytes. + fn write_be(&self, mut writer: W) -> io::Result<()> { + use byteorder::{WriteBytesExt, BigEndian}; + + for digit in self.as_ref().iter().rev() { + writer.write_u64::(*digit)?; + } + + Ok(()) + } + + /// Reads a big endian integer occupying (`num_bits` / 8) bytes into this + /// representation. + fn read_be(&mut self, mut reader: R) -> io::Result<()> { + use byteorder::{ReadBytesExt, BigEndian}; + + for digit in self.as_mut().iter_mut().rev() { + *digit = reader.read_u64::()?; + } + + Ok(()) + } +} + +/// An error that may occur when trying to interpret a `PrimeFieldRepr` as a +/// `PrimeField` element. +#[derive(Debug)] +pub enum PrimeFieldDecodingError { + /// The encoded value is not in the field + NotInField(String) +} + +impl Error for PrimeFieldDecodingError { + fn description(&self) -> &str { + match *self { + PrimeFieldDecodingError::NotInField(..) => "not an element of the field" + } + } +} + +impl fmt::Display for PrimeFieldDecodingError { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + match *self { + PrimeFieldDecodingError::NotInField(ref repr) => { + write!(f, "{} is not an element of the field", repr) + } + } + } +} + +/// 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, PrimeFieldDecodingError), + /// The compression mode of the encoded elemnet 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, ref err) => { + write!(f, "{} decoding error: {}", description, err) + }, + _ => { + write!(f, "{}", self.description()) + } + } + } } /// This represents an element of a prime field. @@ -376,7 +468,7 @@ pub trait PrimeField: Field type Repr: PrimeFieldRepr + From; /// Convert this prime field element into a biginteger representation. - fn from_repr(Self::Repr) -> Result; + fn from_repr(Self::Repr) -> Result; /// Convert a biginteger reprensentation into a prime field element, if /// the number is an element of the field.