icon

Time Lock Encryption using Lighthouse Access Control

Introduction

In this tutorial, we delve into the innovative concept of Time-Lock Encryption on the InterPlanetary File System (IPFS) using Lighthouse Access Control. IPFS, often referred to as the distributed web, offers a decentralized protocol to make the web faster, p2p, and more open. On the other hand, Lighthouse.Storage is a Web3 decentralized storage solution, offering perpetual storage to store your data securely long-term.

The amalgamation of these two technologies brings forth an exciting feature – the ability to encrypt files and set conditions for their decryption based on specific blockchain parameters. One of the innovative concept it enables is "Time-Lock Encryption."

What exactly does this mean? Think of it as a time capsule. You can securely store a piece of information, and set a condition that this information will only be accessible after a particular block number on the blockchain like ethereum has been reached. Such a feature has a myriad of applications, from securing early-stage project details to establishing wills or contracts that are meant to be executed in the future.

This tutorial will walk you through the following:

  1. Preparing your environment for Lighthouse.Storage.
  2. Encrypting and uploading a file onto IPFS.
  3. Setting a blockchain-based time-lock condition for accessing this file on optimism chain.
  4. (Optional) Retrieving the conditions set on a file.

Whether you're a blockchain enthusiast, a developer looking to integrate time-lock features, or someone curious about decentralized storage and its potential, this guide is tailored for you.

Let's embark on this journey and unlock the potential of Time-Lock Encryption on IPFS using Lighthouse Storage.


Preparation:

Note: Ensure you have Node.js installed. If not, download it here

  1. Install Lighthouse SDK and Create Wallet:

    • Install the SDK globally:

      npm install -g @lighthouse-web3/sdk
      
    • Create a new Lighthouse wallet, which will provide you with a Public Key and a Private Key. Ensure you safely store this information:

      lighthouse-web3 create-wallet
      
  2. Obtain Lighthouse API Key:

    • Generate a new API key:

      lighthouse-web3 api-key --new
      
    • You will be presented with an API key. Store this securely and avoid sharing it.

  3. Environment Setup for Your Project:

    • Create a new directory for your project:

      mkdir lighthouse-encryption && cd lighthouse-encryption
      
    • Initialize a new Node.js project:

      npm init -y
      
    • Install required local dependencies:

      npm install dotenv ethers
      
    1. Security Configuration:
    • Within your project directory, create a .env file.

    • Inside .env, add your Lighthouse API key and private key:

      API_KEY=Your_Lighthouse_API_Key
      PRIVATE_KEY=Your_Private_Key
      
    • Always ensure your .env file is added to .gitignore to prevent exposing your credentials, especially if you're using a version control system.


    Step 1: Upload an Encrypted File

    Set up a script, upload.js, in your project directory. Add the following code:

    import * as dotenv from 'dotenv';
    dotenv.config();
    import { ethers } from "ethers";
    import lighthouse from '@lighthouse-web3/sdk';
    
    const signAuthMessage = async (publicKey, privateKey) => {
      const provider = new ethers.JsonRpcProvider();
      const signer = new ethers.Wallet(privateKey, provider);
      const messageRequested = (await lighthouse.getAuthMessage(publicKey)).data.message;
      const signedMessage = await signer.signMessage(messageRequested);
      return signedMessage;
    }
    
    const deployEncrypted = async () => {
      const path = "Absolute/path/to/your/file.txt"; // Update this path
      const apiKey = process.env.API_KEY;
      const publicKey = "Your_Public_Key"; // Update this
      const privateKey = process.env.PRIVATE_KEY;
      const signedMessage = await signAuthMessage(publicKey, privateKey);
    
      const response = await lighthouse.uploadEncrypted(
        path,
        apiKey,
        publicKey,
        signedMessage
      );
    
      console.log(response);
    }
    
    deployEncrypted();
    

    Run the script:

    node upload.js
    

    Expected Response:

    {
      data: [
        {
          Name: 'test.txt',
          Hash: 'ENCRYPTED_CID',
          Size: '58'
        }
      ]
    }
    

    Step 2: Apply Access Control Condition:

    Create a script, access-control.js, with the following:

    import * as dotenv from 'dotenv';
    dotenv.config();
    import { ethers } from "ethers";
    import lighthouse from '@lighthouse-web3/sdk';
    
    const signAuthMessage = async (publicKey, privateKey) => {
      const provider = new ethers.JsonRpcProvider();
      const signer = new ethers.Wallet(privateKey, provider);
      const messageRequested = (await lighthouse.getAuthMessage(publicKey)).data.message;
      const signedMessage = await signer.signMessage(messageRequested);
      return signedMessage;
    }
    
    const accessControl = async () => {
    	try{  
    		const cid = "Your_File_CID"; 
    		// Update this with the CID from the previous step
    		const publicKey = "Your_Public_Key"; // Update this
    	  const privateKey = process.env.PRIVATE_KEY;
    
      const conditions = [
        {
          id: 1,
          chain: "Optimism",
          method: "getBlockNumber",
    			standardContractType: "",
          returnValueTest: { comparator: ">", value: "Your_Block_Number" }, // Update this value as per your requirements
        },
      ];
    
    // Aggregator is what kind of operation to apply to access conditions
        // Suppose there are two conditions then you can apply ([1] and [2]), ([1] or [2]), !([1] and [2]).
    
      const aggregator = "([1])";
    
      const signedMessage = await signAuthMessage(publicKey, privateKey);
    
      const response = await lighthouse.applyAccessCondition(
        publicKey,
        cid,
        signedMessage,
        conditions,
        aggregator
      );
    
      console.log(response);
    }
    
    accessControl();
    
    

    Execute the script:

    node access-control.js
    

    Expected Response:

    {
      data: {
        cid: 'ENCRYPTED_CID',
        status: 'Success'
      }
    }
    

    Note:

    • Only the owner of the file can apply access conditions
    • This only works when file is uploaded with lighthouse encryption

    (Optional) Step 3: Retrieve Access Control Conditions:

    Formulate another script, get-conditions.js, as:

    import lighthouse from '@lighthouse-web3/sdk';
    
    const accessConditions = async() => {
      const cid = "Your_File_CID"; // Update this
      const response = await lighthouse.getAccessConditions(cid);
      console.log("Condition:", response.data.conditions);
    	console.log("Response:", response)
    }
    
    accessConditions();
    

    Run the script:

    node get-conditions.js
    

    Expected Response:

    Condition: [
      {
        id: 1,
        chain: 'Optimism',
        method: 'getBlockNumber',
        standardContractType: '',
        returnValueTest: { comparator: '>', value: 'Your_Block_Number' }
      }
    ]
    Response: {
      data: {
        aggregator: '[1]',
        conditions: [ [Object] ],
        conditionsSolana: [],
        sharedTo: [],
        owner: 'Your_Public_Key',
        cid: 'ENCRYPTED_CID'
      }
    }
    

    (Receiver side) Step 4: Verify Access and Retrieve Encryption Key:

    Once you've uploaded a file and set an access control condition, before attempting to download or decrypt it, you might want to check if you have the necessary permissions (or if the conditions have been met). This step will guide you on how to do just that:

    Prepare Your Script:

    Create a new script named verify-access.js in your project directory. Insert the following code:

    import * as dotenv from 'dotenv';
    dotenv.config();
    import { ethers } from "ethers";
    import lighthouse from '@lighthouse-web3/sdk';
    
    const signAuthMessage = async (publicKey, privateKey) => {
      const provider = new ethers.JsonRpcProvider();
      const signer = new ethers.Wallet(privateKey, provider);
      const messageRequested = (await lighthouse.getAuthMessage(publicKey)).data.message;
      const signedMessage = await signer.signMessage(messageRequested);
      return signedMessage;
    }
    
    const getFileEncryptionKey = async () => {
      try {
        const cid = 'ENCRYPTED_CID'; // Replace with your CID
        const publicKey = 'Receiver_side_public_key'; // Replace with your public key
        const privateKey = process.env.RECEIVER_SIDE_PRIVATE_KEY;
    
        const signedMessage = await signAuthMessage(publicKey, privateKey);
    
        const keyResponse = await lighthouse.fetchEncryptionKey(
          cid,
          publicKey,
          signedMessage
        );
    
        // Print the direct response
        console.log(keyResponse);
    
      } catch (error) {
        console.log("Error:", error.message);
      }
    }
    
    getFileEncryptionKey();
    

    Run the Script:

    Execute the verify-access.js script:

    node verify-access.js
    

    Expected Response (When you have access):

    {
      data: {
        key: 'KEY'
      }
    }
    

    Expected Response (When you do not have access):

    { message: "you don't have access", data: {} }
    

Conclusion

By following this tutorial, you've encrypted a file on Lighthouse Storage and set a time-lock condition using the Optimism blockchain's block number. Before sharing or deploying any code, always remember to secure your private and API keys.

To know more join our discord and get in touch with our team. Follow Lighthouse on X.


Our Blogs

Read our latest blog

icon

Nandit Mehra

Encryption and Access Control for Web3 using Lighthouse

icon

Lighthouse

How To Migrate Your Files To Lighthouse

icon

Nandit Mehra

Decentralized storage for the Ocean Protocol

icon

Ravish Sharma

Creating a Pay-to-View Model Using Lighthouse Storage

icon

Aryaman Raj

Getting Started with Lighthouse Python SDK

icon

Aryaman Raj

A Comprehensive Guide to Publishing and Updating Content with Lighthouse IPNS

icon

Aryaman Raj, Nandit Mehra

Time Lock Encryption using Lighthouse Access Control

icon

Aryaman Raj

Secure File Sharing using Lighthouse SDK: A Step-by-Step Guide

icon

Aryaman Raj

Passkey Demo App with WebAuthn and Ethereum

icon

Ishika Rathi

Web3 Storage: IPFS and Filecoin Guide

icon

Ishika Rathi

Understanding How web3 storage Operates

icon

Ishika Rathi

Lighthouse: Secure Web3 Storage for Your AI Data

icon

Ishika Rathi

Decentralized Storage: A Smarter, Safer, and Cheaper Way to Manage Your Data

icon

Ishika Rathi

Unveiling the Mechanics of Perpetual Storage

icon

Ishika Rathi

Navigating Permanent Storage: Harnessing the Power of Filecoin and IPFS

icon

Ishika Rathi

Decentralized Excellence: Elevating Data Storage with Lighthouse

icon

Ishika Rathi

Revolutionizing Permanence in Data Storage

icon

Ishika Rathi

Eternalizing Data: A Permanent storage

icon

Ishika Rathi

Exploring Web3 Advancements in Storage Solutions

icon

Ishika Rathi

NFT Storage Strategies

icon

Ishika Rathi

On-Chain Encryption: Security Unveiled

icon

BananaCircle

Web2 Storage Challenges Versus Web3 Solutions Ft. Lighthouse

icon

Nandit Mehra

Discover How the Endowment Pool Makes Your Data Immortal