Implement squaring for 𝔽p6 = 𝔽p2[∛(1+𝑖)]

This commit is contained in:
Mamy André-Ratsimbazafy 2020-03-21 01:59:23 +01:00
parent bde619155b
commit 03898b2292
No known key found for this signature in database
GPG Key ID: 7B88AD1FE79492E1
5 changed files with 293 additions and 62 deletions

View File

@ -63,6 +63,10 @@ From Ben Edgington, https://hackmd.io/@benjaminion/bls12-381
Daniel V. Bailey and Christof Paar, 1998\
https://www.emsec.ruhr-uni-bochum.de/media/crypto/veroeffentlichungen/2015/03/26/crypto98rc9.pdf
- Asymmetric Squaring Formulae\
Jaewook Chung and M. Anwar Hasan\
http://cacr.uwaterloo.ca/techreports/2006/cacr2006-24.pdf
- Multiplication and Squaring on Pairing-Friendly Fields\
Augusto Jun Devegili and Colm Ó hÉigeartaigh and Michael Scott and Ricardo Dahab, 2006\
https://eprint.iacr.org/2006/471

View File

@ -29,67 +29,6 @@ import
# sum(mR, a, b)
# diff(mR, a, b)
# ############################################################
#
# Quadratic Extension fields
#
# ############################################################
type
QuadExtAddGroup* = concept x
## Quadratic extension fields - Abelian Additive Group concept
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 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)
# ############################################################
#
# Cubic Extension fields
@ -142,6 +81,12 @@ func double*(r: var CubicExtAddGroup, a: CubicExtAddGroup) =
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)
@ -153,3 +98,70 @@ func diff*(r: var CubicExtAddGroup, a, b: CubicExtAddGroup) =
r.c0.diff(a.c0, b.c0)
r.c1.diff(a.c1, b.c1)
r.c2.diff(a.c2, b.c2)
# ############################################################
#
# 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)

View File

@ -61,7 +61,7 @@ type
c0*, c1*: Fp[C]
func square*(r: var Fp2, a: Fp2) =
## Return a^2 in 𝔽p2 = 𝔽p[𝑖] in ``r``
## Return a² in 𝔽p2 = 𝔽p[𝑖] in ``r``
## ``r`` is initialized/overwritten
# (c0, c1)² => (c0 + c1𝑖
# => c0² + 2 c0 c1𝑖 + (c1𝑖

View File

@ -0,0 +1,82 @@
# 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.
# ############################################################
#
# Cubic Extension field over base field 𝔽p2
# 𝔽p6 = 𝔽p2[∛(1 + 𝑖)]
#
# ############################################################
# This implements a quadratic extension field over 𝔽p2 = 𝔽p[𝑖]
# the base field 𝔽p:
# 𝔽p6 = 𝔽p2[∛(1 + 𝑖)]
# with element A of coordinates (a0, a1) represented
# by a0 + a1 ξ + a2 ξ²
#
# The irreducible polynomial chosen is
# x³ - ξ with ξ = 𝑖+1
#
#
# Consequently, for this file Fp2 to be valid
# 𝑖+1 MUST not be a square in 𝔽p2
import
../arithmetic,
../config/curves,
./abelian_groups,
./fp2_complex
type
Fp6*[C: static Curve] = object
## Element of the extension field
## 𝔽p6 = 𝔽p2[∛(1 + 𝑖)]
##
## with coordinates (c0, c1, c2) such as
## c0 + c1 ξ + c2 ξ²
##
## This requires 1 + 𝑖 to not be a cube in 𝔽p2
c0*, c1*, c2*: Fp2[C]
Xi = object
## ξ (Xi) the cubic non-residue
func `*`(_: typedesc[Xi], a: Fp2): Fp2 =
## Multiply an element of 𝔽p2 by 𝔽p6 cubic non-residue 1 + 𝑖
## (c0 + c1 𝑖) (1 + 𝑖) => c0 + (c0 + c1)𝑖 + c1 𝑖²
## => c0 - c1 + (c0 + c1) 𝑖
result.c0 = a.c0 - a.c1
result.c1 = a.c0 + a.c1
template `*`(a: Fp2, _: typedesc[Xi]): Fp2 =
Xi * a
func square*[C](r: var Fp6[C], a: Fp6[C]) =
## Return a²
##
# Algorithm is Chung-Hasan Squaring SQR3
# http://cacr.uwaterloo.ca/techreports/2006/cacr2006-24.pdf
var v2{.noInit.}, v3{.noInit.}, v4{.noInit.}, v5{.noInit.}: Fp2[C]
v4.prod(a.c0, a.c1)
v4.double()
v5.square(a.c2)
r.c1 = Xi * v5
r.c1 += v4
v2.diff(v4, v5)
v3.square(a.c0)
v4.diff(a.c0, a.c1)
v4 += a.c2
v5.prod(a.c1, a.c2)
v5.double()
v4.square(v4)
r.c0 = Xi * v5
r.c0 += v3
r.c2.sum(v2, v4)
r.c2 += v5
r.c2 -= v3

133
tests/test_fp6.nim Normal file
View File

@ -0,0 +1,133 @@
# 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, fp6_1_plus_i],
../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_fp6 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 "𝔽p6 = 𝔽p2[∛(1+𝑖)] (irreducible polynomial x³ - (1+𝑖))":
test "Squaring 1 returns 1":
template test(C: static Curve) =
block:
proc testInstance() =
let One = block:
var O{.noInit.}: Fp6[C]
O.setOne()
O
block:
var r{.noinit.}: Fp6[C]
r.square(One)
check: bool(r == One)
# block:
# var r{.noinit.}: Fp6[C]
# r.prod(One, One)
# check: bool(r == One)
testInstance()
test(BN254)
test(BLS12_381)
test "Squaring 2 returns 4":
template test(C: static Curve) =
block:
proc testInstance() =
let One = block:
var O{.noInit.}: Fp6[C]
O.setOne()
O
var Two: Fp6[C]
Two.double(One)
var Four: Fp6[C]
Four.double(Two)
var r: Fp6[C]
r.square(Two)
check: bool(r == Four)
testInstance()
test(BN254)
test(BLS12_381)
test "Squaring 3 returns 9":
template test(C: static Curve) =
block:
proc testInstance() =
let One = block:
var O{.noInit.}: Fp6[C]
O.setOne()
O
var Three: Fp6[C]
for _ in 0 ..< 3:
Three += One
var Nine: Fp6[C]
for _ in 0 ..< 9:
Nine += One
var u: Fp6[C]
u.square(Three)
check: bool(u == Nine)
testInstance()
test(BN254)
test(BLS12_381)
test "Squaring -3 returns 9":
template test(C: static Curve) =
block:
proc testInstance() =
let One = block:
var O{.noInit.}: Fp6[C]
O.setOne()
O
var MinusThree: Fp6[C]
for _ in 0 ..< 3:
MinusThree -= One
var Nine: Fp6[C]
for _ in 0 ..< 9:
Nine += One
var u: Fp6[C]
u.square(MinusThree)
check: bool(u == Nine)
testInstance()
test(BN254)
test(BLS12_381)