-
Notifications
You must be signed in to change notification settings - Fork 11.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding new topics on signing, new Cryptography node in left nav (#9962)
## Description Describe the changes or additions included in this PR. ## Test Plan How did you test the new or updated feature? --- If your changes are not user-facing and not a breaking change, you can skip the following section. Otherwise, please indicate what changed, and then add to the Release Notes section as highlighted during the release process. ### Type of Change (Check all that apply) - [ ] user-visible impact - [ ] breaking change for a client SDKs - [ ] breaking change for FNs (FN binary must upgrade) - [ ] breaking change for validators or node operators (must upgrade binaries) - [ ] breaking change for on-chain data layout - [ ] necessitate either a data wipe or data migration ### Release notes --------- Co-authored-by: ronny-mysten <118224482+ronny-mysten@users.noreply.github.com>
- Loading branch information
1 parent
1ed5b2c
commit 6780cf6
Showing
6 changed files
with
298 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
--- | ||
title: Sui Cryptography | ||
--- | ||
|
||
Learn about cryptography in Sui: | ||
* [Sui Intent Signing](../cryptography/sui-intent-signing.md) | ||
* [Sui Offline Signing](../cryptography/sui-offline-signing.md) | ||
* [Sui Multi-Signature](../cryptography/sui-multisig.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
--- | ||
title: Sui Intent Signing | ||
--- | ||
|
||
In Sui, an intent is a compact struct that serves as the domain separator for a message that a signature commits to. The data that the signature commits to is an intent message. All signatures in Sui must commit to an intent message, instead of the message itself. | ||
|
||
## Motivation | ||
|
||
In previous releases, Sui used a special `Signable` trait that attached the Rust struct name as a prefix to the serialized data. This is not ideal because it's: | ||
* **Not compact:** The prefix `TransactionData::` is significantly larger than 1 byte. | ||
* **Not user-friendly:** Non-Rust applications need to maintain a list of Rust-struct names. | ||
|
||
The intent signing standard provides a compact domain separator to the data being signed for both user signatures and authority signatures. It has several benefits, including: | ||
|
||
* The intent scope is replaced by an u8 representation instead of a Rust struct tag name string. | ||
* In addition to the intent scope, other important domain separators can be committed as well (e.g. intent version, app id). | ||
* The data itself no longer needs to implement the `Signable` trait, it just needs to implement `Serialize`. | ||
* All signatures can adopt the same intent message structure, including both user signatures (only to commit to `TransactionData`) and authority signature (commits to all internal intent scopes such as `TransactionEffects`, `ProofOfPossession`, and `SenderSignedTransaction`). | ||
|
||
## Structs | ||
|
||
The `IntentMessage` struct consists of the intent and the serialized data value. | ||
|
||
```rust | ||
pub struct IntentMessage<T> { | ||
pub intent: Intent, | ||
pub value: T, | ||
} | ||
``` | ||
|
||
To create an intent struct, include the `IntentScope` (what the type of the message is), `IntentVersion` (what version the network supports), and `AppId` (what application that the signature refers to). | ||
|
||
```rust | ||
pub struct Intent { | ||
scope: IntentScope, | ||
version: IntentVersion, | ||
app_id: AppId, | ||
} | ||
``` | ||
|
||
To see a detailed definition for each field, see each enum definition [in the source code](https://github.com/MystenLabs/sui/blob/0dc1a38f800fc2d8fabe11477fdef702058cf00d/crates/sui-types/src/intent.rs). | ||
|
||
The serialization of an `Intent` is a 3-byte array where each field is represented by a byte. | ||
|
||
The serialization of an `IntentMessage<T>` is the 3 bytes of the intent concatenated with the BCS serialized message. | ||
|
||
## User Signature | ||
|
||
To create a user signature, construct an intent message first, and create the signature over the BCS serialized value of the intent message (`intent || message`). | ||
|
||
Here is an example in Rust: | ||
|
||
```rust | ||
let intent = Intent::default(); | ||
let intent_msg = IntentMessage::new(intent, data); | ||
let signature = Signature::new_secure(&intent_msg, signer); | ||
``` | ||
|
||
Here is an example in Typescript: | ||
|
||
```typescript | ||
const intentMessage = messageWithIntent( | ||
IntentScope.TransactionData, | ||
transactionBytes, | ||
); | ||
const signature = await this.signData(intentMessage); | ||
``` | ||
|
||
## Authority Signature | ||
|
||
The authority signature is created using the protocol key. The data that it commits to is also an intent message `intent || message`. See all available intent scopes [in the source code](https://github.com/MystenLabs/sui/blob/0dc1a38f800fc2d8fabe11477fdef702058cf00d/crates/sui-types/src/intent.rs#L66) | ||
|
||
# Implementation | ||
|
||
1. [Struct and enum definitions](https://github.com/MystenLabs/sui/blob/0dc1a38f800fc2d8fabe11477fdef702058cf00d/crates/sui-types/src/intent.rs) | ||
2. [Test](https://github.com/MystenLabs/sui/blob/d009e82fa35bda4f2b3e7a86a9529d36c32a8159/crates/sui-types/src/unit_tests/intent_tests.rs) | ||
3. User transaction intent signing [PR 1](https://github.com/MystenLabs/sui/pull/6445), [PR 2](https://github.com/MystenLabs/sui/pull/8321) | ||
4. Authority intent signing [PR 1](https://github.com/MystenLabs/sui/pull/8154), [PR 2](https://github.com/MystenLabs/sui/pull/8726) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
--- | ||
title: Sui Multi-Signature | ||
--- | ||
|
||
Sui supports `k` out of `n` multi-signature (multisig) transactions where `n <= 10`. A multisig transaction is one that requires more than one private key to authorize it. This topic demonstrate the workflow to create a multisig transaction in Sui, and then submit it using the Sui CLI against a local network. To learn how to set up a local network, see [Sui Local Network](../build/sui-local-network.md). | ||
|
||
## Step 1: Add keys to Sui keystore | ||
|
||
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. | ||
|
||
```shell | ||
sui client new-address ed25519 | ||
sui client new-address secp256k1 | ||
sui client new-address secp256r1 | ||
|
||
sui keytool list | ||
``` | ||
|
||
The response resembles the following, but displays actual addresses and keys: | ||
|
||
``` | ||
Sui Address | Public Key (Base64) | Scheme | ||
-------------------------------------------------------------------------- | ||
$ADDR_1 | $PK_1 | secp256r1 | ||
$ADDR_2 | $PK_2 | secp256k1 | ||
$ADDR_3 | $PK_3 | ed25519 | ||
``` | ||
|
||
## Step 2: Create a multisig address | ||
|
||
To create a multisig address, input a list of public keys to use for the multisig address and list their corresponding weights. | ||
|
||
```shell | ||
sui keytool multi-sig-address --pks $PK_1 $PK_2 $PK_3 --weights 1 2 3 --threshold 3 | ||
Multisig address: $MULTISIG_ADDR | ||
``` | ||
|
||
The response resembles the following: | ||
|
||
``` | ||
Participating parties: | ||
Sui Address | Public Key (Base64)| Weight | ||
------------------------------------------ | ||
$ADDR_1 | $PK_1 | 1 | ||
$ADDR_2 | $PK_2 | 2 | ||
$ADDR_3 | $PK_3 | 3 | ||
``` | ||
|
||
## Step 3: Send objects to a multisig address | ||
|
||
This example requests gas from a local network using the default URL following the guidance in [Sui Local Network](../build/sui-local-network.md). | ||
|
||
|
||
```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 3: Serialize a transaction | ||
|
||
This section demonstrates how to use an object that belongs to a multisig address and serialize a transfer to be signed. This can be any serialized transaction data where the sender is the multisig address. | ||
|
||
```shell | ||
sui client serialize-transfer-sui --to $$MULTISIG_ADDR --sui-coin-object-id $OBJECT_ID --gas-budget 1000 | ||
|
||
Raw tx_bytes to execute: $TX_BYTES | ||
``` | ||
|
||
## Step 4: 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 $ADDR_1 --data $TX_BYTES | ||
|
||
Raw tx_bytes to execute: $TX_BYTES | ||
Serialized signature (`flag || sig || pk` in Base64): $SIG_1 | ||
|
||
sui keytool sign --address $ADDR_2 --data $TX_BYTES | ||
|
||
Raw tx_bytes to execute: $TX_BYTES | ||
Serialized signature (`flag || sig || pk` in Base64): $SIG_2 | ||
``` | ||
|
||
## Step 5: Combine individual signatures into a multisig | ||
|
||
This sample demonstrates how to combine the two signatures: | ||
```shell | ||
sui keytool multi-sig-combine-partial-sig --pks $PK_1 $PK_2 $PK_3 --weights 1 2 3 --threshold 3 --sigs $SIG_1 $SIG_2 | ||
``` | ||
|
||
## Step 6: Execute a transaction with multisig | ||
|
||
This sample demonstrates how to execute a transaction using multisig: | ||
```shell | ||
sui client execute-signed-tx --tx-bytes $TX_BYTES --signature $SERIALIZED_MULTISIG | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
--- | ||
title: Offline Signing | ||
--- | ||
|
||
Sui supports offline signing, which is signing transactions using a device not connected to a Sui network, or in a wallet implemented in a different programming language without relying on the Sui key store. The steps to implement offline signing include: | ||
|
||
1. Serialize the data for signing. | ||
1. Sign the serialized data. Put the serialized data in a location to sign (such as the wallet of your choice, or tools in other programming languages) and to produce a signature with the corresponding public key. | ||
1. Execute the signed transaction. | ||
|
||
## Serialize data for a transfer | ||
|
||
You must serialize transaction data following [Binary Canonical Serialization](https://crates.io/crates/bcs) (BCS). It is supported in [other languages](https://github.com/zefchain/serde-reflection#language-interoperability). | ||
|
||
The following example demonstrates how to to serialize data for a transfer using the Sui CLI. This returns serialized transaction data in Base64. Submit the raw transaction to execute as `tx_bytes`. | ||
|
||
```shell | ||
sui client serialize-transfer-sui --to $ADDRESS --sui-coin-object-id $OBJECT_ID --gas-budget 1000 | ||
|
||
Raw tx_bytes to execute: $TX_BYTES | ||
``` | ||
|
||
## Sign the serialized data | ||
|
||
You can sign the data using the device and programming language you choose. Sui accepts signatures for pure ed25519, ECDSA secp256k1, ECDSA secp256r1 and native multisig. To learn more about multisig, see [Sui Multi-Signature](sui-multisig.md). | ||
|
||
The signature is committed to an intent message of the transaction data. To learn how to construct an intent message, see [Sui Intent signing](sui-intent_signing.md). | ||
|
||
Before you pass it in to the signing API, you must first hash the intent message to 32 bytes using Blake2b. To be compatible with existing standards and hardware secure modules (HSMs), the signing algorithms perform additional hashing internally. For ECDSA Secp256k1 and Secp256r1, you must use SHA-2 SHA256 as the internal hash function. For pure Ed25519, you must use SHA-512. | ||
|
||
Additional signature requirements: | ||
|
||
An accepted ECDSA secp256k1 and secp256r1 signature must follow: | ||
1. The internal hash used by ECDSA must be SHA256 [SHA-2](https://en.wikipedia.org/wiki/SHA-2) hash of the transaction data. We use SHA256 because it is supported by [Apple](https://developer.apple.com/forums/thread/89619), HSMs, and [cloud](https://developer.apple.com/forums/thread/89619), and it is widely adopted by [Bitcoin](https://en.bitcoin.it/wiki/Elliptic_Curve_Digital_Signature_Algorithm). | ||
1. The signature must be of length 64 bytes in the form of `[r, s]` where the first 32 bytes are `r`, the second 32 bytes are `s`. | ||
1. The `r` value can be between 0x1 and 0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364140 (inclusive). | ||
1. The `s` value must be in the lower half of the curve order. If the signature is too high, convert it to a lower `s` according to [BIP-0062](https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki#low-s-values-in-signatures) with the corresponding curve orders using `order - s`. For secp256k1, the curve order is `0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141`. For secp256r1, the curve order is `0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551` defined in [Standards for Efficient Cryptography](https://secg.org/SEC2-Ver-1.0.pdf). | ||
1. Ideally, the signature must be generated with deterministic nonce according to [RFC6979](https://www.rfc-editor.org/rfc/rfc6979). | ||
|
||
An accepted pure ed25519 signature follows: | ||
1. The signature must be produced according to [RFC 8032](https://www.rfc-editor.org/rfc/rfc8032.html#section-5.1.6). The internal hash used is SHA-512. | ||
1. The signature must be valid according to [ZIP215](https://github.com/zcash/zips/blob/main/zip-0215.rst). | ||
|
||
This example uses the `keytool` command to sign, using the ed25519 key corresponding to the provided address stored in `sui.keystore`. This commands outputs the signature, the public key, and the flag encoded in Base64. This command is backed by [fastcrypto](https://crates.io/crates/fastcrypto). | ||
|
||
```shell | ||
sui keytool sign --address $ADDRESS --data $TX_BYTES | ||
|
||
Signer address: $ADDRESS | ||
Raw tx_bytes to execute: $TX_BYTES | ||
Intent: Intent { scope: TransactionData, version: V0, app_id: Sui } | ||
Raw intent message: $INTENT_MSG | ||
Digest to sign: $DIGEST | ||
Serialized signature (`flag || sig || pk` in Base64): $SERIALIZED_SIG | ||
``` | ||
To ensure the signature produced offline matches with Sui's validity rules for testing purposes, you can import the mnemonics to `sui.keystore` using `sui keytool import`. You can then sign with it using `sui keytool sign` and then compare the signature results. Additionally, you can find test vectors in `~/sui/sdk/typescript/test/e2e/raw-signer.test.ts`. | ||
To verify a signature against the cryptography library backing Sui when debugging, see [sigs-cli](https://github.com/MystenLabs/fastcrypto/blob/4cf71bd8b3a373495beeb77ce81c27827516c218/fastcrypto-cli/src/sigs_cli.rs). | ||
## Execute the signed transaction | ||
After you obtain the serialized signature, you can submit it using the execution transaction command. This command takes `--tx-bytes` as the raw transaction bytes to execute (see output of `sui client serialize-transfer-sui`) and the serialized signature (Base64 encoded `flag || sig || pk`, see output of `sui keytool sign`). This executes the signed transaction and returns the certificate and transaction effects if successful. | ||
```shell | ||
sui client execute-signed-tx --tx-bytes $TX_BYTES --signatures $SERIALIZED_SIG | ||
----- Certificate ---- | ||
Transaction Hash: $TX_ID | ||
Transaction Signature: $SIGNSTURE | ||
Signed Authorities Bitmap: RoaringBitmap<[0, 1, 3]> | ||
Transaction Kind : Transfer SUI | ||
Recipient : $ADDRESS | ||
Amount: Full Balance | ||
----- Transaction Effects ---- | ||
Status : Success | ||
Mutated Objects: | ||
- ID: $OBJECT_ID , Owner: Account Address ( $ADDRESS ) | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters