]> Cypherpunks.ru repositories - gogost.git/blob - src/cypherpunks.ru/gogost/gost341194/hash.go
a65a3f500b18cce6bbab0e17b87a44fc902bb1ab
[gogost.git] / src / cypherpunks.ru / gogost / gost341194 / 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-94 hash function.
18 // RFC 5831.
19 package gost341194
20
21 import (
22         "encoding/binary"
23         "math/big"
24
25         "cypherpunks.ru/gogost/gost28147"
26 )
27
28 const (
29         BlockSize = 32
30         Size      = 32
31 )
32
33 var (
34         SboxDefault *gost28147.Sbox = &gost28147.GostR3411_94_TestParamSet
35
36         c2 [BlockSize]byte = [BlockSize]byte{
37                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
38                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
39                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
40                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
41         }
42         c3 [BlockSize]byte = [BlockSize]byte{
43                 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff,
44                 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00,
45                 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
46                 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
47         }
48         c4 [BlockSize]byte = [BlockSize]byte{
49                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
50                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
51                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
52                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
53         }
54
55         big256 *big.Int = big.NewInt(0).SetBit(big.NewInt(0), 256, 1)
56 )
57
58 type Hash struct {
59         sbox *gost28147.Sbox
60         size uint64
61         hsh  [BlockSize]byte
62         chk  *big.Int
63         buf  []byte
64         tmp  [BlockSize]byte
65 }
66
67 func New(sbox *gost28147.Sbox) *Hash {
68         h := Hash{sbox: sbox}
69         h.Reset()
70         return &h
71 }
72
73 func (h *Hash) Reset() {
74         h.size = 0
75         h.hsh = [BlockSize]byte{
76                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
77                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
78                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
79                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
80         }
81         h.chk = big.NewInt(0)
82         h.buf = h.buf[:0]
83 }
84
85 func (h *Hash) BlockSize() int {
86         return BlockSize
87 }
88
89 func (h *Hash) Size() int {
90         return BlockSize
91 }
92
93 func fA(in *[BlockSize]byte) *[BlockSize]byte {
94         out := new([BlockSize]byte)
95         out[0] = in[16+0] ^ in[24+0]
96         out[1] = in[16+1] ^ in[24+1]
97         out[2] = in[16+2] ^ in[24+2]
98         out[3] = in[16+3] ^ in[24+3]
99         out[4] = in[16+4] ^ in[24+4]
100         out[5] = in[16+5] ^ in[24+5]
101         out[6] = in[16+6] ^ in[24+6]
102         out[7] = in[16+7] ^ in[24+7]
103         copy(out[8:], in[0:24])
104         return out
105 }
106
107 func fP(in *[BlockSize]byte) *[BlockSize]byte {
108         return &[BlockSize]byte{
109                 in[0], in[8], in[16], in[24], in[1], in[9], in[17],
110                 in[25], in[2], in[10], in[18], in[26], in[3],
111                 in[11], in[19], in[27], in[4], in[12], in[20],
112                 in[28], in[5], in[13], in[21], in[29], in[6],
113                 in[14], in[22], in[30], in[7], in[15], in[23], in[31],
114         }
115 }
116
117 func fChi(in *[BlockSize]byte) *[BlockSize]byte {
118         out := new([BlockSize]byte)
119         out[0] = in[32-2] ^ in[32-4] ^ in[32-6] ^ in[32-8] ^ in[32-32] ^ in[32-26]
120         out[1] = in[32-1] ^ in[32-3] ^ in[32-5] ^ in[32-7] ^ in[32-31] ^ in[32-25]
121         copy(out[2:32], in[0:30])
122         return out
123 }
124
125 func blockReverse(dst, src []byte) {
126         for i, j := 0, BlockSize-1; i < j; i, j = i+1, j-1 {
127                 dst[i], dst[j] = src[j], src[i]
128         }
129 }
130
131 func blockXor(dst, a, b *[BlockSize]byte) {
132         for i := 0; i < BlockSize; i++ {
133                 dst[i] = a[i] ^ b[i]
134         }
135         return
136 }
137
138 func (h *Hash) step(hin, m [BlockSize]byte) [BlockSize]byte {
139         out := new([BlockSize]byte)
140         u := new([BlockSize]byte)
141         v := new([BlockSize]byte)
142         k := new([BlockSize]byte)
143         (*u) = hin
144         (*v) = m
145         blockXor(k, u, v)
146         k = fP(k)
147         blockReverse(k[:], k[:])
148         kk := *k
149         c := gost28147.NewCipher(kk, h.sbox)
150         s := make([]byte, gost28147.BlockSize)
151         c.Encrypt(s, []byte{
152                 hin[31], hin[30], hin[29], hin[28], hin[27], hin[26], hin[25], hin[24],
153         })
154         out[31] = s[0]
155         out[30] = s[1]
156         out[29] = s[2]
157         out[28] = s[3]
158         out[27] = s[4]
159         out[26] = s[5]
160         out[25] = s[6]
161         out[24] = s[7]
162
163         blockXor(u, fA(u), &c2)
164         v = fA(fA(v))
165         blockXor(k, u, v)
166         k = fP(k)
167         blockReverse(k[:], k[:])
168         c = gost28147.NewCipher(*k, h.sbox)
169         c.Encrypt(s, []byte{
170                 hin[23], hin[22], hin[21], hin[20], hin[19], hin[18], hin[17], hin[16],
171         })
172         out[23] = s[0]
173         out[22] = s[1]
174         out[21] = s[2]
175         out[20] = s[3]
176         out[19] = s[4]
177         out[18] = s[5]
178         out[17] = s[6]
179         out[16] = s[7]
180
181         blockXor(u, fA(u), &c3)
182         v = fA(fA(v))
183         blockXor(k, u, v)
184         k = fP(k)
185         blockReverse(k[:], k[:])
186         c = gost28147.NewCipher(*k, h.sbox)
187         c.Encrypt(s, []byte{
188                 hin[15], hin[14], hin[13], hin[12], hin[11], hin[10], hin[9], hin[8],
189         })
190         out[15] = s[0]
191         out[14] = s[1]
192         out[13] = s[2]
193         out[12] = s[3]
194         out[11] = s[4]
195         out[10] = s[5]
196         out[9] = s[6]
197         out[8] = s[7]
198
199         blockXor(u, fA(u), &c4)
200         v = fA(fA(v))
201         blockXor(k, u, v)
202         k = fP(k)
203         blockReverse(k[:], k[:])
204         c = gost28147.NewCipher(*k, h.sbox)
205         c.Encrypt(s, []byte{
206                 hin[7], hin[6], hin[5], hin[4], hin[3], hin[2], hin[1], hin[0],
207         })
208         out[7] = s[0]
209         out[6] = s[1]
210         out[5] = s[2]
211         out[4] = s[3]
212         out[3] = s[4]
213         out[2] = s[5]
214         out[1] = s[6]
215         out[0] = s[7]
216
217         for i := 0; i < 12; i++ {
218                 out = fChi(out)
219         }
220         blockXor(out, out, &m)
221         out = fChi(out)
222         blockXor(out, out, &hin)
223         for i := 0; i < 61; i++ {
224                 out = fChi(out)
225         }
226         return *out
227 }
228
229 func (h *Hash) chkAdd(data []byte) *big.Int {
230         i := big.NewInt(0).SetBytes(data)
231         i.Add(i, h.chk)
232         if i.Cmp(big256) != -1 {
233                 i.Sub(i, big256)
234         }
235         return i
236 }
237
238 func (h *Hash) Write(data []byte) (int, error) {
239         h.buf = append(h.buf, data...)
240         for len(h.buf) >= BlockSize {
241                 h.size += BlockSize * 8
242                 blockReverse(h.tmp[:], h.buf[:BlockSize])
243                 h.chk = h.chkAdd(h.tmp[:])
244                 h.buf = h.buf[BlockSize:]
245                 h.hsh = h.step(h.hsh, h.tmp)
246         }
247         return len(data), nil
248 }
249
250 func (h *Hash) Sum(in []byte) []byte {
251         size := h.size
252         chk := h.chk
253         hsh := h.hsh
254         block := new([BlockSize]byte)
255         if len(h.buf) != 0 {
256                 size += uint64(len(h.buf)) * 8
257                 copy(block[:], h.buf)
258                 blockReverse(block[:], block[:])
259                 chk = h.chkAdd(block[:])
260                 hsh = h.step(hsh, *block)
261                 block = new([BlockSize]byte)
262         }
263         binary.BigEndian.PutUint64(block[24:], size)
264         hsh = h.step(hsh, *block)
265         block = new([BlockSize]byte)
266         chkBytes := chk.Bytes()
267         copy(block[BlockSize-len(chkBytes):], chkBytes)
268         hsh = h.step(hsh, *block)
269         blockReverse(hsh[:], hsh[:])
270         return append(in, hsh[:]...)
271 }