/**
 * @file x25519.h
 * @copyright
 *   Copyright (c) 2016 Cryptography Research, Inc.  \n
 *   Released under the MIT License.  See LICENSE.txt for license information.
 * @author Mike Hamburg
 * @brief X25519 key exchange and signatures.
 */

#ifndef __X25519_H__
#define __X25519_H__

#define X25519_BYTES (256/8)

/* The base point (9) */
extern const unsigned char X25519_BASE_POINT[X25519_BYTES];

/** Number of bytes in an EC public key */
#define EC_PUBLIC_BYTES 32

/** Number of bytes in an EC private key */
#define EC_PRIVATE_BYTES 32

/**
 * Number of bytes in a Schnorr challenge.
 * Could be set to 16 in a pinch.  (FUTURE?)
 */
#define EC_CHALLENGE_BYTES 32

/** Enough bytes to get a uniform sample mod #E.  For eg a Brainpool
 * curve this would need to be more than for a private key, but due
 * to the special prime used by Curve25519, the same size is enough.
 */
#define EC_UNIFORM_BYTES 32

/* x25519 scalar multiplication.  Sets out to scalar*base.
 *
 * If clamp is set (and supported by X25519_INTEROP_SUPPORT_CLAMP)
 * then the scalar will be "clamped" like a Curve25519 secret key.
 * This adds almost no security, but permits interop with other x25519
 * implementations without manually clamping the keys.
 *
 * Per RFC 7748, this function returns failure (-1) if the output
 * is zero and clamp is set.  This indicates "non-contributory behavior",
 * meaning that one party might steer the key so that the other party's
 * contribution doesn't matter, or contributes only a little entropy.
 *
 * WARNING: however, this function differs from RFC 7748 in another way:
 * it pays attention to the high bit base[EC_PUBLIC_BYTES-1] & 0x80, but
 * RFC 7748 says to ignore this bit.  For compatibility with RFC 7748,
 * you must also clear this bit by running base[EC_PUBLIC_BYTES-1] &= 0x7F.
 * This library won't clear it for you because it takes the base point as
 * const, and (depending on build flags) dosen't copy it.
 *
 * If clamp==0, or if X25519_INTEROP_SUPPORT_CLAMP==0, then this function
 * always returns 0.
 */
int x25519 (
    unsigned char out[EC_PUBLIC_BYTES],
    const unsigned char scalar[EC_PRIVATE_BYTES],
    const unsigned char base[EC_PUBLIC_BYTES],
    int clamp
);

/**
 * Returns 0 on success, -1 on failure.
 *
 * Per RFC 7748, this function returns failure if the output
 * is zero and clamp is set.  This usually doesn't matter for
 * base scalarmuls.
 *
 * If clamp==0, or if X25519_INTEROP_SUPPORT_CLAMP==0, then this function
 * always returns 0.
 *
 * Same as x255(out,scalar,X255_BASE_POINT), except that
 * other implementations may optimize it.
 */
static inline int x25519_base (
    unsigned char out[EC_PUBLIC_BYTES],
    const unsigned char scalar[EC_PRIVATE_BYTES],
    int clamp
) {
    return x25519(out,scalar,X25519_BASE_POINT,clamp);
}

/**
 * As x25519_base, but with a scalar that's EC_UNIFORM_BYTES long,
 * and clamp always 0 (and thus, no return value).
 *
 * This is used for signing.  Implementors must replace it for
 * curves that require more bytes for uniformity (Brainpool).
 */
static inline void x25519_base_uniform (
    unsigned char out[EC_PUBLIC_BYTES],
    const unsigned char scalar[EC_UNIFORM_BYTES]
) {
    (void)x25519_base(out,scalar,0);
}

/**
 * STROBE-compatible Schnorr signatures using curve25519 (not ed25519)
 *
 * The user will call x25519_base_uniform(eph,eph_secret) to schedule
 * a random ephemeral secret key.  They then call a Schnorr oracle to
 * get a challenge, and compute the response using this function.
 */
void x25519_sign_p2 (
    unsigned char response[EC_PRIVATE_BYTES],
    const unsigned char challenge[EC_CHALLENGE_BYTES],
    const unsigned char eph_secret[EC_UNIFORM_BYTES],
    const unsigned char secret[EC_PRIVATE_BYTES]
);

/**
 * STROBE-compatible signature verification using curve25519 (not ed25519).
 * This function is the public equivalent x25519_sign_p2, taking the long-term
 * and ephemeral public keys instead of secret ones.
 *
 * Returns -1 on failure and 0 on success.
 */
int x25519_verify_p2 (
    const unsigned char response[X25519_BYTES],
    const unsigned char challenge[X25519_BYTES],
    const unsigned char eph[X25519_BYTES],
    const unsigned char pub[X25519_BYTES]
);

#endif /* __X25519_H__ */