Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs(spec): hashing and keys #5478

Merged
merged 5 commits into from
Apr 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use a hash (could be sha256) of the string as domain separator, so we can avoid this problem and also embed the version in there?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Somewhat related: should we also inject the chain id into the domain separator, as eip712 does?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use a hash (could be sha256) of the string as domain separator, so we can avoid this problem and also embed the version in there?

If Noir can evaluate a hash function at compile time, that approach would be nice. I think I'd like the string to be explicitly written in the Noir function, for easier maintainability/auditabiility. If we just paste the output of the hash function into Noir, I anticipate that will lead to maintenance pain and bugs.

Somewhat related: should we also inject the chain id into the domain separator, as eip712 does?

I'm not sure of the answer to this. I imagined that two chains could have identical domain separators for everything. Any hash which needs to distinguish by chain_id will include the chain_id in the hash preimage? (E.g. tx signatures, and block headers(?))

:::

```rust
address_crh(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does crh stand for?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Collision-resistant hash. It was a half-hearted attempt at reminding us what properties we want from each hash. The zcash spec names hashes similarly, so I took inspiration from there. We can just call it hash if it's too ugly?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

crh is fine, just having a mention to its meaning right before it's defined is good enough

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?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say this depends on the precompile that's going to be validating this set of keys, assuming we go with that design.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. What domain separator should we use for this particular keys scheme? :)


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
Loading