mirror of
https://github.com/logos-storage/constantine.git
synced 2026-01-03 21:53:06 +00:00
Less magics, les macros, faster compile-times (or not, Fp6 starts to get really slow, like 5s) + some cleanups in curve families + test 𝔽p6 on 32-bit
This commit is contained in:
parent
c40bc1977d
commit
2d5b173a39
@ -72,8 +72,8 @@ task test, "Run all tests":
|
|||||||
test "-d:Constantine32", "tests/test_finite_fields_vs_gmp.nim"
|
test "-d:Constantine32", "tests/test_finite_fields_vs_gmp.nim"
|
||||||
|
|
||||||
# Towers of extension fields
|
# Towers of extension fields
|
||||||
test "", "tests/test_fp2.nim"
|
test "-d:Constantine32", "tests/test_fp2.nim"
|
||||||
test "", "tests/test_fp6.nim"
|
test "-d:Constantine32", "tests/test_fp6.nim"
|
||||||
|
|
||||||
task test_no_gmp, "Run tests that don't require GMP":
|
task test_no_gmp, "Run tests that don't require GMP":
|
||||||
# -d:testingCurves is configured in a *.nim.cfg for convenience
|
# -d:testingCurves is configured in a *.nim.cfg for convenience
|
||||||
@ -112,8 +112,8 @@ task test_no_gmp, "Run tests that don't require GMP":
|
|||||||
test "-d:Constantine32", "tests/test_finite_fields_powinv.nim"
|
test "-d:Constantine32", "tests/test_finite_fields_powinv.nim"
|
||||||
|
|
||||||
# Towers of extension fields
|
# Towers of extension fields
|
||||||
test "", "tests/test_fp2.nim"
|
test "-d:Constantine32", "tests/test_fp2.nim"
|
||||||
test "", "tests/test_fp6.nim"
|
test "-d:Constantine32", "tests/test_fp6.nim"
|
||||||
|
|
||||||
proc runBench(benchName: string, compiler = "") =
|
proc runBench(benchName: string, compiler = "") =
|
||||||
if not dirExists "build":
|
if not dirExists "build":
|
||||||
|
|||||||
@ -29,14 +29,13 @@ import
|
|||||||
../config/[common, curves],
|
../config/[common, curves],
|
||||||
./bigints, ./limbs_montgomery
|
./bigints, ./limbs_montgomery
|
||||||
|
|
||||||
# type
|
type
|
||||||
# `Fp`*[C: static Curve] = object
|
Fp*[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
|
||||||
# ## Internally, data is stored in Montgomery n-residue form
|
## 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)
|
## with the magic constant chosen for convenient division (a power of 2 depending on P bitsize)
|
||||||
# mres*: matchingBigInt(C)
|
mres*: matchingBigInt(C)
|
||||||
export Fp # defined in ../config/curves to avoid recursive module dependencies
|
|
||||||
|
|
||||||
debug:
|
debug:
|
||||||
func `$`*[C: static Curve](a: Fp[C]): string =
|
func `$`*[C: static Curve](a: Fp[C]): string =
|
||||||
@ -57,16 +56,16 @@ debug:
|
|||||||
|
|
||||||
func fromBig*[C: static Curve](T: type Fp[C], src: BigInt): Fp[C] {.noInit.} =
|
func fromBig*[C: static Curve](T: type Fp[C], src: BigInt): Fp[C] {.noInit.} =
|
||||||
## Convert a BigInt to its Montgomery form
|
## Convert a BigInt to its Montgomery form
|
||||||
result.mres.montyResidue(src, C.Mod.mres, C.getR2modP(), C.getNegInvModWord(), C.canUseNoCarryMontyMul())
|
result.mres.montyResidue(src, C.Mod, C.getR2modP(), C.getNegInvModWord(), C.canUseNoCarryMontyMul())
|
||||||
|
|
||||||
func fromBig*[C: static Curve](dst: var Fp[C], src: BigInt) {.noInit.} =
|
func fromBig*[C: static Curve](dst: var Fp[C], src: BigInt) {.noInit.} =
|
||||||
## Convert a BigInt to its Montgomery form
|
## Convert a BigInt to its Montgomery form
|
||||||
dst.mres.montyResidue(src, C.Mod.mres, C.getR2modP(), C.getNegInvModWord(), C.canUseNoCarryMontyMul())
|
dst.mres.montyResidue(src, C.Mod, C.getR2modP(), C.getNegInvModWord(), C.canUseNoCarryMontyMul())
|
||||||
|
|
||||||
func toBig*(src: Fp): auto {.noInit.} =
|
func toBig*(src: Fp): auto {.noInit.} =
|
||||||
## Convert a finite-field element to a BigInt in natural representation
|
## Convert a finite-field element to a BigInt in natural representation
|
||||||
var r {.noInit.}: typeof(src.mres)
|
var r {.noInit.}: typeof(src.mres)
|
||||||
r.redc(src.mres, Fp.C.Mod.mres, Fp.C.getNegInvModWord(), Fp.C.canUseNoCarryMontyMul())
|
r.redc(src.mres, Fp.C.Mod, Fp.C.getNegInvModWord(), Fp.C.canUseNoCarryMontyMul())
|
||||||
return r
|
return r
|
||||||
|
|
||||||
# ############################################################
|
# ############################################################
|
||||||
@ -84,7 +83,7 @@ func toBig*(src: Fp): auto {.noInit.} =
|
|||||||
# exist and can be implemented with compile-time specialization.
|
# exist and can be implemented with compile-time specialization.
|
||||||
|
|
||||||
# Note: for `+=`, double, sum
|
# Note: for `+=`, double, sum
|
||||||
# not(a.mres < Fp.C.Mod.mres) is unnecessary if the prime has the form
|
# not(a.mres < Fp.C.Mod) is unnecessary if the prime has the form
|
||||||
# (2^64)^w - 1 (if using uint64 words).
|
# (2^64)^w - 1 (if using uint64 words).
|
||||||
# In practice I'm not aware of such prime being using in elliptic curves.
|
# In practice I'm not aware of such prime being using in elliptic curves.
|
||||||
# 2^127 - 1 and 2^521 - 1 are used but 127 and 521 are not multiple of 32/64
|
# 2^127 - 1 and 2^521 - 1 are used but 127 and 521 are not multiple of 32/64
|
||||||
@ -107,52 +106,52 @@ func setOne*(a: var Fp) =
|
|||||||
func `+=`*(a: var Fp, b: Fp) =
|
func `+=`*(a: var Fp, b: Fp) =
|
||||||
## In-place addition modulo p
|
## In-place addition modulo p
|
||||||
var overflowed = add(a.mres, b.mres)
|
var overflowed = add(a.mres, b.mres)
|
||||||
overflowed = overflowed or not(a.mres < Fp.C.Mod.mres)
|
overflowed = overflowed or not(a.mres < Fp.C.Mod)
|
||||||
discard csub(a.mres, Fp.C.Mod.mres, overflowed)
|
discard csub(a.mres, Fp.C.Mod, overflowed)
|
||||||
|
|
||||||
func `-=`*(a: var Fp, b: Fp) =
|
func `-=`*(a: var Fp, b: Fp) =
|
||||||
## In-place substraction modulo p
|
## In-place substraction modulo p
|
||||||
let underflowed = sub(a.mres, b.mres)
|
let underflowed = sub(a.mres, b.mres)
|
||||||
discard cadd(a.mres, Fp.C.Mod.mres, underflowed)
|
discard cadd(a.mres, Fp.C.Mod, underflowed)
|
||||||
|
|
||||||
func double*(a: var Fp) =
|
func double*(a: var Fp) =
|
||||||
## Double ``a`` modulo p
|
## Double ``a`` modulo p
|
||||||
var overflowed = double(a.mres)
|
var overflowed = double(a.mres)
|
||||||
overflowed = overflowed or not(a.mres < Fp.C.Mod.mres)
|
overflowed = overflowed or not(a.mres < Fp.C.Mod)
|
||||||
discard csub(a.mres, Fp.C.Mod.mres, overflowed)
|
discard csub(a.mres, Fp.C.Mod, overflowed)
|
||||||
|
|
||||||
func sum*(r: var Fp, a, b: Fp) =
|
func sum*(r: var Fp, a, b: Fp) =
|
||||||
## Sum ``a`` and ``b`` into ``r`` module p
|
## Sum ``a`` and ``b`` into ``r`` module p
|
||||||
## r is initialized/overwritten
|
## r is initialized/overwritten
|
||||||
var overflowed = r.mres.sum(a.mres, b.mres)
|
var overflowed = r.mres.sum(a.mres, b.mres)
|
||||||
overflowed = overflowed or not(r.mres < Fp.C.Mod.mres)
|
overflowed = overflowed or not(r.mres < Fp.C.Mod)
|
||||||
discard csub(r.mres, Fp.C.Mod.mres, overflowed)
|
discard csub(r.mres, Fp.C.Mod, overflowed)
|
||||||
|
|
||||||
func diff*(r: var Fp, a, b: Fp) =
|
func diff*(r: var Fp, a, b: Fp) =
|
||||||
## Substract `b` from `a` and store the result into `r`.
|
## Substract `b` from `a` and store the result into `r`.
|
||||||
## `r` is initialized/overwritten
|
## `r` is initialized/overwritten
|
||||||
var underflowed = r.mres.diff(a.mres, b.mres)
|
var underflowed = r.mres.diff(a.mres, b.mres)
|
||||||
discard cadd(r.mres, Fp.C.Mod.mres, underflowed)
|
discard cadd(r.mres, Fp.C.Mod, underflowed)
|
||||||
|
|
||||||
func double*(r: var Fp, a: Fp) =
|
func double*(r: var Fp, a: Fp) =
|
||||||
## Double ``a`` into ``r``
|
## Double ``a`` into ``r``
|
||||||
## `r` is initialized/overwritten
|
## `r` is initialized/overwritten
|
||||||
var overflowed = r.mres.double(a.mres)
|
var overflowed = r.mres.double(a.mres)
|
||||||
overflowed = overflowed or not(r.mres < Fp.C.Mod.mres)
|
overflowed = overflowed or not(r.mres < Fp.C.Mod)
|
||||||
discard csub(r.mres, Fp.C.Mod.mres, overflowed)
|
discard csub(r.mres, Fp.C.Mod, overflowed)
|
||||||
|
|
||||||
func prod*(r: var Fp, a, b: Fp) =
|
func prod*(r: var Fp, a, b: Fp) =
|
||||||
## Store the product of ``a`` by ``b`` modulo p into ``r``
|
## Store the product of ``a`` by ``b`` modulo p into ``r``
|
||||||
## ``r`` is initialized / overwritten
|
## ``r`` is initialized / overwritten
|
||||||
r.mres.montyMul(a.mres, b.mres, Fp.C.Mod.mres, Fp.C.getNegInvModWord(), Fp.C.canUseNoCarryMontyMul())
|
r.mres.montyMul(a.mres, b.mres, Fp.C.Mod, Fp.C.getNegInvModWord(), Fp.C.canUseNoCarryMontyMul())
|
||||||
|
|
||||||
func square*(r: var Fp, a: Fp) =
|
func square*(r: var Fp, a: Fp) =
|
||||||
## Squaring modulo p
|
## Squaring modulo p
|
||||||
r.mres.montySquare(a.mres, Fp.C.Mod.mres, Fp.C.getNegInvModWord(), Fp.C.canUseNoCarryMontySquare())
|
r.mres.montySquare(a.mres, Fp.C.Mod, Fp.C.getNegInvModWord(), Fp.C.canUseNoCarryMontySquare())
|
||||||
|
|
||||||
func neg*(r: var Fp, a: Fp) =
|
func neg*(r: var Fp, a: Fp) =
|
||||||
## Negate modulo p
|
## Negate modulo p
|
||||||
discard r.mres.diff(Fp.C.Mod.mres, a.mres)
|
discard r.mres.diff(Fp.C.Mod, a.mres)
|
||||||
|
|
||||||
# ############################################################
|
# ############################################################
|
||||||
#
|
#
|
||||||
@ -169,7 +168,7 @@ func pow*(a: var Fp, exponent: BigInt) =
|
|||||||
const windowSize = 5 # TODO: find best window size for each curves
|
const windowSize = 5 # TODO: find best window size for each curves
|
||||||
a.mres.montyPow(
|
a.mres.montyPow(
|
||||||
exponent,
|
exponent,
|
||||||
Fp.C.Mod.mres, Fp.C.getMontyOne(),
|
Fp.C.Mod, Fp.C.getMontyOne(),
|
||||||
Fp.C.getNegInvModWord(), windowSize,
|
Fp.C.getNegInvModWord(), windowSize,
|
||||||
Fp.C.canUseNoCarryMontyMul()
|
Fp.C.canUseNoCarryMontyMul()
|
||||||
)
|
)
|
||||||
@ -188,7 +187,7 @@ func powUnsafeExponent*(a: var Fp, exponent: BigInt) =
|
|||||||
const windowSize = 5 # TODO: find best window size for each curves
|
const windowSize = 5 # TODO: find best window size for each curves
|
||||||
a.mres.montyPowUnsafeExponent(
|
a.mres.montyPowUnsafeExponent(
|
||||||
exponent,
|
exponent,
|
||||||
Fp.C.Mod.mres, Fp.C.getMontyOne(),
|
Fp.C.Mod, Fp.C.getMontyOne(),
|
||||||
Fp.C.getNegInvModWord(), windowSize,
|
Fp.C.getNegInvModWord(), windowSize,
|
||||||
Fp.C.canUseNoCarryMontyMul()
|
Fp.C.canUseNoCarryMontyMul()
|
||||||
)
|
)
|
||||||
@ -228,4 +227,4 @@ func `*=`*(a: var Fp, b: Fp) =
|
|||||||
|
|
||||||
func square*(a: var Fp) =
|
func square*(a: var Fp) =
|
||||||
## Squaring modulo p
|
## Squaring modulo p
|
||||||
a.mres.montySquare(a.mres, Fp.C.Mod.mres, Fp.C.getNegInvModWord(), Fp.C.canUseNoCarryMontySquare())
|
a.mres.montySquare(a.mres, Fp.C.Mod, Fp.C.getNegInvModWord(), Fp.C.canUseNoCarryMontySquare())
|
||||||
|
|||||||
@ -131,4 +131,4 @@ func inv*(r: var Fp, a: Fp) =
|
|||||||
# For now we don't activate the addition chain.
|
# For now we don't activate the addition chain.
|
||||||
# Performance is equal to GCD and it does not pass test on 𝔽p2
|
# Performance is equal to GCD and it does not pass test on 𝔽p2
|
||||||
# We need faster squaring/multiplications
|
# We need faster squaring/multiplications
|
||||||
r.mres.steinsGCD(a.mres, Fp.C.getR2modP(), Fp.C.Mod.mres, Fp.C.getPrimePlus1div2())
|
r.mres.steinsGCD(a.mres, Fp.C.getR2modP(), Fp.C.Mod, Fp.C.getPrimePlus1div2())
|
||||||
|
|||||||
@ -131,62 +131,7 @@ declareCurves:
|
|||||||
|
|
||||||
# ############################################################
|
# ############################################################
|
||||||
#
|
#
|
||||||
# Curve Families
|
# Curve characteristics
|
||||||
#
|
|
||||||
# ############################################################
|
|
||||||
type CurveFamily = enum
|
|
||||||
None
|
|
||||||
BN # Barreto-Naehrig
|
|
||||||
BLS # Barreto-Lynn-Scott
|
|
||||||
|
|
||||||
func family*(curve: Curve): CurveFamily =
|
|
||||||
case curve
|
|
||||||
of BN254:
|
|
||||||
BN
|
|
||||||
of BLS12_381:
|
|
||||||
BLS
|
|
||||||
else:
|
|
||||||
None
|
|
||||||
|
|
||||||
# ############################################################
|
|
||||||
#
|
|
||||||
# Curve Specific Parameters
|
|
||||||
#
|
|
||||||
# ############################################################
|
|
||||||
#
|
|
||||||
# In the form CurveXXX_ParameterName where CurveXXX is the curve name + number of bits
|
|
||||||
# of the field modulus
|
|
||||||
|
|
||||||
# BN Curves
|
|
||||||
# ------------------------------------------------------------
|
|
||||||
# See https://tools.ietf.org/id/draft-yonezawa-pairing-friendly-curves-00.html
|
|
||||||
#
|
|
||||||
# The prime p and order r are primes and of the form
|
|
||||||
# p = 36u^4 + 36u^3 + 24u^2 + 6u + 1
|
|
||||||
# r = 36u^4 + 36u^3 + 18u^2 + 6u + 1
|
|
||||||
#
|
|
||||||
# https://eprint.iacr.org/2010/429.pdf
|
|
||||||
# https://eprint.iacr.org/2013/879.pdf
|
|
||||||
# Usage: Zero-Knowledge Proofs / zkSNARKs in ZCash and Ethereum 1
|
|
||||||
# https://eips.ethereum.org/EIPS/eip-196
|
|
||||||
|
|
||||||
# BLS Curves
|
|
||||||
# ------------------------------------------------------------
|
|
||||||
# See https://tools.ietf.org/id/draft-yonezawa-pairing-friendly-curves-00.html
|
|
||||||
#
|
|
||||||
# BLS12 curves
|
|
||||||
# The prime p and order r are primes and of the form
|
|
||||||
# p = (u - 1)^2 (u^4 - u^2 + 1)/3 + u
|
|
||||||
# r = u^4 - u^2 + 1
|
|
||||||
#
|
|
||||||
# BLS48 curves
|
|
||||||
# The prime p and order r are primes and of the form
|
|
||||||
# p = (u - 1)^2 (u^16 - u^8 + 1)/3 + u
|
|
||||||
# r = u^16 - u^8 + 1
|
|
||||||
|
|
||||||
# ############################################################
|
|
||||||
#
|
|
||||||
# Curve Modulus Accessor
|
|
||||||
#
|
#
|
||||||
# ############################################################
|
# ############################################################
|
||||||
|
|
||||||
@ -196,6 +141,13 @@ macro Mod*(C: static Curve): untyped =
|
|||||||
## Get the Modulus associated to a curve
|
## Get the Modulus associated to a curve
|
||||||
result = bindSym($C & "_Modulus")
|
result = bindSym($C & "_Modulus")
|
||||||
|
|
||||||
|
func getCurveBitSize*(C: static Curve): static int =
|
||||||
|
## Returns the number of bits taken by the curve modulus
|
||||||
|
result = static(CurveBitSize[C])
|
||||||
|
|
||||||
|
template matchingBigInt*(C: static Curve): untyped =
|
||||||
|
BigInt[CurveBitSize[C]]
|
||||||
|
|
||||||
# ############################################################
|
# ############################################################
|
||||||
#
|
#
|
||||||
# Autogeneration of precomputed Montgomery constants in ROM
|
# Autogeneration of precomputed Montgomery constants in ROM
|
||||||
@ -220,10 +172,7 @@ macro genMontyMagics(T: typed): untyped =
|
|||||||
result.add newConstStmt(
|
result.add newConstStmt(
|
||||||
ident($curve & "_CanUseNoCarryMontyMul"), newCall(
|
ident($curve & "_CanUseNoCarryMontyMul"), newCall(
|
||||||
bindSym"useNoCarryMontyMul",
|
bindSym"useNoCarryMontyMul",
|
||||||
nnkDotExpr.newTree(
|
bindSym($curve & "_Modulus")
|
||||||
bindSym($curve & "_Modulus"),
|
|
||||||
ident"mres"
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -231,10 +180,7 @@ macro genMontyMagics(T: typed): untyped =
|
|||||||
result.add newConstStmt(
|
result.add newConstStmt(
|
||||||
ident($curve & "_CanUseNoCarryMontySquare"), newCall(
|
ident($curve & "_CanUseNoCarryMontySquare"), newCall(
|
||||||
bindSym"useNoCarryMontySquare",
|
bindSym"useNoCarryMontySquare",
|
||||||
nnkDotExpr.newTree(
|
bindSym($curve & "_Modulus")
|
||||||
bindSym($curve & "_Modulus"),
|
|
||||||
ident"mres"
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -242,10 +188,7 @@ macro genMontyMagics(T: typed): untyped =
|
|||||||
result.add newConstStmt(
|
result.add newConstStmt(
|
||||||
ident($curve & "_R2modP"), newCall(
|
ident($curve & "_R2modP"), newCall(
|
||||||
bindSym"r2mod",
|
bindSym"r2mod",
|
||||||
nnkDotExpr.newTree(
|
bindSym($curve & "_Modulus")
|
||||||
bindSym($curve & "_Modulus"),
|
|
||||||
ident"mres"
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -253,40 +196,28 @@ macro genMontyMagics(T: typed): untyped =
|
|||||||
result.add newConstStmt(
|
result.add newConstStmt(
|
||||||
ident($curve & "_NegInvModWord"), newCall(
|
ident($curve & "_NegInvModWord"), newCall(
|
||||||
bindSym"negInvModWord",
|
bindSym"negInvModWord",
|
||||||
nnkDotExpr.newTree(
|
bindSym($curve & "_Modulus")
|
||||||
bindSym($curve & "_Modulus"),
|
|
||||||
ident"mres"
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
# const MyCurve_montyOne = montyOne(MyCurve_Modulus)
|
# const MyCurve_montyOne = montyOne(MyCurve_Modulus)
|
||||||
result.add newConstStmt(
|
result.add newConstStmt(
|
||||||
ident($curve & "_MontyOne"), newCall(
|
ident($curve & "_MontyOne"), newCall(
|
||||||
bindSym"montyOne",
|
bindSym"montyOne",
|
||||||
nnkDotExpr.newTree(
|
bindSym($curve & "_Modulus")
|
||||||
bindSym($curve & "_Modulus"),
|
|
||||||
ident"mres"
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
# const MyCurve_InvModExponent = primeMinus2_BE(MyCurve_Modulus)
|
# const MyCurve_InvModExponent = primeMinus2_BE(MyCurve_Modulus)
|
||||||
result.add newConstStmt(
|
result.add newConstStmt(
|
||||||
ident($curve & "_InvModExponent"), newCall(
|
ident($curve & "_InvModExponent"), newCall(
|
||||||
bindSym"primeMinus2_BE",
|
bindSym"primeMinus2_BE",
|
||||||
nnkDotExpr.newTree(
|
bindSym($curve & "_Modulus")
|
||||||
bindSym($curve & "_Modulus"),
|
|
||||||
ident"mres"
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
# const MyCurve_PrimePlus1div2 = primePlus1div2(MyCurve_Modulus)
|
# const MyCurve_PrimePlus1div2 = primePlus1div2(MyCurve_Modulus)
|
||||||
result.add newConstStmt(
|
result.add newConstStmt(
|
||||||
ident($curve & "_PrimePlus1div2"), newCall(
|
ident($curve & "_PrimePlus1div2"), newCall(
|
||||||
bindSym"primePlus1div2",
|
bindSym"primePlus1div2",
|
||||||
nnkDotExpr.newTree(
|
bindSym($curve & "_Modulus")
|
||||||
bindSym($curve & "_Modulus"),
|
|
||||||
ident"mres"
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -294,10 +225,6 @@ macro genMontyMagics(T: typed): untyped =
|
|||||||
|
|
||||||
genMontyMagics(Curve)
|
genMontyMagics(Curve)
|
||||||
|
|
||||||
func getCurveBitSize*(C: static Curve): static int =
|
|
||||||
## Returns the number of bits taken by the curve modulus
|
|
||||||
result = static(CurveBitSize[C])
|
|
||||||
|
|
||||||
macro canUseNoCarryMontyMul*(C: static Curve): untyped =
|
macro canUseNoCarryMontyMul*(C: static Curve): untyped =
|
||||||
## Returns true if the Modulus is compatible with a fast
|
## Returns true if the Modulus is compatible with a fast
|
||||||
## Montgomery multiplication that avoids many carries
|
## Montgomery multiplication that avoids many carries
|
||||||
|
|||||||
@ -59,8 +59,6 @@ macro declareCurves*(curves: untyped): untyped =
|
|||||||
var CurveBitSize = nnKBracket.newTree()
|
var CurveBitSize = nnKBracket.newTree()
|
||||||
var curveModStmts = newStmtList()
|
var curveModStmts = newStmtList()
|
||||||
|
|
||||||
let Fp = ident"Fp"
|
|
||||||
|
|
||||||
for curveDesc in curves:
|
for curveDesc in curves:
|
||||||
curveDesc.expectKind(nnkCommand)
|
curveDesc.expectKind(nnkCommand)
|
||||||
doAssert curveDesc[0].eqIdent"curve"
|
doAssert curveDesc[0].eqIdent"curve"
|
||||||
@ -94,20 +92,14 @@ macro declareCurves*(curves: untyped): untyped =
|
|||||||
curve, bitSize
|
curve, bitSize
|
||||||
)
|
)
|
||||||
|
|
||||||
# const BN254_Modulus = Fp[BN254](value: fromHex(BigInt[254], "0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47"))
|
# const BN254_Modulus = fromHex(BigInt[254], "0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47")
|
||||||
let modulusID = ident($curve & "_Modulus")
|
let modulusID = ident($curve & "_Modulus")
|
||||||
curveModStmts.add newConstStmt(
|
curveModStmts.add newConstStmt(
|
||||||
modulusID,
|
modulusID,
|
||||||
nnkObjConstr.newTree(
|
newCall(
|
||||||
nnkBracketExpr.newTree(Fp, curve),
|
bindSym"fromHex",
|
||||||
nnkExprColonExpr.newTree(
|
nnkBracketExpr.newTree(bindSym"BigInt", bitSize),
|
||||||
ident"mres",
|
modulus
|
||||||
newCall(
|
|
||||||
bindSym"fromHex",
|
|
||||||
nnkBracketExpr.newTree(bindSym"BigInt", bitSize),
|
|
||||||
modulus
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -130,45 +122,6 @@ macro declareCurves*(curves: untyped): untyped =
|
|||||||
cbs, CurveBitSize
|
cbs, CurveBitSize
|
||||||
)
|
)
|
||||||
|
|
||||||
# Need template indirection in the type section to avoid Nim sigmatch bug
|
|
||||||
# template matchingBigInt(C: static Curve): untyped =
|
|
||||||
# BigInt[CurveBitSize[C]]
|
|
||||||
let C = ident"C"
|
|
||||||
let matchingBigInt = genSym(nskTemplate, "matchingBigInt")
|
|
||||||
result.add newProc(
|
|
||||||
name = matchingBigInt,
|
|
||||||
params = [ident"untyped", newIdentDefs(C, nnkStaticTy.newTree(Curve))],
|
|
||||||
body = nnkBracketExpr.newTree(bindSym"BigInt", nnkBracketExpr.newTree(cbs, C)),
|
|
||||||
procType = nnkTemplateDef
|
|
||||||
)
|
|
||||||
|
|
||||||
# type
|
|
||||||
# `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)
|
|
||||||
result.add nnkTypeSection.newTree(
|
|
||||||
nnkTypeDef.newTree(
|
|
||||||
nnkPostfix.newTree(ident"*", Fp),
|
|
||||||
nnkGenericParams.newTree(newIdentDefs(
|
|
||||||
C, nnkStaticTy.newTree(Curve), newEmptyNode()
|
|
||||||
)),
|
|
||||||
# TODO: where should I put the nnkCommentStmt?
|
|
||||||
nnkObjectTy.newTree(
|
|
||||||
newEmptyNode(),
|
|
||||||
newEmptyNode(),
|
|
||||||
nnkRecList.newTree(
|
|
||||||
newIdentDefs(
|
|
||||||
nnkPostfix.newTree(ident"*", ident"mres"),
|
|
||||||
newCall(matchingBigInt, C)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
result.add curveModStmts
|
result.add curveModStmts
|
||||||
|
|
||||||
# echo result.toStrLit()
|
# echo result.toStrLit()
|
||||||
|
|||||||
@ -90,8 +90,8 @@ func random[T](rng: var RngState, a: var T, C: static Curve) {.noInit.}=
|
|||||||
unreduced.limbs[i] = Word(rng.next())
|
unreduced.limbs[i] = Word(rng.next())
|
||||||
|
|
||||||
# Note: a simple modulo will be biaised but it's simple and "fast"
|
# Note: a simple modulo will be biaised but it's simple and "fast"
|
||||||
reduced.reduce(unreduced, C.Mod.mres)
|
reduced.reduce(unreduced, C.Mod)
|
||||||
a.montyResidue(reduced, C.Mod.mres, C.getR2modP(), C.getNegInvModWord(), C.canUseNoCarryMontyMul())
|
a.montyResidue(reduced, C.Mod, C.getR2modP(), C.getNegInvModWord(), C.canUseNoCarryMontyMul())
|
||||||
|
|
||||||
else:
|
else:
|
||||||
for field in fields(a):
|
for field in fields(a):
|
||||||
|
|||||||
@ -6,14 +6,35 @@
|
|||||||
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
|
# * 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.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
|
# This script checks polynomial irreducibility
|
||||||
|
#
|
||||||
|
# Constructing Tower Extensions for the implementation of Pairing-Based Cryptography
|
||||||
|
# Naomi Benger and Michael Scott, 2009
|
||||||
|
# https://eprint.iacr.org/2009/556
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# ############################################################
|
# ############################################################
|
||||||
#
|
#
|
||||||
# Quadratic and Cubic Non-Residue
|
# Failed experiments of actually instantiating
|
||||||
|
# the tower of extension fields
|
||||||
#
|
#
|
||||||
# ############################################################
|
# ############################################################
|
||||||
#
|
|
||||||
# This script checks the compatibility of a field modulus
|
|
||||||
# with given tower extensions
|
|
||||||
|
|
||||||
# ############################################################
|
# ############################################################
|
||||||
# 1st try
|
# 1st try
|
||||||
@ -50,19 +71,20 @@
|
|||||||
# K.<xi, im, p> = NumberField([x^3 - I - 1, x^2 + 1, x - 1])
|
# K.<xi, im, p> = NumberField([x^3 - I - 1, x^2 + 1, x - 1])
|
||||||
|
|
||||||
# ############################################################
|
# ############################################################
|
||||||
# Let's at least verify Fp6
|
# 4th try, just trying to verify Fp6
|
||||||
print('Verifying non-residues')
|
# print('Verifying non-residues')
|
||||||
|
|
||||||
modulus = Integer('0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47')
|
# modulus = Integer('0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47')
|
||||||
|
|
||||||
Fp.<p> = NumberField(x - 1)
|
# Fp.<p> = NumberField(x - 1)
|
||||||
r1 = Fp(-1).residue_symbol(Fp.ideal(modulus),2)
|
# r1 = Fp(-1).residue_symbol(Fp.ideal(modulus),2)
|
||||||
print('Fp² = Fp[sqrt(-1)]: ' + str(r1))
|
# print('Fp² = Fp[sqrt(-1)]: ' + str(r1))
|
||||||
|
|
||||||
Fp2.<im> = Fp.extension(x^2 + 1)
|
# Fp2.<im> = Fp.extension(x^2 + 1)
|
||||||
xi = Fp2(1+im)
|
|
||||||
r2 = xi.residue_symbol(Fp2.ideal(modulus),3)
|
# xi = Fp2(1+im)
|
||||||
# ValueError: The residue symbol to that power is not defined for the number field
|
# r2 = xi.residue_symbol(Fp2.ideal(modulus),3)
|
||||||
# ^ AFAIK that means that Fp2 doesn't contain the 3rd root of unity
|
# # ValueError: The residue symbol to that power is not defined for the number field
|
||||||
# so we are clear
|
# # ^ AFAIK that means that Fp2 doesn't contain the 3rd root of unity
|
||||||
print('Fp6 = Fp²[cubicRoot(1+I)]: ' + str(r2))
|
# # so we are clear
|
||||||
|
# print('Fp6 = Fp²[cubicRoot(1+I)]: ' + str(r2))
|
||||||
|
|||||||
@ -61,7 +61,7 @@ proc binary_prologue[C: static Curve, N: static int](
|
|||||||
mpz_urandomb(a, gmpRng, uint bits)
|
mpz_urandomb(a, gmpRng, uint bits)
|
||||||
mpz_urandomb(b, gmpRng, uint bits)
|
mpz_urandomb(b, gmpRng, uint bits)
|
||||||
# Set modulus to curve modulus
|
# Set modulus to curve modulus
|
||||||
let err = mpz_set_str(p, Curve(C).Mod.mres.toHex(), 0)
|
let err = mpz_set_str(p, Curve(C).Mod.toHex(), 0)
|
||||||
doAssert err == 0, "Error on prime for curve " & $Curve(C)
|
doAssert err == 0, "Error on prime for curve " & $Curve(C)
|
||||||
|
|
||||||
#########################################################
|
#########################################################
|
||||||
|
|||||||
@ -40,12 +40,12 @@ suite "𝔽p2 = 𝔽p[𝑖] (irreducible polynomial x²+1)":
|
|||||||
O.setOne()
|
O.setOne()
|
||||||
O
|
O
|
||||||
let oneBig = block:
|
let oneBig = block:
|
||||||
var O{.noInit.}: typeof(C.Mod.mres)
|
var O{.noInit.}: typeof(C.Mod)
|
||||||
O.setOne()
|
O.setOne()
|
||||||
O
|
O
|
||||||
|
|
||||||
var r: typeof(C.Mod.mres)
|
var r: typeof(C.Mod)
|
||||||
r.redc(oneFp2.c0.mres, C.Mod.mres, C.getNegInvModWord(), canUseNoCarryMontyMul = false)
|
r.redc(oneFp2.c0.mres, C.Mod, C.getNegInvModWord(), canUseNoCarryMontyMul = false)
|
||||||
|
|
||||||
check:
|
check:
|
||||||
bool(r == oneBig)
|
bool(r == oneBig)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user