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