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)
}
