Implement Jacobian mixed addition (#142)
This commit is contained in:
parent
b91ec1cb15
commit
d12d5faf21
|
@ -48,6 +48,7 @@ proc main() =
|
|||
addBench(ECP_ShortW_Proj[Fp[curve], NotOnTwist], Iters)
|
||||
addBench(ECP_ShortW_Jac[Fp[curve], NotOnTwist], Iters)
|
||||
mixedAddBench(ECP_ShortW_Proj[Fp[curve], NotOnTwist], Iters)
|
||||
mixedAddBench(ECP_ShortW_Jac[Fp[curve], NotOnTwist], Iters)
|
||||
doublingBench(ECP_ShortW_Proj[Fp[curve], NotOnTwist], Iters)
|
||||
doublingBench(ECP_ShortW_Jac[Fp[curve], NotOnTwist], Iters)
|
||||
separator()
|
||||
|
|
|
@ -49,6 +49,7 @@ proc main() =
|
|||
addBench(ECP_ShortW_Proj[Fp2[curve], OnTwist], Iters)
|
||||
addBench(ECP_ShortW_Jac[Fp2[curve], OnTwist], Iters)
|
||||
mixedAddBench(ECP_ShortW_Proj[Fp2[curve], OnTwist], Iters)
|
||||
mixedAddBench(ECP_ShortW_Jac[Fp2[curve], OnTwist], Iters)
|
||||
doublingBench(ECP_ShortW_Proj[Fp2[curve], OnTwist], Iters)
|
||||
doublingBench(ECP_ShortW_Jac[Fp2[curve], OnTwist], Iters)
|
||||
separator()
|
||||
|
|
|
@ -17,7 +17,11 @@ import
|
|||
../constantine/config/[curves, common],
|
||||
../constantine/arithmetic,
|
||||
../constantine/io/io_bigints,
|
||||
../constantine/elliptic/[ec_shortweierstrass_affine, ec_shortweierstrass_projective, ec_scalar_mul, ec_endomorphism_accel],
|
||||
../constantine/elliptic/[
|
||||
ec_shortweierstrass_affine,
|
||||
ec_shortweierstrass_projective,
|
||||
ec_shortweierstrass_jacobian,
|
||||
ec_scalar_mul, ec_endomorphism_accel],
|
||||
# Helpers
|
||||
../helpers/[prng_unsafe, static_for],
|
||||
./platforms,
|
||||
|
@ -64,7 +68,10 @@ proc mixedAddBench*(T: typedesc, iters: int) =
|
|||
let P = rng.random_unsafe(T)
|
||||
let Q = rng.random_unsafe(T)
|
||||
var Qaff: ECP_ShortW_Aff[T.F, T.Tw]
|
||||
Qaff.affineFromProjective(Q)
|
||||
when Q is ECP_ShortW_Proj:
|
||||
Qaff.affineFromProjective(Q)
|
||||
else:
|
||||
Qaff.affineFromJacobian(Q)
|
||||
bench("EC Mixed Addition " & G1_or_G2, T, iters):
|
||||
r.madd(P, Qaff)
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ const testDesc: seq[tuple[path: string, useGMP: bool]] = @[
|
|||
# ("tests/t_ec_shortw_jac_g1_mul_sanity.nim", false),
|
||||
# ("tests/t_ec_shortw_jac_g1_mul_distri.nim", false),
|
||||
("tests/t_ec_shortw_jac_g1_mul_vs_ref.nim", false),
|
||||
# mixed_add
|
||||
("tests/t_ec_shortw_jac_g1_mixed_add.nim", false),
|
||||
|
||||
# Elliptic curve arithmetic G2
|
||||
# ----------------------------------------------------------
|
||||
|
@ -107,25 +107,25 @@ const testDesc: seq[tuple[path: string, useGMP: bool]] = @[
|
|||
# ("tests/t_ec_shortw_jac_g2_mul_sanity_bn254_snarks.nim", false),
|
||||
# ("tests/t_ec_shortw_jac_g2_mul_distri_bn254_snarks.nim", false),
|
||||
("tests/t_ec_shortw_jac_g2_mul_vs_ref_bn254_snarks.nim", false),
|
||||
# mixed_add
|
||||
("tests/t_ec_shortw_jac_g2_mixed_add_bn254_snarks.nim", false),
|
||||
|
||||
# ("tests/t_ec_shortw_jac_g2_add_double_bls12_381.nim", false),
|
||||
# ("tests/t_ec_shortw_jac_g2_mul_sanity_bls12_381.nim", false),
|
||||
# ("tests/t_ec_shortw_jac_g2_mul_distri_bls12_381.nim", false),
|
||||
("tests/t_ec_shortw_jac_g2_mul_vs_ref_bls12_381.nim", false),
|
||||
# mixed_add
|
||||
("tests/t_ec_shortw_jac_g2_mixed_add_bls12_381.nim", false),
|
||||
|
||||
# ("tests/t_ec_shortw_jac_g2_add_double_bls12_377.nim", false),
|
||||
# ("tests/t_ec_shortw_jac_g2_mul_sanity_bls12_377.nim", false),
|
||||
# ("tests/t_ec_shortw_jac_g2_mul_distri_bls12_377.nim", false),
|
||||
("tests/t_ec_shortw_jac_g2_mul_vs_ref_bls12_377.nim", false),
|
||||
# mixed_add
|
||||
("tests/t_ec_shortw_jac_g2_mixed_add_bls12_377.nim", false),
|
||||
|
||||
# ("tests/t_ec_shortw_jac_g2_add_double_bw6_761.nim", false),
|
||||
# ("tests/t_ec_shortw_jac_g2_mul_sanity_bw6_761.nim", false),
|
||||
# ("tests/t_ec_shortw_jac_g2_mul_distri_bw6_761.nim", false),
|
||||
("tests/t_ec_shortw_jac_g2_mul_vs_ref_bw6_761.nim", false),
|
||||
# mixed_add
|
||||
("tests/t_ec_shortw_jac_g2_mixed_add_bw6_761.nim", false),
|
||||
|
||||
# Elliptic curve arithmetic vs Sagemath
|
||||
# ----------------------------------------------------------
|
||||
|
|
|
@ -63,13 +63,14 @@ when UseASM_X86_64:
|
|||
|
||||
func setZero*(a: var Limbs) =
|
||||
## Set ``a`` to 0
|
||||
zeroMem(a[0].addr, sizeof(a))
|
||||
for i in 0 ..< a.len:
|
||||
a[i] = Zero
|
||||
|
||||
func setOne*(a: var Limbs) =
|
||||
## Set ``a`` to 1
|
||||
a[0] = One
|
||||
when a.len > 1:
|
||||
zeroMem(a[1].addr, (a.len - 1) * sizeof(SecretWord))
|
||||
for i in 1 ..< a.len:
|
||||
a[i] = Zero
|
||||
|
||||
func setUint*(a: var Limbs, n: SomeUnsignedInt) =
|
||||
## set ``a`` to an unsigned integer ``n``
|
||||
|
|
|
@ -32,6 +32,16 @@ type
|
|||
## over a field F
|
||||
x*, y*: F
|
||||
|
||||
func isInf*(P: ECP_ShortW_Aff): SecretBool =
|
||||
## Returns true if P is an infinity point
|
||||
## and false otherwise
|
||||
##
|
||||
## Note: the jacobian coordinates equation is
|
||||
## Y² = X³ + aXZ⁴ + bZ⁶
|
||||
## A "zero" point is any point with coordinates X and Z = 0
|
||||
## Y can be anything
|
||||
result = P.x.isZero() and P.y.isZero()
|
||||
|
||||
func curve_eq_rhs*[F](y2: var F, x: F, Tw: static Twisted) =
|
||||
## Compute the curve equation right-hand-side from field element `x`
|
||||
## i.e. `y²` in `y² = x³ + a x + b`
|
||||
|
|
|
@ -291,6 +291,85 @@ func sum*[F; Tw: static Twisted](
|
|||
r.ccopy(Q, P.isInf())
|
||||
r.ccopy(P, Q.isInf())
|
||||
|
||||
func madd*[F; Tw: static Twisted](
|
||||
r: var ECP_ShortW_Jac[F, Tw],
|
||||
P: ECP_ShortW_Jac[F, Tw],
|
||||
Q: ECP_ShortW_Aff[F, Tw]
|
||||
) =
|
||||
## Elliptic curve mixed addition for Short Weierstrass curves
|
||||
## with p in Jacobian coordinates and Q in affine coordinates
|
||||
##
|
||||
## R = P + Q
|
||||
# "madd-2007-bl" mixed addition formula - https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl
|
||||
# with conditional copies to handle infinity points
|
||||
# Assumptions: Z2=1.
|
||||
# Cost: 7M + 4S + 9add + 3*2 + 1*4.
|
||||
# Source: 2007 Bernstein–Lange.
|
||||
# Explicit formulas:
|
||||
#
|
||||
# Z1Z1 = Z1²
|
||||
# U2 = X2*Z1Z1
|
||||
# S2 = Y2*Z1*Z1Z1
|
||||
# H = U2-X1
|
||||
# HH = H2
|
||||
# I = 4*HH
|
||||
# J = H*I
|
||||
# r = 2*(S2-Y1)
|
||||
# V = X1*I
|
||||
# X3 = r²-J-2*V
|
||||
# Y3 = r*(V-X3)-2*Y1*J
|
||||
# Z3 = (Z1+H)²-Z1Z1-HH
|
||||
var Z1Z1 {.noInit.}, H {.noInit.}, HH {.noInit.}, I{.noInit.}, J {.noInit.}: F
|
||||
|
||||
# Preload P and Q in cache
|
||||
let pIsInf = P.isInf()
|
||||
let qIsInf = Q.isInf()
|
||||
|
||||
Z1Z1.square(P.z) # Z₁Z₁ = Z₁²
|
||||
r.z.prod(P.z, Z1Z1) # P.Z is hot in cache, keep it in same register.
|
||||
r.z *= Q.y # S₂ = Y₂Z₁Z₁Z₁ -- r.z used as S₂
|
||||
|
||||
H.prod(Q.x, Z1Z1) # U₂ = X₂Z₁Z₁
|
||||
H -= P.x # H = U₂ - X₁
|
||||
|
||||
HH.square(H) # HH = H²
|
||||
|
||||
I.double(HH)
|
||||
I.double() # I = 4HH
|
||||
|
||||
J.prod(H, I) # J = H*I
|
||||
r.y.prod(P.x, I) # V = X₁*I -- r.y used as V
|
||||
|
||||
r.z -= P.y #
|
||||
r.z.double() # r = 2*(S₂-Y₁) -- r.z used as r
|
||||
|
||||
r.x.square(r.z) # r²
|
||||
r.x -= J
|
||||
r.x -= r.y
|
||||
r.x -= r.y # X₃ = r²-J-2*V -- r.x computed
|
||||
|
||||
r.y -= r.x # V-X₃
|
||||
r.y *= r.z # r*(V-X₃)
|
||||
|
||||
J *= P.y # Y₁J -- J reused as Y₁J
|
||||
r.y -= J
|
||||
r.y -= J # Y₃ = r*(V-X₃) - 2*Y₁J -- r.y computed
|
||||
|
||||
r.z.sum(P.z, H) # Z₁ + H
|
||||
r.z.square()
|
||||
r.z -= Z1Z1
|
||||
r.z -= HH # Z₃ = (Z1+H)²-Z1Z1-HH
|
||||
|
||||
# Now handle points at infinity
|
||||
proc one(): F =
|
||||
result.setOne()
|
||||
|
||||
r.x.ccopy(Q.x, pIsInf)
|
||||
r.y.ccopy(Q.y, pIsInf)
|
||||
r.z.ccopy(static(one()), pIsInf)
|
||||
|
||||
r.ccopy(P, qIsInf)
|
||||
|
||||
func double*[F; Tw: static Twisted](
|
||||
r: var ECP_ShortW_Jac[F, Tw],
|
||||
P: ECP_ShortW_Jac[F, Tw]
|
||||
|
@ -373,13 +452,13 @@ func diff*(r: var ECP_ShortW_Jac,
|
|||
func affineFromJacobian*[F; Tw](
|
||||
aff: var ECP_ShortW_Aff[F, Tw],
|
||||
jac: ECP_ShortW_Jac[F, Tw]) =
|
||||
var invZ {.noInit.}, invZ2: F
|
||||
var invZ {.noInit.}, invZ2{.noInit.}: F
|
||||
invZ.inv(jac.z)
|
||||
invZ2.square(invZ)
|
||||
|
||||
aff.x.prod(jac.x, invZ2)
|
||||
aff.y.prod(jac.y, invZ)
|
||||
aff.y.prod(jac.y, invZ2)
|
||||
aff.y *= invZ2
|
||||
|
||||
func jacobianFromAffine*[F; Tw](
|
||||
jac: var ECP_ShortW_Jac[F, Tw],
|
||||
|
|
|
@ -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
|
||||
# Internals
|
||||
../constantine/config/curves,
|
||||
../constantine/elliptic/ec_shortweierstrass_jacobian,
|
||||
../constantine/arithmetic,
|
||||
# Test utilities
|
||||
./t_ec_template
|
||||
|
||||
const
|
||||
Iters = 12
|
||||
|
||||
run_EC_mixed_add_impl(
|
||||
ec = ECP_ShortW_Jac[Fp[BN254_Snarks], NotOnTwist],
|
||||
Iters = Iters,
|
||||
moduleName = "test_ec_shortweierstrass_jacobian_mixed_add_" & $BN254_Snarks
|
||||
)
|
||||
|
||||
run_EC_mixed_add_impl(
|
||||
ec = ECP_ShortW_Jac[Fp[BLS12_381], NotOnTwist],
|
||||
Iters = Iters,
|
||||
moduleName = "test_ec_shortweierstrass_jacobian_mixed_add_" & $BLS12_381
|
||||
)
|
||||
|
||||
run_EC_mixed_add_impl(
|
||||
ec = ECP_ShortW_Jac[Fp[BLS12_377], NotOnTwist],
|
||||
Iters = Iters,
|
||||
moduleName = "test_ec_shortweierstrass_jacobian_mixed_add_" & $BLS12_377
|
||||
)
|
||||
|
||||
run_EC_mixed_add_impl(
|
||||
ec = ECP_ShortW_Jac[Fp[BW6_761], NotOnTwist],
|
||||
Iters = Iters,
|
||||
moduleName = "test_ec_shortweierstrass_jacobian_mixed_add_" & $BW6_761
|
||||
)
|
|
@ -441,7 +441,10 @@ proc run_EC_mixed_add_impl*(
|
|||
let a = rng.random_point(EC, randZ, gen)
|
||||
let b = rng.random_point(EC, randZ, gen)
|
||||
var bAff: ECP_ShortW_Aff[EC.F, EC.Tw]
|
||||
bAff.affineFromProjective(b)
|
||||
when b is ECP_ShortW_Proj:
|
||||
bAff.affineFromProjective(b)
|
||||
else:
|
||||
bAff.affineFromJacobian(b)
|
||||
|
||||
var r_generic, r_mixed: EC
|
||||
|
||||
|
|
Loading…
Reference in New Issue