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