github.com/badrootd/nibiru-cometbft@v0.37.5-0.20240307173500-2a75559eee9b/docs/architecture/adr-024-sign-bytes.md (about)

     1  # ADR 024: SignBytes and validator types in privval
     2  
     3  ## Context
     4  
     5  Currently, the messages exchanged between tendermint and a (potentially remote) signer/validator, 
     6  namely votes, proposals, and heartbeats, are encoded as a JSON string 
     7  (e.g., via `Vote.SignBytes(...)`) and then 
     8  signed . JSON encoding is sub-optimal for both, hardware wallets 
     9  and for usage in ethereum smart contracts. Both is laid down in detail in [issue#1622].  
    10  
    11  Also, there are currently no differences between sign-request and -replies. Also, there is no possibility 
    12  for a remote signer to include an error code or message in case something went wrong.
    13  The messages exchanged between tendermint and a remote signer currently live in 
    14  [privval/socket.go] and encapsulate the corresponding types in [types].
    15  
    16  
    17  [privval/socket.go]: https://github.com/tendermint/tendermint/blob/d419fffe18531317c28c29a292ad7d253f6cafdf/privval/socket.go#L496-L502
    18  [issue#1622]: https://github.com/tendermint/tendermint/issues/1622
    19  [types]: https://github.com/tendermint/tendermint/tree/v0.37.x/types
    20   
    21  
    22  ## Decision
    23  
    24  - restructure vote, proposal, and heartbeat such that their encoding is easily parseable by 
    25  hardware devices and smart contracts using a  binary encoding format ([amino] in this case)
    26  - split up the messages exchanged between tendermint and remote signers into requests and 
    27  responses (see details below)
    28  - include an error type in responses
    29  
    30  ### Overview
    31  ```
    32  +--------------+                      +----------------+
    33  |              |     SignXRequest     |                |
    34  |Remote signer |<---------------------+  tendermint    |
    35  | (e.g. KMS)   |                      |                |
    36  |              +--------------------->|                |
    37  +--------------+    SignedXReply      +----------------+
    38  
    39  
    40  SignXRequest {
    41      x: X
    42  }
    43  
    44  SignedXReply {
    45      x: X
    46    sig: Signature // []byte
    47    err: Error{ 
    48      code: int
    49      desc: string
    50    }
    51  }
    52  ```
    53  
    54  TODO: Alternatively, the type `X` might directly include the signature. A lot of places expect a vote with a 
    55  signature and do not necessarily deal with "Replies".
    56  Still exploring what would work best here. 
    57  This would look like (exemplified using X = Vote):
    58  ```
    59  Vote {
    60      // all fields besides signature
    61  }
    62  
    63  SignedVote {
    64   Vote Vote
    65   Signature []byte
    66  }
    67  
    68  SignVoteRequest {
    69     Vote Vote
    70  }
    71  
    72  SignedVoteReply {
    73      Vote SignedVote
    74      Err  Error
    75  }
    76  ```
    77  
    78  **Note:** There was a related discussion around including a fingerprint of, or, the whole public-key 
    79  into each sign-request to tell the signer which corresponding private-key to 
    80  use to sign the message. This is particularly relevant in the context of the KMS
    81  but is currently not considered in this ADR. 
    82  
    83  
    84  [amino]: https://github.com/tendermint/go-amino/
    85  
    86  ### Vote
    87  
    88  As explained in [issue#1622] `Vote` will be changed to contain the following fields 
    89  (notation in protobuf-like syntax for easy readability):
    90  
    91  ```proto
    92  // vanilla protobuf / amino encoded
    93  message Vote {
    94      Version       fixed32                      
    95      Height        sfixed64       
    96      Round         sfixed32
    97      VoteType      fixed32
    98      Timestamp     Timestamp         // << using protobuf definition
    99      BlockID       BlockID           // << as already defined 
   100      ChainID       string            // at the end because length could vary a lot
   101  }
   102  
   103  // this is an amino registered type; like currently privval.SignVoteMsg: 
   104  // registered with "tendermint/socketpv/SignVoteRequest"
   105  message SignVoteRequest {
   106     Vote vote
   107  }
   108  
   109  //  amino registered type
   110  // registered with "tendermint/socketpv/SignedVoteReply"
   111  message SignedVoteReply { 
   112     Vote      Vote
   113     Signature Signature 
   114     Err       Error
   115  }
   116  
   117  // we will use this type everywhere below
   118  message Error {
   119    Type        uint  // error code
   120    Description string  // optional description
   121  }
   122  
   123  ```
   124  
   125  The `ChainID` gets moved into the vote message directly. Previously, it was injected 
   126  using the [Signable] interface method `SignBytes(chainID string) []byte`. Also, the 
   127  signature won't be included directly, only in the corresponding `SignedVoteReply` message.
   128  
   129  [Signable]: https://github.com/tendermint/tendermint/blob/d419fffe18531317c28c29a292ad7d253f6cafdf/types/signable.go#L9-L11
   130   
   131  ### Proposal
   132  
   133  ```proto
   134  // vanilla protobuf / amino encoded
   135  message Proposal {                      
   136      Height            sfixed64       
   137      Round             sfixed32
   138      Timestamp         Timestamp         // << using protobuf definition
   139      BlockPartsHeader  PartSetHeader     // as already defined
   140      POLRound          sfixed32
   141      POLBlockID        BlockID           // << as already defined    
   142  }
   143   
   144  // amino registered with "tendermint/socketpv/SignProposalRequest"
   145  message SignProposalRequest {
   146     Proposal proposal
   147  }
   148  
   149  // amino registered with "tendermint/socketpv/SignProposalReply"
   150  message SignProposalReply { 
   151     Prop   Proposal
   152     Sig    Signature 
   153     Err    Error     // as defined above
   154  }
   155  ```
   156  
   157  ### Heartbeat
   158  
   159  **TODO**: clarify if heartbeat also needs a fixed offset and update the fields accordingly: 
   160  
   161  ```proto
   162  message Heartbeat {
   163  	ValidatorAddress Address 
   164  	ValidatorIndex   int     
   165  	Height           int64   
   166  	Round            int     
   167  	Sequence         int     
   168  }
   169  // amino registered with "tendermint/socketpv/SignHeartbeatRequest"
   170  message SignHeartbeatRequest {
   171     Hb Heartbeat
   172  }
   173  
   174  // amino registered with "tendermint/socketpv/SignHeartbeatReply"
   175  message SignHeartbeatReply { 
   176     Hb     Heartbeat
   177     Sig    Signature 
   178     Err    Error     // as defined above
   179  }
   180  
   181  ```
   182  
   183  ## PubKey
   184  
   185  TBA -  this needs further thoughts: e.g. what todo like in the case of the KMS which holds
   186  several keys? How does it know with which key to reply?
   187  
   188  ## SignBytes
   189  `SignBytes` will not require a `ChainID` parameter:
   190  
   191  ```golang
   192  type Signable interface {
   193  	SignBytes() []byte
   194  }
   195  
   196  ```
   197  And the implementation for vote, heartbeat, proposal will look like:
   198  ```golang
   199  // type T is one of vote, sign, proposal
   200  func (tp *T) SignBytes() []byte {
   201  	bz, err := cdc.MarshalBinary(tp)
   202  	if err != nil {
   203  		panic(err)
   204  	}
   205  	return bz
   206  }
   207  ```
   208  
   209  ## Status
   210  
   211  Partially Accepted
   212  
   213  ## Consequences
   214  
   215  
   216  
   217  ### Positive
   218  
   219  The most relevant positive effect is that the signing bytes can easily be parsed by a 
   220  hardware module and a smart contract. Besides that:
   221   
   222  - clearer separation between requests and responses
   223  - added error messages enable better error handling 
   224  
   225  
   226  ### Negative
   227  
   228  - relatively huge change / refactoring touching quite some code
   229  - lot's of places assume a `Vote` with a signature included -> they will need to 
   230  - need to modify some interfaces 
   231  
   232  ### Neutral
   233  
   234  not even the swiss are neutral