10510fcb99
Protocol Buffers interaction is just another serialization standard, while its widespread it has fortunately mostly been kept out of anything relevant or important. Mostly due to the fact that is really quite bad from a technical perspective. This adds simple and basic support for creating and parsing protocol buffer messages, mostly to allow interoperability. If you want quality: use the MessagBuilder/MessageParser ones instead.
282 lines
9.4 KiB
Protocol Buffer
282 lines
9.4 KiB
Protocol Buffer
/*
|
|
* Electron Cash - a lightweight Bitcoin Cash client
|
|
* CashFusion - an advanced coin anonymizer
|
|
*
|
|
* Copyright (C) 2020 Mark B. Lundeberg
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person
|
|
* obtaining a copy of this software and associated documentation files
|
|
* (the "Software"), to deal in the Software without restriction,
|
|
* including without limitation the rights to use, copy, modify, merge,
|
|
* publish, distribute, sublicense, and/or sell copies of the Software,
|
|
* and to permit persons to whom the Software is furnished to do so,
|
|
* subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be
|
|
* included in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*/
|
|
syntax = "proto2";
|
|
|
|
package fusion;
|
|
|
|
// Some primitives
|
|
|
|
message InputComponent {
|
|
required bytes prev_txid = 1; // in 'reverse' order, just like in tx
|
|
required uint32 prev_index = 2;
|
|
required bytes pubkey = 3;
|
|
required uint64 amount = 4;
|
|
}
|
|
|
|
message OutputComponent {
|
|
required bytes scriptpubkey = 1;
|
|
required uint64 amount = 2;
|
|
}
|
|
|
|
message BlankComponent {
|
|
}
|
|
|
|
message Component {
|
|
required bytes salt_commitment = 1; // 32 bytes
|
|
oneof component {
|
|
InputComponent input = 2;
|
|
OutputComponent output = 3;
|
|
BlankComponent blank = 4;
|
|
}
|
|
}
|
|
|
|
message InitialCommitment {
|
|
required bytes salted_component_hash = 1; // 32 byte hash
|
|
required bytes amount_commitment = 2; // uncompressed point
|
|
required bytes communication_key = 3; // compressed point
|
|
}
|
|
|
|
message Proof {
|
|
// During blame phase, messages of this form are encrypted and sent
|
|
// to a different player. It is already known which commitment this
|
|
// should apply to, so we only need to point at the component.
|
|
required fixed32 component_idx = 1;
|
|
required bytes salt = 2; // 32 bytes
|
|
required bytes pedersen_nonce = 3; // 32 bytes
|
|
}
|
|
|
|
|
|
|
|
// Primary communication message types (and flow)
|
|
|
|
// Setup phase
|
|
|
|
message ClientHello { // from client
|
|
required bytes version = 1;
|
|
optional bytes genesis_hash = 2; // 32 byte hash (bitcoind little-endian memory order)
|
|
}
|
|
|
|
message ServerHello { // from server
|
|
repeated uint64 tiers = 1;
|
|
required uint32 num_components = 2;
|
|
required uint64 component_feerate = 4; // sats/kB
|
|
required uint64 min_excess_fee = 5; // sats
|
|
required uint64 max_excess_fee = 6; // sats
|
|
|
|
optional string donation_address = 15; // BCH Address "bitcoincash:qpx..."
|
|
}
|
|
|
|
message JoinPools { // from client
|
|
message PoolTag {
|
|
// These tags can be used to client to stop the server from including
|
|
// the client too many times in the same fusion. Thus, the client can
|
|
// connect many times without fear of fusing with themselves.
|
|
required bytes id = 1; // allowed up to 20 bytes
|
|
required uint32 limit = 2; // between 1 and 5 inclusive
|
|
optional bool no_ip = 3; // whether to do an IP-less tag -- this will collide with all other users, make sure it's random so you can't get DoSed.
|
|
}
|
|
repeated uint64 tiers = 1;
|
|
repeated PoolTag tags = 2; // at most five tags.
|
|
}
|
|
|
|
message TierStatusUpdate { // from server
|
|
message TierStatus {
|
|
// in future, we will want server to indicate 'remaining time' and mask number of players.
|
|
// note: if player is in queue then a status will be ommitted.
|
|
optional uint32 players = 1;
|
|
optional uint32 min_players = 2; // minimum required to start (may have delay to allow extra)
|
|
optional uint32 max_players = 3; // maximum allowed (immediate start)
|
|
optional uint32 time_remaining = 4;
|
|
}
|
|
map<uint64, TierStatus> statuses = 1;
|
|
}
|
|
|
|
message FusionBegin { // from server
|
|
required uint64 tier = 1;
|
|
required bytes covert_domain = 2;
|
|
required uint32 covert_port = 3;
|
|
optional bool covert_ssl = 4;
|
|
required fixed64 server_time = 5; // server unix time when sending this message; can't be too far off from recipient's clock.
|
|
}
|
|
|
|
|
|
// Fusion round (repeatable multiple times per connection)
|
|
|
|
message StartRound { // from server
|
|
required bytes round_pubkey = 1;
|
|
repeated bytes blind_nonce_points = 2;
|
|
required fixed64 server_time = 5; // server unix time when sending this message; can't be too far off from recipient's clock.
|
|
}
|
|
|
|
// Phase 3
|
|
message PlayerCommit { // from client
|
|
repeated bytes initial_commitments = 1; // serialized InitialCommitment messages; server will repeat them later, verbatim.
|
|
required uint64 excess_fee = 2;
|
|
required bytes pedersen_total_nonce = 3; // 32 bytes
|
|
required bytes random_number_commitment = 4; // 32 bytes
|
|
repeated bytes blind_sig_requests = 5; // 32 byte scalars
|
|
}
|
|
|
|
// Phase 4
|
|
message BlindSigResponses { // from server
|
|
repeated bytes scalars = 1; // 32 byte scalars
|
|
}
|
|
|
|
message AllCommitments {
|
|
// All the commitments from all players. At ~140 bytes per commitment and hundreds of commitments, this can be quite large, so it gets sent in its own message during the covert phase.
|
|
repeated bytes initial_commitments = 1;
|
|
}
|
|
|
|
//Phase 5
|
|
message CovertComponent { // from covert client
|
|
// The round key is used to identify the pool if needed
|
|
optional bytes round_pubkey = 1;
|
|
required bytes signature = 2;
|
|
required bytes component = 3; // bytes so that it can be signed and hashed verbatim
|
|
}
|
|
|
|
//Phase 6
|
|
message ShareCovertComponents { // from server
|
|
// This is a large message! 168 bytes per initial commitment, ~112 bytes per input component.
|
|
// Can easily reach 100 kB or more.
|
|
repeated bytes components = 4;
|
|
optional bool skip_signatures = 5; // if the server already sees a problem in submitted components
|
|
optional bytes session_hash = 6; // the server's calculation of session hash, so clients can crosscheck.
|
|
}
|
|
|
|
// Phase 7A
|
|
message CovertTransactionSignature { // from covert client
|
|
// The round key is used to identify the pool if needed
|
|
optional bytes round_pubkey = 1;
|
|
required uint32 which_input = 2;
|
|
required bytes txsignature = 3;
|
|
}
|
|
|
|
// Phase 8
|
|
message FusionResult { // from server
|
|
required bool ok = 1;
|
|
repeated bytes txsignatures = 2; // if ok
|
|
repeated uint32 bad_components = 3; // if not ok
|
|
}
|
|
|
|
// Phase 9
|
|
message MyProofsList { // from client
|
|
repeated bytes encrypted_proofs = 1;
|
|
required bytes random_number = 2; // the number we committed to, back in phase 3
|
|
}
|
|
|
|
message TheirProofsList { // from server
|
|
message RelayedProof {
|
|
required bytes encrypted_proof = 1;
|
|
required uint32 src_commitment_idx = 2; // which of the commitments is being proven (index in full list)
|
|
required uint32 dst_key_idx = 3; // which of the recipient's keys will unlock the encryption (index in player list)
|
|
}
|
|
repeated RelayedProof proofs = 1;
|
|
}
|
|
|
|
// Phase 10
|
|
message Blames { // from client
|
|
message BlameProof {
|
|
required uint32 which_proof = 1;
|
|
oneof decrypter {
|
|
bytes session_key = 2; // 32 byte, preferred if the proof decryption works at all
|
|
bytes privkey = 3; // 32 byte scalar
|
|
}
|
|
|
|
// Some errors can only be discovered by checking the blockchain,
|
|
// Namely, if an input UTXO is missing/spent/unconfirmed/different
|
|
// scriptpubkey/different amount, than indicated.
|
|
optional bool need_lookup_blockchain = 4;
|
|
|
|
// The client can indicate why it thinks the blame is deserved. In
|
|
// case the server finds no issue, this string might help for debugging.
|
|
optional string blame_reason = 5;
|
|
}
|
|
repeated BlameProof blames = 1;
|
|
}
|
|
|
|
// Final message of the round
|
|
message RestartRound {
|
|
}
|
|
|
|
// Fatal error from server, likely we did something wrong (it will disconnect us, but the message may help debugging).
|
|
message Error {
|
|
optional string message = 1;
|
|
}
|
|
|
|
// Simple ping, as a keepalive.
|
|
message Ping {
|
|
}
|
|
|
|
// Simple acknowledgement, nothing more to say.
|
|
message OK {
|
|
}
|
|
|
|
// Primary communication channel types
|
|
|
|
message ClientMessage {
|
|
oneof msg {
|
|
ClientHello clienthello = 1;
|
|
JoinPools joinpools = 2;
|
|
PlayerCommit playercommit = 3;
|
|
MyProofsList myproofslist = 5;
|
|
Blames blames = 6;
|
|
}
|
|
}
|
|
|
|
message ServerMessage {
|
|
oneof msg {
|
|
ServerHello serverhello = 1;
|
|
TierStatusUpdate tierstatusupdate = 2;
|
|
FusionBegin fusionbegin = 3;
|
|
StartRound startround = 4;
|
|
BlindSigResponses blindsigresponses = 5;
|
|
AllCommitments allcommitments = 6;
|
|
ShareCovertComponents sharecovertcomponents = 7;
|
|
FusionResult fusionresult = 8;
|
|
TheirProofsList theirproofslist = 9;
|
|
|
|
RestartRound restartround = 14;
|
|
Error error = 15;
|
|
}
|
|
}
|
|
|
|
message CovertMessage { // client -> server, covertly
|
|
oneof msg {
|
|
CovertComponent component = 1;
|
|
CovertTransactionSignature signature = 2;
|
|
Ping ping = 3;
|
|
}
|
|
}
|
|
|
|
message CovertResponse { // server -> a covert client
|
|
oneof msg {
|
|
OK ok = 1;
|
|
Error error = 15;
|
|
}
|
|
}
|