use crate::types::GroupGT;
use super::ECCurve::fp12::{DENSE, FP12};
use super::ECCurve::fp4::FP4;
use super::ECCurve::pair::{another, ate, ate2, fexp, initmp, miller};
use crate::constants::GroupGT_SIZE;
use crate::errors::{SerzDeserzError, ValueError};
use crate::field_elem::FieldElement;
use crate::group_elem::GroupElement;
use crate::group_elem_g1::G1;
use crate::group_elem_g2::{parse_hex_as_FP2, G2};
use core::fmt;
use std::hash::{Hash, Hasher};
use std::ops::Mul;
use serde::de::{Deserialize, Deserializer, Error as DError, Visitor};
use serde::ser::{Error as SError, Serialize, Serializer};
use std::str::{FromStr, SplitWhitespace};
use zeroize::Zeroize;
#[derive(Clone)]
pub struct GT {
value: GroupGT,
}
impl fmt::Debug for GT {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let c = self.value.clone();
write!(f, "{}", c.tostring())
}
}
impl GT {
pub fn new() -> Self {
Self {
value: GroupGT::new(),
}
}
pub fn ate_pairing(g1: &G1, g2: &G2) -> Self {
if g1.is_identity() || g2.is_identity() {
return Self::one();
}
let e = ate(&g2.to_ecp(), &g1.to_ecp());
Self { value: fexp(&e) }
}
pub fn ate_2_pairing(g1: &G1, g2: &G2, h1: &G1, h2: &G2) -> Self {
if g1.is_identity() || g2.is_identity() {
return Self::ate_pairing(h1, h2);
}
if h1.is_identity() || h2.is_identity() {
return Self::ate_pairing(g1, g2);
}
let e = ate2(&g2.to_ecp(), &g1.to_ecp(), &h2.to_ecp(), &h1.to_ecp());
Self { value: fexp(&e) }
}
pub fn ate_multi_pairing(elems: Vec<(&G1, &G2)>) -> Self {
let mut accum = initmp();
for (g1, g2) in elems {
if g1.is_identity() || g2.is_identity() {
continue;
}
another(&mut accum, &g2.to_ecp(), &g1.to_ecp());
}
let e = miller(&mut accum);
Self { value: fexp(&e) }
}
pub fn inner_product(left: &[G1], right: &[G2]) -> Result<Self, ValueError> {
check_vector_size_for_equality!(left, right)?;
let mut accum = initmp();
for (g1, g2) in left.iter().zip(right) {
if g1.is_identity() || g2.is_identity() {
continue;
}
another(&mut accum, &g2.to_ecp(), &g1.to_ecp());
}
let e = miller(&mut accum);
Ok(Self { value: fexp(&e) })
}
pub fn product(a: &Self, b: &Self) -> Self {
let mut m = FP12::new_copy(&a.value);
m.mul(&b.value);
Self { value: m }
}
pub fn pow(&self, e: &FieldElement) -> Self {
Self {
value: self.value.pow(&e.to_bignum()),
}
}
pub fn inverse(&self) -> Self {
let mut inv = self.value.clone();
inv.inverse();
Self { value: inv }
}
pub fn inverse_mut(&mut self) {
self.value.inverse()
}
pub fn is_one(&self) -> bool {
return self.value.isunity();
}
pub fn one() -> Self {
let zero = FP4::new_int(0);
let one = FP4::new_int(1);
Self {
value: FP12::new_fp4s(&one, &zero, &zero),
}
}
pub fn to_fp12(&self) -> FP12 {
self.value.clone()
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut temp = FP12::new();
temp.copy(&self.value);
let mut bytes: [u8; GroupGT_SIZE] = [0; GroupGT_SIZE];
temp.tobytes(&mut bytes);
bytes.to_vec()
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, SerzDeserzError> {
if bytes.len() != GroupGT_SIZE {
return Err(SerzDeserzError::GTBytesIncorrectSize(
bytes.len(),
GroupGT_SIZE,
));
}
Ok(Self {
value: FP12::frombytes(bytes),
})
}
pub fn write_to_slice(&self, target: &mut [u8]) -> Result<(), SerzDeserzError> {
if target.len() != GroupGT_SIZE {
return Err(SerzDeserzError::GTBytesIncorrectSize(
target.len(),
GroupGT_SIZE,
));
}
let mut temp = FP12::new();
temp.copy(&self.value);
temp.tobytes(target);
Ok(())
}
pub fn write_to_slice_unchecked(&self, target: &mut [u8]) {
let mut temp = FP12::new();
temp.copy(&self.value);
temp.tobytes(target);
}
pub fn to_hex(&self) -> String {
self.value.tostring()
}
pub fn from_hex(mut string: String) -> Result<Self, SerzDeserzError> {
unbound_bounded_string!(string, '[', ']', SerzDeserzError::CannotParseGT);
let (a, b, c) = split_string_to_3_tuple!(string, SerzDeserzError::CannotParseGT);
let a_fp4 = parse_hex_as_FP4(a)?;
let b_fp4 = parse_hex_as_FP4(b)?;
let c_fp4 = parse_hex_as_FP4(c)?;
Ok(Self {
value: FP12::new_fp4s(&a_fp4, &b_fp4, &c_fp4),
})
}
#[cfg(test)]
pub fn random() -> Self {
let g1 = G1::random();
let g2 = G2::random();
GT::ate_pairing(&g1, &g2)
}
}
pub fn parse_hex_as_FP4(mut string: String) -> Result<FP4, SerzDeserzError> {
unbound_bounded_string!(string, '[', ']', SerzDeserzError::CannotParseFP4);
let (a, b) = split_string_to_2_tuple!(string, SerzDeserzError::CannotParseFP4);
let a_fp2 = parse_hex_as_FP2(a)?;
let b_fp2 = parse_hex_as_FP2(b)?;
Ok(FP4::new_fp2s(&a_fp2, &b_fp2))
}
impl PartialEq for GT {
fn eq(&self, other: >) -> bool {
self.value.equals(&other.value)
}
}
impl From<GroupGT> for GT {
fn from(x: GroupGT) -> Self {
Self { value: x }
}
}
impl From<&GroupGT> for GT {
fn from(x: &GroupGT) -> Self {
Self { value: x.clone() }
}
}
impl From<&[u8; GroupGT_SIZE]> for GT {
fn from(x: &[u8; GroupGT_SIZE]) -> Self {
Self {
value: GroupGT::frombytes(x),
}
}
}
impl Serialize for GT {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_newtype_struct("GT", &self.to_hex())
}
}
impl<'a> Deserialize<'a> for GT {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'a>,
{
struct GroupElemVisitor;
impl<'a> Visitor<'a> for GroupElemVisitor {
type Value = GT;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("GT")
}
fn visit_str<E>(self, value: &str) -> Result<GT, E>
where
E: DError,
{
Ok(GT::from_hex(value.to_string()).map_err(DError::custom)?)
}
}
deserializer.deserialize_str(GroupElemVisitor)
}
}
impl_group_elem_traits!(GT, GroupGT);
impl Mul<GT> for GT {
type Output = Self;
fn mul(self, other: GT) -> Self {
GT::product(&self, &other)
}
}
impl Mul<>> for GT {
type Output = Self;
fn mul(self, other: >) -> Self {
GT::product(&self, other)
}
}
impl Mul<GT> for > {
type Output = GT;
fn mul(self, other: GT) -> GT {
GT::product(&self, &other)
}
}
impl Mul<>> for > {
type Output = GT;
fn mul(self, other: >) -> GT {
GT::product(self, other)
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::group_elem_g1::G1Vector;
use std::time::{Duration, Instant};
#[test]
fn test_unity() {
let one = GT::one();
assert!(one.is_one());
}
#[test]
fn test_inverse() {
let minus_one = FieldElement::minus_one();
for _ in 0..10 {
let g1 = G1::random();
let g2 = G2::random();
let e = GT::ate_pairing(&g1, &g2);
let e_inv = e.inverse();
assert!(GT::product(&e, &e_inv).is_one());
assert_eq!(GT::pow(&e, &minus_one), e_inv);
assert_eq!(GT::pow(&e_inv, &minus_one), e);
}
}
#[test]
fn test_ate_pairing_identity() {
let g1 = G1::random();
let g2 = G2::random();
let g1_identity = G1::identity();
let g2_identity = G2::identity();
let lhs = GT::ate_pairing(&(&g1 + &g1_identity), &g2);
let rhs = GT::product(
>::ate_pairing(&g1, &g2),
>::ate_pairing(&g1_identity, &g2),
);
assert!(lhs == rhs);
let lhs = GT::ate_pairing(&g1, &(&g2 + &g2_identity));
let rhs = GT::product(
>::ate_pairing(&g1, &g2),
>::ate_pairing(&g1, &g2_identity),
);
assert!(lhs == rhs);
let h1 = G1::random();
let h2 = G2::random();
let lhs = GT::product(
>::ate_pairing(&g1, &g2),
>::ate_pairing(&g1_identity, &h2),
);
let rhs = GT::ate_pairing(&g1, &g2);
assert!(lhs == rhs);
let lhs = GT::product(
>::ate_pairing(&g1_identity, &g2),
>::ate_pairing(&h1, &h2),
);
let rhs = GT::ate_pairing(&h1, &h2);
assert!(lhs == rhs);
assert!(GT::ate_pairing(&g1_identity, &g2_identity).is_one());
assert!(GT::ate_2_pairing(&g1, &g2, &g1_identity, &h2) == GT::ate_pairing(&g1, &g2));
assert!(GT::ate_2_pairing(&g1, &g2, &h1, &g2_identity) == GT::ate_pairing(&g1, &g2));
assert!(GT::ate_2_pairing(&g1_identity, &g2, &h1, &h2) == GT::ate_pairing(&h1, &h2));
assert!(GT::ate_2_pairing(&g1, &g2_identity, &h1, &h2) == GT::ate_pairing(&h1, &h2));
assert!(GT::ate_2_pairing(&g1_identity, &g2_identity, &g1_identity, &g2_identity).is_one());
let k1 = G1::random();
let k2 = G2::random();
assert!(
GT::ate_multi_pairing(vec![(&g1, &g2), (&h1, &h2), (&g1_identity, &k2)])
== GT::ate_multi_pairing(vec![(&g1, &g2), (&h1, &h2)]),
);
assert!(
GT::ate_multi_pairing(vec![(&g1, &g2), (&h1, &h2), (&k1, &g2_identity)])
== GT::ate_multi_pairing(vec![(&g1, &g2), (&h1, &h2)]),
);
assert!(
GT::ate_multi_pairing(vec![(&g1, &g2), (&g1_identity, &h2), (&k1, &k2)])
== GT::ate_multi_pairing(vec![(&g1, &g2), (&k1, &k2)]),
);
assert!(
GT::ate_multi_pairing(vec![(&g1, &g2), (&g1_identity, &h2), (&k1, &k2)])
== GT::ate_multi_pairing(vec![(&g1, &g2), (&k1, &k2)]),
);
assert!(GT::ate_multi_pairing(vec![
(&g1_identity, &g2_identity),
(&g1_identity, &g2_identity),
(&g1_identity, &g2_identity)
])
.is_one());
}
#[test]
fn test_ate_pairing_negative() {
let g1 = G1::random();
let g2 = G2::random();
let g1_neg = -&g1;
let g2_neg = -&g2;
let lhs = GT::ate_pairing(&g1, &g2_neg);
let rhs = GT::ate_pairing(&g1_neg, &g2);
assert!(lhs == rhs);
let e = GT::ate_pairing(&g1, &g2);
let e_inv = e.inverse();
assert!(lhs == e_inv);
let p = GT::ate_pairing(&g1, &g2);
assert!(GT::product(&p, &lhs) == GT::one());
assert!(GT::product(&p, &rhs) == GT::one());
}
#[test]
fn test_ate_pairing_product() {
let g1 = G1::random();
let g2 = G2::random();
let h1 = G1::random();
let h2 = G2::random();
let r1 = GT::ate_pairing(&g1, &g2);
let r2 = GT::ate_pairing(&h1, &h2);
let r3 = GT::product(&r1, &r2);
let r4 = r1 * r2;
assert_eq!(r3, r4);
}
#[test]
fn test_ate_pairing() {
let g1 = G1::random();
let h1 = G1::random();
let g2 = G2::random();
let h2 = G2::random();
let lhs = GT::ate_pairing(&(&g1 + &h1), &g2);
let rhs = GT::product(>::ate_pairing(&g1, &g2), >::ate_pairing(&h1, &g2));
let rhs_1 = GT::ate_2_pairing(&g1, &g2, &h1, &g2);
let rhs_2 = GT::ate_multi_pairing(vec![(&g1, &g2), (&h1, &g2)]);
let rhs_3 = GT::inner_product(
vec![g1.clone(), h1.clone()].as_slice(),
vec![g2.clone(), g2.clone()].as_slice(),
)
.unwrap();
assert_eq!(lhs, rhs);
assert_eq!(rhs_1, rhs);
assert_eq!(rhs_2, rhs);
assert_eq!(rhs_3, rhs);
let lhs = GT::ate_pairing(&g1, &(&g2 + &h2));
let rhs = GT::product(>::ate_pairing(&g1, &g2), >::ate_pairing(&g1, &h2));
let rhs_1 = GT::ate_2_pairing(&g1, &g2, &g1, &h2);
let rhs_2 = GT::ate_multi_pairing(vec![(&g1, &g2), (&g1, &h2)]);
let rhs_3 = GT::inner_product(
vec![g1.clone(), g1.clone()].as_slice(),
vec![g2.clone(), h2.clone()].as_slice(),
)
.unwrap();
assert_eq!(lhs, rhs);
assert_eq!(rhs_1, rhs);
assert_eq!(rhs_2, rhs);
assert_eq!(rhs_3, rhs);
let r = FieldElement::random();
let p1 = GT::ate_pairing(&g1, &(&g2 * &r));
let p2 = GT::ate_pairing(&(&g1 * &r), &g2);
let mut p = GT::ate_pairing(&g1, &g2);
p = p.pow(&r);
assert_eq!(p1, p2);
assert_eq!(p1, p);
}
#[test]
fn test_to_and_from_bytes() {
let count = 100;
for _ in 0..count {
let x = GT::random();
let mut bytes: [u8; GroupGT_SIZE] = [0; GroupGT_SIZE];
x.write_to_slice(&mut bytes).unwrap();
let y = GT::from(&bytes);
assert_eq!(x, y);
let bytes1 = x.to_bytes();
assert_eq!(x, GT::from_bytes(bytes1.as_slice()).unwrap());
let mut bytes2 = bytes1.clone();
bytes2.push(0);
assert!(GT::from_bytes(&bytes2).is_err());
assert!(x.write_to_slice(&mut bytes2).is_err());
assert!(GT::from_bytes(&bytes2[0..GroupGT_SIZE - 4]).is_err());
assert!(x.write_to_slice(&mut bytes2[0..GroupGT_SIZE - 4]).is_err());
}
}
#[test]
fn timing_ate_multi_pairing() {
let count = 10;
let g1_vec = (0..count).map(|_| G1::random()).collect::<Vec<G1>>();
let g2_vec = (0..count).map(|_| G2::random()).collect::<Vec<G2>>();
let mut tuple_vec = vec![];
let start = Instant::now();
let mut accum = GT::ate_pairing(&g1_vec[0], &g2_vec[0]);
tuple_vec.push((&g1_vec[0], &g2_vec[0]));
for i in 1..count {
let e = GT::ate_pairing(&g1_vec[i], &g2_vec[i]);
accum = GT::product(&accum, &e);
tuple_vec.push((&g1_vec[i], &g2_vec[i]));
}
println!(
"Time to compute {} pairings naively is {:?}",
count,
start.elapsed()
);
let start = Instant::now();
let multi = GT::ate_multi_pairing(tuple_vec);
println!(
"Time to compute {} pairings using multi-pairings is {:?}",
count,
start.elapsed()
);
assert!(accum == multi);
let ip = GT::inner_product(&g1_vec, &g2_vec).unwrap();
assert!(accum == ip);
}
#[test]
fn timing_pairing_pow() {
let count = 10;
let g1_vec = (0..count).map(|_| G1::random()).collect::<Vec<G1>>();
let g2_vec = (0..count).map(|_| G2::random()).collect::<Vec<G2>>();
let r_vec = (0..count)
.map(|_| FieldElement::random())
.collect::<Vec<FieldElement>>();
let mut pairing_exp = vec![];
let mut g1_exp = vec![];
let mut g2_exp = vec![];
let start = Instant::now();
for i in 0..count {
pairing_exp.push(GT::pow(>::ate_pairing(&g1_vec[i], &g2_vec[i]), &r_vec[i]));
}
println!(
"Time to compute {} pairing and then exponentiation is {:?}",
count,
start.elapsed()
);
let start = Instant::now();
for i in 0..count {
g1_exp.push(GT::ate_pairing(&(&g1_vec[i] * &r_vec[i]), &g2_vec[i]));
}
println!(
"Time to compute {} pairing after exponentiation in G1 is {:?}",
count,
start.elapsed()
);
let start = Instant::now();
for i in 0..count {
g2_exp.push(GT::ate_pairing(&g1_vec[i], &(&g2_vec[i] * &r_vec[i])));
}
println!(
"Time to compute {} pairing after exponentiation in G2 is {:?}",
count,
start.elapsed()
);
for i in 0..count {
assert_eq!(pairing_exp[i], g1_exp[i]);
assert_eq!(pairing_exp[i], g2_exp[i]);
}
}
}