---
title: "EIP-2098 — Compact Signatures"
description: "EIP-2098 — Compact Signatures mapped to Neo N3."
---
# EIP-2098 — Compact Signatures
[Back to Protocol-Level EIPs](/standards-mirror/protocol-eips)
<StandardsMirror>
<StandardEntry
id="eip-2098"
title="EIP-2098 — Compact Signatures"
eip="2098"
status="Final"
neoMapping="Native (Neo signatures already compact)"
category="Signatures"
parityLabel="Native"
parityClass="sm-pill-native"
>
<template #spec>
## EIP-2098: Compact Signature Representation
ECDSA signatures on the secp256k1 curve consist of `(r, s, v)` where `r` and `s`
are 32-byte field elements and `v` is the recovery byte (1 bit, but stored as a
full byte for alignment reasons → 65 bytes total).
EIP-2098 packs `v` into the high bit of `s`: since secp256k1 enforces low-`s`
canonicality (EIP-2 / EIP-2098 itself), the high bit of `s` is always 0, so it
can carry the recovery bit. Result: 64-byte signatures instead of 65.
### Why It Matters
- Smart contract storage and calldata cost reduction.
- Off-chain protocols that bundle many signatures (multi-sigs, DAOs) save 1.5%.
- Cleaner compatibility with EVM contracts that take `bytes32` slot-aligned signatures.
### Neo Equivalent
Neo signatures are 64 bytes natively. The verification curve is **secp256r1**
(NIST P-256, ECDSA), and the signature format is `(r, s)` directly — no recovery
byte because Neo verification doesn't need to recover the public key from the
signature (the public key is in the witness script).
::: tip Live on Neo TestNet
Both implementations are deployed on Neo N3 TestNet (network magic `894710606`).
| **Solidity** (`neo-solc`) | `0xd63ea34d63f0628c4cd413f58aa1c2623b1121d9` | (reused — see [`0xd63ea34d63f0628c4cd413f58aa1c2623b1121d9`](https://dora.coz.io/contract/neo3/testnet/0xd63ea34d63f0628c4cd413f58aa1c2623b1121d9)) |
| **Neo C#** (`nccs`) | `0xb2701b6d89a734b5a865a1ec6c247466391c4eee` | (reused — see [`0xb2701b6d89a734b5a865a1ec6c247466391c4eee`](https://dora.coz.io/contract/neo3/testnet/0xb2701b6d89a734b5a865a1ec6c247466391c4eee)) |
Checked-in snapshot: Solidity 2 / 2 assertions pass; Neo C# 2 / 2 assertions pass. This is a validation snapshot, not an all-green parity certification; see [TestNet Results](/standards-mirror/deployments/RESULTS) for failure details.
Source pairs: [`docs/standards-mirror/deployments/eip-2098/`](https://github.com/r3e-network/neo-devpack-solidity/tree/main/docs/standards-mirror/deployments/eip-2098).
:::
</template>
<template #solidity>
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
library Compact2098 {
/// Decode a 64-byte EIP-2098 signature into (v, r, s).
function decode(bytes32 r, bytes32 vs)
internal pure returns (uint8 v, bytes32 r_, bytes32 s)
{
v = uint8((uint256(vs) >> 255) + 27);
s = bytes32(uint256(vs) & ((1 << 255) - 1));
r_ = r;
}
/// Recover the signer of a hash given a 2098 compact signature.
function recover(bytes32 hash, bytes32 r, bytes32 vs)
internal pure returns (address)
{
(uint8 v, , bytes32 s) = decode(r, vs);
return ecrecover(hash, v, r, s);
}
}
```
</template>
<template #csharp>
```csharp
using Neo;
using Neo.SmartContract.Framework;
using Neo.SmartContract.Framework.Attributes;
using Neo.SmartContract.Framework.Native;
namespace R3E.Examples;
/// <summary>
/// Neo signatures are 64 bytes from the start — there's no compaction to apply.
///
/// Verification uses CryptoLib.VerifyWithECDsa which takes the raw 64-byte
/// signature plus a public key (because Neo doesn't do recovery). The public
/// key is part of the verification script — the protocol already knows it
/// when verifying transaction witnesses.
/// </summary>
[DisplayName("SigVerify")]
public class SigVerify : SmartContract
{
public static bool Verify(ByteString message, ECPoint pubKey, ByteString signature)
{
// signature.Length must be 64. CryptoLib enforces this.
return CryptoLib.VerifyWithECDsa(message, pubKey, signature, NamedCurve.secp256r1);
}
}
```
### Curve Note
Neo verifies on the **NIST P-256 (secp256r1)** curve, which is implemented in
hardware on most modern phones (Apple Secure Enclave, Android StrongBox), unlike
Ethereum's secp256k1 which doesn't have widespread hardware support. This means
Neo signatures can be produced inside hardware security modules out of the box —
useful for biometric authentication and secure-element wallets.
</template>
</StandardEntry>
</StandardsMirror>