Abstract Nonsense

A place for musings, observations, design notes, code snippets - my thought gists.

Rustlings

As part of my recent quest to learn Rust, I worked through the Rustlings exercises. You’re given a series of ~100 problems, and your goal is to fix the code to make it compile with passing tests. It was a pretty quick whirl-through, and I don’t think the examples are the most interesting, but as a short introduction to the syntax and rudiments of the semantics, it does the trick with aplomb. I did quite enjoy the interactive problem-solving CLI interface, though.

Networking Concepts by Beej

Computer networking always felt like an area in which I was lacking after completing my undergraduate CS education. A good while ago I stumbled across the excellent and freely accessible Beej’s Guide to Networking Concepts and worked through it, tracking my solutions in this solutions-guide-to-networking-concepts repository.

All solutions herein were produced without any LLM assistance. Where any cloze-style template is provided by the textbook for the project, I’ve adopted that as the basis for my solution. Any errors or lapses of understanding are solely my own.

Please note that the selection of chapters for which solutions are presented is non-contiguous as not all chapters in the textbook had programmatic questions or projects associated. The list of projects is as follows:

ChapterTextbook linkSolutions
5HTTP Client and ServerSolutions
9A Better Web ServerSolutions
12Atomic TimeSolutions
13The Word ServerSolutions
16Validating a TCP PacketSolutions
19Computing and Finding SubnetsSolutions
22Routing with Dijkstra’sSolutions
30Using SelectSolutions
39Multiuser Chat Client and ServerSolutions

With the exception of uni-curses’s for the last project, there’s no dependencies other than Python and the standard library.

My focus in these solutions is on simplicity and straightforward, imperative code, following the style used by Beej in the textbook. For production applications, you would certainly want to add more abstraction and robust parsing and error handling. These solutions are meant to be educational and illustrative.

I really enjoyed this little foray into the dark arts of networking, and learned a lot along the way. Most importantly, I learned a lot about what I still don’t know, which I find equally valuable. Here’s a little section-by-section retrospective on working through the exercises:

# 5 HTTP Client and Server

Here you build your own HTTP client and server, and practice opening sockets, sending bytes through and receiving bytes back. It was interesting reading through the socket docs to see what’s exposed by the OS, and learning about arcane incantation option flags like socket.SOL_SOCKET, socket.SO_REUSEADDR....

# 9 A Better Web Server

This was a fun little exercise, and got me thinking about how I would construct type-safe objects to represent the usual menagerie of HTTP headers, requests, paths, methods, protocols… For simplicity I went with TypeAlias to have something more explicit to put into function signatures. I can’t recall why I didn’t use the (relatively new) type statement, though.

It was also a little scary (and fun!) to think about just how many vulnerabilities that a naive implementation of a web server would expose, and just how much complexity is required to remediate those security holes.

# 12 Atomic Time

python
from contextlib import closing
def get_nist_time() -> int:
    with closing(socket.socket()) as s:
        s.connect((TIME_SERVER, TIME_PROTOCOL_PORT))
        logger.info(f'Connected to {TIME_SERVER}:{TIME_PROTOCOL_PORT}')
        
        response = b''.join(iter(lambda: s.recv(RESPONSE_BUFFER_SIZE), b''))
        logger.debug(f'Response: {response}')
        
        return int.from_bytes(response, byteorder='big')

I initially thought that using the closing utility was a smart way to automatically .close the socket after exiting the context manager, but I just realised that:

Changed in version 3.2: Support for the context manager protocol was added. Exiting the context manager is equivalent to calling close().

I also enjoyed using the functional-esque form of iter(callable, sentinel, /). The docs use this example that I borrowed to read data into the buffer from the socket:

One useful application of the second form of iter() is to build a block-reader. For example, reading fixed-width blocks from a binary database file until the end of file is reached:

python
from functools import partial
with open('mydata.db', 'rb') as f:
    for block in iter(partial(f.read, 64), b''):
        process_block(block)

# 13 The Word Server

In this project you have to build up a server-side packet stream that encodes words (English words that is, not machine words) and a client that consumes the packets and parses them. I don’t think my construction here is the cleanest, but I think it does the job for working within the scaffold of the solution and keeping it imperative. I also went down some side exploration on Python’s struct standard library module, and protobufs.

# 16 Validating a TCP Packet

This was an exercise in finagling with bit twiddling operations and coercing Python to use bit arithmetic instead of integer arithmetic. But quite enjoyable once you squash the inevitable off-by-n errors.

# 19 Computing and Finding Subnets

More bit-twiddling exercises! This all came together quite nicely though, and made for some fun arithmetic. doctests was my friend here for helping me validate the functions as I wrote them.

# 22 Routing with Dijkstra’s

This was a straight-forward implementation of Dijkstra’s’s algorithm for route finding. I haven’t dug into it much, but I know there’s a positively inordinate amount of complexity re efficient network routing. I quite enjoy reading the Cloudflare Blog to expose myself to more about the wide, wild and wonderful world of the web.

# 30 Using Select

Not much to say here, just a small exercise on using select. This was instructive in the broader I/O and OS file integration sense, though.

# 39 Multiuser Chat Client and Server

By far my favourite exercise, and one of those “you’ve got to build it yourself once” programmer exercises I can tick off the list!

There’s a veritable endless set of extensions I wanted to add to the project, but got called away by the pursuit of something else in the knowledge-verse. It was the perfect confluence of everything the book had worked through: bits and bytes, sockets, threads, error-handling, packet-wrangling… It was nice handling concurrent users and distributing packets between clients. As a small bonus, I could sneak in my favourite and sparsely utilised walrus operator:

python
while (cmd := read_command(f'{args.client_nickname}> ')) != CLIENT_QUIT_COMMAND:
    if cmd.startswith('/message'):
        _cmd, recipient, message = cmd.split(maxsplit=2)
        packet: bytes = chat_packet.dict_to_packet({
            'type': 'private_message',
            'recipient_nickname': recipient,
            'message': message
        })
    ...

# Conclusion

I’m glad I went through the textbook end-to-end and wrote up solutions for the learning experience, but I don’t think I’ll revisit this much. I think my time is probably better spent on learning other things now. At some point it might be nice to revisit these exercises in Rust, though. I think it provides better affordances and abstractions for writing cleaner and more expressive networking code than Python.

GitHub hijacks and breaks browser search

I like to keep a word list of any new and interesting words I come across day-to-day. Today I was curious how many entries were in my list and went to search the YAML file on GitHub.

To my delight, I discover that GitHub has hijacked the native Cmd-F browser search. To top it off, seems the maximum number of matches GitHub’s search returns is limited to 200.

I’ll excuse a search function that at least reports > 200 results matched, but there is no indication in the UI that this is the case. Even if you navigate to the 200th result and can see additional matches in the viewport, GitHub’s UI steadfastly refuses their existence.

Here’s what it looks like on macOS with Safari version 26.2:

Safari GitHub search

A quickly-disappearing hint on the GitHub search model reported that hitting Cmd-F again brings up the native browser search. I gave that a whirl, but it still wasn’t finding all matches. I thought I’d inspect the page source for the text elements to see what’s going on under the hood:

Viewport bug Safari GitHub

… and hit a render error. This is another lovely bug I’ve been running into when the viewport changes quickly in Safari. I can see a data-target="react-app.reactRoot" attribute lurking in the dark: maybe I shouldn’t besmirch the React-ification of GitHub’s UI, though. After all, at least the raw file searches instantly in the browser:

Safari GitHub raw search

Luckily, Firefox retains its native search experience:

Firefox GitHub search

Maybe I’m getting this all wrong, and I’d love to be corrected. But it sure feels like GitHub’s UI&UX has become increasingly slow and unfriendly as of late. In any case, I’ve reported this bug and I’ll update if I hear anything back.

Talk: Implementing Efficient Language Models under Homomorphic Encryption

Today (11/11 Pepero Day in Korea), I had the pleasure of attending a fascinating talk on Implementing Efficient Language Models under Homomorphic Encryption by Donghwan Rho (노동환) at the Seoul National University Research Institute of Mathematics’ 2025 11.11 Symposium.

I am on holiday in Korea and didn’t want to miss this opportunity to learn more about homomorphic encryption - an area I’ve been been increasingly fascinated by as of late!

# Talk Abstract

As large language models (LLMs) become ubiquitous, users routinely share sensitive information with them, raising pressing privacy concerns. Homomorphic encryption (HE) is a promising solution to privacy-preserving machine learning (PPML), enabling computations on encrypted data. However, many core components of LLMs are not HE-friendly, limiting practical deployments. In this talk, we investigate the main bottleneck - softmax, matrix multiplications, and next-token prediction - and how we address them, moving toward the practical implementation of LLMs under HE.

# What is Homomorphic Encryption?

The core premise of homomorphic encryption is that it allows computations to be performed on encrypted data without needing to decrypt it first. Loosely speaking, the homomorphism property of HE allows for addition and multiplication to be preserved under the ciphertext transform. From these primitive operations (and some others, depending on the scheme), you can compile homomorphic circuits that perform semi-arbitrary computations on encrypted data. The big obstacle to overcome is that homomorphic encryption schemes are typically very computationally expensive, and so making them efficient enough for practical use cases (such as LLM inference) is an active area of research.

There are various schemes for homomorphic encryption, each with their own set of permissible operations and associated trade-offs, but I’ll delegate a more thorough treatment of the intricacies to this excellent blog post series by Jeremy Kun.

# Talk Summary

Full disclaimer: The talk was delivered in Korean, which I sadly do not speak, so I followed the talk partially via live translation and partially via the English slides (available here).

The talk was partitioned into three sections:

  1. An overview of the CKKS homomorphic encryption scheme and its applications to private transformer inference.
  2. The application of HE to fine-tuning LLMs: the replacement of the softmax in the attention layer with Gaussian-kernel attention and the use of LoRA to reduce the number of ciphertext-ciphertext matrix multiplications. This section is based on the paper Encryption-Friendly LLM Architecture by Rho et al., ICLR 2025 (OpenReview).
  3. How to address the lack of random sampling algorithms in CKKS HE schemes when performing next-token prediction. There’s a lot of intricacy here that I sadly couldn’t follow, but a particularly interesting component that stood out to me was applying the Travelling Salesman Problem to define an optimisation problem over the token indices to minimise cosine embedding distances between adjacent tokens. This section is based on the paper Traveling Salesman-Based Token Ordering Improves Stability in Homomorphically Encrypted Language Models by Rho et al (arXiv).

# What’s next?

Many thanks to Donghwan Rho for the talk! I’m looking forward to reading the papers in more detail when I have some time and hope to update this page or blog more about what I learn in the future!

Welcome to the Hyunam-Dong Bookshop by Hwang Bo-Reum

I really enjoyed this book! The original is in Korean, but the version I read was impeccably translated by someone with a masterful command of idiomatic English.

The book charts the life of a burnt-out Korean worker, Yeongju, as she embarks on a new venture by opening a bookshop. Seeing the stereotypes of Korean working culture explored through the interactions of Yeongju with her customers was both concerning and illuminating.

The moment she stepped inside [the bookshop], she relaxed, as if her body and senses basked in the comfort of returning to her workplace. In the past, she used to live by mantras like passion and willpower, as if by imprinting the words on her mind, they would somehow breathe meaning into her life. Then one day she realised it felt like she was driving herself into a corner, and she resolved never to let those words dictate her life again. Instead, she learnt to listen to her body, her feelings, and be in happy places. She would ask herself these questions: does this place make me feel positive? Can I be truly whole and uncompromisingly myself? Do I love and treasure myself here? For Yeongju, the bookshop checked all the boxes.

I enjoyed the fresh writing style; the way the protagonist’s inner monologue is rendered faithfully into prose never felt trite or overdone. The writing felt mellifluous and the book was a reflective read. It really is an ode to the love of the written word:

But now, she treated the silence as a day’s rest for her voice and was perfectly at ease. When she wasn’t talking, her inner voice grew louder. She wasn’t talking, but she still spent the whole day thinking and feeling. Instead of sounds, she expressed herself through the written word. Sometimes, she even wrote three essays on a single Sunday. But these belonged solely to her, and were never shared with anyone else.

I can’t say I’m this prolific a writer, but I suppose there’s something relatable about spending time in quietude writing and pondering.

… Koreans were raised in a culture where they were taught to be conscious of the eyes of others, which made them, Yeongju included, more self-conscious of how they were perceived. Perhaps this was what drew her to the writing of authors from abroad, to those who grew up in a different culture, and who were different in the way they thought, felt, and expressed themselves.

I think this interest is symmetric! It’s precisely why I enjoy reading works of foreign literature.

Dissonance before moments of harmony makes the harmony sound beautiful. Just as harmony and dissonance exist side by side in music, life is the same. Because harmony is preceded by dissonance, that’s why we think life is beautiful… Is there a way that will accurately tell us whether the current moment we’re living in is harmony or dissonance? How do I tell what state I’m in now? Hmm, you won’t quite know while you’re in the moment. It’s only when you look back that the answer is clear.

By the time Seungwoo finished showering, preparing dinner, eating, resting, and doing the dishes, the clock struck eight. This was when he turned into a completely different person. As he shrugged off the cloak of an ordinary company employee, it was as if he, too, put aside the responsibilities of his title, erased the preprogrammed thoughts and actions, and peeled off the facade of indifference. From this moment, every second belonged completely to him. Time was real.

For the past few years, the hours before bedtime were when he could be truly himself, diving deep into something that captivated his interest - the Korean language. He’d spent the past ten years immersed in programming languages, but he was no longer a programmer. Right now, he was just another ordinary company employee, dutifully checking in and out of the office every day. Immersing himself in the Korean language was tiring, but fun. He enjoyed having something to focus on whole-heartedly, devoting himself to studying something he liked. The energy expended at work, he recharged at home.

I strongly relate to this: I find I have almost boundless energy for dabbling with maths and CS outside of work (or whatever other random rabbit hole I find myself in). It’s a refreshing break from the day-to-day that I find restorative and joyful.

And last but not least, an interesting typesetting note I learned from the book jacket:

The text of this book is set in Minion, a digital typeface designed by Robert Slimbach in 1990 for Adobe Systems. The name comes from the traditional naming system for type sizes, in which minion is between nonpareil and brevier. It is inspired by late Renaissance-era type.

Euclidea: An interactive geometric theorem prover

After watching the excellent piece of exposition on mathematical exploration by 3Blue1Brown guest Ben Syversen: “What was Euclid really doing?”, I discovered the fantastic web and mobile game Euclidea.

Geometry was never my favourite branch of mathematics, I always felt more drawn to algebra and more symbolic and abstract forms of reasoning. But Euclidea really does a masterful job of capturing the joy of exploration and problem solving through the lens of scaffolded puzzles of compass-and-straightedge geometric constructions.

As you construct each solution, they get encapsulated and added to your toolkit of re-usable constructions. It’s a best way to demonstrate the power of axiomatisation and iteratively increasing the levels of abstraction.