use ark_bls12_381::{G1Affine};
use ark_ff::{PrimeField, field_new, BigInteger256};
use ark_std::Zero;
use num_bigint::BigUint;
use crate::types::{G1ScalarField, G1BaseField};
const LAMBDA: u128 = 0xac45a4010001a40200000000ffffffff;
pub fn decompose_slow(scalar: &G1ScalarField) -> (G1ScalarField, G1ScalarField) {
let inv_approx: BigUint = BigUint::parse_bytes(b"17c6becf1e01faadd63f6e522f6cfee30", 16).unwrap();
let s: BigUint = scalar.into_repr().into();
let s_hi = s.clone() >> 128;
let mut quotient: BigUint = (s_hi * inv_approx) >> 128;
let mut remainder: BigUint = s - quotient.clone() * LAMBDA;
while remainder >= BigUint::from(LAMBDA) {
remainder -= LAMBDA;
quotient += 1u32;
}
(G1ScalarField::from(quotient), G1ScalarField::from(remainder))
}
const LMDA1: u128 = 0xac45a4010001a402; const LMDA0: u128 = 0x00000000ffffffff; const INV1: u128 = 0x7c6becf1e01faadd; const INV0: u128 = 0x63f6e522f6cfee30; const MASK64: u128 = 0xffffffffffffffff;
pub fn decompose(scalar: &G1ScalarField, window_bits: u32) -> (G1ScalarField, G1ScalarField, bool, bool) {
let (s0, s1, s2, s3, is_neg_scalar) = glv_preprocess_scalar(scalar, window_bits);
let q0: u128 = INV0 * s2;
let q1: u128 = INV1 * s2 + INV0 * s3 + (q0 >> 64);
let q2: u128 = s2 + INV1 * s3 + (q1 >> 64);
let q3: u128 = s3 + (q2 >> 64);
let mut quotient0: u128 = q2 & MASK64;
let mut quotient1: u128 = q3 & MASK64;
let t0: u128 = quotient0 * LMDA0;
let t1: u128 = quotient1 * LMDA0 + quotient0 * LMDA1 + (t0 >> 64);
let t2: u128 = quotient1 * LMDA1 + (t1 >> 64);
let mut carry: i128 = s0 as i128 - (t0 & MASK64) as i128;
let mut r0: u64 = (carry as u128 & MASK64) as u64;
carry = carry >> 64;
carry += s1 as i128 - (t1 & MASK64) as i128;
let mut r1: u64 = (carry as u128 & MASK64) as u64;
carry = carry >> 64;
carry += s2 as i128 - (t2 & MASK64) as i128;
let mut r2: u64 = (carry as u128 & MASK64) as u64;
assert!(r2 < 4, "remainder at most 130 bit");
let mut correction = 0u32;
loop {
carry = r0 as i128 - LMDA0 as i128;
let t0: u64 = (carry as u128 & MASK64) as u64;
carry = carry >> 64;
carry += r1 as i128 - LMDA1 as i128;
let t1: u64 = (carry as u128 & MASK64) as u64;
carry = carry >> 64;
if carry < 0 && r2 == 0 { break;
}
r2 = (r2 as i128 + carry) as u64;
r0 = t0;
r1 = t1;
correction += 1;
}
quotient0 += correction as u128;
quotient1 += quotient0 >> 64;
quotient0 &= MASK64;
let mut is_neg_remainder = false;
if 128 % window_bits == 0 {
is_neg_remainder = glv_post_processing(&mut quotient0, &mut quotient1, &mut r0, &mut r1);
}
(G1ScalarField::from(BigInteger256([quotient0 as u64, quotient1 as u64, 0, 0])),
G1ScalarField::from(BigInteger256([r0, r1, 0, 0])),
is_neg_scalar,
is_neg_remainder)
}
const R3: i128 = 0x73eda753299d7d48;
const R2: i128 = 0x3339d80809a1d805;
const R1: i128 = 0x53bda402fffe5bfe;
const R0: i128 = 0xffffffff00000001;
fn glv_preprocess_scalar(scalar: &G1ScalarField, window_bits: u32) -> (u128, u128, u128, u128, bool) {
let mut s = [
scalar.into_repr().as_ref()[0],
scalar.into_repr().as_ref()[1],
scalar.into_repr().as_ref()[2],
scalar.into_repr().as_ref()[3],
];
let mut is_neg_scalar = false;
if 128 % window_bits == 0 {
if s[3] >= 0x3FFFFFFFFFFFFFFF {
is_neg_scalar = true;
let mut carry: i128 = 0;
carry = carry + R0 - s[0] as i128;
s[0] = (carry as u128 & MASK64) as u64;
carry = carry >> 64;
carry = carry + R1 - s[1] as i128;
s[1] = (carry as u128 & MASK64) as u64;
carry = carry >> 64;
carry = carry + R2 - s[2] as i128;
s[2] = (carry as u128 & MASK64) as u64;
carry = carry >> 64;
carry = carry + R3 - s[3] as i128;
s[3] = (carry as u128 & MASK64) as u64;
}
assert!(s[3] < 0x3FFFFFFFFFFFFFFF);
}
( s[0] as u128,
s[1] as u128,
s[2] as u128,
s[3] as u128,
is_neg_scalar )
}
fn glv_post_processing(q0:&mut u128, q1:&mut u128, r0:&mut u64, r1:&mut u64) -> bool {
if *r1 >= 0x8000000000000000 {
*q0 += 1;
*q1 += (*q0 == 0) as u128;
let mut carry: i128 = 0;
carry = carry + LMDA0 as i128 - *r0 as i128;
*r0 = (carry as u128 & MASK64) as u64;
carry = carry >> 64;
carry = carry + LMDA1 as i128 - *r1 as i128;
*r1 = (carry as u128 & MASK64) as u64;
assert!(*r1 < 0x8000000000000000);
return true;
}
false
}
const BETA: G1BaseField = field_new!(G1BaseField, "4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436");
pub fn endomorphism(point: &mut G1Affine) {
if point.is_zero() {
return;
}
point.x = point.x * BETA;
}