From 398b871c4f16c0eb30c1beda062e142d3e4aa911 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mamy=20Andr=C3=A9-Ratsimbazafy?= Date: Sat, 15 Feb 2020 13:13:01 +0100 Subject: [PATCH] =?UTF-8?q?Reorg=20the=20repo=20to=20introduce=20prepare?= =?UTF-8?q?=20for=20introducing=20the=20R=C2=B2=20(mod=20p)=20magic=20cons?= =?UTF-8?q?tant?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 5 +- constantine/config/curves.nim | 56 +------------------- constantine/config/curves_parser.nim | 6 +-- constantine/math/bigints_checked.nim | 8 +-- constantine/math/bigints_raw.nim | 12 ++--- constantine/math/finite_fields.nim | 4 +- constantine/math/precomputed.nim | 67 ++++++++++++++++++++++++ constantine/primitives/constant_time.nim | 4 +- 8 files changed, 90 insertions(+), 72 deletions(-) create mode 100644 constantine/math/precomputed.nim diff --git a/README.md b/README.md index 7ad3e96..8dd4796 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/constantine/config/curves.nim b/constantine/config/curves.nim index 5009287..eb3aeb5 100644 --- a/constantine/config/curves.nim +++ b/constantine/config/curves.nim @@ -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): diff --git a/constantine/config/curves_parser.nim b/constantine/config/curves_parser.nim index 1edf1b5..9f6ad66 100644 --- a/constantine/config/curves_parser.nim +++ b/constantine/config/curves_parser.nim @@ -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"), diff --git a/constantine/math/bigints_checked.nim b/constantine/math/bigints_checked.nim index 17ffacb..458cd75 100644 --- a/constantine/math/bigints_checked.nim +++ b/constantine/math/bigints_checked.nim @@ -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)) diff --git a/constantine/math/bigints_raw.nim b/constantine/math/bigints_raw.nim index 2001031..94572f9 100644 --- a/constantine/math/bigints_raw.nim +++ b/constantine/math/bigints_raw.nim @@ -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: diff --git a/constantine/math/finite_fields.nim b/constantine/math/finite_fields.nim index b8c0e59..1cd8727 100644 --- a/constantine/math/finite_fields.nim +++ b/constantine/math/finite_fields.nim @@ -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)) diff --git a/constantine/math/precomputed.nim b/constantine/math/precomputed.nim new file mode 100644 index 0000000..6b88974 --- /dev/null +++ b/constantine/math/precomputed.nim @@ -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) diff --git a/constantine/primitives/constant_time.nim b/constantine/primitives/constant_time.nim index 939a810..3a1f341 100644 --- a/constantine/primitives/constant_time.nim +++ b/constantine/primitives/constant_time.nim @@ -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]