Reorg the repo to introduce prepare for introducing the R² (mod p) magic constant

This commit is contained in:
Mamy André-Ratsimbazafy 2020-02-15 13:13:01 +01:00
parent eb94c3d1bc
commit 398b871c4f
No known key found for this signature in database
GPG Key ID: 7B88AD1FE79492E1
8 changed files with 90 additions and 72 deletions

View File

@ -34,8 +34,9 @@ The library is provided as is, without any guarantees at least until:
- formal proofs of correctness are produced
- formal verification of constant-time implementation is possible
Defense against common attack vectors are provided on a best effort basis
attackers may go to great lengths to retrieve secret data including:
Defense against common attack vectors are provided on a best effort basis.
Attackers may go to great lengths to retrieve secret data including:
- Timing the time taken to multiply on an elliptic curve
- Analysing the power usage of embedded devices
- Detecting cache misses when using lookup tables

View File

@ -9,60 +9,8 @@
import
# Internal
./curves_parser, ./common,
../primitives/constant_time,
../math/bigints_checked
../math/[precomputed, bigints_checked]
# ############################################################
#
# Montgomery Magic Constant precomputation
#
# ############################################################
# Note: The declareCurve macro builds an exported montyMagic*(C: static Curve) on top of the one below
func montyMagic(M: BigInt): BaseType =
## Returns the Montgomery domain magic constant for the input modulus:
## -1/M[0] mod LimbSize
## M[0] is the least significant limb of M
## M must be odd and greater than 2.
# We use BaseType for return value because static distinct type
# confuses Nim semchecks [UPSTREAM BUG]
# We don't enforce compile-time evaluation here
# because static BigInt[bits] also causes semcheck troubles [UPSTREAM BUG]
# Modular inverse algorithm:
# Explanation p11 "Dumas iterations" based on Newton-Raphson:
# - Cetin Kaya Koc (2017), https://eprint.iacr.org/2017/411
# - Jean-Guillaume Dumas (2012), https://arxiv.org/pdf/1209.6626v2.pdf
# - Colin Plumb (1994), http://groups.google.com/groups?selm=1994Apr6.093116.27805%40mnemosyne.cs.du.edu
# Other sources:
# - https://crypto.stackexchange.com/questions/47493/how-to-determine-the-multiplicative-inverse-modulo-64-or-other-power-of-two
# - https://mumble.net/~campbell/2015/01/21/inverse-mod-power-of-two
# - http://marc-b-reynolds.github.io/math/2017/09/18/ModInverse.html
# For Montgomery magic number, we are in a special case
# where a = M and m = 2^LimbSize.
# For a and m to be coprimes, a must be odd.
# We have the following relation
# ax ≡ 1 (mod 2^k) <=> ax(2 - ax) ≡ 1 (mod 2^(2k))
#
# To get -1/M0 mod LimbSize
# we can either negate the resulting x of `ax(2 - ax) ≡ 1 (mod 2^(2k))`
# or do ax(2 + ax) ≡ 1 (mod 2^(2k))
#
# To get the the modular inverse of 2^k' with arbitrary k' (like k=63 in our case)
# we can do modInv(a, 2^64) mod 2^63 as mentionned in Koc paper.
let
M0 = BaseType(M.limbs[0])
k = log2(WordPhysBitSize)
result = M0 # Start from an inverse of M0 modulo 2, M0 is odd and it's own inverse
for _ in 0 ..< k: # at each iteration we get the inverse mod(2^2k)
result *= 2 + M0 * result # x' = x(2 + ax) (`+` to avoid negating at the end)
# Our actual word size is 2^63 not 2^64
result = result and BaseType(MaxWord)
# ############################################################
#
@ -89,7 +37,7 @@ func montyMagic(M: BigInt): BaseType =
# - const CurveBitSize: array[Curve, int]
# - proc Mod(curve: static Curve): auto
# which returns the field modulus of the curve
# - proc MontyMagic(curve: static Curve): static Word =
# - proc negInvModWord(curve: static Curve): static Word =
# which returns the Montgomery magic constant
# associated with the curve modulus
when not defined(testingCurves):

View File

@ -198,9 +198,9 @@ macro declareCurves*(curves: untyped): untyped =
procType = nnkFuncDef
)
# proc MontyMagic(curve: static Curve): static Word
# proc negInvModWord(curve: static Curve): static Word
result.add newProc(
name = nnkPostfix.newTree(ident"*", ident"montyMagic"),
name = nnkPostfix.newTree(ident"*", ident"negInvModWord"),
params = [
ident"auto",
newIdentDefs(
@ -209,7 +209,7 @@ macro declareCurves*(curves: untyped): untyped =
)
],
body = newCall(
ident"montyMagic",
ident"negInvModWord",
# curve.Mod().nres
nnkDotExpr.newTree(
newCall(ident"Mod", ident"curve"),

View File

@ -122,7 +122,7 @@ func unsafeMontgomeryResidue*[mBits](nres: var BigInt[mBits], N: BigInt[mBits])
## Nesting Montgomery form is possible by applying this function twice.
montgomeryResidue(nres.view, N.view)
func unsafeRedc*[mBits](nres: var BigInt[mBits], N: BigInt[mBits], montyMagic: static BaseType) =
func unsafeRedc*[mBits](nres: var BigInt[mBits], N: BigInt[mBits], negInvModWord: static BaseType) =
## Convert a BigInt from its Montgomery n-residue form
## to the natural representation
##
@ -130,11 +130,11 @@ func unsafeRedc*[mBits](nres: var BigInt[mBits], N: BigInt[mBits], montyMagic: s
##
## Caller must take care of properly switching between
## the natural and montgomery domain.
redc(nres.view, N.view, Word(montyMagic))
redc(nres.view, N.view, Word(negInvModWord))
func montyMul*[mBits](r: var BigInt[mBits], a, b, M: BigInt[mBits], montyMagic: static BaseType) =
func montyMul*[mBits](r: var BigInt[mBits], a, b, M: BigInt[mBits], negInvModWord: static BaseType) =
## Compute r <- a*b (mod M) in the Montgomery domain
##
## This resets r to zero before processing. Use {.noInit.}
## to avoid duplicating with Nim zero-init policy
montyMul(r.view, a.view, b.view, M.view, Word(montyMagic))
montyMul(r.view, a.view, b.view, M.view, Word(negInvModWord))

View File

@ -415,7 +415,7 @@ func montgomeryResidue*(a: BigIntViewMut, N: BigIntViewConst) =
template wordMul(a, b: Word): Word =
(a * b) and MaxWord
func redc*(a: BigIntViewMut, N: BigIntViewConst, montyMagic: Word) =
func redc*(a: BigIntViewMut, N: BigIntViewConst, negInvModWord: Word) =
## Transform a bigint ``a`` from it's Montgomery N-residue representation (mod N)
## to the regular natural representation (mod N)
##
@ -424,7 +424,7 @@ func redc*(a: BigIntViewMut, N: BigIntViewConst, montyMagic: Word) =
##
## This is called a Montgomery Reduction
## The Montgomery Magic Constant is µ = -1/N mod N
## is used internally and can be precomputed with montyMagic(Curve)
## is used internally and can be precomputed with negInvModWord(Curve)
# References:
# - https://eprint.iacr.org/2017/1057.pdf (Montgomery)
# page: Radix-r interleaved multiplication algorithm
@ -439,7 +439,7 @@ func redc*(a: BigIntViewMut, N: BigIntViewConst, montyMagic: Word) =
let nLen = N.numLimbs()
for i in 0 ..< nLen:
let z0 = wordMul(a[0], montyMagic)
let z0 = wordMul(a[0], negInvModWord)
var carry = DoubleWord(0)
for j in 0 ..< nLen:
@ -452,9 +452,9 @@ func redc*(a: BigIntViewMut, N: BigIntViewConst, montyMagic: Word) =
func montyMul*(
r: BigIntViewMut, a, b: distinct BigIntViewAny,
M: BigIntViewConst, montyMagic: Word) =
M: BigIntViewConst, negInvModWord: Word) =
## Compute r <- a*b (mod M) in the Montgomery domain
## `montyMagic` = -1/M (mod Word). Our words are 2^31 or 2^63
## `negInvModWord` = -1/M (mod Word). Our words are 2^31 or 2^63
##
## This resets r to zero before processing. Use {.noInit.}
## to avoid duplicating with Nim zero-init policy
@ -473,7 +473,7 @@ func montyMul*(
var r_hi = Zero # represents the high word that is used in intermediate computation before reduction mod M
for i in 0 ..< nLen:
let zi = (r[0] + wordMul(a[i], b[0])).wordMul(montyMagic)
let zi = (r[0] + wordMul(a[i], b[0])).wordMul(negInvModWord)
var carry = Zero
for j in 0 ..< nLen:

View File

@ -57,7 +57,7 @@ func fromBig*(T: type Fq, src: BigInt): T =
func toBig*[C: static Curve](src: Fq[C]): auto =
## Convert a finite-field element to a BigInt in natral representation
result = src.nres
result.unsafeRedC(C.Mod.nres, montyMagic(C))
result.unsafeRedC(C.Mod.nres, negInvModWord(C))
# ############################################################
#
@ -107,4 +107,4 @@ func `*`*(a, b: Fq): Fq {.noInit.} =
## as Fq elements are usually large and this
## routine will zero init internally the result.
result.nres.setInternalBitLength()
result.nres.montyMul(a.nres, b.nres, Fq.C.Mod.nres, montyMagic(Fq.C))
result.nres.montyMul(a.nres, b.nres, Fq.C.Mod.nres, negInvModWord(Fq.C))

View File

@ -0,0 +1,67 @@
# 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
./bigints_checked,
../primitives/constant_time,
../config/common
# Precomputed constants
# ############################################################
# ############################################################
#
# Montgomery Magic Constants precomputation
#
# ############################################################
# Note: The declareCurve macro builds an exported negInvModWord*(C: static Curve) on top of the one below
func negInvModWord*(M: BigInt): BaseType =
## Returns the Montgomery domain magic constant for the input modulus:
## -1/M[0] mod LimbSize
## M[0] is the least significant limb of M
## M must be odd and greater than 2.
# We use BaseType for return value because static distinct type
# confuses Nim semchecks [UPSTREAM BUG]
# We don't enforce compile-time evaluation here
# because static BigInt[bits] also causes semcheck troubles [UPSTREAM BUG]
# Modular inverse algorithm:
# Explanation p11 "Dumas iterations" based on Newton-Raphson:
# - Cetin Kaya Koc (2017), https://eprint.iacr.org/2017/411
# - Jean-Guillaume Dumas (2012), https://arxiv.org/pdf/1209.6626v2.pdf
# - Colin Plumb (1994), http://groups.google.com/groups?selm=1994Apr6.093116.27805%40mnemosyne.cs.du.edu
# Other sources:
# - https://crypto.stackexchange.com/questions/47493/how-to-determine-the-multiplicative-inverse-modulo-64-or-other-power-of-two
# - https://mumble.net/~campbell/2015/01/21/inverse-mod-power-of-two
# - http://marc-b-reynolds.github.io/math/2017/09/18/ModInverse.html
# For Montgomery magic number, we are in a special case
# where a = M and m = 2^LimbSize.
# For a and m to be coprimes, a must be odd.
# We have the following relation
# ax ≡ 1 (mod 2^k) <=> ax(2 - ax) ≡ 1 (mod 2^(2k))
#
# To get -1/M0 mod LimbSize
# we can either negate the resulting x of `ax(2 - ax) ≡ 1 (mod 2^(2k))`
# or do ax(2 + ax) ≡ 1 (mod 2^(2k))
#
# To get the the modular inverse of 2^k' with arbitrary k' (like k=63 in our case)
# we can do modInv(a, 2^64) mod 2^63 as mentionned in Koc paper.
let
M0 = BaseType(M.limbs[0])
k = log2(WordPhysBitSize)
result = M0 # Start from an inverse of M0 modulo 2, M0 is odd and it's own inverse
for _ in 0 ..< k: # at each iteration we get the inverse mod(2^2k)
result *= 2 + M0 * result # x' = x(2 + ax) (`+` to avoid negating at the end)
# Our actual word size is 2^63 not 2^64
result = result and BaseType(MaxWord)

View File

@ -151,10 +151,12 @@ template isMsbSet*[T: Ct](x: T): CTBool[T] =
const msb_pos = T.sizeof * 8 - 1
(CTBool[T])(x shr msb_pos)
func log2*(x: uint32): uint32 =
func log2*(x: uint32): uint32 {.compileTime.} =
## Find the log base 2 of a 32-bit or less integer.
## using De Bruijn multiplication
## Works at compile-time, guaranteed constant-time.
## Note: at runtime BitScanReverse or CountLeadingZero are more efficient
## but log2 is never needed at runtime.
# https://graphics.stanford.edu/%7Eseander/bithacks.html#IntegerLogDeBruijn
const lookup: array[32, uint8] = [0'u8, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18,
22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31]