Updated asn1 experiment, now exploring PER and OER
Gajumaru Serialization Tests / tests (push) Successful in 12s

This commit is contained in:
Ulf Wiger
2026-07-08 10:53:31 +02:00
parent 9817af8a46
commit 4036133476
26 changed files with 10499 additions and 39 deletions
+70
View File
@@ -0,0 +1,70 @@
# 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`.
+2 -1
View File
@@ -59,7 +59,8 @@ The template 'language' is defined by these types:
```erlang
-type template() :: [{field_name(), type()}].
-type field_name() :: atom().
-type type() :: 'int'
-type type() :: 'int' % bignum (non-negative, for amounts etc. up to 10^30 Pucks)
| 'uint128' | 'uint64' | 'uint32' | 'uint16' | 'uint8'
| 'bool'
| 'binary'
| 'id' %% As defined in aec_id.erl