Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Twisted Edwards MSM: setNeutral instead of zeroMem #406

Merged
merged 3 commits into from
Jun 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion config.nims
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# Absolute imports from porject root
# Absolute imports from project root
--path:"."
4 changes: 2 additions & 2 deletions constantine/commitments/eth_verkle_ipa.nim
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@ func ipa_verify*[N, logN: static int, EcAff, F](

# ∑ᵢ[uᵢ]Lᵢ + ∑ᵢ[uᵢ⁻¹]Rᵢ + [⟨ā,b̄⟩.w]G - [a₀]G₀ - [a₀.b₀.w]G
var t {.noInit.}: EC
t.multiScalarMul_reference_vartime(fs.toOpenArray(), ecs.toOpenArray())
t.multiScalarMul_vartime(fs.toOpenArray(), ecs.toOpenArray())

# ∑ᵢ[uᵢ]Lᵢ + ∑ᵢ[uᵢ⁻¹]Rᵢ + [⟨ā,b̄⟩.w]G - [a₀]G₀ - [a₀.b₀.w]G = -⟨ā,Ḡ⟩
var C {.noInit.}: EC
Expand Down Expand Up @@ -949,7 +949,7 @@ func ipa_multi_verify*[N, logN: static int, EcAff, F](
# E = ∑rⁱ.Cᵢ/(t-zᵢ)
var E {.noInit.}: EC
var Eaff {.noInit.}: EcAff
E.multiScalarMul_reference_vartime(invTminusChallenges, comms_by_challenges, num_distinct_challenges)
E.multiScalarMul_vartime(invTminusChallenges, comms_by_challenges, num_distinct_challenges)
Eaff.affine(E)
transcript.absorb("E", Eaff)
freeHeapAligned(invTminusChallenges)
Expand Down
4 changes: 2 additions & 2 deletions constantine/commitments/pedersen_commitments.nim
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func pedersen_commit[EC, ECaff](
##
## Output:
## Commit(m) := ∑[mᵢ]Gᵢ
r.multiScalarMul_reference_vartime(messages, public_generators)
r.multiScalarMul_vartime(messages, public_generators)

func pedersen_commit*[N: static int, EC, ECaff, F](
crs: PolynomialEval[N, EcAff],
Expand All @@ -49,7 +49,7 @@ func pedersen_commit*[N: static int, EC, ECaff, F](
##
## Output:
## Commit(m) := ∑[mᵢ]Gᵢ
r.multiScalarMul_reference_vartime(messages.evals, crs.evals)
r.multiScalarMul_vartime(messages.evals, crs.evals)

func pedersen_commit*[EC, ECaff, F](
public_generators: View[ECaff],
Expand Down
6 changes: 4 additions & 2 deletions constantine/math/elliptic/ec_multi_scalar_mul.nim
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,8 @@ func multiScalarMul_vartime*[bits: static int, EC, ECaff](
const numBuckets = 1 shl (c-1)

let buckets = allocHeapArray(EC, numBuckets)
zeroMem(buckets[0].addr, sizeof(EC) * numBuckets)
for i in 0 ..< numBuckets:
buckets[i].setNeutral()

# Algorithm
# ---------
Expand Down Expand Up @@ -367,7 +368,8 @@ func multiScalarMulAffine_vartime[bits: static int, EC, ECaff](
when top != 0: # Prologue
when excess != 0:
# The top might use only a few bits, the affine scheduler would likely have significant collisions
zeroMem(sched.buckets.pt.addr, buckets.pt.sizeof())
for i in 0 ..< numBuckets:
sched.buckets.pt[i].setNeutral()
r.miniMSM(sched.buckets.pt.asUnchecked(), w, kTopWindow, c, coefs, points, N)
w -= c
else:
Expand Down
14 changes: 8 additions & 6 deletions constantine/math/elliptic/ec_multi_scalar_mul_parallel.nim
Original file line number Diff line number Diff line change
Expand Up @@ -135,14 +135,15 @@ export bestBucketBitSize
# Parallel MSM non-affine
# ------------------------------

proc bucketAccumReduce_zeroMem[bits: static int, EC, ECaff](
proc bucketAccumReduce_withInit[bits: static int, EC, ECaff](
windowSum: ptr EC,
buckets: ptr EC or ptr UncheckedArray[EC],
bitIndex: int, miniMsmKind: static MiniMsmKind, c: static int,
coefs: ptr UncheckedArray[BigInt[bits]], points: ptr UncheckedArray[ECaff], N: int) =
const numBuckets = 1 shl (c-1)
let buckets = cast[ptr UncheckedArray[EC]](buckets)
zeroMem(buckets, sizeof(EC) * numBuckets)
for i in 0 ..< numBuckets:
buckets[i].setNeutral()
bucketAccumReduce(windowSum[], buckets, bitIndex, miniMsmKind, c, coefs, points, N)

proc msm_vartime_parallel[bits: static int, EC, ECaff](
Expand All @@ -169,14 +170,14 @@ proc msm_vartime_parallel[bits: static int, EC, ECaff](
# ---------

block: # 1. Bucket accumulation and reduction
miniMSMsReady[0] = tp.spawnAwaitable bucketAccumReduce_zeroMem(
miniMSMsReady[0] = tp.spawnAwaitable bucketAccumReduce_withInit(
miniMSMsResults[0].addr,
bucketsMatrix[0].addr,
bitIndex = 0, kBottomWindow, c,
coefs, points, N)

for w in 1 ..< numFullWindows:
miniMSMsReady[w] = tp.spawnAwaitable bucketAccumReduce_zeroMem(
miniMSMsReady[w] = tp.spawnAwaitable bucketAccumReduce_withInit(
miniMSMsResults[w].addr,
bucketsMatrix[w*numBuckets].addr,
bitIndex = w*c, kFullWindow, c,
Expand All @@ -188,7 +189,7 @@ proc msm_vartime_parallel[bits: static int, EC, ECaff](

when top != 0:
when excess != 0:
bucketAccumReduce_zeroMem(
bucketAccumReduce_withInit(
r,
bucketsMatrix[numFullWindows*numBuckets].addr,
bitIndex = top, kTopWindow, c,
Expand Down Expand Up @@ -375,7 +376,8 @@ proc msmAffine_vartime_parallel[bits: static int, EC, ECaff](
when top != 0:
when excess != 0:
let buckets = allocHeapArray(EC, numBuckets)
zeroMem(buckets[0].addr, sizeof(EC) * numBuckets)
for i in 0 ..< numBuckets:
buckets[i].setNeutral()
r[].bucketAccumReduce(buckets, bitIndex = top, kTopWindow, c,
coefs, points, N)
buckets.freeHeap()
Expand Down
38 changes: 23 additions & 15 deletions constantine/math/elliptic/ec_twistededwards_projective.nim
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,22 @@ type EC_TwEdw_Prj*[F] = object
template getScalarField*(EC: type EC_TwEdw_Prj): untyped =
Fr[EC.F.Name]

func isNeutral*(P: EC_TwEdw_Prj): SecretBool {.inline.} =
## Returns true if P is the neutral element / identity element
## and false otherwise, i.e. ∀Q, P+Q == Q
## Contrary to Short Weierstrass curve, the neutral element is on the curve
# Isogeny-based constructions to create
# prime order curves overload this generic identity check.
result = P.x.isZero() and (P.y == P.z)

func setNeutral*(P: var EC_TwEdw_Prj) {.inline.} =
## Set P to the neutral element / identity element
## i.e. ∀Q, P+Q == Q.
## Contrary to Short Weierstrass curve, the neutral element is on the curve
P.x.setZero()
P.y.setOne()
P.z.setOne()

func `==`*(P, Q: EC_TwEdw_Prj): SecretBool =
## Constant-time equality check
## This is a costly operation
Expand All @@ -52,21 +68,8 @@ func `==`*(P, Q: EC_TwEdw_Prj): SecretBool =
b.prod(Q.y, P.z)
result = result and a == b

func isNeutral*(P: EC_TwEdw_Prj): SecretBool {.inline.} =
## Returns true if P is the neutral element / identity element
## and false otherwise, i.e. ∀Q, P+Q == Q
## Contrary to Short Weierstrass curve, the neutral element is on the curve
# Isogeny-based constructions to create
# prime order curves overload this generic identity check.
result = P.x.isZero() and (P.y == P.z)

func setNeutral*(P: var EC_TwEdw_Prj) {.inline.} =
## Set P to the neutral element / identity element
## i.e. ∀Q, P+Q == Q.
## Contrary to Short Weierstrass curve, the neutral element is on the curve
P.x.setZero()
P.y.setOne()
P.z.setOne()
# Ensure a zero-init point doesn't propagate 0s and match any
result = result and not(P.isNeutral() xor Q.isNeutral())

func ccopy*(P: var EC_TwEdw_Prj, Q: EC_TwEdw_Prj, ctl: SecretBool) {.inline.} =
## Constant-time conditional copy
Expand Down Expand Up @@ -458,6 +461,11 @@ func fromAffine*[F](
proj.y = aff.y
proj.z.setOne()

let inf = aff.isNeutral()
proj.x.csetZero(inf)
proj.y.csetOne(inf)
proj.z.csetOne(inf)

# Vartime overloading
# ------------------------------------------------------------
# For generic vartime operations on both ShortWeierstrass curves and Twisted Edwards
Expand Down
10 changes: 10 additions & 0 deletions constantine/named/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
# Named Algebraic Objects

This folder holds named fields and named curves configuration and precomputed constants.


⚠️ For Twisted Edwards curves
The formula are complete only if d is not a square, otherwise
they must be modified to handle the identity/neutral element with conditional moves.

Sage script to check with Bandersnatch constants for example
r = Integer('0x1cfb69d4ca675f520cce760202687600ff8f87007419047174fd06b52876e7e1')
d = Integer('0x6389c12633c267cbc66e3bf86be3b6d8cb66677177e54f92b369f2f5188d58e7')
GF(r)(d).nth_root(2, all=True)
14 changes: 8 additions & 6 deletions constantine/named/config_fields_and_curves.nim
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,14 @@ export CurveFamily, SexticTwist
# Barbulescu, R. and S. Duquesne, "Updating Key Size Estimations for Pairings",
# Journal of Cryptology, DOI 10.1007/s00145-018-9280-5, January 2018.

# Generates public:
# - type Curve* = enum
# - proc Mod*(curve: static Curve): auto
# which returns the field modulus of the curve
# - proc family*(curve: static Curve): CurveFamily
# which returns the curve family
# ⚠️ For Twisted Edwards curves
# The formula are complete only if d is not a square, otherwise
# they must be modified to handle the identity/neutral element with conditional moves.
#
# Sage script to check with Bandersnatch constants for example
# r = Integer('0x1cfb69d4ca675f520cce760202687600ff8f87007419047174fd06b52876e7e1')
# d = Integer('0x6389c12633c267cbc66e3bf86be3b6d8cb66677177e54f92b369f2f5188d58e7')
# GF(r)(d).nth_root(2, all=True)

declareCurves:
# -----------------------------------------------------------------------------
Expand Down
Loading