Files
p256k1/field_asm_test.go

199 lines
4.4 KiB
Go

package p256k1
import (
"testing"
)
// fieldMulPureGo is the pure Go implementation for comparison
func fieldMulPureGo(r, a, b *FieldElement) {
// Extract limbs for easier access
a0, a1, a2, a3, a4 := a.n[0], a.n[1], a.n[2], a.n[3], a.n[4]
b0, b1, b2, b3, b4 := b.n[0], b.n[1], b.n[2], b.n[3], b.n[4]
const M = uint64(0xFFFFFFFFFFFFF) // 2^52 - 1
const R = uint64(fieldReductionConstantShifted) // 0x1000003D10
// Following the C implementation algorithm exactly
var c, d uint128
d = mulU64ToU128(a0, b3)
d = addMulU128(d, a1, b2)
d = addMulU128(d, a2, b1)
d = addMulU128(d, a3, b0)
c = mulU64ToU128(a4, b4)
d = addMulU128(d, R, c.lo())
c = c.rshift(64)
t3 := d.lo() & M
d = d.rshift(52)
d = addMulU128(d, a0, b4)
d = addMulU128(d, a1, b3)
d = addMulU128(d, a2, b2)
d = addMulU128(d, a3, b1)
d = addMulU128(d, a4, b0)
d = addMulU128(d, R<<12, c.lo())
t4 := d.lo() & M
d = d.rshift(52)
tx := t4 >> 48
t4 &= (M >> 4)
c = mulU64ToU128(a0, b0)
d = addMulU128(d, a1, b4)
d = addMulU128(d, a2, b3)
d = addMulU128(d, a3, b2)
d = addMulU128(d, a4, b1)
u0 := d.lo() & M
d = d.rshift(52)
u0 = (u0 << 4) | tx
c = addMulU128(c, u0, R>>4)
r.n[0] = c.lo() & M
c = c.rshift(52)
c = addMulU128(c, a0, b1)
c = addMulU128(c, a1, b0)
d = addMulU128(d, a2, b4)
d = addMulU128(d, a3, b3)
d = addMulU128(d, a4, b2)
c = addMulU128(c, R, d.lo()&M)
d = d.rshift(52)
r.n[1] = c.lo() & M
c = c.rshift(52)
c = addMulU128(c, a0, b2)
c = addMulU128(c, a1, b1)
c = addMulU128(c, a2, b0)
d = addMulU128(d, a3, b4)
d = addMulU128(d, a4, b3)
c = addMulU128(c, R, d.lo())
d = d.rshift(64)
r.n[2] = c.lo() & M
c = c.rshift(52)
c = addMulU128(c, R<<12, d.lo())
c = addU128(c, t3)
r.n[3] = c.lo() & M
c = c.rshift(52)
r.n[4] = c.lo() + t4
r.magnitude = 1
r.normalized = false
}
func TestFieldMulAsmVsPureGo(t *testing.T) {
// Test with simple values first
a := FieldElement{n: [5]uint64{1, 0, 0, 0, 0}, magnitude: 1, normalized: true}
b := FieldElement{n: [5]uint64{2, 0, 0, 0, 0}, magnitude: 1, normalized: true}
var rAsm, rGo FieldElement
// Pure Go
fieldMulPureGo(&rGo, &a, &b)
// Assembly
if hasFieldAsm() {
fieldMulAsm(&rAsm, &a, &b)
rAsm.magnitude = 1
rAsm.normalized = false
t.Logf("a = %v", a.n)
t.Logf("b = %v", b.n)
t.Logf("Go result: %v", rGo.n)
t.Logf("Asm result: %v", rAsm.n)
for i := 0; i < 5; i++ {
if rAsm.n[i] != rGo.n[i] {
t.Errorf("limb %d mismatch: asm=%x, go=%x", i, rAsm.n[i], rGo.n[i])
}
}
} else {
t.Skip("Assembly not available")
}
}
func TestFieldMulAsmVsPureGoLarger(t *testing.T) {
// Test with larger values
a := FieldElement{
n: [5]uint64{0x1234567890abcdef & 0xFFFFFFFFFFFFF, 0xfedcba9876543210 & 0xFFFFFFFFFFFFF, 0x0123456789abcdef & 0xFFFFFFFFFFFFF, 0xfedcba0987654321 & 0xFFFFFFFFFFFFF, 0x0123456789ab & 0x0FFFFFFFFFFFF},
magnitude: 1,
normalized: true,
}
b := FieldElement{
n: [5]uint64{0xabcdef1234567890 & 0xFFFFFFFFFFFFF, 0x9876543210fedcba & 0xFFFFFFFFFFFFF, 0xfedcba1234567890 & 0xFFFFFFFFFFFFF, 0x0987654321abcdef & 0xFFFFFFFFFFFFF, 0x0fedcba98765 & 0x0FFFFFFFFFFFF},
magnitude: 1,
normalized: true,
}
var rAsm, rGo FieldElement
// Pure Go
fieldMulPureGo(&rGo, &a, &b)
// Assembly
if hasFieldAsm() {
fieldMulAsm(&rAsm, &a, &b)
rAsm.magnitude = 1
rAsm.normalized = false
t.Logf("a = %v", a.n)
t.Logf("b = %v", b.n)
t.Logf("Go result: %v", rGo.n)
t.Logf("Asm result: %v", rAsm.n)
for i := 0; i < 5; i++ {
if rAsm.n[i] != rGo.n[i] {
t.Errorf("limb %d mismatch: asm=%x, go=%x", i, rAsm.n[i], rGo.n[i])
}
}
} else {
t.Skip("Assembly not available")
}
}
func TestFieldSqrAsmVsPureGo(t *testing.T) {
a := FieldElement{
n: [5]uint64{0x1234567890abcdef & 0xFFFFFFFFFFFFF, 0xfedcba9876543210 & 0xFFFFFFFFFFFFF, 0x0123456789abcdef & 0xFFFFFFFFFFFFF, 0xfedcba0987654321 & 0xFFFFFFFFFFFFF, 0x0123456789ab & 0x0FFFFFFFFFFFF},
magnitude: 1,
normalized: true,
}
var rAsm, rGo FieldElement
// Pure Go (a * a)
fieldMulPureGo(&rGo, &a, &a)
// Assembly
if hasFieldAsm() {
fieldSqrAsm(&rAsm, &a)
rAsm.magnitude = 1
rAsm.normalized = false
t.Logf("a = %v", a.n)
t.Logf("Go result: %v", rGo.n)
t.Logf("Asm result: %v", rAsm.n)
for i := 0; i < 5; i++ {
if rAsm.n[i] != rGo.n[i] {
t.Errorf("limb %d mismatch: asm=%x, go=%x", i, rAsm.n[i], rGo.n[i])
}
}
} else {
t.Skip("Assembly not available")
}
}