Rename Fq -> Fp

This commit is contained in:
Mamy André-Ratsimbazafy 2020-02-24 17:10:09 +01:00
parent 3bd70991d4
commit 6b05c69652
No known key found for this signature in database
GPG Key ID: 7B88AD1FE79492E1
7 changed files with 94 additions and 90 deletions

View File

@ -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
)

View File

@ -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()
)),

View File

@ -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)

View File

@ -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)

View File

@ -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")

View File

@ -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

View File

@ -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