/****************************************************************************
*																			*
*					cryptlib Ed25519 Encryption Routines					*
*					  Copyright Peter Gutmann 2023-2025						*
*																			*
****************************************************************************/

#define PKC_CONTEXT		/* Indicate that we're working with PKC contexts */
#include "crypt.h"
#if defined( INC_ALL )
  #include "context.h"
  #include "ecx.h"
#else
  #include "context/context.h"
  #include "crypt/ecx.h"
#endif /* Compiler-specific includes */

/* Ed209 is rather a mess, it was created in part as a reaction to various 
   quirks and problems in the NIST curves but more than makes up for it with 
   plenty of issues of its own.  In particular the standard, RFC 8032, isn't 
   so much a standard as an ambiguously-worded collection of thoughts about 
   how you might do EdDSA, to the extent that several studies have found that 
   no existing implementation actually conforms to it, or at least to one 
   common interpretation since many are possible, and further that almost no 
   two implementations behave the same way.  Implementations don't appear to 
   be from the RFC but cargo-culted forms of the original "ref10" reference 
   with assorted changes each time someone cargo-cults it.  However since 
   other RFC authors assume that 8032 is a clear standard they often just 
   defer to that, e.g. the SSH RFC 8709 which specifies that signatures are 
   "generated according to the procedure in Sections 5.1.6 of RFC 8032" 
   without specifying which interpretation of that section applies.

   On top of that there's special-snowflake data formats for everything, 
   endless super-clever tricks and mathematical curiosities, "this bit 
   behaves unexpectedly but shouldn't be a problem if you use it just 
   right", and many more.  And then there are the two main papers that 
   analyse Ed209, the security-proof one has a mistake in the proof 
   assumptions and the other one has an error in the test vectors they 
   supply, which no-one seems to have noticed.

   To quote Malcolm Tucker, "what a catastrof**k" */

#ifdef USE_ED25519

/* Ed25519 hardcodes the use of SHA-512 (even though only SHA-256 is 
   needed) so we check to ensure that this is available */

#ifndef USE_SHA2_EXT
  #error Ed25519 requires the use of SHA2-512 via the USE_SHA2_EXT define
#endif /* USE_SHA2_EXT */

/* The size of the Ed25519 components and of the SHA-512 hash used with
   Ed25519 */

#define CURVE25519_SIZE		32
#define SHA512_HASHSIZE		64

/****************************************************************************
*																			*
*								Utility Routines							*
*																			*
****************************************************************************/

/* Check whether the public key is of small order by comparing it to one of 
   8 (canonical encoding) or 5 (non-canonical encoding) values.  This is 
   purely a sanity check used in an ENSURES() statement to document the fact
   that initKey() won't load such a key, it does a full check via 
   ed25519_pubkey_verify() rather than just a blocklist check */

typedef BYTE POINT_DATA[ CURVE25519_SIZE ];

#define NONCANONICAL_TEST_VALUE		9	/* First non-canonical encoding */

static const POINT_DATA pointData[] = {
	/* Canonical encodings */
	{ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0xEC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 },
	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	{ 0xC7, 0x17, 0x6A, 0x70, 0x3D, 0x4D, 0xD8, 0x4F,
	  0xBA, 0x3C, 0x0B, 0x76, 0x0D, 0x10, 0x67, 0x0F,
	  0x2A, 0x20, 0x53, 0xFA, 0x2C, 0x39, 0xCC, 0xC6,
	  0x4E, 0xC7, 0xFD, 0x77, 0x92, 0xAC, 0x03, 0x7A },
	{ 0xC7, 0x17, 0x6A, 0x70, 0x3D, 0x4D, 0xD8, 0x4F,
	  0xBA, 0x3C, 0x0B, 0x76, 0x0D, 0x10, 0x67, 0x0F,
	  0x2A, 0x20, 0x53, 0xFA, 0x2C, 0x39, 0xCC, 0xC6,
	  0x4E, 0xC7, 0xFD, 0x77, 0x92, 0xAC, 0x03, 0xFA },
	{ 0x26, 0xE8, 0x95, 0x8F, 0xC2, 0xB2, 0x27, 0xB0,
	  0x45, 0xC3, 0xF4, 0x89, 0xF2, 0xEF, 0x98, 0xF0,
	  0xD5, 0xDF, 0xAC, 0x05, 0xD3, 0xC6, 0x33, 0x39,
	  0xB1, 0x38, 0x02, 0x88, 0x6D, 0x53, 0xFC, 0x05 },
	{ 0x26, 0xE8, 0x95, 0x8F, 0xC2, 0xB2, 0x27, 0xB0,
	  0x45, 0xC3, 0xF4, 0x89, 0xF2, 0xEF, 0x98, 0xF0,
	  0xD5, 0xDF, 0xAC, 0x05, 0xD3, 0xC6, 0x33, 0x39,
	  0xB1, 0x38, 0x02, 0x88, 0x6D, 0x53, 0xFC, 0x85 },
	/* Non-canonical encodings */
	{ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 },
	{ 0xEC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
	{ 0xEE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F },
	{ 0xEE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
	{ 0xED, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
	{ 0xED, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F },
	/* End-of-list marker */
	{ 0xFF, 0x00 }, { 0xFF, 0x00 }
	};

CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
static BOOLEAN isPubkeySmallOrder( IN_BUFFER( CURVE25519_SIZE ) \
										const BYTE *pubKey )
	{
	LOOP_INDEX i;

	LOOP_MED( i = 0, 
			  i < FAILSAFE_ARRAYSIZE( pointData, POINT_DATA ) && \
					!( pointData[ i ][ 0 ] == 0xFF && \
					   pointData[ i ][ 1 ] == 0x00 ),
			  i++ )
		{
		ENSURES_EXT( LOOP_INVARIANT_MED( i, 0, 
										 FAILSAFE_ARRAYSIZE( pointData, \
															 POINT_DATA ) - 1 ),
					 TRUE );

		if( !memcmp( pubKey, pointData[ i ], CURVE25519_SIZE ) )
			return( TRUE );
		}
	ENSURES_EXT( LOOP_BOUND_OK, TRUE );
	
	return( FALSE );
	}

/* Verify that 2^128 < s < L where L is the order of Ed25519, 2^252 + 
   27742317777372353535851937790883648493.  It's actually 0 <= s < L but 
   there's something seriously wrong if the other side sends us the output 
   of memset( s, 0, 32 ), and even the full 128-bit requirement can only 
   occur naturally with a probability of 2^-124 */
   
static const BYTE lowerBound[ CURVE25519_SIZE ] = { 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	};
static const BYTE L[ CURVE25519_SIZE ] = {
#if 1	/* Big-endian form */
	0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x14, 0xDE, 0xF9, 0xDE, 0xA2, 0xF7, 0x9C, 0xD6, 
	0x58, 0x12, 0x63, 0x1A, 0x5C, 0xF5, 0xD3, 0xED
#else	/* Special-snowflake little-endian form.  This can't be used, see the
		   code comment */
	0xED, 0xD3, 0xF5, 0x5C, 0x1A, 0x63, 0x12, 0x58, 
	0xD6, 0x9C, 0xF7, 0xA2, 0xDE, 0xF9, 0xDE, 0x14,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10
#endif /* Different endian forms */
	};

CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
static BOOLEAN checkRangeS( IN_BUFFER( CURVE25519_SIZE ) const BYTE *s ) 
	{
	BYTE sRev[ CURVE25519_SIZE + 8 ];
	LOOP_INDEX i;
	
	assert( isReadPtr( s, CURVE25519_SIZE ) );
	
	/* Because the value is in special-snowflake form we can't just do a 
	   memcmp() to perform the check but have to reverse the bytes in the 
	   value for the memcmp() magnitude-comparison to work.  Using memcmp() 
	   is fine here because the signature is a public value.
	   
	   In theory there's also a bunch of Rube Goldberg tricks that we can 
	   use to perform the comparison algorithmically, but given the cost of 
	   all the other maths related to 25519 and that it's hard to get a
	   memcmp() wrong while there have been various bugs found in attempts 
	   at Rube Goldberg implementations, we take the easy-to-follow just-
	   works approach */
	LOOP_MED( i = 0, i < CURVE25519_SIZE, i++ )
		{
		ENSURES_B( LOOP_INVARIANT_MED( i, 0, CURVE25519_SIZE - 1 ) );
		
		sRev[ i ] = s[ CURVE25519_SIZE - ( i + 1 ) ];
		}
	ENSURES_B( LOOP_BOUND_OK );
	if( memcmp( sRev, lowerBound, CURVE25519_SIZE ) <= 0 || \
		memcmp( sRev, L, CURVE25519_SIZE ) >= 0 )
		{
		zeroise( sRev, CURVE25519_SIZE );
		return( FALSE );
		}
	
	zeroise( sRev, CURVE25519_SIZE );
	return( TRUE );
	}

/* Calculate SHA512( dom2(F, C) || R || A || PH(M) ) where dom2(F, C) is the 
   empty string, R is r, A is the public key, and PH(M) is the identity 
   function, so it's SHA512( r || pubKey || message ) documented as
   SHA512( R || A || M ) in the code */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4, 5 ) ) \
static int hashRAM( OUT_BUFFER_FIXED( hRAMSize ) BYTE *hRAM, 
					IN_LENGTH_SHORT_MIN( SHA512_HASHSIZE ) \
						const int hRAMSize,
					IN_BUFFER( CURVE25519_SIZE ) const BYTE *r,
					IN_BUFFER( CURVE25519_SIZE ) const BYTE *pubKey,
					IN_BUFFER( messageLen ) const BYTE *message,
					IN_LENGTH_SHORT const int messageLen )
	{
	HASH_FUNCTION hashFunction;
	HASHINFO hashInfo;
	int hashSize;

	assert( isWritePtr( hRAM, SHA512_HASHSIZE ) );
	assert( isReadPtr( r, CURVE25519_SIZE ) );
	assert( isReadPtr( pubKey, CURVE25519_SIZE ) );
	assert( isReadPtr( message, messageLen ) );
	
	REQUIRES( isShortIntegerRangeMin( hRAMSize, SHA512_HASHSIZE ) );
	REQUIRES( isShortIntegerRangeNZ( messageLen ) );
	
	/* Calculate SHA512( r || pubKey || message ) = SHA512( R || A || M ) */
	getHashParameters( CRYPT_ALGO_SHA2, SHA512_HASHSIZE, &hashFunction, 
					   &hashSize, NULL );
	hashFunction( hashInfo, NULL, 0, r, CURVE25519_SIZE, HASH_STATE_START );
	hashFunction( hashInfo, NULL, 0, pubKey, CURVE25519_SIZE, 
				  HASH_STATE_CONTINUE );
	hashFunction( hashInfo, hRAM, hRAMSize, message, messageLen, 
				  HASH_STATE_END );
	zeroise( hashInfo, sizeof( HASHINFO ) );
	
	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*								Algorithm Self-test							*
*																			*
****************************************************************************/

/* Test values from RFC 8032 section 7.1.  The first key can't be used for 
   signature-checking because it uses an empty message (we use a dummy 
   string in order to pass the sanity checks in sigCheck()), in order to 
   verify the test vector it's necessary to change the end of the SHA512()
   operations in sigCheck() to:

	hashFunction( hashInfo, hashValue, CRYPT_MAX_HASHSIZE, 
				  pubKey, CURVE25519_SIZE, HASH_STATE_END ); 

   The last test vector isn't from the RFC but from the test vectors at
   https://ed25519.cr.yp.to/python/sign.input, which are actually the ones 
   used in the RFC only they skipped the shorter ones and went straight to 
   the one that requires 1kb of data */

typedef struct {
	const BYTE pub[ CURVE25519_SIZE ];
	const BYTE priv[ CURVE25519_SIZE ];
	const BYTE *message;
	const int messageLen;
	const BYTE sig[ CURVE25519_SIZE * 2 ];
	} ED25519_DATA;

static const ED25519_DATA ed25519TestData[] = {
	{ /* pub  - #0 */
	  { 0xD7, 0x5A, 0x98, 0x01, 0x82, 0xB1, 0x0A, 0xB7, 
		0xD5, 0x4B, 0xFE, 0xD3, 0xC9, 0x64, 0x07, 0x3A,
		0x0E, 0xE1, 0x72, 0xF3, 0xDA, 0xA6, 0x23, 0x25, 
		0xAF, 0x02, 0x1A, 0x68, 0xF7, 0x07, 0x51, 0x1A },
	  /* priv - #0 */
	  { 0x9D, 0x61, 0xB1, 0x9D, 0xEF, 0xFD, 0x5A, 0x60, 
		0xBA, 0x84, 0x4A, 0xF4, 0x92, 0xEC, 0x2C, 0xC4,
		0x44, 0x49, 0xC5, 0x69, 0x7B, 0x32, 0x69, 0x19, 
		0x70, 0x3B, 0xAC, 0x03, 0x1C, 0xAE, 0x7F, 0x60 },
	  "Dummy", 5,		/* Message, see comment above */
	  { /* sig.r */
		0xE5, 0x56, 0x43, 0x00, 0xC3, 0x60, 0xAC, 0x72, 
		0x90, 0x86, 0xE2, 0xCC, 0x80, 0x6E, 0x82, 0x8A,
		0x84, 0x87, 0x7F, 0x1E, 0xB8, 0xE5, 0xD9, 0x74, 
		0xD8, 0x73, 0xE0, 0x65, 0x22, 0x49, 0x01, 0x55,
		/* sig.s */
		0x5F, 0xB8, 0x82, 0x15, 0x90, 0xA3, 0x3B, 0xAC, 
		0xC6, 0x1E, 0x39, 0x70, 0x1C, 0xF9, 0xB4, 0x6B,
		0xD2, 0x5B, 0xF5, 0xF0, 0x59, 0x5B, 0xBE, 0x24, 
		0x65, 0x51, 0x41, 0x43, 0x8E, 0x7A, 0x10, 0x0B } },
	{ /* pub - #1 */
	  { 0x3D, 0x40, 0x17, 0xC3, 0xE8, 0x43, 0x89, 0x5A, 
		0x92, 0xB7, 0x0A, 0xA7, 0x4D, 0x1B, 0x7E, 0xBC,
		0x9C, 0x98, 0x2C, 0xCF, 0x2E, 0xC4, 0x96, 0x8C, 
		0xC0, 0xCD, 0x55, 0xF1, 0x2A, 0xF4, 0x66, 0x0C },
	  /* priv - #1 */
	  { 0x4C, 0xCD, 0x08, 0x9B, 0x28, 0xFF, 0x96, 0xDA, 
		0x9D, 0xB6, 0xC3, 0x46, 0xEC, 0x11, 0x4E, 0x0F,
		0x5B, 0x8A, 0x31, 0x9F, 0x35, 0xAB, 0xA6, 0x24, 
		0xDA, 0x8C, 0xF6, 0xED, 0x4F, 0xB8, 0xA6, 0xFB },
	  "\x72", 1,		/* Message */
	  { /* sig.r */
		0x92, 0xA0, 0x09, 0xA9, 0xF0, 0xD4, 0xCA, 0xB8, 
		0x72, 0x0E, 0x82, 0x0B, 0x5F, 0x64, 0x25, 0x40,
		0xA2, 0xB2, 0x7B, 0x54, 0x16, 0x50, 0x3F, 0x8F, 
		0xB3, 0x76, 0x22, 0x23, 0xEB, 0xDB, 0x69, 0xDA,
		/* sig.s */
		0x08, 0x5A, 0xC1, 0xE4, 0x3E, 0x15, 0x99, 0x6E, 
		0x45, 0x8F, 0x36, 0x13, 0xD0, 0xF1, 0x1D, 0x8C,
		0x38, 0x7B, 0x2E, 0xAE, 0xB4, 0x30, 0x2A, 0xEE, 
		0xB0, 0x0D, 0x29, 0x16, 0x12, 0xBB, 0x0C, 0x00 } },
	{ /* pub - #2 */
	  { 0xFC, 0x51, 0xCD, 0x8E, 0x62, 0x18, 0xA1, 0xA3, 
		0x8D, 0xA4, 0x7E, 0xD0, 0x02, 0x30, 0xF0, 0x58,
		0x08, 0x16, 0xED, 0x13, 0xBA, 0x33, 0x03, 0xAC, 
		0x5D, 0xEB, 0x91, 0x15, 0x48, 0x90, 0x80, 0x25 },
	  /* priv - #2 */
	  { 0xC5, 0xAA, 0x8D, 0xF4, 0x3F, 0x9F, 0x83, 0x7B, 
		0xED, 0xB7, 0x44, 0x2F, 0x31, 0xDC, 0xB7, 0xB1,
		0x66, 0xD3, 0x85, 0x35, 0x07, 0x6F, 0x09, 0x4B, 
		0x85, 0xCE, 0x3A, 0x2E, 0x0B, 0x44, 0x58, 0xF7 },
	  "\xAF\x82", 2,		/* Message */
	  { /* sig.r */
		0x62, 0x91, 0xD6, 0x57, 0xDE, 0xEC, 0x24, 0x02, 
		0x48, 0x27, 0xE6, 0x9C, 0x3A, 0xBE, 0x01, 0xA3,
		0x0C, 0xE5, 0x48, 0xA2, 0x84, 0x74, 0x3A, 0x44, 
		0x5E, 0x36, 0x80, 0xD7, 0xDB, 0x5A, 0xC3, 0xAC,
		/* sig.s */
		0x18, 0xFF, 0x9B, 0x53, 0x8D, 0x16, 0xF2, 0x90, 
		0xAE, 0x67, 0xF7, 0x60, 0x98, 0x4D, 0xC6, 0x59,
		0x4A, 0x7C, 0x15, 0xE9, 0x71, 0x6E, 0xD2, 0x8D, 
		0xC0, 0x27, 0xBE, 0xCE, 0xEA, 0x1E, 0xC4, 0x0A } },
	{ /* pub - #3 */
	  {	0xE6, 0x1A, 0x18, 0x5B, 0xCE, 0xF2, 0x61, 0x3A, 
		0x6C, 0x7C, 0xB7, 0x97, 0x63, 0xCE, 0x94, 0x5D, 
		0x3B, 0x24, 0x5D, 0x76, 0x11, 0x4D, 0xD4, 0x40, 
		0xBC, 0xF5, 0xF2, 0xDC, 0x1A, 0xA5, 0x70, 0x57 },
	  /* priv - #3 */
	  { 0x0D, 0x4A, 0x05, 0xB0, 0x73, 0x52, 0xA5, 0x43, 
		0x6E, 0x18, 0x03, 0x56, 0xDA, 0x0A, 0xE6, 0xEF, 
		0xA0, 0x34, 0x5F, 0xF7, 0xFB, 0x15, 0x72, 0x57, 
		0x57, 0x72, 0xE8, 0x00, 0x5E, 0xD9, 0x78, 0xE9 },
	  "\xCB\xC7\x7B", 3,	/* Message */
	  { /* sig.r */
		0xD9, 0x86, 0x8D, 0x52, 0xC2, 0xBE, 0xBC, 0xE5, 
		0xF3, 0xFA, 0x5A, 0x79, 0x89, 0x19, 0x70, 0xF3, 
		0x09, 0xCB, 0x65, 0x91, 0xE3, 0xE1, 0x70, 0x2A, 
		0x70, 0x27, 0x6F, 0xA9, 0x7C, 0x24, 0xB3, 0xA8,
		/* sig.s */
		0xE5, 0x86, 0x06, 0xC3, 0x8C, 0x97, 0x58, 0x52, 
		0x9D, 0xA5, 0x0E, 0xE3, 0x1B, 0x82, 0x19, 0xCB, 
		0xA4, 0x52, 0x71, 0xC6, 0x89, 0xAF, 0xA6, 0x0B, 
		0x0E, 0xA2, 0x6C, 0x99, 0xDB, 0x19, 0xB0, 0x0C } },
	{ /* pub */
	  { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } },
	{ /* pub */
	  { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }
	};

/* Test values from "Taming the many EdDSAs" */

typedef struct {
	BYTE message[ CURVE25519_SIZE ];
	BYTE pubKey[ CURVE25519_SIZE ];
	BYTE signature[ CURVE25519_SIZE * 2 ];
	BOOLEAN testOK;
	} ED25519_STRESSTEST_DATA;

static const ED25519_STRESSTEST_DATA stressTestData[] = {
	{ /*  0:	S = 0, 	A small order,	R small order */
	  { 0x8C, 0x93, 0x25, 0x5D, 0x71, 0xDC, 0xAB, 0x10,
	    0xE8, 0xF3, 0x79, 0xC2, 0x62, 0x00, 0xF3, 0xC7,
	    0xBD, 0x5F, 0x09, 0xD9, 0xBC, 0x30, 0x68, 0xD3,
	    0xEF, 0x4E, 0xDE, 0xB4, 0x85, 0x30, 0x22, 0xB6 },
	  { 0xC7, 0x17, 0x6A, 0x70, 0x3D, 0x4D, 0xD8, 0x4F,
	    0xBA, 0x3C, 0x0B, 0x76, 0x0D, 0x10, 0x67, 0x0F,
	    0x2A, 0x20, 0x53, 0xFA, 0x2C, 0x39, 0xCC, 0xC6,
	    0x4E, 0xC7, 0xFD, 0x77, 0x92, 0xAC, 0x03, 0xFA },
	  { 0xC7, 0x17, 0x6A, 0x70, 0x3D, 0x4D, 0xD8, 0x4F,
	    0xBA, 0x3C, 0x0B, 0x76, 0x0D, 0x10, 0x67, 0x0F,
	    0x2A, 0x20, 0x53, 0xFA, 0x2C, 0x39, 0xCC, 0xC6,
	    0x4E, 0xC7, 0xFD, 0x77, 0x92, 0xAC, 0x03, 0x7A,
	    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
	  FALSE },
	{ /*  1:	S OK,	A small order,	R mixed order */
	  { 0x9B, 0xD9, 0xF4, 0x4F, 0x4D, 0xCC, 0x75, 0xBD,
	    0x53, 0x1B, 0x56, 0xB2, 0xCD, 0x28, 0x0B, 0x0B,
	    0xB3, 0x8F, 0xC1, 0xCD, 0x6D, 0x12, 0x30, 0xE1,
	    0x48, 0x61, 0xD8, 0x61, 0xDE, 0x09, 0x2E, 0x79 },
	  { 0xC7, 0x17, 0x6A, 0x70, 0x3D, 0x4D, 0xD8, 0x4F,
	    0xBA, 0x3C, 0x0B, 0x76, 0x0D, 0x10, 0x67, 0x0F,
	    0x2A, 0x20, 0x53, 0xFA, 0x2C, 0x39, 0xCC, 0xC6,
	    0x4E, 0xC7, 0xFD, 0x77, 0x92, 0xAC, 0x03, 0xFA },
	  { 0xF7, 0xBA, 0xDE, 0xC5, 0xB8, 0xAB, 0xEA, 0xF6,
	    0x99, 0x58, 0x39, 0x92, 0x21, 0x9B, 0x7B, 0x22,
	    0x3F, 0x1D, 0xF3, 0xFB, 0xBE, 0xA9, 0x19, 0x84,
	    0x4E, 0x3F, 0x7C, 0x55, 0x4A, 0x43, 0xDD, 0x43,
	    0xA5, 0xBB, 0x70, 0x47, 0x86, 0xBE, 0x79, 0xFC,
	    0x47, 0x6F, 0x91, 0xD3, 0xF3, 0xF8, 0x9B, 0x03,
	    0x98, 0x4D, 0x80, 0x68, 0xDC, 0xF1, 0xBB, 0x7D,
	    0xFC, 0x66, 0x37, 0xB4, 0x54, 0x50, 0xAC, 0x04 },
	  FALSE },
	{ /*  2:	S OK,	A mixed order,	R small order */
	  { 0xAE, 0xBF, 0x3F, 0x26, 0x01, 0xA0, 0xC8, 0xC5,
	    0xD3, 0x9C, 0xC7, 0xD8, 0x91, 0x16, 0x42, 0xF7,
	    0x40, 0xB7, 0x81, 0x68, 0x21, 0x8D, 0xA8, 0x47,
	    0x17, 0x72, 0xB3, 0x5F, 0x9D, 0x35, 0xB9, 0xAB },
	  { 0xF7, 0xBA, 0xDE, 0xC5, 0xB8, 0xAB, 0xEA, 0xF6,
	    0x99, 0x58, 0x39, 0x92, 0x21, 0x9B, 0x7B, 0x22,
	    0x3F, 0x1D, 0xF3, 0xFB, 0xBE, 0xA9, 0x19, 0x84,
	    0x4E, 0x3F, 0x7C, 0x55, 0x4A, 0x43, 0xDD, 0x43 },
	  { 0xC7, 0x17, 0x6A, 0x70, 0x3D, 0x4D, 0xD8, 0x4F,
	    0xBA, 0x3C, 0x0B, 0x76, 0x0D, 0x10, 0x67, 0x0F,
	    0x2A, 0x20, 0x53, 0xFA, 0x2C, 0x39, 0xCC, 0xC6,
	    0x4E, 0xC7, 0xFD, 0x77, 0x92, 0xAC, 0x03, 0xFA,
	    0x8C, 0x4B, 0xD4, 0x5A, 0xEC, 0xAC, 0xA5, 0xB2,
	    0x4F, 0xB9, 0x7B, 0xC1, 0x0A, 0xC2, 0x7A, 0xC8,
	    0x75, 0x1A, 0x7D, 0xFE, 0x1B, 0xAF, 0xF8, 0xB9,
	    0x53, 0xEC, 0x9F, 0x58, 0x33, 0xCA, 0x26, 0x0E },
	  FALSE },
	{ /*  3:	S OK,	A mixed order,	R mixed order, cofactored/cofactorless */
	  { 0x9B, 0xD9, 0xF4, 0x4F, 0x4D, 0xCC, 0x75, 0xBD,
	    0x53, 0x1B, 0x56, 0xB2, 0xCD, 0x28, 0x0B, 0x0B,
	    0xB3, 0x8F, 0xC1, 0xCD, 0x6D, 0x12, 0x30, 0xE1,
	    0x48, 0x61, 0xD8, 0x61, 0xDE, 0x09, 0x2E, 0x79 },
	  { 0xCD, 0xB2, 0x67, 0xCE, 0x40, 0xC5, 0xCD, 0x45,
	    0x30, 0x6F, 0xA5, 0xD2, 0xF2, 0x97, 0x31, 0x45,
	    0x93, 0x87, 0xDB, 0xF9, 0xEB, 0x93, 0x3B, 0x7B,
	    0xD5, 0xAE, 0xD9, 0xA7, 0x65, 0xB8, 0x8D, 0x4D },
	  { 0x90, 0x46, 0xA6, 0x47, 0x50, 0x44, 0x49, 0x38,
	    0xDE, 0x19, 0xF2, 0x27, 0xBB, 0x80, 0x48, 0x5E,
	    0x92, 0xB8, 0x3F, 0xDB, 0x4B, 0x65, 0x06, 0xC1,
	    0x60, 0x48, 0x4C, 0x01, 0x6C, 0xC1, 0x85, 0x2F,
	    0x87, 0x90, 0x9E, 0x14, 0x42, 0x8A, 0x7A, 0x1D,
	    0x62, 0xE9, 0xF2, 0x2F, 0x3D, 0x3A, 0xD7, 0x80,
	    0x2D, 0xB0, 0x2E, 0xB2, 0xE6, 0x88, 0xB6, 0xC5,
	    0x2F, 0xCD, 0x66, 0x48, 0xA9, 0x8B, 0xD0, 0x09 },
	  TRUE },
	{ /*  4:	S OK,	A mixed order,	R mixed order, cofactored only */
	  { 0xE4, 0x7D, 0x62, 0xC6, 0x3F, 0x83, 0x0D, 0xC7,
	    0xA6, 0x85, 0x1A, 0x0B, 0x1F, 0x33, 0xAE, 0x4B,
	    0xB2, 0xF5, 0x07, 0xFB, 0x6C, 0xFF, 0xEC, 0x40,
	    0x11, 0xEA, 0xCC, 0xD5, 0x5B, 0x53, 0xF5, 0x6C },
	  { 0xCD, 0xB2, 0x67, 0xCE, 0x40, 0xC5, 0xCD, 0x45,
	    0x30, 0x6F, 0xA5, 0xD2, 0xF2, 0x97, 0x31, 0x45,
	    0x93, 0x87, 0xDB, 0xF9, 0xEB, 0x93, 0x3B, 0x7B,
	    0xD5, 0xAE, 0xD9, 0xA7, 0x65, 0xB8, 0x8D, 0x4D },
	  { 0x16, 0x0A, 0x1C, 0xB0, 0xDC, 0x9C, 0x02, 0x58,
	    0xCD, 0x0A, 0x7D, 0x23, 0xE9, 0x4D, 0x8F, 0xA8,
	    0x78, 0xBC, 0xB1, 0x92, 0x5F, 0x2C, 0x64, 0x24,
	    0x6B, 0x2D, 0xEE, 0x17, 0x96, 0xBE, 0xD5, 0x12,
	    0x5E, 0xC6, 0xBC, 0x98, 0x2A, 0x26, 0x9B, 0x72,
	    0x3E, 0x06, 0x68, 0xE5, 0x40, 0x91, 0x1A, 0x9A,
	    0x6A, 0x58, 0x92, 0x1D, 0x69, 0x25, 0xE4, 0x34,
	    0xAB, 0x10, 0xAA, 0x79, 0x40, 0x55, 0x1A, 0x09 },
	  FALSE },
	{ /*  5:	S OK,	A mixed order,	R = L */
	  { 0xE4, 0x7D, 0x62, 0xC6, 0x3F, 0x83, 0x0D, 0xC7,
	    0xA6, 0x85, 0x1A, 0x0B, 0x1F, 0x33, 0xAE, 0x4B,
	    0xB2, 0xF5, 0x07, 0xFB, 0x6C, 0xFF, 0xEC, 0x40,
	    0x11, 0xEA, 0xCC, 0xD5, 0x5B, 0x53, 0xF5, 0x6C },
	  { 0xCD, 0xB2, 0x67, 0xCE, 0x40, 0xC5, 0xCD, 0x45,
	    0x30, 0x6F, 0xA5, 0xD2, 0xF2, 0x97, 0x31, 0x45,
	    0x93, 0x87, 0xDB, 0xF9, 0xEB, 0x93, 0x3B, 0x7B,
	    0xD5, 0xAE, 0xD9, 0xA7, 0x65, 0xB8, 0x8D, 0x4D },
	  { 0x21, 0x12, 0x2A, 0x84, 0xE0, 0xB5, 0xFC, 0xA4,
	    0x05, 0x2F, 0x5B, 0x12, 0x35, 0xC8, 0x0A, 0x53,
	    0x78, 0x78, 0xB3, 0x8F, 0x31, 0x42, 0x35, 0x6B,
	    0x2C, 0x23, 0x84, 0xEB, 0xAD, 0x46, 0x68, 0xB7,
	    0xE4, 0x0B, 0xC8, 0x36, 0xDA, 0xC0, 0xF7, 0x10,
	    0x76, 0xF9, 0xAB, 0xE3, 0xA5, 0x3F, 0x9C, 0x03,
	    0xC1, 0xCE, 0xEE, 0xDD, 0xB6, 0x58, 0xD0, 0x03,
	    0x04, 0x94, 0xAC, 0xE5, 0x86, 0x68, 0x74, 0x05 },
	  FALSE },
	{ /*  6:	S > L,	A = L,			R = L */
	  { 0x85, 0xE2, 0x41, 0xA0, 0x7D, 0x14, 0x8B, 0x41,
	    0xE4, 0x7D, 0x62, 0xC6, 0x3F, 0x83, 0x0D, 0xC7,
	    0xA6, 0x85, 0x1A, 0x0B, 0x1F, 0x33, 0xAE, 0x4B,
	    0xB2, 0xF5, 0x07, 0xFB, 0x6C, 0xFF, 0xEC, 0x40 },
	  { 0x44, 0x2A, 0xAD, 0x9F, 0x08, 0x9A, 0xD9, 0xE1,
	    0x46, 0x47, 0xB1, 0xEF, 0x90, 0x99, 0xA1, 0xFF,
	    0x47, 0x98, 0xD7, 0x85, 0x89, 0xE6, 0x6F, 0x28,
	    0xEC, 0xA6, 0x9C, 0x11, 0xF5, 0x82, 0xA6, 0x23 },
	  { 0xE9, 0x6F, 0x66, 0xBE, 0x97, 0x6D, 0x82, 0xE6,
	    0x01, 0x50, 0xBA, 0xEC, 0xFF, 0x99, 0x06, 0x68,
	    0x4A, 0xEB, 0xB1, 0xEF, 0x18, 0x1F, 0x67, 0xA7,
	    0x18, 0x9A, 0xC7, 0x8E, 0xA2, 0x3B, 0x6C, 0x0E,
	    0x54, 0x7F, 0x76, 0x90, 0xA0, 0xE2, 0xDD, 0xCD,
	    0x04, 0xD8, 0x7D, 0xBC, 0x34, 0x90, 0xDC, 0x19,
	    0xB3, 0xB3, 0x05, 0x2F, 0x7F, 0xF0, 0x53, 0x8C,
	    0xB6, 0x8A, 0xFB, 0x36, 0x9B, 0xA3, 0xA5, 0x14 },
	  FALSE },
	{ /*  7:	S >> L,	A = L,			R = L */
	  { 0x85, 0xE2, 0x41, 0xA0, 0x7D, 0x14, 0x8B, 0x41,
	    0xE4, 0x7D, 0x62, 0xC6, 0x3F, 0x83, 0x0D, 0xC7,
	    0xA6, 0x85, 0x1A, 0x0B, 0x1F, 0x33, 0xAE, 0x4B,
	    0xB2, 0xF5, 0x07, 0xFB, 0x6C, 0xFF, 0xEC, 0x40 },
	  { 0x44, 0x2A, 0xAD, 0x9F, 0x08, 0x9A, 0xD9, 0xE1,
	    0x46, 0x47, 0xB1, 0xEF, 0x90, 0x99, 0xA1, 0xFF,
	    0x47, 0x98, 0xD7, 0x85, 0x89, 0xE6, 0x6F, 0x28,
	    0xEC, 0xA6, 0x9C, 0x11, 0xF5, 0x82, 0xA6, 0x23 },
	  { 0 },
	  FALSE },
	{ /*  8:	S OK,	A mixed order,	R small order */
	  { 0x9B, 0xED, 0xC2, 0x67, 0x42, 0x37, 0x25, 0xD4,
	    0x73, 0x88, 0x86, 0x31, 0xEB, 0xF4, 0x59, 0x88,
	    0xBA, 0xD3, 0xDB, 0x83, 0x85, 0x1E, 0xE8, 0x5C,
	    0x85, 0xE2, 0x41, 0xA0, 0x7D, 0x14, 0x8B, 0x41 },
	  { 0xF7, 0xBA, 0xDE, 0xC5, 0xB8, 0xAB, 0xEA, 0xF6,
	    0x99, 0x58, 0x39, 0x92, 0x21, 0x9B, 0x7B, 0x22,
	    0x3F, 0x1D, 0xF3, 0xFB, 0xBE, 0xA9, 0x19, 0x84,
	    0x4E, 0x3F, 0x7C, 0x55, 0x4A, 0x43, 0xDD, 0x43 },
	  { 0xEC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	    0x03, 0xBE, 0x96, 0x78, 0xAC, 0x10, 0x2E, 0xDC,
	    0xD9, 0x2B, 0x02, 0x10, 0xBB, 0x34, 0xD7, 0x42,
	    0x8D, 0x12, 0xFF, 0xC5, 0xDF, 0x5F, 0x37, 0xE3,
	    0x59, 0x94, 0x12, 0x66, 0xA4, 0xE3, 0x5F, 0x0F },
	  FALSE },
	{ /*  9:	S OK,	A mixed order,	R small order */
	  { 0x9B, 0xED, 0xC2, 0x67, 0x42, 0x37, 0x25, 0xD4,
	    0x73, 0x88, 0x86, 0x31, 0xEB, 0xF4, 0x59, 0x88,
	    0xBA, 0xD3, 0xDB, 0x83, 0x85, 0x1E, 0xE8, 0x5C,
	    0x85, 0xE2, 0x41, 0xA0, 0x7D, 0x14, 0x8B, 0x41 },
	  { 0xF7, 0xBA, 0xDE, 0xC5, 0xB8, 0xAB, 0xEA, 0xF6,
	    0x99, 0x58, 0x39, 0x92, 0x21, 0x9B, 0x7B, 0x22,
	    0x3F, 0x1D, 0xF3, 0xFB, 0xBE, 0xA9, 0x19, 0x84,
	    0x4E, 0x3F, 0x7C, 0x55, 0x4A, 0x43, 0xDD, 0x43 },
	  { 0xEC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	    0xCA, 0x8C, 0x5B, 0x64, 0xCD, 0x20, 0x89, 0x82,
	    0xAA, 0x38, 0xD4, 0x93, 0x66, 0x21, 0xA4, 0x77,
	    0x5A, 0xA2, 0x33, 0xAA, 0x05, 0x05, 0x71, 0x1D,
	    0x8F, 0xDC, 0xFD, 0xAA, 0x94, 0x3D, 0x49, 0x08 },
	  FALSE },
	{ /* 10:	S OK,	A small order,	R mixed order */
	  { 0xE9, 0x6B, 0x70, 0x21, 0xEB, 0x39, 0xC1, 0xA1,
	    0x63, 0xB6, 0xDA, 0x4E, 0x30, 0x93, 0xDC, 0xD3,
	    0xF2, 0x13, 0x87, 0xDA, 0x4C, 0xC4, 0x57, 0x2B,
	    0xE5, 0x88, 0xFA, 0xFA, 0xE2, 0x3C, 0x15, 0x5B },
	  { 0xEC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
	  { 0xA9, 0xD5, 0x52, 0x60, 0xF7, 0x65, 0x26, 0x1E,
	    0xB9, 0xB8, 0x4E, 0x10, 0x6F, 0x66, 0x5E, 0x00,
	    0xB8, 0x67, 0x28, 0x7A, 0x76, 0x19, 0x90, 0xD7,
	    0x13, 0x59, 0x63, 0xEE, 0x0A, 0x7D, 0x59, 0xDC,
	    0xA5, 0xBB, 0x70, 0x47, 0x86, 0xBE, 0x79, 0xFC,
	    0x47, 0x6F, 0x91, 0xD3, 0xF3, 0xF8, 0x9B, 0x03,
	    0x98, 0x4D, 0x80, 0x68, 0xDC, 0xF1, 0xBB, 0x7D,
	    0xFC, 0x66, 0x37, 0xB4, 0x54, 0x50, 0xAC, 0x04 },
	  FALSE },
	{ /* 11:	S OK,	A small order,	R mixed order */
	  { 0x39, 0xA5, 0x91, 0xF5, 0x32, 0x1B, 0xBE, 0x07,
	    0xFD, 0x5A, 0x23, 0xDC, 0x2F, 0x39, 0xD0, 0x25,
	    0xD7, 0x45, 0x26, 0x61, 0x57, 0x46, 0x72, 0x7C,
	    0xEE, 0xFD, 0x6E, 0x82, 0xAE, 0x65, 0xC0, 0x6F },
	  { 0xEC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
	  { 0xA9, 0xD5, 0x52, 0x60, 0xF7, 0x65, 0x26, 0x1E,
	    0xB9, 0xB8, 0x4E, 0x10, 0x6F, 0x66, 0x5E, 0x00,
	    0xB8, 0x67, 0x28, 0x7A, 0x76, 0x19, 0x90, 0xD7,
	    0x13, 0x59, 0x63, 0xEE, 0x0A, 0x7D, 0x59, 0xDC,
	    0xA5, 0xBB, 0x70, 0x47, 0x86, 0xBE, 0x79, 0xFC,
	    0x47, 0x6F, 0x91, 0xD3, 0xF3, 0xF8, 0x9B, 0x03,
	    0x98, 0x4D, 0x80, 0x68, 0xDC, 0xF1, 0xBB, 0x7D,
	    0xFC, 0x66, 0x37, 0xB4, 0x54, 0x50, 0xAC, 0x04 },
	  FALSE },
	{ /* End-of-list marker */
	  { 0xFF }, { 0xFF }, { 0xFF }, FALSE },
	{ { 0xFF }, { 0xFF }, { 0xFF }, FALSE }
	};

/* Keys for the self-test pairwise consistency test, comprising the first 
   set of RFC 8032 test vector keys */

static const BYTE testKeyPub[] = {
	0xD7, 0x5A, 0x98, 0x01, 0x82, 0xB1, 0x0A, 0xB7, 
	0xD5, 0x4B, 0xFE, 0xD3, 0xC9, 0x64, 0x07, 0x3A,
	0x0E, 0xE1, 0x72, 0xF3, 0xDA, 0xA6, 0x23, 0x25, 
	0xAF, 0x02, 0x1A, 0x68, 0xF7, 0x07, 0x51, 0x1A 
	};
static const BYTE testKeyPriv[] = {
	0x9D, 0x61, 0xB1, 0x9D, 0xEF, 0xFD, 0x5A, 0x60, 
	0xBA, 0x84, 0x4A, 0xF4, 0x92, 0xEC, 0x2C, 0xC4,
	0x44, 0x49, 0xC5, 0x69, 0x7B, 0x32, 0x69, 0x19, 
	0x70, 0x3B, 0xAC, 0x03, 0x1C, 0xAE, 0x7F, 0x60 
	};

/* The SHA-256 hash of an empty string, used as the data to sign in the
   pairwise consistency test */

static const BYTE sha256hash[] = {
	0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14, 
	0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24, 
	0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C, 
	0xA4, 0x95, 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55 
	};

/* Perform a pairwise consistency test on a public/private key pair.  In 
   theory this check doesn't necessarily work because of the way EdDSA 
   works, see among others section 9.1 of "Attacking Deterministic Signature 
   Schemes Using Fault Attacks" by Poddebniak, Somorovsky, Schinzel, Lochter 
   and Rösler and "Ed25519 leaks private key if public key is incorrect", 
   https://github.com/jedisct1/libsodium/issues/170/.
   
   However neither of these seem like real vulnerabilities, the first 
   corrupts M into M', where both the signing and verification operation 
   use h( R, A, M' ), which is a bit of a no-op attack that's only notable
   because the equivalent fault-injection attack on RSA corrupts the CRT 
   multiplication used during signature generation, which is then detectable 
   by the non-CRT-using verification.  Corrupting the data being signed with 
   RSA would lead to the same "attack".
   
   The second relies on an attacker switching out the public key, so the
   data is signed with public key A and private key B.  cryptlib always
   checks that the two match up when the key is loaded, and the same sort
   of attack applies to other PKCs as well */

CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
static BOOLEAN pairwiseConsistencyTest( CONTEXT_INFO *contextInfoPtr )
	{
	const CAPABILITY_INFO *capabilityInfoPtr = \
								DATAPTR_GET( contextInfoPtr->capabilityInfo );
	DLP_PARAMS dlpParamsSign, dlpParamsSigCheck;
	int status;

	assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );

	REQUIRES_B( sanityCheckContext( contextInfoPtr ) );
	REQUIRES_B( capabilityInfoPtr != NULL );

	/* Generate a signature with the private key */
	initDLPParamsSignBernstein( &dlpParamsSign, sha256hash, 32 );
	status = capabilityInfoPtr->signFunction( contextInfoPtr,
						( BYTE * ) &dlpParamsSign, sizeof( DLP_PARAMS ) );
	if( cryptStatusError( status ) )
		return( FALSE );

	/* Verify the signature with the public key */
	initDLPParamsSigCheckBernstein( &dlpParamsSigCheck, sha256hash, 32, 
									dlpParamsSign.outParam, 
									dlpParamsSign.outLen );
	status = capabilityInfoPtr->sigCheckFunction( contextInfoPtr,
						( BYTE * ) &dlpParamsSigCheck, sizeof( DLP_PARAMS ) );
	return( cryptStatusOK( status ) ? TRUE : FALSE );
	}

#ifndef CONFIG_NO_SELFTEST

/* Test the 25519 implementation.  Because a lot of the high-level 
   encryption routines don't exist yet we cheat a bit and set up a dummy 
   encryption context with just enough information for the following code to 
   work */

CHECK_RETVAL \
static int selfTest( void )
	{
	const CAPABILITY_INFO *capabilityInfoPtr;
	CONTEXT_INFO contextInfo;
	PKC_INFO contextData, *pkcInfo = &contextData;
	DLP_PARAMS dlpParams;
	BOOLEAN testResult;
	LOOP_INDEX i;
	int status;

	/* Make sure that we can detect non-canonical encodings */
	if( clib_ed25519_pubkey_verify( pointData[ NONCANONICAL_TEST_VALUE ] ) )
		{
		DEBUG_DIAG(( "Failed to detect non-canonical encoding of 25519 "
					 "value" ));
		return( CRYPT_ERROR_FAILED );
		}

	/* Run through the RFC 8032 test vectors */
	LOOP_SMALL( i = 0, 
				i < FAILSAFE_ARRAYSIZE( ed25519TestData, ED25519_DATA ) && \
					ed25519TestData[ i ].pub[ 0 ] != 0xFF,
				i++ )
		{
		const ED25519_DATA *ed25519TestPtr = &ed25519TestData[ i ];
		
		ENSURES( LOOP_INVARIANT_SMALL( i, 0, 
									   FAILSAFE_ARRAYSIZE( ed25519TestData, \
														   ED25519_DATA ) - 1 ) );

		/* Initialise only the private value and make sure that the public 
		   value is correctly generated from it */
		status = staticInitContext( &contextInfo, CONTEXT_PKC, 
									getEd25519Capability(), &contextData, 
									sizeof( PKC_INFO ), NULL );
		if( cryptStatusError( status ) )
			return( CRYPT_ERROR_FAILED );
		status = import25519ByteString( &pkcInfo->curve25519Param_priv, 
										ed25519TestPtr->priv, 
										CURVE25519_SIZE );
		if( cryptStatusError( status ) )
			{
			staticDestroyContext( &contextInfo );
			retIntError();
			}
		capabilityInfoPtr = DATAPTR_GET( contextInfo.capabilityInfo );
		REQUIRES( capabilityInfoPtr != NULL );
		status = capabilityInfoPtr->initKeyFunction( &contextInfo, NULL, 0 );
		if( cryptStatusOK( status ) )
			{
			BYTE buffer[ CURVE25519_SIZE + 8 ];
			int length;

			status = export25519ByteString( buffer, CURVE25519_SIZE, &length, 
											&pkcInfo->curve25519Param_pub );
			if( cryptStatusError( status ) || length != CURVE25519_SIZE || \
				memcmp( buffer, ed25519TestPtr->pub, CURVE25519_SIZE ) )
				status = CRYPT_ERROR_FAILED;
			}
		if( cryptStatusOK( status ) && i == 0 )
			{
			/* We can't perform a check of the first signature since it uses 
			   an empty message, to perform the check see the code change in
			   the comment at the start of this section */
			staticDestroyContext( &contextInfo );
			continue;
			}
		if( cryptStatusOK( status ) )
			{
			initDLPParamsSigCheckBernstein( &dlpParams, ed25519TestPtr->message, 
											ed25519TestPtr->messageLen, 
											ed25519TestPtr->sig, 
											CURVE25519_SIZE * 2 );
			status = capabilityInfoPtr->sigCheckFunction( &contextInfo,
							( BYTE * ) &dlpParams, sizeof( DLP_PARAMS ) );
			}
		staticDestroyContext( &contextInfo );
		if( cryptStatusError( status ) )
			return( CRYPT_ERROR_FAILED );
		}
	ENSURES( LOOP_BOUND_OK );

	/* Run through the test vectors from "Taming the Many EdDSAs".  Some of 
	   these contain invalid (or at least dubious) public key / A values so
	   won't even pass initKey() let alone the signature check */
	LOOP_MED( i = 0, 
			  i < FAILSAFE_ARRAYSIZE( stressTestData, \
									  ED25519_STRESSTEST_DATA ) && \
					stressTestData[ i ].pubKey[ 0 ] != 0xFF,
			  i++ )
		{
		const ED25519_STRESSTEST_DATA *stressTestDataPtr = &stressTestData[ i ];
		
		ENSURES( LOOP_INVARIANT_MED( i, 0, 
									 FAILSAFE_ARRAYSIZE( stressTestData, \
														 ED25519_STRESSTEST_DATA ) - 1 ) );

		/* Initialise the public value */
		status = staticInitContext( &contextInfo, CONTEXT_PKC, 
									getEd25519Capability(), &contextData, 
									sizeof( PKC_INFO ), NULL );
		if( cryptStatusError( status ) )
			return( CRYPT_ERROR_FAILED );
		SET_FLAG( contextInfo.flags, CONTEXT_FLAG_ISPUBLICKEY );
		status = import25519ByteString( &pkcInfo->curve25519Param_pub, 
										stressTestDataPtr->pubKey, 
										CURVE25519_SIZE );
		if( cryptStatusError( status ) )
			{
			staticDestroyContext( &contextInfo );
			retIntError();
			}
		capabilityInfoPtr = DATAPTR_GET( contextInfo.capabilityInfo );
		REQUIRES( capabilityInfoPtr != NULL );
		status = capabilityInfoPtr->initKeyFunction( &contextInfo, NULL, 0 );
		if( cryptStatusOK( status ) )
			{
			initDLPParamsSigCheckBernstein( &dlpParams, 
											stressTestDataPtr->message, 
											CURVE25519_SIZE, 
											stressTestDataPtr->signature, 
											CURVE25519_SIZE * 2 );
			status = capabilityInfoPtr->sigCheckFunction( &contextInfo,
							( BYTE * ) &dlpParams, sizeof( DLP_PARAMS ) );
			}
		staticDestroyContext( &contextInfo );
		testResult = cryptStatusOK( status ) ? TRUE : FALSE;
		if( stressTestDataPtr->testOK != testResult )
			{
			DEBUG_DIAG(( "Ed25519 test #%d failed, got result %s, "
						 "should have been %s", i, 
						 testResult ? "TRUE" : "FALSE", 
						 stressTestDataPtr->testOK ? "TRUE" : "FALSE" ));
			return( CRYPT_ERROR_FAILED );
			}
		}
	ENSURES( LOOP_BOUND_OK );

	/* Finally, perform a pairwise consistency check using the first signing 
	   key from the RFC 8032 test vectors */
	status = staticInitContext( &contextInfo, CONTEXT_PKC, 
								getEd25519Capability(), &contextData, 
								sizeof( PKC_INFO ), NULL );
	if( cryptStatusError( status ) )
		return( CRYPT_ERROR_FAILED );
	status = import25519ByteString( &pkcInfo->curve25519Param_pub, 
									testKeyPub, CURVE25519_SIZE );
	if( cryptStatusOK( status ) )
		{
		status = import25519ByteString( &pkcInfo->curve25519Param_priv, 
										testKeyPriv, CURVE25519_SIZE );
		}
	if( cryptStatusOK( status ) )
		{
		capabilityInfoPtr = DATAPTR_GET( contextInfo.capabilityInfo );
		REQUIRES( capabilityInfoPtr != NULL );
		status = capabilityInfoPtr->initKeyFunction( &contextInfo, NULL, 0 );
		}
	if( cryptStatusError( status ) )
		{
		staticDestroyContext( &contextInfo );
		retIntError();
		}
	if( !pairwiseConsistencyTest( &contextInfo ) )
		status = CRYPT_ERROR_FAILED;
	staticDestroyContext( &contextInfo );

	return( status );
	}
#else
	#define selfTest	NULL
#endif /* !CONFIG_NO_SELFTEST */

/****************************************************************************
*																			*
*							Create/Check a Signature						*
*																			*
****************************************************************************/

/* Sign a block of data:

	r = nonce mod L;
	R = [r]B;

	h = SHA512( privKey )[ 0..31 ];
	s = clamp( h );
	k = SHA512( R || A || M ) mod L;
	S = ( r + ks ) mod L */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int sign( INOUT_PTR CONTEXT_INFO *contextInfoPtr, 
				 INOUT_BUFFER_FIXED( noBytes ) BYTE *buffer, 
				 IN_LENGTH_FIXED( sizeof( DLP_PARAMS ) ) int noBytes )
	{
	PKC_INFO *pkcInfo = contextInfoPtr->ctxPKC;
	DLP_PARAMS *eccParams = ( DLP_PARAMS * ) buffer;
	MESSAGE_DATA msgData;
	BYTE nonce[ CRYPT_MAX_HASHSIZE + 8 ], hRAM[ CRYPT_MAX_HASHSIZE + 8 ];
	BYTE r[ CURVE25519_SIZE + 8 ], s[ CURVE25519_SIZE + 8 ];
	BYTE pubKey[ CURVE25519_SIZE + 8 ]; 
	BYTE *R, *S;
	int pubKeySize, sSize, osslStatus, status;

	assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
	assert( isWritePtr( eccParams, sizeof( DLP_PARAMS ) ) );
	assert( isReadPtr( eccParams->inMessagePtr, eccParams->inMessageLen ) );

	REQUIRES( sanityCheckContext( contextInfoPtr ) );
	REQUIRES( noBytes == sizeof( DLP_PARAMS ) );
	REQUIRES( eccParams->inMessagePtr != NULL && \
			  isIntegerRangeNZ( eccParams->inMessageLen ) );

	/* Clear return values */
	REQUIRES( rangeCheck( DLP_DATA_SIZE, 1, DLP_DATA_SIZE ) ); 
	memset( eccParams->outParam, 0, min( 16, DLP_DATA_SIZE ) );
	eccParams->outLen = 0;

	R = eccParams->outParam;
	S = eccParams->outParam + CURVE25519_SIZE;

	/* Get the nonce and from that calculate r and R.  The Ed25519 specs 
	   require a complex dance to generate a deterministic nonce by hashing 
	   a truncated hash of the private key and the message to be signed with
	   SHA512, done to deal with broken RNGs and buggy implementations that 
	   reuse nonces.  Since we have an RNG that works, we use a fresh nonce 
	   each time */
	setMessageData( &msgData, nonce, CRYPT_MAX_HASHSIZE );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
							  IMESSAGE_GETATTRIBUTE_S, &msgData,
							  CRYPT_IATTRIBUTE_RANDOM );
	if( cryptStatusError( status ) )
		return( status );
	osslStatus = clib_ed25519_sign_r( R, r, nonce );
	zeroise( nonce, CRYPT_MAX_HASHSIZE );
	if( osslStatus != TRUE )
		{
		zeroise( r, CURVE25519_SIZE );
		return( CRYPT_ERROR_FAILED );
		}

	/* Get the public value in special-snowflake form and use it to generate 
	   SHA512( R || A || M ).  The small-order check here is just a sanity 
	   check since initKey() won't load a public key of small order */
	status = export25519ByteString( pubKey, CURVE25519_SIZE, &pubKeySize, 
									&pkcInfo->curve25519Param_pub );
	if( cryptStatusOK( status ) )
		{
		ENSURES( pubKeySize == CURVE25519_SIZE );
		ENSURES( !isPubkeySmallOrder( pubKey ) );
		status = hashRAM( hRAM, CRYPT_MAX_HASHSIZE, R, pubKey, 
						  eccParams->inMessagePtr, 
						  eccParams->inMessageLen );
		}
	if( cryptStatusError( status ) )
		{
		zeroise( r, CURVE25519_SIZE );
		zeroise( R, CURVE25519_SIZE );
		zeroise( hRAM, CRYPT_MAX_HASHSIZE );
		zeroise( pubKey, CURVE25519_SIZE );
		return( status );
		}

	/* Calculate S using the s value pre-generated at key load time */
	status = export25519ByteString( s, CURVE25519_SIZE, &sSize, 
									&pkcInfo->curve25519Param_s );
	if( cryptStatusOK( status ) )
		{
		ENSURES( sSize == CURVE25519_SIZE );
		osslStatus = clib_ed25519_sign_s( S, hRAM, s, r );
		if( osslStatus != TRUE )
			status = CRYPT_ERROR_FAILED;
		}

	/* Clean up */
	zeroise( s, CURVE25519_SIZE );
	zeroise( r, CURVE25519_SIZE );
	zeroise( hRAM, CRYPT_MAX_HASHSIZE );
	zeroise( pubKey, CURVE25519_SIZE );
	if( cryptStatusOK( status ) )
		eccParams->outLen = CURVE25519_SIZE * 2;
	else
		zeroise( R, CURVE25519_SIZE * 2 );

	ENSURES( sanityCheckPKCInfo( pkcInfo ) );

	return( status );
	}

/* Check a signature { r, s } on a block of data:

	h = SHA512( R || A || M ) mod L;
	rPrime = [s]B - h[A];
	OK -> rPrime == r */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int sigCheck( INOUT_PTR CONTEXT_INFO *contextInfoPtr, 
					 IN_BUFFER( noBytes ) BYTE *buffer, 
					 IN_LENGTH_FIXED( sizeof( DLP_PARAMS ) ) int noBytes )
	{
	PKC_INFO *pkcInfo = contextInfoPtr->ctxPKC;
	DLP_PARAMS *eccParams = ( DLP_PARAMS * ) buffer;
	BYTE pubKey[ CURVE25519_SIZE + 8 ], hRAM[ CRYPT_MAX_HASHSIZE + 8 ];
	const BYTE *r, *s;
	int pubKeySize, status;

	assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
	assert( isWritePtr( eccParams, sizeof( DLP_PARAMS ) ) );
	assert( isReadPtr( eccParams->inMessagePtr, eccParams->inMessageLen ) );

	REQUIRES( sanityCheckContext( contextInfoPtr ) );
	REQUIRES( noBytes == sizeof( DLP_PARAMS ) );
	REQUIRES( eccParams->inMessagePtr != NULL && \
			  isIntegerRangeNZ( eccParams->inMessageLen ) );
	REQUIRES( eccParams->inParam2 != NULL && \
			  eccParams->inLen2 == CURVE25519_SIZE * 2 );

	/* Extract { r, s } from the signature data and verify that they're 
	   kosher.  r is also checked in clib_ed25519_verify() which does an
	   encode-and-memcmp() to compare against the received r value, and
	   is additionally protected by being hashed into the signed data */
	r = eccParams->inParam2;
	s = eccParams->inParam2 + CURVE25519_SIZE;
	if( clib_ed25519_has_small_order( r ) )
		{
		DEBUG_DIAG(( "Ed25519 signature r value has small order" ));
		return( CRYPT_ERROR_SIGNATURE );
		}
	if( !checkRangeS( s ) )
		{
		DEBUG_DIAG(( "Ed25519 signature s value is out of range" ));
		return( CRYPT_ERROR_SIGNATURE );
		}

	/* Get the public key in special-snowflake form.  The small-order 
	   check here is just a sanity check to document the more complete check
	   done by initKey() */
	status = export25519ByteString( pubKey, CURVE25519_SIZE, &pubKeySize, 
									&pkcInfo->curve25519Param_pub );
	if( cryptStatusError( status ) )
		return( status );
	ENSURES( pubKeySize == CURVE25519_SIZE );
	ENSURES( !isPubkeySmallOrder( pubKey ) );
	
	/* Calculate SHA512( dom2(F, C) || R || A || PH(M) ) where dom2(F, C) is
	   the empty string, R is r, A is the public key, and PH(M) is the identity
	   function, so it's SHA512( r || pubKey || message ).  This protects the
	   r component from manipulation but not s, so an attacker could use
	   s' = s + nq and the signature would still verify because s' == s mod q. 
	   The checkRangeS() earlier catches this */
	status = hashRAM( hRAM, CRYPT_MAX_HASHSIZE, r, pubKey, 
					  eccParams->inMessagePtr, eccParams->inMessageLen );
	if( cryptStatusError( status ) )
		{
		zeroise( pubKey, CURVE25519_SIZE );
		return( status );
		}

	/* Verify the signature */
	if( clib_ed25519_verify( hRAM, eccParams->inParam2, pubKey ) != TRUE )
		status = CRYPT_ERROR_SIGNATURE;

	/* Clean up */
	zeroise( hRAM, CRYPT_MAX_HASHSIZE );
	zeroise( pubKey, CURVE25519_SIZE );

	ENSURES( sanityCheckPKCInfo( pkcInfo ) );

	return( status );
	}

/****************************************************************************
*																			*
*								Key Management								*
*																			*
****************************************************************************/

/* Load key components into an encryption context */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int initKey( INOUT_PTR CONTEXT_INFO *contextInfoPtr, 
					IN_BUFFER_OPT( keyLength ) const void *key,
					IN_LENGTH_SHORT_OPT const int keyLength )
	{
	PKC_INFO *pkcInfo = contextInfoPtr->ctxPKC;

	assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
	assert( ( key == NULL && keyLength == 0 ) || \
			( isReadPtrDynamic( key, keyLength ) && \
			  keyLength == sizeof( CRYPT_PKCINFO_DJB ) ) );

	REQUIRES( sanityCheckContext( contextInfoPtr ) );
	REQUIRES( ( key == NULL && keyLength == 0 ) || \
			  ( key != NULL && keyLength == sizeof( CRYPT_PKCINFO_DJB ) ) );

#ifndef USE_FIPS140
	/* Load the key component from the external representation into the
	   internal bignums unless we're doing an internal load */
	if( key != NULL )
		{
		const CRYPT_PKCINFO_DJB *ed25519Key = ( CRYPT_PKCINFO_DJB * ) key;
		int status;

		if( ed25519Key->isPublicKey )
			SET_FLAG( contextInfoPtr->flags, CONTEXT_FLAG_ISPUBLICKEY );
		else
			SET_FLAG( contextInfoPtr->flags, CONTEXT_FLAG_PBO );
		status = import25519ByteString( &pkcInfo->curve25519Param_pub, 
										ed25519Key->pub, CURVE25519_SIZE );
		if( cryptStatusOK( status ) && !ed25519Key->isPublicKey )
			{
			status = import25519ByteString( &pkcInfo->curve25519Param_priv, 
											ed25519Key->priv, 
											CURVE25519_SIZE );
			}
		if( cryptStatusError( status ) )
			return( status );

		ENSURES( sanityCheckPKCInfo( pkcInfo ) );
		}
#endif /* USE_FIPS140 */

	/* Complete the key checking and setup */
	return( initCheck25519Key( contextInfoPtr ) );
	}

/* Generate a key into an encryption context */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int generateKey( INOUT_PTR CONTEXT_INFO *contextInfoPtr, 
						IN_LENGTH_SHORT_MIN( MIN_PKCSIZE_ECC * 8 ) \
							const int keySizeBits )
	{
	int status;

	assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );

	REQUIRES( sanityCheckContext( contextInfoPtr ) );
	REQUIRES( keySizeBits == bytesToBits( CURVE25519_SIZE ) );

	status = generate25519Key( contextInfoPtr );
	if( cryptStatusOK( status ) && \
		!pairwiseConsistencyTest( contextInfoPtr ) )
		{
		DEBUG_DIAG(( "Consistency check of freshly-generated Ed25519 key "
					 "failed" ));
		assert( DEBUG_WARN );
		status = CRYPT_ERROR_FAILED;
		}
	return( cryptArgError( status ) ? CRYPT_ERROR_FAILED : status );
	}

/****************************************************************************
*																			*
*						Capability Access Routines							*
*																			*
****************************************************************************/

static const CAPABILITY_INFO capabilityInfo = {
	CRYPT_ALGO_ED25519, bitsToBytes( 0 ), "Ed25519", 7,
	bitsToBytes( 256 ), bitsToBytes( 256 ), bitsToBytes( 256 ),
	selfTest, getDefaultInfo, NULL, NULL, initKey, generateKey,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 
	sign, sigCheck, readPublicKey25519Function, writePublicKey25519Function, 
	encodeECDLValuesFunction, decodeECDLValuesFunction
	};

CHECK_RETVAL_PTR_NONNULL \
const CAPABILITY_INFO *getEd25519Capability( void )
	{
	return( &capabilityInfo );
	}
#endif /* USE_ED25519 */
