Pasta / Halo2 MSM bench (#243)

* Pasta bench

* cleanup env variables

* [MSM]: generate benchmark coef-points pairs in parallel

* try to fix windows Ci

* add diagnostic info

* fix old test for new codecs/io primitives

* Ensure the projective point at infinity is not all zeros, but (0, 1, 0)
This commit is contained in:
Mamy Ratsimbazafy 2023-06-04 17:41:54 +02:00 committed by GitHub
parent 1325d249ce
commit 0eba593951
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 250 additions and 278 deletions

View File

@ -160,6 +160,10 @@ jobs:
run: |
sudo dpkg --add-architecture i386
sudo apt-fast update -qq
# Try to fix "E: Unable to correct problems, you have held broken packages."
sudo apt-fast clean
sudo DEBIAN_FRONTEND='noninteractive' apt-fast install \
--no-install-recommends -yq \
gcc-multilib g++-multilib \
@ -216,11 +220,12 @@ jobs:
nimble refresh --verbose -y
nimble install --verbose -y gmp jsony asynctools
- name: Print Nim version
if: runner.os != 'Windows'
- name: Print Nim & compiler versions
shell: bash
# gcc is an alias to Clang on MacOS
run: |
nim -v
gcc -v
- name: Run Constantine tests (UNIX with Assembly)
if: runner.os != 'Windows' && matrix.target.BACKEND == 'ASM'
@ -235,9 +240,9 @@ jobs:
shell: bash
run: |
cd constantine
nimble bindings_no_asm --verbose
CTT_ASM=0 nimble bindings --verbose
nimble test_bindings --verbose
nimble test_parallel_no_asm --verbose
CTT_ASM=0 nimble test_parallel --verbose
- name: Run Constantine tests (Windows with Assembly)
# So "test_bindings" uses C and can find GMP
# but nim-gmp cannot find GMP on Windows CI
@ -255,6 +260,6 @@ jobs:
shell: msys2 {0}
run: |
cd constantine
nimble bindings_no_asm --verbose
CTT_ASM=0 nimble bindings --verbose
nimble test_bindings --verbose
nimble test_parallel_no_gmp_no_asm --verbose
CTT_ASM=0 nimble test_parallel_no_gmp --verbose

View File

@ -60,7 +60,7 @@ echo " release: ", defined(release)
echo " danger: ", defined(danger)
echo " inline assembly: ", UseASM_X86_64
when (sizeof(int) == 4) or defined(Ctt32):
when (sizeof(int) == 4) or defined(CTT_32):
echo "⚠️ Warning: using Constantine with 32-bit limbs"
else:
echo "Using Constantine with 64-bit limbs"

View File

@ -0,0 +1,50 @@
# 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
# Internals
../constantine/math/config/curves,
../constantine/math/arithmetic,
../constantine/math/elliptic/[
ec_shortweierstrass_projective,
ec_shortweierstrass_jacobian],
# Helpers
../helpers/prng_unsafe,
./bench_elliptic_parallel_template
# ############################################################
#
# Benchmark of the G1 group of
# Short Weierstrass elliptic curves
# in (homogeneous) projective coordinates
#
# ############################################################
const Iters = 10_000
const AvailableCurves = [
Pallas, Vesta
]
# const testNumPoints = [10, 100, 1000, 10000, 100000]
# const testNumPoints = [64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072]
const testNumPoints = [1 shl 8, 1 shl 9, 1 shl 10, 1 shl 11, 1 shl 12, 1 shl 13, 1 shl 14, 1 shl 15, 1 shl 16, 1 shl 17, 1 shl 22]
proc main() =
separator()
staticFor i, 0, AvailableCurves.len:
const curve = AvailableCurves[i]
separator()
for numPoints in testNumPoints:
let batchIters = max(1, Iters div numPoints)
msmParallelBench(ECP_ShortW_Jac[Fp[curve], G1], numPoints, batchIters)
separator()
separator()
main()
notes()

View File

@ -0,0 +1 @@
--threads:on

View File

@ -21,7 +21,7 @@ import
ec_multi_scalar_mul_parallel],
../constantine/math/constants/zoo_subgroups,
# Threadpool
../constantine/threadpool/threadpool,
../constantine/threadpool/[threadpool, partitioners],
# Helpers
../helpers/prng_unsafe,
./bench_elliptic_template,
@ -55,12 +55,33 @@ proc msmParallelBench*(EC: typedesc, numPoints: int, iters: int) =
var points = newSeq[ECP_ShortW_Aff[EC.F, EC.G]](numPoints)
var scalars = newSeq[BigInt[bits]](numPoints)
for i in 0 ..< numPoints:
var tmp = rng.random_unsafe(EC)
# Creating millions of points and clearing their cofactor takes a long long time
var tp = Threadpool.new()
proc genCoefPointPairs(rngSeed: uint64, start, len: int, points: ptr ECP_ShortW_Aff[EC.F, EC.G], scalars: ptr BigInt[bits]) {.nimcall.} =
let points = cast[ptr UncheckedArray[ECP_ShortW_Aff[EC.F, EC.G]]](points) # TODO use views to reduce verbosity
let scalars = cast[ptr UncheckedArray[BigInt[bits]]](scalars)
# RNGs are not threadsafe, create a threadlocal one seeded from the global RNG
var threadRng: RngState
threadRng.seed(rngSeed)
for i in start ..< start + len:
var tmp = threadRng.random_unsafe(EC)
tmp.clearCofactor()
points[i].affine(tmp)
scalars[i] = rng.random_unsafe(BigInt[bits])
let chunks = balancedChunksPrioNumber(0, numPoints, tp.numThreads)
syncScope:
for (id, start, size) in items(chunks):
tp.spawn genCoefPointPairs(rng.next(), start, size, points[0].addr, scalars[0].addr)
# Even if child threads are sleeping, it seems like perf is lower when there are threads around
# maybe because the kernel has more overhead or time quantum to keep track off so shut them down.
tp.shutdown()
var r{.noInit.}: EC
var startNaive, stopNaive, startMSMbaseline, stopMSMbaseline, startMSMopt, stopMSMopt, startMSMpara, stopMSMpara: MonoTime
@ -88,7 +109,7 @@ proc msmParallelBench*(EC: typedesc, numPoints: int, iters: int) =
stopMSMopt = getMonotime()
block:
var tp = Threadpool.new()
tp = Threadpool.new()
startMSMpara = getMonotime()
bench("EC multi-scalar-mul" & align($tp.numThreads & " threads", 11) & align($numPoints, 10) & " (" & $bits & "-bit coefs, points)", EC, iters):

View File

@ -45,7 +45,7 @@ macro fixEllipticDisplay(EC: typedesc): untyped =
var name = $instantiated[1][0] # EllipticEquationFormCoordinates
let fieldName = $instantiated[1][1][0]
let curveName = $Curve(instantiated[1][1][1].intVal)
name.add "[" & fieldName & "[" & curveName & ']'
name.add "[" & fieldName & "[" & curveName & "]]"
result = newLit name
proc report(op, elliptic: string, start, stop: MonoTime, startClk, stopClk: int64, iters: int) =

View File

@ -61,7 +61,7 @@ echo " release: ", defined(release)
echo " danger: ", defined(danger)
echo " inline assembly: ", UseASM_X86_64
when (sizeof(int) == 4) or defined(Ctt32):
when (sizeof(int) == 4) or defined(CTT_32):
echo "⚠️ Warning: using Constantine with 32-bit limbs"
else:
echo "Using Constantine with 64-bit limbs"

View File

@ -33,7 +33,7 @@ collectBindings(cBindings):
genBindings_EC_ShortW_NonAffine(bls12381_ec_g2_prj, bls12381_ec_g2_aff, bls12381_fp2)
# Write header
when isMainModule and defined(CttGenerateHeaders):
when isMainModule and defined(CTT_GENERATE_HEADERS):
import std/[os, strformat]
proc main() =

View File

@ -35,7 +35,7 @@ collectBindings(cBindings):
genBindings_EC_ShortW_NonAffine(vesta_ec_prj, vesta_ec_aff, vesta_fp)
# Write header
when isMainModule and defined(CttGenerateHeaders):
when isMainModule and defined(CTT_GENERATE_HEADERS):
import std/[os, strformat]
proc main() =

View File

@ -203,7 +203,7 @@ macro collectBindings*(cBindingsStr: untyped, body: typed): untyped =
cBindings &= ");"
if defined(CttGenerateHeaders):
if defined(CTT_GENERATE_HEADERS):
result = newConstStmt(cBindingsStr, newLit cBindings)
else:
result = body

View File

@ -12,12 +12,60 @@ requires "nim >= 1.6.12"
# Nimscript imports
# ----------------------------------------------------------------
import std/strformat
import std/[strformat, strutils]
# Environment variables
# ----------------------------------------------------------------
#
# Compile-time environment variables
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# - CTT_ASM=0
# Disable assembly backend. Otherwise use ASM for supported CPUs and fallback to generic code otherwise.
#
# Runtime environment variables
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# - CTT_NUM_THREADS=N
# Set the threadpool to N threads. Currently this is only supported in some tests/benchmarks.
# Autodetect the number of threads (including siblings from hyperthreading)
#
# Developer, debug, profiling and metrics environment variables
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# - CTT_32
# Compile Constantine with 32-bit backend. Otherwise autodetect.
#
# - CTT_DEBUG
# Add preconditions, invariants and post-conditions checks.
# This may leak the erroring data. Do not use with secrets.
#
# - CTT_GENERATE_HEADERS
# - CTT_TEST_CURVES
#
# - CTT_THREADPOOL_ASSERTS
# - CTT_THREADPOOL_METRICS
# - CTT_THREADPOOL_PROFILE
#
# - CTT_THREADPOOL_DEBUG
# - CTT_THREADPOOL_DEBUG_SPLIT
# - CTT_THREADPOOL_DEBUG_TERMINATION
proc getEnvVars(): tuple[useAsmIfAble, force32: bool] =
if existsEnv"CTT_ASM":
result.useAsmIfAble = parseBool(getEnv"CTT_ASM")
else:
result.useAsmIfAble = true
if existsEnv"CTT_32":
result.force32 = true
else:
result.force32 = false
# Library compilation
# ----------------------------------------------------------------
proc releaseBuildOptions(useASM, useLTO = true): string =
proc releaseBuildOptions(useLTO = true): string =
# -d:danger --opt:size
# to avoid boundsCheck and overflowChecks that would trigger exceptions or allocations in a crypto library.
# Those are internally guaranteed at compile-time by fixed-sized array
@ -53,14 +101,17 @@ proc releaseBuildOptions(useASM, useLTO = true): string =
let compiler = if existsEnv"CC": " --cc:" & getEnv"CC"
else: ""
let noASM = if not useASM: " -d:CttASM=false "
let (useAsmIfAble, force32) = getEnvVars()
let envASM = if not useAsmIfAble: " -d:CTT_ASM=false "
else: ""
let env32 = if force32: " -d:CTT_32 "
else: ""
let lto = if useLTO: " --passC:-flto=auto --passL:-flto=auto "
else: ""
compiler &
noASM &
envASM & env32 &
lto &
" -d:danger " &
# " --opt:size " &
@ -74,13 +125,13 @@ type BindingsKind = enum
kCurve
kProtocol
proc genDynamicBindings(bindingsKind: BindingsKind, bindingsName, prefixNimMain: string, useASM = true) =
proc genDynamicBindings(bindingsKind: BindingsKind, bindingsName, prefixNimMain: string) =
proc compile(libName: string, flags = "") =
echo "Compiling dynamic library: lib/" & libName
exec "nim c " &
flags &
releaseBuildOptions(useASM, useLTO = true) &
releaseBuildOptions(useLTO = true) &
" --noMain --app:lib " &
&" --nimMainPrefix:{prefixNimMain} " &
&" --out:{libName} --outdir:lib " &
@ -111,13 +162,13 @@ proc genDynamicBindings(bindingsKind: BindingsKind, bindingsName, prefixNimMain:
else:
compile "lib" & bindingsName & ".so"
proc genStaticBindings(bindingsKind: BindingsKind, bindingsName, prefixNimMain: string, useASM = true) =
proc genStaticBindings(bindingsKind: BindingsKind, bindingsName, prefixNimMain: string) =
proc compile(libName: string, flags = "") =
echo "Compiling static library: lib/" & libName
exec "nim c " &
flags &
releaseBuildOptions(useASM, useLTO = false) &
releaseBuildOptions(useLTO = false) &
" --noMain --app:staticLib " &
&" --nimMainPrefix:{prefixNimMain} " &
&" --out:{libName} --outdir:lib " &
@ -150,7 +201,7 @@ proc genStaticBindings(bindingsKind: BindingsKind, bindingsName, prefixNimMain:
proc genHeaders(bindingsName: string) =
echo "Generating header: include/" & bindingsName & ".h"
exec "nim c -d:CttGenerateHeaders " &
exec "nim c -d:CTT_GENERATE_HEADERS " &
" -d:release " &
" --verbosity:0 --hints:off --warnings:off " &
" --out:" & bindingsName & "_gen_header.exe --outdir:build " &
@ -158,7 +209,7 @@ proc genHeaders(bindingsName: string) =
" bindings_generators/" & bindingsName & ".nim"
exec "build/" & bindingsName & "_gen_header.exe include"
task bindings, "Generate Constantine bindings (no assembly)":
task bindings, "Generate Constantine bindings":
# Curve arithmetic
genStaticBindings(kCurve, "constantine_bls12_381", "ctt_bls12381_init_")
genDynamicBindings(kCurve, "constantine_bls12_381", "ctt_bls12381_init_")
@ -174,22 +225,6 @@ task bindings, "Generate Constantine bindings (no assembly)":
genDynamicBindings(kProtocol, "ethereum_bls_signatures", "ctt_eth_bls_init_")
echo ""
task bindings_no_asm, "Generate Constantine bindings (no assembly)":
# Curve arithmetic
genStaticBindings(kCurve, "constantine_bls12_381", "ctt_bls12381_init_", useASM = false)
genDynamicBindings(kCurve, "constantine_bls12_381", "ctt_bls12381_init_", useASM = false)
genHeaders("constantine_bls12_381")
echo ""
genStaticBindings(kCurve, "constantine_pasta", "ctt_pasta_init_", useASM = false)
genDynamicBindings(kCurve, "constantine_pasta", "ctt_pasta_init_", useASM = false)
genHeaders("constantine_pasta")
echo ""
# Protocols
genStaticBindings(kProtocol, "ethereum_bls_signatures", "ctt_eth_bls_init_", useASM = false)
genDynamicBindings(kProtocol, "ethereum_bls_signatures", "ctt_eth_bls_init_", useASM = false)
echo ""
proc testLib(path, testName, libName: string, useGMP: bool) =
let dynlibName = if defined(windows): libName & ".dll"
elif defined(macosx): "lib" & libName & ".dylib"
@ -310,17 +345,17 @@ const testDesc: seq[tuple[path: string, useGMP: bool]] = @[
# Elliptic curve arithmetic
# ----------------------------------------------------------
# ("tests/math_elliptic_curves/t_ec_conversion.nim", false),
("tests/math_elliptic_curves/t_ec_conversion.nim", false),
# Elliptic curve arithmetic G1
# ----------------------------------------------------------
# ("tests/math_elliptic_curves/t_ec_shortw_prj_g1_add_double.nim", false),
("tests/math_elliptic_curves/t_ec_shortw_prj_g1_add_double.nim", false),
# ("tests/math_elliptic_curves/t_ec_shortw_prj_g1_mul_sanity.nim", false),
# ("tests/math_elliptic_curves/t_ec_shortw_prj_g1_mul_distri.nim", false),
("tests/math_elliptic_curves/t_ec_shortw_prj_g1_mul_vs_ref.nim", false),
# ("tests/math_elliptic_curves/t_ec_shortw_prj_g1_mixed_add.nim", false),
# ("tests/math_elliptic_curves/t_ec_shortw_jac_g1_add_double.nim", false),
("tests/math_elliptic_curves/t_ec_shortw_jac_g1_add_double.nim", false),
# ("tests/math_elliptic_curves/t_ec_shortw_jac_g1_mul_sanity.nim", false),
# ("tests/math_elliptic_curves/t_ec_shortw_jac_g1_mul_distri.nim", false),
("tests/math_elliptic_curves/t_ec_shortw_jac_g1_mul_vs_ref.nim", false),
@ -561,7 +596,7 @@ proc clearParallelBuild() =
if fileExists(buildParallel):
rmFile(buildParallel)
proc setupTestCommand(flags, path: string, useASM: bool): string =
proc setupTestCommand(flags, path: string): string =
var lang = "c"
if existsEnv"TEST_LANG":
lang = getEnv"TEST_LANG"
@ -569,7 +604,7 @@ proc setupTestCommand(flags, path: string, useASM: bool): string =
return "nim " & lang &
" -r " &
flags &
releaseBuildOptions(useASM) &
releaseBuildOptions() &
" --outdir:build/testsuite " &
&" --nimcache:nimcache/{path} " &
path
@ -580,21 +615,20 @@ proc test(cmd: string) =
echo "=============================================================================================="
exec cmd
proc testBatch(commands: var string, flags, path: string, useASM = true) =
proc testBatch(commands: var string, flags, path: string) =
# With LTO, the linker produces lots of spurious warnings when copying into openArrays/strings
let flags = if defined(gcc): flags & " --passC:-Wno-stringop-overflow --passL:-Wno-stringop-overflow "
else: flags
commands = commands & setupTestCommand(flags, path, useASM) & '\n'
commands = commands & setupTestCommand(flags, path) & '\n'
proc setupBench(benchName: string, run: bool, useAsm: bool): string =
proc setupBench(benchName: string, run: bool): string =
var runFlags = " "
if run: # Beware of https://github.com/nim-lang/Nim/issues/21704
runFlags = runFlags & " -r "
let asmStatus = if useASM: "useASM"
else: "noASM"
let asmStatus = if getEnvVars().useAsmIfAble: "asmIfAvailable" else: "noAsm"
if defined(gcc):
# With LTO, the linker produces lots of spurious warnings when copying into openArrays/strings
@ -605,22 +639,22 @@ proc setupBench(benchName: string, run: bool, useAsm: bool): string =
return "nim c " &
runFlags &
releaseBuildOptions(useASM) &
releaseBuildOptions() &
&" -o:build/bench/{benchName}_{cc}_{asmStatus}" &
&" --nimcache:nimcache/benches/{benchName}_{cc}_{asmStatus}" &
&" benchmarks/{benchName}.nim"
proc runBench(benchName: string, useAsm = true) =
proc runBench(benchName: string) =
if not dirExists "build":
mkDir "build"
let command = setupBench(benchName, run = true, useAsm)
let command = setupBench(benchName, run = true)
exec command
proc buildBenchBatch(commands: var string, benchName: string, useAsm = true) =
let command = setupBench(benchName, run = false, useAsm)
proc buildBenchBatch(commands: var string, benchName: string) =
let command = setupBench(benchName, run = false)
commands = commands & command & '\n'
proc addTestSet(cmdFile: var string, requireGMP: bool, test32bit = false, useASM = true) =
proc addTestSet(cmdFile: var string, requireGMP: bool) =
if not dirExists "build":
mkDir "build"
echo "Found " & $testDesc.len & " tests to run."
@ -628,14 +662,12 @@ proc addTestSet(cmdFile: var string, requireGMP: bool, test32bit = false, useASM
for td in testDesc:
if not(td.useGMP and not requireGMP):
var flags = "" # Beware of https://github.com/nim-lang/Nim/issues/21704
if test32bit:
flags = flags & " -d:Ctt32 "
if td.path in useDebug:
flags = flags & " -d:CttDebug "
flags = flags & " -d:CTT_DEBUG "
if td.path notin skipSanitizers:
flags = flags & sanitizers
cmdFile.testBatch(flags, td.path, useASM)
cmdFile.testBatch(flags, td.path)
proc addTestSetNvidia(cmdFile: var string) =
if not dirExists "build":
@ -659,28 +691,26 @@ proc addTestSetThreadpool(cmdFile: var string) =
flags = flags & sanitizers
cmdFile.testBatch(flags, path)
proc addTestSetMultithreadedCrypto(cmdFile: var string, test32bit = false, useASM = true) =
proc addTestSetMultithreadedCrypto(cmdFile: var string) =
if not dirExists "build":
mkDir "build"
echo "Found " & $testDescMultithreadedCrypto.len & " tests to run."
for td in testDescMultithreadedCrypto:
var flags = " --threads:on --debugger:native"
if test32bit:
flags = flags & " -d:Ctt32 "
if td in useDebug:
flags = flags & " -d:CttDebug "
flags = flags & " -d:CTT_DEBUG "
if td notin skipSanitizers:
flags = flags & sanitizers
cmdFile.testBatch(flags, td, useASM)
cmdFile.testBatch(flags, td)
proc addBenchSet(cmdFile: var string, useAsm = true) =
proc addBenchSet(cmdFile: var string) =
if not dirExists "build":
mkDir "build"
echo "Found " & $benchDesc.len & " benches to compile. (compile-only to ensure they stay relevant)"
for bd in benchDesc:
cmdFile.buildBenchBatch(bd, useASM = useASM)
cmdFile.buildBenchBatch(bd)
proc genParallelCmdRunner() =
exec "nim c --verbosity:0 --hints:off --warnings:off -d:release --out:build/pararun --nimcache:nimcache/pararun helpers/pararun.nim"
@ -689,57 +719,35 @@ proc genParallelCmdRunner() =
# ----------------------------------------------------------------
task test, "Run all tests":
# -d:testingCurves is configured in a *.nim.cfg for convenience
# -d:CTT_TEST_CURVES is configured in a *.nim.cfg for convenience
var cmdFile: string
cmdFile.addTestSet(requireGMP = true, useASM = true)
cmdFile.addBenchSet(useASM = true) # Build (but don't run) benches to ensure they stay relevant
cmdFile.addTestSet(requireGMP = true)
cmdFile.addBenchSet() # Build (but don't run) benches to ensure they stay relevant
cmdFile.addTestSetThreadpool()
cmdFile.addTestSetMultithreadedCrypto()
for cmd in cmdFile.splitLines():
if cmd != "": # Windows doesn't like empty commands
exec cmd
task test_no_asm, "Run all tests (no assembly)":
# -d:testingCurves is configured in a *.nim.cfg for convenience
var cmdFile: string
cmdFile.addTestSet(requireGMP = true, useASM = false)
cmdFile.addBenchSet(useASM = false) # Build (but don't run) benches to ensure they stay relevant
cmdFile.addTestSetThreadpool()
cmdFile.addTestSetMultithreadedCrypto(useASM = false)
for cmd in cmdFile.splitLines():
if cmd != "": # Windows doesn't like empty commands
exec cmd
task test_no_gmp, "Run tests that don't require GMP":
# -d:testingCurves is configured in a *.nim.cfg for convenience
# -d:CTT_TEST_CURVES is configured in a *.nim.cfg for convenience
var cmdFile: string
cmdFile.addTestSet(requireGMP = false, useASM = true)
cmdFile.addBenchSet(useASM = true) # Build (but don't run) benches to ensure they stay relevant
cmdFile.addTestSet(requireGMP = false)
cmdFile.addBenchSet() # Build (but don't run) benches to ensure they stay relevant
cmdFile.addTestSetThreadpool()
cmdFile.addTestSetMultithreadedCrypto()
for cmd in cmdFile.splitLines():
if cmd != "": # Windows doesn't like empty commands
exec cmd
task test_no_gmp_no_asm, "Run tests that don't require GMP using a pure Nim backend":
# -d:testingCurves is configured in a *.nim.cfg for convenience
var cmdFile: string
cmdFile.addTestSet(requireGMP = false, useASM = false)
cmdFile.addBenchSet(useASM = false) # Build (but don't run) benches to ensure they stay relevant
cmdFile.addTestSetThreadpool()
cmdFile.addTestSetMultithreadedCrypto(useASM = false)
for cmd in cmdFile.splitLines():
if cmd != "": # Windows doesn't like empty commands
exec cmd
task test_parallel, "Run all tests in parallel":
# -d:testingCurves is configured in a *.nim.cfg for convenience
# -d:CTT_TEST_CURVES is configured in a *.nim.cfg for convenience
clearParallelBuild()
genParallelCmdRunner()
var cmdFile: string
cmdFile.addTestSet(requireGMP = true, useASM = true)
cmdFile.addBenchSet(useASM = true) # Build (but don't run) benches to ensure they stay relevant
cmdFile.addTestSet(requireGMP = true)
cmdFile.addBenchSet() # Build (but don't run) benches to ensure they stay relevant
writeFile(buildParallel, cmdFile)
exec "build/pararun " & buildParallel
@ -751,33 +759,14 @@ task test_parallel, "Run all tests in parallel":
if cmd != "": # Windows doesn't like empty commands
exec cmd
task test_parallel_no_asm, "Run all tests (without macro assembler) in parallel":
# -d:testingCurves is configured in a *.nim.cfg for convenience
task test_parallel_no_gmp, "Run in parallel tests that don't require GMP":
# -d:CTT_TEST_CURVES is configured in a *.nim.cfg for convenience
clearParallelBuild()
genParallelCmdRunner()
var cmdFile: string
cmdFile.addTestSet(requireGMP = true, useASM = false)
cmdFile.addBenchSet(useASM = false)
writeFile(buildParallel, cmdFile)
exec "build/pararun " & buildParallel
# Threadpool tests done serially
cmdFile = ""
cmdFile.addTestSetThreadpool()
cmdFile.addTestSetMultithreadedCrypto(useASM = false)
for cmd in cmdFile.splitLines():
if cmd != "": # Windows doesn't like empty commands
exec cmd
task test_parallel_no_gmp, "Run all tests in parallel":
# -d:testingCurves is configured in a *.nim.cfg for convenience
clearParallelBuild()
genParallelCmdRunner()
var cmdFile: string
cmdFile.addTestSet(requireGMP = false, useASM = true)
cmdFile.addBenchSet(useASM = true) # Build (but don't run) benches to ensure they stay relevant
cmdFile.addTestSet(requireGMP = false)
cmdFile.addBenchSet() # Build (but don't run) benches to ensure they stay relevant
writeFile(buildParallel, cmdFile)
exec "build/pararun " & buildParallel
@ -789,25 +778,6 @@ task test_parallel_no_gmp, "Run all tests in parallel":
if cmd != "": # Windows doesn't like empty commands
exec cmd
task test_parallel_no_gmp_no_asm, "Run all tests in parallel":
# -d:testingCurves is configured in a *.nim.cfg for convenience
clearParallelBuild()
genParallelCmdRunner()
var cmdFile: string
cmdFile.addTestSet(requireGMP = false, useASM = false)
cmdFile.addBenchSet(useASM = false) # Build (but don't run) benches to ensure they stay relevant
writeFile(buildParallel, cmdFile)
exec "build/pararun " & buildParallel
# Threadpool tests done serially
cmdFile = ""
cmdFile.addTestSetThreadpool()
cmdFile.addTestSetMultithreadedCrypto(useASM = false)
for cmd in cmdFile.splitLines():
if cmd != "": # Windows doesn't like empty commands
exec cmd
task test_threadpool, "Run all tests for the builtin threadpool":
var cmdFile: string
cmdFile.addTestSetThreadpool()
@ -841,197 +811,125 @@ task bench_powmod, "Run modular exponentiation benchmark with your CC compiler":
task bench_fp, "Run benchmark 𝔽p with your CC compiler":
runBench("bench_fp")
task bench_fp_noasm, "Run benchmark 𝔽p with your CC compiler - no Assembly":
runBench("bench_fp", useAsm = false)
# Double-precision field 𝔽pDbl
# ------------------------------------------
task bench_fpdbl, "Run benchmark 𝔽pDbl with your CC compiler":
runBench("bench_fp_double_precision")
task bench_fpdbl_noasm, "Run benchmark 𝔽p with CC compiler - no Assembly":
runBench("bench_fp_double_precision", useAsm = false)
# Extension field 𝔽p2
# ------------------------------------------
task bench_fp2, "Run benchmark 𝔽p2 with your CC compiler":
runBench("bench_fp2")
task bench_fp2_noasm, "Run benchmark 𝔽p2 with CC compiler - no Assembly":
runBench("bench_fp2", useAsm = false)
# Extension field 𝔽p4
# ------------------------------------------
task bench_fp4, "Run benchmark 𝔽p4 with your CC compiler":
runBench("bench_fp4")
task bench_fp4_noasm, "Run benchmark 𝔽p4 with CC compiler - no Assembly":
runBench("bench_fp4", useAsm = false)
# Extension field 𝔽p6
# ------------------------------------------
task bench_fp6, "Run benchmark 𝔽p6 with your CC compiler":
runBench("bench_fp6")
task bench_fp6_noasm, "Run benchmark 𝔽p6 with CC compiler - no Assembly":
runBench("bench_fp6", useAsm = false)
# Extension field 𝔽p12
# ------------------------------------------
task bench_fp12, "Run benchmark 𝔽p12 with your CC compiler":
runBench("bench_fp12")
task bench_fp12_noasm, "Run benchmark 𝔽p12 with CC compiler - no Assembly":
runBench("bench_fp12", useAsm = false)
# Elliptic curve G1
# ------------------------------------------
task bench_ec_g1, "Run benchmark on Elliptic Curve group 𝔾1 - CC compiler":
runBench("bench_ec_g1")
task bench_ec_g1_noasm, "Run benchmark on Elliptic Curve group 𝔾1 - CC compiler no Assembly":
runBench("bench_ec_g1", useAsm = false)
# Elliptic curve G1 - batch operations
# ------------------------------------------
task bench_ec_g1_batch, "Run benchmark on Elliptic Curve group 𝔾1 (batch ops) - CC compiler":
runBench("bench_ec_g1_batch")
task bench_ec_g1_batch_noasm, "Run benchmark on Elliptic Curve group 𝔾1 (batch ops) - CC compiler no Assembly":
runBench("bench_ec_g1_batch", useAsm = false)
# Elliptic curve G1 - scalar multiplication
# ------------------------------------------
task bench_ec_g1_scalar_mul, "Run benchmark on Elliptic Curve group 𝔾1 (Scalar Multiplication) - CC compiler":
runBench("bench_ec_g1_scalar_mul")
task bench_ec_g1_scalar_mul_noasm, "Run benchmark on Elliptic Curve group 𝔾1 (Scalar Multiplication) - CC compiler no Assembly":
runBench("bench_ec_g1_scalar_mul", useAsm = false)
# Elliptic curve G1 - Multi-scalar-mul
# ------------------------------------------
task bench_ec_g1_msm_pasta, "Run benchmark on Elliptic Curve group 𝔾1 (Multi-Scalar-Mul) for Pasta curves - CC compiler":
runBench("bench_ec_g1_msm_pasta")
task bench_ec_g1_msm_bn254_snarks, "Run benchmark on Elliptic Curve group 𝔾1 (Multi-Scalar-Mul) for BN254-Snarks - CC compiler":
runBench("bench_ec_g1_msm_bn254_snarks")
task bench_ec_g1_msm_bn254_snarks_noasm, "Run benchmark on Elliptic Curve group 𝔾1 (Multi-Scalar-Mul) for BN254-Snarks - CC compiler no Assembly":
runBench("bench_ec_g1_msm_bn254_snarks", useAsm = false)
task bench_ec_g1_msm_bls12_381, "Run benchmark on Elliptic Curve group 𝔾1 (Multi-Scalar-Mul) for BLS12-381 - CC compiler":
runBench("bench_ec_g1_msm_bls12_381")
task bench_ec_g1_msm_bls12_381_noasm, "Run benchmark on Elliptic Curve group 𝔾1 (Multi-Scalar-Mul) for BLS12-381 - CC compiler no Assembly":
runBench("bench_ec_g1_msm_bls12_381", useAsm = false)
# Elliptic curve G2
# ------------------------------------------
task bench_ec_g2, "Run benchmark on Elliptic Curve group 𝔾2 - CC compiler":
runBench("bench_ec_g2")
task bench_ec_g2_noasm, "Run benchmark on Elliptic Curve group 𝔾2 - CC compiler no Assembly":
runBench("bench_ec_g2", useAsm = false)
# Elliptic curve G2 - scalar multiplication
# ------------------------------------------
task bench_ec_g2_scalar_mul, "Run benchmark on Elliptic Curve group 𝔾2 (Multi-Scalar-Mul) - CC compiler":
runBench("bench_ec_g2_scalar_mul")
task bench_ec_g2_scalar_mul_noasm, "Run benchmark on Elliptic Curve group 𝔾2 (Multi-Scalar-Mul) - CC compiler no Assembly":
runBench("bench_ec_g2_scalar_mul", useAsm = false)
# Pairings
# ------------------------------------------
task bench_pairing_bls12_377, "Run pairings benchmarks for BLS12-377 - CC compiler":
runBench("bench_pairing_bls12_377")
task bench_pairing_bls12_377_noasm, "Run pairings benchmarks for BLS12-377 - CC compiler no Assembly":
runBench("bench_pairing_bls12_377", useAsm = false)
# --
task bench_pairing_bls12_381, "Run pairings benchmarks for BLS12-381 - CC compiler":
runBench("bench_pairing_bls12_381")
task bench_pairing_bls12_381_noasm, "Run pairings benchmarks for BLS12-381 - CC compiler no Assembly":
runBench("bench_pairing_bls12_381", useAsm = false)
# --
task bench_pairing_bn254_nogami, "Run pairings benchmarks for BN254-Nogami - CC compiler":
runBench("bench_pairing_bn254_nogami")
task bench_pairing_bn254_nogami_noasm, "Run pairings benchmarks for BN254-Nogami - CC compiler no Assembly":
runBench("bench_pairing_bn254_nogami", useAsm = false)
# --
task bench_pairing_bn254_snarks, "Run pairings benchmarks for BN254-Snarks - CC compiler":
runBench("bench_pairing_bn254_snarks")
task bench_pairing_bn254_snarks_noasm, "Run pairings benchmarks for BN254-Snarks - CC compiler no Assembly":
runBench("bench_pairing_bn254_snarks", useAsm = false)
# Curve summaries
# ------------------------------------------
task bench_summary_bls12_377, "Run summary benchmarks for BLS12-377 - CC compiler":
runBench("bench_summary_bls12_377")
task bench_summary_bls12_377_noasm, "Run summary benchmarks for BLS12-377 - CC compiler no Assembly":
runBench("bench_summary_bls12_377", useAsm = false)
# --
task bench_summary_bls12_381, "Run summary benchmarks for BLS12-381 - CC compiler":
runBench("bench_summary_bls12_381")
task bench_summary_bls12_381_noasm, "Run summary benchmarks for BLS12-381 - CC compiler no Assembly":
runBench("bench_summary_bls12_381", useAsm = false)
# --
task bench_summary_bn254_nogami, "Run summary benchmarks for BN254-Nogami - CC compiler":
runBench("bench_summary_bn254_nogami")
task bench_summary_bn254_nogami_noasm, "Run summary benchmarks for BN254-Nogami - CC compiler no Assembly":
runBench("bench_summary_bn254_nogami", useAsm = false)
# --
task bench_summary_bn254_snarks, "Run summary benchmarks for BN254-Snarks - CC compiler":
runBench("bench_summary_bn254_snarks")
task bench_summary_bn254_snarks_noasm, "Run summary benchmarks for BN254-Snarks - CC compiler no Assembly":
runBench("bench_summary_bn254_snarks", useAsm = false)
# --
task bench_summary_pasta, "Run summary benchmarks for the Pasta curves - CC compiler":
runBench("bench_summary_pasta")
task bench_summary_pasta_noasm, "Run summary benchmarks for the Pasta curves - CC compiler no Assembly":
runBench("bench_summary_pasta", useAsm = false)
# Hashes
# ------------------------------------------
@ -1043,13 +941,7 @@ task bench_sha256, "Run SHA256 benchmarks":
task bench_hash_to_curve, "Run Hash-to-Curve benchmarks":
runBench("bench_hash_to_curve")
task bench_hash_to_curve_noasm, "Run Hash-to-Curve benchmarks - No Assembly":
runBench("bench_hash_to_curve", useAsm = false)
# BLS signatures
# ------------------------------------------
task bench_ethereum_bls_signatures, "Run Ethereum BLS signatures benchmarks - CC compiler":
runBench("bench_ethereum_bls_signatures")
task bench_ethereum_bls_signatures_noasm, "Run Ethereum BLS signatures benchmarks - CC compiler no assembly":
runBench("bench_ethereum_bls_signatures", useAsm = false)

View File

@ -41,7 +41,7 @@ export CurveFamily, SexticTwist
declareCurves:
# -----------------------------------------------------------------------------
# Curves added when passed "-d:testingCurves"
# Curves added when passed "-d:CTT_TEST_CURVES"
curve Fake101:
testingCurve: true
bitwidth: 7

View File

@ -159,7 +159,7 @@ proc parseCurveDecls*(defs: var seq[CurveParams], curves: NimNode) =
offset = 1
testCurve = curveParams[0][1].boolVal
if testCurve and defined(testingCurves):
if testCurve and defined(CTT_TEST_CURVES):
continue
# Parameters

View File

@ -139,5 +139,5 @@ macro debugConsts(): untyped {.used.} =
result.add quote do:
echo "----------------------------------------------------------------------------"
# debug: # displayed with -d:CttDebug
# debug: # displayed with -d:CTT_DEBUG
# debugConsts()

View File

@ -43,8 +43,10 @@ func isInf*(P: ECP_ShortW_Jac): SecretBool {.inline.} =
##
## Note: the jacobian coordinates equation is
## Y² = X³ + aXZ⁴ + bZ⁶
## A "zero" point is any point with coordinates X and Z = 0
## Y can be anything
##
## When Z = 0 in the equation, it reduces to
## Y² = X³
## (yZ³)² = (xZ²)³ which is true for any x, y coordinates
result = P.z.isZero()
func setInf*(P: var ECP_ShortW_Jac) {.inline.} =

View File

@ -457,4 +457,5 @@ func fromAffine*[F, G](
let inf = aff.isInf()
proj.x.csetZero(inf)
proj.y.csetOne(inf)
proj.z.csetZero(inf)

View File

@ -19,8 +19,8 @@ export primitives, tracer
# ------------------------------------------------------------
const CttASM {.booldefine.} = true
const UseASM_X86_32* = CttASM and X86 and GCC_Compatible
const CTT_ASM {.booldefine.} = true
const UseASM_X86_32* = CTT_ASM and X86 and GCC_Compatible
const UseASM_X86_64* = sizeof(pointer)*8 == 64 and UseASM_X86_32
# We use Nim effect system to track vartime subroutines
@ -32,7 +32,7 @@ type VarTime* = object
#
# ############################################################
when sizeof(int) == 8 and not defined(Ctt32):
when sizeof(int) == 8 and not defined(CTT_32):
type
BaseType* = uint64
## Physical BigInt for conversion in "normal integers"
@ -121,7 +121,7 @@ debug: # Don't allow printing secret words by default
type SignedSecretWord* = distinct SecretWord
when sizeof(int) == 8 and not defined(Ctt32):
when sizeof(int) == 8 and not defined(CTT_32):
type
SignedBaseType* = int64
else:

View File

@ -48,7 +48,7 @@ type
# Clobbered register
ClobberedReg
when sizeof(int) == 8 and not defined(Ctt32):
when sizeof(int) == 8 and not defined(CTT_32):
type
Register* = enum
rbx

View File

@ -53,7 +53,7 @@ when X86 and GCC_Compatible:
# ############################################################
template debug*(body: untyped): untyped =
when defined(CttDebug):
when defined(CTT_DEBUG):
body
proc builtin_unreachable(){.nodecl, importc: "__builtin_unreachable".}

View File

@ -187,7 +187,7 @@ proc newSpawn*(
result.hasFuture = false
result.fn = fn
when defined(TP_Metrics):
when defined(CTT_THREADPOOL_METRICS):
result.loopStepsLeft = NotALoop
proc newSpawn*(
@ -210,7 +210,7 @@ proc newSpawn*(
result.fn = fn
cast[ptr[type env]](result.env)[] = env
when defined(TP_Metrics):
when defined(CTT_THREADPOOL_METRICS):
result.loopStepsLeft = NotALoop
func ceilDiv_vartime(a, b: auto): auto {.inline.} =

View File

@ -15,15 +15,15 @@ template log*(args: varargs[untyped]): untyped =
flushFile(stdout)
template debugSplit*(body: untyped): untyped =
when defined(TP_DebugSplit) or defined(TP_Debug):
when defined(CTT_THREADPOOL_DEBUG_SPLIT) or defined(CTT_THREADPOOL_DEBUG):
{.noSideEffect, gcsafe.}: body
template debugTermination*(body: untyped): untyped =
when defined(TP_DebugTermination) or defined(TP_Debug):
when defined(CTT_THREADPOOL_DEBUG_TERMINATION) or defined(CTT_THREADPOOL_DEBUG):
{.noSideEffect, gcsafe.}: body
template debug*(body: untyped): untyped =
when defined(TP_Debug):
when defined(CTT_THREADPOOL_DEBUG):
{.noSideEffect, gcsafe.}: body
# --------------------------------------------------------
@ -34,7 +34,7 @@ import std/macros
# --------------------------------------------------------
# Everything should be a template that doesn't produce any code
# when CttDebug is not defined.
# when CTT_DEBUG is not defined.
# Those checks are controlled by a custom flag instead of
# "--boundsChecks" or "--nilChecks" to decouple them from user code checks.
# Furthermore, we want them to be very lightweight on performance
@ -118,7 +118,7 @@ macro assertContract(
{.noSideEffect.}:
when compileOption("assertions"):
assert(`predicate`, `debug` & $`values` & " [Worker " & `workerID` & " on threadpool " & `threadpoolID` & "]\n")
elif defined(TP_Asserts):
elif defined(CTT_THREADPOOL_ASSERTS):
if unlikely(not(`predicate`)):
raise newException(AssertionError, `debug` & $`values` & " [Worker " & `workerID` & " on threadpool " & `threadpoolID` & "]\n")
@ -162,7 +162,7 @@ macro getCounter*(counters: untyped, counterField: static string): untyped =
# Profiling
# ----------------------------------------------------------------------------------
when defined(TP_Profile):
when defined(CTT_THREADPOOL_PROFILE):
import ./primitives/timers
# On windows and Mac, timers.nim uses globals which we want to avoid where possible

View File

@ -27,7 +27,7 @@ export
# flowvars
Flowvar, isSpawned, isReady
when defined(TP_Metrics):
when defined(CTT_THREADPOOL_METRICS):
import ../platforms/static_for
import system/ansi_c
@ -180,7 +180,7 @@ type
# Thefts
rng: WorkStealingRng # RNG state to select victims
when defined(TP_Metrics):
when defined(CTT_THREADPOOL_METRICS):
counters: Counters
Threadpool* = ptr object
@ -202,7 +202,7 @@ type
# ############################################################
template metrics(body: untyped): untyped =
when defined(TP_Metrics):
when defined(CTT_THREADPOOL_METRICS):
block: {.noSideEffect, gcsafe.}: body
template incCounter(ctx: var WorkerContext, name: untyped{ident}, amount = 1) =

View File

@ -50,7 +50,7 @@ reportCli(Metrics, flags)
After compiling with
```
nim c -r --hints:off --warnings:off --verbosity:0 -d:danger -d:CttMeter --outdir:build metering/m_pairings.nim
nim c -r --hints:off --warnings:off --verbosity:0 -d:danger -d:CTT_METER --outdir:build metering/m_pairings.nim
```
We get

View File

@ -15,10 +15,10 @@
# Types
# --------------------------------------------------
const CttMeter {.booldefine.} = off
const CttTrace {.booldefine.} = off # For manual "debug-echo"-style timing.
const CTT_METER {.booldefine.} = off
const CTT_TRACE {.booldefine.} = off # For manual "debug-echo"-style timing.
when CttMeter or CttTrace:
when CTT_METER or CTT_TRACE:
import ../benchmarks/platforms
@ -94,7 +94,7 @@ when CttMeter or CttTrace:
when SupportsGetTicks:
discard Metrics[id].cumulatedCycles.atomicInc(elapsedCycles)
when CttTrace:
when CTT_TRACE:
# Advice: Use "when name == relevantProc" to isolate specific procedures.
# strformat doesn't work in templates.
when SupportsGetTicks:
@ -143,7 +143,7 @@ when CttMeter or CttTrace:
result = procAst
template meter*(procBody: untyped): untyped =
when CttMeter or CttTrace:
when CTT_METER or CTT_TRACE:
meterAnnotate(procBody)
else:
procBody
@ -153,9 +153,9 @@ template meter*(procBody: untyped): untyped =
when isMainModule:
static: doAssert CttMeter or CttTrace, "CttMeter or CttTrace must be on for tracing"
static: doAssert CTT_METER or CTT_TRACE, "CTT_METER or CTT_TRACE must be on for tracing"
when CttMeter or CttTrace: # Avoid warnings from nim check or nimsuggest
when CTT_METER or CTT_TRACE: # Avoid warnings from nim check or nimsuggest
expandMacros:
proc foo(x: int): int{.meter.} =
echo "Hey hey hey"

View File

@ -12,7 +12,7 @@ import std/unittest,
../../constantine/math/io/[io_bigints, io_fields],
../../constantine/math/config/curves
static: doAssert defined(testingCurves), "This modules requires the -d:testingCurves compile option"
static: doAssert defined(CTT_TEST_CURVES), "This modules requires the -d:CTT_TEST_CURVES compile option"
echo "\n------------------------------------------------------\n"

View File

@ -1 +1 @@
-d:testingCurves
-d:CTT_TEST_CURVES

View File

@ -1 +1 @@
-d:CttDebug
-d:CTT_DEBUG

View File

@ -25,7 +25,7 @@ rng.seed(seed)
echo "\n------------------------------------------------------\n"
echo "test_finite_fields_mulsquare xoshiro512** seed: ", seed
static: doAssert defined(testingCurves), "This modules requires the -d:testingCurves compile option"
static: doAssert defined(CTT_TEST_CURVES), "This modules requires the -d:CTT_TEST_CURVES compile option"
proc sanity(C: static Curve) =
test "Squaring 0,1,2 with " & $Curve(C) & " [FastSquaring = " & $(Fp[C].getSpareBits() >= 2) & "]":

View File

@ -1,2 +1,2 @@
-d:testingCurves
-d:CttDebug
-d:CTT_TEST_CURVES
-d:CTT_DEBUG

View File

@ -18,7 +18,7 @@ import
../../helpers/prng_unsafe
static: doAssert defined(testingCurves), "This modules requires the -d:testingCurves compile option"
static: doAssert defined(CTT_TEST_CURVES), "This modules requires the -d:CTT_TEST_CURVES compile option"
const Iters = 8

View File

@ -1 +1 @@
-d:testingCurves
-d:CTT_TEST_CURVES

View File

@ -26,7 +26,7 @@ rng.seed(seed)
echo "\n------------------------------------------------------\n"
echo "test_finite_fields_sqrt xoshiro512** seed: ", seed
static: doAssert defined(testingCurves), "This modules requires the -d:testingCurves compile option"
static: doAssert defined(CTT_TEST_CURVES), "This modules requires the -d:CTT_TEST_CURVES compile option"
proc exhaustiveCheck(C: static Curve, modulus: static int) =
test "Exhaustive square root check for " & $Curve(C):

View File

@ -1 +1 @@
-d:testingCurves
-d:CTT_TEST_CURVES

View File

@ -12,7 +12,7 @@ import
# Third-party
gmp,
# Internal
../../constantine/platforms/abstractions,
../../constantine/platforms/[abstractions, codecs],
../../constantine/math/io/[io_bigints, io_fields],
../../constantine/math/arithmetic,
../../constantine/math/config/curves,

View File

@ -1 +1 @@
-d:testingCurves
-d:CTT_TEST_CURVES