]> Cypherpunks.ru repositories - gogost.git/blob - internal/gost34112012/hash.go
Less Streebog 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         eMsgBuf []byte
299         eKBuf   []byte
300         eXorBuf []byte
301         gBuf    []byte
302         addBuf  []byte
303 }
304
305 // Create new hash object with specified size digest size.
306 func New(size int) *Hash {
307         if size != 32 && size != 64 {
308                 panic("size must be either 32 or 64")
309         }
310         h := Hash{
311                 size:    size,
312                 hsh:     make([]byte, BlockSize),
313                 chk:     make([]byte, BlockSize),
314                 tmp:     make([]byte, BlockSize),
315                 psBuf:   make([]byte, BlockSize),
316                 eMsgBuf: make([]byte, BlockSize),
317                 eKBuf:   make([]byte, BlockSize),
318                 eXorBuf: make([]byte, BlockSize),
319                 gBuf:    make([]byte, BlockSize),
320                 addBuf:  make([]byte, BlockSize),
321         }
322         h.Reset()
323         return &h
324 }
325
326 func (h *Hash) Reset() {
327         h.n = 0
328         h.buf = nil
329         for i := 0; i < BlockSize; i++ {
330                 h.chk[i] = 0
331                 if h.size == 32 {
332                         h.hsh[i] = 1
333                 } else {
334                         h.hsh[i] = 0
335                 }
336         }
337 }
338
339 func (h *Hash) BlockSize() int {
340         return BlockSize
341 }
342
343 func (h *Hash) Size() int {
344         return h.size
345 }
346
347 func (h *Hash) Write(data []byte) (int, error) {
348         h.buf = append(h.buf, data...)
349         for len(h.buf) >= BlockSize {
350                 copy(h.tmp, h.buf[:BlockSize])
351                 copy(h.hsh, h.g(h.n, h.hsh, h.tmp))
352                 copy(h.chk, h.add512bit(h.chk, h.tmp))
353                 h.n += BlockSize * 8
354                 h.buf = h.buf[BlockSize:]
355         }
356         return len(data), nil
357 }
358
359 func (h *Hash) Sum(in []byte) []byte {
360         buf := make([]byte, BlockSize)
361         hsh := make([]byte, BlockSize)
362         copy(h.tmp, buf)
363         copy(buf, h.buf)
364         buf[len(h.buf)] = 1
365         copy(hsh, h.g(h.n, h.hsh, buf))
366         binary.LittleEndian.PutUint64(h.tmp, h.n+uint64(len(h.buf))*8)
367         copy(hsh, h.g(0, hsh, h.tmp))
368         copy(hsh, h.g(0, hsh, h.add512bit(h.chk, buf)))
369         if h.size == 32 {
370                 return append(in, hsh[BlockSize/2:]...)
371         }
372         return append(in, hsh...)
373 }
374
375 func (h *Hash) add512bit(chk, data []byte) []byte {
376         var ss uint16
377         for i := 0; i < BlockSize; i++ {
378                 ss = uint16(chk[i]) + uint16(data[i]) + (ss >> 8)
379                 h.addBuf[i] = byte(0xFF & ss)
380         }
381         return h.addBuf
382 }
383
384 func (h *Hash) g(n uint64, hsh, data []byte) []byte {
385         out := h.gBuf
386         copy(out, hsh)
387         out[0] ^= byte((n >> 0) & 0xFF)
388         out[1] ^= byte((n >> 8) & 0xFF)
389         out[2] ^= byte((n >> 16) & 0xFF)
390         out[3] ^= byte((n >> 24) & 0xFF)
391         out[4] ^= byte((n >> 32) & 0xFF)
392         out[5] ^= byte((n >> 40) & 0xFF)
393         out[6] ^= byte((n >> 48) & 0xFF)
394         out[7] ^= byte((n >> 56) & 0xFF)
395         return blockXor(out, blockXor(out, h.e(l(out, h.ps(out)), data), hsh), data)
396 }
397
398 func (h *Hash) e(k, msg []byte) []byte {
399         for i := 0; i < 12; i++ {
400                 msg = l(h.eMsgBuf, h.ps(blockXor(h.eXorBuf, k, msg)))
401                 k = l(h.eKBuf, h.ps(blockXor(h.eXorBuf, k, c[i][:])))
402         }
403         return blockXor(h.eXorBuf, k, msg)
404 }
405
406 func blockXor(dst, x, y []byte) []byte {
407         for i := 0; i < BlockSize; i++ {
408                 dst[i] = x[i] ^ y[i]
409         }
410         return dst
411 }
412
413 func (h *Hash) ps(data []byte) []byte {
414         for i := 0; i < BlockSize; i++ {
415                 h.psBuf[tau[i]] = pi[int(data[i])]
416         }
417         return h.psBuf
418 }
419
420 func l(out, data []byte) []byte {
421         for i := 0; i < 8; i++ {
422                 res64 := uint64(0)
423                 res64 ^= cache[0][data[8*i+0]]
424                 res64 ^= cache[1][data[8*i+1]]
425                 res64 ^= cache[2][data[8*i+2]]
426                 res64 ^= cache[3][data[8*i+3]]
427                 res64 ^= cache[4][data[8*i+4]]
428                 res64 ^= cache[5][data[8*i+5]]
429                 res64 ^= cache[6][data[8*i+6]]
430                 res64 ^= cache[7][data[8*i+7]]
431                 binary.LittleEndian.PutUint64(out[i*8:i*8+8], res64)
432         }
433         return out
434 }
435
436 func (h *Hash) MarshalBinary() (data []byte, err error) {
437         data = make([]byte, len(MarshaledName)+1+8+2*BlockSize+len(h.buf))
438         copy(data, []byte(MarshaledName))
439         idx := len(MarshaledName)
440         data[idx] = byte(h.size)
441         idx += 1
442         binary.BigEndian.PutUint64(data[idx:idx+8], h.n)
443         idx += 8
444         copy(data[idx:], h.hsh)
445         idx += BlockSize
446         copy(data[idx:], h.chk)
447         idx += BlockSize
448         copy(data[idx:], h.buf)
449         return
450 }
451
452 func (h *Hash) UnmarshalBinary(data []byte) error {
453         expectedLen := len(MarshaledName) + 1 + 8 + 2*BlockSize
454         if len(data) < expectedLen {
455                 return fmt.Errorf("gogost/internal/gost34112012: len(data) != %d", expectedLen)
456         }
457         if !bytes.HasPrefix(data, []byte(MarshaledName)) {
458                 return errors.New("gogost/internal/gost34112012: no hash name prefix")
459         }
460         idx := len(MarshaledName)
461         h.size = int(data[idx])
462         idx += 1
463         h.n = binary.BigEndian.Uint64(data[idx : idx+8])
464         idx += 8
465         copy(h.hsh, data[idx:])
466         idx += BlockSize
467         copy(h.chk, data[idx:])
468         idx += BlockSize
469         h.buf = data[idx:]
470         return nil
471 }