File Coverage

/usr/local/lib/perl5/site_perl/5.42.0/x86_64-linux/Horus/include/horus_uuid.h
Criterion Covered Total %
statement 12 12 100.0
branch n/a
condition n/a
subroutine n/a
pod n/a
total 12 12 100.0


line stmt bran cond sub pod time code
1             #ifndef HORUS_UUID_H
2             #define HORUS_UUID_H
3              
4             /*
5             * horus_uuid.h - Core UUID generation: v1-v8, NIL, MAX
6             *
7             * All generators write into a 16-byte output buffer.
8             * Version and variant bits are stamped last.
9             */
10              
11             #include
12             #include
13             #include /* getuid, getgid */
14              
15             /* ── Version/variant stamping ───────────────────────────────────── */
16              
17 61           static inline void horus_stamp_version_variant(unsigned char *uuid, int version) {
18 61           uuid[6] = (uuid[6] & 0x0F) | ((unsigned char)(version) << 4);
19 61           uuid[8] = (uuid[8] & 0x3F) | 0x80;
20 61           }
21              
22             /* ── NIL UUID ───────────────────────────────────────────────────── */
23              
24             static inline void horus_uuid_nil(unsigned char *out) {
25             memset(out, 0x00, 16);
26             }
27              
28             /* ── MAX UUID ───────────────────────────────────────────────────── */
29              
30             static inline void horus_uuid_max(unsigned char *out) {
31             memset(out, 0xFF, 16);
32             }
33              
34             /* ── v4: Random ─────────────────────────────────────────────────── */
35              
36             static inline void horus_uuid_v4(unsigned char *out) {
37             horus_random_bytes(out, 16);
38             horus_stamp_version_variant(out, 4);
39             }
40              
41             /* ── v1: Time-based (Gregorian) ─────────────────────────────────── */
42              
43             typedef struct {
44             unsigned char node[6];
45             uint16_t clock_seq;
46             uint64_t last_time;
47             int initialized;
48             } horus_v1_state_t;
49              
50             static inline void horus_v1_init_state(horus_v1_state_t *state) {
51             horus_random_bytes(state->node, 6);
52             state->node[0] |= 0x01; /* multicast bit per RFC 9562 */
53             {
54             unsigned char cs[2];
55             horus_random_bytes(cs, 2);
56             state->clock_seq = ((uint16_t)(cs[0] & 0x3F) << 8) | (uint16_t)cs[1];
57             }
58             state->last_time = 0;
59             state->initialized = 1;
60             }
61              
62             static inline void horus_uuid_v1(unsigned char *out, horus_v1_state_t *state) {
63             uint64_t ts;
64             uint32_t time_low;
65             uint16_t time_mid, time_hi;
66              
67             if (!state->initialized)
68             horus_v1_init_state(state);
69              
70             ts = horus_gregorian_100ns();
71              
72             if (ts <= state->last_time) {
73             state->clock_seq = (state->clock_seq + 1) & 0x3FFF;
74             }
75             state->last_time = ts;
76              
77             time_low = (uint32_t)(ts & 0xFFFFFFFF);
78             time_mid = (uint16_t)((ts >> 32) & 0xFFFF);
79             time_hi = (uint16_t)((ts >> 48) & 0x0FFF);
80              
81             /* time_low: bytes 0-3 (big-endian) */
82             out[0] = (unsigned char)(time_low >> 24);
83             out[1] = (unsigned char)(time_low >> 16);
84             out[2] = (unsigned char)(time_low >> 8);
85             out[3] = (unsigned char)(time_low);
86             /* time_mid: bytes 4-5 */
87             out[4] = (unsigned char)(time_mid >> 8);
88             out[5] = (unsigned char)(time_mid);
89             /* time_hi_and_version: bytes 6-7 */
90             out[6] = (unsigned char)(time_hi >> 8);
91             out[7] = (unsigned char)(time_hi);
92             /* clock_seq_hi_and_variant: byte 8 */
93             out[8] = (unsigned char)(state->clock_seq >> 8);
94             /* clock_seq_low: byte 9 */
95             out[9] = (unsigned char)(state->clock_seq);
96             /* node: bytes 10-15 */
97             memcpy(out + 10, state->node, 6);
98              
99             horus_stamp_version_variant(out, 1);
100             }
101              
102             /* ── v2: DCE Security ───────────────────────────────────────────── */
103              
104             static inline void horus_uuid_v2(unsigned char *out, horus_v1_state_t *state,
105             int domain, uint32_t id) {
106             uint64_t ts;
107             uint16_t time_mid, time_hi;
108              
109             if (!state->initialized)
110             horus_v1_init_state(state);
111              
112             ts = horus_gregorian_100ns();
113             state->last_time = ts;
114              
115             time_mid = (uint16_t)((ts >> 32) & 0xFFFF);
116             time_hi = (uint16_t)((ts >> 48) & 0x0FFF);
117              
118             /* Replace time_low with the identifier */
119             out[0] = (unsigned char)(id >> 24);
120             out[1] = (unsigned char)(id >> 16);
121             out[2] = (unsigned char)(id >> 8);
122             out[3] = (unsigned char)(id);
123             /* time_mid: bytes 4-5 */
124             out[4] = (unsigned char)(time_mid >> 8);
125             out[5] = (unsigned char)(time_mid);
126             /* time_hi_and_version: bytes 6-7 */
127             out[6] = (unsigned char)(time_hi >> 8);
128             out[7] = (unsigned char)(time_hi);
129             /* clock_seq_hi replaced with local domain */
130             out[8] = (unsigned char)(domain & 0xFF);
131             /* clock_seq_low */
132             out[9] = (unsigned char)(state->clock_seq & 0xFF);
133             /* node: bytes 10-15 */
134             memcpy(out + 10, state->node, 6);
135              
136             horus_stamp_version_variant(out, 2);
137             }
138              
139             /* ── v3: MD5 namespace ──────────────────────────────────────────── */
140              
141             static inline void horus_uuid_v3(unsigned char *out,
142             const unsigned char *ns_bytes,
143             const unsigned char *name, size_t name_len) {
144             horus_md5_ctx ctx;
145             unsigned char digest[16];
146              
147             horus_md5_init(&ctx);
148             horus_md5_update(&ctx, ns_bytes, 16);
149             horus_md5_update(&ctx, name, name_len);
150             horus_md5_final(digest, &ctx);
151              
152             memcpy(out, digest, 16);
153             horus_stamp_version_variant(out, 3);
154             }
155              
156             /* ── v5: SHA-1 namespace ────────────────────────────────────────── */
157              
158 50           static inline void horus_uuid_v5(unsigned char *out,
159             const unsigned char *ns_bytes,
160             const unsigned char *name, size_t name_len) {
161             horus_sha1_ctx ctx;
162             unsigned char digest[20];
163              
164 50           horus_sha1_init(&ctx);
165 50           horus_sha1_update(&ctx, ns_bytes, 16);
166 50           horus_sha1_update(&ctx, name, name_len);
167 50           horus_sha1_final(digest, &ctx);
168              
169 50           memcpy(out, digest, 16); /* first 16 bytes of SHA-1 */
170 50           horus_stamp_version_variant(out, 5);
171 50           }
172              
173             /* ── v6: Reordered time ─────────────────────────────────────────── */
174              
175             typedef struct {
176             unsigned char last[16]; /* last emitted v6 UUID for monotonic guarantee */
177             int has_last;
178             } horus_v6_state_t;
179              
180             static inline void horus_uuid_v6(unsigned char *out, horus_v1_state_t *v1state,
181             horus_v6_state_t *v6state) {
182             uint64_t ts;
183              
184             if (!v1state->initialized)
185             horus_v1_init_state(v1state);
186              
187             ts = horus_gregorian_100ns();
188              
189             /* v6 reorders: most significant bits first for sorting
190             * time_high (bits 59..28 of timestamp) -> bytes 0-3
191             * time_mid (bits 27..16) -> bytes 4-5
192             * time_low (bits 15..4) -> byte 6 low nibble + byte 7 */
193              
194             out[0] = (unsigned char)(ts >> 52);
195             out[1] = (unsigned char)(ts >> 44);
196             out[2] = (unsigned char)(ts >> 36);
197             out[3] = (unsigned char)(ts >> 28);
198             out[4] = (unsigned char)(ts >> 20);
199             out[5] = (unsigned char)(ts >> 12);
200             out[6] = (unsigned char)((ts >> 4) & 0x0F);
201             out[7] = (unsigned char)((ts << 4) & 0xF0);
202             /* Fill remaining bits: clock_seq and node */
203             out[8] = (unsigned char)(v1state->clock_seq >> 8);
204             out[9] = (unsigned char)(v1state->clock_seq);
205             memcpy(out + 10, v1state->node, 6);
206              
207             horus_stamp_version_variant(out, 6);
208              
209             /* Monotonic guarantee: if new UUID <= last, increment last and use that */
210             if (v6state->has_last && memcmp(out, v6state->last, 16) <= 0) {
211             int i, carry = 1;
212             memcpy(out, v6state->last, 16);
213             /* Increment bytes 8-15 (after version/variant fields) */
214             for (i = 15; i >= 8 && carry; i--) {
215             int val = (int)out[i] + carry;
216             out[i] = (unsigned char)(val & 0xFF);
217             carry = val >> 8;
218             }
219             /* Re-stamp variant (byte 8 top 2 bits) in case carry corrupted it */
220             out[8] = (out[8] & 0x3F) | 0x80;
221             }
222              
223             memcpy(v6state->last, out, 16);
224             v6state->has_last = 1;
225             }
226              
227             /* ── v7: Unix epoch time with monotonic counter ─────────────────── */
228              
229             typedef struct {
230             uint64_t last_ms;
231             unsigned char last_rand[8]; /* bytes 8-15 of the last UUID (after variant) */
232             } horus_v7_state_t;
233              
234             static inline void horus_uuid_v7(unsigned char *out, horus_v7_state_t *state) {
235             uint64_t ms = horus_unix_epoch_ms();
236              
237             /* 48-bit timestamp: bytes 0-5 */
238             out[0] = (unsigned char)(ms >> 40);
239             out[1] = (unsigned char)(ms >> 32);
240             out[2] = (unsigned char)(ms >> 24);
241             out[3] = (unsigned char)(ms >> 16);
242             out[4] = (unsigned char)(ms >> 8);
243             out[5] = (unsigned char)(ms);
244              
245             if (ms == state->last_ms) {
246             /* Same millisecond: increment the random portion for monotonicity */
247             int i;
248             int carry = 1;
249             /* Increment bytes 8-15 (stored in last_rand) */
250             for (i = 7; i >= 0 && carry; i--) {
251             int val = (int)state->last_rand[i] + carry;
252             state->last_rand[i] = (unsigned char)(val & 0xFF);
253             carry = val >> 8;
254             }
255             /* rand_a: bytes 6-7 (12 bits after version) */
256             if (carry) {
257             /* Overflow: increment rand_a portion */
258             unsigned char r[2];
259             horus_random_bytes(r, 2);
260             out[6] = r[0];
261             out[7] = r[1];
262             horus_random_bytes(state->last_rand, 8);
263             } else {
264             out[6] = state->last_rand[0];
265             out[7] = state->last_rand[1];
266             }
267             memcpy(out + 8, state->last_rand + 2, 6);
268             } else {
269             /* New millisecond: fresh random */
270             unsigned char r[10]; /* 2 for rand_a + 8 for rand_b */
271             horus_random_bytes(r, 10);
272             out[6] = r[0];
273             out[7] = r[1];
274             memcpy(out + 8, r + 2, 6);
275              
276             /* Save state */
277             state->last_ms = ms;
278             memcpy(state->last_rand, r, 8);
279             }
280              
281             horus_stamp_version_variant(out, 7);
282              
283             /* Update saved state to reflect version/variant stamping */
284             state->last_rand[0] = out[6];
285             state->last_rand[1] = out[7];
286             memcpy(state->last_rand + 2, out + 8, 6);
287             }
288              
289             /* ── v8: Custom ─────────────────────────────────────────────────── */
290              
291             static inline void horus_uuid_v8(unsigned char *out,
292             const unsigned char *custom_data) {
293             memcpy(out, custom_data, 16);
294             horus_stamp_version_variant(out, 8);
295             }
296              
297             #endif /* HORUS_UUID_H */