Skip to content

Commit

Permalink
Add attestation to REG
Browse files Browse the repository at this point in the history
  • Loading branch information
roshanr95 committed Jan 2, 2021
1 parent f1e1722 commit d5110e0
Showing 1 changed file with 139 additions and 12 deletions.
151 changes: 139 additions & 12 deletions beacon/include/marlin/beacon/DiscoveryServer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
#include <boost/iterator/filter_iterator.hpp>
#include <boost/iterator/transform_iterator.hpp>

#include <secp256k1_recovery.h>
#include <cryptopp/keccak.h>
#include <cryptopp/osrng.h>

#include <spdlog/fmt/bin_to_hex.h>

#include "Messages.hpp"
Expand All @@ -23,6 +27,12 @@
namespace marlin {
namespace beacon {

struct PeerInfo {
uint64_t last_seen;
std::array<uint8_t, 32> key;
std::array<uint8_t, 20> address;
};

//! Class implementing the server side node discovery functionality
/*!
Features:
Expand Down Expand Up @@ -57,17 +67,21 @@ class DiscoveryServer {
void send_LISTPEER(BaseTransport &transport);

void did_recv_HEARTBEAT(BaseTransport &transport, HEARTBEAT &&bytes);
void did_recv_REG(BaseTransport &transport);
void did_recv_REG(BaseTransport &transport, BaseMessageType&& packet);

void heartbeat_timer_cb();
asyncio::Timer heartbeat_timer;

void did_recv_DISCCLUSTER(BaseTransport &transport);
void send_LISTCLUSTER(BaseTransport &transport);

std::unordered_map<core::SocketAddress, std::pair<uint64_t, std::array<uint8_t, 32>>> peers;
std::unordered_map<core::SocketAddress, PeerInfo> peers;

BaseTransport* rt = nullptr;

secp256k1_context* ctx_signer = nullptr;
secp256k1_context* ctx_verifier = nullptr;
uint8_t key[32];
public:
// Listen delegate
bool should_accept(core::SocketAddress const &addr);
Expand All @@ -78,7 +92,12 @@ class DiscoveryServer {
void did_recv(BaseTransport &transport, BaseMessageType &&packet);
void did_send(BaseTransport &transport, core::Buffer &&packet);

DiscoveryServer(core::SocketAddress const& baddr, core::SocketAddress const& haddr, std::optional<core::SocketAddress> raddr = std::nullopt);
DiscoveryServer(
core::SocketAddress const& baddr,
core::SocketAddress const& haddr,
std::optional<core::SocketAddress> raddr = std::nullopt,
std::string key = ""
);

DiscoveryServerDelegate *delegate;
};
Expand Down Expand Up @@ -137,7 +156,7 @@ void DiscoveryServer<DiscoveryServerDelegate>::send_LISTPEER(
auto f_end = boost::make_filter_iterator(filter, peers.end(), peers.end());

// Extract data into pair<addr, key> format
auto transformation = [](auto x) { return std::make_pair(x.first, x.second.second); };
auto transformation = [](auto x) { return std::make_pair(x.first, x.second.key); };
auto t_begin = boost::make_transform_iterator(f_begin, transformation);
auto t_end = boost::make_transform_iterator(f_end, transformation);

Expand Down Expand Up @@ -170,13 +189,14 @@ void DiscoveryServer<DiscoveryServerDelegate>::did_recv_HEARTBEAT(
return;
}

peers[transport.dst_addr].first = asyncio::EventLoop::now();
peers[transport.dst_addr].second = bytes.key_array();
peers[transport.dst_addr].last_seen = asyncio::EventLoop::now();
peers[transport.dst_addr].key = bytes.key_array();
}

template<typename DiscoveryServerDelegate>
void DiscoveryServer<DiscoveryServerDelegate>::did_recv_REG(
BaseTransport &transport
BaseTransport &transport,
BaseMessageType &&packet
) {
SPDLOG_INFO(
"REG <<< {}",
Expand All @@ -193,7 +213,65 @@ void DiscoveryServer<DiscoveryServerDelegate>::did_recv_REG(
transport.dst_addr.to_string()
);

peers[transport.dst_addr].first = asyncio::EventLoop::now();
auto payload = packet.payload_buffer();
if(payload.size() > 73) {
auto cur_time = (uint64_t)std::time(nullptr);
auto p_time = payload.read_uint64_le_unsafe(1);

if(cur_time - p_time > 60 && p_time - cur_time > 60) {
// Too old or too in future
return;
}

uint8_t hash[32];
CryptoPP::Keccak_256 hasher;
// Hash message
hasher.CalculateTruncatedDigest(hash, 32, payload.data()+1, 8);

secp256k1_ecdsa_recoverable_signature sig;
// Parse signature
secp256k1_ecdsa_recoverable_signature_parse_compact(
ctx_verifier,
&sig,
payload.data()+9,
payload.data()[73]
);

// Verify signature
secp256k1_pubkey pubkey;
{
auto res = secp256k1_ecdsa_recover(
ctx_verifier,
&pubkey,
&sig,
hash
);

if(res == 0) {
// Recovery failed
return;
}
}

uint8_t pubkeyser[65];
size_t len = 65;
secp256k1_ec_pubkey_serialize(
ctx_verifier,
pubkeyser,
&len,
&pubkey,
SECP256K1_EC_UNCOMPRESSED
);

// Get address
hasher.CalculateTruncatedDigest(hash, 32, pubkeyser+1, 64);
// address is in hash[12..31]

SPDLOG_INFO("Address: {:spn}", spdlog::to_hex(hash+12, hash+32));
std::memcpy(peers[transport.dst_addr].address.data(), hash+12, 20);
}

peers[transport.dst_addr].last_seen = asyncio::EventLoop::now();
}


Expand All @@ -207,18 +285,54 @@ void DiscoveryServer<DiscoveryServerDelegate>::heartbeat_timer_cb() {
auto iter = peers.begin();
while(iter != peers.end()) {
// Remove stale peers if inactive for a minute
if(now - iter->second.first > 60000) {
if(now - iter->second.last_seen > 60000) {
iter = peers.erase(iter);
} else {
iter++;
}
}

if(rt != nullptr) {
auto time = (uint64_t)std::time(nullptr);
SPDLOG_INFO("REG >>> {}", rt->dst_addr.to_string());
BaseMessageType m(1);
BaseMessageType m(74);
auto reg = m.payload_buffer();
reg.data()[0] = 7;
reg.write_uint64_le_unsafe(1, time);

uint8_t hash[32];
CryptoPP::Keccak_256 hasher;
// Hash message
hasher.CalculateTruncatedDigest(hash, 32, reg.data()+1, 8);

// Sign
secp256k1_ecdsa_recoverable_signature sig;
auto res = secp256k1_ecdsa_sign_recoverable(
ctx_signer,
&sig,
hash,
key,
nullptr,
nullptr
);

if(res == 0) {
// Sign failed
SPDLOG_ERROR("Beacon: Failed to send REG: signature failure");
return;
}

// Output
int recid;
secp256k1_ecdsa_recoverable_signature_serialize_compact(
ctx_signer,
reg.data()+9,
&recid,
&sig
);

reg.data()[73] = (uint8_t)recid;

rt->send(std::move(m));
}
}
Expand Down Expand Up @@ -326,7 +440,7 @@ void DiscoveryServer<DiscoveryServerDelegate>::did_recv(
case 4: did_recv_HEARTBEAT(transport, std::move(packet));
break;
// HEARTBEAT
case 7: did_recv_REG(transport);
case 7: did_recv_REG(transport, std::move(packet));
break;
// DISCCLUSTER
case 9: did_recv_DISCCLUSTER(transport);
Expand Down Expand Up @@ -384,7 +498,8 @@ template<typename DiscoveryServerDelegate>
DiscoveryServer<DiscoveryServerDelegate>::DiscoveryServer(
core::SocketAddress const& baddr,
core::SocketAddress const& haddr,
std::optional<core::SocketAddress> raddr
std::optional<core::SocketAddress> raddr,
std::string key
) : heartbeat_timer(this) {
f.bind(baddr);
f.listen(*this);
Expand All @@ -394,6 +509,18 @@ DiscoveryServer<DiscoveryServerDelegate>::DiscoveryServer(

heartbeat_timer.template start<Self, &Self::heartbeat_timer_cb>(0, 10000);

ctx_signer = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
ctx_verifier = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
if(key.size() == 32) {
if(secp256k1_ec_seckey_verify(ctx_verifier, (uint8_t*)key.c_str()) != 1) {
SPDLOG_ERROR("Beacon: failed to verify key", key.size());
}
std::memcpy(this->key, key.c_str(), 32);
SPDLOG_INFO("Key: {}", spdlog::to_hex(this->key, this->key+32));
} else {
SPDLOG_ERROR("Beacon: failed to load key: {}", key.size());
}

if(raddr.has_value()) {
f.dial(*raddr, *this);
}
Expand Down

0 comments on commit d5110e0

Please sign in to comment.