package sm2m import ( "fmt" "io" "math/big" "xdx.jelly/xgcl/gmath" "xdx.jelly/xgcl/grand" "xdx.jelly/xgcl/sm/sm2" "xdx.jelly/xgcl/sm/sm2/ec256" "xdx.jelly/xgcl/sm/sm3" ) type ClientSignContext struct { k1 *big.Int rand io.Reader } // NewClientSignContext 生成客户端协同签名上下文 // pk没有用,可以传nil, rnd是随机数发生器. // 注: pk实际是用来验证完成后的签名. 这里由调用者自己验证即可. func NewClientSignContext(pk *sm2.PublicKey, rnd io.Reader) *ClientSignContext { c := &ClientSignContext{ k1: new(big.Int), rand: rnd, } return c } /* a) 客户端选择随机数k1 in [1, n - 1],计算e = SM3(Z || M), P = [k1]G, 其中Z为32字节杂凑值,G为基点,向服务端发送签名请求 同时将out = e, P加密为发送给服务端。 */ func (c *ClientSignContext) Initial(e []byte) (out []byte, err error) { if c.rand == nil { c.rand = grand.Reader } if c.k1 == nil { c.k1 = new(big.Int) } buf := make([]byte, sm2.ByteSize()) if n, err := c.rand.Read(buf); n != len(buf) || err != nil { return nil, err } c.k1.SetBytes(buf) c.k1.Mod(c.k1, sm2.OrderN()) x, y := sm2.Curve256.ScalarMult(sm2.BaseX(), sm2.BaseY(), c.k1.Bytes()) out = make([]byte, sm3.Size+2*sm2.ByteSize()) pos := copy(out, e) pos += copy(out[pos:], gmath.BigIntToNByte(x, sm2.ByteSize())) copy(out[pos:], gmath.BigIntToNByte(y, sm2.ByteSize())) return out, nil } /* c) 客户端计算s= d1(k1s1+s2) - r mod n,并检查s,r+s是否为0 mod q。 对消息M的签名为(r,s),客户端可验证签名是否正确。 */ func (c *ClientSignContext) Final(clientKey *sm2.PrivateKey, in []byte) (*sm2.Signature, error) { sig := sm2.NewSignature() sig.R.SetBytes(in[:sm2.ByteSize()]) s1 := new(big.Int).SetBytes(in[sm2.ByteSize() : 2*sm2.ByteSize()]) s2 := new(big.Int).SetBytes(in[2*sm2.ByteSize():]) s1.Mul(s1, c.k1) s1.Add(s1, s2) s1.Mod(s1, sm2.OrderN()) s1.Mul(s1, clientKey.D) s1.Sub(s1, sig.R) s1.Mod(s1, sm2.OrderN()) sig.S.Set(s1) return sig, nil } /* b) in = e || P 服务端生成随机数k2, k3 in [1,n-1],(k = k1 * k2 + k3) 计算(x1,y1)=[k2]P+[k3]G, r=e+x1 mod n , 检查r是否为0,为0则重新生成k2,重新计算。 计算s1=k2d2 mod n, s2=d2(k3+r) mod n, 输出 r || s1 || s2 */ func ServerSign(serverKey *sm2.PrivateKey, in []byte, rand io.Reader) ([]byte, error) { k2 := make([]byte, sm2.ByteSize()) if n, err := rand.Read(k2); n != len(k2) || err != nil { return nil, err } k3 := make([]byte, sm2.ByteSize()) if n, err := rand.Read(k3); n != len(k3) || err != nil { return nil, err } r := new(big.Int).SetBytes(in[:sm2.ByteSize()]) px := new(big.Int).SetBytes(in[sm2.ByteSize() : 2*sm2.ByteSize()]) py := new(big.Int).SetBytes(in[2*sm2.ByteSize() : 3*sm2.ByteSize()]) // x1, _ := sm2.Curve().CombinedMult(px, py, k3, k2) x1, _ := ec256.CombinedMult(px, py, k3, k2) r.Add(r, x1) r.Mod(r, sm2.OrderN()) if gmath.IsBigInt0(r) { return nil, fmt.Errorf("rebuild") } out := make([]byte, 0, 3*sm2.ByteSize()) out = append(out, gmath.BigIntToNByte(r, sm2.ByteSize())...) s := new(big.Int).SetBytes(k2) s.Mul(s, serverKey.D) s.Mod(s, sm2.OrderN()) out = append(out, gmath.BigIntToNByte(s, sm2.ByteSize())...) s.SetBytes(k3) s.Add(s, r) s.Mul(s, serverKey.D) s.Mod(s, sm2.OrderN()) out = append(out, gmath.BigIntToNByte(s, sm2.ByteSize())...) return out, nil }