1
2
3
4
5 package subtle_test
6
7 import (
8 "bytes"
9 "crypto/internal/cryptotest"
10 "crypto/rand"
11 . "crypto/subtle"
12 "fmt"
13 "testing"
14 )
15
16 func TestXORBytes(t *testing.T) {
17 cryptotest.TestAllImplementations(t, "subtle", testXORBytes)
18 }
19
20 func testXORBytes(t *testing.T) {
21 for n := 1; n <= 1024; n++ {
22 if n > 16 && testing.Short() {
23 n += n >> 3
24 }
25 for alignP := 0; alignP < 8; alignP++ {
26 for alignQ := 0; alignQ < 8; alignQ++ {
27 for alignD := 0; alignD < 8; alignD++ {
28 p := make([]byte, alignP+n, alignP+n+100)[alignP:]
29 q := make([]byte, alignQ+n, alignQ+n+100)[alignQ:]
30 if n&1 != 0 {
31 p = p[:n]
32 } else {
33 q = q[:n]
34 }
35 rand.Read(p)
36 rand.Read(q)
37
38 d := make([]byte, alignD+n+100)
39 rand.Read(d)
40
41 want := bytes.Clone(d)
42 for i := range n {
43 want[alignD+i] = p[i] ^ q[i]
44 }
45
46 if nn := XORBytes(d[alignD:], p, q); !bytes.Equal(d, want) {
47 t.Errorf("n=%d alignP=%d alignQ=%d alignD=%d:\n\tp = %x\n\tq = %x\n\td = %x\n\twant %x\n", n, alignP, alignQ, alignD, p, q, d, want)
48 } else if nn != n {
49 t.Errorf("n=%d alignP=%d alignQ=%d alignD=%d: got %d, want %d", n, alignP, alignQ, alignD, nn, n)
50 }
51 p1 := bytes.Clone(p)
52 if nn := XORBytes(p, p, q); !bytes.Equal(p, want[alignD:alignD+n]) {
53 t.Errorf("n=%d alignP=%d alignQ=%d alignD=%d:\n\tp = %x\n\tq = %x\n\td = %x\n\twant %x\n", n, alignP, alignQ, alignD, p, q, d, want)
54 } else if nn != n {
55 t.Errorf("n=%d alignP=%d alignQ=%d alignD=%d: got %d, want %d", n, alignP, alignQ, alignD, nn, n)
56 }
57 if nn := XORBytes(q, p1, q); !bytes.Equal(q, want[alignD:alignD+n]) {
58 t.Errorf("n=%d alignP=%d alignQ=%d alignD=%d:\n\tp = %x\n\tq = %x\n\td = %x\n\twant %x\n", n, alignP, alignQ, alignD, p, q, d, want)
59 } else if nn != n {
60 t.Errorf("n=%d alignP=%d alignQ=%d alignD=%d: got %d, want %d", n, alignP, alignQ, alignD, nn, n)
61 }
62
63 if nn := XORBytes(p, p, p); !bytes.Equal(p, make([]byte, n)) {
64 t.Errorf("n=%d alignP=%d alignQ=%d alignD=%d: got %x, want %x", n, alignP, alignQ, alignD, p, make([]byte, n))
65 } else if nn != n {
66 t.Errorf("n=%d alignP=%d alignQ=%d alignD=%d: got %d, want %d", n, alignP, alignQ, alignD, nn, n)
67 }
68 if nn := XORBytes(p1, q, q); !bytes.Equal(p1, make([]byte, n)) {
69 t.Errorf("n=%d alignP=%d alignQ=%d alignD=%d: got %x, want %x", n, alignP, alignQ, alignD, p1, make([]byte, n))
70 } else if nn != n {
71 t.Errorf("n=%d alignP=%d alignQ=%d alignD=%d: got %d, want %d", n, alignP, alignQ, alignD, nn, n)
72 }
73 }
74 }
75 }
76 }
77 }
78
79 func TestXorBytesPanic(t *testing.T) {
80 mustPanic(t, "subtle.XORBytes: dst too short", func() {
81 XORBytes(nil, make([]byte, 1), make([]byte, 1))
82 })
83 mustPanic(t, "subtle.XORBytes: dst too short", func() {
84 XORBytes(make([]byte, 1), make([]byte, 2), make([]byte, 3))
85 })
86 mustPanic(t, "subtle.XORBytes: invalid overlap", func() {
87 x := make([]byte, 3)
88 XORBytes(x, x[1:], make([]byte, 2))
89 })
90 mustPanic(t, "subtle.XORBytes: invalid overlap", func() {
91 x := make([]byte, 3)
92 XORBytes(x, make([]byte, 2), x[1:])
93 })
94 }
95
96 func TestXORBytesBoundary(t *testing.T) {
97 cryptotest.TestAllImplementations(t, "subtle", testXORBytesBoundary)
98 }
99
100 func testXORBytesBoundary(t *testing.T) {
101 safe := make([]byte, 1000)
102 start, end := cryptotest.BoundarySlices(t, 1000)
103 for i := 1; i <= 1000; i++ {
104 start := start[:i]
105 end := end[len(end)-i:]
106 XORBytes(end, safe, safe[:i])
107 XORBytes(start, safe, safe[:i])
108 XORBytes(safe, start, safe)
109 XORBytes(safe, end, safe)
110 XORBytes(safe, safe, start)
111 XORBytes(safe, safe, end)
112 }
113 }
114
115 func BenchmarkXORBytes(b *testing.B) {
116 dst := make([]byte, 1<<15)
117 data0 := make([]byte, 1<<15)
118 data1 := make([]byte, 1<<15)
119 sizes := []int64{1 << 3, 1 << 7, 1 << 11, 1 << 13, 1 << 15}
120 for _, size := range sizes {
121 b.Run(fmt.Sprintf("%dBytes", size), func(b *testing.B) {
122 s0 := data0[:size]
123 s1 := data1[:size]
124 b.SetBytes(int64(size))
125 for i := 0; i < b.N; i++ {
126 XORBytes(dst, s0, s1)
127 }
128 })
129 }
130 }
131
132 func BenchmarkXORBytesAlignment(b *testing.B) {
133 dst := make([]byte, 8+1<<11)
134 data0 := make([]byte, 8+1<<11)
135 data1 := make([]byte, 8+1<<11)
136 sizes := []int64{1 << 3, 1 << 7, 1 << 11}
137 for _, size := range sizes {
138 for offset := int64(0); offset < 8; offset++ {
139 b.Run(fmt.Sprintf("%dBytes%dOffset", size, offset), func(b *testing.B) {
140 d := dst[offset : offset+size]
141 s0 := data0[offset : offset+size]
142 s1 := data1[offset : offset+size]
143 b.SetBytes(int64(size))
144 for i := 0; i < b.N; i++ {
145 XORBytes(d, s0, s1)
146 }
147 })
148 }
149 }
150 }
151
152 func mustPanic(t *testing.T, expected string, f func()) {
153 t.Helper()
154 defer func() {
155 t.Helper()
156 switch msg := recover().(type) {
157 case nil:
158 t.Errorf("expected panic(%q), but did not panic", expected)
159 case string:
160 if msg != expected {
161 t.Errorf("expected panic(%q), but got panic(%q)", expected, msg)
162 }
163 default:
164 t.Errorf("expected panic(%q), but got panic(%T%v)", expected, msg, msg)
165 }
166 }()
167 f()
168 }
169
View as plain text