2018-05-16 08:41:46 +00:00
|
|
|
# Stint
|
|
|
|
# Copyright 2018 Status Research & Development GmbH
|
|
|
|
# Licensed under either of
|
|
|
|
#
|
|
|
|
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
|
|
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
|
|
|
#
|
|
|
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
|
|
|
|
2023-06-09 08:46:21 +00:00
|
|
|
import ./uintops, private/datatypes
|
2018-05-16 08:41:46 +00:00
|
|
|
|
2023-06-20 14:38:02 +00:00
|
|
|
{.push raises: [], gcsafe.}
|
|
|
|
|
2022-02-24 19:09:53 +00:00
|
|
|
func addmod_internal(a, b, m: StUint): StUint {.inline.}=
|
2018-05-16 08:41:46 +00:00
|
|
|
## Modular addition
|
|
|
|
## ⚠⚠ Assume a < m and b < m
|
|
|
|
|
2019-03-14 02:43:51 +00:00
|
|
|
doAssert a < m
|
|
|
|
doAssert b < m
|
2018-05-16 08:41:46 +00:00
|
|
|
|
|
|
|
# We don't do a_m + b_m directly to avoid overflows
|
|
|
|
let b_from_m = m - b
|
|
|
|
|
|
|
|
if a >= b_from_m:
|
|
|
|
return a - b_from_m
|
|
|
|
return m - b_from_m + a
|
|
|
|
|
2022-02-24 19:09:53 +00:00
|
|
|
func submod_internal(a, b, m: StUint): StUint {.inline.}=
|
2018-05-16 08:41:46 +00:00
|
|
|
## Modular substraction
|
|
|
|
## ⚠⚠ Assume a < m and b < m
|
|
|
|
|
2019-03-14 02:43:51 +00:00
|
|
|
doAssert a < m
|
|
|
|
doAssert b < m
|
2018-05-16 08:41:46 +00:00
|
|
|
|
|
|
|
# We don't do a_m - b_m directly to avoid underflows
|
|
|
|
if a >= b:
|
|
|
|
return a - b
|
|
|
|
return m - b + a
|
|
|
|
|
|
|
|
|
2022-02-24 19:09:53 +00:00
|
|
|
func doublemod_internal(a, m: StUint): StUint {.inline.}=
|
2018-05-16 08:41:46 +00:00
|
|
|
## Double a modulo m. Assume a < m
|
|
|
|
## Internal proc - used in mulmod
|
|
|
|
|
2019-03-14 02:43:51 +00:00
|
|
|
doAssert a < m
|
2018-05-16 08:41:46 +00:00
|
|
|
|
|
|
|
result = a
|
|
|
|
if a >= m - a:
|
|
|
|
result -= m
|
|
|
|
result += a
|
|
|
|
|
2022-02-24 19:09:53 +00:00
|
|
|
func mulmod_internal(a, b, m: StUint): StUint {.inline.}=
|
2018-05-16 08:41:46 +00:00
|
|
|
## Does (a * b) mod m. Assume a < m and b < m
|
|
|
|
## Internal proc - used in powmod
|
|
|
|
|
2019-03-14 02:43:51 +00:00
|
|
|
doAssert a < m
|
|
|
|
doAssert b < m
|
2018-05-16 08:41:46 +00:00
|
|
|
|
|
|
|
var (a, b) = (a, b)
|
|
|
|
|
|
|
|
if b > a:
|
|
|
|
swap(a, b)
|
|
|
|
|
|
|
|
while not b.isZero:
|
|
|
|
if b.isOdd:
|
|
|
|
result = result.addmod_internal(a, m)
|
|
|
|
a = doublemod_internal(a, m)
|
|
|
|
b = b shr 1
|
|
|
|
|
2022-02-24 19:09:53 +00:00
|
|
|
func powmod_internal(a, b, m: StUint): StUint {.inline.}=
|
2018-05-16 08:41:46 +00:00
|
|
|
## Compute ``(a ^ b) mod m``, assume a < m
|
|
|
|
## Internal proc
|
|
|
|
|
2019-03-14 02:43:51 +00:00
|
|
|
doAssert a < m
|
2018-05-16 08:41:46 +00:00
|
|
|
|
|
|
|
var (a, b) = (a, b)
|
|
|
|
result = one(type a)
|
|
|
|
|
|
|
|
while not b.isZero:
|
|
|
|
if b.isOdd:
|
|
|
|
result = result.mulmod_internal(a, m)
|
|
|
|
b = b shr 1
|
|
|
|
a = mulmod_internal(a, a, m)
|
|
|
|
|
2022-02-24 19:09:53 +00:00
|
|
|
func addmod*(a, b, m: StUint): StUint =
|
2018-05-16 08:41:46 +00:00
|
|
|
## Modular addition
|
|
|
|
|
|
|
|
let a_m = if a < m: a
|
|
|
|
else: a mod m
|
|
|
|
let b_m = if b < m: b
|
|
|
|
else: b mod m
|
|
|
|
|
|
|
|
result = addmod_internal(a_m, b_m, m)
|
|
|
|
|
2022-02-24 19:09:53 +00:00
|
|
|
func submod*(a, b, m: StUint): StUint =
|
2018-05-16 08:41:46 +00:00
|
|
|
## Modular substraction
|
|
|
|
|
|
|
|
let a_m = if a < m: a
|
|
|
|
else: a mod m
|
|
|
|
let b_m = if b < m: b
|
|
|
|
else: b mod m
|
|
|
|
|
|
|
|
result = submod_internal(a_m, b_m, m)
|
|
|
|
|
2022-02-24 19:09:53 +00:00
|
|
|
func mulmod*(a, b, m: StUint): StUint =
|
2018-05-16 08:41:46 +00:00
|
|
|
## Modular multiplication
|
|
|
|
|
|
|
|
let a_m = if a < m: a
|
|
|
|
else: a mod m
|
|
|
|
let b_m = if b < m: b
|
|
|
|
else: b mod m
|
|
|
|
|
|
|
|
result = mulmod_internal(a_m, b_m, m)
|
|
|
|
|
2022-02-24 19:09:53 +00:00
|
|
|
func powmod*(a, b, m: StUint): StUint =
|
2018-05-16 08:41:46 +00:00
|
|
|
## Modular exponentiation
|
|
|
|
|
|
|
|
let a_m = if a < m: a
|
|
|
|
else: a mod m
|
|
|
|
|
|
|
|
result = powmod_internal(a_m, b, m)
|
2023-06-20 14:38:02 +00:00
|
|
|
|
|
|
|
{.pop.}
|