Skip to content

Commit

Permalink
mixclient: Sort roots for slot assignment
Browse files Browse the repository at this point in the history
The purpose of the SR (slot reservation) mix is to determine unique anonymous
slot positions for the DC-net (xor) mix.  However, there was a missing check
by non-root-solving peers that the published roots are in the proper order.
This could result in a malicious actor publishing roots in a different order,
disrupting mixes by causing non-root-solving peers to unknowingly perform the
DC-net in the wrong slots, and causing the wrong peers to be blamed for
disrupting the mix.

Prevent this by requiring roots to be sorted before slots are discovered.
This also matches the root-sorting that occurred in the older client-server
design.

This change is not compatible with previous mixclient versions, as the DC-net
mix would occur with peers writing messages into different slots.  The pairing
version included in PR messages is updated to reflect this.
  • Loading branch information
jrick authored and davecgh committed Nov 11, 2024
1 parent fa50dce commit 5634e0f
Showing 1 changed file with 11 additions and 2 deletions.
13 changes: 11 additions & 2 deletions mixing/mixclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import (
// MinPeers is the minimum number of peers required for a mix run to proceed.
const MinPeers = 4

const pairingFlags byte = 0
const pairingVersion byte = 1

const (
timeoutDuration = 30 * time.Second
Expand Down Expand Up @@ -725,7 +725,7 @@ func (c *Client) Dicemix(ctx context.Context, cj *CoinJoin) error {
pr, err := wire.NewMsgMixPairReq(*p.id, cj.prExpiry, cj.mixValue,
string(mixing.ScriptClassP2PKHv0), cj.tx.Version,
cj.tx.LockTime, cj.mcount, cj.inputValue, cj.prUTXOs,
cj.change, prFlags, pairingFlags)
cj.change, prFlags, pairingVersion)
if err != nil {
return err
}
Expand Down Expand Up @@ -1731,6 +1731,9 @@ func (c *Client) roots(ctx context.Context, seenSRs []chainhash.Hash,
close(publishedRoots)
return nil, errTriggeredBlame
}
sort.Slice(roots, func(i, j int) bool {
return roots[i].Cmp(roots[j]) == -1
})
rootBytes := make([][]byte, len(roots))
for i, root := range roots {
rootBytes[i] = root.Bytes()
Expand Down Expand Up @@ -1802,6 +1805,12 @@ func (c *Client) roots(ctx context.Context, seenSRs []chainhash.Hash,
roots = append(roots, root)
}
}
sorted := sort.SliceIsSorted(roots, func(i, j int) bool {
return roots[i].Cmp(roots[j]) == -1
})
if !sorted {
continue
}
if len(roots) == len(a)-1 {
return roots, nil
}
Expand Down

0 comments on commit 5634e0f

Please sign in to comment.