𝔽p12 extension - initial commit of squaring
This commit is contained in:
parent
e47159e40d
commit
8c478df0c1
|
@ -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.
|
||||||
|
|
||||||
|
# ############################################################
|
||||||
|
#
|
||||||
|
# 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²
|
||||||
|
|
||||||
|
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.diff(a.c0, a.c1)
|
||||||
|
r.c1.diff(a.c0, Gamma * a.c1)
|
||||||
|
r.c0.prod(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()
|
|
@ -8,23 +8,22 @@
|
||||||
|
|
||||||
# ############################################################
|
# ############################################################
|
||||||
#
|
#
|
||||||
# Cubic Extension field over base field 𝔽p2
|
# Cubic Extension field over extension field 𝔽p2
|
||||||
# 𝔽p6 = 𝔽p2[∛(1 + 𝑖)]
|
# 𝔽p6 = 𝔽p2[∛(1 + 𝑖)]
|
||||||
#
|
#
|
||||||
# ############################################################
|
# ############################################################
|
||||||
|
|
||||||
# This implements a quadratic extension field over 𝔽p2 = 𝔽p[𝑖]
|
# This implements a quadratic extension field over
|
||||||
# the base field 𝔽p:
|
|
||||||
# 𝔽p6 = 𝔽p2[∛(1 + 𝑖)]
|
# 𝔽p6 = 𝔽p2[∛(1 + 𝑖)]
|
||||||
# with element A of coordinates (a0, a1) represented
|
# with element A of coordinates (a0, a1, a2) represented
|
||||||
# by a0 + a1 ξ + a2 ξ²
|
# by a0 + a1 v + a2 v²
|
||||||
#
|
#
|
||||||
# The irreducible polynomial chosen is
|
# The irreducible polynomial chosen is
|
||||||
# x³ - ξ with ξ = 𝑖+1
|
# v³ - ξ with ξ = 𝑖+1
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Consequently, for this file Fp2 to be valid
|
# Consequently, for this file 𝔽p6 to be valid
|
||||||
# 𝑖+1 MUST not be a square in 𝔽p2
|
# 𝑖+1 MUST not be a cube in 𝔽p2
|
||||||
|
|
||||||
import
|
import
|
||||||
../arithmetic,
|
../arithmetic,
|
||||||
|
@ -38,25 +37,25 @@ type
|
||||||
## 𝔽p6 = 𝔽p2[∛(1 + 𝑖)]
|
## 𝔽p6 = 𝔽p2[∛(1 + 𝑖)]
|
||||||
##
|
##
|
||||||
## with coordinates (c0, c1, c2) such as
|
## with coordinates (c0, c1, c2) such as
|
||||||
## c0 + c1 ξ + c2 ξ²
|
## c0 + c1 v + c2 v² and v³ = ξ = 1+𝑖
|
||||||
##
|
##
|
||||||
## This requires 1 + 𝑖 to not be a cube in 𝔽p2
|
## This requires 1 + 𝑖 to not be a cube in 𝔽p2
|
||||||
c0*, c1*, c2*: Fp2[C]
|
c0*, c1*, c2*: Fp2[C]
|
||||||
|
|
||||||
Xi = object
|
Xi* = object
|
||||||
## ξ (Xi) the cubic non-residue
|
## ξ (Xi) the cubic non-residue of 𝔽p2
|
||||||
|
|
||||||
func `*`(_: typedesc[Xi], a: Fp2): Fp2 {.inline.}=
|
func `*`*(_: typedesc[Xi], a: Fp2): Fp2 {.inline.}=
|
||||||
## Multiply an element of 𝔽p2 by 𝔽p6 cubic non-residue 1 + 𝑖
|
## Multiply an element of 𝔽p2 by 𝔽p6 cubic non-residue ξ = 1 + 𝑖
|
||||||
## (c0 + c1 𝑖) (1 + 𝑖) => c0 + (c0 + c1)𝑖 + c1 𝑖²
|
## (c0 + c1 𝑖) (1 + 𝑖) => c0 + (c0 + c1)𝑖 + c1 𝑖²
|
||||||
## => c0 - c1 + (c0 + c1) 𝑖
|
## => c0 - c1 + (c0 + c1) 𝑖
|
||||||
result.c0.diff(a.c0, a.c1)
|
result.c0.diff(a.c0, a.c1)
|
||||||
result.c1.sum(a.c0, a.c1)
|
result.c1.sum(a.c0, a.c1)
|
||||||
|
|
||||||
template `*`(a: Fp2, _: typedesc[Xi]): Fp2 =
|
template `*`*(a: Fp2, _: typedesc[Xi]): Fp2 =
|
||||||
Xi * a
|
Xi * a
|
||||||
|
|
||||||
func `*=`(a: var Fp2, _: typedesc[Xi]) {.inline.}=
|
func `*=`*(a: var Fp2, _: typedesc[Xi]) {.inline.}=
|
||||||
## Inplace multiply an element of 𝔽p2 by 𝔽p6 cubic non-residue 1 + 𝑖
|
## Inplace multiply an element of 𝔽p2 by 𝔽p6 cubic non-residue 1 + 𝑖
|
||||||
let t = a.c0
|
let t = a.c0
|
||||||
a.c0 -= a.c1
|
a.c0 -= a.c1
|
||||||
|
@ -171,7 +170,7 @@ func inv*[C](r: var Fp6[C], a: Fp6[C]) =
|
||||||
|
|
||||||
v3.inv(v3)
|
v3.inv(v3)
|
||||||
|
|
||||||
# (a0 + a1 ξ + a2 ξ²)^-1 = (A + B ξ + C ξ²) / F
|
# (a0 + a1 v + a2 v²)^-1 = (A + B v + C v²) / F
|
||||||
r.c0 *= v3
|
r.c0 *= v3
|
||||||
r.c1.prod(v1, v3)
|
r.c1.prod(v1, v3)
|
||||||
r.c2.prod(v2, v3)
|
r.c2.prod(v2, v3)
|
||||||
|
|
|
@ -0,0 +1,171 @@
|
||||||
|
# Constantine
|
||||||
|
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
||||||
|
# Copyright (c) 2020-Present Mamy André-Ratsimbazafy
|
||||||
|
# Licensed and distributed under either of
|
||||||
|
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
|
||||||
|
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
|
||||||
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
|
import
|
||||||
|
# Standard library
|
||||||
|
unittest, times, random,
|
||||||
|
# Internals
|
||||||
|
../constantine/tower_field_extensions/[abelian_groups, fp12_quad_fp6],
|
||||||
|
../constantine/config/[common, curves],
|
||||||
|
../constantine/arithmetic,
|
||||||
|
# Test utilities
|
||||||
|
../helpers/prng
|
||||||
|
|
||||||
|
const Iters = 128
|
||||||
|
|
||||||
|
var rng: RngState
|
||||||
|
let seed = uint32(getTime().toUnix() and (1'i64 shl 32 - 1)) # unixTime mod 2^32
|
||||||
|
rng.seed(seed)
|
||||||
|
echo "test_fp12 xoshiro512** seed: ", seed
|
||||||
|
|
||||||
|
# Import: wrap in field element tests in small procedures
|
||||||
|
# otherwise they will become globals,
|
||||||
|
# and will create binary size issues.
|
||||||
|
# Also due to Nim stack scanning,
|
||||||
|
# having too many elements on the stack (a couple kB)
|
||||||
|
# will significantly slow down testing (100x is possible)
|
||||||
|
|
||||||
|
suite "𝔽p12 = 𝔽p6[√∛(1+𝑖)]":
|
||||||
|
test "Squaring 1 returns 1":
|
||||||
|
template test(C: static Curve) =
|
||||||
|
block:
|
||||||
|
proc testInstance() =
|
||||||
|
let One = block:
|
||||||
|
var O{.noInit.}: Fp12[C]
|
||||||
|
O.setOne()
|
||||||
|
O
|
||||||
|
block:
|
||||||
|
var r{.noinit.}: Fp12[C]
|
||||||
|
r.square(One)
|
||||||
|
check: bool(r == One)
|
||||||
|
# block:
|
||||||
|
# var r{.noinit.}: Fp12[C]
|
||||||
|
# r.prod(One, One)
|
||||||
|
# check: bool(r == One)
|
||||||
|
|
||||||
|
testInstance()
|
||||||
|
|
||||||
|
test(BN254)
|
||||||
|
test(BLS12_377)
|
||||||
|
test(BLS12_381)
|
||||||
|
test(BN446)
|
||||||
|
test(FKM12_447)
|
||||||
|
test(BLS12_461)
|
||||||
|
test(BN462)
|
||||||
|
|
||||||
|
test "Squaring 2 returns 4":
|
||||||
|
template test(C: static Curve) =
|
||||||
|
block:
|
||||||
|
proc testInstance() =
|
||||||
|
let One = block:
|
||||||
|
var O{.noInit.}: Fp12[C]
|
||||||
|
O.setOne()
|
||||||
|
O
|
||||||
|
|
||||||
|
var Two: Fp12[C]
|
||||||
|
Two.double(One)
|
||||||
|
|
||||||
|
var Four: Fp12[C]
|
||||||
|
Four.double(Two)
|
||||||
|
|
||||||
|
block:
|
||||||
|
var r: Fp12[C]
|
||||||
|
r.square(Two)
|
||||||
|
|
||||||
|
check: bool(r == Four)
|
||||||
|
# block:
|
||||||
|
# var r: Fp12[C]
|
||||||
|
# r.prod(Two, Two)
|
||||||
|
|
||||||
|
# check: bool(r == Four)
|
||||||
|
|
||||||
|
testInstance()
|
||||||
|
|
||||||
|
# test(BN254)
|
||||||
|
# test(BLS12_377)
|
||||||
|
# test(BLS12_381)
|
||||||
|
# test(BN446)
|
||||||
|
# test(FKM12_447)
|
||||||
|
# test(BLS12_461)
|
||||||
|
# test(BN462)
|
||||||
|
|
||||||
|
test "Squaring 3 returns 9":
|
||||||
|
template test(C: static Curve) =
|
||||||
|
block:
|
||||||
|
proc testInstance() =
|
||||||
|
let One = block:
|
||||||
|
var O{.noInit.}: Fp12[C]
|
||||||
|
O.setOne()
|
||||||
|
O
|
||||||
|
|
||||||
|
var Three: Fp12[C]
|
||||||
|
for _ in 0 ..< 3:
|
||||||
|
Three += One
|
||||||
|
|
||||||
|
var Nine: Fp12[C]
|
||||||
|
for _ in 0 ..< 9:
|
||||||
|
Nine += One
|
||||||
|
|
||||||
|
block:
|
||||||
|
var u: Fp12[C]
|
||||||
|
u.square(Three)
|
||||||
|
|
||||||
|
check: bool(u == Nine)
|
||||||
|
# block:
|
||||||
|
# var u: Fp12[C]
|
||||||
|
# u.prod(Three, Three)
|
||||||
|
|
||||||
|
# check: bool(u == Nine)
|
||||||
|
|
||||||
|
testInstance()
|
||||||
|
|
||||||
|
# test(BN254)
|
||||||
|
# test(BLS12_377)
|
||||||
|
# test(BLS12_381)
|
||||||
|
# test(BN446)
|
||||||
|
# test(FKM12_447)
|
||||||
|
# test(BLS12_461)
|
||||||
|
# test(BN462)
|
||||||
|
|
||||||
|
test "Squaring -3 returns 9":
|
||||||
|
template test(C: static Curve) =
|
||||||
|
block:
|
||||||
|
proc testInstance() =
|
||||||
|
let One = block:
|
||||||
|
var O{.noInit.}: Fp12[C]
|
||||||
|
O.setOne()
|
||||||
|
O
|
||||||
|
|
||||||
|
var MinusThree: Fp12[C]
|
||||||
|
for _ in 0 ..< 3:
|
||||||
|
MinusThree -= One
|
||||||
|
|
||||||
|
var Nine: Fp12[C]
|
||||||
|
for _ in 0 ..< 9:
|
||||||
|
Nine += One
|
||||||
|
|
||||||
|
block:
|
||||||
|
var u: Fp12[C]
|
||||||
|
u.square(MinusThree)
|
||||||
|
|
||||||
|
check: bool(u == Nine)
|
||||||
|
# block:
|
||||||
|
# var u: Fp12[C]
|
||||||
|
# u.prod(MinusThree, MinusThree)
|
||||||
|
|
||||||
|
# check: bool(u == Nine)
|
||||||
|
|
||||||
|
testInstance()
|
||||||
|
|
||||||
|
# test(BN254)
|
||||||
|
# test(BLS12_377)
|
||||||
|
# test(BLS12_381)
|
||||||
|
# test(BN446)
|
||||||
|
# test(FKM12_447)
|
||||||
|
# test(BLS12_461)
|
||||||
|
# test(BN462)
|
Loading…
Reference in New Issue