Skip to content

Commit

Permalink
mixing: review
Browse files Browse the repository at this point in the history
  • Loading branch information
jrick committed May 13, 2024
1 parent 5f3891c commit 8978a78
Show file tree
Hide file tree
Showing 11 changed files with 47 additions and 79 deletions.
8 changes: 6 additions & 2 deletions mixing/dcnet.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
// Copyright (c) 2019-2024 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package mixing

import (
Expand All @@ -18,11 +22,11 @@ func SRMixPads(kp [][]byte, my uint32) []*big.Int {
partialPad := new(big.Int)
for j := uint32(0); int(j) < len(kp); j++ {
pads[j] = new(big.Int)
binary.LittleEndian.PutUint64(scratch, uint64(j)+1)
for i := uint32(0); int(i) < len(kp); i++ {
if my == i {
continue
}
binary.LittleEndian.PutUint64(scratch, uint64(j)+1)
h.Reset()
h.Write(kp[i])
h.Write(scratch)
Expand Down Expand Up @@ -151,7 +155,7 @@ func DCMixPads(kp []wire.MixVect, my uint32) Vec {
if i == int(my) {
continue
}
pads.Xor(pads, (Vec)(kp[i]))
pads.Xor(pads, Vec(kp[i]))
}
return pads
}
Expand Down
12 changes: 5 additions & 7 deletions mixing/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,19 @@ import (
)

var (
ErrInvalidPROrder = errors.New("invalid pair request order")
errInvalidPROrder = errors.New("invalid pair request order")

ErrInvalidSessionID = errors.New("invalid session ID")
errInvalidSessionID = errors.New("invalid session ID")
)

// DecapsulateError identifies the unmixed peer position of a peer who
// submitted an undecryptable ciphertext.
type DecapsulateError struct {
SubmittingIndex uint32
Err error
}

// Error satisifies the error interface.
func (e *DecapsulateError) Error() string {
return fmt.Sprintf("decapsulate failure of ciphertext by peer %d",
e.SubmittingIndex)
}

func (e *DecapsulateError) Unwrap() error {
return e.Err
}
12 changes: 0 additions & 12 deletions mixing/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,17 @@ module github.com/decred/dcrd/mixing
go 1.17

require (
decred.org/cspp/v2 v2.1.1-0.20240506180342-3c816721a1d8
github.com/companyzero/sntrup4591761 v0.0.0-20220309191932-9e0f3af2f07a
github.com/davecgh/go-spew v1.1.1
github.com/decred/dcrd/chaincfg/chainhash v1.0.4
github.com/decred/dcrd/chaincfg/v3 v3.2.0
github.com/decred/dcrd/crypto/blake256 v1.0.1
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0
github.com/decred/dcrd/dcrutil/v4 v4.0.1
github.com/decred/dcrd/txscript/v4 v4.1.0
github.com/decred/dcrd/wire v1.6.0
github.com/decred/slog v1.2.0
golang.org/x/crypto v0.7.0
)

require (
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 // indirect
github.com/dchest/siphash v1.2.3 // indirect
github.com/decred/base58 v1.0.5 // indirect
github.com/decred/dcrd/crypto/ripemd160 v1.0.2 // indirect
github.com/decred/dcrd/dcrec v1.0.1 // indirect
github.com/decred/dcrd/dcrec/edwards/v2 v2.0.3 // indirect
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.6.0 // indirect
lukechampine.com/blake3 v1.2.1 // indirect
)
25 changes: 0 additions & 25 deletions mixing/go.sum
Original file line number Diff line number Diff line change
@@ -1,39 +1,17 @@
decred.org/cspp/v2 v2.1.1-0.20240506180342-3c816721a1d8 h1:sMvVzvKkxl8S/kjSNV7o7HM3TO7hdVlZvkf8SZpXAYE=
decred.org/cspp/v2 v2.1.1-0.20240506180342-3c816721a1d8/go.mod h1:9nO3bfvCheOPIFZw5f6sRQ42CjBFB5RKSaJ9Iq6G4MA=
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 h1:w1UutsfOrms1J05zt7ISrnJIXKzwaspym5BTKGx93EI=
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0=
github.com/companyzero/sntrup4591761 v0.0.0-20220309191932-9e0f3af2f07a h1:clYxJ3Os0EQUKDDVU8M0oipllX0EkuFNBfhVQuIfyF0=
github.com/companyzero/sntrup4591761 v0.0.0-20220309191932-9e0f3af2f07a/go.mod h1:z/9Ck1EDixEbBbZ2KH2qNHekEmDLTOZ+FyoIPWWSVOI=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dchest/siphash v1.2.3 h1:QXwFc8cFOR2dSa/gE6o/HokBMWtLUaNDVd+22aKHeEA=
github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIXMPAkHc=
github.com/decred/base58 v1.0.5 h1:hwcieUM3pfPnE/6p3J100zoRfGkQxBulZHo7GZfOqic=
github.com/decred/base58 v1.0.5/go.mod h1:s/8lukEHFA6bUQQb/v3rjUySJ2hu+RioCzLukAVkrfw=
github.com/decred/dcrd/chaincfg/chainhash v1.0.4 h1:zRCv6tdncLfLTKYqu7hrXvs7hW+8FO/NvwoFvGsrluU=
github.com/decred/dcrd/chaincfg/chainhash v1.0.4/go.mod h1:hA86XxlBWwHivMvxzXTSD0ZCG/LoYsFdWnCekkTMCqY=
github.com/decred/dcrd/chaincfg/v3 v3.2.0 h1:6WxA92AGBkycEuWvxtZMvA76FbzbkDRoK8OGbsR2muk=
github.com/decred/dcrd/chaincfg/v3 v3.2.0/go.mod h1:2rHW1TKyFmwZTVBLoU/Cmf0oxcpBjUEegbSlBfrsriI=
github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y=
github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
github.com/decred/dcrd/crypto/ripemd160 v1.0.2 h1:TvGTmUBHDU75OHro9ojPLK+Yv7gDl2hnUvRocRCjsys=
github.com/decred/dcrd/crypto/ripemd160 v1.0.2/go.mod h1:uGfjDyePSpa75cSQLzNdVmWlbQMBuiJkvXw/MNKRY4M=
github.com/decred/dcrd/dcrec v1.0.1 h1:gDzlndw0zYxM5BlaV17d7ZJV6vhRe9njPBFeg4Db2UY=
github.com/decred/dcrd/dcrec v1.0.1/go.mod h1:CO+EJd8eHFb8WHa84C7ZBkXsNUIywaTHb+UAuI5uo6o=
github.com/decred/dcrd/dcrec/edwards/v2 v2.0.3 h1:l/lhv2aJCUignzls81+wvga0TFlyoZx8QxRMQgXpZik=
github.com/decred/dcrd/dcrec/edwards/v2 v2.0.3/go.mod h1:AKpV6+wZ2MfPRJnTbQ6NPgWrKzbe9RCIlCF/FKzMtM8=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
github.com/decred/dcrd/dcrutil/v4 v4.0.1 h1:E+d2TNbpOj0f1L9RqkZkEm1QolFjajvkzxWC5WOPf1s=
github.com/decred/dcrd/dcrutil/v4 v4.0.1/go.mod h1:7EXyHYj8FEqY+WzMuRkF0nh32ueLqhutZDoW4eQ+KRc=
github.com/decred/dcrd/txscript/v4 v4.1.0 h1:uEdcibIOl6BuWj3AqmXZ9xIK/qbo6lHY9aNk29FtkrU=
github.com/decred/dcrd/txscript/v4 v4.1.0/go.mod h1:OVguPtPc4YMkgssxzP8B6XEMf/J3MB6S1JKpxgGQqi0=
github.com/decred/dcrd/wire v1.6.0 h1:YOGwPHk4nzGr6OIwUGb8crJYWDiVLpuMxfDBCCF7s/o=
github.com/decred/dcrd/wire v1.6.0/go.mod h1:XQ8Xv/pN/3xaDcb7sH8FBLS9cdgVctT7HpBKKGsIACk=
github.com/decred/slog v1.2.0 h1:soHAxV52B54Di3WtKLfPum9OFfWqwtf/ygf9njdfnPM=
github.com/decred/slog v1.2.0/go.mod h1:kVXlGnt6DHy2fV5OjSeuvCJ0OmlmTF6LFpEPMu/fOY0=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/jrick/wsrpc/v2 v2.3.5/go.mod h1:7oBeDM/xMF6Yqy4GDAjpppuOf1hm6lWsaG3EaMrm+aA=
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
Expand All @@ -51,13 +29,10 @@ golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220608164250-635b8c9b7f68/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
Expand Down
22 changes: 10 additions & 12 deletions mixing/keyagreement.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,14 @@ type KX struct {
}

// NewKX generates a mixing identity's public and private keys for a interactive
// key exchange, with randomness read from a run's PRNG.
func NewKX(prng io.Reader) (*KX, error) {
ecdhPublic, ecdhPrivate, err := generateSecp256k1(prng)
// key exchange, with randomness read from a run's CSPRNG.
func NewKX(csprng io.Reader) (*KX, error) {
ecdhPublic, ecdhPrivate, err := generateSecp256k1(csprng)
if err != nil {
return nil, err
}

pqPublic, pqPrivate, err := sntrup4591761.GenerateKey(prng)
pqPublic, pqPrivate, err := sntrup4591761.GenerateKey(csprng)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -89,7 +89,7 @@ func (kx *KX) pqSharedKey(ciphertext *PQCiphertext) ([]byte, error) {

// Encapsulate performs encapsulation for sntrup4591761 key exchanges with each
// other peer in the DC-net. It populates the PQCleartexts field of kx and
// return encrypted cyphertexts of these shared keys.
// returns encrypted cyphertexts of these shared keys.
//
// Encapsulation in the DC-net requires randomness from a CSPRNG seeded by a
// committed secret; blame assignment is not possible otherwise.
Expand Down Expand Up @@ -117,6 +117,8 @@ type RevealedKeys struct {
MyIndex uint32
}

// SharedSecrets is a return value for the KX.SharedSecrets method, housing
// the slot reservation and XOR DC-Net shared secrets between two peers.
type SharedSecrets struct {
SRSecrets [][][]byte
DCSecrets [][]wire.MixVect
Expand Down Expand Up @@ -145,7 +147,6 @@ func (kx *KX) SharedSecrets(k *RevealedKeys, sid []byte, run uint32, mcounts []u
mtot += mcounts[i]
}

h := blake256.New()
s.SRSecrets = make([][][]byte, mcount)
s.DCSecrets = make([][]wire.MixVect, mcount)

Expand All @@ -164,12 +165,11 @@ func (kx *KX) SharedSecrets(k *RevealedKeys, sid []byte, run uint32, mcounts []u
if err != nil {
err := &DecapsulateError{
SubmittingIndex: peer,
Err: err,
}
return s, err
}

// XOR x25519 and both sntrup4591761 keys into a single
// XOR ECDH and both sntrup4591761 keys into a single
// shared key. If sntrup4591761 is discovered to be
// broken in the future, the security only reduces to
// that of x25519.
Expand Down Expand Up @@ -222,10 +222,8 @@ func (kx *KX) SharedSecrets(k *RevealedKeys, sid []byte, run uint32, mcounts []u
}
binary.LittleEndian.PutUint32(seedCounterBytes, seedCounter)

h.Reset()
h.Write(prngSeedPreimage)
prngSeed := h.Sum(nil)
prng := chacha20prng.New(prngSeed, nonce)
prngSeed := blake256.Sum256(prngSeedPreimage)
prng := chacha20prng.New(prngSeed[:], nonce)

s.SRSecrets[i][m] = prng.Next(32)
s.DCSecrets[i][m] = wire.MixVect(randVec(mtot, prng))
Expand Down
8 changes: 4 additions & 4 deletions mixing/message.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2023 The Decred developers
// Copyright (c) 2023-2024 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

Expand All @@ -11,11 +11,11 @@ import (
"github.com/decred/dcrd/wire"
)

// Message is a mixing message. In addition to the implementing wire encoding,
// Message is a mixing message. In addition to implementing wire encoding,
// these messages are signed by an ephemeral mixing participant identity,
// declare the previous messages that have been observed by a peer in a mixing
// session, and include expiry information to increase resilience to
// replay and denial-of-service attacks.
// session, and include expiry information to increase resilience to replay
// and denial-of-service attacks.
//
// All mixing messages satisify this interface, however, the pair request
// message returns nil for some fields that do not apply, as it is the first
Expand Down
4 changes: 4 additions & 0 deletions mixing/scriptclass.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
// Copyright (c) 2023-2024 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package mixing

// ScriptClass describes the type and format of scripts that can be used for
Expand Down
11 changes: 6 additions & 5 deletions mixing/sid.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,10 @@ func (s *sortPRs) Swap(i, j int) {
s.prXorSIDs[i], s.prXorSIDs[j] = s.prXorSIDs[j], s.prXorSIDs[i]
}

// ValidateSession checks whether the original peer order unmixed order of a key
// exchange's pair request hashes is valid, and for a run-0 session starting at
// epoch.
// ValidateSession checks whether the original unmixed peer order of a key
// exchange's pair request hashes is validly sorted for the session ID, and
// for a run-0 KE, also checks that the session hash is derived from the
// specified pair requests and epoch.
func ValidateSession(ke *wire.MsgMixKeyExchange) error {
h := make([]chainhash.Hash, len(ke.SeenPRs))
copy(h, ke.SeenPRs)
Expand All @@ -102,7 +103,7 @@ func ValidateSession(ke *wire.MsgMixKeyExchange) error {
return bytes.Compare(h[i][:], h[j][:]) == -1
})
if !sorted {
return ErrInvalidPROrder
return errInvalidPROrder
}

// If this is a run-0 KE, validate the session hash.
Expand All @@ -113,7 +114,7 @@ func ValidateSession(ke *wire.MsgMixKeyExchange) error {
})
derivedSID := deriveSessionID(h, ke.Epoch)
if derivedSID != ke.SessionID {
return ErrInvalidSessionID
return errInvalidSessionID
}
}

Expand Down
8 changes: 4 additions & 4 deletions mixing/sid_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,15 @@ func TestInvalidSession(t *testing.T) {
}

ke.SessionID[16] ^= 0xFF
if err := ValidateSession(ke); !errors.Is(err, ErrInvalidSessionID) {
if err := ValidateSession(ke); !errors.Is(err, errInvalidSessionID) {
t.Errorf("ValidateSession unexpected error, got %v, want %v",
err, ErrInvalidSessionID)
err, errInvalidSessionID)
}

ke.SessionID = sid
ke.SeenPRs[0], ke.SeenPRs[1] = ke.SeenPRs[1], ke.SeenPRs[0]
if err := ValidateSession(ke); !errors.Is(err, ErrInvalidPROrder) {
if err := ValidateSession(ke); !errors.Is(err, errInvalidPROrder) {
t.Errorf("ValidateSession unexpected error, got %v, want %v",
err, ErrInvalidPROrder)
err, errInvalidPROrder)
}
}
1 change: 1 addition & 0 deletions mixing/signatures.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func SignMessage(m Signed, priv *secp256k1.PrivateKey) error {
if err != nil {
return err
}
// XXX: A SetSig method or similar would be less janky.
copy(m.Sig(), sig)
return nil
}
Expand Down
15 changes: 7 additions & 8 deletions mixing/vec.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
// Copyright (c) 2019-2024 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package mixing

import (
"bytes"
"fmt"
"strings"

"github.com/decred/dcrd/mixing/internal/chacha20prng"
)

// Msize is the size of the message being mixed. This is the size of a
// HASH160, which allows mixes to be create either all P2PKH or P2SH outputs.
const Msize = 20

// Vec is a N-element vector of Msize []byte messages.
Expand All @@ -27,19 +32,13 @@ func (v Vec) Equals(other Vec) bool {
return false
}
for i := range other {
if !bytes.Equal((v)[i][:], other[i][:]) {
if v[i] != other[i] {
return false
}
}
return true
}

// M returns the i'th message of the vector.
// XXX: still necessary?
// func (v Vec) M(i uint32) []byte {
// return v[i][:]
// }

func (v Vec) String() string {
b := new(strings.Builder)
b.Grow(2 + len(v)*(2*Msize+1))
Expand Down

0 comments on commit 8978a78

Please sign in to comment.