diff --git a/bncurve.nimble b/bncurve.nimble index d013f12..1941738 100644 --- a/bncurve.nimble +++ b/bncurve.nimble @@ -8,7 +8,8 @@ skipDirs = @["tests", "Nim", "nim"] ### Dependencies requires "nim >= 1.6.0", - "nimcrypto" + "nimcrypto", + "stint" task test, "Run all tests": for tprog in @[ diff --git a/bncurve/arith.nim b/bncurve/arith.nim index ffaf167..f87599b 100644 --- a/bncurve/arith.nim +++ b/bncurve/arith.nim @@ -10,7 +10,22 @@ import options, endians import nimcrypto/[utils, sysrand] export options -{.deadCodeElim: on.} +# TODO replace private stint operations with an integer primitive library +import stint/private/datatypes + +when sizeof(int) == 4: + import stint/private/primitives/compiletime_fallback + + # TODO a future intops library should expose this on 32-bit platforms too! + func addC*(cOut: var Carry, sum: var uint64, a, b: uint64, cIn: Carry) {.inline.} = + addC_nim(cOut, sum, a, b, cIn) + func subB*(bOut: var Borrow, diff: var uint64, a, b: uint64, bIn: Borrow) {.inline.} = + subB_nim(bOut, diff, a, b, bIn) + proc muladd2(hi, lo: var uint64, a, b, c1, c2: uint64) = + muladd2_nim(hi, lo, a, b, c1, c2) + +else: + import stint/private/primitives/[addcarry_subborrow, extended_precision] type BNU256* = array[4, uint64] @@ -68,16 +83,7 @@ proc getBit*(a: openArray[uint64], n: int): bool {.inline, noinit.} = let bit = n - (part shl 6) result = ((a[part] and (1'u64 shl bit)) != 0) -template splitU64(n: uint64, hi, lo: untyped) = - ## Split 64bit unsigned integer to 32bit parts - hi = n shr 32 - lo = n and 0xFFFF_FFFF'u64 - -template combineU64(hi, lo: untyped): uint64 = - ## Combine 64bit unsigned integer from 32bit parts - (hi shl 32) or lo - -proc div2*(a: var BNU256) {.inline.} = +proc div2(a: var BNU256) {.inline.} = ## Divide integer ``a`` in place by ``2``. var t = a[3] shl 63 a[3] = a[3] shr 1 @@ -90,7 +96,7 @@ proc div2*(a: var BNU256) {.inline.} = a[0] = a[0] shr 1 a[0] = a[0] or t -proc mul2*(a: var BNU256) {.inline.} = +proc mul2(a: var BNU256) {.inline.} = ## Multiply integer ``a`` in place by ``2``. var last = 0'u64 for i in a.mitems(): @@ -99,92 +105,42 @@ proc mul2*(a: var BNU256) {.inline.} = i = i or last last = tmp -proc adc(a, b: uint64, carry: var uint64): uint64 {.inline, noinit.} = - ## Calculate ``a + b`` and return result, set ``carry`` to addition - ## operation carry. - var a0, a1, b0, b1, c, r0, r1: uint64 - splitU64(a, a1, a0) - splitU64(b, b1, b0) - let tmp0 = a0 + b0 + carry - splitU64(tmp0, c, r0) - let tmp1 = a1 + b1 + c - splitU64(tmp1, c, r1) - carry = c - result = combineU64(r1, r0) - -proc addNoCarry*(a: var BNU256, b: BNU256) {.inline.} = +proc addNoCarry(a: var BNU256, b: BNU256) {.inline.} = ## Calculate integer addition ``a = a + b``. - var carry = 0'u64 - a[0] = adc(a[0], b[0], carry) - a[1] = adc(a[1], b[1], carry) - a[2] = adc(a[2], b[2], carry) - a[3] = adc(a[3], b[3], carry) - doAssert(carry == 0) + var carry: Carry + staticFor i, 0, 4: + addC(carry, a[i], a[i], b[i], carry) -proc subNoBorrow*(a: var BNU256, b: BNU256) {.inline.} = +proc subNoBorrow(a: var BNU256, b: BNU256) {.inline.} = ## Calculate integer substraction ``a = a - b``. - proc sbb(a: uint64, b: uint64, - borrow: var uint64): uint64 {.inline, noinit.}= - var a0, a1, b0, b1, t0, r0, r1: uint64 - splitU64(a, a1, a0) - splitU64(b, b1, b0) - let tmp0 = (1'u64 shl 32) + a0 - b0 - borrow - splitU64(tmp0, t0, r0) - let tmp1 = (1'u64 shl 32) + a1 - b1 - uint64(t0 == 0'u64) - splitU64(tmp1, t0, r1) - borrow = uint64(t0 == 0) - result = combineU64(r1, r0) - var borrow = 0'u64 - a[0] = sbb(a[0], b[0], borrow) - a[1] = sbb(a[1], b[1], borrow) - a[2] = sbb(a[2], b[2], borrow) - a[3] = sbb(a[3], b[3], borrow) - doAssert(borrow == 0) - -proc macDigit(acc: var openArray[uint64], pos: int, b: openArray[uint64], - c: uint64) = - proc macWithCarry(a, b, c: uint64, carry: var uint64): uint64 {.noinit.} = - var - bhi, blo, chi, clo, ahi, alo, carryhi, carrylo: uint64 - xhi, xlo, yhi, ylo, zhi, zlo, rhi, rlo: uint64 - splitU64(b, bhi, blo) - splitU64(c, chi, clo) - splitU64(a, ahi, alo) - splitU64(carry, carryhi, carrylo) - splitU64(blo * clo + alo + carrylo, xhi, xlo) - splitU64(blo * chi, yhi, ylo) - splitU64(bhi * clo, zhi, zlo) - splitU64(xhi + ylo + zlo + ahi + carryhi, rhi, rlo) - carry = (bhi * chi) + rhi + yhi + zhi - result = combineU64(rlo, xlo) + var borrow: Borrow + staticFor i, 0, 4: + subB(borrow, a[i], a[i], b[i], borrow) +proc macDigit[N, N2: static int]( + acc: var array[N, uint64], pos: static int, b: array[N2, uint64], c: uint64) = if c == 0'u64: return + var carry = 0'u64 - for i in pos.. i: - result[i] = adc(result[i], c0[i], carry) - elif carry != 0'u64: - result[i] = adc(result[i], 0'u64, carry) + var carry: Carry + staticFor i, 0, len(result): + when len(c0) > i: + addC(carry, result[i], result[i], c0[i], carry) else: - break - doAssert(carry == 0'u64) + addC(carry, result[i], result[i], 0'u64, carry) + + doAssert(carry == 0) proc fromBytes*(dst: var BNU256, src: openArray[byte]): bool = ## Create 256bit integer from big-endian bytes representation ``src``. diff --git a/bncurve/fp.nim b/bncurve/fp.nim index a23bd57..5c7a26b 100644 --- a/bncurve/fp.nim +++ b/bncurve/fp.nim @@ -8,8 +8,6 @@ # those terms. import arith, options -{.deadCodeElim: on.} - template fieldImplementation(finame, fimodulus, firsquared, fircubed, fionep, fiinv: untyped): untyped {.dirty.} = type finame* = distinct BNU256 diff --git a/bncurve/fq12.nim b/bncurve/fq12.nim index 97756f3..d9e1cf2 100644 --- a/bncurve/fq12.nim +++ b/bncurve/fq12.nim @@ -9,8 +9,6 @@ import options import fq6, fq2, fp, arith -{.deadCodeElim: on.} - const frobeniusCoeffsC1: array[4, FQ2] = [ FQ2.one(), FQ2( diff --git a/bncurve/fq2.nim b/bncurve/fq2.nim index 7bad05f..80d57bd 100644 --- a/bncurve/fq2.nim +++ b/bncurve/fq2.nim @@ -9,8 +9,6 @@ import options import fp, arith -{.deadCodeElim: on.} - type FQ2* = object c0*: FQ diff --git a/bncurve/fq6.nim b/bncurve/fq6.nim index f74dc2f..bca4fcd 100644 --- a/bncurve/fq6.nim +++ b/bncurve/fq6.nim @@ -9,8 +9,6 @@ import options import fq2, fp, arith -{.deadCodeElim: on.} - const frobeniusCoeffsC1: array[4, FQ2] = [ FQ2.one(), FQ2(