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

protocol: create new transaction section, action reference #3990

Merged
merged 1 commit into from
Mar 11, 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
6 changes: 4 additions & 2 deletions docs/protocol/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
- [Distributed Key Generation](./crypto/flow-encryption/dkg.md)
- [Homomorphic Threshold Encryption](./crypto/flow-encryption/threshold-encryption.md)
- [Flow Encryption and Consensus](./protocol/flow-consensus.md)
- [Transaction Signing](./crypto/transaction_signing.md)
- [Groth 16 Setup Ceremony](./setup.md)
- [Groth16 Recap](./setup/groth16_recap.md)
- [Discrete Logarithm Proofs](./setup/dlog_proofs.md)
Expand All @@ -48,8 +47,11 @@
- [State Commitment Tree](./sct.md)
- [Tiered Commitment Tree](./sct/tct.md)
- [Nullifiers](./protocol/notes/nullifiers.md)
- [Asset Model](./assets.md)
- [Transaction Model](./transactions.md)
- [Transaction Signing](./transactions/signing.md)
- [Action Reference](./transactions/actions.md)
- [Multi-Asset Shielded Pool](./shielded_pool.md)
- [Asset IDs and Value Commitments](./protocol/value_commitments.md)
- [Note Plaintexts](./protocol/notes/note_plaintexts.md)
- [Note Commitments](./protocol/notes/note_commitments.md)
- [Note Ciphertexts](./protocol/notes/note_ciphertexts.md)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Asset IDs and Value Commitments
# Asset Model

Penumbra's shielded pool can record arbitrary assets. These assets either
originate on Penumbra itself, or, more commonly, originate on other
IBC-connected chains. To record arbitrary assets and enforce value balance
between them, we draw on [ideas][multi_asset] originally proposed for Zcash and
adapt them to the Cosmos context.
Penumbra can record arbitrary assets. These assets either originate on Penumbra
itself, or, more commonly, originate on other IBC-connected chains. To record
arbitrary assets and enforce value balance between them, we draw on
[ideas][multi_asset] originally proposed for Zcash and adapt them to the Cosmos
context.

## Asset types and asset IDs

Expand All @@ -14,8 +14,9 @@ To be precise, we define:
- an *asset ID* to be an $\mathbb F_q$ element;
- a *value* to be a typed quantity, i.e., an amount and an asset ID.

Some asset IDs correspond to a *denomination*, an [ADR001]-style denomination
trace uniquely identifying a cross-chain asset and its provenance, such as:
All asset IDs are currently computed as the hash of a *denomination*, an
[ADR001]-style denomination trace uniquely identifying a cross-chain asset and
its provenance, such as:
- `denom` (native chain A asset)
- `transfer/channelToA/denom` (chain B representation of chain A asset)
- `transfer/channelToB/transfer/channelToA/denom` (chain C representation of chain B representation of chain A asset)
Expand All @@ -31,12 +32,21 @@ personalization `label` on input `input`. Then asset IDs are computed as
asset_id = from_le_bytes(hash(b"Penumbra_AssetID", asset_type)) mod q
```

Other asset IDs do not correspond to denominations, but are computed as hashes
of other state data. By making the asset ID itself be a hash of extended state
data, a note recording value of that type also binds to that extended data, even
though it has the same size as any other note. For instance:
- [The ZSwap mechanism](../zswap/swap.md) has the `Swap` action form a *Swap NFT*, whose asset ID is a Poseidon hash of the user's secret input values address, so that when the `SwapClaim` action spends the NFT, it can (zk)prove consistency of the newly minted swap outputs with the user's inputs and the chain's clearing prices, and that the newly minted outputs are sent to the user's own address.
- [The LPNFT mechanism](../zswap/lpnft.md) creates asset IDs that bind both a liquidity position ID and the position state, so that the value balance mechanism described below can track state changes to concentrated liquidity positions.
In the future, Penumbra may have other asset IDs do not correspond to
denominations, but are computed as hashes of other state data. By making the
asset ID itself be a hash of extended state data, a note recording value of that
type also binds to that extended data, even though it has the same size as any
other note. Currently, however, all asset IDs are computed as the hashes of
denomination strings.

## Asset Metadata

Penumbra also supports Cosmos-style `Metadata` for assets. The chain maintains
an on-chain lookup table of asset IDs to asset metadata, but the on-chain
metadata is minimal and generally only includes the denomination string. Client
software is expected to be opinionated about asset metadata, supplying
definitions with symbols, logos, etc. to help users understand the assets they
hold.

## Value Generators

Expand Down Expand Up @@ -74,25 +84,6 @@ Alternatively, this can be thought of as a commitment to a (sparse) vector
recording the amount of every possible asset type, almost all of whose
coefficients are zero.

## Binding Signatures

Finally, we'd like to be able to prove that a certain value commitment $C$ is a
commitment to $0$. One way to do this would be to prove knowledge of an opening
to the commitment, i.e., producing $\widetilde{v}$ such that $$C = [\widetilde{v}] \widetilde{V} = \operatorname{Commit}(0, \widetilde{v}).$$ But this is exactly what it means to
create a Schnorr signature for the verification key $C$, because a Schnorr
signature is a proof of knowledge of the signing key in the context of the
message.

Therefore, we can prove that a value commitment is a commitment to $0$ by
treating it as a `decaf377-rdsa` verification key and using the corresponding
signing key (the blinding factor) to sign a message. This also gives a way to
bind value commitments to a particular context (e.g., a transaction), by using
the context as the message to be signed, in order to, e.g., ensure that value
commitments cannot be replayed across transactions.




[multi_asset]: https://github.com/zcash/zips/blob/626ea6ed78863290371a4e8bc74ccf8e92292099/drafts/zip-user-defined-assets.rst
[ADR001]: https://docs.cosmos.network/master/architecture/adr-001-coin-source-tracing.html
[IBC]: https://docs.cosmos.network/master/ibc/overview.html
150 changes: 0 additions & 150 deletions docs/protocol/src/crypto/transaction_signing.md
Original file line number Diff line number Diff line change
@@ -1,151 +1 @@
# Transaction Signing

In a transparent blockchain, a signer can inspect the transaction to be signed to
validate the contents are what the signer expects. However, in a shielded
blockchain, the contents of the transaction are opaque. Ideally, using a private
blockchain would enable a user to sign a transaction while also understanding
what they are signing.

To avoid the blind signing problem, in the Penumbra protocol we allow the user
to review a description of the transaction - the `TransactionPlan` - prior to
signing. The `TransactionPlan` contains a declarative description of all details of the proposed transaction, including a plan of each action in a transparent
form, the fee specified, the chain ID, and so on. From this plan, we authorize the and build the transaction. This has the additional advantage of allowing the signer to authorize the
transaction while the computationally-intensive Zero-Knowledge
Proofs (ZKPs) are optimistically generated as part of the transaction build process.

The signing process first takes a `TransactionPlan` and `SpendKey` and returns
the `AuthorizationData`, essentially a bundle of signatures over
the *effect hash*, which can be computed directly from the plan data. You can
read more about the details of the effect hash computation below.

The building process takes the `TransactionPlan`, generates the proofs, and constructs a fully-
formed `Transaction`. This process is internally partitioned into three steps:
1. Each `Action` is individually built based to its specification in the `TransactionPlan`.
2. The pre-built actions to collectively used to construct a transaction with placeholder dummy signatures, that can be filled in once the
signatures from the `AuthorizationData` are ready[^1]. This intermediate state
of the transaction without the full authorizing data is referred to as the "**Unauthenticated Transaction**".
1. Slot the `AuthorizationData` to replace the placeholder signatures to assemble the final `Transaction`.

The Penumbra protocol was designed to only require the custodian, e.g. the hardware wallet
environment, to do signing, as the generation of ZKPs can be done without access to signing keys, requiring only witness data and viewing keys.

A figure showing how these pieces fit together is shown below:

```
╔════════════════════════╗
║ Authorization ║
║ ║
║┌──────────────────────┐║
║│ Spend authorization │║
║│ key │║ ┌───────────────────┐
║└──────────────────────┘║ │ │
║ ║───▶│ AuthorizationData │──┐
║ ║ │ │ │
║┌──────────────────────┐║ └───────────────────┘ │
║│ EffectHash │║ │
║└──────────────────────┘║ │
║ ║ │
║ ║ │
╚════════════▲═══════════╝ │
│ │
│ │ ┌───────────┐
┌───────────┴───────────┐ │ │ │
│ │ └─────────┬────▶│Transaction│
│ TransactionPlan │ | │ │
│ │ │ └───────────┘
└───────────┬───────────┘ │
│ │
│ │
│ │
╔═══════════▼════════════╗ │
║ Proving ║ │
║ ║ │
║┌──────────────────────┐║ │
║│ WitnessData │║ │
║└──────────────────────┘║ ┌──────────────────────────────┐ │
║ ║ │ │ │
║ ╠──▶│ Unauthenticated Transaction ├─┘
║┌──────────────────────┐║ │ │
║│ Full viewing key │║ └──────────────────────────────┘
║└──────────────────────┘║
║ ║
║ ║
║ ║
╚════════════════════════╝

```

Transactions are signed used the [`decaf377-rdsa` construction](../crypto/decaf377-rdsa.md). As described briefly in that section, there are two signature domains used in Penumbra: `SpendAuth` signatures and `Binding` signatures.

## `SpendAuth` Signatures

`SpendAuth` signatures are included on each `Spend` and `DelegatorVote` action
(see [Multi-Asset Shielded Pool](../shielded_pool.md) and [Governance](../governance.md)
for more details on `Spend` and `DelegatorVote` actions respectively).

The `SpendAuth` signatures are created using a randomized signing key $rsk$ and the corresponding randomized verification key $rk$ provided on the action. The purpose of the randomization is to prevent linkage of verification keys across actions.

The `SpendAuth` signature is computed using the `decaf377-rdsa` `Sign` algorithm
where the message to be signed is the *effect hash* of the entire transaction
(described below), and the `decaf377-rdsa` domain is `SpendAuth`.

## Effect Hash

The effect hash is computed over the *effecting data* of the transaction, which following
the terminology used in Zcash[^2]:

> "Effecting data" is any data within a transaction that contributes to the effects of applying the transaction to the global state (results in previously-spendable coins or notes becoming spent, creates newly-spendable coins or notes, causes the root of a commitment tree to change, etc.).

The data that is _not_ effecting data is *authorizing data*:

>"Authorizing data" is the rest of the data within a transaction. It does not contribute to the effects of the transaction on global state, but allows those effects to take place. This data can be changed arbitrarily without resulting in a different transaction (but the changes may alter whether the transaction is allowed to be applied or not).

For example, the nullifier on a `Spend` is effecting data, whereas the
proofs or signatures associated with the `Spend` are authorizing data.

In Penumbra, the effect hash of each transaction is computed using the BLAKE2b-512
hash function. The effect hash is derived from the proto-encoding of the action - in
cases where the effecting data and authorizing data are the same, or the *body*
of the action - in cases where the effecting data and authorizing data are different.
Each proto has a unique string associated with it called its *Type URL*,
which is included in the inputs to BLAKE2b-512.
Type URLs are variable length, so a fixed-length field (8 bytes) is first included
in the hash to denote the length of the Type URL field.

Summarizing the above, the effect hash _for each action_ is computed as:

```
effect_hash = BLAKE2b-512(len(type_url) || type_url || proto_encode(proto))
```

where `type_url` is the bytes of the variable-length Type URL, `len(type_url)` is the length of the Type URL encoded as 8
bytes in little-endian byte order, `proto` represents the proto used to represent
the effecting data, and `proto_encode` represents encoding the proto message as
a vector of bytes. In Rust, the Type URL is found by calling [`type_url()` on the protobuf
message](https://docs.rs/prost/latest/prost/trait.Name.html#method.type_url).

All transaction data field effect hashes, such as the `Fee`, `MemoCiphertext`, and `TransactionParameters`, as well as the per-action effect hashes, are computed using this method.

### Transaction Effect Hash

To compute the effect hash of the _entire transaction_, we combine the hashes of the individual fields in the transaction body. First we include the fixed-sized effect hashes of the per-transaction data fields: the transaction parameters `eh(tx_params)`, fee `eh(fee)`, (optional) detection data `eh(detection_data)`, and (optional) memo `eh(memo)` which are derived as described above. Then, we include the number of actions $j$ and the fixed-size effect hash of each action `a_0` through `a_j`. Combining all fields:

```
effect_hash = BLAKE2b-512(len(type_url) || type_url || eh(tx_params) || eh(fee) || eh(memo) || eh(detection_data) || j || eh(a_0) || ... || eh(a_j))
```

where the `type_url` is the variable-length Type URL of the transaction body message, and `len(type_url)` is the length of that string encoded as 8 bytes in little-endian byte order.

## `Binding` Signature

The `Binding` signature is computed once on the transaction level.
It is a signature over a hash of the authorizing data of that transaction, called the *auth hash*. The auth hash of each transaction is computed using the BLAKE2b-512 hash function over the proto-encoding of the _entire_ `TransactionBody`.

The `Binding` signature is computed using the `decaf377-rdsa` `Sign` algorithm
where the message to be signed is the *auth hash* as described above, and the
`decaf377-rdsa` domain is `Binding`. The binding signing key is computed using the random blinding factors for each balance commitment.

[^1]: At this final stage we also generate the last signature: the binding signature, which can only be added
once the rest of the transaction is ready since it is computed over the proto-encoded `TransactionBody`.

[^2]: https://github.com/zcash/zips/issues/651
49 changes: 49 additions & 0 deletions docs/protocol/src/transactions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Transaction Model

A Penumbra transaction is a bundle of _actions_ that effect changes to the chain
state, together with additional data controlling how those actions are executed
or providing additional metadata. All actions in the transaction are executed together, and the transaction succeeds or fails atomically. A transaction body has four parts:

1. A list of actions effecting changes to the chain state;
2. A set of `TransactionParameters` describing conditions under which the actions may be executed;
3. A set of `DetectionData` that helps third-party servers detect transactions using [Fuzzy Message Detection](./crypto/fmd.md);
4. A `MemoCiphertext` with an encrypted memo visible only to the sender and receiver(s) of the transaction.

The [Transaction Signing](./transactions/signing.md) section describes transaction authorization.

## Actions and Value Balance

The primary content of a transaction is its list of actions. Each action is executed in sequence, and effects changes to the chain state.

Crucially, each action makes a shielded contribution to the transaction's value
balance by means of a _balance commitment_, using the commitment scheme for asset values described in detail in the [Asset Model](./assets.md).

Some actions, like a `Spend`, consume state fragments from the chain and release
value into the transaction, while others, like `Output`, consume value from the
transaction and record it in the state. And actions like `Delegate` consume one
type of value (the staking token) and release another type of value (the
delegation token).

The chain requires that transactions do not create or destroy value. To
accomplish conservation of value, the _binding signature_ proves that the
transaction's value balance, summed up over all actions, is zero. This
construction works as follows. We'd like to be able to prove that a certain
value commitment $C$ is a commitment to $0$. One way to do this would be to
prove knowledge of an opening to the commitment, i.e., producing $\widetilde{v}$
such that $$C = [\widetilde{v}] \widetilde{V} = \operatorname{Commit}(0,
\widetilde{v}).$$ But this is exactly what it means to create a Schnorr
signature for the verification key $C$, because a Schnorr signature is a proof
of knowledge of the signing key in the context of the message.

Therefore, we can prove that a value commitment is a commitment to $0$ by
treating it as a `decaf377-rdsa` verification key and using the corresponding
signing key (the blinding factor) to sign a message. This also gives a way to
bind value commitments to a particular context (e.g., a transaction), by using a
hash of the transaction as the message to be signed, ensuring that actions
cannot be replayed across transactions without knowledge of their contents.

The balance commitment mechanism is essential to security. It is what "glues"
the validity of the local state transitions provided by each action's proof
statement into validity of the global state transition.

A complete list of actions and a summary of their effects on the chain state and the transaction's value balance is provided in the [Action Reference](./transactions/actions.md).
Loading
Loading