use std::time::SystemTime;
use std::time::UNIX_EPOCH;
use super::big;
use super::big::BIG;
use super::ecp;
use super::ecp::ECP;
use super::ecp2::ECP2;
use super::fp12::FP12;
use super::fp4::FP4;
use super::pair;
use super::rom;
use hash256::HASH256;
use hash384::HASH384;
use hash512::HASH512;
use rand::RAND;
pub const EFS: usize = big::MODBYTES as usize;
pub const EGS: usize = big::MODBYTES as usize;
pub const BAD_PARAMS: isize = -11;
pub const INVALID_POINT: isize = -14;
pub const WRONG_ORDER: isize = -18;
pub const BAD_PIN: isize = -19;
pub const SHA256: usize = 32;
pub const SHA384: usize = 48;
pub const SHA512: usize = 64;
pub const MAXPIN: i32 = 10000;
pub const PBLEN: i32 = 14;
pub const TS: usize = 10;
pub const TRAP: usize = 200;
#[allow(non_snake_case)]
fn hash(sha: usize, c: &mut FP4, U: &mut ECP, r: &mut [u8]) -> bool {
let mut w: [u8; EFS] = [0; EFS];
let mut t: [u8; 6 * EFS] = [0; 6 * EFS];
c.geta().geta().tobytes(&mut w);
for i in 0..EFS {
t[i] = w[i]
}
c.geta().getb().tobytes(&mut w);
for i in EFS..2 * EFS {
t[i] = w[i - EFS]
}
c.getb().geta().tobytes(&mut w);
for i in 2 * EFS..3 * EFS {
t[i] = w[i - 2 * EFS]
}
c.getb().getb().tobytes(&mut w);
for i in 3 * EFS..4 * EFS {
t[i] = w[i - 3 * EFS]
}
U.getx().tobytes(&mut w);
for i in 4 * EFS..5 * EFS {
t[i] = w[i - 4 * EFS]
}
U.gety().tobytes(&mut w);
for i in 5 * EFS..6 * EFS {
t[i] = w[i - 5 * EFS]
}
if sha == SHA256 {
let mut h = HASH256::new();
h.process_array(&t);
let sh = h.hash();
for i in 0..ecp::AESKEY {
r[i] = sh[i]
}
return true;
}
if sha == SHA384 {
let mut h = HASH384::new();
h.process_array(&t);
let sh = h.hash();
for i in 0..ecp::AESKEY {
r[i] = sh[i]
}
return true;
}
if sha == SHA512 {
let mut h = HASH512::new();
h.process_array(&t);
let sh = h.hash();
for i in 0..ecp::AESKEY {
r[i] = sh[i]
}
return true;
}
return false;
}
fn hashit(sha: usize, n: usize, id: &[u8], w: &mut [u8]) -> bool {
let mut r: [u8; 64] = [0; 64];
let mut didit = false;
if sha == SHA256 {
let mut h = HASH256::new();
if n > 0 {
h.process_num(n as i32)
}
h.process_array(id);
let hs = h.hash();
for i in 0..sha {
r[i] = hs[i];
}
didit = true;
}
if sha == SHA384 {
let mut h = HASH384::new();
if n > 0 {
h.process_num(n as i32)
}
h.process_array(id);
let hs = h.hash();
for i in 0..sha {
r[i] = hs[i];
}
didit = true;
}
if sha == SHA512 {
let mut h = HASH512::new();
if n > 0 {
h.process_num(n as i32)
}
h.process_array(id);
let hs = h.hash();
for i in 0..sha {
r[i] = hs[i];
}
didit = true;
}
if !didit {
return false;
}
let rm = big::MODBYTES as usize;
if sha > rm {
for i in 0..rm {
w[i] = r[i]
}
} else {
for i in 0..sha {
w[i + rm - sha] = r[i]
}
for i in 0..(rm - sha) {
w[i] = 0
}
}
return true;
}
pub fn today() -> usize {
return (SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs()
/ (60 * 1440)) as usize;
}
#[allow(non_snake_case)]
fn emap(u: &BIG, cb: isize) -> ECP {
let mut P: ECP;
let mut x = BIG::new_copy(u);
let mut p = BIG::new_ints(&rom::MODULUS);
x.rmod(&mut p);
loop {
P = ECP::new_bigint(&x, cb);
if !P.is_infinity() {
break;
}
x.inc(1);
x.norm();
}
return P;
}
#[allow(non_snake_case)]
fn unmap(u: &mut BIG, P: &mut ECP) -> isize {
let s = P.gets();
let mut R: ECP;
let mut r = 0;
let x = P.getx();
u.copy(&x);
loop {
u.dec(1);
u.norm();
r += 1;
R = ECP::new_bigint(u, s);
if !R.is_infinity() {
break;
}
}
return r as isize;
}
pub fn hash_id(sha: usize, id: &[u8], w: &mut [u8]) -> bool {
return hashit(sha, 0, id, w);
}
#[allow(non_snake_case)]
pub fn encoding(rng: &mut RAND, e: &mut [u8]) -> isize {
let mut t: [u8; EFS] = [0; EFS];
for i in 0..EFS {
t[i] = e[i + 1]
}
let mut u = BIG::frombytes(&t);
for i in 0..EFS {
t[i] = e[i + EFS + 1]
}
let mut v = BIG::frombytes(&t);
let mut P = ECP::new_bigs(&u, &v);
if P.is_infinity() {
return INVALID_POINT;
}
let p = BIG::new_ints(&rom::MODULUS);
u = BIG::randomnum(&p, rng);
let mut su = rng.getbyte() as isize;
su %= 2;
let mut W = emap(&mut u, su);
P.sub(&mut W);
let sv = P.gets();
let rn = unmap(&mut v, &mut P);
let mut m = rng.getbyte() as isize;
m %= rn;
v.inc(m + 1);
e[0] = (su + 2 * sv) as u8;
u.tobytes(&mut t);
for i in 0..EFS {
e[i + 1] = t[i]
}
v.tobytes(&mut t);
for i in 0..EFS {
e[i + EFS + 1] = t[i]
}
return 0;
}
#[allow(non_snake_case)]
pub fn decoding(d: &mut [u8]) -> isize {
let mut t: [u8; EFS] = [0; EFS];
if (d[0] & 0x04) != 0 {
return INVALID_POINT;
}
for i in 0..EFS {
t[i] = d[i + 1]
}
let mut u = BIG::frombytes(&t);
for i in 0..EFS {
t[i] = d[i + EFS + 1]
}
let mut v = BIG::frombytes(&t);
let su = (d[0] & 1) as isize;
let sv = ((d[0] >> 1) & 1) as isize;
let mut W = emap(&mut u, su);
let mut P = emap(&mut v, sv);
P.add(&mut W);
u = P.getx();
v = P.gety();
d[0] = 0x04;
u.tobytes(&mut t);
for i in 0..EFS {
d[i + 1] = t[i]
}
v.tobytes(&mut t);
for i in 0..EFS {
d[i + EFS + 1] = t[i]
}
return 0;
}
#[allow(non_snake_case)]
pub fn recombine_g1(r1: &[u8], r2: &[u8], r: &mut [u8]) -> isize {
let mut P = ECP::frombytes(&r1);
let mut Q = ECP::frombytes(&r2);
if P.is_infinity() || Q.is_infinity() {
return INVALID_POINT;
}
P.add(&mut Q);
P.tobytes(r, false);
return 0;
}
#[allow(non_snake_case)]
pub fn recombine_g2(w1: &[u8], w2: &[u8], w: &mut [u8]) -> isize {
let mut P = ECP2::frombytes(&w1);
let mut Q = ECP2::frombytes(&w2);
if P.is_infinity() || Q.is_infinity() {
return INVALID_POINT;
}
P.add(&mut Q);
P.tobytes(w);
return 0;
}
pub fn random_generate(rng: &mut RAND, s: &mut [u8]) -> isize {
let r = BIG::new_ints(&rom::CURVE_ORDER);
let mut sc = BIG::randomnum(&r, rng);
sc.tobytes(s);
return 0;
}
#[allow(non_snake_case)]
pub fn get_server_secret(s: &[u8], sst: &mut [u8]) -> isize {
let mut Q = ECP2::generator();
let mut sc = BIG::frombytes(s);
Q = pair::g2mul(&mut Q, &mut sc);
Q.tobytes(sst);
return 0;
}
#[allow(non_snake_case)]
pub fn get_g1_multiple(
rng: Option<&mut RAND>,
typ: usize,
x: &mut [u8],
g: &[u8],
w: &mut [u8],
) -> isize {
let mut sx: BIG;
let r = BIG::new_ints(&rom::CURVE_ORDER);
if let Some(rd) = rng {
sx = BIG::randomnum(&r, rd);
sx.tobytes(x);
} else {
sx = BIG::frombytes(x);
}
let mut P: ECP;
if typ == 0 {
P = ECP::frombytes(g);
if P.is_infinity() {
return INVALID_POINT;
}
} else {
P = ECP::mapit(g)
}
pair::g1mul(&mut P, &mut sx).tobytes(w, false);
return 0;
}
pub fn get_client_secret(s: &mut [u8], cid: &[u8], cst: &mut [u8]) -> isize {
return get_g1_multiple(None, 1, s, cid, cst);
}
#[allow(non_snake_case)]
pub fn extract_pin(sha: usize, cid: &[u8], pin: i32, token: &mut [u8]) -> isize {
return extract_factor(sha, cid, pin % MAXPIN, PBLEN, token);
}
#[allow(non_snake_case)]
pub fn extract_factor(
sha: usize,
cid: &[u8],
factor: i32,
facbits: i32,
token: &mut [u8],
) -> isize {
let mut P = ECP::frombytes(&token);
const RM: usize = big::MODBYTES as usize;
let mut h: [u8; RM] = [0; RM];
if P.is_infinity() {
return INVALID_POINT;
}
hashit(sha, 0, cid, &mut h);
let mut R = ECP::mapit(&h);
R = R.pinmul(factor, facbits);
P.sub(&mut R);
P.tobytes(token, false);
return 0;
}
#[allow(non_snake_case)]
pub fn restore_factor(
sha: usize,
cid: &[u8],
factor: i32,
facbits: i32,
token: &mut [u8],
) -> isize {
let mut P = ECP::frombytes(&token);
const RM: usize = big::MODBYTES as usize;
let mut h: [u8; RM] = [0; RM];
if P.is_infinity() {
return INVALID_POINT;
}
hashit(sha, 0, cid, &mut h);
let mut R = ECP::mapit(&h);
R = R.pinmul(factor, facbits);
P.add(&mut R);
P.tobytes(token, false);
return 0;
}
#[allow(non_snake_case)]
pub fn precompute(token: &[u8], cid: &[u8], g1: &mut [u8], g2: &mut [u8]) -> isize {
let T = ECP::frombytes(&token);
if T.is_infinity() {
return INVALID_POINT;
}
let P = ECP::mapit(&cid);
let Q = ECP2::generator();
let mut g = pair::ate(&Q, &T);
g = pair::fexp(&g);
g.tobytes(g1);
g = pair::ate(&Q, &P);
g = pair::fexp(&g);
g.tobytes(g2);
return 0;
}
#[allow(non_snake_case)]
pub fn get_client_permit(sha: usize, date: usize, s: &[u8], cid: &[u8], ctt: &mut [u8]) -> isize {
const RM: usize = big::MODBYTES as usize;
let mut h: [u8; RM] = [0; RM];
hashit(sha, date, cid, &mut h);
let mut P = ECP::mapit(&h);
let mut sc = BIG::frombytes(s);
pair::g1mul(&mut P, &mut sc).tobytes(ctt, false);
return 0;
}
#[allow(non_snake_case)]
pub fn client_1(
sha: usize,
date: usize,
client_id: &[u8],
rng: Option<&mut RAND>,
x: &mut [u8],
pin: usize,
token: &[u8],
sec: &mut [u8],
xid: Option<&mut [u8]>,
xcid: Option<&mut [u8]>,
permit: Option<&[u8]>,
) -> isize {
let r = BIG::new_ints(&rom::CURVE_ORDER);
let mut sx: BIG;
if let Some(rd) = rng {
sx = BIG::randomnum(&r, rd);
sx.tobytes(x);
} else {
sx = BIG::frombytes(x);
}
const RM: usize = big::MODBYTES as usize;
let mut h: [u8; RM] = [0; RM];
hashit(sha, 0, &client_id, &mut h);
let mut P = ECP::mapit(&h);
let mut T = ECP::frombytes(&token);
if T.is_infinity() {
return INVALID_POINT;
}
let mut W = P.pinmul((pin as i32) % MAXPIN, PBLEN);
T.add(&mut W);
if date != 0 {
if let Some(rpermit) = permit {
W = ECP::frombytes(&rpermit);
}
if W.is_infinity() {
return INVALID_POINT;
}
T.add(&mut W);
let mut h2: [u8; RM] = [0; RM];
hashit(sha, date, &h, &mut h2);
W = ECP::mapit(&h2);
if let Some(mut rxid) = xid {
P = pair::g1mul(&mut P, &mut sx);
P.tobytes(&mut rxid, false);
W = pair::g1mul(&mut W, &mut sx);
P.add(&mut W);
} else {
P.add(&mut W);
P = pair::g1mul(&mut P, &mut sx);
}
if let Some(mut rxcid) = xcid {
P.tobytes(&mut rxcid, false)
}
} else {
if let Some(mut rxid) = xid {
P = pair::g1mul(&mut P, &mut sx);
P.tobytes(&mut rxid, false);
}
}
T.tobytes(sec, false);
return 0;
}
#[allow(non_snake_case)]
pub fn server_1(sha: usize, date: usize, cid: &[u8], hid: &mut [u8], htid: Option<&mut [u8]>) {
const RM: usize = big::MODBYTES as usize;
let mut h: [u8; RM] = [0; RM];
hashit(sha, 0, cid, &mut h);
let mut P = ECP::mapit(&h);
P.tobytes(hid, false);
if date != 0 {
let mut h2: [u8; RM] = [0; RM];
hashit(sha, date, &h, &mut h2);
let mut R = ECP::mapit(&h2);
P.add(&mut R);
if let Some(rhtid) = htid {
P.tobytes(rhtid, false);
}
}
}
#[allow(non_snake_case)]
pub fn client_2(x: &[u8], y: &[u8], sec: &mut [u8]) -> isize {
let mut r = BIG::new_ints(&rom::CURVE_ORDER);
let mut P = ECP::frombytes(sec);
if P.is_infinity() {
return INVALID_POINT;
}
let mut px = BIG::frombytes(x);
let py = BIG::frombytes(y);
px.add(&py);
px.rmod(&mut r);
P = pair::g1mul(&mut P, &mut px);
P.neg();
P.tobytes(sec, false);
return 0;
}
pub fn get_time() -> usize {
return (SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs()) as usize;
}
pub fn get_y(sha: usize, timevalue: usize, xcid: &[u8], y: &mut [u8]) {
const RM: usize = big::MODBYTES as usize;
let mut h: [u8; RM] = [0; RM];
hashit(sha, timevalue, xcid, &mut h);
let mut sy = BIG::frombytes(&h);
let mut q = BIG::new_ints(&rom::CURVE_ORDER);
sy.rmod(&mut q);
sy.tobytes(y);
}
#[allow(non_snake_case)]
pub fn server_2(
date: usize,
hid: &[u8],
htid: Option<&[u8]>,
y: &[u8],
sst: &[u8],
xid: Option<&[u8]>,
xcid: Option<&[u8]>,
msec: &[u8],
e: Option<&mut [u8]>,
f: Option<&mut [u8]>,
) -> isize {
let Q = ECP2::generator();
let sQ = ECP2::frombytes(&sst);
if sQ.is_infinity() {
return INVALID_POINT;
}
let mut R: ECP;
if date != 0 {
if let Some(rxcid) = xcid {
R = ECP::frombytes(&rxcid);
} else {
return BAD_PARAMS;
}
} else {
if let Some(rxid) = xid {
R = ECP::frombytes(&rxid)
} else {
return BAD_PARAMS;
}
}
if R.is_infinity() {
return INVALID_POINT;
}
let mut sy = BIG::frombytes(&y);
let mut P: ECP;
if date != 0 {
if let Some(rhtid) = htid {
P = ECP::frombytes(&rhtid)
} else {
return BAD_PARAMS;
}
} else {
P = ECP::frombytes(&hid);
}
if P.is_infinity() {
return INVALID_POINT;
}
P = pair::g1mul(&mut P, &mut sy);
P.add(&mut R);
R = ECP::frombytes(&msec);
if R.is_infinity() {
return INVALID_POINT;
}
let mut g: FP12;
g = pair::ate2(&Q, &R, &sQ, &P);
g = pair::fexp(&g);
if !g.isunity() {
if let Some(rxid) = xid {
if let Some(re) = e {
if let Some(rf) = f {
g.tobytes(re);
if date != 0 {
P = ECP::frombytes(&hid);
if P.is_infinity() {
return INVALID_POINT;
}
R = ECP::frombytes(&rxid);
if R.is_infinity() {
return INVALID_POINT;
}
P = pair::g1mul(&mut P, &mut sy);
P.add(&mut R);
}
g = pair::ate(&Q, &P);
g = pair::fexp(&g);
g.tobytes(rf);
}
}
}
return BAD_PIN;
}
return 0;
}
pub fn kangaroo(e: &[u8], f: &[u8]) -> isize {
let mut ge = FP12::frombytes(e);
let mut gf = FP12::frombytes(f);
let mut distance: [isize; TS] = [0; TS];
let mut t = FP12::new_copy(&gf);
let mut table: [FP12; TS] = [FP12::new(); TS];
let mut s: isize = 1;
for m in 0..TS {
distance[m] = s;
table[m] = FP12::new_copy(&t);
s *= 2;
t.usqr();
}
t.one();
let mut dn: isize = 0;
let mut i: usize;
for _ in 0..TRAP {
i = (t.geta().geta().geta().lastbits(20) % (TS as isize)) as usize;
t.mul(&mut table[i]);
dn += distance[i];
}
gf.copy(&t);
gf.conj();
let mut steps: usize = 0;
let mut dm: isize = 0;
let mut res: isize = 0;
while dm - dn < MAXPIN as isize {
steps += 1;
if steps > 4 * TRAP {
break;
}
i = (ge.geta().geta().geta().lastbits(20) % (TS as isize)) as usize;
ge.mul(&mut table[i]);
dm += distance[i];
if ge.equals(&mut t) {
res = dm - dn;
break;
}
if ge.equals(&mut gf) {
res = dn - dm;
break;
}
}
if steps > 4 * TRAP || dm - dn >= MAXPIN as isize {
res = 0
}
return res;
}
pub fn hash_all(
sha: usize,
hid: &[u8],
xid: &[u8],
xcid: Option<&[u8]>,
sec: &[u8],
y: &[u8],
r: &[u8],
w: &[u8],
h: &mut [u8],
) -> bool {
let mut tlen: usize = 0;
const RM: usize = big::MODBYTES as usize;
let mut t: [u8; 10 * RM + 4] = [0; 10 * RM + 4];
for i in 0..hid.len() {
t[i] = hid[i]
}
tlen += hid.len();
if let Some(rxcid) = xcid {
for i in 0..rxcid.len() {
t[i + tlen] = rxcid[i]
}
tlen += rxcid.len();
} else {
for i in 0..xid.len() {
t[i + tlen] = xid[i]
}
tlen += xid.len();
}
for i in 0..sec.len() {
t[i + tlen] = sec[i]
}
tlen += sec.len();
for i in 0..y.len() {
t[i + tlen] = y[i]
}
tlen += y.len();
for i in 0..r.len() {
t[i + tlen] = r[i]
}
tlen += r.len();
for i in 0..w.len() {
t[i + tlen] = w[i]
}
tlen += w.len();
if tlen != 10 * RM + 4 {
return false;
}
return hashit(sha, 0, &t, h);
}
#[allow(non_snake_case)]
pub fn client_key(
sha: usize,
g1: &[u8],
g2: &[u8],
pin: usize,
r: &[u8],
x: &[u8],
h: &[u8],
wcid: &[u8],
ck: &mut [u8],
) -> isize {
let mut g1 = FP12::frombytes(&g1);
let mut g2 = FP12::frombytes(&g2);
let mut z = BIG::frombytes(&r);
let mut x = BIG::frombytes(&x);
let h = BIG::frombytes(&h);
let mut W = ECP::frombytes(&wcid);
if W.is_infinity() {
return INVALID_POINT;
}
W = pair::g1mul(&mut W, &mut x);
let mut r = BIG::new_ints(&rom::CURVE_ORDER);
z.add(&h);
z.rmod(&mut r);
g2.pinpow(pin as i32, PBLEN);
g1.mul(&mut g2);
let mut c = g1.compow(&z, &mut r);
hash(sha, &mut c, &mut W, ck);
return 0;
}
#[allow(non_snake_case)]
pub fn server_key(
sha: usize,
z: &[u8],
sst: &[u8],
w: &[u8],
h: &[u8],
hid: &[u8],
xid: &[u8],
xcid: Option<&[u8]>,
sk: &mut [u8],
) -> isize {
let sQ = ECP2::frombytes(&sst);
if sQ.is_infinity() {
return INVALID_POINT;
}
let mut R = ECP::frombytes(&z);
if R.is_infinity() {
return INVALID_POINT;
}
let mut A = ECP::frombytes(&hid);
if A.is_infinity() {
return INVALID_POINT;
}
let mut U = ECP::new();
if let Some(rxcid) = xcid {
U.copy(&ECP::frombytes(&rxcid));
} else {
U.copy(&ECP::frombytes(&xid));
}
if U.is_infinity() {
return INVALID_POINT;
}
let mut w = BIG::frombytes(&w);
let mut h = BIG::frombytes(&h);
A = pair::g1mul(&mut A, &mut h);
R.add(&mut A);
U = pair::g1mul(&mut U, &mut w);
let mut g = pair::ate(&sQ, &R);
g = pair::fexp(&g);
let mut c = g.trace();
hash(sha, &mut c, &mut U, sk);
return 0;
}