A high-performance Go microservice wrapping the NIST SP 800-90B entropy assessment C++ toolkit via CGO. Provides a CLI, optional gRPC API, and Prometheus metrics with deterministic builds and reproducible outputs. CI enforces a 90% coverage threshold (-tags=teststub); current snapshot coverage is 86.2%.
The service is validated against the upstream NIST reference tools (SP800-90B_EntropyAssessment) and the generated Go bindings:
| Scope | Status | Notes |
|---|---|---|
| NIST C++ parity | Reference build + artifact comparison | nist-validation.yml builds the upstream C++ tools, runs them on bundled datasets, executes the Go wrappers, and uploads both outputs for manual diffing. Automated comparator script is pending. |
| CGO bridge | Unit/integration coverage | IID/Non-IID flows, error paths, and metrics hooks are exercised in unit tests; CGO happy paths are compiled in CI. |
docker-compose up -d- gRPC: enable with
GRPC_ENABLED=true(default portGRPC_PORT=9090, mapped indocker-compose.yml). - Metrics/health:
METRICS_PORT/SERVER_PORT(default 9091). Set either variable to match your compose port mapping. - Prometheus:
localhost:9092 - Grafana:
localhost:3000(admin/admin)
Defaults align with the SP800-22 service (GRPC_PORT=9090, METRICS_PORT=9091); override the env vars if you want different ports when running both stacks together.
# Install system deps and build the NIST C++ library
make deps
make build-nist
# Build Go binaries (CGO enabled)
make build
# Run the server with gRPC enabled
SERVER_PORT=9091 GRPC_ENABLED=true GRPC_PORT=9090 ./build/serverKey environment variables:
METRICS_PORT/SERVER_PORT/SERVER_HOST- HTTP metrics/health bind address (default:0.0.0.0:9091)GRPC_ENABLED/GRPC_PORT- Enable and bind the gRPC APITLS_ENABLED- Enable TLS for the gRPC server (default: false)TLS_CERT_FILE/TLS_KEY_FILE- Server certificate and key (required when TLS is enabled)TLS_CA_FILE- Optional CA bundle for client cert verification (mTLS)TLS_CLIENT_AUTH- Client auth mode (none,request,requireany,verifyifgiven,requireandverify; default:none)TLS_MIN_VERSION- Minimum TLS version (1.2or1.3; default:1.2)AUTH_ENABLED- Enable OAuth2/OIDC token validation for gRPC calls (default: false)AUTH_ISSUER/AUTH_AUDIENCE- Expected issuer and audience (required when auth is enabled)AUTH_TOKEN_TYPE- Token mode:jwt(default) oropaqueAUTH_JWKS_URL- Optional custom JWKS endpoint override (JWT mode)AUTH_INTROSPECTION_URL- OAuth2 introspection endpoint (required in opaque mode)AUTH_INTROSPECTION_AUTH_METHOD- Introspection client auth (client_secret_basicdefault orprivate_key_jwt)AUTH_INTROSPECTION_CLIENT_ID/AUTH_INTROSPECTION_CLIENT_SECRET- Introspection client credentials (required forclient_secret_basic)AUTH_INTROSPECTION_PRIVATE_KEY- Private key content forprivate_key_jwt(PEM, JWK JSON, or Zitadel key JSON)AUTH_INTROSPECTION_PRIVATE_KEY_FILE- Alternative file path forAUTH_INTROSPECTION_PRIVATE_KEY(mutually exclusive)AUTH_INTROSPECTION_PRIVATE_KEY_JWT_KID- Optional JWT headerkidoverride forprivate_key_jwtAUTH_INTROSPECTION_PRIVATE_KEY_JWT_ALG- Optional signing alg override (RS256orES256)AUTHZ_REQUIRED_ROLES/AUTHZ_REQUIRED_SCOPES- Optional required roles/scopes (comma-separated); enables authorization checks when setAUTHZ_ROLE_MATCH_MODE/AUTHZ_SCOPE_MATCH_MODE- Matching mode for required roles/scopes (anyorall; default:any)AUTHZ_ROLE_CLAIM_PATHS/AUTHZ_SCOPE_CLAIM_PATHS- Optional claim paths (comma-separated, dot-notation supported) used for role/scope extractionMAX_UPLOAD_SIZE/TIMEOUT/LOG_LEVEL- Upload limit, server timeouts, and logging level
ZITADEL private_key_jwt examples:
# PEM (inline or from file)
AUTH_TOKEN_TYPE=opaque
AUTH_INTROSPECTION_URL=https://<zitadel-domain>/oauth/v2/introspect
AUTH_INTROSPECTION_AUTH_METHOD=private_key_jwt
AUTH_INTROSPECTION_CLIENT_ID=<client-id>
AUTH_INTROSPECTION_PRIVATE_KEY_FILE=/run/secrets/zitadel-private-key.pem
AUTH_INTROSPECTION_PRIVATE_KEY_JWT_ALG=RS256# Zitadel key JSON envelope (contains keyId/key/clientId)
AUTH_TOKEN_TYPE=opaque
AUTH_INTROSPECTION_URL=https://<zitadel-domain>/oauth/v2/introspect
AUTH_INTROSPECTION_AUTH_METHOD=private_key_jwt
AUTH_INTROSPECTION_PRIVATE_KEY='{"keyId":"...","key":"-----BEGIN PRIVATE KEY-----\n...","clientId":"..."}'# Non-IID assessment (8 bits per symbol)
./build/ea_tool -non-iid -bits 8 data.bin
# IID assessment (auto-detect bit width)
./build/ea_tool -iid -bits 0 data.bin
# JSON output to file
./build/ea_tool -non-iid -bits 8 data.bin -output result.jsonRun the server with GRPC_ENABLED=true, then call via grpcurl:
DATA_BASE64=$(base64 -w0 data.bin)
grpcurl -plaintext \
-d '{"data":"'"$DATA_BASE64"'","bits_per_symbol":8,"non_iid_mode":true}' \
localhost:9090 nist.v1.EntropyService/AssessEntropynist-800-90b-test-suite/
├── api/nist/v1/ # Protobuf API definitions
├── cmd/
│ ├── ea_tool/ # CLI entry point
│ └── server/ # gRPC server + metrics/health
├── internal/
│ ├── config/ # Environment-driven configuration
│ ├── entropy/ # CGO bridge + result types
│ ├── middleware/ # Request-ID interceptor
│ ├── metrics/ # Prometheus instrumentation
│ └── nist/ # NIST C++ sources, wrapper, build assets
├── pkg/pb/ # Generated protobuf code
└── tools/ # CI utilities and scripts
- Entropy Engine (
internal/entropy/): CGO bindings to the NIST SP 800-90B C++ implementation with Go-friendly result structures. - Service Layer (
internal/service/,cmd/server): gRPC handlers for IID and Non-IID estimators with request IDs and structured logging. - CLI Tool (
cmd/ea_tool): Batch processing with IID/Non-IID modes, JSON output, and verbosity controls. - Observability (
internal/metrics/,internal/middleware/): Prometheus counters/histograms, min-entropy gauges, and request ID propagation. - Configuration (
internal/config/): Environment-based configuration for ports, timeouts, log levels, and upload limits.
make testmake coverage # deterministic profile + threshold check (90%)
make cover-html # open build/coverage.htmlmake test-raceThe nist-validation.yml workflow builds the upstream NIST C++ tools, runs them against bundled self-test datasets, executes the Go implementation, and uploads both outputs for comparison. An automated diff script (tools/validate_nist_cpp_vs_go.sh) is pending; manual review of artifacts is currently required.
Benchmark targets run the CGO entropy assessments via go test -bench in internal/entropy/:
make bench # quick run
make bench-all # 10 iterations, writes build/bench-current.txt
make bench-baseline # save baseline to build/bench-baseline.txt
make bench-compare # compare current vs baseline (requires benchstat)bits_per_symbolmust be between 0 (auto-detect) and 8.- Default upload cap:
MAX_UPLOAD_SIZE=100MB. - gRPC is optional; enable with
GRPC_ENABLED=trueand configure ports viaGRPC_PORT/METRICS_PORT.
Use Prometheus metrics to monitor latency and data sizes. For deeper investigation, run the CLI under go test profiles (e.g., go test -c ./cmd/ea_tool and execute with -test.cpuprofile) or wrap the service with standard pprof tooling during local runs.
Metrics are exposed at /metrics when METRICS_ENABLED=true (default):
entropy_requests_total— total requests by test typeentropy_duration_seconds— assessment duration histogramentropy_errors_total— error counts by typeentropy_data_size_bytes— observed payload sizesentropy_min_entropy_value— distribution of computed min-entropy
Health endpoint: /health returns service status and version.
Each gRPC request receives a UUID x-request-id, is logged with duration, and is returned in response metadata for traceability.
Zerolog provides structured JSON logs with request IDs, methods, durations, and errors. Control verbosity via LOG_LEVEL (debug, info, warn, error).
Detailed documentation is available in the docs/ directory:
- Architecture -- System design, component relationships, CGO bridge design, build architecture, deployment model, and integration with entropy-processor
- API Reference -- gRPC service contract, HTTP endpoints, CLI usage, Prometheus metrics, Go package interfaces, and C API specification
- Licensed under the MIT License; see
LICENSE. - Implements the algorithms from NIST SP 800-90B.
- CGO bindings wrap the official NIST reference implementation from https://github.com/usnistgov/SP800-90B_EntropyAssessment (bundled in
internal/nist).
- Go 1.25 or later with CGO enabled
- GCC toolchain:
g++,make,libbz2-dev,libdivsufsort-dev,libjsoncpp-dev,libmpfr-dev,libgmp-dev,libssl-dev protocfor regenerating protobufs- Docker and Docker Compose (for containerized deployment)
make help # Show all available targets
make proto # Generate protobuf code
make build-nist # Build NIST C++ library
make build # Build CLI + gRPC server
make build-arm64 # Cross-compile for ARM64
make run # Run server locally
make clean # Remove build artifacts
make fmt # Format code (gofumpt/gofmt/goimports)
make lint # Static analysis (staticcheck, vet)
make gosec # Security scan
make govulncheck # Vulnerability check
make coverage # Generate coverage + threshold check
make test-race # Run tests with race detector
make docker # Build Docker image- CI (
ci.yml): Protobuf generation, C++ build, Go build, static analysis, vulnerability scanning, unit tests (-tags=teststub), race detector, coverage threshold (90%), and artifact uploads. - NIST Validation (
nist-validation.yml): Builds the upstream C++ reference, runs validation datasets through both C++ and Go binaries, and publishes outputs for manual comparison.
- gRPC not reachable: ensure
GRPC_ENABLED=trueand the port inGRPC_PORTmatches your ingress mapping. - Build errors from CGO: install the required C++ dependencies (
make deps) and rebuild the NIST library (make build-nist). - Upload failures: adjust
MAX_UPLOAD_SIZE(bytes) if your dataset exceeds the default 100MB limit.
- Fork the repository and create a feature branch.
- Make changes with tests; ensure
make testandmake coveragepass. - Open a pull request. Validation against the upstream NIST reference runs in CI.