How To Add Web3-Based Signature Authentication#

This guide will walk you through implementing Web3-based signature authentication using rizemind with Flower, ensuring secure, blockchain-validated authentication for federated learning.

Requirements

We recommend installing python-dotenv to store your mnemonic in a .env file:

# If you use pip
pip install python-dotenv

# If you use uv
uv add python-dotenv

Modifying the Client#

We will use the SigningClient class, which seamlessly integrates with any existing FlowerClient. This class pulls signing instructions from the blockchain. To achieve this, we must define: 1. The gateway URL to access the blockchain. 2. The mnemonic to sign updates.

### Adding Configuration

Add these fields to your pyproject.toml:

[tool.eth.account]
mnemonic = "$RIZENET_MNEMONIC"

[tool.web3]
url = "https://testnet.rizenet.io"

Next, create a .env file in the same directory as pyproject.toml to store your secrets securely (never commit this file to Git):

RIZENET_MNEMONIC="put your mnemonic here"

Note

TomlConfig will automatically replace values in the config with environment variables.

### Updating the Client

Modify the client function to use SigningClient:

from dotenv import load_dotenv
from rizemind.authentication.config import AccountConfig
from rizemind.configuration.toml_config import TomlConfig
from rizemind.web3.config import Web3Config
from rizemind.authentication.eth_account_client import SigningClient
from .task import load_data, load_model

def client_fn(context: Context):
    """Construct a Client that will be run in a ClientApp."""

    # Read node_config to fetch partition details
    partition_id = int(context.node_config["partition-id"])
    num_partitions = int(context.node_config["num-partitions"])
    data = load_data(partition_id, num_partitions)

    # Read run_config to fetch hyperparameters
    epochs = context.run_config["local-epochs"]
    batch_size = context.run_config["batch-size"]
    verbose = context.run_config.get("verbose")
    learning_rate = context.run_config["learning-rate"]

    client = FlowerClient(learning_rate, data, epochs, batch_size, verbose).to_client()

    ##########
    # Adding signing support
    ##########

    # Load values from .env into os.environ
    load_dotenv()

    # Load config and parse env variables
    config = TomlConfig("./pyproject.toml")

    # Create an AccountConfig from the TOML file
    account_config = AccountConfig(**config.get("tool.eth.account"))

    # Derive an address from the mnemonic using HD path
    account = account_config.get_account(partition_id + 1)

    # Load blockchain gateway configuration
    web3_config = Web3Config(**config.get("tool.web3"))

    # Return Client instance with signing capability
    return SigningClient(
        client,
        account,
        web3_config.get_web3(),
    )

Modifying the Aggregator#

On the aggregator side, we will use EthAccountStrategy to validate Web3-based signatures. This integrates seamlessly with any FlowerStrategy.

Adding Smart Contract Configuration#

Add the following parameters to configure the model’s smart contract in pyproject.toml:

[tool.web3.model_v1]
name = "test_model"
ticker = "tst"

Updating the Server#

Modify server_fn to integrate signature validation:

def server_fn(context: Context):
    """Construct components that set the ServerApp behaviour."""
    parameters = ndarrays_to_parameters(load_model().get_weights())

    # Define the strategy
    strategy = FedAvg(
        fraction_fit=float(context.run_config["fraction-fit"]),
        fraction_evaluate=1.0,
        min_available_clients=2,
        initial_parameters=parameters,
        evaluate_metrics_aggregation_fn=weighted_average,
    )

    # Read config values
    num_rounds = int(context.run_config["num-server-rounds"])

    #######
    # Adding signature authentication
    #######

    # Load .env values into os.environ
    load_dotenv()

    # Load and parse config
    config = TomlConfig("./pyproject.toml")

    # Load account and blockchain configuration
    auth_config = AccountConfig(**config.get("tool.eth.account"))
    web3_config = Web3Config(**config.get("tool.web3"))
    w3 = web3_config.get_web3()

    # Derive the aggregator account (account 0)
    account = auth_config.get_account(0)

    # Generate trainer accounts
    members = [auth_config.get_account(i).address for i in range(1, 11)]

    # Load the model configuration
    model_v1_config = ModelFactoryV1Config(**config.get("tool.web3.model_v1"))

    # Deploy the smart contract
    contract = ModelFactoryV1(model_v1_config).deploy(account, members, w3)

    # Define server configuration
    config = ServerConfig(num_rounds=int(num_rounds))

    # Enable authentication strategy
    auth_strategy = EthAccountStrategy(strategy, contract)

    return ServerAppComponents(strategy=auth_strategy, config=config)

Run to Test#

Run your Flower project with:

flwr run .

Debugging#

Issue: Account cannot deploy contracts
  • Copy the address in the error message.

  • Visit rizenet.io/deployer and follow the steps to add the address to the whitelist.

Issue: Account does not have enough gas

By following these steps, you have successfully added Web3-based signature authentication to your Flower project, ensuring secure client authentication and model integrity on the blockchain.