Aliasing Attack
Last updated
Last updated
Some ZKP privacy applications need to prevent double spending by nullifier, which is bound within a valid proof in a ZK way so that it can be examined in the Verifier and marked as "used" after a corresponding action is completed to avoid double spending.
But this can be bypassed by the arithmetic features of cyclic groups if the implementation is wrong.
Here are some examples:
https://github.com/semaphore-protocol/semaphore/issues/16
https://github.com/eea-oasis/baseline/issues/34
https://github.com/semaphore-protocol/semaphore/pull/96/
To reduce gas required by some ZKP schemes, Ethereum defined two precompile contracts for addition and multiplication operations of the elliptic curve alt_bn128 in EIP-196.
Curve alt_bn128 is defined as:
In the finite field F_p
, there is a cyclic subgroup of order q
based on generator P1(1,2)
:
In that cyclic subgroup, there is
Namely, we can regard q
as zero in the finite field operation, adding any multiples of q
to the same point always return itself.
Since we usually use uint256
in related calculations, which has a maximum M
, there exist N
aliases for a given input argument A
:
That is to say, if A
is the nullifier, you can construct at most N
aliases, they are different natural numbers but will output identical results in the cyclic group. Hence, the double spending proof is invalid here, even can be abused to triple or quadruple spending.
This kind of attack was first revealed in the privacy layer project Semaphore, and its course can be traced back to 2017 when Christian Reitwiessner wrote such an unsafe example for implementation. Unfortunately many zkSNARKS libs like snarkjs
and ethsnarks
followed this example.
The solution is simple. Just restrict the inputs should be less than q
(snark_scalar_field
).