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:
ciphertextis the FHE program run parameter created from a single ciphertext that you want to change access onchangesis 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, orlocalhost)--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
)