use crate::util::ops::{ subw, add2 };
pub struct Sc25519 {
pub v: [u32; 32],
}
#[inline]
pub fn make_sc25519() -> Sc25519 {
Sc25519 { v: [0; 32] }
}
#[allow(non_upper_case_globals)]
const m: [u32; 32] = [
0xED, 0xD3, 0xF5, 0x5C, 0x1A, 0x63, 0x12, 0x58,
0xD6, 0x9C, 0xF7, 0xA2, 0xDE, 0xF9, 0xDE, 0x14,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 ];
#[allow(non_upper_case_globals)]
const mu: [u32; 33] = [
0x1B, 0x13, 0x2C, 0x0A, 0xA3, 0xE5, 0x9C, 0xED,
0xA7, 0x29, 0x63, 0x08, 0x5D, 0x21, 0x06, 0x21,
0xEB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x0F ];
#[inline]
fn lt(a: u32, b: u32) -> u32 {
let mut x: u32 = a;
x = subw!( x, b );
x >>= 31;
x
}
fn reduce_add_sub(r: &mut Sc25519) {
let mut pb: u32 = 0;
let mut b: u32 = 0;
let mut t: [u8; 32] = [0; 32];
for i in 0..32 {
pb += m[i];
b = lt(r.v[i], pb);
t[i] = add2!( subw!( r.v[i], pb ), b<<8 ) as u8;
pb = b;
}
let mask: u32 = subw!( b, 1 );
for i in 0..32 {
r.v[i] ^= mask & (r.v[i] ^ (t[i] as u32));
}
}
fn barrett_reduce(r: &mut Sc25519, x: &[u32]) {
let mut q2: [u32; 66] = [0; 66];
let mut r1: [u32; 33] = [0; 33];
let mut r2: [u32; 33] = [0; 33];
for i in 0..33 {
for j in 0..33 {
if i+j >= 31 { q2[i+j] += mu[i]*x[j+31]; }
}
}
let mut carry: u32 = q2[31] >> 8;
q2[32] += carry;
carry = q2[32] >> 8;
q2[33] += carry;
r1.copy_from_slice(&x[0..33]);
let q3 = &q2[33..];
for i in 0..32 {
for j in 0..33 {
if i+j < 33 { r2[i+j] += m[i]*q3[j]; }
}
}
for i in 0..32 {
carry = r2[i] >> 8;
r2[i+1] += carry;
r2[i] &= 0xff;
}
let mut pb: u32 = 0;
for i in 0..32 {
pb += r2[i];
let b = lt(r1[i],pb);
r.v[i] = add2!( subw!( r1[i], pb ), b<<8 );
pb = b;
}
reduce_add_sub(r);
reduce_add_sub(r);
}
pub fn sc25519_from32bytes(r: &mut Sc25519, x: &[u8]) {
let mut t: [u32; 64] = [0; 64];
for i in 0..32 { t[i] = x[i] as u32; }
barrett_reduce(r, &t);
}
pub fn sc25519_from64bytes(r: &mut Sc25519, x: &[u8]) {
let mut t: [u32; 64] = [0; 64];
for i in 0..64 { t[i] = x[i] as u32; }
barrett_reduce(r, &t);
}
pub fn sc25519_to32bytes(r: &mut [u8], x: &Sc25519) {
for i in 0..32 { r[i] = x.v[i] as u8; }
}
pub fn sc25519_add(r: &mut Sc25519, x: &Sc25519, y: &Sc25519) {
for i in 0..32 { r.v[i] = x.v[i] + y.v[i]; }
for i in 0..31 {
let carry = r.v[i] >> 8;
r.v[i+1] += carry;
r.v[i] &= 0xff;
}
reduce_add_sub(r);
}
pub fn sc25519_mul(r: &mut Sc25519, x: &Sc25519, y: &Sc25519) {
let mut t: [u32; 64] = [0; 64];
for i in 0..32 {
for j in 0..32 {
t[i+j] += x.v[i] * y.v[j];
}
}
for i in 0..63 {
let carry = t[i] >> 8;
t[i+1] += carry;
t[i] &= 0xff;
}
barrett_reduce(r, &t);
}
pub fn sc25519_window3(r: &mut [i8], s: &Sc25519) {
for i in 0..10 {
r[8*i+0] = ( s.v[3*i+0] & 7) as i8;
r[8*i+1] = ((s.v[3*i+0] >> 3) & 7) as i8;
r[8*i+2] = ((s.v[3*i+0] >> 6) & 7) as i8;
r[8*i+2] ^= ((s.v[3*i+1] << 2) & 7) as i8;
r[8*i+3] = ((s.v[3*i+1] >> 1) & 7) as i8;
r[8*i+4] = ((s.v[3*i+1] >> 4) & 7) as i8;
r[8*i+5] = ((s.v[3*i+1] >> 7) & 7) as i8;
r[8*i+5] ^= ((s.v[3*i+2] << 1) & 7) as i8;
r[8*i+6] = ((s.v[3*i+2] >> 2) & 7) as i8;
r[8*i+7] = ((s.v[3*i+2] >> 5) & 7) as i8;
}
r[80] = ( s.v[30] & 7) as i8;
r[81] = ((s.v[30] >> 3) & 7) as i8;
r[82] = ((s.v[30] >> 6) & 7) as i8;
r[82] ^= ((s.v[31] << 2) & 7) as i8;
r[83] = ((s.v[31] >> 1) & 7) as i8;
r[84] = ((s.v[31] >> 4) & 7) as i8;
let mut carry: i8 = 0;
for i in 0..84 {
r[i] += carry;
r[i+1] += r[i] >> 3;
r[i] &= 7;
carry = r[i] >> 2;
r[i] -= carry<<3;
}
r[84] += carry;
}
pub fn sc25519_2interleave2(r: &mut[u8], s1: &Sc25519, s2: &Sc25519) {
for i in 0..31 {
r[4*i] = (( s1.v[i] & 3) ^ (( s2.v[i] & 3) << 2)) as u8;
r[4*i+1] = (((s1.v[i] >> 2) & 3) ^ (((s2.v[i] >> 2) & 3) << 2)) as u8;
r[4*i+2] = (((s1.v[i] >> 4) & 3) ^ (((s2.v[i] >> 4) & 3) << 2)) as u8;
r[4*i+3] = (((s1.v[i] >> 6) & 3) ^ (((s2.v[i] >> 6) & 3) << 2)) as u8;
}
r[124] = (( s1.v[31] & 3) ^ (( s2.v[31] & 3) << 2)) as u8;
r[125] = (((s1.v[31] >> 2) & 3) ^ (((s2.v[31] >> 2) & 3) << 2)) as u8;
r[126] = (((s1.v[31] >> 4) & 3) ^ (((s2.v[31] >> 4) & 3) << 2)) as u8;
}