SOV · Regulatory Technology — Sovereign Data Residency
Sovereign Compliance Gateway — Verifiable Payment-Data Residency
C++20 reference implementation that attests where payment data is stored, seals each attestation into an RFC 6962 transparency log, and lets a supervisor check a record against a signed root. Written for the CBN payment-data localisation circular.
Maturity. A reference implementation, not a production deployment. Two high-severity findings from Vlaander's review remain open. First, the shipped witness and provenance tools derive their Ed25519 signing keys from a single public character, so anyone can forge a witness co-signature until you replace them with key files or an HSM. Second, the central plane accepts a seal with an empty, unsigned posture and then ignores the real signed posture for the same tree size, so whoever submits first can make the stored violation count zero (reproduced by Vlaander, 8 October 2026). The critical finding and two other high findings are fixed in the source you receive.
Overview
The source includes a research brief (REGULATION.md, marked partial) on CBN circular PSS/DIR/PUB/CIR/001/004. The brief reads it as requiring payment transaction data generated in Nigeria to be stored and managed in Nigeria from 1 January 2027. The gateway is built to produce evidence of that, record by record.
It works out of band. An inventory scanner reads exports that list where stored artefacts live, such as an object-store inventory or a database catalogue export. It never opens the data and does not sit in a payment flow. Each entry is classified, checked against the residency policy, and recorded as an attestation that holds salted hashes and metadata, not payloads.
Attestations go into a hash-chained, signed ledger and an RFC 6962 Merkle transparency log. The source also includes a witness service, an N-of-M witness quorum, threshold co-signed tree heads, a multi-tenant central plane with an HTTP API, a return renderer, and a standalone verifier that checks a record's inclusion proof and the operator's Ed25519 signature on the root.
The verifier proves that a record was attested and sealed under the operator's key. It does not re-run the policy, require a witness signature, or confirm that the region declared in the inventory is true.
The problem
A supervisor receiving a bank's self-attestation of data residency has nothing to check it against. This code gives each residency decision a signed, sealed record that a supervisor can verify independently and that cannot be silently changed later. That is not the same as proving the declared location is correct.
What it does
- Out-of-band inventory scanner: reads store inventories (locator, region, data class, content reference) and never opens the stored objects.
- Classification and policy for payment, personal and non-regulated data. An unrecognised declared data class is treated as the strictest category, and approved Nigerian facilities are matched as whole tokens rather than substrings (both fixed 8 October 2026).
- Attestation records with salted hashes of the storage locator and content reference, chained into a signed ledger with a durable file store and crash recovery.
- RFC 6962 Merkle transparency log with inclusion and consistency proofs. The consistency check includes the RFC 9162 final-step check (fixed 8 October 2026).
- Witness service over a Unix socket, an N-of-M quorum that verifies co-signatures, split-view detection for heads of the same size, and a 2-of-3 threshold co-signing demonstration (operator, witness, bank).
- Signing through libsodium Ed25519 or a PKCS#11 module, with a libsodium-backed soft token to exercise the PKCS#11 path without hardware.
- Multi-tenant central plane over plain HTTP that re-verifies each tenant's seal signature and append-only consistency, keeps tenants separate and aggregates posture.
- Return renderer for a draft CBN return format (marked v1-draft in the code), and signed build provenance over a source manifest.
- Standalone verifier (scg_verify) that checks a record's inclusion under a signed root against the operator's public key.
Performance
No benchmark figuresSOV publishes no benchmark figure, so its value rests on the assurance and scope below rather than on a number to reproduce.
Value in your own metrics
- Supervisor verification
- With the evidence bundle and the operator's public Ed25519 key, scg_verify reports VERIFIED. Changing one field of the sealed record makes it fail, and with the wrong key it reports authenticity unconfirmed (checked by Vlaander, 8 October 2026). It does not check witness signatures or re-run the policy.
- Payment-path dependency
- None by design. The scanner reads inventory exports out of band, so if it fails, evidence arrives late but payments are not affected.
- Customer-data exposure
- Records hold salted hashes and metadata, never payloads, but they name the jurisdiction and facility in plain text. The salt is applied as a SHA-256 prefix rather than an HMAC, and the shipped salt is a test constant, so production needs a secret salt per tenant (audit finding A8).
- Rewriting sealed history
- Detectable. In the scg_trust demonstration, a forged root fails the consistency check from the earlier head and the witness flags the equivocation (checked by Vlaander, 8 October 2026). Split views at different tree sizes are not flagged, and witnesses co-sign whatever timestamp the operator sends.
- Crash recovery
- In scg_pilot, a ledger rebuilt from its durable store verifies its chain and reproduces the live Merkle root (checked by Vlaander, 8 October 2026). A single torn write at the end of the log stops recovery altogether.
- Regulatory return
- Generated from the sealed records. The schema is a draft, pending the circular's final schedule. Violation counts are signed by the tenant key, but the open central-plane finding in the notice above lets an unsigned empty posture take their place.
- Dependency surface
- Two optional system libraries, both detected at build time: libsodium for Ed25519 and the p11-kit PKCS#11 header for HSM signing. Without libsodium only a test signer is built. Nothing is vendored or downloaded during the build.
Assurance and build
- Language
- C++20 (CMake 3.20 or later)
- Size
- About 6,000 lines of C++ in src and include, plus 940 lines of tests (counted by Vlaander)
- Build
- No warnings with g++ 13.3 on Ubuntu 24.04 under the project's warning flags plus -Werror. clang 18.1.3 builds it and the tests pass, but it reports 20 warnings, so -Werror fails (checked by Vlaander, 8 October 2026)
- Tests
- With libsodium 1.0.18 and the p11-kit header, all 4 test suites pass, including PKCS#11 signing through the soft token, and they also pass under AddressSanitizer and UndefinedBehaviorSanitizer (g++ 13.3, checked by Vlaander, 8 October 2026). Without libsodium only 3 suites are built. They report passing, but the central-plane suite skips all its checks and the other two skip their Ed25519 checks
- Not included
- No fuzzing harness and no ThreadSanitizer configuration ship with the source
- Transparency log
- RFC 6962 Merkle tree. Roots are byte-identical to transparency-dev/merkle at 10,000, 100,000 and 1,000,000 entries (measured by Vlaander, 7 October 2026)
- Scalability
- Every signed tree head and every proof recomputes the whole tree. At 1,000,000 entries, one signed head took about 1.3 s and one inclusion or consistency proof about 1.2–1.3 s, against about 3–10 µs for transparency-dev/merkle (measured by Vlaander on one pinned core of a shared AMD EPYC 7763 Codespace, 7 October 2026)
- Internal review
- Vlaander quality review, 7 October 2026: 1 critical, 4 high, 7 medium and 11 low findings. The critical finding (offshore storage could be recorded as held in an approved Nigerian facility) and 2 high findings (unknown data classes approved by default; fake tree sizes accepted by the consistency check) are fixed in the source you receive (8 October 2026). Still open: the two high findings in the notice above, all medium and low findings, and the scalability limit.
Releases are not yet cryptographically signed, and no release manifests or external audit summaries are published. Check the source tarball you receive against its SHA-256 in Schedule 1 of your Sale and Assignment Agreement, which you see before you sign.
Scope and maturity
What is real today, what is deliberately excluded, and what is pending — published unprompted.
Included today
- Source code of a reference implementation, with its own security audit (SECURITY_AUDIT.md), threat model (SECURITY.md), and design, architecture and regulation notes.
- The core engine (observe, classify, apply policy, attest, seal), the transparency log and witness tools, the central plane, the return renderer and the standalone verifier, with a demonstration program for each part.
Explicitly scoped out
- Connections to bank systems, cloud topology and data formats sit behind pluggable interfaces (observer, classifier, geo resolver, store, signer, return renderer) and are wired by the operator.
- HSM key custody and independent witness operators are deployment tasks. The source includes the PKCS#11 path, but no production keys or witnesses.
Pending
- Replace seed-derived keys in scg_witness, scg_provenance and the demonstrations with key files or PKCS#11, and have the quorum demonstration pin witness keys from configuration rather than from each responder's claimed id (finding SOV-4, open).
- Require a posture signature on every seal, including an empty posture, and reject a same-size resubmission whose posture differs (finding SOV-5, open).
- Add an incremental tree so that signed heads and proofs no longer cost O(n) each (finding SOV-6, open).
- Open medium findings: residency is taken from the inventory's declared region without a cross-check, and any non-empty lawful-basis string approves a cross-border transfer of personal data; the verifier needs no witness signature; witnesses accept backdated timestamps; split views at different sizes go undetected; the 5 s socket timeouts apply per read, so one slow client can block the single-threaded witness; recovery checks the hash chain but not signatures.
- The central plane serves plain HTTP without TLS, and tenant registration is open unless SCG_PLANE_ADMIN_TOKEN is set.
- Final CBN return schedule: the return schema is a draft, and the source's regulation brief is marked partial.
Who it's for
- Nigerian deposit money banks and other institutions covered by the CBN payment-data localisation circular.
- Switches, payment solution service providers (PSSPs) and payment terminal service providers (PTSPs) with residency obligations under the same circular.
- Institutions under other data-residency rules, which would need their own policy, geo-resolver and return-renderer modules.
- Supervisory technology vendors looking for a signed-attestation and transparency-log base rather than a self-attestation workflow.
Before you buy
- Confirm with counsel what the circular requires and that the rendered return meets the form and cadence the supervisor expects. Whether a supervisor accepts cryptographic evidence is a regulatory question, not an engineering one.
- Check the out-of-band model against your own payment topology. The evidence covers only what appears in the inventories you feed it, and the region in those inventories is taken as declared.
- Plan the witness set and key custody before relying on the quorum. With the shipped tools the witness keys are public, so non-equivocation holds only once each witness has its own secret key and is run independently.
- Read the security audit shipped with the source (SECURITY_AUDIT.md) together with the review findings listed above. Together they cover the test-grade signing seeds, the static payload-hash salt and the open central-plane posture issue, all of which must be fixed before production.
What transfers
- The asset's sourceSubject to the Sale and Assignment Agreement, Vlaander assigns to the verified Buyer the transferable right, title and interest that Vlaander owns in the specified Asset. The assignment excludes Third Party Materials, open-source components, Vlaander’s pre-existing tools, generic know-how, development methods, trademarks, confidential information and any rights that cannot lawfully be assigned.
- Its testsThe test suite the published assurance claims rest on, as delivered in the source archive.
- Its audit artefactsSpecifications, model-checking output, reviews and the software bill of materials, where the asset has them.
- Not includedThird-party and open-source materials are not sold or assigned by Vlaander. They remain under their own licences, listed in each asset’s software bill of materials (SBOM.md in the archive), and the Buyer is responsible for complying with those licences.
First described in: VLA-GEN catalogue, 3 August 2026, §3.4. Revised by Vlaander against the delivered source; every figure is labelled with its basis.
From test to source
- 01
Check
Read the engine's page: what Vlaander measured and on which hardware, what it has not measured, and the open review findings. Nothing runs before purchase.
- 02
Buy
Verified businesses only. Place the order, give your company's details, have your authorised signatory sign the Sale and Assignment Agreement, then pay the invoice in naira by bank transfer, or in USDC on Polygon. Once the payment is verified, your account shows Paid.
- 03
Receive
We confirm the funds and release the source tarball to you. Delivering, then Download ready. Check it against the SHA-256 in Schedule 1, then rerun the tests and benchmarks yourself.