71 lines
3.3 KiB
Markdown
71 lines
3.3 KiB
Markdown
# ASN.1 for Static Serialization - Compact Wire Format
|
|
|
|
## Goal
|
|
Use portable ASN.1 techniques to produce the most compact *deterministic* (stable/idempotent for hashing) wire format for gmserialization **static** encoding, based on existing templates.
|
|
|
|
Focus is on the wire format itself (not RLP translation for legacy, which is deferred).
|
|
|
|
## Approach
|
|
- The `asn1/GajumaruSerialization.asn` is the single source of truth (abstract syntax).
|
|
- Use **Unaligned PER (UPER)** as the standard compact canonical encoding rule provided by the ASN.1 framework.
|
|
- Portable across languages/tools that support ASN.1 UPER.
|
|
- Deterministic for a fixed schema (no extensibility, consistent packing).
|
|
- Optimize the schema for packing:
|
|
- Constrain INTEGER ranges.
|
|
- Provide `staticFields` (SEQUENCE OF Value) -- no field names (names are never on the wire for static case).
|
|
- Provide `CompactStatic` top-level type to avoid unnecessary CHOICE overhead for the common static path.
|
|
- Concrete SEQUENCEs for well-known objects (SignedTx, ContractV* etc.) when possible.
|
|
- Encode with the generated ASN.1 module: ` 'GajumaruSerialization':encode('CompactStatic', Value) `.
|
|
|
|
## Results (example sizes)
|
|
|
|
Using current optimized UPER:
|
|
|
|
- Tiny object (tag/vsn + int + 1-byte bin): 9 bytes (legacy RLP = 5)
|
|
- List of 3 ints: 13 bytes (legacy = 7)
|
|
- Signed tx example: 11 bytes (legacy = 7)
|
|
- 256-byte payload: ~263 bytes (legacy ~264) -- matches or slightly better
|
|
|
|
PER/UPER overhead is mainly the structural tags for the generic case. Concrete types and `staticFields` + `CompactStatic` minimize it.
|
|
|
|
Compared to DER (previous orientation): dramatically better (e.g. tiny case was ~36B in DER).
|
|
|
|
## Usage in Erlang (for the compact format)
|
|
|
|
```erlang
|
|
% Build value according to schema (using staticFields for best compactness)
|
|
Value = {'CompactStatic', Tag, Vsn, [
|
|
{'intValue', 42},
|
|
{'binaryValue', <<"data">>}
|
|
% ...
|
|
]},
|
|
|
|
{ok, CompactBytes} = 'GajumaruSerialization':encode('CompactStatic', Value).
|
|
```
|
|
|
|
Compile the schema with:
|
|
```
|
|
asn1ct:compile("GajumaruSerialization.asn", [uper]).
|
|
```
|
|
|
|
## Schema Notes
|
|
- `staticFields` should be used for generic static templates (mirrors legacy positional encoding).
|
|
- Concrete types (e.g. `signedTx`) are preferred when the structure is fixed.
|
|
- `TemplateFields` (with names) is kept for debug/transition but not optimal for wire size.
|
|
- The model directly reflects the static `template()` types from `gmserialization.erl`.
|
|
|
|
## Portability
|
|
Any language with an ASN.1 UPER codec can produce and consume the exact same bytes by using the schema and the same value construction rules.
|
|
|
|
## Stability
|
|
- UPER encoding of this schema is stable (tested roundtrip + re-encode identical).
|
|
- No random/padding choices.
|
|
- Same input value always produces identical bytes.
|
|
|
|
## Limitations / Future
|
|
- For very small objects, hand-crafted RLP is still smaller because it has almost no structural overhead.
|
|
- If an even more compact custom encoding is desired while keeping the model, a custom "encoding rule" can be implemented driven by the schema (similar to how the RLP layer works, but targeting a new bit-packed format).
|
|
- Dynamic encoder (gmser_dyn) is out of scope.
|
|
|
|
See also: `asn1/GajumaruSerialization.asn`, `asn1_compact/`, tests in `src/gmser_asn1_rlp.erl` (for value shapes), `doc/static.md`.
|