package main

/*
#cgo CFLAGS: -I${SRCDIR}/include
#cgo LDFLAGS: -L${SRCDIR}/lib -lKGCAll

#include "miracl.h"
#include "mirdef.h"
#include "hash.h"
#include "kgc.h"
#include "utils.h"
#include "ecurve.h"
#include "sign.h"

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

char* IDA = "1234567890111213141516171819202122232425"; // 发送者ID
char* M = "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD";
char* PRI = "pri_big";
char* PUB = "pub_point";
char* PKPUB = "pk_point";
*/
import "C"
import (
	"fmt"
	"io/ioutil"
	"unsafe"
)

func string_halve(str string) (string, string) {
	// 计算字符串长度
	length := len(str)

	// 将字符串分成两部分
	mid := length / 2
	part1 := str[:mid]
	part2 := str[mid:]

	//fmt.Println("第一部分：", part1)
	//fmt.Println("第二部分：", part2)
	return part1, part2

}

func string_trisect(str string) (string, string, string) {
	length := len(str)

	// 计算每个子字符串的长度
	subStrLen := length / 3

	// 切分字符串
	part1 := str[:subStrLen]
	part2 := str[subStrLen : 2*subStrLen]
	part3 := str[2*subStrLen:]

	return part1, part2, part3
}

func bytes_halve(slice []byte) ([]byte, []byte) {
	length := len(slice)

	// 计算每个部分的长度
	halfLength := length / 2

	// 切分切片
	part1 := slice[:halfLength]
	part2 := slice[halfLength:]

	return part1, part2
}

func bytes_trisect(slice []byte) ([]byte, []byte, []byte) {
	length := len(slice)

	// 计算每个部分的长度
	partLength := length / 3

	// 切分切片
	part1 := slice[:partLength]
	part2 := slice[partLength : 2*partLength]
	part3 := slice[2*partLength:]

	return part1, part2, part3
}

// 实现C语言char字符串转Go语言string
func CharToString(cString *C.char) string {
	goString := C.GoString(cString)
	defer C.free(unsafe.Pointer(cString))
	return goString
}

// ReadFileToBytes 从文件中读取内容，并返回字节数组和可能的错误
func ReadFileToBytes(filename string) ([]byte, error) {
	// 读取文件内容
	data, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}

	return data, nil
}

func BigToBytes(x C.big) []byte {

	cString := C.malloc(257)
	defer C.free(cString)

	// 调用 cotstr 函数将 big 类型的整数转换为字符串
	C.cotstr(x, (*C.char)(cString))

	str := C.GoString((*C.char)(cString))
	bytes := []byte(str)

	return bytes

}

func PointToBytes(p *C.epoint) []byte {

	p_x := C.mirvar(0)
	defer C.mirkill(p_x)
	p_y := C.mirvar(0)
	defer C.mirkill(p_y)

	C.epoint_get(p, p_x, p_y)

	x := BigToBytes(p_x)
	y := BigToBytes(p_y)

	return append(x, y...)
}

func BytesToBig(bytes []byte) C.big {

	big := C.mirvar(0)

	str := C.CString(string(bytes))
	C.cinstr(big, str)
	defer C.free(unsafe.Pointer(str))

	return big
}

func BytesToPoint(bytes []byte) *C.epoint {
	bytes1, bytes2 := bytes_halve(bytes)

	big1 := BytesToBig(bytes1)
	defer C.mirkill(big1)
	big2 := BytesToBig(bytes2)
	defer C.mirkill(big2)

	point := C.epoint_init()
	C.epoint_set(big1, big2, 0, point)
	return point
}

func SigToBytes(U *C.epoint, v C.big) []byte {
	U_bytes := PointToBytes(U)
	val_bytes := BigToBytes(v)
	signature := append(U_bytes, val_bytes...)
	return signature
}

func BytesToSig(sig []byte) (U *C.epoint, val C.big) {
	U_x := C.mirvar(0)
	U_y := C.mirvar(0)
	defer C.mirkill(U_x)
	defer C.mirkill(U_y)

	v_test := C.mirvar(0)
	U_test := C.epoint_init()

	U_x_bytes, U_y_bytes, v_bytes := bytes_trisect(sig)

	Ux := C.CString(string(U_x_bytes))
	Uy := C.CString(string(U_y_bytes))
	v := C.CString(string(v_bytes))

	C.cinstr(U_x, Ux)
	C.cinstr(U_y, Uy)
	C.cinstr(v_test, v)

	defer C.free(unsafe.Pointer(Ux))
	defer C.free(unsafe.Pointer(Uy))
	defer C.free(unsafe.Pointer(v))

	C.epoint_set(U_x, U_y, 0, U_test)
	return U_test, v_test
}

func main() {

	mip := C.mirsys(512, 16) // 初始化MIRACL系统，512位，16进制数
	mip.IOBASE = 16          // 设置大整数为16进制
	defer C.mirexit()

	C.setRandSeed() // 随机数种子

	// 建立椭圆曲线
	var params C.ECC_PARAMS
	if !C.setupEcurve(&params) {
		fmt.Println("ecurve setup failed")
		C.mirexit()
		panic("椭圆曲线建立失败！")
	}
	defer C.freeEcurve(&params)

	//初始化参数
	PK_pub := C.epoint_init() //公钥
	defer C.epoint_free(PK_pub)

	val := C.mirvar(0) //用户返回的签名值
	defer C.mirkill(val)

	U := C.epoint_init() //随机点值
	defer C.epoint_free(U)

	//读取配置文件
	pk, _ := ReadFileToBytes("./cert/pkpub.txt")
	prikey, _ := ReadFileToBytes("./cert/prikey.txt")
	pubkey, _ := ReadFileToBytes("./cert/pubkey.txt")
	//prikey := "A83FADCF99E5F576F9E3C93022BDE2C9A1DCFA9CAE78AEC06FA166BEE4B2DB06"
	//pubkey := "ADB8A74356BB524EE4BCB37E990062007565A563C9C66A6CB9D503B4B9F008EE33D21F33EC4A52C1BBA230C0839EF660D0EA2B3040FE3320F250E1C905FB6D57"
	p1, p2 := bytes_halve(pubkey)

	p1_big := BytesToBig(p1)
	defer C.mirkill(p1_big)

	p2_big := BytesToBig(p2)
	defer C.mirkill(p2_big)

	pri_big := BytesToBig(prikey)
	defer C.mirkill(pri_big)

	//将两个big大数转成点
	pub_point := C.epoint_init()
	defer C.epoint_free(pub_point)

	C.epoint_set(p1_big, p2_big, 0, pub_point)

	//pk := "1980F6B7C93CE23B6D54F7116A11A700DEEDB355FD7F0CF518CC43CADEB92D33DE17316AC929C6DA20117C60AF924CBA98F102D054B34EC0F657CE616590E222"
	//将导入的kgc公钥字节流转为椭圆曲线上的点
	PK_pub = BytesToPoint(pk)

	//打印重要参数
	C.outbig(pri_big, C.PRI)
	C.outpoint(pub_point, C.PUB)
	C.outpoint(PK_pub, C.PKPUB)

	// 签名，Gowri Thumbur方案
	C.sign_Thumbur(&params, C.IDA, C.M, pri_big, pub_point, U, PK_pub, val)

	// 把签名消息转为byte切片放入
	signature := SigToBytes(U, val)
	fmt.Println("\n签名的消息为：", signature)

	//从signatrue中解析U和val
	U_test, v_test := BytesToSig(signature)
	defer C.epoint_free(U_test)
	defer C.mirkill(v_test)

	// 验签
	if C.verify_Thumbur(&params, C.IDA, C.M, pub_point, PK_pub, U_test, v_test) {
		fmt.Println("\nsignature valid.")
	} else {
		fmt.Println("\nverify failed.")
	}

}
