EdDSA (and ed25519) signatures require a scalar multiplication. Currently, I do this directly in Twisted Edwards space. (The code can be found in my crypto library.) My research and my tests suggest it would be quite a bit faster to do that multiplication in Montgomery space instead. This would mean 4 steps:
- Convert the Twisted Edwards point to Montgomery space.
- Perform the Montgomery ladder.
- Recover the Y coordinate.
- Convert back to Twisted Edwards space.
Steps 1, 2, and 4 seem pretty simple (even straightforward). Step 3 is more complex, but is documented in this paper, which I have followed. Here is my attempt, which unfortunately gives the wrong result:
typedef i32 fe[10]
typedef struct { fe X; fe Y; fe Z; fe T; } ge;
sv ge_scalarmult(ge *p, const ge *q, const u8 scalar[32])
{
// convert q to montgomery format
fe x1, y1, z1, x2, z2, x3, z3, t1, t2, t3, t4;
fe_sub(z1, q->Z, q->Y); fe_mul(z1, z1, q->X); fe_invert(z1, z1);
fe_add(t1, q->Z, q->Y);
fe_mul(x1, q->X, t1 ); fe_mul(x1, x1, z1);
fe_mul(y1, q->Z, t1 ); fe_mul(y1, y1, z1);
fe_1(z1); // coherence
// montgomery scalarmult
// The same ladder is used for x25519,
// it comes from the ref10 implementation.
// Field elements are modified in-place
x25519_ladder(x1, x2, z2, x3, z3, scalar);
// recover the y1 coordinate
fe_mul(t1, x1, z2); // t1 = x1 * z2
fe_add(t2, x2, t1); // t2 = x2 + t1
fe_sub(t3, x2, t1); // t3 = x2 − t1
fe_sq (t3, t3); // t3 = t3^2
fe_mul(t3, t3, x3); // t3 = t3 * x3
fe_mul973324(t1, z2);// t1 = 2a * z2
fe_add(t2, t2, t1); // t2 = t2 + t1
fe_mul(t4, x1, x2); // t4 = x1 * x2
fe_add(t4, t4, z2); // t4 = t4 + z2
fe_mul(t2, t2, t4); // t2 = t2 * t4
fe_mul(t1, t1, z2); // t1 = t1 * z2
fe_sub(t2, t2, t1); // t2 = t2 − t1
fe_mul(t2, t2, z3); // t2 = t2 * z3
fe_add(t1, y1, y1); // t1 = y1 + y1
fe_mul(t1, t1, z2); // t1 = t1 * z2
fe_mul(t1, t1, z3); // t1 = t1 * z3
fe_mul(x1, t1, x2); // x1 = t1 * x2
fe_sub(y1, t2, t3); // y1 = t2 − t3
fe_mul(z1, t1, z2); // z1 = t1 * z2
// convert back to twisted edwards
fe_sub(t1 , x1, z1);
fe_add(t2 , x1, z1);
fe_mul(p->X, x1, t2);
fe_mul(p->Y, y1, t1);
fe_mul(p->Z, y1, t2);
fe_mul(p->T, x1, t1);
}
Can someone tell me what I did wrong?