Transaction Signing
This document describes how to manually sign transactions on the Constellation Network. Understanding the transaction signing process is crucial for developers implementing custom signing solutions in various programming languages or integrating with the Constellation Network.
Overview
Constellation Network supports two distinct methods for transaction signing:
DAG/L0 Token Transactions: Uses Kryo serialization without compression
Other Transaction Types: Uses Brotli compression for serialization (TokenLock, AllowSpend, DelegatedStake, etc.)
In the long term, DAG and L0 token transactions will likely be migrated to use the same brotli compression as the newer transaction types but for now, the Kryo serialization method is maintained for backwards compatibility.
Transaction Format
All transactions in the Constellation Network, regardless of type, are submitted to the network using a standard format:
Key components of this format:
value: Contains the transaction body with all relevant transaction details
proofs: An array of signatures that validate the transaction
Currently, all transactions require exactly one proof in the array
The array structure supports future multi-signature functionality
Each proof contains:
id: The public key of the signer
signature: The signature of the transaction body, created using the corresponding private key
The different transaction signing methods described in this document ultimately produce transaction data in this standard format, though the specific contents of the value
field and the method of generating the signature in the proofs
array will differ based on the transaction type.
Prerequisites
To sign transactions, you need:
A private key
A public key
Transaction details to be signed
Understanding of cryptographic operations: SHA-256, SHA-512, and secp256k1 ECDSA signing
1. DAG/L0 Token Transaction Signing
DAG or L0 token transactions follow this signing process:
1.1 Transaction Structure
For token transactions, the following fields are required:
source
: Sender addressdestination
: Recipient addressamount
: Transaction amount (in smallest unit, e.g., 1 DAG = 100,000,000 units)fee
: Transaction fee (in smallest unit)parent
: Last transaction reference (hash and ordinal)salt
: Random value to ensure unique transaction hashes
1.2 Transaction Preparation
Create a transaction object with the required fields
Format the transaction according to the network's expected structure (v2 format)
Encode the transaction into a specific format that concatenates fields with their lengths
1.3 Kryo Serialization
The encoded transaction is serialized using Kryo serialization, which follows these steps:
Create a prefix using the format:
03
(fixed) + UTF-8 encoded lengthConvert the encoded transaction to UTF-8 bytes
Convert the UTF-8 bytes to hexadecimal format
Concatenate the prefix with the hexadecimal transaction
Example pseudo-code for Kryo serialization:
The UTF-8 encoded length is variable-length encoded with specific bit patterns:
Bit 8 denotes UTF-8
Bit 7 denotes if another byte is present
1.4 Hash Computation
Compute the SHA-256 hash of the Kryo-serialized transaction bytes:
1.5 Signature Generation
Sign the hash using ECDSA with the secp256k1 curve and the private key:
Compute SHA-512 hash of the transaction hash
Sign the SHA-512 hash with the private key using secp256k1 ECDSA
Format the signature according to the expected format (often DER encoded and converted to hexadecimal)
1.6 Verification (Optional)
To verify the signature:
Use the public key to verify the signature against the same SHA-512 hash
Ensure the signature verification passes
2. Other Transaction Types (TokenLock, AllowSpend, DelegatedStake, etc.)
For other transaction types, the signing process uses Brotli compression:
2.1 Transaction Normalization
Before serialization, normalize the transaction object:
Sort object keys alphabetically
Remove null/undefined values
Convert the object to a consistent format
2.2 Brotli Serialization
Serialize the normalized transaction using Brotli compression:
Convert the normalized JSON to a string
Encode the string as UTF-8 bytes
Compress the bytes using Brotli compression (typically with compression level 2)
2.3 Hash Computation
Compute the SHA-256 hash of the Brotli-compressed data:
2.4 Signature Generation
Sign the hash with the private key:
Compute SHA-512 hash of the message hash
Sign the SHA-512 hash with the private key using secp256k1 ECDSA
Format the signature according to the expected format
2.5 Result
The final result should be structured as:
Implementation Considerations
Key Format
Private keys should be in hexadecimal format without the "0x" prefix
Public keys for verification can be in compressed or uncompressed format
When using uncompressed public keys, they may need the "04" prefix
Transaction Amounts
Transaction amounts and fees should be represented in the smallest unit (datum)
Example: 1 DAG = 100,000,000 datum (8 decimal places)
Amounts should be integers after being multiplied by 10^8
Hash Functions
SHA-256 and SHA-512 implementations should follow the standard specifications
Input to hash functions should be byte arrays, not hexadecimal strings
ECDSA Signing
Use secp256k1 curve for ECDSA signing
Sign the SHA-512 hash of the message, not the message directly
DER encoding is commonly used for the signature format
Last updated
Was this helpful?