>From 78ba3eb4ade2ee671c6ae0a06b0153979fa77a46 Mon Sep 17 00:00:00 2001
From: Nikos Mavrogiannopoulos <nmav@gnutls.org>
Date: Sun, 14 Aug 2011 09:48:46 +0200
Subject: [PATCH] Added ECC

---
 Makefile.in                  |    9 ++-
 ecc.h                        |  131 ++++++++++++++++++++++++
 ecc_curves.c                 |   68 ++++++++++++
 ecc_free.c                   |   46 +++++++++
 ecc_make_key.c               |  154 ++++++++++++++++++++++++++++
 ecc_map.c                    |   78 ++++++++++++++
 ecc_mulmod.c                 |  191 +++++++++++++++++++++++++++++++++++
 ecc_points.c                 |   69 +++++++++++++
 ecc_projective_add_point.c   |  230 ++++++++++++++++++++++++++++++++++++++++++
 ecc_projective_dbl_point.c   |  208 ++++++++++++++++++++++++++++++++++++++
 ecc_projective_dbl_point_3.c |  156 ++++++++++++++++++++++++++++
 ecc_shared_secret.c          |   93 +++++++++++++++++
 ecc_sign_hash.c              |  116 +++++++++++++++++++++
 ecc_verify_hash.c            |  158 +++++++++++++++++++++++++++++
 nettle.texinfo               |   75 ++++++++++++++-
 testsuite/Makefile.in        |    2 +-
 testsuite/ecc-test.c         |  153 ++++++++++++++++++++++++++++
 17 files changed, 1933 insertions(+), 4 deletions(-)
 create mode 100644 ecc.h
 create mode 100644 ecc_curves.c
 create mode 100644 ecc_free.c
 create mode 100644 ecc_make_key.c
 create mode 100644 ecc_map.c
 create mode 100644 ecc_mulmod.c
 create mode 100644 ecc_points.c
 create mode 100644 ecc_projective_add_point.c
 create mode 100644 ecc_projective_dbl_point.c
 create mode 100644 ecc_projective_dbl_point_3.c
 create mode 100644 ecc_shared_secret.c
 create mode 100644 ecc_sign_hash.c
 create mode 100644 ecc_verify_hash.c
 create mode 100644 testsuite/ecc-test.c

diff --git a/Makefile.in b/Makefile.in
index 3bd8c4f..2f77c66 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -103,7 +103,12 @@ hogweed_SOURCES = sexp.c sexp-format.c \
 		  dsa-sha256-sign.c dsa-sha256-verify.c  \
 		  dsa2sexp.c sexp2dsa.c \
 		  pgp-encode.c rsa2openpgp.c \
-		  der-iterator.c der2rsa.c der2dsa.c
+		  der-iterator.c der2rsa.c der2dsa.c \
+		  ecc_free.c ecc_make_key.c ecc_map.c \
+		  ecc_mulmod.c ecc_points.c ecc_projective_add_point.c \
+		  ecc_projective_dbl_point_3.c ecc_projective_dbl_point.c \
+		  ecc_shared_secret.c ecc_sign_hash.c ecc_verify_hash.c \
+		  ecc_curves.c
 
 HEADERS = aes.h arcfour.h arctwo.h asn1.h bignum.h blowfish.h \
 	  base16.h base64.h buffer.h camellia.h cast128.h \
@@ -119,7 +124,7 @@ HEADERS = aes.h arcfour.h arctwo.h asn1.h bignum.h blowfish.h \
 	  pgp.h pkcs1.h realloc.h rsa.h rsa-compat.h \
 	  sexp.h \
 	  serpent.h sha.h twofish.h \
-	  yarrow.h
+	  yarrow.h ecc.h
 
 INSTALL_HEADERS = $(HEADERS) nettle-stdint.h
 
diff --git a/ecc.h b/ecc.h
new file mode 100644
index 0000000..c510740
--- /dev/null
+++ b/ecc.h
@@ -0,0 +1,131 @@
+#include <gmp.h>
+#include <nettle/nettle-types.h>
+#include <nettle/dsa.h>
+#include <nettle/bignum.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+
+/* assume curve is y^2 = x^3 - 3x + b
+ * instead of the generic y^2 = x^3 + ax + b
+ *
+ * (XXX: the generic case has been tested only
+ *  with the SECG curves.)
+ */
+#define ECC_SECP_CURVES_ONLY
+
+#define PK_PRIVATE 1
+#define PK_PUBLIC 2
+
+/* ---- ECC Routines ---- */
+/* size of our temp buffers for exported keys */
+#define ECC_BUF_SIZE 512
+
+/* max private key size */
+#define ECC_MAXSIZE  66
+
+/** Structure defines a NIST GF(p) curve */
+typedef struct {
+   /** The size of the curve in octets */
+   int size;
+
+   /** name of curve */
+   const char *name; 
+   
+   /** curve's OID */
+   const char *oid;
+
+   /** The prime that defines the field the curve is in (encoded in hex) */
+   const char *prime;
+
+   /** The fields A param (hex) */
+   const char *A;
+
+   /** The fields B param (hex) */
+   const char *B;
+
+   /** The order of the curve (hex) */
+   const char *order;
+  
+   /** The x co-ordinate of the base point on the curve (hex) */
+   const char *Gx;
+ 
+   /** The y co-ordinate of the base point on the curve (hex) */
+   const char *Gy;
+} ecc_set_type;
+
+/** A point on a ECC curve, stored in Jacbobian format such that (x,y,z) => (x/z^2, y/z^3, 1) when interpretted as affine */
+typedef struct {
+    /** The x co-ordinate */
+    mpz_t x;
+
+    /** The y co-ordinate */
+    mpz_t y;
+
+    /** The z co-ordinate */
+    mpz_t z;
+} ecc_point;
+
+/** An ECC key */
+typedef struct {
+    /** Type of key, PK_PRIVATE or PK_PUBLIC */
+    int type;
+
+    mpz_t prime;
+    mpz_t order;
+    mpz_t A;
+    mpz_t Gx;
+    mpz_t Gy;
+
+    /** The public key */
+    ecc_point pubkey;
+
+    /** The private key */
+    mpz_t k;
+} ecc_key;
+
+/* supported curves */
+const ecc_set_type ecc_curves_secp[];
+
+/* Key generation */
+int ecc_make_key(void *random_ctx, nettle_random_func random, ecc_key *key, const ecc_set_type *dp);
+int ecc_make_key_ex(void *random_ctx, nettle_random_func random, ecc_key *key, mpz_t prime, mpz_t order, mpz_t A, mpz_t Gx, mpz_t Gy);
+void ecc_free(ecc_key *key);
+
+/* EC-Diffie-Hellman */
+int  ecc_shared_secret(ecc_key *private_key, ecc_key *public_key, 
+                       unsigned char *out, unsigned long *outlen);
+
+/* ECDSA */
+int ecc_sign_hash(const unsigned char *in,  unsigned long inlen, 
+                        struct dsa_signature *signature,
+                        void *random_ctx, nettle_random_func random, ecc_key *key);
+
+int  ecc_verify_hash(struct dsa_signature * signature,
+                     const unsigned char *hash, unsigned long hashlen, 
+                     int *stat, ecc_key *key);
+
+/* (Internal) low level functions */
+ecc_point *ecc_new_point(void);
+void       ecc_del_point(ecc_point *p);
+
+/* point ops (mp == montgomery digit) */
+/* R = 2P */
+int ecc_projective_dbl_point(ecc_point *P, ecc_point *R, mpz_t a,  mpz_t modulus);
+
+/* R = P + Q */
+int ecc_projective_add_point(ecc_point *P, ecc_point *Q, ecc_point *R, mpz_t A, mpz_t modulus);
+
+/* R = kG */
+int ecc_mulmod(mpz_t k, ecc_point *G, ecc_point *R, mpz_t a, mpz_t modulus, int map);
+
+/* map P to affine from projective */
+int ecc_map(ecc_point *P, mpz_t modulus);
+
+/* helper functions */
+int mp_init_multi(mpz_t *a, ...);
+void mp_clear_multi(mpz_t *a, ...);
+#define mp_isodd(a)                  (mpz_size(a) > 0 ? (mpz_getlimbn(a, 0) & 1 ? 1 : 0) : 0)
+
+#define MP_DIGIT_BIT (sizeof(mp_limb_t) * 8 - GMP_NAIL_BITS)
diff --git a/ecc_curves.c b/ecc_curves.c
new file mode 100644
index 0000000..309fe7b
--- /dev/null
+++ b/ecc_curves.c
@@ -0,0 +1,68 @@
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2011 Nikos Mavrogiannopoulos
+ *  
+ * The nettle library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ * 
+ * The nettle library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#include "ecc.h"
+
+const ecc_set_type ecc_curves_secp[] = {
+{
+    .name = "SECP224R1", 
+    .oid = "1.3.132.0.33",
+    .size = 28,
+    .prime = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001",
+    .A = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE",
+    .B = "B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4",
+    .order = "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D",
+    .Gx =    "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21",
+    .Gy =    "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34",
+},
+{
+    .name = "SECP256R1", 
+    .oid = "1.2.840.10045.3.1.7",
+    .size = 32,
+    .prime = "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
+    .A = "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
+    .B = "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
+    .order = "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
+    .Gx = "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
+    .Gy = "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
+},
+{
+    .name = "SECP384R1",
+    .oid = "1.3.132.0.34",
+    .size = 48,
+    .prime = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF",
+    .A = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC",
+    .B = "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF",
+    .order = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973",
+    .Gx = "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7",
+    .Gy = "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F"
+},
+{
+    .name = "SECP521R1",
+    .oid = "1.3.132.0.35",
+    .size = 66,
+    .prime = "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
+    .A = "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC",
+    .B = "0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00",
+    .order = "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409",
+    .Gx =    "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66",
+    .Gy =    "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650",
+}
+};
diff --git a/ecc_free.c b/ecc_free.c
new file mode 100644
index 0000000..1d7dd64
--- /dev/null
+++ b/ecc_free.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+/* Based on public domain code of LibTomCrypt by Tom St Denis.
+ * Adapted to gmp and nettle by Nikos Mavrogiannopoulos.
+ */
+
+#include "ecc.h"
+
+/*
+  @file ecc_free.c
+  ECC Crypto, Tom St Denis
+*/
+
+/*
+  Free an ECC key from memory
+  @param key   The key you wish to free
+*/
+void
+ecc_free (ecc_key * key)
+{
+  assert (key != NULL);
+  mp_clear_multi (&key->pubkey.x, &key->pubkey.y, &key->pubkey.z, &key->k,
+                  &key->prime, &key->order, &key->Gx, &key->Gy, NULL);
+}
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/ecc/ecc_free.c,v $ */
+/* $Revision: 1.6 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/ecc_make_key.c b/ecc_make_key.c
new file mode 100644
index 0000000..42ac6df
--- /dev/null
+++ b/ecc_make_key.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+/* Based on public domain code of LibTomCrypt by Tom St Denis.
+ * Adapted to gmp and nettle by Nikos Mavrogiannopoulos.
+ */
+
+#include "ecc.h"
+
+/*
+  @file ecc_make_key.c
+  ECC Crypto, Tom St Denis
+*/
+
+/*
+  Make a new ECC key 
+  @param prng         An active PRNG state
+  @param wprng        The index of the PRNG you wish to use
+  @param prime        The prime of curve's field
+  @param order        The order of the G point
+  @param A            The "a" parameter of the curve
+  @param Gx           The x coordinate of the base point
+  @param Gy           The y coordinate of the base point
+  @return 0 if successful, upon error all allocated memory will be freed
+*/
+
+int
+ecc_make_key_ex (void *random_ctx, nettle_random_func random, ecc_key * key,
+                 mpz_t prime, mpz_t order, mpz_t A, mpz_t Gx, mpz_t Gy)
+{
+  int err;
+  ecc_point *base;
+  unsigned char *buf;
+  int keysize;
+
+  assert (key != NULL);
+  assert (random != NULL);
+
+  keysize = nettle_mpz_sizeinbase_256_u (order);
+
+  /* allocate ram */
+  base = NULL;
+  buf = malloc (keysize);
+  if (buf == NULL)
+    {
+      return -1;
+    }
+
+  /* make up random string */
+  random (random_ctx, keysize, buf);
+
+  /* setup the key variables */
+  if ((err =
+       mp_init_multi (&key->pubkey.x, &key->pubkey.y, &key->pubkey.z, &key->k,
+                      &key->prime, &key->order, &key->A, &key->Gx, &key->Gy,
+                      NULL)) != 0)
+    {
+      goto ERR_BUF;
+    }
+  base = ecc_new_point ();
+  if (base == NULL)
+    {
+      err = -1;
+      goto errkey;
+    }
+
+  /* read in the specs for this key */
+  mpz_set (key->prime, prime);
+  mpz_set (key->order, order);
+  mpz_set (key->Gx, Gx);
+  mpz_set (key->Gy, Gy);
+  mpz_set (key->A, A);
+
+  mpz_set (base->x, key->Gx);
+  mpz_set (base->y, key->Gy);
+  mpz_set_ui (base->z, 1);
+  
+  nettle_mpz_set_str_256_u (key->k, keysize, buf);
+
+  /* the key should be smaller than the order of base point */
+  if (mpz_cmp (key->k, key->order) >= 0)
+    {
+      mpz_mod (key->k, key->k, key->order);
+    }
+  /* make the public key */
+  if ((err =
+       ecc_mulmod (key->k, base, &key->pubkey, key->A, key->prime,
+                       1)) != 0)
+    {
+      goto errkey;
+    }
+  key->type = PK_PRIVATE;
+
+  /* free up ram */
+  err = 0;
+  goto cleanup;
+errkey:
+  mp_clear_multi (&key->pubkey.x, &key->pubkey.y, &key->pubkey.z, &key->k,
+                  &key->order, &key->prime, &key->Gx, &key->Gy, &key->A,
+                  NULL);
+cleanup:
+  ecc_del_point (base);
+ERR_BUF:
+  free (buf);
+  return err;
+}
+
+int
+ecc_make_key (void *random_ctx, nettle_random_func random, ecc_key * key,
+              const ecc_set_type * dp)
+{
+  mpz_t prime, order, Gx, Gy, A;
+  int err;
+
+  /* setup the key variables */
+  if ((err = mp_init_multi (&prime, &order, &A, &Gx, &Gy, NULL)) != 0)
+    {
+      goto cleanup;
+    }
+
+  /* read in the specs for this key */
+  mpz_set_str (prime, (char *) dp->prime, 16);
+  mpz_set_str (order, (char *) dp->order, 16);
+  mpz_set_str (Gx, (char *) dp->Gx, 16);
+  mpz_set_str (Gy, (char *) dp->Gy, 16);
+  mpz_set_str (A, (char *) dp->A, 16);
+
+  err = ecc_make_key_ex (random_ctx, random, key, prime, order, A, Gx, Gy);
+
+  mp_clear_multi (&prime, &order, &A, &Gx, &Gy, NULL);
+cleanup:
+  return err;
+}
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/ecc/ecc_make_key.c,v $ */
+/* $Revision: 1.13 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/ecc_map.c b/ecc_map.c
new file mode 100644
index 0000000..561c3b2
--- /dev/null
+++ b/ecc_map.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+/* Based on public domain code of LibTomCrypt by Tom St Denis.
+ * Adapted to gmp and nettle by Nikos Mavrogiannopoulos.
+ */
+
+#include "ecc.h"
+
+/*
+  @file ecc_map.c
+  ECC Crypto, Tom St Denis
+*/
+
+/*
+  Map a projective jacobian point back to affine space
+  @param P        [in/out] The point to map
+  @param modulus  The modulus of the field the ECC curve is in
+  @param mp       The "b" value from montgomery_setup()
+  @return 0 on success
+*/
+int
+ecc_map (ecc_point * P, mpz_t modulus)
+{
+  mpz_t t1, t2;
+  int err;
+
+  assert (P != NULL);
+
+  if ((err = mp_init_multi (&t1, &t2, NULL)) != 0)
+    {
+      return -1;
+    }
+
+  mpz_mod (P->z, P->z, modulus);
+
+  /* get 1/z */
+  mpz_invert (t1, P->z, modulus);
+
+  /* get 1/z^2 and 1/z^3 */
+  mpz_mul (t2, t1, t1);
+  mpz_mod (t2, t2, modulus);
+  mpz_mul (t1, t1, t2);
+  mpz_mod (t1, t1, modulus);
+
+  /* multiply against x/y */
+  mpz_mul (P->x, P->x, t2);
+  mpz_mod (P->x, P->x, modulus);
+  mpz_mul (P->y, P->y, t1);
+  mpz_mod (P->y, P->y, modulus);
+  mpz_set_ui (P->z, 1);
+
+  err = 0;
+
+  mp_clear_multi (&t1, &t2, NULL);
+  return err;
+}
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/ecc/ecc_map.c,v $ */
+/* $Revision: 1.7 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/ecc_mulmod.c b/ecc_mulmod.c
new file mode 100644
index 0000000..fff0fd0
--- /dev/null
+++ b/ecc_mulmod.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+/* Based on public domain code of LibTomCrypt by Tom St Denis.
+ * Adapted to gmp and nettle by Nikos Mavrogiannopoulos.
+ */
+
+#include "ecc.h"
+
+/*
+  @file ecc_mulmod_timing.c
+  ECC Crypto, Tom St Denis
+*/
+
+/*
+   Perform a point multiplication  (timing resistant)
+   @param k    The scalar to multiply by
+   @param G    The base point
+   @param R    [out] Destination for kG
+   @param a        The a value of the curve
+   @param modulus  The modulus of the field the ECC curve is in
+   @param map      Boolean whether to map back to affine or not (1==map, 0 == leave in projective)
+   @return 0 on success
+*/
+int
+ecc_mulmod (mpz_t k, ecc_point * G, ecc_point * R, mpz_t a, mpz_t modulus,
+                int map)
+{
+  ecc_point *tG, *M[3];
+  int i, j, err;
+  unsigned long buf;
+  int bitcnt, mode, digidx;
+
+  assert (k != NULL);
+  assert (G != NULL);
+  assert (R != NULL);
+  assert (modulus != NULL);
+
+  /* alloc ram for window temps */
+  for (i = 0; i < 3; i++)
+    {
+      M[i] = ecc_new_point ();
+      if (M[i] == NULL)
+        {
+          for (j = 0; j < i; j++)
+            {
+              ecc_del_point (M[j]);
+            }
+          return -1;
+        }
+    }
+
+  /* make a copy of G incase R==G */
+  tG = ecc_new_point ();
+  if (tG == NULL)
+    {
+      err = -1;
+      goto done;
+    }
+
+  /* tG = G  and convert to montgomery */
+  mpz_set (tG->x, G->x);
+  mpz_set (tG->y, G->y);
+  mpz_set (tG->z, G->z);
+
+  /* calc the M tab */
+  /* M[0] == G */
+  mpz_set (M[0]->x, tG->x);
+  mpz_set (M[0]->y, tG->y);
+  mpz_set (M[0]->z, tG->z);
+  /* M[1] == 2G */
+  if ((err = ecc_projective_dbl_point (tG, M[1], a, modulus)) != 0)
+    {
+      goto done;
+    }
+
+  /* setup sliding window */
+  mode = 0;
+  bitcnt = 1;
+  buf = 0;
+  digidx = mpz_size (k) - 1;
+
+  /* perform ops */
+  for (;;)
+    {
+      /* grab next digit as required */
+      if (--bitcnt == 0)
+        {
+          if (digidx == -1)
+            {
+              break;
+            }
+          buf = mpz_getlimbn (k, digidx);
+          bitcnt = (int) MP_DIGIT_BIT;
+          --digidx;
+        }
+
+      /* grab the next msb from the ltiplicand */
+      i = (buf >> (MP_DIGIT_BIT - 1)) & 1;
+      buf <<= 1;
+
+      if (mode == 0 && i == 0)
+        {
+          /* dummy operations */
+          if ((err =
+               ecc_projective_add_point (M[0], M[1], M[2], a,
+                                             modulus)) != 0)
+            {
+              goto done;
+            }
+          if ((err =
+               ecc_projective_dbl_point (M[1], M[2], a, modulus)) != 0)
+            {
+              goto done;
+            }
+          continue;
+        }
+
+      if (mode == 0 && i == 1)
+        {
+          mode = 1;
+          /* dummy operations */
+          if ((err =
+               ecc_projective_add_point (M[0], M[1], M[2], a,
+                                             modulus)) != 0)
+            {
+              goto done;
+            }
+          if ((err =
+               ecc_projective_dbl_point (M[1], M[2], a, modulus)) != 0)
+            {
+              goto done;
+            }
+          continue;
+        }
+
+      if ((err =
+           ecc_projective_add_point (M[0], M[1], M[i ^ 1], a,
+                                         modulus)) != 0)
+        {
+          goto done;
+        }
+      if ((err = ecc_projective_dbl_point (M[i], M[i], a, modulus)) != 0)
+        {
+          goto done;
+        }
+    }
+
+  /* copy result out */
+  mpz_set (R->x, M[0]->x);
+  mpz_set (R->y, M[0]->y);
+  mpz_set (R->z, M[0]->z);
+
+  /* map R back from projective space */
+  if (map)
+    {
+      err = ecc_map (R, modulus);
+    }
+  else
+    {
+      err = 0;
+    }
+done:
+  ecc_del_point (tG);
+  for (i = 0; i < 3; i++)
+    {
+      ecc_del_point (M[i]);
+    }
+  return err;
+}
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/ecc/ecc_mulmod_timing.c,v $ */
+/* $Revision: 1.13 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/ecc_points.c b/ecc_points.c
new file mode 100644
index 0000000..cb57823
--- /dev/null
+++ b/ecc_points.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+/* Based on public domain code of LibTomCrypt by Tom St Denis.
+ * Adapted to gmp and nettle by Nikos Mavrogiannopoulos.
+ */
+
+#include "ecc.h"
+
+/*
+  @file ecc_points.c
+  ECC Crypto, Tom St Denis
+*/
+
+/*
+   Allocate a new ECC point
+   @return A newly allocated point or NULL on error 
+*/
+ecc_point *
+ecc_new_point (void)
+{
+  ecc_point *p;
+  p = calloc (1, sizeof (*p));
+  if (p == NULL)
+    {
+      return NULL;
+    }
+  if (mp_init_multi (&p->x, &p->y, &p->z, NULL) != 0)
+    {
+      free (p);
+      return NULL;
+    }
+  return p;
+}
+
+/* Free an ECC point from memory
+  @param p   The point to free
+*/
+void
+ecc_del_point (ecc_point * p)
+{
+  /* prevents free'ing null arguments */
+  if (p != NULL)
+    {
+      mp_clear_multi (&p->x, &p->y, &p->z, NULL);       /* note: p->z may be NULL but that's ok with this function anyways */
+      free (p);
+    }
+}
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/ecc/ecc_points.c,v $ */
+/* $Revision: 1.7 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/ecc_projective_add_point.c b/ecc_projective_add_point.c
new file mode 100644
index 0000000..5a8caaf
--- /dev/null
+++ b/ecc_projective_add_point.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+/* Based on public domain code of LibTomCrypt by Tom St Denis.
+ * Adapted to gmp and nettle by Nikos Mavrogiannopoulos.
+ */
+
+#include "ecc.h"
+
+/*
+  @file ecc_projective_add_point.c
+  ECC Crypto, Tom St Denis
+*/
+
+/*
+   Add two ECC points
+   @param P        The point to add
+   @param Q        The point to add
+   @param R        [out] The destination of the double
+   @param a        Curve's a value
+   @param modulus  The modulus of the field the ECC curve is in
+   @return 0 on success
+*/
+int
+ecc_projective_add_point (ecc_point * P, ecc_point * Q, ecc_point * R,
+                              mpz_t a, mpz_t modulus)
+{
+  mpz_t t1, t2, x, y, z;
+  int err;
+
+  assert (P != NULL);
+  assert (Q != NULL);
+  assert (R != NULL);
+  assert (modulus != NULL);
+
+  if ((err = mp_init_multi (&t1, &t2, &x, &y, &z, NULL)) != 0)
+    {
+      return err;
+    }
+
+  /* Check if P == Q and do doubling in that case 
+   * If Q == -P then P+Q=point at infinity
+   */
+  if ((mpz_cmp (P->x, Q->x) == 0) &&
+      (mpz_cmp (P->z, Q->z) == 0))
+    {
+      /* x and z coordinates match. Check if P->y = Q->y, or P->y = -Q->y
+       */
+      if (mpz_cmp (P->y, Q->y) == 0)
+        {
+          mp_clear_multi (&t1, &t2, &x, &y, &z, NULL);
+          return ecc_projective_dbl_point (P, R, a, modulus);
+        }
+      
+      mpz_sub (t1, modulus, Q->y);
+      if (mpz_cmp (P->y, t1) == 0)
+        {
+          mp_clear_multi (&t1, &t2, &x, &y, &z, NULL);
+          mpz_set_ui(R->x, 1);
+          mpz_set_ui(R->y, 1);
+          mpz_set_ui(R->z, 0);
+          return 0;
+        }
+    }
+
+
+  mpz_set (x, P->x);
+  mpz_set (y, P->y);
+  mpz_set (z, P->z);
+
+  /* if Z is one then these are no-operations */
+  if (mpz_cmp_ui (Q->z, 1) != 0)
+    {
+      /* T1 = Z' * Z' */
+      mpz_mul (t1, Q->z, Q->z);
+      mpz_mod (t1, t1, modulus);
+      /* X = X * T1 */
+      mpz_mul (x, x, t1);
+      mpz_mod (x, x, modulus);
+      /* T1 = Z' * T1 */
+      mpz_mul (t1, t1, Q->z);
+      mpz_mod (t1, t1, modulus);
+      /* Y = Y * T1 */
+      mpz_mul (y, y, t1);
+      mpz_mod (y, y, modulus);
+    }
+
+  /* T1 = Z*Z */
+  mpz_mul (t1, z, z);
+  mpz_mod (t1, t1, modulus);
+  /* T2 = X' * T1 */
+  mpz_mul (t2, t1, Q->x);
+  mpz_mod (t2, t2, modulus);
+  /* T1 = Z * T1 */
+  mpz_mul (t1, t1, z);
+  mpz_mod (t1, t1, modulus);
+  /* T1 = Y' * T1 */
+  mpz_mul (t1, t1, Q->y);
+  mpz_mod (t1, t1, modulus);
+
+  /* Y = Y - T1 */
+  mpz_sub (y, y, t1);
+  if (mpz_cmp_ui (y, 0) < 0)
+    {
+      mpz_add (y, y, modulus);
+    }
+  /* T1 = 2T1 */
+  mpz_add (t1, t1, t1);
+  if (mpz_cmp (t1, modulus) >= 0)
+    {
+      mpz_sub (t1, t1, modulus);
+    }
+  /* T1 = Y + T1 */
+  mpz_add (t1, t1, y);
+  if (mpz_cmp (t1, modulus) >= 0)
+    {
+      mpz_sub (t1, t1, modulus);
+    }
+  /* X = X - T2 */
+  mpz_sub (x, x, t2);
+  if (mpz_cmp_ui (x, 0) < 0)
+    {
+      mpz_add (x, x, modulus);
+    }
+  /* T2 = 2T2 */
+  mpz_add (t2, t2, t2);
+  if (mpz_cmp (t2, modulus) >= 0)
+    {
+      mpz_sub (t2, t2, modulus);
+    }
+  /* T2 = X + T2 */
+  mpz_add (t2, t2, x);
+  if (mpz_cmp (t2, modulus) >= 0)
+    {
+      mpz_sub (t2, t2, modulus);
+    }
+
+  /* if Z' != 1 */
+  if (mpz_cmp_ui (Q->z, 1) != 0)
+    {
+      /* Z = Z * Z' */
+      mpz_mul (z, z, Q->z);
+      mpz_mod (z, z, modulus);
+    }
+
+  /* Z = Z * X */
+  mpz_mul (z, z, x);
+  mpz_mod (z, z, modulus);
+
+  /* T1 = T1 * X  */
+  mpz_mul (t1, t1, x);
+  mpz_mod (t1, t1, modulus);
+  /* X = X * X */
+  mpz_mul (x, x, x);
+  mpz_mod (x, x, modulus);
+  /* T2 = T2 * x */
+  mpz_mul (t2, t2, x);
+  mpz_mod (t2, t2, modulus);
+  /* T1 = T1 * X  */
+  mpz_mul (t1, t1, x);
+  mpz_mod (t1, t1, modulus);
+
+  /* X = Y*Y */
+  mpz_mul (x, y, y);
+  mpz_mod (x, x, modulus);
+  /* X = X - T2 */
+  mpz_sub (x, x, t2);
+  if (mpz_cmp_ui (x, 0) < 0)
+    {
+      mpz_add (x, x, modulus);
+    }
+
+  /* T2 = T2 - X */
+  mpz_sub (t2, t2, x);
+  if (mpz_cmp_ui (t2, 0) < 0)
+    {
+      mpz_add (t2, t2, modulus);
+    }
+  /* T2 = T2 - X */
+  mpz_sub (t2, t2, x);
+  if (mpz_cmp_ui (t2, 0) < 0)
+    {
+      mpz_add (t2, t2, modulus);
+    }
+  /* T2 = T2 * Y */
+  mpz_mul (t2, t2, y);
+  mpz_mod (t2, t2, modulus);
+  /* Y = T2 - T1 */
+  mpz_sub (y, t2, t1);
+  if (mpz_cmp_ui (y, 0) < 0)
+    {
+      mpz_add (y, y, modulus);
+    }
+  /* Y = Y/2 */
+  if (mp_isodd (y))
+    {
+      mpz_add (y, y, modulus);
+    }
+  mpz_divexact_ui (y, y, 2);
+
+  mpz_set (R->x, x);
+  mpz_set (R->y, y);
+  mpz_set (R->z, z);
+
+  err = 0;
+
+  mp_clear_multi (&t1, &t2, &x, &y, &z, NULL);
+  return err;
+}
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/ecc/ecc_projective_add_point.c,v $ */
+/* $Revision: 1.16 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/ecc_projective_dbl_point.c b/ecc_projective_dbl_point.c
new file mode 100644
index 0000000..6f73c4e
--- /dev/null
+++ b/ecc_projective_dbl_point.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+/* Implements ECC point doubling over Z/pZ for curve y^2 = x^3 + ax + b
+ */
+#include "ecc.h"
+
+#ifndef ECC_SECP_CURVES_ONLY
+
+/*
+   Double an ECC point
+   @param P   The point to double
+   @param R   [out] The destination of the double
+   @param a       The "a" value from curve
+   @param modulus  The modulus of the field the ECC curve is in
+   @return 0 on success
+*/
+int
+ecc_projective_dbl_point (ecc_point * P, ecc_point * R, mpz_t a,
+                              mpz_t modulus)
+{
+  mpz_t t1, m, s;
+  int err;
+
+  assert (P != NULL);
+  assert (R != NULL);
+  assert (modulus != NULL);
+
+  /*
+    algorithm used:
+     if (Y == 0)
+       return POINT_AT_INFINITY
+     S = 4*X*Y^2
+     M = 3*X^2 + a*Z^4
+     X' = M^2 - 2*S
+     Y' = M*(S - X') - 8*Y^4
+     Z' = 2*Y*Z
+     return (X', Y', Z')
+   */
+
+  if (mpz_cmp_ui(P->y, 0) == 0)
+    {
+      /* point at infinity 
+       * under jacobian coordinates
+       */
+      mpz_set(R->x, 1);
+      mpz_set(R->y, 1);
+      mpz_set(R->z, 0);
+      
+      return 0;
+    }
+
+  if ((err = mp_init_multi (&t1, &m, &s, NULL)) != 0)
+    {
+      return err;
+    }
+
+  if (P != R)
+    {
+      mpz_set (R->x, P->x);
+      mpz_set (R->y, P->y);
+      mpz_set (R->z, P->z);
+    }
+
+
+  /* m = Z * Z */
+  mpz_mul (m, R->z, R->z);
+  mpz_mod (m, m, modulus);
+
+  /* Calculate Z and get rid of it */
+  /* Z = Y * Z */
+  mpz_mul (R->z, R->y, R->z);
+  mpz_mod (R->z, R->z, modulus);
+  /* Z = 2Z */
+  mpz_add (R->z, R->z, R->z);
+  if (mpz_cmp (R->z, modulus) >= 0)
+    {
+      mpz_sub (R->z, R->z, modulus);
+    }
+
+  /* continue with M and S calculations */
+
+  /* m = m * m = z^4 */
+  mpz_mul (m, m, m);
+  mpz_mod (m, m, modulus);
+
+  /* m = a * m = a*z^4 */
+  mpz_mul (m, a, m);
+  mpz_mod (m, m, modulus);
+
+  /* Y = 2y */
+  mpz_add (R->y, R->y, R->y);
+  if (mpz_cmp (R->y, modulus) >= 0)
+    {
+      mpz_sub (R->y, R->y, modulus);
+    }
+
+  /* Y = Y * Y = 4y^2 */
+  mpz_mul (R->y, R->y, R->y);
+  mpz_mod (R->y, R->y, modulus);
+
+  /* s = X*Y = 4xy^2 */
+  mpz_mul (s, R->x, R->y);
+  mpz_mod (s, s, modulus);
+
+  /* X = x^2 */
+  mpz_mul (R->x, R->x, R->x);
+  mpz_mod (R->x, R->x, modulus);
+
+  /* t1 = 2X = 2x^2 */
+  mpz_add (t1, R->x, R->x);
+  if (mpz_cmp (t1, modulus) >= 0)
+    {
+      mpz_sub (t1, t1, modulus);
+    }
+
+  /* t1 = t1+X = 3X =  3x^2 */
+  mpz_add (t1, t1, R->x);
+  if (mpz_cmp (t1, modulus) >= 0)
+    {
+      mpz_sub (t1, t1, modulus);
+    }
+
+  /* m = t1+m = 3x^2 + a*z^4 */
+  mpz_add (m, m, t1);
+  if (mpz_cmp (m, modulus) >= 0)
+    {
+      mpz_sub (m, m, modulus);
+    }
+
+  /*
+     X' = M^2 - 2*S
+     Y' = M*(S - X') - 8*Y^4
+   */
+
+  /* Y = Y*Y = 16y^4 */
+  mpz_mul (R->y, R->y, R->y);
+  mpz_mod (R->y, R->y, modulus);
+
+  /* Y = 8y^4 */
+  if (mp_isodd (R->y))
+    {
+      mpz_add (R->y, R->y, modulus);
+    }
+  mpz_divexact_ui (R->y, R->y, 2);
+
+  /* X = m^2 */
+  mpz_mul (R->x, m, m);
+  mpz_mod (R->x, R->x, modulus);
+
+  /* X = X - s = m^2 - s */
+  mpz_sub (R->x, R->x, s);
+  if (mpz_cmp_ui (R->x, 0) < 0)
+    {
+      mpz_add (R->x, R->x, modulus);
+    }
+
+  /* X = X - s = m^2 - 2s */
+  mpz_sub (R->x, R->x, s);
+  if (mpz_cmp_ui (R->x, 0) < 0)
+    {
+      mpz_add (R->x, R->x, modulus);
+    }
+
+  /* t1 = s - X */
+  mpz_sub (t1, s, R->x);
+  if (mpz_cmp_ui (t1, 0) < 0)
+    {
+      mpz_add (t1, t1, modulus);
+    }
+
+  /* t1 = M * t1 = M * (s-X) */
+  mpz_mul (t1, m, t1);
+  mpz_mod (t1, t1, modulus);
+
+  /* Y = t1 - Y = (M * (s-X)) - 8y^4 */
+  mpz_sub (R->y, t1, R->y);
+  if (mpz_cmp_ui (R->y, 0) < 0)
+    {
+      mpz_add (R->y, R->y, modulus);
+    }
+
+  err = 0;
+
+  mp_clear_multi (&t1, &m, &s, NULL);
+  return err;
+}
+
+#endif
diff --git a/ecc_projective_dbl_point_3.c b/ecc_projective_dbl_point_3.c
new file mode 100644
index 0000000..18f7cb2
--- /dev/null
+++ b/ecc_projective_dbl_point_3.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+/* Based on public domain code of LibTomCrypt by Tom St Denis.
+ * Adapted to gmp and nettle by Nikos Mavrogiannopoulos.
+ */
+
+#include "ecc.h"
+
+/*
+  @file ecc_projective_dbl_point.c
+  ECC Crypto, Tom St Denis
+*/  
+
+#ifdef ECC_SECP_CURVES_ONLY
+
+/*
+   Double an ECC point
+   @param P   The point to double
+   @param R   [out] The destination of the double
+   @param modulus  The modulus of the field the ECC curve is in
+   @param mp       The "b" value from montgomery_setup()
+   @return 0 on success
+*/
+int
+ecc_projective_dbl_point (ecc_point * P, ecc_point * R, mpz_t a /* a is -3 */,
+                              mpz_t modulus)
+{
+   mpz_t t1, t2;
+   int   err;
+
+   assert(P       != NULL);
+   assert(R       != NULL);
+   assert(modulus != NULL);
+
+   if ((err = mp_init_multi(&t1, &t2, NULL)) != 0) {
+      return err;
+   }
+
+   if (P != R) {
+      mpz_set(R->x, P->x);
+      mpz_set(R->y, P->y);
+      mpz_set(R->z, P->z);
+   }
+
+   /* t1 = Z * Z */
+   mpz_mul(t1, R->z, R->z);
+   mpz_mod(t1, t1, modulus);
+   /* Z = Y * Z */
+   mpz_mul(R->z, R->y, R->z);
+   mpz_mod(R->z, R->z, modulus);
+   /* Z = 2Z */
+   mpz_add(R->z, R->z, R->z);
+   if (mpz_cmp(R->z, modulus) >= 0) {
+      mpz_sub(R->z, R->z, modulus);
+   }
+   
+   /* T2 = X - T1 */
+   mpz_sub(t2, R->x, t1);
+   if (mpz_cmp_ui(t2, 0) < 0) {
+      mpz_add(t2, t2, modulus);
+   }
+   /* T1 = X + T1 */
+   mpz_add(t1, t1, R->x);
+   if (mpz_cmp(t1, modulus) >= 0) {
+      mpz_sub(t1, t1, modulus);
+   }
+   /* T2 = T1 * T2 */
+   mpz_mul(t2, t1, t2);
+   mpz_mod(t2, t2, modulus);
+   /* T1 = 2T2 */
+   mpz_add(t1, t2, t2);
+   if (mpz_cmp(t1, modulus) >= 0) {
+      mpz_sub(t1, t1, modulus);
+   }
+   /* T1 = T1 + T2 */
+   mpz_add(t1, t1, t2);
+   if (mpz_cmp(t1, modulus) >= 0) {
+      mpz_sub(t1, t1, modulus);
+   }
+
+   /* Y = 2Y */
+   mpz_add(R->y, R->y, R->y);
+   if (mpz_cmp(R->y, modulus) >= 0) {
+      mpz_sub(R->y, R->y, modulus);
+   }
+   /* Y = Y * Y */
+   mpz_mul(R->y, R->y, R->y);
+   mpz_mod(R->y, R->y, modulus);
+   /* T2 = Y * Y */
+   mpz_mul(t2, R->y, R->y);
+   mpz_mod(t2, t2, modulus);
+   /* T2 = T2/2 */
+   if (mp_isodd(t2)) {
+      mpz_add(t2, t2, modulus);
+   }
+   mpz_divexact_ui(t2, t2, 2);
+   /* Y = Y * X */
+   mpz_mul(R->y, R->y, R->x);
+   mpz_mod(R->y, R->y, modulus);
+
+   /* X  = T1 * T1 */
+   mpz_mul(R->x, t1, t1);
+   mpz_mod(R->x, R->x, modulus);
+   /* X = X - Y */
+   mpz_sub(R->x, R->x, R->y);
+   if (mpz_cmp_ui(R->x, 0) < 0) {
+      mpz_add(R->x, R->x, modulus);
+   }
+   /* X = X - Y */
+   mpz_sub(R->x, R->x, R->y);
+   if (mpz_cmp_ui(R->x, 0) < 0) {
+      mpz_add(R->x, R->x, modulus);
+   }
+
+   /* Y = Y - X */     
+   mpz_sub(R->y, R->y, R->x);
+   if (mpz_cmp_ui(R->y, 0) < 0) {
+      mpz_add(R->y, R->y, modulus);
+   }
+   /* Y = Y * T1 */
+   mpz_mul(R->y, R->y, t1);
+   mpz_mod(R->y, R->y, modulus);
+   /* Y = Y - T2 */
+   mpz_sub(R->y, R->y, t2);
+   if (mpz_cmp_ui(R->y, 0) < 0) {
+      mpz_add( R->y, R->y, modulus);
+   }
+ 
+   err = 0;
+
+   mp_clear_multi(&t1, &t2, NULL);
+   return err;
+}
+#endif
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/ecc/ecc_projective_dbl_point.c,v $ */
+/* $Revision: 1.11 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
+
diff --git a/ecc_shared_secret.c b/ecc_shared_secret.c
new file mode 100644
index 0000000..e24c140
--- /dev/null
+++ b/ecc_shared_secret.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+/* Based on public domain code of LibTomCrypt by Tom St Denis.
+ * Adapted to gmp and nettle by Nikos Mavrogiannopoulos.
+ */
+
+#include "ecc.h"
+#include <string.h>
+
+/*
+  @file ecc_shared_secret.c
+  ECC Crypto, Tom St Denis
+*/
+
+/*
+  Create an ECC shared secret between two keys
+  @param private_key      The private ECC key
+  @param public_key       The public key
+  @param out              [out] Destination of the shared secret (Conforms to EC-DH from ANSI X9.63)
+  @param outlen           [in/out] The max size and resulting size of the shared secret
+  @return 0 if successful
+*/
+int
+ecc_shared_secret (ecc_key * private_key, ecc_key * public_key,
+                   unsigned char *out, unsigned long *outlen)
+{
+  unsigned long x;
+  ecc_point *result;
+  int err;
+
+  assert (private_key != NULL);
+  assert (public_key != NULL);
+  assert (out != NULL);
+  assert (outlen != NULL);
+
+  /* type valid? */
+  if (private_key->type != PK_PRIVATE)
+    {
+      return -1;
+    }
+
+  /* make new point */
+  result = ecc_new_point ();
+  if (result == NULL)
+    {
+      return -1;
+    }
+
+  if ((err =
+       ecc_mulmod (private_key->k, &public_key->pubkey, result,
+                       private_key->A, private_key->prime, 1)) != 0)
+    {
+      goto done;
+    }
+
+  x = nettle_mpz_sizeinbase_256_u (private_key->prime);
+  if (*outlen < x)
+    {
+      *outlen = x;
+      err = -1;
+      goto done;
+    }
+  memset (out, 0, x);
+  nettle_mpz_get_str_256(x, out + (x - nettle_mpz_sizeinbase_256_u (result->x)), result->x);
+
+  err = 0;
+  *outlen = x;
+done:
+  ecc_del_point (result);
+  return err;
+}
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/ecc/ecc_shared_secret.c,v $ */
+/* $Revision: 1.10 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/ecc_sign_hash.c b/ecc_sign_hash.c
new file mode 100644
index 0000000..cc58a23
--- /dev/null
+++ b/ecc_sign_hash.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+/* Based on public domain code of LibTomCrypt by Tom St Denis.
+ * Adapted to gmp and nettle by Nikos Mavrogiannopoulos.
+ */
+
+#include "ecc.h"
+#include <nettle/dsa.h>
+
+/*
+  @file ecc_sign_hash.c
+  ECC Crypto, Tom St Denis
+*/
+
+/*
+  Sign a message digest
+  @param in        The message digest to sign
+  @param inlen     The length of the digest
+  @param sign      The destination for 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 0 if successful
+*/
+int
+ecc_sign_hash (const unsigned char *in, unsigned long inlen,
+               struct dsa_signature *sig,
+               void *random_ctx, nettle_random_func random, ecc_key * key)
+{
+  ecc_key pubkey;
+  mpz_t e;
+  int err;
+
+  assert (in != NULL);
+  assert (sig != NULL);
+  assert (key != NULL);
+
+  /* is this a private key? */
+  if (key->type != PK_PRIVATE)
+    {
+      return -1;
+    }
+
+  /* get the hash and load it as a bignum into 'e' */
+  /* init the bignums */
+  if ((err = mp_init_multi (&e, NULL)) != 0)
+    {
+      return err;
+    }
+
+  nettle_mpz_set_str_256_u (e, inlen, in);
+
+  /* make up a key and export the public copy */
+  for (;;)
+    {
+      if ((err =
+           ecc_make_key_ex (random_ctx, random, &pubkey, key->prime,
+                            key->order, key->A, key->Gx, key->Gy)) != 0)
+        {
+          goto errnokey;
+        }
+
+      /* find r = x1 mod n */
+      mpz_mod (sig->r, pubkey.pubkey.x, pubkey.order);
+
+      if (mpz_cmp_ui (sig->r, 0) == 0)
+        {
+          ecc_free (&pubkey);
+        }
+      else
+        {
+          /* find s = (e + xr)/k */
+          mpz_invert (pubkey.k, pubkey.k, pubkey.order);
+
+          /* mulmod */
+          mpz_mul (sig->s, key->k, sig->r);
+          mpz_mod (sig->s, sig->s, pubkey.order);
+          mpz_add (sig->s, e, sig->s);
+          mpz_mod (sig->s, sig->s, pubkey.order);
+
+          mpz_mul (sig->s, sig->s, pubkey.k);
+          mpz_mod (sig->s, sig->s, pubkey.order);
+          ecc_free (&pubkey);
+          if (mpz_cmp_ui (sig->s, 0) != 0)
+            {
+              break;
+            }
+        }
+    }
+
+errnokey:
+  mp_clear_multi (&e, NULL);
+  return err;
+}
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/ecc/ecc_sign_hash.c,v $ */
+/* $Revision: 1.11 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/ecc_verify_hash.c b/ecc_verify_hash.c
new file mode 100644
index 0000000..92a996e
--- /dev/null
+++ b/ecc_verify_hash.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+/* Based on public domain code of LibTomCrypt by Tom St Denis.
+ * Adapted to gmp and nettle by Nikos Mavrogiannopoulos.
+ */
+
+#include "ecc.h"
+
+/*
+  @file ecc_verify_hash.c
+  ECC Crypto, Tom St Denis
+*/
+
+/* verify 
+ *
+ * w  = s^-1 mod n
+ * u1 = xw 
+ * u2 = rw
+ * X = u1*G + u2*Q
+ * v = X_x1 mod n
+ * accept if v == r
+ */
+
+/*
+   Verify an ECC signature
+   @param signature         The signature to verify
+   @param hash        The hash (message digest) that was signed
+   @param hashlen     The length of the hash (octets)
+   @param stat        Result of signature, 1==valid, 0==invalid
+   @param key         The corresponding public ECC key
+   @return 0 if successful (even if the signature is not valid)
+*/
+int
+ecc_verify_hash (struct dsa_signature *signature,
+                 const unsigned char *hash, unsigned long hashlen,
+                 int *stat, ecc_key * key)
+{
+  ecc_point *mG, *mQ;
+  mpz_t v, w, u1, u2, e;
+  int err;
+
+  assert (signature != NULL);
+  assert (hash != NULL);
+  assert (stat != NULL);
+  assert (key != NULL);
+
+  /* default to invalid signature */
+  *stat = 0;
+
+  /* allocate ints */
+  if ((err = mp_init_multi (&v, &w, &u1, &u2, &e, NULL)) != 0)
+    {
+      return -1;
+    }
+
+  /* allocate points */
+  mG = ecc_new_point ();
+  mQ = ecc_new_point ();
+  if (mQ == NULL || mG == NULL)
+    {
+      err = -1;
+      goto error;
+    }
+
+  /* check for (0) */
+  if (mpz_cmp_ui (signature->r, 0) == 0 || mpz_cmp_ui (signature->s, 0) == 0
+      || mpz_cmp (signature->r, key->order) >= 0
+      || mpz_cmp (signature->s, key->order) >= 0)
+    {
+      err = -1;
+      goto error;
+    }
+
+  /* read hash */
+  nettle_mpz_set_str_256_u (e, hashlen, hash);
+
+  /*  w  = s^-1 mod n */
+  mpz_invert (w, signature->s, key->order);
+
+  /* u1 = ew */
+  mpz_mul (u1, e, w);
+  mpz_mod (u1, u1, key->order);
+
+  /* u2 = rw */
+  mpz_mul (u2, signature->r, w);
+  mpz_mod (u2, u2, key->order);
+
+  /* find mG and mQ */
+  mpz_set (mG->x, key->Gx);
+  mpz_set (mG->y, key->Gy);
+  mpz_set_ui (mG->z, 1);
+
+  mpz_set (mQ->x, key->pubkey.x);
+  mpz_set (mQ->y, key->pubkey.y);
+  mpz_set (mQ->z, key->pubkey.z);
+
+  /* compute u1*mG + u2*mQ = mG */
+  if ((err = ecc_mulmod (u1, mG, mG, key->A, key->prime, 0)) != 0)
+    {
+      goto error;
+    }
+  if ((err = ecc_mulmod (u2, mQ, mQ, key->A, key->prime, 0)) != 0)
+    {
+      goto error;
+    }
+
+  /* add them */
+  if ((err =
+       ecc_projective_add_point (mQ, mG, mG, key->A, key->prime)) != 0)
+    {
+      goto error;
+    }
+
+  /* reduce */
+  if ((err = ecc_map (mG, key->prime)) != 0)
+    {
+      goto error;
+    }
+
+  /* v = X_x1 mod n */
+  mpz_mod (v, mG->x, key->order);
+
+  /* does v == r */
+  if (mpz_cmp (v, signature->r) == 0)
+    {
+      *stat = 1;
+    }
+
+  /* clear up and return */
+  err = 0;
+error:
+  ecc_del_point (mG);
+  ecc_del_point (mQ);
+  mp_clear_multi (&v, &w, &u1, &u2, &e, NULL);
+  return err;
+}
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/ecc/ecc_verify_hash.c,v $ */
+/* $Revision: 1.14 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
diff --git a/nettle.texinfo b/nettle.texinfo
index 36b9a00..5c32e39 100644
--- a/nettle.texinfo
+++ b/nettle.texinfo
@@ -85,6 +85,8 @@ Public-key algorithms
 
 * RSA::                         The RSA public key algorithm.
 * DSA::                         The DSA digital signature algorithm.
+* ECDSA::                       The ECDSA digital signature algorithm.
+* ECDH::                        The EC Diffie-Hellman key exchange algorithm.
 
 @end detailmenu
 @end menu
@@ -214,6 +216,11 @@ for bignum operations.
 @item DSA
 Written by @value{AUTHOR}, released under the LGPL. Uses the GMP library
 for bignum operations.
+
+@item ECDSA and ECDH
+Added by Nikos Mavrogiannopoulos, based on code by Tom St. Dennis, released 
+under the LGPL. Uses the GMP library for bignum operations.
+
 @end table
 
 @node Conventions, Example, Copyright, Top
@@ -2040,6 +2047,8 @@ key, and to no others''.
 @menu
 * RSA::                         The RSA public key algorithm.
 * DSA::                         The DSA digital signature algorithm.
+* ECDSA::                       The ECDSA digital signature algorithm.
+* ECDH::                        The EC Diffie-Hellman key exchange algorithm.
 @end menu
 
 @node RSA, DSA, Public-key algorithms, Public-key algorithms
@@ -2255,7 +2264,7 @@ example if if @var{n_size} is too small, or if @var{e_size} is zero and
 @code{pub->e} is an even number.
 @end deftypefun
 
-@node DSA,  , RSA, Public-key algorithms
+@node DSA, ECDSA, RSA, Public-key algorithms
 @comment  node-name,  next,  previous,  up
 @subsection Nettle's @acronym{DSA} support
 
@@ -2499,6 +2508,70 @@ Returns one on success, and zero on failure. The function will fail if
 small.
 @end deftypefun
 
+@node ECDSA, ECDH, DSA, Public-key algorithms
+@comment  node-name,  next,  previous,  up
+@subsection Nettle's @acronym{ECDSA} support
+
+The @acronym{ECDSA} digital signature algorithm is the counter-part
+of @acronym{DSA} over elliptic curves.
+
+Nettle represents @acronym{ECDSA} keys using the @code{ecc_key}
+structure. 
+
+@deftp {Context struct} {ecc_key} prime order A Gx Gy pubkey k
+The public and private parameters.
+@end deftp
+
+Before use, these structs must be initialized by calling one of
+@code{ecc_make_key} or @code{ecc_make_key_ex}.
+When finished with them, the space for the numbers must be
+deallocated by @code{ecc_free}.
+
+Signatures are represented using same structure as with DSA signatures, 
+and need to be initialized and cleared in the same way as for the
+DSA case.
+
+@deftp {Context struct} {dsa_signature} r s
+@end deftp
+
+@deftypefun void dsa_signature_init (struct dsa_signature *@var{signature})
+@deftypefunx void dsa_signature_clear (struct dsa_signature *@var{signature})
+You must call @code{dsa_signature_init} before creating or using a
+signature, and call @code{dsa_signature_clear} when you are finished
+with it.
+@end deftypefun
+
+For signing, you need to provide both the ECC key
+and a source for random numbers.
+
+@deftypefun int ecc_sign_hash (const unsigned char *in,  unsigned long inlen, struct dsa_signature *signature, void *random_ctx, nettle_random_func random, ecc_key *key);
+Creates a signature from the given hash value.
+@var{random_ctx} and @var{random} is a randomness generator.
+For advice, see
+@xref{Randomness}. Returns one on success, or zero on failure.
+Signing fails if the key size and the hash size don't match.
+@end deftypefun
+
+Verifying signatures is a little easier, since no randomness generator is
+needed. The functions are
+
+@deftypefun int ecc_verify_hash (struct dsa_signature * signature, const unsigned char *hash, unsigned long hashlen, int *stat, ecc_key *key);
+Verifies a signature. The status of the signature verification is stored in stat. It is 1 if the signature is valid, otherwise 0.
+@end deftypefun
+
+@node ECDH,  , ECDSA, Public-key algorithms
+@comment  node-name,  next,  previous,  up
+@subsection Nettle's @acronym{ECDH} support
+
+The @acronym{ECDH} key exchange method is the counter-part
+of Diffie-Hellman over elliptic curves. It uses the same keys
+as @code{ECDSA}.
+
+@acronym{ECDH} keys are also represented using the @code{ecc_key}
+structure. 
+
+For key exchange the @code{ecc_shared_secret} function is used.
+
 @node Randomness, Miscellaneous functions, Public-key algorithms, Reference
 @comment  node-name,  next,  previous,  up
 @section Randomness
diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in
index 8a263cb..0d41a13 100644
--- a/testsuite/Makefile.in
+++ b/testsuite/Makefile.in
@@ -20,7 +20,7 @@ TS_NETTLE_SOURCES = aes-test.c arcfour-test.c arctwo-test.c \
 		    sha1-test.c sha224-test.c sha256-test.c \
 		    sha384-test.c sha512-test.c \
 		    serpent-test.c twofish-test.c \
-		    knuth-lfib-test.c \
+		    knuth-lfib-test.c ecc-test.c \
 		    cbc-test.c ctr-test.c gcm-test.c hmac-test.c \
 		    meta-hash-test.c meta-cipher-test.c meta-armor-test.c \
 		    buffer-test.c yarrow-test.c
diff --git a/testsuite/ecc-test.c b/testsuite/ecc-test.c
new file mode 100644
index 0000000..c8609b0
--- /dev/null
+++ b/testsuite/ecc-test.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+/* Based on public domain code of LibTomCrypt by Tom St Denis.
+ * Adapted to gmp and nettle by Nikos Mavrogiannopoulos.
+ */
+
+#include "ecc.h"
+#include "gnettle.h"
+#include <gnutls_int.h>
+#include <algorithms.h>
+
+/**
+  @file ecc_test.c
+  ECC Crypto, Tom St Denis
+*/
+
+/**
+  Perform on the ECC system
+  @return 0 if successful
+*/
+int
+ecc_test (void)
+{
+  mpz_t modulus, order, A;
+  ecc_point *G, *GG;
+  int i, err;
+
+  if ((err = mp_init_multi (&modulus, &A, &order, NULL)) != 0)
+    {
+      return err;
+    }
+
+  G = ecc_new_point ();
+  GG = ecc_new_point ();
+  if (G == NULL || GG == NULL)
+    {
+      mp_clear_multi (&modulus, &order, NULL);
+      ecc_del_point (G);
+      ecc_del_point (GG);
+      return -1;
+    }
+
+  for (i = 0; i < 16; i++)
+    {
+      const ecc_set_type *st = ecc_curves_secp[i];
+      
+      if (st->name == NULL)
+        break;
+
+      printf ("Testing %s (%d)\n", st->name, i);
+
+      if (mpz_set_str (A, (char *) st->A, 16) != 0)
+        {
+          fprintf (stderr, "Error loading curve %s: %d\n", st->name, __LINE__);
+          err = -1;
+          goto done;
+        }
+
+      if (mpz_set_str (modulus, (char *) st->prime, 16) != 0)
+        {
+          fprintf (stderr, "Error loading curve %s: %d\n", st->name, __LINE__);
+          err = -1;
+          goto done;
+        }
+
+      if (mpz_set_str (order, (char *) st->order, 16) != 0)
+        {
+          fprintf (stderr, "Error loading curve %s: %d\n", st->name, __LINE__);
+          err = -1;
+          goto done;
+        }
+
+      /* is prime actually prime? */
+      if ((err = mpz_probab_prime_p (modulus, PRIME_CHECK_PARAM)) <= 0)
+        {
+          fprintf (stderr, "Error loading curve %s: %d\n", st->name, __LINE__);
+          err = -1;
+          goto done;
+        }
+
+      if ((err = mpz_probab_prime_p (order, PRIME_CHECK_PARAM)) <= 0)
+        {
+          fprintf (stderr, "Error loading curve %s: %d\n", st->name, __LINE__);
+          err = -1;
+          goto done;
+        }
+
+      if (mpz_set_str (G->x, (char *) st->Gx, 16) != 0)
+        {
+          fprintf (stderr, "Error loading curve %s: %d\n", st->name, __LINE__);
+          err = -1;
+          goto done;
+        }
+
+      if (mpz_set_str (G->y, (char *) st->Gy, 16) != 0)
+        {
+          fprintf (stderr, "Error loading curve %s: %d\n", st->name, __LINE__);
+          err = -1;
+          goto done;
+        }
+      mpz_set_ui (G->z, 1);
+
+      /* then we should have G == (order + 1)G */
+      mpz_add_ui (order, order, 1);
+      if ((err = ecc_mulmod (order, G, GG, A, modulus, 1)) != 0)
+        {
+          goto done;
+        }
+
+      if (mpz_cmp (G->y, GG->y) != 0)
+        {
+          fprintf (stderr, "Error in curve %s: %d\n", st->name, __LINE__);
+          err = -1;
+          goto done;
+        }
+
+      if (mpz_cmp (G->x, GG->x) != 0)
+        {
+          fprintf (stderr, "Error in curve %s: %d\n", st->name, __LINE__);
+          err = -1;
+          goto done;
+        }
+
+    }
+  err = 0;
+done:
+  ecc_del_point (GG);
+  ecc_del_point (G);
+  mp_clear_multi (&order, &modulus, &A, NULL);
+  return err;
+}
+
+/* $Source: /cvs/libtom/libtomcrypt/src/pk/ecc/ecc_test.c,v $ */
+/* $Revision: 1.12 $ */
+/* $Date: 2007/05/12 14:32:35 $ */
-- 
1.7.4.1

