Implements and documents serialization, closes #11.
This commit is contained in:
parent
e72660056e
commit
c618240c91
@ -55,3 +55,17 @@ y = 1339506544944476473020471379941921221584933875938349620426543736416511423956
|
|||||||
x = 3059144344244213709971259814753781636986470325476647558659373206291635324768958432433509563104347017837885763365758*u + 352701069587466618187139116011060144890029952792775240219908644239793785735715026873347600343865175952761926303160
|
x = 3059144344244213709971259814753781636986470325476647558659373206291635324768958432433509563104347017837885763365758*u + 352701069587466618187139116011060144890029952792775240219908644239793785735715026873347600343865175952761926303160
|
||||||
y = 927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582*u + 1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905
|
y = 927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582*u + 1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Serialization
|
||||||
|
|
||||||
|
* Fq elements are encoded in big-endian form. They occupy 48 bytes in this form.
|
||||||
|
* Fq2 elements are encoded in big-endian form, meaning that the Fq element c0 + c1 * u is represented by the Fq element c1 followed by the Fq element c0. This means Fq2 elements occupy 96 bytes in this form.
|
||||||
|
* The group G1 uses Fq elements for coordinates. The group G2 uses Fq2 elements for coordinates.
|
||||||
|
* G1 and G2 elements can be encoded in uncompressed form (the x-coordinate followed by the y-coordinate) or in compressed form (just the x-coordinate). G1 elements occupy 96 bytes in uncompressed form, and 48 bytes in compressed form. G2 elements occupy 192 bytes in uncompressed form, and 96 bytes in compressed form.
|
||||||
|
|
||||||
|
The most-significant three bits of a G1 or G2 encoding should be masked away before the coordinate(s) are interpreted. These bits are used to unambiguously represent the underlying element:
|
||||||
|
|
||||||
|
* The most significant bit, when set, indicates that the point is in compressed form. Otherwise, the point is in uncompressed form.
|
||||||
|
* The second-most significant bit indicates that the point is at infinity. If this bit is set, the remaining bits of the group element's encoding should be set to zero.
|
||||||
|
* The third-most significant bit is set if (and only if) this point is in compressed form _and_ it is not the point at infinity _and_ its y-coordinate is the lexicographically largest of the two associated with the encoded x-coordinate.
|
||||||
|
|
||||||
|
@ -586,37 +586,67 @@ pub mod g1 {
|
|||||||
fn into_affine_unchecked(&self) -> Result<G1Affine, ()> {
|
fn into_affine_unchecked(&self) -> Result<G1Affine, ()> {
|
||||||
use byteorder::{ReadBytesExt, BigEndian};
|
use byteorder::{ReadBytesExt, BigEndian};
|
||||||
|
|
||||||
let mut x = FqRepr([0; 6]);
|
// Create a copy of this representation.
|
||||||
let mut y = FqRepr([0; 6]);
|
let mut copy = self.0;
|
||||||
|
|
||||||
{
|
if copy[0] & (1 << 7) != 0 {
|
||||||
let mut reader = &self.0[..];
|
// Distinguisher bit is set, but this should be uncompressed!
|
||||||
|
|
||||||
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(())
|
return Err(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if copy[0] & (1 << 6) != 0 {
|
||||||
|
// This is the point at infinity, which means that if we mask away
|
||||||
|
// the first two bits, the entire representation should consist
|
||||||
|
// of zeroes.
|
||||||
|
copy[0] &= 0x3f;
|
||||||
|
|
||||||
|
if copy.iter().all(|b| *b == 0) {
|
||||||
|
Ok(G1Affine::zero())
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
} 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(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unset the three most significant bits.
|
||||||
|
copy[0] &= 0x1f;
|
||||||
|
|
||||||
|
let mut x = FqRepr([0; 6]);
|
||||||
|
let mut y = FqRepr([0; 6]);
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut reader = ©[..];
|
||||||
|
|
||||||
|
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) -> Self {
|
||||||
|
use byteorder::{WriteBytesExt, BigEndian};
|
||||||
|
|
||||||
let mut res = Self::empty();
|
let mut res = Self::empty();
|
||||||
|
|
||||||
{
|
if affine.is_zero() {
|
||||||
|
// Set the second-most significant bit to indicate this point
|
||||||
|
// is at infinity.
|
||||||
|
res.0[0] |= 1 << 6;
|
||||||
|
} else {
|
||||||
let mut writer = &mut res.0[..];
|
let mut writer = &mut res.0[..];
|
||||||
|
|
||||||
for digit in affine.x.into_repr().as_ref().iter().rev() {
|
for digit in affine.x.into_repr().as_ref().iter().rev() {
|
||||||
@ -628,7 +658,7 @@ pub mod g1 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(res)
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -662,85 +692,98 @@ pub mod g1 {
|
|||||||
return Err(())
|
return Err(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine if the intended y coordinate must be greater
|
if copy[0] & (1 << 6) != 0 {
|
||||||
// lexicographically.
|
// This is the point at infinity, which means that if we mask away
|
||||||
let greatest = copy[0] & (1 << 6) != 0;
|
// the first two bits, the entire representation should consist
|
||||||
|
// of zeroes.
|
||||||
|
copy[0] &= 0x3f;
|
||||||
|
|
||||||
// Unset the two most significant bits.
|
if copy.iter().all(|b| *b == 0) {
|
||||||
copy[0] &= 0x3f;
|
Ok(G1Affine::zero())
|
||||||
|
} else {
|
||||||
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 > negy;
|
|
||||||
|
|
||||||
Ok(G1Affine {
|
|
||||||
x: x,
|
|
||||||
y: if parity == greatest { y } else { negy },
|
|
||||||
infinity: false
|
|
||||||
})
|
|
||||||
},
|
|
||||||
None => {
|
|
||||||
// Point must not be on the curve.
|
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Determine if the intended y coordinate must be greater
|
||||||
|
// lexicographically.
|
||||||
|
let greatest = copy[0] & (1 << 5) != 0;
|
||||||
|
|
||||||
|
// Unset the three most significant bits.
|
||||||
|
copy[0] &= 0x1f;
|
||||||
|
|
||||||
|
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 > negy;
|
||||||
|
|
||||||
|
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, ()> {
|
fn from_affine(affine: G1Affine) -> Self {
|
||||||
use byteorder::{WriteBytesExt, BigEndian};
|
use byteorder::{WriteBytesExt, BigEndian};
|
||||||
|
|
||||||
if affine.is_zero() {
|
|
||||||
return Err(())
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut res = Self::empty();
|
let mut res = Self::empty();
|
||||||
|
|
||||||
{
|
if affine.is_zero() {
|
||||||
let mut writer = &mut res.0[..];
|
// Set the second-most significant bit to indicate this point
|
||||||
|
// is at infinity.
|
||||||
|
res.0[0] |= 1 << 6;
|
||||||
|
} else {
|
||||||
|
{
|
||||||
|
let mut writer = &mut res.0[..];
|
||||||
|
|
||||||
for digit in affine.x.into_repr().as_ref().iter().rev() {
|
for digit in affine.x.into_repr().as_ref().iter().rev() {
|
||||||
writer.write_u64::<BigEndian>(*digit).unwrap();
|
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;
|
let mut negy = affine.y;
|
||||||
negy.negate();
|
negy.negate();
|
||||||
|
|
||||||
// If the correct y coordinate is the largest (lexicographically),
|
// Set the third most significant bit if the correct y-coordinate
|
||||||
// the bit should be set.
|
// is lexicographically largest.
|
||||||
if affine.y > negy {
|
if affine.y > negy {
|
||||||
res.0[0] |= 1 << 6; // Set second highest bit.
|
res.0[0] |= 1 << 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(res)
|
// Set highest bit to distinguish this as a compressed element.
|
||||||
|
res.0[0] |= 1 << 7;
|
||||||
|
|
||||||
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1080,53 +1123,83 @@ pub mod g2 {
|
|||||||
fn into_affine_unchecked(&self) -> Result<G2Affine, ()> {
|
fn into_affine_unchecked(&self) -> Result<G2Affine, ()> {
|
||||||
use byteorder::{ReadBytesExt, BigEndian};
|
use byteorder::{ReadBytesExt, BigEndian};
|
||||||
|
|
||||||
let mut x_c1 = FqRepr([0; 6]);
|
// Create a copy of this representation.
|
||||||
let mut x_c0 = FqRepr([0; 6]);
|
let mut copy = self.0;
|
||||||
let mut y_c1 = FqRepr([0; 6]);
|
|
||||||
let mut y_c0 = FqRepr([0; 6]);
|
|
||||||
|
|
||||||
{
|
if copy[0] & (1 << 7) != 0 {
|
||||||
let mut reader = &self.0[..];
|
// Distinguisher bit is set, but this should be uncompressed!
|
||||||
|
|
||||||
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(())
|
return Err(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if copy[0] & (1 << 6) != 0 {
|
||||||
|
// This is the point at infinity, which means that if we mask away
|
||||||
|
// the first two bits, the entire representation should consist
|
||||||
|
// of zeroes.
|
||||||
|
copy[0] &= 0x3f;
|
||||||
|
|
||||||
|
if copy.iter().all(|b| *b == 0) {
|
||||||
|
Ok(G2Affine::zero())
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
} 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(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unset the three most significant bits.
|
||||||
|
copy[0] &= 0x1f;
|
||||||
|
|
||||||
|
let mut x_c0 = FqRepr([0; 6]);
|
||||||
|
let mut x_c1 = FqRepr([0; 6]);
|
||||||
|
let mut y_c0 = FqRepr([0; 6]);
|
||||||
|
let mut y_c1 = 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
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) -> Self {
|
||||||
|
use byteorder::{WriteBytesExt, BigEndian};
|
||||||
|
|
||||||
let mut res = Self::empty();
|
let mut res = Self::empty();
|
||||||
|
|
||||||
{
|
if affine.is_zero() {
|
||||||
|
// Set the second-most significant bit to indicate this point
|
||||||
|
// is at infinity.
|
||||||
|
res.0[0] |= 1 << 6;
|
||||||
|
} else {
|
||||||
let mut writer = &mut res.0[..];
|
let mut writer = &mut res.0[..];
|
||||||
|
|
||||||
for digit in affine.x.c1.into_repr().as_ref().iter().rev() {
|
for digit in affine.x.c1.into_repr().as_ref().iter().rev() {
|
||||||
@ -1146,7 +1219,7 @@ pub mod g2 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(res)
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1180,97 +1253,110 @@ pub mod g2 {
|
|||||||
return Err(())
|
return Err(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine if the intended y coordinate must be greater
|
if copy[0] & (1 << 6) != 0 {
|
||||||
// lexicographically.
|
// This is the point at infinity, which means that if we mask away
|
||||||
let greatest = copy[0] & (1 << 6) != 0;
|
// the first two bits, the entire representation should consist
|
||||||
|
// of zeroes.
|
||||||
|
copy[0] &= 0x3f;
|
||||||
|
|
||||||
// Unset the two most significant bits.
|
if copy.iter().all(|b| *b == 0) {
|
||||||
copy[0] &= 0x3f;
|
Ok(G2Affine::zero())
|
||||||
|
} else {
|
||||||
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(())
|
Err(())
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Determine if the intended y coordinate must be greater
|
||||||
|
// lexicographically.
|
||||||
|
let greatest = copy[0] & (1 << 5) != 0;
|
||||||
|
|
||||||
|
// Unset the three most significant bits.
|
||||||
|
copy[0] &= 0x1f;
|
||||||
|
|
||||||
|
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, ()> {
|
fn from_affine(affine: G2Affine) -> Self {
|
||||||
use byteorder::{WriteBytesExt, BigEndian};
|
use byteorder::{WriteBytesExt, BigEndian};
|
||||||
|
|
||||||
if affine.is_zero() {
|
|
||||||
return Err(())
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut res = Self::empty();
|
let mut res = Self::empty();
|
||||||
|
|
||||||
{
|
if affine.is_zero() {
|
||||||
let mut writer = &mut res.0[..];
|
// Set the second-most significant bit to indicate this point
|
||||||
|
// is at infinity.
|
||||||
|
res.0[0] |= 1 << 6;
|
||||||
|
} else {
|
||||||
|
{
|
||||||
|
let mut writer = &mut res.0[..];
|
||||||
|
|
||||||
for digit in affine.x.c1.into_repr().as_ref().iter().rev() {
|
for digit in affine.x.c1.into_repr().as_ref().iter().rev() {
|
||||||
writer.write_u64::<BigEndian>(*digit).unwrap();
|
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.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;
|
let mut negy = affine.y;
|
||||||
negy.negate();
|
negy.negate();
|
||||||
|
|
||||||
// If the correct y coordinate is the largest (lexicographically),
|
// Set the third most significant bit if the correct y-coordinate
|
||||||
// the bit should be set.
|
// is lexicographically largest.
|
||||||
if affine.y > negy {
|
if affine.y > negy {
|
||||||
res.0[0] |= 1 << 6; // Set second highest bit.
|
res.0[0] |= 1 << 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(res)
|
// Set highest bit to distinguish this as a compressed element.
|
||||||
|
res.0[0] |= 1 << 7;
|
||||||
|
|
||||||
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Binary file not shown.
BIN
src/bls12_381/tests/g1_compressed_valid_test_vectors.dat
Normal file
BIN
src/bls12_381/tests/g1_compressed_valid_test_vectors.dat
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -3,14 +3,14 @@ use ::*;
|
|||||||
|
|
||||||
fn test_vectors<G: CurveProjective, E: EncodedPoint<Affine=G::Affine>>(expected: &[u8])
|
fn test_vectors<G: CurveProjective, E: EncodedPoint<Affine=G::Affine>>(expected: &[u8])
|
||||||
{
|
{
|
||||||
let mut e = G::one();
|
let mut e = G::zero();
|
||||||
|
|
||||||
let mut v = vec![];
|
let mut v = vec![];
|
||||||
{
|
{
|
||||||
let mut expected = expected;
|
let mut expected = expected;
|
||||||
for _ in 0..1000 {
|
for _ in 0..1000 {
|
||||||
let e_affine = e.into_affine();
|
let e_affine = e.into_affine();
|
||||||
let encoded = E::from_affine(e_affine).unwrap();
|
let encoded = E::from_affine(e_affine);
|
||||||
v.extend_from_slice(encoded.as_ref());
|
v.extend_from_slice(encoded.as_ref());
|
||||||
|
|
||||||
let mut decoded = E::empty();
|
let mut decoded = E::empty();
|
||||||
@ -27,22 +27,22 @@ fn test_vectors<G: CurveProjective, E: EncodedPoint<Affine=G::Affine>>(expected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_g1_uncompressed_vectors() {
|
fn test_g1_uncompressed_valid_vectors() {
|
||||||
test_vectors::<G1, G1Uncompressed>(include_bytes!("g1_uncompressed_test_vectors.dat"));
|
test_vectors::<G1, G1Uncompressed>(include_bytes!("g1_uncompressed_valid_test_vectors.dat"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_g1_compressed_vectors() {
|
fn test_g1_compressed_valid_vectors() {
|
||||||
test_vectors::<G1, G1Compressed>(include_bytes!("g1_compressed_test_vectors.dat"));
|
test_vectors::<G1, G1Compressed>(include_bytes!("g1_compressed_valid_test_vectors.dat"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_g2_uncompressed_vectors() {
|
fn test_g2_uncompressed_valid_vectors() {
|
||||||
test_vectors::<G2, G2Uncompressed>(include_bytes!("g2_uncompressed_test_vectors.dat"));
|
test_vectors::<G2, G2Uncompressed>(include_bytes!("g2_uncompressed_valid_test_vectors.dat"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_g2_compressed_vectors() {
|
fn test_g2_compressed_valid_vectors() {
|
||||||
test_vectors::<G2, G2Compressed>(include_bytes!("g2_compressed_test_vectors.dat"));
|
test_vectors::<G2, G2Compressed>(include_bytes!("g2_compressed_valid_test_vectors.dat"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,13 +184,13 @@ pub trait CurveAffine: Copy +
|
|||||||
|
|
||||||
/// Converts this element into its compressed encoding, so long as it's not
|
/// Converts this element into its compressed encoding, so long as it's not
|
||||||
/// the point at infinity.
|
/// the point at infinity.
|
||||||
fn into_compressed(&self) -> Result<Self::Compressed, ()> {
|
fn into_compressed(&self) -> Self::Compressed {
|
||||||
<Self::Compressed as EncodedPoint>::from_affine(*self)
|
<Self::Compressed as EncodedPoint>::from_affine(*self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts this element into its uncompressed encoding, so long as it's not
|
/// Converts this element into its uncompressed encoding, so long as it's not
|
||||||
/// the point at infinity.
|
/// the point at infinity.
|
||||||
fn into_uncompressed(&self) -> Result<Self::Uncompressed, ()> {
|
fn into_uncompressed(&self) -> Self::Uncompressed {
|
||||||
<Self::Uncompressed as EncodedPoint>::from_affine(*self)
|
<Self::Uncompressed as EncodedPoint>::from_affine(*self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -230,7 +230,7 @@ pub trait EncodedPoint: Sized +
|
|||||||
|
|
||||||
/// Creates an `EncodedPoint` from an affine point, as long as the
|
/// Creates an `EncodedPoint` from an affine point, as long as the
|
||||||
/// point is not the point at infinity.
|
/// point is not the point at infinity.
|
||||||
fn from_affine(affine: Self::Affine) -> Result<Self, ()>;
|
fn from_affine(affine: Self::Affine) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This trait represents an element of a field.
|
/// This trait represents an element of a field.
|
||||||
|
@ -299,25 +299,32 @@ fn random_transformation_tests<G: CurveProjective>() {
|
|||||||
|
|
||||||
fn random_encoding_tests<G: CurveAffine>()
|
fn random_encoding_tests<G: CurveAffine>()
|
||||||
{
|
{
|
||||||
assert!(G::zero().into_compressed().is_err());
|
|
||||||
assert!(G::zero().into_uncompressed().is_err());
|
|
||||||
|
|
||||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
G::zero().into_uncompressed().into_affine().unwrap(),
|
||||||
|
G::zero()
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
G::zero().into_compressed().into_affine().unwrap(),
|
||||||
|
G::zero()
|
||||||
|
);
|
||||||
|
|
||||||
for _ in 0..1000 {
|
for _ in 0..1000 {
|
||||||
let mut r = G::Projective::rand(&mut rng).into_affine();
|
let mut r = G::Projective::rand(&mut rng).into_affine();
|
||||||
|
|
||||||
let uncompressed = r.into_uncompressed().unwrap();
|
let uncompressed = r.into_uncompressed();
|
||||||
let de_uncompressed = uncompressed.into_affine().unwrap();
|
let de_uncompressed = uncompressed.into_affine().unwrap();
|
||||||
assert_eq!(de_uncompressed, r);
|
assert_eq!(de_uncompressed, r);
|
||||||
|
|
||||||
let compressed = r.into_compressed().unwrap();
|
let compressed = r.into_compressed();
|
||||||
let de_compressed = compressed.into_affine().unwrap();
|
let de_compressed = compressed.into_affine().unwrap();
|
||||||
assert_eq!(de_compressed, r);
|
assert_eq!(de_compressed, r);
|
||||||
|
|
||||||
r.negate();
|
r.negate();
|
||||||
|
|
||||||
let compressed = r.into_compressed().unwrap();
|
let compressed = r.into_compressed();
|
||||||
let de_compressed = compressed.into_affine().unwrap();
|
let de_compressed = compressed.into_affine().unwrap();
|
||||||
assert_eq!(de_compressed, r);
|
assert_eq!(de_compressed, r);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user