@@ -19,10 +19,13 @@ package rng
1919
2020import (
2121 "bytes"
22+ "encoding/binary"
2223 "io"
2324 "math/rand"
2425 "strconv"
2526 "testing"
27+
28+ "github.com/klauspost/cpuid/v2"
2629)
2730
2831func TestSubkeysInitialized (t * testing.T ) {
@@ -204,36 +207,173 @@ func TestReaderSeeker(t *testing.T) {
204207 }
205208}
206209
210+ func forEachXorImpl (t * testing.T , fn func (t * testing.T )) {
211+ t .Helper ()
212+ if ! cpuid .CPU .Has (cpuid .SSE2 ) {
213+ fn (t )
214+ return
215+ }
216+ avx2 := cpuid .CPU .Has (cpuid .AVX2 )
217+ if avx2 {
218+ t .Run ("AVX2" , func (t * testing.T ) {
219+ fn (t )
220+ })
221+ t .Run ("SSE2" , func (t * testing.T ) {
222+ cpuid .CPU .Disable (cpuid .AVX2 )
223+ defer cpuid .CPU .Enable (cpuid .AVX2 )
224+ fn (t )
225+ })
226+ return
227+
228+ }
229+ fn (t )
230+ }
231+
207232func TestXor (t * testing.T ) {
208- // Validate asm, if any, otherwise validate ourselves.
209- rng := rand .New (rand .NewSource (0 ))
210- for _ , size := range []int {1000 , 1024 , 16384 , 1 << 20 } {
211- bufIn := make ([]byte , size )
212- _ , err := io .ReadFull (rng , bufIn )
213- if err != nil {
214- t .Fatal (err )
233+ forEachXorImpl (t , func (t * testing.T ) {
234+ rng := rand .New (rand .NewSource (0 ))
235+ for _ , size := range []int {1000 , 1024 , 16384 , 1 << 20 } {
236+ bufIn := make ([]byte , size )
237+ _ , err := io .ReadFull (rng , bufIn )
238+ if err != nil {
239+ t .Fatal (err )
240+ }
241+ bufOut := make ([]byte , size )
242+ bufOut2 := make ([]byte , size )
243+ var keys [4 ]uint64
244+ for i := range keys {
245+ keys [i ] = rng .Uint64 ()
246+ }
247+ for i := 0 ; i < 1000 ; i ++ {
248+ bSize := (rand .Intn (size ) / 32 ) * 32
249+ bufOut := bufOut [:bSize ]
250+ for i := 0 ; i < len (bufOut ); i ++ {
251+ bufOut [i ] = 0
252+ }
253+ bufOut2 := bufOut2 [:bSize ]
254+ for i := 0 ; i < len (bufOut2 ); i ++ {
255+ bufOut2 [i ] = 0
256+ }
257+ xorSlice (bufIn , bufOut , & keys )
258+ xor32Go (bufIn , bufOut2 , & keys )
259+ if ! bytes .Equal (bufOut , bufOut2 ) {
260+ t .Fatalf ("\n expected %x\n got %x" , bufOut , bufOut2 )
261+ }
262+ }
215263 }
216- bufOut := make ([]byte , size )
217- bufOut2 := make ([]byte , size )
264+ })
265+ }
266+
267+ func TestXorZeroKey (t * testing.T ) {
268+ forEachXorImpl (t , func (t * testing.T ) {
269+ var keys [4 ]uint64
270+ for _ , size := range []int {0 , 32 , 64 , 96 , 128 , 1024 } {
271+ in := make ([]byte , size )
272+ for i := range in {
273+ in [i ] = byte (i )
274+ }
275+ out := make ([]byte , size )
276+ xorSlice (in , out , & keys )
277+ if ! bytes .Equal (in , out ) {
278+ t .Fatalf ("size %d: zero-key xor should copy input\n expected %x\n got %x" , size , in , out )
279+ }
280+ out2 := make ([]byte , size )
281+ xor32Go (in , out2 , & keys )
282+ if ! bytes .Equal (in , out2 ) {
283+ t .Fatalf ("size %d: zero-key xor32Go should copy input" , size )
284+ }
285+ }
286+ })
287+ }
288+
289+ func TestXorDoubleApply (t * testing.T ) {
290+ forEachXorImpl (t , func (t * testing.T ) {
291+ rng := rand .New (rand .NewSource (42 ))
218292 var keys [4 ]uint64
219293 for i := range keys {
220294 keys [i ] = rng .Uint64 ()
221295 }
222- for i := 0 ; i < 1000 ; i ++ {
223- bSize := (rand .Intn (size ) / 32 ) * 32
224- bufOut := bufOut [:bSize ]
225- for i := 0 ; i < len (bufOut ); i ++ {
226- bufOut [i ] = 0
227- }
228- bufOut2 := bufOut2 [:bSize ]
229- for i := 0 ; i < len (bufOut2 ); i ++ {
230- bufOut2 [i ] = 0
296+ for _ , size := range []int {32 , 64 , 96 , 128 , 256 , 1024 , 4096 } {
297+ in := make ([]byte , size )
298+ _ , _ = io .ReadFull (rng , in )
299+ orig := make ([]byte , size )
300+ copy (orig , in )
301+
302+ tmp := make ([]byte , size )
303+ out := make ([]byte , size )
304+ xorSlice (in , tmp , & keys )
305+ xorSlice (tmp , out , & keys )
306+ if ! bytes .Equal (orig , out ) {
307+ t .Fatalf ("size %d: double xor should return original\n expected %x\n got %x" , size , orig [:32 ], out [:32 ])
231308 }
232- xorSlice (bufIn , bufOut , & keys )
233- xor32Go (bufIn , bufOut2 , & keys )
234- if ! bytes .Equal (bufOut , bufOut2 ) {
235- t .Fatalf ("\n expected %x\n got %x" , bufOut , bufOut2 )
309+ }
310+ })
311+ }
312+
313+ func TestXorAllSizes (t * testing.T ) {
314+ forEachXorImpl (t , func (t * testing.T ) {
315+ rng := rand .New (rand .NewSource (99 ))
316+ var keys [4 ]uint64
317+ for i := range keys {
318+ keys [i ] = rng .Uint64 ()
319+ }
320+ in := make ([]byte , 8192 )
321+ _ , _ = io .ReadFull (rng , in )
322+
323+ for size := 0 ; size <= len (in ); size += 32 {
324+ outAsm := make ([]byte , size )
325+ outGo := make ([]byte , size )
326+ xorSlice (in [:size ], outAsm , & keys )
327+ xor32Go (in [:size ], outGo , & keys )
328+ if ! bytes .Equal (outAsm , outGo ) {
329+ t .Fatalf ("size %d: asm and Go disagree\n asm %x\n go %x" , size , outAsm [:min (64 , size )], outGo [:min (64 , size )])
236330 }
237331 }
238- }
332+ })
333+ }
334+
335+ func TestXorDistinctKeys (t * testing.T ) {
336+ forEachXorImpl (t , func (t * testing.T ) {
337+ in := make ([]byte , 256 )
338+ for i := range in {
339+ in [i ] = byte (i )
340+ }
341+ keys1 := [4 ]uint64 {1 , 2 , 3 , 4 }
342+ keys2 := [4 ]uint64 {5 , 6 , 7 , 8 }
343+ out1 := make ([]byte , 256 )
344+ out2 := make ([]byte , 256 )
345+ xorSlice (in , out1 , & keys1 )
346+ xorSlice (in , out2 , & keys2 )
347+ if bytes .Equal (out1 , out2 ) {
348+ t .Fatal ("different keys should produce different output" )
349+ }
350+ })
351+ }
352+
353+ func TestXorKnownValues (t * testing.T ) {
354+ forEachXorImpl (t , func (t * testing.T ) {
355+ in := make ([]byte , 32 )
356+ for i := range in {
357+ in [i ] = byte (i )
358+ }
359+ keys := [4 ]uint64 {0x0807060504030201 , 0x100f0e0d0c0b0a09 , 0x1817161514131211 , 0x201f1e1d1c1b1a19 }
360+ out := make ([]byte , 32 )
361+ xor32Go (in , out , & keys )
362+
363+ expected := make ([]byte , 32 )
364+ for i := 0 ; i < 32 ; i ++ {
365+ keyBytes := make ([]byte , 8 )
366+ binary .LittleEndian .PutUint64 (keyBytes , keys [i / 8 ])
367+ expected [i ] = in [i ] ^ keyBytes [i % 8 ]
368+ }
369+ if ! bytes .Equal (out , expected ) {
370+ t .Fatalf ("known values mismatch\n expected %x\n got %x" , expected , out )
371+ }
372+
373+ outAsm := make ([]byte , 32 )
374+ xorSlice (in , outAsm , & keys )
375+ if ! bytes .Equal (outAsm , expected ) {
376+ t .Fatalf ("xorSlice known values mismatch\n expected %x\n got %x" , expected , outAsm )
377+ }
378+ })
239379}
0 commit comments