@@ -19,6 +19,7 @@ package rng
1919
2020import (
2121 "bytes"
22+ "encoding/binary"
2223 "io"
2324 "math/rand"
2425 "strconv"
@@ -188,3 +189,114 @@ func TestXor(t *testing.T) {
188189 }
189190 }
190191}
192+
193+ func TestXorZeroKey (t * testing.T ) {
194+ var keys [4 ]uint64
195+ for _ , size := range []int {0 , 32 , 64 , 96 , 128 , 1024 } {
196+ in := make ([]byte , size )
197+ for i := range in {
198+ in [i ] = byte (i )
199+ }
200+ out := make ([]byte , size )
201+ xorSlice (in , out , & keys )
202+ if ! bytes .Equal (in , out ) {
203+ t .Fatalf ("size %d: zero-key xor should copy input\n expected %x\n got %x" , size , in , out )
204+ }
205+ out2 := make ([]byte , size )
206+ xor32Go (in , out2 , & keys )
207+ if ! bytes .Equal (in , out2 ) {
208+ t .Fatalf ("size %d: zero-key xor32Go should copy input" , size )
209+ }
210+ }
211+ }
212+
213+ func TestXorDoubleApply (t * testing.T ) {
214+ rng := rand .New (rand .NewSource (42 ))
215+ var keys [4 ]uint64
216+ for i := range keys {
217+ keys [i ] = rng .Uint64 ()
218+ }
219+ for _ , size := range []int {32 , 64 , 96 , 128 , 256 , 1024 , 4096 } {
220+ in := make ([]byte , size )
221+ _ , _ = io .ReadFull (rng , in )
222+ orig := make ([]byte , size )
223+ copy (orig , in )
224+
225+ tmp := make ([]byte , size )
226+ out := make ([]byte , size )
227+ xorSlice (in , tmp , & keys )
228+ xorSlice (tmp , out , & keys )
229+ if ! bytes .Equal (orig , out ) {
230+ t .Fatalf ("size %d: double xor should return original\n expected %x\n got %x" , size , orig [:32 ], out [:32 ])
231+ }
232+ }
233+ }
234+
235+ func TestXorAllSizes (t * testing.T ) {
236+ rng := rand .New (rand .NewSource (99 ))
237+ var keys [4 ]uint64
238+ for i := range keys {
239+ keys [i ] = rng .Uint64 ()
240+ }
241+ in := make ([]byte , 8192 )
242+ _ , _ = io .ReadFull (rng , in )
243+
244+ // Every multiple of 32 up to 8192 exercises different loop paths:
245+ // 0 (empty), 32 (single block), 64 (two blocks / 64-byte loop only),
246+ // 96 (64-byte loop + 32-byte tail), etc.
247+ for size := 0 ; size <= len (in ); size += 32 {
248+ outAsm := make ([]byte , size )
249+ outGo := make ([]byte , size )
250+ xorSlice (in [:size ], outAsm , & keys )
251+ xor32Go (in [:size ], outGo , & keys )
252+ if ! bytes .Equal (outAsm , outGo ) {
253+ t .Fatalf ("size %d: asm and Go disagree\n asm %x\n go %x" , size , outAsm [:min (64 , size )], outGo [:min (64 , size )])
254+ }
255+ }
256+ }
257+
258+ func TestXorDistinctKeys (t * testing.T ) {
259+ in := make ([]byte , 256 )
260+ for i := range in {
261+ in [i ] = byte (i )
262+ }
263+ keys1 := [4 ]uint64 {1 , 2 , 3 , 4 }
264+ keys2 := [4 ]uint64 {5 , 6 , 7 , 8 }
265+ out1 := make ([]byte , 256 )
266+ out2 := make ([]byte , 256 )
267+ xorSlice (in , out1 , & keys1 )
268+ xorSlice (in , out2 , & keys2 )
269+ if bytes .Equal (out1 , out2 ) {
270+ t .Fatal ("different keys should produce different output" )
271+ }
272+ }
273+
274+ func TestXorKnownValues (t * testing.T ) {
275+ in := make ([]byte , 32 )
276+ for i := range in {
277+ in [i ] = byte (i )
278+ }
279+ keys := [4 ]uint64 {0x0807060504030201 , 0x100f0e0d0c0b0a09 , 0x1817161514131211 , 0x201f1e1d1c1b1a19 }
280+ out := make ([]byte , 32 )
281+ xor32Go (in , out , & keys )
282+
283+ // Each 8-byte block: out[i..i+7] = in[i..i+7] XOR keys[i/8]
284+ // Block 0: in[0..7] = 00 01 02 03 04 05 06 07, key = 01 02 03 04 05 06 07 08 (LE)
285+ // XOR => 01 03 01 07 01 03 01 0f
286+ expected := make ([]byte , 32 )
287+ for i := 0 ; i < 32 ; i ++ {
288+ keyBytes := make ([]byte , 8 )
289+ binary .LittleEndian .PutUint64 (keyBytes , keys [i / 8 ])
290+ expected [i ] = in [i ] ^ keyBytes [i % 8 ]
291+ }
292+ if ! bytes .Equal (out , expected ) {
293+ t .Fatalf ("known values mismatch\n expected %x\n got %x" , expected , out )
294+ }
295+
296+ // Now verify xorSlice matches
297+ outAsm := make ([]byte , 32 )
298+ xorSlice (in , outAsm , & keys )
299+ if ! bytes .Equal (outAsm , expected ) {
300+ t .Fatalf ("xorSlice known values mismatch\n expected %x\n got %x" , expected , outAsm )
301+ }
302+ }
0 commit comments