Reorg the repo to introduce prepare for introducing the R² (mod p) magic constant
This commit is contained in:
parent
eb94c3d1bc
commit
398b871c4f
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
|
@ -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]
|
||||
|
|
Loading…
Reference in New Issue