Skip to content
Open
Show file tree
Hide file tree
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
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ shows how users are alerted of pending recoveries during normal SSO login and ca

### Module Implementation

The solution centers on a [new erc7579 validator module](https://erc7579.com/modules) called `GuardianRecoveryValidator`. This guide illustrates
how to perform different guardian recovery actions with this module:
The solution centers on a new [ERC7579 inspired validator module](https://docs.zksync.io/zksync-era/unique-features/zksync-sso/account-modules)
called `GuardianRecoveryValidator`. This guide illustrates how to perform different guardian recovery actions with this module:

#### Adding & verifying a Guardian

Expand Down Expand Up @@ -132,6 +132,173 @@ A pending recovery can be discarded using `discardRecovery`, which:
1. Removes the recovery request from storage.
2. Emits a **`RecoveryDiscarded`** event for traceability.

## Account Recovery with Google

The solution allows users to link **a Google account as a recovery method** to their SSO account,
and later use that Google account to **recover access to their SSO account** without revealing
their email or any information that would expose their identity.

The guide below provides information about the linking and recovery process, with further details about these two main components
in the solution:

- An [ERC7579 inspired validator module](https://docs.zksync.io/zksync-era/unique-features/zksync-sso/account-modules) (`OidcRecoveryValidator`)
is in charge of managing the recovery data of every SSO account.
- A **ZK circuit** is used to prove the ownership of an Google account without revealing the account information.

### Main flows high-level description

The process consists of two main phases:

1. **Google Account Linking:** The user links their Google account to their SSO account with the `OidcRecoveryValidator`.
2. **Account Recovery with Google:** The user shows proof of owning a `JWT` issued to the same Google account
from an auxiliary account and adds a new passkey to their SSO account.

::callout{icon="i-heroicons-light-bulb"}
Throughout this documentation, you'll encounter the term OIDC. Open ID Connect is **an identity authentication protocol**
built on top of OAuth 2.0 to create a standard way of authenticating and authorizing users when they access digital services.
For more information, please refer to the [OIDC documentation](https://openid.net/developers/how-connect-works/).
::

#### **Google account linking to the SSO account**

To use their Google Account for recovery, the user needs to link it to their SSO account. For this, they will request a `JWT`,
extract the necessary data, combine it with the salt, and create a hash of these elements.
Finally, this hash will be registered in the `OidcRecoveryValidator`.

![Google Account Linking](/images/zksync-sso/account-recovery/oidcLinking.svg)

**OIDC Digest**

The JWT has 3 attributes that together identify a Google account: `iss` (issuer), `aud` (audience), and `sub` (subject).
Hashing the 3 of them generates a way to identify the user.

Saving a hash of those 3 is a way to save a reference to the Google account.

To provide extra security, a `salt` is added. This salt is managed by a different entity and works as a second factor of security.

Finally, the digest is calculated as follows:

`PoseidonHash(iss || aud || sub || salt)`

#### **Step 2: Present ownership proof for recovery**

**When users lose access to their account**, they must interact with the `OidcRecoveryValidator` through an auxiliary account
to validate that they have ownership of the account to be recovered.

Since this is a recovery process, users won't have access to their SSO account when presenting the proof.
An auxiliary account with enough funds to cover the transaction cost will have to be used to submit the proof.

OIDC allows users to populate the `nonce` field with custom data. This field contains the recovery data within the `JWT`,
enabling the circuit to verify that the `JWT` was specifically generated for this recovery.

::callout{icon="i-heroicons-light-bulb"}
Through the ZK proof, the system verifies that the Google Account owner is authorizing the SSO account recovery.
Users generate this proof locally on their device, while the contract supplies the public arguments for verification.
::

After completing this process, users can add a new passkey to their SSO account, successfully recovering access to it.

![Google Account Recovery](/images/zksync-sso/account-recovery/oidcRecovery.svg)

### Module Implementation

The [**`OidcRecoveryValidator`**](https://github.com/matter-labs/zksync-sso-clave-contracts/blob/main/src/validators/OidcRecoveryValidator.sol)
is an [ERC7579 inspired validator module](https://docs.zksync.io/zksync-era/unique-features/zksync-sso/account-modules)
that enables zero-knowledge-based account recovery via OpenID Connect (OIDC) identity assertions. It enables user to add a new passkey
if they can prove control over an OIDC identity (e.g., their Google account) previously linked to their SSO account.

#### **Adding & removing linking to OIDC identities**

The following functions manage the linking and unlinking of OIDC identities:

**Account Linking**

The function `addOidcAccount()` links an OIDC identity (`oidcDigest`, `iss`) to a new or existing SSO account.
As a restriction, the `oidcDigest` must not be registered to another account.

- Emits: `OidcAccountUpdated`.

**Remove Linking**

The function `deleteOidcAccount()` (**and internal `_deleteOidcAccount`)** fully cleans OIDC data,
both from the SSO account and the digest mapping.

- Emits: `OidcAccountDeleted`

#### **Recovery process**

The following functions play a crucial role in the recovery process:

**Initiating Recovery**

`startRecovery()` is called with a zk proof and the hash of the new passkey. It checks the proof by calling the ZK verifier.
If the ZK proof verification fails, this method reverts.

- Emits: `RecoveryStarted`

**Completing Recovery (Validating transaction & updating passkey)**

`validateTransaction()` validates a transaction that aims to add a new passkey after a successful `startRecovery()`.

- If all checks pass, it resets the recovery state and returns `true`, authorizing the transaction. Otherwise, it returns `false`.

**Cancelling Recovery**

Users can opt to cancel an active recovery at any time before completion, via `cancelRecovery()`.

- Emits: `RecoveryCancelled`.

### Circuit Implementation

::callout{icon="i-heroicons-light-bulb"}
The circuit is implemented in **Circom** and leverages code from [`circomlib`](https://github.com/iden3/circomlib) and [`zkemail`](https://github.com/zkemail).
::

The circuit performs **two key validations:**

- Prove that the user owns a valid JWT signed by Google and issued for the specific Google account.
- Prove that the owner of the JWT had the intention of performing the transaction.

To do this, it **does 4 main operations:**

1. Validate the JWT. This is done by performing the standard JWT validation using RS256 with the Google public key.
2. Parse and extract important data from the JWT: `iss`, `sub`, `aud`, and `nonce`
3. Recreate and validate the OIDC digest.
4. Recreate and validate the content of the nonce.

![OidcCircuit](/images/zksync-sso/account-recovery/oidcCircuit.png)

For more information, please refer to the [Circuit repository](https://github.com/Moonsong-Labs/zksync-social-login-circuit/).

#### **Inputs**

The circuit's inputs fall into three main categories:

**Key elements for validation**

The circuit requires **4 primary inputs, which enable its core validation functions**:

1. **The `JWT`** (private): This is the raw JWT, as sent by Google.
2. **Google's public key** (public).
3. **The expected digest** (public, more on this later): `PoseidonHash(sub || aud || iss || salt)`
4. **The expected content of the nonce** (public): Set by the user and then signed by Google.

**Privacy & ownership**

Two additional inputs are essential for maintaining privacy:

- **Blinding factor** (private): Random value used to avoid revealing the nonce defined by the user.
- **Salt** (private): Deterministic value. Used to create a second factor of security and avoid Google being
the only custodian of the wallet.

**Optimization & other elements**

Finally, there are several additional inputs used for optimization purposes, such as the indices of all important elements within the JWT.

#### Outputs

Rather than producing an output value, the circuit acts as a validator - it fails if any of the required validations are unsuccessful.

*More account recovery options are coming soon.*

<!--
Expand Down
29 changes: 16 additions & 13 deletions cspell-config/cspell-misc.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
celestia
Celestia
code4rena
Code4rena
Consensys
Expand All @@ -7,34 +9,35 @@ Danksharding
decommitted
deployers
Deployers
eigen
Eigen
eigenda
Gravita
GRVT
Hola
Icones
immediates
Immunefi
initializable
Initializable
Transak
Lukka
mathbb
mundo
permissioned
oidc
Oidc
pcaversaccio
permissioned
permissionlessly
pnpx
Transak
trustlessly
turing
uncompromised
undol
Winternitz
Yubi
zkemail
zkicon
zkvm
Celestia
celestia
Eigen
eigen
eigenda
turing
uncompromised
undol
trustlessly
permissionlessly
Zoltu
Zyfi
Gravita
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.