constantine/constantine/config/curves_prop_derived.nim
Mamy Ratsimbazafy 638cb71e16
Fr: Finite Field parametrized by the curve order (#115)
* Introduce Fr type: finite field over curve order. Need workaround for https://github.com/nim-lang/Nim/issues/16774

* Split curve properties into core and derived

* Attach field properties to an instantiated field instead of the curve enum

* Workaround https://github.com/nim-lang/Nim/issues/14021, yet another "working with types in macros" is difficult https://github.com/nim-lang/RFCs/issues/44

* Implement finite field over prime order of a curve subgroup

* skip OpenSSL tests on windows
2021-01-22 00:09:52 +01:00

140 lines
5.0 KiB
Nim

# 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
# Standard library
std/macros,
# Internal
./type_bigint, ./type_ff, ./common,
./curves_declaration, ./curves_derived
# ############################################################
#
# Access precomputed derived constants in ROM
#
# ############################################################
{.experimental: "dynamicBindSym".}
genDerivedConstants(kModulus)
genDerivedConstants(kOrder)
proc bindConstant(ff: NimNode, property: string): NimNode =
# Need to workaround https://github.com/nim-lang/Nim/issues/14021
# which prevents checking if a type FF[C] = Fp[C] or Fr[C]
# was instantiated with Fp or Fr.
# getTypeInst only returns FF and sameType doesn't work.
# so quote do + when checks.
let T = getTypeInst(ff)
T.expectKind(nnkBracketExpr)
doAssert T[0].eqIdent("typedesc")
if T[1].kind == nnkBracketExpr: # typedesc[Fp[BLS12_381]]
# doAssert T[1][0].eqIdent"Fp" or T[1][0].eqIdent"Fr", "Found ident: '" & $T[1][0] & "' instead of 'Fp' or 'Fr'"
T[1][1].expectKind(nnkIntLit) # static enum are ints in the VM
let curve = $Curve(T[1][1].intVal)
let curve_fp = bindSym(curve & "_Fp_" & property)
let curve_fr = bindSym(curve & "_Fr_" & property)
result = quote do:
when `ff` is Fp:
`curve_fp`
elif `ff` is Fr:
`curve_fr`
else:
{.error: "Unreachable, received type: " & $`ff`.}
else:
echo T.repr()
echo getTypeInst(T[1]).treerepr
error "getTypeInst didn't return the full instantiation." &
" Dealing with types in macros is hard, complain at https://github.com/nim-lang/RFCs/issues/44"
template fieldMod*(Field: type FF): auto =
when Field is Fp:
Field.C.Mod
else:
Field.C.getCurveOrder()
macro canUseNoCarryMontyMul*(ff: type FF): untyped =
## Returns true if the Modulus is compatible with a fast
## Montgomery multiplication that avoids many carries
result = bindConstant(ff, "CanUseNoCarryMontyMul")
macro canUseNoCarryMontySquare*(ff: type FF): untyped =
## Returns true if the Modulus is compatible with a fast
## Montgomery squaring that avoids many carries
result = bindConstant(ff, "CanUseNoCarryMontySquare")
macro getR2modP*(ff: type FF): untyped =
## Get the Montgomery "R^2 mod P" constant associated to a curve field modulus
result = bindConstant(ff, "R2modP")
macro getNegInvModWord*(ff: type FF): untyped =
## Get the Montgomery "-1/P[0] mod 2^Wordbitwidth" constant associated to a curve field modulus
result = bindConstant(ff, "NegInvModWord")
macro getMontyOne*(ff: type FF): untyped =
## Get one in Montgomery representation (i.e. R mod P)
result = bindConstant(ff, "MontyOne")
macro getMontyPrimeMinus1*(ff: type FF): untyped =
## Get (P+1) / 2 for an odd prime
result = bindConstant(ff, "MontyPrimeMinus1")
macro getInvModExponent*(ff: type FF): untyped =
## Get modular inversion exponent (Modulus-2 in canonical representation)
result = bindConstant(ff, "InvModExponent")
macro getPrimePlus1div2*(ff: type FF): untyped =
## Get (P+1) / 2 for an odd prime
## Warning ⚠️: Result in canonical domain (not Montgomery)
result = bindConstant(ff, "PrimePlus1div2")
macro getPrimeMinus1div2_BE*(ff: type FF): untyped =
## Get (P-1) / 2 in big-endian serialized format
result = bindConstant(ff, "PrimeMinus1div2_BE")
macro getPrimeMinus3div4_BE*(ff: type FF): untyped =
## Get (P-3) / 2 in big-endian serialized format
result = bindConstant(ff, "PrimeMinus3div4_BE")
macro getPrimePlus1div4_BE*(ff: type FF): untyped =
## Get (P+1) / 4 for an odd prime in big-endian serialized format
result = bindConstant(ff, "PrimePlus1div4_BE")
# ############################################################
#
# Debug info printed at compile-time
#
# ############################################################
macro debugConsts(): untyped {.used.} =
let curves = bindSym("Curve")
let E = curves.getImpl[2]
result = newStmtList()
for i in 1 ..< E.len:
let curve = E[i]
let curveName = $curve
let modulus = bindSym(curveName & "_Fp_Modulus")
let r2modp = bindSym(curveName & "_Fp_R2modP")
let negInvModWord = bindSym(curveName & "_Fp_NegInvModWord")
result.add quote do:
echo "Curve ", `curveName`,':'
echo " Field Modulus: ", `modulus`
echo " Montgomery R² (mod P): ", `r2modp`
echo " Montgomery -1/P[0] (mod 2^", WordBitWidth, "): ", `negInvModWord`
result.add quote do:
echo "----------------------------------------------------------------------------"
# debug: # displayed with -d:debugConstantine
# debugConsts()