Add more curves for testing: Curve25519, BLS12-377, BN446, FKM-447, BLS12-461, BN462

This commit is contained in:
Mamy André-Ratsimbazafy 2020-03-21 13:05:58 +01:00
parent 9e78cd5d6d
commit 1855d14497
No known key found for this signature in database
GPG Key ID: 7B88AD1FE79492E1
11 changed files with 297 additions and 90 deletions

View File

@ -35,6 +35,36 @@ The library focuses on following properties:
in this order
## Curves supported
At the moment the following curves are supported, adding a new curve only requires adding the prime modulus
and its bitsize in [constantine/config/curves.nim]().
The following curves are configured:
### ECDH / ECDSA curves
- NIST P-224
- Curve25519
- NIST P-256 / Secp256r1
- Secp256k1 (Bitcoin, Ethereum 1)
### Pairing-Friendly curves
Families:
- BN: Barreto-Naerig
- BLS: Barreto-Lynn-Scott
- FKM: Fotiadis-Konstantinou-Martindale
Curves:
- BN254 (Zero-Knowledge Proofs, Snarks, Starks, Zcash, Ethereum 1)
- BLS12-377 (Zexe)
- BLS12-381 (Algorand, Chia Networks, Dfinity, Ethereum 2, Filecoin, Zcash Sapling)
- BN446
- FKM12-447
- BLS12-461
- BN462
## Security
Hardening an implementation against all existing and upcoming attack vectors is an extremely complex task.
@ -82,6 +112,50 @@ The previous implementation was 15x slower and one of the key optimizations
was changing the elliptic curve cryptography backend.
It had a direct implication on hardware cost and/or cloud computing resources required.
## Measuring performance
To measure the performance of Constantine
```bash
git clone https://github.com/mratsim/constantine
nimble bench_fp_clang
nimble bench_fp2_clang
```
As mentioned in the [Compiler caveats](#compiler-caveats) section, GCC is up to 2x slower than Clang due to mishandling of carries and register usage.
On my machine, for selected benchmarks on the prime field for popular pairing-friendly curves.
```
⚠️ Measurements are approximate and use the CPU nominal clock: Turbo-Boost and overclocking will skew them.
==========================================================================================================
All benchmarks are using constant-time implementations to protect against side-channel attacks.
Compiled with Clang
Running on Intel(R) Core(TM) i9-9980XE CPU @ 3.00GHz (overclocked all-core Turbo @4.1GHz)
--------------------------------------------------------------------------------
Addition Fp[BN254] 0 ns 0 cycles
Substraction Fp[BN254] 0 ns 0 cycles
Negation Fp[BN254] 0 ns 0 cycles
Multiplication Fp[BN254] 21 ns 65 cycles
Squaring Fp[BN254] 18 ns 55 cycles
Inversion Fp[BN254] 6266 ns 18799 cycles
--------------------------------------------------------------------------------
Addition Fp[BLS12_381] 0 ns 0 cycles
Substraction Fp[BLS12_381] 0 ns 0 cycles
Negation Fp[BLS12_381] 0 ns 0 cycles
Multiplication Fp[BLS12_381] 45 ns 136 cycles
Squaring Fp[BLS12_381] 39 ns 118 cycles
Inversion Fp[BLS12_381] 15683 ns 47050 cycles
--------------------------------------------------------------------------------
Notes:
GCC is significantly slower than Clang on multiprecision arithmetic.
The simplest operations might be optimized away by the compiler.
```
### Compiler caveats
Unfortunately compilers and in particular GCC are not very good at optimizing big integers and/or cryptographic code even when using intrinsics like `addcarry_u64`.

View File

@ -27,9 +27,15 @@ const InvIters = 1000
const AvailableCurves = [
P224,
BN254,
Curve25519,
P256,
Secp256k1,
BLS12_381
BLS12_377,
BLS12_381,
BN446,
FKM12_447,
BLS12_461,
BN462
]
proc main() =

View File

@ -26,8 +26,14 @@ import
const Iters = 1_000_000
const InvIters = 1000
const AvailableCurves = [
# Pairing-Friendly curves
BN254,
BLS12_381
BLS12_377,
BLS12_381,
BN446,
FKM12_447,
BLS12_461,
BN462
]
proc main() =

View File

@ -26,8 +26,14 @@ import
const Iters = 1_000_000
const InvIters = 1000
const AvailableCurves = [
# Pairing-Friendly curves
BN254,
BLS12_381
BLS12_377,
BLS12_381,
BN446,
FKM12_447,
BLS12_461,
BN462
]
proc main() =

View File

@ -39,37 +39,23 @@ import
# - type Curve* = enum
# - proc Mod*(curve: static Curve): auto
# which returns the field modulus of the curve
when not defined(testingCurves):
declareCurves:
curve P224: # NIST P-224
bitsize: 224
modulus: "0xffffffff_ffffffff_ffffffff_ffffffff_00000000_00000000_00000001"
curve BN254:
bitsize: 254
modulus: "0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47"
# Equation: Y^2 = X^3 + 3
curve P256: # secp256r1 / NIST P-256
bitsize: 256
modulus: "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff"
curve Secp256k1: # Bitcoin curve
bitsize: 256
modulus: "0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F"
curve BLS12_381:
bitsize: 381
modulus: "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab"
# Equation: y^2 = x^3 + 4
else:
# Fake curve for testing field arithmetic
declareCurves:
declareCurves:
# -----------------------------------------------------------------------------
# Curves added when passed "-d:testingCurves"
curve Fake101:
testingCurve: true
bitsize: 7
modulus: "0x65" # 101 in hex
curve Mersenne61:
testingCurve: true
bitsize: 61
modulus: "0x1fffffffffffffff" # 2^61 - 1
curve Mersenne127:
testingCurve: true
bitsize: 127
modulus: "0x7fffffffffffffffffffffffffffffff" # 2^127 - 1
# -----------------------------------------------------------------------------
curve P224: # NIST P-224
bitsize: 224
modulus: "0xffffffff_ffffffff_ffffffff_ffffffff_00000000_00000000_00000001"
@ -77,16 +63,69 @@ else:
bitsize: 254
modulus: "0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47"
# Equation: Y^2 = X^3 + 3
curve Curve25519: # Bernstein curve
bitsize: 255
modulus: "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed"
curve P256: # secp256r1 / NIST P-256
bitsize: 256
modulus: "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff"
curve Secp256k1: # Bitcoin curve
bitsize: 256
modulus: "0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F"
curve BLS12_377:
# Zexe curve
# (p41) https://eprint.iacr.org/2018/962.pdf
# https://github.com/ethereum/EIPs/blob/41dea9615/EIPS/eip-2539.md
bitsize: 377
modulus: "0x01ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d44300000008508c00000000001"
curve BLS12_381:
bitsize: 381
modulus: "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab"
# Equation: y^2 = x^3 + 4
curve BN446:
bitsize: 446
modulus: "0x2400000000000000002400000002d00000000d800000021c0000001800000000870000000b0400000057c00000015c000000132000000067"
# u = 2^110 + 2^36 + 1
curve FKM12_447: # Fotiadis-Konstantinou-Martindale
bitsize: 447
modulus: "0x4ce300001338c00001c08180000f20cfffffe5a8bffffd08a000000f228000007e8ffffffaddfffffffdc00000009efffffffca000000007"
# TNFS Resistant Families of Pairing-Friendly Elliptic Curves
# Georgios Fotiadis and Elisavet Konstantinou, 2018
# https://eprint.iacr.org/2018/1017
#
# Family 17 choice b of
# Optimal TNFS-secure pairings on elliptic curves with composite embedding degree
# Georgios Fotiadis and Chloe Martindale, 2019
# https://eprint.iacr.org/2019/555
#
# A short-list of pairing-friendly curves resistant toSpecial TNFS at the 128-bit security level
# Aurore Guillevic
# https://hal.inria.fr/hal-02396352v2/document
#
# p(x) = 1728x^6 + 2160x^5 + 1548x^4 + 756x^3 + 240x^2 + 54x + 7
# t(x) = 6x² + 1, r(x) = 36x^4 + 36x^3 + 18x^2 + 6x + 1.
# Choice (b):u=2^72 2^71 2^36
#
# Note the paper mentions 446-bit but it's 447
curve BLS12_461:
# Updating Key Size Estimations for Pairings
# Barbulescu, R. and S. Duquesne, 2018
# https://hal.archives-ouvertes.fr/hal-01534101/file/main.pdf
bitsize: 461
modulus: "0x15555545554d5a555a55d69414935fbd6f1e32d8bacca47b14848b42a8dffa5c1cc00f26aa91557f00400020000555554aaaaaac0000aaaaaaab"
# u = 2^77 + 2^50 + 2^33
# p = (u - 1)^2 (u^4 - u^2 + 1)/3 + u
curve BN462:
# Pairing-Friendly Curves
# IETF Draft
# https://tools.ietf.org/id/draft-irtf-cfrg-pairing-friendly-curves-02.html
# Updating Key Size Estimations for Pairings
# Barbulescu, R. and S. Duquesne, 2018
# https://hal.archives-ouvertes.fr/hal-01534101/file/main.pdf
bitsize: 462
modulus: "0x240480360120023ffffffffff6ff0cf6b7d9bfca0000000000d812908f41c8020ffffffffff6ff66fc6ff687f640000000002401b00840138013"
# u = 2^114 + 2^101 2^14 1
# ############################################################
#
@ -253,6 +292,10 @@ macro genMontyMagics(T: typed): untyped =
genMontyMagics(Curve)
func getCurveBitSize*(C: static Curve): static int =
## Returns the number of bits taken by the curve modulus
result = static(CurveBitSize[C])
macro canUseNoCarryMontyMul*(C: static Curve): untyped =
## Returns true if the Modulus is compatible with a fast
## Montgomery multiplication that avoids many carries

View File

@ -71,16 +71,23 @@ macro declareCurves*(curves: untyped): untyped =
let curve = curveDesc[1]
let sizeSection = curveDesc[2][0]
var offset = 0
var testCurve = false
if curveDesc[2][0][0].eqident"testingCurve":
offset = 1
testCurve = curveDesc[2][0][1].boolVal
let sizeSection = curveDesc[2][offset]
doAssert sizeSection[0].eqIdent"bitsize"
sizeSection[1].expectKind(nnkStmtList)
let bitSize = sizeSection[1][0]
let modSection = curveDesc[2][1]
let modSection = curveDesc[2][offset+1]
doAssert modSection[0].eqIdent"modulus"
modSection[1].expectKind(nnkStmtList)
let modulus = modSection[1][0]
if not testCurve or defined(testingCurves):
Curves.add curve
# "BN254: 254" for array construction
CurveBitSize.add nnkExprColonExpr.newTree(

View File

@ -15,6 +15,10 @@
Ben Lynn, 2007\
https://crypto.stanford.edu/pbc/thesis.pdf
- An Analysis of Affine Coordinates for Pairing Computation\
Kristin Lauter, Peter L. Montgomery, and Michael Naehrig, 2010\
https://eprint.iacr.org/2010/363.pdf
- Pairings for beginners\
Craig Costello, 2012 (?)\
http://www.craigcostello.com.au/pairings/PairingsForBeginners.pdf
@ -30,11 +34,14 @@
https://scholarworks.rit.edu/cgi/viewcontent.cgi?referer=&httpsredir=1&article=10083&context=theses
https://github.com/rajeevakarv/FiniteFieldComputations
- A taxonomy of pairings, their security, their complexity\
Razvan Barbulescu, Nadia El Mrabet, and Loubna Ghammam, 2019\
https://hal.archives-ouvertes.fr/hal-02129868/file/2019-485.pdf
- A short-list of pairing-friendly curves resistantto Special TNFS at the 128-bit security level\
Aurore Guillevic\
https://eprint.iacr.org/2019/1371.pdf
### Presentations
- Introduction to pairings\

View File

@ -79,6 +79,10 @@ From Ben Edgington, https://hackmd.io/@benjaminion/bls12-381
Naomi Benger and Michael Scott, 2009\
https://eprint.iacr.org/2009/556
- Faster Squaring in the Cyclotomic Subgroup of Sixth Degree Extensions\
Robert Granger and Michael Scott, 2009\
https://eprint.iacr.org/2009/565.pdf
- High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves\
Jean-Luc Beuchat and Jorge Enrique González Díaz and Shigeo Mitsunari and Eiji Okamoto and Francisco Rodríguez-Henríquez and Tadanori Teruya, 2010\
https://eprint.iacr.org/2010/354

View File

@ -19,11 +19,17 @@ import
var RNG {.compileTime.} = initRand(1234)
const CurveParams = [
P224: (224, "0xffffffffffffffffffffffffffffffff000000000000000000000001"),
BN254: (254, "0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47"),
P256: (256, "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff"),
Secp256k1: (256, "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F"),
BLS12_381: (381, "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab")
P224,
BN254,
Curve25519,
P256,
Secp256k1,
BLS12_377,
BLS12_381,
BN446,
FKM12_447,
BLS12_461,
BN462
]
const AvailableCurves = [P224, BN254, P256, Secp256k1, BLS12_381]
@ -49,13 +55,13 @@ proc binary_prologue[C: static Curve, N: static int](
a, b, p: var mpz_t,
aTest, bTest: var Fp[C],
aBuf, bBuf: var array[N, byte]) =
const bits = CurveParams[C][0]
const bits = C.getCurveBitSize()
# Generate random value in the range 0 ..< 2^(bits-1)
mpz_urandomb(a, gmpRng, uint bits)
mpz_urandomb(b, gmpRng, uint bits)
# Set modulus to curve modulus
let err = mpz_set_str(p, CurveParams[C][1], 0)
let err = mpz_set_str(p, Curve(C).Mod.mres.toHex(), 0)
doAssert err == 0, "Error on prime for curve " & $Curve(C)
#########################################################
@ -116,7 +122,7 @@ proc addTests(gmpRng: var gmp_randstate_t, a, b, p, r: var mpz_t, C: static Curv
# echo "Testing: random modular addition on ", $C
const
bits = CurveParams[C][0]
bits = C.getCurveBitSize()
bufLen = (bits + 7) div 8
var
aTest, bTest{.noInit.}: Fp[C]
@ -139,7 +145,7 @@ proc subTests(gmpRng: var gmp_randstate_t, a, b, p, r: var mpz_t, C: static Curv
# echo "Testing: random modular substraction on ", $C
const
bits = CurveParams[C][0]
bits = C.getCurveBitSize()
bufLen = (bits + 7) div 8
var
aTest, bTest{.noInit.}: Fp[C]
@ -162,7 +168,7 @@ proc mulTests(gmpRng: var gmp_randstate_t, a, b, p, r: var mpz_t, C: static Curv
# echo "Testing: random modular multiplication on ", $C
const
bits = CurveParams[C][0]
bits = C.getCurveBitSize()
bufLen = (bits + 7) div 8
var
aTest, bTest{.noInit.}: Fp[C]
@ -182,7 +188,7 @@ proc invTests(gmpRng: var gmp_randstate_t, a, b, p, r: var mpz_t, C: static Curv
# echo "Testing: random modular inversion on ", $C
const
bits = CurveParams[C][0]
bits = C.getCurveBitSize()
bufLen = (bits + 7) div 8
var
aTest, bTest{.noInit.}: Fp[C]

View File

@ -76,9 +76,14 @@ suite "𝔽p2 = 𝔽p[𝑖] (irreducible polynomial x²+1)":
testInstance()
test(BN254)
test(BLS12_381)
test(P256)
test(Secp256k1)
test(BLS12_377)
test(BLS12_381)
test(BN446)
test(FKM12_447)
test(BLS12_461)
test(BN462)
test "Multiplication by 0 and 1":
template test(C: static Curve, body: untyped) =
@ -192,9 +197,14 @@ suite "𝔽p2 = 𝔽p[𝑖] (irreducible polynomial x²+1)":
bool(r0 == r4)
abelianGroup(BN254)
abelianGroup(BLS12_381)
abelianGroup(Secp256k1)
abelianGroup(P256)
abelianGroup(Secp256k1)
abelianGroup(BLS12_377)
abelianGroup(BLS12_381)
abelianGroup(BN446)
abelianGroup(FKM12_447)
abelianGroup(BLS12_461)
abelianGroup(BN462)
test "𝔽p2 = 𝔽p[𝑖] multiplication is associative and commutative":
proc commutativeRing(curve: static Curve) =
@ -239,9 +249,14 @@ suite "𝔽p2 = 𝔽p[𝑖] (irreducible polynomial x²+1)":
bool(r0 == r4)
commutativeRing(BN254)
commutativeRing(BLS12_381)
commutativeRing(Secp256k1)
commutativeRing(P256)
commutativeRing(Secp256k1)
commutativeRing(BLS12_377)
commutativeRing(BLS12_381)
commutativeRing(BN446)
commutativeRing(FKM12_447)
commutativeRing(BLS12_461)
commutativeRing(BN462)
test "𝔽p2 = 𝔽p[𝑖] extension field multiplicative inverse":
proc mulInvOne(curve: static Curve) =
@ -259,6 +274,11 @@ suite "𝔽p2 = 𝔽p[𝑖] (irreducible polynomial x²+1)":
check: bool(r == one)
mulInvOne(BN254)
mulInvOne(BLS12_381)
mulInvOne(Secp256k1)
mulInvOne(P256)
mulInvOne(Secp256k1)
mulInvOne(BLS12_377)
mulInvOne(BLS12_381)
mulInvOne(BN446)
mulInvOne(FKM12_447)
mulInvOne(BLS12_461)
mulInvOne(BN462)

View File

@ -51,7 +51,14 @@ suite "𝔽p6 = 𝔽p2[∛(1+𝑖)] (irreducible polynomial x³ - (1+𝑖))":
testInstance()
test(BN254)
test(P256)
test(Secp256k1)
test(BLS12_377)
test(BLS12_381)
test(BN446)
test(FKM12_447)
test(BLS12_461)
test(BN462)
test "Squaring 2 returns 4":
template test(C: static Curve) =
@ -76,7 +83,14 @@ suite "𝔽p6 = 𝔽p2[∛(1+𝑖)] (irreducible polynomial x³ - (1+𝑖))":
testInstance()
test(BN254)
test(P256)
test(Secp256k1)
test(BLS12_377)
test(BLS12_381)
test(BN446)
test(FKM12_447)
test(BLS12_461)
test(BN462)
test "Squaring 3 returns 9":
template test(C: static Curve) =
@ -103,7 +117,14 @@ suite "𝔽p6 = 𝔽p2[∛(1+𝑖)] (irreducible polynomial x³ - (1+𝑖))":
testInstance()
test(BN254)
test(P256)
test(Secp256k1)
test(BLS12_377)
test(BLS12_381)
test(BN446)
test(FKM12_447)
test(BLS12_461)
test(BN462)
test "Squaring -3 returns 9":
template test(C: static Curve) =
@ -130,4 +151,11 @@ suite "𝔽p6 = 𝔽p2[∛(1+𝑖)] (irreducible polynomial x³ - (1+𝑖))":
testInstance()
test(BN254)
test(P256)
test(Secp256k1)
test(BLS12_377)
test(BLS12_381)
test(BN446)
test(FKM12_447)
test(BLS12_461)
test(BN462)