package concentration

import (
	"bytes"
	"fmt"
	"testing"

	"xdx.jelly/xgcl/gmath"
	"xdx.jelly/xgcl/grand"
	"xdx.jelly/xgcl/sm/sm2"
)

func TestSign(t *testing.T) {
	fmt.Println("============= 生成密钥 =============")
	clientID := []byte("Teacher Tony")
	serverKeyGenCTX := NewServerKeyGenContext()
	clientKeyGenCTX := NewClientKeyGenContext()

	// 1 server调用密码机获取32字节随机数。 GenerateAgreementData传出数据发送给客户端。
	data, err := serverKeyGenCTX.GenerateAgreementData(grand.GetRandom(sm2.ByteSize()))
	if err != nil {
		panic(err)
	}

	//2 client 调用生成数据和公钥
	data, clientPK, err := clientKeyGenCTX.GenerateAgreementData(data, clientID)
	if err != nil {
		panic(err)
	}

	// 3 server 计算密钥对
	sk, serverPK, err := serverKeyGenCTX.ComputeKeyPair(data, clientID)
	if err != nil {
		panic(err)
	}

	// 服务端清除敏感信息
	serverKeyGenCTX.Clear()

	if !serverPK.Equals(clientPK) {
		panic("clientPK != serverPK")
	}
	fmt.Println("server pubkey: ", serverPK)
	fmt.Println("client pubkey: ", clientPK)
	fmt.Printf("sk: %02x\n", sk)
	fmt.Println()

	fmt.Println("============= 签名 =============")
	e := grand.GetRandom(32)
	serverSignCTX := NewServerSignContext()
	clientSignCTX := NewClientSignContext()

	data, err = serverSignCTX.GenerateSignData(grand.GetRandom(32))
	if err != nil {
		panic(err)
	}

	data, clientR, err := clientSignCTX.GenerateSignData(data, e)
	if err != nil {
		panic(err)
	}

	sig, err := serverSignCTX.Sign(data, e, sk)
	if err != nil {
		panic(err)
	}

	sk.Clear()
	fmt.Println("sig: ", sig)
	fmt.Printf("client's r: %02x\n", clientR)
	fmt.Println("serverPK verify: ", sm2.Verify(e, serverPK, sig))
	fmt.Println("clientPK verify: ", sm2.Verify(e, clientPK, sig))
	if (bytes.Compare(clientR, gmath.BigIntToNByte(sig.R, 32))) != 0 {
		panic("client r != server r")
	}

}

func TestMarshal(t *testing.T) {
	ctx := NewServerSignContext()
	ctx.k1 = sm2.NewPrivateKey().Random(grand.Reader)
	ctx.u = sm2.NewPublicKey().Generate(ctx.k1)
	ctx.clientPPub = sm2.NewPublicKey().Generate(sm2.NewPrivateKey().Random(grand.Reader))
	buf, err := ctx.MarshalBinary()
	if err != nil {
		fmt.Println(err)
	}
	fmt.Printf("%x\n\n", buf)

	ctx1 := NewServerSignContext()
	err = ctx1.UnmarshalBinary(buf)
	if err != nil {
		fmt.Println(err)
	}
	buf, err = ctx1.MarshalBinary()
	if err != nil {
		fmt.Println(err)
	}
	fmt.Printf("%x\n\n", buf)

	if ctx1.k1.D.Cmp(ctx.k1.D) != 0 {
		t.Log()
		t.Fail()
	}
	if !ctx1.u.Equals(ctx.u) {
		t.Log()
		t.Fail()
	}

	if !ctx1.clientPPub.Equals(ctx.clientPPub) {
		t.Log()
		t.Fail()
	}
}
