]> Cypherpunks.ru repositories - gogost.git/blob - src/cypherpunks.ru/gogost/internal/gost34112012/hash.go
c4d98daf65590c2db18c308e8c63f7bdeeedcafa
[gogost.git] / src / cypherpunks.ru / gogost / 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, 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 func New(size int) *Hash {
282         if size != 32 && size != 64 {
283                 panic("size must be either 32 or 64")
284         }
285         h := Hash{
286                 size: size,
287                 hsh:  new([BlockSize]byte),
288                 chk:  new([BlockSize]byte),
289                 tmp:  new([BlockSize]byte),
290         }
291         h.Reset()
292         return &h
293 }
294
295 func (h *Hash) Reset() {
296         h.n = 0
297         h.buf = nil
298         for i := 0; i < BlockSize; i++ {
299                 h.chk[i] = 0
300                 if h.size == 32 {
301                         h.hsh[i] = 1
302                 } else {
303                         h.hsh[i] = 0
304                 }
305         }
306 }
307
308 func (h *Hash) BlockSize() int {
309         return BlockSize
310 }
311
312 func (h *Hash) Size() int {
313         return h.size
314 }
315
316 func (h *Hash) Write(data []byte) (int, error) {
317         h.buf = append(h.buf, data...)
318         for len(h.buf) >= BlockSize {
319                 copy(h.tmp[:], h.buf[:BlockSize])
320                 h.hsh = g(h.n, h.hsh, h.tmp)
321                 h.chk = add512bit(h.chk, h.tmp)
322                 h.n += BlockSize * 8
323                 h.buf = h.buf[BlockSize:]
324         }
325         return len(data), nil
326 }
327
328 func (h *Hash) Sum(in []byte) []byte {
329         buf := new([BlockSize]byte)
330         copy(h.tmp[:], buf[:])
331         copy(buf[:], h.buf[:])
332         buf[len(h.buf)] = 1
333         hsh := g(h.n, h.hsh, buf)
334         binary.LittleEndian.PutUint64(h.tmp[:], h.n+uint64(len(h.buf))*8)
335         hsh = g(0, hsh, h.tmp)
336         hsh = g(0, hsh, add512bit(h.chk, buf))
337         if h.size == 32 {
338                 return append(in, hsh[BlockSize/2:]...)
339         }
340         return append(in, hsh[:]...)
341 }
342
343 func add512bit(chk, data *[BlockSize]byte) *[BlockSize]byte {
344         var ss uint16
345         r := new([BlockSize]byte)
346         for i := 0; i < BlockSize; i++ {
347                 ss = uint16(chk[i]) + uint16(data[i]) + (ss >> 8)
348                 r[i] = byte(0xFF & ss)
349         }
350         return r
351 }
352
353 func g(n uint64, hsh, data *[BlockSize]byte) *[BlockSize]byte {
354         ns := make([]byte, 8)
355         binary.LittleEndian.PutUint64(ns, n)
356         r := new([BlockSize]byte)
357         for i := 0; i < 8; i++ {
358                 r[i] = hsh[i] ^ ns[i]
359         }
360         copy(r[8:], hsh[8:])
361         return blockXor(blockXor(e(l(ps(r)), data), hsh), data)
362 }
363
364 func e(k, msg *[BlockSize]byte) *[BlockSize]byte {
365         for i := 0; i < 12; i++ {
366                 msg = l(ps(blockXor(k, msg)))
367                 k = l(ps(blockXor(k, &c[i])))
368         }
369         return blockXor(k, msg)
370 }
371
372 func blockXor(x, y *[BlockSize]byte) *[BlockSize]byte {
373         r := new([BlockSize]byte)
374         for i := 0; i < BlockSize; i++ {
375                 r[i] = x[i] ^ y[i]
376         }
377         return r
378 }
379
380 func ps(data *[BlockSize]byte) *[BlockSize]byte {
381         r := new([BlockSize]byte)
382         for i := 0; i < BlockSize; i++ {
383                 r[tau[i]] = pi[int(data[i])]
384         }
385         return r
386 }
387
388 func l(data *[BlockSize]byte) *[BlockSize]byte {
389         var val uint64
390         var res64 uint64
391         var j int
392         r := new([BlockSize]byte)
393         for i := 0; i < 8; i++ {
394                 val = binary.LittleEndian.Uint64(data[i*8 : i*8+8])
395                 res64 = 0
396                 for j = 0; j < BlockSize; j++ {
397                         if val&0x8000000000000000 > 0 {
398                                 res64 ^= a[j]
399                         }
400                         val <<= 1
401                 }
402                 binary.LittleEndian.PutUint64(r[i*8:i*8+8], res64)
403         }
404         return r
405 }