1 // GoGOST -- Pure Go GOST cryptographic functions library
2 // Copyright (C) 2015-2019 Sergey Matveev <stargrave@stargrave.org>
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.
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.
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/>.
17 // GOST R 34.11-94 hash function.
25 "cypherpunks.ru/gogost/gost28147"
34 SboxDefault *gost28147.Sbox = &gost28147.SboxIdGostR341194TestParamSet
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,
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,
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,
55 big256 *big.Int = big.NewInt(0).SetBit(big.NewInt(0), 256, 1)
67 func New(sbox *gost28147.Sbox) *Hash {
73 func (h *Hash) Reset() {
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,
85 func (h *Hash) BlockSize() int {
89 func (h *Hash) Size() int {
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])
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],
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])
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]
131 func blockXor(dst, a, b *[BlockSize]byte) {
132 for i := 0; i < BlockSize; i++ {
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)
147 blockReverse(k[:], k[:])
148 c := gost28147.NewCipher(k[:], h.sbox)
149 s := make([]byte, gost28147.BlockSize)
151 hin[31], hin[30], hin[29], hin[28], hin[27], hin[26], hin[25], hin[24],
162 blockXor(u, fA(u), &c2)
166 blockReverse(k[:], k[:])
167 c = gost28147.NewCipher(k[:], h.sbox)
169 hin[23], hin[22], hin[21], hin[20], hin[19], hin[18], hin[17], hin[16],
180 blockXor(u, fA(u), &c3)
184 blockReverse(k[:], k[:])
185 c = gost28147.NewCipher(k[:], h.sbox)
187 hin[15], hin[14], hin[13], hin[12], hin[11], hin[10], hin[9], hin[8],
198 blockXor(u, fA(u), &c4)
202 blockReverse(k[:], k[:])
203 c = gost28147.NewCipher(k[:], h.sbox)
205 hin[7], hin[6], hin[5], hin[4], hin[3], hin[2], hin[1], hin[0],
216 for i := 0; i < 12; i++ {
219 blockXor(out, out, &m)
221 blockXor(out, out, &hin)
222 for i := 0; i < 61; i++ {
228 func (h *Hash) chkAdd(data []byte) *big.Int {
229 i := big.NewInt(0).SetBytes(data)
231 if i.Cmp(big256) != -1 {
237 func (h *Hash) Write(data []byte) (int, error) {
238 h.buf = append(h.buf, data...)
239 for len(h.buf) >= BlockSize {
240 h.size += BlockSize * 8
241 blockReverse(h.tmp[:], h.buf[:BlockSize])
242 h.chk = h.chkAdd(h.tmp[:])
243 h.buf = h.buf[BlockSize:]
244 h.hsh = h.step(h.hsh, h.tmp)
246 return len(data), nil
249 func (h *Hash) Sum(in []byte) []byte {
253 block := new([BlockSize]byte)
255 size += uint64(len(h.buf)) * 8
256 copy(block[:], h.buf)
257 blockReverse(block[:], block[:])
258 chk = h.chkAdd(block[:])
259 hsh = h.step(hsh, *block)
260 block = new([BlockSize]byte)
262 binary.BigEndian.PutUint64(block[24:], size)
263 hsh = h.step(hsh, *block)
264 block = new([BlockSize]byte)
265 chkBytes := chk.Bytes()
266 copy(block[BlockSize-len(chkBytes):], chkBytes)
267 hsh = h.step(hsh, *block)
268 blockReverse(hsh[:], hsh[:])
269 return append(in, hsh[:]...)