For those who don’t know, Spritely is an organisation building various tools to create decentralized applications with object capability security. It is run by familiar names that have participated in the creation of ActivityPub: Jessica Talon and Christine Lemmer-Webber.
The library that they created (currently implemented in Guile and Racket Scheme) called Goblins, allows the creation of such applications easily. A Rust implementation would be really useful for its performance, memory safety and thread safety, things that I believe would help develop the Spritely environment.
There are 5 stages to start implementing Goblins (0 to 4) and I have currently implemented stage 0 and 1. The source code can fe found here: https://codeberg.org/spritely/goblins. Each stages are in the pre-goblins folder. As I approached implementing stage 2 and looked at the overall architecture, I realized how much bigger this project was going to be. I took a lot of time understanding how Goblin works, and even more developping the initial stages. I’m admittedly still a beginner in software development and in making full projects in Rust. Therefore, I encountered several issues that required changes to the architecture of my implementation several times.
I am planning to make my implementation open source after I document stage 1 and make sure I didn’t put any redundant enums and traits. I’m mostly making this post to wonder if anyone would be interested to jump in, or even contribute from time to time? Documenting would even help a lot, since I’m not the best at explaining things in a clear and concise way. So any sort of help, even bug finding or suggestions, would be very helpful!
If I didn’t know this was computer related, I’d have assumed this was a tabletop role-playing.
Fair lol. But it is a very interesting project and I recommend checking it out if you’re interested in ActivityPub!
Thanks but no. Been retired for 10 year. Cant even remember my age anymore. My computer skills have evaporated long long ago.
That’s okay! I hope you enjoy your retirement!
The white paper is 98 pages lolwut. Is there a maybe 5 page document explaining what this is and why you’d want to use it? Are there existing applications that use the current Racket/Scheme implementation? Why do you want to reimplement it in Rust? I had thought that Racket handled multi-threading, and of course Racket and Scheme are already memory safe (in the sense that C is unsafe). Are there significant performance problems in real use of the existing implementation?
Overall this seems like a rewrite project that should first get some sober thought to convince yourself that it’s worthwhile, unless you’re already convinced. Otherwise why not use your creativity to do something that hasn’t already been done?
I know it’s a lot! I myself didn’t fully read the white paper, but skimmed over it and went through the API documentation, as well as looked at how apps that use Goblins work. I’ll try to summarize it as best as I can.
Object Capability (ocap) is a model of sorts that makes an object (app, library, etc.) secure by only allowing it to have access to certain resources based on what it needs and not what environment it’s in. For example, in a regular environment, an object’s permissions are based on who’s running it, what group they belong to, where it’s being run, etc. . It’s hard to keep track of and keep totally secure, since an object might not be isolated enough. In an ocap environment, that object doesn’t have any permission unless it is given. It cannot even try to do something without permission since it doesn’t have the reference to the object that would allow it to do something. If the object does something malicious, you can also easily trace which permission was allocated to it and easily fix the issue.
It’s use cases are mostly related to things that require interoperability between different objects and safety when interacting with these objects, since they might not bee 100% trustworthy. This can help a lot for multiplayer games, cooperative environments, chat applications, and more. To see a use case, you can go to the section 3.3 of the white paper. It was mostly the part where everything clicked for me. Section 3.3.4 really shows the power of having an ocap environment, I believe.
Currently with Rust, if you want to create an app that uses ocap, you have to implement the model yourself. During my research, I had found libraries that allowed creation of applications that use ocap, but only for accessing file/system resources. It didn’t allow the user to create other objects that use ocap.
I have to admit, I am more up to speed with the Guile implementation, since I believe it is the one that the Racket implementation now derives from.
But my justification for implementing it in Rust was that:
-
Implementing it in Rust would allow ocap applications to have access to the Rust environment. I have explored solutions that would allow to use the Guile/Racket library in order to create applications in Rust with it, but they often weren’t viable. I had also thought about applications having to run a Guile part, then would communicate to a Rust part via OCapN, but I thought it would be a complicated sollution. If it is implemented in Rust, it can have access to Bevy, Tauri, and any other libraries that are also available to Rust programmers.
-
Performance, memory safety and thread safety are all things Rust excels at. Currently there are concurrency issues that affect the Guile implementation (I am not sure about the Racket one, to be honest). I don’t want something that completely replaces the Guile implementation, as it has its use (dynamic typing, easier to use, easier to implement features). I do believe that implementing the library in Rust would allow for use cases not only in lower level environments (embeded, kernels, etc.), but also in environments where performance and resources are critical (certain video games, heavier applications like editors, etc.). Video games have already been created using Guile, like Cirkoban (source code: https://codeberg.org/spritely/cirkoban), which you can play right now: https://davexunit.itch.io/cirkoban. From what I’ve seen, Goblins on Guile tends to be a little slow, but I do believe that it is something that will get better as the implementation matures. Implementing it in Rust I believe will allow for a more performant application, but at the cost of dynamic types and harsher rules.
-
Implementing it in Rust implicitly expands the OCapN environment. I believe there are many use cases for applications to use a distributive ocap model. The more languages that not only support OCapN, but also make abstraction of it, the more it gives choices to people who want to jump in. While I do know the basics of Guile and would like to create an application that uses Goblins with it, I know some people who wouldn’t want to use something if it’s made with a programming language they aren’t familiar with. By having more choices, people will feel more inclined to explore the world of ocap.
I’m always open to criticism though. As I said, I’m still a beginner in software engineering. I just really like and see the potential in what Spritely is developing, and would like to contribute to it as well.
It sounds like for this thing to be really useful, you have to replace the whole application ecosystem. Sounds like the basis of a new mobile OS or something. Capability based OS’s have been written before, though IDK if any have gotten any traction.
Guile is supposed to be embeddable in C so I’d hope it’s also embeddable in Rust, or at most needs some Rust bindings. That would be a good thing to write if it hasn’t already been done.
Yeah I don’t know the situation with Guile and threading, but is there really a serious performance bottleneck? What is going on that is slow? If it’s something like cryptographic signatures, it’s presumably using a fast library, so calling the same library from Rust wouldn’t give much of a speedup. If the Guile version is basically fast enough, running it in a single thread could be a decent workaround. Do applications really have to present capabilities millions of times? I’d think it’s something they’d do once at program startup, or maybe occasionally where the user would invoke some protected operation and the capability would temporarily be enabled. In fact maybe you don’t even need language bindings instead of a local socket to pass capabilities through. Then if you really needed parallelism in Guile, you could run multiple processes listening on the socket, instead of multiple threads.
I’ll look at that section of the whitepaper. I’m still a bit puzzled by this whole thing.
-
I’m confused, why do you say Goblins in Rust instead of a Rust implementation of OCapN. Do you intend to copy the API itself? A Rust implementation OCapN would be indeed useful. It would allow the system to have different parts implemented in different languages. But a Goblin in Rust doesn’t even have a clear meaning API-wise.
It’s mostly that I realised that there weren’t any object capability libraries in rust that weren’t just low level stuff. From what I understand, OCapN would allow one to create a Rust app that communicates with an app using Goblins, but the object capability stuff would have to be handled by the developpers. I currently implemented stuff like creating actors with a constructor and the bcom capability, which would allow one to make object capability apps easily.
I have already started an OCapN implementation in Rust as it was still an integral part of Goblins, but another developper was also working on it, so I’m mostly trying to talk and seeing if I could help out as well. But I know I’m not the brightest person, and if a Goblins implementation in Rust would effectively be useless, then it’s okay. I’ll focus on developping OCapN.
I know I’m not the brightest person
Never put yourself down!
If a Goblins implementation in Rust would effectively be useless
Not saying it would be useless, I’m saying I don’t understand what you mean. Certainly a high-level API on top of OCapN would be useful. Goblins, afaiu, is a guile library. Given that there can’t be a 1-1 correspondence between the API, it is unclear what would a Goblins in Rust would look like. Have you written some [non-working] example code to give a more concrete idea of what you are looking to implement?
I do have a peculiar way of saying things sometimes. I didn’t mean to put myself down, but more so that I know I can make mistakes and am open to suggestions. Still, thank you!
My goal is to expand the object capability environment and make it easily usable in Rust. Here’s an implementation of the greeter actor using the API that I made:
// Vat Connector currently doesn't work, since vats are not implemented yet let vat_connector = Some(VatConnector::new()); // New actormap inside vat let am = make_actormap(vat_connector); // Create a new constructor, greeter, that takes in the greeter's name to build an actor constructor!(greeter, |_bcom: Rc<dyn Bcom>, my_name: String| { // Creates a behavior for the actor that takes in a String to say hello to behavior!(|your_name: String| -> String { // Value is returned to handle different responses, but I will clean this up to only return the String itself // Also, Value is for JSON. The API should use Syrup for OCapN Value::String(format!( "Hello {}, my name is {}", your_name, my_name )) }) }); // New actor greeter alice let alice = actormap_direct_run!(&am, { spawn!(greeter, "Alice") }); // Alice greets Bob assert_eq!( "Hello Bob, my name is Alice", actormap_direct_run!(&am, { call!(alice, "Bob") })? );This code works using the library. There are still many things I would like to clean up and change, as indicated by the comments. I just want to make it easier to create applications that interpret object capabilities. There are a lot of things that the library does different than Goblins (type restrictions, uses enums for return values, traits instead of meta types, etc.), but it mostly follows a similar philosophy of having a library that allows you to create an app that relies on object capability.



