OpenCBDC Transaction Processor
Loading...
Searching...
No Matches
signature.cpp
Go to the documentation of this file.
1// Copyright (c) 2022 MIT Digital Currency Initiative,
2// Federal Reserve Bank of Boston
3// Distributed under the MIT software license, see the accompanying
4// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6#include "signature.hpp"
7
8#include "address.hpp"
9#include "crypto/sha256.h"
10#include "format.hpp"
11#include "hash.hpp"
12#include "rlp.hpp"
13#include "serialization.hpp"
14#include "util.hpp"
15#include "util/common/hash.hpp"
17
18#include <optional>
19#include <secp256k1.h>
20
23 secp256k1_ecdsa_recoverable_signature& sig,
24 evm_tx_type type,
25 uint64_t chain_id) -> evm_sig {
26 auto esig = evm_sig{};
27
28 std::reverse_copy(&sig.data[0],
29 &sig.data[sizeof(esig.m_r.bytes)],
30 esig.m_r.bytes);
31 std::reverse_copy(
32 &sig.data[sizeof(esig.m_r.bytes)],
33 &sig.data[sizeof(esig.m_r.bytes) + sizeof(esig.m_s.bytes)],
34 esig.m_s.bytes);
35
36 uint8_t v{};
37 std::reverse_copy(
38 &sig.data[sizeof(esig.m_r.bytes) + sizeof(esig.m_s.bytes)],
39 &sig.data[sizeof(esig.m_r.bytes) + sizeof(esig.m_s.bytes)
40 + sizeof(v)],
41 &v);
42
43 uint64_t v_large = v;
44 if(type == evm_tx_type::legacy) {
45 // Mutate v based on EIP155 and chain ID
46 v_large += eip155_v_offset;
47 v_large += (chain_id * 2);
48 }
49 esig.m_v = evmc::uint256be(v_large);
50
51 return esig;
52 }
53
55 evm_tx_type type,
56 uint64_t chain_id)
57 -> std::optional<secp256k1_ecdsa_recoverable_signature> {
58 auto sig = secp256k1_ecdsa_recoverable_signature{};
59
60 std::reverse_copy(esig.m_r.bytes,
61 &esig.m_r.bytes[sizeof(esig.m_r.bytes)],
62 sig.data);
63 std::reverse_copy(esig.m_s.bytes,
64 &esig.m_s.bytes[sizeof(esig.m_s.bytes)],
65 &sig.data[sizeof(esig.m_r.bytes)]);
66
67 // Recover v mutation based on EIP155 and chain ID
68 auto v_large = to_uint64(esig.m_v);
69 if(type == evm_tx_type::legacy && v_large > eip155_v_offset) {
70 v_large -= eip155_v_offset;
71 v_large -= (chain_id * 2);
72 if(v_large > std::numeric_limits<uint8_t>::max()) {
73 return std::nullopt;
74 }
75 } else if(type == evm_tx_type::legacy
76 && v_large >= pre_eip155_v_offset) {
77 v_large -= pre_eip155_v_offset;
78 }
79 auto v = static_cast<uint8_t>(v_large);
80 std::memcpy(&sig.data[sizeof(sig.data) - sizeof(v)], &v, sizeof(v));
81
82 return sig;
83 }
84
85 auto eth_sign(const privkey_t& key,
86 hash_t& hash,
87 evm_tx_type type,
88 const std::shared_ptr<secp256k1_context>& ctx,
89 uint64_t chain_id) -> evm_sig {
90 secp256k1_ecdsa_recoverable_signature sig;
91 [[maybe_unused]] const auto sig_ret = secp256k1_ecdsa_sign_recoverable(
92 ctx.get(),
93 &sig,
94 hash.data(),
95 key.data(),
96 secp256k1_nonce_function_rfc6979,
97 nullptr);
98 assert(sig_ret == 1);
100 type,
101 chain_id);
102 }
103
105 const std::shared_ptr<secp256k1_context>& ctx,
106 uint64_t chain_id) -> std::optional<evmc::address> {
107 auto sighash = sig_hash(tx, chain_id);
108
109 auto maybe_sig
111 tx.m_type,
112 chain_id);
113
114 if(!maybe_sig.has_value()) {
115 return std::nullopt;
116 }
117
118 auto sig = maybe_sig.value();
119
120 // Recover pubkey
121 auto pk = std::make_unique<secp256k1_pubkey>();
122 [[maybe_unused]] const auto rec_ret
123 = secp256k1_ecdsa_recover(ctx.get(),
124 pk.get(),
125 &sig,
126 sighash.data());
127 if(rec_ret != 1) {
128 return std::nullopt;
129 }
130
131 return eth_addr(pk, ctx);
132 }
133
135 uint64_t chain_id) -> hash_t {
136 auto rlp_buf = tx_encode(tx, chain_id, true);
137 return cbdc::keccak_data(rlp_buf.data(), rlp_buf.size());
138 }
139}
auto tx_encode(const cbdc::parsec::agent::runner::evm_tx &tx, uint64_t chain_id, bool for_sighash) -> cbdc::buffer
Converts the given transaction to an RLP encoded buffer conforming to Ethereums conventions.
auto eth_sign(const privkey_t &key, hash_t &hash, evm_tx_type type, const std::shared_ptr< secp256k1_context > &ctx, uint64_t chain_id) -> evm_sig
Signs a hash using a privkey_t using ecdsa and produces an evm_sig struct Used primarily in unit test...
Definition signature.cpp:85
auto check_signature(const cbdc::parsec::agent::runner::evm_tx &tx, const std::shared_ptr< secp256k1_context > &ctx, uint64_t chain_id) -> std::optional< evmc::address >
Checks the signature of an EVM transaction.
auto secp256k1_ecdsa_recoverable_signature_to_evm_sig(secp256k1_ecdsa_recoverable_signature &sig, evm_tx_type type, uint64_t chain_id) -> evm_sig
Definition signature.cpp:22
auto eth_addr(const std::unique_ptr< secp256k1_pubkey > &pk, const std::shared_ptr< secp256k1_context > &ctx) -> evmc::address
Calculates an eth address from a public key.
Definition address.cpp:56
auto evm_sig_to_secp256k1_ecdsa_recoverable_signature(const evm_sig &esig, evm_tx_type type, uint64_t chain_id) -> std::optional< secp256k1_ecdsa_recoverable_signature >
Definition signature.cpp:54
auto sig_hash(const cbdc::parsec::agent::runner::evm_tx &tx, uint64_t chain_id) -> hash_t
Calculates the hash for creating / validating the signature.
auto to_uint64(const evmc::uint256be &v) -> uint64_t
Converts an uint256be to a uint64_t, ignoring higher order bits.
std::array< unsigned char, cbdc::hash_size > hash_t
SHA256 hash container.
std::array< unsigned char, pubkey_len > privkey_t
A private key of a public/private keypair.
Definition keys.hpp:23
auto keccak_data(const void *data, size_t len) -> hash_t
Calculates the Keccak256 hash of the specified data.