> For the complete documentation index, see [llms.txt](https://hinkal-team.gitbook.io/hinkal/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://hinkal-team.gitbook.io/hinkal/technical-description/setup/encryption.md).

# Encryption

### Note Encryption

Within Hinkal Protocol, the note (UTXO) data created by a transaction is encrypted and published on-chain so that only the recipient's viewing key can decrypt it. This lets users privately and trustlessly detect their incoming notes by scanning published ciphertexts: a note belongs to them precisely when it decrypts and authenticates under their viewing key.

#### Overview

Hinkal uses **Hybrid Public Key Encryption (HPKE)** to accomplish this, instantiated through libsodium's *sealed box* primitive. Before describing the scheme in detail, here is how HPKE works at a high level:

The **sender**…

* generates an ephemeral, single-use asymmetric keypair and, from it, a symmetric encryption key;
* uses the recipient's public key to **encapsulate** that symmetric key so that only the recipient can **decapsulate** it. This mechanism is a Key Encapsulation Module (KEM);
* encrypts the message under the symmetric key using an **authenticated** encryption scheme, so any tampering with the ciphertext in transit is detected;
* publishes the encapsulated key together with the ciphertext.

The **recipient**…

* decapsulates the encapsulated key using their private key to recover the symmetric key;
* attempts to decrypt and authenticate the ciphertext with that key. If authentication fails, they reject the message — which is also the signal that the note was not addressed to them.

Public-key encryption lets the sender encrypt to a recipient without any shared secret, but it is slow; symmetric encryption is fast but needs a pre-shared secret. HPKE combines both, which matters because clients must encrypt and scan many notes on resource-constrained devices while having no trustless channel for sharing secret keys.

#### Detailed Description

Hinkal realizes this scheme with libsodium: `crypto_box_seal` for encryption and `crypto_box_seal_open` for decryption. These operate over **Curve25519** and use **XSalsa20-Poly1305** for authenticated symmetric encryption. First, some definitions:

* `B^N` is the set of all `N`-byte strings; `B` is the set of byte strings of any length.
* `G`: the Curve25519 base point. All curve operations are X25519 scalar multiplications.
* `R ∈ G`: the recipient's **encryption (viewing) public key**, `R = rvk · G`, where `rvk` is the recipient's private viewing key. As described in *Key Derivation*, the viewing keypair is generated with `crypto_box_seed_keypair` seeded from the recipient's nullifying key.
* `(esk, epk)`: an ephemeral, single-use Curve25519 keypair generated by the sender, with `epk = esk · G`. The `epk` is the encapsulated value — the sender's half of a non-interactive Diffie-Hellman exchange.
* `sharedSecret ∈ G`: the Diffie-Hellman shared point established between sender and recipient.
* `BLAKE2b(·) → B^24`: the hash libsodium uses to derive a deterministic 24-byte nonce.
* `KDF(sharedSecret) → key`: the symmetric key derivation libsodium applies to the DH point inside `crypto_box` (HSalsa20), producing the XSalsa20-Poly1305 key.
* `XSalsa20Poly1305`, with:
  * `seal(key, nonce, plaintext) → B`: authenticated encryption of `plaintext`;
  * `open(key, nonce, ciphertext) → B ∪ ⊥`: authenticated decryption, returning an error `⊥` if the Poly1305 tag does not verify.

**Plaintext.** The note plaintext is the serialized UTXO: the `amount`, `erc20TokenAddress`, `randomization`, `stealthAddress`, `timeStamp`, the `isNewStyle` flag, the curve point `H0 = (H0[0], H0[1])`, and an optional Solana `mintAddress`, concatenated as `0x`-prefixed byte strings.

**Encryption** takes as input the note plaintext `msg` and the recipient's viewing public key `R`, and proceeds as follows:

1. `(esk, epk) ← keypair()` — generate the ephemeral keypair, `epk = esk · G`.
2. `sharedSecret ← esk · R` — the `g^{ab}` term of Diffie-Hellman (`a = esk`, `b = rvk`).
3. `nonce ← BLAKE2b(epk ∣∣ R)` — a deterministic 24-byte nonce bound to both public keys.
4. `key ← KDF(sharedSecret)` — derive the symmetric key.
5. `ciphertext ← XSalsa20Poly1305.seal(key, nonce, msg)`.
6. return `(epk ∣∣ ciphertext)` — the encapsulated key prepended to the ciphertext.

**Decryption** takes as input the published `(epk ∣∣ ciphertext)` and the recipient's viewing keypair `(R, rvk)`, and proceeds as follows:

1. parse `epk` from the first 32 bytes of the input.
2. `sharedSecret ← rvk · epk` — the recipient's side of Diffie-Hellman; `(esk · G) · rvk = esk · rvk · G`, the same point computed in step 2 of encryption.
3. `nonce ← BLAKE2b(epk ∣∣ R)`.
4. `key ← KDF(sharedSecret)`.
5. `plaintext ← XSalsa20Poly1305.open(key, nonce, ciphertext)`.
6. if `plaintext = ⊥`, reject the message (the note is not addressed to this recipient, or was tampered with).
7. otherwise, parse the UTXO fields from `plaintext` and return the recovered note.

Because the symmetric key is bound to a fresh ephemeral `epk` for every note and is authenticated with Poly1305, ciphertexts are unlinkable to each other and to the recipient, and only the holder of `rvk` can reproduce the shared secret needed to open them. Trustless detection follows directly: a client simply attempts `crypto_box_seal_open` on each published ciphertext, keeping the notes that authenticate and discarding the rest.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://hinkal-team.gitbook.io/hinkal/technical-description/setup/encryption.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
