blob: 92a596a06a95707cd6922ea1dfa0e2039fe1c730 [file] [log] [blame]
#include "c_validator.h"
#include <cryptopp/cryptlib.h>
#include <cryptopp/files.h>
#include <cryptopp/hex.h>
#include <cryptopp/queue.h>
#include <cryptopp/sha3.h>
#include <cryptopp/xed25519.h>
#include <nlohmann/json.hpp>
#include <iostream>
void CValidator::printHex(std::string& str) {
std::byte bytes[str.length()];
std::memcpy(bytes, str.data(), str.length());
for (auto &b: bytes) {
std::cout << std::to_integer<int>(b) << ' ';
}
std::cout << std::endl;
}
std::string CValidator::CCFulfill(std::string& fulfillment) {
std::string decoded_str = base64_decode(base64_add_padding(fulfillment), false);
std::cout << decoded_str << std::endl;
printHex(decoded_str);
return decoded_str;
}
/*
* TODO: Use actual BER/DER decoding functions from a cryptographic library and
* replace hardcoded numbers with names of ASN1 bits
*
* Example string: pGSAIB4t58gi0CHneoXjs358ykJTwUWGZkWkBo7DLZV64c2KgUDoeWkz2-KrjDXh5ulHa2t-WiF5TT4RnBhqrcXJulJ135i_ipXmtJkLUrsGy884eRNb2_LE8RU2CMtRe4J-3IYM
*
* Fulfillment ::= CHOICE {
* ed25519Sha256 [0] Ed25519Sha512Fulfillment
* }
*
* Ed25519Sha512Fulfillment ::= SEQUENCE {
* publicKey OCTET STRING (SIZE(32)),
* signature OCTET STRING (SIZE(64))
* }
*/
std::unique_ptr<std::vector<std::string>> CValidator::DERDecode(std::string& uri_bytes_str) {
// 4 + 32 + 2 + 64
if (uri_bytes_str.length() != 102) return nullptr;
std::byte bytes[uri_bytes_str.length()];
std::memcpy(bytes, uri_bytes_str.data(), uri_bytes_str.length());
if (std::to_integer<int>(bytes[0]) != 164 ||
std::to_integer<int>(bytes[1]) != 100 ||
std::to_integer<int>(bytes[2]) != 128) {
return nullptr;
}
if (std::to_integer<int>(bytes[3]) != PUBLIC_KEY_LENGTH) return nullptr;
std::string public_key = uri_bytes_str.substr(4, 32);
printHex(public_key);
if (std::to_integer<int>(bytes[36]) != 129) return nullptr;
if (std::to_integer<int>(bytes[37]) != SIGNATURE_LENGTH) return nullptr;
std::string signature = uri_bytes_str.substr(38, 64);
printHex(signature);
std::unique_ptr<std::vector<std::string>> ptr(new std::vector<std::string>);
ptr->push_back(public_key);
ptr->push_back(signature);
return ptr;
}
/*
* TODO: Follow the steps according to
* https://perfect-sunstone-a3b.notion.site/NexRes-C-validation-369f5ad4ef074a1684dc227702a5c866
*/
std::string CValidator::ConstructURI(std::string &public_key, std::string &signature) {
// TODO: DER encode the fingerprint content object
// TODO: SHA256 hash the fingerprint content
// TODO: Generate the fingerprint from the hash
std::string fingerprint = "";
return "ni:///sha-256;" + fingerprint + "?fpt=" + "ed25519-sha-256" +
"&cost=" + std::to_string(ED25519_CRYPTOGRAPHY_COST);
}
/*
* TODO: Follow the steps according to
* https://perfect-sunstone-a3b.notion.site/NexRes-C-validation-369f5ad4ef074a1684dc227702a5c866
*/
bool CValidator::VerifyMessage(std::string &public_key, std::string &signature,
std::string &message) {
return true;
}
std::string CValidator::base64_add_padding(std::string data) {
// convert data to bytes
std::string encoded_data = data;
// char8_t* encoded_data = "";
int missing_padding = (4 - data.size() % 4) % 4;
std::cout << "missing padding: " << missing_padding << std::endl;
for (int i = 0; i < missing_padding; i++) {
encoded_data += u8"=";
}
return encoded_data;
}
std::string CValidator::base64_remove_padding(std::string data) {
int i = data.length() - 1;
while (i >= 0 && data[i] == '=') {
i--;
}
return data.substr(0, i+1);
}
std::string CValidator::CreateMessage(std::string& tx) {
rapidjson::Document doc;
doc.Parse(tx);
RemoveSignature(doc);
doc.AddMember("id", rapidjson::Value(), doc.GetAllocator());
rapidjson::StringBuffer buffer;
buffer.Clear();
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
doc.Accept(writer);
std::string json_str = buffer.GetString();
std::string serialized_str = SerializeMessage(json_str);
// std::cout << serialized_str << std::endl;
// sha3 256 encode the serialized json
CryptoPP::SHA3_256 hash;
hash.Update((const CryptoPP::byte*) serialized_str.data(), serialized_str.size());
// add encoded tx id it fulfills and its index to the sha 256 hash
std::string tail_str = "";
std::string tx_id = doc["inputs"][0]["fulfills"]["transaction_id"].GetString();
int output_index = doc["inputs"][0]["fulfills"]["output_index"].GetInt();
tail_str += tx_id;
tail_str += std::to_string(output_index);
hash.Update((const CryptoPP::byte*) tail_str.data(), tail_str.size());
std::string digest;
digest.resize(hash.DigestSize());
hash.Final((CryptoPP::byte*)&digest[0]);
std::cout << "Digest: ";
CryptoPP::HexEncoder encoder(new CryptoPP::FileSink(std::cout));
CryptoPP::StringSource(digest, true, new CryptoPP::Redirector(encoder));
std::cout << std::endl;
return digest;
}
std::string CValidator::SerializeMessage(std::string& tx) {
nlohmann::json j;
j = nlohmann::json::parse(tx); // sort keys
std::string str = j.dump(-1, ' ', false); // don't indent, don't ensure ascii
return str;
}
void CValidator::RemoveSignature(rapidjson::Document& doc) {
// assert(doc.HasMember("inputs"));
// assert(doc["inputs"].IsArray());
for (auto& inp : doc["inputs"].GetArray()) {
inp.AddMember("fulfillment", rapidjson::Value(), doc.GetAllocator());
}
}