Browse Source

Merge pull request #597 from sa-kib/ed25519ctx

contextualized extension of the Ed25519 scheme
Steffen Jaeckel 3 years ago
parent
commit
ddfe2e8aa7

+ 31 - 7
doc/crypt.tex

@@ -5909,25 +5909,49 @@ It has support for the following output formats:
 To sign and/or verify a message use the following functions:
 
 \index{ed25519\_sign}
+\index{ed25519ctx\_sign}
+\index{ed25519ph\_sign}
 \begin{verbatim}
-int ed25519_sign(const unsigned char  *msg, unsigned long msglen,
-                       unsigned char  *sig, unsigned long *siglen,
+int ed25519_sign(const  unsigned char *msg, unsigned long msglen,
+                        unsigned char *sig, unsigned long *siglen,
                  const curve25519_key *private_key);
+int ed25519ctx_sign(const  unsigned char *msg, unsigned long  msglen,
+                           unsigned char *sig, unsigned long *siglen,
+                    const  unsigned char *ctx, unsigned long  ctxlen,
+                    const curve25519_key *private_key);
+int ed25519ph_sign(const  unsigned char *msg, unsigned long  msglen,
+                          unsigned char *sig, unsigned long *siglen,
+                   const  unsigned char *ctx, unsigned long  ctxlen,
+                   const curve25519_key *private_key);
 \end{verbatim}
 
-This function will EdDSA sign the message stored in the array pointed to by \textit{msg} of length \textit{msglen} octets.  The signature
-will be stored in the array pointed to by \textit{sig} of length \textit{siglen} octets.
+These functions will EdDSA sign the message stored in the array pointed to by \textit{msg} of length \textit{msglen} octets.  The signature
+will be stored in the array pointed to by \textit{sig} of length \textit{siglen} octets.  The \texttt{ctx} and \texttt{ph} variants also
+allow passing a context \textit{ctx} of length \textit{ctxlen} octets.  This context is allowed to be max. 255 octets long.
 
 \index{ed25519\_verify}
+\index{ed25519ctx\_verify}
+\index{ed25519ph\_verify}
 \begin{verbatim}
 int ed25519_verify(const  unsigned char *msg, unsigned long msglen,
                    const  unsigned char *sig, unsigned long siglen,
-                   int *stat, const curve25519_key *public_key);
+                                    int *stat,
+                   const curve25519_key *public_key);
+int ed25519ctx_verify(const  unsigned char *msg, unsigned long msglen,
+                      const  unsigned char *sig, unsigned long siglen,
+                      const  unsigned char *ctx, unsigned long ctxlen,
+                                       int *stat,
+                      const curve25519_key *public_key);
+int ed25519ph_verify(const  unsigned char *msg, unsigned long msglen,
+                     const  unsigned char *sig, unsigned long siglen,
+                     const  unsigned char *ctx, unsigned long ctxlen,
+                                      int *stat,
+                     const curve25519_key *public_key);
 \end{verbatim}
 
-This function will verify the EdDSA signature in the array pointed to by \textit{sig} of length \textit{siglen} octets, against the message
+These functions will verify the EdDSA signature in the array pointed to by \textit{sig} of length \textit{siglen} octets, against the message
 pointed to by the array \textit{msg} of length \textit{msglen}. It will store a non--zero value in \textit{stat} if the signature is valid.  Note:
-the function will not return an error if the signature is invalid. It will return an error, if the actual signature payload is an invalid format.
+the function will not return an error if the signature is invalid. It will only return an error if the actual signature payload is an invalid format.
 
 
 \chapter{Digital Signature Algorithm}

+ 4 - 0
libtomcrypt_VS2008.vcproj

@@ -2326,6 +2326,10 @@
 			<Filter
 				Name="ec25519"
 				>
+				<File
+					RelativePath="src\pk\ec25519\ec25519_crypto_ctx.c"
+					>
+				</File>
 				<File
 					RelativePath="src\pk\ec25519\ec25519_export.c"
 					>

+ 11 - 11
makefile.mingw

@@ -179,17 +179,17 @@ src/pk/dsa/dsa_decrypt_key.o src/pk/dsa/dsa_encrypt_key.o src/pk/dsa/dsa_export.
 src/pk/dsa/dsa_generate_key.o src/pk/dsa/dsa_generate_pqg.o src/pk/dsa/dsa_import.o \
 src/pk/dsa/dsa_make_key.o src/pk/dsa/dsa_set.o src/pk/dsa/dsa_set_pqg_dsaparam.o \
 src/pk/dsa/dsa_shared_secret.o src/pk/dsa/dsa_sign_hash.o src/pk/dsa/dsa_verify_hash.o \
-src/pk/dsa/dsa_verify_key.o src/pk/ec25519/ec25519_export.o src/pk/ec25519/ec25519_import_pkcs8.o \
-src/pk/ec25519/tweetnacl.o src/pk/ecc/ecc.o src/pk/ecc/ecc_ansi_x963_export.o \
-src/pk/ecc/ecc_ansi_x963_import.o src/pk/ecc/ecc_decrypt_key.o src/pk/ecc/ecc_encrypt_key.o \
-src/pk/ecc/ecc_export.o src/pk/ecc/ecc_export_openssl.o src/pk/ecc/ecc_find_curve.o \
-src/pk/ecc/ecc_free.o src/pk/ecc/ecc_get_key.o src/pk/ecc/ecc_get_oid_str.o src/pk/ecc/ecc_get_size.o \
-src/pk/ecc/ecc_import.o src/pk/ecc/ecc_import_openssl.o src/pk/ecc/ecc_import_pkcs8.o \
-src/pk/ecc/ecc_import_x509.o src/pk/ecc/ecc_make_key.o src/pk/ecc/ecc_recover_key.o \
-src/pk/ecc/ecc_set_curve.o src/pk/ecc/ecc_set_curve_internal.o src/pk/ecc/ecc_set_key.o \
-src/pk/ecc/ecc_shared_secret.o src/pk/ecc/ecc_sign_hash.o src/pk/ecc/ecc_sizes.o \
-src/pk/ecc/ecc_ssh_ecdsa_encode_name.o src/pk/ecc/ecc_verify_hash.o src/pk/ecc/ltc_ecc_export_point.o \
-src/pk/ecc/ltc_ecc_import_point.o src/pk/ecc/ltc_ecc_is_point.o \
+src/pk/dsa/dsa_verify_key.o src/pk/ec25519/ec25519_crypto_ctx.o src/pk/ec25519/ec25519_export.o \
+src/pk/ec25519/ec25519_import_pkcs8.o src/pk/ec25519/tweetnacl.o src/pk/ecc/ecc.o \
+src/pk/ecc/ecc_ansi_x963_export.o src/pk/ecc/ecc_ansi_x963_import.o src/pk/ecc/ecc_decrypt_key.o \
+src/pk/ecc/ecc_encrypt_key.o src/pk/ecc/ecc_export.o src/pk/ecc/ecc_export_openssl.o \
+src/pk/ecc/ecc_find_curve.o src/pk/ecc/ecc_free.o src/pk/ecc/ecc_get_key.o src/pk/ecc/ecc_get_oid_str.o \
+src/pk/ecc/ecc_get_size.o src/pk/ecc/ecc_import.o src/pk/ecc/ecc_import_openssl.o \
+src/pk/ecc/ecc_import_pkcs8.o src/pk/ecc/ecc_import_x509.o src/pk/ecc/ecc_make_key.o \
+src/pk/ecc/ecc_recover_key.o src/pk/ecc/ecc_set_curve.o src/pk/ecc/ecc_set_curve_internal.o \
+src/pk/ecc/ecc_set_key.o src/pk/ecc/ecc_shared_secret.o src/pk/ecc/ecc_sign_hash.o \
+src/pk/ecc/ecc_sizes.o src/pk/ecc/ecc_ssh_ecdsa_encode_name.o src/pk/ecc/ecc_verify_hash.o \
+src/pk/ecc/ltc_ecc_export_point.o src/pk/ecc/ltc_ecc_import_point.o src/pk/ecc/ltc_ecc_is_point.o \
 src/pk/ecc/ltc_ecc_is_point_at_infinity.o src/pk/ecc/ltc_ecc_map.o src/pk/ecc/ltc_ecc_mul2add.o \
 src/pk/ecc/ltc_ecc_mulmod.o src/pk/ecc/ltc_ecc_mulmod_timing.o src/pk/ecc/ltc_ecc_points.o \
 src/pk/ecc/ltc_ecc_projective_add_point.o src/pk/ecc/ltc_ecc_projective_dbl_point.o \

+ 11 - 11
makefile.msvc

@@ -172,17 +172,17 @@ src/pk/dsa/dsa_decrypt_key.obj src/pk/dsa/dsa_encrypt_key.obj src/pk/dsa/dsa_exp
 src/pk/dsa/dsa_generate_key.obj src/pk/dsa/dsa_generate_pqg.obj src/pk/dsa/dsa_import.obj \
 src/pk/dsa/dsa_make_key.obj src/pk/dsa/dsa_set.obj src/pk/dsa/dsa_set_pqg_dsaparam.obj \
 src/pk/dsa/dsa_shared_secret.obj src/pk/dsa/dsa_sign_hash.obj src/pk/dsa/dsa_verify_hash.obj \
-src/pk/dsa/dsa_verify_key.obj src/pk/ec25519/ec25519_export.obj src/pk/ec25519/ec25519_import_pkcs8.obj \
-src/pk/ec25519/tweetnacl.obj src/pk/ecc/ecc.obj src/pk/ecc/ecc_ansi_x963_export.obj \
-src/pk/ecc/ecc_ansi_x963_import.obj src/pk/ecc/ecc_decrypt_key.obj src/pk/ecc/ecc_encrypt_key.obj \
-src/pk/ecc/ecc_export.obj src/pk/ecc/ecc_export_openssl.obj src/pk/ecc/ecc_find_curve.obj \
-src/pk/ecc/ecc_free.obj src/pk/ecc/ecc_get_key.obj src/pk/ecc/ecc_get_oid_str.obj src/pk/ecc/ecc_get_size.obj \
-src/pk/ecc/ecc_import.obj src/pk/ecc/ecc_import_openssl.obj src/pk/ecc/ecc_import_pkcs8.obj \
-src/pk/ecc/ecc_import_x509.obj src/pk/ecc/ecc_make_key.obj src/pk/ecc/ecc_recover_key.obj \
-src/pk/ecc/ecc_set_curve.obj src/pk/ecc/ecc_set_curve_internal.obj src/pk/ecc/ecc_set_key.obj \
-src/pk/ecc/ecc_shared_secret.obj src/pk/ecc/ecc_sign_hash.obj src/pk/ecc/ecc_sizes.obj \
-src/pk/ecc/ecc_ssh_ecdsa_encode_name.obj src/pk/ecc/ecc_verify_hash.obj src/pk/ecc/ltc_ecc_export_point.obj \
-src/pk/ecc/ltc_ecc_import_point.obj src/pk/ecc/ltc_ecc_is_point.obj \
+src/pk/dsa/dsa_verify_key.obj src/pk/ec25519/ec25519_crypto_ctx.obj src/pk/ec25519/ec25519_export.obj \
+src/pk/ec25519/ec25519_import_pkcs8.obj src/pk/ec25519/tweetnacl.obj src/pk/ecc/ecc.obj \
+src/pk/ecc/ecc_ansi_x963_export.obj src/pk/ecc/ecc_ansi_x963_import.obj src/pk/ecc/ecc_decrypt_key.obj \
+src/pk/ecc/ecc_encrypt_key.obj src/pk/ecc/ecc_export.obj src/pk/ecc/ecc_export_openssl.obj \
+src/pk/ecc/ecc_find_curve.obj src/pk/ecc/ecc_free.obj src/pk/ecc/ecc_get_key.obj src/pk/ecc/ecc_get_oid_str.obj \
+src/pk/ecc/ecc_get_size.obj src/pk/ecc/ecc_import.obj src/pk/ecc/ecc_import_openssl.obj \
+src/pk/ecc/ecc_import_pkcs8.obj src/pk/ecc/ecc_import_x509.obj src/pk/ecc/ecc_make_key.obj \
+src/pk/ecc/ecc_recover_key.obj src/pk/ecc/ecc_set_curve.obj src/pk/ecc/ecc_set_curve_internal.obj \
+src/pk/ecc/ecc_set_key.obj src/pk/ecc/ecc_shared_secret.obj src/pk/ecc/ecc_sign_hash.obj \
+src/pk/ecc/ecc_sizes.obj src/pk/ecc/ecc_ssh_ecdsa_encode_name.obj src/pk/ecc/ecc_verify_hash.obj \
+src/pk/ecc/ltc_ecc_export_point.obj src/pk/ecc/ltc_ecc_import_point.obj src/pk/ecc/ltc_ecc_is_point.obj \
 src/pk/ecc/ltc_ecc_is_point_at_infinity.obj src/pk/ecc/ltc_ecc_map.obj src/pk/ecc/ltc_ecc_mul2add.obj \
 src/pk/ecc/ltc_ecc_mulmod.obj src/pk/ecc/ltc_ecc_mulmod_timing.obj src/pk/ecc/ltc_ecc_points.obj \
 src/pk/ecc/ltc_ecc_projective_add_point.obj src/pk/ecc/ltc_ecc_projective_dbl_point.obj \

+ 11 - 11
makefile.unix

@@ -189,17 +189,17 @@ src/pk/dsa/dsa_decrypt_key.o src/pk/dsa/dsa_encrypt_key.o src/pk/dsa/dsa_export.
 src/pk/dsa/dsa_generate_key.o src/pk/dsa/dsa_generate_pqg.o src/pk/dsa/dsa_import.o \
 src/pk/dsa/dsa_make_key.o src/pk/dsa/dsa_set.o src/pk/dsa/dsa_set_pqg_dsaparam.o \
 src/pk/dsa/dsa_shared_secret.o src/pk/dsa/dsa_sign_hash.o src/pk/dsa/dsa_verify_hash.o \
-src/pk/dsa/dsa_verify_key.o src/pk/ec25519/ec25519_export.o src/pk/ec25519/ec25519_import_pkcs8.o \
-src/pk/ec25519/tweetnacl.o src/pk/ecc/ecc.o src/pk/ecc/ecc_ansi_x963_export.o \
-src/pk/ecc/ecc_ansi_x963_import.o src/pk/ecc/ecc_decrypt_key.o src/pk/ecc/ecc_encrypt_key.o \
-src/pk/ecc/ecc_export.o src/pk/ecc/ecc_export_openssl.o src/pk/ecc/ecc_find_curve.o \
-src/pk/ecc/ecc_free.o src/pk/ecc/ecc_get_key.o src/pk/ecc/ecc_get_oid_str.o src/pk/ecc/ecc_get_size.o \
-src/pk/ecc/ecc_import.o src/pk/ecc/ecc_import_openssl.o src/pk/ecc/ecc_import_pkcs8.o \
-src/pk/ecc/ecc_import_x509.o src/pk/ecc/ecc_make_key.o src/pk/ecc/ecc_recover_key.o \
-src/pk/ecc/ecc_set_curve.o src/pk/ecc/ecc_set_curve_internal.o src/pk/ecc/ecc_set_key.o \
-src/pk/ecc/ecc_shared_secret.o src/pk/ecc/ecc_sign_hash.o src/pk/ecc/ecc_sizes.o \
-src/pk/ecc/ecc_ssh_ecdsa_encode_name.o src/pk/ecc/ecc_verify_hash.o src/pk/ecc/ltc_ecc_export_point.o \
-src/pk/ecc/ltc_ecc_import_point.o src/pk/ecc/ltc_ecc_is_point.o \
+src/pk/dsa/dsa_verify_key.o src/pk/ec25519/ec25519_crypto_ctx.o src/pk/ec25519/ec25519_export.o \
+src/pk/ec25519/ec25519_import_pkcs8.o src/pk/ec25519/tweetnacl.o src/pk/ecc/ecc.o \
+src/pk/ecc/ecc_ansi_x963_export.o src/pk/ecc/ecc_ansi_x963_import.o src/pk/ecc/ecc_decrypt_key.o \
+src/pk/ecc/ecc_encrypt_key.o src/pk/ecc/ecc_export.o src/pk/ecc/ecc_export_openssl.o \
+src/pk/ecc/ecc_find_curve.o src/pk/ecc/ecc_free.o src/pk/ecc/ecc_get_key.o src/pk/ecc/ecc_get_oid_str.o \
+src/pk/ecc/ecc_get_size.o src/pk/ecc/ecc_import.o src/pk/ecc/ecc_import_openssl.o \
+src/pk/ecc/ecc_import_pkcs8.o src/pk/ecc/ecc_import_x509.o src/pk/ecc/ecc_make_key.o \
+src/pk/ecc/ecc_recover_key.o src/pk/ecc/ecc_set_curve.o src/pk/ecc/ecc_set_curve_internal.o \
+src/pk/ecc/ecc_set_key.o src/pk/ecc/ecc_shared_secret.o src/pk/ecc/ecc_sign_hash.o \
+src/pk/ecc/ecc_sizes.o src/pk/ecc/ecc_ssh_ecdsa_encode_name.o src/pk/ecc/ecc_verify_hash.o \
+src/pk/ecc/ltc_ecc_export_point.o src/pk/ecc/ltc_ecc_import_point.o src/pk/ecc/ltc_ecc_is_point.o \
 src/pk/ecc/ltc_ecc_is_point_at_infinity.o src/pk/ecc/ltc_ecc_map.o src/pk/ecc/ltc_ecc_mul2add.o \
 src/pk/ecc/ltc_ecc_mulmod.o src/pk/ecc/ltc_ecc_mulmod_timing.o src/pk/ecc/ltc_ecc_points.o \
 src/pk/ecc/ltc_ecc_projective_add_point.o src/pk/ecc/ltc_ecc_projective_dbl_point.o \

+ 11 - 11
makefile_include.mk

@@ -350,17 +350,17 @@ src/pk/dsa/dsa_decrypt_key.o src/pk/dsa/dsa_encrypt_key.o src/pk/dsa/dsa_export.
 src/pk/dsa/dsa_generate_key.o src/pk/dsa/dsa_generate_pqg.o src/pk/dsa/dsa_import.o \
 src/pk/dsa/dsa_make_key.o src/pk/dsa/dsa_set.o src/pk/dsa/dsa_set_pqg_dsaparam.o \
 src/pk/dsa/dsa_shared_secret.o src/pk/dsa/dsa_sign_hash.o src/pk/dsa/dsa_verify_hash.o \
-src/pk/dsa/dsa_verify_key.o src/pk/ec25519/ec25519_export.o src/pk/ec25519/ec25519_import_pkcs8.o \
-src/pk/ec25519/tweetnacl.o src/pk/ecc/ecc.o src/pk/ecc/ecc_ansi_x963_export.o \
-src/pk/ecc/ecc_ansi_x963_import.o src/pk/ecc/ecc_decrypt_key.o src/pk/ecc/ecc_encrypt_key.o \
-src/pk/ecc/ecc_export.o src/pk/ecc/ecc_export_openssl.o src/pk/ecc/ecc_find_curve.o \
-src/pk/ecc/ecc_free.o src/pk/ecc/ecc_get_key.o src/pk/ecc/ecc_get_oid_str.o src/pk/ecc/ecc_get_size.o \
-src/pk/ecc/ecc_import.o src/pk/ecc/ecc_import_openssl.o src/pk/ecc/ecc_import_pkcs8.o \
-src/pk/ecc/ecc_import_x509.o src/pk/ecc/ecc_make_key.o src/pk/ecc/ecc_recover_key.o \
-src/pk/ecc/ecc_set_curve.o src/pk/ecc/ecc_set_curve_internal.o src/pk/ecc/ecc_set_key.o \
-src/pk/ecc/ecc_shared_secret.o src/pk/ecc/ecc_sign_hash.o src/pk/ecc/ecc_sizes.o \
-src/pk/ecc/ecc_ssh_ecdsa_encode_name.o src/pk/ecc/ecc_verify_hash.o src/pk/ecc/ltc_ecc_export_point.o \
-src/pk/ecc/ltc_ecc_import_point.o src/pk/ecc/ltc_ecc_is_point.o \
+src/pk/dsa/dsa_verify_key.o src/pk/ec25519/ec25519_crypto_ctx.o src/pk/ec25519/ec25519_export.o \
+src/pk/ec25519/ec25519_import_pkcs8.o src/pk/ec25519/tweetnacl.o src/pk/ecc/ecc.o \
+src/pk/ecc/ecc_ansi_x963_export.o src/pk/ecc/ecc_ansi_x963_import.o src/pk/ecc/ecc_decrypt_key.o \
+src/pk/ecc/ecc_encrypt_key.o src/pk/ecc/ecc_export.o src/pk/ecc/ecc_export_openssl.o \
+src/pk/ecc/ecc_find_curve.o src/pk/ecc/ecc_free.o src/pk/ecc/ecc_get_key.o src/pk/ecc/ecc_get_oid_str.o \
+src/pk/ecc/ecc_get_size.o src/pk/ecc/ecc_import.o src/pk/ecc/ecc_import_openssl.o \
+src/pk/ecc/ecc_import_pkcs8.o src/pk/ecc/ecc_import_x509.o src/pk/ecc/ecc_make_key.o \
+src/pk/ecc/ecc_recover_key.o src/pk/ecc/ecc_set_curve.o src/pk/ecc/ecc_set_curve_internal.o \
+src/pk/ecc/ecc_set_key.o src/pk/ecc/ecc_shared_secret.o src/pk/ecc/ecc_sign_hash.o \
+src/pk/ecc/ecc_sizes.o src/pk/ecc/ecc_ssh_ecdsa_encode_name.o src/pk/ecc/ecc_verify_hash.o \
+src/pk/ecc/ltc_ecc_export_point.o src/pk/ecc/ltc_ecc_import_point.o src/pk/ecc/ltc_ecc_is_point.o \
 src/pk/ecc/ltc_ecc_is_point_at_infinity.o src/pk/ecc/ltc_ecc_map.o src/pk/ecc/ltc_ecc_mul2add.o \
 src/pk/ecc/ltc_ecc_mulmod.o src/pk/ecc/ltc_ecc_mulmod_timing.o src/pk/ecc/ltc_ecc_points.o \
 src/pk/ecc/ltc_ecc_projective_add_point.o src/pk/ecc/ltc_ecc_projective_dbl_point.o \

+ 22 - 4
src/headers/tomcrypt_pk.h

@@ -355,13 +355,31 @@ int ed25519_import_pkcs8(const unsigned char *in, unsigned long inlen,
                                   const void *pwd, unsigned long pwdlen,
                               curve25519_key *key);
 
-int ed25519_sign(const unsigned char  *msg, unsigned long msglen,
-                       unsigned char  *sig, unsigned long *siglen,
+int ed25519_sign(const  unsigned char *msg, unsigned long msglen,
+                        unsigned char *sig, unsigned long *siglen,
                  const curve25519_key *private_key);
-
+int ed25519ctx_sign(const  unsigned char *msg, unsigned long  msglen,
+                           unsigned char *sig, unsigned long *siglen,
+                    const  unsigned char *ctx, unsigned long  ctxlen,
+                    const curve25519_key *private_key);
+int ed25519ph_sign(const  unsigned char *msg, unsigned long  msglen,
+                          unsigned char *sig, unsigned long *siglen,
+                   const  unsigned char *ctx, unsigned long  ctxlen,
+                   const curve25519_key *private_key);
 int ed25519_verify(const  unsigned char *msg, unsigned long msglen,
                    const  unsigned char *sig, unsigned long siglen,
-                   int *stat, const curve25519_key *public_key);
+                                    int *stat,
+                   const curve25519_key *public_key);
+int ed25519ctx_verify(const  unsigned char *msg, unsigned long msglen,
+                      const  unsigned char *sig, unsigned long siglen,
+                      const  unsigned char *ctx, unsigned long ctxlen,
+                                       int *stat,
+                      const curve25519_key *public_key);
+int ed25519ph_verify(const  unsigned char *msg, unsigned long msglen,
+                     const  unsigned char *sig, unsigned long siglen,
+                     const  unsigned char *ctx, unsigned long ctxlen,
+                                      int *stat,
+                     const curve25519_key *public_key);
 
 /** X25519 Key-Exchange API */
 int x25519_make_key(prng_state *prng, int wprng, curve25519_key *key);

+ 7 - 1
src/headers/tomcrypt_private.h

@@ -331,16 +331,19 @@ int dsa_int_validate_primes(const dsa_key *key, int *stat);
 int tweetnacl_crypto_sign(
   unsigned char *sm,unsigned long long *smlen,
   const unsigned char *m,unsigned long long mlen,
-  const unsigned char *sk, const unsigned char *pk);
+  const unsigned char *sk,const unsigned char *pk,
+  const unsigned char *ctx,unsigned long long cs);
 int tweetnacl_crypto_sign_open(
   int *stat,
   unsigned char *m,unsigned long long *mlen,
   const unsigned char *sm,unsigned long long smlen,
+  const unsigned char *ctx, unsigned long cs,
   const unsigned char *pk);
 int tweetnacl_crypto_sign_keypair(prng_state *prng, int wprng, unsigned char *pk,unsigned char *sk);
 int tweetnacl_crypto_sk_to_pk(unsigned char *pk, const unsigned char *sk);
 int tweetnacl_crypto_scalarmult(unsigned char *q, const unsigned char *n, const unsigned char *p);
 int tweetnacl_crypto_scalarmult_base(unsigned char *q,const unsigned char *n);
+int tweetnacl_crypto_ph(unsigned char *out, const unsigned char *msg, unsigned long msglen);
 
 typedef int (*sk_to_pk)(unsigned char *pk ,const unsigned char *sk);
 int ec25519_import_pkcs8(const unsigned char *in, unsigned long inlen,
@@ -350,6 +353,9 @@ int ec25519_import_pkcs8(const unsigned char *in, unsigned long inlen,
 int ec25519_export(       unsigned char *out, unsigned long *outlen,
                                     int  which,
                    const curve25519_key *key);
+int ec25519_crypto_ctx(      unsigned char *out, unsigned long *outlen,
+                             unsigned char flag,
+                       const unsigned char *ctx, unsigned long  ctxlen);
 #endif /* LTC_CURVE25519 */
 
 #ifdef LTC_DER

+ 40 - 0
src/pk/ec25519/ec25519_crypto_ctx.c

@@ -0,0 +1,40 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+#include "tomcrypt_private.h"
+
+/**
+  @file ec25519_crypto_ctx.c
+  curve25519 crypto context helper
+*/
+
+#ifdef LTC_CURVE25519
+
+int ec25519_crypto_ctx(unsigned char *out, unsigned long *outlen, unsigned char flag, const unsigned char *ctx, unsigned long ctxlen)
+{
+  unsigned char *buf = out;
+
+  const char *prefix = "SigEd25519 no Ed25519 collisions";
+  const unsigned long prefix_len = XSTRLEN(prefix);
+  const unsigned char ctxlen8 = (unsigned char)ctxlen;
+
+  if (ctxlen > 255u) return CRYPT_INPUT_TOO_LONG;
+  if (*outlen < prefix_len + 2u + ctxlen) return CRYPT_BUFFER_OVERFLOW;
+
+  XMEMCPY(buf, prefix, prefix_len);
+  buf += prefix_len;
+  XMEMCPY(buf, &flag, 1);
+  buf++;
+  XMEMCPY(buf, &ctxlen8, 1);
+  buf++;
+
+  if (ctxlen > 0u) {
+    XMEMCPY(buf, ctx, ctxlen);
+    buf += ctxlen;
+  }
+
+  *outlen = buf-out;
+
+  return CRYPT_OK;
+}
+
+#endif

+ 31 - 5
src/pk/ec25519/tweetnacl.c

@@ -235,6 +235,27 @@ static int tweetnacl_crypto_hash(u8 *out,const u8 *m,u64 n)
   return 0;
 }
 
+static int tweetnacl_crypto_hash_ctx(u8 *out,const u8 *m,u64 n,const u8 *ctx,u32 cs)
+{
+  unsigned long len;
+  int err;
+  u8 buf[512];
+
+  if(cs == 0)
+    return tweetnacl_crypto_hash(out,m,n);
+
+  len = n + cs;
+  if (len > 512) return CRYPT_HASH_OVERFLOW;
+
+  XMEMCPY(buf,ctx,cs);
+  XMEMCPY(buf+cs,m,n);
+
+  err = tweetnacl_crypto_hash(out,buf,len);
+  zeromem(buf, len);
+
+  return err;
+}
+
 sv add(gf p[4],gf q[4])
 {
   gf a,b,c,d,t,e,f,g,h;
@@ -376,7 +397,7 @@ sv reduce(u8 *r)
   modL(r,x);
 }
 
-int tweetnacl_crypto_sign(u8 *sm,u64 *smlen,const u8 *m,u64 mlen,const u8 *sk,const u8 *pk)
+int tweetnacl_crypto_sign(u8 *sm,u64 *smlen,const u8 *m,u64 mlen,const u8 *sk,const u8 *pk, const u8 *ctx, u64 cs)
 {
   u8 d[64],h[64],r[64];
   i64 i,j,x[64];
@@ -391,13 +412,13 @@ int tweetnacl_crypto_sign(u8 *sm,u64 *smlen,const u8 *m,u64 mlen,const u8 *sk,co
   FOR(i,(i64)mlen) sm[64 + i] = m[i];
   FOR(i,32) sm[32 + i] = d[32 + i];
 
-  tweetnacl_crypto_hash(r, sm+32, mlen+32);
+  tweetnacl_crypto_hash_ctx(r, sm+32, mlen+32,ctx,cs);
   reduce(r);
   scalarbase(p,r);
   pack(sm,p);
 
   FOR(i,32) sm[i+32] = pk[i];
-  tweetnacl_crypto_hash(h,sm,mlen + 64);
+  tweetnacl_crypto_hash_ctx(h,sm,mlen + 64,ctx,cs);
   reduce(h);
 
   FOR(i,64) x[i] = 0;
@@ -444,7 +465,7 @@ static int unpackneg(gf r[4],const u8 p[32])
   return 0;
 }
 
-int tweetnacl_crypto_sign_open(int *stat, u8 *m,u64 *mlen,const u8 *sm,u64 smlen,const u8 *pk)
+int tweetnacl_crypto_sign_open(int *stat, u8 *m,u64 *mlen,const u8 *sm,u64 smlen,const u8 *ctx,size_t cs,const u8 *pk)
 {
   u64 i;
   u8 s[32],t[32],h[64];
@@ -460,7 +481,7 @@ int tweetnacl_crypto_sign_open(int *stat, u8 *m,u64 *mlen,const u8 *sm,u64 smlen
   XMEMMOVE(m,sm,smlen);
   XMEMMOVE(s,m + 32,32);
   XMEMMOVE(m + 32,pk,32);
-  tweetnacl_crypto_hash(h,m,smlen);
+  tweetnacl_crypto_hash_ctx(h,m,smlen,ctx,cs);
   reduce(h);
   scalarmult(p,q,h);
 
@@ -480,3 +501,8 @@ int tweetnacl_crypto_sign_open(int *stat, u8 *m,u64 *mlen,const u8 *sm,u64 smlen
   *mlen = smlen;
   return CRYPT_OK;
 }
+
+int tweetnacl_crypto_ph(u8 *out,const u8 *msg,size_t msglen)
+{
+  return tweetnacl_crypto_hash(out, msg, msglen);
+}

+ 81 - 12
src/pk/ed25519/ed25519_sign.c

@@ -9,17 +9,10 @@
 
 #ifdef LTC_CURVE25519
 
-/**
-   Create an Ed25519 signature.
-   @param private_key     The private Ed25519 key in the pair
-   @param public_key      The public Ed25519 key in the pair
-   @param out             [out] The destination of the shared data
-   @param outlen          [in/out] The max size and resulting size of the shared data.
-   @return CRYPT_OK if successful
-*/
-int ed25519_sign(const unsigned char  *msg, unsigned long msglen,
-                       unsigned char  *sig, unsigned long *siglen,
-                 const curve25519_key *private_key)
+static int s_ed25519_sign(const unsigned char  *msg, unsigned long  msglen,
+                                unsigned char  *sig, unsigned long *siglen,
+                          const unsigned char  *ctx, unsigned long  ctxlen,
+                          const curve25519_key *private_key)
 {
    unsigned char *s;
    unsigned long long smlen;
@@ -44,7 +37,8 @@ int ed25519_sign(const unsigned char  *msg, unsigned long msglen,
 
    err = tweetnacl_crypto_sign(s, &smlen,
                                msg, msglen,
-                               private_key->priv, private_key->pub);
+                               private_key->priv, private_key->pub,
+                               ctx, ctxlen);
 
    XMEMCPY(sig, s, 64uL);
    *siglen = 64uL;
@@ -57,4 +51,79 @@ int ed25519_sign(const unsigned char  *msg, unsigned long msglen,
    return err;
 }
 
+/**
+   Create an Ed25519ctx signature.
+   @param msg             The data to be signed
+   @param msglen          [in] The size of the date to be signed
+   @param sig             [out] The destination of the shared data
+   @param siglen          [in/out] The max size and resulting size of the shared data.
+   @param ctx             [in] The context is a constant null terminated string
+   @param private_key     The private Ed25519 key in the pair
+   @return CRYPT_OK if successful
+*/
+int ed25519ctx_sign(const  unsigned char *msg, unsigned long  msglen,
+                           unsigned char *sig, unsigned long *siglen,
+                    const  unsigned char *ctx, unsigned long  ctxlen,
+                    const curve25519_key *private_key)
+{
+   int err;
+   unsigned char ctx_prefix[512] = {0};
+   unsigned long ctx_prefix_size = sizeof(ctx_prefix);
+
+   LTC_ARGCHK(ctx != NULL);
+
+   if ((err = ec25519_crypto_ctx(ctx_prefix, &ctx_prefix_size, 0, ctx, ctxlen)) != CRYPT_OK)
+      return err;
+
+   return s_ed25519_sign(msg, msglen, sig, siglen, ctx_prefix, ctx_prefix_size, private_key);
+}
+
+/**
+   Create an Ed25519ph signature.
+   @param msg             The data to be signed
+   @param msglen          [in] The size of the date to be signed
+   @param sig             [out] The destination of the shared data
+   @param siglen          [in/out] The max size and resulting size of the shared data.
+   @param ctx             [in] The context is a constant null terminated string
+   @param private_key     The private Ed25519 key in the pair
+   @return CRYPT_OK if successful
+*/
+int ed25519ph_sign(const  unsigned char *msg, unsigned long  msglen,
+                          unsigned char *sig, unsigned long *siglen,
+                   const  unsigned char *ctx, unsigned long  ctxlen,
+                   const curve25519_key *private_key)
+{
+   int err;
+   unsigned char ctx_prefix[512] = {0};
+   unsigned char msg_hash[64] = {0};
+   unsigned long ctx_prefix_size = sizeof(ctx_prefix);
+
+   if ((err = ec25519_crypto_ctx(ctx_prefix, &ctx_prefix_size, 1, ctx, ctxlen)) != CRYPT_OK)
+      return err;
+
+   if ((err = tweetnacl_crypto_ph(msg_hash, msg, msglen)) != CRYPT_OK)
+      return err;
+
+   msg = msg_hash;
+   msglen = 64;
+
+   return s_ed25519_sign(msg, msglen, sig, siglen, ctx_prefix, ctx_prefix_size, private_key);
+}
+
+/**
+   Create an Ed25519 signature.
+   @param msg             The data to be signed
+   @param msglen          [in] The size of the date to be signed
+   @param sig             [out] The destination of the shared data
+   @param siglen          [in/out] The max size and resulting size of the shared data.
+   @param private_key     The private Ed25519 key in the pair
+   @return CRYPT_OK if successful
+*/
+int ed25519_sign(const  unsigned char *msg, unsigned long msglen,
+                        unsigned char *sig, unsigned long *siglen,
+                 const curve25519_key *private_key)
+{
+   return s_ed25519_sign(msg, msglen, sig, siglen, NULL, 0, private_key);
+}
+
 #endif

+ 89 - 13
src/pk/ed25519/ed25519_verify.c

@@ -9,18 +9,11 @@
 
 #ifdef LTC_CURVE25519
 
-/**
-   Verify an Ed25519 signature.
-   @param private_key     The private Ed25519 key in the pair
-   @param public_key      The public Ed25519 key in the pair
-   @param out             [out] The destination of the shared data
-   @param outlen          [in/out] The max size and resulting size of the shared data.
-   @param stat            [out] The result of the signature verification, 1==valid, 0==invalid
-   @return CRYPT_OK if successful
-*/
-int ed25519_verify(const  unsigned char *msg, unsigned long msglen,
-                   const  unsigned char *sig, unsigned long siglen,
-                   int *stat, const curve25519_key *public_key)
+static int s_ed25519_verify(const  unsigned char *msg, unsigned long msglen,
+                            const  unsigned char *sig, unsigned long siglen,
+                            const  unsigned char *ctx, unsigned long ctxlen,
+                                             int *stat,
+                            const curve25519_key *public_key)
 {
    unsigned char* m;
    unsigned long long mlen;
@@ -48,14 +41,97 @@ int ed25519_verify(const  unsigned char *msg, unsigned long msglen,
    err = tweetnacl_crypto_sign_open(stat,
                                     m, &mlen,
                                     m, mlen,
+                                    ctx, ctxlen,
                                     public_key->pub);
 
 #ifdef LTC_CLEAN_STACK
-   zeromem(m, mlen);
+   zeromem(m, msglen + siglen);
 #endif
    XFREE(m);
 
    return err;
 }
 
+/**
+   Verify an Ed25519ctx signature.
+   @param msg             [in] The data to be verified
+   @param msglen          [in] The size of the data to be verified
+   @param sig             [in] The signature to be verified
+   @param siglen          [in] The size of the signature to be verified
+   @param ctx             [in] The context
+   @param ctxlen          [in] The size of the context
+   @param stat            [out] The result of the signature verification, 1==valid, 0==invalid
+   @param public_key      [in] The public Ed25519 key in the pair
+   @return CRYPT_OK if successful
+*/
+int ed25519ctx_verify(const  unsigned char *msg, unsigned long msglen,
+                      const  unsigned char *sig, unsigned long siglen,
+                      const  unsigned char *ctx, unsigned long ctxlen,
+                                       int *stat,
+                      const curve25519_key *public_key)
+{
+   unsigned char ctx_prefix[512] = {0};
+   unsigned long ctx_prefix_size = sizeof(ctx_prefix);
+
+   LTC_ARGCHK(ctx != NULL);
+
+   if (ec25519_crypto_ctx(ctx_prefix, &ctx_prefix_size, 0, ctx, ctxlen) != CRYPT_OK)
+      return CRYPT_INVALID_ARG;
+
+   return s_ed25519_verify(msg, msglen, sig, siglen, ctx_prefix, ctx_prefix_size, stat, public_key);
+}
+
+/**
+   Verify an Ed25519ph signature.
+   @param msg             [in] The data to be verified
+   @param msglen          [in] The size of the data to be verified
+   @param sig             [in] The signature to be verified
+   @param siglen          [in] The size of the signature to be verified
+   @param ctx             [in] The context
+   @param ctxlen          [in] The size of the context
+   @param stat            [out] The result of the signature verification, 1==valid, 0==invalid
+   @param public_key      [in] The public Ed25519 key in the pair
+   @return CRYPT_OK if successful
+*/
+int ed25519ph_verify(const  unsigned char *msg, unsigned long msglen,
+                     const  unsigned char *sig, unsigned long siglen,
+                     const  unsigned char *ctx, unsigned long ctxlen,
+                                      int *stat,
+                     const curve25519_key *public_key)
+{
+   int err;
+   unsigned char ctx_prefix[512] = {0};
+   unsigned char msg_hash[64] = {0};
+   unsigned long ctx_prefix_size = sizeof(ctx_prefix);
+
+   if ((err = ec25519_crypto_ctx(ctx_prefix, &ctx_prefix_size, 1, ctx, ctxlen)) != CRYPT_OK)
+      return err;
+
+   if ((err = tweetnacl_crypto_ph(msg_hash, msg, msglen)) != CRYPT_OK)
+      return err;
+
+   msg = msg_hash;
+   msglen = 64;
+
+   return s_ed25519_verify(msg, msglen, sig, siglen, ctx_prefix, ctx_prefix_size, stat, public_key);
+}
+
+/**
+   Verify an Ed25519 signature.
+   @param msg             [in] The data to be verified
+   @param msglen          [in] The size of the data to be verified
+   @param sig             [in] The signature to be verified
+   @param siglen          [in] The size of the signature to be verified
+   @param stat            [out] The result of the signature verification, 1==valid, 0==invalid
+   @param public_key      [in] The public Ed25519 key in the pair
+   @return CRYPT_OK if successful
+*/
+int ed25519_verify(const  unsigned char *msg, unsigned long msglen,
+                   const  unsigned char *sig, unsigned long siglen,
+                                    int *stat,
+                   const curve25519_key *public_key)
+{
+   return s_ed25519_verify(msg, msglen, sig, siglen, NULL, 0, stat, public_key);
+}
+
 #endif

+ 182 - 7
tests/ed25519_test.c

@@ -9,6 +9,13 @@
 
 #ifdef LTC_CURVE25519
 
+static void xor_shuffle(unsigned char *buf, unsigned long size, unsigned char change)
+{
+   unsigned long i;
+   for(i = 0; i < size; i++)
+      buf[i] ^= change;
+}
+
 static int s_rfc_8410_10_test(void)
 {
    const struct {
@@ -87,11 +94,12 @@ typedef struct {
    const char* public_key;
    const char* message;
    const char* signature;
-} rfc_8032_7_1_t;
+   const char* context;
+} rfc_8032_7_t;
 
 static int s_rfc_8032_7_1_test(void)
 {
-   const rfc_8032_7_1_t rfc_8032_7_1[] = {
+   const rfc_8032_7_t rfc_8032_7_1[] = {
       {
          /* SECRET KEY */
          "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60",
@@ -101,7 +109,9 @@ static int s_rfc_8032_7_1_test(void)
          "",
          /* SIGNATURE */
          "e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e06522490155"
-         "5fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b"
+         "5fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b",
+         /* CONTEXT */
+         NULL
       },
       {
          /* SECRET KEY */
@@ -112,7 +122,9 @@ static int s_rfc_8032_7_1_test(void)
          "72",
          /* SIGNATURE */
          "92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da"
-         "085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00"
+         "085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00",
+         /* CONTEXT */
+         NULL
       },
       {
          /* SECRET KEY */
@@ -123,7 +135,9 @@ static int s_rfc_8032_7_1_test(void)
          "af82",
          /* SIGNATURE */
          "6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac"
-         "18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a"
+         "18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a",
+         /* CONTEXT */
+         NULL
       },
       {
          /* SECRET KEY */
@@ -165,7 +179,9 @@ static int s_rfc_8032_7_1_test(void)
          "0618983f8741c5ef68d3a101e8a3b8cac60c905c15fc910840b94c00a0b9d0",
          /* SIGNATURE */
          "0aab4c900501b3e24d7cdf4663326a3a87df5e4843b2cbdb67cbf6e460fec350"
-         "aa5371b1508f9f4528ecea23c436d94b5e8fcd4f681e30a6ac00a9704a188a03"
+         "aa5371b1508f9f4528ecea23c436d94b5e8fcd4f681e30a6ac00a9704a188a03",
+         /* CONTEXT */
+         NULL
       },
       {
          /* SECRET KEY */
@@ -177,7 +193,9 @@ static int s_rfc_8032_7_1_test(void)
          "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f",
          /* SIGNATURE */
          "dc2a4459e7369633a52b1bf277839a00201009a3efbf3ecb69bea2186c26b589"
-         "09351fc9ac90b3ecfdfbc7c66431e0303dca179c138ac17ad9bef1177331a704"
+         "09351fc9ac90b3ecfdfbc7c66431e0303dca179c138ac17ad9bef1177331a704",
+         /* CONTEXT */
+         NULL
       }
    };
    unsigned int n;
@@ -202,6 +220,13 @@ static int s_rfc_8032_7_1_test(void)
       DO(ed25519_verify(msg, mlen, sig, siglen, &ret, &key));
       DO(do_compare_testvector(&ret, sizeof(ret), &should, sizeof(should), "Ed25519 RFC8032 7.1 - verify w/ privkey", n));
 
+      xor_shuffle(sig, siglen, 0x8u);
+      DO( ed25519_verify(msg, mlen, sig, siglen, &ret, &key));
+      ENSUREX(ret != 1, "ed25519_verify is expected to fail on the modified signature");
+      xor_shuffle(msg, mlen, 0xfu);
+      DO( ed25519_verify(msg, mlen, sig, siglen, &ret, &key));
+      ENSUREX(ret != 1, "ed25519_verify is expected to fail on the modified message");
+
       plen = sizeof(pub);
       DO(base16_decode(rfc_8032_7_1[n].public_key, XSTRLEN(rfc_8032_7_1[n].public_key), pub, &plen));
       mlen = sizeof(msg);
@@ -218,6 +243,150 @@ static int s_rfc_8032_7_1_test(void)
    return CRYPT_OK;
 }
 
+static int s_rfc_8032_7_2_test(void)
+{
+   const rfc_8032_7_t rfc_8032_7_2[] = {
+       {
+         /* SECRET KEY */
+         "0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6",
+         /* PUBLIC KEY */
+         "dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292",
+         /* MESSAGE (length 16 bytes) */
+         "f726936d19c800494e3fdaff20b276a8",
+         /* SIGNATURE */
+         "55a4cc2f70a54e04288c5f4cd1e45a7bb520b36292911876cada7323198dd87a"
+         "8b36950b95130022907a7fb7c4e9b2d5f6cca685a587b4b21f4b888e4e7edb0d",
+         /* CONTEXT */
+         "666f6f",
+      },
+      {
+         /* SECRET KEY */
+         "0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6",
+         /* PUBLIC KEY */
+         "dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292",
+         /* MESSAGE (length 16 bytes) */
+         "f726936d19c800494e3fdaff20b276a8",
+         /* SIGNATURE */
+         "fc60d5872fc46b3aa69f8b5b4351d5808f92bcc044606db097abab6dbcb1aee3"
+         "216c48e8b3b66431b5b186d1d28f8ee15a5ca2df6668346291c2043d4eb3e90d",
+         /* CONTEXT */
+         "626172",
+      },
+      {
+         /* SECRET KEY */
+         "0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6",
+         /* PUBLIC KEY */
+         "dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292",
+         /* MESSAGE (length 16 bytes) */
+         "508e9e6882b979fea900f62adceaca35",
+         /* SIGNATURE */
+         "8b70c1cc8310e1de20ac53ce28ae6e7207f33c3295e03bb5c0732a1d20dc6490"
+         "8922a8b052cf99b7c4fe107a5abb5b2c4085ae75890d02df26269d8945f84b0b",
+         /* CONTEXT */
+         "666f6f",
+      },
+      {
+         /* SECRET KEY */
+         "ab9c2853ce297ddab85c993b3ae14bcad39b2c682beabc27d6d4eb20711d6560",
+         /* PUBLIC KEY */
+         "0f1d1274943b91415889152e893d80e93275a1fc0b65fd71b4b0dda10ad7d772",
+         /* MESSAGE (length 16 bytes) */
+         "f726936d19c800494e3fdaff20b276a8",
+         /* SIGNATURE */
+         "21655b5f1aa965996b3f97b3c849eafba922a0a62992f73b3d1b73106a84ad85"
+         "e9b86a7b6005ea868337ff2d20a7f5fbd4cd10b0be49a68da2b2e0dc0ad8960f",
+         /* CONTEXT */
+         "666f6f",
+      }
+   };
+
+   unsigned int n;
+   unsigned long mlen, slen, plen, siglen, buflen, ctxlen;
+   unsigned char msg[1024], sec[32], pub[32], sig[64], buf[64], ctx[64];
+   curve25519_key key, key2;
+   int ret;
+   const int should = 1;
+
+   for (n = 0; n < sizeof(rfc_8032_7_2)/sizeof(rfc_8032_7_2[0]); ++n) {
+      slen = sizeof(sec);
+      DO(base16_decode(rfc_8032_7_2[n].secret_key, XSTRLEN(rfc_8032_7_2[n].secret_key), sec, &slen));
+      plen = sizeof(pub);
+      DO(base16_decode(rfc_8032_7_2[n].public_key, XSTRLEN(rfc_8032_7_2[n].public_key), pub, &plen));
+      mlen = sizeof(msg);
+      DO(base16_decode(rfc_8032_7_2[n].message, XSTRLEN(rfc_8032_7_2[n].message), msg, &mlen));
+      siglen = sizeof(sig);
+      DO(base16_decode(rfc_8032_7_2[n].signature, XSTRLEN(rfc_8032_7_2[n].signature), sig, &siglen));
+      ctxlen = sizeof(ctx);
+      DO(base16_decode(rfc_8032_7_2[n].context, XSTRLEN(rfc_8032_7_2[n].context), ctx, &ctxlen));
+      buflen = sizeof(buf);
+
+      DO(ed25519_import_raw(sec, slen, PK_PRIVATE, &key));
+      DO(ed25519ctx_sign(msg, mlen, buf, &buflen, ctx, ctxlen, &key));
+      DO(do_compare_testvector(buf, buflen, sig, siglen, "Ed25519 RFC8032 7.2 - sign", n));
+      DO(ed25519ctx_verify(msg, mlen, buf, buflen, ctx, ctxlen, &ret, &key));
+      ENSUREX(ret == should, "Ed25519 RFC8032 7.2 - verify w/ privkey");
+
+      DO(ed25519_import_raw(pub, plen, PK_PUBLIC, &key2));
+      DO(ed25519ctx_verify(msg, mlen, sig, siglen, ctx, ctxlen, &ret, &key2));
+      ENSUREX(ret == should, "Ed25519 RFC8032 7.2 - verify w/ pubkey");
+
+      xor_shuffle(buf, buflen, 0x4u);
+      DO(ed25519ctx_verify(msg, mlen, buf, buflen, ctx, ctxlen, &ret, &key));
+      ENSUREX(ret != 1, "ed25519ctx_verify is expected to fail on the modified signature");
+      xor_shuffle(msg, mlen, 0x8u);
+      DO(ed25519ctx_verify(msg, mlen, buf, buflen, ctx, ctxlen, &ret, &key));
+      ENSUREX(ret != 1, "ed25519ctx_verify is expected to fail on the modified message");
+
+      zeromem(&key, sizeof(key));
+      zeromem(&key2, sizeof(key2));
+   }
+
+   return CRYPT_OK;
+}
+
+static int s_rfc_8032_7_3_test(void)
+{
+   const rfc_8032_7_t rfc_8032_7_3[] = {
+      {
+         /* SECRET KEY */
+         "833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42",
+         /* PUBLIC KEY */
+         "ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf",
+         /* MESSAGE (length 16 bytes) */
+         "616263",
+         /* SIGNATURE */
+         "98a70222f0b8121aa9d30f813d683f809e462b469c7ff87639499bb94e6dae41"
+         "31f85042463c2a355a2003d062adf5aaa10b8c61e636062aaad11c2a26083406",
+         /* CONTEXT */
+         NULL
+      },
+   };
+
+   unsigned long mlen, slen, plen, siglen, buflen;
+   unsigned char msg[1024], sec[32], pub[32], sig[64], buf[64];
+   curve25519_key key;
+   int ret;
+   const int should = 1;
+
+   buflen = sizeof(buf);
+   slen = sizeof(sec);
+   DO(base16_decode(rfc_8032_7_3[0].secret_key, XSTRLEN(rfc_8032_7_3[0].secret_key), sec, &slen));
+   plen = sizeof(pub);
+   DO(base16_decode(rfc_8032_7_3[0].public_key, XSTRLEN(rfc_8032_7_3[0].public_key), pub, &plen));
+   mlen = sizeof(msg);
+   DO(base16_decode(rfc_8032_7_3[0].message, XSTRLEN(rfc_8032_7_3[0].message), msg, &mlen));
+   siglen = sizeof(sig);
+   DO(base16_decode(rfc_8032_7_3[0].signature, XSTRLEN(rfc_8032_7_3[0].signature), sig, &siglen));
+
+   DO(ed25519_import_raw(sec, slen, PK_PRIVATE, &key));
+   DO(ed25519ph_sign(msg, mlen, buf, &buflen, NULL, 0, &key));
+   DO(do_compare_testvector(buf, buflen, sig, siglen, "Ed25519 RFC8032 7.3 - sign", 0));
+   DO(ed25519ph_verify(msg, mlen, buf, buflen, NULL, 0, &ret, &key));
+   ENSUREX(ret == should, "Ed25519 RFC8032 7.3 - verify w/ privkey");
+
+   return CRYPT_OK;
+}
+
 /**
   Test the ed25519 system
   @return CRYPT_OK if successful
@@ -239,6 +408,12 @@ int ed25519_test(void)
    if ((ret = s_rfc_8032_7_1_test()) != CRYPT_OK) {
       return ret;
    }
+   if ((ret = s_rfc_8032_7_2_test()) != CRYPT_OK) {
+      return ret;
+   }
+   if ((ret = s_rfc_8032_7_3_test()) != CRYPT_OK) {
+      return ret;
+   }
 
    return ret;
 }