Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wire: Add p2p mixing messages. #3066

Merged
merged 1 commit into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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",
jrick marked this conversation as resolved.
Show resolved Hide resolved
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"},
jrick marked this conversation as resolved.
Show resolved Hide resolved
{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
Loading