package implicitcert

import (
	"fmt"
	"io"
	"math/big"

	"xdx.jelly/xgcl/gmath"
	"xdx.jelly/xgcl/sm/sm2"
	"xdx.jelly/xgcl/sm/sm2/ec256"
	"xdx.jelly/xgcl/sm/sm3"
)

var errRandomReader = fmt.Errorf("Random Reader reads error")

// KGCComputeUserKey compute user's partial private key and declare public key
// TODO if r is nil, then w=KDF(H_A‖x_U‖y_U‖ks, 8×⌈(5×(log2n))/32⌉) mod n
func KGCComputeUserKey(id []byte,
	userPartialPublickey *sm2.PublicKey,
	kgcPrivateKey *sm2.PrivateKey,
	kgcPublicKey *sm2.PublicKey,
	r io.Reader) (kgcGeneratedUserPartialPrivateKey *sm2.PrivateKey, kgcGeneratedUserDeclarePublicKey *sm2.PublicKey, err error) {

	h := sm2.PreComputeWithIdAndPubkey(id, kgcPublicKey)
	w := make([]byte, sm2.ByteSize())
	if n, err := r.Read(w); n < sm2.ByteSize() || err != nil {
		return nil, nil, errRandomReader
	}
	// x, y := sm2.Curve().CombinedMult(userPartialPublickey.X, userPartialPublickey.Y, w, []byte{1})
	x, y := ec256.CombinedMult(userPartialPublickey.X, userPartialPublickey.Y, w, []byte{1})

	digest := sm3.Sum(gmath.BigIntToNByte(x, sm2.ByteSize()), gmath.BigIntToNByte(y, sm2.ByteSize()), h)
	t := new(big.Int)
	t.SetBytes(digest[:])
	t.Mul(t, kgcPrivateKey.Get())
	t.Mod(t, sm2.OrderN())
	t.Add(t, new(big.Int).SetBytes(w))
	t.Mod(t, sm2.OrderN())
	sk := &sm2.PrivateKey{PublicKey: sm2.PublicKey{X: x, Y: y}, D: t}
	return sk, &sk.PublicKey, nil
}
