Skip to content

auth/auth_handshake.hpp

Namespaces

Name
rlpx
rlpx::auth

Classes

Name
struct rlpx::auth::HandshakeConfig
struct rlpx::auth::HandshakeResult
class rlpx::auth::AuthHandshake
Authentication handshake coordinator.

Functions

Name
FrameSecrets derive_frame_secrets(const AuthKeyMaterial & keys, bool is_initiator)
Derive RLPx frame secrets from authenticated handshake key material.

Attributes

Name
size_t kAuthSize
size_t kAckSize
ack plaintext = eph_pubkey(64) + nonce(32) + ver(1) = 97

Functions Documentation

function derive_frame_secrets

FrameSecrets derive_frame_secrets(
    const AuthKeyMaterial & keys,
    bool is_initiator
)

Derive RLPx frame secrets from authenticated handshake key material.

Parameters:

  • keys All ECDH, nonce, and wire bytes collected during the handshake.
  • is_initiator True for the connection initiator (dialer), false for the responder.

Return: FrameSecrets containing AES/MAC keys and MAC seed byte strings.

Exposed as a free function for unit testing against go-ethereum test vectors.

Attributes Documentation

variable kAuthSize

static size_t kAuthSize = 307;

Plain RLPx v4 fixed wire sizes (ECIES overhead + plaintext) auth plaintext = sig(65) + eph_hash(32) + pubkey(64) + nonce(32) + ver(1) = 194 ECIES overhead = pubkey(65) + iv(16) + mac(32) = 113 ECIES( 194-byte auth body )

variable kAckSize

static size_t kAckSize = 210;

ack plaintext = eph_pubkey(64) + nonce(32) + ver(1) = 97

ECIES( 97-byte ack body )

Source code

// Copyright 2025 GeniusVentures
// SPDX-License-Identifier: Apache-2.0

#pragma once

#include "../rlpx_types.hpp"
#include "../rlpx_error.hpp"
#include "auth_keys.hpp"
#include "../socket/socket_transport.hpp"
#include <boost/asio/spawn.hpp>

namespace rlpx::auth {

static constexpr size_t kAuthSize = 307; 
static constexpr size_t kAckSize  = 210; 

// Handshake configuration parameters
struct HandshakeConfig {
    PublicKey        local_public_key{};
    PrivateKey       local_private_key{};
    std::string      client_id;
    uint16_t         listen_port = 0;
    // Optional for initiator (outbound), empty for recipient (inbound)
    std::optional<PublicKey> peer_public_key;
};

// Handshake result containing all derived material
struct HandshakeResult {
    AuthKeyMaterial key_material;
    FrameSecrets frame_secrets;
    std::string peer_client_id;
    uint16_t peer_listen_port;
    std::optional<socket::SocketTransport> transport; 

    // Grouped access to crypto material
    [[nodiscard]] const AuthKeyMaterial& keys() const noexcept { 
        return key_material; 
    }

    [[nodiscard]] const FrameSecrets& secrets() const noexcept { 
        return frame_secrets; 
    }
};

class AuthHandshake {
public:
    explicit AuthHandshake(const HandshakeConfig& config,
                           socket::SocketTransport transport) noexcept;

    [[nodiscard]] Result<HandshakeResult>
    execute(boost::asio::yield_context yield) noexcept;

    [[nodiscard]] bool is_initiator() const noexcept { 
        return config_.peer_public_key.has_value(); 
    }

    [[nodiscard]] static FrameSecrets
    derive_frame_secrets(const AuthKeyMaterial& keys, bool is_initiator) noexcept;

private:
    [[nodiscard]] AuthResult<AuthKeyMaterial>
    perform_auth(boost::asio::yield_context yield) noexcept;

    [[nodiscard]] Result<void>
    exchange_hello(ByteView aes_key, ByteView mac_key, boost::asio::yield_context yield) noexcept;


    HandshakeConfig config_;
    socket::SocketTransport transport_;
    // Socket abstraction injected via constructor
};

[[nodiscard]] FrameSecrets
derive_frame_secrets(const AuthKeyMaterial& keys, bool is_initiator) noexcept;

} // namespace rlpx::auth

Updated on 2026-04-13 at 23:22:46 -0700