Skip to content
This repository was archived by the owner on Feb 9, 2025. It is now read-only.

Commit 9f4375a

Browse files
axicchfast
andcommitted
secp256k1: Implement Point to address conversion
Add implementation of procedure that converts EC Point (uncompressed public key) to Ethereum address by Keccak hash. Co-authored-by: Paweł Bylica <pawel@ethereum.org>
1 parent cde21f3 commit 9f4375a

File tree

3 files changed

+31
-0
lines changed

3 files changed

+31
-0
lines changed

lib/evmone_precompiles/secp256k1.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Copyright 2023 The evmone Authors.
33
// SPDX-License-Identifier: Apache-2.0
44
#include "secp256k1.hpp"
5+
#include <ethash/keccak.hpp>
56

67
namespace evmmax::secp256k1
78
{
@@ -26,6 +27,20 @@ std::optional<uint256> calculate_y(
2627
return (candidate_parity == y_parity) ? *y : m.sub(0, *y);
2728
}
2829

30+
evmc::address to_address(const Point& pt) noexcept
31+
{
32+
// This performs Ethereum's address hashing on an uncompressed pubkey.
33+
uint8_t serialized[64];
34+
intx::be::unsafe::store(serialized, pt.x);
35+
intx::be::unsafe::store(serialized + 32, pt.y);
36+
37+
const auto hashed = ethash::keccak256(serialized, sizeof(serialized));
38+
evmc::address ret{};
39+
std::memcpy(ret.bytes, hashed.bytes + 12, 20);
40+
41+
return ret;
42+
}
43+
2944
uint256 field_inv(const ModArith<uint256>& m, const uint256& x) noexcept
3045
{
3146
// Computes modular exponentiation

lib/evmone_precompiles/secp256k1.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#pragma once
55

66
#include "ecc.hpp"
7+
#include <evmc/evmc.hpp>
78
#include <optional>
89

910
namespace evmmax::secp256k1
@@ -18,6 +19,9 @@ inline constexpr auto FieldPrime =
1819
inline constexpr auto Order =
1920
0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141_u256;
2021

22+
using Point = ecc::Point<uint256>;
23+
24+
2125
/// Modular inversion for secp256k1 prime field.
2226
///
2327
/// Computes 1/x mod P modular inversion by computing modular exponentiation x^(P-2),
@@ -42,4 +46,7 @@ uint256 scalar_inv(const ModArith<uint256>& m, const uint256& x) noexcept;
4246
std::optional<uint256> calculate_y(
4347
const ModArith<uint256>& m, const uint256& x, bool y_parity) noexcept;
4448

49+
/// Convert the secp256k1 point (uncompressed public key) to Ethereum address.
50+
evmc::address to_address(const Point& pt) noexcept;
51+
4552
} // namespace evmmax::secp256k1

test/unittests/evmmax_secp256k1_test.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <gtest/gtest.h>
88

99
using namespace evmmax::secp256k1;
10+
using namespace evmc::literals;
1011

1112
TEST(secp256k1, field_inv)
1213
{
@@ -141,3 +142,11 @@ TEST(secp256k1, calculate_y_invalid)
141142
ASSERT_FALSE(y_odd.has_value());
142143
}
143144
}
145+
146+
TEST(secp256k1, point_to_address)
147+
{
148+
// Check if converting the point at infinity gives the known address.
149+
// https://www.google.com/search?q=0x3f17f1962B36e491b30A40b2405849e597Ba5FB5
150+
// https://etherscan.io/address/0x3f17f1962b36e491b30a40b2405849e597ba5fb5
151+
EXPECT_EQ(to_address(Point{}), 0x3f17f1962B36e491b30A40b2405849e597Ba5FB5_address);
152+
}

0 commit comments

Comments
 (0)