Skip to content

Repository files navigation

Information Flow

Ask DeepWiki

Privacy-preserving verified reviews and dispute resolution on Midnight.

This project is built on the Midnight Network.

Information Flow gives every ordinary user the same account at registration. What they can do changes only after real events: a merchant records a purchase, a buyer receives a private purchase credential, a customer publishes a verified review or requests support, and an independent reviewer receives a specific escalated case. Public readers can verify the minimum public result without seeing the customer's identity, order details, or private support history.

The Wave 2 foundation includes a restartable account-first web application, a migration-driven SQLite schema, encrypted signing identities, expiring sessions, generic organizations and products, scoped authority lifecycle management, a Compact contract that stores append-only public commitments, a live Midnight deployment and reconnection test, and 27 passing ordinary tests.

The MVP treats InformationFlow as the aggregate root of the ontology:

Actor + Context + Record + Claim + View -> InformationFlow

The MVP validates private flows off-chain and stores only their public commitments on Midnight. A commitment is a cryptographic fingerprint: it can later prove that private flow data has not changed without publishing that data on-chain. The contract retains an append-only sequence of action commitments and the latest value for backward-compatible readers.

Domain layer

src/information-flow.ts defines the complete private aggregate and provides:

  • strict runtime validation of ontology relationships;
  • canonical serialization with stable ordering and Unicode normalization;
  • a cryptographically secure, 32-byte nonce generator;
  • a versioned, length-delimited SHA-256 commitment function.

The private InformationFlow and nonce stay off-chain. Only the resulting 64-character commitment is passed to the Compact contract.

Behavior-derived four-actor slice

src/behavior-derived-system.ts implements the concrete Acme Audio H1 acceptance scenario. All accounts register with the same neutral schema. The system derives contextual actions from signed authority grants, signed purchase credentials, organization control, credential control, and case relationships; there is no setRole operation.

The scenario exercises four accounts from a blank state:

  1. Actor B receives authority to issue H1 purchase credentials.
  2. B signs Actor A's private credential for order ORD-88421.
  3. A publishes one verified H1 review without exposing A or the order.
  4. Actor C reads the public review but gains no private access.
  5. A opens support case CASE-992; B sees only the required eligibility facts.
  6. B records an integrity-protected support decision.
  7. A authorizes a recipient-, case-, purpose-, and record-bound bridge for REG-443 to Actor D.
  8. The exact disclosure, rather than a global reviewer role, allows only D to verify that case.

src/four-actor-scenario.ts remains the deterministic protocol fixture used by the live commitment test. The user-facing application is implemented by src/platform-demo.ts, src/demo-server.ts, and web/. It opens with ordinary login and registration modes plus a separate administrator-login mode, creates every ordinary user with the same account schema, and uses an HTTP-only session cookie. Purchase, business, support, or case tools appear only after the corresponding credential, authority grant, or case relationship exists. An ordinary account may request an organization, but the bootstrap system administrator must approve it before the requester receives organization control. The organization creator approves later membership requests. Scoped product authority can be issued only to approved members, and regulator capability is granted only after a separate administrator-approved application. Existing ordinary accounts keep the same neutral account schema.

The SQLite schema lives in migrations/ and is applied explicitly through the migration runner in src/persistence.ts. Accounts, password hashes, encrypted Ed25519 private keys, login sessions, organizations, control relationships, products, grants, inbox events, and immutable audit events survive a restart. Only a SHA-256 hash of each session token is stored. Grant expiration and revocation are evaluated by the centralized policy layer before every covered operation.

From Linux or Ubuntu WSL, use the primary startup script:

./start.sh

start.sh creates the ignored .env file with a stable cryptographically random data-encryption key on the first run, installs missing npm dependencies, builds the application, and starts it at http://127.0.0.1:4173. The same key is required after every restart, so the script never replaces an existing key. Press Ctrl+C to stop the server.

On the first run, the script stores the initial administrator as normal database data: the account row is linked from system_administrators. Administrator credentials remain configuration data and are never shown on the login page. The administrator approves organization-creation and regulator applications; the creator of an approved organization separately approves membership requests.

Use another port or explicitly refresh dependencies when needed:

./start.sh --port 4175
./start.sh --install

Windows PowerShell is an alternative entry point. It delegates to the same start.sh implementation through WSL:

.\start.ps1
.\start.ps1 -Port 4175
.\start.ps1 -Install

Ordinary-user registration accepts any password from 8 to 128 characters and never grants administrator status. New administrators are not self-registered; they remain separately managed database records. Purchases, reviews, support cases, disclosures, and Midnight submission tracking are still in-memory Wave 1 boundaries and are the next persistence slice. Ed25519 signatures and disclosure policy are verified in the off-chain domain layer; the Compact contract anchors commitments but does not itself prove those policy decisions.

Registration use case

src/register-information-flow.ts connects the private domain layer to a minimal CommitmentAnchor boundary. Registration deliberately has two phases:

  1. Prepare and retain the private nonce before making an unreliable network call.
  2. Submit only the public commitment and return a public transaction receipt.

Reusing the prepared registration retries the same commitment. The application tests use an in-memory fake anchor, while src/midnight-commitment-anchor.ts adapts the real Midnight callTx.registerFlow shape without exposing the privacy-sensitive remainder of its result. src/midnight-providers.ts composes the official provider set, src/midnight-wallet.ts provides a local-only wallet factory, and src/midnight-composition.ts assembles those pieces with a connected contract interface. src/midnight-contract-connection.ts supplies the stateless deployment and public-address reconnection boundary. Persistent commitment-submission tracking is not implemented yet, so the caller remains responsible for securely retaining the private flow and nonce.

Midnight contract definition

src/midnight-information-flow-contract.ts combines the compiler-generated contract binding with its prover, verifier, and ZKIR artifacts as a typed CompiledContract. This definition contains no wallet, private flow, nonce, or network connection; later composition code will use it to deploy or connect to the contract.

contracts/information-flow.compact stores each disclosed commitment under an append-only Uint<64> sequence and increments flowCount. It also retains flowCommitment as the latest value so the original single-commitment reader continues to work. No actor ID, credential, review, support record, regulatory record, or nonce is stored in public ledger state.

src/midnight-providers.ts assembles the Midnight.js provider set from public indexer and proof-server endpoints plus an already-created wallet capability. It derives a local storage scope from the wallet's public coin key and receives the private-state encryption password only as a callback. Provider construction does not read that password, contact the network, or submit a transaction.

src/midnight-wallet.ts is the local-only wallet boundary. It accepts a seed or mnemonic only through an injected callback, uses the official Midnight testkit builder without its seed-logging convenience method, starts the wallet, waits for waitForSyncedState(), and returns a stoppable wallet capability. The factory refuses non-undeployed networks and never returns the supplied secret.

src/midnight-composition.ts creates the application-facing runtime from an already connected contract interface. Deployment and lookup remain explicit operations: deployInformationFlowContract deploys the stateless compiled contract without application data, and connectInformationFlowContract reconnects using only its public contract address. Both return the official Midnight.js callTx interface consumed by the narrow commitment adapter.

Midnight.js 4.1.1 requires one shared @midnight-ntwrk/onchain-runtime-v3 instance across the compiler runtime and transaction runtime. The package override pins that transitive dependency to 3.0.0; without deduplication, two WASM class instances cause valid contract state to fail identity checks.

Verify

Run inside Ubuntu WSL:

npm install
npm run compile
npm run typecheck
npm test

The ordinary suite uses injected fakes and makes no network requests. After the disposable services are healthy and the example accounts have been funded, run either opt-in live check from Windows PowerShell:

npm run test:live
npm run test:live:scenario

Both live checks read the first disposable account from the adjacent Local Dev checkout in memory, create a random compliant storage password and isolated temporary LevelDB path, deploy the contract, and reconnect by public address. test:live submits one fixed 64-character commitment and checks both the latest value and sequence position zero. test:live:scenario executes the four-actor domain journey, submits its four action commitments, and asserts that indexed positions zero through three equal the prepared review, support request, signed decision, and regulatory-bridge commitments. The scripts print only public addresses, transaction IDs, commitments, and aggregate test evidence; they never print or copy the mnemonic.

Local Midnight environment

The official Midnight Local Dev checkout lives beside this repository at ../midnight-local-dev and is pinned for this MVP at commit 902561ddc27a4b096f19835ab1528f38ace515f1. It runs three localhost-only services:

Service Endpoint Pinned image
Midnight node http://127.0.0.1:9944 midnight-node:1.0.0
Indexer GraphQL http://127.0.0.1:8088/api/v4/graphql indexer-standalone:4.3.3
Proof server http://127.0.0.1:6300 proof-server:8.1.0

Start or resume the network from Windows PowerShell:

cd ..\midnight-local-dev
docker compose -p midnight-local-dev -f standalone.yml up -d
docker compose -p midnight-local-dev -f standalone.yml ps

For a fresh local ledger, initialize the repository's local-only example accounts with NIGHT and DUST:

npm start -- --fund-config .\accounts.example.json

Never reuse those example mnemonics outside this disposable local network, and never copy them into this repository. To stop the services without deliberately resetting the ledger:

docker compose -p midnight-local-dev -f standalone.yml stop

Copy .env.example to an ignored .env only when an application adapter needs the endpoint values. It contains no wallet seed or signing secret.

On this workstation, run Local Dev and Docker commands from Windows PowerShell; Docker integration is not enabled inside Ubuntu WSL. Continue to run this repository's TypeScript and Compact checks inside WSL.

Docker startup note

Docker Desktop 4.91.0 is installed, but this Windows host can still hit Docker's open stale AF_UNIX socket issue after an interrupted shutdown. The safe recovery used here was to stop Docker completely, rename the exact Docker\run and docker-secrets-engine runtime directories to timestamped backups, create a new empty Docker\run directory, and start Docker again. Do not use Reset to factory defaults for this symptom; consult the recorded procedure in AGENTS.md and the upstream issue first.

Compile

Run inside Ubuntu WSL:

npm run compile

The generated contract bindings are written to contracts/managed/information-flow/ and are intentionally not committed.

About

Privacy-preserving verified reviews, support, and regulatory escalation on Midnight.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages