Aryan Malhotra

Reston, Virginia aryanmalhotra796@gmail.com github.com/dank0i linkedin

About

I graduated from the University of Maryland in May 2026 with a BS in Computer Science, 3.91 GPA, Dean's List throughout, Cum Laude, and a nomination for the University Medal.

Most recently I interned at Civic Group, shipping production features on a case management platform used by caseworkers and admins. Analytics dashboards, automated inactivity detection, notification integrations, and NLP sentiment analysis to flag cases before they escalated. React and TypeScript on the frontend, Node.js and AWS behind it.

Outside work I build things I actually use. Everything below runs in my apartment or on my own hardware.

Projects

pc-bridge

Dec 2025 to present Rust, MQTT, Home Assistant

  • 1.3 MB binary
  • 2.5 MB RAM
  • <1% CPU
  • 254 commits
  • Windows + Linux

My gaming PC is headless and I play from bed over Moonlight, so Home Assistant needed a way to drive it. This is the agent that lets it. Game detection, power and idle events, hardware telemetry, and remote commands, over MQTT. Runs on Windows and on Linux under both X11 and Wayland.

Game detection is event driven through WMI subscriptions rather than polling. Steam libraries are discovered automatically by parsing the binary appinfo.vdf format. Config hot reloads without a restart.

Features are opt in. Remote command payloads are rejected if they contain shell metacharacters. Credentials live in Windows Credential Manager. An MQTT last will beacon stops automations firing at an agent that is already offline, and updates are signed with minisign and refuse to roll back.

pc-bridge settings window showing per-feature toggles
The settings window. Every feature is off until you turn it on, here 19 of 33.
Home Assistant device page for PC Control
The Home Assistant side, mid transition. The activity log shows booting resolving to on.

cyclone2

2026 Firmware reverse engineering, Ghidra, Raspberry Pi

  • 166 to 230 Hz
  • one byte changed
  • JieLi BR23

I pulled the firmware off a GameSir Cyclone 2 from a flash dump and mapped the timer subsystem and the wireless report path in Ghidra. One divider byte was holding the 2.4 GHz report rate at 166 Hz. Changing it took the pad to 230 Hz.

A Raspberry Pi bridge presents the controller to Windows as an Xbox 360 receiver, and separately as a DualSense. That recovers rumble, battery reporting and RGB control, none of which the stock Bluetooth mode exposes.

I measured the physical ceiling of the link. Packet air time caps it near 400 Hz, and the shipped firmware already ran at 85% of that, so I stopped tuning.

Decompiled firmware showing a divide-by-four applied only in 2.4 GHz mode
The finding. Both send paths check the same in-flight counter, but the 2.4 GHz path adds a counter that has to reach four first. grep -c over the file returns two hits, both on these lines, so the divider is provably exclusive to that mode.

sc3

Aug 2026 Firmware reverse engineering, known-plaintext cryptanalysis, MVsilicon BP1048B2

  • 315,654 words, 0 unsolved
  • no hardware needed
  • four faders, flashed

My motherboard's line out goes into a FIFINE SC3 desk mixer, so its line-in fader works as a hardware volume knob. That is a good setup until you notice line in is also summed into the USB microphone send, and everyone in the call hears themselves back. FIFINE's V22 release notes say it fixes exactly this. It closes the USB loopback and leaves the analog path alone.

The routing lives in the DSP graph, the graph lives in the firmware, and the firmware is encrypted. There is no public reverse engineering tooling for MVsilicon parts. The way in was the corpus, not the cipher. 81 of 87 collected images on the same chip and SDK generation ship completely unencrypted. Encryption is a per-vendor build option and most vendors leave it off. The same SDK strings sit in plaintext elsewhere, which turns it into a known-plaintext attack needing no purchase, no vendor contact and no hardware.

The cipher is an address-keyed keystream with two byte-swap labels and a key-dependent table, derived and written out in full. All 315,654 words of the code image come out, none unsolved, verified against independently obtained plaintext.

Then the goal changed. The SC3 has four faders and the firmware reports one of them to the host. I had been planning to build a potentiometer box for a per-application volume mixer. I was already sitting in front of four faders that were digitised, scanned, and never sent anywhere. The patch exposes all four over USB HID. It is built, flashed, and running. The repository ships tooling only, no firmware.

The same 64 bytes of firmware shown as ciphertext and as decrypted code containing audio function names
The same 64 bytes at one offset, before and after. On the left, Code record entropy 7.999 and nothing to grep for. On the right, the audio subsystem naming itself.

Football match forecasting

Apr 2025 to Aug 2026 Python, LightGBM, PyTorch, SciPy

  • 25,979 matches
  • 11 leagues
  • 92% of market skill
  • 44 tests

Forecasts European football matches and scores the result against bookmaker odds instead of against nothing. An accuracy number for football means nothing without the baseline it has to clear.

70% accuracy on decisive matches against a 61% majority class baseline. 52% on the three way outcome against 46%. Using no betting data at all, it captures 92% of the bookmaker's forecast skill.

Four model classes: Elo ratings, FIFA squad ratings joined as of each kickoff from the starting elevens, a Dixon-Coles bivariate Poisson goal model, and a PyTorch network with learned team embeddings. The remaining gap to the market is an information limit rather than a modelling one, and there is a section on the writeup showing how I established that.

Reliability diagram comparing model and bookmaker calibration
When the model says 60%, it happens 60% of the time.
Ranked probability score by feature set
Every feature set against the bookmaker's line.

Read the full writeup

ledger

Jul 2026 Java, Spring Boot, PostgreSQL, React

  • double entry
  • idempotent posting
  • JUnit + MockMvc

A double entry transaction ledger. Spring Boot REST API, JPA and PostgreSQL with Flyway migrations, and a React and TypeScript frontend for accounts, balances and statement queries.

Posting is idempotent and validates that debits and credits balance. Reconciliation runs on a schedule. CSV imports deduplicate by row hash. Concurrent posting takes pessimistic row locks in consistent id order. That stops deadlocks and read modify write races on cached balances.

Ledger interface showing accounts, a posting form and an account statement
Accounts, posting, and a statement with a running balance. The eight balances sum to zero.

PC Control

2025 to present Python, Home Assistant

  • 7 states
  • 1,504 lines
  • 48 tests

The Home Assistant side of pc-bridge. It models a PC as a state machine, not an on off switch. An automation can tell booting from on, and sleeping from off, instead of guessing during the seconds when a machine is neither.

Liveness comes from two independent signals, ICMP ping and MQTT, so a PC that is reachable but has no agent running is distinguishable from one that is off. Pings are debounced over three misses, because a single dropped reply under load is not a shutdown, and a state that flaps fires every automation watching it.

State diagram of the seven PC power states and their transitions
The transitional states are the reason the integration exists. Each carries a timeout, so a boot that fails resolves instead of stranding the machine.

Also