use crate::jubjub::big;
use crate::jubjub::big::BIG;
use crate::jubjub::ecp;
use crate::jubjub::ecp::ECP;
use crate::jubjub::rom;
use crate::aes;
use crate::hmac;
use crate::rand::RAND;
pub const INVALID_PUBLIC_KEY: isize = -2;
pub const ERROR: isize = -3;
pub const EFS: usize = big::MODBYTES as usize;
pub const EGS: usize = big::MODBYTES as usize;
pub fn rfc7748(r: &mut BIG) {
let mut lg=0;
let mut t=BIG::new_int(1);
let mut c=rom::CURVE_COF_I;
while c!=1 {
lg+=1;
c/=2;
}
let n=(8*EGS-lg+1) as usize;
r.mod2m(n);
t.shl(n);
r.add(&t);
c=r.lastbits(lg as usize);
r.dec(c);
}
#[allow(non_snake_case)]
pub fn in_range(s: &[u8]) -> bool {
let r = BIG::new_ints(&rom::CURVE_ORDER);
let sc = BIG::frombytes(&s);
if sc.iszilch() {
return false;
}
if BIG::comp(&sc, &r) >= 0 {
return false;
}
true
}
#[allow(non_snake_case)]
pub fn key_pair_generate(rng: Option<&mut impl RAND>, s: &mut [u8], w: &mut [u8]) -> isize {
let res = 0;
let mut sc: BIG;
let G = ECP::generator();
let r = BIG::new_ints(&rom::CURVE_ORDER);
if let Some(x) = rng {
if ecp::CURVETYPE != ecp::WEIERSTRASS {
sc = BIG::random(x); } else {
sc = BIG::randomnum(&r, x); }
} else {
sc = BIG::frombytes(&s);
}
if ecp::CURVETYPE != ecp::WEIERSTRASS {
rfc7748(&mut sc); }
sc.tobytes(s);
let WP = G.clmul(&sc,&r);
WP.tobytes(w, false);
res
}
#[allow(non_snake_case)]
pub fn public_key_validate(w: &[u8]) -> isize {
let mut WP = ECP::frombytes(w);
let mut res = 0;
let r = BIG::new_ints(&rom::CURVE_ORDER);
if WP.is_infinity() {
res = INVALID_PUBLIC_KEY
}
if res == 0 {
let q = BIG::new_ints(&rom::MODULUS);
let nb = q.nbits();
let mut k = BIG::new();
k.one();
k.shl((nb + 4) / 2);
k.add(&q);
k.div(&r);
while k.parity() == 0 {
k.shr(1);
WP.dbl();
}
if !k.isunity() {
WP = WP.mul(&mut k)
}
if WP.is_infinity() {
res = INVALID_PUBLIC_KEY
}
}
res
}
#[allow(non_snake_case)]
pub fn ecpsvdp_dh(s: &[u8], wd: &[u8], z: &mut [u8], typ: isize) -> isize {
let mut res = 0;
let sc = BIG::frombytes(&s);
let mut W = ECP::frombytes(&wd);
if W.is_infinity() {
res = ERROR
}
if res == 0 {
let r = BIG::new_ints(&rom::CURVE_ORDER);
W = W.clmul(&sc,&r);
if W.is_infinity() {
res = ERROR;
} else {
if ecp::CURVETYPE != ecp::MONTGOMERY {
if typ>0 {
if typ==1 {
W.tobytes(z,true);
} else {
W.tobytes(z,false);
}
} else {
W.getx().tobytes(z);
}
return res;
} else {
W.getx().tobytes(z);
}
}
}
res
}
#[allow(non_snake_case)]
pub fn ecpsp_dsa(
sha: usize,
rng: &mut impl RAND,
s: &[u8],
f: &[u8],
c: &mut [u8],
d: &mut [u8],
) -> isize {
let mut t: [u8; EGS] = [0; EGS];
let mut b: [u8; EGS] = [0; EGS];
hmac::GPhashit(hmac::MC_SHA2, sha, &mut b, EGS,0,Some(f), -1, None);
let G = ECP::generator();
let r = BIG::new_ints(&rom::CURVE_ORDER);
let sc = BIG::frombytes(s);
let fb = BIG::frombytes(&b);
let mut cb = BIG::new();
let mut db = BIG::new();
let mut tb = BIG::new();
let mut V = ECP::new();
while db.iszilch() {
let mut u = BIG::randomnum(&r, rng);
let w = BIG::randomnum(&r, rng);
V.copy(&G);
V = V.clmul(&u,&r);
let vx = V.getx();
cb.copy(&vx);
cb.rmod(&r);
if cb.iszilch() {
continue;
}
tb.copy(&BIG::modmul(&u, &w, &r));
u.copy(&tb);
u.invmodp(&r);
db.copy(&BIG::modmul(&sc, &cb, &r));
db.copy(&BIG::modadd(&db, &fb, &r));
tb.copy(&BIG::modmul(&db, &w, &r));
db.copy(&tb);
tb.copy(&BIG::modmul(&u, &db, &r));
db.copy(&tb);
}
cb.tobytes(&mut t);
for i in 0..EGS {
c[i] = t[i]
}
db.tobytes(&mut t);
for i in 0..EGS {
d[i] = t[i]
}
0
}
#[allow(non_snake_case)]
pub fn ecpvp_dsa(sha: usize, w: &[u8], f: &[u8], c: &[u8], d: &[u8]) -> isize {
let mut res = 0;
let mut b: [u8; EGS] = [0; EGS];
hmac::GPhashit(hmac::MC_SHA2, sha, &mut b, EGS, 0,Some(f), -1, None);
let mut G = ECP::generator();
let r = BIG::new_ints(&rom::CURVE_ORDER);
let mut cb = BIG::frombytes(c);
let mut db = BIG::frombytes(d);
let mut fb = BIG::frombytes(&b);
let mut tb = BIG::new();
if cb.iszilch() || BIG::comp(&cb, &r) >= 0 || db.iszilch() || BIG::comp(&db, &r) >= 0 {
res = ERROR;
}
if res == 0 {
db.invmodp(&r);
tb.copy(&BIG::modmul(&mut fb, &mut db, &r));
fb.copy(&tb);
let h2 = BIG::modmul(&mut cb, &mut db, &r);
let WP = ECP::frombytes(&w);
if WP.is_infinity() {
res = ERROR;
} else {
let mut P = ECP::new();
P.copy(&WP);
P = P.mul2(&h2, &mut G, &fb);
if P.is_infinity() {
res = ERROR;
} else {
db = P.getx();
db.rmod(&r);
if BIG::comp(&db, &cb) != 0 {
res = ERROR
}
}
}
}
res
}
#[allow(non_snake_case)]
pub fn ecies_encrypt(
sha: usize,
p1: &[u8],
p2: &[u8],
rng: &mut impl RAND,
w: &[u8],
m: &[u8],
v: &mut [u8],
c: &mut [u8],
t: &mut [u8],
) -> usize {
let mut z: [u8; EFS] = [0; EFS];
let mut k1: [u8; ecp::AESKEY] = [0; ecp::AESKEY];
let mut k2: [u8; ecp::AESKEY] = [0; ecp::AESKEY];
let mut u: [u8; EGS] = [0; EGS];
let mut vz: [u8; 3 * EFS + 1] = [0; 3 * EFS + 1];
let mut k: [u8; 2 * ecp::AESKEY] = [0; 2 * ecp::AESKEY];
if key_pair_generate(Some(rng), &mut u, v) != 0 {
return 0;
}
if ecpsvdp_dh(&u, &w, &mut z, 0) != 0 {
return 0;
}
for i in 0..2 * EFS + 1 {
vz[i] = v[i]
}
for i in 0..EFS {
vz[2 * EFS + 1 + i] = z[i]
}
hmac::kdf2(hmac::MC_SHA2, sha, &vz, Some(p1), 2 * ecp::AESKEY, &mut k);
for i in 0..ecp::AESKEY {
k1[i] = k[i];
k2[i] = k[ecp::AESKEY + i]
}
let clen = aes::cbc_iv0_encrypt(&k1, m, c);
let mut l2: [u8; 8] = [0; 8];
let p2l = p2.len();
hmac::inttobytes(p2l, &mut l2);
let mut opt=clen;
for i in 0..p2l {
c[opt]=p2[i]; opt+=1;
}
for i in 0..8 {
c[opt]=l2[i]; opt+=1;
}
hmac::hmac1(hmac::MC_SHA2, sha, t, t.len(), &k2, &c[0..opt]);
clen
}
fn ncomp(t1: &[u8], t2: &[u8], n: usize) -> bool {
let mut res = 0;
for i in 0..n {
res |= (t1[i] ^ t2[i]) as isize;
}
if res == 0 {
return true;
}
false
}
#[allow(non_snake_case)]
pub fn ecies_decrypt(
sha: usize,
p1: &[u8],
p2: &[u8],
v: &[u8],
c: &mut [u8],
clen: usize,
t: &[u8],
u: &[u8],
m: &mut [u8],
) -> usize {
let mut z: [u8; EFS] = [0; EFS];
let mut k1: [u8; ecp::AESKEY] = [0; ecp::AESKEY];
let mut k2: [u8; ecp::AESKEY] = [0; ecp::AESKEY];
let mut vz: [u8; 3 * EFS + 1] = [0; 3 * EFS + 1];
let mut k: [u8; 2 * ecp::AESKEY] = [0; 2 * ecp::AESKEY];
let mut tag: [u8; 32] = [0; 32];
for i in 0..t.len() {
tag[i] = t[i]
}
if ecpsvdp_dh(&u, &v, &mut z, 0) != 0 {
return 0;
}
for i in 0..2 * EFS + 1 {
vz[i] = v[i]
}
for i in 0..EFS {
vz[2 * EFS + 1 + i] = z[i]
}
hmac::kdf2(hmac::MC_SHA2, sha, &vz, Some(p1), 2 * ecp::AESKEY, &mut k);
for i in 0..ecp::AESKEY {
k1[i] = k[i];
k2[i] = k[ecp::AESKEY + i]
}
let mlen = aes::cbc_iv0_decrypt(&k1, &c[0..clen], m);
if mlen == 0 {
return 0;
}
let mut l2: [u8; 8] = [0; 8];
let p2l = p2.len();
hmac::inttobytes(p2l, &mut l2);
let mut opt=clen;
for i in 0..p2l {
c[opt]=p2[i]; opt+=1;
}
for i in 0..8 {
c[opt]=l2[i]; opt+=1;
}
let tl=tag.len();
hmac::hmac1(hmac::MC_SHA2, sha, &mut tag, tl, &k2, &c[0..opt]);
if !ncomp(&t, &tag, t.len()) {
return 0;
}
mlen
}