Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove most of crypto and move out of search path #23

Merged
merged 8 commits into from
Jul 4, 2024
Merged
Show file tree
Hide file tree
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
6 changes: 2 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,8 @@ endif()

# Find all headers and implementation files
include(cmake/SourcesAndHeaders.cmake)
if(${PROJECT_NAME}_ENABLE_CRYPTO_LIBRARY)
add_subdirectory(src/crypto)
endif()
add_subdirectory(external)
add_subdirectory(src/ethyl-keccak)

add_library(
${PROJECT_NAME}
Expand Down Expand Up @@ -99,8 +97,8 @@ target_link_libraries(
secp256k1
nlohmann_json::nlohmann_json
oxenc::oxenc
ethyl-keccak
PRIVATE
cncrypto
gmp
gmpxx
)
Expand Down
13 changes: 2 additions & 11 deletions include/ethyl/ecdsa_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@


/* Returns 1 on success, and 0 on failure. */
[[maybe_unused]] static int fill_random(unsigned char* data, size_t size) {
[[maybe_unused]] static int ethyl_fill_random(unsigned char* data, size_t size) {
#if defined(_WIN32) || defined(__CYGWIN__)
NTSTATUS res = BCryptGenRandom(NULL, data, (ULONG)size, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
if (res != STATUS_SUCCESS || size > ULONG_MAX) {
Expand Down Expand Up @@ -70,17 +70,8 @@
return 0;
}

[[maybe_unused]] static void print_hex(unsigned char* data, size_t size) {
size_t i;
printf("0x");
for (i = 0; i < size; i++) {
printf("%02x", data[i]);
}
printf("\n");
}

/* Cleanses memory to prevent leaking sensitive info. Won't be optimized out. */
[[maybe_unused]] static void secure_erase(void *ptr, size_t len) {
[[maybe_unused]] static void ethyl_secure_erase(void *ptr, size_t len) {
#if defined(_MSC_VER) || defined(__CYGWIN__)
/* SecureZeroMemory is guaranteed not to be optimized out by MSVC. */
SecureZeroMemory(ptr, len);
Expand Down
3 changes: 3 additions & 0 deletions include/ethyl/logs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include <vector>
#include <optional>

namespace ethyl
{
struct LogEntry {
std::string address; // Address from which this log originated
std::vector<std::string> topics; // Array of 0-4 32-byte data of indexed log arguments
Expand All @@ -16,3 +18,4 @@ struct LogEntry {
std::optional<uint32_t> logIndex; // Index of the log in the block (optional)
bool removed; // True if log was removed due to a chain reorganization
};
} // namespace ethyl
46 changes: 28 additions & 18 deletions include/ethyl/signer.hpp
Original file line number Diff line number Diff line change
@@ -1,45 +1,55 @@
#pragma once

#include <array>
#include <memory>
#include "provider.hpp"
#include "utils.hpp"

#include <span>
#include <string>
#include <string_view>
#include <vector>

#include "provider.hpp"

typedef struct secp256k1_context_struct secp256k1_context; // forward decl

namespace ethyl
{
class Signer {
private:
secp256k1_context* ctx;

uint64_t maxPriorityFeePerGas = 0;
uint64_t maxFeePerGas = 0;
uint64_t gasPrice = 0;

public:
Signer();
~Signer();

// Returns <Pubkey, Seckey>
std::pair<std::vector<unsigned char>, std::vector<unsigned char>> generate_key_pair();
std::array<unsigned char, 20> secretKeyToAddress(std::span<const unsigned char> seckey);
std::string secretKeyToAddressString(std::span<const unsigned char> seckey);
Bytes20 secretKeyToAddress(std::span<const unsigned char> seckey);
std::string secretKeyToAddressString(std::span<const unsigned char> seckey);

std::vector<unsigned char> sign(const std::array<unsigned char, 32>& hash, std::span<const unsigned char> seckey);
std::vector<unsigned char> sign(std::string_view hash, std::span<const unsigned char> seckey);
/// Sign a 32 byte hash with secp256k1 and return an ECDSA signature in
/// compact form of 65 bytes (64 bytes + recovery ID)
ECDSACompactSignature sign32(std::span<const unsigned char, 32> bytes, std::span<const unsigned char> seckey);

// Client usage methods
std::vector<unsigned char> signMessage(std::string_view message, std::span<const unsigned char> seckey);
std::string signTransaction(Transaction& tx, std::span<const unsigned char> seckey);
/// Sign the message by hashing `message` with keccak into 32 bytes and then
/// sign the 32 bytes using `seckey` with secp256k1.
ECDSACompactSignature signMessage(std::string_view message, std::span<const unsigned char> seckey);

/// Sign a transaction with the given `seckey`. The transaction is updated
/// to store the signature as computed by this function. This function
/// returns the the RLP serialised TX.
std::vector<unsigned char> signTransaction(Transaction& tx, std::span<const unsigned char> seckey);

/// See `signTransaction`. This function returns the RLP serialised TX in
/// hex without a '0x' prefix.
std::string signTransactionAsHex(Transaction& tx, std::span<const unsigned char> seckey);

void populateTransaction(Transaction& tx, std::string sender_address);

std::string sendTransaction(Transaction& tx, std::span<const unsigned char> seckey);

Provider provider;

private:
secp256k1_context* ctx;
uint64_t maxPriorityFeePerGas = 0;
uint64_t maxFeePerGas = 0;
uint64_t gasPrice = 0;

};
}; // namespace ethyl
52 changes: 33 additions & 19 deletions include/ethyl/transaction.hpp
Original file line number Diff line number Diff line change
@@ -1,37 +1,51 @@
#pragma once

#include "utils.hpp"
#include <string>
#include <vector>
#include <cstdint>

struct Signature {
namespace ethyl
{
struct Signature
{
bool init = false;
uint64_t signatureYParity = 0;
std::vector<unsigned char> signatureR = {};
std::vector<unsigned char> signatureS = {};
Bytes32 signatureR;
Bytes32 signatureS;
void set(ECDSACompactSignature const &signature);
};

bool isEmpty() const;
struct Transaction
{
Transaction() = default;

void fromHex(std::string_view hex_str);
};
Transaction(std::string to, uint64_t value, uint64_t gasLimit = 21000,
std::string data = "");

/// Serialise the transaction into a RLP serialised payload.
std::vector<unsigned char> serialize() const;

/// See `serialize`. The RLP payload is returned in hex without a '0x'
/// prefix.
std::string serializeAsHex() const;

/// Calculate the transaction hash by RLP serializing the contents and
/// applying a keccak hash.
Bytes32 hash() const;

/// Calculate the transaction hash by calling `hash` and returning the hex
/// representation of the 32 byte hash without a '0x' prefix.
std::string hashAsHex() const;

class Transaction {
public:
uint64_t chainId = 0;
uint64_t nonce = 0;
uint64_t maxPriorityFeePerGas = 0;
uint64_t maxFeePerGas = 0;
std::string to;
uint64_t value;
uint64_t gasLimit;
uint64_t value = 0;
uint64_t gasLimit = 0;
std::string data;
Signature sig;

// Constructor
// (toAddress, value, gasLimit, data)
Transaction(std::string to, uint64_t value, uint64_t gasLimit = 21000, std::string data = "")
: to{std::move(to)}, value{std::move(value)}, gasLimit{gasLimit}, data{std::move(data)} {}

std::string serialized() const;
std::string hash() const;

};
} // namespace ethyl
71 changes: 35 additions & 36 deletions include/ethyl/utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,39 +6,23 @@
#include <string>
#include <array>
#include <vector>
#include <sstream>
#include <iomanip>
#include <ios>

#include <oxenc/common.h>
#include <oxenc/hex.h>

namespace utils
namespace ethyl
{
using ECDSACompactSignature = std::array<unsigned char, 64 + 1 /*recovery id*/>;
using Bytes20 = std::array<unsigned char, 20>;
using Bytes32 = std::array<unsigned char, 32>;

namespace utils
{
enum class PaddingDirection {
LEFT,
RIGHT
};

template <typename Container>
std::string toHexString(const Container& bytes) {
std::ostringstream oss;
for(const auto byte : bytes) {
oss << std::setw(2) << std::setfill('0') << std::hex << static_cast<int>(static_cast<unsigned char>(byte));
}
return oss.str();
}

template <typename Container>
std::string toHexStringBigEndian(const Container& bytes) {
std::ostringstream oss;
for(auto it = bytes.rbegin(); it != bytes.rend(); ++it) {
oss << std::setw(2) << std::setfill('0') << std::hex << static_cast<int>(static_cast<unsigned char>(*it));
}
return oss.str();
}

std::string decimalToHex(uint64_t decimal, bool prefixed_0x = false);
std::string_view trimPrefix(std::string_view src, std::string_view prefix);
std::string_view trimLeadingZeros(std::string_view src);
Expand All @@ -47,6 +31,7 @@ namespace utils
template <basic_char Char = unsigned char>
std::vector<Char> fromHexString(std::string_view hexStr) {
hexStr = trimPrefix(hexStr, "0x");
hexStr = trimPrefix(hexStr, "0X");

if (!oxenc::is_hex(hexStr))
throw std::invalid_argument{"input string is not hex"};
Expand Down Expand Up @@ -75,22 +60,21 @@ namespace utils
extern template std::array<char, 32> fromHexString32Byte<char>(std::string_view);
extern template std::array<unsigned char, 32> fromHexString32Byte<unsigned char>(std::string_view);

uint64_t hexStringToU64(std::string_view hexStr);

uint64_t fromHexStringToUint64(std::string_view hexStr);
std::string padToNBytes(std::string_view hexInput, size_t bytes, PaddingDirection direction = PaddingDirection::LEFT);

std::string padToNBytes(std::string_view hex_input, size_t bytes, PaddingDirection direction = PaddingDirection::LEFT);
inline std::string padTo8Bytes(std::string_view hex_input, PaddingDirection direction = PaddingDirection::LEFT) {
return padToNBytes(hex_input, 8, direction);
inline std::string padTo8Bytes(std::string_view hexInput, PaddingDirection direction = PaddingDirection::LEFT) {
return padToNBytes(hexInput, 8, direction);
}

inline std::string padTo32Bytes(std::string_view hex_input, PaddingDirection direction = PaddingDirection::LEFT) {
return padToNBytes(hex_input, 32, direction);
inline std::string padTo32Bytes(std::string_view hexInput, PaddingDirection direction = PaddingDirection::LEFT) {
return padToNBytes(hexInput, 32, direction);
}


/// Parses an integer of some sort from a string, requiring that the entire string be consumed
/// during parsing. Return false if parsing failed, sets `value` and returns true if the entire
/// string was consumed.
/// Parses an integer of some sort from a string, requiring that the entire
/// string be consumed during parsing. Return false if parsing failed, sets
/// `value` and returns true if the entire string was consumed.
template <typename T>
bool parseInt(const std::string_view str, T& value, int base = 10) {
T tmp;
Expand All @@ -102,11 +86,26 @@ namespace utils
return true;
}

std::array<unsigned char, 32> hash(std::string_view in);
/// Hashes a hex string into a 32-byte hash using keccak by first converting
/// the hex to bytes. The hex string is allowed to start with '0x' and '0X'.
/// Passing bytes to this function will throw an `invalid_argument`
/// exception.
Bytes32 hashHex(std::string_view hex);

/// Hash the bytes into a 32-byte hash using keccak.
Bytes32 hashBytesPtr(const void *bytes, size_t size);

/// See `hashBytesPtr`
Bytes32 hashBytes(std::span<const char> bytes);

/// See `hashBytesPtr`
Bytes32 hashBytes(std::span<const unsigned char> bytes);

std::string getFunctionSignature(const std::string& function);
/// Get the function signature for Ethereum contract interaction via an ABI
/// call
std::string toEthFunctionSignature(std::string_view function);

std::string trimAddress(const std::string& address);
} // namespace ethyl::utils
};

// END
}
Loading
Loading