> 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/key-derivation-and-stealth-addresses.md).

# Key Derivation

### Key Derivation

Each Hinkal account is defined by two capabilities: the ability to **spend** notes and the ability to **view** them. Spending is governed by two secrets — the **Nullifying Key** and the **Spending Key** — while viewing is governed by the **Viewing Key**. None of this key material is ever stored. Every key is derived deterministically from a single Ethereum signature, which means that as long as a user controls their Ethereum account, they can reconstruct their entire Hinkal identity simply by signing the same message again and reproducing the identical signature.

The root of the derivation is an Ethereum signature produced under the **ECDSA (Elliptic Curve Digital Signature Algorithm)** scheme over the **secp256k1** elliptic curve. When the user signs Hinkal's fixed login message with their Ethereum private key, the wallet returns a deterministic signature whose `(r, s, v)` components — where `r` and `s` are the curve‑derived signature values and `v` is the recovery identifier — form a high‑entropy secret that no one without the Ethereum key can reproduce. Hinkal treats this signature as the master seed and applies one‑way hash functions to it to obtain each account key, so the keys are reproducible by the legitimate owner yet reveal nothing about one another.

The **Spending Key** is a dedicated **EdDSA‑Poseidon keypair on the BabyJubJub curve** that authorizes transactions. Its private scalar is derived from the same Ethereum signature under a fixed domain‑separation prefix, hashed with Poseidon so that it is cryptographically independent of the nullifying key, and the corresponding public key is computed with circomlib's standard derivation: the secret is expanded and clamped, then multiplied by the curve's base point. At spend time the wallet signs the transaction message with this key, and the resulting signature is verified against the public spending key inside the proof, cryptographically binding each spend to the account owner without ever revealing the secret on‑chain.

The **Nullifying Key** is the core secret of the shielded account and is obtained by hashing the Ethereum signature with `keccak256`, producing a 32‑byte value. Its name reflects its role: it is the secret used to compute the **nullifiers** that mark notes as spent, and it doubles as the scalar that derives each note's stealth point on the BabyJubJub curve. Because redeeming a note requires regenerating its nullifier, control of this key is precisely what lets a user move their shielded balance, while its public counterpart — a Poseidon hash of the key — can be published to identify the account without exposing the secret.

The **Viewing Keys** are deterministically derived from the user's nullifying key using the **libsodium** cryptographic library and its `crypto_box_seed_keypair` function. The 32‑byte hexadecimal nullifying key is converted into a byte array and supplied as the seed to libsodium's deterministic key‑generation algorithm, which produces a **Curve25519‑based** encryption keypair: a private viewing key and its corresponding public viewing key. The public viewing key is shared so that senders can encrypt note data addressed to the recipient, while the private viewing key allows the owner to scan the chain and decrypt their incoming commitments. Crucially, because this keypair is only an encryption key, it grants the ability to *see* balances and incoming transfers without granting the ability to *spend* them — spending always requires the nullifying and spending keys.

#### **Org-scoped viewing keys**

Hinkal allows an org/individual hierarchy for viewing keys, structured as a two-level deterministic derivation tree. Each organization holds a single org master viewing key vk\_org. Individual viewing keys are derived as vk\_user = Poseidon(vk\_org, user\_id), where Poseidon is a hash function and user\_id is a stable per-member identifier within the org. At note creation, the sender encrypts the note payload to the recipient's stealth address using vk\_user.pub; because vk\_org deterministically generates the full set of {vk\_user} private keys, the org master key can re-derive any vk\_user and decrypt any note addressed to any member — without ever recovering spending keys, which remain rooted in the user's wallet signature and are derived along a separate, sibling branch of the tree. The individual key decrypts only that user's shielded notes and stealth-address activity, while the org master key — sitting one level up — decrypts everything across all members. This gives organizations a single credential for compliance, reconciliation, and treasury oversight, with viewing-key authority strictly read-only.


---

# 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/key-derivation-and-stealth-addresses.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.
