Ed25519 secret and public keys can both be represented in 32 bytes. Why does NaCl use 64 byte signing keys?


There are a few different standard forms for an Ed25519 secret key out of the following parts:

  1. A secret scalar $a \in \mathbb Z/\ell\mathbb Z$, where $\ell$ is the order of the standard base point.
  2. A PRF secret $h \in \{0,1\}^{256}$.
  3. A pre-master secret $k \in \{0,1\}^{256}$ from which $a$ and $h$ are derived by $\underline a \mathbin\Vert h = \operatorname{SHA512}(k)$. This is what RFC 8032 calls the ‘secret key’.
  4. A public point $A = [a]B \in E(\mathbb F_p)$, where $B$ is the standard base point.

Here $\underline a$ means the canonical encoding of $a$ in octets (or bits).

Creating a signature on a message $m$ requires computing \begin{align*} \underline r &= \operatorname{SHA512}(h \mathbin\Vert m), \\ R &= [r] B, \quad\text{and} \\ s &\equiv r + \operatorname{SHA512}(\underline R \mathbin\Vert \underline A \mathbin\Vert m)\,a \pmod \ell. \end{align*}

Given the 32-byte secret $k$ you can always compute the rest, but you may not want to derive $a$ from $k$ if you want hierarchical signatures: if you compute a derived secret scalar $a_t$ from a tweak $t$ then you have no hope of finding a $k$ that produces it. So a hierarchical signature scheme will store the 32-byte $\underline a$ and the 32-byte $h$ explicitly as a secret key.

Given $a$ you can always compute $A$, but that requires an additional scalar multiplication, so for performance of signing it is worthwhile to precompute that and store it in an additional 32 bytes. For example, a libsodium crypto_sign secret key is the 64-byte concatenation of the 32-byte secret $k$ called a ‘seed’ and the 32-byte public key $\underline A$.

And of course if you confuse two different 64-byte encodings of the same secret key, who knows what havoc you might wreak!

For crypto_box rather than crypto_sign, all you need is your secret scalar and your peer's public key—no PRF secret, and your public key doesn't figure into the boxing operation, only into the box-opening operation.


Opening and sealing a box involves your private scalar and the other party's public key. So the private key is simply the private scalar.

Signing with Ed25519 involves your private scalar and your public key (to strictly bind the signature to that key). Since computing the public key from the private scalar is expensive, NaCl chooses to store it as part of the private key.

An Ed25519 private key consists of a 32 byte seed (from which you can cheaply derive the 32 byte private scalar and the 32 byte hash prefix) and the 32 byte public key.

Different Ed25519 implementations chose different private key formats, Brian Warner's blog has the details.

  • 3
    $\begingroup$ Accidentally using the wrong public key would also have catastrophic implications. Keeping both keys together makes this situation less likely to happen. See github.com/jedisct1/libsodium/issues/170 for a discussion about this. $\endgroup$ – Frank Denis Dec 31 '17 at 11:50
  • $\begingroup$ What is the "32 byte hash prefix"? $\endgroup$ – knaccc Dec 31 '17 at 16:08

Your Answer

