# How is the edwards448 generator derived from the curve448 generator in RFC 7748?

In RFC 7748, it is explained how the Montgomery curve, curve448, is deterministically generated from the prime $$p = 2^{448} - 2^{224} - 1$$. It is also explained how the generator (given below) for curve448 is derived.

    U(P)  5

V(P)  355293926785568175264127502063783334808976399387714271831880898
435169088786967410002932673765864550910142774147268105838985595290
606362


RFC 7748 also defines the Edwards curve, edwards448, and states that there is an isogeny from curve448 to edwards448 (explicit transformations are defined for curve448 --> edwards448 and edwards448 --> curve448).

The following generator for edwards448 is given:

   X(P)  224580040295924300187604334099896036246789641632564134246125461
686950415467406032909029192869357953282578032075146446173674602635
247710

Y(P)  298819210078481492676017930443930673437544040154080242095928241
372331506189835876003536878655418784733982303233503462500531545062
832660


Can someone explain how X(P),Y(P) are computed from U(P),V(P)?

Plugging U(P),V(P) into the transformation curve448 --> edwards448 does not yield X(P),Y(P) (perhaps it yields some point in an equivalence class with X(P),Y(P) but I am not sure how to check that). However, if you plug X(P),Y(P) into the transformation edwards448 --> curve448, then you do get U(P),V(P).

In case it is helpful, the maps given in RFC 7748 are presented below as sage code:

p =  2^448 - 2^224 - 1

# edwards448 --> curve448
def getU(x,y):
u = mod(y^2/x^2, p)
return u

def getV(x,y):
v = mod((2 - x^2 - y^2)*y/x^3, p)
return v

# curve448 --> edwards448
def getX(u,v):
x = mod(4*v*(u^2 - 1)/(u^4 - 2*u^2 + 4*v^2 + 1), p)
return x

def getY(u,v):
y = mod(-(u^5 - 2*u^3 - 4*u*v^2 + u)/(u^5 - 2*u^2*v^2 - 2*u^3 - 2*v^2 + u), p)
return y

# edwards448 generator
Gx = 224580040295924300187604334099896036246789641632564134246125461686950415467406032909029192869357953282578032075146446173674602635247710
Gy = 298819210078481492676017930443930673437544040154080242095928241372331506189835876003536878655418784733982303233503462500531545062832660

# curve448 generator
Gu = 5
Gv = 355293926785568175264127502063783334808976399387714271831880898435169088786967410002932673765864550910142774147268105838985595290606362

• Did you check the errata? rfc-editor.org/errata/rfc7748 Sep 7 at 20:09
• yes, I did check the errata. There is no mention of this there. Sep 7 at 20:10
• Base points are mapped via the birational equivalence, not with the Isogenies Sep 7 at 20:18
• the birational map is defined between curve448 and an edwards curve slightly different from edwards448 (it has a different d value). I don't see how to use the birational map to go from curve448 to edwards448. Sep 7 at 20:25
• I read that paper previously. A different generator is defined there (i.e. it does not match up with RFC 7748). Sep 7 at 21:43

It doesn't work as you expect.

This is a 4 degree isogeny, not an isomorphism or a birational equivalence. One complete map $$toMonty(toEdwards(P))$$ will not get you to the starting point $$(P)$$, it will get you to $$4*P$$ due to the degree of the isogeny.

So, the map from $$x,y$$ to $$u,v$$ works as you expect because the point on edwards448 was specifically chosen to match, but the inverse map will move you to $$4*P$$ and not to $$P$$.

Here's the sage code that use your formulas to get the Edwards coordinate of $$4^{-1}G$$ that matches the point on Edwards

#define the Montgomery curve. Montgomery curves are natively supported in sage so better to use this instead of Edwards
p = 2^448-2^224-1
F = GF(p)
d = -39081
E = EllipticCurve(F,[0,2-4*d,0,1,0])
#define the base point on Montgomery
curve448_basepoint = E([5,355293926785568175264127502063783334808976399387714271831880898435169088786967410002932673765864550910142774147268105838985595290606362])

#define the order of the point

#Multiply the generator by 4^-1
P = curve448_basepoint*inverse_mod(4,order)

#now use your formulas to get the edwards coordinates
def getX(u,v):
x = 4*v*(u^2 - 1)/(u^4 - 2*u^2 + 4*v^2 + 1)
return x

def getY(u,v):
y = -(u^5 - 2*u^3 - 4*u*v^2 + u)/(u^5 - 2*u^2*v^2 - 2*u^3 - 2*v^2 + u)
return y

#and verify it matches the expected value (the point multiplied by 4)
assert getX(P.xy()[0],P.xy()[1])==224580040295924300187604334099896036246789641632564134246125461686950415467406032909029192869357953282578032075146446173674602635247710
assert getY(P.xy()[0],P.xy()[1])==298819210078481492676017930443930673437544040154080242095928241372331506189835876003536878655418784733982303233503462500531545062832660

• Great, curve enthusiast. Sep 8 at 16:06
• thank-you, Ruggero! Sep 8 at 17:46
• I wonder if it would be better to write $4^{-1} G$ rather than $-4 G$? Sep 8 at 19:01
• @user61836 Ruggero uses additive notation, not multiplication since, in general, we say point addition and scalar multiplication that is just adding $k$ time ( usually written as $[k]P$ ), and the addition comes from the lattices... Sep 8 at 23:56
• The standard notation is to write -4 G to indicate the point that is the additive inverse of 4 G in the ec group (so that -4 G + 4 G = id), but that is not what is meant here. I think writing 4^{-1} G would be clearer. Sep 9 at 0:15

The code below complements Ruggero's answer.

Ruggero explained that the given isogeny, curve448 --> edwards448, is a 4-isogeny, as is stated in RFC 7748.

When it is applied to a point on curve448, it returns 4 times a point on edwards448.

Ruggero's sage code shows that 4^{-1}*(Gu,Gv) maps to (Gx,Gy).

The code below shows that (Gu, Gv) maps to 4*(Gx,Gy):

p =  2**448 - 2**224 - 1
d = -39081
a = 1

def getX(u,v):
x = mod(4*v*(u^2 - 1)/(u^4 - 2*u^2 + 4*v^2 + 1), p)
return x

def getY(u,v):
y = mod(-(u^5 - 2*u^3 - 4*u*v^2 + u)/(u^5 - 2*u^2*v^2 - 2*u^3 - 2*v^2 + u), p)
return y

Gx = 224580040295924300187604334099896036246789641632564134246125461686950415467406032909029192869357953282578032075146446173674602635247710
Gy = 298819210078481492676017930443930673437544040154080242095928241372331506189835876003536878655418784733982303233503462500531545062832660

Gu = 5
Gv = 355293926785568175264127502063783334808976399387714271831880898435169088786967410002932673765864550910142774147268105838985595290606362