"crypto/hmac"
"encoding/binary"
"errors"
- "math/big"
)
-var (
- R64 *big.Int = big.NewInt(0)
- R128 *big.Int = big.NewInt(0)
-)
-
-func init() {
- R64.SetBytes([]byte{
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b,
- })
- R128.SetBytes([]byte{
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87,
- })
+type Mul interface {
+ Mul(x, y []byte) []byte
}
type MGM struct {
bufC []byte
padded []byte
sum []byte
-
- x *big.Int
- y *big.Int
- z *big.Int
- maxBit int
- r *big.Int
- mulBuf []byte
+ mul Mul
}
func NewMGM(cipher cipher.Block, tagSize int) (cipher.AEAD, error) {
bufC: make([]byte, blockSize),
padded: make([]byte, blockSize),
sum: make([]byte, blockSize),
- x: big.NewInt(0),
- y: big.NewInt(0),
- z: big.NewInt(0),
- mulBuf: make([]byte, blockSize),
}
if blockSize == 8 {
- mgm.maxBit = 64 - 1
- mgm.r = R64
+ mgm.mul = newMul64()
} else {
- mgm.maxBit = 128 - 1
- mgm.r = R128
+ mgm.mul = newMul128()
}
return &mgm, nil
}
xor( // sum (xor)= H_i (x) A_i
mgm.sum,
mgm.sum,
- mgm.mul(mgm.bufC, ad[:mgm.BlockSize]),
+ mgm.mul.Mul(mgm.bufC, ad[:mgm.BlockSize]),
)
incr(mgm.bufP[:mgm.BlockSize/2]) // Z_{i+1} = incr_l(Z_i)
ad = ad[mgm.BlockSize:]
mgm.padded[i] = 0
}
mgm.cipher.Encrypt(mgm.bufC, mgm.bufP)
- xor(mgm.sum, mgm.sum, mgm.mul(mgm.bufC, mgm.padded))
+ xor(mgm.sum, mgm.sum, mgm.mul.Mul(mgm.bufC, mgm.padded))
incr(mgm.bufP[:mgm.BlockSize/2])
}
xor( // sum (xor)= H_{h+j} (x) C_j
mgm.sum,
mgm.sum,
- mgm.mul(mgm.bufC, text[:mgm.BlockSize]),
+ mgm.mul.Mul(mgm.bufC, text[:mgm.BlockSize]),
)
incr(mgm.bufP[:mgm.BlockSize/2]) // Z_{h+j+1} = incr_l(Z_{h+j})
text = text[mgm.BlockSize:]
mgm.padded[i] = 0
}
mgm.cipher.Encrypt(mgm.bufC, mgm.bufP)
- xor(mgm.sum, mgm.sum, mgm.mul(mgm.bufC, mgm.padded))
+ xor(mgm.sum, mgm.sum, mgm.mul.Mul(mgm.bufC, mgm.padded))
incr(mgm.bufP[:mgm.BlockSize/2])
}
binary.BigEndian.PutUint64(mgm.bufC[mgm.BlockSize/2:], uint64(textLen))
}
// sum (xor)= H_{h+q+1} (x) (len(A) || len(C))
- xor(mgm.sum, mgm.sum, mgm.mul(mgm.bufP, mgm.bufC))
+ xor(mgm.sum, mgm.sum, mgm.mul.Mul(mgm.bufC, mgm.bufP))
mgm.cipher.Encrypt(mgm.bufP, mgm.sum) // E_K(sum)
copy(out, mgm.bufP[:mgm.TagSize]) // MSB_S(E_K(sum))
}
"bytes"
"crypto/cipher"
"crypto/rand"
+ "io"
"testing"
"testing/quick"
nonce[:gost341264.BlockSize],
)
}
+
+func BenchmarkMGM64(b *testing.B) {
+ key := make([]byte, gost341264.KeySize)
+ if _, err := io.ReadFull(rand.Reader, key); err != nil {
+ panic(err)
+ }
+ nonce := make([]byte, gost341264.BlockSize)
+ if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
+ panic(err)
+ }
+ nonce[0] &= 0x7F
+ pt := make([]byte, 1280+3)
+ if _, err := io.ReadFull(rand.Reader, pt); err != nil {
+ panic(err)
+ }
+ c := gost341264.NewCipher(key)
+ aead, err := NewMGM(c, gost341264.BlockSize)
+ if err != nil {
+ panic(err)
+ }
+ ct := make([]byte, len(pt)+aead.Overhead())
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ aead.Seal(ct[:0], nonce, pt, nil)
+ }
+}
+
+func BenchmarkMGM128(b *testing.B) {
+ key := make([]byte, gost3412128.KeySize)
+ if _, err := io.ReadFull(rand.Reader, key); err != nil {
+ panic(err)
+ }
+ nonce := make([]byte, gost3412128.BlockSize)
+ if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
+ panic(err)
+ }
+ nonce[0] &= 0x7F
+ pt := make([]byte, 1280+3)
+ if _, err := io.ReadFull(rand.Reader, pt); err != nil {
+ panic(err)
+ }
+ c := gost3412128.NewCipher(key)
+ aead, err := NewMGM(c, gost3412128.BlockSize)
+ if err != nil {
+ panic(err)
+ }
+ ct := make([]byte, len(pt)+aead.Overhead())
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ aead.Seal(ct[:0], nonce, pt, nil)
+ }
+}
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2021 Sergey Matveev <stargrave@stargrave.org>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 3 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package mgm
+
+import (
+ "math/big"
+)
+
+const Mul128MaxBit = 128 - 1
+
+var R128 = big.NewInt(0).SetBytes([]byte{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87,
+})
+
+type mul128 struct {
+ x *big.Int
+ y *big.Int
+ z *big.Int
+ buf [16]byte
+}
+
+func newMul128() *mul128 {
+ return &mul128{
+ x: big.NewInt(0),
+ y: big.NewInt(0),
+ z: big.NewInt(0),
+ }
+}
+
+func (mul *mul128) Mul(x, y []byte) []byte {
+ mul.x.SetBytes(x)
+ mul.y.SetBytes(y)
+ mul.z.SetInt64(0)
+ for mul.y.BitLen() != 0 {
+ if mul.y.Bit(0) == 1 {
+ mul.z.Xor(mul.z, mul.x)
+ }
+ if mul.x.Bit(Mul128MaxBit) == 1 {
+ mul.x.SetBit(mul.x, Mul128MaxBit, 0)
+ mul.x.Lsh(mul.x, 1)
+ mul.x.Xor(mul.x, R128)
+ } else {
+ mul.x.Lsh(mul.x, 1)
+ }
+ mul.y.Rsh(mul.y, 1)
+ }
+ zBytes := mul.z.Bytes()
+ rem := len(x) - len(zBytes)
+ for i := 0; i < rem; i++ {
+ mul.buf[i] = 0
+ }
+ copy(mul.buf[rem:], zBytes)
+ return mul.buf[:]
+}
import (
"crypto/rand"
- "math/big"
"testing"
"go.cypherpunks.ru/gogost/v5/gost3412128"
- "go.cypherpunks.ru/gogost/v5/gost341264"
)
-func BenchmarkMul64(b *testing.B) {
- x := make([]byte, gost341264.BlockSize)
- y := make([]byte, gost341264.BlockSize)
- rand.Read(x)
- rand.Read(y)
- mgm := MGM{
- x: big.NewInt(0),
- y: big.NewInt(0),
- z: big.NewInt(0),
- maxBit: 64 - 1,
- r: R64,
- mulBuf: make([]byte, gost341264.BlockSize),
- }
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- mgm.mul(x, y)
- }
-}
-
func BenchmarkMul128(b *testing.B) {
x := make([]byte, gost3412128.BlockSize)
y := make([]byte, gost3412128.BlockSize)
rand.Read(x)
rand.Read(y)
- mgm := MGM{
- x: big.NewInt(0),
- y: big.NewInt(0),
- z: big.NewInt(0),
- maxBit: 128 - 1,
- r: R128,
- mulBuf: make([]byte, gost3412128.BlockSize),
- }
+ mul := newMul128()
b.ResetTimer()
for i := 0; i < b.N; i++ {
- mgm.mul(x, y)
+ mul.Mul(x, y)
}
}
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2021 Sergey Matveev <stargrave@stargrave.org>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 3 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package mgm
+
+import "math/big"
+
+const Mul64MaxBit = 64 - 1
+
+var R64 = big.NewInt(0).SetBytes([]byte{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b,
+})
+
+type mul64 struct {
+ x *big.Int
+ y *big.Int
+ z *big.Int
+ buf [8]byte
+}
+
+func newMul64() *mul64 {
+ return &mul64{
+ x: big.NewInt(0),
+ y: big.NewInt(0),
+ z: big.NewInt(0),
+ }
+}
+
+func (mul *mul64) Mul(x, y []byte) []byte {
+ mul.x.SetBytes(x)
+ mul.y.SetBytes(y)
+ mul.z.SetInt64(0)
+ for mul.y.BitLen() != 0 {
+ if mul.y.Bit(0) == 1 {
+ mul.z.Xor(mul.z, mul.x)
+ }
+ if mul.x.Bit(Mul64MaxBit) == 1 {
+ mul.x.SetBit(mul.x, Mul64MaxBit, 0)
+ mul.x.Lsh(mul.x, 1)
+ mul.x.Xor(mul.x, R64)
+ } else {
+ mul.x.Lsh(mul.x, 1)
+ }
+ mul.y.Rsh(mul.y, 1)
+ }
+ zBytes := mul.z.Bytes()
+ rem := len(x) - len(zBytes)
+ for i := 0; i < rem; i++ {
+ mul.buf[i] = 0
+ }
+ copy(mul.buf[rem:], zBytes)
+ return mul.buf[:]
+}
package mgm
-func (mgm *MGM) mul(xBuf, yBuf []byte) []byte {
- mgm.x.SetBytes(xBuf)
- mgm.y.SetBytes(yBuf)
- mgm.z.SetInt64(0)
- for mgm.y.BitLen() != 0 {
- if mgm.y.Bit(0) == 1 {
- mgm.z.Xor(mgm.z, mgm.x)
- }
- if mgm.x.Bit(mgm.maxBit) == 1 {
- mgm.x.SetBit(mgm.x, mgm.maxBit, 0)
- mgm.x.Lsh(mgm.x, 1)
- mgm.x.Xor(mgm.x, mgm.r)
- } else {
- mgm.x.Lsh(mgm.x, 1)
- }
- mgm.y.Rsh(mgm.y, 1)
- }
- zBytes := mgm.z.Bytes()
- rem := len(xBuf) - len(zBytes)
- for i := 0; i < rem; i++ {
- mgm.mulBuf[i] = 0
+import (
+ "crypto/rand"
+ "testing"
+
+ "go.cypherpunks.ru/gogost/v5/gost341264"
+)
+
+func BenchmarkMul64(b *testing.B) {
+ x := make([]byte, gost341264.BlockSize)
+ y := make([]byte, gost341264.BlockSize)
+ rand.Read(x)
+ rand.Read(y)
+ mul := newMul64()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ mul.Mul(x, y)
}
- copy(mgm.mulBuf[rem:], zBytes)
- return mgm.mulBuf
}