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
}
