poly1305_test.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. // Copyright 2012 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package poly1305
  5. import (
  6. "crypto/rand"
  7. "encoding/binary"
  8. "encoding/hex"
  9. "flag"
  10. "testing"
  11. "unsafe"
  12. )
  13. var stressFlag = flag.Bool("stress", false, "run slow stress tests")
  14. type test struct {
  15. in string
  16. key string
  17. tag string
  18. state string
  19. }
  20. func (t *test) Input() []byte {
  21. in, err := hex.DecodeString(t.in)
  22. if err != nil {
  23. panic(err)
  24. }
  25. return in
  26. }
  27. func (t *test) Key() [32]byte {
  28. buf, err := hex.DecodeString(t.key)
  29. if err != nil {
  30. panic(err)
  31. }
  32. var key [32]byte
  33. copy(key[:], buf[:32])
  34. return key
  35. }
  36. func (t *test) Tag() [16]byte {
  37. buf, err := hex.DecodeString(t.tag)
  38. if err != nil {
  39. panic(err)
  40. }
  41. var tag [16]byte
  42. copy(tag[:], buf[:16])
  43. return tag
  44. }
  45. func (t *test) InitialState() [3]uint64 {
  46. // state is hex encoded in big-endian byte order
  47. if t.state == "" {
  48. return [3]uint64{0, 0, 0}
  49. }
  50. buf, err := hex.DecodeString(t.state)
  51. if err != nil {
  52. panic(err)
  53. }
  54. if len(buf) != 3*8 {
  55. panic("incorrect state length")
  56. }
  57. return [3]uint64{
  58. binary.BigEndian.Uint64(buf[16:24]),
  59. binary.BigEndian.Uint64(buf[8:16]),
  60. binary.BigEndian.Uint64(buf[0:8]),
  61. }
  62. }
  63. func testSum(t *testing.T, unaligned bool, sumImpl func(tag *[TagSize]byte, msg []byte, key *[32]byte)) {
  64. var tag [16]byte
  65. for i, v := range testData {
  66. // cannot set initial state before calling sum, so skip those tests
  67. if v.InitialState() != [3]uint64{0, 0, 0} {
  68. continue
  69. }
  70. in := v.Input()
  71. if unaligned {
  72. in = unalignBytes(in)
  73. }
  74. key := v.Key()
  75. sumImpl(&tag, in, &key)
  76. if tag != v.Tag() {
  77. t.Errorf("%d: expected %x, got %x", i, v.Tag(), tag[:])
  78. }
  79. if !Verify(&tag, in, &key) {
  80. t.Errorf("%d: tag didn't verify", i)
  81. }
  82. // If the key is zero, the tag will always be zero, independent of the input.
  83. if len(in) > 0 && key != [32]byte{} {
  84. in[0] ^= 0xff
  85. if Verify(&tag, in, &key) {
  86. t.Errorf("%d: tag verified after altering the input", i)
  87. }
  88. in[0] ^= 0xff
  89. }
  90. // If the input is empty, the tag only depends on the second half of the key.
  91. if len(in) > 0 {
  92. key[0] ^= 0xff
  93. if Verify(&tag, in, &key) {
  94. t.Errorf("%d: tag verified after altering the key", i)
  95. }
  96. key[0] ^= 0xff
  97. }
  98. tag[0] ^= 0xff
  99. if Verify(&tag, in, &key) {
  100. t.Errorf("%d: tag verified after altering the tag", i)
  101. }
  102. tag[0] ^= 0xff
  103. }
  104. }
  105. func TestBurnin(t *testing.T) {
  106. // This test can be used to sanity-check significant changes. It can
  107. // take about many minutes to run, even on fast machines. It's disabled
  108. // by default.
  109. if !*stressFlag {
  110. t.Skip("skipping without -stress")
  111. }
  112. var key [32]byte
  113. var input [25]byte
  114. var output [16]byte
  115. for i := range key {
  116. key[i] = 1
  117. }
  118. for i := range input {
  119. input[i] = 2
  120. }
  121. for i := uint64(0); i < 1e10; i++ {
  122. Sum(&output, input[:], &key)
  123. copy(key[0:], output[:])
  124. copy(key[16:], output[:])
  125. copy(input[:], output[:])
  126. copy(input[16:], output[:])
  127. }
  128. const expected = "5e3b866aea0b636d240c83c428f84bfa"
  129. if got := hex.EncodeToString(output[:]); got != expected {
  130. t.Errorf("expected %s, got %s", expected, got)
  131. }
  132. }
  133. func TestSum(t *testing.T) { testSum(t, false, Sum) }
  134. func TestSumUnaligned(t *testing.T) { testSum(t, true, Sum) }
  135. func TestSumGeneric(t *testing.T) { testSum(t, false, sumGeneric) }
  136. func TestSumGenericUnaligned(t *testing.T) { testSum(t, true, sumGeneric) }
  137. func TestWriteGeneric(t *testing.T) { testWriteGeneric(t, false) }
  138. func TestWriteGenericUnaligned(t *testing.T) { testWriteGeneric(t, true) }
  139. func TestWrite(t *testing.T) { testWrite(t, false) }
  140. func TestWriteUnaligned(t *testing.T) { testWrite(t, true) }
  141. func testWriteGeneric(t *testing.T, unaligned bool) {
  142. for i, v := range testData {
  143. key := v.Key()
  144. input := v.Input()
  145. var out [16]byte
  146. if unaligned {
  147. input = unalignBytes(input)
  148. }
  149. h := newMACGeneric(&key)
  150. if s := v.InitialState(); s != [3]uint64{0, 0, 0} {
  151. h.macState.h = s
  152. }
  153. n, err := h.Write(input[:len(input)/3])
  154. if err != nil || n != len(input[:len(input)/3]) {
  155. t.Errorf("#%d: unexpected Write results: n = %d, err = %v", i, n, err)
  156. }
  157. n, err = h.Write(input[len(input)/3:])
  158. if err != nil || n != len(input[len(input)/3:]) {
  159. t.Errorf("#%d: unexpected Write results: n = %d, err = %v", i, n, err)
  160. }
  161. h.Sum(&out)
  162. if tag := v.Tag(); out != tag {
  163. t.Errorf("%d: expected %x, got %x", i, tag[:], out[:])
  164. }
  165. }
  166. }
  167. func testWrite(t *testing.T, unaligned bool) {
  168. for i, v := range testData {
  169. key := v.Key()
  170. input := v.Input()
  171. var out [16]byte
  172. if unaligned {
  173. input = unalignBytes(input)
  174. }
  175. h := New(&key)
  176. if s := v.InitialState(); s != [3]uint64{0, 0, 0} {
  177. h.macState.h = s
  178. }
  179. n, err := h.Write(input[:len(input)/3])
  180. if err != nil || n != len(input[:len(input)/3]) {
  181. t.Errorf("#%d: unexpected Write results: n = %d, err = %v", i, n, err)
  182. }
  183. n, err = h.Write(input[len(input)/3:])
  184. if err != nil || n != len(input[len(input)/3:]) {
  185. t.Errorf("#%d: unexpected Write results: n = %d, err = %v", i, n, err)
  186. }
  187. h.Sum(out[:0])
  188. tag := v.Tag()
  189. if out != tag {
  190. t.Errorf("%d: expected %x, got %x", i, tag[:], out[:])
  191. }
  192. if !h.Verify(tag[:]) {
  193. t.Errorf("%d: Verify failed", i)
  194. }
  195. tag[0] ^= 0xff
  196. if h.Verify(tag[:]) {
  197. t.Errorf("%d: Verify succeeded after modifying the tag", i)
  198. }
  199. }
  200. }
  201. func benchmarkSum(b *testing.B, size int, unaligned bool) {
  202. var out [16]byte
  203. var key [32]byte
  204. in := make([]byte, size)
  205. if unaligned {
  206. in = unalignBytes(in)
  207. }
  208. rand.Read(in)
  209. b.SetBytes(int64(len(in)))
  210. b.ResetTimer()
  211. for i := 0; i < b.N; i++ {
  212. Sum(&out, in, &key)
  213. }
  214. }
  215. func benchmarkWrite(b *testing.B, size int, unaligned bool) {
  216. var key [32]byte
  217. h := New(&key)
  218. in := make([]byte, size)
  219. if unaligned {
  220. in = unalignBytes(in)
  221. }
  222. rand.Read(in)
  223. b.SetBytes(int64(len(in)))
  224. b.ResetTimer()
  225. for i := 0; i < b.N; i++ {
  226. h.Write(in)
  227. }
  228. }
  229. func Benchmark64(b *testing.B) { benchmarkSum(b, 64, false) }
  230. func Benchmark1K(b *testing.B) { benchmarkSum(b, 1024, false) }
  231. func Benchmark2M(b *testing.B) { benchmarkSum(b, 2*1024*1024, false) }
  232. func Benchmark64Unaligned(b *testing.B) { benchmarkSum(b, 64, true) }
  233. func Benchmark1KUnaligned(b *testing.B) { benchmarkSum(b, 1024, true) }
  234. func Benchmark2MUnaligned(b *testing.B) { benchmarkSum(b, 2*1024*1024, true) }
  235. func BenchmarkWrite64(b *testing.B) { benchmarkWrite(b, 64, false) }
  236. func BenchmarkWrite1K(b *testing.B) { benchmarkWrite(b, 1024, false) }
  237. func BenchmarkWrite2M(b *testing.B) { benchmarkWrite(b, 2*1024*1024, false) }
  238. func BenchmarkWrite64Unaligned(b *testing.B) { benchmarkWrite(b, 64, true) }
  239. func BenchmarkWrite1KUnaligned(b *testing.B) { benchmarkWrite(b, 1024, true) }
  240. func BenchmarkWrite2MUnaligned(b *testing.B) { benchmarkWrite(b, 2*1024*1024, true) }
  241. func unalignBytes(in []byte) []byte {
  242. out := make([]byte, len(in)+1)
  243. if uintptr(unsafe.Pointer(&out[0]))&(unsafe.Alignof(uint32(0))-1) == 0 {
  244. out = out[1:]
  245. } else {
  246. out = out[:len(in)]
  247. }
  248. copy(out, in)
  249. return out
  250. }