Files
xgcl/tpc/sm2/sm2m/blindsign.go
T
2026-05-27 23:03:00 +08:00

155 lines
4.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package sm2m
import (
"crypto/rand"
"errors"
"io"
"math/big"
"xdx.jelly/xgcl/grand"
"xdx.jelly/xgcl/he/paillier"
"xdx.jelly/xgcl/sm/sm2"
"xdx.jelly/xgcl/sm/sm2/ec256"
)
// clientBlindSignContext 只能使用NewClientBlindSignContext来生成.
type clientBlindSignContext struct {
k1 *big.Int
rand io.Reader
paillierPrivateKey *paillier.PrivateKey
}
// NewClientSignContext 生成客户端协同签名上下文
// pk没有用,可以传nil, rnd是随机数发生器. paillierPrivateKey可以临时产生密钥,也可以产生长期的保存在客户端.
// 注: pk实际是用来验证完成后的签名. 这里由调用者自己验证即可.
func NewClientBlindSignContext(pk *sm2.PublicKey, paillierPrivateKey *paillier.PrivateKey, r io.Reader) *clientBlindSignContext {
c := &clientBlindSignContext{
k1: new(big.Int),
rand: r,
paillierPrivateKey: paillierPrivateKey,
}
return c
}
// Initial 客户端第一步, 返回e的同态密文和临时点P, 将他们同同态公钥一起发送给服务端.
//
// 客户端生成选择随机数k1 in [1, n - 1],计算e = SM3(Z || M), P = [k1]G,
// 其中Z为32字节杂凑值,G为基点,向服务端发送签名请求并将 Enc_paillier(e), P, 发送给服务端。
// 注: 同态公钥可以使用客户端的部分私钥对应的公钥签名,服务端验证.
func (c *clientBlindSignContext) Initial(e []byte) (ecipher *paillier.Cipher, p *sm2.PublicKey, 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, 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())
p = &sm2.PublicKey{Curve: sm2.Curve(), X: x, Y: y}
paillierPublicKey := c.paillierPrivateKey.Public()
ecipher, err = paillierPublicKey.Encrypt(new(big.Int).SetBytes(e), c.rand)
if err != nil {
return nil, nil, err
}
return ecipher, p, nil
}
// ServerSign 服务端计算. serverKey是服务端的部分密钥, pcipher,p和ppublickey是客户端发送过来的数据.
//
// 服务端生成随机数k2, k3, k4 in [1,n-1],(k = k1 * k2 + k3
// 计算(x1,y1)=[k2]P+[k3]G,
// rcipher = Enc(r) = Enc(e)*Enc(x1)
// s1 = k2*d2 mod n
// s2cipher = Enc(s2) = (Enc(r)*E(k_3))^ds * Enc(k4*n) = Enc(ds*(r+k3)+k4*n).
// 返回rcipher, s1, s2cipher, 并发送给客户端
func ServerBlindSign(serverKey *sm2.PrivateKey, ecipher *paillier.Cipher,
p *sm2.PublicKey, ppublickey *paillier.PublicKey, rnd io.Reader) (rcipher *paillier.Cipher, s1 *big.Int, s2cipher *paillier.Cipher, err error) {
var k2, k3, k4 *big.Int
for {
k2, err = rand.Int(rnd, sm2.OrderN())
if err != nil {
return nil, nil, nil, err
}
if k2.Sign() == 0 {
continue
}
k3, err = rand.Int(rnd, sm2.OrderN())
if err != nil {
return nil, nil, nil, err
}
if k3.Sign() == 0 {
continue
}
k4, err = rand.Int(rnd, sm2.OrderN())
if err != nil {
return nil, nil, nil, err
}
if k4.Sign() == 0 {
continue
}
break
}
x1, _ := ec256.CombinedMult(p.X, p.Y, k3.Bytes(), k2.Bytes())
x1cipher, err := ppublickey.Encrypt(x1, rnd)
if err != nil {
return nil, nil, nil, err
}
rcipher = x1cipher.HomomorphicAdd(x1cipher, ecipher, ppublickey)
s1 = new(big.Int)
s1.Mul(k2, serverKey.D)
s1.Mod(s1, sm2.OrderN())
s2cipher, err = ppublickey.Encrypt(k3, rnd)
if err != nil {
return nil, nil, nil, err
}
s2cipher.HomomorphicAdd(s2cipher, rcipher, ppublickey)
s2cipher.HomomorphicScalarMul(s2cipher, serverKey.D, ppublickey)
k4.Mul(k4, sm2.OrderN())
k4Cipher, err := ppublickey.Encrypt(k4, rnd)
if err != nil {
return nil, nil, nil, err
}
s2cipher.HomomorphicAdd(s2cipher, k4Cipher, ppublickey)
return rcipher, s1, s2cipher, nil
}
// Final 客户端计算签名
//
// 客户端解密rcipher, s2cipher得到r, s2,
// 计算s = d1*(k1*s1+s2)-r mod n,并检查s,r+s是否为0 mod q。
// 对消息M的签名为(r,s),客户端可验证签名是否正确.
func (c *clientBlindSignContext) Final(clientKey *sm2.PrivateKey,
rcipher *paillier.Cipher, s1 *big.Int, s2cipher *paillier.Cipher) (*sm2.Signature, error) {
r, err := c.paillierPrivateKey.Decrypt(rcipher)
if err != nil {
return nil, err
}
r.Mod(r, sm2.OrderN())
if r.Sign() == 0 {
return nil, errors.New("Blind sign failed, r = 0")
}
s2, err := c.paillierPrivateKey.Decrypt(s2cipher)
s2.Mod(s2, sm2.OrderN())
s := c.k1.Mul(c.k1, s1)
s.Add(s, s2).Mod(s, sm2.OrderN()).Mul(s, clientKey.D).Sub(s, r).Mod(s, sm2.OrderN())
if s.Sign() == 0 {
return nil, errors.New("Blind sign failed, s = 0")
}
c.k1 = nil
return &sm2.Signature{R: r, S: s}, nil
}