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