20
$\begingroup$

In an application, a curve25519 private key is the only stable identifier for an individual. I don't have readily have access to the corresponding public key.

Would it be safe to generate a public identifier by hashing this private key? E.g.

ID = argon2id(K_curve25519_private)
$\endgroup$
4
  • $\begingroup$ When you say you don't have access, do you mean you also don't have access to a function or library that would be able to calculate the public key? $\endgroup$ Commented Aug 28, 2023 at 0:44
  • 3
    $\begingroup$ Two things: First: Is argon2 actually considered to be a "hash" function (or is it a KDF (Key Derivation Function)? Second: If your application can access every user's private key, I wouldn't consider it to be a "private" key. $\endgroup$
    – U. Windl
    Commented Aug 28, 2023 at 9:29
  • $\begingroup$ @user3074620 Yes. I understood that the proper protocol was to derive the public key. In my environment, I didn't have access to this library function. Although, there was access to argon2 bindings. $\endgroup$ Commented Aug 29, 2023 at 1:29
  • $\begingroup$ @U.Windl This is client-side code. All the private keys are not in an online database. $\endgroup$ Commented Aug 29, 2023 at 1:30

3 Answers 3

37
$\begingroup$

Would it be safe to generate a public identifier by hashing this private key?

It depends on the hash.

If the hash is SHA-512 applied on the private key formatted as a 256-bit (32-byte) string, that's a security disaster, because in EdDSA on Curve25519 all operations involving the private key $k$ actually use some bits of $h=\operatorname{SHA-512}(k)$, thus the public identifier would allow to perform any calculation involving the private key in the context of EdDSA on Curve25519, including signature generation. Leak of even the first 8 bytes (out of 64) of $h$ would seriously harm security.

For other first-preimage-resistant standard hash, e.g. SHA-1, SHA-256, anything SHA-3, SHA-512/256, SHA-512 of a prefix and the private key, and any truncation of these, that's safe. Brute force attack on the hash is hopeless, thus using Argon2id is not even necessary if the private key is full-entropy (which is advisable).


As pointed in another answer, we can compute the public key from the private key, then build the identifier from the public key by some public method (it can e.g. be the public key itself, or a hash thereof). This is not equivalent to what the question proposes: it allows to link a public key to the identifier, which might be a feature or a drawback depending on application.

$\endgroup$
3
  • $\begingroup$ I guess hashing the key together with some application-specific label (maybe better in HMAC form) is safer here. $\endgroup$ Commented Aug 29, 2023 at 22:23
  • $\begingroup$ How much does it harm security if we loose 8 bits of 64 ? $\endgroup$ Commented Aug 30, 2023 at 0:54
  • $\begingroup$ @WillemD'Haeseleer: I think that when it's disclosed $n$ bits among bits $3…253$ of the SHA-512 hash, we loose $≈n/2$ bits of security out of $≈128$ against an attack recovering private key from public key by computing the discrete log. And independently, when it's disclosed $n$ bits among bits $256…511$ of the SHA-512 hash, we loose $n$ bits of security out of $≈256$ against another attack recovering private key from public key, a signature and the corresponding message, by guessing the key for generating the pseudorandom secret session key of the signature. $\endgroup$
    – fgrieu
    Commented Aug 30, 2023 at 1:53
14
$\begingroup$

Remember that Curve25519 is just the elliptic curve. So, if you are mention the private key, it must be set in a certain context - I guess Ed25519 Digital Signature Scheme or X25519 Key Exchange. The solution is to just compute the public key from the private key. In case of Ed25519:

$(\mathsf{sk},\ \mathsf{pk})\leftarrow \mathsf{KeyGen}_{Ed25519}()$

  1. $d\xleftarrow{\\\$} \{0,1\}^{256}$
  2. $h=(h_0, h_1, \ldots, h_{511})=\texttt{SHA-512}(d)$
  3. $h^L=(0, 0, 0,h_3,h_4,h_5, h_6,\ldots, h_{251}, h_{252}, h_{253}, 1, 0)$
  4. $s\xleftarrow{\texttt{LittleEndian::decode()}}h^L$
  5. $Q\xleftarrow{\texttt{LittleEndian::encode()}}[s]G$
  6. $\texttt{return}\ (d,\ Q)$

Above is the key generation algorithm for Ed25519. If you got the private key (variable $d$), then you can compute the public key (variable $Q$) by repeating steps 2, 3, 4 and 5. But remember that implementation with which you are dealing can be done in slightly different way (e.g. private key can be returned not directly as variable $d$, and always watch out for endianess).

In case of X25519, the above key generation algorithm is simpler (in the step 2 just take $h=d$).

I think that would be easier than complicating your security mechanism analysis with a some private key derivative (but of course, under certain assumption hashing private key would work, but I'm afraid that kind of analysis require more detailed knowledge of the designed system/solution). And importantly, identifying a person with a public key can be more convenient.

$\endgroup$
1
  • 1
    $\begingroup$ Thanks, I agree. This is the safer route since it has been studied. Will do, although this is not easy in my use case. Although, academically I think it's still an interesting question. $\endgroup$ Commented Aug 27, 2023 at 1:27
0
$\begingroup$

To me this can work but needs fondamental changes in the identification algorithm . For the identification you need to show you know some private information that others don't and so you are the right person. To use directly hash(SK) this means you also generate a zk proof that you know the input of the hash which can be more complicated. But if the identification is based on PK or Hash(Pk), you send PK and a zk proof that you know SK associated with PK which is easier to prove.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.