WIP update

Implemented X25519.
This commit is contained in:
attermann 2023-10-07 15:03:21 -06:00
parent 1b919a9489
commit 4b062aa485
22 changed files with 490 additions and 165 deletions

View File

@ -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};
}

View File

@ -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;

View File

@ -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() {}

View File

@ -1,11 +1,12 @@
#include "Hashes.h"
#include "../Log.h"
#include "../Bytes.h"
#include <SHA256.h>
#include <SHA512.h>
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;
}

View File

@ -1,10 +1,12 @@
#pragma once
#include "../Bytes.h"
#include <stdint.h>
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);
} }

View File

@ -2,6 +2,8 @@
#include "Bytes.h"
#include <Curve25519.h>
#include <memory>
#include <stdint.h>
@ -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<X25519PublicKey>;
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<X25519PrivateKey>;
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;
};

View File

@ -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;
}

View File

@ -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 <string.h>
@ -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;
}
: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);
//zif (!destination) {
//z destination = packet.generate_proof_destination();
//z}
Packet proof(destination, packet.receiving_interface(), proof_data, RNS::Packet::PROOF);
proof.send();
}

View File

@ -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; }

View File

@ -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");
}

View File

@ -1,11 +1,18 @@
#pragma once
//#include <Arduino.h>
#include "../Log.h"
#include <memory>
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> _object;
};
}

View File

@ -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();
//}

View File

@ -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> _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> _object;
};

View File

@ -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();

View File

@ -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> _object;
};

View File

@ -10,7 +10,6 @@ void test() {
testMap();
testBytes();
testCowBytes();
testObjects();
testBytesConversion();
testReference();

View File

@ -6,8 +6,6 @@ void testBytes();
void testCowBytes();
void testBytesConversion();
void testObjects();
void testReference();
void testCrypto();

View File

@ -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;

View File

@ -25,7 +25,7 @@ void testCrypto() {
int main(void)
{
UNITY_BEGIN();
RUN_TEST(testObjects);
RUN_TEST(testCrypto);
return UNITY_END();
}
*/

View File

@ -23,7 +23,7 @@ void testReference() {
int main(void)
{
UNITY_BEGIN();
RUN_TEST(testObjects);
RUN_TEST(testReference);
return UNITY_END();
}
*/

View File

@ -38,6 +38,6 @@ Transport::~Transport() {
}
/*static*/ bool Transport::outbound(const Packet &packet) {
// mock
// MOCK
return true;
}

View File

@ -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");