Skip to content
This repository has been archived by the owner on Mar 3, 2020. It is now read-only.

Commit

Permalink
KEP-560 Daemon can get bluzelle public key from Solidity contract on …
Browse files Browse the repository at this point in the history
…Ethereum
  • Loading branch information
rnistuk committed Oct 2, 2018
1 parent c36bd95 commit 8084fca
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 7 deletions.
1 change: 1 addition & 0 deletions utils/blacklist.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ namespace {
const std::string ROPSTEN_URL{"https://ropsten.infura.io"};
}


namespace bzn::utils::blacklist
{
bool is_blacklisted(const bzn::uuid_t& uuid, const std::string& url = ROPSTEN_URL);
Expand Down
125 changes: 122 additions & 3 deletions utils/crypto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,19 @@
#include <iostream>
#include <memory>
#include <cstdio>
#include <curl/curl.h>
#include <boost/format.hpp>
#include <iomanip>

namespace
{
const std::string ROPSTEN_URL{"https://ropsten.infura.io"};
const std::string REQUEST_BASE {R"({"jsonrpc":"2.0","method":"eth_call","params":[{"to":"0x492CCD1eAeCDA0262e3AAeF8445F3F731a30AfbB","data": "%s" },"latest"],"id":1})"};
const std::string GET_KEY_SIZE {"0xcf5d53f1"};
const std::string GET_KEY_CHUNK {"0x96ce93e2"};
//const std::string REQUEST_CHUNK_DATA {R"({"jsonrpc":"2.0","method":"eth_call","params":[{"to":"0x492CCD1eAeCDA0262e3AAeF8445F3F731a30AfbB","data": "0x96ce93e2%s" },"latest"],"id":1})"};
//const std::string REQUEST_KEY_SIZE_DATA {R"({"jsonrpc":"2.0","method":"eth_call","params":[{"to":"0x492CCD1eAeCDA0262e3AAeF8445F3F731a30AfbB","data": "0xcf5d53f1" },"latest"],"id":1})"};

/**
* NOTE This is temporary
* We shall use this only until we can get the public key from an Etherium
Expand All @@ -63,8 +73,6 @@ namespace
};




/**
* This function is used by base_64_decode to determine the amount of memory required
* for the binary buffer represented by the base64 encoded string.
Expand Down Expand Up @@ -178,6 +186,104 @@ namespace
return false;
}
}


size_t
write_function(void* contents,size_t size, size_t nmemb, void* userp)
{
reinterpret_cast<std::string*>(userp)->append(reinterpret_cast<char*>(contents), size * nmemb);
return size * nmemb;
}


bzn::json_message
get_curl_response(const std::string& function_call, const std::string& url = ROPSTEN_URL)
{
const std::string MSG_ERROR_CURL{"curl_easy_perform() failed: "};
std::unique_ptr<CURL, std::function<void(CURL*)>> curl(curl_easy_init(),
std::bind(curl_easy_cleanup, std::placeholders::_1));
std::string readBuffer;

curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &readBuffer);

const std::string post_fields{boost::str(boost::format(REQUEST_BASE) % function_call)};

curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDS, post_fields.c_str());

curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDSIZE, -1L);
curl_easy_setopt(curl.get(), CURLOPT_URL, url.c_str());
curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, reinterpret_cast<void*>(write_function));

CURLcode res = curl_easy_perform(curl.get());
if (res != CURLE_OK)
{
throw (std::runtime_error(MSG_ERROR_CURL + curl_easy_strerror(res)));
}

bzn::json_message response;
Json::Reader reader;

if (!reader.parse(readBuffer, response))
{
LOG(error) << "Unable to parse response from Ropsten - could not get key size";
}
return response;
}


// curl --data '{"jsonrpc":"2.0","method":"eth_call","params":[{"to":"0x492CCD1eAeCDA0262e3AAeF8445F3F731a30AfbB","data": "0xcf5d53f1" },"latest"],"id":1}' https://ropsten.infura.io
size_t
get_public_pem_size(const std::string& url = ROPSTEN_URL)
{
const auto response = get_curl_response(GET_KEY_SIZE, url);
// result will look like "0x0000000000000000000000000000000000000000000000000000000000000012"
return std::stoul(response["result"].asString().c_str(), nullptr, 16) ;
}



std::string
integer_to_32_byte_hex(const size_t index)
{
std::stringstream stream;
stream << std::setfill ('0') << std::setw(32*2) << std::hex << index;
return stream.str();
}


//get_key_part(uint256)
//curl --data '{"jsonrpc":"2.0","method":"eth_call","params":[{"to":"0x492CCD1eAeCDA0262e3AAeF8445F3F731a30AfbB","data": "0x96ce93e2+_INDEX" },"latest"],"id":1}' https://ropsten.infura.io
std::string
get_public_pem_chunk(size_t index, const std::string& url = ROPSTEN_URL)
{
std::string function_call{GET_KEY_CHUNK};
function_call.append(integer_to_32_byte_hex(index));
const auto response = get_curl_response(function_call, url);
// need to clean up the response a bit, remove the prepended "0x"
return response["result"].asString().substr(2);
}


// TODO rename hex_string_to_string
std::string
hex_string_to_string(const std::string& hex_string)
{
std::string public_key{""};
for(size_t i=0 ; i < hex_string.size(); i+=2)
{
public_key += static_cast<unsigned char>(std::strtoul(hex_string.substr(i,2).c_str(), nullptr, 16));
}
std::stringstream ss;
for(size_t i=0 ; i < public_key.size(); ++i)
{
if( 0==i%64)
{
ss << '\n';
}
ss << public_key[i];
}
return ss.str();
}
}


Expand All @@ -186,8 +292,20 @@ namespace bzn::utils::crypto
std::string
retrieve_bluzelle_public_key_from_contract()
{
std::string public_key_hex{""};
// TODO retrieve the public key from the contract
return temporary_public_pem;
const size_t key_size = get_public_pem_size();

for (size_t index=0; index < key_size; ++index)
{
const auto line = get_public_pem_chunk(index);
public_key_hex += line;
}

std::string public_key{"-----BEGIN PUBLIC KEY-----"};
public_key.append(hex_string_to_string(public_key_hex));
public_key.append("\n-----END PUBLIC KEY-----");
return public_key;
}


Expand Down Expand Up @@ -258,6 +376,7 @@ namespace bzn::utils::crypto
return ret_val & authentic;
}


std::string read_pem_file(const std::string& filename, const std::string& expected_type)
{
char* name;
Expand Down
4 changes: 2 additions & 2 deletions utils/crypto.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ namespace bzn::utils::crypto
int base64_decode(const std::string& base64_message, std::vector<unsigned char>& decoded_message);



/**
* Retrieves the Bluzelle public key from the Etherium blockchain via a call
* to a contract
* @return a string containing the base64 Encoded Bluzelle public key
*/
std::string
retrieve_bluzelle_public_key_from_contract();
std::string retrieve_bluzelle_public_key_from_contract();


/**
Expand Down
28 changes: 26 additions & 2 deletions utils/test/utils_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,25 @@ namespace
"oz/SiKjCqdN93YdBO4FBF/cWD5WHmD7KaaJYmnztz3W+xS7b/qk2PcN+qpZEXsfr"
"Wie4prB1umESavYLC1pLhoEgc0jRUl1b9mHSY7E4puk="
};


const std::string temporary_public_pem
{
"-----BEGIN PUBLIC KEY-----\n"
"MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA3Delbh36s+NJCCOYi1ql\n"
"NGp+R5EoKWtcazi+Kh/t2V4kN4QCEQdxi3nlhbHdiWWNi8puwwJYFDRdjZvEO+2H\n"
"yEyFui4v9Rl/RoGdDQeXEeQ+QxMVvT6Ya7+unRDjlIuNmQNNe4HKlcA4fqhRqi07\n"
"bF2b1kceuPsxIXcBnrsVVqxvSvqjiVkaSnk+HACm8fjiTwGSFE3ZhooMgxENEWrw\n"
"Ltcr80UdWpMvCrlBCWtlxiLl8VgoPCDZ/R2iXvJaQAOwepfdFGmcPomcO9BOEJfn\n"
"Jg4sBQNu4CqN5KRCS8CN39E705s4upFMRleU6nKHa0kSb9OsqJP/0i0fBVFLsxpX\n"
"WbR2iLwpCy3YqJqwoS8PFz9rr4V9ESqRJlczjkRt6bfx4/fSskxsXWRl+Dlv1V/P\n"
"Sl0zlJXMoxpPuLANxEVsnR9fT07h0XuQ58dsjbMImTL8Hmomfl3n2WK35TesAAaO\n"
"WNa4+2LFYzKwLUL9cRv696544eo8TCi+bXEKSCmUzpLsLIeHVmeHy3CiUUq13ktE\n"
"ykQD9vdtoyJkWJ4n5QMQVaV1k1hJ0V8EMfpV9mMEpItfQQRqDW1QG2fHbZgrUV1m\n"
"5PdnWwf3L9nMNxja7nX0vk5QVw1r8Kl4KqP4sid4djBYz4SBLeSfimUDw/USsKik\n"
"MwoaYGgrejBmlvZ5UiFw+xMCAwEAAQ==\n"
"-----END PUBLIC KEY-----"
};
}


Expand All @@ -298,7 +317,6 @@ TEST(util_test, test_that_is_whitelist_member_returns_FALSE_if_uuid_is_NOT_found
}



TEST(util_test, test_that_a_poorly_formed_uuid_fails)
{
EXPECT_THROW(bzn::utils::blacklist::is_blacklisted("0}56fcb3-ae1e-4b3e-b794-be3270cc9d43", "http://localhost:74858"), std::runtime_error);
Expand All @@ -322,9 +340,15 @@ TEST(util_test, test_that_a_uuid_can_be_validated)
}


TEST(util_test, test_that_verifying_asignature_with_empty_inputs_will_fail_gracefully)
TEST(util_test, test_that_verifying_a_signature_with_empty_inputs_will_fail_gracefully)
{
EXPECT_FALSE(bzn::utils::crypto::verify_signature( "", signature, valid_uuid));
EXPECT_FALSE(bzn::utils::crypto::verify_signature( public_pem, "", valid_uuid));
EXPECT_FALSE(bzn::utils::crypto::verify_signature( public_pem, signature, ""));
}


TEST(util_test, test_that_ethereum_will_provide_bluzel_public_key)
{
EXPECT_EQ(temporary_public_pem, bzn::utils::crypto::retrieve_bluzelle_public_key_from_contract());
}

0 comments on commit 8084fca

Please sign in to comment.