diff --git a/internal/sm2ec/sm2p256_asm_s390x.go b/internal/sm2ec/sm2p256_asm_s390x.go index e428acd..fd60881 100644 --- a/internal/sm2ec/sm2p256_asm_s390x.go +++ b/internal/sm2ec/sm2p256_asm_s390x.go @@ -53,3 +53,8 @@ func p256OrdLittleToBig(res *[32]byte, in *p256OrdElement) // //go:noescape func p256OrdReduce(s *p256OrdElement) + +// Montgomery multiplication modulo org(G). Sets res = in1 * in2 * R⁻¹. +// +//go:noescape +func p256OrdMul(res, in1, in2 *p256OrdElement) diff --git a/internal/sm2ec/sm2p256_asm_s390x_test.go b/internal/sm2ec/sm2p256_asm_s390x_test.go index 1f6194f..8670da7 100644 --- a/internal/sm2ec/sm2p256_asm_s390x_test.go +++ b/internal/sm2ec/sm2p256_asm_s390x_test.go @@ -3,8 +3,11 @@ package sm2ec import ( + "crypto/rand" + "io" "math/big" "testing" + "time" ) var bigOne = big.NewInt(1) @@ -86,3 +89,67 @@ func TestP256OrderReduce(t *testing.T) { testP256OrderReduce(bigVal, bigVal, t) } } + +func p256OrderFromMont(in *p256OrdElement) []byte { + // Montgomery multiplication by R⁻¹, or 1 outside the domain as R⁻¹×R = 1, + // converts a Montgomery value out of the domain. + one := &p256OrdElement{1} + p256OrdMul(in, in, one) + + var xOut [32]byte + p256OrdLittleToBig(&xOut, in) + return xOut[:] +} + +func p256OrdMulTest(t *testing.T, x, y, p, r *big.Int) { + x1 := new(big.Int).Mul(x, r) + x1 = x1.Mod(x1, p) + y1 := new(big.Int).Mul(y, r) + y1 = y1.Mod(y1, p) + ax := new(p256OrdElement) + ay := new(p256OrdElement) + res2 := new(p256OrdElement) + fromBig((*[4]uint64)(ax), x1) + fromBig((*[4]uint64)(ay), y1) + p256OrdMul(res2, ax, ay) + resInt := new(big.Int).SetBytes(p256OrderFromMont(res2)) + + expected := new(big.Int).Mul(x, y) + expected = expected.Mod(expected, p) + if resInt.Cmp(expected) != 0 { + t.FailNow() + } +} + +func TestP256OrdMulOrdMinus1(t *testing.T) { + p, _ := new(big.Int).SetString("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16) + r, _ := new(big.Int).SetString("10000000000000000000000000000000000000000000000000000000000000000", 16) + pMinus1 := new(big.Int).Sub(p, big.NewInt(1)) + p256OrdMulTest(t, pMinus1, pMinus1, p, r) +} + +func TestFuzzyP256OrdMul(t *testing.T) { + p, _ := new(big.Int).SetString("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16) + r, _ := new(big.Int).SetString("10000000000000000000000000000000000000000000000000000000000000000", 16) + var scalar1 [32]byte + var scalar2 [32]byte + var timeout *time.Timer + + if testing.Short() { + timeout = time.NewTimer(10 * time.Millisecond) + } else { + timeout = time.NewTimer(2 * time.Second) + } + for { + select { + case <-timeout.C: + return + default: + } + io.ReadFull(rand.Reader, scalar1[:]) + io.ReadFull(rand.Reader, scalar2[:]) + x := new(big.Int).SetBytes(scalar1[:]) + y := new(big.Int).SetBytes(scalar2[:]) + p256OrdMulTest(t, x, y, p, r) + } +}