Inverting three key relationships in computing
A vision for three key changes to how apps and services work today
This is building on a lot of concepts I’ve co-develop with many others. I’m especially thankful to Scott Miles, Shane Stephens, Walter Korman, Maria Kleiner, Ray Cromwell, Sarah de Hass, Tiziano Santoro, Ben Laurie, Gogul Balakrishnan, Andrew Ferraiuolo, Marco Zamaroto, Carlos Mendonça, Alex Ingerman, Daniel Ramage, Kallista Bonawitz, Gordon Brander, Chris Joel and Alex Komoroske.
Last time, we kicked off the newsletter with a high-level vision for computing, one where we move away from today’s one-size-fits-all software to using AI co-created tools backed by an open ecosystem.
That post ended predicting that the prevailing architecture of computing will have to change as well.
That’s quite a bold claim, and frankly it should worry anyone who otherwise likes the vision. But as this post will discuss in more detail, the shift isn’t as big as it might first appear, reusing many of today’s existing parts and not blocking the development of the missing ones: The shift is primarily an inversion of relationships plus leveraging recent advancements in privacy and safety technologies. But it's a shift necessary for the vision to live up to its full potential, including unlocking a larger and more inclusive ecosystem.
Where today’s permissions break down
To see where the current architecture hits a limit consider how permissions would work in a world of apps created at the press of a button: If such an app asks you for permissions to access your photos, how do you reason about whether to allow it or not?
Today you’d consider who created the app – what are their motivations, what’s the business model, are they a real company with a reputation to uphold, etc. – and make an assessment of whether the use-case is worth the risk. Crucially, there is another entity (the app’s developer) and you decide how much you trust them. And that includes that they take their responsibility seriously, for example that when they include other components that they properly assess how trustworthy those components are. In effect you are delegating those trust decisions to the app’s developer.
But what if you just created the app with the press of a button? Or what if a friend of yours did and invites you to a shared session in it? Neither you nor your friend can reasonably be expected to verify the app’s correctness and assess how trustworthy all the components are – certainly not if those are one-off apps intended for a small audience.
Instead you’ll have to trust the app creation machinery and hence then trust any app created with it.
This can be built over three steps:
Limit what the app can do until it can’t do anything dangerous anymore
(no network, can’t overwrite files, limited resources, etc.)
= Don’t require trust in the app, just the isolation mechanismsCarefully give apps more capabilities; with strict guardrails backed by formal methods that ensure alignment with user interests
= Trust just the runtime and a few trusted components to automatically enforce these guardrailsAllow adding of new capabilities and trusted components in an open-ended and safe way that avoids a ceiling on innovation and all-or-nothing trust situations.
= Open ecosystem with new kinds of roles, including around trust
ChatGPT’s and Bard’s code interpreters implement the first step: The code is executed in a sandbox with no network access with only a small set of packages available. And the output just goes to the user’s screen. Many useful things can be done in this way, enough that a lot of the research enabling these kinds of things is happening. But this approach is ultimately limiting.
To get to trustworthy personalized tools that can perform actions and to trustworthy collaborative tools that users get invited to, we need to also take the other steps: AI co-created tools that are by default safe and private, and an open ecosystem that supports them.
The second step, the automatic enforcement of guardrails, is new and requires a change in how tools are built. This is quite novel and it’ll take full future posts to explain that.
Note that this still involves trusting some entities. But there are fewer of them, and since the trust in them is amortized across many tools and use-cases, it’ll be worth investing in transparency and accountability of these entities to make them truly trustworthy. That is what the third step is about: Transitioning from one single governing entity behind the platform that takes full responsibility and the platform scaling with distributed governing and responsibility.
These three steps change key aspects of our relationship with computing:
Inverting three key relationships
Let’s invert three key relationships that define today’s computing:
Services comes to the data (instead of data going to services)
Code is sandboxed and by default can’t send data outside of the user’s system (following the principle of least privilege). Now the system can freely compose components together to make tools that reuse any data. And data can be shared with other users, making the system collaborative by default.Guardrails on data use are attached to data (instead of each service individually permissioned)
That is, endless permission dialogues are replaced with system-wide guardrails, starting with high baselines for privacy! Instead what is permissible follows from what is minimally needed to accomplish something users ask for. Services and/or automatically assembled tools have to verifiably comply with the user’s guardrails to use data or access sensitive capabilities. And any generated data can be attested to have been generated with those guardrails, extending claims across users and the entire ecosystem.
Trust originates at the edges (instead of services deciding which clients they trust)
Authority originates with the user's devices at the edges and flows through the system. This includes which other devices to trust, remotely attesting cloud infrastructure and delegating to verifiers of trusted components. Identity is established from the edges out as well, without requiring a centralized namespace to rendezvous. This is key to avoiding lock-in.
This is a profound departure from the same-origin security model of the web, which has also become the prevalent mobile app security model. Gordon Brander has a great critique explaining how the same-origin model leads to recentralization. So, while this doesn’t require blockchains or peer-to-peer networks, it can be seen as a take on requirements for decentralized computing!
In fact, the model is a lot closer to the old PC world of local software, with data on an openly accessible filesystem, but with added security that allows for ephemeral software (like the web, no installs required) and making networked collaboration a default capability. Note that this old PC model is what we all often still use for productivity use-cases, especially when working across applications is important!
A copernican shift in perspective
This is primarily a shift in perspective, but quite fundamental, like Copernicus’ shift from geocentrism to heliocentrism:
It was still about the same celestial bodies, just thinking of their relationship with each other in a different way. Similarly, despite the big shift, we can mostly reuse existing pieces, just with increased reliance on privacy and security components. In fact, modern service architectures with cloud functions and functional-reactive app frameworks are already very close to how this will look like.
The new system is in the end simpler, no longer needing a lot of extra mechanisms to work around problems in the paradigm (like deferents and epicycles in the geocentric model). And while the shift to a heliocentric model was significant, it was not the final paradigm shift. The simplification it enabled opened the door for even more profound changes down the line.
It will face resistance as believing in it raises fundamental questions about other closely held beliefs. For example, many take it for granted that owning data is a key part of what makes a business valuable. It’ll require time for this shifted perspective to become acceptable. On the other hand, those who invest earlier might seize a rare opportunity!
Removing friction unlocks new possibilities
Above we stated that per-app trust decisions are no longer necessary and today’s clunky and overly broad permission dialogs mostly disappear. That’s a massive reduction in friction! Friction for users as they experience new tools and participate in more shared spaces, but also friction for creators to build something that makes (safe and responsible!) use of user’s data.
This unlocks new possibilities that aren’t realistically feasible today, be it trying something created by an unknown creator without fearing data loss, inviting others into a new social space without making them go through a signup process, and so on. Note that while this is due to security and safety technologies, the value isn’t just about making people feel better about their privacy and safety, but about the value this unlocks. This will also be key for gaining user adoption: Every previous paradigm shift had a major reduction of friction at the core!
The economic opportunity
Another way to look at this: Today’s market is top heavy and it’s very difficult for new entrants to be successful. This can’t be explained by just the high cost of writing software nor the lack of ideas, opportunities or unsolved problems. It’s a consequence of today’s prevalent architecture that centralizes data and trust in services. So what would it take to level the playing field and invite more economic opportunities? Removing friction around data access, while maintaining safety and privacy!
Eric Norlin and Paul Kedroswky spell out a solid economic argument in Society's Technical Debt and Software's Gutenberg Moment about how the high cost of software creates an economical debt to society, and how making software cheaper will create tremendous value. It’s a great argument for AI co-created tools. But the cost isn’t just the cost to create software, it is also the cost to adopt it. And a big part of that is the friction around establishing and managing trust!
Packy McCormick writes in Small Applications, Growing Protocols about how while it’s ever easier to create social apps, they are also more likely to be short-lived, even when very popular. Packy calls this going supernova and notes that today very little of that energy is captured. Instead of treating such social apps as failures, is there a way to assume short lifespans as normal and accumulate and reuse generated data in future ones? After all the relationships between people, the artifacts they generate, etc. all outlast the popularity of these apps – all should be easily reusable with minimal friction!
Easily co-creating tools with AI will of course have an economic impact. But it’s those changes listed above that are needed to harness the full potential!
Business models will evolve with this. The key is that value is being created, the threshold to participation is low and that the platform allows for experimentation with business models. After all, it took the web over a decade to settle on a prevalent model.
Let’s dive into each inverted relationship listed above:
Services come to the data
Owning your data means that you get to decide what code can act on it. Keeping ownership over your data means that this code doesn’t get to keep a copy for other purposes.
Today we assume that for a service to use our data, we have to give it to it, and hence usually lose control over it. It also means that “our” data is organized by services, living in silos, with possible uses subject to its operator’s interests and limitations.
Even when those services support interop, it comes with significant friction (OAuth, etc.) and can be revoked by the service owner at any time. It also always mean sharing your data with even more services, increasing privacy and security risks, which is why since Cambridge Analytica these APIs became rarer and less complete.
The power dynamics favor the service: In exchange for using it, we have to give our data and often incur high friction to take out our work. Meanwhile the service can block competitors and within a broad margin decide to use our data for new uses.
How can we shift the power balance?
We propose that computing is organized around the data, and that data is sent only to code running in a sandbox under the user’s governance.
Now no one else gets our data by default, nor can the code impose restrictions on further use of its outputs. Authors can still come up with new uses of the data, and even any other data (!), but those will also operate under the same rules. The power balance shifted to the user who can walk away at any time without loosing anything.
By default that sandbox offers the code no capabilities (following the principle of least privilege).
A runtime hosting these sandboxes offers communication between those sandboxes, permanent storage and (carefully) other capabilities.
So now we have a system that
allows ephemeral (i.e. no installation necessary) code to act on user data without leaking it,
allows the user’s system to assemble multiple components and have them collaborate on shared data (we call instructions for such an assembly “recipe”)
allows for safe collaboration amongst multiple users by sharing the underlying data (modern data structures like CRDTs and several of the peer-to-peer syncing projects seem very helpful here).
Collaborative by default
Note that collaboration is defined around shared data, not services. Users create a collaborative space and invite code into it. Any participant can invite code or other components like AI models, and there is no need for every participant to install the same code. This is the opposite of today’s common scenario, where first everyone has to agree on a common service, install it, create accounts, and so on: This removes friction and therefore lock-in.
Programming model
Assemblages of components are driven by a recipe. Recipes can be fairly high-level, primarily declaring the data flow between components.
This is paired with more formal methods to validate valid assemblages, driven by both properties of the components (e.g. matching types on outputs and inputs) and global properties (guardrails discussed below, but also using more modern constructs like formalisms about eventual consistency that CRTDs bring). For example, we don’t need to differentiate in the recipe whether a data source is a stream of data or static: This follows from the components, and components that can handle either can be automatically plugged in in the right way. This mix of declarative and regular programming is itself an interesting development in frameworks.
The actual experience of using the programming model can be fairly close to modern functional reactive frameworks and using cloud functions.
Arcs is an example of such a framework, authored by some of the great folks mentioned at the top. XenonJs is built by some of them with those ideas. And Breadboard is one that the author has recently started working on.
The big opportunity here is AI writing the recipes and even some of the components! See the previous post on AI co-created tools.
The declarative model for the high-level structure, which is more about processes and translating tasks into steps, could be easier to handle for LLMs, while we already know that they perform surprisingly well for smaller, well defined functions. A few hand-crafted, highly reusable key components set up the scaffolding, introducing the formal constraints mentioned above that usefully constrain the composition. Add the ability for users to steer the AI and reuse prior successful recipes and we have an entirely new class of experiences.
Compatibility between services is an important hurdle to consider. Fortunately, recent improvements in AI make this much more feasible, both as a conversion function between structured data, but also with plain text becoming a common format. Very often we don’t need something that can convert any .xyz file losslessly into a .zyx file, but just something that extracts the relevant subset of data, usable just for the task at present (e.g. we don’t need to be able to convert a complete Outlook calendar into a Google calendar, we might just need to know when the event starts and who accepted the invitation). As a more classical approach, see also LensVM for a project that enables data conversions with sandboxed code that can be automatically composed into the flow between two components.
Sandboxing
Those sandboxes don’t have to be local to the user’s device either. All that’s needed is a runtime that is trusted by the user, holding up the necessary properties on the user’s behalf. Server-side hardware-based trusted execution environments (TEEs) are finally becoming more widely available as confidential computing (e.g. by Azure, Google), can play a key role here: They not only keep data confidential (i.e. protecting it from outside access, including the cloud provider), but also via remote attestation letting the user’s devices verify that the runtime inside the enclave is one they trust: The cloud now acts as extension of the client!
Likewise, sandboxing doesn’t have to be WebAssembly or another kind of VM executing code. It could also be something like a SQL query or running inference on an ML model. As long as all capabilities are explicitly provided and there is no ability to otherwise egress data we can consider this “code” that is “sandboxed”.
Note: An important concern with sandboxes are side and covert channels. Addressing these comes with a trade-off with performance and resource overhead (e.g. sharing a process, padding execution times, etc.), prevention vs detection (and the effectiveness of deterrence), etc. – We’ll expand on a possible approach and threat models in a separate post. The biggest concern are covert channels between sandboxed code and highly privileged code running on the same machine, but outside of our platform.
Homomorphic encryption is an ideal sandbox, but its uses are limited. Not only the computational overhead per operation, but also that any computation must by definition run for the same amount of time and access memory in the same exact patterns (anything else would leak information) limits the applicability. More broadly useful might be zero-knowledge proofs (which attest how something was computed without revealing all inputs) to sign outputs.
Gaps
So far so good, but there are a few key things missing:
Data can safely go into the system, but how can data safely leave? That is definitely useful, e.g. to post something more publicly, when triggering an external transaction or even just for analytics and machine learning. How do we know that some code doesn’t secretly attach or encode sensitive information before a piece of data leaves.
How to maintain integrity of the data? If any code can change any data we lose trust in data. We can provide a safety net with versioning and undo-ability, but ideally we gain more formal confidence in the integrity of some key data.
How to prevent abusive use of data? Just because it remains private to the user doesn’t mean that there is no way to use data abusively. For example recommendations might be private, but biased against the user’s interest (maybe guessing the user’s income and only showing expensive items).
We have to go beyond a model that treats all code as sandboxed-but-untrusted:
Guardrails on data use are attached to data
Users set the policies on data use and services have to comply with them to work. This creates pressure to reuse existing policies and especially pressure for those to be strict enough for "untrusted" services. Private is the new default and the power dynamics elevate the user.
And data can optionally be signed, by both the creating user, as well as the policies that constrained e.g. an AI that assisted in the creation. Evaluation of trustworthiness becomes unchained from the service.
Today, information and power asymmetry strongly favors services when it comes to permissions:
Users have to decide whether to trust a service, including accepting a service’s policies (which few people care to read). Services are incentivized to keep policies broad and for users this is often an all-or-nothing question: The power dynamics favor the service, due to information asymmetry and bundling.
And the trustworthiness of data coming out of these services must be evaluated on a per-service basis. The same user posting on a different service is assessed from scratch. And even if a new service implements the same safety measures as an existing one, it isn’t seen as equally trustworthy in that regard. The power dynamics again favor the service, any reputation gained remaining tied to it.
On top of that, today’s permission and consent dialogs are a terrible user experience! A push for more (but still ineffective) control leads to increased friction everywhere, such as with the cookie banners that GDPR and other regulations require: The web is worse off now.
And this model is also what leads to the ever growing data silos in the previous point: Once a service gets past this hurdle it has a major advantage over other services: Network effects from more data generated that only feeds back to the service itself. That is, the data silos called out in the previous point are a direct consequence of protecting user’s privacy!
How can we shift the power balance?
Users set the guardrails on data use and code has to comply with them to work. This creates pressure to reuse existing guardrails.
And it especially creates pressure for those guardrails to be strict enough for "untrusted" services, to minimize any additional verification necessary: Private is the new default, users constrain what models used on their data are optimized for, etc. – That’s a big difference to today’s data-for-service tradeoff!
And data can optionally be signed, by both the creating user, as well as the guardrails that constrained e.g. an AI that assisted in the creation. Evaluation of trustworthiness becomes unchained from the service.
Setting the guardrails shouldn’t be a major burden and will likely rely heavily on delegating decisions to new entities that recommend them. This is bundling again, but this time it shifts bargaining power to users and their communities!
For example, such a guardrail might say that
data and derivative data are by default only shared with the same user, or a group of users (formalizing the concept of privacy by default implied above)
order information can be released to a merchant if the user went through a checkout flow and confirmed the purchase. Attached information also explains how such a UI flow would be trusted (note how this replaces traditional permissions dialogs and instead makes the decision to allow this data to be shared a natural part of the regular UI flow and decisions expressed there)
certain data can be aggregated in a privacy-preserving way, defining the minimum conditions (#participants, noise added, other required preprocessing like lowering precision).
recommendations must be scored related to what is meaningful to the user (not primarily optimized for revenue or engagement)
images must pass through a certain filter before they can be shared
AI models that generate content based on this data must adhere to specific limitations, e.g. to not use manipulative or overly persuasive and personalized language to make a point.
These guardrails control future use of data as well as describe the circumstances a bit of data was generated. E.g. #3 above permits – within bounds – privacy preserving aggregation. And checking for #5 and #6 to have been in place when creating data allow for filtering incoming data that is known to not be abusive (in at least that dimension).
Under the hood this translates to information flow control between the sandboxed components, with confidentiality corresponding to guardrails limiting future use and integrity corresponding to signatures about the origin of data, including guardrails that were present.
The author's current work on safer AI agents is an example of this technique and much of the above should follow from those first steps!
Verifiers
Some components are considered trusted by guardrails, e.g. the checkout UI, and those can declassify data. How that trust is established is of course a critical question. Also the guardrails themselves aren’t something users will directly deal with, but are instead set by something they trust.
That is, there will be a system of verifiers. And users will delegate to them. They can verify code and guardrails. And they are themselves held transparently accountable with techniques like release/binary/certificate/supply chain transparency. Verification can be done by experts, institutions, crowds or even automatically.
Designing a protocol around verifiers that established and maintains trust is a key pillar of making this newsletter’s vision work. More in a later post.
One key property to make this scale is that the amount of code that has to be trusted/verified stays small and is highly reusable. This works by cleverly arranging the data flow between mostly untrusted and a few trusted components.
Verifying AI models is an interesting challenge: On the one hand it is impossible to make a claim that a model will never behave in a certain bad way, but on the other hand the “code” boils down to training data and parameters, which can be attested within the system (using signed data for training and attesting its providence) and is short (the loss function).
Foundation models are particularly interesting as the “code” can boil down to a plaintext prompt that is easily inspectable, even by another AI! This might extend to training of the underlying model (see e.g. Constitutional AI).
UIs are often key trusted components, e.g. going through a checkout flow implies authorizing payments, sharing of what is being purchased, etc., but can often be verified by crowds: If 99% (or whatever is a high, practical threshold) of people agree that some action in a UI imply certain expectations, that can count as verification (or more precisely, the problem reduces to trusting the crowdsourcing mechanism – non-trivial, but highly reusable).
Code remains the hardest one to verify. Ideally, we’d be able to perform formal verification on data, reducing what needs to be verified to a much shorter spec. Quite likely code understanding AI can help guide human verifiers. But often, we’ll also have to trust fairly large codebases, including compilers, sandboxes, machine learning frameworks, etc. where neither is feasible and the question boils down to the governance of the codebase itself and to managing the risk of inevitable bugs in the code (defense in depth, etc.). That’s where release, binary and supply chain transparency become important.
Attached to data
But what does “attached to data” mean? We mean that the policies travel with the data, wherever it goes. When two sources of data merged, both their policies applied (e.g. if you and I merge data we both have to declassify it before either of us can see the result).
And when data moves between computing systems, those systems keep enforcing those policies, transitively. Hence the importance of remote attestation again: Before data is sent, the sending system verifies that the receiving system can be trusted to enforce the policies.
That last bit recovers some useful properties of centralized services. It does make sense to share instances of large or frequently changing databases or of large ML models. And they can be safely queried as long as they (verifiably!) enforce policies, most importantly that the result of a query can only be shared back with whoever made the query. Project Oak, which some of the great folks listed at the top have worked on, implements this.
This could be quite powerful in the context of SaaS: A startup could offer a service that is verifiable following certain policies, making it safe for a customer to expose data to that service, without having to go through a long process to establish trust in that startup. In many ways this is even superior to the customer hosting their own instances of those services.
Attesting how data was created
Received data not only has guardrails for future use attached to it, but also signatures that reflect how it was created and manipulated, including the execution environment and runtimes that were used.
This generalizes what the Content Authenticity Initiative proposes: While data can carry the whole history of edits it might also choose to only carry the guardrails that limited the edits – you don’t have to disclose how AI helped you create the content, just that if any AI was involved at all, how it was constrained.
This can be quite a powerful tool for AI safety, again shifting the power balance a bit: Recipients – not just senders – get to indirectly set guardrails on AI enhanced content they receive. This in turn might shift compute boundaries. For example instead of sending personalized marketing material, send a recipe that generates it privately for the user, but only under the constraints the user sets.
Trusting the runtime
Which runtimes and which executing environments are trusted can itself be set in the attached guardrail (most commonly, as above, by delegating to trusted verifier). It is transitively enforced, i.e. each trusted runtime will only ever send data to runtimes the originator of the data trusts.
This is an instance of the next inversion:
Authority originates at the edges
Authority – often in the form of cryptographic signing or verification – flows from user controlled devices outwards, thus retaining choice of providers, enabling feasible migration and new forms of working with identity.
In today’s compute architecture truth flows from the servers. Even cryptographic signatures are rarely more fine-grained than at the top-level domain level. Servers decide which other servers they trust. And so on.
And to the degree that users make trust decisions about services (e.g. permissions), they are only one level deep, delegating all transitive trust decisions to the service! Before we mentioned the need for verifiers: Effectively, today, those services act as such verifiers! So a question to explore is how that trust between services and their suppliers and reused components can be scaled up to the ecosystem.
This is the most explored power imbalance in today’s computing and where movements like the decentralized web and web3 come from. Here we’ll see which of these ideas apply to this vision and how.
The basis is simple: The root are a limited number of devices the user owns and trusts, and behind that a recovery mechanism to bootstrap new such devices should they all get lost or compromised.
This has implications on computing architecture and identity:
Authority – often in the form of cryptographic signing or verification – flows from user controlled devices outwards, thus retaining choice of providers and trusted verifiers and hence enabling feasible migration of data and trust (see also credible exit).
Identity also emerges from the edge. And for one that means it can stay informal or even anonymous in many cases, only where really necessary layering global namespaces on top, whether self-sovereign or not.
Let’s look at both in more detail:
Remote attestation as relationship inverter
For computing, there is a network of trusted devices with this root device at the center. Each device uses remote attestation to verify that the next device runs a trusted runtime. What “trusted” means stems from the user (via the root device) delegating to trusted verifiers.
“Devices” includes the confidential cloud computing, which is how we get the principles behind "code comes to the data” applied to the cloud: The key is that code runs sandboxed and in a runtime that the user trusts, which we can now establish via remote attestation, even transitively.
As a side note: Confidential computing, i.e. trusted execution environments in the cloud, have been long promised but have been disappointing (see e.g. Intel SGX). This appears to be quickly changing now, with AMD’s SEV-SNP now and Intel’s TDX soon shipping confidential compute capabilities in their newest CPUs by default. Nvidia’s H100 brings those capabilities to GPUs. This technology is available now and in a few years – when cloud providers go through an update cycle – it will be common place.
This is the “personal cloud” as yet another device in a mesh of a user’s private devices. But not just that: Multiple users can connect to the same instance of such a runtime. The runtime enforces the guardrails attached to the data, including by default keeping data flows separate between users. This lets users share expensive resources (e.g. large models), but also allows for interesting collaborative use-cases (e.g. find a common free slot in the calendars and report only that slot back, immediately forgetting all other details).
An important reason for centralized services in today’s computing is trust by the operator of the service: They have to treat the client as untrusted, but they do treat the cloud services they operate as trustworthy. For example to decide whether a customer qualifies for a discount. Remotely attestable compute environments address that need, with for example that discount computing code’s output signed by the confidential compute runtime to have actually been computed by that code. (Note: This is another instance of attesting how data was created, now including the compute environment that made the computation)
Storing a user’s persistent data securely in the cloud is a key use-case. Obviously it’ll be encrypted at rest, with keys that are held by the user’s device. Confidential computing instances can decrypt the data, borrowing keys for a limited time from the user’s device (in practice this is a bit more complicated, with delegated and rotating keys, etc.). If the user’s device becomes unreachable (or it explicitly locks everything), these keys eventually expire and data becomes inert.
This is utility computing, where computing is a shared resource. Interestingly, it accomplishes a lot of the shift in power dynamics that peer-to-peer architectures promise. And in many ways it is both more efficient and easier to use, at least now that confidential compute is finally getting into the deployment phase. It’s a lot more practical, even if it might not cover all edge cases to full satisfaction (e.g. extreme zero-trust or censorship cases). An interesting variant is to use p2p protocols like IPFS and deploy them as sketched above, but making future migration easy. This shifts power away from the cloud providers.
Identity
Identity also emerges from the edge. And for one that means it can stay informal or even anonymous in many cases.
It turns out that globally unique identities, self-sovereign or not, may not be as essential as their current prominence suggests. Instead think of identity as a social construct that itself emerges from social interactions. Transferable reputation, global identifiers, and so on layer on top.
One reason we’re often jumping straight to globally namespaced identities is that the service-centric architecture implicitly creates them anyway during authentication: Any service, which also represents a namespace, requires maintaining a list of its accounts, and give them either identifiers to login in or reuse already existing global identifiers (phone numbers, login with Google, etc.). And as all our digital collaborations require creating such an account as first step to use it, we’re already confronted with that complexity and friction every time. But it’s not actually how identity works in informal settings and not how it worked for most of history.
Gorden Brander, Chris Joel and the rest of Subconscious team have been doing significant work in this new direction, and the articles on signing everything and petnames must reads.
The core operations are:
Creating keys.
Signing any shared data with a key.
Establishing equivalence between two keys, possibly scoped (e.g. via UCAN).
Publishing on transparency logs, establishing “before then” / “in this time interval”.
Revoking keys, establishing “no later than”.
From a user’s point of view, other’s identity emerges as:
This message is from the same user that you talked to over video yesterday
They introduced themselves as / friend introduced them as / you called them
<nickname>
.They verifiably own
<email address>
and<twitter handle>
.
(bootstrapping from traditional identity systems)This is Bank-of-Amurika and you have never interacted with them before.
That is, identity builds over time, mapping to our social contexts. It’s also much lower friction than having to create profiles in every service one uses!
When publishing a user might associate a public profiles with their content. Profiles are just published data signed by a key connected through a chain of equivalence blessings. These profiles can be data about them, point to other published content, list preferred ways of getting in touch (as recipes, naturally!), and so on. See this draft post on decentralized messaging for more on profiles.
Or they might stay pseudonymous and link a more scoped profile (or none), maybe backed up by a reputation. They can still reveal the relationship between the keys to their friends. So to their friends their posts appear as them, but to others they appear as a stranger with a good reputation.
Reputation is loosely layered on top. In fact reputation is just a recipe and any user can execute it in a trusted environment and thus verifiably compute the scores. This can include combining different reputation scores.
One neat possibility is to bootstrap reputation off existing services, e.g. a function that OAuth’s into Reddit and retrieves a user’s karma, running in an attested TEE that signs the output as coming from that function and thus that it really is the user (they can login) and really the score (it was retrieved from Reddit). All with authority that originates at the edge!
A system with a view on all the user’s data is also an interesting opportunity to prevent sybil attacks. The presence of history is a strong signal and between accessing a user’s old services (how many emails does this user have and how old are they) and a lot of signed data (with hashes in transparency logs), this could be bootstrapped as well. Uniqueness oracles that make sure none of these signals is used twice might seem centralized, but any number of them can be bootstrapped. The trickiest part is allowing recovery of a hacked account as signal.
At the technical layer, this can be bootstrapped with passkeys (no more passwords, ever!), an open ecosystem of recovery mechanisms (eventually!) and transparency logs. The really tricky parts are getting key rotation right, deciding which private keys to keep for how long, etc.
Other things to decentralize?
Compute and identity are the most important ones to decentralize. For others – e.g. money – the case for and against can be made independently of computing.
Note that plenty of centralization might still happen, e.g. cloud providers are still used (and colocating a lot of compute with cheap power is still a good idea…), transparency logs can be centralized logs and don’t need to be expensive blockchains, and so on.
Some concepts mentioned above, such as verifiers, benefit from some amount of centralization. They are essentially trusted institutions, and here the goal is less to avoid centralization than to build the mechanisms to build and maintain that trust, and to migrate to alternatives if necessary.
The critical lens to apply isn’t whether something flows through a few nodes, but how much power is being concentrated, how those powers can be made accountable and what it would take to bring up alternatives. As long as there are credible exits, the power balance remains tilted in favor of users and the ecosystem at large.
Outlook
These three key inversions describe an alternative to today’s service-centric computing that the web’s origin model popularized. The result is something closer to how computing worked before the web, and incidentally how a lot of today’s creative work still happens – as locally running applications on a shared filesystem. But modified to be much safer and friction free. And to be natively collaborative.
It’s made possible thanks to recent advances in privacy and security technologies. We haven’t yet touched on Federated Learning, Secure Multiparty Computation and many others, but many can be layered on top. E.g. one of the guardrails in the second inversion could specify that aggregation of data is allowed as long it happens via Federated Learning with Differential Privacy.
The end result should please proponents of the decentralized web and maybe even web3. Please do get in touch and send feedback!
A big question is of course how such a profound change to computing would ever get any adoption. This is where AI comes in. In three ways:
As a big wave of change that this idea could hitch a ride on. A lot of computing will be reinvented anyway in the next few years: Can these ideas influence that?
Unique opportunities that AI could take advantage of, such as safely composing 3P code and using more of the user’s data (see AI co-created tools).
Increased urgency due to the risks that AI brings, making shifting power balances even more important.
This newsletter will keep exploring this possible future. Please subscribe for future posts with more details on many of the topics above, use-cases that illustrate the ideas and much more.
l I think about tools like ChatGPT as our digital brains. And just like we want to own the data and knowledge in our physical brains we want to own the data and knowledge in our digital brains as well. And if we are able to break down the silos currently created by Big Tech and unite all our data and knowledge in one place that we control our AI will be so much more powerful than what can be offered by Big Tech companies that only have access to a portion of our data. Great technical overview of how we can do this thanks for writing it.