#ifndef CIRCE_CORE_H #define CIRCE_CORE_H #include "core/peer_table.h" #include "mldsa/mldsa_native.h" #include "proto_circe.h" #include #include #define CIRCE_MAX_OUTGOING_PACKETS 64 #define CIRCE_HEARTBEAT_PERIOD_MS 1000 enum circe_result { CIRCE_RESULT_SUCCESS = 0, CIRCE_RESULT_INSUFFICIENT_MEM, CIRCE_RESULT_INVALID_PACKET, CIRCE_RESULT_INVALID_MAC, CIRCE_RESULT_INTERNAL_ERROR, CIRCE_RESULT_UNKNOWN_REMOTE, CIRCE_RESULT_OVER_MTU, CIRCE_RESULT_HANDSHAKE_PENDING, CIRCE_RESULT_PEER_TABLE_FULL, CIRCE_RESULT_RELAY_LOOKUP_FAILED, CIRCE_RESULT_PACKET_TABLE_FULL, CIRCE_RESULT_KEX_FAILED, CIRCE_RESULT_SIGNATURE_FAILED, CIRCE_RESULT_INVALID_SIGNATURE, CIRCE_RESULT_INVALID_TIMESTAMP, CIRCE_RESULT_DUPLICATE_HS_PACKET, CIRCE_RESULT_HS_OUT_OF_ORDER, }; enum circe_version { CIRCE_VERSION_V1 = 0, }; struct circe_event { enum { CIRCE_EVENT_DATA_RECEIVED, CIRCE_EVENT_NEW_REMOTE, CIRCE_EVENT_REJECTED_REMOTE, } event_type; }; enum circe_deadline { CIRCE_DEADLINE_NOW, CIRCE_DEADLINE_INDEFINITE, CIRCE_DEADLINE_AS_INDICATED, }; struct circe_outgoing_packet { uint8_t buffer[PROTO_CIRCE_MTU]; size_t length; struct circe_location destination; }; struct circe_context { struct circe_peer peer_table[CIRCE_PEER_TABLE_LEN]; uint64_t peer_handshake_pending_mask; uint64_t peer_table_free_mask; // 1 if free, 0 if full struct circe_outgoing_packet outgoing_packets[CIRCE_MAX_OUTGOING_PACKETS]; uint64_t outgoing_packet_table_free_mask; // 1 if free, 0 if full uint64_t last_tick_ms; uint8_t my_identity[CIRCE_IDENTITY_LEN]; uint8_t my_mldsa_privkey[MLDSA_SECRETKEYBYTES (44)]; void *ctx_handle; bool (*recall_peer_callback) (void *ctx_handle, const uint8_t identity[CIRCE_IDENTITY_LEN], struct circe_peer *out); }; /// Initialize Circe core's context state enum circe_result circe_initialize_core ( struct circe_context *ctx, uint8_t identity[CIRCE_IDENTITY_LEN], uint8_t mldsa_privkey[MLDSA_SECRETKEYBYTES (44)], uint64_t now_ms, void *ctx_handle, bool (*recall_peer_callback) (void *, const uint8_t[CIRCE_IDENTITY_LEN], struct circe_peer *)); /// Process a new incoming raw Circe packet. enum circe_result circe_handle_packet (struct circe_context *ctx, const struct circe_location remote, const uint8_t *restrict in, size_t len, uint8_t *restrict out, size_t *out_len, uint64_t now_ms, struct circe_event *events, size_t *n_events); /// Put outgoing packet into Circe's internal logic. DOES NOT ACTUALLY SEND IT /// OVER THE NETWORK; that is handled opaquely by the caller and `circe_tick`. enum circe_result circe_send_outgoing_packet (struct circe_context *ctx, const uint8_t remote_identity[CIRCE_IDENTITY_LEN], const uint8_t *in, size_t len, uint64_t now_ms, struct circe_event *events, size_t *n_events); /// Get deadline and corresponding millisecond timestamp (for /// `CIRCE_DEADLINE_AS_INDICATED`) for next timer deadline, at which point /// `circe_tick` should be called. Should always be called immediately after /// any other core API function is called to stay up-to-date. enum circe_deadline circe_next_deadline (struct circe_context *ctx, uint64_t *ms_timestamp); /// Iterate the Circe core logic. Assumes `now_ms` increases monotonically with /// time. If `new_packet_out` is true (do not pass in NULL for `out`), then /// `out` contains a new raw Circe packet to be sent out to the location /// `out.destination`. enum circe_result circe_tick (struct circe_context *ctx, uint64_t now_ms, struct circe_outgoing_packet *out, bool *new_packet_out); #endif