{ "openapi": "3.0.3", "info": { "title": "STRIX HTTP API", "version": "0.4.0", "description": "HTTP API of a STRIX true random number generator connected over USB, served by tools/strix_serve.py. The routes match the device's own WiFi HTTP API (arduino/strix/API.md); this server adds the `time` field to GCP records, keeps an hour of them, accepts larger entropy requests and answers 503 while the device is unreachable. Device errors are JSON objects with an `error` field and status 200." }, "servers": [ { "url": "/" } ], "tags": [ { "name": "entropy", "description": "Random bytes from the entropy stream" }, { "name": "device", "description": "Identity, health, statistics and the bias amplifier" }, { "name": "settings", "description": "Runtime settings" }, { "name": "gcp", "description": "Per-second trials in Global Consciousness Project format" } ], "paths": { "/entropy": { "get": { "tags": [ "entropy" ], "summary": "Entropy bytes", "description": "Bytes from the stream source (setting `stream_source`, default: the XOR of all healthy generators). Refused while that source is not healthy.", "parameters": [ { "name": "bytes", "in": "query", "required": true, "schema": { "type": "integer", "minimum": 1, "maximum": 1048576 } }, { "name": "format", "in": "query", "schema": { "type": "string", "enum": [ "hex", "bin" ], "default": "hex" } } ], "responses": { "200": { "description": "Uppercase hex, raw bytes, or an error", "content": { "text/plain": { "schema": { "type": "string" }, "example": "3F09A2C47E11D05B" }, "application/octet-stream": { "schema": { "type": "string", "format": "binary" } }, "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "503": { "$ref": "#/components/responses/Unavailable" } } } }, "/": { "get": { "tags": [ "entropy" ], "summary": "Entropy bytes as hex (compatibility route)", "parameters": [ { "name": "length", "in": "query", "required": true, "schema": { "type": "integer", "minimum": 1, "maximum": 1048576 } } ], "responses": { "200": { "description": "Uppercase hex", "content": { "text/plain": { "schema": { "type": "string" } } } }, "404": { "$ref": "#/components/responses/NotFound" }, "503": { "$ref": "#/components/responses/Unavailable" } } } }, "/id": { "get": { "tags": [ "device" ], "summary": "Device identity", "responses": { "200": { "description": "Identity", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Id" } } } }, "503": { "$ref": "#/components/responses/Unavailable" } } } }, "/health": { "get": { "tags": [ "device" ], "summary": "Generator health and stream state", "responses": { "200": { "description": "Health", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Health" } } } }, "503": { "$ref": "#/components/responses/Unavailable" } } } }, "/stats": { "get": { "tags": [ "device" ], "summary": "Live statistics of the latest trial", "description": "Per channel (`g0`-`g3`, `combined`): bits, ones, bias z and lag-1 autocorrelation z for the trial, the rolling window and the cumulative total (with random walk position).", "responses": { "200": { "description": "Statistics", "content": { "application/json": { "schema": { "type": "object" } } } }, "503": { "$ref": "#/components/responses/Unavailable" } } } }, "/amp": { "get": { "tags": [ "device" ], "summary": "Latest bias amplifier trial", "description": "Per path (`bias`, `autocorr`): amplified bits, ones, z, sub-trial votes (`1`, `0`, `.` for no vote) and the trial result (null on a tie).", "responses": { "200": { "description": "Amplifier trial", "content": { "application/json": { "schema": { "type": "object" } } } }, "503": { "$ref": "#/components/responses/Unavailable" } } } }, "/wifi": { "get": { "tags": [ "device" ], "summary": "WiFi module status", "responses": { "200": { "description": "WiFi status", "content": { "application/json": { "schema": { "type": "object" } } } }, "503": { "$ref": "#/components/responses/Unavailable" } } } }, "/config": { "get": { "tags": [ "settings" ], "summary": "All settings", "responses": { "200": { "description": "Settings", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Config" } } } }, "503": { "$ref": "#/components/responses/Unavailable" } } } }, "/set": { "get": { "tags": [ "settings" ], "summary": "Change a setting", "description": "Value ranges are listed in arduino/strix/API.md. Changing `trial_ms` or `stats_vn` restarts the statistics, `amp_*` the amplifier; `stream_*` flushes the stream. When the server runs with --set-token-file, requests need that token as a bearer token.", "parameters": [ { "name": "key", "in": "query", "required": true, "schema": { "type": "string", "enum": [ "temporal", "generators", "radio_generators", "trial_ms", "stats_vn", "rolling", "stream_source", "stream_vn", "amp_sources", "amp_method", "amp_stages", "amp_sub_ms", "amp_subtrials", "amp_vn" ] } }, { "name": "value", "in": "query", "required": true, "schema": { "type": "string" }, "example": "5" } ], "responses": { "200": { "description": "Confirmation or error", "content": { "application/json": { "schema": { "oneOf": [ { "$ref": "#/components/schemas/Ok" }, { "$ref": "#/components/schemas/Error" } ] } } } }, "401": { "description": "Missing or wrong token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "503": { "$ref": "#/components/responses/Unavailable" } }, "security": [ { "setToken": [] } ] } }, "/gcp": { "get": { "tags": [ "gcp" ], "summary": "Per-second GCP-format trials", "description": "Without `since`: the latest second. With `since`: every kept second after it, oldest first (the last hour is kept). Polling with `since` set to the last second received loses no seconds. Second numbers restart when the device restarts.", "parameters": [ { "name": "since", "in": "query", "schema": { "type": "integer", "minimum": 0 } } ], "responses": { "200": { "description": "One record, a list of records, or an error before the first second", "content": { "application/json": { "schema": { "oneOf": [ { "$ref": "#/components/schemas/GcpRecord" }, { "type": "object", "required": [ "records" ], "properties": { "records": { "type": "array", "items": { "$ref": "#/components/schemas/GcpRecord" } } } }, { "$ref": "#/components/schemas/Error" } ] } } } } } } }, "/openapi.json": { "get": { "summary": "This specification", "responses": { "200": { "description": "OpenAPI document", "content": { "application/json": { "schema": { "type": "object" } } } } } } } }, "components": { "responses": { "Unavailable": { "description": "The device is not connected", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "NotFound": { "description": "Unknown path", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } }, "schemas": { "Error": { "type": "object", "required": [ "error" ], "properties": { "error": { "type": "string" } } }, "Ok": { "type": "object", "required": [ "ok" ], "properties": { "ok": { "type": "boolean" } } }, "Id": { "type": "object", "properties": { "device": { "type": "string", "example": "STRIX" }, "firmware": { "type": "string", "example": "0.4.0" }, "fpga_ready": { "type": "boolean" }, "fpga_version": { "type": "integer", "example": 10 }, "generators": { "type": "integer", "example": 4 }, "rings_per_generator": { "type": "integer", "example": 90 }, "reset_cause": { "type": "integer", "description": "SAMD21 PM->RCAUSE: 1 power-on, 4 brown-out, 16 reset pin, 64 software" }, "external_power": { "type": "boolean", "description": "Charger or USB power present at boot" } } }, "Health": { "type": "object", "properties": { "healthy": { "type": "integer", "description": "Bit mask of healthy generators" }, "generators": { "type": "array", "items": { "type": "object", "properties": { "healthy": { "type": "boolean" }, "active": { "type": "boolean" }, "swept": { "type": "boolean", "description": "A dead-ring sweep has completed" }, "rct_failed": { "type": "boolean" }, "apt_failed": { "type": "boolean" }, "rct_events": { "type": "integer" }, "apt_events": { "type": "integer" }, "dead_rings": { "type": "integer" } } } }, "stream": { "type": "object", "properties": { "level": { "type": "integer" }, "dropped": { "type": "integer" } } } } }, "Config": { "type": "object", "properties": { "temporal": { "type": "integer" }, "generators": { "type": "integer" }, "trial_ms": { "type": "integer" }, "stats_vn": { "type": "integer" }, "rolling": { "type": "integer" }, "stream_source": { "type": "integer" }, "stream_vn": { "type": "integer" }, "amp_sources": { "type": "integer" }, "amp_method": { "type": "string", "enum": [ "walk", "vote" ] }, "amp_stages": { "type": "string", "example": "8,8,4" }, "amp_sub_ms": { "type": "integer" }, "amp_subtrials": { "type": "integer" }, "amp_vn": { "type": "integer" }, "radio_generators": { "type": "integer" } } }, "TrialSet": { "type": "object", "description": "Per-generator sums of XOR-masked bits; null for generators not healthy for the whole second", "properties": { "bits": { "type": "integer", "description": "Bits per generator" }, "sums": { "type": "array", "items": { "type": "integer", "nullable": true } }, "z": { "type": "array", "items": { "type": "number", "nullable": true }, "description": "(2 sum - bits) / sqrt(bits)" }, "stouffer": { "type": "number", "nullable": true, "description": "Sum of z over sqrt(healthy generators)" }, "netvar": { "type": "number", "nullable": true, "description": "stouffer squared, chi-square with one degree of freedom" } } }, "GcpRecord": { "type": "object", "properties": { "time": { "type": "integer", "description": "Unix time at the start of the second, from the host clock" }, "second": { "type": "integer", "description": "Seconds since the FPGA started" }, "healthy": { "type": "integer", "description": "Bit mask of generators healthy for the whole second" }, "sample": { "$ref": "#/components/schemas/TrialSet" }, "full": { "$ref": "#/components/schemas/TrialSet" } } } }, "securitySchemes": { "setToken": { "type": "http", "scheme": "bearer", "description": "Token from the server's --set-token-file" } } } }