199 lines
4.4 KiB
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")
|
|
}
|
|
}
|