The VM<->Node RPC plane is ZAP. Period. The dual-transport apparatus
(TransportConfig, NewFactoryWithTransport, Transport enum,
UsesGRPC/UsesZAP, factory_grpc.go vs factory_zap.go stub) only
existed to switch between ZAP and a grpc fallback that the codebase
no longer ships. Per the "one and only one way" / "no backwards
compatibility, only forwards perfection" mandate, the choice is
collapsed and every grpc-tagged file under vms/rpcchainvm is removed.
Deletions (36 files, ~4.3K lines):
- factory_grpc.go, factory_zap.go, transport.go (the dual-transport
routing + Transport enum)
- vm.go, vm_client.go, vm_server.go, block_adapter.go, *_test.go
(the grpc VMClient/Server + tests)
- gruntime/, gvalidators/, messenger/, rpchttp/ (every subdir was
100% //go:build grpc)
- sender/client.go, sender/server.go (grpc Sender wire impls;
sender.go + zap_client.go + zap_server.go stay)
- runtime/subprocess/runtime_grpc.go (the gRPC subprocess.Bootstrap;
runtime_zap.go is now the only Bootstrap)
- vms/platformvm/warp/rpcwarp/signer_test.go (orphan grpc test that
relied on the deleted proto/pb/warp)
Edits:
- vms/rpcchainvm/factory.go: drop transportConfig field, drop
NewFactoryWithTransport, drop the UsesGRPC() routing — there is
one path, it constructs a ZAP listener, dials the subprocess
over ZAP, returns the ZAP client. No branching.
- vms/rpcchainvm/runtime/subprocess/runtime_zap.go: drop the
`//go:build !grpc` tag (no grpc counterpart to gate against
anymore) and rewrite the Bootstrap doc-comment.
go mod tidy result:
- direct dep `google.golang.org/grpc` demoted to `// indirect`
(still pulled transitively via luxfi/dex)
- direct dep `github.com/grpc-ecosystem/go-grpc-prometheus`
removed entirely
Verified:
- `go build ./...` (default, no tags) clean
- `go test -count=1 ./vms/rpcchainvm/...` clean
- grep -rln 'google.golang.org/grpc' --include='*.go' under node/
returns zero (the only google.golang.org/grpc strings left are
in go.mod/go.sum/README/RELEASES/ci.yml/proto/Dockerfile)
- grep 'grpc.Dial|NewServer|NewClient' in rpcchainvm returns zero
Lux Interchain Messaging
Lux Interchain Messaging (ICM) provides a primitive for cross-chain communication on the Lux Network.
The Lux P-Chain provides an index of every network's validator set on the Lux Network, including the BLS public key of each validator (as of the Banff Upgrade). ICM utilizes the weighted validator sets stored on the P-Chain to build a cross-chain communication protocol between any two networks on Lux.
Any Virtual Machine (VM) on Lux can integrate Lux Interchain Messaging to send and receive messages cross-chain.
Background
This README assumes familiarity with:
- Lux P-Chain / PlatformVM
- ProposerVM
- Basic familiarity with BLS Multi-Signatures
BLS Multi-Signatures with Public-Key Aggregation
Lux Interchain Messaging utilizes BLS multi-signatures with public key aggregation in order to verify messages signed by another network. When a validator joins a network, the P-Chain records the validator's BLS public key and NodeID, as well as a proof of possession of the validator's BLS private key to defend against rogue public-key attacks.
ICM utilizes the validator set's weights and public keys to verify that an aggregate signature has sufficient weight signing the message from the source network.
BLS provides a way to aggregate signatures off chain into a single signature that can be efficiently verified on chain.
ICM Serialization
Unsigned Message:
+---------------+----------+--------------------------+
| codecID : uint16 | 2 bytes |
+---------------+----------+--------------------------+
| networkID : uint32 | 4 bytes |
+---------------+----------+--------------------------+
| sourceChainId : [32]byte | 32 bytes |
+---------------+----------+--------------------------+
| payload : []byte | 4 + size(payload) |
+---------------+----------+--------------------------+
| 42 + size(payload) bytes|
+--------------------------+
codecIDis the codec version used to serialize the payload and is hardcoded to0x0000networkIDis the unique ID of a Lux Network (Mainnet/Testnet) and provides replay protection for BLS Signers across different Lux NetworkssourceChainIDis the hash of the transaction that created the blockchain on the Lux P-Chain. It serves as the unique identifier for the blockchain across the Lux Network so that each blockchain can only sign a message with its own id.payloadprovides an arbitrary byte array containing the contents of the message. VMs define their own message types to include in thepayload
BitSetSignature:
+-----------+----------+---------------------------+
| type_id : uint32 | 4 bytes |
+-----------+----------+---------------------------+
| signers : []byte | 4 + len(signers) |
+-----------+----------+---------------------------+
| signature : [96]byte | 96 bytes |
+-----------+----------+---------------------------+
| 104 + size(signers) bytes |
+---------------------------+
typeIDis the ID of this signature type, which is0x00000000signersencodes a bitset of which validators' signatures are included (a bitset is a byte array where each bit indicates membership of the element at that index in the set)signatureis an aggregated BLS Multi-Signature of the Unsigned Message
BitSetSignatures are verified within the context of a specific P-Chain height. At any given P-Chain height, the PlatformVM serves a canonically ordered validator set for the source network (validator set is ordered lexicographically by the BLS public key's byte representation). The signers bitset encodes which validator signatures were included. A value of 1 at index i in signers bitset indicates that a corresponding signature from the same validator at index i in the canonical validator set was included in the aggregate signature.
The bitset tells the verifier which BLS public keys should be aggregated to verify the interchain message.
Signed Message:
+------------------+------------------+-------------------------------------------------+
| unsigned_message : UnsignedMessage | size(unsigned_message) |
+------------------+------------------+-------------------------------------------------+
| signature : Signature | size(signature) |
+------------------+------------------+-------------------------------------------------+
| size(unsigned_message) + size(signature) bytes |
+-------------------------------------------------+
Sending a Lux Interchain Message
A blockchain on Lux sends a Lux Interchain Message by coming to agreement on the message that every validator should be willing to sign. As an example, the VM of a blockchain may define that once a block is accepted, the VM should be willing to sign a message including the block hash in the payload to attest to any other network that the block was accepted. The contents of the payload, how to aggregate the signature (VM-to-VM communication, off-chain relayer, etc.), is left to the VM.
Once the validator set of a blockchain is willing to sign an arbitrary message M, an aggregator performs the following process:
- Gather signatures of the message
MfromNvalidators (where theNvalidators meet the required threshold of stake on the destination chain) - Aggregate the
Nsignatures into a multi-signature - Look up the canonical validator set at the P-Chain height where the message will be verified
- Encode the selection of the
Nvalidators included in the signature in a bitset - Construct the signed message from the aggregate signature, bitset, and original unsigned message
Verifying / Receiving a Lux Interchain Message
Lux Interchain Messages are verified within the context of a specific P-Chain height included in the ProposerVM's header. The P-Chain height is provided as context to the underlying VM when verifying the underlying VM's blocks (implemented by the optional interface WithVerifyRuntime).
To verify the message, the underlying VM utilizes this warp package to perform the following steps:
- Lookup the canonical validator set of the network sending the message at the P-Chain height
- Filter the canonical validator set to only the validators claimed by the signature
- Verify the weight of the included validators meets the required threshold defined by the receiving VM
- Aggregate the public keys of the claimed validators into a single aggregate public key
- Verify the aggregate signature of the unsigned message against the aggregate public key
Once a message is verified, it is left to the VM to define the semantics of delivering a verified message.
Design Considerations
Processing Historical Lux Interchain Messages
Verifying a Lux Interchain Message requires a lookup of validator sets at a specific P-Chain height. The P-Chain serves lookups maintaining validator set diffs that can be applied in-order to reconstruct the validator set of any network at any height.
As the P-Chain grows, the number of validator set diffs that needs to be applied in order to reconstruct the validator set needed to verify a Lux Interchain Messages increases over time.
Therefore, in order to support verifying historical Lux Interchain Messages, VMs should provide a mechanism to determine whether a Lux Interchain Message was treated as valid or invalid within a historical block.
When nodes bootstrap in the future, they bootstrap blocks that have already been marked as accepted by the network, so they can assume the block was verified by the validators of the network when it was first accepted.
Therefore, the new bootstrapping node can assume the block was valid to determine whether a Lux Interchain Message should be treated as valid/invalid within the execution of that block.
Two strategies to provide that mechanism are:
- Require interchain message validity for transaction inclusion. If the transaction is included, the interchain message must have passed verification.
- Include the results of interchain message verification in the block itself. Use the results to determine which messages passed verification.
Warp 1.5: Quantum-Safe Cross-Chain Messaging
Warp 1.5 extends Lux Interchain Messaging with post-quantum cryptographic security using Corona threshold signatures and ML-KEM encryption.
Signature Types
Warp 1.5 introduces new signature types for quantum-safe messaging:
- BitSetSignature (Warp 1.0): Classical BLS aggregate signatures
- CoronaSignature (Warp 1.5 - Recommended): Post-quantum threshold signatures using LWE
- EncryptedWarpPayload (Warp 1.5): ML-KEM + AES-256-GCM encrypted cross-chain payloads
- HybridBLSRTSignature (Deprecated): BLS + Corona hybrid for transition period
CoronaSignature
Corona is a lattice-based threshold signature scheme from LWE (Learning With Errors).
- Paper: https://eprint.iacr.org/2024/1113
- Implementation: github.com/luxfi/corona
- Properties:
- Post-quantum secure (based on LWE hardness)
- Native threshold support (t-of-n signing in 2 rounds)
- No need for separate TSS layer
+---------------+----------+---------------------------+
| type_id : uint32 | 4 bytes |
+---------------+----------+---------------------------+
| signers : []byte | 4 + len(signers) |
+---------------+----------+---------------------------+
| signature : []byte | 4 + len(signature) |
+---------------+----------+---------------------------+
EncryptedWarpPayload
For confidential cross-chain messaging, Warp 1.5 provides ML-KEM encryption (FIPS 203).
Use cases:
- Private bridge transfers (hidden amounts/recipients)
- Sealed-bid cross-chain auctions
- Confidential governance votes
- MEV protection (encrypt intent until committed)
+--------------------+----------+---------------------------------+
| encapsulated_key : []byte | 4 + 1088 (ML-KEM-768) |
+--------------------+----------+---------------------------------+
| nonce : []byte | 4 + 12 (AES-GCM nonce) |
+--------------------+----------+---------------------------------+
| ciphertext : []byte | 4 + len(ciphertext) |
+--------------------+----------+---------------------------------+
| recipient_key_id : []byte | 4 + len(recipient_key_id) |
+--------------------+----------+---------------------------------+
Teleport: Cross-Chain Bridge Integration
Teleport is the high-level cross-chain bridging protocol built on Warp 1.5:
// TeleportMessage wraps a Warp message for cross-chain transfer
type TeleportMessage struct {
Version uint8 // Teleport protocol version
MessageType TeleportType // Transfer, Swap, Lock, Unlock, etc.
Payload []byte // Application-specific data
Encrypted bool // Whether payload is encrypted
}
// TeleportTypes for cross-chain operations
const (
TeleportTransfer TeleportType = iota // Asset transfer
TeleportSwap // Cross-chain swap
TeleportLock // Lock assets on source
TeleportUnlock // Unlock assets on dest
TeleportAttest // Attestation message
TeleportGovernance // Cross-chain governance
)
Migration Path
- Pre-quantum (Current): BLS-only (
BitSetSignature) - Transition: Support both BLS and Corona signatures
- Post-quantum (Warp 1.5): Corona-only (
CoronaSignature) recommended
Security Levels
| Component | Algorithm | Security Level |
|---|---|---|
| Threshold Signatures | Corona (LWE) | Post-quantum secure |
| Key Encapsulation | ML-KEM-768 | NIST Level 3 (192-bit PQ) |
| Symmetric Encryption | AES-256-GCM | 256-bit classical |
| Legacy Signatures | BLS | Classical (for compatibility) |