use crate::amcl::hmac;
use crate::constants::{
CurveOrder, GroupG1_SIZE, CURVETYPE, G1_COMP_BYTE_SIZE, HASH_TYPE, MONTGOMERY,
};
use crate::errors::{SerzDeserzError, ValueError};
use crate::field_elem::{FieldElement, FieldElementVector};
use crate::group_elem::{GroupElement, GroupElementVector};
use crate::types::{BigNum, GroupG1, FP};
use crate::utils::{hash_msg, hash_to_field};
use std::ops::{Add, AddAssign, Index, IndexMut, Mul, Neg, Sub, SubAssign};
use core::fmt;
use std::hash::{Hash, Hasher};
use std::slice::Iter;
use crate::rayon::iter::IntoParallelRefMutIterator;
use rayon::prelude::*;
use serde::de::{Deserialize, Deserializer, Error as DError, Visitor};
use serde::ser::{Error as SError, Serialize, Serializer};
use zeroize::Zeroize;
#[derive(Clone)]
pub struct G1 {
value: GroupG1,
}
impl fmt::Debug for G1 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "ECP: [ {} ]", self.value.tostring())
}
}
impl GroupElement for G1 {
fn new() -> Self {
Self {
value: GroupG1::new(),
}
}
fn identity() -> Self {
let mut v = GroupG1::new();
v.inf();
Self { value: v }
}
fn generator() -> Self {
GroupG1::generator().into()
}
fn is_identity(&self) -> bool {
self.value.is_infinity()
}
fn set_to_identity(&mut self) {
self.value.inf()
}
fn from_msg_hash(msg: &[u8]) -> Self {
GroupG1::mapit(&hash_msg(msg)).into()
}
impl_group_elem_byte_conversion_methods!(
GroupG1,
GroupG1_SIZE,
G1_COMP_BYTE_SIZE,
SerzDeserzError::G1BytesIncorrectSize
);
fn add_assign_(&mut self, b: &Self) {
self.value.add(&b.value);
}
fn sub_assign_(&mut self, b: &Self) {
self.value.sub(&b.value);
}
fn plus(&self, b: &Self) -> Self {
let mut sum = self.value.clone();
sum.add(&b.value);
sum.into()
}
fn minus(&self, b: &Self) -> Self {
let mut diff = self.value.clone();
diff.sub(&b.value);
diff.into()
}
fn scalar_mul_const_time(&self, a: &FieldElement) -> Self {
self.value.mul(&a.to_bignum()).into()
}
fn double(&self) -> Self {
let mut d = self.value.clone();
d.dbl();
d.into()
}
fn double_mut(&mut self) {
self.value.dbl();
}
fn to_hex(&self) -> String {
self.value.tostring()
}
fn from_hex(mut string: String) -> Result<Self, SerzDeserzError> {
if &string == "infinity" {
return Ok(Self::new());
}
unbound_bounded_string!(string, '(', ')', SerzDeserzError::CannotParseG1);
if CURVETYPE == MONTGOMERY {
let x_big = FieldElement::parse_hex_as_bignum(string)?;
Ok(Self {
value: GroupG1::new_big(&x_big),
})
} else {
let (x, y) = split_string_to_2_tuple!(string, SerzDeserzError::CannotParseG1);
let x_big = FieldElement::parse_hex_as_bignum(x)?;
let y_big = FieldElement::parse_hex_as_bignum(y)?;
Ok(Self {
value: GroupG1::new_bigs(&x_big, &y_big),
})
}
}
fn negation(&self) -> Self {
let mut n = self.to_ecp();
n.neg();
n.into()
}
fn is_extension() -> bool {
return false;
}
fn has_correct_order(&self) -> bool {
return self.value.mul(&CurveOrder).is_infinity();
}
}
impl G1 {
pub fn binary_scalar_mul(&self, h: &Self, a: &FieldElement, b: &FieldElement) -> Self {
self.value
.mul2(&a.to_bignum(), &h.to_ecp(), &b.to_bignum())
.into()
}
pub fn hash_to_curve(domain_separation_tag: &[u8], msg: &[u8]) -> G1 {
let mut u: [FP; 2] = [FP::new(), FP::new()];
hash_to_field(
hmac::MC_SHA2,
HASH_TYPE,
domain_separation_tag,
msg,
&mut u,
2,
);
let mut P = GroupG1::map2point(&u[0]);
let P1 = GroupG1::map2point(&u[1]);
P.add(&P1);
P.cfp();
Self { value: P }
}
}
impl_group_elem_traits!(G1, GroupG1);
impl_group_elem_serz!(G1, GroupG1, "G1");
impl_group_elem_conversions!(G1, GroupG1, GroupG1_SIZE, G1_COMP_BYTE_SIZE);
impl_group_elem_ops!(G1);
impl_scalar_mul_ops!(G1);
impl_group_element_lookup_table!(G1, G1LookupTable);
impl_optmz_scalar_mul_ops!(G1, GroupG1, G1LookupTable);
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct G1Vector {
elems: Vec<G1>,
}
impl_group_elem_vec_ops!(G1, G1Vector);
impl_group_elem_vec_product_ops!(G1, G1Vector, G1LookupTable);
impl_group_elem_vec_conversions!(G1, G1Vector);
#[cfg(test)]
mod test {
use super::*;
use std::borrow::Borrow;
use std::collections::{HashMap, HashSet};
use std::time::{Duration, Instant};
#[test]
fn test_parse_hex_for_FP() {
}
#[test]
fn test_parse_bad_hex_for_FP() {
}
#[test]
fn test_binary_scalar_mul() {
for _ in 0..10 {
let a = FieldElement::random();
let b = FieldElement::random();
let g = G1::random();
let h = G1::random();
assert_eq!(&g * &a + &h * &b, g.binary_scalar_mul(&h, &a, &b))
}
}
#[test]
fn test_multiples() {
for _ in 0..10 {
let a = G1::random();
let mults = a.get_multiples(17);
for i in 1..=17 {
assert_eq!(mults[i - 1], (&a * FieldElement::from(i as u8)));
}
}
}
#[test]
fn timing_multi_scalar_multiplication() {
let mut fs = vec![];
let mut gs = vec![];
let n = 64;
for _ in 0..n {
fs.push(FieldElement::random());
gs.push(G1::random());
}
let gv = G1Vector::from(gs.as_slice());
let fv = FieldElementVector::from(fs.as_slice());
let mut start = Instant::now();
let res = gv.multi_scalar_mul_const_time_naive(&fv).unwrap();
let const_time_naive = start.elapsed();
start = Instant::now();
let res_1 = gv.multi_scalar_mul_var_time(fv.iter()).unwrap();
let var_time = start.elapsed();
assert_eq!(res_1, res);
let lookup_tables: Vec<_> = gv
.as_slice()
.into_iter()
.map(|e| e.to_wnaf_lookup_table(5))
.collect();
let f_refs: Vec<&FieldElement> = fs.iter().map(|f| f).collect();
start = Instant::now();
let res_2 =
G1Vector::multi_scalar_mul_var_time_with_precomputation_done(&lookup_tables, f_refs)
.unwrap();
let var_precomp_time = start.elapsed();
assert_eq!(res_2, res);
start = Instant::now();
let res_3 = gv.multi_scalar_mul_const_time(fv.as_ref()).unwrap();
let const_time = start.elapsed();
assert_eq!(res_3, res);
let group_elem_multiples: Vec<_> = gv
.as_slice()
.into_iter()
.map(|e| e.get_multiples(7))
.collect();
start = Instant::now();
let res_4 = G1Vector::multi_scalar_mul_const_time_with_precomputation_done(
&group_elem_multiples,
fv.as_slice(),
)
.unwrap();
let const_precomp_time = start.elapsed();
assert_eq!(res_4, res);
println!(
"Constant time for {} size multi-scalar multiplications using naive method: {:?}",
n, const_time_naive
);
println!(
"Constant time for {} size multi-scalar multiplications: {:?}",
n, const_time
);
println!(
"Constant time with pre-computation for {} size multi-scalar multiplications: {:?}",
n, const_precomp_time
);
println!(
"Variable time for {} size multi-scalar multiplications: {:?}",
n, var_time
);
println!(
"Variable time with pre-computation for {} size multi-scalar multiplications: {:?}",
n, var_precomp_time
);
}
#[test]
fn timing_wnaf_mul() {
let mut fs = vec![];
let mut gs = vec![];
let n = 64;
let w = 5;
for _ in 0..n {
fs.push(FieldElement::random());
gs.push(G1::random());
}
let gv = G1Vector::from(gs.as_slice());
let fv = FieldElementVector::from(fs.as_slice());
let mut start = Instant::now();
for i in 0..n {
let _ = &gv[i] * &fv[i];
}
println!(
"Time for {} scalar multiplications: {:?}",
n,
start.elapsed()
);
start = Instant::now();
for i in 0..n {
let naf = fv[i].to_wnaf(w);
let table = gv[i].to_wnaf_lookup_table(w);
G1::wnaf_mul(&table, &naf);
}
println!(
"Time for {} scalar multiplications using wnaf: {:?}",
n,
start.elapsed()
);
}
}