Skip to content

Commit b9f39c9

Browse files
authored
Merge PR #6359: Updates to ADR-020 (protobuf signing)
1 parent 0d9faec commit b9f39c9

File tree

1 file changed

+50
-30
lines changed

1 file changed

+50
-30
lines changed

docs/architecture/adr-020-protobuf-transaction-encoding.md

Lines changed: 50 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- 2020 April 13: Added details on interface `oneof` handling
88
- 2020 April 30: Switch to `Any`
99
- 2020 May 14: Describe public key encoding
10+
- 2020 June 08: Store `TxBody` and `AuthInfo` as bytes in `SignDoc`; Document `TxRaw` as broadcast and storage type.
1011

1112
## Status
1213

@@ -56,24 +57,50 @@ package cosmos_sdk.v1;
5657
message Tx {
5758
TxBody body = 1;
5859
AuthInfo auth_info = 2;
60+
// A list of signatures that matches the length and order of AuthInfo's signer_infos to
61+
// allow connecting signature meta information like public key and signing mode by position.
62+
repeated bytes signatures = 3;
63+
}
64+
65+
// A variant of Tx that pins the signer's exact binary represenation of body and
66+
// auth_info. This is used for signing, broadcasting and verification. The binary
67+
// `serialize(tx: TxRaw)` is stored in Tendermint and the hash `sha256(serialize(tx: TxRaw))`
68+
// becomes the "txhash", commonly used as the transaction ID.
69+
message TxRaw {
70+
// A protobuf serialization of a TxBody that matches the representation in SignDoc.
71+
bytes body = 1;
72+
// A protobuf serialization of an AuthInfo that matches the representation in SignDoc.
73+
bytes auth_info = 2;
74+
// A list of signatures that matches the length and order of AuthInfo's signer_infos to
75+
// allow connecting signature meta information like public key and signing mode by position.
5976
repeated bytes signatures = 3;
6077
}
6178
6279
message TxBody {
80+
// A list of messages to be executed. The required signers of those messages define
81+
// the number and order of elements in AuthInfo's signer_infos and Tx's signatures.
82+
// Each required signer address is added to the list only the first time it occurs.
83+
//
84+
// By convention, the first required signer (usually from the first message) is referred
85+
// to as the primary signer and pays the fee for the whole transaction.
6386
repeated google.protobuf.Any messages = 1;
6487
string memo = 2;
6588
int64 timeout_height = 3;
6689
repeated google.protobuf.Any extension_options = 1023;
6790
}
6891
6992
message AuthInfo {
93+
// This list defines the signing modes for the required signers. The number
94+
// and order of elements must match the required signers from TxBody's messages.
95+
// The first element is the primary signer and the one which pays the fee.
7096
repeated SignerInfo signer_infos = 1;
71-
// The first signer is the primary signer and the one which pays the fee
97+
// The fee can be calculated based on the cost of evaluating the body and doing signature verification of the signers. This can be estimated via simulation.
7298
Fee fee = 2;
7399
}
74100
75101
message SignerInfo {
76-
// PublicKey key is optional for accounts that already exist in state
102+
// The public key is optional for accounts that already exist in state. If unset, the
103+
// verifier can use the required signer address for this position and lookup the public key.
77104
PublicKey public_key = 1;
78105
// ModeInfo describes the signing mode of the signer and is a nested
79106
// structure to support nested multisig pubkey's
@@ -149,14 +176,16 @@ buffers implementation
149176
subtle differences between the signing and encoding formats which could
150177
potentially be exploited by an attacker)
151178

152-
Signatures are structured using the `SignDoc` below which reuses `TxBody` and
153-
`AuthInfo` and only adds the fields which are needed for signatures:
179+
Signatures are structured using the `SignDoc` below which reuses the serialization of
180+
`TxBody` and `AuthInfo` and only adds the fields which are needed for signatures:
154181

155182
```proto
156183
// types/types.proto
157184
message SignDoc {
158-
TxBody body = 1;
159-
AuthInfo auth_info = 2;
185+
// A protobuf serialization of a TxBody that matches the representation in TxRaw.
186+
bytes body = 1;
187+
// A protobuf serialization of an AuthInfo that matches the representation in TxRaw.
188+
bytes auth_info = 2;
160189
string chain_id = 3;
161190
uint64 account_number = 4;
162191
// account_sequence starts at 1 rather than 0 to avoid the case where
@@ -167,36 +196,27 @@ message SignDoc {
167196

168197
In order to sign in the default mode, clients take the following steps:
169198

170-
1. Encode `SignDoc`. (The only requirement of the underlying protobuf
171-
implementation is that fields are serialized in order).
172-
2. Sign the encoded `SignDoc` bytes
173-
3. Build and broadcast `Tx`. (The underlying protobuf implementation must encode
174-
`TxBody` and `AuthInfo` with the same binary representation as encoded in
175-
`SignDoc`. If this is a problem for clients, the "raw" types described under
176-
verification can be used for signing as well.)
199+
1. Serialize `TxBody` and `AuthInfo` using any valid protobuf implementation.
200+
2. Create a `SignDoc` and encode it. (The only requirement of the underlying
201+
protobuf implementation is that fields are serialized in order).
202+
3. Sign the encoded `SignDoc` bytes.
203+
4. Build a `TxRaw` and serialize it for broadcasting.
177204

178205
Signature verification is based on comparing the raw `TxBody` and `AuthInfo`
179-
bytes encoded in `Tx` not based on any ["canonicalization"](https://github.com/regen-network/canonical-proto3)
206+
bytes encoded in `TxRaw` not based on any ["canonicalization"](https://github.com/regen-network/canonical-proto3)
180207
algorithm which creates added complexity for clients in addition to preventing
181208
some forms of upgradeability (to be addressed later in this document).
182209

183-
Signature verifiers should use a special set of "raw" types to perform this
184-
binary signature verification rather than attempting to re-encode protobuf
185-
documents which could result in a different binary encoding:
210+
Signature verifiers do:
186211

187-
```proto
188-
message TxRaw {
189-
bytes body_bytes = 1;
190-
repeated bytes signatures = 2;
191-
}
192-
193-
message SignDocRaw {
194-
bytes body_bytes = 1;
195-
string chain_id = 2;
196-
uint64 account_number = 3;
197-
uint64 account_sequence = 4;
198-
}
199-
```
212+
1. Deserialize a `TxRaw` and pull out `body` and `auth_info`.
213+
2. Create a list of required signer addresses from the messages.
214+
3. For each required signer:
215+
- Pull account number and sequence from the state.
216+
- Obtain the public key either from state or `AuthInfo`'s `signer_infos`.
217+
- Create a `SignDoc` and serialize it. Due to the simplicity of the type it
218+
is expected that this matches the serialization used by the signer.
219+
- Verify the signature at the the same list position against the serialized `SignDoc`.
200220

201221
#### `SIGN_MODE_LEGACY_AMINO`
202222

0 commit comments

Comments
 (0)