mirror of
https://github.com/logos-storage/constantine.git
synced 2026-01-08 16:13:14 +00:00
feat: add banderwagon (#271)
* 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 <mamy_github@numforge.co> * Update constantine/math/elliptic/ec_twistededwards_projective.nim Co-authored-by: Mamy Ratsimbazafy <mamy_github@numforge.co> * 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 <mamy_github@numforge.co>
This commit is contained in:
parent
7b64f85a29
commit
f9258531f9
@ -80,6 +80,7 @@ import
|
|||||||
],
|
],
|
||||||
./math/io/[io_bigints, io_fields],
|
./math/io/[io_bigints, io_fields],
|
||||||
signatures/bls_signatures,
|
signatures/bls_signatures,
|
||||||
|
serialization/codecs_status_codes,
|
||||||
serialization/codecs_bls12_381
|
serialization/codecs_bls12_381
|
||||||
|
|
||||||
export
|
export
|
||||||
|
|||||||
@ -18,7 +18,7 @@ import
|
|||||||
./commitments/kzg_polynomial_commitments,
|
./commitments/kzg_polynomial_commitments,
|
||||||
./hashes,
|
./hashes,
|
||||||
./platforms/[abstractions, allocs],
|
./platforms/[abstractions, allocs],
|
||||||
./serialization/[codecs_bls12_381, endians],
|
./serialization/[codecs_status_codes, codecs_bls12_381, endians],
|
||||||
./trusted_setups/ethereum_kzg_srs
|
./trusted_setups/ethereum_kzg_srs
|
||||||
|
|
||||||
export loadTrustedSetup, TrustedSetupStatus, EthereumKZGContext
|
export loadTrustedSetup, TrustedSetupStatus, EthereumKZGContext
|
||||||
|
|||||||
@ -155,6 +155,24 @@ declareCurves:
|
|||||||
coef_a: -5
|
coef_a: -5
|
||||||
coef_d: "6389c12633c267cbc66e3bf86be3b6d8cb66677177e54f92b369f2f5188d58e7"
|
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
|
curve Edwards25519: # Bernstein curve
|
||||||
bitwidth: 255
|
bitwidth: 255
|
||||||
modulus: "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed"
|
modulus: "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed"
|
||||||
|
|||||||
@ -102,6 +102,13 @@ macro genDerivedConstants*(mode: static DerivedConstantMode): untyped =
|
|||||||
M
|
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)
|
# const MyCurve_PrimeMinus3div4_BE = primeMinus3div4_BE(MyCurve_Modulus)
|
||||||
result.add newConstStmt(
|
result.add newConstStmt(
|
||||||
used(curve & ff & "_PrimeMinus3div4_BE"), newCall(
|
used(curve & ff & "_PrimeMinus3div4_BE"), newCall(
|
||||||
|
|||||||
@ -104,6 +104,11 @@ macro getPrimePlus1div2*(ff: type FF): untyped =
|
|||||||
## Warning ⚠️: Result in canonical domain (not Montgomery)
|
## Warning ⚠️: Result in canonical domain (not Montgomery)
|
||||||
result = bindConstant(ff, "PrimePlus1div2")
|
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 =
|
macro getPrimeMinus3div4_BE*(ff: type FF): untyped =
|
||||||
## Get (P-3) / 4 in big-endian serialized format
|
## Get (P-3) / 4 in big-endian serialized format
|
||||||
result = bindConstant(ff, "PrimeMinus3div4_BE")
|
result = bindConstant(ff, "PrimeMinus3div4_BE")
|
||||||
|
|||||||
@ -392,6 +392,16 @@ func primePlus1div2*(P: BigInt): BigInt =
|
|||||||
let carry = result.add(1)
|
let carry = result.add(1)
|
||||||
doAssert not carry
|
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](
|
func primeMinus3div4_BE*[bits: static int](
|
||||||
P: BigInt[bits]
|
P: BigInt[bits]
|
||||||
): array[bits.ceilDiv_vartime(8), byte] {.noInit.} =
|
): array[bits.ceilDiv_vartime(8), byte] {.noInit.} =
|
||||||
|
|||||||
23
constantine/math/constants/bandersnatch_generators.nim
Normal file
23
constantine/math/constants/bandersnatch_generators.nim
Normal file
@ -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
constantine/math/constants/banderwagon_generators.nim
Normal file
23
constantine/math/constants/banderwagon_generators.nim
Normal file
@ -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
constantine/math/constants/banderwagon_sqrt.nim
Normal file
19
constantine/math/constants/banderwagon_sqrt.nim
Normal file
@ -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
constantine/math/constants/banderwagon_subgroups.nim
Normal file
42
constantine/math/constants/banderwagon_subgroups.nim
Normal file
@ -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()
|
||||||
@ -10,7 +10,9 @@ import
|
|||||||
std/macros,
|
std/macros,
|
||||||
../config/curves,
|
../config/curves,
|
||||||
./bls12_381_generators,
|
./bls12_381_generators,
|
||||||
./bn254_snarks_generators
|
./bn254_snarks_generators,
|
||||||
|
./bandersnatch_generators,
|
||||||
|
./banderwagon_generators
|
||||||
|
|
||||||
{.experimental: "dynamicbindsym".}
|
{.experimental: "dynamicbindsym".}
|
||||||
|
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import
|
|||||||
./curve25519_sqrt,
|
./curve25519_sqrt,
|
||||||
./jubjub_sqrt,
|
./jubjub_sqrt,
|
||||||
./bandersnatch_sqrt,
|
./bandersnatch_sqrt,
|
||||||
|
./banderwagon_sqrt,
|
||||||
./pallas_sqrt,
|
./pallas_sqrt,
|
||||||
./vesta_sqrt
|
./vesta_sqrt
|
||||||
|
|
||||||
@ -29,6 +30,7 @@ export
|
|||||||
curve25519_sqrt,
|
curve25519_sqrt,
|
||||||
jubjub_sqrt,
|
jubjub_sqrt,
|
||||||
bandersnatch_sqrt,
|
bandersnatch_sqrt,
|
||||||
|
banderwagon_sqrt,
|
||||||
pallas_sqrt,
|
pallas_sqrt,
|
||||||
vesta_sqrt
|
vesta_sqrt
|
||||||
|
|
||||||
|
|||||||
@ -39,6 +39,11 @@ func isInf*(P: ECP_TwEdwards_Aff): SecretBool =
|
|||||||
## and false otherwise
|
## and false otherwise
|
||||||
result = P.x.isZero() and P.y.isOne()
|
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 =
|
func isOnCurve*[F](x, y: F): SecretBool =
|
||||||
## Returns true if the (x, y) coordinates
|
## Returns true if the (x, y) coordinates
|
||||||
@ -76,6 +81,51 @@ func isOnCurve*[F](x, y: F): SecretBool =
|
|||||||
t2 -= t0
|
t2 -= t0
|
||||||
return t2.isOne()
|
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 =
|
func trySetFromCoordY*[F](P: var ECP_TwEdwards_Aff[F], y: F): SecretBool =
|
||||||
## Try to create a point the elliptic curve
|
## Try to create a point the elliptic curve
|
||||||
## ax²+y²=1+dx²y² (affine coordinate)
|
## ax²+y²=1+dx²y² (affine coordinate)
|
||||||
@ -147,3 +197,30 @@ func cneg*(P: var ECP_TwEdwards_Aff, ctl: CTBool) =
|
|||||||
## Conditional negation.
|
## Conditional negation.
|
||||||
## Negate if ``ctl`` is true
|
## Negate if ``ctl`` is true
|
||||||
P.x.cneg(ctl)
|
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
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import
|
|||||||
../extension_fields,
|
../extension_fields,
|
||||||
./ec_twistededwards_affine
|
./ec_twistededwards_affine
|
||||||
|
|
||||||
|
|
||||||
# ############################################################
|
# ############################################################
|
||||||
#
|
#
|
||||||
# Elliptic Curve in Twisted Edwards form
|
# Elliptic Curve in Twisted Edwards form
|
||||||
@ -65,6 +66,25 @@ func ccopy*(P: var ECP_TwEdwards_Prj, Q: ECP_TwEdwards_Prj, ctl: SecretBool) {.i
|
|||||||
for fP, fQ in fields(P, Q):
|
for fP, fQ in fields(P, Q):
|
||||||
ccopy(fP, fQ, ctl)
|
ccopy(fP, fQ, ctl)
|
||||||
|
|
||||||
|
func trySetFromCoordX*[F](
|
||||||
|
P: var ECP_TwEdwards_Prj[F],
|
||||||
|
x: F): SecretBool =
|
||||||
|
## Try to create a point on the elliptic curve from X co-ordinate
|
||||||
|
## ax²+y²=1+dx²y² (affine coordinate)
|
||||||
|
##
|
||||||
|
## The `Z` coordinates is set to 1
|
||||||
|
##
|
||||||
|
## return true and update `P` if `y` leads to a valid point
|
||||||
|
## return false otherwise, in that case `P` is undefined.
|
||||||
|
|
||||||
|
var Q{.noInit.}: ECP_TwEdwards_Aff[F]
|
||||||
|
result = Q.trySetFromCoordX(x)
|
||||||
|
|
||||||
|
P.x = Q.x
|
||||||
|
P.y = Q.y
|
||||||
|
P.z.setOne()
|
||||||
|
|
||||||
|
|
||||||
func trySetFromCoordY*[F](
|
func trySetFromCoordY*[F](
|
||||||
P: var ECP_TwEdwards_Prj[F],
|
P: var ECP_TwEdwards_Prj[F],
|
||||||
y: F): SecretBool =
|
y: F): SecretBool =
|
||||||
@ -259,11 +279,11 @@ func double*[Field](
|
|||||||
|
|
||||||
# (B-C-D) => 2X1Y1, but With squaring and 2 substractions instead of mul + addition
|
# (B-C-D) => 2X1Y1, but With squaring and 2 substractions instead of mul + addition
|
||||||
# In practice, squaring is not cheap enough to compasate the extra substraction cost.
|
# In practice, squaring is not cheap enough to compasate the extra substraction cost.
|
||||||
|
E.square(P.x)
|
||||||
r.x.prod(P.x, P.y)
|
r.x.prod(P.x, P.y)
|
||||||
r.x.double()
|
r.x.double()
|
||||||
|
|
||||||
D.square(P.y)
|
D.square(P.y)
|
||||||
E.square(P.x)
|
|
||||||
E *= Field.C.getCoefA()
|
E *= Field.C.getCoefA()
|
||||||
|
|
||||||
r.y.sum(E, D) # Ry stores F = E+D
|
r.y.sum(E, D) # Ry stores F = E+D
|
||||||
@ -293,6 +313,14 @@ func diff*(r: var ECP_TwEdwards_Prj,
|
|||||||
nQ.neg(Q)
|
nQ.neg(Q)
|
||||||
r.sum(P, nQ)
|
r.sum(P, nQ)
|
||||||
|
|
||||||
|
template affine*[F](_: type ECP_TwEdwards_Prj[F]): typedesc =
|
||||||
|
## Returns the affine type that corresponds to the Jacobian type input
|
||||||
|
ECP_TwEdwards_Aff[F]
|
||||||
|
|
||||||
|
template projective*[F](_: type ECP_TwEdwards_Aff[F]): typedesc =
|
||||||
|
## Returns the projective type that corresponds to the affine type input
|
||||||
|
ECP_TwEdwards_Aff[F]
|
||||||
|
|
||||||
func affine*[F](
|
func affine*[F](
|
||||||
aff: var ECP_TwEdwards_Aff[F],
|
aff: var ECP_TwEdwards_Aff[F],
|
||||||
proj: ECP_TwEdwards_Prj[F]) =
|
proj: ECP_TwEdwards_Prj[F]) =
|
||||||
@ -302,9 +330,36 @@ func affine*[F](
|
|||||||
aff.x.prod(proj.x, invZ)
|
aff.x.prod(proj.x, invZ)
|
||||||
aff.y.prod(proj.y, invZ)
|
aff.y.prod(proj.y, invZ)
|
||||||
|
|
||||||
func projective*[F](
|
func fromAffine*[F](
|
||||||
proj: var ECP_TwEdwards_Aff[F],
|
proj: var ECP_TwEdwards_Prj[F],
|
||||||
aff: ECP_TwEdwards_Prj[F]) {.inline.} =
|
aff: ECP_TwEdwards_Aff[F]) {.inline.} =
|
||||||
proj.x = aff.x
|
proj.x = aff.x
|
||||||
proj.y = aff.y
|
proj.y = aff.y
|
||||||
proj.z.setOne()
|
proj.z.setOne()
|
||||||
|
|
||||||
|
# ############################################################
|
||||||
|
#
|
||||||
|
# Banderwagon Specific Operations
|
||||||
|
#
|
||||||
|
# ############################################################
|
||||||
|
|
||||||
|
func `==`*(P, Q: ECP_TwEdwards_Prj[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
|
||||||
113
constantine/serialization/codecs_banderwagon.nim
Normal file
113
constantine/serialization/codecs_banderwagon.nim
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
## ############################################################
|
||||||
|
##
|
||||||
|
## Banderwagon Serialization
|
||||||
|
##
|
||||||
|
## ############################################################
|
||||||
|
|
||||||
|
import
|
||||||
|
../platforms/abstractions,
|
||||||
|
../math/config/curves,
|
||||||
|
../math/elliptic/[
|
||||||
|
ec_twistededwards_affine,
|
||||||
|
ec_twistededwards_projective
|
||||||
|
],
|
||||||
|
../math/[
|
||||||
|
extension_fields,
|
||||||
|
arithmetic,
|
||||||
|
constants/banderwagon_subgroups
|
||||||
|
],
|
||||||
|
../math/io/[io_bigints, io_fields],
|
||||||
|
./codecs_status_codes
|
||||||
|
|
||||||
|
type
|
||||||
|
EC_Prj* = ECP_TwEdwards_Prj[Fp[Banderwagon]]
|
||||||
|
EC_Aff* = ECP_TwEdwards_Aff[Fp[Banderwagon]]
|
||||||
|
|
||||||
|
func serialize*(dst: var array[32, byte], P: EC_Prj): CttCodecEccStatus =
|
||||||
|
## Serialize a Banderwagon point(x, y) in the format
|
||||||
|
##
|
||||||
|
## serialize = bigEndian( sign(y) * x )
|
||||||
|
## If y is not lexicographically largest
|
||||||
|
## set x -> -x
|
||||||
|
## then serialize
|
||||||
|
##
|
||||||
|
## Returns cttCodecEcc_Success if successful
|
||||||
|
## Spec: https://hackmd.io/@6iQDuIePQjyYBqDChYw_jg/BJBNcv9fq#Serialisation
|
||||||
|
|
||||||
|
# Setting all bits to 0 for the point of infinity
|
||||||
|
if P.isInf().bool():
|
||||||
|
for i in 0 ..< dst.len:
|
||||||
|
dst[i] = byte 0
|
||||||
|
return cttCodecEcc_Success
|
||||||
|
|
||||||
|
# Convert the projective points into affine format before encoding
|
||||||
|
var aff {.noInit.}: EC_Aff
|
||||||
|
aff.affine(P)
|
||||||
|
|
||||||
|
let lexicographicallyLargest = aff.y.toBig() >= Fp[Banderwagon].getPrimeMinus1div2()
|
||||||
|
|
||||||
|
if not lexicographicallyLargest.bool():
|
||||||
|
aff.x.neg()
|
||||||
|
|
||||||
|
dst.marshal(aff.x, bigEndian)
|
||||||
|
return cttCodecEcc_Success
|
||||||
|
|
||||||
|
func deserialize_unchecked*(dst: var EC_Prj, src: array[32, byte]): CttCodecEccStatus =
|
||||||
|
## Deserialize a Banderwagon point (x, y) in format
|
||||||
|
##
|
||||||
|
## if y is not lexicographically largest
|
||||||
|
## set y -> -y
|
||||||
|
##
|
||||||
|
## Returns cttCodecEcc_Success if successful
|
||||||
|
## https://hackmd.io/@6iQDuIePQjyYBqDChYw_jg/BJBNcv9fq#Serialisation
|
||||||
|
# If infinity, src must be all zeros
|
||||||
|
var check: bool = true
|
||||||
|
for i in 0 ..< src.len:
|
||||||
|
if src[i] != byte 0:
|
||||||
|
check = false
|
||||||
|
break
|
||||||
|
if check:
|
||||||
|
dst.setInf()
|
||||||
|
return cttCodecEcc_PointAtInfinity
|
||||||
|
|
||||||
|
var t{.noInit.}: matchingBigInt(Banderwagon)
|
||||||
|
t.unmarshal(src, bigEndian)
|
||||||
|
|
||||||
|
if bool(t >= Banderwagon.Mod()):
|
||||||
|
return cttCodecEcc_CoordinateGreaterThanOrEqualModulus
|
||||||
|
|
||||||
|
var x{.noInit.}: Fp[Banderwagon]
|
||||||
|
x.fromBig(t)
|
||||||
|
|
||||||
|
let onCurve = dst.trySetFromCoordX(x)
|
||||||
|
if not(bool onCurve):
|
||||||
|
return cttCodecEcc_PointNotOnCurve
|
||||||
|
|
||||||
|
let isLexicographicallyLargest = dst.y.toBig() >= Fp[Banderwagon].getPrimeMinus1div2()
|
||||||
|
dst.y.cneg(not isLexicographicallyLargest)
|
||||||
|
|
||||||
|
return cttCodecEcc_Success
|
||||||
|
|
||||||
|
func deserialize*(dst: var EC_Prj, src: array[32, byte]): CttCodecEccStatus =
|
||||||
|
## Deserialize a Banderwagon point (x, y) in format
|
||||||
|
##
|
||||||
|
## Also checks if the point lies in the banderwagon scheme subgroup
|
||||||
|
##
|
||||||
|
## Returns cttCodecEcc_Success if successful
|
||||||
|
## Returns cttCodecEcc_PointNotInSubgroup if doesn't lie in subgroup
|
||||||
|
result = deserialize_unchecked(dst, src)
|
||||||
|
if result != cttCodecEcc_Success:
|
||||||
|
return result
|
||||||
|
|
||||||
|
if not(bool dst.isInSubgroup()):
|
||||||
|
return cttCodecEcc_PointNotInSubgroup
|
||||||
|
|
||||||
|
return cttCodecEcc_Success
|
||||||
@ -45,22 +45,11 @@ import
|
|||||||
extension_fields,
|
extension_fields,
|
||||||
arithmetic,
|
arithmetic,
|
||||||
constants/zoo_subgroups],
|
constants/zoo_subgroups],
|
||||||
../math/io/[io_bigints, io_fields]
|
../math/io/[io_bigints, io_fields],
|
||||||
|
./codecs_status_codes
|
||||||
|
|
||||||
type
|
type
|
||||||
CttCodecScalarStatus* = enum
|
Scalar* = matchingOrderBigInt(BLS12_381)
|
||||||
cttCodecScalar_Success
|
|
||||||
cttCodecScalar_Zero
|
|
||||||
cttCodecScalar_ScalarLargerThanCurveOrder
|
|
||||||
|
|
||||||
CttCodecEccStatus* = enum
|
|
||||||
cttCodecEcc_Success
|
|
||||||
cttCodecEcc_InvalidEncoding
|
|
||||||
cttCodecEcc_CoordinateGreaterThanOrEqualModulus
|
|
||||||
cttCodecEcc_PointNotOnCurve
|
|
||||||
cttCodecEcc_PointNotInSubgroup
|
|
||||||
cttCodecEcc_PointAtInfinity
|
|
||||||
|
|
||||||
G1P* = ECP_ShortW_Aff[Fp[BLS12_381], G1]
|
G1P* = ECP_ShortW_Aff[Fp[BLS12_381], G1]
|
||||||
G2P* = ECP_ShortW_Aff[Fp2[BLS12_381], G2]
|
G2P* = ECP_ShortW_Aff[Fp2[BLS12_381], G2]
|
||||||
|
|
||||||
|
|||||||
21
constantine/serialization/codecs_status_codes.nim
Normal file
21
constantine/serialization/codecs_status_codes.nim
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
type
|
||||||
|
CttCodecScalarStatus* = enum
|
||||||
|
cttCodecScalar_Success
|
||||||
|
cttCodecScalar_Zero
|
||||||
|
cttCodecScalar_ScalarLargerThanCurveOrder
|
||||||
|
|
||||||
|
CttCodecEccStatus* = enum
|
||||||
|
cttCodecEcc_Success
|
||||||
|
cttCodecEcc_InvalidEncoding
|
||||||
|
cttCodecEcc_CoordinateGreaterThanOrEqualModulus
|
||||||
|
cttCodecEcc_PointNotOnCurve
|
||||||
|
cttCodecEcc_PointNotInSubgroup
|
||||||
|
cttCodecEcc_PointAtInfinity
|
||||||
@ -95,7 +95,7 @@ proc run_EC_addition_tests*(
|
|||||||
const testSuiteDesc = "Elliptic curve in " & $ec.F.C.getEquationForm() & " form"
|
const testSuiteDesc = "Elliptic curve in " & $ec.F.C.getEquationForm() & " form"
|
||||||
|
|
||||||
suite testSuiteDesc & " - " & $ec & " - [" & $WordBitWidth & "-bit mode]":
|
suite testSuiteDesc & " - " & $ec & " - [" & $WordBitWidth & "-bit mode]":
|
||||||
test "The infinity point is the neutral element w.r.t. to EC " & $ec.G & " addition":
|
test "The infinity point is the neutral element w.r.t. to EC " & " addition":
|
||||||
proc test(EC: typedesc, randZ: bool, gen: RandomGen) =
|
proc test(EC: typedesc, randZ: bool, gen: RandomGen) =
|
||||||
var inf {.noInit.}: EC
|
var inf {.noInit.}: EC
|
||||||
inf.setInf()
|
inf.setInf()
|
||||||
@ -182,7 +182,7 @@ proc run_EC_addition_tests*(
|
|||||||
test(ec, randZ = false, gen = Long01Sequence)
|
test(ec, randZ = false, gen = Long01Sequence)
|
||||||
test(ec, randZ = true, gen = Long01Sequence)
|
test(ec, randZ = true, gen = Long01Sequence)
|
||||||
|
|
||||||
test "EC " & $ec.G & " add is commutative":
|
test "EC" & " add is commutative":
|
||||||
proc test(EC: typedesc, randZ: bool, gen: RandomGen) =
|
proc test(EC: typedesc, randZ: bool, gen: RandomGen) =
|
||||||
for _ in 0 ..< Iters:
|
for _ in 0 ..< Iters:
|
||||||
var r0{.noInit.}, r1{.noInit.}: EC
|
var r0{.noInit.}, r1{.noInit.}: EC
|
||||||
@ -200,7 +200,7 @@ proc run_EC_addition_tests*(
|
|||||||
test(ec, randZ = false, gen = Long01Sequence)
|
test(ec, randZ = false, gen = Long01Sequence)
|
||||||
test(ec, randZ = true, gen = Long01Sequence)
|
test(ec, randZ = true, gen = Long01Sequence)
|
||||||
|
|
||||||
test "EC " & $ec.G & " add is associative":
|
test "EC" & " add is associative":
|
||||||
proc test(EC: typedesc, randZ: bool, gen: RandomGen) =
|
proc test(EC: typedesc, randZ: bool, gen: RandomGen) =
|
||||||
for _ in 0 ..< Iters:
|
for _ in 0 ..< Iters:
|
||||||
let a = rng.random_point(EC, randZ, gen)
|
let a = rng.random_point(EC, randZ, gen)
|
||||||
@ -249,7 +249,7 @@ proc run_EC_addition_tests*(
|
|||||||
test(ec, randZ = false, gen = Long01Sequence)
|
test(ec, randZ = false, gen = Long01Sequence)
|
||||||
test(ec, randZ = true, gen = Long01Sequence)
|
test(ec, randZ = true, gen = Long01Sequence)
|
||||||
|
|
||||||
test "EC " & $ec.G & " double and EC " & $ec.G & " add are consistent":
|
test "EC " & " double and EC " & " add are consistent":
|
||||||
proc test(EC: typedesc, randZ: bool, gen: RandomGen) =
|
proc test(EC: typedesc, randZ: bool, gen: RandomGen) =
|
||||||
for _ in 0 ..< Iters:
|
for _ in 0 ..< Iters:
|
||||||
let a = rng.random_point(EC, randZ, gen)
|
let a = rng.random_point(EC, randZ, gen)
|
||||||
@ -469,7 +469,7 @@ proc run_EC_mul_sanity_tests*(
|
|||||||
const testSuiteDesc = "Elliptic curve in " & $ec.F.C.getEquationForm() & " form"
|
const testSuiteDesc = "Elliptic curve in " & $ec.F.C.getEquationForm() & " form"
|
||||||
|
|
||||||
suite testSuiteDesc & " - " & $ec & " - [" & $WordBitWidth & "-bit mode]":
|
suite testSuiteDesc & " - " & $ec & " - [" & $WordBitWidth & "-bit mode]":
|
||||||
test "EC " & $ec.G & " mul [0]P == Inf":
|
test "EC " & " mul [0]P == Inf":
|
||||||
proc test(EC: typedesc, bits: static int, randZ: bool, gen: RandomGen) =
|
proc test(EC: typedesc, bits: static int, randZ: bool, gen: RandomGen) =
|
||||||
for _ in 0 ..< ItersMul:
|
for _ in 0 ..< ItersMul:
|
||||||
let a = rng.random_point(EC, randZ, gen)
|
let a = rng.random_point(EC, randZ, gen)
|
||||||
@ -506,7 +506,7 @@ proc run_EC_mul_sanity_tests*(
|
|||||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = false, gen = Long01Sequence)
|
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = false, gen = Long01Sequence)
|
||||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = true, gen = Long01Sequence)
|
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = true, gen = Long01Sequence)
|
||||||
|
|
||||||
test "EC " & $ec.G & " mul [1]P == P":
|
test "EC " & " mul [1]P == P":
|
||||||
proc test(EC: typedesc, bits: static int, randZ: bool, gen: RandomGen) =
|
proc test(EC: typedesc, bits: static int, randZ: bool, gen: RandomGen) =
|
||||||
for _ in 0 ..< ItersMul:
|
for _ in 0 ..< ItersMul:
|
||||||
let a = rng.random_point(EC, randZ, gen)
|
let a = rng.random_point(EC, randZ, gen)
|
||||||
@ -532,7 +532,7 @@ proc run_EC_mul_sanity_tests*(
|
|||||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = false, gen = Long01Sequence)
|
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = false, gen = Long01Sequence)
|
||||||
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = true, gen = Long01Sequence)
|
test(ec, bits = ec.F.C.getCurveOrderBitwidth(), randZ = true, gen = Long01Sequence)
|
||||||
|
|
||||||
test "EC " & $ec.G & " mul [2]P == P.double()":
|
test "EC " & " mul [2]P == P.double()":
|
||||||
proc test(EC: typedesc, bits: static int, randZ: bool, gen: RandomGen) =
|
proc test(EC: typedesc, bits: static int, randZ: bool, gen: RandomGen) =
|
||||||
for _ in 0 ..< ItersMul:
|
for _ in 0 ..< ItersMul:
|
||||||
let a = rng.random_point(EC, randZ, gen)
|
let a = rng.random_point(EC, randZ, gen)
|
||||||
@ -575,7 +575,7 @@ proc run_EC_mul_distributive_tests*(
|
|||||||
|
|
||||||
suite testSuiteDesc & " - " & $ec & " - [" & $WordBitWidth & "-bit mode]":
|
suite testSuiteDesc & " - " & $ec & " - [" & $WordBitWidth & "-bit mode]":
|
||||||
|
|
||||||
test "EC " & $ec.G & " mul is distributive over EC add":
|
test "EC" & " mul is distributive over EC add":
|
||||||
proc test(EC: typedesc, bits: static int, randZ: bool, gen: RandomGen) =
|
proc test(EC: typedesc, bits: static int, randZ: bool, gen: RandomGen) =
|
||||||
for _ in 0 ..< ItersMul:
|
for _ in 0 ..< ItersMul:
|
||||||
let a = rng.random_point(EC, randZ, gen)
|
let a = rng.random_point(EC, randZ, gen)
|
||||||
|
|||||||
@ -33,3 +33,9 @@ run_EC_addition_tests(
|
|||||||
Iters = Iters,
|
Iters = Iters,
|
||||||
moduleName = "test_ec_twistededwards_projective_add_double_" & $Bandersnatch
|
moduleName = "test_ec_twistededwards_projective_add_double_" & $Bandersnatch
|
||||||
)
|
)
|
||||||
|
|
||||||
|
run_EC_addition_tests(
|
||||||
|
ec = ECP_TwEdwards_Prj[Fp[Banderwagon]],
|
||||||
|
Iters = Iters,
|
||||||
|
moduleName = "test_ec_twistededwards_projective_add_double_" & $Banderwagon
|
||||||
|
)
|
||||||
@ -34,3 +34,9 @@ run_EC_mul_distributive_tests(
|
|||||||
ItersMul = ItersMul,
|
ItersMul = ItersMul,
|
||||||
moduleName = "test_ec_twistededwards_projective_mul_distributive_" & $Bandersnatch
|
moduleName = "test_ec_twistededwards_projective_mul_distributive_" & $Bandersnatch
|
||||||
)
|
)
|
||||||
|
|
||||||
|
run_EC_mul_distributive_tests(
|
||||||
|
ec = ECP_TwEdwards_Prj[Fp[Banderwagon]],
|
||||||
|
ItersMul = ItersMul,
|
||||||
|
moduleName = "test_ec_twistededwards_projective_mul_distributive_" & $Banderwagon
|
||||||
|
)
|
||||||
209
tests/t_banderwagon.nim
Normal file
209
tests/t_banderwagon.nim
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
# 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
|
||||||
|
std/unittest,
|
||||||
|
../constantine/math/config/[type_ff, curves],
|
||||||
|
../constantine/math/elliptic/[
|
||||||
|
ec_twistededwards_affine,
|
||||||
|
ec_twistededwards_projective
|
||||||
|
],
|
||||||
|
../constantine/math/io/io_fields,
|
||||||
|
../constantine/serialization/[
|
||||||
|
codecs_status_codes,
|
||||||
|
codecs_banderwagon,
|
||||||
|
codecs
|
||||||
|
],
|
||||||
|
../constantine/math/arithmetic,
|
||||||
|
../constantine/math/constants/zoo_generators
|
||||||
|
|
||||||
|
type
|
||||||
|
EC* = ECP_TwEdwards_Prj[Fp[Banderwagon]]
|
||||||
|
Bytes* = array[32, byte]
|
||||||
|
|
||||||
|
# The generator point from Banderwagon
|
||||||
|
var generator = Banderwagon.getGenerator()
|
||||||
|
|
||||||
|
# serialized points which lie on Banderwagon
|
||||||
|
const expected_bit_strings: array[16, string] = [
|
||||||
|
"0x4a2c7486fd924882bf02c6908de395122843e3e05264d7991e18e7985dad51e9",
|
||||||
|
"0x43aa74ef706605705989e8fd38df46873b7eae5921fbed115ac9d937399ce4d5",
|
||||||
|
"0x5e5f550494159f38aa54d2ed7f11a7e93e4968617990445cc93ac8e59808c126",
|
||||||
|
"0x0e7e3748db7c5c999a7bcd93d71d671f1f40090423792266f94cb27ca43fce5c",
|
||||||
|
"0x14ddaa48820cb6523b9ae5fe9fe257cbbd1f3d598a28e670a40da5d1159d864a",
|
||||||
|
"0x6989d1c82b2d05c74b62fb0fbdf8843adae62ff720d370e209a7b84e14548a7d",
|
||||||
|
"0x26b8df6fa414bf348a3dc780ea53b70303ce49f3369212dec6fbe4b349b832bf",
|
||||||
|
"0x37e46072db18f038f2cc7d3d5b5d1374c0eb86ca46f869d6a95fc2fb092c0d35",
|
||||||
|
"0x2c1ce64f26e1c772282a6633fac7ca73067ae820637ce348bb2c8477d228dc7d",
|
||||||
|
"0x297ab0f5a8336a7a4e2657ad7a33a66e360fb6e50812d4be3326fab73d6cee07",
|
||||||
|
"0x5b285811efa7a965bd6ef5632151ebf399115fcc8f5b9b8083415ce533cc39ce",
|
||||||
|
"0x1f939fa2fd457b3effb82b25d3fe8ab965f54015f108f8c09d67e696294ab626",
|
||||||
|
"0x3088dcb4d3f4bacd706487648b239e0be3072ed2059d981fe04ce6525af6f1b8",
|
||||||
|
"0x35fbc386a16d0227ff8673bc3760ad6b11009f749bb82d4facaea67f58fc60ed",
|
||||||
|
"0x00f29b4f3255e318438f0a31e058e4c081085426adb0479f14c64985d0b956e0",
|
||||||
|
"0x3fa4384b2fa0ecc3c0582223602921daaa893a97b64bdf94dcaa504e8b7b9e5f",
|
||||||
|
]
|
||||||
|
|
||||||
|
## These are all points which will be shown to be on the curve
|
||||||
|
## but are not in the correct subgroup
|
||||||
|
const bad_bit_string: array[16, string] = [
|
||||||
|
"0x1b6989e2393c65bbad7567929cdbd72bbf0218521d975b0fb209fba0ee493c32",
|
||||||
|
"0x280e608d5bbbe84b16aac62aa450e8921840ea563f1c9c266e0240d89cbe6a78",
|
||||||
|
"0x31468782818807366dbbcd20b9f10f0d5b93f22e33fe49b450dfbddaf3ba6a9b",
|
||||||
|
"0x6bfc4097e4874cdddebe74e041fcd329d8455278cd42b6dd4f40b042d4fc466b",
|
||||||
|
"0x65dc0a9730cce485d82b230ce32c7c21688967c8943b4a51ba468f927e2e28ef",
|
||||||
|
"0x0fd3536157199b46617c3fba4bae1c2ffab5409dfea1de62161bc10748651671",
|
||||||
|
"0x5bdc73f43e90ae5c2956320ce2ef2b17809b11d6b9758c7861793b41f39b7c01",
|
||||||
|
"0x23a89c778ee10b9925ad3df5dc1f7ab244c1daf305669bc6b03d1aaa100037a4",
|
||||||
|
"0x67505814852867356aaa8387896efa1d1b9a72aad95549e53e69c15eb36a642c",
|
||||||
|
"0x301bc9b1129a727c2a65b96f55a5bcd642a3d37e0834196863c4430e4281dc3a",
|
||||||
|
"0x45d08715ac67ebb088bcfa3d04bcce76510edeb9e23f12ed512894ba1e6518fc",
|
||||||
|
"0x0b3b6e1f8ec72e63c6aa7ae87628071df3d82ea2bea6516d1948dac2edc12179",
|
||||||
|
"0x72430a05f507747aa5a42481b4f93522aa682b1d56e5285f089aa1b5fb09c67a",
|
||||||
|
"0x5eb4d3e5ce8107c6dd7c6398f2a903a0df75ce655939c29a3e309f43fe5bcd1f",
|
||||||
|
"0x6671109a7a15f4852ead3298318595a36010930fddbd3c8f667c6390e7ac3c66",
|
||||||
|
"0x120faa1df94d5d831bbb69fc44816e25afd27288a333299ac3c94518fd0e016f",
|
||||||
|
]
|
||||||
|
|
||||||
|
# ############################################################
|
||||||
|
#
|
||||||
|
# Banderwagon Serialization Tests
|
||||||
|
#
|
||||||
|
# ############################################################
|
||||||
|
suite "Banderwagon Serialization Tests":
|
||||||
|
var points: seq[EC]
|
||||||
|
|
||||||
|
## Check encoding if it is as expected or not
|
||||||
|
test "Test Encoding from Fixed Vectors":
|
||||||
|
proc testSerialize(len: int) =
|
||||||
|
# First the point is set to generator P
|
||||||
|
# then with each iteration 2P, 4P, . . . doubling
|
||||||
|
var point {.noInit.}: EC
|
||||||
|
point.fromAffine(generator)
|
||||||
|
|
||||||
|
for i in 0 ..< len:
|
||||||
|
var arr: Bytes
|
||||||
|
let stat = arr.serialize(point)
|
||||||
|
|
||||||
|
# Check if the serialization took place and in expected way
|
||||||
|
doAssert stat == cttCodecEcc_Success, "Serialization Failed"
|
||||||
|
doAssert expected_bit_strings[i] == arr.toHex(), "bit string does not match expected"
|
||||||
|
points.add(point)
|
||||||
|
|
||||||
|
point.double() #doubling the point
|
||||||
|
|
||||||
|
testSerialize(expected_bit_strings.len)
|
||||||
|
|
||||||
|
## Check decoding if it is as expected or not
|
||||||
|
test "Decoding Each bit string":
|
||||||
|
proc testDeserialization(len: int) =
|
||||||
|
# Checks if the point serialized in the previous
|
||||||
|
# tests matches with the deserialization of expected strings
|
||||||
|
for i, bit_string in expected_bit_strings:
|
||||||
|
|
||||||
|
# converts serialized value in hex to byte array
|
||||||
|
var arr: Bytes
|
||||||
|
arr.fromHex(bit_string)
|
||||||
|
|
||||||
|
# deserialization from expected bits
|
||||||
|
var point{.noInit.}: EC
|
||||||
|
let stat = point.deserialize(arr)
|
||||||
|
|
||||||
|
# Assertion check for the Deserialization Success & correctness
|
||||||
|
doAssert stat == cttCodecEcc_Success, "Deserialization Failed"
|
||||||
|
doAssert (point == points[i]).bool(), "Decoded Element is different from expected element"
|
||||||
|
|
||||||
|
testDeserialization(expected_bit_strings.len)
|
||||||
|
|
||||||
|
# Check if the subgroup check is working on eliminating
|
||||||
|
# points which don't lie on banderwagon, while
|
||||||
|
# deserializing from an untrusted source
|
||||||
|
test "Decoding Points Not on Curve":
|
||||||
|
proc testBadPointDeserialization(len: int) =
|
||||||
|
# Checks whether the bad bit string
|
||||||
|
# get deserialized, it should return error -> cttCodecEcc_PointNotInSubgroup
|
||||||
|
for bit_string in bad_bit_string:
|
||||||
|
|
||||||
|
# converts serialized value in hex to byte array
|
||||||
|
var arr: Bytes
|
||||||
|
arr.fromHex(bit_string)
|
||||||
|
|
||||||
|
# deserialization from bits
|
||||||
|
var point{.noInit.}: EC
|
||||||
|
let stat = point.deserialize(arr)
|
||||||
|
|
||||||
|
# Assertion check for error
|
||||||
|
doAssert stat == cttCodecEcc_PointNotInSubgroup, "Bad point Deserialization Failed, in subgroup check"
|
||||||
|
|
||||||
|
testBadPointDeserialization(bad_bit_string.len)
|
||||||
|
|
||||||
|
|
||||||
|
# ############################################################
|
||||||
|
#
|
||||||
|
# Banderwagon Point Operations Tests
|
||||||
|
#
|
||||||
|
# ############################################################
|
||||||
|
suite "Banderwagon Points Tests":
|
||||||
|
|
||||||
|
## Tests if the operation are consistent & correct
|
||||||
|
## consistency of Addition with doubling
|
||||||
|
## and correctness of the subtraction
|
||||||
|
test "Test for Addition, Subtraction, Doubling":
|
||||||
|
proc testAddSubDouble() =
|
||||||
|
var a, b, gen_point, identity {.noInit.} : EC
|
||||||
|
gen_point.fromAffine(generator)
|
||||||
|
|
||||||
|
# Setting the identity Element
|
||||||
|
identity.x.setZero()
|
||||||
|
identity.y.setOne()
|
||||||
|
identity.z.setOne()
|
||||||
|
|
||||||
|
a.sum(gen_point, gen_point) # a = g+g = 2g
|
||||||
|
b.double(gen_point) # b = 2g
|
||||||
|
|
||||||
|
doAssert (not (a == gen_point).bool()), "The generator should not have order < 2"
|
||||||
|
doAssert (a == b).bool(), "Add and Double formulae do not match" # Checks is doubling and addition are consistent
|
||||||
|
|
||||||
|
a.diff(a, b) # a <- a - b
|
||||||
|
doAssert (a == identity).bool(), "Sub formula is incorrect; any point minus itself should give the identity point"
|
||||||
|
|
||||||
|
testAddSubDouble()
|
||||||
|
|
||||||
|
## Points that differ by a two torsion point
|
||||||
|
## are equal, where the two torsion point is not the point at infinity
|
||||||
|
test "Test Two Torsion Equality":
|
||||||
|
proc testTwoTorsion() =
|
||||||
|
var two_torsion: EC
|
||||||
|
|
||||||
|
# Setting the two torsion point
|
||||||
|
two_torsion.x.setZero()
|
||||||
|
two_torsion.y.setMinusOne()
|
||||||
|
two_torsion.z.setOne()
|
||||||
|
|
||||||
|
var point{.noInit.}: EC
|
||||||
|
point.fromAffine(generator)
|
||||||
|
|
||||||
|
for i in 0 ..< 1000:
|
||||||
|
var point_plus_torsion: EC
|
||||||
|
point_plus_torsion.sum(point, two_torsion) # adding generator with two torsion point
|
||||||
|
|
||||||
|
doAssert (point == point_plus_torsion).bool(), "points that differ by an order-2 point should be equal"
|
||||||
|
|
||||||
|
# Serializing to the point and point added with two torsion point
|
||||||
|
var point_bytes: Bytes
|
||||||
|
let stat1 = point_bytes.serialize(point)
|
||||||
|
var plus_point_bytes: Bytes
|
||||||
|
let stat2 = plus_point_bytes.serialize(point_plus_torsion)
|
||||||
|
|
||||||
|
doAssert stat1 == cttCodecEcc_Success and stat2 == cttCodecEcc_Success, "Serialization Failed"
|
||||||
|
doAssert plus_point_bytes == point_bytes, "points that differ by an order-2 point should produce the same bit string"
|
||||||
|
|
||||||
|
point.double()
|
||||||
|
|
||||||
|
testTwoTorsion()
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user