Add elliptic doubling in projective coordinates

This commit is contained in:
Mamy André-Ratsimbazafy 2020-04-15 22:23:46 +02:00
parent f7818b566b
commit 44350d08af
No known key found for this signature in database
GPG Key ID: 7B88AD1FE79492E1
4 changed files with 118 additions and 7 deletions

View File

@ -49,6 +49,8 @@ proc main() =
const curve = AvailableCurves[i]
addBench(ECP_SWei_Proj[Fp[curve]], Iters)
separator()
doublingBench(ECP_SWei_Proj[Fp[curve]], Iters)
separator()
main()

View File

@ -98,7 +98,13 @@ template bench(op: string, T: typedesc, iters: int, body: untyped): untyped =
proc addBench*(T: typedesc, iters: int) =
var r {.noInit.}: T
let x = rng.random_unsafe(T)
let y = rng.random_unsafe(T)
let P = rng.random_unsafe(T)
let Q = rng.random_unsafe(T)
bench("EC Add G1", T, iters):
r.sum(x, y)
r.sum(P, Q)
proc doublingBench*(T: typedesc, iters: int) =
var r {.noInit.}: T
let P = rng.random_unsafe(T)
bench("EC Double G1", T, iters):
r.double(P)

View File

@ -105,6 +105,9 @@ func sum*[F](
P, Q: ECP_SWei_Proj[F]
) =
## Elliptic curve point addition for Short Weierstrass curves in projective coordinate
##
## R = P + Q
##
## Short Weierstrass curves have the following equation in projective coordinates
## Y²Z = X³ + aXZ² + bZ³
## from the affine equation
@ -121,8 +124,8 @@ func sum*[F](
#
# Implementation:
# Algorithms 1 (generic case), 4 (a == -3), 7 (a == 0) of
# Complete addition formulas for prime order elliptic curves\
# Joost Renes and Craig Costello and Lejla Batina, 2015\
# Complete addition formulas for prime order elliptic curves
# Joost Renes and Craig Costello and Lejla Batina, 2015
# https://eprint.iacr.org/2015/1060
#
# with the indices 1 corresponding to ``P``, 2 to ``Q`` and 3 to the result ``r``
@ -132,14 +135,18 @@ func sum*[F](
# Y3 = (3 X1 X2 + a Z1 Z2)(a X1 X2 + 3b (X1 Z2 + X2 Z1) - a² Z1 Z2)
# + (Y1 Y2 + a (X1 Z2 + X2 Z1) + 3b Z1 Z2)(Y1 Y2 - a(X1 Z2 + X2 Z1) - 3b Z1 Z2)
# Z3 = (Y1 Z2 + Y2 Z1)(Y1 Y2 + a(X1 Z2 + X2 Z1) + 3b Z1 Z2) + (X1 Y2 + X2 Y1)(3 X1 X2 + a Z1 Z2)
#
# Cost: 12M + 3 mul(a) + 2 mul(3b) + 23 a
# TODO: static doAssert odd order
when F.C.getCoefA() == 0:
var t0 {.noInit.}, t1 {.noInit.}, t2 {.noInit.}, t3 {.noInit.}, t4 {.noInit.}: F
const b3 = 3 * F.C.getCoefB()
when F.C.getCoefA() == 0:
# Algorithm 7 for curves: y² = x³ + b
# 12M + 2 mul(3b) + 19A
#
# X3 = (X1 Y2 + X2 Y1)(Y1 Y2 3b Z1 Z2)
# 3b(Y1 Z2 + Y2 Z1)(X1 Z2 + X2 Z1)
# Y3 = (Y1 Y2 + 3b Z1 Z2)(Y1 Y2 3b Z1 Z2)
@ -191,3 +198,70 @@ func sum*[F](
r.z += t0 # 33. Z3 <- Z3 + t0 Z3 = (Y1 Z2 + Y2 Z1)(Y1 Y2 + 3b Z1 Z2) + 3 X1 X2 (X1.Y2 + X2.Y1)
else:
{.error: "Not implemented.".}
func double*[F](
r: var ECP_SWei_Proj[F],
P: ECP_SWei_Proj[F]
) =
## Elliptic curve point doubling for Short Weierstrass curves in projective coordinate
##
## R = [2] P
##
## Short Weierstrass curves have the following equation in projective coordinates
## Y²Z = X³ + aXZ² + bZ³
## from the affine equation
## y² = x³ + a x + b
##
## ``r`` is initialized/overwritten with the sum
##
## Implementation is constant-time, in particular it will not expose
## that `P` is an infinity point.
## This is done by using a "complete" or "exception-free" addition law.
##
## This requires the order of the curve to be odd
#
# Implementation:
# Algorithms 3 (generic case), 6 (a == -3), 9 (a == 0) of
# Complete addition formulas for prime order elliptic curves
# Joost Renes and Craig Costello and Lejla Batina, 2015
# https://eprint.iacr.org/2015/1060
#
# X3 = 2XY (Y² - 2aXZ - 3bZ²)
# - 2YZ (aX² + 6bXZ - a²Z²)
# Y3 = (Y² + 2aXZ + 3bZ²)(Y² - 2aXZ - 3bZ²)
# + (3X² + aZ²)(aX² + 6bXZ - a²Z²)
# Z3 = 8Y³Z
#
# Cost: 8M + 3S + 3 mul(a) + 2 mul(3b) + 15a
when F.C.getCoefA() == 0:
var t0 {.noInit.}, t1 {.noInit.}, t2 {.noInit.}: F
const b3 = 3 * F.C.getCoefB()
# Algorithm 9 for curves:
# 6M + 2S + 1 mul(3b) + 9a
#
# X3 = 2XY(Y² - 9bZ²)
# Y3 = (Y² - 9bZ²)(Y² + 3bZ²) + 24bY²Z²
# Z3 = 8Y³Z
t0.square(P.y) # 1. t0 <- Y Y
r.z.double(t0) # 2. Z3 <- t0 + t0
r.z.double() # 3. Z3 <- Z3 + Z3
r.z.double() # 4. Z3 <- Z3 + Z3 Z3 = 8Y²
t1.prod(P.y, P.z) # 5. t1 <- Y Z
t2.square(P.z) # 6. t2 <- Z Z
t2 *= b3 # 7. t2 <- b3 t2
r.x.prod(t2, r.z) # 8. X3 <- t2 Z3
r.y.sum(t0, t2) # 9. Y3 <- t0 + t2
r.z *= t1 # 10. Z3 <- t1 Z3
t1.double(t2) # 11. t1 <- t2 + t2
t2 += t1 # 12. t2 <- t1 + t2
t0 -= t2 # 13. t0 <- t0 - t2
r.y *= t0 # 14. Y3 <- t0 Y3
r.y += r.x # 15. Y3 <- X3 + Y3
t1.prod(P.x, P.y) # 16. t1 <- X Y
r.x.prod(t0, t1) # 17. X3 <- t0 t1
r.x.double() # 18. X3 <- X3 + X3
else:
{.error: "Not implemented.".}

View File

@ -50,6 +50,9 @@ suite "Elliptic curve in Short Weierstrass form y² = x³ + a x + b with project
r.sum(inf, P)
check: bool(r == P)
test(Fp[BN254_Snarks], randZ = false)
test(Fp[BN254_Snarks], randZ = true)
test(Fp[BLS12_381], randZ = false)
test(Fp[BLS12_381], randZ = true)
@ -70,6 +73,8 @@ suite "Elliptic curve in Short Weierstrass form y² = x³ + a x + b with project
r.sum(Q, P)
check: bool r.isInf()
test(Fp[BN254_Snarks], randZ = false)
test(Fp[BN254_Snarks], randZ = true)
test(Fp[BLS12_381], randZ = false)
test(Fp[BLS12_381], randZ = true)
@ -88,6 +93,8 @@ suite "Elliptic curve in Short Weierstrass form y² = x³ + a x + b with project
r1.sum(Q, P)
check: bool(r0 == r1)
test(Fp[BN254_Snarks], randZ = false)
test(Fp[BN254_Snarks], randZ = true)
test(Fp[BLS12_381], randZ = false)
test(Fp[BLS12_381], randZ = true)
@ -138,5 +145,27 @@ suite "Elliptic curve in Short Weierstrass form y² = x³ + a x + b with project
bool(r0 == r3)
bool(r0 == r4)
test(Fp[BN254_Snarks], randZ = false)
test(Fp[BN254_Snarks], randZ = true)
test(Fp[BLS12_381], randZ = false)
test(Fp[BLS12_381], randZ = true)
test "EC double and EC add are consistent":
proc test(F: typedesc, randZ: static bool) =
for _ in 0 ..< Iters:
when randZ:
let a = rng.random_unsafe_with_randZ(ECP_SWei_Proj[F])
else:
let a = rng.random_unsafe(ECP_SWei_Proj[F])
var r0{.noInit.}, r1{.noInit.}: ECP_SWei_Proj[F]
r0.double(a)
r1.sum(a, a)
check: bool(r0 == r1)
test(Fp[BN254_Snarks], randZ = false)
test(Fp[BN254_Snarks], randZ = true)
test(Fp[BLS12_381], randZ = false)
test(Fp[BLS12_381], randZ = true)