packages feed

crypton-2.1.3: cbits/ed25519/ed25519_s2n.c

/*
 * Ed25519's base point multiplication through the vendored s2n-bignum.
 *
 * Signing does this twice: once for the nonce's point R, and once for the
 * public key, which crypton derives from the secret key at every signature
 * rather than trusting the one it is handed.  Both go through here, so both
 * halves of a signature move at once.
 *
 * Measured on an Apple M4, one multiplication with the encoding:
 * ed25519-donna 7.5 us against s2n-bignum 3.5.
 */
#include <string.h>

#include "ed25519/ed25519_s2n.h"

#if defined(CRYPTON_S2N_BIGNUM) && defined(__BYTE_ORDER__) \
    && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define CRYPTON_ED25519_S2N 1
#include "crypton_cpu.h"

extern void edwards25519_scalarmulbase(uint64_t res[8],
                                       const uint64_t scalar[4]);
extern void edwards25519_scalarmulbase_alt(uint64_t res[8],
                                           const uint64_t scalar[4]);
extern void edwards25519_encode(uint8_t z[32], const uint64_t p[8]);

/* The same question as everywhere else in cbits/s2n: a microarchitecture one
 * on ARM that no feature bit answers, and exactly a feature bit on x86-64. */
static int use_alt(void)
{
#if defined(__aarch64__) || defined(__arm64__)
#ifdef __APPLE__
	return 1;
#else
	return 0;
#endif
#else
	return (crypton_x86_simd_features() & CRYPTON_X86_ADX) == 0;
#endif
}
#endif

int crypton_ed25519_base_mult(uint8_t out[32], const uint8_t scalar[32])
{
#ifdef CRYPTON_ED25519_S2N
	/* the assembly takes four little-endian 64-bit words, which is the
	 * same bits as the 32 little-endian bytes the scalar is kept in */
	uint64_t s[4], p[8];

	memcpy(s, scalar, 32);
	if (use_alt())
		edwards25519_scalarmulbase_alt(p, s);
	else
		edwards25519_scalarmulbase(p, s);
	edwards25519_encode(out, p);

	memset(s, 0, sizeof s);
	memset(p, 0, sizeof p);
	return 1;
#else
	(void) out;
	(void) scalar;
	return 0;
#endif
}