Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC 0010: Wallet Attestation API #14

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
244 changes: 244 additions & 0 deletions RFCs/rfc-0010-wallet-provider-attestation-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
# RFC-0010: Wallet Provider Private Attestation API

- **Intent**: Introduces an extension to the wallet provider API that allows the wallet to perform private attestations.
- **Submitted by**: Theodore Pender (Github: @teddyjfpender, email: [email protected], Twitter/X: @franklyteddy)
- **Submitted on**: Monday, January 15, 2024

## Abstract
This proposal introduces an extension to the wallet provider API for Mina wallets, focusing on enabling attestations beyond the current features of attesting to knowledge of private keys through RPC methods like `sign`. Mina's zk-native nature and client-side proving features sees the ecosystem well suited to attest to knowledge of many types of private data beyond knowledge of private keys. This proposal aims to expand this feature, allowing wallets to attest to a broader range of private data, such as credentials and zkOracle proofs. The concept of composable privacy is central to this extension, offering users and developers the discretion to select which data remains private and which becomes public. This ensures that sensitive data is not exposed to the browser context, remaining in the wallet, thereby upholding the privacy and security of users' private information. By empowering wallets to attest to private data within their contexts, this proposal brings to life a crucial aspect of composable privacy in the Mina ecosystem.

## Motivation
The motivation behind extending the Mina wallet provider API stems from the evolving needs of the Mina ecosystem's zkApp landscape. Currently there exists no standard for Mina wallets to interact with zkApps and attest to known private data. This limitation hinders the full potential of Mina's composable privacy feature, which is vital for user autonomy and data security.

## Specification

### Requirements

* Private data can’t leave the wallet sandbox
* No remote code execution in the wallet
* Work for multiple projects without requiring wallet changes / coordination, so it works over the many different projects and any new private data attestation projects that come up
* Should tie into nullifiers (to make sure there is an application specific salt)


### API
Wallets should have a provider API parallel to EIP-1193 but tailored for Mina. The goal of this API extension is to build on top of pre-existing standards.

#### Key Features of the Proposed API

- **Agnosticity to Application Types**: Whether an application operates on-chain, off-chain, or a combination of the two, this API remains consistent and reliable.

- **Explicit User Control**: In a Mina-enabled DOM environment, the user is always in the driver's seat. The protocol is designed such that:
- **User Consent for Attestation**: Explicit user approval is mandatory before the wallet can attest to any statement.

#### Primary Functionalities:
The proposed API should empower a Mina wallet to:
- **Store Credential**: Store credentials to be used by an attestation program.
- **Request Attestation**: Initiate requests to receive an attestation proof of a claim.
- **Request Nullifier Key**: Construct a nullifier key, along with an attestation proof about that nullifier key


### Scenario: Requesting Attestation From a Wallet
#### `mina_requestAttestation`
In the decentralized digital ecosystem, trust is established through verifiable attestations. Attestation, at its core, is an authoritative witness to the authenticity and validity of a piece of information or claim.

Within the Mina-aware DOM settings, providers grant applications access to the `mina_requestAttestation` method, designed specifically for attestation scenarios. It caters to situations where zkApps desire attestations rooted in provable programs. The objective is to equip the wallet with the capability of attesting to specifics such as credentials or other known data. This is achieved without revealing the actual credential, ensuring privacy yet allowing for essential proofs, both for on-chain and off-chain scenarios.

Consider an example where a wallet reveals a credential's proof field to the browser for a transaction specific to a smart contract method. Here, it's anticipated that the wallet possesses a pertinent credential. However, if the wallet recognizes the credential but must attest to properties of the credential or other known data required by the zkApp, it must locally run a provable program to produce this proof. Furthermore, attestation is not limited in any scenario to making provable statements about a single provable data blob but also about multiple provable data blobs; consider the example when a wallet user must attest to owning KYC credentials from multiple global regions to create a single proof usable in a KYC-transaction. The provision for attestation extends beyond just transaction signing; it encapsulates the nuances of provable program inputs and their execution. This versatility serves on-chain and off-chain requirements, akin to verifiable presentations, but also demands caution. For instance, using private keys as public input for provable programs is highly discouraged, ensuring their use is strictly reserved for signatures and related operations.

To facilitate this interaction, the params field is vital, acting as the communication bridge between the requester and the wallet. It elucidates expectations, detailing the provable programs to be executed and the necessary attestations. The following pseudocode captures this flow succinctly:
```
// Pseudocode
START interaction
IF provider is defined
REQUEST[1] attestation
IF user approves
RESOLVE[2] attestation
CONTINUE zkProvableProgram
IF user rejects
REJECT[3] attestation
STOP interaction
IF provider is undefined
STOP interaction
```

[1] REQUEST
The requester MUST request attestation by calling the `mina_requestAttestation` RPC method on the provider exposed at `window.mina`. Calling this method MUST trigger a user interface allowing the user to approve or reject the attestation request. This method MUST return a Promise that is resolved with the desired proof or rejected if the attestation cannot be produced.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the request include information on what information will be revealed to the website? Maybe if so, programs should include data about what information they are proving for the UI?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed -- that's an important component, a wallet user must be able to understand precisely what they are attesting to and with what inputs. I'll add a section on this.


[2] RESOLVE
The Promise returned when calling the `mina_requestAttestation` RPC method MUST be resolved with the desired proof. This should emit an event message indicating that the attestation request has been approved and the promise has been resolved with the desired proof.

[3] REJECT
The Promise returned when calling the `mina_requestAttestation` RPC method MUST be rejected with an informative `Error` if the attestation cannot be produced. This should emit an event message indicating that the attestation request has been denied, and the promise is rejected with an error.

When a requester seeks attestation from a wallet, they must provide contextual bindings. These bindings are key-value pairs where the keys are strings, and the values can be any type with valid JSON encoding.

#### `mina_requestAttestation` Binding Parameters

#### `program`
A unique identifier or hash representing the provable program the wallet should run internally for attestation. Programs will be added via the standards process, and will initially include one program, "flat-credential-attestation".

### `clientData`
An adaptable data structure designed to bind the wallet to contextually relevant information. The content and structure of `clientData` are dynamic, tailored to the specific program.

#### `publicInputs`
A key-value map detailing the provable-program's method signature for open inputs. Each key-value pair describes a specific input and the value to use in the provable-program; further binding the wallet.


#### Example On-Chain Usage -- request attestation using a provable program for royalties claim
```ts
import { Mina } from "o1js";

const mina = window.mina;

try {
// Define the binding for the attestation
const binding = {
// The program could be constrained by a unique identifier for the program like a verification key
program: "flat-credential-attestation",
clientData: {},
// Define the required public inputs
publicInputs: {
"verifier": constructVerifierForRoyaltyClaim(),
},
};

// Request attestation using the binding. Wallet will match and verify internally against stored credentials.
const attestationProof = await mina.request({
method: 'mina_requestAttestation',
params: binding
});

// Construct a transaction using the received attestation proof
let transaction = await Mina.transaction(() => {
new RoyaltiesZkApp(zkappAddress).claim(attestationProof);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would claim be a function on the zkApp, that takes in a Proof type? (like here?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! It would be a method on the contract, or possibly another provable-program!

});

// Prove the transaction
await transaction.prove().catch(err => {
throw new Error(`Proof generation failed: ${err.message}`);
});

// Request the Mina wallet to sign the transaction
await mina.request({ method: 'mina_signTransaction', params: transaction });

// Send the transaction to the Mina network
mina.send('mina_sendTransaction', transaction);

console.log("Royalty claim transaction sent!");

} catch (error) {
if (error.message.includes('User denied')) {
console.error("User denied the attestation request.");
} else {
console.error(`Error while claiming royalties: ${error.message}`);
}
}
```

## User Journey

In this example user journey, an `Wallet` attests that they know some private data (e.g. a credential stating the user is over 18) that satisfies some constraints as defined by a specific zk-program and provides this attestation to a `zkApp`.

For further understanding, consider the sequence diagram below, which outlines the user journey:

```mermaid
sequenceDiagram

Wallet->>zkApp: Connect wallet
zkApp-->>Wallet: Connection Established

Wallet->>zkApp: Click "confirm age > 18"
zkApp->>Wallet: Request Attestation
Wallet->>Wallet: Construct Proof
Wallet->>zkApp: Provide Attestation Proof

zkApp->>zkApp: Verifies Attestation Proof
```

**Note: All interactions with the zkApp are done client-side**

## `Flat-Credential-Attestation` Program

This is the initial program included with the private attestation API.

Data stored should be in the following format:

```
{
("field": String): (Value: Any[Date, Field, UInt32, ECDSA Signature, String, ...])
...
}
```

A small DSL should be built for returning a boolean from simple manipulations of flat credential objects. For example (from the zkPassport RFC):

Credential:
```
{
documentExpiryDate: (Jan 01 2028: Date),
dateOfBirth: (Jan 01 2000: Date),
nationality: ("USA": String),
firstName: ("Alice": String),
...
credentialHash: ("xb82818...": SHA256Hash),
credentialHashSignature: ("ntn838...": PassportSignature),
}
```

Program:
```
let verifier = new FlatCredentialVerifier();
const hash = verifier.sha256Hash([ verifier.field('nationality'), ... ]);
verifier = verifier.checkEqual('credentialHash', hash);
verifier = verifier.verifySignature('credentialHashSignature', verifier.field('credentialHash'), countryPublicKey);
verifier = verifier.checkEqual('nationality', 'USA')
const zkProof = AttestationAPI.createAttestation(verifier);
```

## Use with Nullifiers

**Request Nullifier Key** should also accept a small DSL which allows the construction of unique identifiers, proofs about that unique identifier, and a salt.

For example, using the same credential as above:

```
let verifier = new FlatCredentialVerifier();
const credentialHash = verifier.sha256Hash([ verifier.field('nationality'), ... ]);
verifier = verifier.checkEqual('credentialHash', credentialHash);
verifier = verifier.verifySignature('credentialHashSignature', verifier.field('credentialHash'), countryPublicKey);
verifier = verifier.checkEqual('nationality', 'USA')

requestNullifierKeyAndProof(credentialHash, verifier, applicationSalt)
```

With **requestNullifierKeyAndProof** returning `hash(credentialHash, applicationSalt)`, along with a proof that the hash was constructed correctly, and credentialHash passes the `verifier` claim.

## Backwards Compatibility

As an extension to the existing Mina provider, this API does not affect the operation of existing APIs.

## Security Considerations

The process of attesting to data in the Mina ecosystem, as detailed in this proposal, introduces several security implications that must be carefully considered by implementors. The issues and mitigations outlined here are suggestions for implementors to consider.

### Unauthorized Attestation

#### Issue
If an attacker gains unauthorized access to a user's wallet, they could produce attestations on-behalf of the user.

#### Mitigation
- **Encryption**: Ensure that all private data are encrypted at rest.
- **Limited Lifetime**: Implementations could consider a mechanism where objects have a limited validity period, reducing the impact of potential breaches.

### Replay Attacks

#### Issue
If a user produces an attestation (i.e. a proof object) that proof, if provided to another party can be used in any other zk-program or smart contract method that can verify the proof.

#### Mitigation
- **Limited Lifetime**: Implementations could consider a mechanism where objects have a limited validity period, reducing the impact of potential breaches.
- **Unique Attestation Identifiers**: Include unique identifiers in each attestation. This ensures that each proof object is distinct and cannot be reused in different contexts.

## Future Work

Future work may want to consider other data sources, such as storing data in remote storage, encrypted with a private key in the users wallet.