mirror of
https://github.com/liquidraver/ZephCore.git
synced 2026-10-15 10:49:54 +00:00
- Mesh, Dispatcher, Packet, packet pool and the core headers rebuilt from Arduino MeshCore's text; ZephCore changes re-applied, each fenced `// ZEPHCORE:` (diff vs upstream: 4540 -> 1147 lines) - upstream header layout; MainBoard gains handleCommand/loop and the other upstream members; RNG::nextInt back in Utils.cpp - packet logging moved to the roles' log hooks (helpers/PacketLog.h) - zero-hop direct ACKs deduplicated and length-checked as upstream - RadioIncludes.h -> src/, LoRaConfig.h -> helpers/ - .editorconfig: shared files keep upstream formatting Verified: 10 role builds, per-function disassembly review, bench DM/ACK regression (T1000-E, Wio L1, XIAO S3 on 1.17.4) incl. via live repeater.
125 lines
5.0 KiB
C++
125 lines
5.0 KiB
C++
#pragma once
|
|
|
|
#include <mesh/Utils.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
|
|
namespace mesh {
|
|
|
|
/**
|
|
* \brief An identity in the mesh, with given Ed25519 public key, ie. a party whose signatures can be VERIFIED.
|
|
*/
|
|
class Identity {
|
|
public:
|
|
uint8_t pub_key[PUB_KEY_SIZE];
|
|
|
|
Identity();
|
|
Identity(const char* pub_hex);
|
|
Identity(const uint8_t* _pub) { memcpy(pub_key, _pub, PUB_KEY_SIZE); }
|
|
|
|
int copyHashTo(uint8_t* dest) const {
|
|
memcpy(dest, pub_key, PATH_HASH_SIZE); // hash is just prefix of pub_key
|
|
return PATH_HASH_SIZE;
|
|
}
|
|
int copyHashTo(uint8_t* dest, uint8_t len) const {
|
|
memcpy(dest, pub_key, len); // hash is just prefix of pub_key
|
|
return len;
|
|
}
|
|
bool isHashMatch(const uint8_t* hash) const {
|
|
return memcmp(hash, pub_key, PATH_HASH_SIZE) == 0;
|
|
}
|
|
bool isHashMatch(const uint8_t* hash, uint8_t len) const {
|
|
return memcmp(hash, pub_key, len) == 0;
|
|
}
|
|
|
|
/**
|
|
* \brief Performs Ed25519 signature verification.
|
|
* \param sig IN - must be SIGNATURE_SIZE buffer.
|
|
* \param message IN - the original message which was signed.
|
|
* \param msg_len IN - the length in bytes of message.
|
|
* \returns true, if signature is valid.
|
|
*/
|
|
bool verify(const uint8_t* sig, const uint8_t* message, int msg_len) const;
|
|
|
|
bool matches(const Identity& other) const { return memcmp(pub_key, other.pub_key, PUB_KEY_SIZE) == 0; }
|
|
bool matches(const uint8_t* other_pubkey) const { return memcmp(pub_key, other_pubkey, PUB_KEY_SIZE) == 0; }
|
|
|
|
// ZEPHCORE: buffer I/O instead of Arduino Stream (readFrom/writeTo/printTo).
|
|
bool readFrom(const uint8_t* src, size_t len);
|
|
bool writeTo(uint8_t* dest, size_t max_len) const;
|
|
};
|
|
|
|
/**
|
|
* \brief An Identity generated on THIS device, ie. with public/private Ed25519 key pair being on this device.
|
|
*/
|
|
class LocalIdentity : public Identity {
|
|
uint8_t prv_key[PRV_KEY_SIZE];
|
|
public:
|
|
LocalIdentity();
|
|
LocalIdentity(const char* prv_hex, const char* pub_hex);
|
|
LocalIdentity(RNG* rng); // create new random
|
|
|
|
// ZEPHCORE: derive the Ed25519 key pair from a 32-byte seed produced
|
|
// externally (ZephyrRNG::mixIdentitySeed), instead of through an RNG wrapper.
|
|
void fromSeed(const uint8_t seed[SEED_SIZE]);
|
|
|
|
/**
|
|
* \brief Ed25519 digital signature.
|
|
* \param sig OUT - must be SIGNATURE_SIZE buffer.
|
|
* \param message IN - the raw message bytes to sign.
|
|
* \param msg_len IN - the length in bytes of message.
|
|
*/
|
|
void sign(uint8_t* sig, const uint8_t* message, int msg_len) const;
|
|
|
|
/**
|
|
* \brief the ECDH key exhange, with Ed25519 public key transposed to Ex25519.
|
|
* \param secret OUT - the 'shared secret' (must be PUB_KEY_SIZE bytes)
|
|
* \param other IN - the second party in the exchange.
|
|
*/
|
|
void calcSharedSecret(uint8_t* secret, const Identity& other) const { calcSharedSecret(secret, other.pub_key); }
|
|
|
|
/**
|
|
* \brief the ECDH key exhange, with Ed25519 public key transposed to Ex25519.
|
|
* \param secret OUT - the 'shared secret' (must be PUB_KEY_SIZE bytes)
|
|
* \param other_pub_key IN - the public key of second party in the exchange (must be PUB_KEY_SIZE bytes)
|
|
*/
|
|
void calcSharedSecret(uint8_t* secret, const uint8_t* other_pub_key) const;
|
|
|
|
/**
|
|
* \brief Validates that a given private key can be used for ECDH / shared-secret operations.
|
|
* \param prv IN - the private key to validate (must be PRV_KEY_SIZE bytes)
|
|
* \returns true, if the private key is valid for login.
|
|
*/
|
|
static bool validatePrivateKey(const uint8_t prv[64]);
|
|
|
|
// ZEPHCORE: no Arduino Stream I/O. The buffer format below (prv || pub, or prv
|
|
// alone) is protocol-facing — CMD_EXPORT/IMPORT_PRIVATE_KEY and the `prv.key`
|
|
// CLI — and stays byte-identical to upstream. Never use it for flash storage.
|
|
bool readFrom(const uint8_t* src, size_t len);
|
|
size_t writeTo(uint8_t* dest, size_t max_len) const;
|
|
|
|
// ZEPHCORE: on-flash format pub || prv, matching upstream's IdentityStore
|
|
// (LocalIdentity::writeTo(Stream&)). Kept apart from the buffer format because
|
|
// the two orders differ, and conflating them is how a node ends up advertising
|
|
// a key it cannot sign for.
|
|
size_t writeToStorage(uint8_t* dest, size_t max_len) const;
|
|
|
|
// Tolerant reader for every layout either project has written, told apart by
|
|
// deriving pub from the candidate prv (the stored pub is a checksum of it):
|
|
// len == 64 -> prv only (ZephCore repeater/room <= 1.17.x)
|
|
// len == 96 -> pub || prv (Arduino MeshCore, ZephCore >= 1.17.2)
|
|
// len == 96 -> prv || pub (ZephCore companion <= 1.17.x)
|
|
// pub_key is always the derived value. False when no layout coheres.
|
|
bool readFromStorage(const uint8_t* src, size_t len);
|
|
|
|
// Last resort after readFromStorage() fails: adopt one half of a 96-byte blob
|
|
// if exactly one half passes validatePrivateKey() (ambiguity = refuse). RAM
|
|
// only; the file is left alone so the evidence survives and the warning
|
|
// repeats every boot. Changes the advertised pub_key to the one the private
|
|
// key actually owns.
|
|
bool recoverFromStorage(const uint8_t* src, size_t len);
|
|
};
|
|
|
|
}
|
|
|