Skip to content

Commit

Permalink
Merge pull request #171 from SiaFoundation/add-spendpolicy-fuzzer
Browse files Browse the repository at this point in the history
Add SpendPolicy fuzzer
  • Loading branch information
n8maninger committed Jun 15, 2024
2 parents 36ea9c7 + fc3d451 commit 2c5f229
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 2 deletions.
11 changes: 9 additions & 2 deletions types/encoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -1185,8 +1185,15 @@ func (sp *SatisfiedPolicy) DecodeFrom(d *Decoder) {
rec(p.Of[i])
}
case PolicyTypeUnlockConditions:
for i := range p.PublicKeys {
rec(PolicyPublicKey(*(*PublicKey)(p.PublicKeys[i].Key)))
for _, uk := range p.PublicKeys {
if len(uk.Key) != 32 {
d.SetErr(fmt.Errorf("invalid public key length: %d", len(uk.Key)))
return
} else if uk.Algorithm != SpecifierEd25519 {
d.SetErr(fmt.Errorf("invalid specifier: %v", uk.Algorithm))
return
}
rec(PolicyPublicKey(*(*PublicKey)(uk.Key)))
}
default:
// nothing to do
Expand Down
124 changes: 124 additions & 0 deletions types/encoding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ package types_test
import (
"bytes"
"fmt"
"math"
"testing"
"time"

"go.sia.tech/core/types"
"lukechampine.com/frand"
)

func TestEncodeSlice(t *testing.T) {
Expand Down Expand Up @@ -49,3 +52,124 @@ func TestEncodeSlice(t *testing.T) {
t.Fatal(err)
}
}

func encode(x types.EncoderTo) []byte {
var buf bytes.Buffer
e := types.NewEncoder(&buf)
x.EncodeTo(e)
e.Flush()
return buf.Bytes()
}

func policyCorpus() []types.SpendPolicy {
privateKey := types.GeneratePrivateKey()
publicKey := privateKey.PublicKey()

var hash types.Hash256
frand.Read(hash[:])

date := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)

return []types.SpendPolicy{
types.PolicyAbove(0),
types.PolicyAbove(math.MaxUint64),
types.PolicyAfter(time.Time{}),
types.PolicyAfter(date),
types.PolicyPublicKey(types.PublicKey{}),
types.PolicyPublicKey(publicKey),
types.PolicyHash(types.Hash256{}),
types.PolicyHash(hash),
types.AnyoneCanSpend(),
types.PolicyOpaque(types.PolicyAbove(0)),
{types.PolicyTypeUnlockConditions{
PublicKeys: []types.UnlockKey{{Key: publicKey[:], Algorithm: types.SpecifierEd25519}},
SignaturesRequired: 1,
}},
{types.PolicyTypeUnlockConditions{
Timelock: uint64(date.Unix()),
PublicKeys: []types.UnlockKey{{Key: publicKey[:], Algorithm: types.SpecifierEd25519}},
SignaturesRequired: 1,
}},
{types.PolicyTypeUnlockConditions{
PublicKeys: []types.UnlockKey{
{Key: publicKey[:], Algorithm: types.SpecifierEd25519},
{Key: publicKey[:], Algorithm: types.SpecifierEd25519},
},
SignaturesRequired: 1,
}},
{types.PolicyTypeUnlockConditions{
Timelock: uint64(date.Unix()),
PublicKeys: []types.UnlockKey{
{Key: publicKey[:], Algorithm: types.SpecifierEd25519},
{Key: publicKey[:], Algorithm: types.SpecifierEd25519},
},
SignaturesRequired: 2,
}},
}
}
func FuzzSpendPolicy(f *testing.F) {
seeds := policyCorpus()
for _, seed := range seeds {
f.Add(encode(seed))
}

for i := 0; i < 10; i++ {
rng := frand.Uint64n(uint64(len(seeds)) / 2)
frand.Shuffle(len(seeds), func(i, j int) {
seeds[i], seeds[j] = seeds[j], seeds[i]
})
sp := types.PolicyThreshold(uint8(rng), seeds[:rng])

f.Add(encode(sp))
}

f.Fuzz(func(t *testing.T, data []byte) {
d := types.NewBufDecoder(data)

var sp types.SpendPolicy
sp.DecodeFrom(d)
})
}

func FuzzSatisfiedPolicy(f *testing.F) {
// Some of the satisfied policies we randomly generate are invalid
// and cannot be encoded without panics
tryAddEncode := func(x types.EncoderTo) {
defer func() {
recover()
}()
f.Add(encode(x))
}

policies := policyCorpus()

var signatures [16]types.Signature
for i := 0; i < len(signatures); i++ {
frand.Read(signatures[i][:])
}

var preimages [16][]byte
for i := 0; i < len(preimages); i++ {
preimages[i] = make([]byte, frand.Uint64n(32))
frand.Read(preimages[i])
}

for i := 0; i < 256; i++ {
policy := policies[frand.Uint64n(uint64(len(policies)))]
sigs := signatures[:frand.Uint64n(uint64(len(signatures)))]
pre := preimages[:frand.Uint64n(uint64(len(preimages)))]

tryAddEncode(types.SatisfiedPolicy{
Policy: policy,
Signatures: sigs,
Preimages: pre,
})
}

f.Fuzz(func(t *testing.T, data []byte) {
d := types.NewBufDecoder(data)

var sp types.SatisfiedPolicy
sp.DecodeFrom(d)
})
}

0 comments on commit 2c5f229

Please sign in to comment.