1// Copyright (c) 2019 Andreas Auernhammer. All rights reserved.
2// Use of this source code is governed by a license that can be
3// found in the LICENSE file.
4
5package sio
6
7import (
8	"bytes"
9	"io"
10	"testing"
11)
12
13func BenchmarkEncrypt(b *testing.B) {
14	s, err := AES_128_GCM.Stream(make([]byte, 16))
15	if err != nil {
16		b.Fatalf("Failed to create Stream: %v", err)
17	}
18
19	b.Run("Write", func(b *testing.B) {
20		b.Run("1K", func(b *testing.B) { benchEncryptWrite(b, s, 1024) })
21		b.Run("64K", func(b *testing.B) { benchEncryptWrite(b, s, 64*1024) })
22		b.Run("512K", func(b *testing.B) { benchEncryptWrite(b, s, 512*1024) })
23		b.Run("1M", func(b *testing.B) { benchEncryptWrite(b, s, 1024*1024) })
24	})
25	b.Run("WriteTo", func(b *testing.B) {
26		b.Run("1K", func(b *testing.B) { benchEncryptWriteTo(b, s, 1024) })
27		b.Run("64K", func(b *testing.B) { benchEncryptWriteTo(b, s, 64*1024) })
28		b.Run("512K", func(b *testing.B) { benchEncryptWriteTo(b, s, 512*1024) })
29		b.Run("1M", func(b *testing.B) { benchEncryptWriteTo(b, s, 1024*1024) })
30	})
31	b.Run("Read", func(b *testing.B) {
32		b.Run("1K", func(b *testing.B) { benchEncryptRead(b, s, 1024) })
33		b.Run("64K", func(b *testing.B) { benchEncryptRead(b, s, 64*1024) })
34		b.Run("512K", func(b *testing.B) { benchEncryptRead(b, s, 512*1024) })
35		b.Run("1M", func(b *testing.B) { benchEncryptRead(b, s, 1024*1024) })
36	})
37	b.Run("ReadFrom", func(b *testing.B) {
38		b.Run("1K", func(b *testing.B) { benchEncryptReadFrom(b, s, 1024) })
39		b.Run("64K", func(b *testing.B) { benchEncryptReadFrom(b, s, 64*1024) })
40		b.Run("512K", func(b *testing.B) { benchEncryptReadFrom(b, s, 512*1024) })
41		b.Run("1M", func(b *testing.B) { benchEncryptReadFrom(b, s, 1024*1024) })
42	})
43}
44
45func BenchmarkDecrypt(b *testing.B) {
46	s, err := AES_128_GCM.Stream(make([]byte, 16))
47	if err != nil {
48		b.Fatalf("Failed to create Stream: %v", err)
49	}
50
51	b.Run("Write", func(b *testing.B) {
52		b.Run("1K", func(b *testing.B) { benchDecryptWrite(b, s, 1024) })
53		b.Run("64K", func(b *testing.B) { benchDecryptWrite(b, s, 64*1024) })
54		b.Run("512K", func(b *testing.B) { benchDecryptWrite(b, s, 512*1024) })
55		b.Run("1M", func(b *testing.B) { benchDecryptWrite(b, s, 1024*1024) })
56	})
57	b.Run("WriteTo", func(b *testing.B) {
58		b.Run("1K", func(b *testing.B) { benchDecryptWriteTo(b, s, 1024) })
59		b.Run("64K", func(b *testing.B) { benchDecryptWriteTo(b, s, 64*1024) })
60		b.Run("512K", func(b *testing.B) { benchDecryptWriteTo(b, s, 512*1024) })
61		b.Run("1M", func(b *testing.B) { benchDecryptWriteTo(b, s, 1024*1024) })
62	})
63	b.Run("Read", func(b *testing.B) {
64		b.Run("1K", func(b *testing.B) { benchDecryptRead(b, s, 1024) })
65		b.Run("64K", func(b *testing.B) { benchDecryptRead(b, s, 64*1024) })
66		b.Run("512K", func(b *testing.B) { benchDecryptRead(b, s, 512*1024) })
67		b.Run("1M", func(b *testing.B) { benchDecryptRead(b, s, 1024*1024) })
68	})
69	b.Run("ReadFrom", func(b *testing.B) {
70		b.Run("1K", func(b *testing.B) { benchDecryptReadFrom(b, s, 1024) })
71		b.Run("64K", func(b *testing.B) { benchDecryptReadFrom(b, s, 64*1024) })
72		b.Run("512K", func(b *testing.B) { benchDecryptReadFrom(b, s, 512*1024) })
73		b.Run("1M", func(b *testing.B) { benchDecryptReadFrom(b, s, 1024*1024) })
74	})
75	b.Run("ReadAt", func(b *testing.B) {
76		b.Run("1K", func(b *testing.B) { benchDecryptReadAt(b, s, 0, 1024) })
77		b.Run("64K", func(b *testing.B) { benchDecryptReadAt(b, s, 0, 64*1024) })
78		b.Run("512K", func(b *testing.B) { benchDecryptReadAt(b, s, 0, 512*1024) })
79		b.Run("1M", func(b *testing.B) { benchDecryptReadAt(b, s, 0, 1024*1024) })
80
81		b.Run("512_1K", func(b *testing.B) { benchDecryptReadAt(b, s, 512, 1024) })
82		b.Run("1K_64K", func(b *testing.B) { benchDecryptReadAt(b, s, 1024, 64*1024) })
83		b.Run("65K_512K", func(b *testing.B) { benchDecryptReadAt(b, s, 65*1024, 512*1024) })
84		b.Run("129K_1M", func(b *testing.B) { benchDecryptReadAt(b, s, 129*1024, 1024*1024) })
85	})
86}
87
88func benchEncryptWrite(b *testing.B, s *Stream, size int64) {
89	w := s.EncryptWriter(DevNull, make([]byte, s.NonceSize()), nil)
90	plaintext := make([]byte, size)
91	b.SetBytes(size)
92	b.ResetTimer()
93	for i := 0; i < b.N; i++ {
94		w.Write(plaintext)
95		w.Close()
96
97		w.seqNum = 1
98		w.offset = 0
99		w.closed = false
100		w.associatedData[0] = 0
101	}
102}
103
104func benchDecryptWrite(b *testing.B, s *Stream, size int64) {
105	plaintext := make([]byte, size)
106	nonce := make([]byte, s.NonceSize())
107	ow := s.DecryptWriter(DevNull, nonce, nil)
108	w := s.EncryptWriter(ow, nonce, nil)
109	b.SetBytes(2*size + s.Overhead(size))
110	b.ResetTimer()
111	for i := 0; i < b.N; i++ {
112		w.Write(plaintext)
113		w.Close()
114
115		w.seqNum, ow.seqNum = 1, 1
116		w.offset, ow.offset = 0, 0
117		w.closed, ow.closed = false, false
118		w.associatedData[0], ow.associatedData[0] = 0, 0
119	}
120}
121
122func benchEncryptReadFrom(b *testing.B, s *Stream, size int64) {
123	plaintext := &io.LimitedReader{R: DevNull, N: size}
124	w := s.EncryptWriter(DevNull, make([]byte, s.NonceSize()), nil)
125	b.SetBytes(size)
126	b.ResetTimer()
127	for i := 0; i < b.N; i++ {
128		if _, err := w.ReadFrom(plaintext); err != nil {
129			panic(err)
130		}
131		if err := w.Close(); err != nil {
132			panic(err)
133		}
134
135		w.seqNum = 1
136		w.offset = 0
137		w.closed = false
138		w.associatedData[0] = 0
139		plaintext.N = size
140	}
141}
142
143func benchDecryptReadFrom(b *testing.B, s *Stream, size int64) {
144	plaintext := &io.LimitedReader{R: DevNull, N: size}
145	nonce := make([]byte, s.NonceSize())
146	ow := s.DecryptWriter(DevNull, nonce, nil)
147	w := s.EncryptWriter(ow, nonce, nil)
148	b.SetBytes(2*size + s.Overhead(size))
149	b.ResetTimer()
150	for i := 0; i < b.N; i++ {
151		if _, err := w.ReadFrom(plaintext); err != nil {
152			panic(err)
153		}
154		if err := w.Close(); err != nil {
155			panic(err)
156		}
157
158		w.seqNum, ow.seqNum = 1, 1
159		w.offset, ow.offset = 0, 0
160		w.closed, ow.closed = false, false
161		w.associatedData[0], ow.associatedData[0] = 0, 0
162		plaintext.N = size
163	}
164}
165
166func benchEncryptRead(b *testing.B, s *Stream, size int64) {
167	nonce := make([]byte, s.NonceSize())
168	buffer := make([]byte, s.bufSize+s.cipher.Overhead())
169	plaintext := &io.LimitedReader{R: DevNull, N: size}
170
171	r := s.EncryptReader(plaintext, nonce, nil)
172	b.SetBytes(size)
173	b.ResetTimer()
174	for i := 0; i < b.N; i++ {
175		for {
176			if _, err := readFrom(r, buffer); err == io.EOF {
177				break
178			} else if err != nil {
179				panic(err)
180			}
181		}
182
183		r.seqNum = 1
184		r.offset = 0
185		r.closed = false
186		r.firstRead = true
187		r.associatedData[0] = 0
188		plaintext.N = size
189	}
190}
191
192func benchDecryptRead(b *testing.B, s *Stream, size int64) {
193	nonce := make([]byte, s.NonceSize())
194	buffer := make([]byte, s.bufSize)
195	plaintext := &io.LimitedReader{R: DevNull, N: size}
196
197	sr := s.EncryptReader(plaintext, nonce, nil)
198	r := s.DecryptReader(sr, nonce, nil)
199	b.SetBytes(2*size + s.Overhead(size))
200	b.ResetTimer()
201	for i := 0; i < b.N; i++ {
202		for {
203			if _, err := readFrom(r, buffer); err == io.EOF {
204				break
205			} else if err != nil {
206				panic(err)
207			}
208		}
209
210		r.seqNum, sr.seqNum = 1, 1
211		r.offset, sr.offset = 0, 0
212		r.closed, sr.closed = false, false
213		r.firstRead, sr.firstRead = true, true
214		r.associatedData[0], sr.associatedData[0] = 0, 0
215		plaintext.N = size
216	}
217}
218
219func benchDecryptReadAt(b *testing.B, s *Stream, offset, size int64) {
220	nonce := make([]byte, s.NonceSize())
221
222	data := make([]byte, size)
223	ciphertext := bytes.NewBuffer(nil)
224	w := s.EncryptWriter(ciphertext, nonce, nil)
225	w.Write(data)
226	w.Close()
227
228	r := s.DecryptReaderAt(bytes.NewReader(ciphertext.Bytes()), nonce, nil)
229	b.SetBytes(size - offset + s.Overhead(size-offset))
230	b.ResetTimer()
231	for i := 0; i < b.N; i++ {
232		if _, err := r.ReadAt(data, offset); err != nil {
233			if err != io.EOF {
234				panic(err)
235			}
236		}
237	}
238}
239
240func benchEncryptWriteTo(b *testing.B, s *Stream, size int64) {
241	nonce := make([]byte, s.NonceSize())
242	plaintext := &io.LimitedReader{R: DevNull, N: size}
243
244	r := s.EncryptReader(plaintext, nonce, nil)
245	b.SetBytes(size)
246	b.ResetTimer()
247	for i := 0; i < b.N; i++ {
248		if _, err := r.WriteTo(DevNull); err != nil {
249			panic(err)
250		}
251
252		r.seqNum = 1
253		r.offset = 0
254		r.closed = false
255		r.firstRead = true
256		r.associatedData[0] = 0
257		plaintext.N = size
258	}
259}
260
261func benchDecryptWriteTo(b *testing.B, s *Stream, size int64) {
262	nonce := make([]byte, s.NonceSize())
263	plaintext := &io.LimitedReader{R: DevNull, N: size}
264
265	sr := s.EncryptReader(plaintext, nonce, nil)
266	r := s.DecryptReader(sr, nonce, nil)
267	b.SetBytes(size)
268	b.ResetTimer()
269	for i := 0; i < b.N; i++ {
270		if _, err := r.WriteTo(DevNull); err != nil {
271			panic(err)
272		}
273
274		r.seqNum, sr.seqNum = 1, 1
275		r.offset, sr.offset = 0, 0
276		r.closed, sr.closed = false, false
277		r.firstRead, sr.firstRead = true, true
278		r.associatedData[0], sr.associatedData[0] = 0, 0
279		plaintext.N = size
280	}
281}
282