CI: enable GMP tests on Windows and Linux 32-bit and fix caching (#204)

* Try to compile with GMP on windows and 32-bit linux

* remove leftover msys shell

* Don't use GMP Mersenne Twister, bad randomness and untested Nim wrapper

* properly cache nim

* fix path after cache

* run pacman in msys2 env

* rework msys2 ... again

* shell compat for file clearing

* shell compat try-again for file clearing

* force bash for clearing parallel builds on windows

* Use nimscript directly (why didn't it work last time?)

* Avoid IO redirection to support any shell

* Avoid IO redirection v2 to support any shell

* add debug data

* add debug again

* Introduce pararun, a parallel test runner to remove need of GNU parallel

* pararun: style
This commit is contained in:
Mamy Ratsimbazafy 2022-09-15 09:33:34 +02:00 committed by GitHub
parent 094445482b
commit 962e7ccf49
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 431 additions and 333 deletions

View File

@ -117,10 +117,9 @@ jobs:
run: |
echo '${{ github.workspace }}'"/external/mingw-${{ matrix.target.cpu }}/bin" >> $GITHUB_PATH
echo '${{ github.workspace }}'"/external/dlls-${{ matrix.target.cpu }}" >> $GITHUB_PATH
- name: Restore Nim from cache
if: >
steps.nim-compiler-cache.outputs.cache-hit != 'true' &&
matrix.nim_version != 'devel'
if: matrix.nim_version != 'devel'
id: nim-compiler-cache
uses: actions/cache@v2
with:
@ -128,20 +127,28 @@ jobs:
key: 'nim-${{ matrix.target.cpu }}-${{ matrix.nim_version }}'
- name: Setup Nim
if: steps.nim-compiler-cache.outputs.cache-hit != 'true'
uses: alaviss/setup-nim@0.1.1
with:
path: 'nim'
path: 'nim-${{ matrix.nim_version }}-${{ matrix.target.cpu }}'
version: ${{ matrix.nim_version }}
architecture: ${{ matrix.target.cpu }}
add-to-path: false
- name: Install dependencies (Linux amd64)
- name: Path to cached Nim
shell: bash
run: |
echo '${{ github.workspace }}'"/nim-${{ matrix.nim_version }}-${{ matrix.target.cpu }}/bin" >> $GITHUB_PATH
echo '${{ github.workspace }}'"/.nimble/bin" >> $GITHUB_PATH
- name: Install test dependencies (Linux amd64)
if: runner.os == 'Linux' && matrix.target.cpu == 'amd64'
run: |
sudo DEBIAN_FRONTEND='noninteractive' apt-fast install \
--no-install-recommends -yq \
libgmp-dev
- name: Install dependencies (Linux i386)
- name: Install test dependencies (Linux i386)
if: runner.os == 'Linux' && matrix.target.cpu == 'i386'
run: |
sudo dpkg --add-architecture i386
@ -160,70 +167,51 @@ jobs:
#!/bin/bash
exec $(which g++) -m32 "\$@"
EOF
chmod 755 external/bin/gcc external/bin/g++
chmod 755 external/bin/{gcc,g++}
echo '${{ github.workspace }}/external/bin' >> $GITHUB_PATH
- name: Install dependencies (macOS)
- name: Install test dependencies (macOS)
if: runner.os == 'macOS'
run: brew install gmp parallel
run: brew install gmp
- name: Setup MSYS2 (Windows)
if: runner.os == 'Windows'
uses: msys2/setup-msys2@v2
with:
path-type: inherit
update: true
update: false
install: base-devel git mingw-w64-x86_64-toolchain
- name: Install dependencies (Windows)
- name: Install test dependencies (Windows)
if: runner.os == 'Windows'
shell: msys2 {0}
run: |
pacman -S --needed --noconfirm mingw-w64-x86_64-gmp
pacman -S --needed --noconfirm parallel
nimble refresh -y
nimble install -y gmp stew jsony
nimble refresh --verbose -y
nimble install --verbose -y gmp stew jsony asynctools
- name: Install test dependencies
if: runner.os != 'Windows'
shell: bash
run: |
nimble refresh -y
nimble install -y gmp stew jsony
nimble refresh --verbose -y
nimble install --verbose -y gmp stew jsony asynctools
- name: Run Constantine tests (with Assembler & with GMP)
if: (runner.os == 'Linux' || runner.os == 'macOS') && matrix.target.BACKEND == 'ASM' && matrix.target.cpu != 'i386'
- name: Run Constantine tests (UNIX with Assembler)
if: runner.os != 'Windows' && matrix.target.BACKEND == 'ASM'
shell: bash
run: |
export UCPU="$cpu"
cd constantine
nimble test_parallel
- name: Run Constantine tests (no Assembler & with GMP)
if: (runner.os == 'Linux' || runner.os == 'macOS') && matrix.target.BACKEND == 'NO_ASM' && matrix.target.cpu != 'i386'
nimble test_parallel --verbose
- name: Run Constantine tests (UNIX no Assembler)
if: runner.os != 'Windows' && matrix.target.BACKEND == 'NO_ASM'
shell: bash
run: |
export UCPU="$cpu"
cd constantine
nimble test_parallel_no_assembler
- name: Run Constantine tests (without GMP)
if: runner.os == 'Linux' && matrix.target.BACKEND == 'ASM' && matrix.target.cpu == 'i386'
shell: bash
run: |
export UCPU="$cpu"
cd constantine
nimble test_parallel_no_gmp
- name: Run Constantine tests (without Assembler or GMP)
if: runner.os == 'Linux' && matrix.target.BACKEND == 'NO_ASM' && matrix.target.cpu == 'i386'
shell: bash
run: |
export UCPU="$cpu"
cd constantine
nimble test_parallel_no_gmp_no_assembler
- name: Run Constantine tests (Windows - without Assembler or GMP)
# TODO, why aren't GMP or parallel in path?
if: runner.os == 'Windows'
nimble test_parallel_no_asm --verbose
- name: Run Constantine tests (Windows no Assembler)
if: runner.os == 'Windows' && matrix.target.BACKEND == 'NO_ASM'
shell: msys2 {0}
run: |
export UCPU="$cpu"
cd constantine
nimble test_no_gmp_no_assembler
nimble test_parallel_no_asm --verbose

View File

@ -21,6 +21,24 @@ const buildParallel = "test_parallel.txt"
# Code refactoring requires re-enabling the full suite.
# Basic primitives should stay on to catch compiler regressions.
const testDesc: seq[tuple[path: string, useGMP: bool]] = @[
# Hashing vs OpenSSL
# ----------------------------------------------------------
("tests/t_hash_sha256_vs_openssl.nim", true), # skip OpenSSL tests on Windows
# Ciphers
# ----------------------------------------------------------
("tests/t_cipher_chacha20.nim", false),
# Message Authentication Code
# ----------------------------------------------------------
("tests/t_mac_poly1305.nim", false),
("tests/t_mac_hmac_sha256.nim", false),
# KDF
# ----------------------------------------------------------
("tests/t_kdf_hkdf.nim", false),
# Primitives
# ----------------------------------------------------------
("tests/math/t_primitives.nim", false),
@ -188,29 +206,12 @@ const testDesc: seq[tuple[path: string, useGMP: bool]] = @[
# ----------------------------------------------------------
("tests/math/t_fr.nim", false),
# Hashing vs OpenSSL
# ----------------------------------------------------------
("tests/t_hash_sha256_vs_openssl.nim", true), # skip OpenSSL tests on Windows
# Hashing to elliptic curves
# ----------------------------------------------------------
("tests/t_hash_to_field.nim", false),
("tests/t_hash_to_curve_random.nim", false),
("tests/t_hash_to_curve.nim", false),
# Ciphers
# ----------------------------------------------------------
("tests/t_cipher_chacha20.nim", false),
# Message Authentication Code
# ----------------------------------------------------------
("tests/t_mac_poly1305.nim", false),
("tests/t_mac_hmac_sha256.nim", false),
# KDF
# ----------------------------------------------------------
("tests/t_kdf_hkdf.nim", false),
# Protocols
# ----------------------------------------------------------
("tests/t_ethereum_evm_precompiles.nim", false),
@ -218,6 +219,26 @@ const testDesc: seq[tuple[path: string, useGMP: bool]] = @[
("tests/t_ethereum_eip2333_bls12381_key_derivation.nim", false),
]
const benchDesc = [
"bench_fp",
"bench_fp_double_precision",
"bench_fp2",
"bench_fp6",
"bench_fp12",
"bench_ec_g1",
"bench_ec_g2",
"bench_pairing_bls12_377",
"bench_pairing_bls12_381",
"bench_pairing_bn254_nogami",
"bench_pairing_bn254_snarks",
"bench_summary_bls12_377",
"bench_summary_bls12_381",
"bench_summary_bn254_nogami",
"bench_summary_bn254_snarks",
"bench_sha256",
"bench_hash_to_curve"
]
# For temporary (hopefully) investigation that can only be reproduced in CI
const useDebug = [
"tests/math/t_bigints.nim",
@ -256,13 +277,11 @@ else:
# ----------------------------------------------------------------
proc clearParallelBuild() =
exec "> " & buildParallel
# Support clearing from non POSIX shell like CMD, Powershell or MSYS2
if fileExists(buildParallel):
rmFile(buildParallel)
proc test(flags, path: string, commandFile = false) =
# commandFile should be a "file" but Nimscript doesn't support IO
if not dirExists "build":
mkDir "build"
# Compilation language is controlled by WEAVE_TEST_LANG
template setupCommand(): untyped {.dirty.} =
var lang = "c"
if existsEnv"TEST_LANG":
lang = getEnv"TEST_LANG"
@ -280,36 +299,55 @@ proc test(flags, path: string, commandFile = false) =
" --nimcache:nimcache/" & path & " " &
path
if not commandFile:
echo "\n=============================================================================================="
echo "Running [flags:", flags, "] ", path
echo "=============================================================================================="
exec command
else:
exec "echo \'" & command & "\' >> " & buildParallel
exec "echo \"------------------------------------------------------\""
proc test(cmd: string) =
echo "\n=============================================================================================="
echo "Running '", cmd, "'"
echo "=============================================================================================="
exec cmd
proc buildBench(benchName: string, compiler = "", useAsm = true, run = false) =
if not dirExists "build":
mkDir "build"
proc testBatch(commands: var string, flags, path: string) =
setupCommand()
commands &= command & '\n'
template setupBench(): untyped {.dirty.} =
let runFlag = if run: " -r "
else: " "
else: " "
var lang = " c "
if existsEnv"TEST_LANG":
lang = getEnv"TEST_LANG"
var cc = ""
if compiler != "":
cc = "--cc:" & compiler
elif existsEnv"CC":
cc = " --cc:" & getEnv"CC"
if not useAsm:
cc &= " -d:CttASM=false"
exec "nim c " & cc &
let command = "nim " & lang & cc &
" -d:danger --verbosity:0 -o:build/bench/" & benchName & "_" & compiler & "_" & (if useAsm: "useASM" else: "noASM") &
" --nimcache:nimcache/" & benchName & "_" & compiler & "_" & (if useAsm: "useASM" else: "noASM") &
runFlag & "--hints:off --warnings:off benchmarks/" & benchName & ".nim"
proc runBench(benchName: string, compiler = "", useAsm = true) =
buildBench(benchName, compiler, useAsm, run = true)
if not dirExists "build":
mkDir "build"
let run = true
setupBench()
exec command
proc runTests(requireGMP: bool, dumpCmdFile = false, test32bit = false, testASM = true) =
proc buildBenchBatch(commands: var string, benchName: string, compiler = "", useAsm = true) =
let run = false
let compiler = ""
setupBench()
commands &= command & '\n'
proc addTestSet(cmdFile: var string, requireGMP: bool, test32bit = false, testASM = true) =
if not dirExists "build":
mkDir "build"
echo "Found " & $testDesc.len & " tests to run."
for td in testDesc:
if not(td.useGMP and not requireGMP):
var flags = ""
@ -321,29 +359,15 @@ proc runTests(requireGMP: bool, dumpCmdFile = false, test32bit = false, testASM
flags &= " -d:debugConstantine"
if td.path notin skipSanitizers:
flags &= sanitizers
test flags, td.path, dumpCmdFile
cmdFile.testBatch(flags, td.path)
proc buildAllBenches(useAsm = true) =
echo "\n\n------------------------------------------------------\n"
echo "Building benchmarks to ensure they stay relevant ..."
buildBench("bench_fp", useAsm = useAsm)
buildBench("bench_fp_double_precision", useAsm = useAsm)
buildBench("bench_fp2", useAsm = useAsm)
buildBench("bench_fp6", useAsm = useAsm)
buildBench("bench_fp12", useAsm = useAsm)
buildBench("bench_ec_g1", useAsm = useAsm)
buildBench("bench_ec_g2", useAsm = useAsm)
buildBench("bench_pairing_bls12_377", useAsm = useAsm)
buildBench("bench_pairing_bls12_381", useAsm = useAsm)
buildBench("bench_pairing_bn254_nogami", useAsm = useAsm)
buildBench("bench_pairing_bn254_snarks", useAsm = useAsm)
buildBench("bench_summary_bls12_377", useAsm = useAsm)
buildBench("bench_summary_bls12_381", useAsm = useAsm)
buildBench("bench_summary_bn254_nogami", useAsm = useAsm)
buildBench("bench_summary_bn254_snarks", useAsm = useAsm)
buildBench("bench_sha256", useAsm = useAsm)
buildBench("bench_hash_to_curve", useAsm = useAsm)
echo "All benchmarks compile successfully."
proc addBenchSet(cmdFile: var string, useAsm = true) =
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)
proc genBindings(bindingsName, prefixNimMain: string) =
proc compile(libName: string, flags = "") =
@ -379,6 +403,9 @@ proc genHeaders(bindingsName: string) =
" --nimcache:nimcache/bindings/" & bindingsName & "_header" &
" bindings/" & bindingsName & ".nim"
proc genParallelCmdRunner() =
exec "nim c --verbosity:0 --hints:off --warnings:off -d:release --out:build/pararun --nimcache:nimcache/pararun helpers/pararun.nim"
# Tasks
# ----------------------------------------------------------------
@ -390,123 +417,79 @@ task bindings, "Generate Constantine bindings":
task test, "Run all tests":
# -d:testingCurves is configured in a *.nim.cfg for convenience
runTests(requireGMP = true)
var cmdFile: string
cmdFile.addTestSet(requireGMP = true, testASM = true)
cmdFile.addBenchSet(useASM = true) # Build (but don't run) benches to ensure they stay relevant
for cmd in cmdFile.splitLines():
exec cmd
# if sizeof(int) == 8: # 32-bit tests on 64-bit arch
# runTests(requireGMP = true, test32bit = true)
# Ensure benchmarks stay relevant. Ignore Windows 32-bit at the moment
if not defined(windows) or not (existsEnv"UCPU" or getEnv"UCPU" == "i686"):
buildAllBenches()
task test_no_assembler, "Run all tests":
task test_no_asm, "Run all tests (no assembly)":
# -d:testingCurves is configured in a *.nim.cfg for convenience
runTests(requireGMP = true, testASM = false)
# if sizeof(int) == 8: # 32-bit tests on 64-bit arch
# runTests(requireGMP = true, test32bit = true)
# Ensure benchmarks stay relevant. Ignore Windows 32-bit at the moment
if not defined(windows) or not (existsEnv"UCPU" or getEnv"UCPU" == "i686"):
buildAllBenches(useASM = false)
var cmdFile: string
cmdFile.addTestSet(requireGMP = true, testASM = false)
cmdFile.addBenchSet(useASM = false) # Build (but don't run) benches to ensure they stay relevant
for cmd in cmdFile.splitLines():
exec cmd
task test_no_gmp, "Run tests that don't require GMP":
# -d:testingCurves is configured in a *.nim.cfg for convenience
runTests(requireGMP = false)
var cmdFile: string
cmdFile.addTestSet(requireGMP = false, testASM = true)
cmdFile.addBenchSet(useASM = true) # Build (but don't run) benches to ensure they stay relevant
for cmd in cmdFile.splitLines():
exec cmd
# if sizeof(int) == 8: # 32-bit tests on 64-bit arch
# runTests(requireGMP = true, test32bit = true)
# Ensure benchmarks stay relevant. Ignore Windows 32-bit at the moment
if not defined(windows) or not (existsEnv"UCPU" or getEnv"UCPU" == "i686"):
buildAllBenches()
task test_no_gmp_no_assembler, "Run tests that don't require GMP using a pure Nim backend":
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
runTests(requireGMP = false, testASM = false)
# if sizeof(int) == 8: # 32-bit tests on 64-bit arch
# runTests(requireGMP = true, test32bit = true)
# Ensure benchmarks stay relevant. Ignore Windows 32-bit at the moment
if not defined(windows) or not (existsEnv"UCPU" or getEnv"UCPU" == "i686"):
buildAllBenches()
var cmdFile: string
cmdFile.addTestSet(requireGMP = false, testASM = false)
cmdFile.addBenchSet(useASM = false) # Build (but don't run) benches to ensure they stay relevant
for cmd in cmdFile.splitLines():
exec cmd
task test_parallel, "Run all tests in parallel (via GNU parallel)":
# -d:testingCurves is configured in a *.nim.cfg for convenience
clearParallelBuild()
runTests(requireGMP = true, dumpCmdFile = true)
exec "parallel --keep-order --group < " & buildParallel
genParallelCmdRunner()
# if sizeof(int) == 8: # 32-bit tests on 64-bit arch
# clearParallelBuild()
# runTests(requireGMP = true, dumpCmdFile = true, test32bit = true)
# exec "parallel --keep-order --group < " & buildParallel
var cmdFile: string
cmdFile.addTestSet(requireGMP = true, testASM = true)
cmdFile.addBenchSet(useASM = true) # Build (but don't run) benches to ensure they stay relevant
writeFile(buildParallel, cmdFile)
exec "build/pararun " & buildParallel
# Now run the benchmarks
#
# Benchmarks compile
# ignore Windows 32-bit for the moment
# Ensure benchmarks stay relevant. Ignore Windows 32-bit at the moment
if not defined(windows) or not (existsEnv"UCPU" or getEnv"UCPU" == "i686"):
buildAllBenches()
task test_parallel_no_assembler, "Run all tests (without macro assembler) in parallel (via GNU parallel)":
task test_parallel_no_asm, "Run all tests (without macro assembler) in parallel (via GNU parallel)":
# -d:testingCurves is configured in a *.nim.cfg for convenience
clearParallelBuild()
runTests(requireGMP = true, dumpCmdFile = true, testASM = false)
exec "parallel --keep-order --group < " & buildParallel
genParallelCmdRunner()
# if sizeof(int) == 8: # 32-bit tests on 64-bit arch
# clearParallelBuild()
# runTests(requireGMP = true, dumpCmdFile = true, test32bit = true, testASM = false)
# exec "parallel --keep-order --group < " & buildParallel
# Now run the benchmarks
#
# Benchmarks compile
# ignore Windows 32-bit for the moment
# Ensure benchmarks stay relevant. Ignore Windows 32-bit at the moment
if not defined(windows) or not (existsEnv"UCPU" or getEnv"UCPU" == "i686"):
buildAllBenches(useASM = false)
var cmdFile: string
cmdFile.addTestSet(requireGMP = true, testASM = false)
cmdFile.addBenchSet(useASM = false)
writeFile(buildParallel, cmdFile)
exec "build/pararun " & buildParallel
task test_parallel_no_gmp, "Run all tests in parallel (via GNU parallel)":
# -d:testingCurves is configured in a *.nim.cfg for convenience
clearParallelBuild()
runTests(requireGMP = false, dumpCmdFile = true)
exec "parallel --keep-order --group < " & buildParallel
genParallelCmdRunner()
# if sizeof(int) == 8: # 32-bit tests on 64-bit arch
# clearParallelBuild()
# runTests(requireGMP = false, dumpCmdFile = true, test32bit = true)
# exec "parallel --keep-order --group < " & buildParallel
var cmdFile: string
cmdFile.addTestSet(requireGMP = false, testASM = true)
cmdFile.addBenchSet(useASM = true) # Build (but don't run) benches to ensure they stay relevant
writeFile(buildParallel, cmdFile)
exec "build/pararun " & buildParallel
# Now run the benchmarks
#
# Benchmarks compile
# ignore Windows 32-bit for the moment
# Ensure benchmarks stay relevant. Ignore Windows 32-bit at the moment
if not defined(windows) or not (existsEnv"UCPU" or getEnv"UCPU" == "i686"):
buildAllBenches()
task test_parallel_no_gmp_no_assembler, "Run all tests in parallel (via GNU parallel)":
task test_parallel_no_gmp_no_asm, "Run all tests in parallel (via GNU parallel)":
# -d:testingCurves is configured in a *.nim.cfg for convenience
clearParallelBuild()
runTests(requireGMP = false, dumpCmdFile = true, testASM = false)
exec "parallel --keep-order --group < " & buildParallel
genParallelCmdRunner()
# if sizeof(int) == 8: # 32-bit tests on 64-bit arch
# clearParallelBuild()
# runTests(requireGMP = false, dumpCmdFile = true, test32bit = true, testASM = false)
# exec "parallel --keep-order --group < " & buildParallel
# Now run the benchmarks
#
# Benchmarks compile
# ignore Windows 32-bit for the moment
# Ensure benchmarks stay relevant. Ignore Windows 32-bit at the moment
if not defined(windows) or not (existsEnv"UCPU" or getEnv"UCPU" == "i686"):
buildAllBenches(useASM = false)
var cmdFile: string
cmdFile.addTestSet(requireGMP = false, testASM = false)
cmdFile.addBenchSet(useASM = false) # Build (but don't run) benches to ensure they stay relevant
writeFile(buildParallel, cmdFile)
exec "build/pararun " & buildParallel
# Finite field 𝔽p
# ------------------------------------------

151
helpers/pararun.nim Normal file
View File

@ -0,0 +1,151 @@
# 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
std/[os, strutils, cpuinfo, strformat, deques, terminal],
std/[asyncfutures, asyncdispatch],
asynctools/[asyncproc, asyncpipe, asyncsync]
# Pararun is a parallel shell command runner
# ------------------------------------------
# Usage: pararun <file-with-1-command-per-line> <numWorkers
# AsyncSemaphore
# ----------------------------------------------------------------
type AsyncSemaphore = ref object
waiters: Deque[Future[void]]
slots, max: int
proc new(_: type AsyncSemaphore, max: int): AsyncSemaphore =
## Initialize an AsyncSemaphore that can release up to max items
AsyncSemaphore(
waiters: default(Deque[Future[void]]),
slots: max,
max: max)
proc acquire(s: AsyncSemaphore) {.async.} =
doAssert s.slots in {0..s.max}
if s.slots == 0:
let waiter = newFuture[void]("AsyncSemaphore.acquire")
s.waiters.addLast(waiter)
await waiter
s.slots -= 1
doAssert s.slots in {0..s.max}
proc release(s: AsyncSemaphore) =
doAssert s.slots in {0..s.max-1}
s.slots += 1
if s.waiters.len > 0:
let waiter = s.waiters.popFirst()
waiter.complete()
doAssert s.slots in {0..s.max}
# Task runner
# ----------------------------------------------------------------
type WorkQueue = ref object
sem: AsyncSemaphore
cmdQueue: Deque[string]
outputQueue: AsyncQueue[tuple[cmd: string, p: AsyncProcess]]
lineBuf: string
proc releaseOnProcessExit(sem: AsyncSemaphore, p: AsyncProcess) {.async.} =
# TODO: addProcess callback on exit is cleaner but locks the AsyncPipe "readInto"
#
# p.processID.addProcess do (fd: AsyncFD) -> bool:
# sem.release()
#
# see also: https://forum.nim-lang.org/t/5565
while p.running():
await sleepAsync(10)
sem.release()
proc enqueuePendingCommands(wq: WorkQueue) {.async.} =
while wq.cmdQueue.len > 0:
await wq.sem.acquire()
let cmd = wq.cmdQueue.popFirst()
let p = cmd.startProcess(
options = {poStdErrToStdOut, poUsePath, poEvalCommand}
)
asyncCheck wq.sem.releaseOnProcessExit(p)
wq.outputQueue.putNoWait((cmd, p))
proc flushCommandsOutput(wq: WorkQueue) {.async.} =
while true:
let (cmd, p) = await wq.outputQueue.get()
echo '\n', '='.repeat(80)
echo "||\n|| Running: ", cmd ,"\n||"
echo '='.repeat(80)
while true:
let charsRead = await p.outputHandle.readInto(wq.lineBuf[0].addr, wq.lineBuf.len)
if charsRead == 0:
break
let charsWritten = stdout.writeBuffer(wq.lineBuf[0].addr, charsRead)
doAssert charsRead == charsWritten
if wq.cmdQueue.len == 0 and wq.outputQueue.len == 0:
return
proc runCommands(commandFile: string, numWorkers: int) =
# State
# -----
let wq = WorkQueue(
sem: AsyncSemaphore.new(numWorkers),
cmdQueue: initDeque[string](),
outputQueue: newAsyncQueue[tuple[cmd: string, p: AsyncProcess]](),
lineBuf: newString(max(80, terminalWidth()))
)
# Parse the file
# --------------
for cmd in lines(commandFile):
if cmd.len == 0: continue
wq.cmdQueue.addLast(cmd)
echo "Found ", wq.cmdQueue.len, " commands to run"
# Run the commands
# ----------------
asyncCheck wq.enqueuePendingCommands()
waitFor wq.flushCommandsOutput()
# Main
# ----------------------------------------------------------------
proc main() =
var commandFile: string
var numWorkers = countProcessors()
if paramCount() == 0:
let exeName = getAppFilename().extractFilename()
echo &"Usage: {exeName} <file-with-commands-1-per-line> <numWorkers: {numWorkers}>"
if paramCount() >= 1:
commandFile = paramStr(1)
if paramCount() == 2:
numWorkers = paramStr(2).parseInt()
if paramCount() > 2:
let exeName = getAppFilename().extractFilename()
echo &"Usage: {exeName} <file-with-commands-1-per-line> <numThreads: {numWorkers}>"
quit 1
runCommands(commandFile, numWorkers)
when isMainModule:
main()

View File

@ -158,9 +158,19 @@ func random_unsafe(rng: var RngState, a: var Limbs) =
for i in 0 ..< a.len:
a[i] = SecretWord(rng.next())
template clearExtraBitsOverMSB(a: var BigInt) =
## If we do bit manipulation at the word level,
## for example a 381-bit BigInt stored in a 384-bit buffer
## we need to clear the upper 3-bit
when a.bits != a.limbs.len * WordBitWidth:
const posExtraBits = a.bits - (a.limbs.len-1) * WordBitWidth
const mask = (One shl posExtraBits) - One
a.limbs[^1] = a.limbs[^1] and mask
func random_unsafe(rng: var RngState, a: var BigInt) =
## Initialize a standalone BigInt
rng.random_unsafe(a.limbs)
a.clearExtraBitsOverMSB()
func random_unsafe(rng: var RngState, a: var FF) =
## Initialize a Field element
@ -193,6 +203,7 @@ func random_highHammingWeight(rng: var RngState, a: var BigInt) =
## with high Hamming weight
## to have a higher probability of triggering carries
rng.random_highHammingWeight(a.limbs)
a.clearExtraBitsOverMSB()
func random_highHammingWeight(rng: var RngState, a: var FF) =
## Recursively initialize a BigInt (part of a field) or Field element
@ -236,6 +247,7 @@ func random_long01Seq(rng: var RngState, a: var BigInt) =
a.unmarshal(buf, bigEndian)
else:
a.unmarshal(buf, littleEndian)
a.clearExtraBitsOverMSB()
func random_long01Seq(rng: var RngState, a: var Limbs) =
## Initialize standalone limbs

View File

@ -14,7 +14,9 @@ import
# Internal
../../constantine/math/io/io_bigints,
../../constantine/math/arithmetic,
../../constantine/platforms/primitives
../../constantine/platforms/primitives,
# Test utilities
../../helpers/prng_unsafe
echo "\n------------------------------------------------------\n"
# We test up to 1024-bit, more is really slow
@ -82,15 +84,11 @@ const # https://gmplib.org/manual/Integer-Import-and-Export.html
GMP_LeastSignificantWordFirst = -1'i32
proc main() =
var gmpRng: gmp_randstate_t
gmp_randinit_mt(gmpRng)
# The GMP seed varies between run so that
# test coverage increases as the library gets tested.
# This requires to dump the seed in the console or the function inputs
# to be able to reproduce a bug
var rng: RngState
let seed = uint32(getTime().toUnix() and (1'i64 shl 32 - 1)) # unixTime mod 2^32
echo "GMP seed: ", seed
gmp_randseed_ui(gmpRng, seed)
rng.seed(seed)
echo "\n------------------------------------------------------\n"
echo "test_bigints_mod_vs_gmp xoshiro512** seed: ", seed
var a, m, r: mpz_t
mpz_init(a)
@ -101,34 +99,25 @@ proc main() =
# echo "--------------------------------------------------------------------------------"
echo "Testing: random dividend (" & align($aBits, 4) & "-bit) -- random modulus (" & align($mBits, 4) & "-bit)"
# Generate random value in the range 0 ..< 2^aBits
mpz_urandomb(a, gmpRng, aBits)
# Generate random modulus and ensure the MSB is set
mpz_urandomb(m, gmpRng, mBits)
mpz_setbit(m, mBits-1)
# discard gmp_printf(" -- %#Zx mod %#Zx\n", a.addr, m.addr)
# Build the bigints
let aTest = rng.random_unsafe(BigInt[aBits])
var mTest = rng.random_unsafe(BigInt[mBits])
# Ensure modulus MSB is set
mTest.setBit(mBits-1)
#########################################################
# Conversion buffers
# Conversion to GMP
const aLen = (aBits + 7) div 8
const mLen = (mBits + 7) div 8
var aBuf: array[aLen, byte]
var mBuf: array[mLen, byte]
var aW, mW: csize # Word written by GMP
aBuf.marshal(aTest, bigEndian)
mBuf.marshal(mTest, bigEndian)
discard mpz_export(aBuf[0].addr, aW.addr, GMP_MostSignificantWordFirst, 1, GMP_WordNativeEndian, 0, a)
discard mpz_export(mBuf[0].addr, mW.addr, GMP_MostSignificantWordFirst, 1, GMP_WordNativeEndian, 0, m)
# Since the modulus is using all bits, it's we can test for exact amount copy
doAssert aLen >= aW, "Expected at most " & $aLen & " bytes but wrote " & $aW & " for " & toHex(aBuf) & " (big-endian)"
doAssert mLen == mW, "Expected " & $mLen & " bytes but wrote " & $mW & " for " & toHex(mBuf) & " (big-endian)"
# Build the bigint
let aTest = BigInt[aBits].unmarshal(aBuf.toOpenArray(0, aW-1), bigEndian)
let mTest = BigInt[mBits].unmarshal(mBuf.toOpenArray(0, mW-1), bigEndian)
mpz_import(a, aLen, GMP_MostSignificantWordFirst, 1, GMP_WordNativeEndian, 0, aBuf[0].addr)
mpz_import(m, mLen, GMP_MostSignificantWordFirst, 1, GMP_WordNativeEndian, 0, mBuf[0].addr)
#########################################################
# Modulus
@ -139,8 +128,12 @@ proc main() =
#########################################################
# Check
{.push warnings: off.} # deprecated csize
var aW, mW, rW: csize # Words written by GMP
{.pop.}
var rGMP: array[mLen, byte]
var rW: csize # Word written by GMP
discard mpz_export(rGMP[0].addr, rW.addr, GMP_MostSignificantWordFirst, 1, GMP_WordNativeEndian, 0, r)
var rConstantine: array[mLen, byte]

View File

@ -14,7 +14,9 @@ import
# Internal
../../constantine/math/io/io_bigints,
../../constantine/math/arithmetic,
../../constantine/platforms/abstractions
../../constantine/platforms/abstractions,
# Test utilities
../../helpers/prng_unsafe
echo "\n------------------------------------------------------\n"
# We test up to 1024-bit, more is really slow
@ -51,15 +53,11 @@ const # https://gmplib.org/manual/Integer-Import-and-Export.html
GMP_LeastSignificantWordFirst {.used.} = -1'i32
proc main() =
var gmpRng: gmp_randstate_t
gmp_randinit_mt(gmpRng)
# The GMP seed varies between run so that
# test coverage increases as the library gets tested.
# This requires to dump the seed in the console or the function inputs
# to be able to reproduce a bug
var rng: RngState
let seed = uint32(getTime().toUnix() and (1'i64 shl 32 - 1)) # unixTime mod 2^32
echo "GMP seed: ", seed
gmp_randseed_ui(gmpRng, seed)
rng.seed(seed)
echo "\n------------------------------------------------------\n"
echo "test_bigints_mod_vs_gmp xoshiro512** seed: ", seed
var r, a, b: mpz_t
mpz_init(r)
@ -74,36 +72,23 @@ proc main() =
"-bit) * b (", align($bBits, 4), "-bit) (full mul bits: ", align($(aBits+bBits), 4),
"), r large enough? ", wordsRequired(rBits) >= wordsRequired(aBits+bBits) - wordsStartIndex
# Generate random value in the range 0 ..< 2^aBits
mpz_urandomb(a, gmpRng, aBits)
# Generate random modulus and ensure the MSB is set
mpz_urandomb(b, gmpRng, bBits)
mpz_setbit(r, aBits+bBits)
# discard gmp_printf(" -- %#Zx mod %#Zx\n", a.addr, m.addr)
# Build the bigints
let aTest = rng.random_unsafe(BigInt[aBits])
var bTest = rng.random_unsafe(BigInt[bBits])
#########################################################
# Conversion buffers
# Conversion to GMP
const aLen = (aBits + 7) div 8
const bLen = (bBits + 7) div 8
var aBuf: array[aLen, byte]
var bBuf: array[bLen, byte]
{.push warnings: off.} # deprecated csize
var aW, bW: csize # Word written by GMP
{.pop.}
aBuf.marshal(aTest, bigEndian)
bBuf.marshal(bTest, bigEndian)
discard mpz_export(aBuf[0].addr, aW.addr, GMP_MostSignificantWordFirst, 1, GMP_WordNativeEndian, 0, a)
discard mpz_export(bBuf[0].addr, bW.addr, GMP_MostSignificantWordFirst, 1, GMP_WordNativeEndian, 0, b)
# Since the modulus is using all bits, it's we can test for exact amount copy
doAssert aLen >= aW, "Expected at most " & $aLen & " bytes but wrote " & $aW & " for " & toHex(aBuf) & " (big-endian)"
doAssert bLen >= bW, "Expected at most " & $bLen & " bytes but wrote " & $bW & " for " & toHex(bBuf) & " (big-endian)"
# Build the bigint
let aTest = BigInt[aBits].unmarshal(aBuf.toOpenArray(0, aW-1), bigEndian)
let bTest = BigInt[bBits].unmarshal(bBuf.toOpenArray(0, bW-1), bigEndian)
mpz_import(a, aLen, GMP_MostSignificantWordFirst, 1, GMP_WordNativeEndian, 0, aBuf[0].addr)
mpz_import(b, bLen, GMP_MostSignificantWordFirst, 1, GMP_WordNativeEndian, 0, bBuf[0].addr)
#########################################################
# Multiplication + drop low words
@ -124,11 +109,13 @@ proc main() =
#########################################################
# Check
{.push warnings: off.} # deprecated csize
var aW, bW, rW: csize # Word written by GMP
{.pop.}
const rLen = numWords * WordBitWidth
var rGMP: array[rLen, byte]
{.push warnings: off.} # deprecated csize
var rW: csize # Word written by GMP
{.pop.}
discard mpz_export(rGMP[0].addr, rW.addr, GMP_MostSignificantWordFirst, 1, GMP_WordNativeEndian, 0, r)
var rConstantine: array[rLen, byte]

View File

@ -14,7 +14,9 @@ import
# Internal
../../constantine/math/io/io_bigints,
../../constantine/math/arithmetic,
../../constantine/platforms/abstractions
../../constantine/platforms/abstractions,
# Test utilities
../../helpers/prng_unsafe
echo "\n------------------------------------------------------\n"
# We test up to 1024-bit, more is really slow
@ -48,15 +50,11 @@ const # https://gmplib.org/manual/Integer-Import-and-Export.html
GMP_LeastSignificantWordFirst {.used.} = -1'i32
proc main() =
var gmpRng: gmp_randstate_t
gmp_randinit_mt(gmpRng)
# The GMP seed varies between run so that
# test coverage increases as the library gets tested.
# This requires to dump the seed in the console or the function inputs
# to be able to reproduce a bug
var rng: RngState
let seed = uint32(getTime().toUnix() and (1'i64 shl 32 - 1)) # unixTime mod 2^32
echo "GMP seed: ", seed
gmp_randseed_ui(gmpRng, seed)
rng.seed(seed)
echo "\n------------------------------------------------------\n"
echo "test_bigints_mod_vs_gmp xoshiro512** seed: ", seed
var r, a, b: mpz_t
mpz_init(r)
@ -67,36 +65,23 @@ proc main() =
# echo "--------------------------------------------------------------------------------"
echo "Testing: random mul r (", align($rBits, 4), "-bit) <- a (", align($aBits, 4), "-bit) * b (", align($bBits, 4), "-bit) (full mul bits: ", align($(aBits+bBits), 4), "), r large enough? ", rBits >= aBits+bBits
# Generate random value in the range 0 ..< 2^aBits
mpz_urandomb(a, gmpRng, aBits)
# Generate random modulus and ensure the MSB is set
mpz_urandomb(b, gmpRng, bBits)
mpz_setbit(r, aBits+bBits)
# discard gmp_printf(" -- %#Zx mod %#Zx\n", a.addr, m.addr)
# Build the bigints
let aTest = rng.random_unsafe(BigInt[aBits])
var bTest = rng.random_unsafe(BigInt[bBits])
#########################################################
# Conversion buffers
# Conversion to GMP
const aLen = (aBits + 7) div 8
const bLen = (bBits + 7) div 8
var aBuf: array[aLen, byte]
var bBuf: array[bLen, byte]
{.push warnings: off.} # deprecated csize
var aW, bW: csize # Word written by GMP
{.pop.}
aBuf.marshal(aTest, bigEndian)
bBuf.marshal(bTest, bigEndian)
discard mpz_export(aBuf[0].addr, aW.addr, GMP_MostSignificantWordFirst, 1, GMP_WordNativeEndian, 0, a)
discard mpz_export(bBuf[0].addr, bW.addr, GMP_MostSignificantWordFirst, 1, GMP_WordNativeEndian, 0, b)
# Since the modulus is using all bits, it's we can test for exact amount copy
doAssert aLen >= aW, "Expected at most " & $aLen & " bytes but wrote " & $aW & " for " & toHex(aBuf) & " (big-endian)"
doAssert bLen >= bW, "Expected at most " & $bLen & " bytes but wrote " & $bW & " for " & toHex(bBuf) & " (big-endian)"
# Build the bigint
let aTest = BigInt[aBits].unmarshal(aBuf.toOpenArray(0, aW-1), bigEndian)
let bTest = BigInt[bBits].unmarshal(bBuf.toOpenArray(0, bW-1), bigEndian)
mpz_import(a, aLen, GMP_MostSignificantWordFirst, 1, GMP_WordNativeEndian, 0, aBuf[0].addr)
mpz_import(b, bLen, GMP_MostSignificantWordFirst, 1, GMP_WordNativeEndian, 0, bBuf[0].addr)
#########################################################
# Multiplication
@ -114,11 +99,13 @@ proc main() =
#########################################################
# Check
{.push warnings: off.} # deprecated csize
var aW, bW, rW: csize # Word written by GMP
{.pop.}
const rLen = numWords * WordBitWidth
var rGMP: array[rLen, byte]
{.push warnings: off.} # deprecated csize
var rW: csize # Word written by GMP
{.pop.}
discard mpz_export(rGMP[0].addr, rW.addr, GMP_MostSignificantWordFirst, 1, GMP_WordNativeEndian, 0, r)
var rConstantine: array[rLen, byte]

View File

@ -15,7 +15,9 @@ import
../../constantine/platforms/abstractions,
../../constantine/math/io/[io_bigints, io_fields],
../../constantine/math/arithmetic,
../../constantine/math/config/curves
../../constantine/math/config/curves,
# Test utilities
../../helpers/prng_unsafe
echo "\n------------------------------------------------------\n"
@ -45,36 +47,32 @@ const # https://gmplib.org/manual/Integer-Import-and-Export.html
# Factor common things in proc to avoid generating 100k+ lines of C code
proc binary_prologue[C: static Curve, N: static int](
gmpRng: var gmp_randstate_t,
rng: var RngState,
a, b, p: var mpz_t,
aTest, bTest: var Fp[C],
aBuf, bBuf: var array[N, byte]) =
const bits = C.getCurveBitwidth()
# Generate random value in the range 0 ..< 2^(bits-1)
mpz_urandomb(a, gmpRng, uint bits)
mpz_urandomb(b, gmpRng, uint bits)
# Build the field elements
aTest = rng.random_unsafe(Fp[C])
bTest = rng.random_unsafe(Fp[C])
# Set modulus to curve modulus
let err = mpz_set_str(p, Curve(C).Mod.toHex(), 0)
doAssert err == 0, "Error on prime for curve " & $Curve(C)
#########################################################
# Conversion buffers
const len = (bits + 7) div 8
# Conversion to GMP
const aLen = (C.getCurveBitwidth() + 7) div 8
const bLen = (C.getCurveBitwidth() + 7) div 8
static: doAssert N >= len
var aBuf: array[aLen, byte]
var bBuf: array[bLen, byte]
var aW, bW: csize # Word written by GMP
discard mpz_export(aBuf[0].addr, aW.addr, GMP_MostSignificantWordFirst, 1, GMP_WordNativeEndian, 0, a)
discard mpz_export(bBuf[0].addr, bW.addr, GMP_MostSignificantWordFirst, 1, GMP_WordNativeEndian, 0, b)
aBuf.marshal(aTest, bigEndian)
bBuf.marshal(bTest, bigEndian)
# Since the modulus is using all bits, it's we can test for exact amount copy
doAssert len >= aW, "Expected at most " & $len & " bytes but wrote " & $aW & " for " & toHex(aBuf) & " (big-endian)"
doAssert len >= bW, "Expected at most " & $len & " bytes but wrote " & $bW & " for " & toHex(bBuf) & " (big-endian)"
# Build the bigint
aTest = Fp[C].fromBig BigInt[bits].unmarshal(aBuf.toOpenArray(0, aW-1), bigEndian)
bTest = Fp[C].fromBig BigInt[bits].unmarshal(bBuf.toOpenArray(0, bW-1), bigEndian)
mpz_import(a, aLen, GMP_MostSignificantWordFirst, 1, GMP_WordNativeEndian, 0, aBuf[0].addr)
mpz_import(b, bLen, GMP_MostSignificantWordFirst, 1, GMP_WordNativeEndian, 0, bBuf[0].addr)
proc binary_epilogue[C: static Curve, N: static int](
r, a, b: mpz_t,
@ -85,8 +83,12 @@ proc binary_epilogue[C: static Curve, N: static int](
#########################################################
# Check
{.push warnings: off.} # deprecated csize
var aW, bW, rW: csize # Word written by GMP
{.pop.}
var rGMP: array[N, byte]
var rW: csize # Word written by GMP
discard mpz_export(rGMP[0].addr, rW.addr, GMP_MostSignificantWordFirst, 1, GMP_WordNativeEndian, 0, r)
var rConstantine: array[N, byte]
@ -95,7 +97,6 @@ proc binary_epilogue[C: static Curve, N: static int](
# Note: in bigEndian, GMP aligns left while constantine aligns right
doAssert rGMP.toOpenArray(0, rW-1) == rConstantine.toOpenArray(N-rW, N-1), block:
# Reexport as bigEndian for debugging
var aW, bW: csize
discard mpz_export(aBuf[0].unsafeAddr, aW.addr, GMP_MostSignificantWordFirst, 1, GMP_WordNativeEndian, 0, a)
discard mpz_export(bBuf[0].unsafeAddr, bW.addr, GMP_MostSignificantWordFirst, 1, GMP_WordNativeEndian, 0, b)
"\nModular " & operation & " on curve " & $C & " with operands\n" &
@ -112,7 +113,7 @@ proc binary_epilogue[C: static Curve, N: static int](
#
# ############################################################
proc addTests(gmpRng: var gmp_randstate_t, a, b, p, r: var mpz_t, C: static Curve) =
proc addTests(rng: var RngState, a, b, p, r: var mpz_t, C: static Curve) =
# echo "Testing: random modular addition on ", $C
const
@ -121,7 +122,7 @@ proc addTests(gmpRng: var gmp_randstate_t, a, b, p, r: var mpz_t, C: static Curv
var
aTest, bTest{.noInit.}: Fp[C]
aBuf, bBuf: array[bufLen, byte]
binary_prologue(gmpRng, a, b, p, aTest, bTest, aBuf, bBuf)
binary_prologue(rng, a, b, p, aTest, bTest, aBuf, bBuf)
mpz_add(r, a, b)
mpz_mod(r, r, p)
@ -135,7 +136,7 @@ proc addTests(gmpRng: var gmp_randstate_t, a, b, p, r: var mpz_t, C: static Curv
binary_epilogue(r, a, b, rTest, aBuf, bBuf, "Addition (with result)")
binary_epilogue(r, a, b, r2Test, aBuf, bBuf, "Addition (in-place)")
proc subTests(gmpRng: var gmp_randstate_t, a, b, p, r: var mpz_t, C: static Curve) =
proc subTests(rng: var RngState, a, b, p, r: var mpz_t, C: static Curve) =
# echo "Testing: random modular substraction on ", $C
const
@ -144,7 +145,7 @@ proc subTests(gmpRng: var gmp_randstate_t, a, b, p, r: var mpz_t, C: static Curv
var
aTest, bTest{.noInit.}: Fp[C]
aBuf, bBuf: array[bufLen, byte]
binary_prologue(gmpRng, a, b, p, aTest, bTest, aBuf, bBuf)
binary_prologue(rng, a, b, p, aTest, bTest, aBuf, bBuf)
mpz_sub(r, a, b)
mpz_mod(r, r, p)
@ -163,7 +164,7 @@ proc subTests(gmpRng: var gmp_randstate_t, a, b, p, r: var mpz_t, C: static Curv
binary_epilogue(r, a, b, r2Test, aBuf, bBuf, "Substraction (in-place)")
binary_epilogue(r, a, b, r3Test, aBuf, bBuf, "Substraction (result aliasing)")
proc mulTests(gmpRng: var gmp_randstate_t, a, b, p, r: var mpz_t, C: static Curve) =
proc mulTests(rng: var RngState, a, b, p, r: var mpz_t, C: static Curve) =
# echo "Testing: random modular multiplication on ", $C
const
@ -172,7 +173,7 @@ proc mulTests(gmpRng: var gmp_randstate_t, a, b, p, r: var mpz_t, C: static Curv
var
aTest, bTest{.noInit.}: Fp[C]
aBuf, bBuf: array[bufLen, byte]
binary_prologue(gmpRng, a, b, p, aTest, bTest, aBuf, bBuf)
binary_prologue(rng, a, b, p, aTest, bTest, aBuf, bBuf)
mpz_mul(r, a, b)
mpz_mod(r, r, p)
@ -186,7 +187,7 @@ proc mulTests(gmpRng: var gmp_randstate_t, a, b, p, r: var mpz_t, C: static Curv
binary_epilogue(r, a, b, rTest, aBuf, bBuf, "Multiplication (with result)")
binary_epilogue(r, a, b, r2Test, aBuf, bBuf, "Multiplication (in-place)")
proc invTests(gmpRng: var gmp_randstate_t, a, b, p, r: var mpz_t, C: static Curve) =
proc invTests(rng: var RngState, a, b, p, r: var mpz_t, C: static Curve) =
# We use the binary prologue epilogue but the "b" parameter is actual unused
# echo "Testing: random modular inversion on ", $C
@ -196,7 +197,7 @@ proc invTests(gmpRng: var gmp_randstate_t, a, b, p, r: var mpz_t, C: static Curv
var
aTest, bTest{.noInit.}: Fp[C]
aBuf, bBuf: array[bufLen, byte]
binary_prologue(gmpRng, a, b, p, aTest, bTest, aBuf, bBuf)
binary_prologue(rng, a, b, p, aTest, bTest, aBuf, bBuf)
let exist = mpz_invert(r, a, p)
doAssert exist != 0
@ -227,15 +228,11 @@ macro randomTests(numTests: static int, curveSym, body: untyped): untyped =
`body`
template testSetup {.dirty.} =
var gmpRng: gmp_randstate_t
gmp_randinit_mt(gmpRng)
# The GMP seed varies between run so that
# test coverage increases as the library gets tested.
# This requires to dump the seed in the console or the function inputs
# to be able to reproduce a bug
var rng: RngState
let seed = uint32(getTime().toUnix() and (1'i64 shl 32 - 1)) # unixTime mod 2^32
echo "GMP seed: ", seed
gmp_randseed_ui(gmpRng, seed)
rng.seed(seed)
echo "\n------------------------------------------------------\n"
echo "test_finite_fields_vs_gmp** seed: ", seed
var a, b, p, r: mpz_t
mpz_init(a)
@ -247,25 +244,25 @@ proc mainMul() =
testSetup()
echo "Testing modular multiplications vs GMP"
randomTests(24, curve):
mulTests(gmpRng, a, b, p, r, curve)
mulTests(rng, a, b, p, r, curve)
proc mainAdd() =
testSetup()
echo "Testing modular additions vs GMP"
randomTests(24, curve):
addTests(gmpRng, a, b, p, r, curve)
addTests(rng, a, b, p, r, curve)
proc mainSub() =
testSetup()
echo "Testing modular substractions vs GMP"
randomTests(24, curve):
subTests(gmpRng, a, b, p, r, curve)
subTests(rng, a, b, p, r, curve)
proc mainInv() =
testSetup()
echo "Testing modular inversions vs GMP"
randomTests(24, curve):
invTests(gmpRng, a, b, p, r, curve)
invTests(rng, a, b, p, r, curve)
mainMul()

View File

@ -43,8 +43,8 @@ proc SHA256_OpenSSL[T: byte|char](
# --------------------------------------------------------------------
echo "\n------------------------------------------------------\n"
const SmallSizeIters = 128
const LargeSizeIters = 10
const SmallSizeIters = 64
const LargeSizeIters = 1
proc sanityABC =
var bufCt: array[32, byte]