1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
|
#pragma once
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
typedef uint8_t byte;
typedef byte hash[ 32 ];
typedef byte public_key[ 32 ];
typedef byte private_key[ 32 ];
typedef byte recipient[ 64 ];
typedef byte signature[ 64 ];
typedef byte ipv4[ 4 ];
typedef byte ipv6[ 16 ];
#define MAX_RECIPIENTS 32
struct relay_neighbor {
bool active;
bool has_ipv4;
bool has_ipv6;
ipv4 v4_addr;
ipv6 v6_addr;
};
struct relay_info {
byte major_version;
byte minor_version;
byte motd[ 128 ];
struct {
uint16_t retention_hours;
bool can_store;
byte leading_zeros;
bool accepts_plain;
} capabilities;
struct {
uint16_t neighbors;
uint64_t held_packets;
struct relay_neighbor quick_connect[ 4 ];
} statistics;
};
struct data_packet {
uint32_t nonce;
hash hash;
struct {
bool encrypted;
uint64_t created_time_ms;
public_key author;
public_key author_signing_pub;
uint8_t recipient_count;
recipient recipients[ 32 ];
byte data[ 65536 ];
signature signature;
} contents;
};
// from libsodium
#ifndef SIGN_PUBLICKEYBYTES
#define SIGN_PUBLICKEYBYTES 32
#endif
#ifndef SIGN_SECRETKEYBYTES
#define SIGN_SECRETKEYBYTES 64
#endif
typedef unsigned char sign_public_key[ SIGN_PUBLICKEYBYTES ];
typedef unsigned char sign_secret_key[ SIGN_SECRETKEYBYTES ];
typedef struct {
public_key encryption_pub;
private_key encryption_priv;
sign_public_key signing_pub;
sign_secret_key signing_priv;
} keypair;
struct data_packet_list {
struct data_packet* packets; // caller must free this
uint16_t count;
uint64_t new_offset;
};
typedef enum {
MP_CLIENT_SUCCESS = 0,
MP_CLIENT_ERROR_NETWORK_FAIL,
MP_CLIENT_ERROR_INVALID_ADDRESS,
MP_CLIENT_ERROR_CONNECTION_FAILED,
MP_CLIENT_ERROR_SEND_FAILED,
MP_CLIENT_ERROR_RECV_FAILED,
MP_CLIENT_ERROR_SERVER_BUSY, // 418 teapot
MP_CLIENT_ERROR_INVALID_RESPONSE,
MP_CLIENT_ERROR_DESERIALIZE_FAILED,
MP_CLIENT_ERROR_ALLOC_FAILED,
MP_CLIENT_ERROR_FILE_NOT_FOUND,
MP_CLIENT_ERROR_FILE_READ_FAILED,
MP_CLIENT_ERROR_BAD_ARGUMENT,
} mp_client_error_t;
/**
* @brief Get server information and capabilities.
* @param ip Server IP address (IPv4 or IPv6).
* @param port Server port.
* @param out_info Pointer to a struct where the server info will be stored.
* @return MP_CLIENT_SUCCESS on success, or an error code on failure.
*/
mp_client_error_t mp_get_server_info(const char* ip, int port, struct relay_info* out_info);
/**
* @brief Get a list of neighbors from the server.
* @param ip Server IP address.
* @param port Server port.
* @param count Number of neighbors to request.
* @param out_neighbors Pointer to a pointer that will be updated to point to a newly allocated
* array of neighbors. The caller is responsible for freeing this memory.
* @param out_count Pointer to a byte where the actual number of received neighbors will be stored.
* @return MP_CLIENT_SUCCESS on success, or an error code on failure.
*/
mp_client_error_t mp_get_server_neighbors(
const char* ip, int port, byte count, struct relay_neighbor** out_neighbors, byte* out_count);
/**
* @brief Push a packet to the server.
* @param ip Server IP address.
* @param port Server port.
* @param packet The data packet to push.
* @param out_success Pointer to a boolean that will be true if the server accepted the packet,
* false otherwise.
* @return MP_CLIENT_SUCCESS on success, or an error code on failure.
*/
mp_client_error_t
mp_push_packet(const char* ip, int port, struct data_packet packet, bool* out_success);
/**
* @brief Get a specific packet from the server by its hash.
* @param ip Server IP address.
* @param port Server port.
* @param packet_hash The hash of the packet to retrieve.
* @param out_packet Pointer to a struct where the retrieved packet will be stored.
* @return MP_CLIENT_SUCCESS on success, or an error code on failure.
*/
mp_client_error_t
mp_get_packet(const char* ip, int port, const hash packet_hash, struct data_packet* out_packet);
/**
* @brief Get a batch of packets from the server's firehose stream.
* @param ip Server IP address.
* @param port Server port.
* @param offset The starting offset in the firehose stream.
* @param count The maximum number of packets to retrieve.
* @param out_list Pointer to a data_packet_list struct. The 'packets' member will be allocated by
* the function and must be freed by the caller.
* @return MP_CLIENT_SUCCESS on success, or an error code on failure.
*/
mp_client_error_t mp_get_firehose_packets(
const char* ip, int port, uint64_t offset, uint16_t count, struct data_packet_list* out_list);
/**
* @brief Create a data packet from a raw byte buffer.
* @param input The raw data buffer.
* @param input_len The length of the data buffer.
* @param recipient_count The number of recipients.
* @param recipients An array of recipient public keys.
* @param author_keys The keypair of the packet author.
* @return A new data_packet struct.
*/
struct data_packet mp_create_packet_from_bytes(
const byte* input,
size_t input_len,
byte recipient_count,
recipient* recipients,
keypair author_keys);
/**
* @brief Create a data packet by reading the contents from a file.
* @param filename The path to the file.
* @param recipient_count The number of recipients.
* @param recipients An array of recipient public keys.
* @param author_keys The keypair of the packet author.
* @param out_packet Pointer to a struct where the created packet will be stored.
* @return MP_CLIENT_SUCCESS on success, or an error code on failure.
*/
mp_client_error_t mp_create_packet_from_file(
const char* filename,
byte recipient_count,
recipient* recipients,
keypair author_keys,
struct data_packet* out_packet);
/**
* @brief Run Proof-of-Work on a packet to find a nonce that satisfies the leading zeros
* requirement.
* @param packet The input packet. The 'nonce' and 'hash' fields will be modified.
* @param leading_zeros The number of leading zero bits required for the hash.
* @return The modified packet with a valid nonce and hash.
*/
struct data_packet mp_run_pow(struct data_packet packet, byte leading_zeros);
/**
* @brief Generates a new encryption and signing keypair.
* @return A new keypair struct.
*/
keypair mp_generate_keypair(void);
|