cleaned up old crypto research from root dir

This commit is contained in:
lunar-mining
2021-09-13 09:36:54 +02:00
parent 7de40e7f01
commit 8ce2445879
116 changed files with 0 additions and 12611 deletions

View File

@@ -1,114 +0,0 @@
---
title: Halo 1 Arithmetization Polynomials Expansion
author: Amir Taaki
header-includes: |
- \newcommand{\vec}[1]{\mathbf{#1}}
---
Halo 1 constraints consist of multiplication constraints of the form
$$\vec{a_i} \cdot \vec{b_i} = \vec{c_i}$$
and linear addition constraints of the form
$$\left(\sum_{i = 1}^N \vec{a_i} \cdot (\vec{u_q})_i\right) + \left(\sum_{i = 1}^N \vec{b_i} \cdot (\vec{v_q})_i\right) + \left(\sum_{i = 1}^N \vec{c_i} \cdot (\vec{w_q})_i\right) = \vec{k_q}$$
We embed all these constraints using different powers of $Y$ so they are linearly independent.
$$\sum_{i = 1}^N \vec{a_i} \cdot Y^N u_i(Y) + \sum_{i = 1}^N \vec{b_i} \cdot Y^N v_i(Y) + \sum_{i = 1}^N \vec{c_i} \cdot (Y^N w_i(Y) - Y^i - Y^{-i}) + \sum_{i = 1}^N \vec{a_i b_i} \cdot (Y^i + Y^{-i}) - Y^N k(Y) = 0 $$
where we define the polynomials
$$u_i(Y) = \sum_{q = 1}^Q Y^q (\vec{u}_q)_i \qquad v_i(Y) = \sum_{q = 1}^Q Y^q (\vec{v}_q)_i$$
$$w_i(Y) = \sum_{q = 1}^Q Y^q (\vec{w}_q)_i \qquad k(Y) = \sum_{q = 1}^Q Y^q \vec{k}_q$$
\begin{alignat*}{2}
r(X, Y) &= && \sum_{i = 1}^N \vec{a}_i X^i Y^i + \sum_{i = 1} \vec{b}_i X^{-i} Y^{-i} + \sum_{i = 1}^N \vec{c}_i X^{-i - N} Y^{-i - N} \\
&= \; &&\vec{a_1} XY + \vec{a_2} X^2 Y^2 + \cdots + \vec{a_N} X^N Y^N \\
& && + \vec{b_1} X^{-1} Y^{-1} + \vec{b_2} X^{-2} Y^{-2} + \cdots + \vec{b_N} X^{-N} Y^{-N} \\
& && + \vec{c_1} X^{-1 -N} Y^{-1 -N} + \vec{c_2} X^{-2-N} Y^{-2-N} + \cdots + \vec{c_N} X^{-N-N} Y^{-N-N}
\end{alignat*}
\begin{alignat*}{2}
r(X, 1) &= && \sum_{i = 1}^N \vec{a}_i X^i + \sum_{i = 1} \vec{b}_i X^{-i} + \sum_{i = 1}^N \vec{c}_i X^{-i - N} \\
&= \; &&\vec{a_1} X + \vec{a_2} X^2 + \cdots + \vec{a_N} X^N \\
& && + \vec{b_1} X^{-1} + \vec{b_2} X^{-2} + \cdots + \vec{b_N} X^{-N} \\
& && + \vec{c_1} X^{-1 -N} + \vec{c_2} X^{-2-N} + \cdots + \vec{c_N} X^{-N-N}
\end{alignat*}
$$s(X, Y) = \sum_{i = 1}^N u_i(Y)X^{-i} + \sum_{i = 1}^N v_i(Y) X^i + \sum_{i = 1}^N w_i(Y) X^{i + N}$$
\begin{alignat*}{2}
s'(X, Y) &= && \; Y^N s(X, Y) - \sum_{i = 1}^N (Y^i + Y^{-i}) X^{i + N} \\
&= && \sum_{i = 1}^N X^{-i} Y^N u_i(Y) + \sum_{i = 1}^N X^i Y^N v_i(Y) + \sum_{i = 1}^N X^{i + N} Y^N w_i(Y) - \sum_{i = 1}^N X^{i + N} Y^i - \sum_{i = 1}^N X^{i + N} Y^{-i} \\
&= && \; X^{-1} Y^N u_1(Y) + X^{-2} Y^N u_2(Y) + \cdots + X^{-N} Y^N u_N{Y} \\
& && + X Y^N v_1(Y) + X^2 Y^N v_2(Y) + \cdots + X^N Y^N v_N(Y) \\
& && + X^{N + 1} Y^N w_1(Y) + X^{N + 2} Y^N w_2(Y) + \cdots + X^{N + N} w_N(Y) \\
&= && \; X^{-1} (Y^{1 + N} u_{1,1} + \cdots + Y^{Q + N} u_{Q,1}) \\
& && + X^{-2} (Y^{1 + N} u_{1,2} + \cdots + Y^{Q + N} u_{Q,2}) \\
& && + \cdots \\
& && + X^{-N} (Y^{1 + N} u_{1,N} + \cdots + Y^{Q + N} u_{Q,N}) \\
& && + X (Y^{1 + N} v_{1,1} + \cdots + Y^{Q + N} v_{Q,1}) \\
& && + X^2 (Y^{1 + N} v_{1,2} + \cdots + Y^{Q + N} v_{Q,2}) \\
& && + \cdots \\
& && + X^N (Y^{1 + N} v_{1,N} + \cdots + Y^{Q + N} v_{Q,N}) \\
& && + X^{N + 1} (Y^{1 + N} w_{1,1} + \cdots + Y^{Q + N} w_{Q,1}) \\
& && + X^{N + 2} (Y^{1 + N} w_{1,2} + \cdots + Y^{Q + N} w_{Q,2}) \\
& && + \cdots \\
& && + X^{N + N} (Y^{1 + N} w_{1,N} + \cdots + Y^{Q + N} w_{Q,N}) \\
& && - X^{1 + N} Y - X^{1 + N} Y^{-1} \\
& && - X^{2 + N} Y^2 - X^{2 + N} Y^{-2} \\
& && + \cdots \\
& && - X^{N + N} Y^N - X^{N + N} Y^{-N}
\end{alignat*}
The last expansion above is not necessary for the rest of our argument and is simply included for completeness.
First we compute $r(X, 1) r(X, Y)$ and then $r(X, 1) s'(X, Y)$ to show that the constant argument of $t(X, Y)$ is the left hand side of the combined constraints equation.
We focus only on expanding the terms where powers of $X$ cancel to $0$.
\begin{alignat*}{2}
r(X, 1) r(X, Y) &= && \cdots + \vec{a_1} X \vec{b_1} X^{-1} Y^{-1} + \cdots + \vec{a_2} X^2 \vec{b_2} X^{-2} Y^{-2} + \cdots + \vec{a_N} X^N \vec{b_N} X^{-N} Y^{-N} + \cdots \\
& && + \vec{b_1} X^{-1} \vec{a_1} XY + \cdots + \vec{b_2} X^{-2} \vec{a_2} X^2 Y^2 + \cdots + \vec{b_N} X^{-N} \vec{a_N} X^N Y^N + \cdots \\
&= && \; \cdots + \vec{a_1} \vec{b_1} Y^{-1} + \vec{a_2} \vec{b_2} Y^{-2} + \cdots + \vec{a_N} \vec{b_N} Y^{-N} + \vec{a_1} \vec{b_1} Y + \vec{a_2} \vec{b_2} Y^2 + \cdots + \vec{a_N} \vec{b_N} Y^N \\
&= && \; \sum_{i = 1}^N \vec{a}_i \vec{b}_i (Y_i + Y^{-i})
\end{alignat*}
\begin{alignat*}{2}
r(X, 1) s'(X, Y) &= && \; \vec{a_1} X X^{-1} Y^N u_1(Y) + \vec{a_2} X^2 X^{-2} Y^N u_2(Y) + \cdots + \vec{a_N} X^N X^{-N} Y^N u_N(Y) \\
& && + \vec{b_1} X^{-1} X Y^N v_1(Y) + \vec{b_2} X^{-2} X^2 Y^N v_2(Y) + \cdots + \vec{b_N} X^{-N} X^N Y^N v_N(Y) \\
& && + \vec{c_1} X^{-1-N} X^{N+1} Y^N w_1(Y) + \vec{c_2} X^{-2 - N} X^{N + 2} Y^N w_2(Y) + \cdots + \vec{c_N} X^{-N-N} X^{N + N} Y^N w_N(Y) \\
& && + \vec{c_1} X^{-1-N} (-X^{1 + N} Y - X^{1 + N} Y^{-1}) \\
& && + \vec{c_2} X^{-2-N} (-X^{2+N}Y^2 - X^{2+N}Y^{-2}) \\
& && + \cdots + \vec{c_N} X^{-N-N} (-X^{N+N} Y^N - X^{N+N} Y^{-N}) \\
& && + \cdots \\
&= && \; \vec{a_1} Y^N u_1(Y) + \vec{a_2} Y^N u_2(Y) + \cdots + \vec{a_N} Y^N u_N(Y) \\
& && + \vec{b_1} Y^N v_1(Y) + \vec{b_2} Y^N v_2(Y) + \cdots + \vec{b_N} Y^N v_N(Y) \\
& && + \vec{c_1} Y^N w_1(Y) + \vec{c_2} Y^N w_2(Y) + \cdots + \vec{c_N} Y^N w_N(Y) \\
& && + \vec{c_1} (-Y - Y^{-1}) + \vec{c_2} (-Y^2 - Y^{-2}) + \cdots + \vec{c_N} (-Y^N - Y^{-N}) \\
& && + \cdots \\
&= && \; \sum_{i = 1}^N \vec{a_i} \cdot Y^N u_i(Y) + \sum_{i = 1}^N \vec{b_i} \cdot Y^N v_i(Y) + \sum_{i = 1}^N \vec{c_i} \cdot (Y^N w_i(Y) - Y^i - Y^{-i})
\end{alignat*}
# Simplified Example
Let $x = 4, y = 6$ then $xy = 24$, and $\vec{a} = (4), \vec{b} = (6), \vec{c} = (24)$ with no linear constraints (all selectors set to zero).
$$r(X, Y) = 4XY + 6X^{-1}Y^{-1} + 24 X^{-2} Y^{-2}$$
$$t(X, Y) = r(X, 1) r(X, Y) - X^{N + 1} Y - X^{N + 1} Y^{-1}$$
$$r(X, 1) = 4X + 6X^{-1} + 24 X^{-2}$$
\begin{alignat*}{2}
r(X, 1) r(X, Y) &= && \; 4X (4XY + 6X^{-1}Y^{-1} + 24 X^{-2} Y^{-2}) \\
& && + 6X^{-1} (4XY + 6X^{-1}Y^{-1} + 24 X^{-2} Y^{-2}) \\
& && + 24X^{-2} (4XY + 6X^{-1}Y^{-1} + 24 X^{-2} Y^{-2}) \\
&= && \; 16X^2 Y + 24 Y^{-1} + 96 X^{-1} Y^{-2} \\
& && + 24Y + 36 X^{-2} Y^{-1} + 144 X^{-3} Y^{-2} \\
& && + 96 X^{-1} Y + 144 X^{-3} Y^{-1} + 576 X^{-4} Y^{-2} \\
r(X, 1) (- X^{N + 1} Y - X^{N + 1} Y^{-1}) &= && \; 4X (- X^{N + 1} Y - X^{N + 1} Y^{-1}) \\
& && + 6X^{-1} (- X^{N + 1} Y - X^{N + 1} Y^{-1}) \\
& && + 24 X^{-2} (- X^{N + 1} Y - X^{N + 1} Y^{-1}) \\
&= && \; - 4X^{N + 2} Y - 4X^{N + 2} Y^{-1}) \\
& && - 6X^N Y - 6X^N Y^{-1} \\
& && - 24 X^{N - 1} Y - 24 X^{N - 1} Y^{-1}) \\
&= && \; - 4X^3 Y - 4X^3 Y^{-1}) \\
& && - 6X Y - 6X Y^{-1} \\
& && - 24 Y - 24 Y^{-1} \\
\end{alignat*}

View File

@@ -1,80 +0,0 @@
```python
sage: x
x
sage: l_2 = (x - 1)*(x - 3)*(x - 4)
sage: l_2
(x - 1)*(x - 3)*(x - 4)
sage: l_2(1)
0
sage: l_2(3)
0
sage: l_2(4)
0
sage: l_2(2)
2
sage: l_2
(x - 1)*(x - 3)*(x - 4)
sage: l_2 /= (2-1)*(2-3)*(2-4)
sage: l_2(2)
1
sage: l_3 = (x - 1)*(x - 2)*(x-4) / ((3-1)*(3-2)*(3-4))
sage: l_3(1)
0
sage: l_3(2)
0
sage: l_3(3)
1
sage: l_3(4)
0
sage: l_1 = (x - 2)*(x - 3)*(x - 4) / ((1 - 2)*(1 - 3)*(1
....: - 4))
sage: l_1(1)
1
sage: l_1(2)
0
sage: l_1(3)
0
sage: l_1(4)
0
sage: l_1
-1/6*(x - 2)*(x - 3)*(x - 4)
sage: l_2
1/2*(x - 1)*(x - 3)*(x - 4)
sage: l_3
-1/2*(x - 1)*(x - 2)*(x - 4)
sage: l_4
----------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-24-cbdd82c87bb0> in <module>
----> 1 l_4
NameError: name 'l_4' is not defined
sage: l_4 = (x - 1)*(x - 2)*(x - 3) / ((4 - 1)*(4 - 2)*(4
....: - 3))
sage: l_4(1)
0
sage: l_4(2)
0
sage: l_4(3)
0
sage: l_4(4)
1
sage: for i in range(1, 5):
....: print(i, l_1(i), l_2(i), l_3(i), l_4(i))
....:
1 1 0 0 0
2 0 1 0 0
3 0 0 1 0
4 0 0 0 1
sage: f = 6 * l_1 + 4 * l_2 + 3 * l_3 + 0 * l_4
sage: l_2(2)
1
sage: for i in range(1, 5):
....: print(i, f(i))
....:
1 6
2 4
3 3
4 0
```

View File

@@ -1,19 +0,0 @@
param public_u
param public_v
param value
param serial
param randomness_coin
param randomness_value
constant generator_coin
constant generator_value_commit_value
constant generator_value_commit_random
public coin = mimc_hash(public_u, public_v, value, serial, randomness_coin)
private value_digits = unpack(value)
rangeproof_assert(value, value_digits)
public value_commit = jj_add(
jj_mul(value, generator_value_commit_value),
jj_mul(randomness_value, generator_value_commit_random)
)

View File

@@ -1,15 +0,0 @@
param value
private value_bits[] = unpack(value)
digit = 1
linear_combo = []
for bit in value_bits:
enforce (bit) * (1 - bit) == 0
linear_combo.append((digit bit))
digit = digit.double()
enforce (linear_combo) * (~one) == value

View File

@@ -1,34 +0,0 @@
param secret
param serial
param coin_merkle_branch[4]
param coin_merkle_is_right[4]
constant generator_coin
constant generator_value_commit_value
constant generator_value_commit_random
public nullifier = mimc_hash(secret, serial)
private (public_u, public_v) = jj_mul(secret, generator_coin)
public coin = mimc_hash(public_u, public_v, value, serial, randomness_coin)
let current = coin
for i in range(4):
branch = coin_merkle_branch[i]
is_right = coin_merkle_is_right[i]
# reverse(a, b, condition) = if condition (b, a) else (a, b)
private left, right = conditionally_reverse(current, branch, is_right)
# Only the last one is public
if i == 3:
current = public mimc_hash(left, right)
else:
current = private mimc_hash(left, right)
private value_digits = unpack(value)
rangeproof_assert(value, value_digits)
public value_commit = jj_add(
jj_mul(value, generator_value_commit_value),
jj_mul(randomness_value, generator_value_commit_random)
)

View File

@@ -1,10 +0,0 @@
We have a vanishing polynomial $Z(X) = X^N - 1$. Implicitly we are proving that
$$X^N = 1$$
What are the solutions to this polynomial? Well the answer is $\omega$ which is any root of $1$.
Therefore the solution to the formula $X^N - 1$ will be all the values of $X^N = 1$ or
$$X^N - 1 = (\omega - 1)(\omega^2 - 1)\cdots(\omega^{N - 1} - 1)$$

View File

@@ -1,10 +0,0 @@
accept_url = "127.0.0.1:7777"
rpc_url = "http://127.0.0.1:8000"
client_database_path = "cashier_client_database.db"
btc_endpoint = "tcp://electrum.blockstream.info:50001"
gateway_url = "127.0.0.1:3333"
log_path = "/tmp/cashierd.log"
cashierdb_path = "~/.config/darkfi/cashier.db"
client_walletdb_path = "~/.config/darkfi/cashier_client_walletdb.db"
password = "TEST_PASSWORD"
client_password = "TEST_PASSWORD"

View File

@@ -1,8 +0,0 @@
connect_url = "127.0.0.1:3333"
subscriber_url = "127.0.0.1:4444"
cashier_url = "127.0.0.1:7777"
rpc_url = "127.0.0.1:8000"
database_path = "~/.config/darkfi/database_client.db"
walletdb_path = "~/.config/darkfi/walletdb.db"
log_path = "/tmp/darkfid_service_daemon.log"
password = "TEST_PASSWORD"

View File

@@ -1,2 +0,0 @@
rpc_url = "http://127.0.0.1:8000"
log_path = "/tmp/drk_cli.log"

View File

@@ -1,4 +0,0 @@
connect_url = "127.0.0.1:3333"
publisher_url = "127.0.0.1:4444"
database_path = "gatewayd.db"
log_path = "/tmp/gatewayd.log"

View File

@@ -1,791 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "aes"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561"
dependencies = [
"aes-soft",
"aesni",
"cipher",
]
[[package]]
name = "aes-soft"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072"
dependencies = [
"cipher",
"opaque-debug",
]
[[package]]
name = "aesni"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce"
dependencies = [
"cipher",
"opaque-debug",
]
[[package]]
name = "arrayref"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
[[package]]
name = "arrayvec"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
[[package]]
name = "arrayvec"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4dc07131ffa69b8072d35f5007352af944213cde02545e2103680baed38fcd"
[[package]]
name = "autocfg"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "bigint"
version = "4.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0e8c8a600052b52482eff2cf4d810e462fdff1f656ac1ecb6232132a1ed7def"
dependencies = [
"byteorder",
"crunchy",
]
[[package]]
name = "bitvec"
version = "0.22.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5237f00a8c86130a0cc317830e558b966dd7850d48a953d998c813f01a41b527"
dependencies = [
"funty",
"radium",
"tap",
"wyz",
]
[[package]]
name = "blake2b_simd"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587"
dependencies = [
"arrayref",
"arrayvec 0.5.2",
"constant_time_eq",
]
[[package]]
name = "block-modes"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57a0e8073e8baa88212fb5823574c02ebccb395136ba9a164ab89379ec6072f0"
dependencies = [
"block-padding",
"cipher",
]
[[package]]
name = "block-padding"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae"
[[package]]
name = "bls12_381"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54757888b09a69be70b5ec303e382a74227392086ba808cb01eeca29233a2397"
dependencies = [
"ff",
"rand_core",
"subtle",
]
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cipher"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801"
dependencies = [
"generic-array",
]
[[package]]
name = "constant_time_eq"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
[[package]]
name = "crossbeam-channel"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4"
dependencies = [
"cfg-if",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
dependencies = [
"cfg-if",
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd"
dependencies = [
"cfg-if",
"crossbeam-utils",
"lazy_static",
"memoffset",
"scopeguard",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db"
dependencies = [
"cfg-if",
"lazy_static",
]
[[package]]
name = "crunchy"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda"
[[package]]
name = "crypto_api"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f855e87e75a4799e18b8529178adcde6fd4f97c1449ff4821e747ff728bb102"
[[package]]
name = "crypto_api_chachapoly"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d930b6a026ce9d358a17f9c9046c55d90b14bb847f36b6ebb6b19365d4feffb8"
dependencies = [
"crypto_api",
]
[[package]]
name = "digest"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
dependencies = [
"generic-array",
]
[[package]]
name = "either"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "ff"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0f40b2dcd8bc322217a5f6559ae5f9e9d1de202a2ecee2e9eafcbece7562a4f"
dependencies = [
"bitvec",
"rand_core",
"subtle",
]
[[package]]
name = "fpe"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a25080721bbcd2cd4d765b7d607ea350425fa087ce53cd3e31afcacdab850352"
dependencies = [
"aes",
"block-modes",
"num-bigint",
"num-integer",
"num-traits",
]
[[package]]
name = "funty"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1847abb9cb65d566acd5942e94aea9c8f547ad02c98e1649326fc0e8910b8b1e"
[[package]]
name = "generic-array"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getrandom"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "group"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c363a5301b8f153d80747126a04b3c82073b9fe3130571a9d170cacdeaf7912"
dependencies = [
"byteorder",
"ff",
"rand_core",
"subtle",
]
[[package]]
name = "halo2"
version = "0.0.1"
source = "git+https://github.com/zcash/halo2.git?rev=27c4187673a9c6ade13fbdbd4f20955530c22d7f#27c4187673a9c6ade13fbdbd4f20955530c22d7f"
dependencies = [
"blake2b_simd",
"ff",
"group",
"pasta_curves",
"rand",
"rayon",
]
[[package]]
name = "halo2_ecc"
version = "0.0.0"
source = "git+https://github.com/parazyd/orchard.git?rev=f9cc01c21010b31988129f9cbc2ca8c0bdbf2ee9#f9cc01c21010b31988129f9cbc2ca8c0bdbf2ee9"
dependencies = [
"arrayvec 0.7.1",
"bigint",
"ff",
"group",
"halo2",
"halo2_utilities",
"lazy_static",
"pasta_curves",
"rand",
]
[[package]]
name = "halo2_examples"
version = "0.1.0"
dependencies = [
"arrayvec 0.7.1",
"bigint",
"bitvec",
"ff",
"group",
"halo2",
"halo2_ecc",
"halo2_poseidon",
"halo2_utilities",
"lazy_static",
"orchard",
"pasta_curves",
"rand",
"sinsemilla",
"subtle",
]
[[package]]
name = "halo2_poseidon"
version = "0.0.0"
source = "git+https://github.com/parazyd/orchard.git?rev=f9cc01c21010b31988129f9cbc2ca8c0bdbf2ee9#f9cc01c21010b31988129f9cbc2ca8c0bdbf2ee9"
dependencies = [
"bitvec",
"ff",
"halo2",
"halo2_utilities",
"pasta_curves",
]
[[package]]
name = "halo2_utilities"
version = "0.0.0"
source = "git+https://github.com/parazyd/orchard.git?rev=f9cc01c21010b31988129f9cbc2ca8c0bdbf2ee9#f9cc01c21010b31988129f9cbc2ca8c0bdbf2ee9"
dependencies = [
"bigint",
"ff",
"halo2",
"pasta_curves",
"rand",
]
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "incrementalmerkletree"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16d75fb342984cc8cea665a9ef5607b4956569839ca098172082fa1b19bdaf02"
dependencies = [
"serde",
]
[[package]]
name = "jubjub"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "593fc4726ca80edb47ee18ab4d826719e25c2096991a79308b44fb915c6014ef"
dependencies = [
"bitvec",
"bls12_381",
"ff",
"group",
"rand_core",
"subtle",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1fa8cddc8fbbee11227ef194b5317ed014b8acbf15139bd716a18ad3fe99ec5"
[[package]]
name = "memoffset"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9"
dependencies = [
"autocfg",
]
[[package]]
name = "nonempty"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9e591e719385e6ebaeb5ce5d3887f7d5676fceca6411d1925ccc95745f3d6f7"
[[package]]
name = "num-bigint"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d0a3d5e207573f948a9e5376662aa743a2ea13f7c50a554d7af443a73fbfeba"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-integer"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
dependencies = [
"hermit-abi",
"libc",
]
[[package]]
name = "opaque-debug"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "orchard"
version = "0.0.0"
source = "git+https://github.com/parazyd/orchard.git?rev=f9cc01c21010b31988129f9cbc2ca8c0bdbf2ee9#f9cc01c21010b31988129f9cbc2ca8c0bdbf2ee9"
dependencies = [
"aes",
"arrayvec 0.7.1",
"bigint",
"bitvec",
"blake2b_simd",
"ff",
"fpe",
"group",
"halo2",
"halo2_ecc",
"halo2_poseidon",
"halo2_utilities",
"incrementalmerkletree",
"lazy_static",
"nonempty",
"pasta_curves",
"rand",
"reddsa",
"serde",
"sinsemilla",
"subtle",
"zcash_note_encryption",
]
[[package]]
name = "pasta_curves"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a21914ddc589b74e7638091c8e91a4e8b083ee5e1d0066d64407131b7570799"
dependencies = [
"blake2b_simd",
"ff",
"group",
"lazy_static",
"rand",
"static_assertions",
"subtle",
]
[[package]]
name = "ppv-lite86"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
[[package]]
name = "proc-macro2"
version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "radium"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb"
[[package]]
name = "rand"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
"rand_hc",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
dependencies = [
"getrandom",
]
[[package]]
name = "rand_hc"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7"
dependencies = [
"rand_core",
]
[[package]]
name = "rayon"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90"
dependencies = [
"autocfg",
"crossbeam-deque",
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-utils",
"lazy_static",
"num_cpus",
]
[[package]]
name = "reddsa"
version = "0.0.0"
source = "git+https://github.com/str4d/redjubjub.git?rev=d5d8c5f3bb704bad8ae88fe4a29ae1f744774cb2#d5d8c5f3bb704bad8ae88fe4a29ae1f744774cb2"
dependencies = [
"blake2b_simd",
"byteorder",
"digest",
"group",
"jubjub",
"pasta_curves",
"rand_core",
"serde",
"thiserror",
"zeroize",
]
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "serde"
version = "1.0.128"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1056a0db1978e9dbf0f6e4fca677f6f9143dc1c19de346f22cac23e422196834"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.128"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13af2fbb8b60a8950d6c72a56d2095c28870367cc8e10c55e9745bac4995a2c4"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "sinsemilla"
version = "0.0.0"
source = "git+https://github.com/parazyd/orchard.git?rev=f9cc01c21010b31988129f9cbc2ca8c0bdbf2ee9#f9cc01c21010b31988129f9cbc2ca8c0bdbf2ee9"
dependencies = [
"ff",
"group",
"halo2",
"halo2_ecc",
"halo2_utilities",
"pasta_curves",
"rand",
"subtle",
]
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "subtle"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
[[package]]
name = "syn"
version = "1.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7f58f7e8eaa0009c5fec437aabf511bd9933e4b2d7407bd05273c01a8906ea7"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "synstructure"
version = "0.12.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "474aaa926faa1603c40b7885a9eaea29b444d1cb2850cb7c0e37bb1a4182f4fa"
dependencies = [
"proc-macro2",
"quote",
"syn",
"unicode-xid",
]
[[package]]
name = "tap"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]]
name = "thiserror"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "typenum"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06"
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "version_check"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "wyz"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "129e027ad65ce1453680623c3fb5163cbf7107bfe1aa32257e7d0e63f9ced188"
dependencies = [
"tap",
]
[[package]]
name = "zcash_note_encryption"
version = "0.0.0"
source = "git+https://github.com/zcash/librustzcash.git?rev=13b023387bafdc7b5712c933dc0e16ee94b96a6a#13b023387bafdc7b5712c933dc0e16ee94b96a6a"
dependencies = [
"blake2b_simd",
"byteorder",
"crypto_api_chachapoly",
"ff",
"group",
"rand_core",
"subtle",
]
[[package]]
name = "zeroize"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "377db0846015f7ae377174787dd452e1c5f5a9050bc6f954911d01f116daa0cd"
dependencies = [
"zeroize_derive",
]
[[package]]
name = "zeroize_derive"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2c1e130bebaeab2f23886bf9acbaca14b092408c452543c857f66399cd6dab1"
dependencies = [
"proc-macro2",
"quote",
"syn",
"synstructure",
]

View File

@@ -1,47 +0,0 @@
[package]
name = "halo2_examples"
version = "0.1.0"
authors = ["narodnik <x@x.org>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
ff = "0.10"
group = "0.10"
pasta_curves = "0.1.2"
bitvec = "0.22"
rand = "0.8.4"
arrayvec = "0.7.0"
lazy_static = "1"
bigint = "4"
subtle = "2.3"
halo2 = "0.0"
[patch.crates-io]
halo2 = { git = "https://github.com/zcash/halo2.git", rev = "27c4187673a9c6ade13fbdbd4f20955530c22d7f" }
[dependencies.halo2_poseidon]
git = "https://github.com/parazyd/orchard.git"
#rev = "0d14f2390734e4710fc24a976f037dae3a6e7ac8"
rev = "f9cc01c21010b31988129f9cbc2ca8c0bdbf2ee9"
features = ["halo2"]
[dependencies.halo2_utilities]
git = "https://github.com/parazyd/orchard.git"
#rev = "0d14f2390734e4710fc24a976f037dae3a6e7ac8"
rev = "f9cc01c21010b31988129f9cbc2ca8c0bdbf2ee9"
[dependencies.halo2_ecc]
git = "https://github.com/parazyd/orchard.git"
#rev = "0d14f2390734e4710fc24a976f037dae3a6e7ac8"
rev = "f9cc01c21010b31988129f9cbc2ca8c0bdbf2ee9"
[dependencies.sinsemilla]
git = "https://github.com/parazyd/orchard.git"
#rev = "0d14f2390734e4710fc24a976f037dae3a6e7ac8"
rev = "f9cc01c21010b31988129f9cbc2ca8c0bdbf2ee9"
[dependencies.orchard]
git = "https://github.com/parazyd/orchard.git"
rev = "f9cc01c21010b31988129f9cbc2ca8c0bdbf2ee9"

View File

@@ -1,6 +0,0 @@
Always use the --release flag otherwise it's too slow:
```
cargo run --release --bin simple3
```

View File

@@ -1,73 +0,0 @@
use std::iter;
use group::{ff::PrimeFieldBits, Curve};
use halo2::{
arithmetic::{CurveAffine, Field, FieldExt},
pasta::{Fp, Fq},
};
use halo2_ecc::gadget::FixedPoints;
use halo2_poseidon::primitive::{ConstantLength, Hash, P128Pow5T3 as OrchardNullifier};
use orchard::constants::{fixed_bases::OrchardFixedBases, sinsemilla::MERKLE_CRH_PERSONALIZATION};
use rand::rngs::OsRng;
use sinsemilla::primitive::{CommitDomain, HashDomain};
use halo2_examples::pedersen_commitment;
fn main() {
let secret_key = Fq::random(&mut OsRng);
let serial = Fp::random(&mut OsRng);
// Sinsemilla hash
let domain = HashDomain::new(MERKLE_CRH_PERSONALIZATION);
let nullifier = domain
.hash(
iter::empty()
.chain(secret_key.to_le_bits().iter().by_val())
.chain(serial.to_le_bits().iter().by_val()),
)
.unwrap();
let public_key = OrchardFixedBases::SpendAuthG.generator() * secret_key;
let coords = public_key.to_affine().coordinates().unwrap();
let value = 110;
let asset = 1;
let value_blind = Fq::random(&mut OsRng);
let asset_blind = Fq::random(&mut OsRng);
let coin_blind = Fp::random(&mut OsRng);
// FIXME:
let messages = [
[*coords.x(), *coords.y()],
[Fp::from(value), Fp::from(asset)],
[serial, coin_blind],
];
let mut coin = Fp::zero();
for msg in messages.iter() {
coin += Hash::init(OrchardNullifier, ConstantLength::<2>).hash(*msg);
}
// TODO: Merkle
let value_commit = pedersen_commitment(value, value_blind);
let asset_commit = pedersen_commitment(asset, asset_blind);
let value_coords = value_commit.to_affine().coordinates().unwrap();
let asset_coords = value_commit.to_affine().coordinates().unwrap();
let sig_secret = Fq::random(&mut OsRng);
let sig_pubkey = OrchardFixedBases::SpendAuthG.generator() * sig_secret;
let sig_pk_coords = sig_pubkey.to_affine().coordinates().unwrap();
let mut public_inputs = vec![
nullifier,
*value_coords.x(),
*value_coords.y(),
*asset_coords.x(),
*asset_coords.y(),
// merkle_root,
*sig_pk_coords.x(),
*sig_pk_coords.y(),
];
}

View File

@@ -1,439 +0,0 @@
use std::{convert::TryInto, time::Instant};
use group::{ff::Field, Curve, Group};
use halo2::{
arithmetic::CurveAffine,
circuit::{floor_planner, Layouter},
dev::MockProver,
pasta::{vesta, Ep, Fp, Fq},
plonk,
plonk::{Circuit, ConstraintSystem, Error},
poly::commitment,
transcript::{Blake2bRead, Blake2bWrite},
};
use halo2_ecc::{chip::EccChip, gadget::FixedPoint};
use halo2_poseidon::{
gadget::{Hash as PoseidonHash, Word},
pow5t3::{Pow5T3Chip as PoseidonChip, StateWord},
primitive::{ConstantLength, Hash, P128Pow5T3 as OrchardNullifier},
};
use halo2_utilities::{
lookup_range_check::LookupRangeCheckConfig, CellValue, UtilitiesInstructions, Var,
};
use orchard::constants::fixed_bases::OrchardFixedBases;
use rand::rngs::OsRng;
use halo2_examples::{circuit::Config, pedersen_commitment};
const K: u32 = 9;
#[derive(Default, Debug)]
struct MintCircuit {
pub_x: Option<Fp>, // x coordinate for pubkey
pub_y: Option<Fp>, // y coordinate for pubkey
value: Option<Fp>, // The value of this coin
asset: Option<Fp>, // The asset ID
serial: Option<Fp>, // Unique serial number corresponding to this coin
coin_blind: Option<Fp>, // Random blinding factor for coin
value_blind: Option<Fq>, // Random blinding factor for value commitment
asset_blind: Option<Fq>, // Random blinding factor for the asset ID
}
impl UtilitiesInstructions<Fp> for MintCircuit {
type Var = CellValue<Fp>;
}
impl Circuit<Fp> for MintCircuit {
type Config = Config;
type FloorPlanner = floor_planner::V1;
//type FloorPlanner = SimpleFloorPlanner;
fn without_witnesses(&self) -> Self {
Self::default()
}
fn configure(meta: &mut ConstraintSystem<Fp>) -> Self::Config {
let advices = [
meta.advice_column(),
meta.advice_column(),
meta.advice_column(),
meta.advice_column(),
meta.advice_column(),
meta.advice_column(),
meta.advice_column(),
meta.advice_column(),
meta.advice_column(),
meta.advice_column(),
];
let q_add = meta.selector();
let table_idx = meta.lookup_table_column();
// let lookup = (
// table_idx,
// meta.lookup_table_column(),
// meta.lookup_table_column(),
// );
let primary = meta.instance_column();
meta.enable_equality(primary.into());
for advice in advices.iter() {
meta.enable_equality((*advice).into());
}
let lagrange_coeffs = [
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
];
let rc_a = lagrange_coeffs[2..5].try_into().unwrap();
let rc_b = lagrange_coeffs[5..8].try_into().unwrap();
meta.enable_constant(lagrange_coeffs[0]);
let range_check = LookupRangeCheckConfig::configure(meta, advices[9], table_idx);
let ecc_config = EccChip::<OrchardFixedBases>::configure(
meta,
advices,
lagrange_coeffs,
range_check.clone(),
);
let poseidon_config = PoseidonChip::configure(
meta,
OrchardNullifier,
advices[6..9].try_into().unwrap(),
advices[5],
rc_a,
rc_b,
);
Config {
primary,
q_add,
advices,
ecc_config,
poseidon_config,
}
}
fn synthesize(
&self,
config: Self::Config,
mut layouter: impl Layouter<Fp>,
) -> Result<(), Error> {
// Construct the ECC chip.
let ecc_chip = EccChip::construct(config.ecc_config.clone());
let pub_x = self.load_private(
layouter.namespace(|| "load pubkey x"),
config.advices[0],
self.pub_x,
)?;
let pub_y = self.load_private(
layouter.namespace(|| "load pubkey y"),
config.advices[0],
self.pub_y,
)?;
let value = self.load_private(
layouter.namespace(|| "load value"),
config.advices[0],
self.value,
)?;
let asset = self.load_private(
layouter.namespace(|| "load asset"),
config.advices[0],
self.asset,
)?;
let serial = self.load_private(
layouter.namespace(|| "load serial"),
config.advices[0],
self.serial,
)?;
let coin_blind = self.load_private(
layouter.namespace(|| "load coin_blind"),
config.advices[0],
self.coin_blind,
)?;
// =============
// = Coin hash =
// =============
// TODO: This is a hack until issue is resolved in poseidon gadget
let mut coin = Fp::zero();
let messages = [[pub_x, pub_y], [value, asset], [serial, coin_blind]];
//let messages = [[pub_x, pub_y], [value, asset]];
//let messages = [[pub_x, pub_y]];
for msg in messages.iter() {
let poseidon_message = layouter.assign_region(
|| "load message",
|mut region| {
let mut message_word = |i: usize| {
let val = msg[i].value();
let var = region.assign_advice(
|| format!("load message_{}", i),
config.poseidon_config.state()[i],
0,
|| val.ok_or(Error::SynthesisError),
)?;
region.constrain_equal(var, msg[i].cell())?;
Ok(Word::<_, _, OrchardNullifier, 3, 2>::from_inner(
StateWord::new(var, val),
))
};
Ok([message_word(0)?, message_word(1)?])
},
)?;
let poseidon_hasher = PoseidonHash::init(
PoseidonChip::construct(config.poseidon_config.clone()),
layouter.namespace(|| "Poseidon init"),
ConstantLength::<2>,
)?;
let poseidon_output =
poseidon_hasher.hash(layouter.namespace(|| "Poseidon hash"), poseidon_message)?;
let poseidon_output: CellValue<Fp> = poseidon_output.inner().into();
if !poseidon_output.value().is_none() {
coin += poseidon_output.value().unwrap();
}
}
// if coin != Fp::zero() {
// println!("circuit hash: {:?}", coin);
// }
let hash = self.load_private(
layouter.namespace(|| "load hash"),
config.advices[0],
Some(coin),
)?;
// Constrain the coin C; index in public values is 0
layouter.constrain_instance(hash.cell(), config.primary, 0)?;
// ====================
// = Value commitment =
// ====================
// This constant one is used for multiplication
let one = self.load_constant(
layouter.namespace(|| "constant one"),
config.advices[0],
Fp::one(),
)?;
// v*G_1
let (commitment, _) = {
let value_commit_v = OrchardFixedBases::ValueCommitV;
let value_commit_v = FixedPoint::from_inner(ecc_chip.clone(), value_commit_v);
value_commit_v.mul_short(layouter.namespace(|| "[value] ValueCommitV"), (value, one))?
};
// r_V*G_2
let (blind, _rcv) = {
let rcv = self.value_blind;
let value_commit_r = OrchardFixedBases::ValueCommitR;
let value_commit_r = FixedPoint::from_inner(ecc_chip.clone(), value_commit_r);
value_commit_r.mul(layouter.namespace(|| "[value_blind] ValueCommitR"), rcv)?
};
// Constrain the x and y; indexes in public values are 1 and 2
let value_commit = commitment.add(layouter.namespace(|| "valuecommit"), &blind)?;
layouter.constrain_instance(value_commit.inner().x().cell(), config.primary, 1)?;
layouter.constrain_instance(value_commit.inner().y().cell(), config.primary, 2)?;
// ====================
// = Asset commitment =
// ====================
// a*G_1
let (commitment, _) = {
let asset_commit_v = OrchardFixedBases::ValueCommitV;
let asset_commit_v = FixedPoint::from_inner(ecc_chip.clone(), asset_commit_v);
asset_commit_v.mul_short(layouter.namespace(|| "[asset] ValueCommitV"), (asset, one))?
};
// r_A*G_2
let (blind, _rca) = {
let rca = self.asset_blind;
let asset_commit_r = OrchardFixedBases::ValueCommitR;
let asset_commit_r = FixedPoint::from_inner(ecc_chip.clone(), asset_commit_r);
asset_commit_r.mul(layouter.namespace(|| "[asset_blind] ValueCommitR"), rca)?
};
// Constrain the x and y; indexes in public values are 3 and 4
let asset_commit = commitment.add(layouter.namespace(|| "assetcommit"), &blind)?;
layouter.constrain_instance(asset_commit.inner().x().cell(), config.primary, 3)?;
layouter.constrain_instance(asset_commit.inner().y().cell(), config.primary, 4)?;
Ok(())
}
}
#[derive(Debug)]
struct VerifyingKey {
params: commitment::Params<vesta::Affine>,
vk: plonk::VerifyingKey<vesta::Affine>,
}
impl VerifyingKey {
fn build() -> Self {
let params = commitment::Params::new(K);
let circuit: MintCircuit = Default::default();
let vk = plonk::keygen_vk(&params, &circuit).unwrap();
VerifyingKey { params, vk }
}
}
#[derive(Debug)]
struct ProvingKey {
params: commitment::Params<vesta::Affine>,
pk: plonk::ProvingKey<vesta::Affine>,
}
impl ProvingKey {
fn build() -> Self {
let params = commitment::Params::new(K);
let circuit: MintCircuit = Default::default();
let vk = plonk::keygen_vk(&params, &circuit).unwrap();
let pk = plonk::keygen_pk(&params, vk, &circuit).unwrap();
ProvingKey { params, pk }
}
}
#[derive(Clone, Debug)]
struct Proof(Vec<u8>);
impl AsRef<[u8]> for Proof {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl Proof {
fn create(pk: &ProvingKey, circuits: &[MintCircuit], pubinputs: &[Fp]) -> Result<Self, Error> {
let mut transcript = Blake2bWrite::<_, vesta::Affine, _>::init(vec![]);
plonk::create_proof(
&pk.params,
&pk.pk,
circuits,
&[&[pubinputs]],
&mut transcript,
)?;
Ok(Proof(transcript.finalize()))
}
fn verify(&self, vk: &VerifyingKey, pubinputs: &[Fp]) -> Result<(), plonk::Error> {
let msm = vk.params.empty_msm();
let mut transcript = Blake2bRead::init(&self.0[..]);
let guard = plonk::verify_proof(&vk.params, &vk.vk, msm, &[&[pubinputs]], &mut transcript)?;
let msm = guard.clone().use_challenges();
if msm.eval() {
Ok(())
} else {
Err(Error::ConstraintSystemFailure)
}
}
// fn new(bytes: Vec<u8>) -> Self {
// Proof(bytes)
// }
}
fn main() {
let pubkey = Ep::random(&mut OsRng);
let coords = pubkey.to_affine().coordinates().unwrap();
let value = 110;
let asset = 1;
let value_blind = Fq::random(&mut OsRng);
let asset_blind = Fq::random(&mut OsRng);
let serial = Fp::random(&mut OsRng);
let coin_blind = Fp::random(&mut OsRng);
let mut coin = Fp::zero();
let messages = [
[*coords.x(), *coords.y()],
[Fp::from(value), Fp::from(asset)],
[serial, coin_blind],
];
// TODO: This is a hack until issue is fixed in poseidon gadget
for msg in messages.iter() {
coin += Hash::init(OrchardNullifier, ConstantLength::<2>).hash(*msg);
}
let value_commit = pedersen_commitment(value, value_blind);
let value_coords = value_commit.to_affine().coordinates().unwrap();
let asset_commit = pedersen_commitment(asset, asset_blind);
let asset_coords = asset_commit.to_affine().coordinates().unwrap();
let mut public_inputs = vec![
coin,
*value_coords.x(),
*value_coords.y(),
*asset_coords.x(),
*asset_coords.y(),
];
let circuit = MintCircuit {
pub_x: Some(*coords.x()),
pub_y: Some(*coords.y()),
value: Some(vesta::Scalar::from(value)),
asset: Some(vesta::Scalar::from(asset)),
serial: Some(serial),
coin_blind: Some(coin_blind),
value_blind: Some(value_blind),
asset_blind: Some(asset_blind),
};
// Valid MockProver
let prover = MockProver::run(K, &circuit, vec![public_inputs.clone()]).unwrap();
assert_eq!(prover.verify(), Ok(()));
// Add 1 to break the public inputs
public_inputs[0] += Fp::from(0xdeadbeef);
// Invalid MockProver
let prover = MockProver::run(K, &circuit, vec![public_inputs.clone()]).unwrap();
assert!(prover.verify().is_err());
// Remove 1 to make the public inputs valid again
public_inputs[0] -= Fp::from(0xdeadbeef);
// Actual ZK proof
let start = Instant::now();
let vk = VerifyingKey::build();
let pk = ProvingKey::build();
println!("\nSetup: [{:?}]", start.elapsed());
let start = Instant::now();
let proof = Proof::create(&pk, &[circuit], &public_inputs).unwrap();
println!("Prove: [{:?}]", start.elapsed());
let start = Instant::now();
assert!(proof.verify(&vk, &public_inputs).is_ok());
println!("Verify: [{:?}]", start.elapsed());
}

View File

@@ -1,298 +0,0 @@
use std::convert::TryInto;
use std::time::Instant;
use halo2::{
circuit::{floor_planner, Layouter},
pasta::{vesta, Fp},
plonk,
plonk::{
Advice, Circuit, Column, ConstraintSystem, Error, Instance as InstanceColumn, Selector,
},
poly::{commitment, Rotation},
transcript::{Blake2bRead, Blake2bWrite},
};
use halo2_poseidon::{
gadget::{Hash as PoseidonHash, Word},
pow5t3::{Pow5T3Chip as PoseidonChip, Pow5T3Config as PoseidonConfig, StateWord},
primitive::{ConstantLength, Hash, P128Pow5T3 as OrchardNullifier},
};
use halo2_utilities::{copy, CellValue, UtilitiesInstructions, Var};
const K: u32 = 6;
#[derive(Clone, Debug)]
struct Config {
primary: Column<InstanceColumn>,
q_add: Selector,
advices: [Column<Advice>; 10],
poseidon_config: PoseidonConfig<Fp>,
}
#[derive(Default, Debug)]
struct HashCircuit {
a: Option<Fp>, // First input for hash
b: Option<Fp>, // Second input for hash
c: Option<Fp>, // c is summed with hash
}
impl UtilitiesInstructions<Fp> for HashCircuit {
type Var = CellValue<Fp>;
}
impl Circuit<Fp> for HashCircuit {
type Config = Config;
type FloorPlanner = floor_planner::V1;
fn without_witnesses(&self) -> Self {
Self::default()
}
fn configure(meta: &mut ConstraintSystem<Fp>) -> Self::Config {
// 10 advice columns
let advices = [
meta.advice_column(),
meta.advice_column(),
meta.advice_column(),
meta.advice_column(),
meta.advice_column(),
meta.advice_column(),
meta.advice_column(),
meta.advice_column(),
meta.advice_column(),
meta.advice_column(),
];
// Addition of two field elements: poseidon_hash(a, b) + c
let q_add = meta.selector();
meta.create_gate("poseidon_hash(a, b) + c", |meta| {
let q_add = meta.query_selector(q_add);
let sum = meta.query_advice(advices[6], Rotation::cur());
let hash = meta.query_advice(advices[7], Rotation::cur());
let c = meta.query_advice(advices[8], Rotation::cur());
vec![q_add * (hash + c - sum)]
});
let primary = meta.instance_column();
meta.enable_equality(primary.into());
for advice in advices.iter() {
meta.enable_equality((*advice).into());
}
let lagrange_coeffs = [
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
];
let rc_a = lagrange_coeffs[2..5].try_into().unwrap();
let rc_b = lagrange_coeffs[5..8].try_into().unwrap();
meta.enable_constant(lagrange_coeffs[0]);
let poseidon_config = PoseidonChip::configure(
meta,
OrchardNullifier,
advices[6..9].try_into().unwrap(),
advices[5],
rc_a,
rc_b,
);
Config {
primary,
q_add,
advices,
poseidon_config,
}
}
fn synthesize(
&self,
config: Self::Config,
mut layouter: impl Layouter<Fp>,
) -> Result<(), Error> {
let a = self.load_private(layouter.namespace(|| "load a"), config.advices[0], self.a)?;
let b = self.load_private(layouter.namespace(|| "load b"), config.advices[0], self.b)?;
let c = self.load_private(layouter.namespace(|| "load c"), config.advices[0], self.c)?;
let hash = {
let message = [a, b];
let poseidon_message = layouter.assign_region(
|| "load message",
|mut region| {
let mut message_word = |i: usize| {
let value = message[i].value();
let var = region.assign_advice(
|| format!("load message_{}", i),
config.poseidon_config.state()[i],
0,
|| value.ok_or(Error::SynthesisError),
)?;
region.constrain_equal(var, message[i].cell())?;
Ok(Word::<_, _, OrchardNullifier, 3, 2>::from_inner(
StateWord::new(var, value),
))
};
Ok([message_word(0)?, message_word(1)?])
},
)?;
let poseidon_hasher = PoseidonHash::init(
//config.poseidon_chip(),
PoseidonChip::construct(config.poseidon_config.clone()),
layouter.namespace(|| "Poseidon init"),
ConstantLength::<2>,
)?;
let poseidon_output = poseidon_hasher.hash(
layouter.namespace(|| "Poseidon hash (a, b)"),
poseidon_message,
)?;
let poseidon_output: CellValue<Fp> = poseidon_output.inner().into();
poseidon_output
};
// Add hash output to c
let scalar = layouter.assign_region(
|| " `scalar` = poseidon_hash(a, b) + c",
|mut region| {
config.q_add.enable(&mut region, 0)?;
copy(&mut region, || "copy hash", config.advices[7], 0, &hash)?;
copy(&mut region, || "copy c", config.advices[8], 0, &c)?;
let scalar_val = hash.value().zip(c.value()).map(|(hash, c)| hash + c);
let cell = region.assign_advice(
|| "poseidon_hash(a, b) + c",
config.advices[6],
0,
|| scalar_val.ok_or(Error::SynthesisError),
)?;
Ok(CellValue::new(cell, scalar_val))
},
)?;
layouter.constrain_instance(scalar.cell(), config.primary, 0)
}
}
#[derive(Debug)]
struct VerifyingKey {
params: commitment::Params<vesta::Affine>,
vk: plonk::VerifyingKey<vesta::Affine>,
}
impl VerifyingKey {
fn build() -> Self {
let params = commitment::Params::new(K);
let circuit: HashCircuit = Default::default();
let vk = plonk::keygen_vk(&params, &circuit).unwrap();
VerifyingKey { params, vk }
}
}
#[derive(Debug)]
struct ProvingKey {
params: commitment::Params<vesta::Affine>,
pk: plonk::ProvingKey<vesta::Affine>,
}
impl ProvingKey {
fn build() -> Self {
let params = commitment::Params::new(K);
let circuit: HashCircuit = Default::default();
let vk = plonk::keygen_vk(&params, &circuit).unwrap();
let pk = plonk::keygen_pk(&params, vk, &circuit).unwrap();
ProvingKey { params, pk }
}
}
#[derive(Clone, Debug)]
struct Proof(Vec<u8>);
impl AsRef<[u8]> for Proof {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl Proof {
fn create(pk: &ProvingKey, circuits: &[HashCircuit], pubinputs: &[Fp]) -> Result<Self, Error> {
let mut transcript = Blake2bWrite::<_, vesta::Affine, _>::init(vec![]);
plonk::create_proof(
&pk.params,
&pk.pk,
circuits,
&[&[pubinputs]],
&mut transcript,
)?;
Ok(Proof(transcript.finalize()))
}
fn verify(&self, vk: &VerifyingKey, pubinputs: &[Fp]) -> Result<(), plonk::Error> {
let msm = vk.params.empty_msm();
let mut transcript = Blake2bRead::init(&self.0[..]);
let guard = plonk::verify_proof(&vk.params, &vk.vk, msm, &[&[pubinputs]], &mut transcript)?;
let msm = guard.clone().use_challenges();
if msm.eval() {
Ok(())
} else {
Err(Error::ConstraintSystemFailure)
}
}
// fn new(bytes: Vec<u8>) -> Self {
// Proof(bytes)
// }
}
fn main() {
let a = Fp::from(13);
let b = Fp::from(69);
let c = Fp::from(42);
let message = [a, b];
let output = Hash::init(OrchardNullifier, ConstantLength::<2>).hash(message);
let circuit = HashCircuit {
a: Some(a),
b: Some(b),
c: Some(c),
};
let sum = output + c;
// Correct:
let public_inputs = vec![sum];
// Incorrect:
// let public_inputs = vec![sum + Fp::one()];
let start = Instant::now();
let vk = VerifyingKey::build();
let pk = ProvingKey::build();
println!("Setup: [{:?}]", start.elapsed());
let start = Instant::now();
let proof = Proof::create(&pk, &[circuit], &public_inputs).unwrap();
println!("Prove: [{:?}]", start.elapsed());
let start = Instant::now();
assert!(proof.verify(&vk, &public_inputs).is_ok());
println!("Verify: [{:?}]", start.elapsed());
}

View File

@@ -1,130 +0,0 @@
use halo2::{
circuit::{SimpleFloorPlanner, Chip, Layouter},
pasta::{EqAffine, Fp},
plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Expression, Selector, create_proof, verify_proof, keygen_vk, keygen_pk},
poly::{commitment::Params, Rotation},
transcript::{Blake2bRead, Blake2bWrite, Challenge255},
};
use std::time::Instant;
#[derive(Clone, Debug)]
struct CoolConfig {
a_col: Column<Advice>,
s_range: Selector,
}
struct CoolChip {
config: CoolConfig
}
impl Chip<Fp> for CoolChip {
type Config = CoolConfig;
type Loaded = ();
fn config(&self) -> &Self::Config {
&self.config
}
fn loaded(&self) -> &Self::Loaded {
&()
}
}
impl CoolChip {
fn construct(config: CoolConfig) -> Self {
Self { config }
}
fn configure(cs: &mut ConstraintSystem<Fp>) -> CoolConfig {
let a_col = cs.advice_column();
let s_range = cs.selector();
cs.create_gate("check", |cs| {
let a = cs.query_advice(a_col, Rotation::cur());
let s_range = cs.query_selector(s_range);
vec![s_range * (a - Expression::Constant(Fp::from(2)))]
});
CoolConfig { a_col, s_range }
}
fn alloc_and_check(
&self,
layouter: &mut impl Layouter<Fp>,
a: Option<Fp>,
) -> Result<(), Error> {
layouter.assign_region(
|| "load private inputs",
|mut region| {
let row_offset = 0;
self.config.s_range.enable(&mut region, row_offset)?;
region.assign_advice(
|| "private input 'a'",
self.config.a_col,
row_offset,
|| a.ok_or(Error::SynthesisError),
)?;
Ok(())
},
)
}
}
#[derive(Clone)]
struct CoolCircuit {
// Private input.
a: Option<Fp>,
}
impl Circuit<Fp> for CoolCircuit {
type Config = CoolConfig;
type FloorPlanner = SimpleFloorPlanner;
fn without_witnesses(&self) -> Self {
Self { a: None }
}
fn configure(cs: &mut ConstraintSystem<Fp>) -> Self::Config {
CoolChip::configure(cs)
}
fn synthesize(&self, config: Self::Config, mut layouter: impl Layouter<Fp>) -> Result<(), Error> {
let chip = CoolChip::construct(config);
chip.alloc_and_check(&mut layouter, self.a)
}
}
fn main() {
let start = Instant::now();
let params: Params<EqAffine> = Params::new(4);
let empty_circuit = CoolCircuit { a: None };
let vk = keygen_vk(&params, &empty_circuit).expect("keygen_vk should not fail");
let pk = keygen_pk(&params, vk, &empty_circuit).expect("keygen_pk should not fail");
println!("Setup: [{:?}]", start.elapsed());
let start = Instant::now();
let circuit = CoolCircuit {
a: Some(Fp::from(2)),
};
// Create a proof
let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]);
create_proof(&params, &pk, &[circuit], &[&[]], &mut transcript)
.expect("proof generation should not fail");
let proof = transcript.finalize();
println!("Prove: [{:?}]", start.elapsed());
let start = Instant::now();
let msm = params.empty_msm();
let mut transcript = Blake2bRead::<_, _, Challenge255<_>>::init(&proof[..]);
let verification = verify_proof(&params, pk.get_vk(), msm, &[&[]], &mut transcript);
if let Err(err) = verification {
panic!("error {:?}", err);
}
let guard = verification.unwrap();
let msm = guard.clone().use_challenges();
assert!(msm.eval());
println!("Verify: [{:?}]", start.elapsed());
}

View File

@@ -1,267 +0,0 @@
use halo2::{
circuit::{SimpleFloorPlanner, Cell, Chip, Layouter},
pasta::{EqAffine, Fp},
plonk::{Advice, Any, Circuit, Column, ConstraintSystem, Error, Expression, Selector, create_proof, verify_proof, keygen_vk, keygen_pk, Permutation},
poly::{commitment::{Blind, Params}, Rotation},
transcript::{Blake2bRead, Blake2bWrite, Challenge255},
};
use group::Curve;
use std::time::Instant;
#[derive(Clone, Debug)]
struct CoolConfig {
a_col: Column<Advice>,
b_col: Column<Advice>,
permute: Permutation,
s_range: Selector,
s_mul: Selector,
s_pub: Selector,
}
struct CoolChip {
config: CoolConfig
}
impl Chip<Fp> for CoolChip {
type Config = CoolConfig;
type Loaded = ();
fn config(&self) -> &Self::Config {
&self.config
}
fn loaded(&self) -> &Self::Loaded {
&()
}
}
#[derive(Clone, Debug)]
struct Number {
cell: Cell,
value: Option<Fp>,
}
impl CoolChip {
fn construct(config: CoolConfig) -> Self {
Self { config }
}
fn configure(cs: &mut ConstraintSystem<Fp>) -> CoolConfig {
let a_col = cs.advice_column();
let b_col = cs.advice_column();
let instance = cs.instance_column();
let permute = {
// Convert advice columns into an "any" columns.
let cols: [Column<Any>; 2] = [a_col.into(), b_col.into()];
Permutation::new(cs, &cols)
};
let s_range = cs.selector();
let s_mul = cs.selector();
let s_pub = cs.selector();
cs.create_gate("check", |cs| {
let a = cs.query_advice(a_col, Rotation::cur());
let s_range = cs.query_selector(s_range);
vec![s_range * (a - Expression::Constant(Fp::from(2)))]
});
cs.create_gate("mul", |cs| {
let lhs = cs.query_advice(a_col, Rotation::cur());
let rhs = cs.query_advice(b_col, Rotation::cur());
let out = cs.query_advice(a_col, Rotation::next());
let s_mul = cs.query_selector(s_mul);
vec![s_mul * (lhs * rhs + out * -Fp::one())]
});
cs.create_gate("public input", |cs| {
let a = cs.query_advice(b_col, Rotation::cur());
let p = cs.query_instance(instance, Rotation::cur());
let s = cs.query_selector(s_pub);
vec![s * (p + a * -Fp::one())]
});
CoolConfig { a_col, b_col, permute, s_range, s_mul, s_pub }
}
fn alloc_left(
&self,
layouter: &mut impl Layouter<Fp>,
value: Option<Fp>
) -> Result<Number, Error> {
layouter.assign_region(
|| "load left private input",
|mut region| {
let cell = region.assign_advice(
|| "private input 'a'",
self.config.a_col,
0,
|| value.ok_or(Error::SynthesisError),
)?;
Ok(Number { cell, value })
}
)
}
fn check(
&self,
layouter: &mut impl Layouter<Fp>,
number: Number
) -> Result<(), Error> {
layouter.assign_region(
|| "load private inputs",
|mut region| {
self.config.s_range.enable(&mut region, 0)?;
let a = region.assign_advice(
|| "lhs",
self.config.a_col,
0,
|| number.value.ok_or(Error::SynthesisError),
)?;
region.constrain_equal(&self.config.permute, number.cell, a)?;
Ok(())
},
)
}
fn mul(
&self,
layouter: &mut impl Layouter<Fp>,
a: Number,
b: Number
) -> Result<Number, Error> {
let mut out = None;
layouter.assign_region(
|| "mul",
|mut region| {
self.config.s_mul.enable(&mut region, 0)?;
let lhs = region.assign_advice(
|| "lhs",
self.config.a_col,
0,
|| a.value.ok_or(Error::SynthesisError),
)?;
let rhs = region.assign_advice(
|| "rhs",
self.config.b_col,
0,
|| b.value.ok_or(Error::SynthesisError),
)?;
region.constrain_equal(&self.config.permute, a.cell, lhs)?;
region.constrain_equal(&self.config.permute, b.cell, rhs)?;
let value = a.value.and_then(|a| b.value.map(|b| a * b));
let cell = region.assign_advice(
|| "lhs * rhs",
self.config.a_col,
1,
|| value.ok_or(Error::SynthesisError),
)?;
out = Some(Number { cell, value });
Ok(())
},
)?;
Ok(out.unwrap())
}
fn expose_public(&self, layouter: &mut impl Layouter<Fp>, num: Number) -> Result<(), Error> {
layouter.assign_region(
|| "expose public",
|mut region| {
self.config.s_pub.enable(&mut region, 0)?;
let out = region.assign_advice(
|| "public advice",
self.config.b_col,
0,
|| num.value.ok_or(Error::SynthesisError),
)?;
region.constrain_equal(&self.config.permute, num.cell, out)?;
Ok(())
},
)
}
}
#[derive(Clone)]
struct CoolCircuit {
// Private input.
a: Option<Fp>,
}
impl Circuit<Fp> for CoolCircuit {
type Config = CoolConfig;
type FloorPlanner = SimpleFloorPlanner;
fn without_witnesses(&self) -> Self {
Self { a: None }
}
fn configure(cs: &mut ConstraintSystem<Fp>) -> Self::Config {
CoolChip::configure(cs)
}
fn synthesize(&self, config: Self::Config, mut layouter: impl Layouter<Fp>) -> Result<(), Error> {
let chip = CoolChip::construct(config);
let a = chip.alloc_left(&mut layouter, self.a)?;
chip.check(&mut layouter, a.clone())?;
let a2 = chip.mul(&mut layouter, a.clone(), a)?;
chip.expose_public(&mut layouter, a2)?;
Ok(())
}
}
fn main() {
let k = 6;
let start = Instant::now();
let params: Params<EqAffine> = Params::new(k);
let empty_circuit = CoolCircuit { a: None };
let vk = keygen_vk(&params, &empty_circuit).expect("keygen_vk should not fail");
let pk = keygen_pk(&params, vk, &empty_circuit).expect("keygen_pk should not fail");
println!("Setup: [{:?}]", start.elapsed());
let start = Instant::now();
let circuit = CoolCircuit {
a: Some(Fp::from(2)),
};
let mut public_inputs = pk.get_vk().get_domain().empty_lagrange();
public_inputs[4] = Fp::from(4);
// Create a proof
let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]);
create_proof(&params, &pk, &[circuit], &[&[public_inputs.clone()]], &mut transcript)
.expect("proof generation should not fail");
let proof = transcript.finalize();
println!("Prove: [{:?}]", start.elapsed());
let pubinput = params
.commit_lagrange(&public_inputs, Blind::default())
.to_affine();
let pubinput_slice = &[pubinput];
let start = Instant::now();
let msm = params.empty_msm();
let mut transcript = Blake2bRead::<_, _, Challenge255<_>>::init(&proof[..]);
let verification = verify_proof(&params, pk.get_vk(), msm, &[pubinput_slice], &mut transcript);
if let Err(err) = verification {
panic!("error {:?}", err);
}
let guard = verification.unwrap();
let msm = guard.clone().use_challenges();
assert!(msm.eval());
println!("Verify: [{:?}]", start.elapsed());
}

View File

@@ -1,16 +0,0 @@
use halo2::{
pasta::pallas,
plonk::{Advice, Column, Instance as InstanceColumn, Selector},
};
use halo2_ecc::chip::EccConfig;
use halo2_poseidon::pow5t3::Pow5T3Config as PoseidonConfig;
#[derive(Clone, Debug)]
pub struct Config {
pub primary: Column<InstanceColumn>,
pub q_add: Selector,
pub advices: [Column<Advice>; 10],
pub ecc_config: EccConfig,
pub poseidon_config: PoseidonConfig<pallas::Base>,
}

View File

@@ -1,19 +0,0 @@
pub mod circuit;
use halo2::{
arithmetic::{CurveExt, FieldExt},
pasta::{Ep, Fq},
};
use orchard::constants::fixed_bases::{
VALUE_COMMITMENT_PERSONALIZATION, VALUE_COMMITMENT_R_BYTES, VALUE_COMMITMENT_V_BYTES,
};
#[allow(non_snake_case)]
pub fn pedersen_commitment(value: u64, blind: Fq) -> Ep {
let hasher = Ep::hash_to_curve(VALUE_COMMITMENT_PERSONALIZATION);
let V = hasher(&VALUE_COMMITMENT_V_BYTES);
let R = hasher(&VALUE_COMMITMENT_R_BYTES);
let value = Fq::from_u64(value);
V * value + R * blind
}

View File

@@ -1,7 +0,0 @@
#!/bin/bash -x
racket lisp/jj.rkt || exit $?
python scripts/compile.py --supervisor jj.psm --output jubjub.zcd || exit $?
cargo run --release --bin zkvm -- init jubjub.zcd jubjub.zts
cargo run --release --bin zkvm -- prove jubjub.zcd jubjub.zts proofs/jubjub.params jubjub.prf
cargo run --release --bin zkvm -- verify jubjub.zcd jubjub.zts jubjub.prf
cargo run --release --bin zkvm -- show jubjub.prf

View File

@@ -1,7 +0,0 @@
#!/bin/bash -x
python3 scripts/preprocess.py proofs/mimc.psm > /tmp/mimc.psm || exit $?
python3 scripts/compile.py --supervisor /tmp/mimc.psm --output mimc.zcd || exit $?
cargo run --release --bin zkvm -- init mimc.zcd mimc.zts
cargo run --release --bin zkvm -- prove mimc.zcd mimc.zts proofs/mimc.params mimc.prf
cargo run --release --bin zkvm -- verify mimc.zcd mimc.zts mimc.prf
cargo run --release --bin zkvm -- show mimc.prf

View File

@@ -1,5 +0,0 @@
#!/bin/bash -x
python3 scripts/preprocess.py proofs/mint2.psm > /tmp/mint2.psm || exit $?
python3 scripts/compile.py --supervisor /tmp/mint2.psm --output mint.zcd || exit $?
cargo run --release --bin mint

View File

@@ -1,74 +0,0 @@
#!/bin/bash
arg=$1
gatewayd_path="./target/release/gatewayd"
cashierd_path="./target/release/cashierd"
darkfid_path="./target/release/darkfid"
drk_path="./target/release/drk"
echo Running demo...
if [ "$arg" = "-d" ]; then
echo DEBUG MODE
gatewayd_path="./target/debug/gatewayd"
cashierd_path="./target/debug/cashierd"
darkfid_path="./target/debug/darkfid"
drk_path="./target/debug/drk"
fi
echo Open new tab and run:
echo " $ " $drk_path --help
trap cleanup SIGINT
function cleanup()
{
screen -X -S "gatewayd" quit
screen -X -S "cashierd" quit
screen -X -S "darkfid" quit
echo Exit demo...
}
# Start gateway daemon
screen -S "gatewayd" -dm "$gatewayd_path" -v
status=$?
if [ $status -ne 0 ]; then
echo "Failed to start gateway daemon: $status"
exit $status
fi
# Start cashier daemon
screen -S "cashierd" -dm "$cashierd_path" -v
status=$?
if [ $status -ne 0 ]; then
echo "Failed to start cashier daemon: $status"
exit $status
fi
# Start darkfi daemon
screen -S "darkfid" -dm "$darkfid_path" -v
status=$?
if [ $status -ne 0 ]; then
echo "Failed to start darkfi daemon: $status"
exit $status
fi
# Exit with an error if it detects that either of the processes has exited.
# Otherwise it loops forever, waking up every 60 seconds
while sleep 60; do
ps aux |grep "gatewayd" |grep -q -v grep
PROCESS_1_STATUS=$?
ps aux |grep "cashierd" |grep -q -v grep
PROCESS_2_STATUS=$?
ps aux |grep "darkfid" |grep -q -v grep
PROCESS_3_STATUS=$?
if [ $PROCESS_1_STATUS -ne 0 -o $PROCESS_2_STATUS -ne 0 -o $PROCESS_3_STATUS -ne 0 ]; then
echo "One of the processes has already exited."
cleanup
exit 1
fi
done

View File

@@ -1,29 +0,0 @@
contract bits_decomposition
param x
{% for i in range(256) %}
private b_{{i}}
{% endfor %}
# x is unpacked into little endian order
unpack_bits x b_0 b_255
{% for i in range(256) %}
# (1 - b) * b == 0
lc0_add_one
lc0_sub b_{{i}}
lc1_add b_{{i}}
enforce
{% endfor %}
{% for i in range(256) %}
lc0_add b_{{i}}
lc_coeff_double
{% endfor %}
lc_coeff_reset
lc0_sub x
lc1_add_one
enforce
end

View File

@@ -1,4 +0,0 @@
a_u 15a36d1f0f390d8852a35a8c1908dd87a361ee3fd48fdf77b9819dc82d90607e
a_v 015d8c7f5b43fe33f7891142c001d9251f3abeeb98fad3e87b0dc53c4ebf1891
b_u 15a36d1f0f390d8852a35a8c1908dd87a361ee3fd48fdf77b9819dc82d90607e
b_v 015d8c7f5b43fe33f7891142c001d9251f3abeeb98fad3e87b0dc53c4ebf1891

View File

@@ -1,103 +0,0 @@
constant a 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000
constant d 0x2a9318e74bfa2b48f5fd9207e6bd7fd4292d7f6d37579d2601065fd6d6343eb1
constant one 0x0000000000000000000000000000000000000000000000000000000000000001
{% macro jubjub_add(P, x1, y1, x2, y2) -%}
# Compute U = (x1 + y1) * (y2 - EDWARDS_A*x2)
# = (x1 + y1) * (x2 + y2)
private {{P}}_U
set {{P}}_U {{ x1 }}
add {{P}}_U {{ y1 }}
local {{P}}_tmp
set {{P}}_tmp {{ x2 }}
add {{P}}_tmp {{ y2 }}
mul {{P}}_U {{P}}_tmp
# assert (x1 + y1) * (x2 + y2) == U
lc0_add {{ x1 }}
lc0_add {{ y1 }}
lc1_add {{ x2 }}
lc1_add {{ y2 }}
lc2_add {{P}}_U
enforce
# Compute A = y2 * x1
private {{P}}_A
set {{P}}_A {{ y2 }}
mul {{P}}_A {{ x1 }}
# Compute B = x2 * y1
private {{P}}_B
set {{P}}_B {{ x2 }}
mul {{P}}_B {{ y1 }}
# Compute C = d*A*B
private {{P}}_C
load {{P}}_C d
mul {{P}}_C {{P}}_A
mul {{P}}_C {{P}}_B
# assert (d * A) * (B) == C
lc0_add_coeff d {{P}}_A
lc1_add {{P}}_B
lc2_add {{P}}_C
enforce
# Compute P.x = (A + B) / (1 + C)
private {{P}}_x
set {{P}}_x {{P}}_A
add {{P}}_x {{P}}_B
local {{P}}_x_denom
load {{P}}_x_denom one
add {{P}}_x_denom {{P}}_C
divide {{P}}_x {{P}}_x_denom
lc0_add_one
lc0_add {{P}}_C
lc1_add {{P}}_x
lc2_add {{P}}_A
lc2_add {{P}}_B
enforce
# Compute P.y = (U - A - B) / (1 - C)
private {{P}}_y
set {{P}}_y {{P}}_U
sub {{P}}_y {{P}}_A
sub {{P}}_y {{P}}_B
local {{P}}_y_denom
load {{P}}_y_denom one
sub {{P}}_y_denom {{P}}_C
divide {{P}}_y {{P}}_y_denom
lc0_add_one
lc0_sub {{P}}_C
lc1_add {{P}}_y
lc2_add {{P}}_U
lc2_sub {{P}}_A
lc2_sub {{P}}_B
enforce
{%- endmacro %}
contract input_spend
param x1
param y1
param x2
param y2
{{ jubjub_add("P", "x1", "y1", "x2", "y2") }}
public x3
set x3 P_x
public y3
set y3 P_y
lc0_add x3
lc1_add_one
lc2_add P_x
enforce
lc0_add y3
lc1_add_one
lc2_add P_y
enforce
end

View File

@@ -1,60 +0,0 @@
{% include 'mimc_constants.psm' %}
contract mimc
param left_0
param right
{# Jinja cannot set variables inside loops so use this hack #}
{% set ns = namespace(right="right") %}
{% for i in range(322) %}
# Each round perform these steps:
# xL, xR := xR + (xL + Ci)^3, xL
local mimc_const
load mimc_const mimc_constant_{{i}}
private tmp_{{i}}
set tmp_{{i}} left_{{i}}
add tmp_{{i}} mimc_const
square tmp_{{i}}
lc0_add left_{{i}}
lc0_add_constant mimc_constant_{{i}}
lc1_add left_{{i}}
lc1_add_constant mimc_constant_{{i}}
lc2_add tmp_{{i}}
enforce
# new_xL = xR + (xL + Ci)^3
# new_xL = xR + tmp * (xL + Ci)
# new_xL - xR = tmp * (xL + Ci)
private left_{{i+1}}
set left_{{i+1}} left_{{i}}
add left_{{i+1}} mimc_const
mul left_{{i+1}} tmp_{{i}}
add left_{{i+1}} {{ns.right}}
lc0_add tmp_{{i}}
lc1_add left_{{i}}
lc1_add_constant mimc_constant_{{i}}
lc2_add left_{{i+1}}
lc2_sub {{ns.right}}
enforce
# xR = xL
# right_{{i+1}} = left_{{i}}
{% set ns.right = "left_" + i|string %}
# xL = new_xL
{% endfor %}
public hash_result
set hash_result left_322
lc0_add left_322
lc1_add_one
lc2_add hash_result
enforce
end

View File

@@ -1,322 +0,0 @@
constant mimc_constant_0 0x4699afdd3f9ce9916eaffcfbef597c5009ae9d3209c3b15feb6928a4a8d4b59e
constant mimc_constant_1 0x41e2431761fee4a40b468524d91b3d64590b3c242de10d18f55f0c5e3883ef02
constant mimc_constant_2 0x5a04a1ea758bf1cc1140fcec1ce2c9d68da53d6cf7ee8dfeedfb2ee45db08c27
constant mimc_constant_3 0x2e4b930078e93e73581d7b71120a8e8b9627955a0aabf139bbfa5feceaab2e3b
constant mimc_constant_4 0x6a9db69e4fd0a3f94402cf22076bd18300c344c69bf665542129ad887f0030ab
constant mimc_constant_5 0x4458f2de4e16ce2ead3fe9dd164cca36d2b70a25e71f55cf0c51ca553a4f83ad
constant mimc_constant_6 0x04f539ab6ea2d344049219c720a16c4e6033f8360b124519fdbb6d441428143b
constant mimc_constant_7 0x6b9c7b12a4b3cf92e2f2b386426058709573f9abdf1bcc5411dacd7ea0eaf8f3
constant mimc_constant_8 0x4375e3120921697155b3ea15c32b9412adce3a8ff8e28e1b8c95935cc71ad853
constant mimc_constant_9 0x041854bb643e9e5e5d8aa6e828dc4c732c8fa24192a160f40da85737372c5d0c
constant mimc_constant_10 0x65d9cc7ab2a2060d198d66310a902bddeeb7f5150173190036d2fae68de1c2b9
constant mimc_constant_11 0x1e7d2b472c6a40254a228b0543aff318084e7f6152617a6cf7fc405d917bfc37
constant mimc_constant_12 0x35293381012ebaf649d8c6db4e4d5e594bd114c99c234ddff7b9b5f6f8a9ec36
constant mimc_constant_13 0x3a50794418ac54a1467578ed61e34d8be5d52c5f188f42955fe8d5e257ad3e89
constant mimc_constant_14 0x446d905f60110dbd51129896a63a0e34bb0502101ad6311998ad2dfd74818277
constant mimc_constant_15 0x3eee70356bab144c54b5fc1095f9bce59c727a57a5582dcbbd5c3afc3c61ceca
constant mimc_constant_16 0x40b08ae056833e12c82f7e15e2dc72febc15d3275b51ec70afaffa6ce8bbb3d0
constant mimc_constant_17 0x205923e6eb137869a552b4857bb64f946c912f3335a94291ebb8b29ecd3e6034
constant mimc_constant_18 0x2a6aebced756f7e33c466bca2169ba24c471a088c8363fe0a966a223fd3b59ea
constant mimc_constant_19 0x566efaf4e022036a8e073fd9812376888ac9f37c794daebe3fa77b1a87bf109e
constant mimc_constant_20 0x1ee814f2660e7272712d588477e458c06f8f06950402e97c542d3682ad5f9aed
constant mimc_constant_21 0x257fe0ace4965622be247dba9185f108707f4ab16c910c03c565afab43b0fb4f
constant mimc_constant_22 0x43e156f0cad02ff6b763645c97663ab72229bb0a34f975681359797ccd58093c
constant mimc_constant_23 0x317f43b78cc26f0332a3ec3ec187332d4de0f2baf04f62fe76bee9b11256130b
constant mimc_constant_24 0x076ca6cd23830e3b3ece767b774e1b2243408098a7c5b816e7c616cb88f6b916
constant mimc_constant_25 0x14e30a644f034c72cf40b1bc790200c2e8ab3e750e38f3fb0160188e817e4560
constant mimc_constant_26 0x02eb02bfbac795a497a0882d66b718bb23de64f9fe7644179ddd3241cc407942
constant mimc_constant_27 0x644f175cf6f2268d451e5188e467c508bc91d870646de9297911be2aedf26daf
constant mimc_constant_28 0x14aef8f4f5499a0387e521a1c6064094590f149c52fb99e37b583434ca6bd46c
constant mimc_constant_29 0x2ddc7c6bba8895913f3deee128bc63b5e34797274de80da775c4a0c810ac60e6
constant mimc_constant_30 0x46adc33428a63a20459699183272b14797a5a7d1d66079701d214bced9a4be71
constant mimc_constant_31 0x552847d9a2a5b03f726b277ba01ad61c0e28114667e7a9e11229b83224f74349
constant mimc_constant_32 0x624921e44f5811f76c06ab74a11ad56e5241e4c597e9d172ee3c862bf6d4b1fd
constant mimc_constant_33 0x506af906fab5f9407ee71824d72dfcd99115c5a2eb53b55a1d5877910a645282
constant mimc_constant_34 0x514ddde7e75b27ae6f31efb7375bc209dcdd0ab4c277ee0f8b362cb5211def31
constant mimc_constant_35 0x2e3be2e2a10f8e24b411902d9578d44e2a4a5042036ecc397e1cc5ab88e76329
constant mimc_constant_36 0x61755a2f6a9729a3bd8d21aea98f4cf885aa1751a714e251a517395711674bf5
constant mimc_constant_37 0x68f8f91713d81c2a6d601411447e944c27f7a1862855b940ef3521cbf4074e96
constant mimc_constant_38 0x32e6b3dfaa0162846620ace97838a93f48999b5bbc078964687c795a9e5b71a0
constant mimc_constant_39 0x3c783bf0caa35bd381603b9e3aa5dbcc4ed4fc93b03d69a49fa15286a6374f8d
constant mimc_constant_40 0x4a3f322f033de27244d79dd5c6c2f34d84c24c917ce95cfb6458d72124280e70
constant mimc_constant_41 0x3ee0abb7af79168e05566994017fade2d69bdb55c4253f996362b73d49f3f70e
constant mimc_constant_42 0x15498a06e80c6060320e9a01292ee1a805c2aafd7b92f76b5f5e8be515e0a3b3
constant mimc_constant_43 0x02424410de65455350831f5b1c3554626f6bbf373ed0f627b42f0d3ec2fdd487
constant mimc_constant_44 0x5886da407f6014665272b45d213cb388987503398d407732f278c9a35267622d
constant mimc_constant_45 0x15f6180f287d2ef5d9d057dc18eb7df732d97632bfb31e93ac065dcf0c67fd40
constant mimc_constant_46 0x65f5dc85c9660f184a09ee768ae9af0f62911af31920d3b5c49ac0360d261441
constant mimc_constant_47 0x65751a6bbccb0ea7fd79fe7231d03d2f14ec6a24c5d9c4a77d1a86acf3d027a9
constant mimc_constant_48 0x4c21c6990442cb96b2ca684c9d427dc41090447248378f50b4de15b616f1f133
constant mimc_constant_49 0x34cde97ef5c2459e29dbad8324fbefa5097f744f737cc59ad2681e49dfa43f99
constant mimc_constant_50 0x5df3e3787510f9e2b32beb2fdf76fc6d646b3fb94d4ede65309762fc515ffb55
constant mimc_constant_51 0x30394778b396dd8191e78cb7627636eb82b15b0de788c1e2db2788b05caedd8b
constant mimc_constant_52 0x695a64cc6953c658f40c1c2666715790410e302d3d902fcb809924896c2d1f4e
constant mimc_constant_53 0x6a4fe5863990f4b4d588841b0e52c4dc7a8c4644edfec7c721ab66b162ec5de9
constant mimc_constant_54 0x62e4428cb1856ae809589806e5e7869ab0fb818d6c0a696d94ee616fe549400e
constant mimc_constant_55 0x0b1e8a6d6581c13b6888d0bd9816bda3695f917d03510d9b42452f3501e3d55a
constant mimc_constant_56 0x5e5a2b767f853d0f0bf0e3cae872fb942065db112cb48a12dbce3ce4da28aa87
constant mimc_constant_57 0x2c1c59e21a9741edbaf1e5a275c573bbeb395c6a79abdd0e532e000298dc8c00
constant mimc_constant_58 0x25d648572388935cac47095b4f38b3ebe6519766a0d03bf7de9b4368b7bc1b58
constant mimc_constant_59 0x475a00fdc58c8a7092cae8942af520dd5e0f476dc469f0c3e908da68be55e6ff
constant mimc_constant_60 0x3fe62baf8e0a5286b0055e16e712ad06d233fa71fb374557d4c3d585e33dd37b
constant mimc_constant_61 0x54d74923f593c55659f92b34bf5c05a400187e143850173786c8a1dd2f3a1283
constant mimc_constant_62 0x6aa3afe84262b6c5bc8994a2c0e66a64a534904efcf47ead067fa09cd2d58a6a
constant mimc_constant_63 0x2069d079cd963cec28ccac413172576ace57da0b4ab502c11289fff6ff2de6eb
constant mimc_constant_64 0x364b3a05a8b1271aa61d5894b51a445c5896e86a535869b70e56e1e0f7f49f42
constant mimc_constant_65 0x1c904753197233afda76661025e67f6a8e7a5c209292e151a7f34119397c281f
constant mimc_constant_66 0x45f6d1ed8bc4395ccc6cfc90a1cf5f636248e966d82d040d795014f5d184b3ac
constant mimc_constant_67 0x1bdbb396d84fe4c8b5b230e1c925e9f0f5f88faea9b713b319c7c11c307cbdbe
constant mimc_constant_68 0x347c35497a65e93d8f4ec06c1546991841fd680868e145849195e38ef783d1a4
constant mimc_constant_69 0x1d9c23cb0d4a20c384d629c6e706ebaf12fe0fc4eb0860c8175e687742e941cc
constant mimc_constant_70 0x59378cc30bc5948d66a6f1671e84e2e9ef342e0e3dd682015d93f96a68159f3a
constant mimc_constant_71 0x59992c34faff2238e03be3d6e87086a427e6eef2c5647a690363a9ddc0c82d67
constant mimc_constant_72 0x60b13d9cae9b2504ca982c50b14ee5a628d40832bab95108e6640b9a8ef8a853
constant mimc_constant_73 0x4cea35b5ebf7d7956c0c592d4238051c37bdb8bcb4c08fa29239ffaff00793bf
constant mimc_constant_74 0x25344d0db88e9df26d216c287ddc36a958ba1e4d4c05a9cd59715de870d47e36
constant mimc_constant_75 0x19a1c0a1f3aa80db57b014a2dad65eecf645fcd442a09b97e78d044a50ba58c3
constant mimc_constant_76 0x32a6b9ba275d0204fd0e3de5fed3eac823aa8ce0ef5eca627fe92030e4506fe3
constant mimc_constant_77 0x4e4f1056e9e3b8861117ba8bba1a1c37e784ef9e1358473aa55156e3b1523dff
constant mimc_constant_78 0x710f51f9f3866ab261df0fad6ad3986f75d9990bf7776f4e4775f9c8f95045c2
constant mimc_constant_79 0x48623d21c816d6a47a6339d9bda7ff31f2b32b8491c72967b93f2734ec37f64d
constant mimc_constant_80 0x69aae3a126e0625c52d05e8c98ea912f56a582419cef7f13f31be66ec14bd43c
constant mimc_constant_81 0x2f7264fc97a0ff9188c506d5df4bf3d4f28cb1d12fa2767e18d023f8a7e907b0
constant mimc_constant_82 0x54bf8632b89211a06bbf9c0ee5ba2328b1f2cbc1892b76282599c0fb432d761d
constant mimc_constant_83 0x0deb44dd3e20b34cfb473944f4f8f07b4d337da0fc18021777c983bf3e4e7f44
constant mimc_constant_84 0x37a108a7b9e612231e21f0b4c7186163e3cc59325cbb17a39e1e25b4c4345dba
constant mimc_constant_85 0x317515ddac6dcb33a4ac68d4c02c6d93d147b61cd892474292258ebceaf5ce83
constant mimc_constant_86 0x38e225b4f524fa89f414976687473eb4c5f3edfe983dbdd07d3e8486f3b93c0a
constant mimc_constant_87 0x636b27e505a14fb8362beb2e436582db991e3089e6edaeb9aaba3d67f58c8c60
constant mimc_constant_88 0x28fd1afb8cf1e9c7594b5b8d6b50ff1f81aa19f211c5c271f2181836158bb625
constant mimc_constant_89 0x1a8cf4f8569d80ca7d878d7a76d959956ac5e7edb37fbcfd2f5d130e3841dbc0
constant mimc_constant_90 0x2cfbffcc25a0a01ab7cd1e700030d0e363ac170dd000397fa83d107a6d12bd54
constant mimc_constant_91 0x325355d6824f71f550b102c6fa6c8c129de58d325174c5981c562e606a58c55f
constant mimc_constant_92 0x1716f66b4ad2388a23ce111dd5ff7c04d4478dd81930050fdf0c4a90fcd6d381
constant mimc_constant_93 0x02992cefec8ee9bef9602858d51c87a2c4180d9fe0c02e6c6003531010793572
constant mimc_constant_94 0x2132b3fd309dd69a9f3c39b450534d857721dd5a2bcb23b479a29b08e8f8551e
constant mimc_constant_95 0x369986658b8e7e4f990fd6fc09b99a056d81ee47c7a9e46b4109d8af0956678c
constant mimc_constant_96 0x25e00309f0c3097a6500df9ed5587ec128b20a97379814b4a0522f7e775a4548
constant mimc_constant_97 0x529a8ecdddfb500c68b664f7303dad768da802c29a933801b2199cf74a3470f5
constant mimc_constant_98 0x3cf98a6dc8290785ede38da9455dbd28a64a1bda35a48d6c6b1b35ba6df3268b
constant mimc_constant_99 0x127401f379aa992d492782910baee0fb331b3e9c1a66492c9b002a37999f356a
constant mimc_constant_100 0x449dabe3e12e7b495e0421de157acbd4b3852cb824bba7171c8e3da565e3f95e
constant mimc_constant_101 0x410d1d4fb041736101f5468ebdfd9380f2066593534339bc419f35d530c92cd7
constant mimc_constant_102 0x09747f87db187d67e7881e1b64345754ec9bc9ec353e9b055bc377f1618ef17e
constant mimc_constant_103 0x5fec471449175525c56b18200dd8ab96b2f9ee383849545628f0ceff76f631d8
constant mimc_constant_104 0x0c7e402c723170d5dc5f15e229f4bacc5eb50b34dbfb6129215ee662288e159c
constant mimc_constant_105 0x158896654586f5c3a34808ef7ab93def61fc9257d5b7631ed6869259a45d1d01
constant mimc_constant_106 0x57ab3eab90ec38cfb23625e7110948e4b56e38a1ccc2cfffc344876d28aceddd
constant mimc_constant_107 0x08d08f8650f5ca7bf03aad9a80ae09c697327a131827a9c2aec67d1d9f58064e
constant mimc_constant_108 0x273607089f1e9c2b99812e032dfb62c359438c76556a15692a3de02b8c13df4d
constant mimc_constant_109 0x55bf5cd5a1a89d7e3d1d274cc5b1b765e42a9eab5cfd32148c1633550ecfffce
constant mimc_constant_110 0x5c4f6e0acb889fbb573583767535e95bc537641769c35063c0bd3a65812ade57
constant mimc_constant_111 0x581faa1d0a57ef947001fd8e57eee26e645d15eebedb7ebb1d85581968544ca6
constant mimc_constant_112 0x48b77ab45f5fb6d615bd759a6661097bb8a3b5c27ba35f1b127d2ee12f043bc4
constant mimc_constant_113 0x590618389009da43c679b6254ae4cc86dbfa397981f4dff30e064e07bfdc9eab
constant mimc_constant_114 0x3ef9bd95ccaa3c577ab98d3fad87fe69953bbbba6c8bbca0301a6c88e9bed8e6
constant mimc_constant_115 0x2bc1dd87795feb2a5e8d98759371592ba7147ee4c2a3473d18c496ebe3721216
constant mimc_constant_116 0x620ba5be31e353f1f3c72a4380f32c016f0746f5446f9e1743fb01fe6994051e
constant mimc_constant_117 0x151d0bcf972db311553ef8da672b1c861d118e9b78da632d24c49d4a0fa177b7
constant mimc_constant_118 0x01f1bda7ed65ad241d6fa13d8c5cb40cc335a0b2a31b433f2c65cb01e8dad5bc
constant mimc_constant_119 0x4aec58578fdfd5e59d18063bdcc69086dae303518f5155facdc2824878862c53
constant mimc_constant_120 0x1ca2d39cd13b6c690faf2be3da4d4517e28244fbf9ca0f8f4d80565205fb86f2
constant mimc_constant_121 0x72432f39b454d6457ffae81f2e843df03c1526920384c50136beca0627f9054a
constant mimc_constant_122 0x1910c2e6bb35a12e22ec46cd0db6185f352bf3581cf46d2f9c494daf8d94b993
constant mimc_constant_123 0x4e47d6f9080e682d34ae07d5886c29869d16324c468782bea9c62334b583251f
constant mimc_constant_124 0x3240024a0dd08da0c135caf8114ea8d333ab181e94a3a01edabb760a64adcee4
constant mimc_constant_125 0x1669aabbd01c4541575f150981af0cf9a196e0b98908af53ea14b81734ecce5a
constant mimc_constant_126 0x316aa08fd611919a73b60dc2b3175b3843f17035d71b9edf2f72c32850629574
constant mimc_constant_127 0x4919d1e48c28eb1d36a689d8a5826c4ae4cd4e84a8347a9c9238b825a0b53a8e
constant mimc_constant_128 0x4572211d4d1c8257d142ff2335eea65ccbf3177a982fed00931410f3bdf08c19
constant mimc_constant_129 0x5d2d04f110bb9a50adf25427b232870f2be2307685f19df47f9b2f1bae984a04
constant mimc_constant_130 0x472609c977c6854de75985c9154f70a7fda1843a38f10dd4985ab8dc353ad5a7
constant mimc_constant_131 0x5c2ba4f8bec80b52e65afbe7b2ff41ad73542275e40acba8730403e9e33c7697
constant mimc_constant_132 0x267614d22d526f429346fb2e9dcc4930880971780e85ef44a199feabe2b48227
constant mimc_constant_133 0x1110d3da8ece3e4eda99c2d63f6724779af505b9527f0b191b34b5bfabbf5584
constant mimc_constant_134 0x68fc77023c046909572d302630c6508922cbc03e6c6d9a05108bc8db71e045ff
constant mimc_constant_135 0x1b6630a5ab959106f3951689fcbc6a757c97511d08a3d4652b8ee7eab820d575
constant mimc_constant_136 0x2e34a9c19201971c6cffc366e7955b33d0b7dc59fbaf87cadeb8d0c099cfb541
constant mimc_constant_137 0x060bd11957a053af7aec4b2c2caf7e227512d9e856552e5cf6f4ed4b04753bec
constant mimc_constant_138 0x0d8a6987303d76b12f97eaeacfd783401ffef6ac2e994182eaa93843300385ae
constant mimc_constant_139 0x0e9b15bfa73141c59edc9d11ec4ee316525ba53c4b91e4f1a8adb8d372e91dff
constant mimc_constant_140 0x55215d958a6afccf90247026efb61dd9bae318cd31ad27746b227de8873add8c
constant mimc_constant_141 0x4ccb674b94da03efd3404a424a422d42fd4f3a8b9f73de3aa7377e728400e797
constant mimc_constant_142 0x256f31bdb0e0cad47ec44da9bdd1fc146d0284f1d71c596e12b0c690e202d1c4
constant mimc_constant_143 0x60797d9977e8cf8484240c0ac4d3703818c096db8d61ca640bab83ea4e675919
constant mimc_constant_144 0x57fd867a56f6fba130d5cd80d1aa2562ca3bdb6956892c0f66e8d9bbe1fe49e7
constant mimc_constant_145 0x09115f248d518063beb8d89c11115a6b53ac2927b2eeb0c50b50b3e82c314e5e
constant mimc_constant_146 0x6a10f8ecb4e14465b19148ae366be2452b809596eec80f4913a2240e5e89c98d
constant mimc_constant_147 0x0399008978536884058e8b36c86b622d5da6cde04ceabb591fe8057153f6c7b2
constant mimc_constant_148 0x2c7ba50ad84ce603d8206950a09277dbf59da814c5b5119763a208953d946812
constant mimc_constant_149 0x02a697c90f23766d5fde4b61101665b865375243f1bde57522bcb4bcda33804d
constant mimc_constant_150 0x3bba46c732127685e3a7c6963ec063f961bfa23dce70af06fbbdba02d295aa8a
constant mimc_constant_151 0x206c47de6dfd8600586a42f98aea1284742671c605e7a274a306e188015e031d
constant mimc_constant_152 0x608a94a91f8e4e1b0adf94c1af4992b0176fc84d8d79b881ec02d2613f4d9083
constant mimc_constant_153 0x28f906b6e3e6d01ac90251789b81001bb5d96ec2f55be04354b37bd7211c8731
constant mimc_constant_154 0x25c66f7f7c9db885d9f7d7b64bd555f7e2e939878a6f1f1056c0c5af008949a7
constant mimc_constant_155 0x4992f08ef5816859cd16e02a367e55fb073cc08ba19fce061e83288caba6e308
constant mimc_constant_156 0x432fd05cdbd6ce762396cc6b88f6db33f0e6daa1e4faf602a599575fe797979d
constant mimc_constant_157 0x4961bcdf4ad6da150ed71fe78f84c9faaa28e63e378af83aedd33870e337c362
constant mimc_constant_158 0x4d1025421a43054ecb8eab1d4ed666a8cfc7b3e1d3f5243bd945032b7ae19a1b
constant mimc_constant_159 0x0eb68c99851461def5baf569dff154f8ac4591e8ad194f641dc5fcfbc157c07d
constant mimc_constant_160 0x256cd6ef41e108838bc52d51af281be02ad6c5d2a3e6f49f2cb864bcf2397447
constant mimc_constant_161 0x0df82b76b04d8813711f92ed2bc6dda5f32e4778b5f1b328bd3b2a3b82928645
constant mimc_constant_162 0x73397a58cf55ae9d2b14647125725f053dc0a9d5d5599f67955b8b8ceb8c43d8
constant mimc_constant_163 0x352a6762b6764cd234a5e7e24e1beaed50618b691be9e40d4b15813d6023439a
constant mimc_constant_164 0x4ebe36c93f3561edd31170f6775e38889598f0b40a3a2967882b60c6bcf8d6f6
constant mimc_constant_165 0x4af798462ebca10935795dcb09770d98e2a93bc25a99af876c1f080fdf04047e
constant mimc_constant_166 0x6f9acbad33e5d972376f1f67457fb5565582c0cc233006fe51942c48479a3c9f
constant mimc_constant_167 0x395558ce9453ad4999a1d87585bc88b08731882ae0ffbbec886db1cc3fc7ee62
constant mimc_constant_168 0x17b48a7db220b2b4e4a3e9139168f050056e71049e4080ded3949222d3915dd2
constant mimc_constant_169 0x13266faaffcb6e011f73a4065bb1f7bdc373571d1b9c0210674f4f9d18cdbf3f
constant mimc_constant_170 0x0edbbed85597c4beb59685811f7f3c0ce807083c032e6c71e5869004bb37c93d
constant mimc_constant_171 0x64a7409e0e833df31fb574e1c12f764ecf0e3d335cc53afcdc22ac13d7a81da8
constant mimc_constant_172 0x730fbba0d85d06eabf3f517d4826457bacb2fa8c2f24168c1b026ada9eca5bf5
constant mimc_constant_173 0x1ffdde6d216f269f8d25efca3b28590416ea7340d92df2c02d111e30302ba020
constant mimc_constant_174 0x6551f0ba88e2b256f61e052c2ed98e5253fb7791614da7f7f10f9db1dbace96f
constant mimc_constant_175 0x5a40abaaa2542543cd1710bab187798b01f6c7d93395e3a1cdaed5b8866018e9
constant mimc_constant_176 0x7021fa2631484663ef5e14124c49b3078b460d77c9972b9f3aa8fe7bed79bed6
constant mimc_constant_177 0x28e1b47a74ed1328c9cf0188bcce0e6bc8e32d808ad91d62d747382141e7c439
constant mimc_constant_178 0x267bb1817a59e83c9cb67f740cb31fccde2ae0f6dc49745f826267f78136bc5a
constant mimc_constant_179 0x6f2a6bdaf2152c1368e51b4d1ae3ce48bb8a62e00d92f2f9f21393c691243aee
constant mimc_constant_180 0x00cd4b3d36b639b44a828c3dfe8e8da68a7cccaf7063fa92877683c0e5080869
constant mimc_constant_181 0x3e8e056dee60929e925fdcd2395a9959202ef71b82a638fd1e3decba9051d016
constant mimc_constant_182 0x651baeb3fea106c59cefec6a9c8973347a481a75b04f547d8d2f63a1ced57161
constant mimc_constant_183 0x1e6ea48da02249378957d446d9603e4a1e0efd343426933d0cf5a1400148f654
constant mimc_constant_184 0x5eb2faa76b282614614ae97db1e0bb722146ac8230739cf9abb35058ae7f6363
constant mimc_constant_185 0x6400a9ba34a8ce081b7755a5241338c78c10c07ff6cc97ac94f29b23775922f3
constant mimc_constant_186 0x5c475b1284568d5c55fae4840fd5bf9b9f8041fb4c75f3fd902681d97d4b09d2
constant mimc_constant_187 0x037e3fa79fcab75541fe4ceed6404d2a89228694646835e0422fb558477fb128
constant mimc_constant_188 0x39186a11b8693a21684796f4dd227523ac2782d6d23330d8287d77e19f106923
constant mimc_constant_189 0x44b4264d680b2bfa7081436798dce5bc3b20bedf250dfb2103abdde5b3f24eb2
constant mimc_constant_190 0x01fd3211afd7ab17103dd5a181b91982d83e69f9df9568ed132db65c23bfba2d
constant mimc_constant_191 0x66bd19f66bf63ef557cd87c638d6a97f2853a284307ff04392e61b7a68e56b12
constant mimc_constant_192 0x09e3ea8c3c87110454cb0045179ac850f74285652c6854351682cd1706b54f88
constant mimc_constant_193 0x22b7ffce8814457850e403085d0f725dc72396144565f4542d5bf826f4627106
constant mimc_constant_194 0x255b1285cd235b83bbdc8032f637a74bc8b33a798e2751969ebe67c593b578bb
constant mimc_constant_195 0x5b568413938daa1acec17d776af723451fc067e63ed8a24d58cefc27ef7feca9
constant mimc_constant_196 0x4fc38e950b447f3040484e58a7d106386da69400c9292640014886e33eb7596f
constant mimc_constant_197 0x044e95a76627fade400c813061a56bd38ae137734ac1b7b11fce4a12eed6bb68
constant mimc_constant_198 0x129d3939b05352392ee46921665e027d3cb9c9857f0b2f161bb1f0fdd58a74bf
constant mimc_constant_199 0x327b98a9fc847d6b6d54a175aaed3678172d615d37cf1c4448c9d4588a2eb7c7
constant mimc_constant_200 0x63675e996ad78bc6725b923b4cbeacf40f7d4b85bf38fd8b5ed0f63424779ab5
constant mimc_constant_201 0x7374af204d7432c7954dbbd12ed973b79fd0a6d7109061ffd10ecb2f6942d5fd
constant mimc_constant_202 0x0fdf70b408b29ce4bb3ef9a02c333ba7789fffbf2b17dc2ef4dce8714ada06a8
constant mimc_constant_203 0x4373b306976a59fbd07f82bb44c4ee4e4a11806801960c5c18f32f7679321d3c
constant mimc_constant_204 0x1b218fbc57953d8d44ab45c19993b223939a121a1e6bf87b4ca549e06699880a
constant mimc_constant_205 0x09b95f647fc4e11ed6a4757be6287d3f4d6bbdc6da8173da072d7a5d046862b1
constant mimc_constant_206 0x1def7155ba82eebd07611e2dd694a49dac9085004c1b4e9de2b4f0bf40c063fd
constant mimc_constant_207 0x38921799f2fae22e5dc387e3b63a8d4d2210ad60690f61cce190bad2a304c035
constant mimc_constant_208 0x2cfc11979ac028eea6636015cd2241a9ca2b9256bcdbae2f89df853751f63589
constant mimc_constant_209 0x21e602b39eade2ce622e3da4c76124a5f9b2580296037a33f88044895aa8562c
constant mimc_constant_210 0x25c9a818e3691a8d36cc881eed8513110fbcd2c855270ae265cc4a53283e2f4e
constant mimc_constant_211 0x6d17e4bdef0620c74ce13ee9b219e49bf2c8ac57cb1882bca03c64ec7c7c69fc
constant mimc_constant_212 0x2285fe01b02e1cb4331c2e86272f10d7e7daeac3d368b914e9115d832aab4e12
constant mimc_constant_213 0x3fb801cc1a5264babd7f35a65091d15eb9b47a6f06ab9422defafaee4cd35a84
constant mimc_constant_214 0x5b2ae60ec46971d3b3535743c3ab4d99f07ee2f551bfb2212ecfc7120169c8eb
constant mimc_constant_215 0x5322e28426199923aab00dcb5aa2c0c92690628e69ddbeaa8a9e0b92e4d84aa4
constant mimc_constant_216 0x1db225ddf28a651a6f809533078dfc8a006d4b76b59afde3d3356c7f26bf1ac2
constant mimc_constant_217 0x600fcc0f370b76ed88186364efc8d0435ba4efe84abd6b2573e87e213cb405dc
constant mimc_constant_218 0x007c21ae6a4471fb33141d353cb73f3769ee63d78cbc5d7e6a8c1bdb7cf3eb4f
constant mimc_constant_219 0x17520db9848586770ced86adfca305209a0884592720f70eb91f9e3a22c23a94
constant mimc_constant_220 0x3db8aeed94f87b37fc9cfee7a7c027605bec03af4965b840a8942b89fef39ecf
constant mimc_constant_221 0x10b3102359b66388bf079dd2f30d8131ec4da41bf159fae392838a9708e1cfc9
constant mimc_constant_222 0x0c9f537a5a0efc930019893a3fbd46c5e2a85b78b22b4bb60c0c1ec2da334a07
constant mimc_constant_223 0x165f9cb0313efaf5a0636141f39c3ff22089c0f9c494ebc40e9e8060b84f149f
constant mimc_constant_224 0x001879a49e2e539bf9e9c713416f517ee14f6e510a9cafb9a321fef9ca23ed49
constant mimc_constant_225 0x32e53a1e65305675144ebd5bb49bdcf81879daab30fff361eba5cfef952184a3
constant mimc_constant_226 0x51b4edb20a2bbb2daf144d4ab3b72a5a4cc956d9bd9e2ba5017c2163928118c3
constant mimc_constant_227 0x140c9db4c384a0e3757a41ae5005b2557148cb3c190ab7101059053039d655ed
constant mimc_constant_228 0x1737e47c806e74be09d8f7daf7c9d12ede33929f5152eda6c8c008064cfc1be3
constant mimc_constant_229 0x23f3501123499df44f5cd31b08fa1338be61194a023c9101a41ce7518acddcdd
constant mimc_constant_230 0x68dcbacbeb6727e3b47ef3a6291421496a78d81a645f2451c2cd89818715329b
constant mimc_constant_231 0x2f1dd4d3ce3e7b49d67a4bca9ba8b5b64ee37a20496ddbc302aa8c1bed9b2fbf
constant mimc_constant_232 0x2b5427a54294793e926c0ed030eff8b5020801ae8a46b1d7cecc49d01d2cd4a1
constant mimc_constant_233 0x1bcdebbdce2545485d5db25d9776f7bdc31dc799c61cb726e20e0071e939e4c4
constant mimc_constant_234 0x6021616995863e2b6fb9015892f2f361b60656bf1998239aa471d4c698564e9f
constant mimc_constant_235 0x4816704f77b55fba8188d9424143ffd7b015587467072992b2482e9bacd4f072
constant mimc_constant_236 0x60aad5cbecde71eae3fb3e8355137d5890f2947227093bacd23291a731720e79
constant mimc_constant_237 0x5bff651adb907adde66b4a4810173bb8cc0cc618e6698e236979750865b68466
constant mimc_constant_238 0x4dc639d5986ad912fc2632704ad03b039c6982fccad820b16ce2e519de54dcb0
constant mimc_constant_239 0x1780c0f66f7afefb6b32a019956b2a209224b9eeba8a643a222f7355214be300
constant mimc_constant_240 0x6d23740f70b21671e66d9bb35d7387b017dd56c78b65973db44e5479567c27a0
constant mimc_constant_241 0x1784ada0fe2211721dff5b63c46ddbd0cc2a7161e42f24b26b10cf0a807398c9
constant mimc_constant_242 0x3721b5cbdc714dc02db737a41bac0ad9dfd640229e4ef73c780f2abc7907a101
constant mimc_constant_243 0x6777e0e8612172897bde7e5e4d7edafdfac32f855d07b645ef0a2c2b6815d7bd
constant mimc_constant_244 0x5430480105f06250a915e429d5436268eeff94a54606848883d84eece231db3a
constant mimc_constant_245 0x5b06f0578c8e419abaf9365b1e0e4605a270d831b886b1310c2b30830f70aa05
constant mimc_constant_246 0x064faf1daa9415f3bf666dccf10e96a660e3c3e08945cecfad74bcf656a09b63
constant mimc_constant_247 0x5a7cf453cdc309e004ac0d4b161686c9497ddd5333302ce1ac689d3cd3f15fe8
constant mimc_constant_248 0x3d1cdaba6330736b0b9c17a27d3f31b58ea7b0aa1a46faa5cbc191faef9e41ef
constant mimc_constant_249 0x59c894b434302a88c78f3438263ff4a3f82f27af2f086958497b75ba9ede3267
constant mimc_constant_250 0x4f96eab2814accfe7cc529624df63fd4d9d3932ecace112a52d488ebd64f86a9
constant mimc_constant_251 0x5c3395a99f651f587c1e9f88fb32ffde50f312874219daec0f67f604ba56f55a
constant mimc_constant_252 0x10bc86369a85dae2cbcb60d1a110675555b1f29f01af909d0b0a452fd6f8aa0a
constant mimc_constant_253 0x025c11c9d5846be858ed85b2706718d0859b14b5e6afafc50e5b7cab9390e88d
constant mimc_constant_254 0x6a0df7099df32bbf845516682d8b2c40d5b238bab4493508146ec7da5280b31d
constant mimc_constant_255 0x15dee1455b9289a97a4fb4561cd05cc4eaac7f45e2098e6db369c4e38780a898
constant mimc_constant_256 0x6b00cd849365b050f85b3bcb73dc91ae063ed60360b053ccecd4ea226f5d3480
constant mimc_constant_257 0x36ba01e51f6cce897b12718e2947d0ded1b43f1ad65045d9e80792cc0d2afbcf
constant mimc_constant_258 0x705ec3f8f1bdd15381e69d0241b37349e11963b509f73dde27e4d00f7173e9d2
constant mimc_constant_259 0x00259c2c2a277983602c80547343f0037a7a3c7edfdf98a1ffd16bea20204aa2
constant mimc_constant_260 0x07ba65993dc66a3359f96e202f8408f9367d24e37a83164c622f682ef4d113d0
constant mimc_constant_261 0x56324ef5c5a36793bc76d0c2a38e6ae35916ab04bc072325036d9e832981518d
constant mimc_constant_262 0x3cdc6e8fc9101d4e6be6b5fb368a3911ac13c4090ea7da9f345cd5f7ae7b1e6c
constant mimc_constant_263 0x3fe62a321b08da7f8f6cd2080867b98b6c9f54bf910bac77db5a71da68b18270
constant mimc_constant_264 0x53915ca5503403181327eea9143a99782e31f1636a324a946882376fb9d07681
constant mimc_constant_265 0x45ec1e9c297bdd973aec556197b1168f8a55b0d7bb0519b5db479f95d11cd045
constant mimc_constant_266 0x7310ab366f789b5264f16fd563b6dd31462f3e352a92fbb5e2357a9fbb9a1f16
constant mimc_constant_267 0x739ebe2484fabba7b18d7f3a213bb9d3bb2d78a8c05f41515aa20533b933cc2e
constant mimc_constant_268 0x048f8d7f23612a95c09d90137f7a4d87e340a1e83ec3c94284d6784ea8006423
constant mimc_constant_269 0x49a59faf4bbf57ee29b5e186bb0008a4ec74c8fdb7ea8fe7e1aa46bc40873b50
constant mimc_constant_270 0x5cf260d13f5da4870855a40e71d4effda202f310a955db2d140e9317e4238998
constant mimc_constant_271 0x38c2eba027b51ab146dc61e33b7403789b63641a5cba018829e3dfc9336cbcb8
constant mimc_constant_272 0x1f90a83ada4e0d548c8beea8f902f4bdd8466948161fe2760a0127f44a0edea8
constant mimc_constant_273 0x6b65cc39e2d766f83e8f6f59fd5e40290bf8b887c99da8c166417d5a9cae1444
constant mimc_constant_274 0x1da9f1f317f97e9c6132dc6808def44d32daa0c2dbcffe580d8f35b85400ccc3
constant mimc_constant_275 0x3df94f558d1e935080d48183a3e742f6be2992f5aea51387f01c90219e980fa2
constant mimc_constant_276 0x59974c89246e978cbee6e84478252843235f550eb7ba45324d4a7ea572ca7e2b
constant mimc_constant_277 0x094be891b94edbc55530775ac31dd8f5ac0d1e2462579c158ce2f28843a2e9b2
constant mimc_constant_278 0x02c997879aff55f85e9e19e36a32758b868a0504ff0cb4a704fabdb897f308bd
constant mimc_constant_279 0x090a6946efff80828d498845e43aebaf02f19cc8a5459db7b12952e4924e1fd1
constant mimc_constant_280 0x3cf7d767a121eb81462c2731ee18da4f5579e007ed7e198ed9c74d0e4122d247
constant mimc_constant_281 0x4dafcb7ed415b248c5f169092d29b0f5d213e599e2bf15ade507d9ae2c9d764d
constant mimc_constant_282 0x5204fb985e7a86bb77fd705bf71787c4a09b97e7729318e6828a422f70aabcea
constant mimc_constant_283 0x0e1b38375d5ded933a6c9d7512ade1e96679651be670f381f875dd62c7279827
constant mimc_constant_284 0x6b612638db66a469241a60b7222956ca0364f2d77ea8849aeb99fad2a0b5637f
constant mimc_constant_285 0x3626c1544bd18d8a9bde32d6210aa6179839b1ebefb87fdb914d3735db50f92e
constant mimc_constant_286 0x222fd118f0cc69ef015f43fdd95a4db3fc08eec734f4cd3fce78e73348373e03
constant mimc_constant_287 0x369885b7348e2be8c21dce937e248cc6c390c703a09dddbb88b39bbfb3fa2943
constant mimc_constant_288 0x0794753806f2502ff43f7b8c4990e446c37677a49f78e0a8e38622a23c34eb60
constant mimc_constant_289 0x4b9b69b8b54c2ba38a23c409263b2ea543ba2082b6fded12c3c9b9dc754c4202
constant mimc_constant_290 0x06fae323404cc19a099fb298803a76737720c25913e21f38a75f1c8e63a96b9c
constant mimc_constant_291 0x50461e3977f12ec2de486071fc3924cd1aef82a6bc9fbde215eaddee6780de1d
constant mimc_constant_292 0x5ff12618767830d17a759dadc62c40221cc848ef84da8cd91b76e5ca59ccaa37
constant mimc_constant_293 0x6b7bdeac8d4dc989219510a928aa2e2a8995f4aba16e9f59d85e88ae3f6f5f5f
constant mimc_constant_294 0x5fbc48469f2e94eaee4ce3cc7af5c45f27a6532f0b7d8aaad76e61091a319ecd
constant mimc_constant_295 0x024ec0f964b1ce01b08352c231662c238c623cd66a2da4ef330debc7323dba8e
constant mimc_constant_296 0x0dfd978f5c1e804bd89e9d579edb44c49335296cd5948420d7650775cf88fc0c
constant mimc_constant_297 0x57ecafcf80a257780a9bbac3793c3e772fde0c88d6ce8e39399c7eb0a7e76d6a
constant mimc_constant_298 0x705b423e84afdccba45b0286397d1a29896cc1dc3fb41721e9e14942a2c13db6
constant mimc_constant_299 0x61efd69d156931b397d7aebd87d6c7599f6a5e2925cb7d8891fd751b7757c486
constant mimc_constant_300 0x5b0a8e0bc9d55850e65cb119b6b43abd5eda13de38ffd6e45130a6b2c7184251
constant mimc_constant_301 0x2ee9eb134a2f83e93bb4b09c71da3e7810d9a2bd01acaacf70fc7b43ccc2fec6
constant mimc_constant_302 0x136a3734420b9a29249f23e3292d871653540c3a86fdfbdbb655596aac99d0ce
constant mimc_constant_303 0x11ea5a840d53c0f0eaa111e6f43d953cdadcddedd8b7658d82266fd0897cd71a
constant mimc_constant_304 0x51a4d6a93c09813a72f272b043ef5cf88fe27eeadb2065cb75c95620874ea281
constant mimc_constant_305 0x00b698d1b30b8486b7fb7cafdae54bb93ac182be3623f1feffa7edc12486d4e8
constant mimc_constant_306 0x22386f894f2a9326c7ab4cfbceae435cb69f3e359ee49946dc566f242f4238de
constant mimc_constant_307 0x636d98aea6cb6afe50fd1e96bb8bfdf18a9d54a87e66fd79e3dff80abda98c18
constant mimc_constant_308 0x067a4de70930459165ff7d84a0dc375adb145ac07e67eb0e1fadebd4e2610eeb
constant mimc_constant_309 0x64721850463f2d1dfe148e429e472914d67d9867409de6c39150225106d4d425
constant mimc_constant_310 0x6c87827aa64247be6bb132c49e271a6e23c54c8334f2c3eca5551b4ae5260f05
constant mimc_constant_311 0x65cbbc751ea4f5e7956628b8645708187b37f2d65c6c297a5854355256de476e
constant mimc_constant_312 0x6bf24b343856b4066e2835b1fe3e5d16496a36f41386c2afd44d001ba886fdc7
constant mimc_constant_313 0x41d82825d409ab7c996773b516f6720e34cbfdebdc9c069fa579dcea11ef44f6
constant mimc_constant_314 0x45f741f2e9481a85b86467ab30d363fd0328e33d53fce6b39286c2494ee7bd28
constant mimc_constant_315 0x6c06f72d4e071f9c1ddca4f9ea231853f6d8c5e9b7418e9c564c995912d19c18
constant mimc_constant_316 0x154f9ecfb65370a8b59a12cd736348aead2e59a7e3701d20a669bec15363fe62
constant mimc_constant_317 0x0c4d910fbd3b57be6d6680e8d2db47c1454712b240b78468cb764702be5c1aec
constant mimc_constant_318 0x0e1ac575e1125f5ee86da3342018bc4f3c1e2310148043d5074eb4ee22fc55b6
constant mimc_constant_319 0x273531c7d0d03d8f97b722ef1f0c324dac39f804e0222202f7502946647ef332
constant mimc_constant_320 0x101464d19cf380958e5aef1084736db89f4cb131033ae670f6de0a5cf9d92b73
constant mimc_constant_321 0x597cdd384abdad1beccc73fb39f74a18eb44d056951d602c2ef6ef6448fc5626

View File

@@ -1,92 +0,0 @@
# :set syntax=pism
# :source ../scripts/pism.vim
constant G_VCV FixedGenerator
constant G_VCR FixedGenerator
constant CRH_IVK BlakePersonalization
#constant JUBJUB_FR_CAPACITY BinarySize
#constant NOTE_COMMIT PedersenPersonalization
contract mint_contract
# Value commitment
param value U64
param asset_id Fr
param randomness_value Fr
param randomness_asset Fr
param serial Fr
param randomness_coin Fr
param public Point
start
# Witness input values
u64_as_binary_le value param:value
fr_as_binary_le asset_id param:asset_id
fr_as_binary_le randomness_value param:randomness_value
fr_as_binary_le randomness_asset param:randomness_asset
fr_as_binary_le serial param:serial
fr_as_binary_le randomness_coin param:randomness_coin
witness public param:public
assert_not_small_order public
# Make value commitment
# V = v * G_VCV + r * G_VCR
ec_mul_const vcv value G_VCV
ec_mul_const rcv randomness_value G_VCR
ec_add cv vcv rcv
# emit cv
emit_ec cv
# Make asset_id commitment
# A = a * G_VCV + r_a * G_VCR
ec_mul_const vca asset_id G_VCV
ec_mul_const rca randomness_asset G_VCR
ec_add ca vca rca
# emit ca
emit_ec ca
# Make the coin
# C = Hash(public_key, value, asset_id, serial, randomness_coin)
# Build the preimage to hash
alloc_binary preimage
# public_key
ec_repr repr_public public
binary_extend preimage repr_public
# value
binary_extend preimage value
# Fr values are 252 bits so we need to pad it with extra 0s
# to match the Rust values which are 256 bits
{% macro binary_put_fr(binary, var) -%}
binary_extend {{ binary }} {{ var }}
{% for n in range(4) %}
alloc_const_bit zero_bit false
binary_push {{ binary }} zero_bit
{% endfor %}
{%- endmacro %}
# serial
{{ binary_put_fr("preimage", "serial") }}
# randomness_coin
{{ binary_put_fr("preimage", "randomness_coin") }}
# asset_id
{{ binary_put_fr("preimage", "asset_id") }}
# Public key: SubgroupPoint = 256 bits
# Value: u64 = 64 bits
# AssetID: Fr = 252 + 4 bits padding
# Serial: Fr = 252 + 4 bits padding
# Randomness coin Fr = 252 + 4 bits padding
# TOTAL: 1088 bits for preimage
static_assert_binary_size preimage 1088
blake2s coin preimage CRH_IVK
emit_binary coin
end

View File

@@ -1,41 +0,0 @@
{
"constants": {
"G_SPEND": {
"maps_to": "zcash_proofs::constants::SPENDING_KEY_GENERATOR"
},
"G_PROOF": {
"maps_to": "zcash_proofs::constants::PROOF_GENERATION_KEY_GENERATOR"
},
"CRH_IVK": {
"maps_to": "zcash_primitives::constants::CRH_IVK_PERSONALIZATION"
},
"PRF_NF": {
"maps_to": "zcash_primitives::constants::PRF_NF_PERSONALIZATION"
},
"G_VCV": {
"maps_to": "zcash_proofs::constants::VALUE_COMMITMENT_VALUE_GENERATOR"
},
"G_VCR": {
"maps_to": "zcash_proofs::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR"
},
"JUBJUB_FR_CAPACITY": {
"maps_to": "jubjub::Fr::CAPACITY as usize"
},
"NOTE_COMMIT": {
"maps_to": "pedersen_hash::Personalization::NoteCommitment"
},
"MERKLE_0": {
"maps_to": "pedersen_hash::Personalization::MerkleTree(0)"
},
"MERKLE_1": {
"maps_to": "pedersen_hash::Personalization::MerkleTree(1)"
},
"MERKLE_2": {
"maps_to": "pedersen_hash::Personalization::MerkleTree(2)"
},
"MERKLE_3": {
"maps_to": "pedersen_hash::Personalization::MerkleTree(3)"
}
}
}

View File

@@ -1,163 +0,0 @@
# :set syntax=pism
# :source ../scripts/pism.vim
constant G_VCV FixedGenerator
constant G_VCR FixedGenerator
constant G_SPEND FixedGenerator
constant G_PROOF FixedGenerator
constant G_NOTE_COMMIT_R FixedGenerator
constant G_NULL FixedGenerator
constant CRH_IVK BlakePersonalization
constant NOTE_COMMIT PedersenPersonalization
constant MERKLE_0 PedersenPersonalization
constant MERKLE_1 PedersenPersonalization
constant MERKLE_2 PedersenPersonalization
constant MERKLE_3 PedersenPersonalization
# ...
constant PRF_NF BlakePersonalization
constant JUBJUB_FR_CAPACITY ByteSize
contract input_spend
param value U64
param randomness Fr
param ak Point
param ar Fr
param nsk Fr
param g_d Point
param commitment_randomness Fr
param auth_path_0_0 Scalar
param auth_path_0_1 Bool
param auth_path_1_0 Scalar
param auth_path_1_1 Bool
# ...
param anchor Scalar
start
# let rk: Point = ak + ar * G_SPEND
witness ak param:ak
assert_not_small_order ak
fr_as_binary_le ar param:ar
ec_mul_const ar ar G_SPEND
ec_add rk ak ar
# emit rk
emit_ec rk
# let nk: Point = nsk * G_PROOF
fr_as_binary_le nsk param:nsk
ec_mul_const nk nsk G_PROOF
# let mut ivk_preimage: BinaryNumber = []
alloc_binary ivk_preimage
# ivk_preimage.put(ak)
ec_repr repr_ak ak
binary_extend ivk_preimage repr_ak
# let mut nf_preimage: BinaryNumber = []
alloc_binary nf_preimage
ec_repr repr_nk nk
binary_clone repr_nk repr_nk2
# ivk_preimage.put(nk)
binary_extend ivk_preimage repr_nk
# nf_preimage.put(nk)
binary_extend ivk_preimage repr_nk2
# assert ivk_preimage.len() == 512
static_assert_binary_size ivk_preimage 512
# assert nf_preimage.len() == 256
static_assert_binary_size nf_preimage 256
# let mut ivk = blake2s(ivk_preimage, CRH_IVK)
blake2s ivk ivk_preimage CRH_IVK
# ivk.truncate(JUBJUB_FR_CAPACITY)
binary_truncate ivk JUBJUB_FR_CAPACITY
# let pk_d: Point = ivk * g_d
witness g_d param:g_d
assert_not_small_order g_d
ec_mul pk_d ivk g_d
# let cv: Point = value * G_VCV + rcv * G_VCR
u64_as_binary_le value_bits param:value
ec_mul_const value value_bits G_VCV
fr_as_binary_le rcv param:randomness
ec_mul_const rcv rcv G_VCR
ec_add cv value rcv
# emit cv
emit_ec cv
# let mut note_contents: BinaryNumber = []
alloc_binary note_contents
# note_contents.put(value)
binary_extend note_contents value
# note_contents.put(g_d)
ec_repr repr_g_d g_d
binary_extend note_contents repr_g_d
# note_contents.put(p_k)
ec_repr repr_p_k p_k
binary_extend note_contents repr_p_k
# assert note_contents.len() == 64 + 256 + 256
static_assert_binary_size ivk_preimage 576
# let mut cm = pedersen_hash(note_contents, NOTE_COMMIT)
pedersen_hash cm note_contents NOTE_COMMIT
# cm += commitment_randomness * G_NOTE_COMMIT_R
fr_as_binary_le rcm param:commitment_randomness
ec_mul_const cm1 rcm G_NOTE_COMMIT_R
ec_add cm cm cm1
# let mut position = []
alloc_binary position
# let mut cur: Scalar = cm.u
ec_get_u cur cm
# There are no loops in this language.
# ZK proofs must have a fixed size.
# So in this assembly we UNROLL all loops.
# for i in range(auth_path.size()):
#
# Here we give the example of loop 0.
# Replace the indexes with the value i
# Below line is auth_path[0].1
# let (node: Scalar, is_right: Bool) = auth_path[i]
# position.push(is_right)
alloc_bit cur_is_right param:auth_path_0_1
clone_bit cur_is_right2 cur_is_right
binary_push position cur_is_right2
alloc_num path_element param:auth_path_0_0
# let (left: Scalar, right: Scalar) = swap_if(is_right, cur, node)
conditionally_reverse ulur cur path_element is_right
get_0 ul ulur
get_1 ur ulur
# let mut preimage: BinaryNumber = []
alloc_binary preimage
# preimage.put(left)
num_to_binary ul_bits ul
binary_extend preimage ul_bits
# preimage.put(right)
num_to_binary ur_bits ur
binary_extend preimage ur_bits
# cur = pedersen_hash(MERKLE_TREE[i], preimage).u
pedersen_hash curhash preimage MERKLE_0
ec_get_u cur curhash
# ... repeat the above N times
# enforce cur == rt
alloc_num rt param:anchor
num_enforce_equal cur rt
# emit rt
emit_num rt
# let rho: Point = rho + position * G_NULL
ec_mul_const position position_bits G_NULL
ec_add rho rho position
# nf_preimage.put(rho)
ec_repr repr_rho rho
binary_extend nf_preimage repr_rho
# assert nf_preimage.len() == 512
static_assert_binary_size nf_preimage 512
# let nf: BinaryNumber = blake2s(nf_preimage, PRF_NF)
blake2s nf nf_preimage PRF_NF
emit_binary nf
end

View File

@@ -1,175 +0,0 @@
# You will need this repo:
# https://github.com/zcash/librustzcash/
# Then compare this code to the file:
# librustzcash/zcash_proofs/src/circuit/sapling.rs
# What is the LC stuff?
# Difference between AllocatedNum and Num
# Why BlsScalar vs JJScalar?
const:
G_VCV: Point
G_VCR: Point
G_SPEND: Point
G_PROOF: Point
G_NOTE_COMMIT_R: Point
G_NULL: Point
CRH_IVK: Blake2sPersonalization
NOTE_COMMIT: PedersenPersonalization
MERKLE: list<PedersenPersonalization>
PRF_NF: Blake2sPersonalization
def value_commit(value: u64, randomness: Scalar) -> (Point, list<bool>):
let value_bits: list<bool> = value as list<bool>
let value: Point = value * G_VCV
let rcv: list<bool> = randomness as list<bool>
let rcv: Point = rcv * G_VCR
let cv: Point = value + rcv
return cv, value_bits
# The parameters to this function are the same as in:
# struct Spend
def input_burn(
value: u64, # ValueCommitment.value
randomness: Scalar, # ValueCommitment.randomness
ak: Point, # from ProofGenerationKey
ar: Scalar,
nsk: Scalar, # from ProofGenerationKey
g_d: Point, # Computed from payment_address
commitment_randomness: Scalar,
auth_path: list<(Scalar, bool)>,
anchor: Scalar
) -> (Point, Point, Point, list<bool>):
let ak = witness(ak)
ak.assert_not_small_order()
let ar: list<bool> = ar as list<bool>
let ar: Point = ar * G_SPEND
let rk: Point = ak + ar
let nsk: list<bool> = nsk as list<bool>
let nk: Point = nsk * G_PROOF
let mut ivk_preimage: list<bool> = []
# Must be list<bool> as well
ivk_preimage.extend(ak.repr())
let mut nf_preimage: list<bool> = []
let nk_repr: list<bool> = nk.repr()
ivk_preimage.extend(nk_repr)
nf_preimage.extend(nk_repr)
assert len(ivk_preimage) == 512
assert len(nf_preimage) == 256
let mut ivk: list<bool> = blake2s(ivk_preimage, CRH_IVK)
ivk.truncate(Scalar::CAPACITY)
let g_d: Point = witness g_d
g_d.assert_not_small_order()
let pk_d: Point = ivk * g_d
let mut note_contents: list<bool> = []
let (cv: Point, value_bits: list<bool>) = value_commit(value, randomness)
let mut value_num: Num = Num.zero()
let mut coeff: Scalar = Scalar.one()
for bit in value_bits:
value_num = value_num.add_bool_with_coeff(bit, coeff)
coeff = coeff.double()
# Is this equivalent?
let value_num = value_bits as Num
note_contents.extend(value_bits)
note_contents.extend(g_d)
note_contents.extend(pk_d)
assert len(note_contents) == 64 + 256 + 256
let mut cm: Point = pedersen_hash(NOTE_COMMIT, note_contents)
let rcm: list<bool> = commitment_randomness as list<bool>
let rcm: Point = rcm * G_NOTE_COMMIT_R
cm += rcm
let mut position_bits: list<bool> = []
let mut cur: Scalar = cm.u
for i, (node, is_right) in enumerate(auth_path):
position_bits.push(is_right)
let node: EncryptedNum = EncryptedNum.from(node)
print(node)
let (left: list<bool>, right: list<bool>) = Num.swap_if(is_right, cur, node)
let mut preimage: list<bool> = []
preimage.extend(left)
preimage.extend(right)
cur = pedersen_hash(MERKLE_TREE[i], preimage).u
let rt: Point = EncryptedNum.from(anchor)
enforce (cur - rt) * value_num == 0
let position: Point = position_bits * G_NULL
let rho: Point = cm + position
nf_preimage.extend(rho)
assert len(nf_preimage) == 512
let nf: list<bool> = blake2s(nf_preimage, PRF_NF)
return (rk, cv, rt, nf)
def output_mint(
value: u64,
randomness: Scalar,
g_d: Point,
esk: Scalar,
pk_d: Point,
commitment_randomness: Scalar
) -> (Point, Point, Scalar):
let (cv: Point, value_bits: list<bool>) = value_commit(value, randomness)
let mut note_contents: list<bool> = []
note_contents.extend(value_bits)
let g_d: Point = witness g_d
assert is_not_small_order(g_d)
let esk: list<bool> = esk as list<bool>
let epk: Point = esk * g_d
let v_contents: list<bool> = pk_d.v as list<bool>
let sign_bit: bool = pk_d.u.is_odd() as bool
note_contents.extend(v_contents)
note_contents.push(sign_bit)
assert len(note_contents) == 64 + 256 + 256
let mut cm: Point = pedersen_hash(NOTE_COMMIT, note_contents)
let rcm: list<bool> = commitment_randomness as list<bool>
let rcm: Point = rcm * G_NOTE_COMMIT_R
cm += rcm
let cmu: Scalar = cm.u
return (cv, epk, cmu)

View File

@@ -1,179 +0,0 @@
# You will need this repo:
# https://github.com/zcash/librustzcash/
# Then compare this code to the file:
# librustzcash/zcash_proofs/src/circuit/sapling.rs
# What is the LC stuff?
# Difference between AllocatedNum and Num
# Why BlsScalar vs JJScalar?
const:
G_VCV: Point
G_VCR: Point
G_SPEND: Point
G_PROOF: Point
G_NOTE_COMMIT_R: Point
G_NULL: Point
CRH_IVK: Blake2sPersonalization
NOTE_COMMIT: PedersenPersonalization
MERKLE: list<PedersenPersonalization>
PRF_NF: Blake2sPersonalization
def value_commit(value: u64, randomness: Scalar) -> (Point, list<bool>):
let value_bits: list<bool> = value as list<bool>
let value: Point = value * G_VCV
let rcv: list<bool> = randomness as list<bool>
let rcv: Point = rcv * G_VCR
let cv: Point = value + rcv
emit cv
return value_bits
# The parameters to this function are the same as in:
# struct Spend
proof input_burn:
private:
value: u64 # ValueCommitment.value
randomness: Scalar # ValueCommitment.randomness
ak: Point # from ProofGenerationKey
ar: Scalar
nsk: Scalar # from ProofGenerationKey
g_d: Point # Computed from payment_address
commitment_randomness: Scalar
auth_path: list<(Scalar, bool)>
anchor: Scalar
contract -> (Point, Point, Point, list<bool>):
let ak = witness(ak)
ak.assert_not_small_order()
let ar: list<bool> = ar as list<bool>
let ar: Point = ar * G_SPEND
let rk: Point = ak + ar
emit rk
let nsk: list<bool> = nsk as list<bool>
let nk: Point = nsk * G_PROOF
let mut ivk_preimage: list<bool> = []
# Must be list<bool> as well
ivk_preimage.extend(ak.repr())
let mut nf_preimage: list<bool> = []
let nk_repr: list<bool> = nk.repr()
ivk_preimage.extend(nk_repr)
nf_preimage.extend(nk_repr)
assert len(ivk_preimage) == 512
assert len(nf_preimage) == 256
let mut ivk: list<bool> = blake2s(ivk_preimage, CRH_IVK)
ivk.truncate(Scalar::CAPACITY)
let g_d: Point = witness g_d
g_d.assert_not_small_order()
let pk_d: Point = ivk * g_d
let mut note_contents: list<bool> = []
let (cv: Point, value_bits: list<bool>) = value_commit(value, randomness)
let mut value_num: Num = Num.zero()
let mut coeff: Scalar = Scalar.one()
for bit in value_bits:
value_num = value_num.add_bool_with_coeff(bit, coeff)
coeff = coeff.double()
# Is this equivalent?
let value_num = value_bits as Num
note_contents.extend(value_bits)
note_contents.extend(g_d)
note_contents.extend(pk_d)
assert len(note_contents) == 64 + 256 + 256
let mut cm: Point = pedersen_hash(NOTE_COMMIT, note_contents)
let rcm: list<bool> = commitment_randomness as list<bool>
let rcm: Point = rcm * G_NOTE_COMMIT_R
cm += rcm
let mut position_bits: list<bool> = []
let mut cur: Scalar = cm.u
for i, (node, is_right) in enumerate(auth_path):
position_bits.push(is_right)
let node: EncryptedNum = EncryptedNum.from(node)
print(node)
let (left: list<bool>, right: list<bool>) = Num.swap_if(is_right, cur, node)
let mut preimage: list<bool> = []
preimage.extend(left)
preimage.extend(right)
cur = pedersen_hash(MERKLE_TREE[i], preimage).u
let rt: Point = EncryptedNum.from(anchor)
enforce (cur - rt) * value_num == 0
emit rt
let position: Point = position_bits * G_NULL
let rho: Point = cm + position
nf_preimage.extend(rho)
assert len(nf_preimage) == 512
let nf: list<bool> = blake2s(nf_preimage, PRF_NF)
emit nf
def output_mint(
value: u64,
randomness: Scalar,
g_d: Point,
esk: Scalar,
pk_d: Point,
commitment_randomness: Scalar
) -> (Point, Point, Scalar):
let (cv: Point, value_bits: list<bool>) = value_commit(value, randomness)
let mut note_contents: list<bool> = []
note_contents.extend(value_bits)
let g_d: Point = witness g_d
assert is_not_small_order(g_d)
let esk: list<bool> = esk as list<bool>
let epk: Point = esk * g_d
let v_contents: list<bool> = pk_d.v as list<bool>
let sign_bit: bool = pk_d.u.is_odd() as bool
note_contents.extend(v_contents)
note_contents.push(sign_bit)
assert len(note_contents) == 64 + 256 + 256
let mut cm: Point = pedersen_hash(NOTE_COMMIT, note_contents)
let rcm: list<bool> = commitment_randomness as list<bool>
let rcm: Point = rcm * G_NOTE_COMMIT_R
cm += rcm
let cmu: Scalar = cm.u
return (cv, epk, cmu)

View File

@@ -1,178 +0,0 @@
# You will need this repo:
# https://github.com/zcash/librustzcash/
# Then compare this code to the file:
# librustzcash/zcash_proofs/src/circuit/sapling.rs
# What is the LC stuff?
# Difference between AllocatedNum and Num
# Why BlsScalar vs JJScalar?
const:
G_VCV: SubgroupPoint
G_VCR: SubgroupPoint
G_SPEND: SubgroupPoint
G_PROOF: SubgroupPoint
G_NOTE_COMMIT_R: SubgroupPoint
G_NULL: SubgroupPoint
CRH_IVK: Blake2sPersonalization
NOTE_COMMIT: PedersenPersonalization
MERKLE: list<PedersenPersonalization>
PRF_NF: Blake2sPersonalization
def value_commit(value: U64, randomness: Scalar) -> Binary:
let value_bits: Binary = value as Binary
let value: SubgroupPoint = value * G_VCV
let rcv: Binary = randomness as Binary
let rcv: SubgroupPoint = rcv * G_VCR
let cv: SubgroupPoint = value + rcv
emit cv
return value_bits
# The parameters to this function are the same as in:
# struct Spend
contract input_burn(
value: U64, # ValueCommitment.value
randomness: Scalar, # ValueCommitment.randomness
ak: SubgroupPoint, # from ProofGenerationKey
ar: Scalar,
nsk: Scalar, # from ProofGenerationKey
g_d: SubgroupPoint, # Computed from payment_address
commitment_randomness: Scalar,
auth_path: list<(Scalar, Bool)>,
anchor: Scalar
) -> (SubgroupPoint, SubgroupPoint, SubgroupPoint, Binary):
let ak = witness(ak)
ak.assert_not_small_order()
let ar: Binary = ar as Binary
let ar: SubgroupPoint = ar * G_SPEND
let rk: SubgroupPoint = ak + ar
let nsk: Binary = nsk as Binary
let nk: SubgroupPoint = nsk * G_PROOF
let mut ivk_preimage: Binary = []
# Must be Binary as well
ivk_preimage.extend(ak.repr())
let mut nf_preimage: Binary = []
let nk_repr: Binary = nk.repr()
ivk_preimage.extend(nk_repr)
nf_preimage.extend(nk_repr)
assert len(ivk_preimage) == 512
assert len(nf_preimage) == 256
let mut ivk: Binary = blake2s(ivk_preimage, CRH_IVK)
ivk.truncate(Scalar.CAPACITY)
let g_d: SubgroupPoint = witness g_d
g_d.assert_not_small_order()
let pk_d: SubgroupPoint = ivk * g_d
let mut note_contents: Binary = []
let (cv: SubgroupPoint, value_bits: Binary) = value_commit(value, randomness)
let mut value_num: Num = Num.zero()
let mut coeff: Scalar = Scalar.one()
for bit in value_bits:
value_num = value_num.add_Bool_with_coeff(bit, coeff)
coeff = coeff.double()
# Is this equivalent?
let value_num = value_bits as Num
note_contents.extend(value_bits)
note_contents.extend(g_d)
note_contents.extend(pk_d)
assert len(note_contents) == 64 + 256 + 256
let mut cm: SubgroupPoint = pedersen_hash(NOTE_COMMIT, note_contents)
let rcm: Binary = commitment_randomness as Binary
let rcm: SubgroupPoint = rcm * G_NOTE_COMMIT_R
cm += rcm
let mut position_bits: Binary = []
let mut cur: Scalar = cm.u
for i in range(auth_path.size()):
let (node: Scalar, is_right: Bool) = auth_path[i]
position_bits.push(is_right)
let node: EncryptedNum = EncryptedNum.from(node)
print(node)
let (left: Binary, right: Binary) = Num.swap_if(is_right, cur, node)
let mut preimage: Binary = []
preimage.extend(left)
preimage.extend(right)
cur = pedersen_hash(MERKLE_TREE[i], preimage).u
let rt: SubgroupPoint = EncryptedNum.from(anchor)
enforce (cur - rt) * value_num == 0
let position: SubgroupPoint = position_bits * G_NULL
let rho: SubgroupPoint = cm + position
nf_preimage.extend(rho)
assert len(nf_preimage) == 512
let nf: Binary = blake2s(nf_preimage, PRF_NF)
emit (rk, cv, rt, nf)
contract output_mint(
value: U64,
randomness: Scalar,
g_d: SubgroupPoint,
esk: Scalar,
pk_d: SubgroupPoint,
commitment_randomness: Scalar
) -> (SubgroupPoint, SubgroupPoint, Scalar):
let value_bits: Binary = value_commit(value, randomness)
let mut note_contents: Binary = []
note_contents.extend(value_bits)
let g_d: EdwardsPoint = witness(g_d)
g_d.assert_not_small_order()
let esk: Binary = esk as Binary
let epk: SubgroupPoint = esk * g_d
let v_contents: Binary = pk_d.v as Binary
let sign_bit: Bool = pk_d.u.is_odd() as Bool
note_contents.extend(v_contents)
note_contents.push(sign_bit)
assert len(note_contents) == 64 + 256 + 256
let mut cm: SubgroupPoint = pedersen_hash(NOTE_COMMIT, note_contents)
let rcm: Binary = commitment_randomness as Binary
let rcm: SubgroupPoint = rcm * G_NOTE_COMMIT_R
cm += rcm
let cmu: Scalar = cm.u
emit (cv, epk, cmu)

View File

@@ -1,120 +0,0 @@
# :set syntax=drk
# :source ../scripts/drk.vim
const:
G_VCV: SubgroupPoint
G_VCR: SubgroupPoint
G_SPEND: SubgroupPoint
G_PROOF: SubgroupPoint
G_NOTE_COMMIT_R: SubgroupPoint
G_NULL: SubgroupPoint
CRH_IVK: Blake2sPersonalization
NOTE_COMMIT: PedersenPersonalization
MERKLE: list<PedersenPersonalization>
PRF_NF: Blake2sPersonalization
contract input_spend(
value: U64 -> BinaryNumber
randomness: Fr -> BinaryNumber
ak: Point
ar: Fr -> BinaryNumber
nsk: Fr -> BinaryNumber
g_d: Point
commitment_randomness: Fr -> BinaryNumber
auth_path: [(Scalar, Bool)]
anchor: Scalar
) -> (Point, Point, Scalar, BinaryNumber):
let rk: Point = ak + ar * G_SPEND
emit rk
let nk: Point = nsk * G_PROOF
let mut ivk_preimage: BinaryNumber = []
ivk_preimage.put(ak)
let mut nf_preimage: BinaryNumber = []
ivk_preimage.put(nk)
nf_preimage.put(nk)
assert ivk_preimage.len() == 512
assert nf_preimage.len() == 256
let mut ivk = blake2s(ivk_preimage, CRH_IVK)
ivk.truncate(JUBJUB_FR_CAPACITY)
# This will error if ivk.len() != 256
#let ivk: Fr = ivk as Fr
let pk_d: Point = ivk * g_d
let cv: Point = value * G_VCV + rcv * G_VCR
emit cv
let mut note_contents: BinaryNumber = []
note_contents.put(value)
note_contents.put(g_d)
note_contents.put(p_k)
assert note_contents.len() == 64 + 256 + 256
let mut cm = pedersen_hash(note_contents, NOTE_COMMIT)
cm += commitment_randomness * G_NOTE_COMMIT_R
let mut position = []
let mut cur: Scalar = cm.u
for i in range(auth_path.size()):
let (node: Scalar, is_right: Bool) = auth_path[i]
position.push(is_right)
# Scalar -> AllocatedNum
let (left: Scalar, right: Scalar) = swap_if(is_right, cur, node)
let mut preimage: BinaryNumber = []
preimage.put(left)
preimage.put(right)
cur = pedersen_hash(MERKLE_TREE[i], preimage).u
enforce cur == rt
emit rt
let rho: Point = rho + position * G_NULL
nf_preimage.put(rho)
assert nf_preimage.len() == 512
let nf: BinaryNumber = blake2s(nf_preimage, PRF_NF)
emit nf
contract output_mint(
value: U64 -> BinaryNumber
randomness: Fr -> BinaryNumber
g_d: Point
esk: Fr -> BinaryNumber
pk_d: Point
commitment_randomness: Fr -> BinaryNumber
) -> (Point, Point, Scalar):
let cv: Point = value * G_VCV + rcv * G_VCR
emit cv
let mut note_contents: Binary = []
note_contents.put(value)
let epk: Point = esk * g_d
emit epk
let v_contents: Scalar = pk_d.v
let sign_bit: Bool = pk_d.u.is_odd()
note_contents.put(v_contents)
note_contents.put(sign_bit)
assert len(note_contents) == 64 + 256 + 256
let mut cm: Point = pedersen_hash(note_contents, NOTE_COMMIT)
let rcm: Point = commitment_randomness * G_NOTE_COMMIT_R
cm += rcm
let cmu: Scalar = cm.u
emit cmu

View File

@@ -1,23 +0,0 @@
{
"constants": {
"G_SPEND": {
"maps_to": "zcash_proofs::constants::SPENDING_KEY_GENERATOR"
},
"G_VCV": {
"maps_to": "zcash_proofs::constants::VALUE_COMMITMENT_VALUE_GENERATOR"
},
"G_VCR": {
"maps_to": "zcash_proofs::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR"
},
"CRH_IVK": {
"maps_to": "zcash_primitives::constants::CRH_IVK_PERSONALIZATION"
},
"JUBJUB_FR_CAPACITY": {
"maps_to": "jubjub::Fr::CAPACITY as usize"
},
"NOTE_COMMIT": {
"maps_to": "pedersen_hash::Personalization::NoteCommitment"
}
}
}

View File

@@ -1,57 +0,0 @@
# :set syntax=pism
# :source ../scripts/pism.vim
constant G_SPEND FixedGenerator
constant CRH_IVK BlakePersonalization
constant JUBJUB_FR_CAPACITY BinarySize
constant NOTE_COMMIT PedersenPersonalization
contract input_spend
param secret Fr
param ak Point
param value U64
param is_cool Bool
param path Scalar
start
# Compute P = xG + A
witness ak param:ak
assert_not_small_order ak
fr_as_binary_le secret param:secret
ec_mul_const public secret G_SPEND
ec_add public public ak
emit_ec public
# Make some a blake2s hash
alloc_binary preimage
ec_repr repr_ak ak
binary_extend preimage repr_ak
static_assert_binary_size preimage 256
blake2s ivk preimage CRH_IVK
emit_binary ivk
# Below lines are random garbage
# Uncomment them to test
#binary_clone ivk2 ivk
#binary_truncate ivk2 JUBJUB_FR_CAPACITY
#u64_as_binary_le value_bits param:value
#ec_mul pk_d value_bits public
#pedersen_hash cm ivk NOTE_COMMIT
#ec_get_u cur cm
#
#alloc_bit is_cool param:is_cool
#clone_bit is_cool2 is_cool
#binary_push ivk is_cool2
#alloc_scalar path param:path
#conditionally_reverse ul ur cur path is_cool
#scalar_as_binary ul_bin ul
#binary_extend preimage ul_bin
#scalar_enforce_equal ur ul
#emit_scalar ur
end

View File

@@ -1,8 +0,0 @@
const G_SPEND: SubgroupPoint
contract input_spend(
secret: Fr -> BinaryNumber
) -> Point:
let public: Point = secret * G_SPEND
emit public

View File

@@ -1,69 +0,0 @@
# :set syntax=pism
# :source ../scripts/pism.vim
constant G_SPEND FixedGenerator
constant CRH_IVK BlakePersonalization
constant JUBJUB_FR_CAPACITY BinarySize
constant NOTE_COMMIT PedersenPersonalization
contract input_spend
param secret Fr
param ak Point
param value U64
param is_cool Bool
param path Scalar
{% for n in range(10) %}
param path_{{ n }} Scalar
param is_right_{{ n }} Bool
{% endfor %}
start
# Compute P = xG + A
witness ak param:ak
assert_not_small_order ak
fr_as_binary_le secret param:secret
ec_mul_const public secret G_SPEND
ec_add public public ak
emit_ec public
# Make some a blake2s hash
alloc_binary preimage
ec_repr repr_ak ak
binary_extend preimage repr_ak
static_assert_binary_size preimage 256
blake2s ivk preimage CRH_IVK
emit_binary ivk
############
# For loop 10 times
{% for n in range(10) %}
alloc_bit is_right param:is_right_{{ n }}
alloc_scalar path param:path_{{ n }}
{% endfor %}
############
# Below lines are random garbage
# Uncomment them to test
#binary_clone ivk2 ivk
#binary_truncate ivk2 JUBJUB_FR_CAPACITY
#u64_as_binary_le value_bits param:value
#ec_mul pk_d value_bits public
#pedersen_hash cm ivk NOTE_COMMIT
#ec_get_u cur cm
#
#alloc_bit is_cool param:is_cool
#clone_bit is_cool2 is_cool
#binary_push ivk is_cool2
#alloc_scalar path param:path
#conditionally_reverse ul ur cur path is_cool
#scalar_as_binary ul_bin ul
#binary_extend preimage ul_bin
#scalar_enforce_equal ur ul
#emit_scalar ur
end

View File

@@ -1,165 +0,0 @@
# :set syntax=pism
# :source ../scripts/pism.vim
constant G_VCV FixedGenerator
constant G_VCR FixedGenerator
constant G_SPEND FixedGenerator
constant G_PROOF FixedGenerator
constant G_NOTE_COMMIT_R FixedGenerator
constant G_NULL FixedGenerator
constant CRH_IVK BlakePersonalization
constant NOTE_COMMIT PedersenPersonalization
constant MERKLE_0 PedersenPersonalization
constant MERKLE_1 PedersenPersonalization
constant MERKLE_2 PedersenPersonalization
constant MERKLE_3 PedersenPersonalization
# ...
constant PRF_NF BlakePersonalization
constant JUBJUB_FR_CAPACITY ByteSize
contract input_spend
param secret Fr
param value U64
param randomness Fr
param ak Point
param ar Fr
param nsk Fr
param g_d Point
param commitment_randomness Fr
param auth_path_0_0 Scalar
param auth_path_0_1 Bool
param auth_path_1_0 Scalar
param auth_path_1_1 Bool
# ...
param anchor Scalar
start
# let rk: Point = ak + ar * G_SPEND
witness ak param:ak
assert_not_small_order ak
fr_as_binary_le ar param:ar
ec_mul_const ar ar G_SPEND
ec_add rk ak ar
# emit rk
emit_ec rk
# let nk: Point = nsk * G_PROOF
fr_as_binary_le nsk param:nsk
ec_mul_const nk nsk G_PROOF
# let mut ivk_preimage: BinaryNumber = []
alloc_binary ivk_preimage
# ivk_preimage.put(ak)
ec_repr repr_ak ak
binary_extend ivk_preimage repr_ak
# let mut nf_preimage: BinaryNumber = []
alloc_binary nf_preimage
ec_repr repr_nk nk
binary_clone repr_nk2 repr_nk
# ivk_preimage.put(nk)
binary_extend ivk_preimage repr_nk
# nf_preimage.put(nk)
binary_extend ivk_preimage repr_nk2
# assert ivk_preimage.len() == 512
static_assert_binary_size ivk_preimage 512
# assert nf_preimage.len() == 256
static_assert_binary_size nf_preimage 256
# let mut ivk = blake2s(ivk_preimage, CRH_IVK)
blake2s ivk ivk_preimage CRH_IVK
# ivk.truncate(JUBJUB_FR_CAPACITY)
binary_truncate ivk JUBJUB_FR_CAPACITY
# let pk_d: Point = ivk * g_d
witness g_d param:g_d
assert_not_small_order g_d
ec_mul pk_d ivk g_d
# let cv: Point = value * G_VCV + rcv * G_VCR
u64_as_binary_le value_bits param:value
ec_mul_const value value_bits G_VCV
fr_as_binary_le rcv param:randomness
ec_mul_const rcv rcv G_VCR
ec_add cv value rcv
# emit cv
emit_ec cv
# let mut note_contents: BinaryNumber = []
alloc_binary note_contents
# note_contents.put(value)
binary_extend note_contents value
# note_contents.put(g_d)
ec_repr repr_g_d g_d
binary_extend note_contents repr_g_d
# note_contents.put(p_k)
ec_repr repr_p_k p_k
binary_extend note_contents repr_p_k
# assert note_contents.len() == 64 + 256 + 256
static_assert_binary_size ivk_preimage 576
# let mut cm = pedersen_hash(note_contents, NOTE_COMMIT)
pedersen_hash cm note_contents NOTE_COMMIT
# cm += commitment_randomness * G_NOTE_COMMIT_R
fr_as_binary_le rcm param:commitment_randomness
ec_mul_const cm1 rcm G_NOTE_COMMIT_R
ec_add cm cm cm1
# let mut position = []
alloc_binary position
# let mut cur: Scalar = cm.u
ec_get_u cur cm
###############################################
# There are no loops in this language.
# ZK proofs must have a fixed size.
# So in this assembly we UNROLL all loops.
# for i in range(auth_path.size()):
#
# Here we give the example of loop 0.
# Replace the indexes with the value i
# Below line is auth_path[0].1
# let (node: Scalar, is_right: Bool) = auth_path[i]
# position.push(is_right)
alloc_bit cur_is_right param:auth_path_0_1
clone_bit cur_is_right2 cur_is_right
binary_push position cur_is_right2
alloc_num path_element param:auth_path_0_0
# let (left: Scalar, right: Scalar) = swap_if(is_right, cur, node)
conditionally_reverse ul ur cur path_element is_right
# let mut preimage: BinaryNumber = []
alloc_binary preimage
# preimage.put(left)
num_to_binary ul_bits ul
binary_extend preimage ul_bits
# preimage.put(right)
num_to_binary ur_bits ur
binary_extend preimage ur_bits
# cur = pedersen_hash(MERKLE_TREE[i], preimage).u
pedersen_hash curhash preimage MERKLE_0
ec_get_u cur curhash
# ... repeat the above N times
###############################################
# enforce cur == rt
alloc_num rt param:anchor
num_enforce_equal cur rt
# emit rt
emit_num rt
# let rho: Point = rho + position * G_NULL
ec_mul_const position position_bits G_NULL
ec_add rho rho position
# nf_preimage.put(rho)
ec_repr repr_rho rho
binary_extend nf_preimage repr_rho
# assert nf_preimage.len() == 512
static_assert_binary_size nf_preimage 512
# let nf: BinaryNumber = blake2s(nf_preimage, PRF_NF)
blake2s nf nf_preimage PRF_NF
emit_binary nf
end

View File

@@ -1,158 +0,0 @@
constant G_VCV FixedGenerator
constant G_VCR FixedGenerator
constant G_SPEND FixedGenerator
constant PRF_NF BlakePersonalization
constant CRH_IVK BlakePersonalization
constant NOTE_COMMIT PedersenPersonalization
{% for i in range(32) %}
constant MERKLE_{{ i }} PedersenPersonalization
{% endfor %}
contract spend_contract
# Value commitment
param value U64
param asset_id Fr
param randomness_value Fr
param randomness_asset Fr
param serial Fr
param randomness_coin Fr
param secret Fr
param signature_secret Fr
{% for i in range(32) %}
param branch_{{ i }} Scalar
param is_right_{{ i }} Bool
{% endfor %}
start
# Witness input values
u64_as_binary_le value param:value
fr_as_binary_le asset_id param:asset_id
fr_as_binary_le randomness_value param:randomness_value
fr_as_binary_le randomness_asset param:randomness_asset
# Make value commitment
# V = v * G_VCV + r * G_VCR
ec_mul_const vcv value G_VCV
ec_mul_const rcv randomness_value G_VCR
ec_add cv vcv rcv
# emit cv
emit_ec cv
# Make asset_id commitment
# A = a * G_VCV + r * G_VCR
ec_mul_const vca asset_id G_VCV
ec_mul_const rca randomness_asset G_VCR
ec_add ca vca rca
# emit ca
emit_ec ca
# Make the nullifier
# N = Hash(secret, serial)
fr_as_binary_le serial param:serial
fr_as_binary_le secret param:secret
alloc_binary nf_preimage
# Fr values are 252 bits so we need to pad it with extra 0s
# to match the Rust values which are 256 bits
{% macro binary_put_fr(binary, var) -%}
binary_extend {{ binary }} {{ var }}
{% for n in range(4) %}
alloc_const_bit zero_bit false
binary_push {{ binary }} zero_bit
{% endfor %}
{%- endmacro %}
# secret
binary_clone secret2 secret
{{ binary_put_fr("nf_preimage", "secret2") }}
# serial
binary_clone serial2 serial
{{ binary_put_fr("nf_preimage", "serial2") }}
# Secret: Fr = 252 + 4 bits padding
# Serial: Fr = 252 + 4 bits padding
# TOTAL: 512 bits for preimage
static_assert_binary_size nf_preimage 512
blake2s nf nf_preimage PRF_NF
emit_binary nf
# Derive the public key
# P = secret * G
ec_mul_const public secret G_SPEND
# Make the coin (same as mint contract)
# C = Hash(public_key, value, asset_id, serial, randomness_coin)
fr_as_binary_le randomness_coin param:randomness_coin
# Build the preimage to hash
alloc_binary preimage
# public_key
ec_repr repr_public public
binary_extend preimage repr_public
# value
binary_extend preimage value
# serial
{{ binary_put_fr("preimage", "serial") }}
# randomness_coin
{{ binary_put_fr("preimage", "randomness_coin") }}
# asset_id
{{ binary_put_fr("preimage", "asset_id") }}
# Public key: SubgroupPoint = 256 bits
# Value: u64 = 64 bits
# AssetID: Fr = 252 + 4 bits padding
# Serial: Fr = 252 + 4 bits padding
# Randomness coin Fr = 252 + 4 bits padding
# TOTAL: 1088 bits for preimage
static_assert_binary_size preimage 1088
blake2s coin preimage CRH_IVK
# Debug stuff. Normally we don't reveal the coin in the spend proof.
#binary_clone coin2 coin
#emit_binary coin2
# coin_commit = PedersenHash(coin)
pedersen_hash cm coin NOTE_COMMIT
# left = coin_commit.u
ec_get_u current cm
# Our merkle tree has a height of 32
{% for i in range(32) %}
# left = current
# right = branch[{{ i }}]
alloc_scalar branch param:branch_{{ i }}
# is_right = is_right[{{ i }}]
alloc_bit is_right param:is_right_{{ i }}
# reverse(a, b, condition) = if condition (b, a) else (a, b)
conditionally_reverse left right current branch is_right
# coin_commit = PedersenHash(left || right)
scalar_as_binary left left
scalar_as_binary right right
alloc_binary preimage
binary_extend preimage left
binary_extend preimage right
pedersen_hash cm preimage MERKLE_{{ i }}
# current = coin_commit.u
ec_get_u current cm
{% endfor %}
# Reveal the merkle root
emit_scalar current
# Emit the signature public key
fr_as_binary_le signature_secret param:signature_secret
ec_mul_const signature_public signature_secret G_SPEND
emit_ec signature_public
end

View File

@@ -1,52 +0,0 @@
constant one 0x0000000000000000000000000000000000000000000000000000000000000001
contract tutorial_contract
param w
param a
param b
private m
set m a
mul m b
# ab = m
lc0_add a
lc1_add b
lc2_add m
enforce
# v = wab ...
public v
set v w
mul v a
mul v b
# v = wab + a + b ...
add v a
add v b
# v = wab + a + b - v'
# v' = w(a + b)
local vprime
set vprime a
add vprime b
mul vprime w
sub v vprime
# w(m - a - b) = v - a - b
lc0_add w
lc1_add m
lc1_sub a
lc1_sub b
lc2_add v
lc2_sub a
lc2_sub b
enforce
# Binary check that w^2 = w
lc0_add w
lc1_add w
lc2_add w
enforce
end

View File

@@ -1,31 +0,0 @@
constant v 123
contract input_spend
param x
private x2
set x2 x
mul x2 x
lc0_add x
lc1_add x
lc2_add x2
enforce
private x3
set x3 x2
mul x3 x
lc0_add x2
lc1_add x
lc2_add x3
enforce
public input
set input x3
lc0_add input
lc1_add_one
lc2_add x3
enforce
end

View File

@@ -1,131 +0,0 @@
# Functions here are called from pism.py using getattr()
# and the function name as a string.
def witness(line, out, point):
return \
r"""let %s = ecc::EdwardsPoint::witness(
cs.namespace(|| "%s"),
%s.map(jubjub::ExtendedPoint::from))?;""" % (out, line, point)
def assert_not_small_order(line, point):
return '%s.assert_not_small_order(cs.namespace(|| "%s"))?;' % (point, line)
def u64_as_binary_le(line, out, val):
return \
r"""let %s = boolean::u64_into_boolean_vec_le(
cs.namespace(|| "%s"),
%s,
)?;""" % (out, line, val)
def fr_as_binary_le(line, out, fr):
return \
r"""let %s = boolean::field_into_boolean_vec_le(
cs.namespace(|| "%s"), %s)?;""" % (out, line, fr)
def ec_mul_const(line, out, fr, base):
return \
r"""let %s = ecc::fixed_base_multiplication(
cs.namespace(|| "%s"),
&%s,
&%s,
)?;""" % (out, line, base, fr)
def ec_mul(line, out, fr, base):
return 'let %s = %s.mul(cs.namespace(|| "%s"), &%s)?;' % (
out, base, line, fr)
def ec_add(line, out, a, b):
return 'let %s = %s.add(cs.namespace(|| "%s"), &%s)?;' % (out, a, line, b)
def ec_repr(line, out, point):
return 'let %s = %s.repr(cs.namespace(|| "%s"))?;' % (out, point, line)
def ec_get_u(line, out, point):
return "let mut %s = %s.get_u().clone();" % (out, point)
def emit_ec(line, point):
return '%s.inputize(cs.namespace(|| "%s"))?;' % (point, line)
def alloc_binary(line, out):
return "let mut %s = vec![];" % out
def binary_clone(line, out, binary):
return "let mut %s: Vec<_> = %s.iter().cloned().collect();" % (out, binary)
def binary_extend(line, binary, value):
return "%s.extend(%s);" % (binary, value)
def binary_push(line, binary, bit):
return "%s.push(%s);" % (binary, bit)
def binary_truncate(line, binary, size):
return "%s.truncate(%s);" % (binary, size)
def static_assert_binary_size(line, binary, size):
return "assert_eq!(%s.len(), %s);" % (binary, size)
def blake2s(line, out, input, personalization):
return \
r"""let mut %s = blake2s::blake2s(
cs.namespace(|| "%s"),
&%s,
%s,
)?;""" % (out, line, input, personalization)
def pedersen_hash(line, out, input, personalization):
return \
r"""let mut %s = pedersen_hash::pedersen_hash(
cs.namespace(|| "%s"),
%s,
&%s,
)?;""" % (out, line, personalization, input)
def emit_binary(line, binary):
return 'multipack::pack_into_inputs(cs.namespace(|| "%s"), &%s)?;' % (
line, binary)
def alloc_bit(line, out, value):
return \
r"""let %s = boolean::Boolean::from(boolean::AllocatedBit::alloc(
cs.namespace(|| "%s"),
%s
)?);""" % (out, line, value)
def alloc_const_bit(line, out, value):
return "let %s = Boolean::constant(%s);" % (out, value)
def clone_bit(line, out, value):
return "let %s = %s.clone();" % (out, value)
def alloc_scalar(line, out, scalar):
return \
r"""let %s =
num::AllocatedNum::alloc(cs.namespace(|| "%s"), || Ok(*%s.get()?))?;""" % (
out, line, scalar)
def scalar_as_binary(line, out, scalar):
return 'let %s = %s.to_bits_le(cs.namespace(|| "%s"))?;' % (out, scalar,
line)
def emit_scalar(line, scalar):
return '%s.inputize(cs.namespace(|| "%s"))?;' % (scalar, line)
def scalar_enforce_equal(line, scalar_left, scalar_right):
return \
r"""cs.enforce(
|| "%s",
|lc| lc + %s.get_variable(),
|lc| lc + CS::one(),
|lc| lc + %s.get_variable(),
);""" % (line, scalar_left, scalar_right)
def conditionally_reverse(line, out_left, out_right, in_left, in_right,
condition):
return \
r"""let (%s, %s) = num::AllocatedNum::conditionally_reverse(
cs.namespace(|| "%s"),
&%s,
&%s,
&%s,
)?;""" % (out_left, out_right, line, in_left, in_right, condition)

View File

@@ -1,460 +0,0 @@
import argparse
import sys
from enum import Enum
alloc_commands = {
"param": 1,
"private": 1,
"public": 1,
}
op_commands = {
"set": 2,
"mul": 2,
"add": 2,
"sub": 2,
"divide": 2,
"double": 1,
"square": 1,
"invert": 1,
"unpack_bits": 3,
"load": 2,
"local": 1,
"debug": 1,
"dump_alloc": 0,
"dump_local": 0,
}
constraint_commands = {
"lc0_add": 1,
"lc1_add": 1,
"lc2_add": 1,
"lc0_sub": 1,
"lc1_sub": 1,
"lc2_sub": 1,
"lc0_add_one": 0,
"lc1_add_one": 0,
"lc2_add_one": 0,
"lc0_sub_one": 0,
"lc1_sub_one": 0,
"lc2_sub_one": 0,
"lc0_add_coeff": 2,
"lc1_add_coeff": 2,
"lc2_add_coeff": 2,
"lc0_add_constant": 1,
"lc1_add_constant": 1,
"lc2_add_constant": 1,
"enforce": 0,
"lc_coeff_reset": 0,
"lc_coeff_double": 0,
}
def eprint(*args):
print(*args, file=sys.stderr)
class Line:
def __init__(self, text, line_number):
self.text = text
self.orig = text
self.lineno = line_number
self.clean()
def clean(self):
# Remove the comments
self.text = self.text.split("#", 1)[0]
# Remove whitespace
self.text = self.text.strip()
def is_empty(self):
return bool(self.text)
def __repr__(self):
return "Line %s: %s" % (self.lineno, self.orig.lstrip())
def command(self):
if not self.is_empty():
return None
return self.text.split(" ")[0]
def args(self):
if not self.is_empty():
return None
return self.text.split()[1:]
def clean(contents):
# Split input into lines
contents = contents.split("\n")
contents = [Line(line, i + 1) for i, line in enumerate(contents)]
# Remove empty blank lines
contents = [line for line in contents if line.is_empty()]
return contents
def divide_sections(contents):
state = "NOSCOPE"
segments = {}
current_segment = []
contract_name = None
for line in contents:
if line.command() == "contract":
if len(line.args()) != 1:
eprint("error: missing contract name")
eprint(line)
return None
contract_name = line.args()[0]
if state == "NOSCOPE":
assert not current_segment
state = "INSCOPE"
continue
else:
assert state == "INSCOPE"
eprint("error: double contract entry violation")
eprint(line)
return None
elif line.command() == "end":
if len(line.args()) != 0:
eprint("error: end takes no args")
eprint(line)
return None
if state == "NOSCOPE":
eprint("error: missing contract start for end")
eprint(line)
return None
else:
assert state == "INSCOPE"
state = "NOSCOPE"
segments[contract_name] = current_segment
current_segment = []
continue
elif state == "NOSCOPE":
# Ignore lines outside any contract
continue
current_segment.append(line)
if state != "NOSCOPE":
eprint("error: reached end of file with unclosed scope")
return None
return segments
def extract_relevant_lines(contract, commands_table):
relevant_lines = []
for line in contract:
command = line.command()
if command not in commands_table.keys():
continue
define = commands_table[command]
if len(line.args()) != define:
eprint("error: wrong number of args")
return None
relevant_lines.append(line)
return relevant_lines
class VariableType(Enum):
PUBLIC = 1
PRIVATE = 2
class Variable:
def __init__(self, symbol, index, type, is_param):
self.symbol = symbol
self.index = index
self.type = type
self.is_param = is_param
def __repr__(self):
return "<Variable %s:%s>" % (self.symbol, self.index)
def generate_alloc_table(contract):
relevant_lines = extract_relevant_lines(contract, alloc_commands)
alloc_table = {}
for i, line in enumerate(relevant_lines):
assert len(line.args()) == 1
symbol = line.args()[0]
command = line.command()
if command == "param":
type = VariableType.PRIVATE
is_param = True
elif command == "private":
type = VariableType.PRIVATE
is_param = False
elif command == "public":
type = VariableType.PUBLIC
is_param = False
else:
assert False
if symbol in alloc_table:
eprint("error: duplicate symbol '%s'" % symbol)
eprint(line)
return None
alloc_table[symbol] = Variable(symbol, i, type, is_param)
return alloc_table
class Operation:
def __init__(self, line, indexes):
self.command = line.command()
self.args = indexes
self.line = line
class VariableRefType(Enum):
AUX = 1
LOCAL = 2
CONST = 3
class VariableRef:
def __init__(self, type, index):
self.type = type
self.index = index
def __repr__(self):
return "%s(%s)" % (self.type.name, self.index)
def symbols_list_to_refs(line, alloc, local_vars, constants):
indexes = []
for symbol in line.args():
if symbol in alloc:
# Lookup variable index
index = alloc[symbol].index
index = VariableRef(VariableRefType.AUX, index)
elif symbol in local_vars:
index = local_vars[symbol]
index = VariableRef(VariableRefType.LOCAL, index)
elif symbol in constants:
index = constants[symbol][0]
index = VariableRef(VariableRefType.CONST, index)
else:
eprint("error: missing unallocated symbol '%s'" % symbol)
eprint(line)
return None
indexes.append(index)
return indexes
def generate_ops_table(contract, alloc, constants):
relevant_lines = extract_relevant_lines(contract, op_commands)
ops = []
local_vars = {}
for line in relevant_lines:
# This is a special case which creates a new local stack value
if line.command() == "local":
assert len(line.args()) == 1
symbol = line.args()[0]
local_vars[symbol] = len(local_vars)
indexes = []
else:
if (indexes := symbols_list_to_refs(line, alloc,
local_vars, constants)) is None:
return None
# Handle this here directly since only the
# load command deals with constants
if line.command() == "load":
assert len(indexes) == 2
# This is the only command which uses consts
if indexes[1].type != VariableRefType.CONST:
eprint("error: load command takes a const argument")
eprint(line)
return None
elif any(index.type == VariableRefType.CONST for index in indexes):
eprint("error: invalid const arg")
eprint(line)
return None
ops.append(Operation(line, indexes))
return ops
class Constraint:
def __init__(self, line, lcargs):
self.command = line.command()
self.args = lcargs
self.line = line
def args_comment(self):
return ", ".join("%s" % symbol for symbol in self.line.args())
def symbols_list_to_lcargs(line, alloc, constants):
lcargs = []
for symbol in line.args():
if symbol in alloc:
# Lookup variable index
index = alloc[symbol].index
lcargs.append(index)
elif symbol in constants:
value = constants[symbol]
lcargs.append(value)
else:
eprint("error: missing unallocated symbol '%s'" % symbol)
eprint(line)
return None
return lcargs
def generate_constraints_table(contract, alloc, constants):
relevant_lines = extract_relevant_lines(contract, constraint_commands)
constraints = []
for line in relevant_lines:
if (lcargs := symbols_list_to_lcargs(line, alloc, constants)) is None:
return None
constraints.append(Constraint(line, lcargs))
return constraints
class Contract:
def __init__(self, constants, alloc, ops, constraints):
self.constants = constants
self.alloc = alloc
self.ops = ops
self.constraints = constraints
def __repr__(self):
repr_str = ""
repr_str += "Constants:\n"
for symbol, value in self.constants.items():
repr_str += " // %s\n" % symbol
repr_str += " %s: %s\n" % value
repr_str += "Alloc table:\n"
for symbol, variable in self.alloc.items():
repr_str += " // %s\n" % symbol
repr_str += " %s %s\n" % (variable.type, variable.index)
repr_str += "Operations:\n"
for op in self.ops:
repr_str += " // %s\n" % op.line
repr_str += " %s %s\n" % (op.command, op.args)
repr_str += "Constraints:\n"
for constraint in self.constraints:
if constraint.args:
repr_str += " // %s\n" % constraint.args_comment()
repr_str += " %s %s\n" % (constraint.command, constraint.args)
repr_str += "Stats:\n"
repr_str += " Constants: %s\n" % len(self.constants)
repr_str += " Alloc: %s\n" % len(self.alloc)
repr_str += " Operations: %s\n" % len(self.ops)
repr_str += " Constraint Instructions: %s\n" % len(self.constraints)
return repr_str
def compile(contract, constants):
# Allocation table
# symbol: Private/Public, is_param, index
if (alloc := generate_alloc_table(contract)) is None:
return None
# Operations lines list
if (ops := generate_ops_table(contract, alloc, constants)) is None:
return None
# Constraint commands
if (constraints := generate_constraints_table(
contract, alloc, constants)) is None:
return None
return Contract(constants, alloc, ops, constraints)
def parse_constants(contents):
relevant_lines = [line for line in contents if line.command() == "constant"]
constants = {}
for line in relevant_lines:
assert line.command() == "constant"
if len(line.args()) != 2:
eprint("error: wrong number of args for constant")
eprint(line)
return None
symbol, value = line.args()
try:
int(value, 16)
except ValueError:
eprint("error: invalid constant value for '%s'" % symbol)
eprint(line)
return None
if len(value) != 32*2 + 2 or value[:2] != "0x":
eprint("error: invalid hex value for constant")
eprint(line)
return None
# Remove 0x prefix
value = value[2:]
constants[symbol] = (len(constants), value)
return constants
def process(contents):
# Remove left whitespace
contents = clean(contents)
# Parse all constants
if (constants := parse_constants(contents)) is None:
return None
# Divide into contract sections
if (pre_contracts := divide_sections(contents)) is None:
return None
# Process each contract
contracts = {}
for contract_name, pre_contract in pre_contracts.items():
if (contract := compile(pre_contract, constants)) is None:
return None
contracts[contract_name] = contract
return contracts
def main(argv):
parser = argparse.ArgumentParser()
parser.add_argument("filename", help="VM PISM file: proofs/vm.pism")
parser.add_argument("--output", type=argparse.FileType('wb', 0),
default=sys.stdout.buffer, help="Output file")
group = parser.add_mutually_exclusive_group()
group.add_argument('--display', action='store_true',
help="show the compiled code in human readable format")
group.add_argument('--rust', action='store_true',
help="output compiled code to rust for testing")
group.add_argument('--supervisor', action='store_true',
help="output compiled code to zkvm supervisor")
args = parser.parse_args()
src_filename = args.filename
contents = open(src_filename).read()
if (contracts := process(contents)) is None:
return -2
def default_display():
for contract_name, contract in contracts.items():
print("Contract:", contract_name)
print(contract)
if args.display:
default_display()
elif args.rust:
import compile_export_rust
for contract_name, contract in contracts.items():
compile_export_rust.display(contract)
elif args.supervisor:
import compile_export_supervisor
for contract_name, contract in contracts.items():
compile_export_supervisor.export(args.output, contract_name,
contract)
else:
default_display()
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv))

View File

@@ -1,122 +0,0 @@
from compile import VariableType, VariableRefType
def to_initial_caps(snake_str):
components = snake_str.split("_")
return "".join(x.title() for x in components)
def display(contract):
indent = " " * 4
print(r"""use super::vm::{ZkVirtualMachine, CryptoOperation, AllocType, ConstraintInstruction, VariableIndex, VariableRef};
use bls12_381::Scalar;
pub fn load_params(params: Vec<Scalar>) -> Vec<(VariableIndex, Scalar)> {""")
params = [(symbol, var) for symbol, var in contract.alloc.items() if var.is_param]
print("%sassert_eq!(params.len(), %s);" % (indent, len(params)))
print("%slet mut result = vec![(0, Scalar::zero()); %s];" % (
indent, len(params)))
for i, (symbol, variable) in enumerate(params):
assert variable.is_param
print("%s// %s" % (indent, symbol))
print("%sresult[%s] = (%s, params[%s]);" % (
indent, i, variable.index, i))
print("%sresult" % indent)
print("}\n")
print(r"""pub fn load_zkvm() -> ZkVirtualMachine {
ZkVirtualMachine {
constants: vec![""")
constants = list(contract.constants.items())
constants.sort(key=lambda obj: obj[1][0])
constants = [(obj[0], obj[1][1]) for obj in constants]
for symbol, value in constants:
print("%s// %s" % (indent * 3, symbol))
assert len(value) == 32*2
chunk_str = lambda line, n: \
[line[i:i + n] for i in range(0, len(line), n)]
chunks = chunk_str(value, 2)
# Reverse the endianness
# We allow literal numbers but rust wants little endian
chunks = chunks[::-1]
print("%sScalar::from_bytes(&[" % (indent * 3))
for i in range(0, 32, 4):
print("%s0x%s, 0x%s, 0x%s, 0x%s," % (indent * 4,
chunks[i], chunks[i + 1], chunks[i + 2], chunks[i + 3]))
print("%s]).unwrap()," % (indent * 3))
print("%s]," % (indent * 2))
print("%salloc: vec![" % (indent * 2))
for symbol, variable in contract.alloc.items():
print("%s// %s" % (indent * 3, symbol))
if variable.type.name == VariableType.PRIVATE.name:
typestring = "Private"
elif variable.type.name == VariableType.PUBLIC.name:
typestring = "Public"
else:
assert False
print("%s(AllocType::%s, %s)," % (indent * 3, typestring,
variable.index))
print("%s]," % (indent * 2))
print("%sops: vec![" % (indent * 2))
def var_ref_str(var_ref):
if var_ref.type.name == VariableRefType.AUX.name:
return "VariableRef::Aux(%s)" % var_ref.index
elif var_ref.type.name == VariableRefType.LOCAL.name:
return "VariableRef::Local(%s)" % var_ref.index
else:
assert False
for op in contract.ops:
print("%s// %s" % (indent * 3, op.line))
args_part = ""
if op.command == "load":
assert len(op.args) == 2
args_part = "(%s, %s)" % (var_ref_str(op.args[0]), op.args[1].index)
elif op.command == "debug":
assert len(op.args) == 1
args_part = '(String::from("%s"), %s)' % (
op.line, var_ref_str(op.args[0]))
elif op.args:
args_part = ", ".join(var_ref_str(var_ref) for var_ref in op.args)
args_part = "(%s)" % args_part
print("%sCryptoOperation::%s%s," % (
indent * 3,
to_initial_caps(op.command),
args_part
))
print("%s]," % (indent * 2))
print("%sconstraints: vec![" % (indent * 2))
for constraint in contract.constraints:
args_part = ""
if constraint.args:
print("%s// %s" % (indent *3, constraint.args_comment()))
args = constraint.args[:]
if (constraint.command == "lc0_add_coeff" or
constraint.command == "lc1_add_coeff" or
constraint.command == "lc2_add_coeff" or
constraint.command == "lc0_add_one_coeff" or
constraint.command == "lc1_add_one_coeff" or
constraint.command == "lc2_add_one_coeff"):
args[0] = args[0][0]
args_part = ", ".join(str(index) for index in args)
args_part = "(%s)" % args_part
print("%sConstraintInstruction::%s%s," % (
indent * 3,
to_initial_caps(constraint.command),
args_part
))
print(r""" ],
aux: vec![],
params: None,
verifying_key: None,
}
}""")

View File

@@ -1,193 +0,0 @@
import struct
from compile import VariableType, VariableRefType
class Operation:
def __init__(self, ident, args):
self.ident = ident
self.args = args
class ArgVarRef:
def __init__(self, type, index):
self.type = type
self.index = index
def bytes(self):
return struct.pack("<BI", self.type, self.index)
class ArgVarIndex:
def __init__(self, _, index):
self.index = index
def bytes(self):
return struct.pack("<I", self.index)
class ArgString:
def __init__(self, description, index):
self.description = description
self.index = index
ops_table = {
"set": Operation(0, [ArgVarRef, ArgVarRef]),
"mul": Operation(1, [ArgVarRef, ArgVarRef]),
"add": Operation(2, [ArgVarRef, ArgVarRef]),
"sub": Operation(3, [ArgVarRef, ArgVarRef]),
"divide": Operation(4, [ArgVarRef, ArgVarRef]),
"double": Operation(5, [ArgVarRef]),
"square": Operation(6, [ArgVarRef]),
"invert": Operation(7, [ArgVarRef]),
"unpack_bits": Operation(8, [ArgVarRef, ArgVarRef, ArgVarRef]),
"local": Operation(9, []),
"load": Operation(10, [ArgVarRef, ArgVarIndex]),
"debug": Operation(11, [ArgString, ArgVarRef]),
"dump_alloc": Operation(12, []),
"dump_local": Operation(13, []),
}
constraint_ident_map = {
"lc0_add": 0,
"lc1_add": 1,
"lc2_add": 2,
"lc0_sub": 3,
"lc1_sub": 4,
"lc2_sub": 5,
"lc0_add_one": 6,
"lc1_add_one": 7,
"lc2_add_one": 8,
"lc0_sub_one": 9,
"lc1_sub_one": 10,
"lc2_sub_one": 11,
"lc0_add_coeff": 12,
"lc1_add_coeff": 13,
"lc2_add_coeff": 14,
"lc0_add_constant": 15,
"lc1_add_constant": 16,
"lc2_add_constant": 17,
"enforce": 18,
"lc_coeff_reset": 19,
"lc_coeff_double": 20,
}
def varuint(value):
if value <= 0xfc:
return struct.pack("<B", value)
elif value <= 0xffff:
return struct.pack("<BH", 0xfd, value)
elif value <= 0xffffffff:
return struct.pack("<BI", 0xfe, value)
else:
return struct.pack("<BQ", 0xff, value)
def export(output, contract_name, contract):
output.write(varuint(len(contract_name)))
output.write(contract_name.encode())
constants = list(contract.constants.items())
constants.sort(key=lambda obj: obj[1][0])
constants = [(obj[0], obj[1][1]) for obj in constants]
# Constants
output.write(varuint(len(constants)))
for symbol, value in constants:
print("Constant '%s' = %s" % (symbol, value))
# Bellman uses little endian for Scalars from_bytes function
const_bytes = bytearray.fromhex(value)[::-1]
assert len(const_bytes) == 32
output.write(const_bytes)
# Alloc
output.write(varuint(len(contract.alloc)))
for symbol, variable in contract.alloc.items():
print("Alloc '%s' = (%s, %s)" % (symbol,
variable.type.name, variable.index))
if variable.type.name == VariableType.PRIVATE.name:
typeval = 0
elif variable.type.name == VariableType.PUBLIC.name:
typeval = 1
else:
assert False
alloc_bytes = struct.pack("<BI", typeval, variable.index)
assert len(alloc_bytes) == 5
output.write(alloc_bytes)
# Ops
output.write(varuint(len(contract.ops)))
for op in contract.ops:
op_form = ops_table[op.command]
output.write(struct.pack("B", op_form.ident))
if op.command == "debug":
# Special case
assert len(op.args) == 1
line_str = str(op.line).encode()
output.write(varuint(len(line_str)))
output.write(line_str)
op_arg = op.args[0]
if op_arg.type.name == VariableRefType.AUX.name:
arg_type = 0
elif op_arg.type.name == VariableRefType.LOCAL.name:
arg_type = 1
arg = ArgVarRef(arg_type, op_arg.index)
output.write(arg.bytes())
continue
assert len(op_form.args) == len(op.args)
for arg_form, op_arg in zip(op_form.args, op.args):
if op_arg.type.name == VariableRefType.AUX.name:
arg_type = 0
elif op_arg.type.name == VariableRefType.LOCAL.name:
arg_type = 1
arg = arg_form(arg_type, op_arg.index)
output.write(arg.bytes())
print("#", op.line)
print("Operation", op.command,
[(arg.type.name, arg.index) for arg in op.args])
# Constraints
output.write(varuint(len(contract.constraints)))
for constraint in contract.constraints:
args = constraint.args[:]
if (constraint.command == "lc0_add_coeff" or
constraint.command == "lc1_add_coeff" or
constraint.command == "lc2_add_coeff" or
constraint.command == "lc0_add_constant" or
constraint.command == "lc1_add_constant" or
constraint.command == "lc2_add_constant"):
args[0] = args[0][0]
print("#", constraint.line)
print("Constraint", constraint.command, args if args else "")
enum_ident = constraint_ident_map[constraint.command]
output.write(struct.pack("B", enum_ident))
for arg in args:
output.write(struct.pack("<I", arg))
# Params Map
param_alloc = [(symbol, variable) for (symbol, variable)
in contract.alloc.items() if variable.is_param]
output.write(varuint(len(param_alloc)))
for symbol, variable in param_alloc:
assert variable.is_param
print("Parameter '%s' = %s" % (symbol, variable.index))
symbol = symbol.encode()
output.write(varuint(len(symbol)))
output.write(symbol)
output.write(struct.pack("<I", variable.index))
# Public Map
public_alloc = [(symbol, variable) for (symbol, variable)
in contract.alloc.items()
if variable.type.name == VariableType.PUBLIC.name]
output.write(varuint(len(public_alloc)))
for symbol, variable in public_alloc:
assert not variable.is_param
assert variable.type.name == VariableType.PUBLIC.name
print("Public '%s' = %s" % (symbol, variable.index))
symbol = symbol.encode()
output.write(varuint(len(symbol)))
output.write(symbol)
output.write(struct.pack("<I", variable.index))

View File

@@ -1,21 +0,0 @@
if exists('b:current_syntax')
finish
endif
syn keyword drkKeyword assert enforce for in def return const as let emit contract private proof
syn keyword drkAttr mut
syn keyword drkType BinaryNumber Point Fr SubgroupPoint EdwardsPoint Scalar EncryptedNum list Bool U64 Num Binary
syn match drkFunction "\zs[a-zA-Z0-9_]*\ze("
syn match drkComment "#.*$"
syn match drkNumber '\d\+'
syn match drkConst '[A-Z_]\{2,}[A-Z0-9_]*'
hi def link drkKeyword Statement
hi def link drkAttr StorageClass
hi def link drkType Type
hi def link drkFunction Function
hi def link drkComment Comment
hi def link drkNumber Constant
hi def link drkConst Constant
let b:current_syntax = "drk"

View File

@@ -1,40 +0,0 @@
from finite_fields import finitefield
def add(x_1, y_1, x_2, y_2):
if (x_1, y_1) == (x_2, y_2):
if y_1 == 0:
return None
# slope of the tangent line
m = (3 * x_1 * x_1 + a) / (2 * y_1)
return None
else:
if x_1 == x_2:
return None
# slope of the secant line
m = (y_2 - y_1) / (x_2 - x_1)
x_3 = m*m - x_1 - x_2
y_3 = m*(x_1 - x_3) - y_1
return (x_3, y_3)
if __name__ == "__main__":
# Vesta
q = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001
fq = finitefield.IntegersModP(q)
a, b = fq(0x00), fq(0x05)
p = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001
C = (fq(0x1ca18c7c3fcb110f9e92c694ce552238f95e9f9b911599cedaff6018cfc5ed52), fq(0x3ad6133a791e41f3e062d370b40e97e77d20effc00b7ee88c4bb097d245cb438))
D = (fq(0x3e544e611bb895166afe1a46c6e551c47968daf962d824f79f795cb53585b098), fq(0x2fd03c4da47baf2dfd251e85d18864d4885ddd0e8df648550565b850b79349e3))
C_plus_D = (fq(0x06f822cbde350215558c46aac9e60eee31afd942ca6da568845ca4f8fe911e17), fq(0x3e294e73970abc197dfff1a14e74cb20c11b81422d9f920c7b0b0c63affdf67b))
result = add(C[0], C[1], D[0], D[1])
print(result)
print(list("%x" % x.n for x in result))
assert result[0] == C_plus_D[0]
assert result[1] == C_plus_D[1]

View File

@@ -1 +0,0 @@
../finite_fields/

View File

@@ -1,4 +0,0 @@
finite-fields
=============
Python code and tests for the post ["Programming with Finite Fields"](http://jeremykun.com/2014/03/13/programming-with-finite-fields/)

View File

@@ -1,45 +0,0 @@
from test import test
from euclidean import *
test(1, gcd(7, 9))
test(2, gcd(8, 18))
test(-12, gcd(-12, 24))
test(12, gcd(12, -24)) # gcd is only unique up to multiplication by a unit, and so sometimes we'll get negatives.
test(38, gcd(4864, 3458))
test((32, -45, 38), extendedEuclideanAlgorithm(4864, 3458))
test((-45, 32, 38), extendedEuclideanAlgorithm(3458, 4864))
from modp import *
Mod2 = IntegersModP(2)
test(Mod2(1), gcd(Mod2(1), Mod2(0)))
test(Mod2(1), gcd(Mod2(1), Mod2(1)))
test(Mod2(0), gcd(Mod2(2), Mod2(2)))
Mod7 = IntegersModP(7)
test(Mod7(6), gcd(Mod7(6), Mod7(14)))
test(Mod7(2), gcd(Mod7(6), Mod7(9)))
ModHuge = IntegersModP(9923)
test(ModHuge(38), gcd(ModHuge(4864), ModHuge(3458)))
test((ModHuge(32), ModHuge(-45), ModHuge(38)),
extendedEuclideanAlgorithm(ModHuge(4864), ModHuge(3458)))
from polynomial import *
p = polynomialsOver(Mod7).factory
test(p([-1, 1]), gcd(p([-1,0,1]), p([-1,0,0,1])))
f = p([-1,0,1])
g = p([-1,0,0,1])
test((p([0,-1]), p([1]), p([-1, 1])), extendedEuclideanAlgorithm(f, g))
test(p([-1,1]), f * p([0,-1]) + g * p([1]))
p = polynomialsOver(Mod2).factory
f = p([1,0,0,0,1,1,1,0,1,1,1]) # x^10 + x^9 + x^8 + x^6 + x^5 + x^4 + 1
g = p([1,0,1,1,0,1,1,0,0,1]) # x^9 + x^6 + x^5 + x^3 + x^1 + 1
theGcd = p([1,1,0,1]) # x^3 + x + 1
x = p([0,0,0,0,1]) # x^4
y = p([1,1,1,1,1,1]) # x^5 + x^4 + x^3 + x^2 + x + 1
test((x, y, theGcd), extendedEuclideanAlgorithm(f, g))

View File

@@ -1,34 +0,0 @@
# a general Euclidean algorithm for any number type with
# a divmod and a valuation abs() whose minimum value is zero
def gcd(a, b):
if abs(a) < abs(b):
return gcd(b, a)
while abs(b) > 0:
_,r = divmod(a,b)
a,b = b,r
return a
# extendedEuclideanAlgorithm: int, int -> int, int, int
# input (a,b) and output three numbers x,y,d such that ax + by = d = gcd(a,b).
# Works for any number type with a divmod and a valuation abs()
# whose minimum value is zero
def extendedEuclideanAlgorithm(a, b):
if abs(b) > abs(a):
(x,y,d) = extendedEuclideanAlgorithm(b, a)
return (y,x,d)
if abs(b) == 0:
return (1, 0, a)
x1, x2, y1, y2 = 0, 1, 1, 0
while abs(b) > 0:
q, r = divmod(a,b)
x = x2 - q*x1
y = y2 - q*y1
a, b, x2, x1, y2, y1 = b, r, x1, x, y1, y
return (x2, y2, a)

View File

@@ -1,28 +0,0 @@
from test import test
from finitefield import *
from polynomial import *
from modp import *
def p(L, q):
f = IntegersModP(q)
Polynomial = polynomialsOver(f).factory
return Polynomial(L)
test(True, isIrreducible(p([0,1], 2), 2))
test(False, isIrreducible(p([1,0,1], 2), 2))
test(True, isIrreducible(p([1,0,1], 3), 3))
test(False, isIrreducible(p([1,0,0,1], 5), 5))
test(False, isIrreducible(p([1,0,0,1], 7), 7))
test(False, isIrreducible(p([1,0,0,1], 11), 11))
test(True, isIrreducible(p([-2, 0, 1], 13), 13))
Z5 = IntegersModP(5)
Poly = polynomialsOver(Z5).factory
f = Poly([3,0,1])
F25 = FiniteField(5, 2, polynomialModulus=f)
x = F25([2,1])
test(Poly([1,2]), x.inverse())

View File

@@ -1,128 +0,0 @@
import random
from .polynomial import polynomialsOver
from .modp import *
# isIrreducible: Polynomial, int -> bool
# determine if the given monic polynomial with coefficients in Z/p is
# irreducible over Z/p where p is the given integer
# Algorithm 4.69 in the Handbook of Applied Cryptography
def isIrreducible(polynomial, p):
ZmodP = IntegersModP(p)
if polynomial.field is not ZmodP:
raise TypeError("Given a polynomial that's not over %s, but instead %r" %
(ZmodP.__name__, polynomial.field.__name__))
poly = polynomialsOver(ZmodP).factory
x = poly([0,1])
powerTerm = x
isUnit = lambda p: p.degree() == 0
for _ in range(int(polynomial.degree() / 2)):
powerTerm = powerTerm.powmod(p, polynomial)
gcdOverZmodp = gcd(polynomial, powerTerm - x)
if not isUnit(gcdOverZmodp):
return False
return True
# generateIrreduciblePolynomial: int, int -> Polynomial
# generate a random irreducible polynomial of a given degree over Z/p, where p
# is given by the integer 'modulus'. This algorithm is expected to terminate
# after 'degree' many irreducilibity tests. By Chernoff bounds the probability
# it deviates from this by very much is exponentially small.
def generateIrreduciblePolynomial(modulus, degree):
Zp = IntegersModP(modulus)
Polynomial = polynomialsOver(Zp)
while True:
coefficients = [Zp(random.randint(0, modulus-1)) for _ in range(degree)]
randomMonicPolynomial = Polynomial(coefficients + [Zp(1)])
print(randomMonicPolynomial)
if isIrreducible(randomMonicPolynomial, modulus):
return randomMonicPolynomial
# create a type constructor for the finite field of order p^m for p prime, m >= 1
@memoize
def FiniteField(p, m, polynomialModulus=None):
Zp = IntegersModP(p)
if m == 1:
return Zp
Polynomial = polynomialsOver(Zp)
if polynomialModulus is None:
polynomialModulus = generateIrreduciblePolynomial(modulus=p, degree=m)
class Fq(FieldElement):
fieldSize = int(p ** m)
primeSubfield = Zp
idealGenerator = polynomialModulus
operatorPrecedence = 3
def __init__(self, poly):
if type(poly) is Fq:
self.poly = poly.poly
elif type(poly) is int or type(poly) is Zp:
self.poly = Polynomial([Zp(poly)])
elif isinstance(poly, Polynomial):
self.poly = poly % polynomialModulus
else:
self.poly = Polynomial([Zp(x) for x in poly]) % polynomialModulus
self.field = Fq
@typecheck
def __add__(self, other): return Fq(self.poly + other.poly)
@typecheck
def __sub__(self, other): return Fq(self.poly - other.poly)
@typecheck
def __mul__(self, other): return Fq(self.poly * other.poly)
@typecheck
def __eq__(self, other): return isinstance(other, Fq) and self.poly == other.poly
@typecheck
def __ne__(self, other): return not self == other
def __pow__(self, n):
if n==0: return Fq([1])
if n==1: return self
if n%2==0:
sqrut = self**(n//2)
return sqrut*sqrut
if n%2==1: return (self**(n-1))*self
#def __pow__(self, n): return Fq(pow(self.poly, n))
def __neg__(self): return Fq(-self.poly)
def __abs__(self): return abs(self.poly)
def __repr__(self): return repr(self.poly) + ' \u2208 ' + self.__class__.__name__
@typecheck
def __divmod__(self, divisor):
q,r = divmod(self.poly, divisor.poly)
return (Fq(q), Fq(r))
def inverse(self):
if self == Fq(0):
raise ZeroDivisionError
x,y,d = extendedEuclideanAlgorithm(self.poly, self.idealGenerator)
if d.degree() != 0:
raise Exception('Somehow, this element has no inverse! Maybe intialized with a non-prime?')
return Fq(x) * Fq(d.coefficients[0].inverse())
Fq.__name__ = 'F_{%d^%d}' % (p,m)
return Fq
if __name__ == "__main__":
F23 = FiniteField(2,3)
x = F23([1,1])
F35 = FiniteField(3,5)
y = F35([1,1,2])

View File

@@ -1,12 +0,0 @@
from modp import *
from test import test
mod7 = IntegersModP(7)
test(mod7(5), mod7(5)) # Sanity check
test(mod7(5), 1 / mod7(3))
test(mod7(1), mod7(3) * mod7(5))
test(mod7(3), mod7(3) * 1)
test(mod7(2), mod7(5) + mod7(4))
test(True, mod7(0) == mod7(3) + mod7(4))

View File

@@ -1,84 +0,0 @@
from .euclidean import *
from .numbertype import *
# so all IntegersModP are instances of the same base class
class _Modular(FieldElement):
pass
@memoize
def IntegersModP(p):
# assume p is prime
class IntegerModP(_Modular):
def __init__(self, n):
try:
self.n = int(n) % IntegerModP.p
except:
raise TypeError("Can't cast type %s to %s in __init__" %
(type(n).__name__, type(self).__name__))
self.field = IntegerModP
@typecheck
def __add__(self, other):
return IntegerModP(self.n + other.n)
@typecheck
def __sub__(self, other):
return IntegerModP(self.n - other.n)
@typecheck
def __mul__(self, other):
return IntegerModP(self.n * other.n)
def __neg__(self):
return IntegerModP(-self.n)
@typecheck
def __eq__(self, other):
return isinstance(other, IntegerModP) and self.n == other.n
@typecheck
def __ne__(self, other):
return isinstance(other, IntegerModP) is False or self.n != other.n
@typecheck
def __divmod__(self, divisor):
q,r = divmod(self.n, divisor.n)
return (IntegerModP(q), IntegerModP(r))
def inverse(self):
# need to use the division algorithm *as integers* because we're
# doing it on the modulus itself (which would otherwise be zero)
x,y,d = extendedEuclideanAlgorithm(self.n, self.p)
if d != 1:
raise Exception("Error: p is not prime in %s!" % (self.__name__))
return IntegerModP(x)
def __abs__(self):
return abs(self.n)
def __str__(self):
return str(self.n)
def __repr__(self):
return '%d (mod %d)' % (self.n, self.p)
def __int__(self):
return self.n
def __hash__(self):
return hash((self.n, self.p))
IntegerModP.p = p
IntegerModP.__name__ = 'Z/%d' % (p)
IntegerModP.englishName = 'IntegersMod%d' % (p)
return IntegerModP
if __name__ == "__main__":
mod7 = IntegersModP(7)

View File

@@ -1,97 +0,0 @@
# memoize calls to the class constructors for fields
# this helps typechecking by never creating two separate
# instances of a number class.
def memoize(f):
cache = {}
def memoizedFunction(*args, **kwargs):
argTuple = args + tuple(kwargs)
if argTuple not in cache:
cache[argTuple] = f(*args, **kwargs)
return cache[argTuple]
memoizedFunction.cache = cache
return memoizedFunction
# type check a binary operation, and silently typecast 0 or 1
def typecheck(f):
def newF(self, other):
if (hasattr(other.__class__, 'operatorPrecedence') and
other.__class__.operatorPrecedence > self.__class__.operatorPrecedence):
return NotImplemented
if type(self) is not type(other):
try:
other = self.__class__(other)
except TypeError:
message = 'Not able to typecast %s of type %s to type %s in function %s'
raise TypeError(message % (other, type(other).__name__, type(self).__name__, f.__name__))
except Exception as e:
message = 'Type error on arguments %r, %r for functon %s. Reason:%s'
raise TypeError(message % (self, other, f.__name__, type(other).__name__, type(self).__name__, e))
return f(self, other)
return newF
# require a subclass to implement +-* neg and to perform typechecks on all of
# the binary operations finally, the __init__ must operate when given a single
# argument, provided that argument is the int zero or one
class DomainElement(object):
operatorPrecedence = 1
# the 'r'-operators are only used when typecasting ints
def __radd__(self, other): return self + other
def __rsub__(self, other): return -self + other
def __rmul__(self, other): return self * other
# square-and-multiply algorithm for fast exponentiation
def __pow__(self, n):
if type(n) is not int:
raise TypeError
Q = self
R = self if n & 1 else self.__class__(1)
i = 2
while i <= n:
Q = (Q * Q)
if n & i == i:
R = (Q * R)
i = i << 1
return R
# requires the additional % operator (i.e. a Euclidean Domain)
def powmod(self, n, modulus):
if type(n) is not int:
raise TypeError
Q = self
R = self if n & 1 else self.__class__(1)
i = 2
while i <= n:
Q = (Q * Q) % modulus
if n & i == i:
R = (Q * R) % modulus
i = i << 1
return R
# additionally require inverse() on subclasses
class FieldElement(DomainElement):
def __truediv__(self, other): return self * other.inverse()
def __rtruediv__(self, other): return self.inverse() * other
def __div__(self, other): return self.__truediv__(other)
def __rdiv__(self, other): return self.__rtruediv__(other)

View File

@@ -1,51 +0,0 @@
from __future__ import division
from test import test
from fractions import Fraction
from polynomial import *
from modp import *
Mod5 = IntegersModP(5)
Mod11 = IntegersModP(11)
polysOverQ = polynomialsOver(Fraction).factory
polysMod5 = polynomialsOver(Mod5).factory
polysMod11 = polynomialsOver(Mod11).factory
for p in [polysOverQ, polysMod5, polysMod11]:
# equality
test(True, p([]) == p([]))
test(True, p([1,2]) == p([1,2]))
test(True, p([1,2,0]) == p([1,2,0,0]))
# addition
test(p([1,2,3]), p([1,0,3]) + p([0,2]))
test(p([1,2,3]), p([1,2,3]) + p([]))
test(p([5,2,3]), p([4]) + p([1,2,3]))
test(p([1,2]), p([1,2,3]) + p([0,0,-3]))
# subtraction
test(p([1,-2,3]), p([1,0,3]) - p([0,2]))
test(p([1,2,3]), p([1,2,3]) - p([]))
test(p([-1,-2,-3]), p([]) - p([1,2,3]))
# multiplication
test(p([1,2,1]), p([1,1]) * p([1,1]))
test(p([2,5,5,3]), p([2,3]) * p([1,1,1]))
test(p([0,7,49]), p([0,1,7]) * p([7]))
# division
test(p([1,1,1,1,1,1]), p([-1,0,0,0,0,0,1]) / p([-1,1]))
test(p([-1,1,-1,1,-1,1]), p([1,0,0,0,0,0,1]) / p([1,1]))
test(p([]), p([]) / p([1,1]))
test(p([1,1]), p([1,1]) / p([1]))
test(p([1,1]), p([2,2]) / p([2]))
# modulus
test(p([]), p([1,7,49]) % p([7]))
test(p([-7]), p([-3,10,-5,3]) % p([1,3]))
test(polysOverQ([Fraction(1,7), 1, 7]), polysOverQ([1,7,49]) / polysOverQ([7]))
test(polysMod5([1 / Mod5(7), 1, 7]), polysMod5([1,7,49]) / polysMod5([7]))
test(polysMod11([1 / Mod11(7), 1, 7]), polysMod11([1,7,49]) / polysMod11([7]))

View File

@@ -1,143 +0,0 @@
try:
from itertools import zip_longest
except ImportError:
from itertools import izip_longest as zip_longest
import fractions
from .numbertype import *
# strip all copies of elt from the end of the list
def strip(L, elt):
if len(L) == 0: return L
i = len(L) - 1
while i >= 0 and L[i] == elt:
i -= 1
return L[:i+1]
# create a polynomial with coefficients in a field; coefficients are in
# increasing order of monomial degree so that, for example, [1,2,3]
# corresponds to 1 + 2x + 3x^2
@memoize
def polynomialsOver(field=fractions.Fraction):
class Polynomial(DomainElement):
operatorPrecedence = 2
@classmethod
def factory(cls, L):
return Polynomial([cls.field(x) for x in L])
def __init__(self, c):
if type(c) is Polynomial:
self.coefficients = c.coefficients
elif isinstance(c, field):
self.coefficients = [c]
elif not hasattr(c, '__iter__') and not hasattr(c, 'iter'):
self.coefficients = [field(c)]
else:
self.coefficients = c
self.coefficients = strip(self.coefficients, field(0))
def isZero(self): return self.coefficients == []
def __repr__(self):
if self.isZero():
return '0'
return ' + '.join(['%s x^%d' % (a,i) if i > 0 else '%s'%a
for i,a in enumerate(self.coefficients)])
def __abs__(self): return len(self.coefficients) # the valuation only gives 0 to the zero polynomial, i.e. 1+degree
def __len__(self): return len(self.coefficients)
def __sub__(self, other): return self + (-other)
def __iter__(self): return iter(self.coefficients)
def __neg__(self): return Polynomial([-a for a in self])
def iter(self): return self.__iter__()
def leadingCoefficient(self): return self.coefficients[-1]
def degree(self): return abs(self) - 1
@typecheck
def __eq__(self, other):
return self.degree() == other.degree() and all([x==y for (x,y) in zip(self, other)])
@typecheck
def __ne__(self, other):
return self.degree() != other.degree() or any([x!=y for (x,y) in zip(self, other)])
@typecheck
def __add__(self, other):
newCoefficients = [sum(x) for x in zip_longest(self, other, fillvalue=self.field(0))]
return Polynomial(newCoefficients)
@typecheck
def __mul__(self, other):
if self.isZero() or other.isZero():
return Zero()
newCoeffs = [self.field(0) for _ in range(len(self) + len(other) - 1)]
for i,a in enumerate(self):
for j,b in enumerate(other):
newCoeffs[i+j] += a*b
return Polynomial(newCoeffs)
@typecheck
def __divmod__(self, divisor):
quotient, remainder = Zero(), self
divisorDeg = divisor.degree()
divisorLC = divisor.leadingCoefficient()
while remainder.degree() >= divisorDeg:
monomialExponent = remainder.degree() - divisorDeg
monomialZeros = [self.field(0) for _ in range(monomialExponent)]
monomialDivisor = Polynomial(monomialZeros + [remainder.leadingCoefficient() / divisorLC])
quotient += monomialDivisor
remainder -= monomialDivisor * divisor
return quotient, remainder
@typecheck
def __truediv__(self, divisor):
if divisor.isZero():
raise ZeroDivisionError
return divmod(self, divisor)[0]
@typecheck
def __mod__(self, divisor):
if divisor.isZero():
raise ZeroDivisionError
return divmod(self, divisor)[1]
def __call__(self, x):
if type(x) is int:
x = self.field(x)
assert type(x) is self.field
if self.isZero():
return self.field(0)
y = self.leadingCoefficient()
for coeff in self.coefficients[-2::-1]:
y = y * x + coeff
return y
def Zero():
return Polynomial([])
Polynomial.field = field
Polynomial.__name__ = '(%s)[x]' % field.__name__
Polynomial.englishName = 'Polynomials in one variable over %s' % field.__name__
return Polynomial

View File

@@ -1,8 +0,0 @@
def test(expected, actual):
if expected != actual:
import sys, traceback
(filename, lineno, container, code) = traceback.extract_stack()[-2]
print("Test: %r failed on line %d in file %r.\nExpected %r but got %r\n" %
(code, lineno, filename, expected, actual))
sys.exit(1)

View File

@@ -1,11 +0,0 @@
from modp import *
from polynomial import *
mod3 = IntegersModP(3)
Polynomial = polynomialsOver(mod3)
x = mod3(1)
p = Polynomial([1,2])
x+p
p+x

View File

@@ -1,88 +0,0 @@
# Notes from paper:
# "Efficient Zero-Knowledge Arguments for Arithmetic Circuits in the
# Discrete Log Setting" by Bootle and others (EUROCRYPT 2016)
from finite_fields import finitefield
import numpy as np
p = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001
fp = finitefield.IntegersModP(p)
# Number of variables
m = 16
# Number of rows for multiplication statements
n = 3
N = n * m
# Initialize zeroed table
aux = np.full(m, fp(0))
# From the zk-explainer document, we will represent the function:
#
# def foo(w, a, b):
# if w:
# return a * b
# else:
# return a + b
#
# Which can be translated mathematically to the statements:
#
# ab = m
# w(m - a - b) = v - a - b
# w^2 = w
#
# Where m is an intermediate value.
var_one = 0
aux[var_one] = fp(1)
var_a = 1
var_b = 2
var_w = 3
aux[var_a] = fp(110)
aux[var_b] = fp(4)
aux[var_w] = fp(1)
# Calculate intermediate advice values
var_m = 4
aux[var_m] = aux[var_a] * aux[var_b]
# Calculate public input values
var_v = 5
aux[var_v] = aux[var_w] * (aux[var_a] * aux[var_b]) + \
(aux[var_one] - aux[var_w]) * (aux[var_a] + aux[var_b])
# Just a quick enforcement check:
assert aux[var_a] * aux[var_b] == aux[var_m]
assert aux[var_w] * (aux[var_m] - aux[var_a] - aux[var_b]) == \
aux[var_v] - aux[var_a] - aux[var_b]
assert aux[var_w] * aux[var_w] == aux[var_w]
# Setup the gates. For each row of a, b and c, the statement a b = c holds
# R1CS, more info here:
# http://www.zeroknowledgeblog.com/index.php/the-pinocchio-protocol/r1cs
left = np.full((n, m), fp(0))
right = np.full((n, m), fp(0))
output = np.full((n, m), fp(0))
# ab = m
left[0][var_a] = fp(1)
right[0][var_b] = fp(1)
output[0][var_m] = fp(1)
assert aux.dot(left[0]) * aux.dot(right[0]) == aux.dot(output[0])
# w(m - a - b) = v - a - b
left[1][var_w] = fp(1)
right[1][var_m] = fp(1)
right[1][var_a] = fp(-1)
right[1][var_b] = fp(-1)
output[1][var_v] = fp(1)
output[1][var_a] = fp(-1)
output[1][var_b] = fp(-1)
assert aux.dot(left[1]) * aux.dot(right[1]) == aux.dot(output[1])
# w^2 = w
left[2][var_w] = fp(1)
right[2][var_w] = fp(1)
output[2][var_w] = fp(1)
assert aux.dot(left[2]) * aux.dot(right[2]) == aux.dot(output[2])

View File

@@ -1,64 +0,0 @@
# See also https://cp-algorithms.com/algebra/fft.html
q = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001
K = GF(q)
P.<X> = K[]
def get_omega():
generator = K(5)
assert (q - 1) % 2^32 == 0
# Root of unity
t = (q - 1) / 2^32
omega = generator**t
assert omega != 1
assert omega^(2^16) != 1
assert omega^(2^31) != 1
assert omega^(2^32) == 1
return omega
# Order of this element is 2^32
omega = get_omega()
k = 3
n = 2^k
omega = omega^(2^32 / n)
assert omega^n == 1
f = 6*X^7 + 7*X^5 + 3*X^2 + X
def fft(F):
print(f"fft({F})")
# On the first invocation:
#assert len(F) == n
N = len(F)
if N == 1:
print(" returning 1")
return F
omega_prime = omega^(n/N)
assert omega_prime^(n - 1) != 1
assert omega_prime^N == 1
# Split into even and odd powers of X
F_e = [a for a in F[::2]]
print(" Evens:", F_e)
F_o = [a for a in F[1::2]]
print(" Odds:", F_o)
y_e, y_o = fft(F_e), fft(F_o)
print(f"y_e = {y_e}, y_o = {y_o}")
y = [0] * N
for j in range(N / 2):
y[j] = y_e[j] + omega_prime^j * y_o[j]
y[j + N / 2] = y_e[j] - omega_prime^j * y_o[j]
print(f" returning y = {y}")
return y
print("f =", f)
evals = fft(list(f))
print("evals =", evals)
print("{omega^i : i in {0, 1, ..., n - 1}} =", [omega^i for i in range(n)])
evals2 = [f(omega^i) for i in range(n)]
print("{f(omega^i) for all omega^i} =", evals2)
assert evals == evals2

View File

@@ -1 +0,0 @@
../finite_fields/

View File

@@ -1,89 +0,0 @@
import numpy as np
# Implementation of Groth09 inner product proof
q = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001
K = GF(q)
a = K(0x00)
b = K(0x05)
E = EllipticCurve(K, (a, b))
G = E(0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000000, 0x02)
p = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001
assert E.order() == p
Scalar = GF(p)
x = np.array([
Scalar(110), Scalar(56), Scalar(89), Scalar(6543), Scalar(2)
])
y = np.array([
Scalar(4), Scalar(88), Scalar(14), Scalar(33), Scalar(6)
])
z = x.dot(y)
assert len(x) == len(y)
# Create some generator points. Normally we would use hash to curve.
# All these points will be generators since the curve is a cyclic group
H = E.random_element()
G_vec = [E.random_element() for _ in range(len(x))]
# We will now construct a proof
# Commitments
def dot_product(x, y):
result = None
for x_i, y_i in zip(x, y):
if result is None:
result = int(x_i) * y_i
else:
result += int(x_i) * y_i
return result
t = Scalar.random_element()
r = Scalar.random_element()
s = Scalar.random_element()
C_z = int(t) * H + int(z) * G
C_x = int(r) * H + dot_product(x, G_vec)
C_y = int(s) * H + dot_product(y, G_vec)
d_x = np.array([Scalar.random_element() for _ in range(len(x))])
d_y = np.array([Scalar.random_element() for _ in range(len(x))])
r_d = Scalar.random_element()
s_d = Scalar.random_element()
A_d = int(r_d) * H + dot_product(d_x, G_vec)
B_d = int(s_d) * H + dot_product(d_y, G_vec)
# (cx + d_x)(cy + d_y) = d_x d_y + c(x d_y + y d_x) + c^2 xy
t_0 = Scalar.random_element()
t_1 = Scalar.random_element()
C_0 = int(t_0) * H + int(d_x.dot(d_y)) * G
C_1 = int(t_1) * H + int(x.dot(d_y) + y.dot(d_x)) * G
# Challenge
# Using the Fiat-Shamir transform, we would hash the transcript
c = Scalar.random_element()
# Responses
f_x = c * x + d_x
f_y = c * y + d_y
r_x = c * r + r_d
s_y = c * s + s_d
t_z = c**2 * t + c * t_1 + t_0
# Verify
assert int(c) * C_x + A_d == int(r_x) * H + dot_product(f_x, G_vec)
assert int(c) * C_y + B_d == int(s_y) * H + dot_product(f_y, G_vec)
# Actual inner product check
# Comm(f_x f_y) == e^2 C_z + c Comm(x d_y + y d_x) + Comm(d_x d_y)
assert int(t_z) * H + int(f_x.dot(f_y)) * G == int(c**2) * C_z + int(c) * C_1 + C_0

View File

@@ -1,177 +0,0 @@
# This file was *autogenerated* from the file groth_poly_commit.sage
from sage.all_cmdline import * # import sage library
_sage_const_0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001 = Integer(0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001); _sage_const_0x00 = Integer(0x00); _sage_const_0x05 = Integer(0x05); _sage_const_0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000000 = Integer(0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000000); _sage_const_0x02 = Integer(0x02); _sage_const_0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001 = Integer(0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001); _sage_const_1000 = Integer(1000); _sage_const_1 = Integer(1); _sage_const_110 = Integer(110); _sage_const_2 = Integer(2); _sage_const_56 = Integer(56); _sage_const_89 = Integer(89); _sage_const_6543 = Integer(6543); _sage_const_0 = Integer(0); _sage_const_77 = Integer(77)
import numpy as np
from collections import namedtuple
PolyProof = namedtuple("PolyProof", [
"poly_commit",
"poly_blind_commit",
"poly_response",
"poly_blind_respond",
"x_blind_factors",
"evaluation_commits",
"evaluation_response",
"value"
])
# Implementation of Groth09 inner product proof
q = _sage_const_0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001
K = GF(q)
a = K(_sage_const_0x00 )
b = K(_sage_const_0x05 )
E = EllipticCurve(K, (a, b))
G = E(_sage_const_0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000000 , _sage_const_0x02 )
p = _sage_const_0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001
assert E.order() == p
Scalar = GF(p)
# Create some generator points. Normally we would use hash to curve.
# All these points will be generators since the curve is a cyclic group
H = E.random_element()
G_vec = [E.random_element() for _ in range(_sage_const_1000 )]
def dot_product(x, y):
result = None
for x_i, y_i in zip(x, y):
if result is None:
result = int(x_i) * y_i
else:
result += int(x_i) * y_i
return result
def poly_commit(p):
# Sage randomly orders terms. No guarantee about ordering.
#a = np.array(p.coefficients())
a = np.array([p[i] for i in range(p.degree() + _sage_const_1 )])
r = Scalar.random_element()
C_x = int(r) * H + dot_product(a, G_vec)
return (r, C_x)
def create_proof(p, r, x):
a = np.array([p[i] for i in range(p.degree() + _sage_const_1 )])
#a = np.array(p.coefficients())
x = np.array([x**i for i in range(p.degree() + _sage_const_1 )])
# Evaluate the polynomial
z = a.dot(x)
assert len(a) == len(x)
# We will now construct a proof
# Commitments
t = Scalar.random_element()
#r = Scalar.random_element()
s = Scalar.random_element()
C_z = int(t) * H + int(z) * G
C_x = int(r) * H + dot_product(a, G_vec)
C_y = int(s) * H + dot_product(x, G_vec)
d_x = np.array([Scalar.random_element() for _ in range(len(x))])
d_y = np.array([Scalar.random_element() for _ in range(len(x))])
r_d = Scalar.random_element()
s_d = Scalar.random_element()
A_d = int(r_d) * H + dot_product(d_x, G_vec)
B_d = int(s_d) * H + dot_product(d_y, G_vec)
# (cx + d_x)(cy + d_y) = d_x d_y + c(x d_y + y d_x) + c^2 xy
t_0 = Scalar.random_element()
t_1 = Scalar.random_element()
C_0 = int(t_0) * H + int(d_x.dot(d_y)) * G
C_1 = int(t_1) * H + int(a.dot(d_y) + x.dot(d_x)) * G
# Challenge
# Using the Fiat-Shamir transform, we would hash the transcript
#c = Scalar.random_element()
c = _sage_const_110
# Responses
f_x = c * a + d_x
f_y = c * x + d_y
r_x = c * r + r_d
s_y = c * s + s_d
t_z = c**_sage_const_2 * t + c * t_1 + t_0
# Verify
#B_d = int(s_d) * H + dot_product(d_y, G_vec)
#C_y = int(s) * H + dot_product(x, G_vec)
assert int(c) * C_x + A_d == int(r_x) * H + dot_product(f_x, G_vec)
assert int(c) * C_y + B_d == int(s_y) * H + dot_product(f_y, G_vec)
# Actual inner product check
# Comm(f_x f_y) == e^2 C_z + c Comm(x d_y + y d_x) + Comm(d_x d_y)
assert int(t_z) * H + int(f_x.dot(f_y)) * G == int(c**_sage_const_2 ) * C_z + int(c) * C_1 + C_0
return PolyProof(
poly_commit=C_x,
poly_blind_commit=A_d,
poly_response=f_x,
poly_blind_respond=r_x,
x_blind_factors=(s_d, d_y, s),
evaluation_commits=(C_0, C_1, C_z),
evaluation_response=t_z,
value=z
)
def verify_proof(proof, x):
C_x = proof.poly_commit
A_d = proof.poly_blind_commit
f_x = proof.poly_response
r_x = proof.poly_blind_respond
(s_d, d_y, s) = proof.x_blind_factors
(C_0, C_1, C_z) = proof.evaluation_commits
t_z = proof.evaluation_response
z = proof.value
x = np.array([x**i for i in range(len(a))])
c = _sage_const_110
f_y = c * x + d_y
s_y = c * s + s_d
B_d = int(s_d) * H + dot_product(d_y, G_vec)
C_y = int(s) * H + dot_product(x, G_vec)
if int(c) * C_x + A_d != int(r_x) * H + dot_product(f_x, G_vec):
return False
if int(c) * C_y + B_d != int(s_y) * H + dot_product(f_y, G_vec):
return False
# Actual inner product check
# Comm(f_x f_y) == e^2 C_z + c Comm(x d_y + y d_x) + Comm(d_x d_y)
if int(t_z) * H + int(f_x.dot(f_y)) * G != int(c**_sage_const_2 ) * C_z + int(c) * C_1 + C_0:
return False
return True
#R = LaurentPolynomialRing(Scalar, names=('x',)); (x,) = R._first_ngens(1)
#a = np.array([
# Scalar(_sage_const_110 ), Scalar(_sage_const_56 ), Scalar(_sage_const_89 ), Scalar(_sage_const_6543 ), Scalar(_sage_const_2 )
#])
#p = _sage_const_0
#for i, a_i in enumerate(a):
# p += a_i * x**i
#print(p)
#xx = Scalar(_sage_const_77 )
#r, commit = poly_commit(p)
#proof = create_proof(p, r, xx)
#assert verify_proof(proof, xx)
#assert proof.poly_commit == commit
#assert proof.value == p(xx)

View File

@@ -1,170 +0,0 @@
import numpy as np
from collections import namedtuple
PolyProof = namedtuple("PolyProof", [
"poly_commit",
"poly_blind_commit",
"poly_response",
"poly_blind_respond",
"x_blind_factors",
"evaluation_commits",
"evaluation_response",
"value"
])
# Implementation of Groth09 inner product proof
q = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001
K = GF(q)
a = K(0x00)
b = K(0x05)
E = EllipticCurve(K, (a, b))
G = E(0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000000, 0x02)
p = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001
assert E.order() == p
Scalar = GF(p)
# Create some generator points. Normally we would use hash to curve.
# All these points will be generators since the curve is a cyclic group
H = E.random_element()
G_vec = [E.random_element() for _ in range(1000)]
def dot_product(x, y):
result = None
for x_i, y_i in zip(x, y):
if result is None:
result = int(x_i) * y_i
else:
result += int(x_i) * y_i
return result
def poly_commit(p):
# Sage randomly orders terms. No guarantee about ordering.
#a = np.array(p.coefficients())
a = np.array([p[i] for i in range(p.degree() + 1)])
r = Scalar.random_element()
C_x = int(r) * H + dot_product(a, G_vec)
return (r, C_x)
def create_proof(p, r, x):
a = np.array([p[i] for i in range(p.degree() + 1)])
#a = np.array(p.coefficients())
x = np.array([x**i for i in range(p.degree() + 1)])
# Evaluate the polynomial
z = a.dot(x)
assert len(a) == len(x)
# We will now construct a proof
# Commitments
t = Scalar.random_element()
#r = Scalar.random_element()
s = Scalar.random_element()
C_z = int(t) * H + int(z) * G
C_x = int(r) * H + dot_product(a, G_vec)
C_y = int(s) * H + dot_product(x, G_vec)
d_x = np.array([Scalar.random_element() for _ in range(len(x))])
d_y = np.array([Scalar.random_element() for _ in range(len(x))])
r_d = Scalar.random_element()
s_d = Scalar.random_element()
A_d = int(r_d) * H + dot_product(d_x, G_vec)
B_d = int(s_d) * H + dot_product(d_y, G_vec)
# (cx + d_x)(cy + d_y) = d_x d_y + c(x d_y + y d_x) + c^2 xy
t_0 = Scalar.random_element()
t_1 = Scalar.random_element()
C_0 = int(t_0) * H + int(d_x.dot(d_y)) * G
C_1 = int(t_1) * H + int(a.dot(d_y) + x.dot(d_x)) * G
# Challenge
# Using the Fiat-Shamir transform, we would hash the transcript
#c = Scalar.random_element()
c = 110
# Responses
f_x = c * a + d_x
f_y = c * x + d_y
r_x = c * r + r_d
s_y = c * s + s_d
t_z = c**2 * t + c * t_1 + t_0
# Verify
#B_d = int(s_d) * H + dot_product(d_y, G_vec)
#C_y = int(s) * H + dot_product(x, G_vec)
assert int(c) * C_x + A_d == int(r_x) * H + dot_product(f_x, G_vec)
assert int(c) * C_y + B_d == int(s_y) * H + dot_product(f_y, G_vec)
# Actual inner product check
# Comm(f_x f_y) == e^2 C_z + c Comm(x d_y + y d_x) + Comm(d_x d_y)
assert int(t_z) * H + int(f_x.dot(f_y)) * G == int(c**2) * C_z + int(c) * C_1 + C_0
return PolyProof(
poly_commit=C_x,
poly_blind_commit=A_d,
poly_response=f_x,
poly_blind_respond=r_x,
x_blind_factors=(s_d, d_y, s),
evaluation_commits=(C_0, C_1, C_z),
evaluation_response=t_z,
value=z
)
def verify_proof(proof, x):
C_x = proof.poly_commit
A_d = proof.poly_blind_commit
f_x = proof.poly_response
r_x = proof.poly_blind_respond
(s_d, d_y, s) = proof.x_blind_factors
(C_0, C_1, C_z) = proof.evaluation_commits
t_z = proof.evaluation_response
z = proof.value
x = np.array([x**i for i in range(len(a))])
c = 110
f_y = c * x + d_y
s_y = c * s + s_d
B_d = int(s_d) * H + dot_product(d_y, G_vec)
C_y = int(s) * H + dot_product(x, G_vec)
if int(c) * C_x + A_d != int(r_x) * H + dot_product(f_x, G_vec):
return False
if int(c) * C_y + B_d != int(s_y) * H + dot_product(f_y, G_vec):
return False
# Actual inner product check
# Comm(f_x f_y) == e^2 C_z + c Comm(x d_y + y d_x) + Comm(d_x d_y)
if int(t_z) * H + int(f_x.dot(f_y)) * G != int(c**2) * C_z + int(c) * C_1 + C_0:
return False
return True
R.<x> = LaurentPolynomialRing(Scalar)
a = np.array([
Scalar(110), Scalar(56), Scalar(89), Scalar(6543), Scalar(2)
])
p = 0
for i, a_i in enumerate(a):
p += a_i * x**i
print(p)
xx = Scalar(77)
r, commit = poly_commit(p)
proof = create_proof(p, r, xx)
assert verify_proof(proof, xx)
assert proof.poly_commit == commit
assert proof.value == p(xx)

View File

@@ -1,282 +0,0 @@
import numpy as np
from groth_poly_commit import Scalar, poly_commit, create_proof, verify_proof
K = Scalar
# Just use the same finite field we put in the polynomial commitment scheme file
#p = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001
#K = FiniteField(p)
R.<x, y> = LaurentPolynomialRing(K)
var_one = K(1)
var_x = K(4)
var_y = K(6)
var_s = K(1)
var_xy = var_x * var_y
var_sxy = var_s * var_xy
var_1_neg_s = var_one - var_s
var_x_y = var_x + var_y
var_1_neg_s_x_y = var_1_neg_s * var_x_y
var_s_neg_1 = -var_1_neg_s
var_zero = K(0)
public_v = var_s * (var_x * var_y) + (1 - var_s) * (var_x + var_y)
a = np.array([
var_one, var_x, var_xy, var_1_neg_s, var_s
])
b = np.array([
var_one, var_y, var_s, var_x_y, var_s_neg_1
])
c = np.array([
var_one, var_xy, var_sxy, var_1_neg_s_x_y, var_zero
])
assert len(a) == len(b)
assert len(b) == len(c)
for i, (a_i, b_i, c_i) in enumerate(zip(a, b, c), 1):
try:
assert a_i * b_i == c_i
except AssertionError:
print("Error for %i" % i)
raise
# 1 - s = -(s - 1)
u1 = np.array([0, 0, 0, 1, 0])
v1 = np.array([0, 0, 0, 0, 1])
w1 = np.array([0, 0, 0, 0, 0])
k1 = 0
assert a.dot(u1) + b.dot(v1) + c.dot(w1) == k1
# xy = xy
u2 = np.array([0, 0, 1, 0, 0])
v2 = np.array([0, 0, 0, 0, 0])
w2 = np.array([0, -1, 0, 0, 0])
k2 = 0
assert a.dot(u2) + b.dot(v2) + c.dot(w2) == k2
# s = s
u3 = np.array([0, 0, 0, 0, -1])
v3 = np.array([0, 0, 1, 0, 0])
w3 = np.array([0, 0, 0, 0, 0])
k3 = 0
assert a.dot(u3) + b.dot(v3) + c.dot(w3) == k3
# zero = 0
u4 = np.array([0, 0, 0, 0, 0])
v4 = np.array([0, 0, 0, 0, 0])
w4 = np.array([0, 0, 0, 0, 1])
k4 = 0
assert a.dot(u4) + b.dot(v4) + c.dot(w4) == k4
# 1 - s
u5 = np.array([1, 0, 0, -1, 0])
v5 = np.array([0, 0, -1, 0, 0])
w5 = np.array([0, 0, 0, 0, 0])
k5 = 0
assert a.dot(u5) + b.dot(v5) + c.dot(w5) == k5
# x + y
u6 = np.array([0, 1, 0, 0, 0])
v6 = np.array([0, 1, 0, -1, 0])
w6 = np.array([0, 0, 0, 0, 0])
k6 = 0
assert a.dot(u6) + b.dot(v6) + c.dot(w6) == k6
# Final check:
# v = s(xy) + (1 - s)(x + y)
u7 = np.array([0, 0, 0, 0, 0])
v7 = np.array([0, 0, 0, 0, 0])
w7 = np.array([0, 0, 1, 1, 0])
k7 = public_v
assert a.dot(u7) + b.dot(v7) + c.dot(w7) == k7
u = np.vstack((u1, u2, u3, u4, u5, u6, u7))
v = np.vstack((v1, v2, v3, v4, v5, v6, v7))
w = np.vstack((w1, w2, w3, w4, w5, w6, w7))
assert u.shape == v.shape
assert u.shape == w.shape
k = np.array((k1, k2, k3, k4, k5, k6, k7))
p = K(0)
for i, (a_i, b_i, c_i) in enumerate(zip(a, b, c), 1):
#print(a_i, "\t", b_i, "\t", c_i)
p += y**i * (a_i * b_i - c_i)
print(p)
p = K(0)
for q, (u_q, v_q, w_q, k_q) in enumerate(zip(u, v, w, k)):
p += y**q * (a.dot(u_q) + b.dot(v_q) + c.dot(w_q) - k_q)
print(p)
n = len(a)
assert len(b) == n
assert len(c) == n
assert u.shape == (7, n)
assert v.shape == u.shape
assert w.shape == u.shape
assert k.shape == (7,)
r_x_y = 0
s_x_y = 0
for i, (a_i, b_i, c_i) in enumerate(zip(a, b, c), 1):
assert 1 <= i <= n
r_x_y += x**i * y**i * a_i
r_x_y += x**-i * y**-i * b_i
r_x_y += x**(-i - n) * y**(-i - n) * c_i
u_i = u.T[i - 1]
v_i = v.T[i - 1]
w_i = w.T[i - 1]
u_i_Y = 0
v_i_Y = 0
w_i_Y = 0
for q, (u_q_i, v_q_i, w_q_i) in enumerate(zip(u_i, v_i, w_i), 1):
assert 1 <= q <= 7
u_i_Y += y**q * u_q_i
v_i_Y += y**q * v_q_i
w_i_Y += y**q * w_q_i
s_x_y += u_i_Y * x**-i + v_i_Y * x**i + w_i_Y * x**(i + n)
k_y = 0
for q, k_q in enumerate(k, 1):
assert 1 <= q <= 7
k_y += y**q * k_q
# Section 6, Figure 2
#
# zkP1
# 4 blinding factors since we evaluate r(X, Y) 3 times
# Blind r(X, Y)
for i in range(1, 4 + 1):
blind_c_i = K.random_element()
r_x_y += x**(-2*n - i) * y**(-2*n - i) * blind_c_i
# Commit to r(X, Y)
s_prime_x_y = y**n * s_x_y
for i in range(1, n):
s_prime_x_y -= (y**i + y**-i) * x**(i + n)
r_x_1 = r_x_y(y=K(1))
t_x_y = r_x_1 * (r_x_y + s_prime_x_y) - y**n * k_y
# This can be opened to r(X, Y) since r(X, Y) = r(XY, 1)
r_x_1_scaled = (r_x_1 * x**(3*n - 1)).univariate_polynomial()
rx1_commit_blind, rx1_commit = poly_commit(r_x_1_scaled)
print("===================")
print(" t(X, Y)")
print("===================")
power_dict = ["", "¹", "²", "³", "", "", "", "", "", ""]
def superscript(number):
sign = ""
if number < 0:
sign = ""
number = -number
return sign + "".join([power_dict[int(digit)] for digit in list(str(number))])
decorated = []
for (x_power, y_power), coeff in t_x_y.dict().items():
if coeff == 1:
coeff = ""
display = "%s X%s Y%s" % (coeff, superscript(x_power), superscript(y_power))
decorated.append([x_power, y_power, display])
decorated.sort(key=lambda x: (x[0], -x[1]))
for _, _, display in decorated:
print(display)
print()
print("Constant coefficient:", t_x_y.constant_coefficient())
print()
# zkV1
# Send a random y
challenge_y = K.random_element()
# zkP2
# Commit to t(X, y)
t_x = t_x_y(y=challenge_y)
t_x = t_x.univariate_polynomial()
print("===================")
print(" t(X, y)")
print("===================")
print(t_x.dict())
print()
print("Constant coefficient:", t_x.constant_coefficient())
# Split the polynomial into low and hi versions
t_lo_x = 0
t_hi_x = 0
smallest_power = -min(t_x.dict().keys())
for power, coeff in t_x.dict().items():
assert power != 0
if power < 0:
t_lo_x += x**(smallest_power + power) * coeff
else:
t_hi_x += x**(power - 1) * coeff
d = t_lo_x.degree() + 1
t_lo_x = t_lo_x.univariate_polynomial()
t_hi_x = t_hi_x.univariate_polynomial()
assert (t_lo_x * x**-d + t_hi_x * x).univariate_polynomial() == t_x
T_lo_commit_blind, T_lo = poly_commit(t_lo_x)
T_hi_commit_blind, T_hi = poly_commit(t_hi_x)
# zkV2
# Send a random z
challenge_z = K.random_element()
# zkP3
# Evaluate a = r(z, 1)
a = r_x_y(x=challenge_z, y=K(1))
# Evaluate b = r(z, y)
b = r_x_y(x=challenge_z, y=challenge_y)
# Evaluate t = t(z, y)
t = t_x_y(x=challenge_z, y=challenge_y)
# Evaluate s = s(z, y)
s = s_prime_x_y(x=challenge_z, y=challenge_y)
# Calculate equivalent openings
# s'(X, Y) is known by both prover and verifier
a_proof = create_proof(r_x_1_scaled, rx1_commit_blind, challenge_z)
assert a_proof.poly_commit == rx1_commit
b_proof = create_proof(r_x_1_scaled, rx1_commit_blind, challenge_y * challenge_z)
assert b_proof.poly_commit == rx1_commit
t_proof_lo = create_proof(t_lo_x, T_lo_commit_blind, challenge_z)
assert t_proof_lo.poly_commit == T_lo
t_proof_hi = create_proof(t_hi_x, T_hi_commit_blind, challenge_z)
assert t_proof_hi.poly_commit == T_hi
# Signature of correct computation not yet implemented
# So just use s for now as is
# Scaling factor
verifier_rescale = challenge_z**(-3*n + 1)
assert a_proof.value * verifier_rescale == a
verifier_rescale = (challenge_y * challenge_z)**(-3*n + 1)
assert b_proof.value * verifier_rescale == b
# zkV3
# Recalculate t from a, b and s
t_new = t_proof_lo.value * challenge_z**-d + t_proof_hi.value * challenge_z
assert t_new == t
t = t_new
k = (y**n * k_y)(y=challenge_y)
t_new = a * (b + s) - k
assert t_new == t
# Verify polynomial commitments

View File

@@ -1,347 +0,0 @@
import numpy as np
q = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001
K = GF(q)
P.<X> = K[]
# GENERATOR^{2^s} where t * 2^s + 1 = q with t odd.
# In other words, this is a t root of unity.
generator = K(5)
# There is a large 2^32 order subgroup in this curve because it is 2-adic
t = (K(q) - 1) / 2^32
assert int(t) % 2 != 0
delta = generator^(2^32)
assert delta^t == 1
# The size of the multiplicative group is phi(q) = q - 1
# And inside this group are 2 distinct subgroups of size t and 2^s.
# delta is the generator for the size t subgroup, and omega for the 2^s one.
# Taking powers of these generators and multiplying them will produce
# unique cosets that divide the entire group for q.
def get_omega():
generator = K(5)
assert (q - 1) % 2^32 == 0
# Root of unity
t = (q - 1) / 2^32
omega = generator**t
assert omega != 1
assert omega^(2^16) != 1
assert omega^(2^31) != 1
assert omega^(2^32) == 1
return omega
# Order of this element is 2^32
omega = get_omega()
k = 4
n = 2^k
omega = omega^(2^32 / n)
assert omega^n == 1
# Arithmetization for:
# sxy + (s - 1)(x + y) - z = 0
# s(s - 1) = 0
# F1(A1 - 1) + F2 (A1 - I) + F3((1 - A1)(A2 + A3) - A4) + F4(A1 A2 A3 - A4) = 0
A = []
F = []
var_zero = K(0)
var_x = K(4)
var_y = K(6)
var_s = K(1)
var_sxy = var_s * var_x * var_y
var_1s_xy = (1 - var_s) * (var_x + var_y)
# Public
var_z = var_sxy + var_1s_xy
# 4 advice columns
# 4 fixed columns
# 1 instance column
# Row 1
# z = public z
A_1_1, A_2_1, A_3_1, A_4_1 = var_z, 0, 0, 0
F_1_1, F_2_1, F_3_1, F_4_1 = 1, 0, 0, 0
I_1 = var_z
# Row 2
# ~0 == 0
A_1_2, A_2_2, A_3_2, A_4_2 = var_zero, 0, 0, 0
F_1_2, F_2_2, F_3_2, F_4_2 = 0, 1, 0, 0
I_2 = 0
# Row 3
# Boolean check
# (1 - s)(s + 0) == 0
A_1_3, A_2_3, A_3_3, A_4_3 = var_s, var_s, var_zero, var_zero
F_1_3, F_2_3, F_3_3, F_4_3 = 0, 0, 1, 0
I_3 = 0
# Row 4
# s x y == sxy
A_1_4, A_2_4, A_3_4, A_4_4 = var_s, var_x, var_y, var_sxy
F_1_4, F_2_4, F_3_4, F_4_4 = 0, 0, 0, 1
I_4 = 0
# Row 5
# (1 - s)(x + y) = (1-s)(x+y)
A_1_5, A_2_5, A_3_5, A_4_5 = var_s, var_x, var_y, var_1s_xy
F_1_5, F_2_5, F_3_5, F_4_5 = 0, 0, 1, 0
I_5 = 0
# Row 6
# (1 - 0)(sxy + (1-s)(x+y)) = z
A_1_6, A_2_6, A_3_6, A_4_6 = var_zero, var_sxy, var_1s_xy, var_z
F_1_6, F_2_6, F_3_6, F_4_6 = 0, 0, 1, 0
I_6 = 0
A1 = [A_1_1, A_1_2, A_1_3, A_1_4, A_1_5, A_1_6]
A2 = [A_2_1, A_2_2, A_2_3, A_2_4, A_2_5, A_2_6]
A3 = [A_3_1, A_3_2, A_3_3, A_3_4, A_3_5, A_3_6]
A4 = [A_4_1, A_4_2, A_4_3, A_4_4, A_4_5, A_4_6]
F1 = [F_1_1, F_1_2, F_1_3, F_1_4, F_1_5, F_1_6]
F2 = [F_2_1, F_2_2, F_2_3, F_2_4, F_2_5, F_2_6]
F3 = [F_3_1, F_3_2, F_3_3, F_3_4, F_3_5, F_3_6]
F4 = [F_4_1, F_4_2, F_4_3, F_4_4, F_4_5, F_4_6]
I = [I_1, I_2, I_3, I_4, I_5, I_6]
# There should be 5 unused blinding rows.
# see src/plonk/circuit.rs: fn blinding_factors(&self) -> usize;
# We have 9 so we are perfectly fine.
# Add 9 empty rows
assert n - len(A1) == 10
for i in range(10):
A1.append(K.random_element())
A2.append(K.random_element())
A3.append(K.random_element())
A4.append(K.random_element())
F1.append(0)
F2.append(0)
F3.append(0)
F4.append(0)
I.append(K.random_element())
assert (len(A1) == len(A2) == len(A3) == len(A4) == len(F1) == len(F2)
== len(F3) == len(F4) == len(I) == n)
for A_1_i, A_2_i, A_3_i, A_4_i, F_1_i, F_2_i, F_3_i, F_4_i, I_i in zip(
A1, A2, A3, A4, F1, F2, F3, F4, I):
assert (F_1_i * (A_1_i - I_i)
+ F_2_i * A_1_i
+ F_3_i * ((1 - A_1_i) * (A_2_i + A_3_i) - A_4_i)
+ F_4_i * (A_1_i * A_2_i * A_3_i - A_4_i)) == 0
a_1_X = P.lagrange_polynomial((omega^i, A_1_i) for i, A_1_i in enumerate(A1))
a_2_X = P.lagrange_polynomial((omega^i, A_2_i) for i, A_2_i in enumerate(A2))
a_3_X = P.lagrange_polynomial((omega^i, A_3_i) for i, A_3_i in enumerate(A3))
a_4_X = P.lagrange_polynomial((omega^i, A_4_i) for i, A_4_i in enumerate(A4))
f_1_X = P.lagrange_polynomial((omega^i, F_1_i) for i, F_1_i in enumerate(F1))
f_2_X = P.lagrange_polynomial((omega^i, F_2_i) for i, F_2_i in enumerate(F2))
f_3_X = P.lagrange_polynomial((omega^i, F_3_i) for i, F_3_i in enumerate(F3))
f_4_X = P.lagrange_polynomial((omega^i, F_4_i) for i, F_4_i in enumerate(F4))
# Treat the instance wire as a 5th advice wire
a_5_X = P.lagrange_polynomial((omega^i, A_5_i) for i, A_5_i in enumerate(I))
for i, (A_1_i, A_2_i, A_3_i, A_4_i, F_1_i, F_2_i, F_3_i, F_4_i, I_i) in \
enumerate(zip(A1, A2, A3, A4, F1, F2, F3, F4, I)):
assert a_1_X(omega^i) == A_1_i
assert a_2_X(omega^i) == A_2_i
assert a_3_X(omega^i) == A_3_i
assert a_4_X(omega^i) == A_4_i
assert a_5_X(omega^i) == I_i
assert f_1_X(omega^i) == F_1_i
assert f_2_X(omega^i) == F_2_i
assert f_3_X(omega^i) == F_3_i
assert f_4_X(omega^i) == F_4_i
# beta, gamma
beta = K.random_element()
gamma = K.random_element()
# 0 1 2 3 4 5 ... 15
# A1: z, 0, s, s, s, 0,
#
# 16 17 18 19 20 21 ... 31
# A2: -, -, s, x, x, sxy,
#
# 32 33 34 35 36 37 ... 47
# A3: -, -, 0, y, y, (1-s)(x+y),
#
# 48 49 50 51 52 53 ... 63
# A4: -, -, 0, sxy, (1-s)(x + y), z,
#
# 64 65 66 67 68 69 ... 79
# A5: z, -, -, -, -, -,
# z = (0 53 64)
# 0 = (1 5 34 50)
# s = (2 3 4 18)
# x = (19 20)
# sxy = (21 51)
# y = (35 36)
# (1-s)(x+y) = (37 52)
permuted_indices = list(range(n * 5))
assert len(permuted_indices) == 80
# Apply the actual permutation cycles
# z
permuted_indices[0] = 53
permuted_indices[53] = 64
permuted_indices[64] = 0
# ~0
permuted_indices[1] = 5
permuted_indices[5] = 34
permuted_indices[34] = 50
permuted_indices[50] = 1
# s
permuted_indices[2] = 3
permuted_indices[3] = 4
permuted_indices[4] = 18
permuted_indices[18] = 2
# x
permuted_indices[19] = 20
permuted_indices[20] = 19
# sxy
permuted_indices[21] = 51
permuted_indices[51] = 21
# y
permuted_indices[35] = 36
permuted_indices[36] = 35
# (1-s)(x+y)
permuted_indices[37] = 52
permuted_indices[52] = 37
witness = A1 + A2 + A3 + A4 + I
for i, val in enumerate(witness):
assert val == witness[permuted_indices[i]]
# How to join lists together?
indices = ([omega^i for i in range(n)]
+ [delta * omega^i for i in range(n)]
+ [delta^2 * omega^i for i in range(n)]
+ [delta^3 * omega^i for i in range(n)]
+ [delta^4 * omega^i for i in range(n)])
assert len(indices) == 80
# Permuted indices
sigma_star = [indices[i] for i in permuted_indices]
s = [sigma_star[:n], sigma_star[n:2 * n], sigma_star[2 * n:3 * n],
sigma_star[3 * n:4 * n], sigma_star[4 * n:]]
assert s[0] + s[1] + s[2] + s[3] + s[4] == sigma_star
v = [A1, A2, A3, A4, I]
# We split the columns into sets of size m.
# Here we will use m = 1 for illustration purposes
# We have 6 usable rows
# n = 16 rows total
# row u (q_last) will be the 7th row
# So we have 9 unusable rows
q_blind = [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1]
q_last = [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
# Turn both of these into polynomial form
q_blind = P.lagrange_polynomial((omega^i, q_i) for i, q_i in enumerate(q_blind))
assert q_blind(omega^5) == 0
assert q_blind(omega^6) == 0
assert q_blind(omega^7) == 1
assert q_blind(omega^11) == 1
q_last = P.lagrange_polynomial((omega^i, q_i) for i, q_i in enumerate(q_last))
assert q_last(omega^5) == 0
assert q_last(omega^6) == 1
assert q_last(omega^7) == 0
assert q_last(omega^11) == 0
m = 5
assert n == 16
# 6 usable rows
u = 6
# There are 5 columns
# We will split the columns partitions into 5 partitions to make things easy
# So b = 5, and each partition contains only a single column
# We still iterate over the column to make it more obvious
m = 1
permutation_points = [(1, 1)]
last_y_value = 1
ZP = []
# a is the current column partition we are aggregating
for a in range(5):
# j iterates over the rows
for j in range(u):
current = last_y_value
# i iterates over the columns in our partition
for i in range(a * m, (a + 1)):
current *= v[i][j] + beta * delta^i * omega^j + gamma
current /= v[i][j] + beta * s[i][j] + gamma
last_y_value = current
permutation_points.append((omega^(j + 1), current))
ZP_a = P.lagrange_polynomial(permutation_points)
ZP.append(ZP_a)
permutation_points = [(1, last_y_value)]
# l_0(X) (1 - ZP,0(X)) = 0
# => ZP,0(1) = 1
assert ZP[0](1) == 1
# Checks for l_0(X) (ZP,a(X) - ZP,a-1(omega^u X)) = 1
# => ZP,a(Z) = ZP,a-1(omega^u X)
# This copies the end value from one partition to the next one
assert ZP[1](omega^0) == ZP[0](omega^u)
assert ZP[2](omega^0) == ZP[1](omega^u)
assert ZP[3](omega^0) == ZP[2](omega^u)
assert ZP[4](omega^0) == ZP[3](omega^u)
# Allow the last value to be either 0 or 1 for full ZK
assert ZP[4](omega^u) in (0, 1)
y = K.random_element()
gate_0 = f_1_X * (a_1_X - a_5_X)
gate_1 = f_2_X * a_1_X
gate_2 = f_3_X * ((1 - a_1_X) * (a_2_X + a_3_X) - a_4_X)
gate_3 = f_4_X * (a_1_X * a_2_X * a_3_X - a_4_X)
c = gate_0 + y * gate_1 + y^2 * gate_2 + y^3 * gate_3
t = X^n - 1
for i in range(n):
assert h(omega^i) == 0
# Normally we do:
#h = c / t
# But for some reason sage is producing fractional coefficients
h, rem = c.quo_rem(t)
assert rem == 0
# We send commitments to the terms of h(X)
# h_0(x), ..., h_{d - 1}(x)
# Commitments:
# H = [H_0, ..., H_{d - 1}]
x = K.random_element()
# Send evaluations at x of everything we committed to so far
# A_0(x), ..., A_{m - 1}(x)
# ZP,0(x), ..., ZP,b-1(x)
# H_0(x), ..., H_{d-1}(x)
a_evals = [a_1_X(x), a_2_X(x), a_3_X(x), a_4_X(x), a_5_X(x)]
h_evals = []
# Iterate starting from lowest powers first
h_test = 0
for i, h_i in enumerate(h):
h_evals.append(h_i * x^i)
h_test += h_i * X^i
assert h_test == h
assert sum(h_evals) == h(x)
assert sum(h_evals) * t(x) == (
f_1_X(x) * (a_evals[0] - a_evals[4])
+ y * f_2_X(x) * a_evals[0]
+ y^2 * f_3_X(x) * ((1 - a_evals[0]) * (a_evals[1] + a_evals[2])
- a_evals[3])
+ y^3 * f_4_X(x) * (a_evals[0] * a_evals[1] * a_evals[2] - a_evals[3]))

View File

@@ -1,33 +0,0 @@
import random
def sample_random(fp, seed=None):
rnd = random.Random(seed)
# Range of the field is 0 ... p - 1
return fp(rnd.randint(0, fp.p - 1))
def is_power_of_two(n):
# Power of two number is represented by a single digit
# followed by zeroes.
return n & (n - 1) == 0
#| ## Choosing roots of unity
def get_omega(fp, n, seed=None):
"""
Given a field, this method returns an n^th root of unity.
If the seed is not None then this method will return the
same n'th root of unity for every run with the same seed
This only makes sense if n is a power of 2.
"""
assert is_power_of_two(n)
# https://crypto.stackexchange.com/questions/63614/finding-the-n-th-root-of-unity-in-a-finite-field
while True:
# Sample random x != 0
x = sample_random(fp, seed)
# Compute g = x^{(q - 1)/n}
y = pow(x, (fp.p - 1) // n)
# If g^{n/2} != 1 then g is a primitive root
if y != 1 and pow(y, n // 2) != 1:
assert pow(y, n) == 1, "omega must be 2nd root of unity"
return y

View File

@@ -1,288 +0,0 @@
import numpy as np
from finite_fields import finitefield
class Variable:
def __init__(self, name, fp):
self.name = name
self.fp = fp
def __pow__(self, n):
expr = MultiplyExpression(self.fp)
expr.set_symbol(self.name, n)
return expr
def __eq__(self, other):
return self.name == other.name
def __hash__(self):
return hash(self.name)
def termify(self):
expr = MultiplyExpression(self.fp)
expr.set_symbol(self.name, 1)
return expr
class MultiplyExpression:
def __init__(self, fp):
self.coeff = fp(1)
self.symbols = {}
self.fp = fp
def copy(self):
result = MultiplyExpression(self.fp)
result.coeff = self.coeff
result.symbols = self.symbols.copy()
return result
def clean(self):
for symbol in list(self.symbols.keys()):
if self.symbols[symbol] == 0:
del self.symbols[symbol]
def matches(self, other):
return self.symbols == other.symbols
def set_symbol(self, var_name, power):
self.symbols[var_name] = power
def __eq__(self, other):
return (self.coeff == other.coeff and
self.symbols == other.symbols)
def __neg__(self):
result = self.copy()
result.coeff *= -1
return result
def __mul__(self, expr):
result = MultiplyExpression(self.fp)
result.coeff = self.coeff
result.symbols = self.symbols.copy()
if isinstance(expr, np.int64) or isinstance(expr, int):
expr = self.fp(int(expr))
if hasattr(expr, "field"):
result.coeff *= expr
return result
if isinstance(expr, Variable):
expr = expr.termify()
for var_name, power in expr.symbols.items():
if var_name in result.symbols:
result.symbols[var_name] += power
else:
result.symbols[var_name] = power
# Remember to multiply the coefficients
result.coeff *= expr.coeff
return result
def __add__(self, expr):
if isinstance(expr, Variable):
expr = expr.termify()
if self.matches(expr):
result = self.copy()
result.coeff += expr.coeff
return result
return MultivariatePolynomial([self, expr])
def __sub__(self, expr):
expr = -expr
return self + expr
def evaluate(self, symbol_map):
result = MultiplyExpression(self.fp)
for symbol, power in self.symbols.items():
if symbol in symbol_map:
value = symbol_map[symbol]
result *= value**power
else:
result *= Variable(symbol, self.fp)**power
return result
def __str__(self):
repr = ""
first = True
if self.coeff != 1:
repr += str(self.coeff)
first = False
for var_name, power in self.symbols.items():
if first:
first = False
else:
repr += " "
if power == 1:
repr += var_name
else:
repr += var_name + "^" + str(power)
return repr
class MultivariatePolynomial:
def __init__(self, terms=[]):
self.terms = terms
def copy(self):
terms = [term.copy() for term in self.terms]
return MultivariatePolynomial(terms)
# Operations can accept Variables and constants
# so we make sure to convert them to MultiplyExpression types
def _convert_term(self, term):
if isinstance(term, Variable):
term = term.termify()
if hasattr(term, "field"):
expr = MultiplyExpression(term.field)
expr.coeff = term
term = expr
return term
def __bool__(self):
return bool(self.terms)
def __eq__(self, other):
return self.terms == other.terms
def __neg__(self):
terms = [-term for term in self.terms]
return MultivariatePolynomial(terms)
def __add__(self, term):
term = self._convert_term(term)
if isinstance(term, MultivariatePolynomial):
# Recursively apply addition operation
result = self.copy()
for other_term in term.terms:
result += other_term
return result
assert isinstance(term, MultiplyExpression)
# Delete ^0 variables
term.clean()
# Skip terms where the coeff is 0
if term.coeff == 0:
return self
result = self.copy()
result_term = result._find(term)
if result_term is None:
result.terms.append(term)
else:
result_term.coeff += term.coeff
return result
def __sub__(self, term):
term = -term
return self + term
def __mul__(self, term):
term = self._convert_term(term)
if isinstance(term, MultivariatePolynomial):
# Recursively apply addition operation
result = MultivariatePolynomial()
for other_term in term.terms:
result += self * other_term
return result
assert isinstance(term, MultiplyExpression)
# Delete ^0 variables
term.clean()
# Skip terms where the coeff is 0
if term.coeff == 0:
return self
terms = [self_term * term for self_term in self.terms]
result = MultivariatePolynomial(terms)
return result
def divmod(self, poly):
assert isinstance(poly, MultivariatePolynomial)
# https://www.win.tue.nl/~aeb/2WF02/groebner.pdf
def _find(self, other):
for term in self.terms:
if term.matches(other):
return term
return None
def evaluate(self, variable_map):
p = MultivariatePolynomial()
for term in self.terms:
assert isinstance(term, MultiplyExpression)
p += term.evaluate(variable_map)
return p
def _assert_unique_terms(self):
for i, term1 in enumerate(self.terms):
for q, term2 in enumerate(self.terms):
if i == q:
continue
assert not term1.matches(term2)
def filter(self, variables):
p = MultivariatePolynomial()
for term in self.terms:
assert isinstance(term, MultiplyExpression)
skip = False
for variable in variables:
symbol = variable.name
if symbol in term.symbols:
skip = True
if not skip:
p += term
return p
def __str__(self):
if not self.terms:
return "0"
repr = ""
first = True
for term in self.terms:
if first:
first = False
else:
repr += " + "
repr += str(term)
return repr
if __name__ == "__main__":
from finite_fields import finitefield
p = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001
fp = finitefield.IntegersModP(p)
x = Variable("X")
y = Variable("Y")
z = Variable("Z")
print(y**2 + y**2)
p = x**3 * y**2 * x**2 * fp(5) * fp(2) + x**3 * y + z + fp(6)
q = x**3 * y * fp(3) + y
print(p)
print(q)
print(p + q)
print(p * q)
print(-q)
print(p - q)

View File

@@ -1,5 +0,0 @@
from finite_fields import finitefield
q = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001
fq = finitefield.IntegersModP(q)

View File

@@ -1,187 +0,0 @@
#import numpy as np
from groth_poly_commit import Scalar, poly_commit, create_proof, verify_proof
K = Scalar
#R.<x> = LaurentPolynomialRing(K)
R.<x> = PolynomialRing(K)
var_one = K(1)
var_x = K(4)
var_y = K(6)
var_s = K(1)
var_xy = var_x * var_y
var_x_y = var_x + var_y
var_1_neg_s = var_one - var_s
var_sxy = var_s * var_xy
var_1_neg_s_x_y = var_1_neg_s * var_x_y
#var_s_neg_1 = -var_1_neg_s
var_zero = K(0)
public_value = var_s * (var_x * var_y) + (1 - var_s) * (var_x + var_y)
# x * y = xy
a1 = var_x
b1 = var_y
c1 = var_xy
Ql1 = 0
Qr1 = 0
Qm1 = 1
Qo1 = -1
Qc1 = 0
assert Ql1 * a1 + Qr1 * b1 + Qm1 * a1 * b1 + Qo1 * c1 + Qc1 == 0
# x + y = (x + y)
a2 = var_x
b2 = var_y
c2 = var_x_y
Ql2 = 1
Qr2 = 1
Qm2 = 0
Qo2 = -1
Qc2 = 0
assert Ql2 * a2 + Qr2 * b2 + Qm2 * a2 * b2 + Qo2 * c2 + Qc2 == 0
# 1 - s = (1 - s)
a3 = var_one
b3 = var_s
c3 = var_1_neg_s
Ql3 = 1
Qr3 = -1
Qm3 = 0
Qo3 = -1
Qc3 = 0
assert Ql3 * a3 + Qr3 * b3 + Qm3 * a3 * b3 + Qo3 * c3 + Qc3 == 0
# s * (xy) = sxy
a4 = var_s
b4 = var_xy
c4 = var_sxy
Ql4 = 0
Qr4 = 0
Qm4 = 1
Qo4 = -1
Qc4 = 0
assert Ql4 * a4 + Qr4 * b4 + Qm4 * a4 * b4 + Qo4 * c4 + Qc4 == 0
# (1 - s) * (x + y) = [(1 - s)(x + y)]
a5 = var_1_neg_s
b5 = var_x_y
c5 = var_1_neg_s_x_y
Ql5 = 0
Qr5 = 0
Qm5 = 1
Qo5 = -1
Qc5 = 0
assert Ql5 * a5 + Qr5 * b5 + Qm5 * a5 * b5 + Qo5 * c5 + Qc5 == 0
# (sxy) + [(1 - s)(x + y)] = public_value
a6 = var_sxy
b6 = var_1_neg_s_x_y
# Unused
c6 = var_zero
Ql6 = 1
Qr6 = 1
Qm6 = 0
Qo6 = 0
Qc6 = -public_value
assert Ql6 * a6 + Qr6 * b6 + Qm6 * a6 * b6 + Qo6 * c6 + Qc6 == 0
# one == 1
a7 = var_one
# Unused
b7 = var_zero
# Unused
c7 = var_zero
Ql7 = 1
Qr7 = 0
Qm7 = 0
Qo7 = 0
Qc7 = -1
assert Ql7 * a7 + Qr7 * b7 + Qm7 * a7 * b7 + Qo7 * c7 + Qc7 == 0
a = [a1, a2, a3, a4, a5, a6, a7]
b = [b1, b2, b3, b4, b5, b6, b7]
c = [c1, c2, c3, c4, c5, c6, c7]
Ql = [Ql1, Ql2, Ql3, Ql4, Ql5, Ql6]
Qr = [Qr1, Qr2, Qr3, Qr4, Qr5, Qr6]
Qm = [Qm1, Qm2, Qm3, Qm4, Qm5, Qm6]
Qo = [Qo1, Qo2, Qo3, Qo4, Qo5, Qo6]
Qc = [Qc1, Qc2, Qc3, Qc4, Qc5, Qc6]
# 0 1 2 3 4 5 6
# a: x, x, 1, s, 1 - s, sxy, 1
#
# 7 8 9 10 11 12 13
# b: y, y, s, xy, x + y, (1 - s)(x + y), -
#
# 14 15 16 17 18 19 20
# c: xy, x + y, 1 - s, sxy, (1 - s)(x + y), -, -
permuted_indices = [
1, 0, 6, 9, 16, 17, 2,
8, 7, 3, 14, 15, 18, 13,
10, 11, 4, 5, 12, 19, 20
]
eval_domain = range(0, len(permuted_indices))
witness = a + b + c
for i, val in enumerate(a + b + c):
assert val == witness[permuted_indices[i]]
#def lagrange(domain, codomain):
# S.<x> = PolynomialRing(K)
# p = S.lagrange_polynomial(zip(eval_domain, permuted_indices))
# # Convert to a Laurent polynomial
# return R(p)
# This is what the prover passes to the verifier
witness_y = R.lagrange_polynomial(enumerate(witness))
assert witness_y(12) == witness[12]
witness_x_a = R.lagrange_polynomial(
zip(eval_domain[0:7], eval_domain[0:7]))
witness_x_b = R.lagrange_polynomial(
zip(eval_domain[7:14], eval_domain[7:14]))
witness_x_c = R.lagrange_polynomial(
zip(eval_domain[14:], eval_domain[14:]))
assert witness_x_a(2) == eval_domain[2]
assert witness_x_b(8) == eval_domain[8]
assert witness_x_c(16) == eval_domain[16]
witness_x_a_prime = R.lagrange_polynomial(
zip(eval_domain[0:7], permuted_indices[0:7]))
witness_x_b_prime = R.lagrange_polynomial(
zip(eval_domain[7:14], permuted_indices[7:14]))
witness_x_c_prime = R.lagrange_polynomial(
zip(eval_domain[14:], permuted_indices[14:]))
assert witness_x_a_prime(2) == permuted_indices[2]
assert witness_x_b_prime(8) == permuted_indices[8]
assert witness_x_c_prime(16) == permuted_indices[16]
v1 = K(2)
v2 = K(3)
px = 1
for i in range(0, len(a)):
px *= v1 + witness_x_a(i) + v2 * witness_y(i)
for i in range(len(a), 2 * len(a)):
px *= v1 + witness_x_b(i) + v2 * witness_y(i)
for i in range(2 * len(a), 3 * len(a)):
px *= v1 + witness_x_c(i) + v2 * witness_y(i)
px_prime = 1
for i in range(0, len(a)):
px_prime *= v1 + witness_x_a_prime(i) + v2 * witness_y(i)
for i in range(len(a), 2 * len(a)):
px_prime *= v1 + witness_x_b_prime(i) + v2 * witness_y(i)
for i in range(2 * len(a), 3 * len(a)):
px_prime *= v1 + witness_x_c_prime(i) + v2 * witness_y(i)
assert px == px_prime

View File

@@ -1,360 +0,0 @@
F101 = Integers(101)
E = EllipticCurve(F101, [0, 3])
R.<X> = PolynomialRing(F101)
# Extension field of points of 101, and solutions of x^2 + 2
K.<X> = GF(101**2, modulus=X^2 + 2)
# y^2 = x^3 + 3 in this curve defined over the extension field.
# Needed for pairing.
E2 = EllipticCurve(K, [0, 3])
# Generator point because 1^3 + 3 = 4 which is sqrt of 2
G = E([1, 2])
G2 = E2([36, 31*X])
assert G.order() == 17
F17 = Integers(17)
assert F17.square_roots_of_one() == (1, 16)
# 16 == -1
# so now we have the 4th roots of 1
w = vector(F17, [1, 4, -1, -4])
# omega = 4, omega^0 = 1, omega^1 = 4, omega^3 = -1 = 13, omega^3 = 13
# so now we are still defining our reference string
# we have 4 x labels for our permutation vector but we need 12
# so we generate 2 cosets using quadratic non-residues in F
# all 3 cosets should not share any value in common
k1 = 2
k2 = 3
assert w == vector(F17, [1, 4, 16, 13])
assert k1 * w == vector(F17, [2, 8, 15, 9])
assert k2 * w == vector(F17, [3, 12, 14, 5])
A = matrix(F17, [
[1, 1, 1, 1],
[4^0, 4^1, 4^2, 4^3],
[16^0, 16^1, 16^2, 16^3],
[13^0, 13^1, 13^2, 13^3]
])
Ai = A.inverse()
P.<x> = F17[]
x = P.0
# We only have 3 gates in this example for x^3 + x = 30
# x x^2 x^3
# x x x
# x^2 x^3 0
# public input: 30
# we have 4 w values so the last column is empty (all set to 0 in this case)
fa = P.lagrange_polynomial(zip([1, 4, 16, 13], [3, 9, 27, 0]))
#fa = P(list(Ai * vector(F17, [3, 9, 27, 0])))
assert fa(1) == 3
assert fa(4) == 9
assert fa(16) == 27
assert fa(13) == 0
fb = P(list(Ai * vector(F17, [3, 3, 3, 0])))
assert fb(1) == 3
assert fb(4) == 3
assert fb(16) == 3
assert fb(13) == 0
fc = P(list(Ai * vector(F17, [9, 27, 0, 0])))
assert fc(1) == 9
assert fc(4) == 27
assert fc(16) == 0
assert fc(13) == 0
# List of operations
#
# mul, mul, add/cons, null
ql = P(list(Ai * vector(F17, [0, 0, 1, 0])))
qr = P(list(Ai * vector(F17, [0, 0, 1, 0])))
qm = P(list(Ai * vector(F17, [1, 1, 0, 0])))
qo = P(list(Ai * vector(F17, [-1, -1, 0, 0])))
qc = P(list(Ai * vector(F17, [0, 0, -30, 0])))
# permutation/copy constraints
# We are using the coset values here for a, b, c
# 1 4 16 13
# 2 8 15 9
# 3 12 14 5
# Applying the permutation for:
# x x^2 x^3
# x x x
# x^2 x^3 0
# then we get:
# 2 3 12 13
# 1 15 8 9
# 4 16 14 5
# We swap indices whenever there is an equality between wires:
# a1 = b1
# a2 = c1
# ...
sa = P(list(Ai * vector(F17, [2, 3, 12, 13])))
sb = P(list(Ai * vector(F17, [1, 15, 8, 9])))
sc = P(list(Ai * vector(F17, [4, 16, 14, 5])))
# Setup phase complete
# Prove phase
# Round 1
# Create vanishing polynomial which is zero for every root of unity.
# That is Z(w_1) = Z(w_2) = ... = 0
Z = x^4 - 1
assert Z(1) == 0
assert Z(4) == 0
assert Z(16) == 0
assert Z(13) == 0
# 9 random blinding values. We will use:
# 7, 4, 11, 12, 16, 2
# 14, 11, 7 (used in round 2)
# Blind our witness polynomials
# The blinding factors will disappear at the evaluation points.
a = (7*x + 4) * Z + fa
b = (11*x + 12) * Z + fb
c = (16*x + 2) * Z + fc
# During the SRS phase we created a random s point and its powers
s = 2
# So now we evaluate a, b, c with these powers of G
a_s = ZZ(a(s)) * G
b_s = ZZ(b(s)) * G
c_s = ZZ(c(s)) * G
# Round 2
# Random transcript challenges
beta = 12
gamma = 13
# Build accumulation
acc = 1
accs = []
for i in range(4):
# w_{n + j} corresponds to b(w[i])
# and w_{2n + j} is c(w[i])
accs.append(acc)
acc = acc * (
(a(w[i]) + beta * w[i] + gamma)
* (b(w[i]) + beta * k1 * w[i] + gamma)
* (c(w[i]) + beta * k2 * w[i] + gamma) /
(
(a(w[i]) + beta * sa(w[i]) + gamma)
* (b(w[i]) + beta * sb(w[i]) + gamma)
* (c(w[i]) + beta * sc(w[i]) + gamma)
))
assert accs == [1, 12, 10, 1]
del accs
acc = P(list(Ai * vector(F17, [1, 12, 10, 1])))
Zx = (14*x^2 + 11*x + 7) * Z + acc
# Evaluate z(x) at our secret point
Z_s = ZZ(Zx(s)) * G
# Round 3
alpha = 15
t1Z = a * b * qm + a * ql + b * qr + c * qo + qc
t2Z = ((a + beta * x + gamma)
* (b + beta * k1 * x + gamma)
* (c + beta * k2 * x + gamma)) * Zx * alpha
# w[1] is our first root of unity
Zw = Zx(w[1] * x)
t3Z = -((a + beta * sa + gamma)
* (b + beta * sb + gamma)
* (c + beta * sc + gamma)) * Zw * alpha
# Lagrangian polynomial which evaluates to 1 at 1
# L_1(w_1) = 1 and 0 on the other evaluation points
L = P(list(Ai * vector(F17, [1, 0, 0, 0])))
assert L(1) == 1
# w_2 = 4
assert L(4) == 0
t4Z = (Zx - 1) * L * alpha^2
tZ = t1Z + t2Z + t3Z + t4Z
# and cancel out the factor Z now
t = P(tZ / Z)
# Split t into 3 parts
# t(X) = t_lo(X) + X^n t_mid(X) + X^{2n} t_hi(X)
t_list = t.list()
t_lo = t_list[0:6]
t_mid = t_list[6:12]
t_hi = t_list[12:18]
# and create the evaluations
t_lo_s = ZZ(P(t_lo)(s)) * G
t_mid_s = ZZ(P(t_mid)(s)) * G
t_hi_s = ZZ(P(t_hi)(s)) * G
# Round 4
zeta = 5
a_ = a(zeta)
b_ = b(zeta)
c_ = c(zeta)
sa_ = sa(zeta)
sb_ = sb(zeta)
t_ = t(zeta)
zw_ = Zx(zeta * w[1])
l_ = L(zeta)
assert a_ == 8
assert b_ == 12
assert c_ == 10
assert sa_ == 0
assert sb_ == 16
assert t_ == 3
assert zw_ == 14
r1 = a_ * b_ * qm + a_ * ql + b_ * qr + c_ * qo + qc
r2 = ((a_ + beta * zeta + gamma)
* (b_ + beta * k1 * zeta + gamma)
* (c_ + beta * k2 * zeta + gamma)) * Zx * alpha
r3 = -((a_ + beta * sa_ + gamma)
* (b_ + beta * sb_ + gamma)
* beta * zw_ * sc * alpha)
r4 = Zx * l_ * alpha^2
r = r1 + r2 + r3 + r4
r_ = r(zeta)
assert r_ == 7
# Round 5
vega = 12
v1 = P(t_lo)
# Polynomial was in parts consisting of 6 powers
v2 = zeta^6 * P(t_mid)
v3 = zeta^12 * P(t_hi)
v4 = -t_
assert v4 == 14
v5 = (
vega * (r - r_)
+ vega^2 * (a - a_) + vega^3 * (b - b_) + vega^4 * (c - c_)
+ vega^5 * (sa - sa_) + vega^6 * (sb - sb_)
)
W = v1 + v2 + v3 + v4 + v5
Wz = W / (x - zeta)
# Calculate the opening proof
Wzw = (Zx - zw_) / (x - zeta * w[1])
# Compute evaluations of Wz and Wzw
Wz_s = ZZ(Wz(s)) * G
Wzw_s = ZZ(Wzw(s)) * G
# Finished the proving algo
proof = (a_s, b_s, c_s, Z_s, t_lo_s, t_mid_s, t_hi_s, Wz_s, Wzw_s,
a_, b_, c_, sa_, sb_, r_, zw_)
# Verification
qm_s = ZZ(qm(s)) * G
ql_s = ZZ(ql(s)) * G
qr_s = ZZ(qr(s)) * G
qo_s = ZZ(qo(s)) * G
qc_s = ZZ(qc(s)) * G
sa_s = ZZ(sa(s)) * G
sb_s = ZZ(sb(s)) * G
sc_s = ZZ(sc(s)) * G
# Check all the points are on the curve.
# y^2 = x^3 + 3
# ...
# Also check the scalar values are in the group for F17
# ...
# step 4: random upsilon
upsilon = 4
# step 5
Z_z = F17(zeta^4 - 1)
assert Z_z == 12
# step 6
# Calculate evaluation of L1 at zeta
L1_z = F17((zeta^4 - 1) / (4 * (zeta - 1)))
assert L1_z == 5
# step 7
# no public inputs in this example
# step 8
t_ = (r_ - (a_ + beta * sa_ + gamma)
* (b_ + beta * sb_ + gamma)
* (c_ + gamma) * zw_ * alpha
- L1_z * alpha^2) / Z_z
assert t_ == 3
# step 9
# qx_s are points, and we are multiplying them by scalars
# so convert the values to integers first
d1 = (ZZ(a_ * b_ * vega) * qm_s
+ ZZ(a_ * vega) * ql_s
+ ZZ(b_ * vega) * qr_s
+ ZZ(c_ * vega) * qo_s
+ vega * qc_s)
d2 = ZZ((a_ + beta * zeta + gamma)
* (b_ + beta * k1 * zeta + gamma)
* (c_ + beta * k2 * zeta + gamma)
* alpha * vega
+ L1_z * alpha^2 * vega
+ F17(upsilon)) * Z_s
d3 = -ZZ((a_ + beta * sa_ + gamma)
* (b_ + beta * sb_ + gamma)
* alpha * vega * beta * zw_) * sc_s
d = d1 + d2 + d3
# step 10
f = (t_lo_s + zeta^6 * t_mid_s + zeta^12 * t_hi_s
+ d
+ vega^2 * a_s + vega^3 * b_s + vega^4 * c_s
+ vega^5 * sa_s + vega^6 * sb_s)
# step 11
e = ZZ(t_ + vega * r_
+ vega^2 * a_ + vega^3 * b_ + vega^4 * c_
+ vega^5 * sa_ + vega^6 * sb_
+ upsilon * zw_) * G
# step 12
# construct points for the pairing check
x1 = Wz_s + upsilon * Wzw_s
x2 = s * G2
y1 = zeta * Wz_s + ZZ(upsilon * zeta * w[1]) * Wzw_s + f - e
y2 = G2
# do the pairing check
x1_ = E2(x1)
x2_ = E2(x2)
y1_ = E2(y1)
y2_ = E2(y2)
assert x1_.weil_pairing(x2_, 17) == y1_.weil_pairing(y2_, 17)

View File

@@ -1,325 +0,0 @@
q = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001
K = GF(q)
P.<X> = K[]
# The pallas and vesta curves are 2-adic. This means there is a large
# power of 2 subgroup within both of their fields.
# This function finds a generator for this subgroup within the field.
def get_omega():
# Slower alternative:
# generator = K.multiplicative_generator()
# Just hardcode the value here instead
generator = K(5)
assert (q - 1) % 2^32 == 0
# Root of unity
t = (q - 1) / 2^32
omega = generator**t
assert omega != 1
assert omega^(2^16) != 1
assert omega^(2^31) != 1
assert omega^(2^32) == 1
return omega
# Order of this element is 2^32
omega = get_omega()
# f(s, x, y) = sxy + (1 - s)(x + y)
var_one = K(1)
var_x = K(4)
var_y = K(6)
var_s = K(1)
var_xy = var_x * var_y
var_x_y = var_x + var_y
var_1_neg_s = var_one - var_s
var_sxy = var_s * var_xy
var_1_neg_s_x_y = var_1_neg_s * var_x_y
#var_s_neg_1 = -var_1_neg_s
var_zero = K(0)
public_value = -(var_s * (var_x * var_y) + (1 - var_s) * (var_x + var_y))
# Ql a + Qr b + Qm a b + Qo c + Qc + P == 0
# See also the file plonk-naive.sage
# x * y = xy
a1, b1, c1 = var_x, var_y, var_xy
Ql1, Qr1, Qm1, Qo1, Qc1 = 0, 0, 1, -1, 0
assert Ql1 * a1 + Qr1 * b1 + Qm1 * a1 * b1 + Qo1 * c1 + Qc1 == 0
# x + y = (x + y)
a2, b2, c2 = var_x, var_y, var_x_y
Ql2, Qr2, Qm2, Qo2, Qc2 = 1, 1, 0, -1, 0
assert Ql2 * a2 + Qr2 * b2 + Qm2 * a2 * b2 + Qo2 * c2 + Qc2 == 0
# 1 - s = (1 - s)
a3, b3, c3 = var_one, var_s, var_1_neg_s
Ql3, Qr3, Qm3, Qo3, Qc3 = 1, -1, 0, -1, 0
assert Ql3 * a3 + Qr3 * b3 + Qm3 * a3 * b3 + Qo3 * c3 + Qc3 == 0
# s * (xy) = sxy
a4, b4, c4 = var_s, var_xy, var_sxy
Ql4, Qr4, Qm4, Qo4, Qc4 = 0, 0, 1, -1, 0
assert Ql4 * a4 + Qr4 * b4 + Qm4 * a4 * b4 + Qo4 * c4 + Qc4 == 0
# (1 - s) * (x + y) = [(1 - s)(x + y)]
a5, b5, c5 = var_1_neg_s, var_x_y, var_1_neg_s_x_y
Ql5, Qr5, Qm5, Qo5, Qc5 = 0, 0, 1, -1, 0
assert Ql5 * a5 + Qr5 * b5 + Qm5 * a5 * b5 + Qo5 * c5 + Qc5 == 0
# (sxy) + [(1 - s)(x + y)] = public_value
# c6 is unused
a6, b6, c6 = var_sxy, var_1_neg_s_x_y, var_zero
Ql6, Qr6, Qm6, Qo6, Qc6 = 1, 1, 0, 0, 0
assert Ql6 * a6 + Qr6 * b6 + Qm6 * a6 * b6 + Qo6 * c6 + Qc6 + public_value == 0
# one == 1, b7 and c7 unused
a7, b7, c7 = var_one, var_zero, var_zero
Ql7, Qr7, Qm7, Qo7, Qc7 = 1, 0, 0, 0, -1
assert Ql7 * a7 + Qr7 * b7 + Qm7 * a7 * b7 + Qo7 * c7 + Qc7 == 0
# Add a last fake constraint so n is a power of 2
# This is needed since we are working with omega whose size is 2^32
# and we will create a generator from it whose order is 2^3
a8, b8, c8 = var_zero, var_zero, var_zero
Ql8, Qr8, Qm8, Qo8, Qc8 = 0, 0, 0, 0, 0
assert Ql8 * a8 + Qr8 * b8 + Qm8 * a8 * b8 + Qo8 * c8 + Qc8 == 0
a = [a1, a2, a3, a4, a5, a6, a7, a8]
b = [b1, b2, b3, b4, b5, b6, b7, b8]
c = [c1, c2, c3, c4, c5, c6, c7, c8]
Ql = [Ql1, Ql2, Ql3, Ql4, Ql5, Ql6, Ql7, Ql8]
Qr = [Qr1, Qr2, Qr3, Qr4, Qr5, Qr6, Qr7, Qr8]
Qm = [Qm1, Qm2, Qm3, Qm4, Qm5, Qm6, Qm7, Qm8]
Qo = [Qo1, Qo2, Qo3, Qo4, Qo5, Qo6, Qo7, Qo8]
Qc = [Qc1, Qc2, Qc3, Qc4, Qc5, Qc6, Qc7, Qc8]
public_values = [0, 0, 0, 0, 0, public_value, 0, 0]
n = 8
for a_i, b_i, c_i, Ql_i, Qr_i, Qm_i, Qo_i, Qc_i, public_i in \
zip(a, b, c, Ql, Qr, Qm, Qo, Qc, public_values):
assert (Ql_i * a_i + Qr_i * b_i + Qm_i * a_i * b_i + Qo_i * c_i
+ Qc_i + public_i) == 0
# 0 1 2 3 4 5 6 7
# a: x, x, 1, s, 1 - s, sxy, 1 -
#
# 8 9 10 11 12 13 14 15
# b: y, y, s, xy, x + y, (1 - s)(x + y), - -
#
# 16 17 18 19 20 21 22 23
# c: xy, x + y, 1 - s, sxy, (1 - s)(x + y), -, - -
permuted_indices_a = [1, 0, 6, 10, 18, 19, 2, 7]
permuted_indices_b = [8, 9, 3, 16, 17, 20, 14, 15]
permuted_indices_c = [11, 12, 4, 5, 13, 21, 22, 23]
eval_domain = range(0, n * 3)
witness = a + b + c
permuted_indices = permuted_indices_a + permuted_indices_b + permuted_indices_c
for i, val in enumerate(a + b + c):
assert val == witness[permuted_indices[i]]
omega = omega^(2^32 / n)
assert omega^n == 1
# Calculate the vanishing polynomial
# This is the same as (X - omega^0)(X - omega^1)...(X - omega^{n - 1})
Z_H = X^n - 1
assert Z_H(1) == 0
assert Z_H(omega^4) == 0
qL_X = P.lagrange_polynomial((omega^i, Ql_i) for i, Ql_i in enumerate(Ql))
qR_X = P.lagrange_polynomial((omega^i, Qr_i) for i, Qr_i in enumerate(Qr))
qM_X = P.lagrange_polynomial((omega^i, Qm_i) for i, Qm_i in enumerate(Qm))
qO_X = P.lagrange_polynomial((omega^i, Qo_i) for i, Qo_i in enumerate(Qo))
qC_X = P.lagrange_polynomial((omega^i, Qc_i) for i, Qc_i in enumerate(Qc))
PI_X = P.lagrange_polynomial((omega^i, public_i) for i, public_i
in enumerate(public_values))
b_1 = K.random_element()
b_2 = K.random_element()
b_3 = K.random_element()
b_4 = K.random_element()
b_5 = K.random_element()
b_6 = K.random_element()
b_7 = K.random_element()
b_8 = K.random_element()
b_9 = K.random_element()
# Round 1
# Calculate wire witness polynomials
a_X = (b_1 * X + b_2) * Z_H + \
P.lagrange_polynomial((omega^i, a_i) for i, a_i in enumerate(a))
assert a_X(omega^2) == a[2]
b_X = (b_3 * X + b_4) * Z_H + \
P.lagrange_polynomial((omega^i, b_i) for i, b_i in enumerate(b))
assert b_X(omega^5) == b[5]
c_X = (b_5 * X + b_6) * Z_H + \
P.lagrange_polynomial((omega^i, c_i) for i, c_i in enumerate(c))
assert c_X(omega^0) == c[0]
# Commit to a(X), b(X), c(X)
# ...
# Round 2
beta = K.random_element()
gamma = K.random_element()
def find_quadratic_non_residue():
k = K.random_element()
while kronecker(k, q) != -1:
k = K.random_element()
return k
# These values do not have a square root
k1 = find_quadratic_non_residue()
k2 = find_quadratic_non_residue()
assert k1 != k2
indices = ([omega^i for i in range(n)]
+ [k1 * omega^i for i in range(n)]
+ [k2 * omega^i for i in range(n)])
# Permuted indices
sigma_star = [indices[i] for i in permuted_indices]
permutation_points = [(1, 1)]
for i in range(n - 1):
x = omega^(i + 1)
y = 1
for j in range(i + 1):
y *= witness[j] + beta * omega^j + gamma
y *= witness[n + j] + beta * k1 * omega^j + gamma
y *= witness[2 * n + j] + beta * k2 * omega^j + gamma
y /= witness[j] + sigma_star[j] * beta + gamma
y /= witness[n + j] + sigma_star[n + j] * beta + gamma
y /= witness[2 * n + j] + sigma_star[2 * n + j] * beta + gamma
permutation_points.append((x, y))
z_X = (b_7 * X^2 + b_8 * X + b_9) * Z_H + \
P.lagrange_polynomial(permutation_points)
assert witness[0] == 4
assert witness[n] == 6
assert witness[2 * n] == var_xy == 24
assert sigma_star[0] == omega
assert sigma_star[n] == k1 * omega^8
assert sigma_star[2 * n] == k1 * omega^11
assert z_X(omega^0) == 1
assert ((4 + beta + gamma) * (6 + beta * k1 + gamma) * (24 + beta * k2 + gamma)
) == (z_X(omega)
* (4 + omega * beta + gamma)
* (6 + k1 * omega^8 * beta + gamma)
* (24 + k1 * omega^11 * beta + gamma))
assert witness[2] == var_one == 1
assert witness[n + 2] == var_s == 1
assert witness[2 * n + 2] == var_1_neg_s == 0
assert sigma_star[2] == omega^6
assert sigma_star[n + 2] == omega^3
assert sigma_star[2 * n + 2] == omega^4
assert (z_X(omega^2) * (1 + beta * omega^2 + gamma)
* (1 + beta * k1 * omega^2 + gamma)
* (0 + beta * k2 * omega^2 + gamma)
) == (z_X(omega^3) * (1 + omega^6 * beta + gamma)
* (1 + omega^3 * beta + gamma)
* (0 + omega^4 * beta + gamma))
# Round 3
alpha = K.random_element()
Ssigma_1 = P.lagrange_polynomial((omega^i, sigma_star[i]) for i in range(8))
Ssigma_2 = P.lagrange_polynomial((omega^i, sigma_star[n + i]) for i in range(8))
Ssigma_3 = P.lagrange_polynomial((omega^i, sigma_star[2 * n + i])
for i in range(8))
assert Ssigma_1(omega^0) == omega^1
assert Ssigma_1(omega^3) == k1 * omega^10
assert Ssigma_2(omega^2) == omega^3
assert Ssigma_3(omega^7) == k2 * omega^7 == k2 * omega^23
t_X_constraints = ((a_X * b_X * qM_X) + (a_X * qL_X) + (b_X * qR_X)
+ (c_X * qO_X) + qC_X + PI_X)
for i in range(8):
assert t_X_constraints(omega^i) == 0
t_X_permutations = ((a_X + beta * X + gamma)
* (b_X + beta * k1 * X + gamma)
* (c_X + beta * k2 * X + gamma) * z_X
# Permutated accumulator
- (a_X + beta * Ssigma_1 + gamma)
* (b_X + beta * Ssigma_2 + gamma)
* (c_X + beta * Ssigma_3 + gamma) * z_X(X * omega))
for i in range(8):
assert t_X_permutations(omega^i) == 0
L1_X = P.lagrange_polynomial([(1, 1)] + [(omega^i, 0) for i in range(1, n)])
assert L1_X(omega^0) == 1
assert L1_X(omega^2) == 0
t_X_zloops = (z_X - 1) * L1_X
assert t_X_zloops(omega^0) == 0
assert t_X_zloops(omega^2) == 0
assert t_X_zloops(omega^8) == 0
t = (t_X_constraints + t_X_permutations * alpha + t_X_zloops * alpha^2) / Z_H
# Commit to t
# ...
# Round 4
zeta = K.random_element()
a_bar = a_X(zeta)
b_bar = b_X(zeta)
c_bar = c_X(zeta)
s_bar_1 = Ssigma_1(zeta)
s_bar_2 = Ssigma_2(zeta)
z_bar_omega = z_X(zeta * omega)
# Now we provide proofs that all the above values are correct openings
# of the committed polynomials.
# And we prove that a reconstructed version of t(X) from the polynomial
# commitments of the witness and permutation polynomials equals the
# t(X) commitment.
# t(X) - r(X) = 0 where r(X) is the reconstructed polynomial.
# In order to avoid sending Ssigma_1(zeta) and z(zeta), plonk does an
# optimization using the Maller trick documented in section 4 under
# the title "Reducing the number of field elements"
# Round 5
# To reduce the proof by two elements, we construct a linearization polynomial
# which only contains 1 interminate per multiplication expression which is
# enough to prove the polynomial correctly evaluates.
r = (
# This is proving the constraint polynomial has roots at H
(a_bar * b_bar * qM_X) + (a_bar * qL_X) + (b_bar * qR_X)
+ (c_bar * qO_X) + PI_X + qC_X
+ alpha * ((a_bar + beta * zeta + gamma)
* (b_bar + beta * k1 * zeta + gamma)
* (c_bar + beta * k2 * zeta + gamma) * z_X
-
(a_bar + beta * s_bar_1 + gamma)
* (b_bar + beta * s_bar_2 + gamma)
* (c_bar + beta * Ssigma_3 + gamma) * z_bar_omega)
+ alpha^2 * (z_X - 1) * L1_X(zeta)
# t = (t_X_constraints + t_X_permutations * alpha + t_X_zloops * alpha^2)
# -------------------------------------------------------------------
# Z_H
- Z_H(zeta) * t
)
assert r(zeta) == 0
# That is basically the plonk prover. The remaining stuff are details such as
# which polynomial commitment scheme you use (kate, bulletproofs, ...)

View File

@@ -1,301 +0,0 @@
#| # Evaluation Representation of Polynomials and FFT optimizations
#| In addition to the coefficient-based representation of polynomials used
#| in babysnark.py, for performance we will also use an alternative
#| representation where the polynomial is evaluated at a fixed set of points.
#| Some operations, like multiplication and division, are significantly more
#| efficient in this form.
#| We can use FFT-based tools for efficiently converting
#| between coefficient and evaluation representation.
#|
#| This library provides:
#| - Fast fourier transform for finite fields
#| - Interpolation and evaluation using FFT
from finite_fields.finitefield import FiniteField
from finite_fields.polynomial import polynomialsOver
from finite_fields.euclidean import extendedEuclideanAlgorithm
import random
from finite_fields.numbertype import typecheck, memoize, DomainElement
from functools import reduce
import numpy as np
#| ## Fast Fourier Transform on Finite Fields
def fft_helper(a, omega, field):
"""
Given coefficients A of polynomial this method does FFT and returns
the evaluation of the polynomial at [omega^0, omega^(n-1)]
If the polynomial is a0*x^0 + a1*x^1 + ... + an*x^n then the coefficients
list is of the form [a0, a1, ... , an].
"""
n = len(a)
assert not (n & (n - 1)), "n must be a power of 2"
if n == 1:
return a
b, c = a[0::2], a[1::2]
b_bar = fft_helper(b, pow(omega, 2), field)
c_bar = fft_helper(c, pow(omega, 2), field)
a_bar = [field(1)] * (n)
for j in range(n):
k = j % (n // 2)
a_bar[j] = b_bar[k] + pow(omega, j) * c_bar[k]
return a_bar
#| ## Representing a polynomial by evaluation at fixed points
@memoize
def make_polynomial_evalrep(field, omega, n):
assert n & n - 1 == 0, "n must be a power of 2"
# Check that omega is an n'th primitive root of unity
assert type(omega) is field
omega = field(omega)
assert omega**(n) == 1
_powers = [omega**i for i in range(n)]
assert len(set(_powers)) == n
_poly_coeff = polynomialsOver(field)
class PolynomialEvalRep(object):
def __init__(self, xs, ys):
# Each element of xs must be a power of omega.
# There must be a corresponding y for every x.
if type(xs) is not tuple:
xs = tuple(xs)
if type(ys) is not tuple:
ys = tuple(ys)
assert len(xs) <= n+1
assert len(xs) == len(ys)
for x in xs:
assert x in _powers
for y in ys:
assert type(y) is field
self.evalmap = dict(zip(xs, ys))
@classmethod
def from_coeffs(cls, poly):
assert type(poly) is _poly_coeff
assert poly.degree() <= n
padded_coeffs = poly.coefficients + [field(0)] * (n - len(poly.coefficients))
ys = fft_helper(padded_coeffs, omega, field)
xs = [omega**i for i in range(n) if ys[i] != 0]
ys = [y for y in ys if y != 0]
return cls(xs, ys)
def to_coeffs(self):
# To convert back to the coefficient form, we use polynomial interpolation.
# The non-zero elements stored in self.evalmap, so we fill in the zero values
# here.
ys = [self.evalmap[x] if x in self.evalmap else field(0) for x in _powers]
coeffs = [b / field(n) for b in fft_helper(ys, 1 / omega, field)]
return _poly_coeff(coeffs)
_lagrange_cache = {}
def __call__(self, x):
if type(x) is int:
x = field(x)
assert type(x) is field
xs = _powers
def lagrange(x, xi):
# Let's cache lagrange values
if (x,xi) in PolynomialEvalRep._lagrange_cache:
return PolynomialEvalRep._lagrange_cache[(x,xi)]
mul = lambda a,b: a*b
num = reduce(mul, [x - xj for xj in xs if xj != xi], field(1))
den = reduce(mul, [xi - xj for xj in xs if xj != xi], field(1))
PolynomialEvalRep._lagrange_cache[(x,xi)] = num / den
return PolynomialEvalRep._lagrange_cache[(x,xi)]
y = field(0)
for xi, yi in self.evalmap.items():
y += yi * lagrange(x, xi)
return y
def __mul__(self, other):
# Scale by integer
if type(other) is int:
other = field(other)
if type(other) is field:
return PolynomialEvalRep(self.evalmap.keys(),
[other * y for y in self.evalmap.values()])
# Multiply another polynomial in the same representation
if type(other) is type(self):
xs = []
ys = []
for x, y in self.evalmap.items():
if x in other.evalmap:
xs.append(x)
ys.append(y * other.evalmap[x])
return PolynomialEvalRep(xs, ys)
@typecheck
def __iadd__(self, other):
# Add another polynomial to this one in place.
# This is especially efficient when the other polynomial is sparse,
# since we only need to add the non-zero elements.
for x, y in other.evalmap.items():
if x not in self.evalmap:
self.evalmap[x] = y
else:
self.evalmap[x] += y
return self
@typecheck
def __add__(self, other):
res = PolynomialEvalRep(self.evalmap.keys(), self.evalmap.values())
res += other
return res
def __sub__(self, other): return self + (-other)
def __neg__(self): return PolynomialEvalRep(self.evalmap.keys(),
[-y for y in self.evalmap.values()])
def __truediv__(self, divisor):
# Scale by integer
if type(divisor) is int:
other = field(divisor)
if type(divisor) is field:
return self * (1/divisor)
if type(divisor) is type(self):
res = PolynomialEvalRep((),())
for x, y in self.evalmap.items():
assert x in divisor.evalmap
res.evalmap[x] = y / divisor.evalmap[x]
return res
return NotImplemented
def __copy__(self):
return PolynomialEvalRep(self.evalmap.keys(), self.evalmap.values())
def __repr__(self):
return f'PolyEvalRep[{hex(omega.n)[:15]}...,{n}]({len(self.evalmap)} elements)'
@classmethod
def divideWithCoset(cls, p, t, c=field(3)):
"""
This assumes that p and t are polynomials in coefficient representation,
and that p is divisible by t.
This function is useful when t has roots at some or all of the powers of omega,
in which case we cannot just convert to evalrep and use division above
(since it would cause a divide by zero.
Instead, we evaluate p(X) at powers of (c*omega) for some constant cofactor c.
To do this efficiently, we create new polynomials, pc(X) = p(cX), tc(X) = t(cX),
and evaluate these at powers of omega. This conversion can be done efficiently
on the coefficient representation.
See also: cosetFFT in libsnark / libfqfft.
https://github.com/scipr-lab/libfqfft/blob/master/libfqfft/evaluation_domain/domains/extended_radix2_domain.tcc
"""
assert type(p) is _poly_coeff
assert type(t) is _poly_coeff
# Compute p(cX), t(cX) by multiplying coefficients
c_acc = field(1)
pc = _poly_coeff(list(p.coefficients)) # make a copy
for i in range(p.degree() + 1):
pc.coefficients[-i-1] *= c_acc
c_acc *= c
c_acc = field(1)
tc = _poly_coeff(list(t.coefficients)) # make a copy
for i in range(t.degree() + 1):
tc.coefficients[-i-1] *= c_acc
c_acc *= c
# Divide using evalrep
pc_rep = cls.from_coeffs(pc)
tc_rep = cls.from_coeffs(tc)
hc_rep = pc_rep / tc_rep
hc = hc_rep.to_coeffs()
# Compute h(X) from h(cX) by dividing coefficients
c_acc = field(1)
h = _poly_coeff(list(hc.coefficients)) # make a copy
for i in range(hc.degree() + 1):
h.coefficients[-i-1] /= c_acc
c_acc *= c
# Correctness checks
# assert pc == tc * hc
# assert p == t * h
return h
return PolynomialEvalRep
#| ## Sparse Matrix
#| In our setting, we have O(m*m) elements in the matrix, and expect the number of
#| elements to be O(m).
#| In this setting, it's appropriate to use a rowdict representation - a dense
#| array of dictionaries, one for each row, where the keys of each dictionary
#| are column indices.
class RowDictSparseMatrix():
# Only a few necessary methods are included here.
# This could be replaced with a generic sparse matrix class, such as scipy.sparse,
# but this does not work as well with custom value types like Fp
def __init__(self, m, n, zero=None):
self.m = m
self.n = n
self.shape = (m,n)
self.zero = zero
self.rowdicts = [dict() for _ in range(m)]
def __setitem__(self, key, v):
i, j = key
self.rowdicts[i][j] = v
def __getitem__(self, key):
i, j = key
return self.rowdicts[i][j] if j in self.rowdicts[i] else self.zero
def items(self):
for i in range(self.m):
for j, v in self.rowdicts[i].items():
yield (i,j), v
def dot(self, other):
if isinstance(other, np.ndarray):
assert other.dtype == 'O'
assert other.shape in ((self.n,),(self.n,1))
ret = np.empty((self.m,), dtype='O')
ret.fill(self.zero)
for i in range(self.m):
for j, v in self.rowdicts[i].items():
ret[i] += other[j] * v
return ret
def to_dense(self):
mat = np.empty((self.m, self.n), dtype='O')
mat.fill(self.zero)
for (i,j), val in self.items():
mat[i,j] = val
return mat
def __repr__(self): return repr(self.rowdicts)
#-
# Examples
if __name__ == '__main__':
import misc
Fp = FiniteField(52435875175126190479447740508185965837690552500527637822603658699938581184513,1) # (# noqa: E501)
Poly = polynomialsOver(Fp)
n = 8
omega = misc.get_omega(Fp, n)
PolyEvalRep = make_polynomial_evalrep(Fp, omega, n)
f = Poly([1,2,3,4,5])
xs = tuple([omega**i for i in range(n)])
ys = tuple(map(f, xs))
# print('xs:', xs)
# print('ys:', ys)
assert f == PolyEvalRep(xs, ys).to_coeffs()

View File

@@ -1,204 +0,0 @@
# From the Sonic paper
from finite_fields import finitefield
import numpy as np
import misc
from multipoly import Variable, MultivariatePolynomial
p = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001
fp = finitefield.IntegersModP(p)
var_one = fp(1)
var_x = fp(4)
var_y = fp(6)
var_s = fp(1)
var_xy = var_x * var_y
var_sxy = var_s * var_xy
var_1_neg_s = var_one - var_s
var_x_y = var_x + var_y
var_1_neg_s_x_y = var_1_neg_s * var_x_y
var_s_neg_1 = -var_1_neg_s
var_zero = fp(0)
public_v = var_s * (var_x * var_y) + (1 - var_s) * (var_x + var_y)
a = np.array([
var_one, var_x, var_xy, var_1_neg_s, var_s
])
b = np.array([
var_one, var_y, var_s, var_x_y, var_s_neg_1
])
c = np.array([
var_one, var_xy, var_sxy, var_1_neg_s_x_y, var_zero
])
assert len(a) == len(b)
assert len(b) == len(c)
for i, (a_i, b_i, c_i) in enumerate(zip(a, b, c), 1):
try:
assert a_i * b_i == c_i
except AssertionError:
print("Error for %i" % i)
raise
# 1 - s = -(s - 1)
u1 = np.array([0, 0, 0, 1, 0])
v1 = np.array([0, 0, 0, 0, 1])
w1 = np.array([0, 0, 0, 0, 0])
k1 = 0
assert a.dot(u1) + b.dot(v1) + c.dot(w1) == k1
# xy = xy
u2 = np.array([0, 0, 1, 0, 0])
v2 = np.array([0, 0, 0, 0, 0])
w2 = np.array([0, -1, 0, 0, 0])
k2 = 0
assert a.dot(u2) + b.dot(v2) + c.dot(w2) == k2
# s = s
u3 = np.array([0, 0, 0, 0, -1])
v3 = np.array([0, 0, 1, 0, 0])
w3 = np.array([0, 0, 0, 0, 0])
k3 = 0
assert a.dot(u3) + b.dot(v3) + c.dot(w3) == k3
# zero = 0
u4 = np.array([0, 0, 0, 0, 0])
v4 = np.array([0, 0, 0, 0, 0])
w4 = np.array([0, 0, 0, 0, 1])
k4 = 0
assert a.dot(u4) + b.dot(v4) + c.dot(w4) == k4
# 1 - s
u5 = np.array([1, 0, 0, -1, 0])
v5 = np.array([0, 0, -1, 0, 0])
w5 = np.array([0, 0, 0, 0, 0])
k5 = 0
assert a.dot(u5) + b.dot(v5) + c.dot(w5) == k5
# x + y
u6 = np.array([0, 1, 0, 0, 0])
v6 = np.array([0, 1, 0, -1, 0])
w6 = np.array([0, 0, 0, 0, 0])
k6 = 0
assert a.dot(u6) + b.dot(v6) + c.dot(w6) == k6
# Final check:
# v = s(xy) + (1 - s)(x + y)
u7 = np.array([0, 0, 0, 0, 0])
v7 = np.array([0, 0, 0, 0, 0])
w7 = np.array([0, 0, 1, 1, 0])
k7 = public_v
assert a.dot(u7) + b.dot(v7) + c.dot(w7) == k7
u = np.vstack((u1, u2, u3, u4, u5, u6, u7))
v = np.vstack((v1, v2, v3, v4, v5, v6, v7))
w = np.vstack((w1, w2, w3, w4, w5, w6, w7))
assert u.shape == v.shape
assert u.shape == w.shape
k = np.array((k1, k2, k3, k4, k5, k6, k7))
x = Variable("X", fp)
y = Variable("Y", fp)
p = MultivariatePolynomial()
for i, (a_i, b_i, c_i) in enumerate(zip(a, b, c), 1):
#print(a_i, "\t", b_i, "\t", c_i)
p += y**i * (a_i * b_i - c_i)
assert not p
p = MultivariatePolynomial()
for q, (u_q, v_q, w_q, k_q) in enumerate(zip(u, v, w, k)):
p += y**q * (a.dot(u_q) + b.dot(v_q) + c.dot(w_q) - k_q)
assert not p
n = len(a)
assert len(b) == n
assert len(c) == n
assert u.shape == (7, n)
assert v.shape == u.shape
assert w.shape == u.shape
assert k.shape == (7,)
r_x_y = MultivariatePolynomial()
s_x_y = MultivariatePolynomial()
for i, (a_i, b_i, c_i) in enumerate(zip(a, b, c), 1):
assert 1 <= i <= n
r_x_y += x**i * y**i * a_i
r_x_y += x**-i * y**-i * b_i
r_x_y += x**(-i - n) * y**(-i - n) * c_i
u_i = u.T[i - 1]
v_i = v.T[i - 1]
w_i = w.T[i - 1]
u_i_Y = MultivariatePolynomial()
v_i_Y = MultivariatePolynomial()
w_i_Y = MultivariatePolynomial()
for q, (u_q_i, v_q_i, w_q_i) in enumerate(zip(u_i, v_i, w_i), 1):
assert 1 <= q <= 7
u_i_Y += y**(q + n) * u_q_i
v_i_Y += y**(q + n) * v_q_i
w_i_Y += -y**i - y**(-i) + y**(q + n) * v_q_i
s_x_y += u_i_Y * x**-i + v_i_Y * x**i + w_i_Y * x**(i + n)
k_y = MultivariatePolynomial()
for q, k_q in enumerate(k, 1):
assert 1 <= q <= 7
k_y += y**(q + n) * k_q
r_prime_x_y = r_x_y + s_x_y
r_x_1 = r_x_y.evaluate({y.name: fp(1)})
t_x_y = r_x_1 * r_prime_x_y - k_y
t_x_y._assert_unique_terms()
const_t = t_x_y.filter([x])
print(const_t)
# Section 6, Figure 2
#
# zkP1
# 4 blinding factors since we evaluate r(X, Y) 3 times
# Blind r(X, Y)
for i in range(1, 4):
blind_c_i = misc.sample_random(fp)
r_x_y += x**(-2*n - i) * y**(-2*n - i) * blind_c_i
# Commit to r(X, Y)
# zkV1
# Send a random y
challenge_y = misc.sample_random(fp)
# zkP2
# Commit to t(X, y)
# zkV2
# Send a random z
challenge_z = misc.sample_random(fp)
# zkP3
# Evaluate a = r(z, 1)
a = r_x_y.evaluate({x.name: challenge_z, y.name: fp(1)})
# Evaluate b = r(z, y)
b = r_x_y.evaluate({x.name: challenge_z, y.name: challenge_y})
# Evaluate t = t(z, y)
t = t_x_y.evaluate({x.name: challenge_z, y.name: challenge_y})
# Evaluate s = s(z, y)
s = s_x_y.evaluate({x.name: challenge_z, y.name: challenge_y})
# zkV3
# Recalculate t from a, b and s
k = k_y.evaluate({y.name: challenge_y})
t = a * (b + s) - k
# Verify polynomial commitments

View File

@@ -1,201 +0,0 @@
import numpy as np
from groth_poly_commit import K, create_proof, verify_proof
# Just use the same finite field we put in the polynomial commitment scheme file
#p = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001
#K = FiniteField(p)
R.<x, y> = LaurentPolynomialRing(K)
var_one = K(1)
var_x = K(4)
var_y = K(6)
var_s = K(1)
var_xy = var_x * var_y
var_sxy = var_s * var_xy
var_1_neg_s = var_one - var_s
var_x_y = var_x + var_y
var_1_neg_s_x_y = var_1_neg_s * var_x_y
var_s_neg_1 = -var_1_neg_s
var_zero = K(0)
public_v = var_s * (var_x * var_y) + (1 - var_s) * (var_x + var_y)
a = np.array([
var_one, var_x, var_xy, var_1_neg_s, var_s
])
b = np.array([
var_one, var_y, var_s, var_x_y, var_s_neg_1
])
c = np.array([
var_one, var_xy, var_sxy, var_1_neg_s_x_y, var_zero
])
assert len(a) == len(b)
assert len(b) == len(c)
for i, (a_i, b_i, c_i) in enumerate(zip(a, b, c), 1):
try:
assert a_i * b_i == c_i
except AssertionError:
print("Error for %i" % i)
raise
# 1 - s = -(s - 1)
u1 = np.array([0, 0, 0, 1, 0])
v1 = np.array([0, 0, 0, 0, 1])
w1 = np.array([0, 0, 0, 0, 0])
k1 = 0
assert a.dot(u1) + b.dot(v1) + c.dot(w1) == k1
# xy = xy
u2 = np.array([0, 0, 1, 0, 0])
v2 = np.array([0, 0, 0, 0, 0])
w2 = np.array([0, -1, 0, 0, 0])
k2 = 0
assert a.dot(u2) + b.dot(v2) + c.dot(w2) == k2
# s = s
u3 = np.array([0, 0, 0, 0, -1])
v3 = np.array([0, 0, 1, 0, 0])
w3 = np.array([0, 0, 0, 0, 0])
k3 = 0
assert a.dot(u3) + b.dot(v3) + c.dot(w3) == k3
# zero = 0
u4 = np.array([0, 0, 0, 0, 0])
v4 = np.array([0, 0, 0, 0, 0])
w4 = np.array([0, 0, 0, 0, 1])
k4 = 0
assert a.dot(u4) + b.dot(v4) + c.dot(w4) == k4
# 1 - s
u5 = np.array([1, 0, 0, -1, 0])
v5 = np.array([0, 0, -1, 0, 0])
w5 = np.array([0, 0, 0, 0, 0])
k5 = 0
assert a.dot(u5) + b.dot(v5) + c.dot(w5) == k5
# x + y
u6 = np.array([0, 1, 0, 0, 0])
v6 = np.array([0, 1, 0, -1, 0])
w6 = np.array([0, 0, 0, 0, 0])
k6 = 0
assert a.dot(u6) + b.dot(v6) + c.dot(w6) == k6
# Final check:
# v = s(xy) + (1 - s)(x + y)
u7 = np.array([0, 0, 0, 0, 0])
v7 = np.array([0, 0, 0, 0, 0])
w7 = np.array([0, 0, 1, 1, 0])
k7 = public_v
assert a.dot(u7) + b.dot(v7) + c.dot(w7) == k7
u = np.vstack((u1, u2, u3, u4, u5, u6, u7))
v = np.vstack((v1, v2, v3, v4, v5, v6, v7))
w = np.vstack((w1, w2, w3, w4, w5, w6, w7))
assert u.shape == v.shape
assert u.shape == w.shape
k = np.array((k1, k2, k3, k4, k5, k6, k7))
p = K(0)
for i, (a_i, b_i, c_i) in enumerate(zip(a, b, c), 1):
#print(a_i, "\t", b_i, "\t", c_i)
p += y**i * (a_i * b_i - c_i)
print(p)
p = K(0)
for q, (u_q, v_q, w_q, k_q) in enumerate(zip(u, v, w, k)):
p += y**q * (a.dot(u_q) + b.dot(v_q) + c.dot(w_q) - k_q)
print(p)
n = len(a)
assert len(b) == n
assert len(c) == n
assert u.shape == (7, n)
assert v.shape == u.shape
assert w.shape == u.shape
assert k.shape == (7,)
r_x_y = 0
s_x_y = 0
for i, (a_i, b_i, c_i) in enumerate(zip(a, b, c), 1):
assert 1 <= i <= n
r_x_y += x**i * y**i * a_i
r_x_y += x**-i * y**-i * b_i
r_x_y += x**(-i - n) * y**(-i - n) * c_i
u_i = u.T[i - 1]
v_i = v.T[i - 1]
w_i = w.T[i - 1]
u_i_Y = 0
v_i_Y = 0
w_i_Y = 0
for q, (u_q_i, v_q_i, w_q_i) in enumerate(zip(u_i, v_i, w_i), 1):
assert 1 <= q <= 7
u_i_Y += y**(q + n) * u_q_i
v_i_Y += y**(q + n) * v_q_i
w_i_Y += -y**i - y**(-i) + y**(q + n) * w_q_i
s_x_y += u_i_Y * x**-i + v_i_Y * x**i + w_i_Y * x**(i + n)
k_y = 0
for q, k_q in enumerate(k, 1):
assert 1 <= q <= 7
k_y += y**(q + n) * k_q
# Section 6, Figure 2
#
# zkP1
# 4 blinding factors since we evaluate r(X, Y) 3 times
# Blind r(X, Y)
#for i in range(1, 4 + 1):
# blind_c_i = K.random_element()
# r_x_y += x**(-2*n - i) * y**(-2*n - i) * blind_c_i
# Commit to r(X, Y)
r_prime_x_y = r_x_y + s_x_y
r_x_1 = r_x_y(y=K(1))
t_x_y = r_x_1 * r_prime_x_y - k_y
print(t_x_y.constant_coefficient())
# zkV1
# Send a random y
challenge_y = K.random_element()
# zkP2
# Commit to t(X, y)
t_x = t_x_y(y=challenge_y)
t_x = t_x.univariate_polynomial()
print(t_x.constant_coefficient())
# zkV2
# Send a random z
challenge_z = K.random_element()
# zkP3
# Evaluate a = r(z, 1)
a = r_x_y(x=challenge_z, y=K(1))
# Evaluate b = r(z, y)
b = r_x_y(x=challenge_z, y=challenge_y)
# Evaluate t = t(z, y)
t = t_x_y(x=challenge_z, y=challenge_y)
# Evaluate s = s(z, y)
s = s_x_y(x=challenge_z, y=challenge_y)
# zkV3
# Recalculate t from a, b and s
k = k_y(y=challenge_y)
t_new = a * (b + s) - k
assert t_new == t
# Verify polynomial commitments

View File

@@ -1,116 +0,0 @@
import random
import misc
import pasta
from polynomial_evalrep import make_polynomial_evalrep
n = 8
omega_base = misc.get_omega(pasta.fp, 2**32, seed=0)
assert misc.is_power_of_two(8)
omega = omega_base ** (2 ** 32 // n)
# Order of omega is n
assert omega ** n == 1
# Compute complete roots of this group
ROOTS = [omega ** i for i in range(n)]
PolyEvalRep = make_polynomial_evalrep(pasta.fp, omega, n)
import numpy as np
from tabulate import tabulate
# Wires
a = ["x", "v1", "v2", "1", "1", "v3", "e1", "e2"]
b = ["x", "x", "x", "5", "35", "5", "e3", "e4"]
c = ["v1", "v2", "v3", "5", "35", "35", "e5", "e6"]
wires = a + b + c
# Gates
# La + Rb + Oc + Mab + C = 0
add = np.array([1, 1, 0, -1, 0])
mul = np.array([0, 0, 1, -1, 0])
const5 = np.array([0, 1, 0, 0, -5])
public_input = np.array([0, 1, 0, 0, 0])
empty = np.array([0, 0, 0, 0, 0])
gates_matrix = np.array(
[mul, mul, add, const5, public_input, add, empty, empty])
print("Wires:")
print(tabulate([["a ="] + a, ["b ="] + b, ["c ="] + c]))
print()
print("Gates:")
print(gates_matrix)
print()
# The index of the public input in the gates_matrix
# We specify its position and its value
public_input_values = [(4, 35)]
def permute_indices(wires):
size = len(wires)
permutation = [i + 1 for i in range(size)]
for i in range(size):
for j in range(i + 1, size):
if wires[i] == wires[j]:
permutation[i], permutation[j] = permutation[j], permutation[i]
break
return permutation
permutation = permute_indices(wires)
table = [
["Wires"] + wires,
["Indices"] + list(i + 1 for i in range(len(wires))),
["Permutations"] + permutation
]
print(tabulate(table))
print()
import misc
from pasta import fp
def setup(wires, gates_matrix):
# Section 8.1
# The selector polynomials that define the circuit's arithmetisation
gates_matrix = gates_matrix.transpose()
ql = PolyEvalRep(ROOTS, [fp(i) for i in gates_matrix[0]])
qr = PolyEvalRep(ROOTS, [fp(i) for i in gates_matrix[1]])
qm = PolyEvalRep(ROOTS, [fp(i) for i in gates_matrix[2]])
qo = PolyEvalRep(ROOTS, [fp(i) for i in gates_matrix[3]])
qc = PolyEvalRep(ROOTS, [fp(i) for i in gates_matrix[4]])
selector_polys = [ql, qr, qm, qo, qc]
public_input = [fp(0) for i in range(len(ROOTS))]
for (index, value) in public_input_values:
# This is negative because the value is added to
# the output of the const selector poly:
# La + Rb + Oc + Mab + (C + PI) = 0
public_input[index] = fp(-value)
public_input_poly = PolyEvalRep(ROOTS, public_input)
# Identity permutations applied to a, b, c
# Ideally H, k_1 H, k_2 H are distinct cosets of H
# Here we just sample k and assume it's high-order
# Random high order k to form distinct cosets
k = misc.sample_random(fp)
id_domain_a = ROOTS
id_domain_b = [k * root for root in ROOTS]
id_domain_c = [k**2 * root for root in ROOTS]
id_domain = id_domain_a + id_domain_b + id_domain_c
# Intermediate step where we permute the positions of the domain
# generated above
permuted_domain = [id_domain[i - 1] for i in permutation]
permuted_domain_a = permuted_domain[:n]
permuted_domain_b = permuted_domain[n:2 * n]
permuted_domain_c = permuted_domain[2*n:3 * n]
# The copy permuation applied to a, b, c
# Returns the permuted index value (corresponding root of unity coset)
# when evaluated on the domain.
ssigma_1 = PolyEvalRep(ROOTS, permuted_domain_a)
ssigma_2 = PolyEvalRep(ROOTS, permuted_domain_b)
ssigma_3 = PolyEvalRep(ROOTS, permuted_domain_c)
copy_permutes = [ssigma_1, ssigma_2, ssigma_3]
setup(wires, gates_matrix)

View File

@@ -1,80 +0,0 @@
from finite_fields.modp import IntegersModP
q = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001
modq = IntegersModP(q)
a = modq(-1)
print("a:", hex(a.n))
d = -(modq(10240)/modq(10241))
params = (a, d)
def is_jubjub(params, x, y):
a, d = params
return a * x**2 + y**2 == 1 + d * x**2 * y**2
def add(params, point_1, point_2):
# From here: https://z.cash/technology/jubjub/
a, d = params
x1, y1 = point_1
x2, y2 = point_2
x3 = (x1 * y2 + y1 * x2) / (1 + d * x1 * x2 * y1 * y2)
y3 = (y1 * y2 + x1 * x2) / (1 - d * x1 * x2 * y1 * y2)
return (x3, y3)
def fake_zk_add(params, point_1, point_2):
# From here: https://z.cash/technology/jubjub/
a, d = params
x1, y1 = point_1
x2, y2 = point_2
# Compute U = (u1 + v1) * (v2 - EDWARDS_A*u2)
# = (u1 + v1) * (u2 + v2)
U = (x1 + y1) * (x2 + y2)
assert (x1 + y1) * (x2 + y2) == U
# Compute A = v2 * u1
A = y2 * x1
# Compute B = u2 * v1
B = x2 * y1
# Compute C = d*A*B
C = d * A * B
assert (d * A) * (B) == C
# Compute u3 = (A + B) / (1 + C)
# NOTE: make sure we check for (1 + C) has an inverse
u3 = (A + B) / (1 + C)
assert (1 + C) * (u3) == (A + B)
# Compute v3 = (U - A - B) / (1 - C)
# We will also need to check inverse here as well.
v3 = (U - A - B) / (1 - C)
assert (1 - C) * (v3) == (U - A - B)
return u3, v3
x = 0x15a36d1f0f390d8852a35a8c1908dd87a361ee3fd48fdf77b9819dc82d90607e
y = 0x015d8c7f5b43fe33f7891142c001d9251f3abeeb98fad3e87b0dc53c4ebf1891
x3, y3 = add(params, (x, y), (x, y))
print(hex(x3.n), hex(y3.n))
u3, v3 = fake_zk_add(params, (x, y), (x, y))
print(hex(u3.n), hex(v3.n))
print(is_jubjub(params, x, y))
print(is_jubjub(params, x3, y3))
print()
print("Identity (0, 1) is jubjub?", is_jubjub(params, 0, 1))
print("Torsion (0, -1) is jubjub?", is_jubjub(params, 0, -1))
double_torsion = add(params, (0, -1), (0, -1))
print("Double torsion is:", hex(double_torsion[0].n), hex(double_torsion[1].n))
dbl_ident = add(params, (0, 1), (0, 1))
print("Double identity is:", hex(dbl_ident[0].n), hex(dbl_ident[1].n))

View File

@@ -1,30 +0,0 @@
from finite_fields.modp import IntegersModP
q = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001
modq = IntegersModP(q)
a = modq(-1)
print("0x%x" % a.n)
print("\n")
two = modq(2)
inv2 = modq(2).inverse()
print("Inverse of 2 = 0x%x" % inv2.n)
print((two * inv2))
# This is from bellman
inv2_bellman = 0x39f6d3a994cebea4199cec0404d0ec02a9ded2017fff2dff7fffffff80000001
assert inv2.n == inv2_bellman
assert (2 * inv2.n) % q == 1
# Futures contract calculation
multiplier = modq(1)
quantity = modq(100)
entry_price = modq(10000)
exit_price = modq(15000)
initial_margin = multiplier * quantity
print("initial margin =", initial_margin)
price_return = exit_price * entry_price.inverse()
print("R =", price_return)
pnl = initial_margin - (initial_margin * exit_price) * entry_price.inverse()
print("PNL =", pnl)

View File

@@ -1,159 +0,0 @@
import asyncio
from tabulate import tabulate
from copy import deepcopy
import re
import os
import sys
import time
lock = asyncio.Lock()
logs_path = "/tmp/darkfi/"
node_info = {
}
ping_times = {
}
def debug(line):
#print(line)
pass
def process(info, line):
regex_listen = re.compile(
".* Listening on (\d+[.]\d+[.]\d+[.]\d+:\d+)")
regex_inbound_connect = re.compile(
".* Connected inbound \[(\d+[.]\d+[.]\d+[.]\d+:\d+)\]")
regex_outbound_slots = re.compile(
".* Starting (\d+) outbound connection slots.")
regex_outbound_connect = re.compile(
".* #(\d+) connected to outbound \[(\d+[.]\d+[.]\d+[.]\d+:\d+)\]")
regex_channel_disconnected = re.compile(
".* Channel (\d+[.]\d+[.]\d+[.]\d+:\d+) disconnected")
regex_pong_recv = re.compile(
".* Received Pong message (\d+)ms from \[(\d+[.]\d+[.]\d+[.]\d+:\d+)\]")
if "net: P2p::start() [BEGIN]" in line:
info["status"] = "p2p-start"
elif "net: SeedSession::start() [START]" in line:
info["status"] = "seed-start"
elif "net: SeedSession::start() [END]" in line:
info["status"] = "seed-done"
elif "net: P2p::start() [END]" in line:
info["status"] = "p2p-done"
elif "net: P2p::run() [BEGIN]" in line:
info["status"] = "p2p-run"
elif "Not configured for accepting incoming connections." in line:
info["inbounds"] = ["Disabled"]
elif (match := regex_listen.match(line)) is not None:
address = match.group(1)
info["listen"] = address
elif (match := regex_inbound_connect.match(line)) is not None:
address = match.group(1)
info["inbounds"].append(address)
elif (match := regex_outbound_slots.match(line)) is not None:
slots = match.group(1)
info["outbounds"] = ["None" for _ in range(int(slots))]
elif (match := regex_outbound_connect.match(line)) is not None:
slot = match.group(1)
address = match.group(2)
info["outbounds"][int(slot)] = address
elif (match := regex_channel_disconnected.match(line)) is not None:
address = match.group(1)
try:
info["inbounds"].remove(address)
except ValueError:
pass
try:
idx = info["outbounds"].index(address)
info["outbounds"][idx] = "None"
except ValueError:
pass
elif (match := regex_pong_recv.match(line)) is not None:
ping_time = match.group(1)
address = match.group(2)
ping_times[address] = ping_time
async def scanner(filename):
global table_data
async with lock:
node_info[filename] = {
"status": "none",
"inbounds": [],
"outbounds": [],
}
info = node_info[filename]
with open(logs_path + filename) as fileh:
while True:
line = fileh.readline()
if line:
debug("R: " + filename + ": " + line[:-1])
async with lock:
process(info, line)
else:
await asyncio.sleep(0.5)
def clear_lines(n):
for i in range(n):
sys.stdout.write('\033[F')
def get_ping(addr):
ping_time = "none"
if addr in ping_times:
ping_time = str(ping_times[addr]) + " ms"
return ping_time
def table_format(ninfo):
table_data = []
for filename, info in ninfo.items():
table_data.append([filename, "", ""])
table_data.append(["", "status", info["status"]])
if "listen" in info:
table_data.append(["", "listen", info["listen"]])
inbounds = info["inbounds"]
if inbounds:
table_data.append(["", "inbounds", inbounds[0],
get_ping(inbounds[0])])
for inbound in inbounds[1:]:
table_data.append(["", "", inbound, get_ping(inbound)])
outbounds = info["outbounds"]
if outbounds:
table_data.append(["", "outbounds", outbounds[0],
get_ping(outbounds[0])])
for outbound in outbounds[1:]:
table_data.append(["", "", outbound, get_ping(outbound)])
headers = ["Name", "Attribute", "Value", "Ping Times"]
return headers, table_data
async def refresh_table(tick=1):
for filename in os.listdir(logs_path):
asyncio.create_task(scanner(filename))
previous_lines = 0
while True:
clear_lines(previous_lines)
async with lock:
ninfo = deepcopy(node_info)
headers, table_data = table_format(ninfo)
lines = tabulate(table_data, headers=headers).split("\n")
debug("-------------------")
for line in lines:
print('\x1b[2K\r', end="")
print(line)
previous_lines = len(lines)
await asyncio.sleep(1)
asyncio.run(refresh_table())

View File

@@ -1,2 +0,0 @@
#!/bin/bash
python scripts/parser.py proofs/sapling3.prf | rustfmt > proofs/sapling3.rs

View File

@@ -1,4 +0,0 @@
#!/bin/bash -x
python scripts/pism.py proofs/simple.pism | rustfmt > src/simple_circuit.rs
cargo run --release --bin simple

View File

@@ -1,5 +0,0 @@
# Dark Client
$ python3 -m venv env
$ source env/bin/activate
$ pip install -r requirements.txt

View File

@@ -1,89 +0,0 @@
#!/usr/bin/env python
from util import arg_parser
import aiohttp
import asyncio
class DarkClient:
# TODO: generate random ID (4 byte unsigned int) (rand range 0 - max size
# uint32
def __init__(self, client_session):
self.url = "http://localhost:8000/"
self.client_session = client_session
self.payload = {
"method": [],
"params": [],
"jsonrpc": [],
"id": [],
}
async def key_gen(self, payload):
payload['method'] = "key_gen"
payload['jsonrpc'] = "2.0"
payload['id'] = "0"
key = await self.__request(payload)
print(key)
async def get_info(self, payload):
payload['method'] = "get_info"
payload['jsonrpc'] = "2.0"
payload['id'] = "0"
info = await self.__request(payload)
print(info)
async def stop(self, payload):
payload['method'] = "stop"
payload['jsonrpc'] = "2.0"
payload['id'] = "0"
stop = await self.__request(payload)
print(stop)
async def say_hello(self, payload):
payload['method'] = "say_hello"
payload['jsonrpc'] = "2.0"
payload['id'] = "0"
hello = await self.__request(payload)
print(hello)
async def create_wallet(self, payload):
payload['method'] = "create_wallet"
payload['jsonrpc'] = "2.0"
payload['id'] = "0"
wallet = await self.__request(payload)
print(wallet)
async def create_cashier_wallet(self, payload):
payload['method'] = "create_cashier_wallet"
payload['jsonrpc'] = "2.0"
payload['id'] = "0"
wallet = await self.__request(payload)
print(wallet)
async def test_wallet(self, payload):
payload['method'] = "test_wallet"
payload['jsonrpc'] = "2.0"
payload['id'] = "0"
test = await self.__request(payload)
print(test)
async def __request(self, payload):
async with self.client_session.post(self.url, json=payload) as response:
resp = await response.text()
print(resp)
async def main():
try:
async with aiohttp.ClientSession() as session:
client = DarkClient(session)
await arg_parser(client)
except aiohttp.ClientConnectorError as err:
print('CONNECTION ERROR:', str(err))
except Exception as err:
print("ERROR: ", str(err))
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())

View File

@@ -1,14 +0,0 @@
aiodns==3.0.0
aiohttp==3.7.4.post0
async-timeout==3.0.1
attrs==21.2.0
brotlipy==0.7.0
cchardet==2.1.7
cffi==1.14.5
chardet==4.0.0
idna==3.2
multidict==5.1.0
pycares==4.0.0
pycparser==2.20
typing-extensions==3.10.0.0
yarl==1.6.3

View File

@@ -1,53 +0,0 @@
import argparse
async def arg_parser(client):
parser = argparse.ArgumentParser(
prog='drk',
usage='%(prog)s [commands]',
description="""DarkFi wallet command-line tool"""
)
parser.add_argument('-c', '--cashier', action='store_true', help='Create a cashier wallet')
parser.add_argument('-w', '--wallet', action='store_true', help='Create a new wallet')
parser.add_argument('-k', '--key', action='store_true', help='Test key')
parser.add_argument('-i', '--info', action='store_true', help='Request info from daemon')
parser.add_argument('-hi', '--hello', action='store_true', help='Test hello')
parser.add_argument("-s", "--stop", action='store_true', help="Send a stop signal to the daemon")
parser.add_argument("-t", "--test", action='store_true', help="Test writing to the wallet")
try:
args = parser.parse_args()
if args.key:
print("Attemping to generate a create key pair...")
await client.key_gen(client.payload)
if args.wallet:
print("Attemping to create a wallet...")
await client.create_wallet(client.payload)
if args.info:
print("Info was entered")
await client.get_info(client.payload)
print("Requesting daemon info...")
if args.stop:
print("Stop was entered")
await client.stop(client.payload)
print("Sending a stop signal...")
if args.hello:
print("Hello was entered")
await client.say_hello(client.payload)
if args.cashier:
print("Attempting to generate a cashier wallet...")
await client.create_cashier_wallet(client.payload)
if args.test:
print("Testing wallet write")
await client.test_wallet(client.payload)
except Exception:
raise

View File

@@ -1,5 +0,0 @@
#!/bin/bash -x
python scripts/preprocess.py proofs/bits.psm > /tmp/bits.psm
python scripts/vm.py --rust /tmp/bits.psm > src/bits_contract.rs
cargo run --release --bin bits

View File

@@ -1,5 +0,0 @@
#!/bin/bash -x
python scripts/preprocess.py proofs/mimc.psm > /tmp/mimc.psm
python scripts/vm.py --rust /tmp/mimc.psm > src/zkmimc_contract.rs
cargo run --release --bin zkmimc

View File

@@ -1,5 +0,0 @@
#!/bin/bash -x
python scripts/preprocess.py proofs/mint2.psm > /tmp/mint2.psm || exit $?
python scripts/vm.py --rust /tmp/mint2.psm > src/mint2_contract.rs || exit $?
cargo run --release --bin mint2

View File

@@ -1,4 +0,0 @@
#!/bin/bash -x
python scripts/preprocess.py proofs/mint.pism > /tmp/mint.pism
python scripts/pism.py /tmp/mint.pism proofs/mint.aux | rustfmt > src/mint_contract.rs
cargo run --release --bin mint

View File

@@ -1,4 +0,0 @@
#!/bin/bash -x
python scripts/preprocess.py proofs/spend.pism > /tmp/spend.pism
python scripts/pism.py /tmp/spend.pism proofs/mint.aux | rustfmt > src/spend_contract.rs
cargo run --release --bin spend

View File

@@ -1,5 +0,0 @@
#!/bin/bash -x
python scripts/preprocess.py proofs/jubjub.pism > /tmp/jubjub.pism
python scripts/vm.py --rust /tmp/jubjub.pism > src/vm_load.rs
cargo run --release --bin vmtest

View File

@@ -1,835 +0,0 @@
import lark
import pprint
import re
import sys
class LineDesc:
def __init__(self, level, text, lineno):
self.level = level
self.text = text
self.lineno = lineno
assert self.text[0] != ' '
def __repr__(self):
return "<%s:'%s'>" % (self.level, self.text)
def clean_line(line):
lead_spaces = len(line) - len(line.lstrip(" "))
level = lead_spaces / 4
# Remove leading spaces
if line.strip(" ") == "":
return None
line = line.lstrip(" ")
# Remove all comments
line = re.sub('#.*$', '', line).strip()
if not line:
return None
return level, line
def parse(text):
lines = text.split("\n")
linedescs = []
# These are to join open parenthesis
current_line = ""
paren_level = 0
for lineno, line in enumerate(lines):
if (lineinfo := clean_line(line)) is None:
continue
level, line = lineinfo
for c in line:
if c == "(":
paren_level += 1
elif c == ")":
paren_level -= 1
#print(level, paren_level, current_line)
if paren_level < 0:
print("error: too many closing paren )", file=sys.stderr)
print("line:", lineno)
return
if current_line:
current_line += " " + line
else:
current_line = line
if paren_level > 0:
continue
#print(level, current_line)
ldesc = LineDesc(level, current_line, lineno)
linedescs.append(ldesc)
current_line = ""
if paren_level > 0:
print("error: missing closing paren )", file=sys.stderr)
return None
return linedescs
def section(linedescs):
sections = []
current_section = None
for desc in linedescs:
if desc.level == 0:
if current_section:
sections.append(current_section)
current_section = [desc]
continue
current_section.append(desc)
sections.append(current_section)
return sections
def classify(sections):
consts = []
funcs = []
contracts = []
for section in sections:
assert len(section)
if section[0].text == "const:":
consts.append(section)
elif section[0].text.startswith("def"):
funcs.append(section)
elif section[0].text.startswith("contract"):
contracts.append(section)
return consts, funcs, contracts
def tokenize_const(text):
parser = lark.Lark(r"""
value_map: name ":" type_def
name: NAME
?type_def: point
| blake2s_personalization
| pedersen_personalization
| list
point: "Point"
blake2s_personalization: "Blake2sPersonalization"
pedersen_personalization: "PedersenPersonalization"
list: "list<" type_def ">"
%import common.CNAME -> NAME
%import common.WS
%ignore WS
""", start="value_map")
return parser.parse(text)
class ConstTransformer(lark.Transformer):
def name(self, name):
return str(name[0])
def point(self, _):
return "Point"
def blake2s_personalization(self, _):
return "Blake2sPersonalization"
def pedersen_personalization(self, _):
return "PedersenPersonalization"
value_map = tuple
list = list
def read_consts(consts):
consts_map = {}
for subsection in consts:
assert subsection[0].text == "const:"
for ldesc in subsection[1:]:
tree = tokenize_const(ldesc.text)
tokens = ConstTransformer().transform(tree)
#print(tokens)
name, typedesc = tokens
consts_map[name] = typedesc
#pprint.pprint(consts_map)
return consts_map
class FuncDefTransformer(lark.Transformer):
def func_name(self, name):
return str(name[0])
def param(self, obj):
return tuple(obj)
def param_name(self, name):
return str(name[0])
def u64(self, _):
return "U64"
def scalar(self, _):
return "Scalar"
def point(self, _):
return "Point"
def binary(self, _):
return "Binary"
def type(self, obj):
return obj[0]
func_def = list
params = list
type_list = list
def parse_func_def(text):
parser = lark.Lark(r"""
func_def: "def" func_name "(" params+ ")" "->" type_list ":"
func_name: NAME
params: param ("," param)*
type_list: type
| "(" type ("," type)* ")"
param: param_name ":" type
param_name: NAME
type: u64 | scalar | point | binary
u64: "U64"
scalar: "Scalar"
point: "Point"
binary: "Binary"
%import common.CNAME -> NAME
%import common.WS
%ignore WS
""", start="func_def")
tree = parser.parse(text)
tokens = FuncDefTransformer().transform(tree)
assert len(tokens) == 3
return tokens
def compile_func_header(func_def):
func_name, params, retvals = func_def
#print("Function:", func_name)
#print("Params:", params)
#print("Return values:", retvals)
#print()
param_str = ""
for param, type in params:
if param_str:
param_str += ", "
param_str += param + ": Option<"
if type == "U64":
param_str += "u64"
elif type == "Scalar":
param_str += "jubjub::Fr"
elif type == "Point":
param_str += "jubjub::SubgroupPoint"
else:
print("error: unsupported param type", file=sys.stderr)
print("line:", line.text, "line:", line.lineno)
return None
param_str += ">"
converted_retvals = []
for type in retvals:
if type == "Binary":
converted_retvals.append("boolean::Boolean")
else:
print("error: unsupported return type", file=sys.stderr)
print("line:", line.text, "line:", line.lineno)
return None
retvals = converted_retvals
if len(retvals) == 1:
retstr = retvals[0]
else:
retstr = "(" + ", ".join(retvals) + ")"
header = r"""fn %s<CS>(
mut cs: CS,
%s
) -> Result<%s, SynthesisError>
where
CS: ConstraintSystem<bls12_381::Scalar>,
{
""" % (func_name, param_str, retstr)
return header
def as_expr(line, stack, consts, expr, code):
var_from, type_to = expr.children
if var_from not in stack:
print("error: variable from not in stack frame:", var_from,
file=sys.stderr)
print("line:", line.text, "line:", line.lineno)
return None
type_from = stack[var_from]
if type_from == "U64" and type_to == "Binary":
code += "boolean::u64_into_boolean_vec_le(" + \
"cs.namespace(|| \"" + line.text + "\"), " + var_from + \
")?;"
elif type_from == "Scalar" and type_to == "Binary":
code += "boolean::field_into_boolean_vec_le(" + \
"cs.namespace(|| \"" + line.text + "\"), " + var_from + \
")?;"
else:
print("error: unknown type conversion!", file=sys.stderr)
print("line:", line.text, "line:", line.lineno)
return None
#print(var_from, type_from, type_to)
return code, type_to
def mul_expr(line, stack, consts, expr, code):
var_a, var_b = expr.children
#print("MUL", var_a, var_b)
if var_b not in consts:
print("error: unknown base!", file=sys.stderr)
print("line:", line.text, "line:", line.lineno)
return None
base_type = consts[var_b]
if base_type != "Point":
print("error: unknown base type!", file=sys.stderr)
print("line:", line.text, "line:", line.lineno)
return None
code += "ecc::fixed_base_multiplication(" + \
"cs.namespace(|| \"" + line.text + "\"), &" + var_b + \
", &" + var_a + ")?;"
return code, base_type
def add_expr(line, stack, consts, expr, code):
var_a, var_b = expr.children
if var_a not in stack or var_b not in stack:
print("error: missing stack item!", file=sys.stderr)
print("line:", line.text, "line:", line.lineno)
return None
result_type = stack[var_a]
if stack[var_b] != result_type:
print("error: non matching items for addition!", file=sys.stderr)
print("line:", line.text, "line:", line.lineno)
return None
code += var_a + ".add(cs.namespace(|| \"" + line.text \
+ "\"), &" + var_b + ")?;"
return (code, result_type)
def compile_let(line, stack, consts, statement):
is_mutable = False
if statement[0] == "mut":
is_mutable = True
statement = statement[1:]
variable_name, variable_type = statement[0], statement[1]
expr = statement[2]
#print("LET", is_mutable, variable_name, variable_type)
#print(" ", expr)
code = "let " + ("mut " if is_mutable else "") + variable_name + " = "
if expr.data == "as_expr":
ceval = as_expr(line, stack, consts, expr, code)
elif expr.data == "mul_expr":
ceval = mul_expr(line, stack, consts, expr, code)
elif expr.data == "add_expr":
ceval = add_expr(line, stack, consts, expr, code)
if ceval is None:
return None
code, type_to = ceval
if variable_type != type_to:
print("error: sub expr does not evaluate to correct type",
file=sys.stderr)
print("line:", line.text, "line:", line.lineno)
return None
stack[variable_name] = variable_type
return code
def interpret_func(func, consts):
func_def = parse_func_def(func[0].text)
header = compile_func_header(func_def)
if header is None:
return
subroutine = header
indent = " " * 4
stack = dict(func_def[1])
emitted_types = []
for line in func[1:]:
statement_type, statement = interpret_func_line(line.text, stack, consts)
if statement_type == "let":
code = compile_let(line, stack, consts, statement)
if code is None:
return
subroutine += indent + code + "\n"
elif statement_type == "return":
for var in statement:
if var not in stack:
print("error: missing variable in stack!", file=sys.stderr)
print("line:", line.text, "line:", line.lineno)
return None
if len(statement) == 1:
code = "Ok(" + statement[0] + ")"
else:
code = "Ok(" + ",".join(statement) + ")"
subroutine += indent + code + "\n"
elif statement_type == "emit":
assert len(statement) == 1
variable = statement[0]
if variable not in stack:
print("error: missing variable in stack!", file=sys.stderr)
print("line:", line.text, "line:", line.lineno)
return None
variable_type = stack[variable]
if variable_type == "Point":
code = variable + ".inputize(cs.namespace(|| \"" + \
line.text + "\"))?;"
else:
print("error: unable to inputize type!", file=sys.stderr)
print("line:", line.text, "line:", line.lineno)
return None
emitted_types.append(variable_type)
subroutine += indent + code + "\n"
subroutine += "}\n\n"
return subroutine, emitted_types, func_def
class CodeLineTransformer(lark.Transformer):
def variable_name(self, name):
return str(name[0])
def let_statement(self, obj):
return ("let", obj)
def return_statement(self, obj):
return ("return", obj)
def emit_statement(self, obj):
return ("emit", obj)
def point(self, _):
return "Point"
def scalar(self, _):
return "Scalar"
def binary(self, _):
return "Binary"
def u64(self, _):
return "U64"
def type(self, typename):
return str(typename[0])
def mutable(self, _):
return "mut"
statement = list
def interpret_func_line(text, stack, consts):
parser = lark.Lark(r"""
statement: let_statement
| return_statement
| emit_statement
let_statement: "let" [mutable] variable_name ":" type "=" expr
mutable: "mut"
?expr: as_expr
| mul_expr
| add_expr
as_expr: variable_name "as" type
mul_expr: variable_name "*" variable_name
add_expr: variable_name "+" variable_name
return_statement: "return" variable_name
| "return" variable_tuple
variable_tuple: "(" variable_name ("," variable_name)* ")"
emit_statement: "emit" variable_name
variable_name: NAME
type: u64 | scalar | point | binary
u64: "U64"
scalar: "Scalar"
point: "Point"
binary: "Binary"
%import common.CNAME -> NAME
%import common.WS
%ignore WS
""", start="statement")
tree = parser.parse(text)
tokens = CodeLineTransformer().transform(tree)[0]
return tokens
class ContractDefTransformer(lark.Transformer):
def contract_name(self, name):
return str(name[0])
def param(self, obj):
return tuple(obj)
def param_name(self, name):
return str(name[0])
def u64(self, _):
return "U64"
def scalar(self, _):
return "Scalar"
def point(self, _):
return "Point"
def binary(self, _):
return "Binary"
def type(self, obj):
return obj[0]
contract_def = list
params = list
type_list = list
def parse_contract_def(text):
parser = lark.Lark(r"""
contract_def: "contract" contract_name "(" params+ ")" "->" type_list ":"
contract_name: NAME
params: param ("," param)*
type_list: type
| "(" type ("," type)* ")"
param: param_name ":" type
param_name: NAME
type: u64 | scalar | point | binary
u64: "U64"
scalar: "Scalar"
point: "Point"
binary: "Binary"
%import common.CNAME -> NAME
%import common.WS
%ignore WS
""", start="contract_def")
tree = parser.parse(text)
tokens = ContractDefTransformer().transform(tree)
assert len(tokens) == 3
return tokens
class ContractCodeLineTransformer(lark.Transformer):
def variable_name(self, name):
return str(name[0])
def let_statement(self, obj):
return ("let", obj)
def return_statement(self, obj):
return ("return", obj)
def emit_statement(self, obj):
return ("emit", obj)
def method_statement(self, obj):
return ("method", obj)
def point(self, _):
return "Point"
def scalar(self, _):
return "Scalar"
def binary(self, _):
return "Binary"
def u64(self, _):
return "U64"
def type(self, typename):
return str(typename[0])
def mutable(self, _):
return "mut"
def function_name(self, name):
return str(name[0])
statement = list
variable_assign = list
variable_decl = tuple
def interpret_contract_line(text, stack, consts):
parser = lark.Lark(r"""
statement: let_statement
| return_statement
| emit_statement
| method_statement
let_statement: "let" variable_assign "=" expr
mutable: "mut"
variable_assign: variable_decl
| "(" variable_decl ("," variable_decl)* ")"
variable_decl: [mutable] variable_name ":" type
?expr: as_expr
| mul_expr
| add_expr
| funccall_expr
| empty_list_expr
as_expr: variable_name "as" type
mul_expr: variable_name "*" variable_name
add_expr: variable_name "+" variable_name
funccall_expr: function_name "(" [variable_name ("," variable_name)*] ")"
empty_list_expr: "[]"
return_statement: "return" variable_name
| "return" variable_tuple
variable_tuple: "(" variable_name ("," variable_name)* ")"
emit_statement: "emit" variable_name
method_statement: variable_name "." funccall_expr
variable_name: NAME
function_name: NAME
type: u64 | scalar | point | binary
u64: "U64"
scalar: "Scalar"
point: "Point"
binary: "Binary"
%import common.CNAME -> NAME
%import common.WS
%ignore WS
""", start="statement")
tree = parser.parse(text)
tokens = ContractCodeLineTransformer().transform(tree)[0]
return tokens
def to_initial_caps(snake_str):
components = snake_str.split("_")
return "".join(x.title() for x in components)
def create_contract_header(contract_def):
contract_name, params, retvals = contract_def
contract_name = to_initial_caps(contract_name)
header = "pub struct %s {\n" % contract_name
for param_name, param_type in params:
if param_type == "U64":
param_type = "u64"
elif param_type == "Scalar":
param_type = "jubjub::Fr"
elif param_type == "Point":
param_type = "jubjub::SubgroupPoint"
header += " " * 4 + "pub %s: Option<%s>,\n" % (param_name, param_type)
header += "}\n\n"
header += r"""impl Circuit<bls12_381::Scalar> for %s {
fn synthesize<CS: ConstraintSystem<bls12_381::Scalar>>(
self,
cs: &mut CS,
) -> Result<(), SynthesisError> {
""" % contract_name
return header
# Worst code ever
def compile_let2(line, stack, consts, funcs, selfvars, statement):
lhs = []
for variable_decl in statement[0]:
assert len(variable_decl) == 2 or \
(len(variable_decl) == 3 and variable_decl[0] == "mut")
if len(variable_decl) == 2:
mutable = False
elif len(variable_decl) == 3:
assert variable_decl[0] == "mut"
mutable = True
variable_decl = variable_decl[1:]
#else:
# Error!
lhs.append(list(variable_decl) + [mutable])
variable_types = []
code = "let "
if len(lhs) == 1:
name, type, is_mutable = lhs[0]
variable_types.append(type)
code += ("mut " if is_mutable else "") + name
else:
code += "("
start = True
for name, type, is_mutable in lhs:
if not start:
code += ", "
start = False
code += name
variable_types.append(type)
code += ")"
code += " = "
expr = statement[1]
expr_type = expr.data
expr = expr.children
if expr_type == "funccall_expr":
ceval = funccall_expr(line, stack, consts, funcs, selfvars, expr, code)
elif expr_type == "empty_list_expr":
ceval = code + "vec![];", ["Binary"]
#code = "let " + ("mut " if is_mutable else "") + variable_name + " = "
if ceval is None:
return None
code, types_to = ceval
if variable_types != types_to:
print("error: sub expr does not evaluate to correct type",
file=sys.stderr)
print("line:", line.text, "line:", line.lineno)
return None
for name, type, _ in lhs:
stack[name] = type
return code
def funccall_expr(line, stack, consts, funcs, selfvars, expr, code):
func_name, arguments = expr[0], expr[1:]
if func_name not in funcs:
print("error: non-existant function call",
file=sys.stderr)
print("line:", line.text, "line:", line.lineno)
return None
arguments = [("self." + arg if arg in selfvars else arg)
for arg in arguments]
code += "%s(cs.namespace(|| \"%s\"), %s)?;" % (
func_name, line.text, ", ".join(arguments))
return_type = funcs[func_name][-1][-1]
return code, return_type
def compile_method_call(line, stack, consts, funcs, selfvars, statement):
variable = statement[0]
method = statement[1].children[0]
arguments = statement[1].children[1:]
arguments = [("self." + arg if arg in selfvars else arg)
for arg in arguments]
return "%s.%s(%s);" % (variable, method, ", ".join(arguments))
def interpret_contract(contract, consts, funcs):
contract_def = parse_contract_def(contract[0].text)
contract_code = create_contract_header(contract_def)
selfvars = set(varname[0] for varname in contract_def[1])
stack = dict(contract_def[1])
for line in contract[1:10]:
indent = " " * 4 * int(line.level + 1)
statement_type, statement = interpret_contract_line(line.text, stack, consts)
#pprint.pprint(statement_type)
if statement_type == "let":
code = compile_let2(line, stack, consts, funcs, selfvars, statement)
if code is None:
return
elif statement_type == "method":
code = compile_method_call(line, stack, consts, funcs,
selfvars, statement)
if code is None:
return
contract_code += indent + code + "\n"
contract_code += " " * 8 + "Ok(())\n"
contract_code += " " * 4 + "}\n"
contract_code += "}\n\n"
#print("-------------------------------")
#print(contract_code)
return contract_code, contract_def
def main(argv):
if len(argv) == 1:
print("error: missing proof file", file=sys.stderr)
return -1
filename = sys.argv[1]
text = open(filename, "r").read()
if (linedescs := parse(text)) is None:
return -1
sections = section(linedescs)
consts, funcs, contracts = classify(sections)
consts = read_consts(consts)
compiled_funcs = {}
for func in funcs:
if (compiled := interpret_func(func, consts)) is None:
return -1
_, _, func_def = compiled
func_name, _, _ = func_def
compiled_funcs[func_name] = compiled
funcs = compiled_funcs
compiled_contracts = {}
for contract in contracts[1:]:
if (compiled := interpret_contract(contract, consts, funcs)) is None:
return -1
#print(contract)
_, contract_def = compiled
contract_name, _, _ = contract_def
compiled_contracts[contract_name] = compiled
contracts = compiled_contracts
# Concat
output = ""
for _, func in funcs.items():
output += func[0]
for _, contract in contracts.items():
output += contract[0]
#print(output)
if __name__ == "__main__":
main(sys.argv)

View File

@@ -1,16 +0,0 @@
[package]
name = "pasta"
version = "0.1.0"
authors = ["narodnik <x@x.org>"]
edition = "2018"
[dependencies]
pasta_curves = { path = "/home/narodnik/src/sw/zectings/pasta_curves" }
ff = "0.9"
group = "0.9"
rand = "0.8.4"
[[bin]]
name = "pasta"
path = "main.rs"

View File

@@ -1,21 +0,0 @@
use pasta_curves as pasta;
use group::{Group, Curve};
use rand::rngs::OsRng;
fn main() {
let g = pasta::vesta::Point::generator();
println!("G = {:?}", g.to_affine());
let x = pasta::vesta::Scalar::from(87u64);
println!("x = 87 = {:?}", x);
let b = g * x;
println!("B = xG = {:?}", b.to_affine());
let y = x - pasta::vesta::Scalar::from(90u64);
println!("y = x - 90 = {:?}", y);
let c = pasta::vesta::Point::random(&mut OsRng);
let d = pasta::vesta::Point::random(&mut OsRng);
println!("C = {:?}", c.to_affine());
println!("D = {:?}", d.to_affine());
println!("C + D = {:?}", (c + d).to_affine());
}

Some files were not shown because too many files have changed in this diff Show More