Mamy Ratsimbazafy c312210878
Rework towering (#148)
* naive removal of out-of-place mul by non residue

* Use {.inline.} in a consistent manner across the codebase

* Handle aliasing for quadratic multiplication

* reorg optimization

* Handle aliasing for quadratic squaring

* handle aliasing in mul_sparse_complex_by_0y

* Rework multiplication by nonresidue, assume tower and twist use same non-residue

* continue rework

* continue on non-residues

* Remove "NonResidue *" calls

* handle aliasing in Chung-Hasan SQR2

* Handla aliasing in Chung-Hasan SQR3

* Use one less temporary in Chung Hasan sqr2

* handle aliasing in cubic extensions

* merge extension tower in the same file to reduce duplicate proc and allow better inlining

* handle aliasing in cubic inversion

* drop out-of-place proc from BigInt and finite fields as well

* less copies in line_projective

* remove a copy in fp12 by lines
2021-02-06 16:28:38 +01:00

190 lines
6.0 KiB
Nim

# 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,
../io/io_bigints,
./extension_fields
# ############################################################
#
# Exponentiations (pow and square roots) in extension fields
#
# ############################################################
# Square root should be implemented in constant-time for hash-to-curve:
# https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-05#section-4
# No exceptions allowed
{.push raises: [].}
# Pow
# -----------------------------------------------------------
template checkPowScratchSpaceLen(len: int) =
## Checks that there is a minimum of scratchspace to hold the temporaries
debug:
assert len >= 2, "Internal Error: the scratchspace for powmod should be equal or greater than 2"
func getWindowLen(bufLen: int): uint =
## Compute the maximum window size that fits in the scratchspace buffer
checkPowScratchSpaceLen(bufLen)
result = 4
while (1 shl result) + 1 > bufLen:
dec result
func powPrologue[F](a: var F, scratchspace: var openarray[F]): uint =
## Setup the scratchspace, then set a to 1.
## Returns the fixed-window size for exponentiation with window optimization
result = scratchspace.len.getWindowLen
# Precompute window content, special case for window = 1
# (i.e scratchspace has only space for 2 temporaries)
# The content scratchspace[2+k] is set at [k]P
# with scratchspace[0] untouched
if result == 1:
scratchspace[1] = a
else:
scratchspace[2] = a
for k in 2 ..< 1 shl result:
scratchspace[k+1].prod(scratchspace[k], a)
a.setOne()
func powSquarings[F](
a: var F,
exponent: openArray[byte],
tmp: var F,
window: uint,
acc, acc_len: var uint,
e: var int
): tuple[k, bits: uint] {.inline.}=
## Squaring step of exponentiation by squaring
## Get the next k bits in range [1, window)
## Square k times
## Returns the number of squarings done and the corresponding bits
##
## Updates iteration variables and accumulators
# Due to the high number of parameters,
# forcing this inline actually reduces the code size
#
# ⚠️: Extreme care should be used to not leak
# the exponent bits nor its real bitlength
# i.e. if the exponent is zero but encoded in a
# 256-bit integer, only "256" should leak
# as for some application like RSA
# the exponent might be the user secret key.
# Get the next bits
# acc/acc_len must be uint to avoid Nim runtime checks leaking bits
# acc/acc_len must be uint to avoid Nim runtime checks leaking bits
# e is public
var k = window
if acc_len < window:
if e < exponent.len:
acc = (acc shl 8) or exponent[e].uint
inc e
acc_len += 8
else: # Drained all exponent bits
k = acc_len
let bits = (acc shr (acc_len - k)) and ((1'u32 shl k) - 1)
acc_len -= k
# We have k bits and can do k squaring
for i in 0 ..< k:
a.square()
return (k, bits)
func powUnsafeExponent[F](
a: var F,
exponent: openArray[byte],
scratchspace: var openArray[F]
) =
## Extension field exponentiation r = a^exponent (mod p^m)
##
## Warning ⚠️ :
## This is an optimization for public exponent
## Otherwise bits of the exponent can be retrieved with:
## - memory access analysis
## - power analysis
## - timing analysis
# TODO: scratchspace[1] is unused when window > 1
let window = powPrologue(a, scratchspace)
var
acc, acc_len: uint
e = 0
while acc_len > 0 or e < exponent.len:
let (_, bits) = powSquarings(
a, exponent,
scratchspace[0], window,
acc, acc_len, e
)
## Warning ⚠️: Exposes the exponent bits
if bits != 0:
if window > 1:
scratchspace[0].prod(a, scratchspace[1+bits])
else:
# scratchspace[1] holds the original `a`
scratchspace[0].prod(a, scratchspace[1])
a = scratchspace[0]
func powUnsafeExponent*[F](
a: var F,
exponent: openArray[byte],
window: static int
) =
## Extension field exponentiation r = a^exponent (mod p^m)
## exponent is an big integer in canonical octet-string format
##
## Window is used for window optimization.
## 2^window field elements are allocated for scratchspace.
##
## - On Fp2, with a 256-bit base field, a window of size 5 requires
## 2*256*2^5 = 16KiB
##
## Warning ⚠️ :
## This is an optimization for public exponent
## Otherwise bits of the exponent can be retrieved with:
## - memory access analysis
## - power analysis
## - timing analysis
const scratchLen = if window == 1: 2
else: (1 shl window) + 1
var scratchSpace {.noInit.}: array[scratchLen, typeof(a)]
a.powUnsafeExponent(exponent, scratchspace)
func powUnsafeExponent*[F; bits: static int](
a: var F,
exponent: BigInt[bits],
window: static int
) =
## Extension field exponentiation r = a^exponent (mod p^m)
## exponent is an big integer in canonical octet-string format
##
## Window is used for window optimization.
## 2^window field elements are allocated for scratchspace.
##
## - On Fp2, with a 256-bit base field, a window of size 5 requires
## 2*256*2^5 = 16KiB
##
## Warning ⚠️ :
## This is an optimization for public exponent
## Otherwise bits of the exponent can be retrieved with:
## - memory access analysis
## - power analysis
## - timing analysis
var expBE {.noInit.}: array[(bits + 7) div 8, byte]
expBE.exportRawUint(exponent, bigEndian)
a.powUnsafeExponent(expBE, window)