Cryptographic Algorithms Neo Uses for Digital Signatures and Transaction Validation
Neo employs three distinct cryptographic schemes—ECDSA on the Secp256r1 (NIST-P-256) curve, Ed25519, and BLS12-381—to verify digital signatures during transaction validation, selecting the appropriate algorithm based on the witness contract type detected in the transaction payload.
Understanding the cryptographic algorithms Neo uses for digital signatures is essential for developers building secure applications on the neo-project/neo blockchain. Neo's protocol implements a flexible, multi-algorithm architecture that verifies ownership and authorization through distinct cryptographic paths during transaction validation.
Neo's Cryptographic Algorithm Suite
Neo supports three primary signature algorithms, each optimized for different security and performance characteristics.
ECDSA Secp256r1 (NIST-P-256)
The default algorithm for standard user accounts and single-signature contracts, ECDSA on Secp256r1 provides industry-standard elliptic curve cryptography. In src/Neo/Cryptography/Crypto.cs, the VerifySignature method validates 64-byte signatures (concatenated r and s values) against public keys on the ECCurve.Secp256r1 curve.
This implementation serves as the foundation for most Neo transactions, including standard NEP-17 token transfers and smart contract invocations requiring single-party authorization.
Ed25519
Used primarily by native contracts such as CryptoLib, Ed25519 offers fast, deterministic signature generation with built-in resistance against side-channel attacks. The implementation resides in src/Neo/Cryptography/Ed25519.cs and is exposed to smart contracts through CryptoLib.VerifyWithEd25519 in src/Neo/SmartContract/Native/CryptoLib.cs.
Ed25519 signatures are 64 bytes and utilize the twisted Edwards curve, providing faster verification speeds compared to ECDSA for certain workloads.
BLS12-381
For advanced use cases requiring aggregate signatures and pairing-based cryptography, Neo implements BLS12-381. Defined in src/Neo/SmartContract/Native/CryptoLib.BLS12_381.cs, this algorithm allows multiple signatures to be combined into a single short proof.
BLS12-381 supports committee-based consensus scenarios and multi-signature contracts where signature aggregation reduces on-chain storage and verification costs.
Transaction Validation Architecture
Neo integrates these algorithms into a layered verification pipeline that processes every transaction before inclusion in a block.
Witness Structure and Contract Detection
Each transaction contains a list of Witness objects defined in src/Neo/Network/P2P/Payloads/Transaction.cs. Every witness consists of:
- Verification script – The locking script (redeem script) that defines the spending conditions
- Invocation script – The unlocking script that provides the actual signatures and parameters
Before selecting a cryptographic algorithm, the engine inspects the verification script using helpers in src/Neo/SmartContract/Helper.cs:
if (IsSignatureContract(witness.VerificationScript.Span) &&
IsSingleSignatureInvocationScript(witness.InvocationScript, out var signature))
{
// Route to single-signature ECDSA verification
}
else if (IsMultiSigContract(witness.VerificationScript.Span))
{
// Route to multi-signature verification logic
}
Single-Signature Verification Flow
For standard single-signature contracts, the validation process follows this sequence:
-
Public key extraction – The engine recovers the public key from the contract's redeem script using
Contract.CreateSignatureRedeemScript(pubkey)found insrc/Neo/SmartContract/Contract.cs. -
Sign data calculation – The transaction hash is computed via
ScriptContainer.GetSignData(network), referenced inApplicationEngine.Crypto.cs. -
Signature verification – The system calls
Crypto.VerifySignaturewith the Secp256r1 curve:
if (!Crypto.VerifySignature(this.GetSignData(settings.Network),
signature.Span,
pubkey,
ECCurve.Secp256r1))
return VerifyResult.InvalidSignature;
Multi-Signature and Native Contract Verification
Multi-signature contracts extract all public keys from the redeem script, then iterate through provided signatures, verifying each against the transaction hash using the same Crypto.VerifySignature routine.
Ed25519 verification occurs when native contracts require this specific scheme. The engine delegates to:
CryptoLib.VerifyWithEd25519(message, pubkey, signature);
BLS12-381 aggregate signatures are validated through CryptoLib.BLS12_381.cs, where VerifyBlsSignature performs pairing-based cryptographic checks to confirm that aggregated signatures correspond to the claimed set of public keys.
Practical Implementation Examples
Signing with ECDSA Secp256r1
Standard user transactions utilize the KeyPair class in src/Neo/Wallets/KeyPair.cs to generate signatures:
using Neo.Cryptography;
using Neo.Wallets;
// Generate Secp256r1 key pair
var keyPair = new KeyPair(privateKeyBytes);
byte[] message = System.Text.Encoding.UTF8.GetBytes("Neo transaction data");
// Create 64-byte signature (r || s)
byte[] signature = keyPair.Sign(message);
// Verify using static Crypto class
bool isValid = Crypto.VerifySignature(message, signature, keyPair.PublicKey, ECCurve.Secp256r1);
Creating Single-Signature Contracts
To lock funds to a specific public key, developers use Contract.CreateSignatureRedeemScript:
using Neo.SmartContract;
using Neo.Cryptography.ECC;
// Decode public key from bytes
ECPoint publicKey = ECPoint.DecodePoint(pubKeyBytes, ECCurve.Secp256r1);
// Generate the verification script
byte[] redeemScript = Contract.CreateSignatureRedeemScript(publicKey);
// Create contract object
var contract = new Contract
{
Script = redeemScript,
ParameterList = new[] { ContractParameterType.Signature }
};
During transaction validation, Neo extracts the public key from this script and verifies the provided signature against it.
Verifying Ed25519 Signatures
For contracts requiring Ed25519, native code paths invoke the specialized verifier:
using Neo.SmartContract.Native;
// message, pubKey (32 bytes), signature (64 bytes)
bool valid = CryptoLib.VerifyWithEd25519(messageBytes, ed25519PubKey, ed25519Signature);
BLS12-381 Aggregate Verification
Committee-based operations utilize BLS aggregation for efficiency:
// Verify aggregated signature against multiple public keys
bool result = CryptoLib.VerifyBlsAggregateSignature(
messageHash,
publicKeyG1Points,
aggregateSignatureG2
);
Summary
- Neo supports three cryptographic algorithms for digital signatures: ECDSA Secp256r1 (default), Ed25519 (native contracts), and BLS12-381 (aggregate signatures).
- Transaction validation relies on a Witness structure containing verification and invocation scripts, parsed by helper functions in
Helper.cs. - The engine automatically detects contract types (
IsSignatureContract,IsMultiSigContract) to route validation through the appropriate cryptographic primitive. - ECDSA verification uses
Crypto.VerifySignatureinCrypto.cs, while Ed25519 and BLS operations are handled through the nativeCryptoLibcontract.
Frequently Asked Questions
Which cryptographic curve does Neo use by default for standard user transactions?
Neo defaults to ECDSA on the Secp256r1 curve (also known as NIST-P-256) for standard user accounts and single-signature contracts. This implementation resides in src/Neo/Cryptography/Crypto.cs and produces 64-byte signatures consisting of the concatenated r and s values.
How does Neo handle multi-signature transaction validation?
Neo detects multi-signature contracts using IsMultiSigContract in src/Neo/SmartContract/Helper.cs. The engine extracts all public keys embedded in the redeem script, then iterates through the signatures provided in the invocation script, verifying each against the transaction hash using Crypto.VerifySignature until the required threshold of valid signatures is met.
What is the role of the CryptoLib native contract in Neo's signature validation?
CryptoLib in src/Neo/SmartContract/Native/CryptoLib.cs exposes advanced cryptographic primitives—including Ed25519 verification via VerifyWithEd25519 and BLS12-381 operations via CryptoLib.BLS12_381.cs—that standard smart contracts cannot access directly. This native contract enables deterministic Ed25519 validation and pairing-based BLS signature aggregation for committee and group signature scenarios.
Where is the transaction signature hash calculated in the Neo source code?
The transaction hash used for signature verification is calculated by GetSignData(network) defined in the transaction payload implementation (src/Neo/Network/P2P/Payloads/Transaction.cs). This method produces the exact byte sequence that signers must hash and sign to prove transaction authorization.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →