diff options
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/engine/core_engine/def_pk_ops.cpp | 9 | ||||
-rw-r--r-- | src/lib/pubkey/curve25519/curve25519.cpp | 115 | ||||
-rw-r--r-- | src/lib/pubkey/curve25519/curve25519.h | 94 | ||||
-rw-r--r-- | src/lib/pubkey/curve25519/donna.cpp | 456 | ||||
-rw-r--r-- | src/lib/pubkey/curve25519/donna128.h | 116 | ||||
-rw-r--r-- | src/lib/pubkey/curve25519/info.txt | 9 | ||||
-rw-r--r-- | src/lib/pubkey/pk_algs.cpp | 14 |
7 files changed, 813 insertions, 0 deletions
diff --git a/src/lib/engine/core_engine/def_pk_ops.cpp b/src/lib/engine/core_engine/def_pk_ops.cpp index b21877b16..cbe7d27fc 100644 --- a/src/lib/engine/core_engine/def_pk_ops.cpp +++ b/src/lib/engine/core_engine/def_pk_ops.cpp @@ -43,6 +43,10 @@ #include <botan/ecdh.h> #endif +#if defined(BOTAN_HAS_CURVE_25519) + #include <botan/curve25519.h> +#endif + namespace Botan { PK_Ops::Encryption* @@ -90,6 +94,11 @@ Core_Engine::get_key_agreement_op(const Private_Key& key, RandomNumberGenerator& return new ECDH_KA_Operation(*ecdh); #endif +#if defined(BOTAN_HAS_CURVE_25519) + if(const Curve25519_PrivateKey* c25519 = dynamic_cast<const Curve25519_PrivateKey*>(&key)) + return new Curve25519_KA_Operation(*c25519); +#endif + return nullptr; } diff --git a/src/lib/pubkey/curve25519/curve25519.cpp b/src/lib/pubkey/curve25519/curve25519.cpp new file mode 100644 index 000000000..fe30e37d9 --- /dev/null +++ b/src/lib/pubkey/curve25519/curve25519.cpp @@ -0,0 +1,115 @@ +/* +* Curve25519 +* (C) 2014 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/curve25519.h> +#include <botan/ber_dec.h> +#include <botan/der_enc.h> + +namespace Botan { + +namespace { + +void size_check(size_t size, const char* thing) + { + if(size != 32) + throw Decoding_Error("Invalid size " + std::to_string(size) + " for Curve25519 " + thing); + } + +secure_vector<byte> curve25519(const secure_vector<byte>& secret, + const byte pubval[32]) + { + secure_vector<byte> out(32); + const int rc = curve25519_donna(&out[0], &secret[0], &pubval[0]); + BOTAN_ASSERT_EQUAL(rc, 0, "Return value of curve25519_donna is ok"); + return out; + } + +secure_vector<byte> curve25519_basepoint(const secure_vector<byte>& secret) + { + const byte basepoint[32] = { 9 }; + return curve25519(secret, basepoint); + } + +} + +AlgorithmIdentifier Curve25519_PublicKey::algorithm_identifier() const + { + return AlgorithmIdentifier(get_oid(), AlgorithmIdentifier::USE_NULL_PARAM); + } + +bool Curve25519_PublicKey::check_key(RandomNumberGenerator&, bool) const + { + return true; // no tests possible? + } + +Curve25519_PublicKey::Curve25519_PublicKey(const AlgorithmIdentifier&, + const secure_vector<byte>& key_bits) + { + BER_Decoder(key_bits) + .start_cons(SEQUENCE) + .decode(m_public, OCTET_STRING) + .verify_end() + .end_cons(); + + size_check(m_public.size(), "public key"); + } + +std::vector<byte> Curve25519_PublicKey::x509_subject_public_key() const + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(m_public, OCTET_STRING) + .end_cons() + .get_contents_unlocked(); + } + +Curve25519_PrivateKey::Curve25519_PrivateKey(RandomNumberGenerator& rng) + { + m_private = rng.random_vec(32); + m_public = curve25519_basepoint(m_private); + } + +Curve25519_PrivateKey::Curve25519_PrivateKey(const AlgorithmIdentifier&, + const secure_vector<byte>& key_bits, + RandomNumberGenerator& rng) + { + BER_Decoder(key_bits) + .start_cons(SEQUENCE) + .decode(m_public, OCTET_STRING) + .decode(m_private, OCTET_STRING) + .verify_end() + .end_cons(); + + size_check(m_public.size(), "public key"); + size_check(m_private.size(), "private key"); + + load_check(rng); + } + +secure_vector<byte> Curve25519_PrivateKey::pkcs8_private_key() const + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(m_public, OCTET_STRING) + .encode(m_private, OCTET_STRING) + .end_cons() + .get_contents(); + } + +bool Curve25519_PrivateKey::check_key(RandomNumberGenerator&, bool) const + { + return curve25519_basepoint(m_private) == m_public; + } + +secure_vector<byte> Curve25519_PrivateKey::agree(const byte w[], size_t w_len) const + { + size_check(w_len, "public value"); + + return curve25519(m_private, w); + } + +} diff --git a/src/lib/pubkey/curve25519/curve25519.h b/src/lib/pubkey/curve25519/curve25519.h new file mode 100644 index 000000000..718ebf05d --- /dev/null +++ b/src/lib/pubkey/curve25519/curve25519.h @@ -0,0 +1,94 @@ +/* +* Curve25519 +* (C) 2014 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CURVE_25519_H__ +#define BOTAN_CURVE_25519_H__ + +#include <botan/pk_keys.h> +#include <botan/pk_ops.h> + +namespace Botan { + +class BOTAN_DLL Curve25519_PublicKey : public virtual Public_Key + { + public: + std::string algo_name() const override { return "Curve25519"; } + + size_t estimated_strength() const override { return 128; } + + size_t max_input_bits() const { return 256; } + + bool check_key(RandomNumberGenerator& rng, bool strong) const override; + + AlgorithmIdentifier algorithm_identifier() const override; + + std::vector<byte> x509_subject_public_key() const override; + + std::vector<byte> public_value() const { return unlock(m_public); } + + Curve25519_PublicKey(const AlgorithmIdentifier& alg_id, + const secure_vector<byte>& key_bits); + + Curve25519_PublicKey(const secure_vector<byte>& pub) : m_public(pub) {} + protected: + Curve25519_PublicKey() {} + secure_vector<byte> m_public; + }; + +class BOTAN_DLL Curve25519_PrivateKey : public Curve25519_PublicKey, + public virtual Private_Key, + public virtual PK_Key_Agreement_Key + { + public: + Curve25519_PrivateKey(const AlgorithmIdentifier& alg_id, + const secure_vector<byte>& key_bits, + RandomNumberGenerator& rng); + + Curve25519_PrivateKey(RandomNumberGenerator& rng); + + Curve25519_PrivateKey(const secure_vector<byte>& secret_key); + + std::vector<byte> public_value() const override { return Curve25519_PublicKey::public_value(); } + + secure_vector<byte> agree(const byte w[], size_t w_len) const; + + const secure_vector<byte>& get_x() const { return m_private; } + + secure_vector<byte> pkcs8_private_key() const override; + + bool check_key(RandomNumberGenerator& rng, bool strong) const override; + private: + secure_vector<byte> m_private; + }; + +/** +* Curve25519 operation +*/ +class BOTAN_DLL Curve25519_KA_Operation : public PK_Ops::Key_Agreement + { + public: + Curve25519_KA_Operation(const Curve25519_PrivateKey& key) : m_key(key) {} + + secure_vector<byte> agree(const byte w[], size_t w_len) + { + return m_key.agree(w, w_len); + } + private: + const Curve25519_PrivateKey& m_key; + }; + +/* +* The types above are just wrappers for curve25519_donna, plus defining +* encodings for public and private keys. +*/ +int BOTAN_DLL curve25519_donna(uint8_t mypublic[32], + const uint8_t secret[32], + const uint8_t basepoint[32]); + +} + +#endif diff --git a/src/lib/pubkey/curve25519/donna.cpp b/src/lib/pubkey/curve25519/donna.cpp new file mode 100644 index 000000000..29d40ce13 --- /dev/null +++ b/src/lib/pubkey/curve25519/donna.cpp @@ -0,0 +1,456 @@ +/* +* curve25519-donna-c64.c from github.com/agl/curve25519-donna +* revision 80ad9b9930c9baef5829dd2a235b6b7646d32a8e +*/ + +/* Copyright 2008, Google Inc. + * All rights reserved. + * + * Code released into the public domain. + * + * curve25519-donna: Curve25519 elliptic curve, public key function + * + * http://code.google.com/p/curve25519-donna/ + * + * Adam Langley <[email protected]> + * + * Derived from public domain C code by Daniel J. Bernstein <[email protected]> + * + * More information about curve25519 can be found here + * http://cr.yp.to/ecdh.html + * + * djb's sample implementation of curve25519 is written in a special assembly + * language called qhasm and uses the floating point registers. + * + * This is, almost, a clean room reimplementation from the curve25519 paper. It + * uses many of the tricks described therein. Only the crecip function is taken + * from the sample implementation. + */ + +#include <botan/curve25519.h> +#include <botan/mul128.h> +#include <botan/loadstor.h> +#include <string.h> + +#if !defined(BOTAN_TARGET_HAS_NATIVE_UINT128) + #include <botan/internal/donna128.h> +#endif + +namespace Botan { + +typedef byte u8; +typedef u64bit limb; +typedef limb felem[5]; + +#if !defined(BOTAN_TARGET_HAS_NATIVE_UINT128) +typedef donna128 uint128_t; + +#else + +inline u64bit carry_shift(const uint128_t a, size_t shift) + { + return static_cast<u64bit>(a >> shift); + } + +inline u64bit combine_lower(const uint128_t a, size_t s1, + const uint128_t b, size_t s2) + { + return static_cast<u64bit>((a >> s1) | (b << s2)); + } + +#endif + +/* Sum two numbers: output += in */ +static inline void +fsum(limb *output, const limb *in) { + output[0] += in[0]; + output[1] += in[1]; + output[2] += in[2]; + output[3] += in[3]; + output[4] += in[4]; +} + +/* Find the difference of two numbers: output = in - output + * (note the order of the arguments!) + * + * Assumes that out[i] < 2**52 + * On return, out[i] < 2**55 + */ +static inline void +fdifference_backwards(felem out, const felem in) { + /* 152 is 19 << 3 */ + static const limb two54m152 = (static_cast<limb>(1) << 54) - 152; + static const limb two54m8 = (static_cast<limb>(1) << 54) - 8; + + out[0] = in[0] + two54m152 - out[0]; + out[1] = in[1] + two54m8 - out[1]; + out[2] = in[2] + two54m8 - out[2]; + out[3] = in[3] + two54m8 - out[3]; + out[4] = in[4] + two54m8 - out[4]; +} + +/* Multiply a number by a scalar: output = in * scalar */ +static inline void +fscalar_product(felem output, const felem in, const limb scalar) { + uint128_t a = uint128_t(in[0]) * scalar; + output[0] = a & 0x7ffffffffffff; + + a = uint128_t(in[1]) * scalar + carry_shift(a, 51); + output[1] = a & 0x7ffffffffffff; + + a = uint128_t(in[2]) * scalar + carry_shift(a, 51); + output[2] = a & 0x7ffffffffffff; + + a = uint128_t(in[3]) * scalar + carry_shift(a, 51); + output[3] = a & 0x7ffffffffffff; + + a = uint128_t(in[4]) * scalar + carry_shift(a, 51); + output[4] = a & 0x7ffffffffffff; + + output[0] += carry_shift(a, 51) * 19; +} + +/* Multiply two numbers: output = in2 * in + * + * output must be distinct to both inputs. The inputs are reduced coefficient + * form, the output is not. + * + * Assumes that in[i] < 2**55 and likewise for in2. + * On return, output[i] < 2**52 + */ +static inline void +fmul(felem output, const felem in2, const felem in) { + uint128_t t[5]; + limb r0,r1,r2,r3,r4,s0,s1,s2,s3,s4,c; + + r0 = in[0]; + r1 = in[1]; + r2 = in[2]; + r3 = in[3]; + r4 = in[4]; + + s0 = in2[0]; + s1 = in2[1]; + s2 = in2[2]; + s3 = in2[3]; + s4 = in2[4]; + + t[0] = uint128_t(r0) * s0; + t[1] = uint128_t(r0) * s1 + uint128_t(r1) * s0; + t[2] = uint128_t(r0) * s2 + uint128_t(r2) * s0 + uint128_t(r1) * s1; + t[3] = uint128_t(r0) * s3 + uint128_t(r3) * s0 + uint128_t(r1) * s2 + uint128_t(r2) * s1; + t[4] = uint128_t(r0) * s4 + uint128_t(r4) * s0 + uint128_t(r3) * s1 + uint128_t(r1) * s3 + uint128_t(r2) * s2; + + r4 *= 19; + r1 *= 19; + r2 *= 19; + r3 *= 19; + + t[0] += uint128_t(r4) * s1 + uint128_t(r1) * s4 + uint128_t(r2) * s3 + uint128_t(r3) * s2; + t[1] += uint128_t(r4) * s2 + uint128_t(r2) * s4 + uint128_t(r3) * s3; + t[2] += uint128_t(r4) * s3 + uint128_t(r3) * s4; + t[3] += uint128_t(r4) * s4; + + r0 = t[0] & 0x7ffffffffffff; c = carry_shift(t[0], 51); + t[1] += c; r1 = t[1] & 0x7ffffffffffff; c = carry_shift(t[1], 51); + t[2] += c; r2 = t[2] & 0x7ffffffffffff; c = carry_shift(t[2], 51); + t[3] += c; r3 = t[3] & 0x7ffffffffffff; c = carry_shift(t[3], 51); + t[4] += c; r4 = t[4] & 0x7ffffffffffff; c = carry_shift(t[4], 51); + r0 += c * 19; c = carry_shift(r0, 51); r0 = r0 & 0x7ffffffffffff; + r1 += c; c = carry_shift(r1, 51); r1 = r1 & 0x7ffffffffffff; + r2 += c; + + output[0] = r0; + output[1] = r1; + output[2] = r2; + output[3] = r3; + output[4] = r4; +} + +static inline void fsquare_times(felem output, const felem in, limb count) { + uint128_t t[5]; + limb r0,r1,r2,r3,r4,c; + limb d0,d1,d2,d4,d419; + + r0 = in[0]; + r1 = in[1]; + r2 = in[2]; + r3 = in[3]; + r4 = in[4]; + + do { + d0 = r0 * 2; + d1 = r1 * 2; + d2 = r2 * 2 * 19; + d419 = r4 * 19; + d4 = d419 * 2; + + t[0] = uint128_t(r0) * r0 + uint128_t(d4) * r1 + uint128_t(d2) * (r3 ); + t[1] = uint128_t(d0) * r1 + uint128_t(d4) * r2 + uint128_t(r3) * (r3 * 19); + t[2] = uint128_t(d0) * r2 + uint128_t(r1) * r1 + uint128_t(d4) * (r3 ); + t[3] = uint128_t(d0) * r3 + uint128_t(d1) * r2 + uint128_t(r4) * (d419 ); + t[4] = uint128_t(d0) * r4 + uint128_t(d1) * r3 + uint128_t(r2) * (r2 ); + + r0 = t[0] & 0x7ffffffffffff; c = carry_shift(t[0], 51); + t[1] += c; r1 = t[1] & 0x7ffffffffffff; c = carry_shift(t[1], 51); + t[2] += c; r2 = t[2] & 0x7ffffffffffff; c = carry_shift(t[2], 51); + t[3] += c; r3 = t[3] & 0x7ffffffffffff; c = carry_shift(t[3], 51); + t[4] += c; r4 = t[4] & 0x7ffffffffffff; c = carry_shift(t[4], 51); + r0 += c * 19; c = r0 >> 51; r0 = r0 & 0x7ffffffffffff; + r1 += c; c = r1 >> 51; r1 = r1 & 0x7ffffffffffff; + r2 += c; + } while(--count); + + output[0] = r0; + output[1] = r1; + output[2] = r2; + output[3] = r3; + output[4] = r4; +} + +/* Load a little-endian 64-bit number */ +static limb +load_limb(const u8 *in) { + return load_le<u64bit>(in, 0); +} + +static void +store_limb(u8 *out, limb in) { + store_le(in, out); +} + +/* Take a little-endian, 32-byte number and expand it into polynomial form */ +static void +fexpand(limb *output, const u8 *in) { + output[0] = load_limb(in) & 0x7ffffffffffff; + output[1] = (load_limb(in+6) >> 3) & 0x7ffffffffffff; + output[2] = (load_limb(in+12) >> 6) & 0x7ffffffffffff; + output[3] = (load_limb(in+19) >> 1) & 0x7ffffffffffff; + output[4] = (load_limb(in+24) >> 12) & 0x7ffffffffffff; +} + +/* Take a fully reduced polynomial form number and contract it into a + * little-endian, 32-byte array + */ +static void +fcontract(u8 *output, const felem input) { + uint128_t t[5]; + + t[0] = input[0]; + t[1] = input[1]; + t[2] = input[2]; + t[3] = input[3]; + t[4] = input[4]; + + t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffff; + t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffff; + t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffff; + t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffff; + t[0] += (t[4] >> 51) * 19; t[4] &= 0x7ffffffffffff; + + t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffff; + t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffff; + t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffff; + t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffff; + t[0] += (t[4] >> 51) * 19; t[4] &= 0x7ffffffffffff; + + /* now t is between 0 and 2^255-1, properly carried. */ + /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */ + + t[0] += 19; + + t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffff; + t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffff; + t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffff; + t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffff; + t[0] += (t[4] >> 51) * 19; t[4] &= 0x7ffffffffffff; + + /* now between 19 and 2^255-1 in both cases, and offset by 19. */ + + t[0] += 0x8000000000000 - 19; + t[1] += 0x8000000000000 - 1; + t[2] += 0x8000000000000 - 1; + t[3] += 0x8000000000000 - 1; + t[4] += 0x8000000000000 - 1; + + /* now between 2^255 and 2^256-20, and offset by 2^255. */ + + t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffff; + t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffff; + t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffff; + t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffff; + t[4] &= 0x7ffffffffffff; + + store_limb(output, combine_lower(t[0], 0, t[1], 51)); + store_limb(output+8, combine_lower(t[1], 13, t[2], 38)); + store_limb(output+16, combine_lower(t[2], 26, t[3], 25)); + store_limb(output+24, combine_lower(t[3], 39, t[4], 12)); +} + +/* Input: Q, Q', Q-Q' + * Output: 2Q, Q+Q' + * + * x2 z3: long form + * x3 z3: long form + * x z: short form, destroyed + * xprime zprime: short form, destroyed + * qmqp: short form, preserved + */ +static void +fmonty(limb *x2, limb *z2, /* output 2Q */ + limb *x3, limb *z3, /* output Q + Q' */ + limb *x, limb *z, /* input Q */ + limb *xprime, limb *zprime, /* input Q' */ + const limb *qmqp /* input Q - Q' */) { + limb origx[5], origxprime[5], zzz[5], xx[5], zz[5], xxprime[5], + zzprime[5], zzzprime[5]; + + memcpy(origx, x, 5 * sizeof(limb)); + fsum(x, z); + fdifference_backwards(z, origx); // does x - z + + memcpy(origxprime, xprime, sizeof(limb) * 5); + fsum(xprime, zprime); + fdifference_backwards(zprime, origxprime); + fmul(xxprime, xprime, z); + fmul(zzprime, x, zprime); + memcpy(origxprime, xxprime, sizeof(limb) * 5); + fsum(xxprime, zzprime); + fdifference_backwards(zzprime, origxprime); + fsquare_times(x3, xxprime, 1); + fsquare_times(zzzprime, zzprime, 1); + fmul(z3, zzzprime, qmqp); + + fsquare_times(xx, x, 1); + fsquare_times(zz, z, 1); + fmul(x2, xx, zz); + fdifference_backwards(zz, xx); // does zz = xx - zz + fscalar_product(zzz, zz, 121665); + fsum(zzz, xx); + fmul(z2, zz, zzz); +} + +// ----------------------------------------------------------------------------- +// Maybe swap the contents of two limb arrays (@a and @b), each @len elements +// long. Perform the swap iff @swap is non-zero. +// +// This function performs the swap without leaking any side-channel +// information. +// ----------------------------------------------------------------------------- +static void +swap_conditional(limb a[5], limb b[5], limb iswap) { + unsigned i; + const limb swap = -iswap; + + for (i = 0; i < 5; ++i) { + const limb x = swap & (a[i] ^ b[i]); + a[i] ^= x; + b[i] ^= x; + } +} + +/* Calculates nQ where Q is the x-coordinate of a point on the curve + * + * resultx/resultz: the x coordinate of the resulting curve point (short form) + * n: a little endian, 32-byte number + * q: a point of the curve (short form) + */ +static void +cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) { + limb a[5] = {0}, b[5] = {1}, c[5] = {1}, d[5] = {0}; + limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t; + limb e[5] = {0}, f[5] = {1}, g[5] = {0}, h[5] = {1}; + limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h; + + unsigned i, j; + + memcpy(nqpqx, q, sizeof(limb) * 5); + + for (i = 0; i < 32; ++i) { + u8 byte = n[31 - i]; + for (j = 0; j < 8; ++j) { + const limb bit = byte >> 7; + + swap_conditional(nqx, nqpqx, bit); + swap_conditional(nqz, nqpqz, bit); + fmonty(nqx2, nqz2, + nqpqx2, nqpqz2, + nqx, nqz, + nqpqx, nqpqz, + q); + swap_conditional(nqx2, nqpqx2, bit); + swap_conditional(nqz2, nqpqz2, bit); + + t = nqx; + nqx = nqx2; + nqx2 = t; + t = nqz; + nqz = nqz2; + nqz2 = t; + t = nqpqx; + nqpqx = nqpqx2; + nqpqx2 = t; + t = nqpqz; + nqpqz = nqpqz2; + nqpqz2 = t; + + byte <<= 1; + } + } + + memcpy(resultx, nqx, sizeof(limb) * 5); + memcpy(resultz, nqz, sizeof(limb) * 5); +} + + +// ----------------------------------------------------------------------------- +// Shamelessly copied from djb's code, tightened a little +// ----------------------------------------------------------------------------- +static void +crecip(felem out, const felem z) { + felem a,t0,b,c; + + /* 2 */ fsquare_times(a, z, 1); // a = 2 + /* 8 */ fsquare_times(t0, a, 2); + /* 9 */ fmul(b, t0, z); // b = 9 + /* 11 */ fmul(a, b, a); // a = 11 + /* 22 */ fsquare_times(t0, a, 1); + /* 2^5 - 2^0 = 31 */ fmul(b, t0, b); + /* 2^10 - 2^5 */ fsquare_times(t0, b, 5); + /* 2^10 - 2^0 */ fmul(b, t0, b); + /* 2^20 - 2^10 */ fsquare_times(t0, b, 10); + /* 2^20 - 2^0 */ fmul(c, t0, b); + /* 2^40 - 2^20 */ fsquare_times(t0, c, 20); + /* 2^40 - 2^0 */ fmul(t0, t0, c); + /* 2^50 - 2^10 */ fsquare_times(t0, t0, 10); + /* 2^50 - 2^0 */ fmul(b, t0, b); + /* 2^100 - 2^50 */ fsquare_times(t0, b, 50); + /* 2^100 - 2^0 */ fmul(c, t0, b); + /* 2^200 - 2^100 */ fsquare_times(t0, c, 100); + /* 2^200 - 2^0 */ fmul(t0, t0, c); + /* 2^250 - 2^50 */ fsquare_times(t0, t0, 50); + /* 2^250 - 2^0 */ fmul(t0, t0, b); + /* 2^255 - 2^5 */ fsquare_times(t0, t0, 5); + /* 2^255 - 21 */ fmul(out, t0, a); +} + +int +curve25519_donna(u8 *mypublic, const u8 *secret, const u8 *basepoint) { + limb bp[5], x[5], z[5], zmone[5]; + uint8_t e[32]; + int i; + + for (i = 0;i < 32;++i) e[i] = secret[i]; + e[0] &= 248; + e[31] &= 127; + e[31] |= 64; + + fexpand(bp, basepoint); + cmult(x, z, e, bp); + crecip(zmone, z); + fmul(z, x, zmone); + fcontract(mypublic, z); + return 0; +} + +} diff --git a/src/lib/pubkey/curve25519/donna128.h b/src/lib/pubkey/curve25519/donna128.h new file mode 100644 index 000000000..f2b2d88ea --- /dev/null +++ b/src/lib/pubkey/curve25519/donna128.h @@ -0,0 +1,116 @@ +/* +* A minimal 128-bit integer type for curve25519-donna +* (C) 2014 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CURVE25519_DONNA128_H__ +#define BOTAN_CURVE25519_DONNA128_H__ + +#include <botan/mul128.h> + +namespace Botan { + +class donna128 + { + public: + donna128(u64bit ll = 0, u64bit hh = 0) { l = ll; h = hh; } + + donna128(const donna128&) = default; + donna128& operator=(const donna128&) = default; + + friend donna128 operator>>(const donna128& x, size_t shift) + { + donna128 z = x; + const u64bit carry = z.h << (64 - shift); + z.h = (z.h >> shift); + z.l = (z.l >> shift) | carry; + return z; + } + + friend donna128 operator<<(const donna128& x, size_t shift) + { + donna128 z = x; + const u64bit carry = z.l >> (64 - shift); + z.l = (z.l << shift); + z.h = (z.h << shift) | carry; + return z; + } + + friend u64bit operator&(const donna128& x, u64bit mask) + { + return x.l & mask; + } + + u64bit operator&=(u64bit mask) + { + h = 0; + l &= mask; + return l; + } + + donna128& operator+=(const donna128& x) + { + l += x.l; + h += (l < x.l); + h += x.h; + return *this; + } + + donna128& operator+=(u64bit x) + { + l += x; + h += (l < x); + return *this; + } + + u64bit lo() const { return l; } + u64bit hi() const { return h; } + private: + u64bit h = 0, l = 0; + }; + +inline donna128 operator*(const donna128& x, u64bit y) + { + BOTAN_ASSERT(x.hi() == 0, "High 64 bits of donna128 set to zero during multiply"); + + u64bit lo = 0, hi = 0; + mul64x64_128(x.lo(), y, &lo, &hi); + return donna128(lo, hi); + } + +inline donna128 operator+(const donna128& x, const donna128& y) + { + donna128 z = x; + z += y; + return z; + } + +inline donna128 operator+(const donna128& x, u64bit y) + { + donna128 z = x; + z += y; + return z; + } + +inline donna128 operator|(const donna128& x, const donna128& y) + { + return donna128(x.lo() | y.lo(), x.hi() | y.hi()); + } + +inline u64bit carry_shift(const donna128& a, size_t shift) + { + return (a >> shift).lo(); + } + +inline u64bit combine_lower(const donna128 a, size_t s1, + const donna128 b, size_t s2) + { + donna128 z = (a >> s1) | (b << s2); + return z.lo(); + } + +} + +#endif diff --git a/src/lib/pubkey/curve25519/info.txt b/src/lib/pubkey/curve25519/info.txt new file mode 100644 index 000000000..68c417056 --- /dev/null +++ b/src/lib/pubkey/curve25519/info.txt @@ -0,0 +1,9 @@ +define CURVE_25519 20141227 + +<header:public> +curve25519.h +</header:public> + +<header:internal> +donna128.h +</header:internal> diff --git a/src/lib/pubkey/pk_algs.cpp b/src/lib/pubkey/pk_algs.cpp index 9673199e0..e1784dd9f 100644 --- a/src/lib/pubkey/pk_algs.cpp +++ b/src/lib/pubkey/pk_algs.cpp @@ -44,6 +44,10 @@ #include <botan/ecdh.h> #endif +#if defined(BOTAN_HAS_CURVE_25519) + #include <botan/curve25519.h> +#endif + namespace Botan { Public_Key* make_public_key(const AlgorithmIdentifier& alg_id, @@ -98,6 +102,11 @@ Public_Key* make_public_key(const AlgorithmIdentifier& alg_id, return new ECDH_PublicKey(alg_id, key_bits); #endif +#if defined(BOTAN_HAS_CURVE_25519) + if(alg_name == "Curve25519") + return new Curve25519_PublicKey(alg_id, key_bits); +#endif + return nullptr; } @@ -154,6 +163,11 @@ Private_Key* make_private_key(const AlgorithmIdentifier& alg_id, return new ECDH_PrivateKey(alg_id, key_bits); #endif +#if defined(BOTAN_HAS_CURVE_25519) + if(alg_name == "Curve25519") + return new Curve25519_PrivateKey(alg_id, key_bits, rng); +#endif + return nullptr; } |