Cryptography
Cryptography
The XE network uses a small set of well-established cryptographic primitives. All implementations -- Go node, CLI client, web wallet -- must produce identical outputs for the same inputs.
Key generation
Algorithm: Ed25519
Two modes of key generation:
Function
Description
GenerateKeyPair()
Generate a random ed25519 keypair using crypto/rand
KeyPairFromSeed(seed)
Deterministic derivation from a 32-byte seed. Panics on invalid seed length.
TryKeyPairFromSeed(seed)
Like KeyPairFromSeed but returns an error instead of panicking for invalid seed length. Use for untrusted input.
KeyPairFromSeed always produces the same keypair for a given seed. This is how the standalone CLI and web wallet derive keys -- the user stores only the seed.
Account addresses
An account address is the hex-encoded ed25519 public key -- 64 hexadecimal characters (32 bytes).
Example: a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2There is no checksum, prefix, or other encoding. The raw public key bytes in hex are the address.
Hashing
Two hash functions are used for different purposes:
Algorithm
Use
Digest size
SHA-256
Block content hashing
32 bytes
Blake2b
Proof of work
8 bytes (truncated)
Block hashing
The block hash is SHA-256(canonical_bytes) where canonical_bytes is the output of MarshalBlockCanonical. The hash is hex-encoded for storage and display.
[!IMPORTANT] Important The canonical encoding excludes the PoW nonce. The hash covers only the content that the account holder signs. See Binary Encoding for the exact byte layout.
Signing
Block signing
Ed25519 signatures over the SHA-256 hash of canonical block bytes.
hash = SHA-256(MarshalBlockCanonical(block))
signature = ed25519.Sign(privateKey, hash)SignBlock computes the hash and signs in one step. VerifyBlock recomputes the hash from the block fields and verifies the signature against the account's public key (the account address, hex-decoded).
Vote signing
Representatives sign votes over the canonical vote binary encoding:
payload = EncodeVote(vote) // without the signature fields
signature = ed25519.Sign(repPrivateKey, payload)See Binary Encoding for the vote wire format.
Attestation signing
Timekeepers sign lease attestations:
data = SHA-256(leaseHash || timestamp)
signature = ed25519.Sign(timekeeperKey, data)Where || denotes concatenation and timestamp is the attestation timestamp as a string.
Chat signing
P2P chat messages carry ed25519 detached signatures over the message envelope (serialized message content). This proves the sender's identity without requiring the recipient to trust the relay.
Directory signing
Account directory registrations are signed:
data = account + timestamp
signature = ed25519.Sign(privateKey, data)Where account is the hex address and timestamp is a string representation.
State chain signing
DAO state chain blocks are signed over the SHA-256 hash of the serialized block operations:
hash = SHA-256(serializedOperations)
signature = ed25519.Sign(memberKey, hash)Multiple DAO members sign the same hash to reach the signing threshold.
Web wallet implementation
The web wallet uses JavaScript equivalents that must produce byte-identical results:
Go
JavaScript
Purpose
crypto/ed25519
tweetnacl.js
Key generation, signing, verification
crypto/sha256
Web Crypto API (subtle.digest)
Block hashing
golang.org/x/crypto/blake2b
blakejs
Proof of work
[!WARNING] Cross-implementation compatibility The canonical encoding must match byte-for-byte between Go and JavaScript. A single byte difference in the canonical form produces a completely different hash and an invalid signature. Both implementations use
VERSION_BYTE = 0x02, identical type bytes, and identical field ordering.
Summary
┌─────────────────────────────────────────────┐
│ Cryptographic Flow │
├─────────────────────────────────────────────┤
│ │
│ seed (32 bytes) │
│ │ │
│ ▼ │
│ KeyPairFromSeed(seed) │
│ ├── publicKey (32 bytes) = address │
│ └── privateKey (64 bytes) │
│ │
│ Block signing: │
│ canonical = MarshalBlockCanonical(block) │
│ hash = SHA-256(canonical) │
│ sig = ed25519.Sign(privateKey, hash) │
│ │
│ Block verification: │
│ hash = SHA-256(MarshalBlockCanonical(b)) │
│ ok = ed25519.Verify(pubKey, hash, sig) │
│ │
│ Proof of work: │
│ result = Blake2b_8(nonce_LE || hash) │
│ valid = result >= difficulty │
│ │
└─────────────────────────────────────────────┘See also
- Binary Encoding -- canonical byte layout for hashing
- Proof of Work -- Blake2b PoW algorithm
- Wallet Security -- AES-GCM seed encryption in the browser
- Accounts and Keys -- account model and key concepts