Implement matrix multiplication with pure Go

Set suitable backend for GF127 arithmetic for Concat(), Sum() etc.
This commit is contained in:
Evgenii Stratonikov 2019-10-09 11:37:22 +03:00
parent 06362477ed
commit f613ab2c25
3 changed files with 37 additions and 9 deletions

View file

@ -160,23 +160,24 @@ func Add(a, b, c *GF127) {
} }
// Mul sets c to a*b. // Mul sets c to a*b.
// TODO make it work in-place without allocations
// TODO optimization: no need to perform shift by i every time, cache results // TODO optimization: no need to perform shift by i every time, cache results
func Mul(a, b, c *GF127) { func Mul(a, b, c *GF127) {
c[0] = 0 r := new(GF127)
c[1] = 0
d := new(GF127) d := new(GF127)
for i := uint(0); i < 64; i++ { for i := uint(0); i < 64; i++ {
if b[0]&(1<<i) != 0 { if b[0]&(1<<i) != 0 {
shl(i, a, d) shl(i, a, d)
Add(c, d, c) Add(r, d, r)
} }
} }
for i := uint(0); i < 63; i++ { for i := uint(0); i < 63; i++ {
if b[1]&(1<<i) != 0 { if b[1]&(1<<i) != 0 {
shl(i+64, a, d) shl(i+64, a, d)
Add(c, d, c) Add(r, d, r)
} }
} }
*c = *r
} }
// shl performs left shift by consecutive multiplications by 2. // shl performs left shift by consecutive multiplications by 2.

View file

@ -36,7 +36,7 @@ const (
bitAVX2 = 1 << 5 bitAVX2 = 1 << 5
) )
func init() { func setFeatures() {
maxID, _, _, _ := cpuid(0, 0) maxID, _, _, _ := cpuid(0, 0)
if maxID < 1 { if maxID < 1 {
return return

View file

@ -4,6 +4,7 @@ import (
"errors" "errors"
"github.com/nspcc-dev/tzhash/gf127" "github.com/nspcc-dev/tzhash/gf127"
"github.com/nspcc-dev/tzhash/gogf127"
) )
type sl2 [2][2]gf127.GF127 type sl2 [2][2]gf127.GF127
@ -13,6 +14,18 @@ var id = sl2{
{gf127.GF127{0, 0}, gf127.GF127{1, 0}}, {gf127.GF127{0, 0}, gf127.GF127{1, 0}},
} }
var mul func(a, b, c *sl2, x *[4]gf127.GF127)
func init() {
setFeatures()
if hasAVX {
mul = mulSL2AVX
} else {
mul = mulSL2Pure
}
}
func (c *sl2) MarshalBinary() (data []byte, err error) { func (c *sl2) MarshalBinary() (data []byte, err error) {
s := c.ByteArray() s := c.ByteArray()
return s[:], nil return s[:], nil
@ -79,8 +92,7 @@ func (c *sl2) mulStrassen(a, b *sl2, x *[8]gf127.GF127) *sl2 {
return c return c
} }
func (c *sl2) mul(a, b *sl2, x *[4]gf127.GF127) *sl2 { func mulSL2AVX(a, b, c *sl2, x *[4]gf127.GF127) {
// naive implementation
gf127.Mul(&a[0][0], &b[0][0], &x[0]) gf127.Mul(&a[0][0], &b[0][0], &x[0])
gf127.Mul(&a[0][0], &b[0][1], &x[1]) gf127.Mul(&a[0][0], &b[0][1], &x[1])
gf127.Mul(&a[1][0], &b[0][0], &x[2]) gf127.Mul(&a[1][0], &b[0][0], &x[2])
@ -94,8 +106,22 @@ func (c *sl2) mul(a, b *sl2, x *[4]gf127.GF127) *sl2 {
gf127.Add(&c[1][0], &x[2], &c[1][0]) gf127.Add(&c[1][0], &x[2], &c[1][0])
gf127.Mul(&a[1][1], &b[1][1], &c[1][1]) gf127.Mul(&a[1][1], &b[1][1], &c[1][1])
gf127.Add(&c[1][1], &x[3], &c[1][1]) gf127.Add(&c[1][1], &x[3], &c[1][1])
}
return c func mulSL2Pure(a, b, c *sl2, x *[4]gf127.GF127) {
gogf127.Mul((*gogf127.GF127)(&a[0][0]), (*gogf127.GF127)(&b[0][0]), (*gogf127.GF127)(&x[0]))
gogf127.Mul((*gogf127.GF127)(&a[0][0]), (*gogf127.GF127)(&b[0][1]), (*gogf127.GF127)(&x[1]))
gogf127.Mul((*gogf127.GF127)(&a[1][0]), (*gogf127.GF127)(&b[0][0]), (*gogf127.GF127)(&x[2]))
gogf127.Mul((*gogf127.GF127)(&a[1][0]), (*gogf127.GF127)(&b[0][1]), (*gogf127.GF127)(&x[3]))
gogf127.Mul((*gogf127.GF127)(&a[0][1]), (*gogf127.GF127)(&b[1][0]), (*gogf127.GF127)(&c[0][0]))
gogf127.Add((*gogf127.GF127)(&c[0][0]), (*gogf127.GF127)(&x[0]), (*gogf127.GF127)(&c[0][0]))
gogf127.Mul((*gogf127.GF127)(&a[0][1]), (*gogf127.GF127)(&b[1][1]), (*gogf127.GF127)(&c[0][1]))
gogf127.Add((*gogf127.GF127)(&c[0][1]), (*gogf127.GF127)(&x[1]), (*gogf127.GF127)(&c[0][1]))
gogf127.Mul((*gogf127.GF127)(&a[1][1]), (*gogf127.GF127)(&b[1][0]), (*gogf127.GF127)(&c[1][0]))
gogf127.Add((*gogf127.GF127)(&c[1][0]), (*gogf127.GF127)(&x[2]), (*gogf127.GF127)(&c[1][0]))
gogf127.Mul((*gogf127.GF127)(&a[1][1]), (*gogf127.GF127)(&b[1][1]), (*gogf127.GF127)(&c[1][1]))
gogf127.Add((*gogf127.GF127)(&c[1][1]), (*gogf127.GF127)(&x[3]), (*gogf127.GF127)(&c[1][1]))
} }
func (c *sl2) MulA() *sl2 { func (c *sl2) MulA() *sl2 {
@ -129,7 +155,8 @@ func (c *sl2) MulB() *sl2 {
} }
func (c *sl2) Mul(a, b *sl2) *sl2 { func (c *sl2) Mul(a, b *sl2) *sl2 {
return c.mul(a, b, new([4]gf127.GF127)) mul(a, b, c, new([4]gf127.GF127))
return c
} }
// Inv returns inverse of a in GL_2(GF(2^127)) // Inv returns inverse of a in GL_2(GF(2^127))