For finite fields, we will use the Montgomery n-residue form by default

This commit is contained in:
Mamy André-Ratsimbazafy 2020-02-14 13:36:34 +01:00
parent f6b229b19c
commit f418e08746
No known key found for this signature in database
GPG Key ID: 7B88AD1FE79492E1
6 changed files with 59 additions and 76 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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