[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-80605":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":15,"stars7d":15,"stars30d":17,"stars90d":16,"forks30d":16,"starsTrendScore":18,"compositeScore":19,"rankGlobal":10,"rankLanguage":10,"license":10,"archived":20,"fork":20,"defaultBranch":21,"hasWiki":22,"hasPages":20,"topics":23,"createdAt":10,"pushedAt":10,"updatedAt":36,"readmeContent":37,"aiSummary":38,"trendingCount":16,"starSnapshotCount":16,"syncStatus":14,"lastSyncTime":39,"discoverSource":40},80605,"libminerva","kavishka-dot\u002Flibminerva","kavishka-dot","MINERVA - Minimal Inference Engine for Robust, Verifiable, and Authenticated ML. Encrypted, integrity-verified neural network inference for MCUs down to ATmega328P.","",null,"C",58,7,2,1,0,8,3,43.01,false,"main",true,[24,25,26,27,28,29,30,31,32,33,34,35],"arduino","atmega","avr","c","embedded-ml","inference-engine","iot","machine-learning","microcontroller","neural-network","security","tiny-ml","2026-06-12 04:01:29","# MINERVA\n\n| Category | Badges |\n|---|---|\n| **Release** | ![Version](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fversion-1.3.0-blue) ![Codename](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fcodename-Athena-gold) |\n| **Core** | ![Language](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Flanguage-C-00599C) ![Standard](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FC-C11-blue) ![License](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Flicense-MIT-green) |\n| **Quality** | ![Build](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fbuild-passing-brightgreen) ![Tests](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Ftests-26%20passing-brightgreen) |\n| **Embedded Constraints** | ![Allocation](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fallocation-zero-orange) ![Dynamic Memory](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fdynamic%20memory-none-red) |\n| **Security** | ![Security](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fsecurity-encrypted%20%7C%20authenticated-purple) ![Crypto](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fcrypto-ChaCha20%20%2B%20BLAKE2s-purple) |\n| **Hardware Targets** | ![Targets](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Ftargets-AVR%20%7C%20STM32%20%7C%20Host-lightgrey) ![MCU](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fmin%20target-ATmega328P-informational) |\n| **Footprint** | ![RAM](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FRAM-~960B-informational) ![Flash](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fflash-~14KB-informational) |\n\n\u003Cimg width=\"2349\" height=\"758\" alt=\"image\" src=\"https:\u002F\u002Fgithub.com\u002Fuser-attachments\u002Fassets\u002Fefc12c71-9c4c-42d3-a6c9-70d513156137\" \u002F>\n\n\n\n**Minimal Inference Engine for Robust, Verifiable, and Authenticated ML**\n*Version 1.3.0 - \"Athena\"*\n\n```\nSmall. Secure. Certain.\n```\n\nMinerva is a pure C ML inference library for microcontrollers, from ATtiny85 to\nSTM32, with military-grade security properties. It runs encrypted,\nintegrity-verified neural networks with constant-time execution, anti-glitch\ncanaries, blinded LUT activations, output authentication, and zero dynamic\nallocation.\n\nThe smallest supported target is an **ATmega328P** (32 KB flash, 2 KB RAM).\nA 3-layer MLP runs in ~14.5 KB flash at ~28 ms\u002Finference including all\nsecurity overhead.\n\n---\n\n## The Three Minerva Laws\n\n> **I. Certainty** - Minerva never produces output from an unverified model.\n> Integrity checking is not optional.\n\n> **II. Silence** - Minerva reveals nothing about weights, activations, or\n> intermediate state through timing, power, or output behavior.\n\n> **III. Stillness** - Minerva never allocates dynamically. Every byte it will\n> ever use is known at compile time.\n\n---\n\n## Features\n\n| Feature | Details |\n|---|---|\n| **Architectures** | MLP, 1D CNN, Binary Neural Network (BNN) |\n| **Quantization** | Q8 (int8), Q4, Binary (1-bit XNOR+popcount) |\n| **Weight encryption** | ChaCha20-256, RFC 7539, constant-time |\n| **Integrity** | BLAKE2s-256 keyed MAC, encrypt-then-MAC |\n| **Accumulator** | int32_t throughout -- no overflow for any layer width |\n| **Anti-glitch** | SRAM canaries + double-run comparison |\n| **Blinded LUT** | Offset-masked activation scan, Law II hardening (v1.1) |\n| **Output auth** | Per-inference session MAC, replay prevention (v1.1) |\n| **Allocation** | Zero. Static buffers only. |\n| **Targets** | ATtiny85, ATmega328P, ATmega2560, STM32F0\u002FF4, Host |\n| **Compiler** | Python: float model to encrypted C arrays + debug dump |\n\n---\n\n## Quick Start\n\n### 1. Configure\n\nEdit `include\u002Fmnv_config.h`:\n\n```c\n#define MNV_TARGET_ATMEGA328P\n#define MNV_ARCH_MLP\n#define MNV_QUANT_Q8\n\n#define MNV_INPUT_SIZE    8U\n#define MNV_LAYER_0_SIZE  16U\n#define MNV_LAYER_1_SIZE  8U\n#define MNV_OUTPUT_SIZE   4U\n```\n\n### 2. Compile model\n\n```bash\n# One-time: generate device key\npython compiler\u002Fminerva_compile.py --gen-key key.bin\n\n# Compile trained model\npython compiler\u002Fminerva_compile.py model.npz \\\n    --key key.bin --target atmega328p --quant q8\n\n# Optional: dump decrypted weights for Python-side validation\npython compiler\u002Fminerva_compile.py model.npz \\\n    --key key.bin --target atmega328p --dump-weights\n```\n\n### 3. Use in firmware\n\n```c\n#include \"minerva.h\"\n#include \"weights.h\"   \u002F\u002F generated\n#include \"secrets.h\"   \u002F\u002F defines MNV_DEVICE_KEY\n\nstatic mnv_ctx_t ctx;\n\nvoid setup(void) {\n    if (mnv_init(&ctx, &mnv_model) != MNV_OK) fatal();\n    mnv_seed_prng(&ctx, read_adc_noise()); \u002F\u002F hardware entropy\n}\n\nvoid loop(void) {\n    int8_t input[MNV_INPUT_SIZE]   = { \u002F* sensor data *\u002F };\n    int8_t output[MNV_OUTPUT_SIZE] = { 0 };\n\n    if (mnv_run_with_model(&ctx, &mnv_model, input, output) == MNV_OK) {\n        uint8_t cls = mnv_ct_argmax(output, MNV_OUTPUT_SIZE);\n        act_on_class(cls);\n    }\n}\n```\n\n---\n\n## Resource Budget\n\n**Target:** ATmega328P, **Model:** MLP 8->16->8->4, Q8\n\n| Resource | v1.1 | v1.2 | Budget |\n|---|---|---|---|\n| Flash | 14,438 B | 14,494 B | 32,768 B |\n| SRAM | 1,442 B | 1,488 B | 2,048 B |\n| Inference time | ~26 ms | ~28 ms | -- |\n| Flash delta | -- | +56 B | int32 accumulator |\n\nThe +56 B flash and +2 ms for int32 accumulator is the correct engineering\ntradeoff: int16 overflows for any layer with more than 2 inputs.\n\n---\n\n## What Changed in v1.2\n\n### Bug 1 -- BLAKE2s rotation direction (critical, security)\nBLAKE2s uses ROTATE RIGHT in its G mixing function. v1.0\u002Fv1.1 used ROTATE\nLEFT for the 12, 8, and 7-bit rotations. This caused every MAC verification\nto fail, meaning tampered models were accepted and legitimate models were\nrejected. Fixed with ROTR32 macro.\n\n**Impact:** MAC verification was completely broken in v1.0 and v1.1.\n\n### Bug 2 -- int16 accumulator overflow (critical, correctness)\nThe Q8 dot product accumulator was `int16_t`. For any layer with 3 or more\ninputs, `N * 127 * 127 > 32767` overflows int16. For typical networks\n(8+ inputs per layer), results were completely wrong.\n\nFixed: `mnv_acc_t` is now `int32_t` throughout. Cost: +56 B flash, +2 ms\ninference on ATmega328P.\n\n### Bug 3 -- Weight matrix transpose (critical, correctness)\nThe Python compiler serialized weights as `W[in, out]` row-major, but the C\nengine indexes them as `W[out, in]` (weight[out_neuron * in_sz + in_neuron]).\nEvery inference produced wrong outputs.\n\nFixed: compiler now transposes before serialization: `quantize(W.T)`.\n\n### Bug 4 -- CT argmax broken (correctness)\nThe branchless select in `mnv_ct_argmax` used incorrect sign-bit extraction\nthat always returned index 0 for typical input vectors.\n\nFixed: rewrote with `diff16 = (int16_t)vec[i] - (int16_t)max_val` and\n`is_gt = ~((uint8_t)((uint16_t)(diff16-1) >> 8))`.\n\n### Bug 5 -- MNV_MIN_CONFIDENCE default too aggressive\nDefault of 64 (25% of Q8 range) rejected valid inferences from models with\nsmall-magnitude output logits.\n\nFixed: default changed to 0 (disabled). Set per-application via\n`-DMNV_MIN_CONFIDENCE=N` or in `mnv_config.h`.\n\n---\n\n## Python Validation Note\n\nWhen simulating Q8 inference in Python, use `\u002F\u002F128` for the accumulator\nright-shift, NOT `>>7`. Python's `>>` on arbitrary-precision integers does\nnot match C's arithmetic right shift on `int32_t` for negative values in all\ncases. The compiler's `--dump-weights` flag emits `weights_debug.npz` with\nthe exact quantized arrays for validation:\n\n```python\nimport numpy as np\n\nd = np.load(\"weights_debug.npz\")\nW0T_q, b0_q = d[\"W0T_q\"], d[\"b0_q\"]\n\nx  = input_q8.astype(np.int32)\nh0 = np.maximum(0, np.clip(\n    (W0T_q.astype(np.int32) @ x) \u002F\u002F 128 + b0_q.astype(np.int32),\n    -128, 127)).astype(np.int32)\n# ... continue for each layer\n```\n\n---\n\n## Stress Test Results (simavr, ATmega328P @ 16 MHz)\n\nModel: 8->16->8->4 MLP, Q8, 4-class sensor classification, 99.2% float accuracy.\n\n```\nInit: verifying MAC... OK          \u003C- Bug 1 fixed (was FAILED in v1.0\u002Fv1.1)\nSCORE: 8\u002F16                        \u003C- Q8 model accuracy (not a Minerva bug)\nRe-verify MAC: OK\navg inference: 27,883 us\nmax inference: 27,905 us\nFlash: 14,494 B \u002F 32,768 B (44.2%)\nSRAM:   1,488 B \u002F  2,048 B (72.7%)\n```\n\nThe 8\u002F16 Q8 accuracy reflects quantization degradation on class boundaries,\nnot a Minerva engine bug. Python Q8 simulation agrees with firmware 16\u002F16,\nconfirming the engine computes correctly. See Known Limitations.\n\n---\n\n## Known Limitations (v1.3 Roadmap)\n\n**Bias quantization scale**\nBiases are quantized independently (scaled to [-127,127]). For models\ntrained in float32, this works well for hidden layers but can distort the\noutput layer when one class has a much larger bias than others. The correct\nfix is quantization-aware training (QAT) where the model is trained with\nsimulated Q8 rounding. A `--qat-export` flag is planned for v1.3.\n\n**SRAM weight scratch buffer**\nThe weight scratch buffer is sized for the widest layer (MNV_LAYER_0_SIZE *\nMNV_INPUT_SIZE bytes). For models with large intermediate layers, this can\npush SRAM usage high. Layer-by-layer streaming with smaller scratch is\nplanned.\n\n**Output bus integrity**\nOutput MAC (v1.1) covers the result but does not encrypt it. A consumer on\nthe output bus can read the plaintext inference result. Encrypted output\nchannels are planned for v1.3.\n\n---\n\n## Security Architecture\n\n```\nFlash (read-protected)\n+-------------------------------------------------------+\n|  [IV 12B] [BLAKE2s MAC 32B] [ChaCha20 ciphertext]    |\n+-------------------------------------------------------+\n         | mnv_init(): BLAKE2s verify -- halt on failure\n         | mnv_run():  decrypt one layer at a time\n\nSRAM (volatile)\n+-------------------------------------------------------+\n|  [canary x4] [act_buf_a] [act_buf_b] [weight_scratch] |\n|  [canary x4]   \u003C- zeroed after each layer             |\n+-------------------------------------------------------+\n         | double-run comparison on every inference\n         | blinded LUT: 256-entry scan per activation\n\nOutput (v1.1+)\n+-------------------------------------------------------+\n|  output[0..N] + BLAKE2s-8B(output || input || counter)|\n+-------------------------------------------------------+\n```\n\n---\n\n## Running Host Tests\n\n```bash\nmkdir build && cd build && cmake .. -DMNV_TARGET=host && make && ctest -V\n```\n\nOr directly:\n\n```bash\ngcc -DMNV_TARGET_HOST -Iinclude -Isrc\u002Fcore -Isrc\u002Fsecurity -Isrc\u002Farch -Isrc\u002Fhal \\\n    tests\u002Fhost\u002Ftest_host.c src\u002Fcore\u002Fmnv_fixed.c \\\n    src\u002Fsecurity\u002Fmnv_chacha20.c src\u002Fsecurity\u002Fmnv_blake2s.c \\\n    src\u002Fsecurity\u002Fmnv_ct.c src\u002Fsecurity\u002Fmnv_lut.c \\\n    src\u002Fsecurity\u002Fmnv_outauth.c src\u002Fhal\u002Fmnv_hal_host.c \\\n    -std=c11 -O2 -o test_host && .\u002Ftest_host\n# Expected: All 32 tests PASSED.\n```\n\n---\n\n## Supported Targets\n\n| MCU | Flash | RAM | Max Params (Q8) | Status |\n|---|---|---|---|---|\n| ATtiny85 | 8 KB | 512 B | ~2K (BNN only) | ✓ |\n| ATmega328P | 32 KB | 2 KB | ~14K | ✓ |\n| ATmega2560 | 256 KB | 8 KB | ~200K | ✓ |\n| STM32F0 | 64 KB | 8 KB | ~40K | ✓ |\n| STM32F4 | 1 MB | 192 KB | ~800K | ✓ |\n\n---\n\n## Citation\n\n```bibtex\n@software{minerva2025,\n  title   = {MINERVA: Minimal Inference Engine for Robust, Verifiable,\n             and Authenticated ML},\n  version = {1.2.0},\n  year    = {2025},\n  note    = {https:\u002F\u002Fgithub.com\u002Fkavishka-dot\u002Flibminerva}\n}\n```\n\n---\n\n## License\n\nMIT License. See `LICENSE`.\n\n---\n\n*\"Inference is only useful when the model can be trusted.\"*\n","MINERVA 是一个专为微控制器设计的轻量级机器学习推理引擎，特别适用于资源受限的环境。它支持MLP、1D CNN和二值神经网络等架构，并通过Q8、Q4及二值量化技术优化模型大小与性能。该项目采用C语言编写，具有零动态内存分配的特点，确保了在如ATmega328P这样低端MCU上的稳定运行。其核心功能包括使用ChaCha20加密算法保护权重安全、利用BLAKE2s进行完整性验证以及实施多种防篡改措施来增强数据处理过程的安全性。MINERVA非常适合需要高度安全性和低功耗的应用场景，比如物联网设备中的边缘计算任务。","2026-06-11 04:01:21","CREATED_QUERY"]