package sm2a

import (
	"crypto/rand"
	"encoding/binary"
	"fmt"
	"io"
	"math/big"

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

type ServerSignKeyGenContext struct {
	B [SecureParam]*big.Int
	X [SecureParam]*big.Int

	ServerKey    *sm2.PrivateKey
	PubKey       *sm2.PublicKey
	ServerSubKey *sm2.PrivateKey // ServerSubKey * ClientSubKey = 1+d

	isServerKeyReady bool
}

func NewServerSignKeyGenContext() *ServerSignKeyGenContext {
	s := new(ServerSignKeyGenContext)
	for i := 0; i < SecureParam; i++ {
		s.B[i] = new(big.Int)
		s.X[i] = new(big.Int)
	}
	s.ServerKey = sm2.NewPrivateKey()
	s.PubKey = sm2.NewPublicKey()
	s.ServerSubKey = sm2.NewPrivateKey()

	return s
}

func (s *ServerSignKeyGenContext) GetServerKey() (*sm2.PrivateKey, error) {
	if s.isServerKeyReady {
		return s.ServerKey, nil
	}
	return nil, fmt.Errorf("Key agreement not finished")
}

func (s *ServerSignKeyGenContext) GetServerSubKey() (*sm2.PrivateKey, error) {
	if s.isServerKeyReady {
		return s.ServerSubKey, nil
	}
	return nil, fmt.Errorf("Key agreement not finished")
}

func (s *ServerSignKeyGenContext) GetPublicKey() (*sm2.PublicKey, error) {
	if s.isServerKeyReady {
		return s.PubKey, nil
	}
	return nil, fmt.Errorf("Key agreement not finished")
}

// MarshalBinary 保存ServerSignKeyGenContext
func (s *ServerSignKeyGenContext) MarshalBinary() ([]byte, error) {
	out := make([]byte, 0, 8432)
	size := sm2.ByteSize()
	N := sm2.OrderN()

	// binary.BigEndian.PutUint32(out[:4], uint32(SecureParam))
	for i := 0; i < SecureParam; i++ {
		s.B[i].Mod(s.B[i], N)
		out = append(out, gmath.BigIntToNByte(s.B[i], size)...)
		s.X[i].Mod(s.X[i], N)
		out = append(out, gmath.BigIntToNByte(s.X[i], size)...)

	}
	// s.ServerSubKey.Mod(s.ServerSubKey, N)
	// out = append(out, gmath.BigIntToNByte(s.ServerSubKey, size)...)

	var buf4 [4]byte
	buf, err := s.ServerSubKey.MarshalBinary()
	if err != nil {
		return nil, err
	}
	binary.BigEndian.PutUint32(buf4[:], uint32(len(buf)))
	out = append(out, buf4[:]...)
	out = append(out, buf...)

	buf, err = s.ServerKey.MarshalBinary()
	if err != nil {
		return nil, err
	}
	binary.BigEndian.PutUint32(buf4[:], uint32(len(buf)))
	out = append(out, buf4[:]...)
	out = append(out, buf...)

	buf, err = s.PubKey.MarshalBinary()
	if err != nil {
		return nil, err
	}
	binary.BigEndian.PutUint32(buf4[:], uint32(len(buf)))
	out = append(out, buf4[:]...)
	out = append(out, buf...)

	if s.isServerKeyReady {
		out = append(out, 1)
	} else {
		out = append(out, 0)
	}
	return out, nil
}

// UnmarshalBinary 恢复ServerSignKeyGenContext
func (s *ServerSignKeyGenContext) UnmarshalBinary(b []byte) error {
	size := sm2.ByteSize()

	for i := 0; i < SecureParam; i++ {
		s.B[i].SetBytes(b[:size])
		b = b[size:]
		s.X[i].SetBytes(b[:size])
		b = b[size:]
	}

	// s.ServerSubKey.SetBytes(b[:size])
	// b = b[size:]

	len := binary.BigEndian.Uint32(b)
	b = b[4:]
	if err := s.ServerSubKey.UnmarshalBinary(b[:len]); err != nil {
		return err
	}
	b = b[len:]

	len = binary.BigEndian.Uint32(b)
	b = b[4:]
	if err := s.ServerKey.UnmarshalBinary(b[:len]); err != nil {
		return err
	}
	b = b[len:]

	len = binary.BigEndian.Uint32(b)
	b = b[4:]
	if err := s.PubKey.UnmarshalBinary(b[:len]); err != nil {
		return err
	}
	b = b[len:]

	if b[0] != 0 {
		s.isServerKeyReady = true
	} else {
		s.isServerKeyReady = false
	}

	return nil
}

// ServerGenKey_one 服务端第一步，生成协同密钥中间数据给客户端
// 计算(X_i,Y_i) = [x_i]·G
// 输出 X_1||Y_1||X_2||Y_2||....||X_128||Y_128
func (s *ServerSignKeyGenContext) ServerGenKey_one(rnd io.Reader) ([]byte, error) {
	var err error
	s.isServerKeyReady = false
	buf := make([]byte, sm2.ByteSize())
	out := make([]byte, 2*SecureParam*sm2.ByteSize())
	defer func() {
		for i := range buf {
			buf[i] = 0 // 清除临时使用的内存数据
		}
	}()

	// 使用基于SM3的随机比特生成器生成服务端签名密钥分量
	s.ServerKey.D, err = rand.Int(drng.SM3Rng, sm2.OrderN())
	if err != nil {
		return nil, err
	}

	d := s.ServerKey.Get()
	d.SetInt64(0)
	// 服务端计算中间数据
	for i := 0; i < SecureParam; i++ {
		if n, err := rnd.Read(buf); n != len(buf) || err != nil {
			return nil, fmt.Errorf("Generate random number error")
		}
		s.B[i].SetBytes(buf)
		d.Add(d, s.B[i])
		if n, err := rnd.Read(buf); n != len(buf) || err != nil {
			return nil, fmt.Errorf("Generate random number error")
		}
		s.X[i].SetBytes(buf)
		x, y := sm2.Curve256.ScalarBaseMult(buf)
		copy(out[(i*2+1)*sm2.ByteSize()-len(x.Bytes()):], x.Bytes())
		copy(out[(i*2+2)*sm2.ByteSize()-len(y.Bytes()):], y.Bytes())
	}
	d.Mod(d, sm2.OrderN())

	return out, nil
}

// ServerGenKey_two 服务端第二步，收到客户端数据in，计算中间数据并返回给客户端
// 其中in = (h_i0, h_i1, F_ix, F_iy), ... , for i = 1...128
// 输出 (C_i0, C_i1), ...., for i = 1..128
func (s *ServerSignKeyGenContext) ServerGenKey_two(in []byte, rand io.Reader) ([]byte, error) {
	tmp := new(big.Int)
	h0 := new(big.Int)
	h1 := new(big.Int)
	fx := new(big.Int)
	fy := new(big.Int)
	out := make([]byte, 2*sm2.ByteSize()*SecureParam+2*sm2.ByteSize())
	v := new(big.Int)
	buf := make([]byte, sm2.ByteSize())
	if n, err := rand.Read(buf); n != len(buf) || err != nil {
		return nil, fmt.Errorf("Generate random number error")
	}
	v.SetBytes(buf)
	v.Mod(v, sm2.Curve().Params().P)
	pos := 0
	for i := 0; i < SecureParam; i++ {
		h0.SetBytes(in[pos : pos+sm2.ByteSize()])
		pos += sm2.ByteSize()
		h1.SetBytes(in[pos : pos+sm2.ByteSize()])
		pos += sm2.ByteSize()
		fx.SetBytes(in[pos : pos+sm2.ByteSize()])
		pos += sm2.ByteSize()
		fy.SetBytes(in[pos : pos+sm2.ByteSize()])
		pos += sm2.ByteSize()

		x, y := sm2.Curve256.ScalarMult(fx, fy, s.X[i].Bytes())
		h0.Add(h0, s.B[i])
		h0.Mul(h0, v)
		pointToInt(tmp, x, y)
		h0.Add(h0, tmp)
		h0.Mod(h0, sm2.Curve().Params().N)

		x, y = sm2.Curve256.ScalarBaseMult(s.X[i].Bytes())
		y.Sub(sm2.Curve().Params().P, y)
		fx, fy = sm2.Curve().Add(fx, fy, x, y)
		x, y = sm2.Curve256.ScalarMult(fx, fy, s.X[i].Bytes())
		h1.Add(h1, s.B[i])
		h1.Mul(h1, v)
		pointToInt(tmp, x, y)
		h1.Add(h1, tmp)
		h1.Mod(h1, sm2.Curve().Params().N)

		copy(out[i*2*sm2.ByteSize():], gmath.BigIntToNByte(h0, sm2.ByteSize()))
		copy(out[(i*2+1)*sm2.ByteSize():], gmath.BigIntToNByte(h1, sm2.ByteSize()))
	}
	fx, fy = sm2.Curve256.ScalarBaseMult(v.Bytes())
	copy(out[SecureParam*2*sm2.ByteSize():], gmath.BigIntToNByte(fx, sm2.ByteSize()))
	copy(out[(SecureParam*2+1)*sm2.ByteSize():], gmath.BigIntToNByte(fy, sm2.ByteSize()))
	s.ServerSubKey.SetBigInt(v)
	return out, nil
}

// ServerGenKey_three 服务端第三步，服务端计算公钥
// in = [u^{-1}]·G
func (s *ServerSignKeyGenContext) ServerGenKey_three(in []byte) (err error) {
	x := new(big.Int)
	y := new(big.Int)
	x.SetBytes(in[:sm2.ByteSize()])
	y.SetBytes(in[sm2.ByteSize() : 2*sm2.ByteSize()])
	x, y = sm2.Curve256.ScalarMult(x, y, s.ServerSubKey.Bytes())
	y.Sub(sm2.Curve().Params().P, y)
	x, y = sm2.Curve().Add(x, y, sm2.Curve().Params().Gx, sm2.Curve().Params().Gy)
	y.Sub(sm2.Curve().Params().P, y)
	s.PubKey.X.Set(x)
	s.PubKey.Y.Set(y)
	s.isServerKeyReady = true
	return nil
}
