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
5package salsa20
6
7import (
8	"bytes"
9	"encoding/hex"
10	"testing"
11)
12
13func fromHex(s string) []byte {
14	ret, err := hex.DecodeString(s)
15	if err != nil {
16		panic(err)
17	}
18	return ret
19}
20
21// testVectors was taken from set 6 of the ECRYPT test vectors:
22// http://www.ecrypt.eu.org/stream/svn/viewcvs.cgi/ecrypt/trunk/submissions/salsa20/full/verified.test-vectors?logsort=rev&rev=210&view=markup
23var testVectors = []struct {
24	key      []byte
25	iv       []byte
26	numBytes int
27	xor      []byte
28}{
29	{
30		fromHex("0053A6F94C9FF24598EB3E91E4378ADD3083D6297CCF2275C81B6EC11467BA0D"),
31		fromHex("0D74DB42A91077DE"),
32		131072,
33		fromHex("C349B6A51A3EC9B712EAED3F90D8BCEE69B7628645F251A996F55260C62EF31FD6C6B0AEA94E136C9D984AD2DF3578F78E457527B03A0450580DD874F63B1AB9"),
34	},
35	{
36		fromHex("0558ABFE51A4F74A9DF04396E93C8FE23588DB2E81D4277ACD2073C6196CBF12"),
37		fromHex("167DE44BB21980E7"),
38		131072,
39		fromHex("C3EAAF32836BACE32D04E1124231EF47E101367D6305413A0EEB07C60698A2876E4D031870A739D6FFDDD208597AFF0A47AC17EDB0167DD67EBA84F1883D4DFD"),
40	},
41	{
42		fromHex("0A5DB00356A9FC4FA2F5489BEE4194E73A8DE03386D92C7FD22578CB1E71C417"),
43		fromHex("1F86ED54BB2289F0"),
44		131072,
45		fromHex("3CD23C3DC90201ACC0CF49B440B6C417F0DC8D8410A716D5314C059E14B1A8D9A9FB8EA3D9C8DAE12B21402F674AA95C67B1FC514E994C9D3F3A6E41DFF5BBA6"),
46	},
47	{
48		fromHex("0F62B5085BAE0154A7FA4DA0F34699EC3F92E5388BDE3184D72A7DD02376C91C"),
49		fromHex("288FF65DC42B92F9"),
50		131072,
51		fromHex("E00EBCCD70D69152725F9987982178A2E2E139C7BCBE04CA8A0E99E318D9AB76F988C8549F75ADD790BA4F81C176DA653C1A043F11A958E169B6D2319F4EEC1A"),
52	},
53}
54
55func TestSalsa20(t *testing.T) {
56	var inBuf, outBuf []byte
57	var key [32]byte
58
59	for i, test := range testVectors {
60		if test.numBytes%64 != 0 {
61			t.Errorf("#%d: numBytes is not a multiple of 64", i)
62			continue
63		}
64
65		if test.numBytes > len(inBuf) {
66			inBuf = make([]byte, test.numBytes)
67			outBuf = make([]byte, test.numBytes)
68		}
69		in := inBuf[:test.numBytes]
70		out := outBuf[:test.numBytes]
71		copy(key[:], test.key)
72		XORKeyStream(out, in, test.iv, &key)
73
74		var xor [64]byte
75		for len(out) > 0 {
76			for i := 0; i < 64; i++ {
77				xor[i] ^= out[i]
78			}
79			out = out[64:]
80		}
81
82		if !bytes.Equal(xor[:], test.xor) {
83			t.Errorf("#%d: bad result", i)
84		}
85	}
86}
87
88var xSalsa20TestData = []struct {
89	in, nonce, key, out []byte
90}{
91	{
92		[]byte("Hello world!"),
93		[]byte("24-byte nonce for xsalsa"),
94		[]byte("this is 32-byte key for xsalsa20"),
95		[]byte{0x00, 0x2d, 0x45, 0x13, 0x84, 0x3f, 0xc2, 0x40, 0xc4, 0x01, 0xe5, 0x41},
96	},
97	{
98		make([]byte, 64),
99		[]byte("24-byte nonce for xsalsa"),
100		[]byte("this is 32-byte key for xsalsa20"),
101		[]byte{0x48, 0x48, 0x29, 0x7f, 0xeb, 0x1f, 0xb5, 0x2f, 0xb6,
102			0x6d, 0x81, 0x60, 0x9b, 0xd5, 0x47, 0xfa, 0xbc, 0xbe, 0x70,
103			0x26, 0xed, 0xc8, 0xb5, 0xe5, 0xe4, 0x49, 0xd0, 0x88, 0xbf,
104			0xa6, 0x9c, 0x08, 0x8f, 0x5d, 0x8d, 0xa1, 0xd7, 0x91, 0x26,
105			0x7c, 0x2c, 0x19, 0x5a, 0x7f, 0x8c, 0xae, 0x9c, 0x4b, 0x40,
106			0x50, 0xd0, 0x8c, 0xe6, 0xd3, 0xa1, 0x51, 0xec, 0x26, 0x5f,
107			0x3a, 0x58, 0xe4, 0x76, 0x48},
108	},
109}
110
111func TestXSalsa20(t *testing.T) {
112	var key [32]byte
113
114	for i, test := range xSalsa20TestData {
115		out := make([]byte, len(test.in))
116		copy(key[:], test.key)
117		XORKeyStream(out, test.in, test.nonce, &key)
118		if !bytes.Equal(out, test.out) {
119			t.Errorf("%d: expected %x, got %x", i, test.out, out)
120		}
121	}
122}
123
124var (
125	keyArray [32]byte
126	key      = &keyArray
127	nonce    [8]byte
128	msg      = make([]byte, 1<<10)
129)
130
131func BenchmarkXOR1K(b *testing.B) {
132	b.StopTimer()
133	out := make([]byte, 1024)
134	b.StartTimer()
135	for i := 0; i < b.N; i++ {
136		XORKeyStream(out, msg[:1024], nonce[:], key)
137	}
138	b.SetBytes(1024)
139}
140