aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/examples/Makefile4
-rw-r--r--doc/examples/ecdsa.cpp16
-rw-r--r--doc/license.txt3
-rw-r--r--include/bigint.h3
-rw-r--r--include/curve_gfp.h165
-rw-r--r--include/ec.h376
-rw-r--r--include/ec_dompar.h115
-rw-r--r--include/ecdsa.h100
-rw-r--r--include/engine.h17
-rw-r--r--include/gfp_element.h308
-rw-r--r--include/gfp_modulus.h124
-rw-r--r--include/pk_core.h53
-rw-r--r--include/pk_ops.h32
-rw-r--r--include/point_gfp.h307
-rw-r--r--include/rsa.h1
-rw-r--r--src/curve_gfp.cpp157
-rw-r--r--src/ec.cpp533
-rw-r--r--src/ec_dompar.cpp288
-rw-r--r--src/ecdsa.cpp72
-rw-r--r--src/eng_base.cpp20
-rw-r--r--src/engine.cpp38
-rw-r--r--src/gfp_element.cpp674
-rw-r--r--src/pk_core.cpp78
-rw-r--r--src/point_gfp.cpp1157
24 files changed, 4639 insertions, 2 deletions
diff --git a/doc/examples/Makefile b/doc/examples/Makefile
index 6706aaaf6..a25782f89 100644
--- a/doc/examples/Makefile
+++ b/doc/examples/Makefile
@@ -65,6 +65,10 @@ encrypt: encrypt.cpp
$(CXX) $(FLAGS) $? $(LIBS) -o $@
@$(STRIP) $@
+ecdsa: ecdsa.cpp
+ $(CXX) $(FLAGS) $? $(LIBS) -o $@
+ @$(STRIP) $@
+
factor: factor.cpp
$(CXX) $(FLAGS) $? $(LIBS) -o $@
@$(STRIP) $@
diff --git a/doc/examples/ecdsa.cpp b/doc/examples/ecdsa.cpp
new file mode 100644
index 000000000..6b6bb65e5
--- /dev/null
+++ b/doc/examples/ecdsa.cpp
@@ -0,0 +1,16 @@
+#include <botan/botan.h>
+#include <botan/ec.h>
+
+#include <memory>
+
+using namespace Botan;
+
+int main()
+ {
+ std::auto_ptr<RandomNumberGenerator> rng(RandomNumberGenerator::make_rng());
+
+ EC_Domain_Params params = get_EC_Dom_Pars_by_oid("1.3.132.8");
+
+ ECDSA_PrivateKey ecdsa(rng, params);
+
+ }
diff --git a/doc/license.txt b/doc/license.txt
index c0fb58c10..1b36b84c7 100644
--- a/doc/license.txt
+++ b/doc/license.txt
@@ -7,6 +7,9 @@ Copyright (C) 1999-2008 Jack Lloyd
2007 Yves Jerschow
2007-2008 FlexSecure GmbH
2007-2008 Falko Strenzke
+ 2007 Martin Doering
+ 2007 Manuel Hartl
+ 2007 Christoph Ludwig
Redistribution and use in source and binary forms, for any use, with or without
modification, is permitted provided that the following conditions are met:
diff --git a/include/bigint.h b/include/bigint.h
index c1dbc7171..194516518 100644
--- a/include/bigint.h
+++ b/include/bigint.h
@@ -77,7 +77,9 @@ class BOTAN_DLL BigInt
const word* data() const { return reg.begin(); }
SecureVector<word>& get_reg() { return reg; }
+
void grow_reg(u32bit) const;
+ void grow_to(u32bit) const;
word& operator[](u32bit);
word operator[](u32bit) const;
@@ -107,7 +109,6 @@ class BOTAN_DLL BigInt
BigInt(Sign, u32bit);
BigInt(NumberType, u32bit);
private:
- void grow_to(u32bit) const;
SecureVector<word> reg;
Sign signedness;
};
diff --git a/include/curve_gfp.h b/include/curve_gfp.h
new file mode 100644
index 000000000..49688b5dc
--- /dev/null
+++ b/include/curve_gfp.h
@@ -0,0 +1,165 @@
+/******************************************************
+ * Elliptic curves over GF(p) (header file) *
+ * *
+ * (C) 2007 Martin Doering *
+ * Christoph Ludwig *
+ * Falko Strenzke *
+ ******************************************************/
+
+#ifndef BOTAN_EC_CURVE_GFP_H__
+#define BOTAN_EC_CURVE_GFP_H__
+
+#include <botan/gfp_element.h>
+#include <botan/bigint.h>
+#include <tr1/memory>
+
+namespace Botan {
+
+/**
+* This class represents an elliptic curve over GF(p)
+*/
+class CurveGFp
+ {
+ public:
+ /**
+ * Construct the elliptic curve E: y^2 = x^3 + ax + b over GF(p)
+ * @param a first coefficient
+ * @param b second coefficient
+ * @param p prime number of the field
+ */
+ CurveGFp(GFpElement const& a, GFpElement const& b,
+ const BigInt& p);
+
+ /**
+ * Copy constructor
+ * @param other The curve to clone
+ */
+ CurveGFp(CurveGFp const& other);
+
+ /**
+ * Assignment operator
+ * @param other The curve to use as source for the assignment
+ */
+ CurveGFp const& operator=(CurveGFp const& other);
+
+ /**
+ * Set the shared GFpModulus object.
+ * Warning: do not use this function unless you know in detail how
+ * the sharing of values
+ * in the various EC related objects works.
+ * Do NOT spread pointers to a GFpModulus over different threads!
+ * @param mod a shared pointer to a GFpModulus object suitable for
+ * *this.
+ */
+ void set_shrd_mod(std::tr1::shared_ptr<Botan::GFpModulus> const mod);
+
+ // getters
+
+ /**
+ * Get coefficient a
+ * @result coefficient a
+ */
+ GFpElement const get_a() const;
+
+ /**
+ * Get coefficient b
+ * @result coefficient b
+ */
+ GFpElement const get_b() const;
+
+ /**
+ * Get the GFpElement coefficient a transformed
+ * to its m-residue. This can be used for efficency reasons: the curve
+ * stores the transformed version after the first invocation of this
+ * function.
+ * @result the coefficient a, transformed to its m-residue
+ */
+ GFpElement const get_mres_a() const;
+
+ /**
+ * Get the GFpElement coefficient b transformed
+ * to it´s m-residue. This can be used for efficency reasons: the curve
+ * stores the transformed version after the first invocation of this
+ * function.
+ * @result the coefficient b, transformed to it´s m-residue
+ */
+ GFpElement const get_mres_b() const;
+
+
+ /**
+ * Get the GFpElement 1 transformed
+ * to it´s m-residue. This can be used for efficency reasons: the curve
+ * stores the transformed version after the first invocation of this
+ * function.
+ * @result the GFpElement 1, transformed to it´s m-residue
+ */
+ std::tr1::shared_ptr<GFpElement const> const get_mres_one() const;
+
+ /**
+ * Get prime modulus of the field of the curve
+ * @result prime modulus of the field of the curve
+ */
+ BigInt const get_p() const;
+ /*inline std::tr1::shared_ptr<BigInt> const get_ptr_p() const
+ {
+ return mp_p;
+ }*/
+
+ /**
+ * Retrieve a shared pointer to the curves GFpModulus object for efficient storage
+ * and computation of montgomery multiplication related data members and functions.
+ * Warning: do not use this function unless you know in detail how the sharing of values
+ * in the various EC related objects works.
+ * Do NOT spread pointers to a GFpModulus over different threads!
+ * @result a shared pointer to a GFpModulus object
+ */
+ inline std::tr1::shared_ptr<Botan::GFpModulus> const get_ptr_mod() const
+ {
+ return mp_mod;
+ }
+
+ /**
+ * swaps the states of *this and other, does not throw
+ * @param other The curve to swap values with
+ */
+ void swap(CurveGFp& other);
+
+ private:
+ std::tr1::shared_ptr<Botan::GFpModulus> mp_mod;
+ GFpElement mA;
+ GFpElement mB;
+ mutable std::tr1::shared_ptr<GFpElement> mp_mres_a;
+ mutable std::tr1::shared_ptr<GFpElement> mp_mres_b;
+ mutable std::tr1::shared_ptr<GFpElement> mp_mres_one;
+ };
+
+// relational operators
+bool operator==(CurveGFp const& lhs, CurveGFp const& rhs);
+inline bool operator!=(CurveGFp const& lhs, CurveGFp const& rhs) {
+return !operator==(lhs, rhs);
+}
+
+// swaps the states of curve1 and curve2, does not throw!
+// cf. Meyers, Item 25
+inline
+void swap(CurveGFp& curve1, CurveGFp& curve2) {
+curve1.swap(curve2);
+}
+
+}
+
+namespace std {
+
+template<> inline void swap<Botan::CurveGFp>(
+ Botan::CurveGFp& curve1,
+ Botan::CurveGFp& curve2)
+ {
+ curve1.swap(curve2);
+ }
+
+}
+
+#endif
diff --git a/include/ec.h b/include/ec.h
new file mode 100644
index 000000000..5515d641f
--- /dev/null
+++ b/include/ec.h
@@ -0,0 +1,376 @@
+/*************************************************
+* ECDSA Header File *
+* (C) 2007 Falko Strenzke, FlexSecure GmbH *
+* Manuel hartl, FlexSecure GmbH *
+*************************************************/
+
+#ifndef BOTAN_EC_H__
+#define BOTAN_EC_H__
+
+#include <botan/if_algo.h>
+#include <botan/bigint.h>
+#include <botan/curve_gfp.h>
+#include <botan/pk_keys.h>
+#include <botan/ec_dompar.h>
+
+namespace Botan {
+
+/**
+* This class represents abstract EC Public Keys.
+* When encoding a key via an encoder that can be accessed via
+* the corresponding member functions, the key will decide upon its
+* internally stored encoding information whether to encode itself with
+* or without domain parameters, or using the domain parameter oid.
+* Furthermore, a public key
+* without domain parameters can be decoded. In that case, it cannot be used
+* for verification until its domain parameters are set by calling the
+* corresponding member function.
+*/
+class EC_PublicKey : public virtual Public_Key
+ {
+ public:
+
+ /**
+ * Tells whether this key knows his own domain parameters.
+ * @result true if the domain parameters are set, false otherwise
+ */
+ bool domain_parameters_set();
+
+ /**
+ * Get the public point of this key.
+ * @throw Invalid_State is thrown if the
+ * domain parameters of this point are not set
+ * @result the public point of this key
+ */
+ inline Botan::PointGFp get_public_point() const
+ {
+ if (!mp_public_point.get())
+ {
+ throw Invalid_State("EC_PublicKey::get_public_point(): public point not set because ec domain parameters are not yet set");
+ }
+ return *mp_public_point;
+ }
+ /**
+ * Get the domain parameters of this key.
+ * @throw Invalid_State is thrown if the
+ * domain parameters of this point are not set
+ * @result the domain parameters of this key
+ */
+ EC_Domain_Params const get_domain_parameters() const;
+ /**
+ * Set the domain parameter encoding to be used when encoding this key.
+ * @param enc the encoding to use
+ */
+ void set_parameter_encoding(EC_dompar_enc enc);
+ /**
+ * Get the domain parameter encoding to be used when encoding this key.
+ * @result the encoding to use
+ */
+ inline int get_parameter_encoding() const
+ {
+ return m_param_enc;
+ }
+ //ctors
+
+ EC_PublicKey()
+ : m_param_enc(ENC_EXPLICIT)
+ {
+ //assert(mp_dom_pars.get() == 0);
+ //assert(mp_public_point.get() == 0);
+ }
+
+ /**
+ * Get an x509_encoder that can be used to encode this key.
+ * @result an x509_encoder for this key
+ */
+ X509_Encoder* x509_encoder() const;
+ /**
+ * Get an x509_decoder that can be used to decode a stored key into
+ * this key.
+ * @result an x509_decoder for this key
+ */
+ X509_Decoder* x509_decoder();
+
+ /**
+ * Make sure that the public point and domain parameters of this key are set.
+ * @throw Invalid_State if either of the two data members is not set
+ */
+ virtual void affirm_init() const;
+ virtual ~EC_PublicKey()
+ {}
+ protected:
+ virtual void X509_load_hook();
+ SecureVector<byte> m_enc_public_point; // stores the public point
+ // until dom pars are provided
+ std::auto_ptr<EC_Domain_Params> mp_dom_pars;
+ std::auto_ptr<Botan::PointGFp> mp_public_point;
+ mutable EC_dompar_enc m_param_enc;
+ };
+
+/**
+* This abstract class represents general EC Private Keys
+*/
+class EC_PrivateKey : public virtual EC_PublicKey, public virtual Private_Key
+ {
+ public:
+
+ /**
+ * Get an PKCS#8 encoder that can be used to encoded this key.
+ * @result an PKCS#8 encoder for this key
+ */
+ PKCS8_Encoder* pkcs8_encoder() const;
+ /**
+ * Get an PKCS#8 decoder that can be used to decoded a stored key into
+ * this key.
+ * @result an PKCS#8 decoder for this key
+ */
+ PKCS8_Decoder* pkcs8_decoder(RandomNumberGenerator&);
+ /**
+ * Get the private key value of this key object.
+ * @result the private key value of this key object
+ */
+ inline BigInt const get_value() const
+ {
+ return m_private_value;
+ }
+ /**
+ * Make sure that the public key parts of this object are set
+ * (calls EC_PublicKey::affirm_init()) as well as the private key
+ * value.
+ * @throw Invalid_State if the above conditions are not satisfied
+ */
+ virtual void affirm_init() const;
+ virtual ~EC_PrivateKey()
+ {}
+ protected:
+ virtual void PKCS8_load_hook(bool = false);
+ void generate_private_key(RandomNumberGenerator&);
+ BigInt m_private_value;
+ };
+
+/**
+* This class represents ECDSA Public Keys.
+*/
+class ECDSA_PublicKey : public virtual EC_PublicKey, public PK_Verifying_wo_MR_Key
+ {
+ public:
+ /**
+ * Get this keys algorithm name.
+ * @result this keys algorithm name
+ */
+ std::string algo_name() const
+ {
+ return "ECDSA";
+ }
+ /**
+ * Get the maximum number of bits allowed to be fed to this key.
+ * This is the bitlength of the order of the base point.
+ *
+ * @result the maximum number of input bits
+ */
+ u32bit max_input_bits() const;
+ /**
+ * Verify a message with this key.
+ * @param message the byte array containing the message
+ * @param mess_len the number of bytes in the message byte array
+ * @param signature the byte array containing the signature
+ * @param sig_len the number of bytes in the signature byte array
+ */
+ bool verify(const byte message[], u32bit mess_len, const byte signature [], u32bit sig_len) const;
+
+ /**
+ * Default constructor. Use this one if you want to later fill this object with data
+ * from an encoded key.
+ */
+ ECDSA_PublicKey()
+ {}
+ /**
+ * Construct a public key from a given public point.
+ * @param dom_par the domain parameters associated with this key
+ * @param public_point the public point defining this key
+ */
+ ECDSA_PublicKey(EC_Domain_Params const& dom_par, Botan::PointGFp const& public_point); // sets core
+ void X509_load_hook();
+
+ ECDSA_PublicKey const& operator= (ECDSA_PublicKey const& rhs);
+
+ ECDSA_PublicKey(ECDSA_PublicKey const& other);
+
+ /**
+ * Set the domain parameters of this key. This function has to be
+ * used when a key encoded without domain parameters was decoded into
+ * this key. Otherwise it will not be able to verify a signature.
+ * @param dom_pars the domain_parameters associated with this key
+ * @throw Invalid_Argument if the point was found not to be satisfying the
+ * curve equation of the provided domain parameters
+ * or if this key already has domain parameters set
+ * and these are differing from those given as the parameter
+ */
+ void set_domain_parameters(EC_Domain_Params const& dom_pars);
+ /**
+ * Make sure that the public point and domain parameters of this key are set.
+ * @throw Invalid_State if either of the two data members is not set
+ */
+ virtual void affirm_init() const;
+
+
+ protected:
+ virtual void set_all_values(ECDSA_PublicKey const& other);
+
+ ECDSA_Core m_ecdsa_core;
+ };
+/**
+* This class represents ECDSA Public Keys.
+*/
+class ECDSA_PrivateKey : public ECDSA_PublicKey, public EC_PrivateKey, public PK_Signing_Key
+ {
+ public:
+ //ctors
+ /**
+ * Default constructor. Use this one if you want to later fill this object with data
+ * from an encoded key.
+ */
+ ECDSA_PrivateKey()
+ {}
+ /**
+ * Generate a new private key
+ * @param the domain parameters to used for this key
+ */
+ ECDSA_PrivateKey(RandomNumberGenerator& rng,
+ EC_Domain_Params const& dom_pars)
+ {
+ mp_dom_pars = std::auto_ptr<EC_Domain_Params>(new EC_Domain_Params(dom_pars));
+ generate_private_key(rng);
+ mp_public_point->check_invariants();
+ m_ecdsa_core = ECDSA_Core(*mp_dom_pars, m_private_value, *mp_public_point);
+ }
+ ECDSA_PrivateKey(ECDSA_PrivateKey const& other);
+ ECDSA_PrivateKey const& operator= (ECDSA_PrivateKey const& rhs);
+
+ /**
+ * Sign a message with this key.
+ * @param message the byte array representing the message to be signed
+ * @param mess_len the length of the message byte array
+ * @result the signature
+ */
+ SecureVector<byte> sign(const byte message[], u32bit mess_len) const;
+ /**
+ * Make sure that the public key parts of this object are set
+ * (calls EC_PublicKey::affirm_init()) as well as the private key
+ * value.
+ * @throw Invalid_State if the above conditions are not satisfied
+ */
+ virtual void affirm_init() const;
+ protected:
+ virtual void set_all_values ( ECDSA_PrivateKey const& other );
+ private:
+ void PKCS8_load_hook(bool = false);
+ };
+
+/**
+* This class represents ECKAEG Public Keys.
+*/
+class ECKAEG_PublicKey : public virtual EC_PublicKey
+ {
+ public:
+ /**
+ * Default constructor. Use this one if you want to later fill this object with data
+ * from an encoded key.
+ */
+ ECKAEG_PublicKey()
+ {};
+ /**
+ * Construct a public key from a given public point.
+ * @param dom_par the domain parameters associated with this key
+ * @param public_point the public point defining this key
+ */
+ ECKAEG_PublicKey(EC_Domain_Params const& dom_par, Botan::PointGFp const& public_point);
+
+ /**
+ * Get this keys algorithm name.
+ * @result this keys algorithm name
+ */
+ std::string algo_name() const
+ {
+ return "ECKAEG";
+ }
+ /**
+ * Get the maximum number of bits allowed to be fed to this key.
+ * This is the bitlength of the order of the base point.
+ *
+ * @result the maximum number of input bits
+ */
+ u32bit max_input_bits() const
+ {
+ if (!mp_dom_pars.get())
+ {
+ throw Invalid_State("ECKAEG_PublicKey::max_input_bits(): domain parameters not set");
+ }
+ return mp_dom_pars->get_order().bits();
+ }
+ ECKAEG_PublicKey(ECKAEG_PublicKey const& other);
+ ECKAEG_PublicKey const& operator= (ECKAEG_PublicKey const& rhs);
+
+
+ /**
+ * Make sure that the public point and domain parameters of this key are set.
+ * @throw Invalid_State if either of the two data members is not set
+ */
+ virtual void affirm_init() const;
+ protected:
+ void X509_load_hook();
+ virtual void set_all_values ( ECKAEG_PublicKey const& other );
+
+ ECKAEG_Core m_eckaeg_core;
+ };
+
+/**
+* This class represents ECKAEG Private Keys.
+*/
+class ECKAEG_PrivateKey : public ECKAEG_PublicKey, public EC_PrivateKey, public PK_Key_Agreement_Key
+ {
+ public:
+ /**
+ * Generate a new private key
+ * @param the domain parameters to used for this key
+ */
+ ECKAEG_PrivateKey(RandomNumberGenerator& rng,
+ EC_Domain_Params const& dom_pars)
+ {
+ mp_dom_pars = std::auto_ptr<EC_Domain_Params>(new EC_Domain_Params(dom_pars));
+ generate_private_key(rng);
+ mp_public_point->check_invariants();
+ m_eckaeg_core = ECKAEG_Core(*mp_dom_pars, m_private_value, *mp_public_point);
+ }
+ /**
+ * Default constructor. Use this one if you want to later fill this object with data
+ * from an encoded key.
+ */
+ ECKAEG_PrivateKey()
+ {}
+ ECKAEG_PrivateKey(ECKAEG_PrivateKey const& other);
+ ECKAEG_PrivateKey const& operator= (ECKAEG_PrivateKey const& rhs);
+
+ void PKCS8_load_hook(bool = false);
+
+ /**
+ * Derive a shared key with the other partys public key.
+ * @param pub_key the other partys public key
+ */
+ SecureVector<byte> derive_key(const Public_Key& pub_key) const;
+
+ /**
+ * Make sure that the public key parts of this object are set
+ * (calls EC_PublicKey::affirm_init()) as well as the private key
+ * value.
+ * @throw Invalid_State if the above conditions are not satisfied
+ */
+ virtual void affirm_init() const;
+
+ protected:
+ virtual void set_all_values ( ECKAEG_PrivateKey const& other );
+ };
+
+}
+
+#endif
diff --git a/include/ec_dompar.h b/include/ec_dompar.h
new file mode 100644
index 000000000..8f9cc77d9
--- /dev/null
+++ b/include/ec_dompar.h
@@ -0,0 +1,115 @@
+/*************************************************
+* ECDSA Domain Parameters Header File *
+* (C) 2007 Falko Strenzke, FlexSecure GmbH *
+*************************************************/
+
+#ifndef EC_DOMPAR_H__
+#define EC_DOMPAR_H__
+
+#include <botan/point_gfp.h>
+#include <botan/gfp_element.h>
+#include <botan/curve_gfp.h>
+#include <botan/bigint.h>
+#include <botan/der_enc.h>
+#include <botan/ber_dec.h>
+#include <botan/alg_id.h>
+#include <botan/enums.h>
+
+namespace Botan {
+
+/**
+* This class represents elliptic curce domain parameters
+*/
+class EC_Domain_Params
+ {
+ public:
+
+ /**
+ * Construct Domain paramers from specified parameters
+ * @param curve elliptic curve
+ * @param base_point a base point
+ * @param order the order of the base point
+ * @param cofactor the cofactor
+ */
+ EC_Domain_Params(CurveGFp const& curve, PointGFp const& base_point,
+ const BigInt& order, const BigInt& cofactor);
+
+ /**
+ * Return domain parameter curve
+ * @result domain parameter curve
+ */
+ const CurveGFp& get_curve() const
+ {
+ return m_curve;
+ }
+
+ /**
+ * Return domain parameter curve
+ * @result domain parameter curve
+ */
+ const PointGFp& get_base_point() const
+ {
+ return m_base_point;
+ }
+
+ /**
+ * Return the order of the base point
+ * @result order of the base point
+ */
+ const BigInt& get_order() const
+ {
+ return m_order;
+ }
+
+ /**
+ * Return the cofactor
+ * @result the cofactor
+ */
+ const BigInt& get_cofactor() const
+ {
+ return m_cofactor;
+ }
+
+ /**
+ * Return the OID of these domain parameters
+ * @result the OID
+ */
+ std::string get_oid() const { return m_oid; }
+
+ private:
+ friend EC_Domain_Params get_EC_Dom_Pars_by_oid(std::string oid);
+
+ CurveGFp m_curve;
+ PointGFp m_base_point;
+ BigInt m_order;
+ BigInt m_cofactor;
+ std::string m_oid;
+ };
+
+bool operator==(EC_Domain_Params const& lhs, EC_Domain_Params const& rhs);
+
+inline bool operator!=(const EC_Domain_Params& lhs,
+ const EC_Domain_Params& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+enum EC_dompar_enc { ENC_EXPLICIT = 0, ENC_IMPLICITCA = 1, ENC_OID = 2 };
+
+SecureVector<byte> encode_der_ec_dompar(EC_Domain_Params const& dom_pars,
+ EC_dompar_enc enc_type);
+
+EC_Domain_Params decode_ber_ec_dompar(SecureVector<byte> const& encoded);
+
+/**
+* Factory function, the only way to obtain EC domain parameters with an OID.
+* The demanded OID has to be registered in the InSiTo configuration. Consult the file
+* policy.cpp for the default configuration.
+* @param the oid of the demanded EC domain parameters
+* @result the EC domain parameters associated with the OID
+*/
+EC_Domain_Params get_EC_Dom_Pars_by_oid(std::string oid);
+
+}
+
+#endif
diff --git a/include/ecdsa.h b/include/ecdsa.h
new file mode 100644
index 000000000..2f8392a3f
--- /dev/null
+++ b/include/ecdsa.h
@@ -0,0 +1,100 @@
+/*************************************************
+* ECDSA Header File *
+* (C) 2007 Falko Strenzke, FlexSecure GmbH *
+* Defines classes ECDSA_Signature and *
+* ECDSA_Signature_De/Encoder, *
+*************************************************/
+
+#ifndef BOTAN_ECDSA_H__
+#define BOTAN_ECDSA_H__
+
+#include <botan/bigint.h>
+#include <botan/der_enc.h>
+#include <botan/ber_dec.h>
+
+namespace Botan {
+
+class ECDSA_Signature_Decoder;
+class ECDSA_Signature_Encoder;
+
+class ECDSA_Signature
+ {
+ friend class ECDSA_Signature_Decoder;
+ friend class ECDSA_Signature_Encoder;
+ public:
+ ECDSA_Signature(const BigInt& r, const BigInt& s);
+ ECDSA_Signature()
+ {}
+ ;
+ ECDSA_Signature(ECDSA_Signature const& other);
+ ECDSA_Signature const& operator=(ECDSA_Signature const& other);
+
+ BigInt const get_r() const
+ {
+ return m_r;
+ }
+ BigInt const get_s() const
+ {
+ return m_s;
+ }
+ /**
+ * return the r||s
+ */
+ SecureVector<byte> const get_concatenation() const;
+
+
+ ECDSA_Signature_Encoder* x509_encoder() const;
+ ECDSA_Signature_Decoder* x509_decoder();
+ private:
+ BigInt m_r;
+ BigInt m_s;
+ };
+
+bool operator== ( ECDSA_Signature const& lhs, ECDSA_Signature const& rhs );
+inline bool operator!= ( ECDSA_Signature const& lhs, ECDSA_Signature const& rhs )
+ {
+ return !operator== ( lhs, rhs );
+ }
+
+class ECDSA_Signature_Decoder
+ {
+ public:
+ void signature_bits(const MemoryRegion<byte>& bits)
+ {
+ BER_Decoder(bits)
+ .start_cons(SEQUENCE)
+ .decode(m_signature->m_r)
+ .decode(m_signature->m_s)
+ .verify_end()
+ .end_cons();
+ }
+ ECDSA_Signature_Decoder(ECDSA_Signature* signature) : m_signature(signature)
+ {}
+ private:
+ ECDSA_Signature* m_signature;
+ };
+
+class ECDSA_Signature_Encoder
+ {
+ public:
+ MemoryVector<byte> signature_bits() const
+ {
+ return DER_Encoder()
+ .start_cons(SEQUENCE)
+ .encode(m_signature->m_r)
+ .encode(m_signature->m_s)
+ .end_cons()
+ .get_contents();
+ }
+ ECDSA_Signature_Encoder(const ECDSA_Signature* signature) : m_signature(signature)
+ {}
+ private:
+ const ECDSA_Signature* m_signature;
+ };
+
+ECDSA_Signature const decode_seq(MemoryRegion<byte> const& seq);
+ECDSA_Signature const decode_concatenation(MemoryRegion<byte> const& concatenation);
+
+}
+
+#endif
diff --git a/include/engine.h b/include/engine.h
index 13007e662..74449c959 100644
--- a/include/engine.h
+++ b/include/engine.h
@@ -8,6 +8,7 @@
#include <botan/base.h>
#include <botan/mutex.h>
+#include <botan/ec_dompar.h>
#include <botan/pk_ops.h>
#include <botan/pow_mod.h>
#include <botan/basefilt.h>
@@ -43,6 +44,14 @@ class BOTAN_DLL Engine
const BigInt&) const;
virtual DH_Operation* dh_op(const DL_Group&, const BigInt&) const;
+ virtual ECDSA_Operation* ecdsa_op(const EC_Domain_Params& dom_pars,
+ const BigInt& priv_key,
+ const PointGFp& pub_key) const;
+
+ virtual ECKAEG_Operation* eckaeg_op(const EC_Domain_Params& dom_pars,
+ const BigInt& priv_key,
+ const PointGFp& pub_key) const;
+
virtual Modular_Exponentiator* mod_exp(const BigInt&,
Power_Mod::Usage_Hints) const;
@@ -116,6 +125,14 @@ ELG_Operation* elg_op(const DL_Group&, const BigInt&, const BigInt&);
DH_Operation* dh_op(const DL_Group&, const BigInt&);
+ECDSA_Operation* ecdsa_op(const EC_Domain_Params& dom_pars,
+ const BigInt& priv_key,
+ const PointGFp& pub_key);
+
+ECKAEG_Operation* eckaeg_op(const EC_Domain_Params& dom_pars,
+ const BigInt& priv_key,
+ const PointGFp& pub_key);
+
}
}
diff --git a/include/gfp_element.h b/include/gfp_element.h
new file mode 100644
index 000000000..e9850df30
--- /dev/null
+++ b/include/gfp_element.h
@@ -0,0 +1,308 @@
+/******************************************************
+ * Arithmetic for prime fields GF(p) (header file) *
+ * *
+ * (C) 2007 Martin Döring *
+* Christoph Ludwig *
+* Falko Strenzke *
+******************************************************/
+
+#ifndef BOTAN_MATH_GF_GFP_ELEMENT_H_GUARD_
+#define BOTAN_MATH_GF_GFP_ELEMENT_H_GUARD_
+
+#include <botan/gfp_modulus.h>
+#include <botan/bigint.h>
+#include <tr1/memory>
+
+namespace Botan
+{
+
+struct Illegal_Transformation : public Exception
+{
+ Illegal_Transformation(const std::string& err = "Requested transformation is not possible")
+ : Exception(err) {}
+};
+
+/**
+* This class represents one element in GF(p). Enables the convenient, transparent use
+* of the montgomery multiplication.
+*/
+class GFpElement
+ {
+
+ private:
+ std::tr1::shared_ptr<GFpModulus> mp_mod;
+ mutable BigInt m_value; // ordinary residue or m-residue respectively
+ mutable BigInt workspace;
+ // *****************************************
+ // data members for montgomery multiplication
+ mutable bool m_use_montgm;
+ //mutable BigInt m_mres;
+ // this bool tells use whether the m_mres carries
+ // the actual value (in this case mValue doesn´t)
+ mutable bool m_is_trf;
+
+
+ void ensure_montgm_precomp() const;
+ void trf_to_mres() const;
+ void trf_to_ordres() const;
+
+ public:
+
+
+ /** construct an element of GF(p) with the given value.
+ * use_montg defaults to false and determines wether Montgomery multiplications
+ * will be use when applying operators '*' , '*='.
+ * @param p the prime number of the field
+ * @param value the element value
+ * @param use_montgm whether this object will use Montgomery multiplication
+ */
+ explicit GFpElement ( const BigInt& p, const BigInt& value, bool use_montgm = false );
+
+
+ /** construct an element of GF(p) with the given value (defaults to 0).
+ * use_montg defaults to false and determines wether montgomery multiplications
+ * will be use when applying operators '*' , '*='.
+ * Use this constructor for efficient use of Montgomery multiplication in a context with a
+ * fixed a modulus.
+ * Warning: do not use this function unless you know in detail about
+ * the implications of using
+ * the shared GFpModulus objects!
+ * @param mod shared pointer to the GFpModulus to be shared
+ * @param value the element value
+ * @param use_montgm whether this object will use Montgomery multiplication
+ */
+ explicit GFpElement(std::tr1::shared_ptr<GFpModulus> const mod, const BigInt& value, bool use_mongm = false);
+
+ /**
+ * Copy constructor
+ * @param other The element to clone
+ */
+ GFpElement ( GFpElement const& other );
+
+ /**
+ * Assignment operator.
+ * makes *this a totally independent object
+ * (gives *this independent modulus specific values).
+ *
+ * @param other The element to assign to our object
+ */
+ GFpElement const& operator= ( GFpElement const& other );
+
+ /**
+ * Works like the assignment operator, but lets
+ * *this share the modulus dependend value with other.
+ * Warning: do not use this function unless you know in detail about
+ * the implications of using
+ * the shared GFpModulus objects!
+ * @param other The element to assign to our object
+ */
+ void share_assign(GFpElement const& other);
+
+ /**
+ * Switch Montgomery multiplcation optimizations ON
+ */
+ void turn_on_sp_red_mul() const;
+
+ /**
+ * Switch Montgomery multiplcation optimizations OFF
+ */
+ void turn_off_sp_red_mul() const;
+
+ /**
+ * += Operator
+ * @param rhs the GFpElement to add to the local value
+ * @result *this
+ */
+ GFpElement& operator+= ( GFpElement const& rhs );
+
+ /**
+ * -= Operator
+ * @param rhs the GFpElement to subtract from the local value
+ * @result *this
+ */
+ GFpElement& operator-= ( GFpElement const& rhs );
+
+ /**
+ * *= Operator
+ * @param rhs the GFpElement to multiply with the local value
+ * @result *this
+ */
+ GFpElement& operator*= ( GFpElement const& rhs );
+ /**
+ * /= Operator
+ * @param rhs the GFpElement to divide the local value by
+ * @result *this
+ */
+ GFpElement& operator/= ( GFpElement const& rhs );
+
+ /**
+ * *= Operator
+ * @param rhs the value to multiply with the local value
+ * @result *this
+ */
+ GFpElement& operator*= (u32bit rhs);
+
+ /**
+ * Negate internal value ( *this *= -1 )
+ * @return *this
+ */
+ GFpElement& negate();
+
+ /**
+ * Assigns the inverse of *this to *this, i.e.
+ * *this = (*this)^(-1)
+ * @result *this
+ */
+ GFpElement& inverse_in_place();
+
+ /**
+ * checks whether the value is zero (without provoking
+ * a backtransformation to the ordinary-residue)
+ * @result true, if the value is zero, false otherwise.
+ */
+ bool is_zero();
+
+ /**
+ * return prime number of GF(p)
+ * @result a prime number
+ */
+ BigInt const get_p() const;
+
+ /**
+ * Return the represented value in GF(p)
+ * @result The value in GF(p)
+ */
+ BigInt const get_value() const;
+
+ /**
+ * Returns the shared pointer to the GFpModulus of *this.
+ * Warning: do not use this function unless you know in detail about
+ * the implications of using
+ * the shared GFpModulus objects!
+ * @result the shared pointer to the GFpModulus of *this
+ */
+ inline std::tr1::shared_ptr<GFpModulus> const get_ptr_mod() const
+ {
+ return mp_mod;
+ }
+
+
+ /**
+ * Sets the shared pointer to the GFpModulus of *this.
+ * Warning: do not use this function unless you know in detail about
+ * the implications of using
+ * the shared GFpModulus objects!
+ * @param mod a shared pointer to a GFpModulus that will be held in *this
+ */
+ void set_shrd_mod(std::tr1::shared_ptr<GFpModulus> const mod);
+
+ /**
+ * Tells whether this GFpElement is currently transformed to it´ m-residue,
+ * i.e. in the form x_bar = x * r mod m.
+ * @result true if it is currently transformed to it´s m-residue.
+ */
+ bool is_trf_to_mres() const;
+
+ /**
+ * Transforms this to x_bar = x * r mod m
+ * @result return the value x_bar.
+ */
+ BigInt const get_mres() const;
+
+ /**
+ * Check, if montgomery multiplication is used.
+ * @result true, if montgomery multiplication is used, false otherwise
+ */
+ bool is_use_montgm() const
+ {
+ return m_use_montgm;
+ }
+
+ /**
+ * Transforms the arguments in such way that either both
+ * are in m-residue representation (returns true) or both are
+ * in ordinary residue representation (returns false).
+ * m-residue is prefered in case of ambiguity.
+ * does not toggle m_use_montgm of the arguments.
+ * Don´t be confused about the constness of the arguments:
+ * the transformation between normal residue and m-residue is
+ * considered as leaving the object const.
+ * @param lhs the first operand to be aligned
+ * @param rhs the second operand to be aligned
+ * @result true if both are transformed to their m-residue,
+ * false it both are transformed to their normal residue.
+ */
+ static bool align_operands_res(GFpElement const& lhs, GFpElement const& rhs);
+
+ //friend declarations for non-member functions
+
+ /**
+ * write a GFpElement to an output stream.
+ * @param output the output stream to write to
+ * @param elem the object to write
+ * @result the output stream
+ */
+ friend class Point_Coords_GFp;
+
+ /**
+ * swaps the states of *this and other, does not throw!
+ * @param other The value to swap with
+ */
+ void swap ( GFpElement& other );
+
+ };
+
+// relational operators
+bool operator== ( GFpElement const& lhs, GFpElement const& rhs );
+inline bool operator!= ( GFpElement const& lhs, GFpElement const& rhs )
+ {
+ return !operator== ( lhs, rhs );
+ }
+
+// arithmetic operators
+GFpElement operator+ ( GFpElement const& lhs, GFpElement const& rhs );
+GFpElement operator- ( GFpElement const& lhs, GFpElement const& rhs );
+GFpElement operator- ( GFpElement const& lhs );
+
+GFpElement operator* ( GFpElement const& lhs, GFpElement const& rhs );
+GFpElement operator/ ( GFpElement const& lhs, GFpElement const& rhs );
+GFpElement operator* (GFpElement const& lhs, u32bit rhs);
+GFpElement operator* (u32bit rhs, GFpElement const& lhs);
+
+// return (*this)^(-1)
+GFpElement inverse ( GFpElement const& elem );
+
+// encoding and decoding
+SecureVector<byte> FE2OSP ( GFpElement const& elem );
+GFpElement OS2FEP ( MemoryRegion<byte> const& os, BigInt p );
+
+
+// swaps the states of elem1 and elem2, does not throw!
+// cf. Meyers, Item 25
+inline
+void swap ( GFpElement& elem1, GFpElement& elem2 )
+ {
+ elem1.swap ( elem2 );
+ }
+
+} // namespace Botan
+
+namespace std
+{
+
+// swaps the states of elem1 and elem2, does not throw!
+// cf. Meyers, Item 25
+template<>
+inline
+void swap< Botan::GFpElement>(Botan::GFpElement& elem1,
+ Botan::GFpElement& elem2)
+ {
+ elem1.swap(elem2);
+ }
+
+} // namespace std
+
+#endif
diff --git a/include/gfp_modulus.h b/include/gfp_modulus.h
new file mode 100644
index 000000000..5edf44ba0
--- /dev/null
+++ b/include/gfp_modulus.h
@@ -0,0 +1,124 @@
+/******************************************************
+ * Modulus and related data for a specific *
+ * implementation of GF(p) (header file) *
+ * *
+ * (C) 2008 Martin Döring *
+ * Christoph Ludwig *
+ * Falko Strenzke *
+ ******************************************************/
+
+#ifndef BOTAN_MATH_GF_GFP_MODULUS_H_GUARD_
+#define BOTAN_MATH_GF_GFP_MODULUS_H_GUARD_
+
+#include <botan/bigint.h>
+
+namespace Botan
+{
+
+class GFpElement;
+/**
+* This class represents a GFpElement modulus including the modulus related
+* values necessary for the montgomery multiplication.
+*/
+class GFpModulus
+ {
+ friend class GFpElement;
+ private:
+ BigInt m_p; // the modulus itself
+ mutable BigInt m_p_dash;
+ mutable BigInt m_r;
+ mutable BigInt m_r_inv;
+ public:
+
+ /**
+ * Construct a GF(P)-Modulus from a BigInt
+ */
+ GFpModulus(BigInt p)
+ : m_p(p),
+ m_p_dash(),
+ m_r(),
+ m_r_inv()
+ {}
+
+ /**
+ * Tells whether the precomputations necessary for the use of the montgomery
+ * multiplication have yet been established.
+ * @result true if the precomputated value are already available.
+ */
+ inline bool has_precomputations() const
+ {
+ return(!m_p_dash.is_zero() && !m_r.is_zero() && !m_r_inv.is_zero());
+ }
+
+ /**
+ * Swaps this with another GFpModulus, does not throw.
+ * @param other the GFpModulus to swap *this with.
+ */
+ inline void swap(GFpModulus& other)
+ {
+ m_p.swap(other.m_p);
+ m_p_dash.swap(other.m_p_dash);
+ m_r.swap(other.m_r);
+ m_r_inv.swap(other.m_r_inv);
+ }
+
+ /**
+ * Tells whether the modulus of *this is equal to the argument.
+ * @param mod the modulus to compare this with
+ * @result true if the modulus of *this and the argument are equal.
+ */
+ inline bool p_equal_to(const BigInt& mod) const
+ {
+ return (m_p == mod);
+ }
+
+ /**
+ * Return the modulus of this GFpModulus.
+ * @result the modulus of *this.
+ */
+ inline const BigInt get_p() const
+ {
+ return m_p;
+ }
+
+ /**
+ * returns the montgomery multiplication related value r.
+ * Warning: will be zero if precomputations have not yet been
+ * performed!
+ * @result r
+ */
+ inline const BigInt get_r() const
+ {
+ return m_r;
+ }
+
+ /**
+ * returns the montgomery multiplication related value r^{-1}.
+ * Warning: will be zero if precomputations have not yet been
+ * performed!
+ * @result r^{-1}
+ */
+ inline const BigInt get_r_inv() const
+ {
+ return m_r_inv;
+ }
+
+ /**
+ * returns the montgomery multiplication related value p'.
+ * Warning: will be zero if precomputations have not yet been
+ * performed!
+ * @result p'
+ */
+ inline const BigInt get_p_dash() const
+ {
+ return m_p_dash;
+ }
+ // default cp-ctor, op= are fine
+ };
+
+}
+
+#endif
diff --git a/include/pk_core.h b/include/pk_core.h
index 585c12ee4..66b1d43f9 100644
--- a/include/pk_core.h
+++ b/include/pk_core.h
@@ -8,6 +8,7 @@
#include <botan/bigint.h>
#include <botan/dl_group.h>
+#include <botan/ec_dompar.h>
#include <botan/blinding.h>
#include <botan/pk_ops.h>
@@ -123,6 +124,58 @@ class BOTAN_DLL DH_Core
Blinder blinder;
};
+/*************************************************
+* ECDSA Core *
+*************************************************/
+class ECDSA_Core
+ {
+ public:
+ bool verify(const byte signature[], u32bit sig_len,
+ const byte message[], u32bit mess_len) const;
+
+ SecureVector<byte> sign(const byte message[], u32bit mess_len) const;
+
+ ECDSA_Core& operator=(const ECDSA_Core&);
+
+ ECDSA_Core() { op = 0; }
+
+ ECDSA_Core(const ECDSA_Core&);
+
+ ECDSA_Core(const EC_Domain_Params& dom_pars,
+ const BigInt& priv_key,
+ const PointGFp& pub_key);
+
+ ~ECDSA_Core() { delete op; }
+ private:
+ ECDSA_Operation* op;
+ };
+
+/*************************************************
+* ECKAEG Core *
+*************************************************/
+class ECKAEG_Core
+ {
+ public:
+ SecureVector<byte> agree(const PointGFp&) const;
+
+ ECKAEG_Core& operator=(const ECKAEG_Core&);
+
+ ECKAEG_Core() { op = 0; }
+
+ ECKAEG_Core(const ECKAEG_Core&);
+
+ ECKAEG_Core(const EC_Domain_Params& dom_pars,
+ const BigInt& priv_key,
+ PointGFp const& pub_key);
+
+ ~ECKAEG_Core() { delete op; }
+ private:
+ ECKAEG_Operation* op;
+ Blinder blinder;
+ };
+
+
+
}
#endif
diff --git a/include/pk_ops.h b/include/pk_ops.h
index fad87b573..7a0cbccf7 100644
--- a/include/pk_ops.h
+++ b/include/pk_ops.h
@@ -1,6 +1,6 @@
/*************************************************
* Public Key Operations Header File *
-* (C) 1999-2007 Jack Lloyd *
+* (C) 1999-2008 Jack Lloyd *
*************************************************/
#ifndef BOTAN_PK_OPS_H__
@@ -8,6 +8,8 @@
#include <botan/bigint.h>
#include <botan/dl_group.h>
+#include <botan/point_gfp.h>
+#include <botan/ecdsa.h>
namespace Botan {
@@ -74,6 +76,34 @@ class BOTAN_DLL DH_Operation
virtual ~DH_Operation() {}
};
+/*************************************************
+* ECDSA Operation *
+*************************************************/
+class BOTAN_DLL ECDSA_Operation
+ {
+ public:
+ virtual bool verify(const byte sig[], u32bit sig_len,
+ const byte msg[], u32bit msg_len) const = 0;
+
+ virtual SecureVector<byte> sign(const byte message[],
+ u32bit mess_len) const = 0;
+
+ virtual ECDSA_Operation* clone() const = 0;
+
+ virtual ~ECDSA_Operation() {}
+ };
+
+/*************************************************
+* ECKAEG Operation *
+*************************************************/
+class BOTAN_DLL ECKAEG_Operation
+ {
+ public:
+ virtual SecureVector<byte> agree(const PointGFp&) const = 0;
+ virtual ECKAEG_Operation* clone() const = 0;
+ virtual ~ECKAEG_Operation() {}
+ };
+
}
#endif
diff --git a/include/point_gfp.h b/include/point_gfp.h
new file mode 100644
index 000000000..7e5aec379
--- /dev/null
+++ b/include/point_gfp.h
@@ -0,0 +1,307 @@
+/*************************************************
+* Arithmetic over GF(p) *
+* *
+* (C) 2007 Martin Doering *
+* Christoph Ludwig *
+* Falko Strenzke *
+* (C) 2008 Jack Lloyd *
+*************************************************/
+
+#ifndef BOTAN_POINT_GFP_H__
+#define BOTAN_POINT_GFP_H__
+
+#include <botan/curve_gfp.h>
+#include <botan/gfp_element.h>
+#include <botan/bigint.h>
+#include <botan/exceptn.h>
+#include <vector>
+
+namespace Botan {
+
+struct Illegal_Point : public Exception
+ {
+ Illegal_Point(const std::string& err = "") : Exception(err) {}
+ };
+
+/**
+* This class represents one point on a curve of GF(p).
+*/
+class PointGFp
+ {
+ public:
+ /**
+ * uncompressed encoding byte value
+ */
+ static const int UNCOMPRESSED = 0;
+
+ /**
+ * compressed encoding byte value
+ */
+ static const int COMPRESSED = 1;
+
+ /**
+ * hybrid encoding byte value
+ */
+ static const int HYBRID = 2;
+
+ /**
+ * Construct the point O
+ * @param curve The base curve
+ */
+ explicit PointGFp(CurveGFp const& curve);
+
+ /**
+ * Construct a point given its affine coordinates
+ * @param curve the base curve
+ * @param x affine x coordinate
+ * @param y affine y coordinate
+ */
+ explicit PointGFp(CurveGFp const& curve, GFpElement const& x,
+ GFpElement const& y );
+
+ /**
+ * Construct a point given its jacobian projective coordinates
+ * @param curve the base curve
+ * @param x jacobian projective x coordinate
+ * @param y jacobian projective y coordinate
+ * @param z jacobian projective y coordinate
+ */
+ explicit PointGFp(CurveGFp const& curve, GFpElement const& x,
+ GFpElement const& y, GFpElement const& z );
+
+ /**
+ * copy constructor
+ * @param other the value to clone
+ */
+ PointGFp(PointGFp const& other );
+
+ /**
+ * assignment operator
+ * @param other The point to use as source for the assignment
+ */
+ PointGFp const& operator=(PointGFp const& other );
+
+ /**
+ * assign another point which is on the same curve as *this
+ * @param other The point to use as source for the assignment
+ */
+ PointGFp const& assign_within_same_curve(PointGFp const& other);
+
+
+
+ /**
+ * += Operator
+ * @param rhs the PointGFp to add to the local value
+ * @result resulting PointGFp
+ */
+ PointGFp& operator+=(PointGFp const& rhs );
+
+ /**
+ * -= Operator
+ * @param rhs the PointGFp to subtract from the local value
+ * @result resulting PointGFp
+ */
+ PointGFp& operator-=(PointGFp const& rhs );
+
+ /**
+ * *= Operator
+ * This function turns on the the special reduction multiplication
+ * itself for fast computation, turns it off again when finished.
+ * @param scalar the PointGFp to multiply with *this
+ * @result resulting PointGFp
+ */
+ PointGFp& operator*=(const BigInt& scalar );
+
+ /**
+ * the equivalent to operator*= with countermeasures against
+ * sidechannel attacks, using the randomized exponent
+ * and add-and-double-always
+ * countermeasures (suitable for ECDSA and ECKAEG)
+ * @param scalar the scalar to multiply the point with
+ * @param point_order a multiple of the order of the point
+ *(= n * k in the general case; k is the cofactor)
+ * @param max_secr the maximal size of the scalar
+ * (will usually be n-1 )
+ * @result resulting PointGFp
+ */
+ PointGFp& mult_this_secure(const BigInt& scalar,
+ const BigInt& point_order,
+ const BigInt& max_secr
+ );
+
+ /**
+ * Negate internal value(*this *= -1 )
+ * @return *this
+ */
+ PointGFp& negate();
+
+ /**
+ * Multiply the point by two(*this *= 2 )
+ * @return *this
+ */
+ PointGFp& mult2_in_place();
+
+ /**
+ * Set z coordinate to one.
+ * @return *this
+ */
+ PointGFp const& set_z_to_one() const;
+
+ /**
+ * Turn on the special reduction multiplication (i.e. the
+ * Montgomery multiplication in the current implementation) for
+ * the coordinates. This enables fast execution of mult2_in_place()
+ * and operator+=().
+ */
+ void turn_on_sp_red_mul() const;
+
+ /**
+ * Return a point
+ * where the coordinates are transformed
+ * so that z equals one,
+ * thus x and y have just the affine values.
+ * @result *this
+ */
+ PointGFp const get_z_to_one() const;
+
+ /**
+ * Return base curve of this point
+ * @result the curve over GF(p) of this point
+ */
+ CurveGFp const get_curve() const;
+
+ /**
+ * get affine x coordinate
+ * @result affine x coordinate
+ */
+ GFpElement const get_affine_x() const;
+
+ /**
+ * get affine y coordinate
+ * @result affine y coordinate
+ */
+ GFpElement const get_affine_y() const;
+
+ /**
+ * get the jacobian projective x coordinate
+ * @result jacobian projective x coordinate
+ */
+ GFpElement const get_jac_proj_x() const;
+
+ /**
+ * get the jacobian projective y coordinate
+ * @result jacobian projective y coordinate
+ */
+ GFpElement const get_jac_proj_y() const;
+
+ /**
+ * get the jacobian projective z coordinate
+ * @result jacobian projective z coordinate
+ */
+ GFpElement const get_jac_proj_z() const;
+
+ /**
+ * Is this the point at infinity?
+ * @result true, if this point is at infinity, false otherwise.
+ */
+ bool is_zero() const;
+
+ /**
+ * Checks whether the point is to be found on the underlying curve.
+ * Throws an Invalid_Point exception in case of detecting that the point
+ * does not satisfy the curve equation.
+ * To be used to ensure against fault attacks.
+ */
+ void check_invariants() const;
+
+
+ /**
+ * swaps the states of *this and other, does not throw!
+ * @param other the object to swap values with
+ */
+ void swap(PointGFp& other );
+
+ /**
+ * Sets the shared pointer to the GFpModulus that will be
+ * held in *this, specifically the various members of *this.
+ * Warning: do not use this function unless you know in detail about
+ * the implications of using
+ * the shared GFpModulus objects!
+ * Do NOT spread a shared pointer to GFpModulus over different
+ * threads!
+ * @param mod a shared pointer to a GFpModulus that will
+ * be held in the members *this
+ */
+ void set_shrd_mod(std::tr1::shared_ptr<Botan::GFpModulus> p_mod);
+
+ static GFpElement decompress(bool yMod2, GFpElement const& x, CurveGFp const& curve );
+
+ private:
+ static const u32bit GFPEL_WKSP_SIZE = 9;
+ void ensure_worksp() const;
+
+ inline std::tr1::shared_ptr<PointGFp> mult_loop(int l, const BigInt& m, std::tr1::shared_ptr<PointGFp> H, std::tr1::shared_ptr<PointGFp> tmp, PointGFp const& P);
+
+ CurveGFp mC;
+ mutable GFpElement mX; // NOTE: these values must be mutable (affine<->proj)
+ mutable GFpElement mY;
+ mutable GFpElement mZ;
+ mutable GFpElement mZpow2; // mZ^2
+ mutable GFpElement mZpow3; // mZ^3
+ mutable GFpElement mAZpow4; // mA*mZ^4
+ mutable bool mZpow2_set;
+ mutable bool mZpow3_set;
+ mutable bool mAZpow4_set;
+ mutable std::tr1::shared_ptr<std::vector<GFpElement> > mp_worksp_gfp_el;
+
+ };
+
+// relational operators
+bool operator==(PointGFp const& lhs, PointGFp const& rhs );
+inline bool operator!=(PointGFp const& lhs, PointGFp const& rhs )
+ {
+ return !operator==(lhs, rhs );
+ }
+
+// arithmetic operators
+PointGFp operator+(PointGFp const& lhs, PointGFp const& rhs );
+PointGFp operator-(PointGFp const& lhs, PointGFp const& rhs );
+PointGFp operator-(PointGFp const& lhs );
+
+PointGFp operator*(const BigInt& scalar, PointGFp const& point );
+PointGFp operator*(PointGFp const& point, const BigInt& scalar );
+PointGFp mult_point_secure(PointGFp const& point, const BigInt& scalar, const BigInt& point_order, const BigInt& max_secret);
+
+PointGFp const mult2 (PointGFp const& point);
+
+PointGFp const create_random_point(RandomNumberGenerator& rng,
+ CurveGFp const& curve);
+
+// encoding and decoding
+SecureVector<byte> EC2OSP(PointGFp const& point, byte format );
+PointGFp OS2ECP(MemoryRegion<byte> const& os, CurveGFp const& curve );
+
+SecureVector<byte> encode_uncompressed(PointGFp const& point ); // maybe make private
+SecureVector<byte> encode_hybrid(PointGFp const& point ); // maybe make private
+SecureVector<byte> encode_compressed(PointGFp const& point ); // maybe make private
+
+// swaps the states of point1 and point2, does not throw!
+// cf. Meyers, Item 25
+inline
+void swap(PointGFp& point1, PointGFp& point2 )
+ {
+ point1.swap(point2 );
+ }
+
+} // namespace Botan
+
+namespace std {
+
+// swaps the states of point1 and point2, does not throw!
+// cf. Meyers, Item 25
+template<> inline void
+swap<Botan::PointGFp>(Botan::PointGFp& x, Botan::PointGFp& y) { x.swap(y); }
+
+} // namespace std
+
+#endif
diff --git a/include/rsa.h b/include/rsa.h
index 445902a6f..64aa748ad 100644
--- a/include/rsa.h
+++ b/include/rsa.h
@@ -1,3 +1,4 @@
+
/*************************************************
* RSA Header File *
* (C) 1999-2008 Jack Lloyd *
diff --git a/src/curve_gfp.cpp b/src/curve_gfp.cpp
new file mode 100644
index 000000000..89fa74c49
--- /dev/null
+++ b/src/curve_gfp.cpp
@@ -0,0 +1,157 @@
+/******************************************************
+ * Elliptic curves over GF(p) (source file) *
+ * *
+ * (C) 2007 Martin Doering *
+ * Christoph Ludwig *
+ * Falko Strenzke *
+ ******************************************************/
+
+#include <botan/curve_gfp.h>
+
+namespace Botan {
+
+CurveGFp::CurveGFp(GFpElement const& a, GFpElement const& b,
+ const BigInt& p) :
+ mA(a), mB(b)
+ {
+ if(p != mA.get_p() || p != mB.get_p())
+ throw Invalid_Argument("could not construct curve: moduli of arguments differ");
+
+ std::tr1::shared_ptr<GFpModulus> p_mod = std::tr1::shared_ptr<GFpModulus>(new GFpModulus(p));
+ // the above is the creation of the GFpModuls object which will be shared point-wide
+ // (in the context of a point of course)
+ set_shrd_mod(p_mod);
+ }
+
+// copy constructor
+CurveGFp::CurveGFp(CurveGFp const& other)
+ : mA(other.get_a()),
+ mB(other.get_b())
+ {
+ mp_mod = std::tr1::shared_ptr<GFpModulus>(new GFpModulus(*other.mp_mod));
+ //assert(mp_mod->p_equal_to(mA.get_p()));
+ //assert(mp_mod->p_equal_to(mB.get_p()));
+ set_shrd_mod(mp_mod);
+ if(other.mp_mres_a.get())
+ {
+ mp_mres_a = std::tr1::shared_ptr<GFpElement>(new GFpElement(*other.mp_mres_a));
+ }
+ if(other.mp_mres_b.get())
+ {
+ mp_mres_b = std::tr1::shared_ptr<GFpElement>(new GFpElement(*other.mp_mres_b));
+ }
+ if(other.mp_mres_one.get())
+ {
+ mp_mres_one = std::tr1::shared_ptr<GFpElement>(new GFpElement(*other.mp_mres_one));
+ }
+
+ }
+
+// assignment operator
+CurveGFp const& CurveGFp::operator=(CurveGFp const& other)
+ {
+ // for exception safety...
+ GFpElement a_tmp = other.mA;
+ GFpElement b_tmp = other.mB;
+ mA.swap(a_tmp);
+ mB.swap(b_tmp);
+
+ std::tr1::shared_ptr<GFpModulus> p_mod = std::tr1::shared_ptr<GFpModulus>(new GFpModulus(*other.mp_mod));
+ set_shrd_mod(p_mod);
+
+ // exception safety note: no problem if we have a throw from here on...
+ if(other.mp_mres_a.get())
+ {
+ mp_mres_a = std::tr1::shared_ptr<GFpElement>(new GFpElement(*other.mp_mres_a));
+ }
+ if(other.mp_mres_b.get())
+ {
+ mp_mres_b = std::tr1::shared_ptr<GFpElement>(new GFpElement(*other.mp_mres_b));
+ }
+ if(other.mp_mres_one.get())
+ {
+ mp_mres_one = std::tr1::shared_ptr<GFpElement>(new GFpElement(*other.mp_mres_one));
+ }
+ return *this;
+ }
+
+// getters
+GFpElement const CurveGFp::get_a() const
+ {
+ return mA;
+ }
+GFpElement const CurveGFp::get_b() const
+ {
+ return mB;
+ }
+
+BigInt const CurveGFp::get_p() const
+ {
+ //assert(mp_mod.get() != 0);
+ return mp_mod->get_p();
+ }
+
+// swaps the states of *this and other, does not throw
+void CurveGFp::swap(CurveGFp& other)
+ {
+ mA.swap(other.mA);
+ mB.swap(other.mB);
+ mp_mod.swap(other.mp_mod);
+ std::swap(mp_mres_a, other.mp_mres_a);
+ std::swap(mp_mres_b, other.mp_mres_b);
+ std::swap(mp_mres_one, other.mp_mres_one);
+ }
+
+void CurveGFp::set_shrd_mod(std::tr1::shared_ptr<GFpModulus> const mod)
+ {
+ mp_mod = mod;
+ mA.turn_off_sp_red_mul();// m.m. is not needed, must be trf. back
+ mB.turn_off_sp_red_mul();// m.m. is not needed, must be trf. back
+ //ok, above we destroy any evantually computated montg. mult. values,
+ // but that won't influence performance in usual applications
+ mA.set_shrd_mod(mod);
+ mB.set_shrd_mod(mod);
+ }
+
+GFpElement const CurveGFp::get_mres_a() const
+ {
+ if(mp_mres_a.get() == 0)
+ {
+ mp_mres_a = std::tr1::shared_ptr<GFpElement>(new GFpElement(mA));
+ mp_mres_a->turn_on_sp_red_mul();
+ mp_mres_a->get_mres();
+ }
+ return GFpElement(*mp_mres_a);
+ }
+
+GFpElement const CurveGFp::get_mres_b() const
+ {
+ if(mp_mres_b.get() == 0)
+ {
+ mp_mres_b = std::tr1::shared_ptr<GFpElement>(new GFpElement(mB));
+ mp_mres_b->turn_on_sp_red_mul();
+ mp_mres_b->get_mres();
+ }
+ return GFpElement(*mp_mres_b);
+ }
+
+std::tr1::shared_ptr<GFpElement const> const CurveGFp::get_mres_one() const
+ {
+ if(mp_mres_one.get() == 0)
+ {
+ mp_mres_one = std::tr1::shared_ptr<GFpElement>(new GFpElement(mp_mod->get_p(), 1));
+ mp_mres_one->turn_on_sp_red_mul();
+ mp_mres_one->get_mres();
+ }
+ return mp_mres_one;
+ }
+
+bool operator==(CurveGFp const& lhs, CurveGFp const& rhs)
+ {
+ return (lhs.get_p() == rhs.get_p() && lhs.get_a() == rhs.get_a() && lhs.get_b() == rhs.get_b());
+ }
+
+}
diff --git a/src/ec.cpp b/src/ec.cpp
new file mode 100644
index 000000000..7384f8082
--- /dev/null
+++ b/src/ec.cpp
@@ -0,0 +1,533 @@
+/*************************************************
+* ECC Key implemenation *
+* (C) 2007 Manuel Hartl / FlexSecure GmbH *
+* *
+* Falko Strenzke *
+*************************************************/
+
+#include <botan/ec.h>
+#include <botan/numthry.h>
+#include <botan/util.h>
+#include <botan/der_enc.h>
+#include <botan/ber_dec.h>
+#include <botan/secmem.h>
+#include <botan/point_gfp.h>
+
+namespace Botan {
+
+/*************************************************
+* EC_PublicKey *
+*************************************************/
+void EC_PublicKey::affirm_init() const // virtual
+ {
+ if ((mp_dom_pars.get() == 0) || (mp_public_point.get() == 0))
+ {
+ throw Invalid_State("cannot use uninitialized EC_Key");
+ }
+ }
+EC_Domain_Params const EC_PublicKey::get_domain_parameters() const
+ {
+ if(!mp_dom_pars.get())
+ {
+ throw Invalid_State("EC_PublicKey::get_domain_parameters(): ec domain parameters are not yet set");
+ }
+ return *mp_dom_pars;
+ }
+bool EC_PublicKey::domain_parameters_set()
+ {
+ if (mp_dom_pars.get())
+ {
+ return true;
+ }
+ return false;
+ }
+void EC_PublicKey::X509_load_hook()
+ {
+ try
+ {
+ // the base point is checked to be on curve already when decoding it
+ affirm_init();
+ mp_public_point->check_invariants();
+ }
+ catch ( Illegal_Point exc )
+ {
+ throw Decoding_Error ( "decoded public point was found not to lie on curve" );
+ }
+ }
+
+
+X509_Encoder* EC_PublicKey::x509_encoder() const
+ {
+ class EC_Key_Encoder : public X509_Encoder
+ {
+ public:
+ AlgorithmIdentifier alg_id() const
+ {
+ key->affirm_init();
+ SecureVector<byte> params = encode_der_ec_dompar ( * ( key->mp_dom_pars ), key->m_param_enc );
+ return AlgorithmIdentifier ( key->get_oid(),
+ params );
+ }
+
+ MemoryVector<byte> key_bits() const
+ {
+ key->affirm_init();
+ return EC2OSP ( * ( key->mp_public_point ), PointGFp::COMPRESSED );
+
+ }
+
+ EC_Key_Encoder ( const EC_PublicKey* k ) : key ( k )
+ {}
+ private:
+ const EC_PublicKey* key;
+ };
+
+ return new EC_Key_Encoder(this);
+ }
+
+X509_Decoder* EC_PublicKey::x509_decoder()
+ {
+ class EC_Key_Decoder : public X509_Decoder
+ {
+ public:
+ void alg_id ( const AlgorithmIdentifier& alg_id )
+ {
+ key->mp_dom_pars.reset ( new EC_Domain_Params ( decode_ber_ec_dompar ( alg_id.parameters ) ) );
+ }
+
+ void key_bits ( const MemoryRegion<byte>& bits )
+ {
+ key->mp_public_point.reset ( new PointGFp ( OS2ECP ( bits, key->mp_dom_pars->get_curve() ) ) );
+ key->X509_load_hook();
+ }
+
+ EC_Key_Decoder ( EC_PublicKey* k ) : key ( k )
+ {}
+ private:
+ EC_PublicKey* key;
+ };
+
+ return new EC_Key_Decoder(this);
+ }
+
+void EC_PublicKey::set_parameter_encoding ( EC_dompar_enc type )
+ {
+ if ( ( type != ENC_EXPLICIT ) && ( type != ENC_IMPLICITCA ) && ( type != ENC_OID ) )
+ {
+ throw Invalid_Argument ( "invalid encoding type for EC-key object specified" );
+ }
+ affirm_init();
+ if ( ( mp_dom_pars->get_oid() == "" ) && ( type == ENC_OID ) )
+ {
+ throw Invalid_Argument ( "invalid encoding type ENC_OID specified for EC-key object whose corresponding domain parameters are without oid" );
+ }
+ m_param_enc = type;
+ }
+
+/********************************
+* EC_PrivateKey *
+********************************/
+void EC_PrivateKey::affirm_init() const // virtual
+ {
+ EC_PublicKey::affirm_init();
+ if (m_private_value == 0)
+ {
+ throw Invalid_State("cannot use EC_PrivateKey when private key is uninitialized");
+ }
+ }
+
+/**
+* EC_PrivateKey generator
+**/
+void EC_PrivateKey::generate_private_key(RandomNumberGenerator& rng)
+ {
+ if (mp_dom_pars.get() == 0)
+ {
+ throw Invalid_State("cannot generate private key when domain parameters are not set");
+ }
+ BigInt tmp_private_value(0);
+ tmp_private_value = random_integer (rng, 1, mp_dom_pars->get_order() );
+
+ mp_public_point = std::auto_ptr<PointGFp>( new PointGFp (mp_dom_pars->get_base_point()));
+ mp_public_point->mult_this_secure(tmp_private_value, mp_dom_pars->get_order(), mp_dom_pars->get_order()-1);
+ //assert(mp_public_point.get() != 0);
+ tmp_private_value.swap(m_private_value);
+ }
+
+/**
+* Return the PKCS #8 public key encoder
+**/
+PKCS8_Encoder* EC_PrivateKey::pkcs8_encoder() const
+ {
+ class EC_Key_Encoder : public PKCS8_Encoder
+ {
+ public:
+ AlgorithmIdentifier alg_id() const
+ {
+ key->affirm_init();
+ SecureVector<byte> params = encode_der_ec_dompar ( * ( key->mp_dom_pars ), ENC_EXPLICIT );
+ return AlgorithmIdentifier ( key->get_oid(),
+ params );
+ }
+
+ MemoryVector<byte> key_bits() const
+ {
+ key->affirm_init();
+ SecureVector<byte> octstr_secret = BigInt::encode_1363 ( key->m_private_value, key->m_private_value.bytes() );
+
+ return DER_Encoder()
+ .start_cons ( SEQUENCE )
+ .encode ( BigInt ( 1 ) )
+ .encode ( octstr_secret, OCTET_STRING )
+ .end_cons()
+ .get_contents();
+ }
+
+ EC_Key_Encoder ( const EC_PrivateKey* k ) : key ( k )
+ {}
+ private:
+ const EC_PrivateKey* key;
+ };
+
+ return new EC_Key_Encoder(this);
+ }
+
+/**
+* Return the PKCS #8 public key decoder
+*/
+PKCS8_Decoder* EC_PrivateKey::pkcs8_decoder(RandomNumberGenerator&)
+ {
+ class EC_Key_Decoder : public PKCS8_Decoder
+ {
+ public:
+ void alg_id ( const AlgorithmIdentifier& alg_id )
+ {
+ key->mp_dom_pars.reset ( new EC_Domain_Params ( decode_ber_ec_dompar ( alg_id.parameters ) ) );
+ }
+
+ void key_bits ( const MemoryRegion<byte>& bits )
+ {
+ u32bit version;
+ SecureVector<byte> octstr_secret;
+ BER_Decoder ( bits )
+ .start_cons ( SEQUENCE )
+ .decode ( version )
+ .decode ( octstr_secret, OCTET_STRING )
+ .verify_end()
+ .end_cons();
+ key->m_private_value = BigInt::decode ( octstr_secret, octstr_secret.size() );
+ if ( version != 1 )
+ throw Decoding_Error ( "Wrong PKCS #1 key format version for EC key" );
+ key->PKCS8_load_hook();
+ }
+
+ EC_Key_Decoder ( EC_PrivateKey* k ) : key ( k )
+ {}
+ private:
+ EC_PrivateKey* key;
+ };
+
+ return new EC_Key_Decoder(this);
+ }
+
+
+void EC_PrivateKey::PKCS8_load_hook ( bool )
+ {
+ // we cannot use affirm_init() here because mp_public_point might still be null
+ if (mp_dom_pars.get() == 0 )
+ {
+ throw Invalid_State("attempt to set public point for an uninitialized key");
+ }
+ mp_public_point.reset ( new PointGFp ( m_private_value * mp_dom_pars->get_base_point() ) );
+ mp_public_point->check_invariants();
+
+ }
+
+
+
+
+/*************************************************
+* ECDSA_PublicKey *
+*************************************************/
+void ECDSA_PublicKey::affirm_init() const // virtual
+ {
+ EC_PublicKey::affirm_init();
+ }
+void ECDSA_PublicKey::set_domain_parameters(EC_Domain_Params const& dom_pars)
+ {
+ if (mp_dom_pars.get())
+ {
+ // they are already set, we must ensure that they are equal to the arg
+ if (dom_pars != *mp_dom_pars.get())
+ {
+ throw Invalid_Argument("EC_PublicKey::set_domain_parameters(): domain parameters are already set, and they are different from the argument");
+ }
+ else
+ {
+ // they are equal, so nothing to do
+ return;
+ }
+ }
+ // set them ...
+ if (m_enc_public_point.size() == 0)
+ {
+ throw Invalid_State("EC_PublicKey::set_domain_parameters(): encoded public point isn´t set");
+ }
+
+ // now try to decode the public key ...
+ PointGFp tmp_pp(OS2ECP(m_enc_public_point, dom_pars.get_curve()));
+ try
+ {
+ tmp_pp.check_invariants();
+ }
+ catch(Illegal_Point e)
+ {
+ throw Invalid_State("EC_PublicKey::set_domain_parameters(): point does not lie on provided curve");
+ }
+ std::auto_ptr<EC_Domain_Params> p_tmp_pars(new EC_Domain_Params(dom_pars));
+ ECDSA_Core tmp_ecdsa_core( *p_tmp_pars, BigInt ( 0 ), tmp_pp );
+ mp_public_point.reset(new PointGFp(tmp_pp));
+ m_ecdsa_core = tmp_ecdsa_core;
+ mp_dom_pars = p_tmp_pars;
+ }
+
+void ECDSA_PublicKey::set_all_values ( ECDSA_PublicKey const& other )
+ {
+ m_param_enc = other.m_param_enc;
+ m_ecdsa_core = other.m_ecdsa_core;
+ m_enc_public_point = other.m_enc_public_point;
+ if ( other.mp_dom_pars.get() )
+ {
+ mp_dom_pars.reset ( new EC_Domain_Params ( * ( other.mp_dom_pars ) ) );
+ }
+ if ( other.mp_public_point.get() )
+ {
+ mp_public_point.reset ( new PointGFp ( * ( other.mp_public_point ) ) );
+ }
+ }
+ECDSA_PublicKey::ECDSA_PublicKey ( ECDSA_PublicKey const& other )
+ : Public_Key(),
+ EC_PublicKey(),
+ PK_Verifying_wo_MR_Key()
+ {
+ set_all_values ( other );
+ }
+ECDSA_PublicKey const& ECDSA_PublicKey::operator= ( ECDSA_PublicKey const& rhs )
+ {
+ set_all_values ( rhs );
+ return *this;
+ }
+bool ECDSA_PublicKey::verify ( const byte message[], u32bit mess_len, const byte signature [], u32bit sig_len ) const
+ {
+ affirm_init();
+ ECDSA_Signature sig;
+ std::auto_ptr<ECDSA_Signature_Decoder> dec(sig.x509_decoder());
+ SecureVector<byte> sv_sig;
+ sv_sig.set ( signature, sig_len );
+ dec->signature_bits ( sv_sig );
+ SecureVector<byte> sv_plain_sig = sig.get_concatenation();
+ return m_ecdsa_core.verify ( sv_plain_sig, sv_plain_sig.size(), message, mess_len );
+ }
+ECDSA_PublicKey::ECDSA_PublicKey ( EC_Domain_Params const& dom_par, PointGFp const& public_point )
+ {
+ mp_dom_pars = std::auto_ptr<EC_Domain_Params> ( new EC_Domain_Params ( dom_par ) );
+ mp_public_point = std::auto_ptr<PointGFp> ( new PointGFp ( public_point ) );
+ m_param_enc = ENC_EXPLICIT;
+ m_ecdsa_core = ECDSA_Core ( *mp_dom_pars, BigInt ( 0 ), *mp_public_point );
+ }
+void ECDSA_PublicKey::X509_load_hook()
+ {
+ EC_PublicKey::X509_load_hook();
+ EC_PublicKey::affirm_init();
+ m_ecdsa_core = ECDSA_Core ( *mp_dom_pars, BigInt ( 0 ), *mp_public_point );
+ }
+u32bit ECDSA_PublicKey::max_input_bits() const
+ {
+ if(!mp_dom_pars.get())
+ {
+ throw Invalid_State("ECDSA_PublicKey::max_input_bits(): domain parameters not set");
+ }
+ return mp_dom_pars->get_order().bits();
+ }
+
+
+/*************************
+* ECDSA_PrivateKey *
+*************************/
+
+void ECDSA_PrivateKey::affirm_init() const // virtual
+ {
+ EC_PrivateKey::affirm_init();
+ }
+
+void ECDSA_PrivateKey::PKCS8_load_hook ( bool generated )
+ {
+ EC_PrivateKey::PKCS8_load_hook ( generated );
+ EC_PrivateKey::affirm_init();
+ m_ecdsa_core = ECDSA_Core ( *mp_dom_pars, m_private_value, *mp_public_point );
+ }
+
+
+void ECDSA_PrivateKey::set_all_values ( ECDSA_PrivateKey const& other )
+ {
+ m_private_value = other.m_private_value;
+ m_param_enc = other.m_param_enc;
+ m_ecdsa_core = other.m_ecdsa_core;
+ m_enc_public_point = other.m_enc_public_point;
+ if ( other.mp_dom_pars.get() )
+ {
+ mp_dom_pars.reset ( new EC_Domain_Params ( * ( other.mp_dom_pars ) ) );
+ }
+ if ( other.mp_public_point.get() )
+ {
+ mp_public_point.reset ( new PointGFp ( * ( other.mp_public_point ) ) );
+ }
+ }
+
+ECDSA_PrivateKey::ECDSA_PrivateKey(ECDSA_PrivateKey const& other)
+ : Public_Key(),
+ EC_PublicKey(),
+ Private_Key(),
+ ECDSA_PublicKey(),
+ EC_PrivateKey(),
+ PK_Signing_Key()
+ {
+ set_all_values(other);
+ }
+ECDSA_PrivateKey const& ECDSA_PrivateKey::operator= (ECDSA_PrivateKey const& rhs)
+ {
+ set_all_values(rhs);
+ return *this;
+ }
+SecureVector<byte> ECDSA_PrivateKey::sign ( const byte message [], u32bit mess_len ) const
+ {
+ affirm_init();
+ SecureVector<byte> sv_sig = m_ecdsa_core.sign ( message, mess_len );
+ //code which der encodes the signature returned
+ ECDSA_Signature sig = decode_concatenation( sv_sig );
+ std::auto_ptr<ECDSA_Signature_Encoder> enc(sig.x509_encoder());
+ return enc->signature_bits();
+
+ }
+
+
+
+/*********************************
+* ECKAEG_PublicKey *
+*********************************/
+
+void ECKAEG_PublicKey::affirm_init() const // virtual
+ {
+ EC_PublicKey::affirm_init();
+ }
+
+void ECKAEG_PublicKey::set_all_values ( ECKAEG_PublicKey const& other )
+ {
+ m_param_enc = other.m_param_enc;
+ m_eckaeg_core = other.m_eckaeg_core;
+ m_enc_public_point = other.m_enc_public_point;
+ if ( other.mp_dom_pars.get() )
+ {
+ mp_dom_pars.reset ( new EC_Domain_Params ( * ( other.mp_dom_pars ) ) );
+ }
+ if ( other.mp_public_point.get() )
+ {
+ mp_public_point.reset ( new PointGFp ( * ( other.mp_public_point ) ) );
+ }
+ }
+ECKAEG_PublicKey::ECKAEG_PublicKey ( ECKAEG_PublicKey const& other )
+ : Public_Key(),
+ EC_PublicKey()
+ {
+ set_all_values ( other );
+ }
+ECKAEG_PublicKey const& ECKAEG_PublicKey::operator= ( ECKAEG_PublicKey const& rhs )
+ {
+ set_all_values ( rhs );
+ return *this;
+ }
+
+void ECKAEG_PublicKey::X509_load_hook()
+ {
+ EC_PublicKey::X509_load_hook();
+ EC_PublicKey::affirm_init();
+ m_eckaeg_core = ECKAEG_Core ( *mp_dom_pars, BigInt ( 0 ), *mp_public_point );
+ }
+ECKAEG_PublicKey::ECKAEG_PublicKey ( EC_Domain_Params const& dom_par, PointGFp const& public_point )
+ {
+
+ mp_dom_pars = std::auto_ptr<EC_Domain_Params> ( new EC_Domain_Params ( dom_par ) );
+ mp_public_point = std::auto_ptr<PointGFp> ( new PointGFp ( public_point ) );
+ if(mp_public_point->get_curve() != mp_dom_pars->get_curve())
+ {
+ throw Invalid_Argument("ECKAEG_PublicKey(): curve of arg. point and curve of arg. domain parameters are different");
+ }
+ EC_PublicKey::affirm_init();
+ m_eckaeg_core = ECKAEG_Core ( *mp_dom_pars, BigInt ( 0 ), *mp_public_point );
+ }
+
+
+/*********************************
+* ECKAEG_PrivateKey *
+*********************************/
+void ECKAEG_PrivateKey::affirm_init() const // virtual
+ {
+ EC_PrivateKey::affirm_init();
+ }
+void ECKAEG_PrivateKey::PKCS8_load_hook ( bool generated )
+ {
+ EC_PrivateKey::PKCS8_load_hook ( generated );
+ EC_PrivateKey::affirm_init();
+ m_eckaeg_core = ECKAEG_Core ( *mp_dom_pars, m_private_value, *mp_public_point );
+ }
+void ECKAEG_PrivateKey::set_all_values ( ECKAEG_PrivateKey const& other )
+ {
+ m_private_value = other.m_private_value;
+ m_param_enc = other.m_param_enc;
+ m_eckaeg_core = other.m_eckaeg_core;
+ m_enc_public_point = other.m_enc_public_point;
+ if ( other.mp_dom_pars.get() )
+ {
+ mp_dom_pars.reset ( new EC_Domain_Params ( * ( other.mp_dom_pars ) ) );
+ }
+ if ( other.mp_public_point.get() )
+ {
+ mp_public_point.reset ( new PointGFp ( * ( other.mp_public_point ) ) );
+ }
+ }
+
+ECKAEG_PrivateKey::ECKAEG_PrivateKey(ECKAEG_PrivateKey const& other)
+ : Public_Key(),
+ EC_PublicKey(),
+ Private_Key(),
+ ECKAEG_PublicKey(),
+ EC_PrivateKey(),
+ PK_Key_Agreement_Key()
+
+ {
+ set_all_values(other);
+ }
+ECKAEG_PrivateKey const& ECKAEG_PrivateKey::operator= (ECKAEG_PrivateKey const& rhs)
+ {
+ set_all_values(rhs);
+ return *this;
+ }
+
+/**
+* Derive a key
+*/
+SecureVector<byte> ECKAEG_PrivateKey::derive_key(const Public_Key& key) const
+ {
+ affirm_init();
+
+ const EC_PublicKey * p_ec_pk = dynamic_cast<const EC_PublicKey*>(&key);
+ if(!p_ec_pk)
+ {
+ throw Invalid_Argument("ECKAEG_PrivateKey::derive_key(): argument must be an EC_PublicKey");
+ }
+ p_ec_pk->affirm_init();
+ return m_eckaeg_core.agree ( p_ec_pk->get_public_point() );
+ }
+
+}
diff --git a/src/ec_dompar.cpp b/src/ec_dompar.cpp
new file mode 100644
index 000000000..232233669
--- /dev/null
+++ b/src/ec_dompar.cpp
@@ -0,0 +1,288 @@
+#include <botan/ec_dompar.h>
+#include <botan/ec.h>
+#include <botan/enums.h>
+#include <botan/parsing.h>
+#include <botan/libstate.h>
+#include <botan/hex.h>
+
+namespace Botan {
+
+namespace {
+
+std::vector<std::string> get_standard_domain_parameter(const std::string& oid)
+ {
+ /*
+ GEC 2: Test Vectors for SEC 1
+ Certicom Research
+ Working Draft
+ September, 1999
+ Version 0.3;
+ section 2.1.2
+ */
+ if(oid == "1.3.132.8") // InSiTo had '08'
+ {
+ std::vector<std::string> dom_par;
+ dom_par.push_back("0xffffffffffffffffffffffffffffffff7fffffff"); //p
+ dom_par.push_back("0xffffffffffffffffffffffffffffffff7ffffffc"); // a
+ dom_par.push_back("0x1c97befc54bd7a8b65acf89f81d4d4adc565fa45"); // b
+ dom_par.push_back("024a96b5688ef573284664698968c38bb913cbfc82"); // G
+ dom_par.push_back("0x0100000000000000000001f4c8f927aed3ca752257"); // order
+ dom_par.push_back("1"); // cofactor
+ return dom_par;
+ }
+
+ if(oid == "1.2.840.10045.3.1.1") // prime192v1 Flexiprovider
+ {
+ std::vector<std::string> dom_par;
+ dom_par.push_back("0xfffffffffffffffffffffffffffffffeffffffffffffffff"); //p
+ dom_par.push_back("0xfffffffffffffffffffffffffffffffefffffffffffffffc"); // a
+ dom_par.push_back("0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1"); // b
+ dom_par.push_back("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012"); // G
+ dom_par.push_back("0xffffffffffffffffffffffff99def836146bc9b1b4d22831"); // order
+ dom_par.push_back("1"); // cofactor
+ }
+
+ /* prime192v2; source: Flexiprovider */
+ if(oid == "1.2.840.10045.3.1.2")
+ {
+ std::vector<std::string> dom_par;
+ dom_par.push_back("0xfffffffffffffffffffffffffffffffeffffffffffffffff"); //p
+ dom_par.push_back("0xffffffffffffffffffffffffffffffFeffffffffffffffFC"); // a
+ dom_par.push_back("0xcc22d6dfb95c6b25e49c0d6364a4e5980c393aa21668d953"); // b
+ dom_par.push_back("03eea2bae7e1497842f2de7769cfe9c989c072ad696f48034a"); // G
+ dom_par.push_back("0xfffffffffffffffffffffffe5fb1a724dc80418648d8dd31"); // order
+ dom_par.push_back("1"); // cofactor
+ }
+
+ /* prime192v3; source: Flexiprovider */
+ if(oid == "1.2.840.10045.3.1.3")
+ {
+ std::vector<std::string> dom_par;
+ dom_par.push_back("0xfffffffffffffffffffffffffffffffeffffffffffffffff"); //p
+ dom_par.push_back("0xfffffffffffffffffffffffffffffffefffffffffffffffc"); // a
+ dom_par.push_back("0x22123dc2395a05caa7423daeccc94760a7d462256bd56916"); // b
+ dom_par.push_back("027d29778100c65a1da1783716588dce2b8b4aee8e228f1896"); // G
+ dom_par.push_back("0xffffffffffffffffffffffff7a62d031c83f4294f640ec13"); // order
+ dom_par.push_back("1"); // cofactor
+ }
+
+ /* prime239v1; source: Flexiprovider */
+ if(oid == "1.2.840.10045.3.1.4")
+ {
+ std::vector<std::string> dom_par;
+ dom_par.push_back("0x7fffffffffffffffffffffff7fffffffffff8000000000007fffffffffff"); //p
+ dom_par.push_back("0x7ffFffffffffffffffffffff7fffffffffff8000000000007ffffffffffc"); // a
+ dom_par.push_back("0x6B016C3BDCF18941D0D654921475CA71A9DB2FB27D1D37796185C2942C0A"); // b
+ dom_par.push_back("020ffA963CDCA8816CCC33B8642BEDF905C3D358573D3F27FBBD3B3CB9AAAF"); // G
+ dom_par.push_back("0x7fffffffffffffffffffffff7fffff9e5e9a9f5d9071fbd1522688909d0b"); // order
+ dom_par.push_back("1"); // cofactor
+ }
+
+ /* prime239v2; source: Flexiprovider */
+ if(oid == "1.2.840.10045.3.1.5")
+ {
+ std::vector<std::string> dom_par;
+ dom_par.push_back("0x7fffffffffffffffffffffff7fffffffffff8000000000007fffffffffff"); //p
+ dom_par.push_back("0x7ffFffffffffffffffffffff7ffFffffffff8000000000007ffFffffffFC"); // a
+ dom_par.push_back("0x617FAB6832576CBBFED50D99F0249C3FEE58B94BA0038C7AE84C8C832F2C"); // b
+ dom_par.push_back("0238AF09D98727705120C921BB5E9E26296A3CDCF2F35757A0EAFD87B830E7"); // G
+ dom_par.push_back("0x7fffffffffffffffffffffff800000CFA7E8594377D414C03821BC582063"); // order
+ dom_par.push_back("1"); // cofactor
+ }
+
+ /* prime239v3; source: Flexiprovider */
+ if(oid == "1.2.840.10045.3.1.6")
+ {
+ std::vector<std::string> dom_par;
+ dom_par.push_back("0x7fffffffffffffffffffffff7fffffffffff8000000000007fffffffffff"); //p
+ dom_par.push_back("0x7ffFffffffffffffffffffff7ffFffffffff8000000000007ffFffffffFC"); // a
+ dom_par.push_back("0x255705FA2A306654B1F4CB03D6A750A30C250102D4988717D9BA15AB6D3E"); // b
+ dom_par.push_back("036768AE8E18BB92CFCF005C949AA2C6D94853D0E660BBF854B1C9505FE95A"); // G
+ dom_par.push_back("0x7fffffffffffffffffffffff7fffff975DEB41B3A6057C3C432146526551"); // order
+ dom_par.push_back("1"); // cofactor
+ }
+
+ /* prime256v1; source: Flexiprovider */
+ if(oid == "1.2.840.10045.3.1.7")
+ {
+ std::vector<std::string> dom_par;
+ dom_par.push_back("0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff"); //p
+ dom_par.push_back("0xffffffff00000001000000000000000000000000ffffffffffffffffffffffFC"); // a
+ dom_par.push_back("0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B"); // b
+ dom_par.push_back("036B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"); // G
+ dom_par.push_back("0xffffffff00000000ffffffffffffffffBCE6FAADA7179E84F3B9CAC2FC632551"); // order
+ dom_par.push_back("1"); // cofactor
+ }
+
+ throw Invalid_Argument("No such ECC curve " + oid);
+
+ // Todo, add SEC2, Brainpool, NIST curves
+ }
+
+EC_Domain_Params get_ec_dompar(const std::string& oid)
+ {
+ std::vector<std::string> dom_par = get_standard_domain_parameter(oid);
+
+ BigInt p(dom_par[0]); // give as 0x...
+ GFpElement a(p, BigInt(dom_par[1]));
+ GFpElement b(p, BigInt(dom_par[2]));
+
+ Pipe pipe(new Hex_Decoder);
+ pipe.process_msg(dom_par[3]);
+ SecureVector<byte> sv_g = pipe.read_all();
+
+ CurveGFp curve(a, b, p);
+ PointGFp G = OS2ECP ( sv_g, curve );
+ G.check_invariants();
+ BigInt order(dom_par[4]);
+ BigInt cofactor(dom_par[5]);
+ EC_Domain_Params result(curve, G, order, cofactor);
+ return result;
+ }
+
+}
+
+EC_Domain_Params get_EC_Dom_Pars_by_oid(std::string oid)
+ {
+ EC_Domain_Params result = get_ec_dompar(oid);
+ result.m_oid = oid;
+ return result;
+ }
+
+EC_Domain_Params::EC_Domain_Params(const CurveGFp& curve, const PointGFp& base_point,
+ const BigInt& order, const BigInt& cofactor)
+ : m_curve(curve),
+ m_base_point(base_point),
+ m_order(order),
+ m_cofactor(cofactor),
+ m_oid("")
+ { }
+
+namespace {
+
+SecureVector<byte> encode_der_ec_dompar_explicit(EC_Domain_Params const& dom_pars)
+ {
+ u32bit ecpVers1 = 1;
+ OID curve_type_oid("1.2.840.10045.1.1");
+
+ DER_Encoder der;
+
+ der.start_cons(SEQUENCE)
+ .encode(ecpVers1)
+ .start_cons(SEQUENCE)
+ .encode(curve_type_oid)
+ .encode(dom_pars.get_curve().get_p())
+ .end_cons()
+ .start_cons(SEQUENCE)
+ .encode(FE2OSP ( dom_pars.get_curve().get_a() ), OCTET_STRING)
+ .encode(FE2OSP ( dom_pars.get_curve().get_b() ), OCTET_STRING)
+ .end_cons()
+ .encode(EC2OSP ( dom_pars.get_base_point(), PointGFp::UNCOMPRESSED), OCTET_STRING)
+ .encode(dom_pars.get_order())
+ .encode(dom_pars.get_cofactor())
+ .end_cons();
+
+ return der.get_contents();
+ }
+
+EC_Domain_Params decode_ber_ec_dompar_explicit(SecureVector<byte> const& encoded)
+ {
+ BigInt ecpVers1(1);
+ OID curve_type_oid;
+ SecureVector<byte> sv_a;
+ SecureVector<byte> sv_b;
+ BigInt p;
+ SecureVector<byte> sv_base_point;
+ BigInt order;
+ BigInt cofactor;
+ BER_Decoder dec(encoded);
+ dec
+ .start_cons(SEQUENCE)
+ .decode(ecpVers1)
+ .start_cons(SEQUENCE)
+ .decode(curve_type_oid)
+ .decode(p)
+ .end_cons()
+ .start_cons(SEQUENCE)
+ .decode(sv_a, OCTET_STRING)
+ .decode(sv_b, OCTET_STRING)
+ .end_cons()
+ .decode(sv_base_point, OCTET_STRING)
+ .decode(order)
+ .decode(cofactor)
+ .verify_end()
+ .end_cons();
+ if(ecpVers1 != 1)
+ {
+ throw Decoding_Error("wrong ecpVers");
+ }
+ // Set the domain parameters
+ if(curve_type_oid.as_string() != "1.2.840.10045.1.1") // NOTE: hardcoded: prime field type
+ {
+ throw Decoding_Error("wrong curve type oid where prime field was expected");
+ }
+ GFpElement a(p,BigInt::decode(sv_a, sv_a.size()));
+ GFpElement b(p,BigInt::decode(sv_b, sv_b.size()));
+ CurveGFp curve(a,b,p);
+ PointGFp G = OS2ECP ( sv_base_point, curve );
+ G.check_invariants();
+ return EC_Domain_Params(curve, G, order, cofactor);
+ }
+
+} // end anonymous namespace
+
+SecureVector<byte> encode_der_ec_dompar(EC_Domain_Params const& dom_pars, EC_dompar_enc enc_type)
+ {
+ SecureVector<byte> result;
+
+ if(enc_type == ENC_EXPLICIT)
+ {
+ result = encode_der_ec_dompar_explicit(dom_pars);
+ }
+ else if(enc_type == ENC_OID)
+ {
+ OID dom_par_oid(dom_pars.get_oid());
+ result = DER_Encoder().encode(dom_par_oid).get_contents();
+ }
+ else if(enc_type == ENC_IMPLICITCA)
+ {
+ result = DER_Encoder().encode_null().get_contents();
+ }
+ else
+ {
+ throw Internal_Error("encountered illegal value for ec parameter encoding type");
+ }
+ return result;
+ }
+
+EC_Domain_Params decode_ber_ec_dompar(SecureVector<byte> const& encoded)
+ {
+ BER_Decoder dec(encoded);
+ BER_Object obj = dec.get_next_object();
+ ASN1_Tag tag = obj.type_tag;
+ std::auto_ptr<EC_Domain_Params> p_result;
+
+ if(tag == OBJECT_ID)
+ {
+ OID dom_par_oid;
+ BER_Decoder(encoded).decode(dom_par_oid);
+ return EC_Domain_Params(get_ec_dompar(dom_par_oid.as_string()));
+ }
+ else if(tag == SEQUENCE)
+ return EC_Domain_Params(decode_ber_ec_dompar_explicit(encoded));
+ else if(tag == NULL_TAG)
+ throw Decoding_Error("cannot decode ECDSA parameters that are ImplicitCA");
+
+ throw Decoding_Error("encountered unexpected when trying to decode domain parameters");
+ }
+
+bool operator==(EC_Domain_Params const& lhs, EC_Domain_Params const& rhs)
+ {
+ return ((lhs.get_curve() == rhs.get_curve()) &&
+ (lhs.get_base_point() == rhs.get_base_point()) &&
+ (lhs.get_order() == rhs.get_order()) &&
+ (lhs.get_cofactor() == rhs.get_cofactor()));
+ }
+
+}
+
diff --git a/src/ecdsa.cpp b/src/ecdsa.cpp
new file mode 100644
index 000000000..04dc1e529
--- /dev/null
+++ b/src/ecdsa.cpp
@@ -0,0 +1,72 @@
+#include <botan/bigint.h>
+#include <botan/ecdsa.h>
+#include <memory>
+
+namespace Botan {
+
+ECDSA_Signature::ECDSA_Signature(const BigInt& r, const BigInt& s)
+ : m_r(r),
+ m_s(s)
+ {}
+
+ECDSA_Signature::ECDSA_Signature(ECDSA_Signature const& other)
+ : m_r(other.m_r),
+ m_s(other.m_s)
+ {}
+
+ECDSA_Signature const& ECDSA_Signature::operator=(ECDSA_Signature const& other)
+ {
+ m_r = other.m_r;
+ m_s = other.m_s;
+ return *this;
+ }
+
+bool operator== ( ECDSA_Signature const& lhs, ECDSA_Signature const& rhs )
+ {
+ return (lhs.get_r() == rhs.get_r() && lhs.get_s() == rhs.get_s());
+ }
+
+ECDSA_Signature_Decoder* ECDSA_Signature::x509_decoder()
+ {
+ return new ECDSA_Signature_Decoder(this);
+ }
+
+ECDSA_Signature_Encoder* ECDSA_Signature::x509_encoder() const
+ {
+ return new ECDSA_Signature_Encoder(this);
+ }
+SecureVector<byte> const ECDSA_Signature::get_concatenation() const
+ {
+ u32bit enc_len = m_r > m_s ? m_r.bytes() : m_s.bytes(); // use the larger
+ SecureVector<byte> sv_r = BigInt::encode_1363 ( m_r, enc_len );
+ SecureVector<byte> sv_s = BigInt::encode_1363 ( m_s, enc_len );
+ SecureVector<byte> result(sv_r);
+ result.append(sv_s);
+ return result;
+ }
+
+ECDSA_Signature const decode_seq(MemoryRegion<byte> const& seq)
+ {
+ ECDSA_Signature sig;
+ std::auto_ptr<ECDSA_Signature_Decoder> dec(sig.x509_decoder());
+ dec->signature_bits(seq);
+ return sig;
+ }
+
+ECDSA_Signature const decode_concatenation(MemoryRegion<byte> const& concatenation)
+ {
+ if(concatenation.size() % 2 != 0)
+ {
+ throw Invalid_Argument("Erroneous length of signature");
+ }
+ u32bit rs_len = concatenation.size()/2;
+ SecureVector<byte> sv_r;
+ SecureVector<byte> sv_s;
+ sv_r.set(concatenation.begin(), rs_len);
+ sv_s.set(&concatenation[rs_len], rs_len);
+ BigInt r = BigInt::decode ( sv_r, sv_r.size());
+ BigInt s = BigInt::decode (sv_s, sv_s.size());
+ return ECDSA_Signature(r, s);
+ }
+
+}
diff --git a/src/eng_base.cpp b/src/eng_base.cpp
index 38234d462..bd6b53447 100644
--- a/src/eng_base.cpp
+++ b/src/eng_base.cpp
@@ -111,6 +111,26 @@ DH_Operation* Engine::dh_op(const DL_Group&, const BigInt&) const
/*************************************************
* Basic No-Op Engine Implementation *
*************************************************/
+ECDSA_Operation* Engine::ecdsa_op(const EC_Domain_Params&,
+ const BigInt&,
+ const PointGFp&) const
+ {
+ return 0;
+ }
+
+/*************************************************
+* Basic No-Op Engine Implementation *
+*************************************************/
+ECKAEG_Operation* Engine::eckaeg_op(const EC_Domain_Params&,
+ const BigInt&,
+ const PointGFp&) const
+ {
+ return 0;
+ }
+
+/*************************************************
+* Basic No-Op Engine Implementation *
+*************************************************/
Modular_Exponentiator* Engine::mod_exp(const BigInt&,
Power_Mod::Usage_Hints) const
{
diff --git a/src/engine.cpp b/src/engine.cpp
index 0a4bb48ee..bfa02ed5d 100644
--- a/src/engine.cpp
+++ b/src/engine.cpp
@@ -101,6 +101,44 @@ DH_Operation* dh_op(const DL_Group& group, const BigInt& x)
}
/*************************************************
+* Acquire an ECDSA op *
+*************************************************/
+ECDSA_Operation* ecdsa_op(const EC_Domain_Params& dom_pars,
+ const BigInt& priv_key,
+ const PointGFp& pub_key)
+ {
+ Library_State::Engine_Iterator i(global_state());
+
+ while(const Engine* engine = i.next())
+ {
+ ECDSA_Operation* op = engine->ecdsa_op(dom_pars, priv_key, pub_key);
+ if(op)
+ return op;
+ }
+
+ throw Lookup_Error("Engine_Core::ecdsa_op: Unable to find a working engine");
+ }
+
+/*************************************************
+* Acquire a ECKAEG op *
+*************************************************/
+ECKAEG_Operation* eckaeg_op(const EC_Domain_Params& dom_pars,
+ const BigInt& priv_key,
+ const PointGFp& pub_key)
+ {
+ Library_State::Engine_Iterator i(global_state());
+
+ while(const Engine* engine = i.next())
+ {
+ ECKAEG_Operation* op = engine->eckaeg_op(dom_pars, priv_key, pub_key);
+ if(op)
+ return op;
+ }
+
+ throw Lookup_Error("Engine_Core::eckaeg_op: Unable to find a working engine");
+ }
+
+/*************************************************
* Acquire a modular exponentiator *
*************************************************/
Modular_Exponentiator* mod_exp(const BigInt& n, Power_Mod::Usage_Hints hints)
diff --git a/src/gfp_element.cpp b/src/gfp_element.cpp
new file mode 100644
index 000000000..686cc338b
--- /dev/null
+++ b/src/gfp_element.cpp
@@ -0,0 +1,674 @@
+/******************************************************
+ * Arithmetic for prime fields GF(p) (source file) *
+ * *
+ * (C) 2007 Martin Doering *
+ * Christoph Ludwig *
+ * Falko Strenzke *
+ ******************************************************/
+
+#include <botan/gfp_element.h>
+#include <botan/numthry.h>
+#include <botan/def_powm.h>
+#include <botan/mp_asm.h>
+#include <botan/mp_asmi.h>
+#include <botan/mp_core.h>
+
+namespace Botan {
+
+namespace {
+
+/**
+*calculates R=b^n (here b=2) with R>m (and R beeing as small as possible) for an odd modulus m.
+* no check for oddity is performed!
+*/
+BigInt montgm_calc_r_oddmod(const BigInt& prime)
+ {
+ u32bit n = prime.sig_words();
+ BigInt result(1);
+ result <<= n*BOTAN_MP_WORD_BITS;
+ return result;
+
+ }
+
+/**
+*calculates m' with r*r^-1 - m*m' = 1
+* where r^-1 is the multiplicative inverse of r to the modulus m
+*/
+BigInt montgm_calc_m_dash(const BigInt& r, const BigInt& m, const BigInt& r_inv )
+ {
+ BigInt result = ((r * r_inv) - BigInt(1))/m;
+ return result;
+ }
+BigInt montg_trf_to_mres(const BigInt& ord_res, const BigInt& r, const BigInt& m)
+ {
+ BigInt result(ord_res);
+ result *= r;
+ result %= m;
+ return result;
+ }
+BigInt montg_trf_to_ordres(const BigInt& m_res, const BigInt& m, const BigInt& r_inv)
+ {
+ BigInt result(m_res);
+ result *= r_inv;
+ result %= m;
+ return result;
+ }
+
+void inner_montg_mult_sos(word result[], const word* a_bar,
+ const word* b_bar, const word* n,
+ const word* n_dash, u32bit s)
+ {
+ SecureVector<word> t;
+ t.grow_to(2*s+1);
+
+ for (u32bit i=0; i<s; i++)
+ {
+ word C = 0;
+ word S = 0;
+ for (u32bit j=0; j<s; j++)
+ {
+ S = word_madd3(a_bar[j], b_bar[i], t[i+j], &C);
+ t[i+j] = S;
+ }
+ t[i+s] = C;
+ }
+
+
+ for (u32bit i=0; i<s; i++)
+ {
+ // word word_madd2(word a, word b, word c, word* carry)
+ // returns a * b + c, resets the carry
+
+ word C = 0;
+ word m = word_madd2(t[i], n_dash[0], &C);
+ // C = 0; ???
+
+ for (u32bit j=0; j<s; j++)
+ {
+ word S = word_madd3(m, n[j], t[i+j], &C);
+ t[i+j] = S;
+ }
+
+ //// mp_mulop.cpp:
+ ////word bigint_mul_add_words(word z[], const word x[], u32bit x_size, word y)
+ u32bit cnt = 0;
+ while (C > 0)
+ {
+ // we need not worry here about C > 1, because the other operand is zero
+ word tmp = word_add(t[i+s+cnt], 0, &C);
+ t[i+s+cnt] = tmp;
+ cnt++;
+ }
+ }
+ SecureVector<word> u;
+ u.grow_to(s+1);
+ for (u32bit j=0; j<s+1; j++)
+ {
+ u[j] = t[j+s];
+ }
+
+ word B = 0;
+ word D = 0;
+ for (u32bit i=0; i<s; i++)
+ {
+ D = word_sub(u[i], n[i], &B);
+ t[i] = D;
+ }
+ D = word_sub(u[s], 0, &B);
+ t[s] = D;
+ if (B == 0)
+ {
+ for (u32bit i=0; i<s; i++)
+ {
+ result[i] = t[i];
+ }
+ }
+ else
+ {
+ for (u32bit i=0; i<s; i++)
+ {
+ result[i] = u[i];
+ }
+ }
+ }
+
+void montg_mult(BigInt& result, BigInt& a_bar, BigInt& b_bar, const BigInt& m, const BigInt& m_dash, const BigInt )
+ {
+ if (m.is_zero() || m_dash.is_zero())
+ {
+ throw Invalid_Argument("montg_mult(): neither modulus nor m_dash may be zero (and one of them was)");
+ }
+ if (a_bar.is_zero() || b_bar.is_zero())
+ {
+ result = 0;
+ }
+ u32bit s = m.sig_words();
+ a_bar.grow_to(s);
+ b_bar.grow_to(s);
+
+ result.grow_to(s);
+
+ inner_montg_mult_sos(result.get_reg(), a_bar.data(), b_bar.data(), m.data(), m_dash.data(), s);
+
+ }
+
+
+}
+
+GFpElement::GFpElement ( const BigInt& p, const BigInt& value, bool use_montgm)
+ : mp_mod(),
+ m_value(value %p),
+ m_use_montgm(use_montgm),
+ m_is_trf(false)
+ {
+ //assert(mp_mod.get() == 0);
+ mp_mod = std::tr1::shared_ptr<GFpModulus>(new GFpModulus(p));
+ //assert(mp_mod->m_p_dash == 0);
+ if (m_use_montgm)
+ {
+ ensure_montgm_precomp();
+
+ }
+
+ }
+
+GFpElement::GFpElement(std::tr1::shared_ptr<GFpModulus> const mod, const BigInt& value, bool use_montgm)
+ : mp_mod(),
+ m_value(value % mod->m_p),
+ m_use_montgm(use_montgm),
+ m_is_trf(false)
+ {
+ //assert(mp_mod.get() == 0);
+ mp_mod = mod;
+ }
+
+GFpElement::GFpElement ( GFpElement const& other )
+ : m_value ( other.m_value ),
+ m_use_montgm(other.m_use_montgm),
+ m_is_trf(other.m_is_trf)
+
+ {
+ //creates an independent copy
+ //assert((other.m_is_trf && other.m_use_montgm) || !other.m_is_trf);
+ mp_mod.reset(new GFpModulus(*other.mp_mod)); // copy-ctor of GFpModulus
+ }
+
+void GFpElement::turn_on_sp_red_mul() const
+ {
+ ensure_montgm_precomp();
+ m_use_montgm = true;
+ }
+void GFpElement::turn_off_sp_red_mul() const
+ {
+ if (m_is_trf)
+ {
+ trf_to_ordres();
+ // will happen soon anyway, so we can do it here already
+ // (this is not lazy but way more secure concerning our internal logic here)
+ }
+ m_use_montgm = false;
+ }
+void GFpElement::ensure_montgm_precomp() const
+ {
+ if ((!mp_mod->m_r.is_zero()) && (!mp_mod->m_r_inv.is_zero()) && (!mp_mod->m_p_dash.is_zero()))
+ {
+ // values are already set, nothing more to do
+ }
+ else
+ {
+ BigInt tmp_r(montgm_calc_r_oddmod(mp_mod->m_p));
+
+ BigInt tmp_r_inv(inverse_mod(tmp_r, mp_mod->m_p));
+
+ BigInt tmp_p_dash(montgm_calc_m_dash(tmp_r, mp_mod->m_p, tmp_r_inv));
+
+ mp_mod->m_r.grow_reg(tmp_r.size());
+ mp_mod->m_r_inv.grow_reg(tmp_r_inv.size());
+ mp_mod->m_p_dash.grow_reg(tmp_p_dash.size());
+
+ mp_mod->m_r = tmp_r;
+ mp_mod->m_r_inv = tmp_r_inv;
+ mp_mod->m_p_dash = tmp_p_dash;
+
+ //assert(!mp_mod->m_r.is_zero());
+ //assert(!mp_mod->m_r_inv.is_zero());
+ //assert(!mp_mod->m_p_dash.is_zero());
+ }
+
+ }
+
+void GFpElement::set_shrd_mod(std::tr1::shared_ptr<GFpModulus> const p_mod)
+ {
+ mp_mod = p_mod;
+ }
+void GFpElement::trf_to_mres() const
+ {
+ if (!m_use_montgm)
+ {
+ throw Illegal_Transformation("GFpElement is not allowed to be transformed to m-residue");
+ }
+ //assert(m_is_trf == false);
+ //assert(!mp_mod->m_r_inv.is_zero());
+ //assert(!mp_mod->m_p_dash.is_zero());
+ m_value = montg_trf_to_mres(m_value, mp_mod->m_r, mp_mod->m_p);
+ m_is_trf = true;
+ }
+void GFpElement::trf_to_ordres() const
+ {
+ //assert(m_is_trf == true);
+ m_value = montg_trf_to_ordres(m_value, mp_mod->m_p, mp_mod->m_r_inv);
+ m_is_trf = false;
+ }
+bool GFpElement::align_operands_res(GFpElement const& lhs, GFpElement const& rhs) //static
+ {
+ //assert(lhs.mp_mod->m_p == rhs.mp_mod->m_p);
+ if (lhs.m_use_montgm && rhs.m_use_montgm)
+ {
+
+ //assert(rhs.mp_mod->m_p_dash == lhs.mp_mod->m_p_dash);
+ //assert(rhs.mp_mod->m_r == lhs.mp_mod->m_r);
+ //assert(rhs.mp_mod->m_r_inv == lhs.mp_mod->m_r_inv);
+ if (!lhs.m_is_trf && !rhs.m_is_trf)
+ {
+ return false;
+ }
+ else if (lhs.m_is_trf && rhs.m_is_trf)
+ {
+ return true;
+ }
+ else // one is transf., the other not
+ {
+ if (!lhs.m_is_trf)
+ {
+ lhs.trf_to_mres();
+ //assert(rhs.m_is_trf==true);
+ return true;
+ }
+ //assert(rhs.m_is_trf==false);
+ //assert(lhs.m_is_trf==true);
+ rhs.trf_to_mres(); // the only possibility left...
+ return true;
+ }
+ }
+ else // at least one of them does not use mm
+ // (so it is impossible that both use it)
+ {
+ if (lhs.m_is_trf)
+ {
+ lhs.trf_to_ordres();
+ //assert(rhs.m_is_trf == false);
+ return false;
+ }
+ if (rhs.m_is_trf)
+ {
+ rhs.trf_to_ordres();
+ //assert(lhs.m_is_trf == false);
+ return false;
+ }
+ return false;
+ }
+ //assert(false);
+
+ }
+bool GFpElement::is_trf_to_mres() const
+ {
+ return m_is_trf;
+
+ }
+BigInt const GFpElement::get_p() const
+ {
+ return (mp_mod->m_p);
+ }
+BigInt const GFpElement::get_value() const
+ {
+
+ if (m_is_trf)
+ {
+ //assert(m_use_montgm);
+ trf_to_ordres();
+ }
+ return m_value;
+ }
+BigInt const GFpElement::get_mres() const
+ {
+ if (!m_use_montgm)
+ {
+ // does the following exception really make sense?
+ // wouldn´t it be better to simply turn on montg.mult. when
+ // this explicit request is made?
+ throw Illegal_Transformation("GFpElement is not allowed to be transformed to m-residue");
+ }
+ if (!m_is_trf)
+ {
+
+ trf_to_mres();
+
+ }
+ return m_value;
+ }
+GFpElement const& GFpElement::operator= ( GFpElement const& other )
+ {
+ m_value.grow_reg(other.m_value.size()); // grow first for exception safety
+
+ //m_value = other.m_value;
+
+ // m_use_montgm = other.m_use_montgm;
+ // m_is_trf = other.m_is_trf;
+ // we want to keep the member pointers, which might be part of a "sharing group"
+ // but we may not simply overwrite the BigInt values with those of the argument!!
+ // if ours already contains precomputations, it would be hazardous to
+ // set them back to zero.
+ // thus we first check for equality of the moduli,
+ // then whether either of the two objects already contains
+ // precomputed values.
+
+ // we also deal with the case were the pointers themsevles are equal:
+ if (mp_mod.get() == other.mp_mod.get())
+ {
+ // everything ok, we are in the same sharing group anyway, nothing to do
+ m_value = other.m_value; // cannot throw
+ m_use_montgm = other.m_use_montgm;
+ m_is_trf = other.m_is_trf;
+ return *this;
+ }
+ if (mp_mod->m_p != other.mp_mod->m_p)
+ {
+ // the moduli are different, this is a special case
+ // which will not occur in usual applications,
+ // so we don´t hesitate to simply create new objects
+ // (we do want to create an independent copy)
+ mp_mod.reset(new GFpModulus(*other.mp_mod)); // this could throw,
+ // and because of this
+ // we haven't modified
+ // anything so far
+ m_value = other.m_value; // can't throw
+ m_use_montgm = other.m_use_montgm;
+ m_is_trf = other.m_is_trf;
+ return *this;
+ }
+ // exception safety note: from now on we are on the safe
+ // side with respect to the modulus,
+ // so we can assign the value now:
+ m_value = other.m_value;
+ m_use_montgm = other.m_use_montgm;
+ m_is_trf = other.m_is_trf;
+ // the moduli are equal, but we deal with different sharing groups.
+ // we will NOT fuse the sharing goups
+ // and we will NOT reset already precomputed values
+ if (mp_mod->has_precomputations())
+ {
+ // our own sharing group already has precomputed values,
+ // so nothing to do.
+ return *this;
+ }
+ else
+ {
+ // let´s see whether the argument has something for us...
+ if (other.mp_mod->has_precomputations())
+ {
+ // fetch them for our sharing group
+ // exc. safety note: grow first
+ mp_mod->m_p_dash.grow_reg(other.mp_mod->m_p_dash.size());
+ mp_mod->m_r.grow_reg(other.mp_mod->m_r.size());
+ mp_mod->m_r_inv.grow_reg(other.mp_mod->m_r_inv.size());
+
+ mp_mod->m_p_dash = other.mp_mod->m_p_dash;
+ mp_mod->m_r = other.mp_mod->m_r;
+ mp_mod->m_r_inv = other.mp_mod->m_r_inv;
+ return *this;
+ }
+ }
+ // our precomputations aren´t set, the arguments neither,
+ // so we let them alone
+ return *this;
+
+
+ }
+void GFpElement::share_assign(GFpElement const& other)
+ {
+ //assert((other.m_is_trf && other.m_use_montgm) || !other.m_is_trf);
+
+ // use grow_to to make it exc safe
+ m_value.grow_reg(other.m_value.size());
+ m_value = other.m_value;
+
+ m_use_montgm = other.m_use_montgm;
+ m_is_trf = other.m_is_trf;
+ mp_mod = other.mp_mod; // cannot throw
+
+ }
+GFpElement& GFpElement::operator+= ( GFpElement const& rhs )
+ {
+ GFpElement::align_operands_res(*this, rhs);
+
+ workspace = m_value;
+ workspace += rhs.m_value;
+ if (workspace >= mp_mod->m_p)
+ {
+ workspace -= mp_mod->m_p;
+ }
+
+ m_value = workspace;
+ //assert(m_value < mp_mod->m_p);
+ //assert(m_value >= 0);
+
+ return *this;
+ }
+GFpElement& GFpElement::operator-= ( GFpElement const& rhs )
+ {
+ GFpElement::align_operands_res(*this, rhs);
+
+ workspace = m_value;
+
+ workspace -= rhs.m_value;
+
+ if (workspace.is_negative())
+ {
+ workspace += mp_mod->m_p;
+ }
+
+ m_value = workspace;
+ //assert(m_value < mp_mod->m_p);
+ //assert(m_value >= 0);
+ return *this;
+
+ }
+GFpElement& GFpElement::operator*= (u32bit rhs)
+ {
+ workspace = m_value;
+ workspace *= rhs;
+ workspace %= mp_mod->m_p;
+ m_value = workspace;
+ return *this;
+ }
+GFpElement& GFpElement::operator*= ( GFpElement const& rhs )
+ {
+ //assert(rhs.mp_mod->m_p == mp_mod->m_p);
+ // here, we do not use align_operands_res() for one simple reason:
+ // we want to enforce the transformation to an m-residue, otherwise it would
+ // never happen
+ if (m_use_montgm && rhs.m_use_montgm)
+ {
+ //assert(rhs.mp_mod->m_p == mp_mod->m_p); // is montgm. mult is on, then precomps must be there
+ //assert(rhs.mp_mod->m_p_dash == mp_mod->m_p_dash);
+ //assert(rhs.mp_mod->m_r == mp_mod->m_r);
+ if (!m_is_trf)
+ {
+ trf_to_mres();
+ }
+ if (!rhs.m_is_trf)
+ {
+ rhs.trf_to_mres();
+ }
+ workspace = m_value;
+ montg_mult(m_value, workspace, rhs.m_value, mp_mod->m_p, mp_mod->m_p_dash, mp_mod->m_r);
+ }
+ else // ordinary multiplication
+ {
+ if (m_is_trf)
+ {
+ //assert(m_use_montgm);
+ trf_to_ordres();
+ }
+ if (rhs.m_is_trf)
+ {
+ //assert(rhs.m_use_montgm);
+ rhs.trf_to_ordres();
+ }
+ workspace = m_value;
+ workspace *= rhs.m_value;
+ workspace %= mp_mod->m_p;
+ m_value = workspace;
+ }
+ return *this;
+ }
+GFpElement& GFpElement::operator/= ( GFpElement const& rhs )
+ {
+ bool use_mres = GFpElement::align_operands_res(*this, rhs);
+ //assert((this->m_is_trf && rhs.m_is_trf) || !(this->m_is_trf && rhs.m_is_trf) );
+ // (internal note: see C86)
+ if (use_mres)
+ {
+ //assert(m_use_montgm && rhs.m_use_montgm);
+ GFpElement rhs_ordres(rhs);
+ rhs_ordres.trf_to_ordres();
+ rhs_ordres.inverse_in_place();
+ workspace = m_value;
+ workspace *= rhs_ordres.get_value();
+ workspace %= mp_mod->m_p;
+ m_value = workspace;
+
+ }
+ else
+ {
+ GFpElement inv_rhs(rhs);
+ inv_rhs.inverse_in_place();
+ *this *= inv_rhs;
+ }
+ return *this;
+ }
+bool GFpElement::is_zero()
+ {
+ return (m_value.is_zero());
+ // this is correct because x_bar = x * r = x = 0 for x = 0
+ }
+GFpElement& GFpElement::inverse_in_place()
+ {
+ m_value = inverse_mod(m_value, mp_mod->m_p);
+ if (m_is_trf)
+ {
+ //assert(m_use_montgm);
+
+ m_value *= mp_mod->m_r;
+ m_value *= mp_mod->m_r;
+ m_value %= mp_mod->m_p;
+ }
+ //assert(m_value <= mp_mod->m_p);
+ return *this;
+
+ }
+GFpElement& GFpElement::negate()
+ {
+ m_value = mp_mod->m_p - m_value;
+ //assert(m_value <= mp_mod->m_p);
+ return *this;
+ }
+void GFpElement::swap ( GFpElement& other )
+ {
+ m_value.swap ( other.m_value );
+ mp_mod.swap(other.mp_mod);
+ std::swap<bool>(m_use_montgm,other.m_use_montgm);
+ std::swap<bool>(m_is_trf,other.m_is_trf);
+ }
+
+bool operator== ( GFpElement const& lhs, GFpElement const& rhs )
+ {
+ // for effeciency reasons we firstly check whether
+ //the modulus pointers are different in the first place:
+ if (lhs.get_ptr_mod() != rhs.get_ptr_mod())
+ {
+ if (lhs.get_p() != rhs.get_p())
+ {
+ return false;
+ }
+ }
+ // so the modulus is equal, now check the values
+ bool use_mres = GFpElement::align_operands_res(lhs, rhs);
+
+ if (use_mres)
+ {
+ return (lhs.get_mres() == rhs.get_mres());
+ }
+ else
+ {
+ return(lhs.get_value() == rhs.get_value());
+ }
+ }
+
+GFpElement operator+ ( GFpElement const& lhs, GFpElement const& rhs )
+ {
+ // consider the case that lhs and rhs both use montgm:
+ // then += returns an element which uses montgm.
+ // thus the return value of op+ here will be an element
+ // using montgm in this case
+ // NOTE: the rhs might be transformed when using op+, the lhs never
+ GFpElement result ( lhs );
+ result += rhs;
+ return result;
+ }
+GFpElement operator- ( GFpElement const& lhs, GFpElement const& rhs )
+ {
+ GFpElement result ( lhs );
+ result -= rhs;
+ return result;
+ // NOTE: the rhs might be transformed when using op-, the lhs never
+ }
+GFpElement operator- ( GFpElement const& lhs )
+ {
+ return ( GFpElement ( lhs ) ).negate();
+ }
+GFpElement operator* ( GFpElement const& lhs, GFpElement const& rhs )
+ {
+ // consider the case that lhs and rhs both use montgm:
+ // then *= returns an element which uses montgm.
+ // thus the return value of op* here will be an element
+ // using montgm in this case
+ GFpElement result ( lhs );
+ result *= rhs;
+ return result;
+ }
+GFpElement operator*(GFpElement const& lhs, u32bit rhs)
+ {
+ GFpElement result(lhs);
+ result *= rhs;
+ return result;
+
+ }
+GFpElement operator*(u32bit lhs, GFpElement const& rhs )
+ {
+ return rhs*lhs;
+ }
+GFpElement operator/ ( GFpElement const& lhs, GFpElement const& rhs )
+ {
+ GFpElement result (lhs);
+ result /= rhs;
+ return result;
+ }
+SecureVector<byte> FE2OSP ( GFpElement const& elem )
+ {
+ return BigInt::encode_1363 ( elem.get_value(), elem.get_p().bytes() );
+ }
+GFpElement OS2FEP ( MemoryRegion<byte> const& os, BigInt p )
+ {
+
+ return GFpElement ( p, BigInt::decode ( os.begin(), os.size() ) );
+ }
+GFpElement inverse ( GFpElement const& elem )
+ {
+ return GFpElement ( elem ).inverse_in_place();
+ }
+
+} // namespace Botan
diff --git a/src/pk_core.cpp b/src/pk_core.cpp
index 82fe4c217..63a1141a0 100644
--- a/src/pk_core.cpp
+++ b/src/pk_core.cpp
@@ -297,4 +297,82 @@ BigInt DH_Core::agree(const BigInt& i) const
return blinder.unblind(op->agree(blinder.blind(i)));
}
+/*************************************************
+* ECKAEG_Core Constructor *
+*************************************************/
+ECKAEG_Core::ECKAEG_Core(const EC_Domain_Params& dom_pars,
+ const BigInt& priv_key,
+ const PointGFp& pub_key)
+ {
+ op = Engine_Core::eckaeg_op(dom_pars, priv_key, pub_key);
+ }
+
+/*************************************************
+* ECKAEG_Core Copy Constructor *
+*************************************************/
+ECKAEG_Core::ECKAEG_Core(const ECKAEG_Core& core)
+ {
+ op = 0;
+ if(core.op)
+ op = core.op->clone();
+ blinder = core.blinder;
+ }
+
+/*************************************************
+* ECKAEG_Core Assignment Operator *
+*************************************************/
+ECKAEG_Core& ECKAEG_Core::operator=(const ECKAEG_Core& core)
+ {
+ delete op;
+ if(core.op)
+ op = core.op->clone();
+ blinder = core.blinder;
+ return (*this);
+ }
+
+/*************************************************
+* ECKAEG Operation *
+*************************************************/
+SecureVector<byte> ECKAEG_Core::agree(const PointGFp& otherKey) const
+ {
+ //assert(op.get());
+ return op->agree(otherKey);
+ }
+
+/*************************************************
+* ECDSA Operation *
+*************************************************/
+bool ECDSA_Core::verify(const byte signature[], u32bit sig_len,
+ const byte message[], u32bit mess_len) const
+ {
+ //assert(op.get());
+ return op->verify(signature, sig_len, message, mess_len);
+ }
+
+SecureVector<byte> ECDSA_Core::sign(const byte message[], u32bit mess_len) const
+ {
+ //assert(op.get());
+ return op->sign(message, mess_len);
+ }
+
+ECDSA_Core& ECDSA_Core::operator=(const ECDSA_Core& core)
+ {
+ delete op;
+ if(core.op)
+ op = core.op->clone();
+ return (*this);
+ }
+
+ECDSA_Core::ECDSA_Core(const ECDSA_Core& core)
+ {
+ op = 0;
+ if(core.op)
+ op = core.op->clone();
+ }
+
+ECDSA_Core::ECDSA_Core(EC_Domain_Params const& dom_pars, const BigInt& priv_key, PointGFp const& pub_key)
+ {
+ op = Engine_Core::ecdsa_op(dom_pars, priv_key, pub_key);
+ }
+
}
diff --git a/src/point_gfp.cpp b/src/point_gfp.cpp
new file mode 100644
index 000000000..23b6d4518
--- /dev/null
+++ b/src/point_gfp.cpp
@@ -0,0 +1,1157 @@
+/******************************************************
+ * Arithmetic for point groups of elliptic curves *
+ * over GF(p) (source file) *
+ * *
+ * (C) 2007 Martin Döring *
+ * Christoph Ludwig *
+ * Falko Strenzke *
+ ******************************************************/
+
+#include <botan/point_gfp.h>
+#include <botan/numthry.h>
+
+namespace Botan {
+
+// construct the point at infinity or a random point
+PointGFp::PointGFp(CurveGFp const& curve)
+ : mC(curve),
+ mX(curve.get_p(), 0),
+ mY(curve.get_p(), 1),
+ mZ(curve.get_p(), 0),
+ mZpow2(curve.get_p(),0),
+ mZpow3(curve.get_p(),0),
+ mAZpow4(curve.get_p(),0),
+ mZpow2_set(false),
+ mZpow3_set(false),
+ mAZpow4_set(false)
+ {
+ // first set the point wide pointer
+
+ set_shrd_mod(mC.get_ptr_mod());
+
+ }
+
+
+// construct a point given its jacobian projective coordinates
+PointGFp::PointGFp(CurveGFp const& curve, GFpElement const& x,
+ GFpElement const& y, GFpElement const& z)
+ : mC(curve),
+ mX(x),
+ mY(y),
+ mZ(z),
+ mZpow2(curve.get_p(),0),
+ mZpow3(curve.get_p(),0),
+ mAZpow4(curve.get_p(),0),
+ mZpow2_set(false),
+ mZpow3_set(false),
+ mAZpow4_set(false)
+ {
+ set_shrd_mod(mC.get_ptr_mod());
+ }
+PointGFp::PointGFp ( CurveGFp const& curve, GFpElement const& x,
+ GFpElement const& y )
+ :mC(curve),
+ mX(x),
+ mY(y),
+ mZ(curve.get_p(),1),
+ mZpow2(curve.get_p(),0),
+ mZpow3(curve.get_p(),0),
+ mAZpow4(curve.get_p(),0),
+ mZpow2_set(false),
+ mZpow3_set(false),
+ mAZpow4_set(false)
+ {
+ set_shrd_mod(mC.get_ptr_mod());
+ }
+
+// copy constructor
+PointGFp::PointGFp(PointGFp const& other)
+ : mC(other.mC),
+ mX(other.mX),
+ mY(other.mY),
+ mZ(other.mZ),
+ mZpow2(other.mZpow2),
+ mZpow3(other.mZpow3),
+ mAZpow4(other.mAZpow4),
+ mZpow2_set(other.mZpow2_set),
+ mZpow3_set(other.mZpow3_set),
+ mAZpow4_set(other.mAZpow4_set)
+ {
+ set_shrd_mod(mC.get_ptr_mod());
+ }
+
+// assignment operator
+PointGFp const& PointGFp::operator=(PointGFp const& other)
+ {
+ mC = other.get_curve();
+ mX = other.get_jac_proj_x();
+ mY = other.get_jac_proj_y();
+ mZ = other.get_jac_proj_z();
+ mZpow2 = GFpElement(other.mZpow2);
+ mZpow3 = GFpElement(other.mZpow3);
+ mAZpow4 = GFpElement(other.mAZpow4);
+ mZpow2_set = other.mZpow2_set;
+ mZpow3_set = other.mZpow3_set;
+ mAZpow4_set = other.mAZpow4_set;
+ set_shrd_mod(mC.get_ptr_mod());
+ return *this;
+ }
+
+PointGFp const& PointGFp::assign_within_same_curve(PointGFp const& other)
+ {
+ mX = other.get_jac_proj_x();
+ mY = other.get_jac_proj_y();
+ mZ = other.get_jac_proj_z();
+ mZpow2_set = false;
+ mZpow3_set = false;
+ mAZpow4_set = false;
+ // the rest stays!
+ return *this;
+ }
+
+void PointGFp::set_shrd_mod(std::tr1::shared_ptr<GFpModulus> p_mod)
+ {
+ mX.set_shrd_mod(p_mod);
+ mY.set_shrd_mod(p_mod);
+ mZ.set_shrd_mod(p_mod);
+ mZpow2.set_shrd_mod(p_mod);
+ mZpow3.set_shrd_mod(p_mod);
+ mAZpow4.set_shrd_mod(p_mod);
+ }
+
+void PointGFp::ensure_worksp() const
+ {
+ if (mp_worksp_gfp_el.get() != 0)
+ {
+ if ((*mp_worksp_gfp_el).size() == GFPEL_WKSP_SIZE)
+ {
+ return;
+ }
+ else
+ {
+ throw Invalid_State("encountered incorrect size for PointGFp´s GFpElement workspace");
+ }
+ }
+
+ mp_worksp_gfp_el = std::tr1::shared_ptr<std::vector<GFpElement> >(new std::vector<GFpElement>);
+ mp_worksp_gfp_el->reserve(9);
+ for (u32bit i=0; i<GFPEL_WKSP_SIZE; i++)
+ {
+ mp_worksp_gfp_el->push_back(GFpElement(1,0));
+
+ }
+ }
+
+// arithmetic operators
+PointGFp& PointGFp::operator+=(PointGFp const& rhs)
+ {
+ if (is_zero())
+ {
+ *this = rhs;
+ return *this;
+ }
+ if (rhs.is_zero())
+ {
+ return *this;
+ }
+ ensure_worksp();
+
+ if (rhs.mZ == *(mC.get_mres_one()))
+ {
+ //U1 = mX;
+ (*mp_worksp_gfp_el)[0].share_assign(mX);
+
+ //S1 = mY;
+ (*mp_worksp_gfp_el)[2].share_assign(mY);
+ }
+ else
+ {
+ if ((!rhs.mZpow2_set) || (!rhs.mZpow3_set))
+ {
+ rhs.mZpow2 = rhs.mZ;
+ rhs.mZpow2 *= rhs.mZ;
+ rhs.mZpow3 = rhs.mZpow2;
+ rhs.mZpow3 *= rhs.mZ;
+
+ rhs.mZpow2_set = true;
+ rhs.mZpow3_set = true;
+ }
+ //U1 = mX * rhs.mZpow2;
+ (*mp_worksp_gfp_el)[0].share_assign(mX);
+ (*mp_worksp_gfp_el)[0] *= rhs.mZpow2;
+
+ //S1 = mY * rhs.mZpow3;
+ (*mp_worksp_gfp_el)[2].share_assign(mY);
+ (*mp_worksp_gfp_el)[2] *= rhs.mZpow3;
+
+ }
+ if (mZ == *(mC.get_mres_one()))
+ {
+ //U2 = rhs.mX;
+ (*mp_worksp_gfp_el)[1].share_assign(rhs.mX);
+
+ //S2 = rhs.mY;
+ (*mp_worksp_gfp_el)[3].share_assign(rhs.mY);
+ }
+ else
+ {
+ if ((!mZpow2_set) || (!mZpow3_set))
+ {
+ // precomputation can´t be used, because *this changes anyway
+ mZpow2 = mZ;
+ mZpow2 *= mZ;
+
+ mZpow3 = mZpow2;
+ mZpow3 *= mZ;
+ }
+ //U2 = rhs.mX * mZpow2;
+ (*mp_worksp_gfp_el)[1].share_assign(rhs.mX);
+ (*mp_worksp_gfp_el)[1] *= mZpow2;
+
+ //S2 = rhs.mY * mZpow3;
+ (*mp_worksp_gfp_el)[3].share_assign(rhs.mY);
+ (*mp_worksp_gfp_el)[3] *= mZpow3;
+
+ }
+ //GFpElement H(U2 - U1);
+
+ (*mp_worksp_gfp_el)[4].share_assign((*mp_worksp_gfp_el)[1]);
+ (*mp_worksp_gfp_el)[4] -= (*mp_worksp_gfp_el)[0];
+
+ //GFpElement r(S2 - S1);
+ (*mp_worksp_gfp_el)[5].share_assign((*mp_worksp_gfp_el)[3]);
+ (*mp_worksp_gfp_el)[5] -= (*mp_worksp_gfp_el)[2];
+
+ //if(H.is_zero())
+ if ((*mp_worksp_gfp_el)[4].is_zero())
+
+ {
+ if ((*mp_worksp_gfp_el)[5].is_zero())
+
+ {
+ mult2_in_place();
+ return *this;
+ }
+ *this = PointGFp(mC); // setting myself to zero
+ return *this;
+ }
+
+ //U2 = H * H;
+ (*mp_worksp_gfp_el)[1].share_assign((*mp_worksp_gfp_el)[4]);
+ (*mp_worksp_gfp_el)[1] *= (*mp_worksp_gfp_el)[4];
+
+ //S2 = U2 * H;
+ (*mp_worksp_gfp_el)[3].share_assign((*mp_worksp_gfp_el)[1]);
+ (*mp_worksp_gfp_el)[3] *= (*mp_worksp_gfp_el)[4];
+
+ //U2 *= U1;
+ (*mp_worksp_gfp_el)[1] *= (*mp_worksp_gfp_el)[0];
+
+ //GFpElement x(r*r - S2 - (U2+U2));
+ (*mp_worksp_gfp_el)[6].share_assign((*mp_worksp_gfp_el)[5]);
+ (*mp_worksp_gfp_el)[6] *= (*mp_worksp_gfp_el)[5];
+ (*mp_worksp_gfp_el)[6] -= (*mp_worksp_gfp_el)[3];
+ (*mp_worksp_gfp_el)[6] -= (*mp_worksp_gfp_el)[1];
+ (*mp_worksp_gfp_el)[6] -= (*mp_worksp_gfp_el)[1];
+
+ //GFpElement z(S1 * S2);
+ (*mp_worksp_gfp_el)[8].share_assign((*mp_worksp_gfp_el)[2]);
+ (*mp_worksp_gfp_el)[8] *= (*mp_worksp_gfp_el)[3];
+
+ //GFpElement y(r * (U2-x) - z);
+ (*mp_worksp_gfp_el)[7].share_assign((*mp_worksp_gfp_el)[1]);
+ (*mp_worksp_gfp_el)[7] -= (*mp_worksp_gfp_el)[6];
+ (*mp_worksp_gfp_el)[7] *= (*mp_worksp_gfp_el)[5];
+ (*mp_worksp_gfp_el)[7] -= (*mp_worksp_gfp_el)[8];
+
+ if (mZ == *(mC.get_mres_one()))
+ {
+ if (rhs.mZ != *(mC.get_mres_one()))
+ {
+ //z = rhs.mZ * H;
+ (*mp_worksp_gfp_el)[8].share_assign(rhs.mZ);
+ (*mp_worksp_gfp_el)[8] *= (*mp_worksp_gfp_el)[4];
+ }
+ else
+ {
+ //z = H;
+ (*mp_worksp_gfp_el)[8].share_assign((*mp_worksp_gfp_el)[4]);
+ }
+ }
+ else if (rhs.mZ != *(mC.get_mres_one()))
+ {
+ //U1 = mZ * rhs.mZ;
+ (*mp_worksp_gfp_el)[0].share_assign(mZ);
+ (*mp_worksp_gfp_el)[0] *= rhs.mZ;
+
+ //z = U1 * H;
+ (*mp_worksp_gfp_el)[8].share_assign((*mp_worksp_gfp_el)[0]);
+ (*mp_worksp_gfp_el)[8] *= (*mp_worksp_gfp_el)[4];
+
+ }
+ else
+ {
+ //z = mZ * H;
+ (*mp_worksp_gfp_el)[8].share_assign(mZ);
+ (*mp_worksp_gfp_el)[8] *= (*mp_worksp_gfp_el)[4];
+
+ }
+ mZpow2_set = false;
+ mZpow3_set = false;
+ mAZpow4_set = false;
+
+ mX = (*mp_worksp_gfp_el)[6];
+ mY = (*mp_worksp_gfp_el)[7];
+ mZ = (*mp_worksp_gfp_el)[8];
+
+ return *this;
+
+ }
+PointGFp& PointGFp::operator-=(PointGFp const& rhs)
+ {
+ PointGFp minus_rhs = PointGFp(rhs).negate();
+
+ if (is_zero())
+ {
+ *this = minus_rhs;
+ }
+ else
+ {
+ *this += minus_rhs;
+ }
+ return *this;
+ }
+
+PointGFp& PointGFp::mult_this_secure(const BigInt& scalar,
+ const BigInt& /*point_order*/,
+ const BigInt& /*max_secr*/)
+ {
+ // NOTE: FS: so far this is code duplication of op*=.
+ // we have to see how we deal with this.
+ // fact is that we will probably modify this function
+ // while evaluating the countermeasures
+ // whereas we probably will not start modifying the
+ // function operator*=.
+ // however, in the end both should be merged.
+
+ // use montgomery mult. in this operation
+ this->turn_on_sp_red_mul();
+
+ std::tr1::shared_ptr<PointGFp> H(new PointGFp(this->mC));
+ std::tr1::shared_ptr<PointGFp> tmp; // used for AADA
+
+ PointGFp P(*this);
+ BigInt m(scalar);
+
+ if (m < BigInt(0))
+ {
+ m = -m;
+ P.negate();
+ }
+ if (P.is_zero() || (m == BigInt(0)))
+ {
+ *this = *H;
+ return *this;
+ }
+ if (m == BigInt(1))
+ {
+ return *this;
+ }
+ //
+#ifdef CM_AADA
+#ifndef CM_RAND_EXP
+ int max_secr_bits = max_secr.bits();
+#endif
+#endif
+
+ int mul_bits = m.bits(); // this is used for a determined number of loop runs in
+ // the mult_loop where leading zero´s are padded if necessary.
+ // Here we assign the value that will be used when no countermeasures are specified
+#ifdef CM_RAND_EXP
+ u32bit rand_r_bit_len = 20; // Coron(99) proposes 20 bit for r
+
+#ifdef CM_AADA
+
+ BigInt r_max(1);
+
+#endif // CM_AADA
+
+ // use randomized exponent
+#ifdef TA_COLL_T
+ static BigInt r_randexp;
+ if (new_rand)
+ {
+ r_randexp = random_integer(rand_r_bit_len);
+ }
+ //assert(!r_randexp.is_zero());
+#else
+ BigInt r_randexp(random_integer(rand_r_bit_len));
+#endif
+
+ m += r_randexp * point_order;
+ // determine mul_bits...
+#ifdef CM_AADA
+ // AADA with rand. Exp.
+ //assert(rand_r_bit_len > 0);
+ r_max <<= rand_r_bit_len;
+ r_max -= 1;
+ //assert(r_max.bits() == rand_r_bit_len);
+ mul_bits = (max_secr + point_order * r_max).bits();
+#else
+ // rand. Exp. without AADA
+ mul_bits = m.bits();
+#endif // CM_AADA
+
+
+#endif // CM_RAND_EXP
+
+ // determine mul_bits...
+#if (CM_AADA == 1 && CM_RAND_EXP != 1)
+
+ mul_bits = max_secr_bits;
+#endif // CM_AADA without CM_RAND_EXP
+
+ //assert(mul_bits != 0);
+
+
+ H = mult_loop(mul_bits-1, m, H, tmp, P);
+
+ if (!H->is_zero()) // cannot convert if H == O
+ {
+ *this = H->get_z_to_one();
+ }else
+ {
+ *this = *H;
+ }
+ mX.turn_off_sp_red_mul();
+ mY.turn_off_sp_red_mul();
+ mZ.turn_off_sp_red_mul();
+ return *this;
+ }
+PointGFp& PointGFp::operator*=(const BigInt& scalar)
+ {
+ // use montgomery mult. in this operation
+
+ this->turn_on_sp_red_mul();
+
+ PointGFp H(this->mC); // create as zero
+ H.turn_on_sp_red_mul();
+ PointGFp P(*this);
+ P.turn_on_sp_red_mul();
+ BigInt m(scalar);
+ if (m < BigInt(0))
+ {
+ m = -m;
+ P.negate();
+ }
+ if (P.is_zero() || (m == BigInt(0)))
+ {
+ *this = H;
+ return *this;
+ }
+ if (m == BigInt(1))
+ {
+ //*this == P already
+ return *this;
+ }
+
+ const int l = m.bits() - 1;
+ for (int i=l; i >=0; i--)
+ {
+
+ H.mult2_in_place();
+ if (m.get_bit(i))
+ {
+ H += P;
+ }
+ }
+
+ if (!H.is_zero()) // cannot convert if H == O
+ {
+ *this = H.get_z_to_one();
+ }else
+ {
+ *this = H;
+ }
+ return *this;
+ }
+
+inline std::tr1::shared_ptr<PointGFp> PointGFp::mult_loop(
+ int l,
+ const BigInt& m,
+ std::tr1::shared_ptr<PointGFp> H,
+ std::tr1::shared_ptr<PointGFp> tmp,
+ PointGFp const& P)
+ {
+
+ //assert(l >= (int)m.bits()- 1);
+ tmp = H;
+ std::tr1::shared_ptr<PointGFp> to_add(new PointGFp(P)); // we just need some point
+ // so that we can use op=
+ // inside the loop
+ for (int i=l; i >=0; i--)
+ {
+ H->mult2_in_place();
+
+#ifndef CM_AADA
+
+ if (m.get_bit(i))
+ {
+ *H += P;
+ }
+#else // (CM_AADA is in)
+
+ if (H.get() == to_add.get())
+ {
+ to_add = tmp; // otherwise all pointers might point to the same object
+ // and we always need two objects to be able to switch around
+ }
+ to_add->assign_within_same_curve(*H);
+ tmp = H;
+ *tmp += P; // tmp already points to H
+
+ if (m.get_bit(i))
+ {
+ H = tmp; // NOTE: assign the pointer, not the value!
+ // (so that the operation is fast and thus as difficult
+ // to detect as possible)
+ }
+ else
+ {
+ H = to_add; // NOTE: this is necessary, because the assignment
+ // "*tmp = ..." already changed what H pointed to
+
+
+ }
+#endif // CM_AADA
+
+ }
+ return H;
+ }
+PointGFp& PointGFp::negate()
+ {
+ if (!is_zero())
+ {
+ mY.negate();
+ }
+ return *this;
+ }
+// *this *= 2
+PointGFp& PointGFp::mult2_in_place()
+ {
+ if (is_zero())
+ {
+ return *this;
+ }
+ if (mY.is_zero())
+ {
+
+ *this = PointGFp(mC); // setting myself to zero
+ return *this;
+ }
+ ensure_worksp();
+
+ (*mp_worksp_gfp_el)[0].share_assign(mY);
+ (*mp_worksp_gfp_el)[0] *= mY;
+
+ //GFpElement S(mX * z);
+ (*mp_worksp_gfp_el)[1].share_assign(mX);
+ (*mp_worksp_gfp_el)[1] *= (*mp_worksp_gfp_el)[0];
+
+ //GFpElement x(S + S);
+ (*mp_worksp_gfp_el)[2].share_assign((*mp_worksp_gfp_el)[1]);
+ (*mp_worksp_gfp_el)[2] += (*mp_worksp_gfp_el)[1];
+
+ //S = x + x;
+ (*mp_worksp_gfp_el)[1].share_assign((*mp_worksp_gfp_el)[2]);
+ (*mp_worksp_gfp_el)[1] += (*mp_worksp_gfp_el)[2];
+
+ if (!mAZpow4_set)
+ {
+ if (mZ == *(mC.get_mres_one()))
+ {
+ mAZpow4 = mC.get_mres_a();
+ mAZpow4_set = true;
+ }
+ else
+ {
+ if (!mZpow2_set)
+ {
+ mZpow2 = mZ;
+ mZpow2 *= mZ;
+
+ mZpow2_set = true;
+ }
+ //x = mZpow2 * mZpow2;
+ (*mp_worksp_gfp_el)[2].share_assign(mZpow2);
+ (*mp_worksp_gfp_el)[2] *= mZpow2;
+
+ //mAZpow4 = mC.get_mres_a() * x;
+ mAZpow4 = mC.get_mres_a();
+ mAZpow4 *= (*mp_worksp_gfp_el)[2];
+
+ }
+
+ }
+
+ //GFpElement y(mX * mX);
+ (*mp_worksp_gfp_el)[3].share_assign(mX);
+ (*mp_worksp_gfp_el)[3] *= mX;
+
+ //GFpElement M(y + y + y + mAZpow4);
+ (*mp_worksp_gfp_el)[4].share_assign((*mp_worksp_gfp_el)[3]);
+ (*mp_worksp_gfp_el)[4] += (*mp_worksp_gfp_el)[3];
+ (*mp_worksp_gfp_el)[4] += (*mp_worksp_gfp_el)[3];
+ (*mp_worksp_gfp_el)[4] += mAZpow4;
+
+ //x = M * M - (S+S);
+ (*mp_worksp_gfp_el)[2].share_assign((*mp_worksp_gfp_el)[4]);
+ (*mp_worksp_gfp_el)[2] *= (*mp_worksp_gfp_el)[4];
+ (*mp_worksp_gfp_el)[2] -= (*mp_worksp_gfp_el)[1];
+ (*mp_worksp_gfp_el)[2] -= (*mp_worksp_gfp_el)[1];
+
+ //y = z * z;
+ (*mp_worksp_gfp_el)[3].share_assign((*mp_worksp_gfp_el)[0]);
+ (*mp_worksp_gfp_el)[3] *= (*mp_worksp_gfp_el)[0];
+
+ //GFpElement U(y + y);
+ (*mp_worksp_gfp_el)[5].share_assign((*mp_worksp_gfp_el)[3]);
+ (*mp_worksp_gfp_el)[5] += (*mp_worksp_gfp_el)[3];
+
+ //z = U + U;
+ (*mp_worksp_gfp_el)[0].share_assign((*mp_worksp_gfp_el)[5]);
+ (*mp_worksp_gfp_el)[0] += (*mp_worksp_gfp_el)[5];
+
+ //U = z + z;
+ (*mp_worksp_gfp_el)[5].share_assign((*mp_worksp_gfp_el)[0]);
+ (*mp_worksp_gfp_el)[5] += (*mp_worksp_gfp_el)[0];
+
+ //y = M * (S - x) - U;
+ (*mp_worksp_gfp_el)[3].share_assign((*mp_worksp_gfp_el)[1]);
+ (*mp_worksp_gfp_el)[3] -= (*mp_worksp_gfp_el)[2];
+ (*mp_worksp_gfp_el)[3] *= (*mp_worksp_gfp_el)[4];
+ (*mp_worksp_gfp_el)[3] -= (*mp_worksp_gfp_el)[5];
+
+ if (mZ != *(mC.get_mres_one()))
+ {
+ //z = mY * mZ;
+ (*mp_worksp_gfp_el)[0].share_assign(mY);
+ (*mp_worksp_gfp_el)[0] *= mZ;
+
+ }
+ else
+ {
+ //z = mY;
+ (*mp_worksp_gfp_el)[0].share_assign(mY);
+
+ }
+ //z = z + z;
+ (*mp_worksp_gfp_el)[6].share_assign((*mp_worksp_gfp_el)[0]);
+ (*mp_worksp_gfp_el)[0] += (*mp_worksp_gfp_el)[6];
+
+ //mX = x;
+ //mY = y;
+ //mZ = z;
+ mX = (*mp_worksp_gfp_el)[2];
+ mY = (*mp_worksp_gfp_el)[3];
+ mZ = (*mp_worksp_gfp_el)[0];
+
+ mZpow2_set = false;
+ mZpow3_set = false;
+ mAZpow4_set = false;
+ return *this;
+
+ }
+void PointGFp::turn_on_sp_red_mul() const
+ {
+ mX.turn_on_sp_red_mul();
+ mY.turn_on_sp_red_mul();
+ mZ.turn_on_sp_red_mul();
+
+ // also pretransform, otherwise
+ // we might have bad results with respect to
+ // performance because
+ // additions/subtractions in mult2_in_place()
+ // and op+= spread untransformed GFpElements
+ mX.get_mres();
+ mY.get_mres();
+ mZ.get_mres();
+
+ mZpow2.turn_on_sp_red_mul();
+ mZpow3.turn_on_sp_red_mul();
+ mAZpow4.turn_on_sp_red_mul();
+ }
+// getters
+
+/**
+* returns a point equivalent to *this but were
+* Z has value one, i.e. x and y correspond to
+* their values in affine coordinates
+*/
+PointGFp const PointGFp::get_z_to_one() const
+ {
+ return PointGFp(*this).set_z_to_one();
+ }
+/**
+* changes the representation of *this so that
+* Z has value one, i.e. x and y correspond to
+* their values in affine coordinates.
+* returns *this.
+*/
+PointGFp const& PointGFp::set_z_to_one() const
+ {
+ if (!(mZ.get_value() == BigInt(1)) && !(mZ.get_value() == BigInt(0)))
+ {
+ GFpElement z = inverse(mZ);
+ GFpElement z2 = z * z;
+ z *= z2;
+ GFpElement x = mX * z2;
+ GFpElement y = mY * z;
+ mZ = GFpElement(mC.get_p(), BigInt(1));
+ mX = x;
+ mY = y;
+ }
+ else
+ {
+ if (mZ.get_value() == BigInt(0))
+ {
+ throw Illegal_Transformation("cannot convert Z to one");
+ }
+ }
+ return *this; // mZ = 1 already
+ }
+CurveGFp const PointGFp::get_curve() const
+ {
+ return mC;
+ }
+GFpElement const PointGFp::get_affine_x() const
+ {
+
+ if (is_zero())
+ {
+ throw Illegal_Transformation("cannot convert to affine");
+
+ }
+ /*if(!mZpow2_set)
+ {*/
+ mZpow2 = mZ * mZ;
+ mZpow2_set = true;
+ //}
+ //assert(mZpow2 == mZ*mZ);
+ GFpElement z2 = mZpow2;
+ return mX * z2.inverse_in_place();
+ }
+
+GFpElement const PointGFp::get_affine_y() const
+ {
+
+ if (is_zero())
+ {
+ throw Illegal_Transformation("cannot convert to affine");
+
+ }
+ /*if(!mZpow3_set )
+ {*/
+ mZpow3 = mZ * mZ * mZ;
+ mZpow3_set = true;
+ //}
+ //assert(mZpow3 == mZ * mZ *mZ);
+ GFpElement z3 = mZpow3;
+ return mY * z3.inverse_in_place();
+ }
+GFpElement const PointGFp::get_jac_proj_x() const
+ {
+ return GFpElement(mX);
+ }
+GFpElement const PointGFp::get_jac_proj_y() const
+ {
+ return GFpElement(mY);
+ }
+GFpElement const PointGFp::get_jac_proj_z() const
+ {
+ return GFpElement(mZ);
+ }
+
+// Is this the point at infinity?
+bool PointGFp::is_zero() const
+ {
+ return(mX.is_zero() && mZ.is_zero());
+ //NOTE: the calls to GFpElement::is_zero() instead of getting the value and
+ // and comparing it are import because they do not provoke backtransformations
+ // to the ordinary residue.
+ }
+
+// Is the point still on the curve??
+// (If everything is correct, the point is always on its curve; then the
+// function will return silently. If Oskar managed to corrupt this object's state,
+// then it will throw an exception.)
+void PointGFp::check_invariants() const
+ {
+ if (is_zero())
+ {
+ return;
+ }
+ const GFpElement y2 = mY * mY;
+ const GFpElement x3 = mX * mX * mX;
+
+ if (mZ.get_value() == BigInt(1))
+ {
+ GFpElement ax = mC.get_a() * mX;
+ if (y2 != (x3 + ax + mC.get_b()))
+ {
+ throw Illegal_Point();
+ }
+
+ }
+ /*if (!mZpow2_set)
+ {*/
+ mZpow2 = mZ * mZ;
+ mZpow2_set = true;
+ /*}
+ if (!mZpow3_set)
+ {*/
+ mZpow3 = mZpow2 * mZ;
+ mZpow3_set = true;
+ /*}
+ if(!mAZpow4_set)
+ {*/
+ mAZpow4 = mZpow3 * mZ * mC.get_a();
+ mAZpow4_set = true;
+ //}
+ const GFpElement aXZ4 = mAZpow4 * mX;
+ const GFpElement bZ6 = mC.get_b() * mZpow3 * mZpow3;
+
+ if (y2 != (x3 + aXZ4 + bZ6))
+ {
+ throw Illegal_Point();
+ }
+
+ }
+// swaps the states of *this and other, does not throw!
+void PointGFp::swap(PointGFp& other)
+ {
+ mC.swap(other.mC);
+ mX.swap(other.mX);
+ mY.swap(other.mY);
+ mZ.swap(other.mZ);
+ mZpow2.swap(other.mZpow2);
+ mZpow3.swap(other.mZpow3);
+ mAZpow4.swap(other.mAZpow4);
+ std::swap<bool>(mZpow2_set, other.mZpow2_set);
+ std::swap<bool>(mZpow3_set, other.mZpow3_set);
+ std::swap<bool>(mAZpow4_set, other.mAZpow4_set);
+ }
+
+PointGFp const mult2(PointGFp const& point)
+ {
+ return (PointGFp(point)).mult2_in_place();
+ }
+
+
+bool operator==(PointGFp const& lhs, PointGFp const& rhs)
+ {
+ if (lhs.is_zero() && rhs.is_zero())
+ {
+ return true;
+ }
+ if ((lhs.is_zero() && !rhs.is_zero()) || (!lhs.is_zero() && rhs.is_zero()))
+ {
+ return false;
+ }
+ // neither operand is zero, so we can call get_z_to_one()
+ //assert(!lhs.is_zero());
+ //assert(!rhs.is_zero());
+ PointGFp aff_lhs = lhs.get_z_to_one();
+ PointGFp aff_rhs = rhs.get_z_to_one();
+ return (aff_lhs.get_curve() == aff_rhs.get_curve() &&
+ aff_lhs.get_jac_proj_x() == aff_rhs.get_jac_proj_x() &&
+ aff_lhs.get_jac_proj_y() == aff_rhs.get_jac_proj_y());
+ }
+
+// arithmetic operators
+PointGFp operator+(PointGFp const& lhs, PointGFp const& rhs)
+ {
+ PointGFp tmp(lhs);
+ return tmp += rhs;
+ }
+
+PointGFp operator-(PointGFp const& lhs, PointGFp const& rhs)
+ {
+ PointGFp tmp(lhs);
+ return tmp -= rhs;
+ }
+
+PointGFp operator-(PointGFp const& lhs)
+ {
+ return PointGFp(lhs).negate();
+ }
+
+PointGFp operator*(const BigInt& scalar, PointGFp const& point)
+ {
+ PointGFp result(point);
+ return result *= scalar;
+ }
+
+PointGFp operator*(PointGFp const& point, const BigInt& scalar)
+ {
+ PointGFp result(point);
+ return result *= scalar;
+ }
+
+PointGFp mult_point_secure(PointGFp const& point, const BigInt& scalar, const BigInt& point_order, const BigInt& max_secret)
+ {
+ PointGFp result(point);
+ result.mult_this_secure(scalar, point_order, max_secret);
+ return result;
+ }
+
+// encoding and decoding
+SecureVector<byte> EC2OSP(PointGFp const& point, byte format)
+ {
+ SecureVector<byte> result;
+ if (format == PointGFp::UNCOMPRESSED)
+ {
+ result = encode_uncompressed(point);
+ }
+ else if (format == PointGFp::COMPRESSED)
+ {
+ result = encode_compressed(point);
+
+ }
+ else if (format == PointGFp::HYBRID)
+ {
+ result = encode_hybrid(point);
+ }
+ else
+ {
+ throw Format_Error("illegal point encoding format specification");
+ }
+ return result;
+ }
+SecureVector<byte> encode_compressed(PointGFp const& point)
+ {
+
+
+ if (point.is_zero())
+ {
+ SecureVector<byte> result (1);
+ result[0] = 0;
+ return result;
+
+ }
+ u32bit l = point.get_curve().get_p().bits();
+ int dummy = l & 7;
+ if (dummy != 0)
+ {
+ l += 8 - dummy;
+ }
+ l /= 8;
+ SecureVector<byte> result (l+1);
+ result[0] = 2;
+ BigInt x = point.get_affine_x().get_value();
+ SecureVector<byte> bX = BigInt::encode_1363(x, l);
+ result.copy(1, bX.begin(), bX.size());
+ BigInt y = point.get_affine_y().get_value();
+ if (y.get_bit(0))
+ {
+ result[0] |= 1;
+ }
+ return result;
+ }
+
+
+SecureVector<byte> encode_uncompressed(PointGFp const& point)
+ {
+ if (point.is_zero())
+ {
+ SecureVector<byte> result (1);
+ result[0] = 0;
+ return result;
+ }
+ u32bit l = point.get_curve().get_p().bits();
+ int dummy = l & 7;
+ if (dummy != 0)
+ {
+ l += 8 - dummy;
+ }
+ l /= 8;
+ SecureVector<byte> result (2*l+1);
+ result[0] = 4;
+ BigInt x = point.get_affine_x().get_value();
+ BigInt y = point.get_affine_y().get_value();
+ SecureVector<byte> bX = BigInt::encode_1363(x, l);
+ SecureVector<byte> bY = BigInt::encode_1363(y, l);
+ result.copy(1, bX.begin(), l);
+ result.copy(l+1, bY.begin(), l);
+ return result;
+
+ }
+
+SecureVector<byte> encode_hybrid(PointGFp const& point)
+ {
+ if (point.is_zero())
+ {
+ SecureVector<byte> result (1);
+ result[0] = 0;
+ return result;
+ }
+ u32bit l = point.get_curve().get_p().bits();
+ int dummy = l & 7;
+ if (dummy != 0)
+ {
+ l += 8 - dummy;
+ }
+ l /= 8;
+ SecureVector<byte> result (2*l+1);
+ result[0] = 6;
+ BigInt x = point.get_affine_x().get_value();
+ BigInt y = point.get_affine_y().get_value();
+ SecureVector<byte> bX = BigInt::encode_1363(x, l);
+ SecureVector<byte> bY = BigInt::encode_1363(y, l);
+ result.copy(1, bX.begin(), bX.size());
+ result.copy(l+1, bY.begin(), bY.size());
+ if (y.get_bit(0))
+ {
+ result[0] |= 1;
+ }
+ return result;
+ }
+
+PointGFp OS2ECP(MemoryRegion<byte> const& os, CurveGFp const& curve)
+ {
+ if (os.size() == 1 && os[0] == 0)
+ {
+ return PointGFp(curve); // return zero
+ }
+ SecureVector<byte> bX;
+ SecureVector<byte> bY;
+
+ GFpElement x(1,0);
+ GFpElement y(1,0);
+ GFpElement z(1,0);
+
+ const byte pc = os[0];
+ BigInt bi_dec_x;
+ BigInt bi_dec_y;
+ switch (pc)
+ {
+ case 2:
+ case 3:
+ //compressed form
+ bX = SecureVector<byte>(os.size() - 1);
+ bX.copy(os.begin()+1, os.size()-1);
+
+ /* Problem wäre, wenn decode() das erste bit als Vorzeichen interpretiert.
+ *---------------------
+ * AW(FS): decode() interpretiert das erste Bit nicht als Vorzeichen
+ */
+ bi_dec_x = BigInt::decode(bX, bX.size());
+ x = GFpElement(curve.get_p(), bi_dec_x);
+ bool yMod2;
+ yMod2 = (pc & 1) == 1;
+ y = PointGFp::decompress(yMod2, x, curve);
+ break;
+ case 4:
+ // uncompressed form
+ int l;
+ l = (os.size() -1)/2;
+ bX = SecureVector<byte>(l);
+ bY = SecureVector<byte>(l);
+ bX.copy(os.begin()+1, l);
+ bY.copy(os.begin()+1+l, l);
+ bi_dec_x = BigInt::decode(bX.begin(), bX.size());
+
+ bi_dec_y = BigInt::decode(bY.begin(),bY.size());
+ x = GFpElement(curve.get_p(), bi_dec_x);
+ y = GFpElement(curve.get_p(), bi_dec_y);
+ break;
+
+ case 6:
+ case 7:
+ //hybrid form
+ l = (os.size() - 1)/2;
+ bX = SecureVector<byte>(l);
+ bY = SecureVector<byte>(l);
+ bX.copy(os.begin() + 1, l);
+ bY.copy(os.begin()+1+l, l);
+ yMod2 = (pc & 0x01) == 1;
+ if (!(PointGFp::decompress(yMod2, x, curve) == y))
+ {
+ throw Illegal_Point("error during decoding hybrid format");
+ }
+ break;
+ default:
+ throw Format_Error("encountered illegal format specification while decoding point");
+ }
+ z = GFpElement(curve.get_p(), BigInt(1));
+ //assert((x.is_trf_to_mres() && x.is_use_montgm()) || !x.is_trf_to_mres());
+ //assert((y.is_trf_to_mres() && y.is_use_montgm()) || !y.is_trf_to_mres());
+ //assert((z.is_trf_to_mres() && z.is_use_montgm()) || !z.is_trf_to_mres());
+ PointGFp result(curve, x, y, z);
+ result.check_invariants();
+ //assert((result.get_jac_proj_x().is_trf_to_mres() && result.get_jac_proj_x().is_use_montgm()) || !result.get_jac_proj_x().is_trf_to_mres());
+ //assert((result.get_jac_proj_y().is_trf_to_mres() && result.get_jac_proj_y().is_use_montgm()) || !result.get_jac_proj_y().is_trf_to_mres());
+ //assert((result.get_jac_proj_z().is_trf_to_mres() && result.get_jac_proj_z().is_use_montgm()) || !result.get_jac_proj_z().is_trf_to_mres());
+ return result;
+ }
+
+GFpElement PointGFp::decompress(bool yMod2, GFpElement const& x,
+ CurveGFp const& curve)
+ {
+ BigInt xVal = x.get_value();
+ BigInt xpow3 = xVal * xVal * xVal;
+ BigInt g = curve.get_a().get_value() * xVal;
+ g += xpow3;
+ g += curve.get_b().get_value();
+ g = g%curve.get_p();
+ BigInt z = ressol(g, curve.get_p());
+
+ if(z < 0)
+ throw Illegal_Point("error during decompression");
+
+ bool zMod2 = z.get_bit(0);
+ if ((zMod2 && ! yMod2) || (!zMod2 && yMod2))
+ {
+ z = curve.get_p() - z;
+ }
+ return GFpElement(curve.get_p(),z);
+ }
+
+PointGFp const create_random_point(RandomNumberGenerator& rng,
+ CurveGFp const& curve)
+ {
+
+ // create a random point
+ GFpElement mX(1,1);
+ GFpElement mY(1,1);
+ GFpElement mZ(1,1);
+ GFpElement minusOne(curve.get_p(), BigInt(BigInt::Negative,1));
+ mY = minusOne;
+ GFpElement y2(1,1);
+ GFpElement x(1,1);
+
+ while (mY == minusOne)
+ {
+ BigInt value(rng, curve.get_p().bits());
+ mX = GFpElement(curve.get_p(),value);
+ y2 = curve.get_a() * mX;
+ x = mX * mX;
+ x *= mX;
+ y2 += (x + curve.get_b());
+
+ value = ressol(y2.get_value(), curve.get_p());
+
+ if(value < 0)
+ mY = minusOne;
+ else
+ mY = GFpElement(curve.get_p(), value);
+ }
+ mZ = GFpElement(curve.get_p(), BigInt(1));
+
+ return PointGFp(curve, mX, mY, mZ);
+ }
+
+} // namespace Botan