// PureNoise CryptoLib (c) 1997-2004, PureNoise Ltd Vaduz <www.cryptolib.com>
// Ruptor's ECDH sample code (unchecked, may contain errors, may not compile)

#include "crypto.h"
#include "chaos/chaos.h"
#include "aes/aes.h"
#include "channel/channel.h"

int sample_ecdh (aes_keystream *incoming_ks, aes_keystream *outgoing_ks)	// incoming traffic decryption and outgoing traffic encryption key streams
{
	// Important Note:
	// keep them all ECC_WORDS + 3: + 1 for size + 1 for trailing zero + 1 to protect from overflow caused by big_psub <- big_redc <- nres_modmult <- nres_powmod <- nres_sqroot <- ecc_point_set
	
	unsigned long		local_sec[ECC_WORDS + 3];			// Local Secret Key (just a random number)
	ecc_point			local_epub;							// Local Public Key = ECC_XYZ * (Local Secret Key) in N-RESIDUE format - X includes LSB of redc(Y) in X[ECC_WORDS+1]
	ecc_point			remote_epub;						// Remote Public Key = ECC_XYZ * (Remote Secret Key) in N-RESIDUE format - X includes LSB of redc(Y) in X[ECC_WORDS+1]
	ecc_point			ecommon;							// Common Key = ECC_XYZ * (Local/Remote Secret Key) * (Remote/Local Public Key) in N-RESIDUE format - no need to convert, just use it like that: who cares?
	unsigned long		y[ECC_WORDS + 3], i;				// Y coordinate in binary form (converted back from n-residue) - a bs temporary variable
	
	channel_new_keypair (local_sec, &local_epub);	// generates a new random keypair
	...
	if (x = send_key (local_epub.X)) return x;		// transmission errors
	...
	if (x = recv_key (remote_epub.X)) return x;		// transmission or traffic decryption errors
	if (remote_epub.X[0] < ECC_WORDS - 1) return -1;	// ERROR_PUBLIC_KEY_TOO_SHORT: any shorter is unacceptable
	...
	ecc_point_mult (local_sec, remote_epub, &ecommon);	// it also resets the sign of the Y coordinate to 0, which is handy
	ecc_point_norm (ecommon);	// EPOINT_NORMALIZED to make sure they always match
	if (ecommon.X[0] < ECC_WORDS - 1) return -1;		// ERROR_PUBLIC_KEY_TOO_SHORT: any shorter is unacceptable
	if (ecommon.X[0] < ECC_WORDS) ecommon.X[++(ecommon.X[0])] = 0;	// making sure that public key X coordinate is exactly ECC_WORDS long (one 0 is acceptable)
	...
	memset (y, 'R', CIPHER_KEY_BYTES);
	chaos_block (y, CIPHER_KEY_WORDS, remote_epub.X, (ECC_WORDS+3)*2);	// compressing both coordinates into one 256-bit block - better than standard hashes
	chaos_block (y, CIPHER_KEY_WORDS, ecommon.X, (ECC_WORDS+3)*2);	// compressing both coordinates into one 256-bit block - better than standard hashes
	aes_setkey (y, incoming_ks);	// decrypt incoming traffic with this key stream
	memset (y, 'R', CIPHER_KEY_BYTES);
	chaos_block (y, CIPHER_KEY_WORDS, local_epub.X, (ECC_WORDS+3)*2);	// compressing both coordinates into one 256-bit block - better than standard hashes
	chaos_block (y, CIPHER_KEY_WORDS, ecommon.X, (ECC_WORDS+3)*2);	// compressing both coordinates into one 256-bit block - better than standard hashes
	aes_setkey (y, outgoing_ks);	// encrypt outgoing traffic with this key stream
	// keys and coordinates can be destroyed now
	return 0;
	
	// Remember, it's just an example!
	// Use authenticated Kim-Song key exchange instead of standard Diffie-Hellman
	// Check keys validity before exchanging traffic
	// On the first exchange always verify the common key fingerprint outside the protocol

	// Good luck! Stay secure. Stay out of trouble.
	// Ruptor
}
