// Generated by build/codegen_ecdh_factory.sh
// Tue Jun 20 07:54:50 UTC 2023
#include <string.h>
#include <lauxlib.h>
#include <zen_ecdh.h>
#include <zen_error.h>
#include <ecdh_SECP256K1.h>
#include <ecp_SECP256K1.h>

static char ORDER[MODBYTES_256_28];
static char PRIME[MODBYTES_256_28];

#define Cof CURVE_Cof_I_SECP256K1;

void ecdh_init(lua_State *L, ecdh *ECDH) {
	ECDH->fieldsize = EFS_SECP256K1;
	ECDH->hash = HASH_TYPE_SECP256K1;
	ECDH->ECP__KEY_PAIR_GENERATE = ECP_SECP256K1_KEY_PAIR_GENERATE;
	ECDH->ECP__PUBLIC_KEY_VALIDATE	= ECP_SECP256K1_PUBLIC_KEY_VALIDATE;
	ECDH->ECP__SVDP_DH = ECP_SECP256K1_SVDP_DH;
	ECDH->ECP__ECIES_ENCRYPT = ECP_SECP256K1_ECIES_ENCRYPT;
	ECDH->ECP__ECIES_DECRYPT = ECP_SECP256K1_ECIES_DECRYPT;
	ECDH->ECP__SP_DSA = ECP_SECP256K1_SP_DSA;
	ECDH->ECP__SP_DSA_DET = ECP_SECP256K1_SP_DSA_DET;
	ECDH->ECP__SP_DSA_DET_NOHASH = ECP_SECP256K1_SP_DSA_DET_NOHASH;
	ECDH->ECP__VP_DSA = ECP_SECP256K1_VP_DSA;
	ECDH->ECP__SP_DSA_NOHASH = ECP_SECP256K1_SP_DSA_NOHASH;
	ECDH->ECP__VP_DSA_NOHASH = ECP_SECP256K1_VP_DSA_NOHASH;
	ECDH->ECP__PUBLIC_KEY_RECOVERY = ECP_SECP256K1_PUBLIC_KEY_RECOVERY;
	BIG_256_28 tmp; // toBytes takes a non const BIG
	BIG_256_28_rcopy(tmp, CURVE_Order_SECP256K1);
	BIG_256_28_toBytes(ORDER, tmp);
	ECDH->order = ORDER;
	ECDH->cofactor = Cof;
	BIG_256_28_rcopy(tmp, Modulus_SECP256K1);
	BIG_256_28_toBytes(PRIME, tmp);
	ECDH->prime = PRIME;
	ECDH->mod_size = MODBYTES_256_28;
	act(L,"ECDH curve is SECP256K1");
}

/*
   Takes two points on the curve ECDH (in the form of a public key),
   add them and return the point (as a public key not compressed)

   @param pk1 addendum point
   @param pk2 addendum point
   @return sum result
*/
extern ecdh ECDH;

int ecdh_add(lua_State *L) {
	BEGIN();
	char *failed_msg = NULL;
	octet *pk1 = o_arg(L, 1);
	octet *pk2 = o_arg(L, 2);
	if(pk1 == NULL || pk2 == NULL) {
		failed_msg = "Could not allocate public key";
		goto end;
	}
	if((*ECDH.ECP__PUBLIC_KEY_VALIDATE)(pk1)!=0 ||
	   (*ECDH.ECP__PUBLIC_KEY_VALIDATE)(pk2)!=0) {
		failed_msg = "Invalid public key passed as argument";
		goto end;
	}
	ECP_SECP256K1 p1, p2;
	// Export public key to octet.  This is like o_dup but skips
	// first byte since that is used internally by Milagro as a
	// prefix for Montgomery (2) or non-Montgomery curves (4)
	octet *pk_sum = o_new(L, pk1->len);
	if(pk_sum == NULL) {
		failed_msg = "Could not create public key";
		goto end;
	}
	ECP_SECP256K1_fromOctet(&p1, pk1);
	ECP_SECP256K1_fromOctet(&p2, pk2);
	ECP_SECP256K1_add(&p1, &p2);
	ECP_SECP256K1_toOctet(pk_sum, &p1, false);
end:
	o_free(L, pk1);
	o_free(L, pk2);
	if(failed_msg) {
		THROW(failed_msg);
	}
	return 1;
}


