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
|
||||
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] =
|
||||
## Constant-time big integer in-place optional addition
|
||||
## 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.
|
||||
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]) =
|
||||
## 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
|
||||
## the natural and montgomery domain.
|
||||
let one = block:
|
||||
var one: BigInt[mBits]
|
||||
one.setInternalBitLength()
|
||||
one.limbs[0] = Word(1)
|
||||
var one {.noInit.}: BigInt[mBits]
|
||||
one.setOne()
|
||||
one
|
||||
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]
|
||||
result = accum.isZero()
|
||||
|
||||
func setZero*(a: BigIntViewMut) =
|
||||
func setZero(a: BigIntViewMut) =
|
||||
## Set a BigInt to 0
|
||||
## It's bit size is unchanged
|
||||
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)
|
||||
# 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) =
|
||||
## Addition over Fp
|
||||
## Addition modulo p
|
||||
var ctl = add(a, b, CtTrue)
|
||||
ctl = ctl or not sub(a, Fp.C.Mod, CtFalse)
|
||||
discard sub(a, Fp.C.Mod, ctl)
|
||||
|
||||
func `-=`*(a: var Fp, b: Fp) =
|
||||
## Substraction over Fp
|
||||
## Substraction modulo p
|
||||
let ctl = sub(a, b, CtTrue)
|
||||
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.} =
|
||||
## Multiplication over Fp
|
||||
## Multiplication modulo p
|
||||
##
|
||||
## It is recommended to assign with {.noInit.}
|
||||
## as Fp elements are usually large and this
|
||||
## routine will zero init internally the result.
|
||||
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.} =
|
||||
## Squaring over Fp
|
||||
## Squaring modulo p
|
||||
##
|
||||
## It is recommended to assign with {.noInit.}
|
||||
## 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())
|
||||
|
||||
func pow*(a: var Fp, exponent: BigInt) =
|
||||
## Exponentiation over Fp
|
||||
## Exponentiation modulo p
|
||||
## ``a``: a field element to be exponentiated
|
||||
## ``exponent``: a big integer
|
||||
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) =
|
||||
## Exponentiation over Fp
|
||||
## Exponentiation modulo p
|
||||
## ``a``: a field element to be exponentiated
|
||||
## ``exponent``: a big integer
|
||||
##
|
||||
|
@ -170,7 +197,7 @@ func powUnsafeExponent*(a: var Fp, exponent: BigInt) =
|
|||
)
|
||||
|
||||
func inv*(a: var Fp) =
|
||||
## Modular inversion
|
||||
## Inversion modulo p
|
||||
## Warning ⚠️ :
|
||||
## - This assumes that `Fp` is a prime field
|
||||
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