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