]> Cypherpunks.ru repositories - gogost.git/blob - src/cypherpunks.ru/gogost/gost34112012/hash.go
1.1 release is ready
[gogost.git] / src / cypherpunks.ru / gogost / gost34112012 / hash.go
1 // GoGOST -- Pure Go GOST cryptographic functions library
2 // Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
17 // GOST R 34.11-2012 hash function.
18 // RFC 6986.
19 package gost34112012
20
21 import (
22         "encoding/binary"
23 )
24
25 const (
26         BlockSize = 64
27 )
28
29 var (
30         pi [256]byte = [256]byte{
31                 0xfc, 0xee, 0xdd, 0x11, 0xcf, 0x6e, 0x31, 0x16,
32                 0xfb, 0xc4, 0xfa, 0xda, 0x23, 0xc5, 0x04, 0x4d,
33                 0xe9, 0x77, 0xf0, 0xdb, 0x93, 0x2e, 0x99, 0xba,
34                 0x17, 0x36, 0xf1, 0xbb, 0x14, 0xcd, 0x5f, 0xc1,
35                 0xf9, 0x18, 0x65, 0x5a, 0xe2, 0x5c, 0xef, 0x21,
36                 0x81, 0x1c, 0x3c, 0x42, 0x8b, 0x01, 0x8e, 0x4f,
37                 0x05, 0x84, 0x02, 0xae, 0xe3, 0x6a, 0x8f, 0xa0,
38                 0x06, 0x0b, 0xed, 0x98, 0x7f, 0xd4, 0xd3, 0x1f,
39                 0xeb, 0x34, 0x2c, 0x51, 0xea, 0xc8, 0x48, 0xab,
40                 0xf2, 0x2a, 0x68, 0xa2, 0xfd, 0x3a, 0xce, 0xcc,
41                 0xb5, 0x70, 0x0e, 0x56, 0x08, 0x0c, 0x76, 0x12,
42                 0xbf, 0x72, 0x13, 0x47, 0x9c, 0xb7, 0x5d, 0x87,
43                 0x15, 0xa1, 0x96, 0x29, 0x10, 0x7b, 0x9a, 0xc7,
44                 0xf3, 0x91, 0x78, 0x6f, 0x9d, 0x9e, 0xb2, 0xb1,
45                 0x32, 0x75, 0x19, 0x3d, 0xff, 0x35, 0x8a, 0x7e,
46                 0x6d, 0x54, 0xc6, 0x80, 0xc3, 0xbd, 0x0d, 0x57,
47                 0xdf, 0xf5, 0x24, 0xa9, 0x3e, 0xa8, 0x43, 0xc9,
48                 0xd7, 0x79, 0xd6, 0xf6, 0x7c, 0x22, 0xb9, 0x03,
49                 0xe0, 0x0f, 0xec, 0xde, 0x7a, 0x94, 0xb0, 0xbc,
50                 0xdc, 0xe8, 0x28, 0x50, 0x4e, 0x33, 0x0a, 0x4a,
51                 0xa7, 0x97, 0x60, 0x73, 0x1e, 0x00, 0x62, 0x44,
52                 0x1a, 0xb8, 0x38, 0x82, 0x64, 0x9f, 0x26, 0x41,
53                 0xad, 0x45, 0x46, 0x92, 0x27, 0x5e, 0x55, 0x2f,
54                 0x8c, 0xa3, 0xa5, 0x7d, 0x69, 0xd5, 0x95, 0x3b,
55                 0x07, 0x58, 0xb3, 0x40, 0x86, 0xac, 0x1d, 0xf7,
56                 0x30, 0x37, 0x6b, 0xe4, 0x88, 0xd9, 0xe7, 0x89,
57                 0xe1, 0x1b, 0x83, 0x49, 0x4c, 0x3f, 0xf8, 0xfe,
58                 0x8d, 0x53, 0xaa, 0x90, 0xca, 0xd8, 0x85, 0x61,
59                 0x20, 0x71, 0x67, 0xa4, 0x2d, 0x2b, 0x09, 0x5b,
60                 0xcb, 0x9b, 0x25, 0xd0, 0xbe, 0xe5, 0x6c, 0x52,
61                 0x59, 0xa6, 0x74, 0xd2, 0xe6, 0xf4, 0xb4, 0xc0,
62                 0xd1, 0x66, 0xaf, 0xc2, 0x39, 0x4b, 0x63, 0xb6,
63         }
64         tau [64]int = [64]int{
65                 0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38,
66                 0x01, 0x09, 0x11, 0x19, 0x21, 0x29, 0x31, 0x39,
67                 0x02, 0x0a, 0x12, 0x1a, 0x22, 0x2a, 0x32, 0x3a,
68                 0x03, 0x0b, 0x13, 0x1b, 0x23, 0x2b, 0x33, 0x3b,
69                 0x04, 0x0c, 0x14, 0x1c, 0x24, 0x2c, 0x34, 0x3c,
70                 0x05, 0x0d, 0x15, 0x1d, 0x25, 0x2d, 0x35, 0x3d,
71                 0x06, 0x0e, 0x16, 0x1e, 0x26, 0x2e, 0x36, 0x3e,
72                 0x07, 0x0f, 0x17, 0x1f, 0x27, 0x2f, 0x37, 0x3f,
73         }
74         c [12][BlockSize]byte = [12][BlockSize]byte{
75                 [BlockSize]byte{
76                         0x07, 0x45, 0xa6, 0xf2, 0x59, 0x65, 0x80, 0xdd,
77                         0x23, 0x4d, 0x74, 0xcc, 0x36, 0x74, 0x76, 0x05,
78                         0x15, 0xd3, 0x60, 0xa4, 0x08, 0x2a, 0x42, 0xa2,
79                         0x01, 0x69, 0x67, 0x92, 0x91, 0xe0, 0x7c, 0x4b,
80                         0xfc, 0xc4, 0x85, 0x75, 0x8d, 0xb8, 0x4e, 0x71,
81                         0x16, 0xd0, 0x45, 0x2e, 0x43, 0x76, 0x6a, 0x2f,
82                         0x1f, 0x7c, 0x65, 0xc0, 0x81, 0x2f, 0xcb, 0xeb,
83                         0xe9, 0xda, 0xca, 0x1e, 0xda, 0x5b, 0x08, 0xb1,
84                 },
85                 [BlockSize]byte{
86                         0xb7, 0x9b, 0xb1, 0x21, 0x70, 0x04, 0x79, 0xe6,
87                         0x56, 0xcd, 0xcb, 0xd7, 0x1b, 0xa2, 0xdd, 0x55,
88                         0xca, 0xa7, 0x0a, 0xdb, 0xc2, 0x61, 0xb5, 0x5c,
89                         0x58, 0x99, 0xd6, 0x12, 0x6b, 0x17, 0xb5, 0x9a,
90                         0x31, 0x01, 0xb5, 0x16, 0x0f, 0x5e, 0xd5, 0x61,
91                         0x98, 0x2b, 0x23, 0x0a, 0x72, 0xea, 0xfe, 0xf3,
92                         0xd7, 0xb5, 0x70, 0x0f, 0x46, 0x9d, 0xe3, 0x4f,
93                         0x1a, 0x2f, 0x9d, 0xa9, 0x8a, 0xb5, 0xa3, 0x6f,
94                 },
95                 [BlockSize]byte{
96                         0xb2, 0x0a, 0xba, 0x0a, 0xf5, 0x96, 0x1e, 0x99,
97                         0x31, 0xdb, 0x7a, 0x86, 0x43, 0xf4, 0xb6, 0xc2,
98                         0x09, 0xdb, 0x62, 0x60, 0x37, 0x3a, 0xc9, 0xc1,
99                         0xb1, 0x9e, 0x35, 0x90, 0xe4, 0x0f, 0xe2, 0xd3,
100                         0x7b, 0x7b, 0x29, 0xb1, 0x14, 0x75, 0xea, 0xf2,
101                         0x8b, 0x1f, 0x9c, 0x52, 0x5f, 0x5e, 0xf1, 0x06,
102                         0x35, 0x84, 0x3d, 0x6a, 0x28, 0xfc, 0x39, 0x0a,
103                         0xc7, 0x2f, 0xce, 0x2b, 0xac, 0xdc, 0x74, 0xf5,
104                 },
105                 [BlockSize]byte{
106                         0x2e, 0xd1, 0xe3, 0x84, 0xbc, 0xbe, 0x0c, 0x22,
107                         0xf1, 0x37, 0xe8, 0x93, 0xa1, 0xea, 0x53, 0x34,
108                         0xbe, 0x03, 0x52, 0x93, 0x33, 0x13, 0xb7, 0xd8,
109                         0x75, 0xd6, 0x03, 0xed, 0x82, 0x2c, 0xd7, 0xa9,
110                         0x3f, 0x35, 0x5e, 0x68, 0xad, 0x1c, 0x72, 0x9d,
111                         0x7d, 0x3c, 0x5c, 0x33, 0x7e, 0x85, 0x8e, 0x48,
112                         0xdd, 0xe4, 0x71, 0x5d, 0xa0, 0xe1, 0x48, 0xf9,
113                         0xd2, 0x66, 0x15, 0xe8, 0xb3, 0xdf, 0x1f, 0xef,
114                 },
115                 [BlockSize]byte{
116                         0x57, 0xfe, 0x6c, 0x7c, 0xfd, 0x58, 0x17, 0x60,
117                         0xf5, 0x63, 0xea, 0xa9, 0x7e, 0xa2, 0x56, 0x7a,
118                         0x16, 0x1a, 0x27, 0x23, 0xb7, 0x00, 0xff, 0xdf,
119                         0xa3, 0xf5, 0x3a, 0x25, 0x47, 0x17, 0xcd, 0xbf,
120                         0xbd, 0xff, 0x0f, 0x80, 0xd7, 0x35, 0x9e, 0x35,
121                         0x4a, 0x10, 0x86, 0x16, 0x1f, 0x1c, 0x15, 0x7f,
122                         0x63, 0x23, 0xa9, 0x6c, 0x0c, 0x41, 0x3f, 0x9a,
123                         0x99, 0x47, 0x47, 0xad, 0xac, 0x6b, 0xea, 0x4b,
124                 },
125                 [BlockSize]byte{
126                         0x6e, 0x7d, 0x64, 0x46, 0x7a, 0x40, 0x68, 0xfa,
127                         0x35, 0x4f, 0x90, 0x36, 0x72, 0xc5, 0x71, 0xbf,
128                         0xb6, 0xc6, 0xbe, 0xc2, 0x66, 0x1f, 0xf2, 0x0a,
129                         0xb4, 0xb7, 0x9a, 0x1c, 0xb7, 0xa6, 0xfa, 0xcf,
130                         0xc6, 0x8e, 0xf0, 0x9a, 0xb4, 0x9a, 0x7f, 0x18,
131                         0x6c, 0xa4, 0x42, 0x51, 0xf9, 0xc4, 0x66, 0x2d,
132                         0xc0, 0x39, 0x30, 0x7a, 0x3b, 0xc3, 0xa4, 0x6f,
133                         0xd9, 0xd3, 0x3a, 0x1d, 0xae, 0xae, 0x4f, 0xae,
134                 },
135                 [BlockSize]byte{
136                         0x93, 0xd4, 0x14, 0x3a, 0x4d, 0x56, 0x86, 0x88,
137                         0xf3, 0x4a, 0x3c, 0xa2, 0x4c, 0x45, 0x17, 0x35,
138                         0x04, 0x05, 0x4a, 0x28, 0x83, 0x69, 0x47, 0x06,
139                         0x37, 0x2c, 0x82, 0x2d, 0xc5, 0xab, 0x92, 0x09,
140                         0xc9, 0x93, 0x7a, 0x19, 0x33, 0x3e, 0x47, 0xd3,
141                         0xc9, 0x87, 0xbf, 0xe6, 0xc7, 0xc6, 0x9e, 0x39,
142                         0x54, 0x09, 0x24, 0xbf, 0xfe, 0x86, 0xac, 0x51,
143                         0xec, 0xc5, 0xaa, 0xee, 0x16, 0x0e, 0xc7, 0xf4,
144                 },
145                 [BlockSize]byte{
146                         0x1e, 0xe7, 0x02, 0xbf, 0xd4, 0x0d, 0x7f, 0xa4,
147                         0xd9, 0xa8, 0x51, 0x59, 0x35, 0xc2, 0xac, 0x36,
148                         0x2f, 0xc4, 0xa5, 0xd1, 0x2b, 0x8d, 0xd1, 0x69,
149                         0x90, 0x06, 0x9b, 0x92, 0xcb, 0x2b, 0x89, 0xf4,
150                         0x9a, 0xc4, 0xdb, 0x4d, 0x3b, 0x44, 0xb4, 0x89,
151                         0x1e, 0xde, 0x36, 0x9c, 0x71, 0xf8, 0xb7, 0x4e,
152                         0x41, 0x41, 0x6e, 0x0c, 0x02, 0xaa, 0xe7, 0x03,
153                         0xa7, 0xc9, 0x93, 0x4d, 0x42, 0x5b, 0x1f, 0x9b,
154                 },
155                 [BlockSize]byte{
156                         0xdb, 0x5a, 0x23, 0x83, 0x51, 0x44, 0x61, 0x72,
157                         0x60, 0x2a, 0x1f, 0xcb, 0x92, 0xdc, 0x38, 0x0e,
158                         0x54, 0x9c, 0x07, 0xa6, 0x9a, 0x8a, 0x2b, 0x7b,
159                         0xb1, 0xce, 0xb2, 0xdb, 0x0b, 0x44, 0x0a, 0x80,
160                         0x84, 0x09, 0x0d, 0xe0, 0xb7, 0x55, 0xd9, 0x3c,
161                         0x24, 0x42, 0x89, 0x25, 0x1b, 0x3a, 0x7d, 0x3a,
162                         0xde, 0x5f, 0x16, 0xec, 0xd8, 0x9a, 0x4c, 0x94,
163                         0x9b, 0x22, 0x31, 0x16, 0x54, 0x5a, 0x8f, 0x37,
164                 },
165                 [BlockSize]byte{
166                         0xed, 0x9c, 0x45, 0x98, 0xfb, 0xc7, 0xb4, 0x74,
167                         0xc3, 0xb6, 0x3b, 0x15, 0xd1, 0xfa, 0x98, 0x36,
168                         0xf4, 0x52, 0x76, 0x3b, 0x30, 0x6c, 0x1e, 0x7a,
169                         0x4b, 0x33, 0x69, 0xaf, 0x02, 0x67, 0xe7, 0x9f,
170                         0x03, 0x61, 0x33, 0x1b, 0x8a, 0xe1, 0xff, 0x1f,
171                         0xdb, 0x78, 0x8a, 0xff, 0x1c, 0xe7, 0x41, 0x89,
172                         0xf3, 0xf3, 0xe4, 0xb2, 0x48, 0xe5, 0x2a, 0x38,
173                         0x52, 0x6f, 0x05, 0x80, 0xa6, 0xde, 0xbe, 0xab,
174                 },
175                 [BlockSize]byte{
176                         0x1b, 0x2d, 0xf3, 0x81, 0xcd, 0xa4, 0xca, 0x6b,
177                         0x5d, 0xd8, 0x6f, 0xc0, 0x4a, 0x59, 0xa2, 0xde,
178                         0x98, 0x6e, 0x47, 0x7d, 0x1d, 0xcd, 0xba, 0xef,
179                         0xca, 0xb9, 0x48, 0xea, 0xef, 0x71, 0x1d, 0x8a,
180                         0x79, 0x66, 0x84, 0x14, 0x21, 0x80, 0x01, 0x20,
181                         0x61, 0x07, 0xab, 0xeb, 0xbb, 0x6b, 0xfa, 0xd8,
182                         0x94, 0xfe, 0x5a, 0x63, 0xcd, 0xc6, 0x02, 0x30,
183                         0xfb, 0x89, 0xc8, 0xef, 0xd0, 0x9e, 0xcd, 0x7b,
184                 },
185                 [BlockSize]byte{
186                         0x20, 0xd7, 0x1b, 0xf1, 0x4a, 0x92, 0xbc, 0x48,
187                         0x99, 0x1b, 0xb2, 0xd9, 0xd5, 0x17, 0xf4, 0xfa,
188                         0x52, 0x28, 0xe1, 0x88, 0xaa, 0xa4, 0x1d, 0xe7,
189                         0x86, 0xcc, 0x91, 0x18, 0x9d, 0xef, 0x80, 0x5d,
190                         0x9b, 0x9f, 0x21, 0x30, 0xd4, 0x12, 0x20, 0xf8,
191                         0x77, 0x1d, 0xdf, 0xbc, 0x32, 0x3c, 0xa4, 0xcd,
192                         0x7a, 0xb1, 0x49, 0x04, 0xb0, 0x80, 0x13, 0xd2,
193                         0xba, 0x31, 0x16, 0xf1, 0x67, 0xe7, 0x8e, 0x37,
194                 },
195         }
196         a [64]uint64 // It is filled in init()
197 )
198
199 func init() {
200         as := [64][]byte{
201                 []byte{0x8e, 0x20, 0xfa, 0xa7, 0x2b, 0xa0, 0xb4, 0x70},
202                 []byte{0x47, 0x10, 0x7d, 0xdd, 0x9b, 0x50, 0x5a, 0x38},
203                 []byte{0xad, 0x08, 0xb0, 0xe0, 0xc3, 0x28, 0x2d, 0x1c},
204                 []byte{0xd8, 0x04, 0x58, 0x70, 0xef, 0x14, 0x98, 0x0e},
205                 []byte{0x6c, 0x02, 0x2c, 0x38, 0xf9, 0x0a, 0x4c, 0x07},
206                 []byte{0x36, 0x01, 0x16, 0x1c, 0xf2, 0x05, 0x26, 0x8d},
207                 []byte{0x1b, 0x8e, 0x0b, 0x0e, 0x79, 0x8c, 0x13, 0xc8},
208                 []byte{0x83, 0x47, 0x8b, 0x07, 0xb2, 0x46, 0x87, 0x64},
209                 []byte{0xa0, 0x11, 0xd3, 0x80, 0x81, 0x8e, 0x8f, 0x40},
210                 []byte{0x50, 0x86, 0xe7, 0x40, 0xce, 0x47, 0xc9, 0x20},
211                 []byte{0x28, 0x43, 0xfd, 0x20, 0x67, 0xad, 0xea, 0x10},
212                 []byte{0x14, 0xaf, 0xf0, 0x10, 0xbd, 0xd8, 0x75, 0x08},
213                 []byte{0x0a, 0xd9, 0x78, 0x08, 0xd0, 0x6c, 0xb4, 0x04},
214                 []byte{0x05, 0xe2, 0x3c, 0x04, 0x68, 0x36, 0x5a, 0x02},
215                 []byte{0x8c, 0x71, 0x1e, 0x02, 0x34, 0x1b, 0x2d, 0x01},
216                 []byte{0x46, 0xb6, 0x0f, 0x01, 0x1a, 0x83, 0x98, 0x8e},
217                 []byte{0x90, 0xda, 0xb5, 0x2a, 0x38, 0x7a, 0xe7, 0x6f},
218                 []byte{0x48, 0x6d, 0xd4, 0x15, 0x1c, 0x3d, 0xfd, 0xb9},
219                 []byte{0x24, 0xb8, 0x6a, 0x84, 0x0e, 0x90, 0xf0, 0xd2},
220                 []byte{0x12, 0x5c, 0x35, 0x42, 0x07, 0x48, 0x78, 0x69},
221                 []byte{0x09, 0x2e, 0x94, 0x21, 0x8d, 0x24, 0x3c, 0xba},
222                 []byte{0x8a, 0x17, 0x4a, 0x9e, 0xc8, 0x12, 0x1e, 0x5d},
223                 []byte{0x45, 0x85, 0x25, 0x4f, 0x64, 0x09, 0x0f, 0xa0},
224                 []byte{0xac, 0xcc, 0x9c, 0xa9, 0x32, 0x8a, 0x89, 0x50},
225                 []byte{0x9d, 0x4d, 0xf0, 0x5d, 0x5f, 0x66, 0x14, 0x51},
226                 []byte{0xc0, 0xa8, 0x78, 0xa0, 0xa1, 0x33, 0x0a, 0xa6},
227                 []byte{0x60, 0x54, 0x3c, 0x50, 0xde, 0x97, 0x05, 0x53},
228                 []byte{0x30, 0x2a, 0x1e, 0x28, 0x6f, 0xc5, 0x8c, 0xa7},
229                 []byte{0x18, 0x15, 0x0f, 0x14, 0xb9, 0xec, 0x46, 0xdd},
230                 []byte{0x0c, 0x84, 0x89, 0x0a, 0xd2, 0x76, 0x23, 0xe0},
231                 []byte{0x06, 0x42, 0xca, 0x05, 0x69, 0x3b, 0x9f, 0x70},
232                 []byte{0x03, 0x21, 0x65, 0x8c, 0xba, 0x93, 0xc1, 0x38},
233                 []byte{0x86, 0x27, 0x5d, 0xf0, 0x9c, 0xe8, 0xaa, 0xa8},
234                 []byte{0x43, 0x9d, 0xa0, 0x78, 0x4e, 0x74, 0x55, 0x54},
235                 []byte{0xaf, 0xc0, 0x50, 0x3c, 0x27, 0x3a, 0xa4, 0x2a},
236                 []byte{0xd9, 0x60, 0x28, 0x1e, 0x9d, 0x1d, 0x52, 0x15},
237                 []byte{0xe2, 0x30, 0x14, 0x0f, 0xc0, 0x80, 0x29, 0x84},
238                 []byte{0x71, 0x18, 0x0a, 0x89, 0x60, 0x40, 0x9a, 0x42},
239                 []byte{0xb6, 0x0c, 0x05, 0xca, 0x30, 0x20, 0x4d, 0x21},
240                 []byte{0x5b, 0x06, 0x8c, 0x65, 0x18, 0x10, 0xa8, 0x9e},
241                 []byte{0x45, 0x6c, 0x34, 0x88, 0x7a, 0x38, 0x05, 0xb9},
242                 []byte{0xac, 0x36, 0x1a, 0x44, 0x3d, 0x1c, 0x8c, 0xd2},
243                 []byte{0x56, 0x1b, 0x0d, 0x22, 0x90, 0x0e, 0x46, 0x69},
244                 []byte{0x2b, 0x83, 0x88, 0x11, 0x48, 0x07, 0x23, 0xba},
245                 []byte{0x9b, 0xcf, 0x44, 0x86, 0x24, 0x8d, 0x9f, 0x5d},
246                 []byte{0xc3, 0xe9, 0x22, 0x43, 0x12, 0xc8, 0xc1, 0xa0},
247                 []byte{0xef, 0xfa, 0x11, 0xaf, 0x09, 0x64, 0xee, 0x50},
248                 []byte{0xf9, 0x7d, 0x86, 0xd9, 0x8a, 0x32, 0x77, 0x28},
249                 []byte{0xe4, 0xfa, 0x20, 0x54, 0xa8, 0x0b, 0x32, 0x9c},
250                 []byte{0x72, 0x7d, 0x10, 0x2a, 0x54, 0x8b, 0x19, 0x4e},
251                 []byte{0x39, 0xb0, 0x08, 0x15, 0x2a, 0xcb, 0x82, 0x27},
252                 []byte{0x92, 0x58, 0x04, 0x84, 0x15, 0xeb, 0x41, 0x9d},
253                 []byte{0x49, 0x2c, 0x02, 0x42, 0x84, 0xfb, 0xae, 0xc0},
254                 []byte{0xaa, 0x16, 0x01, 0x21, 0x42, 0xf3, 0x57, 0x60},
255                 []byte{0x55, 0x0b, 0x8e, 0x9e, 0x21, 0xf7, 0xa5, 0x30},
256                 []byte{0xa4, 0x8b, 0x47, 0x4f, 0x9e, 0xf5, 0xdc, 0x18},
257                 []byte{0x70, 0xa6, 0xa5, 0x6e, 0x24, 0x40, 0x59, 0x8e},
258                 []byte{0x38, 0x53, 0xdc, 0x37, 0x12, 0x20, 0xa2, 0x47},
259                 []byte{0x1c, 0xa7, 0x6e, 0x95, 0x09, 0x10, 0x51, 0xad},
260                 []byte{0x0e, 0xdd, 0x37, 0xc4, 0x8a, 0x08, 0xa6, 0xd8},
261                 []byte{0x07, 0xe0, 0x95, 0x62, 0x45, 0x04, 0x53, 0x6c},
262                 []byte{0x8d, 0x70, 0xc4, 0x31, 0xac, 0x02, 0xa7, 0x36},
263                 []byte{0xc8, 0x38, 0x62, 0x96, 0x56, 0x01, 0xdd, 0x1b},
264                 []byte{0x64, 0x1c, 0x31, 0x4b, 0x2b, 0x8e, 0xe0, 0x83},
265         }
266         for i := 0; i < 64; i++ {
267                 a[i] = binary.BigEndian.Uint64(as[i])
268         }
269 }
270
271 type Hash struct {
272         size int
273         buf  []byte
274         n    uint64
275         hsh  *[BlockSize]byte
276         chk  *[BlockSize]byte
277         tmp  *[BlockSize]byte
278 }
279
280 // Create new hash object with specified size digest size.
281 // Size is either 512 or 256 (bits).
282 func New(size int) *Hash {
283         if size != 256 && size != 512 {
284                 panic("size must be either 256 or 512")
285         }
286         h := Hash{
287                 size: size,
288                 hsh:  new([BlockSize]byte),
289                 chk:  new([BlockSize]byte),
290                 tmp:  new([BlockSize]byte),
291         }
292         h.Reset()
293         return &h
294 }
295
296 func (h *Hash) Reset() {
297         h.n = 0
298         h.buf = nil
299         for i := 0; i < BlockSize; i++ {
300                 h.chk[i] = 0
301                 if h.size == 256 {
302                         h.hsh[i] = 1
303                 } else {
304                         h.hsh[i] = 0
305                 }
306         }
307 }
308
309 func (h *Hash) BlockSize() int {
310         return BlockSize
311 }
312
313 func (h *Hash) Size() int {
314         return h.size / 8
315 }
316
317 func (h *Hash) Write(data []byte) (int, error) {
318         h.buf = append(h.buf, data...)
319         for len(h.buf) >= BlockSize {
320                 copy(h.tmp[:], h.buf[:BlockSize])
321                 h.hsh = g(h.n, h.hsh, h.tmp)
322                 h.chk = add512bit(h.chk, h.tmp)
323                 h.n += BlockSize * 8
324                 h.buf = h.buf[BlockSize:]
325         }
326         return len(data), nil
327 }
328
329 func (h *Hash) Sum(in []byte) []byte {
330         buf := new([BlockSize]byte)
331         copy(h.tmp[:], buf[:])
332         copy(buf[:], h.buf[:])
333         buf[len(h.buf)] = 1
334         hsh := g(h.n, h.hsh, buf)
335         binary.LittleEndian.PutUint64(h.tmp[:], h.n+uint64(len(h.buf))*8)
336         hsh = g(0, hsh, h.tmp)
337         hsh = g(0, hsh, add512bit(h.chk, buf))
338         if h.size == 256 {
339                 return append(in, hsh[BlockSize/2:]...)
340         }
341         return append(in, hsh[:]...)
342 }
343
344 func add512bit(chk, data *[BlockSize]byte) *[BlockSize]byte {
345         var ss uint16
346         r := new([BlockSize]byte)
347         for i := 0; i < BlockSize; i++ {
348                 ss = uint16(chk[i]) + uint16(data[i]) + (ss >> 8)
349                 r[i] = byte(0xFF & ss)
350         }
351         return r
352 }
353
354 func g(n uint64, hsh, data *[BlockSize]byte) *[BlockSize]byte {
355         ns := make([]byte, 8)
356         binary.LittleEndian.PutUint64(ns, n)
357         r := new([BlockSize]byte)
358         for i := 0; i < 8; i++ {
359                 r[i] = hsh[i] ^ ns[i]
360         }
361         copy(r[8:], hsh[8:])
362         return blockXor(blockXor(e(l(ps(r)), data), hsh), data)
363 }
364
365 func e(k, msg *[BlockSize]byte) *[BlockSize]byte {
366         for i := 0; i < 12; i++ {
367                 msg = l(ps(blockXor(k, msg)))
368                 k = l(ps(blockXor(k, &c[i])))
369         }
370         return blockXor(k, msg)
371 }
372
373 func blockXor(x, y *[BlockSize]byte) *[BlockSize]byte {
374         r := new([BlockSize]byte)
375         for i := 0; i < BlockSize; i++ {
376                 r[i] = x[i] ^ y[i]
377         }
378         return r
379 }
380
381 func ps(data *[BlockSize]byte) *[BlockSize]byte {
382         r := new([BlockSize]byte)
383         for i := 0; i < BlockSize; i++ {
384                 r[tau[i]] = pi[int(data[i])]
385         }
386         return r
387 }
388
389 func l(data *[BlockSize]byte) *[BlockSize]byte {
390         var val uint64
391         var res64 uint64
392         var j int
393         r := new([BlockSize]byte)
394         for i := 0; i < 8; i++ {
395                 val = binary.LittleEndian.Uint64(data[i*8 : i*8+8])
396                 res64 = 0
397                 for j = 0; j < BlockSize; j++ {
398                         if val&0x8000000000000000 > 0 {
399                                 res64 ^= a[j]
400                         }
401                         val <<= 1
402                 }
403                 binary.LittleEndian.PutUint64(r[i*8:i*8+8], res64)
404         }
405         return r
406 }