Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Add recover_key & assert_recover_key to rodeos #10456

Merged
merged 1 commit into from
Jun 25, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 68 additions & 2 deletions libraries/rodeos/include/b1/rodeos/callbacks/crypto.hpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
#pragma once

#include <b1/rodeos/callbacks/vm_types.hpp>
#include <eosio/chain/config.hpp>
#include <fc/crypto/public_key.hpp>
#include <fc/crypto/ripemd160.hpp>
#include <fc/crypto/sha1.hpp>
#include <fc/crypto/sha256.hpp>
#include <fc/crypto/sha512.hpp>
#include <fc/crypto/signature.hpp>
#include <fc/io/datastream.hpp>

namespace b1::rodeos {

Expand All @@ -15,8 +19,70 @@ struct crypto_callbacks {
throw std::runtime_error("wasm called " + std::string(name) + ", which is unimplemented");
}

void assert_recover_key(int, int, int, int, int) { return unimplemented<void>("assert_recover_key"); }
int recover_key(int, int, int, int, int) { return unimplemented<int>("recover_key"); }
void assert_recover_key( legacy_ptr<const fc::sha256> digest,
legacy_span<const char> sig,
legacy_span<const char> pub ) const {
fc::crypto::signature s;
fc::crypto::public_key p;
fc::datastream<const char*> ds( sig.data(), sig.size() );
fc::datastream<const char*> pubds ( pub.data(), pub.size() );

fc::raw::unpack( ds, s );
fc::raw::unpack( pubds, p );

// TODO: enforce supported key types
// EOS_ASSERT(static_cast<unsigned>(s.which()) < db.get<protocol_state_object>().num_supported_key_types,
// eosio::chain::unactivated_signature_type,
// "Unactivated signature type used during assert_recover_key");
// EOS_ASSERT(static_cast<unsigned>(p.which()) < db.get<protocol_state_object>().num_supported_key_types,
// eosio::chain::unactivated_key_type,
// "Unactivated key type used during assert_recover_key");

// TODO: enforce subjective signature length limit maximum-variable-signature-length in queries. Filters don't need this protection.
// EOS_ASSERT(s.variable_size() <= configured_subjective_signature_length_limit(),
// eosio::chain::sig_variable_size_limit_exception, "signature variable length component size greater than subjective maximum");

auto check = fc::crypto::public_key( s, *digest, false );
EOS_ASSERT( check == p, eosio::chain::crypto_api_exception, "Error expected key different than recovered key" );
}

int32_t recover_key( legacy_ptr<const fc::sha256> digest,
legacy_span<const char> sig,
legacy_span<char> pub ) const {
fc::crypto::signature s;
fc::datastream<const char*> ds( sig.data(), sig.size() );
fc::raw::unpack(ds, s);

// TODO: enforce supported key types
// EOS_ASSERT(static_cast<unsigned>(s.which()) < db.get<protocol_state_object>().num_supported_key_types,
// eosio::chain::unactivated_signature_type,
// "Unactivated signature type used during assert_recover_key");

// TODO: enforce subjective signature length limit maximum-variable-signature-length in queries. Filters don't need this protection.
// EOS_ASSERT(s.variable_size() <= configured_subjective_signature_length_limit(),
// eosio::chain::sig_variable_size_limit_exception, "signature variable length component size greater than subjective maximum");

auto recovered = fc::crypto::public_key(s, *digest, false);

// the key types newer than the first 2 may be varible in length
if (static_cast<unsigned>(s.which()) >= eosio::chain::config::genesis_num_supported_key_types ) {
EOS_ASSERT(pub.size() >= 33, eosio::chain::wasm_execution_error,
"destination buffer must at least be able to hold an ECC public key");
auto packed_pubkey = fc::raw::pack(recovered);
auto copy_size = std::min<size_t>(pub.size(), packed_pubkey.size());
std::memcpy(pub.data(), packed_pubkey.data(), copy_size);
return packed_pubkey.size();
} else {
// legacy behavior, key types 0 and 1 always pack to 33 bytes.
// this will do one less copy for those keys while maintaining the rules of
// [0..33) dest sizes: assert (asserts in fc::raw::pack)
// [33..inf) dest sizes: return packed size (always 33)
fc::datastream<char*> out_ds( pub.data(), pub.size() );
fc::raw::pack(out_ds, recovered);
return out_ds.tellp();
}
}

void assert_sha256(int, int, int) { return unimplemented<void>("assert_sha256"); }
void assert_sha1(int, int, int) { return unimplemented<void>("assert_sha1"); }
void assert_sha512(int, int, int) { return unimplemented<void>("assert_sha512"); }
Expand Down