For finite fields, we will use the Montgomery n-residue form by default
This commit is contained in:
parent
f6b229b19c
commit
f418e08746
|
@ -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
|
# Test vectors: https://www.researchgate.net/publication/4107322_Montgomery_modular_multiplication_architecture_for_public_key_cryptosystems
|
||||||
# on p354
|
# on p354
|
||||||
# Reference C impl: http://www.hackersdelight.org/hdcodetxt/mont64.c.txt
|
# Reference C impl: http://www.hackersdelight.org/hdcodetxt/mont64.c.txt
|
||||||
|
# Explanation: https://eprint.iacr.org/2017/1057.pdf
|
||||||
|
|
||||||
# ######################################################################
|
# ######################################################################
|
||||||
# Implementation of modular multiplicative inverse
|
# Implementation of modular multiplicative inverse
|
||||||
|
|
|
@ -60,7 +60,7 @@ macro declareCurves*(curves: untyped): untyped =
|
||||||
var curveModStmts = newStmtList()
|
var curveModStmts = newStmtList()
|
||||||
var curveModWhenStmt = nnkWhenStmt.newTree()
|
var curveModWhenStmt = nnkWhenStmt.newTree()
|
||||||
|
|
||||||
let Fp = ident"Fp"
|
let Fq = ident"Fq"
|
||||||
|
|
||||||
for curveDesc in curves:
|
for curveDesc in curves:
|
||||||
curveDesc.expectKind(nnkCommand)
|
curveDesc.expectKind(nnkCommand)
|
||||||
|
@ -88,14 +88,14 @@ macro declareCurves*(curves: untyped): untyped =
|
||||||
curve, bitSize
|
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")
|
let modulusID = ident($curve & "_Modulus")
|
||||||
curveModStmts.add newConstStmt(
|
curveModStmts.add newConstStmt(
|
||||||
modulusID,
|
modulusID,
|
||||||
nnkObjConstr.newTree(
|
nnkObjConstr.newTree(
|
||||||
nnkBracketExpr.newTree(Fp, curve),
|
nnkBracketExpr.newTree(Fq, curve),
|
||||||
nnkExprColonExpr.newTree(
|
nnkExprColonExpr.newTree(
|
||||||
ident"value",
|
ident"nres",
|
||||||
newCall(
|
newCall(
|
||||||
bindSym"fromHex",
|
bindSym"fromHex",
|
||||||
nnkBracketExpr.newTree(bindSym"BigInt", bitSize),
|
nnkBracketExpr.newTree(bindSym"BigInt", bitSize),
|
||||||
|
@ -146,13 +146,15 @@ macro declareCurves*(curves: untyped): untyped =
|
||||||
)
|
)
|
||||||
|
|
||||||
# type
|
# type
|
||||||
# `Fp`*[C: static Curve] = object
|
# `Fq`*[C: static Curve] = object
|
||||||
# ## All operations on a field are modulo P
|
# ## All operations on a field are modulo P
|
||||||
# ## P being the prime modulus of the Curve C
|
# ## 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(
|
result.add nnkTypeSection.newTree(
|
||||||
nnkTypeDef.newTree(
|
nnkTypeDef.newTree(
|
||||||
nnkPostfix.newTree(ident"*", Fp),
|
nnkPostfix.newTree(ident"*", Fq),
|
||||||
nnkGenericParams.newTree(newIdentDefs(
|
nnkGenericParams.newTree(newIdentDefs(
|
||||||
C, nnkStaticTy.newTree(Curve), newEmptyNode()
|
C, nnkStaticTy.newTree(Curve), newEmptyNode()
|
||||||
)),
|
)),
|
||||||
|
@ -160,6 +162,10 @@ macro declareCurves*(curves: untyped): untyped =
|
||||||
newEmptyNode(),
|
newEmptyNode(),
|
||||||
newEmptyNode(),
|
newEmptyNode(),
|
||||||
nnkRecList.newTree(
|
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(
|
newIdentDefs(
|
||||||
nnkPostfix.newTree(ident"*", ident"value"),
|
nnkPostfix.newTree(ident"*", ident"value"),
|
||||||
newCall(matchingBigInt, C)
|
newCall(matchingBigInt, C)
|
||||||
|
|
|
@ -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 q is known at compile-time
|
||||||
# We assume that p is not even (requirement for Montgomery form)
|
# 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
|
import
|
||||||
../primitives/constant_time,
|
../primitives/constant_time,
|
||||||
|
@ -21,16 +26,32 @@ import
|
||||||
./bigints_checked
|
./bigints_checked
|
||||||
|
|
||||||
# type
|
# type
|
||||||
# Fp*[C: static Curve] = object
|
# `Fq`*[C: static Curve] = object
|
||||||
# ## P is the prime modulus of the Curve C
|
|
||||||
# ## All operations on a field are modulo P
|
# ## All operations on a field are modulo P
|
||||||
# value*: BigInt[CurveBitSize[C]]
|
# ## P being the prime modulus of the Curve C
|
||||||
export Fp # defined in ../config/curves to avoid recursive module dependencies
|
# ## 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:
|
debug:
|
||||||
func `==`*(a, b: Fp): CTBool[Word] =
|
func `==`*(a, b: Fq): CTBool[Word] =
|
||||||
## Returns true if 2 big ints are equal
|
## 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
|
## Constant-time big integer in-place optional addition
|
||||||
## The addition is only performed if ctl is "true"
|
## The addition is only performed if ctl is "true"
|
||||||
## The result carry is always computed.
|
## 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)
|
## a and b MUST have the same announced bitlength (i.e. `bits` static parameters)
|
||||||
add(a.value, b.value, ctl)
|
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
|
## Constant-time big integer in-place optional substraction
|
||||||
## The substraction is only performed if ctl is "true"
|
## The substraction is only performed if ctl is "true"
|
||||||
## The result carry is always computed.
|
## 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
|
# No exceptions allowed
|
||||||
{.push raises: [].}
|
{.push raises: [].}
|
||||||
|
|
||||||
func `+=`*(a: var Fp, b: Fp) =
|
func `+=`*(a: var Fq, b: Fq) =
|
||||||
## Addition over Fp
|
## Addition over Fq
|
||||||
var ctl = add(a, b, CtTrue)
|
var ctl = add(a, b, CtTrue)
|
||||||
ctl = ctl or not sub(a, Fp.C.Mod, CtFalse)
|
ctl = ctl or not sub(a, Fq.C.Mod, CtFalse)
|
||||||
discard sub(a, Fp.C.Mod, ctl)
|
discard sub(a, Fq.C.Mod, ctl)
|
||||||
|
|
||||||
func `-=`*(a: var Fp, b: Fp) =
|
func `-=`*(a: var Fq, b: Fq) =
|
||||||
## Substraction over Fp
|
## Substraction over Fq
|
||||||
let ctl = sub(a, b, CtTrue)
|
let ctl = sub(a, b, CtTrue)
|
||||||
discard add(a, Fp.C.Mod, ctl)
|
discard add(a, Fq.C.Mod, ctl)
|
||||||
|
|
|
@ -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)
|
|
|
@ -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.
|
|
|
@ -17,7 +17,7 @@ proc main() =
|
||||||
suite "Basic arithmetic over finite fields":
|
suite "Basic arithmetic over finite fields":
|
||||||
test "Addition mod 101":
|
test "Addition mod 101":
|
||||||
block:
|
block:
|
||||||
var x, y, z: Fp[Fake101]
|
var x, y, z: Fq[Fake101]
|
||||||
|
|
||||||
x.fromUint(80'u32)
|
x.fromUint(80'u32)
|
||||||
y.fromUint(10'u32)
|
y.fromUint(10'u32)
|
||||||
|
@ -27,7 +27,7 @@ proc main() =
|
||||||
check: bool(z == x)
|
check: bool(z == x)
|
||||||
|
|
||||||
block:
|
block:
|
||||||
var x, y, z: Fp[Fake101]
|
var x, y, z: Fq[Fake101]
|
||||||
|
|
||||||
x.fromUint(80'u32)
|
x.fromUint(80'u32)
|
||||||
y.fromUint(21'u32)
|
y.fromUint(21'u32)
|
||||||
|
@ -37,7 +37,7 @@ proc main() =
|
||||||
check: bool(z == x)
|
check: bool(z == x)
|
||||||
|
|
||||||
block:
|
block:
|
||||||
var x, y, z: Fp[Fake101]
|
var x, y, z: Fq[Fake101]
|
||||||
|
|
||||||
x.fromUint(80'u32)
|
x.fromUint(80'u32)
|
||||||
y.fromUint(22'u32)
|
y.fromUint(22'u32)
|
||||||
|
@ -48,7 +48,7 @@ proc main() =
|
||||||
|
|
||||||
test "Substraction mod 101":
|
test "Substraction mod 101":
|
||||||
block:
|
block:
|
||||||
var x, y, z: Fp[Fake101]
|
var x, y, z: Fq[Fake101]
|
||||||
|
|
||||||
x.fromUint(80'u32)
|
x.fromUint(80'u32)
|
||||||
y.fromUint(10'u32)
|
y.fromUint(10'u32)
|
||||||
|
@ -58,7 +58,7 @@ proc main() =
|
||||||
check: bool(z == x)
|
check: bool(z == x)
|
||||||
|
|
||||||
block:
|
block:
|
||||||
var x, y, z: Fp[Fake101]
|
var x, y, z: Fq[Fake101]
|
||||||
|
|
||||||
x.fromUint(80'u32)
|
x.fromUint(80'u32)
|
||||||
y.fromUint(80'u32)
|
y.fromUint(80'u32)
|
||||||
|
@ -68,7 +68,7 @@ proc main() =
|
||||||
check: bool(z == x)
|
check: bool(z == x)
|
||||||
|
|
||||||
block:
|
block:
|
||||||
var x, y, z: Fp[Fake101]
|
var x, y, z: Fq[Fake101]
|
||||||
|
|
||||||
x.fromUint(80'u32)
|
x.fromUint(80'u32)
|
||||||
y.fromUint(81'u32)
|
y.fromUint(81'u32)
|
||||||
|
|
Loading…
Reference in New Issue