Fp: setZero, setOne, double, in-place mul, Fp2: square
This commit is contained in:
parent
6b05c69652
commit
78dee73648
|
@ -101,6 +101,18 @@ func isZero*(a: BigInt): CTBool[Word] =
|
||||||
## Returns true if a big int is equal to zero
|
## Returns true if a big int is equal to zero
|
||||||
a.view.isZero
|
a.view.isZero
|
||||||
|
|
||||||
|
func setZero*(a: var BigInt) =
|
||||||
|
## Set a BigInt to 0
|
||||||
|
a.setInternalBitLength()
|
||||||
|
zeroMem(a.limbs[0].unsafeAddr, a.limbs.len * sizeof(Word))
|
||||||
|
|
||||||
|
func setOne*(a: var BigInt) =
|
||||||
|
## Set a BigInt to 1
|
||||||
|
a.setInternalBitLength()
|
||||||
|
a.limbs[0] = Word(1)
|
||||||
|
when a.limbs.len > 1:
|
||||||
|
zeroMem(a.limbs[1].unsafeAddr, (a.limbs.len-1) * sizeof(Word))
|
||||||
|
|
||||||
func add*[bits](a: var BigInt[bits], b: BigInt[bits], ctl: CTBool[Word]): CTBool[Word] =
|
func add*[bits](a: var BigInt[bits], b: BigInt[bits], ctl: CTBool[Word]): CTBool[Word] =
|
||||||
## Constant-time big integer in-place optional addition
|
## Constant-time big integer in-place optional addition
|
||||||
## The addition is only performed if ctl is "true"
|
## The addition is only performed if ctl is "true"
|
||||||
|
@ -113,6 +125,12 @@ func sub*[bits](a: var BigInt[bits], b: BigInt[bits], ctl: CTBool[Word]): CTBool
|
||||||
## The result carry is always computed.
|
## The result carry is always computed.
|
||||||
sub(a.view, b.view, ctl)
|
sub(a.view, b.view, ctl)
|
||||||
|
|
||||||
|
func double*[bits](a: var BigInt[bits], ctl: CTBool[Word]): CTBool[Word] =
|
||||||
|
## Constant-time big integer in-place optional doubling
|
||||||
|
## The doubling is only performed if ctl is "true"
|
||||||
|
## The result carry is always computed.
|
||||||
|
add(a.view, a.view, ctl)
|
||||||
|
|
||||||
func reduce*[aBits, mBits](r: var BigInt[mBits], a: BigInt[aBits], M: BigInt[mBits]) =
|
func reduce*[aBits, mBits](r: var BigInt[mBits], a: BigInt[aBits], M: BigInt[mBits]) =
|
||||||
## Reduce `a` modulo `M` and store the result in `r`
|
## Reduce `a` modulo `M` and store the result in `r`
|
||||||
##
|
##
|
||||||
|
@ -145,9 +163,8 @@ func redc*[mBits](r: var BigInt[mBits], a, N: BigInt[mBits], negInvModWord: stat
|
||||||
## Caller must take care of properly switching between
|
## Caller must take care of properly switching between
|
||||||
## the natural and montgomery domain.
|
## the natural and montgomery domain.
|
||||||
let one = block:
|
let one = block:
|
||||||
var one: BigInt[mBits]
|
var one {.noInit.}: BigInt[mBits]
|
||||||
one.setInternalBitLength()
|
one.setOne()
|
||||||
one.limbs[0] = Word(1)
|
|
||||||
one
|
one
|
||||||
redc(r.view, a.view, one.view, N.view, Word(negInvModWord))
|
redc(r.view, a.view, one.view, N.view, Word(negInvModWord))
|
||||||
|
|
||||||
|
|
|
@ -223,7 +223,7 @@ func isZero*(a: BigIntViewAny): CTBool[Word] =
|
||||||
accum = accum or a[i]
|
accum = accum or a[i]
|
||||||
result = accum.isZero()
|
result = accum.isZero()
|
||||||
|
|
||||||
func setZero*(a: BigIntViewMut) =
|
func setZero(a: BigIntViewMut) =
|
||||||
## Set a BigInt to 0
|
## Set a BigInt to 0
|
||||||
## It's bit size is unchanged
|
## It's bit size is unchanged
|
||||||
zeroMem(a[0].unsafeAddr, a.numLimbs() * sizeof(Word))
|
zeroMem(a[0].unsafeAddr, a.numLimbs() * sizeof(Word))
|
||||||
|
|
|
@ -113,27 +113,54 @@ template sub(a: var Fp, b: Fp, ctl: CTBool[Word]): CTBool[Word] =
|
||||||
# - Golden Primes (φ^2 - φ - 1 with φ = 2^k for example Ed448-Goldilocks: 2^448 - 2^224 - 1)
|
# - Golden Primes (φ^2 - φ - 1 with φ = 2^k for example Ed448-Goldilocks: 2^448 - 2^224 - 1)
|
||||||
# exist and can be implemented with compile-time specialization.
|
# exist and can be implemented with compile-time specialization.
|
||||||
|
|
||||||
|
func setZero*(a: var Fp) =
|
||||||
|
## Set ``a`` to zero
|
||||||
|
a.setZero()
|
||||||
|
|
||||||
|
func setOne*(a: var Fp) =
|
||||||
|
## Set ``a`` to one
|
||||||
|
# Note: we need 1 in Montgomery residue form
|
||||||
|
a = Fp.C.getMontyOne()
|
||||||
|
|
||||||
func `+=`*(a: var Fp, b: Fp) =
|
func `+=`*(a: var Fp, b: Fp) =
|
||||||
## Addition over Fp
|
## Addition modulo p
|
||||||
var ctl = add(a, b, CtTrue)
|
var ctl = add(a, b, CtTrue)
|
||||||
ctl = ctl or not sub(a, Fp.C.Mod, CtFalse)
|
ctl = ctl or not sub(a, Fp.C.Mod, CtFalse)
|
||||||
discard sub(a, Fp.C.Mod, ctl)
|
discard sub(a, Fp.C.Mod, ctl)
|
||||||
|
|
||||||
func `-=`*(a: var Fp, b: Fp) =
|
func `-=`*(a: var Fp, b: Fp) =
|
||||||
## Substraction over Fp
|
## Substraction modulo p
|
||||||
let ctl = sub(a, b, CtTrue)
|
let ctl = sub(a, b, CtTrue)
|
||||||
discard add(a, Fp.C.Mod, ctl)
|
discard add(a, Fp.C.Mod, ctl)
|
||||||
|
|
||||||
|
func double*(a: var Fp) =
|
||||||
|
## Double ``a`` modulo p
|
||||||
|
var ctl = double(a, CtTrue)
|
||||||
|
ctl = ctl or not sub(a, Fp.C.Mod, CtFalse)
|
||||||
|
discard sub(a, Fp.C.Mod, ctl)
|
||||||
|
|
||||||
func `*`*(a, b: Fp): Fp {.noInit.} =
|
func `*`*(a, b: Fp): Fp {.noInit.} =
|
||||||
## Multiplication over Fp
|
## Multiplication modulo p
|
||||||
##
|
##
|
||||||
## It is recommended to assign with {.noInit.}
|
## It is recommended to assign with {.noInit.}
|
||||||
## as Fp elements are usually large and this
|
## as Fp elements are usually large and this
|
||||||
## routine will zero init internally the result.
|
## routine will zero init internally the result.
|
||||||
result.mres.montyMul(a.mres, b.mres, Fp.C.Mod.mres, Fp.C.getNegInvModWord())
|
result.mres.montyMul(a.mres, b.mres, Fp.C.Mod.mres, Fp.C.getNegInvModWord())
|
||||||
|
|
||||||
|
func `*=`*(a: var Fp, b: Fp) =
|
||||||
|
## Multiplication modulo p
|
||||||
|
##
|
||||||
|
## Implementation note:
|
||||||
|
## - This requires a temporary field element
|
||||||
|
##
|
||||||
|
## Cost
|
||||||
|
## Stack: 1 * ModulusBitSize
|
||||||
|
var tmp{.noInit.}: Fp
|
||||||
|
tmp.mres.montyMul(a.mres, b.mres, Fp.C.Mod.mres, Fp.C.getNegInvModWord())
|
||||||
|
a = tmp
|
||||||
|
|
||||||
func square*(a: Fp): Fp {.noInit.} =
|
func square*(a: Fp): Fp {.noInit.} =
|
||||||
## Squaring over Fp
|
## Squaring modulo p
|
||||||
##
|
##
|
||||||
## It is recommended to assign with {.noInit.}
|
## It is recommended to assign with {.noInit.}
|
||||||
## as Fp elements are usually large and this
|
## as Fp elements are usually large and this
|
||||||
|
@ -141,7 +168,7 @@ func square*(a: Fp): Fp {.noInit.} =
|
||||||
result.mres.montySquare(a.mres, Fp.C.Mod.mres, Fp.C.getNegInvModWord())
|
result.mres.montySquare(a.mres, Fp.C.Mod.mres, Fp.C.getNegInvModWord())
|
||||||
|
|
||||||
func pow*(a: var Fp, exponent: BigInt) =
|
func pow*(a: var Fp, exponent: BigInt) =
|
||||||
## Exponentiation over Fp
|
## Exponentiation modulo p
|
||||||
## ``a``: a field element to be exponentiated
|
## ``a``: a field element to be exponentiated
|
||||||
## ``exponent``: a big integer
|
## ``exponent``: a big integer
|
||||||
const windowSize = 5 # TODO: find best window size for each curves
|
const windowSize = 5 # TODO: find best window size for each curves
|
||||||
|
@ -152,7 +179,7 @@ func pow*(a: var Fp, exponent: BigInt) =
|
||||||
)
|
)
|
||||||
|
|
||||||
func powUnsafeExponent*(a: var Fp, exponent: BigInt) =
|
func powUnsafeExponent*(a: var Fp, exponent: BigInt) =
|
||||||
## Exponentiation over Fp
|
## Exponentiation modulo p
|
||||||
## ``a``: a field element to be exponentiated
|
## ``a``: a field element to be exponentiated
|
||||||
## ``exponent``: a big integer
|
## ``exponent``: a big integer
|
||||||
##
|
##
|
||||||
|
@ -170,7 +197,7 @@ func powUnsafeExponent*(a: var Fp, exponent: BigInt) =
|
||||||
)
|
)
|
||||||
|
|
||||||
func inv*(a: var Fp) =
|
func inv*(a: var Fp) =
|
||||||
## Modular inversion
|
## Inversion modulo p
|
||||||
## Warning ⚠️ :
|
## Warning ⚠️ :
|
||||||
## - This assumes that `Fp` is a prime field
|
## - This assumes that `Fp` is a prime field
|
||||||
const windowSize = 5 # TODO: find best window size for each curves
|
const windowSize = 5 # TODO: find best window size for each curves
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
# 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
|
||||||
|
|
||||||
|
import
|
||||||
|
../arithmetic/finite_fields,
|
||||||
|
../config/curves
|
||||||
|
|
||||||
|
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[Curve]
|
||||||
|
|
||||||
|
func setZero*(a: var Fp2) =
|
||||||
|
## Set ``a`` to zero in 𝔽p2
|
||||||
|
## Coordinates 0 + 0𝑖
|
||||||
|
a.c0.setZero()
|
||||||
|
a.c1.setZero()
|
||||||
|
|
||||||
|
func setOne*(a: var Fp2) =
|
||||||
|
## Set ``a`` to one in 𝔽p2
|
||||||
|
## Coordinates 1 + 0𝑖
|
||||||
|
a.c0.setOne()
|
||||||
|
a.c1.setZero()
|
||||||
|
|
||||||
|
func `+=`*(a: var Fp2, b: Fp2) =
|
||||||
|
## Addition over 𝔽p2
|
||||||
|
a.c0 += b.c0
|
||||||
|
a.c1 += b.c1
|
||||||
|
|
||||||
|
func `-=`*(a: var Fp2, b: Fp2) =
|
||||||
|
## Substraction over 𝔽p2
|
||||||
|
a.c0 -= b.c0
|
||||||
|
a.c1 -= b.c1
|
||||||
|
|
||||||
|
func square*(a: Fp2): Fp2 {.noInit.} =
|
||||||
|
## Return a^2 in 𝔽p2
|
||||||
|
# (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), 2 c0 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 multiplication temporary)
|
||||||
|
# as multiplications require a (shared) internal temporary
|
||||||
|
|
||||||
|
var c0mc1 = a.c0
|
||||||
|
c0mc1 -= a.c1 # c0mc1 = c0 - c1 [1 Sub]
|
||||||
|
result.c0 = c0mc1 # result.c0 = c0 - c1
|
||||||
|
|
||||||
|
result.c1 = a.c1
|
||||||
|
result.c1.double() # result.c1 = 2 c1 [1 Dbl, 1 Sub]
|
||||||
|
|
||||||
|
result.c0 += result.c1 # result.c0 = c0 - c1 + 2 c1 [1 Add, 1 Dbl, 1 Sub]
|
||||||
|
result.c0 *= c0mc1 # result.c0 = (c0 + c1)(c0 - c1) = c0² - c1² [1 Mul, 1 Add, 1 Dbl, 1 Sub]
|
||||||
|
|
||||||
|
result.c1 *= a.c0 # result.c1 = 2 c1 c0 [2 Mul, 1 Add, 1 Dbl, 1 Sub]
|
Loading…
Reference in New Issue