From 6b05c69652f805b978ca1784e048fd6f0532ce5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mamy=20Andr=C3=A9-Ratsimbazafy?= Date: Mon, 24 Feb 2020 17:10:09 +0100 Subject: [PATCH] Rename Fq -> Fp --- constantine/arithmetic/finite_fields.nim | 98 ++++++++++++------------ constantine/config/curves_parser.nim | 10 +-- constantine/io/io_fields.nim | 10 +-- tests/test_finite_fields.nim | 30 ++++---- tests/test_finite_fields_powinv.nim | 14 ++-- tests/test_finite_fields_vs_gmp.nim | 6 +- tests/test_io_fields.nim | 16 ++-- 7 files changed, 94 insertions(+), 90 deletions(-) diff --git a/constantine/arithmetic/finite_fields.nim b/constantine/arithmetic/finite_fields.nim index 7326cf6..39d9d63 100644 --- a/constantine/arithmetic/finite_fields.nim +++ b/constantine/arithmetic/finite_fields.nim @@ -8,17 +8,21 @@ # ############################################################ # -# Fq: Finite Field arithmetic over Q +# Fp: Finite Field arithmetic with prime field modulus P # # ############################################################ -# 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 +# Constraints: +# - We assume that p is known at compile-time +# - We assume that p 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, p must be odd +# - We assume that p is a prime +# - Modular inversion uses the Fermat's little theorem +# which requires a prime import ../primitives/constant_time, @@ -28,21 +32,21 @@ import from ../io/io_bigints import exportRawUint # for "pow" # type -# `Fq`*[C: static Curve] = object +# `Fp`*[C: static Curve] = object # ## All operations on a field are modulo P # ## 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) # mres*: matchingBigInt(C) -export Fq # defined in ../config/curves to avoid recursive module dependencies +export Fp # defined in ../config/curves to avoid recursive module dependencies debug: - func `==`*(a, b: Fq): CTBool[Word] = + func `==`*(a, b: Fp): CTBool[Word] = ## Returns true if 2 big ints are equal a.mres == b.mres - func `$`*[C: static Curve](a: Fq[C]): string = - result = "Fq[" & $C + func `$`*[C: static Curve](a: Fp[C]): string = + result = "Fp[" & $C result.add "](" result.add $a.mres result.add ')' @@ -57,18 +61,18 @@ debug: # # ############################################################ -func fromBig*[C: static Curve](T: type Fq[C], src: BigInt): Fq[C] {.noInit.} = +func fromBig*[C: static Curve](T: type Fp[C], src: BigInt): Fp[C] {.noInit.} = ## Convert a BigInt to its Montgomery form result.mres.montyResidue(src, C.Mod.mres, C.getR2modP(), C.getNegInvModWord()) -func fromBig*[C: static Curve](dst: var Fq[C], src: BigInt) {.noInit.} = +func fromBig*[C: static Curve](dst: var Fp[C], src: BigInt) {.noInit.} = ## Convert a BigInt to its Montgomery form dst.mres.montyResidue(src, C.Mod.mres, C.getR2modP(), C.getNegInvModWord()) -func toBig*(src: Fq): auto {.noInit.} = +func toBig*(src: Fp): auto {.noInit.} = ## Convert a finite-field element to a BigInt in natral representation var r {.noInit.}: typeof(src.mres) - r.redc(src.mres, Fq.C.Mod.mres, Fq.C.getNegInvModWord()) + r.redc(src.mres, Fp.C.Mod.mres, Fp.C.getNegInvModWord()) return r # ############################################################ @@ -77,7 +81,7 @@ func toBig*(src: Fq): auto {.noInit.} = # # ############################################################ -template add(a: var Fq, b: Fq, ctl: CTBool[Word]): CTBool[Word] = +template add(a: var Fp, b: Fp, 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. @@ -86,7 +90,7 @@ template add(a: var Fq, b: Fq, ctl: CTBool[Word]): CTBool[Word] = ## a and b MUST have the same announced bitlength (i.e. `bits` static parameters) add(a.mres, b.mres, ctl) -template sub(a: var Fq, b: Fq, ctl: CTBool[Word]): CTBool[Word] = +template sub(a: var Fp, b: Fp, 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. @@ -109,46 +113,46 @@ template sub(a: var Fq, b: Fq, ctl: CTBool[Word]): CTBool[Word] = # - Golden Primes (φ^2 - φ - 1 with φ = 2^k for example Ed448-Goldilocks: 2^448 - 2^224 - 1) # exist and can be implemented with compile-time specialization. -func `+=`*(a: var Fq, b: Fq) = - ## Addition over Fq +func `+=`*(a: var Fp, b: Fp) = + ## Addition over Fp var ctl = add(a, b, CtTrue) - ctl = ctl or not sub(a, Fq.C.Mod, CtFalse) - discard sub(a, Fq.C.Mod, ctl) + ctl = ctl or not sub(a, Fp.C.Mod, CtFalse) + discard sub(a, Fp.C.Mod, ctl) -func `-=`*(a: var Fq, b: Fq) = - ## Substraction over Fq +func `-=`*(a: var Fp, b: Fp) = + ## Substraction over Fp let ctl = sub(a, b, CtTrue) - discard add(a, Fq.C.Mod, ctl) + discard add(a, Fp.C.Mod, ctl) -func `*`*(a, b: Fq): Fq {.noInit.} = - ## Multiplication over Fq +func `*`*(a, b: Fp): Fp {.noInit.} = + ## Multiplication over Fp ## ## It is recommended to assign with {.noInit.} - ## as Fq elements are usually large and this + ## as Fp elements are usually large and this ## routine will zero init internally the result. - result.mres.montyMul(a.mres, b.mres, Fq.C.Mod.mres, Fq.C.getNegInvModWord()) + result.mres.montyMul(a.mres, b.mres, Fp.C.Mod.mres, Fp.C.getNegInvModWord()) -func square*(a: Fq): Fq {.noInit.} = - ## Squaring over Fq +func square*(a: Fp): Fp {.noInit.} = + ## Squaring over Fp ## ## It is recommended to assign with {.noInit.} - ## as Fq elements are usually large and this + ## as Fp elements are usually large and this ## routine will zero init internally the result. - result.mres.montySquare(a.mres, Fq.C.Mod.mres, Fq.C.getNegInvModWord()) + result.mres.montySquare(a.mres, Fp.C.Mod.mres, Fp.C.getNegInvModWord()) -func pow*(a: var Fq, exponent: BigInt) = - ## Exponentiation over Fq +func pow*(a: var Fp, exponent: BigInt) = + ## Exponentiation over Fp ## ``a``: a field element to be exponentiated ## ``exponent``: a big integer const windowSize = 5 # TODO: find best window size for each curves a.mres.montyPow( exponent, - Fq.C.Mod.mres, Fq.C.getMontyOne(), - Fq.C.getNegInvModWord(), windowSize + Fp.C.Mod.mres, Fp.C.getMontyOne(), + Fp.C.getNegInvModWord(), windowSize ) -func powUnsafeExponent*(a: var Fq, exponent: BigInt) = - ## Exponentiation over Fq +func powUnsafeExponent*(a: var Fp, exponent: BigInt) = + ## Exponentiation over Fp ## ``a``: a field element to be exponentiated ## ``exponent``: a big integer ## @@ -161,17 +165,17 @@ func powUnsafeExponent*(a: var Fq, exponent: BigInt) = const windowSize = 5 # TODO: find best window size for each curves a.mres.montyPowUnsafeExponent( exponent, - Fq.C.Mod.mres, Fq.C.getMontyOne(), - Fq.C.getNegInvModWord(), windowSize + Fp.C.Mod.mres, Fp.C.getMontyOne(), + Fp.C.getNegInvModWord(), windowSize ) -func inv*(a: var Fq) = +func inv*(a: var Fp) = ## Modular inversion ## Warning ⚠️ : - ## - This assumes that `Fq` is a prime field + ## - This assumes that `Fp` is a prime field const windowSize = 5 # TODO: find best window size for each curves a.mres.montyPowUnsafeExponent( - Fq.C.getInvModExponent(), - Fq.C.Mod.mres, Fq.C.getMontyOne(), - Fq.C.getNegInvModWord(), windowSize + Fp.C.getInvModExponent(), + Fp.C.Mod.mres, Fp.C.getMontyOne(), + Fp.C.getNegInvModWord(), windowSize ) diff --git a/constantine/config/curves_parser.nim b/constantine/config/curves_parser.nim index 1814971..c0bbcb7 100644 --- a/constantine/config/curves_parser.nim +++ b/constantine/config/curves_parser.nim @@ -59,7 +59,7 @@ macro declareCurves*(curves: untyped): untyped = var CurveBitSize = nnKBracket.newTree() var curveModStmts = newStmtList() - let Fq = ident"Fq" + let Fp = ident"Fp" for curveDesc in curves: curveDesc.expectKind(nnkCommand) @@ -87,12 +87,12 @@ macro declareCurves*(curves: untyped): untyped = curve, bitSize ) - # const BN254_Modulus = Fq[BN254](value: fromHex(BigInt[254], "0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47")) + # const BN254_Modulus = Fp[BN254](value: fromHex(BigInt[254], "0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47")) let modulusID = ident($curve & "_Modulus") curveModStmts.add newConstStmt( modulusID, nnkObjConstr.newTree( - nnkBracketExpr.newTree(Fq, curve), + nnkBracketExpr.newTree(Fp, curve), nnkExprColonExpr.newTree( ident"mres", newCall( @@ -136,7 +136,7 @@ macro declareCurves*(curves: untyped): untyped = ) # type - # `Fq`*[C: static Curve] = object + # `Fp`*[C: static Curve] = object # ## All operations on a field are modulo P # ## P being the prime modulus of the Curve C # ## Internally, data is stored in Montgomery n-residue form @@ -144,7 +144,7 @@ macro declareCurves*(curves: untyped): untyped = # mres*: matchingBigInt(C) result.add nnkTypeSection.newTree( nnkTypeDef.newTree( - nnkPostfix.newTree(ident"*", Fq), + nnkPostfix.newTree(ident"*", Fp), nnkGenericParams.newTree(newIdentDefs( C, nnkStaticTy.newTree(Curve), newEmptyNode() )), diff --git a/constantine/io/io_fields.nim b/constantine/io/io_fields.nim index e577a25..b9973fe 100644 --- a/constantine/io/io_fields.nim +++ b/constantine/io/io_fields.nim @@ -21,7 +21,7 @@ import # # ############################################################ -func fromUint*(dst: var Fq, +func fromUint*(dst: var Fp, src: SomeUnsignedInt) = ## Parse a regular unsigned integer ## and store it into a BigInt of size `bits` @@ -29,7 +29,7 @@ func fromUint*(dst: var Fq, dst.fromBig(raw) func exportRawUint*(dst: var openarray[byte], - src: Fq, + src: Fp, dstEndianness: static Endianness) = ## Serialize a finite field element to its canonical big-endian or little-endian ## representation @@ -42,7 +42,7 @@ func exportRawUint*(dst: var openarray[byte], ## I.e least significant bit is aligned to buffer boundary exportRawUint(dst, src.toBig(), dstEndianness) -func toHex*(f: Fq, order: static Endianness = bigEndian): string = +func toHex*(f: Fp, order: static Endianness = bigEndian): string = ## Stringify a finite field element to hex. ## Note. Leading zeros are not removed. ## Result is prefixed with 0x @@ -53,7 +53,7 @@ func toHex*(f: Fq, order: static Endianness = bigEndian): string = ## - no leaks result = f.toBig().toHex(order) -func fromHex*(dst: var Fq, s: string) {.raises: [ValueError].}= - ## Convert a hex string to a element of Fq +func fromHex*(dst: var Fp, s: string) {.raises: [ValueError].}= + ## Convert a hex string to a element of Fp let raw {.noinit.} = fromHex(dst.mres.typeof, s) dst.fromBig(raw) diff --git a/tests/test_finite_fields.nim b/tests/test_finite_fields.nim index 73eac84..78ab08d 100644 --- a/tests/test_finite_fields.nim +++ b/tests/test_finite_fields.nim @@ -19,7 +19,7 @@ proc main() = suite "Basic arithmetic over finite fields": test "Addition mod 101": block: - var x, y, z: Fq[Fake101] + var x, y, z: Fp[Fake101] x.fromUint(80'u32) y.fromUint(10'u32) @@ -37,7 +37,7 @@ proc main() = 90'u64 == cast[uint64](x_bytes) block: - var x, y, z: Fq[Fake101] + var x, y, z: Fp[Fake101] x.fromUint(80'u32) y.fromUint(21'u32) @@ -55,7 +55,7 @@ proc main() = 0'u64 == cast[uint64](x_bytes) block: - var x, y, z: Fq[Fake101] + var x, y, z: Fp[Fake101] x.fromUint(80'u32) y.fromUint(22'u32) @@ -74,7 +74,7 @@ proc main() = test "Substraction mod 101": block: - var x, y, z: Fq[Fake101] + var x, y, z: Fp[Fake101] x.fromUint(80'u32) y.fromUint(10'u32) @@ -92,7 +92,7 @@ proc main() = 70'u64 == cast[uint64](x_bytes) block: - var x, y, z: Fq[Fake101] + var x, y, z: Fp[Fake101] x.fromUint(80'u32) y.fromUint(80'u32) @@ -110,7 +110,7 @@ proc main() = 0'u64 == cast[uint64](x_bytes) block: - var x, y, z: Fq[Fake101] + var x, y, z: Fp[Fake101] x.fromUint(80'u32) y.fromUint(81'u32) @@ -129,7 +129,7 @@ proc main() = test "Multiplication mod 101": block: - var x, y, z: Fq[Fake101] + var x, y, z: Fp[Fake101] x.fromUint(10'u32) y.fromUint(10'u32) @@ -147,7 +147,7 @@ proc main() = 100'u64 == cast[uint64](r_bytes) block: - var x, y, z: Fq[Fake101] + var x, y, z: Fp[Fake101] x.fromUint(10'u32) y.fromUint(11'u32) @@ -166,7 +166,7 @@ proc main() = test "Addition mod 2^61 - 1": block: - var x, y, z: Fq[Mersenne61] + var x, y, z: Fp[Mersenne61] x.fromUint(80'u64) y.fromUint(10'u64) @@ -185,7 +185,7 @@ proc main() = new_x == 90'u64 block: - var x, y, z: Fq[Mersenne61] + var x, y, z: Fp[Mersenne61] x.fromUint(1'u64 shl 61 - 2) y.fromUint(1'u32) @@ -204,7 +204,7 @@ proc main() = new_x == 0'u64 block: - var x, y, z: Fq[Mersenne61] + var x, y, z: Fp[Mersenne61] x.fromUint(1'u64 shl 61 - 2) y.fromUint(2'u64) @@ -224,7 +224,7 @@ proc main() = test "Substraction mod 2^61 - 1": block: - var x, y, z: Fq[Mersenne61] + var x, y, z: Fp[Mersenne61] x.fromUint(80'u64) y.fromUint(10'u64) @@ -243,7 +243,7 @@ proc main() = new_x == 70'u64 block: - var x, y, z: Fq[Mersenne61] + var x, y, z: Fp[Mersenne61] x.fromUint(0'u64) y.fromUint(1'u64) @@ -263,7 +263,7 @@ proc main() = test "Multiplication mod 2^61 - 1": block: - var x, y, z: Fq[Mersenne61] + var x, y, z: Fp[Mersenne61] x.fromUint(10'u32) y.fromUint(10'u32) @@ -282,7 +282,7 @@ proc main() = cast[uint64](r_bytes) == 100'u64 block: - var x, y, z: Fq[Mersenne61] + var x, y, z: Fp[Mersenne61] x.fromUint(1'u32 shl 31) y.fromUint(1'u32 shl 31) diff --git a/tests/test_finite_fields_powinv.nim b/tests/test_finite_fields_powinv.nim index 5d5f815..d6d8b86 100644 --- a/tests/test_finite_fields_powinv.nim +++ b/tests/test_finite_fields_powinv.nim @@ -21,7 +21,7 @@ proc main() = let exponent = BigInt[64].fromUint(2'u64) block: # 1^2 mod 101 - var n, expected: Fq[Fake101] + var n, expected: Fp[Fake101] n.fromUint(1'u32) expected = n @@ -39,7 +39,7 @@ proc main() = 1'u64 == r block: # 2^2 mod 101 - var n, expected: Fq[Fake101] + var n, expected: Fp[Fake101] n.fromUint(2'u32) expected.fromUint(4'u32) @@ -57,7 +57,7 @@ proc main() = 4'u64 == r block: # 10^2 mod 101 - var n, expected: Fq[Fake101] + var n, expected: Fp[Fake101] n.fromUint(10'u32) expected.fromUint(100'u32) @@ -75,7 +75,7 @@ proc main() = 100'u64 == r block: # 11^2 mod 101 - var n, expected: Fq[Fake101] + var n, expected: Fp[Fake101] n.fromUint(11'u32) expected.fromUint(20'u32) @@ -94,7 +94,7 @@ proc main() = test "x^(p-2) mod p (modular inversion if p prime)": block: - var x: Fq[BLS12_381] + var x: Fp[BLS12_381] # BN254 field modulus x.fromHex("0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47") @@ -110,7 +110,7 @@ proc main() = computed == expected block: - var x: Fq[BLS12_381] + var x: Fp[BLS12_381] # BN254 field modulus x.fromHex("0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47") @@ -127,7 +127,7 @@ proc main() = suite "Modular inversion over prime fields": test "x^(-1) mod p": - var x: Fq[BLS12_381] + var x: Fp[BLS12_381] # BN254 field modulus x.fromHex("0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47") diff --git a/tests/test_finite_fields_vs_gmp.nim b/tests/test_finite_fields_vs_gmp.nim index 942a867..6918d3b 100644 --- a/tests/test_finite_fields_vs_gmp.nim +++ b/tests/test_finite_fields_vs_gmp.nim @@ -94,8 +94,8 @@ proc mainMul() = doAssert len >= bW, "Expected at most " & $len & " bytes but wrote " & $bW & " for " & toHex(bBuf) & " (little-endian)" # Build the bigint - TODO more fields codecs - let aTest = Fq[curve].fromBig BigInt[bits].fromRawUint(aBuf, littleEndian) - let bTest = Fq[curve].fromBig BigInt[bits].fromRawUint(bBuf, littleEndian) + let aTest = Fp[curve].fromBig BigInt[bits].fromRawUint(aBuf, littleEndian) + let bTest = Fp[curve].fromBig BigInt[bits].fromRawUint(bBuf, littleEndian) ######################################################### # Modular multiplication @@ -169,7 +169,7 @@ proc mainInv() = doAssert len >= aW, "Expected at most " & $len & " bytes but wrote " & $aW & " for " & toHex(aBuf) & " (little-endian)" # Build the bigint - TODO more fields codecs - let aTest = Fq[curve].fromBig BigInt[bits].fromRawUint(aBuf[0 ..< aW], bigEndian) + let aTest = Fp[curve].fromBig BigInt[bits].fromRawUint(aBuf[0 ..< aW], bigEndian) ######################################################### # Modular inversion diff --git a/tests/test_io_fields.nim b/tests/test_io_fields.nim index fed1cfe..1e06d7c 100644 --- a/tests/test_io_fields.nim +++ b/tests/test_io_fields.nim @@ -22,7 +22,7 @@ proc main() = # "Little-endian" - 0 let x = 0'u64 let x_bytes = cast[array[8, byte]](x) - var f: Fq[Mersenne61] + var f: Fp[Mersenne61] f.fromUint(x) var r_bytes: array[8, byte] @@ -33,7 +33,7 @@ proc main() = # "Little-endian" - 1 let x = 1'u64 let x_bytes = cast[array[8, byte]](x) - var f: Fq[Mersenne61] + var f: Fp[Mersenne61] f.fromUint(x) var r_bytes: array[8, byte] @@ -44,7 +44,7 @@ proc main() = # "Little-endian" - 2^31 let x = 1'u64 shl 31 let x_bytes = cast[array[8, byte]](x) - var f: Fq[Mersenne61] + var f: Fp[Mersenne61] f.fromUint(x) var r_bytes: array[8, byte] @@ -55,7 +55,7 @@ proc main() = # "Little-endian" - 2^32 let x = 1'u64 shl 32 let x_bytes = cast[array[8, byte]](x) - var f: Fq[Mersenne61] + var f: Fp[Mersenne61] f.fromUint(x) var r_bytes: array[8, byte] @@ -67,7 +67,7 @@ proc main() = # "Little-endian" - 2^63 let x = 1'u64 shl 63 let x_bytes = cast[array[8, byte]](x) - var f: Fq[Mersenne127] + var f: Fp[Mersenne127] f.fromUint(x) var r_bytes: array[16, byte] @@ -77,7 +77,7 @@ proc main() = block: # "Little-endian" - single random let x = uint64 rand(0..high(int)) let x_bytes = cast[array[8, byte]](x) - var f: Fq[Mersenne127] + var f: Fp[Mersenne127] f.fromUint(x) var r_bytes: array[16, byte] @@ -88,7 +88,7 @@ proc main() = for _ in 0 ..< 10: let x = uint64 rand(0..high(int)) let x_bytes = cast[array[8, byte]](x) - var f: Fq[Mersenne127] + var f: Fp[Mersenne127] f.fromUint(x) var r_bytes: array[16, byte] @@ -98,7 +98,7 @@ proc main() = test "Round trip on large constant": block: # 2^126 const p = "0x40000000000000000000000000000000" - let x = Fq[Mersenne127].fromBig BigInt[127].fromHex(p) + let x = Fp[Mersenne127].fromBig BigInt[127].fromHex(p) let hex = x.toHex(bigEndian) check: p == hex