Add test vectors for public key generation
diff --git a/test/public_key_test_vectors.c b/test/public_key_test_vectors.c
new file mode 100644
index 0000000..a0afba8
--- /dev/null
+++ b/test/public_key_test_vectors.c
@@ -0,0 +1,338 @@
+/* Copyright 2020, Kenneth MacKay. Licensed under the BSD 2-clause license. */
+
+#include "uECC.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct {
+  const char* k;
+  const char* Q;
+  int success;
+} Test;
+
+Test secp160r1_tests[] = {
+    /* Note, I couldn't find any test vectors for secp160r1 online, so these are just
+       generated on my desktop using uECC. */
+    {
+        "000000000000000000000000000000000000000000",
+        "00000000000000000000000000000000000000000000000000000000000000000000000000000000",
+        0
+    },
+    {
+        "000000000000000000000000000000000000000001",
+        "00000000000000000000000000000000000000000000000000000000000000000000000000000000",
+        0
+    },
+    {
+        "000000000000000000000000000000000000000002",
+        "02F997F33C5ED04C55D3EDF8675D3E92E8F46686F083A323482993E9440E817E21CFB7737DF8797B",
+        1
+    },
+    {
+        "000000000000000000000000000000000000000003",
+        "7B76FF541EF363F2DF13DE1650BD48DAA958BC59C915CA790D8C8877B55BE0079D12854FFE9F6F5A",
+        1
+    },
+    {   /* n - 4 */
+        "0100000000000000000001F4C8F927AED3CA752253",
+        "B4041D8683BE99F0AFE01C307B1AD4C100CF2A88C0CD35127BE0F73FF99F338B350B5A42864112F7",
+        1
+    },
+    {   /* n - 3 */
+        "0100000000000000000001F4C8F927AED3CA752254",
+        "7B76FF541EF363F2DF13DE1650BD48DAA958BC5936EA3586F27377884AA41FF862ED7AAF816090A5",
+        1
+    },
+    {   /* n - 2 */
+        "0100000000000000000001F4C8F927AED3CA752255",
+        "00000000000000000000000000000000000000000000000000000000000000000000000000000000",
+        0
+    },
+    {   /* n - 1 */
+        "0100000000000000000001F4C8F927AED3CA752256",
+        "00000000000000000000000000000000000000000000000000000000000000000000000000000000",
+        0
+    },
+    {   /* n */
+        "0100000000000000000001F4C8F927AED3CA752257",
+        "00000000000000000000000000000000000000000000000000000000000000000000000000000000",
+        0
+    },
+};
+
+
+Test secp192r1_tests[] = {
+    {
+        "000000000000000000000000000000000000000000000000",
+        "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+        0
+    },
+    {
+        "000000000000000000000000000000000000000000000001",
+        "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF101207192B95FFC8DA78631011ED6B24CDD573F977A11E794811",
+        0
+    },
+    {
+        "000000000000000000000000000000000000000000000002",
+        "DAFEBF5828783F2AD35534631588A3F629A70FB16982A888DD6BDA0D993DA0FA46B27BBC141B868F59331AFA5C7E93AB",
+        1
+    },
+    {
+        "000000000000000000000000000000000000000000000003",
+        "76E32A2557599E6EDCD283201FB2B9AADFD0D359CBB263DA782C37E372BA4520AA62E0FED121D49EF3B543660CFD05FD",
+        1
+    },
+    {   /* n - 4 */
+        "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D2282D",
+        "35433907297CC378B0015703374729D7A4FE46647084E4BA5D9B667B0DECA3CFE15C534F88932B0DDAC764CEE24C41CD",
+        1
+    },
+    {   /* n - 3 */
+        "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D2282E",
+        "76E32A2557599E6EDCD283201FB2B9AADFD0D359CBB263DA87D3C81C8D45BADF559D1F012EDE2B600C4ABC99F302FA02",
+        1
+    },
+    {   /* n - 2 */
+        "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D2282F",
+        "DAFEBF5828783F2AD35534631588A3F629A70FB16982A888229425F266C25F05B94D8443EBE4796FA6CCE505A3816C54",
+        0
+    },
+    {   /* n - 1 */
+        "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22830",
+        "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012F8E6D46A003725879CEFEE1294DB32298C06885EE186B7EE",
+        0
+    },
+    {   /* n */
+        "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831",
+        "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+        0
+    },
+};
+
+Test secp224r1_tests[] = {
+    {
+        "00000000000000000000000000000000000000000000000000000000",
+        "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+        0
+    },
+    {
+        "00000000000000000000000000000000000000000000000000000001",
+        "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34",
+        0
+    },
+    {
+        "00000000000000000000000000000000000000000000000000000002",
+        "706A46DC76DCB76798E60E6D89474788D16DC18032D268FD1A704FA61C2B76A7BC25E7702A704FA986892849FCA629487ACF3709D2E4E8BB",
+        1
+    },
+    {
+        "00000000000000000000000000000000000000000000000000000003",
+        "DF1B1D66A551D0D31EFF822558B9D2CC75C2180279FE0D08FD896D04A3F7F03CADD0BE444C0AA56830130DDF77D317344E1AF3591981A925",
+        1
+    },
+    {   /* n - 4 */
+        "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A39",
+        "AE99FEEBB5D26945B54892092A8AEE02912930FA41CD114E40447301FB7DA7F5F13A43B81774373C879CD32D6934C05FA758EEB14FCFAB38",
+        1
+    },
+    {   /* n - 3 */
+        "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3A",
+        "DF1B1D66A551D0D31EFF822558B9D2CC75C2180279FE0D08FD896D045C080FC3522F41BBB3F55A97CFECF21F882CE8CBB1E50CA6E67E56DC",
+        1
+    },
+    {   /* n - 2 */
+        "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3B",
+        "706A46DC76DCB76798E60E6D89474788D16DC18032D268FD1A704FA6E3D4895843DA188FD58FB0567976D7B50359D6B78530C8F62D1B1746",
+        0
+    },
+    {   /* n - 1 */
+        "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3C",
+        "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D2142C89C774A08DC04B3DD201932BC8A5EA5F8B89BBB2A7E667AFF81CD",
+        0
+    },
+    {   /* n */
+        "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D",
+        "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+        0
+    },
+};
+
+Test secp256r1_tests[] = {
+    {
+        "0000000000000000000000000000000000000000000000000000000000000000",
+        "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+        0
+    },
+    {
+        "0000000000000000000000000000000000000000000000000000000000000001",
+        "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
+        0
+    },
+    {
+        "0000000000000000000000000000000000000000000000000000000000000002",
+        "7CF27B188D034F7E8A52380304B51AC3C08969E277F21B35A60B48FC4766997807775510DB8ED040293D9AC69F7430DBBA7DADE63CE982299E04B79D227873D1",
+        1
+    },
+    {
+        "0000000000000000000000000000000000000000000000000000000000000003",
+        "5ECBE4D1A6330A44C8F7EF951D4BF165E6C6B721EFADA985FB41661BC6E7FD6C8734640C4998FF7E374B06CE1A64A2ECD82AB036384FB83D9A79B127A27D5032",
+        1
+    },
+    {   /* n - 4 */
+        "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC63254D",
+        "E2534A3532D08FBBA02DDE659EE62BD0031FE2DB785596EF509302446B0308521F0EA8A4B39CC339E62011A02579D289B103693D0CF11FFAA3BD3DC0E7B12739",
+        1
+    },
+    {   /* n - 3 */
+        "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC63254E",
+        "5ECBE4D1A6330A44C8F7EF951D4BF165E6C6B721EFADA985FB41661BC6E7FD6C78CB9BF2B6670082C8B4F931E59B5D1327D54FCAC7B047C265864ED85D82AFCD",
+        1
+    },
+    {   /* n - 2 */
+        "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC63254F",
+        "7CF27B188D034F7E8A52380304B51AC3C08969E277F21B35A60B48FC47669978F888AAEE24712FC0D6C26539608BCF244582521AC3167DD661FB4862DD878C2E",
+        0
+    },
+    {   /* n - 1 */
+        "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632550",
+        "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296B01CBD1C01E58065711814B583F061E9D431CCA994CEA1313449BF97C840AE0A",
+        0
+    },
+    {   /* n */
+        "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
+        "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+        0
+    },
+};
+
+Test secp256k1_tests[] = {
+    {
+        "0000000000000000000000000000000000000000000000000000000000000000",
+        "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+        0
+    },
+    {
+        "0000000000000000000000000000000000000000000000000000000000000001",
+        "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8",
+        0
+    },
+    {
+        "0000000000000000000000000000000000000000000000000000000000000002",
+        "C6047F9441ED7D6D3045406E95C07CD85C778E4B8CEF3CA7ABAC09B95C709EE51AE168FEA63DC339A3C58419466CEAEEF7F632653266D0E1236431A950CFE52A",
+        1
+    },
+    {
+        "0000000000000000000000000000000000000000000000000000000000000003",
+        "F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9388F7B0F632DE8140FE337E62A37F3566500A99934C2231B6CB9FD7584B8E672",
+        1
+    },
+    {   /* n - 4 */
+        "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD036413D",
+        "E493DBF1C10D80F3581E4904930B1404CC6C13900EE0758474FA94ABE8C4CD13AE1266C15F2BAA48A9BD1DF6715AEBB7269851CC404201BF30168422B88C630D",
+        1
+    },
+    {   /* n - 3 */
+        "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD036413E",
+        "F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9C77084F09CD217EBF01CC819D5C80CA99AFF5666CB3DDCE4934602897B4715BD",
+        1
+    },
+    {   /* n - 2 */
+        "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD036413F",
+        "C6047F9441ED7D6D3045406E95C07CD85C778E4B8CEF3CA7ABAC09B95C709EE5E51E970159C23CC65C3A7BE6B99315110809CD9ACD992F1EDC9BCE55AF301705",
+        0
+    },
+    {   /* n - 1 */
+        "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140",
+        "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798B7C52588D95C3B9AA25B0403F1EEF75702E84BB7597AABE663B82F6F04EF2777",
+        0
+    },
+    {   /* n */
+        "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141",
+        "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+        0
+    },
+};
+
+
+void vli_print(uint8_t *vli, unsigned int size) {
+    for(unsigned i=0; i<size; ++i) {
+        printf("%02X ", (unsigned)vli[i]);
+    }
+    printf("\n");
+}
+
+void strtobytes(const char* str, uint8_t* bytes, int count) {
+  for (int c = 0; c < count; ++c) {
+    if (sscanf(str, "%2hhx", &bytes[c]) != 1) {
+      printf("Failed to read string to bytes");
+      exit(1);
+    }
+    str += 2;
+  }
+}
+
+int run(Test* tests, int num_tests, uECC_Curve curve) {
+    uint8_t private[32] = {0};
+    uint8_t public[64] = {0};
+    uint8_t expected[64] = {0};
+    int result;
+    int i;
+    int private_key_size;
+    int public_key_size;
+    int all_success = 1;
+
+    private_key_size = uECC_curve_private_key_size(curve);
+    public_key_size = uECC_curve_public_key_size(curve);
+
+    for (i = 0; i < num_tests; ++i) {
+        strtobytes(tests[i].k, private, private_key_size);
+        result = uECC_compute_public_key(private, public, curve);
+        if (result != tests[i].success) {
+            all_success = 0;
+            printf("  Got unexpected result from test %d: %d\n", i, result);
+        }
+        if (result) {
+            strtobytes(tests[i].Q, expected, public_key_size);
+            if (memcmp(public, expected, public_key_size) != 0) {
+                all_success = 0;
+                printf("  Got incorrect public key for test %d\n", i);
+                printf("    Expected: ");
+                vli_print(expected, public_key_size);
+                printf("    Calculated: ");
+                vli_print(public, public_key_size);
+            }
+        }
+    }
+
+    return all_success;
+}
+
+#define RUN_TESTS(curve) \
+    printf(#curve ":\n"); \
+    if (run(curve##_tests, sizeof(curve##_tests) / sizeof(curve##_tests[0]), uECC_##curve()) ) { \
+        printf("  All passed\n"); \
+    } else { \
+        printf("  Failed\n"); \
+    }
+
+int main() {
+#if uECC_SUPPORTS_secp160r1
+    RUN_TESTS(secp160r1)
+#endif
+#if uECC_SUPPORTS_secp192r1
+    RUN_TESTS(secp192r1)
+#endif
+#if uECC_SUPPORTS_secp224r1
+    RUN_TESTS(secp224r1)
+#endif
+#if uECC_SUPPORTS_secp256r1
+    RUN_TESTS(secp256r1)
+#endif
+#if uECC_SUPPORTS_secp256k1
+    RUN_TESTS(secp256k1)
+#endif
+
+    return 0;
+}