shard_test.go raw
1 package gnarlring
2
3 import "testing"
4
5 func TestShareSecret(t *testing.T) {
6 // Generate a master secret and split into 5 shares.
7 _, sk := LWEKeyGen()
8 master := sk.S
9
10 shares := ShareSecret(master, 5)
11 if len(shares) != 5 {
12 t.Fatalf("got %d shares, want 5", len(shares))
13 }
14
15 // Verify Σ shares = master.
16 sum := NewPoly27()
17 for _, s := range shares {
18 sum = Add(sum, s)
19 }
20 if !Equal(sum, master) {
21 t.Fatal("Σ shares ≠ master secret")
22 }
23 }
24
25 func TestDistributedDecryption(t *testing.T) {
26 seed := []byte("common-reference-string")
27 a := GenerateSharedA(seed)
28
29 // 5 parties generate keys with shared A.
30 k := 5
31 pks := make([]*LWEPublicKey, k)
32 sks := make([]*LWESecretKey, k)
33 for i := 0; i < k; i++ {
34 pks[i], sks[i] = LWEKeyGenWithA(a)
35 }
36
37 // Aggregate public key.
38 aggPK := LWEKeyAgg(pks)
39
40 // Encrypt under aggregate key.
41 for _, bit := range []int{0, 1} {
42 correct := 0
43 secrets := make([]*Poly27, k)
44 for i := 0; i < k; i++ {
45 secrets[i] = sks[i].S
46 }
47 for trial := 0; trial < 50; trial++ {
48 ct := EncryptGroup(aggPK, bit)
49
50 // Each party computes partial decryption.
51 partials := make([]*Poly27, k)
52 for i := 0; i < k; i++ {
53 partials[i] = PartialDecryption(secrets[i], ct.U)
54 }
55
56 dec := DistributedDecrypt(ct, partials)
57 if dec == bit {
58 correct++
59 }
60 }
61 rate := float64(correct) / 50.0
62 t.Logf("bit=%d: %d/50 correct (%.1f%%)", bit, correct, rate*100)
63 if rate < 0.85 {
64 t.Errorf("distributed decryption rate %.1f%% < 85%% for bit=%d", rate*100, bit)
65 }
66 }
67 }
68
69 func TestDistributedDecryptionSubset(t *testing.T) {
70 seed := []byte("threshold-crs")
71 a := GenerateSharedA(seed)
72
73 k := 7
74 pks := make([]*LWEPublicKey, k)
75 sks := make([]*LWESecretKey, k)
76 for i := 0; i < k; i++ {
77 pks[i], sks[i] = LWEKeyGenWithA(a)
78 }
79 aggPK := LWEKeyAgg(pks)
80
81 // Encrypt under aggregate key.
82 ct := EncryptGroup(aggPK, 1)
83
84 // 3 of 7 parties decrypt (subsets work with additive shares).
85 partials := make([]*Poly27, 3)
86 for i := 0; i < 3; i++ {
87 partials[i] = PartialDecryption(sks[i].S, ct.U)
88 }
89
90 // Incomplete share set — decryption should fail (the sum of 3 shares
91 // doesn't decode correctly because the encrypted aggregate uses
92 // all 7 secrets).
93 dec := DistributedDecrypt(ct, partials)
94 t.Logf("subset decryption (3/7): %d (expected failure)", dec)
95 // This will usually NOT decode correctly with only 3 of 7 shares.
96 }
97
98 func TestSharedADeterministic(t *testing.T) {
99 seed := []byte("deterministic-a")
100 a1 := GenerateSharedA(seed)
101 a2 := GenerateSharedA(seed)
102 if !Equal(a1, a2) {
103 t.Fatal("shared A is not deterministic")
104 }
105
106 a3 := GenerateSharedA([]byte("different-seed"))
107 if Equal(a1, a3) {
108 t.Fatal("different seeds produced same A")
109 }
110 }
111