mirror of
https://github.com/codex-storage/constantine.git
synced 2025-01-30 12:36:27 +00:00
Properly precompute the montomery cosntants at compile-time and store them in ROM
This commit is contained in:
parent
4970572393
commit
05a2c6a34b
@ -7,6 +7,8 @@
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
# Standard library
|
||||
macros,
|
||||
# Internal
|
||||
./curves_parser, ./common,
|
||||
../math/[precomputed, bigints_checked]
|
||||
@ -52,3 +54,49 @@ else:
|
||||
curve Fake101:
|
||||
bitsize: 7
|
||||
modulus: "0x65" # 101 in hex
|
||||
|
||||
# ############################################################
|
||||
#
|
||||
# Autogeneration of precomputed constants in ROM
|
||||
#
|
||||
# ############################################################
|
||||
|
||||
const MontyNegInvModWord* = block:
|
||||
## Store the Montgomery Magic Constant "Negative Inverse mod 2^63" in ROM
|
||||
var buf: array[Curve, BaseType]
|
||||
for curve in Curve:
|
||||
buf[curve] = curve.Mod.mres.negInvModWord
|
||||
buf
|
||||
|
||||
{.experimental: "dynamicBindSym".}
|
||||
|
||||
macro genR2modP(T: typed): untyped =
|
||||
## Store the Montgomery Magic Constant "R^2 mod N" in ROM
|
||||
## For each curve under the private symbol "MyCurve_R2modP"
|
||||
T.getImpl.expectKind(nnkTypeDef)
|
||||
T.getImpl[2].expectKind(nnkEnumTy)
|
||||
|
||||
result = newStmtList()
|
||||
|
||||
let E = T.getImpl[2]
|
||||
for i in 1 ..< E.len:
|
||||
let curve = E[i]
|
||||
result.add newConstStmt(
|
||||
ident($curve & "_R2modP"), newCall(
|
||||
bindSym"r2mod",
|
||||
# The curve parser creates modulus
|
||||
# under symbol "MyCurve_Modulus"
|
||||
nnkDotExpr.newTree(
|
||||
bindSym($curve & "_Modulus"),
|
||||
ident"mres"
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
# echo result.toStrLit
|
||||
|
||||
genR2modP(Curve)
|
||||
|
||||
macro getR2modP*(C: static Curve): untyped =
|
||||
## Get the Montgomery Magic Constant Associated to a curve
|
||||
result = bindSym($C & "_R2modP")
|
||||
|
@ -58,7 +58,7 @@ macro declareCurves*(curves: untyped): untyped =
|
||||
var Curves: seq[NimNode]
|
||||
var CurveBitSize = nnKBracket.newTree()
|
||||
var curveModStmts = newStmtList()
|
||||
var curveModWhenStmt = nnkWhenStmt.newTree()
|
||||
var curveModWhenStmt = nnkIfStmt.newTree()
|
||||
|
||||
let Fq = ident"Fq"
|
||||
|
||||
@ -112,7 +112,7 @@ macro declareCurves*(curves: untyped): untyped =
|
||||
ident"curve",
|
||||
curve
|
||||
),
|
||||
modulusID
|
||||
newAssignment(ident"result", modulusID)
|
||||
)
|
||||
# end for ---------------------------------------------------
|
||||
|
||||
@ -172,13 +172,11 @@ macro declareCurves*(curves: untyped): untyped =
|
||||
)
|
||||
)
|
||||
|
||||
# Add 'else: {.error: "Unreachable".}' to the when statements
|
||||
# Add 'else: error"Unreachable" to the when statements
|
||||
curveModWhenStmt.add nnkElse.newTree(
|
||||
nnkPragma.newTree(
|
||||
nnkExprColonExpr.newTree(
|
||||
ident"error",
|
||||
newLit"Unreachable: the curve does not exist."
|
||||
)
|
||||
newCall(
|
||||
bindSym"error",
|
||||
newLit"Unreachable: the curve does not exist."
|
||||
)
|
||||
)
|
||||
|
||||
@ -191,11 +189,12 @@ macro declareCurves*(curves: untyped): untyped =
|
||||
ident"auto",
|
||||
newIdentDefs(
|
||||
name = ident"curve",
|
||||
kind = nnkStaticTy.newTree(ident"Curve")
|
||||
kind = ident"Curve"
|
||||
)
|
||||
],
|
||||
body = curveModWhenStmt,
|
||||
procType = nnkFuncDef
|
||||
procType = nnkFuncDef,
|
||||
pragmas = nnkPragma.newTree(ident"compileTime")
|
||||
)
|
||||
|
||||
# echo result.toStrLit()
|
||||
|
@ -9,9 +9,7 @@
|
||||
import
|
||||
./io_bigints,
|
||||
../config/curves,
|
||||
../math/[bigints_checked, finite_fields],
|
||||
# TODO: should be a const/proc in curves.nim
|
||||
../math/precomputed
|
||||
../math/[bigints_checked, finite_fields]
|
||||
|
||||
# ############################################################
|
||||
#
|
||||
@ -24,7 +22,7 @@ func fromUint*(dst: var Fq,
|
||||
## Parse a regular unsigned integer
|
||||
## and store it into a BigInt of size `bits`
|
||||
let raw = (type dst.mres).fromRawUint(cast[array[sizeof(src), byte]](src), cpuEndian)
|
||||
dst.mres.unsafeMontyResidue(raw, Fq.C.Mod.mres, r2mod(Fq.C.Mod.mres), neginvModWord(Fq.C.Mod.mres))
|
||||
dst.mres.unsafeMontyResidue(raw, Fq.C.Mod.mres, Fq.C.getR2modP(), MontyNegInvModWord[Fq.C])
|
||||
|
||||
func serializeRawUint*(dst: var openarray[byte],
|
||||
src: Fq,
|
||||
|
@ -53,7 +53,7 @@ type
|
||||
##
|
||||
## This internal representation can be changed
|
||||
## without notice and should not be used by external applications or libraries.
|
||||
bitLength: uint32
|
||||
bitLength*: uint32
|
||||
limbs*: array[bits.wordsRequired, Word]
|
||||
|
||||
template view*(a: BigInt): BigIntViewConst =
|
||||
|
@ -23,9 +23,7 @@
|
||||
import
|
||||
../primitives/constant_time,
|
||||
../config/[common, curves],
|
||||
./bigints_checked,
|
||||
# TODO: should be a const/proc in curves.nim
|
||||
./precomputed
|
||||
./bigints_checked
|
||||
|
||||
# type
|
||||
# `Fq`*[C: static Curve] = object
|
||||
@ -53,12 +51,12 @@ debug:
|
||||
|
||||
func fromBig*(T: type Fq, src: BigInt): T =
|
||||
## Convert a BigInt to its Montgomery form
|
||||
result.mres.unsafeMontyResidue(src, Fq.C.Mod.mres, r2mod(Fq.C.Mod.mres), neginvModWord(Fq.C.Mod.mres))
|
||||
result.mres.unsafeMontyResidue(src, Fq.C.Mod.mres, Fq.C.getR2modP(), MontyNegInvModWord[Fq.C])
|
||||
|
||||
func toBig*(src: Fq): auto =
|
||||
## Convert a finite-field element to a BigInt in natral representation
|
||||
result = src.mres
|
||||
result.unsafeRedC(Fq.C.Mod.mres, Fq.C.Mod.mres.negInvModWord())
|
||||
result.unsafeRedC(Fq.C.Mod.mres, MontyNegInvModWord[Fq.C])
|
||||
|
||||
# ############################################################
|
||||
#
|
||||
@ -116,4 +114,4 @@ func `*`*(a, b: Fq): Fq {.noInit.} =
|
||||
## as Fq elements are usually large and this
|
||||
## routine will zero init internally the result.
|
||||
result.mres.setInternalBitLength()
|
||||
result.mres.montyMul(a.mres, b.mres, Fq.C.Mod.mres, Fq.C.Mod.mres.negInvModWord())
|
||||
result.mres.montyMul(a.mres, b.mres, Fq.C.Mod.mres, MontyNegInvModWord[Fq.C])
|
||||
|
@ -24,22 +24,30 @@ import
|
||||
# They are generic over the bitsize: enabling them at runtime
|
||||
# would create a copy for each bitsize used (monomorphization)
|
||||
# leading to code-bloat.
|
||||
# Thos are NOT compile-time, using CTBool seems to confuse the VM
|
||||
|
||||
func double(a: var BigInt): CTBool[Word] =
|
||||
# We don't use distinct types here, they confuse the VM
|
||||
# Similarly, isMsbSet causes trouble with distinct type in the VM
|
||||
|
||||
func isMsbSet(x: BaseType): bool =
|
||||
const msb_pos = BaseType.sizeof * 8 - 1
|
||||
bool(x shr msb_pos)
|
||||
|
||||
func double(a: var BigInt): bool =
|
||||
## In-place multiprecision double
|
||||
## a -> 2a
|
||||
for i in 0 ..< a.limbs.len:
|
||||
BaseType(a.limbs[i]) *= 2
|
||||
a.limbs[i] += Word(result)
|
||||
result = a.limbs[i].isMsbSet()
|
||||
a.limbs[i] = a.limbs[i] and MaxWord
|
||||
var z = BaseType(a.limbs[i]) * 2 + BaseType(result)
|
||||
result = z.isMsbSet()
|
||||
a.limbs[i] = Word(z) and MaxWord
|
||||
|
||||
func sub(a: var BigInt, b: BigInt, ctl: CTBool[Word]): CTBool[Word] =
|
||||
func sub(a: var BigInt, b: BigInt, ctl: bool): bool =
|
||||
## In-place optional substraction
|
||||
for i in 0 ..< a.limbs.len:
|
||||
let new_a = a.limbs[i] - b.limbs[i] - Word(result)
|
||||
let new_a = BaseType(a.limbs[i]) - BaseType(b.limbs[i]) - BaseType(result)
|
||||
result = new_a.isMsbSet()
|
||||
a.limbs[i] = ctl.mux(new_a and MaxWord, a.limbs[i])
|
||||
a.limbs[i] = if ctl: new_a.Word and MaxWord
|
||||
else: a.limbs[i]
|
||||
|
||||
func doubleMod(a: var BigInt, M: BigInt) =
|
||||
## In-place modular double
|
||||
@ -49,8 +57,8 @@ func doubleMod(a: var BigInt, M: BigInt) =
|
||||
## only for compile-time precomputation
|
||||
## of non-secret data.
|
||||
var ctl = double(a)
|
||||
ctl = ctl or not a.sub(M, CtFalse)
|
||||
discard a.sub(M, ctl)
|
||||
ctl = ctl or not sub(a, M, false)
|
||||
discard sub(a, M, ctl)
|
||||
|
||||
# ############################################################
|
||||
#
|
||||
|
Loading…
x
Reference in New Issue
Block a user