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

Bandersnatch/banderwagon endomorphism acceleration #380

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

mratsim
Copy link
Owner

@mratsim mratsim commented May 8, 2024

This implements:

  • endomorphism acceleration support for Twisted Edwards curves
  • endomorphism acceleration for Bandersnatch and Banderwagon
  • benchmarks for scalar multiplication and MSM

Departures from the generic derivation

λ

The endomorphism is equivalent to a scalar multiplication by a solution of λ² = -2.
There are 2 such solutions and for a generic implementation we should try
to ensure which of λ₀ = √-2 and λ₁ = -√-2 corresponds to the computation at

func computeEndoBander[F](r {.noalias.}: var ECP_TwEdwards_Prj[F], P: ECP_TwEdwards_Prj[F]) =
static: doAssert F.C in {Bandersnatch, Banderwagon}
var xy {.noInit.}, yy {.noInit.}, zz {.noInit.}: F
xy.prod(P.x, P.y)
yy.square(P.y)
zz.square(P.z)
const b = F.fromHex("0x52c9f28b828426a561f00d3a63511a882ea712770d9af4d6ee0f014d172510b4")
const c = F.fromHex("0x6cc624cf865457c3a97c6efd6c17d1078456abcfff36f4e9515c806cdf650b3d")
r.x.diff(zz, yy)
r.x *= c
zz *= b
r.y.sum(yy, zz)
r.y *= b
r.z.diff(yy, zz)
r.x *= r.z
r.y *= xy
r.z *= xy

This is what is done for cubic root endomorphisms:

try:
check_cubic_root_endo(G1, Fp, r, cofactor, int(lambda1), phi1)
except:
print('Failure with:')
print(' 𝜑 (mod p): 0x' + Integer(phi1).hex())
print(' λᵩ (mod r): 0x' + Integer(lambda1).hex())
phi1, phi2 = phi2, phi1
check_cubic_root_endo(G1, Fp, r, cofactor, int(lambda1), phi1)
finally:
print('Success with:')
print(' 𝜑 (mod p): 0x' + Integer(phi1).hex())
print(' λᵩ (mod r): 0x' + Integer(lambda1).hex())

def check_cubic_root_endo(G1, Fp, r, cofactor, lambdaR, phiP):
## Check the Endomorphism for p mod 3 == 1
## Endomorphism can be field multiplication by one of the non-trivial cube root of unity 𝜑
## Rationale:
## curve equation is y² = x³ + b, and y² = (x𝜑)³ + b <=> y² = x³ + b (with 𝜑³ == 1) so we are still on the curve
## this means that multiplying by 𝜑 the x-coordinate is equivalent to a scalar multiplication by some λᵩ
## with λᵩ² + λᵩ + 1 ≡ 0 (mod r) and 𝜑² + 𝜑 + 1 ≡ 0 (mod p), see below.
## Hence we have a 2 dimensional decomposition of the scalar multiplication
## i.e. For any [s]P, we can find a corresponding [k1]P + [k2][λᵩ]P with [λᵩ]P being a simple field multiplication by 𝜑
## Finding cube roots:
## x³−1=0 <=> (x−1)(x²+x+1) = 0, if x != 1, x solves (x²+x+1) = 0 <=> x = (-1±√3)/2
assert phiP^3 == Fp(1)
assert lambdaR^3 % r == 1
Prand = G1.random_point()
P = Prand * cofactor
assert P != G1([0, 1, 0])
(Px, Py, Pz) = P
Qendo = G1([Px*phiP, Py, Pz])
Qlambda = lambdaR * P
assert P != Qendo
assert P != Qlambda
assert Qendo == Qlambda
print('Endomorphism OK')

However, SageMath has no builtin support for Edwards curves so we would would need to reimplement scalar multiplication to do these checks. Hence we hardcode the λ from the paper.

Lattice decomposition

The lattice decomposition also follows the reference implementation, i.e. instead of

def derive_lattice(r, lambdaR, m):
lat = Matrix(matrix.identity(m))
lat[0, 0] = r
for i in range(1, m):
lat[i, 0] = -lambdaR^i
return lat.LLL()

we do https://github.com/asanso/Bandersnatch/blob/e280929/python-ref-impl/bandersnatch.py#L20-L21

        M = Matrix([[-L,1], [r,0]])
        self.N = M.LLL()

This only moves signs around.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Bandersnatch / Banderwagon endomorphism acceleration
1 participant