ftu/fstoken.h

80 lines
3.4 KiB
C

#ifndef __FSTOKEN_H__
#define __FSTOKEN_H__
#include "blst/blst.h"
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
// only used for debugging
#include <stdio.h>
#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!). Keeping 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;
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);
#endif