Temp switch to uint32 words for testing modulo. Remove tests that depend on word size
This commit is contained in:
parent
166a1075b1
commit
30f8756dfc
|
@ -40,8 +40,8 @@
|
|||
import ./primitives
|
||||
from ./private/primitives_internal import unsafeDiv2n1n, unsafeExtendedPrecMul
|
||||
|
||||
type Word* = Ct[uint64]
|
||||
type BaseType* = uint64 # Exported type for conversion in "normal integers"
|
||||
type Word* = Ct[uint32]
|
||||
type BaseType* = uint32 # Exported type for conversion in "normal integers"
|
||||
|
||||
const WordBitSize* = sizeof(Word) * 8 - 1
|
||||
## Limbs are 63-bit by default
|
||||
|
@ -217,16 +217,16 @@ func shlAddMod[bits](a: var BigInt[bits], c: Word, M: BigInt[bits]) =
|
|||
const R = bits and WordBitSize # R = bits mod 64
|
||||
|
||||
when R == 0: # If the number of bits is a multiple of 64
|
||||
let a1 = a.limbs[^2] #
|
||||
let a0 = a.limbs[^1] #
|
||||
moveMem(a.limbs[1].addr, a.limbs[0].addr, (len-1) * Word.sizeof) # we can just shift words
|
||||
a.limbs[0] = c # and replace the first one by c
|
||||
let a1 = a.limbs[^1]
|
||||
let m0 = M.limbs[^1]
|
||||
else: # Need to deal with partial word shifts at the edge.
|
||||
let a1 = ((a.limbs[^2] shl (WordBitSize-R)) or (a.limbs[^3] shr R)) and MaxWord
|
||||
let a0 = ((a.limbs[^1] shl (WordBitSize-R)) or (a.limbs[^2] shr R)) and MaxWord
|
||||
moveMem(a.limbs[1].addr, a.limbs[0].addr, (len-1) * Word.sizeof)
|
||||
a.limbs[0] = c
|
||||
let a1 = ((a.limbs[^1] shl (WordBitSize-R)) or (a.limbs[^2] shr R)) and MaxWord
|
||||
let m0 = ((M.limbs[^1] shl (WordBitSize-R)) or (M.limbs[^2] shr R)) and MaxWord
|
||||
|
||||
# m0 has its high bit set. (a0, a1)/p0 fits in a limb.
|
||||
|
@ -256,8 +256,8 @@ func shlAddMod[bits](a: var BigInt[bits], c: Word, M: BigInt[bits]) =
|
|||
block: # q*p
|
||||
var qp_hi: Word
|
||||
unsafeExtendedPrecMul(qp_hi, qp_lo, q, M.limbs[i]) # q * p
|
||||
assert qp_lo.isMsbSet.not.bool
|
||||
assert carry.isMsbSet.not.bool
|
||||
# assert qp_lo.isMsbSet.not.bool
|
||||
# assert carry.isMsbSet.not.bool
|
||||
qp_lo += carry # Add carry from previous limb
|
||||
let qp_carry = qp_lo.isMsbSet
|
||||
carry = mux(qp_carry, qp_hi + One, qp_hi) # New carry
|
||||
|
|
|
@ -57,6 +57,12 @@ func unsafeExtendedPrecMul*(hi, lo: var Ct[uint64], a, b: Ct[uint64]) {.inline.}
|
|||
else:
|
||||
asm_x86_64_extMul(T(hi), T(lo), T(a), T(b))
|
||||
|
||||
func unsafeExtendedPrecMul*(hi, lo: var Ct[uint32], a, b: Ct[uint32]) {.inline.}=
|
||||
## Extended precision multiplication uint32 * uint32 --> uint32
|
||||
let extMul = uint64(a) * uint64(b)
|
||||
hi = (Ct[uint32])(extMul shr 32)
|
||||
lo = (Ct[uint32])(extMul and 31)
|
||||
|
||||
func asm_x86_64_div2n1n(q, r: var uint64, n_hi, n_lo, d: uint64) {.inline.}=
|
||||
## Division uint128 by uint64
|
||||
## Warning ⚠️ :
|
||||
|
@ -118,6 +124,20 @@ func unsafeDiv2n1n*(q, r: var Ct[uint64], n_hi, n_lo, d: Ct[uint64]) {.inline.}=
|
|||
else:
|
||||
asm_x86_64_div2n1n(T(q), T(r), T(n_hi), T(n_lo), T(d))
|
||||
|
||||
func unsafeDiv2n1n*(q, r: var Ct[uint32], n_hi, n_lo, d: Ct[uint32]) {.inline.}=
|
||||
## Division uint64 by uint32
|
||||
## Warning ⚠️ :
|
||||
## - if n_hi == d, quotient does not fit in an uint32
|
||||
## - if n_hi > d result is undefined
|
||||
##
|
||||
## To avoid issues, n_hi, n_lo, d should be normalized.
|
||||
## i.e. shifted (== multiplied by the same power of 2)
|
||||
## so that the most significant bit in d is set.
|
||||
let dividend = (uint64(n_hi) shl 32) or uint64(n_lo)
|
||||
let divisor = uint64(d)
|
||||
q = (Ct[uint32])(dividend div divisor)
|
||||
r = (Ct[uint32])(dividend mod divisor)
|
||||
|
||||
when isMainModule:
|
||||
block: # Multiplication
|
||||
var hi, lo: uint64
|
||||
|
|
|
@ -124,22 +124,6 @@ suite "Arithmetic operations - Addition":
|
|||
bool(a == c)
|
||||
not bool(carry)
|
||||
|
||||
block:
|
||||
var a = fromHex(BigInt[128], "0xFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF")
|
||||
let b = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000001")
|
||||
let carry = a.add(b, ctrue(Word))
|
||||
|
||||
# BigInt[128] takes 3 Words as a BigInt Word is 63-bit
|
||||
var ab: array[3*sizeof(Word), byte]
|
||||
ab.dumpRawUint(a, littleEndian)
|
||||
|
||||
# Given that it uses 3 words, we actually can store 2^128 in BigInt[128]
|
||||
var c: array[3*sizeof(Word), byte]
|
||||
c[16] = 1
|
||||
check:
|
||||
c == ab
|
||||
not bool(carry) # carry can only happen within limbs
|
||||
|
||||
suite "Modular operations - small modulus":
|
||||
# Vectors taken from Stint - https://github.com/status-im/nim-stint
|
||||
test "100 mod 13":
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
# 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.
|
||||
|
||||
import
|
||||
# Standard library
|
||||
unittest, random, strutils,
|
||||
# Third-party
|
||||
../constantine/[io, bigints, primitives]
|
||||
|
||||
suite "Bigints - Multiprecision modulo":
|
||||
test "bitsize 237 mod bitsize 192":
|
||||
let a = BigInt[237].fromHex("0x123456789012345678901234567890123456789012345678901234567890")
|
||||
let m = BigInt[192].fromHex("0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB")
|
||||
|
||||
let expected = BigInt[192].fromHex("0x34567890123456789012345678901234567886f8091a3087")
|
||||
|
||||
var r: BigInt[192]
|
||||
r.reduce(a, m)
|
||||
|
||||
check:
|
||||
bool(r == expected)
|
||||
|
||||
test "bitsize 365 mod bitsize 258":
|
||||
let a = BigInt[365].fromHex("0x6c8ae85a6cab4bc530b91177e3f399894ff1fe335b6b3fcdc577ea4f8d754bbe71a6353e8609a4769ec8c56727a")
|
||||
let m = BigInt[258].fromHex("0x2cadadfa2bb7d7141ad9728d6955ddb68a8b81ecb6a7610575bf4d6f562b09f0d")
|
||||
|
||||
let expected = BigInt[258].fromHex("0xb7c8844f534bf298645dc118384e975245c1a44ba4b0bca8a04c9db0c9035b9")
|
||||
|
||||
var r: BigInt[258]
|
||||
r.reduce(a, m)
|
||||
|
||||
check:
|
||||
bool(r == expected)
|
|
@ -23,15 +23,6 @@ suite "IO":
|
|||
T(big.limbs[0]) == 0
|
||||
T(big.limbs[1]) == 0
|
||||
|
||||
block: # 2^63 is properly represented on 2 limbs
|
||||
let x = 1'u64 shl 63
|
||||
let x_bytes = cast[array[8, byte]](x)
|
||||
let big = BigInt[64].fromRawUint(x_bytes, cpuEndian)
|
||||
|
||||
check:
|
||||
T(big.limbs[0]) == 0
|
||||
T(big.limbs[1]) == 1
|
||||
|
||||
test "Parsing and dumping round-trip on uint64":
|
||||
block:
|
||||
# "Little-endian" - 2^63
|
||||
|
|
Loading…
Reference in New Issue