mirror of
https://github.com/status-im/constantine.git
synced 2025-02-23 17:38:09 +00:00
Refactor: Higher-Kinded Tower of Extension Fields (#25)
* Mention that the inverse of 0 is 0 (TODO tests) * Introduce "Higher-Kinded tower extensions" * rename isCOmplexExtension -> fromComplexExtension * update benchmarks with the new tower scheme * Try to recover some speed on mul/squaring for an optimal tower (but this was not it)
This commit is contained in:
parent
2f839cb1bf
commit
c04721a04e
@ -14,11 +14,9 @@
|
|||||||
|
|
||||||
import
|
import
|
||||||
# Internals
|
# Internals
|
||||||
../constantine/config/[common, curves],
|
../constantine/config/curves,
|
||||||
../constantine/arithmetic,
|
../constantine/arithmetic,
|
||||||
../constantine/io/[io_bigints, io_fields],
|
../constantine/towers,
|
||||||
../constantine/primitives,
|
|
||||||
../constantine/tower_field_extensions/[abelian_groups, fp2_complex, fp6_1_plus_i],
|
|
||||||
# Helpers
|
# Helpers
|
||||||
../helpers/[timers, prng, static_for],
|
../helpers/[timers, prng, static_for],
|
||||||
# Standard library
|
# Standard library
|
||||||
|
@ -55,5 +55,6 @@ proc main() =
|
|||||||
main()
|
main()
|
||||||
|
|
||||||
echo "Notes:"
|
echo "Notes:"
|
||||||
echo " GCC is significantly slower than Clang on multiprecision arithmetic."
|
echo " - GCC is significantly slower than Clang on multiprecision arithmetic."
|
||||||
echo " The simplest operations might be optimized away by the compiler."
|
echo " - The simplest operations might be optimized away by the compiler."
|
||||||
|
echo " - Fast Squaring and Fast Multiplication are possible if there are spare bits in the prime representation (i.e. the prime uses 254 bits out of 256 bits)"
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
import
|
import
|
||||||
# Internals
|
# Internals
|
||||||
../constantine/config/curves,
|
../constantine/config/curves,
|
||||||
../constantine/tower_field_extensions/[abelian_groups, fp12_quad_fp6],
|
../constantine/towers,
|
||||||
# Helpers
|
# Helpers
|
||||||
../helpers/static_for,
|
../helpers/static_for,
|
||||||
./bench_fields_template,
|
./bench_fields_template,
|
||||||
@ -27,14 +27,14 @@ const Iters = 10_000
|
|||||||
const InvIters = 1000
|
const InvIters = 1000
|
||||||
const AvailableCurves = [
|
const AvailableCurves = [
|
||||||
# Pairing-Friendly curves
|
# Pairing-Friendly curves
|
||||||
BN254_Nogami,
|
# BN254_Nogami,
|
||||||
BN254_Snarks,
|
BN254_Snarks,
|
||||||
BLS12_377,
|
BLS12_377,
|
||||||
BLS12_381,
|
BLS12_381
|
||||||
BN446,
|
# BN446,
|
||||||
FKM12_447,
|
# FKM12_447,
|
||||||
BLS12_461,
|
# BLS12_461,
|
||||||
BN462
|
# BN462
|
||||||
]
|
]
|
||||||
|
|
||||||
proc main() =
|
proc main() =
|
||||||
@ -52,4 +52,6 @@ proc main() =
|
|||||||
main()
|
main()
|
||||||
|
|
||||||
echo "Notes:"
|
echo "Notes:"
|
||||||
echo " GCC is significantly slower than Clang on multiprecision arithmetic."
|
echo " - GCC is significantly slower than Clang on multiprecision arithmetic."
|
||||||
|
echo " - Fast Squaring and Fast Multiplication are possible if there are spare bits in the prime representation (i.e. the prime uses 254 bits out of 256 bits)"
|
||||||
|
echo " - The tower of extension fields chosen can lead to a large difference of performance between primes of similar bitwidth."
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
import
|
import
|
||||||
# Internals
|
# Internals
|
||||||
../constantine/config/curves,
|
../constantine/config/curves,
|
||||||
../constantine/tower_field_extensions/[abelian_groups, fp2_complex],
|
../constantine/towers,
|
||||||
# Helpers
|
# Helpers
|
||||||
../helpers/static_for,
|
../helpers/static_for,
|
||||||
./bench_fields_template,
|
./bench_fields_template,
|
||||||
@ -27,14 +27,14 @@ const Iters = 1_000_000
|
|||||||
const InvIters = 1000
|
const InvIters = 1000
|
||||||
const AvailableCurves = [
|
const AvailableCurves = [
|
||||||
# Pairing-Friendly curves
|
# Pairing-Friendly curves
|
||||||
BN254_Nogami,
|
# BN254_Nogami,
|
||||||
BN254_Snarks,
|
BN254_Snarks,
|
||||||
BLS12_377,
|
BLS12_377,
|
||||||
BLS12_381,
|
BLS12_381
|
||||||
BN446,
|
# BN446,
|
||||||
FKM12_447,
|
# FKM12_447,
|
||||||
BLS12_461,
|
# BLS12_461,
|
||||||
BN462
|
# BN462
|
||||||
]
|
]
|
||||||
|
|
||||||
proc main() =
|
proc main() =
|
||||||
@ -52,4 +52,6 @@ proc main() =
|
|||||||
main()
|
main()
|
||||||
|
|
||||||
echo "Notes:"
|
echo "Notes:"
|
||||||
echo " GCC is significantly slower than Clang on multiprecision arithmetic."
|
echo " - GCC is significantly slower than Clang on multiprecision arithmetic."
|
||||||
|
echo " - Fast Squaring and Fast Multiplication are possible if there are spare bits in the prime representation (i.e. the prime uses 254 bits out of 256 bits)"
|
||||||
|
echo " - The tower of extension fields chosen can lead to a large difference of performance between primes of similar bitwidth."
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
import
|
import
|
||||||
# Internals
|
# Internals
|
||||||
../constantine/config/curves,
|
../constantine/config/curves,
|
||||||
../constantine/tower_field_extensions/[abelian_groups, fp6_1_plus_i],
|
../constantine/towers,
|
||||||
# Helpers
|
# Helpers
|
||||||
../helpers/static_for,
|
../helpers/static_for,
|
||||||
./bench_fields_template,
|
./bench_fields_template,
|
||||||
@ -27,14 +27,14 @@ const Iters = 1_000_000
|
|||||||
const InvIters = 1000
|
const InvIters = 1000
|
||||||
const AvailableCurves = [
|
const AvailableCurves = [
|
||||||
# Pairing-Friendly curves
|
# Pairing-Friendly curves
|
||||||
BN254_Nogami,
|
# BN254_Nogami,
|
||||||
BN254_Snarks,
|
BN254_Snarks,
|
||||||
BLS12_377,
|
BLS12_377,
|
||||||
BLS12_381,
|
BLS12_381
|
||||||
BN446,
|
# BN446,
|
||||||
FKM12_447,
|
# FKM12_447,
|
||||||
BLS12_461,
|
# BLS12_461,
|
||||||
BN462
|
# BN462
|
||||||
]
|
]
|
||||||
|
|
||||||
proc main() =
|
proc main() =
|
||||||
@ -52,4 +52,6 @@ proc main() =
|
|||||||
main()
|
main()
|
||||||
|
|
||||||
echo "Notes:"
|
echo "Notes:"
|
||||||
echo " GCC is significantly slower than Clang on multiprecision arithmetic."
|
echo " - GCC is significantly slower than Clang on multiprecision arithmetic."
|
||||||
|
echo " - Fast Squaring and Fast Multiplication are possible if there are spare bits in the prime representation (i.e. the prime uses 254 bits out of 256 bits)"
|
||||||
|
echo " - The tower of extension fields chosen can lead to a large difference of performance between primes of similar bitwidth."
|
||||||
|
@ -416,3 +416,8 @@ func `*=`*(a: var Fp, b: static int) {.inline.} =
|
|||||||
a += t4
|
a += t4
|
||||||
else:
|
else:
|
||||||
{.error: "Multiplication by this small int not implemented".}
|
{.error: "Multiplication by this small int not implemented".}
|
||||||
|
|
||||||
|
func `*`*(b: static int, a: Fp): Fp {.noinit, inline.} =
|
||||||
|
## Multiplication by a small integer known at compile-time
|
||||||
|
result = a
|
||||||
|
result *= b
|
||||||
|
@ -152,6 +152,11 @@ func invmod_addchain_bn[C](r: var Fp[C], a: Fp[C]) =
|
|||||||
|
|
||||||
func inv*(r: var Fp, a: Fp) =
|
func inv*(r: var Fp, a: Fp) =
|
||||||
## Inversion modulo p
|
## Inversion modulo p
|
||||||
|
##
|
||||||
|
## The inverse of 0 is 0.
|
||||||
|
## Incidentally this avoids extra check
|
||||||
|
## to convert Jacobian and Projective coordinates
|
||||||
|
## to affine for elliptic curve
|
||||||
# For now we don't activate the addition chains
|
# For now we don't activate the addition chains
|
||||||
# neither for Secp256k1 nor BN curves
|
# neither for Secp256k1 nor BN curves
|
||||||
# Performance is slower than GCD
|
# Performance is slower than GCD
|
||||||
|
@ -65,6 +65,8 @@ func steinsGCD*(v: var Limbs, a: Limbs, F, M: Limbs, bits: int, mp1div2: Limbs)
|
|||||||
##
|
##
|
||||||
## This takes (M+1)/2 (mp1div2) as a precomputed parameter as a slight optimization
|
## This takes (M+1)/2 (mp1div2) as a precomputed parameter as a slight optimization
|
||||||
## in stack size and speed.
|
## in stack size and speed.
|
||||||
|
##
|
||||||
|
## The inverse of 0 is 0.
|
||||||
|
|
||||||
# Ideally we need registers for a, b, u, v
|
# Ideally we need registers for a, b, u, v
|
||||||
# but:
|
# but:
|
||||||
|
@ -1,187 +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
|
|
||||||
../arithmetic,
|
|
||||||
../config/common,
|
|
||||||
../primitives
|
|
||||||
|
|
||||||
# ############################################################
|
|
||||||
#
|
|
||||||
# Algebraic concepts
|
|
||||||
#
|
|
||||||
# ############################################################
|
|
||||||
# Too heavy on the Nim compiler, we just rely on generic instantiation
|
|
||||||
# to complain if the base field procedures don't exist.
|
|
||||||
|
|
||||||
# type
|
|
||||||
# AbelianGroup* {.explain.} = concept a, b, var mA, var mR
|
|
||||||
# setZero(mA)
|
|
||||||
# setOne(mA)
|
|
||||||
# `+=`(mA, b)
|
|
||||||
# `-=`(mA, b)
|
|
||||||
# double(mR, a)
|
|
||||||
# sum(mR, a, b)
|
|
||||||
# diff(mR, a, b)
|
|
||||||
|
|
||||||
# ############################################################
|
|
||||||
#
|
|
||||||
# Cubic Extension fields
|
|
||||||
#
|
|
||||||
# ############################################################
|
|
||||||
|
|
||||||
type
|
|
||||||
CubicExtAddGroup* = concept x
|
|
||||||
## Cubic extension fields - Abelian Additive Group concept
|
|
||||||
type BaseField = auto
|
|
||||||
x.c0 is BaseField
|
|
||||||
x.c1 is BaseField
|
|
||||||
x.c2 is BaseField
|
|
||||||
|
|
||||||
func `==`*(a, b: CubicExtAddGroup): CTBool[Word] =
|
|
||||||
## Constant-time equality check
|
|
||||||
(a.c0 == b.c0) and (a.c1 == b.c1) and (a.c2 == b.c2)
|
|
||||||
|
|
||||||
func setZero*(a: var CubicExtAddGroup) =
|
|
||||||
## Set ``a`` to zero in the extension field
|
|
||||||
## Coordinates 0 + 0 w + 0 w²
|
|
||||||
## with w the solution of f(x) = x³ - µ = 0
|
|
||||||
a.c0.setZero()
|
|
||||||
a.c1.setZero()
|
|
||||||
a.c2.setZero()
|
|
||||||
|
|
||||||
func setOne*(a: var CubicExtAddGroup) =
|
|
||||||
## Set ``a`` to one in the extension field
|
|
||||||
## Coordinates 1 + 0 w + 0 w²
|
|
||||||
## with w the solution of f(x) = x³ - µ = 0
|
|
||||||
a.c0.setOne()
|
|
||||||
a.c1.setZero()
|
|
||||||
a.c2.setZero()
|
|
||||||
|
|
||||||
func `+=`*(a: var CubicExtAddGroup, b: CubicExtAddGroup) =
|
|
||||||
## Addition in the extension field
|
|
||||||
a.c0 += b.c0
|
|
||||||
a.c1 += b.c1
|
|
||||||
a.c2 += b.c2
|
|
||||||
|
|
||||||
func `-=`*(a: var CubicExtAddGroup, b: CubicExtAddGroup) =
|
|
||||||
## Substraction in the extension field
|
|
||||||
a.c0 -= b.c0
|
|
||||||
a.c1 -= b.c1
|
|
||||||
a.c2 -= b.c2
|
|
||||||
|
|
||||||
func double*(r: var CubicExtAddGroup, a: CubicExtAddGroup) =
|
|
||||||
## Double in the extension field
|
|
||||||
r.c0.double(a.c0)
|
|
||||||
r.c1.double(a.c1)
|
|
||||||
r.c2.double(a.c2)
|
|
||||||
|
|
||||||
func double*(a: var CubicExtAddGroup) =
|
|
||||||
## Double in the extension field
|
|
||||||
double(a.c0)
|
|
||||||
double(a.c1)
|
|
||||||
double(a.c2)
|
|
||||||
|
|
||||||
func sum*(r: var CubicExtAddGroup, a, b: CubicExtAddGroup) =
|
|
||||||
## Sum ``a`` and ``b`` into r
|
|
||||||
r.c0.sum(a.c0, b.c0)
|
|
||||||
r.c1.sum(a.c1, b.c1)
|
|
||||||
r.c2.sum(a.c2, b.c2)
|
|
||||||
|
|
||||||
func diff*(r: var CubicExtAddGroup, a, b: CubicExtAddGroup) =
|
|
||||||
## Difference of ``a`` by `b`` into r
|
|
||||||
r.c0.diff(a.c0, b.c0)
|
|
||||||
r.c1.diff(a.c1, b.c1)
|
|
||||||
r.c2.diff(a.c2, b.c2)
|
|
||||||
|
|
||||||
func neg*(r: var CubicExtAddGroup, a: CubicExtAddGroup) =
|
|
||||||
## Negate ``a`` and store the result into r
|
|
||||||
r.c0.neg(a.c0)
|
|
||||||
r.c1.neg(a.c1)
|
|
||||||
r.c2.neg(a.c2)
|
|
||||||
|
|
||||||
# TODO: The type system is lost with out-of-place result concepts
|
|
||||||
# func `+`*(a, b: CubicExtAddGroup): CubicExtAddGroup =
|
|
||||||
# result.sum(a, b)
|
|
||||||
#
|
|
||||||
# func `-`*(a, b: CubicExtAddGroup): CubicExtAddGroup =
|
|
||||||
# result.sum(a, b)
|
|
||||||
|
|
||||||
# ############################################################
|
|
||||||
#
|
|
||||||
# Quadratic Extension fields
|
|
||||||
#
|
|
||||||
# ############################################################
|
|
||||||
|
|
||||||
type
|
|
||||||
QuadExtAddGroup* = concept x
|
|
||||||
## Quadratic extension fields - Abelian Additive Group concept
|
|
||||||
not(x is CubicExtAddGroup)
|
|
||||||
type BaseField = auto
|
|
||||||
x.c0 is BaseField
|
|
||||||
x.c1 is BaseField
|
|
||||||
|
|
||||||
func `==`*(a, b: QuadExtAddGroup): CTBool[Word] =
|
|
||||||
## Constant-time equality check
|
|
||||||
(a.c0 == b.c0) and (a.c1 == b.c1)
|
|
||||||
|
|
||||||
func setZero*(a: var QuadExtAddGroup) =
|
|
||||||
## Set ``a`` to zero in the extension field
|
|
||||||
## Coordinates 0 + 0 𝛼
|
|
||||||
## with 𝛼 the solution of f(x) = x² - µ = 0
|
|
||||||
a.c0.setZero()
|
|
||||||
a.c1.setZero()
|
|
||||||
|
|
||||||
func setOne*(a: var QuadExtAddGroup) =
|
|
||||||
## Set ``a`` to one in the extension field
|
|
||||||
## Coordinates 1 + 0 𝛼
|
|
||||||
## with 𝛼 the solution of f(x) = x² - µ = 0
|
|
||||||
a.c0.setOne()
|
|
||||||
a.c1.setZero()
|
|
||||||
|
|
||||||
func `+=`*(a: var QuadExtAddGroup, b: QuadExtAddGroup) =
|
|
||||||
## Addition in the extension field
|
|
||||||
a.c0 += b.c0
|
|
||||||
a.c1 += b.c1
|
|
||||||
|
|
||||||
func `-=`*(a: var QuadExtAddGroup, b: QuadExtAddGroup) =
|
|
||||||
## Substraction in the extension field
|
|
||||||
a.c0 -= b.c0
|
|
||||||
a.c1 -= b.c1
|
|
||||||
|
|
||||||
func double*(r: var QuadExtAddGroup, a: QuadExtAddGroup) =
|
|
||||||
## Double in the extension field
|
|
||||||
r.c0.double(a.c0)
|
|
||||||
r.c1.double(a.c1)
|
|
||||||
|
|
||||||
func double*(a: var QuadExtAddGroup) =
|
|
||||||
## Double in the extension field
|
|
||||||
double(a.c0)
|
|
||||||
double(a.c1)
|
|
||||||
|
|
||||||
func sum*(r: var QuadExtAddGroup, a, b: QuadExtAddGroup) =
|
|
||||||
## Sum ``a`` and ``b`` into r
|
|
||||||
r.c0.sum(a.c0, b.c0)
|
|
||||||
r.c1.sum(a.c1, b.c1)
|
|
||||||
|
|
||||||
func diff*(r: var QuadExtAddGroup, a, b: QuadExtAddGroup) =
|
|
||||||
## Difference of ``a`` by `b`` into r
|
|
||||||
r.c0.diff(a.c0, b.c0)
|
|
||||||
r.c1.diff(a.c1, b.c1)
|
|
||||||
|
|
||||||
func neg*(r: var QuadExtAddGroup, a: QuadExtAddGroup) =
|
|
||||||
## Negate ``a`` into ``r``
|
|
||||||
r.c0.neg(a.c0)
|
|
||||||
r.c1.neg(a.c1)
|
|
||||||
|
|
||||||
# TODO: The type system is lost with out-of-place result concepts
|
|
||||||
# func `+`*(a, b: CubicExtAddGroup): CubicExtAddGroup =
|
|
||||||
# result.sum(a, b)
|
|
||||||
#
|
|
||||||
# func `-`*(a, b: CubicExtAddGroup): CubicExtAddGroup =
|
|
||||||
# result.sum(a, b)
|
|
@ -6,74 +6,28 @@
|
|||||||
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
|
# * 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.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
# ############################################################
|
|
||||||
#
|
|
||||||
# Cubic Extension field over extension field 𝔽p2
|
|
||||||
# 𝔽p6 = 𝔽p2[∛(1 + 𝑖)]
|
|
||||||
#
|
|
||||||
# ############################################################
|
|
||||||
|
|
||||||
# This implements a quadratic extension field over
|
|
||||||
# 𝔽p6 = 𝔽p2[∛(1 + 𝑖)]
|
|
||||||
# with element A of coordinates (a0, a1, a2) represented
|
|
||||||
# by a0 + a1 v + a2 v²
|
|
||||||
#
|
|
||||||
# The irreducible polynomial chosen is
|
|
||||||
# v³ - ξ with ξ = 𝑖+1
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# Consequently, for this file 𝔽p6 to be valid
|
|
||||||
# 𝑖+1 MUST not be a cube in 𝔽p2
|
|
||||||
|
|
||||||
import
|
import
|
||||||
../arithmetic,
|
../arithmetic,
|
||||||
../config/curves,
|
../primitives,
|
||||||
./abelian_groups,
|
./tower_common
|
||||||
./fp2_complex
|
|
||||||
|
|
||||||
type
|
# Commutative ring implementation for Cubic Extension Fields
|
||||||
Fp6*[C: static Curve] = object
|
# -------------------------------------------------------------------
|
||||||
## Element of the extension field
|
|
||||||
## 𝔽p6 = 𝔽p2[∛(1 + 𝑖)]
|
|
||||||
##
|
|
||||||
## with coordinates (c0, c1, c2) such as
|
|
||||||
## c0 + c1 v + c2 v² and v³ = ξ = 1+𝑖
|
|
||||||
##
|
|
||||||
## This requires 1 + 𝑖 to not be a cube in 𝔽p2
|
|
||||||
c0*, c1*, c2*: Fp2[C]
|
|
||||||
|
|
||||||
Xi* = object
|
func square*(r: var CubicExt, a: CubicExt) =
|
||||||
## ξ (Xi) the cubic non-residue of 𝔽p2
|
|
||||||
|
|
||||||
func `*`*(_: typedesc[Xi], a: Fp2): Fp2 {.inline.}=
|
|
||||||
## Multiply an element of 𝔽p2 by 𝔽p6 cubic non-residue ξ = 1 + 𝑖
|
|
||||||
## (c0 + c1 𝑖) (1 + 𝑖) => c0 + (c0 + c1)𝑖 + c1 𝑖²
|
|
||||||
## => c0 - c1 + (c0 + c1) 𝑖
|
|
||||||
result.c0.diff(a.c0, a.c1)
|
|
||||||
result.c1.sum(a.c0, a.c1)
|
|
||||||
|
|
||||||
template `*`*(a: Fp2, _: typedesc[Xi]): Fp2 =
|
|
||||||
Xi * a
|
|
||||||
|
|
||||||
func `*=`*(a: var Fp2, _: typedesc[Xi]) {.inline.}=
|
|
||||||
## Inplace multiply an element of 𝔽p2 by 𝔽p6 cubic non-residue 1 + 𝑖
|
|
||||||
let t = a.c0
|
|
||||||
a.c0 -= a.c1
|
|
||||||
a.c1 += t
|
|
||||||
|
|
||||||
func square*[C](r: var Fp6[C], a: Fp6[C]) =
|
|
||||||
## Returns r = a²
|
## Returns r = a²
|
||||||
# Algorithm is Chung-Hasan Squaring SQR2
|
# Algorithm is Chung-Hasan Squaring SQR2
|
||||||
# http://cacr.uwaterloo.ca/techreports/2006/cacr2006-24.pdf
|
# http://cacr.uwaterloo.ca/techreports/2006/cacr2006-24.pdf
|
||||||
#
|
#
|
||||||
# TODO: change to SQR1 or SQR3 (requires div2)
|
# TODO: change to SQR1 or SQR3 (requires div2)
|
||||||
# which are faster for the sizes we are interested in.
|
# which are faster for the sizes we are interested in.
|
||||||
var v2{.noInit.}, v3{.noInit.}, v4{.noInit.}, v5{.noInit.}: Fp2[C]
|
mixin prod, square, sum
|
||||||
|
var v2{.noInit.}, v3{.noInit.}, v4{.noInit.}, v5{.noInit.}: typeof(r.c0)
|
||||||
|
|
||||||
v4.prod(a.c0, a.c1)
|
v4.prod(a.c0, a.c1)
|
||||||
v4.double()
|
v4.double()
|
||||||
v5.square(a.c2)
|
v5.square(a.c2)
|
||||||
r.c1 = Xi * v5
|
r.c1 = β * v5
|
||||||
r.c1 += v4
|
r.c1 += v4
|
||||||
v2.diff(v4, v5)
|
v2.diff(v4, v5)
|
||||||
v3.square(a.c0)
|
v3.square(a.c0)
|
||||||
@ -82,39 +36,39 @@ func square*[C](r: var Fp6[C], a: Fp6[C]) =
|
|||||||
v5.prod(a.c1, a.c2)
|
v5.prod(a.c1, a.c2)
|
||||||
v5.double()
|
v5.double()
|
||||||
v4.square()
|
v4.square()
|
||||||
r.c0 = Xi * v5
|
r.c0 = β * v5
|
||||||
r.c0 += v3
|
r.c0 += v3
|
||||||
r.c2.sum(v2, v4)
|
r.c2.sum(v2, v4)
|
||||||
r.c2 += v5
|
r.c2 += v5
|
||||||
r.c2 -= v3
|
r.c2 -= v3
|
||||||
|
|
||||||
func prod*[C](r: var Fp6[C], a, b: Fp6[C]) =
|
func prod*(r: var CubicExt, a, b: CubicExt) =
|
||||||
## Returns r = a * b
|
## Returns r = a * b
|
||||||
##
|
##
|
||||||
## r MUST not share a buffer with a
|
## r MUST not share a buffer with a
|
||||||
# Algorithm is Karatsuba
|
# Algorithm is Karatsuba
|
||||||
var v0{.noInit.}, v1{.noInit.}, v2{.noInit.}, t{.noInit.}: Fp2[C]
|
var v0{.noInit.}, v1{.noInit.}, v2{.noInit.}, t{.noInit.}: typeof(r.c0)
|
||||||
|
|
||||||
v0.prod(a.c0, b.c0)
|
v0.prod(a.c0, b.c0)
|
||||||
v1.prod(a.c1, b.c1)
|
v1.prod(a.c1, b.c1)
|
||||||
v2.prod(a.c2, b.c2)
|
v2.prod(a.c2, b.c2)
|
||||||
|
|
||||||
# r.c0 = ((a.c1 + a.c2) * (b.c1 + b.c2) - v1 - v2) * Xi + v0
|
# r.c0 = β ((a.c1 + a.c2) * (b.c1 + b.c2) - v1 - v2) + v0
|
||||||
r.c0.sum(a.c1, a.c2)
|
r.c0.sum(a.c1, a.c2)
|
||||||
t.sum(b.c1, b.c2)
|
t.sum(b.c1, b.c2)
|
||||||
r.c0 *= t
|
r.c0 *= t
|
||||||
r.c0 -= v1
|
r.c0 -= v1
|
||||||
r.c0 -= v2
|
r.c0 -= v2
|
||||||
r.c0 *= Xi
|
r.c0 *= β
|
||||||
r.c0 += v0
|
r.c0 += v0
|
||||||
|
|
||||||
# r.c1 = (a.c0 + a.c1) * (b.c0 + b.c1) - v0 - v1 + Xi * v2
|
# r.c1 = (a.c0 + a.c1) * (b.c0 + b.c1) - v0 - v1 + β v2
|
||||||
r.c1.sum(a.c0, a.c1)
|
r.c1.sum(a.c0, a.c1)
|
||||||
t.sum(b.c0, b.c1)
|
t.sum(b.c0, b.c1)
|
||||||
r.c1 *= t
|
r.c1 *= t
|
||||||
r.c1 -= v0
|
r.c1 -= v0
|
||||||
r.c1 -= v1
|
r.c1 -= v1
|
||||||
r.c1 += Xi * v2
|
r.c1 += β * v2
|
||||||
|
|
||||||
# r.c2 = (a.c0 + a.c2) * (b.c0 + b.c2) - v0 - v2 + v1
|
# r.c2 = (a.c0 + a.c2) * (b.c0 + b.c2) - v0 - v2 + v1
|
||||||
r.c2.sum(a.c0, a.c2)
|
r.c2.sum(a.c0, a.c2)
|
||||||
@ -124,9 +78,13 @@ func prod*[C](r: var Fp6[C], a, b: Fp6[C]) =
|
|||||||
r.c2 -= v2
|
r.c2 -= v2
|
||||||
r.c2 += v1
|
r.c2 += v1
|
||||||
|
|
||||||
func inv*[C](r: var Fp6[C], a: Fp6[C]) =
|
func inv*(r: var CubicExt, a: CubicExt) =
|
||||||
## Compute the multiplicative inverse of ``a``
|
## Compute the multiplicative inverse of ``a``
|
||||||
## in 𝔽p6 = 𝔽p2[∛(1 + 𝑖)]
|
##
|
||||||
|
## The inverse of 0 is 0.
|
||||||
|
## Incidentally this avoids extra check
|
||||||
|
## to convert Jacobian and Projective coordinates
|
||||||
|
## to affine for elliptic curve
|
||||||
#
|
#
|
||||||
# Algorithm 5.23
|
# Algorithm 5.23
|
||||||
#
|
#
|
||||||
@ -139,20 +97,19 @@ func inv*[C](r: var Fp6[C], a: Fp6[C]) =
|
|||||||
# instead of 9, because 5 * 2 (𝔽p2) * Bitsize would be:
|
# instead of 9, because 5 * 2 (𝔽p2) * Bitsize would be:
|
||||||
# - ~2540 bits for BN254
|
# - ~2540 bits for BN254
|
||||||
# - ~3810 bits for BLS12-381
|
# - ~3810 bits for BLS12-381
|
||||||
var
|
var v1 {.noInit.}, v2 {.noInit.}, v3 {.noInit.}: typeof(r.c0)
|
||||||
v1 {.noInit.}, v2 {.noInit.}, v3 {.noInit.}: Fp2[C]
|
|
||||||
|
|
||||||
# A in r0
|
# A in r0
|
||||||
# A <- a0² - ξ(a1 a2)
|
# A <- a0² - β a1 a2
|
||||||
r.c0.square(a.c0)
|
r.c0.square(a.c0)
|
||||||
v1.prod(a.c1, a.c2)
|
v1.prod(a.c1, a.c2)
|
||||||
v1 *= Xi
|
v1 *= β
|
||||||
r.c0 -= v1
|
r.c0 -= v1
|
||||||
|
|
||||||
# B in v1
|
# B in v1
|
||||||
# B <- ξ a2² - a0 a1
|
# B <- β a2² - a0 a1
|
||||||
v1.square(a.c2)
|
v1.square(a.c2)
|
||||||
v1 *= Xi
|
v1 *= β
|
||||||
v2.prod(a.c0, a.c1)
|
v2.prod(a.c0, a.c1)
|
||||||
v1 -= v2
|
v1 -= v2
|
||||||
|
|
||||||
@ -163,9 +120,9 @@ func inv*[C](r: var Fp6[C], a: Fp6[C]) =
|
|||||||
v2 -= v3
|
v2 -= v3
|
||||||
|
|
||||||
# F in v3
|
# F in v3
|
||||||
# F <- ξ a1 C + a0 A + ξ a2 B
|
# F <- β a1 C + a0 A + β a2 B
|
||||||
r.c1.prod(v1, Xi * a.c2)
|
r.c1.prod(v1, β * a.c2)
|
||||||
r.c2.prod(v2, Xi * a.c1)
|
r.c2.prod(v2, β * a.c1)
|
||||||
v3.prod(r.c0, a.c0)
|
v3.prod(r.c0, a.c0)
|
||||||
v3 += r.c1
|
v3 += r.c1
|
||||||
v3 += r.c2
|
v3 += r.c2
|
||||||
@ -177,10 +134,9 @@ func inv*[C](r: var Fp6[C], a: Fp6[C]) =
|
|||||||
r.c1.prod(v1, v3)
|
r.c1.prod(v1, v3)
|
||||||
r.c2.prod(v2, v3)
|
r.c2.prod(v2, v3)
|
||||||
|
|
||||||
func `*=`*(a: var Fp6, b: Fp6) {.inline.} =
|
func `*=`*(a: var CubicExt, b: CubicExt) {.inline.} =
|
||||||
# Need to ensure different buffers for ``a`` and result
|
## In-place multiplication
|
||||||
|
# On higher extension field like 𝔽p6,
|
||||||
|
# if `prod` is called on shared in and out buffer, the result is wrong
|
||||||
let t = a
|
let t = a
|
||||||
a.prod(t, b)
|
a.prod(t, b)
|
||||||
|
|
||||||
func `*`*(a, b: Fp6): Fp6 {.inline, noInit.} =
|
|
||||||
result.prod(a, b)
|
|
@ -1,153 +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.
|
|
||||||
|
|
||||||
# ############################################################
|
|
||||||
#
|
|
||||||
# Quadratic Extension field over extension field 𝔽p6
|
|
||||||
# 𝔽p12 = 𝔽p6[√γ]
|
|
||||||
# with γ the cubic root of the non-residue of 𝔽p6
|
|
||||||
#
|
|
||||||
# ############################################################
|
|
||||||
|
|
||||||
# This implements a quadratic extension field over
|
|
||||||
# 𝔽p12 = 𝔽p6[γ]
|
|
||||||
# with γ the cubic root of the non-residue of 𝔽p6
|
|
||||||
# with element A of coordinates (a0, a1) represented
|
|
||||||
# by a0 + a1 γ
|
|
||||||
#
|
|
||||||
# The irreducible polynomial chosen is
|
|
||||||
# w² - γ
|
|
||||||
# with γ the cubic root of the non-residue of 𝔽p6
|
|
||||||
# I.e. if 𝔽p6 irreducible polynomial is
|
|
||||||
# v³ - ξ with ξ = 1+𝑖
|
|
||||||
# γ = v = ∛(1 + 𝑖)
|
|
||||||
#
|
|
||||||
# Consequently, for this file 𝔽p12 to be valid
|
|
||||||
# ∛(1 + 𝑖) MUST not be a square in 𝔽p6
|
|
||||||
|
|
||||||
import
|
|
||||||
../arithmetic,
|
|
||||||
../config/curves,
|
|
||||||
./abelian_groups,
|
|
||||||
./fp6_1_plus_i
|
|
||||||
|
|
||||||
type
|
|
||||||
Fp12*[C: static Curve] = object
|
|
||||||
## Element of the extension field
|
|
||||||
## 𝔽p12 = 𝔽p6[γ]
|
|
||||||
##
|
|
||||||
## I.e. if 𝔽p6 irreducible polynomial is
|
|
||||||
## v³ - ξ with ξ = 1+𝑖
|
|
||||||
## γ = v = ∛(1 + 𝑖)
|
|
||||||
##
|
|
||||||
## with coordinates (c0, c1) such as
|
|
||||||
## c0 + c1 w
|
|
||||||
c0*, c1*: Fp6[C]
|
|
||||||
|
|
||||||
Gamma = object
|
|
||||||
## γ (Gamma) the quadratic non-residue of 𝔽p6
|
|
||||||
## γ = v with v the factor in for 𝔽p6 coordinate
|
|
||||||
## i.e. a point in 𝔽p6 as coordinates a0 + a1 v + a2 v²
|
|
||||||
|
|
||||||
func `*`(_: typedesc[Gamma], a: Fp6): Fp6 {.noInit, inline.} =
|
|
||||||
## Multiply an element of 𝔽p6 by 𝔽p12 quadratic non-residue
|
|
||||||
## Conveniently γ = v with v the factor in for 𝔽p6 coordinate
|
|
||||||
## and v³ = ξ
|
|
||||||
## (c0 + c1 v + c2 v²) v => ξ c2 + c0 v + c1 v²
|
|
||||||
discard
|
|
||||||
|
|
||||||
result.c0 = a.c2 * Xi
|
|
||||||
result.c1 = a.c0
|
|
||||||
result.c2 = a.c1
|
|
||||||
|
|
||||||
template `*`(a: Fp6, _: typedesc[Gamma]): Fp6 =
|
|
||||||
Gamma * a
|
|
||||||
|
|
||||||
func `*=`(a: var Fp6, _: typedesc[Gamma]) {.inline.} =
|
|
||||||
a = Gamma * a
|
|
||||||
|
|
||||||
func square*(r: var Fp12, a: Fp12) =
|
|
||||||
## Return a² in ``r``
|
|
||||||
## ``r`` is initialized/overwritten
|
|
||||||
# (c0, c1)² => (c0 + c1 w)²
|
|
||||||
# => c0² + 2 c0 c1 w + c1²w²
|
|
||||||
# => c0² + γ c1² + 2 c0 c1 w
|
|
||||||
# => (c0² + γ c1², 2 c0 c1)
|
|
||||||
# We have 2 squarings and 1 multiplication in 𝔽p6
|
|
||||||
# which are significantly more costly:
|
|
||||||
# - 4 limbs like BN254: multiplication is 20x slower than addition/substraction
|
|
||||||
# - 6 limbs like BLS12-381: multiplication is 28x slower than addition/substraction
|
|
||||||
#
|
|
||||||
# We can save operations with one of the following expressions
|
|
||||||
# of c0² + γ c1² and noticing that c0c1 is already computed for the "y" coordinate
|
|
||||||
#
|
|
||||||
# Alternative 1:
|
|
||||||
# c0² + γ c1² <=> (c0 - c1)(c0 - γ c1) + γ c0c1 + c0c1
|
|
||||||
#
|
|
||||||
# Alternative 2:
|
|
||||||
# c0² + γ c1² <=> (c0 + c1)(c0 + γ c1) - γ c0c1 - c0c1
|
|
||||||
|
|
||||||
# r0 <- (c0 + c1)(c0 + γ c1)
|
|
||||||
r.c0.sum(a.c0, a.c1)
|
|
||||||
r.c1.sum(a.c0, Gamma * a.c1)
|
|
||||||
r.c0 *= r.c1
|
|
||||||
|
|
||||||
# r1 <- c0 c1
|
|
||||||
r.c1.prod(a.c0, a.c1)
|
|
||||||
|
|
||||||
# r0 = (c0 + c1)(c0 + γ c1) - γ c0c1 - c0c1
|
|
||||||
r.c0 -= Gamma * r.c1
|
|
||||||
r.c0 -= r.c1
|
|
||||||
|
|
||||||
# r1 = 2 c0c1
|
|
||||||
r.c1.double()
|
|
||||||
|
|
||||||
func prod*[C](r: var Fp12[C], a, b: Fp12[C]) =
|
|
||||||
## Returns r = a * b
|
|
||||||
# r0 = a0 b0 + γ a1 b1
|
|
||||||
# r1 = (a0 + a1) (b0 + b1) - a0 b0 - a1 b1 (Karatsuba)
|
|
||||||
var t {.noInit.}: Fp6[C]
|
|
||||||
|
|
||||||
# r1 <- (a0 + a1)(b0 + b1)
|
|
||||||
r.c0.sum(a.c0, a.c1)
|
|
||||||
t.sum(b.c0, b.c1)
|
|
||||||
r.c1.prod(r.c0, t)
|
|
||||||
|
|
||||||
# r0 <- a0 b0
|
|
||||||
# r1 <- (a0 + a1)(b0 + b1) - a0 b0 - a1 b1
|
|
||||||
r.c0.prod(a.c0, b.c0)
|
|
||||||
t.prod(a.c1, b.c1)
|
|
||||||
r.c1 -= r.c0
|
|
||||||
r.c1 -= t
|
|
||||||
|
|
||||||
# r0 <- a0 b0 + γ a1 b1
|
|
||||||
r.c0 += Gamma * t
|
|
||||||
|
|
||||||
func inv*[C](r: var Fp12[C], a: Fp12[C]) =
|
|
||||||
## Compute the multiplicative inverse of ``a``
|
|
||||||
#
|
|
||||||
# Algorithm: (the inverse exist if a != 0 which might cause constant-time issue)
|
|
||||||
#
|
|
||||||
# 1 / (a0 + a1 w) <=> (a0 - a1 w) / (a0 + a1 w)(a0 - a1 w)
|
|
||||||
# <=> (a0 - a1 w) / (a0² - a1² w²)
|
|
||||||
# In our case 𝔽p12 = 𝔽p6[γ], we have w² = γ
|
|
||||||
# So the inverse is (a0 - a1 w) / (a0² - γ a1²)
|
|
||||||
|
|
||||||
# [2 Sqr, 1 Add]
|
|
||||||
var v0 {.noInit.}, v1 {.noInit.}: Fp6[C]
|
|
||||||
v0.square(a.c0)
|
|
||||||
v1.square(a.c1)
|
|
||||||
v0 -= Gamma * v1 # v0 = a0² - γ a1² (the norm / squared magnitude of a)
|
|
||||||
|
|
||||||
# [1 Inv, 2 Sqr, 1 Add]
|
|
||||||
v1.inv(v0) # v1 = 1 / (a0² - γ a1²)
|
|
||||||
|
|
||||||
# [1 Inv, 2 Mul, 2 Sqr, 1 Add, 1 Neg]
|
|
||||||
r.c0.prod(a.c0, v1) # r0 = a0 / (a0² - γ a1²)
|
|
||||||
v0.neg(v1) # v0 = -1 / (a0² - γ a1²)
|
|
||||||
r.c1.prod(a.c1, v0) # r1 = -a1 / (a0² - γ a1²)
|
|
@ -1,169 +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.
|
|
||||||
|
|
||||||
# ############################################################
|
|
||||||
#
|
|
||||||
# Quadratic Extension field over base field 𝔽p
|
|
||||||
# 𝔽p2 = 𝔽p[𝑖]
|
|
||||||
#
|
|
||||||
# ############################################################
|
|
||||||
|
|
||||||
# This implements a quadratic extension field over
|
|
||||||
# the base field 𝔽p:
|
|
||||||
# 𝔽p2 = 𝔽p[x]
|
|
||||||
# with element A of coordinates (a0, a1) represented
|
|
||||||
# by a0 + a1 x
|
|
||||||
#
|
|
||||||
# The irreducible polynomial chosen is
|
|
||||||
# x² - µ with µ = -1
|
|
||||||
# i.e. 𝔽p2 = 𝔽p[𝑖], 𝑖 being the imaginary unit
|
|
||||||
#
|
|
||||||
# Consequently, for this file Fp2 to be valid
|
|
||||||
# -1 MUST not be a square in 𝔽p
|
|
||||||
#
|
|
||||||
# µ is also chosen to simplify multiplication and squaring
|
|
||||||
# => A(a0, a1) * B(b0, b1)
|
|
||||||
# => (a0 + a1 x) * (b0 + b1 x)
|
|
||||||
# => a0 b0 + (a0 b1 + a1 b0) x + a1 b1 x²
|
|
||||||
# We need x² to be as cheap as possible
|
|
||||||
#
|
|
||||||
# References
|
|
||||||
# [1] Constructing Tower Extensions for the implementation of Pairing-Based Cryptography\
|
|
||||||
# Naomi Benger and Michael Scott, 2009\
|
|
||||||
# https://eprint.iacr.org/2009/556
|
|
||||||
#
|
|
||||||
# [2] Choosing and generating parameters for low level pairing implementation on BN curves\
|
|
||||||
# Sylvain Duquesne and Nadia El Mrabet and Safia Haloui and Franck Rondepierre, 2015\
|
|
||||||
# https://eprint.iacr.org/2015/1212
|
|
||||||
|
|
||||||
# TODO: Clarify some assumptions about the prime p ≡ 3 (mod 4)
|
|
||||||
|
|
||||||
import
|
|
||||||
../arithmetic,
|
|
||||||
../config/curves,
|
|
||||||
./abelian_groups
|
|
||||||
|
|
||||||
type
|
|
||||||
Fp2*[C: static Curve] = object
|
|
||||||
## Element of the extension field
|
|
||||||
## 𝔽p2 = 𝔽p[𝑖] of a prime p
|
|
||||||
##
|
|
||||||
## with coordinates (c0, c1) such as
|
|
||||||
## c0 + c1 𝑖
|
|
||||||
##
|
|
||||||
## This requires 𝑖² = -1 to not
|
|
||||||
## be a square (mod p)
|
|
||||||
c0*, c1*: Fp[C]
|
|
||||||
|
|
||||||
func square*(r: var Fp2, a: Fp2) =
|
|
||||||
## Return a² in 𝔽p2 = 𝔽p[𝑖] in ``r``
|
|
||||||
## ``r`` is initialized/overwritten
|
|
||||||
# (c0, c1)² => (c0 + c1𝑖)²
|
|
||||||
# => c0² + 2 c0 c1𝑖 + (c1𝑖)²
|
|
||||||
# => c0²-c1² + 2 c0 c1𝑖
|
|
||||||
# => (c0²-c1², 2 c0 c1)
|
|
||||||
# or
|
|
||||||
# => ((c0-c1)(c0+c1), 2 c0 c1)
|
|
||||||
# => ((c0-c1)(c0-c1 + 2 c1), c0 * 2 c1)
|
|
||||||
#
|
|
||||||
# Costs (naive implementation)
|
|
||||||
# - 1 Multiplication 𝔽p
|
|
||||||
# - 2 Squarings 𝔽p
|
|
||||||
# - 1 Doubling 𝔽p
|
|
||||||
# - 1 Substraction 𝔽p
|
|
||||||
# Stack: 4 * ModulusBitSize (4x 𝔽p element)
|
|
||||||
#
|
|
||||||
# Or (with 1 less Mul/Squaring at the cost of 1 addition and extra 2 𝔽p stack space)
|
|
||||||
#
|
|
||||||
# - 2 Multiplications 𝔽p
|
|
||||||
# - 1 Addition 𝔽p
|
|
||||||
# - 1 Doubling 𝔽p
|
|
||||||
# - 1 Substraction 𝔽p
|
|
||||||
# Stack: 6 * ModulusBitSize (4x 𝔽p element + 1 named temporaries + 1 in-place multiplication temporary)
|
|
||||||
# as in-place multiplications require a (shared) internal temporary
|
|
||||||
|
|
||||||
var c0mc1 {.noInit.}: Fp[Fp2.C]
|
|
||||||
c0mc1.diff(a.c0, a.c1) # c0mc1 = c0 - c1 [1 Sub]
|
|
||||||
r.c1.double(a.c1) # result.c1 = 2 c1 [1 Dbl, 1 Sub]
|
|
||||||
r.c0.sum(c0mc1, r.c1) # result.c0 = c0 - c1 + 2 c1 [1 Add, 1 Dbl, 1 Sub]
|
|
||||||
r.c0 *= c0mc1 # result.c0 = (c0 + c1)(c0 - c1) = c0² - c1² [1 Mul, 1 Add, 1 Dbl, 1 Sub] - 𝔽p temporary
|
|
||||||
r.c1 *= a.c0 # result.c1 = 2 c1 c0 [2 Mul, 1 Add, 1 Dbl, 1 Sub] - 𝔽p temporary
|
|
||||||
|
|
||||||
func prod*(r: var Fp2, a, b: Fp2) =
|
|
||||||
## Return a * b in 𝔽p2 = 𝔽p[𝑖] in ``r``
|
|
||||||
## ``r`` is initialized/overwritten
|
|
||||||
# (a0, a1) (b0, b1) => (a0 + a1𝑖) (b0 + b1𝑖)
|
|
||||||
# => (a0 b0 - a1 b1) + (a0 b1 + a1 b0) 𝑖
|
|
||||||
#
|
|
||||||
# In Fp, multiplication has cost O(n²) with n the number of limbs
|
|
||||||
# while addition has cost O(3n) (n for addition, n for overflow, n for conditional substraction)
|
|
||||||
# and substraction has cost O(2n) (n for substraction + underflow, n for conditional addition)
|
|
||||||
#
|
|
||||||
# Even for 256-bit primes, we are looking at always a minimum of n=5 limbs (with 2^63 words)
|
|
||||||
# where addition/substraction are significantly cheaper than multiplication
|
|
||||||
#
|
|
||||||
# So we always reframe the imaginary part using Karatsuba approach to save a multiplication
|
|
||||||
# (a0, a1) (b0, b1) => (a0 b0 - a1 b1) + 𝑖( (a0 + a1)(b0 + b1) - a0 b0 - a1 b1 )
|
|
||||||
#
|
|
||||||
# Costs (naive implementation)
|
|
||||||
# - 4 Multiplications 𝔽p
|
|
||||||
# - 1 Addition 𝔽p
|
|
||||||
# - 1 Substraction 𝔽p
|
|
||||||
# Stack: 6 * ModulusBitSize (4x 𝔽p element + 2x named temporaries)
|
|
||||||
#
|
|
||||||
# Costs (Karatsuba)
|
|
||||||
# - 3 Multiplications 𝔽p
|
|
||||||
# - 3 Substraction 𝔽p (2 are fused)
|
|
||||||
# - 2 Addition 𝔽p
|
|
||||||
# Stack: 6 * ModulusBitSize (4x 𝔽p element + 2x named temporaries + 1 in-place multiplication temporary)
|
|
||||||
var a0b0 {.noInit.}, a1b1 {.noInit.}: Fp[Fp2.C]
|
|
||||||
a0b0.prod(a.c0, b.c0) # [1 Mul]
|
|
||||||
a1b1.prod(a.c1, b.c1) # [2 Mul]
|
|
||||||
|
|
||||||
r.c0.sum(a.c0, a.c1) # r0 = (a0 + a1) # [2 Mul, 1 Add]
|
|
||||||
r.c1.sum(b.c0, b.c1) # r1 = (b0 + b1) # [2 Mul, 2 Add]
|
|
||||||
r.c1 *= r.c0 # r1 = (b0 + b1)(a0 + a1) # [3 Mul, 2 Add] - 𝔽p temporary
|
|
||||||
|
|
||||||
r.c0.diff(a0b0, a1b1) # r0 = a0 b0 - a1 b1 # [3 Mul, 2 Add, 1 Sub]
|
|
||||||
r.c1 -= a0b0 # r1 = (b0 + b1)(a0 + a1) - a0b0 # [3 Mul, 2 Add, 2 Sub]
|
|
||||||
r.c1 -= a1b1 # r1 = (b0 + b1)(a0 + a1) - a0b0 - a1b1 # [3 Mul, 2 Add, 3 Sub]
|
|
||||||
|
|
||||||
func inv*(r: var Fp2, a: Fp2) =
|
|
||||||
## Compute the multiplicative inverse of ``a``
|
|
||||||
## in 𝔽p2 = 𝔽p[𝑖]
|
|
||||||
#
|
|
||||||
# Algorithm: (the inverse exist if a != 0 which might cause constant-time issue)
|
|
||||||
#
|
|
||||||
# 1 / (a0 + a1 x) <=> (a0 - a1 x) / (a0 + a1 x)(a0 - a1 x)
|
|
||||||
# <=> (a0 - a1 x) / (a0² - a1² x²)
|
|
||||||
# In our case 𝔽p2 = 𝔽p[𝑖], we have x = 𝑖
|
|
||||||
# So the inverse is (a0 - a1 𝑖) / (a0² + a1²)
|
|
||||||
|
|
||||||
# [2 Sqr, 1 Add]
|
|
||||||
var t0 {.noInit.}, t1 {.noInit.}: Fp[Fp2.C]
|
|
||||||
t0.square(a.c0)
|
|
||||||
t1.square(a.c1)
|
|
||||||
t0 += t1 # t0 = a0² + a1² (the norm / squared magnitude of a)
|
|
||||||
|
|
||||||
# [1 Inv, 2 Sqr, 1 Add]
|
|
||||||
t0.inv(t0) # t0 = 1 / (a0² + a1²)
|
|
||||||
|
|
||||||
# [1 Inv, 2 Mul, 2 Sqr, 1 Add, 1 Neg]
|
|
||||||
r.c0.prod(a.c0, t0) # r0 = a0 / (a0² + a1²)
|
|
||||||
t1.neg(t0) # t0 = -1 / (a0² + a1²)
|
|
||||||
r.c1.prod(a.c1, t1) # r1 = -a1 / (a0² + a1²)
|
|
||||||
|
|
||||||
func square*(a: var Fp2) {.inline.} =
|
|
||||||
let t = a
|
|
||||||
a.square(t)
|
|
||||||
|
|
||||||
func `*=`*(a: var Fp2, b: Fp2) {.inline.} =
|
|
||||||
a.prod(a, b)
|
|
||||||
|
|
||||||
func `*`*(a, b: Fp2): Fp2 {.inline, noInit.} =
|
|
||||||
result.prod(a, b)
|
|
@ -1,72 +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.
|
|
||||||
|
|
||||||
# ############################################################
|
|
||||||
#
|
|
||||||
# Quadratic Extension field over base field 𝔽p
|
|
||||||
# 𝔽p2 = 𝔽p[√-5]
|
|
||||||
#
|
|
||||||
# ############################################################
|
|
||||||
|
|
||||||
# This implements a quadratic extension field over
|
|
||||||
# the base field 𝔽p:
|
|
||||||
# 𝔽p2 = 𝔽p[x]
|
|
||||||
# with element A of coordinates (a0, a1) represented
|
|
||||||
# by a0 + a1 x
|
|
||||||
#
|
|
||||||
# The irreducible polynomial chosen is
|
|
||||||
# x² - µ with µ = -2
|
|
||||||
# i.e. 𝔽p2 = 𝔽p[√-2]
|
|
||||||
#
|
|
||||||
# Consequently, for this file Fp2 to be valid
|
|
||||||
# -2 MUST not be a square in 𝔽p
|
|
||||||
#
|
|
||||||
# References
|
|
||||||
# [1] Software Implementation of Pairings\
|
|
||||||
# D. Hankerson, A. Menezes, and M. Scott, 2009\
|
|
||||||
# http://cacr.uwaterloo.ca/~ajmeneze/publications/pairings_software.pdf
|
|
||||||
|
|
||||||
|
|
||||||
import
|
|
||||||
../arithmetic,
|
|
||||||
../config/curves,
|
|
||||||
./abelian_groups
|
|
||||||
|
|
||||||
type
|
|
||||||
Fp2*[C: static Curve] = object
|
|
||||||
## Element of the extension field
|
|
||||||
## 𝔽p2 = 𝔽p[√-2] of a prime p
|
|
||||||
##
|
|
||||||
## with coordinates (c0, c1) such as
|
|
||||||
## c0 + c1 √-2
|
|
||||||
##
|
|
||||||
## This requires -2 to not be a square (mod p)
|
|
||||||
c0*, c1*: Fp[C]
|
|
||||||
|
|
||||||
func square*(r: var Fp2, a: Fp2) =
|
|
||||||
## Return a^2 in 𝔽p2 in ``r``
|
|
||||||
## ``r`` is initialized/overwritten
|
|
||||||
# (c0, c1)² => (c0 + c1√-2)²
|
|
||||||
# => c0² + 2 c0 c1√-2 + (c1√-2)²
|
|
||||||
# => c0² - 2c1² + 2 c0 c1 √-2
|
|
||||||
# => (c0²-2c1², 2 c0 c1)
|
|
||||||
#
|
|
||||||
# Costs (naive implementation)
|
|
||||||
# - 2 Multiplications 𝔽p
|
|
||||||
# - 1 Squaring 𝔽p
|
|
||||||
# - 1 Doubling 𝔽p
|
|
||||||
# - 1 Substraction 𝔽p
|
|
||||||
# Stack: 6 * ModulusBitSize (4x 𝔽p element + 2 named temporaries + 1 "in-place" mul temporary)
|
|
||||||
|
|
||||||
var c1d, c0s {.noInit.}: typeof(a.c1)
|
|
||||||
c1d.double(a.c1) # c1d = 2 c1 [1 Dbl]
|
|
||||||
c0s.square(a.c0) # c0s = c0² [1 Sqr, 1 Dbl]
|
|
||||||
|
|
||||||
r.c1.prod(c1d, a.c0) # r.c1 = 2 c1 c0 [1 Mul, 1 Sqr, 1 Dbl]
|
|
||||||
c1d *= a.c1 # c1d = 2 c1² [2 Mul, 1 Sqr, 1 Dbl] - 1 "in-place" temporary
|
|
||||||
r.c0.diff(c0s, c1d) # r.c0 = c0²-2c1² [2 Mul, 1 Sqr, 1 Dbl, 1 Sub]
|
|
@ -1,52 +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.
|
|
||||||
|
|
||||||
# ############################################################
|
|
||||||
#
|
|
||||||
# Quadratic Extension field over base field 𝔽p
|
|
||||||
# 𝔽p2 = 𝔽p[√-5]
|
|
||||||
#
|
|
||||||
# ############################################################
|
|
||||||
|
|
||||||
# This implements a quadratic extension field over
|
|
||||||
# the base field 𝔽p:
|
|
||||||
# 𝔽p2 = 𝔽p[x]
|
|
||||||
# with element A of coordinates (a0, a1) represented
|
|
||||||
# by a0 + a1 x
|
|
||||||
#
|
|
||||||
# The irreducible polynomial chosen is
|
|
||||||
# x² - µ with µ = -5
|
|
||||||
# i.e. 𝔽p2 = 𝔽p[√-5]
|
|
||||||
#
|
|
||||||
# Consequently, for this file Fp2 to be valid
|
|
||||||
# -5 MUST not be a square in 𝔽p
|
|
||||||
#
|
|
||||||
# References
|
|
||||||
# [1] High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves\
|
|
||||||
# Jean-Luc Beuchat and Jorge Enrique González Díaz and Shigeo Mitsunari and Eiji Okamoto and Francisco Rodríguez-Henríquez and Tadanori Teruya, 2010\
|
|
||||||
# https://eprint.iacr.org/2010/354
|
|
||||||
|
|
||||||
import
|
|
||||||
../arithmetic,
|
|
||||||
../config/curves,
|
|
||||||
./abelian_groups
|
|
||||||
|
|
||||||
type
|
|
||||||
Fp2*[C: static Curve] = object
|
|
||||||
## Element of the extension field
|
|
||||||
## 𝔽p2 = 𝔽p[√-5] of a prime p
|
|
||||||
##
|
|
||||||
## with coordinates (c0, c1) such as
|
|
||||||
## c0 + c1 √-5
|
|
||||||
##
|
|
||||||
## This requires -5 to not be a square (mod p)
|
|
||||||
c0*, c1*: Fp[C]
|
|
||||||
|
|
||||||
# TODO: need fast multiplication by small constant
|
|
||||||
# which probably requires lazy carries
|
|
||||||
# https://github.com/mratsim/constantine/issues/15
|
|
227
constantine/tower_field_extensions/quadratic_extensions.nim
Normal file
227
constantine/tower_field_extensions/quadratic_extensions.nim
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
# Constantine
|
||||||
|
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
||||||
|
# Copyright (c) 2020-Present Mamy André-Ratsimbazafy
|
||||||
|
# Licensed and distributed under either of
|
||||||
|
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
|
||||||
|
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
|
||||||
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
|
import
|
||||||
|
../arithmetic,
|
||||||
|
../config/common,
|
||||||
|
../primitives,
|
||||||
|
./tower_common
|
||||||
|
|
||||||
|
# Commutative ring implementation for complex extension fields
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
|
||||||
|
func square_complex(r: var QuadraticExt, a: QuadraticExt) =
|
||||||
|
## Return a² in 𝔽p2 = 𝔽p[𝑖] in ``r``
|
||||||
|
## ``r`` is initialized/overwritten
|
||||||
|
##
|
||||||
|
## Requires a complex extension field
|
||||||
|
# (c0, c1)² => (c0 + c1𝑖)²
|
||||||
|
# => c0² + 2 c0 c1𝑖 + (c1𝑖)²
|
||||||
|
# => c0²-c1² + 2 c0 c1𝑖
|
||||||
|
# => (c0²-c1², 2 c0 c1)
|
||||||
|
# or
|
||||||
|
# => ((c0-c1)(c0+c1), 2 c0 c1)
|
||||||
|
# => ((c0-c1)(c0-c1 + 2 c1), c0 * 2 c1)
|
||||||
|
#
|
||||||
|
# Costs (naive implementation)
|
||||||
|
# - 1 Multiplication 𝔽p
|
||||||
|
# - 2 Squarings 𝔽p
|
||||||
|
# - 1 Doubling 𝔽p
|
||||||
|
# - 1 Substraction 𝔽p
|
||||||
|
# Stack: 4 * ModulusBitSize (4x 𝔽p element)
|
||||||
|
#
|
||||||
|
# Or (with 1 less Mul/Squaring at the cost of 1 addition and extra 2 𝔽p stack space)
|
||||||
|
#
|
||||||
|
# - 2 Multiplications 𝔽p
|
||||||
|
# - 1 Addition 𝔽p
|
||||||
|
# - 1 Doubling 𝔽p
|
||||||
|
# - 1 Substraction 𝔽p
|
||||||
|
# Stack: 6 * ModulusBitSize (4x 𝔽p element + 1 named temporaries + 1 in-place multiplication temporary)
|
||||||
|
# as in-place multiplications require a (shared) internal temporary
|
||||||
|
mixin fromComplexExtension
|
||||||
|
static: doAssert r.fromComplexExtension()
|
||||||
|
|
||||||
|
var c0mc1 {.noInit.}: typeof(r.c0)
|
||||||
|
c0mc1.diff(a.c0, a.c1) # c0mc1 = c0 - c1 [1 Sub]
|
||||||
|
r.c1.double(a.c1) # result.c1 = 2 c1 [1 Dbl, 1 Sub]
|
||||||
|
r.c0.sum(c0mc1, r.c1) # result.c0 = c0 - c1 + 2 c1 [1 Add, 1 Dbl, 1 Sub]
|
||||||
|
r.c0 *= c0mc1 # result.c0 = (c0 + c1)(c0 - c1) = c0² - c1² [1 Mul, 1 Add, 1 Dbl, 1 Sub] - 𝔽p temporary
|
||||||
|
r.c1 *= a.c0 # result.c1 = 2 c1 c0 [2 Mul, 1 Add, 1 Dbl, 1 Sub] - 𝔽p temporary
|
||||||
|
|
||||||
|
func prod_complex(r: var QuadraticExt, a, b: QuadraticExt) =
|
||||||
|
## Return a * b in 𝔽p2 = 𝔽p[𝑖] in ``r``
|
||||||
|
## ``r`` is initialized/overwritten
|
||||||
|
##
|
||||||
|
## Requires a complex extension field
|
||||||
|
# (a0, a1) (b0, b1) => (a0 + a1𝑖) (b0 + b1𝑖)
|
||||||
|
# => (a0 b0 - a1 b1) + (a0 b1 + a1 b0) 𝑖
|
||||||
|
#
|
||||||
|
# In Fp, multiplication has cost O(n²) with n the number of limbs
|
||||||
|
# while addition has cost O(3n) (n for addition, n for overflow, n for conditional substraction)
|
||||||
|
# and substraction has cost O(2n) (n for substraction + underflow, n for conditional addition)
|
||||||
|
#
|
||||||
|
# Even for 256-bit primes, we are looking at always a minimum of n=5 limbs (with 2^63 words)
|
||||||
|
# where addition/substraction are significantly cheaper than multiplication
|
||||||
|
#
|
||||||
|
# So we always reframe the imaginary part using Karatsuba approach to save a multiplication
|
||||||
|
# (a0, a1) (b0, b1) => (a0 b0 - a1 b1) + 𝑖( (a0 + a1)(b0 + b1) - a0 b0 - a1 b1 )
|
||||||
|
#
|
||||||
|
# Costs (naive implementation)
|
||||||
|
# - 4 Multiplications 𝔽p
|
||||||
|
# - 1 Addition 𝔽p
|
||||||
|
# - 1 Substraction 𝔽p
|
||||||
|
# Stack: 6 * ModulusBitSize (4x 𝔽p element + 2x named temporaries)
|
||||||
|
#
|
||||||
|
# Costs (Karatsuba)
|
||||||
|
# - 3 Multiplications 𝔽p
|
||||||
|
# - 3 Substraction 𝔽p (2 are fused)
|
||||||
|
# - 2 Addition 𝔽p
|
||||||
|
# Stack: 6 * ModulusBitSize (4x 𝔽p element + 2x named temporaries + 1 in-place multiplication temporary)
|
||||||
|
mixin fromComplexExtension
|
||||||
|
static: doAssert r.fromComplexExtension()
|
||||||
|
|
||||||
|
var a0b0 {.noInit.}, a1b1 {.noInit.}: typeof(r.c0)
|
||||||
|
a0b0.prod(a.c0, b.c0) # [1 Mul]
|
||||||
|
a1b1.prod(a.c1, b.c1) # [2 Mul]
|
||||||
|
|
||||||
|
r.c0.sum(a.c0, a.c1) # r0 = (a0 + a1) # [2 Mul, 1 Add]
|
||||||
|
r.c1.sum(b.c0, b.c1) # r1 = (b0 + b1) # [2 Mul, 2 Add]
|
||||||
|
r.c1 *= r.c0 # r1 = (b0 + b1)(a0 + a1) # [3 Mul, 2 Add] - 𝔽p temporary
|
||||||
|
|
||||||
|
r.c0.diff(a0b0, a1b1) # r0 = a0 b0 - a1 b1 # [3 Mul, 2 Add, 1 Sub]
|
||||||
|
r.c1 -= a0b0 # r1 = (b0 + b1)(a0 + a1) - a0b0 # [3 Mul, 2 Add, 2 Sub]
|
||||||
|
r.c1 -= a1b1 # r1 = (b0 + b1)(a0 + a1) - a0b0 - a1b1 # [3 Mul, 2 Add, 3 Sub]
|
||||||
|
|
||||||
|
# Commutative ring implementation for generic quadratic extension fields
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
|
||||||
|
func square_generic(r: var QuadraticExt, a: QuadraticExt) =
|
||||||
|
## Return a² in ``r``
|
||||||
|
## ``r`` is initialized/overwritten
|
||||||
|
# Algorithm (with β the non-residue in the base field)
|
||||||
|
#
|
||||||
|
# (c0, c1)² => (c0 + c1 w)²
|
||||||
|
# => c0² + 2 c0 c1 w + c1²w²
|
||||||
|
# => c0² + β c1² + 2 c0 c1 w
|
||||||
|
# => (c0² + β c1², 2 c0 c1)
|
||||||
|
# We have 2 squarings and 1 multiplication in the base field
|
||||||
|
# which are significantly more costly than additions.
|
||||||
|
# For example when construction 𝔽p12 from 𝔽p6:
|
||||||
|
# - 4 limbs like BN254: multiplication is 20x slower than addition/substraction
|
||||||
|
# - 6 limbs like BLS12-381: multiplication is 28x slower than addition/substraction
|
||||||
|
#
|
||||||
|
# We can save operations with one of the following expressions
|
||||||
|
# of c0² + β c1² and noticing that c0c1 is already computed for the "y" coordinate
|
||||||
|
#
|
||||||
|
# Alternative 1:
|
||||||
|
# c0² + β c1² <=> (c0 - c1)(c0 - β c1) + β c0c1 + c0c1
|
||||||
|
#
|
||||||
|
# Alternative 2:
|
||||||
|
# c0² + β c1² <=> (c0 + c1)(c0 + β c1) - β c0c1 - c0c1
|
||||||
|
mixin prod
|
||||||
|
|
||||||
|
# r0 <- (c0 + c1)(c0 + β c1)
|
||||||
|
r.c0.sum(a.c0, a.c1)
|
||||||
|
r.c1.sum(a.c0, β * a.c1)
|
||||||
|
r.c0 *= r.c1
|
||||||
|
|
||||||
|
# r1 <- c0 c1
|
||||||
|
r.c1.prod(a.c0, a.c1)
|
||||||
|
|
||||||
|
# r0 = (c0 + c1)(c0 + β c1) - β c0c1 - c0c1
|
||||||
|
r.c0 -= β * r.c1
|
||||||
|
r.c0 -= r.c1
|
||||||
|
|
||||||
|
# r1 = 2 c0c1
|
||||||
|
r.c1.double()
|
||||||
|
|
||||||
|
func prod_generic(r: var QuadraticExt, a, b: QuadraticExt) =
|
||||||
|
## Returns r = a * b
|
||||||
|
# Algorithm (with β the non-residue in the base field)
|
||||||
|
#
|
||||||
|
# r0 = a0 b0 + β a1 b1
|
||||||
|
# r1 = (a0 + a1) (b0 + b1) - a0 b0 - a1 b1 (Karatsuba)
|
||||||
|
mixin prod
|
||||||
|
var t {.noInit.}: typeof(r.c0)
|
||||||
|
|
||||||
|
# r1 <- (a0 + a1)(b0 + b1)
|
||||||
|
r.c0.sum(a.c0, a.c1)
|
||||||
|
t.sum(b.c0, b.c1)
|
||||||
|
r.c1.prod(r.c0, t)
|
||||||
|
|
||||||
|
# r0 <- a0 b0
|
||||||
|
# r1 <- (a0 + a1)(b0 + b1) - a0 b0 - a1 b1
|
||||||
|
r.c0.prod(a.c0, b.c0)
|
||||||
|
t.prod(a.c1, b.c1)
|
||||||
|
r.c1 -= r.c0
|
||||||
|
r.c1 -= t
|
||||||
|
|
||||||
|
# r0 <- a0 b0 + β a1 b1
|
||||||
|
r.c0 += β * t
|
||||||
|
|
||||||
|
# Exported symbols
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
|
||||||
|
func square*(r: var QuadraticExt, a: QuadraticExt) {.inline.} =
|
||||||
|
mixin fromComplexExtension
|
||||||
|
when r.fromComplexExtension():
|
||||||
|
r.square_complex(a)
|
||||||
|
else:
|
||||||
|
r.square_generic(a)
|
||||||
|
|
||||||
|
func prod*(r: var QuadraticExt, a, b: QuadraticExt) {.inline.} =
|
||||||
|
mixin fromComplexExtension
|
||||||
|
when r.fromComplexExtension():
|
||||||
|
r.prod_complex(a, b)
|
||||||
|
else:
|
||||||
|
r.prod_generic(a, b)
|
||||||
|
|
||||||
|
func inv*(r: var QuadraticExt, a: QuadraticExt) =
|
||||||
|
## Compute the multiplicative inverse of ``a``
|
||||||
|
##
|
||||||
|
## The inverse of 0 is 0.
|
||||||
|
## Incidentally this avoids extra check
|
||||||
|
## to convert Jacobian and Projective coordinates
|
||||||
|
## to affine for elliptic curve
|
||||||
|
#
|
||||||
|
# Algorithm:
|
||||||
|
#
|
||||||
|
# 1 / (a0 + a1 w) <=> (a0 - a1 w) / (a0 + a1 w)(a0 - a1 w)
|
||||||
|
# <=> (a0 - a1 w) / (a0² - a1² w²)
|
||||||
|
# with w being our coordinate system and β the quadratic non-residue
|
||||||
|
# we have w² = β
|
||||||
|
# So the inverse is (a0 - a1 w) / (a0² - β a1²)
|
||||||
|
mixin fromComplexExtension
|
||||||
|
|
||||||
|
# [2 Sqr, 1 Add]
|
||||||
|
var v0 {.noInit.}, v1 {.noInit.}: typeof(r.c0)
|
||||||
|
v0.square(a.c0)
|
||||||
|
v1.square(a.c1)
|
||||||
|
when r.fromComplexExtension():
|
||||||
|
v0 += v1
|
||||||
|
else:
|
||||||
|
v0 -= β * v1 # v0 = a0² - β a1² (the norm / squared magnitude of a)
|
||||||
|
|
||||||
|
# [1 Inv, 2 Sqr, 1 Add]
|
||||||
|
v1.inv(v0) # v1 = 1 / (a0² - β a1²)
|
||||||
|
|
||||||
|
# [1 Inv, 2 Mul, 2 Sqr, 1 Add, 1 Neg]
|
||||||
|
r.c0.prod(a.c0, v1) # r0 = a0 / (a0² - β a1²)
|
||||||
|
v0.neg(v1) # v0 = -1 / (a0² - β a1²)
|
||||||
|
r.c1.prod(a.c1, v0) # r1 = -a1 / (a0² - β a1²)
|
||||||
|
|
||||||
|
func `*=`*(a: var QuadraticExt, b: QuadraticExt) {.inline.} =
|
||||||
|
## In-place multiplication
|
||||||
|
# On higher extension field like 𝔽p12,
|
||||||
|
# if `prod` is called on shared in and out buffer, the result is wrong
|
||||||
|
let t = a
|
||||||
|
a.prod(t, b)
|
||||||
|
|
||||||
|
func square*(a: var QuadraticExt){.inline.} =
|
||||||
|
let t = a
|
||||||
|
a.square(t)
|
116
constantine/tower_field_extensions/tower_common.nim
Normal file
116
constantine/tower_field_extensions/tower_common.nim
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
# 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/common,
|
||||||
|
../primitives,
|
||||||
|
../arithmetic
|
||||||
|
|
||||||
|
# Note: to avoid burdening the Nim compiler, we rely on generic extension
|
||||||
|
# to complain if the base field procedures don't exist
|
||||||
|
|
||||||
|
# Common type definition
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
|
||||||
|
type
|
||||||
|
β* = object
|
||||||
|
## Non-Residue β
|
||||||
|
##
|
||||||
|
## Placeholder for the appropriate quadratic or cubic non-residue
|
||||||
|
|
||||||
|
CubicExt* = concept x
|
||||||
|
## Cubic Extension field concept
|
||||||
|
type BaseField = auto
|
||||||
|
x.c0 is BaseField
|
||||||
|
x.c1 is BaseField
|
||||||
|
x.c2 is BaseField
|
||||||
|
|
||||||
|
QuadraticExt* = concept x
|
||||||
|
## Quadratic Extension field concept
|
||||||
|
not(x is CubicExt)
|
||||||
|
|
||||||
|
type BaseField = auto
|
||||||
|
x.c0 is BaseField
|
||||||
|
x.c1 is BaseField
|
||||||
|
|
||||||
|
ExtensionField = QuadraticExt or CubicExt
|
||||||
|
|
||||||
|
# Initialization
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
|
||||||
|
func setZero*(a: var ExtensionField) =
|
||||||
|
## Set ``a`` to 0 in the extension field
|
||||||
|
for field in fields(a):
|
||||||
|
field.setZero()
|
||||||
|
|
||||||
|
func setOne*(a: var ExtensionField) =
|
||||||
|
## Set ``a`` to 1 in the extension field
|
||||||
|
for fieldName, fA in fieldPairs(a):
|
||||||
|
when fieldName == "c0":
|
||||||
|
fA.setOne()
|
||||||
|
else:
|
||||||
|
fA.setZero()
|
||||||
|
|
||||||
|
# Comparison
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
|
||||||
|
func `==`*(a, b: ExtensionField): CTBool[Word] =
|
||||||
|
## Constant-time equality check
|
||||||
|
result = CtFalse
|
||||||
|
for fA, fB in fields(a, b):
|
||||||
|
result = result or (fA == fB)
|
||||||
|
|
||||||
|
# Abelian group
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
|
||||||
|
func `+=`*(a: var ExtensionField, b: ExtensionField) =
|
||||||
|
## Addition in the extension field
|
||||||
|
for fA, fB in fields(a, b):
|
||||||
|
fA += fB
|
||||||
|
|
||||||
|
func `-=`*(a: var ExtensionField, b: ExtensionField) =
|
||||||
|
## Substraction in the extension field
|
||||||
|
for fA, fB in fields(a, b):
|
||||||
|
fA -= fB
|
||||||
|
|
||||||
|
func double*(r: var ExtensionField, a: ExtensionField) =
|
||||||
|
## Field out-of-place doubling
|
||||||
|
for fR, fA in fields(r, a):
|
||||||
|
fR.double(fA)
|
||||||
|
|
||||||
|
func double*(a: var ExtensionField) =
|
||||||
|
## Field in-place doubling
|
||||||
|
for fA in fields(a):
|
||||||
|
fA.double()
|
||||||
|
|
||||||
|
func neg*(r: var ExtensionField, a: ExtensionField) =
|
||||||
|
## Field out-of-place negation
|
||||||
|
for fR, fA in fields(r, a):
|
||||||
|
fR.neg(fA)
|
||||||
|
|
||||||
|
func sum*(r: var QuadraticExt, a, b: QuadraticExt) =
|
||||||
|
## Sum ``a`` and ``b`` into ``r``
|
||||||
|
r.c0.sum(a.c0, b.c0)
|
||||||
|
r.c1.sum(a.c1, b.c1)
|
||||||
|
|
||||||
|
func sum*(r: var CubicExt, a, b: CubicExt) =
|
||||||
|
## Sum ``a`` and ``b`` into ``r``
|
||||||
|
r.c0.sum(a.c0, b.c0)
|
||||||
|
r.c1.sum(a.c1, b.c1)
|
||||||
|
r.c2.sum(a.c2, b.c2)
|
||||||
|
|
||||||
|
func diff*(r: var QuadraticExt, a, b: QuadraticExt) =
|
||||||
|
## Diff ``a`` and ``b`` into ``r``
|
||||||
|
r.c0.sum(a.c0, b.c0)
|
||||||
|
r.c1.sum(a.c1, b.c1)
|
||||||
|
|
||||||
|
func diff*(r: var CubicExt, a, b: CubicExt) =
|
||||||
|
## Diff ``a`` and ``b`` into ``r``
|
||||||
|
r.c0.sum(a.c0, b.c0)
|
||||||
|
r.c1.sum(a.c1, b.c1)
|
||||||
|
r.c2.sum(a.c2, b.c2)
|
@ -7,15 +7,119 @@
|
|||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import
|
import
|
||||||
tower_field_extensions/[
|
./arithmetic,
|
||||||
abelian_groups,
|
./config/curves,
|
||||||
fp2_complex,
|
./tower_field_extensions/[
|
||||||
fp6_1_plus_i,
|
tower_common,
|
||||||
fp12_quad_fp6
|
quadratic_extensions,
|
||||||
|
cubic_extensions
|
||||||
]
|
]
|
||||||
|
|
||||||
export
|
export tower_common, quadratic_extensions, cubic_extensions
|
||||||
abelian_groups,
|
|
||||||
fp2_complex,
|
# 𝔽p2
|
||||||
fp6_1_plus_i,
|
# ----------------------------------------------------------------
|
||||||
fp12_quad_fp6
|
|
||||||
|
type
|
||||||
|
Fp2*[C: static Curve] = object
|
||||||
|
c0*, c1*: Fp[C]
|
||||||
|
|
||||||
|
template fromComplexExtension*[F](elem: F): static bool =
|
||||||
|
## Returns true if the input is a complex extension
|
||||||
|
## i.e. the irreducible polynomial chosen is
|
||||||
|
## x² - µ with µ = -1
|
||||||
|
## and so 𝔽p2 = 𝔽p[x] / x² - µ = 𝔽p[𝑖]
|
||||||
|
when F is Fp2 and F.C.get_QNR_Fp() == -1:
|
||||||
|
true
|
||||||
|
else:
|
||||||
|
false
|
||||||
|
|
||||||
|
func `*=`*(a: var Fp, _: typedesc[β]) {.inline.} =
|
||||||
|
## Multiply an element of 𝔽p by the quadratic non-residue
|
||||||
|
## chosen to construct 𝔽p2
|
||||||
|
static: doAssert Fp.C.get_QNR_Fp() != -1, "𝔽p2 should be specialized for complex extension"
|
||||||
|
a *= Fp.C.get_QNR_Fp()
|
||||||
|
|
||||||
|
func `*`*(_: typedesc[β], a: Fp): Fp {.inline, noInit.} =
|
||||||
|
## Multiply an element of 𝔽p by the quadratic non-residue
|
||||||
|
## chosen to construct 𝔽p2
|
||||||
|
result = a
|
||||||
|
result *= β
|
||||||
|
|
||||||
|
# 𝔽p6
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
|
||||||
|
type
|
||||||
|
Fp6*[C: static Curve] = object
|
||||||
|
c0*, c1*, c2*: Fp2[C]
|
||||||
|
|
||||||
|
ξ = β
|
||||||
|
# We call the non-residue ξ on 𝔽p6 to avoid confusion between non-residue
|
||||||
|
# of different tower level
|
||||||
|
|
||||||
|
func `*`*(_: typedesc[β], a: Fp2): Fp2 {.inline, noInit.} =
|
||||||
|
## Multiply an element of 𝔽p2 by the cubic non-residue
|
||||||
|
## chosen to construct 𝔽p6
|
||||||
|
# Yet another const tuple unpacking bug
|
||||||
|
const u = Fp2.C.get_CNR_Fp2()[0] # Cubic non-residue to construct 𝔽p6
|
||||||
|
const v = Fp2.C.get_CNR_Fp2()[1]
|
||||||
|
const Beta = Fp2.C.get_QNR_Fp() # Quadratic non-residue to construct 𝔽p2
|
||||||
|
# ξ = u + v x
|
||||||
|
# and x² = β
|
||||||
|
#
|
||||||
|
# (c0 + c1 x) (u + v x) => u c0 + (u c0 + u c1)x + v c1 x²
|
||||||
|
# => u c0 + β v c1 + (v c0 + u c1) x
|
||||||
|
|
||||||
|
# TODO: check code generated when ξ = 1 + 𝑖
|
||||||
|
# The mul by constant are inline but
|
||||||
|
# since we don't have __restrict tag
|
||||||
|
# and we use arrays (which decay into pointer)
|
||||||
|
# the compiler might not elide the temporary
|
||||||
|
when a.fromComplexExtension():
|
||||||
|
result.c0.diff(u * a.c0, v * a.c1)
|
||||||
|
else:
|
||||||
|
result.c0.sum(u * a.c0, (Beta * v) * a.c1)
|
||||||
|
result.c1.sum(v * a.c0, u * a.c1 )
|
||||||
|
|
||||||
|
func `*=`*(a: var Fp2, _: typedesc[ξ]) {.inline.} =
|
||||||
|
## Multiply an element of 𝔽p by the quadratic non-residue
|
||||||
|
## chosen to construct 𝔽p2
|
||||||
|
# Yet another const tuple unpacking bug
|
||||||
|
const u = Fp2.C.get_CNR_Fp2()[0] # Cubic non-residue to construct 𝔽p6
|
||||||
|
const v = Fp2.C.get_CNR_Fp2()[1]
|
||||||
|
const Beta = Fp2.C.get_QNR_Fp() # Quadratic non-residue to construct 𝔽p2
|
||||||
|
# ξ = u + v x
|
||||||
|
# and x² = β
|
||||||
|
#
|
||||||
|
# (c0 + c1 x) (u + v x) => u c0 + (u c0 + u c1)x + v c1 x²
|
||||||
|
# => u c0 + β v c1 + (v c0 + u c1) x
|
||||||
|
when a.fromComplexExtension() and u == 1 and v == 1:
|
||||||
|
let t = a.c0
|
||||||
|
a.c0 -= a.c1
|
||||||
|
a.c1 += t
|
||||||
|
else: # TODO: optim for inline
|
||||||
|
a = ξ * a
|
||||||
|
|
||||||
|
# 𝔽p12
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
|
||||||
|
type
|
||||||
|
Fp12*[C: static Curve] = object
|
||||||
|
c0*, c1*: Fp6[C]
|
||||||
|
|
||||||
|
γ = β
|
||||||
|
# We call the non-residue γ (Gamma) on 𝔽p6 to avoid confusion between non-residue
|
||||||
|
# of different tower level
|
||||||
|
|
||||||
|
func `*`*(_: typedesc[γ], a: Fp6): Fp6 {.noInit, inline.} =
|
||||||
|
## Multiply an element of 𝔽p6 by the cubic non-residue
|
||||||
|
## chosen to construct 𝔽p12
|
||||||
|
## For all curves γ = v with v the factor for 𝔽p6 coordinate
|
||||||
|
## and v³ = ξ
|
||||||
|
## (c0 + c1 v + c2 v²) v => ξ c2 + c0 v + c1 v²
|
||||||
|
result.c0 = ξ * a.c2
|
||||||
|
result.c1 = a.c0
|
||||||
|
result.c2 = a.c1
|
||||||
|
|
||||||
|
func `*=`*(a: var Fp6, _: typedesc[γ]) {.inline.} =
|
||||||
|
a = γ * a
|
||||||
|
@ -10,7 +10,7 @@ import
|
|||||||
# Standard library
|
# Standard library
|
||||||
unittest, times, random,
|
unittest, times, random,
|
||||||
# Internals
|
# Internals
|
||||||
../constantine/tower_field_extensions/[abelian_groups, fp12_quad_fp6],
|
../constantine/towers,
|
||||||
../constantine/config/[common, curves],
|
../constantine/config/[common, curves],
|
||||||
../constantine/arithmetic,
|
../constantine/arithmetic,
|
||||||
# Test utilities
|
# Test utilities
|
||||||
@ -50,14 +50,14 @@ suite "𝔽p12 = 𝔽p6[√∛(1+𝑖)]":
|
|||||||
|
|
||||||
testInstance()
|
testInstance()
|
||||||
|
|
||||||
test(BN254_Nogami)
|
# test(BN254_Nogami)
|
||||||
test(BN254_Snarks)
|
test(BN254_Snarks)
|
||||||
test(BLS12_377)
|
test(BLS12_377)
|
||||||
test(BLS12_381)
|
test(BLS12_381)
|
||||||
test(BN446)
|
# test(BN446)
|
||||||
test(FKM12_447)
|
# test(FKM12_447)
|
||||||
test(BLS12_461)
|
# test(BLS12_461)
|
||||||
test(BN462)
|
# test(BN462)
|
||||||
|
|
||||||
test "Squaring 2 returns 4":
|
test "Squaring 2 returns 4":
|
||||||
template test(C: static Curve) =
|
template test(C: static Curve) =
|
||||||
@ -87,14 +87,14 @@ suite "𝔽p12 = 𝔽p6[√∛(1+𝑖)]":
|
|||||||
|
|
||||||
testInstance()
|
testInstance()
|
||||||
|
|
||||||
test(BN254_Nogami)
|
# test(BN254_Nogami)
|
||||||
test(BN254_Snarks)
|
test(BN254_Snarks)
|
||||||
test(BLS12_377)
|
test(BLS12_377)
|
||||||
test(BLS12_381)
|
test(BLS12_381)
|
||||||
test(BN446)
|
# test(BN446)
|
||||||
test(FKM12_447)
|
# test(FKM12_447)
|
||||||
test(BLS12_461)
|
# test(BLS12_461)
|
||||||
test(BN462)
|
# test(BN462)
|
||||||
|
|
||||||
test "Squaring 3 returns 9":
|
test "Squaring 3 returns 9":
|
||||||
template test(C: static Curve) =
|
template test(C: static Curve) =
|
||||||
@ -126,14 +126,14 @@ suite "𝔽p12 = 𝔽p6[√∛(1+𝑖)]":
|
|||||||
|
|
||||||
testInstance()
|
testInstance()
|
||||||
|
|
||||||
test(BN254_Nogami)
|
# test(BN254_Nogami)
|
||||||
test(BN254_Snarks)
|
test(BN254_Snarks)
|
||||||
test(BLS12_377)
|
test(BLS12_377)
|
||||||
test(BLS12_381)
|
test(BLS12_381)
|
||||||
test(BN446)
|
# test(BN446)
|
||||||
test(FKM12_447)
|
# test(FKM12_447)
|
||||||
test(BLS12_461)
|
# test(BLS12_461)
|
||||||
test(BN462)
|
# test(BN462)
|
||||||
|
|
||||||
test "Squaring -3 returns 9":
|
test "Squaring -3 returns 9":
|
||||||
template test(C: static Curve) =
|
template test(C: static Curve) =
|
||||||
@ -165,14 +165,14 @@ suite "𝔽p12 = 𝔽p6[√∛(1+𝑖)]":
|
|||||||
|
|
||||||
testInstance()
|
testInstance()
|
||||||
|
|
||||||
test(BN254_Nogami)
|
# test(BN254_Nogami)
|
||||||
test(BN254_Snarks)
|
test(BN254_Snarks)
|
||||||
test(BLS12_377)
|
test(BLS12_377)
|
||||||
test(BLS12_381)
|
test(BLS12_381)
|
||||||
test(BN446)
|
# test(BN446)
|
||||||
test(FKM12_447)
|
# test(FKM12_447)
|
||||||
test(BLS12_461)
|
# test(BLS12_461)
|
||||||
test(BN462)
|
# test(BN462)
|
||||||
|
|
||||||
test "Multiplication by 0 and 1":
|
test "Multiplication by 0 and 1":
|
||||||
template test(C: static Curve, body: untyped) =
|
template test(C: static Curve, body: untyped) =
|
||||||
@ -194,18 +194,18 @@ suite "𝔽p12 = 𝔽p6[√∛(1+𝑖)]":
|
|||||||
|
|
||||||
testInstance()
|
testInstance()
|
||||||
|
|
||||||
test(BN254_Nogami):
|
# test(BN254_Nogami):
|
||||||
r.prod(x, Zero)
|
# r.prod(x, Zero)
|
||||||
check: bool(r == Zero)
|
# check: bool(r == Zero)
|
||||||
test(BN254_Nogami):
|
# test(BN254_Nogami):
|
||||||
r.prod(Zero, x)
|
# r.prod(Zero, x)
|
||||||
check: bool(r == Zero)
|
# check: bool(r == Zero)
|
||||||
test(BN254_Nogami):
|
# test(BN254_Nogami):
|
||||||
r.prod(x, One)
|
# r.prod(x, One)
|
||||||
check: bool(r == x)
|
# check: bool(r == x)
|
||||||
test(BN254_Nogami):
|
# test(BN254_Nogami):
|
||||||
r.prod(One, x)
|
# r.prod(One, x)
|
||||||
check: bool(r == x)
|
# check: bool(r == x)
|
||||||
test(BN254_Snarks):
|
test(BN254_Snarks):
|
||||||
r.prod(x, Zero)
|
r.prod(x, Zero)
|
||||||
check: bool(r == Zero)
|
check: bool(r == Zero)
|
||||||
@ -230,18 +230,18 @@ suite "𝔽p12 = 𝔽p6[√∛(1+𝑖)]":
|
|||||||
test(BLS12_381):
|
test(BLS12_381):
|
||||||
r.prod(One, x)
|
r.prod(One, x)
|
||||||
check: bool(r == x)
|
check: bool(r == x)
|
||||||
test(BN462):
|
# test(BN462):
|
||||||
r.prod(x, Zero)
|
# r.prod(x, Zero)
|
||||||
check: bool(r == Zero)
|
# check: bool(r == Zero)
|
||||||
test(BN462):
|
# test(BN462):
|
||||||
r.prod(Zero, x)
|
# r.prod(Zero, x)
|
||||||
check: bool(r == Zero)
|
# check: bool(r == Zero)
|
||||||
test(BN462):
|
# test(BN462):
|
||||||
r.prod(x, One)
|
# r.prod(x, One)
|
||||||
check: bool(r == x)
|
# check: bool(r == x)
|
||||||
test(BN462):
|
# test(BN462):
|
||||||
r.prod(One, x)
|
# r.prod(One, x)
|
||||||
check: bool(r == x)
|
# check: bool(r == x)
|
||||||
|
|
||||||
test "Multiplication and Squaring are consistent":
|
test "Multiplication and Squaring are consistent":
|
||||||
template test(C: static Curve) =
|
template test(C: static Curve) =
|
||||||
@ -258,14 +258,14 @@ suite "𝔽p12 = 𝔽p6[√∛(1+𝑖)]":
|
|||||||
|
|
||||||
testInstance()
|
testInstance()
|
||||||
|
|
||||||
test(BN254_Nogami)
|
# test(BN254_Nogami)
|
||||||
test(BN254_Snarks)
|
test(BN254_Snarks)
|
||||||
test(BLS12_377)
|
test(BLS12_377)
|
||||||
test(BLS12_381)
|
test(BLS12_381)
|
||||||
test(BN446)
|
# test(BN446)
|
||||||
test(FKM12_447)
|
# test(FKM12_447)
|
||||||
test(BLS12_461)
|
# test(BLS12_461)
|
||||||
test(BN462)
|
# test(BN462)
|
||||||
|
|
||||||
test "Squaring the opposite gives the same result":
|
test "Squaring the opposite gives the same result":
|
||||||
template test(C: static Curve) =
|
template test(C: static Curve) =
|
||||||
@ -285,14 +285,14 @@ suite "𝔽p12 = 𝔽p6[√∛(1+𝑖)]":
|
|||||||
|
|
||||||
testInstance()
|
testInstance()
|
||||||
|
|
||||||
test(BN254_Nogami)
|
# test(BN254_Nogami)
|
||||||
test(BN254_Snarks)
|
test(BN254_Snarks)
|
||||||
test(BLS12_377)
|
test(BLS12_377)
|
||||||
test(BLS12_381)
|
test(BLS12_381)
|
||||||
test(BN446)
|
# test(BN446)
|
||||||
test(FKM12_447)
|
# test(FKM12_447)
|
||||||
test(BLS12_461)
|
# test(BLS12_461)
|
||||||
test(BN462)
|
# test(BN462)
|
||||||
|
|
||||||
test "Multiplication and Addition/Substraction are consistent":
|
test "Multiplication and Addition/Substraction are consistent":
|
||||||
template test(C: static Curve) =
|
template test(C: static Curve) =
|
||||||
@ -329,14 +329,14 @@ suite "𝔽p12 = 𝔽p6[√∛(1+𝑖)]":
|
|||||||
|
|
||||||
testInstance()
|
testInstance()
|
||||||
|
|
||||||
test(BN254_Nogami)
|
# test(BN254_Nogami)
|
||||||
test(BN254_Snarks)
|
test(BN254_Snarks)
|
||||||
test(BLS12_377)
|
test(BLS12_377)
|
||||||
test(BLS12_381)
|
test(BLS12_381)
|
||||||
test(BN446)
|
# test(BN446)
|
||||||
test(FKM12_447)
|
# test(FKM12_447)
|
||||||
test(BLS12_461)
|
# test(BLS12_461)
|
||||||
test(BN462)
|
# test(BN462)
|
||||||
|
|
||||||
test "𝔽p12 = 𝔽p6[√∛(1+𝑖)] addition is associative and commutative":
|
test "𝔽p12 = 𝔽p6[√∛(1+𝑖)] addition is associative and commutative":
|
||||||
proc abelianGroup(curve: static Curve) =
|
proc abelianGroup(curve: static Curve) =
|
||||||
@ -380,14 +380,14 @@ suite "𝔽p12 = 𝔽p6[√∛(1+𝑖)]":
|
|||||||
bool(r0 == r3)
|
bool(r0 == r3)
|
||||||
bool(r0 == r4)
|
bool(r0 == r4)
|
||||||
|
|
||||||
abelianGroup(BN254_Nogami)
|
# abelianGroup(BN254_Nogami)
|
||||||
abelianGroup(BN254_Snarks)
|
abelianGroup(BN254_Snarks)
|
||||||
abelianGroup(BLS12_377)
|
abelianGroup(BLS12_377)
|
||||||
abelianGroup(BLS12_381)
|
abelianGroup(BLS12_381)
|
||||||
abelianGroup(BN446)
|
# abelianGroup(BN446)
|
||||||
abelianGroup(FKM12_447)
|
# abelianGroup(FKM12_447)
|
||||||
abelianGroup(BLS12_461)
|
# abelianGroup(BLS12_461)
|
||||||
abelianGroup(BN462)
|
# abelianGroup(BN462)
|
||||||
|
|
||||||
test "𝔽p12 = 𝔽p6[√∛(1+𝑖)] multiplication is associative and commutative":
|
test "𝔽p12 = 𝔽p6[√∛(1+𝑖)] multiplication is associative and commutative":
|
||||||
proc commutativeRing(curve: static Curve) =
|
proc commutativeRing(curve: static Curve) =
|
||||||
@ -431,14 +431,14 @@ suite "𝔽p12 = 𝔽p6[√∛(1+𝑖)]":
|
|||||||
bool(r0 == r3)
|
bool(r0 == r3)
|
||||||
bool(r0 == r4)
|
bool(r0 == r4)
|
||||||
|
|
||||||
commutativeRing(BN254_Nogami)
|
# commutativeRing(BN254_Nogami)
|
||||||
commutativeRing(BN254_Snarks)
|
commutativeRing(BN254_Snarks)
|
||||||
commutativeRing(BLS12_377)
|
commutativeRing(BLS12_377)
|
||||||
commutativeRing(BLS12_381)
|
commutativeRing(BLS12_381)
|
||||||
commutativeRing(BN446)
|
# commutativeRing(BN446)
|
||||||
commutativeRing(FKM12_447)
|
# commutativeRing(FKM12_447)
|
||||||
commutativeRing(BLS12_461)
|
# commutativeRing(BLS12_461)
|
||||||
commutativeRing(BN462)
|
# commutativeRing(BN462)
|
||||||
|
|
||||||
test "𝔽p6 = 𝔽p2[∛(1+𝑖)] extension field multiplicative inverse":
|
test "𝔽p6 = 𝔽p2[∛(1+𝑖)] extension field multiplicative inverse":
|
||||||
proc mulInvOne(curve: static Curve) =
|
proc mulInvOne(curve: static Curve) =
|
||||||
@ -462,11 +462,11 @@ suite "𝔽p12 = 𝔽p6[√∛(1+𝑖)]":
|
|||||||
r.prod(aInv, a)
|
r.prod(aInv, a)
|
||||||
check: bool(r == one)
|
check: bool(r == one)
|
||||||
|
|
||||||
mulInvOne(BN254_Nogami)
|
# mulInvOne(BN254_Nogami)
|
||||||
mulInvOne(BN254_Snarks)
|
mulInvOne(BN254_Snarks)
|
||||||
mulInvOne(BLS12_377)
|
mulInvOne(BLS12_377)
|
||||||
mulInvOne(BLS12_381)
|
mulInvOne(BLS12_381)
|
||||||
mulInvOne(BN446)
|
# mulInvOne(BN446)
|
||||||
mulInvOne(FKM12_447)
|
# mulInvOne(FKM12_447)
|
||||||
mulInvOne(BLS12_461)
|
# mulInvOne(BLS12_461)
|
||||||
mulInvOne(BN462)
|
# mulInvOne(BN462)
|
||||||
|
@ -10,7 +10,7 @@ import
|
|||||||
# Standard library
|
# Standard library
|
||||||
unittest, times, random,
|
unittest, times, random,
|
||||||
# Internals
|
# Internals
|
||||||
../constantine/tower_field_extensions/[abelian_groups, fp2_complex],
|
../constantine/towers,
|
||||||
../constantine/config/[common, curves],
|
../constantine/config/[common, curves],
|
||||||
../constantine/arithmetic,
|
../constantine/arithmetic,
|
||||||
# Test utilities
|
# Test utilities
|
||||||
@ -51,7 +51,7 @@ suite "𝔽p2 = 𝔽p[𝑖] (irreducible polynomial x²+1)":
|
|||||||
bool(r == oneBig)
|
bool(r == oneBig)
|
||||||
bool(oneFp2.c1.mres.isZero())
|
bool(oneFp2.c1.mres.isZero())
|
||||||
|
|
||||||
test(BN254_Nogami)
|
# test(BN254_Nogami)
|
||||||
test(BN254_Snarks)
|
test(BN254_Snarks)
|
||||||
test(BLS12_381)
|
test(BLS12_381)
|
||||||
|
|
||||||
@ -74,14 +74,14 @@ suite "𝔽p2 = 𝔽p[𝑖] (irreducible polynomial x²+1)":
|
|||||||
|
|
||||||
testInstance()
|
testInstance()
|
||||||
|
|
||||||
test(BN254_Nogami)
|
# test(BN254_Nogami)
|
||||||
test(BN254_Snarks)
|
test(BN254_Snarks)
|
||||||
test(BLS12_377)
|
test(BLS12_377)
|
||||||
test(BLS12_381)
|
test(BLS12_381)
|
||||||
test(BN446)
|
# test(BN446)
|
||||||
test(FKM12_447)
|
# test(FKM12_447)
|
||||||
test(BLS12_461)
|
# test(BLS12_461)
|
||||||
test(BN462)
|
# test(BN462)
|
||||||
|
|
||||||
test "Multiplication by 0 and 1":
|
test "Multiplication by 0 and 1":
|
||||||
template test(C: static Curve, body: untyped) =
|
template test(C: static Curve, body: untyped) =
|
||||||
@ -103,18 +103,18 @@ suite "𝔽p2 = 𝔽p[𝑖] (irreducible polynomial x²+1)":
|
|||||||
|
|
||||||
testInstance()
|
testInstance()
|
||||||
|
|
||||||
test(BN254_Nogami):
|
# test(BN254_Nogami):
|
||||||
r.prod(x, Zero)
|
# r.prod(x, Zero)
|
||||||
check: bool(r == Zero)
|
# check: bool(r == Zero)
|
||||||
test(BN254_Nogami):
|
# test(BN254_Nogami):
|
||||||
r.prod(Zero, x)
|
# r.prod(Zero, x)
|
||||||
check: bool(r == Zero)
|
# check: bool(r == Zero)
|
||||||
test(BN254_Nogami):
|
# test(BN254_Nogami):
|
||||||
r.prod(x, One)
|
# r.prod(x, One)
|
||||||
check: bool(r == x)
|
# check: bool(r == x)
|
||||||
test(BN254_Nogami):
|
# test(BN254_Nogami):
|
||||||
r.prod(One, x)
|
# r.prod(One, x)
|
||||||
check: bool(r == x)
|
# check: bool(r == x)
|
||||||
test(BN254_Snarks):
|
test(BN254_Snarks):
|
||||||
r.prod(x, Zero)
|
r.prod(x, Zero)
|
||||||
check: bool(r == Zero)
|
check: bool(r == Zero)
|
||||||
@ -155,14 +155,14 @@ suite "𝔽p2 = 𝔽p[𝑖] (irreducible polynomial x²+1)":
|
|||||||
|
|
||||||
testInstance()
|
testInstance()
|
||||||
|
|
||||||
test(BN254_Nogami)
|
# test(BN254_Nogami)
|
||||||
test(BN254_Snarks)
|
test(BN254_Snarks)
|
||||||
test(BLS12_377)
|
test(BLS12_377)
|
||||||
test(BLS12_381)
|
test(BLS12_381)
|
||||||
test(BN446)
|
# test(BN446)
|
||||||
test(FKM12_447)
|
# test(FKM12_447)
|
||||||
test(BLS12_461)
|
# test(BLS12_461)
|
||||||
test(BN462)
|
# test(BN462)
|
||||||
|
|
||||||
test "Squaring the opposite gives the same result":
|
test "Squaring the opposite gives the same result":
|
||||||
template test(C: static Curve) =
|
template test(C: static Curve) =
|
||||||
@ -182,14 +182,14 @@ suite "𝔽p2 = 𝔽p[𝑖] (irreducible polynomial x²+1)":
|
|||||||
|
|
||||||
testInstance()
|
testInstance()
|
||||||
|
|
||||||
test(BN254_Nogami)
|
# test(BN254_Nogami)
|
||||||
test(BN254_Snarks)
|
test(BN254_Snarks)
|
||||||
test(BLS12_377)
|
test(BLS12_377)
|
||||||
test(BLS12_381)
|
test(BLS12_381)
|
||||||
test(BN446)
|
# test(BN446)
|
||||||
test(FKM12_447)
|
# test(FKM12_447)
|
||||||
test(BLS12_461)
|
# test(BLS12_461)
|
||||||
test(BN462)
|
# test(BN462)
|
||||||
|
|
||||||
test "Multiplication and Addition/Substraction are consistent":
|
test "Multiplication and Addition/Substraction are consistent":
|
||||||
template test(C: static Curve) =
|
template test(C: static Curve) =
|
||||||
@ -226,14 +226,14 @@ suite "𝔽p2 = 𝔽p[𝑖] (irreducible polynomial x²+1)":
|
|||||||
|
|
||||||
testInstance()
|
testInstance()
|
||||||
|
|
||||||
test(BN254_Nogami)
|
# test(BN254_Nogami)
|
||||||
test(BN254_Snarks)
|
test(BN254_Snarks)
|
||||||
test(BLS12_377)
|
test(BLS12_377)
|
||||||
test(BLS12_381)
|
test(BLS12_381)
|
||||||
test(BN446)
|
# test(BN446)
|
||||||
test(FKM12_447)
|
# test(FKM12_447)
|
||||||
test(BLS12_461)
|
# test(BLS12_461)
|
||||||
test(BN462)
|
# test(BN462)
|
||||||
|
|
||||||
test "𝔽p2 = 𝔽p[𝑖] addition is associative and commutative":
|
test "𝔽p2 = 𝔽p[𝑖] addition is associative and commutative":
|
||||||
proc abelianGroup(curve: static Curve) =
|
proc abelianGroup(curve: static Curve) =
|
||||||
@ -277,14 +277,14 @@ suite "𝔽p2 = 𝔽p[𝑖] (irreducible polynomial x²+1)":
|
|||||||
bool(r0 == r3)
|
bool(r0 == r3)
|
||||||
bool(r0 == r4)
|
bool(r0 == r4)
|
||||||
|
|
||||||
abelianGroup(BN254_Nogami)
|
# abelianGroup(BN254_Nogami)
|
||||||
abelianGroup(BN254_Snarks)
|
abelianGroup(BN254_Snarks)
|
||||||
abelianGroup(BLS12_377)
|
abelianGroup(BLS12_377)
|
||||||
abelianGroup(BLS12_381)
|
abelianGroup(BLS12_381)
|
||||||
abelianGroup(BN446)
|
# abelianGroup(BN446)
|
||||||
abelianGroup(FKM12_447)
|
# abelianGroup(FKM12_447)
|
||||||
abelianGroup(BLS12_461)
|
# abelianGroup(BLS12_461)
|
||||||
abelianGroup(BN462)
|
# abelianGroup(BN462)
|
||||||
|
|
||||||
test "𝔽p2 = 𝔽p[𝑖] multiplication is associative and commutative":
|
test "𝔽p2 = 𝔽p[𝑖] multiplication is associative and commutative":
|
||||||
proc commutativeRing(curve: static Curve) =
|
proc commutativeRing(curve: static Curve) =
|
||||||
@ -328,14 +328,14 @@ suite "𝔽p2 = 𝔽p[𝑖] (irreducible polynomial x²+1)":
|
|||||||
bool(r0 == r3)
|
bool(r0 == r3)
|
||||||
bool(r0 == r4)
|
bool(r0 == r4)
|
||||||
|
|
||||||
commutativeRing(BN254_Nogami)
|
# commutativeRing(BN254_Nogami)
|
||||||
commutativeRing(BN254_Snarks)
|
commutativeRing(BN254_Snarks)
|
||||||
commutativeRing(BLS12_377)
|
commutativeRing(BLS12_377)
|
||||||
commutativeRing(BLS12_381)
|
commutativeRing(BLS12_381)
|
||||||
commutativeRing(BN446)
|
# commutativeRing(BN446)
|
||||||
commutativeRing(FKM12_447)
|
# commutativeRing(FKM12_447)
|
||||||
commutativeRing(BLS12_461)
|
# commutativeRing(BLS12_461)
|
||||||
commutativeRing(BN462)
|
# commutativeRing(BN462)
|
||||||
|
|
||||||
test "𝔽p2 = 𝔽p[𝑖] extension field multiplicative inverse":
|
test "𝔽p2 = 𝔽p[𝑖] extension field multiplicative inverse":
|
||||||
proc mulInvOne(curve: static Curve) =
|
proc mulInvOne(curve: static Curve) =
|
||||||
@ -352,11 +352,11 @@ suite "𝔽p2 = 𝔽p[𝑖] (irreducible polynomial x²+1)":
|
|||||||
r.prod(aInv, a)
|
r.prod(aInv, a)
|
||||||
check: bool(r == one)
|
check: bool(r == one)
|
||||||
|
|
||||||
mulInvOne(BN254_Nogami)
|
# mulInvOne(BN254_Nogami)
|
||||||
mulInvOne(BN254_Snarks)
|
mulInvOne(BN254_Snarks)
|
||||||
mulInvOne(BLS12_377)
|
mulInvOne(BLS12_377)
|
||||||
mulInvOne(BLS12_381)
|
mulInvOne(BLS12_381)
|
||||||
mulInvOne(BN446)
|
# mulInvOne(BN446)
|
||||||
mulInvOne(FKM12_447)
|
# mulInvOne(FKM12_447)
|
||||||
mulInvOne(BLS12_461)
|
# mulInvOne(BLS12_461)
|
||||||
mulInvOne(BN462)
|
# mulInvOne(BN462)
|
||||||
|
@ -10,7 +10,7 @@ import
|
|||||||
# Standard library
|
# Standard library
|
||||||
unittest, times, random,
|
unittest, times, random,
|
||||||
# Internals
|
# Internals
|
||||||
../constantine/tower_field_extensions/[abelian_groups, fp6_1_plus_i],
|
../constantine/towers,
|
||||||
../constantine/config/[common, curves],
|
../constantine/config/[common, curves],
|
||||||
../constantine/arithmetic,
|
../constantine/arithmetic,
|
||||||
# Test utilities
|
# Test utilities
|
||||||
@ -50,14 +50,14 @@ suite "𝔽p6 = 𝔽p2[∛(1+𝑖)] (irreducible polynomial x³ - (1+𝑖))":
|
|||||||
|
|
||||||
testInstance()
|
testInstance()
|
||||||
|
|
||||||
test(BN254_Nogami)
|
# test(BN254_Nogami)
|
||||||
test(BN254_Snarks)
|
test(BN254_Snarks)
|
||||||
test(BLS12_377)
|
test(BLS12_377)
|
||||||
test(BLS12_381)
|
test(BLS12_381)
|
||||||
test(BN446)
|
# test(BN446)
|
||||||
test(FKM12_447)
|
# test(FKM12_447)
|
||||||
test(BLS12_461)
|
# test(BLS12_461)
|
||||||
test(BN462)
|
# test(BN462)
|
||||||
|
|
||||||
test "Squaring 2 returns 4":
|
test "Squaring 2 returns 4":
|
||||||
template test(C: static Curve) =
|
template test(C: static Curve) =
|
||||||
@ -87,14 +87,14 @@ suite "𝔽p6 = 𝔽p2[∛(1+𝑖)] (irreducible polynomial x³ - (1+𝑖))":
|
|||||||
|
|
||||||
testInstance()
|
testInstance()
|
||||||
|
|
||||||
test(BN254_Nogami)
|
# test(BN254_Nogami)
|
||||||
test(BN254_Snarks)
|
test(BN254_Snarks)
|
||||||
test(BLS12_377)
|
test(BLS12_377)
|
||||||
test(BLS12_381)
|
test(BLS12_381)
|
||||||
test(BN446)
|
# test(BN446)
|
||||||
test(FKM12_447)
|
# test(FKM12_447)
|
||||||
test(BLS12_461)
|
# test(BLS12_461)
|
||||||
test(BN462)
|
# test(BN462)
|
||||||
|
|
||||||
test "Squaring 3 returns 9":
|
test "Squaring 3 returns 9":
|
||||||
template test(C: static Curve) =
|
template test(C: static Curve) =
|
||||||
@ -126,14 +126,14 @@ suite "𝔽p6 = 𝔽p2[∛(1+𝑖)] (irreducible polynomial x³ - (1+𝑖))":
|
|||||||
|
|
||||||
testInstance()
|
testInstance()
|
||||||
|
|
||||||
test(BN254_Nogami)
|
# test(BN254_Nogami)
|
||||||
test(BN254_Snarks)
|
test(BN254_Snarks)
|
||||||
test(BLS12_377)
|
test(BLS12_377)
|
||||||
test(BLS12_381)
|
test(BLS12_381)
|
||||||
test(BN446)
|
# test(BN446)
|
||||||
test(FKM12_447)
|
# test(FKM12_447)
|
||||||
test(BLS12_461)
|
# test(BLS12_461)
|
||||||
test(BN462)
|
# test(BN462)
|
||||||
|
|
||||||
test "Squaring -3 returns 9":
|
test "Squaring -3 returns 9":
|
||||||
template test(C: static Curve) =
|
template test(C: static Curve) =
|
||||||
@ -165,14 +165,14 @@ suite "𝔽p6 = 𝔽p2[∛(1+𝑖)] (irreducible polynomial x³ - (1+𝑖))":
|
|||||||
|
|
||||||
testInstance()
|
testInstance()
|
||||||
|
|
||||||
test(BN254_Nogami)
|
# test(BN254_Nogami)
|
||||||
test(BN254_Snarks)
|
test(BN254_Snarks)
|
||||||
test(BLS12_377)
|
test(BLS12_377)
|
||||||
test(BLS12_381)
|
test(BLS12_381)
|
||||||
test(BN446)
|
# test(BN446)
|
||||||
test(FKM12_447)
|
# test(FKM12_447)
|
||||||
test(BLS12_461)
|
# test(BLS12_461)
|
||||||
test(BN462)
|
# test(BN462)
|
||||||
|
|
||||||
test "Multiplication by 0 and 1":
|
test "Multiplication by 0 and 1":
|
||||||
template test(C: static Curve, body: untyped) =
|
template test(C: static Curve, body: untyped) =
|
||||||
@ -194,18 +194,18 @@ suite "𝔽p6 = 𝔽p2[∛(1+𝑖)] (irreducible polynomial x³ - (1+𝑖))":
|
|||||||
|
|
||||||
testInstance()
|
testInstance()
|
||||||
|
|
||||||
test(BN254_Nogami):
|
# test(BN254_Nogami):
|
||||||
r.prod(x, Zero)
|
# r.prod(x, Zero)
|
||||||
check: bool(r == Zero)
|
# check: bool(r == Zero)
|
||||||
test(BN254_Nogami):
|
# test(BN254_Nogami):
|
||||||
r.prod(Zero, x)
|
# r.prod(Zero, x)
|
||||||
check: bool(r == Zero)
|
# check: bool(r == Zero)
|
||||||
test(BN254_Nogami):
|
# test(BN254_Nogami):
|
||||||
r.prod(x, One)
|
# r.prod(x, One)
|
||||||
check: bool(r == x)
|
# check: bool(r == x)
|
||||||
test(BN254_Nogami):
|
# test(BN254_Nogami):
|
||||||
r.prod(One, x)
|
# r.prod(One, x)
|
||||||
check: bool(r == x)
|
# check: bool(r == x)
|
||||||
test(BN254_Snarks):
|
test(BN254_Snarks):
|
||||||
r.prod(x, Zero)
|
r.prod(x, Zero)
|
||||||
check: bool(r == Zero)
|
check: bool(r == Zero)
|
||||||
@ -230,18 +230,18 @@ suite "𝔽p6 = 𝔽p2[∛(1+𝑖)] (irreducible polynomial x³ - (1+𝑖))":
|
|||||||
test(BLS12_381):
|
test(BLS12_381):
|
||||||
r.prod(One, x)
|
r.prod(One, x)
|
||||||
check: bool(r == x)
|
check: bool(r == x)
|
||||||
test(BN462):
|
# test(BN462):
|
||||||
r.prod(x, Zero)
|
# r.prod(x, Zero)
|
||||||
check: bool(r == Zero)
|
# check: bool(r == Zero)
|
||||||
test(BN462):
|
# test(BN462):
|
||||||
r.prod(Zero, x)
|
# r.prod(Zero, x)
|
||||||
check: bool(r == Zero)
|
# check: bool(r == Zero)
|
||||||
test(BN462):
|
# test(BN462):
|
||||||
r.prod(x, One)
|
# r.prod(x, One)
|
||||||
check: bool(r == x)
|
# check: bool(r == x)
|
||||||
test(BN462):
|
# test(BN462):
|
||||||
r.prod(One, x)
|
# r.prod(One, x)
|
||||||
check: bool(r == x)
|
# check: bool(r == x)
|
||||||
|
|
||||||
test "Multiplication and Squaring are consistent":
|
test "Multiplication and Squaring are consistent":
|
||||||
template test(C: static Curve) =
|
template test(C: static Curve) =
|
||||||
@ -258,14 +258,14 @@ suite "𝔽p6 = 𝔽p2[∛(1+𝑖)] (irreducible polynomial x³ - (1+𝑖))":
|
|||||||
|
|
||||||
testInstance()
|
testInstance()
|
||||||
|
|
||||||
test(BN254_Nogami)
|
# test(BN254_Nogami)
|
||||||
test(BN254_Snarks)
|
test(BN254_Snarks)
|
||||||
test(BLS12_377)
|
test(BLS12_377)
|
||||||
test(BLS12_381)
|
test(BLS12_381)
|
||||||
test(BN446)
|
# test(BN446)
|
||||||
test(FKM12_447)
|
# test(FKM12_447)
|
||||||
test(BLS12_461)
|
# test(BLS12_461)
|
||||||
test(BN462)
|
# test(BN462)
|
||||||
|
|
||||||
test "Squaring the opposite gives the same result":
|
test "Squaring the opposite gives the same result":
|
||||||
template test(C: static Curve) =
|
template test(C: static Curve) =
|
||||||
@ -285,14 +285,14 @@ suite "𝔽p6 = 𝔽p2[∛(1+𝑖)] (irreducible polynomial x³ - (1+𝑖))":
|
|||||||
|
|
||||||
testInstance()
|
testInstance()
|
||||||
|
|
||||||
test(BN254_Nogami)
|
# test(BN254_Nogami)
|
||||||
test(BN254_Snarks)
|
test(BN254_Snarks)
|
||||||
test(BLS12_377)
|
test(BLS12_377)
|
||||||
test(BLS12_381)
|
test(BLS12_381)
|
||||||
test(BN446)
|
# test(BN446)
|
||||||
test(FKM12_447)
|
# test(FKM12_447)
|
||||||
test(BLS12_461)
|
# test(BLS12_461)
|
||||||
test(BN462)
|
# test(BN462)
|
||||||
|
|
||||||
test "Multiplication and Addition/Substraction are consistent":
|
test "Multiplication and Addition/Substraction are consistent":
|
||||||
template test(C: static Curve) =
|
template test(C: static Curve) =
|
||||||
@ -329,14 +329,14 @@ suite "𝔽p6 = 𝔽p2[∛(1+𝑖)] (irreducible polynomial x³ - (1+𝑖))":
|
|||||||
|
|
||||||
testInstance()
|
testInstance()
|
||||||
|
|
||||||
test(BN254_Nogami)
|
# test(BN254_Nogami)
|
||||||
test(BN254_Snarks)
|
test(BN254_Snarks)
|
||||||
test(BLS12_377)
|
test(BLS12_377)
|
||||||
test(BLS12_381)
|
test(BLS12_381)
|
||||||
test(BN446)
|
# test(BN446)
|
||||||
test(FKM12_447)
|
# test(FKM12_447)
|
||||||
test(BLS12_461)
|
# test(BLS12_461)
|
||||||
test(BN462)
|
# test(BN462)
|
||||||
|
|
||||||
test "𝔽p6 = 𝔽p2[∛(1+𝑖)] addition is associative and commutative":
|
test "𝔽p6 = 𝔽p2[∛(1+𝑖)] addition is associative and commutative":
|
||||||
proc abelianGroup(curve: static Curve) =
|
proc abelianGroup(curve: static Curve) =
|
||||||
@ -380,14 +380,14 @@ suite "𝔽p6 = 𝔽p2[∛(1+𝑖)] (irreducible polynomial x³ - (1+𝑖))":
|
|||||||
bool(r0 == r3)
|
bool(r0 == r3)
|
||||||
bool(r0 == r4)
|
bool(r0 == r4)
|
||||||
|
|
||||||
abelianGroup(BN254_Nogami)
|
# abelianGroup(BN254_Nogami)
|
||||||
abelianGroup(BN254_Snarks)
|
abelianGroup(BN254_Snarks)
|
||||||
abelianGroup(BLS12_377)
|
abelianGroup(BLS12_377)
|
||||||
abelianGroup(BLS12_381)
|
abelianGroup(BLS12_381)
|
||||||
abelianGroup(BN446)
|
# abelianGroup(BN446)
|
||||||
abelianGroup(FKM12_447)
|
# abelianGroup(FKM12_447)
|
||||||
abelianGroup(BLS12_461)
|
# abelianGroup(BLS12_461)
|
||||||
abelianGroup(BN462)
|
# abelianGroup(BN462)
|
||||||
|
|
||||||
test "𝔽p6 = 𝔽p2[∛(1+𝑖)] multiplication is associative and commutative":
|
test "𝔽p6 = 𝔽p2[∛(1+𝑖)] multiplication is associative and commutative":
|
||||||
proc commutativeRing(curve: static Curve) =
|
proc commutativeRing(curve: static Curve) =
|
||||||
@ -431,14 +431,14 @@ suite "𝔽p6 = 𝔽p2[∛(1+𝑖)] (irreducible polynomial x³ - (1+𝑖))":
|
|||||||
bool(r0 == r3)
|
bool(r0 == r3)
|
||||||
bool(r0 == r4)
|
bool(r0 == r4)
|
||||||
|
|
||||||
commutativeRing(BN254_Nogami)
|
# commutativeRing(BN254_Nogami)
|
||||||
commutativeRing(BN254_Snarks)
|
commutativeRing(BN254_Snarks)
|
||||||
commutativeRing(BLS12_377)
|
commutativeRing(BLS12_377)
|
||||||
commutativeRing(BLS12_381)
|
commutativeRing(BLS12_381)
|
||||||
commutativeRing(BN446)
|
# commutativeRing(BN446)
|
||||||
commutativeRing(FKM12_447)
|
# commutativeRing(FKM12_447)
|
||||||
commutativeRing(BLS12_461)
|
# commutativeRing(BLS12_461)
|
||||||
commutativeRing(BN462)
|
# commutativeRing(BN462)
|
||||||
|
|
||||||
test "𝔽p6 = 𝔽p2[∛(1+𝑖)] extension field multiplicative inverse":
|
test "𝔽p6 = 𝔽p2[∛(1+𝑖)] extension field multiplicative inverse":
|
||||||
proc mulInvOne(curve: static Curve) =
|
proc mulInvOne(curve: static Curve) =
|
||||||
@ -462,11 +462,11 @@ suite "𝔽p6 = 𝔽p2[∛(1+𝑖)] (irreducible polynomial x³ - (1+𝑖))":
|
|||||||
r.prod(aInv, a)
|
r.prod(aInv, a)
|
||||||
check: bool(r == one)
|
check: bool(r == one)
|
||||||
|
|
||||||
mulInvOne(BN254_Nogami)
|
# mulInvOne(BN254_Nogami)
|
||||||
mulInvOne(BN254_Snarks)
|
mulInvOne(BN254_Snarks)
|
||||||
mulInvOne(BLS12_377)
|
mulInvOne(BLS12_377)
|
||||||
mulInvOne(BLS12_381)
|
mulInvOne(BLS12_381)
|
||||||
mulInvOne(BN446)
|
# mulInvOne(BN446)
|
||||||
mulInvOne(FKM12_447)
|
# mulInvOne(FKM12_447)
|
||||||
mulInvOne(BLS12_461)
|
# mulInvOne(BLS12_461)
|
||||||
mulInvOne(BN462)
|
# mulInvOne(BN462)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user