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