Skip to content

Commit

Permalink
Use separate parameters for encrypted values for receiver vs. authority
Browse files Browse the repository at this point in the history
Signed-off-by: Jim Zhang <jim.zhang@kaleido.io>
  • Loading branch information
jimthematrix committed Aug 15, 2024
1 parent 23aa921 commit dc0f729
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 27 deletions.
68 changes: 44 additions & 24 deletions solidity/contracts/zeto_anon_enc_nullifier_non_repudiation.sol
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@ contract Zeto_AnonEncNullifierNonRepudiation is
ZetoNullifier,
ZetoFungibleWithdrawWithNullifiers
{
event UTXOTransferNonRepudiation(
uint256[] inputs,
uint256[] outputs,
uint256 encryptionNonce,
uint256[] encryptedValuesForReceiver,
uint256[] encryptedValuesForAuthority,
address indexed submitter
);

Groth16Verifier_AnonEncNullifierNonRepudiation verifier;
// the authority public key that must be used to
// encrypt the secrets of every transaction
Expand Down Expand Up @@ -70,17 +79,21 @@ contract Zeto_AnonEncNullifierNonRepudiation is
* @param nullifiers Array of nullifiers that are secretly bound to UTXOs to be spent by the transaction.
* @param outputs Array of new UTXOs to generate, for future transactions to spend.
* @param root The root hash of the Sparse Merkle Tree that contains the nullifiers.
* @param encryptionNonce The nonce used to derive the shared secret for encryption by the receiver.
* @param encryptedValuesForReceiver Array of encrypted values, salts and public keys for the receiver UTXO
* @param encryptedValuesForAuthority Array of encrypted values, salts and public keys for the input UTXOs and output UTXOs.
* @param proof A zero knowledge proof that the submitter is authorized to spend the inputs, and
* that the outputs are valid in terms of obeying mass conservation rules.
*
* Emits a {UTXOTransferWithEncryptedValues} event.
* Emits a {UTXOTransferNonRepudiation} event.
*/
function transfer(
uint256[2] memory nullifiers,
uint256[2] memory outputs,
uint256 root,
uint256 encryptionNonce,
uint256[16] memory encryptedValues,
uint256[2] memory encryptedValuesForReceiver,
uint256[14] memory encryptedValuesForAuthority,
Commonlib.Proof calldata proof
) public returns (bool) {
require(
Expand All @@ -90,22 +103,22 @@ contract Zeto_AnonEncNullifierNonRepudiation is

// construct the public inputs
uint256[26] memory publicInputs;
publicInputs[0] = encryptedValues[0]; // encrypted value for the receiver UTXO
publicInputs[1] = encryptedValues[1]; // encrypted salt for the receiver UTXO
publicInputs[2] = encryptedValues[2]; // encrypted input owner public key[0]
publicInputs[3] = encryptedValues[3]; // encrypted input owner public key[1]
publicInputs[4] = encryptedValues[4]; // encrypted input value[0]
publicInputs[5] = encryptedValues[5]; // encrypted input salt[0]
publicInputs[6] = encryptedValues[6]; // encrypted input value[1]
publicInputs[7] = encryptedValues[7]; // encrypted input salt[1]
publicInputs[8] = encryptedValues[8]; // encrypted first output owner public key[0]
publicInputs[9] = encryptedValues[9]; // encrypted first output owner public key[1]
publicInputs[10] = encryptedValues[10]; // encrypted second output owner public key[0]
publicInputs[11] = encryptedValues[11]; // encrypted second output owner public key[1]
publicInputs[12] = encryptedValues[12]; // encrypted output value[0]
publicInputs[13] = encryptedValues[13]; // encrypted output salt[0]
publicInputs[14] = encryptedValues[14]; // encrypted output value[1]
publicInputs[15] = encryptedValues[15]; // encrypted output salt[1]
publicInputs[0] = encryptedValuesForReceiver[0]; // encrypted value for the receiver UTXO
publicInputs[1] = encryptedValuesForReceiver[1]; // encrypted salt for the receiver UTXO
publicInputs[2] = encryptedValuesForAuthority[0]; // encrypted input owner public key[0]
publicInputs[3] = encryptedValuesForAuthority[1]; // encrypted input owner public key[1]
publicInputs[4] = encryptedValuesForAuthority[2]; // encrypted input value[0]
publicInputs[5] = encryptedValuesForAuthority[3]; // encrypted input salt[0]
publicInputs[6] = encryptedValuesForAuthority[4]; // encrypted input value[1]
publicInputs[7] = encryptedValuesForAuthority[5]; // encrypted input salt[1]
publicInputs[8] = encryptedValuesForAuthority[6]; // encrypted first output owner public key[0]
publicInputs[9] = encryptedValuesForAuthority[7]; // encrypted first output owner public key[1]
publicInputs[10] = encryptedValuesForAuthority[8]; // encrypted second output owner public key[0]
publicInputs[11] = encryptedValuesForAuthority[9]; // encrypted second output owner public key[1]
publicInputs[12] = encryptedValuesForAuthority[10]; // encrypted output value[0]
publicInputs[13] = encryptedValuesForAuthority[11]; // encrypted output salt[0]
publicInputs[14] = encryptedValuesForAuthority[12]; // encrypted output value[1]
publicInputs[15] = encryptedValuesForAuthority[13]; // encrypted output salt[1]
publicInputs[16] = nullifiers[0];
publicInputs[17] = nullifiers[1];
publicInputs[18] = root;
Expand All @@ -128,22 +141,29 @@ contract Zeto_AnonEncNullifierNonRepudiation is

uint256[] memory nullifierArray = new uint256[](nullifiers.length);
uint256[] memory outputArray = new uint256[](outputs.length);
uint256[] memory encryptedValuesArray = new uint256[](
encryptedValues.length
uint256[] memory encryptedValuesReceiverArray = new uint256[](
encryptedValuesForReceiver.length
);
uint256[] memory encryptedValuesAuthorityArray = new uint256[](
encryptedValuesForAuthority.length
);
for (uint256 i = 0; i < nullifiers.length; ++i) {
nullifierArray[i] = nullifiers[i];
outputArray[i] = outputs[i];
}
for (uint256 i = 0; i < encryptedValues.length; ++i) {
encryptedValuesArray[i] = encryptedValues[i];
for (uint256 i = 0; i < encryptedValuesForReceiver.length; ++i) {
encryptedValuesReceiverArray[i] = encryptedValuesForReceiver[i];
}
for (uint256 i = 0; i < encryptedValuesForAuthority.length; ++i) {
encryptedValuesAuthorityArray[i] = encryptedValuesForAuthority[i];
}

emit UTXOTransferWithEncryptedValues(
emit UTXOTransferNonRepudiation(
nullifierArray,
outputArray,
encryptionNonce,
encryptedValuesArray,
encryptedValuesReceiverArray,
encryptedValuesAuthorityArray,
msg.sender
);
return true;
Expand Down
10 changes: 10 additions & 0 deletions solidity/test/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,16 @@ export function parseUTXOEvents(zetoTokenContract: any, result: ContractTransact
submitter: event?.args.submitter
};
returnValues.push(transfer);
} else if (event?.name === 'UTXOTransferNonRepudiation') {
const transfer = {
inputs: event?.args.inputs,
outputs: event?.args.outputs,
encryptedValuesForReceiver: event?.args.encryptedValuesForReceiver,
encryptedValuesForAuthority: event?.args.encryptedValuesForAuthority,
encryptionNonce: event?.args.encryptionNonce,
submitter: event?.args.submitter
};
returnValues.push(transfer);
} else if (event?.name === 'UTXOMint') {
const mint = {
outputs: event?.args.outputs,
Expand Down
8 changes: 5 additions & 3 deletions solidity/test/zeto_anon_enc_nullifier_non_repudiation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,15 +148,15 @@ describe("Zeto based fungible token with anonymity using nullifiers and encrypti

// Bob uses the encrypted values in the event to decrypt and recover the UTXO value and salt
const sharedKey1 = genEcdhSharedKey(Bob.babyJubPrivateKey, Alice.babyJubPublicKey);
const plainText1 = poseidonDecrypt(events[0].encryptedValues.slice(0, 2), sharedKey1, events[0].encryptionNonce);
const plainText1 = poseidonDecrypt(events[0].encryptedValuesForReceiver, sharedKey1, events[0].encryptionNonce);
expect(plainText1).to.deep.equal([
25n,
result2.plainTextSalt,
]);

// The regulator uses the encrypted values in the event to decrypt and recover the UTXO value and salt
const sharedKey2 = genEcdhSharedKey(Authority.babyJubPrivateKey, Alice.babyJubPublicKey);
const plainText2 = poseidonDecrypt(events[0].encryptedValues.slice(2, 16), sharedKey2, events[0].encryptionNonce);
const plainText2 = poseidonDecrypt(events[0].encryptedValuesForAuthority, sharedKey2, events[0].encryptionNonce);
expect(plainText2).to.deep.equal([
Alice.babyJubPublicKey[0],
Alice.babyJubPublicKey[1],
Expand Down Expand Up @@ -399,7 +399,9 @@ describe("Zeto based fungible token with anonymity using nullifiers and encrypti
encodedProof: any
) {
const startTx = Date.now();
const tx = await zeto.connect(signer.signer).transfer(nullifiers, outputCommitments, root, encryptionNonce, encryptedValues, encodedProof);
const encryptedValuesForReceiver = encryptedValues.slice(0, 2);
const encryptedValuesForRegulator = encryptedValues.slice(2, 16);
const tx = await zeto.connect(signer.signer).transfer(nullifiers, outputCommitments, root, encryptionNonce, encryptedValuesForReceiver, encryptedValuesForRegulator, encodedProof);
const results: ContractTransactionReceipt | null = await tx.wait();
console.log(`Time to execute transaction: ${Date.now() - startTx}ms. Gas used: ${results?.gasUsed}`);
return results;
Expand Down

0 comments on commit dc0f729

Please sign in to comment.