From f418e0874615be234e78283b2b0c3e6c20f5cfde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mamy=20Andr=C3=A9-Ratsimbazafy?= Date: Fri, 14 Feb 2020 13:36:34 +0100 Subject: [PATCH] For finite fields, we will use the Montgomery n-residue form by default --- constantine/config/curves.nim | 1 + constantine/config/curves_parser.nim | 20 ++++++--- constantine/math/finite_fields.nim | 57 +++++++++++++++++-------- constantine/math/montgomery_checked.nim | 38 ----------------- constantine/math/montgomery_raw.nim | 7 --- tests/test_finite_fields.nim | 12 +++--- 6 files changed, 59 insertions(+), 76 deletions(-) delete mode 100644 constantine/math/montgomery_checked.nim delete mode 100644 constantine/math/montgomery_raw.nim diff --git a/constantine/config/curves.nim b/constantine/config/curves.nim index 9e15013..585bf1f 100644 --- a/constantine/config/curves.nim +++ b/constantine/config/curves.nim @@ -27,6 +27,7 @@ func montyMagic(M: static BigInt): static Word {.inline.} = # Test vectors: https://www.researchgate.net/publication/4107322_Montgomery_modular_multiplication_architecture_for_public_key_cryptosystems # on p354 # Reference C impl: http://www.hackersdelight.org/hdcodetxt/mont64.c.txt + # Explanation: https://eprint.iacr.org/2017/1057.pdf # ###################################################################### # Implementation of modular multiplicative inverse diff --git a/constantine/config/curves_parser.nim b/constantine/config/curves_parser.nim index fb965b6..1087b67 100644 --- a/constantine/config/curves_parser.nim +++ b/constantine/config/curves_parser.nim @@ -60,7 +60,7 @@ macro declareCurves*(curves: untyped): untyped = var curveModStmts = newStmtList() var curveModWhenStmt = nnkWhenStmt.newTree() - let Fp = ident"Fp" + let Fq = ident"Fq" for curveDesc in curves: curveDesc.expectKind(nnkCommand) @@ -88,14 +88,14 @@ macro declareCurves*(curves: untyped): untyped = curve, bitSize ) - # const BN254_Modulus = Fp[BN254](value: fromHex(BigInt[254], "0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47")) + # const BN254_Modulus = Fq[BN254](value: fromHex(BigInt[254], "0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47")) let modulusID = ident($curve & "_Modulus") curveModStmts.add newConstStmt( modulusID, nnkObjConstr.newTree( - nnkBracketExpr.newTree(Fp, curve), + nnkBracketExpr.newTree(Fq, curve), nnkExprColonExpr.newTree( - ident"value", + ident"nres", newCall( bindSym"fromHex", nnkBracketExpr.newTree(bindSym"BigInt", bitSize), @@ -146,13 +146,15 @@ macro declareCurves*(curves: untyped): untyped = ) # type - # `Fp`*[C: static Curve] = object + # `Fq`*[C: static Curve] = object # ## All operations on a field are modulo P # ## P being the prime modulus of the Curve C - # value*: matchingBigInt(C) + # ## Internally, data is stored in Montgomery n-residue form + # ## with the magic constant chosen for convenient division (a power of 2 depending on P bitsize) + # nres*: matchingBigInt(C) result.add nnkTypeSection.newTree( nnkTypeDef.newTree( - nnkPostfix.newTree(ident"*", Fp), + nnkPostfix.newTree(ident"*", Fq), nnkGenericParams.newTree(newIdentDefs( C, nnkStaticTy.newTree(Curve), newEmptyNode() )), @@ -160,6 +162,10 @@ macro declareCurves*(curves: untyped): untyped = newEmptyNode(), newEmptyNode(), nnkRecList.newTree( + nnkCommentStmt.newTree "All operations on a field are modulo P", + nnkCommentStmt.newTree "P being the prime modulus of the Curve C", + nnkCommentStmt.newTree "Internally, data is stored in Montgomery n-residue form", + nnkCommentStmt.newTree "with the magic constant chosen for convenient division (a power of 2 depending on P bitsize)" newIdentDefs( nnkPostfix.newTree(ident"*", ident"value"), newCall(matchingBigInt, C) diff --git a/constantine/math/finite_fields.nim b/constantine/math/finite_fields.nim index 5ed39da..572577f 100644 --- a/constantine/math/finite_fields.nim +++ b/constantine/math/finite_fields.nim @@ -8,12 +8,17 @@ # ############################################################ # -# Field arithmetic over Fp +# Fq: Finite Field arithmetic over Q # # ############################################################ -# We assume that p is prime known at compile-time -# We assume that p is not even (requirement for Montgomery form) +# We assume that q is known at compile-time +# We assume that q is not even: +# - Operations are done in the Montgomery domain +# - The Montgomery domain introduce a Montgomery constant that must be coprime +# with the field modulus. +# - The constant is chosen a power of 2 +# => to be coprime with a power of 2, q must be odd import ../primitives/constant_time, @@ -21,16 +26,32 @@ import ./bigints_checked # type -# Fp*[C: static Curve] = object -# ## P is the prime modulus of the Curve C +# `Fq`*[C: static Curve] = object # ## All operations on a field are modulo P -# value*: BigInt[CurveBitSize[C]] -export Fp # defined in ../config/curves to avoid recursive module dependencies +# ## P being the prime modulus of the Curve C +# ## Internally, data is stored in Montgomery n-residue form +# ## with the magic constant chosen for convenient division (a power of 2 depending on P bitsize) +# nres*: matchingBigInt(C) +export Fq # defined in ../config/curves to avoid recursive module dependencies debug: - func `==`*(a, b: Fp): CTBool[Word] = + func `==`*(a, b: Fq): CTBool[Word] = ## Returns true if 2 big ints are equal - a.value == b.value + a.nres == b.nres + +# No exceptions allowed +{.push raises: [].} + +func toMonty*[C: static Curve](a: Fq[C]): Montgomery[C] = + ## Convert a big integer over Fq to its montgomery representation + ## over Fq. + ## i.e. Does "a * (2^LimbSize)^W (mod p), where W is the number + ## of words needed to represent p in base 2^LimbSize + + result = a + for i in static(countdown(C.Mod.limbs.high, 1)): + shiftAdd(result, 0) + # ############################################################ # @@ -38,7 +59,7 @@ debug: # # ############################################################ -template add(a: var Fp, b: Fp, ctl: CTBool[Word]): CTBool[Word] = +template add(a: var Fq, b: Fq, ctl: CTBool[Word]): CTBool[Word] = ## Constant-time big integer in-place optional addition ## The addition is only performed if ctl is "true" ## The result carry is always computed. @@ -47,7 +68,7 @@ template add(a: var Fp, b: Fp, ctl: CTBool[Word]): CTBool[Word] = ## a and b MUST have the same announced bitlength (i.e. `bits` static parameters) add(a.value, b.value, ctl) -template sub(a: var Fp, b: Fp, ctl: CTBool[Word]): CTBool[Word] = +template sub(a: var Fq, b: Fq, ctl: CTBool[Word]): CTBool[Word] = ## Constant-time big integer in-place optional substraction ## The substraction is only performed if ctl is "true" ## The result carry is always computed. @@ -65,13 +86,13 @@ template sub(a: var Fp, b: Fp, ctl: CTBool[Word]): CTBool[Word] = # No exceptions allowed {.push raises: [].} -func `+=`*(a: var Fp, b: Fp) = - ## Addition over Fp +func `+=`*(a: var Fq, b: Fq) = + ## Addition over Fq var ctl = add(a, b, CtTrue) - ctl = ctl or not sub(a, Fp.C.Mod, CtFalse) - discard sub(a, Fp.C.Mod, ctl) + ctl = ctl or not sub(a, Fq.C.Mod, CtFalse) + discard sub(a, Fq.C.Mod, ctl) -func `-=`*(a: var Fp, b: Fp) = - ## Substraction over Fp +func `-=`*(a: var Fq, b: Fq) = + ## Substraction over Fq let ctl = sub(a, b, CtTrue) - discard add(a, Fp.C.Mod, ctl) + discard add(a, Fq.C.Mod, ctl) diff --git a/constantine/math/montgomery_checked.nim b/constantine/math/montgomery_checked.nim deleted file mode 100644 index 54663d8..0000000 --- a/constantine/math/montgomery_checked.nim +++ /dev/null @@ -1,38 +0,0 @@ -# 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. - -# ############################################################ -# -# Compute the Montgomery Magic Number -# -# ############################################################ - -import - ./primitives, ./bigints, ./primitives - -# No exceptions allowed -{.push raises: [].} - -# ############################################################ -# -# Montgomery domain primitives -# -# ############################################################ - -# No exceptions allowed -{.push raises: [].} - -func toMonty*[C: static Curve](a: Fp[C]): Montgomery[C] = - ## Convert a big integer over Fp to it's montgomery representation - ## over Fp. - ## i.e. Does "a * (2^LimbSize)^W (mod p), where W is the number - ## of words needed to represent p in base 2^LimbSize - - result = a - for i in static(countdown(C.Mod.limbs.high, 1)): - shiftAdd(result, 0) diff --git a/constantine/math/montgomery_raw.nim b/constantine/math/montgomery_raw.nim deleted file mode 100644 index 1ce2a27..0000000 --- a/constantine/math/montgomery_raw.nim +++ /dev/null @@ -1,7 +0,0 @@ -# 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. diff --git a/tests/test_finite_fields.nim b/tests/test_finite_fields.nim index 8828de5..3b1bfd3 100644 --- a/tests/test_finite_fields.nim +++ b/tests/test_finite_fields.nim @@ -17,7 +17,7 @@ proc main() = suite "Basic arithmetic over finite fields": test "Addition mod 101": block: - var x, y, z: Fp[Fake101] + var x, y, z: Fq[Fake101] x.fromUint(80'u32) y.fromUint(10'u32) @@ -27,7 +27,7 @@ proc main() = check: bool(z == x) block: - var x, y, z: Fp[Fake101] + var x, y, z: Fq[Fake101] x.fromUint(80'u32) y.fromUint(21'u32) @@ -37,7 +37,7 @@ proc main() = check: bool(z == x) block: - var x, y, z: Fp[Fake101] + var x, y, z: Fq[Fake101] x.fromUint(80'u32) y.fromUint(22'u32) @@ -48,7 +48,7 @@ proc main() = test "Substraction mod 101": block: - var x, y, z: Fp[Fake101] + var x, y, z: Fq[Fake101] x.fromUint(80'u32) y.fromUint(10'u32) @@ -58,7 +58,7 @@ proc main() = check: bool(z == x) block: - var x, y, z: Fp[Fake101] + var x, y, z: Fq[Fake101] x.fromUint(80'u32) y.fromUint(80'u32) @@ -68,7 +68,7 @@ proc main() = check: bool(z == x) block: - var x, y, z: Fp[Fake101] + var x, y, z: Fq[Fake101] x.fromUint(80'u32) y.fromUint(81'u32)