Skip to content

Commit

Permalink
doc: update zklogin multisig docs (MystenLabs#17501)
Browse files Browse the repository at this point in the history
## Description 

updated docs re multisig + zklogin, also graphq endpoint on zklogin
signature verifiy.
## Test plan 

How did you test the new or updated feature?

---

## Release notes

Check each box that your changes affect. If none of the boxes relate to
your changes, release notes aren't required.

For each box you select, include information after the relevant heading
that describes the impact of your changes that a user might notice and
any actions they must take to implement updates.

- [ ] Protocol: 
- [ ] Nodes (Validators and Full nodes): 
- [ ] Indexer: 
- [ ] JSON-RPC: 
- [ ] GraphQL: 
- [ ] CLI: 
- [ ] Rust SDK:

---------

Co-authored-by: Ronny Roland <[email protected]>
  • Loading branch information
joyqvq and ronny-mysten authored May 4, 2024
1 parent 05d1ea7 commit 3a062ec
Show file tree
Hide file tree
Showing 8 changed files with 266 additions and 168 deletions.
147 changes: 2 additions & 145 deletions docs/content/concepts/cryptography/transaction-auth/multisig.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -27,149 +27,6 @@ resulting in a single signature payload, making it indistinguishable from a sing
![Supported structures in Sui multisig](images/sui_multisig_structures.png 'Supported structures in Sui multisig')
_Multisig structures supported in Sui._

## Example workflow
## Related links

The following steps demonstrate how to create a multisig transaction and then submit it against a local network using the [Sui CLI](/references/cli.mdx). A transaction can be the transfer of an object, the publish or upgrade of a package, the payment of SUI, and so on. To learn how to set up a local network, see [Connect to a Local Network](/guides/developer/getting-started/local-network.mdx).

### Step 1: Create keys

Use the following command to generate a Sui address and key for each supported key scheme and add it to the `sui.keystore`, then list the keys.

Use `sui client` to create Sui addresses of different key schemes.

```shell
sui client new-address ed25519
sui client new-address secp256k1
sui client new-address secp256r1
```

### Step 2: Add keys to Sui keystore

Use `sui keytool` to list the signatures you created in the previous step.

```shell
sui keytool list
```

The response resembles the following, but displays actual addresses, keys, and peer IDs:

```shell
╭────────────────────────────────────────────────────────────────────────────────────────────╮
│ ╭─────────────────┬──────────────────────────────────────────────────────────────────────╮ │
│ │ suiAddress │ <SUI-ADDRESS> │ │
│ │ publicBase64Key │ <PUBLIC-KEY> │ │
│ │ keyScheme │ ed25519 │ │
│ │ flag │ 0 │ │
│ │ peerId │ <PEER-ID> │ │
│ ╰─────────────────┴──────────────────────────────────────────────────────────────────────╯ │
│ ╭─────────────────┬──────────────────────────────────────────────────────────────────────╮ │
│ │ suiAddress │ <SUI-ADDRESS> │ │
│ │ publicBase64Key │ <PUBLIC-KEY> │ │
│ │ keyScheme │ secp256k1 │ │
│ │ flag │ 0 │ │
│ │ peerId │ <PEER-ID> │ │
│ ╰─────────────────┴──────────────────────────────────────────────────────────────────────╯ │
│ ╭─────────────────┬──────────────────────────────────────────────────────────────────────╮ │
│ │ suiAddress │ <SUI-ADDRESS> │ │
│ │ publicBase64Key │ <PUBLIC-KEY> │ │
│ │ keyScheme │ secp256r1 │ │
│ │ flag │ 0 │ │
│ │ peerId │ <PEER-ID> │ │
│ ╰─────────────────┴──────────────────────────────────────────────────────────────────────╯ │
╰────────────────────────────────────────────────────────────────────────────────────────────╯
```

## Step 3: Create a multisig address

To create a multisig address, input a list of public keys to use for the multisig address and a list of their corresponding weights and the threshold (replacing `<VARIABLES>` with actual values).

```shell
sui keytool multi-sig-address --pks <PUBLIC-KEY-ED25519> <PUBLIC-KEY-SECPK1> <PUBLIC-KEY-SECP256R1> --weights 1 2 3 --threshold 3
```

The response resembles the following:

```
╭─────────────────┬────────────────────────────────────────────────────────────────────────────────────╮
│ multisigAddress │ <MULTISIG-ADDRESS> │
│ multisig │ ╭────────────────────────────────────────────────────────────────────────────────╮ │
│ │ │ ╭─────────────────┬──────────────────────────────────────────────────────────╮ │ │
│ │ │ │ address │ <SUI-ADDRESS> │ │ │
│ │ │ │ publicBase64Key │ <PUBLIC-KEY> │ │ │
│ │ │ │ weight │ 1 │ │ │
│ │ │ ╰─────────────────┴──────────────────────────────────────────────────────────╯ │ │
│ │ │ ╭─────────────────┬──────────────────────────────────────────────────────────╮ │ │
│ │ │ │ address │ <SUI-ADDRESS> │ │ │
│ │ │ │ publicBase64Key │ <PUBLIC-KEY> │ │ │
│ │ │ │ weight │ 2 │ │ │
│ │ │ ╰─────────────────┴──────────────────────────────────────────────────────────╯ │ │
│ │ │ ╭─────────────────┬──────────────────────────────────────────────────────────╮ │ │
│ │ │ │ address │ <SUI-ADDRESS> │ │ │
│ │ │ │ publicBase64Key │ <PUBLIC-KEY> │ │ │
│ │ │ │ weight │ 3 │ │ │
│ │ │ ╰─────────────────┴──────────────────────────────────────────────────────────╯ │ │
│ │ ╰────────────────────────────────────────────────────────────────────────────────╯ │
╰─────────────────┴────────────────────────────────────────────────────────────────────────────────────╯
```

## Step 4: Send objects to a multisig address

This example requests gas from a local network using the default URL following the guidance in [Connect to a Local Network](/guides/developer/getting-started/local-network.mdx). If following along, be sure to replace `<MULTISIG-ADDR>` with the address you receive in the previous step.

```shell
curl --location --request POST 'http://127.0.0.1:9123/gas' --header 'Content-Type: application/json' --data-raw "{ \"FixedAmountRequest\": { \"recipient\": \"<MULTISIG-ADDR>\" } }"
```

The response resembles the following:

```
{"transferred_gas_objects":[{"amount":200000,"id":"<OBJECT-ID>", ...}]}
```

## Step 5: Serialize any transaction

This section demonstrates how to use an object that belongs to a multisig address and serialize a transfer to be signed. The `tx_bytes` value can be any serialized transaction data where the sender is the multisig address. Use the `--serialize-unsigned-transaction` flag for supported commands in `sui client -h` (`publish`, `upgrade`, `call`, `transfer`, `transfer-sui`, `pay`, `pay-all-sui`, `pay-sui`, `split`, `merge-coin`) to output the Base64 encoded transaction bytes.

```shell
sui client transfer --to <SUI-ADDRESS> --object-id <OBJECT-ID> --gas-budget <GAS-AMOUNT> --serialize-unsigned-transaction

Raw tx_bytes to execute: <TX_BYTES>
```

## Step 6: Sign the transaction with two keys

Use the following code sample to sign the transaction with two keys in `sui.keystore`. You can do this with other tools as long as you serialize it to `flag || sig || pk`.

```shell
sui keytool sign --address <SUI-ADDRESS> --data <TX_BYTES>

Raw tx_bytes to execute: <TX_BYTES>
Serialized signature (`flag || sig || pk` in Base64): $SIG_1

sui keytool sign --address <SUI-ADDRESS> --data <TX_BYTES>

Raw tx_bytes to execute: <TX_BYTES>
Serialized signature (`flag || sig || pk` in Base64): $SIG_2
```

## Step 7: Combine individual signatures into a multisig

This sample demonstrates how to combine the two signatures:

```shell
sui keytool multi-sig-combine-partial-sig --pks <PUBLIC-KEY-1> <PUBLIC-KEY-2> <PUBLIC-KEY-3> --weights 1 2 3 --threshold 3 --sigs <SIGNATURE-1> <SIGNATURE-2>

multisig address: <MULTISIG-ADDRESS> # Informational
multisig parsed: <HUMAN-READABLE-STRUCT> # Informational
multisig serialized: <SERIALIZED-MULTISIG>
```

You need only the signatures of the participating signers whose sum of weights `>=k`. You must provide all public keys and their weights, and the threshold that defined the multisig address.

## Step 8: Execute a transaction with multisig

Use `sui client` to execute a transaction using multisig:

```shell
sui client execute-signed-tx --tx-bytes <TX_BYTES> --signatures <SERIALIZED-MULTISIG>
```
- [Multisig Authentication](../../../guides/developer/cryptography/multisig.mdx): Guide on how to create a multisig transaction.
27 changes: 15 additions & 12 deletions docs/content/concepts/cryptography/transaction-auth/signatures.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,27 @@ The `flag` is a 1-byte representation corresponding to the signature scheme that
| ECDSA Secp256k1 | 0x01 |
| ECDSA Secp256r1 | 0x02 |
| multisig | 0x03 |
| zkLogin | 0x05 |

The `sig` bytes are the compressed bytes representation of the signature instead of DER encoding. The following table lists the expected size of each format:

| Scheme | Signature |
| --------------- | ------------------------------------------ |
| Pure Ed25519 | Compressed, 64 bytes |
| ECDSA Secp256k1 | Non-recoverable, compressed, 64 bytes |
| ECDSA Secp256r1 | Non-recoverable, compressed, 64 bytes |
| multisig | BCS serialized all signatures, size varies |
| Scheme | Signature |
| --------------- | ------------------------------------------------------------------------------|
| Pure Ed25519 | Compressed, 64 bytes |
| ECDSA Secp256k1 | Non-recoverable, compressed, 64 bytes |
| ECDSA Secp256r1 | Non-recoverable, compressed, 64 bytes |
| multisig | BCS serialized all signatures, size varies |
| zkLogin | BCS serialized zkLogin inputs, max epoch and ephemeral signature, size varies |

The `pk` bytes are the bytes representation of the public key corresponding to the signature.

| Scheme | Public key |
| --------------- | --------------------------------------------------------- |
| Pure Ed25519 | Compressed, 32 bytes |
| ECDSA Secp256k1 | Compressed, 33 bytes |
| ECDSA Secp256r1 | Compressed, 33 bytes |
| multisig | BCS serialized all participating public keys, size varies |
| Scheme | Public key |
| --------------- | ------------------------------------------------------------------------------------ |
| Pure Ed25519 | Compressed, 32 bytes |
| ECDSA Secp256k1 | Compressed, 33 bytes |
| ECDSA Secp256r1 | Compressed, 33 bytes |
| multisig | BCS serialized all participating public keys, size varies |
| zkLogin | Concatenation of iss length, iss bytes, address seed padded to 32-bytes, size varies |

## Signature requirements {#signature-requirements}

Expand Down
28 changes: 18 additions & 10 deletions docs/content/concepts/cryptography/zklogin.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ Locally unique and never reassigned identifier within the issuer for the end use

### JSON Web Key (JWK)

A JSON data structure that represents a set of public keys for an OP. A public endpoint (e.g. https://www.googleapis.com/oauth2/v3/certs) can be queried to retrieve the valid public keys corresponding to `kid` for the provider. Upon matching with the `kid` in the header of a JWT, the JWT can be verified against the payload and its corresponding JWK. In Sui, all authorities call the JWK endpoints independently, and update the latest view of JWKs for all supported providers during protocol upgrades. The correctness of JWKs is guaranteed by the quorum (2f+1) of validator stake.
A JSON data structure that represents a set of public keys for an OP. A public endpoint (as in https://www.googleapis.com/oauth2/v3/certs) can be queried to retrieve the valid public keys corresponding to `kid` for the provider. Upon matching with the `kid` in the header of a JWT, the JWT can be verified against the payload and its corresponding JWK. In Sui, all authorities call the JWK endpoints independently, and update the latest view of JWKs for all supported providers during protocol upgrades. The correctness of JWKs is guaranteed by the quorum (2f+1) of validator stake.

### JSON Web Token (JWT)

Expand Down Expand Up @@ -296,23 +296,31 @@ The key differentiators that zkLogin brings to Sui are:

1. Native Support in Sui: Unlike other solutions that are blockchain agnostic, zkLogin is deployed just for Sui. This means a zkLogin transaction can be combined with Multisig and sponsored transactions seamlessly.

2. Self-Custodial without additional trust: We leverage the nonce field in JWT to commit to ephemeral public key, so no persistent private key management is required with any trusted parties. In addition, the JWK itself is an oracle agreed upon by the quorum of stakes by the validators with trusting any source of authority.
1. Self-Custodial without additional trust: We leverage the nonce field in JWT to commit to ephemeral public key, so no persistent private key management is required with any trusted parties. In addition, the JWK itself is an oracle agreed upon by the quorum of stakes by the validators with trusting any source of authority.

3. Full privacy: Nothing is required to submit on-chain except the ZK proof and the ephemeral signature.
1. Full privacy: Nothing is required to submit on-chain except the ZK proof and the ephemeral signature.

4. Compatible with Existing Identity Providers: zkLogin is compatible with providers that adopt OpenID Connect. No need to trust any intermediate identity issuers or verifiers other than the OAuth providers themselves.
1. Compatible with Existing Identity Providers: zkLogin is compatible with providers that adopt OpenID Connect. No need to trust any intermediate identity issuers or verifiers other than the OAuth providers themselves.

### How to verify a zkLogin signature off chain?

The following options support a zkLogin signature over either transaction data or personal message.
The following options support a zkLogin signature over either transaction data or personal message using the JWK state on Sui and current epoch.

1. Use keytool: See usage in keytool.
1. Use Sui Typescript SDK. This initializes a GraphQL client and calls the endpoint under the hood.

```bash
$SUI_BINARY keytool zk-login-sig-verify -h
```
1. Use the GraphQL endpoint directly: `https://sui-[network].mystenlabs.com/graphql`, changing `[network]` to the appropriate value. See the <a href="/references/sui-api/sui-graphql/reference/api/queries/verify-zklogin-signature" data-noBrokenLinkCheck="true">GraphQL documentation</a> for more details. This is recommended if you do not plan to run any servers or handle any JWK rotations.

2. Use a self hosted server endpoint: See usage in [zklogin-verifier](https://github.com/MystenLabs/zklogin-verifier).
1. Use the [Sui Keytool CLI](../../references/cli/keytool.mdx). This is recommended for debug usage.

```sh
$SUI_BINARY keytool zk-login-sig-verify --sig $ZKLOGIN_SIG --bytes $BYTES --intent-scope 3 --network devnet --curr-epoch 3
```

1. Use a self-hosted server endpoint and call this endpoint, as described in [zklogin-verifier](https://github.com/MystenLabs/zklogin-verifier). This provides logic flexibility.

### Can I use zkLogin inside a multisig wallet?

Yes. See the [Multisig Guide](../../guides/developer/cryptography/multisig.mdx) for more details.

## Related links

Expand Down
Loading

0 comments on commit 3a062ec

Please sign in to comment.