use bn::{
arith::{U256, U512},
*,
};
use byteorder::ByteOrder;
use crate::error::{Error, Result};
pub(crate) fn mod_u256(num: U256, modulus: U256) -> U256 {
let mut reduced = num;
while reduced > modulus {
reduced.add(&U256::zero(), &modulus);
}
reduced
}
pub(crate) fn to_u512(coord: Fq2) -> U512 {
let c0: U256 = (coord.real()).into_u256();
let c1: U256 = (coord.imaginary()).into_u256();
U512::new(&c1, &c0, &Fq::modulus())
}
pub(crate) fn arbitrary_string_to_g1(data: &[u8; 32]) -> Result<G1> {
let mut v = vec![0x02];
v.extend(data);
let point = G1::from_compressed(&v)?;
Ok(point)
}
pub(crate) fn fr_to_bytes(fr: bn::Fr) -> Result<Vec<u8>> {
let mut result: [u8; 32] = [0; 32];
fr.into_u256().to_big_endian(&mut result)?;
Ok(result.to_vec())
}
pub(crate) fn g1_to_compressed(point: G1) -> Result<Vec<u8>> {
let affine_coords = AffineG1::from_jacobian(point).ok_or(Error::PointInJacobian)?;
let x = Fq::into_u256(affine_coords.x());
let y = Fq::into_u256(affine_coords.y());
let parity = y.get_bit(0).ok_or(Error::IndexOutOfBounds)?;
let mut s = [0u8; 32];
x.to_big_endian(&mut s)?;
let mut result: Vec<u8> = Vec::new();
result.push(if parity { 3 } else { 2 });
result.append(&mut s.to_vec());
Ok(result)
}
pub(crate) fn from_uncompressed_to_g2(bytes: &[u8]) -> Result<G2> {
if bytes.len() != 128 {
return Err(Error::InvalidLength {});
}
let x = Fq2::new(Fq::from_slice(&bytes[0..32])?, Fq::from_slice(&bytes[32..64])?);
let y = Fq2::new(Fq::from_slice(&bytes[64..96])?, Fq::from_slice(&bytes[96..128])?);
let g2_point = AffineG2::new(x, y)?;
Ok(g2_point.into())
}
pub(crate) fn g2_to_compressed(g2: G2) -> Result<Vec<u8>> {
let modulus = Fq::modulus();
let affine_coords = AffineG2::from_jacobian(g2).ok_or(Error::PointInJacobian)?;
let x_real = Fq::into_u256(affine_coords.x().real());
let x_imaginary = Fq::into_u256(affine_coords.x().imaginary());
let y = affine_coords.y();
let y_neg = -y;
let sign: u8 = if to_u512(y) > to_u512(y_neg) { 0x0b } else { 0x0a };
let compressed = U512::new(&x_imaginary, &x_real, &modulus);
let mut buf: [u8; 64] = [0; (4 * 16)];
for (l, i) in (0..4).rev().zip((0..4).map(|i| i * 16)) {
byteorder::BigEndian::write_u128(&mut buf[i..], compressed.0[l]);
}
let mut result: Vec<u8> = Vec::new();
result.push(sign);
result.append(&mut buf.to_vec());
Ok(result)
}
pub(crate) fn g2_to_uncompressed(g2: G2) -> Result<Vec<u8>> {
let affine_coords = AffineG2::from_jacobian(g2).ok_or(Error::PointInJacobian)?;
let mut result: [u8; 32 * 4] = [0; (4 * 32)];
Fq::into_u256(affine_coords.x().real()).to_big_endian(&mut result[0..32])?;
Fq::into_u256(affine_coords.x().imaginary()).to_big_endian(&mut result[32..64])?;
Fq::into_u256(affine_coords.y().real()).to_big_endian(&mut result[64..96])?;
Fq::into_u256(affine_coords.y().imaginary()).to_big_endian(&mut result[96..128])?;
Ok(result.to_vec())
}