gmsm/internal/sm2ec/sm2p256_mqv.go

79 lines
2.0 KiB
Go

package sm2ec
import (
"encoding/binary"
"errors"
"math/bits"
)
var p256Order = [4]uint64{0x53bbf40939d54123, 0x7203df6b21c6052b,
0xffffffffffffffff, 0xfffffffeffffffff}
func fromBytes(bytes []byte) (*[4]uint64, error) {
if len(bytes) != 32 {
return nil, errors.New("invalid scalar length")
}
var t [4]uint64
t[0] = binary.BigEndian.Uint64(bytes[24:])
t[1] = binary.BigEndian.Uint64(bytes[16:])
t[2] = binary.BigEndian.Uint64(bytes[8:])
t[3] = binary.BigEndian.Uint64(bytes)
return &t, nil
}
func toBytes(t *[4]uint64) []byte {
var bytes [32]byte
binary.BigEndian.PutUint64(bytes[:], t[3])
binary.BigEndian.PutUint64(bytes[8:], t[2])
binary.BigEndian.PutUint64(bytes[16:], t[1])
binary.BigEndian.PutUint64(bytes[24:], t[0])
return bytes[:]
}
// p256OrdAdd sets res = x + y.
func p256OrdAdd(res, x, y *[4]uint64) {
var c, b uint64
t1 := make([]uint64, 4)
t1[0], c = bits.Add64(x[0], y[0], 0)
t1[1], c = bits.Add64(x[1], y[1], c)
t1[2], c = bits.Add64(x[2], y[2], c)
t1[3], c = bits.Add64(x[3], y[3], c)
t2 := make([]uint64, 4)
t2[0], b = bits.Sub64(t1[0], p256Order[0], 0)
t2[1], b = bits.Sub64(t1[1], p256Order[1], b)
t2[2], b = bits.Sub64(t1[2], p256Order[2], b)
t2[3], b = bits.Sub64(t1[3], p256Order[3], b)
// Three options:
// - a+b < p
// then c is 0, b is 1, and t1 is correct
// - p <= a+b < 2^256
// then c is 0, b is 0, and t2 is correct
// - 2^256 <= a+b
// then c is 1, b is 1, and t2 is correct
t2Mask := (c ^ b) - 1
res[0] = (t1[0] & ^t2Mask) | (t2[0] & t2Mask)
res[1] = (t1[1] & ^t2Mask) | (t2[1] & t2Mask)
res[2] = (t1[2] & ^t2Mask) | (t2[2] & t2Mask)
res[3] = (t1[3] & ^t2Mask) | (t2[3] & t2Mask)
}
func ImplicitSig(sPriv, ePriv, t []byte) ([]byte, error) {
mulRes, err := P256OrdMul(ePriv, t)
if err != nil {
return nil, err
}
t1, err := fromBytes(mulRes)
if err != nil {
return nil, err
}
t2, err := fromBytes(sPriv)
if err != nil {
return nil, err
}
var t3 [4]uint64
p256OrdAdd(&t3, t1, t2)
return toBytes(&t3), nil
}