# How Clients Authenticate with Ed25519 or P‑256 Signatures in mpCium

> Learn how clients authenticate with Ed25519 or P256 signatures in mpCium. Discover the dual-signature scheme and how the LocalSigner dispatches signing routines for secure identity verification.

- Repository: [Fystack Labs/mpcium](https://github.com/fystack/mpcium)
- Tags: how-to-guide
- Published: 2026-03-02

---

**mpCium implements a dual-signature authentication scheme allowing clients to prove identity using either Ed25519 (EdDSA) or P‑256 (ECDSA) keys, with the `LocalSigner` type in [`pkg/client/local_signer.go`](https://github.com/fystack/mpcium/blob/main/pkg/client/local_signer.go) dispatching to algorithm-specific signing routines and the server verifying via [`pkg/identity/identity.go`](https://github.com/fystack/mpcium/blob/main/pkg/identity/identity.go).**

The fystack/mpcium repository provides a cryptographic authentication layer that supports both modern Ed25519 curves and NIST P‑256 ECDSA signatures. This flexibility enables integration with diverse blockchain ecosystems while maintaining a unified verification interface in the `identity` package.

## The Three-Stage Authentication Flow

mpCium authenticates clients through a structured three-stage process involving key initialization, payload signing, and server-side verification according to the specific cryptographic algorithm configured.

### Stage 1: Key Selection and Loading

The client creates a **LocalSigner** that determines which algorithm to use based on the `EventInitiatorKeyTypeEd25519` or `EventInitiatorKeyTypeP256` constant. In [`pkg/client/local_signer.go`](https://github.com/fystack/mpcium/blob/main/pkg/client/local_signer.go), the `NewLocalSigner` constructor (lines 33‑66) reads the key material from a file path specified in `LocalSignerOptions`, automatically detecting `.age` extensions for encrypted keys.

The constructor dispatches to algorithm-specific loaders:

- `loadEd25519Key` (lines 99‑106) parses the 32‑byte private key for Ed25519.
- `loadP256Key` (lines 109‑116) loads the private key for P‑256 curve operations.

### Stage 2: Message Signing

The client constructs an initiator message such as `SignTxMessage` or `GenerateKeyMessage` defined in [`pkg/types/initiator_msg.go`](https://github.com/fystack/mpcium/blob/main/pkg/types/initiator_msg.go). Before transmission, the message must include a signature over its canonical payload.

The `LocalSigner.Sign` method (lines 22‑34 of [`local_signer.go`](https://github.com/fystack/mpcium/blob/main/local_signer.go)) automatically dispatches to the appropriate cryptographic routine:

- **Ed25519**: calls `ed25519.Sign` from the Go standard library.
- **P‑256**: calls `encryption.SignWithP256` from [`pkg/encryption/p256.go`](https://github.com/fystack/mpcium/blob/main/pkg/encryption/p256.go).

The signer invokes `msg.Raw()` (implemented at lines 64‑80 of [`initiator_msg.go`](https://github.com/fystack/mpcium/blob/main/initiator_msg.go)) to obtain a deterministic JSON payload excluding the `Signature` field itself, then stores the resulting signature in the message's `Signature` field.

### Stage 3: Server-Side Verification

When the mpCium node receives the initiator message, [`pkg/identity/identity.go`](https://github.com/fystack/mpcium/blob/main/pkg/identity/identity.go) handles verification using public keys stored in the node's identity file and optional authorizer configurations.

For the initiator signature, the system selects the verifier based on the configured key type:

- `fileStore.verifyEd25519` (lines 55‑66) retrieves the stored Ed25519 public key via `GetPublicKey` (lines 39‑49) and executes `ed25519.Verify`.
- `fileStore.verifyP256` (lines 71‑82) calls `encryption.VerifyP256Signature` to perform ECDSA verification on the P‑256 curve.

If the message includes authorizer signatures defined in the `authorizer_public_keys` section of [`config.yaml`](https://github.com/fystack/mpcium/blob/main/config.yaml), the `verifyAuthorizerSignature` function (lines 20‑42) matches each authorizer's `algorithm` field (`AlgorithmEd25519` or `AlgorithmP256`) to the cached key type and invokes the corresponding verification routine.

## Implementation Examples

### Authenticating with Ed25519

To authenticate using Ed25519, initialize the signer with `EventInitiatorKeyTypeEd25519` and construct the transaction message:

```go
// Load the Ed25519 signer from pkg/client/local_signer.go
signer, err := client.NewLocalSigner(
    types.EventInitiatorKeyTypeEd25519,
    client.LocalSignerOptions{KeyPath: "./event_initiator.key"},
)
if err != nil {
    log.Fatal(err)
}

// Build the transaction request
txMsg := &types.SignTxMessage{
    KeyType:             types.KeyTypeEd25519,
    WalletID:            "wallet-123",
    NetworkInternalCode: "solana-devnet",
    TxID:                uuid.New().String(),
    Tx:                  []byte{0xde, 0xad, 0xbe, 0xef},
}

// Sign and publish via the MPC client
mpcClient := client.NewMPCClient(client.Options{
    NatsConn: natsConn,
    Signer:   signer,
})
if err := mpcClient.SignTransaction(txMsg); err != nil {
    log.Fatal(err)
}

```

Behind the scenes, `SignTransaction` internally calls `signer.Sign(txMsg.Raw())`, which triggers `ed25519.Sign` from the standard library. The server-side `verifyEd25519` function in [`pkg/identity/identity.go`](https://github.com/fystack/mpcium/blob/main/pkg/identity/identity.go) validates the signature against the initiator's stored public key.

### Authenticating with P‑256

For P‑256 authentication, specify `EventInitiatorKeyTypeP256` during signer creation. Note that wallet key types use `KeyTypeSecp256k1` to indicate P‑256 curve usage:

```go
// Load the P‑256 signer
signer256, err := client.NewLocalSigner(
    types.EventInitiatorKeyTypeP256,
    client.LocalSignerOptions{KeyPath: "./event_initiator_p256.key"},
)
if err != nil {
    log.Fatal(err)
}

// Construct the message with secp256k1 key type for P‑256 wallets
msg := &types.SignTxMessage{
    KeyType:             types.KeyTypeSecp256k1, // Indicates P‑256 wallet
    WalletID:            "wallet-456",
    NetworkInternalCode: "ethereum-mainnet",
    TxID:                uuid.New().String(),
    Tx:                  []byte("transaction_data"),
}

// The client automatically uses encryption.SignWithP256
mpcClient := client.NewMPCClient(client.Options{
    NatsConn: natsConn,
    Signer:   signer256,
})
mpcClient.SignTransaction(msg)

```

Verification follows the `verifyP256` path in [`identity.go`](https://github.com/fystack/mpcium/blob/main/identity.go), which delegates to `encryption.VerifyP256Signature` using the stored ECDSA public key.

### Verifying Authorizer Signatures

Authorizers provide additional signatures configured in [`config.yaml`](https://github.com/fystack/mpcium/blob/main/config.yaml) with explicit algorithm declarations:

```yaml
authorizer_public_keys:
  auditor1:
    public_key: "a1b2c3d4..."  # 32-byte hex for Ed25519

    algorithm: "ed25519"
  compliance2:
    public_key: "04d5e6f7..."  # DER-encoded P‑256 key

    algorithm: "p256"

```

When including authorizer signatures in the message:

```go
rawPayload, _ := txMsg.Raw()

txMsg.AuthorizerSignatures = []types.AuthorizerSignature{
    {
        AuthorizerID: "auditor1",
        Signature:    ed25519.Sign(privEd25519, rawPayload),
    },
    {
        AuthorizerID: "compliance2",
        Signature:    encryption.SignWithP256(privP256, rawPayload),
    },
}

```

The server's `verifyAuthorizerSignature` function automatically selects `ed25519.Verify` or `encryption.VerifyP256Signature` based on the `algorithm` field in the configuration.

## Summary

- **Dual-algorithm support**: mpCium clients authenticate using either Ed25519 or P‑256 signatures via the `LocalSigner` interface in [`pkg/client/local_signer.go`](https://github.com/fystack/mpcium/blob/main/pkg/client/local_signer.go).
- **Automatic dispatch**: The `Sign` method (lines 22‑34) automatically routes to `ed25519.Sign` or `encryption.SignWithP256` based on the initiator key type specified during construction.
- **Deterministic payloads**: All signatures are computed over the canonical output of `msg.Raw()` (lines 64‑80 of [`pkg/types/initiator_msg.go`](https://github.com/fystack/mpcium/blob/main/pkg/types/initiator_msg.go)), ensuring consistent verification data.
- **Flexible verification**: The server-side [`identity.go`](https://github.com/fystack/mpcium/blob/main/identity.go) file provides `verifyEd25519` (lines 55‑66) and `verifyP256` (lines 71‑82) for initiators, plus `verifyAuthorizerSignature` (lines 20‑42) for multi-party authorization.

## Frequently Asked Questions

### How do I configure an mpCium client to use Ed25519 instead of P‑256?

Pass `types.EventInitiatorKeyTypeEd25519` as the first argument to `client.NewLocalSigner` in [`pkg/client/local_signer.go`](https://github.com/fystack/mpcium/blob/main/pkg/client/local_signer.go), and ensure your key file contains a valid 32‑byte Ed25519 private key. The constructor (lines 33‑66) automatically selects the Ed25519 loading path via `loadEd25519Key` (lines 99‑106).

### What determines whether the server uses Ed25519 or P‑256 verification?

The server checks the initiator's configured key type stored in the identity file, then dispatches to either `fileStore.verifyEd25519` or `fileStore.verifyP256` in [`pkg/identity/identity.go`](https://github.com/fystack/mpcium/blob/main/pkg/identity/identity.go) (lines 55‑82). Each function retrieves the appropriate public key via `GetPublicKey` (lines 39‑49) and calls the corresponding verification routine.

### Can authorizers use a different signature algorithm than the initiator?

Yes. The `verifyAuthorizerSignature` function (lines 20‑42 of [`pkg/identity/identity.go`](https://github.com/fystack/mpcium/blob/main/pkg/identity/identity.go)) reads the `algorithm` field from the `authorizer_public_keys` configuration and independently selects Ed25519 or P‑256 verification. This allows mixed-algorithm scenarios where, for example, an initiator uses Ed25519 while authorizers use P‑256.

### Where is the P‑256 signing logic implemented?

P‑256 signing is implemented in [`pkg/encryption/p256.go`](https://github.com/fystack/mpcium/blob/main/pkg/encryption/p256.go) via the `SignWithP256` function, which the `LocalSigner` calls when configured with `EventInitiatorKeyTypeP256`. Verification uses `encryption.VerifyP256Signature` (also in [`p256.go`](https://github.com/fystack/mpcium/blob/main/p256.go)) invoked by `verifyP256` in [`pkg/identity/identity.go`](https://github.com/fystack/mpcium/blob/main/pkg/identity/identity.go).