Merge pull request #94 from mratsim/reorg-curves-constants

Reorg curves constants
This commit is contained in:
Mamy Ratsimbazafy 2020-09-27 22:31:13 +02:00 committed by GitHub
commit 51586c7272
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
69 changed files with 1840 additions and 1884 deletions

146
README.md
View File

@ -9,8 +9,20 @@
This library provides constant-time implementation of elliptic curve cryptography.
> Warning ⚠️: The library is in development state and cannot be used at the moment
> except as a showcase or to start a discussion on modular big integers internals.
The implementation is accompanied with SAGE code used as reference implementation and test vectors generators before high speed implementation.
> The library is in development state and high-level wrappers or example protocols are not available yet.
## Target audience
The library aims to be a portable, compact and hardened library for elliptic curve cryptography needs, in particular for blockchain protocols and zero-knowledge proofs system.
The library focuses on following properties:
- constant-time (not leaking secret data via side-channels)
- performance
- generated code size, datatype size and stack usage
in this order
## Installation
@ -31,17 +43,6 @@ This can be deactivated with `"-d:ConstantineASM=false"`:
- at misssed opportunity on recent CPUs that support MULX/ADCX/ADOX instructions (~60% faster than Clang).
- There is a 2.4x perf ratio between using plain GCC vs GCC with inline assembly.
## Target audience
The library aims to be a portable, compact and hardened library for elliptic curve cryptography needs, in particular for blockchain protocols and zero-knowledge proofs system.
The library focuses on following properties:
- constant-time (not leaking secret data via side-channels)
- performance
- generated code size, datatype size and stack usage
in this order
## Curves supported
At the moment the following curves are supported, adding a new curve only requires adding the prime modulus
@ -49,11 +50,9 @@ and its bitsize in [constantine/config/curves.nim](constantine/config/curves_dec
The following curves are configured:
> Note: At the moment, finite field arithmetic is fully supported
> but elliptic curve arithmetic is work-in-progress.
### ECDH / ECDSA curves
### ECDH / ECDSA / EdDSA curves
WIP:
- NIST P-224
- Curve25519
- NIST P-256 / Secp256r1
@ -61,20 +60,22 @@ The following curves are configured:
### Pairing-Friendly curves
Supports:
- [x] Field arithmetics
- [x] Curve arithmetic
- [x] Pairing
- [ ] Multi-Pairing
- [ ] Hash-To-Curve
Families:
- BN: Barreto-Naerig
- BN: Barreto-Naehrig
- BLS: Barreto-Lynn-Scott
- FKM: Fotiadis-Konstantinou-Martindale
Curves:
- BN254_Nogami
- BN254_Snarks (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
@ -141,73 +142,72 @@ 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
### Measuring performance
To measure the performance of Constantine
```bash
git clone https://github.com/mratsim/constantine
nimble bench_fp # Using Assembly (+ GCC)
nimble bench_fp_clang # Using Clang only
nimble bench_fp_gcc # Using Clang only (very slow)
nimble bench_fp # Using default compiler + Assembly
nimble bench_fp_clang # Using Clang + Assembly (recommended)
nimble bench_fp_gcc # Using GCC + Assembly (very slow)
nimble bench_fp_clang_noasm # Using Clang only
nimble bench_fp_gcc # Using GCC only (slowest)
nimble bench_fp2
# ...
nimble bench_ec_g1
nimble bench_ec_g2
nimble bench_pairing_bn254_nogami
nimble bench_pairing_bn254_snarks
nimble bench_pairing_bls12_377
nimble bench_pairing_bls12_381
```
"Unsafe" lines uses a non-constant-time algorithm.
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.
On my machine i9-9980XE, for selected benchmarks with Clang + Assembly
```
Compiled with GCC
Optimization level =>
no optimization: false
release: true
danger: true
inline assembly: true
Using Constantine with 64-bit limbs
Running on Intel(R) Core(TM) i9-9980XE CPU @ 3.00GHz
⚠️ Cycles measurements are approximate and use the CPU nominal clock: Turbo-Boost and overclocking will skew them.
i.e. a 20% overclock will be about 20% off (assuming no dynamic frequency scaling)
=================================================================================================================
-------------------------------------------------------------------------------------------------------------------------------------------------
Addition Fp[BN254_Snarks] 333333333.333 ops/s 3 ns/op 9 CPU cycles (approx)
Substraction Fp[BN254_Snarks] 500000000.000 ops/s 2 ns/op 8 CPU cycles (approx)
Negation Fp[BN254_Snarks] 1000000000.000 ops/s 1 ns/op 3 CPU cycles (approx)
Multiplication Fp[BN254_Snarks] 71428571.429 ops/s 14 ns/op 44 CPU cycles (approx)
Squaring Fp[BN254_Snarks] 71428571.429 ops/s 14 ns/op 44 CPU cycles (approx)
Inversion (constant-time Euclid) Fp[BN254_Snarks] 122579.063 ops/s 8158 ns/op 24474 CPU cycles (approx)
Inversion via exponentiation p-2 (Little Fermat) Fp[BN254_Snarks] 153822.489 ops/s 6501 ns/op 19504 CPU cycles (approx)
Square Root + square check (constant-time) Fp[BN254_Snarks] 153491.942 ops/s 6515 ns/op 19545 CPU cycles (approx)
Exp curve order (constant-time) - 254-bit Fp[BN254_Snarks] 104580.632 ops/s 9562 ns/op 28687 CPU cycles (approx)
Exp curve order (Leak exponent bits) - 254-bit Fp[BN254_Snarks] 153798.831 ops/s 6502 ns/op 19506 CPU cycles (approx)
-------------------------------------------------------------------------------------------------------------------------------------------------
Addition Fp[BLS12_381] 250000000.000 ops/s 4 ns/op 14 CPU cycles (approx)
Substraction Fp[BLS12_381] 250000000.000 ops/s 4 ns/op 13 CPU cycles (approx)
Negation Fp[BLS12_381] 1000000000.000 ops/s 1 ns/op 4 CPU cycles (approx)
Multiplication Fp[BLS12_381] 35714285.714 ops/s 28 ns/op 84 CPU cycles (approx)
Squaring Fp[BLS12_381] 35714285.714 ops/s 28 ns/op 85 CPU cycles (approx)
Inversion (constant-time Euclid) Fp[BLS12_381] 43763.676 ops/s 22850 ns/op 68552 CPU cycles (approx)
Inversion via exponentiation p-2 (Little Fermat) Fp[BLS12_381] 63983.620 ops/s 15629 ns/op 46889 CPU cycles (approx)
Square Root + square check (constant-time) Fp[BLS12_381] 63856.960 ops/s 15660 ns/op 46982 CPU cycles (approx)
Exp curve order (constant-time) - 255-bit Fp[BLS12_381] 68535.399 ops/s 14591 ns/op 43775 CPU cycles (approx)
Exp curve order (Leak exponent bits) - 255-bit Fp[BLS12_381] 93222.709 ops/s 10727 ns/op 32181 CPU cycles (approx)
-------------------------------------------------------------------------------------------------------------------------------------------------
Notes:
- Compilers:
Compilers are severely limited on multiprecision arithmetic.
Inline Assembly is used by default (nimble bench_fp).
Bench without assembly can use "nimble bench_fp_gcc" or "nimble bench_fp_clang".
GCC is significantly slower than Clang on multiprecision arithmetic due to catastrophic handling of carries.
- The simplest operations might be optimized away by the compiler.
- 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)
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Line double BLS12_381 649350.649 ops/s 1540 ns/op 4617 CPU cycles (approx)
Line add BLS12_381 482858.522 ops/s 2071 ns/op 6211 CPU cycles (approx)
Mul 𝔽p12 by line xy000z BLS12_381 543478.261 ops/s 1840 ns/op 5518 CPU cycles (approx)
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Final Exponentiation Easy BLS12_381 39411.973 ops/s 25373 ns/op 76119 CPU cycles (approx)
Final Exponentiation Hard BLS12 BLS12_381 2141.603 ops/s 466940 ns/op 1400833 CPU cycles (approx)
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Miller Loop BLS12 BLS12_381 2731.576 ops/s 366089 ns/op 1098278 CPU cycles (approx)
Final Exponentiation BLS12 BLS12_381 2033.045 ops/s 491873 ns/op 1475634 CPU cycles (approx)
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Pairing BLS12 BLS12_381 1131.391 ops/s 883868 ns/op 2651631 CPU cycles (approx)
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
```
```
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
EC Add G1 ECP_SWei_Proj[Fp[BLS12_381]] 2118644.068 ops/s 472 ns/op 1416 CPU cycles (approx)
EC Mixed Addition G1 ECP_SWei_Proj[Fp[BLS12_381]] 2439024.390 ops/s 410 ns/op 1232 CPU cycles (approx)
EC Double G1 ECP_SWei_Proj[Fp[BLS12_381]] 3448275.862 ops/s 290 ns/op 871 CPU cycles (approx)
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
EC ScalarMul G1 (unsafe reference DoubleAdd) ECP_SWei_Proj[Fp[BLS12_381]] 7147.094 ops/s 139917 ns/op 419756 CPU cycles (approx)
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
EC ScalarMul Generic G1 (window = 2, scratchsize = 4) ECP_SWei_Proj[Fp[BLS12_381]] 5048.975 ops/s 198060 ns/op 594188 CPU cycles (approx)
EC ScalarMul Generic G1 (window = 3, scratchsize = 8) ECP_SWei_Proj[Fp[BLS12_381]] 7148.269 ops/s 139894 ns/op 419685 CPU cycles (approx)
EC ScalarMul Generic G1 (window = 4, scratchsize = 16) ECP_SWei_Proj[Fp[BLS12_381]] 8112.735 ops/s 123263 ns/op 369791 CPU cycles (approx)
EC ScalarMul Generic G1 (window = 5, scratchsize = 32) ECP_SWei_Proj[Fp[BLS12_381]] 8464.534 ops/s 118140 ns/op 354424 CPU cycles (approx)
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
EC ScalarMul G1 (endomorphism accelerated) ECP_SWei_Proj[Fp[BLS12_381]] 9679.418 ops/s 103312 ns/op 309939 CPU cycles (approx)
EC ScalarMul Window-2 G1 (endomorphism accelerated) ECP_SWei_Proj[Fp[BLS12_381]] 13089.348 ops/s 76398 ns/op 229195 CPU cycles (approx)
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
```
### 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

@ -37,10 +37,6 @@ const AvailableCurves = [
# Secp256k1,
BLS12_377,
BLS12_381,
# BN446,
# FKM12_447,
# BLS12_461,
# BN462
]
proc main() =

View File

@ -38,10 +38,6 @@ const AvailableCurves = [
# Secp256k1,
BLS12_377,
BLS12_381,
# BN446,
# FKM12_447,
# BLS12_461,
# BN462
]
proc main() =

View File

@ -35,10 +35,6 @@ const AvailableCurves = [
# Secp256k1,
BLS12_377,
BLS12_381,
# BN446,
# FKM12_447,
# BLS12_461,
# BN462
]
proc main() =

View File

@ -31,10 +31,6 @@ const AvailableCurves = [
BN254_Snarks,
BLS12_377,
BLS12_381
# BN446,
# FKM12_447,
# BLS12_461,
# BN462
]
proc main() =

View File

@ -31,10 +31,6 @@ const AvailableCurves = [
BN254_Snarks,
BLS12_377,
BLS12_381
# BN446,
# FKM12_447,
# BLS12_461,
# BN462
]
proc main() =

View File

@ -30,11 +30,7 @@ const AvailableCurves = [
BN254_Nogami,
BN254_Snarks,
BLS12_377,
BLS12_381
# BN446,
# FKM12_447,
# BLS12_461,
# BN462
BLS12_381,
]
proc main() =

View File

@ -33,8 +33,7 @@ const testDesc: seq[tuple[path: string, useGMP: bool]] = @[
("tests/t_finite_fields_sqrt.nim", false),
("tests/t_finite_fields_powinv.nim", false),
("tests/t_finite_fields_vs_gmp.nim", true),
# Precompute
("tests/t_precomputed", false),
("tests/t_fp_cubic_root.nim", false),
# Double-width finite fields
("tests/t_finite_fields_double_width.nim", false),
# Towers of extension fields

View File

@ -10,8 +10,8 @@ import
# Standard library
std/macros,
# Internal
../config/common,
../primitives
../../config/common,
../../primitives
# ############################################################
#

View File

@ -10,9 +10,9 @@ import
# Standard library
std/macros,
# Internal
../config/common,
../primitives,
./limbs
../../config/common,
../../primitives,
../limbs
# ############################################################
#

View File

@ -10,9 +10,9 @@ import
# Standard library
std/macros,
# Internal
../config/common,
../primitives,
./limbs,
../../config/common,
../../primitives,
../limbs,
./limbs_asm_montred_x86
# ############################################################

View File

@ -10,9 +10,9 @@ import
# Standard library
std/macros,
# Internal
../config/common,
../primitives,
./limbs,
../../config/common,
../../primitives,
../limbs,
./limbs_asm_montred_x86
# ############################################################

View File

@ -10,9 +10,9 @@ import
# Standard library
std/macros,
# Internal
../config/common,
../primitives,
./limbs
../../config/common,
../../primitives,
../limbs
# ############################################################
#

View File

@ -10,9 +10,9 @@ import
# Standard library
std/macros,
# Internal
../config/common,
../primitives,
./limbs,
../../config/common,
../../primitives,
../limbs,
./limbs_asm_montred_x86
# ############################################################

View File

@ -10,8 +10,8 @@ import
# Standard library
std/macros,
# Internal
../config/common,
../primitives
../../config/common,
../../primitives
# ############################################################
#

View File

@ -10,8 +10,8 @@ import
# Standard library
std/macros,
# Internal
../config/common,
../primitives
../../config/common,
../../primitives
# ############################################################
#

View File

@ -10,8 +10,8 @@ import
# Standard library
std/macros,
# Internal
../config/common,
../primitives
../../config/common,
../../primitives
# ############################################################
#

View File

@ -10,7 +10,7 @@ import
../config/[common, type_bigint],
../primitives,
./limbs,
./limbs_generic_modular,
./limbs_modular,
./limbs_montgomery
export BigInt

View File

@ -31,7 +31,7 @@ import
./bigints, ./limbs_montgomery
when UseASM_X86_64:
import ./limbs_asm_modular_x86
import ./assembly/limbs_asm_modular_x86
when nimvm:
from ../config/precompute import montyResidue_precompute
@ -340,10 +340,15 @@ func `*=`*(a: var Fp, b: Fp) {.inline.} =
## Multiplication modulo p
a.prod(a, b)
func square*(a: var Fp) {.inline.}=
func square*(a: var Fp) {.inline.} =
## Squaring modulo p
a.mres.montySquare(a.mres, Fp.C.Mod, Fp.C.getNegInvModWord(), Fp.C.canUseNoCarryMontySquare())
func square_repeated*(r: var Fp, num: int) {.inline.} =
## Repeated squarings
for _ in 0 ..< num:
r.square()
func `*=`*(a: var Fp, b: static int) {.inline.} =
## Multiplication by a small integer known at compile-time
# Implementation:

View File

@ -15,7 +15,7 @@ import
./limbs_double_width
when UseASM_X86_64:
import limbs_asm_modular_dbl_width_x86
import assembly/limbs_asm_modular_dbl_width_x86
type FpDbl*[C: static Curve] = object
## Double-width Fp element

View File

@ -7,506 +7,25 @@
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import
../config/[common, curves],
../config/[common, curves, type_fp],
./bigints,
./finite_fields
../curves/zoo_inversions
export zoo_inversions
# ############################################################
#
# Specialized inversions
# Finite field inversion
#
# ############################################################
# Field-specific inversion routines
func square_repeated(r: var Fp, num: int) =
## Repeated squarings
for _ in 0 ..< num:
r.square()
# Secp256k1
# ------------------------------------------------------------
func inv_addchain(r: var Fp[Secp256k1], a: Fp[Secp256k1]) {.used.}=
## We invert via Little Fermat's theorem
## a^(-1) ≡ a^(p-2) (mod p)
## with p = "0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F"
## We take advantage of the prime special form to hardcode
## the sequence of squarings and multiplications for the modular exponentiation
##
## See libsecp256k1
##
## The binary representation of (p - 2) has 5 blocks of 1s, with lengths in
## { 1, 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block:
## [1], [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223]
var
x2{.noInit.}: Fp[Secp256k1]
x3{.noInit.}: Fp[Secp256k1]
x6{.noInit.}: Fp[Secp256k1]
x9{.noInit.}: Fp[Secp256k1]
x11{.noInit.}: Fp[Secp256k1]
x22{.noInit.}: Fp[Secp256k1]
x44{.noInit.}: Fp[Secp256k1]
x88{.noInit.}: Fp[Secp256k1]
x176{.noInit.}: Fp[Secp256k1]
x220{.noInit.}: Fp[Secp256k1]
x223{.noInit.}: Fp[Secp256k1]
x2.square(a)
x2 *= a
x3.square(x2)
x3 *= a
x6 = x3
x6.square_repeated(3)
x6 *= x3
x9 = x6
x9.square_repeated(3)
x9 *= x3
x11 = x9
x11.square_repeated(2)
x11 *= x2
x22 = x11
x22.square_repeated(11)
x22 *= x11
x44 = x22
x44.square_repeated(22)
x44 *= x22
x88 = x44
x88.square_repeated(44)
x88 *= x44
x176 = x88
x88.square_repeated(88)
x176 *= x88
x220 = x176
x220.square_repeated(44)
x220 *= x44
x223 = x220
x223.square_repeated(3)
x223 *= x3
# The final result is then assembled using a sliding window over the blocks
r = x223
r.square_repeated(23)
r *= x22
r.square_repeated(5)
r *= a
r.square_repeated(3)
r *= x2
r.square_repeated(2)
r *= a
# BLS12-381
# ------------------------------------------------------------
func inv_addchain*(r: var Fp[BLS12_381], a: Fp[BLS12_381]) =
var
x10 {.noinit.}: Fp[BLS12_381]
x100 {.noinit.}: Fp[BLS12_381]
x1000 {.noinit.}: Fp[BLS12_381]
x1001 {.noinit.}: Fp[BLS12_381]
x1011 {.noinit.}: Fp[BLS12_381]
x1101 {.noinit.}: Fp[BLS12_381]
x10001 {.noinit.}: Fp[BLS12_381]
x10100 {.noinit.}: Fp[BLS12_381]
x11001 {.noinit.}: Fp[BLS12_381]
x11010 {.noinit.}: Fp[BLS12_381]
x110100 {.noinit.}: Fp[BLS12_381]
x110110 {.noinit.}: Fp[BLS12_381]
x110111 {.noinit.}: Fp[BLS12_381]
x1001101 {.noinit.}: Fp[BLS12_381]
x1001111 {.noinit.}: Fp[BLS12_381]
x1010101 {.noinit.}: Fp[BLS12_381]
x1011101 {.noinit.}: Fp[BLS12_381]
x1100111 {.noinit.}: Fp[BLS12_381]
x1101001 {.noinit.}: Fp[BLS12_381]
x1110111 {.noinit.}: Fp[BLS12_381]
x1111011 {.noinit.}: Fp[BLS12_381]
x10001001 {.noinit.}: Fp[BLS12_381]
x10010101 {.noinit.}: Fp[BLS12_381]
x10010111 {.noinit.}: Fp[BLS12_381]
x10101001 {.noinit.}: Fp[BLS12_381]
x10110001 {.noinit.}: Fp[BLS12_381]
x10111111 {.noinit.}: Fp[BLS12_381]
x11000011 {.noinit.}: Fp[BLS12_381]
x11010000 {.noinit.}: Fp[BLS12_381]
x11010111 {.noinit.}: Fp[BLS12_381]
x11100001 {.noinit.}: Fp[BLS12_381]
x11100101 {.noinit.}: Fp[BLS12_381]
x11101011 {.noinit.}: Fp[BLS12_381]
x11110101 {.noinit.}: Fp[BLS12_381]
x11111111 {.noinit.}: Fp[BLS12_381]
x10 .square(a)
x100 .square(x10)
x1000 .square(x100)
x1001 .prod(a, x1000)
x1011 .prod(x10, x1001)
x1101 .prod(x10, x1011)
x10001 .prod(x100, x1101)
x10100 .prod(x1001, x1011)
x11001 .prod(x1000, x10001)
x11010 .prod(a, x11001)
x110100 .square(x11010)
x110110 .prod(x10, x110100)
x110111 .prod(a, x110110)
x1001101 .prod(x11001, x110100)
x1001111 .prod(x10, x1001101)
x1010101 .prod(x1000, x1001101)
x1011101 .prod(x1000, x1010101)
x1100111 .prod(x11010, x1001101)
x1101001 .prod(x10, x1100111)
x1110111 .prod(x11010, x1011101)
x1111011 .prod(x100, x1110111)
x10001001 .prod(x110100, x1010101)
x10010101 .prod(x11010, x1111011)
x10010111 .prod(x10, x10010101)
x10101001 .prod(x10100, x10010101)
x10110001 .prod(x1000, x10101001)
x10111111 .prod(x110110, x10001001)
x11000011 .prod(x100, x10111111)
x11010000 .prod(x1101, x11000011)
x11010111 .prod(x10100, x11000011)
x11100001 .prod(x10001, x11010000)
x11100101 .prod(x100, x11100001)
x11101011 .prod(x10100, x11010111)
x11110101 .prod(x10100, x11100001)
x11111111 .prod(x10100, x11101011) # 35 operations
# TODO: we can accumulate in a partially reduced
# doubled-size `r` to avoid the final substractions.
# and only reduce at the end.
# This requires the number of op to be less than log2(p) == 381
# 35 + 22 = 57 operations
r.prod(x10111111, x11100001)
r.square_repeated(8)
r *= x10001
r.square_repeated(11)
r *= x11110101
# 57 + 28 = 85 operations
r.square_repeated(11)
r *= x11100101
r.square_repeated(8)
r *= x11111111
r.square_repeated(7)
# 88 + 22 = 107 operations
r *= x1001101
r.square_repeated(9)
r *= x1101001
r.square_repeated(10)
r *= x10110001
# 107+24 = 131 operations
r.square_repeated(7)
r *= x1011101
r.square_repeated(9)
r *= x1111011
r.square_repeated(6)
# 131+23 = 154 operations
r *= x11001
r.square_repeated(11)
r *= x1101001
r.square_repeated(9)
r *= x11101011
# 154+28 = 182 operations
r.square_repeated(10)
r *= x11010111
r.square_repeated(6)
r *= x11001
r.square_repeated(10)
# 182+23 = 205 operations
r *= x1110111
r.square_repeated(9)
r *= x10010111
r.square_repeated(11)
r *= x1001111
# 205+30 = 235 operations
r.square_repeated(10)
r *= x11100001
r.square_repeated(9)
r *= x10001001
r.square_repeated(9)
# 235+21 = 256 operations
r *= x10111111
r.square_repeated(8)
r *= x1100111
r.square_repeated(10)
r *= x11000011
# 256+28 = 284 operations
r.square_repeated(9)
r *= x10010101
r.square_repeated(12)
r *= x1111011
r.square_repeated(5)
# 284 + 21 = 305 operations
r *= x1011
r.square_repeated(11)
r *= x1111011
r.square_repeated(7)
r *= x1001
# 305+32 = 337 operations
r.square_repeated(13)
r *= x11110101
r.square_repeated(9)
r *= x10111111
r.square_repeated(8)
# 337+22 = 359 operations
r *= x11111111
r.square_repeated(8)
r *= x11101011
r.square_repeated(11)
r *= x10101001
# 359+24 = 383 operations
r.square_repeated(8)
r *= x11111111
r.square_repeated(8)
r *= x11111111
r.square_repeated(6)
# 383+22 = 405 operations
r *= x110111
r.square_repeated(10)
r *= x11111111
r.square_repeated(9)
r *= x11111111
# 405+26 = 431 operations
r.square_repeated(8)
r *= x11111111
r.square_repeated(8)
r *= x11111111
r.square_repeated(8)
# 431+19 = 450 operations
r *= x11111111
r.square_repeated(7)
r *= x1010101
r.square_repeated(9)
r *= x10101001
# Total 450 operations:
# - 74 multiplications
# - 376 squarings
# BN Curves
# ------------------------------------------------------------
# Efficient Pairings and ECC for Embedded Systems
# Thomas Unterluggauer and Erich Wenger
# https://eprint.iacr.org/2014/800.pdf
#
# BN curve field modulus are of the form:
# p = 36u^4 + 36u^3 + 24u^2 + 6u + 1
#
# We construct the following multiplication-squaring chain
# a^-1 mod p = a^(p-2) mod p (Little Fermat Theorem)
# = a^(36 u^4 + 36 u^3 + 24 u^2 + 6u + 1 - 2) mod p
# = a^(36 u^4) . a^(36 u^3) . a^(24 u^2) . a^(6u-1) mod p
#
# Note: it only works for u positive, in particular BN254_Nogami doesn't work :/
# Is there a way to only use a^-u or even powers?
func inv_addchain_bn[C](r: var Fp[C], a: Fp[C]) {.used.}=
## Inversion on BN prime fields with positive base parameter `u`
## via Little Fermat theorem and leveraging the prime low Hamming weight
##
## Requires a `bn` curve with a positive parameter `u`
# TODO: debug for input "0x0d2007d8aaface1b8501bfbe792974166e8f9ad6106e5b563604f0aea9ab06f6"
# on BN254_Snarks see test suite (but works in Sage so aliasing issue?)
#
# For BN254_Snarks `u` and `6u-1` exponentiation are not fast enough
# (even with dedicated addchains)
# compared to an addchain on the full prime modulus
static: doAssert C.canUse_BN_AddchainInversion()
var v0 {.noInit.}, v1 {.noInit.}: Fp[C]
v0 = a
v0.powUnsafeExponent(C.getBN_param_6u_minus_1_BE()) # v0 <- a^(6u-1)
v1.prod(v0, a) # v1 <- a^(6u)
v1.powUnsafeExponent(C.getBN_param_u_BE()) # v1 <- a^(6u²)
r.square(v1) # r <- a^(12u²)
v1.square(r) # v1 <- a^(24u²)
v0 *= v1 # v0 <- a^(24u²) a^(6u-1)
v1 *= r # v1 <- a^(24u²) a^(12u²) = a^(36u²)
v1.powUnsafeExponent(C.getBN_param_u_BE()) # v1 <- a^(36u³)
r.prod(v0, v1) # r <- a^(36u³) a^(24u²) a^(6u-1)
v1.powUnsafeExponent(C.getBN_param_u_BE()) # v1 <- a^(36u⁴)
r *= v1 # r <- a^(36u⁴) a^(36u³) a^(24u²) a^(6u-1) = a^(p-2) = a^(-1)
func inv_addchain*(r: var Fp[BN254_Snarks], a: Fp[BN254_Snarks]) =
var
x10 {.noInit.}: Fp[BN254_Snarks]
x11 {.noInit.}: Fp[BN254_Snarks]
x101 {.noInit.}: Fp[BN254_Snarks]
x110 {.noInit.}: Fp[BN254_Snarks]
x1000 {.noInit.}: Fp[BN254_Snarks]
x1101 {.noInit.}: Fp[BN254_Snarks]
x10010 {.noInit.}: Fp[BN254_Snarks]
x10011 {.noInit.}: Fp[BN254_Snarks]
x10100 {.noInit.}: Fp[BN254_Snarks]
x10111 {.noInit.}: Fp[BN254_Snarks]
x11100 {.noInit.}: Fp[BN254_Snarks]
x100000 {.noInit.}: Fp[BN254_Snarks]
x100011 {.noInit.}: Fp[BN254_Snarks]
x101011 {.noInit.}: Fp[BN254_Snarks]
x101111 {.noInit.}: Fp[BN254_Snarks]
x1000001 {.noInit.}: Fp[BN254_Snarks]
x1010011 {.noInit.}: Fp[BN254_Snarks]
x1011011 {.noInit.}: Fp[BN254_Snarks]
x1100001 {.noInit.}: Fp[BN254_Snarks]
x1110101 {.noInit.}: Fp[BN254_Snarks]
x10010001 {.noInit.}: Fp[BN254_Snarks]
x10010101 {.noInit.}: Fp[BN254_Snarks]
x10110101 {.noInit.}: Fp[BN254_Snarks]
x10111011 {.noInit.}: Fp[BN254_Snarks]
x11000001 {.noInit.}: Fp[BN254_Snarks]
x11000011 {.noInit.}: Fp[BN254_Snarks]
x11010011 {.noInit.}: Fp[BN254_Snarks]
x11100001 {.noInit.}: Fp[BN254_Snarks]
x11100011 {.noInit.}: Fp[BN254_Snarks]
x11100111 {.noInit.}: Fp[BN254_Snarks]
x10 .square(a)
x11 .prod(x10, a)
x101 .prod(x10, x11)
x110 .prod(x101, a)
x1000 .prod(x10, x110)
x1101 .prod(x101, x1000)
x10010 .prod(x101, x1101)
x10011 .prod(x10010, a)
x10100 .prod(x10011, a)
x10111 .prod(x11, x10100)
x11100 .prod(x101, x10111)
x100000 .prod(x1101, x10011)
x100011 .prod(x11, x100000)
x101011 .prod(x1000, x100011)
x101111 .prod(x10011, x11100)
x1000001 .prod(x10010, x101111)
x1010011 .prod(x10010, x1000001)
x1011011 .prod(x1000, x1010011)
x1100001 .prod(x110, x1011011)
x1110101 .prod(x10100, x1100001)
x10010001 .prod(x11100, x1110101)
x10010101 .prod(x100000, x1110101)
x10110101 .prod(x100000, x10010101)
x10111011 .prod(x110, x10110101)
x11000001 .prod(x110, x10111011)
x11000011 .prod(x10, x11000001)
x11010011 .prod(x10010, x11000001)
x11100001 .prod(x100000, x11000001)
x11100011 .prod(x10, x11100001)
x11100111 .prod(x110, x11100001) # 30 operations
# 30 + 27 = 57 operations
r.square(x11000001)
r.square_repeated(7)
r *= x10010001
r.square_repeated(10)
r *= x11100111
r.square_repeated(7)
# 57 + 19 = 76 operations
r *= x10111
r.square_repeated(9)
r *= x10011
r.square_repeated(7)
r *= x1101
# 76 + 33 = 109 operations
r.square_repeated(14)
r *= x1010011
r.square_repeated(9)
r *= x11100001
r.square_repeated(8)
# 109 + 18 = 127 operations
r *= x1000001
r.square_repeated(10)
r *= x1011011
r.square_repeated(5)
r *= x1101
# 127 + 34 = 161 operations
r.square_repeated(8)
r *= x11
r.square_repeated(12)
r *= x101011
r.square_repeated(12)
# 161 + 25 = 186 operations
r *= x10111011
r.square_repeated(8)
r *= x101111
r.square_repeated(14)
r *= x10110101
# 186 + 28 = 214
r.square_repeated(9)
r *= x10010001
r.square_repeated(5)
r *= x1101
r.square_repeated(12)
# 214 + 22 = 236
r *= x11100011
r.square_repeated(8)
r *= x10010101
r.square_repeated(11)
r *= x11010011
# 236 + 32 = 268
r.square_repeated(7)
r *= x1100001
r.square_repeated(11)
r *= x100011
r.square_repeated(12)
# 268 + 20 = 288
r *= x1011011
r.square_repeated(9)
r *= x11000011
r.square_repeated(8)
r *= x11100111
# 288 + 15 = 303
r.square_repeated(7)
r *= x1110101
r.square_repeated(6)
r *= x101
# ############################################################
#
# Dispatch
#
# ############################################################
func inv_euclid*(r: var Fp, a: Fp) =
func inv_euclid*(r: var Fp, a: Fp) {.inline.} =
## Inversion modulo p via
## Niels Moller constant-time version of
## Stein's GCD derived from extended binary Euclid algorithm
r.mres.steinsGCD(a.mres, Fp.C.getR2modP(), Fp.C.Mod, Fp.C.getPrimePlus1div2())
func inv*(r: var Fp, a: Fp) =
func inv*(r: var Fp, a: Fp) {.inline.} =
## Inversion modulo p
##
## The inverse of 0 is 0.
@ -522,7 +41,7 @@ func inv*(r: var Fp, a: Fp) =
else:
r.inv_euclid(a)
func inv*(a: var Fp) =
func inv*(a: var Fp) {.inline.} =
## Inversion modulo p
##
## The inverse of 0 is 0.

View File

@ -7,9 +7,9 @@
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import
std/macros,
../primitives,
../config/[common, type_fp, curves],
../curves/zoo_square_roots,
../io/[io_bigints, io_fields],
./bigints, ./finite_fields, ./limbs_montgomery
@ -112,25 +112,11 @@ func sqrt_if_square_p3mod4[C](a: var Fp[C]): SecretBool {.inline.} =
# Tonelli Shanks for any prime
# ------------------------------------------------------------
const
# with e = 2adicity
# p == s * 2^e + 1
# root_of_unity = smallest_quadratic_nonresidue^s
# exponent = (p-1-2^e)/2^e / 2
TonelliShanks_exponent_BLS12_377 = BigInt[330].fromHex"0x35c748c2f8a21d58c760b80d94292763445b3e601ea271e3de6c45f741290002e16ba88600000010a11"
TonelliShanks_twoAdicity_BLS12_377 = 46
TonelliShanks_root_of_unity_BLS12_377 = Fp[BLS12_377].fromHex"0x382d3d99cdbc5d8fe9dee6aa914b0ad14fcaca7022110ec6eaa2bc56228ac41ea03d28cc795186ba6b5ef26b00bbe8"
{.experimental: "dynamicBindSym".}
macro tsGet(C: static Curve, value: untyped): untyped =
return bindSym("TonelliShanks_" & $value & "_" & $C)
func precompute_tonelli_shanks[C](
a_pre_exp: var Fp[C],
a: Fp[C]) =
a_pre_exp = a
a_pre_exp.powUnsafeExponent(C.tsGet(exponent))
a_pre_exp.powUnsafeExponent(C.tonelliShanks(exponent))
func isSquare_tonelli_shanks[C](
a, a_pre_exp: Fp[C]): SecretBool =
@ -139,7 +125,7 @@ func isSquare_tonelli_shanks[C](
## Tonelli-Shanks based square root and inverse square root
##
## a^((p-1-2^e)/(2*2^e))
const e = C.tsGet(twoAdicity)
const e = C.tonelliShanks(twoAdicity)
var r {.noInit.}: Fp[C]
r.square(a_pre_exp) # a^(2(q-1-2^e)/(2*2^e)) = a^((q-1)/2^e - 1)
r *= a # a^((q-1)/2^e)
@ -169,13 +155,13 @@ func sqrt_invsqrt_tonelli_shanks[C](
template z: untyped = a_pre_exp
template r: untyped = invsqrt
var t {.noInit.}: Fp[C]
const e = C.tsGet(twoAdicity)
const e = C.tonelliShanks(twoAdicity)
t.square(z)
t *= a
r = z
var b = t
var root = C.tsGet(root_of_unity)
var root = C.tonelliShanks(root_of_unity)
var buf {.noInit.}: Fp[C]

View File

@ -11,10 +11,10 @@ import
../primitives
when UseASM_X86_32:
import ./limbs_asm_x86
import ./assembly/limbs_asm_x86
when UseASM_X86_64:
import ./limbs_asm_mul_x86
import ./limbs_asm_mul_x86_adx_bmi2
import ./assembly/limbs_asm_mul_x86
import ./assembly/limbs_asm_mul_x86_adx_bmi2
# ############################################################
#

View File

@ -12,9 +12,9 @@ import
./limbs
when UseASM_X86_32:
import ./limbs_asm_montred_x86
import ./assembly/limbs_asm_montred_x86
when UseASM_X86_64:
import ./limbs_asm_montred_x86_adx_bmi2
import ./assembly/limbs_asm_montred_x86_adx_bmi2
# ############################################################
#

View File

@ -16,8 +16,8 @@ import
when UseASM_X86_64:
import
./limbs_asm_montmul_x86,
./limbs_asm_montmul_x86_adx_bmi2
./assembly/limbs_asm_montmul_x86,
./assembly/limbs_asm_montmul_x86_adx_bmi2
# ############################################################
#

View File

@ -158,33 +158,6 @@ macro getPrimePlus1div4_BE*(C: static Curve): untyped =
## Get (P+1) / 4 for an odd prime in big-endian serialized format
result = bindSym($C & "_PrimePlus1div4_BE")
# Family specific
# -------------------------------------------------------
macro canUse_BN_AddchainInversion*(C: static Curve): untyped =
## A BN curve can use the fast BN inversion if the parameter "u" is positive
if CurveFamilies[C] != BarretoNaehrig:
return newLit false
return bindSym($C & "_BN_can_use_addchain_inversion")
macro getBN_param_u_BE*(C: static Curve): untyped =
## Get the ``u`` parameter of a BN curve in canonical big-endian representation
result = bindSym($C & "_BN_u_BE")
macro getBN_param_6u_minus_1_BE*(C: static Curve): untyped =
## Get the ``6u-1`` from the ``u`` parameter
## of a BN curve in canonical big-endian representation
result = bindSym($C & "_BN_6u_minus_1_BE")
# Endomorphism
# -------------------------------------------------------
macro getCubicRootOfUnity_mod_p*(C: static Curve): untyped =
## Get a non-trivial cubic root of unity (mod p) with p the prime field
result = bindSym($C & "_cubicRootOfUnity_mod_p")
macro getCubicRootOfUnity_mod_r*(C: static Curve): untyped =
## Get a non-trivial cubic root of unity (mod r) with r the curve order
result = bindSym($C & "_cubicRootOfUnity_mod_r")
# ############################################################
#
# Debug info printed at compile-time
@ -202,15 +175,12 @@ macro debugConsts(): untyped {.used.} =
let modulus = bindSym(curveName & "_Modulus")
let r2modp = bindSym(curveName & "_R2modP")
let negInvModWord = bindSym(curveName & "_NegInvModWord")
let cubeRootOfUnity = ident(curveName & "_cubicRootOfUnity")
result.add quote do:
echo "Curve ", `curveName`,':'
echo " Field Modulus: ", `modulus`
echo " Montgomery R² (mod P): ", `r2modp`
echo " Montgomery -1/P[0] (mod 2^", WordBitWidth, "): ", `negInvModWord`
when declared(`cubeRootOfUnity`):
echo " Cube root of unity: ", `cubeRootOfUnity`
result.add quote do:
echo "----------------------------------------------------------------------------"

View File

@ -38,15 +38,6 @@ export CurveFamily
# which returns the field modulus of the curve
# - proc Family*(curve: static Curve): CurveFamily
# which returns the curve family
# - proc get_BN_param_u_BE*(curve: static Curve): array[N, byte]
# which returns the "u" parameter of a BN curve
# as a big-endian canonical integer representation
# if it's a BN curve and u is positive
# - proc get_BN_param_6u_minus1_BE*(curve: static Curve): array[N, byte]
# which returns the "6u-1" parameter of a BN curve
# as a big-endian canonical integer representation
# if it's a BN curve and u is positive.
# This is used for optimized field inversion for BN curves
declareCurves:
# -----------------------------------------------------------------------------
@ -102,11 +93,6 @@ declareCurves:
bitwidth: 254
modulus: "0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47"
family: BarretoNaehrig
bn_u_bitwidth: 63
bn_u: "0x44e992b44a6909f1" # u: 4965661367192848881
cubicRootOfUnity_modP: "0x30644e72e131a0295e6dd9e7e0acccb0c28f069fbb966e3de4bd44e5607cfd48"
# For sanity checks
cubicRootOfUnity_modR: "0x30644e72e131a029048b6e193fd84104cc37a73fec2bc5e9b8ca0b2d36636f23"
# G1 Equation: Y^2 = X^3 + 3
# G2 Equation: Y^2 = X^3 + 3/(9+𝑖)
@ -140,7 +126,6 @@ declareCurves:
family: BarretoLynnScott
# u: 3 * 2^46 * (7 * 13 * 499) + 1
# u: 0x8508c00000000001
cubicRootOfUnity_mod_p: "0x9b3af05dd14f6ec619aaf7d34594aabc5ed1347970dec00452217cc900000008508c00000000001"
# G1 Equation: y² = x³ + 1
# G2 Equation: y² = x³ + 1/ with 𝑗 = √-5
@ -160,7 +145,6 @@ declareCurves:
modulus: "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab"
family: BarretoLynnScott
# u: -(2^63 + 2^62 + 2^60 + 2^57 + 2^48 + 2^16)
cubicRootOfUnity_mod_p: "0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac"
# G1 Equation: y² = x³ + 4
# G2 Equation: y² = x³ + 4 (1+i)
@ -175,53 +159,3 @@ declareCurves:
sexticTwist: M_Twist
sexticNonResidue_fp2: (1, 1) # 1+𝑖
curve BN446:
bitwidth: 446
modulus: "0x2400000000000000002400000002d00000000d800000021c0000001800000000870000000b0400000057c00000015c000000132000000067"
family: BarretoNaehrig
# u = 2^110 + 2^36 + 1
curve FKM12_447: # Fotiadis-Konstantinou-Martindale
bitwidth: 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
bitwidth: 461
modulus: "0x15555545554d5a555a55d69414935fbd6f1e32d8bacca47b14848b42a8dffa5c1cc00f26aa91557f00400020000555554aaaaaac0000aaaaaaab"
# u = 2^77 + 2^50 + 2^33
# p = (u - 1)^2 (u^4 - u^2 + 1)/3 + u
# Note there is another BLS12-461 proposed here:
# https://tools.ietf.org/id/draft-yonezawa-pairing-friendly-curves-00.html#rfc.section.4.2
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
bitwidth: 462
modulus: "0x240480360120023ffffffffff6ff0cf6b7d9bfca0000000000d812908f41c8020ffffffffff6ff66fc6ff687f640000000002401b00840138013"
family: BarretoNaehrig
# u = 2^114 + 2^101 - 2^14 - 1

View File

@ -124,57 +124,4 @@ macro genDerivedConstants*(): untyped =
)
)
# const MyCurve_cubicRootOfUnity_mod_p
block:
let cubicHex = ident(curve & "_cubicRootOfUnity_modP_Hex")
let cubic = used(curve & "_cubicRootOfUnity_mod_p")
let M = bindSym(curve & "_Modulus")
let r2modM = ident(curve & "_R2modP")
let m0ninv = ident(curve & "_NegInvModWord")
result.add quote do:
when declared(`cubicHex`):
const `cubic` = block:
var cubic: Fp[Curve(`curveSym`)]
montyResidue_precompute(
cubic.mres,
fromHex(cubic.mres.typeof, `cubicHex`),
`M`, `r2modM`, `m0ninv`
)
cubic
# const MyCurve_cubicRootOfUnity_mod_r
block: # For scalar decomposition sanity checks
let cubicHex = ident(curve & "_cubicRootOfUnity_modR_Hex")
let cubic = used(curve & "_cubicRootOfUnity_mod_r")
let getCurveOrderBitwidth = ident"getCurveOrderBitwidth"
result.add quote do:
when declared(`cubicHex`):
const `cubic` = fromHex(BigInt[
`getCurveOrderBitwidth`(Curve(`curveSym`))
], `cubicHex`)
if CurveFamilies[curveSym] == BarretoNaehrig:
# when declared(MyCurve_BN_param_u):
# const MyCurve_BN_u_BE = toCanonicalIntRepr(MyCurve_BN_param_u)
# const MyCurve_BN_6u_minus_1_BE = bn_6u_minus_1_BE(MyCurve_BN_param_u)
var bnStmts = newStmtList()
bnStmts.add newConstStmt(
used(curve & "_BN_u_BE"), newCall(
bindSym"toCanonicalIntRepr",
ident(curve & "_BN_param_u")
)
)
bnStmts.add newConstStmt(
used(curve & "_BN_6u_minus_1_BE"), newCall(
bindSym"bn_6u_minus_1_BE",
ident(curve & "_BN_param_u")
)
)
result.add nnkWhenStmt.newTree(
nnkElifBranch.newTree(
newCall(ident"declared", ident(curve & "_BN_param_u")),
bnStmts
)
)
# echo result.toStrLit()

View File

@ -109,15 +109,7 @@ type
sexticTwist: SexticTwist
sexticNonResidue_fp2: NimNode # nnkPar(nnkIntLit, nnkIntLit)
# Endomorphisms
cubicRootOfUnity_modP: NimNode # nnkStrLit
cubicRootOfUnity_modR: NimNode # nnkStrLit
family: CurveFamily
# BN family
# ------------------------
bn_u_bitwidth: NimNode # nnkIntLit
bn_u: NimNode # nnkStrLit (hex)
var curvesDefinitions {.compileTime.}: seq[CurveParams]
@ -182,14 +174,6 @@ proc parseCurveDecls(defs: var seq[CurveParams], curves: NimNode) =
params.modulus = sectionVal
elif sectionId.eqIdent"family":
params.family = parseEnum[CurveFamily]($sectionVal)
elif sectionId.eqIdent"bn_u_bitwidth":
params.bn_u_bitwidth = sectionVal
elif sectionId.eqIdent"bn_u":
params.bn_u = sectionVal
elif sectionId.eqident"cubicRootOfUnity_modP":
params.cubicRootOfUnity_modP = sectionVal
elif sectionId.eqident"cubicRootOfUnity_modR":
params.cubicRootOfUnity_modR = sectionVal
elif sectionId.eqIdent"eq_form":
params.eq_form = parseEnum[CurveEquationForm]($sectionVal)
elif sectionId.eqIdent"coef_a":
@ -323,42 +307,6 @@ proc genMainConstants(defs: var seq[CurveParams]): NimNode =
curveDef.sexticNonResidue_fp2
)
# Endomorphisms
# -----------------------------------------------
if not curveDef.cubicRootOfUnity_modP.isNil:
curveExtraStmts.add newConstStmt(
exported($curve & "_cubicRootOfUnity_modP_Hex"),
curveDef.cubicRootOfUnity_modP
)
if not curveDef.cubicRootOfUnity_modR.isNil:
curveExtraStmts.add newConstStmt(
exported($curve & "_cubicRootOfUnity_modR_Hex"),
curveDef.cubicRootOfUnity_modR
)
# BN curves
# -----------------------------------------------
if family == BarretoNaehrig:
if not curveDef.bn_u_bitwidth.isNil and
not curveDef.bn_u.isNil and
($curveDef.bn_u)[0] != '-': # The parameter must be positive
curveExtraStmts.add newConstStmt(
exported($curve & "_BN_can_use_addchain_inversion"),
newLit true
)
curveExtraStmts.add newConstStmt(
exported($curve & "_BN_param_u"),
newCall(
bindSym"fromHex",
nnkBracketExpr.newTree(bindSym"BigInt", curveDef.bn_u_bitwidth),
curveDef.bn_u
)
)
else:
curveExtraStmts.add newConstStmt(
exported($curve & "_BN_can_use_addchain_inversion"),
newLit false
)
# end for ---------------------------------------------------
result = newStmtList()

View File

@ -458,35 +458,6 @@ func toCanonicalIntRepr*[bits: static int](
## (octet-string)
result.exportRawUint(a, bigEndian)
func bn_6u_minus_1_BE*[bits: static int](
u: BigInt[bits]
): array[(bits+7+3) div 8, byte] {.noInit.} =
## For a BN curve
## Precompute 6u-1 (for Little Fermat inversion)
## and store it in canonical integer representation
# TODO: optimize output size
# each extra 0-bit is an extra useless squaring for a public exponent
# For example, for BN254-Snarks, u = 0x44E992B44A6909F1 (63-bit)
# and 6u+1 is 65-bit (not 66 as inferred)
# Zero-extend "u"
var u_ext: BigInt[bits+3]
for i in 0 ..< u.limbs.len:
u_ext.limbs[i] = u.limbs[i]
# Addition chain to u -> 6u
discard u_ext.dbl() # u_ext = 2u
let u_ext2 = u_ext # u_ext2 = 2u
discard u_ext.dbl() # u_ext = 4u
discard u_ext.cadd(u_ext2, true) # u_ext = 6u
# Sustract 1
discard u_ext.sub(1)
# Export
result.exportRawUint(u_ext, bigEndian)
# ############################################################
#
# Compile-time Conversion to Montgomery domain

View File

@ -0,0 +1,9 @@
# Curve-specific constants and procedures
This folder holds curve-specific constants and procedure in particular:
- Inversion addition chains
- Final exponentiation addition chains
- Square root constants for Tonelli Shanks
- Lattice decomposition constants for endomorphism acceleration
- Frobenius endomorphism constants

View File

@ -0,0 +1,119 @@
# 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
../config/curves,
../towers,
../io/io_towers
# Frobenius map - on extension fields
# -----------------------------------------------------------------
# c = (SNR^((p-1)/6)^coef).
# Then for frobenius(2): c * conjugate(c)
# And for frobenius(3): c² * conjugate(c)
const BLS12_377_FrobeniusMapCoefficients* = [
# frobenius(1)
[Fp2[BLS12_377].fromHex( # SNR^((p-1)/6)^0
"0x1",
"0x0"
),
Fp2[BLS12_377].fromHex( # SNR^((p-1)/6)^1
"0x9a9975399c019633c1e30682567f915c8a45e0f94ebc8ec681bf34a3aa559db57668e558eb0188e938a9d1104f2031",
"0x0"
),
Fp2[BLS12_377].fromHex( # SNR^((p-1)/6)^2 = SNR^((p-1)/3)
"0x9b3af05dd14f6ec619aaf7d34594aabc5ed1347970dec00452217cc900000008508c00000000002",
"0x0"
),
Fp2[BLS12_377].fromHex( # SNR^((p-1)/6)^3 = SNR^((p-1)/2)
"0x1680a40796537cac0c534db1a79beb1400398f50ad1dec1bce649cf436b0f6299588459bff27d8e6e76d5ecf1391c63",
"0x0"
),
Fp2[BLS12_377].fromHex( # SNR^((p-1)/6)^4 = SNR^(2(p-1)/3)
"0x9b3af05dd14f6ec619aaf7d34594aabc5ed1347970dec00452217cc900000008508c00000000001",
"0x0"
),
Fp2[BLS12_377].fromHex( # SNR^((p-1)/6)^5
"0xcd70cb3fc936348d0351d498233f1fe379531411832232f6648a9a9fc0b9c4e3e21b7467077c05853e2c1be0e9fc32",
"0x0"
)],
# frobenius(2)
[Fp2[BLS12_377].fromHex( # norm(SNR)^((p-1)/6)^1
"0x1",
"0x0"
),
Fp2[BLS12_377].fromHex( # norm(SNR)^((p-1)/6)^2
"0x9b3af05dd14f6ec619aaf7d34594aabc5ed1347970dec00452217cc900000008508c00000000002",
"0x0"
),
Fp2[BLS12_377].fromHex(
"0x9b3af05dd14f6ec619aaf7d34594aabc5ed1347970dec00452217cc900000008508c00000000001",
"0x0"
),
Fp2[BLS12_377].fromHex(
"0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d44300000008508c00000000000",
"0x0"
),
Fp2[BLS12_377].fromHex(
"0x1ae3a4617c510eabc8756ba8f8c524eb8882a75cc9bc8e359064ee822fb5bffd1e945779fffffffffffffffffffffff",
"0x0"
),
Fp2[BLS12_377].fromHex(
"0x1ae3a4617c510eabc8756ba8f8c524eb8882a75cc9bc8e359064ee822fb5bffd1e94577a00000000000000000000000",
"0x0"
)],
# frobenius(3)
[Fp2[BLS12_377].fromHex(
"0x1",
"0x0"
),
Fp2[BLS12_377].fromHex(
"0x1680a40796537cac0c534db1a79beb1400398f50ad1dec1bce649cf436b0f6299588459bff27d8e6e76d5ecf1391c63",
"0x0"
),
Fp2[BLS12_377].fromHex(
"0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d44300000008508c00000000000",
"0x0"
),
Fp2[BLS12_377].fromHex(
"0x4630059e5fd9200575d0e552278a89da1f40fdf62334cd620d1860769e389d7db2d8ea700d82721691ea130ec6e39e",
"0x0"
),
Fp2[BLS12_377].fromHex(
"0x1",
"0x0"
),
Fp2[BLS12_377].fromHex(
"0x1680a40796537cac0c534db1a79beb1400398f50ad1dec1bce649cf436b0f6299588459bff27d8e6e76d5ecf1391c63",
"0x0"
)]]
# ψ (Psi) - Untwist-Frobenius-Twist Endomorphisms on twisted curves
# -----------------------------------------------------------------
# BLS12_377 is a D-Twist: SNR^((p-1)/6)
const BLS12_377_FrobeniusPsi_psi1_coef1* = Fp2[BLS12_377].fromHex(
"0x9a9975399c019633c1e30682567f915c8a45e0f94ebc8ec681bf34a3aa559db57668e558eb0188e938a9d1104f2031",
"0x0"
)
# SNR^((p-1)/3)
const BLS12_377_FrobeniusPsi_psi1_coef2* = Fp2[BLS12_377].fromHex(
"0x9b3af05dd14f6ec619aaf7d34594aabc5ed1347970dec00452217cc900000008508c00000000002",
"0x0"
)
# SNR^((p-1)/2)
const BLS12_377_FrobeniusPsi_psi1_coef3* = Fp2[BLS12_377].fromHex(
"0x1680a40796537cac0c534db1a79beb1400398f50ad1dec1bce649cf436b0f6299588459bff27d8e6e76d5ecf1391c63",
"0x0"
)
# norm(SNR)^((p-1)/3)
const BLS12_377_FrobeniusPsi_psi2_coef2* = Fp2[BLS12_377].fromHex(
"0x9b3af05dd14f6ec619aaf7d34594aabc5ed1347970dec00452217cc900000008508c00000000001",
"0x0"
)

View File

@ -0,0 +1,69 @@
# 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
../config/[curves, type_bigint, type_fp],
../io/[io_bigints, io_fields]
# BLS12-377 G1
# ----------------------------------------------------------------------------------------
const BLS12_377_cubicRootofUnity_mod_p* =
Fp[BLS12_377].fromHex"0x9b3af05dd14f6ec619aaf7d34594aabc5ed1347970dec00452217cc900000008508c00000000001"
const BLS12_377_Lattice_G1* = (
# (BigInt, isNeg)
((BigInt[127].fromHex"0x452217cc900000010a11800000000000", false), # u² - 1
(BigInt[1].fromHex"0x1", true)), # -1
((BigInt[1].fromHex"0x1", false), # 1
(BigInt[127].fromHex"0x452217cc900000010a11800000000001", false)) # u²
)
const BLS12_377_Babai_G1* = (
# Vector for Babai rounding
# (BigInt, isNeg)
(BigInt[130].fromHex"0x3b3f7aa969fd371607f72ed32af90182c", false),
(BigInt[4].fromHex"0xd", false)
)
# BLS12-377 G2
# ----------------------------------------------------------------------------------------
const BLS12_377_Lattice_G2* = (
# Curve of order 254 -> mini scalars of size 65
# x = -0xd201000000010000
# Value, isNeg
((BigInt[64].fromHex"0x8508c00000000001", true), # -x
(BigInt[1].fromHex"0x1", false), # 1
(BigInt[1].fromHex"0x0", false), # 0
(BigInt[1].fromHex"0x0", false)), # 0
((BigInt[1].fromHex"0x0", false), # 0
(BigInt[64].fromHex"0x8508c00000000001", true), # -x
(BigInt[1].fromHex"0x1", false), # 1
(BigInt[1].fromHex"0x0", false)), # 0
((BigInt[1].fromHex"0x0", false), # 0
(BigInt[1].fromHex"0x0", false), # 0
(BigInt[64].fromHex"0x8508c00000000001", true), # -x
(BigInt[1].fromHex"0x1", false)), # 1
((BigInt[1].fromHex"0x1", false), # 1
(BigInt[1].fromHex"0x0", false), # 0
(BigInt[1].fromHex"0x1", true), # -1
(BigInt[64].fromHex"0x8508c00000000001", true)) # -x
)
const BLS12_377_Babai_G2* = (
# Vector for Babai rounding
# Value, isNeg
(BigInt[193].fromHex"0x1eca0125755aed064f63abaff9084ce152979759b442f60d1", true),
(BigInt[130].fromHex"0x3b3f7aa969fd371607f72ed32af90181f", true),
(BigInt[67].fromhex"0x72030ba8ee9c06415", true),
(BigInt[1].fromhex"0x0", false)
)

View 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
../config/[curves, type_bigint],
../towers,
../io/io_bigints,
../pairing/cyclotomic_fp12
# The bit count must be exact for the Miller loop
const BLS12_377_pairing_ate_param* = block:
# BLS Miller loop is parametrized by u
# +1 so that we can take *3 and NAF encode it
BigInt[64+1].fromHex("0x8508c00000000001")
const BLS12_377_pairing_ate_param_isNeg* = false
const BLS12_377_pairing_finalexponent* = block:
# (p^12 - 1) / r
# BigInt[4269].fromHex"0x1b2ff68c1abdc48ab4f04ed12cc8f9b2f161b41c7eb8865b9ad3c9bb0571dd94c6bde66548dc13624d9d741024ceb315f46a89cc2482605eb6afc6d8977e5e2ccbec348dd362d59ec2b5bc62a1b467ae44572215548abc98bb4193886ed89cceaedd0221aba84fb33e5584ac29619a87a00c315178155496857c995eab4a8a9af95f4015db27955ae408d6927d0ab37d52f3917c4ddec88f8159f7bcba7eb65f1aae4eeb4e70cb20227159c08a7fdfea9b62bb308918eac3202569dd1bcdd86b431e3646356fc3fb79f89b30775e006993adb629586b6c874b7688f86f11ef7ad94a40eb020da3c532b317232fa56dc564637b331a8e8832eab84269f00b506602c8594b7f7da5a5d8d851fff6ab1d38a354fc8e0b8958e2a9e5ce2d7e50ec36d761d9505fe5e1f317257e2df2952fcd4c93b85278c20488b4ccaee94db3fec1ce8283473e4b493843fa73abe99af8bafce29170b2b863b9513b5a47312991f60c5a4f6872b5d574212bf00d797c0bea3c0f7dfd748e63679fda9b1c50f2df74de38f38e004ae0df997a10db31d209cacbf58ba0678bfe7cd0985bc43258d72d8d5106c21635ae1e527eb01fca3032d50d97756ec9ee756eaba7f21652a808a4e2539e838ef7ec4b178b29e3b976c46bd0ecdd32c1fb75e6e0aef2d8b5661f595a98023f3520381aba8da6cce785dbb0a0bba025478d75ee749619cdb7c42a21098ece86a00c6c2046c1e00000063c69000000000000"
# (p^12 - 1) / r * 3
BigInt[4271].fromHex"0x518fe3a450394da01ed0ec73865aed18d4251c557c299312d07b5d31105598be5439b32fda943a26e8d85c306e6c1941dd3f9d646d87211c240f5489c67b1a8663c49da97a2880dc48213527e51d370acd05663ffda035ca31c4ba994c89d66c0c97066502f8ef19bb008e047c24cf96e02493f4683ffdc39075cc1c01df9fd0ec1dc0419176c010ac1a83b777201a77f8dab474e99c59ae840de7362f7c231d500aecc1eb52616067540d419f7f9fbfd22831919b4ac04960703d9753698941c95aa2d2a04f4bf26de9d191661a013cbb09227c09424595e2639ae94d35ce708bdec2c10628eb4f981945698ef049502d2a71994fab9898c028c73dd021f13208590be27e78f0f18a88f5ffe40157a9e9fef5aa229c0aa7fdb16a887af2c4a486258bf11fb1a5d945707a89d7bf8f67e5bb28f76a460d9a1e660cbbe91bfc456b8789d5bae1dba8cbef5b03bcd0ea30f6a7b45218292b2bf3b20ed5937cb5e2250eee395821805c6383d0286c7423beb42e79f85dab2a36df8fd154f2d89e5e9aaadaaa00e0a29ecc6e329195761d6063e0a2e136a3fb7671c9134c970a8588a7f3144642a10a5af77c105f5e90987f28c6604c5dcb604c02f7d642f7f819eea6fadb8aace7c4e146a17dab2c644d4372c6979845f261b4a20cd88a20325e0c0fc806bd9f60a8502fa8f466b6919311e232e06fd6a861cb5dc24d69274c7e631cac6b93e0254460d445a0000012b53b000000000000"
func pow_x*(r: var Fp12[BLS12_377], a: Fp12[BLS12_377], invert = BLS12_377_pairing_ate_param_isNeg) =
## f^x with x the curve parameter
## For BLS12_377 f^-0x8508c00000000001
## Warning: The parameter is odd and needs a correction
r.cyclotomic_square(a)
r *= a
r.cyclotomic_square()
r *= a
let t111 = r
r.cycl_sqr_repeated(2)
let t111000 = r
r *= t111
let t100011 = r
r.cyclotomic_square()
r *= t100011
r *= t111000
r.cycl_sqr_repeated(10)
r *= t100011
r.cycl_sqr_repeated(46)
r *= a
if invert:
r.cyclotomic_inv()

View File

@ -0,0 +1,20 @@
# 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
../config/[curves, type_bigint, type_fp],
../io/[io_bigints, io_fields]
const
# with e = 2adicity
# p == s * 2^e + 1
# root_of_unity = smallest_quadratic_nonresidue^s
# exponent = (p-1-2^e)/2^e / 2
BLS12_377_TonelliShanks_exponent* = BigInt[330].fromHex"0x35c748c2f8a21d58c760b80d94292763445b3e601ea271e3de6c45f741290002e16ba88600000010a11"
BLS12_377_TonelliShanks_twoAdicity* = 46
BLS12_377_TonelliShanks_root_of_unity* = Fp[BLS12_377].fromHex"0x382d3d99cdbc5d8fe9dee6aa914b0ad14fcaca7022110ec6eaa2bc56228ac41ea03d28cc795186ba6b5ef26b00bbe8"

View File

@ -0,0 +1,119 @@
# 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
../config/curves,
../towers,
../io/io_towers
# Frobenius map - on extension fields
# -----------------------------------------------------------------
# c = (SNR^((p-1)/6)^coef).
# Then for frobenius(2): c * conjugate(c)
# And for frobenius(3): c² * conjugate(c)
const BLS12_381_FrobeniusMapCoefficients* = [
# frobenius(1)
[Fp2[BLS12_381].fromHex( # SNR^((p-1)/6)^0
"0x1",
"0x0"
),
Fp2[BLS12_381].fromHex( # SNR^((p-1)/6)^1
"0x1904d3bf02bb0667c231beb4202c0d1f0fd603fd3cbd5f4f7b2443d784bab9c4f67ea53d63e7813d8d0775ed92235fb8",
"0xfc3e2b36c4e03288e9e902231f9fb854a14787b6c7b36fec0c8ec971f63c5f282d5ac14d6c7ec22cf78a126ddc4af3"
),
Fp2[BLS12_381].fromHex( # SNR^((p-1)/6)^2 = SNR^((p-1)/3)
"0x0",
"0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac"
),
Fp2[BLS12_381].fromHex( # SNR^((p-1)/6)^3 = SNR^((p-1)/2)
"0x6af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09",
"0x6af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09"
),
Fp2[BLS12_381].fromHex( # SNR^((p-1)/6)^4 = SNR^(2(p-1)/3)
"0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaad",
"0x0"
),
Fp2[BLS12_381].fromHex( # SNR^((p-1)/6)^5
"0x5b2cfd9013a5fd8df47fa6b48b1e045f39816240c0b8fee8beadf4d8e9c0566c63a3e6e257f87329b18fae980078116",
"0x144e4211384586c16bd3ad4afa99cc9170df3560e77982d0db45f3536814f0bd5871c1908bd478cd1ee605167ff82995"
)],
# frobenius(2)
[Fp2[BLS12_381].fromHex( # norm(SNR)^((p-1)/6)^1
"0x1",
"0x0"
),
Fp2[BLS12_381].fromHex( # norm(SNR)^((p-1)/6)^2
"0x5f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffeffff",
"0x0"
),
Fp2[BLS12_381].fromHex(
"0x5f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe",
"0x0"
),
Fp2[BLS12_381].fromHex(
"0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa",
"0x0"
),
Fp2[BLS12_381].fromHex(
"0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac",
"0x0"
),
Fp2[BLS12_381].fromHex(
"0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaad",
"0x0"
)],
# frobenius(3)
[Fp2[BLS12_381].fromHex(
"0x1",
"0x0"
),
Fp2[BLS12_381].fromHex(
"0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2",
"0x6af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09"
),
Fp2[BLS12_381].fromHex(
"0x0",
"0x1"
),
Fp2[BLS12_381].fromHex(
"0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2",
"0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2"
),
Fp2[BLS12_381].fromHex(
"0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa",
"0x0"
),
Fp2[BLS12_381].fromHex(
"0x6af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09",
"0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2"
)]]
# ψ (Psi) - Untwist-Frobenius-Twist Endomorphisms on twisted curves
# -----------------------------------------------------------------
# BLS12_381 is a M-twist: (1/SNR)^((p-1)/6)
const BLS12_381_FrobeniusPsi_psi1_coef1* = Fp2[BLS12_381].fromHex(
"0x5b2cfd9013a5fd8df47fa6b48b1e045f39816240c0b8fee8beadf4d8e9c0566c63a3e6e257f87329b18fae980078116",
"0x5b2cfd9013a5fd8df47fa6b48b1e045f39816240c0b8fee8beadf4d8e9c0566c63a3e6e257f87329b18fae980078116"
)
# (1/SNR)^((p-1)/3)
const BLS12_381_FrobeniusPsi_psi1_coef2* = Fp2[BLS12_381].fromHex(
"0x0",
"0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaad"
)
# (1/SNR)^((p-1)/2)
const BLS12_381_FrobeniusPsi_psi1_coef3* = Fp2[BLS12_381].fromHex(
"0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2",
"0x6af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09"
)
# norm(SNR)^((p-1)/3)
const BLS12_381_FrobeniusPsi_psi2_coef2* = Fp2[BLS12_381].fromHex(
"0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac",
"0x0"
)

View File

@ -0,0 +1,69 @@
# 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
../config/[curves, type_bigint, type_fp],
../io/[io_bigints, io_fields]
# BLS12-381 G1
# ----------------------------------------------------------------------------------------
const BLS12_381_cubicRootOfUnity_mod_p* =
Fp[BLS12_381].fromHex"0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac"
const BLS12_381_Lattice_G1* = (
# (BigInt, isNeg)
((BigInt[128].fromHex"0xac45a4010001a40200000000ffffffff", false), # u² - 1
(BigInt[1].fromHex"0x1", true)), # -1
((BigInt[1].fromHex"0x1", false), # 1
(BigInt[128].fromHex"0xac45a4010001a4020000000100000000", false)) # u²
)
const BLS12_381_Babai_G1* = (
# Vector for Babai rounding
# (BigInt, isNeg)
(BigInt[129].fromHex"0x17c6becf1e01faadd63f6e522f6cfee30", false),
(BigInt[2].fromHex"0x2", false)
)
# BLS12-381 G2
# ----------------------------------------------------------------------------------------
const BLS12_381_Lattice_G2* = (
# Curve of order 254 -> mini scalars of size 65
# x = -0xd201000000010000
# Value, isNeg
((BigInt[64].fromHex"0xd201000000010000", false), # -x
(BigInt[1].fromHex"0x1", false), # 1
(BigInt[1].fromHex"0x0", false), # 0
(BigInt[1].fromHex"0x0", false)), # 0
((BigInt[1].fromHex"0x0", false), # 0
(BigInt[64].fromHex"0xd201000000010000", false), # -x
(BigInt[1].fromHex"0x1", false), # 1
(BigInt[1].fromHex"0x0", false)), # 0
((BigInt[1].fromHex"0x0", false), # 0
(BigInt[1].fromHex"0x0", false), # 0
(BigInt[64].fromHex"0xd201000000010000", false), # -x
(BigInt[1].fromHex"0x1", false)), # 1
((BigInt[1].fromHex"0x1", false), # 1
(BigInt[1].fromHex"0x0", false), # 0
(BigInt[1].fromHex"0x1", true), # -1
(BigInt[64].fromHex"0xd201000000010000", false)) # -x
)
const BLS12_381_Babai_G2* = (
# Vector for Babai rounding
# Value, isNeg
(BigInt[193].fromHex"0x1381204ca56cd56b533cfcc0d3e76ec2892078a5e8573b29c", false),
(BigInt[129].fromHex"0x17c6becf1e01faadd63f6e522f6cfee2f", true),
(BigInt[65].fromhex"0x1cfbe4f7bd0027db0", false),
(BigInt[1].fromhex"0x0", false)
)

View File

@ -0,0 +1,219 @@
# 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
../config/curves,
../arithmetic/finite_fields
# ############################################################
#
# Specialized inversion for BLS12-381
#
# ############################################################
func inv_addchain*(r: var Fp[BLS12_381], a: Fp[BLS12_381]) =
var
x10 {.noinit.}: Fp[BLS12_381]
x100 {.noinit.}: Fp[BLS12_381]
x1000 {.noinit.}: Fp[BLS12_381]
x1001 {.noinit.}: Fp[BLS12_381]
x1011 {.noinit.}: Fp[BLS12_381]
x1101 {.noinit.}: Fp[BLS12_381]
x10001 {.noinit.}: Fp[BLS12_381]
x10100 {.noinit.}: Fp[BLS12_381]
x11001 {.noinit.}: Fp[BLS12_381]
x11010 {.noinit.}: Fp[BLS12_381]
x110100 {.noinit.}: Fp[BLS12_381]
x110110 {.noinit.}: Fp[BLS12_381]
x110111 {.noinit.}: Fp[BLS12_381]
x1001101 {.noinit.}: Fp[BLS12_381]
x1001111 {.noinit.}: Fp[BLS12_381]
x1010101 {.noinit.}: Fp[BLS12_381]
x1011101 {.noinit.}: Fp[BLS12_381]
x1100111 {.noinit.}: Fp[BLS12_381]
x1101001 {.noinit.}: Fp[BLS12_381]
x1110111 {.noinit.}: Fp[BLS12_381]
x1111011 {.noinit.}: Fp[BLS12_381]
x10001001 {.noinit.}: Fp[BLS12_381]
x10010101 {.noinit.}: Fp[BLS12_381]
x10010111 {.noinit.}: Fp[BLS12_381]
x10101001 {.noinit.}: Fp[BLS12_381]
x10110001 {.noinit.}: Fp[BLS12_381]
x10111111 {.noinit.}: Fp[BLS12_381]
x11000011 {.noinit.}: Fp[BLS12_381]
x11010000 {.noinit.}: Fp[BLS12_381]
x11010111 {.noinit.}: Fp[BLS12_381]
x11100001 {.noinit.}: Fp[BLS12_381]
x11100101 {.noinit.}: Fp[BLS12_381]
x11101011 {.noinit.}: Fp[BLS12_381]
x11110101 {.noinit.}: Fp[BLS12_381]
x11111111 {.noinit.}: Fp[BLS12_381]
x10 .square(a)
x100 .square(x10)
x1000 .square(x100)
x1001 .prod(a, x1000)
x1011 .prod(x10, x1001)
x1101 .prod(x10, x1011)
x10001 .prod(x100, x1101)
x10100 .prod(x1001, x1011)
x11001 .prod(x1000, x10001)
x11010 .prod(a, x11001)
x110100 .square(x11010)
x110110 .prod(x10, x110100)
x110111 .prod(a, x110110)
x1001101 .prod(x11001, x110100)
x1001111 .prod(x10, x1001101)
x1010101 .prod(x1000, x1001101)
x1011101 .prod(x1000, x1010101)
x1100111 .prod(x11010, x1001101)
x1101001 .prod(x10, x1100111)
x1110111 .prod(x11010, x1011101)
x1111011 .prod(x100, x1110111)
x10001001 .prod(x110100, x1010101)
x10010101 .prod(x11010, x1111011)
x10010111 .prod(x10, x10010101)
x10101001 .prod(x10100, x10010101)
x10110001 .prod(x1000, x10101001)
x10111111 .prod(x110110, x10001001)
x11000011 .prod(x100, x10111111)
x11010000 .prod(x1101, x11000011)
x11010111 .prod(x10100, x11000011)
x11100001 .prod(x10001, x11010000)
x11100101 .prod(x100, x11100001)
x11101011 .prod(x10100, x11010111)
x11110101 .prod(x10100, x11100001)
x11111111 .prod(x10100, x11101011) # 35 operations
# TODO: we can accumulate in a partially reduced
# doubled-size `r` to avoid the final substractions.
# and only reduce at the end.
# This requires the number of op to be less than log2(p) == 381
# 35 + 22 = 57 operations
r.prod(x10111111, x11100001)
r.square_repeated(8)
r *= x10001
r.square_repeated(11)
r *= x11110101
# 57 + 28 = 85 operations
r.square_repeated(11)
r *= x11100101
r.square_repeated(8)
r *= x11111111
r.square_repeated(7)
# 88 + 22 = 107 operations
r *= x1001101
r.square_repeated(9)
r *= x1101001
r.square_repeated(10)
r *= x10110001
# 107+24 = 131 operations
r.square_repeated(7)
r *= x1011101
r.square_repeated(9)
r *= x1111011
r.square_repeated(6)
# 131+23 = 154 operations
r *= x11001
r.square_repeated(11)
r *= x1101001
r.square_repeated(9)
r *= x11101011
# 154+28 = 182 operations
r.square_repeated(10)
r *= x11010111
r.square_repeated(6)
r *= x11001
r.square_repeated(10)
# 182+23 = 205 operations
r *= x1110111
r.square_repeated(9)
r *= x10010111
r.square_repeated(11)
r *= x1001111
# 205+30 = 235 operations
r.square_repeated(10)
r *= x11100001
r.square_repeated(9)
r *= x10001001
r.square_repeated(9)
# 235+21 = 256 operations
r *= x10111111
r.square_repeated(8)
r *= x1100111
r.square_repeated(10)
r *= x11000011
# 256+28 = 284 operations
r.square_repeated(9)
r *= x10010101
r.square_repeated(12)
r *= x1111011
r.square_repeated(5)
# 284 + 21 = 305 operations
r *= x1011
r.square_repeated(11)
r *= x1111011
r.square_repeated(7)
r *= x1001
# 305+32 = 337 operations
r.square_repeated(13)
r *= x11110101
r.square_repeated(9)
r *= x10111111
r.square_repeated(8)
# 337+22 = 359 operations
r *= x11111111
r.square_repeated(8)
r *= x11101011
r.square_repeated(11)
r *= x10101001
# 359+24 = 383 operations
r.square_repeated(8)
r *= x11111111
r.square_repeated(8)
r *= x11111111
r.square_repeated(6)
# 383+22 = 405 operations
r *= x110111
r.square_repeated(10)
r *= x11111111
r.square_repeated(9)
r *= x11111111
# 405+26 = 431 operations
r.square_repeated(8)
r *= x11111111
r.square_repeated(8)
r *= x11111111
r.square_repeated(8)
# 431+19 = 450 operations
r *= x11111111
r.square_repeated(7)
r *= x1010101
r.square_repeated(9)
r *= x10101001
# Total 450 operations:
# - 74 multiplications
# - 376 squarings

View File

@ -0,0 +1,51 @@
# 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
../config/[curves, type_bigint],
../towers,
../io/io_bigints,
../pairing/cyclotomic_fp12
# The bit count must be exact for the Miller loop
const BLS12_381_pairing_ate_param* = block:
# BLS Miller loop is parametrized by u
BigInt[64+2].fromHex("0xd201000000010000") # +2 so that we can take *3 and NAF encode it
const BLS12_381_pairing_ate_param_isNeg* = true
const BLS12_381_pairing_finalexponent* = block:
# (p^12 - 1) / r
# BigInt[4314].fromHex"0x2ee1db5dcc825b7e1bda9c0496a1c0a89ee0193d4977b3f7d4507d07363baa13f8d14a917848517badc3a43d1073776ab353f2c30698e8cc7deada9c0aadff5e9cfee9a074e43b9a660835cc872ee83ff3a0f0f1c0ad0d6106feaf4e347aa68ad49466fa927e7bb9375331807a0dce2630d9aa4b113f414386b0e8819328148978e2b0dd39099b86e1ab656d2670d93e4d7acdd350da5359bc73ab61a0c5bf24c374693c49f570bcd2b01f3077ffb10bf24dde41064837f27611212596bc293c8d4c01f25118790f4684d0b9c40a68eb74bb22a40ee7169cdc1041296532fef459f12438dfc8e2886ef965e61a474c5c85b0129127a1b5ad0463434724538411d1676a53b5a62eb34c05739334f46c02c3f0bd0c55d3109cd15948d0a1fad20044ce6ad4c6bec3ec03ef19592004cedd556952c6d8823b19dadd7c2498345c6e5308f1c511291097db60b1749bf9b71a9f9e0100418a3ef0bc627751bbd81367066bca6a4c1b6dcfc5cceb73fc56947a403577dfa9e13c24ea820b09c1d9f7c31759c3635de3f7a3639991708e88adce88177456c49637fd7961be1a4c7e79fb02faa732e2f3ec2bea83d196283313492caa9d4aff1c910e9622d2a73f62537f2701aaef6539314043f7bbce5b78c7869aeb2181a67e49eeed2161daf3f881bd88592d767f67c4717489119226c2f011d4cab803e9d71650a6f80698e2f8491d12191a04406fbc8fbd5f48925f98630e68bfb24c0bcb9b55df57510"
# (p^12 - 1) / r * 3
BigInt[4316].fromHex"0x8ca592196587127a538fd40dc3e541f9dca04bb7dc671be77cf17715a2b2fe3bea73dfb468d8f473094aecb7315a664019fbd84913caba6579c08fd42009fe1bd6fcbce15eacb2cf3218a165958cb8bfdae2d2d54207282314fc0dea9d6ff3a07dbd34efb77b732ba5f994816e296a72928cfee133bdc3ca9412b984b9783d9c6aa81297ab1cd294a502304773528bbae8706979f28efa0d355b0224e2513d6e4a5d3bb4dde0523678105d9167ff1323d6e99ac312d8a7d762336370c4347bb5a7e405d6f3496b2dd38e722d4c1f3ac25e3167ec2cb543d69430c37c2f98fcdd0dd36caa9f5aa7994cec31b24ed5e515911037b376e521070d29c9d56cfa8c3574363efb20f28c19e4105ab99edd44084bd23725017931d6740bda71e5f07600ce6b407e543c4bc40bcd4c0b600e6c98003bf8548986b14d9098746dc89d154af91ad54f337b31c79222145dd3ed254fdeda0300c49ebcd2352765f533883a3513435f3ee452496f5166c25bf503bd6ec0a0679efda3b46ebf86211d458de749460d4a2a19abe6ea2accb451ab9a096b98465d044dc2a7f86c253a4ee57b6df108eff598a8dbc483bf8b74c2789939db85ffd7e0fd55b32bc26877f5be26fa7d750500ce2fab93c0cbe7336b126a5693d0c16484f37addccc7642590dbe98538990b88637e374d545d9b34b67448d0357e60280bbd8542f1f4e813caa8e8db57364b4e0cc14f35af381dd9b71ec9292b3a3f16e42362d2019e05f30"
func pow_xdiv2*(r: var Fp12[BLS12_381], a: Fp12[BLS12_381], invert = BLS12_381_pairing_ate_param_isNeg) =
## f^(x/2) with x the curve parameter
## For BLS12_381 f^-0xd201000000010000
r.cyclotomic_square(a)
r *= a
r.cycl_sqr_repeated(2)
r *= a
r.cycl_sqr_repeated(3)
r *= a
r.cycl_sqr_repeated(9)
r *= a
r.cycl_sqr_repeated(32) # TODO: use Karabina?
r *= a
r.cycl_sqr_repeated(16-1) # Don't do the last iteration
if invert:
r.cyclotomic_inv()
func pow_x*(r: var Fp12[BLS12_381], a: Fp12[BLS12_381], invert = BLS12_381_pairing_ate_param_isNeg) =
## f^x with x the curve parameter
## For BLS12_381 f^-0xd201000000010000
r.pow_xdiv2(a, invert)
r.cyclotomic_square()

View File

@ -0,0 +1,119 @@
# 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
../config/curves,
../towers,
../io/io_towers
# Frobenius map - on extension fields
# -----------------------------------------------------------------
# c = (SNR^((p-1)/6)^coef).
# Then for frobenius(2): c * conjugate(c)
# And for frobenius(3): c² * conjugate(c)
const BN254_Nogami_FrobeniusMapCoefficients* = [
# frobenius(1)
[Fp2[BN254_Nogami].fromHex( # SNR^((p-1)/6)^0
"0x1",
"0x0"
),
Fp2[BN254_Nogami].fromHex( # SNR^((p-1)/6)^1
"0x1b377619212e7c8cb6499b50a846953f850974924d3f77c2e17de6c06f2a6de9",
"0x9ebee691ed1837503eab22f57b96ac8dc178b6db2c08850c582193f90d5922a"
),
Fp2[BN254_Nogami].fromHex( # SNR^((p-1)/6)^2 = SNR^((p-1)/3)
"0x0",
"0x25236482400000017080eb4000000006181800000000000cd98000000000000b"
),
Fp2[BN254_Nogami].fromHex( # SNR^((p-1)/6)^3 = SNR^((p-1)/2)
"0x23dfc9d1a39f4db8c69b87a8848aa075a7333a0e62d78cbf4b1b8eeae58b81c5",
"0x23dfc9d1a39f4db8c69b87a8848aa075a7333a0e62d78cbf4b1b8eeae58b81c5"
),
Fp2[BN254_Nogami].fromHex( # SNR^((p-1)/6)^4 = SNR^(2(p-1)/3)
"0x25236482400000017080eb4000000006181800000000000cd98000000000000c",
"0x0"
),
Fp2[BN254_Nogami].fromHex( # SNR^((p-1)/6)^5
"0x19f3db6884cdca43c2b0d5792cd135accb1baea0b017046e859975ab54b5ef9b",
"0xb2f8919bb3235bdf7837806d32eca5b9605515f4fe8fba521668a54ab4a1078"
)],
# frobenius(2)
[Fp2[BN254_Nogami].fromHex( # norm(SNR)^((p-1)/6)^1
"0x1",
"0x0"
),
Fp2[BN254_Nogami].fromHex( # norm(SNR)^((p-1)/6)^2
"0x49b36240000000024909000000000006cd80000000000008",
"0x0"
),
Fp2[BN254_Nogami].fromHex(
"0x49b36240000000024909000000000006cd80000000000007",
"0x0"
),
Fp2[BN254_Nogami].fromHex(
"0x2523648240000001ba344d80000000086121000000000013a700000000000012",
"0x0"
),
Fp2[BN254_Nogami].fromHex(
"0x25236482400000017080eb4000000006181800000000000cd98000000000000b",
"0x0"
),
Fp2[BN254_Nogami].fromHex(
"0x25236482400000017080eb4000000006181800000000000cd98000000000000c",
"0x0"
)],
# frobenius(3)
[Fp2[BN254_Nogami].fromHex(
"0x1",
"0x0"
),
Fp2[BN254_Nogami].fromHex(
"0x1439ab09c60b248f398c5d77b755f92b9edc5f19d2873545be471151a747e4e",
"0x23dfc9d1a39f4db8c69b87a8848aa075a7333a0e62d78cbf4b1b8eeae58b81c5"
),
Fp2[BN254_Nogami].fromHex(
"0x0",
"0x1"
),
Fp2[BN254_Nogami].fromHex(
"0x1439ab09c60b248f398c5d77b755f92b9edc5f19d2873545be471151a747e4e",
"0x1439ab09c60b248f398c5d77b755f92b9edc5f19d2873545be471151a747e4e"
),
Fp2[BN254_Nogami].fromHex(
"0x2523648240000001ba344d80000000086121000000000013a700000000000012",
"0x0"
),
Fp2[BN254_Nogami].fromHex(
"0x23dfc9d1a39f4db8c69b87a8848aa075a7333a0e62d78cbf4b1b8eeae58b81c5",
"0x1439ab09c60b248f398c5d77b755f92b9edc5f19d2873545be471151a747e4e"
)]]
# ψ (Psi) - Untwist-Frobenius-Twist Endomorphisms on twisted curves
# -----------------------------------------------------------------
# BN254_Snarks is a D-Twist: SNR^((p-1)/6)
const BN254_Nogami_FrobeniusPsi_psi1_coef1* = Fp2[BN254_Nogami].fromHex(
"0x1b377619212e7c8cb6499b50a846953f850974924d3f77c2e17de6c06f2a6de9",
"0x9ebee691ed1837503eab22f57b96ac8dc178b6db2c08850c582193f90d5922a"
)
# SNR^((p-1)/3)
const BN254_Nogami_FrobeniusPsi_psi1_coef2* = Fp2[BN254_Nogami].fromHex(
"0x0",
"0x25236482400000017080eb4000000006181800000000000cd98000000000000b"
)
# SNR^((p-1)/2)
const BN254_Nogami_FrobeniusPsi_psi1_coef3* = Fp2[BN254_Nogami].fromHex(
"0x23dfc9d1a39f4db8c69b87a8848aa075a7333a0e62d78cbf4b1b8eeae58b81c5",
"0x23dfc9d1a39f4db8c69b87a8848aa075a7333a0e62d78cbf4b1b8eeae58b81c5"
)
# norm(SNR)^((p-1)/3)
const BN254_Nogami_FrobeniusPsi_psi2_coef2* = Fp2[BN254_Nogami].fromHex(
"0x49b36240000000024909000000000006cd80000000000007",
"0x0"
)

View File

@ -0,0 +1,37 @@
# 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
../config/[curves, type_bigint],
../towers,
../io/io_bigints,
../pairing/cyclotomic_fp12
# The bit count must be exact for the Miller loop
const BN254_Nogami_pairing_ate_param* = block:
# BN Miller loop is parametrized by 6u+2
# 65+2 bit for NAF x3 encoding
BigInt[65+2].fromHex"0x18300000000000004"
const BN254_Nogami_pairing_ate_param_isNeg* = true
const BN254_Nogami_pairing_finalexponent* = block:
# (p^12 - 1) / r
BigInt[2786].fromHex"0x2928fbb36b391596ee3fe4cbe857330da83e46fedf04d235a4a8daf5ff9f6eabcb4e3f20aa06f0a0d96b24f9af0cbbce750d61627dcbf5fec9139b8f1c46c86b49b4f8a202af26e4504f2c0f56570e9bd5b94c403f385d1908556486e24b396ddc2cdf13d06542f84fe8e82ccbad7b7423fc1ef4e8cc73d605e3e867c0a75f45ea7f6356d9846ce35d5a34f30396938818ad41914b97b99c289a7259b5d2e09477a77bd3c409b19f19e893f8ade90b0aed1b5fc8a07a3cebb41d4e9eee96b21a832ddb1e93e113edfb704fa532848c18593cd0ee90444a1b3499a800177ea38bdec62ec5191f2b6bbee449722f98d2173ad33077545c2ad10347e125a56fb40f086e9a4e62ad336a72c8b202ac3c1473d73b93d93dc0795ca0ca39226e7b4c1bb92f99248ec0806e0ad70744e9f2238736790f5185ea4c70808442a7d530c6ccd56b55a6973867ec6c73599bbd020bbe105da9c6b5c009ad8946cd6f0"
func pow_u*(r: var Fp12[BN254_Nogami], a: Fp12[BN254_Nogami], invert = BN254_Nogami_pairing_ate_param_isNeg) =
## f^u with u the curve parameter
## For BN254_Nogami f^-0x4080000000000001
r = a
r.cycl_sqr_repeated(7)
r *= a
r.cycl_sqr_repeated(55)
r *= a
if invert:
r.cyclotomic_inv()

View File

@ -0,0 +1,119 @@
# 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
../config/curves,
../towers,
../io/io_towers
# Frobenius map - on extension fields
# -----------------------------------------------------------------
# c = (SNR^((p-1)/6)^coef).
# Then for frobenius(2): c * conjugate(c)
# And for frobenius(3): c² * conjugate(c)
const BN254_Snarks_FrobeniusMapCoefficients* = [
# frobenius(1)
[Fp2[BN254_Snarks].fromHex( # SNR^((p-1)/6)^0
"0x1",
"0x0"
),
Fp2[BN254_Snarks].fromHex( # SNR^((p-1)/6)^1
"0x1284b71c2865a7dfe8b99fdd76e68b605c521e08292f2176d60b35dadcc9e470",
"0x246996f3b4fae7e6a6327cfe12150b8e747992778eeec7e5ca5cf05f80f362ac"
),
Fp2[BN254_Snarks].fromHex( # SNR^((p-1)/6)^2 = SNR^((p-1)/3)
"0x2fb347984f7911f74c0bec3cf559b143b78cc310c2c3330c99e39557176f553d",
"0x16c9e55061ebae204ba4cc8bd75a079432ae2a1d0b7c9dce1665d51c640fcba2"
),
Fp2[BN254_Snarks].fromHex( # SNR^((p-1)/6)^3 = SNR^((p-1)/2)
"0x63cf305489af5dcdc5ec698b6e2f9b9dbaae0eda9c95998dc54014671a0135a",
"0x7c03cbcac41049a0704b5a7ec796f2b21807dc98fa25bd282d37f632623b0e3"
),
Fp2[BN254_Snarks].fromHex( # SNR^((p-1)/6)^4 = SNR^(2(p-1)/3)
"0x5b54f5e64eea80180f3c0b75a181e84d33365f7be94ec72848a1f55921ea762",
"0x2c145edbe7fd8aee9f3a80b03b0b1c923685d2ea1bdec763c13b4711cd2b8126"
),
Fp2[BN254_Snarks].fromHex( # SNR^((p-1)/6)^5
"0x183c1e74f798649e93a3661a4353ff4425c459b55aa1bd32ea2c810eab7692f",
"0x12acf2ca76fd0675a27fb246c7729f7db080cb99678e2ac024c6b8ee6e0c2c4b"
)],
# frobenius(2)
[Fp2[BN254_Snarks].fromHex( # norm(SNR)^((p-1)/6)^1
"0x1",
"0x0"
),
Fp2[BN254_Snarks].fromHex( # norm(SNR)^((p-1)/6)^2
"0x30644e72e131a0295e6dd9e7e0acccb0c28f069fbb966e3de4bd44e5607cfd49",
"0x0"
),
Fp2[BN254_Snarks].fromHex(
"0x30644e72e131a0295e6dd9e7e0acccb0c28f069fbb966e3de4bd44e5607cfd48",
"0x0"
),
Fp2[BN254_Snarks].fromHex(
"0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd46",
"0x0"
),
Fp2[BN254_Snarks].fromHex(
"0x59e26bcea0d48bacd4f263f1acdb5c4f5763473177fffffe",
"0x0"
),
Fp2[BN254_Snarks].fromHex(
"0x59e26bcea0d48bacd4f263f1acdb5c4f5763473177ffffff",
"0x0"
)],
# frobenius(3)
[Fp2[BN254_Snarks].fromHex(
"0x1",
"0x0"
),
Fp2[BN254_Snarks].fromHex(
"0x19dc81cfcc82e4bbefe9608cd0acaa90894cb38dbe55d24ae86f7d391ed4a67f",
"0xabf8b60be77d7306cbeee33576139d7f03a5e397d439ec7694aa2bf4c0c101"
),
Fp2[BN254_Snarks].fromHex(
"0x856e078b755ef0abaff1c77959f25ac805ffd3d5d6942d37b746ee87bdcfb6d",
"0x4f1de41b3d1766fa9f30e6dec26094f0fdf31bf98ff2631380cab2baaa586de"
),
Fp2[BN254_Snarks].fromHex(
"0x2a275b6d9896aa4cdbf17f1dca9e5ea3bbd689a3bea870f45fcc8ad066dce9ed",
"0x28a411b634f09b8fb14b900e9507e9327600ecc7d8cf6ebab94d0cb3b2594c64"
),
Fp2[BN254_Snarks].fromHex(
"0xbc58c6611c08dab19bee0f7b5b2444ee633094575b06bcb0e1a92bc3ccbf066",
"0x23d5e999e1910a12feb0f6ef0cd21d04a44a9e08737f96e55fe3ed9d730c239f"
),
Fp2[BN254_Snarks].fromHex(
"0x13c49044952c0905711699fa3b4d3f692ed68098967c84a5ebde847076261b43",
"0x16db366a59b1dd0b9fb1b2282a48633d3e2ddaea200280211f25041384282499"
)]]
# ψ (Psi) - Untwist-Frobenius-Twist Endomorphisms on twisted curves
# -----------------------------------------------------------------
# BN254_Snarks is a D-Twist: SNR^((p-1)/6)
const BN254_Snarks_FrobeniusPsi_psi1_coef1* = Fp2[BN254_Snarks].fromHex(
"0x1284b71c2865a7dfe8b99fdd76e68b605c521e08292f2176d60b35dadcc9e470",
"0x246996f3b4fae7e6a6327cfe12150b8e747992778eeec7e5ca5cf05f80f362ac"
)
# SNR^((p-1)/3)
const BN254_Snarks_FrobeniusPsi_psi1_coef2* = Fp2[BN254_Snarks].fromHex(
"0x2fb347984f7911f74c0bec3cf559b143b78cc310c2c3330c99e39557176f553d",
"0x16c9e55061ebae204ba4cc8bd75a079432ae2a1d0b7c9dce1665d51c640fcba2"
)
# SNR^((p-1)/2)
const BN254_Snarks_FrobeniusPsi_psi1_coef3* = Fp2[BN254_Snarks].fromHex(
"0x63cf305489af5dcdc5ec698b6e2f9b9dbaae0eda9c95998dc54014671a0135a",
"0x7c03cbcac41049a0704b5a7ec796f2b21807dc98fa25bd282d37f632623b0e3"
)
# norm(SNR)^((p-1)/3)
const BN254_Snarks_FrobeniusPsi_psi2_coef2* = Fp2[BN254_Snarks].fromHex(
"0x30644e72e131a0295e6dd9e7e0acccb0c28f069fbb966e3de4bd44e5607cfd48",
"0x0"
)

View 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
../config/[curves, type_bigint, type_fp],
../io/[io_bigints, io_fields]
# BN254 Snarks G1
# ----------------------------------------------------------------------------------------
const BN254_Snarks_cubicRootofUnity_mod_p* =
Fp[BN254_Snarks].fromHex"0x30644e72e131a0295e6dd9e7e0acccb0c28f069fbb966e3de4bd44e5607cfd48"
# Chapter 6.3.1 - Guide to Pairing-based Cryptography
const BN254_Snarks_Lattice_G1* = (
# Curve of order 254 -> mini scalars of size 127
# u = 0x44E992B44A6909F1
# (BigInt, isNeg)
((BigInt[64].fromHex"0x89d3256894d213e3", false), # 2u + 1
(BigInt[127].fromHex"0x6f4d8248eeb859fd0be4e1541221250b", false)), # 6u² + 4u + 1
((BigInt[127].fromHex"0x6f4d8248eeb859fc8211bbeb7d4f1128", false), # 6u² + 2u
(BigInt[64].fromHex"0x89d3256894d213e3", true)) # -2u - 1
)
const BN254_Snarks_Babai_G1* = (
# Vector for Babai rounding
# (BigInt, isNeg)
(BigInt[66].fromHex"0x2d91d232ec7e0b3d7", false), # (2u + 1) << 2^256 // r
(BigInt[130].fromHex"0x24ccef014a773d2d25398fd0300ff6565", false) # (6u² + 4u + 1) << 2^256 // r
)
# BN254 Snarks G2
# ----------------------------------------------------------------------------------------
const BN254_Snarks_Lattice_G2* = (
# Curve of order 254 -> mini scalars of size 65
# x = 0x44E992B44A6909F1
# Value, isNeg
((BigInt[63].fromHex"0x44e992b44a6909f2", false), # x+1
(BigInt[63].fromHex"0x44e992b44a6909f1", false), # x
(BigInt[63].fromHex"0x44e992b44a6909f1", false), # x
(BigInt[64].fromHex"0x89d3256894d213e2", true)), # -2x
((BigInt[64].fromHex"0x89d3256894d213e3", false), # 2x+1
(BigInt[63].fromHex"0x44e992b44a6909f1", true), # -x
(BigInt[63].fromHex"0x44e992b44a6909f2", true), # -x-1
(BigInt[63].fromHex"0x44e992b44a6909f1", true)), # -x
((BigInt[64].fromHex"0x89d3256894d213e2", false), # 2x
(BigInt[64].fromHex"0x89d3256894d213e3", false), # 2x+1
(BigInt[64].fromHex"0x89d3256894d213e3", false), # 2x+1
(BigInt[64].fromHex"0x89d3256894d213e3", false)), # 2x+1
((BigInt[63].fromHex"0x44e992b44a6909f0", false), # x-1
(BigInt[65].fromHex"0x113a64ad129a427c6", false), # 4x+2
(BigInt[64].fromHex"0x89d3256894d213e1", true), # -2x+1
(BigInt[63].fromHex"0x44e992b44a6909f0", false)), # x-1
)
const BN254_Snarks_Babai_G2* = (
# Vector for Babai rounding
# Value, isNeg
(BigInt[128].fromHex"0xc444fab18d269b9dd0cb46fd51906254", false), # 2x²+3x+1 << 2^256 // r
(BigInt[193].fromHex"0x13d00631561b2572922df9f942d7d77c7001378f5ee78976d", false), # 3x³+8x²+x << 2^256 // r
(BigInt[192].fromhex"0x9e80318ab0d92b94916fcfca16bebbe436510546a93478ab", false), # 6x³+4x²+x << 2^256 // r
(BigInt[128].fromhex"0xc444fab18d269b9af7ae23ce89afae7d", true) # -2x²-x << 2^256 // r
)

View File

@ -0,0 +1,158 @@
# 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
../config/curves,
../arithmetic/finite_fields
# ############################################################
#
# Specialized inversion for BN254-Snarks
#
# ############################################################
func inv_addchain*(r: var Fp[BN254_Snarks], a: Fp[BN254_Snarks]) =
var
x10 {.noInit.}: Fp[BN254_Snarks]
x11 {.noInit.}: Fp[BN254_Snarks]
x101 {.noInit.}: Fp[BN254_Snarks]
x110 {.noInit.}: Fp[BN254_Snarks]
x1000 {.noInit.}: Fp[BN254_Snarks]
x1101 {.noInit.}: Fp[BN254_Snarks]
x10010 {.noInit.}: Fp[BN254_Snarks]
x10011 {.noInit.}: Fp[BN254_Snarks]
x10100 {.noInit.}: Fp[BN254_Snarks]
x10111 {.noInit.}: Fp[BN254_Snarks]
x11100 {.noInit.}: Fp[BN254_Snarks]
x100000 {.noInit.}: Fp[BN254_Snarks]
x100011 {.noInit.}: Fp[BN254_Snarks]
x101011 {.noInit.}: Fp[BN254_Snarks]
x101111 {.noInit.}: Fp[BN254_Snarks]
x1000001 {.noInit.}: Fp[BN254_Snarks]
x1010011 {.noInit.}: Fp[BN254_Snarks]
x1011011 {.noInit.}: Fp[BN254_Snarks]
x1100001 {.noInit.}: Fp[BN254_Snarks]
x1110101 {.noInit.}: Fp[BN254_Snarks]
x10010001 {.noInit.}: Fp[BN254_Snarks]
x10010101 {.noInit.}: Fp[BN254_Snarks]
x10110101 {.noInit.}: Fp[BN254_Snarks]
x10111011 {.noInit.}: Fp[BN254_Snarks]
x11000001 {.noInit.}: Fp[BN254_Snarks]
x11000011 {.noInit.}: Fp[BN254_Snarks]
x11010011 {.noInit.}: Fp[BN254_Snarks]
x11100001 {.noInit.}: Fp[BN254_Snarks]
x11100011 {.noInit.}: Fp[BN254_Snarks]
x11100111 {.noInit.}: Fp[BN254_Snarks]
x10 .square(a)
x11 .prod(x10, a)
x101 .prod(x10, x11)
x110 .prod(x101, a)
x1000 .prod(x10, x110)
x1101 .prod(x101, x1000)
x10010 .prod(x101, x1101)
x10011 .prod(x10010, a)
x10100 .prod(x10011, a)
x10111 .prod(x11, x10100)
x11100 .prod(x101, x10111)
x100000 .prod(x1101, x10011)
x100011 .prod(x11, x100000)
x101011 .prod(x1000, x100011)
x101111 .prod(x10011, x11100)
x1000001 .prod(x10010, x101111)
x1010011 .prod(x10010, x1000001)
x1011011 .prod(x1000, x1010011)
x1100001 .prod(x110, x1011011)
x1110101 .prod(x10100, x1100001)
x10010001 .prod(x11100, x1110101)
x10010101 .prod(x100000, x1110101)
x10110101 .prod(x100000, x10010101)
x10111011 .prod(x110, x10110101)
x11000001 .prod(x110, x10111011)
x11000011 .prod(x10, x11000001)
x11010011 .prod(x10010, x11000001)
x11100001 .prod(x100000, x11000001)
x11100011 .prod(x10, x11100001)
x11100111 .prod(x110, x11100001) # 30 operations
# 30 + 27 = 57 operations
r.square(x11000001)
r.square_repeated(7)
r *= x10010001
r.square_repeated(10)
r *= x11100111
r.square_repeated(7)
# 57 + 19 = 76 operations
r *= x10111
r.square_repeated(9)
r *= x10011
r.square_repeated(7)
r *= x1101
# 76 + 33 = 109 operations
r.square_repeated(14)
r *= x1010011
r.square_repeated(9)
r *= x11100001
r.square_repeated(8)
# 109 + 18 = 127 operations
r *= x1000001
r.square_repeated(10)
r *= x1011011
r.square_repeated(5)
r *= x1101
# 127 + 34 = 161 operations
r.square_repeated(8)
r *= x11
r.square_repeated(12)
r *= x101011
r.square_repeated(12)
# 161 + 25 = 186 operations
r *= x10111011
r.square_repeated(8)
r *= x101111
r.square_repeated(14)
r *= x10110101
# 186 + 28 = 214
r.square_repeated(9)
r *= x10010001
r.square_repeated(5)
r *= x1101
r.square_repeated(12)
# 214 + 22 = 236
r *= x11100011
r.square_repeated(8)
r *= x10010101
r.square_repeated(11)
r *= x11010011
# 236 + 32 = 268
r.square_repeated(7)
r *= x1100001
r.square_repeated(11)
r *= x100011
r.square_repeated(12)
# 268 + 20 = 288
r *= x1011011
r.square_repeated(9)
r *= x11000011
r.square_repeated(8)
r *= x11100111
# 288 + 15 = 303
r.square_repeated(7)
r *= x1110101
r.square_repeated(6)
r *= x101

View File

@ -0,0 +1,107 @@
# 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
../config/[curves, type_bigint],
../towers,
../io/io_bigints,
../pairing/cyclotomic_fp12
# The bit count must be exact for the Miller loop
const BN254_Snarks_pairing_ate_param* = block:
# BN Miller loop is parametrized by 6u+2
BigInt[65+2].fromHex"0x19d797039be763ba8"
const BN254_Snarks_pairing_ate_param_isNeg* = false
const BN254_Snarks_pairing_finalexponent* = block:
# (p^12 - 1) / r
BigInt[2790].fromHex"0x2f4b6dc97020fddadf107d20bc842d43bf6369b1ff6a1c71015f3f7be2e1e30a73bb94fec0daf15466b2383a5d3ec3d15ad524d8f70c54efee1bd8c3b21377e563a09a1b705887e72eceaddea3790364a61f676baaf977870e88d5c6c8fef0781361e443ae77f5b63a2a2264487f2940a8b1ddb3d15062cd0fb2015dfc6668449aed3cc48a82d0d602d268c7daab6a41294c0cc4ebe5664568dfc50e1648a45a4a1e3a5195846a3ed011a337a02088ec80e0ebae8755cfe107acf3aafb40494e406f804216bb10cf430b0f37856b42db8dc5514724ee93dfb10826f0dd4a0364b9580291d2cd65664814fde37ca80bb4ea44eacc5e641bbadf423f9a2cbf813b8d145da90029baee7ddadda71c7f3811c4105262945bba1668c3be69a3c230974d83561841d766f9c9d570bb7fbe04c7e8a6c3c760c0de81def35692da361102b6b9b2b918837fa97896e84abb40a4efb7e54523a486964b64ca86f120"
func pow_u*(r: var Fp12[BN254_Snarks], a: Fp12[BN254_Snarks], invert = BN254_Snarks_pairing_ate_param_isNeg) =
## f^u with u the curve parameter
## For BN254_Snarks f^0x44e992b44a6909f1
when false:
cyclotomic_exp(
r, a,
BigInt[63].fromHex("0x44e992b44a6909f1"),
invert
)
else:
var # Hopefully the compiler optimizes away unused Fp12
# because those are huge
x10 {.noInit.}: Fp12[BN254_Snarks]
x11 {.noInit.}: Fp12[BN254_Snarks]
x100 {.noInit.}: Fp12[BN254_Snarks]
x110 {.noInit.}: Fp12[BN254_Snarks]
x1100 {.noInit.}: Fp12[BN254_Snarks]
x1111 {.noInit.}: Fp12[BN254_Snarks]
x10010 {.noInit.}: Fp12[BN254_Snarks]
x10110 {.noInit.}: Fp12[BN254_Snarks]
x11100 {.noInit.}: Fp12[BN254_Snarks]
x101110 {.noInit.}: Fp12[BN254_Snarks]
x1001010 {.noInit.}: Fp12[BN254_Snarks]
x1111000 {.noInit.}: Fp12[BN254_Snarks]
x10001110 {.noInit.}: Fp12[BN254_Snarks]
x10 .cyclotomic_square(a)
x11 .prod(x10, a)
x100 .prod(x11, a)
x110 .prod(x10, x100)
x1100 .cyclotomic_square(x110)
x1111 .prod(x11, x1100)
x10010 .prod(x11, x1111)
x10110 .prod(x100, x10010)
x11100 .prod(x110, x10110)
x101110 .prod(x10010, x11100)
x1001010 .prod(x11100, x101110)
x1111000 .prod(x101110, x1001010)
x10001110 .prod(x10110, x1111000)
var
i15 {.noInit.}: Fp12[BN254_Snarks]
i16 {.noInit.}: Fp12[BN254_Snarks]
i17 {.noInit.}: Fp12[BN254_Snarks]
i18 {.noInit.}: Fp12[BN254_Snarks]
i20 {.noInit.}: Fp12[BN254_Snarks]
i21 {.noInit.}: Fp12[BN254_Snarks]
i22 {.noInit.}: Fp12[BN254_Snarks]
i26 {.noInit.}: Fp12[BN254_Snarks]
i27 {.noInit.}: Fp12[BN254_Snarks]
i61 {.noInit.}: Fp12[BN254_Snarks]
i15.cyclotomic_square(x10001110)
i15 *= x1001010
i16.prod(x10001110, i15)
i17.prod(x1111, i16)
i18.prod(i16, i17)
i20.cyclotomic_square(i18)
i20 *= i17
i21.prod(x1111000, i20)
i22.prod(i15, i21)
i26.cyclotomic_square(i22)
i26.cyclotomic_square()
i26 *= i22
i26 *= i18
i27.prod(i22, i26)
i61.prod(i26, i27)
i61.cycl_sqr_repeated(17)
i61 *= i27
i61.cycl_sqr_repeated(14)
i61 *= i21
r = i61
r.cycl_sqr_repeated(16)
r *= i20
if invert:
r.cyclotomic_inv()

View File

@ -0,0 +1,96 @@
# 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
../config/curves,
../arithmetic/finite_fields
# ############################################################
#
# Specialized inversion for Secp256k1
#
# ############################################################
func inv_addchain*(r: var Fp[Secp256k1], a: Fp[Secp256k1]) {.used.}=
## We invert via Little Fermat's theorem
## a^(-1) ≡ a^(p-2) (mod p)
## with p = "0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F"
## We take advantage of the prime special form to hardcode
## the sequence of squarings and multiplications for the modular exponentiation
##
## See libsecp256k1
##
## The binary representation of (p - 2) has 5 blocks of 1s, with lengths in
## { 1, 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block:
## [1], [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223]
var
x2{.noInit.}: Fp[Secp256k1]
x3{.noInit.}: Fp[Secp256k1]
x6{.noInit.}: Fp[Secp256k1]
x9{.noInit.}: Fp[Secp256k1]
x11{.noInit.}: Fp[Secp256k1]
x22{.noInit.}: Fp[Secp256k1]
x44{.noInit.}: Fp[Secp256k1]
x88{.noInit.}: Fp[Secp256k1]
x176{.noInit.}: Fp[Secp256k1]
x220{.noInit.}: Fp[Secp256k1]
x223{.noInit.}: Fp[Secp256k1]
x2.square(a)
x2 *= a
x3.square(x2)
x3 *= a
x6 = x3
x6.square_repeated(3)
x6 *= x3
x9 = x6
x9.square_repeated(3)
x9 *= x3
x11 = x9
x11.square_repeated(2)
x11 *= x2
x22 = x11
x22.square_repeated(11)
x22 *= x11
x44 = x22
x44.square_repeated(22)
x44 *= x22
x88 = x44
x88.square_repeated(44)
x88 *= x44
x176 = x88
x88.square_repeated(88)
x176 *= x88
x220 = x176
x220.square_repeated(44)
x220 *= x44
x223 = x220
x223.square_repeated(3)
x223 *= x3
# The final result is then assembled using a sliding window over the blocks
r = x223
r.square_repeated(23)
r *= x22
r.square_repeated(5)
r *= a
r.square_repeated(3)
r *= x2
r.square_repeated(2)
r *= a

View 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
std/macros,
../config/curves,
./bls12_377_frobenius,
./bls12_381_frobenius,
./bn254_nogami_frobenius,
./bn254_snarks_frobenius
{.experimental: "dynamicBindSym".}
macro frobMapConst*(C: static Curve, coef, p_pow: static int): untyped =
## Access the field Frobenius map a -> a^(p^p_pow)
## Call with
## frobMapConst(Curve, coef, p_pow)
##
## With pow the
return nnkBracketExpr.newTree(
nnkBracketExpr.newTree(
bindSym($C & "_FrobeniusMapCoefficients"),
newLit(p_pow-1)
),
newLit coef
)
macro frobPsiConst*(C: static Curve, psipow, coefpow: static int): untyped =
return bindSym($C & "_FrobeniusPsi_psi" & $psipow & "_coef" & $coefpow)

View File

@ -0,0 +1,37 @@
# Constantine
# Copyright (c) 2018-2019 Status Research & Development GmbH
# Copyright (c) 2020-Present Mamy André-Ratsimbazafy
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import
std/macros,
../config/[curves, type_fp],
../towers,
./bls12_377_glv,
./bls12_381_glv,
# ./bn254_nogami_glv,
./bn254_snarks_glv
{.experimental: "dynamicBindSym".}
macro dispatch(C: static Curve, tag: static string, G: static string): untyped =
result = bindSym($C & "_" & tag & "_" & G)
template babai*(F: typedesc[Fp or Fp2]): untyped =
## Return the GLV Babai roundings vector
const G = if F is Fp: "G1"
else: "G2"
dispatch(F.C, "Babai", G)
template lattice*(F: typedesc[Fp or Fp2]): untyped =
## Returns the GLV Decomposition Lattice
const G = if F is Fp: "G1"
else: "G2"
dispatch(F.C, "Lattice", G)
macro getCubicRootOfUnity_mod_p*(C: static Curve): untyped =
## Get a non-trivial cubic root of unity (mod p) with p the prime field
result = bindSym($C & "_cubicRootOfUnity_mod_p")

View File

@ -0,0 +1,17 @@
# 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
./bls12_381_inversion,
./bn254_snarks_inversion,
./secp256k1_inversion
export
bls12_381_inversion,
bn254_snarks_inversion,
secp256k1_inversion

View File

@ -0,0 +1,23 @@
# Constantine
# Copyright (c) 2018-2019 Status Research & Development GmbH
# Copyright (c) 2020-Present Mamy André-Ratsimbazafy
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import
std/macros,
../config/curves,
./bls12_377_pairing,
./bls12_381_pairing,
./bn254_nogami_pairing,
./bn254_snarks_pairing
{.experimental: "dynamicBindSym".}
macro pairing*(C: static Curve, value: untyped): untyped =
## Get pairing related constants
return bindSym($C & "_pairing_" & $value)
export pow_x, pow_xdiv2, pow_u

View File

@ -0,0 +1,18 @@
# Constantine
# Copyright (c) 2018-2019 Status Research & Development GmbH
# Copyright (c) 2020-Present Mamy André-Ratsimbazafy
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import
std/macros,
../config/curves,
./bls12_377_square_root
{.experimental: "dynamicBindSym".}
macro tonelliShanks*(C: static Curve, value: untyped): untyped =
## Get Square Root via Tonelli-Shanks related constants
return bindSym($C & "_TonelliShanks_" & $value)

View File

@ -117,6 +117,12 @@ We use the complete addition law from Bos2014 for Jacobian coordinates, note tha
https://eprint.iacr.org/2014/130
https://www.imsc.res.in/~ecc14/slides/costello.pdf
- Efficient and Secure Algorithms for GLV-Based Scalar\
Multiplication and their Implementation\
on GLV-GLSCurves (Extended Version)\
Armando Faz-Hernández, Patrick Longa, Ana H. Sánchez, 2013\
https://eprint.iacr.org/2013/158.pdf
- Remote Timing Attacks are Still Practical\
Billy Bob Brumley and Nicola Tuveri\
https://eprint.iacr.org/2011/232

View File

@ -12,13 +12,13 @@ import
# Internal
../primitives,
../config/[common, curves, type_bigint],
../curves/zoo_glv,
../arithmetic,
../io/io_bigints,
../towers,
../isogeny/frobenius,
./ec_weierstrass_affine,
./ec_weierstrass_projective,
./ec_endomorphism_params
./ec_weierstrass_projective
# ############################################################
#
@ -33,6 +33,84 @@ import
# - GLV and GLS endomorphisms on G2 (Galbraith-Lin-Scott)
# - NAF recoding (windowed Non-Adjacent-Form)
# Decomposition into scalars -> miniscalars
# ----------------------------------------------------------------------------------------
type
MultiScalar[M, LengthInBits: static int] = array[M, BigInt[LengthInBits]]
## Decomposition of a secret scalar in multiple scalars
func decomposeEndo*[M, scalBits, L: static int](
miniScalars: var MultiScalar[M, L],
scalar: BigInt[scalBits],
F: typedesc[Fp or Fp2]
) =
## Decompose a secret scalar into M mini-scalars
## using a curve endomorphism(s) characteristics.
##
## A scalar decomposition might lead to negative miniscalar(s).
## For proper handling it requires either:
## 1. Negating it and then negating the corresponding curve point P
## 2. Adding an extra bit to the recoding, which will do the right thing™
##
## For implementation solution 1 is faster:
## - Double + Add is about 5000~8000 cycles on 6 64-bits limbs (BLS12-381)
## - Conditional negate is about 10 cycles per Fp, on G2 projective we have 3 (coords) * 2 (Fp2) * 10 (cycles) ~= 60 cycles
## We need to test the mini scalar, which is 65 bits so 2 Fp so about 2 cycles
## and negate it as well.
##
## However solution 1 seems to cause issues (TODO)
## with some of the BLS12-381 test cases (6 and 9)
## - 0x5668a2332db27199dcfb7cbdfca6317c2ff128db26d7df68483e0a095ec8e88f
## - 0x644dc62869683f0c93f38eaef2ba6912569dc91ec2806e46b4a3dd6a4421dad1
# Equal when no window or no negative handling, greater otherwise
static: doAssert L >= (scalBits + M - 1) div M + 1
const w = F.C.getCurveOrderBitwidth().wordsRequired()
when F is Fp:
var alphas{.noInit.}: (
BigInt[scalBits + babai(F)[0][0].bits],
BigInt[scalBits + babai(F)[1][0].bits]
)
else:
var alphas{.noInit.}: (
BigInt[scalBits + babai(F)[0][0].bits],
BigInt[scalBits + babai(F)[1][0].bits],
BigInt[scalBits + babai(F)[2][0].bits],
BigInt[scalBits + babai(F)[3][0].bits]
)
staticFor i, 0, M:
when bool babai(F)[i][0].isZero():
alphas[i].setZero()
else:
alphas[i].prod_high_words(babai(F)[i][0], scalar, w)
when babai(F)[i][1]:
# prod_high_words works like logical right shift
# When negative, we should add 1 to properly round toward -infinity
alphas[i] += SecretWord(1)
# We have k0 = s - 𝛼0 b00 - 𝛼1 b10 ... - 𝛼m bm0
# and kj = 0 - 𝛼j b0j - 𝛼1 b1j ... - 𝛼m bmj
var
k: array[M, BigInt[scalBits]] # zero-init required
alphaB {.noInit.}: BigInt[scalBits]
k[0] = scalar
staticFor miniScalarIdx, 0, M:
staticFor basisIdx, 0, M:
when not bool lattice(F)[basisIdx][miniScalarIdx][0].isZero():
when bool lattice(F)[basisIdx][miniScalarIdx][0].isOne():
alphaB.copyTruncatedFrom(alphas[basisIdx])
else:
alphaB.prod(alphas[basisIdx], lattice(F)[basisIdx][miniScalarIdx][0])
when lattice(F)[basisIdx][miniScalarIdx][1] xor babai(F)[basisIdx][1]:
k[miniScalarIdx] += alphaB
else:
k[miniScalarIdx] -= alphaB
miniScalars[miniScalarIdx].copyTruncatedFrom(k[miniScalarIdx])
# Secret scalar + dynamic point
# ----------------------------------------------------------------

View File

@ -1,289 +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
std/macros,
# Internal
../primitives,
../config/[common, curves, type_bigint],
../arithmetic,
../io/io_bigints,
../towers,
./ec_weierstrass_projective
# ############################################################
#
# Endomorphism acceleration decomposition parameters
# for Scalar Multiplication
#
# ############################################################
#
# TODO: cleanup, those should be derived in the config folder
# and stored in a constant
# or generated from sage into a config file read at compile-time
type
MultiScalar*[M, LengthInBits: static int] = array[M, BigInt[LengthInBits]]
## Decomposition of a secret scalar in multiple scalars
# BN254 Snarks G1
# ----------------------------------------------------------------------------------------
# Chapter 6.3.1 - Guide to Pairing-based Cryptography
const Lattice_BN254_Snarks_G1 = (
# Curve of order 254 -> mini scalars of size 127
# u = 0x44E992B44A6909F1
# (BigInt, isNeg)
((BigInt[64].fromHex"0x89d3256894d213e3", false), # 2u + 1
(BigInt[127].fromHex"0x6f4d8248eeb859fd0be4e1541221250b", false)), # 6u² + 4u + 1
((BigInt[127].fromHex"0x6f4d8248eeb859fc8211bbeb7d4f1128", false), # 6u² + 2u
(BigInt[64].fromHex"0x89d3256894d213e3", true)) # -2u - 1
)
const Babai_BN254_Snarks_G1 = (
# Vector for Babai rounding
# (BigInt, isNeg)
(BigInt[66].fromHex"0x2d91d232ec7e0b3d7", false), # (2u + 1) << 2^256 // r
(BigInt[130].fromHex"0x24ccef014a773d2d25398fd0300ff6565", false) # (6u² + 4u + 1) << 2^256 // r
)
# BLS12-377 G1
# ----------------------------------------------------------------------------------------
const Lattice_BLS12_377_G1 = (
# (BigInt, isNeg)
((BigInt[127].fromHex"0x452217cc900000010a11800000000000", false), # u² - 1
(BigInt[1].fromHex"0x1", true)), # -1
((BigInt[1].fromHex"0x1", false), # 1
(BigInt[127].fromHex"0x452217cc900000010a11800000000001", false)) # u²
)
const Babai_BLS12_377_G1 = (
# Vector for Babai rounding
# (BigInt, isNeg)
(BigInt[130].fromHex"0x3b3f7aa969fd371607f72ed32af90182c", false),
(BigInt[4].fromHex"0xd", false)
)
# BLS12-381 G1
# ----------------------------------------------------------------------------------------
const Lattice_BLS12_381_G1 = (
# (BigInt, isNeg)
((BigInt[128].fromHex"0xac45a4010001a40200000000ffffffff", false), # u² - 1
(BigInt[1].fromHex"0x1", true)), # -1
((BigInt[1].fromHex"0x1", false), # 1
(BigInt[128].fromHex"0xac45a4010001a4020000000100000000", false)) # u²
)
const Babai_BLS12_381_G1 = (
# Vector for Babai rounding
# (BigInt, isNeg)
(BigInt[129].fromHex"0x17c6becf1e01faadd63f6e522f6cfee30", false),
(BigInt[2].fromHex"0x2", false)
)
# BN254 Snarks G2
# ----------------------------------------------------------------------------------------
const Lattice_BN254_Snarks_G2 = (
# Curve of order 254 -> mini scalars of size 65
# x = 0x44E992B44A6909F1
# Value, isNeg
((BigInt[63].fromHex"0x44e992b44a6909f2", false), # x+1
(BigInt[63].fromHex"0x44e992b44a6909f1", false), # x
(BigInt[63].fromHex"0x44e992b44a6909f1", false), # x
(BigInt[64].fromHex"0x89d3256894d213e2", true)), # -2x
((BigInt[64].fromHex"0x89d3256894d213e3", false), # 2x+1
(BigInt[63].fromHex"0x44e992b44a6909f1", true), # -x
(BigInt[63].fromHex"0x44e992b44a6909f2", true), # -x-1
(BigInt[63].fromHex"0x44e992b44a6909f1", true)), # -x
((BigInt[64].fromHex"0x89d3256894d213e2", false), # 2x
(BigInt[64].fromHex"0x89d3256894d213e3", false), # 2x+1
(BigInt[64].fromHex"0x89d3256894d213e3", false), # 2x+1
(BigInt[64].fromHex"0x89d3256894d213e3", false)), # 2x+1
((BigInt[63].fromHex"0x44e992b44a6909f0", false), # x-1
(BigInt[65].fromHex"0x113a64ad129a427c6", false), # 4x+2
(BigInt[64].fromHex"0x89d3256894d213e1", true), # -2x+1
(BigInt[63].fromHex"0x44e992b44a6909f0", false)), # x-1
)
const Babai_BN254_Snarks_G2 = (
# Vector for Babai rounding
# Value, isNeg
(BigInt[128].fromHex"0xc444fab18d269b9dd0cb46fd51906254", false), # 2x²+3x+1 << 2^256 // r
(BigInt[193].fromHex"0x13d00631561b2572922df9f942d7d77c7001378f5ee78976d", false), # 3x³+8x²+x << 2^256 // r
(BigInt[192].fromhex"0x9e80318ab0d92b94916fcfca16bebbe436510546a93478ab", false), # 6x³+4x²+x << 2^256 // r
(BigInt[128].fromhex"0xc444fab18d269b9af7ae23ce89afae7d", true) # -2x²-x << 2^256 // r
)
# BLS12-377 G2
# ----------------------------------------------------------------------------------------
const Lattice_BLS12_377_G2 = (
# Curve of order 254 -> mini scalars of size 65
# x = -0xd201000000010000
# Value, isNeg
((BigInt[64].fromHex"0x8508c00000000001", true), # -x
(BigInt[1].fromHex"0x1", false), # 1
(BigInt[1].fromHex"0x0", false), # 0
(BigInt[1].fromHex"0x0", false)), # 0
((BigInt[1].fromHex"0x0", false), # 0
(BigInt[64].fromHex"0x8508c00000000001", true), # -x
(BigInt[1].fromHex"0x1", false), # 1
(BigInt[1].fromHex"0x0", false)), # 0
((BigInt[1].fromHex"0x0", false), # 0
(BigInt[1].fromHex"0x0", false), # 0
(BigInt[64].fromHex"0x8508c00000000001", true), # -x
(BigInt[1].fromHex"0x1", false)), # 1
((BigInt[1].fromHex"0x1", false), # 1
(BigInt[1].fromHex"0x0", false), # 0
(BigInt[1].fromHex"0x1", true), # -1
(BigInt[64].fromHex"0x8508c00000000001", true)) # -x
)
const Babai_BLS12_377_G2 = (
# Vector for Babai rounding
# Value, isNeg
(BigInt[193].fromHex"0x1eca0125755aed064f63abaff9084ce152979759b442f60d1", true),
(BigInt[130].fromHex"0x3b3f7aa969fd371607f72ed32af90181f", true),
(BigInt[67].fromhex"0x72030ba8ee9c06415", true),
(BigInt[1].fromhex"0x0", false)
)
# BLS12-381 G2
# ----------------------------------------------------------------------------------------
const Lattice_BLS12_381_G2 = (
# Curve of order 254 -> mini scalars of size 65
# x = -0xd201000000010000
# Value, isNeg
((BigInt[64].fromHex"0xd201000000010000", false), # -x
(BigInt[1].fromHex"0x1", false), # 1
(BigInt[1].fromHex"0x0", false), # 0
(BigInt[1].fromHex"0x0", false)), # 0
((BigInt[1].fromHex"0x0", false), # 0
(BigInt[64].fromHex"0xd201000000010000", false), # -x
(BigInt[1].fromHex"0x1", false), # 1
(BigInt[1].fromHex"0x0", false)), # 0
((BigInt[1].fromHex"0x0", false), # 0
(BigInt[1].fromHex"0x0", false), # 0
(BigInt[64].fromHex"0xd201000000010000", false), # -x
(BigInt[1].fromHex"0x1", false)), # 1
((BigInt[1].fromHex"0x1", false), # 1
(BigInt[1].fromHex"0x0", false), # 0
(BigInt[1].fromHex"0x1", true), # -1
(BigInt[64].fromHex"0xd201000000010000", false)) # -x
)
const Babai_BLS12_381_G2 = (
# Vector for Babai rounding
# Value, isNeg
(BigInt[193].fromHex"0x1381204ca56cd56b533cfcc0d3e76ec2892078a5e8573b29c", false),
(BigInt[129].fromHex"0x17c6becf1e01faadd63f6e522f6cfee2f", true),
(BigInt[65].fromhex"0x1cfbe4f7bd0027db0", false),
(BigInt[1].fromhex"0x0", false)
)
# Decomposition routine
# ----------------------------------------------------------------------------------------
{.experimental: "dynamicbindsym".}
macro dispatch(prefix: static string, C: static Curve, G: static string): untyped =
result = bindSym(prefix & $C & "_" & G)
template babai(F: typedesc[Fp or Fp2]): untyped =
const G = if F is Fp: "G1"
else: "G2"
dispatch("Babai_", F.C, G)
template lattice(F: typedesc[Fp or Fp2]): untyped =
const G = if F is Fp: "G1"
else: "G2"
dispatch("Lattice_", F.C, G)
func decomposeEndo*[M, scalBits, L: static int](
miniScalars: var MultiScalar[M, L],
scalar: BigInt[scalBits],
F: typedesc[Fp or Fp2]
) =
## Decompose a secret scalar into M mini-scalars
## using a curve endomorphism(s) characteristics.
##
## A scalar decomposition might lead to negative miniscalar(s).
## For proper handling it requires either:
## 1. Negating it and then negating the corresponding curve point P
## 2. Adding an extra bit to the recoding, which will do the right thing™
##
## For implementation solution 1 is faster:
## - Double + Add is about 5000~8000 cycles on 6 64-bits limbs (BLS12-381)
## - Conditional negate is about 10 cycles per Fp, on G2 projective we have 3 (coords) * 2 (Fp2) * 10 (cycles) ~= 60 cycles
## We need to test the mini scalar, which is 65 bits so 2 Fp so about 2 cycles
## and negate it as well.
##
## However solution 1 seems to cause issues (TODO)
## with some of the BLS12-381 test cases (6 and 9)
## - 0x5668a2332db27199dcfb7cbdfca6317c2ff128db26d7df68483e0a095ec8e88f
## - 0x644dc62869683f0c93f38eaef2ba6912569dc91ec2806e46b4a3dd6a4421dad1
# Equal when no window or no negative handling, greater otherwise
static: doAssert L >= (scalBits + M - 1) div M + 1
const w = F.C.getCurveOrderBitwidth().wordsRequired()
when F is Fp:
var alphas{.noInit.}: (
BigInt[scalBits + babai(F)[0][0].bits],
BigInt[scalBits + babai(F)[1][0].bits]
)
else:
var alphas{.noInit.}: (
BigInt[scalBits + babai(F)[0][0].bits],
BigInt[scalBits + babai(F)[1][0].bits],
BigInt[scalBits + babai(F)[2][0].bits],
BigInt[scalBits + babai(F)[3][0].bits]
)
staticFor i, 0, M:
when bool babai(F)[i][0].isZero():
alphas[i].setZero()
else:
alphas[i].prod_high_words(babai(F)[i][0], scalar, w)
when babai(F)[i][1]:
# prod_high_words works like logical right shift
# When negative, we should add 1 to properly round toward -infinity
alphas[i] += SecretWord(1)
# We have k0 = s - 𝛼0 b00 - 𝛼1 b10 ... - 𝛼m bm0
# and kj = 0 - 𝛼j b0j - 𝛼1 b1j ... - 𝛼m bmj
var
k: array[M, BigInt[scalBits]] # zero-init required
alphaB {.noInit.}: BigInt[scalBits]
k[0] = scalar
staticFor miniScalarIdx, 0, M:
staticFor basisIdx, 0, M:
when not bool lattice(F)[basisIdx][miniScalarIdx][0].isZero():
when bool lattice(F)[basisIdx][miniScalarIdx][0].isOne():
alphaB.copyTruncatedFrom(alphas[basisIdx])
else:
alphaB.prod(alphas[basisIdx], lattice(F)[basisIdx][miniScalarIdx][0])
when lattice(F)[basisIdx][miniScalarIdx][1] xor babai(F)[basisIdx][1]:
k[miniScalarIdx] += alphaB
else:
k[miniScalarIdx] -= alphaB
miniScalars[miniScalarIdx].copyTruncatedFrom(k[miniScalarIdx])

View File

@ -12,8 +12,6 @@ import
std/typetraits,
# Internal
./io_bigints, ./io_fields,
../config/curves,
../arithmetic/finite_fields,
../towers
# No exceptions allowed

View File

@ -8,9 +8,9 @@
import
std/macros,
../config/[common, curves],
../io/io_towers,
../towers, ../arithmetic
../arithmetic,
../towers,
../curves/zoo_frobenius
# Frobenius Map
# ------------------------------------------------------------
@ -66,331 +66,12 @@ template mulCheckSparse[Fp2](a: var Fp2, b: Fp2) =
# Frobenius map - on extension fields
# -----------------------------------------------------------------
# c = (SNR^((p-1)/6)^coef).
# Then for frobenius(2): c * conjugate(c)
# And for frobenius(3): c² * conjugate(c)
const FrobMapConst_BLS12_377 = [
# frobenius(1)
[Fp2[BLS12_377].fromHex( # SNR^((p-1)/6)^0
"0x1",
"0x0"
),
Fp2[BLS12_377].fromHex( # SNR^((p-1)/6)^1
"0x9a9975399c019633c1e30682567f915c8a45e0f94ebc8ec681bf34a3aa559db57668e558eb0188e938a9d1104f2031",
"0x0"
),
Fp2[BLS12_377].fromHex( # SNR^((p-1)/6)^2 = SNR^((p-1)/3)
"0x9b3af05dd14f6ec619aaf7d34594aabc5ed1347970dec00452217cc900000008508c00000000002",
"0x0"
),
Fp2[BLS12_377].fromHex( # SNR^((p-1)/6)^3 = SNR^((p-1)/2)
"0x1680a40796537cac0c534db1a79beb1400398f50ad1dec1bce649cf436b0f6299588459bff27d8e6e76d5ecf1391c63",
"0x0"
),
Fp2[BLS12_377].fromHex( # SNR^((p-1)/6)^4 = SNR^(2(p-1)/3)
"0x9b3af05dd14f6ec619aaf7d34594aabc5ed1347970dec00452217cc900000008508c00000000001",
"0x0"
),
Fp2[BLS12_377].fromHex( # SNR^((p-1)/6)^5
"0xcd70cb3fc936348d0351d498233f1fe379531411832232f6648a9a9fc0b9c4e3e21b7467077c05853e2c1be0e9fc32",
"0x0"
)],
# frobenius(2)
[Fp2[BLS12_377].fromHex( # norm(SNR)^((p-1)/6)^1
"0x1",
"0x0"
),
Fp2[BLS12_377].fromHex( # norm(SNR)^((p-1)/6)^2
"0x9b3af05dd14f6ec619aaf7d34594aabc5ed1347970dec00452217cc900000008508c00000000002",
"0x0"
),
Fp2[BLS12_377].fromHex(
"0x9b3af05dd14f6ec619aaf7d34594aabc5ed1347970dec00452217cc900000008508c00000000001",
"0x0"
),
Fp2[BLS12_377].fromHex(
"0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d44300000008508c00000000000",
"0x0"
),
Fp2[BLS12_377].fromHex(
"0x1ae3a4617c510eabc8756ba8f8c524eb8882a75cc9bc8e359064ee822fb5bffd1e945779fffffffffffffffffffffff",
"0x0"
),
Fp2[BLS12_377].fromHex(
"0x1ae3a4617c510eabc8756ba8f8c524eb8882a75cc9bc8e359064ee822fb5bffd1e94577a00000000000000000000000",
"0x0"
)],
# frobenius(3)
[Fp2[BLS12_377].fromHex(
"0x1",
"0x0"
),
Fp2[BLS12_377].fromHex(
"0x1680a40796537cac0c534db1a79beb1400398f50ad1dec1bce649cf436b0f6299588459bff27d8e6e76d5ecf1391c63",
"0x0"
),
Fp2[BLS12_377].fromHex(
"0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d44300000008508c00000000000",
"0x0"
),
Fp2[BLS12_377].fromHex(
"0x4630059e5fd9200575d0e552278a89da1f40fdf62334cd620d1860769e389d7db2d8ea700d82721691ea130ec6e39e",
"0x0"
),
Fp2[BLS12_377].fromHex(
"0x1",
"0x0"
),
Fp2[BLS12_377].fromHex(
"0x1680a40796537cac0c534db1a79beb1400398f50ad1dec1bce649cf436b0f6299588459bff27d8e6e76d5ecf1391c63",
"0x0"
)]]
# c = (SNR^((p-1)/6)^coef).
# Then for frobenius(2): c * conjugate(c)
# And for frobenius(3): c² * conjugate(c)
const FrobMapConst_BLS12_381 = [
# frobenius(1)
[Fp2[BLS12_381].fromHex( # SNR^((p-1)/6)^0
"0x1",
"0x0"
),
Fp2[BLS12_381].fromHex( # SNR^((p-1)/6)^1
"0x1904d3bf02bb0667c231beb4202c0d1f0fd603fd3cbd5f4f7b2443d784bab9c4f67ea53d63e7813d8d0775ed92235fb8",
"0xfc3e2b36c4e03288e9e902231f9fb854a14787b6c7b36fec0c8ec971f63c5f282d5ac14d6c7ec22cf78a126ddc4af3"
),
Fp2[BLS12_381].fromHex( # SNR^((p-1)/6)^2 = SNR^((p-1)/3)
"0x0",
"0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac"
),
Fp2[BLS12_381].fromHex( # SNR^((p-1)/6)^3 = SNR^((p-1)/2)
"0x6af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09",
"0x6af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09"
),
Fp2[BLS12_381].fromHex( # SNR^((p-1)/6)^4 = SNR^(2(p-1)/3)
"0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaad",
"0x0"
),
Fp2[BLS12_381].fromHex( # SNR^((p-1)/6)^5
"0x5b2cfd9013a5fd8df47fa6b48b1e045f39816240c0b8fee8beadf4d8e9c0566c63a3e6e257f87329b18fae980078116",
"0x144e4211384586c16bd3ad4afa99cc9170df3560e77982d0db45f3536814f0bd5871c1908bd478cd1ee605167ff82995"
)],
# frobenius(2)
[Fp2[BLS12_381].fromHex( # norm(SNR)^((p-1)/6)^1
"0x1",
"0x0"
),
Fp2[BLS12_381].fromHex( # norm(SNR)^((p-1)/6)^2
"0x5f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffeffff",
"0x0"
),
Fp2[BLS12_381].fromHex(
"0x5f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe",
"0x0"
),
Fp2[BLS12_381].fromHex(
"0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa",
"0x0"
),
Fp2[BLS12_381].fromHex(
"0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac",
"0x0"
),
Fp2[BLS12_381].fromHex(
"0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaad",
"0x0"
)],
# frobenius(3)
[Fp2[BLS12_381].fromHex(
"0x1",
"0x0"
),
Fp2[BLS12_381].fromHex(
"0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2",
"0x6af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09"
),
Fp2[BLS12_381].fromHex(
"0x0",
"0x1"
),
Fp2[BLS12_381].fromHex(
"0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2",
"0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2"
),
Fp2[BLS12_381].fromHex(
"0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa",
"0x0"
),
Fp2[BLS12_381].fromHex(
"0x6af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09",
"0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2"
)]]
const FrobMapConst_BN254_Nogami = [
# frobenius(1)
[Fp2[BN254_Nogami].fromHex( # SNR^((p-1)/6)^0
"0x1",
"0x0"
),
Fp2[BN254_Nogami].fromHex( # SNR^((p-1)/6)^1
"0x1b377619212e7c8cb6499b50a846953f850974924d3f77c2e17de6c06f2a6de9",
"0x9ebee691ed1837503eab22f57b96ac8dc178b6db2c08850c582193f90d5922a"
),
Fp2[BN254_Nogami].fromHex( # SNR^((p-1)/6)^2 = SNR^((p-1)/3)
"0x0",
"0x25236482400000017080eb4000000006181800000000000cd98000000000000b"
),
Fp2[BN254_Nogami].fromHex( # SNR^((p-1)/6)^3 = SNR^((p-1)/2)
"0x23dfc9d1a39f4db8c69b87a8848aa075a7333a0e62d78cbf4b1b8eeae58b81c5",
"0x23dfc9d1a39f4db8c69b87a8848aa075a7333a0e62d78cbf4b1b8eeae58b81c5"
),
Fp2[BN254_Nogami].fromHex( # SNR^((p-1)/6)^4 = SNR^(2(p-1)/3)
"0x25236482400000017080eb4000000006181800000000000cd98000000000000c",
"0x0"
),
Fp2[BN254_Nogami].fromHex( # SNR^((p-1)/6)^5
"0x19f3db6884cdca43c2b0d5792cd135accb1baea0b017046e859975ab54b5ef9b",
"0xb2f8919bb3235bdf7837806d32eca5b9605515f4fe8fba521668a54ab4a1078"
)],
# frobenius(2)
[Fp2[BN254_Nogami].fromHex( # norm(SNR)^((p-1)/6)^1
"0x1",
"0x0"
),
Fp2[BN254_Nogami].fromHex( # norm(SNR)^((p-1)/6)^2
"0x49b36240000000024909000000000006cd80000000000008",
"0x0"
),
Fp2[BN254_Nogami].fromHex(
"0x49b36240000000024909000000000006cd80000000000007",
"0x0"
),
Fp2[BN254_Nogami].fromHex(
"0x2523648240000001ba344d80000000086121000000000013a700000000000012",
"0x0"
),
Fp2[BN254_Nogami].fromHex(
"0x25236482400000017080eb4000000006181800000000000cd98000000000000b",
"0x0"
),
Fp2[BN254_Nogami].fromHex(
"0x25236482400000017080eb4000000006181800000000000cd98000000000000c",
"0x0"
)],
# frobenius(3)
[Fp2[BN254_Nogami].fromHex(
"0x1",
"0x0"
),
Fp2[BN254_Nogami].fromHex(
"0x1439ab09c60b248f398c5d77b755f92b9edc5f19d2873545be471151a747e4e",
"0x23dfc9d1a39f4db8c69b87a8848aa075a7333a0e62d78cbf4b1b8eeae58b81c5"
),
Fp2[BN254_Nogami].fromHex(
"0x0",
"0x1"
),
Fp2[BN254_Nogami].fromHex(
"0x1439ab09c60b248f398c5d77b755f92b9edc5f19d2873545be471151a747e4e",
"0x1439ab09c60b248f398c5d77b755f92b9edc5f19d2873545be471151a747e4e"
),
Fp2[BN254_Nogami].fromHex(
"0x2523648240000001ba344d80000000086121000000000013a700000000000012",
"0x0"
),
Fp2[BN254_Nogami].fromHex(
"0x23dfc9d1a39f4db8c69b87a8848aa075a7333a0e62d78cbf4b1b8eeae58b81c5",
"0x1439ab09c60b248f398c5d77b755f92b9edc5f19d2873545be471151a747e4e"
)]]
const FrobMapConst_BN254_Snarks = [
# frobenius(1)
[Fp2[BN254_Snarks].fromHex( # SNR^((p-1)/6)^0
"0x1",
"0x0"
),
Fp2[BN254_Snarks].fromHex( # SNR^((p-1)/6)^1
"0x1284b71c2865a7dfe8b99fdd76e68b605c521e08292f2176d60b35dadcc9e470",
"0x246996f3b4fae7e6a6327cfe12150b8e747992778eeec7e5ca5cf05f80f362ac"
),
Fp2[BN254_Snarks].fromHex( # SNR^((p-1)/6)^2 = SNR^((p-1)/3)
"0x2fb347984f7911f74c0bec3cf559b143b78cc310c2c3330c99e39557176f553d",
"0x16c9e55061ebae204ba4cc8bd75a079432ae2a1d0b7c9dce1665d51c640fcba2"
),
Fp2[BN254_Snarks].fromHex( # SNR^((p-1)/6)^3 = SNR^((p-1)/2)
"0x63cf305489af5dcdc5ec698b6e2f9b9dbaae0eda9c95998dc54014671a0135a",
"0x7c03cbcac41049a0704b5a7ec796f2b21807dc98fa25bd282d37f632623b0e3"
),
Fp2[BN254_Snarks].fromHex( # SNR^((p-1)/6)^4 = SNR^(2(p-1)/3)
"0x5b54f5e64eea80180f3c0b75a181e84d33365f7be94ec72848a1f55921ea762",
"0x2c145edbe7fd8aee9f3a80b03b0b1c923685d2ea1bdec763c13b4711cd2b8126"
),
Fp2[BN254_Snarks].fromHex( # SNR^((p-1)/6)^5
"0x183c1e74f798649e93a3661a4353ff4425c459b55aa1bd32ea2c810eab7692f",
"0x12acf2ca76fd0675a27fb246c7729f7db080cb99678e2ac024c6b8ee6e0c2c4b"
)],
# frobenius(2)
[Fp2[BN254_Snarks].fromHex( # norm(SNR)^((p-1)/6)^1
"0x1",
"0x0"
),
Fp2[BN254_Snarks].fromHex( # norm(SNR)^((p-1)/6)^2
"0x30644e72e131a0295e6dd9e7e0acccb0c28f069fbb966e3de4bd44e5607cfd49",
"0x0"
),
Fp2[BN254_Snarks].fromHex(
"0x30644e72e131a0295e6dd9e7e0acccb0c28f069fbb966e3de4bd44e5607cfd48",
"0x0"
),
Fp2[BN254_Snarks].fromHex(
"0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd46",
"0x0"
),
Fp2[BN254_Snarks].fromHex(
"0x59e26bcea0d48bacd4f263f1acdb5c4f5763473177fffffe",
"0x0"
),
Fp2[BN254_Snarks].fromHex(
"0x59e26bcea0d48bacd4f263f1acdb5c4f5763473177ffffff",
"0x0"
)],
# frobenius(3)
[Fp2[BN254_Snarks].fromHex(
"0x1",
"0x0"
),
Fp2[BN254_Snarks].fromHex(
"0x19dc81cfcc82e4bbefe9608cd0acaa90894cb38dbe55d24ae86f7d391ed4a67f",
"0xabf8b60be77d7306cbeee33576139d7f03a5e397d439ec7694aa2bf4c0c101"
),
Fp2[BN254_Snarks].fromHex(
"0x856e078b755ef0abaff1c77959f25ac805ffd3d5d6942d37b746ee87bdcfb6d",
"0x4f1de41b3d1766fa9f30e6dec26094f0fdf31bf98ff2631380cab2baaa586de"
),
Fp2[BN254_Snarks].fromHex(
"0x2a275b6d9896aa4cdbf17f1dca9e5ea3bbd689a3bea870f45fcc8ad066dce9ed",
"0x28a411b634f09b8fb14b900e9507e9327600ecc7d8cf6ebab94d0cb3b2594c64"
),
Fp2[BN254_Snarks].fromHex(
"0xbc58c6611c08dab19bee0f7b5b2444ee633094575b06bcb0e1a92bc3ccbf066",
"0x23d5e999e1910a12feb0f6ef0cd21d04a44a9e08737f96e55fe3ed9d730c239f"
),
Fp2[BN254_Snarks].fromHex(
"0x13c49044952c0905711699fa3b4d3f692ed68098967c84a5ebde847076261b43",
"0x16db366a59b1dd0b9fb1b2282a48633d3e2ddaea200280211f25041384282499"
)]]
{.experimental: "dynamicBindSym".}
macro frobMapConst(C: static Curve): untyped =
return bindSym("FrobMapConst_" & $C)
func frobenius_map*[C](r: var Fp4[C], a: Fp4[C], k: static int = 1) {.inline.} =
## Computes a^(p^k)
## The p-power frobenius automorphism on 𝔽p4
r.c0.frobenius_map(a.c0, k)
r.c1.frobenius_map(a.c1, k)
r.c1.mulCheckSparse frobMapConst(C)[k-1][3]
r.c1.mulCheckSparse frobMapConst(C, 3, k)
func frobenius_map*[C](r: var Fp6[C], a: Fp6[C], k: static int = 1) {.inline.} =
## Computes a^(p^k)
@ -398,8 +79,8 @@ func frobenius_map*[C](r: var Fp6[C], a: Fp6[C], k: static int = 1) {.inline.} =
r.c0.frobenius_map(a.c0, k)
r.c1.frobenius_map(a.c1, k)
r.c2.frobenius_map(a.c2, k)
r.c1.mulCheckSparse frobMapConst(C)[k-1][2]
r.c2.mulCheckSparse frobMapConst(C)[k-1][4]
r.c1.mulCheckSparse frobMapConst(C, 2, k)
r.c2.mulCheckSparse frobMapConst(C, 4, k)
func frobenius_map*[C](r: var Fp12[C], a: Fp12[C], k: static int = 1) {.inline.} =
## Computes a^(p^k)
@ -409,108 +90,20 @@ func frobenius_map*[C](r: var Fp12[C], a: Fp12[C], k: static int = 1) {.inline.}
for r_fp2, a_fp2 in fields(r_fp4, a_fp4):
r_fp2.frobenius_map(a_fp2, k)
r.c0.c0.mulCheckSparse frobMapConst(C)[k-1][0]
r.c0.c1.mulCheckSparse frobMapConst(C)[k-1][3]
r.c1.c0.mulCheckSparse frobMapConst(C)[k-1][1]
r.c1.c1.mulCheckSparse frobMapConst(C)[k-1][4]
r.c2.c0.mulCheckSparse frobMapConst(C)[k-1][2]
r.c2.c1.mulCheckSparse frobMapConst(C)[k-1][5]
r.c0.c0.mulCheckSparse frobMapConst(C, 0, k)
r.c0.c1.mulCheckSparse frobMapConst(C, 3, k)
r.c1.c0.mulCheckSparse frobMapConst(C, 1, k)
r.c1.c1.mulCheckSparse frobMapConst(C, 4, k)
r.c2.c0.mulCheckSparse frobMapConst(C, 2, k)
r.c2.c1.mulCheckSparse frobMapConst(C, 5, k)
# ψ (Psi) - Untwist-Frobenius-Twist Endomorphisms on twisted curves
# -----------------------------------------------------------------
# TODO: generate those constants via Sage in a Json file
# and parse at compile-time
# Constants:
# Assuming embedding degree of 12 and a sextic twist
# with SNR the sextic non-residue
#
# BN254_Snarks is a D-Twist: SNR^((p-1)/6)
const FrobPsiConst_BN254_Snarks_psi1_coef1 = Fp2[BN254_Snarks].fromHex(
"0x1284b71c2865a7dfe8b99fdd76e68b605c521e08292f2176d60b35dadcc9e470",
"0x246996f3b4fae7e6a6327cfe12150b8e747992778eeec7e5ca5cf05f80f362ac"
)
# SNR^((p-1)/3)
const FrobPsiConst_BN254_Snarks_psi1_coef2 = Fp2[BN254_Snarks].fromHex(
"0x2fb347984f7911f74c0bec3cf559b143b78cc310c2c3330c99e39557176f553d",
"0x16c9e55061ebae204ba4cc8bd75a079432ae2a1d0b7c9dce1665d51c640fcba2"
)
# SNR^((p-1)/2)
const FrobPsiConst_BN254_Snarks_psi1_coef3 = Fp2[BN254_Snarks].fromHex(
"0x63cf305489af5dcdc5ec698b6e2f9b9dbaae0eda9c95998dc54014671a0135a",
"0x7c03cbcac41049a0704b5a7ec796f2b21807dc98fa25bd282d37f632623b0e3"
)
# norm(SNR)^((p-1)/3)
const FrobPsiConst_BN254_Snarks_psi2_coef2 = Fp2[BN254_Snarks].fromHex(
"0x30644e72e131a0295e6dd9e7e0acccb0c28f069fbb966e3de4bd44e5607cfd48",
"0x0"
)
# BN254_Nogami is a D-Twist: SNR^((p-1)/6)
const FrobPsiConst_BN254_Nogami_psi1_coef1 = Fp2[BN254_Nogami].fromHex(
"0x1b377619212e7c8cb6499b50a846953f850974924d3f77c2e17de6c06f2a6de9",
"0x9ebee691ed1837503eab22f57b96ac8dc178b6db2c08850c582193f90d5922a"
)
# SNR^((p-1)/3)
const FrobPsiConst_BN254_Nogami_psi1_coef2 = Fp2[BN254_Nogami].fromHex(
"0x0",
"0x25236482400000017080eb4000000006181800000000000cd98000000000000b"
)
# SNR^((p-1)/2)
const FrobPsiConst_BN254_Nogami_psi1_coef3 = Fp2[BN254_Nogami].fromHex(
"0x23dfc9d1a39f4db8c69b87a8848aa075a7333a0e62d78cbf4b1b8eeae58b81c5",
"0x23dfc9d1a39f4db8c69b87a8848aa075a7333a0e62d78cbf4b1b8eeae58b81c5"
)
# norm(SNR)^((p-1)/3)
const FrobPsiConst_BN254_Nogami_psi2_coef2 = Fp2[BN254_Nogami].fromHex(
"0x49b36240000000024909000000000006cd80000000000007",
"0x0"
)
# BLS12_377 is a D-Twist: SNR^((p-1)/6)
const FrobPsiConst_BLS12_377_psi1_coef1 = Fp2[BLS12_377].fromHex(
"0x9a9975399c019633c1e30682567f915c8a45e0f94ebc8ec681bf34a3aa559db57668e558eb0188e938a9d1104f2031",
"0x0"
)
# SNR^((p-1)/3)
const FrobPsiConst_BLS12_377_psi1_coef2 = Fp2[BLS12_377].fromHex(
"0x9b3af05dd14f6ec619aaf7d34594aabc5ed1347970dec00452217cc900000008508c00000000002",
"0x0"
)
# SNR^((p-1)/2)
const FrobPsiConst_BLS12_377_psi1_coef3 = Fp2[BLS12_377].fromHex(
"0x1680a40796537cac0c534db1a79beb1400398f50ad1dec1bce649cf436b0f6299588459bff27d8e6e76d5ecf1391c63",
"0x0"
)
# norm(SNR)^((p-1)/3)
const FrobPsiConst_BLS12_377_psi2_coef2 = Fp2[BLS12_377].fromHex(
"0x9b3af05dd14f6ec619aaf7d34594aabc5ed1347970dec00452217cc900000008508c00000000001",
"0x0"
)
# BLS12_381 is a M-twist: (1/SNR)^((p-1)/6)
const FrobPsiConst_BLS12_381_psi1_coef1 = Fp2[BLS12_381].fromHex(
"0x5b2cfd9013a5fd8df47fa6b48b1e045f39816240c0b8fee8beadf4d8e9c0566c63a3e6e257f87329b18fae980078116",
"0x5b2cfd9013a5fd8df47fa6b48b1e045f39816240c0b8fee8beadf4d8e9c0566c63a3e6e257f87329b18fae980078116"
)
# (1/SNR)^((p-1)/3)
const FrobPsiConst_BLS12_381_psi1_coef2 = Fp2[BLS12_381].fromHex(
"0x0",
"0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaad"
)
# (1/SNR)^((p-1)/2)
const FrobPsiConst_BLS12_381_psi1_coef3 = Fp2[BLS12_381].fromHex(
"0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2",
"0x6af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09"
)
# norm(SNR)^((p-1)/3)
const FrobPsiConst_BLS12_381_psi2_coef2 = Fp2[BLS12_381].fromHex(
"0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac",
"0x0"
)
macro frobPsiConst(C: static Curve, psipow, coefpow: static int): untyped =
return bindSym("FrobPsiConst_" & $C & "_psi" & $psipow & "_coef" & $coefpow)
func frobenius_psi*[PointG2](r: var PointG2, P: PointG2) =
## "Untwist-Frobenius-Twist" endomorphism

View File

@ -225,6 +225,11 @@ func cyclotomic_square*[C](a: var Fp12[C]) =
else:
{.error: "Not implemented".}
func cycl_sqr_repeated*(f: var Fp12, num: int) {.inline.} =
## Repeated cyclotomic squarings
for _ in 0 ..< num:
f.cyclotomic_square()
iterator unpack(scalarByte: byte): bool =
yield bool((scalarByte and 0b10000000) shr 7)
yield bool((scalarByte and 0b01000000) shr 6)

View File

@ -7,12 +7,8 @@
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import
std/macros,
../primitives,
../config/[common, curves],
../arithmetic,
../config/[curves, type_fp],
../towers,
../io/io_bigints,
../elliptic/[
ec_weierstrass_affine,
ec_weierstrass_projective
@ -20,7 +16,8 @@ import
../isogeny/frobenius,
./lines_projective,
./mul_fp12_by_lines,
./cyclotomic_fp12
./cyclotomic_fp12,
../curves/zoo_pairings
# ############################################################
#
@ -45,41 +42,10 @@ import
# Craig Costello, Tanja Lange, and Michael Naehrig, 2009
# https://eprint.iacr.org/2009/615.pdf
# TODO: should be part of curve parameters
# The bit count must be exact for the Miller loop
const BLS12_377_ate_param = block:
# BLS Miller loop is parametrized by u
BigInt[64+1].fromHex("0x8508c00000000001") # +1 so that we can take *3 and NAF encode it
const BLS12_377_ate_param_isNeg = false
const BLS12_381_ate_param = block:
# BLS Miller loop is parametrized by u
BigInt[64+2].fromHex("0xd201000000010000") # +2 so that we can take *3 and NAF encode it
const BLS12_381_ate_param_isNeg = true
# Generic slow pairing implementation
# Generic pairing implementation
# ----------------------------------------------------------------
const BLS12_377_finalexponent = block:
# (p^12 - 1) / r
# BigInt[4269].fromHex"0x1b2ff68c1abdc48ab4f04ed12cc8f9b2f161b41c7eb8865b9ad3c9bb0571dd94c6bde66548dc13624d9d741024ceb315f46a89cc2482605eb6afc6d8977e5e2ccbec348dd362d59ec2b5bc62a1b467ae44572215548abc98bb4193886ed89cceaedd0221aba84fb33e5584ac29619a87a00c315178155496857c995eab4a8a9af95f4015db27955ae408d6927d0ab37d52f3917c4ddec88f8159f7bcba7eb65f1aae4eeb4e70cb20227159c08a7fdfea9b62bb308918eac3202569dd1bcdd86b431e3646356fc3fb79f89b30775e006993adb629586b6c874b7688f86f11ef7ad94a40eb020da3c532b317232fa56dc564637b331a8e8832eab84269f00b506602c8594b7f7da5a5d8d851fff6ab1d38a354fc8e0b8958e2a9e5ce2d7e50ec36d761d9505fe5e1f317257e2df2952fcd4c93b85278c20488b4ccaee94db3fec1ce8283473e4b493843fa73abe99af8bafce29170b2b863b9513b5a47312991f60c5a4f6872b5d574212bf00d797c0bea3c0f7dfd748e63679fda9b1c50f2df74de38f38e004ae0df997a10db31d209cacbf58ba0678bfe7cd0985bc43258d72d8d5106c21635ae1e527eb01fca3032d50d97756ec9ee756eaba7f21652a808a4e2539e838ef7ec4b178b29e3b976c46bd0ecdd32c1fb75e6e0aef2d8b5661f595a98023f3520381aba8da6cce785dbb0a0bba025478d75ee749619cdb7c42a21098ece86a00c6c2046c1e00000063c69000000000000"
# (p^12 - 1) / r * 3
BigInt[4271].fromHex"0x518fe3a450394da01ed0ec73865aed18d4251c557c299312d07b5d31105598be5439b32fda943a26e8d85c306e6c1941dd3f9d646d87211c240f5489c67b1a8663c49da97a2880dc48213527e51d370acd05663ffda035ca31c4ba994c89d66c0c97066502f8ef19bb008e047c24cf96e02493f4683ffdc39075cc1c01df9fd0ec1dc0419176c010ac1a83b777201a77f8dab474e99c59ae840de7362f7c231d500aecc1eb52616067540d419f7f9fbfd22831919b4ac04960703d9753698941c95aa2d2a04f4bf26de9d191661a013cbb09227c09424595e2639ae94d35ce708bdec2c10628eb4f981945698ef049502d2a71994fab9898c028c73dd021f13208590be27e78f0f18a88f5ffe40157a9e9fef5aa229c0aa7fdb16a887af2c4a486258bf11fb1a5d945707a89d7bf8f67e5bb28f76a460d9a1e660cbbe91bfc456b8789d5bae1dba8cbef5b03bcd0ea30f6a7b45218292b2bf3b20ed5937cb5e2250eee395821805c6383d0286c7423beb42e79f85dab2a36df8fd154f2d89e5e9aaadaaa00e0a29ecc6e329195761d6063e0a2e136a3fb7671c9134c970a8588a7f3144642a10a5af77c105f5e90987f28c6604c5dcb604c02f7d642f7f819eea6fadb8aace7c4e146a17dab2c644d4372c6979845f261b4a20cd88a20325e0c0fc806bd9f60a8502fa8f466b6919311e232e06fd6a861cb5dc24d69274c7e631cac6b93e0254460d445a0000012b53b000000000000"
const BLS12_381_finalexponent = block:
# (p^12 - 1) / r
# BigInt[4314].fromHex"0x2ee1db5dcc825b7e1bda9c0496a1c0a89ee0193d4977b3f7d4507d07363baa13f8d14a917848517badc3a43d1073776ab353f2c30698e8cc7deada9c0aadff5e9cfee9a074e43b9a660835cc872ee83ff3a0f0f1c0ad0d6106feaf4e347aa68ad49466fa927e7bb9375331807a0dce2630d9aa4b113f414386b0e8819328148978e2b0dd39099b86e1ab656d2670d93e4d7acdd350da5359bc73ab61a0c5bf24c374693c49f570bcd2b01f3077ffb10bf24dde41064837f27611212596bc293c8d4c01f25118790f4684d0b9c40a68eb74bb22a40ee7169cdc1041296532fef459f12438dfc8e2886ef965e61a474c5c85b0129127a1b5ad0463434724538411d1676a53b5a62eb34c05739334f46c02c3f0bd0c55d3109cd15948d0a1fad20044ce6ad4c6bec3ec03ef19592004cedd556952c6d8823b19dadd7c2498345c6e5308f1c511291097db60b1749bf9b71a9f9e0100418a3ef0bc627751bbd81367066bca6a4c1b6dcfc5cceb73fc56947a403577dfa9e13c24ea820b09c1d9f7c31759c3635de3f7a3639991708e88adce88177456c49637fd7961be1a4c7e79fb02faa732e2f3ec2bea83d196283313492caa9d4aff1c910e9622d2a73f62537f2701aaef6539314043f7bbce5b78c7869aeb2181a67e49eeed2161daf3f881bd88592d767f67c4717489119226c2f011d4cab803e9d71650a6f80698e2f8491d12191a04406fbc8fbd5f48925f98630e68bfb24c0bcb9b55df57510"
# (p^12 - 1) / r * 3
BigInt[4316].fromHex"0x8ca592196587127a538fd40dc3e541f9dca04bb7dc671be77cf17715a2b2fe3bea73dfb468d8f473094aecb7315a664019fbd84913caba6579c08fd42009fe1bd6fcbce15eacb2cf3218a165958cb8bfdae2d2d54207282314fc0dea9d6ff3a07dbd34efb77b732ba5f994816e296a72928cfee133bdc3ca9412b984b9783d9c6aa81297ab1cd294a502304773528bbae8706979f28efa0d355b0224e2513d6e4a5d3bb4dde0523678105d9167ff1323d6e99ac312d8a7d762336370c4347bb5a7e405d6f3496b2dd38e722d4c1f3ac25e3167ec2cb543d69430c37c2f98fcdd0dd36caa9f5aa7994cec31b24ed5e515911037b376e521070d29c9d56cfa8c3574363efb20f28c19e4105ab99edd44084bd23725017931d6740bda71e5f07600ce6b407e543c4bc40bcd4c0b600e6c98003bf8548986b14d9098746dc89d154af91ad54f337b31c79222145dd3ed254fdeda0300c49ebcd2352765f533883a3513435f3ee452496f5166c25bf503bd6ec0a0679efda3b46ebf86211d458de749460d4a2a19abe6ea2accb451ab9a096b98465d044dc2a7f86c253a4ee57b6df108eff598a8dbc483bf8b74c2789939db85ffd7e0fd55b32bc26877f5be26fa7d750500ce2fab93c0cbe7336b126a5693d0c16484f37addccc7642590dbe98538990b88637e374d545d9b34b67448d0357e60280bbd8542f1f4e813caa8e8db57364b4e0cc14f35af381dd9b71ec9292b3a3f16e42362d2019e05f30"
{.experimental: "dynamicBindSym".}
macro get(C: static Curve, value: untyped): untyped =
return bindSym($C & "_" & $value)
func millerLoopGenericBLS12*[C: static Curve](
func millerLoopGenericBLS12*[C](
f: var Fp12[C],
P: ECP_SWei_Aff[Fp[C]],
Q: ECP_SWei_Aff[Fp2[C]]
@ -129,8 +95,8 @@ func millerLoopGenericBLS12*[C: static Curve](
else:
f.mul_sparse_by_line_xy000z(line)
template u: untyped = C.get(ate_param)
let u3 = 3*C.get(ate_param)
template u: untyped = C.pairing(ate_param)
let u3 = 3*C.pairing(ate_param)
for i in countdown(u3.bits - 2, 1):
f.square()
line.line_double(T, P)
@ -145,7 +111,7 @@ func millerLoopGenericBLS12*[C: static Curve](
line.line_add(T, nQ, P)
f.mul(line)
when C.get(ate_param_isNeg):
when C.pairing(ate_param_isNeg):
# In GT, x^-1 == conjugate(x)
# Remark 7.1, chapter 7.1.1 of Guide to Pairing-Based Cryptography, El Mrabet, 2017
f.conj()
@ -153,7 +119,7 @@ func millerLoopGenericBLS12*[C: static Curve](
func finalExpGeneric[C: static Curve](f: var Fp12[C]) =
## A generic and slow implementation of final exponentiation
## for sanity checks purposes.
f.powUnsafeExponent(C.get(finalexponent), window = 3)
f.powUnsafeExponent(C.pairing(finalexponent), window = 3)
func pairing_bls12_reference*[C](gt: var Fp12[C], P: ECP_SWei_Proj[Fp[C]], Q: ECP_SWei_Proj[Fp2[C]]) =
## Compute the optimal Ate Pairing for BLS12 curves
@ -171,66 +137,7 @@ func pairing_bls12_reference*[C](gt: var Fp12[C], P: ECP_SWei_Proj[Fp[C]], Q: EC
# Optimized pairing implementation
# ----------------------------------------------------------------
func cycl_sqr_repeated(f: var Fp12, num: int) =
## Repeated cyclotomic squarings
for _ in 0 ..< num:
f.cyclotomic_square()
func pow_xdiv2(r: var Fp12[BLS12_381], a: Fp12[BLS12_381], invert = BLS12_381_ate_param_isNeg) =
## f^(x/2) with x the curve parameter
## For BLS12_381 f^-0xd201000000010000
r.cyclotomic_square(a)
r *= a
r.cycl_sqr_repeated(2)
r *= a
r.cycl_sqr_repeated(3)
r *= a
r.cycl_sqr_repeated(9)
r *= a
r.cycl_sqr_repeated(32) # TODO: use Karabina?
r *= a
r.cycl_sqr_repeated(16-1) # Don't do the last iteration
if invert:
r.cyclotomic_inv()
func pow_x(r: var Fp12[BLS12_381], a: Fp12[BLS12_381], invert = BLS12_381_ate_param_isNeg) =
## f^x with x the curve parameter
## For BLS12_381 f^-0xd201000000010000
r.pow_xdiv2(a, invert)
r.cyclotomic_square()
func pow_x(r: var Fp12[BLS12_377], a: Fp12[BLS12_377], invert = BLS12_377_ate_param_isNeg) =
## f^x with x the curve parameter
## For BLS12_377 f^-0x8508c00000000001
## Warning: The parameter is odd and needs a correction
r.cyclotomic_square(a)
r *= a
r.cyclotomic_square()
r *= a
let t111 = r
r.cycl_sqr_repeated(2)
let t111000 = r
r *= t111
let t100011 = r
r.cyclotomic_square()
r *= t100011
r *= t111000
r.cycl_sqr_repeated(10)
r *= t100011
r.cycl_sqr_repeated(46)
r *= a
if invert:
r.cyclotomic_inv()
func finalExpHard_BLS12*[C: static Curve](f: var Fp12[C]) =
func finalExpHard_BLS12*[C](f: var Fp12[C]) =
## Hard part of the final exponentiation
## Specialized for BLS12 curves
##
@ -259,7 +166,7 @@ func finalExpHard_BLS12*[C: static Curve](f: var Fp12[C]) =
v2.cyclotomic_square(f) # v2 = f²
# (x1)²
when C.get(ate_param).isEven.bool:
when C.pairing(ate_param).isEven.bool:
v0.pow_xdiv2(v2) # v0 = (f²)^(x/2) = f^x
else:
v0.pow_x(f)

View File

@ -7,10 +7,7 @@
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import
std/macros,
../primitives,
../config/[common, curves],
../arithmetic,
../config/[curves, type_fp],
../towers,
../io/io_bigints,
../elliptic/[
@ -20,7 +17,8 @@ import
./lines_projective,
./mul_fp12_by_lines,
./cyclotomic_fp12,
../isogeny/frobenius
../isogeny/frobenius,
../curves/zoo_pairings
# ############################################################
#
@ -42,37 +40,10 @@ import
# Craig Costello, Tanja Lange, and Michael Naehrig, 2009
# https://eprint.iacr.org/2009/615.pdf
# TODO: should be part of curve parameters
# The bit count must be exact for the Miller loop
const BN254_Snarks_ate_param = block:
# BN Miller loop is parametrized by 6u+2
BigInt[65+2].fromHex"0x19d797039be763ba8"
const BN254_Snarks_ate_param_isNeg = false
const BN254_Nogami_ate_param = block:
# BN Miller loop is parametrized by 6u+2
BigInt[65+2].fromHex"0x18300000000000004" # 65+2 bit for NAF x3 encoding
const BN254_Nogami_ate_param_isNeg = true
# Generic slow pairing implementation
# Generic pairing implementation
# ----------------------------------------------------------------
const BN254_Snarks_finalexponent = block:
# (p^12 - 1) / r
BigInt[2790].fromHex"0x2f4b6dc97020fddadf107d20bc842d43bf6369b1ff6a1c71015f3f7be2e1e30a73bb94fec0daf15466b2383a5d3ec3d15ad524d8f70c54efee1bd8c3b21377e563a09a1b705887e72eceaddea3790364a61f676baaf977870e88d5c6c8fef0781361e443ae77f5b63a2a2264487f2940a8b1ddb3d15062cd0fb2015dfc6668449aed3cc48a82d0d602d268c7daab6a41294c0cc4ebe5664568dfc50e1648a45a4a1e3a5195846a3ed011a337a02088ec80e0ebae8755cfe107acf3aafb40494e406f804216bb10cf430b0f37856b42db8dc5514724ee93dfb10826f0dd4a0364b9580291d2cd65664814fde37ca80bb4ea44eacc5e641bbadf423f9a2cbf813b8d145da90029baee7ddadda71c7f3811c4105262945bba1668c3be69a3c230974d83561841d766f9c9d570bb7fbe04c7e8a6c3c760c0de81def35692da361102b6b9b2b918837fa97896e84abb40a4efb7e54523a486964b64ca86f120"
const BN254_Nogami_finalexponent = block:
# (p^12 - 1) / r
BigInt[2786].fromHex"0x2928fbb36b391596ee3fe4cbe857330da83e46fedf04d235a4a8daf5ff9f6eabcb4e3f20aa06f0a0d96b24f9af0cbbce750d61627dcbf5fec9139b8f1c46c86b49b4f8a202af26e4504f2c0f56570e9bd5b94c403f385d1908556486e24b396ddc2cdf13d06542f84fe8e82ccbad7b7423fc1ef4e8cc73d605e3e867c0a75f45ea7f6356d9846ce35d5a34f30396938818ad41914b97b99c289a7259b5d2e09477a77bd3c409b19f19e893f8ade90b0aed1b5fc8a07a3cebb41d4e9eee96b21a832ddb1e93e113edfb704fa532848c18593cd0ee90444a1b3499a800177ea38bdec62ec5191f2b6bbee449722f98d2173ad33077545c2ad10347e125a56fb40f086e9a4e62ad336a72c8b202ac3c1473d73b93d93dc0795ca0ca39226e7b4c1bb92f99248ec0806e0ad70744e9f2238736790f5185ea4c70808442a7d530c6ccd56b55a6973867ec6c73599bbd020bbe105da9c6b5c009ad8946cd6f0"
{.experimental: "dynamicBindSym".}
macro get(C: static Curve, value: untyped): untyped =
return bindSym($C & "_" & $value)
func millerLoopGenericBN*[C: static Curve](
func millerLoopGenericBN*[C](
f: var Fp12[C],
P: ECP_SWei_Aff[Fp[C]],
Q: ECP_SWei_Aff[Fp2[C]]
@ -123,8 +94,8 @@ func millerLoopGenericBN*[C: static Curve](
else:
f.mul_sparse_by_line_xy000z(line)
template u: untyped = C.get(ate_param)
let u3 = 3*C.get(ate_param)
template u: untyped = C.pairing(ate_param)
let u3 = 3*C.pairing(ate_param)
for i in countdown(u3.bits - 2, 1):
f.square()
line.line_double(T, P)
@ -138,13 +109,13 @@ func millerLoopGenericBN*[C: static Curve](
line.line_add(T, nQ, P)
f.mul(line)
when C.get(ate_param_isNeg):
when C.pairing(ate_param_isNeg):
# In GT, x^-1 == conjugate(x)
# Remark 7.1, chapter 7.1.1 of Guide to Pairing-Based Cryptography, El Mrabet, 2017
f.conj()
# Ate pairing for BN curves need adjustment after Miller loop
when C.get(ate_param_isNeg):
when C.pairing(ate_param_isNeg):
T.neg()
var V {.noInit.}: typeof(Q)
@ -160,7 +131,7 @@ func millerLoopGenericBN*[C: static Curve](
func finalExpGeneric[C: static Curve](f: var Fp12[C]) =
## A generic and slow implementation of final exponentiation
## for sanity checks purposes.
f.powUnsafeExponent(C.get(finalexponent), window = 3)
f.powUnsafeExponent(C.pairing(finalexponent), window = 3)
func pairing_bn_reference*[C](gt: var Fp12[C], P: ECP_SWei_Proj[Fp[C]], Q: ECP_SWei_Proj[Fp2[C]]) =
## Compute the optimal Ate Pairing for BN curves
@ -178,106 +149,6 @@ func pairing_bn_reference*[C](gt: var Fp12[C], P: ECP_SWei_Proj[Fp[C]], Q: ECP_S
# Optimized pairing implementation
# ----------------------------------------------------------------
func cycl_sqr_repeated(f: var Fp12, num: int) =
## Repeated cyclotomic squarings
for _ in 0 ..< num:
f.cyclotomic_square()
func pow_u(r: var Fp12[BN254_Nogami], a: Fp12[BN254_Nogami], invert = BN254_Nogami_ate_param_isNeg) =
## f^u with u the curve parameter
## For BN254_Nogami f^-0x4080000000000001
r = a
r.cycl_sqr_repeated(7)
r *= a
r.cycl_sqr_repeated(55)
r *= a
if invert:
r.cyclotomic_inv()
func pow_u(r: var Fp12[BN254_Snarks], a: Fp12[BN254_Snarks], invert = BN254_Snarks_ate_param_isNeg) =
## f^u with u the curve parameter
## For BN254_Snarks f^0x44e992b44a6909f1
when false:
cyclotomic_exp(
r, a,
BigInt[63].fromHex("0x44e992b44a6909f1"),
invert
)
else:
var # Hopefully the compiler optimizes away unused Fp12
# because those are huge
x10 {.noInit.}: Fp12[BN254_Snarks]
x11 {.noInit.}: Fp12[BN254_Snarks]
x100 {.noInit.}: Fp12[BN254_Snarks]
x110 {.noInit.}: Fp12[BN254_Snarks]
x1100 {.noInit.}: Fp12[BN254_Snarks]
x1111 {.noInit.}: Fp12[BN254_Snarks]
x10010 {.noInit.}: Fp12[BN254_Snarks]
x10110 {.noInit.}: Fp12[BN254_Snarks]
x11100 {.noInit.}: Fp12[BN254_Snarks]
x101110 {.noInit.}: Fp12[BN254_Snarks]
x1001010 {.noInit.}: Fp12[BN254_Snarks]
x1111000 {.noInit.}: Fp12[BN254_Snarks]
x10001110 {.noInit.}: Fp12[BN254_Snarks]
x10 .cyclotomic_square(a)
x11 .prod(x10, a)
x100 .prod(x11, a)
x110 .prod(x10, x100)
x1100 .cyclotomic_square(x110)
x1111 .prod(x11, x1100)
x10010 .prod(x11, x1111)
x10110 .prod(x100, x10010)
x11100 .prod(x110, x10110)
x101110 .prod(x10010, x11100)
x1001010 .prod(x11100, x101110)
x1111000 .prod(x101110, x1001010)
x10001110 .prod(x10110, x1111000)
var
i15 {.noInit.}: Fp12[BN254_Snarks]
i16 {.noInit.}: Fp12[BN254_Snarks]
i17 {.noInit.}: Fp12[BN254_Snarks]
i18 {.noInit.}: Fp12[BN254_Snarks]
i20 {.noInit.}: Fp12[BN254_Snarks]
i21 {.noInit.}: Fp12[BN254_Snarks]
i22 {.noInit.}: Fp12[BN254_Snarks]
i26 {.noInit.}: Fp12[BN254_Snarks]
i27 {.noInit.}: Fp12[BN254_Snarks]
i61 {.noInit.}: Fp12[BN254_Snarks]
i15.cyclotomic_square(x10001110)
i15 *= x1001010
i16.prod(x10001110, i15)
i17.prod(x1111, i16)
i18.prod(i16, i17)
i20.cyclotomic_square(i18)
i20 *= i17
i21.prod(x1111000, i20)
i22.prod(i15, i21)
i26.cyclotomic_square(i22)
i26.cyclotomic_square()
i26 *= i22
i26 *= i18
i27.prod(i22, i26)
i61.prod(i26, i27)
i61.cycl_sqr_repeated(17)
i61 *= i27
i61.cycl_sqr_repeated(14)
i61 *= i21
r = i61
r.cycl_sqr_repeated(16)
r *= i20
if invert:
r.cyclotomic_inv()
func finalExpHard_BN*[C: static Curve](f: var Fp12[C]) =
## Hard part of the final exponentiation
## Specialized for BN curves
@ -302,7 +173,7 @@ func finalExpHard_BN*[C: static Curve](f: var Fp12[C]) =
t1 *= t0 # t1 = f^6|u|
t2.pow_u(t1, invert = false) # t2 = f^6u²
if C.get(ate_param_is_Neg):
if C.pairing(ate_param_is_Neg):
t3.cyclotomic_inv(t1) # t3 = f^6u
else:
t3 = t1 # t3 = f^6u
@ -311,7 +182,7 @@ func finalExpHard_BN*[C: static Curve](f: var Fp12[C]) =
t4.pow_u(t3) # t4 = f^12u³
t4 *= t1 # t4 = f^(6u + 6u² + 12u³) = f^λ₂
if not C.get(ate_param_is_Neg):
if not C.pairing(ate_param_is_Neg):
t0.cyclotomic_inv() # t0 = f^-2u
t3.prod(t4, t0) # t3 = f^(4u + 6u² + 12u³)

View File

@ -33,10 +33,15 @@ const CryptoModSizes = [
# Barreto-Naehrig
254, # BN254
# Barreto-Lynn-Scott
377, # BLS12-377
381, # BLS12-381
383, # BLS12-383
461, # BLS12-461
480, # BLS24-480
# Brezing-Weng
761, # BW6-761
# Cocks-Pinch
782, # CP6-782
# Miyaji-Nakabayashi-Takano
298, # MNT4-298, MNT6-298
753, # MNT4-753, MNT6-753
# NIST recommended curves for US Federal Government (FIPS)
# https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf
192,

View File

@ -198,10 +198,6 @@ proc main() =
testRandomDiv2 Secp256k1
testRandomDiv2 BLS12_377
testRandomDiv2 BLS12_381
testRandomDiv2 BN446
testRandomDiv2 FKM12_447
testRandomDiv2 BLS12_461
testRandomDiv2 BN462
suite "Modular inversion over prime fields" & " [" & $WordBitwidth & "-bit mode]":
test "Specific tests on Fp[BLS12_381]":
@ -289,10 +285,6 @@ proc main() =
testRandomInv Secp256k1
testRandomInv BLS12_377
testRandomInv BLS12_381
testRandomInv BN446
testRandomInv FKM12_447
testRandomInv BLS12_461
testRandomInv BN462
main()

View File

@ -129,17 +129,13 @@ proc main() =
randomSqrtCheck Secp256k1
randomSqrtCheck BLS12_377 # p ≢ 3 (mod 4)
randomSqrtCheck BLS12_381
randomSqrtCheck BN446
randomSqrtCheck FKM12_447
randomSqrtCheck BLS12_461
randomSqrtCheck BN462
suite "Modular square root - 32-bit bugs highlighted by property-based testing " & " [" & $WordBitwidth & "-bit mode]":
test "FKM12_447 - #30":
var a: Fp[FKM12_447]
a.fromHex"0x406e5e74ee09c84fa0c59f2db3ac814a4937e2f57ecd3c0af4265e04598d643c5b772a6549a2d9b825445c34b8ba100fe8d912e61cfda43d"
a.square()
check: bool a.isSquare()
# test "FKM12_447 - #30": - Deactivated, we don't support the curve as no one uses it.
# var a: Fp[FKM12_447]
# a.fromHex"0x406e5e74ee09c84fa0c59f2db3ac814a4937e2f57ecd3c0af4265e04598d643c5b772a6549a2d9b825445c34b8ba100fe8d912e61cfda43d"
# a.square()
# check: bool a.isSquare()
test "Fused modular square root on 32-bit - inconsistent with isSquare - #42":
var a: Fp[BLS12_381]

View File

@ -18,10 +18,6 @@ const TestCurves = [
BN254_Snarks,
BLS12_377,
BLS12_381,
# BN446
# FKM12_447
# BLS12_461
# BN462
]
runFrobeniusTowerTests(

View File

@ -14,14 +14,10 @@ import
./t_fp_tower_template
const TestCurves = [
# BN254_Nogami
BN254_Nogami,
BN254_Snarks,
BLS12_377,
BLS12_381,
# BN446
# FKM12_447
# BLS12_461
# BN462
]
runTowerTests(

View File

@ -18,10 +18,6 @@ const TestCurves = [
BN254_Snarks,
BLS12_377,
BLS12_381,
# BN446
# FKM12_447
# BLS12_461
# BN462
]
runFrobeniusTowerTests(

View File

@ -16,12 +16,8 @@ import
const TestCurves = [
BN254_Nogami,
BN254_Snarks,
# BLS12_377,
BLS12_377,
BLS12_381,
# BN446
# FKM12_447
# BLS12_461
# BN462
]
runFrobeniusTowerTests(

View File

@ -16,12 +16,8 @@ import
const TestCurves = [
BN254_Nogami,
BN254_Snarks,
# BLS12_377,
BLS12_377,
BLS12_381,
# BN446
# FKM12_447
# BLS12_461
# BN462
]
runFrobeniusTowerTests(

View File

@ -10,7 +10,7 @@ import std/unittest,
../constantine/config/common,
../constantine/arithmetic,
../constantine/config/curves,
../constantine/io/[io_bigints, io_fields]
../constantine/curves/zoo_glv
echo "\n------------------------------------------------------\n"
@ -22,19 +22,10 @@ proc checkCubeRootOfUnity(curve: static Curve) =
check: bool cru.isOne()
test $curve & " cube root of unity (mod r)":
var cru: BigInt[3 * curve.getCurveOrderBitwidth()]
cru.prod(curve.getCubicRootOfUnity_mod_r(), curve.getCubicRootOfUnity_mod_r())
cru.mul(curve.getCubicRootOfUnity_mod_r())
var r: BigInt[curve.getCurveOrderBitwidth()]
r.reduce(cru, curve.getCurveOrder)
check: bool r.isOne()
proc main() =
suite "Sanity checks on precomputed values" & " [" & $WordBitwidth & "-bit mode]":
checkCubeRootOfUnity(BN254_Snarks)
# checkCubeRootOfUnity(BLS12_381)
checkCubeRootOfUnity(BLS12_377)
checkCubeRootOfUnity(BLS12_381)
main()