Skip to main content

Python SDK for the QCicada QRNG (Crypta Labs) — macOS-first, works on Linux too

Project description

qcicada

Rust and Python SDK for the QCicada quantum random number generator by Crypta Labs.

The official pyqcc SDK doesn't work on macOS due to FTDI serial driver differences. This SDK fixes that — and provides a cleaner API with no monkey-patching.

Quick Start

Python

pip install ./python    # requires pyserial
from qcicada import QCicada

with QCicada() as qrng:
    print(qrng.random(32).hex())

Rust

[dependencies]
qcicada = "0.1"
use qcicada::QCicada;

let mut qrng = QCicada::open(None, None)?;
let bytes = qrng.random(32)?;

That's it. The device is auto-detected. If you have multiple USB-serial devices, pass the port explicitly: QCicada(port="/dev/cu.usbserial-DK0HFP4T").

Finding Your Device

from qcicada import find_devices, discover_devices, open_by_serial

# List USB-serial ports (fast, no device communication)
find_devices()
# ['/dev/cu.usbserial-DK0HFP4T']

# Probe each port and confirm it's actually a QCicada
for dev in discover_devices():
    print(f"{dev.port}  serial={dev.info.serial}  hw={dev.info.hw_info}")
# /dev/cu.usbserial-DK0HFP4T  serial=QC0000000217  hw=CICADA-QRNG-1.1

# Open a specific device by serial number
qrng = open_by_serial("QC0000000217")

The same functions are available in Rust.

Entropy Modes

The QCicada supports three post-processing modes:

Mode What you get
SHA256 (default) NIST SP 800-90B conditioned output — use this for cryptography
Raw Noise Noise after health-test conditioning — use this for entropy research
Raw Samples Unprocessed samples from the quantum optical module
from qcicada import QCicada, PostProcess

with QCicada() as qrng:
    # Default: SHA256
    qrng.random(32).hex()

    # Switch to raw noise
    qrng.set_postprocess(PostProcess.RAW_NOISE)
    qrng.random(32).hex()

    # Switch to raw samples
    qrng.set_postprocess(PostProcess.RAW_SAMPLES)
    qrng.random(32).hex()

Device Info & Status

with QCicada() as qrng:
    info = qrng.get_info()
    # DeviceInfo(serial='QC0000000217', fw_version=0x5000e,
    #            core_version=0x1000c, hw_info='CICADA-QRNG-1.1')

    status = qrng.get_status()
    # DeviceStatus(initialized=True, ready_bytes=13440, ...)

    stats = qrng.get_statistics()
    # DeviceStatistics(generated_bytes=4928, speed=100696, ...)

    config = qrng.get_config()
    # DeviceConfig(postprocess=SHA256, auto_calibration=True, block_size=448, ...)

Full Configuration

Every device setting is readable and writable:

from dataclasses import replace

config = qrng.get_config()

# Modify and write back
config = replace(config, block_size=256, auto_calibration=False)
qrng.set_config(config)
Field Type Description
postprocess PostProcess SHA256, RawNoise, or RawSamples
initial_level float LED initial level
startup_test bool Run health test on startup
auto_calibration bool Auto-calibrate light source
repetition_count bool NIST SP 800-90B repetition count test
adaptive_proportion bool NIST SP 800-90B adaptive proportion test
bit_count bool Crypta Labs bit balance test
generate_on_error bool Keep generating if a health test fails
n_lsbits int Number of LSBs to extract per sample
hash_input_size int Bytes fed into SHA256 per output block
block_size int Output block size in bytes
autocalibration_target int Target value for auto-calibration

Signed Reads

Get random bytes with a cryptographic signature (requires firmware 5.13+):

result = qrng.signed_read(32)
print(result.data.hex())       # 32 random bytes
print(result.signature.hex())  # 64-byte signature

The signature is produced by the device's internal asymmetric key. Check the QCicada documentation for how to extract the public key and verify signatures.

Continuous Mode

For high-throughput streaming, use continuous mode instead of one-shot:

with QCicada() as qrng:
    qrng.start_continuous()
    for _ in range(100):
        chunk = qrng.read_continuous(1024)
        process(chunk)
    qrng.stop()

The device streams random data until stop() is called. There's no per-request overhead, so this is faster for bulk entropy collection.

API Reference

Method Description
random(n) Get n random bytes (1–65535, one-shot)
signed_read(n) Get n random bytes + 64-byte signature (FW 5.13+)
start_continuous() Start continuous streaming mode
read_continuous(n) Read n bytes from continuous stream
fill_bytes(buf) Fill a buffer of any size (auto-chunks)
get_info() Serial number, firmware version, hardware
get_status() Health flags, ready byte count
get_config() Full device configuration
set_config(config) Write device configuration
set_postprocess(mode) Shortcut to change entropy mode
get_statistics() Bytes generated, speed, failure counts
reset() Restart generation and clear statistics
stop() Halt any active generation
close() Close serial port

Rust: QCicada also implements std::io::Read, so it works anywhere a reader is expected.

Why Not pyqcc?

The official Crypta Labs SDK (pyqcc) has macOS issues:

  • Uses /dev/tty.* ports — macOS needs /dev/cu.*
  • Sets inter_byte_timeout — causes FTDI read failures on macOS
  • Timeouts too short — macOS FTDI driver needs at least 500ms
  • No flush delay — FTDI driver drops bytes without a post-write pause
  • Device may be left in continuous mode — no drain on connect

This SDK fixes all of these. It also works fine on Linux.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

qcicada-0.1.0.tar.gz (16.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

qcicada-0.1.0-py3-none-any.whl (12.0 kB view details)

Uploaded Python 3

File details

Details for the file qcicada-0.1.0.tar.gz.

File metadata

  • Download URL: qcicada-0.1.0.tar.gz
  • Upload date:
  • Size: 16.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for qcicada-0.1.0.tar.gz
Algorithm Hash digest
SHA256 4c4f68d238410dee6669b19898de88d331891525618c5fed463536321d162d57
MD5 fc8054634b7bd1fadd1e4db28c8ac4c3
BLAKE2b-256 fcf3f1269ef536a3b5f1a8b71faff0bdd73607a4f7f9579e86db59bffe161610

See more details on using hashes here.

File details

Details for the file qcicada-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: qcicada-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 12.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for qcicada-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5aaa393761a3222d863e32c0ec3c19265f07d0b785828f67060d159bb3be8542
MD5 a43063be85bc8d24e64b264f205db626
BLAKE2b-256 07d1bc715ffa3b4c1dd0683eb372559da20557031128c64933367b80fbd169a0

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page