From: Sergey Matveev Date: Fri, 8 Oct 2021 09:38:10 +0000 (+0300) Subject: Separate GF^64 and GF^128 multiplier implementations X-Git-Tag: v5.8.0~3 X-Git-Url: http://www.git.cypherpunks.ru/?p=gogost.git;a=commitdiff_plain;h=7e8907d3f9c6eeec0a49e563923cb0aab0e9aeac Separate GF^64 and GF^128 multiplier implementations --- diff --git a/mgm/mode.go b/mgm/mode.go index c281567..38b9ab3 100644 --- a/mgm/mode.go +++ b/mgm/mode.go @@ -21,22 +21,10 @@ import ( "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 { @@ -49,13 +37,7 @@ 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) { @@ -76,17 +58,11 @@ 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 } @@ -148,7 +124,7 @@ func (mgm *MGM) auth(out, text, ad []byte) { 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:] @@ -159,7 +135,7 @@ func (mgm *MGM) auth(out, text, ad []byte) { 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]) } @@ -168,7 +144,7 @@ func (mgm *MGM) auth(out, text, ad []byte) { 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:] @@ -179,7 +155,7 @@ func (mgm *MGM) auth(out, text, ad []byte) { 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]) } @@ -193,7 +169,7 @@ func (mgm *MGM) auth(out, text, ad []byte) { 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)) } diff --git a/mgm/mode_test.go b/mgm/mode_test.go index 7d1d984..984ea48 100644 --- a/mgm/mode_test.go +++ b/mgm/mode_test.go @@ -19,6 +19,7 @@ import ( "bytes" "crypto/cipher" "crypto/rand" + "io" "testing" "testing/quick" @@ -145,3 +146,55 @@ func TestSymmetric(t *testing.T) { 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) + } +} diff --git a/mgm/mul128.go b/mgm/mul128.go new file mode 100644 index 0000000..07f105b --- /dev/null +++ b/mgm/mul128.go @@ -0,0 +1,68 @@ +// GoGOST -- Pure Go GOST cryptographic functions library +// Copyright (C) 2015-2021 Sergey Matveev +// +// 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 . + +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[:] +} diff --git a/mgm/mul_test.go b/mgm/mul128_test.go similarity index 62% rename from mgm/mul_test.go rename to mgm/mul128_test.go index b585799..0654880 100644 --- a/mgm/mul_test.go +++ b/mgm/mul128_test.go @@ -17,47 +17,19 @@ package mgm 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) } } diff --git a/mgm/mul64.go b/mgm/mul64.go new file mode 100644 index 0000000..4d3ccd0 --- /dev/null +++ b/mgm/mul64.go @@ -0,0 +1,65 @@ +// GoGOST -- Pure Go GOST cryptographic functions library +// Copyright (C) 2015-2021 Sergey Matveev +// +// 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 . + +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[:] +} diff --git a/mgm/mul.go b/mgm/mul64_test.go similarity index 58% rename from mgm/mul.go rename to mgm/mul64_test.go index 8fec466..43411cd 100644 --- a/mgm/mul.go +++ b/mgm/mul64_test.go @@ -15,28 +15,21 @@ 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 }