2020-02-08 17:50:01 +00:00
|
|
|
# Constantine
|
|
|
|
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
|
|
|
# Copyright (c) 2020-Present Mamy André-Ratsimbazafy
|
|
|
|
# Licensed and distributed under either of
|
|
|
|
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
|
|
|
|
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
|
|
|
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
|
|
|
|
2020-06-19 20:08:15 +00:00
|
|
|
import
|
|
|
|
# Standard library
|
|
|
|
std/unittest,
|
|
|
|
# Internal
|
2022-02-27 00:49:08 +00:00
|
|
|
../../constantine/math/io/io_bigints,
|
|
|
|
../../constantine/math/arithmetic,
|
|
|
|
../../constantine/platforms/abstractions,
|
2020-06-19 20:08:15 +00:00
|
|
|
# Test utilities,
|
|
|
|
support/canaries
|
2020-02-08 17:50:01 +00:00
|
|
|
|
2020-06-15 20:58:56 +00:00
|
|
|
echo "\n------------------------------------------------------\n"
|
|
|
|
|
2020-03-20 22:03:52 +00:00
|
|
|
proc mainArith() =
|
2023-01-11 18:31:23 +00:00
|
|
|
suite "isZero" & " [" & $WordBitWidth & "-bit mode]":
|
2020-02-11 23:25:48 +00:00
|
|
|
test "isZero for zero":
|
|
|
|
var x: BigInt[128]
|
|
|
|
check: x.isZero().bool
|
|
|
|
test "isZero for non-zero":
|
|
|
|
block:
|
2022-02-28 08:23:26 +00:00
|
|
|
let x = fromHex(BigInt[128], "0x00000000000000000000000000000001")
|
2020-02-11 23:25:48 +00:00
|
|
|
check: not x.isZero().bool
|
|
|
|
block:
|
2022-02-28 08:23:26 +00:00
|
|
|
let x = fromHex(BigInt[128], "0x00000000000000010000000000000000")
|
2020-02-11 23:25:48 +00:00
|
|
|
check: not x.isZero().bool
|
|
|
|
block:
|
2022-02-28 08:23:26 +00:00
|
|
|
let x = fromHex(BigInt[128], "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
|
2020-02-11 23:25:48 +00:00
|
|
|
check: not x.isZero().bool
|
|
|
|
|
2020-08-31 21:18:48 +00:00
|
|
|
test "isZero for zero (compile-time)":
|
|
|
|
const x = BigInt[128]()
|
|
|
|
check: static(x.isZero().bool)
|
|
|
|
test "isZero for non-zero (compile-time)":
|
|
|
|
block:
|
2022-02-28 08:23:26 +00:00
|
|
|
const x = fromHex(BigInt[128], "0x00000000000000000000000000000001")
|
2020-08-31 21:18:48 +00:00
|
|
|
check: static(not x.isZero().bool)
|
|
|
|
block:
|
2022-02-28 08:23:26 +00:00
|
|
|
const x = fromHex(BigInt[128], "0x00000000000000010000000000000000")
|
2020-08-31 21:18:48 +00:00
|
|
|
check: static(not x.isZero().bool)
|
|
|
|
block:
|
2022-02-28 08:23:26 +00:00
|
|
|
const x = fromHex(BigInt[128], "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
|
2020-08-31 21:18:48 +00:00
|
|
|
check: static(not x.isZero().bool)
|
|
|
|
|
|
|
|
|
2023-01-11 18:31:23 +00:00
|
|
|
suite "Arithmetic operations - Addition" & " [" & $WordBitWidth & "-bit mode]":
|
2020-02-11 23:25:48 +00:00
|
|
|
test "Adding 2 zeros":
|
2022-02-28 08:23:26 +00:00
|
|
|
var a = fromHex(BigInt[128], "0x00000000000000000000000000000000")
|
|
|
|
let b = fromHex(BigInt[128], "0x00000000000000000000000000000000")
|
2020-04-14 20:55:52 +00:00
|
|
|
let carry = a.cadd(b, CtTrue)
|
2020-02-11 23:25:48 +00:00
|
|
|
check: a.isZero().bool
|
|
|
|
|
|
|
|
test "Adding 1 zero - real addition":
|
|
|
|
block:
|
2022-02-28 08:23:26 +00:00
|
|
|
var a = fromHex(BigInt[128], "0x00000000000000000000000000000000")
|
|
|
|
let b = fromHex(BigInt[128], "0x00000000000000000000000000000001")
|
2020-04-14 20:55:52 +00:00
|
|
|
let carry = a.cadd(b, CtTrue)
|
2020-02-11 23:25:48 +00:00
|
|
|
|
2022-02-28 08:23:26 +00:00
|
|
|
let c = fromHex(BigInt[128], "0x00000000000000000000000000000001")
|
2020-02-11 23:25:48 +00:00
|
|
|
check:
|
|
|
|
bool(a == c)
|
|
|
|
block:
|
2022-02-28 08:23:26 +00:00
|
|
|
var a = fromHex(BigInt[128], "0x00000000000000000000000000000001")
|
|
|
|
let b = fromHex(BigInt[128], "0x00000000000000000000000000000000")
|
2020-04-14 20:55:52 +00:00
|
|
|
let carry = a.cadd(b, CtTrue)
|
2020-02-11 23:25:48 +00:00
|
|
|
|
2022-02-28 08:23:26 +00:00
|
|
|
let c = fromHex(BigInt[128], "0x00000000000000000000000000000001")
|
2020-02-11 23:25:48 +00:00
|
|
|
check:
|
|
|
|
bool(a == c)
|
|
|
|
|
|
|
|
test "Adding 1 zero - fake addition":
|
|
|
|
block:
|
2022-02-28 08:23:26 +00:00
|
|
|
var a = fromHex(BigInt[128], "0x00000000000000000000000000000000")
|
|
|
|
let b = fromHex(BigInt[128], "0x00000000000000000000000000000001")
|
2020-04-14 20:55:52 +00:00
|
|
|
let carry = a.cadd(b, CtFalse)
|
2020-02-11 23:25:48 +00:00
|
|
|
|
|
|
|
let c = a
|
|
|
|
check:
|
|
|
|
bool(a == c)
|
|
|
|
block:
|
2022-02-28 08:23:26 +00:00
|
|
|
var a = fromHex(BigInt[128], "0x00000000000000000000000000000001")
|
|
|
|
let b = fromHex(BigInt[128], "0x00000000000000000000000000000000")
|
2020-04-14 20:55:52 +00:00
|
|
|
let carry = a.cadd(b, CtFalse)
|
2020-02-11 23:25:48 +00:00
|
|
|
|
|
|
|
let c = a
|
|
|
|
check:
|
|
|
|
bool(a == c)
|
|
|
|
|
|
|
|
test "Adding non-zeros - real addition":
|
|
|
|
block:
|
2022-02-28 08:23:26 +00:00
|
|
|
var a = fromHex(BigInt[128], "0x00000000000000010000000000000000")
|
|
|
|
let b = fromHex(BigInt[128], "0x00000000000000000000000000000001")
|
2020-04-14 20:55:52 +00:00
|
|
|
let carry = a.cadd(b, CtTrue)
|
2020-02-11 23:25:48 +00:00
|
|
|
|
2022-02-28 08:23:26 +00:00
|
|
|
let c = fromHex(BigInt[128], "0x00000000000000010000000000000001")
|
2020-02-11 23:25:48 +00:00
|
|
|
check:
|
|
|
|
bool(a == c)
|
|
|
|
block:
|
2022-02-28 08:23:26 +00:00
|
|
|
var a = fromHex(BigInt[128], "0x00000000000000000000000000000001")
|
|
|
|
let b = fromHex(BigInt[128], "0x00000000000000010000000000000000")
|
2020-04-14 20:55:52 +00:00
|
|
|
let carry = a.cadd(b, CtTrue)
|
2020-02-11 23:25:48 +00:00
|
|
|
|
2022-02-28 08:23:26 +00:00
|
|
|
let c = fromHex(BigInt[128], "0x00000000000000010000000000000001")
|
2020-02-11 23:25:48 +00:00
|
|
|
check:
|
|
|
|
bool(a == c)
|
|
|
|
|
|
|
|
test "Adding non-zeros - fake addition":
|
|
|
|
block:
|
2022-02-28 08:23:26 +00:00
|
|
|
var a = fromHex(BigInt[128], "0x00000000000000010000000000000000")
|
|
|
|
let b = fromHex(BigInt[128], "0x00000000000000000000000000000001")
|
2020-04-14 20:55:52 +00:00
|
|
|
let carry = a.cadd(b, CtFalse)
|
2020-02-11 23:25:48 +00:00
|
|
|
|
|
|
|
let c = a
|
|
|
|
check:
|
|
|
|
bool(a == c)
|
|
|
|
block:
|
2022-02-28 08:23:26 +00:00
|
|
|
var a = fromHex(BigInt[128], "0x00000000000000000000000000000001")
|
|
|
|
let b = fromHex(BigInt[128], "0x00000000000000010000000000000000")
|
2020-04-14 20:55:52 +00:00
|
|
|
let carry = a.cadd(b, CtFalse)
|
2020-02-11 23:25:48 +00:00
|
|
|
|
|
|
|
let c = a
|
|
|
|
check:
|
|
|
|
bool(a == c)
|
|
|
|
|
|
|
|
test "Addition limbs carry":
|
|
|
|
block:
|
2022-02-28 08:23:26 +00:00
|
|
|
var a = fromHex(BigInt[128], "0x00000000FFFFFFFFFFFFFFFFFFFFFFFE")
|
|
|
|
let b = fromHex(BigInt[128], "0x00000000000000000000000000000001")
|
2020-04-14 20:55:52 +00:00
|
|
|
let carry = a.cadd(b, CtTrue)
|
2020-02-11 23:25:48 +00:00
|
|
|
|
2022-02-28 08:23:26 +00:00
|
|
|
let c = fromHex(BigInt[128], "0x00000000FFFFFFFFFFFFFFFFFFFFFFFF")
|
2020-02-11 23:25:48 +00:00
|
|
|
check:
|
|
|
|
bool(a == c)
|
|
|
|
not bool(carry)
|
|
|
|
|
|
|
|
block:
|
2022-02-28 08:23:26 +00:00
|
|
|
var a = fromHex(BigInt[128], "0x00000000FFFFFFFFFFFFFFFFFFFFFFFF")
|
|
|
|
let b = fromHex(BigInt[128], "0x00000000000000000000000000000001")
|
2020-04-14 20:55:52 +00:00
|
|
|
let carry = a.cadd(b, CtTrue)
|
2020-02-11 23:25:48 +00:00
|
|
|
|
2022-02-28 08:23:26 +00:00
|
|
|
let c = fromHex(BigInt[128], "0x00000001000000000000000000000000")
|
2020-02-11 23:25:48 +00:00
|
|
|
check:
|
|
|
|
bool(a == c)
|
|
|
|
not bool(carry)
|
|
|
|
|
2023-01-11 18:31:23 +00:00
|
|
|
suite "BigInt + SecretWord" & " [" & $WordBitWidth & "-bit mode]":
|
2020-03-20 22:03:52 +00:00
|
|
|
test "Addition limbs carry":
|
|
|
|
block: # P256 / 2
|
|
|
|
var a = BigInt[256].fromhex"0x7fffffff800000008000000000000000000000007fffffffffffffffffffffff"
|
|
|
|
|
|
|
|
let expected = BigInt[256].fromHex"7fffffff80000000800000000000000000000000800000000000000000000000"
|
|
|
|
|
2021-01-24 11:57:13 +00:00
|
|
|
discard a.add(One)
|
2020-03-20 22:03:52 +00:00
|
|
|
check: bool(a == expected)
|
|
|
|
|
2020-08-20 08:21:39 +00:00
|
|
|
proc mainMul() =
|
2023-01-11 18:31:23 +00:00
|
|
|
suite "Multi-precision multiplication" & " [" & $WordBitWidth & "-bit mode]":
|
2020-06-14 13:39:06 +00:00
|
|
|
test "Same size operand into double size result":
|
|
|
|
block:
|
2020-06-19 20:08:15 +00:00
|
|
|
var r = canary(BigInt[256])
|
2022-02-28 08:23:26 +00:00
|
|
|
let a = BigInt[128].fromHex"0x12345678FF11FFAA00321321CAFECAFE"
|
|
|
|
let b = BigInt[128].fromHex"0xDEADBEEFDEADBEEFDEADBEEFDEADBEEF"
|
2020-06-14 13:39:06 +00:00
|
|
|
|
|
|
|
let expected = BigInt[256].fromHex"fd5bdef43d64113f371ab5d8843beca889c07fd549b84d8a5001a8f102e0722"
|
|
|
|
|
|
|
|
r.prod(a, b)
|
|
|
|
check: bool(r == expected)
|
|
|
|
r.prod(b, a)
|
|
|
|
check: bool(r == expected)
|
|
|
|
|
|
|
|
test "Different size into large result":
|
|
|
|
block:
|
2020-06-19 20:08:15 +00:00
|
|
|
var r = canary(BigInt[200])
|
2020-06-14 13:39:06 +00:00
|
|
|
let a = BigInt[29].fromHex"0x12345678"
|
2022-02-28 08:23:26 +00:00
|
|
|
let b = BigInt[128].fromHex"0xDEADBEEFDEADBEEFDEADBEEFDEADBEEF"
|
2020-06-14 13:39:06 +00:00
|
|
|
|
|
|
|
let expected = BigInt[200].fromHex"fd5bdee65f787f665f787f665f787f65621ca08"
|
|
|
|
|
|
|
|
r.prod(a, b)
|
|
|
|
check: bool(r == expected)
|
|
|
|
r.prod(b, a)
|
|
|
|
check: bool(r == expected)
|
|
|
|
|
|
|
|
test "Destination is properly zero-padded if multiplicands are too short":
|
|
|
|
block:
|
2022-02-28 08:23:26 +00:00
|
|
|
var r = BigInt[200].fromHex"0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDE"
|
2020-06-14 13:39:06 +00:00
|
|
|
let a = BigInt[29].fromHex"0x12345678"
|
2022-02-28 08:23:26 +00:00
|
|
|
let b = BigInt[128].fromHex"0xDEADBEEFDEADBEEFDEADBEEFDEADBEEF"
|
2020-06-14 13:39:06 +00:00
|
|
|
|
|
|
|
let expected = BigInt[200].fromHex"fd5bdee65f787f665f787f665f787f65621ca08"
|
|
|
|
|
|
|
|
r.prod(a, b)
|
|
|
|
check: bool(r == expected)
|
|
|
|
r.prod(b, a)
|
|
|
|
check: bool(r == expected)
|
|
|
|
|
2020-08-20 08:21:39 +00:00
|
|
|
proc mainMulHigh() =
|
2023-01-11 18:31:23 +00:00
|
|
|
suite "Multi-precision multiplication keeping only high words" & " [" & $WordBitWidth & "-bit mode]":
|
2020-06-14 13:39:06 +00:00
|
|
|
test "Same size operand into double size result - discard first word":
|
|
|
|
block:
|
2020-06-19 20:08:15 +00:00
|
|
|
var r = canary(BigInt[256])
|
2022-02-28 08:23:26 +00:00
|
|
|
let a = BigInt[128].fromHex"0x12345678FF11FFAA00321321CAFECAFE"
|
|
|
|
let b = BigInt[128].fromHex"0xDEADBEEFDEADBEEFDEADBEEFDEADBEEF"
|
2020-06-14 13:39:06 +00:00
|
|
|
|
|
|
|
when WordBitWidth == 32:
|
|
|
|
let expected = BigInt[256].fromHex"fd5bdef43d64113f371ab5d8843beca889c07fd549b84d8a5001a8f"
|
|
|
|
else:
|
|
|
|
let expected = BigInt[256].fromHex"fd5bdef43d64113f371ab5d8843beca889c07fd549b84d8"
|
|
|
|
|
2022-02-28 08:23:26 +00:00
|
|
|
r.prodhighwords(a, b, 1)
|
2020-06-14 13:39:06 +00:00
|
|
|
check: bool(r == expected)
|
2022-02-28 08:23:26 +00:00
|
|
|
r.prodhighwords(b, a, 1)
|
2020-06-14 13:39:06 +00:00
|
|
|
check: bool(r == expected)
|
|
|
|
|
|
|
|
test "Same size operand into double size result - discard first 3 words":
|
|
|
|
block:
|
2020-06-19 20:08:15 +00:00
|
|
|
var r = canary(BigInt[256])
|
2022-02-28 08:23:26 +00:00
|
|
|
let a = BigInt[128].fromHex"0x12345678FF11FFAA00321321CAFECAFE"
|
|
|
|
let b = BigInt[128].fromHex"0xDEADBEEFDEADBEEFDEADBEEFDEADBEEF"
|
2020-06-14 13:39:06 +00:00
|
|
|
|
|
|
|
when WordBitWidth == 32:
|
|
|
|
let expected = BigInt[256].fromHex"fd5bdef43d64113f371ab5d8843beca889c07fd"
|
|
|
|
else:
|
|
|
|
let expected = BigInt[256].fromHex"fd5bdef43d64113"
|
|
|
|
|
2022-02-28 08:23:26 +00:00
|
|
|
r.prodhighwords(a, b, 3)
|
2020-06-14 13:39:06 +00:00
|
|
|
check: bool(r == expected)
|
2022-02-28 08:23:26 +00:00
|
|
|
r.prodhighwords(b, a, 3)
|
2020-06-14 13:39:06 +00:00
|
|
|
check: bool(r == expected)
|
|
|
|
|
|
|
|
test "All lower words trigger a carry":
|
|
|
|
block:
|
2020-06-19 20:08:15 +00:00
|
|
|
var r = canary(BigInt[256])
|
2022-02-28 08:23:26 +00:00
|
|
|
let a = BigInt[256].fromHex"0xFFFFF000FFFFF111FFFFFFFAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
|
|
|
|
let b = BigInt[256].fromHex"0xFFFFFFFFFFFFF222FFFFFFFBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
|
2020-06-14 13:39:06 +00:00
|
|
|
|
|
|
|
# Full product:
|
2022-02-28 08:23:26 +00:00
|
|
|
# fffff000ffffe33500ddc21a00cf39720000810900000013fffffffffffffffe
|
|
|
|
# 00000fff00001ccb000000090000000000000000000000000000000000000001
|
|
|
|
let expected = BigInt[256].fromHex"0xfffff000ffffe33500ddc21a00cf39720000810900000013fffffffffffffffe"
|
2020-06-14 13:39:06 +00:00
|
|
|
when WordBitWidth == 32:
|
|
|
|
const startWord = 8
|
|
|
|
else:
|
|
|
|
const startWord = 4
|
|
|
|
|
2022-02-28 08:23:26 +00:00
|
|
|
r.prodhighwords(a, b, startWord)
|
2020-06-14 13:39:06 +00:00
|
|
|
check: bool(r == expected)
|
2022-02-28 08:23:26 +00:00
|
|
|
r.prodhighwords(b, a, startWord)
|
2020-06-14 13:39:06 +00:00
|
|
|
check: bool(r == expected)
|
|
|
|
|
|
|
|
test "Different size into large result":
|
|
|
|
block:
|
2020-06-19 20:08:15 +00:00
|
|
|
var r = canary(BigInt[200])
|
2020-06-14 13:39:06 +00:00
|
|
|
let a = BigInt[29].fromHex"0x12345678"
|
2022-02-28 08:23:26 +00:00
|
|
|
let b = BigInt[128].fromHex"0xDEADBEEFDEADBEEFDEADBEEFDEADBEEF"
|
2020-06-14 13:39:06 +00:00
|
|
|
|
|
|
|
when WordBitWidth == 32:
|
|
|
|
let expected = BigInt[200].fromHex"fd5bdee65f787f665f787f6"
|
|
|
|
else:
|
|
|
|
let expected = BigInt[200].fromHex"fd5bdee"
|
|
|
|
|
2022-02-28 08:23:26 +00:00
|
|
|
r.prodhighwords(a, b, 2)
|
2020-06-14 13:39:06 +00:00
|
|
|
check: bool(r == expected)
|
2022-02-28 08:23:26 +00:00
|
|
|
r.prodhighwords(b, a, 2)
|
2020-06-14 13:39:06 +00:00
|
|
|
check: bool(r == expected)
|
|
|
|
|
|
|
|
test "Destination is properly zero-padded if multiplicands are too short":
|
|
|
|
block:
|
2022-02-28 08:23:26 +00:00
|
|
|
var r = BigInt[200].fromHex"0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDE"
|
2020-06-14 13:39:06 +00:00
|
|
|
let a = BigInt[29].fromHex"0x12345678"
|
2022-02-28 08:23:26 +00:00
|
|
|
let b = BigInt[128].fromHex"0xDEADBEEFDEADBEEFDEADBEEFDEADBEEF"
|
2020-06-14 13:39:06 +00:00
|
|
|
|
|
|
|
when WordBitWidth == 32:
|
|
|
|
let expected = BigInt[200].fromHex"fd5bdee65f787f665f787f6"
|
|
|
|
else:
|
|
|
|
let expected = BigInt[200].fromHex"fd5bdee"
|
|
|
|
|
2022-02-28 08:23:26 +00:00
|
|
|
r.prodhighwords(a, b, 2)
|
2020-06-14 13:39:06 +00:00
|
|
|
check: bool(r == expected)
|
2022-02-28 08:23:26 +00:00
|
|
|
r.prodhighwords(b, a, 2)
|
2020-06-14 13:39:06 +00:00
|
|
|
check: bool(r == expected)
|
|
|
|
|
2021-02-01 02:52:27 +00:00
|
|
|
proc mainSquare() =
|
2023-01-11 18:31:23 +00:00
|
|
|
suite "Multi-precision multiplication" & " [" & $WordBitWidth & "-bit mode]":
|
2021-02-01 02:52:27 +00:00
|
|
|
test "Squaring is consistent with multiplication (rBits = 2*aBits)":
|
|
|
|
block:
|
2022-02-28 08:23:26 +00:00
|
|
|
let a = BigInt[200].fromHex"0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDE"
|
2021-02-01 02:52:27 +00:00
|
|
|
|
2022-02-28 08:23:26 +00:00
|
|
|
var rmul, rsqr: BigInt[400]
|
2021-02-01 02:52:27 +00:00
|
|
|
|
2022-02-28 08:23:26 +00:00
|
|
|
rmul.prod(a, a)
|
|
|
|
rsqr.square(a)
|
|
|
|
check: bool(rmul == rsqr)
|
2021-02-01 02:52:27 +00:00
|
|
|
|
|
|
|
test "Squaring is consistent with multiplication (truncated)":
|
|
|
|
block:
|
2022-02-28 08:23:26 +00:00
|
|
|
let a = BigInt[200].fromHex"0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDE"
|
2021-02-01 02:52:27 +00:00
|
|
|
|
2022-02-28 08:23:26 +00:00
|
|
|
var rmul, rsqr: BigInt[256]
|
2021-02-01 02:52:27 +00:00
|
|
|
|
2022-02-28 08:23:26 +00:00
|
|
|
rmul.prod(a, a)
|
|
|
|
rsqr.square(a)
|
|
|
|
check: bool(rmul == rsqr)
|
2021-02-01 02:52:27 +00:00
|
|
|
|
2020-08-20 08:21:39 +00:00
|
|
|
proc mainModular() =
|
2023-01-11 18:31:23 +00:00
|
|
|
suite "Modular operations - small modulus" & " [" & $WordBitWidth & "-bit mode]":
|
2020-02-11 23:25:48 +00:00
|
|
|
# Vectors taken from Stint - https://github.com/status-im/nim-stint
|
|
|
|
test "100 mod 13":
|
|
|
|
# Test 1 word and more than 1 word
|
|
|
|
block:
|
|
|
|
let a = BigInt[7].fromUint(100'u32)
|
|
|
|
let m = BigInt[4].fromUint(13'u8)
|
|
|
|
|
2020-06-19 20:08:15 +00:00
|
|
|
var r = canary(BigInt[4])
|
2020-02-11 23:25:48 +00:00
|
|
|
r.reduce(a, m)
|
2020-06-19 20:08:15 +00:00
|
|
|
let expected = BigInt[4].fromUint(100'u8 mod 13)
|
|
|
|
doAssert bool(r == expected),
|
|
|
|
"\n r (low-level repr): " & $r &
|
|
|
|
"\n expected (ll repr): " & $expected
|
2020-02-11 23:25:48 +00:00
|
|
|
|
|
|
|
block: #
|
|
|
|
let a = BigInt[32].fromUint(100'u32)
|
|
|
|
let m = BigInt[4].fromUint(13'u8)
|
|
|
|
|
2020-06-19 20:08:15 +00:00
|
|
|
var r = canary(BigInt[4])
|
2020-02-11 23:25:48 +00:00
|
|
|
r.reduce(a, m)
|
2020-06-19 20:08:15 +00:00
|
|
|
let expected = BigInt[4].fromUint(100'u8 mod 13)
|
|
|
|
doAssert bool(r == expected),
|
|
|
|
"\n r (low-level repr): " & $r &
|
|
|
|
"\n expected (ll repr): " & $expected
|
2020-02-11 23:25:48 +00:00
|
|
|
|
|
|
|
block: #
|
|
|
|
let a = BigInt[64].fromUint(100'u32)
|
|
|
|
let m = BigInt[4].fromUint(13'u8)
|
|
|
|
|
2020-06-19 20:08:15 +00:00
|
|
|
var r = canary(BigInt[4])
|
2020-02-11 23:25:48 +00:00
|
|
|
r.reduce(a, m)
|
2020-06-19 20:08:15 +00:00
|
|
|
let expected = BigInt[4].fromUint(100'u8 mod 13)
|
|
|
|
doAssert bool(r == expected),
|
|
|
|
"\n r (low-level repr): " & $r &
|
|
|
|
"\n expected (ll repr): " & $expected
|
2020-02-11 23:25:48 +00:00
|
|
|
|
|
|
|
test "2^64 mod 3":
|
2022-02-28 08:23:26 +00:00
|
|
|
let a = BigInt[65].fromHex("0x10000000000000000")
|
2020-02-11 23:25:48 +00:00
|
|
|
let m = BigInt[8].fromUint(3'u8)
|
|
|
|
|
2020-06-19 20:08:15 +00:00
|
|
|
var r = canary(BigInt[8])
|
2020-02-11 23:25:48 +00:00
|
|
|
r.reduce(a, m)
|
2020-06-19 20:08:15 +00:00
|
|
|
let expected = BigInt[8].fromUint(1'u8)
|
|
|
|
doAssert bool(r == expected),
|
|
|
|
"\n r (low-level repr): " & $r &
|
|
|
|
"\n expected (ll repr): " & $expected
|
2020-02-08 17:50:01 +00:00
|
|
|
|
2020-02-11 23:25:48 +00:00
|
|
|
test "1234567891234567890 mod 10":
|
|
|
|
let a = BigInt[64].fromUint(1234567891234567890'u64)
|
|
|
|
let m = BigInt[8].fromUint(10'u8)
|
2020-02-08 17:50:01 +00:00
|
|
|
|
2020-06-19 20:08:15 +00:00
|
|
|
var r = canary(BigInt[8])
|
2020-02-11 23:25:48 +00:00
|
|
|
r.reduce(a, m)
|
2020-06-19 20:08:15 +00:00
|
|
|
let expected = BigInt[8].fromUint(0'u8)
|
|
|
|
doAssert bool(r == expected),
|
|
|
|
"\n r (low-level repr): " & $r &
|
|
|
|
"\n expected (ll repr): " & $expected
|
2020-02-08 17:50:01 +00:00
|
|
|
|
2023-01-11 18:31:23 +00:00
|
|
|
suite "Modular operations - small modulus - Stint specific failures highlighted by property-based testing" & " [" & $WordBitWidth & "-bit mode]":
|
2020-02-11 23:25:48 +00:00
|
|
|
# Vectors taken from Stint - https://github.com/status-im/nim-stint
|
|
|
|
test "Modulo: 65696211516342324 mod 174261910798982":
|
|
|
|
let u = 65696211516342324'u64
|
|
|
|
let v = 174261910798982'u64
|
2020-02-08 17:50:01 +00:00
|
|
|
|
2020-02-11 23:25:48 +00:00
|
|
|
let a = BigInt[56].fromUint(u)
|
|
|
|
let m = BigInt[48].fromUint(v)
|
2020-02-08 17:50:01 +00:00
|
|
|
|
2020-06-19 20:08:15 +00:00
|
|
|
var r = canary(BigInt[48])
|
2020-02-11 23:25:48 +00:00
|
|
|
r.reduce(a, m)
|
2020-02-08 18:09:20 +00:00
|
|
|
|
2020-06-19 20:08:15 +00:00
|
|
|
let expected = BigInt[48].fromUint(u mod v)
|
|
|
|
doAssert bool(r == expected),
|
|
|
|
"\n r (low-level repr): " & $r &
|
|
|
|
"\n expected (ll repr): " & $expected
|
2020-02-08 18:09:20 +00:00
|
|
|
|
2020-02-11 23:25:48 +00:00
|
|
|
test "Modulo: 15080397990160655 mod 600432699691":
|
|
|
|
let u = 15080397990160655'u64
|
|
|
|
let v = 600432699691'u64
|
2020-02-10 18:57:35 +00:00
|
|
|
|
2020-02-11 23:25:48 +00:00
|
|
|
let a = BigInt[54].fromUint(u)
|
|
|
|
let m = BigInt[40].fromUint(v)
|
2020-02-10 18:57:35 +00:00
|
|
|
|
2020-06-19 20:08:15 +00:00
|
|
|
var r = canary(BigInt[40])
|
2020-02-10 18:57:35 +00:00
|
|
|
r.reduce(a, m)
|
|
|
|
|
2020-06-19 20:08:15 +00:00
|
|
|
let expected = BigInt[40].fromUint(u mod v)
|
|
|
|
doAssert bool(r == expected),
|
|
|
|
"\n r (low-level repr): " & $r &
|
|
|
|
"\n expected (ll repr): " & $expected
|
2020-02-09 17:17:32 +00:00
|
|
|
|
2020-03-20 22:03:52 +00:00
|
|
|
proc mainNeg() =
|
2023-01-11 18:31:23 +00:00
|
|
|
suite "Conditional negation" & " [" & $WordBitWidth & "-bit mode]":
|
2020-03-20 22:03:52 +00:00
|
|
|
test "Conditional negation":
|
|
|
|
block:
|
2022-02-28 08:23:26 +00:00
|
|
|
var a = fromHex(BigInt[128], "0x12345678FF11FFAA00321321CAFECAFE")
|
|
|
|
var b = fromHex(BigInt[128], "0xDEADBEEFDEADBEEFDEADBEEFDEADBEEF")
|
2020-03-20 22:03:52 +00:00
|
|
|
|
|
|
|
let a2 = a
|
|
|
|
let b2 = b
|
|
|
|
|
|
|
|
a.cneg(CtTrue)
|
|
|
|
b.cneg(CtTrue)
|
|
|
|
|
|
|
|
discard a.add(a2)
|
|
|
|
discard b.add(b2)
|
|
|
|
|
|
|
|
check:
|
|
|
|
bool(a.isZero)
|
|
|
|
bool(b.isZero)
|
|
|
|
|
|
|
|
block:
|
2022-02-28 08:23:26 +00:00
|
|
|
var a = fromHex(BigInt[128], "0x12345678FF11FFAA00321321CAFECAFE")
|
|
|
|
var b = fromHex(BigInt[128], "0xDEADBEEFDEADBEEFDEADBEEFDEADBEEF")
|
2020-03-20 22:03:52 +00:00
|
|
|
|
|
|
|
let a2 = a
|
|
|
|
let b2 = b
|
|
|
|
|
|
|
|
a.cneg(CtFalse)
|
|
|
|
b.cneg(CtFalse)
|
|
|
|
|
|
|
|
check:
|
|
|
|
bool(a == a2)
|
|
|
|
bool(b == b2)
|
|
|
|
|
|
|
|
test "Conditional negation with carries":
|
|
|
|
block:
|
2022-02-28 08:23:26 +00:00
|
|
|
var a = fromHex(BigInt[128], "0x12345678FF11FFAA00321321FFFFFFFF")
|
|
|
|
var b = fromHex(BigInt[128], "0xFFFFFFFFFFFFFFFF0000000000000000")
|
2020-03-20 22:03:52 +00:00
|
|
|
|
|
|
|
let a2 = a
|
|
|
|
let b2 = b
|
|
|
|
|
|
|
|
a.cneg(CtTrue)
|
|
|
|
b.cneg(CtTrue)
|
|
|
|
|
|
|
|
discard a.add(a2)
|
|
|
|
discard b.add(b2)
|
|
|
|
|
|
|
|
check:
|
|
|
|
bool(a.isZero)
|
|
|
|
bool(b.isZero)
|
|
|
|
|
|
|
|
block:
|
2022-02-28 08:23:26 +00:00
|
|
|
var a = fromHex(BigInt[128], "0x123456780000000000321321FFFFFFFF")
|
|
|
|
var b = fromHex(BigInt[128], "0xFFFFFFFFFFFFFFFF0000000000000000")
|
2020-03-20 22:03:52 +00:00
|
|
|
|
|
|
|
let a2 = a
|
|
|
|
let b2 = b
|
|
|
|
|
|
|
|
a.cneg(CtFalse)
|
|
|
|
b.cneg(CtFalse)
|
|
|
|
|
|
|
|
check:
|
|
|
|
bool(a == a2)
|
|
|
|
bool(b == b2)
|
|
|
|
|
|
|
|
test "Conditional all-zero bit or all-one bit":
|
|
|
|
block:
|
2022-02-28 08:23:26 +00:00
|
|
|
var a = fromHex(BigInt[128], "0x00000000000000000000000000000000")
|
|
|
|
var b = fromHex(BigInt[128], "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
|
2020-03-20 22:03:52 +00:00
|
|
|
|
|
|
|
let a2 = a
|
|
|
|
let b2 = b
|
|
|
|
|
|
|
|
a.cneg(CtTrue)
|
|
|
|
b.cneg(CtTrue)
|
|
|
|
|
|
|
|
discard a.add(a2)
|
|
|
|
discard b.add(b2)
|
|
|
|
|
|
|
|
check:
|
|
|
|
bool(a.isZero)
|
|
|
|
bool(b.isZero)
|
|
|
|
|
|
|
|
block:
|
2022-02-28 08:23:26 +00:00
|
|
|
var a = fromHex(BigInt[128], "0x00000000000000000000000000000000")
|
|
|
|
var b = fromHex(BigInt[128], "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
|
2020-03-20 22:03:52 +00:00
|
|
|
|
|
|
|
let a2 = a
|
|
|
|
let b2 = b
|
|
|
|
|
|
|
|
a.cneg(CtFalse)
|
|
|
|
b.cneg(CtFalse)
|
|
|
|
|
|
|
|
check:
|
|
|
|
bool(a == a2)
|
|
|
|
bool(b == b2)
|
|
|
|
|
|
|
|
proc mainCopySwap() =
|
2023-01-11 18:31:23 +00:00
|
|
|
suite "Copy and Swap" & " [" & $WordBitWidth & "-bit mode]":
|
2020-03-20 22:03:52 +00:00
|
|
|
test "Conditional copy":
|
|
|
|
block:
|
2022-02-28 08:23:26 +00:00
|
|
|
var a = fromHex(BigInt[128], "0x12345678FF11FFAA00321321CAFECAFE")
|
|
|
|
let b = fromHex(BigInt[128], "0xDEADBEEFDEADBEEFDEADBEEFDEADBEEF")
|
2020-03-20 22:03:52 +00:00
|
|
|
|
|
|
|
var expected = a
|
|
|
|
a.ccopy(b, CtFalse)
|
|
|
|
|
|
|
|
check: bool(expected == a)
|
|
|
|
|
|
|
|
block:
|
2022-02-28 08:23:26 +00:00
|
|
|
var a = fromHex(BigInt[128], "0x00000000FFFFFFFFFFFFFFFFFFFFFFFF")
|
|
|
|
let b = fromHex(BigInt[128], "0x00000000000000000000000000000001")
|
2020-03-20 22:03:52 +00:00
|
|
|
|
|
|
|
var expected = b
|
|
|
|
a.ccopy(b, CtTrue)
|
|
|
|
|
|
|
|
check: bool(expected == b)
|
|
|
|
|
|
|
|
test "Conditional swap":
|
|
|
|
block:
|
2022-02-28 08:23:26 +00:00
|
|
|
var a = fromHex(BigInt[128], "0x12345678FF11FFAA00321321CAFECAFE")
|
|
|
|
var b = fromHex(BigInt[128], "0xDEADBEEFDEADBEEFDEADBEEFDEADBEEF")
|
2020-03-20 22:03:52 +00:00
|
|
|
|
|
|
|
let eA = a
|
|
|
|
let eB = b
|
|
|
|
|
|
|
|
a.cswap(b, CtFalse)
|
|
|
|
check:
|
|
|
|
bool(eA == a)
|
|
|
|
bool(eB == b)
|
|
|
|
|
|
|
|
block:
|
2022-02-28 08:23:26 +00:00
|
|
|
var a = fromHex(BigInt[128], "0x00000000FFFFFFFFFFFFFFFFFFFFFFFF")
|
|
|
|
var b = fromHex(BigInt[128], "0x00000000000000000000000000000001")
|
2020-03-20 22:03:52 +00:00
|
|
|
|
|
|
|
let eA = b
|
|
|
|
let eB = a
|
|
|
|
|
|
|
|
a.cswap(b, CtTrue)
|
|
|
|
check:
|
|
|
|
bool(eA == a)
|
|
|
|
bool(eB == b)
|
|
|
|
|
|
|
|
proc mainModularInverse() =
|
2023-01-11 18:31:23 +00:00
|
|
|
suite "Modular Inverse (with odd modulus)" & " [" & $WordBitWidth & "-bit mode]":
|
2020-03-20 22:03:52 +00:00
|
|
|
# Note: We don't define multi-precision multiplication
|
|
|
|
# because who needs it when you have Montgomery?
|
2022-02-28 08:23:26 +00:00
|
|
|
# ¯\(ツ)/¯
|
2020-03-20 22:03:52 +00:00
|
|
|
test "42^-1 (mod 2017) = 1969":
|
|
|
|
block: # small int
|
|
|
|
let a = BigInt[16].fromUint(42'u16)
|
|
|
|
let M = BigInt[16].fromUint(2017'u16)
|
|
|
|
|
|
|
|
let expected = BigInt[16].fromUint(1969'u16)
|
2020-06-19 20:08:15 +00:00
|
|
|
var r = canary(BigInt[16])
|
2020-03-20 22:03:52 +00:00
|
|
|
|
2022-02-10 13:05:07 +00:00
|
|
|
r.invmod(a, M)
|
2020-03-20 22:03:52 +00:00
|
|
|
|
|
|
|
check: bool(r == expected)
|
|
|
|
|
|
|
|
block: # huge int
|
|
|
|
let a = BigInt[381].fromUint(42'u16)
|
|
|
|
let M = BigInt[381].fromUint(2017'u16)
|
|
|
|
|
|
|
|
let expected = BigInt[381].fromUint(1969'u16)
|
2020-06-19 20:08:15 +00:00
|
|
|
var r = canary(BigInt[381])
|
2020-03-20 22:03:52 +00:00
|
|
|
|
2022-02-10 13:05:07 +00:00
|
|
|
r.invmod(a, M)
|
2020-03-20 22:03:52 +00:00
|
|
|
|
|
|
|
check: bool(r == expected)
|
|
|
|
|
|
|
|
test "271^-1 (mod 383) = 106":
|
|
|
|
block: # small int
|
|
|
|
let a = BigInt[16].fromUint(271'u16)
|
|
|
|
let M = BigInt[16].fromUint(383'u16)
|
|
|
|
|
|
|
|
let expected = BigInt[16].fromUint(106'u16)
|
2020-06-19 20:08:15 +00:00
|
|
|
var r = canary(BigInt[16])
|
2020-03-20 22:03:52 +00:00
|
|
|
|
2022-02-10 13:05:07 +00:00
|
|
|
r.invmod(a, M)
|
2020-03-20 22:03:52 +00:00
|
|
|
|
|
|
|
check: bool(r == expected)
|
|
|
|
|
|
|
|
block: # huge int
|
|
|
|
let a = BigInt[381].fromUint(271'u16)
|
|
|
|
let M = BigInt[381].fromUint(383'u16)
|
|
|
|
|
|
|
|
let expected = BigInt[381].fromUint(106'u16)
|
2020-06-19 20:08:15 +00:00
|
|
|
var r = canary(BigInt[381])
|
2020-03-20 22:03:52 +00:00
|
|
|
|
2022-02-10 13:05:07 +00:00
|
|
|
r.invmod(a, M)
|
2020-03-20 22:03:52 +00:00
|
|
|
|
|
|
|
check: bool(r == expected)
|
|
|
|
|
|
|
|
test "BN254_Modulus^-1 (mod BLS12_381)":
|
|
|
|
let a = BigInt[381].fromHex("0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47")
|
|
|
|
let M = BigInt[381].fromHex("0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab")
|
|
|
|
|
|
|
|
let expected = BigInt[381].fromHex("0x0636759a0f3034fa47174b2c0334902f11e9915b7bd89c6a2b3082b109abbc9837da17201f6d8286fe6203caa1b9d4c8")
|
|
|
|
|
2020-06-19 20:08:15 +00:00
|
|
|
var r = canary(BigInt[381])
|
2022-02-10 13:05:07 +00:00
|
|
|
r.invmod(a, M)
|
2020-03-20 22:03:52 +00:00
|
|
|
|
|
|
|
check: bool(r == expected)
|
|
|
|
|
2020-04-14 11:39:03 +00:00
|
|
|
test "0^-1 (mod any) = 0 (need for tower of extension fields)":
|
|
|
|
block:
|
|
|
|
let a = BigInt[16].fromUint(0'u16)
|
|
|
|
let M = BigInt[16].fromUint(2017'u16)
|
2020-03-20 22:03:52 +00:00
|
|
|
|
2020-04-14 11:39:03 +00:00
|
|
|
let expected = BigInt[16].fromUint(0'u16)
|
2020-06-19 20:08:15 +00:00
|
|
|
var r = canary(BigInt[16])
|
2020-03-20 22:03:52 +00:00
|
|
|
|
2022-02-10 13:05:07 +00:00
|
|
|
r.invmod(a, M)
|
2020-03-20 22:03:52 +00:00
|
|
|
|
2020-04-14 11:39:03 +00:00
|
|
|
check: bool(r == expected)
|
|
|
|
|
|
|
|
block:
|
|
|
|
let a = BigInt[381].fromUint(0'u16)
|
|
|
|
let M = BigInt[381].fromHex("0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab")
|
|
|
|
|
|
|
|
let expected = BigInt[381].fromUint(0'u16)
|
2020-06-19 20:08:15 +00:00
|
|
|
var r = canary(BigInt[381])
|
2020-03-20 22:03:52 +00:00
|
|
|
|
2022-02-10 13:05:07 +00:00
|
|
|
r.invmod(a, M)
|
2020-04-14 11:39:03 +00:00
|
|
|
|
|
|
|
check: bool(r == expected)
|
2020-03-20 22:03:52 +00:00
|
|
|
|
|
|
|
mainArith()
|
2021-02-01 02:52:27 +00:00
|
|
|
mainMul()
|
|
|
|
mainMulHigh()
|
|
|
|
mainSquare()
|
|
|
|
mainModular()
|
|
|
|
mainNeg()
|
|
|
|
mainCopySwap()
|
|
|
|
mainModularInverse()
|