iw4x-client/src/Components/Modules/Node.cpp

897 lines
25 KiB
C++
Raw Normal View History

2016-07-11 11:14:58 -04:00
#include "STDInclude.hpp"
namespace Components
{
Utils::Cryptography::ECC::Key Node::SignatureKey;
std::vector<Node::NodeEntry> Node::Nodes;
std::vector<Node::ClientSession> Node::Sessions;
void Node::LoadNodePreset()
{
FileSystem::File defaultNodes("nodes_default.dat");
if (!defaultNodes.Exists()) return;
auto buffer = defaultNodes.GetBuffer();
Utils::String::Replace(buffer, "\r", "");
auto nodes = Utils::String::Explode(buffer, '\n');
for (auto node : nodes)
{
if (!node.empty())
{
Node::AddNode(node);
}
}
}
void Node::LoadNodes()
{
Proto::Node::List list;
std::string nodes = Utils::IO::ReadFile("players/nodes.dat");
if (nodes.empty() || !list.ParseFromString(nodes)) return;
for (int i = 0; i < list.address_size(); ++i)
{
Node::AddNode(list.address(i));
}
}
void Node::StoreNodes(bool force)
{
if (Dedicated::IsEnabled() && Dvar::Var("sv_lanOnly").Get<bool>()) return;
2016-07-11 11:14:58 -04:00
static int lastStorage = 0;
// Don't store nodes if the delta is too small and were not forcing it
if (((Game::Sys_Milliseconds() - lastStorage) < NODE_STORE_INTERVAL && !force) || !Node::GetValidNodeCount()) return;
lastStorage = Game::Sys_Milliseconds();
Proto::Node::List list;
// This is obsolete when storing to file.
// However, defining another proto message due to this would be redundant.
//list.set_is_dedi(Dedicated::IsDedicated());
for (auto node : Node::Nodes)
{
if (node.state == Node::STATE_VALID && node.registered)
{
node.address.Serialize(list.add_address());
}
}
CreateDirectoryW(L"players", NULL);
Utils::IO::WriteFile("players/nodes.dat", list.SerializeAsString());
}
Node::NodeEntry* Node::FindNode(Network::Address address)
{
for (auto i = Node::Nodes.begin(); i != Node::Nodes.end(); ++i)
{
if (i->address == address)
{
return &(*i);
}
}
return nullptr;
}
Node::ClientSession* Node::FindSession(Network::Address address)
{
for (auto i = Node::Sessions.begin(); i != Node::Sessions.end(); ++i)
{
if (i->address == address)
{
return &(*i);
}
}
return nullptr;
}
unsigned int Node::GetValidNodeCount()
{
unsigned int count = 0;
for (auto node : Node::Nodes)
{
if (node.state == Node::STATE_VALID)
{
++count;
}
}
return count;
}
void Node::AddNode(Network::Address address)
{
#ifdef DEBUG
if (!address.IsValid() || address.IsSelf()) return;
#else
if (!address.IsValid() || address.IsLocal() || address.IsSelf()) return;
#endif
Node::NodeEntry* existingEntry = Node::FindNode(address);
if (existingEntry)
{
existingEntry->lastHeard = Game::Sys_Milliseconds();
}
else
{
Node::NodeEntry entry;
entry.lastHeard = Game::Sys_Milliseconds();
entry.lastTime = 0;
entry.lastListQuery = 0;
entry.registered = false;
entry.state = Node::STATE_UNKNOWN;
entry.address = address;
entry.challenge.clear();
Node::Nodes.push_back(entry);
#ifdef DEBUG
Logger::Print("Adding node %s...\n", address.GetCString());
#endif
}
}
void Node::SendNodeList(Network::Address address)
{
if (address.IsSelf()) return;
Proto::Node::List list;
list.set_is_dedi(Dedicated::IsEnabled());
2016-07-11 11:14:58 -04:00
list.set_protocol(PROTOCOL);
list.set_version(NODE_VERSION);
for (auto node : Node::Nodes)
{
if (node.state == Node::STATE_VALID && node.registered)
{
node.address.Serialize(list.add_address());
}
if (list.address_size() >= NODE_PACKET_LIMIT)
{
Network::SendCommand(address, "nodeListResponse", list.SerializeAsString());
list.clear_address();
}
}
// Even if we send an empty list, we have to tell the client about our dedi-status
// If the amount of servers we have modulo the NODE_PACKET_LIMIT equals 0, we will send this request without any servers, so it's obsolete, but meh...
Network::SendCommand(address, "nodeListResponse", list.SerializeAsString());
}
void Node::DeleteInvalidSessions()
{
for (auto i = Node::Sessions.begin(); i != Node::Sessions.end();)
{
if (i->lastTime <= 0 || (Game::Sys_Milliseconds() - i->lastTime) > SESSION_TIMEOUT)
{
i = Node::Sessions.erase(i);
}
else
{
++i;
}
}
}
void Node::DeleteInvalidNodes()
{
std::vector<Node::NodeEntry> cleanNodes;
for (auto node : Node::Nodes)
{
if (node.state == Node::STATE_INVALID && (Game::Sys_Milliseconds() - node.lastHeard) > NODE_INVALID_DELETE)
{
Logger::Print("Removing invalid node %s\n", node.address.GetCString());
}
else
{
cleanNodes.push_back(node);
}
}
if (cleanNodes.size() != Node::Nodes.size())
{
//Node::Nodes.clear();
//Utils::Merge(&Node::Nodes, cleanNodes);
Node::Nodes = cleanNodes;
}
}
void Node::SyncNodeList()
{
for (auto& node : Node::Nodes)
{
if (node.state == Node::STATE_VALID && node.registered)
{
node.state = Node::STATE_UNKNOWN;
node.registered = false;
}
}
}
void Node::PerformRegistration(Network::Address address)
{
Node::NodeEntry* entry = Node::FindNode(address);
if (!entry) return;
entry->lastTime = Game::Sys_Milliseconds();
if (Dedicated::IsEnabled())
2016-07-11 11:14:58 -04:00
{
entry->challenge = fmt::sprintf("%X", Utils::Cryptography::Rand::GenerateInt());
Proto::Node::Packet packet;
packet.set_challenge(entry->challenge);
#ifdef DEBUG
Logger::Print("Sending registration request to %s\n", entry->address.GetCString());
#endif
Network::SendCommand(entry->address, "nodeRegisterRequest", packet.SerializeAsString());
}
else
{
#ifdef DEBUG
Logger::Print("Sending session request to %s\n", entry->address.GetCString());
#endif
Network::SendCommand(entry->address, "sessionRequest");
}
}
void Node::FrameHandler()
{
if (Dedicated::IsEnabled() && Dvar::Var("sv_lanOnly").Get<bool>()) return;
2016-07-11 11:14:58 -04:00
// Frame limit
static int lastFrame = 0;
if ((Game::Sys_Milliseconds() - lastFrame) < (1000 / NODE_FRAME_LOCK) || Game::Sys_Milliseconds() < 5000) return;
lastFrame = Game::Sys_Milliseconds();
int registerCount = 0;
int listQueryCount = 0;
for (auto &node : Node::Nodes)
{
// TODO: Decide how to handle nodes that were already registered, but timed out re-registering.
if (node.state == STATE_NEGOTIATING && (Game::Sys_Milliseconds() - node.lastTime) > (NODE_QUERY_TIMEOUT))
{
node.registered = false; // Definitely unregister here!
node.state = Node::STATE_INVALID;
node.lastHeard = Game::Sys_Milliseconds();
node.lastTime = Game::Sys_Milliseconds();
Logger::Print("Node negotiation timed out. Invalidating %s\n", node.address.GetCString());
}
if (registerCount < NODE_FRAME_QUERY_LIMIT)
{
// Register when unregistered and in UNKNOWN state (I doubt it's possible to be unregistered and in VALID state)
if (!node.registered && (node.state != Node::STATE_NEGOTIATING && node.state != Node::STATE_INVALID))
{
++registerCount;
node.state = Node::STATE_NEGOTIATING;
Node::PerformRegistration(node.address);
}
// Requery invalid nodes within the NODE_QUERY_INTERVAL
// This is required, as a node might crash, which causes it to be invalid.
// If it's restarted though, we wouldn't query it again.
// But wouldn't it send a registration request to us?
// Not sure if the code below is necessary...
// Well, it might be possible that this node doesn't know use anymore. Anyways, just keep that code here...
// Nvm, this is required for clients, as nodes don't send registration requests to clients.
else if (node.state == STATE_INVALID && (Game::Sys_Milliseconds() - node.lastTime) > NODE_QUERY_INTERVAL)
{
++registerCount;
Node::PerformRegistration(node.address);
}
}
if (listQueryCount < NODE_FRAME_QUERY_LIMIT)
{
if (node.registered && node.state == Node::STATE_VALID && (!node.lastListQuery || (Game::Sys_Milliseconds() - node.lastListQuery) > NODE_QUERY_INTERVAL))
{
++listQueryCount;
node.state = Node::STATE_NEGOTIATING;
node.lastTime = Game::Sys_Milliseconds();
node.lastListQuery = Game::Sys_Milliseconds();
if (Dedicated::IsEnabled())
2016-07-11 11:14:58 -04:00
{
Network::SendCommand(node.address, "nodeListRequest");
}
else
{
Network::SendCommand(node.address, "sessionRequest");
}
}
}
}
static int lastCheck = 0;
if ((Game::Sys_Milliseconds() - lastCheck) < 1000) return;
lastCheck = Game::Sys_Milliseconds();
Node::DeleteInvalidSessions();
Node::DeleteInvalidNodes();
Node::StoreNodes(false);
}
const char* Node::GetStateName(EntryState state)
{
switch (state)
{
case Node::STATE_UNKNOWN:
return "Unknown";
case Node::STATE_NEGOTIATING:
return "Negotiating";
case Node::STATE_INVALID:
return "Invalid";
case Node::STATE_VALID:
return "Valid";
}
return "";
}
Node::Node()
{
Node::Nodes.clear();
// ZoneBuilder doesn't require node stuff
if (ZoneBuilder::IsEnabled()) return;
// Generate our ECDSA key
Node::SignatureKey = Utils::Cryptography::ECC::GenerateKey(512);
// Load stored nodes
Dvar::OnInit([] ()
{
Node::LoadNodePreset();
Node::LoadNodes();
});
// Send deadline when shutting down
if (Dedicated::IsEnabled())
2016-07-11 11:14:58 -04:00
{
QuickPatch::OnShutdown([] ()
{
if (Dvar::Var("sv_lanOnly").Get<bool>()) return;
std::string challenge = fmt::sprintf("%X", Utils::Cryptography::Rand::GenerateInt());
Proto::Node::Packet packet;
packet.set_challenge(challenge);
packet.set_signature(Utils::Cryptography::ECC::SignMessage(Node::SignatureKey, challenge));
for (auto node : Node::Nodes)
{
Network::SendCommand(node.address, "nodeDeregister", packet.SerializeAsString());
}
});
// This is the handler that accepts registration requests from other nodes
// If you want to get accepted as node, you have to send a request to this handler
Network::Handle("nodeRegisterRequest", [] (Network::Address address, std::string data)
{
if (Dvar::Var("sv_lanOnly").Get<bool>()) return;
Node::NodeEntry* entry = Node::FindNode(address);
// Create a new entry, if we don't already know it
if (!entry)
{
Node::AddNode(address);
entry = Node::FindNode(address);
if (!entry) return;
}
#ifdef DEBUG
Logger::Print("Received registration request from %s\n", address.GetCString());
#endif
Proto::Node::Packet packet;
if (!packet.ParseFromString(data)) return;
if (packet.challenge().empty()) return;
std::string signature = Utils::Cryptography::ECC::SignMessage(Node::SignatureKey, packet.challenge());
std::string challenge = fmt::sprintf("%X", Utils::Cryptography::Rand::GenerateInt());
// The challenge this client sent is exactly the challenge we stored for this client
// That means this is us, so we're going to ignore us :P
if (packet.challenge() == entry->challenge)
{
entry->lastHeard = Game::Sys_Milliseconds();
entry->lastTime = Game::Sys_Milliseconds();
entry->registered = false;
entry->state = Node::STATE_INVALID;
return;
}
packet.Clear();
packet.set_challenge(challenge);
packet.set_signature(signature);
packet.set_publickey(Node::SignatureKey.GetPublicKey());
entry->lastTime = Game::Sys_Milliseconds();
entry->challenge = challenge;
entry->state = Node::STATE_NEGOTIATING;
Network::SendCommand(address, "nodeRegisterSynchronize", packet.SerializeAsString());
});
Network::Handle("nodeRegisterSynchronize", [] (Network::Address address, std::string data)
{
if (Dvar::Var("sv_lanOnly").Get<bool>()) return;
Node::NodeEntry* entry = Node::FindNode(address);
if (!entry || entry->state != Node::STATE_NEGOTIATING) return;
#ifdef DEBUG
Logger::Print("Received synchronization data for registration from %s!\n", address.GetCString());
#endif
Proto::Node::Packet packet;
if (!packet.ParseFromString(data)) return;
if (packet.challenge().empty()) return;
if (packet.publickey().empty()) return;
if (packet.signature().empty()) return;
std::string challenge = packet.challenge();
std::string publicKey = packet.publickey();
std::string signature = packet.signature();
// Verify signature
entry->publicKey.Set(publicKey);
if (!Utils::Cryptography::ECC::VerifyMessage(entry->publicKey, entry->challenge, signature))
{
Logger::Print("Signature from %s for challenge '%s' is invalid!\n", address.GetCString(), entry->challenge.data());
return;
}
// Mark as registered
entry->lastTime = Game::Sys_Milliseconds();
entry->state = Node::STATE_VALID;
entry->registered = true;
#ifdef DEBUG
Logger::Print("Signature from %s for challenge '%s' is valid!\n", address.GetCString(), entry->challenge.data());
Logger::Print("Node %s registered\n", address.GetCString());
#endif
// Build response
publicKey = Node::SignatureKey.GetPublicKey();
signature = Utils::Cryptography::ECC::SignMessage(Node::SignatureKey, challenge);
packet.Clear();
packet.set_signature(signature);
packet.set_publickey(publicKey);
Network::SendCommand(address, "nodeRegisterAcknowledge", packet.SerializeAsString());
});
Network::Handle("nodeRegisterAcknowledge", [] (Network::Address address, std::string data)
{
if (Dvar::Var("sv_lanOnly").Get<bool>()) return;
// Ignore requests from nodes we don't know
Node::NodeEntry* entry = Node::FindNode(address);
if (!entry || entry->state != Node::STATE_NEGOTIATING) return;
#ifdef DEBUG
Logger::Print("Received acknowledgment from %s\n", address.GetCString());
#endif
Proto::Node::Packet packet;
if (!packet.ParseFromString(data)) return;
if (packet.signature().empty()) return;
if (packet.publickey().empty()) return;
std::string publicKey = packet.publickey();
std::string signature = packet.signature();
entry->publicKey.Set(publicKey);
if (Utils::Cryptography::ECC::VerifyMessage(entry->publicKey, entry->challenge, signature))
{
entry->lastTime = Game::Sys_Milliseconds();
entry->state = Node::STATE_VALID;
entry->registered = true;
#ifdef DEBUG
Logger::Print("Signature from %s for challenge '%s' is valid!\n", address.GetCString(), entry->challenge.data());
Logger::Print("Node %s registered\n", address.GetCString());
#endif
}
else
{
Logger::Print("Signature from %s for challenge '%s' is invalid!\n", address.GetCString(), entry->challenge.data());
}
});
Network::Handle("nodeListRequest", [] (Network::Address address, std::string data)
{
if (Dvar::Var("sv_lanOnly").Get<bool>()) return;
// Check if this is a registered node
bool allowed = false;
Node::NodeEntry* entry = Node::FindNode(address);
if (entry && entry->registered)
{
entry->lastTime = Game::Sys_Milliseconds();
allowed = true;
}
// Check if there is any open session
if (!allowed)
{
Node::ClientSession* session = Node::FindSession(address);
if (session)
{
session->lastTime = Game::Sys_Milliseconds();
allowed = session->valid;
}
}
if (allowed)
{
Node::SendNodeList(address);
}
else
{
// Unallowed connection
Logger::Print("Node list requested by %s, but no valid session was present!\n", address.GetCString());
Network::SendCommand(address, "nodeListError");
}
});
Network::Handle("nodeDeregister", [] (Network::Address address, std::string data)
{
if (Dvar::Var("sv_lanOnly").Get<bool>()) return;
Node::NodeEntry* entry = Node::FindNode(address);
if (!entry || !entry->registered) return;
Proto::Node::Packet packet;
if (!packet.ParseFromString(data)) return;
if (packet.challenge().empty()) return;
if (packet.signature().empty()) return;
std::string challenge = packet.challenge();
std::string signature = packet.signature();
if (Utils::Cryptography::ECC::VerifyMessage(entry->publicKey, challenge, signature))
{
entry->lastHeard = Game::Sys_Milliseconds();
entry->lastTime = Game::Sys_Milliseconds();
entry->registered = false;
entry->state = Node::STATE_INVALID;
#ifdef DEBUG
Logger::Print("Node %s unregistered\n", address.GetCString());
#endif
}
else
{
Logger::Print("Node %s tried to unregister using an invalid signature!\n", address.GetCString());
}
});
Network::Handle("sessionRequest", [] (Network::Address address, std::string data)
{
if (Dvar::Var("sv_lanOnly").Get<bool>()) return;
// Search an active session, if we haven't found one, register a template
if (!Node::FindSession(address))
{
Node::ClientSession templateSession;
templateSession.address = address;
Node::Sessions.push_back(templateSession);
}
// Search our target session (this should not fail!)
Node::ClientSession* session = Node::FindSession(address);
if (!session) return; // Registering template session failed, odd...
#ifdef DEBUG
Logger::Print("Client %s is requesting a new session\n", address.GetCString());
#endif
// Initialize session data
session->challenge = fmt::sprintf("%X", Utils::Cryptography::Rand::GenerateInt());
session->lastTime = Game::Sys_Milliseconds();
session->valid = false;
Network::SendCommand(address, "sessionInitialize", session->challenge);
});
Network::Handle("sessionSynchronize", [] (Network::Address address, std::string data)
{
if (Dvar::Var("sv_lanOnly").Get<bool>()) return;
// Return if we don't have a session for this address
Node::ClientSession* session = Node::FindSession(address);
if (!session || session->valid) return;
if (session->challenge == data)
{
#ifdef DEBUG
Logger::Print("Session for %s validated.\n", address.GetCString());
#endif
session->valid = true;
Network::SendCommand(address, "sessionAcknowledge");
}
else
{
session->lastTime = -1;
Logger::Print("Challenge mismatch. Validating session for %s failed.\n", address.GetCString());
}
});
}
else
{
Network::Handle("sessionInitialize", [] (Network::Address address, std::string data)
{
Node::NodeEntry* entry = Node::FindNode(address);
if (!entry) return;
#ifdef DEBUG
Logger::Print("Session initialization received from %s. Synchronizing...\n", address.GetCString());
#endif
entry->lastTime = Game::Sys_Milliseconds();
Network::SendCommand(address, "sessionSynchronize", data);
});
Network::Handle("sessionAcknowledge", [] (Network::Address address, std::string data)
{
Node::NodeEntry* entry = Node::FindNode(address);
if (!entry) return;
entry->state = Node::STATE_VALID;
entry->registered = true;
entry->lastTime = Game::Sys_Milliseconds();
#ifdef DEBUG
Logger::Print("Session acknowledged by %s, synchronizing node list...\n", address.GetCString());
#endif
Network::SendCommand(address, "nodeListRequest");
Node::SendNodeList(address);
});
}
Network::Handle("nodeListResponse", [] (Network::Address address, std::string data)
{
Proto::Node::List list;
if (data.empty() || !list.ParseFromString(data))
{
Logger::Print("Received invalid node list from %s!\n", address.GetCString());
return;
}
Node::NodeEntry* entry = Node::FindNode(address);
if (entry)
{
if (entry->registered)
{
Logger::Print("Received valid node list with %i entries from %s\n", list.address_size(), address.GetCString());
entry->isDedi = list.is_dedi();
entry->protocol = list.protocol();
entry->version = list.version();
entry->state = Node::STATE_VALID;
entry->lastTime = Game::Sys_Milliseconds();
if (!Dedicated::IsEnabled() && entry->isDedi && ServerList::IsOnlineList() && entry->protocol == PROTOCOL)
2016-07-11 11:14:58 -04:00
{
ServerList::InsertRequest(entry->address, true);
}
for (int i = 0; i < list.address_size(); ++i)
{
Network::Address _addr(list.address(i));
// Version 0 sends port in the wrong byte order!
if (entry->version == 0)
{
_addr.SetPort(ntohs(_addr.GetPort()));
}
// if (!Node::FindNode(_addr) && _addr.GetPort() >= 1024 && _addr.GetPort() - 20 < 1024)
// {
// std::string a1 = _addr.GetString();
// std::string a2 = address.GetString();
// Logger::Print("Received weird address %s from %s\n", a1.data(), a2.data());
// }
Node::AddNode(_addr);
}
}
}
else
{
//Node::AddNode(address);
Node::ClientSession* session = Node::FindSession(address);
if (session && session->valid)
{
session->lastTime = Game::Sys_Milliseconds();
for (int i = 0; i < list.address_size(); ++i)
{
Node::AddNode(list.address(i));
}
}
}
});
// If we receive that response, our request was not permitted
// So we either have to register as node, or register a remote session
Network::Handle("nodeListError", [] (Network::Address address, std::string data)
{
if (Dedicated::IsEnabled())
2016-07-11 11:14:58 -04:00
{
Node::NodeEntry* entry = Node::FindNode(address);
if (entry)
{
// Set to unregistered to perform registration later on
entry->lastTime = Game::Sys_Milliseconds();
entry->registered = false;
entry->state = Node::STATE_UNKNOWN;
}
else
{
// Add as new entry to perform registration
Node::AddNode(address);
}
}
else
{
// TODO: Implement client handshake stuff
// Nvm, clients can simply ignore that i guess
}
});
Command::Add("listnodes", [] (Command::Params params)
{
Logger::Print("Nodes: %d (%d)\n", Node::Nodes.size(), Node::GetValidNodeCount());
for (auto node : Node::Nodes)
{
Logger::Print("%s\t(%s)\n", node.address.GetCString(), Node::GetStateName(node.state));
}
});
Command::Add("addnode", [] (Command::Params params)
{
if (params.Length() < 2) return;
Network::Address address(params[1]);
Node::AddNode(address);
Node::NodeEntry* entry = Node::FindNode(address);
if (entry)
{
entry->state = Node::STATE_UNKNOWN;
entry->registered = false;
}
});
Command::Add("syncnodes", [] (Command::Params params)
{
Logger::Print("Re-Synchronizing nodes...\n");
for (auto& node : Node::Nodes)
{
node.state = Node::STATE_UNKNOWN;
node.registered = false;
node.lastTime = 0;
node.lastListQuery = 0;
}
});
// Install frame handlers
QuickPatch::OnFrame(Node::FrameHandler);
}
Node::~Node()
{
Node::SignatureKey.Free();
Node::StoreNodes(true);
Node::Nodes.clear();
Node::Sessions.clear();
}
bool Node::UnitTest()
{
printf("Testing ECDSA key...");
if (!Node::SignatureKey.IsValid())
{
printf("Error\n");
printf("ECDSA key seems invalid!\n");
return false;
}
printf("Success\n");
printf("Testing 10 valid signatures...");
for (int i = 0; i < 10; ++i)
{
std::string message = fmt::sprintf("%X", Utils::Cryptography::Rand::GenerateInt());
std::string signature = Utils::Cryptography::ECC::SignMessage(Node::SignatureKey, message);
if (!Utils::Cryptography::ECC::VerifyMessage(Node::SignatureKey, message, signature))
{
printf("Error\n");
printf("Signature for '%s' (%d) was invalid!\n", message.data(), i);
return false;
}
}
printf("Success\n");
printf("Testing 10 invalid signatures...");
for (int i = 0; i < 10; ++i)
{
std::string message = fmt::sprintf("%X", Utils::Cryptography::Rand::GenerateInt());
std::string signature = Utils::Cryptography::ECC::SignMessage(Node::SignatureKey, message);
// Invalidate the message...
++message[Utils::Cryptography::Rand::GenerateInt() % message.size()];
if (Utils::Cryptography::ECC::VerifyMessage(Node::SignatureKey, message, signature))
{
printf("Error\n");
printf("Signature for '%s' (%d) was valid? What the fuck? That is absolutely impossible...\n", message.data(), i);
return false;
}
}
printf("Success\n");
printf("Testing ECDSA key import...");
std::string pubKey = Node::SignatureKey.GetPublicKey();
std::string message = fmt::sprintf("%X", Utils::Cryptography::Rand::GenerateInt());
std::string signature = Utils::Cryptography::ECC::SignMessage(Node::SignatureKey, message);
Utils::Cryptography::ECC::Key testKey;
testKey.Set(pubKey);
if (!Utils::Cryptography::ECC::VerifyMessage(Node::SignatureKey, message, signature))
{
printf("Error\n");
printf("Verifying signature for message '%s' using imported keys failed!\n", message.data());
return false;
}
printf("Success\n");
uint32_t randIntCount = 4'000'000;
printf("Generating %d random integers...", randIntCount);
auto startTime = std::chrono::high_resolution_clock::now();
for (uint32_t i = 0; i < randIntCount; ++i)
{
Utils::Cryptography::Rand::GenerateInt();
}
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - startTime).count();
Logger::Print("took %llims\n", duration);
return true;
}
}