diff --git a/benchmarks/big_to_fq.nim b/benchmarks/big_to_fq.nim new file mode 100644 index 0000000..cbd1663 --- /dev/null +++ b/benchmarks/big_to_fq.nim @@ -0,0 +1,48 @@ +# 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. + +# ############################################################ +# +# Benchmark of the conversion from Big Int to Fq +# +# ############################################################ + +# 2 implementations are possible +# - 1 based on Montgomery Multiplication +# - 1 based on modular left shift which involves multiple divisions + +import + ../constantine/config/[common, curves], + ../constantine/math/[bigints_checked, finite_fields], + random, std/monotimes, times, strformat + +const Iters = 1_000_000 + +randomize(1234) + +proc main() = + var x: BigInt[381] + x.setInternalBitLength() + for i in 0 ..< x.limbs.len - 1: + # Set x to a random value guaranteed below the prime + x.limbs[i] = Word(rand(BaseType.high.int)) + + + let start = getMonotime() + for _ in 0 ..< Iters: + let y = Fq[BLS12_381].fromBig(x) + let stop = getMonotime() + + echo &"Time for {Iters} iterations: {inMilliseconds(stop-start)} ms" + + +main() +# 1_000_000 iterations with -d:danger on i9-9980XE all-core turbo 4.1GHz +# Montgomery Multiplication based: 254ms +# shlAddMod based (using assembly div2n1n!!): 907 ms +# Note: shlAddMod will be even slower when division is made constant-time diff --git a/constantine/math/bigints_checked.nim b/constantine/math/bigints_checked.nim index 9481d35..a37e4a4 100644 --- a/constantine/math/bigints_checked.nim +++ b/constantine/math/bigints_checked.nim @@ -120,14 +120,7 @@ func unsafeMontyResidue*[mBits](mres: var BigInt[mBits], a, N, r2modN: BigInt[mB ## Caller must take care of properly switching between ## the natural and montgomery domain. ## Nesting Montgomery form is possible by applying this function twice. - # TODO: benchmark - when true: - # Montgomery multiplication based - montyResidue(mres.view, a.view, N.view, r2modN.view, Word(negInvModWord)) - else: - # Modular left shift based - mres = a - montyResidue(mres.view, N.view) + montyResidue(mres.view, a.view, N.view, r2modN.view, Word(negInvModWord)) func unsafeRedc*[mBits](mres: var BigInt[mBits], N: BigInt[mBits], negInvModWord: static BaseType) = ## Convert a BigInt from its Montgomery n-residue form diff --git a/constantine/math/finite_fields.nim b/constantine/math/finite_fields.nim index 48f4311..8f996db 100644 --- a/constantine/math/finite_fields.nim +++ b/constantine/math/finite_fields.nim @@ -49,11 +49,11 @@ debug: # # ############################################################ -func fromBig*(T: type Fq, src: BigInt): T = +func fromBig*[C: static Curve](T: type Fq[C], src: BigInt): Fq[C] {.noInit.} = ## Convert a BigInt to its Montgomery form - result.mres.unsafeMontyResidue(src, Fq.C.Mod.mres, Fq.C.getR2modP(), Fq.C.getNegInvModWord()) + result.mres.unsafeMontyResidue(src, C.Mod.mres, C.getR2modP(), C.getNegInvModWord()) -func toBig*(src: Fq): auto = +func toBig*(src: Fq): auto {.noInit.} = ## Convert a finite-field element to a BigInt in natral representation result = src.mres result.unsafeRedC(Fq.C.Mod.mres, Fq.C.getNegInvModWord())