consensus_test.go raw
1 package gnarlring
2
3 import (
4 "math"
5 "testing"
6 )
7
8 func TestCastVote(t *testing.T) {
9 yes := CastVote(1)
10 no := CastVote(-1)
11
12 if IsZero(yes.Z) || IsZero(no.Z) {
13 t.Fatal("vote vectors are zero")
14 }
15
16 // YES: first coefficient = 1. NO: first coefficient = Q-1.
17 if yes.Z.Coeffs[0] != 1 {
18 t.Fatalf("YES vote coeff[0] = %d, want 1", yes.Z.Coeffs[0])
19 }
20 if no.Z.Coeffs[0] != Q-1 {
21 t.Fatalf("NO vote coeff[0] = %d, want %d", no.Z.Coeffs[0], Q-1)
22 }
23
24 // Other coefficients should be Gaussian (non-zero on average).
25 nonZeroCount := 0
26 for i := 1; i < N; i++ {
27 if yes.Z.Coeffs[i] != 0 || no.Z.Coeffs[i] != 0 {
28 nonZeroCount++
29 }
30 }
31 if nonZeroCount < 10 {
32 t.Fatalf("only %d/26 non-zero Gaussian coefficients — unlikely", nonZeroCount)
33 }
34 }
35
36 func TestVoteTally(t *testing.T) {
37 tally := NewVoteTally()
38 for i := 0; i < 15; i++ {
39 tally.Add(CastVote(1), true)
40 }
41 for i := 0; i < 12; i++ {
42 tally.Add(CastVote(-1), false)
43 }
44
45 if tally.YesCount != 15 || tally.NoCount != 12 {
46 t.Fatalf("yes=%d no=%d", tally.YesCount, tally.NoCount)
47 }
48
49 if !tally.ConsensusResult(10) {
50 t.Fatal("threshold 10 should pass with 15 yes")
51 }
52 if !tally.ConsensusResult(14) {
53 t.Fatal("threshold 14 should pass with 15 yes")
54 }
55 if tally.ConsensusResult(16) {
56 t.Fatal("threshold 16 should fail with 15 yes")
57 }
58
59 normVal := math.Sqrt(float64(NormSq(tally.Z)))
60 maxPossible := float64(tally.YesCount+tally.NoCount) * 150.0
61 t.Logf("tally norm=%.0f max=%.0f", normVal, maxPossible)
62 if normVal > maxPossible {
63 t.Fatalf("tally norm %.0f exceeds max %.0f", normVal, maxPossible)
64 }
65 }
66
67 func TestEncryptedVote(t *testing.T) {
68 lwePK, lweSK := LWEKeyGen()
69
70 yes := CastVote(1)
71 ev := EncryptVote(lwePK, yes, nil)
72 if ev.Ct == nil {
73 t.Fatal("encrypted vote is nil")
74 }
75
76 result := DecryptVote(lweSK, ev)
77 if !result {
78 t.Fatal("decrypted vote should be YES")
79 }
80
81 no := CastVote(-1)
82 evNo := EncryptVote(lwePK, no, nil)
83 resultNo := DecryptVote(lweSK, evNo)
84 if resultNo {
85 t.Fatal("decrypted NO vote should be false")
86 }
87
88 correct := 0
89 for trial := 0; trial < 50; trial++ {
90 v := CastVote(1)
91 ev := EncryptVote(lwePK, v, nil)
92 if DecryptVote(lweSK, ev) {
93 correct++
94 }
95 }
96 t.Logf("encrypted vote accuracy: %d/50", correct)
97 if correct < 45 {
98 t.Fatalf("encrypted vote accuracy %d/50 < 90%%", correct)
99 }
100 }
101
102 func BenchmarkCastVote(b *testing.B) {
103 b.ReportAllocs()
104 for i := 0; i < b.N; i++ {
105 CastVote(1)
106 }
107 }
108
109 func BenchmarkVoteSum(b *testing.B) {
110 votes := make([]*Vote, 27)
111 for i := range votes {
112 votes[i] = CastVote(1)
113 }
114 tally := NewVoteTally()
115 b.ReportAllocs()
116 b.ResetTimer()
117 for i := 0; i < b.N; i++ {
118 for _, v := range votes {
119 tally.Add(v, true)
120 }
121 }
122 }
123