Cross-Language Interoperability
A core design goal of MetaMUI Crypto Primitives is verified interoperability: a key generated in one language can be used in any other, and a signature produced in one language can be verified in all others. This is achieved through strict adherence to standard wire formats and extensive cross-language testing.
How It Works
Cross-language interoperability is built on three principles:
- Standard wire formats – All implementations encode keys and signatures using the same byte-level format (NIST encodings for PQC algorithms, RFC encodings for classical algorithms).
- Shared test vectors – A single set of test vectors is generated by the C reference implementation and verified by every other language.
- Deterministic verification – Given the same public key, message, and signature bytes, every implementation must produce the same accept/reject decision.
Falcon Cross-Language Verification
Falcon-512 and Falcon-1024 have the most thorough cross-language testing, covering 8 languages with full round-trip verification.
Test Vector Generation
The C implementation serves as the reference. It generates test vectors consisting of:
- 5 distinct messages per parameter set (Falcon-512 and Falcon-1024)
- For each message: a key pair (public key + secret key) and a signature
- All encoded using NIST standard byte formats
Test vector files:
test-vectors/falcon512_cross_lang.jsontest-vectors/falcon1024_cross_lang.json
Verification Chain
Each language loads the C-generated test vectors and verifies every signature against the corresponding public key and message. The full verification chain is:
C → Go → Rust → Python → Java → Kotlin → C# → Swift
Results
| Language | Falcon-512 | Falcon-1024 | Total Tests |
|---|---|---|---|
| C | generates vectors | generates vectors | reference |
| Go | 5/5 pass | 5/5 pass | 10/10 |
| Rust | 5/5 pass | 5/5 pass | 10/10 |
| Python | 1/1 pass | 1/1 pass | 2/2 |
| Java | 1/1 pass | 1/1 pass | 2/2 |
| Kotlin | 1/1 pass | 1/1 pass | 2/2 |
| C# | 1/1 pass | 1/1 pass | 2/2 |
| Swift | 5/5 pass | 5/5 pass | 10/10 |
All implementations produce identical accept/reject decisions for all test vectors.
NIST Encoding Standard
All platforms use the same byte-level encoding for Falcon keys and signatures. The first byte of each encoded object is a header byte that identifies the object type and parameter set:
Public Key
Header: 0x00 | logn
- Falcon-512 (logn=9): header byte
0x09 - Falcon-1024 (logn=10): header byte
0x0A
Secret Key
Header: 0x50 | logn
- Falcon-512: header byte
0x59 - Falcon-1024: header byte
0x5A
Signature
Header: 0x30 | logn
- Falcon-512: header byte
0x39 - Falcon-1024: header byte
0x3A
The signature uses compressed encoding (variable-length), where the actual byte length depends on the entropy of the signature polynomial.
KAT Vector Coverage
Beyond cross-language vectors, MetaMUI validates against known-answer test (KAT) vectors from:
- NIST CAVP/ACVP – The Cryptographic Algorithm Validation Program vectors used for FIPS certification testing
- KPQC vectors – Test vectors published alongside the Korean PQC algorithm specifications
These vectors ensure that each implementation not only agrees with other MetaMUI implementations but also with the external reference implementations published by algorithm designers and standards bodies.
WASM / TypeScript Note
The TypeScript/WASM implementation uses a non-NIST encoding format: 896-byte public keys and 666-byte fixed-length signatures. This is because the WASM build compiles Falcon from Rust using a different serialization path. The underlying cryptographic operations are correct – verified by compiling and testing against the same Rust core – but the wire format is not directly compatible with the NIST-encoded formats used by the other 8 platforms.
Applications that need to exchange Falcon keys or signatures between WASM and other platforms should perform format conversion at the boundary.
Adding Interoperability for New Algorithms
The same cross-language verification approach applies to all algorithms in the MetaMUI suite:
- Choose a reference implementation (typically C or Rust) to generate test vectors.
- Serialize keys, ciphertexts, and signatures using the algorithm’s standard encoding.
- Write test vector files in JSON format with hex-encoded byte strings.
- Implement verification tests in each target language that load and validate the vectors.
For more details on getting started with a specific platform, see Getting Started.