Skip to content

Commit

Permalink
feat: add banderwagon (#271)
Browse files Browse the repository at this point in the history
* banderwagon curve declaration added

* equality for banderwagon implemented

* subgroup check added

* map_to_field added

* feat: banderwagon serialization

* fix: imported codecs_status_codes into bls_signature

* fix: spec links added in comments

* fix: typo in curve declaration

* fix: banderwagon subgroup check shifted to subgroups file + map_to_field removed

* feat:  new equality re-exported

* fix: codecs_status_codes imported

* fix: equality check removed from banderwagon.nim to twistedEdwards implementation

* Update constantine/math/elliptic/ec_twistededwards_affine.nim

Co-authored-by: Mamy Ratsimbazafy <[email protected]>

* Update constantine/math/elliptic/ec_twistededwards_projective.nim

Co-authored-by: Mamy Ratsimbazafy <[email protected]>

* adding and doubling tests with minor fixes

* feat: banderwagon & bandersnatch generators added

* fix: doubling point error for twisted edwards projective

* fix: negation of x co-ordinate in spec

* fix: negetion of x in serialization

* fix: negetion in deserializarion

* feat: banderwagon tests

* fix: comments added for tests and serialization

* Update suggestion constantine/math/config/precompute.nim

---------

Co-authored-by: Mamy Ratsimbazafy <[email protected]>
  • Loading branch information
advaita-saha and mratsim authored Sep 23, 2023
1 parent 7b64f85 commit f925853
Show file tree
Hide file tree
Showing 21 changed files with 656 additions and 28 deletions.
1 change: 1 addition & 0 deletions constantine/ethereum_bls_signatures.nim
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ import
],
./math/io/[io_bigints, io_fields],
signatures/bls_signatures,
serialization/codecs_status_codes,
serialization/codecs_bls12_381

export
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import
./commitments/kzg_polynomial_commitments,
./hashes,
./platforms/[abstractions, allocs],
./serialization/[codecs_bls12_381, endians],
./serialization/[codecs_status_codes, codecs_bls12_381, endians],
./trusted_setups/ethereum_kzg_srs

export loadTrustedSetup, TrustedSetupStatus, EthereumKZGContext
Expand Down
18 changes: 18 additions & 0 deletions constantine/math/config/curves_declaration.nim
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,24 @@ declareCurves:
coef_a: -5
coef_d: "6389c12633c267cbc66e3bf86be3b6d8cb66677177e54f92b369f2f5188d58e7"

curve Banderwagon: # Banderwagon is a prime subgroup constructed over the Bandersnatch Curve.
# https://hackmd.io/@6iQDuIePQjyYBqDChYw_jg/BJBNcv9fq
bitwidth: 255
modulus: "0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001"

# Weierstrass form: y² = x³ − 3763200000x − 7867596800000
# Mongomery form: By² = x³ + Ax² + x
# B=0x300c3385d13bedb7c9e229e185c4ce8b1dd3b71366bb97c30855c0aa41d62727
# A=0x4247698f4e32ad45a293959b4ca17afa4a2d2317e4c6ce5023e1f
# Twisted Edwards form: −5x² + y² = 1 + dx²y²
# d = 138827208126141220649022263972958607803 / 171449701953573178309673572579671231137
order: "0x1cfb69d4ca675f520cce760202687600ff8f87007419047174fd06b52876e7e1"
orderBitwidth: 253
cofactor: 4
eq_form: TwistedEdwards
coef_a: -5
coef_d: "6389c12633c267cbc66e3bf86be3b6d8cb66677177e54f92b369f2f5188d58e7"

curve Edwards25519: # Bernstein curve
bitwidth: 255
modulus: "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed"
Expand Down
7 changes: 7 additions & 0 deletions constantine/math/config/curves_derived.nim
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,13 @@ macro genDerivedConstants*(mode: static DerivedConstantMode): untyped =
M
)
)
# const MyCurve_PrimeMinus1div2 = primeMinus1div2(MyCurve_Modulus)
result.add newConstStmt(
used(curve & ff & "_PrimeMinus1div2"), newCall(
bindSym"primeMinus1div2",
M
)
)
# const MyCurve_PrimeMinus3div4_BE = primeMinus3div4_BE(MyCurve_Modulus)
result.add newConstStmt(
used(curve & ff & "_PrimeMinus3div4_BE"), newCall(
Expand Down
5 changes: 5 additions & 0 deletions constantine/math/config/curves_prop_field_derived.nim
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,11 @@ macro getPrimePlus1div2*(ff: type FF): untyped =
## Warning ⚠️: Result in canonical domain (not Montgomery)
result = bindConstant(ff, "PrimePlus1div2")

macro getPrimeMinus1div2*(ff: type FF): untyped =
## Get (P-1) / 2 for an odd prime
## Warning ⚠️: Result in canonical domain (not Montgomery)
result = bindConstant(ff, "PrimeMinus1div2")

macro getPrimeMinus3div4_BE*(ff: type FF): untyped =
## Get (P-3) / 4 in big-endian serialized format
result = bindConstant(ff, "PrimeMinus3div4_BE")
Expand Down
10 changes: 10 additions & 0 deletions constantine/math/config/precompute.nim
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,16 @@ func primePlus1div2*(P: BigInt): BigInt =
let carry = result.add(1)
doAssert not carry

func primeMinus1div2*(P: BigInt): BigInt =
## Compute (P-1)/2
## For use in constant-time modular inversion
##
## Warning ⚠️: Result is in the canonical domain (not Montgomery)

result = P
# discard result.sub(1) # right-shifting automatically implies "-1" for odd numbers (which all prime >2 are).
result.shiftRight(1)

func primeMinus3div4_BE*[bits: static int](
P: BigInt[bits]
): array[bits.ceilDiv_vartime(8), byte] {.noInit.} =
Expand Down
23 changes: 23 additions & 0 deletions constantine/math/constants/bandersnatch_generators.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# 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.

import
../config/curves,
../elliptic/ec_twistededwards_affine,
../io/[io_fields, io_extfields]

{.used.}

# Generators
# -----------------------------------------------------------------
# https://eprint.iacr.org/2021/1152.pdf

const Bandersnatch_generator* = ECP_TwEdwards_Aff[Fp[Bandersnatch]](
x: Fp[Bandersnatch].fromHex"0x29c132cc2c0b34c5743711777bbe42f32b79c022ad998465e1e71866a252ae18",
y: Fp[Bandersnatch].fromHex"0x2a6c669eda123e0f157d8b50badcd586358cad81eee464605e3167b6cc974166"
)
23 changes: 23 additions & 0 deletions constantine/math/constants/banderwagon_generators.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# 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.

import
../config/curves,
../elliptic/ec_twistededwards_affine,
../io/[io_fields, io_extfields]

{.used.}

# Generators
# -----------------------------------------------------------------
# https://eprint.iacr.org/2021/1152.pdf

const Banderwagon_generator* = ECP_TwEdwards_Aff[Fp[Banderwagon]](
x: Fp[Banderwagon].fromHex("29c132cc2c0b34c5743711777bbe42f32b79c022ad998465e1e71866a252ae18"),
y: Fp[Banderwagon].fromHex("2a6c669eda123e0f157d8b50badcd586358cad81eee464605e3167b6cc974166")
)
19 changes: 19 additions & 0 deletions constantine/math/constants/banderwagon_sqrt.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# 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.

import
../config/curves,
../io/[io_bigints, io_fields],
../arithmetic/finite_fields

const
# with e = 2adicity
# p == s * 2^e + 1
# root_of_unity = smallest_quadratic_nonresidue^s
# exponent = (p-1-2^e)/2^e / 2
Banderwagon_TonelliShanks_exponent* = BigInt[222].fromHex"0x39f6d3a994cebea4199cec0404d0ec02a9ded2017fff2dff7fffffff"
Banderwagon_TonelliShanks_twoAdicity* = 32
Banderwagon_TonelliShanks_root_of_unity* = Fp[Banderwagon].fromHex"0x212d79e5b416b6f0fd56dc8d168d6c0c4024ff270b3e0941b788f500b912f1f"
42 changes: 42 additions & 0 deletions constantine/math/constants/banderwagon_subgroups.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# 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.

import
../../platforms/abstractions,
../config/curves,
../arithmetic,
../extension_fields,
../elliptic/ec_twistededwards_projective

# ############################################################
#
# Subgroup Check
#
# ############################################################

func isInSubGroup*(P: ECP_TwEdwards_Prj[Fp[Banderwagon]]): SecretBool =
## Checks if the point is in the quotient subgroup
## The group law does not change because what we quotiented by was a subgroup.
## These are still points on the bandersnatch curve and form a group under point addition.
##
## This is to be used to check if the point lies in the Banderwagon
## while importing a point from serialized bytes

var res{.noInit.}: typeof(P).F
var one{.noInit.}: typeof(P).F

one.setOne()
res.setZero()

## Compute 1 - aX^2 and check its legendre symbol
res.prod(P.x, P.x)
res.prod(res, Banderwagon.getCoefA())
res.neg(res)
res.sum(res, one)

return res.isSquare()
4 changes: 3 additions & 1 deletion constantine/math/constants/zoo_generators.nim
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import
std/macros,
../config/curves,
./bls12_381_generators,
./bn254_snarks_generators
./bn254_snarks_generators,
./bandersnatch_generators,
./banderwagon_generators

{.experimental: "dynamicbindsym".}

Expand Down
2 changes: 2 additions & 0 deletions constantine/math/constants/zoo_square_roots.nim
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import
./curve25519_sqrt,
./jubjub_sqrt,
./bandersnatch_sqrt,
./banderwagon_sqrt,
./pallas_sqrt,
./vesta_sqrt

Expand All @@ -29,6 +30,7 @@ export
curve25519_sqrt,
jubjub_sqrt,
bandersnatch_sqrt,
banderwagon_sqrt,
pallas_sqrt,
vesta_sqrt

Expand Down
77 changes: 77 additions & 0 deletions constantine/math/elliptic/ec_twistededwards_affine.nim
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ func isInf*(P: ECP_TwEdwards_Aff): SecretBool =
## and false otherwise
result = P.x.isZero() and P.y.isOne()

func setInf*(P: var ECP_TwEdwards_Aff) {.inline.} =
## Set ``P`` to infinity
P.x.setZero()
P.y.setOne()


func isOnCurve*[F](x, y: F): SecretBool =
## Returns true if the (x, y) coordinates
Expand Down Expand Up @@ -76,6 +81,51 @@ func isOnCurve*[F](x, y: F): SecretBool =
t2 -= t0
return t2.isOne()

func trySetFromCoordX*[F](P: var ECP_TwEdwards_Aff[F], x: F): SecretBool =
## Try to create a point on the elliptic curve from X co-ordinate
## ax²+y²=1+dx²y² (affine coordinate)
##
## return true and update `P` if `y` leads to a valid point
## return false otherwise, in that case `P` is undefined.

# y² = (1 - ax²)/(1 - dx²)
var t {.noInit.}: F
var one {.noInit.}: F
one.setOne()

# (1 - dx²)
t.square(x)
when F.C.getCoefD() is int:
when F.C.getCoefD() >= 0:
P.y.fromUint uint F.C.getCoefD()
else:
P.y.fromUint uint -F.C.getCoefD()
P.y.neg()
else:
P.y = F.C.getCoefD()
P.y *= t
P.y.neg()
P.y += one

# (1 - ax²)
when F.C.getCoefA() is int:
when F.C.getCoefA() >= 0:
P.x.fromUint uint F.C.getCoefA()
else:
P.x.fromUint uint -F.C.getCoefA()
P.x.neg()
else:
P.x = F.C.getCoefA()
P.x *= t
P.x.neg()
P.x += one

# √((1 - ax²)/(1 - dx²))
result = sqrt_ratio_if_square(t, P.x, P.y)
P.y = t
P.x = x


func trySetFromCoordY*[F](P: var ECP_TwEdwards_Aff[F], y: F): SecretBool =
## Try to create a point the elliptic curve
## ax²+y²=1+dx²y² (affine coordinate)
Expand Down Expand Up @@ -147,3 +197,30 @@ func cneg*(P: var ECP_TwEdwards_Aff, ctl: CTBool) =
## Conditional negation.
## Negate if ``ctl`` is true
P.x.cneg(ctl)

# ############################################################
#
# Banderwagon Specific Operations
#
# ############################################################

func `==`*(P, Q: ECP_TwEdwards_Aff[Fp[Banderwagon]]): SecretBool =
## Equality check for points in the Banderwagon Group
## The equality check is optimized for the quotient group
## see: https://hackmd.io/@6iQDuIePQjyYBqDChYw_jg/BJBNcv9fq#Equality-check
##
## Check for the (0,0) point, which is possible
##
## This is a costly operation

var lhs{.noInit.}, rhs{.noInit.}: typeof(P).F

# Check for the zero points
result = not(P.x.is_zero() and P.y.is_zero())
result = result or not(Q.x.is_zero() and Q.y.is_zero())

## Check for the equality of the points
## X1 * Y2 == X2 * Y1
lhs.prod(P.x, Q.y)
rhs.prod(Q.x, P.y)
result = result and lhs == rhs
Loading

0 comments on commit f925853

Please sign in to comment.