static int get_and_cmp_point (const char *name, const char *mpi_x_string, const char *mpi_y_string, const char *desc, gcry_ctx_t ctx) { gcry_mpi_point_t point; gcry_mpi_t x, y, z; int result = 0; point = gcry_mpi_ec_get_point (name, ctx, 1); if (!point) { fail ("error getting point parameter '%s' of curve '%s'\n", name, desc); return 1; } if (debug) print_point (name, point); x = gcry_mpi_new (0); y = gcry_mpi_new (0); z = gcry_mpi_new (0); gcry_mpi_point_snatch_get (x, y, z, point); if (cmp_mpihex (x, mpi_x_string)) { fail ("x coordinate of '%s' of curve '%s' does not match\n", name, desc); result = 1; } if (cmp_mpihex (y, mpi_y_string)) { fail ("y coordinate of '%s' of curve '%s' does not match\n", name, desc); result = 1; } if (cmp_mpihex (z, "01")) { fail ("z coordinate of '%s' of curve '%s' is not 1\n", name, desc); result = 1; } gcry_mpi_release (x); gcry_mpi_release (y); gcry_mpi_release (z); return result; }
static int get_and_cmp_mpi (const char *name, const char *mpistring, const char *desc, gcry_ctx_t ctx) { gcry_mpi_t mpi; mpi = gcry_mpi_ec_get_mpi (name, ctx, 1); if (!mpi) { fail ("error getting parameter '%s' of curve '%s'\n", name, desc); return 1; } if (debug) print_mpi (name, mpi); if (cmp_mpihex (mpi, mpistring)) { fail ("parameter '%s' of curve '%s' does not match\n", name, desc); gcry_mpi_release (mpi); return 1; } gcry_mpi_release (mpi); return 0; }
static void check_extract_param (void) { /* This sample data is a real key but with some parameters of the public key modified. */ static char sample1[] = "(key-data" " (public-key" " (ecc" " (curve Ed25519)" " (p #6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED#)" " (a #EF#)" " (b #C2036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978B6#)" " (g #14" " 216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A" " 6666666666666666666666666666666666666666666666666666666666666658#)" " (n #0000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED#)" " (q #20B37806015CA06B3AEB9423EE84A41D7F31AA65F4148553755206D679F8BF62#)" "))" " (private-key" " (ecc" " (curve Ed25519)" " (p #7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED#)" " (a #FF#)" " (b #D2036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978B6#)" " (g #04" " 216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A" " 6666666666666666666666666666666666666666666666666666666666666658#)" " (n #1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED#)" " (q #30B37806015CA06B3AEB9423EE84A41D7F31AA65F4148553755206D679F8BF62#)" " (d #56BEA284A22F443A7AEA8CEFA24DA5055CDF1D490C94D8C568FE0802C9169276#)" ")))"; static char sample1_p[] = "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED"; static char sample1_px[] = "6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED"; static char sample1_a[] = "FF"; static char sample1_ax[] = "EF"; static char sample1_b[] = "D2036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978B6"; static char sample1_bx[] = "C2036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978B6"; static char sample1_g[] = "04" "216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A" "6666666666666666666666666666666666666666666666666666666666666658"; static char sample1_gx[] = "14" "216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A" "6666666666666666666666666666666666666666666666666666666666666658"; static char sample1_n[] = "1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED"; static char sample1_nx[] = "0000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED"; static char sample1_q[] = "30B37806015CA06B3AEB9423EE84A41D7F31AA65F4148553755206D679F8BF62"; static char sample1_qx[] = "20B37806015CA06B3AEB9423EE84A41D7F31AA65F4148553755206D679F8BF62"; static char sample1_d[] = "56BEA284A22F443A7AEA8CEFA24DA5055CDF1D490C94D8C568FE0802C9169276"; static struct { const char *sexp_str; const char *path; const char *list; int nparam; gpg_err_code_t expected_err; const char *exp_p; const char *exp_a; const char *exp_b; const char *exp_g; const char *exp_n; const char *exp_q; const char *exp_d; } tests[] = { { sample1, NULL, "pabgnqd", 6, GPG_ERR_MISSING_VALUE, }, { sample1, NULL, "pabgnq", 7, GPG_ERR_INV_ARG }, { sample1, NULL, "pab'gnq", 7, GPG_ERR_SYNTAX }, { sample1, NULL, "pab''gnq", 7, GPG_ERR_SYNTAX }, { sample1, NULL, "pabgnqd", 7, 0, sample1_px, sample1_ax, sample1_bx, sample1_gx, sample1_nx, sample1_qx, sample1_d }, { sample1, NULL, " pab\tg nq\nd ", 7, 0, sample1_px, sample1_ax, sample1_bx, sample1_gx, sample1_nx, sample1_qx, sample1_d }, { sample1, NULL, "abg", 3, 0, sample1_ax, sample1_bx, sample1_gx }, { sample1, NULL, "ab'g'", 3, 0, sample1_ax, sample1_bx, sample1_gx }, { sample1, NULL, "x?abg", 4, 0, NULL, sample1_ax, sample1_bx, sample1_gx }, { sample1, NULL, "p?abg", 4, GPG_ERR_USER_1, NULL, sample1_ax, sample1_bx, sample1_gx }, { sample1, NULL, "pax?gnqd", 7, 0, sample1_px, sample1_ax, NULL, sample1_gx, sample1_nx, sample1_qx, sample1_d }, { sample1, "public-key", "pabgnqd", 7, GPG_ERR_NO_OBJ, /* d is not in public key. */ sample1_px, sample1_ax, sample1_bx, sample1_gx, sample1_nx, sample1_qx, sample1_d }, { sample1, "private-key", "pabgnqd", 7, 0, sample1_p, sample1_a, sample1_b, sample1_g, sample1_n, sample1_q, sample1_d }, { sample1, "public-key!ecc", "pabgnq", 6, 0, sample1_px, sample1_ax, sample1_bx, sample1_gx, sample1_nx, sample1_qx }, { sample1, "public-key!ecc!foo", "pabgnq", 6, GPG_ERR_NOT_FOUND }, { sample1, "public-key!!ecc", "pabgnq", 6, GPG_ERR_NOT_FOUND }, { sample1, "private-key", "pa/bgnqd", 7, 0, sample1_p, sample1_a, sample1_b, sample1_g, sample1_n, sample1_q, sample1_d }, { sample1, "private-key", "p-a+bgnqd", 7, 0, sample1_p, "-01", sample1_b, sample1_g, sample1_n, sample1_q, sample1_d }, {NULL} }; int idx, i; const char *paramstr; int paramidx; gpg_error_t err; gcry_sexp_t sxp; gcry_mpi_t mpis[7]; gcry_buffer_t ioarray[7]; char iobuffer[200]; info ("checking gcry_sexp_extract_param\n"); for (idx=0; tests[idx].sexp_str; idx++) { err = gcry_sexp_new (&sxp, tests[idx].sexp_str, 0, 1); if (err) die ("converting string to sexp failed: %s", gpg_strerror (err)); memset (mpis, 0, sizeof mpis); switch (tests[idx].nparam) { case 0: err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list, NULL); break; case 1: err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list, mpis+0, NULL); break; case 2: err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list, mpis+0, mpis+1, NULL); break; case 3: err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list, mpis+0, mpis+1, mpis+2, NULL); break; case 4: err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list, mpis+0, mpis+1, mpis+2, mpis+3, NULL); break; case 5: err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list, mpis+0, mpis+1, mpis+2, mpis+3, mpis+4, NULL); break; case 6: err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list, mpis+0, mpis+1, mpis+2, mpis+3, mpis+4, mpis+5, NULL); break; case 7: err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list, mpis+0, mpis+1, mpis+2, mpis+3, mpis+4, mpis+5, mpis+6, NULL); break; default: die ("test %d: internal error", idx); } if (tests[idx].expected_err && tests[idx].expected_err != GPG_ERR_USER_1) { if (tests[idx].expected_err != gpg_err_code (err)) fail ("gcry_sexp_extract_param test %d failed: " "expected error '%s' - got '%s'", idx, gpg_strerror (tests[idx].expected_err),gpg_strerror (err)); } else if (err) { fail ("gcry_sexp_extract_param test %d failed: %s", idx, gpg_strerror (err)); } else /* No error - check the extracted values. */ { for (paramidx=0; paramidx < DIM (mpis); paramidx++) { switch (paramidx) { case 0: paramstr = tests[idx].exp_p; break; case 1: paramstr = tests[idx].exp_a; break; case 2: paramstr = tests[idx].exp_b; break; case 3: paramstr = tests[idx].exp_g; break; case 4: paramstr = tests[idx].exp_n; break; case 5: paramstr = tests[idx].exp_q; break; case 6: paramstr = tests[idx].exp_d; break; default: die ("test %d: internal error: bad param %d", idx, paramidx); } if (tests[idx].expected_err == GPG_ERR_USER_1 && mpis[paramidx] && !paramstr && paramidx == 0) ; /* Okay Special case error for param 0. */ else if (!mpis[paramidx] && !paramstr) ; /* Okay. */ else if (!mpis[paramidx] && paramstr) fail ("test %d: value for param %d expected but not returned", idx, paramidx); else if (mpis[paramidx] && !paramstr) fail ("test %d: value for param %d not expected", idx, paramidx); else if (cmp_mpihex (mpis[paramidx], paramstr)) { fail ("test %d: param %d mismatch", idx, paramidx); gcry_log_debug ("expected: %s\n", paramstr); gcry_log_debugmpi (" got", mpis[paramidx]); } else if (tests[idx].expected_err && paramidx == 0) fail ("test %d: param %d: expected error '%s' - got 'Success'", idx, paramidx, gpg_strerror (tests[idx].expected_err)); } } for (i=0; i < DIM (mpis); i++) gcry_mpi_release (mpis[i]); gcry_sexp_release (sxp); } info ("checking gcry_sexp_extract_param/desc\n"); memset (ioarray, 0, sizeof ioarray); err = gcry_sexp_new (&sxp, sample1, 0, 1); if (err) die ("converting string to sexp failed: %s", gpg_strerror (err)); ioarray[1].size = sizeof iobuffer; ioarray[1].data = iobuffer; ioarray[1].off = 0; ioarray[2].size = sizeof iobuffer; ioarray[2].data = iobuffer; ioarray[2].off = 50; assert (ioarray[2].off < sizeof iobuffer); err = gcry_sexp_extract_param (sxp, "key-data!private-key", "&pab", ioarray+0, ioarray+1, ioarray+2, NULL); if (err) fail ("gcry_sexp_extract_param with desc failed: %s", gpg_strerror (err)); else { if (!ioarray[0].data) fail ("gcry_sexp_extract_param/desc failed: no P"); else if (ioarray[0].size != 32) fail ("gcry_sexp_extract_param/desc failed: P has wrong size"); else if (ioarray[0].len != 32) fail ("gcry_sexp_extract_param/desc failed: P has wrong length"); else if (ioarray[0].off) fail ("gcry_sexp_extract_param/desc failed: P has OFF set"); else if (cmp_bufhex (ioarray[0].data, ioarray[0].len, sample1_p)) { fail ("gcry_sexp_extract_param/desc failed: P mismatch"); gcry_log_debug ("expected: %s\n", sample1_p); gcry_log_debughex (" got", ioarray[0].data, ioarray[0].len); } if (!ioarray[1].data) fail ("gcry_sexp_extract_param/desc failed: A buffer lost"); else if (ioarray[1].size != sizeof iobuffer) fail ("gcry_sexp_extract_param/desc failed: A size changed"); else if (ioarray[1].off != 0) fail ("gcry_sexp_extract_param/desc failed: A off changed"); else if (ioarray[1].len != 1) fail ("gcry_sexp_extract_param/desc failed: A has wrong length"); else if (cmp_bufhex ((char *)ioarray[1].data + ioarray[1].off, ioarray[1].len, sample1_a)) { fail ("gcry_sexp_extract_param/desc failed: A mismatch"); gcry_log_debug ("expected: %s\n", sample1_a); gcry_log_debughex (" got", (char *)ioarray[1].data + ioarray[1].off, ioarray[1].len); } if (!ioarray[2].data) fail ("gcry_sexp_extract_param/desc failed: B buffer lost"); else if (ioarray[2].size != sizeof iobuffer) fail ("gcry_sexp_extract_param/desc failed: B size changed"); else if (ioarray[2].off != 50) fail ("gcry_sexp_extract_param/desc failed: B off changed"); else if (ioarray[2].len != 32) fail ("gcry_sexp_extract_param/desc failed: B has wrong length"); else if (cmp_bufhex ((char *)ioarray[2].data + ioarray[2].off, ioarray[2].len, sample1_b)) { fail ("gcry_sexp_extract_param/desc failed: B mismatch"); gcry_log_debug ("expected: %s\n", sample1_b); gcry_log_debughex (" got", (char *)ioarray[2].data + ioarray[2].off, ioarray[2].len); } xfree (ioarray[0].data); } gcry_sexp_release (sxp); info ("checking gcry_sexp_extract_param long name\n"); memset (ioarray, 0, sizeof ioarray); memset (mpis, 0, sizeof mpis); err = gcry_sexp_new (&sxp, sample1, 0, 1); if (err) die ("converting string to sexp failed: %s", gpg_strerror (err)); err = gcry_sexp_extract_param (sxp, "key-data!private-key", "&'curve'+p", ioarray+0, mpis+0, NULL); if (err) fail ("gcry_sexp_extract_param long name failed: %s", gpg_strerror (err)); if (!ioarray[0].data) fail ("gcry_sexp_extract_param long name failed: no curve"); else if (ioarray[0].size != 7) fail ("gcry_sexp_extract_param long name failed: curve has wrong size"); else if (ioarray[0].len != 7) fail ("gcry_sexp_extract_param long name failed: curve has wrong length"); else if (ioarray[0].off) fail ("gcry_sexp_extract_param long name failed: curve has OFF set"); else if (strncmp (ioarray[0].data, "Ed25519", 7)) { fail ("gcry_sexp_extract_param long name failed: curve mismatch"); gcry_log_debug ("expected: %s\n", "Ed25519"); gcry_log_debug (" got: %.*s\n", (int)ioarray[0].len, (char*)ioarray[0].data); } if (!mpis[0]) fail ("gcry_sexp_extract_param long name failed: p not returned"); else if (cmp_mpihex (mpis[0], sample1_p)) { fail ("gcry_sexp_extract_param long name failed: p mismatch"); gcry_log_debug ("expected: %s\n", sample1_p); gcry_log_debugmpi (" got", mpis[0]); } gcry_free (ioarray[0].data); gcry_mpi_release (mpis[0]); gcry_sexp_release (sxp); }
/* This is the same as basic_ec_math but uses more advanced features. */ static void basic_ec_math_simplified (void) { gpg_error_t err; gcry_ctx_t ctx; gcry_mpi_point_t G, Q; gcry_mpi_t d; gcry_mpi_t x, y, z; gcry_sexp_t sexp; wherestr = "basic_ec_math_simplified"; show ("checking basic math functions for EC (variant)\n"); d = hex2mpi ("D4EF27E32F8AD8E2A1C6DDEBB1D235A69E3CEF9BCE90273D"); Q = gcry_mpi_point_new (0); err = gcry_mpi_ec_new (&ctx, NULL, "NIST P-192"); if (err) die ("gcry_mpi_ec_new failed: %s\n", gpg_strerror (err)); G = gcry_mpi_ec_get_point ("g", ctx, 1); if (!G) die ("gcry_mpi_ec_get_point(G) failed\n"); gcry_mpi_ec_mul (Q, d, G, ctx); x = gcry_mpi_new (0); y = gcry_mpi_new (0); z = gcry_mpi_new (0); gcry_mpi_point_get (x, y, z, Q); if (cmp_mpihex (x, "222D9EC717C89D047E0898C9185B033CD11C0A981EE6DC66") || cmp_mpihex (y, "605DE0A82D70D3E0F84A127D0739ED33D657DF0D054BFDE8") || cmp_mpihex (z, "00B06B519071BC536999AC8F2D3934B3C1FC9EACCD0A31F88F")) fail ("computed public key does not match\n"); if (debug) { print_mpi ("Q.x", x); print_mpi ("Q.y", y); print_mpi ("Q.z", z); } if (gcry_mpi_ec_get_affine (x, y, Q, ctx)) fail ("failed to get affine coordinates\n"); if (cmp_mpihex (x, "008532093BA023F4D55C0424FA3AF9367E05F309DC34CDC3FE") || cmp_mpihex (y, "00C13CA9E617C6C8487BFF6A726E3C4F277913D97117939966")) fail ("computed affine coordinates of public key do not match\n"); if (debug) { print_mpi ("q.x", x); print_mpi ("q.y", y); } gcry_mpi_release (z); gcry_mpi_release (y); gcry_mpi_release (x); /* Let us also check wheer we can update the context. */ err = gcry_mpi_ec_set_point ("g", G, ctx); if (err) die ("gcry_mpi_ec_set_point(G) failed\n"); err = gcry_mpi_ec_set_mpi ("d", d, ctx); if (err) die ("gcry_mpi_ec_set_mpi(d) failed\n"); /* FIXME: Below we need to check that the returned S-expression is as requested. For now we use manual inspection using --debug. */ /* Does get_sexp return the private key? */ err = gcry_pubkey_get_sexp (&sexp, 0, ctx); if (err) fail ("gcry_pubkey_get_sexp(0) failed: %s\n", gpg_strerror (err)); else if (verbose) print_sexp ("Result of gcry_pubkey_get_sexp (0):\n", sexp); gcry_sexp_release (sexp); /* Does get_sexp return the public key if requested? */ err = gcry_pubkey_get_sexp (&sexp, GCRY_PK_GET_PUBKEY, ctx); if (err) fail ("gcry_pubkey_get_sexp(GET_PUBKEY) failed: %s\n", gpg_strerror (err)); else if (verbose) print_sexp ("Result of gcry_pubkey_get_sexp (GET_PUBKEY):\n", sexp); gcry_sexp_release (sexp); /* Does get_sexp return the public key if after d has been deleted? */ err = gcry_mpi_ec_set_mpi ("d", NULL, ctx); if (err) die ("gcry_mpi_ec_set_mpi(d=NULL) failed\n"); err = gcry_pubkey_get_sexp (&sexp, 0, ctx); if (err) fail ("gcry_pubkey_get_sexp(0 w/o d) failed: %s\n", gpg_strerror (err)); else if (verbose) print_sexp ("Result of gcry_pubkey_get_sexp (0 w/o d):\n", sexp); gcry_sexp_release (sexp); /* Does get_sexp return an error after d has been deleted? */ err = gcry_pubkey_get_sexp (&sexp, GCRY_PK_GET_SECKEY, ctx); if (gpg_err_code (err) != GPG_ERR_NO_SECKEY) fail ("gcry_pubkey_get_sexp(GET_SECKEY) returned wrong error: %s\n", gpg_strerror (err)); gcry_sexp_release (sexp); /* Does get_sexp return an error after d and Q have been deleted? */ err = gcry_mpi_ec_set_point ("q", NULL, ctx); if (err) die ("gcry_mpi_ec_set_point(q=NULL) failed\n"); err = gcry_pubkey_get_sexp (&sexp, 0, ctx); if (gpg_err_code (err) != GPG_ERR_BAD_CRYPT_CTX) fail ("gcry_pubkey_get_sexp(0 w/o Q,d) returned wrong error: %s\n", gpg_strerror (err)); gcry_sexp_release (sexp); gcry_mpi_point_release (Q); gcry_mpi_release (d); gcry_mpi_point_release (G); gcry_ctx_release (ctx); }
/* This tests checks that the low-level EC API yields the same result as using the high level API. The values have been taken from a test run using the high level API. */ static void basic_ec_math (void) { gpg_error_t err; gcry_ctx_t ctx; gcry_mpi_t P, A; gcry_mpi_point_t G, Q; gcry_mpi_t d; gcry_mpi_t x, y, z; wherestr = "basic_ec_math"; show ("checking basic math functions for EC\n"); P = hex2mpi ("0xfffffffffffffffffffffffffffffffeffffffffffffffff"); A = hex2mpi ("0xfffffffffffffffffffffffffffffffefffffffffffffffc"); G = make_point ("188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012", "7192B95FFC8DA78631011ED6B24CDD573F977A11E794811", "1"); d = hex2mpi ("D4EF27E32F8AD8E2A1C6DDEBB1D235A69E3CEF9BCE90273D"); Q = gcry_mpi_point_new (0); err = ec_p_new (&ctx, P, A); if (err) die ("ec_p_new failed: %s\n", gpg_strerror (err)); x = gcry_mpi_new (0); y = gcry_mpi_new (0); z = gcry_mpi_new (0); { /* A quick check that multiply by zero works. */ gcry_mpi_t tmp; tmp = gcry_mpi_new (0); gcry_mpi_ec_mul (Q, tmp, G, ctx); gcry_mpi_release (tmp); gcry_mpi_point_get (x, y, z, Q); if (gcry_mpi_cmp_ui (x, 0) || gcry_mpi_cmp_ui (y, 0) || gcry_mpi_cmp_ui (z, 0)) fail ("multiply a point by zero failed\n"); } gcry_mpi_ec_mul (Q, d, G, ctx); gcry_mpi_point_get (x, y, z, Q); if (cmp_mpihex (x, "222D9EC717C89D047E0898C9185B033CD11C0A981EE6DC66") || cmp_mpihex (y, "605DE0A82D70D3E0F84A127D0739ED33D657DF0D054BFDE8") || cmp_mpihex (z, "00B06B519071BC536999AC8F2D3934B3C1FC9EACCD0A31F88F")) fail ("computed public key does not match\n"); if (debug) { print_mpi ("Q.x", x); print_mpi ("Q.y", y); print_mpi ("Q.z", z); } if (gcry_mpi_ec_get_affine (x, y, Q, ctx)) fail ("failed to get affine coordinates\n"); if (cmp_mpihex (x, "008532093BA023F4D55C0424FA3AF9367E05F309DC34CDC3FE") || cmp_mpihex (y, "00C13CA9E617C6C8487BFF6A726E3C4F277913D97117939966")) fail ("computed affine coordinates of public key do not match\n"); if (debug) { print_mpi ("q.x", x); print_mpi ("q.y", y); } gcry_mpi_release (z); gcry_mpi_release (y); gcry_mpi_release (x); gcry_mpi_point_release (Q); gcry_mpi_release (d); gcry_mpi_point_release (G); gcry_mpi_release (A); gcry_mpi_release (P); gcry_ctx_release (ctx); }
/* Check the math used with Twisted Edwards curves. */ static void twistededwards_math (void) { gpg_error_t err; gcry_ctx_t ctx; gcry_mpi_point_t G, Q; gcry_mpi_t k; gcry_mpi_t w, a, x, y, z, p, n, b, I; wherestr = "twistededwards_math"; show ("checking basic Twisted Edwards math\n"); err = gcry_mpi_ec_new (&ctx, NULL, "Ed25519"); if (err) die ("gcry_mpi_ec_new failed: %s\n", gpg_strerror (err)); k = hex2mpi ("2D3501E723239632802454EE5DDC406EFB0BDF18486A5BDE9C0390A9C2984004" "F47252B628C953625B8DEB5DBCB8DA97AA43A1892D11FA83596F42E0D89CB1B6"); G = gcry_mpi_ec_get_point ("g", ctx, 1); if (!G) die ("gcry_mpi_ec_get_point(G) failed\n"); Q = gcry_mpi_point_new (0); w = gcry_mpi_new (0); a = gcry_mpi_new (0); x = gcry_mpi_new (0); y = gcry_mpi_new (0); z = gcry_mpi_new (0); I = gcry_mpi_new (0); p = gcry_mpi_ec_get_mpi ("p", ctx, 1); n = gcry_mpi_ec_get_mpi ("n", ctx, 1); b = gcry_mpi_ec_get_mpi ("b", ctx, 1); /* Check: 2^{p-1} mod p == 1 */ gcry_mpi_sub_ui (a, p, 1); gcry_mpi_powm (w, GCRYMPI_CONST_TWO, a, p); if (gcry_mpi_cmp_ui (w, 1)) fail ("failed assertion: 2^{p-1} mod p == 1\n"); /* Check: p % 4 == 1 */ gcry_mpi_mod (w, p, GCRYMPI_CONST_FOUR); if (gcry_mpi_cmp_ui (w, 1)) fail ("failed assertion: p % 4 == 1\n"); /* Check: 2^{n-1} mod n == 1 */ gcry_mpi_sub_ui (a, n, 1); gcry_mpi_powm (w, GCRYMPI_CONST_TWO, a, n); if (gcry_mpi_cmp_ui (w, 1)) fail ("failed assertion: 2^{n-1} mod n == 1\n"); /* Check: b^{(p-1)/2} mod p == p-1 */ gcry_mpi_sub_ui (a, p, 1); gcry_mpi_div (x, NULL, a, GCRYMPI_CONST_TWO, -1); gcry_mpi_powm (w, b, x, p); gcry_mpi_abs (w); if (gcry_mpi_cmp (w, a)) fail ("failed assertion: b^{(p-1)/2} mod p == p-1\n"); /* I := 2^{(p-1)/4} mod p */ gcry_mpi_sub_ui (a, p, 1); gcry_mpi_div (x, NULL, a, GCRYMPI_CONST_FOUR, -1); gcry_mpi_powm (I, GCRYMPI_CONST_TWO, x, p); /* Check: I^2 mod p == p-1 */ gcry_mpi_powm (w, I, GCRYMPI_CONST_TWO, p); if (gcry_mpi_cmp (w, a)) fail ("failed assertion: I^2 mod p == p-1\n"); /* Check: G is on the curve */ if (!gcry_mpi_ec_curve_point (G, ctx)) fail ("failed assertion: G is on the curve\n"); /* Check: nG == (0,1) */ gcry_mpi_ec_mul (Q, n, G, ctx); if (gcry_mpi_ec_get_affine (x, y, Q, ctx)) fail ("failed to get affine coordinates\n"); if (gcry_mpi_cmp_ui (x, 0) || gcry_mpi_cmp_ui (y, 1)) fail ("failed assertion: nG == (0,1)\n"); /* Now two arbitrary point operations taken from the ed25519.py sample data. */ gcry_mpi_release (a); a = hex2mpi ("4f71d012df3c371af3ea4dc38385ca5bb7272f90cb1b008b3ed601c76de1d496" "e30cbf625f0a756a678d8f256d5325595cccc83466f36db18f0178eb9925edd3"); gcry_mpi_ec_mul (Q, a, G, ctx); if (gcry_mpi_ec_get_affine (x, y, Q, ctx)) fail ("failed to get affine coordinates\n"); if (cmp_mpihex (x, ("157f7361c577aad36f67ed33e38dc7be" "00014fecc2165ca5cee9eee19fe4d2c1")) || cmp_mpihex (y, ("5a69dbeb232276b38f3f5016547bb2a2" "4025645f0b820e72b8cad4f0a909a092"))) { fail ("sample point multiply failed:\n"); print_mpi ("r", a); print_mpi ("Rx", x); print_mpi ("Ry", y); } gcry_mpi_release (a); a = hex2mpi ("2d3501e723239632802454ee5ddc406efb0bdf18486a5bde9c0390a9c2984004" "f47252b628c953625b8deb5dbcb8da97aa43a1892d11fa83596f42e0d89cb1b6"); gcry_mpi_ec_mul (Q, a, G, ctx); if (gcry_mpi_ec_get_affine (x, y, Q, ctx)) fail ("failed to get affine coordinates\n"); if (cmp_mpihex (x, ("6218e309d40065fcc338b3127f468371" "82324bd01ce6f3cf81ab44e62959c82a")) || cmp_mpihex (y, ("5501492265e073d874d9e5b81e7f8784" "8a826e80cce2869072ac60c3004356e5"))) { fail ("sample point multiply failed:\n"); print_mpi ("r", a); print_mpi ("Rx", x); print_mpi ("Ry", y); } gcry_mpi_release (I); gcry_mpi_release (b); gcry_mpi_release (n); gcry_mpi_release (p); gcry_mpi_release (w); gcry_mpi_release (a); gcry_mpi_release (x); gcry_mpi_release (y); gcry_mpi_release (z); gcry_mpi_point_release (Q); gcry_mpi_point_release (G); gcry_mpi_release (k); gcry_ctx_release (ctx); }