2

I want to verify an aggregate bn254 signature. Now lets say that I am aggregating 3 identical signatures which results in a new signature. So now if I give 3 identical public keys and 3 identical messages to the verifyMultiple function then will the gas cost of this be different from a scenario where all the public keys, messages and signatures are unique?

I am using this script to verify: https://github.com/thehubbleproject/hubble-contracts/blob/master/contracts/libs/BLS.sol

1 Answer 1

1
+50

No.

At the end of the day, you are passing values to the ecPairing precompiled contract at address 0x8 (see this static call) to be evaluated, and it does not care if those values correspond to identical public keys and messages or not.

The cost of executing that precompile is in fact dependent on the bytes size of the data, with a minimum of 45000 gas cost.

So, technically, the gas cost of verifying an aggregate signature with identical or unique public keys and messages in the verifyMultiple function can slightly vary due to differences in computation complexity, but the difference might not be significant and it's not related to the fact they are identical but to their actual byte size.

Below, you can see a couple of examples.

I copied the first example from evm.codes playground, and using Remix it costs 113661 gas for execution.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

contract PairingExample {
    function run() public returns (uint) {
        uint256[12] memory input;
        //(G1)x
        input[0] = uint256(0x2cf44499d5d27bb186308b7af7af02ac5bc9eeb6a3d147c186b21fb1b76e18da);
        //(G1)y
        input[1] = uint256(0x2c0f001f52110ccfe69108924926e45f0b0c868df0e7bde1fe16d3242dc715f6);
        //(G2)x_1
        input[2] = uint256(0x1fb19bb476f6b9e44e2a32234da8212f61cd63919354bc06aef31e3cfaff3ebc); 
        //(G2)x_0
        input[3] = uint256(0x22606845ff186793914e03e21df544c34ffe2f2f3504de8a79d9159eca2d98d9); 
        //(G2)y_1
        input[4] = uint256(0x2bd368e28381e8eccb5fa81fc26cf3f048eea9abfdd85d7ed3ab3698d63e4f90); 
        //(G2)y_0
        input[5] = uint256(0x2fe02e47887507adf0ff1743cbac6ba291e66f59be6bd763950bb16041a0a85e); 
        //(G1)x
        input[6] = uint256(0x0000000000000000000000000000000000000000000000000000000000000001); 
        //(G1)y
        input[7] = uint256(0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd45); 
        //(G2)x_1
        input[8] = uint256(0x1971ff0471b09fa93caaf13cbf443c1aede09cc4328f5a62aad45f40ec133eb4); 
        //(G2)x_0
        input[9] = uint256(0x091058a3141822985733cbdddfed0fd8d6c104e9e9eff40bf5abfef9ab163bc7); 
        //(G2)y_1
        input[10] = uint256(0x2a23af9a5ce2ba2796c1f4e453a370eb0af8c212d9dc9acd8fc02c2e907baea2);    
        //(G2)y_0
        input[11] = uint256(0x23a8eb0b0996252cb548a4487da97b02422ebc0e834613f954de6c7e0afdc1fc);
        //multiplies the pairings and stores a 1 in the first element of input
        assembly {
            if iszero(
                call(not(0), 0x08, 0, input, 0x0180, input, 0x20)
            ) {
                revert(0, 0)
            }
        }
        return input[0];
    }
}

In this second example, I modified the code to use two identical keys and messages, and it costs 113712 gas, slightly more than the first one. That is probably due to many zeros in the first examples, so when handling that code, the overall execution is slightly less costly.

But the cost of calling the ecPairing contract does not change.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

contract PairingExample {
    function run() public returns (uint) {
        uint256[12] memory input;
        //(G1)x
        input[0] = uint256(0x2cf44499d5d27bb186308b7af7af02ac5bc9eeb6a3d147c186b21fb1b76e18da);
        //(G1)y
        input[1] = uint256(0x2c0f001f52110ccfe69108924926e45f0b0c868df0e7bde1fe16d3242dc715f6);
        //(G2)x_1
        input[2] = uint256(0x1fb19bb476f6b9e44e2a32234da8212f61cd63919354bc06aef31e3cfaff3ebc); 
        //(G2)x_0
        input[3] = uint256(0x22606845ff186793914e03e21df544c34ffe2f2f3504de8a79d9159eca2d98d9); 
        //(G2)y_1
        input[4] = uint256(0x2bd368e28381e8eccb5fa81fc26cf3f048eea9abfdd85d7ed3ab3698d63e4f90); 
        //(G2)y_0
        input[5] = uint256(0x2fe02e47887507adf0ff1743cbac6ba291e66f59be6bd763950bb16041a0a85e); 
        //(G1)x
        input[6] = uint256(0x2cf44499d5d27bb186308b7af7af02ac5bc9eeb6a3d147c186b21fb1b76e18da); 
        //(G1)y
        input[7] = uint256(0x2c0f001f52110ccfe69108924926e45f0b0c868df0e7bde1fe16d3242dc715f6); 
        //(G2)x_1
        input[8] = uint256(0x1fb19bb476f6b9e44e2a32234da8212f61cd63919354bc06aef31e3cfaff3ebc); 
        //(G2)x_0
        input[9] = uint256(0x22606845ff186793914e03e21df544c34ffe2f2f3504de8a79d9159eca2d98d9); 
        //(G2)y_1
        input[10] = uint256(0x2bd368e28381e8eccb5fa81fc26cf3f048eea9abfdd85d7ed3ab3698d63e4f90);    
        //(G2)y_0
        input[11] = uint256(0x2fe02e47887507adf0ff1743cbac6ba291e66f59be6bd763950bb16041a0a85e);
        //multiplies the pairings and stores a 1 in the first element of input
        assembly {
            if iszero(
                call(not(0), 0x08, 0, input, 0x0180, input, 0x20)
            ) {
                revert(0, 0)
            }
        }
        return input[0];
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.