Sismo Connect Solidity Library: Verify Onchain

Verify proofs from your users

The Sismo Connect Solidity Library allows to easily verify proofs from your users onchain.

This page will detail all the specifications of the Sismo Connect Solidity Library that is deployed on the following chains.

You can find the Solidity Library GitHub repository here.

Usage

Installation

Make sure to have Foundry installed.

Install the Forge dependency:

foundryup
forge install sismo-core/sismo-connect-solidity --no-commit

Add the remapping in remappings.txt:

echo $'sismo-connect-solidity/=lib/sismo-connect-solidity/src/' >> remappings.txt

Import the library

In your Solidity file:

import "sismo-connect-solidity/SismoConnectLib.sol"; 

Contract inheritance

Inherit your contract from the Sismo Connect Library.

Call the SismoConnect constructor in the constructor of your contract with an appId. Here is a tutorial to get an appId.

contract MyContract is SismoConnect { // inherits from Sismo Connect library
 
 // call SismoConnect constructor with your appId
 constructor(bytes16 appId) SismoConnect(buildConfig(appId)) {}
 
}

Verify proofs from your users

You will then need to create some request objects to check that the proofs from your users are valid with respect to these requests.

Finally, use the verify() function to verify the proof stored in sismoConnectResponse with respect to some requests. For example, below we verify that the proof in the sismoConnectResponse is cryptographically valid for a certain ClaimRequest, AuthRequests and SignatureRequest.

function doSomethingUsingSismoConnect(bytes memory sismoConnectResponse) public {    
    SismoConnectVerifiedResult memory result = verify({
        responseBytes: sismoConnectResponse,
        // we want users to prove that they own a Sismo Vault
        // and that they are members of the group with the id 0x42c768bb8ae79e4c5c05d3b51a4ec74a
        // we are recreating the auth and claim requests made in the frontend to be sure that 
        // the proofs provided in the response are valid with respect to this auth request
        auth: buildAuth({authType: AuthType.VAULT}),       
        claim: buildClaim({groupId: 0x42c768bb8ae79e4c5c05d3b51a4ec74a},
        // we also want to check if the signed message provided in the response is the signature of the user's address
        signature:  buildSignature({message: abi.encode(msg.sender)})
    });

    // if the proofs and signed message are valid, we can take the userId from the verified result
    // in this case the userId is the vaultId (since we used AuthType.VAULT in the auth request) 
    // it is the anonymous identifier of a user's vault for a specific app 
    // --> vaultId = hash(userVaultSecret, appId)
    uint256 vaultId = SismoConnectHelper.getUserId(result, AuthType.VAULT);
    
    // do something with this vaultId for example
}

If your proof is valid, the contract will continue its execution, otherwise, it will produce an error.

Documentation

verify()

The verify() function allows you to verify a proof generated by the Sismo Vault app with respect to some requests.

function verify(
    bytes memory responseBytes, // required
    AuthRequest memory auth, // optional
    ClaimRequest memory claim, // optional
    SignatureRequest memory signature, // optional
    bytes16 namespace // optional
) public returns (SismoConnectVerifiedResult memory)

The function can take these 5 arguments:

  • responseBytes (required): The response sent back by the Data Vault. It contains the appId, the namespace, the version and the proofs corresponding to the requests made in the front end.

The function needs to verify that the proof is cryptographically valid but also that it has been well generated from the requests specified in the front end. To do this, we also need to set up the same requests in the contract:

  • claim: The object that holds all the information needed to request a proof of group membership.

  • auth: The object that holds all the information needed to request a proof of account ownership.

  • signature: It contains the message that the user should sign.

  • namespace: The namespace of the application that the contract uses.

And it returns a SismoConnectVerifiedResult.

responseBytes (required)

The responseBytes is the encoded version of the sismoConnectResponse, the response that the front end receives from the Data Vault app.

Once decoded, here is the type of the SismoConnectResponse:

struct SismoConnectResponse {
    // the app identifier (registered in the Sismo Factory)
    bytes16 appId;
    // the app service from which the proof is requested
    // default: bytes16(keccak256("main"))
    bytes16 namespace;
    // the version of the Data Vault app
    // default: "sismo-connect-v2"
    bytes32 version;
    // A message provided by the user and signed with the vault.
    bytes signedMessage;
    // the array of Sismo Connect proofs generated
    // only one proof is generated for now)
    SismoConnectProof[] proofs;
}

proofs[] : The array that contains all the sismoConnectProofs the front end provides to the contract. A sismoConnectProof contains several objects:

struct SismoConnectProof {
  Claim[] claims;
  Auth[] auths;
  bytes32 provingScheme;
  bytes proofData;
  bytes extraData;
}

claim : The data requested to generate a group membership proof for a specific value.

struct Claim {
  ClaimType claimType; // default: GTE
  // the group identifier used to check
  // if the user is eligible in order to generate the zero-knowledge proof.
  bytes16 groupId;
  // the timestamp of the group snapshot for which the user had to be eligible to
  // in order to generate the zero-knowledge proof.
  bytes16 groupTimestamp;
  // Make the value the user wants to use to prove membership selectable
  // e.g. value is 1, the user has a value of 3, he can choose to prove the value 2
  bool isSelectableByUser;
  // A group is a mapping of account and value pairs.
  // Limit eligibility to users in the group with a specified value.
  uint256 value;
  bytes extraData;
}

enum ClaimType {
  GTE,
  GT,
  EQ,
  LT,
  LTE
}

auth : The data requested to generate a proof of account ownership

struct Auth {
  AuthType authType; // default: VAULT
  // (soon™) Does not reveal the userId with which the user performs the auth
  bool isAnon; // false
  // Make the account whose ownership the user wants to prove selectable
  bool isSelectableByUser;
  // The id of the account
  // e.g. if the authType is TWITTER, the userId will be your twitterId.
  uint256 userId;
  bytes extraData;
}

enum AuthType {
  VAULT,
  GITHUB,
  TWITTER,
  EVM_ACCOUNT
}

provingScheme : The proving scheme that the Data Vault app uses to generate and verify the proof.

proofData : The proof's content.

extraData : other data that can be used in the future by other proving schemes. Currently not used in the current proving scheme use: the Hydra-S2.

The next objects are the references that allow the verify() function to ensure that the proof sent by the user matches the proof expected by the contract:

claimRequest (optional)

The data requested to generate a group membership proof for a specific value.

struct ClaimRequest {
  ClaimType claimType; // default: GTE
  bytes16 groupId;
  bytes16 groupTimestamp; // default: bytes16("latest")
  uint256 value; // default: 1
  // flags
  bool isOptional; // default: false 
  bool isSelectableByUser; // default: true
  bytes extraData; // default: ""
}

enum ClaimType {
  GTE,
  GT,
  EQ,
  LT,
  LTE,
}

// Example: Build your Sismo Contributor level 2 claim
Claim memory myExampleClaim = buildClaim({
    groupId: 0xe9ed316946d3d98dfcd829a53ec9822e,
    value: 2
})

authRequest (optional)

The data requested to generate a proof of account ownership.

struct AuthRequest {
  AuthType authType;
  uint256 userId; // default: 0
  // flags
  bool isAnon; // default: false -> true not supported yet
  bool isOptional; // default: false
  bool isSelectableByUser; // default: true
  bytes extraData; // default: ""
}

enum AuthType {
  VAULT,
  GITHUB,
  TWITTER,
  EVM_ACCOUNT
}

// Example: Build your Twitter auth
Auth memory myExampleAuth = buildAuth({
    authType: authType.TWITTER
})

signatureRequest (optional)

A message provided by the user and signed with the Vault.

// Example of a signedMessage
struct SignatureRequest {
  bytes message; // default: "MESSAGE_SELECTED_BY_USER"
  bool isSelectableByUser; // default: false
  bytes extraData; // default: ""
}

// Example: Build your signed message
signature: buildSignature({message: message})

namespace (optional)

By default set to “main”. You can optionally define a namespace on top of the appId to use the sismoConnect flow in different parts of your application. You can see an example of two different namespaces used at the end of the sismoConnect server documentation.

SismoConnectVerifiedResult

The SismoConnectVerifiedResult is the object returned by the verify() function if the proofs are valid. It contains all the verifications processed, that is:

  • The claim: verifiedClaims

  • The auth: verifiedAuths

  • The signed message signedMessages

struct SismoConnectVerifiedResult {
  bytes16 appId;
  bytes16 namespace;
  bytes32 version;
  VerifiedAuth[] auths;
  VerifiedClaim[] claims;
  bytes signedMessage; 
}

struct VerifiedAuth {
  AuthType authType;
  bool isAnon; // false
  // Contains an id regarding the requested auth 
  // that can be used to identify the user
  // It may be a vaultId, a githubId or a twitterId
  uint256 userId;
  bytes extraData;
  bytes proofData;
}

struct VerifiedClaim {
  ClaimType claimType;
  bytes16 groupId;
  bytes16 groupTimestamp;
  uint256 value;
  bytes extraData;
  // the identifier of the proof, unique for each different namespace
  uint256 proofId;
  bytes proofData;
}

Last updated