282 lines
7.1 KiB
Go
282 lines
7.1 KiB
Go
package sm2
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/hex"
|
|
"math/big"
|
|
"strings"
|
|
|
|
"golang.org/x/crypto/cryptobyte"
|
|
"golang.org/x/crypto/cryptobyte/asn1"
|
|
"xdx.jelly/xgcl/gerrors"
|
|
"xdx.jelly/xgcl/gmath"
|
|
"xdx.jelly/xgcl/sm/sm2/ec256"
|
|
"xdx.jelly/xgcl/sm/sm3"
|
|
)
|
|
|
|
// Signature 签名结构体
|
|
type Signature struct {
|
|
R, S *big.Int
|
|
}
|
|
|
|
// NewSignature .
|
|
func NewSignature() *Signature {
|
|
return &Signature{
|
|
R: new(big.Int),
|
|
S: new(big.Int),
|
|
}
|
|
}
|
|
|
|
// MarshalUtil implements the gcl/util/encoding/UtilMarshaler interface
|
|
func (sig *Signature) MarshalUtil(data []byte) ([]byte, error) {
|
|
if data == nil {
|
|
data = make([]byte, 0, 2*ECCRefMaxLen)
|
|
}
|
|
|
|
sig.R.Mod(sig.R, orderN)
|
|
sig.S.Mod(sig.S, orderN)
|
|
data = append(data, gmath.BigIntToNByte(sig.R, ECCRefMaxLen)...)
|
|
data = append(data, gmath.BigIntToNByte(sig.S, ECCRefMaxLen)...)
|
|
return data, nil
|
|
}
|
|
|
|
func (sig *Signature) UnmarshalUtil(data []byte) (uint64, error) {
|
|
n := uint64(0)
|
|
if len(data) < 2*ECCRefMaxLen {
|
|
return 0, gerrors.WithAnnotating(ErrInvalidInput, "input data too short")
|
|
}
|
|
r := new(big.Int).SetBytes(data[:ECCRefMaxLen])
|
|
data = data[ECCRefMaxLen:]
|
|
n += ECCRefMaxLen
|
|
|
|
if r.Cmp(orderN) >= 0 || r.Sign() == 0 {
|
|
return 0, gerrors.WithAnnotating(ErrInvalidInput, "r is zero or bigger than the order N")
|
|
}
|
|
s := new(big.Int).SetBytes(data[:ECCRefMaxLen])
|
|
data = data[ECCRefMaxLen:]
|
|
n += ECCRefMaxLen
|
|
|
|
if s.Cmp(orderN) >= 0 || s.Sign() == 0 {
|
|
return 0, gerrors.WithAnnotating(ErrInvalidInput, "s is zero or bigger than the order N")
|
|
}
|
|
sig.R.Set(r)
|
|
sig.S.Set(s)
|
|
return n, nil
|
|
}
|
|
|
|
// MarshalBinary implements the encoding.BinaryMarshaler interface
|
|
// r || s
|
|
func (sig *Signature) MarshalBinary() ([]byte, error) {
|
|
data := make([]byte, 2*ECCRefMaxLen)
|
|
sig.R.Mod(sig.R, orderN)
|
|
sig.S.Mod(sig.S, orderN)
|
|
rBytes := sig.R.Bytes()
|
|
copy(data[ECCRefMaxLen-len(rBytes):], rBytes)
|
|
sBytes := sig.S.Bytes()
|
|
copy(data[2*ECCRefMaxLen-len(sBytes):], sBytes)
|
|
return data, nil
|
|
}
|
|
|
|
// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
|
|
func (sig *Signature) UnmarshalBinary(data []byte) error {
|
|
if len(data) != 2*ECCRefMaxLen {
|
|
return gerrors.WithAnnotating(ErrInvalidInput, "input data too short")
|
|
}
|
|
r := new(big.Int).SetBytes(data[:ECCRefMaxLen])
|
|
if r.Cmp(orderN) >= 0 || r.Sign() == 0 {
|
|
return gerrors.WithAnnotating(ErrInvalidInput, "r is zero or bigger than the order N")
|
|
}
|
|
s := new(big.Int).SetBytes(data[ECCRefMaxLen : 2*ECCRefMaxLen])
|
|
if s.Cmp(orderN) >= 0 || s.Sign() == 0 {
|
|
return gerrors.WithAnnotating(ErrInvalidInput, "s is zero or bigger than the order N")
|
|
}
|
|
sig.R.Set(r)
|
|
sig.S.Set(s)
|
|
return nil
|
|
}
|
|
|
|
func (sig *Signature) MarshalASN1() ([]byte, error) {
|
|
var b cryptobyte.Builder
|
|
b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) {
|
|
b.AddASN1BigInt(sig.R)
|
|
b.AddASN1BigInt(sig.S)
|
|
})
|
|
return b.Bytes()
|
|
}
|
|
|
|
func (sig *Signature) UnmarshalASN1(data []byte) error {
|
|
if sig.R == nil {
|
|
sig.R = new(big.Int)
|
|
}
|
|
if sig.S == nil {
|
|
sig.S = new(big.Int)
|
|
}
|
|
|
|
var inner cryptobyte.String
|
|
input := cryptobyte.String(data)
|
|
if !input.ReadASN1(&inner, asn1.SEQUENCE) ||
|
|
!input.Empty() ||
|
|
!inner.ReadASN1Integer(sig.R) ||
|
|
!inner.ReadASN1Integer(sig.S) ||
|
|
!inner.Empty() {
|
|
return ErrDecodeASN1Failed
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// SetBytes set Signature from a byte slice
|
|
func (sig *Signature) SetBytes(rs []byte) error {
|
|
if len(rs) < 2*byteSize {
|
|
return gerrors.WithAnnotating(ErrInvalidInput, "input data too short")
|
|
}
|
|
if sig.R == nil {
|
|
sig.R = new(big.Int)
|
|
}
|
|
|
|
if sig.S == nil {
|
|
sig.S = new(big.Int)
|
|
}
|
|
|
|
sig.R.SetBytes(rs[:byteSize])
|
|
sig.S.SetBytes(rs[byteSize : 2*byteSize])
|
|
return nil
|
|
}
|
|
|
|
// Bytes return byte slice of a signature
|
|
func (sig *Signature) Bytes() []byte {
|
|
buf := make([]byte, 2*byteSize)
|
|
_ = gmath.FillBytes(sig.R, buf[:byteSize])
|
|
_ = gmath.FillBytes(sig.S, buf[byteSize:])
|
|
return buf
|
|
}
|
|
|
|
// String return a readable string
|
|
func (sig *Signature) String() string {
|
|
var buf strings.Builder
|
|
buf.WriteString("r: ")
|
|
buf.WriteString(hex.EncodeToString(gmath.BigIntToNByte(sig.R, ECCRefMaxLen)))
|
|
buf.WriteString("\ns: ")
|
|
buf.WriteString(hex.EncodeToString(gmath.BigIntToNByte(sig.S, ECCRefMaxLen)))
|
|
return buf.String()
|
|
}
|
|
|
|
// update a random k in case when Sign got a random integer k error
|
|
// k's address are unchanged
|
|
func update(k []byte) {
|
|
hash := sm3.Sum(k)
|
|
copy(k, hash[:])
|
|
}
|
|
|
|
// fermatInverse calculates the inverse of k in GF(P) using Fermat's method.
|
|
// This has better constant-time properties than Euclid's method (implemented
|
|
// in math/big.Int.ModInverse) although math/big itself isn't strictly
|
|
// constant-time so it's not perfect.
|
|
// k = k^{-1} mod N
|
|
func fermatInverse(k, N *big.Int) {
|
|
// two := big.NewInt(2)
|
|
nMinus2 := new(big.Int)
|
|
nMinus2.Sub(N, gmath.BigInt2)
|
|
k.Exp(k, nMinus2, N)
|
|
}
|
|
|
|
// Sign 签名
|
|
// e: sm3(Z || M),使用PreComputeWithIdAndPubkeyAndMessage计算
|
|
// k: 32字节随机数
|
|
func Sign(e, k []byte, privateKey *PrivateKey) (*Signature, error) {
|
|
if len(e) < byteSize {
|
|
return nil, gerrors.WithAnnotatingf(ErrInvalidInput, "input e should be of %d bytes, but it is %d bytes", byteSize, len(e))
|
|
}
|
|
if len(k) < byteSize {
|
|
return nil, gerrors.WithAnnotatingf(ErrInvalidInput, "input k should be of %d bytes, but it is %d bytes", byteSize, len(k))
|
|
}
|
|
|
|
r := new(big.Int).SetBytes(e[:byteSize])
|
|
s := new(big.Int)
|
|
intK := new(big.Int)
|
|
|
|
// for only loop one time for almost all case
|
|
for {
|
|
intK.SetBytes(k[:byteSize])
|
|
if intK.Cmp(orderN) >= 0 {
|
|
intK.Sub(intK, orderN)
|
|
}
|
|
if intK.Sign() == 0 {
|
|
// omit the return error cause nMinusOne > 0
|
|
intK, _ = rand.Int(rand.Reader, nMinusOne)
|
|
}
|
|
// ScalarBaseMult is in constant-time
|
|
x1, _ := sm2Curve.ScalarBaseMult(intK.Bytes())
|
|
r.Add(x1, r) // r = x1 + e
|
|
r.Mod(r, orderN)
|
|
// rearly happen
|
|
if gmath.IsBigInt0(r) {
|
|
goto Next
|
|
}
|
|
|
|
// s = (1+d)^(-1)(k + r - r - r*d)=(1+d)^(-1) * (k+r) - r
|
|
s.Add(privateKey.D, gmath.BigInt1)
|
|
// invert s mod N costs much time
|
|
if f, ok := sm2Curve.(interface{ Inverse(*big.Int) *big.Int }); ok {
|
|
s = f.Inverse(s)
|
|
} else {
|
|
// s.ModInverse(s, orderN)
|
|
fermatInverse(s, orderN)
|
|
}
|
|
intK.Add(intK, r)
|
|
|
|
// k + r < 2N and k + r > N is the most likely case
|
|
if cmpResult := intK.Cmp(orderN); cmpResult > 0 {
|
|
intK.Sub(intK, orderN)
|
|
} else if cmpResult == 0 {
|
|
goto Next
|
|
}
|
|
|
|
s.Mul(s, intK)
|
|
s.Sub(s, r)
|
|
s.Mod(s, orderN)
|
|
break
|
|
Next:
|
|
// for another random k
|
|
update(k[:byteSize])
|
|
continue
|
|
}
|
|
return &Signature{R: r, S: s}, nil
|
|
}
|
|
|
|
// Verify 验签
|
|
// pk:公钥,不做验证pk是否有效,另调用pk.IsValid()判断pk是否是在曲线上。
|
|
//
|
|
// 当然如果pk无效,返回false
|
|
//
|
|
// e: sm3(Z || M),使用PreComputeWithIdAndPubkeyAndMessage计算
|
|
func Verify(e []byte, pk *PublicKey, sig *Signature) bool {
|
|
if len(e) != byteSize {
|
|
return false
|
|
}
|
|
|
|
r := sig.R
|
|
s := sig.S
|
|
|
|
if r.Sign() <= 0 || s.Sign() <= 0 ||
|
|
r.Cmp(orderN) >= 0 || s.Cmp(orderN) >= 0 {
|
|
return false
|
|
}
|
|
|
|
x := pk.X
|
|
y := pk.Y
|
|
t := new(big.Int).Add(r, s)
|
|
var x1, y1 *big.Int
|
|
if false {
|
|
t.Mod(t, orderN)
|
|
x1, y1 = sm2Curve.ScalarBaseMult(sig.S.Bytes())
|
|
x2, y2 := sm2Curve.ScalarMult(x, y, t.Bytes())
|
|
x1, _ = sm2Curve.Add(x1, y1, x2, y2)
|
|
} else {
|
|
x1, _ = ec256.CombinedMult(x, y, sig.S.Bytes(), t.Bytes())
|
|
}
|
|
t.SetBytes(e)
|
|
x1.Add(x1, t)
|
|
x1.Mod(x1, orderN)
|
|
return x1.Cmp(r) == 0
|
|
}
|