diff --git a/gf127/gf127.go b/gf127/gf127.go index 8d4152b..40e7965 100644 --- a/gf127/gf127.go +++ b/gf127/gf127.go @@ -164,8 +164,8 @@ func Add(a, b, c *GF127) // Mul sets c to a*b. func Mul(a, b, c *GF127) -// Mul10 sets y to a*x. +// Mul10 sets b to a*x. func Mul10(a, b *GF127) -// Mul11 sets y to a*(x+1). +// Mul11 sets b to a*(x+1). func Mul11(a, b *GF127) diff --git a/gf127/gf127_amd64.s b/gf127/gf127_amd64.s index d159814..ada6f24 100644 --- a/gf127/gf127_amd64.s +++ b/gf127/gf127_amd64.s @@ -27,6 +27,22 @@ TEXT ·Mul10(SB),NOSPLIT,$0 MOVUPD X1, (AX) 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) TEXT ·Mul11(SB),NOSPLIT,$0 MOVQ a+0(FP), AX @@ -44,6 +60,23 @@ TEXT ·Mul11(SB),NOSPLIT,$0 MOVUPD X1, (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 + // func Mul(a, b, c *[2]uint64) TEXT ·Mul(SB),NOSPLIT,$0 MOVQ a+0(FP), AX // X0 = a0 . a1 diff --git a/gf127/gf127x2.go b/gf127/gf127x2.go new file mode 100644 index 0000000..1087050 --- /dev/null +++ b/gf127/gf127x2.go @@ -0,0 +1,51 @@ +package gf127 + +import ( + "encoding/binary" + "encoding/hex" + "unsafe" +) + +// GF127x2 represents a pair of elements of GF(2^127) stored together. +type GF127x2 [4]uint64 + +// Split returns 2 components of pair without additional allocations. +func Split(a *GF127x2) (*GF127, *GF127) { + return (*GF127)(unsafe.Pointer(a)), (*GF127)(unsafe.Pointer(&(*a)[2])) +} + +// CombineTo 2 elements of GF(2^127) to the respective components of pair. +func CombineTo(a *GF127, b *GF127, c *GF127x2) { + c[0] = a[0] + c[1] = a[1] + c[2] = b[0] + c[3] = b[1] +} + +// Equal checks if both elements of GF(2^127) pair are equal. +func (a *GF127x2) Equal(b *GF127x2) bool { + return a[0] == b[0] && a[1] == b[1] && a[2] == b[2] && a[3] == b[3] +} + +// String returns hex-encoded representation, starting with MSB. +// Elements of pair are separated by comma. +func (a *GF127x2) String() string { + b := a.ByteArray() + return hex.EncodeToString(b[:16]) + " , " + hex.EncodeToString(b[16:]) +} + +// ByteArray represents element of GF(2^127) as byte array of length 32. +func (a *GF127x2) ByteArray() (buf []byte) { + buf = make([]byte, 32) + binary.BigEndian.PutUint64(buf, a[1]) + binary.BigEndian.PutUint64(buf[8:], a[0]) + binary.BigEndian.PutUint64(buf[16:], a[3]) + binary.BigEndian.PutUint64(buf[24:], a[2]) + return +} + +// Mul10x2 sets (b1, b2) to (a1*x, a2*x) +func Mul10x2(a, b *GF127x2) + +// Mul10x2 sets (b1, b2) to (a1*(x+1), a2*(x+1)) +func Mul11x2(a, b *GF127x2) diff --git a/gf127/gf127x2_test.go b/gf127/gf127x2_test.go new file mode 100644 index 0000000..64370c1 --- /dev/null +++ b/gf127/gf127x2_test.go @@ -0,0 +1,61 @@ +package gf127 + +import "testing" + +var testCasesSplit = []struct { + num *GF127x2 + h1 *GF127 + h2 *GF127 +}{ + {&GF127x2{123, 31, 141, 9}, &GF127{123, 31}, &GF127{141, 9}}, + {&GF127x2{maxUint64, 0, 0, maxUint64}, &GF127{maxUint64, 0}, &GF127{0, maxUint64}}, +} + +func TestSplit(t *testing.T) { + for _, tc := range testCasesSplit { + a, b := Split(tc.num) + if !a.Equals(tc.h1) || !b.Equals(tc.h2) { + t.Errorf("expected (%s,%s), got (%s,%s)", tc.h1, tc.h2, a, b) + } + } +} + +func TestCombineTo(t *testing.T) { + c := new(GF127x2) + for _, tc := range testCasesSplit { + CombineTo(tc.h1, tc.h2, c) + if !c.Equal(tc.num) { + t.Errorf("expected (%s), got (%s)", tc.num, c) + } + } +} + +var testCasesMul10x2 = [][2]*GF127x2{ + {&GF127x2{123, 0, 123, 0}, &GF127x2{246, 0, 246, 0}}, + {&GF127x2{maxUint64, 2, 0, 1}, &GF127x2{maxUint64 - 1, 5, 0, 2}}, + {&GF127x2{0, maxUint64 >> 1, maxUint64, 2}, &GF127x2{1 + 1<<63, maxUint64>>1 - 1, maxUint64 - 1, 5}}, +} + +func TestMul10x2(t *testing.T) { + c := new(GF127x2) + for _, tc := range testCasesMul10x2 { + if Mul10x2(tc[0], c); !c.Equal(tc[1]) { + t.Errorf("expected (%s), got (%s)", tc[1], c) + } + } +} + +var testCasesMul11x2 = [][2]*GF127x2{ + {&GF127x2{123, 0, 123, 0}, &GF127x2{141, 0, 141, 0}}, + {&GF127x2{maxUint64, 2, 0, 1}, &GF127x2{1, 7, 0, 3}}, + {&GF127x2{0, maxUint64 >> 1, maxUint64, 2}, &GF127x2{1 + 1<<63, 1, 1, 7}}, +} + +func TestMul11x2(t *testing.T) { + c := new(GF127x2) + for _, tc := range testCasesMul11x2 { + if Mul11x2(tc[0], c); !c.Equal(tc[1]) { + t.Errorf("expected (%s), got (%s)", tc[1], c) + } + } +}