Skip to content

Commit c5e4679

Browse files
authored
Merge pull request #436 from rmw42/feature/ecrecover
Implement ecc_recover_key to recover public key from hash+signature
2 parents b44155f + 88d9b6d commit c5e4679

File tree

11 files changed

+720
-150
lines changed

11 files changed

+720
-150
lines changed

doc/crypt.tex

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5549,6 +5549,22 @@ \subsection{Signature Generation}
55495549
This function creates the same ECDSA signature as \textit{ecc\_sign\_hash} only the output format is different.
55505550
The format follows \url{https://tools.ietf.org/html/rfc7518#section-3.4}, sometimes it is also called plain signature.
55515551

5552+
\index{ecc\_sign\_hash_ex()}
5553+
\begin{verbatim}
5554+
int ecc_sign_hash_ex(const unsigned char *in,
5555+
unsigned long inlen,
5556+
unsigned char *out,
5557+
unsigned long *outlen,
5558+
prng_state *prng,
5559+
int wprng,
5560+
ecc_signature_type sigformat,
5561+
int *recid,
5562+
ecc_key *key);
5563+
\end{verbatim}
5564+
5565+
This function is an extended version of the ECDSA signature in \textit{ecc\_sign\_hash}, but with a choice of output formats
5566+
and an optional output of the recovery ID for use with \textit{ecc\_recover\_key}.
5567+
55525568
\subsection{Signature Verification}
55535569
\index{ecc\_verify\_hash()}
55545570
\begin{verbatim}
@@ -5579,12 +5595,74 @@ \subsection{Signature Verification}
55795595
This function validate the ECDSA signature as \textit{ecc\_verify\_hash} only the signature input format
55805596
follows \url{https://tools.ietf.org/html/rfc7518#section-3.4}.
55815597

5598+
\index{ecc\_verify\_hash_ex()}
5599+
\begin{verbatim}
5600+
int ecc_verify_hash_ex(const unsigned char *sig,
5601+
unsigned long siglen,
5602+
const unsigned char *hash,
5603+
unsigned long hashlen,
5604+
ecc_signature_type sigformat,
5605+
int *stat,
5606+
ecc_key *key);
5607+
\end{verbatim}
5608+
5609+
This function validates an ECDSA signature as \textit{ecc\_verify\_hash} but with a choice of signature formats.
5610+
55825611
{\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
55835612
will still work, and in effect the signature will still work. With ECC keys the strength of the signature is limited
55845613
by the size of the hash, or the size of the key, whichever is smaller. For example, if you sign with SHA256 and a
55855614
P--192 key, you have in effect 96--bits of security. The library will not warn you if you make this mistake, so it
55865615
is important to check yourself before using the signatures.
55875616

5617+
\subsection{Public Key Recovery}
5618+
\index{ecc\_recover\_key()}
5619+
\begin{verbatim}
5620+
int ecc_recover_key(const unsigned char *sig,
5621+
unsigned long siglen,
5622+
const unsigned char *hash,
5623+
unsigned long hashlen,
5624+
int recid,
5625+
ecc_signature_type sigformat,
5626+
ecc_key *key);
5627+
\end{verbatim}
5628+
5629+
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
5630+
pointed to by the array \textit{hash} of length \textit{hashlen}, and the recovery id \textit{recid}. It will store the recovered
5631+
key into \textit{key} and return CRYPT\_OK if recovery succeeds, or an error if recovery fails.
5632+
This is for compatibility with the (v,r,s) signatures used in Ethereum, where public keys are not explicitly shared,
5633+
only the parity of the public key. For curves like secp256k1, recid will take values of 0 or 1, corresponding to the
5634+
parity of the public key's y coordinate. For curves like secp112r2, with a cofactor of 4, values 0..7 are possible,
5635+
with the low bit corresponding to the parity and the higher bits specifying the public key's x coordinate's multiple
5636+
of the curve's order.
5637+
If the signature format contains the recovery id (currently only \textit{LTC\_ECCSIG\_ETH27}), \textit{recid} can be -1
5638+
which signals that the recovery id from the signature blob should be used. This means an application does not need to
5639+
extract the recovery id from such a signature in order to use this function.
5640+
The function \textit{ecc\_recover\_key} implements multiple signature formats, and the output is compliant for GF(p) curves.
5641+
5642+
\subsection{Signature Formats}
5643+
The following signature formats are suported:
5644+
5645+
\begin{figure}[hpbt]
5646+
\index{Signature Formats}
5647+
\begin{small}
5648+
\begin{center}
5649+
\begin{tabular}{|l|l|}
5650+
\hline \textbf{sigformat} & \textbf{description} \\
5651+
\hline LTC\_ECCSIG\_ANSIX962 & ASN.1 encoded, ANSI X9.62 \\
5652+
\hline LTC\_ECCSIG\_RFC7518 & raw R, S values as defined in RFC7518 \\
5653+
\hline LTC\_ECCSIG\_ETH27 & raw R, S, V values (V has 27 added) \\
5654+
\hline
5655+
\end{tabular}
5656+
\end{center}
5657+
\end{small}
5658+
\caption{Signature Formats}
5659+
\label{fig:sigformat}
5660+
\end{figure}
5661+
5662+
The \textit{LTC\_ECCSIG\_ETH27} format is based on the Ethereum Yellow Paper, see \url{https://github.com/ethereum/yellowpaper}
5663+
(Appendix F). However, convention allows the use of v=0,1 as equivalent to v=27,28 and both are accepted by
5664+
\textit{ecc\_recover\_key}.
5665+
55885666
\mysection{Shared Secret (ECDH)}
55895667
To construct a Diffie-Hellman shared secret with a private and public ECC key, use the following function:
55905668
\index{ecc\_shared\_secret()}

libtomcrypt_VS2008.vcproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2338,6 +2338,10 @@
23382338
RelativePath="src\pk\ecc\ecc_make_key.c"
23392339
>
23402340
</File>
2341+
<File
2342+
RelativePath="src\pk\ecc\ecc_recover_key.c"
2343+
>
2344+
</File>
23412345
<File
23422346
RelativePath="src\pk\ecc\ecc_set_curve.c"
23432347
>

makefile.mingw

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,9 +181,9 @@ src/pk/ecc/ecc_ansi_x963_import.o src/pk/ecc/ecc_decrypt_key.o src/pk/ecc/ecc_en
181181
src/pk/ecc/ecc_export.o src/pk/ecc/ecc_export_openssl.o src/pk/ecc/ecc_find_curve.o \
182182
src/pk/ecc/ecc_free.o src/pk/ecc/ecc_get_key.o src/pk/ecc/ecc_get_oid_str.o src/pk/ecc/ecc_get_size.o \
183183
src/pk/ecc/ecc_import.o src/pk/ecc/ecc_import_openssl.o src/pk/ecc/ecc_import_x509.o \
184-
src/pk/ecc/ecc_make_key.o src/pk/ecc/ecc_set_curve.o src/pk/ecc/ecc_set_curve_internal.o \
185-
src/pk/ecc/ecc_set_key.o src/pk/ecc/ecc_shared_secret.o src/pk/ecc/ecc_sign_hash.o \
186-
src/pk/ecc/ecc_sizes.o src/pk/ecc/ecc_test.o src/pk/ecc/ecc_verify_hash.o \
184+
src/pk/ecc/ecc_make_key.o src/pk/ecc/ecc_recover_key.o src/pk/ecc/ecc_set_curve.o \
185+
src/pk/ecc/ecc_set_curve_internal.o src/pk/ecc/ecc_set_key.o src/pk/ecc/ecc_shared_secret.o \
186+
src/pk/ecc/ecc_sign_hash.o src/pk/ecc/ecc_sizes.o src/pk/ecc/ecc_test.o src/pk/ecc/ecc_verify_hash.o \
187187
src/pk/ecc/ltc_ecc_export_point.o src/pk/ecc/ltc_ecc_import_point.o src/pk/ecc/ltc_ecc_is_point.o \
188188
src/pk/ecc/ltc_ecc_is_point_at_infinity.o src/pk/ecc/ltc_ecc_map.o src/pk/ecc/ltc_ecc_mul2add.o \
189189
src/pk/ecc/ltc_ecc_mulmod.o src/pk/ecc/ltc_ecc_mulmod_timing.o src/pk/ecc/ltc_ecc_points.o \

makefile.msvc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -174,9 +174,9 @@ src/pk/ecc/ecc_ansi_x963_import.obj src/pk/ecc/ecc_decrypt_key.obj src/pk/ecc/ec
174174
src/pk/ecc/ecc_export.obj src/pk/ecc/ecc_export_openssl.obj src/pk/ecc/ecc_find_curve.obj \
175175
src/pk/ecc/ecc_free.obj src/pk/ecc/ecc_get_key.obj src/pk/ecc/ecc_get_oid_str.obj src/pk/ecc/ecc_get_size.obj \
176176
src/pk/ecc/ecc_import.obj src/pk/ecc/ecc_import_openssl.obj src/pk/ecc/ecc_import_x509.obj \
177-
src/pk/ecc/ecc_make_key.obj src/pk/ecc/ecc_set_curve.obj src/pk/ecc/ecc_set_curve_internal.obj \
178-
src/pk/ecc/ecc_set_key.obj src/pk/ecc/ecc_shared_secret.obj src/pk/ecc/ecc_sign_hash.obj \
179-
src/pk/ecc/ecc_sizes.obj src/pk/ecc/ecc_test.obj src/pk/ecc/ecc_verify_hash.obj \
177+
src/pk/ecc/ecc_make_key.obj src/pk/ecc/ecc_recover_key.obj src/pk/ecc/ecc_set_curve.obj \
178+
src/pk/ecc/ecc_set_curve_internal.obj src/pk/ecc/ecc_set_key.obj src/pk/ecc/ecc_shared_secret.obj \
179+
src/pk/ecc/ecc_sign_hash.obj src/pk/ecc/ecc_sizes.obj src/pk/ecc/ecc_test.obj src/pk/ecc/ecc_verify_hash.obj \
180180
src/pk/ecc/ltc_ecc_export_point.obj src/pk/ecc/ltc_ecc_import_point.obj src/pk/ecc/ltc_ecc_is_point.obj \
181181
src/pk/ecc/ltc_ecc_is_point_at_infinity.obj src/pk/ecc/ltc_ecc_map.obj src/pk/ecc/ltc_ecc_mul2add.obj \
182182
src/pk/ecc/ltc_ecc_mulmod.obj src/pk/ecc/ltc_ecc_mulmod_timing.obj src/pk/ecc/ltc_ecc_points.obj \

makefile.unix

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,9 +191,9 @@ src/pk/ecc/ecc_ansi_x963_import.o src/pk/ecc/ecc_decrypt_key.o src/pk/ecc/ecc_en
191191
src/pk/ecc/ecc_export.o src/pk/ecc/ecc_export_openssl.o src/pk/ecc/ecc_find_curve.o \
192192
src/pk/ecc/ecc_free.o src/pk/ecc/ecc_get_key.o src/pk/ecc/ecc_get_oid_str.o src/pk/ecc/ecc_get_size.o \
193193
src/pk/ecc/ecc_import.o src/pk/ecc/ecc_import_openssl.o src/pk/ecc/ecc_import_x509.o \
194-
src/pk/ecc/ecc_make_key.o src/pk/ecc/ecc_set_curve.o src/pk/ecc/ecc_set_curve_internal.o \
195-
src/pk/ecc/ecc_set_key.o src/pk/ecc/ecc_shared_secret.o src/pk/ecc/ecc_sign_hash.o \
196-
src/pk/ecc/ecc_sizes.o src/pk/ecc/ecc_test.o src/pk/ecc/ecc_verify_hash.o \
194+
src/pk/ecc/ecc_make_key.o src/pk/ecc/ecc_recover_key.o src/pk/ecc/ecc_set_curve.o \
195+
src/pk/ecc/ecc_set_curve_internal.o src/pk/ecc/ecc_set_key.o src/pk/ecc/ecc_shared_secret.o \
196+
src/pk/ecc/ecc_sign_hash.o src/pk/ecc/ecc_sizes.o src/pk/ecc/ecc_test.o src/pk/ecc/ecc_verify_hash.o \
197197
src/pk/ecc/ltc_ecc_export_point.o src/pk/ecc/ltc_ecc_import_point.o src/pk/ecc/ltc_ecc_is_point.o \
198198
src/pk/ecc/ltc_ecc_is_point_at_infinity.o src/pk/ecc/ltc_ecc_map.o src/pk/ecc/ltc_ecc_mul2add.o \
199199
src/pk/ecc/ltc_ecc_mulmod.o src/pk/ecc/ltc_ecc_mulmod_timing.o src/pk/ecc/ltc_ecc_points.o \

makefile_include.mk

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -351,9 +351,9 @@ src/pk/ecc/ecc_ansi_x963_import.o src/pk/ecc/ecc_decrypt_key.o src/pk/ecc/ecc_en
351351
src/pk/ecc/ecc_export.o src/pk/ecc/ecc_export_openssl.o src/pk/ecc/ecc_find_curve.o \
352352
src/pk/ecc/ecc_free.o src/pk/ecc/ecc_get_key.o src/pk/ecc/ecc_get_oid_str.o src/pk/ecc/ecc_get_size.o \
353353
src/pk/ecc/ecc_import.o src/pk/ecc/ecc_import_openssl.o src/pk/ecc/ecc_import_x509.o \
354-
src/pk/ecc/ecc_make_key.o src/pk/ecc/ecc_set_curve.o src/pk/ecc/ecc_set_curve_internal.o \
355-
src/pk/ecc/ecc_set_key.o src/pk/ecc/ecc_shared_secret.o src/pk/ecc/ecc_sign_hash.o \
356-
src/pk/ecc/ecc_sizes.o src/pk/ecc/ecc_test.o src/pk/ecc/ecc_verify_hash.o \
354+
src/pk/ecc/ecc_make_key.o src/pk/ecc/ecc_recover_key.o src/pk/ecc/ecc_set_curve.o \
355+
src/pk/ecc/ecc_set_curve_internal.o src/pk/ecc/ecc_set_key.o src/pk/ecc/ecc_shared_secret.o \
356+
src/pk/ecc/ecc_sign_hash.o src/pk/ecc/ecc_sizes.o src/pk/ecc/ecc_test.o src/pk/ecc/ecc_verify_hash.o \
357357
src/pk/ecc/ltc_ecc_export_point.o src/pk/ecc/ltc_ecc_import_point.o src/pk/ecc/ltc_ecc_is_point.o \
358358
src/pk/ecc/ltc_ecc_is_point_at_infinity.o src/pk/ecc/ltc_ecc_map.o src/pk/ecc/ltc_ecc_mul2add.o \
359359
src/pk/ecc/ltc_ecc_mulmod.o src/pk/ecc/ltc_ecc_mulmod_timing.o src/pk/ecc/ltc_ecc_points.o \

src/headers/tomcrypt_pk.h

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,16 @@ typedef struct {
244244
void *k;
245245
} ecc_key;
246246

247+
/** Formats of ECC signatures */
248+
typedef enum ecc_signature_type_ {
249+
/* ASN.1 encoded, ANSI X9.62 */
250+
LTC_ECCSIG_ANSIX962 = 0x0,
251+
/* raw R, S values */
252+
LTC_ECCSIG_RFC7518 = 0x1,
253+
/* raw R, S, V (+27) values */
254+
LTC_ECCSIG_ETH27 = 0x2
255+
} ecc_signature_type;
256+
247257
/** the ECC params provided */
248258
extern const ltc_ecc_curve ltc_ecc_curves[];
249259

@@ -286,21 +296,30 @@ int ecc_decrypt_key(const unsigned char *in, unsigned long inlen,
286296
unsigned char *out, unsigned long *outlen,
287297
const ecc_key *key);
288298

289-
int ecc_sign_hash_rfc7518(const unsigned char *in, unsigned long inlen,
290-
unsigned char *out, unsigned long *outlen,
291-
prng_state *prng, int wprng, const ecc_key *key);
299+
#define ecc_sign_hash_rfc7518(in_, inlen_, out_, outlen_, prng_, wprng_, key_) \
300+
ecc_sign_hash_ex(in_, inlen_, out_, outlen_, prng_, wprng_, LTC_ECCSIG_RFC7518, NULL, key_)
301+
302+
#define ecc_sign_hash(in_, inlen_, out_, outlen_, prng_, wprng_, key_) \
303+
ecc_sign_hash_ex(in_, inlen_, out_, outlen_, prng_, wprng_, LTC_ECCSIG_ANSIX962, NULL, key_)
304+
305+
#define ecc_verify_hash_rfc7518(sig_, siglen_, hash_, hashlen_, stat_, key_) \
306+
ecc_verify_hash_ex(sig_, siglen_, hash_, hashlen_, LTC_ECCSIG_RFC7518, stat_, key_)
307+
308+
#define ecc_verify_hash(sig_, siglen_, hash_, hashlen_, stat_, key_) \
309+
ecc_verify_hash_ex(sig_, siglen_, hash_, hashlen_, LTC_ECCSIG_ANSIX962, stat_, key_)
292310

293-
int ecc_sign_hash(const unsigned char *in, unsigned long inlen,
294-
unsigned char *out, unsigned long *outlen,
295-
prng_state *prng, int wprng, const ecc_key *key);
311+
int ecc_sign_hash_ex(const unsigned char *in, unsigned long inlen,
312+
unsigned char *out, unsigned long *outlen,
313+
prng_state *prng, int wprng, ecc_signature_type sigformat,
314+
int *recid, const ecc_key *key);
296315

297-
int ecc_verify_hash_rfc7518(const unsigned char *sig, unsigned long siglen,
298-
const unsigned char *hash, unsigned long hashlen,
299-
int *stat, const ecc_key *key);
316+
int ecc_verify_hash_ex(const unsigned char *sig, unsigned long siglen,
317+
const unsigned char *hash, unsigned long hashlen,
318+
ecc_signature_type sigformat, int *stat, const ecc_key *key);
300319

301-
int ecc_verify_hash(const unsigned char *sig, unsigned long siglen,
320+
int ecc_recover_key(const unsigned char *sig, unsigned long siglen,
302321
const unsigned char *hash, unsigned long hashlen,
303-
int *stat, const ecc_key *key);
322+
int recid, ecc_signature_type sigformat, ecc_key *key);
304323

305324
#endif
306325

0 commit comments

Comments
 (0)