As part of the message router design, some structures are specified as ‘Cstructs’, which are basically a way of tightly packing bytes together with the layout of a ‘struct’ in C, but in OCaml.
My concern is that it’s not the right time in the project to introduce them: they break type safety, introduce run-time errors and require a lot of mental effort to properly use. Thoughts?
And, can what I’ve written below be improved?
Specifically:
Given this specification from the doc:
typedef uint8_t Curve25519PubKey[32];
typedef uint8_t EdDSASig[64];
typedef uint8_t Blake3Hash[32];
enum MessageType {
UNICAST = 0,
MULTICAST = 1,
CBOR = 2
};
struct MessageHeader {
uint16_t size;
uint16_t type;
};
struct UnicastMessage {
struct MessageHeader header;
uint32_t flags;
uint32_t ttl;
Curve25519Pubkey source;
Curve25519Pubkey destination;
Curve25519Pubkey via;
EdDSASig signature;
};
struct MulticastMessage {
struct MessageHeader header;
uint32_t flags;
uint32_t ttl;
Blake3Hash seen[4];
Curve25519PubKey group;
Curve25519PubKey via;
EdDSASig signature;
};
this is how I got it working using OCaml’s Cstructs. (Note, skipping the enum for now).
[%%cstruct
type unicast_message = {
message_header_size: uint16_t;
message_header_type: uint16_t;
flags: uint32_t;
ttl: uint32_t;
source: uint8_t [@len 32]; (* Curve25519Pubkey *)
destination: uint8_t [@len 32]; (* Curve25519Pubkey *)
via: uint8_t [@len 32]; (* Curve25519Pubkey *)
signature: uint8_t [@len 64]; (* EdDSASig *)
} [@@big_endian]]
[%%cstruct
type multicast_message = {
message_header_size: uint16_t;
message_header_type: uint16_t;
flags: uint32_t;
ttl: uint32_t;
seen: uint8_t [@len 128]; (* Blake3Hash[4] *)
group: uint8_t [@len 32]; (* Curve25519Pubkey *)
via: uint8_t [@len 32]; (* Curve25519Pubkey *)
signature: uint8_t [@len 64]; (* EdDSASig *)
} [@@big_endian]]
It seems that:
- You can’t embed a struct (like
message_header
) inside another one (unicast_message
/multicase_message
), leading to repetition. - You can’t create custom types (like
curve_25519_pubkey
) and use them in a struct, so you have to write it out each time as an array of integers. - Multidimensional arrays like
seen
are even trickier (128uint8
s, in this case)