**We recommend the [Prehash and SignPrehash](https://developers.google.com/tink/sign-data-remotely#prehash_and_signprehash)
primitives with an [ML_DSA_44 key](https://developers.google.com/tink/sign-data-remotely#choose_a_key_type) when
the private key lives somewhere the message can't be sent.**

Sometimes the party that holds the signing key can't -- or shouldn't -- receive
the message itself: the key lives in an HSM or a KMS, or the message is larger
than the signer's request size limit.

The Prehash and SignPrehash primitives solve this by splitting signing into two
steps. You compute a short prehash value where the message is, using only the
**public** key, and send it to the signer. The signer turns it into a signature
using the **private** key, without ever seeing the message. With ML-DSA in
External Mu mode -- the algorithm Tink supports here -- the prehash value is 69
bytes, whatever the size of the message.

The signature you get back is an ordinary signature over the original message:
verifiers use the regular
[Digital Signature](https://developers.google.com/tink/digital-signature) primitive and don't need to know that
two steps were involved.

## Before you begin

Create an ML-DSA keyset whose keys have an ID requirement -- either the
`TINK` variant, or `NO_PREFIX_WITH_PREHASH_ID` if you don't want an output
prefix on the resulting signature. Give the signer the private keyset and the
prehashing side the corresponding public keyset. The signer should have an
enabled key for every key ID the prehashing side can produce; see
[Keysets](https://developers.google.com/tink/prehash-signing#keysets).

## Step 1: Compute the prehash value

Run this wherever the message is. It needs only the public keyset.

### C++

```c++
#include "tink/keyset_handle.h"
#include "tink/signature/config_2026.h"
#include "tink/signature/prehash.h"

absl::StatusOr<std::unique_ptr<crypto::tink::Prehash>> prehasher =
    public_handle.GetPrimitive<crypto::tink::Prehash>(
        crypto::tink::ConfigSignature2026());
if (!prehasher.ok()) return prehasher.status();

absl::StatusOr<std::string> prehash = (*prehasher)->Compute(message);
if (!prehash.ok()) return prehash.status();
```

### Go

```go
import "github.com/tink-crypto/tink-go/v2/signprehash"

prehasher, err := signprehash.NewPrehash(publicHandle)
if err != nil {
    return err
}
prehash, err := prehasher.ComputePrehash(message)
if err != nil {
    return err
}
```

### Python

```python
from tink import signature

# Due to the internal structure of Tink Python, Prehash and SignPrehash
# are an exception where calling signature.register() is not necessary.
# Do not expect the same for other primitives (such as PublicKeyVerify in
# Step 4).
prehasher = public_handle.primitive(signature.Prehash)
prehash = prehasher.compute(message)
```

## Step 2: Send the prehash value to the signer

Send the prehash value to whatever holds the private key. It is not
secret, but you must protect its **integrity** in transit: an attacker who can
modify it in flight controls what gets signed.

## Step 3: Sign the prehash value

Run this wherever the private key is.

### C++

```c++
#include "tink/keyset_handle.h"
#include "tink/signature/config_2026.h"
#include "tink/signature/sign_prehash.h"

absl::StatusOr<std::unique_ptr<crypto::tink::SignPrehash>> signer =
    private_handle.GetPrimitive<crypto::tink::SignPrehash>(
        crypto::tink::ConfigSignature2026());
if (!signer.ok()) return signer.status();

absl::StatusOr<std::string> signature = (*signer)->Sign(prehash);
if (!signature.ok()) return signature.status();
```

### Go

```go
import "github.com/tink-crypto/tink-go/v2/signprehash"

signer, err := signprehash.NewPrehashSigner(privateHandle)
if err != nil {
    return err
}
sig, err := signer.SignPrehash(prehash)
if err != nil {
    return err
}
```

### Python

```python
from tink import signature

# Due to the internal structure of Tink Python, Prehash and SignPrehash
# are an exception where calling signature.register() is not necessary.
# Do not expect the same for other primitives (such as PublicKeyVerify in
# Step 4).
signer = private_handle.primitive(signature.SignPrehash)
sig = signer.sign(prehash)
```

## Step 4: Verify the signature

Verification is the ordinary [Digital Signature](https://developers.google.com/tink/digital-signature) flow
over the **original message**, not over the prehash value.

### C++

```c++
absl::StatusOr<std::unique_ptr<crypto::tink::PublicKeyVerify>> verifier =
    public_handle.GetPrimitive<crypto::tink::PublicKeyVerify>(
        crypto::tink::ConfigSignature2026());
if (!verifier.ok()) return verifier.status();

absl::Status verified = (*verifier)->Verify(signature, message);
```

### Go

```go
import "github.com/tink-crypto/tink-go/v2/signature"

verifier, err := signature.NewVerifier(publicHandle)
if err != nil {
    return err
}
if err := verifier.Verify(sig, message); err != nil {
    return err
}
```

### Python

```python
from tink import signature

signature.register()

verifier = public_handle.primitive(signature.PublicKeyVerify)
verifier.verify(sig, message)
```

## Prehash and SignPrehash

The Prehash and SignPrehash primitives split the computation of a digital
signature into two steps:

1. **Prehash** needs only the *public* key. It turns a message of arbitrary length into a short, fixed-size *prehash value*.
2. **SignPrehash** needs the *private* key. It turns a prehash value into a signature.

The signature that comes out is an ordinary signature over the original
message. You verify it with the regular
[Digital Signature](https://developers.google.com/tink/digital-signature) `PublicKeyVerify` primitive, and
verifiers don't need to know -- or care -- that the signature was produced in
two steps.

Treat the prehash value as opaque bytes. It has a fixed size and it carries the
ID of the key it was computed for, but its layout is part of Tink's wire format,
and you should not parse or construct one yourself. If you are porting Tink or
need the byte-level details, see
[Tink wire format](https://developers.google.com/tink/wire-format#prehash).

Use this pair of primitives when:

- **The signing key lives somewhere else**, for example in an HSM, in a KMS, or behind an RPC boundary, and you don't want to ship the full message across that boundary.
- **The message is large**, and the remote signer enforces a request size limit.

If neither of these applies, use the plain
[Digital Signature](https://developers.google.com/tink/digital-signature) primitive instead: it is simpler,
and it is harder to misuse.

### Keysets

The two primitives select keys differently, in the same way that signing and
verification do for the [Digital Signature](https://developers.google.com/tink/digital-signature) primitive:

- `Prehash.Compute` always uses the **primary key** of the public keyset, and records that key's ID in the prehash value. It is the side that *chooses* which key the signature will be made with.
- `SignPrehash.Sign` reads the key ID out of the prehash value and signs with the matching **enabled** key of the private keyset. It is the side that *follows* a choice someone else has already made. If no enabled key in the keyset has that ID, the call fails.

Every key in a SignPrehash keyset must have an ID requirement, otherwise
creating the primitive fails.

### Minimal security guarantees

- The resulting signature has the same properties as a signature produced by the [Digital Signature](https://developers.google.com/tink/digital-signature) primitive with the same key type.
- Tink prefixes the prehash value with 5 bytes containing a special reserved value and the ID of the key it was computed for. `SignPrehash` signs the value only with that key. Whether the value is *cryptographically* bound to that key depends on the algorithm; for External Mu ML-DSA it is, see [Tink wire format](https://developers.google.com/tink/wire-format#prehash).
- Messages can have arbitrary length.

### Things to watch out for

- **The signer cannot inspect what it signs.** Anyone who can call `SignPrehash` can get an arbitrary message signed, and the signer has no way to apply a policy to the message contents. Protect access to `SignPrehash` exactly as you would protect access to `PublicKeySign`.
- **Protect the prehash value in transit.** It is not secret, but an attacker who can modify it in flight controls what gets signed.

### Choose a key type

ML-DSA in *External Mu* mode, as described in
[RFC 9881](https://www.rfc-editor.org/rfc/rfc9881.html#externalmu), is the only
algorithm Tink supports for Prehash and SignPrehash. You should use a standard
ML-DSA key with these primitives.

We recommend **ML_DSA_44** for most use cases.

The key must have an ID requirement, because every prehash value starts with a
prefix that contains the ID of the key it was computed for. The following
variants are accepted:

- `TINK` -- the resulting signature starts with Tink's usual 5-byte output prefix.
- `NO_PREFIX_WITH_PREHASH_ID` -- the resulting signature carries no output prefix, while the key still has the ID that the prehash value needs.

Keys that use the `NO_PREFIX` (raw) variant are not supported, because they
have no key ID.