Skip to content

Commit

Permalink
docs(spec): hashing and keys (#5478)
Browse files Browse the repository at this point in the history
- Make hashing definitions more exact: introducing poseidon2 instead of
"hash".
- Using strings as domain separators.
- Merkle Tree page
- Hash page
- Re-write keys derivations, taking inspiration from the zcash and bip
specs.
- Be more exact with the derivations, hash choices & domain separators.
- Still some work to do, but it won't be done for a while, so would
prefer to just merge what we have.
- Move examples of keys being used to a subdir. (So a lot of the pages
that look like brand new pages, are actually just cut-pasting sections
into their own page, and prefixing those sections with all the latex
boilerplate which defines commonly-used keys).
  • Loading branch information
iAmMichaelConnor authored Apr 5, 2024
1 parent 88e8b6d commit 820ac8c
Show file tree
Hide file tree
Showing 22 changed files with 1,185 additions and 713 deletions.
90 changes: 90 additions & 0 deletions yellow-paper/docs/addresses-and-keys/0-keys-latex-preamble.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
$$
\gdef\sk{\color{red}{sk}\color{black}{}}
\gdef\seed{\color{red}\text{{seed}}\color{black}{}}
\gdef\nskm{\color{red}{nsk_m}\color{black}{}}
\gdef\tskm{\color{red}{tsk_m}\color{black}{}}
\gdef\ivskm{\color{red}{ivsk_m}\color{black}{}}
\gdef\ovskm{\color{red}{ovsk_m}\color{black}{}}
\gdef\Npkm{\color{green}{Npk_m}\color{black}{}}
\gdef\Tpkm{\color{green}{Tpk_m}\color{black}{}}
\gdef\Ivpkm{\color{green}{Ivpk_m}\color{black}{}}
\gdef\Ovpkm{\color{green}{Ovpk_m}\color{black}{}}
\gdef\address{\color{green}{address}\color{black}{}}
\gdef\codehash{\color{green}{code\_hash}\color{black}{}}
\gdef\constructorhash{\color{green}{constructor\_hash}\color{black}{}}
\gdef\classid{\color{green}{class\id}\color{black}{}}
\gdef\nskapp{\color{red}{nsk_{app}}\color{black}{}}
\gdef\tskapp{\color{red}{tsk_{app}}\color{black}{}}
\gdef\ivskapp{\color{red}{ivsk_{app}}\color{black}{}}
\gdef\ovskapp{\color{red}{ovsk_{app}}\color{black}{}}
\gdef\Nkapp{\color{orange}{Nk_{app}}\color{black}{}}
\gdef\Npkapp{\color{green}{Npk_{app}}\color{black}{}}
\gdef\Ivpkapp{\color{green}{Ivpk_{app}}\color{black}{}}
\gdef\happL{\color{green}{h_{app}^L}\color{black}{}}
\gdef\happn{\color{green}{h_{app}^n}\color{black}{}}
\gdef\happiv{\color{green}{h_{app}^{iv}}\color{black}{}}
\gdef\d{\color{green}{d}\color{black}{}}
\gdef\Gd{\color{green}{G_d}\color{black}{}}
\gdef\Ivpkappd{\color{violet}{Ivpk_{app,d}}\color{black}{}}
\gdef\shareableIvpkappd{\color{violet}{\widetilde{Ivpk_{app,d}}}\color{black}{}}
\gdef\Ivpkmd{\color{violet}{Ivpk_{m,d}}\color{black}{}}
\gdef\shareableIvpkmd{\color{violet}{\widetilde{Ivpk_{m,d}}}\color{black}{}}
\gdef\ivskappstealth{\color{red}{ivsk_{app,stealth}}\color{black}{}}
\gdef\Ivpkappdstealth{\color{violet}{Ivpk_{app,d,stealth}}\color{black}{}}
\gdef\Pkappdstealth{\color{violet}{Pk_{app,d,stealth}}\color{black}{}}
\gdef\ivskmstealth{\color{red}{ivsk_{m,stealth}}\color{black}{}}
\gdef\Ivpkmdstealth{\color{violet}{Ivpk_{m,d,stealth}}\color{black}{}}
\gdef\Pkmdstealth{\color{violet}{Pk_{m,d,stealth}}\color{black}{}}
\gdef\hstealth{\color{violet}{h_{stealth}}\color{black}{}}
\gdef\esk{\color{red}{esk}\color{black}{}}
\gdef\Epk{\color{green}{Epk}\color{black}{}}
\gdef\Epkd{\color{green}{Epk_d}\color{black}{}}
\gdef\eskheader{\color{red}{esk_{header}}\color{black}{}}
\gdef\Epkheader{\color{green}{Epk_{header}}\color{black}{}}
\gdef\Epkdheader{\color{green}{Epk_{d,header}}\color{black}{}}
\gdef\sharedsecret{\color{violet}{\text{S}}\color{black}{}}
\gdef\sharedsecretmheader{\color{violet}{\text{S_{m,header}}}\color{black}{}}
\gdef\sharedsecretappheader{\color{violet}{\text{S_{app,header}}}\color{black}{}}
\gdef\hmencheader{\color{violet}{h_{m,enc,header}}\color{black}{}}
\gdef\happencheader{\color{violet}{h_{app,enc,header}}\color{black}{}}
\gdef\hmenc{\color{violet}{h_{m,enc}}\color{black}{}}
\gdef\happenc{\color{violet}{h_{app,enc}}\color{black}{}}
\gdef\incomingenckey{\color{violet}{h_{incoming\_enc\_key}}\color{black}{}}
\gdef\plaintext{\color{red}{\text{plaintext}}\color{black}{}}
\gdef\ciphertext{\color{green}{\text{ciphertext}}\color{black}{}}
\gdef\ciphertextheader{\color{green}{\text{ciphertext\_header}}\color{black}{}}
\gdef\payload{\color{green}{\text{payload}}\color{black}{}}
\gdef\tagg{\color{green}{\text{tag}}\color{black}{}}
\gdef\Taghs{\color{green}{\text{Tag}_{hs}}\color{black}{}}
$$
70 changes: 58 additions & 12 deletions yellow-paper/docs/addresses-and-keys/address.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ title: Address

An address is computed as the hash of the following fields:

<!-- TODO: discrepancy between this hash preimage and the contract classes page pseudocode, which includes a version -->

<!-- prettier-ignore -->
| Field | Type | Description |
|----------|----------|----------|
Expand All @@ -27,21 +29,65 @@ We may remove the `portal_contract_address` as a first-class citizen.

The hashing scheme for the address should then ensure that checks that are more frequent can be done cheaply, and that data shared out of band is kept manageable. We define the hash to be computed as follows:

```
salted_initialization_hash = pedersen([salt, initialization_hash, deployer as Field, portal_contract_address as Field], GENERATOR__SALTED_INITIALIZATION_HASH)
partial_address = pedersen([contract_class_id, salted_initialization_hash], GENERATOR__CONTRACT_PARTIAL_ADDRESS_V1)
address = pedersen([public_keys_hash, partial_address], GENERATOR__CONTRACT_ADDRESS_V1)
```
<!-- TODO: missing `version` from hashing! -->

:::warning
Some of these draft domain separators might be too many bits; they need to fit inside a single field element. Version numbers might not be needed until we roll the _next_ version.
:::

```rust
address_crh(
version: Field,
salt: Field,
deployer: AztecAddress,
contract_class_id: Field,
initialization_hash: Field,
portal_contract_address: EthereumAddress,
public_keys_hash: Field,
) -> Field {

let salted_initialization_hash: Field = poseidon2(
be_string_to_field("az_salted_initialization_hash_v1"),

The `public_keys` array can vary depending on the format of keys used by the address, but it is suggested it includes the master keys defined in the [keys section](./keys.md).
salt,
initialization_hash,
deployer.to_field(),
be_bits_to_field(portal_contract_address)
);

let partial_address: Field = poseidon2(
be_string_to_field("az_contract_partial_address_v1"),

contract_class_id,
salted_initialization_hash
);

let address: Field = poseidon2(
be_string_to_field("az_contract_address_v1"),

public_keys_hash,
partial_address
);

address
}
```
public_keys_hash = pedersen([
nullifier_pubkey.x, nullifier_pubkey.y,
tagging_pubkey.x, tagging_pubkey.y,
incoming_view_pubkey.x, incoming_view_pubkey.y,
outgoing_view_pubkey.x, outgoing_view_pubkey.y
], GENERATOR__PUBLIC_KEYS)

The `public_keys` array can vary depending on the format of keys used by the address, but it is suggested it includes the master keys defined in the [keys section](./keys.mdx). For example:

```rust
let public_keys_hash: Field = poseidon2(
be_string_to_field("az_public_keys_hash"), // TODO: does this need some unique ID, to disambiguate from other approaches people might have for other public keys?

nullifier_pubkey.x,
nullifier_pubkey.y,
tagging_pubkey.x,
tagging_pubkey.y,
incoming_view_pubkey.x,
incoming_view_pubkey.y,
outgoing_view_pubkey.x,
outgoing_view_pubkey.y
);
```

This recommended hash format is compatible with the [encryption precompiles](./precompiles.md#encryption-and-tagging-precompiles) initially defined in the protocol and advertised in the canonical [registry](../pre-compiled-contracts/registry.md) for private message delivery. An address that chooses to use a different format for its keys will not be compatible with apps that rely on the registry for note encryption. Nevertheless, new precompiles introduced in future versions of the protocol could use different public keys formats.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Diversified and Stealth Accounts
---

The [keys specification](./keys.md) describes derivation mechanisms for diversified and stealth public keys. However, the protocol requires users to interact with addresses.
The [keys specification](./keys.mdx) describes derivation mechanisms for diversified and stealth public keys. However, the protocol requires users to interact with addresses.

## Computing Addresses

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<!-- @dev: if you want to import the preamble, remember to make the importing file a `.mdx` file. -->

import LatexPreamble from "../0-keys-latex-preamble.md";
<LatexPreamble />;

## Deriving diversified public keys

A diversified public key can be derived from Alice's keys, to enhance Alice's transaction privacy. If Alice's counterparties' databases are compromised, it enables Alice to retain privacy from such leakages. Diversified public keys are used for generating diversified addresses.

Basically, Alice must personally derive and provide Bob and Charlie with random-looking addresses (for Alice). Because Alice is the one deriving these Diversified Addresses (they can _only_ be derived by Alice), if Bob and Charlie chose to later collude, they would not be able to convince each-other that they'd interacted with Alice.

This is not to be confused with 'Stealth Addresses', which 'flip' who derives: Bob and Charlie would each derive a random-looking Stealth Address for Alice. Alice would then discover her new Stealth Addresses through decryption.

> All of the key information below is Alice's
Alice derives a 'diversified' incoming viewing public key, and sends it to Bob:

<!-- prettier-ignore -->
| Thing | Derivation | Name | Comments |
|---|---|---|---|
$\d$ | $\stackrel{rand}{\leftarrow} \mathbb{F}$ |diversifier |
$\Gd$ | $\d \cdot G$ | diversified generator |
$\Ivpkmd$ | $\ivskm \cdot \Gd$ | Diversified incoming viewing public key |

> Notice: when $\d = 1$, $\Ivpkmd = \Ivpkm$. Often, it will be unncessary to diversify the below data, but we keep $\d$ around for the most generality.

## Deriving stealth public keys

> All of the key information below is Alice's
Stealth Public Keys are used for generating Stealth Addresses. For Bob to derive a Stealth Address for Alice, Bob derives:

<!-- prettier-ignore -->
| Thing | Derivation | Name | Comments |
|---|---|---|---|
$\d$ | Given by Alice | (Diversifier) | Remember, in most cases, $\d=1$ is sufficient.
$\Gd$ | $\d \cdot G$ | (Diversified) generator | Remember, when $\d = 1$, $\Gd = G$.
$\esk_{stealth}$ | $\stackrel{rand}{\leftarrow} \mathbb{F}$ | ephemeral secret, for deriving the stealth key shared secret |
$\Epkd,_{stealth}$ | $\esk_{stealth} \cdot \Gd$ | (Diversified) Ephemeral public key, for deriving the stealth key shared secret |
$\sharedsecret_{m, stealth}$ | $\esk_{stealth} \cdot \Ivpkmd$ | Stealth key shared secret |
$\hstealth$ | $\text{pos2}(\text{``az\_stealth\_key''}, \sharedsecret_{m, stealth})$ | stealth key |
$\Ivpkmdstealth$ | $\hstealth \cdot \Gd + \Ivpkmd$ | (Diversified) Stealth viewing public key |

Having derived a Stealth Address for Alice, Bob can now share it with Alice as follows:

<!-- prettier-ignore -->
| Thing | Derivation | Name | Comments |
|---|---|---|---|
$\tagg_{m, i}^{Bob \rightarrow Alice}$ | See earlier in this doc. | | Derive the next tag in the $Bob\rightarrow Alice$ sequence.<br />Note: we illustrate with a _master_ tag sequence, but an app-specific tag sequence could also be used (in which case an encryption of the app_address in a ciphertext header wouldn't be required; it could just be inferred from the tag used). |
$\esk_{header}$ | $\stackrel{rand}{\leftarrow} \mathbb{F}$ | ephemeral secret key, for deriving the ciphertext header shared secret |
$\Epkd,_{header}$ | $\esk_{header} \cdot \Gd$ | (Diversified) Ephemeral public key, for deriving the ciphertext header shared secret |
$\sharedsecret_{m,header}$ | $\esk_{header} \cdot \Ivpkm$ | Ciphertext header shared secret | TODO: we might need to use a different ephemeral keypair from the one used to derive the stealth address. |
$\hmencheader$ | $\text{pos2}(\text{``az\_enc\_key''}, \sharedsecret_{m,header})$ | ciphertext header encryption key
$\ciphertextheader$ | $\text{encrypt}^{\Ivpkm}_{\hmencheader}$(app\_address) | | TODO: diversify this? |
$\payload$ | [ $\tagg_{m, i}^{Bob \rightarrow Alice}$, $\Epkd,_{header}$, $\ciphertextheader$, $\Epkd,_{stealth}$ ] |

Alice can learn about her new Stealth Address as follows. First, she would identify the transaction has intended for her, either by observing $\tagg_{m, i}^{Bob \rightarrow Alice}$ on-chain herself (and then downloading the rest of the payload which accompanies the tag), or by making a privacy-preserving request to a server, to retrieve the payload which accompanies the tag. Assuming the $\payload$ has been identified as Alice's, we proceed:

<!-- prettier-ignore -->
| Thing | Derivation | Name |
|---|---|---|
$\sharedsecret_{m,header}$ | $\ivskm \cdot \Epkd,_{header}$ | Ciphertext header shared secret |
$\hmencheader$ | $\text{pos2}(\text{``az\_enc\_key''}, \sharedsecret_{m,header})$ | ciphertext header encryption key |
app_address | $\text{decrypt}_{\hmencheader}^{\ivskm}(\ciphertextheader)$ |
$\ivskm$ | See derivations above. Use the decrypted app_address in the derivation. | app-specific incoming viewing secret key |
$\sharedsecret_{m, stealth}$ | $\ivskm \cdot \Epkd,_{stealth}$ | Stealth key shared secret |
$\hstealth$ | $\text{pos2}(\text{``az\_stealth\_key''}, \sharedsecret_{m, stealth})$ | stealth key |
$\ivskmstealth$ | $\hstealth + \ivskm$ |
$\Ivpkmdstealth$ | $\ivskmstealth \cdot \Gd$ | (Diversified) Stealth viewing public key |
Loading

0 comments on commit 820ac8c

Please sign in to comment.