File size: 4,108 Bytes
d36206f | 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 | /*
* anu_node.c — ANU Quantum Node (SEIT product recreation)
* Copyright (C) 2026 Ahmad Ali Parr / SnapKitty Research Lab
* SPDX-License-Identifier: LicenseRef-SEIT-FSL-Donation-1.0
*
* Functional source, donation-gated runtime: you may read, share, and
* modify this source freely; running it requires a qualifying donation
* to the licensor. See LICENSE.txt for the full terms. No warranty.
*/
/*
* anu_node.c -- ANU Quantum Node (SEIT product recreation)
*
* Draws 32 bytes of entropy ("temperature") from one of two tiers:
*
* Tier 1: the live Australian National University quantum random number
* generator JSON API. Vacuum-fluctuation-derived hex strings,
* fetched with curl and parsed by hand (no JSON library).
* Tier 2: getrandom() as the fallback. Used on ANY failure of Tier 1:
* curl missing or failing, network error, timeout, malformed
* JSON, wrong data length, non-hex characters.
*
* The program prints which tier supplied the bytes and the drawn bytes
* as hex. Every run's temperature has never existed before and will
* never exist again.
*/
#define _GNU_SOURCE /* getrandom(), popen() under -std=c11 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/random.h>
#define DRAW_BYTES 32u /* total bytes drawn per run */
#define CHUNK_LEN 16u /* bytes per ANU hex string requested */
#define RESP_MAX 16384 /* largest ANU JSON response we accept */
#define ANU_URL "https://qrng.anu.edu.au/API/jsonI.php?length=16&type=hex"
#define CURL_CMD "curl -s --max-time 10 '" ANU_URL "'"
/* Return the nibble value of a hex digit, or -1 if not hex. */
static int hex_nibble(char c)
{
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
return -1;
}
/*
* Attempt a Tier 1 draw: fetch DRAW_BYTES bytes worth of hex strings from
* the live ANU QRNG JSON API. Returns 0 on success, -1 on any failure.
* Each hex string must be exactly 2*CHUNK_LEN hex characters; the first
* DRAW_BYTES/CHUNK_LEN strings are consumed in order.
*/
static int draw_anu(unsigned char *out, size_t n)
{
char resp[RESP_MAX];
FILE *fp;
size_t len, got, need, i;
const char *data, *p, *q;
int status, hi, lo;
if (n == 0 || n % CHUNK_LEN != 0)
return -1;
fp = popen(CURL_CMD, "r");
if (fp == NULL)
return -1;
len = fread(resp, 1, sizeof(resp) - 1, fp);
status = pclose(fp);
if (status != 0)
return -1;
resp[len] = '\0';
/* Locate the "data" array. */
data = strstr(resp, "\"data\"");
if (data == NULL)
return -1;
data = strchr(data, '[');
if (data == NULL)
return -1;
p = data + 1;
need = n / CHUNK_LEN;
got = 0;
for (i = 0; i < need; i++) {
p = strchr(p, '"');
if (p == NULL)
return -1;
p++;
q = strchr(p, '"');
if (q == NULL)
return -1;
if ((size_t)(q - p) != (size_t)(CHUNK_LEN * 2))
return -1;
for (size_t j = 0; j < CHUNK_LEN; j++) {
hi = hex_nibble(p[2 * j]);
lo = hex_nibble(p[2 * j + 1]);
if (hi < 0 || lo < 0)
return -1;
*out++ = (unsigned char)((hi << 4) | lo);
}
got++;
p = q + 1;
}
if (got != need)
return -1;
return 0;
}
/* Tier 2 draw: OS entropy via getrandom(). Returns 0/-1. */
static int draw_fallback(unsigned char *out, size_t n)
{
size_t got = 0;
while (got < n) {
ssize_t r = getrandom(out + got, n - got, 0);
if (r < 0)
return -1;
got += (size_t)r;
}
return 0;
}
/* Print bytes as lowercase hex on one line. */
static void print_hex(const unsigned char *buf, size_t n)
{
for (size_t i = 0; i < n; i++)
printf("%02x", buf[i]);
printf("\n");
}
int main(void)
{
unsigned char buf[DRAW_BYTES];
const char *label;
if (draw_anu(buf, sizeof(buf)) == 0) {
label = "ANU QRNG (live)";
} else if (draw_fallback(buf, sizeof(buf)) == 0) {
label = "getrandom() (fallback)";
} else {
fprintf(stderr, "anu_node: both entropy tiers failed\n");
return EXIT_FAILURE;
}
printf("source: %s\n", label);
printf("temperature: ");
print_hex(buf, sizeof(buf));
return EXIT_SUCCESS;
}
|