DEV Community

Aimua
Aimua

Posted on

Programmable Key Pairs (PKPs): A Versatile Tool for Secure Authentication

Introduction

When it comes to the field of secure authentication PKPs are the future, Programmable Key Pairs (PKPs) have emerged as a powerful tool. PKPs offer a flexible and efficient approach to authentication, providing developers with a secure means of verifying user identities while supporting a wide range of use cases. In this article, I will provide a high-level overview of how PKPs work, I will talk about different use cases and offer a quick DIY guide for developers interested in leveraging this innovative technology.

Understanding Programmable Key Pairs (PKPs)

PKPs are cryptographic key pairs consisting of a private key and a corresponding public key. The private key remains securely stored, while the public key is made available for authentication purposes. Unlike traditional public-private key pairs, PKPs have an additional layer of programmability enabling developers to dynamically control and manage access to resources. Each Programmable Key Pair (PKP) is a versatile Multi-Party Computation (MPC) wallet that can be used to power a wide array of potential applications and use cases.
Hold up, what's an MPC wallet?
To understand that I think it's best to build a solid foundation on the understanding of the Lit network.
Straight out the docs the Lit network is described as

"The Lit network operates through a distributed federation of nodes, where each node plays a vital role in key generation, consensus, and the execution of Lit Actions. What sets Lit apart is its foundation on threshold cryptography. With this approach, Lit ensures that no single node possesses complete control or executive authority over the network.
This decentralized structure guarantees enhanced security, resilience, and trustworthiness for all participants in the Lit ecosystem."

Threshold cryptography is utilized in Lit to generate shares of a new public/private key pair through a process called Distributed Key Generation (DKG). Unlike traditional cryptography, the private key is never fully formed. Rather each node in the network possesses a unique private key share. These shares function similarly to regular private keys allowing nodes to perform cryptographic operations like signing and decryption.
However a combination of shares from multiple nodes exceeding a pre-defined threshold (currently set at two-thirds), is required to obtain the final signature or decrypted content.
This decentralized ownership of private key shares across nodes enhances security and eliminates single points of control. All cryptographic operations occur within a secure, isolated environment, preventing node operators and external agents from accessing the private key shares. When interacting with user nodes communicate through independent encrypted channels ensuring the confidentiality of shares for signing and decryption. The shares are only exposed client-side during the recombination process maintaining a high level of security.
In summary threshold cryptography employed in the Lit network distributes power among participating nodes ensuring the network's security and integrity. No single node possesses complete control over the private key as it requires collaboration and collective participation to perform cryptographic operations. This approach strengthens security by eliminating central points of vulnerability and enhances the overall robustness of the key management system.
Now that you understand how the underlying operation of the Lit network, it is easy to see how MPCs function in the context of PKPs.

Now back to MPCs, Multi-party computation (MPC) is a method that enables multiple parties to collaboratively compute a function using a set of private inputs, while keeping those inputs secret. In the context of PKPs, MPC can be used to generate distributed shares of a public/private key pair, allowing encryption and signing without revealing the complete private key. This method ensures no single party has full control over the key pair and removes single points of failure present in centralized key management systems.

How PKPs Work

  • Key Generation: Each PKP is an ECDSA key pair generated collectively by the Lit nodes through a process called Distributed Key Generation (DKG). Operating as a decentralized network, this allows Lit to generate a new key pair where the private key never exists in its entirety. Instead, each node only holds a share of the key. These signature shares must be combined above the threshold (two-thirds of the nodes) to produce the complete signature signed by the PKP. This signature can then be used for instances such as posting a transaction to a blockchain network.

  • Minting a PKP: As per the docs, you can mint a PKP in four major ways.

    • Minting via contracts: Lit has a custom EVM rollup testnet called Chronicle, You can mint an NFT from our PKP contract on Chronicle.
    • Minting via Social: You can mint a PKP by presenting a valid OAuth token as an authentication method to the Lit Relay server. At the time of this article, only Google OAuth tokens are supported however there are plans in place to support Discord soon.
    • Minting via Email / SMS (OTP): You can mint a PKP by presenting a generated token from successful OTP code confirmation, which will be returned by the lit-auth-client in the AuthMethod return from successful code confirmation.
    • Minting via WebAuthn: You can mint a PKP by presenting a valid WebAuthn credential generated by your browser to the Lit Relay server. There is a frontend developed by the people at Lit protocol that helps with this process, you can check it out here It currently supports both username-based and username-less WebAuthn registration, usernames are purely used for your convenience/reference on the client side.
  • Authentication Process: When you call a Lit Action, you may pass Auth Methods that should be resolved. These could be things like a WebAuthn (Apple Passkey) signature, or an OAuth token from a service like Discord or Google. An authentication method refers to the specific credential (i.e. a wallet address, Google OAuth, or Discord account) that is programmatically tied to the PKP and used to control the underlying key pair. Only the auth method associated with a particular PKP can combine the underlying shares. You can read more about how authentication works here
    There are currently two main ways to do auth with Lit Actions.

    • Using Lit Auth Directly: Several auth methods are supported by Lit directly. These include methods configured using the PKPPermissions contract, the user holding the PKP NFT, or assigned via a Lit Action with permission to sign using the PKP. If you use Lit auth directly, you are limited to the auth methods that are supported by Lit. Existing supported lit-auth methods are: An address, An action, web authentication, Discord, OTP, Google and Google_JWT.
    • Custom Auth: If you would like further customization over your PKP auth methods, you can do auth yourself with a Lit Action, using the auth helpers provided in the documentation In this scenario, after you give your Lit Action permission to use the PKP, the typical flow is to burn the PKP NFT or send it to itself. However, it is imperative to understand that if you do decide to burn the PKP, you will be unable to add additional auth methods in the future. If you go this route your auth looks like a bunch of if statements inside the Lit Action.
  • Verification: The system verifies the authenticity of the public key against the corresponding private key stored securely.

  • Access Control: With access control, you can introduce private and permissioned data to the open web using decentralized encryption.
    Using Lit actions and PKPs you can provide decryption "keys" to users based on on-chain conditions, such as ownership over a specific NFT or membership within a DAO.
    If you're blockchain 1337 you understand how much of a big deal this is. This is a game changer in the context of backend web3 programming as lit actions in conjunction with a web3 storage service e.g. ceramic can decentralize backend services at scale.
    For example, Lit Actions + PKPs + web3 storage can be a replacement for a traditional web2 backend. Consider a web3-based Twitter alternative that utilizes Ceramic as its data storage solution. By creating a PKP associated with a Ceramic stream and granting specific Lit Actions the capability to sign with that PKP, you can emulate the functionality of a web2 backend. The Lit Actions can enforce business logic to ensure that only accurate data is written to the Ceramic stream.
    A quoteTweet() Lit Action could verify whether a user has already quoted a tweet before allowing the quote tweet to be recorded in the stream.

Use Cases for PKPs

  • Web3 automation and interoperability with Lit Actions and PKPs:

DeFi Automation: Using PKPs and Lit Actions you can automate your interactions across decentralized finance.
Common implementations include:
Condition-based transactions (ex. on-chain limit orders).
Recurring payments.
A popular example is Sling Protocol: An SDK for automating transactions on popular DEXs.
Currently supports Uniswap V3 and 1inch.
You can use this to authorize flash loans.

Infrastructure: Build powerful infrastructure that harnesses the power of Lit!
Event listening and condition-based execution.
Cross-chain bridges.
Decentralized key custodians.
Privacy-preserving transactions amongst others.

  • Secure User Authentication: Introduce privacy to decentralized applications. Use Lit to securely store private and permissioned data on the open web. PKPs enable secure authentication mechanisms for applications and systems, mitigating the risk of password-based attacks and unauthorized access.

  • Multi-Factor Authentication (MFA): Use on-chain credentials to gate access to your favorite web2 applications and data. PKPs can be utilized as a component of a 2FA system, where the private key acts as the second factor, enhancing the overall security of the authentication process.

Basic Example

Restrict access based on the possession of an ERC1155 token.
In this example, the token contract's address is 0x3110c39b428221012934A7F617913b095BC1078C and the token id we are checking for is 9541.

 const accessControlConditions = [
   {
     contractAddress: '0x3110c39b428221012934A7F617913b095BC1078C',
     standardContractType: 'ERC1155',
     chain,
     method: 'balanceOf',
     parameters: [
       ':userAddress',
       '9541'
     ],
     returnValueTest: {
       comparator: '>',
       value: '0'
     }
   }
 ]

Enter fullscreen mode Exit fullscreen mode
  • Web3 Social: Social applications that empower users with privacy and true data ownership.
    Credentialing systems for privacy-preserving web3 login, Account abstraction with support for web2 auth methods (i.e. Apple Passkey), Verifiable on-chain reputation building.

  • Gaming: PKPs can enhance the state of web3 gaming by offering various benefits some of which include
    Signing and wallet abstraction for blockchain-based games: Programmable key pairs allow for seamless signing and wallet management in blockchain-based games. Players can securely sign transactions and interact with the game's smart contracts without exposing their private keys directly, improving the user experience and enhancing security.
    Condition-based reward systems and achievements: PKPs can enable the implementation of condition-based reward systems and achievements in games. Smart contracts can verify specific conditions or achievements and automatically distribute rewards to players, ensuring fairness and transparency in the gaming ecosystem.
    Private data for multiplayer games: By using cryptographic techniques, sensitive player information can be encrypted and securely shared among authorized participants, protecting privacy and enhancing the security of multiplayer gaming experiences.

  • Using PKPs as Wallets: With PKPs, you can build secure, customizable MPC wallets that offer intuitive onboarding experiences without the pain of private key management.

Quick Start Guide to PKPs for Developers

To get started with PKPs you can leverage Lit Protocol and WalletConnect V2 to seamlessly connect PKPs to hundreds of dApps. WalletConnect enables secure communication between wallets and dApps through QR code scanning and deep linking. With WalletConnect, PKPs act as MPC wallets, interacting with dApps without ever exposing private keys.

To connect a PKP and a dApp, you will need to:

  • Create a PKPClient.

  • Initialize PKPWalletConnect with the PKPClient.

  • Subscribe and respond to events.

Step 1: Create a PKPClient
PKPClient represents a PKP and initializes signers for use across multiple blockchains (note: EVM-only at the moment).

import { PKPClient } from '@lit-protocol/pkp-client';

const pkpClient = new PKPClient({
  controllerAuthSig: '<Your AuthSig>',
  // Or you can also pass in controllerSessionSigs
  pkpPubKey: '<Your PKP public key>',
});
await pkpClient.connect();

Enter fullscreen mode Exit fullscreen mode

The controllerAuthSig (or controllerSessionSigs) is used to authorize requests to the Lit nodes. To learn how to leverage different authentication methods, refer to the Authentication section of the docs.

To view more constructor options, refer to the API docs.

Step 2: Initialize PKPWalletConnect with the PKPClient
PKPWalletConnect wraps @walletconnect/web3wallet to manage WalletConnect session proposals and requests using the given PKPClient.

import { PKPWalletConnect } from '@lit-protocol/pkp-walletconnect';

const config = {
  projectId: '<Your WalletConnect project ID>',
  metadata: {
    name: 'Test Lit Wallet',
    description: 'Test Lit Wallet',
    url: 'https://litprotocol.com/',
    icons: ['https://litprotocol.com/favicon.png'],
  },
};
const wcClient = new PKPWalletConnect();
await wcClient.initWalletConnect(config);
wcClient.addPKPClient(pkpWallet)

Enter fullscreen mode Exit fullscreen mode

Step 3: Subscribe and respond to events

Session Proposal
Once the WalletConnect client is initialized, the PKP is ready to connect to dApps. The dApp will request to connect to your PKP through a session proposal. To respond to session proposals, subscribe to the session_proposal event.

pkpWalletConnect.on('session_proposal', async (proposal) => {
  console.log('Received session proposal: ', proposal);

  // Accept session proposal
  await pkpWalletConnect.approveSessionProposal(proposal);

  // Log active sessions
  const sessions = Object.values(pkpWalletConnect.getActiveSessions());
  for (const session of sessions) {
    const { name, url } = session.peer.metadata;
    console.log(`Active Session: ${name} (${url})`);
  }
});

Enter fullscreen mode Exit fullscreen mode

To trigger the session proposal, visit any WalletConnect V2 compatible dApp to obtain a URI. For an example, navigate to WalletConnect's test dApp, choose 'Ethereum' network, and click "Connect". A "Connect wallet" modal should appear with a copy icon located at the top right. Click on the icon to copy the URI.

// Pair using the given URI
await pkpWalletConnect.pair({ uri: uri });

Enter fullscreen mode Exit fullscreen mode

Session Request

Once the session proposal is approved, the dApp can then request your PKP to perform actions, such as signing, via a session request. To acknowledge and respond to these session requests, set up an event listener for the session_request event.

pkpWalletConnect.on('session_request', async (requestEvent) => {
  console.log('Received session request: ', requestEvent);

  const { topic, params } = requestEvent;
  const { request } = params;
  const requestSession = signClient.session.get(topic);
  const { name, url } = requestSession.peer.metadata;

  // Accept session request
  console.log(
    `\nApproving ${request.method} request for session ${name} (${url})...\n`
  );
  await pkpWalletConnect.approveSessionRequest(requestEvent);
  console.log(
    `Check the ${name} dapp to confirm whether the request was approved`
  );
});
Enter fullscreen mode Exit fullscreen mode

Alternatively, you can use **SignClient**.
Using SignClient The @lit-protocol/pkp-walletconnect library exposes base functionality needed to pair PKPs to dApps, approve and reject session proposals, and respond to session requests. For extended capabilities, you can retrieve WalletConnect's SignClient from the PKPWalletConnect instance.

const signClient = pkpWalletConnect.getSignClient();
Enter fullscreen mode Exit fullscreen mode

For more information on their protocol and SDKs you can refer to the WalletConnect V2 docs

Conclusion

Programmable Key Pairs (PKPs) provide developers with a versatile and secure means of authentication. By combining the power of public-key cryptography with programmability, PKPs offer enhanced security and flexibility across various use cases, from user authentication to secure communications and Gaming. With a quick start guide in hand, developers can embark on leveraging this innovative tool to enhance the security of the decentralized web.
Hope you enjoyed my first-ever article, do let me know if it helped in any way. As always, It's your boy Kimonic wishing you peace and blessings.

Top comments (0)