From ad4c2707b0115516154820b0ee2603a148a4fcaa Mon Sep 17 00:00:00 2001 From: Jan Bormet Date: Mon, 28 Aug 2023 13:57:13 +0200 Subject: [PATCH] Add more benchmarks --- tsibe_test.go | 341 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 287 insertions(+), 54 deletions(-) diff --git a/tsibe_test.go b/tsibe_test.go index 797b635..8a99620 100644 --- a/tsibe_test.go +++ b/tsibe_test.go @@ -3,14 +3,20 @@ package main_test import ( "bytes" "crypto/rand" + "encoding/binary" "fmt" "github.com/stretchr/testify/require" + "go.dedis.ch/kyber/v3" "go.dedis.ch/kyber/v3/pairing" + "go.dedis.ch/kyber/v3/share" "gonum.org/v1/gonum/stat/combin" "math" r "math/rand" + "sync" "testing" "time" + "tsibe/commit" + "tsibe/hash" "tsibe/tsibe" ) @@ -48,15 +54,10 @@ func BenchmarkTSIBE_Enc(b *testing.B) { } func benchEnc(b *testing.B, t, n int, latency time.Duration) { - sets := make([][][]int, n-t+1) - for i := range sets { - sets[i] = combin.Combinations(n, i+t) - } + sets := combin.Combinations(n, t) actualSets := make([][]int, b.N) for i := range actualSets { - numberOfPartiesIndex := r.Intn(n - t + 1) - combination := r.Intn(len(sets[numberOfPartiesIndex])) - actualSets[i] = sets[numberOfPartiesIndex][combination] + actualSets[i] = sets[r.Intn(len(sets))] } e := tsibe.NewTSIBE(pairing.NewSuiteBn256(), t, n, latency) msgs := make([][]byte, b.N) @@ -74,75 +75,307 @@ func benchEnc(b *testing.B, t, n int, latency time.Duration) { receivers[i] = r.Intn(math.MaxUint32) } ciphertexts := make([]tsibe.Ciphertext, b.N) - done := make([]chan struct{}, b.N) - for i := range done { - done[i] = make(chan struct{}) - } + wg := sync.WaitGroup{} b.StartTimer() for i := 0; i < b.N; i++ { + wg.Add(1) go func(i int) { + defer wg.Done() c, _ := e.Enc(senders[i], receivers[i], msgs[i], actualSets[i]) ciphertexts[i] = c - close(done[i]) }(i) } - for i := range done { - <-done[i] - } + wg.Wait() b.StopTimer() - cor := make([]chan bool, b.N) - for i := range cor { - cor[i] = make(chan bool) + // Make sure the compiler doesn't optimize away the benchmark loop. + for i := range ciphertexts { + require.Equal(b, senders[i], ciphertexts[i].Sender) } - for i := range msgs { - go func(i int) { - key, err := e.DeriveIdentityKey(receivers[i], sets[0][0]) - if err != nil { - cor[i] <- false - close(cor[i]) - return - } - res, err := e.Dec(key, ciphertexts[i]) - if err != nil { - cor[i] <- false + // Verify correctness of results. + // We comment it out for computing the actual benchmark results, because it significantly increases the benchmarking + // time. It has no influence on the benchmark results. + /* + cor := make([]chan bool, b.N) + for i := range cor { + cor[i] = make(chan bool) + } + for i := range msgs { + go func(i int) { + key, err := e.DeriveIdentityKey(receivers[i], sets[0]) + if err != nil { + cor[i] <- false + close(cor[i]) + return + } + res, err := e.Dec(key, ciphertexts[i]) + if err != nil { + cor[i] <- false + close(cor[i]) + return + } + if !bytes.Equal(res, msgs[i]) { + cor[i] <- false + close(cor[i]) + return + } + cor[i] <- true close(cor[i]) - return + }(i) + } + for i := range cor { + x := <-cor[i] + require.True(b, x) + }*/ +} + +func BenchmarkTSIBE_EncSingleServer(b *testing.B) { + for par := 1; par <= 24; par++ { + b.Run(fmt.Sprintf(":par=%d", par), func(b *testing.B) { + simulateSingleServer(b, par) + }) + } +} + +func simulateSingleServer(b *testing.B, par int) { + rIDs := make([][]byte, b.N) + sIDs := make([][]byte, b.N) + commitments := make([][]byte, b.N) + right := make([][]byte, b.N) + for i, _ := range rIDs { + rIDs[i] = make([]byte, 4) + _, err := rand.Read(rIDs[i]) + require.NoError(b, err) + sIDs[i] = make([]byte, 4) + _, err = rand.Read(sIDs[i]) + require.NoError(b, err) + commitments[i] = make([]byte, 32) + _, err = rand.Read(commitments[i]) + require.NoError(b, err) + right[i] = make([]byte, 36) + copy(right[i][:4], rIDs[i]) + copy(right[i][4:], commitments[i]) + } + suite := pairing.NewSuiteBn256() + poly := share.NewPriPoly(suite.GT(), 2, nil, suite.RandomStream()) + shares := poly.Shares(6) + sk := shares[0] + results := make([][]kyber.Point, par) + parLeft := make([][][]byte, par) + parRight := make([][][]byte, par) + for i := range parLeft { + start := i * (b.N / par) + if i == par-1 { + parLeft[i] = rIDs[start:] + parRight[i] = right[start:] + results[i] = make([]kyber.Point, b.N-start) + } else { + end := (i + 1) * (b.N / par) + parLeft[i] = rIDs[start:end] + parRight[i] = right[start:end] + results[i] = make([]kyber.Point, end-start) + } + + } + b.ResetTimer() + wg := sync.WaitGroup{} + wg.Add(par) + for i := 0; i < par; i++ { + go func(i int) { + for j := 0; j < len(parLeft[i]); j++ { + le := hash.HashToG1(suite, parLeft[i][j]) + ri := hash.HashToG2(suite, parRight[i][j]) + pt := suite.Pair(le, ri) + pt.Mul(sk.V, pt) + results[i][j] = pt } - if !bytes.Equal(res, msgs[i]) { - cor[i] <- false - close(cor[i]) - return + wg.Done() + }(i) + + } + wg.Wait() + b.StopTimer() + sum := 0 + for i, resPar := range results { + for j, res := range resPar { + require.NotNil(b, res, fmt.Sprintf("i=%d,j=%d", i, j)) + sum += 1 + } + } + require.Equal(b, b.N, sum) +} + +func BenchmarkTSIBE_DIdkSingleServer(b *testing.B) { + for par := 1; par <= 24; par++ { + b.Run(fmt.Sprintf(":par=%d", par), func(b *testing.B) { + simulateSingleServerDIdk(b, par) + }) + } +} + +func simulateSingleServerDIdk(b *testing.B, par int) { + ids := make([][]byte, b.N) + for i, _ := range ids { + ids[i] = make([]byte, 4) + _, err := rand.Read(ids[i]) + require.NoError(b, err) + } + suite := pairing.NewSuiteBn256() + poly := share.NewPriPoly(suite.GT(), 2, nil, suite.RandomStream()) + shares := poly.Shares(6) + sk := shares[0] + results := make([][]kyber.Point, par) + parLeft := make([][][]byte, par) + for i := range parLeft { + start := i * (b.N / par) + if i == par-1 { + parLeft[i] = ids[start:] + results[i] = make([]kyber.Point, b.N-start) + } else { + end := (i + 1) * (b.N / par) + parLeft[i] = ids[start:end] + results[i] = make([]kyber.Point, end-start) + } + + } + b.ResetTimer() + wg := sync.WaitGroup{} + wg.Add(par) + for i := 0; i < par; i++ { + go func(i int) { + for j := 0; j < len(parLeft[i]); j++ { + le := hash.HashToG1(suite, parLeft[i][j]) + le.Mul(sk.V, le) + results[i][j] = le } - cor[i] <- true - close(cor[i]) + wg.Done() }(i) + } - for i := range cor { - x := <-cor[i] - require.True(b, x) + wg.Wait() + b.StopTimer() + sum := 0 + for i, resPar := range results { + for j, res := range resPar { + require.NotNil(b, res, fmt.Sprintf("i=%d,j=%d", i, j)) + sum += 1 + } } + require.Equal(b, b.N, sum) } -/* -func BenchmarkMultiEnc(b *testing.B) { - e := tsibe.NewTSIBE(pairing.NewSuiteBn256(), 2, 6, 100*time.Millisecond) - msgs := make([][]byte, 100) +func BenchmarkTSIBE_Dec(b *testing.B) { + c, m, rec, idk, suite := prepareCiphertexts(5000) + for par := 1; par <= 24; par++ { + b.Run(fmt.Sprintf(":par=%d", par), func(b *testing.B) { + dec(b, par, suite, c[:b.N], m[:b.N], rec, idk) + }) + } +} + +func prepareCiphertexts(amt int) ([]tsibe.Ciphertext, [][]byte, int, kyber.Point, *pairing.SuiteBn256) { + t := 2 + n := 3 + msgs := make([][]byte, amt) for i := range msgs { msgs[i] = make([]byte, 32) _, err := rand.Read(msgs[i]) - require.NoError(b, err) + if err != nil { + panic(err) + } } - b.StartTimer() - ctxts, err := e.MultiEnc(0, 100, msgs, []int{0, 1}) + senders := make([]int, amt) + for i := range senders { + senders[i] = r.Intn(math.MaxUint32) + } + receiver := 42 + sets := combin.Combinations(n, t) + actualSets := make([][]int, amt) + for i := range actualSets { + actualSets[i] = sets[r.Intn(len(sets))] + } + e := tsibe.NewTSIBE(pairing.NewSuiteBn256(), t, n, 0) + ciphertexts := make([]tsibe.Ciphertext, amt) + wg := sync.WaitGroup{} + for i := 0; i < amt; i++ { + wg.Add(1) + go func(i int) { + defer wg.Done() + c, _ := e.Enc(senders[i], receiver, msgs[i], actualSets[i]) + ciphertexts[i] = c + }(i) + } + wg.Wait() + idk, err := e.DeriveIdentityKey(receiver, sets[0]) + if err != nil { + panic(err) + } + return ciphertexts, msgs, receiver, idk, e.Suite + +} + +func dec(b *testing.B, par int, s *pairing.SuiteBn256, ciphertexts []tsibe.Ciphertext, messages [][]byte, rec int, idk kyber.Point) { + recBytes := make([]byte, 4) + binary.LittleEndian.PutUint32(recBytes, uint32(rec)) + results := make([][][]byte, par) + cPar := make([][]tsibe.Ciphertext, par) + expected := make([][][]byte, par) + for i := range cPar { + start := i * (b.N / par) + if i == par-1 { + cPar[i] = ciphertexts[start:] + expected[i] = messages[start:] + results[i] = make([][]byte, b.N-start) + } else { + end := (i + 1) * (b.N / par) + cPar[i] = ciphertexts[start:end] + expected[i] = messages[start:end] + results[i] = make([][]byte, end-start) + } + + } + + wg := sync.WaitGroup{} + wg.Add(par) + b.ResetTimer() + for i := 0; i < par; i++ { + go func(i int) { + for j, c := range cPar[i] { + senBytes := make([]byte, 4) + binary.LittleEndian.PutUint32(senBytes, uint32(c.Sender)) + wk := deriveFromLeftKey(s, idk, append(senBytes, c.Commitment...)) + wkBytes, err := wk.MarshalBinary() + if err != nil { + panic(err) + } + mAndO := make([]byte, len(c.Gamma)) + s.XOF(wkBytes).XORKeyStream(mAndO, c.Gamma) + m := mAndO[:len(c.Gamma)-256] + o := mAndO[len(c.Gamma)-256:] + cIn := make([]byte, len(m)+len(recBytes)) + copy(cIn[:len(m)], m) + copy(cIn[len(m):], recBytes) + if commit.Verify(s, c.Commitment, o, cIn) { + results[i][j] = m + } else { + panic("invalid ciphertext") + } + } + wg.Done() + }(i) + + } + wg.Wait() b.StopTimer() - require.NoError(b, err) - key, err := e.DeriveIdentityKey(100, []int{0, 1}) - require.NoError(b, err) - for i := range msgs { - res, err := e.Dec(key, ctxts[i]) - require.NoError(b, err) - require.True(b, bytes.Equal(res, msgs[i])) + for i, resPar := range results { + for j, res := range resPar { + require.True(b, bytes.Equal(res, expected[i][j]), fmt.Sprintf("i=%d,j=%d", i, j)) + } } -}*/ +} + +func deriveFromLeftKey(suite *pairing.SuiteBn256, left kyber.Point, right []byte) kyber.Point { + wk := hash.HashToG2(suite, right) + return suite.Pair(left, wk) +}