Skip to main content

Access control

Access control ensures that only the appropriate parties can decrypt ciphertext data (i.e. can access the underlying plaintext data).

Our smart contract library enables developers to request access control changes on ciphertexts stored in SPF. This includes granting run permissions (to allow an entity to run FHE programs using the ciphertext as input) and decryption permissions (to allow an entity to decrypt the ciphertext), as well as other advanced access control changes.

Preparation of access change items

ACL changes happen in two steps. First, you specify the access changes you want to apply to a certain ciphertext. Then, you request the access change to be applied to the ciphertext. Here we cover the first step.

Creating a run permission

The following access change allows an entity to request execution of a certain FHE program using the ciphertext as its input.

function prepareContractRunAccess(address contractAddress, SpfLibrary lib, SpfProgram prog) returns (SpfAccessChange memory)

This is for the case where the entity is a contract address on the current chain. It will require you to provide a “program library / program entry point” combination to limit the run access to a certain FHE program.

Creating a decrypt permission

This access change allows an entity to request decryption of the ciphertext. It comes in two variants: one for allowing a contract to decrypt a value

function prepareContractDecryptAccess(address contractAddress) returns (SpfAccessChange memory)

and one for allowing a end user (wallet) to decrypt a value.

function prepareSignerDecryptAccess(address signerAddress) returns (SpfAccessChange memory)

Request an access change

After you have prepared all access changes, it’s time to request the access change.

function requestAclAsContract(SpfParameter ciphertext, SpfAccessChange[] memory changes) returns (SpfParameter)

This function takes two arguments:

  • ciphertext is the FHE program run parameter created from a single ciphertext that you want to change access on
  • changes is the access changes to be applied to the ciphertext

Obtain access confirmation

Before submitting on-chain transactions, verify access permissions off-chain and obtain a cryptographic signature from SPF using the spf-client access check command.

Access types: admin, decrypt, run

Common parameters:

  • --ciphertext-id: The ciphertext identifier
  • --address: The address to check access for
  • --chain: Chain identifier (required: monad, sepolia, or localhost)
  • --json: Output full JSON response instead of just signature bytes

Additional parameters for run access:

  • --library: Library identifier (program hash)
  • --entry-point: Program entry point name

Example:

# Check run access and get signature
spf-client access check run \
--ciphertext-id $CIPHERTEXT_ID \
--address $CONTRACT_ADDRESS \
--library $LIBRARY_ID \
--entry-point tally_votes \
--chain monad

The signature returned can be used with the verification functions described in the Verify ciphertext access section below.

Verify ciphertext access

Some applications may require verifying a ciphertext could be used for running a program (i.e., using the ciphertext won’t cause the program to fail because of missing access control conditions or mismatched bit width) or decryption. This can be solved by using the ciphertext access signature.

One can request SPF to confirm that a certain ciphertext has a certain access change. If true, SPF will sign some message that encodes this confirmation using the private key. The message format is public and anyone can construct it. The address corresponding to the SPF private key is also public, allowing a contract to use ecrecover for verification.

The “confirmation” of the ciphertext access is obtained off-chain using the check access functionality provided by the client. To verify the signature in a contract, we provided a series of functions for different access items — all of them will need a data structure of type SpfParameterSignature which you can obtain from the signature bytes using this helper function:

function createSignatureStruct(bytes memory sig) returns (SpfParameterSignature memory)

Verifying run access

To verify that a ciphertext has run permission for a certain FHE program in the current contract, use the following function:

function verifyCiphertextRunnable(
SpfParameter memory parameter,
uint8 bitWidth,
SpfParameterSignature memory sig,
SpfLibrary spfLibrary,
SpfProgram spfProgram
)

Verifying decrypt access

To verify that a ciphertext has decrypt permission in the current contract, use the following function:

function verifyCiphertextDecryptable(
SpfParameter memory parameter,
uint8 bitWidth,
SpfParameterSignature memory sig
)

Advanced access control changes

There are other less common access control changes and verification functions that may be useful in some scenarios.

Admin permissions

This access item adds an entity as the admin (owner) of the ciphertext. Admins have the ability to run programs using the ciphertext as input, decrypt the ciphertext, and manage access control on the ciphertext to other entities. As such, admin access is quite powerful and should be used with care.

There are two functions to create this access change: to add a contract as admin

function prepareContractAdminAccess(address contractAddress) returns (SpfAccessChange memory)

and to add a signer as admin.

function prepareSignerAdminAccess(address signerAddress) returns (SpfAccessChange memory)

Verifying admin access

To verify the admin on a ciphertext, the function to use is

function verifyCiphertextOwnedBySigner(
SpfParameter memory parameter,
uint8 bitWidth,
SpfParameterSignature memory sig,
address signerAddress
)

or

function verifyCiphertextOwnedByContract(
SpfParameter memory parameter,
uint8 bitWidth,
SpfParameterSignature memory sig,
address contractAddress
)

or

function verifyCiphertextOwned(
SpfParameter memory parameter,
uint8 bitWidth,
SpfParameterSignature memory sig,
)

They look pretty similar; the differences are the first uses signer address, the second uses the provided contract address, while the last uses current contract.

Less common run permissions

The following access item allows an entity to request execution of a certain FHE program using the ciphertext as its input. The function you use is

function prepareSignerRunAccess(address signerAddress, SpfLibrary lib, SpfProgram prog) returns (SpfAccessChange memory)

This is for the case where the entity is a signer address. It will require you to provide a “program library / program entry point” combination to limit the run access to a certain FHE program.

Less common verifications

Some additional verification options (that are less likely to be used) are included below.

Run access verification

We can verify that some contract (potentially not the current contract) has run access on a ciphertext using the following function.

function verifyCiphertextRunnableByContract(
SpfParameter memory parameter,
uint8 bitWidth,
SpfParameterSignature memory sig,
address contractAddress,
SpfLibrary spfLibrary,
SpfProgram spfProgram
)

Decrypt access verification

The first option uses the signer address while the second option uses the contract address on the current chain

function verifyCiphertextDecryptableBySigner(
SpfParameter memory parameter,
uint8 bitWidth,
SpfParameterSignature memory sig,
address signerAddress
)

or

function verifyCiphertextDecryptableByContract(
SpfParameter memory parameter,
uint8 bitWidth,
SpfParameterSignature memory sig,
address contractAddress
)