-
Notifications
You must be signed in to change notification settings - Fork 295
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This introduces a new package and module containing code for supporting peer-to-peer transaction mixing derived from CoinShuffle++. The mixing package contains the function and type primitives that will be used by mixing clients to perform the slot reservation and XOR DC-nets.
- Loading branch information
Showing
15 changed files
with
1,107 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
package mixing | ||
|
||
import ( | ||
"encoding/binary" | ||
"math/big" | ||
|
||
"github.com/decred/dcrd/crypto/blake256" | ||
"github.com/decred/dcrd/wire" | ||
) | ||
|
||
// SRMixPads creates a vector of exponential DC-net pads from a vector of | ||
// shared secrets with each participating peer in the DC-net. | ||
func SRMixPads(kp [][]byte, my uint32) []*big.Int { | ||
h := blake256.New() | ||
scratch := make([]byte, 8) | ||
|
||
pads := make([]*big.Int, len(kp)) | ||
partialPad := new(big.Int) | ||
for j := uint32(0); int(j) < len(kp); j++ { | ||
pads[j] = new(big.Int) | ||
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) | ||
digest := h.Sum(nil) | ||
partialPad.SetBytes(digest) | ||
if my > i { | ||
pads[j].Add(pads[j], partialPad) | ||
} else { | ||
pads[j].Sub(pads[j], partialPad) | ||
} | ||
} | ||
pads[j].Mod(pads[j], F) | ||
} | ||
return pads | ||
} | ||
|
||
// SRMix creates the padded {m**1, m**2, ..., m**n} message exponentials | ||
// vector. Message must be bounded by the field prime and must be unique to | ||
// every exponential SR run in a mix session to ensure anonymity. | ||
func SRMix(m *big.Int, pads []*big.Int) []*big.Int { | ||
mix := make([]*big.Int, len(pads)) | ||
exp := new(big.Int) | ||
for i := int64(0); i < int64(len(mix)); i++ { | ||
mexp := new(big.Int).Exp(m, exp.SetInt64(i+1), nil) | ||
mix[i] = mexp.Add(mexp, pads[i]) | ||
mix[i].Mod(mix[i], F) | ||
} | ||
return mix | ||
} | ||
|
||
// IntVectorsFromBytes creates a 2-dimensional *big.Int slice from their absolute | ||
// values as bytes. | ||
func IntVectorsFromBytes(vs [][][]byte) [][]*big.Int { | ||
ints := make([][]*big.Int, len(vs)) | ||
for i := range vs { | ||
ints[i] = make([]*big.Int, len(vs[i])) | ||
for j := range vs[i] { | ||
ints[i][j] = new(big.Int).SetBytes(vs[i][j]) | ||
} | ||
} | ||
return ints | ||
} | ||
|
||
// IntVectorsToBytes creates a 2-dimensional slice of big.Int absolute values as | ||
// bytes. | ||
func IntVectorsToBytes(ints [][]*big.Int) [][][]byte { | ||
bytes := make([][][]byte, len(ints)) | ||
for i := range ints { | ||
bytes[i] = make([][]byte, len(ints[i])) | ||
for j := range ints[i] { | ||
bytes[i][j] = ints[i][j].Bytes() | ||
} | ||
} | ||
return bytes | ||
} | ||
|
||
// AddVectors sums each vector element over F, returning a new vector. When | ||
// peers are honest (DC-mix pads sum to zero) this creates the unpadded vector | ||
// of message power sums. | ||
func AddVectors(vs ...[]*big.Int) []*big.Int { | ||
sums := make([]*big.Int, len(vs)) | ||
for i := range sums { | ||
sums[i] = new(big.Int) | ||
for j := range vs { | ||
sums[i].Add(sums[i], vs[j][i]) | ||
} | ||
sums[i].Mod(sums[i], F) | ||
} | ||
return sums | ||
} | ||
|
||
// Coefficients calculates a{0}..a{n} for the polynomial: | ||
// | ||
// g(x) = a{0} + a{1}x + a{2}x**2 + ... + a{n-1}x**(n-1) + a{n}x**n (mod F) | ||
// | ||
// where | ||
// | ||
// a{n} = -1 | ||
// a{n-1} = -(1/1) * a{n}*S{0} | ||
// a{n-2} = -(1/2) * (a{n-1}*S{0} + a{n}*S{1}) | ||
// a{n-3} = -(1/3) * (a{n-2}*S{0} + a{n-1}*S{1} + a{n}*S{2}) | ||
// ... | ||
// | ||
// The roots of this polynomial are the set of recovered messages. | ||
// | ||
// Note that the returned slice of coefficients is one element larger than the | ||
// slice of partial sums. | ||
func Coefficients(S []*big.Int) []*big.Int { | ||
n := len(S) + 1 | ||
a := make([]*big.Int, n) | ||
a[len(a)-1] = big.NewInt(-1) | ||
a[len(a)-1].Add(a[len(a)-1], F) // a{n} = -1 (mod F) = F - 1 | ||
scratch := new(big.Int) | ||
for i := 0; i < len(a)-1; i++ { | ||
a[n-2-i] = new(big.Int) | ||
for j := 0; j <= i; j++ { | ||
a[n-2-i].Add(a[n-2-i], scratch.Mul(a[n-1-i+j], S[j])) | ||
} | ||
xinv := scratch.ModInverse(scratch.SetInt64(int64(i)+1), F) | ||
xinv.Neg(xinv) | ||
a[n-2-i].Mul(a[n-2-i], xinv) | ||
a[n-2-i].Mod(a[n-2-i], F) | ||
} | ||
return a | ||
} | ||
|
||
// IsRoot checks that the message m is a root of the polynomial with | ||
// coefficients a (mod F) without solving for every root. | ||
func IsRoot(m *big.Int, a []*big.Int) bool { | ||
sum := new(big.Int) | ||
scratch := new(big.Int) | ||
for i := range a { | ||
scratch.Exp(m, scratch.SetInt64(int64(i)), F) | ||
scratch.Mul(scratch, a[i]) | ||
sum.Add(sum, scratch) | ||
} | ||
sum.Mod(sum, F) | ||
return sum.Sign() == 0 | ||
} | ||
|
||
// DCMixPads creates the vector of DC-net pads from shared secrets with each mix | ||
// participant. | ||
func DCMixPads(kp []wire.MixVect, my uint32) Vec { | ||
pads := make(Vec, len(kp)) | ||
for i := range kp { | ||
if i == int(my) { | ||
continue | ||
} | ||
pads.Xor(pads, (Vec)(kp[i])) | ||
} | ||
return pads | ||
} | ||
|
||
// DCMix creates the DC-net vector of message m xor'd into m's reserved | ||
// anonymous slot position of the pads DC-net pads. Panics if len(m) is not the | ||
// vector's message size. | ||
func DCMix(pads Vec, m []byte, slot uint32) Vec { | ||
if len(m) != Msize { | ||
panic("m is not len Msize") | ||
} | ||
|
||
dcmix := make(Vec, len(pads)) | ||
copy(dcmix, pads) | ||
slotm := dcmix[slot][:] | ||
for i := range m { | ||
slotm[i] ^= m[i] | ||
} | ||
return dcmix | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
// Copyright (c) 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 ( | ||
"errors" | ||
"fmt" | ||
) | ||
|
||
var ( | ||
ErrInvalidPROrder = errors.New("invalid pair request order") | ||
|
||
ErrInvalidSessionID = errors.New("invalid session ID") | ||
) | ||
|
||
type DecapsulateError struct { | ||
SubmittingIndex uint32 | ||
Err error | ||
} | ||
|
||
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// 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 | ||
|
||
import ( | ||
"time" | ||
|
||
"github.com/decred/dcrd/chaincfg/v3" | ||
) | ||
|
||
// MaxExpiry returns the maximum allowed expiry for a new pair request message | ||
// created with a blockchain tip at tipHeight. | ||
func MaxExpiry(tipHeight uint32, params *chaincfg.Params) uint32 { | ||
target := params.TargetTimePerBlock | ||
return tipHeight + uint32(60*time.Minute/target) + 1 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package mixing | ||
|
||
import ( | ||
"math/big" | ||
) | ||
|
||
// FieldPrime is the field prime 2**127 - 1. | ||
var F *big.Int | ||
|
||
func init() { | ||
F, _ = new(big.Int).SetString("7fffffffffffffffffffffffffffffff", 16) | ||
} | ||
|
||
// InField returns whether x is bounded by the field F. | ||
func InField(x *big.Int) bool { | ||
return x.Sign() != -1 && x.Cmp(F) == -1 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package mixing | ||
|
||
const ( | ||
// PRFlagCanSolveRoots describes a bit in the pair request flags field | ||
// indicating support for solving and publishing factored slot | ||
// reservation polynomials. | ||
PRFlagCanSolveRoots byte = 1 << iota | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
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 | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
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= | ||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= | ||
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= | ||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= | ||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= | ||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= | ||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= | ||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= | ||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= | ||
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= | ||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | ||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= | ||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= | ||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= | ||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= | ||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= | ||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= | ||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | ||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= | ||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= | ||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||
lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= | ||
lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= |
Oops, something went wrong.