Skip to content

Commit

Permalink
wire: add p2p mixing messages
Browse files Browse the repository at this point in the history
These messages implement the stages of a cspp mix.  Messages will be
broadcast to all full nodes and all peers participating in mixing
through inventory messages.
  • Loading branch information
jrick committed Mar 19, 2024
1 parent fac4c14 commit 8de97a9
Show file tree
Hide file tree
Showing 28 changed files with 3,997 additions and 20 deletions.
101 changes: 101 additions & 0 deletions wire/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,14 @@ func readElement(r io.Reader, element interface{}) error {
}
return nil

// Mixed message
case *[MixMsgSize]byte:
_, err := io.ReadFull(r, e[:])
if err != nil {
return err
}
return nil

case *[32]byte:
_, err := io.ReadFull(r, e[:])
if err != nil {
Expand All @@ -322,6 +330,38 @@ func readElement(r io.Reader, element interface{}) error {
}
return nil

// Mix identity
case *[33]byte:
_, err := io.ReadFull(r, e[:])
if err != nil {
return err
}
return nil

// Mix signature
case *[64]byte:
_, err := io.ReadFull(r, e[:])
if err != nil {
return err
}
return nil

// sntrup4591651 ciphertext
case *[1047]byte:
_, err := io.ReadFull(r, e[:])
if err != nil {
return err
}
return nil

// sntrup4591651 public key
case *[1218]byte:
_, err := io.ReadFull(r, e[:])
if err != nil {
return err
}
return nil

case *ServiceFlag:
rv, err := binarySerializer.Uint64(r, littleEndian)
if err != nil {
Expand Down Expand Up @@ -377,6 +417,20 @@ func writeElement(w io.Writer, element interface{}) error {
// Attempt to write the element based on the concrete type via fast
// type assertions first.
switch e := element.(type) {
case uint8:
err := binarySerializer.PutUint8(w, e)
if err != nil {
return err
}
return nil

case uint16:
err := binarySerializer.PutUint16(w, littleEndian, e)
if err != nil {
return err
}
return nil

case int32:
err := binarySerializer.PutUint32(w, littleEndian, uint32(e))
if err != nil {
Expand Down Expand Up @@ -441,13 +495,60 @@ func writeElement(w io.Writer, element interface{}) error {
}
return nil

// Mixed message
case *[MixMsgSize]byte:
_, err := w.Write(e[:])
if err != nil {
return err
}
return nil

case *[32]byte:
_, err := w.Write(e[:])
if err != nil {
return err
}
return nil

case *chainhash.Hash:
_, err := w.Write(e[:])
if err != nil {
return err
}
return nil

// Mix identity
case *[33]byte:
_, err := w.Write(e[:])
if err != nil {
return err
}
return nil

// Mix signature
case *[64]byte:
_, err := w.Write(e[:])
if err != nil {
return err
}
return nil

// sntrup4591761 ciphertext
case *[1047]byte:
_, err := w.Write(e[:])
if err != nil {
return err
}
return nil

// sntrup4591761 public key
case *[1218]byte:
_, err := w.Write(e[:])
if err != nil {
return err
}
return nil

case ServiceFlag:
err := binarySerializer.PutUint64(w, littleEndian, uint64(e))
if err != nil {
Expand Down
56 changes: 56 additions & 0 deletions wire/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -907,3 +907,59 @@ func TestRandomUint64Errors(t *testing.T) {
t.Errorf("Nonce is not 0 [%v]", nonce)
}
}

// repeat returns the byte slice containing count elements of the byte b.
func repeat(b byte, count int) []byte {
s := make([]byte, count)
for i := range s {
s[i] = b
}
return s
}

// rhash returns a chainhash.Hash with all bytes set to b.
func rhash(b byte) chainhash.Hash {
var h chainhash.Hash
for i := range h {
h[i] = b
}
return h
}

// varBytesLen returns the size required to encode l bytes as a varint
// followed by the bytes themselves.
func varBytesLen(l uint32) uint32 {
return uint32(VarIntSerializeSize(uint64(l))) + l
}

// expectedSerializationCompare compares serialized bytes to the expected
// sequence of bytes. When got and expected are not equal, the test t will be
// errored with descriptive messages of how the two encodings are different.
// Returns true if the serialization are equal, and false if the test
// errors.
func expectedSerializationEqual(t *testing.T, got, expected []byte) bool {
if bytes.Equal(got, expected) {
return true
}

t.Errorf("encoded message differs from expected serialization")
minLen := len(expected)
if len(got) < minLen {
minLen = len(got)
}
for i := 0; i < minLen; i++ {
if b := got[i]; b != expected[i] {
t.Errorf("message differs at index %d (got 0x%x, expected 0x%x)",
i, b, expected[i])
}
}
if len(got) > len(expected) {
t.Errorf("serialized message contains extra bytes [%x]",
got[len(expected):])
}
if len(expected) > len(got) {
t.Errorf("serialization prematurely ends at index %d, missing bytes [%x]",
len(got), expected[len(got):])
}
return false
}
20 changes: 20 additions & 0 deletions wire/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,22 @@ const (
// ErrTooManyTSpends is returned when the number of tspend hashes
// exceeds the maximum allowed.
ErrTooManyTSpends

// ErrTooManyManyMixPairReqs is returned when the number of mix pair
// request message hashes exceeds the maximum allowed.
ErrTooManyManyMixPairReqs

// ErrMixPairReqScriptClassTooLong is returned when a mixing script
// class type string is longer than allowed by the protocol.
ErrMixPairReqScriptClassTooLong

// ErrTooManyMixPairReqUTXOs is returned when a MixPairReq message
// contains more UTXOs than allowed by the protocol.
ErrTooManyMixPairReqUTXOs

// ErrTooManyPrevMixMsgs is returned when too many previous messages of
// a mix run are referenced by a message.
ErrTooManyPrevMixMsgs
)

// Map of ErrorCode values back to their constant names for pretty printing.
Expand Down Expand Up @@ -168,6 +184,10 @@ var errorCodeStrings = map[ErrorCode]string{
ErrTooManyInitStateTypes: "ErrTooManyInitStateTypes",
ErrInitStateTypeTooLong: "ErrInitStateTypeTooLong",
ErrTooManyTSpends: "ErrTooManyTSpends",
ErrTooManyManyMixPairReqs: "ErrTooManyManyMixPairReqs",
ErrMixPairReqScriptClassTooLong: "ErrMixPairReqScriptClassTooLong",
ErrTooManyMixPairReqUTXOs: "ErrTooManyMixPairReqUTXOs",
ErrTooManyPrevMixMsgs: "ErrTooManyPrevMixMsgs",
}

// String returns the ErrorCode as a human-readable name.
Expand Down
6 changes: 5 additions & 1 deletion wire/error_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) 2017 The btcsuite developers
// Copyright (c) 2015-2020 The Decred developers
// Copyright (c) 2015-2023 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

Expand Down Expand Up @@ -50,6 +50,10 @@ func TestMessageErrorCodeStringer(t *testing.T) {
{ErrTooManyInitStateTypes, "ErrTooManyInitStateTypes"},
{ErrInitStateTypeTooLong, "ErrInitStateTypeTooLong"},
{ErrTooManyTSpends, "ErrTooManyTSpends"},
{ErrTooManyManyMixPairReqs, "ErrTooManyManyMixPairReqs"},
{ErrMixPairReqScriptClassTooLong, "ErrMixPairReqScriptClassTooLong"},
{ErrTooManyMixPairReqUTXOs, "ErrTooManyMixPairReqUTXOs"},
{ErrTooManyPrevMixMsgs, "ErrTooManyPrevMixMsgs"},

{0xffff, "Unknown ErrorCode (65535)"},
}
Expand Down
6 changes: 2 additions & 4 deletions wire/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@ go 1.17
require (
github.com/davecgh/go-spew v1.1.1
github.com/decred/dcrd/chaincfg/chainhash v1.0.4
github.com/decred/dcrd/crypto/blake256 v1.0.1
lukechampine.com/blake3 v1.2.1
)

require (
github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
)
require github.com/klauspost/cpuid/v2 v2.0.9 // indirect
2 changes: 2 additions & 0 deletions wire/invvect.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const (
InvTypeTx InvType = 1
InvTypeBlock InvType = 2
InvTypeFilteredBlock InvType = 3
InvTypeMix InvType = 4
)

// Map of service flags back to their constant names for pretty printing.
Expand All @@ -38,6 +39,7 @@ var ivStrings = map[InvType]string{
InvTypeTx: "MSG_TX",
InvTypeBlock: "MSG_BLOCK",
InvTypeFilteredBlock: "MSG_FILTERED_BLOCK",
InvTypeMix: "MSG_MIX",
}

// String returns the InvType in human-readable form.
Expand Down
3 changes: 2 additions & 1 deletion wire/invvect_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) 2013-2016 The btcsuite developers
// Copyright (c) 2015-2016 The Decred developers
// Copyright (c) 2015-2023 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

Expand All @@ -23,6 +23,7 @@ func TestInvTypeStringer(t *testing.T) {
{InvTypeError, "ERROR"},
{InvTypeTx, "MSG_TX"},
{InvTypeBlock, "MSG_BLOCK"},
{InvTypeMix, "MSG_MIX"},
{0xffffffff, "Unknown InvType (4294967295)"},
}

Expand Down
28 changes: 28 additions & 0 deletions wire/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ const (
CmdCFilterV2 = "cfilterv2"
CmdGetInitState = "getinitstate"
CmdInitState = "initstate"
CmdMixPairReq = "mixpairreq"
CmdMixKeyExchange = "mixkeyxchg"
CmdMixCiphertexts = "mixcphrtxt"
CmdMixSlotReserve = "mixslotres"
CmdMixDCNet = "mixdcnet"
CmdMixConfirm = "mixconfirm"
CmdMixSecrets = "mixsecrets"
)

const (
Expand Down Expand Up @@ -188,6 +195,27 @@ func makeEmptyMessage(command string) (Message, error) {
case CmdInitState:
msg = &MsgInitState{}

case CmdMixPairReq:
msg = &MsgMixPairReq{}

case CmdMixKeyExchange:
msg = &MsgMixKeyExchange{}

case CmdMixCiphertexts:
msg = &MsgMixCiphertexts{}

case CmdMixSlotReserve:
msg = &MsgMixSlotReserve{}

case CmdMixDCNet:
msg = &MsgMixDCNet{}

case CmdMixConfirm:
msg = &MsgMixConfirm{}

case CmdMixSecrets:
msg = &MsgMixSecrets{}

default:
str := fmt.Sprintf("unhandled command [%s]", command)
return nil, messageError(op, ErrUnknownCmd, str)
Expand Down
21 changes: 19 additions & 2 deletions wire/message_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) 2013-2016 The btcsuite developers
// Copyright (c) 2015-2021 The Decred developers
// Copyright (c) 2015-2024 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

Expand Down Expand Up @@ -80,6 +80,16 @@ func TestMessage(t *testing.T) {
msgReject := NewMsgReject("block", RejectDuplicate, "duplicate block")
msgGetInitState := NewMsgGetInitState()
msgInitState := NewMsgInitState()
msgMixPR, err := NewMsgMixPairReq([33]byte{}, 1, 1, "", 1, 1, 1, 1, []MixPairReqUTXO{}, NewTxOut(0, []byte{}))
if err != nil {
t.Errorf("NewMsgMixPairReq: %v", err)
}
msgMixKE := NewMsgMixKeyExchange([33]byte{}, [32]byte{}, 1, [33]byte{}, [1218]byte{}, [32]byte{}, []chainhash.Hash{})
msgMixCT := NewMsgMixCiphertexts([33]byte{}, [32]byte{}, 1, [][1047]byte{}, []chainhash.Hash{})
msgMixSR := NewMsgMixSlotReserve([33]byte{}, [32]byte{}, 1, [][][]byte{{{}}}, []chainhash.Hash{})
msgMixDC := NewMsgMixDCNet([33]byte{}, [32]byte{}, 1, []MixVect{make(MixVect, 1)}, []chainhash.Hash{})
msgMixCM := NewMsgMixConfirm([33]byte{}, [32]byte{}, 1, NewMsgTx(), []chainhash.Hash{})
msgMixRS := NewMsgMixSecrets([33]byte{}, [32]byte{}, 1, [32]byte{}, [][]byte{}, MixVect{})

tests := []struct {
in Message // Value to encode
Expand Down Expand Up @@ -111,7 +121,14 @@ func TestMessage(t *testing.T) {
{msgCFHeaders, msgCFHeaders, pver, MainNet, 58},
{msgCFTypes, msgCFTypes, pver, MainNet, 26},
{msgGetInitState, msgGetInitState, pver, MainNet, 25},
{msgInitState, msgInitState, pver, MainNet, 27},
{msgInitState, msgInitState, pver, MainNet, 28},
{msgMixPR, msgMixPR, pver, MainNet, 165},
{msgMixKE, msgMixKE, pver, MainNet, 1441},
{msgMixCT, msgMixCT, pver, MainNet, 158},
{msgMixSR, msgMixSR, pver, MainNet, 161},
{msgMixDC, msgMixDC, pver, MainNet, 181},
{msgMixCM, msgMixCM, pver, MainNet, 173},
{msgMixRS, msgMixRS, pver, MainNet, 192},
}

t.Logf("Running %d tests", len(tests))
Expand Down
Loading

0 comments on commit 8de97a9

Please sign in to comment.