# Where does Curve25519's limit occur?

While informing myself on the inner-working of Monero, I stumbled on Curve25519.

The CryptoNote White Paper states:

l: a prime order of the base point; l = 2^252 + 27742317777372353535851937790883648493;
[...]
private ec-key is a standard elliptic curve private key: a number a ∈ [1, l − 1];

Another Stack Exchange answer states the following:

All you need protocol-wise is a private spend key and a private view key, where a private key is just some number smaller than `l` where `l` is a prime order of the EC curve basepoint `l=2^252 + 27742317777372353535851937790883648493`. Anything bigger than that will get wrapped around ie `a` and `a+l` are equivalent.

From my understanding this means that a private key `a` has the same derived public key as private key `a+l`.

I've however been unable to reproduce the said "wrapping".

Using a very random `a=0x1111111111111111111111111111111111111111111111111111111111111111` I calculated `a+l=0x2111111111111111111111111111111125f00aefb408ade76923742b6e06e4fe`.

I then tried to use `a` and `a+l` on llcoins as Hexadecimal Seed, as Private Spend Key or as Private View Key. They never generated the same results.

Does the wrapping occurring on `a` ,when greater or equal to `l`, occur at another step? Does it only occur sometimes?

It will get wrapped around because it's later passed through sc_reduce32 function which performs `mod l` operation on the input.

See below example using silent Matt's big int library which is loaded with llcoins. Easiest to just open the developer tab and type stuff into JS console.

To calculate 2^252 + 27742317777372353535851937790883648493:

``````l = JSBigInt(2).pow(252).add(JSBigInt.parse("27742317777372353535851937790883648493",10));
``````

To print out the number in base16:

``````l.toString(16);
"1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED"
``````

That's the `l`. If you swap byes and feed it as seed to llcoins, you should get `0x0` as seed. Try inputting `EDD3F55C1A631258D69CF7A2DEF9DE1400000000000000000000000000000010` (little endian) as seed and you'll get `0000000000000000000000000000000000000000000000000000000000000000` as private key.

``````a = JSBigInt.parse("0x1111111111111111111111111111111111111111111111111111111111111111");
BigInteger {_d: Array(11), _s: 1}
BigInteger {_d: Array(11), _s: 1}
c.toString(16);
``````

Performing `mod l` will give you:

``````c.remainder(l).toString(16);
``````

observe how you don't get the value of `a` because `a` itself is bigger than `l`:

``````a.remainder(l).toString(16);
``````

so adding `l` to this will give you the original number:

``````a.remainder(l).add(l).toString(16);
"1111111111111111111111111111111111111111111111111111111111111111"
``````

If you swap endian of `c` and feed it as seed to llcoins, you'll get the same remainder but with little endian byte order:

`seed=FEE4066E2B742369E7AD08B4EF0AF02511111111111111111111111111111121`

`privSpend=243d1bb4f6adfeb83a74196e321732fc10111111111111111111111111111101`

• Add which step? I discovered that using the `a+l` as seed is the same as using the private key generated by `a+l` as seed. However this private key is not the `mod l` of `a+l`. Dec 27, 2017 at 23:00
• It should be. If you're doing it by other means, pay attention to byte endianness, though. Using your calc, `l=FFFFFFFFFFFFFFFFFFFFFFFF0BCA1161B7C687A4B21172333C8170C38FC05F0D`, `l+a=11111111111111111111111101cdb2272c8d798b5c32283444d9281d4a0d1701e` and `mod l = 1111111111111111111111111111111111111111111111111111111111111111`. Dec 27, 2017 at 23:15
• How did you find `l=FFFFFFFFFFFFFFFFFFFFFFFF0BCA1161B7C687A4B21172333C8170C38F‌​C05F0D`? When does the switch of endianness occur? Dec 28, 2017 at 13:12
• I used JS BigInt lib to play with this a while ago and computed hex value of l from whitepaper definition. See my code here: github.com/JollyMort/monero-wallet-generator/blob/master/… Dec 28, 2017 at 13:28
• Check my updated answer with some examples, I have no idea how I got the `FFFFFFFFFFFFFFFFFFFFFFFF0BCA1161B7C687A4B21172333C8170C38F‌​C05F0D`, must have messed up somewhere. The updated answer has correct values :) Dec 28, 2017 at 16:57