Merge pull request #18 from nspcc-dev/feat/interface

Restructure code layout in gf127/
This commit is contained in:
fyrchik 2019-10-15 14:19:13 +03:00 committed by GitHub
commit 702d2553ba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 216 additions and 392 deletions

View file

@ -3,22 +3,10 @@
// Package gf127 implements the GF(2^127) arithmetic // Package gf127 implements the GF(2^127) arithmetic
// modulo reduction polynomial x^127 + x^63 + 1 . // modulo reduction polynomial x^127 + x^63 + 1 .
// Implementation is in pure Go. // Implementation is in pure Go.
package gogf127 package gf127
import ( import (
"encoding/binary"
"encoding/hex"
"errors"
"math/bits" "math/bits"
"math/rand"
)
// GF127 represents element of GF(2^127)
type GF127 [2]uint64
const (
msb64 = uint64(0x8000000000000000)
byteSize = 16
) )
var ( var (
@ -32,50 +20,6 @@ func New(lo, hi uint64) *GF127 {
return &GF127{lo, hi} return &GF127{lo, hi}
} }
// Random returns random element from GF(2^127).
// Is used mostly for testing.
func Random() *GF127 {
return &GF127{rand.Uint64(), rand.Uint64() >> 1}
}
// String returns hex-encoded representation, starting with MSB.
func (c *GF127) String() string {
return hex.EncodeToString(c.ByteArray())
}
// Equals checks if two reduced (zero MSB) elements of GF(2^127) are equal
func (c *GF127) Equals(b *GF127) bool {
return c[0] == b[0] && c[1] == b[1]
}
// ByteArray represents element of GF(2^127) as byte array of length 16.
func (c *GF127) ByteArray() (buf []byte) {
buf = make([]byte, 16)
binary.BigEndian.PutUint64(buf[:8], c[1])
binary.BigEndian.PutUint64(buf[8:], c[0])
return
}
// MarshalBinary implements encoding.BinaryMarshaler.
func (c *GF127) MarshalBinary() (data []byte, err error) {
return c.ByteArray(), nil
}
// UnmarshalBinary implements encoding.BinaryUnmarshaler.
func (c *GF127) UnmarshalBinary(data []byte) error {
if len(data) != byteSize {
return errors.New("data must be 16-bytes long")
}
c[0] = binary.BigEndian.Uint64(data[8:])
c[1] = binary.BigEndian.Uint64(data[:8])
if c[1]&msb64 != 0 {
return errors.New("MSB must be zero")
}
return nil
}
// Inv sets b to a^-1 // Inv sets b to a^-1
// Algorithm is based on Extended Euclidean Algorithm // Algorithm is based on Extended Euclidean Algorithm
// and is described by Hankerson, Hernandez, Menezes in // and is described by Hankerson, Hernandez, Menezes in
@ -129,18 +73,6 @@ func msb(a *GF127) (x int) {
return 127 - x return 127 - x
} }
// Mul sets c to the product a*b and returns c.
func (c *GF127) Mul(a, b *GF127) *GF127 {
Mul(a, b, c)
return c
}
// Add sets c to the sum a+b and returns c.
func (c *GF127) Add(a, b *GF127) *GF127 {
Add(a, b, c)
return c
}
// Mul1 copies a to b. // Mul1 copies a to b.
func Mul1(a, b *GF127) { func Mul1(a, b *GF127) {
b[0] = a[0] b[0] = a[0]

View file

@ -1,4 +1,4 @@
package gogf127 package gf127
import ( import (
"testing" "testing"
@ -6,8 +6,6 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
const maxUint64 = ^uint64(0)
func TestAdd(t *testing.T) { func TestAdd(t *testing.T) {
var ( var (
a = Random() a = Random()

34
gf127/avx/gf127.go Normal file
View file

@ -0,0 +1,34 @@
// Copyright 2018 (c) NSPCC
//
// Package gf127 implements the GF(2^127) arithmetic
// modulo reduction polynomial x^127 + x^63 + 1 .
// This is rather straight-forward re-implementation of C library
// available here https://github.com/srijs/hwsl2-core .
// Interfaces are highly influenced by math/big .
package avx
import (
"github.com/nspcc-dev/tzhash/gf127"
)
// GF127 is an alias for a main type.
type GF127 = gf127.GF127
const msb64 = uint64(1) << 63
var (
// x127x63 represents x^127 + x^63. Used in assembly file.
x127x63 = GF127{msb64, msb64}
)
// Add sets c to a+b.
func Add(a, b, c *GF127)
// Mul sets c to a*b.
func Mul(a, b, c *GF127)
// Mul10 sets b to a*x.
func Mul10(a, b *GF127)
// Mul11 sets b to a*(x+1).
func Mul11(a, b *GF127)

View file

@ -27,22 +27,6 @@ TEXT ·Mul10(SB),NOSPLIT,$0
MOVUPD X1, (AX) MOVUPD X1, (AX)
RET RET
// func Mul10x2(a, b) *[4]uint64
TEXT ·Mul10x2(SB),NOSPLIT,$0
MOVQ a+0(FP), AX
VMOVDQA (AX), Y0
VPSLLQ $1, Y0, Y1
VPALIGNR $8, Y1, Y0, Y2
VPSRLQ $63, Y2, Y2
VPXOR Y1, Y2, Y2
VPSRLQ $63, Y1, Y3
VPSLLQ $63, Y3, Y3
VPUNPCKHQDQ Y3, Y3, Y3
VPXOR Y2, Y3, Y3
MOVQ b+8(FP), AX
VMOVDQA Y3, (AX)
RET
// func Mul11(a, b *[2]uint64) // func Mul11(a, b *[2]uint64)
TEXT ·Mul11(SB),NOSPLIT,$0 TEXT ·Mul11(SB),NOSPLIT,$0
MOVQ a+0(FP), AX MOVQ a+0(FP), AX
@ -60,23 +44,6 @@ TEXT ·Mul11(SB),NOSPLIT,$0
MOVUPD X1, (AX) MOVUPD X1, (AX)
RET RET
// func Mul11x2(a, b) *[4]uint64
TEXT ·Mul11x2(SB),NOSPLIT,$0
MOVQ a+0(FP), AX
VMOVDQA (AX), Y0
VPSLLQ $1, Y0, Y1
VPALIGNR $8, Y1, Y0, Y2
VPSRLQ $63, Y2, Y2
VPXOR Y1, Y2, Y2
VPSRLQ $63, Y1, Y3
VPSLLQ $63, Y3, Y3
VPUNPCKHQDQ Y3, Y3, Y3
VPXOR Y2, Y3, Y3
VPXOR Y0, Y3, Y3
MOVQ b+8(FP), AX
VMOVDQA Y3, (AX)
RET
// func Mul(a, b, c *[2]uint64) // func Mul(a, b, c *[2]uint64)
TEXT ·Mul(SB),NOSPLIT,$0 TEXT ·Mul(SB),NOSPLIT,$0
MOVQ a+0(FP), AX // X0 = a0 . a1 MOVQ a+0(FP), AX // X0 = a0 . a1

View file

@ -1,8 +1,9 @@
package gf127 package avx
import ( import (
"testing" "testing"
"github.com/nspcc-dev/tzhash/gf127"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -10,12 +11,12 @@ const maxUint64 = ^uint64(0)
func TestAdd(t *testing.T) { func TestAdd(t *testing.T) {
var ( var (
a = Random() a = gf127.Random()
b = Random() b = gf127.Random()
e = &GF127{a[0] ^ b[0], a[1] ^ b[1]} e = &GF127{a[0] ^ b[0], a[1] ^ b[1]}
c = new(GF127) c = new(GF127)
) )
c.Add(a, b) Add(a, b, c)
require.Equal(t, e, c) require.Equal(t, e, c)
} }
@ -65,46 +66,3 @@ func TestMul11(t *testing.T) {
require.Equal(t, tc[1], c) require.Equal(t, tc[1], c)
} }
} }
var testCasesInv = [][2]*GF127{
{&GF127{1, 0}, &GF127{1, 0}},
{&GF127{3, 0}, &GF127{msb64, ^msb64}},
{&GF127{54321, 12345}, &GF127{8230555108620784737, 3929873967650665114}},
}
func TestInv(t *testing.T) {
var a, b, c = new(GF127), new(GF127), new(GF127)
for _, tc := range testCasesInv {
Inv(tc[0], c)
require.Equal(t, tc[1], c)
}
for i := 0; i < 3; i++ {
// 0 has no inverse
if a = Random(); a.Equals(&GF127{0, 0}) {
continue
}
Inv(a, b)
Mul(a, b, c)
require.Equal(t, &GF127{1, 0}, c)
}
}
func TestGF127_MarshalBinary(t *testing.T) {
a := New(0xFF, 0xEE)
data, err := a.MarshalBinary()
require.NoError(t, err)
require.Equal(t, data, []byte{0, 0, 0, 0, 0, 0, 0, 0xEE, 0, 0, 0, 0, 0, 0, 0, 0xFF})
a = Random()
data, err = a.MarshalBinary()
require.NoError(t, err)
b := new(GF127)
err = b.UnmarshalBinary(data)
require.NoError(t, err)
require.Equal(t, a, b)
err = b.UnmarshalBinary([]byte{0, 1, 2, 3})
require.Error(t, err)
}

View file

@ -1,10 +1,15 @@
package gf127 package avx2
import ( import (
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
"github.com/nspcc-dev/tzhash/gf127"
) )
// GF127 is an alias for a main type.
type GF127 = gf127.GF127
// GF127x2 represents a pair of elements of GF(2^127) stored together. // GF127x2 represents a pair of elements of GF(2^127) stored together.
type GF127x2 [2]GF127 type GF127x2 [2]GF127

View file

@ -0,0 +1,35 @@
#include "textflag.h"
// func Mul10x2(a, b) *[4]uint64
TEXT ·Mul10x2(SB),NOSPLIT,$0
MOVQ a+0(FP), AX
VMOVDQA (AX), Y0
VPSLLQ $1, Y0, Y1
VPALIGNR $8, Y1, Y0, Y2
VPSRLQ $63, Y2, Y2
VPXOR Y1, Y2, Y2
VPSRLQ $63, Y1, Y3
VPSLLQ $63, Y3, Y3
VPUNPCKHQDQ Y3, Y3, Y3
VPXOR Y2, Y3, Y3
MOVQ b+8(FP), AX
VMOVDQA Y3, (AX)
RET
// func Mul11x2(a, b) *[4]uint64
TEXT ·Mul11x2(SB),NOSPLIT,$0
MOVQ a+0(FP), AX
VMOVDQA (AX), Y0
VPSLLQ $1, Y0, Y1
VPALIGNR $8, Y1, Y0, Y2
VPSRLQ $63, Y2, Y2
VPXOR Y1, Y2, Y2
VPSRLQ $63, Y1, Y3
VPSLLQ $63, Y3, Y3
VPUNPCKHQDQ Y3, Y3, Y3
VPXOR Y2, Y3, Y3
VPXOR Y0, Y3, Y3
MOVQ b+8(FP), AX
VMOVDQA Y3, (AX)
RET

View file

@ -1,4 +1,4 @@
package gf127 package avx2
import ( import (
"testing" "testing"
@ -6,6 +6,8 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
const maxUint64 = ^uint64(0)
var testCasesSplit = []struct { var testCasesSplit = []struct {
num *GF127x2 num *GF127x2
h1 *GF127 h1 *GF127

View file

@ -1,42 +1,21 @@
// Copyright 2018 (c) NSPCC
//
// Package gf127 implements the GF(2^127) arithmetic
// modulo reduction polynomial x^127 + x^63 + 1 .
// This is rather straight-forward re-implementation of C library
// available here https://github.com/srijs/hwsl2-core .
// Interfaces are highly influenced by math/big .
package gf127 package gf127
import ( import (
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
"errors" "errors"
"math/bits"
"math/rand" "math/rand"
) )
const (
byteSize = 16
maxUint64 = ^uint64(0)
msb64 = uint64(1) << 63
)
// GF127 represents element of GF(2^127) // GF127 represents element of GF(2^127)
type GF127 [2]uint64 type GF127 [2]uint64
const (
msb64 = uint64(0x8000000000000000)
byteSize = 16
)
var (
// x127x63 represents x^127 + x^63. Used in assembly file.
x127x63 = GF127{msb64, msb64}
// x126x631 is reduction polynomial x^127+x^63+1
x127x631 = GF127{msb64 + 1, msb64}
)
// New constructs new element of GF(2^127) as hi*x^64 + lo.
// It is assumed that hi has zero MSB.
func New(lo, hi uint64) *GF127 {
return &GF127{lo, hi}
}
// Random returns random element from GF(2^127). // Random returns random element from GF(2^127).
// Is used mostly for testing. // Is used mostly for testing.
func Random() *GF127 { func Random() *GF127 {
@ -80,92 +59,3 @@ func (c *GF127) UnmarshalBinary(data []byte) error {
return nil return nil
} }
// Inv sets b to a^-1
// Algorithm is based on Extended Euclidean Algorithm
// and is described by Hankerson, Hernandez, Menezes in
// https://link.springer.com/content/pdf/10.1007/3-540-44499-8_1.pdf
func Inv(a, b *GF127) {
var (
v = x127x631
u = *a
c, d = &GF127{1, 0}, &GF127{0, 0}
t = new(GF127)
x *GF127
)
// degree of polynomial is a position of most significant bit
for du, dv := msb(&u), msb(&v); du != 0; du, dv = msb(&u), msb(&v) {
if du < dv {
v, u = u, v
dv, du = du, dv
d, c = c, d
}
x = xN(du - dv)
Mul(x, &v, t)
Add(&u, t, &u)
// becasuse mul performs reduction on t, we need
// manually reduce u at first step
if msb(&u) == 127 {
Add(&u, &x127x631, &u)
}
Mul(x, d, t)
Add(c, t, c)
}
*b = *c
}
func xN(n int) *GF127 {
if n < 64 {
return &GF127{1 << uint(n), 0}
}
return &GF127{0, 1 << uint(n-64)}
}
func msb(a *GF127) (x int) {
x = bits.LeadingZeros64(a[1])
if x == 64 {
x = bits.LeadingZeros64(a[0]) + 64
}
return 127 - x
}
// Mul sets c to the product a*b and returns c.
func (c *GF127) Mul(a, b *GF127) *GF127 {
Mul(a, b, c)
return c
}
// Add sets c to the sum a+b and returns c.
func (c *GF127) Add(a, b *GF127) *GF127 {
Add(a, b, c)
return c
}
// Mul1 copies a to b.
func Mul1(a, b *GF127) {
b[0] = a[0]
b[1] = a[1]
}
// And sets c to a & b (bitwise-and).
func And(a, b, c *GF127) {
c[0] = a[0] & b[0]
c[1] = a[1] & b[1]
}
// Add sets c to a+b.
func Add(a, b, c *GF127)
// Mul sets c to a*b.
func Mul(a, b, c *GF127)
// Mul10 sets b to a*x.
func Mul10(a, b *GF127)
// Mul11 sets b to a*(x+1).
func Mul11(a, b *GF127)

View file

@ -6,20 +6,18 @@ package tz
import ( import (
"hash" "hash"
"math" "math"
"github.com/nspcc-dev/tzhash/gf127"
) )
type digest struct { type digest struct {
x [4]gf127.GF127 x [4]GF127
} }
// type assertion // type assertion
var _ hash.Hash = (*digest)(nil) var _ hash.Hash = (*digest)(nil)
var ( var (
minmax = [2]gf127.GF127{{0, 0}, {math.MaxUint64, math.MaxUint64}} minmax = [2]GF127{{0, 0}, {math.MaxUint64, math.MaxUint64}}
x127x63 = gf127.GF127{1 << 63, 1 << 63} x127x63 = GF127{1 << 63, 1 << 63}
) )
func newAVX() *digest { func newAVX() *digest {
@ -48,10 +46,10 @@ func (d *digest) byteArray() (b [hashSize]byte) {
} }
func (d *digest) Reset() { func (d *digest) Reset() {
d.x[0] = gf127.GF127{1, 0} d.x[0] = GF127{1, 0}
d.x[1] = gf127.GF127{0, 0} d.x[1] = GF127{0, 0}
d.x[2] = gf127.GF127{0, 0} d.x[2] = GF127{0, 0}
d.x[3] = gf127.GF127{1, 0} d.x[3] = GF127{1, 0}
} }
func (d *digest) Write(data []byte) (n int, err error) { func (d *digest) Write(data []byte) (n int, err error) {
@ -77,4 +75,4 @@ func (d *digest) BlockSize() int {
return hashBlockSize return hashBlockSize
} }
func mulBitRight(c00, c01, c10, c11, e *gf127.GF127) func mulBitRight(c00, c01, c10, c11, e *GF127)

View file

@ -6,11 +6,11 @@ package tz
import ( import (
"hash" "hash"
"github.com/nspcc-dev/tzhash/gf127" "github.com/nspcc-dev/tzhash/gf127/avx2"
) )
type digest2 struct { type digest2 struct {
x [2]gf127.GF127x2 x [2]avx2.GF127x2
} }
// type assertion // type assertion
@ -44,8 +44,8 @@ func (d *digest2) Sum(in []byte) []byte {
return append(in, h[:]...) return append(in, h[:]...)
} }
func (d *digest2) Reset() { func (d *digest2) Reset() {
d.x[0] = gf127.GF127x2{gf127.GF127{1, 0}, gf127.GF127{0, 0}} d.x[0] = avx2.GF127x2{GF127{1, 0}, GF127{0, 0}}
d.x[1] = gf127.GF127x2{gf127.GF127{0, 0}, gf127.GF127{1, 0}} d.x[1] = avx2.GF127x2{GF127{0, 0}, GF127{1, 0}}
} }
func (d *digest2) Size() int { return hashSize } func (d *digest2) Size() int { return hashSize }
func (d *digest2) BlockSize() int { return hashBlockSize } func (d *digest2) BlockSize() int { return hashBlockSize }
@ -62,4 +62,4 @@ func (d *digest2) checkSum() (b [hashSize]byte) {
return return
} }
func mulBitRightx2(c00c10 *gf127.GF127x2, c01c11 *gf127.GF127x2, e *gf127.GF127) func mulBitRightx2(c00c10 *avx2.GF127x2, c01c11 *avx2.GF127x2, e *GF127)

View file

@ -7,11 +7,11 @@ package tz
import ( import (
"hash" "hash"
"github.com/nspcc-dev/tzhash/gf127" "github.com/nspcc-dev/tzhash/gf127/avx2"
) )
type digest3 struct { type digest3 struct {
x [2]gf127.GF127x2 x [2]avx2.GF127x2
} }
// type assertion // type assertion
@ -38,8 +38,8 @@ func (d *digest3) Sum(in []byte) []byte {
return append(in, h[:]...) return append(in, h[:]...)
} }
func (d *digest3) Reset() { func (d *digest3) Reset() {
d.x[0] = gf127.GF127x2{gf127.GF127{1, 0}, gf127.GF127{0, 0}} d.x[0] = avx2.GF127x2{GF127{1, 0}, GF127{0, 0}}
d.x[1] = gf127.GF127x2{gf127.GF127{0, 0}, gf127.GF127{1, 0}} d.x[1] = avx2.GF127x2{GF127{0, 0}, GF127{1, 0}}
} }
func (d *digest3) Size() int { return hashSize } func (d *digest3) Size() int { return hashSize }
func (d *digest3) BlockSize() int { return hashBlockSize } func (d *digest3) BlockSize() int { return hashBlockSize }
@ -56,4 +56,4 @@ func (d *digest3) checkSum() (b [hashSize]byte) {
return return
} }
func mulByteRightx2(c00c10 *gf127.GF127x2, c01c11 *gf127.GF127x2, b byte) func mulByteRightx2(c00c10 *avx2.GF127x2, c01c11 *avx2.GF127x2, b byte)

View file

@ -1,11 +1,11 @@
package tz package tz
import ( import (
"github.com/nspcc-dev/tzhash/gogf127" "github.com/nspcc-dev/tzhash/gf127"
) )
type digestp struct { type digestp struct {
x [4]gogf127.GF127 x [4]GF127
} }
// New returns a new hash.Hash computing the Tillich-Zémor checksum. // New returns a new hash.Hash computing the Tillich-Zémor checksum.
@ -35,15 +35,15 @@ func (d *digestp) byteArray() (b [hashSize]byte) {
} }
func (d *digestp) Reset() { func (d *digestp) Reset() {
d.x[0] = gogf127.GF127{1, 0} d.x[0] = GF127{1, 0}
d.x[1] = gogf127.GF127{0, 0} d.x[1] = GF127{0, 0}
d.x[2] = gogf127.GF127{0, 0} d.x[2] = GF127{0, 0}
d.x[3] = gogf127.GF127{1, 0} d.x[3] = GF127{1, 0}
} }
func (d *digestp) Write(data []byte) (n int, err error) { func (d *digestp) Write(data []byte) (n int, err error) {
n = len(data) n = len(data)
tmp := new(gogf127.GF127) tmp := new(GF127)
for _, b := range data { for _, b := range data {
mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x80 != 0, tmp) mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x80 != 0, tmp)
mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x40 != 0, tmp) mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x40 != 0, tmp)
@ -65,28 +65,28 @@ func (d *digestp) BlockSize() int {
return hashBlockSize return hashBlockSize
} }
func mulBitRightPure(c00, c01, c10, c11 *gogf127.GF127, bit bool, tmp *gogf127.GF127) { func mulBitRightPure(c00, c01, c10, c11 *GF127, bit bool, tmp *GF127) {
if bit { if bit {
*tmp = *c00 *tmp = *c00
gogf127.Mul10(c00, c00) gf127.Mul10(c00, c00)
gogf127.Add(c00, c01, c00) gf127.Add(c00, c01, c00)
gogf127.Mul11(tmp, tmp) gf127.Mul11(tmp, tmp)
gogf127.Add(c01, tmp, c01) gf127.Add(c01, tmp, c01)
*tmp = *c10 *tmp = *c10
gogf127.Mul10(c10, c10) gf127.Mul10(c10, c10)
gogf127.Add(c10, c11, c10) gf127.Add(c10, c11, c10)
gogf127.Mul11(tmp, tmp) gf127.Mul11(tmp, tmp)
gogf127.Add(c11, tmp, c11) gf127.Add(c11, tmp, c11)
} else { } else {
*tmp = *c00 *tmp = *c00
gogf127.Mul10(c00, c00) gf127.Mul10(c00, c00)
gogf127.Add(c00, c01, c00) gf127.Add(c00, c01, c00)
*c01 = *tmp *c01 = *tmp
*tmp = *c10 *tmp = *c10
gogf127.Mul10(c10, c10) gf127.Mul10(c10, c10)
gogf127.Add(c10, c11, c10) gf127.Add(c10, c11, c10)
*c11 = *tmp *c11 = *tmp
} }
} }

162
tz/sl2.go
View file

@ -4,17 +4,21 @@ import (
"errors" "errors"
"github.com/nspcc-dev/tzhash/gf127" "github.com/nspcc-dev/tzhash/gf127"
"github.com/nspcc-dev/tzhash/gogf127" "github.com/nspcc-dev/tzhash/gf127/avx"
) )
type sl2 [2][2]gf127.GF127 type (
GF127 = gf127.GF127
sl2 [2][2]GF127
)
var id = sl2{ var id = sl2{
{gf127.GF127{1, 0}, gf127.GF127{0, 0}}, {GF127{1, 0}, GF127{0, 0}},
{gf127.GF127{0, 0}, gf127.GF127{1, 0}}, {GF127{0, 0}, GF127{1, 0}},
} }
var mul func(a, b, c *sl2, x *[4]gf127.GF127) var mul func(a, b, c *sl2, x *[4]GF127)
func init() { func init() {
if hasAVX { if hasAVX {
@ -50,130 +54,130 @@ func (c *sl2) UnmarshalBinary(data []byte) (err error) {
return return
} }
func (c *sl2) mulStrassen(a, b *sl2, x *[8]gf127.GF127) *sl2 { func (c *sl2) mulStrassen(a, b *sl2, x *[8]GF127) *sl2 {
// strassen algorithm // strassen algorithm
gf127.Add(&a[0][0], &a[1][1], &x[0]) avx.Add(&a[0][0], &a[1][1], &x[0])
gf127.Add(&b[0][0], &b[1][1], &x[1]) avx.Add(&b[0][0], &b[1][1], &x[1])
gf127.Mul(&x[0], &x[1], &x[0]) avx.Mul(&x[0], &x[1], &x[0])
gf127.Add(&a[1][0], &a[1][1], &x[1]) avx.Add(&a[1][0], &a[1][1], &x[1])
gf127.Mul(&x[1], &b[0][0], &x[1]) avx.Mul(&x[1], &b[0][0], &x[1])
gf127.Add(&b[0][1], &b[1][1], &x[2]) avx.Add(&b[0][1], &b[1][1], &x[2])
gf127.Mul(&x[2], &a[0][0], &x[2]) avx.Mul(&x[2], &a[0][0], &x[2])
gf127.Add(&b[1][0], &b[0][0], &x[3]) avx.Add(&b[1][0], &b[0][0], &x[3])
gf127.Mul(&x[3], &a[1][1], &x[3]) avx.Mul(&x[3], &a[1][1], &x[3])
gf127.Add(&a[0][0], &a[0][1], &x[4]) avx.Add(&a[0][0], &a[0][1], &x[4])
gf127.Mul(&x[4], &b[1][1], &x[4]) avx.Mul(&x[4], &b[1][1], &x[4])
gf127.Add(&a[1][0], &a[0][0], &x[5]) avx.Add(&a[1][0], &a[0][0], &x[5])
gf127.Add(&b[0][0], &b[0][1], &x[6]) avx.Add(&b[0][0], &b[0][1], &x[6])
gf127.Mul(&x[5], &x[6], &x[5]) avx.Mul(&x[5], &x[6], &x[5])
gf127.Add(&a[0][1], &a[1][1], &x[6]) avx.Add(&a[0][1], &a[1][1], &x[6])
gf127.Add(&b[1][0], &b[1][1], &x[7]) avx.Add(&b[1][0], &b[1][1], &x[7])
gf127.Mul(&x[6], &x[7], &x[6]) avx.Mul(&x[6], &x[7], &x[6])
gf127.Add(&x[2], &x[4], &c[0][1]) avx.Add(&x[2], &x[4], &c[0][1])
gf127.Add(&x[1], &x[3], &c[1][0]) avx.Add(&x[1], &x[3], &c[1][0])
gf127.Add(&x[4], &x[6], &x[4]) avx.Add(&x[4], &x[6], &x[4])
gf127.Add(&x[0], &x[3], &c[0][0]) avx.Add(&x[0], &x[3], &c[0][0])
gf127.Add(&c[0][0], &x[4], &c[0][0]) avx.Add(&c[0][0], &x[4], &c[0][0])
gf127.Add(&x[0], &x[1], &x[0]) avx.Add(&x[0], &x[1], &x[0])
gf127.Add(&x[2], &x[5], &c[1][1]) avx.Add(&x[2], &x[5], &c[1][1])
gf127.Add(&c[1][1], &x[0], &c[1][1]) avx.Add(&c[1][1], &x[0], &c[1][1])
return c return c
} }
func mulSL2AVX(a, b, c *sl2, x *[4]gf127.GF127) { func mulSL2AVX(a, b, c *sl2, x *[4]GF127) {
gf127.Mul(&a[0][0], &b[0][0], &x[0]) avx.Mul(&a[0][0], &b[0][0], &x[0])
gf127.Mul(&a[0][0], &b[0][1], &x[1]) avx.Mul(&a[0][0], &b[0][1], &x[1])
gf127.Mul(&a[1][0], &b[0][0], &x[2]) avx.Mul(&a[1][0], &b[0][0], &x[2])
gf127.Mul(&a[1][0], &b[0][1], &x[3]) avx.Mul(&a[1][0], &b[0][1], &x[3])
gf127.Mul(&a[0][1], &b[1][0], &c[0][0]) avx.Mul(&a[0][1], &b[1][0], &c[0][0])
gf127.Add(&c[0][0], &x[0], &c[0][0]) avx.Add(&c[0][0], &x[0], &c[0][0])
gf127.Mul(&a[0][1], &b[1][1], &c[0][1]) avx.Mul(&a[0][1], &b[1][1], &c[0][1])
gf127.Add(&c[0][1], &x[1], &c[0][1]) avx.Add(&c[0][1], &x[1], &c[0][1])
gf127.Mul(&a[1][1], &b[1][0], &c[1][0]) avx.Mul(&a[1][1], &b[1][0], &c[1][0])
gf127.Add(&c[1][0], &x[2], &c[1][0]) avx.Add(&c[1][0], &x[2], &c[1][0])
gf127.Mul(&a[1][1], &b[1][1], &c[1][1]) avx.Mul(&a[1][1], &b[1][1], &c[1][1])
gf127.Add(&c[1][1], &x[3], &c[1][1]) avx.Add(&c[1][1], &x[3], &c[1][1])
} }
func mulSL2Pure(a, b, c *sl2, x *[4]gf127.GF127) { func mulSL2Pure(a, b, c *sl2, x *[4]GF127) {
gogf127.Mul((*gogf127.GF127)(&a[0][0]), (*gogf127.GF127)(&b[0][0]), (*gogf127.GF127)(&x[0])) gf127.Mul((*GF127)(&a[0][0]), (*GF127)(&b[0][0]), (*GF127)(&x[0]))
gogf127.Mul((*gogf127.GF127)(&a[0][0]), (*gogf127.GF127)(&b[0][1]), (*gogf127.GF127)(&x[1])) gf127.Mul((*GF127)(&a[0][0]), (*GF127)(&b[0][1]), (*GF127)(&x[1]))
gogf127.Mul((*gogf127.GF127)(&a[1][0]), (*gogf127.GF127)(&b[0][0]), (*gogf127.GF127)(&x[2])) gf127.Mul((*GF127)(&a[1][0]), (*GF127)(&b[0][0]), (*GF127)(&x[2]))
gogf127.Mul((*gogf127.GF127)(&a[1][0]), (*gogf127.GF127)(&b[0][1]), (*gogf127.GF127)(&x[3])) gf127.Mul((*GF127)(&a[1][0]), (*GF127)(&b[0][1]), (*GF127)(&x[3]))
gogf127.Mul((*gogf127.GF127)(&a[0][1]), (*gogf127.GF127)(&b[1][0]), (*gogf127.GF127)(&c[0][0])) gf127.Mul((*GF127)(&a[0][1]), (*GF127)(&b[1][0]), (*GF127)(&c[0][0]))
gogf127.Add((*gogf127.GF127)(&c[0][0]), (*gogf127.GF127)(&x[0]), (*gogf127.GF127)(&c[0][0])) gf127.Add((*GF127)(&c[0][0]), (*GF127)(&x[0]), (*GF127)(&c[0][0]))
gogf127.Mul((*gogf127.GF127)(&a[0][1]), (*gogf127.GF127)(&b[1][1]), (*gogf127.GF127)(&c[0][1])) gf127.Mul((*GF127)(&a[0][1]), (*GF127)(&b[1][1]), (*GF127)(&c[0][1]))
gogf127.Add((*gogf127.GF127)(&c[0][1]), (*gogf127.GF127)(&x[1]), (*gogf127.GF127)(&c[0][1])) gf127.Add((*GF127)(&c[0][1]), (*GF127)(&x[1]), (*GF127)(&c[0][1]))
gogf127.Mul((*gogf127.GF127)(&a[1][1]), (*gogf127.GF127)(&b[1][0]), (*gogf127.GF127)(&c[1][0])) gf127.Mul((*GF127)(&a[1][1]), (*GF127)(&b[1][0]), (*GF127)(&c[1][0]))
gogf127.Add((*gogf127.GF127)(&c[1][0]), (*gogf127.GF127)(&x[2]), (*gogf127.GF127)(&c[1][0])) gf127.Add((*GF127)(&c[1][0]), (*GF127)(&x[2]), (*GF127)(&c[1][0]))
gogf127.Mul((*gogf127.GF127)(&a[1][1]), (*gogf127.GF127)(&b[1][1]), (*gogf127.GF127)(&c[1][1])) gf127.Mul((*GF127)(&a[1][1]), (*GF127)(&b[1][1]), (*GF127)(&c[1][1]))
gogf127.Add((*gogf127.GF127)(&c[1][1]), (*gogf127.GF127)(&x[3]), (*gogf127.GF127)(&c[1][1])) gf127.Add((*GF127)(&c[1][1]), (*GF127)(&x[3]), (*GF127)(&c[1][1]))
} }
func (c *sl2) MulA() *sl2 { func (c *sl2) MulA() *sl2 {
var a gf127.GF127 var a GF127
gf127.Mul10(&c[0][0], &a) avx.Mul10(&c[0][0], &a)
gf127.Mul1(&c[0][0], &c[0][1]) gf127.Mul1(&c[0][0], &c[0][1])
gf127.Add(&a, &c[0][1], &c[0][0]) avx.Add(&a, &c[0][1], &c[0][0])
gf127.Mul10(&c[1][0], &a) avx.Mul10(&c[1][0], &a)
gf127.Mul1(&c[1][0], &c[1][1]) gf127.Mul1(&c[1][0], &c[1][1])
gf127.Add(&a, &c[1][1], &c[1][0]) avx.Add(&a, &c[1][1], &c[1][0])
return c return c
} }
func (c *sl2) MulB() *sl2 { func (c *sl2) MulB() *sl2 {
var a gf127.GF127 var a GF127
gf127.Mul1(&c[0][0], &a) gf127.Mul1(&c[0][0], &a)
gf127.Mul10(&c[0][0], &c[0][0]) avx.Mul10(&c[0][0], &c[0][0])
gf127.Add(&c[0][1], &c[0][0], &c[0][0]) avx.Add(&c[0][1], &c[0][0], &c[0][0])
gf127.Add(&c[0][0], &a, &c[0][1]) avx.Add(&c[0][0], &a, &c[0][1])
gf127.Mul1(&c[1][0], &a) gf127.Mul1(&c[1][0], &a)
gf127.Mul10(&c[1][0], &c[1][0]) avx.Mul10(&c[1][0], &c[1][0])
gf127.Add(&c[1][1], &c[1][0], &c[1][0]) avx.Add(&c[1][1], &c[1][0], &c[1][0])
gf127.Add(&c[1][0], &a, &c[1][1]) avx.Add(&c[1][0], &a, &c[1][1])
return c return c
} }
func (c *sl2) Mul(a, b *sl2) *sl2 { func (c *sl2) Mul(a, b *sl2) *sl2 {
mul(a, b, c, new([4]gf127.GF127)) mul(a, b, c, new([4]GF127))
return c return c
} }
// Inv returns inverse of a in GL_2(GF(2^127)) // Inv returns inverse of a in GL_2(GF(2^127))
func Inv(a *sl2) (b *sl2) { func Inv(a *sl2) (b *sl2) {
b = new(sl2) b = new(sl2)
inv(a, b, new([2]gf127.GF127)) inv(a, b, new([2]GF127))
return return
} }
func inv(a, b *sl2, t *[2]gf127.GF127) { func inv(a, b *sl2, t *[2]GF127) {
gf127.Mul(&a[0][0], &a[1][1], &t[0]) avx.Mul(&a[0][0], &a[1][1], &t[0])
gf127.Mul(&a[0][1], &a[1][0], &t[1]) avx.Mul(&a[0][1], &a[1][0], &t[1])
gf127.Add(&t[0], &t[1], &t[0]) avx.Add(&t[0], &t[1], &t[0])
gf127.Inv(&t[0], &t[1]) gf127.Inv(&t[0], &t[1])
gf127.Mul(&t[1], &a[0][0], &b[1][1]) avx.Mul(&t[1], &a[0][0], &b[1][1])
gf127.Mul(&t[1], &a[0][1], &b[0][1]) avx.Mul(&t[1], &a[0][1], &b[0][1])
gf127.Mul(&t[1], &a[1][0], &b[1][0]) avx.Mul(&t[1], &a[1][0], &b[1][0])
gf127.Mul(&t[1], &a[1][1], &b[0][0]) avx.Mul(&t[1], &a[1][1], &b[0][0])
} }
func (c *sl2) String() string { func (c *sl2) String() string {

View file

@ -6,6 +6,7 @@ import (
"time" "time"
"github.com/nspcc-dev/tzhash/gf127" "github.com/nspcc-dev/tzhash/gf127"
"github.com/nspcc-dev/tzhash/gf127/avx"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -21,12 +22,12 @@ func random() (a *sl2) {
// so that result is in SL2 // so that result is in SL2
// d = a^-1*(1+b*c) // d = a^-1*(1+b*c)
gf127.Mul(&a[0][1], &a[1][0], &a[1][1]) avx.Mul(&a[0][1], &a[1][0], &a[1][1])
gf127.Add(&a[1][1], gf127.New(1, 0), &a[1][1]) avx.Add(&a[1][1], gf127.New(1, 0), &a[1][1])
t := gf127.New(0, 0) t := gf127.New(0, 0)
gf127.Inv(&a[0][0], t) gf127.Inv(&a[0][0], t)
gf127.Mul(t, &a[1][1], &a[1][1]) avx.Mul(t, &a[1][1], &a[1][1])
return return
} }