// Elliptic curve operations (Short Weierstrass Jacobian form)
#define POINT_ZERO ((POINT_jacobian){FIELD_ZERO, FIELD_ONE, FIELD_ZERO})
typedef struct {
FIELD x FIELD y} POINT_affine
typedef struct {
FIELD x FIELD y FIELD z} POINT_jacobian
// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
DEVICE POINT_jacobian POINT_double(POINT_jacobian inp) {
const FIELD local_zero = FIELD_ZERO if(FIELD_eq(inp.z, local_zero)) {
return inp }
const FIELD a = FIELD_sqr(inp.x) const FIELD b = FIELD_sqr(inp.y) FIELD c = FIELD_sqr(b)
// D = 2*((X1+B)2-A-C)
FIELD d = FIELD_add(inp.x, b) d = FIELD_sqr(d)
const FIELD e = FIELD_add(FIELD_double(a), a) const FIELD f = FIELD_sqr(e)
inp.z = FIELD_mul(inp.y, inp.z) inp.x = FIELD_sub(FIELD_sub(f, d), d)
// Y3 = E*(D-X3)-8*C
c = FIELD_double(c) inp.y = FIELD_sub(FIELD_mul(FIELD_sub(d, inp.x), e), c)
return inp}
// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl
DEVICE POINT_jacobian POINT_add_mixed(POINT_jacobian a, POINT_affine b) {
const FIELD local_zero = FIELD_ZERO if(FIELD_eq(a.z, local_zero)) {
const FIELD local_one = FIELD_ONE a.x = b.x a.y = b.y a.z = local_one return a }
const FIELD z1z1 = FIELD_sqr(a.z) const FIELD u2 = FIELD_mul(b.x, z1z1) const FIELD s2 = FIELD_mul(FIELD_mul(b.y, a.z), z1z1)
if(FIELD_eq(a.x, u2) && FIELD_eq(a.y, s2)) {
return POINT_double(a) }
const FIELD h = FIELD_sub(u2, a.x) const FIELD hh = FIELD_sqr(h) FIELD i = FIELD_double(hh) FIELD j = FIELD_mul(h, i) FIELD r = FIELD_sub(s2, a.y) const FIELD v = FIELD_mul(a.x, i)
POINT_jacobian ret
// X3 = r^2 - J - 2*V
ret.x = FIELD_sub(FIELD_sub(FIELD_sqr(r), j), FIELD_double(v))
// Y3 = r*(V-X3)-2*Y1*J
j = FIELD_mul(a.y, j) ret.y = FIELD_sub(FIELD_mul(FIELD_sub(v, ret.x), r), j)
// Z3 = (Z1+H)^2-Z1Z1-HH
ret.z = FIELD_add(a.z, h) return ret}
// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
DEVICE POINT_jacobian POINT_add(POINT_jacobian a, POINT_jacobian b) {
const FIELD local_zero = FIELD_ZERO if(FIELD_eq(a.z, local_zero)) return b if(FIELD_eq(b.z, local_zero)) return a
const FIELD z1z1 = FIELD_sqr(a.z) const FIELD z2z2 = FIELD_sqr(b.z) const FIELD u1 = FIELD_mul(a.x, z2z2) const FIELD u2 = FIELD_mul(b.x, z1z1) FIELD s1 = FIELD_mul(FIELD_mul(a.y, b.z), z2z2) const FIELD s2 = FIELD_mul(FIELD_mul(b.y, a.z), z1z1)
if(FIELD_eq(u1, u2) && FIELD_eq(s1, s2))
return POINT_double(a) else {
const FIELD h = FIELD_sub(u2, u1) FIELD i = FIELD_double(h) const FIELD j = FIELD_mul(h, i) FIELD r = FIELD_sub(s2, s1) const FIELD v = FIELD_mul(u1, i) a.x = FIELD_sub(FIELD_sub(FIELD_sub(FIELD_sqr(r), j), v), v)
// Y3 = r*(V - X3) - 2*S1*J
a.y = FIELD_mul(FIELD_sub(v, a.x), r) s1 = FIELD_mul(s1, j) a.y = FIELD_sub(a.y, s1)
// Z3 = ((Z1+Z2)^2 - Z1Z1 - Z2Z2)*H
a.z = FIELD_add(a.z, b.z) a.z = FIELD_sub(FIELD_sub(a.z, z1z1), z2z2) a.z = FIELD_mul(a.z, h)
return a }
}