mirror of
https://github.com/luxfi/threshold.git
synced 2026-10-30 15:15:53 +00:00
- Remove unnecessary trailing newlines - Fix comment formatting - Adjust indentation and spacing - Remove unused nolint directives
114 lines
3.5 KiB
Go
114 lines
3.5 KiB
Go
package protocol
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/fxamacker/cbor/v2"
|
|
"github.com/luxfi/threshold/internal/round"
|
|
"github.com/luxfi/threshold/pkg/hash"
|
|
"github.com/luxfi/threshold/pkg/party"
|
|
)
|
|
|
|
type Message struct {
|
|
// SSID is a byte string which uniquely identifies the session this message belongs to.
|
|
SSID []byte
|
|
// From is the party.ID of the sender
|
|
From party.ID
|
|
// To is the intended recipient for this message. If To == "", then the message should be sent to all.
|
|
To party.ID
|
|
// Protocol identifies the protocol this message belongs to
|
|
Protocol string
|
|
// RoundNumber is the index of the round this message belongs to
|
|
RoundNumber round.Number
|
|
// Data is the actual content consumed by the round.
|
|
Data []byte
|
|
// Broadcast indicates whether this message should be reliably broadcast to all participants.
|
|
Broadcast bool
|
|
// BroadcastVerification is the hash of all messages broadcast by the parties,
|
|
// and is included in all messages in the round following a broadcast round.
|
|
BroadcastVerification []byte
|
|
// Compressed indicates whether the Data field is compressed
|
|
Compressed bool
|
|
}
|
|
|
|
// String implements fmt.Stringer.
|
|
func (m Message) String() string {
|
|
return fmt.Sprintf("message: round %d, from: %s, to %v, protocol: %s", m.RoundNumber, m.From, m.To, m.Protocol)
|
|
}
|
|
|
|
// IsFor returns true if the message is intended for the designated party.
|
|
func (m Message) IsFor(id party.ID) bool {
|
|
if m.From == id {
|
|
return false
|
|
}
|
|
return m.To == "" || m.To == id
|
|
}
|
|
|
|
// Hash returns a 64 byte hash of the message content, including the headers.
|
|
// Can be used to produce a signature for the message.
|
|
func (m *Message) Hash() []byte {
|
|
var broadcast byte
|
|
if m.Broadcast {
|
|
broadcast = 1
|
|
}
|
|
h := hash.New(
|
|
hash.BytesWithDomain{TheDomain: "SSID", Bytes: m.SSID},
|
|
m.From,
|
|
m.To,
|
|
hash.BytesWithDomain{TheDomain: "Protocol", Bytes: []byte(m.Protocol)},
|
|
m.RoundNumber,
|
|
hash.BytesWithDomain{TheDomain: "Content", Bytes: m.Data},
|
|
hash.BytesWithDomain{TheDomain: "Broadcast", Bytes: []byte{broadcast}},
|
|
hash.BytesWithDomain{TheDomain: "BroadcastVerification", Bytes: m.BroadcastVerification},
|
|
)
|
|
return h.Sum()
|
|
}
|
|
|
|
// marshallableMessage is a copy of message for the purpose of cbor marshaling.
|
|
//
|
|
// This is a workaround to use cbor's default marshaling for Message, all while providing
|
|
// a MarshalBinary method
|
|
type marshallableMessage struct {
|
|
SSID []byte
|
|
From party.ID
|
|
To party.ID
|
|
Protocol string
|
|
RoundNumber round.Number
|
|
Data []byte
|
|
Broadcast bool
|
|
BroadcastVerification []byte
|
|
}
|
|
|
|
func (m *Message) toMarshallable() *marshallableMessage {
|
|
return &marshallableMessage{
|
|
SSID: m.SSID,
|
|
From: m.From,
|
|
To: m.To,
|
|
Protocol: m.Protocol,
|
|
RoundNumber: m.RoundNumber,
|
|
Data: m.Data,
|
|
Broadcast: m.Broadcast,
|
|
BroadcastVerification: m.BroadcastVerification,
|
|
}
|
|
}
|
|
|
|
func (m *Message) MarshalBinary() ([]byte, error) {
|
|
return cbor.Marshal(m.toMarshallable())
|
|
}
|
|
|
|
func (m *Message) UnmarshalBinary(data []byte) error {
|
|
deserialized := m.toMarshallable()
|
|
if err := cbor.Unmarshal(data, deserialized); err != nil {
|
|
return err
|
|
}
|
|
m.SSID = deserialized.SSID
|
|
m.From = deserialized.From
|
|
m.To = deserialized.To
|
|
m.Protocol = deserialized.Protocol
|
|
m.RoundNumber = deserialized.RoundNumber
|
|
m.Data = deserialized.Data
|
|
m.Broadcast = deserialized.Broadcast
|
|
m.BroadcastVerification = deserialized.BroadcastVerification
|
|
return nil
|
|
}
|