소스 검색

Merge pull request #450 from libtom/pr/ecdsa-der-attempt1

Fix #449 (ECDSA forcing DER/ASN.1)
Steffen Jaeckel 7 달 전
부모
커밋
a6b9aff7aa

+ 97 - 53
doc/crypt.tex

@@ -1,4 +1,5 @@
 \documentclass[synpaper]{book}
 \documentclass[synpaper]{book}
+\usepackage[T1]{fontenc}
 \usepackage{geometry}
 \usepackage{geometry}
 \usepackage{hyperref}
 \usepackage{hyperref}
 \usepackage{makeidx}
 \usepackage{makeidx}
@@ -44,6 +45,7 @@
 \def\C{{\mathbb C}}
 \def\C{{\mathbb C}}
 \def\Q{{\mathbb Q}}
 \def\Q{{\mathbb Q}}
 \definecolor{DGray}{gray}{0.5}
 \definecolor{DGray}{gray}{0.5}
+\newcommand{\code}[1]{\texttt{\textit{#1}}}
 \newcommand{\emailaddr}[1]{\mbox{$<${#1}$>$}}
 \newcommand{\emailaddr}[1]{\mbox{$<${#1}$>$}}
 \def\twiddle{\raisebox{0.3ex}{\mbox{\tiny $\sim$}}}
 \def\twiddle{\raisebox{0.3ex}{\mbox{\tiny $\sim$}}}
 \def\gap{\vspace{0.5ex}}
 \def\gap{\vspace{0.5ex}}
@@ -5801,8 +5803,14 @@ The imported key is stored in the ECC key pointed to by \textit{key}.  The funct
 
 
 
 
 \mysection{Signatures (ECDSA)}
 \mysection{Signatures (ECDSA)}
-There are also functions to sign and verify messages. They use the ANSI X9.62 ECDSA algorithm to generate and verify signatures in the
-ANSI X9.62 format.
+There are also functions to sign and verify messages. They use the \textit{ANSI X9.62} \textit{ECDSA} algorithm to generate and verify signatures in the
+\textit{ANSI X9.62} format.
+
+\textbf{BEWARE:} With \textit{ECC} if you try to sign a hash that is bigger than your \textit{ECC} key you can run into problems. The math
+will still work, and in effect the signature will still work.  With \textit{ECC} keys the strength of the signature is limited
+by the size of the hash, or the size of the key, whichever is smaller.  For example, if you sign with SHA256 and a
+P--192 key, you have in effect 96--bits of security. The library will not warn you if you make this mistake, so it
+is important to check yourself before using the signatures.
 
 
 \subsection{Signature Generation}
 \subsection{Signature Generation}
 To sign a message digest (hash) use the following function:
 To sign a message digest (hash) use the following function:
@@ -5815,12 +5823,12 @@ int ecc_sign_hash(const unsigned char *in,
                         unsigned long *outlen,
                         unsigned long *outlen,
                            prng_state *prng,
                            prng_state *prng,
                                   int  wprng,
                                   int  wprng,
-                              ecc_key *key);
+                  const       ecc_key *key);
 \end{verbatim}
 \end{verbatim}
 
 
-This function will ECDSA sign the message digest stored in the array pointed to by \textit{in} of length \textit{inlen} octets.  The signature
-will be stored in the array pointed to by \textit{out} of length \textit{outlen} octets.  The function requires a properly seeded PRNG, and
-the ECC \textit{key} provided must be a private key.
+This function will \textit{ECDSA} sign the message digest stored in the array pointed to by \code{in} of length \code{inlen} octets.  The signature
+will be stored in the array pointed to by \code{out} of length \code{outlen} octets.  The function requires a properly seeded \textit{PRNG}, and
+the \textit{ECC} \code{key} provided must be a private key.
 
 
 \index{ecc\_sign\_hash\_rfc7518()}
 \index{ecc\_sign\_hash\_rfc7518()}
 \begin{verbatim}
 \begin{verbatim}
@@ -5830,27 +5838,53 @@ int ecc_sign_hash_rfc7518(const unsigned char *in,
                                 unsigned long *outlen,
                                 unsigned long *outlen,
                                    prng_state *prng,
                                    prng_state *prng,
                                           int  wprng,
                                           int  wprng,
-                                      ecc_key *key);
+                          const       ecc_key *key);
 \end{verbatim}
 \end{verbatim}
 
 
-This function creates the same ECDSA signature as \textit{ecc\_sign\_hash} only the output format is different.
+This function creates the same \textit{ECDSA} signature as \code{ecc\_sign\_hash()} only the output format is different.
 The format follows \url{https://tools.ietf.org/html/rfc7518#section-3.4}, sometimes it is also called plain signature.
 The format follows \url{https://tools.ietf.org/html/rfc7518#section-3.4}, sometimes it is also called plain signature.
 
 
-\index{ecc\_sign\_hash\_ex()}
+\index{ecc\_sign\_hash\_rfc7518\_ex()}
 \begin{verbatim}
 \begin{verbatim}
-int ecc_sign_hash_ex(const unsigned char *in,
-                           unsigned long  inlen,
-                           unsigned char *out,
-                           unsigned long *outlen,
-                              prng_state *prng,
-                                     int  wprng,
-                      ecc_signature_type  sigformat,
-                                     int *recid,
-                                 ecc_key *key);
+int ecc_sign_hash_rfc7518_ex(const unsigned char *in,
+                                   unsigned long  inlen,
+                                   unsigned char *out,
+                                   unsigned long *outlen,
+                                      prng_state *prng,
+                                             int  wprng,
+                                             int *recid,
+                             const       ecc_key *key);
+\end{verbatim}
+
+This function is an extended version of the \textit{ECDSA} signature in \code{ecc\_sign\_hash\_rfc7518()}, but with an additional output of the recovery ID
+for use with \code{ecc\_recover\_key()}.
+
+\index{ecc\_sign\_hash\_rfc5656()}
+\begin{verbatim}
+int ecc_sign_hash_rfc5656(const unsigned char *in,
+                                unsigned long  inlen,
+                                unsigned char *out,
+                                unsigned long *outlen,
+                                   prng_state *prng,
+                                          int  wprng,
+                          const       ecc_key *key);
+\end{verbatim}
+
+This function creates an \textit{ECDSA} signature and the output format is according to \textit{RFC5656}, i.e. \textit{SSH} compatible.
+
+\index{ecc\_sign\_hash\_eth27()}
+\begin{verbatim}
+int ecc_sign_hash_eth27(const unsigned char *in,
+                              unsigned long  inlen,
+                              unsigned char *out,
+                              unsigned long *outlen,
+                                 prng_state *prng,
+                                        int  wprng,
+                        const       ecc_key *key);
 \end{verbatim}
 \end{verbatim}
 
 
-This function is an extended version of the ECDSA signature in \textit{ecc\_sign\_hash}, but with a choice of output formats
-and an optional output of the recovery ID for use with \textit{ecc\_recover\_key}.
+This function creates an \textit{ECDSA} signature and the output format is according to the Ethereum format.
+With this API the curve is limited to \textit{secp256k1}.
 
 
 \subsection{Signature Verification}
 \subsection{Signature Verification}
 \index{ecc\_verify\_hash()}
 \index{ecc\_verify\_hash()}
@@ -5860,14 +5894,14 @@ int ecc_verify_hash(const unsigned char *sig,
                     const unsigned char *hash,
                     const unsigned char *hash,
                           unsigned long  hashlen,
                           unsigned long  hashlen,
                                     int *stat,
                                     int *stat,
-                                ecc_key *key);
+                    const       ecc_key *key);
 \end{verbatim}
 \end{verbatim}
 
 
-This function will verify the ECDSA signature in the array pointed to by \textit{sig} of length \textit{siglen} octets, against the message digest
-pointed to by the array \textit{hash} of length \textit{hashlen}. It will store a non--zero value in \textit{stat} if the signature is valid.  Note:
+This function will verify the \textit{ECDSA} signature in the array pointed to by \code{sig} of length \code{siglen} octets, against the message digest
+pointed to by the array \code{hash} of length \code{hashlen}. It will store a non--zero value in \code{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 return an error, if the actual signature payload is an invalid format.
-The ECC \textit{key} must be the public (or private) ECC key corresponding to the key that performed the signature.
-The function \textit{ecc\_verify\_hash} implements signature format according to X9.62 ECDSA, and the output is compliant for GF(p) curves.
+The \textit{ECC} \code{key} must be the public (or private) \textit{ECC} key corresponding to the key that performed the signature.
+The function \code{ecc\_verify\_hash()} implements signature format according to \textit{ANSI X9.62} EC\textit{DSA}, and the output is compliant for GF(p) curves.
 
 
 \index{ecc\_verify\_hash\_rfc7518()}
 \index{ecc\_verify\_hash\_rfc7518()}
 \begin{verbatim}
 \begin{verbatim}
@@ -5876,30 +5910,36 @@ int ecc_verify_hash_rfc7518(const unsigned char *sig,
                             const unsigned char *hash,
                             const unsigned char *hash,
                                   unsigned long  hashlen,
                                   unsigned long  hashlen,
                                             int *stat,
                                             int *stat,
-                                        ecc_key *key);
+                            const       ecc_key *key);
 \end{verbatim}
 \end{verbatim}
 
 
-This function validate the ECDSA signature as \textit{ecc\_verify\_hash} only the signature input format
+This function validates the \textit{ECDSA} signature as \code{ecc\_verify\_hash()}, only the signature input format
 follows \url{https://tools.ietf.org/html/rfc7518#section-3.4}.
 follows \url{https://tools.ietf.org/html/rfc7518#section-3.4}.
 
 
-\index{ecc\_verify\_hash\_ex()}
+\index{ecc\_verify\_hash\_rfc5656()}
 \begin{verbatim}
 \begin{verbatim}
-int ecc_verify_hash_ex(const unsigned char *sig,
-                             unsigned long  siglen,
-                       const unsigned char *hash,
-                             unsigned long  hashlen,
-                        ecc_signature_type  sigformat,
-                                       int *stat,
-                                   ecc_key *key);
+int ecc_verify_hash_rfc5656(const unsigned char *sig,
+                                  unsigned long  siglen,
+                            const unsigned char *hash,
+                                  unsigned long  hashlen,
+                                            int *stat,
+                            const       ecc_key *key);
 \end{verbatim}
 \end{verbatim}
 
 
-This function validates an ECDSA signature as \textit{ecc\_verify\_hash} but with a choice of signature formats.
+This function validates the \textit{ECDSA} signature according to the format defined in \textit{RFC5656}, i.e. \textit{SSH} compatible.
 
 
-{\bf BEWARE:} With ECC if you try to sign a hash that is bigger than your ECC key you can run into problems. The math
-will still work, and in effect the signature will still work.  With ECC keys the strength of the signature is limited
-by the size of the hash, or the size of the key, whichever is smaller.  For example, if you sign with SHA256 and a
-P--192 key, you have in effect 96--bits of security. The library will not warn you if you make this mistake, so it
-is important to check yourself before using the signatures.
+
+\index{ecc\_verify\_hash\_eth27()}
+\begin{verbatim}
+int ecc_verify_hash_eth27(const unsigned char *sig,
+                                unsigned long  siglen,
+                          const unsigned char *hash,
+                                unsigned long  hashlen,
+                                          int *stat,
+                          const       ecc_key *key);
+\end{verbatim}
+
+This function validates the \textit{ECDSA} signature according to the Ethereum format.
 
 
 \subsection{Public Key Recovery}
 \subsection{Public Key Recovery}
 \index{ecc\_recover\_key()}
 \index{ecc\_recover\_key()}
@@ -5913,18 +5953,18 @@ int ecc_recover_key(const unsigned char *sig,
                                 ecc_key *key);
                                 ecc_key *key);
 \end{verbatim}
 \end{verbatim}
 
 
-This function will recover (a) public key from the ECDSA signature in the array pointed to by \textit{sig} of length \textit{siglen} octets, the message digest
-pointed to by the array \textit{hash} of length \textit{hashlen}, and the recovery id \textit{recid}. It will store the recovered
-key into \textit{key} and return CRYPT\_OK if recovery succeeds, or an error if recovery fails.
+This function will recover (a) public key from the \textit{ECDSA} signature in the array pointed to by \code{sig} of length \code{siglen} octets, the message digest
+pointed to by the array \code{hash} of length \code{hashlen}, and the recovery id \code{recid}. It will store the recovered
+key into \code{key} and return \code{CRYPT\_OK} if recovery succeeds, or an error if recovery fails.
 This is for compatibility with the (v,r,s) signatures used in Ethereum, where public keys are not explicitly shared,
 This is for compatibility with the (v,r,s) signatures used in Ethereum, where public keys are not explicitly shared,
-only the parity of the public key. For curves like secp256k1, recid will take values of 0 or 1, corresponding to the
-parity of the public key's y coordinate. For curves like secp112r2, with a cofactor of 4, values 0..7 are possible,
+only the parity of the public key. For curves like \textit{secp256k1}, \code{recid} will take values of 0 or 1, corresponding to the
+parity of the public key's y coordinate. For curves like \textit{secp112r2}, with a cofactor of 4, values 0..7 are possible,
 with the low bit corresponding to the parity and the higher bits specifying the public key's x coordinate's multiple
 with the low bit corresponding to the parity and the higher bits specifying the public key's x coordinate's multiple
 of the curve's order.
 of the curve's order.
-If the signature format contains the recovery id (currently only \textit{LTC\_ECCSIG\_ETH27}), \textit{recid} can be -1
+If the signature format contains the recovery id (currently only \code{LTC\_ECCSIG\_ETH27}), \code{recid} can be -1
 which signals that the recovery id from the signature blob should be used. This means an application does not need to
 which signals that the recovery id from the signature blob should be used. This means an application does not need to
 extract the recovery id from such a signature in order to use this function.
 extract the recovery id from such a signature in order to use this function.
-The function \textit{ecc\_recover\_key} implements multiple signature formats, and the output is compliant for GF(p) curves.
+The function \code{ecc\_recover\_key()} implements multiple signature formats, and the output is compliant for GF(p) curves.
 
 
 \subsection{Signature Formats}
 \subsection{Signature Formats}
 The following signature formats are suported:
 The following signature formats are suported:
@@ -5935,10 +5975,10 @@ The following signature formats are suported:
 \begin{center}
 \begin{center}
 \begin{tabular}{|l|l|}
 \begin{tabular}{|l|l|}
 \hline \textbf{sigformat} & \textbf{description} \\
 \hline \textbf{sigformat} & \textbf{description} \\
-\hline LTC\_ECCSIG\_ANSIX962 & ASN.1 encoded, ANSI X9.62 \\
-\hline LTC\_ECCSIG\_RFC7518 & raw R, S values as defined in RFC7518 \\
+\hline LTC\_ECCSIG\_ANSIX962 & ASN.1 encoded, \textit{ANSI X9.62} \\
+\hline LTC\_ECCSIG\_RFC7518 & raw R, S values as defined in \textit{RFC7518} \\
 \hline LTC\_ECCSIG\_ETH27 & raw R, S, V values (V has 27 added) \\
 \hline LTC\_ECCSIG\_ETH27 & raw R, S, V values (V has 27 added) \\
-\hline LTC\_ECCSIG\_RFC5656 & SSH+ECDSA format as defined in RFC5656 \\
+\hline LTC\_ECCSIG\_RFC5656 & \textit{SSH+ECDSA} format as defined in \textit{RFC5656} \\
 \hline
 \hline
 \end{tabular}
 \end{tabular}
 \end{center}
 \end{center}
@@ -5947,9 +5987,13 @@ The following signature formats are suported:
 \label{fig:sigformat}
 \label{fig:sigformat}
 \end{figure}
 \end{figure}
 
 
-The \textit{LTC\_ECCSIG\_ETH27} format is based on the Ethereum Yellow Paper, see \url{https://github.com/ethereum/yellowpaper}
+The \code{LTC\_ECCSIG\_ETH27} format is based on the Ethereum Yellow Paper, see \url{https://github.com/ethereum/yellowpaper}
 (Appendix F). However, convention allows the use of v=0,1 as equivalent to v=27,28 and both are accepted by
 (Appendix F). However, convention allows the use of v=0,1 as equivalent to v=27,28 and both are accepted by
-\textit{ecc\_recover\_key}.
+\code{ecc\_recover\_key()}.
+
+\textbf{NOTE:} If you're using a tailored version of libtomcrypt, it is possible to disable \code{LTC\_DER} which will disable
+the option to use \code{LTC\_ECCSIG\_ANSIX962}. Also it is possible to disable \code{LTC\_SSH} which will disable
+the option to use \code{LTC\_ECCSIG\_RFC5656}.
 
 
 \mysection{Shared Secret (ECDH)}
 \mysection{Shared Secret (ECDH)}
 To construct a Diffie-Hellman shared secret with a private and public ECC key, use the following function:
 To construct a Diffie-Hellman shared secret with a private and public ECC key, use the following function:

+ 32 - 0
libtomcrypt_VS2008.vcproj

@@ -2510,6 +2510,22 @@
 					RelativePath="src\pk\ecc\ecc_sign_hash.c"
 					RelativePath="src\pk\ecc\ecc_sign_hash.c"
 					>
 					>
 				</File>
 				</File>
+				<File
+					RelativePath="src\pk\ecc\ecc_sign_hash_eth27.c"
+					>
+				</File>
+				<File
+					RelativePath="src\pk\ecc\ecc_sign_hash_internal.c"
+					>
+				</File>
+				<File
+					RelativePath="src\pk\ecc\ecc_sign_hash_rfc5656.c"
+					>
+				</File>
+				<File
+					RelativePath="src\pk\ecc\ecc_sign_hash_rfc7518.c"
+					>
+				</File>
 				<File
 				<File
 					RelativePath="src\pk\ecc\ecc_sizes.c"
 					RelativePath="src\pk\ecc\ecc_sizes.c"
 					>
 					>
@@ -2522,6 +2538,22 @@
 					RelativePath="src\pk\ecc\ecc_verify_hash.c"
 					RelativePath="src\pk\ecc\ecc_verify_hash.c"
 					>
 					>
 				</File>
 				</File>
+				<File
+					RelativePath="src\pk\ecc\ecc_verify_hash_eth27.c"
+					>
+				</File>
+				<File
+					RelativePath="src\pk\ecc\ecc_verify_hash_internal.c"
+					>
+				</File>
+				<File
+					RelativePath="src\pk\ecc\ecc_verify_hash_rfc5656.c"
+					>
+				</File>
+				<File
+					RelativePath="src\pk\ecc\ecc_verify_hash_rfc7518.c"
+					>
+				</File>
 				<File
 				<File
 					RelativePath="src\pk\ecc\ltc_ecc_export_point.c"
 					RelativePath="src\pk\ecc\ltc_ecc_export_point.c"
 					>
 					>

+ 6 - 2
makefile.mingw

@@ -193,8 +193,12 @@ src/pk/ecc/ecc_get_size.o src/pk/ecc/ecc_import.o src/pk/ecc/ecc_import_openssl.
 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_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_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_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/ecc_sign_hash_eth27.o src/pk/ecc/ecc_sign_hash_internal.o \
+src/pk/ecc/ecc_sign_hash_rfc5656.o src/pk/ecc/ecc_sign_hash_rfc7518.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/ecc_verify_hash_eth27.o \
+src/pk/ecc/ecc_verify_hash_internal.o src/pk/ecc/ecc_verify_hash_rfc5656.o \
+src/pk/ecc/ecc_verify_hash_rfc7518.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_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_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 \
 src/pk/ecc/ltc_ecc_projective_add_point.o src/pk/ecc/ltc_ecc_projective_dbl_point.o \

+ 6 - 2
makefile.msvc

@@ -186,8 +186,12 @@ src/pk/ecc/ecc_get_size.obj src/pk/ecc/ecc_import.obj src/pk/ecc/ecc_import_open
 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_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_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_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/ecc_sign_hash_eth27.obj src/pk/ecc/ecc_sign_hash_internal.obj \
+src/pk/ecc/ecc_sign_hash_rfc5656.obj src/pk/ecc/ecc_sign_hash_rfc7518.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/ecc_verify_hash_eth27.obj \
+src/pk/ecc/ecc_verify_hash_internal.obj src/pk/ecc/ecc_verify_hash_rfc5656.obj \
+src/pk/ecc/ecc_verify_hash_rfc7518.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_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_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 \
 src/pk/ecc/ltc_ecc_projective_add_point.obj src/pk/ecc/ltc_ecc_projective_dbl_point.obj \

+ 6 - 2
makefile.unix

@@ -207,8 +207,12 @@ src/pk/ecc/ecc_get_size.o src/pk/ecc/ecc_import.o src/pk/ecc/ecc_import_openssl.
 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_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_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_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/ecc_sign_hash_eth27.o src/pk/ecc/ecc_sign_hash_internal.o \
+src/pk/ecc/ecc_sign_hash_rfc5656.o src/pk/ecc/ecc_sign_hash_rfc7518.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/ecc_verify_hash_eth27.o \
+src/pk/ecc/ecc_verify_hash_internal.o src/pk/ecc/ecc_verify_hash_rfc5656.o \
+src/pk/ecc/ecc_verify_hash_rfc7518.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_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_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 \
 src/pk/ecc/ltc_ecc_projective_add_point.o src/pk/ecc/ltc_ecc_projective_dbl_point.o \

+ 6 - 2
makefile_include.mk

@@ -369,8 +369,12 @@ src/pk/ecc/ecc_get_size.o src/pk/ecc/ecc_import.o src/pk/ecc/ecc_import_openssl.
 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_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_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_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/ecc_sign_hash_eth27.o src/pk/ecc/ecc_sign_hash_internal.o \
+src/pk/ecc/ecc_sign_hash_rfc5656.o src/pk/ecc/ecc_sign_hash_rfc7518.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/ecc_verify_hash_eth27.o \
+src/pk/ecc/ecc_verify_hash_internal.o src/pk/ecc/ecc_verify_hash_rfc5656.o \
+src/pk/ecc/ecc_verify_hash_rfc7518.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_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_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 \
 src/pk/ecc/ltc_ecc_projective_add_point.o src/pk/ecc/ltc_ecc_projective_dbl_point.o \

+ 8 - 0
sources.cmake

@@ -426,9 +426,17 @@ src/pk/ecc/ecc_set_curve_internal.c
 src/pk/ecc/ecc_set_key.c
 src/pk/ecc/ecc_set_key.c
 src/pk/ecc/ecc_shared_secret.c
 src/pk/ecc/ecc_shared_secret.c
 src/pk/ecc/ecc_sign_hash.c
 src/pk/ecc/ecc_sign_hash.c
+src/pk/ecc/ecc_sign_hash_eth27.c
+src/pk/ecc/ecc_sign_hash_internal.c
+src/pk/ecc/ecc_sign_hash_rfc5656.c
+src/pk/ecc/ecc_sign_hash_rfc7518.c
 src/pk/ecc/ecc_sizes.c
 src/pk/ecc/ecc_sizes.c
 src/pk/ecc/ecc_ssh_ecdsa_encode_name.c
 src/pk/ecc/ecc_ssh_ecdsa_encode_name.c
 src/pk/ecc/ecc_verify_hash.c
 src/pk/ecc/ecc_verify_hash.c
+src/pk/ecc/ecc_verify_hash_eth27.c
+src/pk/ecc/ecc_verify_hash_internal.c
+src/pk/ecc/ecc_verify_hash_rfc5656.c
+src/pk/ecc/ecc_verify_hash_rfc7518.c
 src/pk/ecc/ltc_ecc_export_point.c
 src/pk/ecc/ltc_ecc_export_point.c
 src/pk/ecc/ltc_ecc_import_point.c
 src/pk/ecc/ltc_ecc_import_point.c
 src/pk/ecc/ltc_ecc_is_point.c
 src/pk/ecc/ltc_ecc_is_point.c

+ 4 - 2
src/headers/tomcrypt_custom.h

@@ -622,9 +622,11 @@
    #define LTC_PKCS_8
    #define LTC_PKCS_8
 #endif
 #endif
 
 
-#ifdef LTC_PKCS_8
+#if defined(LTC_PKCS_8) && defined(LTC_DER)
    #define LTC_PADDING
    #define LTC_PADDING
    #define LTC_PBES
    #define LTC_PBES
+#else
+   #undef LTC_PKCS_8
 #endif
 #endif
 
 
 #if defined(LTC_CLEAN_STACK)
 #if defined(LTC_CLEAN_STACK)
@@ -664,7 +666,7 @@
    #error ASN.1 DER requires MPI functionality
    #error ASN.1 DER requires MPI functionality
 #endif
 #endif
 
 
-#if (defined(LTC_MDSA) || defined(LTC_MRSA) || defined(LTC_MECC)) && !defined(LTC_DER)
+#if (defined(LTC_MDSA) || defined(LTC_MRSA)) && !defined(LTC_DER)
    #error PK requires ASN.1 DER functionality, make sure LTC_DER is enabled
    #error PK requires ASN.1 DER functionality, make sure LTC_DER is enabled
 #endif
 #endif
 
 

+ 87 - 29
src/headers/tomcrypt_pk.h

@@ -312,22 +312,25 @@ int  ecc_make_key(prng_state *prng, int wprng, int keysize, ecc_key *key);
 int  ecc_make_key_ex(prng_state *prng, int wprng, ecc_key *key, const ltc_ecc_curve *cu);
 int  ecc_make_key_ex(prng_state *prng, int wprng, ecc_key *key, const ltc_ecc_curve *cu);
 void ecc_free(ecc_key *key);
 void ecc_free(ecc_key *key);
 
 
+#if defined(LTC_DER)
 int  ecc_export(unsigned char *out, unsigned long *outlen, int type, const ecc_key *key);
 int  ecc_export(unsigned char *out, unsigned long *outlen, int type, const ecc_key *key);
 int  ecc_import(const unsigned char *in, unsigned long inlen, ecc_key *key);
 int  ecc_import(const unsigned char *in, unsigned long inlen, ecc_key *key);
 int  ecc_import_ex(const unsigned char *in, unsigned long inlen, ecc_key *key, const ltc_ecc_curve *cu);
 int  ecc_import_ex(const unsigned char *in, unsigned long inlen, ecc_key *key, const ltc_ecc_curve *cu);
 
 
-int ecc_ansi_x963_export(const ecc_key *key, unsigned char *out, unsigned long *outlen);
-int ecc_ansi_x963_import(const unsigned char *in, unsigned long inlen, ecc_key *key);
-int ecc_ansi_x963_import_ex(const unsigned char *in, unsigned long inlen, ecc_key *key, const ltc_ecc_curve *cu);
+int  ecc_export_openssl(unsigned char *out, unsigned long *outlen, int type, const ecc_key *key);
+int  ecc_import_openssl(const unsigned char *in, unsigned long inlen, ecc_key *key);
+int  ecc_import_pkcs8(const unsigned char *in, unsigned long inlen, const password_ctx *pw_ctx, ecc_key *key);
+int  ecc_import_x509(const unsigned char *in, unsigned long inlen, ecc_key *key);
+#endif
 
 
-int ecc_export_openssl(unsigned char *out, unsigned long *outlen, int type, const ecc_key *key);
-int ecc_import_openssl(const unsigned char *in, unsigned long inlen, ecc_key *key);
-int ecc_import_pkcs8(const unsigned char *in, unsigned long inlen, const password_ctx *pw_ctx, ecc_key *key);
-int ecc_import_x509(const unsigned char *in, unsigned long inlen, ecc_key *key);
+int  ecc_ansi_x963_export(const ecc_key *key, unsigned char *out, unsigned long *outlen);
+int  ecc_ansi_x963_import(const unsigned char *in, unsigned long inlen, ecc_key *key);
+int  ecc_ansi_x963_import_ex(const unsigned char *in, unsigned long inlen, ecc_key *key, const ltc_ecc_curve *cu);
 
 
 int  ecc_shared_secret(const ecc_key *private_key, const ecc_key *public_key,
 int  ecc_shared_secret(const ecc_key *private_key, const ecc_key *public_key,
                        unsigned char *out, unsigned long *outlen);
                        unsigned char *out, unsigned long *outlen);
 
 
+#if defined(LTC_DER)
 int  ecc_encrypt_key(const unsigned char *in,   unsigned long inlen,
 int  ecc_encrypt_key(const unsigned char *in,   unsigned long inlen,
                            unsigned char *out,  unsigned long *outlen,
                            unsigned char *out,  unsigned long *outlen,
                            prng_state *prng, int wprng, int hash,
                            prng_state *prng, int wprng, int hash,
@@ -337,30 +340,85 @@ int  ecc_decrypt_key(const unsigned char *in,  unsigned long  inlen,
                            unsigned char *out, unsigned long *outlen,
                            unsigned char *out, unsigned long *outlen,
                            const ecc_key *key);
                            const ecc_key *key);
 
 
-#define ecc_sign_hash_rfc7518(in_, inlen_, out_, outlen_, prng_, wprng_, key_) \
-   ecc_sign_hash_ex(in_, inlen_, out_, outlen_, prng_, wprng_, LTC_ECCSIG_RFC7518, NULL, key_)
-
-#define ecc_sign_hash(in_, inlen_, out_, outlen_, prng_, wprng_, key_) \
-   ecc_sign_hash_ex(in_, inlen_, out_, outlen_, prng_, wprng_, LTC_ECCSIG_ANSIX962, NULL, key_)
-
-#define ecc_verify_hash_rfc7518(sig_, siglen_, hash_, hashlen_, stat_, key_) \
-   ecc_verify_hash_ex(sig_, siglen_, hash_, hashlen_, LTC_ECCSIG_RFC7518, stat_, key_)
-
-#define ecc_verify_hash(sig_, siglen_, hash_, hashlen_, stat_, key_) \
-   ecc_verify_hash_ex(sig_, siglen_, hash_, hashlen_, LTC_ECCSIG_ANSIX962, stat_, key_)
-
-int  ecc_sign_hash_ex(const unsigned char *in,  unsigned long inlen,
-                            unsigned char *out, unsigned long *outlen,
-                            prng_state *prng, int wprng, ecc_signature_type sigformat,
-                            int *recid, const ecc_key *key);
+int ecc_sign_hash(const unsigned char *in,
+                        unsigned long  inlen,
+                        unsigned char *out,
+                        unsigned long *outlen,
+                           prng_state *prng,
+                                  int  wprng,
+                  const       ecc_key *key);
+
+int ecc_verify_hash(const unsigned char *sig,
+                          unsigned long  siglen,
+                    const unsigned char *hash,
+                          unsigned long  hashlen,
+                                    int *stat,
+                    const       ecc_key *key);
+#endif
 
 
-int  ecc_verify_hash_ex(const unsigned char *sig,  unsigned long siglen,
-                        const unsigned char *hash, unsigned long hashlen,
-                        ecc_signature_type sigformat, int *stat, const ecc_key *key);
+int ecc_sign_hash_rfc7518(const unsigned char *in,
+                                unsigned long  inlen,
+                                unsigned char *out,
+                                unsigned long *outlen,
+                                   prng_state *prng,
+                                          int  wprng,
+                          const       ecc_key *key);
+
+int ecc_sign_hash_rfc7518_ex(const unsigned char *in,
+                                   unsigned long  inlen,
+                                   unsigned char *out,
+                                   unsigned long *outlen,
+                                      prng_state *prng,
+                                             int  wprng,
+                                             int *recid,
+                             const       ecc_key *key);
+
+int ecc_verify_hash_rfc7518(const unsigned char *sig,
+                                  unsigned long  siglen,
+                            const unsigned char *hash,
+                                  unsigned long  hashlen,
+                                            int *stat,
+                            const       ecc_key *key);
+
+#if defined(LTC_SSH)
+int ecc_sign_hash_rfc5656(const unsigned char *in,
+                                unsigned long  inlen,
+                                unsigned char *out,
+                                unsigned long *outlen,
+                                   prng_state *prng,
+                                          int  wprng,
+                          const       ecc_key *key);
+
+int ecc_verify_hash_rfc5656(const unsigned char *sig,
+                                  unsigned long  siglen,
+                            const unsigned char *hash,
+                                  unsigned long  hashlen,
+                                            int *stat,
+                            const       ecc_key *key);
+#endif
 
 
-int  ecc_recover_key(const unsigned char *sig,  unsigned long siglen,
-                     const unsigned char *hash, unsigned long hashlen,
-                     int recid, ecc_signature_type sigformat, ecc_key *key);
+int ecc_sign_hash_eth27(const unsigned char *in,
+                              unsigned long  inlen,
+                              unsigned char *out,
+                              unsigned long *outlen,
+                                 prng_state *prng,
+                                        int  wprng,
+                        const       ecc_key *key);
+
+int ecc_verify_hash_eth27(const unsigned char *sig,
+                                unsigned long  siglen,
+                          const unsigned char *hash,
+                                unsigned long  hashlen,
+                                          int *stat,
+                          const       ecc_key *key);
+
+int  ecc_recover_key(const unsigned char *sig,
+                           unsigned long  siglen,
+                     const unsigned char *hash,
+                           unsigned long  hashlen,
+                                     int  recid,
+                      ecc_signature_type  sigformat,
+                                 ecc_key *key);
 
 
 #endif
 #endif
 
 

+ 20 - 1
src/headers/tomcrypt_private.h

@@ -84,6 +84,7 @@ typedef int (*fn_kdf_t)(const struct password *pwd,
                               int iteration_count,  int hash_idx,
                               int iteration_count,  int hash_idx,
                               unsigned char *out,   unsigned long *outlen);
                               unsigned char *out,   unsigned long *outlen);
 
 
+#if defined(LTC_PBES)
 typedef struct {
 typedef struct {
    /* KDF */
    /* KDF */
    fn_kdf_t kdf;
    fn_kdf_t kdf;
@@ -107,6 +108,7 @@ typedef struct
    /* only used for RC2 */
    /* only used for RC2 */
    unsigned long key_bits;
    unsigned long key_bits;
 } pbes_arg;
 } pbes_arg;
+#endif
 
 
 typedef struct {
 typedef struct {
    const pbes_properties *data;
    const pbes_properties *data;
@@ -362,11 +364,14 @@ struct get_char {
 void copy_or_zeromem(const unsigned char* src, unsigned char* dest, unsigned long len, int coz);
 void copy_or_zeromem(const unsigned char* src, unsigned char* dest, unsigned long len, int coz);
 void password_free(struct password *pw, const struct password_ctx *ctx);
 void password_free(struct password *pw, const struct password_ctx *ctx);
 
 
+#if defined(LTC_PBES)
 int pbes_decrypt(const pbes_arg  *arg, unsigned char *dec_data, unsigned long *dec_size);
 int pbes_decrypt(const pbes_arg  *arg, unsigned char *dec_data, unsigned long *dec_size);
 
 
 int pbes1_extract(const ltc_asn1_list *s, pbes_arg *res);
 int pbes1_extract(const ltc_asn1_list *s, pbes_arg *res);
 int pbes2_extract(const ltc_asn1_list *s, pbes_arg *res);
 int pbes2_extract(const ltc_asn1_list *s, pbes_arg *res);
+#endif
 
 
+#ifdef LTC_PEM
 int pem_decrypt(unsigned char *data, unsigned long *datalen,
 int pem_decrypt(unsigned char *data, unsigned long *datalen,
                 unsigned char *key,  unsigned long keylen,
                 unsigned char *key,  unsigned long keylen,
                 unsigned char *iv,   unsigned long ivlen,
                 unsigned char *iv,   unsigned long ivlen,
@@ -378,6 +383,7 @@ int pem_get_char_from_file(struct get_char *g);
 #endif /* LTC_NO_FILE */
 #endif /* LTC_NO_FILE */
 int pem_get_char_from_buf(struct get_char *g);
 int pem_get_char_from_buf(struct get_char *g);
 int pem_read(void *pem, unsigned long *w, struct pem_headers *hdr, struct get_char *g);
 int pem_read(void *pem, unsigned long *w, struct pem_headers *hdr, struct get_char *g);
+#endif
 
 
 /* tomcrypt_pk.h */
 /* tomcrypt_pk.h */
 
 
@@ -387,10 +393,14 @@ int rand_bn_upto(void *N, void *limit, prng_state *prng, int wprng);
 int pk_get_oid(enum ltc_oid_id id, const char **st);
 int pk_get_oid(enum ltc_oid_id id, const char **st);
 int pk_get_pka_id(enum ltc_oid_id id, enum ltc_pka_id *pka);
 int pk_get_pka_id(enum ltc_oid_id id, enum ltc_pka_id *pka);
 int pk_get_oid_id(enum ltc_pka_id pka, enum ltc_oid_id *oid);
 int pk_get_oid_id(enum ltc_pka_id pka, enum ltc_oid_id *oid);
+#ifdef LTC_DER
 int pk_get_oid_from_asn1(const ltc_asn1_list *oid, enum ltc_oid_id *id);
 int pk_get_oid_from_asn1(const ltc_asn1_list *oid, enum ltc_oid_id *id);
+#endif
 int pk_oid_str_to_num(const char *OID, unsigned long *oid, unsigned long *oidlen);
 int pk_oid_str_to_num(const char *OID, unsigned long *oid, unsigned long *oidlen);
 int pk_oid_num_to_str(const unsigned long *oid, unsigned long oidlen, char *OID, unsigned long *outlen);
 int pk_oid_num_to_str(const unsigned long *oid, unsigned long oidlen, char *OID, unsigned long *outlen);
 
 
+int pk_oid_cmp_with_ulong(const char *o1, const unsigned long *o2, unsigned long o2size);
+
 /* ---- DH Routines ---- */
 /* ---- DH Routines ---- */
 #ifdef LTC_MRSA
 #ifdef LTC_MRSA
 int rsa_init(rsa_key *key);
 int rsa_init(rsa_key *key);
@@ -416,10 +426,20 @@ int ecc_set_curve_from_mpis(void *a, void *b, void *prime, void *order, void *gx
 int ecc_copy_curve(const ecc_key *srckey, ecc_key *key);
 int ecc_copy_curve(const ecc_key *srckey, ecc_key *key);
 int ecc_set_curve_by_size(int size, ecc_key *key);
 int ecc_set_curve_by_size(int size, ecc_key *key);
 int ecc_import_subject_public_key_info(const unsigned char *in, unsigned long inlen, ecc_key *key);
 int ecc_import_subject_public_key_info(const unsigned char *in, unsigned long inlen, ecc_key *key);
+#ifdef LTC_DER
 int ecc_import_pkcs8_asn1(ltc_asn1_list *alg_id, ltc_asn1_list *priv_key, ecc_key *key);
 int ecc_import_pkcs8_asn1(ltc_asn1_list *alg_id, ltc_asn1_list *priv_key, ecc_key *key);
+#endif
 int ecc_import_with_curve(const unsigned char *in, unsigned long inlen, int type, ecc_key *key);
 int ecc_import_with_curve(const unsigned char *in, unsigned long inlen, int type, ecc_key *key);
 int ecc_import_with_oid(const unsigned char *in, unsigned long inlen, unsigned long *oid, unsigned long oid_len, int type, ecc_key *key);
 int ecc_import_with_oid(const unsigned char *in, unsigned long inlen, unsigned long *oid, unsigned long oid_len, int type, ecc_key *key);
 
 
+int ecc_sign_hash_internal(const unsigned char *in,  unsigned long inlen,
+                           void *r, void *s, prng_state *prng, int wprng,
+                           int *recid, const ecc_key *key);
+
+int ecc_verify_hash_internal(void *r, void *s,
+                             const unsigned char *hash, unsigned long hashlen,
+                             int *stat, const ecc_key *key);
+
 #ifdef LTC_SSH
 #ifdef LTC_SSH
 int ecc_ssh_ecdsa_encode_name(char *buffer, unsigned long *buflen, const ecc_key *key);
 int ecc_ssh_ecdsa_encode_name(char *buffer, unsigned long *buflen, const ecc_key *key);
 #endif
 #endif
@@ -604,7 +624,6 @@ int x509_decode_subject_public_key_info(const unsigned char *in, unsigned long i
         enum ltc_oid_id algorithm, void *public_key, unsigned long *public_key_len,
         enum ltc_oid_id algorithm, void *public_key, unsigned long *public_key_len,
         ltc_asn1_type parameters_type, ltc_asn1_list* parameters, unsigned long *parameters_len);
         ltc_asn1_type parameters_type, ltc_asn1_list* parameters, unsigned long *parameters_len);
 
 
-int pk_oid_cmp_with_ulong(const char *o1, const unsigned long *o2, unsigned long o2size);
 int pk_oid_cmp_with_asn1(const char *o1, const ltc_asn1_list *o2);
 int pk_oid_cmp_with_asn1(const char *o1, const ltc_asn1_list *o2);
 
 
 #endif /* LTC_DER */
 #endif /* LTC_DER */

+ 2 - 2
src/pk/asn1/oid/pk_oid_cmp.c

@@ -2,8 +2,6 @@
 /* SPDX-License-Identifier: Unlicense */
 /* SPDX-License-Identifier: Unlicense */
 #include "tomcrypt_private.h"
 #include "tomcrypt_private.h"
 
 
-#ifdef LTC_DER
-
 /*
 /*
    Compare an OID string to an array of `unsigned long`.
    Compare an OID string to an array of `unsigned long`.
    @return CRYPT_OK if equal
    @return CRYPT_OK if equal
@@ -28,6 +26,8 @@ int pk_oid_cmp_with_ulong(const char *o1, const unsigned long *o2, unsigned long
    return CRYPT_OK;
    return CRYPT_OK;
 }
 }
 
 
+#ifdef LTC_DER
+
 /*
 /*
    Compare an OID string to an OID element decoded from ASN.1.
    Compare an OID string to an OID element decoded from ASN.1.
    @return CRYPT_OK if equal
    @return CRYPT_OK if equal

+ 1 - 1
src/pk/ecc/ecc_decrypt_key.c

@@ -8,7 +8,7 @@
   ECC Crypto, Tom St Denis
   ECC Crypto, Tom St Denis
 */
 */
 
 
-#ifdef LTC_MECC
+#if defined(LTC_MECC) && defined(LTC_DER)
 
 
 /**
 /**
   Decrypt an ECC encrypted key
   Decrypt an ECC encrypted key

+ 1 - 1
src/pk/ecc/ecc_encrypt_key.c

@@ -8,7 +8,7 @@
   ECC Crypto, Tom St Denis
   ECC Crypto, Tom St Denis
 */
 */
 
 
-#ifdef LTC_MECC
+#if defined(LTC_MECC) && defined(LTC_DER)
 
 
 /**
 /**
   Encrypt a symmetric key with ECC
   Encrypt a symmetric key with ECC

+ 1 - 1
src/pk/ecc/ecc_export.c

@@ -8,7 +8,7 @@
   ECC Crypto, Tom St Denis
   ECC Crypto, Tom St Denis
 */
 */
 
 
-#ifdef LTC_MECC
+#if defined(LTC_MECC) && defined(LTC_DER)
 
 
 /**
 /**
   Export an ECC key as a binary packet
   Export an ECC key as a binary packet

+ 1 - 1
src/pk/ecc/ecc_export_openssl.c

@@ -3,7 +3,7 @@
 
 
 #include "tomcrypt_private.h"
 #include "tomcrypt_private.h"
 
 
-#ifdef LTC_MECC
+#if defined(LTC_MECC) && defined(LTC_DER)
 
 
 /**
 /**
   Export an ECC key as a binary packet
   Export an ECC key as a binary packet

+ 1 - 1
src/pk/ecc/ecc_import.c

@@ -8,7 +8,7 @@
   ECC Crypto, Tom St Denis
   ECC Crypto, Tom St Denis
 */
 */
 
 
-#ifdef LTC_MECC
+#if defined(LTC_MECC) && defined(LTC_DER)
 
 
 /**
 /**
   Import an ECC key from a binary packet
   Import an ECC key from a binary packet

+ 1 - 1
src/pk/ecc/ecc_import_openssl.c

@@ -3,7 +3,7 @@
 
 
 #include "tomcrypt_private.h"
 #include "tomcrypt_private.h"
 
 
-#ifdef LTC_MECC
+#if defined(LTC_MECC) && defined(LTC_DER)
 
 
 static int s_ecc_import_private_with_oid(const unsigned char *in, unsigned long inlen, ecc_key *key)
 static int s_ecc_import_private_with_oid(const unsigned char *in, unsigned long inlen, ecc_key *key)
 {
 {

+ 1 - 1
src/pk/ecc/ecc_import_pkcs8.c

@@ -3,7 +3,7 @@
 
 
 #include "tomcrypt_private.h"
 #include "tomcrypt_private.h"
 
 
-#ifdef LTC_MECC
+#if defined(LTC_MECC) && defined(LTC_DER)
 
 
 int ecc_import_pkcs8_asn1(ltc_asn1_list *alg_id, ltc_asn1_list *priv_key, ecc_key *key)
 int ecc_import_pkcs8_asn1(ltc_asn1_list *alg_id, ltc_asn1_list *priv_key, ecc_key *key)
 {
 {

+ 1 - 1
src/pk/ecc/ecc_import_x509.c

@@ -2,7 +2,7 @@
 /* SPDX-License-Identifier: Unlicense */
 /* SPDX-License-Identifier: Unlicense */
 #include "tomcrypt_private.h"
 #include "tomcrypt_private.h"
 
 
-#ifdef LTC_MECC
+#if defined(LTC_MECC) && defined(LTC_DER)
 
 
 static int s_ecc_import_x509_with_oid(const unsigned char *in, unsigned long inlen, ecc_key *key)
 static int s_ecc_import_x509_with_oid(const unsigned char *in, unsigned long inlen, ecc_key *key)
 {
 {

+ 12 - 13
src/pk/ecc/ecc_recover_key.c

@@ -3,9 +3,7 @@
 
 
 #include "tomcrypt_private.h"
 #include "tomcrypt_private.h"
 
 
-#ifdef LTC_MECC
-
-#ifdef LTC_ECC_SHAMIR
+#if defined(LTC_MECC) && defined(LTC_ECC_SHAMIR)
 
 
 /**
 /**
   @file ecc_recover_key.c
   @file ecc_recover_key.c
@@ -67,14 +65,7 @@ int ecc_recover_key(const unsigned char *sig,  unsigned long siglen,
       goto error;
       goto error;
    }
    }
 
 
-   if (sigformat == LTC_ECCSIG_ANSIX962) {
-      /* ANSI X9.62 format - ASN.1 encoded SEQUENCE{ INTEGER(r), INTEGER(s) }  */
-      if ((err = der_decode_sequence_multi_ex(sig, siglen, LTC_DER_SEQ_SEQUENCE | LTC_DER_SEQ_STRICT,
-                                     LTC_ASN1_INTEGER, 1UL, r,
-                                     LTC_ASN1_INTEGER, 1UL, s,
-                                     LTC_ASN1_EOL, 0UL, LTC_NULL)) != CRYPT_OK)                         { goto error; }
-   }
-   else if (sigformat == LTC_ECCSIG_RFC7518) {
+   if (sigformat == LTC_ECCSIG_RFC7518) {
       /* RFC7518 format - raw (r,s) */
       /* RFC7518 format - raw (r,s) */
       i = ltc_mp_unsigned_bin_size(key->dp.order);
       i = ltc_mp_unsigned_bin_size(key->dp.order);
       if (siglen != (2*i)) {
       if (siglen != (2*i)) {
@@ -105,6 +96,15 @@ int ecc_recover_key(const unsigned char *sig,  unsigned long siglen,
       if ((err = ltc_mp_read_unsigned_bin(r, sig,  32)) != CRYPT_OK)                                    { goto error; }
       if ((err = ltc_mp_read_unsigned_bin(r, sig,  32)) != CRYPT_OK)                                    { goto error; }
       if ((err = ltc_mp_read_unsigned_bin(s, sig+32, 32)) != CRYPT_OK)                                  { goto error; }
       if ((err = ltc_mp_read_unsigned_bin(s, sig+32, 32)) != CRYPT_OK)                                  { goto error; }
    }
    }
+#ifdef LTC_DER
+   else if (sigformat == LTC_ECCSIG_ANSIX962) {
+         /* ANSI X9.62 format - ASN.1 encoded SEQUENCE{ INTEGER(r), INTEGER(s) }  */
+         if ((err = der_decode_sequence_multi_ex(sig, siglen, LTC_DER_SEQ_SEQUENCE | LTC_DER_SEQ_STRICT,
+                                                 LTC_ASN1_INTEGER, 1UL, r,
+                                                 LTC_ASN1_INTEGER, 1UL, s,
+                                                 LTC_ASN1_EOL, 0UL, LTC_NULL)) != CRYPT_OK)             { goto error; }
+   }
+#endif
 #ifdef LTC_SSH
 #ifdef LTC_SSH
    else if (sigformat == LTC_ECCSIG_RFC5656) {
    else if (sigformat == LTC_ECCSIG_RFC5656) {
       char name[64], name2[64];
       char name[64], name2[64];
@@ -116,7 +116,7 @@ int ecc_recover_key(const unsigned char *sig,  unsigned long siglen,
                                            LTC_SSHDATA_STRING, name, &namelen,
                                            LTC_SSHDATA_STRING, name, &namelen,
                                            LTC_SSHDATA_MPINT,  r,
                                            LTC_SSHDATA_MPINT,  r,
                                            LTC_SSHDATA_MPINT,  s,
                                            LTC_SSHDATA_MPINT,  s,
-                                           LTC_SSHDATA_EOL,    NULL)) != CRYPT_OK)                      { goto error; }
+                                           LTC_SSHDATA_EOL,    LTC_NULL)) != CRYPT_OK)                  { goto error; }
 
 
 
 
       /* Check curve matches identifier string */
       /* Check curve matches identifier string */
@@ -257,4 +257,3 @@ error:
 }
 }
 
 
 #endif
 #endif
-#endif

+ 15 - 154
src/pk/ecc/ecc_sign_hash.c

@@ -3,178 +3,39 @@
 
 
 #include "tomcrypt_private.h"
 #include "tomcrypt_private.h"
 
 
-#ifdef LTC_MECC
+#if defined(LTC_MECC) && defined(LTC_DER)
 
 
 /**
 /**
-  @file ecc_sign_hash.c
-  ECC Crypto, Tom St Denis
-*/
-
-/**
-  Sign a message digest
+  Sign a message digest (ANSI X9.62 format)
   @param in        The message digest to sign
   @param in        The message digest to sign
   @param inlen     The length of the digest
   @param inlen     The length of the digest
   @param out       [out] The destination for the signature
   @param out       [out] The destination for the signature
   @param outlen    [in/out] The max size and resulting size of the signature
   @param outlen    [in/out] The max size and resulting size of the signature
   @param prng      An active PRNG state
   @param prng      An active PRNG state
   @param wprng     The index of the PRNG you wish to use
   @param wprng     The index of the PRNG you wish to use
-  @param sigformat The format of the signature to generate (ecc_signature_type)
-  @param recid     [out] The recovery ID for this signature (optional)
   @param key       A private ECC key
   @param key       A private ECC key
   @return CRYPT_OK if successful
   @return CRYPT_OK if successful
 */
 */
-int ecc_sign_hash_ex(const unsigned char *in,  unsigned long inlen,
-                     unsigned char *out, unsigned long *outlen,
-                     prng_state *prng, int wprng, ecc_signature_type sigformat,
-                     int *recid, const ecc_key *key)
+int ecc_sign_hash(const unsigned char *in,  unsigned long inlen,
+                  unsigned char *out, unsigned long *outlen,
+                  prng_state *prng, int wprng, const ecc_key *key)
 {
 {
-   ecc_key       pubkey;
-   void          *r, *s, *e, *p, *b;
-   int           v = 0;
-   int           err, max_iterations = LTC_PK_MAX_RETRIES;
-   unsigned long pbits, pbytes, i, shift_right;
-   unsigned char ch, buf[MAXBLOCKSIZE];
+   int err;
+   void *r, *s;
 
 
-   LTC_ARGCHK(in     != NULL);
    LTC_ARGCHK(out    != NULL);
    LTC_ARGCHK(out    != NULL);
    LTC_ARGCHK(outlen != NULL);
    LTC_ARGCHK(outlen != NULL);
-   LTC_ARGCHK(key    != NULL);
-
-   /* is this a private key? */
-   if (key->type != PK_PRIVATE) {
-      return CRYPT_PK_NOT_PRIVATE;
-   }
-
-   /* init the bignums */
-   if ((err = ltc_mp_init_multi(&r, &s, &e, &b, LTC_NULL)) != CRYPT_OK) {
-      return err;
-   }
-
-   /* get the hash and load it as a bignum into 'e' */
-   p = key->dp.order;
-   pbits = ltc_mp_count_bits(p);
-   pbytes = (pbits+7) >> 3;
-   if (pbits > inlen*8) {
-      if ((err = ltc_mp_read_unsigned_bin(e, in, inlen)) != CRYPT_OK)    { goto errnokey; }
-   }
-   else if (pbits % 8 == 0) {
-      if ((err = ltc_mp_read_unsigned_bin(e, in, pbytes)) != CRYPT_OK)   { goto errnokey; }
-   }
-   else {
-      shift_right = 8 - pbits % 8;
-      for (i=0, ch=0; i<pbytes; i++) {
-        buf[i] = ch;
-        ch = (in[i] << (8-shift_right));
-        buf[i] = buf[i] ^ (in[i] >> shift_right);
-      }
-      if ((err = ltc_mp_read_unsigned_bin(e, buf, pbytes)) != CRYPT_OK)  { goto errnokey; }
-   }
-
-   /* make up a key and export the public copy */
-   do {
-      if ((err = ecc_copy_curve(key, &pubkey)) != CRYPT_OK)                { goto errnokey; }
-      if ((err = ecc_generate_key(prng, wprng, &pubkey)) != CRYPT_OK)      { goto errnokey; }
 
 
-      /* find r = x1 mod n */
-      if ((err = ltc_mp_mod(pubkey.pubkey.x, p, r)) != CRYPT_OK)               { goto error; }
-
-      if (recid || sigformat==LTC_ECCSIG_ETH27) {
-         /* find recovery ID (if needed) */
-         v = 0;
-         if (ltc_mp_copy(pubkey.pubkey.x, s) != CRYPT_OK)                      { goto error; }
-         while (ltc_mp_cmp_d(s, 0) == LTC_MP_GT && ltc_mp_cmp(s, p) != LTC_MP_LT) {
-            /* Compute x1 div n... this will almost never be reached for curves with order 1 */
-            v += 2;
-            if ((err = ltc_mp_sub(s, p, s)) != CRYPT_OK)                       { goto error; }
-         }
-         if (ltc_mp_isodd(pubkey.pubkey.y)) v += 1;
-      }
-
-      if (ltc_mp_iszero(r) == LTC_MP_YES) {
-         ecc_free(&pubkey);
-      } else {
-         if ((err = rand_bn_upto(b, p, prng, wprng)) != CRYPT_OK)          { goto error; } /* b = blinding value */
-         /* find s = (e + xr)/k */
-         if ((err = ltc_mp_mulmod(pubkey.k, b, p, pubkey.k)) != CRYPT_OK)      { goto error; } /* k = kb */
-         if ((err = ltc_mp_invmod(pubkey.k, p, pubkey.k)) != CRYPT_OK)         { goto error; } /* k = 1/kb */
-         if ((err = ltc_mp_mulmod(key->k, r, p, s)) != CRYPT_OK)               { goto error; } /* s = xr */
-         if ((err = ltc_mp_mulmod(pubkey.k, s, p, s)) != CRYPT_OK)             { goto error; } /* s = xr/kb */
-         if ((err = ltc_mp_mulmod(pubkey.k, e, p, e)) != CRYPT_OK)             { goto error; } /* e = e/kb */
-         if ((err = ltc_mp_add(e, s, s)) != CRYPT_OK)                          { goto error; } /* s = e/kb + xr/kb */
-         if ((err = ltc_mp_mulmod(s, b, p, s)) != CRYPT_OK)                    { goto error; } /* s = b(e/kb + xr/kb) = (e + xr)/k */
-         ecc_free(&pubkey);
-         if (ltc_mp_iszero(s) == LTC_MP_NO) {
-            break;
-         }
-      }
-   } while (--max_iterations > 0);
-
-   if (max_iterations == 0) {
-      goto errnokey;
-   }
-
-   if (recid) *recid = v;
-
-   if (sigformat == LTC_ECCSIG_ANSIX962) {
-      /* store as ASN.1 SEQUENCE { r, s -- integer } */
-      err = der_encode_sequence_multi(out, outlen,
-                               LTC_ASN1_INTEGER, 1UL, r,
-                               LTC_ASN1_INTEGER, 1UL, s,
-                               LTC_ASN1_EOL, 0UL, NULL);
-   }
-   else if (sigformat == LTC_ECCSIG_RFC7518) {
-      /* RFC7518 format - raw (r,s) */
-      if (*outlen < 2*pbytes) { err = CRYPT_MEM; goto errnokey; }
-      zeromem(out, 2*pbytes);
-      i = ltc_mp_unsigned_bin_size(r);
-      if ((err = ltc_mp_to_unsigned_bin(r, out + (pbytes - i)))   != CRYPT_OK) { goto errnokey; }
-      i = ltc_mp_unsigned_bin_size(s);
-      if ((err = ltc_mp_to_unsigned_bin(s, out + (2*pbytes - i))) != CRYPT_OK) { goto errnokey; }
-      *outlen = 2*pbytes;
-      err = CRYPT_OK;
-   }
-   else if (sigformat == LTC_ECCSIG_ETH27) {
-      /* Ethereum (v,r,s) format */
-      if (pk_oid_cmp_with_ulong("1.3.132.0.10", key->dp.oid, key->dp.oidlen) != CRYPT_OK) {
-         /* Only valid for secp256k1 - OID 1.3.132.0.10 */
-         err = CRYPT_ERROR; goto errnokey;
-      }
-      if (*outlen < 65) { err = CRYPT_MEM; goto errnokey; }
-      zeromem(out, 65);
-      i = ltc_mp_unsigned_bin_size(r);
-      if ((err = ltc_mp_to_unsigned_bin(r, out + 32 - i)) != CRYPT_OK) { goto errnokey; }
-      i = ltc_mp_unsigned_bin_size(s);
-      if ((err = ltc_mp_to_unsigned_bin(s, out + 64 - i)) != CRYPT_OK) { goto errnokey; }
-      out[64] = (unsigned char)(v + 27); /* Recovery ID is 27/28 for Ethereum */
-      *outlen = 65;
-      err = CRYPT_OK;
-   }
-#ifdef LTC_SSH
-   else if (sigformat == LTC_ECCSIG_RFC5656) {
-      /* Get identifier string */
-      char name[64];
-      unsigned long namelen = sizeof(name);
-      if ((err = ecc_ssh_ecdsa_encode_name(name, &namelen, key)) != CRYPT_OK) { goto errnokey; }
-
-      /* Store as SSH data sequence, per RFC4251 */
-      err = ssh_encode_sequence_multi(out, outlen,
-                                      LTC_SSHDATA_STRING, name, namelen,
-                                      LTC_SSHDATA_MPINT,  r,
-                                      LTC_SSHDATA_MPINT,  s,
-                                      LTC_SSHDATA_EOL,    NULL);
-   }
-#endif
-   else {
-      /* Unknown signature format */
-      err = CRYPT_ERROR;
-      goto error;
-   }
+   if ((err = ltc_mp_init_multi(&r, &s, LTC_NULL)) != CRYPT_OK) return err;
+   if ((err = ecc_sign_hash_internal(in, inlen, r, s, prng, wprng, NULL, key)) != CRYPT_OK) goto error;
 
 
-   goto errnokey;
+   /* store as ASN.1 SEQUENCE { r, s -- integer } */
+   err = der_encode_sequence_multi(out, outlen,
+                                   LTC_ASN1_INTEGER, 1UL, r,
+                                   LTC_ASN1_INTEGER, 1UL, s,
+                                   LTC_ASN1_EOL, 0UL, NULL);
 error:
 error:
-   ecc_free(&pubkey);
-errnokey:
-   ltc_mp_deinit_multi(r, s, e, b, LTC_NULL);
+   ltc_mp_deinit_multi(r, s, LTC_NULL);
    return err;
    return err;
 }
 }
 
 

+ 57 - 0
src/pk/ecc/ecc_sign_hash_eth27.c

@@ -0,0 +1,57 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#include "tomcrypt_private.h"
+
+#ifdef LTC_MECC
+
+/**
+  Sign a message digest (Ethereum format with recovery_id+27)
+  @param in        The message digest to sign
+  @param inlen     The length of the digest
+  @param out       [out] The destination for the signature
+  @param outlen    [in/out] The max size and resulting size of the signature
+  @param prng      An active PRNG state
+  @param wprng     The index of the PRNG you wish to use
+  @param key       A private ECC key
+  @return CRYPT_OK if successful
+*/
+int ecc_sign_hash_eth27(const unsigned char *in,  unsigned long inlen,
+                        unsigned char *out, unsigned long *outlen,
+                        prng_state *prng, int wprng, const ecc_key *key)
+{
+   int err, recid;
+   void *r, *s;
+   unsigned long i;
+
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+   LTC_ARGCHK(key    != NULL);
+
+   /* Only valid for secp256k1 - OID 1.3.132.0.10 */
+   if (pk_oid_cmp_with_ulong("1.3.132.0.10", key->dp.oid, key->dp.oidlen) != CRYPT_OK) {
+      return CRYPT_ERROR;
+   }
+   if (*outlen < 65) {
+      *outlen = 65;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   if ((err = ltc_mp_init_multi(&r, &s, LTC_NULL)) != CRYPT_OK) return err;
+   if ((err = ecc_sign_hash_internal(in, inlen, r, s, prng, wprng, &recid, key)) != CRYPT_OK) goto error;
+
+   zeromem(out, 65);
+   *outlen = 65;
+   i = ltc_mp_unsigned_bin_size(r);
+   if ((err = ltc_mp_to_unsigned_bin(r, out + 32 - i)) != CRYPT_OK) goto error;
+   i = ltc_mp_unsigned_bin_size(s);
+   if ((err = ltc_mp_to_unsigned_bin(s, out + 64 - i)) != CRYPT_OK) goto error;
+   out[64] = (unsigned char)(recid + 27); /* Recovery ID is 27/28 for Ethereum */
+   err = CRYPT_OK;
+
+error:
+   ltc_mp_deinit_multi(r, s, LTC_NULL);
+   return err;
+}
+
+#endif

+ 111 - 0
src/pk/ecc/ecc_sign_hash_internal.c

@@ -0,0 +1,111 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#include "tomcrypt_private.h"
+
+#ifdef LTC_MECC
+
+int ecc_sign_hash_internal(const unsigned char *in,  unsigned long inlen,
+                           void *r, void *s, prng_state *prng, int wprng,
+                           int *recid, const ecc_key *key)
+{
+   ecc_key       pubkey;
+   void          *e, *p, *b;
+   int           v = 0;
+   int           err, max_iterations = LTC_PK_MAX_RETRIES;
+   unsigned long pbits, pbytes, i, shift_right;
+   unsigned char ch, buf[MAXBLOCKSIZE];
+
+   LTC_ARGCHK(r      != NULL);
+   LTC_ARGCHK(s      != NULL);
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(key    != NULL);
+
+   /* is this a private key? */
+   if (key->type != PK_PRIVATE) {
+      return CRYPT_PK_NOT_PRIVATE;
+   }
+
+   /* init the bignums */
+   if ((err = ltc_mp_init_multi(&e, &b, LTC_NULL)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* get the hash and load it as a bignum into 'e' */
+   p = key->dp.order;
+   pbits = ltc_mp_count_bits(p);
+   pbytes = (pbits+7) >> 3;
+   if (pbits > inlen*8) {
+      if ((err = ltc_mp_read_unsigned_bin(e, (unsigned char *)in, inlen)) != CRYPT_OK)    { goto errnokey; }
+   }
+   else if (pbits % 8 == 0) {
+      if ((err = ltc_mp_read_unsigned_bin(e, (unsigned char *)in, pbytes)) != CRYPT_OK)   { goto errnokey; }
+   }
+   else {
+      if (pbytes >= MAXBLOCKSIZE) {
+         err = CRYPT_BUFFER_OVERFLOW;
+         goto error;
+      }
+      shift_right = 8 - pbits % 8;
+      for (i=0, ch=0; i<pbytes; i++) {
+        buf[i] = ch;
+        ch = (in[i] << (8-shift_right));
+        buf[i] = buf[i] ^ (in[i] >> shift_right);
+      }
+      if ((err = ltc_mp_read_unsigned_bin(e, (unsigned char *)buf, pbytes)) != CRYPT_OK)  { goto errnokey; }
+   }
+
+   /* make up a key and export the public copy */
+   do {
+      if ((err = ecc_copy_curve(key, &pubkey)) != CRYPT_OK)                { goto errnokey; }
+      if ((err = ecc_generate_key(prng, wprng, &pubkey)) != CRYPT_OK)      { goto errnokey; }
+
+      /* find r = x1 mod n */
+      if ((err = ltc_mp_mod(pubkey.pubkey.x, p, r)) != CRYPT_OK)               { goto error; }
+
+      if (recid) {
+         /* find recovery ID (if needed) */
+         v = 0;
+         if (ltc_mp_copy(pubkey.pubkey.x, s) != CRYPT_OK)                      { goto error; }
+         while (ltc_mp_cmp_d(s, 0) == LTC_MP_GT && ltc_mp_cmp(s, p) != LTC_MP_LT) {
+            /* Compute x1 div n... this will almost never be reached for curves with order 1 */
+            v += 2;
+            if ((err = ltc_mp_sub(s, p, s)) != CRYPT_OK)                       { goto error; }
+         }
+         if (ltc_mp_isodd(pubkey.pubkey.y)) v += 1;
+      }
+
+      if (ltc_mp_iszero(r) == LTC_MP_YES) {
+         ecc_free(&pubkey);
+      } else {
+         if ((err = rand_bn_upto(b, p, prng, wprng)) != CRYPT_OK)          { goto error; } /* b = blinding value */
+         /* find s = (e + xr)/k */
+         if ((err = ltc_mp_mulmod(pubkey.k, b, p, pubkey.k)) != CRYPT_OK)      { goto error; } /* k = kb */
+         if ((err = ltc_mp_invmod(pubkey.k, p, pubkey.k)) != CRYPT_OK)         { goto error; } /* k = 1/kb */
+         if ((err = ltc_mp_mulmod(key->k, r, p, s)) != CRYPT_OK)               { goto error; } /* s = xr */
+         if ((err = ltc_mp_mulmod(pubkey.k, s, p, s)) != CRYPT_OK)             { goto error; } /* s = xr/kb */
+         if ((err = ltc_mp_mulmod(pubkey.k, e, p, e)) != CRYPT_OK)             { goto error; } /* e = e/kb */
+         if ((err = ltc_mp_add(e, s, s)) != CRYPT_OK)                          { goto error; } /* s = e/kb + xr/kb */
+         if ((err = ltc_mp_mulmod(s, b, p, s)) != CRYPT_OK)                    { goto error; } /* s = b(e/kb + xr/kb) = (e + xr)/k */
+         ecc_free(&pubkey);
+         if (ltc_mp_iszero(s) == LTC_MP_NO) {
+            break;
+         }
+      }
+   } while (--max_iterations > 0);
+
+   if (max_iterations == 0) {
+      goto errnokey;
+   }
+
+   if (recid) *recid = v;
+
+   goto errnokey;
+error:
+   ecc_free(&pubkey);
+errnokey:
+   ltc_mp_deinit_multi(e, b, LTC_NULL);
+   return err;
+}
+
+#endif

+ 48 - 0
src/pk/ecc/ecc_sign_hash_rfc5656.c

@@ -0,0 +1,48 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#include "tomcrypt_private.h"
+
+#if defined(LTC_MECC) && defined(LTC_SSH)
+
+/**
+  Sign a message digest (RFC5656 / SSH format)
+  @param in        The message digest to sign
+  @param inlen     The length of the digest
+  @param out       [out] The destination for the signature
+  @param outlen    [in/out] The max size and resulting size of the signature
+  @param prng      An active PRNG state
+  @param wprng     The index of the PRNG you wish to use
+  @param key       A private ECC key
+  @return CRYPT_OK if successful
+*/
+int ecc_sign_hash_rfc5656(const unsigned char *in,  unsigned long inlen,
+                          unsigned char *out, unsigned long *outlen,
+                          prng_state *prng, int wprng, const ecc_key *key)
+{
+   int err;
+   void *r, *s;
+   char name[64];
+   unsigned long namelen = sizeof(name);
+
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   /* Get identifier string */
+   if ((err = ecc_ssh_ecdsa_encode_name(name, &namelen, key)) != CRYPT_OK) return err;
+
+   if ((err = ltc_mp_init_multi(&r, &s, LTC_NULL)) != CRYPT_OK) return err;
+   if ((err = ecc_sign_hash_internal(in, inlen, r, s, prng, wprng, NULL, key)) != CRYPT_OK) goto error;
+
+   /* Store as SSH data sequence, per RFC4251 */
+   err = ssh_encode_sequence_multi(out, outlen,
+                                   LTC_SSHDATA_STRING, name, namelen,
+                                   LTC_SSHDATA_MPINT,  r,
+                                   LTC_SSHDATA_MPINT,  s,
+                                   LTC_SSHDATA_EOL,    LTC_NULL);
+error:
+   ltc_mp_deinit_multi(r, s, LTC_NULL);
+   return err;
+}
+
+#endif

+ 73 - 0
src/pk/ecc/ecc_sign_hash_rfc7518.c

@@ -0,0 +1,73 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#include "tomcrypt_private.h"
+
+#ifdef LTC_MECC
+
+/**
+  Sign a message digest (RFC7518 format + recovery_id)
+  @param in        The message digest to sign
+  @param inlen     The length of the digest
+  @param out       [out] The destination for the signature
+  @param outlen    [in/out] The max size and resulting size of the signature
+  @param prng      An active PRNG state
+  @param wprng     The index of the PRNG you wish to use
+  @param recid     [out] Recovery ID
+  @param key       A private ECC key
+  @return CRYPT_OK if successful
+*/
+int ecc_sign_hash_rfc7518_ex(const unsigned char *in,  unsigned long inlen,
+                             unsigned char *out, unsigned long *outlen,
+                             prng_state *prng, int wprng,
+                             int *recid, const ecc_key *key)
+{
+   int err;
+   void *r, *s;
+   unsigned long pbytes, i;
+
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+   LTC_ARGCHK(key    != NULL);
+
+   /* RFC7518 format - raw (r,s) */
+   pbytes = ltc_mp_unsigned_bin_size(key->dp.order);
+   if (*outlen < 2 * pbytes) {
+      *outlen = 2 * pbytes;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   if ((err = ltc_mp_init_multi(&r, &s, LTC_NULL)) != CRYPT_OK) return err;
+   if ((err = ecc_sign_hash_internal(in, inlen, r, s, prng, wprng, recid, key)) != CRYPT_OK) goto error;
+
+   zeromem(out, 2 * pbytes);
+   *outlen = 2 * pbytes;
+   i = ltc_mp_unsigned_bin_size(r);
+   if ((err = ltc_mp_to_unsigned_bin(r, out + pbytes - i)) != CRYPT_OK) goto error;
+   i = ltc_mp_unsigned_bin_size(s);
+   err = ltc_mp_to_unsigned_bin(s, out + 2 * pbytes - i);
+
+error:
+   ltc_mp_deinit_multi(r, s, LTC_NULL);
+   return err;
+}
+
+/**
+  Sign a message digest (RFC7518 format)
+  @param in        The message digest to sign
+  @param inlen     The length of the digest
+  @param out       [out] The destination for the signature
+  @param outlen    [in/out] The max size and resulting size of the signature
+  @param prng      An active PRNG state
+  @param wprng     The index of the PRNG you wish to use
+  @param key       A private ECC key
+  @return CRYPT_OK if successful
+*/
+int ecc_sign_hash_rfc7518(const unsigned char *in,  unsigned long inlen,
+                          unsigned char *out, unsigned long *outlen,
+                          prng_state *prng, int wprng, const ecc_key *key)
+{
+   return ecc_sign_hash_rfc7518_ex(in, inlen, out, outlen, prng, wprng, NULL, key);
+}
+
+#endif

+ 14 - 173
src/pk/ecc/ecc_verify_hash.c

@@ -3,7 +3,7 @@
 
 
 #include "tomcrypt_private.h"
 #include "tomcrypt_private.h"
 
 
-#ifdef LTC_MECC
+#if defined(LTC_MECC) && defined(LTC_DER)
 
 
 /**
 /**
   @file ecc_verify_hash.c
   @file ecc_verify_hash.c
@@ -11,195 +11,36 @@
 */
 */
 
 
 /**
 /**
-   Verify an ECC signature in RFC7518 format
+   Verify an ECC signature (ANSI X9.62 format)
    @param sig         The signature to verify
    @param sig         The signature to verify
    @param siglen      The length of the signature (octets)
    @param siglen      The length of the signature (octets)
    @param hash        The hash (message digest) that was signed
    @param hash        The hash (message digest) that was signed
    @param hashlen     The length of the hash (octets)
    @param hashlen     The length of the hash (octets)
-   @param sigformat   The format of the signature (ecc_signature_type)
-   @param stat        Result of signature, 1==valid, 0==invalid
+   @param stat        [out] Result of signature, 1==valid, 0==invalid
    @param key         The corresponding public ECC key
    @param key         The corresponding public ECC key
    @return CRYPT_OK if successful (even if the signature is not valid)
    @return CRYPT_OK if successful (even if the signature is not valid)
 */
 */
-int ecc_verify_hash_ex(const unsigned char *sig,  unsigned long siglen,
-                       const unsigned char *hash, unsigned long hashlen,
-                       ecc_signature_type sigformat, int *stat, const ecc_key *key)
+int ecc_verify_hash(const unsigned char *sig,  unsigned long siglen,
+                    const unsigned char *hash, unsigned long hashlen,
+                    int *stat, const ecc_key *key)
 {
 {
-   ecc_point     *mG = NULL, *mQ = NULL;
-   void          *r, *s, *v, *w, *u1, *u2, *e, *p, *m, *a, *a_plus3;
-   void          *mu = NULL, *ma = NULL;
-   void          *mp = NULL;
-   int           err;
-   unsigned long pbits, pbytes, i, shift_right;
-   unsigned char ch, buf[MAXBLOCKSIZE];
+   void *r, *s;
+   int err;
 
 
-   LTC_ARGCHK(sig  != NULL);
-   LTC_ARGCHK(hash != NULL);
-   LTC_ARGCHK(stat != NULL);
-   LTC_ARGCHK(key  != NULL);
+   LTC_ARGCHK(sig != NULL);
 
 
-   /* default to invalid signature */
-   *stat = 0;
+   if ((err = ltc_mp_init_multi(&r, &s, NULL)) != CRYPT_OK) return err;
 
 
-   /* allocate ints */
-   if ((err = ltc_mp_init_multi(&r, &s, &v, &w, &u1, &u2, &e, &a_plus3, LTC_NULL)) != CRYPT_OK) {
-      return err;
-   }
-
-   p = key->dp.order;
-   m = key->dp.prime;
-   a = key->dp.A;
-   if ((err = ltc_mp_add_d(a, 3, a_plus3)) != CRYPT_OK) {
-      goto error;
-   }
-
-   /* allocate points */
-   mG = ltc_ecc_new_point();
-   mQ = ltc_ecc_new_point();
-   if (mQ  == NULL || mG == NULL) {
-      err = CRYPT_MEM;
-      goto error;
-   }
-
-   if (sigformat == LTC_ECCSIG_ANSIX962) {
-      /* ANSI X9.62 format - ASN.1 encoded SEQUENCE{ INTEGER(r), INTEGER(s) }  */
-      if ((err = der_decode_sequence_multi_ex(sig, siglen, LTC_DER_SEQ_SEQUENCE | LTC_DER_SEQ_STRICT,
+   /* ANSI X9.62 format - ASN.1 encoded SEQUENCE{ INTEGER(r), INTEGER(s) }  */
+   if ((err = der_decode_sequence_multi_ex(sig, siglen, LTC_DER_SEQ_SEQUENCE | LTC_DER_SEQ_STRICT,
                                      LTC_ASN1_INTEGER, 1UL, r,
                                      LTC_ASN1_INTEGER, 1UL, r,
                                      LTC_ASN1_INTEGER, 1UL, s,
                                      LTC_ASN1_INTEGER, 1UL, s,
                                      LTC_ASN1_EOL, 0UL, LTC_NULL)) != CRYPT_OK)                         { goto error; }
                                      LTC_ASN1_EOL, 0UL, LTC_NULL)) != CRYPT_OK)                         { goto error; }
-   }
-   else if (sigformat == LTC_ECCSIG_RFC7518) {
-      /* RFC7518 format - raw (r,s) */
-      i = ltc_mp_unsigned_bin_size(key->dp.order);
-      if (siglen != (2 * i)) {
-         err = CRYPT_INVALID_PACKET;
-         goto error;
-      }
-      if ((err = ltc_mp_read_unsigned_bin(r, sig,   i)) != CRYPT_OK)                                        { goto error; }
-      if ((err = ltc_mp_read_unsigned_bin(s, sig+i, i)) != CRYPT_OK)                                        { goto error; }
-   }
-   else if (sigformat == LTC_ECCSIG_ETH27) {
-      /* Ethereum (v,r,s) format */
-      if (pk_oid_cmp_with_ulong("1.3.132.0.10", key->dp.oid, key->dp.oidlen) != CRYPT_OK) {
-         /* Only valid for secp256k1 - OID 1.3.132.0.10 */
-         err = CRYPT_ERROR; goto error;
-      }
-      if (siglen != 65) { /* Only secp256k1 curves use this format, so must be 65 bytes long */
-         err = CRYPT_INVALID_PACKET;
-         goto error;
-      }
-      if ((err = ltc_mp_read_unsigned_bin(r, sig,  32)) != CRYPT_OK)                                        { goto error; }
-      if ((err = ltc_mp_read_unsigned_bin(s, sig+32, 32)) != CRYPT_OK)                                      { goto error; }
-   }
-#ifdef LTC_SSH
-   else if (sigformat == LTC_ECCSIG_RFC5656) {
-      char name[64], name2[64];
-      unsigned long namelen = sizeof(name);
-      unsigned long name2len = sizeof(name2);
-
-      /* Decode as SSH data sequence, per RFC4251 */
-      if ((err = ssh_decode_sequence_multi(sig, &siglen,
-                                           LTC_SSHDATA_STRING, name, &namelen,
-                                           LTC_SSHDATA_MPINT,  r,
-                                           LTC_SSHDATA_MPINT,  s,
-                                           LTC_SSHDATA_EOL,    NULL)) != CRYPT_OK)                      { goto error; }
-
-
-      /* Check curve matches identifier string */
-      if ((err = ecc_ssh_ecdsa_encode_name(name2, &name2len, key)) != CRYPT_OK)                         { goto error; }
-      if ((namelen != name2len) || (XSTRCMP(name, name2) != 0)) {
-         err = CRYPT_INVALID_ARG;
-         goto error;
-      }
-   }
-#endif
-   else {
-      /* Unknown signature format */
-      err = CRYPT_ERROR;
-      goto error;
-   }
-
-   /* check for zero */
-   if (ltc_mp_cmp_d(r, 0) != LTC_MP_GT || ltc_mp_cmp_d(s, 0) != LTC_MP_GT ||
-       ltc_mp_cmp(r, p) != LTC_MP_LT || ltc_mp_cmp(s, p) != LTC_MP_LT) {
-      err = CRYPT_INVALID_PACKET;
-      goto error;
-   }
-
-   /* read hash - truncate if needed */
-   pbits = ltc_mp_count_bits(p);
-   pbytes = (pbits+7) >> 3;
-   if (pbits > hashlen*8) {
-      if ((err = ltc_mp_read_unsigned_bin(e, hash, hashlen)) != CRYPT_OK)                                   { goto error; }
-   }
-   else if (pbits % 8 == 0) {
-      if ((err = ltc_mp_read_unsigned_bin(e, hash, pbytes)) != CRYPT_OK)                                    { goto error; }
-   }
-   else {
-      shift_right = 8 - pbits % 8;
-      for (i=0, ch=0; i<pbytes; i++) {
-        buf[i] = ch;
-        ch = (hash[i] << (8-shift_right));
-        buf[i] = buf[i] ^ (hash[i] >> shift_right);
-      }
-      if ((err = ltc_mp_read_unsigned_bin(e, buf, pbytes)) != CRYPT_OK)                                     { goto error; }
-   }
-
-   /*  w  = s^-1 mod n */
-   if ((err = ltc_mp_invmod(s, p, w)) != CRYPT_OK)                                                          { goto error; }
-
-   /* u1 = ew */
-   if ((err = ltc_mp_mulmod(e, w, p, u1)) != CRYPT_OK)                                                      { goto error; }
-
-   /* u2 = rw */
-   if ((err = ltc_mp_mulmod(r, w, p, u2)) != CRYPT_OK)                                                      { goto error; }
-
-   /* find mG and mQ */
-   if ((err = ltc_ecc_copy_point(&key->dp.base, mG)) != CRYPT_OK)                                       { goto error; }
-   if ((err = ltc_ecc_copy_point(&key->pubkey, mQ)) != CRYPT_OK)                                        { goto error; }
-
-   /* find the montgomery mp */
-   if ((err = ltc_mp_montgomery_setup(m, &mp)) != CRYPT_OK)                                                 { goto error; }
-
-   /* for curves with a == -3 keep ma == NULL */
-   if (ltc_mp_cmp(a_plus3, m) != LTC_MP_EQ) {
-      if ((err = ltc_mp_init_multi(&mu, &ma, LTC_NULL)) != CRYPT_OK)                                        { goto error; }
-      if ((err = ltc_mp_montgomery_normalization(mu, m)) != CRYPT_OK)                                       { goto error; }
-      if ((err = ltc_mp_mulmod(a, mu, m, ma)) != CRYPT_OK)                                                  { goto error; }
-   }
-
-   /* compute u1*mG + u2*mQ = mG */
-   if (ltc_mp.ecc_mul2add == NULL) {
-      if ((err = ltc_mp.ecc_ptmul(u1, mG, mG, a, m, 0)) != CRYPT_OK)                                    { goto error; }
-      if ((err = ltc_mp.ecc_ptmul(u2, mQ, mQ, a, m, 0)) != CRYPT_OK)                                    { goto error; }
-
-      /* add them */
-      if ((err = ltc_mp.ecc_ptadd(mQ, mG, mG, ma, m, mp)) != CRYPT_OK)                                  { goto error; }
-
-      /* reduce */
-      if ((err = ltc_mp.ecc_map(mG, m, mp)) != CRYPT_OK)                                                { goto error; }
-   } else {
-      /* use Shamir's trick to compute u1*mG + u2*mQ using half of the doubles */
-      if ((err = ltc_mp.ecc_mul2add(mG, u1, mQ, u2, mG, ma, m)) != CRYPT_OK)                            { goto error; }
-   }
-
-   /* v = X_x1 mod n */
-   if ((err = ltc_mp_mod(mG->x, p, v)) != CRYPT_OK)                                                         { goto error; }
 
 
-   /* does v == r */
-   if (ltc_mp_cmp(v, r) == LTC_MP_EQ) {
-      *stat = 1;
-   }
+   err = ecc_verify_hash_internal(r, s, hash, hashlen, stat, key);
 
 
-   /* clear up and return */
-   err = CRYPT_OK;
 error:
 error:
-   if (mG != NULL) ltc_ecc_del_point(mG);
-   if (mQ != NULL) ltc_ecc_del_point(mQ);
-   if (mu != NULL) ltc_mp_clear(mu);
-   if (ma != NULL) ltc_mp_clear(ma);
-   ltc_mp_deinit_multi(r, s, v, w, u1, u2, e, a_plus3, LTC_NULL);
-   if (mp != NULL) ltc_mp_montgomery_free(mp);
+   ltc_mp_deinit_multi(r, s, LTC_NULL);
    return err;
    return err;
 }
 }
 
 

+ 53 - 0
src/pk/ecc/ecc_verify_hash_eth27.c

@@ -0,0 +1,53 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#include "tomcrypt_private.h"
+
+#ifdef LTC_MECC
+
+/**
+  @file ecc_verify_hash.c
+  ECC Crypto, Tom St Denis
+*/
+
+/**
+   Verify an ECC signature (Ethereum format with recovery_id+27)
+   @param sig         The signature to verify
+   @param siglen      The length of the signature (octets)
+   @param hash        The hash (message digest) that was signed
+   @param hashlen     The length of the hash (octets)
+   @param stat        [out] Result of signature, 1==valid, 0==invalid
+   @param key         The corresponding public ECC key
+   @return CRYPT_OK if successful (even if the signature is not valid)
+*/
+int ecc_verify_hash_eth27(const unsigned char *sig,  unsigned long siglen,
+                          const unsigned char *hash, unsigned long hashlen,
+                          int *stat, const ecc_key *key)
+{
+   void *r, *s;
+   int err;
+
+   LTC_ARGCHK(sig != NULL);
+   LTC_ARGCHK(key != NULL);
+
+   /* Only valid for secp256k1 - OID 1.3.132.0.10 */
+   if (pk_oid_cmp_with_ulong("1.3.132.0.10", key->dp.oid, key->dp.oidlen) != CRYPT_OK) {
+      return CRYPT_ERROR;
+   }
+   /* Only secp256k1 curves uses this format, so must be 65 bytes long */
+   if (siglen != 65) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   if ((err = ltc_mp_init_multi(&r, &s, LTC_NULL)) != CRYPT_OK) return err;
+   if ((err = ltc_mp_read_unsigned_bin(r, (unsigned char *)sig, 32)) != CRYPT_OK) goto error;
+   if ((err = ltc_mp_read_unsigned_bin(s, (unsigned char *)sig + 32, 32)) != CRYPT_OK) goto error;
+
+   err = ecc_verify_hash_internal(r, s, hash, hashlen, stat, key);
+
+error:
+   ltc_mp_deinit_multi(r, s, LTC_NULL);
+   return err;
+}
+
+#endif

+ 137 - 0
src/pk/ecc/ecc_verify_hash_internal.c

@@ -0,0 +1,137 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#include "tomcrypt_private.h"
+
+#ifdef LTC_MECC
+
+int ecc_verify_hash_internal(void *r, void *s,
+                             const unsigned char *hash, unsigned long hashlen,
+                             int *stat, const ecc_key *key)
+{
+   ecc_point     *mG = NULL, *mQ = NULL;
+   void          *v, *w, *u1, *u2, *e, *p, *m, *a, *a_plus3;
+   void          *mu = NULL, *ma = NULL;
+   void          *mp = NULL;
+   int           err;
+   unsigned long pbits, pbytes, i, shift_right;
+   unsigned char ch, buf[MAXBLOCKSIZE];
+
+   LTC_ARGCHK(r    != NULL);
+   LTC_ARGCHK(s    != NULL);
+   LTC_ARGCHK(hash != NULL);
+   LTC_ARGCHK(stat != NULL);
+   LTC_ARGCHK(key  != NULL);
+
+   /* default to invalid signature */
+   *stat = 0;
+
+   /* allocate ints */
+   if ((err = ltc_mp_init_multi(&v, &w, &u1, &u2, &e, &a_plus3, LTC_NULL)) != CRYPT_OK) {
+      return err;
+   }
+
+   p = key->dp.order;
+   m = key->dp.prime;
+   a = key->dp.A;
+   if ((err = ltc_mp_add_d(a, 3, a_plus3)) != CRYPT_OK) {
+      goto error;
+   }
+
+   /* allocate points */
+   mG = ltc_ecc_new_point();
+   mQ = ltc_ecc_new_point();
+   if (mQ  == NULL || mG == NULL) {
+      err = CRYPT_MEM;
+      goto error;
+   }
+
+   /* check for zero */
+   if (ltc_mp_cmp_d(r, 0) != LTC_MP_GT || ltc_mp_cmp_d(s, 0) != LTC_MP_GT ||
+       ltc_mp_cmp(r, p) != LTC_MP_LT || ltc_mp_cmp(s, p) != LTC_MP_LT) {
+      err = CRYPT_INVALID_PACKET;
+      goto error;
+   }
+
+   /* read hash - truncate if needed */
+   pbits = ltc_mp_count_bits(p);
+   pbytes = (pbits+7) >> 3;
+   if (pbits > hashlen*8) {
+      if ((err = ltc_mp_read_unsigned_bin(e, (unsigned char *)hash, hashlen)) != CRYPT_OK)                  { goto error; }
+   }
+   else if (pbits % 8 == 0) {
+      if ((err = ltc_mp_read_unsigned_bin(e, (unsigned char *)hash, pbytes)) != CRYPT_OK)                   { goto error; }
+   }
+   else {
+      if (pbytes >= MAXBLOCKSIZE) {
+         err = CRYPT_BUFFER_OVERFLOW;
+         goto error;
+      }
+      shift_right = 8 - pbits % 8;
+      for (i=0, ch=0; i<pbytes; i++) {
+        buf[i] = ch;
+        ch = (hash[i] << (8-shift_right));
+        buf[i] = buf[i] ^ (hash[i] >> shift_right);
+      }
+      if ((err = ltc_mp_read_unsigned_bin(e, (unsigned char *)buf, pbytes)) != CRYPT_OK)                    { goto error; }
+   }
+
+   /*  w  = s^-1 mod n */
+   if ((err = ltc_mp_invmod(s, p, w)) != CRYPT_OK)                                                          { goto error; }
+
+   /* u1 = ew */
+   if ((err = ltc_mp_mulmod(e, w, p, u1)) != CRYPT_OK)                                                      { goto error; }
+
+   /* u2 = rw */
+   if ((err = ltc_mp_mulmod(r, w, p, u2)) != CRYPT_OK)                                                      { goto error; }
+
+   /* find mG and mQ */
+   if ((err = ltc_ecc_copy_point(&key->dp.base, mG)) != CRYPT_OK)                                       { goto error; }
+   if ((err = ltc_ecc_copy_point(&key->pubkey, mQ)) != CRYPT_OK)                                        { goto error; }
+
+   /* find the montgomery mp */
+   if ((err = ltc_mp_montgomery_setup(m, &mp)) != CRYPT_OK)                                                 { goto error; }
+
+   /* for curves with a == -3 keep ma == NULL */
+   if (ltc_mp_cmp(a_plus3, m) != LTC_MP_EQ) {
+      if ((err = ltc_mp_init_multi(&mu, &ma, NULL)) != CRYPT_OK)                                            { goto error; }
+      if ((err = ltc_mp_montgomery_normalization(mu, m)) != CRYPT_OK)                                       { goto error; }
+      if ((err = ltc_mp_mulmod(a, mu, m, ma)) != CRYPT_OK)                                                  { goto error; }
+   }
+
+   /* compute u1*mG + u2*mQ = mG */
+   if (ltc_mp.ecc_mul2add == NULL) {
+      if ((err = ltc_mp.ecc_ptmul(u1, mG, mG, a, m, 0)) != CRYPT_OK)                                    { goto error; }
+      if ((err = ltc_mp.ecc_ptmul(u2, mQ, mQ, a, m, 0)) != CRYPT_OK)                                    { goto error; }
+
+      /* add them */
+      if ((err = ltc_mp.ecc_ptadd(mQ, mG, mG, ma, m, mp)) != CRYPT_OK)                                  { goto error; }
+
+      /* reduce */
+      if ((err = ltc_mp.ecc_map(mG, m, mp)) != CRYPT_OK)                                                { goto error; }
+   } else {
+      /* use Shamir's trick to compute u1*mG + u2*mQ using half of the doubles */
+      if ((err = ltc_mp.ecc_mul2add(mG, u1, mQ, u2, mG, ma, m)) != CRYPT_OK)                            { goto error; }
+   }
+
+   /* v = X_x1 mod n */
+   if ((err = ltc_mp_mod(mG->x, p, v)) != CRYPT_OK)                                                         { goto error; }
+
+   /* does v == r */
+   if (ltc_mp_cmp(v, r) == LTC_MP_EQ) {
+      *stat = 1;
+   }
+
+   /* clear up and return */
+   err = CRYPT_OK;
+error:
+   if (mG != NULL) ltc_ecc_del_point(mG);
+   if (mQ != NULL) ltc_ecc_del_point(mQ);
+   if (mu != NULL) ltc_mp_clear(mu);
+   if (ma != NULL) ltc_mp_clear(ma);
+   ltc_mp_deinit_multi(v, w, u1, u2, e, a_plus3, LTC_NULL);
+   if (mp != NULL) ltc_mp_montgomery_free(mp);
+   return err;
+}
+
+#endif

+ 65 - 0
src/pk/ecc/ecc_verify_hash_rfc5656.c

@@ -0,0 +1,65 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#include "tomcrypt_private.h"
+
+#if defined(LTC_MECC) && defined(LTC_SSH)
+
+/**
+  @file ecc_verify_hash.c
+  ECC Crypto, Tom St Denis
+*/
+
+/**
+   Verify an ECC signature (RFC5656 / SSH format)
+   @param sig         The signature to verify
+   @param siglen      The length of the signature (octets)
+   @param hash        The hash (message digest) that was signed
+   @param hashlen     The length of the hash (octets)
+   @param stat        [out] Result of signature, 1==valid, 0==invalid
+   @param key         The corresponding public ECC key
+   @return CRYPT_OK if successful (even if the signature is not valid)
+*/
+int ecc_verify_hash_rfc5656(const unsigned char *sig,  unsigned long siglen,
+                            const unsigned char *hash, unsigned long hashlen,
+                            int *stat, const ecc_key *key)
+{
+   void *r, *s;
+   int err;
+   char name[64], name2[64];
+   unsigned long namelen = sizeof(name);
+   unsigned long name2len = sizeof(name2);
+   unsigned long slen = siglen;
+
+   LTC_ARGCHK(sig != NULL);
+   LTC_ARGCHK(key != NULL);
+
+   if ((err = ltc_mp_init_multi(&r, &s, LTC_NULL)) != CRYPT_OK) return err;
+
+   /* Decode as SSH data sequence, per RFC4251 */
+   if ((err = ssh_decode_sequence_multi(sig, &slen,
+                                        LTC_SSHDATA_STRING, name, &namelen,
+                                        LTC_SSHDATA_MPINT,  r,
+                                        LTC_SSHDATA_MPINT,  s,
+                                        LTC_SSHDATA_EOL,    LTC_NULL)) != CRYPT_OK) goto error;
+
+   if (slen != siglen) {
+      err = CRYPT_INVALID_PACKET;
+      goto error;
+   }
+
+   /* Check curve matches identifier string */
+   if ((err = ecc_ssh_ecdsa_encode_name(name2, &name2len, key)) != CRYPT_OK) goto error;
+   if (XSTRCMP(name,name2) != 0) {
+      err = CRYPT_INVALID_ARG;
+      goto error;
+   }
+
+   err = ecc_verify_hash_internal(r, s, hash, hashlen, stat, key);
+
+error:
+   ltc_mp_deinit_multi(r, s, LTC_NULL);
+   return err;
+}
+
+#endif

+ 52 - 0
src/pk/ecc/ecc_verify_hash_rfc7518.c

@@ -0,0 +1,52 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#include "tomcrypt_private.h"
+
+#ifdef LTC_MECC
+
+/**
+  @file ecc_verify_hash.c
+  ECC Crypto, Tom St Denis
+*/
+
+/**
+   Verify an ECC signature (RFC7518 format)
+   @param sig         The signature to verify
+   @param siglen      The length of the signature (octets)
+   @param hash        The hash (message digest) that was signed
+   @param hashlen     The length of the hash (octets)
+   @param stat        [out] Result of signature, 1==valid, 0==invalid
+   @param key         The corresponding public ECC key
+   @return CRYPT_OK if successful (even if the signature is not valid)
+*/
+int ecc_verify_hash_rfc7518(const unsigned char *sig,  unsigned long siglen,
+                            const unsigned char *hash, unsigned long hashlen,
+                            int *stat, const ecc_key *key)
+{
+   void *r, *s;
+   int err;
+   unsigned long i;
+
+   LTC_ARGCHK(sig != NULL);
+   LTC_ARGCHK(key != NULL);
+
+   if ((err = ltc_mp_init_multi(&r, &s, LTC_NULL)) != CRYPT_OK) return err;
+
+   /* RFC7518 format - raw (r,s) */
+   i = ltc_mp_unsigned_bin_size(key->dp.order);
+   if (siglen != (2 * i)) {
+      err = CRYPT_INVALID_PACKET;
+      goto error;
+   }
+   if ((err = ltc_mp_read_unsigned_bin(r, (unsigned char *)sig, i)) != CRYPT_OK) goto error;
+   if ((err = ltc_mp_read_unsigned_bin(s, (unsigned char *)sig + i, i)) != CRYPT_OK) goto error;
+
+   err = ecc_verify_hash_internal(r, s, hash, hashlen, stat, key);
+
+error:
+   ltc_mp_deinit_multi(r, s, LTC_NULL);
+   return err;
+}
+
+#endif

+ 45 - 9
tests/ecc_test.c

@@ -616,10 +616,9 @@ static int s_ecc_new_api(void)
 #ifdef LTC_SSH
 #ifdef LTC_SSH
       /* test SSH+ECDSA/RFC5656 signature */
       /* test SSH+ECDSA/RFC5656 signature */
       len = sizeof(buf);
       len = sizeof(buf);
-      DO(ecc_sign_hash_ex(data16, 16, buf, &len, &yarrow_prng, find_prng ("yarrow"),
-                          LTC_ECCSIG_RFC5656, NULL, &privkey));
+      DO(ecc_sign_hash_rfc5656(data16, 16, buf, &len, &yarrow_prng, find_prng ("yarrow"), &privkey));
       stat = 0;
       stat = 0;
-      DO(ecc_verify_hash_ex(buf, len, data16, 16, LTC_ECCSIG_RFC5656, &stat, &pubkey));
+      DO(ecc_verify_hash_rfc5656(buf, len, data16, 16, &stat, &pubkey));
       if (stat != 1) return CRYPT_FAIL_TESTVECTOR;
       if (stat != 1) return CRYPT_FAIL_TESTVECTOR;
 #endif
 #endif
 
 
@@ -1517,6 +1516,44 @@ static int s_ecc_import_export(void) {
 }
 }
 
 
 #ifdef LTC_ECC_SHAMIR
 #ifdef LTC_ECC_SHAMIR
+static int s_ecc_test_ethereum(void)
+{
+#ifdef LTC_ECC_SECP256K1
+   int stat;
+   const ltc_ecc_curve* dp;
+   ecc_key key, reckey;
+   unsigned char buf[128];
+   unsigned long len;
+   unsigned char data16[16] = { 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1 };
+
+   DO(ecc_find_curve("SECP256K1", &dp));
+
+   DO(ecc_make_key_ex(&yarrow_prng, find_prng ("yarrow"), &key, dp));
+
+   /* test Ethereum signature */
+   len = sizeof(buf);
+   DO(ecc_sign_hash_eth27(data16, 16, buf, &len, &yarrow_prng, find_prng ("yarrow"), &key));
+   stat = 0;
+   DO(ecc_verify_hash_eth27(buf, len, data16, 16, &stat, &key));
+   if (stat != 1) return CRYPT_FAIL_TESTVECTOR;
+
+   /* XXX-FIXME: TFM does not support sqrtmod_prime */
+   if (strcmp(ltc_mp.name, "TomsFastMath") != 0) {
+      DO(ecc_set_curve(dp, &reckey));
+      DO(ecc_recover_key(buf, len, data16, 16, -1, LTC_ECCSIG_ETH27, &reckey));
+      DO(ecc_key_cmp(PK_PUBLIC, &key, &reckey));
+
+      /* cleanup */
+      ecc_free(&reckey);
+   }
+   /* cleanup */
+   ecc_free(&key);
+   return CRYPT_OK;
+#else
+   return CRYPT_NOP;
+#endif
+}
+
 static int s_ecc_test_recovery(void)
 static int s_ecc_test_recovery(void)
 {
 {
    int i, recid, stat;
    int i, recid, stat;
@@ -1554,14 +1591,12 @@ static int s_ecc_test_recovery(void)
    DO(ecc_set_key(eth_pubkey, sizeof(eth_pubkey), PK_PUBLIC, &pubkey));
    DO(ecc_set_key(eth_pubkey, sizeof(eth_pubkey), PK_PUBLIC, &pubkey));
 
 
    DO(ecc_set_curve(dp, &reckey));
    DO(ecc_set_curve(dp, &reckey));
-   stat = ecc_recover_key(eth_sig, sizeof(eth_sig)-1, eth_hash, sizeof(eth_hash), 0, LTC_ECCSIG_RFC7518, &reckey);
-   if (stat != CRYPT_OK) return CRYPT_FAIL_TESTVECTOR;
+   DO(ecc_recover_key(eth_sig, sizeof(eth_sig)-1, eth_hash, sizeof(eth_hash), 0, LTC_ECCSIG_RFC7518, &reckey));
    DO(ecc_key_cmp(PK_PUBLIC, &pubkey, &reckey));
    DO(ecc_key_cmp(PK_PUBLIC, &pubkey, &reckey));
    ecc_free(&reckey);
    ecc_free(&reckey);
 
 
    DO(ecc_set_curve(dp, &reckey));
    DO(ecc_set_curve(dp, &reckey));
-   stat = ecc_recover_key(eth_sig, sizeof(eth_sig), eth_hash, sizeof(eth_hash), -1, LTC_ECCSIG_ETH27, &reckey);
-   if (stat != CRYPT_OK) return CRYPT_FAIL_TESTVECTOR;
+   DO(ecc_recover_key(eth_sig, sizeof(eth_sig), eth_hash, sizeof(eth_hash), -1, LTC_ECCSIG_ETH27, &reckey));
    DO(ecc_key_cmp(PK_PUBLIC, &pubkey, &reckey));
    DO(ecc_key_cmp(PK_PUBLIC, &pubkey, &reckey));
    ecc_free(&reckey);
    ecc_free(&reckey);
 
 
@@ -1596,11 +1631,11 @@ static int s_ecc_test_recovery(void)
       /* test signature */
       /* test signature */
       len = sizeof(buf);
       len = sizeof(buf);
       recid = 0;
       recid = 0;
-      DO(ecc_sign_hash_ex(data16, 16, buf, &len, &yarrow_prng, find_prng ("yarrow"), LTC_ECCSIG_RFC7518, &recid, &privkey));
+      DO(ecc_sign_hash_rfc7518_ex(data16, 16, buf, &len, &yarrow_prng, find_prng ("yarrow"), &recid, &privkey));
 
 
       /* test verification */
       /* test verification */
       stat = 0;
       stat = 0;
-      DO(ecc_verify_hash_ex(buf, len, data16, 16, LTC_ECCSIG_RFC7518, &stat, &pubkey));
+      DO(ecc_verify_hash_rfc7518(buf, len, data16, 16, &stat, &pubkey));
       if (stat != 1) return CRYPT_FAIL_TESTVECTOR;
       if (stat != 1) return CRYPT_FAIL_TESTVECTOR;
 
 
       /* test recovery */
       /* test recovery */
@@ -1633,6 +1668,7 @@ int ecc_test(void)
 #ifdef LTC_ECC_SHAMIR
 #ifdef LTC_ECC_SHAMIR
    DO(s_ecc_test_shamir());
    DO(s_ecc_test_shamir());
    DO(s_ecc_test_recovery());
    DO(s_ecc_test_recovery());
+   DO(s_ecc_test_ethereum());
 #endif
 #endif
    return CRYPT_OK;
    return CRYPT_OK;
 }
 }