Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compression/Decompression of G2 Points for BLS12_381 #909

Merged
merged 16 commits into from
Sep 9, 2024
Merged
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
use super::{field_extension::BLS12381PrimeField, twist::BLS12381TwistCurve};
use crate::{
elliptic_curve::{
short_weierstrass::{
curves::bls12_381::{
curve::BLS12381Curve, field_extension::Degree2ExtensionField, sqrt,
},
point::ShortWeierstrassProjectivePoint,
traits::Compress,
},
traits::IsEllipticCurve,
elliptic_curve::short_weierstrass::{
curves::bls12_381::{curve::BLS12381Curve, field_extension::Degree2ExtensionField, sqrt},
point::ShortWeierstrassProjectivePoint,
traits::Compress,
},
field::element::FieldElement,
};
Expand All @@ -20,12 +15,13 @@ use crate::{
};

type G1Point = ShortWeierstrassProjectivePoint<BLS12381Curve>;
type G2Point = ShortWeierstrassProjectivePoint<BLS12381TwistCurve>;
type BLS12381FieldElement = FieldElement<BLS12381PrimeField>;

impl Compress for BLS12381Curve {
type G1Point = G1Point;

type G2Point = <BLS12381TwistCurve as IsEllipticCurve>::PointRepresentation;
type G2Point = G2Point;

type Error = ByteConversionError;

Expand Down Expand Up @@ -106,7 +102,48 @@ impl Compress for BLS12381Curve {
.ok_or(ByteConversionError::PointNotInSubgroup)
}

#[allow(unused)]
#[cfg(feature = "alloc")]
fn compress_g2_point(point: &Self::G2Point) -> alloc::vec::Vec<u8> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need a Vec here or is it constant size?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Traits get in the way, but we can try to solve this if we expose more things

if *point == G2Point::neutral_element() {
// point is at infinity
let mut x_bytes = alloc::vec![0_u8; 96];
x_bytes[0] |= 1 << 7;
x_bytes[0] |= 1 << 6;
Comment on lines +115 to +116
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
x_bytes[0] |= 1 << 7;
x_bytes[0] |= 1 << 6;
x_bytes[0] |= 0b11 << 6;

x_bytes
} else {
// point is not at infinity
let point_affine = point.to_affine();
let x = point_affine.x();
let y = point_affine.y();

let x_rev: FieldElement<Degree2ExtensionField> =
FieldElement::new([x.value()[1].clone(), x.value()[0].clone()]);

let mut x_bytes = x_rev.to_bytes_be();

// Set first bit to to 1 indicate this is compressed element.
x_bytes[0] |= 1 << 7;

// Set the 3rd bit based on y value.
let y_neg = -y;

match (
y.value()[0]
.representative()
.cmp(&y_neg.value()[0].representative()),
y.value()[1]
.representative()
.cmp(&y_neg.value()[1].representative()),
) {
(Ordering::Greater, _) | (Ordering::Equal, Ordering::Greater) => {
x_bytes[0] |= 1 << 5;
}
(_, _) => (),
}
x_bytes
}
}

fn decompress_g2_point(input_bytes: &mut [u8; 96]) -> Result<Self::G2Point, Self::Error> {
let first_byte = input_bytes.first().unwrap();

Expand All @@ -124,6 +161,8 @@ impl Compress for BLS12381Curve {
return Ok(Self::G2Point::neutral_element());
}

let third_bit = prefix_bits & 1_u8;

let first_byte_without_control_bits = (first_byte << 3) >> 3;
input_bytes[0] = first_byte_without_control_bits;

Expand All @@ -136,7 +175,7 @@ impl Compress for BLS12381Curve {
const VALUE: BLS12381FieldElement = BLS12381FieldElement::from_hex_unchecked("4");
let b_param_qfe = FieldElement::<Degree2ExtensionField>::new([VALUE, VALUE]);

let y = sqrt::sqrt_qfe(&(x.pow(3_u64) + b_param_qfe), 0)
let y = sqrt::sqrt_qfe(&(x.pow(3_u64) + b_param_qfe), third_bit)
.ok_or(ByteConversionError::InvalidValue)?;

Self::G2Point::from_affine(x, y).map_err(|_| ByteConversionError::InvalidValue)
Expand Down Expand Up @@ -226,4 +265,102 @@ mod tests {

assert_eq!(g_2, decompressed_g2);
}

#[cfg(feature = "alloc")]
#[test]
fn test_compress_decompress_generator_g2() {
use crate::elliptic_curve::short_weierstrass::{
curves::bls12_381::twist::BLS12381TwistCurve, traits::Compress,
};

let g = BLS12381TwistCurve::generator();
let compressed_g = BLS12381Curve::compress_g2_point(&g);
let mut compressed_g_slice: [u8; 96] = compressed_g.try_into().unwrap();

let decompressed_g = BLS12381Curve::decompress_g2_point(&mut compressed_g_slice).unwrap();

assert_eq!(g, decompressed_g);
}

#[cfg(feature = "alloc")]
#[test]
fn test_compress_decompress_generator_g2_neg() {
use crate::elliptic_curve::short_weierstrass::{
curves::bls12_381::twist::BLS12381TwistCurve, traits::Compress,
};

let g = BLS12381TwistCurve::generator();
let g_neg = g.neg();

let compressed_g_neg = BLS12381Curve::compress_g2_point(&g_neg);
let mut compressed_g_neg_slice: [u8; 96] = compressed_g_neg.try_into().unwrap();

let decompressed_g_neg =
BLS12381Curve::decompress_g2_point(&mut compressed_g_neg_slice).unwrap();

assert_eq!(g_neg, decompressed_g_neg);
}

#[cfg(feature = "alloc")]
#[test]
fn test_decompress_g2() {
use crate::{
elliptic_curve::short_weierstrass::curves::bls12_381::{
field_extension::Degree2ExtensionField, twist::BLS12381TwistCurve,
},
field::element::FieldElement,
};

let mut compressed_point = [0_u8; 96];
compressed_point[0] |= 1 << 7;
compressed_point[95] |= 1 << 1;

// Valig G2 point coordinates:
let x_0 = BLS12381FieldElement::from_hex_unchecked("02");
let x_1 = BLS12381FieldElement::from_hex_unchecked("0");
let y_0 = BLS12381FieldElement::from_hex_unchecked("013a59858b6809fca4d9a3b6539246a70051a3c88899964a42bc9a69cf9acdd9dd387cfa9086b894185b9a46a402be73");
let y_1 = BLS12381FieldElement::from_hex_unchecked("02d27e0ec3356299a346a09ad7dc4ef68a483c3aed53f9139d2f929a3eecebf72082e5e58c6da24ee32e03040c406d4f");

let x: FieldElement<Degree2ExtensionField> = FieldElement::new([x_0, x_1]);
let y: FieldElement<Degree2ExtensionField> = FieldElement::new([y_0, y_1]);

let valid_g2_point = BLS12381TwistCurve::create_point_from_affine(x, y).unwrap();

let decompressed_point = BLS12381Curve::decompress_g2_point(&mut compressed_point).unwrap();

assert_eq!(valid_g2_point, decompressed_point);
}

#[cfg(feature = "alloc")]
#[test]
fn test_compress_g2() {
use crate::{
elliptic_curve::short_weierstrass::{
curves::bls12_381::{
field_extension::Degree2ExtensionField, twist::BLS12381TwistCurve,
},
traits::Compress,
},
field::element::FieldElement,
};

// Valig G2 point coordinates:
let x_0 = BLS12381FieldElement::from_hex_unchecked("02");
let x_1 = BLS12381FieldElement::from_hex_unchecked("0");
let y_0 = BLS12381FieldElement::from_hex_unchecked("013a59858b6809fca4d9a3b6539246a70051a3c88899964a42bc9a69cf9acdd9dd387cfa9086b894185b9a46a402be73");
let y_1 = BLS12381FieldElement::from_hex_unchecked("02d27e0ec3356299a346a09ad7dc4ef68a483c3aed53f9139d2f929a3eecebf72082e5e58c6da24ee32e03040c406d4f");

let x: FieldElement<Degree2ExtensionField> = FieldElement::new([x_0, x_1]);
let y: FieldElement<Degree2ExtensionField> = FieldElement::new([y_0, y_1]);

let point = BLS12381TwistCurve::create_point_from_affine(x, y).unwrap();

let compress_point = BLS12381Curve::compress_g2_point(&point);

let mut valid_compressed_point = [0_u8; 96];
valid_compressed_point[0] |= 1 << 7;
valid_compressed_point[95] |= 1 << 1;

assert_eq!(compress_point, valid_compressed_point);
}
}
3 changes: 3 additions & 0 deletions math/src/elliptic_curve/short_weierstrass/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ pub trait Compress {
#[cfg(feature = "alloc")]
fn compress_g1_point(point: &Self::G1Point) -> alloc::vec::Vec<u8>;

#[cfg(feature = "alloc")]
fn compress_g2_point(point: &Self::G2Point) -> alloc::vec::Vec<u8>;

fn decompress_g1_point(input_bytes: &mut [u8; 48]) -> Result<Self::G1Point, Self::Error>;

fn decompress_g2_point(input_bytes: &mut [u8; 96]) -> Result<Self::G2Point, Self::Error>;
Expand Down
Loading