mirror of
https://github.com/Qortal/pirate-librustzcash.git
synced 2025-01-31 07:42:15 +00:00
Encoding of G1/G2 elements in compressed or uncompressed form.
This commit is contained in:
parent
021077b56b
commit
3faf8c526a
@ -11,3 +11,4 @@ repository = "https://github.com/ebfull/pairing"
|
||||
|
||||
[dependencies]
|
||||
rand = "0.3"
|
||||
byteorder = "1.1"
|
||||
|
@ -4,7 +4,9 @@ macro_rules! curve_impl {
|
||||
$affine:ident,
|
||||
$prepared:ident,
|
||||
$basefield:ident,
|
||||
$scalarfield:ident
|
||||
$scalarfield:ident,
|
||||
$uncompressed:ident,
|
||||
$compressed:ident
|
||||
) => {
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub struct $affine {
|
||||
@ -98,6 +100,8 @@ macro_rules! curve_impl {
|
||||
type Base = $basefield;
|
||||
type Prepared = $prepared;
|
||||
type Projective = $projective;
|
||||
type Uncompressed = $uncompressed;
|
||||
type Compressed = $compressed;
|
||||
|
||||
fn zero() -> Self {
|
||||
$affine {
|
||||
@ -563,10 +567,190 @@ macro_rules! curve_impl {
|
||||
|
||||
pub mod g1 {
|
||||
use rand::{Rand, Rng};
|
||||
use super::super::{Fq, Fr, FrRepr};
|
||||
use ::{CurveProjective, CurveAffine, PrimeField, PrimeFieldRepr, Field, BitIterator};
|
||||
use super::super::{Fq, Fr, FrRepr, FqRepr};
|
||||
use ::{CurveProjective, CurveAffine, PrimeField, SqrtField, PrimeFieldRepr, Field, BitIterator, EncodedPoint};
|
||||
|
||||
curve_impl!(G1, G1Affine, G1Prepared, Fq, Fr);
|
||||
curve_impl!(G1, G1Affine, G1Prepared, Fq, Fr, G1Uncompressed, G1Compressed);
|
||||
|
||||
pub struct G1Uncompressed([u8; 96]);
|
||||
|
||||
impl AsRef<[u8]> for G1Uncompressed {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<[u8]> for G1Uncompressed {
|
||||
fn as_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl EncodedPoint for G1Uncompressed {
|
||||
type Affine = G1Affine;
|
||||
|
||||
fn empty() -> Self { G1Uncompressed([0; 96]) }
|
||||
fn size() -> usize { 96 }
|
||||
fn into_affine_unchecked(&self) -> Result<G1Affine, ()> {
|
||||
use byteorder::{ReadBytesExt, BigEndian};
|
||||
|
||||
let mut x = FqRepr([0; 6]);
|
||||
let mut y = FqRepr([0; 6]);
|
||||
|
||||
{
|
||||
let mut reader = &self.0[..];
|
||||
|
||||
for b in x.0.iter_mut().rev() {
|
||||
*b = reader.read_u64::<BigEndian>().unwrap();
|
||||
}
|
||||
|
||||
for b in y.0.iter_mut().rev() {
|
||||
*b = reader.read_u64::<BigEndian>().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
Ok(G1Affine {
|
||||
x: Fq::from_repr(x)?,
|
||||
y: Fq::from_repr(y)?,
|
||||
infinity: false
|
||||
})
|
||||
}
|
||||
fn from_affine(affine: G1Affine) -> Result<Self, ()> {
|
||||
use byteorder::{WriteBytesExt, BigEndian};
|
||||
|
||||
if affine.is_zero() {
|
||||
return Err(())
|
||||
}
|
||||
|
||||
let mut res = Self::empty();
|
||||
|
||||
{
|
||||
let mut writer = &mut res.0[..];
|
||||
|
||||
for digit in affine.x.into_repr().as_ref().iter().rev() {
|
||||
writer.write_u64::<BigEndian>(*digit).unwrap();
|
||||
}
|
||||
|
||||
for digit in affine.y.into_repr().as_ref().iter().rev() {
|
||||
writer.write_u64::<BigEndian>(*digit).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct G1Compressed([u8; 48]);
|
||||
|
||||
impl AsRef<[u8]> for G1Compressed {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<[u8]> for G1Compressed {
|
||||
fn as_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl EncodedPoint for G1Compressed {
|
||||
type Affine = G1Affine;
|
||||
|
||||
fn empty() -> Self { G1Compressed([0; 48]) }
|
||||
fn size() -> usize { 48 }
|
||||
fn into_affine_unchecked(&self) -> Result<G1Affine, ()> {
|
||||
use byteorder::{ReadBytesExt, BigEndian};
|
||||
|
||||
// Create a copy of this representation.
|
||||
let mut copy = self.0;
|
||||
|
||||
if copy[0] & (1 << 7) == 0 {
|
||||
// Distinguisher bit isn't set.
|
||||
return Err(())
|
||||
}
|
||||
|
||||
// Determine if the intended y coordinate must be greater
|
||||
// lexicographically.
|
||||
let greatest = copy[0] & (1 << 6) != 0;
|
||||
|
||||
// Unset the two most significant bits.
|
||||
copy[0] &= 0x3f;
|
||||
|
||||
let mut x = FqRepr([0; 6]);
|
||||
|
||||
{
|
||||
let mut reader = ©[..];
|
||||
|
||||
for b in x.0.iter_mut().rev() {
|
||||
*b = reader.read_u64::<BigEndian>().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
// Interpret as Fq element.
|
||||
let x = Fq::from_repr(x)?;
|
||||
|
||||
// Compute x^3 + b
|
||||
let mut x3b = x;
|
||||
x3b.square();
|
||||
x3b.mul_assign(&x);
|
||||
x3b.add_assign(&G1Affine::get_coeff_b());
|
||||
|
||||
// Attempt to compute y
|
||||
match x3b.sqrt() {
|
||||
Some(y) => {
|
||||
let mut negy = y;
|
||||
negy.negate();
|
||||
|
||||
// Get the parity of the sqrt we found.
|
||||
let parity = y.into_repr() > negy.into_repr();
|
||||
|
||||
Ok(G1Affine {
|
||||
x: x,
|
||||
y: if parity == greatest { y } else { negy },
|
||||
infinity: false
|
||||
})
|
||||
},
|
||||
None => {
|
||||
// Point must not be on the curve.
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
fn from_affine(affine: G1Affine) -> Result<Self, ()> {
|
||||
use byteorder::{WriteBytesExt, BigEndian};
|
||||
|
||||
if affine.is_zero() {
|
||||
return Err(())
|
||||
}
|
||||
|
||||
let mut res = Self::empty();
|
||||
|
||||
{
|
||||
let mut writer = &mut res.0[..];
|
||||
|
||||
for digit in affine.x.into_repr().as_ref().iter().rev() {
|
||||
writer.write_u64::<BigEndian>(*digit).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
// Distinguish this from an uncompressed element.
|
||||
res.0[0] |= 1 << 7; // Set highest bit.
|
||||
|
||||
{
|
||||
let mut negy = affine.y;
|
||||
negy.negate();
|
||||
|
||||
// If the correct y coordinate is the largest (lexicographically),
|
||||
// the bit should be set.
|
||||
if affine.y.into_repr() > negy.into_repr() {
|
||||
res.0[0] |= 1 << 6; // Set second highest bit.
|
||||
}
|
||||
}
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
impl G1Affine {
|
||||
fn get_generator() -> Self {
|
||||
@ -629,9 +813,6 @@ pub mod g1 {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
use super::super::{FqRepr};
|
||||
|
||||
#[test]
|
||||
fn g1_generator() {
|
||||
use ::SqrtField;
|
||||
@ -880,10 +1061,226 @@ pub mod g1 {
|
||||
|
||||
pub mod g2 {
|
||||
use rand::{Rand, Rng};
|
||||
use super::super::{Fq2, Fr, FrRepr};
|
||||
use ::{CurveProjective, CurveAffine, PrimeField, PrimeFieldRepr, Field, BitIterator};
|
||||
use super::super::{Fq2, Fr, Fq, FrRepr, FqRepr};
|
||||
use ::{CurveProjective, CurveAffine, PrimeField, SqrtField, PrimeFieldRepr, Field, BitIterator, EncodedPoint};
|
||||
|
||||
curve_impl!(G2, G2Affine, G2Prepared, Fq2, Fr);
|
||||
curve_impl!(G2, G2Affine, G2Prepared, Fq2, Fr, G2Uncompressed, G2Compressed);
|
||||
|
||||
pub struct G2Uncompressed([u8; 192]);
|
||||
|
||||
impl AsRef<[u8]> for G2Uncompressed {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<[u8]> for G2Uncompressed {
|
||||
fn as_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl EncodedPoint for G2Uncompressed {
|
||||
type Affine = G2Affine;
|
||||
|
||||
fn empty() -> Self { G2Uncompressed([0; 192]) }
|
||||
fn size() -> usize { 192 }
|
||||
fn into_affine_unchecked(&self) -> Result<G2Affine, ()> {
|
||||
use byteorder::{ReadBytesExt, BigEndian};
|
||||
|
||||
let mut x_c1 = FqRepr([0; 6]);
|
||||
let mut x_c0 = FqRepr([0; 6]);
|
||||
let mut y_c1 = FqRepr([0; 6]);
|
||||
let mut y_c0 = FqRepr([0; 6]);
|
||||
|
||||
{
|
||||
let mut reader = &self.0[..];
|
||||
|
||||
for b in x_c1.0.iter_mut().rev() {
|
||||
*b = reader.read_u64::<BigEndian>().unwrap();
|
||||
}
|
||||
|
||||
for b in x_c0.0.iter_mut().rev() {
|
||||
*b = reader.read_u64::<BigEndian>().unwrap();
|
||||
}
|
||||
|
||||
for b in y_c1.0.iter_mut().rev() {
|
||||
*b = reader.read_u64::<BigEndian>().unwrap();
|
||||
}
|
||||
|
||||
for b in y_c0.0.iter_mut().rev() {
|
||||
*b = reader.read_u64::<BigEndian>().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
Ok(G2Affine {
|
||||
x: Fq2 {
|
||||
c0: Fq::from_repr(x_c0)?,
|
||||
c1: Fq::from_repr(x_c1)?
|
||||
},
|
||||
y: Fq2 {
|
||||
c0: Fq::from_repr(y_c0)?,
|
||||
c1: Fq::from_repr(y_c1)?
|
||||
},
|
||||
infinity: false
|
||||
})
|
||||
}
|
||||
fn from_affine(affine: G2Affine) -> Result<Self, ()> {
|
||||
use byteorder::{WriteBytesExt, BigEndian};
|
||||
|
||||
if affine.is_zero() {
|
||||
return Err(())
|
||||
}
|
||||
|
||||
let mut res = Self::empty();
|
||||
|
||||
{
|
||||
let mut writer = &mut res.0[..];
|
||||
|
||||
for digit in affine.x.c1.into_repr().as_ref().iter().rev() {
|
||||
writer.write_u64::<BigEndian>(*digit).unwrap();
|
||||
}
|
||||
|
||||
for digit in affine.x.c0.into_repr().as_ref().iter().rev() {
|
||||
writer.write_u64::<BigEndian>(*digit).unwrap();
|
||||
}
|
||||
|
||||
for digit in affine.y.c1.into_repr().as_ref().iter().rev() {
|
||||
writer.write_u64::<BigEndian>(*digit).unwrap();
|
||||
}
|
||||
|
||||
for digit in affine.y.c0.into_repr().as_ref().iter().rev() {
|
||||
writer.write_u64::<BigEndian>(*digit).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct G2Compressed([u8; 96]);
|
||||
|
||||
impl AsRef<[u8]> for G2Compressed {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<[u8]> for G2Compressed {
|
||||
fn as_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl EncodedPoint for G2Compressed {
|
||||
type Affine = G2Affine;
|
||||
|
||||
fn empty() -> Self { G2Compressed([0; 96]) }
|
||||
fn size() -> usize { 96 }
|
||||
fn into_affine_unchecked(&self) -> Result<G2Affine, ()> {
|
||||
use byteorder::{ReadBytesExt, BigEndian};
|
||||
|
||||
// Create a copy of this representation.
|
||||
let mut copy = self.0;
|
||||
|
||||
if copy[0] & (1 << 7) == 0 {
|
||||
// Distinguisher bit isn't set.
|
||||
return Err(())
|
||||
}
|
||||
|
||||
// Determine if the intended y coordinate must be greater
|
||||
// lexicographically.
|
||||
let greatest = copy[0] & (1 << 6) != 0;
|
||||
|
||||
// Unset the two most significant bits.
|
||||
copy[0] &= 0x3f;
|
||||
|
||||
let mut x_c1 = FqRepr([0; 6]);
|
||||
let mut x_c0 = FqRepr([0; 6]);
|
||||
|
||||
{
|
||||
let mut reader = ©[..];
|
||||
|
||||
for b in x_c1.0.iter_mut().rev() {
|
||||
*b = reader.read_u64::<BigEndian>().unwrap();
|
||||
}
|
||||
|
||||
for b in x_c0.0.iter_mut().rev() {
|
||||
*b = reader.read_u64::<BigEndian>().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
// Interpret as Fq element.
|
||||
let x = Fq2 {
|
||||
c0: Fq::from_repr(x_c0)?,
|
||||
c1: Fq::from_repr(x_c1)?
|
||||
};
|
||||
|
||||
// Compute x^3 + b
|
||||
let mut x3b = x;
|
||||
x3b.square();
|
||||
x3b.mul_assign(&x);
|
||||
x3b.add_assign(&G2Affine::get_coeff_b());
|
||||
|
||||
// Attempt to compute y
|
||||
match x3b.sqrt() {
|
||||
Some(y) => {
|
||||
let mut negy = y;
|
||||
negy.negate();
|
||||
|
||||
// Get the parity of the sqrt we found.
|
||||
let parity = y > negy;
|
||||
|
||||
Ok(G2Affine {
|
||||
x: x,
|
||||
y: if parity == greatest { y } else { negy },
|
||||
infinity: false
|
||||
})
|
||||
},
|
||||
None => {
|
||||
// Point must not be on the curve.
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
fn from_affine(affine: G2Affine) -> Result<Self, ()> {
|
||||
use byteorder::{WriteBytesExt, BigEndian};
|
||||
|
||||
if affine.is_zero() {
|
||||
return Err(())
|
||||
}
|
||||
|
||||
let mut res = Self::empty();
|
||||
|
||||
{
|
||||
let mut writer = &mut res.0[..];
|
||||
|
||||
for digit in affine.x.c1.into_repr().as_ref().iter().rev() {
|
||||
writer.write_u64::<BigEndian>(*digit).unwrap();
|
||||
}
|
||||
|
||||
for digit in affine.x.c0.into_repr().as_ref().iter().rev() {
|
||||
writer.write_u64::<BigEndian>(*digit).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
// Distinguish this from an uncompressed element.
|
||||
res.0[0] |= 1 << 7; // Set highest bit.
|
||||
|
||||
{
|
||||
let mut negy = affine.y;
|
||||
negy.negate();
|
||||
|
||||
// If the correct y coordinate is the largest (lexicographically),
|
||||
// the bit should be set.
|
||||
if affine.y > negy {
|
||||
res.0[0] |= 1 << 6; // Set second highest bit.
|
||||
}
|
||||
}
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
impl G2Affine {
|
||||
fn get_generator() -> Self {
|
||||
@ -948,9 +1345,6 @@ pub mod g2 {
|
||||
pub(crate) infinity: bool
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
use super::super::{Fq, FqRepr};
|
||||
|
||||
#[test]
|
||||
fn g2_generator() {
|
||||
use ::SqrtField;
|
||||
@ -965,14 +1359,12 @@ pub mod g2 {
|
||||
rhs.add_assign(&G2Affine::get_coeff_b());
|
||||
|
||||
if let Some(y) = rhs.sqrt() {
|
||||
let yrepr = y.c1.into_repr();
|
||||
let mut negy = y;
|
||||
negy.negate();
|
||||
let negyrepr = negy.c1.into_repr();
|
||||
|
||||
let p = G2Affine {
|
||||
x: x,
|
||||
y: if yrepr < negyrepr { y } else { negy },
|
||||
y: if y < negy { y } else { negy },
|
||||
infinity: false
|
||||
};
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
use rand::{Rng, Rand};
|
||||
use ::{Field, SqrtField};
|
||||
use ::{Field, SqrtField, PrimeField};
|
||||
use super::fq::{Fq, FROBENIUS_COEFF_FQ2_C1, NEGATIVE_ONE};
|
||||
|
||||
use std::cmp::Ordering;
|
||||
|
||||
/// An element of F_{q^2}, represented by c0 + c1 * u.
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub struct Fq2 {
|
||||
@ -9,6 +11,24 @@ pub struct Fq2 {
|
||||
pub c1: Fq
|
||||
}
|
||||
|
||||
impl Ord for Fq2 {
|
||||
#[inline(always)]
|
||||
fn cmp(&self, other: &Fq2) -> Ordering {
|
||||
match self.c1.into_repr().cmp(&other.c1.into_repr()) {
|
||||
Ordering::Greater => Ordering::Greater,
|
||||
Ordering::Less => Ordering::Less,
|
||||
Ordering::Equal => self.c0.into_repr().cmp(&other.c0.into_repr())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Fq2 {
|
||||
#[inline(always)]
|
||||
fn partial_cmp(&self, other: &Fq2) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Fq2 {
|
||||
/// Multiply this element by the cubic and quadratic nonresidue 1 + u.
|
||||
pub fn mul_by_nonresidue(&mut self) {
|
||||
@ -157,6 +177,30 @@ impl SqrtField for Fq2 {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq2_ordering() {
|
||||
let mut a = Fq2 {
|
||||
c0: Fq::zero(),
|
||||
c1: Fq::zero()
|
||||
};
|
||||
|
||||
let mut b = a.clone();
|
||||
|
||||
assert!(a.cmp(&b) == Ordering::Equal);
|
||||
b.c0.add_assign(&Fq::one());
|
||||
assert!(a.cmp(&b) == Ordering::Less);
|
||||
a.c0.add_assign(&Fq::one());
|
||||
assert!(a.cmp(&b) == Ordering::Equal);
|
||||
b.c1.add_assign(&Fq::one());
|
||||
assert!(a.cmp(&b) == Ordering::Less);
|
||||
a.c0.add_assign(&Fq::one());
|
||||
assert!(a.cmp(&b) == Ordering::Less);
|
||||
a.c1.add_assign(&Fq::one());
|
||||
assert!(a.cmp(&b) == Ordering::Greater);
|
||||
b.c0.add_assign(&Fq::one());
|
||||
assert!(a.cmp(&b) == Ordering::Equal);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fq2_basics() {
|
||||
assert_eq!(Fq2 { c0: Fq::zero(), c1: Fq::zero() }, Fq2::zero());
|
||||
|
@ -5,11 +5,14 @@ mod fq6;
|
||||
mod fq12;
|
||||
mod ec;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub use self::fr::{Fr, FrRepr};
|
||||
pub use self::fq::{Fq, FqRepr};
|
||||
pub use self::fq2::Fq2;
|
||||
pub use self::fq12::Fq12;
|
||||
pub use self::ec::{G1, G2, G1Affine, G2Affine, G1Prepared, G2Prepared};
|
||||
pub use self::ec::{G1, G2, G1Affine, G2Affine, G1Prepared, G2Prepared, G1Uncompressed, G2Uncompressed, G1Compressed, G2Compressed};
|
||||
|
||||
use super::{Engine, CurveAffine, Field, BitIterator};
|
||||
|
||||
|
BIN
src/bls12_381/tests/g1_compressed_test_vectors.dat
Normal file
BIN
src/bls12_381/tests/g1_compressed_test_vectors.dat
Normal file
Binary file not shown.
BIN
src/bls12_381/tests/g1_uncompressed_test_vectors.dat
Normal file
BIN
src/bls12_381/tests/g1_uncompressed_test_vectors.dat
Normal file
Binary file not shown.
BIN
src/bls12_381/tests/g2_compressed_test_vectors.dat
Normal file
BIN
src/bls12_381/tests/g2_compressed_test_vectors.dat
Normal file
Binary file not shown.
BIN
src/bls12_381/tests/g2_uncompressed_test_vectors.dat
Normal file
BIN
src/bls12_381/tests/g2_uncompressed_test_vectors.dat
Normal file
Binary file not shown.
48
src/bls12_381/tests/mod.rs
Normal file
48
src/bls12_381/tests/mod.rs
Normal file
@ -0,0 +1,48 @@
|
||||
use super::*;
|
||||
use ::*;
|
||||
|
||||
fn test_vectors<G: CurveProjective, E: EncodedPoint<Affine=G::Affine>>(expected: &[u8])
|
||||
{
|
||||
let mut e = G::one();
|
||||
|
||||
let mut v = vec![];
|
||||
{
|
||||
let mut expected = expected;
|
||||
for _ in 0..1000 {
|
||||
let e_affine = e.to_affine();
|
||||
let encoded = E::from_affine(e_affine).unwrap();
|
||||
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();
|
||||
assert_eq!(e_affine, decoded);
|
||||
|
||||
e.add_assign(&G::one());
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(&v[..], expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_g1_uncompressed_vectors() {
|
||||
test_vectors::<G1, G1Uncompressed>(include_bytes!("g1_uncompressed_test_vectors.dat"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_g1_compressed_vectors() {
|
||||
test_vectors::<G1, G1Compressed>(include_bytes!("g1_compressed_test_vectors.dat"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_g2_uncompressed_vectors() {
|
||||
test_vectors::<G2, G2Uncompressed>(include_bytes!("g2_uncompressed_test_vectors.dat"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_g2_compressed_vectors() {
|
||||
test_vectors::<G2, G2Compressed>(include_bytes!("g2_compressed_test_vectors.dat"));
|
||||
}
|
||||
|
53
src/lib.rs
53
src/lib.rs
@ -5,6 +5,7 @@
|
||||
extern crate test;
|
||||
|
||||
extern crate rand;
|
||||
extern crate byteorder;
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests;
|
||||
@ -151,6 +152,8 @@ pub trait CurveAffine: Copy +
|
||||
type Base: SqrtField;
|
||||
type Projective: CurveProjective<Affine=Self, Scalar=Self::Scalar>;
|
||||
type Prepared: Clone + Send + Sync + 'static;
|
||||
type Uncompressed: EncodedPoint<Affine=Self>;
|
||||
type Compressed: EncodedPoint<Affine=Self>;
|
||||
|
||||
/// Returns the additive identity.
|
||||
fn zero() -> Self;
|
||||
@ -176,6 +179,56 @@ pub trait CurveAffine: Copy +
|
||||
|
||||
/// Converts this element into its affine representation.
|
||||
fn to_projective(&self) -> Self::Projective;
|
||||
|
||||
/// Converts this element into its compressed encoding, so long as it's not
|
||||
/// the point at infinity.
|
||||
fn to_compressed(&self) -> Result<Self::Compressed, ()> {
|
||||
<Self::Compressed as EncodedPoint>::from_affine(*self)
|
||||
}
|
||||
|
||||
/// Converts this element into its uncompressed encoding, so long as it's not
|
||||
/// the point at infinity.
|
||||
fn to_uncompressed(&self) -> Result<Self::Uncompressed, ()> {
|
||||
<Self::Uncompressed as EncodedPoint>::from_affine(*self)
|
||||
}
|
||||
}
|
||||
|
||||
/// An encoded elliptic curve point, which should essentially wrap a `[u8; N]`.
|
||||
pub trait EncodedPoint: Sized +
|
||||
Send +
|
||||
Sync +
|
||||
AsRef<[u8]> +
|
||||
AsMut<[u8]> +
|
||||
'static
|
||||
{
|
||||
type Affine: CurveAffine;
|
||||
|
||||
/// Creates an empty representation.
|
||||
fn empty() -> Self;
|
||||
|
||||
/// Returns the number of bytes consumed by this representation.
|
||||
fn size() -> usize;
|
||||
|
||||
/// Converts an `EncodedPoint` into a `CurveAffine` element,
|
||||
/// if the point is valid.
|
||||
fn into_affine(&self) -> Result<Self::Affine, ()> {
|
||||
let affine = self.into_affine_unchecked()?;
|
||||
|
||||
if affine.is_valid() {
|
||||
Ok(affine)
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
/// 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<Self::Affine, ()>;
|
||||
|
||||
/// Creates an `EncodedPoint` from an affine point, as long as the
|
||||
/// point is not the point at infinity.
|
||||
fn from_affine(affine: Self::Affine) -> Result<Self, ()>;
|
||||
}
|
||||
|
||||
/// This trait represents an element of a field.
|
||||
|
@ -1,6 +1,6 @@
|
||||
use rand::{SeedableRng, XorShiftRng, Rand};
|
||||
|
||||
use ::{CurveProjective, CurveAffine, Field};
|
||||
use ::{CurveProjective, CurveAffine, Field, EncodedPoint};
|
||||
|
||||
pub fn curve_tests<G: CurveProjective>()
|
||||
{
|
||||
@ -59,6 +59,7 @@ pub fn curve_tests<G: CurveProjective>()
|
||||
random_negation_tests::<G>();
|
||||
random_transformation_tests::<G>();
|
||||
random_wnaf_tests::<G>();
|
||||
random_encoding_tests::<G::Affine>();
|
||||
}
|
||||
|
||||
fn random_wnaf_tests<G: CurveProjective>() {
|
||||
@ -291,3 +292,29 @@ fn random_transformation_tests<G: CurveProjective>() {
|
||||
assert_eq!(v, expected_v);
|
||||
}
|
||||
}
|
||||
|
||||
fn random_encoding_tests<G: CurveAffine>()
|
||||
{
|
||||
assert!(G::zero().to_compressed().is_err());
|
||||
assert!(G::zero().to_uncompressed().is_err());
|
||||
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let mut r = G::Projective::rand(&mut rng).to_affine();
|
||||
|
||||
let uncompressed = r.to_uncompressed().unwrap();
|
||||
let de_uncompressed = uncompressed.into_affine().unwrap();
|
||||
assert_eq!(de_uncompressed, r);
|
||||
|
||||
let compressed = r.to_compressed().unwrap();
|
||||
let de_compressed = compressed.into_affine().unwrap();
|
||||
assert_eq!(de_compressed, r);
|
||||
|
||||
r.negate();
|
||||
|
||||
let compressed = r.to_compressed().unwrap();
|
||||
let de_compressed = compressed.into_affine().unwrap();
|
||||
assert_eq!(de_compressed, r);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user