/* * Copyright (c) 2013-2020, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * * See full license text in LICENSE file at top of project tree */ #ifndef ED25519_H__ #define ED25519_H__ #include #include #include "Crypto.h" namespace i2p { namespace crypto { struct EDDSAPoint { BIGNUM * x {nullptr}; BIGNUM * y {nullptr}; BIGNUM * z {nullptr}; BIGNUM * t {nullptr}; // projective coordinates EDDSAPoint () {} EDDSAPoint (const EDDSAPoint& other) { *this = other; } EDDSAPoint (EDDSAPoint&& other) { *this = std::move (other); } EDDSAPoint (BIGNUM * x1, BIGNUM * y1, BIGNUM * z1 = nullptr, BIGNUM * t1 = nullptr) : x(x1) , y(y1) , z(z1) , t(t1) {} ~EDDSAPoint () { BN_free (x); BN_free (y); BN_free(z); BN_free(t); } EDDSAPoint& operator=(EDDSAPoint&& other) { if (this != &other) { BN_free (x); x = other.x; other.x = nullptr; BN_free (y); y = other.y; other.y = nullptr; BN_free (z); z = other.z; other.z = nullptr; BN_free (t); t = other.t; other.t = nullptr; } return *this; } EDDSAPoint& operator=(const EDDSAPoint& other) { if (this != &other) { BN_free (x); x = other.x ? BN_dup (other.x) : nullptr; BN_free (y); y = other.y ? BN_dup (other.y) : nullptr; BN_free (z); z = other.z ? BN_dup (other.z) : nullptr; BN_free (t); t = other.t ? BN_dup (other.t) : nullptr; } return *this; } EDDSAPoint operator-() const { BIGNUM * x1 = NULL, * y1 = NULL, * z1 = NULL, * t1 = NULL; if (x) { x1 = BN_dup (x); BN_set_negative (x1, !BN_is_negative (x)); }; if (y) y1 = BN_dup (y); if (z) z1 = BN_dup (z); if (t) { t1 = BN_dup (t); BN_set_negative (t1, !BN_is_negative (t)); }; return EDDSAPoint {x1, y1, z1, t1}; } }; const size_t EDDSA25519_PUBLIC_KEY_LENGTH = 32; const size_t EDDSA25519_SIGNATURE_LENGTH = 64; const size_t EDDSA25519_PRIVATE_KEY_LENGTH = 32; class Ed25519 { public: Ed25519 (); Ed25519 (const Ed25519& other); ~Ed25519 (); EDDSAPoint GeneratePublicKey (const uint8_t * expandedPrivateKey, BN_CTX * ctx) const; EDDSAPoint DecodePublicKey (const uint8_t * buf, BN_CTX * ctx) const; void EncodePublicKey (const EDDSAPoint& publicKey, uint8_t * buf, BN_CTX * ctx) const; #if !OPENSSL_X25519 void ScalarMul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const; // p is point, e is number for x25519 void ScalarMulB (const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const; #endif void BlindPublicKey (const uint8_t * pub, const uint8_t * seed, uint8_t * blinded); // for encrypted LeaseSet2, pub - 32, seed - 64, blinded - 32 void BlindPrivateKey (const uint8_t * priv, const uint8_t * seed, uint8_t * blindedPriv, uint8_t * blindedPub); // for encrypted LeaseSet2, pub - 32, seed - 64, blinded - 32 bool Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature) const; void Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len, uint8_t * signature) const; void SignRedDSA (const uint8_t * privateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len, uint8_t * signature) const; static void ExpandPrivateKey (const uint8_t * key, uint8_t * expandedKey); // key - 32 bytes, expandedKey - 64 bytes void CreateRedDSAPrivateKey (uint8_t * priv); // priv is 32 bytes private: EDDSAPoint Sum (const EDDSAPoint& p1, const EDDSAPoint& p2, BN_CTX * ctx) const; void Double (EDDSAPoint& p, BN_CTX * ctx) const; EDDSAPoint Mul (const EDDSAPoint& p, const BIGNUM * e, BN_CTX * ctx) const; EDDSAPoint MulB (const uint8_t * e, BN_CTX * ctx) const; // B*e, e is 32 bytes Little Endian EDDSAPoint Normalize (const EDDSAPoint& p, BN_CTX * ctx) const; bool IsOnCurve (const EDDSAPoint& p, BN_CTX * ctx) const; BIGNUM * RecoverX (const BIGNUM * y, BN_CTX * ctx) const; EDDSAPoint DecodePoint (const uint8_t * buf, BN_CTX * ctx) const; void EncodePoint (const EDDSAPoint& p, uint8_t * buf) const; template BIGNUM * DecodeBN (const uint8_t * buf) const; void EncodeBN (const BIGNUM * bn, uint8_t * buf, size_t len) const; #if !OPENSSL_X25519 // for x25519 BIGNUM * ScalarMul (const BIGNUM * p, const BIGNUM * e, BN_CTX * ctx) const; #endif private: BIGNUM * q, * l, * d, * I; // transient values BIGNUM * two_252_2; // 2^252-2 EDDSAPoint Bi256[32][128]; // per byte, Bi256[i][j] = (256+j+1)^i*B, we don't store zeroes // if j > 128 we use 256 - j and carry 1 to next byte // Bi256[0][0] = B, base point EDDSAPoint Bi256Carry; // Bi256[32][0] }; std::unique_ptr& GetEd25519 (); } } #endif