// 蒙哥马利模乘,快速计算 c = a * b % Q 
// R = 2 ^ 32
// 蒙哥马利约减, reduce(a) = a / R % Q, 将 a 从蒙哥马利域转换到普通域
// 蒙哥马利乘法, mul(a, b) = a * b / R = reduce(a * b) 
// a * R % Q, 将 a 从普通域转换到蒙哥马利域

///|
const QINV : Int = 58728449 // QINV * Q % R = 1

///| 将 a 从蒙哥马利域转换到普通域
/// return a * R^-1 % Q
/// 
pub fn montgomery_reduce(a : Int64) -> Int {
  let t : Int64 = (a.to_int() * QINV).to_int64()
  let x = (a - t * Q.to_int64()) >> 32
  x.to_int()
}

///| 对于一个有限域元素a, a <= 2 ^ {31} - 2 ^ {22} - 1,
/// 计算 r \equiv a (mod Q), 满足 -6283009 <= r <= 6283008
pub fn reduce32(a : Int) -> Int {
  /// Q = 8380417, 2 ^ {22} = 4194304, 2 ^ {23} = 8388608
  let mut t = (a + (1 << 22)) >> 23 // 近似 a / Q 
  t = a - t * Q
  t
}

///| 如果输入为负数,则加上Q
pub fn caddq(a : Int) -> Int {
  a + ((a >> 31) & Q) // a是负数时算术右移31位得到全1
}

///|
test "caddq" {
  inspect(caddq(-10), content="\{Q - 10}")
  inspect(caddq(-1), content="\{Q - 1}")
  inspect(caddq(0), content="0")
  inspect(caddq(1), content="1")
}