mirror of
https://github.com/logos-storage/constantine.git
synced 2026-01-02 21:23:11 +00:00
G2 / Operations on the twisted curve E'(Fp2) (#51)
* Split elliptic curve tests to better use parallel testing * Add support for printing points on G2 * Implement multiplication and division by optimal sextic non-residue (BLS12-381) * Implement modular square root in 𝔽p2 * Support EC add and EC double on G2 (for BLS12-381) * Support G2 divisive twists with non-unit sextic-non-residue like BN254 snarks * Add EC G2 bench * cleanup some unused warnings * Reorg the tests for parallelization and to avoid instantiating huge files
This commit is contained in:
parent
2613356281
commit
d376f08d1b
@ -59,7 +59,7 @@ proc main() =
|
||||
separator()
|
||||
scalarMulGenericBench(ECP_SWei_Proj[Fp[curve]], scratchSpaceSize = 1 shl 4, MulIters)
|
||||
separator()
|
||||
scalarMulGLV(ECP_SWei_Proj[Fp[curve]], MulIters)
|
||||
scalarMulEndo(ECP_SWei_Proj[Fp[curve]], MulIters)
|
||||
separator()
|
||||
separator()
|
||||
|
||||
|
||||
72
benchmarks/bench_ec_g2.nim
Normal file
72
benchmarks/bench_ec_g2.nim
Normal file
@ -0,0 +1,72 @@
|
||||
# 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/config/curves,
|
||||
../constantine/arithmetic,
|
||||
../constantine/towers,
|
||||
../constantine/elliptic/ec_weierstrass_projective,
|
||||
# Helpers
|
||||
../helpers/static_for,
|
||||
./bench_elliptic_template,
|
||||
# Standard library
|
||||
std/strutils
|
||||
|
||||
# ############################################################
|
||||
#
|
||||
# Benchmark of the G1 group of
|
||||
# Short Weierstrass elliptic curves
|
||||
# in (homogeneous) projective coordinates
|
||||
#
|
||||
# ############################################################
|
||||
|
||||
|
||||
const Iters = 500_000
|
||||
const MulIters = 500
|
||||
const AvailableCurves = [
|
||||
# P224,
|
||||
# BN254_Nogami,
|
||||
BN254_Snarks,
|
||||
# Curve25519,
|
||||
# P256,
|
||||
# Secp256k1,
|
||||
# BLS12_377,
|
||||
BLS12_381,
|
||||
# BN446,
|
||||
# FKM12_447,
|
||||
# BLS12_461,
|
||||
# BN462
|
||||
]
|
||||
|
||||
proc main() =
|
||||
separator()
|
||||
staticFor i, 0, AvailableCurves.len:
|
||||
const curve = AvailableCurves[i]
|
||||
addBench(ECP_SWei_Proj[Fp2[curve]], Iters)
|
||||
separator()
|
||||
doublingBench(ECP_SWei_Proj[Fp2[curve]], Iters)
|
||||
separator()
|
||||
scalarMulUnsafeDoubleAddBench(ECP_SWei_Proj[Fp2[curve]], MulIters)
|
||||
separator()
|
||||
scalarMulGenericBench(ECP_SWei_Proj[Fp2[curve]], scratchSpaceSize = 1 shl 2, MulIters)
|
||||
separator()
|
||||
scalarMulGenericBench(ECP_SWei_Proj[Fp2[curve]], scratchSpaceSize = 1 shl 3, MulIters)
|
||||
separator()
|
||||
scalarMulGenericBench(ECP_SWei_Proj[Fp2[curve]], scratchSpaceSize = 1 shl 4, MulIters)
|
||||
separator()
|
||||
# scalarMulEndo(ECP_SWei_Proj[Fp2[curve]], MulIters)
|
||||
# separator()
|
||||
separator()
|
||||
|
||||
main()
|
||||
|
||||
echo "\nNotes:"
|
||||
echo " - GCC is significantly slower than Clang on multiprecision arithmetic."
|
||||
echo " - The simplest operations might be optimized away by the compiler."
|
||||
echo " - Fast Squaring and Fast Multiplication are possible if there are spare bits in the prime representation (i.e. the prime uses 254 bits out of 256 bits)"
|
||||
@ -111,20 +111,23 @@ template bench(op: string, T: typedesc, iters: int, body: untyped): untyped =
|
||||
report(op, fixEllipticDisplay(T), start, stop, startClk, stopClk, iters)
|
||||
|
||||
proc addBench*(T: typedesc, iters: int) =
|
||||
const G1_or_G2 = when T.F is Fp: "G1" else: "G2"
|
||||
var r {.noInit.}: T
|
||||
let P = rng.random_unsafe(T)
|
||||
let Q = rng.random_unsafe(T)
|
||||
bench("EC Add G1", T, iters):
|
||||
bench("EC Add " & G1_or_G2, T, iters):
|
||||
r.sum(P, Q)
|
||||
|
||||
proc doublingBench*(T: typedesc, iters: int) =
|
||||
const G1_or_G2 = when T.F is Fp: "G1" else: "G2"
|
||||
var r {.noInit.}: T
|
||||
let P = rng.random_unsafe(T)
|
||||
bench("EC Double G1", T, iters):
|
||||
bench("EC Double " & G1_or_G2, T, iters):
|
||||
r.double(P)
|
||||
|
||||
proc scalarMulGenericBench*(T: typedesc, scratchSpaceSize: static int, iters: int) =
|
||||
const bits = T.F.C.getCurveOrderBitwidth()
|
||||
const G1_or_G2 = when T.F is Fp: "G1" else: "G2"
|
||||
|
||||
var r {.noInit.}: T
|
||||
let P = rng.random_unsafe(T) # TODO: clear cofactor
|
||||
@ -135,24 +138,29 @@ proc scalarMulGenericBench*(T: typedesc, scratchSpaceSize: static int, iters: in
|
||||
|
||||
var scratchSpace{.noInit.}: array[scratchSpaceSize, T]
|
||||
|
||||
bench("EC ScalarMul Generic G1 (scratchsize = " & $scratchSpaceSize & ')', T, iters):
|
||||
bench("EC ScalarMul Generic " & G1_or_G2 & " (scratchsize = " & $scratchSpaceSize & ')', T, iters):
|
||||
r = P
|
||||
r.scalarMulGeneric(exponentCanonical, scratchSpace)
|
||||
|
||||
proc scalarMulGLV*(T: typedesc, iters: int) =
|
||||
proc scalarMulEndo*(T: typedesc, iters: int) =
|
||||
const bits = T.F.C.getCurveOrderBitwidth()
|
||||
const G1_or_G2 = when T.F is Fp: "G1" else: "G2"
|
||||
|
||||
var r {.noInit.}: T
|
||||
let P = rng.random_unsafe(T) # TODO: clear cofactor
|
||||
|
||||
let exponent = rng.random_unsafe(BigInt[bits])
|
||||
|
||||
bench("EC ScalarMul G1 (GLV endomorphism accelerated)", T, iters):
|
||||
bench("EC ScalarMul " & G1_or_G2 & " (endomorphism accelerated)", T, iters):
|
||||
r = P
|
||||
r.scalarMulGLV(exponent)
|
||||
when T.F is Fp:
|
||||
r.scalarMulGLV(exponent)
|
||||
else:
|
||||
{.error: "Not implemented".}
|
||||
|
||||
proc scalarMulUnsafeDoubleAddBench*(T: typedesc, iters: int) =
|
||||
const bits = T.F.C.getCurveOrderBitwidth()
|
||||
const G1_or_G2 = when T.F is Fp: "G1" else: "G2"
|
||||
|
||||
var r {.noInit.}: T
|
||||
let P = rng.random_unsafe(T) # TODO: clear cofactor
|
||||
@ -161,6 +169,6 @@ proc scalarMulUnsafeDoubleAddBench*(T: typedesc, iters: int) =
|
||||
var exponentCanonical{.noInit.}: array[(bits+7) div 8, byte]
|
||||
exponentCanonical.exportRawUint(exponent, bigEndian)
|
||||
|
||||
bench("EC ScalarMul G1 (unsafe reference DoubleAdd)", T, iters):
|
||||
bench("EC ScalarMul " & G1_or_G2 & " (unsafe reference DoubleAdd)", T, iters):
|
||||
r = P
|
||||
r.unsafe_ECmul_double_add(exponentCanonical)
|
||||
|
||||
@ -5,12 +5,67 @@ description = "This library provides constant time big int primitives."
|
||||
license = "MIT or Apache License 2.0"
|
||||
srcDir = "src"
|
||||
|
||||
### Dependencies
|
||||
# Dependencies
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
requires "nim >= 1.1.0"
|
||||
|
||||
# Test config
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
const buildParallel = "test_parallel.txt"
|
||||
|
||||
### Helper functions
|
||||
const testDesc: seq[tuple[path: string, useGMP: bool]] = @[
|
||||
# Primitives
|
||||
("tests/test_primitives.nim", false),
|
||||
# Big ints
|
||||
("tests/test_io_bigints.nim", false),
|
||||
("tests/test_bigints.nim", false),
|
||||
("tests/test_bigints_multimod.nim", false),
|
||||
("tests/test_bigints_mod_vs_gmp.nim", true),
|
||||
("tests/test_bigints_mul_vs_gmp.nim", true),
|
||||
("tests/test_bigints_mul_high_words_vs_gmp.nim", true),
|
||||
# Field
|
||||
("tests/test_io_fields", false),
|
||||
("tests/test_finite_fields.nim", false),
|
||||
("tests/test_finite_fields_mulsquare.nim", false),
|
||||
("tests/test_finite_fields_sqrt.nim", false),
|
||||
("tests/test_finite_fields_powinv.nim", false),
|
||||
("tests/test_finite_fields_vs_gmp.nim", true),
|
||||
# Precompute
|
||||
("tests/test_precomputed", false),
|
||||
# Towers of extension fields
|
||||
("tests/test_fp2.nim", false),
|
||||
("tests/test_fp2_sqrt.nim", false),
|
||||
("tests/test_fp6_bn254_snarks.nim", false),
|
||||
("tests/test_fp6_bls12_377.nim", false),
|
||||
("tests/test_fp6_bls12_381.nim", false),
|
||||
("tests/test_fp12_bn254_snarks.nim", false),
|
||||
("tests/test_fp12_bls12_377.nim", false),
|
||||
("tests/test_fp12_bls12_381.nim", false),
|
||||
# Elliptic curve arithmetic G1
|
||||
("tests/test_ec_weierstrass_projective_g1_add_double.nim", false),
|
||||
("tests/test_ec_weierstrass_projective_g1_mul_sanity.nim", false),
|
||||
("tests/test_ec_weierstrass_projective_g1_mul_distributive.nim", false),
|
||||
("tests/test_ec_weierstrass_projective_g1_mul_vs_ref.nim", false),
|
||||
# Elliptic curve arithmetic G2
|
||||
("tests/test_ec_weierstrass_projective_g2_add_double_bn254_snarks.nim", false),
|
||||
("tests/test_ec_weierstrass_projective_g2_mul_sanity_bn254_snarks.nim", false),
|
||||
("tests/test_ec_weierstrass_projective_g2_mul_distributive_bn254_snarks.nim", false),
|
||||
("tests/test_ec_weierstrass_projective_g2_mul_vs_ref_bn254_snarks.nim", false),
|
||||
|
||||
("tests/test_ec_weierstrass_projective_g2_add_double_bls12_381.nim", false),
|
||||
("tests/test_ec_weierstrass_projective_g2_mul_sanity_bls12_381.nim", false),
|
||||
("tests/test_ec_weierstrass_projective_g2_mul_distributive_bls12_381.nim", false),
|
||||
("tests/test_ec_weierstrass_projective_g2_mul_vs_ref_bls12_381.nim", false),
|
||||
# Elliptic curve arithmetic vs Sagemath
|
||||
("tests/test_ec_sage_bn254.nim", false),
|
||||
("tests/test_ec_sage_bls12_381.nim", false)
|
||||
]
|
||||
|
||||
# Helper functions
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
proc test(flags, path: string, commandFile = false) =
|
||||
# commandFile should be a "file" but Nimscript doesn't support IO
|
||||
# TODO: use a proper runner
|
||||
@ -28,9 +83,9 @@ proc test(flags, path: string, commandFile = false) =
|
||||
let command = "nim " & lang & cc & " " & flags & " --verbosity:0 --outdir:build -r --hints:off --warnings:off " & path
|
||||
|
||||
if not commandFile:
|
||||
echo "\n========================================================================================"
|
||||
echo "\n=============================================================================================="
|
||||
echo "Running [flags: ", flags, "] ", path
|
||||
echo "========================================================================================"
|
||||
echo "=============================================================================================="
|
||||
exec command
|
||||
else:
|
||||
# commandFile.writeLine command
|
||||
@ -47,74 +102,18 @@ proc runBench(benchName: string, compiler = "") =
|
||||
" -d:danger --verbosity:0 -o:build/" & benchName & "_" & compiler &
|
||||
" -r --hints:off --warnings:off benchmarks/" & benchName & ".nim"
|
||||
|
||||
### tasks
|
||||
# Tasks
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
task test, "Run all tests":
|
||||
# -d:testingCurves is configured in a *.nim.cfg for convenience
|
||||
|
||||
# Primitives
|
||||
test "", "tests/test_primitives.nim"
|
||||
|
||||
# Big ints
|
||||
test "", "tests/test_io_bigints.nim"
|
||||
test "", "tests/test_bigints.nim"
|
||||
test "", "tests/test_bigints_multimod.nim"
|
||||
|
||||
test "", "tests/test_bigints_mod_vs_gmp.nim"
|
||||
|
||||
# Field
|
||||
test "", "tests/test_io_fields"
|
||||
test "", "tests/test_finite_fields.nim"
|
||||
test "", "tests/test_finite_fields_mulsquare.nim"
|
||||
test "", "tests/test_finite_fields_sqrt.nim"
|
||||
test "", "tests/test_finite_fields_powinv.nim"
|
||||
|
||||
test "", "tests/test_finite_fields_vs_gmp.nim"
|
||||
|
||||
# Precompute
|
||||
test "", "tests/test_precomputed"
|
||||
|
||||
# Towers of extension fields
|
||||
test "", "tests/test_fp2.nim"
|
||||
test "", "tests/test_fp6.nim"
|
||||
test "", "tests/test_fp12.nim"
|
||||
|
||||
# Elliptic curve arithmetic
|
||||
test "", "tests/test_ec_weierstrass_projective_g1.nim"
|
||||
test "", "tests/test_ec_bn254.nim"
|
||||
test "", "tests/test_ec_bls12_381.nim"
|
||||
for td in testDesc:
|
||||
test "", td.path
|
||||
|
||||
if sizeof(int) == 8: # 32-bit tests on 64-bit arch
|
||||
# Primitives
|
||||
test "-d:Constantine32", "tests/test_primitives.nim"
|
||||
|
||||
# Big ints
|
||||
test "-d:Constantine32", "tests/test_io_bigints.nim"
|
||||
test "-d:Constantine32", "tests/test_bigints.nim"
|
||||
test "-d:Constantine32", "tests/test_bigints_multimod.nim"
|
||||
|
||||
test "-d:Constantine32", "tests/test_bigints_mod_vs_gmp.nim"
|
||||
|
||||
# Field
|
||||
test "-d:Constantine32", "tests/test_io_fields"
|
||||
test "-d:Constantine32", "tests/test_finite_fields.nim"
|
||||
test "-d:Constantine32", "tests/test_finite_fields_mulsquare.nim"
|
||||
test "-d:Constantine32", "tests/test_finite_fields_sqrt.nim"
|
||||
test "-d:Constantine32", "tests/test_finite_fields_powinv.nim"
|
||||
|
||||
test "-d:Constantine32", "tests/test_finite_fields_vs_gmp.nim"
|
||||
|
||||
# Precompute
|
||||
test "-d:Constantine32", "tests/test_precomputed"
|
||||
|
||||
# Towers of extension fields
|
||||
test "-d:Constantine32", "tests/test_fp2.nim"
|
||||
test "-d:Constantine32", "tests/test_fp6.nim"
|
||||
test "-d:Constantine32", "tests/test_fp12.nim"
|
||||
|
||||
# Elliptic curve arithmetic
|
||||
test "-d:Constantine32", "tests/test_ec_weierstrass_projective_g1.nim"
|
||||
test "-d:Constantine32", "tests/test_ec_bn254.nim"
|
||||
test "-d:Constantine32", "tests/test_ec_bls12_381.nim"
|
||||
for td in testDesc:
|
||||
test "-d:Constantine32", td.path
|
||||
|
||||
# Benchmarks compile and run
|
||||
# ignore Windows 32-bit for the moment
|
||||
@ -125,66 +124,18 @@ task test, "Run all tests":
|
||||
runBench("bench_fp6")
|
||||
runBench("bench_fp12")
|
||||
runBench("bench_ec_g1")
|
||||
runBench("bench_ec_g2")
|
||||
|
||||
task test_no_gmp, "Run tests that don't require GMP":
|
||||
# -d:testingCurves is configured in a *.nim.cfg for convenience
|
||||
for td in testDesc:
|
||||
if not td.useGMP:
|
||||
test "", td.path
|
||||
|
||||
# Primitives
|
||||
test "", "tests/test_primitives.nim"
|
||||
|
||||
# Big ints
|
||||
test "", "tests/test_io_bigints.nim"
|
||||
test "", "tests/test_bigints.nim"
|
||||
test "", "tests/test_bigints_multimod.nim"
|
||||
|
||||
# Field
|
||||
test "", "tests/test_io_fields"
|
||||
test "", "tests/test_finite_fields.nim"
|
||||
test "", "tests/test_finite_fields_mulsquare.nim"
|
||||
test "", "tests/test_finite_fields_sqrt.nim"
|
||||
test "", "tests/test_finite_fields_powinv.nim"
|
||||
|
||||
# Precompute
|
||||
test "", "tests/test_precomputed"
|
||||
|
||||
# Towers of extension fields
|
||||
test "", "tests/test_fp2.nim"
|
||||
test "", "tests/test_fp6.nim"
|
||||
test "", "tests/test_fp12.nim"
|
||||
|
||||
# Elliptic curve arithmetic
|
||||
test "", "tests/test_ec_weierstrass_projective_g1.nim"
|
||||
test "", "tests/test_ec_bn254.nim"
|
||||
test "", "tests/test_ec_bls12_381.nim"
|
||||
|
||||
if sizeof(int) == 8: # 32-bit tests
|
||||
# Primitives
|
||||
test "-d:Constantine32", "tests/test_primitives.nim"
|
||||
|
||||
# Big ints
|
||||
test "-d:Constantine32", "tests/test_io_bigints.nim"
|
||||
test "-d:Constantine32", "tests/test_bigints.nim"
|
||||
test "-d:Constantine32", "tests/test_bigints_multimod.nim"
|
||||
|
||||
# Field
|
||||
test "-d:Constantine32", "tests/test_io_fields"
|
||||
test "-d:Constantine32", "tests/test_finite_fields.nim"
|
||||
test "-d:Constantine32", "tests/test_finite_fields_mulsquare.nim"
|
||||
test "-d:Constantine32", "tests/test_finite_fields_sqrt.nim"
|
||||
test "-d:Constantine32", "tests/test_finite_fields_powinv.nim"
|
||||
|
||||
# Precompute
|
||||
test "-d:Constantine32", "tests/test_precomputed"
|
||||
|
||||
# Towers of extension fields
|
||||
test "-d:Constantine32", "tests/test_fp2.nim"
|
||||
test "-d:Constantine32", "tests/test_fp6.nim"
|
||||
test "-d:Constantine32", "tests/test_fp12.nim"
|
||||
|
||||
# Elliptic curve arithmetic
|
||||
test "-d:Constantine32", "tests/test_ec_weierstrass_projective_g1.nim"
|
||||
test "-d:Constantine32", "tests/test_ec_bn254.nim"
|
||||
test "-d:Constantine32", "tests/test_ec_bls12_381.nim"
|
||||
if sizeof(int) == 8: # 32-bit tests on 64-bit arch
|
||||
for td in testDesc:
|
||||
if not td.useGMP:
|
||||
test "-d:Constantine32", td.path
|
||||
|
||||
# Benchmarks compile and run
|
||||
# ignore Windows 32-bit for the moment
|
||||
@ -195,79 +146,24 @@ task test_no_gmp, "Run tests that don't require GMP":
|
||||
runBench("bench_fp6")
|
||||
runBench("bench_fp12")
|
||||
runBench("bench_ec_g1")
|
||||
runBench("bench_ec_g2")
|
||||
|
||||
task test_parallel, "Run all tests in parallel (via GNU parallel)":
|
||||
# -d:testingCurves is configured in a *.nim.cfg for convenience
|
||||
let cmdFile = true # open(buildParallel, mode = fmWrite) # Nimscript doesn't support IO :/
|
||||
exec "> " & buildParallel
|
||||
|
||||
# Primitives
|
||||
test "", "tests/test_primitives.nim", cmdFile
|
||||
|
||||
# Big ints
|
||||
test "", "tests/test_io_bigints.nim", cmdFile
|
||||
test "", "tests/test_bigints.nim", cmdFile
|
||||
test "", "tests/test_bigints_multimod.nim", cmdFile
|
||||
|
||||
test "", "tests/test_bigints_mul_vs_gmp.nim", cmdFile
|
||||
test "", "tests/test_bigints_mod_vs_gmp.nim", cmdFile
|
||||
|
||||
# Field
|
||||
test "", "tests/test_io_fields", cmdFile
|
||||
test "", "tests/test_finite_fields.nim", cmdFile
|
||||
test "", "tests/test_finite_fields_mulsquare.nim", cmdFile
|
||||
test "", "tests/test_finite_fields_sqrt.nim", cmdFile
|
||||
test "", "tests/test_finite_fields_powinv.nim", cmdFile
|
||||
|
||||
test "", "tests/test_finite_fields_vs_gmp.nim", cmdFile
|
||||
|
||||
# Towers of extension fields
|
||||
test "", "tests/test_fp2.nim", cmdFile
|
||||
test "", "tests/test_fp6.nim", cmdFile
|
||||
test "", "tests/test_fp12.nim", cmdFile
|
||||
|
||||
# Elliptic curve arithmetic
|
||||
test "", "tests/test_ec_weierstrass_projective_g1.nim", cmdFile
|
||||
test "", "tests/test_ec_bn254.nim", cmdFile
|
||||
test "", "tests/test_ec_bls12_381.nim", cmdFile
|
||||
for td in testDesc:
|
||||
test "", td.path, cmdFile
|
||||
|
||||
# cmdFile.close()
|
||||
# Execute everything in parallel with GNU parallel
|
||||
exec "parallel --keep-order --group < " & buildParallel
|
||||
|
||||
exec "> " & buildParallel
|
||||
|
||||
if sizeof(int) == 8: # 32-bit tests on 64-bit arch
|
||||
# Primitives
|
||||
test "-d:Constantine32", "tests/test_primitives.nim", cmdFile
|
||||
|
||||
# Big ints
|
||||
test "-d:Constantine32", "tests/test_io_bigints.nim", cmdFile
|
||||
test "-d:Constantine32", "tests/test_bigints.nim", cmdFile
|
||||
test "-d:Constantine32", "tests/test_bigints_multimod.nim", cmdFile
|
||||
|
||||
test "-d:Constantine32", "tests/test_bigints_mul_vs_gmp.nim", cmdFile
|
||||
test "-d:Constantine32", "tests/test_bigints_mod_vs_gmp.nim", cmdFile
|
||||
|
||||
# Field
|
||||
test "-d:Constantine32", "tests/test_io_fields", cmdFile
|
||||
test "-d:Constantine32", "tests/test_finite_fields.nim", cmdFile
|
||||
test "-d:Constantine32", "tests/test_finite_fields_mulsquare.nim", cmdFile
|
||||
test "-d:Constantine32", "tests/test_finite_fields_sqrt.nim", cmdFile
|
||||
test "-d:Constantine32", "tests/test_finite_fields_powinv.nim", cmdFile
|
||||
|
||||
test "-d:Constantine32", "tests/test_finite_fields_vs_gmp.nim", cmdFile
|
||||
|
||||
# Towers of extension fields
|
||||
test "-d:Constantine32", "tests/test_fp2.nim", cmdFile
|
||||
test "-d:Constantine32", "tests/test_fp6.nim", cmdFile
|
||||
test "-d:Constantine32", "tests/test_fp12.nim", cmdFile
|
||||
|
||||
# Elliptic curve arithmetic
|
||||
test "-d:Constantine32", "tests/test_ec_weierstrass_projective_g1.nim", cmdFile
|
||||
test "-d:Constantine32", "tests/test_ec_bn254.nim", cmdFile
|
||||
test "-d:Constantine32", "tests/test_ec_bls12_381.nim", cmdFile
|
||||
|
||||
for td in testDesc:
|
||||
test "-d:Constantine32", td.path, cmdFile
|
||||
# cmdFile.close()
|
||||
# Execute everything in parallel with GNU parallel
|
||||
exec "parallel --keep-order --group < " & buildParallel
|
||||
@ -283,6 +179,7 @@ task test_parallel, "Run all tests in parallel (via GNU parallel)":
|
||||
runBench("bench_fp6")
|
||||
runBench("bench_fp12")
|
||||
runBench("bench_ec_g1")
|
||||
runBench("bench_ec_g2")
|
||||
|
||||
task bench_fp, "Run benchmark 𝔽p with your default compiler":
|
||||
runBench("bench_fp")
|
||||
@ -323,8 +220,17 @@ task bench_fp12_clang, "Run benchmark 𝔽p12 with clang":
|
||||
task bench_ec_g1, "Run benchmark on Elliptic Curve group 𝔾1 - Short Weierstrass with Projective Coordinates - GCC":
|
||||
runBench("bench_ec_g1")
|
||||
|
||||
task bench_ec_gcc, "Run benchmark on Elliptic Curve group 𝔾1 - Short Weierstrass with Projective Coordinates - GCC":
|
||||
task bench_ec_g1_gcc, "Run benchmark on Elliptic Curve group 𝔾1 - Short Weierstrass with Projective Coordinates - GCC":
|
||||
runBench("bench_ec_g1", "gcc")
|
||||
|
||||
task bench_ec_g1_clang, "Run benchmark on Elliptic Curve group 𝔾1 - Short Weierstrass with Projective Coordinates - Clang":
|
||||
runBench("bench_ec_g1", "clang")
|
||||
|
||||
task bench_ec_g2, "Run benchmark on Elliptic Curve group 𝔾2 - Short Weierstrass with Projective Coordinates - GCC":
|
||||
runBench("bench_ec_g2")
|
||||
|
||||
task bench_ec_g2_gcc, "Run benchmark on Elliptic Curve group 𝔾2 - Short Weierstrass with Projective Coordinates - GCC":
|
||||
runBench("bench_ec_g2", "gcc")
|
||||
|
||||
task bench_ec_g2_clang, "Run benchmark on Elliptic Curve group 𝔾2 - Short Weierstrass with Projective Coordinates - Clang":
|
||||
runBench("bench_ec_g2", "clang")
|
||||
|
||||
@ -301,7 +301,7 @@ func reduce*[aBits, mBits](r: var BigInt[mBits], a: BigInt[aBits], M: BigInt[mBi
|
||||
# pass a pointer+length to a fixed session of the BSS.
|
||||
reduce(r.limbs, a.limbs, aBits, M.limbs, mBits)
|
||||
|
||||
func div2mod*[bits](a: var BigInt[bits], mp1div2: BigInt[bits]) =
|
||||
func div2_modular*[bits](a: var BigInt[bits], mp1div2: BigInt[bits]) =
|
||||
## Compute a <- a/2 (mod M)
|
||||
## `mp1div2` is the modulus (M+1)/2
|
||||
##
|
||||
@ -313,7 +313,7 @@ func div2mod*[bits](a: var BigInt[bits], mp1div2: BigInt[bits]) =
|
||||
## overflowing the "Limbs" by dividing by 2 first
|
||||
## and add 1
|
||||
## Otherwise `mp1div2` should be M/2
|
||||
a.limbs.div2mod(mp1div2.limbs)
|
||||
a.limbs.div2_modular(mp1div2.limbs)
|
||||
|
||||
func steinsGCD*[bits](r: var BigInt[bits], a, F, M, mp1div2: BigInt[bits]) =
|
||||
## Compute F multiplied the modular inverse of ``a`` modulo M
|
||||
|
||||
@ -45,7 +45,7 @@ func fromBig*[C: static Curve](T: type Fp[C], src: BigInt): Fp[C] {.noInit.} =
|
||||
## Convert a BigInt to its Montgomery form
|
||||
result.mres.montyResidue(src, C.Mod, C.getR2modP(), C.getNegInvModWord(), C.canUseNoCarryMontyMul())
|
||||
|
||||
func fromBig*[C: static Curve](dst: var Fp[C], src: BigInt) {.noInit.} =
|
||||
func fromBig*[C: static Curve](dst: var Fp[C], src: BigInt) =
|
||||
## Convert a BigInt to its Montgomery form
|
||||
dst.mres.montyResidue(src, C.Mod, C.getR2modP(), C.getNegInvModWord(), C.canUseNoCarryMontyMul())
|
||||
|
||||
@ -168,7 +168,7 @@ func neg*(r: var Fp, a: Fp) =
|
||||
|
||||
func div2*(a: var Fp) =
|
||||
## Modular division by 2
|
||||
a.mres.div2mod(Fp.C.getPrimePlus1div2())
|
||||
a.mres.div2_modular(Fp.C.getPrimePlus1div2())
|
||||
|
||||
# ############################################################
|
||||
#
|
||||
@ -247,11 +247,13 @@ func isSquare*[C](a: Fp[C]): SecretBool =
|
||||
# as we assume that
|
||||
var xi {.noInit.} = a # TODO: is noInit necessary? see https://github.com/mratsim/constantine/issues/21
|
||||
xi.powUnsafeExponent(C.getPrimeMinus1div2_BE())
|
||||
result = xi.isOne()
|
||||
# 0 is also a square
|
||||
result = result or xi.isZero()
|
||||
result = not(xi.mres == C.getMontyPrimeMinus1())
|
||||
# xi can be:
|
||||
# - 1 if a square
|
||||
# - 0 if 0
|
||||
# - -1 if a quadratic non-residue
|
||||
|
||||
func sqrt_p3mod4*[C](a: var Fp[C]) =
|
||||
func sqrt_p3mod4[C](a: var Fp[C]) =
|
||||
## Compute the square root of ``a``
|
||||
##
|
||||
## This requires ``a`` to be a square
|
||||
@ -262,10 +264,10 @@ func sqrt_p3mod4*[C](a: var Fp[C]) =
|
||||
## The square root, if it exist is multivalued,
|
||||
## i.e. both x² == (-x)²
|
||||
## This procedure returns a deterministic result
|
||||
static: doAssert C.Mod.limbs[0].BaseType mod 4 == 3
|
||||
static: doAssert BaseType(C.Mod.limbs[0]) mod 4 == 3
|
||||
a.powUnsafeExponent(C.getPrimePlus1div4_BE())
|
||||
|
||||
func sqrt_if_square_p3mod4*[C](a: var Fp[C]): SecretBool =
|
||||
func sqrt_if_square_p3mod4[C](a: var Fp[C]): SecretBool =
|
||||
## If ``a`` is a square, compute the square root of ``a``
|
||||
## if not, ``a`` is unmodified.
|
||||
##
|
||||
@ -290,6 +292,33 @@ func sqrt_if_square_p3mod4*[C](a: var Fp[C]): SecretBool =
|
||||
result = not(a0.mres == C.getMontyPrimeMinus1())
|
||||
a.ccopy(a1a, result)
|
||||
|
||||
func sqrt*[C](a: var Fp[C]) =
|
||||
## Compute the square root of ``a``
|
||||
##
|
||||
## This requires ``a`` to be a square
|
||||
##
|
||||
## The result is undefined otherwise
|
||||
##
|
||||
## The square root, if it exist is multivalued,
|
||||
## i.e. both x² == (-x)²
|
||||
## This procedure returns a deterministic result
|
||||
when BaseType(C.Mod.limbs[0]) mod 4 == 3:
|
||||
sqrt_p3mod4(a)
|
||||
else:
|
||||
{.error: "Square root is only implemented for p ≡ 3 (mod 4)".}
|
||||
|
||||
func sqrt_if_square*[C](a: var Fp[C]): SecretBool =
|
||||
## If ``a`` is a square, compute the square root of ``a``
|
||||
## if not, ``a`` is unmodified.
|
||||
##
|
||||
## The square root, if it exist is multivalued,
|
||||
## i.e. both x² == (-x)²
|
||||
## This procedure returns a deterministic result
|
||||
when BaseType(C.Mod.limbs[0]) mod 4 == 3:
|
||||
result = sqrt_if_square_p3mod4(a)
|
||||
else:
|
||||
{.error: "Square root is only implemented for p ≡ 3 (mod 4)".}
|
||||
|
||||
# ############################################################
|
||||
#
|
||||
# Field arithmetic ergonomic primitives
|
||||
|
||||
@ -162,3 +162,18 @@ func inv*(r: var Fp, a: Fp) =
|
||||
# Performance is slower than GCD
|
||||
# To be revisited with faster squaring/multiplications
|
||||
r.mres.steinsGCD(a.mres, Fp.C.getR2modP(), Fp.C.Mod, Fp.C.getPrimePlus1div2())
|
||||
|
||||
func inv*(a: var Fp) =
|
||||
## Inversion modulo p
|
||||
##
|
||||
## The inverse of 0 is 0.
|
||||
## Incidentally this avoids extra check
|
||||
## to convert Jacobian and Projective coordinates
|
||||
## to affine for elliptic curve
|
||||
# For now we don't activate the addition chains
|
||||
# neither for Secp256k1 nor BN curves
|
||||
# Performance is slower than GCD
|
||||
# To be revisited with faster squaring/multiplications
|
||||
var t: typeof(a) # TODO: zero-init needed?
|
||||
t.mres.steinsGCD(a.mres, Fp.C.getR2modP(), Fp.C.Mod, Fp.C.getPrimePlus1div2())
|
||||
a = t
|
||||
|
||||
@ -20,7 +20,7 @@ import
|
||||
#
|
||||
# ############################################################
|
||||
|
||||
func div2mod*(a: var Limbs, mp1div2: Limbs) {.inline.}=
|
||||
func div2_modular*(a: var Limbs, mp1div2: Limbs) {.inline.}=
|
||||
## Modular Division by 2
|
||||
## `a` will be divided in-place
|
||||
## `mp1div2` is the modulus (M+1)/2
|
||||
@ -39,7 +39,7 @@ func div2mod*(a: var Limbs, mp1div2: Limbs) {.inline.}=
|
||||
# a = a shr 1
|
||||
let wasOdd = a.isOdd()
|
||||
a.shiftRight(1)
|
||||
let carry = a.cadd(mp1div2, wasOdd)
|
||||
let carry {.used.} = a.cadd(mp1div2, wasOdd)
|
||||
debug: doAssert not carry.bool
|
||||
|
||||
# ############################################################
|
||||
@ -133,10 +133,10 @@ func steinsGCD*(v: var Limbs, a: Limbs, F, M: Limbs, bits: int, mp1div2: Limbs)
|
||||
u.cswap(v, aLessThanB)
|
||||
# if isOddA: u -= v (mod M)
|
||||
let neg = isOddA and (SecretBool) u.csub(v, isOddA)
|
||||
let corrected = u.cadd(M, neg)
|
||||
discard u.cadd(M, neg)
|
||||
|
||||
# u = u/2 (mod M)
|
||||
u.div2mod(mp1div2)
|
||||
u.div2_modular(mp1div2)
|
||||
|
||||
debug:
|
||||
doAssert bool a.isZero()
|
||||
|
||||
@ -596,7 +596,7 @@ func montyPowUnsafeExponent*(
|
||||
acc, acc_len: uint
|
||||
e = 0
|
||||
while acc_len > 0 or e < exponent.len:
|
||||
let (k, bits) = montyPowSquarings(
|
||||
let (_, bits) = montyPowSquarings(
|
||||
a, exponent, M, m0ninv,
|
||||
scratchspace[0], window,
|
||||
acc, acc_len, e,
|
||||
|
||||
@ -65,7 +65,7 @@ func scalarMulPrologue(
|
||||
P: var ECP_SWei_Proj,
|
||||
scratchspace: var openarray[ECP_SWei_Proj]
|
||||
): uint =
|
||||
## Setup the scratchspace
|
||||
## Setup the scratchspace then set P to infinity
|
||||
## Returns the fixed-window size for scalar mul with window optimization
|
||||
result = scratchspace.len.getWindowLen()
|
||||
# Precompute window content, special case for window = 1
|
||||
@ -218,7 +218,7 @@ func scalarMul*(
|
||||
## P <- [k] P
|
||||
# This calls endomorphism accelerated scalar mul if available
|
||||
# or the generic scalar mul otherwise
|
||||
when ECP_SWei_Proj.F.C in {BN254_Snarks, BLS12_381}:
|
||||
when ECP_SWei_Proj.F is Fp and ECP_SWei_Proj.F.C in {BN254_Snarks, BLS12_381}:
|
||||
# ⚠️ This requires the cofactor to be cleared
|
||||
scalarMulGLV(P, scalar)
|
||||
else:
|
||||
|
||||
@ -23,15 +23,29 @@ func curve_eq_rhs*[F](y2: var F, x: F) =
|
||||
t.square(x)
|
||||
t *= x
|
||||
|
||||
# No need to precompute `b` in 𝔽p or 𝔽p² or `b/µ` `µ b`
|
||||
# This procedure is not use in perf critcal situation like signing/verification
|
||||
# This procedure is not use in perf critical situation like signing/verification
|
||||
# but for testing to quickly create points on a curve.
|
||||
y2 = F.fromBig F.C.matchingBigInt().fromUint F.C.getCoefB()
|
||||
# That said D-Twists require an inversion
|
||||
# and we could avoid doing `b/µ` or `µ*b` at runtime on 𝔽p²
|
||||
# which would accelerate random point generation
|
||||
#
|
||||
# This is preferred to generating random point
|
||||
# via random scalar multiplication of the curve generator
|
||||
# as the latter assumes:
|
||||
# - point addition, doubling work
|
||||
# - scalar multiplication works
|
||||
# - a generator point is defined
|
||||
# i.e. you can't test unless everything is already working
|
||||
#
|
||||
# TODO: precomputation needed when deserializing points
|
||||
# to check if a point is on-curve and prevent denial-of-service
|
||||
# using slow inversion.
|
||||
y2.fromBig F.C.matchingBigInt().fromUint F.C.getCoefB()
|
||||
when F is Fp2:
|
||||
when F.C.getSexticTwist() == D_Twist:
|
||||
y2 /= F.C.get_SNR_Fp2()
|
||||
y2 /= SexticNonResidue
|
||||
elif F.C.getSexticTwist() == M_Twist:
|
||||
y2 *= F.C.get_SNR_Fp2()
|
||||
y2 *= SexticNonResidue
|
||||
else:
|
||||
{.error: "Only twisted curves are supported on extension field 𝔽p²".}
|
||||
|
||||
|
||||
@ -81,7 +81,7 @@ func trySetFromCoordsXandZ*[F](P: var ECP_SWei_Proj[F], x, z: F): SecretBool =
|
||||
## will be provided, this is intended for testing purposes.
|
||||
P.y.curve_eq_rhs(x)
|
||||
# TODO: supports non p ≡ 3 (mod 4) modulus like BLS12-377
|
||||
result = sqrt_if_square_p3mod4(P.y)
|
||||
result = sqrt_if_square(P.y)
|
||||
|
||||
P.x.prod(x, z)
|
||||
P.y *= z
|
||||
@ -100,7 +100,7 @@ func trySetFromCoordX*[F](P: var ECP_SWei_Proj[F], x: F): SecretBool =
|
||||
## will be provided, this is intended for testing purposes.
|
||||
P.y.curve_eq_rhs(x)
|
||||
# TODO: supports non p ≡ 3 (mod 4) modulus like BLS12-377
|
||||
result = sqrt_if_square_p3mod4(P.y)
|
||||
result = sqrt_if_square(P.y)
|
||||
P.x = x
|
||||
P.z.setOne()
|
||||
|
||||
@ -178,32 +178,32 @@ func sum*[F](
|
||||
t4.sum(t0, t1) # 7. t4 <- t0 + t1
|
||||
t3 -= t4 # 8. t3 <- t3 - t4 t3 = (X1 + Y1)(X2 + Y2) - (X1 X2 + Y1 Y2) = X1.Y2 + X2.Y1
|
||||
when F is Fp2 and F.C.getSexticTwist() == D_Twist:
|
||||
t3 *= F.sexticNonResidue()
|
||||
t3 *= SexticNonResidue
|
||||
t4.sum(P.y, P.z) # 9. t4 <- Y1 + Z1
|
||||
r.x.sum(Q.y, Q.z) # 10. X3 <- Y2 + Z2
|
||||
t4 *= r.x # 11. t4 <- t4 X3
|
||||
r.x.sum(t1, t2) # 12. X3 <- t1 + t2 X3 = Y1 Y2 + Z1 Z2
|
||||
t4 -= r.x # 13. t4 <- t4 - X3 t4 = (Y1 + Z1)(Y2 + Z2) - (Y1 Y2 + Z1 Z2) = Y1 Z2 + Y2 Z1
|
||||
when F is Fp2 and F.C.getSexticTwist() == D_Twist:
|
||||
t4 *= F.sexticNonResidue()
|
||||
t4 *= SexticNonResidue
|
||||
r.x.sum(P.x, P.z) # 14. X3 <- X1 + Z1
|
||||
r.y.sum(Q.x, Q.z) # 15. Y3 <- X2 + Z2
|
||||
r.x *= r.y # 16. X3 <- X3 Y3 X3 = (X1 Z1)(X2 Z2)
|
||||
r.y.sum(t0, t2) # 17. Y3 <- t0 + t2 Y3 = X1 X2 + Z1 Z2
|
||||
r.y.diff(r.x, r.y) # 18. Y3 <- X3 - Y3 Y3 = (X1 + Z1)(X2 + Z2) - (X1 X2 + Z1 Z2) = X1 Z2 + X2 Z1
|
||||
when F is Fp2 and F.C.getSexticTwist() == D_Twist:
|
||||
t0 *= F.sexticNonResidue()
|
||||
t1 *= F.sexticNonResidue()
|
||||
t0 *= SexticNonResidue
|
||||
t1 *= SexticNonResidue
|
||||
r.x.double(t0) # 19. X3 <- t0 + t0 X3 = 2 X1 X2
|
||||
t0 += r.x # 20. t0 <- X3 + t0 t0 = 3 X1 X2
|
||||
t2 *= b3 # 21. t2 <- b3 t2 t2 = 3b Z1 Z2
|
||||
when F is Fp2 and F.C.getSexticTwist() == M_Twist:
|
||||
t2 *= F.sexticNonResidue()
|
||||
t2 *= SexticNonResidue
|
||||
r.z.sum(t1, t2) # 22. Z3 <- t1 + t2 Z3 = Y1 Y2 + 3b Z1 Z2
|
||||
t1 -= t2 # 23. t1 <- t1 - t2 t1 = Y1 Y2 - 3b Z1 Z2
|
||||
r.y *= b3 # 24. Y3 <- b3 Y3 Y3 = 3b(X1 Z2 + X2 Z1)
|
||||
when F is Fp2 and F.C.getSexticTwist() == M_Twist:
|
||||
r.y *= F.sexticNonResidue()
|
||||
r.y *= SexticNonResidue
|
||||
r.x.prod(t4, r.y) # 25. X3 <- t4 Y3 X3 = 3b(Y1 Z2 + Y2 Z1)(X1 Z2 + X2 Z1)
|
||||
t2.prod(t3, t1) # 26. t2 <- t3 t1 t2 = (X1 Y2 + X2 Y1) (Y1 Y2 - 3b Z1 Z2)
|
||||
r.x.diff(t2, r.x) # 27. X3 <- t2 - X3 X3 = (X1 Y2 + X2 Y1) (Y1 Y2 - 3b Z1 Z2) - 3b(Y1 Z2 + Y2 Z1)(X1 Z2 + X2 Z1)
|
||||
@ -252,7 +252,7 @@ func double*[F](
|
||||
# Cost: 8M + 3S + 3 mul(a) + 2 mul(3b) + 15a
|
||||
|
||||
when F.C.getCoefA() == 0:
|
||||
var t0 {.noInit.}, t1 {.noInit.}, t2 {.noInit.}: F
|
||||
var t0 {.noInit.}, t1 {.noInit.}, t2 {.noInit.}, snrY {.noInit.}: F
|
||||
const b3 = 3 * F.C.getCoefB()
|
||||
|
||||
# Algorithm 9 for curves:
|
||||
@ -261,14 +261,21 @@ func double*[F](
|
||||
# X3 = 2XY(Y² - 9bZ²)
|
||||
# Y3 = (Y² - 9bZ²)(Y² + 3bZ²) + 24bY²Z²
|
||||
# Z3 = 8Y³Z
|
||||
|
||||
t0.square(P.y) # 1. t0 <- Y Y
|
||||
snrY = P.y
|
||||
when F is Fp2 and F.C.getSexticTwist() == D_Twist:
|
||||
snrY *= SexticNonResidue
|
||||
t0.square(P.y)
|
||||
t0 *= SexticNonResidue
|
||||
else:
|
||||
t0.square(P.y) # 1. t0 <- Y Y
|
||||
r.z.double(t0) # 2. Z3 <- t0 + t0
|
||||
r.z.double() # 3. Z3 <- Z3 + Z3
|
||||
r.z.double() # 4. Z3 <- Z3 + Z3 Z3 = 8Y²
|
||||
t1.prod(P.y, P.z) # 5. t1 <- Y Z
|
||||
t1.prod(snrY, P.z) # 5. t1 <- Y Z
|
||||
t2.square(P.z) # 6. t2 <- Z Z
|
||||
t2 *= b3 # 7. t2 <- b3 t2
|
||||
when F is Fp2 and F.C.getSexticTwist() == M_Twist:
|
||||
t2 *= SexticNonResidue
|
||||
r.x.prod(t2, r.z) # 8. X3 <- t2 Z3
|
||||
r.y.sum(t0, t2) # 9. Y3 <- t0 + t2
|
||||
r.z *= t1 # 10. Z3 <- t1 Z3
|
||||
@ -277,7 +284,7 @@ func double*[F](
|
||||
t0 -= t2 # 13. t0 <- t0 - t2
|
||||
r.y *= t0 # 14. Y3 <- t0 Y3
|
||||
r.y += r.x # 15. Y3 <- X3 + Y3
|
||||
t1.prod(P.x, P.y) # 16. t1 <- X Y
|
||||
t1.prod(P.x, snrY) # 16. t1 <- X Y
|
||||
r.x.prod(t0, t1) # 17. X3 <- t0 t1
|
||||
r.x.double() # 18. X3 <- X3 + X3
|
||||
else:
|
||||
|
||||
@ -428,6 +428,27 @@ func fromHex*(T: type BigInt, s: string): T {.noInit.} =
|
||||
# 2. Convert canonical uint to Big Int
|
||||
result.fromRawUint(bytes, bigEndian)
|
||||
|
||||
func appendHex*(dst: var string, big: BigInt, order: static Endianness = bigEndian) =
|
||||
## Append the BigInt hex into an accumulator
|
||||
## Note. Leading zeros are not removed.
|
||||
## Result is prefixed with 0x
|
||||
##
|
||||
## Output will be padded with 0s to maintain constant-time.
|
||||
##
|
||||
## CT:
|
||||
## - no leaks
|
||||
##
|
||||
## This is useful to reduce the number of allocations when serializing
|
||||
## Fp towers
|
||||
|
||||
# 1. Convert Big Int to canonical uint
|
||||
const canonLen = (big.bits + 8 - 1) div 8
|
||||
var bytes: array[canonLen, byte]
|
||||
exportRawUint(bytes, big, cpuEndian)
|
||||
|
||||
# 2 Convert canonical uint to hex
|
||||
dst.add bytes.nativeEndianToHex(order)
|
||||
|
||||
func toHex*(big: BigInt, order: static Endianness = bigEndian): string =
|
||||
## Stringify an int to hex.
|
||||
## Note. Leading zeros are not removed.
|
||||
@ -437,11 +458,4 @@ func toHex*(big: BigInt, order: static Endianness = bigEndian): string =
|
||||
##
|
||||
## CT:
|
||||
## - no leaks
|
||||
|
||||
# 1. Convert Big Int to canonical uint
|
||||
const canonLen = (big.bits + 8 - 1) div 8
|
||||
var bytes: array[canonLen, byte]
|
||||
exportRawUint(bytes, big, cpuEndian)
|
||||
|
||||
# 2 Convert canonical uint to hex
|
||||
result = bytes.nativeEndianToHex(order)
|
||||
result.appendHex(big, order)
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
./io_bigints, ./io_fields,
|
||||
./io_bigints, ./io_fields, ./io_towers,
|
||||
../config/curves,
|
||||
../elliptic/[
|
||||
ec_weierstrass_affine,
|
||||
@ -41,11 +41,11 @@ func toHex*(P: ECP_SWei_Proj): string =
|
||||
var aff {.noInit.}: typeof(P)
|
||||
aff.affineFromProjective(P)
|
||||
|
||||
result = $aff.F.C & "(x: "
|
||||
result &= aff.x.tohex(bigEndian)
|
||||
result &= ", y: "
|
||||
result &= aff.y.tohex(bigEndian)
|
||||
result &= ')'
|
||||
result = "ECP[" & $aff.F & "](\n x: "
|
||||
result.appendHex(aff.x, bigEndian)
|
||||
result &= ",\n y: "
|
||||
result.appendHex(aff.y, bigEndian)
|
||||
result &= "\n)"
|
||||
|
||||
func fromHex*(dst: var ECP_SWei_Proj, x, y: string): bool {.raises: [ValueError].}=
|
||||
## Convert hex strings to a curve point
|
||||
|
||||
@ -42,6 +42,17 @@ func exportRawUint*(dst: var openarray[byte],
|
||||
## I.e least significant bit is aligned to buffer boundary
|
||||
exportRawUint(dst, src.toBig(), dstEndianness)
|
||||
|
||||
func appendHex*(dst: var string, f: Fp, order: static Endianness = bigEndian) =
|
||||
## Stringify a finite field element to hex.
|
||||
## Note. Leading zeros are not removed.
|
||||
## Result is prefixed with 0x
|
||||
##
|
||||
## Output will be padded with 0s to maintain constant-time.
|
||||
##
|
||||
## CT:
|
||||
## - no leaks
|
||||
dst.appendHex(f.toBig(), order)
|
||||
|
||||
func toHex*(f: Fp, order: static Endianness = bigEndian): string =
|
||||
## Stringify a finite field element to hex.
|
||||
## Note. Leading zeros are not removed.
|
||||
@ -51,7 +62,7 @@ func toHex*(f: Fp, order: static Endianness = bigEndian): string =
|
||||
##
|
||||
## CT:
|
||||
## - no leaks
|
||||
result = f.toBig().toHex(order)
|
||||
result.appendHex(f, order)
|
||||
|
||||
func fromHex*(dst: var Fp, s: string) {.raises: [ValueError].}=
|
||||
## Convert a hex string to a element of Fp
|
||||
|
||||
48
constantine/io/io_towers.nim
Normal file
48
constantine/io/io_towers.nim
Normal file
@ -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.
|
||||
|
||||
|
||||
import
|
||||
# Standard library
|
||||
std/typetraits,
|
||||
# Internal
|
||||
./io_bigints, ./io_fields,
|
||||
../config/curves,
|
||||
../arithmetic/finite_fields,
|
||||
../towers
|
||||
|
||||
# No exceptions allowed
|
||||
{.push raises: [].}
|
||||
{.push inline.}
|
||||
|
||||
# ############################################################
|
||||
#
|
||||
# Parsing from canonical inputs to internal representation
|
||||
#
|
||||
# ############################################################
|
||||
|
||||
func appendHex*(accum: var string, f: Fp2 or Fp6 or Fp12, order: static Endianness = bigEndian) =
|
||||
## Hex accumulator
|
||||
accum.add static($f.typeof.genericHead() & '(')
|
||||
for fieldName, fieldValue in fieldPairs(f):
|
||||
when fieldName != "c0":
|
||||
accum.add ", "
|
||||
accum.add fieldName & ": "
|
||||
accum.appendHex(fieldValue, order)
|
||||
accum.add ")"
|
||||
|
||||
func toHex*(f: Fp2 or Fp6 or Fp12, order: static Endianness = bigEndian): string =
|
||||
## Stringify a tower field element to hex.
|
||||
## Note. Leading zeros are not removed.
|
||||
## Result is prefixed with 0x
|
||||
##
|
||||
## Output will be padded with 0s to maintain constant-time.
|
||||
##
|
||||
## CT:
|
||||
## - no leaks
|
||||
result.appendHex(f, order)
|
||||
@ -50,7 +50,7 @@ func square_Chung_Hasan_SQR2(r: var CubicExt, a: CubicExt) =
|
||||
v4.prod(a.c0, a.c1)
|
||||
v4.double()
|
||||
v5.square(a.c2)
|
||||
r.c1 = β * v5
|
||||
r.c1 = NonResidue * v5
|
||||
r.c1 += v4
|
||||
r.c2.diff(v4, v5)
|
||||
v3.square(a.c0)
|
||||
@ -59,7 +59,7 @@ func square_Chung_Hasan_SQR2(r: var CubicExt, a: CubicExt) =
|
||||
v5.prod(a.c1, a.c2)
|
||||
v5.double()
|
||||
v4.square()
|
||||
r.c0 = β * v5
|
||||
r.c0 = NonResidue * v5
|
||||
r.c0 += v3
|
||||
r.c2 += v4
|
||||
r.c2 += v5
|
||||
@ -70,29 +70,29 @@ func square_Chung_Hasan_SQR3(r: var CubicExt, a: CubicExt) =
|
||||
mixin prod, square, sum
|
||||
var v0{.noInit.}, v2{.noInit.}: typeof(r.c0)
|
||||
|
||||
r.c1.sum(a.c0, a.c2) # r1 = a0 + a2
|
||||
v2.diff(r.c1, a.c1) # v2 = a0 - a1 + a2
|
||||
r.c1 += a.c1 # r1 = a0 + a1 + a2
|
||||
r.c1.square() # r1 = (a0 + a1 + a2)²
|
||||
v2.square() # v2 = (a0 - a1 + a2)²
|
||||
r.c1.sum(a.c0, a.c2) # r1 = a0 + a2
|
||||
v2.diff(r.c1, a.c1) # v2 = a0 - a1 + a2
|
||||
r.c1 += a.c1 # r1 = a0 + a1 + a2
|
||||
r.c1.square() # r1 = (a0 + a1 + a2)²
|
||||
v2.square() # v2 = (a0 - a1 + a2)²
|
||||
|
||||
r.c2.sum(r.c1, v2) # r2 = (a0 + a1 + a2)² + (a0 - a1 + a2)²
|
||||
r.c2.div2() # r2 = ((a0 + a1 + a2)² + (a0 - a1 + a2)²)/2
|
||||
r.c2.sum(r.c1, v2) # r2 = (a0 + a1 + a2)² + (a0 - a1 + a2)²
|
||||
r.c2.div2() # r2 = ((a0 + a1 + a2)² + (a0 - a1 + a2)²)/2
|
||||
|
||||
r.c0.prod(a.c1, a.c2) # r0 = a1 a2
|
||||
r.c0.double() # r0 = 2 a1 a2
|
||||
r.c0.prod(a.c1, a.c2) # r0 = a1 a2
|
||||
r.c0.double() # r0 = 2 a1 a2
|
||||
|
||||
v2.square(a.c2) # v2 = a2²
|
||||
r.c1 += β * v2 # r1 = (a0 + a1 + a2)² + β a2²
|
||||
r.c1 -= r.c0 # r1 = (a0 + a1 + a2)² - 2 a1 a2 + β a2²
|
||||
r.c1 -= r.c2 # r1 = (a0 + a1 + a2)² - 2 a1 a2 - ((a0 + a1 + a2)² + (a0 - a1 + a2)²)/2 + β a2²
|
||||
v2.square(a.c2) # v2 = a2²
|
||||
r.c1 += NonResidue * v2 # r1 = (a0 + a1 + a2)² + β a2²
|
||||
r.c1 -= r.c0 # r1 = (a0 + a1 + a2)² - 2 a1 a2 + β a2²
|
||||
r.c1 -= r.c2 # r1 = (a0 + a1 + a2)² - 2 a1 a2 - ((a0 + a1 + a2)² + (a0 - a1 + a2)²)/2 + β a2²
|
||||
|
||||
v0.square(a.c0) # v0 = a0²
|
||||
r.c0 *= β # r0 = β 2 a1 a2
|
||||
r.c0 += v0 # r0 = a0² + β 2 a1 a2
|
||||
v0.square(a.c0) # v0 = a0²
|
||||
r.c0 *= NonResidue # r0 = β 2 a1 a2
|
||||
r.c0 += v0 # r0 = a0² + β 2 a1 a2
|
||||
|
||||
r.c2 -= v0 # r2 = ((a0 + a1 + a2)² + (a0 - a1 + a2)²)/2 - a0²
|
||||
r.c2 -= v2 # r2 = ((a0 + a1 + a2)² + (a0 - a1 + a2)²)/2 - a0² - a2²
|
||||
r.c2 -= v0 # r2 = ((a0 + a1 + a2)² + (a0 - a1 + a2)²)/2 - a0²
|
||||
r.c2 -= v2 # r2 = ((a0 + a1 + a2)² + (a0 - a1 + a2)²)/2 - a0² - a2²
|
||||
|
||||
func square*(r: var CubicExt, a: CubicExt) {.inline.} =
|
||||
## Returns r = a²
|
||||
@ -115,7 +115,7 @@ func prod*(r: var CubicExt, a, b: CubicExt) =
|
||||
r.c0 *= t
|
||||
r.c0 -= v1
|
||||
r.c0 -= v2
|
||||
r.c0 *= β
|
||||
r.c0 *= NonResidue
|
||||
r.c0 += v0
|
||||
|
||||
# r.c1 = (a.c0 + a.c1) * (b.c0 + b.c1) - v0 - v1 + β v2
|
||||
@ -124,7 +124,7 @@ func prod*(r: var CubicExt, a, b: CubicExt) =
|
||||
r.c1 *= t
|
||||
r.c1 -= v0
|
||||
r.c1 -= v1
|
||||
r.c1 += β * v2
|
||||
r.c1 += NonResidue * v2
|
||||
|
||||
# r.c2 = (a.c0 + a.c2) * (b.c0 + b.c2) - v0 - v2 + v1
|
||||
r.c2.sum(a.c0, a.c2)
|
||||
@ -159,13 +159,13 @@ func inv*(r: var CubicExt, a: CubicExt) =
|
||||
# A <- a0² - β a1 a2
|
||||
r.c0.square(a.c0)
|
||||
v1.prod(a.c1, a.c2)
|
||||
v1 *= β
|
||||
v1 *= NonResidue
|
||||
r.c0 -= v1
|
||||
|
||||
# B in v1
|
||||
# B <- β a2² - a0 a1
|
||||
v1.square(a.c2)
|
||||
v1 *= β
|
||||
v1 *= NonResidue
|
||||
v2.prod(a.c0, a.c1)
|
||||
v1 -= v2
|
||||
|
||||
@ -177,8 +177,8 @@ func inv*(r: var CubicExt, a: CubicExt) =
|
||||
|
||||
# F in v3
|
||||
# F <- β a1 C + a0 A + β a2 B
|
||||
r.c1.prod(v1, β * a.c2)
|
||||
r.c2.prod(v2, β * a.c1)
|
||||
r.c1.prod(v1, NonResidue * a.c2)
|
||||
r.c2.prod(v2, NonResidue * a.c1)
|
||||
v3.prod(r.c0, a.c0)
|
||||
v3 += r.c1
|
||||
v3 += r.c2
|
||||
|
||||
223
constantine/tower_field_extensions/exponentiations.nim
Normal file
223
constantine/tower_field_extensions/exponentiations.nim
Normal file
@ -0,0 +1,223 @@
|
||||
# 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
|
||||
../arithmetic,
|
||||
../config/[common, curves],
|
||||
../primitives,
|
||||
./tower_common,
|
||||
./quadratic_extensions,
|
||||
./cubic_extensions
|
||||
|
||||
# ############################################################
|
||||
#
|
||||
# Exponentiations (pow and square roots) in extension fields
|
||||
#
|
||||
# ############################################################
|
||||
|
||||
# Square root should be implemented in constant-time for hash-to-curve:
|
||||
# https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-05#section-4
|
||||
#
|
||||
# Further non-constant-time optimization may be used
|
||||
# - Square Root Computation over Even Extension Fields
|
||||
# Gora Adj, Francisco Rodríguez-Henríquez, 2012
|
||||
# https://eprint.iacr.org/2012/685
|
||||
|
||||
# No exceptions allowed
|
||||
{.push raises: [].}
|
||||
|
||||
# Pow
|
||||
# -----------------------------------------------------------
|
||||
|
||||
template checkPowScratchSpaceLen(len: int) =
|
||||
## Checks that there is a minimum of scratchspace to hold the temporaries
|
||||
debug:
|
||||
assert len >= 2, "Internal Error: the scratchspace for powmod should be equal or greater than 2"
|
||||
|
||||
func getWindowLen(bufLen: int): uint =
|
||||
## Compute the maximum window size that fits in the scratchspace buffer
|
||||
checkPowScratchSpaceLen(bufLen)
|
||||
result = 4
|
||||
while (1 shl result) + 1 > bufLen:
|
||||
dec result
|
||||
|
||||
func powPrologue[F](a: var F, scratchspace: var openarray[F]): uint =
|
||||
## Setup the scratchspace, then set a to 1.
|
||||
## Returns the fixed-window size for exponentiation with window optimization
|
||||
result = scratchspace.len.getWindowLen
|
||||
# Precompute window content, special case for window = 1
|
||||
# (i.e scratchspace has only space for 2 temporaries)
|
||||
# The content scratchspace[2+k] is set at [k]P
|
||||
# with scratchspace[0] untouched
|
||||
if result == 1:
|
||||
scratchspace[1] = a
|
||||
else:
|
||||
scratchspace[2] = a
|
||||
for k in 2 ..< 1 shl result:
|
||||
scratchspace[k+1]
|
||||
a.setOne()
|
||||
|
||||
func powSquarings[F](
|
||||
a: var F,
|
||||
exponent: openArray[byte],
|
||||
tmp: var F,
|
||||
window: uint,
|
||||
acc, acc_len: var uint,
|
||||
e: var uint
|
||||
): tuple[k, bits: uint] {.inline.}=
|
||||
## Squaring step of exponentiation by squaring
|
||||
## Get the next k bits in range [1, window)
|
||||
## Square k times
|
||||
## Returns the number of squarings done and the corresponding bits
|
||||
##
|
||||
## Updates iteration variables and accumulators
|
||||
# Due to the high number of parameters,
|
||||
# forcing this inline actually reduces the code size
|
||||
#
|
||||
# ⚠️: Extreme care should be used to not leak
|
||||
# the exponent bits nor its real bitlength
|
||||
# i.e. if the exponent is zero but encoded in a
|
||||
# 256-bit integer, only "256" should leak
|
||||
# as for some application like RSA
|
||||
# the exponent might be the user secret key.
|
||||
|
||||
# Get the next bits
|
||||
# acc/acc_len must be uint to avoid Nim runtime checks leaking bits
|
||||
# acc/acc_len must be uint to avoid Nim runtime checks leaking bits
|
||||
# e is public
|
||||
var k = window
|
||||
if acc_len < window:
|
||||
if e < exponent.len:
|
||||
acc = (acc shl 8) or exponent[e].uint
|
||||
inc e
|
||||
acc_len += 8
|
||||
else: # Drained all exponent bits
|
||||
k = acc_len
|
||||
|
||||
let bits = (acc shr (acc_len - k)) and ((1'u32 shl k) - 1)
|
||||
acc_len -= k
|
||||
|
||||
# We have k bits and can do k squaring
|
||||
for i in 0 ..< k:
|
||||
a.square()
|
||||
|
||||
return (k, bits)
|
||||
|
||||
func powUnsafeExponent(
|
||||
a: var ExtensionField,
|
||||
exponent: openArray[byte],
|
||||
scratchspace: var openArray[byte]
|
||||
) =
|
||||
## Extension field exponentiation r = a^exponent (mod p^m)
|
||||
##
|
||||
## Warning ⚠️ :
|
||||
## This is an optimization for public exponent
|
||||
## Otherwise bits of the exponent can be retrieved with:
|
||||
## - memory access analysis
|
||||
## - power analysis
|
||||
## - timing analysis
|
||||
|
||||
# TODO: scratchspace[1] is unused when window > 1
|
||||
let window = powPrologue(a, scratchspace)
|
||||
|
||||
var
|
||||
acc, acc_len: uint
|
||||
e = 0
|
||||
while acc_len > 0 or e < exponent.len:
|
||||
let (_, bits) = powSquarings(
|
||||
a, exponent,
|
||||
scratchspace[0], window,
|
||||
acc, acc_len, e
|
||||
)
|
||||
|
||||
## Warning ⚠️: Exposes the exponent bits
|
||||
if bits != 0:
|
||||
if window > 1:
|
||||
scratchspace[0].prod(a, scratchspace[1+bits])
|
||||
else:
|
||||
# scratchspace[1] holds the original `a`
|
||||
scratchspace[0].prod(a, scratchspace[1])
|
||||
a = scratchspace[0]
|
||||
|
||||
# Square root
|
||||
# -----------------------------------------------------------
|
||||
#
|
||||
# Warning ⚠️:
|
||||
# p the characteristic, i.e. the prime modulus of the base field
|
||||
# in extension field we require q = p^m be of special form
|
||||
# i.e. q ≡ 3 (mod 4) or q ≡ 9 (mod 16)
|
||||
#
|
||||
# In Fp2 in particular p² ≡ 1 (mod 4) always hold
|
||||
# and p² ≡ 5 (mod 8) is not possible
|
||||
# if Fp2 = Fp[v]/(v² − β) with β a quadratic non-residue in Fp
|
||||
|
||||
func isSquare*(a: QuadraticExt): SecretBool =
|
||||
## Returns true if ``a`` is a square (quadratic residue) in 𝔽p2
|
||||
##
|
||||
## Assumes that the prime modulus ``p`` is public.
|
||||
# Implementation:
|
||||
#
|
||||
# (a0, a1) = a in F(p^2)
|
||||
# is_square(a) = is_square(|a|) over F(p)
|
||||
# where |a| = a0^2 + a1^2
|
||||
#
|
||||
# This can be done recursively in an extension tower
|
||||
#
|
||||
# https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-08#appendix-G.5
|
||||
# https://eprint.iacr.org/2012/685
|
||||
|
||||
mixin fromComplexExtension # TODO: relax this
|
||||
static: doAssert a.fromComplexExtension()
|
||||
|
||||
var tv1{.noInit.}, tv2{.noInit.}: typeof(a.c0)
|
||||
|
||||
tv1.square(a.c0) # a0²
|
||||
tv2.square(a.c1) # - β a1² with β = 𝑖² in a complex extension field
|
||||
|
||||
tv1 += tv2 # a0 - (-1) a1²
|
||||
result = tv1.isSquare()
|
||||
|
||||
func sqrt_if_square*(a: var QuadraticExt): SecretBool =
|
||||
## If ``a`` is a square, compute the square root of ``a``
|
||||
## if not, ``a`` is unmodified.
|
||||
##
|
||||
## The square root, if it exist is multivalued,
|
||||
## i.e. both x² == (-x)²
|
||||
## This procedure returns a deterministic result
|
||||
#
|
||||
# Implementation via the complex method (which confusingly does not require a complex field)
|
||||
# We make it constant-time via conditional copies
|
||||
|
||||
mixin fromComplexExtension # TODO: relax this
|
||||
static: doAssert a.fromComplexExtension()
|
||||
|
||||
var t1{.noInit.}, t2{.noInit.}, t3{.noInit.}: typeof(a.c0)
|
||||
|
||||
t1.square(a.c0) # a0²
|
||||
t2.square(a.c1) # - β a1² with β = 𝑖² in a complex extension field
|
||||
|
||||
t1 += t2 # a0 - (-1) a1²
|
||||
result = t1.sqrt_if_square()
|
||||
|
||||
t2.sum(a.c0, t1)
|
||||
t2.div2()
|
||||
|
||||
t3.diff(a.c0, t1)
|
||||
t3.div2()
|
||||
|
||||
let quadResidTest = t2.isSquare()
|
||||
t2.ccopy(t3, not quadResidTest)
|
||||
|
||||
t2.sqrt()
|
||||
a.c0.ccopy(t2, result)
|
||||
|
||||
t2.double()
|
||||
t1.inv(t2)
|
||||
t1 *= a.c1
|
||||
a.c1.ccopy(t1, result)
|
||||
@ -126,14 +126,14 @@ func square_generic(r: var QuadraticExt, a: QuadraticExt) =
|
||||
|
||||
# r0 <- (c0 + c1)(c0 + β c1)
|
||||
r.c0.sum(a.c0, a.c1)
|
||||
r.c1.sum(a.c0, β * a.c1)
|
||||
r.c1.sum(a.c0, NonResidue * a.c1)
|
||||
r.c0 *= r.c1
|
||||
|
||||
# r1 <- c0 c1
|
||||
r.c1.prod(a.c0, a.c1)
|
||||
|
||||
# r0 = (c0 + c1)(c0 + β c1) - β c0c1 - c0c1
|
||||
r.c0 -= β * r.c1
|
||||
r.c0 -= NonResidue * r.c1
|
||||
r.c0 -= r.c1
|
||||
|
||||
# r1 = 2 c0c1
|
||||
@ -161,7 +161,7 @@ func prod_generic(r: var QuadraticExt, a, b: QuadraticExt) =
|
||||
r.c1 -= t
|
||||
|
||||
# r0 <- a0 b0 + β a1 b1
|
||||
r.c0 += β * t
|
||||
r.c0 += NonResidue * t
|
||||
|
||||
# Exported symbols
|
||||
# -------------------------------------------------------------------
|
||||
@ -204,15 +204,15 @@ func inv*(r: var QuadraticExt, a: QuadraticExt) =
|
||||
when r.fromComplexExtension():
|
||||
v0 += v1
|
||||
else:
|
||||
v0 -= β * v1 # v0 = a0² - β a1² (the norm / squared magnitude of a)
|
||||
v0 -= NonResidue * v1 # v0 = a0² - β a1² (the norm / squared magnitude of a)
|
||||
|
||||
# [1 Inv, 2 Sqr, 1 Add]
|
||||
v1.inv(v0) # v1 = 1 / (a0² - β a1²)
|
||||
v1.inv(v0) # v1 = 1 / (a0² - β a1²)
|
||||
|
||||
# [1 Inv, 2 Mul, 2 Sqr, 1 Add, 1 Neg]
|
||||
r.c0.prod(a.c0, v1) # r0 = a0 / (a0² - β a1²)
|
||||
v0.neg(v1) # v0 = -1 / (a0² - β a1²)
|
||||
r.c1.prod(a.c1, v0) # r1 = -a1 / (a0² - β a1²)
|
||||
r.c0.prod(a.c0, v1) # r0 = a0 / (a0² - β a1²)
|
||||
v0.neg(v1) # v0 = -1 / (a0² - β a1²)
|
||||
r.c1.prod(a.c1, v0) # r1 = -a1 / (a0² - β a1²)
|
||||
|
||||
func `*=`*(a: var QuadraticExt, b: QuadraticExt) {.inline.} =
|
||||
## In-place multiplication
|
||||
|
||||
@ -18,10 +18,10 @@ import
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
type
|
||||
β* = object
|
||||
## Non-Residue β
|
||||
NonResidue* = object
|
||||
## Non-Residue
|
||||
##
|
||||
## Placeholder for the appropriate quadratic or cubic non-residue
|
||||
## Placeholder for the appropriate quadratic, cubic or sectic non-residue
|
||||
|
||||
CubicExt* = concept x
|
||||
## Cubic Extension field concept
|
||||
@ -38,7 +38,7 @@ type
|
||||
x.c0 is BaseField
|
||||
x.c1 is BaseField
|
||||
|
||||
ExtensionField = QuadraticExt or CubicExt
|
||||
ExtensionField* = QuadraticExt or CubicExt
|
||||
|
||||
# Initialization
|
||||
# -------------------------------------------------------------------
|
||||
@ -56,6 +56,14 @@ func setOne*(a: var ExtensionField) =
|
||||
else:
|
||||
fA.setZero()
|
||||
|
||||
func fromBig*(a: var ExtensionField, src: BigInt) =
|
||||
## Set ``a`` to the bigint value int eh extension field
|
||||
for fieldName, fA in fieldPairs(a):
|
||||
when fieldName == "c0":
|
||||
fA.fromBig(src)
|
||||
else:
|
||||
fA.setZero()
|
||||
|
||||
# Comparison
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
@ -145,3 +153,77 @@ func diff*(r: var CubicExt, a, b: CubicExt) =
|
||||
r.c0.diff(a.c0, b.c0)
|
||||
r.c1.diff(a.c1, b.c1)
|
||||
r.c2.diff(a.c2, b.c2)
|
||||
|
||||
# Multiplication by a small integer known at compile-time
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
func `*=`*(a: var ExtensionField, b: static int) {.inline.} =
|
||||
## Multiplication by a small integer known at compile-time
|
||||
|
||||
const negate = b < 0
|
||||
const b = if negate: -b
|
||||
else: b
|
||||
when negate:
|
||||
a.neg(a)
|
||||
when b == 0:
|
||||
a.setZero()
|
||||
elif b == 1:
|
||||
return
|
||||
elif b == 2:
|
||||
a.double()
|
||||
elif b == 3:
|
||||
let t1 = a
|
||||
a.double()
|
||||
a += t1
|
||||
elif b == 4:
|
||||
a.double()
|
||||
a.double()
|
||||
elif b == 5:
|
||||
let t1 = a
|
||||
a.double()
|
||||
a.double()
|
||||
a += t1
|
||||
elif b == 6:
|
||||
a.double()
|
||||
let t2 = a
|
||||
a.double() # 4
|
||||
a += t2
|
||||
elif b == 7:
|
||||
let t1 = a
|
||||
a.double()
|
||||
let t2 = a
|
||||
a.double() # 4
|
||||
a += t2
|
||||
a += t1
|
||||
elif b == 8:
|
||||
a.double()
|
||||
a.double()
|
||||
a.double()
|
||||
elif b == 9:
|
||||
let t1 = a
|
||||
a.double()
|
||||
a.double()
|
||||
a.double() # 8
|
||||
a += t1
|
||||
elif b == 10:
|
||||
a.double()
|
||||
let t2 = a
|
||||
a.double()
|
||||
a.double() # 8
|
||||
a += t2
|
||||
elif b == 11:
|
||||
let t1 = a
|
||||
a.double()
|
||||
let t2 = a
|
||||
a.double()
|
||||
a.double() # 8
|
||||
a += t2
|
||||
a += t1
|
||||
elif b == 12:
|
||||
a.double()
|
||||
a.double() # 4
|
||||
let t4 = a
|
||||
a.double() # 8
|
||||
a += t4
|
||||
else:
|
||||
{.error: "Multiplication by this small int not implemented".}
|
||||
|
||||
@ -9,13 +9,15 @@
|
||||
import
|
||||
./arithmetic,
|
||||
./config/curves,
|
||||
./io/io_fields,
|
||||
./tower_field_extensions/[
|
||||
tower_common,
|
||||
quadratic_extensions,
|
||||
cubic_extensions
|
||||
cubic_extensions,
|
||||
exponentiations
|
||||
]
|
||||
|
||||
export tower_common, quadratic_extensions, cubic_extensions
|
||||
export tower_common, quadratic_extensions, cubic_extensions, exponentiations
|
||||
|
||||
# 𝔽p2
|
||||
# ----------------------------------------------------------------
|
||||
@ -24,6 +26,8 @@ type
|
||||
Fp2*[C: static Curve] = object
|
||||
c0*, c1*: Fp[C]
|
||||
|
||||
β = NonResidue
|
||||
|
||||
template fromComplexExtension*[F](elem: F): static bool =
|
||||
## Returns true if the input is a complex extension
|
||||
## i.e. the irreducible polynomial chosen is
|
||||
@ -46,6 +50,73 @@ func `*`*(_: typedesc[β], a: Fp): Fp {.inline, noInit.} =
|
||||
result = a
|
||||
result *= β
|
||||
|
||||
type
|
||||
SexticNonResidue* = object
|
||||
|
||||
func `*=`*(a: var Fp2, _: typedesc[SexticNonResidue]) {.inline.} =
|
||||
## Multiply an element of 𝔽p2 by the sextic non-residue
|
||||
## chosen to construct the sextic twist
|
||||
# Yet another const tuple unpacking bug
|
||||
const u = Fp2.C.get_SNR_Fp2()[0] # Sextic non-residue to construct 𝔽p12
|
||||
const v = Fp2.C.get_SNR_Fp2()[1]
|
||||
const Beta = Fp2.C.get_QNR_Fp() # Quadratic non-residue to construct 𝔽p2
|
||||
# ξ = u + v x
|
||||
# and x² = β
|
||||
#
|
||||
# (c0 + c1 x) (u + v x) => u c0 + (u c0 + u c1)x + v c1 x²
|
||||
# => u c0 + β v c1 + (v c0 + u c1) x
|
||||
when a.fromComplexExtension() and u == 1 and v == 1:
|
||||
let t = a.c0
|
||||
a.c0 -= a.c1
|
||||
a.c1 += t
|
||||
else:
|
||||
let a0 = a.c0
|
||||
let a1 = a.c1
|
||||
when a.fromComplexExtension():
|
||||
a.c0.diff(u * a0, v * a1)
|
||||
else:
|
||||
a.c0.sum(u * a0, (Beta * v) * a1)
|
||||
a.c1.sum(v * a0, u * a1)
|
||||
|
||||
func `/=`*(a: var Fp2, _: typedesc[SexticNonResidue]) {.inline.} =
|
||||
## Multiply an element of 𝔽p by the quadratic non-residue
|
||||
## chosen to construct sextic twist
|
||||
# Yet another const tuple unpacking bug
|
||||
const u = Fp2.C.get_SNR_Fp2()[0] # Sextic non-residue to construct 𝔽p12
|
||||
const v = Fp2.C.get_SNR_Fp2()[1]
|
||||
const Beta = Fp2.C.get_QNR_Fp() # Quadratic non-residue to construct 𝔽p2
|
||||
# ξ = u + v x
|
||||
# and x² = β
|
||||
#
|
||||
# (c0 + c1 x) / (u + v x) => (c0 + c1 x)(u - v x) / ((u + vx)(u-vx))
|
||||
# => u c0 - v c1 x² + (u c1 - v c0) x / (u² - x²v²)
|
||||
# => 1/(u² - βv²) * (uc0 - β v c1, u c1 - v c0)
|
||||
# With β = 𝑖 = √-1
|
||||
# 1/(u² + v²) * (u c0 + v c1, u c1 - v c0)
|
||||
#
|
||||
# With β = 𝑖 = √-1 and ξ = 1 + 𝑖
|
||||
# 1/2 * (c0 + c1, c1 - c0)
|
||||
|
||||
when a.fromComplexExtension() and u == 1 and v == 1:
|
||||
let t = a.c0
|
||||
a.c0 += a.c1
|
||||
a.c1 -= t
|
||||
a.div2()
|
||||
else:
|
||||
let a0 = a.c0
|
||||
let a1 = a.c1
|
||||
const u2v2 = u*u - Beta*v*v # (u² - βv²)
|
||||
# TODO can be precomputed (or precompute b/µ the twist coefficient)
|
||||
# and use faster non-constant-time inversion in the VM
|
||||
var u2v2inv {.noInit.}: a.c0.typeof
|
||||
u2v2inv.fromUint(u2v2)
|
||||
u2v2inv.inv()
|
||||
|
||||
a.c0.diff(u * a0, (Beta * v) * a1)
|
||||
a.c1.diff(u * a1, v * a0)
|
||||
a.c0 *= u2v2inv
|
||||
a.c1 *= u2v2inv
|
||||
|
||||
# 𝔽p6
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
@ -82,8 +153,8 @@ func `*`*(_: typedesc[β], a: Fp2): Fp2 {.inline, noInit.} =
|
||||
result.c1.sum(v * a.c0, u * a.c1 )
|
||||
|
||||
func `*=`*(a: var Fp2, _: typedesc[ξ]) {.inline.} =
|
||||
## Multiply an element of 𝔽p by the quadratic non-residue
|
||||
## chosen to construct 𝔽p2
|
||||
## Multiply an element of 𝔽p2 by the quadratic non-residue
|
||||
## chosen to construct 𝔽p6
|
||||
# Yet another const tuple unpacking bug
|
||||
const u = Fp2.C.get_CNR_Fp2()[0] # Cubic non-residue to construct 𝔽p6
|
||||
const v = Fp2.C.get_CNR_Fp2()[1]
|
||||
|
||||
@ -30,6 +30,8 @@ def compute_curve_characteristic(u_str):
|
||||
else:
|
||||
print(' Parameter u (hex): 0x' + u.hex())
|
||||
|
||||
print()
|
||||
|
||||
print(f' p mod 3: ' + str(p % 3))
|
||||
print(f' p mod 4: ' + str(p % 4))
|
||||
print(f' p mod 8: ' + str(p % 8))
|
||||
@ -38,6 +40,14 @@ def compute_curve_characteristic(u_str):
|
||||
|
||||
print()
|
||||
|
||||
print(f' p^2 mod 3: ' + str(p^2 % 3))
|
||||
print(f' p^2 mod 4: ' + str(p^2 % 4))
|
||||
print(f' p^2 mod 8: ' + str(p^2 % 8))
|
||||
print(f' p^2 mod 12: ' + str(p^2 % 12))
|
||||
print(f' p^2 mod 16: ' + str(p^2 % 16))
|
||||
|
||||
print()
|
||||
|
||||
print(f' Endomorphism-based acceleration when p mod 3 == 1')
|
||||
print(f' Endomorphism can be field multiplication by one of the non-trivial cube root of unity 𝜑')
|
||||
print(f' Rationale:')
|
||||
|
||||
@ -38,6 +38,14 @@ def compute_curve_characteristic(u_str):
|
||||
|
||||
print()
|
||||
|
||||
print(f' p^2 mod 3: ' + str(p^2 % 3))
|
||||
print(f' p^2 mod 4: ' + str(p^2 % 4))
|
||||
print(f' p^2 mod 8: ' + str(p^2 % 8))
|
||||
print(f' p^2 mod 12: ' + str(p^2 % 12))
|
||||
print(f' p^2 mod 16: ' + str(p^2 % 16))
|
||||
|
||||
print()
|
||||
|
||||
print(f' Endomorphism-based acceleration when p mod 3 == 1')
|
||||
print(f' Endomorphism can be field multiplication by one of the non-trivial cube root of unity 𝜑')
|
||||
print(f' Rationale:')
|
||||
|
||||
@ -10,7 +10,7 @@ import
|
||||
# Internals
|
||||
../../constantine/config/[common, curves],
|
||||
../../constantine/arithmetic,
|
||||
../../constantine/elliptic/[ec_weierstrass_affine, ec_weierstrass_projective]
|
||||
../../constantine/elliptic/ec_weierstrass_projective
|
||||
|
||||
# Support files for testing Elliptic Curve arithmetic
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
@ -12,8 +12,10 @@ import std/unittest,
|
||||
../constantine/config/common,
|
||||
../constantine/primitives
|
||||
|
||||
echo "\n------------------------------------------------------\n"
|
||||
|
||||
proc mainArith() =
|
||||
suite "isZero":
|
||||
suite "isZero" & " [" & $WordBitwidth & "-bit mode]":
|
||||
test "isZero for zero":
|
||||
var x: BigInt[128]
|
||||
check: x.isZero().bool
|
||||
@ -28,7 +30,7 @@ proc mainArith() =
|
||||
var x = fromHex(BigInt[128], "0xFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF")
|
||||
check: not x.isZero().bool
|
||||
|
||||
suite "Arithmetic operations - Addition":
|
||||
suite "Arithmetic operations - Addition" & " [" & $WordBitwidth & "-bit mode]":
|
||||
test "Adding 2 zeros":
|
||||
var a = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000000")
|
||||
let b = fromHex(BigInt[128], "0x00000000_00000000_00000000_00000000")
|
||||
@ -128,7 +130,7 @@ proc mainArith() =
|
||||
bool(a == c)
|
||||
not bool(carry)
|
||||
|
||||
suite "BigInt + SecretWord":
|
||||
suite "BigInt + SecretWord" & " [" & $WordBitwidth & "-bit mode]":
|
||||
test "Addition limbs carry":
|
||||
block: # P256 / 2
|
||||
var a = BigInt[256].fromhex"0x7fffffff800000008000000000000000000000007fffffffffffffffffffffff"
|
||||
@ -138,7 +140,7 @@ proc mainArith() =
|
||||
discard a.add(SecretWord 1)
|
||||
check: bool(a == expected)
|
||||
|
||||
suite "Multi-precision multiplication":
|
||||
suite "Multi-precision multiplication" & " [" & $WordBitwidth & "-bit mode]":
|
||||
test "Same size operand into double size result":
|
||||
block:
|
||||
var r: BigInt[256]
|
||||
@ -178,7 +180,7 @@ proc mainArith() =
|
||||
r.prod(b, a)
|
||||
check: bool(r == expected)
|
||||
|
||||
suite "Multi-precision multiplication keeping only high words":
|
||||
suite "Multi-precision multiplication keeping only high words" & " [" & $WordBitwidth & "-bit mode]":
|
||||
test "Same size operand into double size result - discard first word":
|
||||
block:
|
||||
var r: BigInt[256]
|
||||
@ -263,7 +265,7 @@ proc mainArith() =
|
||||
r.prod_high_words(b, a, 2)
|
||||
check: bool(r == expected)
|
||||
|
||||
suite "Modular operations - small modulus":
|
||||
suite "Modular operations - small modulus" & " [" & $WordBitwidth & "-bit mode]":
|
||||
# Vectors taken from Stint - https://github.com/status-im/nim-stint
|
||||
test "100 mod 13":
|
||||
# Test 1 word and more than 1 word
|
||||
@ -312,7 +314,7 @@ proc mainArith() =
|
||||
check:
|
||||
bool(r == BigInt[8].fromUint(0'u8))
|
||||
|
||||
suite "Modular operations - small modulus - Stint specific failures highlighted by property-based testing":
|
||||
suite "Modular operations - small modulus - Stint specific failures highlighted by property-based testing" & " [" & $WordBitwidth & "-bit mode]":
|
||||
# Vectors taken from Stint - https://github.com/status-im/nim-stint
|
||||
test "Modulo: 65696211516342324 mod 174261910798982":
|
||||
let u = 65696211516342324'u64
|
||||
@ -341,7 +343,7 @@ proc mainArith() =
|
||||
bool(r == BigInt[40].fromUint(u mod v))
|
||||
|
||||
proc mainNeg() =
|
||||
suite "Conditional negation":
|
||||
suite "Conditional negation" & " [" & $WordBitwidth & "-bit mode]":
|
||||
test "Conditional negation":
|
||||
block:
|
||||
var a = fromHex(BigInt[128], "0x12345678_FF11FFAA_00321321_CAFECAFE")
|
||||
@ -439,7 +441,7 @@ proc mainNeg() =
|
||||
bool(b == b2)
|
||||
|
||||
proc mainCopySwap() =
|
||||
suite "Copy and Swap":
|
||||
suite "Copy and Swap" & " [" & $WordBitwidth & "-bit mode]":
|
||||
test "Conditional copy":
|
||||
block:
|
||||
var a = fromHex(BigInt[128], "0x12345678_FF11FFAA_00321321_CAFECAFE")
|
||||
@ -485,7 +487,7 @@ proc mainCopySwap() =
|
||||
bool(eB == b)
|
||||
|
||||
proc mainModularInverse() =
|
||||
suite "Modular Inverse (with odd modulus)":
|
||||
suite "Modular Inverse (with odd modulus)" & " [" & $WordBitwidth & "-bit mode]":
|
||||
# Note: We don't define multi-precision multiplication
|
||||
# because who needs it when you have Montgomery?
|
||||
# ¯\_(ツ)_/¯
|
||||
|
||||
@ -16,6 +16,7 @@ import
|
||||
../constantine/arithmetic,
|
||||
../constantine/primitives
|
||||
|
||||
echo "\n------------------------------------------------------\n"
|
||||
# We test up to 1024-bit, more is really slow
|
||||
|
||||
var bitSizeRNG {.compileTime.} = initRand(1234)
|
||||
|
||||
@ -17,6 +17,7 @@ import
|
||||
../constantine/primitives,
|
||||
../constantine/config/[common, type_bigint]
|
||||
|
||||
echo "\n------------------------------------------------------\n"
|
||||
# We test up to 1024-bit, more is really slow
|
||||
|
||||
var bitSizeRNG {.compileTime.} = initRand(1234)
|
||||
|
||||
@ -17,6 +17,7 @@ import
|
||||
../constantine/primitives,
|
||||
../constantine/config/[common, type_bigint]
|
||||
|
||||
echo "\n------------------------------------------------------\n"
|
||||
# We test up to 1024-bit, more is really slow
|
||||
|
||||
var bitSizeRNG {.compileTime.} = initRand(1234)
|
||||
|
||||
@ -10,12 +10,15 @@ import
|
||||
# Standard library
|
||||
std/unittest,
|
||||
# Third-party
|
||||
../constantine/config/common,
|
||||
../constantine/io/io_bigints,
|
||||
../constantine/arithmetic,
|
||||
../constantine/primitives
|
||||
|
||||
echo "\n------------------------------------------------------\n"
|
||||
|
||||
proc main() =
|
||||
suite "Bigints - Multiprecision modulo":
|
||||
suite "Bigints - Multiprecision modulo" & " [" & $WordBitwidth & "-bit mode]":
|
||||
test "bitsize 237 mod bitsize 192":
|
||||
let a = BigInt[237].fromHex("0x123456789012345678901234567890123456789012345678901234567890")
|
||||
let m = BigInt[192].fromHex("0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB")
|
||||
|
||||
@ -17,6 +17,8 @@ import
|
||||
# Test utilities
|
||||
./support/ec_reference_scalar_mult
|
||||
|
||||
echo "\n------------------------------------------------------\n"
|
||||
|
||||
proc test(
|
||||
id: int,
|
||||
EC: typedesc[ECP_SWei_Proj],
|
||||
@ -51,7 +53,7 @@ proc test(
|
||||
doAssert: bool(Q == impl)
|
||||
doAssert: bool(Q == endo)
|
||||
|
||||
suite "Scalar Multiplication (cofactor cleared): BLS12_381 implementation (and unsafe reference impl) vs SageMath":
|
||||
suite "Scalar Multiplication (cofactor cleared): BLS12_381 implementation vs SageMath" & " [" & $WordBitwidth & "-bit mode]":
|
||||
# Generated via sage sage/testgen_bls12_381.sage
|
||||
test(
|
||||
id = 1,
|
||||
@ -17,6 +17,8 @@ import
|
||||
# Test utilities
|
||||
./support/ec_reference_scalar_mult
|
||||
|
||||
echo "\n------------------------------------------------------\n"
|
||||
|
||||
proc test(
|
||||
id: int,
|
||||
EC: typedesc[ECP_SWei_Proj],
|
||||
@ -51,7 +53,7 @@ proc test(
|
||||
doAssert: bool(Q == impl)
|
||||
doAssert: bool(Q == endo)
|
||||
|
||||
suite "Scalar Multiplication: BN254 implementation (and unsafe reference impl) vs SageMath":
|
||||
suite "Scalar Multiplication: BN254 implementation vs SageMath" & " [" & $WordBitwidth & "-bit mode]":
|
||||
# Generated via sage sage/testgen_bn254_snarks.sage
|
||||
test(
|
||||
id = 1,
|
||||
399
tests/test_ec_template.nim
Normal file
399
tests/test_ec_template.nim
Normal file
@ -0,0 +1,399 @@
|
||||
# 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.
|
||||
|
||||
# ############################################################
|
||||
#
|
||||
# Template tests for elliptic curve operations
|
||||
#
|
||||
# ############################################################
|
||||
|
||||
import
|
||||
# Standard library
|
||||
std/[unittest, times],
|
||||
# Internals
|
||||
../constantine/config/[common, curves],
|
||||
../constantine/arithmetic,
|
||||
../constantine/towers,
|
||||
../constantine/io/io_bigints,
|
||||
../constantine/elliptic/[ec_weierstrass_projective, ec_scalar_mul],
|
||||
# Test utilities
|
||||
../helpers/prng_unsafe,
|
||||
./support/ec_reference_scalar_mult
|
||||
|
||||
proc run_EC_addition_tests*(
|
||||
ec: typedesc,
|
||||
Iters: static int,
|
||||
moduleName: string
|
||||
) =
|
||||
|
||||
# Random seed for reproducibility
|
||||
var rng: RngState
|
||||
let seed = uint32(getTime().toUnix() and (1'i64 shl 32 - 1)) # unixTime mod 2^32
|
||||
rng.seed(seed)
|
||||
echo "\n------------------------------------------------------\n"
|
||||
echo moduleName, " xoshiro512** seed: ", seed
|
||||
|
||||
when ec.F is Fp:
|
||||
const G1_or_G2 = "G1"
|
||||
else:
|
||||
const G1_or_G2 = "G2"
|
||||
|
||||
const testSuiteDesc = "Elliptic curve in Short Weierstrass form with projective coordinates"
|
||||
|
||||
suite testSuiteDesc & " - " & $ec & " - [" & $WordBitwidth & "-bit mode]":
|
||||
test "The infinity point is the neutral element w.r.t. to EC " & G1_or_G2 & " addition":
|
||||
proc test(EC: typedesc, randZ: static bool) =
|
||||
var inf {.noInit.}: EC
|
||||
inf.setInf()
|
||||
check: bool inf.isInf()
|
||||
|
||||
for _ in 0 ..< Iters:
|
||||
var r{.noInit.}: EC
|
||||
when randZ:
|
||||
let P = rng.random_unsafe_with_randZ(EC)
|
||||
else:
|
||||
let P = rng.random_unsafe(EC)
|
||||
|
||||
r.sum(P, inf)
|
||||
check: bool(r == P)
|
||||
|
||||
r.sum(inf, P)
|
||||
check: bool(r == P)
|
||||
|
||||
test(ec, randZ = false)
|
||||
test(ec, randZ = true)
|
||||
|
||||
test "Adding opposites gives an infinity point":
|
||||
proc test(EC: typedesc, randZ: static bool) =
|
||||
for _ in 0 ..< Iters:
|
||||
var r{.noInit.}: EC
|
||||
when randZ:
|
||||
let P = rng.random_unsafe_with_randZ(EC)
|
||||
else:
|
||||
let P = rng.random_unsafe(EC)
|
||||
var Q = P
|
||||
Q.neg()
|
||||
|
||||
r.sum(P, Q)
|
||||
check: bool r.isInf()
|
||||
|
||||
r.sum(Q, P)
|
||||
check: bool r.isInf()
|
||||
|
||||
test(ec, randZ = false)
|
||||
test(ec, randZ = true)
|
||||
|
||||
test "EC " & G1_or_G2 & " add is commutative":
|
||||
proc test(EC: typedesc, randZ: static bool) =
|
||||
for _ in 0 ..< Iters:
|
||||
var r0{.noInit.}, r1{.noInit.}: EC
|
||||
when randZ:
|
||||
let P = rng.random_unsafe_with_randZ(EC)
|
||||
let Q = rng.random_unsafe_with_randZ(EC)
|
||||
else:
|
||||
let P = rng.random_unsafe(EC)
|
||||
let Q = rng.random_unsafe(EC)
|
||||
|
||||
r0.sum(P, Q)
|
||||
r1.sum(Q, P)
|
||||
check: bool(r0 == r1)
|
||||
|
||||
test(ec, randZ = false)
|
||||
test(ec, randZ = true)
|
||||
|
||||
test "EC " & G1_or_G2 & " add is associative":
|
||||
proc test(EC: typedesc, randZ: static bool) =
|
||||
for _ in 0 ..< Iters:
|
||||
when randZ:
|
||||
let a = rng.random_unsafe_with_randZ(EC)
|
||||
let b = rng.random_unsafe_with_randZ(EC)
|
||||
let c = rng.random_unsafe_with_randZ(EC)
|
||||
else:
|
||||
let a = rng.random_unsafe(EC)
|
||||
let b = rng.random_unsafe(EC)
|
||||
let c = rng.random_unsafe(EC)
|
||||
|
||||
var tmp1{.noInit.}, tmp2{.noInit.}: EC
|
||||
|
||||
# r0 = (a + b) + c
|
||||
tmp1.sum(a, b)
|
||||
tmp2.sum(tmp1, c)
|
||||
let r0 = tmp2
|
||||
|
||||
# r1 = a + (b + c)
|
||||
tmp1.sum(b, c)
|
||||
tmp2.sum(a, tmp1)
|
||||
let r1 = tmp2
|
||||
|
||||
# r2 = (a + c) + b
|
||||
tmp1.sum(a, c)
|
||||
tmp2.sum(tmp1, b)
|
||||
let r2 = tmp2
|
||||
|
||||
# r3 = a + (c + b)
|
||||
tmp1.sum(c, b)
|
||||
tmp2.sum(a, tmp1)
|
||||
let r3 = tmp2
|
||||
|
||||
# r4 = (c + a) + b
|
||||
tmp1.sum(c, a)
|
||||
tmp2.sum(tmp1, b)
|
||||
let r4 = tmp2
|
||||
|
||||
# ...
|
||||
|
||||
check:
|
||||
bool(r0 == r1)
|
||||
bool(r0 == r2)
|
||||
bool(r0 == r3)
|
||||
bool(r0 == r4)
|
||||
|
||||
test(ec, randZ = false)
|
||||
test(ec, randZ = true)
|
||||
|
||||
test "EC " & G1_or_G2 & " double and EC " & G1_or_G2 & " add are consistent":
|
||||
proc test(EC: typedesc, randZ: static bool) =
|
||||
for _ in 0 ..< Iters:
|
||||
when randZ:
|
||||
let a = rng.random_unsafe_with_randZ(EC)
|
||||
else:
|
||||
let a = rng.random_unsafe(EC)
|
||||
|
||||
var r0{.noInit.}, r1{.noInit.}: EC
|
||||
|
||||
r0.double(a)
|
||||
r1.sum(a, a)
|
||||
|
||||
check: bool(r0 == r1)
|
||||
|
||||
test(ec, randZ = false)
|
||||
test(ec, randZ = true)
|
||||
|
||||
proc run_EC_mul_sanity_tests*(
|
||||
ec: typedesc,
|
||||
ItersMul: static int,
|
||||
moduleName: string
|
||||
) =
|
||||
|
||||
# Random seed for reproducibility
|
||||
var rng: RngState
|
||||
let seed = uint32(getTime().toUnix() and (1'i64 shl 32 - 1)) # unixTime mod 2^32
|
||||
rng.seed(seed)
|
||||
echo "\n------------------------------------------------------\n"
|
||||
echo moduleName, " xoshiro512** seed: ", seed
|
||||
|
||||
when ec.F is Fp:
|
||||
const G1_or_G2 = "G1"
|
||||
else:
|
||||
const G1_or_G2 = "G2"
|
||||
|
||||
const testSuiteDesc = "Elliptic curve in Short Weierstrass form with projective coordinates"
|
||||
|
||||
suite testSuiteDesc & " - " & $ec & " - [" & $WordBitwidth & "-bit mode]":
|
||||
test "EC " & G1_or_G2 & " mul [0]P == Inf":
|
||||
proc test(EC: typedesc, bits: static int, randZ: static bool) =
|
||||
for _ in 0 ..< ItersMul:
|
||||
when randZ:
|
||||
let a = rng.random_unsafe_with_randZ(EC)
|
||||
else:
|
||||
let a = rng.random_unsafe(EC)
|
||||
|
||||
# zeroInit
|
||||
var exponentCanonical: array[(bits+7) div 8, byte]
|
||||
|
||||
var
|
||||
impl = a
|
||||
reference = a
|
||||
scratchSpace{.noInit.}: array[1 shl 4, EC]
|
||||
|
||||
impl.scalarMulGeneric(exponentCanonical, scratchSpace)
|
||||
reference.unsafe_ECmul_double_add(exponentCanonical)
|
||||
|
||||
check:
|
||||
bool(impl.isInf())
|
||||
bool(reference.isInf())
|
||||
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = false)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = true)
|
||||
|
||||
test "EC " & G1_or_G2 & " mul [1]P == P":
|
||||
proc test(EC: typedesc, bits: static int, randZ: static bool) =
|
||||
for _ in 0 ..< ItersMul:
|
||||
when randZ:
|
||||
let a = rng.random_unsafe_with_randZ(EC)
|
||||
else:
|
||||
let a = rng.random_unsafe(EC)
|
||||
|
||||
var exponent{.noInit.}: BigInt[bits]
|
||||
exponent.setOne()
|
||||
var exponentCanonical{.noInit.}: array[(bits+7) div 8, byte]
|
||||
exponentCanonical.exportRawUint(exponent, bigEndian)
|
||||
|
||||
var
|
||||
impl = a
|
||||
reference = a
|
||||
scratchSpace{.noInit.}: array[1 shl 4, EC]
|
||||
|
||||
impl.scalarMulGeneric(exponentCanonical, scratchSpace)
|
||||
reference.unsafe_ECmul_double_add(exponentCanonical)
|
||||
|
||||
check:
|
||||
bool(impl == a)
|
||||
bool(reference == a)
|
||||
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = false)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = true)
|
||||
|
||||
test "EC " & G1_or_G2 & " mul [2]P == P.double()":
|
||||
proc test(EC: typedesc, bits: static int, randZ: static bool) =
|
||||
for _ in 0 ..< ItersMul:
|
||||
when randZ:
|
||||
let a = rng.random_unsafe_with_randZ(EC)
|
||||
else:
|
||||
let a = rng.random_unsafe(EC)
|
||||
|
||||
var doubleA{.noInit.}: EC
|
||||
doubleA.double(a)
|
||||
|
||||
let exponent = BigInt[bits].fromUint(2)
|
||||
var exponentCanonical{.noInit.}: array[(bits+7) div 8, byte]
|
||||
exponentCanonical.exportRawUint(exponent, bigEndian)
|
||||
|
||||
var
|
||||
impl = a
|
||||
reference = a
|
||||
scratchSpace{.noInit.}: array[1 shl 4, EC]
|
||||
|
||||
impl.scalarMulGeneric(exponentCanonical, scratchSpace)
|
||||
reference.unsafe_ECmul_double_add(exponentCanonical)
|
||||
|
||||
check:
|
||||
bool(impl == doubleA)
|
||||
bool(reference == doubleA)
|
||||
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = false)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = true)
|
||||
|
||||
proc run_EC_mul_distributive_tests*(
|
||||
ec: typedesc,
|
||||
ItersMul: static int,
|
||||
moduleName: string
|
||||
) =
|
||||
|
||||
# Random seed for reproducibility
|
||||
var rng: RngState
|
||||
let seed = uint32(getTime().toUnix() and (1'i64 shl 32 - 1)) # unixTime mod 2^32
|
||||
rng.seed(seed)
|
||||
echo "\n------------------------------------------------------\n"
|
||||
echo moduleName, " xoshiro512** seed: ", seed
|
||||
|
||||
when ec.F is Fp:
|
||||
const G1_or_G2 = "G1"
|
||||
else:
|
||||
const G1_or_G2 = "G2"
|
||||
|
||||
const testSuiteDesc = "Elliptic curve in Short Weierstrass form with projective coordinates"
|
||||
|
||||
suite testSuiteDesc & " - " & $ec & " - [" & $WordBitwidth & "-bit mode]":
|
||||
|
||||
test "EC " & G1_or_G2 & " mul is distributive over EC add":
|
||||
proc test(EC: typedesc, bits: static int, randZ: static bool) =
|
||||
for _ in 0 ..< ItersMul:
|
||||
when randZ:
|
||||
let a = rng.random_unsafe_with_randZ(EC)
|
||||
let b = rng.random_unsafe_with_randZ(EC)
|
||||
else:
|
||||
let a = rng.random_unsafe(EC)
|
||||
let b = rng.random_unsafe_with_randZ(EC)
|
||||
|
||||
let exponent = rng.random_unsafe(BigInt[bits])
|
||||
var exponentCanonical{.noInit.}: array[(bits+7) div 8, byte]
|
||||
exponentCanonical.exportRawUint(exponent, bigEndian)
|
||||
|
||||
# [k](a + b) - Factorized
|
||||
var
|
||||
fImpl{.noInit.}: EC
|
||||
fReference{.noInit.}: EC
|
||||
scratchSpace{.noInit.}: array[1 shl 4, EC]
|
||||
|
||||
fImpl.sum(a, b)
|
||||
fReference.sum(a, b)
|
||||
|
||||
fImpl.scalarMulGeneric(exponentCanonical, scratchSpace)
|
||||
fReference.unsafe_ECmul_double_add(exponentCanonical)
|
||||
|
||||
# [k]a + [k]b - Distributed
|
||||
var kaImpl = a
|
||||
var kaRef = a
|
||||
|
||||
kaImpl.scalarMulGeneric(exponentCanonical, scratchSpace)
|
||||
kaRef.unsafe_ECmul_double_add(exponentCanonical)
|
||||
|
||||
var kbImpl = b
|
||||
var kbRef = b
|
||||
|
||||
kbImpl.scalarMulGeneric(exponentCanonical, scratchSpace)
|
||||
kbRef.unsafe_ECmul_double_add(exponentCanonical)
|
||||
|
||||
var kakbImpl{.noInit.}, kakbRef{.noInit.}: EC
|
||||
kakbImpl.sum(kaImpl, kbImpl)
|
||||
kakbRef.sum(kaRef, kbRef)
|
||||
|
||||
check:
|
||||
bool(fImpl == kakbImpl)
|
||||
bool(fReference == kakbRef)
|
||||
bool(fImpl == fReference)
|
||||
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = false)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = true)
|
||||
|
||||
proc run_EC_mul_vs_ref_impl*(
|
||||
ec: typedesc,
|
||||
ItersMul: static int,
|
||||
moduleName: string
|
||||
) =
|
||||
|
||||
# Random seed for reproducibility
|
||||
var rng: RngState
|
||||
let seed = uint32(getTime().toUnix() and (1'i64 shl 32 - 1)) # unixTime mod 2^32
|
||||
rng.seed(seed)
|
||||
echo "\n------------------------------------------------------\n"
|
||||
echo moduleName, " xoshiro512** seed: ", seed
|
||||
|
||||
when ec.F is Fp:
|
||||
const G1_or_G2 = "G1"
|
||||
else:
|
||||
const G1_or_G2 = "G2"
|
||||
|
||||
const testSuiteDesc = "Elliptic curve in Short Weierstrass form with projective coordinates"
|
||||
|
||||
suite testSuiteDesc & " - " & $ec & " - [" & $WordBitwidth & "-bit mode]":
|
||||
test "EC " & G1_or_G2 & " mul constant-time is equivalent to a simple double-and-add algorithm":
|
||||
proc test(EC: typedesc, bits: static int, randZ: static bool) =
|
||||
for _ in 0 ..< ItersMul:
|
||||
when randZ:
|
||||
let a = rng.random_unsafe_with_randZ(EC)
|
||||
else:
|
||||
let a = rng.random_unsafe(EC)
|
||||
|
||||
let exponent = rng.random_unsafe(BigInt[bits])
|
||||
var exponentCanonical{.noInit.}: array[(bits+7) div 8, byte]
|
||||
exponentCanonical.exportRawUint(exponent, bigEndian)
|
||||
|
||||
var
|
||||
impl = a
|
||||
reference = a
|
||||
scratchSpace{.noInit.}: array[1 shl 4, EC]
|
||||
|
||||
impl.scalarMulGeneric(exponentCanonical, scratchSpace)
|
||||
reference.unsafe_ECmul_double_add(exponentCanonical)
|
||||
|
||||
check: bool(impl == reference)
|
||||
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = false)
|
||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = true)
|
||||
@ -1,381 +0,0 @@
|
||||
# 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
|
||||
# Standard library
|
||||
std/[unittest, times],
|
||||
# Internals
|
||||
../constantine/config/[common, curves],
|
||||
../constantine/arithmetic,
|
||||
../constantine/io/io_bigints,
|
||||
../constantine/elliptic/[ec_weierstrass_affine, ec_weierstrass_projective, ec_scalar_mul],
|
||||
# Test utilities
|
||||
../helpers/prng_unsafe,
|
||||
./support/ec_reference_scalar_mult
|
||||
|
||||
const
|
||||
Iters = 128
|
||||
ItersMul = Iters div 4
|
||||
|
||||
var rng: RngState
|
||||
let seed = uint32(getTime().toUnix() and (1'i64 shl 32 - 1)) # unixTime mod 2^32
|
||||
rng.seed(seed)
|
||||
echo "test_ec_weierstrass_projective_g1 xoshiro512** seed: ", seed
|
||||
|
||||
# Import: wrap in elliptic curve tests in small procedures
|
||||
# otherwise they will become globals,
|
||||
# and will create binary size issues.
|
||||
# Also due to Nim stack scanning,
|
||||
# having too many elements on the stack (a couple kB)
|
||||
# will significantly slow down testing (100x is possible)
|
||||
|
||||
suite "Elliptic curve in Short Weierstrass form y² = x³ + a x + b with projective coordinates (X, Y, Z): Y²Z = X³ + aXZ² + bZ³ i.e. X = xZ, Y = yZ":
|
||||
test "The infinity point is the neutral element w.r.t. to EC addition":
|
||||
proc test(F: typedesc, randZ: static bool) =
|
||||
var inf {.noInit.}: ECP_SWei_Proj[F]
|
||||
inf.setInf()
|
||||
check: bool inf.isInf()
|
||||
|
||||
for _ in 0 ..< Iters:
|
||||
var r{.noInit.}: ECP_SWei_Proj[F]
|
||||
when randZ:
|
||||
let P = rng.random_unsafe_with_randZ(ECP_SWei_Proj[F])
|
||||
else:
|
||||
let P = rng.random_unsafe(ECP_SWei_Proj[F])
|
||||
|
||||
r.sum(P, inf)
|
||||
check: bool(r == P)
|
||||
|
||||
r.sum(inf, P)
|
||||
check: bool(r == P)
|
||||
|
||||
|
||||
test(Fp[BN254_Snarks], randZ = false)
|
||||
test(Fp[BN254_Snarks], randZ = true)
|
||||
test(Fp[BLS12_381], randZ = false)
|
||||
test(Fp[BLS12_381], randZ = true)
|
||||
|
||||
test "Adding opposites gives an infinity point":
|
||||
proc test(F: typedesc, randZ: static bool) =
|
||||
for _ in 0 ..< Iters:
|
||||
var r{.noInit.}: ECP_SWei_Proj[F]
|
||||
when randZ:
|
||||
let P = rng.random_unsafe_with_randZ(ECP_SWei_Proj[F])
|
||||
else:
|
||||
let P = rng.random_unsafe(ECP_SWei_Proj[F])
|
||||
var Q = P
|
||||
Q.neg()
|
||||
|
||||
r.sum(P, Q)
|
||||
check: bool r.isInf()
|
||||
|
||||
r.sum(Q, P)
|
||||
check: bool r.isInf()
|
||||
|
||||
test(Fp[BN254_Snarks], randZ = false)
|
||||
test(Fp[BN254_Snarks], randZ = true)
|
||||
test(Fp[BLS12_381], randZ = false)
|
||||
test(Fp[BLS12_381], randZ = true)
|
||||
|
||||
test "EC add is commutative":
|
||||
proc test(F: typedesc, randZ: static bool) =
|
||||
for _ in 0 ..< Iters:
|
||||
var r0{.noInit.}, r1{.noInit.}: ECP_SWei_Proj[F]
|
||||
when randZ:
|
||||
let P = rng.random_unsafe_with_randZ(ECP_SWei_Proj[F])
|
||||
let Q = rng.random_unsafe_with_randZ(ECP_SWei_Proj[F])
|
||||
else:
|
||||
let P = rng.random_unsafe(ECP_SWei_Proj[F])
|
||||
let Q = rng.random_unsafe(ECP_SWei_Proj[F])
|
||||
|
||||
r0.sum(P, Q)
|
||||
r1.sum(Q, P)
|
||||
check: bool(r0 == r1)
|
||||
|
||||
test(Fp[BN254_Snarks], randZ = false)
|
||||
test(Fp[BN254_Snarks], randZ = true)
|
||||
test(Fp[BLS12_381], randZ = false)
|
||||
test(Fp[BLS12_381], randZ = true)
|
||||
|
||||
test "EC add is associative":
|
||||
proc test(F: typedesc, randZ: static bool) =
|
||||
for _ in 0 ..< Iters:
|
||||
when randZ:
|
||||
let a = rng.random_unsafe_with_randZ(ECP_SWei_Proj[F])
|
||||
let b = rng.random_unsafe_with_randZ(ECP_SWei_Proj[F])
|
||||
let c = rng.random_unsafe_with_randZ(ECP_SWei_Proj[F])
|
||||
else:
|
||||
let a = rng.random_unsafe(ECP_SWei_Proj[F])
|
||||
let b = rng.random_unsafe(ECP_SWei_Proj[F])
|
||||
let c = rng.random_unsafe(ECP_SWei_Proj[F])
|
||||
|
||||
var tmp1{.noInit.}, tmp2{.noInit.}: ECP_SWei_Proj[F]
|
||||
|
||||
# r0 = (a + b) + c
|
||||
tmp1.sum(a, b)
|
||||
tmp2.sum(tmp1, c)
|
||||
let r0 = tmp2
|
||||
|
||||
# r1 = a + (b + c)
|
||||
tmp1.sum(b, c)
|
||||
tmp2.sum(a, tmp1)
|
||||
let r1 = tmp2
|
||||
|
||||
# r2 = (a + c) + b
|
||||
tmp1.sum(a, c)
|
||||
tmp2.sum(tmp1, b)
|
||||
let r2 = tmp2
|
||||
|
||||
# r3 = a + (c + b)
|
||||
tmp1.sum(c, b)
|
||||
tmp2.sum(a, tmp1)
|
||||
let r3 = tmp2
|
||||
|
||||
# r4 = (c + a) + b
|
||||
tmp1.sum(c, a)
|
||||
tmp2.sum(tmp1, b)
|
||||
let r4 = tmp2
|
||||
|
||||
# ...
|
||||
|
||||
check:
|
||||
bool(r0 == r1)
|
||||
bool(r0 == r2)
|
||||
bool(r0 == r3)
|
||||
bool(r0 == r4)
|
||||
|
||||
test(Fp[BN254_Snarks], randZ = false)
|
||||
test(Fp[BN254_Snarks], randZ = true)
|
||||
test(Fp[BLS12_381], randZ = false)
|
||||
test(Fp[BLS12_381], randZ = true)
|
||||
|
||||
test "EC double and EC add are consistent":
|
||||
proc test(F: typedesc, randZ: static bool) =
|
||||
for _ in 0 ..< Iters:
|
||||
when randZ:
|
||||
let a = rng.random_unsafe_with_randZ(ECP_SWei_Proj[F])
|
||||
else:
|
||||
let a = rng.random_unsafe(ECP_SWei_Proj[F])
|
||||
|
||||
var r0{.noInit.}, r1{.noInit.}: ECP_SWei_Proj[F]
|
||||
|
||||
r0.double(a)
|
||||
r1.sum(a, a)
|
||||
|
||||
check: bool(r0 == r1)
|
||||
|
||||
test(Fp[BN254_Snarks], randZ = false)
|
||||
test(Fp[BN254_Snarks], randZ = true)
|
||||
test(Fp[BLS12_381], randZ = false)
|
||||
test(Fp[BLS12_381], randZ = true)
|
||||
|
||||
|
||||
const BN254_Snarks_order_bits = BN254_Snarks.getCurveOrderBitwidth()
|
||||
const BLS12_381_order_bits = BLS12_381.getCurveOrderBitwidth()
|
||||
|
||||
test "EC mul [0]P == Inf":
|
||||
proc test(F: typedesc, bits: static int, randZ: static bool) =
|
||||
for _ in 0 ..< ItersMul:
|
||||
when randZ:
|
||||
let a = rng.random_unsafe_with_randZ(ECP_SWei_Proj[F])
|
||||
else:
|
||||
let a = rng.random_unsafe(ECP_SWei_Proj[F])
|
||||
|
||||
# zeroInit
|
||||
var exponentCanonical: array[(bits+7) div 8, byte]
|
||||
|
||||
var
|
||||
impl = a
|
||||
reference = a
|
||||
scratchSpace{.noInit.}: array[1 shl 4, ECP_SWei_Proj[F]]
|
||||
|
||||
impl.scalarMulGeneric(exponentCanonical, scratchSpace)
|
||||
reference.unsafe_ECmul_double_add(exponentCanonical)
|
||||
|
||||
check:
|
||||
bool(impl.isInf())
|
||||
bool(reference.isInf())
|
||||
|
||||
test(Fp[BN254_Snarks], bits = BN254_Snarks_order_bits, randZ = false)
|
||||
test(Fp[BN254_Snarks], bits = BN254_Snarks_order_bits, randZ = true)
|
||||
test(Fp[BLS12_381], bits = BLS12_381_order_bits, randZ = false)
|
||||
test(Fp[BLS12_381], bits = BLS12_381_order_bits, randZ = true)
|
||||
|
||||
test "EC mul [Order]P == Inf":
|
||||
proc test(F: typedesc, bits: static int, randZ: static bool) =
|
||||
for _ in 0 ..< ItersMul:
|
||||
when randZ:
|
||||
let a = rng.random_unsafe_with_randZ(ECP_SWei_Proj[F])
|
||||
else:
|
||||
let a = rng.random_unsafe(ECP_SWei_Proj[F])
|
||||
|
||||
let exponent = F.C.getCurveOrder()
|
||||
var exponentCanonical{.noInit.}: array[(bits+7) div 8, byte]
|
||||
exponentCanonical.exportRawUint(exponent, bigEndian)
|
||||
|
||||
var
|
||||
impl = a
|
||||
reference = a
|
||||
scratchSpace{.noInit.}: array[1 shl 4, ECP_SWei_Proj[F]]
|
||||
|
||||
impl.scalarMulGeneric(exponentCanonical, scratchSpace)
|
||||
reference.unsafe_ECmul_double_add(exponentCanonical)
|
||||
|
||||
check:
|
||||
bool(impl.isInf())
|
||||
bool(reference.isInf())
|
||||
|
||||
test(Fp[BN254_Snarks], bits = BN254_Snarks_order_bits, randZ = false)
|
||||
test(Fp[BN254_Snarks], bits = BN254_Snarks_order_bits, randZ = true)
|
||||
# TODO: BLS12 is using a subgroup of order "r" such as r*h = CurveOrder
|
||||
# with h the curve cofactor
|
||||
# instead of the full group
|
||||
# test(Fp[BLS12_381], bits = BLS12_381_order_bits, randZ = false)
|
||||
# test(Fp[BLS12_381], bits = BLS12_381_order_bits, randZ = true)
|
||||
|
||||
test "EC mul [1]P == P":
|
||||
proc test(F: typedesc, bits: static int, randZ: static bool) =
|
||||
for _ in 0 ..< ItersMul:
|
||||
when randZ:
|
||||
let a = rng.random_unsafe_with_randZ(ECP_SWei_Proj[F])
|
||||
else:
|
||||
let a = rng.random_unsafe(ECP_SWei_Proj[F])
|
||||
|
||||
var exponent{.noInit.}: BigInt[bits]
|
||||
exponent.setOne()
|
||||
var exponentCanonical{.noInit.}: array[(bits+7) div 8, byte]
|
||||
exponentCanonical.exportRawUint(exponent, bigEndian)
|
||||
|
||||
var
|
||||
impl = a
|
||||
reference = a
|
||||
scratchSpace{.noInit.}: array[1 shl 4, ECP_SWei_Proj[F]]
|
||||
|
||||
impl.scalarMulGeneric(exponentCanonical, scratchSpace)
|
||||
reference.unsafe_ECmul_double_add(exponentCanonical)
|
||||
|
||||
check:
|
||||
bool(impl == a)
|
||||
bool(reference == a)
|
||||
|
||||
test(Fp[BN254_Snarks], bits = BN254_Snarks_order_bits, randZ = false)
|
||||
test(Fp[BN254_Snarks], bits = BN254_Snarks_order_bits, randZ = true)
|
||||
test(Fp[BLS12_381], bits = BLS12_381_order_bits, randZ = false)
|
||||
test(Fp[BLS12_381], bits = BLS12_381_order_bits, randZ = true)
|
||||
|
||||
test "EC mul [2]P == P.double()":
|
||||
proc test(F: typedesc, bits: static int, randZ: static bool) =
|
||||
for _ in 0 ..< ItersMul:
|
||||
when randZ:
|
||||
let a = rng.random_unsafe_with_randZ(ECP_SWei_Proj[F])
|
||||
else:
|
||||
let a = rng.random_unsafe(ECP_SWei_Proj[F])
|
||||
|
||||
var doubleA{.noInit.}: ECP_SWei_Proj[F]
|
||||
doubleA.double(a)
|
||||
|
||||
let exponent = BigInt[bits].fromUint(2)
|
||||
var exponentCanonical{.noInit.}: array[(bits+7) div 8, byte]
|
||||
exponentCanonical.exportRawUint(exponent, bigEndian)
|
||||
|
||||
var
|
||||
impl = a
|
||||
reference = a
|
||||
scratchSpace{.noInit.}: array[1 shl 4, ECP_SWei_Proj[F]]
|
||||
|
||||
impl.scalarMulGeneric(exponentCanonical, scratchSpace)
|
||||
reference.unsafe_ECmul_double_add(exponentCanonical)
|
||||
|
||||
check:
|
||||
bool(impl == doubleA)
|
||||
bool(reference == doubleA)
|
||||
|
||||
test(Fp[BN254_Snarks], bits = BN254_Snarks_order_bits, randZ = false)
|
||||
test(Fp[BN254_Snarks], bits = BN254_Snarks_order_bits, randZ = true)
|
||||
test(Fp[BLS12_381], bits = BLS12_381_order_bits, randZ = false)
|
||||
test(Fp[BLS12_381], bits = BLS12_381_order_bits, randZ = true)
|
||||
|
||||
test "EC mul is distributive over EC add":
|
||||
proc test(F: typedesc, bits: static int, randZ: static bool) =
|
||||
for _ in 0 ..< ItersMul:
|
||||
when randZ:
|
||||
let a = rng.random_unsafe_with_randZ(ECP_SWei_Proj[F])
|
||||
let b = rng.random_unsafe_with_randZ(ECP_SWei_Proj[F])
|
||||
else:
|
||||
let a = rng.random_unsafe(ECP_SWei_Proj[F])
|
||||
let b = rng.random_unsafe_with_randZ(ECP_SWei_Proj[F])
|
||||
|
||||
let exponent = rng.random_unsafe(BigInt[bits])
|
||||
var exponentCanonical{.noInit.}: array[(bits+7) div 8, byte]
|
||||
exponentCanonical.exportRawUint(exponent, bigEndian)
|
||||
|
||||
# [k](a + b) - Factorized
|
||||
var
|
||||
fImpl{.noInit.}: ECP_SWei_Proj[F]
|
||||
fReference{.noInit.}: ECP_SWei_Proj[F]
|
||||
scratchSpace{.noInit.}: array[1 shl 4, ECP_SWei_Proj[F]]
|
||||
|
||||
fImpl.sum(a, b)
|
||||
fReference.sum(a, b)
|
||||
|
||||
fImpl.scalarMulGeneric(exponentCanonical, scratchSpace)
|
||||
fReference.unsafe_ECmul_double_add(exponentCanonical)
|
||||
|
||||
# [k]a + [k]b - Distributed
|
||||
var kaImpl = a
|
||||
var kaRef = a
|
||||
|
||||
kaImpl.scalarMulGeneric(exponentCanonical, scratchSpace)
|
||||
kaRef.unsafe_ECmul_double_add(exponentCanonical)
|
||||
|
||||
var kbImpl = b
|
||||
var kbRef = b
|
||||
|
||||
kbImpl.scalarMulGeneric(exponentCanonical, scratchSpace)
|
||||
kbRef.unsafe_ECmul_double_add(exponentCanonical)
|
||||
|
||||
var kakbImpl{.noInit.}, kakbRef{.noInit.}: ECP_SWei_Proj[F]
|
||||
kakbImpl.sum(kaImpl, kbImpl)
|
||||
kakbRef.sum(kaRef, kbRef)
|
||||
|
||||
check:
|
||||
bool(fImpl == kakbImpl)
|
||||
bool(fReference == kakbRef)
|
||||
bool(fImpl == fReference)
|
||||
|
||||
test(Fp[BN254_Snarks], bits = BN254_Snarks_order_bits, randZ = false)
|
||||
test(Fp[BN254_Snarks], bits = BN254_Snarks_order_bits, randZ = true)
|
||||
test(Fp[BLS12_381], bits = BLS12_381_order_bits, randZ = false)
|
||||
test(Fp[BLS12_381], bits = BLS12_381_order_bits, randZ = true)
|
||||
|
||||
test "EC mul constant-time is equivalent to a simple double-and-add algorithm":
|
||||
proc test(F: typedesc, bits: static int, randZ: static bool) =
|
||||
for _ in 0 ..< ItersMul:
|
||||
when randZ:
|
||||
let a = rng.random_unsafe_with_randZ(ECP_SWei_Proj[F])
|
||||
else:
|
||||
let a = rng.random_unsafe(ECP_SWei_Proj[F])
|
||||
|
||||
let exponent = rng.random_unsafe(BigInt[bits])
|
||||
var exponentCanonical{.noInit.}: array[(bits+7) div 8, byte]
|
||||
exponentCanonical.exportRawUint(exponent, bigEndian)
|
||||
|
||||
var
|
||||
impl = a
|
||||
reference = a
|
||||
scratchSpace{.noInit.}: array[1 shl 4, ECP_SWei_Proj[F]]
|
||||
|
||||
impl.scalarMulGeneric(exponentCanonical, scratchSpace)
|
||||
reference.unsafe_ECmul_double_add(exponentCanonical)
|
||||
|
||||
check: bool(impl == reference)
|
||||
|
||||
test(Fp[BN254_Snarks], bits = BN254_Snarks_order_bits, randZ = false)
|
||||
test(Fp[BN254_Snarks], bits = BN254_Snarks_order_bits, randZ = true)
|
||||
test(Fp[BLS12_381], bits = BLS12_381_order_bits, randZ = false)
|
||||
test(Fp[BLS12_381], bits = BLS12_381_order_bits, randZ = true)
|
||||
34
tests/test_ec_weierstrass_projective_g1_add_double.nim
Normal file
34
tests/test_ec_weierstrass_projective_g1_add_double.nim
Normal file
@ -0,0 +1,34 @@
|
||||
# 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
|
||||
# Standard library
|
||||
std/[unittest, times],
|
||||
# Internals
|
||||
../constantine/config/[common, curves],
|
||||
../constantine/arithmetic,
|
||||
../constantine/io/io_bigints,
|
||||
../constantine/elliptic/[ec_weierstrass_affine, ec_weierstrass_projective],
|
||||
# Test utilities
|
||||
../helpers/prng_unsafe,
|
||||
./test_ec_template
|
||||
|
||||
const
|
||||
Iters = 128
|
||||
|
||||
run_EC_addition_tests(
|
||||
ec = ECP_SWei_Proj[Fp[BN254_Snarks]],
|
||||
Iters = Iters,
|
||||
moduleName = "test_ec_weierstrass_projective_g1_add_double_" & $BN254_Snarks
|
||||
)
|
||||
|
||||
run_EC_addition_tests(
|
||||
ec = ECP_SWei_Proj[Fp[BLS12_381]],
|
||||
Iters = Iters,
|
||||
moduleName = "test_ec_weierstrass_projective_g1_add_double_" & $BLS12_381
|
||||
)
|
||||
36
tests/test_ec_weierstrass_projective_g1_mul_distributive.nim
Normal file
36
tests/test_ec_weierstrass_projective_g1_mul_distributive.nim
Normal file
@ -0,0 +1,36 @@
|
||||
# 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
|
||||
# Standard library
|
||||
std/[unittest, times],
|
||||
# Internals
|
||||
../constantine/config/[common, curves],
|
||||
../constantine/arithmetic,
|
||||
../constantine/io/io_bigints,
|
||||
../constantine/elliptic/[ec_weierstrass_affine, ec_weierstrass_projective, ec_scalar_mul],
|
||||
# Test utilities
|
||||
../helpers/prng_unsafe,
|
||||
./support/ec_reference_scalar_mult,
|
||||
./test_ec_template
|
||||
|
||||
const
|
||||
Iters = 128
|
||||
ItersMul = Iters div 4
|
||||
|
||||
run_EC_mul_distributive_tests(
|
||||
ec = ECP_SWei_Proj[Fp[BN254_Snarks]],
|
||||
ItersMul = ItersMul,
|
||||
moduleName = "test_ec_weierstrass_projective_g1_mul_distributive_" & $BN254_Snarks
|
||||
)
|
||||
|
||||
run_EC_mul_distributive_tests(
|
||||
ec = ECP_SWei_Proj[Fp[BLS12_381]],
|
||||
ItersMul = ItersMul,
|
||||
moduleName = "test_ec_weierstrass_projective_g1_mul_distributive_" & $BLS12_381
|
||||
)
|
||||
74
tests/test_ec_weierstrass_projective_g1_mul_sanity.nim
Normal file
74
tests/test_ec_weierstrass_projective_g1_mul_sanity.nim
Normal file
@ -0,0 +1,74 @@
|
||||
# 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
|
||||
# Standard library
|
||||
std/[unittest, times],
|
||||
# Internals
|
||||
../constantine/config/[common, curves],
|
||||
../constantine/arithmetic,
|
||||
../constantine/io/io_bigints,
|
||||
../constantine/elliptic/[ec_weierstrass_affine, ec_weierstrass_projective, ec_scalar_mul],
|
||||
# Test utilities
|
||||
../helpers/prng_unsafe,
|
||||
./support/ec_reference_scalar_mult,
|
||||
./test_ec_template
|
||||
|
||||
const
|
||||
Iters = 128
|
||||
ItersMul = Iters div 4
|
||||
|
||||
run_EC_mul_sanity_tests(
|
||||
ec = ECP_SWei_Proj[Fp[BN254_Snarks]],
|
||||
ItersMul = ItersMul,
|
||||
moduleName = "test_ec_weierstrass_projective_g1_mul_sanity_" & $BN254_Snarks
|
||||
)
|
||||
|
||||
run_EC_mul_sanity_tests(
|
||||
ec = ECP_SWei_Proj[Fp[BLS12_381]],
|
||||
ItersMul = ItersMul,
|
||||
moduleName = "test_ec_weierstrass_projective_g1_mul_sanity_" & $BLS12_381
|
||||
)
|
||||
|
||||
|
||||
test "EC mul [Order]P == Inf":
|
||||
var rng: RngState
|
||||
let seed = uint32(getTime().toUnix() and (1'i64 shl 32 - 1)) # unixTime mod 2^32
|
||||
rng.seed(seed)
|
||||
echo "test_ec_weierstrass_projective_g1_mul_sanity_extra_curve_order_mul_sanity xoshiro512** seed: ", seed
|
||||
|
||||
proc test(EC: typedesc, bits: static int, randZ: static bool) =
|
||||
for _ in 0 ..< ItersMul:
|
||||
when randZ:
|
||||
let a = rng.random_unsafe_with_randZ(EC)
|
||||
else:
|
||||
let a = rng.random_unsafe(EC)
|
||||
|
||||
let exponent = EC.F.C.getCurveOrder()
|
||||
var exponentCanonical{.noInit.}: array[(bits+7) div 8, byte]
|
||||
exponentCanonical.exportRawUint(exponent, bigEndian)
|
||||
|
||||
var
|
||||
impl = a
|
||||
reference = a
|
||||
scratchSpace{.noInit.}: array[1 shl 4, EC]
|
||||
|
||||
impl.scalarMulGeneric(exponentCanonical, scratchSpace)
|
||||
reference.unsafe_ECmul_double_add(exponentCanonical)
|
||||
|
||||
check:
|
||||
bool(impl.isInf())
|
||||
bool(reference.isInf())
|
||||
|
||||
test(ECP_SWei_Proj[Fp[BN254_Snarks]], bits = BN254_Snarks.getCurveOrderBitwidth(), randZ = false)
|
||||
test(ECP_SWei_Proj[Fp[BN254_Snarks]], bits = BN254_Snarks.getCurveOrderBitwidth(), randZ = true)
|
||||
# TODO: BLS12 is using a subgroup of order "r" such as r*h = CurveOrder
|
||||
# with h the curve cofactor
|
||||
# instead of the full group
|
||||
# test(Fp[BLS12_381], bits = BLS12_381.getCurveOrderBitwidth(), randZ = false)
|
||||
# test(Fp[BLS12_381], bits = BLS12_381.getCurveOrderBitwidth(), randZ = true)
|
||||
36
tests/test_ec_weierstrass_projective_g1_mul_vs_ref.nim
Normal file
36
tests/test_ec_weierstrass_projective_g1_mul_vs_ref.nim
Normal file
@ -0,0 +1,36 @@
|
||||
# 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
|
||||
# Standard library
|
||||
std/[unittest, times],
|
||||
# Internals
|
||||
../constantine/config/[common, curves],
|
||||
../constantine/arithmetic,
|
||||
../constantine/io/io_bigints,
|
||||
../constantine/elliptic/[ec_weierstrass_affine, ec_weierstrass_projective, ec_scalar_mul],
|
||||
# Test utilities
|
||||
../helpers/prng_unsafe,
|
||||
./support/ec_reference_scalar_mult,
|
||||
./test_ec_template
|
||||
|
||||
const
|
||||
Iters = 128
|
||||
ItersMul = Iters div 4
|
||||
|
||||
run_EC_mul_vs_ref_impl(
|
||||
ec = ECP_SWei_Proj[Fp[BN254_Snarks]],
|
||||
ItersMul = ItersMul,
|
||||
moduleName = "test_ec_weierstrass_projective_g1_mul_vs_ref_" & $BN254_Snarks
|
||||
)
|
||||
|
||||
run_EC_mul_vs_ref_impl(
|
||||
ec = ECP_SWei_Proj[Fp[BLS12_381]],
|
||||
ItersMul = ItersMul,
|
||||
moduleName = "test_ec_weierstrass_projective_g1_mul_vs_ref_" & $BLS12_381
|
||||
)
|
||||
@ -0,0 +1,29 @@
|
||||
# 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
|
||||
# Standard library
|
||||
std/[unittest, times],
|
||||
# Internals
|
||||
../constantine/config/[common, curves],
|
||||
../constantine/arithmetic,
|
||||
../constantine/towers,
|
||||
../constantine/io/io_bigints,
|
||||
../constantine/elliptic/[ec_weierstrass_affine, ec_weierstrass_projective],
|
||||
# Test utilities
|
||||
../helpers/prng_unsafe,
|
||||
./test_ec_template
|
||||
|
||||
const
|
||||
Iters = 128
|
||||
|
||||
run_EC_addition_tests(
|
||||
ec = ECP_SWei_Proj[Fp2[BLS12_381]],
|
||||
Iters = Iters,
|
||||
moduleName = "test_ec_weierstrass_projective_g2_add_double_" & $BLS12_381
|
||||
)
|
||||
@ -0,0 +1,29 @@
|
||||
# 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
|
||||
# Standard library
|
||||
std/[unittest, times],
|
||||
# Internals
|
||||
../constantine/config/[common, curves],
|
||||
../constantine/arithmetic,
|
||||
../constantine/towers,
|
||||
../constantine/io/io_bigints,
|
||||
../constantine/elliptic/[ec_weierstrass_affine, ec_weierstrass_projective],
|
||||
# Test utilities
|
||||
../helpers/prng_unsafe,
|
||||
./test_ec_template
|
||||
|
||||
const
|
||||
Iters = 128
|
||||
|
||||
run_EC_addition_tests(
|
||||
ec = ECP_SWei_Proj[Fp2[BN254_Snarks]],
|
||||
Iters = Iters,
|
||||
moduleName = "test_ec_weierstrass_projective_g2_add_double_" & $BN254_Snarks
|
||||
)
|
||||
@ -0,0 +1,31 @@
|
||||
# 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
|
||||
# Standard library
|
||||
std/[unittest, times],
|
||||
# Internals
|
||||
../constantine/config/[common, curves],
|
||||
../constantine/arithmetic,
|
||||
../constantine/towers,
|
||||
../constantine/io/io_bigints,
|
||||
../constantine/elliptic/[ec_weierstrass_affine, ec_weierstrass_projective, ec_scalar_mul],
|
||||
# Test utilities
|
||||
../helpers/prng_unsafe,
|
||||
./support/ec_reference_scalar_mult,
|
||||
./test_ec_template
|
||||
|
||||
const
|
||||
Iters = 128
|
||||
ItersMul = Iters div 4
|
||||
|
||||
run_EC_mul_distributive_tests(
|
||||
ec = ECP_SWei_Proj[Fp2[BLS12_381]],
|
||||
ItersMul = ItersMul,
|
||||
moduleName = "test_ec_weierstrass_projective_g2_mul_distributive_" & $BLS12_381
|
||||
)
|
||||
@ -0,0 +1,31 @@
|
||||
# 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
|
||||
# Standard library
|
||||
std/[unittest, times],
|
||||
# Internals
|
||||
../constantine/config/[common, curves],
|
||||
../constantine/arithmetic,
|
||||
../constantine/towers,
|
||||
../constantine/io/io_bigints,
|
||||
../constantine/elliptic/[ec_weierstrass_affine, ec_weierstrass_projective, ec_scalar_mul],
|
||||
# Test utilities
|
||||
../helpers/prng_unsafe,
|
||||
./support/ec_reference_scalar_mult,
|
||||
./test_ec_template
|
||||
|
||||
const
|
||||
Iters = 128
|
||||
ItersMul = Iters div 4
|
||||
|
||||
run_EC_mul_distributive_tests(
|
||||
ec = ECP_SWei_Proj[Fp2[BN254_Snarks]],
|
||||
ItersMul = ItersMul,
|
||||
moduleName = "test_ec_weierstrass_projective_g2_mul_distributive_" & $BN254_Snarks
|
||||
)
|
||||
@ -0,0 +1,65 @@
|
||||
# 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
|
||||
# Standard library
|
||||
std/[unittest, times],
|
||||
# Internals
|
||||
../constantine/config/[common, curves],
|
||||
../constantine/arithmetic,
|
||||
../constantine/towers,
|
||||
../constantine/io/io_bigints,
|
||||
../constantine/elliptic/[ec_weierstrass_affine, ec_weierstrass_projective, ec_scalar_mul],
|
||||
# Test utilities
|
||||
../helpers/prng_unsafe,
|
||||
./support/ec_reference_scalar_mult,
|
||||
./test_ec_template
|
||||
|
||||
const
|
||||
Iters = 128
|
||||
ItersMul = Iters div 4
|
||||
|
||||
run_EC_mul_sanity_tests(
|
||||
ec = ECP_SWei_Proj[Fp2[BLS12_381]],
|
||||
ItersMul = ItersMul,
|
||||
moduleName = "test_ec_weierstrass_projective_g2_mul_sanity_" & $BLS12_381
|
||||
)
|
||||
|
||||
# TODO: the order on E'(Fp2) for BLS curves is ??? with r the order on E(Fp)
|
||||
#
|
||||
# test "EC mul [Order]P == Inf":
|
||||
# var rng: RngState
|
||||
# let seed = uint32(getTime().toUnix() and (1'i64 shl 32 - 1)) # unixTime mod 2^32
|
||||
# rng.seed(seed)
|
||||
# echo "test_ec_weierstrass_projective_g1_mul_sanity_extra_curve_order_mul_sanity xoshiro512** seed: ", seed
|
||||
#
|
||||
# proc test(EC: typedesc, bits: static int, randZ: static bool) =
|
||||
# for _ in 0 ..< ItersMul:
|
||||
# when randZ:
|
||||
# let a = rng.random_unsafe_with_randZ(EC)
|
||||
# else:
|
||||
# let a = rng.random_unsafe(EC)
|
||||
#
|
||||
# let exponent = F.C.getCurveOrder()
|
||||
# var exponentCanonical{.noInit.}: array[(bits+7) div 8, byte]
|
||||
# exponentCanonical.exportRawUint(exponent, bigEndian)
|
||||
#
|
||||
# var
|
||||
# impl = a
|
||||
# reference = a
|
||||
# scratchSpace{.noInit.}: array[1 shl 4, EC]
|
||||
#
|
||||
# impl.scalarMulGeneric(exponentCanonical, scratchSpace)
|
||||
# reference.unsafe_ECmul_double_add(exponentCanonical)
|
||||
#
|
||||
# check:
|
||||
# bool(impl.isInf())
|
||||
# bool(reference.isInf())
|
||||
#
|
||||
# test(ECP_SWei_Proj[Fp2[BLS12_381]], bits = BLS12_381.getCurveOrderBitwidth(), randZ = false)
|
||||
# test(ECP_SWei_Proj[Fp2[BLS12_381]], bits = BLS12_381.getCurveOrderBitwidth(), randZ = true)
|
||||
@ -0,0 +1,65 @@
|
||||
# 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
|
||||
# Standard library
|
||||
std/[unittest, times],
|
||||
# Internals
|
||||
../constantine/config/[common, curves],
|
||||
../constantine/arithmetic,
|
||||
../constantine/towers,
|
||||
../constantine/io/io_bigints,
|
||||
../constantine/elliptic/[ec_weierstrass_affine, ec_weierstrass_projective, ec_scalar_mul],
|
||||
# Test utilities
|
||||
../helpers/prng_unsafe,
|
||||
./support/ec_reference_scalar_mult,
|
||||
./test_ec_template
|
||||
|
||||
const
|
||||
Iters = 128
|
||||
ItersMul = Iters div 4
|
||||
|
||||
run_EC_mul_sanity_tests(
|
||||
ec = ECP_SWei_Proj[Fp2[BN254_Snarks]],
|
||||
ItersMul = ItersMul,
|
||||
moduleName = "test_ec_weierstrass_projective_g2_mul_sanity_" & $BN254_Snarks
|
||||
)
|
||||
|
||||
# TODO: the order on E'(Fp2) for BN curve is r∗(2p−r) with r the order on E(Fp)
|
||||
#
|
||||
# test "EC mul [Order]P == Inf":
|
||||
# var rng: RngState
|
||||
# let seed = uint32(getTime().toUnix() and (1'i64 shl 32 - 1)) # unixTime mod 2^32
|
||||
# rng.seed(seed)
|
||||
# echo "test_ec_weierstrass_projective_g1_mul_sanity_extra_curve_order_mul_sanity xoshiro512** seed: ", seed
|
||||
#
|
||||
# proc test(EC: typedesc, bits: static int, randZ: static bool) =
|
||||
# for _ in 0 ..< ItersMul:
|
||||
# when randZ:
|
||||
# let a = rng.random_unsafe_with_randZ(EC)
|
||||
# else:
|
||||
# let a = rng.random_unsafe(EC)
|
||||
#
|
||||
# let exponent = F.C.getCurveOrder()
|
||||
# var exponentCanonical{.noInit.}: array[(bits+7) div 8, byte]
|
||||
# exponentCanonical.exportRawUint(exponent, bigEndian)
|
||||
#
|
||||
# var
|
||||
# impl = a
|
||||
# reference = a
|
||||
# scratchSpace{.noInit.}: array[1 shl 4, EC]
|
||||
#
|
||||
# impl.scalarMulGeneric(exponentCanonical, scratchSpace)
|
||||
# reference.unsafe_ECmul_double_add(exponentCanonical)
|
||||
#
|
||||
# check:
|
||||
# bool(impl.isInf())
|
||||
# bool(reference.isInf())
|
||||
#
|
||||
# test(ECP_SWei_Proj[Fp2[BN254_Snarks]], bits = BN254_Snarks.getCurveOrderBitwidth(), randZ = false)
|
||||
# test(ECP_SWei_Proj[Fp2[BN254_Snarks]], bits = BN254_Snarks.getCurveOrderBitwidth(), randZ = true)
|
||||
@ -0,0 +1,31 @@
|
||||
# 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
|
||||
# Standard library
|
||||
std/[unittest, times],
|
||||
# Internals
|
||||
../constantine/config/[common, curves],
|
||||
../constantine/arithmetic,
|
||||
../constantine/towers,
|
||||
../constantine/io/io_bigints,
|
||||
../constantine/elliptic/[ec_weierstrass_affine, ec_weierstrass_projective, ec_scalar_mul],
|
||||
# Test utilities
|
||||
../helpers/prng_unsafe,
|
||||
./support/ec_reference_scalar_mult,
|
||||
./test_ec_template
|
||||
|
||||
const
|
||||
Iters = 128
|
||||
ItersMul = Iters div 4
|
||||
|
||||
run_EC_mul_vs_ref_impl(
|
||||
ec = ECP_SWei_Proj[Fp2[BLS12_381]],
|
||||
ItersMul = ItersMul,
|
||||
moduleName = "test_ec_weierstrass_projective_g2_mul_vs_ref_" & $BLS12_381
|
||||
)
|
||||
@ -0,0 +1,31 @@
|
||||
# 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
|
||||
# Standard library
|
||||
std/[unittest, times],
|
||||
# Internals
|
||||
../constantine/config/[common, curves],
|
||||
../constantine/arithmetic,
|
||||
../constantine/towers,
|
||||
../constantine/io/io_bigints,
|
||||
../constantine/elliptic/[ec_weierstrass_affine, ec_weierstrass_projective, ec_scalar_mul],
|
||||
# Test utilities
|
||||
../helpers/prng_unsafe,
|
||||
./support/ec_reference_scalar_mult,
|
||||
./test_ec_template
|
||||
|
||||
const
|
||||
Iters = 128
|
||||
ItersMul = Iters div 4
|
||||
|
||||
run_EC_mul_vs_ref_impl(
|
||||
ec = ECP_SWei_Proj[Fp2[BN254_Snarks]],
|
||||
ItersMul = ItersMul,
|
||||
moduleName = "test_ec_weierstrass_projective_g2_mul_vs_ref_" & $BN254_Snarks
|
||||
)
|
||||
@ -13,6 +13,8 @@ import std/unittest,
|
||||
|
||||
static: doAssert defined(testingCurves), "This modules requires the -d:testingCurves compile option"
|
||||
|
||||
echo "\n------------------------------------------------------\n"
|
||||
|
||||
proc main() =
|
||||
suite "Basic arithmetic over finite fields":
|
||||
test "Addition mod 101":
|
||||
|
||||
@ -21,6 +21,7 @@ const Iters = 128
|
||||
var rng: RngState
|
||||
let seed = uint32(getTime().toUnix() and (1'i64 shl 32 - 1)) # unixTime mod 2^32
|
||||
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"
|
||||
@ -76,7 +77,7 @@ proc sanity(C: static Curve) =
|
||||
bool(n == expected)
|
||||
|
||||
proc mainSanity() =
|
||||
suite "Modular squaring is consistent with multiplication on special elements":
|
||||
suite "Modular squaring is consistent with multiplication on special elements" & " [" & $WordBitwidth & "-bit mode]":
|
||||
sanity Fake101
|
||||
sanity Mersenne61
|
||||
sanity Mersenne127
|
||||
@ -87,7 +88,7 @@ proc mainSanity() =
|
||||
mainSanity()
|
||||
|
||||
proc mainSelectCases() =
|
||||
suite "Modular Squaring: selected tricky cases":
|
||||
suite "Modular Squaring: selected tricky cases" & " [" & $WordBitwidth & "-bit mode]":
|
||||
test "P-256 [FastSquaring = " & $P256.canUseNoCarryMontySquare & "]":
|
||||
block:
|
||||
# Triggered an issue in the (t[N+1], t[N]) = t[N] + (A1, A0)
|
||||
@ -114,7 +115,7 @@ proc randomCurve(C: static Curve) =
|
||||
|
||||
doAssert bool(r_mul == r_sqr)
|
||||
|
||||
suite "Random Modular Squaring is consistent with Modular Multiplication":
|
||||
suite "Random Modular Squaring is consistent with Modular Multiplication" & " [" & $WordBitwidth & "-bit mode]":
|
||||
test "Random squaring mod P-224 [FastSquaring = " & $P224.canUseNoCarryMontySquare & "]":
|
||||
for _ in 0 ..< Iters:
|
||||
randomCurve(P224)
|
||||
|
||||
@ -10,6 +10,7 @@ import
|
||||
# Standard library
|
||||
std/[unittest, times],
|
||||
# Internal
|
||||
../constantine/config/common,
|
||||
../constantine/arithmetic,
|
||||
../constantine/io/[io_bigints, io_fields],
|
||||
../constantine/config/curves,
|
||||
@ -24,10 +25,11 @@ const Iters = 512
|
||||
var rng: RngState
|
||||
let seed = uint32(getTime().toUnix() and (1'i64 shl 32 - 1)) # unixTime mod 2^32
|
||||
rng.seed(seed)
|
||||
echo "\n------------------------------------------------------\n"
|
||||
echo "test_finite_fields_powinv xoshiro512** seed: ", seed
|
||||
|
||||
proc main() =
|
||||
suite "Modular exponentiation over finite fields":
|
||||
suite "Modular exponentiation over finite fields" & " [" & $WordBitwidth & "-bit mode]":
|
||||
test "n² mod 101":
|
||||
let exponent = BigInt[64].fromUint(2'u64)
|
||||
|
||||
@ -181,7 +183,7 @@ proc main() =
|
||||
testRandomDiv2 BLS12_461
|
||||
testRandomDiv2 BN462
|
||||
|
||||
suite "Modular inversion over prime fields":
|
||||
suite "Modular inversion over prime fields" & " [" & $WordBitwidth & "-bit mode]":
|
||||
test "Specific tests on Fp[BLS12_381]":
|
||||
block: # No inverse exist for 0 --> should return 0 for projective/jacobian to affine coordinate conversion
|
||||
var r, x: Fp[BLS12_381]
|
||||
|
||||
@ -22,6 +22,7 @@ const Iters = 128
|
||||
var rng: RngState
|
||||
let seed = uint32(getTime().toUnix() and (1'i64 shl 32 - 1)) # unixTime mod 2^32
|
||||
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"
|
||||
@ -59,11 +60,11 @@ proc exhaustiveCheck_p3mod4(C: static Curve, modulus: static int) =
|
||||
var a2 = a
|
||||
check:
|
||||
bool a.isSquare()
|
||||
bool a.sqrt_if_square_p3mod4()
|
||||
bool a.sqrt_if_square()
|
||||
|
||||
# 2 different code paths have the same result
|
||||
# (despite 2 square roots existing per square)
|
||||
a2.sqrt_p3mod4()
|
||||
a2.sqrt()
|
||||
check: bool(a == a2)
|
||||
|
||||
var r_bytes: array[8, byte]
|
||||
@ -78,7 +79,7 @@ proc exhaustiveCheck_p3mod4(C: static Curve, modulus: static int) =
|
||||
|
||||
check:
|
||||
bool not a.isSquare()
|
||||
bool not a.sqrt_if_square_p3mod4()
|
||||
bool not a.sqrt_if_square()
|
||||
bool (a == a2) # a shouldn't be modified
|
||||
|
||||
proc randomSqrtCheck_p3mod4(C: static Curve) =
|
||||
@ -97,15 +98,15 @@ proc randomSqrtCheck_p3mod4(C: static Curve) =
|
||||
bool a2.isSquare()
|
||||
|
||||
var r, s = a2
|
||||
r.sqrt_p3mod4()
|
||||
let ok = s.sqrt_if_square_p3mod4()
|
||||
r.sqrt()
|
||||
let ok = s.sqrt_if_square()
|
||||
check:
|
||||
bool ok
|
||||
bool(r == s)
|
||||
bool(r == a or r == na)
|
||||
|
||||
proc main() =
|
||||
suite "Modular square root":
|
||||
suite "Modular square root" & " [" & $WordBitwidth & "-bit mode]":
|
||||
exhaustiveCheck_p3mod4 Fake103, 103
|
||||
exhaustiveCheck_p3mod4 Fake10007, 10007
|
||||
exhaustiveCheck_p3mod4 Fake65519, 65519
|
||||
|
||||
@ -17,6 +17,8 @@ import
|
||||
../constantine/primitives,
|
||||
../constantine/config/curves
|
||||
|
||||
echo "\n------------------------------------------------------\n"
|
||||
|
||||
var RNG {.compileTime.} = initRand(1234)
|
||||
const CurveParams = [
|
||||
P224,
|
||||
|
||||
26
tests/test_fp12_bls12_377.nim
Normal file
26
tests/test_fp12_bls12_377.nim
Normal file
@ -0,0 +1,26 @@
|
||||
# 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/towers,
|
||||
../constantine/config/curves,
|
||||
# Test utilities
|
||||
./test_fp_tower_template
|
||||
|
||||
const TestCurves = [
|
||||
BLS12_377,
|
||||
]
|
||||
|
||||
runTowerTests(
|
||||
ExtDegree = 12,
|
||||
Iters = 128,
|
||||
TestCurves = TestCurves,
|
||||
moduleName = "test_fp12_" & $BLS12_377,
|
||||
testSuiteDesc = "𝔽p12 = 𝔽p6[w] " & $BLS12_377
|
||||
)
|
||||
26
tests/test_fp12_bls12_381.nim
Normal file
26
tests/test_fp12_bls12_381.nim
Normal file
@ -0,0 +1,26 @@
|
||||
# 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/towers,
|
||||
../constantine/config/curves,
|
||||
# Test utilities
|
||||
./test_fp_tower_template
|
||||
|
||||
const TestCurves = [
|
||||
BLS12_381
|
||||
]
|
||||
|
||||
runTowerTests(
|
||||
ExtDegree = 12,
|
||||
Iters = 128,
|
||||
TestCurves = TestCurves,
|
||||
moduleName = "test_fp12_" & $BLS12_381,
|
||||
testSuiteDesc = "𝔽p12 = 𝔽p6[w] " & $BLS12_381
|
||||
)
|
||||
@ -14,20 +14,13 @@ import
|
||||
./test_fp_tower_template
|
||||
|
||||
const TestCurves = [
|
||||
# BN254_Nogami
|
||||
BN254_Snarks,
|
||||
BLS12_377,
|
||||
BLS12_381,
|
||||
# BN446
|
||||
# FKM12_447
|
||||
# BLS12_461
|
||||
# BN462
|
||||
]
|
||||
|
||||
runTowerTests(
|
||||
ExtDegree = 12,
|
||||
Iters = 128,
|
||||
TestCurves = TestCurves,
|
||||
moduleName = "test_fp12",
|
||||
testSuiteDesc = "𝔽p12 = 𝔽p6[w] (irreducible polynomial w²-γ = 0) -> 𝔽p12 point (a, b) with coordinate a + bw and γ quadratic non-residue in 𝔽p6"
|
||||
moduleName = "test_fp12_" & $BN254_Snarks,
|
||||
testSuiteDesc = "𝔽p12 = 𝔽p6[w] " & $BN254_Snarks
|
||||
)
|
||||
56
tests/test_fp2_sqrt.nim
Normal file
56
tests/test_fp2_sqrt.nim
Normal file
@ -0,0 +1,56 @@
|
||||
# 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
|
||||
# Standard library
|
||||
std/[tables, unittest, times],
|
||||
# Internals
|
||||
../constantine/config/common,
|
||||
../constantine/[arithmetic, primitives],
|
||||
../constantine/towers,
|
||||
../constantine/config/curves,
|
||||
# Test utilities
|
||||
../helpers/prng_unsafe
|
||||
|
||||
const Iters = 128
|
||||
|
||||
var rng: RngState
|
||||
let seed = uint32(getTime().toUnix() and (1'i64 shl 32 - 1)) # unixTime mod 2^32
|
||||
rng.seed(seed)
|
||||
echo "\n------------------------------------------------------\n"
|
||||
echo "test_fp2_sqrt xoshiro512** seed: ", seed
|
||||
|
||||
proc randomSqrtCheck_p3mod4(C: static Curve) =
|
||||
test "[𝔽p2] Random square root check for p ≡ 3 (mod 4) on " & $Curve(C):
|
||||
for _ in 0 ..< Iters:
|
||||
let a = rng.random_unsafe(Fp2[C])
|
||||
var na{.noInit.}: Fp2[C]
|
||||
na.neg(a)
|
||||
|
||||
var a2 = a
|
||||
var na2 = na
|
||||
a2.square()
|
||||
na2.square()
|
||||
check:
|
||||
bool a2 == na2
|
||||
bool a2.isSquare()
|
||||
|
||||
var r, s = a2
|
||||
# r.sqrt()
|
||||
let ok = s.sqrt_if_square()
|
||||
check:
|
||||
bool ok
|
||||
# bool(r == s)
|
||||
bool(s == a or s == na)
|
||||
|
||||
proc main() =
|
||||
suite "Modular square root" & " [" & $WordBitwidth & "-bit mode]":
|
||||
randomSqrtCheck_p3mod4 BN254_Snarks
|
||||
randomSqrtCheck_p3mod4 BLS12_381
|
||||
|
||||
main()
|
||||
26
tests/test_fp6_bls12_377.nim
Normal file
26
tests/test_fp6_bls12_377.nim
Normal file
@ -0,0 +1,26 @@
|
||||
# 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/towers,
|
||||
../constantine/config/curves,
|
||||
# Test utilities
|
||||
./test_fp_tower_template
|
||||
|
||||
const TestCurves = [
|
||||
BLS12_377,
|
||||
]
|
||||
|
||||
runTowerTests(
|
||||
ExtDegree = 6,
|
||||
Iters = 128,
|
||||
TestCurves = TestCurves,
|
||||
moduleName = "test_fp6_" & $BLS12_377,
|
||||
testSuiteDesc = "𝔽p6 = 𝔽p2[v] " & $BLS12_377
|
||||
)
|
||||
26
tests/test_fp6_bls12_381.nim
Normal file
26
tests/test_fp6_bls12_381.nim
Normal file
@ -0,0 +1,26 @@
|
||||
# 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/towers,
|
||||
../constantine/config/curves,
|
||||
# Test utilities
|
||||
./test_fp_tower_template
|
||||
|
||||
const TestCurves = [
|
||||
BLS12_381
|
||||
]
|
||||
|
||||
runTowerTests(
|
||||
ExtDegree = 6,
|
||||
Iters = 128,
|
||||
TestCurves = TestCurves,
|
||||
moduleName = "test_fp6_" & $BLS12_381,
|
||||
testSuiteDesc = "𝔽p6 = 𝔽p2[v] " & $BLS12_381
|
||||
)
|
||||
@ -14,20 +14,13 @@ import
|
||||
./test_fp_tower_template
|
||||
|
||||
const TestCurves = [
|
||||
# BN254_Nogami
|
||||
BN254_Snarks,
|
||||
BLS12_377,
|
||||
BLS12_381,
|
||||
# BN446
|
||||
# FKM12_447
|
||||
# BLS12_461
|
||||
# BN462
|
||||
]
|
||||
|
||||
runTowerTests(
|
||||
ExtDegree = 6,
|
||||
Iters = 128,
|
||||
TestCurves = TestCurves,
|
||||
moduleName = "test_fp6",
|
||||
testSuiteDesc = "𝔽p6 = 𝔽p2[v] (irreducible polynomial v³-ξ = 0) -> 𝔽p6 point (a, b, c) with coordinate a + bv + cv² and ξ cubic non-residue in 𝔽p2"
|
||||
moduleName = "test_fp6_" & $BN254_Snarks,
|
||||
testSuiteDesc = "𝔽p6 = 𝔽p2[w] " & $BN254_Snarks
|
||||
)
|
||||
@ -23,6 +23,8 @@ import
|
||||
# Test utilities
|
||||
../helpers/[prng_unsafe, static_for]
|
||||
|
||||
echo "\n------------------------------------------------------\n"
|
||||
|
||||
template ExtField(degree: static int, curve: static Curve): untyped =
|
||||
when degree == 2:
|
||||
Fp2[curve]
|
||||
@ -47,7 +49,7 @@ proc runTowerTests*[N](
|
||||
rng.seed(seed)
|
||||
echo moduleName, " xoshiro512** seed: ", seed
|
||||
|
||||
suite testSuiteDesc:
|
||||
suite testSuiteDesc & " [" & $WordBitwidth & "-bit mode]":
|
||||
test "Comparison sanity checks":
|
||||
proc test(Field: typedesc) =
|
||||
var z, o {.noInit.}: Field
|
||||
|
||||
@ -16,12 +16,13 @@ import std/[unittest,times],
|
||||
var rng: RngState
|
||||
let seed = uint32(getTime().toUnix() and (1'i64 shl 32 - 1)) # unixTime mod 2^32
|
||||
rng.seed(seed)
|
||||
echo "\n------------------------------------------------------\n"
|
||||
echo "test_io_bigints xoshiro512** seed: ", seed
|
||||
|
||||
type T = BaseType
|
||||
|
||||
proc main() =
|
||||
suite "IO":
|
||||
suite "IO - BigInt" & " [" & $WordBitwidth & "-bit mode]":
|
||||
test "Parsing raw integers":
|
||||
block: # Sanity check
|
||||
let x = 0'u64
|
||||
|
||||
@ -17,10 +17,11 @@ import std/[unittest, times],
|
||||
var rng: RngState
|
||||
let seed = uint32(getTime().toUnix() and (1'i64 shl 32 - 1)) # unixTime mod 2^32
|
||||
rng.seed(seed)
|
||||
echo "\n------------------------------------------------------\n"
|
||||
echo "test_io_fields xoshiro512** seed: ", seed
|
||||
|
||||
proc main() =
|
||||
suite "IO - Finite fields":
|
||||
suite "IO - Finite fields" & " [" & $WordBitwidth & "-bit mode]":
|
||||
test "Parsing and serializing round-trip on uint64":
|
||||
# 101 ---------------------------------
|
||||
block:
|
||||
|
||||
@ -7,10 +7,13 @@
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import std/unittest,
|
||||
../constantine/config/common,
|
||||
../constantine/arithmetic,
|
||||
../constantine/config/curves,
|
||||
../constantine/io/[io_bigints, io_fields]
|
||||
|
||||
echo "\n------------------------------------------------------\n"
|
||||
|
||||
proc checkCubeRootOfUnity(curve: static Curve) =
|
||||
test $curve & " cube root of unity (mod p)":
|
||||
var cru = curve.getCubicRootOfUnity_mod_p()
|
||||
@ -30,7 +33,7 @@ proc checkCubeRootOfUnity(curve: static Curve) =
|
||||
check: bool r.isOne()
|
||||
|
||||
proc main() =
|
||||
suite "Sanity checks on precomputed values":
|
||||
suite "Sanity checks on precomputed values" & " [" & $WordBitwidth & "-bit mode]":
|
||||
checkCubeRootOfUnity(BN254_Snarks)
|
||||
# checkCubeRootOfUnity(BLS12_381)
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import std/[unittest, times, math],
|
||||
../constantine/config/common,
|
||||
../constantine/primitives,
|
||||
../helpers/prng_unsafe
|
||||
|
||||
@ -14,13 +15,14 @@ import std/[unittest, times, math],
|
||||
var rng: RngState
|
||||
let seed = uint32(getTime().toUnix() and (1'i64 shl 32 - 1)) # unixTime mod 2^32
|
||||
rng.seed(seed)
|
||||
echo "\n------------------------------------------------------\n"
|
||||
echo "test_primitives xoshiro512** seed: ", seed
|
||||
|
||||
template undistinct[T](x: Ct[T]): T =
|
||||
T(x)
|
||||
|
||||
proc main() =
|
||||
suite "Constant-time unsigned integers":
|
||||
suite "Constant-time unsigned integers" & " [" & $WordBitwidth & "-bit mode]":
|
||||
test "High - getting the biggest representable number":
|
||||
check:
|
||||
high(Ct[byte]).undistinct == 0xFF.byte
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user