#include <stdio.h>
#include <gmp.h>
#include <nettle/ecc.h>
#include <nettle/ecc-curve.h>
#include <openssl/bn.h>
#include <openssl/ec.h>
#include <openssl/obj_mac.h>

#define XCOORD "23000000000000000000000000000000000000000000000000110011C2DD0000000000000000000000000000"
#define YCOORD "46BE3FEF75FCA4BD52CE28EC3F1483A05EE154965B05282F9029E14277409908C0EBAAD2CA5449FFA61FEC78473816BC"
#define SCALAR "23000000000000C1DD3FF800E83E2CACA1010A21"

int main() {
	mpz_t x, y, gmul;
	struct ecc_point point, result;
	struct ecc_scalar gs1;
	BIGNUM *ox = BN_new(), *oy = BN_new(), *scal = BN_new();
	EC_GROUP *curve;
	EC_POINT *p1;
	BN_CTX *ctx = BN_CTX_new();


	mpz_init_set_str(x, XCOORD, 16);
	mpz_init_set_str(y, YCOORD, 16);
	mpz_init_set_str(gmul, SCALAR, 16);

	gmp_printf("input x:  %ZX\n", x);
	gmp_printf("input y:  %ZX\n", y);
	gmp_printf("scalar:   %ZX\n\n", gmul);

	ecc_point_init(&point, &nettle_secp_384r1);
	if (ecc_point_set(&point, x, y) == 0) { printf("point not on curve\n"); return -1; }
	ecc_scalar_init(&gs1, &nettle_secp_384r1);
	if (ecc_scalar_set(&gs1, gmul) ==0) { printf ("scalar out of range\n"); return -1; }
	ecc_point_init(&result, &nettle_secp_384r1);
	ecc_point_mul(&result, &gs1, &point);

	ecc_point_get(&result, x, y);
	gmp_printf("nettle out x:  %ZX\n", x);
	gmp_printf("nettle out y:  %ZX\n\n", y);


	curve = EC_GROUP_new_by_curve_name(NID_secp384r1);
	p1 = EC_POINT_new(curve);

	BN_hex2bn(&ox, XCOORD);
	BN_hex2bn(&oy, YCOORD);
	BN_hex2bn(&scal, SCALAR);
	if (EC_POINT_set_affine_coordinates_GFp(curve, p1, ox, oy, ctx) != 1) {printf("error creating point\n");return -2; }
	if (EC_POINT_is_on_curve(curve, p1, ctx) != 1) { printf("point not on curve\n");return -3;}

	EC_POINT_mul(curve, p1, 0, p1, scal, ctx);
	EC_POINT_get_affine_coordinates_GFp(curve, p1, ox, oy, ctx);

	printf("openssl out x: %s\nopenssl out y: %s\n", BN_bn2hex(ox), BN_bn2hex(oy));
}
