I was wondering if it is possible to perform key switching (reencrypt) on a euint32 value passed as an argument to contract view function?
I was able to get a similar bit of code working as expected, by calling a view function from the contract that stores the encrypted value as follows:
Storage.sol:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;
import "fhevm/lib/TFHE.sol";
contract Storage {
euint32 internal superSecretValue;
constructor() {}
function setSuperSecretValue(bytes memory v_) public returns (bool) {
euint32 value_ = TFHE.asEuint32(v_);
superSecretValue = value_;
return true;
}
function getSuperSecretValue() public view returns (euint32) {
return superSecretValue;
}
}
KeySwitcher.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;
import "fhevm/lib/TFHE.sol";
import "./Storage.sol";
contract KeySwitcher {
constructor() {}
function switchKeys(
address s_,
euint32 value_,
bytes32 publicKey_
)
public
view
returns (bytes memory)
{
return TFHE.reencrypt(Storage(s_).getSuperSecretValue(), publicKey_, 0);
}
}
However, when I alter the KeySwitcher contract as follows the reencrypt reverts without an error string:
FaultyKeySwitcher.sol:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;
import "fhevm/lib/TFHE.sol";
contract FaultyKeySwitcher {
constructor() {}
function switchKeys(
euint32 value_,
bytes32 publicKey_
)
public
view
returns (bytes memory)
{
return TFHE.reencrypt(value_, publicKey_, 0);
}
}
Note that switchKeys is called from off-chain using the following script:
script.ts:
async function getNetworkPublicKey(): Promise<string> {
const provider = ethers.provider
// Calls the fallback function of the contract at the given address
const publicKey = await provider.call({
to: '0x0000000000000000000000000000000000000044'
})
return publicKey
}
async function createInstance(): Promise<FhevmInstance> {
const provider = ethers.provider
const network = await provider.getNetwork()
const chainId = network.chainId
const instance = await fhevmjs.createInstance({
chainId: Number(chainId),
publicKey: await getNetworkPublicKey()
})
return instance
}
async function setTokenSignature(instance: FhevmInstance, contractAddress: string, signer: Signer): Promise<void> {
const token = instance.generateToken({
verifyingContract: contractAddress
})
const signature = await signer.signTypedData(
token.token.domain,
{ Reencrypt: token.token.types.Reencrypt },
token.token.message
)
instance.setTokenSignature(contractAddress, signature)
return
}
const encryptedValue = await storage.getSuperSecretValue()
const signer = (await ethers.getSigners())[0]
const instance = await createInstance() // Custom function for creating the instance
await setTokenSignature(instance, faultyKeySwitcher.target.toString(), signer) // Custom function for setting token signature
const token = instance.getTokenSignature(faultyKeySwitcher.target.toString())
const switchedValue = await faultyKeySwitcher.switchKeys(encryptedValue, token.publicKey) // Reverts!