Skip to content

Commit

Permalink
re-organize chain abstraction (#1793)
Browse files Browse the repository at this point in the history
* re-organize chain abstraction

* Apply suggestions from code review

* Apply suggestions from code review

* chain signatures suggestions for `abs-sig` branch (#1801)

* standardize cross chain signatures -> chain sig

* update learn intro

* update intro;

* update title & payload/transaction

* update payload->tx & highlight examples

* update tip

* break down derivation components

* update example address / minor edit

* minor edits / duplicate info annotation at bottom

* wip

* enhance derivation path

* update multichain smart contract

* mpc consolidation WIP

* udpate mpc

* Apply suggestions from code review

---------

Co-authored-by: Damián Parrino <bucanero@users.noreply.github.com>
Co-authored-by: Josh Ford <thisisjoshford@gmail.com>
  • Loading branch information
3 people authored Mar 9, 2024
1 parent faa512c commit 60a99d1
Show file tree
Hide file tree
Showing 2 changed files with 180 additions and 106 deletions.
121 changes: 62 additions & 59 deletions docs/1.concepts/abstraction/chain-signatures.md
Original file line number Diff line number Diff line change
@@ -1,110 +1,113 @@
---
id: chain-signatures
title: Chain Signatures
title: What are Chain Signatures?
sidebar_label: What are Chain Signatures?
---

Chain Signatures unlock the ability for a single account to transact across multiple blockchain protocols, giving ownership of cross-chain accounts, data, and assets to one NEAR account.
Chain signatures enable NEAR accounts, including smart contracts, to sign and execute transactions across many blockchain protocols.

This many-to-one ownership is made possible through a mixture of services across our tech stack:
This unlocks the next level of blockchain interoperability by giving ownership of diverse assets, cross-chain accounts, and data to a single NEAR account.

1. A [smart contract](../basics/accounts/smartcontract.md) that holds requests for multi-chain signatures.
2. A [multiparty computation](https://www.zellic.io/blog/mpc-from-scratch/) service listening for signature requests.
3. A multi-chain [relayer](./relayers.md), which can submit signed transactions to other networks.
:::info Looking for code?

To get started using Chain Signatures in your project see **[Create a Chain Signature](../../8.abstraction/chain-signatures.md)**.

:::info
This section presents an overview of Chain Signatures. To create one, please switch to the [**building a Chain Signature**](../../8.abstraction/chain-signatures.md) document.
:::

---

## How It Works

![chain-signatures](/docs/assets/welcome-pages/chain-signatures-overview.png)
_Diagram of a chain signature in NEAR_
Controlling accounts and their assets on other blockchain platforms is made possible thanks to the interaction between three elements:

There are four steps involved on Chain Signatures:

1. [Create a Payload](#1-create-a-payload) - The user creates the transaction / message they want to sign
2. [Signature Request](#2-request-signature) - The user calls the NEAR `multichain` contract, requesting to sign the transaction
3. [MPC Signing Service](#3-sign-with-mpc) - A service captures the call, and returns the signed the transaction for the user
4. [Relay Signed Payload](#4-relaying-the-signature) - The signed payload is then sent to the destination chain for execution.
1. [**Derivation Paths**](#derivation-paths-one-account-multiple-chains) - A deterministic way to derive multiple addresses from one NEAR account
2. [**Multichain Smart Contract**](#multichain-smart-contract) - Receives requests to sign a transaction for other blockchains
3. [**Multiparty Computation Service**](#multi-party-computation-service) Third-party service providing signatures to the contract

<hr class="subsection" />

### 1. Create Payload
### Derivation Paths: One Account, Multiple Chains

The first step is to construct a payload (transaction, message, data, etc.) for the target blockchain platform. This variates depending on the target blockchain, but in general, it's a hash of the message or transaction to be signed.
Chain Signatures link NEAR accounts to other blockchain accounts using [Additive Key Derivation](https://eprint.iacr.org/2021/1330#:~:text=Additive%20key%20derivation%20is%20a,Improvement%20Proposal%2032%20(BIP32)) _(a simple mechanism for deriving many subkeys from a single master key)_. These keys are generated using `derivation paths` _(or `paths` for short)_.

<hr class="subsection" />
A `derivation path` is simply a string _(e.g. `ethereum-1`, `ethereum-2`, etc)_ that in conjunction with the NEAR account derives a unique address on the target blockchain.

### 2. Signature Request
For example, we can derive multiple Ethereum accounts from `example.near` by using different paths:

Once a payload is created and ready to sign, a signature request is made by calling `sign` on the deployed smart contract `multichain.near`. This method takes two parameters:
1. **payload:** The payload (transaction, message, data, etc.) to be signed for the target blockchain
2. **path:** A name representing the account that should be used to sign the payload (e.g. ethereum-1)
1. `example.near` + `ethereum-1` = `0x1b48b83a308ea4beb845db088180dc3389f8aa3b`
2. `example.near` + `ethereum-2` = `0x99c5d3025dc736541f2d97c3ef3c90de4d221315`
3. `example.near` + `...` = `0x...`

```rust
pub fn sign(payload: [u8; 32], path: String) -> Signature
```
_[See the full code in Github](https://github.com/near/mpc-recovery/blob/bc85d66833ffa8537ec61d0b22cd5aa96fbe3197/contract/src/lib.rs#L263)_
This external address is deterministically derived using the `path` (`example.near` + `ethereum-1`) and the MPC service's public key.

For example, a user could request a signature to `send 0.1 ETH to 0x060f1...` **(payload)** using the `ethereum-1` account **(path)**.
:::info

After a request is made, the `sign` method starts recursively calling itself in order to wait while the [MPC signing service](#3-mpc-signing-service) signs the payload.
See [**Create a Chain Signature - how the derivation is implemented**](../../8.abstraction/chain-signatures.md#1-deriving-the-foreign-address) for an example implementation

<details>
<summary> A Contract Recursively Calling Itself? </summary>
:::

NEAR smart contracts are unable to halt execution and await the completion of a process. To solve this, one can make the contract call itself again and again checking on each iteration if the result is ready.
<hr class="subsection" />

Note that each call will take one block, and thus result on ~1s of waiting. After some time the contract will either return a result - since somebody external provided it - or run out of GAS waiting.
### Multichain Smart Contract

</details>
A deployed multichain smart contract is used to request signatures for transactions on other blockchains.

<hr class="subsection" />
This contract has a `sign` method that takes two parameters:

### 3. MPC Signing Service
1. The `payload` (transaction) to be signed for the target blockchain
2. The `path` that identifies the account you want to use to sign the transaction.

A multi-party computation service (`MPC service`, see more below) is constantly listening for signature requests (i.e. users calling the `sign` method). When a call is detected, the service will:
For example, a user could request a signature to `send 0.1 ETH to 0x060f1...` **(transaction)** using the `ethereum-1` account **(path)**.

1. Use the `accountId` of the requester, and the `path` (in our example, `ethereum-1`) to derive a key
2. Sign the `payload` (in our example, a transaction transferring ETH) using the stored key
3. Call the contract `multichain.near`, storing the resulting `Signature`
After a request is made, the `sign` method starts recursively calling itself to wait while the [MPC signing service](#multi-party-computation-service-mpc) signs the transaction.

:::tip
Every time an account makes a signature request using the same `path`, the same `key` will be derived. This allows to use always the same account to sign different transactions.
:::
Once the signature is ready, the contract gains access to it and returns it to the user. This signature is a valid signed transaction that can be readily sent to the target blockchain to be executed.

<details>
<summary> What is an MPC Service? </summary>
<summary> A Contract Recursively Calling Itself? </summary>

MPC (multi-party computation) allows independent actors to do shared computations on private information, without revealing secrets to each-other.
NEAR smart contracts are unable to halt execution and await the completion of a process. To solve this, one can make the contract call itself again and again checking on each iteration to see if the result is ready.

NEAR uses its own MPC service to safely sign transactions for other chains on behalf of the user. In practice, **no single node** on the MPC can **sign by itself** since they do **not hold the user's keys**. Instead, nodes create signature-shares which are aggregated through multiple rounds to jointly sign the payload.
**Note:** Each call will take one block which equates to ~1 second of waiting. After some time the contract will either return a result that an external party provided or return an error running out of GAS waiting.

Generally, MPC signing services work by sharing a master key, which needs to be re-created each time a node joins or leaves. NEAR's MPC service allows for nodes to safely join and leave, without needing to re-derive a master key.
</details>

If you want to learn more about how MPC works, we recommend to [**check this article**](https://www.zellic.io/blog/mpc-from-scratch/)
:::info

</details>
See [**Create a Chain Signature - requesting the signature**](../../8.abstraction/chain-signatures.md#3-requesting-the-signature) for an example implementation

:::

<hr class="subsection" />

### 4. Relaying the Signature
### Multi-Party Computation Service

The essence of Multi-Party Computation (MPC) is to enable independent parties to perform shared computations on private information without revealing secrets to each other. In practice, this system can be used with blockchain platforms to safely sign a transaction on behalf of a user without ever having to expose a private key.

NEAR's MPC service is comprised of several independent nodes, **none of which can sign by itself**, but instead create **signature-shares** that are **aggregated through multiple rounds** to **jointly** sign a transaction.

This service continuously listens for signature requests _(i.e. users calling the `sign` method on the `multichain` smart contract)_ and when a call is detected the MPC service:

At this point - assuming the contract didn't run out of gas waiting - the contract will return the response for the signature request. This response is a valid signed transaction that can be readily sent to the target blockchain to be executed.
1. Asks its nodes to jointly derive a signature for the `payload` using the account identified by the `path`
2. Once complete, call the `multichain` contract to store the resulting `Signature`

To simplify relaying the transaction, we are building an indexer that will automatically capture the signature, and submit it to the target chain using a multi-chain [relayer](relayers.md).
:::info A Custom MPC Service

Generally, MPC signing services work by sharing a master key, which needs to be re-created each time a node joins or leaves.

NEAR's MPC service allows for nodes to safely join and leave, without needing to re-derive a master key
:::

:::tip
A multi-chain [relayer](relayers.md) is a service that knows how to relay signed transactions into their target networks so they are executed on-chain.

Want to learn more about the mathematics that enable MPC? [**Check this awesome article**](https://www.zellic.io/blog/mpc-from-scratch/)

:::

<!-- ### Workflow
## Concluding Remarks

Chain Signatures are a powerful tool that allows NEAR accounts to control accounts on other blockchains. This is a fundamental step towards enabling true ownership of cross-chain data and assets.

For the user, the process is made completely **on chain**, since they only need to make a call to a smart contract and wait for the response.

- A NEAR account requests a payload to be signed by a deployed [MPC](#multi-party-computation-mpc) smart contract
> This request is performed by calling `sign` and passing the payload (hash from a message or transaction)
- A key is derived from the MPC root key using `account_id` and derivation path. (this ensures that it will be the same key if the two parameters are the same)
- Once the client gets the signature, it can send the transaction to a relayer
> In a future release, an indexing service will listen to all `sign` events from the MPC contract and will trigger a multi-chain relayer -->
Thanks to `derivation paths`, a single NEAR account can control **multiple accounts** on different blockchains, and thanks to the MPC service, the user can be sure that **nobody but themselves** can request signatures for those accounts.
Loading

0 comments on commit 60a99d1

Please sign in to comment.