#ifndef __FSTOKEN_H__ #define __FSTOKEN_H__ #include "blst/bindings/blst.h" #include #include #include // only used for debugging #include #include "debugprint.h" // Note: In constrained environments where the IDBITS and HASHBITS values of the tokens in use are known, such as in fsp, these can be set exactly. // However, that may render some structs (such as the request descriptor) incompatible if moved to an environment where this is nonstandard. #define IDBITS_DEFAULT 128 #define IDBITS_MAX 256 #define HASHBITS_DEFAULT 256 #define HASHBITS_MAX 256 #define IDBYTES_MAX (IDBITS_MAX + 7) / 8 #define HASHBYTES_MAX (HASHBITS_MAX + 7) / 8 #define FSTOKEN_DST ((byte*) "MY-DST") // For efficiency's sake, structs intended for use with the FemtoStar Protocol must be strictly-aligned without padding, with little-endian byte ordering. // This avoids wasting network capacity on padding, and avoids the performance impact of reordering on most modern platforms (most importantly x86 and RISC-V) // while ensuring compatibility with strict-alignment architectures. Take note: This is NOT typical network-order! // Additionally, note that most structs do not explicitly include what target they are for (even the target descriptor!). Tracking what is for what target is // not a core part of fstoken, and is the responsibility of the software using fstoken (e.g. ctm or an implementation of fsp). This keeps tokens light in // situations where which target is relevant is unambiguous (e.g. in the session setup with a satellite, where the satellite is always the same target). // A target_descriptor is a stored description of a target, which can be used to request, verify, and sometimes sign tokens for it. typedef struct{ #pragma scalar_storage_order little-endian uint8_t target_descriptor_version; bool sk_available; uint16_t idbits; uint16_t hashbits; byte sk[32]; byte pk[96]; } fstoken_target_descriptor; // A request descriptor is a structure held privately by the requester until they receive a signature for their request - it is then used to generate a token typedef struct{ #pragma scalar_storage_order little-endian byte blinding_factor[32]; byte token_id[IDBYTES_MAX]; } fstoken_request_descriptor; // A request is a structure sent by the requester to the signer, to be signed and a signature returned. It need not be kept private. typedef struct{ #pragma scalar_storage_order little-endian byte id_blind[48]; } fstoken_request; // I'm unsure if these "single-item structs" make any sense - signatures in blst are independent of system or scalar_storage_order endianness anyway typedef struct{ #pragma scalar_storage_order little-endian byte signature[48]; } fstoken_signature; typedef struct{ #pragma scalar_storage_order little-endian byte signature[48]; byte token_id[IDBYTES_MAX]; } fstoken_token; typedef struct{ #pragma scalar_storage_order little-endian byte hash[HASHBYTES_MAX]; byte token_id[IDBYTES_MAX]; } fstoken_short_token; void fstoken_keygen(byte* ikm, byte* sk_byte, byte* pk_byte); void fstoken_get_pk_from_sk(byte* sk_byte, byte* pk_byte); void bit_truncated_copy(byte* src, byte* dest, size_t destlen, int bits); void fstoken_gen_request(fstoken_request* req, fstoken_request_descriptor* reqdesc, fstoken_target_descriptor* target, byte* token_id, byte* blinding_factor); int fstoken_sign_request(fstoken_request* req, fstoken_signature* sig, fstoken_target_descriptor* targ); int fstoken_gen_token(fstoken_request_descriptor* req, fstoken_signature* sig, fstoken_token* token); int fstoken_verify_token(fstoken_token* token, fstoken_target_descriptor* targ); int fstoken_shorten_token(fstoken_token* token, fstoken_short_token short_token); int fstoken_target_token_length(fstoken_target_descriptor* target); #endif