Skip to content

NEP: Standard for Offline Message Signing and Verification #210

@adrian-fjellberg

Description

@adrian-fjellberg
NEP: XXX
Title: Standard for Offline Message Signing and Verification
Author: Adrian (atlazor)
Discussions-To: https://github.com/neo-project/proposals/issues
Status: Draft
Type: Standards Track
Category: Core
Created: 2025-11-10 

Simple Summary

Define a standardized JSON format and signing algorithm specification for offline message signing in Neo N3 CLI and compatible wallets, ensuring consistent and verifiable results across implementations.

Abstract

This NEP introduces a standard for offline message signing and verification. It defines:

  1. A canonical JSON structure for the signed message output.
  2. A versioning convention for signing standards (e.g., NEP-XXX.1).
  3. The algo property to identify the algorithm used for message payload construction.
  4. The curve property to define the elliptic curve used for signing.

The initial algorithm, nep33_safe_message_v1, provides a secure method of signing arbitrary messages without risk of the resulting signature being interpreted as a valid Neo transaction.

Motivation

Governance candidates, node operators, and automated agents often need to sign arbitrary messages securely and verifiably using Neo wallets or CLI tools. Currently, there is no standard output format or canonical signing algorithm for this process.

Different wallets have implemented ad-hoc approaches for signing messages, leading to verification inconsistencies and interoperability issues.

The goal of NEP-33 is to unify how offline messages are signed, serialized, and verified across the Neo ecosystem.

Specification

The standard defines both the output format and the algorithmic method for constructing the payload to be signed.

JSON Output Format

The standardized JSON object MUST include the following fields:

{
  "version": "NEP-XXX.1",
  "algo": "nepXXX_safe_message_v1",
  "curve": "secp256r1",
  "signedPayloadBase64": "AQAB8MmMZCPvdYfAA7ScAZZiw8NLil8isWvxfs5Q...AA==",
  "signatures": [
    {
      "address": "NZf33mJcBxW6ZjYGRcbvV2eiVigFD3g2Ak",
      "publicKey": "03a9321588342aaecca1f4983a5bca1b16e460ed3d07e40a5d9f76ae7077d9779d",
      "signature": "b8170ac6c93a0b79...",
      "salt": "42a0df62e01367f430842f2f551d46a4"
    }
  ]
}

Field Descriptions

  • version — NEP reference and sub-version (e.g., NEP-XXX.1).

  • algo — The algorithm used to construct the signed payload.

  • curve — Elliptic curve used for signing (secp256r1, secp256k1, etc.).

  • signedPayloadBase64MUST be the exact byte sequence that was signed, encoded in base64 (no 0x prefix or hex). This enables unambiguous reconstruction and verification across languages and platforms.

  • signatures — List of signature entries, one for each signing account.

    • address — Neo N3 address of the signer.
    • publicKey — Compressed public key of the signer.
    • signature — Hex-encoded signature.
    • salt — Random 16-byte hex string used in payload construction.

Encoding Rules:

  • Implementations MUST base64-encode the raw payload bytes as signedPayloadBase64.
  • Implementations SHOULD NOT include a duplicate hex-encoded payload field; hex can be ambiguous across environments (e.g., 0x prefixes).
  • If a hex form is exposed for debugging, it MUST be named signedPayloadHex and is OPTIONAL.

Algorithm Definitions

nepXXX_safe_message_v1

The nepXXX_safe_message_v1 aims to prevent message signatures from being valid Neo transactions by embedding the message inside a non-transactional payload.

Payload Construction:

010001f0 + VarBytes(Salt + Message) + 0000

Verification Steps:

  1. Rebuild the payload using the provided salt and message data according to the defined algorithm.
  2. Apply the chosen elliptic curve (curve) and signature scheme.
  3. Verify using the provided publicKey and signature.

Security Rationale:
The prefix 010001f0 and suffix 0000 ensure the signed payload cannot be interpreted as a valid Neo transaction, mitigating the risk of transaction replay or signature misuse.

Rationale

A common, machine-readable format for offline message signing simplifies cross-tool verification, governance audits, and automated attestation mechanisms. It also ensures that node operators and wallets can independently verify message authenticity without requiring a running Neo node.

Backward Compatibility

This proposal introduces new functionality and does not break any existing behavior. Future wallet or CLI implementations can adopt NEP-XXX incrementally.

Reference Implementation

The Neo CLI implementation added by Adrian (atlazor) in November 2025:
https://github.com/neo-project/neo/blob/master/src/Neo.CLI/CLI/MainService.Wallet.cs

[ConsoleCommand("sign message", Category = "Wallet Commands")]
private void OnSignMessageCommand(string message)

Payload construction follows:

010001f0 + VarBytes(Salt + Message) + 0000

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions