summaryrefslogtreecommitdiff
path: root/cipher/ecc.c
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2007-03-21 19:55:39 +0000
committerWerner Koch <wk@gnupg.org>2007-03-21 19:55:39 +0000
commit5fb3fe0e58466d9556839cd7b5cfaab9468dd0cd (patch)
tree3e6d6010e06be69d144b6a8c68f580144217b478 /cipher/ecc.c
parent1765d8626332ba69d45d4413a9436186d6a2cc63 (diff)
downloadlibgcrypt-5fb3fe0e58466d9556839cd7b5cfaab9468dd0cd.tar.gz
New code from Sergi Blanch i Torne.
Need some mangling for use with Libgcrypt, as this code is designed to work with GnuPG 1.4.6.
Diffstat (limited to 'cipher/ecc.c')
-rw-r--r--cipher/ecc.c1733
1 files changed, 1733 insertions, 0 deletions
diff --git a/cipher/ecc.c b/cipher/ecc.c
new file mode 100644
index 00000000..b2e08478
--- /dev/null
+++ b/cipher/ecc.c
@@ -0,0 +1,1733 @@
+/* ecc.c - ECElGamal Public Key encryption & ECDSA signature algorithm
+ * Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+/* This code is a based on the
+ * Patch 0.1.6 for the gnupg 1.4.x branch
+ * as retrieved on 2007-03-21 from
+ * http://www.calcurco.cat/eccGnuPG/src/gnupg-1.4.6-ecc0.2.0beta1.diff.bz2
+ *
+ * Written by
+ * Sergi Blanch i Torne <d4372211 at alumnes.eup.udl.es>,
+ * Ramiro Moreno Chiral <ramiro at eup.udl.es>
+ * Maintainers
+ * Sergi Blanch i Torne
+ * Ramiro Moreno Chiral
+ * Mikael Mylnikov (mmr)
+ */
+
+/*
+ * This module are under development, it would not have to be used
+ * in a production environments. It can have bugs!
+ *
+ * Made work:
+ * alex: found a bug over the passphrase.
+ * mmr: signature bug found and solved (afine conversion).
+ * mmr: found too many mistakes in the mathematical background transcription.
+ * mmr: improve the mathematical performance.
+ * mmr: solve ECElGamal IFP weakness.
+ * more polite gen_k() and its calls.
+ * mmr: extend the check_secret_key()
+ * In process:
+ * genBigPoint(): Randomize the point generation.
+ * improve te memory uses.
+ * Separation between sign & encrypt keys to facility the subkeys creation.
+ * read & reread the code in a bug search!
+ * To do:
+ * 2-isogeny: randomize the elliptic curves.
+ * E(F_{2^m})
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "types.h"
+#include "util.h"
+#include "mpi.h"
+#include "cipher.h"
+#include "ecc.h"
+
+//ECC over F_p; E(F_p)
+//T=(p,a,b,G,n,h)
+// p: big odd number
+// a,b: curve generators
+// G: Subgroup generator point
+// n: big int, in G order
+// h: cofactor
+// y^2=x^3+ax+b --> (Y^2)Z=X^3+aX(Z^2)+b(Z^3)
+
+//
+// Q=[d]G, 1<=d<=n-1
+
+typedef struct {
+ MPI x_;
+ MPI y_;
+ MPI z_;
+} point; //Point representation in projective coordinates.
+
+typedef struct {
+ MPI p_;
+ MPI a_,b_;
+ //MPI Gx,Gy,Gz;
+ point G;
+ MPI n_;
+ //MPI h_; =1 //!! We will need to change this value in 2-isogeny
+} ellipticCurve;//doubtful name //!!
+
+typedef struct {
+ ellipticCurve E;
+ point Q; /*Q=[d]G*/
+} ECC_public_key;//Q
+
+typedef struct {
+ ellipticCurve E;
+ point Q; /*Q=[d]G*/
+ MPI d;
+} ECC_secret_key;//d
+
+
+static MPI gen_k( MPI p, int secure );
+
+static void generateCurve(unsigned nbits, ellipticCurve *ECC_curve);//choice a curve of the rank
+
+static void generateKey(ECC_secret_key *sk, unsigned nbits , MPI **factors );//Generate de cryptosystem setup.
+static void testKeys( ECC_secret_key *sk, unsigned nbits );//verify correct skey
+static int check_secret_key( ECC_secret_key *sk );//check the validity of the value
+static void doEncrypt(MPI input, ECC_public_key *pkey, point *R, MPI c);
+static MPI decrypt(MPI output, ECC_secret_key *skey, point R, MPI c);
+static void sign(MPI input, ECC_secret_key *skey, MPI *r, MPI *s);
+static int verify(MPI input, ECC_public_key *pkey, MPI r, MPI s);
+
+static int genBigPoint(MPI *prime, ellipticCurve *base, point *G, unsigned nbits);//return -1 if it isn't possible
+static point genPoint(MPI prime, ellipticCurve base);//random point over an Elliptic curve
+static MPI existSquareRoot(MPI integer, MPI modulus);//return true or false
+static void Lucas(MPI n, MPI p_, MPI q_, MPI k, MPI V_n, MPI Q_0);
+
+static int PointAtInfinity(point Query);//return true(1), false(0), or error(-1) for an invalid point
+
+static void escalarMult(MPI escalar, point *P, point *R, ellipticCurve *base);//return R=escalarP
+static void sumPoints(point *P0, point *P1, point *P2, ellipticCurve *base);//P2=P0+P1
+static void duplicatePoint(point *P, point *R, ellipticCurve *base);//R=2P
+static void invertPoint(point *P, ellipticCurve *base);//P=-P
+
+static point point_copy(point P);
+static void point_free(point *P);
+static int point_affine(point *P, MPI x, MPI y, ellipticCurve *base);//turn an projective coordinate to affine, return 0 (1 if error).
+static ellipticCurve curve_copy(ellipticCurve E);
+static void curve_free(ellipticCurve *E);
+static MPI gen_bit();
+static MPI gen_y_2(MPI x, ellipticCurve *base);
+
+//Function for IFP ECElGamal Weakness.
+static void sha256_hashing(MPI input, MPI *output);//Compute a hash
+static void aes256_encrypting(MPI key, MPI input, MPI *output);//Encrypt simmetricaly
+static void aes256_decrypting(MPI key, MPI input, MPI *output);//Decrypt simmetricaly
+
+static void (*progress_cb) ( void *, int );
+static void *progress_cb_data;
+
+static void
+progress( int c )
+{
+ if ( progress_cb )
+ progress_cb ( progress_cb_data, c );
+ else
+ fputc( c, stderr );
+}
+
+/****************
+ * At the begging was the same than elgamal.c
+ * but mmr improve it.
+ * Generate a random secret scalar k with an order of p
+ * Moreover it do NOT use Wiener's table.
+ */
+static MPI
+gen_k( MPI p, int secure ){
+
+ MPI k = mpi_alloc_secure( 0 );
+ unsigned int nbits = mpi_get_nbits(p);
+ unsigned int nbytes;
+
+ nbytes = (nbits+7)/8;
+ if( DBG_CIPHER )
+ log_debug("choosing a random k of %u bits\n", nbits);
+ char *c = get_random_bits( nbits, secure, 1 );
+ mpi_set_buffer( k, c, nbytes, 0 );
+ xfree(c);
+ mpi_fdiv_r(k,k, p);//simple module: k=k (mod p)
+ if( DBG_CIPHER )
+ progress('\n');
+
+ return k;
+}
+
+/****************
+ * Generate de cryptosystem setup.
+ * At this time it fix the values to the ones which NIST recomend.
+ * The subgroup generator point is in another function: 'genBigPoint'.
+ */
+static void
+generateCurve(unsigned nbits, ellipticCurve *ECC_curve){
+
+ ellipticCurve E;
+ //point *G;
+
+ if( nbits == 192 ){//NIST P-192
+ E.p_ =mpi_alloc((nbits/(BYTES_PER_MPI_LIMB*8))+1);
+ if (mpi_fromstr(E.p_,\
+ "0xfffffffffffffffffffffffffffffffeffffffffffffffff"))
+ log_fatal("ECC operation: Curve assigments failed(p)\n");
+ else ECC_curve->p_ = mpi_copy(E.p_);
+ E.a_ =mpi_alloc((2/(BYTES_PER_MPI_LIMB*8))+1);
+ if (mpi_fromstr(E.a_,\
+ "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC"))//"-0x3"))
+ log_fatal("ECC operation: Curve assigments failed(a)\n");
+ else ECC_curve->a_ = mpi_copy(E.a_);
+ E.b_ =mpi_alloc((nbits/(BYTES_PER_MPI_LIMB*8))+1);
+ if (mpi_fromstr(E.b_,\
+ "0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1"))
+ log_fatal("ECC operation: Curve assigments failed(b)\n");
+ else ECC_curve->b_ = mpi_copy(E.b_);
+ E.n_ =mpi_alloc((nbits/(BYTES_PER_MPI_LIMB*8))+1);
+ if (mpi_fromstr(E.n_,\
+ "0xffffffffffffffffffffffff99def836146bc9b1b4d22831"))
+ log_fatal("ECC operation: Curve assigments failed(n)\n");
+ else ECC_curve->n_ = mpi_copy(E.n_);
+ }
+ else if( nbits == 224 ){//NIST P-224
+ E.p_ =mpi_alloc((nbits/(BYTES_PER_MPI_LIMB*8))+1);
+ if (mpi_fromstr(E.p_,\
+ "0xffffffffffffffffffffffffffffffff000000000000000000000001"))
+ log_fatal("ECC operation: Curve assigments failed(p)\n");
+ else ECC_curve->p_ = mpi_copy(E.p_);
+ E.a_ =mpi_alloc((2/(BYTES_PER_MPI_LIMB*8))+1);
+ if (mpi_fromstr(E.a_,\
+ "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE"))//"-0x3"))
+ log_fatal("ECC operation: Curve assigments failed(a)\n");
+ else ECC_curve->a_ = mpi_copy(E.a_);
+ E.b_ =mpi_alloc((nbits/(BYTES_PER_MPI_LIMB*8))+1);
+ if (mpi_fromstr(E.b_,\
+ "0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4"))
+ log_fatal("ECC operation: Curve assigments failed(b)\n");
+ else ECC_curve->b_ = mpi_copy(E.b_);
+ E.n_ =mpi_alloc((nbits/(BYTES_PER_MPI_LIMB*8))+1);
+ if (mpi_fromstr(E.n_,\
+ "0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d"))
+ log_fatal("ECC operation: Curve assigments failed(n)\n");
+ else ECC_curve->n_ = mpi_copy(E.n_);
+ }
+ else if( nbits == 256 ){//NIST P-256
+ E.p_ =mpi_alloc((nbits/(BYTES_PER_MPI_LIMB*8))+1);
+ if (mpi_fromstr(E.p_,\
+ "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff"))
+ log_fatal("ECC operation: Curve assigments failed(p)\n");
+ else ECC_curve->p_ = mpi_copy(E.p_);
+ E.a_ =mpi_alloc((2/(BYTES_PER_MPI_LIMB*8))+1);
+ if (mpi_fromstr(E.a_,\
+ "0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC"))//"-0x3"))
+ log_fatal("ECC operation: Curve assigments failed(a)\n");
+ else ECC_curve->a_ = mpi_copy(E.a_);
+ E.b_ =mpi_alloc((nbits/(BYTES_PER_MPI_LIMB*8))+1);
+ if (mpi_fromstr(E.b_,\
+ "0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b"))
+ log_fatal("ECC operation: Curve assigments failed(b)\n");
+ else ECC_curve->b_ = mpi_copy(E.b_);
+ E.n_ =mpi_alloc((nbits/(BYTES_PER_MPI_LIMB*8))+1);
+ if (mpi_fromstr(E.n_,\
+ "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"))
+ log_fatal("ECC operation: Curve assigments failed(n)\n");
+ else ECC_curve->n_ = mpi_copy(E.n_);
+ }
+ else if( nbits == 384 ){//NIST P-384
+ E.p_ =mpi_alloc((nbits/(BYTES_PER_MPI_LIMB*8))+1);
+ if (mpi_fromstr(E.p_,\
+ "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff"))
+ log_fatal("ECC operation: Curve assigments failed(p)\n");
+ else ECC_curve->p_ = mpi_copy(E.p_);
+ E.a_ =mpi_alloc((2/(BYTES_PER_MPI_LIMB*8))+1);
+ if (mpi_fromstr(E.a_,\
+ "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC"))//"-0x3"))
+ log_fatal("ECC operation: Curve assigments failed(a)\n");
+ else ECC_curve->a_ = mpi_copy(E.a_);
+ E.b_ =mpi_alloc((nbits/(BYTES_PER_MPI_LIMB*8))+1);
+ if (mpi_fromstr(E.b_,\
+ "0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef"))
+ log_fatal("ECC operation: Curve assigments failed(b)\n");
+ else ECC_curve->b_ = mpi_copy(E.b_);
+ E.n_ =mpi_alloc((nbits/(BYTES_PER_MPI_LIMB*8))+1);
+ if (mpi_fromstr(E.n_,\
+ "0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973"))
+ log_fatal("ECC operation: Curve assigments failed(n)\n");
+ else ECC_curve->n_ = mpi_copy(E.n_);
+ }
+ else if( nbits == 521 ){//NIST P-521
+ E.p_ =mpi_alloc((nbits/(BYTES_PER_MPI_LIMB*8))+1);
+ if (mpi_fromstr(E.p_,\
+ "0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))
+ log_fatal("ECC operation: Curve assigments failed(p)\n");
+ else ECC_curve->p_ = mpi_copy(E.p_);
+ E.a_ =mpi_alloc((2/(BYTES_PER_MPI_LIMB*8))+1);
+ if (mpi_fromstr(E.a_,\
+ "0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC"))//"-0x3"))
+ log_fatal("ECC operation: Curve assigments failed(a)\n");
+ else ECC_curve->a_ = mpi_copy(E.a_);
+ E.b_ =mpi_alloc((nbits/(BYTES_PER_MPI_LIMB*8))+1);
+ if (mpi_fromstr(E.b_,\
+ "0x051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00"))
+ log_fatal("ECC operation: Curve assigments failed(b)\n");
+ else ECC_curve->b_ = mpi_copy(E.b_);
+ E.n_ =mpi_alloc((nbits/(BYTES_PER_MPI_LIMB*8))+1);
+ if (mpi_fromstr(E.n_,\
+ "0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409"))
+ log_fatal("ECC operation: Curve assigments failed(n)\n");
+ else ECC_curve->n_ = mpi_copy(E.n_);
+ }
+ else{
+ log_fatal("ECC operation: Curve generation failed\n");
+ }
+ if( DBG_CIPHER ){
+ progress('\n');
+ log_mpidump("generation p= ", ECC_curve->p_ );
+ log_mpidump("generation a= ", ECC_curve->a_ );
+ log_mpidump("generation b= ", ECC_curve->b_ );
+ log_mpidump("generation n= ", ECC_curve->n_ );
+ }
+ if ( genBigPoint(&ECC_curve->n_, ECC_curve, &ECC_curve->G, nbits) == -1){
+ log_fatal("ECC operation: Point generation failed\n");
+ }
+ if( DBG_CIPHER ) {
+ log_mpidump("generation Gx= ", ECC_curve->G.x_ );
+ log_mpidump("generation Gy= ", ECC_curve->G.y_ );
+ log_mpidump("generation Gz= ", ECC_curve->G.z_ );
+ log_info("Setup generated\n");
+ progress('\n');
+ }
+}
+
+/****************
+ * Fisrt obtain the setup.
+ * Over the finite field randomize an scalar secret value, and calculat de public point.
+ *
+ * !! What about the **ret_factors !! //!!
+ */
+static void
+generateKey(ECC_secret_key *sk, unsigned nbits , MPI **ret_factors ){
+
+ ellipticCurve E;
+ MPI d;
+ point Q,G;
+
+ generateCurve(nbits,&E);
+
+ d = mpi_alloc_secure(nbits/BITS_PER_MPI_LIMB);
+ if( DBG_CIPHER )
+ log_debug("choosing a random x of size %u\n", nbits );
+ d = gen_k(E.n_,2);//generate_secret_prime(nbits);
+ G = point_copy(E.G);
+
+ escalarMult(d,&E.G,&Q,&E);
+
+ /* copy the stuff to the key structures */
+ sk->E.p_ = mpi_copy(E.p_);
+ sk->E.a_ = mpi_copy(E.a_);
+ sk->E.b_ = mpi_copy(E.b_);
+ sk->E.G = point_copy(E.G);
+ sk->E.n_ = mpi_copy(E.n_);
+ sk->Q = point_copy(Q);
+ sk->d = mpi_copy(d);
+
+ /* now we can test our keys (this should never fail!) */
+ testKeys( sk, nbits - 64 );
+
+ point_free(&Q);
+ mpi_free(d);
+ curve_free(&E);
+}
+
+/****************
+ * To verify correct skey it use a random information.
+ * First, encrypt and decrypt this dummy value,
+ * test if the information is recuperated.
+ * Second, test with the sign and verify functions.
+ */
+static void
+testKeys( ECC_secret_key *sk, unsigned nbits ){
+
+ ECC_public_key pk;
+ MPI test = mpi_alloc( nbits / BITS_PER_MPI_LIMB );
+ point R_;
+ MPI c = mpi_alloc( nbits / BITS_PER_MPI_LIMB );
+ MPI out = mpi_alloc( nbits / BITS_PER_MPI_LIMB );
+ MPI r = mpi_alloc( nbits / BITS_PER_MPI_LIMB );
+ MPI s = mpi_alloc( nbits / BITS_PER_MPI_LIMB );
+
+ if( DBG_CIPHER )log_info("Testing key.\n");
+
+ pk.E = curve_copy(sk->E);
+ pk.E.G = point_copy(sk->E.G);
+ pk.Q = point_copy(sk->Q);
+
+ /*mpi_set_bytes( test, nbits, get_random_byte, 0 );*/
+ { char *p = get_random_bits( nbits, 0, 0 );
+ mpi_set_buffer( test, p, (nbits+7)/8, 0 );
+ xfree(p);
+ }
+
+ doEncrypt(test,&pk,&R_,c);
+
+ out = decrypt(out,sk,R_,c);
+
+ if( mpi_cmp( test, out ) )//test!=out
+ log_fatal("ECELG operation: encrypt, decrypt failed\n");
+ if( DBG_CIPHER )log_info("ECELG operation: encrypt, decrypt ok.\n");
+
+ sign(test,sk,&r,&s);
+
+ if( !verify(test,&pk,r,s) ){
+ log_fatal("ECDSA operation: sign, verify failed\n");}
+
+ if( DBG_CIPHER )log_info("ECDSA operation: sign, verify ok.\n");
+
+ mpi_free(s);
+ mpi_free(r);
+ mpi_free(out);
+ mpi_free(c);
+ point_free(&R_);
+ mpi_free(test);
+}
+
+/****************
+ * To check the validity of the value, recalculate the correspondence
+ * between the public value and de secret one.
+ */
+static int
+check_secret_key( ECC_secret_key *sk ){
+
+ point Q;
+ MPI y_2,y2 = mpi_alloc(0);
+
+ //?primarity test of 'p'
+ // (...) //!!
+ //G in E(F_p)
+ y_2 = gen_y_2(sk->E.G.x_,&sk->E);// y^2=x^3+a*x+b
+ mpi_mulm(y2,sk->E.G.y_,sk->E.G.y_,sk->E.p_);// y^2=y*y
+ if (mpi_cmp(y_2,y2)){
+ if( DBG_CIPHER )log_info("Bad check: Point 'G' does not belong to curve 'E'!\n");
+ return (1);
+ }
+ //G != PaI
+ if (PointAtInfinity(sk->E.G)){
+ if( DBG_CIPHER )log_info("Bad check: 'G' cannot be Point at Infinity!\n");
+ return (1);
+ }
+ //?primarity test of 'n'
+ // (...) //!!
+ //?(p-sqrt(p)) < n < (p+sqrt(p))
+ //?n!=p
+ //?(n^k) mod p !=1 for k=1 to 31 (from GOST) or k=1 to 50 (from MIRACL)
+ //Q=[n]G over E = PaI
+ escalarMult(sk->E.n_,&sk->E.G,&Q,&sk->E);
+ if (!PointAtInfinity(Q)){
+ if( DBG_CIPHER )log_info("Bad check: 'E' is not curve of order 'n'!\n");
+ return (1);
+ }
+ //pubkey cannot be PaI
+ if (PointAtInfinity(sk->Q)){
+ if( DBG_CIPHER )log_info("Bad check: Q can not be a Point at Infinity!\n");
+ return (1);
+ }
+ //pubkey = [d]G over E
+ escalarMult(sk->d,&sk->E.G,&Q,&sk->E);
+ if ((Q.x_ == sk->Q.x_) && (Q.y_ == sk->Q.y_) && (Q.z_ == sk->Q.z_)){
+ if( DBG_CIPHER )log_info("Bad check: There is NO correspondence between 'd' and 'Q'!\n");
+ return (1);
+ }
+ point_free(&Q);
+ return (0);
+}
+
+/****************
+ * Encrypt a number and obtain and struct (R,c)
+ */
+static void
+doEncrypt(MPI input, ECC_public_key *pkey, point *R, MPI c){
+
+ MPI k,p,x,y;
+ point P,Q,G;
+ ellipticCurve E;
+
+ k = mpi_alloc(0);
+ p = mpi_copy(pkey->E.p_);
+ x = mpi_alloc(0);
+ y = mpi_alloc(0);
+ Q = point_copy(pkey->Q);
+ G = point_copy(pkey->E.G);
+ E = curve_copy(pkey->E);
+
+ k = gen_k( p, 1);//2nd parametre: how much security?
+ escalarMult(k,&Q,&P,&E);//P=[k]Q=[k]([d]G)
+ escalarMult(k,&G,R,&E);//R=[k]G
+ //IFP weakness//mpi_mul(c,input,Q.x_);//c=input*Q_x
+ //MMR Use affine conversion befor extract x-coordinate
+ if (point_affine(&P,x,y,&E)){//Q cannot turn to affine coordinate
+ if( DBG_CIPHER ){log_info("Encrypting: Cannot turn to affine.\n");}
+ }
+ //MMR According to the standard P1363 we can not use x-coordinate directly.
+ // It is necessary to add hash-operation later.
+ // As the maximal length of a key for the symmetric cipher is 256 bit it is possible to take hash-function SHA256.
+ sha256_hashing(x,&x);
+ aes256_encrypting(x,input,&c);
+
+ if( DBG_CIPHER ){log_debug("doEncrypt: end.\n");}
+}
+
+/****************
+ * Undo the ciphertext
+ */
+static MPI
+decrypt(MPI output, ECC_secret_key *skey, point R, MPI c){
+
+ MPI p,inv,x,y;
+ point P,Q;
+ ellipticCurve E;
+
+ p = mpi_copy(skey->E.p_);
+ inv = mpi_alloc(0);
+ x = mpi_alloc(0);
+ y = mpi_alloc(0);
+ Q = point_copy(skey->Q);
+ E = curve_copy(skey->E);
+
+ escalarMult(skey->d,&R,&P,&E);//P=[d]R
+ //That is like: mpi_fdiv_q(output,c,Q.x_);
+ //IFP weakness//mpi_invm(inv,Q.x_,p);//inv=Q{_x}^-1 (mod p)
+ //IFP weakness//mpi_mulm(output,c,inv,p);//output=c*inv (mod p)
+ //MMR Use affine conversion befor extract x-coordinate
+ if (point_affine(&P,x,y,&E)){//Q cannot turn to affine coordinate
+ if( DBG_CIPHER ){log_info("Encrypting: Cannot turn to affine.\n");}
+ }
+ sha256_hashing(x,&x);
+ aes256_decrypting(x,c,&output);
+
+ if( DBG_CIPHER ){log_debug("decrypt: end.\n");}
+ return (output);
+}
+
+/****************
+ * Return the signature struct (r,s) from the message hash.
+ */
+static void
+sign(MPI input, ECC_secret_key *skey, MPI *r, MPI *s){
+
+ MPI k,i,dr,sum,k_1,x,y;
+ point G,I;
+ ellipticCurve E;
+
+ k = mpi_alloc(0); i = mpi_alloc(0); dr = mpi_alloc(0); sum = mpi_alloc(0); k_1 = mpi_alloc(0);
+ x = mpi_alloc(0); y = mpi_alloc(0);
+ G = point_copy(skey->E.G);
+ E = curve_copy(skey->E);
+ *r = mpi_alloc(0);
+ *s = mpi_alloc(0);
+
+ while (!mpi_cmp_ui(*s,0)){//s==0
+ while (!mpi_cmp_ui(*r,0)){//r==0
+ k = gen_k( E.p_, 1 );
+ escalarMult(k,&G,&I,&E);//I=[k]G
+ if (point_affine(&I,x,y,&E)){//I cannot turn to affine coordinate
+ if( DBG_CIPHER ){log_info("Sign: Cannot turn to affine. Cannot complete sign.\n");}
+ }
+ i = mpi_copy(x);//i=I_x
+ mpi_fdiv_r(*r,i,E.n_);//simple module: r=i (mod n)
+ }
+ mpi_mulm(dr,skey->d,*r,E.n_);//dr=d*r (mod n)
+ mpi_addm(sum,input,dr,E.n_);//sum=hash+(d*r) (mod n)
+ mpi_invm(k_1,k,E.n_);//k_1=k^(-1) (mod n)
+ mpi_mulm(*s,k_1,sum,E.n_);// s=k^(-1)*(hash+(d*r)) (mod n)
+ }
+ if( DBG_CIPHER ){log_debug("Sign: end\n");}
+ mpi_free(y);
+ mpi_free(x);
+ mpi_free(k_1);
+ mpi_free(sum);
+ mpi_free(dr);
+ mpi_free(i);
+ mpi_free(k);
+}
+
+/****************
+ * Check if the struct (r,s) is for the hash value that it have.
+ */
+static int
+verify(MPI input, ECC_public_key *pkey, MPI r, MPI s){
+
+ MPI r_,s_,h,h1,h2,i,x,y;
+ point Q,Q1,Q2,G;
+ ellipticCurve E;
+
+ r_ = mpi_alloc(0); s_ = mpi_alloc(0); h = mpi_alloc(0); h1 = mpi_alloc(0); h2 = mpi_alloc(0); x = mpi_alloc(0); y = mpi_alloc(0);
+ G = point_copy(pkey->E.G);
+ E = curve_copy(pkey->E);
+
+ mpi_fdiv_r(r_,r,pkey->E.n_);//simple module
+ mpi_fdiv_r(s_,s,pkey->E.n_);//simple module
+
+ //check if the input parameters are valid.
+ if ( mpi_cmp(r_,r) || mpi_cmp(s_,s)) {//r_!=r || s_!=s
+ if( DBG_CIPHER ){log_info("Verification: No valid values.\n");}
+ return 0; //not valid values.
+ }
+
+ mpi_invm(h,s,E.n_);//h=s^(-1) (mod n)
+ mpi_mulm(h1,input,h,E.n_);//h1=hash*s^(-1) (mod n)
+ escalarMult(h1,&G,&Q1,&E);//Q1=[hash*s^(-1)]G
+ mpi_mulm(h2,r,h,E.n_);//h2=r*s^(-1) (mod n)
+ escalarMult(h2,&pkey->Q,&Q2,&E);//Q2=[r*s^(-1)]Q
+ sumPoints(&Q1,&Q2,&Q,&E);//Q=([hash*s^(-1)]G)+([r*s^(-1)]Q)
+
+ if (PointAtInfinity(Q)){
+ if( DBG_CIPHER ){log_info("Verification: Rejected.\n");}
+ return 0;//rejected
+ }
+ if (point_affine(&Q,x,y,&E)){//Q cannot turn to affine coordinate
+ if( DBG_CIPHER ){log_info("Verification: Cannot turn to affine. Rejected.\n");}
+ return 0;//rejected
+ }
+ i = mpi_copy(x);//Give the x_coordinate
+ mpi_fdiv_r(i,i,E.n_);//simple module
+
+ if (!mpi_cmp(i,r)){//i==r => Return 0 (distance between them).
+ if( DBG_CIPHER ){log_info("Verification: Accepted.\n");}
+ return 1;//accepted
+ }
+ if( DBG_CIPHER ){log_info("Verification: Not verified.\n");}
+ return 0;
+}
+
+/****************
+ * A point of order 'n' is needed to generate a ciclic subgroup.
+ * Over this ciclic subgroup it's defined the ECDLP.
+ * Now it use a fix values from NIST FIPS PUB 186-2.
+ */
+static int
+genBigPoint(MPI *prime, ellipticCurve *base, point *G, unsigned nbits){
+ ///*estandard nist
+ if( nbits == 192 ){//NIST P-192
+ G->x_ = mpi_alloc(mpi_get_nlimbs(base->n_));
+ if (mpi_fromstr(G->x_,\
+ "0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012"))
+ log_fatal("Generator operation: Point assigments failed(x)\n");
+ G->y_ = mpi_alloc(mpi_get_nlimbs(base->n_));
+ if (mpi_fromstr(G->y_,\
+ "0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811"))
+ log_fatal("Generator operation: Point assigments failed(y)\n");
+ G->z_ = mpi_alloc_set_ui(1);
+ }
+ else if( nbits == 224 ){//NIST P-224
+ G->x_ = mpi_alloc(mpi_get_nlimbs(base->n_));
+ if (mpi_fromstr(G->x_,\
+ "0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21"))
+ log_fatal("Generator operation: Point assigments failed(x)\n");
+ G->y_ = mpi_alloc(mpi_get_nlimbs(base->n_));
+ if (mpi_fromstr(G->y_,\
+ "0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34"))
+ log_fatal("Generator operation: Point assigments failed(y)\n");
+ G->z_ = mpi_alloc_set_ui(1);
+ }
+ else if( nbits == 256 ){//NIST P-256
+ G->x_ = mpi_alloc(mpi_get_nlimbs(base->n_));
+ if (mpi_fromstr(G->x_,\
+ "0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296"))
+ log_fatal("Generator operation: Point assigments failed(x)\n");
+ G->y_ = mpi_alloc(mpi_get_nlimbs(base->n_));
+ if (mpi_fromstr(G->y_,\
+ "0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"))
+ log_fatal("Generator operation: Point assigments failed(y)\n");
+ G->z_ = mpi_alloc_set_ui(1);
+ }
+ else if( nbits == 384 ){//NIST P-384
+ G->x_ = mpi_alloc(mpi_get_nlimbs(base->n_));
+ if (mpi_fromstr(G->x_,\
+ "0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7"))
+ log_fatal("Generator operation: Point assigments failed(x)\n");
+ G->y_ = mpi_alloc(mpi_get_nlimbs(base->n_));
+ if (mpi_fromstr(G->y_,\
+ "0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f"))
+ log_fatal("Generator operation: Point assigments failed(y)\n");
+ G->z_ = mpi_alloc_set_ui(1);
+ }
+ else if( nbits == 521 ){//NIST P-521
+ G->x_ = mpi_alloc(mpi_get_nlimbs(base->n_));
+ if (mpi_fromstr(G->x_,\
+ "0xc6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66"))
+ log_fatal("Generator operation: Point assigments failed(x)\n");
+ G->y_ = mpi_alloc(mpi_get_nlimbs(base->n_));
+ if (mpi_fromstr(G->y_,\
+ "0x11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650"))
+ log_fatal("Generator operation: Point assigments failed(y)\n");
+ G->z_ = mpi_alloc_set_ui(1);
+ }
+ //end Estandard nist
+ /*Randomize G
+ unsigned int i=0;
+ MPI one;
+ point Big, P;
+
+ one = mpi_alloc_set_ui(1);
+ G->x_ = mpi_alloc(mpi_get_nlimbs(*prime));
+ G->y_ = mpi_alloc(mpi_get_nlimbs(*prime));
+ G->z_ = mpi_alloc(mpi_get_nlimbs(*prime));
+
+ if( DBG_MPI )log_info("Generating a Big point.\n");
+ do{
+ do{
+ *P = genPoint(*prime,*base);
+ }while(PointAtInfinity(*P));//A random point in the curve that it's not PaI
+ escalarMult(base.h,&P,&G,&base);//cofactor (1 o 2), could be improved
+ }while(PointAtInfinity(G));
+ if( DBG_MPI )log_info("Big point generated.\n");
+ if( DBG_MPI ){
+ log_mpidump("Gx=",G->x_);log_mpidump("Gy=",G->y_);log_mpidump("Gz=",G->z_);
+ }
+ return 0;
+ *///end aleatoritzar G
+ return 0;
+}
+
+/****************
+ * Generate a random point over an Elliptic curve
+ * is the first step to find a random ciclic subgroup
+ * generator.
+ *
+ * !! At this moment it isn't used !! //!!
+ */
+static point
+genPoint(MPI prime, ellipticCurve base){
+
+ unsigned int i=0;
+ MPI x,y_2,y;
+ MPI one, one_neg,bit;
+ point P;
+
+ x = mpi_alloc(mpi_get_nlimbs(base.p_));
+ y_2 = mpi_alloc(mpi_get_nlimbs(base.p_));
+ y = mpi_alloc(mpi_get_nlimbs(base.p_));
+ one = mpi_alloc_set_ui(1);
+ one_neg = mpi_alloc(mpi_get_nlimbs(one));
+ mpi_invm(one_neg,one,base.p_);
+
+ if( DBG_MPI )log_info("Generating a normal point.\n");
+ do{
+ x = gen_k(base.p_,1);//generate_public_prime(mpi_get_nlimbs(base.n_)*BITS_PER_MPI_LIMB);
+ do{
+ y_2 = gen_y_2(x,&base);//x^3+ax+b (mod p)
+ mpi_add_ui(x, x, 1);
+ i++;
+ }while( !mpi_cmp_ui(y_2,0) && i<0xf);//Try to find a valid value until 16 iterations.
+ i=0;
+ y = existSquareRoot(y_2,base.p_);
+ }while( !mpi_cmp_ui(y,0));//Repeat until a valid coordinate is found.
+ bit = gen_bit();//generate one bit
+ if (mpi_cmp_ui(bit,1)){//choose the y coordinate
+ mpi_invm(y, y, base.p_);//mpi_powm(y, y, one_neg,base.p_);
+ }
+ if( DBG_MPI )log_info("Normal point generated.\n");
+
+ P.x_ = mpi_copy(x);
+ P.y_ = mpi_copy(y);
+ P.z_ = mpi_copy(one);
+
+ mpi_free(bit);
+ mpi_free(one_neg);
+ mpi_free(one);
+ mpi_free(y);
+ mpi_free(y_2);
+ mpi_free(x);
+
+ return(P);
+}
+
+/****************
+ * Find, if it exist, the square root of one integer module a big prime.
+ * Return the square root or 0 if it is not found.
+ */
+static MPI
+existSquareRoot(MPI integer, MPI modulus){
+
+ unsigned long int i=0;
+ MPI one,two,three,four,five,eight;
+ MPI k,r,z,k1;
+ MPI t1,t2,t3,t4;
+
+ one = mpi_alloc_set_ui(1);
+ two = mpi_alloc_set_ui(2);
+ three = mpi_alloc_set_ui(3);
+ four = mpi_alloc_set_ui(4);
+ five = mpi_alloc_set_ui(5);
+ eight = mpi_alloc_set_ui(8);
+ k = mpi_alloc(mpi_get_nlimbs(modulus));
+ r = mpi_alloc(mpi_get_nlimbs(modulus));
+ z = mpi_alloc(mpi_get_nlimbs(modulus));
+ k1 = mpi_alloc(mpi_get_nlimbs(modulus));
+ t1 = mpi_alloc(mpi_get_nlimbs(modulus));
+ t2 = mpi_alloc(mpi_get_nlimbs(modulus));
+ t3 = mpi_alloc(mpi_get_nlimbs(modulus));
+ t4 = mpi_alloc(mpi_get_nlimbs(modulus));
+
+ if( DBG_MPI )log_mpidump("?exist Square Root of ",integer);
+
+ mpi_fdiv_qr(k,r,modulus,four);
+ if (mpi_cmp(r,three)){//p=3 (mod 4)
+ mpi_addm(k1,k,one,modulus);
+ mpi_powm(z,integer,k1,modulus);
+ if( DBG_MPI ){log_mpidump("z=",z);}
+ return z;//value found
+ }
+ mpi_fdiv_qr(k,r,modulus,eight);
+ if (mpi_cmp(r,five)){//p=5 (mod 8)
+ mpi_mulm(t1,two,integer,modulus);
+ mpi_powm(t2,t1,k,modulus);
+ mpi_powm(t2,t2,two,modulus);
+ mpi_mulm(t2,t1,t2,modulus);
+ mpi_mulm(t3,integer,t1,modulus);
+ mpi_subm(t4,t2,one,modulus);
+ mpi_mulm(z,t3,t4,modulus);
+ if( DBG_MPI ){log_mpidump("z=",z);}
+ return z;//value found
+ }
+ if (mpi_cmp(r,one)){//p=1 (mod 8)
+ while(i<0xFF){//while not find z after 256 iterations*/
+ if( DBG_MPI )log_info("Square root bucle.\n");
+ t1 = mpi_copy(integer);
+ t2 = gen_k(modulus,0);
+ mpi_add_ui(t3,modulus,1);//t3=p+1
+ mpi_rshift(t3,t3,1);//t3=t3/2
+ Lucas(t1,t2,t3,modulus,t4,t3);//t4=V_k
+ mpi_rshift(z,t4,1);//z=V/2
+ mpi_sub_ui(t3,modulus,1);//t3=p-1
+ mpi_rshift(t4,t3,2);//t4=t3/2
+ Lucas(t1,t2,t4,modulus,t4,t1);//t1=Q_0
+ mpi_powm(t2,z,two,modulus);//t2=z^2
+ if (mpi_cmp(t1,integer)){
+ if( DBG_MPI ){log_mpidump("z=",z);}
+ return z;//value found
+ }
+ if (t4>mpi_alloc_set_ui(1) && t4<t3){
+ if( DBG_MPI )log_info("Rejected.\n");
+ return (0); //NULL
+ }
+ if( DBG_MPI )log_info("Another loop.\n");
+ }
+ }
+ if( DBG_MPI )log_info("iterations limit.\n");
+ return (0);//because this algorithm not always finish.
+}
+
+/****************
+ * Formal definition:
+ * V_0=2;V_1=p
+ * V_k=(p*V_(k-1))-(q*V_(k-2)) for k>=2
+ */
+static void
+Lucas(MPI n, MPI p_, MPI q_, MPI k, MPI V_n, MPI Q_0){
+
+ MPI v0,v1,q0,q1;
+ MPI t1,t2;
+ unsigned int r,i;
+
+ v0 = mpi_alloc_set_ui(2);
+ v1 = mpi_copy(p_);
+ q0 = mpi_alloc_set_ui(1);
+ q1 = mpi_alloc_set_ui(1);
+ t1 = mpi_alloc_set_ui(0);
+ t2 = mpi_alloc_set_ui(0);
+
+ if( DBG_MPI ){log_info("Generating lucas sequence.\n");log_mpidump("k=",k);}
+
+ r = mpi_get_nbits(k)-1;
+ i = 0;
+ while (mpi_test_bit(k,i) != 1){ //search the first bit with value '1'
+ i++;
+ }
+ while (i<r){
+ if( DBG_MPI ){
+ log_info("Lucas sequence bucle.\n");
+ log_mpidump("i=",mpi_alloc_set_ui(i));
+ log_mpidump("r=",mpi_alloc_set_ui(r));
+ }
+ mpi_mulm(q0,q0,q1,n);
+ if (mpi_test_bit(k,i) == 1){
+ mpi_mulm(q1,q0,q_,n);
+ mpi_mul(t1,v0,v1);
+ mpi_mul(t2,p_,q0);
+ mpi_subm(v0,t1,t2,n);
+ mpi_powm(t1,v1,mpi_alloc_set_ui(2),n);
+ mpi_mul(t2,mpi_alloc_set_ui(2),q1);
+ mpi_subm(v1,t1,t2,n);
+ }
+ else{
+ q1 = mpi_copy(q0);
+ mpi_mul(t1,v0,v1);
+ mpi_mul(t2,p_,q0);
+ mpi_subm(v1,t1,t2,n);
+ mpi_powm(t1,v0,mpi_alloc_set_ui(2),n);
+ mpi_mul(t2,mpi_alloc_set_ui(2),q0);
+ mpi_subm(v0,t1,t2,n);
+ }
+ i++;
+ }
+ V_n = mpi_copy(v0);
+ Q_0 = mpi_copy(q0);
+ if( DBG_MPI ){
+ log_info("Lucas sequence generated.\n");
+ log_mpidump("V_n=",V_n);
+ log_mpidump("Q_0=",Q_0);
+ }
+}
+
+/****************
+ * The point at infinity is needed to make
+ * a group structure to the elliptic curve.
+ * Know if one point is it, is needed so
+ * much times in this code.
+ */
+static int
+PointAtInfinity(point Query){
+
+ if( DBG_MPI ){log_info("?is a Point at Infinity.\n");}
+
+ if (!mpi_cmp_ui(Query.z_,0)){//Z=0
+ if (/*mpi_cmp_ui(Query.x_,0) && */mpi_cmp_ui(Query.y_,0)){//X & Y!=0 & Z=0
+ if( DBG_MPI )log_info("True:It is a Point at Infinite.\n");
+ return (1); //true
+ }
+ if( DBG_MPI )log_info("Error:It isn't an elliptic curve valid point.\n");
+ return (-1); //
+ }
+ if( DBG_MPI ){log_info("False:It isn't a Point at Infinity.\n");}
+ return (0); //it is a valid curve point, but it isn't the point at infinity
+}
+
+/****************
+ * The modular power used without EC,
+ * is this function over EC.
+ */
+static void
+escalarMult(MPI escalar, point *P, point *R, ellipticCurve *base){
+
+ MPI one,two,three;
+ MPI p;
+ MPI xx,yy,zz,x1,y1,z1,z2,z3,k,h;//it could use less memory!!!!
+ unsigned int i,loops;
+ point P1,P2,P1_;
+
+ x1 = mpi_alloc(mpi_get_nlimbs(P->x_));
+ y1 = mpi_alloc(mpi_get_nlimbs(P->y_));
+ z2 = mpi_alloc(mpi_get_nlimbs(P->z_));
+ z3 = mpi_alloc(mpi_get_nlimbs(P->z_));
+ h = mpi_alloc(mpi_get_nlimbs(P->z_));
+
+ if( DBG_MPI )log_info("Calculating an scalar Multiple.\n");
+
+ one = mpi_alloc_set_ui(1);
+ two = mpi_alloc_set_ui(2);
+ three = mpi_alloc_set_ui(3);
+ p = mpi_copy(base->p_);
+
+ if ( !mpi_cmp_ui(escalar,0) || mpi_cmp_ui(P->z_,0)){//n=0 | Z=0 => [1:1:0]
+ R->x_ = mpi_copy(one);
+ R->y_ = mpi_copy(one);
+ R->z_ = mpi_alloc(0);
+ }
+ xx = mpi_copy(P->x_);
+ zz = mpi_copy(P->z_);
+ z1 = mpi_copy(one);
+ if (mpi_is_neg(escalar)){//(-n)P=n(-P)
+ escalar->sign = 0;//+n
+ k = mpi_copy(escalar);
+ yy = mpi_copy(P->y_);//-P
+ mpi_invm(yy,yy,p);
+ }
+ else {
+ k = mpi_copy(escalar);
+ yy = mpi_copy(P->y_);
+ }
+ if (!mpi_cmp(zz,one)){//zz==1
+ x1 = mpi_copy(xx);
+ y1 = mpi_copy(yy);
+ }
+ else {
+ mpi_mulm(z2,zz,zz,p);//z^2
+ mpi_mulm(z3,zz,z2,p);//z^3
+ mpi_invm(z2,z2,p);//1/Z^2
+ mpi_mulm(x1,xx,z2,p);//xx/z^2
+ mpi_invm(z3,z3,p);//1/z^3
+ mpi_mulm(y1,yy,z3,p);//yy/z^3
+ }
+ mpi_mul(h,three,k);//h=3k
+ loops = mpi_get_nbits(h);
+ i=loops-2; // i = l-1 = loops-2
+ R->x_ = mpi_copy(xx);
+ R->y_ = mpi_copy(yy);
+ R->z_ = mpi_copy(zz);
+ P1.x_ = mpi_copy(x1);
+ P1.y_ = mpi_copy(y1);
+ P1.z_ = mpi_copy(z1);
+ while(i>0){ // A.10.9. step 11 i from l-1 downto 1
+ duplicatePoint(R,R,base);
+ if ( mpi_test_bit(h,i) == 1 && mpi_test_bit(k,i) == 0){//h_i=1 & k_i=0
+ P2 = point_copy(*R);
+ sumPoints(&P2,&P1,R,base);//R=P2+P1 over the base elliptic curve
+ }
+ if ( mpi_test_bit(h,i) == 0 && mpi_test_bit(k,i) == 1){//h_i=0 & k_i=1
+ P2 = point_copy(*R);
+ P1_ = point_copy(P1);
+ invertPoint(&P1_,base);
+ sumPoints(&P2,&P1_,R,base);//R=P2+P1_ over the base elliptic curve
+ }
+ i--;
+ }
+ if( DBG_MPI )log_info("Scalar Multiple calculated.\n");
+
+ point_free(&P1);
+ point_free(&P2);
+ point_free(&P1_);
+ mpi_free(h);
+ mpi_free(k);
+ mpi_free(z3);
+ mpi_free(z2);
+ mpi_free(z1);
+ mpi_free(y1);
+ mpi_free(x1);
+ mpi_free(zz);
+ mpi_free(yy);
+ mpi_free(xx);
+ mpi_free(p);
+ mpi_free(three);
+ mpi_free(two);
+ mpi_free(one);
+}
+
+/****************
+ * Point addition is the group operation.
+ */
+static void
+sumPoints(point *P0, point *P1, point *P2, ellipticCurve *base){
+
+ MPI one,two;
+ MPI p;
+ MPI t1,t2,t3,t4,t5,t6,t7;
+
+ one = mpi_alloc_set_ui(1);
+ two = mpi_alloc_set_ui(2);
+ p = mpi_copy(base->p_);
+ t1 = mpi_alloc(mpi_get_nlimbs(p));
+ t2 = mpi_alloc(mpi_get_nlimbs(p));
+ t3 = mpi_alloc(mpi_get_nlimbs(p));
+ t4 = mpi_alloc(mpi_get_nlimbs(p));
+ t5 = mpi_alloc(mpi_get_nlimbs(p));
+ t6 = mpi_alloc(mpi_get_nlimbs(p));
+ t7 = mpi_alloc(mpi_get_nlimbs(p));
+
+ if( DBG_MPI )log_info("Add two points.\n");
+
+ if ((!mpi_cmp(P1->x_,P0->x_)) && (!mpi_cmp(P1->y_,P0->y_)) && (!mpi_cmp(P1->z_,P0->z_))){// P1=P0
+ duplicatePoint(P0,P2,base);
+ }
+ else if (PointAtInfinity(*P0)){//(!mpi_cmp_ui(P0->y_,0) || !mpi_cmp_ui(P0->z_,0)){// P2=0+P1=P1
+ P2->x_ = mpi_copy(P1->x_);
+ P2->y_ = mpi_copy(P1->y_);
+ P2->z_ = mpi_copy(P1->z_);
+ }
+ else if (PointAtInfinity(*P1)){//(!mpi_cmp_ui(P1->y_,0) || !mpi_cmp_ui(P1->z_,0)){// P2=P0+0=P0
+ P2->x_ = mpi_copy(P0->x_);
+ P2->y_ = mpi_copy(P0->y_);
+ P2->z_ = mpi_copy(P0->z_);
+ }
+ else {
+ t1 = mpi_copy(P0->x_);//t1=x0
+ t2 = mpi_copy(P0->y_);//t2=y0
+ t3 = mpi_copy(P0->z_);//t3=z0
+ t4 = mpi_copy(P1->x_);//t4=x1
+ t5 = mpi_copy(P1->y_);//t5=y2
+ if (mpi_cmp(P1->z_,one)){//z1!=1
+ t6 = mpi_copy(P1->z_);//t6=z1
+ mpi_powm(t7, t6,two,p);//t7=t6^2 mod p
+ mpi_mulm(t1,t1,t7,p);//t1=t1*t7 mod p
+ mpi_mulm(t7,t6,t7,p);//t7=t6*t7 mod p
+ mpi_mulm(t2,t2,t7,p);//t2=t2*t7 mod p
+ }
+ mpi_powm(t7,t3,two,p);//t7=t3^2 mod p
+ mpi_mulm(t4,t4,t7,p);//t4=t4*t7 mod p
+ mpi_mulm(t7,t3,t7,p);//t7=t3*t7 mod p
+ mpi_mulm(t5,t5,t7,p);//t5=t5*t7 mod p
+ mpi_subm(t4,t1,t4,p);//t4=t1-t4 mod p
+ mpi_subm(t5,t2,t5,p);//t5=t2-t5 mod p
+ if (!mpi_cmp_ui(t4,0)){//t4==0
+ if (!mpi_cmp_ui(t5,0)){//return (0:0:0), it have an special mean.
+ if( DBG_MPI )log_info("Point Addition: [0:0:0]!\n");
+ P2->x_ = mpi_copy(mpi_alloc_set_ui(0));
+ P2->y_ = mpi_copy(mpi_alloc_set_ui(0));
+ P2->z_ = mpi_copy(mpi_alloc_set_ui(0));
+ }
+ else {//return (1:1:0)
+ if( DBG_MPI )log_info("Point Addition: [1:1:0]!\n");
+ P2->x_ = mpi_copy(one);
+ P2->y_ = mpi_copy(one);
+ P2->z_ = mpi_copy(mpi_alloc_set_ui(0));
+ }
+ }
+ else{
+ mpi_mulm(t1,two,t1,p);
+ mpi_subm(t1,t1,t4,p);//t1=2*t1-t4 mod p
+ mpi_mulm(t2,two,t2,p);
+ mpi_subm(t2,t2,t5,p);//t2=2*t2-t5 mod p
+ if (mpi_cmp(P1->z_,one)){//z1!=1
+ mpi_mulm(t3,t3,t6,p);//t3=t3*t6
+ }
+ mpi_mulm(t3,t3,t4,p);//t3=t3*t4 mod p
+ mpi_powm(t7,t4,two,p);//t7=t4^2 mod p
+ mpi_mulm(t4,t4,t7,p);//t4=t4*t7 mod p
+ mpi_mulm(t7,t1,t7,p);//t7=t1*t7 mod p
+ mpi_powm(t1,t5,two,p);//t1=t5^2 mod p
+ mpi_subm(t1,t1,t7,p);//t1=t1-t7 mod p
+ mpi_mulm(t6,two,t1,p);
+ mpi_subm(t7,t7,t6,p);//t7=t7-2*t1 mod p
+ mpi_mulm(t5,t5,t7,p);//t5=t5*t7 mod p
+ mpi_mulm(t4,t2,t4,p);//t4=t2*t4 mod p
+ mpi_subm(t2,t5,t4,p);//t2=t5-t4 mod p
+ mpi_invm(t6,two,p);
+ mpi_mulm(t2,t2,t6,p);//t2 = t2/2
+
+ P2->x_ = mpi_copy(t1);
+ P2->y_ = mpi_copy(t2);
+ P2->z_ = mpi_copy(t3);
+ }
+ }
+ mpi_free(t7);
+ mpi_free(t6);
+ mpi_free(t5);
+ mpi_free(t4);
+ mpi_free(t3);
+ mpi_free(t2);
+ mpi_free(t1);
+ mpi_free(p);
+ mpi_free(two);
+ mpi_free(one);
+}
+
+/****************
+ * Scalar multiplication of one point, with the integer fixed to 2.
+ */
+static void
+duplicatePoint(point *P, point *R, ellipticCurve *base){
+
+ MPI one,two,three,four,eight;
+ MPI p,p_3,a;
+ MPI t1,t2,t3,t4,t5,t6,t7;
+ MPI aux;
+
+ one = mpi_alloc_set_ui(1);
+ two = mpi_alloc_set_ui(2);
+ three = mpi_alloc_set_ui(3);
+ four = mpi_alloc_set_ui(4);
+ eight = mpi_alloc_set_ui(8);
+ p = mpi_copy(base->p_);
+ p_3 = mpi_alloc(mpi_get_nlimbs(p));
+ mpi_sub_ui(p_3,p,3);
+ a = mpi_copy(base->a_);
+ t1 = mpi_alloc(mpi_get_nlimbs(p));
+ t2 = mpi_alloc(mpi_get_nlimbs(p));
+ t3 = mpi_alloc(mpi_get_nlimbs(p));
+ t4 = mpi_alloc(mpi_get_nlimbs(p));
+ t5 = mpi_alloc(mpi_get_nlimbs(p));
+ t6 = mpi_alloc(mpi_get_nlimbs(p));
+ t7 = mpi_alloc(mpi_get_nlimbs(p));
+ aux= mpi_alloc(mpi_get_nlimbs(p));
+
+ if( DBG_MPI ){log_info("Duplicate a point.\n");}
+
+ t1 = mpi_copy(P->x_);//t1=x1
+ t2 = mpi_copy(P->y_);//t2=y1
+ t3 = mpi_copy(P->z_);//t3=z1
+
+ if (!mpi_cmp_ui(t2,0) || !mpi_cmp_ui(t3,0)){//t2==0 | t3==0 => [1:1:0]
+ if( DBG_MPI ){log_info("t2==0 | t3==0\n");}
+ R->x_ = mpi_copy(one);
+ R->y_ = mpi_copy(one);
+ R->z_ = mpi_copy(mpi_alloc_set_ui(0));
+ }
+ else{
+ mpi_fdiv_r(a,a,p);//a mod p
+ if (!mpi_cmp(a,p_3)){//a==p-3
+ mpi_powm(t4,t3,two,p);//t4=t3^2 mod p
+ mpi_subm(t5,t1,t4,p);//t5=t1-t4 mod p
+ mpi_addm(t4,t1,t4,p);//t4=t1+t4 mod p
+ mpi_mulm(t5,t4,t5,p);//t5=t4*t5 mod p
+ mpi_mulm(t4,three,t5,p);//t4=3*t5 mod p
+ }
+ else{
+ t4 = mpi_copy(a);//t4=a
+ mpi_powm(t5,t3,two,p);//t5=t3^2 mod p
+ mpi_powm(t5,t5,two,p);//t5=t5^2 mod p
+ mpi_mulm(t5,t4,t5,p);//t5=t4*t5 mod p
+ mpi_powm(t4,t1,two,p);//t4=t1^2 mod p
+ mpi_mulm(t4,three,t4,p);//t4=3*t4 mod p
+ mpi_addm(t4,t4,t5,p);//t4=t4+t5 mod p
+ }
+ if( DBG_MPI ){log_info("t2!=0 & t3!=0\n");}
+ mpi_mulm(t3,t2,t3,p);//t3=t2*t3 mod p
+ mpi_mulm(t3,two,t3,p);//t3=2*t3 mod p
+ mpi_powm(aux,t2,two,p);//t2=t2^2 mod p
+ t2 = mpi_copy(aux);
+ mpi_mulm(t5,t1,t2,p);//t5=t1*t2 mod p
+ mpi_mulm(t5,four,t5,p);//t5=4*t5 mod p
+ mpi_powm(t1,t4,two,p);//t1=t4^2 mod p
+ mpi_mulm(aux,two,t5,p);
+ mpi_subm(t1,t1,aux,p);//t1=t1-2*t5 mod p
+ mpi_powm(aux,t2,two,p);//t2=t2^2 mod p
+ t2 = mpi_copy(aux);
+ mpi_mulm(t2,eight,t2,p);//t2=8*t2 mod p
+ mpi_subm(t5,t5,t1,p);//t5=t5-t1 mod p
+ mpi_mulm(t5,t4,t5,p);//t5=t4*t5 mod p
+ mpi_subm(t2,t5,t2,p);//t2=t5-t2 mod p
+
+ R->x_ = mpi_copy(t1);
+ R->y_ = mpi_copy(t2);
+ R->z_ = mpi_copy(t3);
+ }
+ if( DBG_MPI ){log_info("Duplicated point.\n");}
+
+ mpi_free(aux);
+ mpi_free(t7);
+ mpi_free(t6);
+ mpi_free(t5);
+ mpi_free(t4);
+ mpi_free(t3);
+ mpi_free(t2);
+ mpi_free(t1);
+ mpi_free(p);
+ mpi_free(p_3);
+ mpi_free(a);
+ mpi_free(eight);
+ mpi_free(four);
+ mpi_free(three);
+ mpi_free(two);
+ mpi_free(one);
+
+}
+
+/****************
+ * The point inversion over F_p
+ * is a simple modular inversion
+ * of the Y coordinate.
+ */
+static void
+invertPoint(point *P, ellipticCurve *base){
+
+ mpi_subm(P->y_,base->p_,P->y_,base->p_);//y=p-y mod p
+}
+
+/****************
+ * Auxiliar function to made easy a struct copy.
+ */
+static point
+point_copy(point P){
+ point R;
+
+ R.x_ = mpi_copy(P.x_);
+ R.y_ = mpi_copy(P.y_);
+ R.z_ = mpi_copy(P.z_);
+
+ return R;
+}
+
+/****************
+ * Made easy the free memory for a point struct.
+ */
+static void
+point_free(point *P){
+
+ mpi_free(P->x_);
+ mpi_free(P->y_);
+ mpi_free(P->z_);
+}
+
+/****************
+ * Turn a projective coordinate to affine, return 0 (or 1 in error case).
+ * Needed to verify a signature.
+ *
+ * y_coordinate it is never used, we could do without it. //!!
+ */
+static int
+point_affine(point *P, MPI x, MPI y, ellipticCurve *base){
+
+ //MPI z;
+ MPI z1,z2,z3;
+
+ z1 = mpi_alloc(0);
+ z2 = mpi_alloc(0);
+ z3 = mpi_alloc(0);
+
+ if (PointAtInfinity(*P)){
+ if( DBG_CIPHER )log_info("Affine: Point at Infinity does NOT exist in the affine plane!\n");
+ return 1;
+ }
+
+ mpi_invm(z1,P->z_,base->p_); // z1 =Z^{-1} (mod p)
+ mpi_mulm(z2,z1,z1,base->p_); // z2 =Z^(-2) (mod p)
+ mpi_mulm(z3,z2,z1,base->p_); // z3 =Z^(-3) (mod p)
+ mpi_mulm(x,P->x_,z2,base->p_);
+ mpi_mulm(y,P->y_,z3,base->p_);
+
+ mpi_free(z1);
+ mpi_free(z2);
+ mpi_free(z3);
+ return 0;
+}
+
+/****************
+ * Auxiliar function to made easy a struct copy.
+ */
+static ellipticCurve
+curve_copy(ellipticCurve E){
+
+ ellipticCurve R;
+
+ R.p_ = mpi_copy(E.p_);
+ R.a_ = mpi_copy(E.a_);
+ R.b_ = mpi_copy(E.b_);
+ R.G = point_copy(E.G);
+ R.n_ = mpi_copy(E.n_);
+
+ return R;
+}
+
+/****************
+ * Made easy the free memory for a setup struct.
+ */
+static void
+curve_free(ellipticCurve *E){
+ mpi_free(E->p_);
+ mpi_free(E->a_);
+ mpi_free(E->b_);
+ point_free(&E->G);
+ mpi_free(E->n_);
+}
+
+/****************
+ * Boolean generator to choose between to coordinates.
+ */
+static MPI
+gen_bit(){
+
+ MPI aux = mpi_alloc_set_ui(0);
+
+ //Get one random bit, with less security level, and translate it to an MPI.
+ mpi_set_buffer( aux, get_random_bits( 1, 0, 1 ), 1, 0 );//gen_k(...)
+
+ return aux;//b;
+}
+
+/****************
+ * Solve the right side of the equation that define a curve.
+ */
+static MPI
+gen_y_2(MPI x, ellipticCurve *base){
+
+ MPI three;
+ MPI x_3,ax,axb,y;
+ MPI a,b,p;
+
+ three = mpi_alloc_set_ui(3);
+ a = mpi_copy(base->a_);
+ b = mpi_copy(base->b_),
+ p = mpi_copy(base->p_);
+ x_3 = mpi_alloc(mpi_get_nlimbs(p));
+ ax = mpi_alloc(mpi_get_nlimbs(p));
+ axb = mpi_alloc(mpi_get_nlimbs(p));
+ y = mpi_alloc(mpi_get_nlimbs(p));
+
+ if( DBG_MPI )log_info("solving an elliptic equation.\n");
+
+ mpi_powm(x_3,x,three,p);//x_3=x^3 mod p
+ mpi_mulm(ax,a,x,p);//ax=a*x mod p
+ mpi_addm(axb,ax,b,p);//axb=ax+b mod p
+ mpi_addm(y,x_3,axb,p);//y=x^3+ax+b mod p
+
+ if( DBG_MPI )log_info("solved.\n");
+
+ return y;//the quadratic value of the coordinate if it exist.
+}
+
+//Function to solve an IFP ECElGamal weakness:
+// sha256_hashing()
+// aes256_encrypting()
+// aes356_decrypting()
+
+/****************
+ * Compute 256 bit hash value from input MPI.
+ * Use SHA256 Algorithm.
+ */
+static void
+sha256_hashing(MPI input, MPI *output){ //
+
+ int sign;
+ byte *hash_inp_buf;
+ byte hash_out_buf[32];
+ MD_HANDLE hash = md_open(8,1);//algo SHA256 in secure mode
+
+ unsigned int nbytes;
+
+ hash_inp_buf = mpi_get_secure_buffer( input, &nbytes, &sign );//convert MPI input to string
+
+ md_write( hash, hash_inp_buf, nbytes );//hashing input string
+ wipememory( hash_inp_buf, sizeof hash_inp_buf ); // burn temp value
+ xfree(hash_inp_buf);
+
+ md_digest(hash, 8, hash_out_buf, 32);
+ mpi_set_buffer( *output, hash_out_buf, 32, 0 );// convert 256 bit digest to MPI
+
+ wipememory( hash_out_buf, sizeof hash_out_buf ); // burn temp value
+ md_close(hash);// destroy and free hash state.
+
+}
+
+/****************
+ * Encrypt input MPI.
+ * Use AES256 algorithm.
+ */
+
+static void
+aes256_encrypting(MPI key, MPI input, MPI *output){ //
+
+ int sign;
+ byte *key_buf;
+ byte *cipher_buf;
+
+ unsigned int keylength;
+ unsigned int nbytes;
+
+
+ CIPHER_HANDLE cipher = cipher_open(9,CIPHER_MODE_CFB,1);//algo AES256 CFB mode in secure memory
+ cipher_setiv( cipher, NULL, 0 ); // Zero IV
+
+ key_buf = mpi_get_secure_buffer( key, &keylength, &sign );//convert MPI key to string
+ cipher_setkey( cipher, key_buf, keylength );
+ wipememory( key_buf, sizeof key_buf ); // burn temp value
+ xfree(key_buf);
+
+ cipher_buf = mpi_get_secure_buffer( input, &nbytes, &sign );//convert MPI input to string
+
+ cipher_encrypt( cipher, cipher_buf+1, cipher_buf+1, nbytes-1);//
+ cipher_close(cipher);// destroy and free cipher state.
+
+ mpi_set_buffer( *output, cipher_buf, nbytes, 0 );// convert encrypted string to MPI
+ wipememory( cipher_buf, sizeof cipher_buf ); // burn temp value
+ xfree(cipher_buf);
+}
+
+/****************
+ * Decrypt input MPI.
+ * Use AES256 algorithm.
+ */
+
+static void
+aes256_decrypting(MPI key, MPI input, MPI *output){ //
+
+ int sign;
+ byte *key_buf;
+ byte *cipher_buf;
+
+ unsigned int keylength;
+ unsigned int nbytes;
+
+
+ CIPHER_HANDLE cipher = cipher_open(9,CIPHER_MODE_CFB,1);//algo AES256 CFB mode in secure memory
+ cipher_setiv( cipher, NULL, 0 ); // Zero IV
+
+ key_buf = mpi_get_secure_buffer( key, &keylength, &sign );//convert MPI input to string
+ cipher_setkey( cipher, key_buf, keylength );
+ wipememory( key_buf, sizeof key_buf ); // burn temp value
+ xfree(key_buf);
+
+ cipher_buf = mpi_get_secure_buffer( input, &nbytes, &sign );//convert MPI input to string;
+
+ cipher_decrypt( cipher, cipher_buf+1, cipher_buf+1, nbytes-1 );//
+ cipher_close(cipher);// destroy and free cipher state.
+
+ mpi_set_buffer( *output, cipher_buf, nbytes, 0 );// convert encrypted string to MPI
+ wipememory( cipher_buf, sizeof cipher_buf ); // burn temp value
+ xfree(cipher_buf);
+}
+//End of IFP ECElGamal weakness functions.
+
+/*********************************************
+ ************** interface ******************
+ *********************************************/
+int
+ecc_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
+{
+
+ ECC_secret_key sk;
+
+ if( !is_ECC(algo) )
+ return G10ERR_PUBKEY_ALGO;
+
+ generateKey( &sk, nbits, retfactors );
+
+ skey[0] = sk.E.p_;
+ skey[1] = sk.E.a_;
+ skey[2] = sk.E.b_;
+ skey[3] = sk.E.G.x_;
+ skey[4] = sk.E.G.y_;
+ skey[5] = sk.E.G.z_;
+ skey[6] = sk.E.n_;
+ skey[7] = sk.Q.x_;
+ skey[8] = sk.Q.y_;
+ skey[9] = sk.Q.z_;
+ skey[10] = sk.d;
+
+ if( DBG_CIPHER ) {
+ progress('\n');
+
+ log_mpidump("[ecc] p= ", skey[0]);
+ log_mpidump("[ecc] a= ", skey[1]);
+ log_mpidump("[ecc] b= ", skey[2]);
+ log_mpidump("[ecc] Gx= ", skey[3]);
+ log_mpidump("[ecc] Gy= ", skey[4]);
+ log_mpidump("[ecc] Gz= ", skey[5]);
+ log_mpidump("[ecc] n= ", skey[6]);
+ log_mpidump("[ecc] Qx= ", skey[7]);
+ log_mpidump("[ecc] Qy= ", skey[8]);
+ log_mpidump("[ecc] Qz= ", skey[9]);
+ log_mpidump("[ecc] d= ", skey[10]);
+ }
+
+ if( DBG_CIPHER ){log_info("ECC key Generated.\n");}
+ return 0;
+}
+
+
+int
+ecc_check_secret_key( int algo, MPI *skey )
+{
+ ECC_secret_key sk;
+
+ if( !is_ECC(algo) )
+ return G10ERR_PUBKEY_ALGO;
+ if(!skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4] || !skey[5] || !skey[6] || !skey[7] || !skey[8] || !skey[9] || !skey[10])
+ return G10ERR_BAD_MPI;
+
+ if( DBG_CIPHER ){log_info("ECC check secret key.\n");}
+ sk.E.p_ = skey[0];
+ sk.E.a_ = skey[1];
+ sk.E.b_ = skey[2];
+ sk.E.G.x_ = skey[3];
+ sk.E.G.y_ = skey[4];
+ sk.E.G.z_ = skey[5];
+ sk.E.n_ = skey[6];
+ sk.Q.x_ = skey[7];
+ sk.Q.y_ = skey[8];
+ sk.Q.z_ = skey[9];
+ sk.d = skey[10];
+
+ if( check_secret_key(&sk)){
+ if( DBG_CIPHER )log_info("Bad check: Bad secret key.\n");
+ return G10ERR_BAD_SECKEY;
+ }
+ return 0;
+}
+
+
+
+int
+ecc_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
+{
+ ECC_public_key pk;
+ point R;
+
+ if( algo != PUBKEY_ALGO_ECC && algo != PUBKEY_ALGO_ECC_E )
+ return G10ERR_PUBKEY_ALGO;
+ if( !data || !pkey[0] || !pkey[1] || !pkey[2] || !pkey[3] || !pkey[4] || !pkey[5] || !pkey[6] || !pkey[7] || !pkey[8] || !pkey[9])
+ return G10ERR_BAD_MPI;
+
+ if( DBG_CIPHER ){log_info("ECC encrypt.\n");}
+ pk.E.p_ = pkey[0];
+ pk.E.a_ = pkey[1];
+ pk.E.b_ = pkey[2];
+ pk.E.G.x_ = pkey[3];
+ pk.E.G.y_ = pkey[4];
+ pk.E.G.z_ = pkey[5];
+ pk.E.n_ = pkey[6];
+ pk.Q.x_ = pkey[7];
+ pk.Q.y_ = pkey[8];
+ pk.Q.z_ = pkey[9];
+
+ R.x_ = resarr[0] = mpi_alloc( mpi_get_nlimbs( pk.Q.x_ ) );
+ R.y_ = resarr[1] = mpi_alloc( mpi_get_nlimbs( pk.Q.y_ ) );
+ R.z_ = resarr[2] = mpi_alloc( mpi_get_nlimbs( pk.Q.z_ ) );
+ resarr[3] = mpi_alloc( mpi_get_nlimbs( pk.E.p_ ) );
+
+ doEncrypt(data, &pk, &R, resarr[3]);
+
+ resarr[0] = mpi_copy(R.x_);
+ resarr[1] = mpi_copy(R.y_);
+ resarr[2] = mpi_copy(R.z_);
+ return 0;
+}
+
+int
+ecc_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
+{
+ ECC_secret_key sk;
+ point R;
+
+ if( algo != PUBKEY_ALGO_ECC && algo != PUBKEY_ALGO_ECC_E )
+ return G10ERR_PUBKEY_ALGO;
+ if( !data[0] || !data[1] || !data[2] || !data[3] || !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4] || !skey[5] || !skey[6] || !skey[7] || !skey[8] || !skey[9] || !skey[10])
+ return G10ERR_BAD_MPI;
+
+ if( DBG_CIPHER ){log_info("ECC decrypt.\n");}
+ R.x_ = data[0];
+ R.y_ = data[1];
+ R.z_ = data[2];
+ sk.E.p_ = skey[0];
+ sk.E.a_ = skey[1];
+ sk.E.b_ = skey[2];
+ sk.E.G.x_ = skey[3];
+ sk.E.G.y_ = skey[4];
+ sk.E.G.z_ = skey[5];
+ sk.E.n_ = skey[6];
+ sk.Q.x_ = skey[7];
+ sk.Q.y_ = skey[8];
+ sk.Q.z_ = skey[9];
+ sk.d = skey[10];
+
+ *result = mpi_alloc_secure( mpi_get_nlimbs( sk.E.p_ ) );
+ *result = decrypt( *result, &sk, R, data[3]);
+ return 0;
+}
+
+int
+ecc_sign( int algo, MPI *resarr, MPI data, MPI *skey )
+{
+ ECC_secret_key sk;
+
+ if( algo != PUBKEY_ALGO_ECC && algo != PUBKEY_ALGO_ECC_S )
+ return G10ERR_PUBKEY_ALGO;
+ if( !data || !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4] || !skey[5] || !skey[6] || !skey[7] || !skey[8] || !skey[9] || !skey[10])
+ return G10ERR_BAD_MPI;
+
+ sk.E.p_ = skey[0];
+ sk.E.a_ = skey[1];
+ sk.E.b_ = skey[2];
+ sk.E.G.x_ = skey[3];
+ sk.E.G.y_ = skey[4];
+ sk.E.G.z_ = skey[5];
+ sk.E.n_ = skey[6];
+ sk.Q.x_ = skey[7];
+ sk.Q.y_ = skey[8];
+ sk.Q.z_ = skey[9];
+ sk.d = skey[10];
+
+ resarr[0] = mpi_alloc( mpi_get_nlimbs( sk.E.p_ ) );
+ resarr[1] = mpi_alloc( mpi_get_nlimbs( sk.E.p_ ) );
+ sign( data, &sk, &resarr[0], &resarr[1]);
+ return 0;
+}
+
+int
+ecc_verify( int algo, MPI hash, MPI *data, MPI *pkey )
+{
+ ECC_public_key pk;
+
+ if( algo != PUBKEY_ALGO_ECC && algo != PUBKEY_ALGO_ECC_S )
+ return G10ERR_PUBKEY_ALGO;
+ if( !data[0] || !data[1] || !hash || !pkey[0] || !pkey[1] || !pkey[2] || !pkey[3] || !pkey[4] || !pkey[5] || !pkey[6] || !pkey[7] || !pkey[8] || !pkey[9])
+ return G10ERR_BAD_MPI;
+
+ if( DBG_CIPHER ){log_info("ECC verify.\n");}
+ pk.E.p_ = pkey[0];
+ pk.E.a_ = pkey[1];
+ pk.E.b_ = pkey[2];
+ pk.E.G.x_ = pkey[3];
+ pk.E.G.y_ = pkey[4];
+ pk.E.G.z_ = pkey[5];
+ pk.E.n_ = pkey[6];
+ pk.Q.x_ = pkey[7];
+ pk.Q.y_ = pkey[8];
+ pk.Q.z_ = pkey[9];
+
+ if( !verify( hash, &pk, data[0], data[1]) )
+ return G10ERR_BAD_SIGN;
+ return 0;
+}
+
+
+
+unsigned int
+ecc_get_nbits( int algo, MPI *pkey )
+{
+ if ( !is_ECC(algo) ){
+ return 0;
+ }
+ if( DBG_CIPHER ){log_info("ECC get nbits.\n");}
+
+ if( DBG_CIPHER ) {
+ progress('\n');
+
+ log_mpidump("[ecc] p= ", pkey[0]);
+ log_mpidump("[ecc] a= ", pkey[1]);
+ log_mpidump("[ecc] b= ", pkey[2]);
+ log_mpidump("[ecc] Gx= ", pkey[3]);
+ log_mpidump("[ecc] Gy= ", pkey[4]);
+ log_mpidump("[ecc] Gz= ", pkey[5]);
+ log_mpidump("[ecc] n= ", pkey[6]);
+ log_mpidump("[ecc] Qx= ", pkey[7]);
+ log_mpidump("[ecc] Qy= ", pkey[8]);
+ log_mpidump("[ecc] Qz= ", pkey[9]);
+ }
+
+ return mpi_get_nbits( pkey[0] );
+}
+
+const char *
+ecc_get_info( int algo, int *npkey, int *nskey, int *nenc, int *nsig, int *use )
+{
+ *npkey = 10;
+ *nskey = 11;
+ *nenc = 4;
+ *nsig = 2;
+
+ if( DBG_CIPHER ){log_info("ECC get info.\n");}
+ switch( algo ) {
+ case PUBKEY_ALGO_ECC:
+ *use = PUBKEY_USAGE_SIG|PUBKEY_USAGE_ENC;
+ return "ECC";
+ case PUBKEY_ALGO_ECC_S:
+ *use = PUBKEY_USAGE_SIG;
+ return "ECDSA";
+ case PUBKEY_ALGO_ECC_E:
+ *use = PUBKEY_USAGE_ENC;
+ return "ECELG";
+ default: *use = 0; return NULL;
+ }
+}