Converting Ed25519 public key to a Curve25519 public key I understand that:

$$x_{montgomery} = \frac{1 + y_{edwards}}{1 - y_{edwards}}$$

Using the libsodium ed25519 implementation, I have tried to write the following:

void keypair_2(unsigned char *pk, unsigned char *sk)
{
    ge_p3 A;
    int i;

    sk[0] &amp;= 248;
    sk[31] &amp;= 63;
    sk[31] |= 64;

    ge_scalarmult_base(&amp;A,sk); // generate ed25519 public from sk.

    fe one;
    fe u, v, vinv;
    fe montx;
    fe_1(one);
    fe_sub(v, one, A.Y); //v = 1-y
    fe_add(u, A.Y, one); //u = y+1
    fe_invert(vinv, v); //vinv = v^(-1) = (1-y)^(-1)
    fe_mul(montx, u, vinv); //montx = u/v = (y+1)/(1-y)
    fe_tobytes(pk, montx);
}


And I have compared this against the curve25519 implementation, but I am getting differing results.

I am unsure as to my error.
ge_scalarmult_base returns GroupElementP3 which doesn't have (x, y) as members. It has X, Y, Z from which you can compute x = X / Z and y = Y / Z.

So you have two choices:


Compress the point with ge_tobytes:

byte[32] Abytes;
fe y;

ge_scalarmult_base(&amp;A,sk);

ge_tobytes(Abytes, &amp;A);
fe_frombytes(&amp;y, Abytes);

// your code here using `y` instead of `A.Y`


The downside of this technique is that it costs two field inversions. So I'd only use it if the input is a compressed point.
Modify the formula to work with X, Y, Z coordinates:

$$x_{mont} = \frac{1+y_{ed}}{1-y_{ed}} = \frac{1+\frac{Y}{Z}}{1-\frac{Y}{Z}} = \frac{Z+Y}{Z-Y}$$

fe_sub(v, A.Z, A.Y); //v = Z - Y
fe_add(u, A.Y, A.Z); //u = Z + Y


This solution is preferable if you just computed the point without having reduced yet. Typically directly after a scalar multiplication.