From 4b062aa4853852287bab5bd096a6d225c217a0da Mon Sep 17 00:00:00 2001 From: attermann Date: Sat, 7 Oct 2023 15:03:21 -0600 Subject: [PATCH] WIP update Implemented X25519. --- src/Bytes.cpp | 52 ++++++----- src/Bytes.h | 42 +++++---- src/Cryptography/Ed25519.h | 1 + src/Cryptography/Hashes.cpp | 20 ++-- src/Cryptography/Hashes.h | 6 +- src/Cryptography/X25519.h | 95 ++++++++++++++----- src/Destination.cpp | 16 ++-- src/Identity.cpp | 173 ++++++++++++++++++++++++++++++----- src/Identity.h | 14 ++- src/Interfaces/Interface.cpp | 4 +- src/Interfaces/Interface.h | 35 ++++++- src/Packet.cpp | 16 +++- src/Packet.h | 39 +++++--- src/Reticulum.cpp | 9 ++ src/Reticulum.h | 17 ++-- src/Test/Test.cpp | 1 - src/Test/Test.h | 2 - src/Test/TestBytes.cpp | 50 ++++++++++ src/Test/TestCrypto.cpp | 2 +- src/Test/TestReference.cpp | 2 +- src/Transport.cpp | 2 +- src/main.cpp | 57 ++++++------ 22 files changed, 490 insertions(+), 165 deletions(-) diff --git a/src/Bytes.cpp b/src/Bytes.cpp index fa49904..1a0d818 100644 --- a/src/Bytes.cpp +++ b/src/Bytes.cpp @@ -39,27 +39,6 @@ int8_t Bytes::compare(const Bytes &bytes) const { } } -char const hex_upper_chars[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; -char const hex_lower_chars[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; - -std::string Bytes::toHex(bool upper /*= true*/) const { - if (!_data) { - return ""; - } - std::string hex; - for (uint8_t byte : *_data) { - if (upper) { - hex += hex_upper_chars[ (byte & 0xF0) >> 4]; - hex += hex_upper_chars[ (byte & 0x0F) >> 0]; - } - else { - hex += hex_lower_chars[ (byte & 0xF0) >> 4]; - hex += hex_lower_chars[ (byte & 0x0F) >> 0]; - } - } - return hex; -} - void Bytes::assignHex(const char* hex) { // if assignment is empty then clear data and don't bother creating new if (hex == nullptr || hex[0] == 0) { @@ -86,3 +65,34 @@ void Bytes::appendHex(const char* hex) { _data->push_back(byte); } } + +char const hex_upper_chars[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; +char const hex_lower_chars[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + +std::string Bytes::toHex(bool upper /*= true*/) const { + if (!_data) { + return ""; + } + std::string hex; + for (uint8_t byte : *_data) { + if (upper) { + hex += hex_upper_chars[ (byte & 0xF0) >> 4]; + hex += hex_upper_chars[ (byte & 0x0F) >> 0]; + } + else { + hex += hex_lower_chars[ (byte & 0xF0) >> 4]; + hex += hex_lower_chars[ (byte & 0x0F) >> 0]; + } + } + return hex; +} + +Bytes Bytes::mid(size_t pos, size_t len) const { + if (!_data || pos >= size()) { + return NONE; + } + if ((pos + len) >= size()) { + len = (size() - pos); + } + return {data() + pos, len}; +} diff --git a/src/Bytes.h b/src/Bytes.h index d6b32b1..73ecdf2 100644 --- a/src/Bytes.h +++ b/src/Bytes.h @@ -12,6 +12,8 @@ namespace RNS { + #define COW + class Bytes { private: @@ -34,8 +36,7 @@ namespace RNS { } Bytes(const Bytes &bytes) { //extreme("Bytes is using shared data"); - _data = bytes.shareData(); - _owner = false; + assign(bytes); //extreme("Bytes object copy created from bytes \"" + toString() + "\", this: " + std::to_string((ulong)this) + ", data: " + std::to_string((ulong)_data.get())); } Bytes(const uint8_t *chunk, size_t size) { @@ -103,21 +104,11 @@ namespace RNS { void ownData(); public: - int8_t compare(const Bytes &bytes) const; - inline size_t size() const { if (!_data) return 0; return _data->size(); } - inline bool empty() const { if (!_data) return true; return _data->empty(); } - inline size_t capacity() const { if (!_data) return 0; return _data->capacity(); } - inline const uint8_t *data() const { if (!_data) return nullptr; return _data->data(); } - - inline std::string toString() const { if (!_data) return ""; return {(const char*)data(), size()}; } - std::string toHex(bool upper = true) const; - - inline uint8_t *writable(size_t size) { - newData(size); - return _data->data(); - } - inline void assign(const Bytes& bytes) { +#ifdef COW + _data = bytes.shareData(); + _owner = false; +#else // if assignment is empty then clear data and don't bother creating new if (bytes.size() <= 0) { _data = nullptr; @@ -125,6 +116,7 @@ namespace RNS { } newData(); _data->insert(_data->begin(), bytes._data->begin(), bytes._data->end()); +#endif } inline void assign(const uint8_t *chunk, size_t size) { // if assignment is empty then clear data and don't bother creating new @@ -178,6 +170,24 @@ namespace RNS { } void appendHex(const char* hex); + public: + int8_t compare(const Bytes &bytes) const; + inline size_t size() const { if (!_data) return 0; return _data->size(); } + inline bool empty() const { if (!_data) return true; return _data->empty(); } + inline size_t capacity() const { if (!_data) return 0; return _data->capacity(); } + inline const uint8_t *data() const { if (!_data) return nullptr; return _data->data(); } + + inline std::string toString() const { if (!_data) return ""; return {(const char*)data(), size()}; } + std::string toHex(bool upper = true) const; + Bytes mid(size_t pos, size_t len) const; + inline Bytes left(size_t len) const { if (!_data) return NONE; if (len > size()) len = size(); return {data(), len}; } + inline Bytes right(size_t len) const { if (!_data) return NONE; if (len > size()) len = size(); return {data() + (size() - len), len}; } + + inline uint8_t *writable(size_t size) { + newData(size); + return _data->data(); + } + private: SharedData _data; mutable bool _owner = true; diff --git a/src/Cryptography/Ed25519.h b/src/Cryptography/Ed25519.h index 14e746d..bffca0a 100644 --- a/src/Cryptography/Ed25519.h +++ b/src/Cryptography/Ed25519.h @@ -55,6 +55,7 @@ namespace RNS { namespace Cryptography { // create random private key Ed25519::generatePrivateKey(_privateKey.writable(32)); } + // derive public key from private key Ed25519::derivePublicKey(_publicKey.writable(32), _privateKey.data()); } ~Ed25519PrivateKey() {} diff --git a/src/Cryptography/Hashes.cpp b/src/Cryptography/Hashes.cpp index db5ca0b..5229989 100644 --- a/src/Cryptography/Hashes.cpp +++ b/src/Cryptography/Hashes.cpp @@ -1,11 +1,12 @@ #include "Hashes.h" #include "../Log.h" +#include "../Bytes.h" #include #include -using namespace RNS::Cryptography; +using namespace RNS; /* The SHA primitives are abstracted here to allow platform- @@ -14,18 +15,23 @@ uses Python's internal SHA-256 implementation. All SHA-256 calls in RNS end up here. */ -void RNS::Cryptography::sha256(uint8_t *hash, const uint8_t *data, uint16_t data_len) { +Bytes RNS::Cryptography::sha256(const Bytes &data) { //extreme("Cryptography::sha256: data: " + data.toHex() ); SHA256 digest; digest.reset(); - digest.update(data, data_len); - digest.finalize(hash, 32); + digest.update(data.data(), data.size()); + Bytes hash; + digest.finalize(hash.writable(32), 32); //extreme("Cryptography::sha256: hash: " + hash.toHex() ); + return hash; } -void RNS::Cryptography::sha512(uint8_t *hash, const uint8_t *data, uint16_t data_len) { +Bytes RNS::Cryptography::sha512(const Bytes &data) { SHA512 digest; digest.reset(); - digest.update(data, data_len); - digest.finalize(hash, 64); + digest.update(data.data(), data.size()); + Bytes hash; + digest.finalize(hash.writable(64), 64); + //extreme("Cryptography::sha512: hash: " + hash.toHex() ); + return hash; } diff --git a/src/Cryptography/Hashes.h b/src/Cryptography/Hashes.h index b400a23..8c0b913 100644 --- a/src/Cryptography/Hashes.h +++ b/src/Cryptography/Hashes.h @@ -1,10 +1,12 @@ #pragma once +#include "../Bytes.h" + #include namespace RNS { namespace Cryptography { - void sha256(uint8_t *hash, const uint8_t *data, uint16_t data_len); - void sha512(uint8_t *hash, const uint8_t *data, uint16_t data_len); + Bytes sha256(const Bytes &data); + Bytes sha512(const Bytes &data); } } diff --git a/src/Cryptography/X25519.h b/src/Cryptography/X25519.h index 988eb6e..cdd558d 100644 --- a/src/Cryptography/X25519.h +++ b/src/Cryptography/X25519.h @@ -2,6 +2,8 @@ #include "Bytes.h" +#include + #include #include @@ -10,29 +12,41 @@ namespace RNS { namespace Cryptography { class X25519PublicKey { public: +/* X25519PublicKey(const Bytes &x) { _x = x; } +*/ + X25519PublicKey(const Bytes &publicKey) { + _publicKey = publicKey; + } ~X25519PublicKey() {} using Ptr = std::shared_ptr; public: // creates a new instance with specified seed +/* static inline Ptr from_public_bytes(const Bytes &data) { - //return Ptr(new X25519PublicKey(_unpack_number(data))); - // MOCK - return Ptr(new X25519PublicKey(nullptr)); + return Ptr(new X25519PublicKey(_unpack_number(data))); + } +*/ + static inline Ptr from_public_bytes(const Bytes &publicKey) { + return Ptr(new X25519PublicKey(publicKey)); } +/* Bytes public_bytes() { - //return _pack_number(_x); - // MOCK - return nullptr; + return _pack_number(_x); + } +*/ + Bytes public_bytes() { + return _publicKey; } private: - Bytes _x; + //Bytes _x; + Bytes _publicKey; }; @@ -47,43 +61,74 @@ namespace RNS { namespace Cryptography { const uint8_t T_MAX = 0; public: +/* X25519PrivateKey(const Bytes &a) { _a = a; } +*/ + X25519PrivateKey(const Bytes &privateKey) { + if (privateKey) { + // use specified private key + _privateKey = privateKey; + // similar to derive public key from private key + // second param "f" is secret + //eval(uint8_t result[32], const uint8_t s[32], const uint8_t x[32]) + // derive public key from private key + Curve25519::eval(_publicKey.writable(32), _privateKey.data(), 0); + } + else { + // create random private key and derive public key + // second param "f" is secret + //dh1(uint8_t k[32], uint8_t f[32]) + Curve25519::dh1(_publicKey.writable(32), _privateKey.writable(32)); + } + } ~X25519PrivateKey() {} using Ptr = std::shared_ptr; public: // creates a new instance with a random seed +/* static inline Ptr generate() { - //return from_private_bytes(os.urandom(32)); - // MOCK - return from_private_bytes(nullptr); + return from_private_bytes(os.urandom(32)); + } +*/ + static inline Ptr generate() { + return from_private_bytes(Bytes::NONE); } // creates a new instance with specified seed +/* static inline Ptr from_private_bytes(const Bytes &data) { - //return Ptr(new X25519PrivateKey(_fix_secret(_unpack_number(data)))); - // MOCK - return Ptr(new X25519PrivateKey(nullptr)); + return Ptr(new X25519PrivateKey(_fix_secret(_unpack_number(data)))); + } +*/ + static inline Ptr from_private_bytes(const Bytes &privateKey) { + return Ptr(new X25519PrivateKey(privateKey)); } +/* inline Bytes private_bytes() { - //return _pack_number(_a); - // MOCK - return nullptr; + return _pack_number(_a); + } +*/ + inline Bytes private_bytes() { + return _privateKey; } // creates a new instance of public key for this private key +/* inline X25519PublicKey::Ptr public_key() { - //return X25519PublicKey::from_public_bytes(_pack_number(_raw_curve25519(9, _a))); - // MOCK - return X25519PublicKey::from_public_bytes(nullptr); + return X25519PublicKey::from_public_bytes(_pack_number(_raw_curve25519(9, _a))); + } +*/ + inline X25519PublicKey::Ptr public_key() { + return X25519PublicKey::from_public_bytes(_publicKey); } - inline Bytes exchange(const Bytes &peer_public_key) { /* + inline Bytes exchange(const Bytes &peer_public_key) { if isinstance(peer_public_key, bytes): peer_public_key = X25519PublicKey.from_public_bytes(peer_public_key) @@ -119,12 +164,18 @@ namespace RNS { namespace Cryptography { X25519PrivateKey.T_MAX = duration return shared + } */ - return nullptr; + inline Bytes exchange(const Bytes &peer_public_key) { + Bytes sharedKey(peer_public_key); + Curve25519::dh2(sharedKey.writable(32), _privateKey.writable(32)); + return sharedKey; } private: - Bytes _a; + //Bytes _a; + Bytes _privateKey; + Bytes _publicKey; }; diff --git a/src/Destination.cpp b/src/Destination.cpp index eba8b55..06c7f78 100644 --- a/src/Destination.cpp +++ b/src/Destination.cpp @@ -272,15 +272,15 @@ Bytes Destination::encrypt(const Bytes &data) { assert(_object); debug("Destination::encrypt: encrypting bytes"); -/* if (_object->_type == Destination::PLAIN) { return data; } if (_object->_type == Destination::SINGLE && _object->_identity) { - return _object->_identity.encrypt(data) + return _object->_identity.encrypt(data); } +/* if (_object->_type == Destination::GROUP { if hasattr(self, "prv") and self.prv != None: try: @@ -292,9 +292,8 @@ Bytes Destination::encrypt(const Bytes &data) { raise ValueError("No private key held by GROUP destination. Did you create or load one?") } */ - // MOCK - return data; + return Bytes::NONE; } /* @@ -307,15 +306,15 @@ Bytes Destination::decrypt(const Bytes &data) { assert(_object); debug("Destination::decrypt: decrypting bytes"); -/* if (_object->_type == Destination::PLAIN) { return data; } if (_object->_type == Destination::SINGLE && _object->_identity) { - return identity.decrypt(data); + return _object->_identity.decrypt(data); } +/* if (_object->_type == Destination::GROUP) { if hasattr(self, "prv") and self.prv != None: try: @@ -327,9 +326,8 @@ Bytes Destination::decrypt(const Bytes &data) { raise ValueError("No private key held by GROUP destination. Did you create or load one?") } */ - // MOCK - return data; + return Bytes::NONE; } /* @@ -343,5 +341,5 @@ Bytes Destination::sign(const Bytes &message) { if (_object->_type == Destination::SINGLE && _object->_identity) { return _object->_identity.sign(message); } - return nullptr; + return Bytes::NONE; } diff --git a/src/Identity.cpp b/src/Identity.cpp index 88ead56..c144268 100644 --- a/src/Identity.cpp +++ b/src/Identity.cpp @@ -1,7 +1,10 @@ #include "Identity.h" +#include "Reticulum.h" +#include "Packet.h" #include "Log.h" #include "Cryptography/Hashes.h" +#include "Cryptography/X25519.h" #include @@ -20,7 +23,7 @@ void Identity::createKeys() { _object->_prv = Cryptography::X25519PrivateKey::generate(); _object->_prv_bytes = _object->_prv->private_bytes(); - debug("Identity::createKeys: prv bytes: " + _object->_prv_bytes.toHex()); + debug("Identity::createKeys: prv bytes: " + _object->_prv_bytes.toHex()); _object->_sig_prv = Cryptography::Ed25519PrivateKey::generate(); _object->_sig_prv_bytes = _object->_sig_prv->private_bytes(); @@ -28,7 +31,7 @@ void Identity::createKeys() { _object->_pub = _object->_prv->public_key(); _object->_pub_bytes = _object->_pub->public_bytes(); - debug("Identity::createKeys: pub bytes: " + _object->_pub_bytes.toHex()); + debug("Identity::createKeys: pub bytes: " + _object->_pub_bytes.toHex()); _object->_sig_pub = _object->_sig_prv->public_key(); _object->_sig_pub_bytes = _object->_sig_pub->public_bytes(); @@ -45,18 +48,122 @@ void Identity::createKeys() { Bytes Identity::get_public_key() { assert(_object); return _object->_pub_bytes + _object->_sig_pub_bytes; - // MOCK - return "abc123"; } void Identity::update_hashes() { assert(_object); _object->_hash = truncated_hash(get_public_key()); - debug("Identity::update_hashes: hash: " + _object->_hash.toHex()); + debug("Identity::update_hashes: hash: " + _object->_hash.toHex()); _object->_hexhash = _object->_hash.toHex(); debug("Identity::update_hashes: hexhash: " + _object->_hexhash); }; + +/* +Get a SHA-256 hash of passed data. + +:param data: Data to be hashed as *bytes*. +:returns: SHA-256 hash as *bytes* +*/ +/*static*/ Bytes Identity::full_hash(const Bytes &data) { + return Cryptography::sha256(data); +} + +/* +Get a truncated SHA-256 hash of passed data. + +:param data: Data to be hashed as *bytes*. +:returns: Truncated SHA-256 hash as *bytes* +*/ +/*static*/ Bytes Identity::truncated_hash(const Bytes &data) { + return full_hash(data).right(TRUNCATED_HASHLENGTH/8); +} + + +/* +Encrypts information for the identity. + +:param plaintext: The plaintext to be encrypted as *bytes*. +:returns: Ciphertext token as *bytes*. +:raises: *KeyError* if the instance does not hold a public key. +*/ +Bytes Identity::encrypt(const Bytes &plaintext) { + assert(_object); + if (_object->_pub) { + Cryptography::X25519PrivateKey::Ptr ephemeral_key = Cryptography::X25519PrivateKey::generate(); + Bytes ephemeral_pub_bytes = ephemeral_key->public_key()->public_bytes(); + +/* + Bytes shared_key = ephemeral_key->exchange(_object->_pub); + + Bytes derived_key = RNS.Cryptography.hkdf( + length=32, + derive_from=shared_key, + salt=get_salt(), + context=get_context(), + ) + + fernet = Fernet(derived_key) + ciphertext = fernet.encrypt(plaintext) + + return ephemeral_pub_bytes + ciphertext; +*/ + // MOCK + return Bytes::NONE; + } + else { + throw std::runtime_error("Encryption failed because identity does not hold a public key"); + } +} + + +/* +Decrypts information for the identity. + +:param ciphertext: The ciphertext to be decrypted as *bytes*. +:returns: Plaintext as *bytes*, or *None* if decryption fails. +:raises: *KeyError* if the instance does not hold a private key. +*/ +Bytes Identity::decrypt(const Bytes &ciphertext_token) { + assert(_object); + if (_object->_prv) { + if (ciphertext_token.size() > Identity::KEYSIZE/8/2) { + Bytes plaintext; + try { + Bytes peer_pub_bytes = ciphertext_token.right(Identity::KEYSIZE/8/2); + Cryptography::X25519PublicKey::Ptr peer_pub = Cryptography::X25519PublicKey::from_public_bytes(peer_pub_bytes); + +/* + Bytes shared_key = _object->_prv->exchange(peer_pub); + + Bytes derived_key = RNS.Cryptography.hkdf( + length=32, + derive_from=shared_key, + salt=get_salt(), + context=get_context(), + ) + + fernet = Fernet(derived_key) + ciphertext = ciphertext_token[Identity.KEYSIZE//8//2:] + plaintext = fernet.decrypt(ciphertext) +*/ + } + catch (std::exception &e) { + debug("Decryption by " + _object->_hash.toHex() + " failed: " + e.what()); + } + + return plaintext; + } + else { + debug("Decryption failed because the token size was invalid."); + return Bytes::NONE; + } + } + else { + throw std::runtime_error("Decryption failed because identity does not hold a private key"); + } +} + /* Signs information by the identity. @@ -70,7 +177,7 @@ Bytes Identity::sign(const Bytes &message) { try { return _object->_sig_prv->sign(message); } - catch (std::exception e) { + catch (std::exception &e) { error("The identity " + toString() + " could not sign the requested message. The contained exception was: " + e.what()); throw e; } @@ -80,29 +187,45 @@ Bytes Identity::sign(const Bytes &message) { } } - /* -Get a SHA-256 hash of passed data. +Validates the signature of a signed message. -:param data: Data to be hashed as *bytes*. -:returns: SHA-256 hash as *bytes* +:param signature: The signature to be validated as *bytes*. +:param message: The message to be validated as *bytes*. +:returns: True if the signature is valid, otherwise False. +:raises: *KeyError* if the instance does not hold a public key. */ -/*static*/ Bytes Identity::full_hash(const Bytes &data) { - Bytes hash; - Cryptography::sha256(hash.writable(HASHLENGTH/8), data.data(), data.size()); - //debug("Identity::full_hash: hash: " + hash.toHex()); - return hash; +bool Identity::validate(const Bytes &signature, const Bytes &message) { + assert(_object); + if (_object->_pub) { + try { + _object->_sig_pub->verify(signature, message); + return true; + } + catch (std::exception &e) { + return false; + } + } + else { + throw std::runtime_error("Signature validation failed because identity does not hold a public key"); + } } -/* -Get a truncated SHA-256 hash of passed data. +void Identity::prove(const Packet &packet, const Destination &destination /*= Destination::NONE*/) { + assert(_object); + Bytes signature(sign(packet._packet_hash)); + Bytes proof_data; + if (RNS::Reticulum::should_use_implicit_proof()) { + proof_data = signature; + } + else { + proof_data = packet._packet_hash + signature; + } + + //zif (!destination) { + //z destination = packet.generate_proof_destination(); + //z} -:param data: Data to be hashed as *bytes*. -:returns: Truncated SHA-256 hash as *bytes* -*/ -/*static*/ Bytes Identity::truncated_hash(const Bytes &data) { - Bytes hash = full_hash(data); - //Bytes truncated_hash(hash.data() + (TRUNCATED_HASHLENGTH/8), TRUNCATED_HASHLENGTH/8); - //debug("Identity::truncated_hash: truncated hash: " + truncated_hash.toHex()); - return Bytes(hash.data() + (TRUNCATED_HASHLENGTH/8), TRUNCATED_HASHLENGTH/8); + Packet proof(destination, packet.receiving_interface(), proof_data, RNS::Packet::PROOF); + proof.send(); } diff --git a/src/Identity.h b/src/Identity.h index 51fee3b..264332f 100644 --- a/src/Identity.h +++ b/src/Identity.h @@ -1,6 +1,8 @@ #pragma once #include "Reticulum.h" +// CBA TODO determine why including Destination.h here causes build errors +//#include "Destination.h" #include "Log.h" #include "Bytes.h" #include "Cryptography/Fernet.h" @@ -13,6 +15,9 @@ namespace RNS { + class Destination; + class Packet; + class Identity { public: @@ -66,8 +71,15 @@ namespace RNS { static Bytes full_hash(const Bytes &data); static Bytes truncated_hash(const Bytes &data); - Bytes sign(const Bytes &message); + Bytes encrypt(const Bytes &plaintext); + Bytes decrypt(const Bytes &ciphertext_token); + Bytes sign(const Bytes &message); + bool validate(const Bytes &signature, const Bytes &message); + //void prove(const Packet &packet, const Destination &destination = Destination::NONE); + void prove(const Packet &packet, const Destination &destination); + + // getters/setters inline Bytes encryptionPrivateKey() const { assert(_object); return _object->_prv_bytes; } inline Bytes signingPrivateKey() const { assert(_object); return _object->_sig_prv_bytes; } inline Bytes encryptionPublicKey() const { assert(_object); return _object->_prv_bytes; } diff --git a/src/Interfaces/Interface.cpp b/src/Interfaces/Interface.cpp index 7d569c4..2383979 100644 --- a/src/Interfaces/Interface.cpp +++ b/src/Interfaces/Interface.cpp @@ -5,10 +5,10 @@ using namespace RNS; Interface::Interface() { - log("Interface object created", LOG_EXTREME); + extreme("Interface object created"); } Interface::~Interface() { - log("Interface object destroyed", LOG_EXTREME); + extreme("Interface object destroyed"); } diff --git a/src/Interfaces/Interface.h b/src/Interfaces/Interface.h index 7b726b2..3a88383 100644 --- a/src/Interfaces/Interface.h +++ b/src/Interfaces/Interface.h @@ -1,11 +1,18 @@ #pragma once -//#include +#include "../Log.h" + +#include namespace RNS { class Interface { + public: + enum NoneConstructor { + NONE + }; + public: // Interface mode definitions enum modes { @@ -22,9 +29,33 @@ namespace RNS { //zDISCOVER_PATHS_FOR = [MODE_ACCESS_POINT, MODE_GATEWAY] public: + Interface(NoneConstructor none) { + extreme("Interface object NONE created"); + } + Interface(const Interface &interface) : _object(interface._object) { + extreme("Interface object copy created"); + } Interface(); ~Interface(); + inline Interface& operator = (const Interface &interface) { + _object = interface._object; + extreme("Interface object copy created by assignment, this: " + std::to_string((ulong)this) + ", data: " + std::to_string((uint32_t)_object.get())); + return *this; + } + inline operator bool() const { + return _object.get() != nullptr; + } + + private: + class Object { + private: + + + friend class Interface; + }; + std::shared_ptr _object; + }; -} \ No newline at end of file +} diff --git a/src/Packet.cpp b/src/Packet.cpp index 44dbe7a..2995998 100644 --- a/src/Packet.cpp +++ b/src/Packet.cpp @@ -8,8 +8,8 @@ using namespace RNS; -Packet::Packet(const Destination &destination, const Bytes &data, types packet_type, context_types context, Transport::types transport_type, header_types header_type, const uint8_t *transport_id, Interface *attached_interface, bool create_receipt) : _object(new Object(destination)) { - assert(_object); +//Packet::Packet(const Destination &destination, const Bytes &data, types packet_type, context_types context, Transport::types transport_type, header_types header_type, const uint8_t *transport_id, Interface *attached_interface, bool create_receipt) : _object(new Object(destination)) { +Packet::Packet(const Destination &destination, const Interface &attached_interface, const Bytes &data, types packet_type /*= DATA*/, context_types context /*= CONTEXT_NONE*/, Transport::types transport_type /*= Transport::BROADCAST*/, header_types header_type /*= HEADER_1*/, const uint8_t *transport_id /*= nullptr*/, bool create_receipt /*= true*/) : _object(new Object(destination, attached_interface)) { if (_object->_destination) { // CBA TODO handle NONE @@ -52,7 +52,6 @@ Packet::Packet(const Destination &destination, const Bytes &data, types packet_t _fromPacked = true; _create_receipt = false; } - _attached_interface = attached_interface; extreme("Packet object created"); } @@ -427,8 +426,8 @@ bool Packet::unpack() { _packed = false; update_hash(); } - catch (std::exception& ex) { - log(std::string("Received malformed packet, dropping it. The contained exception was: ") + ex.what(), LOG_EXTREME); + catch (std::exception& e) { + error(std::string("Received malformed packet, dropping it. The contained exception was: ") + e.what()); return false; } @@ -530,3 +529,10 @@ Bytes Packet::get_hashable_part() { hashable_part.append(_data-Reticulum::DESTINATION_LENGTH-1, _data_len+Reticulum::DESTINATION_LENGTH+1); return hashable_part; } + +// Generates a special destination that allows Reticulum +// to direct the proof back to the proved packet's sender +//ProofDestination &Packet::generate_proof_destination() { +// return ProofDestination(); +//} + diff --git a/src/Packet.h b/src/Packet.h index ff3bdd0..cf80452 100644 --- a/src/Packet.h +++ b/src/Packet.h @@ -14,6 +14,7 @@ namespace RNS { class Packet; class PacketProof; + class ProofDestination; class PacketReceipt; class PacketReceiptCallbacks; @@ -84,7 +85,9 @@ namespace RNS { uint8_t EMPTY_DESTINATION[Reticulum::DESTINATION_LENGTH] = {0}; public: - Packet(const Destination &destination, const Bytes &data, types packet_type = DATA, context_types context = CONTEXT_NONE, Transport::types transport_type = Transport::BROADCAST, header_types header_type = HEADER_1, const uint8_t *transport_id = nullptr, Interface *attached_interface = nullptr, bool create_receipt = true); + Packet(const Destination &destination, const Interface &attached_interface, const Bytes &data, types packet_type = DATA, context_types context = CONTEXT_NONE, Transport::types transport_type = Transport::BROADCAST, header_types header_type = HEADER_1, const uint8_t *transport_id = nullptr, bool create_receipt = true); + Packet(const Destination &destination, const Bytes &data, types packet_type = DATA, context_types context = CONTEXT_NONE, Transport::types transport_type = Transport::BROADCAST, header_types header_type = HEADER_1, const uint8_t *transport_id = nullptr, bool create_receipt = true) : Packet(destination, Interface::NONE, data, DATA, CONTEXT_NONE, Transport::BROADCAST, HEADER_1, nullptr, create_receipt) { + } Packet(NoneConstructor none) { extreme("Packet NONE object created"); } @@ -110,16 +113,6 @@ namespace RNS { void setData(const uint8_t* rata, uint16_t len); */ - private: - class Object { - public: - Object(const Destination &destination) : _destination(destination) {} - private: - Destination _destination; - friend class Packet; - }; - std::shared_ptr _object; - public: uint8_t get_packed_flags(); void pack(); @@ -130,8 +123,12 @@ namespace RNS { Bytes get_hash(); Bytes getTruncatedHash(); Bytes get_hashable_part(); + //zProofDestination &generate_proof_destination(); - private: + // getters/setters + inline const Interface& receiving_interface() const { assert(_object); return _object->_receiving_interface; } + + public: types _packet_type; header_types _header_type; context_types _context; @@ -151,9 +148,6 @@ namespace RNS { uint16_t _mtu = Reticulum::MTU; time_t _sent_at = 0; - Interface *_attached_interface = nullptr; - Interface *_receiving_interface = nullptr; - float _rssi = 0.0; float _snr = 0.0; @@ -166,6 +160,21 @@ namespace RNS { uint8_t _header[Reticulum::HEADER_MAXSIZE]; uint8_t *_data = _raw + Reticulum::HEADER_MAXSIZE; uint16_t _data_len = 0; + + private: + class Object { + public: + Object(const Destination &destination, const Interface &attached_interface) : _destination(destination), _attached_interface(attached_interface) {} + private: + + Destination _destination; + + Interface _attached_interface; + Interface _receiving_interface; + + friend class Packet; + }; + std::shared_ptr _object; }; diff --git a/src/Reticulum.cpp b/src/Reticulum.cpp index 28f4c61..a2399de 100644 --- a/src/Reticulum.cpp +++ b/src/Reticulum.cpp @@ -18,6 +18,15 @@ Reticulum::~Reticulum() { extreme("Reticulum object destroyed"); } +/* +Returns whether proofs sent are explicit or implicit. + +:returns: True if the current running configuration specifies to use implicit proofs. False if not. +*/ +/*static*/ bool Reticulum::should_use_implicit_proof() { + return __use_implicit_proof; +} + void Reticulum::loop() { // Perform random number gnerator housekeeping RNG.loop(); diff --git a/src/Reticulum.h b/src/Reticulum.h index f8aed51..074eb44 100644 --- a/src/Reticulum.h +++ b/src/Reticulum.h @@ -10,12 +10,6 @@ namespace RNS { class Reticulum { - private: - class Object { - private: - friend class Reticulum; - }; - public: enum NoneConstructor { NONE @@ -85,6 +79,12 @@ namespace RNS { static const uint8_t DESTINATION_LENGTH = TRUNCATED_HASHLENGTH/8; // In bytes + static const bool __transport_enabled = false; + static const bool __use_implicit_proof = true; + static const bool __allow_probes = false; + + static const bool panic_on_interface_error = false; + public: Reticulum(); Reticulum(NoneConstructor none) { @@ -105,9 +105,14 @@ namespace RNS { } public: + static bool should_use_implicit_proof(); void loop(); private: + class Object { + private: + friend class Reticulum; + }; std::shared_ptr _object; }; diff --git a/src/Test/Test.cpp b/src/Test/Test.cpp index ac05c4a..9858bf9 100644 --- a/src/Test/Test.cpp +++ b/src/Test/Test.cpp @@ -10,7 +10,6 @@ void test() { testMap(); testBytes(); testCowBytes(); - testObjects(); testBytesConversion(); testReference(); diff --git a/src/Test/Test.h b/src/Test/Test.h index 6016dd8..dc209b2 100644 --- a/src/Test/Test.h +++ b/src/Test/Test.h @@ -6,8 +6,6 @@ void testBytes(); void testCowBytes(); void testBytesConversion(); -void testObjects(); - void testReference(); void testCrypto(); diff --git a/src/Test/TestBytes.cpp b/src/Test/TestBytes.cpp index 9c92921..779a8af 100644 --- a/src/Test/TestBytes.cpp +++ b/src/Test/TestBytes.cpp @@ -105,6 +105,56 @@ void testBytes() { assert(bytes.size() == 11); assert(memcmp(bytes.data(), "Hello World", bytes.size()) == 0); + // test left in range + { + RNS::Bytes left(bytes.left(5)); + RNS::extreme("left: " + left.toString()); + assert(left.size() == 5); + assert(memcmp(left.data(), "Hello", left.size()) == 0); + } + // test left oob + { + RNS::Bytes left(bytes.left(20)); + RNS::extreme("oob left: " + left.toString()); + assert(left.size() == 11); + assert(memcmp(left.data(), "Hello World", left.size()) == 0); + } + // test right in range + { + RNS::Bytes right(bytes.right(5)); + RNS::extreme("right: " + right.toString()); + assert(right.size() == 5); + assert(memcmp(right.data(), "World", right.size()) == 0); + } + // test right oob + { + RNS::Bytes right(bytes.right(20)); + RNS::extreme("oob right: " + right.toString()); + assert(right.size() == 11); + assert(memcmp(right.data(), "Hello World", right.size()) == 0); + } + // test mid in range + { + RNS::Bytes mid(bytes.mid(3, 5)); + RNS::extreme("mid: " + mid.toString()); + assert(mid.size() == 5); + assert(memcmp(mid.data(), "lo Wo", mid.size()) == 0); + } + // test mid oob pos + { + RNS::Bytes mid(bytes.mid(20, 5)); + RNS::extreme("oob pos mid: " + mid.toString()); + assert(!mid); + assert(mid.size() == 0); + } + // test mid oob pos + { + RNS::Bytes mid(bytes.mid(3, 20)); + RNS::extreme("oob len mid: " + mid.toString()); + assert(mid.size() == 8); + assert(memcmp(mid.data(), "lo World", mid.size()) == 0); + } + // stream into empty bytes { RNS::Bytes strmbuf; diff --git a/src/Test/TestCrypto.cpp b/src/Test/TestCrypto.cpp index 14ff92b..7589f37 100644 --- a/src/Test/TestCrypto.cpp +++ b/src/Test/TestCrypto.cpp @@ -25,7 +25,7 @@ void testCrypto() { int main(void) { UNITY_BEGIN(); - RUN_TEST(testObjects); + RUN_TEST(testCrypto); return UNITY_END(); } */ diff --git a/src/Test/TestReference.cpp b/src/Test/TestReference.cpp index 3e91cb4..0d840b0 100644 --- a/src/Test/TestReference.cpp +++ b/src/Test/TestReference.cpp @@ -23,7 +23,7 @@ void testReference() { int main(void) { UNITY_BEGIN(); - RUN_TEST(testObjects); + RUN_TEST(testReference); return UNITY_END(); } */ diff --git a/src/Transport.cpp b/src/Transport.cpp index 1304e5f..23681d0 100644 --- a/src/Transport.cpp +++ b/src/Transport.cpp @@ -38,6 +38,6 @@ Transport::~Transport() { } /*static*/ bool Transport::outbound(const Packet &packet) { - // mock + // MOCK return true; } diff --git a/src/main.cpp b/src/main.cpp index c45227c..42d4a5c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -39,45 +39,50 @@ void setup() { Serial.print("Hello from T-Beam on PlatformIO!\n"); #endif + try { + #ifndef NDEBUG - //RNS::loglevel(RNS::LOG_WARNING); - RNS::loglevel(RNS::LOG_EXTREME); - //test(); - testCrypto(); - return; + RNS::loglevel(RNS::LOG_WARNING); + //RNS::loglevel(RNS::LOG_EXTREME); + test(); #endif - //std::stringstream test; - // !!! just adding this single stringstream alone (not even using it) adds a whopping 17.1% !!! - // !!! JUST SAY NO TO STRINGSTREAM !!! + //std::stringstream test; + // !!! just adding this single stringstream alone (not even using it) adds a whopping 17.1% !!! + // !!! JUST SAY NO TO STRINGSTREAM !!! - RNS::loglevel(RNS::LOG_EXTREME); + RNS::loglevel(RNS::LOG_EXTREME); - // 18.5% completely empty program + // 18.5% completely empty program - // 21.8% baseline here with serial + // 21.8% baseline here with serial - RNS::Reticulum reticulum; - // 21.9% (+0.1%) + RNS::Reticulum reticulum; + // 21.9% (+0.1%) - RNS::Identity identity; - // 22.6% (+0.7%) + RNS::Identity identity; + // 22.6% (+0.7%) - RNS::Destination destination(identity, RNS::Destination::IN, RNS::Destination::SINGLE, "test", "context"); - // 23.0% (+0.4%) + RNS::Destination destination(identity, RNS::Destination::IN, RNS::Destination::SINGLE, "test", "context"); + // 23.0% (+0.4%) - //destination.announce(RNS::bytesFromString(fruits[rand() % 7])); - // test path - destination.announce(RNS::bytesFromString(fruits[rand() % 7]), true, nullptr, RNS::bytesFromString("test_tag")); - // 23.9% (+0.8%) + //destination.announce(RNS::bytesFromString(fruits[rand() % 7])); + // test path + destination.announce(RNS::bytesFromString(fruits[rand() % 7]), true, nullptr, RNS::bytesFromString("test_tag")); + // 23.9% (+0.8%) - //zdestination.set_proof_strategy(RNS::Destination::PROVE_ALL); + //zdestination.set_proof_strategy(RNS::Destination::PROVE_ALL); - //zannounce_handler = ExampleAnnounceHandler( - //z aspect_filter="example_utilities.announcesample.fruits"; - //z) + //zannounce_handler = ExampleAnnounceHandler( + //z aspect_filter="example_utilities.announcesample.fruits"; + //z) - //zRNS::Transport.register_announce_handler(announce_handler); + //zRNS::Transport.register_announce_handler(announce_handler); + + } + catch (std::exception& e) { + RNS::error(std::string("!!! Exception in main: ") + e.what() + " !!!"); + } #ifndef NATIVE Serial.print("Goodbye from T-Beam on PlatformIO!\n");