Commit ce39a68a authored by XFT-dev's avatar XFT-dev
Browse files

initializing repo

parent 8605a110
# protocol-main
offshift code + docs
\ No newline at end of file
# Confidential contracts ingredients
##
## 1. Homomorphic encryption
**Intro:**
Properties of the homomorphic encryption:
- The complexity of obtaining the original data from the ciphertext:
E(x) -> x.
- Changing the original data changes the outputs of the function:
If x != y ⇒ E(x) != E(y)
- With several known values of encrypted data, an arithmetic operation can be performed between them:
- If E(x) and E(y) are known, we can receive E(func(x + y)) without disclosure.
**Protocol:**
1. g - public generator;
2. Evaluation: E(x) = gx nod n;
3. E(x + y) = gx \* gy = E(x) \* E(y)
4. E(ax + by) = gax \* gby = E(x)a \* E(y)b
**Example:**
Consider an example that illustrates this approach. For example, Alice wants to prove to Bob that she knows two numbers, the sum of which will be 15. Take the values of the secrets x = 13 and y = 2. The parties jointly determine the modulus n = 17 and the base point value g = 3 (as the encryption algorithm we will use RSA). To prove to Bob that she knows these secrets, she blinds them and gets two meanings, which she gives to Bob:
E(x) = gx mod n=313 mod 17= 12mod 17,
E(y) = gy mod n=32mod 17=9 mod 17.
Bob, in turn, needs to make sure that the sum of the secrets is indeed equal to 15. To do this, he "adds" both values received from Alice as follows:
E(x + y) = gx+y mod n=gxgy mod n= 129 mod 17=6 mod 17.
Following this, he independently encrypts the known result 15 and compares the obtained values:
E(15) =g15 mod n=315 mod 17=6 mod 17=> E(x + y) = E(15).
Since the results are the same, Alice can prove to Bob that she knows two numbers that add up to 15, while not divulging these numbers, but only transmitting them in an encrypted (blinded) form. Therefore, the properties we noted earlier are fully secured.
##
## 2. Blind Evaluation of Polynomials
**Intro:**
The polynomial is represented as follows:
F(x)=a0+a1x + a2x2+...+an-1xn-1, where
x – variable, a – constant coefficients. We can evaluate a polynomial in terms of a specific value of s:
F(s)=a0+a1s + a2s2+...+an-1sn-1
Accordingly, the party who knows the coefficients of the polynomial can evaluate it at any point.
**Protocol** :
1. Bob sends to Alice E(1), E(s), …, E(sd);
2. Alice computes and returns E(P(s)).
**Example:**
So, suppose Bob knows a particular polynomial and wants to make sure that its coefficients are also known to Alice (who doesn't want to divulge them). To do this, he wants to get a blinded value E(P(x)) from Alice. If it weren't for zero knowledge proofs, Bob could have passed x to Alice and got P(x). However, what if Bob doesn't want to pass on the secret to Alice?
For this, homomorphic encryption, which we discussed earlier, can be used. Bob initially forms E(P(x)) and "memorizes" it in order to compare it with the value received from Alice. After that, he forms a set of blinded values of the polynomial components and passes them to Alice:
E(1), E(x), E(x2),...,E(xn-1).
Note that if at this stage Alice knows the coefficients of the polynomial, then she can provide the correct value for E(P(x)). How does this happen? We discussed earlier how the blinded value is multiplied by a scalar. Also, in this case, Alice can multiply the blinded values received from Bob by the coefficients she knows. As a result, it will receive the following value:
E(P(x)) =E(1)a0E(x)a1E(x2)a2...E(xn-1)an-1.
The resulting blinded value is passed to Bob and compared with the previously calculated one. If the values match, then Bob is guaranteed to make sure that Alice knows the coefficients of the polynomial (except for a very low probability). At the same time, everyone fulfills the properties of zero-knowledge proofs: Alice does not learn the secret from Bob, does not divulge the values of the coefficients to Bob, but convinces him that she knows these values.
## 3. Knowledge of the Coefficient
**Intro:**
In the example above, Alice does not have to send Bob the correct estimate of the polynomial - she can send him fake data (we are based on the assumption that Bob cannot estimate the polynomial on his own and check the result).
**Protocol:**
KC test proceeds as follows:
1. Bob chooses random α and a ∈ G snf computes b = αa.
2. Bob sends "challenge" α-pair (a, b). Alice can't receive the α value.
3. Alice sends different α-pair (a', b'). How she can successfully respond to the challenge without knowingα:
1. Alice chooses some γ and responds via (a', b') = (γa, γb). Alice knows the ration between a and a'.
4. If (a', b') is valid α-pair Bob accepts Alice's response.
**Example:**
For example, Bob generates a random value a = 3 and α = 7. He calculates b = αa = 3 \* 7 = 21. Bob sends to Alice 3 and 21. In this case, it is quite easy to find the value α = 7, however, due to the peculiarities of arithmetic, which we use, this solution is in the field of the solution to the discrete logarithm problem. Alice then chooses the value γ = 13 and calculates:
(a', b') = (γa, γb) = (13 \* 3, 13 \* 21) = (39, 273)
Alice then passes the α-pair to Bob. Bob's check is b'(273)? = αa'(7 \* 39). In this case, Bob can verify that (a', b') are an α-pair.
##
## 4. Verifiable blind evaluation of polynomials
**Intro:**
Now we turn to how the blinding of polynomials occurs so that Bob can verify that he received the correct evaluation from Alice. In this case, 2 properties must be fulfilled:
- Blindness (Alice will not receive the s);
- Verifiability (Alice can not provide fake value instead E(P(s))).
Bob sends several α-pairs (a0, b0),...,(an-1, bn-1). Alice has to return different α-pair (a', b'). (a', b') = (sum(ciai), sum(cibi)), ci are generated by Alice.
**Protocol:**
1. Bob chooses random α and sends to Alice hided values of:
1. 1, s, …, sd: E(1), E(s), …, E(sd);
2. α, αs, …, αsd: E(α), E(αs), …, E(αsd)
2. Alice computes a = E(P(s)) and b = αE(P(s))
3. Bob checks that b = αa.
## 5. Arithmetic circuits
**Intro:**
Everything that was described earlier is the mechanism of operation and calculation with polynomials. Now we need to figure out how to transform some statement (which needs to be proved and verified) into a set of polynomials.
An arithmetic circuit consists of gates computing arithmetic operations like addition and multiplication, with wires connecting the gates.
**Protocol:**
The complex program has to be divided to minimal atomic operations in following form:
a = b (op) c
**Example:**
x2-x-6=0
Can be transformed to the program:
![](assets/image5.png)
That has to be divided to operations:
![](assets/image12.png)
## 6. R1CS
**Intro:**
Now we can convert the received states (simplified version of the code) to R1CS. To do this, first we need to form a state vector, which contains all the variables of the simplified program and the value 1 (to represent constant values).
![](assets/image1.png)
**Protocol:**
In fact, R1CS is a list of vector triplets (a, b, c) for which the following condition is satisfied:
<ai · s> <bi · s> - <ci · s> = 0
This equality must be fulfilled for each line of simplified code, that weis, the correspondence of each logical transition to a new state is controlled.
As a result we will receive the set of vectors a, b and c for each state of program like:
![](assets/image7.png)
**Example:**
1.
![](assets/image13.png)
![](assets/image8.png)
2 and 3.
![](assets/image11.png) ![](assets/image10.png)
![](assets/image4.png)
## 7. QAP
**Intro:**
To perform the transition to QAP, it is necessary to transform the set of vectors into a set of polynomials A, B and C. From three groups, each of which contains 3 vectors, we should get 15 polynomials of the third degree. To obtain a polynomial, we need to determine the points through which the graph described by this polynomial passes. Further, using these points and Lagrange interpolation, we get polynomials.
**Protocol:**
When using Lagrange interpolation, the polynomial is calculated as follows:
L(x)=i=0nfi(x)li(x), where li(x)=j=0, jinx - xjxi-xj.
**Example:**
![](assets/image3.png)
Further, based on the obtained values of the points, we transform the vectors into the following set of polynomials:
![](assets/image6.png)
We can check the polynomial&#39;s correctness next way:
![](assets/image14.png)
Transformation into QAP allows us to transform equality into an equality of the following type:
A(x)*B(x)-C(x)=0, where
A(x) = A · s, B(x) = B · s, C(x) = C · s.
This equality will be fulfilled for each transition (x = 1, 2, 3). However, in doing so, we can check the compliance of our witness with this task. If we change the value of witness, for example, instead of [1, 3, 9, 6, 0] we take [1, 3, 10, 6, 0], then the equality for the transitions will not be fulfilled:
![](assets/image2.png)
In this case, we get a lot of term, which must be divisible without a remainder by (x-1)(x-2)(x-3), since 1, 2 and 3 are its roots (the function will take on the value 0). That is, we can quickly check the validity of a polynomial by dividing by said polynomial:
L(x) = (x-1)(x-2)(x-3)\*H(x), where (x-1)(x-2)(x-3) = T(x)
## 8. Pinocchio protocol
**Intro:**
The prover can send the verifier a short proof that she has the required QAP assignment set.
**Protocol:**
1. Alice select A(x), B(x), C(x) and H(x);
2. Bob selects random r and computes E(T(x));
3. Alice sends to Bob E(A(x)), E(B(x)), E(C(x)), E(H(x));
4. Bob checks E(A(x)\*B(x)-C(x)) == E(T(x)\*H(x)).
The protocol above only guarantees that Alice uses some polynomials of the correct order, but does not guarantee that they were created from a valid assignment set. The formal proof is somewhat tricky, so we will give an example solution.
##
## 9. Zcash shielding
Commitment = Hash(recipient address, amount, rho, r):
- rho - unique value used for nullifier derivation;
- R - random nonce.
During shielded transaction spending sender uses spending key
Nullifier = Hash(spending key, rho).
## ![](assets/image9.png)
## 10. Elliptic curve pairing
**Intro:**
I think for now we can omit how it works.
## 11. ZOKRATES Example
**docker run -ti zokrates/zokrates /bin/bash**
**cd home**
**cd zokrates**
**mkdir test**
**touch root.zok**
**cat \&gt; root.zok**
## 11.1 Problem
Lets prove that we know some _ **a** _-value that a^2 == b.
## 11.2 Problem description
def main(private field a, field b) -\&gt; bool: **// program on zokrates language**
return a\*a == b
## 11.3 From problem to arithmetic circuits
**zokrates compile -i root.zok**
Compiled program: **// initial C program (arithmetic circuit)**
def main(\_0, \_1) -\&gt; (1):
(1 \* \_0) \* (1 \* \_0) == 1 \* \_4
# \_2, \_3 = ConditionEq((1 \* ~one) \* ((-1) \* \_1 + 1 \* \_4))
((-1) \* \_1 + 1 \* \_4) \* (1 \* \_3) == 1 \* \_2
(1 \* ~one + (-1) \* \_2) \* ((-1) \* \_1 + 1 \* \_4) == 0
(1 \* ~one) \* (1 \* ~one + (-1) \* \_2) == 1 \* ~out\_0
return ~out\_0
Compiled code written to &#39;out&#39;
Human readable code to &#39;out.ztf&#39;
Number of constraints: 4
**ls**
abi.json out out.ztf root.zok
**cat out //displaying in compiled form**
ZOK????mai???C?p?yH?3(]X???EP?)?1?rNd???C?p?yH?3(]X???EP?)?1?rNd???C?p?yH?3(]X???EP?)?1?rNd???C?p?yH?3(]X???EP?)?1?rNd???C?p?yH?3(]X???EP?)?1?rNd0????????????????
**cat out.ztf**
def main(\_0, \_1) -\&gt; (1):
(1 \* \_0) \* (1 \* \_0) == 1 \* \_4
# \_2, \_3 = ConditionEq((1 \* ~one) \* ((-1) \* \_1 + 1 \* \_4))
((-1) \* \_1 + 1 \* \_4) \* (1 \* \_3) == 1 \* \_2
(1 \* ~one + (-1) \* \_2) \* ((-1) \* \_1 + 1 \* \_4) == 0
(1 \* ~one) \* (1 \* ~one + (-1) \* \_2) == 1 \* ~out\_0
return ~out\_0
**cat abi.json //binary interface**
{
&quot;inputs&quot;: [
{
&quot;name&quot;: &quot;a&quot;,
&quot;public&quot;: false,
&quot;type&quot;: &quot;field&quot;
},
{
&quot;name&quot;: &quot;b&quot;,
&quot;public&quot;: true,
&quot;type&quot;: &quot;field&quot;
}
],
&quot;outputs&quot;: [
{
&quot;type&quot;: &quot;bool&quot;
}
]
## 11.4 Trusted setup (prover and verifier keys generation)
**zokrates setup**
Performing setup...
def main(\_0, \_1) -\&gt; (1):
(1 \* \_0) \* (1 \* \_0) == 1 \* \_4
# \_2, \_3 = ConditionEq((1 \* ~one) \* ((-1) \* \_1 + 1 \* \_4))
((-1) \* \_1 + 1 \* \_4) \* (1 \* \_3) == 1 \* \_2
(1 \* ~one + (-1) \* \_2) \* ((-1) \* \_1 + 1 \* \_4) == 0
(1 \* ~one) \* (1 \* ~one + (-1) \* \_2) == 1 \* ~out\_0
return ~out\_0
WARNING: You are using the G16 scheme which is subject to malleability. See zokrates.github.io/toolbox/proving\_schemes.html#g16-malleability for implications.
| **NOTE**** When using G16, developers should pay attention to the fact that an attacker, seeing a valid proof, can very easily generate a different but still valid proof. Therefore, depending on the use case, making sure on chain that the same proof cannot be submitted twice may not be enough to guarantee that attackers cannot replay proofs. Mechanisms to solve this issue include:**
- **signed proofs**
- **nullifiers**
- **usage of an ethereum address as a public input to the program**
- **usage of non-malleable schemes such as GM17**
|
| --- |
From this reason we will use gm17 prove scheme
**zokrates setup -s gm17 -b ark //GM17 - prove scheme, ARK - backend (for GM17 supporting)**
Performing setup...
def main(\_0, \_1) -\&gt; (1):
(1 \* \_0) \* (1 \* \_0) == 1 \* \_4
# \_2, \_3 = ConditionEq((1 \* ~one) \* ((-1) \* \_1 + 1 \* \_4))
((-1) \* \_1 + 1 \* \_4) \* (1 \* \_3) == 1 \* \_2
(1 \* ~one + (-1) \* \_2) \* ((-1) \* \_1 + 1 \* \_4) == 0
(1 \* ~one) \* (1 \* ~one + (-1) \* \_2) == 1 \* ~out\_0
return ~out\_0
Setup completed.
I recommend not try to understand what is keeped in verifier key)
**cat verification.key**
{
&quot;h&quot;: [
[
&quot;0x21ed25b314584c89fd75fc60b48ae3c5862a6fecb1ce467d6c6de3816fb2b7df&quot;,
&quot;0x3032b7523599019887d7967dc5c5b6db702b89d8af9a7b09bfa6ca8575cdac56&quot;
],
[
&quot;0x17d27e70aca2e4402b4d3c5d0b4fa42fe861ff09e6452cf6a30340d3b831b187&quot;,
&quot;0x173b7f0b011769371695d87258a9794cf5ef6a210025b2ef8d0adc4a19b23af0&quot;
]
],
&quot;g\_alpha&quot;: [
&quot;0x278a9668fe236f39390edf6e1a549f824eaae03635cabefdb4d503f5826513d2&quot;,
&quot;0x0ae043095f676b9ef74237fdaf4d3002403c328d55d1763d3905d2ddf763b55d&quot;
],
&quot;h\_beta&quot;: [
[
&quot;0x02b8284a22bbfa1f969b47f9063b5fc326c9ba46da517ada70a27aafd9a7a592&quot;,
&quot;0x10a859399627a97eefa078cf7120a0917f095ac4b865434fb6fa33472bc3d59d&quot;
],
[
&quot;0x22679a7aedbf02a36bf41265ed6673f3a8a55f4b49966bf325175da5c837e262&quot;,
&quot;0x01b24384861ffee62a56edd0210072ef823b9609df3cbce84f6c146531f5b216&quot;
]
],
&quot;g\_gamma&quot;: [
&quot;0x29c9815e24bcbe89fcdfe9f1b2dc3dbd80b3e3a9d5a49dee883f476ae9aa711f&quot;,
&quot;0x063b306c1e6dfb31a84a1ac01f869f6350ff743a7d64a27a9c266038395018c9&quot;
],
&quot;h\_gamma&quot;: [
[
&quot;0x21ed25b314584c89fd75fc60b48ae3c5862a6fecb1ce467d6c6de3816fb2b7df&quot;,
&quot;0x3032b7523599019887d7967dc5c5b6db702b89d8af9a7b09bfa6ca8575cdac56&quot;
],
[
&quot;0x17d27e70aca2e4402b4d3c5d0b4fa42fe861ff09e6452cf6a30340d3b831b187&quot;,
&quot;0x173b7f0b011769371695d87258a9794cf5ef6a210025b2ef8d0adc4a19b23af0&quot;
]
],
&quot;query&quot;: [
[
&quot;0x12cfe3e37bc89a4ced92c48be1745973a011be6fc0a01afee6fc8100ba40329d&quot;,
&quot;0x0d6ebd5b8ce577577c8ef036f1d737e7be647b948dfdfd7b47707981d1629cd3&quot;
],
[
&quot;0x2347a9ab877444c1b5b5474d572c793f6318f0f25ea0433d22e7b49a7316e004&quot;,
&quot;0x1b1fd6f7178b50033301608a01e55c67bda52546a03d4215a472e1b41a4a59dc&quot;
],
[
&quot;0x03ff7e4173415786c57995ac258ef71181f1905802abf12b80280a6d31f1b426&quot;,
&quot;0x0731ee572bd61e233d0081fc15b34f2e345263e29fed957a11277d6013407d5d&quot;
]
]
## 11.5 Witness computation
**zokrates compute-witness -a 7 5 // 337^2 == 113569**
Computing witness...
def main(\_0, \_1) -\&gt; (1):
(1 \* \_0) \* (1 \* \_0) == 1 \* \_4
# \_2, \_3 = ConditionEq((1 \* ~one) \* ((-1) \* \_1 + 1 \* \_4))
((-1) \* \_1 + 1 \* \_4) \* (1 \* \_3) == 1 \* \_2
(1 \* ~one + (-1) \* \_2) \* ((-1) \* \_1 + 1 \* \_4) == 0
(1 \* ~one) \* (1 \* ~one + (-1) \* \_2) == 1 \* ~out\_0
return ~out\_0
Witness:
[&quot;1&quot;]
**cat witness**
~out\_0 1
~one 1
\_0 337
\_1 113569
\_2 0
\_3 1
\_4 113569
## 11.6 Proofs computation
**zokrates generate-proof -s gm17 -b ark**
Generating proof...
Proof:
{
&quot;proof&quot;: {
&quot;a&quot;: [
&quot;0x1e605fe761bd55b5f1553338e912bf8c5a6f74c67a867ee22ebe1313809a6d6f&quot;,
&quot;0x05c3bbade2ba5783c8dc23fe195dea1c38fed05917aedd2e7535bc3665d027a4&quot;
],
&quot;b&quot;: [
[
&quot;0x304ac962dc4f96c5dd3124264657069b1639ca44e8a4fba64e47b33fc3c76e88&quot;,
&quot;0x2ddddfd5a1c9ea0f92d4568fbfd07495525892217bf7680a4bfbe6019e36991b&quot;
],
[
&quot;0x18cb37a3b678cb3cb80e3d6cec5aa3a72afb581b6a60c6a12b24afe2bb631213&quot;,
&quot;0x11f7855f453796b83d7910c2cacb33c6f4804914e16b90131caa7e88246b55d8&quot;
]
],
&quot;c&quot;: [
&quot;0x199eb31e71ef8a06b5837a2296bc61adfdf95e7f537c6947f4ca43fff2e0c2f8&quot;,
&quot;0x2491f520d3cd4b8cb96fec337ae5ea08ffb567383b5fda22dab0b59b7c82d84d&quot;
]
},
&quot;inputs&quot;: [
&quot;0x000000000000000000000000000000000000000000000000000000000001bba1&quot;,
&quot;0x0000000000000000000000000000000000000000000000000000000000000001&quot;
]
}
## 11.7 Verifier contract generation
**zokrates@543d3d274994:~/test$ zokrates export-verifier -s gm17**
Exporting verifier...
Finished exporting verifier.
**Generated contract**
**pragma solidity ^0.6.1;**
**/\*\***
**\* @title Elliptic curve operations on twist points for alt\_bn128**
**\* @author Mustafa Al-Bassam (mus@musalbas.com)**
**\* @dev Homepage: https://github.com/musalbas/solidity-BN256G2**
**\*/**
**library BN256G2 {**
**uint256 internal constant FIELD\_MODULUS = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47;**
**uint256 internal constant TWISTBX = 0x2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e5;**
**uint256 internal constant TWISTBY = 0x9713b03af0fed4cd2cafadeed8fdf4a74fa084e52d1852e4a2bd0685c315d2;**
**uint internal constant PTXX = 0;**
**uint internal constant PTXY = 1;**
**uint internal constant PTYX = 2;**
**uint internal constant PTYY = 3;**
**uint internal constant PTZX = 4;**
**uint internal constant PTZY = 5;**
**/\*\***
**\* @notice Add two twist points**
**\* @param pt1xx Coefficient 1 of x on point 1**
**\* @param pt1xy Coefficient 2 of x on point 1**
**\* @param pt1yx Coefficient 1 of y on point 1**
**\* @param pt1yy Coefficient 2 of y on point 1**
**\* @param pt2xx Coefficient 1 of x on point 2**
**\* @param pt2xy Coefficient 2 of x on point 2**
**\* @param pt2yx Coefficient 1 of y on point 2**
**\* @param pt2yy Coefficient 2 of y on point 2**
**\* @return (pt3xx, pt3xy, pt3yx, pt3yy)**
**\*/**
**function ECTwistAdd(**
**uint256 pt1xx, uint256 pt1xy,**
**uint256 pt1yx, uint256 pt1yy,**
**uint256 pt2xx, uint256 pt2xy,**
**uint256 pt2yx, uint256 pt2yy**
**) public view returns (**
**uint256, uint256,**
**uint256, uint256**
**) {**
**if (**
**pt1xx == 0 &amp;&amp; pt1xy == 0 &amp;&amp;**
**pt1yx == 0 &amp;&amp; pt1yy == 0**
**) {**
**if (!(**
**pt2xx == 0 &amp;&amp; pt2xy == 0 &amp;&amp;**
**pt2yx == 0 &amp;&amp; pt2yy == 0**
**)) {**
**assert(\_isOnCurve(**
**pt2xx, pt2xy,**
**pt2yx, pt2yy**
**));**
**}**
**return (**
**pt2xx, pt2xy,**
**pt2yx, pt2yy**
**);**
**} else if (**
**pt2xx == 0 &amp;&amp; pt2xy == 0 &amp;&amp;**
**pt2yx == 0 &amp;&amp; pt2yy == 0**
**) {**
**assert(\_isOnCurve(**
**pt1xx, pt1xy,**
**pt1yx, pt1yy**
**));**
**return (**
**pt1xx, pt1xy,**
**pt1yx, pt1yy**
**);**
**}**
**assert(\_isOnCurve(**
**pt1xx, pt1xy,**
**pt1yx, pt1yy**
**));**
**assert(\_isOnCurve(**
**pt2xx, pt2xy,**
**pt2yx, pt2yy**
**));**
**uint256[6] memory pt3 = \_ECTwistAddJacobian(**
**pt1xx, pt1xy,**
**pt1yx, pt1yy,**
**1, 0,**
**pt2xx, pt2xy,**
**pt2yx, pt2yy,**
**1, 0**
**);**
**return \_fromJacobian(**
**pt3[PTXX], pt3[PTXY],**
**pt3[PTYX], pt3[PTYY],**
**pt3[PTZX], pt3[PTZY]**
**);**
**}**
**/\*\***
**\* @notice Multiply a twist point by a scalar**
**\* @param s Scalar to multiply by**
**\* @param pt1xx Coefficient 1 of x**
**\* @param pt1xy Coefficient 2 of x**
**\* @param pt1yx Coefficient 1 of y**
**\* @param pt1yy Coefficient 2 of y**
**\* @return (pt2xx, pt2xy, pt2yx, pt2yy)**
**\*/**
**function ECTwistMul(**
**uint256 s,**
**uint256 pt1xx, uint256 pt1xy,**
**uint256 pt1yx, uint256 pt1yy**
**) public view returns (**
**uint256, uint256,**
**uint256, uint256**
**) {**
**uint256 pt1zx = 1;**
**if (**
**pt1xx == 0 &amp;&amp; pt1xy == 0 &amp;&amp;**
**pt1yx == 0 &amp;&amp; pt1yy == 0**
**) {**
**pt1xx = 1;**
**pt1yx = 1;**
**pt1zx = 0;**
**} else {**
**assert(\_isOnCurve(**
**pt1xx, pt1xy,**
**pt1yx, pt1yy**
**));**
**}**
**uint256[6] memory pt2 = \_ECTwistMulJacobian(**
**s,**
**pt1xx, pt1xy,**
**pt1yx, pt1yy,**
**pt1zx, 0**
**);**
**return \_fromJacobian(**
**pt2[PTXX], pt2[PTXY],**
**pt2[PTYX], pt2[PTYY],**
**pt2[PTZX], pt2[PTZY]**
**);**
**}**
**/\*\***
**\* @notice Get the field modulus**
**\* @return The field modulus**
**\*/**
**function GetFieldModulus() public pure returns (uint256) {**
**return FIELD\_MODULUS;**
**}**
**function submod(uint256 a, uint256 b, uint256 n) internal pure returns (uint256) {**
**return addmod(a, n - b, n);**
**}**
**function \_FQ2Mul(**
**uint256 xx, uint256 xy,**
**uint256 yx, uint256 yy**
**) internal pure returns (uint256, uint256) {**
**return (**
**submod(mulmod(xx, yx, FIELD\_MODULUS), mulmod(xy, yy, FIELD\_MODULUS), FIELD\_MODULUS),**
**addmod(mulmod(xx, yy, FIELD\_MODULUS), mulmod(xy, yx, FIELD\_MODULUS), FIELD\_MODULUS)**
**);**
**}**
**function \_FQ2Muc(**
**uint256 xx, uint256 xy,**
**uint256 c**
**) internal pure returns (uint256, uint256) {**
**return (**
**mulmod(xx, c, FIELD\_MODULUS),**
**mulmod(xy, c, FIELD\_MODULUS)**
**);**
**}**
**function \_FQ2Add(**
**uint256 xx, uint256 xy,**
**uint256 yx, uint256 yy**
**) internal pure returns (uint256, uint256) {**
**return (**
**addmod(xx, yx, FIELD\_MODULUS),**
**addmod(xy, yy, FIELD\_MODULUS)**
**);**
**}**
**function \_FQ2Sub(**
**uint256 xx, uint256 xy,**
**uint256 yx, uint256 yy**
**) internal pure returns (uint256 rx, uint256 ry) {**
**return (**
**submod(xx, yx, FIELD\_MODULUS),**
**submod(xy, yy, FIELD\_MODULUS)**
**);**
**}**
**function \_FQ2Div(**
**uint256 xx, uint256 xy,**
**uint256 yx, uint256 yy**
**) internal view returns (uint256, uint256) {**
**(yx, yy) = \_FQ2Inv(yx, yy);**
**return \_FQ2Mul(xx, xy, yx, yy);**
**}**
**function \_FQ2Inv(uint256 x, uint256 y) internal view returns (uint256, uint256) {**
**uint256 inv = \_modInv(addmod(mulmod(y, y, FIELD\_MODULUS), mulmod(x, x, FIELD\_MODULUS), FIELD\_MODULUS), FIELD\_MODULUS);**
**return (**
**mulmod(x, inv, FIELD\_MODULUS),**
**FIELD\_MODULUS - mulmod(y, inv, FIELD\_MODULUS)**
**);**
**}**
**function \_isOnCurve(**
**uint256 xx, uint256 xy,**
**uint256 yx, uint256 yy**
**) internal pure returns (bool) {**
**uint256 yyx;**
**uint256 yyy;**
**uint256 xxxx;**
**uint256 xxxy;**
**(yyx, yyy) = \_FQ2Mul(yx, yy, yx, yy);**
**(xxxx, xxxy) = \_FQ2Mul(xx, xy, xx, xy);**
**(xxxx, xxxy) = \_FQ2Mul(xxxx, xxxy, xx, xy);**
**(yyx, yyy) = \_FQ2Sub(yyx, yyy, xxxx, xxxy);**
**(yyx, yyy) = \_FQ2Sub(yyx, yyy, TWISTBX, TWISTBY);**
**return yyx == 0 &amp;&amp; yyy == 0;**
**}**
**function \_modInv(uint256 a, uint256 n) internal view returns (uint256 result) {**
**bool success;**
**assembly {**
**let freemem := mload(0x40)**
**mstore(freemem, 0x20)**
**mstore(add(freemem,0x20), 0x20)**
**mstore(add(freemem,0x40), 0x20)**
**mstore(add(freemem,0x60), a)**
**mstore(add(freemem,0x80), sub(n, 2))**
**mstore(add(freemem,0xA0), n)**
**success := staticcall(sub(gas(), 2000), 5, freemem, 0xC0, freemem, 0x20)**
**result := mload(freemem)**
**}**
**require(success);**
**}**
**function \_fromJacobian(**
**uint256 pt1xx, uint256 pt1xy,**
**uint256 pt1yx, uint256 pt1yy,**
**uint256 pt1zx, uint256 pt1zy**
**) internal view returns (**
**uint256 pt2xx, uint256 pt2xy,**
**uint256 pt2yx, uint256 pt2yy**
**) {**
**uint256 invzx;**
**uint256 invzy;**
**(invzx, invzy) = \_FQ2Inv(pt1zx, pt1zy);**
**(pt2xx, pt2xy) = \_FQ2Mul(pt1xx, pt1xy, invzx, invzy);**
**(pt2yx, pt2yy) = \_FQ2Mul(pt1yx, pt1yy, invzx, invzy);**
**}**
**function \_ECTwistAddJacobian(**
**uint256 pt1xx, uint256 pt1xy,**
**uint256 pt1yx, uint256 pt1yy,**
**uint256 pt1zx, uint256 pt1zy,**
**uint256 pt2xx, uint256 pt2xy,**
**uint256 pt2yx, uint256 pt2yy,**
**uint256 pt2zx, uint256 pt2zy) internal pure returns (uint256[6] memory pt3) {**
**if (pt1zx == 0 &amp;&amp; pt1zy == 0) {**
**(**
**pt3[PTXX], pt3[PTXY],**
**pt3[PTYX], pt3[PTYY],**
**pt3[PTZX], pt3[PTZY]**
**) = (**
**pt2xx, pt2xy,**
**pt2yx, pt2yy,**
**pt2zx, pt2zy**
**);**
**return pt3;**
**} else if (pt2zx == 0 &amp;&amp; pt2zy == 0) {**
**(**
**pt3[PTXX], pt3[PTXY],**
**pt3[PTYX], pt3[PTYY],**
**pt3[PTZX], pt3[PTZY]**
**) = (**
**pt1xx, pt1xy,**
**pt1yx, pt1yy,**
**pt1zx, pt1zy**
**);**
**return pt3;**
**}**
**(pt2yx, pt2yy) = \_FQ2Mul(pt2yx, pt2yy, pt1zx, pt1zy); // U1 = y2 \* z1**
**(pt3[PTYX], pt3[PTYY]) = \_FQ2Mul(pt1yx, pt1yy, pt2zx, pt2zy); // U2 = y1 \* z2**
**(pt2xx, pt2xy) = \_FQ2Mul(pt2xx, pt2xy, pt1zx, pt1zy); // V1 = x2 \* z1**
**(pt3[PTZX], pt3[PTZY]) = \_FQ2Mul(pt1xx, pt1xy, pt2zx, pt2zy); // V2 = x1 \* z2**
**if (pt2xx == pt3[PTZX] &amp;&amp; pt2xy == pt3[PTZY]) {**
**if (pt2yx == pt3[PTYX] &amp;&amp; pt2yy == pt3[PTYY]) {**
**(**
**pt3[PTXX], pt3[PTXY],**
**pt3[PTYX], pt3[PTYY],**
**pt3[PTZX], pt3[PTZY]**
**) = \_ECTwistDoubleJacobian(pt1xx, pt1xy, pt1yx, pt1yy, pt1zx, pt1zy);**
**return pt3;**
**}**
**(**
**pt3[PTXX], pt3[PTXY],**
**pt3[PTYX], pt3[PTYY],**
**pt3[PTZX], pt3[PTZY]**
**) = (**
**1, 0,**
**1, 0,**
**0, 0**
**);**
**return pt3;**
**}**
**(pt2zx, pt2zy) = \_FQ2Mul(pt1zx, pt1zy, pt2zx, pt2zy); // W = z1 \* z2**
**(pt1xx, pt1xy) = \_FQ2Sub(pt2yx, pt2yy, pt3[PTYX], pt3[PTYY]); // U = U1 - U2**
**(pt1yx, pt1yy) = \_FQ2Sub(pt2xx, pt2xy, pt3[PTZX], pt3[PTZY]); // V = V1 - V2**
**(pt1zx, pt1zy) = \_FQ2Mul(pt1yx, pt1yy, pt1yx, pt1yy); // V\_squared = V \* V**
**(pt2yx, pt2yy) = \_FQ2Mul(pt1zx, pt1zy, pt3[PTZX], pt3[PTZY]); // V\_squared\_times\_V2 = V\_squared \* V2**
**(pt1zx, pt1zy) = \_FQ2Mul(pt1zx, pt1zy, pt1yx, pt1yy); // V\_cubed = V \* V\_squared**
**(pt3[PTZX], pt3[PTZY]) = \_FQ2Mul(pt1zx, pt1zy, pt2zx, pt2zy); // newz = V\_cubed \* W**
**(pt2xx, pt2xy) = \_FQ2Mul(pt1xx, pt1xy, pt1xx, pt1xy); // U \* U**
**(pt2xx, pt2xy) = \_FQ2Mul(pt2xx, pt2xy, pt2zx, pt2zy); // U \* U \* W**
**(pt2xx, pt2xy) = \_FQ2Sub(pt2xx, pt2xy, pt1zx, pt1zy); // U \* U \* W - V\_cubed**
**(pt2zx, pt2zy) = \_FQ2Muc(pt2yx, pt2yy, 2); // 2 \* V\_squared\_times\_V2**
**(pt2xx, pt2xy) = \_FQ2Sub(pt2xx, pt2xy, pt2zx, pt2zy); // A = U \* U \* W - V\_cubed - 2 \* V\_squared\_times\_V2**
**(pt3[PTXX], pt3[PTXY]) = \_FQ2Mul(pt1yx, pt1yy, pt2xx, pt2xy); // newx = V \* A**
**(pt1yx, pt1yy) = \_FQ2Sub(pt2yx, pt2yy, pt2xx, pt2xy); // V\_squared\_times\_V2 - A**
**(pt1yx, pt1yy) = \_FQ2Mul(pt1xx, pt1xy, pt1yx, pt1yy); // U \* (V\_squared\_times\_V2 - A)**
**(pt1xx, pt1xy) = \_FQ2Mul(pt1zx, pt1zy, pt3[PTYX], pt3[PTYY]); // V\_cubed \* U2**
**(pt3[PTYX], pt3[PTYY]) = \_FQ2Sub(pt1yx, pt1yy, pt1xx, pt1xy); // newy = U \* (V\_squared\_times\_V2 - A) - V\_cubed \* U2**
**}**
**function \_ECTwistDoubleJacobian(**
**uint256 pt1xx, uint256 pt1xy,**
**uint256 pt1yx, uint256 pt1yy,**
**uint256 pt1zx, uint256 pt1zy**
**) internal pure returns (**
**uint256 pt2xx, uint256 pt2xy,**
**uint256 pt2yx, uint256 pt2yy,**
**uint256 pt2zx, uint256 pt2zy**
**) {**
**(pt2xx, pt2xy) = \_FQ2Muc(pt1xx, pt1xy, 3); // 3 \* x**
**(pt2xx, pt2xy) = \_FQ2Mul(pt2xx, pt2xy, pt1xx, pt1xy); // W = 3 \* x \* x**
**(pt1zx, pt1zy) = \_FQ2Mul(pt1yx, pt1yy, pt1zx, pt1zy); // S = y \* z**
**(pt2yx, pt2yy) = \_FQ2Mul(pt1xx, pt1xy, pt1yx, pt1yy); // x \* y**
**(pt2yx, pt2yy) = \_FQ2Mul(pt2yx, pt2yy, pt1zx, pt1zy); // B = x \* y \* S**
**(pt1xx, pt1xy) = \_FQ2Mul(pt2xx, pt2xy, pt2xx, pt2xy); // W \* W**
**(pt2zx, pt2zy) = \_FQ2Muc(pt2yx, pt2yy, 8); // 8 \* B**
**(pt1xx, pt1xy) = \_FQ2Sub(pt1xx, pt1xy, pt2zx, pt2zy); // H = W \* W - 8 \* B**
**(pt2zx, pt2zy) = \_FQ2Mul(pt1zx, pt1zy, pt1zx, pt1zy); // S\_squared = S \* S**
**(pt2yx, pt2yy) = \_FQ2Muc(pt2yx, pt2yy, 4); // 4 \* B**
**(pt2yx, pt2yy) = \_FQ2Sub(pt2yx, pt2yy, pt1xx, pt1xy); // 4 \* B - H**
**(pt2yx, pt2yy) = \_FQ2Mul(pt2yx, pt2yy, pt2xx, pt2xy); // W \* (4 \* B - H)**
**(pt2xx, pt2xy) = \_FQ2Muc(pt1yx, pt1yy, 8); // 8 \* y**
**(pt2xx, pt2xy) = \_FQ2Mul(pt2xx, pt2xy, pt1yx, pt1yy); // 8 \* y \* y**
**(pt2xx, pt2xy) = \_FQ2Mul(pt2xx, pt2xy, pt2zx, pt2zy); // 8 \* y \* y \* S\_squared**
**(pt2yx, pt2yy) = \_FQ2Sub(pt2yx, pt2yy, pt2xx, pt2xy); // newy = W \* (4 \* B - H) - 8 \* y \* y \* S\_squared**
**(pt2xx, pt2xy) = \_FQ2Muc(pt1xx, pt1xy, 2); // 2 \* H**
**(pt2xx, pt2xy) = \_FQ2Mul(pt2xx, pt2xy, pt1zx, pt1zy); // newx = 2 \* H \* S**
**(pt2zx, pt2zy) = \_FQ2Mul(pt1zx, pt1zy, pt2zx, pt2zy); // S \* S\_squared**
**(pt2zx, pt2zy) = \_FQ2Muc(pt2zx, pt2zy, 8); // newz = 8 \* S \* S\_squared**
**}**
**function \_ECTwistMulJacobian(**
**uint256 d,**
**uint256 pt1xx, uint256 pt1xy,**
**uint256 pt1yx, uint256 pt1yy,**
**uint256 pt1zx, uint256 pt1zy**
**) internal pure returns (uint256[6] memory pt2) {**
**while (d != 0) {**
**if ((d &amp; 1) != 0) {**
**pt2 = \_ECTwistAddJacobian(**
**pt2[PTXX], pt2[PTXY],**
**pt2[PTYX], pt2[PTYY],**
**pt2[PTZX], pt2[PTZY],**
**pt1xx, pt1xy,**
**pt1yx, pt1yy,**
**pt1zx, pt1zy);**
**}**
**(**
**pt1xx, pt1xy,**
**pt1yx, pt1yy,**
**pt1zx, pt1zy**
**) = \_ECTwistDoubleJacobian(**
**pt1xx, pt1xy,**
**pt1yx, pt1yy,**
**pt1zx, pt1zy**
**);**
**d = d / 2;**
**}**
**}**
**}**
**// This file is MIT Licensed.**
**//**
**// Copyright 2017 Christian Reitwiessner**
**// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the &quot;Software&quot;), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:**
**// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.**
**// THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.**
**pragma solidity ^0.6.1;**
**library Pairing {**
**struct G1Point {**
**uint X;**
**uint Y;**
**}**
**// Encoding of field elements is: X[0] \* z + X[1]**
**struct G2Point {**
**uint[2] X;**
**uint[2] Y;**
**}**
**/// @return the generator of G1**
**function P1() pure internal returns (G1Point memory) {**
**return G1Point(1, 2);**
**}**
**/// @return the generator of G2**
**function P2() pure internal returns (G2Point memory) {**
**return G2Point(**
**[10857046999023057135944570762232829481370756359578518086990519993285655852781,**
**11559732032986387107991004021392285783925812861821192530917403151452391805634],**
**[8495653923123431417604973247489272438418190587263600148770280649306958101930,**
**4082367875863433681332203403145435568316851327593401208105741076214120093531]**
**);**
**}**
**/// @return the negation of p, i.e. p.addition(p.negate()) should be zero.**
**function negate(G1Point memory p) pure internal returns (G1Point memory) {**
**// The prime q in the base field F\_q for G1**
**uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583;**
**if (p.X == 0 &amp;&amp; p.Y == 0)**
**return G1Point(0, 0);**
**return G1Point(p.X, q - (p.Y % q));**
**}**
**/// @return r the sum of two points of G1**
**function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {**
**uint[4] memory input;**
**input[0] = p1.X;**
**input[1] = p1.Y;**
**input[2] = p2.X;**
**input[3] = p2.Y;**
**bool success;**
**assembly {**
**success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)**
**// Use &quot;invalid&quot; to make gas estimation work**
**switch success case 0 { invalid() }**
**}**
**require(success);**
**}**
**/// @return r the sum of two points of G2**
**function addition(G2Point memory p1, G2Point memory p2) internal view returns (G2Point memory r) {**
**(r.X[0], r.X[1], r.Y[0], r.Y[1]) = BN256G2.ECTwistAdd(p1.X[0],p1.X[1],p1.Y[0],p1.Y[1],p2.X[0],p2.X[1],p2.Y[0],p2.Y[1]);**
**}**
**/// @return r the product of a point on G1 and a scalar, i.e.**
**/// p == p.scalar\_mul(1) and p.addition(p) == p.scalar\_mul(2) for all points p.**
**function scalar\_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) {**
**uint[3] memory input;**
**input[0] = p.X;**
**input[1] = p.Y;**
**input[2] = s;**
**bool success;**
**assembly {**
**success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)**
**// Use &quot;invalid&quot; to make gas estimation work**
**switch success case 0 { invalid() }**
**}**
**require (success);**
**}**
**/// @return the result of computing the pairing check**
**/// e(p1[0], p2[0]) \* .... \* e(p1[n], p2[n]) == 1**
**/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should**
**/// return true.**
**function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) {**
**require(p1.length == p2.length);**
**uint elements = p1.length;**
**uint inputSize = elements \* 6;**
**uint[] memory input = new uint[](inputSize);**
**for (uint i = 0; i \&lt; elements; i++)**
**{**
**input[i \* 6 + 0] = p1[i].X;**
**input[i \* 6 + 1] = p1[i].Y;**
**input[i \* 6 + 2] = p2[i].X[1];**
**input[i \* 6 + 3] = p2[i].X[0];**
**input[i \* 6 + 4] = p2[i].Y[1];**
**input[i \* 6 + 5] = p2[i].Y[0];**
**}**
**uint[1] memory out;**
**bool success;**
**assembly {**
**success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)**
**// Use &quot;invalid&quot; to make gas estimation work**
**switch success case 0 { invalid() }**
**}**
**require(success);**
**return out[0] != 0;**
**}**
**/// Convenience method for a pairing check for two pairs.**
**function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2) internal view returns (bool) {**
**G1Point[] memory p1 = new G1Point[](2);**
**G2Point[] memory p2 = new G2Point[](2);**
**p1[0] = a1;**
**p1[1] = b1;**
**p2[0] = a2;**
**p2[1] = b2;**
**return pairing(p1, p2);**
**}**
**/// Convenience method for a pairing check for three pairs.**
**function pairingProd3(**
**G1Point memory a1, G2Point memory a2,**
**G1Point memory b1, G2Point memory b2,**
**G1Point memory c1, G2Point memory c2**
**) internal view returns (bool) {**
**G1Point[] memory p1 = new G1Point[](3);**
**G2Point[] memory p2 = new G2Point[](3);**
**p1[0] = a1;**
**p1[1] = b1;**
**p1[2] = c1;**
**p2[0] = a2;**
**p2[1] = b2;**
**p2[2] = c2;**
**return pairing(p1, p2);**
**}**
**/// Convenience method for a pairing check for four pairs.**
**function pairingProd4(**
**G1Point memory a1, G2Point memory a2,**
**G1Point memory b1, G2Point memory b2,**
**G1Point memory c1, G2Point memory c2,**
**G1Point memory d1, G2Point memory d2**
**) internal view returns (bool) {**
**G1Point[] memory p1 = new G1Point[](4);**
**G2Point[] memory p2 = new G2Point[](4);**
**p1[0] = a1;**
**p1[1] = b1;**
**p1[2] = c1;**
**p1[3] = d1;**
**p2[0] = a2;**
**p2[1] = b2;**
**p2[2] = c2;**
**p2[3] = d2;**
**return pairing(p1, p2);**
**}**
**}**
**contract Verifier {**
**using Pairing for \*;**
**struct VerifyingKey {**
**Pairing.G2Point h;**
**Pairing.G1Point g\_alpha;**
**Pairing.G2Point h\_beta;**
**Pairing.G1Point g\_gamma;**
**Pairing.G2Point h\_gamma;**
**Pairing.G1Point[] query;**
**}**
**struct Proof {**
**Pairing.G1Point a;**
**Pairing.G2Point b;**
**Pairing.G1Point c;**
**}**
**function verifyingKey() pure internal returns (VerifyingKey memory vk) {**
**vk.h = Pairing.G2Point([uint256(0x21ed25b314584c89fd75fc60b48ae3c5862a6fecb1ce467d6c6de3816fb2b7df), uint256(0x3032b7523599019887d7967dc5c5b6db702b89d8af9a7b09bfa6ca8575cdac56)], [uint256(0x17d27e70aca2e4402b4d3c5d0b4fa42fe861ff09e6452cf6a30340d3b831b187), uint256(0x173b7f0b011769371695d87258a9794cf5ef6a210025b2ef8d0adc4a19b23af0)]);**
**vk.g\_alpha = Pairing.G1Point(uint256(0x278a9668fe236f39390edf6e1a549f824eaae03635cabefdb4d503f5826513d2), uint256(0x0ae043095f676b9ef74237fdaf4d3002403c328d55d1763d3905d2ddf763b55d));**
**vk.h\_beta = Pairing.G2Point([uint256(0x02b8284a22bbfa1f969b47f9063b5fc326c9ba46da517ada70a27aafd9a7a592), uint256(0x10a859399627a97eefa078cf7120a0917f095ac4b865434fb6fa33472bc3d59d)], [uint256(0x22679a7aedbf02a36bf41265ed6673f3a8a55f4b49966bf325175da5c837e262), uint256(0x01b24384861ffee62a56edd0210072ef823b9609df3cbce84f6c146531f5b216)]);**
**vk.g\_gamma = Pairing.G1Point(uint256(0x29c9815e24bcbe89fcdfe9f1b2dc3dbd80b3e3a9d5a49dee883f476ae9aa711f), uint256(0x063b306c1e6dfb31a84a1ac01f869f6350ff743a7d64a27a9c266038395018c9));**
**vk.h\_gamma = Pairing.G2Point([uint256(0x21ed25b314584c89fd75fc60b48ae3c5862a6fecb1ce467d6c6de3816fb2b7df), uint256(0x3032b7523599019887d7967dc5c5b6db702b89d8af9a7b09bfa6ca8575cdac56)], [uint256(0x17d27e70aca2e4402b4d3c5d0b4fa42fe861ff09e6452cf6a30340d3b831b187), uint256(0x173b7f0b011769371695d87258a9794cf5ef6a210025b2ef8d0adc4a19b23af0)]);**
**vk.query = new Pairing.G1Point[](3);**
**vk.query[0] = Pairing.G1Point(uint256(0x12cfe3e37bc89a4ced92c48be1745973a011be6fc0a01afee6fc8100ba40329d), uint256(0x0d6ebd5b8ce577577c8ef036f1d737e7be647b948dfdfd7b47707981d1629cd3));**
**vk.query[1] = Pairing.G1Point(uint256(0x2347a9ab877444c1b5b5474d572c793f6318f0f25ea0433d22e7b49a7316e004), uint256(0x1b1fd6f7178b50033301608a01e55c67bda52546a03d4215a472e1b41a4a59dc));**
**vk.query[2] = Pairing.G1Point(uint256(0x03ff7e4173415786c57995ac258ef71181f1905802abf12b80280a6d31f1b426), uint256(0x0731ee572bd61e233d0081fc15b34f2e345263e29fed957a11277d6013407d5d));**
**}**
**function verify(uint[] memory input, Proof memory proof) internal view returns (uint) {**
**uint256 snark\_scalar\_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617;**
**VerifyingKey memory vk = verifyingKey();**
**require(input.length + 1 == vk.query.length);**
**// Compute the linear combination vk\_x**
**Pairing.G1Point memory vk\_x = Pairing.G1Point(0, 0);**
**for (uint i = 0; i \&lt; input.length; i++) {**
**require(input[i] \&lt; snark\_scalar\_field);**
**vk\_x = Pairing.addition(vk\_x, Pairing.scalar\_mul(vk.query[i + 1], input[i]));**
**}**
**vk\_x = Pairing.addition(vk\_x, vk.query[0]);**
**/\*\***
**\* e(A\*G^{alpha}, B\*H^{beta}) = e(G^{alpha}, H^{beta}) \* e(G^{psi}, H^{gamma})**
**\* \* e(C, H)**
**\* where psi = \sum\_{i=0}^l input\_i pvk.query[i]**
**\*/**
**if (!Pairing.pairingProd4(vk.g\_alpha, vk.h\_beta, vk\_x, vk.h\_gamma, proof.c, vk.h, Pairing.negate(Pairing.addition(proof.a, vk.g\_alpha)), Pairing.addition(proof.b, vk.h\_beta))) return 1;**
**/\*\***
**\* e(A, H^{gamma}) = e(G^{gamma}, b)**
**\*/**
**if (!Pairing.pairingProd2(proof.a, vk.h\_gamma, Pairing.negate(vk.g\_gamma), proof.b)) return 2;**
**return 0;**
**}**
**function verifyTx(**
**uint[2] memory a,**
**uint[2][2] memory b,**
**uint[2] memory c, uint[2] memory input**
**) public view returns (bool r) {**
**Proof memory proof;**
**proof.a = Pairing.G1Point(a[0], a[1]);**
**proof.b = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);**
**proof.c = Pairing.G1Point(c[0], c[1]);**
**uint[] memory inputValues = new uint[](2);**
**for(uint i = 0; i \&lt; input.length; i++){**
**inputValues[i] = input[i];**
**}**
**if (verify(inputValues, proof) == 0) {**
**return true;**
**} else {**
**return false;**
**}**
**}**
**}**
**zokrates verify -s gm17 -b ark**
Performing verification...
The verification result is: PASS
## 12 Conclusion
We can use ZoKrates library in the rough format but it will take a lot of time for developing necessary circuits.
We can not reuse the AZTEC approach. It&#39;s a pretty difficult solution, some components are private and there are a lot of questions about the security of their solution. And potentially we will have to use their crypromodule and sdk.
backend/Confidential_tokens/assets/image1.png

146 KB

backend/Confidential_tokens/assets/image10.png

539 KB

backend/Confidential_tokens/assets/image11.png

546 KB

backend/Confidential_tokens/assets/image12.png

179 KB

backend/Confidential_tokens/assets/image13.png

493 KB

backend/Confidential_tokens/assets/image14.png

173 KB

backend/Confidential_tokens/assets/image2.png

899 KB

backend/Confidential_tokens/assets/image3.png

689 KB

backend/Confidential_tokens/assets/image4.png

143 KB

backend/Confidential_tokens/assets/image5.png

97 KB

backend/Confidential_tokens/assets/image6.png

495 KB

backend/Confidential_tokens/assets/image7.png

146 KB

backend/Confidential_tokens/assets/image8.png

174 KB

backend/Confidential_tokens/assets/image9.png

290 KB

pragma solidity ^0.6.7;
import "https://github.com/smartcontractkit/chainlink/blob/master/evm-contracts/src/v0.6/interfaces/AggregatorV3Interface.sol";
contract PriceConsumerV3 {
function getLatestPrice(address aggregatorAddress) public view returns (int) {
AggregatorV3Interface priceFeed = AggregatorV3Interface(aggregatorAddress);
(
uint80 roundID,
int price,
uint startedAt,
uint timeStamp,
uint80 answeredInRound
) = priceFeed.latestRoundData();
// If the round is not complete yet, timestamp is 0
require(timeStamp > 0, "Round not complete");
return price;
}
function getPrice(address _Aaddress, address _bAddress) public view returns (uint256) {
uint priceA = uint(getLatestPrice(_Aaddress))
unit priceB = uint(getLatestPrice(_Baddress))
return uint((priceA * 10 ** decimals) / priceB);
}
}
pragma solidity ^0.6.0;
// SPDX-License-Identifier: MIT
interface zkAsset {
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function mint(address to, uint256 amount) external;
function burn(address to, uint256 amount) external;
event Transfer(address indexed from, address indexed to, uint256 value);
}
interface chainLink {
function getPrice() external view returns (uint256);
}
contract burner {
zkAsset tokenA;
zkAsset tokenB;
chainLink priceOracle;
event Shifted(uint256 value);
constructor(address _tokenA, address _tokenB) public{
tokenA = zkAsset(_tokenA);
tokenB = zkAsset(_tokenB);
priceOracle = chainLink(); // deployed chainlink.sol address
}
function shift(uint256 amount) public {
require(amount > 0, "amount can't be zero");
uint256 allowance = tokenA.allowance(msg.sender, address(this));
uint256 Price = priceOracle.getPrice();
require(allowance >= amount, "remember to approve this contract");
tokenA.transferFrom(msg.sender, address(0x5a6b6173736574), amount);// <--- burn here
tokenB.mint(msg.sender ,((amount * Price)/10**18);//mint
emit Shifted(amount);
}
}
pragma solidity ^0.6.0;
// SPDX-License-Identifier: MIT
interface zkAsset {
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function mint(address to, uint256 amount) external;
function burn(address to, uint256 amount) external;
event Transfer(address indexed from, address indexed to, uint256 value);
}
interface xftTest {
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function mint(address to, uint256 amount) external;
function burn(address to, uint256 amount) external;
function balanceOf(address account) external view returns (uint256);
event Transfer(address indexed from, address indexed to, uint256 value);
}
interface chainLink {
function getPrice(address _Aaddress, address _bAddress) external view returns (uint256);
}
contract burner {
xftTest tokenA;
zkAsset tokenB;
chainLink priceOracle;
event Shifted(uint256 value);
constructor(address _tokenA, address _tokenB) public{
tokenA = xftTest(_tokenA);
tokenB = zkAsset(_tokenB);
priceOracle = chainLink(0x51681E73Ec15C3206074d668cE55FAF4305Ea9D7); // deployed chainlink.sol address
}
function shift(uint256 amount, address _Aaddress, address _bAddress) public {
require(amount > 0, "amount can't be zero");
uint256 allowance = tokenA.allowance(msg.sender, address(this));
uint256 Price = priceOracle.getPrice(_Aaddress, _bAddress);
require(allowance >= amount, "remember to approve this contract");
tokenA.transferFrom(msg.sender, address(0x5a6b6173736574), amount); // <--- burn here
tokenB.mint(msg.sender ,((amount * Price)/10**18)); //mint
emit Shifted(amount);
}
function faucet() public payable {
require(tokenA.balanceOf(msg.sender)<(10*10**18), "you already have enough tokens!!");
tokenA.mint(msg.sender, (10*10**18));
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment