Skip to main content

Verify Signature

Every EigenAI API response includes a cryptographic signature field that proves the response was generated by the EigenAI Operator (that is, EigenLabs). You can verify this signature to ensure authenticity and integrity of the response. When signature verification succeeds, you have cryptographic proof that:

  • The response was generated by Eigenlab’s EigenAI operator(that is, the holder of the signing private key).
  • The response has not been modified after signing.
  • The specific model, prompt, and output are authentic.

What is signed?

The signature covers a specific message constructed from four components concatenated together with no separators:

chain_id + model_id + prompt + output

Where:

  • chain_id: Network identifier (1 for mainnet, 11155111 for Sepolia testnet)
  • model_id: The model field from the API response
  • prompt: All content fields from the original request’s messages array, concatenated
  • output: All content fields from the API response’s choices array, concatenated
important

You need to store your original request, the API response, and the chainID of the network queried to verify the signature.

Steps to verify

The steps to verify the signature are:

  1. Extract the prompt from the original request
  2. Extract the output from the response
  3. Construct the message
  4. Verify the signature
  5. Compare addresses.

1. Extract the prompt

Concatenate all request.messages[].content fields, in order, with no separators.

Example

Request messages: [{"content": "Hello"}, {"content": "World"}]

Prompt: "HelloWorld"

2. Extract the output

Concatenate all response.choices[].message.content fields, with no separators.

Example

Response choices: [{"message": {"content": "AI response here"}}]

Output: "AI response here"

3. Construct the message

Build the verification message by concatenating the four components with no separators, spaces, or delimiters:

{chain_id}{model_id}{prompt}{output}
Mainnet example

1gpt-oss-120b-f16HelloWorldAI response here

4. Verify the signature

You can verify the signature using either standard libraries (recommended) or manually.

Using standard libraries

use alloy_primitives::hex;
use alloy_signer::Signature;

// Parse the signature (65 bytes: r, s, v)
let signature_bytes = hex::decode(response_signature)?;
let signature = Signature::try_from(signature_bytes.as_slice())?;

// Recover the signer address
let recovered = signature.recover_address_from_msg(message.as_bytes())?;

Manual verification

If you prefer not to use libraries or want to understand the process, expand for the manual verification process:
  1. Add Ethereum Signed Message Prefix

    Prepend the standard Ethereum prefix to your message:

    "\x19Ethereum Signed Message:\n" + message_length + message

    Example:

    "\x19Ethereum Signed Message:\n42" + "1gpt-oss-120b-f16HelloWorldAI response here"

  2. Hash with Keccak256

    Compute the Keccak256 hash of the prefixed message. This produces a 32-byte hash.

  3. Parse the Signature

    The signature is 65 bytes encoded as 130 hex characters:

    • Bytes 0-31 (chars 0-63): r component
    • Bytes 32-63 (chars 64-127): s component
    • Byte 64 (chars 128-129): v component (recovery ID)
  4. Perform ECDSA public key recovery

    Using the secp256k1 elliptic curve:

    1. Take the 32-byte hash from step 2
    2. Take the r, s, v values from step 3
    3. Use ECDSA recovery algorithm to extract the public key.

    The recovery process uses the mathematical relationship between the signature components, the hash, and the original public key on the secp256k1 curve.

  5. Derive Ethereum address from public key

    1. Take the recovered 64-byte uncompressed public key (x and y coordinates)
    2. Hash it with Keccak256 (produces 32 bytes)
    3. Take the last 20 bytes
    4. Prepend "0x" for standard Ethereum address format

5. Compare addresses

Check that the recovered address matches the expected EigenAI signer:

EnvironmentChain IDSigner Address
Mainnet10x7053bfb0433a16a2405de785d547b1b32cee0cf3
Sepolia Testnet111551110xB876f1301b39c673554EE0259F11395565dCd295

The ECDSA signer can be looked up onchain in the KeyRegistrar contract using the Operator address. The deployed KeyRegistrar addresses for Mainnet and Sepolia testnet are listed in the eigenlayer-contracts repository.