-
Notifications
You must be signed in to change notification settings - Fork 0
/
authdataspec_property_test.go
109 lines (96 loc) · 2.87 KB
/
authdataspec_property_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package byzq
import (
"math"
"reflect"
"testing"
"github.com/leanovate/gopter"
"github.com/leanovate/gopter/gen"
"github.com/leanovate/gopter/prop"
)
func TestAuthDataQSpecProperties(t *testing.T) {
properties := gopter.NewProperties(nil)
properties.Property("undefined for all n <= 3", prop.ForAll(
func(n int) bool {
bq, err := NewAuthDataQ(n, priv, &priv.PublicKey)
return err != nil && bq == nil
},
gen.IntRange(math.MinInt32, 3),
))
properties.Property("3(f+1) >= n >= 3f+1", prop.ForAll(
func(n int) bool {
bq, err := NewAuthDataQ(n, priv, &priv.PublicKey)
return err == nil && n >= 3*bq.f+1 && n <= 3*(bq.f+1)
},
gen.IntRange(4, math.MaxInt32),
))
properties.TestingRun(t)
}
func TestAuthDataQuorumProperties(t *testing.T) {
properties := gopter.NewProperties(nil)
type qfParams struct {
quorumSize int
qspec *AuthDataQ
}
replyGen := func(numReplies int) []*Value {
sliceGen := gen.SliceOfN(numReplies, gen.Const(myVal))
result := sliceGen(gopter.DefaultGenParameters())
value, ok := result.Retrieve()
if !ok || value == nil {
t.Fatalf("invalid value: %#v", value)
}
replies, ok := value.([]*Value)
if !ok || len(replies) != numReplies {
t.Fatalf("invalid number of replies: %d, expected: %d", len(replies), numReplies)
}
return replies
}
quorumRangeGen := func(min, max int, qspec *AuthDataQ) gopter.Gen {
return gen.IntRange(min, max).Map(func(quorumSize interface{}) *qfParams {
return &qfParams{quorumSize.(int), qspec}
})
}
properties.Property("no quorum unless enough replies", prop.ForAll(
func(params *qfParams) bool {
replies := replyGen(params.quorumSize)
reply, byzquorum := params.qspec.ReadQF(replies)
return !byzquorum && reply == nil
},
gen.IntRange(4, 200).FlatMap(func(n interface{}) gopter.Gen {
qspec, err := NewAuthDataQ(n.(int), priv, &priv.PublicKey)
if err != nil {
t.Fatalf("failed to create quorum specification for size %d", n)
}
return quorumRangeGen(0, qspec.q, qspec)
}, reflect.TypeOf(&qfParams{})),
))
properties.Property("sufficient replies guarantees a quorum", prop.ForAll(
func(params *qfParams) bool {
replies := replyGen(params.quorumSize)
var err error
for i, r := range replies {
replies[i], err = params.qspec.Sign(r.C)
if err != nil {
t.Fatal("failed to sign message")
}
}
reply, byzquorum := params.qspec.SequentialVerifyReadQF(replies)
if !byzquorum {
return false
}
for _, r := range replies {
if reply.Equal(r.GetC()) {
return true
}
}
return false
},
gen.IntRange(4, 200).FlatMap(func(n interface{}) gopter.Gen {
qspec, err := NewAuthDataQ(n.(int), priv, &priv.PublicKey)
if err != nil {
t.Fatalf("failed to create quorum specification for size %d", n)
}
return quorumRangeGen(qspec.q+1, qspec.n, qspec)
}, reflect.TypeOf(&qfParams{})),
))
properties.TestingRun(t)
}