diff --git a/constantine.nimble b/constantine.nimble index 41985d2..01e20b6 100644 --- a/constantine.nimble +++ b/constantine.nimble @@ -19,4 +19,5 @@ task test, "Run all tests": test "", "tests/test_primitives.nim" test "", "tests/test_io.nim" test "", "tests/test_bigints.nim" + test "", "tests/test_bigints_multimod.nim" test " -d:testingCurves", "tests/test_field_fp.nim" diff --git a/constantine/bigints_raw.nim b/constantine/bigints_raw.nim index dae885b..20258ad 100644 --- a/constantine/bigints_raw.nim +++ b/constantine/bigints_raw.nim @@ -57,6 +57,8 @@ from sugar import distinctBase type Word* = Ct[uint32] ## Logical BigInt word ## A logical BigInt word is of size physical MachineWord-1 +type DoubleWord = Ct[uint64] + type BaseType* = uint32 ## Physical BigInt for conversion in "normal integers" @@ -357,17 +359,15 @@ func shlAddMod(a: BigIntViewMut, c: Word, M: BigIntViewConst) = var qp_lo: Word block: # q*p - var qp_hi: Word - unsafeExtendedPrecMul(qp_hi, qp_lo, q, M[i]) # q * p - qp_lo += carry # Add carry from previous limb - - carry = qp_hi shl 1 + qp_lo.isMsbSet.Word # New carry - qp_lo = qp_lo and MaxWord # Normalize to u63 + # q * p + carry (doubleword) carry from previous limb + let qp = unsafeExtPrecMul(q, M[i]) + carry.DoubleWord + carry = Word(qp shr WordBitSize) # New carry: high digit besides LSB + qp_lo = qp.Word and MaxWord # Normalize to u63 block: # a*2^63 - q*p a[i] -= qp_lo - carry += Word(a[i].isMsbSet) # Adjust if borrow - a[i] = a[i] and MaxWord # Normalize to u63 + carry += Word(a[i].isMsbSet) # Adjust if borrow + a[i] = a[i] and MaxWord # Normalize to u63 over_p = mux( a[i] == M[i], over_p, diff --git a/constantine/primitives_extprecision.nim b/constantine/primitives_extprecision.nim index 756ea0d..722b243 100644 --- a/constantine/primitives_extprecision.nim +++ b/constantine/primitives_extprecision.nim @@ -38,7 +38,7 @@ func asm_x86_64_extMul(hi, lo: var uint64, a, b: uint64) {.inline.}= : """ -func unsafeExtendedPrecMul*(hi, lo: var Ct[uint64], a, b: Ct[uint64]) {.inline.}= +func unsafeExtPrecMul*(hi, lo: var Ct[uint64], a, b: Ct[uint64]) {.inline.}= ## Extended precision multiplication uint64 * uint64 --> uint128 ## ## TODO, at the moment only x86_64 architecture are supported @@ -57,13 +57,9 @@ 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)) -import strutils - -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 ((1'u64 shl 32) - 1)) +template unsafeExtPrecMul*(a, b: Ct[uint32]): Ct[uint64] = + ## Extended precision multiplication uint32 * uint32 --> uint64 + Ct[uint64](uint64(a) * uint64(b)) func asm_x86_64_div2n1n(q, r: var uint64, n_hi, n_lo, d: uint64) {.inline.}= ## Division uint128 by uint64 diff --git a/tests/test_bigints_multimod.nim b/tests/test_bigints_multimod.nim index c1ab968..8b0c3eb 100644 --- a/tests/test_bigints_multimod.nim +++ b/tests/test_bigints_multimod.nim @@ -10,7 +10,7 @@ import # Standard library unittest, random, strutils, # Third-party - ../constantine/[io, bigints, primitives] + ../constantine/[io, bigints_raw, bigints_public, primitives] suite "Bigints - Multiprecision modulo": test "bitsize 237 mod bitsize 192": diff --git a/tests/test_bigints_multimod.nim.cfg b/tests/test_bigints_multimod.nim.cfg new file mode 100644 index 0000000..dd68656 --- /dev/null +++ b/tests/test_bigints_multimod.nim.cfg @@ -0,0 +1 @@ +-d:debugConstantine