From 813686fde57c4bdbc1dc4092b7beee06af841712 Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Fri, 8 Oct 2021 14:02:56 +0300 Subject: [PATCH] Optimized Kuznechik --- gost3412128/cipher.go | 191 +++++++++++++++++++------------------ gost3412128/cipher_test.go | 16 ++-- gost3412128/xor_safe.go | 23 +++++ gost3412128/xor_words.go | 21 ++++ 4 files changed, 152 insertions(+), 99 deletions(-) create mode 100644 gost3412128/xor_safe.go create mode 100644 gost3412128/xor_words.go diff --git a/gost3412128/cipher.go b/gost3412128/cipher.go index cbc2b3e..dc33fec 100644 --- a/gost3412128/cipher.go +++ b/gost3412128/cipher.go @@ -52,7 +52,7 @@ var ( 192, 209, 102, 175, 194, 57, 75, 99, 182, } piInv [256]byte - cBlk [32][]byte + cBlk [32]*[BlockSize]byte gfCache [256][256]byte ) @@ -71,33 +71,62 @@ func gf(a, b byte) (c byte) { return } -func l(blk []byte) { +func l(blk *[BlockSize]byte) { for n := 0; n < BlockSize; n++ { - t := blk[15] - t ^= gfCache[blk[0]][lc[0]] - t ^= gfCache[blk[1]][lc[1]] - t ^= gfCache[blk[2]][lc[2]] - t ^= gfCache[blk[3]][lc[3]] - t ^= gfCache[blk[4]][lc[4]] - t ^= gfCache[blk[5]][lc[5]] - t ^= gfCache[blk[6]][lc[6]] - t ^= gfCache[blk[7]][lc[7]] - t ^= gfCache[blk[8]][lc[8]] - t ^= gfCache[blk[9]][lc[9]] - t ^= gfCache[blk[10]][lc[10]] - t ^= gfCache[blk[11]][lc[11]] - t ^= gfCache[blk[12]][lc[12]] - t ^= gfCache[blk[13]][lc[13]] - t ^= gfCache[blk[14]][lc[14]] - copy(blk[1:], blk) - blk[0] = t + blk[0], + blk[1], + blk[2], + blk[3], + blk[4], + blk[5], + blk[6], + blk[7], + blk[8], + blk[9], + blk[10], + blk[11], + blk[12], + blk[13], + blk[14], + blk[15] = (blk[15] ^ + gfCache[blk[0]][lc[0]] ^ + gfCache[blk[1]][lc[1]] ^ + gfCache[blk[2]][lc[2]] ^ + gfCache[blk[3]][lc[3]] ^ + gfCache[blk[4]][lc[4]] ^ + gfCache[blk[5]][lc[5]] ^ + gfCache[blk[6]][lc[6]] ^ + gfCache[blk[7]][lc[7]] ^ + gfCache[blk[8]][lc[8]] ^ + gfCache[blk[9]][lc[9]] ^ + gfCache[blk[10]][lc[10]] ^ + gfCache[blk[11]][lc[11]] ^ + gfCache[blk[12]][lc[12]] ^ + gfCache[blk[13]][lc[13]] ^ + gfCache[blk[14]][lc[14]]), + blk[0], + blk[1], + blk[2], + blk[3], + blk[4], + blk[5], + blk[6], + blk[7], + blk[8], + blk[9], + blk[10], + blk[11], + blk[12], + blk[13], + blk[14] } } -func lInv(blk []byte) { +func lInv(blk *[BlockSize]byte) { + var t byte for n := 0; n < BlockSize; n++ { - t := blk[0] - copy(blk, blk[1:]) + t = blk[0] + copy(blk[:], blk[1:]) t ^= gfCache[blk[0]][lc[0]] t ^= gfCache[blk[1]][lc[1]] t ^= gfCache[blk[2]][lc[2]] @@ -117,23 +146,7 @@ func lInv(blk []byte) { } } -func init() { - for a := 0; a < 256; a++ { - for b := 0; b < 256; b++ { - gfCache[a][b] = gf(byte(a), byte(b)) - } - } - for i := 0; i < 256; i++ { - piInv[int(pi[i])] = byte(i) - } - for i := 0; i < 32; i++ { - cBlk[i] = make([]byte, BlockSize) - cBlk[i][15] = byte(i) + 1 - l(cBlk[i]) - } -} - -func s(blk []byte) { +func s(blk *[BlockSize]byte) { blk[0] = pi[int(blk[0])] blk[1] = pi[int(blk[1])] blk[2] = pi[int(blk[2])] @@ -152,27 +165,30 @@ func s(blk []byte) { blk[15] = pi[int(blk[15])] } -func xor(dst, src1, src2 []byte) { - dst[0] = src1[0] ^ src2[0] - dst[1] = src1[1] ^ src2[1] - dst[2] = src1[2] ^ src2[2] - dst[3] = src1[3] ^ src2[3] - dst[4] = src1[4] ^ src2[4] - dst[5] = src1[5] ^ src2[5] - dst[6] = src1[6] ^ src2[6] - dst[7] = src1[7] ^ src2[7] - dst[8] = src1[8] ^ src2[8] - dst[9] = src1[9] ^ src2[9] - dst[10] = src1[10] ^ src2[10] - dst[11] = src1[11] ^ src2[11] - dst[12] = src1[12] ^ src2[12] - dst[13] = src1[13] ^ src2[13] - dst[14] = src1[14] ^ src2[14] - dst[15] = src1[15] ^ src2[15] +func sInv(blk *[BlockSize]byte) { + for n := 0; n < BlockSize; n++ { + blk[n] = piInv[int(blk[n])] + } +} + +func init() { + for a := 0; a < 256; a++ { + for b := 0; b < 256; b++ { + gfCache[a][b] = gf(byte(a), byte(b)) + } + } + for i := 0; i < 256; i++ { + piInv[int(pi[i])] = byte(i) + } + for i := 0; i < 32; i++ { + cBlk[i] = new([BlockSize]byte) + cBlk[i][15] = byte(i) + 1 + l(cBlk[i]) + } } type Cipher struct { - ks [10][]byte + ks [10][BlockSize]byte } func (c *Cipher) BlockSize() int { @@ -183,55 +199,48 @@ func NewCipher(key []byte) *Cipher { if len(key) != KeySize { panic("invalid key size") } - var ks [10][]byte - for i := 0; i < len(ks); i++ { - ks[i] = make([]byte, BlockSize) - } - kr0 := make([]byte, BlockSize) - kr1 := make([]byte, BlockSize) - krt := make([]byte, BlockSize) - copy(kr0, key[:BlockSize]) - copy(kr1, key[BlockSize:]) - copy(ks[0], kr0) - copy(ks[1], kr1) + var ks [10][BlockSize]byte + var kr0 [BlockSize]byte + var kr1 [BlockSize]byte + var krt [BlockSize]byte + copy(kr0[:], key[:BlockSize]) + copy(kr1[:], key[BlockSize:]) + copy(ks[0][:], kr0[:]) + copy(ks[1][:], kr1[:]) for i := 0; i < 4; i++ { for j := 0; j < 8; j++ { - xor(krt, kr0, cBlk[8*i+j]) - s(krt) - l(krt) - xor(krt, krt, kr1) - copy(kr1, kr0) - copy(kr0, krt) + xor(krt[:], kr0[:], cBlk[8*i+j][:]) + s(&krt) + l(&krt) + xor(krt[:], krt[:], kr1[:]) + copy(kr1[:], kr0[:]) + copy(kr0[:], krt[:]) } - copy(ks[2+2*i], kr0) - copy(ks[2+2*i+1], kr1) + copy(ks[2+2*i][:], kr0[:]) + copy(ks[2+2*i+1][:], kr1[:]) } return &Cipher{ks} } func (c *Cipher) Encrypt(dst, src []byte) { - blk := make([]byte, BlockSize) - copy(blk, src) + blk := new([BlockSize]byte) + copy(blk[:], src) for i := 0; i < 9; i++ { - xor(blk, blk, c.ks[i]) + xor(blk[:], blk[:], c.ks[i][:]) s(blk) l(blk) } - xor(blk, blk, c.ks[9]) - copy(dst[:BlockSize], blk) + xor(blk[:], blk[:], c.ks[9][:]) + copy(dst, blk[:]) } func (c *Cipher) Decrypt(dst, src []byte) { - blk := make([]byte, BlockSize) - copy(blk, src) - var n int + blk := new([BlockSize]byte) + copy(blk[:], src) for i := 9; i > 0; i-- { - xor(blk, blk, c.ks[i]) + xor(blk[:], blk[:], c.ks[i][:]) lInv(blk) - for n = 0; n < BlockSize; n++ { - blk[n] = piInv[int(blk[n])] - } + sInv(blk) } - xor(blk, blk, c.ks[0]) - copy(dst[:BlockSize], blk) + xor(dst, blk[:], c.ks[0][:]) } diff --git a/gost3412128/cipher_test.go b/gost3412128/cipher_test.go index f25b6d3..08eabb8 100644 --- a/gost3412128/cipher_test.go +++ b/gost3412128/cipher_test.go @@ -86,28 +86,28 @@ func TestS(t *testing.T) { 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x00, } - s(blk[:]) + s(&blk) if bytes.Compare(blk[:], []byte{ 0xb6, 0x6c, 0xd8, 0x88, 0x7d, 0x38, 0xe8, 0xd7, 0x77, 0x65, 0xae, 0xea, 0x0c, 0x9a, 0x7e, 0xfc, }) != 0 { t.FailNow() } - s(blk[:]) + s(&blk) if bytes.Compare(blk[:], []byte{ 0x55, 0x9d, 0x8d, 0xd7, 0xbd, 0x06, 0xcb, 0xfe, 0x7e, 0x7b, 0x26, 0x25, 0x23, 0x28, 0x0d, 0x39, }) != 0 { t.FailNow() } - s(blk[:]) + s(&blk) if bytes.Compare(blk[:], []byte{ 0x0c, 0x33, 0x22, 0xfe, 0xd5, 0x31, 0xe4, 0x63, 0x0d, 0x80, 0xef, 0x5c, 0x5a, 0x81, 0xc5, 0x0b, }) != 0 { t.FailNow() } - s(blk[:]) + s(&blk) if bytes.Compare(blk[:], []byte{ 0x23, 0xae, 0x65, 0x63, 0x3f, 0x84, 0x2d, 0x29, 0xc5, 0xdf, 0x52, 0x9c, 0x13, 0xf5, 0xac, 0xda, @@ -165,28 +165,28 @@ func TestL(t *testing.T) { 0x64, 0xa5, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, } - l(blk[:]) + l(&blk) if bytes.Compare(blk[:], []byte{ 0xd4, 0x56, 0x58, 0x4d, 0xd0, 0xe3, 0xe8, 0x4c, 0xc3, 0x16, 0x6e, 0x4b, 0x7f, 0xa2, 0x89, 0x0d, }) != 0 { t.FailNow() } - l(blk[:]) + l(&blk) if bytes.Compare(blk[:], []byte{ 0x79, 0xd2, 0x62, 0x21, 0xb8, 0x7b, 0x58, 0x4c, 0xd4, 0x2f, 0xbc, 0x4f, 0xfe, 0xa5, 0xde, 0x9a, }) != 0 { t.FailNow() } - l(blk[:]) + l(&blk) if bytes.Compare(blk[:], []byte{ 0x0e, 0x93, 0x69, 0x1a, 0x0c, 0xfc, 0x60, 0x40, 0x8b, 0x7b, 0x68, 0xf6, 0x6b, 0x51, 0x3c, 0x13, }) != 0 { t.FailNow() } - l(blk[:]) + l(&blk) if bytes.Compare(blk[:], []byte{ 0xe6, 0xa8, 0x09, 0x4f, 0xee, 0x0a, 0xa2, 0x04, 0xfd, 0x97, 0xbc, 0xb0, 0xb4, 0x4b, 0x85, 0x80, diff --git a/gost3412128/xor_safe.go b/gost3412128/xor_safe.go new file mode 100644 index 0000000..eaa1ad1 --- /dev/null +++ b/gost3412128/xor_safe.go @@ -0,0 +1,23 @@ +//go:build !amd64 && !386 && !ppc64 && !ppc64le && !s390x +// +build !amd64,!386,!ppc64,!ppc64le,!s390x + +package gost3412128 + +func xor(dst, src1, src2 []byte) { + dst[0] = src1[0] ^ src2[0] + dst[1] = src1[1] ^ src2[1] + dst[2] = src1[2] ^ src2[2] + dst[3] = src1[3] ^ src2[3] + dst[4] = src1[4] ^ src2[4] + dst[5] = src1[5] ^ src2[5] + dst[6] = src1[6] ^ src2[6] + dst[7] = src1[7] ^ src2[7] + dst[8] = src1[8] ^ src2[8] + dst[9] = src1[9] ^ src2[9] + dst[10] = src1[10] ^ src2[10] + dst[11] = src1[11] ^ src2[11] + dst[12] = src1[12] ^ src2[12] + dst[13] = src1[13] ^ src2[13] + dst[14] = src1[14] ^ src2[14] + dst[15] = src1[15] ^ src2[15] +} diff --git a/gost3412128/xor_words.go b/gost3412128/xor_words.go new file mode 100644 index 0000000..36582c3 --- /dev/null +++ b/gost3412128/xor_words.go @@ -0,0 +1,21 @@ +//go:build amd64 || 386 || ppc64 || ppc64le || s390x +// +build amd64 386 ppc64 ppc64le s390x + +// Fast XOR taken from native crypto/cipher + +package gost3412128 + +import ( + "unsafe" +) + +const xorWords = BlockSize / int(unsafe.Sizeof(uintptr(0))) + +func xor(dst, a, b []byte) { + dw := *(*[]uintptr)(unsafe.Pointer(&dst)) + aw := *(*[]uintptr)(unsafe.Pointer(&a)) + bw := *(*[]uintptr)(unsafe.Pointer(&b)) + for i := 0; i < xorWords; i++ { + dw[i] = aw[i] ^ bw[i] + } +} -- 2.44.0