Skip to main content

FPSF-MPC-001 — Guides

Layer: Guides · Audience: developers integrating with the MPC system For normative requirements, see the Formal Specification.


Guide 1: Setting Up Root and Sub Keys

Before making any API request, you need a root key pair (offline) and a sub key pair (online).

Generate a root key pair (offline device)

# Using OpenSSL
openssl genpkey -algorithm ed25519 -out root_sk.pem
openssl pkey -in root_sk.pem -pubout -out root_pk.pem

Store root_sk.pem securely offline. You only need it to authorize new sub keys.

Generate a sub key pair (online device)

openssl genpkey -algorithm ed25519 -out sub_sk.pem
openssl pkey -in sub_sk.pem -pubout -out sub_pk.pem

Create an Authorization Token

On your offline device, create and sign the following JSON using RFC 8785 canonical serialization:

{
"version": "1",
"type": "sub_key_authorization",
"root_key_pub": "<base64url root public key>",
"sub_key_pub": "<base64url sub public key>",
"issued_at": "2026-03-25T12:00:00.000Z",
"expires_at": "2026-06-25T12:00:00.000Z"
}

Sign the canonical JSON bytes with your root private key. The resulting base64url-encoded signature is your token_sig. You will include both the token object and this signature in every API request.


Guide 2: Creating a Disposable Key

Build the signed request envelope and call POST /api/v1/keys.

Request envelope structure

{
"envelope": {
"version": "1",
"action": "create_key",
"nonce": "<16 random bytes, base64url>",
"timestamp": "2026-03-25T12:00:00.000Z",
"sub_key_pub": "<base64url sub public key>",
"root_key_pub": "<base64url root public key>",
"authorization": {
"token": {
"version": "1",
"type": "sub_key_authorization",
"root_key_pub": "<base64url>",
"sub_key_pub": "<base64url>",
"issued_at": "2026-03-25T12:00:00.000Z",
"expires_at": "2026-06-25T12:00:00.000Z"
},
"token_sig": "<base64url root key signature over canonical token>"
},
"params": {
"threshold_t": 3,
"threshold_n": 5
}
},
"sig": "<base64url sub key signature over canonical JSON of envelope>"
}

To sign:

  1. Serialize the envelope object using RFC 8785 (JCS).
  2. Sign the resulting bytes with your sub key's Ed25519 private key.
  3. Encode the signature as base64url.

Successful response

{
"key_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"public_key": "<base64url Ed25519 public key>",
"threshold_t": 3,
"threshold_n": 5,
"created_at": "2026-03-25T12:00:01.234Z"
}

Save the key_id and public_key. The public_key is what you share with counterparties as your verifiable identity for this key.


Guide 3: Signing a Message

To sign a message with a disposable key, call POST /api/v1/keys/{key_id}/sign.

The message field in the envelope is the raw bytes you want signed, encoded as base64url.

{
"envelope": {
"version": "1",
"action": "sign",
"nonce": "<fresh 16 random bytes, base64url>",
"timestamp": "2026-03-25T12:01:00.000Z",
"sub_key_pub": "<base64url>",
"root_key_pub": "<base64url>",
"authorization": { "token": {}, "token_sig": "<base64url>" },
"message": "<base64url — the bytes to sign>"
},
"sig": "<base64url sub key signature over canonical JSON of envelope>"
}

Response:

{
"key_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"signature": "<base64url Ed25519 signature over message>",
"public_key": "<base64url>",
"signed_at": "2026-03-25T12:01:00.456Z"
}

The returned signature is a standard Ed25519 signature. Any Ed25519 verifier can verify it against public_key without knowing the MPC system was involved.


Guide 4: Destroying a Key

When you are done with a disposable key, destroy it. Call DELETE /api/v1/keys/{key_id} with a signed envelope in the X-MPC-Request header.

The header value is the base64url-encoded canonical JSON of:

{
"version": "1",
"action": "destroy_key",
"nonce": "<fresh 16 random bytes, base64url>",
"timestamp": "<ISO 8601 UTC>",
"sub_key_pub": "<base64url>",
"root_key_pub": "<base64url>",
"authorization": { "token": {}, "token_sig": "<base64url>" },
"sig": "<base64url sub key signature over canonical JSON of this envelope>"
}

Response:

{
"key_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"destroyed_at": "2026-03-25T12:05:00.000Z",
"ack_count": 5,
"pending_ack_count": 0
}

Once destroyed, the key cannot be used again. Any subsequent requests referencing this key_id will return KEY_DESTROYED.


Guide 5: Using MPC Keys with CashPack (FPSF-CPP-001)

When receiving a cash-pack, generate a fresh disposable key pair for that instrument:

  1. Call POST /api/v1/keys to create a disposable key. Note the key_id and public_key.
  2. Provide the public_key to the sender as your incoming_bearer_pk in the renewal entry.
  3. When you renew or redeem the instrument, call POST /api/v1/keys/{key_id}/sign with the renewal entry or redemption request (canonically serialized) as the message.
  4. Use the returned signature as your outgoing_bearer_signature.
  5. After the instrument is renewed or redeemed, call DELETE /api/v1/keys/{key_id} to destroy the key.

This workflow ensures each bearer position uses a unique, ephemeral key — the strongest privacy guarantee the protocol offers.


FPSF-MPC-001 v1.0.0 · Draft · Fabric Payment Standards Foundation · Apache-2.0