init: v1.0.0

This commit is contained in:
yaole
2026-05-27 23:03:00 +08:00
commit 8d97f750eb
466 changed files with 80067 additions and 0 deletions
+54
View File
@@ -0,0 +1,54 @@
package outsource
import (
"crypto/rand"
"errors"
"io"
"math/big"
"xdx.jelly/xgcl/gerrors"
"xdx.jelly/xgcl/gmath"
"xdx.jelly/xgcl/he/paillier"
"xdx.jelly/xgcl/sm/sm2"
)
/*
============================= 生成授权密钥 ===============================
客户端 服务端
---------------------------request-------------------------->
Enc(pailliar, dc'),
虎符服务端公钥pk加密R: Enc(SM4GCM, k, R), Enc(SM2, pk, k)
<------------------------------------------------------------
解密dc'
组合授权包
*/
// OSGenerateAuthKey 外包服务根据用户的授权密钥密文生成授权密钥密文,以及给虎符服务端的授权因子R
// R由外包服务加密. (注,不能把R明文发给用户, 否则用户可以还原出自己的授权密钥)
func OSGenerateAuthKey(encryptedKey *paillier.Cipher, evalKey *paillier.PublicKey, rnd io.Reader) (*paillier.Cipher, []byte, error) {
var r *big.Int
var err error
for r == nil || gmath.IsBigInt0(r) {
r, err = rand.Int(rnd, sm2.OrderN())
if err != nil {
return nil, nil, errors.New("generate random number failed")
}
}
c := (&paillier.Cipher{}).HomomorphicScalarMul(encryptedKey, r, evalKey)
rBytes := make([]byte, sm2.ByteSize())
r.FillBytes(rBytes)
return c, rBytes, nil
}
// ClientDecryptAuthKey 客户端解密授权密钥密文, 小程序中实现.
func ClientDecryptAuthKey(encryptedAuthKey *paillier.Cipher, decKey *paillier.PrivateKey) (*sm2.PrivateKey, error) {
d, err := decKey.Decrypt(encryptedAuthKey)
if err != nil {
return nil, gerrors.WithAnnotating(err, "ClientDecryptAuthKey decrypt failed")
}
d.Mod(d, sm2.OrderN())
return (&sm2.PrivateKey{}).SetBigInt(d), nil
}
+115
View File
@@ -0,0 +1,115 @@
package outsource
import (
"math/big"
"testing"
"github.com/stretchr/testify/assert"
"xdx.jelly/xgcl/gmath"
"xdx.jelly/xgcl/grand"
"xdx.jelly/xgcl/he/paillier"
"xdx.jelly/xgcl/sm/sm2"
"xdx.jelly/xgcl/sm/sm3"
"xdx.jelly/xgcl/tpc/sm2/sm2m"
)
func BenchmarkOS(b *testing.B) {
// O、客户端生成paillier密钥
salt := grand.GetRandom(16)
paiPrivKey, err := paillier.GenerateKeyFromPassword(2048, []byte("password123"), salt, 1024)
assert.Nil(b, err)
paiPubKey := paiPrivKey.Public()
// 一、密钥生成
// 1)客户端第一步, a1, a2 发外包服务器
clientKeyGen := &ClientKeyGenerator{}
a1, a2, err := clientKeyGen.Step1(paiPubKey, grand.Reader)
assert.Nil(b, err)
// 2) 外包服务器第一步
// 保存encryptedClientKey1encryptedClientKey2,
// 把 P 发客户端
// encryptedClientKey1 -签名用
// encryptedClientKey2 -解密加密密钥保护结构用
osKenGen := &OSKeyGenerator{}
encryptedClientKey1, _, P, err := osKenGen.Step1(a1, a2, paiPubKey, grand.Reader)
assert.Nil(b, err)
// 3) 客户端第二步
// clientTempKey发协同签名服务端
clientTempKey, err := clientKeyGen.Step2(P)
// 4)协同签名服务器
// serverTempKey 发客户端,保存serverKey-服务端密钥分量
serverKey, serverTempKey, publicKey, _ := sm2m.ServerGenSignKey(clientTempKey, grand.GetRandom(32))
// 5)客户端第三步
// 把(serverTempKey,S)发送给外包服务器
S, err := clientKeyGen.Step3(serverTempKey)
assert.Nil(b, err)
// 6)外包服务器第二步
// 把T osPublicKey发给客户端。保存osPublicKey为用户签名公钥
T, osPublicKey, err := osKenGen.Step2(serverTempKey, S)
assert.Nil(b, err)
// 7)客户端第四步
// clientPublicKey, 客户端生成的公钥,如果没有返错,则应与ocPublicKey一致。
clientPublicKey, err := clientKeyGen.Step4(T)
assert.Nil(b, err)
assert.True(b, clientPublicKey.Equals(osPublicKey))
e := grand.GetRandom(32)
// 签名
b.ResetTimer()
for i := 0; i < b.N; i++ {
// 1)客户端发起请求
// 2)外包方计算
b.StartTimer()
outsourcintCtx := new(OSSignContext)
PPrime, err := outsourcintCtx.Step1(grand.Reader) // P'
assert.Nil(b, err)
// outsourcintCtx把PPrime发给客户端,保存outsourcintCtx.Marshal()
// 3) 客户端组合数据data = (e,p)=e||px||py并发送给协同服务端
b.StopTimer()
data := make([]byte, sm3.Size+2*sm2.ByteSize())
pos := copy(data, e)
pos += copy(data[pos:], gmath.BigIntToNByte(PPrime.X, sm2.ByteSize()))
copy(data[pos:], gmath.BigIntToNByte(PPrime.Y, sm2.ByteSize()))
// 4) 协同服务端计算,发回data
b.StartTimer()
data, err = sm2m.ServerSign(serverKey, data, grand.Reader)
assert.Nil(b, err)
// 5) 客户端解析data = r || s1 || s2, 把s1, s2发给外包服务器。
b.StopTimer()
r := new(big.Int)
r.SetBytes(data[:sm2.ByteSize()])
s1 := new(big.Int).SetBytes(data[sm2.ByteSize() : 2*sm2.ByteSize()])
s2 := new(big.Int).SetBytes(data[2*sm2.ByteSize():])
// 6) 外包服务器解析data并计算c,把c发送给客户端
b.StartTimer()
c, err := outsourcintCtx.Step2(s1, s2, encryptedClientKey1, paiPubKey)
assert.Nil(b, err)
// 7) 客户端计算签名值
b.StopTimer()
s, _ := paillier.Decrypt(c, paiPrivKey)
s.Sub(s, r)
s.Mod(s, sm2.OrderN())
sig := &sm2.Signature{
R: r,
S: s,
}
// 8) 客户端验证签名
assert.True(b, sm2.Verify(e, publicKey, sig))
}
}
+97
View File
@@ -0,0 +1,97 @@
package outsource
import (
"crypto/rand"
"errors"
"io"
"math/big"
"xdx.jelly/xgcl/grand"
"xdx.jelly/xgcl/he/paillier"
"xdx.jelly/xgcl/sm/sm2"
)
// osBlindSignContext 外包服务盲协同签名上下文. 使用NewOSBlindSignContext生成.
// 与盲签名外包服务端一致
type OSBlindSignContext struct {
OSSignContext
}
func NewOSBlindSignContext() *OSBlindSignContext {
return new(OSBlindSignContext)
}
// 盲签名客户端(与JS一致)
type clientBlindSignContext struct {
pprivateKey *paillier.PrivateKey
r *big.Int
k1pp *big.Int
rnd io.Reader
}
// NewClientBlindSignContext simple factory for creating clientBlindSignContext
func NewClientBlindSignContext(pprivateKey *paillier.PrivateKey, rnd io.Reader) *clientBlindSignContext {
ctx := &clientBlindSignContext{
pprivateKey: pprivateKey,
rnd: rnd,
}
if rnd == nil {
ctx.rnd = grand.Reader
}
return ctx
}
// Step1 客户端签名第一步 收到外包服务返回的pp, 返回ecipher, p给虎符服务端
//
// pp是外包服务第一步返回的P'=k1p*G
// 返回ecipher = Enc_paillier(e), p = k1p * k2pp * G
func (c *clientBlindSignContext) Step1(e []byte, pp *sm2.PublicKey) (ecipher *paillier.Cipher, p *sm2.PublicKey, err error) {
c.k1pp, err = rand.Int(c.rnd, sm2.OrderN())
if err != nil {
return nil, nil, err
}
x, y := sm2.Curve256.ScalarMult(pp.X, pp.Y, c.k1pp.Bytes())
p = &sm2.PublicKey{Curve: sm2.Curve(), X: x, Y: y}
ecipher, err = c.pprivateKey.Encrypt(new(big.Int).SetBytes(e), c.rnd)
return ecipher, p, err
}
// Step2 客户端签名第二步, 收到虎符服务端盲签名接口ServerBlindSign返回的rcipher, s1, s2cipher, 计算s1p, 把s1p, s2p给外包服务
func (c *clientBlindSignContext) Step2(rcipher *paillier.Cipher, s1 *big.Int, s2cipher *paillier.Cipher) (s1p *big.Int, s2p *big.Int, err error) {
c.r, err = c.pprivateKey.Decrypt(rcipher)
if err != nil {
return nil, nil, err
}
c.r.Mod(c.r, sm2.OrderN())
if c.r.Sign() == 0 {
return nil, nil, errors.New("Outsource sign failed, r = 0")
}
s1p = c.k1pp
c.k1pp = nil
s1p.Mul(s1p, s1).Mod(s1p, sm2.OrderN())
s2p, err = c.pprivateKey.Decrypt(s2cipher)
s2p.Mod(s2p, sm2.OrderN())
if err != nil {
return nil, nil, err
}
return s1p, s2p, nil
}
// Step3 客户端签名第三步, 收到外包服务返回的w = Enc(s+r), 输出签名
func (c *clientBlindSignContext) Step3(w *paillier.Cipher) (*sm2.Signature, error) {
s, err := c.pprivateKey.Decrypt(w)
if err != nil {
return nil, err
}
if s.Sign() == 0 {
return nil, errors.New("Outsource sign failed, s = 0")
}
s.Sub(s, c.r).Mod(s, sm2.OrderN())
r := c.r
c.r = nil
return &sm2.Signature{R: r, S: s}, nil
}
@@ -0,0 +1,52 @@
package outsource
import (
"testing"
"github.com/stretchr/testify/assert"
"xdx.jelly/xgcl/grand"
"xdx.jelly/xgcl/sm/sm2"
"xdx.jelly/xgcl/tpc/sm2/sm2m"
)
// 外包盲签名流程示例
func TestOSBlindSign(t *testing.T) {
//O、客户端生成paillier密钥
var err error
rnd := grand.Reader
paiPrivKey, paiPubKey, encryptedClientKey1, _, serverKey, publicKey := osGenerateKey(t)
e := make([]byte, 32)
rnd.Read(e)
clientCtx := NewClientBlindSignContext(paiPrivKey, rnd)
// 1) client -> os
// 2os -> client
osServerCtx := NewOSBlindSignContext()
pp, err := osServerCtx.Step1(rnd) // P'
assert.Nil(t, err)
// 3) client -> hfserver
ecipher, p, err := clientCtx.Step1(e, pp)
assert.Nil(t, err)
// 4) hfserver -> client
rcipher, s1, s2cipher, err := sm2m.ServerBlindSign(serverKey, ecipher, p, paiPubKey, rnd)
assert.Nil(t, err)
// 5) clinet -> os
s1p, s2p, err := clientCtx.Step2(rcipher, s1, s2cipher)
assert.Nil(t, err)
// 6) 外包服务器解析data并计算c,把c发送给客户端
w, err := osServerCtx.Step2(s1p, s2p, encryptedClientKey1, paiPubKey)
assert.Nil(t, err)
// 7) 客户端计算签名值
sig, err := clientCtx.Step3(w)
assert.Nil(t, err)
// 8) 客户端验证签名
assert.True(t, sm2.Verify(e, publicKey, sig))
}
+66
View File
@@ -0,0 +1,66 @@
package outsource
import (
"crypto/rand"
"io"
"math/big"
"xdx.jelly/xgcl/he/paillier"
"xdx.jelly/xgcl/sm/sm2"
)
var nGx = new(big.Int).Set(sm2.BaseX())
var nGy = new(big.Int).Sub(sm2.Prime(), sm2.BaseY())
// OSDecrypt 外包服务器使用签名密钥解密, C1 = (x,y)
func OSDecrypt(encryptedKey *paillier.Cipher, paiPubKey *paillier.PublicKey, xC1 *big.Int, yC1 *big.Int, rnd io.Reader) (*paillier.Cipher, *big.Int, *big.Int, error) {
var k1, k2 *big.Int
var err error
for {
k1, err = rand.Int(rnd, sm2.OrderN())
if err != nil {
return nil, nil, nil, err
}
if k1.Sign() > 0 {
break
}
}
for {
k2, err = rand.Int(rnd, sm2.OrderN())
if err != nil {
return nil, nil, nil, err
}
if k2.Sign() > 0 {
break
}
}
xF, yF := sm2.Curve256.ScalarMult(xC1, yC1, k1.Bytes())
k1.ModInverse(k1, sm2.OrderN())
blind, err := paiPubKey.Encrypt(k2.Mul(k2, sm2.OrderN()), rnd)
if err != nil {
return nil, nil, nil, err
}
E := new(paillier.Cipher).HomomorphicScalarMul(encryptedKey, k1, paiPubKey)
E.HomomorphicAdd(E, blind, paiPubKey)
return E, xF, yF, nil
}
type ClientDecContext struct {
}
// 客户端先把(x,y) = C1发送给外包服务器
func (*ClientDecContext) Step1(E *paillier.Cipher, xF, yF *big.Int, paiPrivKey *paillier.PrivateKey) (*big.Int, *big.Int, error) {
e, err := paiPrivKey.Decrypt(E)
e.Mod(e, sm2.OrderN())
if err != nil {
return nil, nil, err
}
x, y := sm2.Curve256.ScalarMult(xF, yF, e.Bytes())
return x, y, nil
}
func (*ClientDecContext) Step2(cipher *sm2.Cipher, x, y *big.Int) ([]byte, error) {
ny := new(big.Int).Sub(sm2.Prime(), cipher.Y)
xJ, yJ := sm2.Curve256.Add(x, y, cipher.X, ny)
return sm2.Decrypt_aux(xJ, yJ, cipher)
}
+94
View File
@@ -0,0 +1,94 @@
package outsource
import (
"crypto/rand"
"math/big"
"testing"
"github.com/stretchr/testify/assert"
"xdx.jelly/xgcl/gmath"
"xdx.jelly/xgcl/grand"
"xdx.jelly/xgcl/he/elgamal"
"xdx.jelly/xgcl/sm/sm2"
"xdx.jelly/xgcl/sm/sm3"
"xdx.jelly/xgcl/tpc/sm2/sm2m"
)
// 示例ElGamal 不能加入盲化因子。弃用。
func TestOutsourceWithElGamal(t *testing.T) {
clientKey, clientTempKey, _ := sm2m.ClientGenSignKey_one(grand.Reader)
serverKey, serverTempKey, publicKey, _ := sm2m.ServerGenSignKey(clientTempKey, grand.GetRandom(32))
err := sm2m.ClientGenSignKey_two(clientKey, serverTempKey, publicKey)
if err != nil {
t.Fatal("client's public key and server's public key are not equal.")
}
e := grand.GetRandom(32)
sk, pk, err := elgamal.GenerateKey(grand.Reader, elgamal.P1024)
assert.Nil(t, err)
encryptedClientKey, err := pk.Encryption(clientKey.D, grand.Reader)
assert.Nil(t, err)
// 受托方计算
k1, err := rand.Int(grand.Reader, sm2.OrderN())
assert.Nil(t, err)
px, py := sm2.Curve256.ScalarMult(sm2.BaseX(), sm2.BaseY(), k1.Bytes())
data := make([]byte, sm3.Size+2*sm2.ByteSize())
pos := copy(data, e)
pos += copy(data[pos:], gmath.BigIntToNByte(px, sm2.ByteSize()))
copy(data[pos:], gmath.BigIntToNByte(py, sm2.ByteSize()))
// data = (e,p) => 协同服务端
// 协同服务端计算
data, err = sm2m.ServerSign(serverKey, data, grand.Reader)
assert.Nil(t, err)
// data = (r||s1||s2)
r := new(big.Int)
r.SetBytes(data[:sm2.ByteSize()])
s1 := new(big.Int).SetBytes(data[sm2.ByteSize() : 2*sm2.ByteSize()])
s2 := new(big.Int).SetBytes(data[2*sm2.ByteSize():])
// s1, s2 => 受托方
s := big.NewInt(0).Mul(k1, s1)
s.Add(s, s2)
s.Mod(s, sm2.OrderN())
// 计算 c = Enc(dc*(k1*s1+s2))
S, err := pk.Encryption(s, grand.Reader)
assert.Nil(t, err)
c := &elgamal.Cipher{}
c, err = c.HomoMap(encryptedClientKey, S)
assert.Nil(t, err)
// 加入随机因子?HOW.
// k, err := rand.Int(grand.Reader, pk.Param.Q)
// assert.Nil(t, err)
// nminus1 := new(big.Int).Set(sm2.OrderN())
// k.Mul(k, nminus1)
// k.Mod(k, pk.Param.Q)
// k.Exp(pk.Param.G, k, pk.Param.P)
// c1, err := pk.Encryption(k, grand.Reader)
// assert.Nil(t, err)
// c.HomoMap(c, c1) // c = Enc(dc*(k1*s1+s2) * g^{K(N-1)})
// c 发送给委托方
// 委托方计算
s, err = sk.Decryption(c)
assert.Nil(t, err)
s.Sub(s, r)
s.Mod(s, sm2.OrderN())
sig := &sm2.Signature{
R: r,
S: s,
}
if !sm2.Verify(e, publicKey, sig) {
t.Fatal("verify failed")
}
}
+134
View File
@@ -0,0 +1,134 @@
package outsource
import (
"crypto/rand"
"errors"
"io"
"math/big"
"xdx.jelly/xgcl/gmath"
"xdx.jelly/xgcl/he/paillier"
"xdx.jelly/xgcl/sm/sm2"
)
// 客户端加密clientKey^{-1}给外包服务器保存,用作同态解密密钥
func EncryptClientDecKey(clientKey *sm2.PrivateKey, k *paillier.PublicKey, rnd io.Reader) (*paillier.Cipher, error) {
d := clientKey.D
di := new(big.Int).ModInverse(d, sm2.OrderN())
return k.Encrypt(di, rnd)
}
type ClientKeyGenerator struct {
dc1, dc1Inv *big.Int
}
// NewClientKeyGen 客户端第一步
// 返回数据发送给OS服务端
func (c *ClientKeyGenerator) Step1(k *paillier.PublicKey, rnd io.Reader) (*paillier.Cipher, *paillier.Cipher, error) {
var d *big.Int
var err error
for {
d, err = rand.Int(rnd, sm2.OrderN())
if err != nil {
return nil, nil, err
}
if d.Sign() > 0 {
break
}
}
di := new(big.Int).ModInverse(d, sm2.OrderN())
c.dc1 = d
c.dc1Inv = di
a1, err := k.Encrypt(d, rnd)
if err != nil {
return nil, nil, err
}
a2, err := k.Encrypt(di, rnd)
if err != nil {
return nil, nil, err
}
return a1, a2, nil
}
// GenerateDataToServer 客户端第二步
// 返回的sm2.PublicKey发送给协同签名服务端。
func (c *ClientKeyGenerator) Step2(P *sm2.PublicKey) (*sm2.PublicKey, error) {
x, y := sm2.Curve256.ScalarMult(P.X, P.Y, c.dc1Inv.Bytes())
return &sm2.PublicKey{Curve: sm2.Curve(), X: x, Y: y}, nil
}
// GenerateDataToServer 客户端第三步
// 收到协同签名服务端返回数据
func (c *ClientKeyGenerator) Step3(R *sm2.PublicKey) (*sm2.PublicKey, error) {
x, y := sm2.Curve256.ScalarMult(R.X, R.Y, c.dc1Inv.Bytes())
return &sm2.PublicKey{Curve: sm2.Curve(), X: x, Y: y}, nil
}
// GenerateDataToServer 客户端第四步
// 收到协同签名服务端返回数据
func (c *ClientKeyGenerator) Step4(T1 *sm2.PublicKey) (*sm2.PublicKey, error) {
x, y := sm2.Curve256.ScalarMult(T1.X, T1.Y, c.dc1Inv.Bytes())
x, y = sm2.Curve256.Add(x, y, nGx, nGy)
return &sm2.PublicKey{Curve: sm2.Curve(), X: x, Y: y}, nil
}
// OS服务端
type OSKeyGenerator struct {
dc2, dc2Inv *big.Int
}
func (o *OSKeyGenerator) Marshal() ([]byte, error) {
data := make([]byte, 64)
if o.dc2 != nil {
gmath.FillBytes(o.dc2, data)
}
if o.dc2Inv != nil {
gmath.FillBytes(o.dc2, data[32:])
}
return data, nil
}
func (o *OSKeyGenerator) Unmarshal(b []byte) error {
if len(b) < 64 {
return errors.New("input too short")
}
o.dc2 = new(big.Int).SetBytes(b[:32])
o.dc2Inv = new(big.Int).SetBytes(b[32:64])
return nil
}
// OSGenerateKey 外包服务器计算, 返回B1, B2, P
// 其中,保存B1, B2, B1用于签名,B2用于解密加密密钥保护结构。
// P发送给客户端。
func (o *OSKeyGenerator) Step1(a1 *paillier.Cipher, a2 *paillier.Cipher, pk *paillier.PublicKey, rnd io.Reader) (*paillier.Cipher, *paillier.Cipher, *sm2.PublicKey, error) {
var d *big.Int
var err error
for {
d, err = rand.Int(rnd, sm2.OrderN())
if err != nil {
return nil, nil, nil, err
}
if d.Sign() > 0 {
break
}
}
di := new(big.Int).ModInverse(d, sm2.OrderN())
o.dc2 = d
o.dc2Inv = di
x, y := sm2.Curve256.ScalarBaseMult(di.Bytes())
b1 := new(paillier.Cipher).HomomorphicScalarMul(a1, d, pk)
b2 := new(paillier.Cipher).HomomorphicScalarMul(a2, di, pk)
return b1, b2, &sm2.PublicKey{Curve: sm2.Curve(), X: x, Y: y}, nil
}
func (o *OSKeyGenerator) Step2(R *sm2.PublicKey, S *sm2.PublicKey) (*sm2.PublicKey, *sm2.PublicKey, error) {
x1, y1 := sm2.Curve256.ScalarMult(R.X, R.Y, o.dc2Inv.Bytes())
x2, y2 := sm2.Curve256.ScalarMult(S.X, S.Y, o.dc2Inv.Bytes())
x, y := sm2.Curve256.Add(x2, y2, nGx, nGy)
return &sm2.PublicKey{Curve: sm2.Curve(), X: x1, Y: y1}, &sm2.PublicKey{Curve: sm2.Curve(), X: x, Y: y}, nil
}
+166
View File
@@ -0,0 +1,166 @@
package outsource
import (
"crypto/rand"
"errors"
"io"
"math/big"
"xdx.jelly/xgcl/grand"
"xdx.jelly/xgcl/he/paillier"
"xdx.jelly/xgcl/sm/sm2"
)
// 外包服务计算
type OSSignContext struct {
k1p *big.Int
}
func NewOSSignContext() *OSSignContext {
return &OSSignContext{}
}
// Step1 需要临时保存k1
func (o *OSSignContext) Step1(rnd io.Reader) (pp *sm2.PublicKey, err error) {
for {
k, err := rand.Int(rnd, sm2.OrderN())
if err != nil {
return nil, err
}
if k.Sign() == 0 {
continue
}
x, y := sm2.Curve256.ScalarBaseMult(k.Bytes())
o.k1p = k
pp = &sm2.PublicKey{Curve: sm2.Curve(), X: x, Y: y}
return pp, nil
}
}
// Step2 input s1 in [1, N-1]
func (o *OSSignContext) Step2(s1 *big.Int, s2 *big.Int, encryptedKey *paillier.Cipher, evalKey *paillier.PublicKey) (w *paillier.Cipher, err error) {
if o.k1p == nil || o.k1p.Sign() == 0 {
return nil, errors.New("call Prepare first")
}
if s1 == nil || s2 == nil {
return nil, errors.New("s1 or s2 is nil")
}
// s1, s2不能为0 mod n, 否则外包服务可能被套取到用户的密钥.
if s1.Sign() <= 0 || s1.Cmp(sm2.OrderN()) >= 0 || s2.Sign() <= 0 || s2.Cmp(sm2.OrderN()) >= 0 {
return nil, errors.New("s1 or s2 not in range [1, N-1]")
}
s := new(big.Int).Mul(o.k1p, s1)
s.Add(s, s2).Mod(s, sm2.OrderN()) // s = k*s1 + s2 mod N
// check s = 0?
// 计算 w = encryptedClientKey^s mod n^2 = Enc(ds * s)
w = (&paillier.Cipher{}).HomomorphicScalarMul(encryptedKey, s, evalKey)
// blind the result
if true {
k, err := rand.Int(grand.Reader, sm2.OrderN())
if err != nil {
return nil, err
}
k.Mul(k, sm2.OrderN())
w.HomomorphicAddInt(w, k, evalKey)
} else {
kn, err := rand.Int(grand.Reader, sm2.OrderN())
if err != nil {
return nil, err
}
kn.Mul(kn, sm2.OrderN())
blind, err := paillier.Encrypt(kn, evalKey, grand.Reader)
if err != nil {
return nil, err
}
w.HomomorphicAdd(w, blind, evalKey) // c = Enc(dc*(k1*s1+s2) + k*N)
}
return w, nil
}
// outsourcingContext 需要序列化后保存到redis中
func (o *OSSignContext) Marshal() ([]byte, error) {
buf := make([]byte, sm2.ByteSize())
return o.k1p.FillBytes(buf), nil
}
func (o *OSSignContext) Unmarshal(b []byte) error {
if len(b) != sm2.ByteSize() {
return errors.New("input data invalid")
}
if o.k1p == nil {
o.k1p = new(big.Int)
}
o.k1p.SetBytes(b)
return nil
}
// clientSignContext 外包服务客户端(与JS的outsource.ClientSigner一致)
type clientSignContext struct {
pprivateKey *paillier.PrivateKey
r *big.Int
k1pp *big.Int
rnd io.Reader
}
// NewClientSignContext simple factory for creating clientSignContext.
func NewClientSignContext(pprivateKey *paillier.PrivateKey, rnd io.Reader) *clientSignContext {
ctx := &clientSignContext{
pprivateKey: pprivateKey,
rnd: rnd,
}
if rnd == nil {
ctx.rnd = grand.Reader
}
return ctx
}
// Step1 客户端签名第一步 返回p给虎符服务端
//
// pp是外包服务第一步返回的P'=k1p*G
// 返回p = k1p * k2pp * G
func (c *clientSignContext) Step1(e []byte, pp *sm2.PublicKey) (p *sm2.PublicKey, err error) {
c.k1pp, err = rand.Int(c.rnd, sm2.OrderN())
if err != nil {
return nil, err
}
x, y := sm2.Curve256.ScalarMult(pp.X, pp.Y, c.k1pp.Bytes())
p = &sm2.PublicKey{Curve: sm2.Curve(), X: x, Y: y}
return p, nil
}
// Step2 客户端签名第二步, 收到虎符服务端返回的r, s1, s2, 计算s1p, 把s1p, s2p给外包服务
func (c *clientSignContext) Step2(r *big.Int, s1 *big.Int, s2 *big.Int) (s1p *big.Int, s2p *big.Int, err error) {
c.r = r
if r.Sign() == 0 {
return nil, nil, errors.New("Outsource sign failed, r = 0")
}
s1p = c.k1pp
c.k1pp = nil
s1p.Mul(s1p, s1).Mod(s1p, sm2.OrderN())
s2p = s2
return s1p, s2p, nil
}
// Step3 客户端签名第三步, 收到外包服务返回的w = Enc(s+r), 输出签名
func (c *clientSignContext) Step3(w *paillier.Cipher) (*sm2.Signature, error) {
s, err := c.pprivateKey.Decrypt(w)
if err != nil {
return nil, err
}
if s.Sign() == 0 {
return nil, errors.New("Outsource sign failed, s = 0")
}
s.Sub(s, c.r).Mod(s, sm2.OrderN())
r := c.r
c.r = nil
return &sm2.Signature{R: r, S: s}, nil
}
+271
View File
@@ -0,0 +1,271 @@
package outsource
import (
"bytes"
"math/big"
"testing"
"github.com/stretchr/testify/assert"
"xdx.jelly/xgcl/gmath"
"xdx.jelly/xgcl/grand"
"xdx.jelly/xgcl/he/paillier"
"xdx.jelly/xgcl/sm/sm2"
"xdx.jelly/xgcl/sm/sm3"
"xdx.jelly/xgcl/tpc/sm2/sm2m"
)
// osGenerateKey 客户端,外包,服务端协同密钥生成
func osGenerateKey(t *testing.T) (*paillier.PrivateKey, *paillier.PublicKey, *paillier.Cipher, *paillier.Cipher, *sm2.PrivateKey, *sm2.PublicKey) {
rnd := grand.Reader
salt := []byte("12345678")
paiPrivKey, err := paillier.GenerateKeyFromPassword(2048, []byte("password123"), salt, 1024)
assert.Nil(t, err)
paiPubKey := paiPrivKey.Public()
// 一、密钥生成
// 1)客户端第一步, a1, a2 发 外包服务器
clientKeyGen := &ClientKeyGenerator{}
a1, a2, err := clientKeyGen.Step1(paiPubKey, rnd)
assert.Nil(t, err)
// 2) 外包服务器第一步
// 保存encryptedClientKey1encryptedClientKey2,
// 把 P 发客户端
// encryptedClientKey1 -签名用
// encryptedClientKey2 -解密加密密钥保护结构用
osKenGen := &OSKeyGenerator{}
encryptedClientKey1, encryptedClientKey2, P, err := osKenGen.Step1(a1, a2, paiPubKey, rnd)
assert.Nil(t, err)
// 3) 客户端第二步
// clientTempKey发协同签名服务端
clientTempKey, err := clientKeyGen.Step2(P)
// 4)协同签名服务器
// serverTempKey 发客户端,保存serverKey-服务端密钥分量
b := make([]byte, 32)
rnd.Read(b)
serverKey, serverTempKey, publicKey, _ := sm2m.ServerGenSignKey(clientTempKey, b)
// 5)客户端第三步
// 把(serverTempKey,S)发送给外包服务器
S, err := clientKeyGen.Step3(serverTempKey)
assert.Nil(t, err)
// 6)外包服务器第二步
// 把T osPublicKey发给客户端。保存osPublicKey为用户签名公钥
T, osPublicKey, err := osKenGen.Step2(serverTempKey, S)
assert.Nil(t, err)
// 7)客户端第四步
// clientPublicKey, 客户端生成的公钥,如果没有返错,则应与ocPublicKey一致。
clientPublicKey, err := clientKeyGen.Step4(T)
assert.Nil(t, err)
assert.True(t, clientPublicKey.Equals(osPublicKey))
return paiPrivKey, paiPubKey, encryptedClientKey1, encryptedClientKey2, serverKey, publicKey
}
// 外包签名流程
func TestOSSign(t *testing.T) {
//O、生成密钥
var err error
rnd := grand.Reader
paiPrivKey, paiPubKey, encryptedClientKey1, _, serverKey, publicKey := osGenerateKey(t)
e := make([]byte, 32)
rnd.Read(e)
clientCtx := NewClientSignContext(paiPrivKey, rnd)
// 1) client -> os
// 2os -> client
osServerCtx := NewOSSignContext()
pp, err := osServerCtx.Step1(rnd) // P'
assert.Nil(t, err)
// 3) client -> hfserver
p, err := clientCtx.Step1(e, pp)
assert.Nil(t, err)
// 组合数据data = (e,p)=e||px||py并发送给协同服务端
data := make([]byte, sm3.Size+2*sm2.ByteSize())
pos := copy(data, e)
pos += copy(data[pos:], gmath.BigIntToNByte(p.X, sm2.ByteSize()))
copy(data[pos:], gmath.BigIntToNByte(p.Y, sm2.ByteSize()))
// 4) hfserver -> client
data, err = sm2m.ServerSign(serverKey, data, rnd)
assert.Nil(t, err)
// 5) clinet -> os
// 解析数据
r := new(big.Int).SetBytes(data[:sm2.ByteSize()])
s1 := new(big.Int).SetBytes(data[sm2.ByteSize() : 2*sm2.ByteSize()])
s2 := new(big.Int).SetBytes(data[2*sm2.ByteSize():])
s1p, s2p, err := clientCtx.Step2(r, s1, s2)
assert.Nil(t, err)
// 6) 外包服务器解析data并计算c,把c发送给客户端
w, err := osServerCtx.Step2(s1p, s2p, encryptedClientKey1, paiPubKey)
assert.Nil(t, err)
// 7) 客户端计算签名值
sig, err := clientCtx.Step3(w)
assert.Nil(t, err)
// 8) 客户端验证签名
assert.True(t, sm2.Verify(e, publicKey, sig))
}
// 外包计算完整流程示例
// deprecated: 签名的客户端第3和第5步有遗失. 签名见上面的流程TestOSSign. 相当于客户端选择了随机数k1” = 1.
func TestOutsourceWithPaillier(t *testing.T) {
//O、客户端生成paillier密钥
var err error
paiPrivKey, paiPubKey, encryptedClientKey1, encryptedClientKey2, serverKey, publicKey := osGenerateKey(t)
// 外包服务收到客户端发来的同态公钥
paiPubKeyClientData, _ := paiPubKey.Marshal()
paiPubKey = new(paillier.PublicKey)
err = paiPubKey.Unmarshal(paiPubKeyClientData)
// 外包服务将公钥数据paiPubKeyServerData存储数据库中, 包括预计算数据.
paiPubKeyServerData, _ := paiPubKey.MarshalExt()
// 外包服务从数据库中恢复用户的同态公钥, 用于外包同态计算.
_ = paiPubKey.UnmarshalExt(paiPubKeyServerData)
rnd := grand.Reader
_, _ = encryptedClientKey1, rnd
/*
// 二、签名
// 1)客户端发起请求
e := make([]byte, 32)
rnd.Read(e)
// 2)外包方计算
outsourcintCtx := new(OSSignContext)
PPrime, err := outsourcintCtx.Step1(rnd) // P'
assert.Nil(t, err)
// outsourcintCtx把PPrime发给客户端,保存outsourcintCtx.Marshal()
// 3) 客户端组合数据data = (e,p)=e||px||py并发送给协同服务端
data := make([]byte, sm3.Size+2*sm2.ByteSize())
pos := copy(data, e)
pos += copy(data[pos:], gmath.BigIntToNByte(PPrime.X, sm2.ByteSize()))
copy(data[pos:], gmath.BigIntToNByte(PPrime.Y, sm2.ByteSize()))
// 4) 协同服务端计算,发回data
data, err = sm2m.ServerSign(serverKey, data, rnd)
assert.Nil(t, err)
// 5) 客户端解析data = r || s1 || s2, 把s1, s2发给外包服务器。
r := new(big.Int)
r.SetBytes(data[:sm2.ByteSize()])
s1 := new(big.Int).SetBytes(data[sm2.ByteSize() : 2*sm2.ByteSize()])
s2 := new(big.Int).SetBytes(data[2*sm2.ByteSize():])
// 6) 外包服务器解析data并计算c,把c发送给客户端
c, err := outsourcintCtx.Step2(s1, s2, encryptedClientKey1, paiPubKey)
assert.Nil(t, err)
// 7) 客户端计算签名值
s, _ := paillier.Decrypt(c, paiPrivKey)
s.Sub(s, r)
s.Mod(s, sm2.OrderN())
sig := &sm2.Signature{
R: r,
S: s,
}
// 8) 客户端验证签名
assert.True(t, sm2.Verify(e, publicKey, sig))
*/
// 三、使用签名密钥解密
plaintext := grand.GetRandom(16)
cipher, err := sm2.Encrypt(publicKey, plaintext, grand.GetRandom(32))
assert.Nil(t, err)
// 1) 客户端把(x,y)=C1 发送给外包服务器
// 2)外包服务计算, 把paiCipher, xF, yF发送给客户端
paiCipher, xF, yF, err := OSDecrypt(encryptedClientKey2, paiPubKey, cipher.X, cipher.Y, grand.Reader)
assert.Nil(t, err)
// 3) 客户端计算
clientDecCtx := &ClientDecContext{}
xH, yH, err := clientDecCtx.Step1(paiCipher, xF, yF, paiPrivKey)
assert.Nil(t, err)
// 4) 协同签名服务器计算
inData := make([]byte, 2*sm2.ByteSize())
xH.FillBytes(inData[:sm2.ByteSize()])
yH.FillBytes(inData[sm2.ByteSize():])
outData, err := sm2m.ServerDec(serverKey, inData)
// 5) 客户端计算
x := new(big.Int).SetBytes(outData[:sm2.ByteSize()])
y := new(big.Int).SetBytes(outData[sm2.ByteSize():])
decPlain, err := clientDecCtx.Step2(cipher, x, y)
assert.Nil(t, err)
assert.True(t, bytes.Equal(plaintext, decPlain))
// 四、解密密钥分拆
// 假设客户端解密得到的解密密钥de
de, err := sm2.GenerateKey(sm2.Curve(), grand.Reader)
assert.Nil(t, err)
// 客户端分拆解密密钥, deServer给协同签名服务端
deClient, deServer, err := sm2m.SplitDecryptKey(de, grand.Reader)
assert.Nil(t, err)
// 加密deClient给外包服务端保存。
encryptedEncKey, err := EncryptClientDecKey(deClient, paiPubKey, grand.Reader)
assert.Nil(t, err)
// 五、使用解密密钥解密(同使用签名密钥解密)
plaintext = grand.GetRandom(16)
cipher, err = sm2.Encrypt(&de.PublicKey, plaintext, grand.GetRandom(32))
assert.Nil(t, err)
// (一)对比非OS的协同解密
clientCTX := sm2m.NewClientDecContext()
out, _ := clientCTX.Initial(cipher)
out, _ = sm2m.ServerDec(deServer, out)
decPlain, _ = clientCTX.Final(deClient, out)
assert.True(t, bytes.Equal(plaintext, decPlain))
// (二)OS解密
// 1) 客户端把(x,y)=C1 发送给外包服务器
// 2)外包服务计算, 把paiCipher, xF, yF发送给客户端
paiCipher, xF, yF, err = OSDecrypt(encryptedEncKey, paiPubKey, cipher.X, cipher.Y, grand.Reader)
assert.Nil(t, err)
// 3) 客户端计算
clientDecCtx = &ClientDecContext{}
xH, yH, err = clientDecCtx.Step1(paiCipher, xF, yF, paiPrivKey)
assert.Nil(t, err)
// 4) 协同签名服务器计算
inData = make([]byte, 2*sm2.ByteSize())
xH.FillBytes(inData[:sm2.ByteSize()])
yH.FillBytes(inData[sm2.ByteSize():])
outData, err = sm2m.ServerDec(deServer, inData)
// 5) 客户端计算
x = new(big.Int).SetBytes(outData[:sm2.ByteSize()])
y = new(big.Int).SetBytes(outData[sm2.ByteSize():])
decPlain, err = clientDecCtx.Step2(cipher, x, y)
assert.Nil(t, err)
assert.True(t, bytes.Equal(plaintext, decPlain))
}