- elliptic-curves ed25519 libsodium x25519
- Updated Thu, 26 May 2022 23:09:07 GMT

I understand with `curve25519`

that the private key for `secret.box`

is clamped...

I understand that this clamping process to clear the **lower 3 bits** in order to ensure the key is a **multiple** of 8, ensuring it's part of the right cyclic subgroup.

However, as I generate example keyPairs using sodium such as:

```
a67e2d949d00606d2b6d0d9114d3ee273f118a078151c7aad2b55694ea18bb39 // 1010011001111110001011011001010010011101000000000110000001101101001010110110110100001101100100010001010011010011111011100010011100111111000100011000101000000111100000010101000111000111101010101101001010110101010101101001010011101010000110001011101100111001
```

or

```
b2c80def0dc392671e5143e9804c1083a39c751eec7348383eb586d708b374cc // 1011001011001000000011011110111100001101110000111001001001100111000111100101000101000011111010011000000001001100000100001000001110100011100111000111010100011110111011000111001101001000001110000011111010110101100001101101011100001000101100110111010011001100
```

I noticed that despite being able to positively confirm they are part of the multiple of 8 subgroup, their binary representation does **not** have the lower three bits cleared...

So as you can see above, the binary representation of these random private keys doesn't have `000`

for the lowest three bits. Yet when I check in SageMath, I can confirm both of these keys are multiples of 8.

**Update**:
I generated the keys using the libSodium->SecretBox->KeyPair()...

Which internally calls the clamping/scalar multiplication.

I also verified that despite not ending in three zeros `(000)`

- the private keys are always of order `7237005577332262213973186563042994240857116359379907606001950938285454250989`

and as such are of the correct subgroup.

Any idea why?

The clamping happens as part of the key agreement / signing procedure. The private key itself isn't clamped when stored.

(How did you test the numbers you have provided? None of them seem to be multiple of 8. Also recall that curve25519 keys are in little endian.)

- +0 – the keys seem to be always multiples of 8 though, and part of the right group, see updated question... I tested the numbers, by converting the hex to decimal, using Sage to multiply the decimal by the base point and testing the order of the point returned...so the generated keys seem to be clamped. — Nov 22, 2019 at 11:34
- +0 – Writing the curve order as $8n$ with $n$ prime; the base point has order $n$, so if you multiply it by some $k \neq 0 \bmod p$ the resulting point will also have order $n$. This does not imply that $k$ is a multiple of 8. The clamping protects ECDH when multiplying with some arbitrary point provided by the other party which may have order different than $n$. — Nov 22, 2019 at 11:41
- +1 – @FrankDenis thanks for the reply sir. So even though the clamped scalar is used to generate the public key point, libsodium stores the public key + Unclamped scalar in the Keypair object? — Nov 22, 2019 at 14:09
- +1 – @Woodstock yes, it's also done when computing the public key from the private, and anywhere the private key is used in a point multiplication. But the (unclamped) private key stored doesn't change. — Nov 22, 2019 at 15:42
- +1 – @Woodstock Correct. If you really don't want clampling to happen, this is still an option (
`crypto_scalarmult_ed25519_noclamp()`

and`crypto_scalarmult_ed25519_base_noclamp()`

), but these functions will check that the public key is on the main subgroup, which is slower than clamping. Using the Ristretto encoding may be a better option. — Nov 22, 2019 at 21:27