Falcon source files (reference implementation)


tool.c

    1 /*
    2  * Command-line tool for Falcon.
    3  *
    4  * ==========================(LICENSE BEGIN)============================
    5  *
    6  * Copyright (c) 2017  Falcon Project
    7  *
    8  * Permission is hereby granted, free of charge, to any person obtaining
    9  * a copy of this software and associated documentation files (the
   10  * "Software"), to deal in the Software without restriction, including
   11  * without limitation the rights to use, copy, modify, merge, publish,
   12  * distribute, sublicense, and/or sell copies of the Software, and to
   13  * permit persons to whom the Software is furnished to do so, subject to
   14  * the following conditions:
   15  *
   16  * The above copyright notice and this permission notice shall be
   17  * included in all copies or substantial portions of the Software.
   18  *
   19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   20  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
   22  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
   23  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
   24  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
   25  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   26  *
   27  * ===========================(LICENSE END)=============================
   28  *
   29  * @author   Thomas Pornin <thomas.pornin@nccgroup.trust>
   30  */
   31 
   32 #include <stdio.h>
   33 #include <stdlib.h>
   34 #include <string.h>
   35 
   36 #include "falcon.h"
   37 
   38 static void *
   39 xmalloc(size_t len)
   40 {
   41         void *buf;
   42 
   43         if (len == 0) {
   44                 return NULL;
   45         }
   46         buf = malloc(len);
   47         if (buf == NULL) {
   48                 fprintf(stderr, "memory allocation error\n");
   49                 exit(EXIT_FAILURE);
   50         }
   51         return buf;
   52 }
   53 
   54 static void
   55 xfree(void *buf)
   56 {
   57         if (buf != NULL) {
   58                 free(buf);
   59         }
   60 }
   61 
   62 static unsigned char *
   63 read_file(const char *fname, size_t *data_len)
   64 {
   65         FILE *f;
   66         unsigned char *buf;
   67         size_t ptr, len;
   68 
   69         f = fopen(fname, "rb");
   70         if (f == NULL) {
   71                 fprintf(stderr, "could not open file '%s'\n", fname);
   72                 exit(EXIT_FAILURE);
   73         }
   74         buf = NULL;
   75         ptr = 0;
   76         len = 0;
   77         for (;;) {
   78                 unsigned char tmp[4096];
   79                 size_t rlen;
   80 
   81                 rlen = fread(tmp, 1, sizeof tmp, f);
   82                 if (rlen == 0) {
   83                         break;
   84                 }
   85                 if (buf == NULL) {
   86                         buf = xmalloc(rlen);
   87                         memcpy(buf, tmp, rlen);
   88                         ptr = rlen;
   89                         len = rlen;
   90                 } else {
   91                         if ((len - ptr) < rlen) {
   92                                 unsigned char *nbuf;
   93 
   94                                 len <<= 1;
   95                                 if ((len - ptr) < rlen) {
   96                                         len = ptr + rlen;
   97                                 }
   98                                 nbuf = xmalloc(len);
   99                                 memcpy(nbuf, buf, ptr);
  100                                 xfree(buf);
  101                                 buf = nbuf;
  102                         }
  103                         memcpy(buf + ptr, tmp, rlen);
  104                         ptr += rlen;
  105                 }
  106         }
  107         fclose(f);
  108         *data_len = ptr;
  109         return buf;
  110 }
  111 
  112 static void
  113 write_file(const char *fname, const void *data, size_t len)
  114 {
  115         const unsigned char *buf;
  116         FILE *f;
  117 
  118         f = fopen(fname, "wb");
  119         if (f == NULL) {
  120                 fprintf(stderr, "could not open file '%s'\n", fname);
  121                 exit(EXIT_FAILURE);
  122         }
  123         buf = data;
  124         while (len > 0) {
  125                 size_t wlen;
  126 
  127                 wlen = fwrite(buf, 1, len, f);
  128                 if (wlen == 0) {
  129                         fprintf(stderr, "write error in '%s'\n", fname);
  130                         exit(EXIT_FAILURE);
  131                 }
  132                 buf += wlen;
  133                 len -= wlen;
  134         }
  135         fclose(f);
  136 }
  137 
  138 static int
  139 eqstr(const char *s1, const char *s2)
  140 {
  141         for (;;) {
  142                 int c1, c2;
  143 
  144                 c1 = *s1 ++;
  145                 c2 = *s2 ++;
  146                 if (c1 >= 'A' && c1 <= 'Z') {
  147                         c1 += 'a' - 'A';
  148                 }
  149                 if (c2 >= 'A' && c2 <= 'Z') {
  150                         c2 += 'a' - 'A';
  151                 }
  152                 if (c1 != c2) {
  153                         return 0;
  154                 }
  155                 if (c1 == 0) {
  156                         return 1;
  157                 }
  158         }
  159 }
  160 
  161 static unsigned char *
  162 hextobin(const char *hex, size_t *len)
  163 {
  164         unsigned char *buf;
  165 
  166         buf = NULL;
  167         for (;;) {
  168                 const char *p;
  169                 size_t u;
  170                 int acc;
  171                 int z;
  172 
  173                 u = 0;
  174                 acc = 0;
  175                 z = 0;
  176                 for (p = hex; *p; p ++) {
  177                         int c;
  178 
  179                         c = *p;
  180                         if (c >= '0' && c <= '9') {
  181                                 c -= '0';
  182                         } else if (c >= 'A' && c <= 'F') {
  183                                 c -= ('A' - 10);
  184                         } else if (c >= 'a' && c <= 'f') {
  185                                 c -= ('a' - 10);
  186                         } else if (c == ' ' || c == ':') {
  187                                 continue;
  188                         } else {
  189                                 fprintf(stderr, "not an hexdigit: 0x%02X\n", c);
  190                                 exit(EXIT_FAILURE);
  191                         }
  192                         if (z) {
  193                                 if (buf != NULL) {
  194                                         buf[u] = (acc << 4) + c;
  195                                 }
  196                                 u ++;
  197                         } else {
  198                                 acc = c;
  199                         }
  200                         z = !z;
  201                 }
  202                 if (z) {
  203                         fprintf(stderr, "odd number of hexdigits\n");
  204                         exit(EXIT_FAILURE);
  205                 }
  206                 if (buf == NULL) {
  207                         buf = xmalloc(u);
  208                 } else {
  209                         *len = u;
  210                         return buf;
  211                 }
  212         }
  213 }
  214 
  215 static void
  216 usage(void)
  217 {
  218         fprintf(stderr,
  219 "usage: falcon command [ options ]\n");
  220         fprintf(stderr,
  221 "commands:\n");
  222         fprintf(stderr,
  223 "   sign     compute a signature\n");
  224         fprintf(stderr,
  225 "   verify   verify a signature\n");
  226         fprintf(stderr,
  227 "   keygen   generate a key pair\n");
  228         exit(EXIT_FAILURE);
  229 }
  230 
  231 static void
  232 usage_sign(void)
  233 {
  234         fprintf(stderr,
  235 "usage: falcon sign [ options ]\n"
  236 "options:\n"
  237 "   -key fname      read private key from file 'fname'\n"
  238 "   -in fname       read data from file 'fname' ('-' for standard input)\n"
  239 "   -out fname      write signature in file 'fname'\n"
  240 "   -nonce hex      use specific nonce (provided in hexadecimal)\n"
  241 "Normal output is the nonce (lowercase hexadecimal, one line) then the\n"
  242 "signature (lowercase hexadecimal, one line). If '-out' is used, only the\n"
  243 "nonce is printed on output, and the signature will be written out in\n"
  244 "binary. If '-nonce' is used, then the nonce output is suppressed.\n");
  245         exit(EXIT_FAILURE);
  246 }
  247 
  248 static void
  249 do_sign(int argc, char *argv[])
  250 {
  251         int i;
  252         const char *fname_key;
  253         const char *fname_in;
  254         const char *fname_out;
  255         const char *hexnonce;
  256         unsigned char *skey;
  257         size_t skey_len;
  258         unsigned char *nonce;
  259         size_t nonce_len;
  260         falcon_sign *fs;
  261         FILE *df;
  262         unsigned char sig[2049];
  263         size_t sig_len;
  264 
  265         fname_key = NULL;
  266         fname_in = NULL;
  267         fname_out = NULL;
  268         hexnonce = NULL;
  269         for (i = 0; i < argc; i ++) {
  270                 const char *opt;
  271 
  272                 opt = argv[i];
  273                 if (eqstr(opt, "-key")) {
  274                         if (++ i >= argc) {
  275                                 fprintf(stderr, "missing arg for '-key'\n");
  276                                 usage_sign();
  277                         }
  278                         if (fname_key != NULL) {
  279                                 fprintf(stderr, "duplicate '-key'\n");
  280                                 usage_sign();
  281                         }
  282                         fname_key = argv[i];
  283                 } else if (eqstr(opt, "-in")) {
  284                         if (++ i >= argc) {
  285                                 fprintf(stderr, "missing arg for '-in'\n");
  286                                 usage_sign();
  287                         }
  288                         if (fname_in != NULL) {
  289                                 fprintf(stderr, "duplicate '-in'\n");
  290                                 usage_sign();
  291                         }
  292                         fname_in = argv[i];
  293                 } else if (eqstr(opt, "-out")) {
  294                         if (++ i >= argc) {
  295                                 fprintf(stderr, "missing arg for '-out'\n");
  296                                 usage_sign();
  297                         }
  298                         if (fname_out != NULL) {
  299                                 fprintf(stderr, "duplicate '-out'\n");
  300                                 usage_sign();
  301                         }
  302                         fname_out = argv[i];
  303                 } else if (eqstr(opt, "-nonce")) {
  304                         if (++ i >= argc) {
  305                                 fprintf(stderr, "missing arg for '-nonce'\n");
  306                                 usage_sign();
  307                         }
  308                         if (hexnonce != NULL) {
  309                                 fprintf(stderr, "duplicate '-nonce'\n");
  310                                 usage_sign();
  311                         }
  312                         hexnonce = argv[i];
  313                 } else {
  314                         fprintf(stderr, "unknown option: '%s'\n", opt);
  315                         usage_sign();
  316                 }
  317         }
  318 
  319         if (fname_key == NULL) {
  320                 fprintf(stderr, "no private key specified\n");
  321                 usage_sign();
  322         }
  323         skey = read_file(fname_key, &skey_len);
  324         if (hexnonce != NULL) {
  325                 nonce = hextobin(hexnonce, &nonce_len);
  326         } else {
  327                 nonce = NULL;
  328         }
  329 
  330         fs = falcon_sign_new();
  331         if (fs == NULL) {
  332                 fprintf(stderr, "memory allocation error\n");
  333                 exit(EXIT_FAILURE);
  334         }
  335 
  336         if (!falcon_sign_set_private_key(fs, skey, skey_len)) {
  337                 fprintf(stderr, "error loading private key\n");
  338                 exit(EXIT_FAILURE);
  339         }
  340 
  341         /*
  342          * We get the degree from the first key byte (this is for the
  343          * 'recording' test feature).
  344          */
  345         xfree(skey);
  346 
  347         if (nonce == NULL) {
  348                 unsigned char r[40];
  349                 size_t u;
  350 
  351                 if (!falcon_sign_start(fs, r)) {
  352                         fprintf(stderr, "RNG seeding failed\n");
  353                         exit(EXIT_FAILURE);
  354                 }
  355                 for (u = 0; u < sizeof r; u ++) {
  356                         printf("%02x", r[u]);
  357                 }
  358                 printf("\n");
  359         } else {
  360                 falcon_sign_start_external_nonce(fs, nonce, nonce_len);
  361                 xfree(nonce);
  362         }
  363 
  364         /*
  365          * Read and hash data to sign.
  366          */
  367         if (fname_in != NULL) {
  368                 df = fopen(fname_in, "rb");
  369                 if (df == NULL) {
  370                         fprintf(stderr, "error opening file '%s'\n", fname_in);
  371                         exit(EXIT_FAILURE);
  372                 }
  373         } else {
  374                 df = stdin;
  375         }
  376         for (;;) {
  377                 unsigned char tmp[4096];
  378                 size_t rlen;
  379 
  380                 rlen = fread(tmp, 1, sizeof tmp, df);
  381                 if (rlen == 0) {
  382                         break;
  383                 }
  384                 falcon_sign_update(fs, tmp, rlen);
  385         }
  386         if (df != stdin) {
  387                 fclose(df);
  388         }
  389 
  390         /*
  391          * Obtain signature.
  392          */
  393         sig_len = falcon_sign_generate(fs,
  394                 sig, sizeof sig, FALCON_COMP_STATIC);
  395         if (sig_len == 0) {
  396                 fprintf(stderr, "signature failure\n");
  397                 exit(EXIT_FAILURE);
  398         }
  399 
  400         if (fname_out == NULL) {
  401                 size_t u;
  402 
  403                 for (u = 0; u < sig_len; u ++) {
  404                         printf("%02x", sig[u]);
  405                 }
  406                 printf("\n");
  407         } else {
  408                 write_file(fname_out, sig, sig_len);
  409         }
  410 
  411         falcon_sign_free(fs);
  412 }
  413 
  414 static void
  415 usage_vrfy(void)
  416 {
  417         fprintf(stderr,
  418 "usage: falcon verify [ options ]\n"
  419 "options:\n"
  420 "   -key fname      read public key from file 'fname'\n"
  421 "   -in fname       read data from file 'fname' ('-' for standard input)\n"
  422 "   -nonce hex      set nonce (provided in hexadecimal)\n"
  423 "   -sig fname      read signature from file 'fname'\n"
  424 "   -sighex hex     set signature (provided in hexadecimal)\n"
  425 "Output will be 'OK' for a valid signature, 'INVALID' for an invalid\n"
  426 "signature. The key, signature and nonce MUST be provided.\n");
  427         exit(EXIT_FAILURE);
  428 }
  429 
  430 static void
  431 do_vrfy(int argc, char *argv[])
  432 {
  433         int i;
  434         const char *fname_key;
  435         const char *fname_in;
  436         const char *fname_sig;
  437         const char *hexnonce;
  438         const char *hexsig;
  439         unsigned char *pkey;
  440         size_t pkey_len;
  441         unsigned char *nonce;
  442         size_t nonce_len;
  443         unsigned char *sig;
  444         size_t sig_len;
  445         falcon_vrfy *fv;
  446         FILE *df;
  447         int z;
  448 
  449         fname_key = NULL;
  450         fname_in = NULL;
  451         fname_sig = NULL;
  452         hexnonce = NULL;
  453         hexsig = NULL;
  454         for (i = 0; i < argc; i ++) {
  455                 const char *opt;
  456 
  457                 opt = argv[i];
  458                 if (eqstr(opt, "-key")) {
  459                         if (++ i >= argc) {
  460                                 fprintf(stderr, "missing arg for '-key'\n");
  461                                 usage_vrfy();
  462                         }
  463                         if (fname_key != NULL) {
  464                                 fprintf(stderr, "duplicate '-key'\n");
  465                                 usage_vrfy();
  466                         }
  467                         fname_key = argv[i];
  468                 } else if (eqstr(opt, "-in")) {
  469                         if (++ i >= argc) {
  470                                 fprintf(stderr, "missing arg for '-in'\n");
  471                                 usage_vrfy();
  472                         }
  473                         if (fname_in != NULL) {
  474                                 fprintf(stderr, "duplicate '-in'\n");
  475                                 usage_vrfy();
  476                         }
  477                         fname_in = argv[i];
  478                 } else if (eqstr(opt, "-sig")) {
  479                         if (++ i >= argc) {
  480                                 fprintf(stderr, "missing arg for '-sig'\n");
  481                                 usage_vrfy();
  482                         }
  483                         if (fname_sig != NULL) {
  484                                 fprintf(stderr, "duplicate '-sig'\n");
  485                                 usage_vrfy();
  486                         }
  487                         fname_sig = argv[i];
  488                 } else if (eqstr(opt, "-nonce")) {
  489                         if (++ i >= argc) {
  490                                 fprintf(stderr, "missing arg for '-nonce'\n");
  491                                 usage_vrfy();
  492                         }
  493                         if (hexnonce != NULL) {
  494                                 fprintf(stderr, "duplicate '-nonce'\n");
  495                                 usage_vrfy();
  496                         }
  497                         hexnonce = argv[i];
  498                 } else if (eqstr(opt, "-sighex")) {
  499                         if (++ i >= argc) {
  500                                 fprintf(stderr, "missing arg for '-sighex'\n");
  501                                 usage_vrfy();
  502                         }
  503                         if (hexsig != NULL) {
  504                                 fprintf(stderr, "duplicate '-sighex'\n");
  505                                 usage_vrfy();
  506                         }
  507                         hexsig = argv[i];
  508                 } else {
  509                         fprintf(stderr, "unknown option: '%s'\n", opt);
  510                         usage_vrfy();
  511                 }
  512         }
  513 
  514         if (fname_key == NULL) {
  515                 fprintf(stderr, "no public key specified\n");
  516                 usage_vrfy();
  517         }
  518         if (hexnonce == NULL) {
  519                 fprintf(stderr, "no nonce provided\n");
  520                 usage_vrfy();
  521         }
  522         if (fname_sig == NULL && hexsig == NULL) {
  523                 fprintf(stderr, "no signature provided\n");
  524                 usage_vrfy();
  525         }
  526         if (fname_sig != NULL && hexsig != NULL) {
  527                 fprintf(stderr, "two signatures provided\n");
  528                 usage_vrfy();
  529         }
  530 
  531         pkey = read_file(fname_key, &pkey_len);
  532         nonce = hextobin(hexnonce, &nonce_len);
  533         if (fname_sig != NULL) {
  534                 sig = read_file(fname_sig, &sig_len);
  535         } else {
  536                 sig = hextobin(hexsig, &sig_len);
  537         }
  538 
  539         fv = falcon_vrfy_new();
  540         if (fv == NULL) {
  541                 fprintf(stderr, "memory allocation error\n");
  542                 exit(EXIT_FAILURE);
  543         }
  544 
  545         if (!falcon_vrfy_set_public_key(fv, pkey, pkey_len)) {
  546                 fprintf(stderr, "error loading public key\n");
  547                 exit(EXIT_FAILURE);
  548         }
  549         xfree(pkey);
  550 
  551         falcon_vrfy_start(fv, nonce, nonce_len);
  552         xfree(nonce);
  553 
  554         /*
  555          * Read and hash data to sign.
  556          */
  557         if (fname_in != NULL) {
  558                 df = fopen(fname_in, "rb");
  559                 if (df == NULL) {
  560                         fprintf(stderr, "error opening file '%s'\n", fname_in);
  561                         exit(EXIT_FAILURE);
  562                 }
  563         } else {
  564                 df = stdin;
  565         }
  566         for (;;) {
  567                 unsigned char tmp[4096];
  568                 size_t rlen;
  569 
  570                 rlen = fread(tmp, 1, sizeof tmp, df);
  571                 if (rlen == 0) {
  572                         break;
  573                 }
  574                 falcon_vrfy_update(fv, tmp, rlen);
  575         }
  576         if (df != stdin) {
  577                 fclose(df);
  578         }
  579 
  580         /*
  581          * Verify signature.
  582          */
  583         z = falcon_vrfy_verify(fv, sig, sig_len);
  584         xfree(sig);
  585         falcon_vrfy_free(fv);
  586 
  587         if (z > 0) {
  588                 printf("OK\n");
  589         } else {
  590                 printf("INVALID: %d\n", z);
  591                 exit(EXIT_FAILURE);
  592         }
  593 }
  594 
  595 static void
  596 usage_keygen(void)
  597 {
  598         fprintf(stderr,
  599 "usage: falcon keygen [ options ]\n"
  600 "options:\n"
  601 "   -priv fname     write private key into file 'fname'\n"
  602 "   -pub fname      write public key into file 'fname'\n"
  603 "   -logn logn      use degree 2^logn (default is 512 = 2^9)\n"
  604 "   -logt logn      use degree 1.5*2^logn\n"
  605 "Only one of -logn and -logt may be specified.\n");
  606         exit(EXIT_FAILURE);
  607 }
  608 
  609 static void
  610 do_keygen(int argc, char *argv[])
  611 {
  612         int i;
  613         const char *fname_priv;
  614         const char *fname_pub;
  615         unsigned logn;
  616         int ternary;
  617         falcon_keygen *fk;
  618         unsigned char *privkey;
  619         size_t privkey_len;
  620         unsigned char *pubkey;
  621         size_t pubkey_len;
  622         int ret;
  623 
  624         fname_priv = NULL;
  625         fname_pub = NULL;
  626         logn = 0;
  627         ternary = 0;
  628         for (i = 0; i < argc; i ++) {
  629                 const char *opt;
  630 
  631                 opt = argv[i];
  632                 if (eqstr(opt, "-priv")) {
  633                         if (++ i >= argc) {
  634                                 fprintf(stderr, "missing arg for '-priv'\n");
  635                                 usage_keygen();
  636                         }
  637                         if (fname_priv != NULL) {
  638                                 fprintf(stderr, "duplicate '-priv'\n");
  639                                 usage_keygen();
  640                         }
  641                         fname_priv = argv[i];
  642                 } else if (eqstr(opt, "-pub")) {
  643                         if (++ i >= argc) {
  644                                 fprintf(stderr, "missing arg for '-pub'\n");
  645                                 usage_keygen();
  646                         }
  647                         if (fname_pub != NULL) {
  648                                 fprintf(stderr, "duplicate '-pub'\n");
  649                                 usage_keygen();
  650                         }
  651                         fname_pub = argv[i];
  652                 } else if (eqstr(opt, "-logn")) {
  653                         int x;
  654 
  655                         if (++ i >= argc) {
  656                                 fprintf(stderr, "missing arg for '-logn'\n");
  657                                 usage_keygen();
  658                         }
  659                         if (logn != 0) {
  660                                 fprintf(stderr, "duplicate '-logn'/'-logt'\n");
  661                                 usage_keygen();
  662                         }
  663                         x = atoi(argv[i]);
  664                         if (x < 1 || x > 10) {
  665                                 fprintf(stderr, "unsupported degree\n");
  666                                 usage_keygen();
  667                         }
  668                         logn = (unsigned)x;
  669                 } else if (eqstr(opt, "-logt")) {
  670                         int x;
  671 
  672                         if (++ i >= argc) {
  673                                 fprintf(stderr, "missing arg for '-logt'\n");
  674                                 usage_keygen();
  675                         }
  676                         if (logn != 0) {
  677                                 fprintf(stderr, "duplicate '-logn'/'-logt'\n");
  678                                 usage_keygen();
  679                         }
  680                         x = atoi(argv[i]);
  681                         if (x < 2 || x > 9) {
  682                                 fprintf(stderr, "unsupported degree\n");
  683                                 usage_keygen();
  684                         }
  685                         logn = (unsigned)x;
  686                         ternary = 1;
  687                 } else {
  688                         fprintf(stderr, "unknown option: '%s'\n", opt);
  689                         usage_keygen();
  690                 }
  691         }
  692 
  693         if (fname_priv == NULL) {
  694                 fprintf(stderr, "no output file for private key\n");
  695                 usage_keygen();
  696         }
  697 
  698         if (logn == 0) {
  699                 logn = 9;
  700         }
  701 
  702         fk = NULL;
  703         privkey = NULL;
  704         pubkey = NULL;
  705 
  706         fk = falcon_keygen_new(logn, ternary);
  707         if (fk == NULL) {
  708                 fprintf(stderr, "memory allocation error\n");
  709                 exit(EXIT_FAILURE);
  710         }
  711 
  712         privkey_len = falcon_keygen_max_privkey_size(fk);
  713         privkey = xmalloc(privkey_len);
  714         pubkey_len = falcon_keygen_max_pubkey_size(fk);
  715         pubkey = xmalloc(pubkey_len);
  716 
  717         ret = falcon_keygen_make(fk, FALCON_COMP_STATIC,
  718                 privkey, &privkey_len, pubkey, &pubkey_len);
  719         if (ret) {
  720                 write_file(fname_priv, privkey, privkey_len);
  721                 if (fname_pub != NULL) {
  722                         write_file(fname_pub, pubkey, pubkey_len);
  723                 }
  724         } else {
  725                 fprintf(stderr, "key generation failed\n");
  726         }
  727 
  728         falcon_keygen_free(fk);
  729         xfree(privkey);
  730         xfree(pubkey);
  731 
  732         if (!ret) {
  733                 exit(EXIT_FAILURE);
  734         }
  735 }
  736 
  737 int
  738 main(int argc, char *argv[])
  739 {
  740         if (argc < 2) {
  741                 usage();
  742         }
  743         if (eqstr(argv[1], "sign")) {
  744                 do_sign(argc - 2, argv + 2);
  745         } else if (eqstr(argv[1], "vrfy") || eqstr(argv[1], "verify")) {
  746                 do_vrfy(argc - 2, argv + 2);
  747         } else if (eqstr(argv[1], "keygen")) {
  748                 do_keygen(argc - 2, argv + 2);
  749         } else {
  750                 usage();
  751         }
  752         return 0;
  753 }