We want to be able to support a wide variety of interfaces to Penumbra.
While it's important that there be at least one first-class wallet experience at launch, Penumbra's capabilities are multifaceted, and users will probably be best served by specialized interfaces: e.g., one for basic transfers or swaps, one for governance, one for power users to manage liquidity or examine the liquidity graph, etc.
Supporting a wide variety of interfaces is also important for decentralization: no one entity should "own" the Penumbra userbase via control of a single frontend, or be at risk of becoming a chokepoint for control of those users. This also means that it should be possible to build frontend interfaces to Penumbra that do not require custom backend infrastructure beyond an ordinary pd full node.
We want those interfaces to be as easy to build as interfaces to transparent chains.
Historically, interfaces to shielded chains have been more difficult to build than interfaces to transparent chains, because they require the application developer to manage synchronization of users' private state, unlike a transparent chain, where user state is accessible via RPC. Penumbra is about privacy without compromise, so we want to make it as easy to build those interfaces for Penumbra as it is for a shielded chain.
We want our users to have security when interacting with those interfaces.
In order for users to benefit from the availability of a wide variety of third-party interfaces, users need to be confident they can use them without risk of losing funds or being hacked. We need to ensure that only the user can authorize a transaction, and be able to understand exactly what actions they're authorizing when they do so.
How do we accomplish these goals?
We can do this by building a local state storage solution downstream of our syncing and decryption logic that contains data within the "decryption horizon" of the available keys (as defined by the available keys). What is visible to the keys available can be treated as if it is a fragment of a transparent chain, and the rest of the data which is opaque is irrelevant. This provides a "transparent chain experience" on a shielded chain.
Current Architecture
We've already been prototyping a modular client architecture in pcli since April, so we have a good idea of how a Penumbra client decomposes into components with different levels of capability, and how those components interact with each other and with the network:
The client decomposes into three components: the custody service, which holds spending keys and is responsible for transaction authorization, the view service, which holds viewing keys and is responsible for syncing the private chain state, and the wallet logic itself, which queries:
the view service (using the gRPC view protocol) to learn about state like account balances;
the custody service (using the gRPC custody protocol) with requests to authorize a planned transaction;
a pd full node (using the oblivious or specific gRPC protocols) for public chain state, and using a grpc proxy to tendermint for transaction submission;
Separating Viewing Capability
Penumbra view keys are long-term key material, giving the capability to view all activity on an account, for all time, and cannot be revoked or rotated without changing addresses. This means that we cannot expose viewing keys to third-party interfaces and meet our goal of ensuring users have security when interacting with those interfaces. A compromised frontend should only be able to exfiltrate current activity, not all future activity.
Towards this goal, we've built the TransactionView/TransactionPerspective data modeling, giving a way to view cleartext contents of specific transactions, without having access to view keys. Clients can request a TransactionPerspective, a per-transaction bundle of key material and commitment openings that determines a TransactionView. Different users may have different perspectives, and hence different views, of the same transaction. For instance, the sender can view all of the transaction's actions, while the receiver views only the outputs addressed to them. The resulting architecture is as follows:
How does this revised architecture map to the web context?
We need to isolate the spending keys, and thus the custody service, from any web content. This is important for two reasons: first, compromised or malicious web content should not be able to access spending keys, and second, the signing interface needs to display details on a secure path, so that compromised or malicious web content cannot phish users by pretending to sign one transaction while actually signing a different one. We would also like to isolate the long-term viewing keys from any web content, and allow access only through TransactionPerspectives.
The scanning and synchronization performed by the view service should ideally be done once per device, rather than being duplicated across every interface. This provides a better user experience when using multiple interfaces, and protects privacy by reducing network traffic.
The first goal, key isolation, requires that the custody service be implemented in a browser extension. Then spending keys would stay inside the extension, and the extension could display its own UI to the user to authorize signing, showing the details of the TransactionPlan. To isolate viewing keys from web content, we would also need the extension to provide the view service. This also solves the second goal, sharing synchronization work, because the extension could do scanning and synchronization once, save the resulting data, and allow web content to query it.
In the web context, the web content can communicate directly with the extension, so rather than using literal grpc transport, we'll have the web content pass the request types for the view and custody protocols' grpc messages.
Plan to get there
Our current client code in pcli does not make this segmentation, and so our existing client implementation does not work as an example of how a Penumbra client could work without having direct access to view keys.
[x] #1782
The Planner takes view keys, but they are only needed at the very end, where used in the following ways:
For proposal methods we're planning to delete (so we disregard this use)
To construct the account ID when querying the view service.
Interfaces planning
We want to be able to support a wide variety of interfaces to Penumbra.
While it's important that there be at least one first-class wallet experience at launch, Penumbra's capabilities are multifaceted, and users will probably be best served by specialized interfaces: e.g., one for basic transfers or swaps, one for governance, one for power users to manage liquidity or examine the liquidity graph, etc.
Supporting a wide variety of interfaces is also important for decentralization: no one entity should "own" the Penumbra userbase via control of a single frontend, or be at risk of becoming a chokepoint for control of those users. This also means that it should be possible to build frontend interfaces to Penumbra that do not require custom backend infrastructure beyond an ordinary
pd
full node.We want those interfaces to be as easy to build as interfaces to transparent chains.
Historically, interfaces to shielded chains have been more difficult to build than interfaces to transparent chains, because they require the application developer to manage synchronization of users' private state, unlike a transparent chain, where user state is accessible via RPC. Penumbra is about privacy without compromise, so we want to make it as easy to build those interfaces for Penumbra as it is for a shielded chain.
We want our users to have security when interacting with those interfaces.
In order for users to benefit from the availability of a wide variety of third-party interfaces, users need to be confident they can use them without risk of losing funds or being hacked. We need to ensure that only the user can authorize a transaction, and be able to understand exactly what actions they're authorizing when they do so.
How do we accomplish these goals?
We can do this by building a local state storage solution downstream of our syncing and decryption logic that contains data within the "decryption horizon" of the available keys (as defined by the available keys). What is visible to the keys available can be treated as if it is a fragment of a transparent chain, and the rest of the data which is opaque is irrelevant. This provides a "transparent chain experience" on a shielded chain.
Current Architecture
We've already been prototyping a modular client architecture in
pcli
since April, so we have a good idea of how a Penumbra client decomposes into components with different levels of capability, and how those components interact with each other and with the network:The client decomposes into three components: the custody service, which holds spending keys and is responsible for transaction authorization, the view service, which holds viewing keys and is responsible for syncing the private chain state, and the wallet logic itself, which queries:
Separating Viewing Capability
Penumbra view keys are long-term key material, giving the capability to view all activity on an account, for all time, and cannot be revoked or rotated without changing addresses. This means that we cannot expose viewing keys to third-party interfaces and meet our goal of ensuring users have security when interacting with those interfaces. A compromised frontend should only be able to exfiltrate current activity, not all future activity.
Towards this goal, we've built the
TransactionView
/TransactionPerspective
data modeling, giving a way to view cleartext contents of specific transactions, without having access to view keys. Clients can request aTransactionPerspective
, a per-transaction bundle of key material and commitment openings that determines aTransactionView
. Different users may have different perspectives, and hence different views, of the same transaction. For instance, the sender can view all of the transaction's actions, while the receiver views only the outputs addressed to them. The resulting architecture is as follows:Web Architecture
How does this revised architecture map to the web context?
We need to isolate the spending keys, and thus the custody service, from any web content. This is important for two reasons: first, compromised or malicious web content should not be able to access spending keys, and second, the signing interface needs to display details on a secure path, so that compromised or malicious web content cannot phish users by pretending to sign one transaction while actually signing a different one. We would also like to isolate the long-term viewing keys from any web content, and allow access only through
TransactionPerspective
s.The scanning and synchronization performed by the view service should ideally be done once per device, rather than being duplicated across every interface. This provides a better user experience when using multiple interfaces, and protects privacy by reducing network traffic.
The first goal, key isolation, requires that the custody service be implemented in a browser extension. Then spending keys would stay inside the extension, and the extension could display its own UI to the user to authorize signing, showing the details of the TransactionPlan. To isolate viewing keys from web content, we would also need the extension to provide the view service. This also solves the second goal, sharing synchronization work, because the extension could do scanning and synchronization once, save the resulting data, and allow web content to query it.
The resulting architecture looks like this:
In the web context, the web content can communicate directly with the extension, so rather than using literal grpc transport, we'll have the web content pass the request types for the view and custody protocols' grpc messages.
Plan to get there
Our current client code in
pcli
does not make this segmentation, and so our existing client implementation does not work as an example of how a Penumbra client could work without having direct access to view keys.Planner
takes view keys, but they are only needed at the very end, where used in the following ways:Other improvements:
Zpoken Links