#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <openssl/sha.h>
#include "ed25519-donna.h"

static void dump_point(const char *label, const ge25519 *p)
{
    unsigned char packed[32];
    int i;

    if (label) {
	printf("%s ", label);
    }

    ge25519_pack(packed, p);
    for (i=0;i<32;++i) {
	printf("%02x", packed[i]);
    }
    printf("\n");
}

static void dump_multiples(const ge25519 *p)
{
    ge25519 kp;
    bignum256modm k = {0};
    bignum256modm zero = {0};
    char label[7] = "*  l =";
    int i;

    for (i=1;i<=8;++i) {
	k[0] = i;
	ge25519_double_scalarmult_vartime(&kp, p, k, zero);
	label[2] = '0'+i;
	dump_point(label, &kp);
    }
    printf("\n");
}

static void randpoint(char *randstate, ge25519 *p)
{
    unsigned char hash[64];
    SHA512(randstate, 32, hash);
    ge25519_unpack_negative_vartime(p, hash);
    memmove(randstate, hash+32, 32);
}

int main(int argc, char **argv)
{
    unsigned char randstate[32];
    ge25519 p, mp;
    bignum256modm zero = {0};

    int rfd = open("/dev/urandom", O_RDONLY);
    if (rfd < 0) {
	perror("open /dev/urandom");
	exit(1);
    }
    if (read(rfd, randstate, 32) < 32) {
	perror("read /dev/urandom");
	exit(1);
    }
    close(rfd);

    while(1) {
	randpoint(randstate, &p);

	dump_point("Orig =", &p);
	// Multiply by the group order
	ge25519_double_scalarmult_vartime(&mp, &p, modm_m, zero);
	dump_multiples(&mp);
    }

    return 0;
}
