From 1a0278f307622ba7c8fe718ff83e80ab70d95e4f Mon Sep 17 00:00:00 2001 From: liberhe Date: Wed, 18 Oct 2023 17:43:34 +0800 Subject: [PATCH] delet the useless code --- basic/34-scroll-layer2/hardhat.config.js | 5 + basic/45-Ethereum-2.0/code.md | 27 + basic/49-aa/README.md | 18 +- crypto/ECC/README.md | 643 ------------------ crypto/ECC/ecc_secp256k1.py | 112 --- crypto/ECC/elliptic.py | 509 -------------- crypto/ECC/sign.md | 147 ---- crypto/ECC/test.py | 34 - crypto/Groth16/readme.md | 0 crypto/Halo2/readme.md | 67 -- crypto/Mina/README.md | 19 - crypto/Mina/docs/mina.md | 634 ----------------- crypto/Mina/readme.md | 19 - crypto/Mina/zkApp/README.md | 13 - crypto/PLONK/plonk_gadget.md | 10 - crypto/PLONK/readme.md | 72 -- crypto/ZK-SNARK/README.md | 286 -------- crypto/ZKStark/readme.md | 125 ---- crypto/Zcash/readme.md | 34 - crypto/readme.md | 32 - defi/Aave/graph/package.json | 6 +- lib/openzeppelin-contracts | 1 - socialfi/lens/README.md | 39 -- socialfi/lens/minitwitter/client/.gitignore | 23 - socialfi/lens/minitwitter/client/README.md | 70 -- socialfi/lens/minitwitter/client/package.json | 43 -- .../minitwitter/client/public/favicon.ico | Bin 3870 -> 0 bytes .../lens/minitwitter/client/public/index.html | 43 -- .../minitwitter/client/public/manifest.json | 25 - .../lens/minitwitter/client/public/robots.txt | 3 - socialfi/lens/minitwitter/client/src/App.css | 15 - socialfi/lens/minitwitter/client/src/App.js | 60 -- .../lens/minitwitter/client/src/api/api.js | 92 --- .../lens/minitwitter/client/src/index.css | 13 - socialfi/lens/minitwitter/client/src/index.js | 15 - socialfi/lens/package.json | 0 36 files changed, 48 insertions(+), 3206 deletions(-) create mode 100644 basic/45-Ethereum-2.0/code.md delete mode 100644 crypto/ECC/README.md delete mode 100644 crypto/ECC/ecc_secp256k1.py delete mode 100644 crypto/ECC/elliptic.py delete mode 100644 crypto/ECC/sign.md delete mode 100644 crypto/ECC/test.py delete mode 100644 crypto/Groth16/readme.md delete mode 100644 crypto/Halo2/readme.md delete mode 100644 crypto/Mina/README.md delete mode 100644 crypto/Mina/docs/mina.md delete mode 100644 crypto/Mina/readme.md delete mode 100644 crypto/Mina/zkApp/README.md delete mode 100644 crypto/PLONK/plonk_gadget.md delete mode 100644 crypto/PLONK/readme.md delete mode 100644 crypto/ZK-SNARK/README.md delete mode 100644 crypto/ZKStark/readme.md delete mode 100644 crypto/Zcash/readme.md delete mode 100644 crypto/readme.md delete mode 160000 lib/openzeppelin-contracts delete mode 100644 socialfi/lens/README.md delete mode 100644 socialfi/lens/minitwitter/client/.gitignore delete mode 100644 socialfi/lens/minitwitter/client/README.md delete mode 100644 socialfi/lens/minitwitter/client/package.json delete mode 100644 socialfi/lens/minitwitter/client/public/favicon.ico delete mode 100644 socialfi/lens/minitwitter/client/public/index.html delete mode 100644 socialfi/lens/minitwitter/client/public/manifest.json delete mode 100644 socialfi/lens/minitwitter/client/public/robots.txt delete mode 100644 socialfi/lens/minitwitter/client/src/App.css delete mode 100644 socialfi/lens/minitwitter/client/src/App.js delete mode 100644 socialfi/lens/minitwitter/client/src/api/api.js delete mode 100644 socialfi/lens/minitwitter/client/src/index.css delete mode 100644 socialfi/lens/minitwitter/client/src/index.js delete mode 100644 socialfi/lens/package.json diff --git a/basic/34-scroll-layer2/hardhat.config.js b/basic/34-scroll-layer2/hardhat.config.js index abeae5f93..1a380512c 100644 --- a/basic/34-scroll-layer2/hardhat.config.js +++ b/basic/34-scroll-layer2/hardhat.config.js @@ -78,6 +78,11 @@ module.exports = { mnemonic() ] }, + polygonZkEVM: { + url: `https://rpc.public.zkevm-test.net`, + accounts: [ mnemonic() + ], + }, }, etherscan: { apiKey: { diff --git a/basic/45-Ethereum-2.0/code.md b/basic/45-Ethereum-2.0/code.md new file mode 100644 index 000000000..a7052a37d --- /dev/null +++ b/basic/45-Ethereum-2.0/code.md @@ -0,0 +1,27 @@ + +# 源码解析: +以太坊中的MPT +以太坊中的所有的merkle树都是指Merkle Patricia Tree。 + +从区块头中可以看到有3棵MPT的根。 + +stateRoot +transcationsRoot +receiptsRoot + +## State树 +State树是一棵全局的树,它的key是sha3(ethereumAddress),即账户地址的hash值。其存储的值value为rlp(ethereumAccount),即账户信息的rlp编码。其中账户信息是一个[nonce,balance,storageRoot,codeHash]的四元组,其中storageRoot指向账户的Storage树。 + +## Storage树 +一般的外部账户Storage为空,而合约账户通常会储存一定的数据,这些数据就是存储在合约账户的Storage树中,storage树中的key与账户地址和其中实际存储的key有关,其value值为合约定义的value值。 + +## Transactions树 +每一个区块都会有一棵Transactions树,其key为rlp(transactionIndex)(交易在区块中的编号,0,1…),其value值为经过rlp编码的交易。在实际情况中该树并不会真的存储到数据库中,只是在生成block以及校验block的时候用于得到当前区块的TransactionsRoot。 + +## Receipts树 +每一个区块都会有一棵Receipts树树,其key为rlp(transactionIndex)(交易在区块中的编号,0,1…),其value值为经过rlp编码的交易收据。在实际情况中该树并不会真的存储到数据库中,只是在生成block以及校验block的时候用于得到当前区块的ReceiptsRoot。 + + + +## 参考链接: +以太坊技术与实现:https://learnblockchain.cn/books/geth/part3/statedb.html \ No newline at end of file diff --git a/basic/49-aa/README.md b/basic/49-aa/README.md index f0166a33c..c70737305 100644 --- a/basic/49-aa/README.md +++ b/basic/49-aa/README.md @@ -39,10 +39,20 @@ yarn yarn hardhat run scripts/paymaster.js ``` +## 文档 +- eip-4337文档:4337的规范。https://eips.ethereum.org/EIPS/eip-4337 +- sdk:提供了构建UserOperation,推送UserOperation的能力。源码位于https://github.com/eth-infinitism/bundler/tree/main/packages/sdk。 +npm包位于 +https://www.npmjs.com/package/@account-abstraction/sdk。 + +- bundler:收集UserOperation,验证并推送到EntryPoint合约。git地址https://github.com/eth-infinitism/bundler +- contracts: 主要是EntryPoint,验证UserOperation,并调用AA账户的业务逻辑。git地址https://github.com/eth-infinitism/account-abstraction + # 参考资料 -[EIP-4337](https://eips.ethereum.org/EIPS/eip-4337) -[EIP-4337 Implementation](https://github.com/eth-infinitism/account-abstraction) -[Resources](https://eip4337.com/en/latest/resources.html) -[开发指导](https://www.notion.so/dapplearning/1-9d99463f25ca4c32a5776f6f2cb57edf) +- [EIP-4337](https://eips.ethereum.org/EIPS/eip-4337) +- [EIP-4337 Implementation](https://github.com/eth-infinitism/account-abstraction) +- [Resources](https://eip4337.com/en/latest/resources.html) +- [开发指导1](https://www.notion.so/dapplearning/1-9d99463f25ca4c32a5776f6f2cb57edf) +- [用trampoline开发AA钱包](https://docs.qq.com/doc/DVHBBU0lxR0V4dEV4) diff --git a/crypto/ECC/README.md b/crypto/ECC/README.md deleted file mode 100644 index 482d98cd8..000000000 --- a/crypto/ECC/README.md +++ /dev/null @@ -1,643 +0,0 @@ -# Elliptic Curve Cryptography - -> 本文部分内容出自 [Andrea Corbellini](https://www.linkedin.com/in/andreacorbellini/) 的系列文章,搭配阅读原文体验更佳 -> [Elliptic Curve Cryptography: a gentle introduction](https://andrea.corbellini.name/2015/05/17/elliptic-curve-cryptography-a-gentle-introduction/) - -椭圆曲线密码学(英语:Elliptic Curve Cryptography,缩写:ECC)是一种基于椭圆曲线数学的公开密钥加密算法。椭圆曲线在密码学中的使用是在 1985 年由 Neal Koblitz 和 Victor Miller 分别独立提出的。 - -ECC 的主要优势是它相比 RSA 加密算法使用较小的密钥长度并提供相当等级的安全性[1]。ECC 的另一个优势是可以定义群之间的双线性映射,基于 Weil 对或是 Tate 对。 - -比特币采用了椭圆曲线签名算法来签署交易。 - -
-建议预先掌握的知识点: - -- Group (mathematics) 群, Subgroup 子群, Finite field 有限域 - - [Abstract Algebra: The definition of a Group](https://www.youtube.com/watch?v=QudbrUcVPxk&list=PLi01XoE8jYoi3SgnnGorR_XOW3IcK-TP6&index=3) - - [Group Definition (expanded) - Abstract Algebra](https://www.youtube.com/watch?v=g7L_r6zw4-c&list=PLi01XoE8jYoi3SgnnGorR_XOW3IcK-TP6&index=2) - - [Abstract Algebra: The definition of a Subgroup](https://www.youtube.com/watch?v=TJAQNlGvfjE&list=PLi01XoE8jYoi3SgnnGorR_XOW3IcK-TP6&index=5) -- [Euler's Totient Function](https://www.youtube.com/watch?v=NgZ33qr5WHM) -- [Extended Euclidean Algorithm](https://www.youtube.com/watch?v=6KmhCKxFWOs) - -
-
- -## Elliptic Curves - -首先定义椭圆曲线方程,我们需要的是在曲线上的点的集合 (the set of points described by the equation) - - - - -![Different shapes for different elliptic curves ](https://andrea.corbellini.name/images/curves.png) - -Different shapes for different elliptic curves (b = 1, -3 < a < 2) - -![Types of singularities](https://andrea.corbellini.name/images/singularities.png) - -Types of singularities: 左边是带奇点的曲线,右边是自相交的曲线,都不是有效的椭圆曲线 - -椭圆曲线关于 x 轴对称。我们还需要定义一个无穷远点作为 0 点 (symbol 0) - -最终曲线定义如下 - - - - -## The group law for elliptic curves - -### Group - -理解群的概念 - -群 G 是一个元素集合,我们给他定义了一个二元运算方法,“加法” +。 - -1. **closure**: 对于 G 中的元素 a 和 b, a + b 也是 G 中的元素; -2. **associativity**: (a+b)+c=a+(b+c); -3. **identity element**: 单位元 0 , a+0=0+a; -4. **inverse**: 每个元素都有一个逆元,即对于 G 中的元素 a 都存在一个元素 b, a + b = 0; - -我们附加了一条特性 - -5. **commutativity**: a+b=b+a (Abelian group 阿贝尔群) - -### Geometric addition - -我们在椭圆曲线上定义了一个群,是曲线上点的集合 - -- 元素是椭圆曲线上的点 -- identity element 是无穷远的 0 点(point at infinity 0) -- 对于点 P ,inverse (逆元) 是关于 x 轴对称的点 -- addition 加法的规则:一条直线与椭圆曲线相交的三个非 0 的点 P, Q, R 他们的和是 0 点,即 P+Q+R=0 - - P+Q=-R - - -R 是 R 的逆元 - - 即 P+Q 等于 R 相对于 x 轴对称的点 - -![Draw the line through and . The line intersects a third point . The point symmetric to it, , is the result of .](https://andrea.corbellini.name/images/point-addition.png) - -P+Q=-R - -直线与椭圆曲线相交有三种特殊情况 - -1. P=0 or Q=0. 我们不可能在 xy 坐标上标出 0 点(无穷远),所以也无法画出这条线。但我们可以将 0 点定义为 identity element (单位元),即 P+0=P and 0+Q=Q -2. P=-Q. P 和 Q 关于 x 轴对称,此时直线将于 x 轴垂直,与椭圆曲线没有第三个交点 R,则 Q 是 P 的逆元,即 P+Q=0 -3. P=Q. Q 无限接近 P 点,直线是椭圆曲线的切线,P+Q=P+P=-R - -![As the two points become closer together, the line passing through them becomes tangent to the curve.](https://andrea.corbellini.name/images/animation-point-doubling.gif) - -可以到这里尝试自己修改参数,观察曲线和直线交点的变化 [HTML5/JavaScript visual tool](https://andrea.corbellini.name/ecc/interactive/reals-add.html) - -### Algebraic addition - -为了精确计算点的加法,我们需要把上述几何方法转换为代数算法。 - -已知 P,Q 的坐标,计算 R 点。 - -```math -P=(xP, yP) -Q=(xQ, yQ) -``` - -### xP!=xQ - -首先考虑 xP != xQ 的情况,直线的斜率 m 为 - - - - -R 的坐标可以如下计算 - - - - - - - -或者 - - - - -推导过程如下(感谢 kaiji 的补充): - -代入 Q 点和 P 点到椭圆曲线 - - - - - - - -将上述两个等式相减 - - - - -将 yQ - yR 替换为 m(xQ-xR),等式两边消去 (yQ+yR) - - - - -同理可得 - - - - -将上述两个等式相减 - - - - -两边同时除以 (xP-xQ) - - - - -计算出 R 点之后,进而得出关于 x 轴对称点 -R,即为 P+Q 的结果 - -(xP,yP) + (xQ,yQ) = (xR,-yR) - -我们可以用实际的点去验证上述公式 - -- (1,2)+(3,4)=(-3,2) -- (-1,4)+(1,2)=(1,-2) - -### xP=xQ - -我们先将椭圆曲线方程改成 y 的一次方形式 - - - - -当 P,Q 横坐标相同,直线为椭圆曲线的切线,我们将更改斜率 m 的定义为椭圆曲线的导函数 - - - - -xR 和 yR 的公式保持不变,我们将 P=Q=(1,2) 代入公式验证 - -(1,2)+(1,2)=2(1,2)=(-1,-4) - -### Scalar multiplication - -上述加法运算中,当 P=Q 时,P+P=2P,我们可以将其定义为 **scalar multiplication** 标量乘法。 - -nP=P+P+...+P (n times) - -如果 n 在二进制中有 k 位(If n has k binary digits),其算法复杂度 O(2^k),我们需要对其优化。 - -**double and add algorithm** 用一个例子解释该算法工作原理:假设 n=151,其二进制表示为 10010111 - - - - -double and add algorithm 将要做的是: - -- P, 即 2^0\*P -- P+P=2P, 即 2^1\*P -- 2P+2P=4P, 即 2^2\*P -- 4P+4P=8P, 即 2^3\*P -- 8P+8P=16P, 即 2^4\*P -- 151P = 2^4\*P + 2^2\*P + 2^1\*P + 2^0\*P - -算法 python 实现 - -```python -def bits(n): - """ - Generates the binary digits of n, starting - from the least significant bit. - - bits(151) -> 1, 1, 1, 0, 1, 0, 0, 1 - """ - while n: - yield n & 1 - n >>= 1 - -def double_and_add(n, x): - """ - Returns the result of n * x, computed using - the double and add algorithm. - """ - result = 0 - addend = x - - for bit in bits(n): - if bit == 1: - result += addend - addend *= 2 - - return result -``` - -假定 翻倍 doubling 和 加法 adding 操作都是 O(1), 那么这个算法将是 O(log(n)) (如果我们考虑 n 的位数,将是 O(k)) - -## The field of integers modulo p - -首先,有限域是具有有限个元素的集合。有限域的一个例子是模 p 的整数集合,其中 p 是素数。它通常表示为 Z/p、GF(p) 或 Fp。我们将使用后一种表示法。 - -在有限域中,我们有两种二元运算:addition(+), multiplication(·)。两种运算都符合 closed, associative and commutative 特性。 - -举例说明,对于 F23 (mod 23 的有限域) - -- Addition: (18+9) mod 23 = 4 -- Subtraction: (7-14) mod 23 = 16 -- Multiplication: 4·7 mod 23 = 5 -- Additive inverse: -5 mod 23 = 18 - - (5+(-5)) mod 23 = (5+18) mod 23 = 0 -- Multiplicative inverse: 9^-1 mod 23 = 18 - - 9·9^-1 mod 23 = 9·18 mod 23 = 1 - -**p 必须是素数!** - -整数模 4 的集合不是一个域:2 没有乘法逆元(即方程 2⋅x mod 4=1 没有解)。 - -### Division modulo p - -在 Fp 中的除法模运算即为求出一个元素的乘法逆元,然后执行乘法运算。 - -x/y = x·y^-1 - -根据拓展欧几里得算法 [extended Euclidean algorithm](https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm) , 求出一个元素的乘法逆元的复杂度将是 O(log(p)) (如果考虑二进制位数将是 O(k))。 - -给定 n 和 p,求 n 在 Fp 中的乘法逆元,即当 n · n^-1 mod p = 1 时,求 n^-1 - -上述条件可以改写为 n · x - p · y = 1, 其中 y 为 n // p (商) , x % p 即为 n^-1 (x 有可能比 p 大,固结果还要取模) - -Computing the multiplicative inverse Python implementation - -- `extended_euclidean_algorithm(a, b)` - - 根据拓展欧几里得算法,返回 GCD (最大公约数), x, y - - 使用辗转相除法,当余数 r 为 0 时终止循环 - - 返回结果满足 a \* x + b \* y = GCD -- `inverse_of(n, p)` 求 n 在 Fp 中的乘法逆元 - - 当 gcd = 1 时,乘法逆元即为 x % p - - 否则 n 在 Fp 中不存在乘法逆元 - -```python -def extended_euclidean_algorithm(a, b): - """ - Returns a three-tuple (gcd, x, y) such that - a * x + b * y == gcd, where gcd is the greatest - common divisor of a and b. - - This function implements the extended Euclidean - algorithm and runs in O(log b) in the worst case. - """ - s, old_s = 0, 1 - t, old_t = 1, 0 - r, old_r = b, a - - while r != 0: - quotient = old_r // r - old_r, r = r, old_r - quotient * r - old_s, s = s, old_s - quotient * s - old_t, t = t, old_t - quotient * t - - return old_r, old_s, old_t - - -def inverse_of(n, p): - """ - Returns the multiplicative inverse of - n modulo p. - - This function returns an integer m such that - (n * m) % p == 1. - """ - gcd, x, y = extended_euclidean_algorithm(n, p) - assert (n * x + p * y) % p == gcd - - if gcd != 1: - # Either n is 0, or p is not a prime number. - raise ValueError( - '{} has no multiplicative inverse ' - 'modulo {}'.format(n, p)) - else: - return x % p -``` - -## Elliptic curves in Fp - -对椭圆曲线取模,公式将变成如下形式 - - - - -0 点仍然是无穷远点,(x, y) 是 Fp 中的整数。 - -![(x,y) in Fp^2](https://andrea.corbellini.name/images/elliptic-curves-mod-p.png) - -(上图中 p = 19,97,127,487。可以对于每个 x 值,最多存在两个点,每个点关于 y=p/2 上下对称) - -![singular curve](https://andrea.corbellini.name/images/singular-mod-p.png) - -(y^2= x^3 (mod 29)) 不是一个有效的椭圆曲线,包含了 0 点 (0,0) - -在有限域 Fp 中,椭圆曲线仍然形成一个阿贝尔群。 - -### Point addition - -我们之前已经讨论过在椭圆曲线上 P+Q+R=0 的定义,三个点都在实属域 R 中。那么在有限域 Fp 中,将满足以下等式 - - - - -![addition in Fp](https://andrea.corbellini.name/images/point-addition-mod-p.png) - -(curve y^2=x^3-x+3 (mod 127), P=(16,20) and Q=(41,120)) - -Fp 中的加法属性 - -- Q + 0 = 0 + Q = Q (单位元的定义) -- 给定非零点 Q,其逆元 -Q 是横坐标相同,但纵坐标关于 y=p/2 横线对称的点,即 -Q=(2, -5 mod 29) = (2, 24) -- P+(-P)=0 - -### Algebraic sum - -将上述图形方法转为代数算法来计算 P+Q=-R - -直接将实数域的公式增加 mod p - - - - - - - -or - - - - -对于斜率 m,当 xP != xQ - - - - -当 xP = xQ - - - - -### The order of an elliptic curve group - -对于 Fp 的阶数 order (元素个数),当 p 是一个很大的素数时,要计算 order 数量将会很困难, O(p) - -### Scalar multiplication and cyclic subgroups - -对于椭圆曲线 y^2=x^3+2x+3 (mod 97) 和点 P=(3,6),P 只需要与自己相加 5 次即可回到初始点。 - -![just five distinct points](https://andrea.corbellini.name/images/cyclic-subgroup.png) - -- 0P=0 -- 1P=(3,6) -- 2P=(80,100) -- 3P=(80,87) -- 4P=(3,91) -- 5P=0 -- ... - -P 的倍数只有 5 个,且是循环出现的,于是我们可以重写一下结果: - -- 5kP=0 -- (5k+1)P=P -- (5k+2)P=2P -- (5k+3)P=3P -- (5k+4)P=4P - -P 的倍数组成的集合是椭圆曲线在 Fp 有限域中的循环子群。 (the set of the multiples of is a cyclic subgroup of the group formed by the elliptic curve.) - -在该循环子群中,点 P 为称作生成元 或 基点 (generator or base point)。 - -循环子群是 ECC 和其他密码系统的基础。 - -### Subgroup order - -如何计算子群的阶数? - -- order 阶数即为群中元素的个数,对于上述循环子群,order of P 即为满足 nP=0 的最小正整数。 -- 根据拉格朗日定理 [Lagrange's theorem](), order of P 子群的阶数是父群的阶数的除数 - - 换言之,椭圆曲线包含 N 个点,其循环子群包含 n 个点,则 n 是 N 的除数 - -结合上述两条信息,计算子群阶数的步骤如下: - -1. 计算椭圆曲线包含的元素个数 N 使用 [Schoof's algorithm](https://en.wikipedia.org/wiki/Schoof%27s_algorithm) -2. 找出所有 N 的除数 -3. 对每个 N 的除数 n,计算 nP -4. 满足 nP=0 条件的最小的正整数,即为子群的阶数 order of the subgroup - -例 1:在 y^2=(x^3-x+3) mod 37 中,总的点个数 N = 42,可能的 order n=1,2,3,6,7,14,21,42. 给定点 P=(2,3),我们可以尝试计算 P,2P,3P,6P,7P, 一直到 7P=0,因此由 P 点作为基点的循环子群,其阶数(order of P) n=7 - -例 2: 在 Y^2=(x^3-x+1) mod 29 中,总的点个数 N = 37。 由于 N 是素数,其除数只有 1 和 37。当子群的 order n = 1 时,其中只能包含一个元素,即无穷远 0 点。当 n = 37 时,子群就是整个曲线点集合。 - -### Finding a base point - -寻找基点(生成元)。 - -对于椭圆曲线加密算法,我们希望基点生成的子群拥有尽量多的个数,即 order 越大越好。因此我们会先算出椭圆曲线的点个数 N,然后选择其最大的除数作为子群的元素个数 n,再去匹配符合要求的基点。 - -令 h = N/n , 由于 n 是 N 的除数,固也是整数。我们称 h 为子群的辅因子 cofactor of the subgroup。 - -由于 nP=0 (循环子群的特性), 而 N 是 n 的倍数,即 N = nh, 我们可得出 - -n(hP)=0 - -假设 n 是素数,用 G 表示所求的基点,则 G=hP。方法总结如下: - -1. 计算椭圆曲线的点个数 N -2. 选择子群的阶数 n, 满足 n 是素数,且必须是 N 的除数 -3. 计算子群辅因子 cofactor h = N/n -4. 在曲线上随机选择一个点 P -5. 计算 G = hP -6. 如果 G 是无穷远 0 点,返回第 4 步;不为 0 点,则我们找到了一个子群的基点(生成元),其阶数为 n,辅因子为 h。 - -请注意,此算法仅在 n 是素数时才有效。如果 n 不是素数,则 G 的阶数可能是 n 的除数之一。 - -### Discrete logarithm - -在循环子群内,当我们已知 P 和 Q 点,要如何求 P=kQ 中的 k 是多少呢?将循环子群看成一个圆形时钟,从 P 到 Q,实际上我们无法得知究竟转了多少圈。这个逆运算的问题被称为离散对数问题 discrete logarithm problem。 - -discrete logarithm problem 被认为是很困难的,这一特性同样被运用在其他加密算法中,例如 RSA, D-H。 - -所不同的是,ECC 使用更少位数的 k 就能达到相同安全级别。 - -### Domain parameters - -我们的椭圆曲线算法将在有限域上的椭圆曲线的循环子群中工作。因此,我们的算法将需要以下参数 - -- 素数 p 作为有限域的阶数. -- 系数 a 和 b 定义椭圆曲线 (y^2 = x^3 + ax +b). -- 循环子群的基点 G 作为生成元. -- 循环子群的阶数 n. -- 循环子群的辅因子 h. - -### Random curves - -尽管椭圆曲线加密大部分是安全的,但仍有一些是比较弱的,会有安全隐患。如何才能保证一条椭圆曲线是安全的呢? - -为了解决这个问题,我们使用种子 S 进行 hash 去生成系数 a, b, 或者基点 G,甚至全部用种子随机生成。 - -![A simple sketch of how a random curve is generated from a seed](https://andrea.corbellini.name/images/random-parameters-generation.png) - -(A simple sketch of how a random curve is generated from a seed: the hash of a random number is used to calculate different parameters of the curve.) - -!["hard" problem: hash inversion](https://andrea.corbellini.name/images/seed-inversion.png) - -(If we wanted to cheat and try to construct a seed from the domain parameters, we would have to solve a "hard" problem: hash inversion.) - -参数由随机种子生成的曲线,称之为 **verifiably random** - -## Elliptic Curve Cryptography - -定义公私钥对 - -1. private key 是从 [1, n-1] (n 是子群的阶数) 中选取的整数 `d` -2. public key 是点 `H = dG` (G 是子群的基点) - -如果我们知道私钥 d 和 基点 G 找到公钥 H 0 是很容易的,但是反过来,已知 H 和 G,要找到私钥 d 是很困难的。 - -### Encryption with ECDH - -ECDH 是椭圆曲线 [Diffie-Hellman](https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange) 算法的变体。它实际上是一种密钥协商协议 [key-agreement protocol](https://en.wikipedia.org/wiki/Key-agreement_protocol),而不是一种加密算法。ECDH 定义了如何在各方之间生成和交换密钥。如何使用这些密钥实际加密数据取决于我们。 - -Alice 和 Bob 想要隐私且安全的交换信息,不被第三方看到内容: - -1. Alice 和 Bob 创建各自的公私钥对。Alice 的私钥 dA 公钥 HA = dA\*G,Bob 的是 dB 和 HB = dB \* G。 两人使用同一条曲线的同一个有限域(系数和生成元相同) -2. Alice 和 Bob 互相交换公钥 HA 和 HB ,第三方可见公钥,但无法知道两人的私钥。 -3. Alice 计算出消息 S = dA\*HB , Bob 也计算出消息 S = dB\*HA, 两人会得到相同的结果 - - - - -原理在于两人用自己的私钥乘以对方的公钥,其结果都是 dA\*dB\*G , 但第三方只知道公钥,就无法得到信息。 - -![Diffie-Hellman key exchange](https://andrea.corbellini.name/images/ecdh.png) - -现在 Alice 和 Bob 已经获得了共享秘密 S ,他们可以通过对称加密交换数据。 - -[ECDH demo](https://github.com/andreacorbellini/ecc/blob/master/scripts/ecdhe.py) - -### Ephemeral ECDH - -ECDHE 中的“E”代表“Ephemeral”,指的是交换的密钥是临时的,而不是静态的。 例如,在 TLS 中使用 ECDHE,在建立连接时,客户端和服务器都会即时生成它们的公钥-私钥对。然后使用 TLS 证书对密钥进行签名(用于身份验证)并在各方之间进行交换。 - -### Signing with ECDSA - -ECDH 不能体现所有权,即 Alice 签名的消息,只有 Bob 可以验证,第三方无法验证真伪。 - -ECDSA 可以实现这一场景,它是 DSA [Digital Signature Algorithm](https://en.wikipedia.org/wiki/Digital_Signature_Algorithm) 的一种变体。 - -ECSDA 处理消息的 hash 而不是消息本身,hash 函数由我们自己选择。hash 会被截断,与 n (子群的阶数)的位数相同,截断后的 hash 应是一个整数,用 `z` 表示。 - -Alice 为消息签名所执行的算法如下: - -1. 从 [1, n-1] (n 是子群的阶数) 中选取随机的整数 `k` -2. 计算点 P=kG (G 是子群的基点) -3. 计算 r = xP mod n (xP 是 P 点横坐标) -4. 如果 r 是 0,返回第 1 步 -5. 计算 s = k^-1(z + r\*dA) mod n (dA 是 Alice 的私钥, k^-1 是 k 在 k mod n 中的乘法逆元) -6. 如果 s 是 0,返回第 1 步 - -最终 (r, s) 对就是签名 - -![ECDSA sign](https://andrea.corbellini.name/images/ecdsa.png) - -Alice 使用她的私钥 dA 和随机 k 对哈希 z 进行签名。 Bob 使用 Alice 的公钥 HA 验证消息是否已正确签名。 - -再次强调,n 需要是素数,否则无法求 k^-1。 - -### Verifying signatures - -为了验证签名,我们需要 Alice 的公钥 HA、(截断的)hash `z`,还有签名 (r,s)。 - -1. 计算整数 u1 = s^-1 \* z mod n -2. 计算整数 u2 = s^-1 \* r mod n -3. 计算点 P = u1\*G + u2\*HA - -当 r == xP mod n 时,签名有效。 - -### Correctness of the algorithm - -算法的逻辑看起来不明显 - -P = u1\*G + u2\*HA - -公钥的定义是 HA=dA\*G (dA 是私钥) - -```math -P = u1*G + u2*HA - = u1*G + u2*dA*G - = (u1 + u2*dA)*G -``` - -再将u1 和u2 的定义代入 - -```math -P = (u1 + u2*dA)*G - = (s^-1*z + s^-1*r*dA)*G - = s^-1(z + r*dA)*G -``` - -这里我们为了简洁省略了“mod n”,并且因为 G 生成的循环子群具有 n 阶,因此“mod n”是多余的。 - -之前我们定义了 s = k^-1(z + r\*dA) mod n, 两边乘以 k 再除以 s 则 - -k = s^-1(z + r\*dA) mod n - -代入 P 的表达式 - -```math -P = s^-1(z + r*dA)*G = k*G -``` - -这与签名时第2步相同,即如果 xP mod n 与 r 相同,则说明签名有效。 - -### Playing with ECDSA - -[a Python script for signature generation and verification](https://github.com/andreacorbellini/ecc/blob/master/scripts/ecdsa.py) - - -### The importance of k - -在生成 ECDSA 签名时,将秘密 k 保密很重要。如果我们对所有签名使用相同的 k,或者如果我们的随机数生成器在某种程度上是可预测的,那么攻击者将能够找到私钥! - -著名的 PlayStation 3 事故 [This is the kind of mistake made by Sony a few years ago](http://www.bbc.com/news/technology-12116051)。索尼的ECDSA签名算法使用的时静态的 k,即每次的k值都相同,导致攻击者很容易就能破解私钥。 - -攻击者只需要购买两个游戏,然后提取他们的 hash (z1, z2) 和 签名 (r1,s1),(r2,s2) - -1. 首先 r1 = r2 ,因为 r = xP mod n , P = kG ,如果k值不变, r也不会变 -2. (s1 - s2) mod n = k^-1(z1 - z2) mod n -3. 两边同时乘以 k , k(s1 - s2) mod n = (z1 - z2) mod n -4. k = (z1 - z2)(s1 - s2)^-1 mod n - -最后通过k计算私钥 dS - -s = k^-1 (z + r\*dS) mod n - -dS = r^-1 (s\*k - z) mod n - -## 其他 ECDSA 实现 - -- [ecc-secp256k1.py](./ecc_secp256k1.py) -- [elliptic.py](./elliptic.py) - -> mac m1 芯片可能无法安装 fastecdsa , 可以使用下列命令安装,详见 [Cannot install in macOS BigSur (M1 chip)](https://github.com/AntonKueltz/fastecdsa/issues/74) - -```sh -CFLAGS=-I/opt/homebrew/opt/gmp/include LDFLAGS=-L/opt/homebrew/opt/gmp/lib python3 -m pip install --no-binary :all: --no-use-pep517 fastecdsa -``` - -## 参考 - -- [Elliptic Curve Cryptography: a gentle introduction](https://andrea.corbellini.name/2015/05/17/elliptic-curve-cryptography-a-gentle-introduction/) -- [Elliptic Curve Cryptography: finite fields and discrete logarithms](https://andrea.corbellini.name/2015/05/23/elliptic-curve-cryptography-finite-fields-and-discrete-logarithms/) -- [Elliptic Curve Cryptography: ECDH and ECDSA](https://andrea.corbellini.name/2015/05/30/elliptic-curve-cryptography-ecdh-and-ecdsa/) -- [Elliptic Curve Cryptography: breaking security and a comparison with RSA](https://andrea.corbellini.name/2015/06/08/elliptic-curve-cryptography-breaking-security-and-a-comparison-with-rsa/) -- [github andreacorbellini/ecc](https://github.com/andreacorbellini/ecc) -- [ecdsa-math](https://happypeter.github.io/binfo/ecdsa-math.html) -- -- -- -- -- diff --git a/crypto/ECC/ecc_secp256k1.py b/crypto/ECC/ecc_secp256k1.py deleted file mode 100644 index f39807f41..000000000 --- a/crypto/ECC/ecc_secp256k1.py +++ /dev/null @@ -1,112 +0,0 @@ -#coding:utf-8 - -#!/usr/bin/env python - -import sys - -if sys.version_info < (3,0): - print("Please use python3 version to run the code") - print("请使用 python3 运行代码") - sys.exit() - -# Super simple Elliptic Curve Presentation. No imported libraries, wrappers, nothing. -# For educational purposes only. - -# Below are the public specs for Bitcoin's curve - the secp256k1 - -Pcurve = 2**256 - 2**32 - 2**9 - 2**8 - 2**7 - 2**6 - 2**4 -1 # Finite field, 有限域 -# 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f - -N = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 # 群的阶 -Acurve = 0; Bcurve = 7 # 椭圆曲线的参数式. y^2 = x^3 + Acurve * x + Bcurve - -Gx = 55066263022277343669578718895168534326250603453777594175500187360389116729240 -# 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 - -Gy = 32670510020758816978083085130507043184471273380659243275938904335757337482424 -# 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 - -GPoint = (Gx, Gy) # 椭圆曲线生成点, Base point. - -#(Gx**3+7) % Pcurve == (Gy**2) % Pcurve, GPoint在椭圆曲线上, x/y坐标符合椭圆曲线方程 - -h = 1 # Subgroup cofactor, 子群辅因子为1, 就不参与运算了 - -# Pcurve, N, GPoint, secp256k1的函数式, 都是严格规定的, 严禁修改 !!! - -class ECC256k1: - - # 扩展欧几里得算法, https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm - # Extended Euclidean Algorithm/'division' in elliptic curves - def inverse_mod(self, a, n=Pcurve): - lm, hm = 1, 0 - low, high = a % n, n - while low > 1: - ratio = high //low - nm, new = hm - lm * ratio, high - low * ratio - lm, low, hm, high = nm, new, lm, low - return lm % n - - def ECadd(self, a, b): # 椭圆曲线加法 - LamAdd = ((b[1] - a[1]) * self.inverse_mod(b[0] - a[0], Pcurve)) % Pcurve - - x = (LamAdd * LamAdd - a[0] - b[0]) % Pcurve - y = (LamAdd * (a[0] - x) - a[1]) % Pcurve - return (x,y) - - def ECdouble(self, a): # 椭圆曲线倍乘 - Lam = ((3 * a[0] * a[0] + Acurve) * self.inverse_mod((2 * a[1]), Pcurve)) % Pcurve - - x = (Lam * Lam - 2 * a[0]) % Pcurve - y = (Lam * (a[0] - x) - a[1]) % Pcurve - - return (x,y) - - def EccMultiply(self, GenPoint, ScalarHex): # Double & Add. Not true multiplication - if ScalarHex == 0 or ScalarHex >= N: raise Exception("Invalid Scalar/Private Key") - - ScalarBin = str(bin(ScalarHex))[2:] - - Q = GenPoint - for i in range (1, len(ScalarBin)): # EC乘法转为标量乘法进行计算 减少运算量 - Q = self.ECdouble(Q) - - if ScalarBin[i] == "1": - Q = self.ECadd(Q, GenPoint); # print "ADD", Q[0]; print - - return (Q) - - def publicKey(self, privKey): - return self.EccMultiply(GPoint, privKey) - - def compressedPubkey(self, pubKey): - fill = str(hex(pubKey[0])[2:]).zfill(64) - if pubKey[1] % 2 == 1: # If the Y value for the Public Key is odd. - return ("03" + fill) - else: # Or else, if the Y value is even. - return ("02" + fill) - - def uncompressedPubkey(self, pubKey): - return ("04" + "%064x" % pubKey[0] + "%064x" % pubKey[1]) - - -def main(): - priv_key = 0x1111111111111111111111111111111111111111111111111111111111111111 - - ecc = ECC256k1() - - PublicKey = ecc.publicKey(priv_key) - print("私钥:") - print(priv_key) - - print("未压缩公钥 (坐标):") - print(PublicKey) - - print("未压缩公钥 (十六进制):") - print(ecc.uncompressedPubkey(PublicKey)) - - print("压缩公钥:") - print(ecc.compressedPubkey(PublicKey)) - -if __name__ == "__main__": - main() diff --git a/crypto/ECC/elliptic.py b/crypto/ECC/elliptic.py deleted file mode 100644 index a3cb44ab5..000000000 --- a/crypto/ECC/elliptic.py +++ /dev/null @@ -1,509 +0,0 @@ -""" -By Willem Hengeveld -ecdsa implementation in python -demonstrating several 'unconventional' calculations, -like finding a public key from a signature, -and finding a private key from 2 signatures with identical 'r' -""" - - -def GCD(a, b): - """ - (gcd,c,d)= GCD(a, b) ===> a*c+b*d!=gcd: - """ - if a == 0: - return (b, 0, 1) - d1, x1, y1 = GCD(b % a, a) - return (d1, y1 - (b // a) * x1, x1) - - -def modinv(x, m): - (gcd, c, d) = GCD(x, m) - return c - - -def samefield(a, b): - """ - determine if a uses the same field - """ - if a.field != b.field: - raise RuntimeError("field mismatch") - return True - - -class FiniteField: - """ - FiniteField implements a value modulus a number. - """ - - class Value: - """ - represent a value in the FiniteField - this class forwards all operations to the FiniteField class - """ - - def __init__(self, field, value): - self.field = field - self.value = field.integer(value) - - # Value * int - def __add__(self, rhs): - return self.field.add(self, self.field.value(rhs)) - - def __sub__(self, rhs): - return self.field.sub(self, self.field.value(rhs)) - - def __mul__(self, rhs): - return self.field.mul(self, self.field.value(rhs)) - - def __truediv__(self, rhs): - return self.field.div(self, self.field.value(rhs)) - - def __pow__(self, rhs): - return self.field.pow(self, rhs) - - # int * Value - def __radd__(self, rhs): - return self.field.add(self.field.value(rhs), self) - - def __rsub__(self, rhs): - return self.field.sub(self.field.value(rhs), self) - - def __rmul__(self, rhs): - return self.field.mul(self.field.value(rhs), self) - - def __rtruediv__(self, rhs): - return self.field.div(self.field.value(rhs), self) - - def __rpow__(self, rhs): - return self.field.pow(self.field.value(rhs), self) - - def __eq__(self, rhs): - return self.field.eq(self, self.field.value(rhs)) - - def __ne__(self, rhs): - return not (self == rhs) - - def __neg__(self): - return self.field.neg(self) - - def sqrt(self, flag): - return self.field.sqrt(self, flag) - - def inverse(self): - return self.field.inverse(self) - - def iszero(self): - return self.value == 0 - - def __repr__(self): - return "%d (mod %d)" % (self.value, self.field.p) - - def __str__(self): - return "%d (mod %d)" % (self.value, self.field.p) - - def __init__(self, p, order=1): - self.p = p ** order - - """ - several basic operators - """ - - def add(self, lhs, rhs): - return samefield(lhs, rhs) and self.value((lhs.value + rhs.value) % self.p) - - def sub(self, lhs, rhs): - return samefield(lhs, rhs) and self.value((lhs.value - rhs.value) % self.p) - - def mul(self, lhs, rhs): - return samefield(lhs, rhs) and self.value((lhs.value * rhs.value) % self.p) - - def div(self, lhs, rhs): - return samefield(lhs, rhs) and self.value((lhs.value * rhs.inverse()) % self.p) - - def pow(self, lhs, rhs): - return self.value(pow(lhs.value, self.integer(rhs), self.p)) - - def eq(self, lhs, rhs): - return (lhs.value - rhs.value) % self.p == 0 - - def neg(self, val): - return self.value(self.p - val.value) - - def sqrt(self, val, flag): - """ - calculate the square root modulus p - """ - if val.iszero(): - return val - sw = self.p % 8 - if sw == 3 or sw == 7: - res = val ** ((self.p + 1) / 4) - elif sw == 5: - x = val ** ((self.p + 1) / 4) - if x == 1: - res = val ** ((self.p + 3) / 8) - else: - res = (4 * val) ** ((self.p - 5) / 8) * 2 * val - else: - raise Exception("modsqrt non supported for (p%8)==1") - if res.value % 2 == flag: - return res - else: - return -res - - def inverse(self, value): - """ - calculate the multiplicative inverse - """ - return modinv(value.value, self.p) - - def value(self, x): - """ - converts an integer or FinitField.Value to a value of this FiniteField. - """ - return ( - x - if isinstance(x, FiniteField.Value) and x.field == self - else FiniteField.Value(self, x) - ) - - def integer(self, x): - """ - returns a plain integer - """ - return x.value if isinstance(x, FiniteField.Value) else x - - def zero(self): - """ - returns the additive identity value - meaning: a + 0 = a - """ - return FiniteField.Value(self, 0) - - def one(self): - """ - returns the multiplicative identity value - meaning a * 1 = a - """ - return FiniteField.Value(self, 1) - - -class EllipticCurve: - """ - EllipticCurve implements a point on a elliptic curve - """ - - class Point: - """ - represent a value in the EllipticCurve - this class forwards all operations to the EllipticCurve class - """ - - def __init__(self, curve, x, y): - self.curve = curve - self.x = x - self.y = y - - # Point + Point - def __add__(self, rhs): - return self.curve.add(self, rhs) - - def __sub__(self, rhs): - return self.curve.sub(self, rhs) - - # Point * int or Point * Value - def __mul__(self, rhs): - return self.curve.mul(self, rhs) - - def __div__(self, rhs): - return self.curve.div(self, rhs) - - def __eq__(self, rhs): - return self.curve.eq(self, rhs) - - def __ne__(self, rhs): - return not (self == rhs) - - def __str__(self): - return "(%s,%s)" % (self.x, self.y) - - def __neg__(self): - return self.curve.neg(self) - - def iszero(self): - return self.x.iszero() and self.y.iszero() - - def isoncurve(self): - return self.curve.isoncurve(self) - - def __init__(self, field, a, b): - self.field = field - self.a = field.value(a) - self.b = field.value(b) - - def add(self, p, q): - """ - perform elliptic curve addition - """ - if p.iszero(): - return q - if q.iszero(): - return p - - # calculate the slope of the intersection line - if p == q: - if p.y == 0: - return self.zero() - l = (3 * p.x ** 2 + self.a) / (2 * p.y) - elif p.x == q.x: - return self.zero() - else: - l = (p.y - q.y) / (p.x - q.x) - - # calculate the intersection point - x = l ** 2 - (p.x + q.x) - y = l * (p.x - x) - p.y - return self.point(x, y) - - # subtraction is : a - b = a + -b - def sub(self, lhs, rhs): - return lhs + -rhs - - # scalar multiplication is implemented like repeated addition - def mul(self, pt, scalar): - scalar = self.field.integer(scalar) - accumulator = self.zero() - shifter = pt - while scalar != 0: - bit = scalar % 2 - if bit: - accumulator += shifter - shifter += shifter - scalar //= 2 - - return accumulator - - def div(self, pt, scalar): - """ - scalar division: P / a = P * (1/a) - scalar is assumed to be of type FiniteField(grouporder) - """ - return pt * (1 // scalar) - - def eq(self, lhs, rhs): - return lhs.x == rhs.x and lhs.y == rhs.y - - def neg(self, pt): - return self.point(pt.x, -pt.y) - - def zero(self): - """ - Return the additive identity point ( aka '0' ) - P + 0 = P - """ - return self.point(self.field.zero(), self.field.zero()) - - def point(self, x, y): - """ - construct a point from 2 values - """ - return EllipticCurve.Point(self, self.field.value(x), self.field.value(y)) - - def isoncurve(self, p): - """ - verifies if a point is on the curve - """ - return p.iszero() or p.y ** 2 == p.x ** 3 + self.a * p.x + self.b - - def decompress(self, x, flag): - """ - calculate the y coordinate given only the x value. - there are 2 possible solutions, use 'flag' to select. - """ - x = self.field.value(x) - ysquare = x ** 3 + self.a * x + self.b - - return self.point(x, ysquare.sqrt(flag)) - - -class ECDSA: - """ - Digital Signature Algorithm using Elliptic Curves - """ - - def __init__(self, ec, G, n): - self.ec = ec - self.G = G - self.GFn = FiniteField(n) - - def calcpub(self, privkey): - """ - calculate the public key for private key x - return G*x - """ - return self.G * self.GFn.value(privkey) - - def sign(self, message, privkey, secret): - """ - sign the message using private key and sign secret - for signsecret k, message m, privatekey x - return (G*k, (m+x*r)/k) - """ - m = self.GFn.value(message) - x = self.GFn.value(privkey) - k = self.GFn.value(secret) - - R = self.G * k - - r = self.GFn.value(R.x) - s = (m + x * r) / k - - print("=== Signature Generated Successfully ===") - - return (r, s) - - def verify(self, message, pubkey, rnum, snum): - """ - Verify the signature - for message m, pubkey Y, signature (r,s) - r = xcoord(R) - verify that : G*m+Y*r=R*s - this is true because: { Y=G*x, and R=G*k, s=(m+x*r)/k } - - G*m+G*x*r = G*k*(m+x*r)/k -> - G*(m+x*r) = G*(m+x*r) - several ways to do the verification: - r == xcoord[ G*(m/s) + Y*(r/s) ] <<< the standard way - R * s == G*m + Y*r - r == xcoord[ (G*m + Y*r)/s) ] - - """ - m = self.GFn.value(message) - r = self.GFn.value(rnum) - s = self.GFn.value(snum) - - R = self.G * (m / s) + pubkey * (r / s) - - # alternative methods of verifying - # RORG= self.ec.decompress(r, 0) - # RR = self.G * m + pubkey * r - # print "#1: %s .. %s" % (RR, RORG*s) - # print "#2: %s .. %s" % (RR*(1/s), r) - # print "#3: %s .. %s" % (R, r) - if R.x == r: - print("=== Signature is Valid ===") - - return R.x == r - - def crack2(self, r, s1, s2, m1, m2): - """ - find signsecret and privkey from duplicate 'r' - signature (r,s1) for message m1 - and signature (r,s2) for message m2 - s1= (m1 + x*r)/k - s2= (m2 + x*r)/k - subtract -> (s1-s2) = (m1-m2)/k -> k = (m1-m2)/(s1-s2) - -> privkey = (s1*k-m1)/r .. or (s2*k-m2)/r - """ - sdelta = self.GFn.value(s1 - s2) - mdelta = self.GFn.value(m1 - m2) - - secret = mdelta / sdelta - x1 = self.crack1(r, s1, m1, secret) - x2 = self.crack1(r, s2, m2, secret) - - if x1 != x2: - print("x1=%s" % x1) - print("x2=%s" % x2) - - return (secret, x1) - - def crack1(self, rnum, snum, message, signsecret): - """ - find privkey, given signsecret k, message m, signature (r,s) - x= (s*k-m)/r - """ - m = self.GFn.value(message) - r = self.GFn.value(rnum) - s = self.GFn.value(snum) - k = self.GFn.value(signsecret) - return (s * k - m) / r - - -def secp256k1(): - """ - create the secp256k1 curve - """ - GFp = FiniteField(2 ** 256 - 2 ** 32 - 977) - ec = EllipticCurve(GFp, 0, 7) - return ECDSA( - ec, - ec.point( - 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798, - 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8, - ), - 2 ** 256 - 432420386565659656852420866394968145599, - ) - - -def verifytest(calced, expected, descr): - """ - verifytest is used to verify test results - """ - if type(calced) != type(expected): - if type(expected) == str: - calced = "%s" % calced - if calced != expected: - print("ERROR in %s: got %s, expected %s" % (descr, calced, expected)) - else: - return True - - -def test_dsa(): - dsa = secp256k1() - - priv = 0x12345 - pubkey = dsa.calcpub(priv) - signsecret1 = 0x1111 - signsecret2 = 0x2222 - - msg1 = 0x1234123412341234123412341234123412341234123412341234123412341234 - (r1, s1) = dsa.sign(msg1, priv, signsecret1) - check1 = dsa.verify(msg1, pubkey, r1, s1) - - msg2 = 0x1111111111111111111111111111111111111111111111111111111111111111 - (r2, s2) = dsa.sign(msg2, priv, signsecret1) - check2 = dsa.verify(msg2, pubkey, r2, s2) - - (crackedsecret, crackedprivkey) = dsa.crack2(r1, s1, s2, msg1, msg2) - if verifytest(crackedprivkey, priv, "crackedpriv"): - print("=== Cracked!!! ===\nThe Private Key is ", crackedprivkey.value) - - -def test_ff(): - ff = FiniteField(17) - assert ff.value(5) + ff.value(15) == ff.value(3) - assert ff.value(5) * ff.value(15) / ff.value(15) == ff.value(5) - print("test_ff() passed") - - -def test_curve(): - dsa = secp256k1() - G2 = dsa.G * 2 - assert G2 == dsa.G + dsa.G - assert G2.x == 0xC6047F9441ED7D6D3045406E95C07CD85C778E4B8CEF3CA7ABAC09B95C709EE5 - assert G2.y == 0x1AE168FEA63DC339A3C58419466CEAEEF7F632653266D0E1236431A950CFE52A - G20 = dsa.G * 20 - assert G20.x == 0x4CE119C96E2FA357200B559B2F7DD5A5F02D5290AFF74B03F3E471B273211C97 - assert G20.y == 0x12BA26DCB10EC1625DA61FA10A844C676162948271D96967450288EE9233DC3A - Gx = dsa.G * 112233445566778899 - assert Gx.x == 0xA90CC3D3F3E146DAADFC74CA1372207CB4B725AE708CEF713A98EDD73D99EF29 - assert Gx.y == 0x5A79D6B289610C68BC3B47F3D72F9788A26A06868B4D8E433E1E2AD76FB7DC76 - print("test_curve() passed") - - -if __name__ == "__main__": - test_ff() - test_curve() - test_dsa() diff --git a/crypto/ECC/sign.md b/crypto/ECC/sign.md deleted file mode 100644 index 0989653ba..000000000 --- a/crypto/ECC/sign.md +++ /dev/null @@ -1,147 +0,0 @@ -# 以太坊签名函数实操 - -> 函数式编程是有别于传统的面对对象范式的编程范式,函数式方向是目前编程语言发展的大方向,所有新设计的编程语言都或多或少的引入了函数式编程功能。 - - - -前文索引: - -> [理解以太坊合约数据读取过程 | 函数式与区块链(二)](http://mp.weixin.qq.com/s?__biz=MzI0NTM0MzE5Mw==&mid=2247485420&idx=1&sn=1149067c6a0bfb13bde552bb5721eefd&chksm=e94eb15ade39384c9e68e2bd6bf321640b5da57eefc828ff92b24669fe6e4aa93468464f74e3&scene=21#wechat_redirect) -> - -本篇描述 Rust 两种函数式编程语言下 ECDSA 算法下使用 Secp256k1 签名的过程。 - -本文侧重相关库的使用,相关原理解析可见: - -> 一个数字引发的探索——ECDSA 解析: -> -> https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/articles/3_features/36_cryptographic/ecdsa_analysis.html?highlight=v%20r%20s -> -> 一场椭圆曲线的寻根问祖之旅: -> -> https://fisco-bcos-documentation.readthedocs.io/zh_CN/dev/docs/articles/3_features/36_cryptographic/elliptic_curve.html - - -在 Rust 中,使用了`secp256k1`库与`bitcoin_hashes`库: - -```rust -# cargo.toml -[dependencies] -secp256k1 = {version = "0.20.3", features = ["rand-std", "recovery"] } -bitcoin_hashes = "0.9" -``` - -完整实现见: - -> https://github.com/leeduckgo/secp256k1-example-rs - -## 未压缩的签名 - -未压缩的签名即是简单粗暴的直接用私钥(privkey)给信息(message)进行签名,签名字节数可能是 71、72 或 73。 - - -### Rust 中的实现 - -```rust -///https://github.com/leeduckgo/secp256k1-example-rs/blob/main/src/main.rs - -fn main(){ - let (seckey, pubkey) = generate_keys(); - let digest = b"This is some message"; - let sig = sign(digest, seckey); - let serialize_sig = sig.serialize_compact().to_vec(); - verify(digest, serialize_sig, pubkey); -} - -///https://github.com/rust-bitcoin/rust-secp256k1/blob/master/examples/sign_verify.rs -fn sign(digest: &[u8], seckey: SecretKey) -> Signature { - let secp = Secp256k1::new(); - let signature = do_sign(&secp, digest, seckey).unwrap(); - println!("signature: {:?}", signature); - signature -} - -fn verify(digest: &[u8], sig: Vec, pubkey: PublicKey){ - let secp = Secp256k1::new(); - let result = do_verify(&secp, digest, sig, pubkey).unwrap(); - println!("verify result: {:?}", result) -} - -fn do_sign(secp: &Secp256k1, digest: &[u8], seckey: SecretKey) -> Result { - let digest = sha256::Hash::hash(digest); - let digest = Message::from_slice(&digest)?; - Ok(secp.sign(&digest, &seckey)) -} - -fn do_verify(secp: &Secp256k1, digest: &[u8], sig: Vec, pubkey: PublicKey) -> Result { - let digest = sha256::Hash::hash(digest); - let digest = Message::from_slice(&digest)?; - let sig = Signature::from_compact(&sig)?; - - Ok(secp.verify(&digest, &sig, &pubkey).is_ok()) -} -``` - -## 压缩的签名 - -通过压缩签名算法(sign_compact),会生成 v, r, s。r 和 s 拼凑起来是签名本体,v 的全称是 Recovery ID,起到从签名中恢复公钥的作用。 - -> 对比比特币签名,以太坊的签名格式是`r+s+v`。 r 和 s 是 ECDSA 签名的原始输出,而末尾的一个字节为 recovery id 值,但在以太坊中用`V`表示,v 值为 1 或者 0。recovery id 简称 recid,表示从内容和签名中成功恢复出公钥时需要查找的次数(因为根据`r`值在椭圆曲线中查找符合要求的坐标点可能有多个),但在比特币下最多需要查找两次。这样在签名校验恢复公钥时,不需要遍历查找,一次便可找准公钥,加速签名校验速度。 -> -> —— https://learnblockchain.cn/books/geth/part3/sign-and-valid.html - -压缩签名的长度是 r 和 s 各是 32 字节,v 是 1 字节,总共是 65 字节。 - - -### Rust 中的实现 - -压缩签名函数实现: - -```rust -fn sign_compact(digest: &[u8], seckey: SecretKey) -> (RecoveryId, Vec) { - let secp = Secp256k1::new(); - let signature = do_sign_compact(&secp, digest, seckey).unwrap(); - let (recovery_id, serialized_sig) = signature.serialize_compact(); - println!("signature compacted: {:?}", serialized_sig); - println!("recovery id: {:?}", recovery_id); - (recovery_id, serialized_sig.to_vec()) -} - -fn do_sign_compact(secp: &Secp256k1, digest: &[u8], seckey: SecretKey) -> Result { - let digest = sha256::Hash::hash(digest); - let digest = Message::from_slice(&digest)?; - Ok(secp.sign_recoverable(&digest, &seckey)) -} -``` - -公钥恢复函数: - -```rust -fn recover(digest: &[u8],sig: Vec,recovery_id: RecoveryId) { - let secp = Secp256k1::new(); - let pubkey = do_recover(&secp, digest, sig, recovery_id); - println!("pubkey recovered: {:?}", pubkey) -} -fn do_recover(secp: &Secp256k1,digest: &[u8],sig: Vec,recovery_id: RecoveryId) -> Result { - let digest = sha256::Hash::hash(digest); - let digest = Message::from_slice(&digest)?; - let sig = RecoverableSignature::from_compact(&sig, recovery_id)?; - - secp.recover(&digest, &sig) -} -``` - -完整主函数(main): - -```rust -fn main(){ - let (seckey, pubkey) = generate_keys(); - let digest = b"This is some message"; - let sig = sign(digest, seckey); - let serialize_sig = sig.serialize_compact().to_vec(); - verify(digest, serialize_sig, pubkey); - let (recovery_id, sig_compact) = sign_compact(digest, seckey); - verify(digest, sig_compact.clone(), pubkey); - recover(digest, sig_compact, recovery_id); -} -``` diff --git a/crypto/ECC/test.py b/crypto/ECC/test.py deleted file mode 100644 index 84f9412da..000000000 --- a/crypto/ECC/test.py +++ /dev/null @@ -1,34 +0,0 @@ -import unittest -from binascii import hexlify, unhexlify -from fastecdsa import keys, curve -from fastecdsa.encoding.sec1 import InvalidSEC1PublicKey, SEC1Encoder -from ecc_secp256k1 import ECC256k1 - -PRIV_KEY = 0x92c0302c1fff4679f4c98684ff368fdbe04da815e6de24d246793f5812577016 - -pub_key = keys.get_public_key(PRIV_KEY, curve.secp256k1) -uncompressed_pubkey = (hexlify(SEC1Encoder.encode_public_key(pub_key, compressed=False))).decode() -compressed_pubkey = (hexlify(SEC1Encoder.encode_public_key(pub_key))).decode() - -print("私钥:", PRIV_KEY) -print("公钥:" , pub_key) -print("未压缩公钥:", uncompressed_pubkey) -print("压缩公钥:", compressed_pubkey) - -ecc = ECC256k1() -publicKey = ecc.publicKey(PRIV_KEY) -uncompressedPubkey = ecc.uncompressedPubkey(publicKey) -compressedPubkey = ecc.compressedPubkey(publicKey) - -class TestEccSecp256k1(unittest.TestCase): - - def test_uncompressed_pubkey(self): - self.assertEqual(uncompressedPubkey, uncompressed_pubkey, "未压缩公钥不相等") - - def test_compressed_pubkey(self): - self.assertEqual(compressedPubkey, compressed_pubkey, "压缩公钥不相等") - -if __name__ == '__main__': - unittest.main() - -# https://github.com/AntonKueltz/fastecdsa diff --git a/crypto/Groth16/readme.md b/crypto/Groth16/readme.md deleted file mode 100644 index e69de29bb..000000000 diff --git a/crypto/Halo2/readme.md b/crypto/Halo2/readme.md deleted file mode 100644 index 02ff0f53b..000000000 --- a/crypto/Halo2/readme.md +++ /dev/null @@ -1,67 +0,0 @@ -## plonkish and halo2 -中文文档:https://trapdoor-tech.github.io/halo2-book-chinese/index.html -实操demo: https://trapdoor-tech.github.io/halo2-book-chinese/user/simple-example.html -trapdoor bilibili: - -PSE: -Halo 2 - with PSE, Present by CC Liang: https://www.youtube.com/watch?v=ihPcnctm4q4&t=12s -plookup: -系统性课程0xparc: https://learn.0xparc.org/circom/ -tutorial: https://github.com/icemelon/halo2-tutorial/ - -halo2 tutorial& gitbook: https://erroldrummond.gitbook.io/halo2-tutorial/ - -## 基本概念 - -Halo2: ultraPlonk + 嵌套均摊技术 -three components: -arithmetisation , polynomial commitment scheme(inner product argument), accumulation scheme(recursion) - -plonk -> TurboPlonk(with custom constraints) -> UltraPlonk(lookup table) -**vanilla plonk**: -ql*Xa + qr*Xb +qm*XaXb+qo*Xc=0 -**TurboPLONK(GW19)**: -each wire(column is encoded as a Lagrange polynomial) - -**UltraPLONK** -lookup table -qlookup*a0+(1-qlookup) -三个特性: - 1. 采用plonk约束系统 - 2. 采用lookup table - 3. 支持custom gate - 4. 模块化设计(多项式承诺方案采用KZG) - -advice: private ,witness -instance: public input ,output -fixed: lookup -selector: bool value ,to control the custom gate wheather turn on or off - -loopup arguments: - - useful for range check and bitwise operations - - -### 编程 -- configure - 1. 申请 advice, instance , fixed , columns - 2. 定义custom gate - 3. 定义lookup关系式 -- synthesize() - 1. 分配region; - 2. 给region中的变量赋值 - -Three steps to implement a circuit -- 1. define a config struct that includes the columns used in circuit -- 2. define a chip struct that configures the constraints in the circuit and providers assignment functions - -- 3. deine a circuit struct that implements the circuit trait and instantiates a circuit -instance that will be fed into the prover - - - -## 参考链接 -- PPT: https://docs.google.com/presentation/d/1H2BziGitl16ARRgBwIZV5sYD_Xj16Zw0PfTRBl0_CxM/edit#slide=id.g132fa596714_0_0 -- Halo2 Learning Group Homespace: https://0xparc.notion.site/Halo2-Learning-Group-Homespace-32b6c45eeaa84c3baa01015da98f3ab4 -- 星想法halo2: https://space.bilibili.com/596457384 -- AppliedZKP zkEVM Circuit Code: A Guide: https://hackernoon.com/appliedzkp-zkevm-circuit-code-a-guide -- rust-zk 库: https://github.com/orgs/arkworks-rs/repositories?type=all \ No newline at end of file diff --git a/crypto/Mina/README.md b/crypto/Mina/README.md deleted file mode 100644 index 59b1b94fd..000000000 --- a/crypto/Mina/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# MINA - -- [Mina Intro](./docs/mina.md) - -## Mina workshop - -- youtube: -- ppt: - -## Reference - -- mina 介绍: -- mina zk: https://o1-labs.github.io/proof-systems/introduction.html -- snapps: -- SnarkyJS: -- snapps: - -- Snapp Developer Resource Kit : - diff --git a/crypto/Mina/docs/mina.md b/crypto/Mina/docs/mina.md deleted file mode 100644 index 0288a0278..000000000 --- a/crypto/Mina/docs/mina.md +++ /dev/null @@ -1,634 +0,0 @@ -# Mina - -## 什么是 Mina? - -Mina 是第一个支持精简区块链概念的加密货币协议。当前的加密货币区块链存储了数百 GB 的数据, 同时随着时间的推移,区块链的大小会不断增长。然而,无论使用量增长多少,Mina 区块链可以始终保持同样的大小 - 大概 22kb。这意味着参与者可以快速同步和验证区块网络。 - -支持 Mina 实现精简区块的关键是 zk-SNARKs(一种精简的加密证明)。每次 Mina 节点生成一个新的区块时,它同样会生成一个 SNARK 证明,用于验证该区块是否有效。然后所有节点可以存储这个占比很小的 SNARK 证明,而不是存储整个区块链数据。由于不再担心区块的大小,Mina 协议支持区块链在扩展时同样保持着去中心化特性。 - -默认情况下,Mina 节点是非常精简的, 它们并不需要存储关于网络、区块、交易相关的历史信息。但对于某些情况下,我们需要存储这些历史信息,这时我们可以通过运行 Mina 档案节点来实现它。 - -Mina 档案节点是在普通的 Mina 节点守护进程上,连接一个运行着的档案进程。Mina 守护进程会定时持续发送区块链数据给档案进程,档案进程再将此数据保存在 [Postgres](https://www.postgresql.org/) 数据库内。 - -因此,运行一个档案节点会需要您了解如何管理 Postgres 数据库实例。 若是想了解如何设置 Postgres 数据库,运行档案节点,可以查看[如何运行一个档案节点](https://docs.minaprotocol.com/en/advanced/archive-node)。 - -对于如何开始搭建 Mina, 生成密钥对,连接至主区块网络进行付款等具体操作命令,可以查看以下链接: - -- [安装搭建 Mina](https://docs.minaprotocol.com/en/getting-started) -- [如何生成密钥对](https://docs.minaprotocol.com/en/using-mina/keypair) -- [连接至主区块网络](https://docs.minaprotocol.com/en/using-mina/connecting) -- [使用 Mina 进行交易付款](https://docs.minaprotocol.com/en/using-mina/send-payment) -- [赌注 Mina 参与共识](https://docs.minaprotocol.com/en/using-mina/staking) -- [命令行界面](https://docs.minaprotocol.com/en/using-mina/cli-reference) - -接下来,将从 Mina 协议的架构简要介绍,再到协议的具体相关实现,最后讲述基于 Mina 链上的 Snapps 概念。 - -## Mina 协议架构 - -Mina 协议架构中包含几个关键的模块, 分别为区块(Block), 区块生产者(Block Producer), 共识机制(Consensus), Snark 工作者(Snark Workers), 扫描状态(Scan State), 和代币(Token)。 这些模块共同协作支持整个协议的正常运行。 - -### 区块(Block) - -区块链中的每个区块包含了许多交易信息和共识信息,共同组合成当前状态的区块链。Mina 的区块中还包含了一个证明(zkSnark proof), 以证明当前区块链的状态是有效的。 - -当一个 Mina 节点接收到来自于另一个节点(Peer)的新区块时,这个区块会首先被验证,然后再更新当前区块状态,最后添加至这个节点的区块本地存储内, 又名过渡边界结构内(Transition Frontier)。如果基于共识规则,此区块导致当前区块链的长度增加,那么这个节点的链上数据将被更新,区块边界指标将上移,保持着区块边界结构内始终只包含 k 个区块。 - -目前,每个 Mina 区块由以下部分组成: - -- 协议状态 - - 协议状态由先前的协议状态哈希和包含以下内容的数据结构组成: - - - 创世状态哈希(Genesis State Hash): 创世状态哈希是创世协议状态的协议状态哈希。 - - 区块链状态: 包括 1) 分阶段的账本哈希(Staged ledger hash), 2) Snarked 账本哈希(Snarked ledger hash), 3) Snarked 下一个可用令牌(Snarked next available token), 4) 创世账本哈希, 5) 时间戳。 - - 共识状态: 包括 1) 区块链长度, 2) 纪元计数(Epoch count), 3) 最小窗口密度, 4) 子窗口密度, 5) 最后一个 VRF 输出, 6) 总货币, 7) 当前全局插槽, 8) 自创世以来的全球插槽, 9) 质押纪元数据, 10) 下一个纪元数据, 11) 在同一个检查点窗口中是否有祖先, 12) 区块质押赢家, 13) 区块创建者, 14) 币库接收者, 15) 增压币库。 - - 共识常数: 参考 [共识参数](https://docs.minaprotocol.com/en/architecture/whats-in-a-block#consensus_state) 查看具体的常数列表。 - - 每个区块都包含前一个区块的协议状态哈希,这样区块即可链接在一起形成一个不可变的区块链。协议状态哈希是根据前一个状态的哈希列表和主体进行再次哈希而确定的,同时它是作为每个区块的唯一标识符。 - -- 协议状态证明 - - 协议状态证明是证明区块生产者生成的新协议状态有效的区块链证明。由于使用了递归 SNARK,这个协议状态证明证明了整个链的历史是有效的。 - -- 分阶段账本差异 - - 当区块生产者赢得一个槽(Slot)来生产一个区块时,他们会从交易列表池和 snark 池中选择所需的交易列表和 snark。他们会产生一个待定的区块链下一状态,其中包括创建分阶段分类账的差异。这些差异包含: - - - 区块中包含的交易 - - 添加了由 snark 工作人员为先前交易生成的 SNARK 证明列表 - - 待定的币库(coinbase) - - 分阶段账本可以被视为一个待处理的账户数据库,其中的交易列表(比如支付、币和证明费用支付)暂无 SNARK 证明。换言之,它包括账户状态(账本)和一个没有 SNARK 证明的交易队列, 这个交易队列又名为扫描状态。 - -- Delta 过渡链证明 - - 通常,在网络中同步新产生的区块时,基于会出现不良好的网络条件的考虑,Mina 会允许一定的网络延迟。而 Delta 过渡链证明证明该块是在分配的时间段内产生的。 - -- 当前协议版本 -- 提议的协议版本 - -以下举例一个具体的块实例: - -```json -{ - "external_transition": { - "protocol_state": { - "previous_state_hash": "3NLKJLNbD7rBAbGdjZz3tfNBPYxUJJaLmwCP9jMKR65KSz4RKV6b", - "body": { - "genesis_state_hash": "3NLxYrjb7zmHdoFgBrubCN8ijM8v7eT8kvLiPLc9DHt3M8XrDDEG", - "blockchain_state": { - "staged_ledger_hash": { - "non_snark": { - "ledger_hash": "jxV4SS44wHUVrGEucCsfxLisZyUC5QddsiokGH3kz5xm2hJWZ25", - "aux_hash": "UmosfM82dH5xzqdckXgA1JoAvJ5tLxch2wsty4sXmiEPKnPTPq", - "pending_coinbase_aux": "WLo8mDN6oBUTSyBkFCy7Fky7Na5fN4R6oGq4HMf3YoHCAj4cwY" - }, - "pending_coinbase_hash": "2mze7iXKwA9JAqVDC1MVvgWfJDgvbgSexKtuShdkgqMfv1tjATQQ" - }, - "snarked_ledger_hash": "jx9171AbMApHNG1guAcKct1E6nyUFweA7M4ZPCjBZpgNNrE21Nj", - "genesis_ledger_hash": "jxX6VJ84HaafrKozFRA4qjnni4aPXqXC2H5vQLKSryNpKTXuz1R", - "snarked_next_available_token": "2", - "timestamp": "1611691710000" - }, - "consensus_state": { - "blockchain_length": "3852", - "epoch_count": "1", - "min_window_density": "1", - "sub_window_densities": ["3", "1", "3", "1", "4", "2", "1", "2", "2", "4", "5"], - "last_vrf_output": "g_1vrXSXLhvn1e4Ap1Ey5e8yh3PFMJT0vZyhZLlTBAA=", - "total_currency": "167255800000001000", - "curr_global_slot": { - "slot_number": "12978", - "slots_per_epoch": "7140" - }, - "global_slot_since_genesis": "12978", - "staking_epoch_data": { - "ledger": { - "hash": "jxX6VJ84HaafrKozFRA4qjnni4aPXqXC2H5vQLKSryNpKTXuz1R", - "total_currency": "165950000000001000" - }, - "seed": "2vb1Mjvydod6sEwn7qpbejKCfRqugMgyG3MHXXRKcAkwQLRs9fj8", - "start_checkpoint": "3NK2tkzqqK5spR2sZ7tujjqPksL45M3UUrcA4WhCkeiPtnugyE2x", - "lock_checkpoint": "3NK5G8Xqn1Prh3XoTyZ2tqntJC6X2nVwruv5mEJCL3GaTk7jKUNo", - "epoch_length": "1769" - }, - "next_epoch_data": { - "ledger": { - "hash": "jx7XXjRfJj2mGXmiHQmpm6ZgTxz14udpugyFtw4DefJFpie7apN", - "total_currency": "166537000000001000" - }, - "seed": "2vavBR2GfJWvWkpC7yGJQFnts18nHaFjdVEr84r1Y9DQXvnJRhmd", - "start_checkpoint": "3NLdAqxtBRYxYbCWMXxGu6j1hGDrpQwGkBDF9QvGxmtpziXQDADu", - "lock_checkpoint": "3NL4Eis1pS1yrPdfCbiJcpCCYsHuXY3ZgEzHojPnFWfMK9gKmhZh", - "epoch_length": "2084" - }, - "has_ancestor_in_same_checkpoint_window": true, - "block_stake_winner": "B62qpBrUYW8SHcKTFWLbHKD7d3FqYFvGRBaWRLQCgsr3V9pwsPSd7Ms", - "block_creator": "B62qpBrUYW8SHcKTFWLbHKD7d3FqYFvGRBaWRLQCgsr3V9pwsPSd7Ms", - "coinbase_receiver": "B62qpBrUYW8SHcKTFWLbHKD7d3FqYFvGRBaWRLQCgsr3V9pwsPSd7Ms", - "supercharge_coinbase": true - }, - "constants": { - "k": "290", - "slots_per_epoch": "7140", - "slots_per_sub_window": "7", - "delta": "0", - "genesis_state_timestamp": "1609355670000" - } - } - }, - "protocol_state_proof": "", - "staged_ledger_diff": "", - "delta_transition_chain_proof": "", - "current_protocol_version": "1.1.0", - "proposed_protocol_version": "" - } -} -``` - -### 区块生产者(Block Producer) - -Mina 中区块生产者的作用是达成共识并为区块链提供安全性。区块生产者负责创建新区块,其中包括在网络上广播的最新交易以及可用于证明当前区块链状态有效性的区块链证明。在 Mina,任何人都可能成为区块生产者。有无限数量的参与者有机会产生与所押资金成正比的区块。资金不会被锁定,也不会受到削减。作为抵押资金和生成所需的区块链证明的回报,那些被创造和包含在当前有效区块链的区块将会获得奖励,奖励以币和交易费用的形式发放。 - -区块生产者需更新至区块链的最新状态后才可以成功产生新的区块。同时,他们也必须有足够的算力在规定的时间内计算出区块链 SNARK 证明,然后在可接受的延迟内连接到其他节点以广播新生成的区块。 - -#### 选择区块生产者的策略 - -在规定时间内生成一个区块的机会是由可验证随机函数(VRF) 决定的。你可以把它理解成类似抽彩票一样。每个区块生产者在每个区间(slot)内独立运行 VRF 函数,如果在某个区间运行的结果大于生产者的质押比例阈值,那他们就有机会在这个区间产出一个区块。 - -此过程是私密的,只有私钥持有者可以确定 VRF 的结果输出,因此只有他们知道何时他们可以产出一个区块。第三方也无法通过拒绝服务或有针对性的攻击对在某个区间内的指定区块生产者进行攻击,这一定程度上提高了安全性。从结果上来看,它同样意味着可以为同一个区间(slot)选择多个区块生产者。如果多个区块生产者为同一个区间均产出有效的区块,那么将会有一个短程的分叉,然后会由共识规则来选择最长的链以确定最终区块生成者。 - -关于质押分配,它是由 (当前纪元(epoch)数 - 2) 的最新区块上的 snarked 账本来确定的。因此在获取最新赢得的或委托的质押值时会存在一定的延迟。例如,如果当前纪元数为 10,那么质押分配将会由第 8 个纪元的最新区块上的 snarked 账本确定。 - -#### 如何生成一个区块 - -当一个区块生产者被选中来为一个区间(slot)生产一个区块时,通常会有以下步骤: - -- 从节点的区块本地存储(区块过渡边界结构, Transition Frontier)内选择最佳的新增区块位置。 -- 从交易池和 snark 池中选择所需的交易列表和 snark 工作量。任何交易都需要一定的 snark 工作量,因此区块生产者最少需购买能支付他们用于把区块添加到区块链上的 snark 费用。 -- 生成一个待定的区块链下一状态。这包含创建阶段性账本的差异(diff), 这些差异包含账户账本和扫描状态(尚未有证明 proof 的交易队列). 这个 diff 用于在当前阶段性账本的基础上生成一个新的区块链的下一个状态。 -- 创建一个区块链证明(snark proof)以验证区块链的新状态是有效的。同时这个证明还递归验证了之前的协议状态证明。 -- 如果在网络共识参数定义的可接受的网络延迟内收到新区块,则创建一个增量转换链证明,证明该块的有效性。 -- 在本地确定更新这个新区块状态,同时添加到节点的区块本地存储内(区块过度边界结构, Transition Frontier)。 -- 想其他节点(peer)广播这个新区块(会被视为外部转换)。 - -## 共识机制(Consensus) - -共识指的是网络中参与者确定什么信息会被保留在区块链中的过程。在像区块链这样的系统中,使用新信息扩展区块链的责任分布在整个网络的参与节点之间。所有的节点不能被默认假设为"诚实"节点,因此那些真正的"诚实"节点需要合作来确定哪些信息是需要被保存在链上的。目前存在着很多方法来取得这种分布式的共识,我们把这些方法统称为共识机制。Mina 在代码层面上抽象出共识机制模块,用单一接口来取得与其他模块的互动。同样,这个接口允许有不同的具体实现。最后实现将共识机制作为基础模块支撑整个协议的目的。 - -### 质押证明(Proof of Stake) - -目前 Mina 的共识机制是基于质押证明 Proof of Stake 来实现的。具体的实现是基于 Ouroboros Praos 协议的某个版本进行拓展和修改,以支持 Mina 的精简区块链特性。有关 Ouroboros 协议的完整说明,请参阅原始 Ouroboros 论文: [Ouroboros](https://eprint.iacr.org/2016/889.pdf) 和 [Praos](https://eprint.iacr.org/2017/573.pdf)。 - -在 Ouroboros 中,节点需要在上一个纪元开始时实现/保留分类帐,以便进行 VRF 评估。这是因为仅仅有 VRF 输出不足以知道一个区块是"诚实"提出的。为了确定区块是否由提议该区块的节点所赢得,VRF 输出必须低于提议者的质押比例阈值。但是在一个精简的区块链上, 如 Mina, 保存过去的账本并不是一件容易的事。与其他链不同,Mina 节点不能随意请求链上的历史片段,来重新组合成他们感兴趣的信息。这意味着如果不采取一定的优化方式,那么将会需要 3 份的全账本拷贝,同时需要等待 2 个纪元的时间才可访问链上数据。显然,这是不可行的。 - -默认情况下,在 Ouroboros 中,每个节点在收到新区块时都需要验证区块提议者是否赢得了该区块,这意味着他们必须查看评估 VRF 的公钥的余额。然而在 Mina 中,VRF 评估的准确性可以由 snark 计算得出,因此其他节点只需验证 snark 即可确定区块是否由提议者赢得。由于提议者可通过 snark 自我证明,那就可以大大缩小链上关于纪元账本的存储信息。只需存储指定的账户和相关的 merkle 路径。另外, Ouroboros 需要 2 个纪元的时间来最终确定交易,那对于 Mina 节点可以等待交易最终确定后再确定 snark, 这进一步缩小了所需的存储空间。最终这个 snark 证明将会证明: 1) 对于指定的公钥,VRF 评估是准确的, 2) 纪元账本上的公钥账户,其余额创建的 VRF 阈值大于 VRF 输出(使用默克尔路径从账户中证明纪元分类账的默克尔根)。(note: 这并没有立即解决提议者节点需要在线足够长的时间才能存储这些必要信息的问题,但它开辟了提议者获取该信息的其他途径,主要包括提议者可以请求一个账户记录和默克尔路径,证明它存在于指定的纪元账本中。) - -### 数据和钩子 - -共识机制影响着协议的许多方面。我们将共识机制的规定分为两部分:数据(可用的数据结构和可用的交互)和钩子(基于共识机制上的协议调用的特定顶层钩子)。这些基于共识机制的数据结构对外部保持抽象,然后由钩子消费实现具体行为。 - -数据主要包括: - -- Local_state - Local_state 是只存储在机器本地的共识相关状态。它提供了一个达成共识的地方,以在协议状态的终结点上跟踪有关本地节点的一些信息。更多具体使用可以参考 frontier_root_transition 钩子 -- Consensus_transition_data - - Consensus_transition_data 是包含在 Snark_transition 结构内. 它帮助提供额外信息以验证一个转换是否有效。与 Consensus_state 不同, Consensus_transition_data 中的信息仅由创建转换的节点使用,其他节点不可用。 - -- Consensus_state - - Consensus_state 包含在 Protocol_state 协议中。它为共识机制提供了一个存储信息的地方,这些信息在协议的每个状态下都可用,并且可以在 snark 中得到证明。由于它包含在 Protocol_state 中,因此网络上的其他节点可以检查此信息。 - -钩子 Hooks 主要包括: - -- generate_transition() - - 该 generate_transition 钩子完全生成新的协议状态和共识转换数据,以此作为链上先前协议状态的扩展。该 hook 将会获得新的区块链状态,新的待引入的交易列表以及相关提议数据。该钩子主要由提议者调用来获取转换的相关数据。提议者应该与 next_proposal 钩子交互以确定何时应该调用此钩子。 - -- next_proposal() - - next_proposal 钩子可用于告知协议何时可以生产和提议下个转换。它返回一个具体的可提议下一个转换的时间,或者告知下一个时间点再次尝试调用该钩子以获取具体时间点。这将给共识机制更大的灵活度以及根据协议的其他信息进行更好的提案调度。 - -- next_state_checked() - - 该 next_state_checked 钩子返回一个检查计算,其计算/制约了给予其前任的过渡 blockchain 序列中的下一个共识状态。该钩子包含在构成区块链 snark 约束系统的检查计算中。因此,这是对共识状态执行验证的主要功能。 - -- select() - - select 钩子会从共识机制的角度选择更为何时的状态。这个钩子主要负责在多条链中哪条链应被保留,被调用后会返回是否保留当前状态链,或选取新状态链,它在共识达成的过程中扮演了重要的角色。 - -- received_at_valid_time() - - 该 received_at_valid_time 钩子用于表明一个给定的共识状态在给定时间内是否有效。每次网络接收到新的转换,协议都应该调用此钩子以确定有效性。 - -- frontier_root_transition() - - 当状态转换最终确定时,协议应当调用此钩子以更新本地状态。 - -- should_bootstrap() - - should_bootstrap 钩子通知协议是否需要在收到状态转换时启动节点引导程序,将节点更新至最新的区块链状态。此钩子应在每次收到状态转换和初始验证成功后被调用。 - -## Snark 工作者(Snark Workers) - -大多数区块链协议只有一个主要的节点操作员群体(通常成为矿工、验证器或区块生产者), Mina 会有另外一个群体 - Snark 工作者。Snark 工作者对于 Mina 区块网络的健康至关重要,因为他们负责对网络中的交易进行 SNARK 证明或生成 SNARK 证明。通过生成这些证明,snark 工人有助于保持 Mina 区块链的简洁性。 - -Mina 区别于其他区块链的特性是它的精简性。每个区块生产者在向网络提议新区块时,还必须包含一个针对该区块的 zk-SNARK 证明。这允许节点丢弃所有已完成的历史数据,只保留 SNARK。如果您不熟悉 Mina 协议,可以看下这个 [视频](https://www.youtube.com/watch?v=eWVGATxEB6M)。 - -然而,仅仅只有针对区块的 Snark 证明时不够的,区块内的交易列表同样需要计算其 Snark 证明,因为区块链 Snark 证明 没有对包含在区块中的交易的有效性做出任何声明。举个例子, 若当前区块头部的状态哈希为(a6f8792226xxx), 然后我们收到一个具有(0ffdcf284fxxx)的状态哈希的新块。这区块内部包含区块生产者选择包含在该区块中的所有交易以及相关的元数据,另外还会有用于验证声明的随附 Snark: - -“存在一个状态哈希为(0ffdcf284fxxx)的区块,它是在区块头部状态哈希为(a6f8792226xxx)的区块链上附加上的。” - -我们会发现这个证明并没有说明任何区块内部的交易的有效性。因此存在第三方替换区块内交易数据再用原生的 Snark 证明广播的问题进而欺骗其他节点。因此,若我们不采取类似其他区块链携带内部完整的交易列表来验证交易的有效性,我们需要对内部的交易列表也进行 Snark 证明。 - -### Snark 交易 - -Snark 交易可以针对每个交易进行 Snark 证明,然后再组合起来。然而,计算 Sanrk 证明是耗费高算力的,如果对每个交易都进行 Snark 证明,那整体吞吐量会很低,同时出块时间也会猛增。此外,现实世界环境中的事务是异步进行的,因此很难预测何时执行下一项工作。 - -幸运的是,我们可以利用 Snark 的两个特性来解决上述问题: - -1. Snark 证明可以被合并 — 两个证明可以合并形成一个合并证明 -2. Snark 合并证明支持无序合并 - 无论合并顺序如何,Snark 合并证明都是相同的 - -![](https://docs.minaprotocol.com/static/img/docs-images/Documents_FAQFork_Mobile%201.jpg) - -这两个属性本质上支持了 Snark 证明的并行操作。如果可以合并证明,并且它们如何组合并不重要,那么可以并行生成 Snark 证明。先完成的证明可以稍后与正在进行的证明结合。这可以被想象成一个二叉树,其中底行(叶子)由单独的交易证明组成,每个父行由各自的合并证明集组成。我们可以将这些一直组合到根,它代表通过应用所有事务执行的状态更新。 - -此外,因为 Snark 证明不相互依赖,我们可以利用并行性,这意味着任何人都可以完成这项工作。最终结果是分布式工作池是无权限的。任何拥有空闲计算能力的人都可以作为 Snark 工作者加入网络,观察需要被 snark 处理的事务,并贡献他们的计算量。当然,他们将因在 snarketplace 的工作而获得报酬。 - -### Snark 市场 - -Snark 工作的另一个关键点是:区块生产者使用他们的区块奖励从 Snark 工人那里购买 snark 工作量。 - -Mina 协议没有参与对 Snark 工作量的定价,也没有对 Snark 工人生产 Snark 进行任何协议级别的奖励。激励纯粹是点对点的,并且在公共市场(又名 Snark 市场, Snarketplace)中动态建立。 - -你可能会问,为什么区块生产者需要购买 Snarks?好问题 - 原因是区块内部的交易需要被 Snark 证明以验证当前区块链的状态是有效的。此外,为了使区块内不断增加的交易及时被验证,我们需要将 Snark 的验证速度与交易的添加速度对齐,以避免积累过多未验证的交易导致这些交易最终未被验证。 - -由于区块生产者通过将交易打包在一个区块中(通过交易费用和币交易)来获利,因此他们也有责任通过购买相同数量的已完成的 Snarks 来维持区块状态的有效性,而这也创造了对 Snarks 的需求。当然,区块生产者作为买方希望从 Snark 市场以最低价格购买 Snark。另一方面,Snark 工作者希望最大化他们的利润, 这两个角色充当市场的两侧,随着时间的推移,以市场价格为 Snark 市场建立均衡。 - -### 如何为 Snark 工作量定价 - -我们预计 Snark 市场中的价格遵循简单的供求规律动态平衡。虽然每个 snark 工作适用于不同的交易,但从更大的角度来看,snark 工作在很大程度上是一种商品(这意味着哪个 snark 工人生产商品并不重要——它会是一样的)。但是,存在一些细微差别,因此对定价策略进行一些说明可能会有所帮助: - -- 如果市场价格为 X,那么以低于 X 的任何价格(例如 X - 1)出售 Snark 工作可能是有效的,前提是它在扣除运营费用后是有利可图的。 -- 区块生产者被激励从同一个 Snark 工作者那里购买更多单位的 Snark 工作量,因为这样会省部分转移交易的费用。 - - 基本上,区块生产者支付 Snark 工作者的方式是通过一种称为费用转移的特殊交易。区块生产者的动机是尽量减少费用转移的数量,因为每笔交易都是需要添加到区块中的哈希交易。因此,最好的情况是从同一个 Snark 工人那里购买 Snark 工作量。 -- 一些 Snark 工作量在其他工作之前完成会更重要,因为它会释放整个树的内存(有关更多详细信息,请参见上面的视频)。这是通过不同的工作选择方法实现的。目前支持的两种方法是顺序和随机。然而,这些都没有利用动态市场,这部分之后可以由 Mina 社区进行改善支持。 - -由于有关 Snark 和价格的所有数据都是公开的,因此有很多方法可以检查 Snark 市场的真实性。一个示例是使用 GraphQL API,其他选项包括使用 CLI,或可以自定义解决方案以跟踪 Snark 内存池中的 Snark。 - -## 扫描状态 - -扫描状态是一种支持将交易 Snark 证明的生产从区块生产者中解耦到 Sanrk 工作者的数据结构。 - -由于区块生产者不再需要产生这些交易 Snark,因此无论交易吞吐量如何,区块生产时间都可能保持不变。此外,扫描状态这个数据结构支持由多个竞争的 Snark 工作者并行生成和处理针对交易的 Snark 证明。 - -扫描状态由众多全二叉树组成,其中树中的每个节点都是分配给 Snark 工作者的任务。扫描状态周期性地从树的顶部返回一个证明,证明树底部所有交易的正确性。然后区块生产者会添加该证明,以证明链的当前状态和包含在 Snarked 账本内的所有交易是有效的。 - -因此,基于扫描状态能够调整以匹配所需的交易吞吐量,区块出块时间便可以在交易吞吐量大幅变化时仍可能保持不变。 - -### 添加交易进扫描状态 - -区块生产者会以扫描状态数据结构中的最大允许添加交易数来打包交易。在打包交易时,他们会获得相应的交易上的费用作为回报。每个被打包的交易都会自动转换成一个新任务,添加进扫描状态结构中。 - -对于添加的每个交易,区块生产者必须包含等量的已完成的 Snarks,该 Snarks 对应于已存在于扫描状态中的一系列任务。这些已完成的 Snarks,当被添加到扫描状态时,会创建新的合并 Snark(对于根节点该 Snark 会直接返回作为结果)。 - -区块生产者不会自己执行这些 Snark 任务, 而是在 Snark 池中可用的投标中徐州呢从 Snark 工作者那里购买已完成的 Snark 任务。 - -### 扫描状态参数 - -扫描状态中结构中有两个参数比较关键,决定了扫描状态的结构和行为: - -- transaction_capacity_log_2 - - transaction_capacity_log_2 参数定义了一个区块中可以包含的最大交易数: - - max_no_of_transactions = 2^{transaction_capacity_log_2} - -- work_delay - - work_delay 确保有足够的时间让 Snark 工作者完成 Snark 工作。如果没有已完成的 Snark 证明可用,则区块生产者不能包含任何交易。使用工作延迟,扫描状态下可能存在的最大树数定义为: - - max_number_of_trees = (transaction_capacity_log_2 + 1) * (work_delay + 1) + 1 - - 每个块可能包含的最大证明数定义为: - - max_number_of_proofs = 2^{transaction\_capacity_log_2 + 1} - 1 - - 这些扫描状态约束确保每个区块只能发出一个证明,并且在添加与其子项对应的证明后要更新的合并节点始终为空。 - -虽然最大交易数可能是固定的,但这可以动态调整以适应交易吞吐量。因此,扫描状态可以处理无限的交易吞吐量,尽管以增加交易证明的延迟为代价。 - -下面将举例说明: - -假设一个扫描状态结构,其 max_no_of_transactions 为 4, work_delay 为 1。这意味着可以完成的最大工作量为 7, 最多 7 颗树。 - -在初始状态,扫描状态内部为空。 -![](https://docs.minaprotocol.com/static/img/docs-images/scan-state/ZJXLozR.png) -区块 1:区块生产者打包了 4 个交易,添加到扫描状态结构中,记为 B1. 这四个交易首先会添加到第一颗树的叶节点。 -![](https://docs.minaprotocol.com/static/img/docs-images/scan-state/mY4MzW0.png) -区块 2:在第二个区块,区块生产者添加另外四笔交易(B2)。这些被添加到第二棵树,再次填充叶节点。由于存在 1 个区块的工作延迟,因此不需要证明。 -![](https://docs.minaprotocol.com/static/img/docs-images/scan-state/jzYrmZf.png) -区块 3:在第三个区块,区块生产者 B3 向第三棵树添加了四笔交易,但必须包括第一棵树的四个证明。由于包含这些已完成的证明,因此生成了两个 M3 合并工作。 -![](https://docs.minaprotocol.com/static/img/docs-images/scan-state/tECFm3I.png) -(注意: B 或 M 表示基本或合并工作,数字表示添加到扫描状态结构的顺序。) - -区块 4:对于第四个区块,区块生产者在第四棵树的叶节点添加另外四笔交易(B4)。同时它们也打包了 4 个针对第二个区块中的 4 个交易的相应的证明,以此,同样生成了 2 个 M4 合并工作。 -![](https://docs.minaprotocol.com/static/img/docs-images/scan-state/76R2bpU.png) -(note: 任何待处理的工作(以橙色显示)都是由 Snark 工作者完成的工作。Snark 工作者将完成的工作提交到 Snark 池。可能存在多个 Snark 工作者完成证明工作,但区块生产者可能只会购买池中费用最低的证明。) - -区块 5:在第 5 个区块中,同样打包了 4 个交易(B5)以填充第五棵树的叶节点,另外包含了 6 个证明(4 个 B3 和 2 个 M3)。M3 合并作业完成后将生成对于第一颗树的最后一项任务(M5)。 -![](https://docs.minaprotocol.com/static/img/docs-images/scan-state/QaqfbXG.png) -区块 6:在第六个区块中,同样打包了 4 个交易(B6)以填充第六棵树的叶节点,另外包含了 6 个证明(4 个 B4 和 2 个 M4)。产生了 3 个 M6 合并作业,其中第一个 M6 也是对于第二颗树的最后一项任务。 -![](https://docs.minaprotocol.com/static/img/docs-images/scan-state/y6dM2FT.png) -区块 7:在第七个区块中,同样打包了 4 个交易(B7)以填充第七棵树的叶节点。根据扫描状态结构中的参数 7 棵数已达上限。同样包含了 7 个证明(4 个 B5 和 3 个 M5)。第一颗数的 M5 已完成并被发送出。另两个 M5 和第五棵数的 B5 共同生成了 M7 的合并工作。 -![](https://docs.minaprotocol.com/static/img/docs-images/scan-state/RY8umxW.png) -从第一棵树发出的证明是与在区块 1 中添加的交易相对应的帐本证明。之后被删除第一颗树的内容以为后续交易创造空间。 -![](https://docs.minaprotocol.com/static/img/docs-images/scan-state/hQvFVfp.png) -区块 8:在第八个区块中,区块生产者添加了两个交易(B8)和 4 个(B6)证明。这 4 个 B6 证明产生进一步的 2 个 M8 合并工作。注意,添加两个交易只需要四个证明。 -![](https://docs.minaprotocol.com/static/img/docs-images/scan-state/A3o18oN.png) -(Note: 除了对于树的根证明, Snark 工作通常被捆绑进包含 2 个 workIds 的工作包中。通常一个交易需要两个证明,这确保了交易和要购买的 Snark 工作量的一致性。) - -区块 9:在第 9 个区块中,区块生产者添加了三个交易(B9),会有总量 6 个的证明。三个用于之前未完成的 M6 工作。第二棵数的 M6 位于 root 在获取到证明后直接返回。第二棵树也随之重置为空,然后第三 B9 笔交易进入该空树,同时添加了针对 B7 的两个证明。 -![](https://docs.minaprotocol.com/static/img/docs-images/scan-state/JGlawxh.png) -区块 10:在块 10,该块生产者增加了四笔交易,同时添加了 7 个证明。 -![](https://docs.minaprotocol.com/static/img/docs-images/scan-state/kQASfTN.png) -第 11 块:在第 11 个块中,区块生产者添加了三个交易(B11)并按顺序完成了五个证明(B9,B9,M8,M8,M9)。此外,M9 账本证明从第四棵树返回。 -![](https://docs.minaprotocol.com/static/img/docs-images/scan-state/FaVTmWD.png) -(Note: 可以使用 mina advanced snark-job-list 命令来查看扫描状态结构的具体内容。) - -### 与 Snark 池集成 - -新添加到扫描状态的作业是等待 Snark 工作者完成的作业。Snark 工作人员完成所需的 Snark 工作量,然后拍卖这些工作量。当一个节点接收到此 Snark 并且验证其有效后,会将此 Snark 添加进节点本地的 Snark 池。同样此 Snark 也会被同步到网络上的其他节点。(Note: 虽然多个 Snark 工人可以完成相同的工作,但 Snark 池中只包含最低的费用。) - -当区块生产者将完成的证明包含在一个区块中以抵消他们添加的任何交易时,他们可以从 Snark 池中购买相应的工作。例如,继续上面的例子考虑下一个块 (12)。如果区块生产者想要添加三笔交易,包括购买币、用户付款和转账给 Snark 工作者,他们需要购买三个完成的 Snark 工作。这对应于 6 个证明:B9、B10s、M9 和 M10(来自第七棵树),因为每个 Snark 包括两个 workIds。 - -在生成块期间,除了所需作业的最佳出价(在示例中分别为 0.025、0.165、0.1 和 0.5)之外,snark 池还可能包括已完成的工作。 -![](https://docs.minaprotocol.com/static/img/docs-images/scan-state/fDBZog9.png) -区块生产者在选择交易之前会考虑可用工作的价格。区块生产者将添加的第一笔交易将是有币奖励的交易。如果交易费用不包括包含它们所需的 Snark 费用,则不会添加它们。区块生产者不会在利益获取的情况下购买 Snark。 - -如果在所需的订单中没有可以购买的已完成的 Snark 工作,则相应的交易将不会包含在一个区块中。这可能会导致一个空块,但对于无法添加任何交易的情况(包括币库交易),也不会对区块生产者有任何奖励。(Note: 当前的 Snark 池可通过 GraphQL 或 CLI[mina advanced snark-pool 命令]查看。) - -## 代币(Token) - -代币为用户提供了一种创建和铸造(发行)他们自己的自定义代币的方式,而这需要一个特殊的代币账户。 - -在 Mina 协议中,用户可以创建自己的代币,这些代币可以通过使用特殊的代币账户来铸造(或创建)和发送。Mina CLI(命令行界面)是与 Mina 区块链上的代币进行交互的主要方式。它提供了一个客户端接口,支持创建新令牌、创建新令牌帐户和铸造非默认令牌的功能。除了令牌接口之外,还有其他高级客户端和守护程序命令(请参阅 CLI 参考)。 - -### 创建令牌 - -使用 CLI,您可以在 Mina 上创建自己的 Token。非默认 Token 是 Mina 区块链引入的一种新型 Token。这些新型 Token 具有唯一标识符,可将它们与区块链中的所有其他 Token 区分开来。然后,拥有这个关联 token 帐户的用户可以接收/发送这种 Token。 - -创建新 Token 时,会创建新 Token ID 以及基于公钥的 Token 帐户。这个 Token 账户拥有 Token 并且可以铸造更多的 Token。该帐户还将(最终)有权启用/禁用帐户,并设置是否可以创建新帐户。 - -注意,创建新的 Token 需要在原先已有的交易费用之上支付额外费用。这笔额外费用是用于支付创建帐户的费用。 - -### 创建一个新令牌 - - $ mina client create-token --sender - -用以下命令了解有关如何使用该命令的更多信息。 - - $ mina client create-token -help - -### 创建令牌帐户 - -使用 CLI,您可以为现有 Token 创建 Token 帐户。Token 账户类似于普通账户,但仅用于与 Mina 协议中存在的非默认 Token 进行交互。您必须为您希望与之交互的每种类型的令牌创建一个单独的唯一令牌帐户。 - -### 创建一个新的令牌帐户 - - $ mina client create-token-account --token-owner --receiver --sender --token - -用以下命令了解有关如何使用该命令的更多信息。 - - $ mina client create-token-account -help - -### 铸造代币 - -使用 CLI,您可以创建自己的代币。铸造自己的代币只会增加特定 Token 的供应量。铸造 Token 是所有非默认 Token 的创建方式,没有其他协议事件或命令可以创建非默认 Token。此命令只能由 Token 所有者发出,但可以在任何现有帐户中为该代币铸造 Token。 - -铸造代币命令: - - $ mina client mint-tokens --amount --sender --token - - 创建新令牌帐户的必填字段是: - - 数量:要创建的新代币数量 - - 发件人:您要从中发送交易的公钥 - - token : 要铸造的令牌的 ID - - 可选字段,可让您指定帐户的公钥以在以下位置创建新令牌: - - 接收者:用于在其中创建新令牌的帐户的公钥 - -用以下命令了解有关如何使用该命令的更多信息。 - - mina client mint-tokens -help - -### 协议运行流程 - -针对协议各个关键模块的解读后,我们可以从交易的层面来看下协议如何完整运行的。我们将以付款为例子来进行说明。付款是一种交易,要求将价值从一个帐户转移到另一个帐户,以及发送方愿意为付款支付的相关费用。以下举例说明 Bob 向 Alice 发送 mina 的流程。 - -1. 创建交易 - Bob 点击“发送” 付款 - - Mina 区块链网络中的任何成员都可以创建付款并与 Mina 网络共享。付款使用私钥进行加密签名,以便可以验证发送方的帐户。然后将其广播发送到网络上的其他对应节点进行处理。接受方收到后将存在他们本地的 transaction pool 数据结构内(节点内用于存储来自网络上的所有交易的内存结构)。 - -2. 生产一个区块 - Bob 的付款被放入待办事项列表 - - 在给定的时间内 Mina 网络会选择一个区块生产者用于生产新区快。当前活跃的区块生产者基于支付费用的考虑自行选择这些交易,然后将它们放在一个称为过渡块(Transition Block)的列表中进行处理。区块生产者通过产出新区块来赚取 mina。区块生产者会产出一个初始 Snark 文件,定义当前的过渡块的结构,用于与前一个区块相比。注意这个 Snark 还未验证区块内部的交易。生产者将这些新信息传输给 Snark 工作者进行处理。 - -3. Snark 验证交易 - Bob 的付款获得 Snark 签名 - - 网络上的 Snar 工作节点开始对新过渡块中的每一交易执行 Snark 计算。首先会对每个交易进行验证产出证明,再对相邻的交易进行合并产出证明,直至最后所有交易均被验证。Snark 工作者从这些 Snark 产出证明中获取相应的收益,而这些收益是由区块生产者来支付,他们会从产出区块的收益中剥离部分用于支付 Snark 工作者。最后,这些 Snark 证明被广播至网络中。 - -4. 交易确认 - Alice 和 Bob 的账户显示转账结果 - - 一旦区块被验证完毕,区块生产者便会发出针对于该过渡块的确认信息至网络中。然后网络中其他节点便会基于此更新本地区块,最后实现账户上双方余额的更新。 - -5. 交易置信度 - Alice 确认转账已完成 - - 随着不断新的后续区块的加入,接受者会更加确认之前那个交易已经完成且网络对这个结果已达成共识。当然,像其他区块链一样,我们会有一个交易最终确认时间,意指在特定的几个区块后交易才会被最终确认。在比特币区块链中,会需要 6 个区块(60 分钟)之后交易才最终确认。同样,在 Mina 区块链中,会建议等待 15 个区块(同样是 60 分钟)来达到高置信度(99.9%), 以阻止交易被篡改撤销。 - -## Mina 协议的具体实现 - -Mina 协议是用 OCaml 语言编写的,Ocaml 是一种静态的函数式编程语言。关于 Ocaml, 可以参考[Ocaml 文档](https://realworldocaml.org/)。 - -### 编译相关 - -OCaml 编译器支持字节码和原生编译。Mina 代码与一些库静态链接,因此无法编译为字节码。Mina 代码同样也不能很好地支持 REPL。Mina 的编译系统为 Dune。在 Dune 上,一个文件代表一个模块,文件夹代表着模块的组合。如果文件夹中有一个同名的文件,它会类似于 index.js 在 Node.js 中的作用。 - -我们还有 OCaml 中的接口文件——它们的扩展名.mli 只包含模块的类型签名和结构。相应的实现必须具有相同的文件名,但带有.ml 扩展名。只有接口中定义的东西才能从其他模块中获得。如果模块不存在接口文件,则默认情况下会公开所有内容。注意: Reason 遵循与.rei 和.re 扩展相同的规则。 - -对于链接步骤,在引擎盖下 dune 使用 ldd。您还可以使用诸如-O3 优化之类的东西。对于调试,您可以使用 gdbOCaml 不完全支持但它可以工作的。即将发布的 OCaml (4.08) 将与 gdb. - -### 代码结构 - -你可以从 [Mina Code Repository](https://github.com/minaprotocol/mina) 上查看具体的实现细节。下面将对项目结构进行简要说明,以帮助更容易地阅读源码。 - -- dockerfiles/ - 包含 Docker 相关脚本 -- docs/ - - 贡献代码和流程的文档在这里。包含演练文档的文档网站位于 frontend/website/docs. - -- frontend/ - - 所有与 Mina 前端 UI 和产品相关的代码 - - - wallet/ - - Mina 钱包的源代码 - - - website/ - - https://minaprotocol.com 网站的源码 - - - docs/ - - 关于加入位于https://minaprotocol.com/docs的 Mina 网络的文档和说明 - - - posts/ - - 博客文章的 Markdown 文档 - - - src/ - - 网站的源代码 - - - static/ - - 静态文件,如图像等。 - - - rfcs/ - - 该目录包含根据 RFC 流程提出的所有已接受的 RFC(或“征求意见”)。 - - - scripts/ - 脚本相关。 - - src/ - - 所有协议源代码,包括应用程序和库代码,都在这个目录中。 - - - \*.opam - - Mina 的 dune 构建系统需要这些文件。lib 文件夹中的每个库都对应着一个\*.opam 文件。当创建一个库 lib/foo_lib 时,会由 dune 配置文件确定当前库名,同时需要创建所需的 foo_lib.opam 文件。 - - - config/ - - 构建时配置 - 这些.mlh 文件定义了编译时常量及其值。 - - - app/ - - 应用程序所在位置。 - - - cli/ - - 这是 mina 客户端/守护进程。用于运行 Staker, Snaker, 或简单的用于发送接收交易的客户端。 - - - website/ - - 即将被弃用的网站目录 - 大部分代码已迁移到 frontend/website/ - - - reformat/ - - 该程序 ocamlformat 在源代码树中的大多数文件上运行,只有少数例外。 - - - logproc/ - - 该实用程序从 stdinmina 守护程序发出的日志消息中读取并可以过滤和打印这些日志消息。 - - - libp2p_helper/ - - 该程序使用 go-libp2p 来实现 Mina 守护进程所需的点对点管道。 - - - external/ - - 第三方库,其中部分库进行了一些定制修改。 - - - lib/ - - 主要包含两种库: - - - 通用类型库: 包括 snarky,fold_lib,vrf_lib,sgn 等。 - - 应用程序专属类型库: 包括 syncable_ledger,staged_ledger,transaction_snark 等。 - -## Snapps - -Snapps(“Snark 应用程序”)是 Mina 区块链上基于 zk-SNARK 的智能合约。Snapps 的执行和状态模型都是基于链下的,而这这有助于私有计算和私有状态维护。基于 zk-SNARK,Snapps 可以在链下执行任意复杂的计算,同时只需支付固定费用即可将生成的零知识证明发送到链,这与使用基于 gas 模型的其他区块链相反。 - -![](https://docs.minaprotocol.com/static/img/docs-images/1_Snapps_Off-Chain_Performance.jpg) - -Snapps 是用 TypeScript 编写的。TypeScript 提供了一种简单、熟悉的语言 (JavaScript),但增加了类型安全性,有助于开发者更容易上手 Snapps。 - -### Snapps 原理 - -Snapps 是使用 Snapp CLI 以 TypeScript 编写的。(Note: Snapps 目前在最新版本的 Chrome、Firefox、Edge 和 Brave 中运行。我们打算在未来添加对 Safari 的支持。) - -如下图所示, “snapp”由两部分组成:1.) 智能合约和 2.) 供用户与之交互的 UI(用户界面)。 -![](https://docs.minaprotocol.com/static/img/docs-images/3_Snapps_Structure.jpg) - -### 基于零知识的智能合约 - -由于 Snapps 基于零知识证明 (zk-SNARKs),因此 Snapp 开发人员会编写出所谓的“电路” - 这是在构建过程中派生出证明函数和相应验证函数的方法。 - -证明函数就是用于执行智能合约里的代码的函数。它运行于用户的浏览器中,当用户在浏览器中的相关行为(如用币购买服务)产生输入数据后,经过该验证函数,最终输出一个 zk 证明。 - -![](https://docs.minaprotocol.com/static/img/docs-images/4_Snapps_Prover_Function.jpg) - -而验证函数的功能是用于验证是否零知识证明成功通过了所有的证明函数定义的约束。验证函数的时间复杂度不受证明函数内部的复杂度影响。在 Mina 网络中,Mina 作为验证者并运行这些验证函数。 -![](https://docs.minaprotocol.com/static/img/docs-images/5_Snapps_Verifier_Function.jpg) - -### Mina 的证明函数和验证密钥 - -当 Snapp 开发人员编写完他们的智能合约, 运行 npm run build 后,会产出一个 smart_contract.js 文件。在运行或部署完该合约后,你可以运行您的证明函数或生成验证密钥。该验证密钥存于 Mina 链上指定的 Snapp 账户,用于由 Mina 网络来验证零知识证明是否满足在证明函数中定义的所有要求。同样,这个密钥也用与创建 Snapp 帐户。 - -### 部署智能合约 - -![](https://docs.minaprotocol.com/static/img/docs-images/6_Snapps_DeploySmartContract.jpg) -在 Mina 上需要使用 Snapp CLI 来进行部署智能合约。部署过程中 CLI 会发送包含验证密钥的交易到 Mina 链上的指定地址。 - -当 Mina 地址包含验证密钥时,它类似于一个 Snapp 账户。该账户仅能接受那些包含证明(通过验证函数的证明)的交易。那些无法通过验证函数的交易会被 Mina 区块链网络拒绝。 - -(注意: 当您部署到新的 Mina 地址时,Mina 协议将收取 1 MINA 的帐户创建费用。这与 Snapps 无关,是为了帮助防止 sybil 或拒绝服务攻击。) - -### 用户如何与 Snapp 交互 - -Auro 是目前唯一支持 Snapp 交易的钱包。但是,计划在未来将对 snapps 的支持扩展到其他类型的钱包(例如移动钱包和桌面钱包)。安装 Auro 钱包可参考: [Google Chrome 安装 Auro 钱包](https://www.aurowallet.com/)。 - -将 Snapp 部署到主机(例如 mycoolsnapp.com)后,用户可以与其进行交互: - -1. 用户访问 mycoolsnapp.com。 -2. 用户与 Snapp 交互并根据需要输入任何数据。(例如,如果这是一个自动做市商,用户可能会指定“以 y 价格购买 x 数量的 ABC”。) -3. Snapp 中的证明功能现在将根据用户输入的数据在本地生成零知识证明。这些数据可以是私有的(区块链永远不会看到的)或公共的(将存储在链上或链下),这取决于开发人员指定的内容,以及给定用例的需要。此外,将生成此交易要创建的状态更新列表并与此证明相关联。 -4. 用户在 Snapp UI 中点击“提交链”,他们的钱包(例如浏览器扩展钱包)将提示他们确认发送交易。钱包签署包含证明和相关状态描述的交易以更新并将其发送到 Mina 区块链。 -5. 当 Mina 网络收到此交易时,它会验证该证明是否成功通过了 Snapp 帐户上列出的验证者方法。如果网络接受此交易,则表明此证明和请求的状态更改有效,因此允许更新 snapp 的状态。 - -因为用户的交互发生在他们的 Web 浏览器本地(在客户端上使用 JavaScript),所以可以维护用户的隐私。 - -### 状态如何在链上更新 - -当证明功能在 Web 浏览器中运行时,智能合约会输出证明和一些我们称之为“事件”的相关数据。当将交易发送到 Snapp 地址时,这将作为交易的一部分发送。这些事件是纯文本描述(JSON 格式),描述了如何更新 Snapp 帐户的状态。 - -通过将这些事件的哈希作为公共输入传递给智能合约,可以确保这些事件的完整性。它们必须存在且未经修改,验证函数在 Mina 上运行时才能成功通过。通过这种方式,Mina 网络可以确认证明和相关事件的完整性,这些事件描述了如何更新 snapp 帐户的状态。 - -### 快照状态 - -Mina 上存在两种不同类型的状态:链上状态和链下状态。链上状态描述了存在于 Mina 区块链上的状态。链下状态描述了存储在其他任何地方的状态——例如 IPFS 等。 - -### 链上状态 - -每个 Snapp 帐户提供 8 个字段,每个字段 32 字节任意存储。您可以将任何东西存放在这里,只要它符合提供的尺寸即可。如果您预计您的状态会大于此值,或者如果每个用户使用 Snapp 累积状态,那么您将需要改用链外状态。 - -### 脱链状态 - -对于较大的数据,您可能需要考虑将 Merkle 树(或类似数据结构)的根存储在您的 snapp 链上存储结构中,然后该存储进一步引用其他的链下存储,例如 IPFS。 - -当 snapp 在用户的 Web 浏览器中运行时,它可能会将状态插入到外部存储中,例如 IPFS。当交易被发送到 Mina 网络时,如果 Mina 接受这个 Snapp 交易(即这个证明和状态是有效的,所以允许更新),那么 Snapp 交易将更新存储在链上的 Merkle 树的根。 -![](https://docs.minaprotocol.com/static/img/docs-images/9_Snapps_Off-Chain_State.jpg) - -### SnarkyJS API 参考 - -要编写 Snapp,我们建议使用 Snapp CLI,它通过包含 SnarkyJS 并提供项目脚手架、测试框架和格式,使编写 Snapp 变得容易。具体 API 参考: [SnarkyJS API 参考](https://docs.minaprotocol.com/en/snapps/snarkyjs-reference) - -## 最后 - -至此,本文基于 Mina 的官方文档进一步整理,介绍了 Mina 的基本概念,涉及 Mina 协议的各个关键模块, 说明协议具体的实现,最后简要介绍 Snapps 的概念。 diff --git a/crypto/Mina/readme.md b/crypto/Mina/readme.md deleted file mode 100644 index 59b1b94fd..000000000 --- a/crypto/Mina/readme.md +++ /dev/null @@ -1,19 +0,0 @@ -# MINA - -- [Mina Intro](./docs/mina.md) - -## Mina workshop - -- youtube: -- ppt: - -## Reference - -- mina 介绍: -- mina zk: https://o1-labs.github.io/proof-systems/introduction.html -- snapps: -- SnarkyJS: -- snapps: - -- Snapp Developer Resource Kit : - diff --git a/crypto/Mina/zkApp/README.md b/crypto/Mina/zkApp/README.md deleted file mode 100644 index 95097facc..000000000 --- a/crypto/Mina/zkApp/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Mina zkApp - -zkApps ("zero-knowledge apps") are Mina Protocol’s smart contracts powered by zero-knowledge proofs, specifically using zk-SNARKs. - -zkApps use an off-chain execution and mostly off-chain state model. This allows for private computation and state that can be either private or public. - -zkApps can perform arbitrarily-complex computations off chain while incurring only a flat fee to send the resulting zero-knowledge proof to the chain for verification of this computation, as opposed to other blockchains that run computations on chain and use a variable gas-fee based model. - -![1_zkApps_Off-Chain_Performance.jpg](https://docs.minaprotocol.com/static/img/docs-images/1_zkApps_Off-Chain_Performance.jpg) - -## Reference - -- zkApp doc: diff --git a/crypto/PLONK/plonk_gadget.md b/crypto/PLONK/plonk_gadget.md deleted file mode 100644 index 46a1359a7..000000000 --- a/crypto/PLONK/plonk_gadget.md +++ /dev/null @@ -1,10 +0,0 @@ -练习使用plonk gadget 书写简单电路 -参考 read me: https://github.com/dusk-network/plonk - -题目: -有输入a,b,c,d 整数,满足 c = a.euqals(b), -if(c) { -return d -}else { -return d^2 -} diff --git a/crypto/PLONK/readme.md b/crypto/PLONK/readme.md deleted file mode 100644 index a4038663e..000000000 --- a/crypto/PLONK/readme.md +++ /dev/null @@ -1,72 +0,0 @@ -# PLONK zksnark算法 - -数学基础:https://learnblockchain.cn/article/2801 -电路介绍:https://blog.csdn.net/adijeshen/article/details/123332665 - -## 视频介绍 -kevin: https://mp.weixin.qq.com/mp/appmsgalbum?action=getalbum&__biz=MzA5NzI4MzkyNA==&scene=1&album_id=1664071313331650562&count=3#wechat_redirect - - -## Schwartz-Zippel 定理 - Schwartz-Zippel 辅助定理,即不同的多项式在大多数点的求值是不同的,因此只要检查少量的点,其实就可验证证明者使用的多项式是否正确。 - - 多项式在很大的集合中随机选取参数,恰好多项式值等于0的概率几乎为0 -## KZG承诺 - -预备知识: - -由Kate,Zaverucha和Goldberg发表的多项式承诺方案; -在一个多项式承诺方案中,证明者计算一个多项式的承诺(commitment), 并可以在多项式的任意一个点进行打开(opening):该承诺方案能证明多项式在特定位置的值与指定的数值一致。 -https://dankradfeist.de/ethereum/2021/10/13/kate-polynomial-commitments-mandarin.html - -多项式承诺 -在不泄露多项式f(x)的情况下,使验证者确信对于某个z, f(z) 是正确的计算结果。 -(1) 首先需要计算多项式承诺,为f(s)*G1 ,其中为s可信设置密秘选取的值,G为椭圆曲线基点; - -(2) 为了验证f(z), 证明者需要计算: -Q(x)=[f(x)-f(z)]/(x-z) -然后将Q(x), f(z)的承诺发给验证者 - -(3) 验证者验证: -e(f(x)*G1 - G1*f(z), G2) = e(Q(x)*G1, xG2-zG2); -e(f(x)*G1 - G1*f(z), G2) = e(G1, G2)^(f(x)-f(z)); -e(Q(x)*G1 , xG2-zG2) = e(G1, G2)^[(x-z)*Q(x)]; - -## 原理 - -gorth16: https://mp.weixin.qq.com/s?__biz=MzIxNjkwODE5NQ==&mid=2247484672&idx=1&sn=a41bc8436703e8e2bab9ad16634956e5&chksm=9780adcca0f724dadb06f670a9b783c6d50426354e408b3b7a7d7f5d21dddc061c7cc9aa19ac&cur_album_id=1432629901374636033&scene=189#wechat_redirect -gorth16 setup时候依赖电路结构 - -1. 门约束 -Ql*a+Qr*b+Qo*c+Qm * ab + Qc=0 -2. 复制约束 - - - -**plonk vs groth16** -plonk: plinkish, universal setup , larger proof -can be imoroved with custom gate - -## 代码 -源码最小实现:https://github.com/fabrizio-m/TyPLONK - - -## 参考链接 -- V神文章: https://vitalik.ca/general/2019/09/22/plonk.html -- Plonk零知识证明方案: https://www.jianshu.com/p/889b7e09ae9a -- PLONK(零知识证明)最终版原文解读系列: https://blog.csdn.net/guoyihaoguoyihao/article/details/104715756?spm=1001.2014.3001.5502 -- PLONK代码解析:https://blog.csdn.net/mutourend/article/details/113803758? -- Bulletproofs、Sigma protocol、Halo2等ZK方案小结: https://blog.csdn.net/mutourend/article/details/126751659 -- http://www.cxyzjd.com/article/weixin_43179764/112861106 - -- https://www.zeroknowledgeblog.com/ - -- https://medium.com/aztec-protocol/- aztecs-zk-zk-rollup-looking-behind-the-cryptocurtain-2b8af1fca619 - -- Plonk零知识证明方案: https://www.jianshu.com/p/889b7e09ae9a - -- Plonk Unrolled For Ethereum: https://github.com/matter-labs/- proof_system_info_v1.0/blob/master/PlonkUnrolledForEthereum.pdf - -- On PLONK and plookup: https://research.metastate.dev/- on-plonk-and-plookup/ - -- PLONK by Hand: https://research.metastate.dev/plonk-by-hand-part-1/ \ No newline at end of file diff --git a/crypto/ZK-SNARK/README.md b/crypto/ZK-SNARK/README.md deleted file mode 100644 index 671c4dc30..000000000 --- a/crypto/ZK-SNARK/README.md +++ /dev/null @@ -1,286 +0,0 @@ -# zk-SNARKs - -## 预备知识 - -### 多项式 - -多项式有一个非常好的特性,就是如果我们有两个阶为 d 的不相等多项式,他们相交的点数不会超过 d。 - -多项式的「知识」就是多项式的系数。所谓「知道」多项式就是指「知道」多项式的系数。 - -#### Schwatz-Zippel 定理 - -我们不可能找到共享连续段的两条不相等曲线,也就是任何多项式在任意点的计算结果都可以看做是其唯一身份的表示。也就是说只要能证明多项式上的某个随机点就可以证明这个多项式(只有在知道了多项式,才能算出这个点对于的值),这个性质是我们下面所有证明的核心。 - -### Elliptic Curve Cryptography - -椭圆加密曲线,我们需要利用它进行加密运算。 - -- [ECC README.md](../ECC/README.md) - -### Pairing Function - -Pairing 是可以使两个加密值相乘,并映射到另一个域的 mapping 过程(因为 KEA 的加密值之间不能进行运算); - -Pairing 是 zk-SNARKs 中的重要运算工具,主要用于约束 prover 使用合法的多项式变量和项来进行证明过程; - -(建议先跳过底层原理,先理解 Pairing 运算特性即可开始学习 zk-SNARKs) - -- [Pairing function WIKI](https://en.wikipedia.org/wiki/Pairing_function) -- [Exploring Elliptic Curve Pairings](https://medium.com/@VitalikButerin/exploring-elliptic-curve-pairings-c73c1864e627) -- [**Pairings For Beginners** by Craig Costello](https://static1.squarespace.com/static/5fdbb09f31d71c1227082339/t/5ff394720493bd28278889c6/1609798774687/PairingsForBeginners.pdf) - -## FFT 快速傅立叶变换 - -- FFT 基础: - -## zk-SNARK 原理介绍 - -### 初始版本 - -基于 Schwatz-Zippel 定理, 如果一个 prover 声称他知道一些 verifier 也知道的多项式(无论多项式的阶数有多大)时,他们就可以按照一个简单的协议去验证。 - -- verifier 选择一个随机值 x 并在本地计算多项式结果 -- verifier 将 x 值给到 prover,并让他计算相关的多项式结果 -- prover 代入 x 到多项式计算并将结果给到 verifier -- verifier 检查本地的计算结果和 prover 的计算结果是否相等,如果相等那就说明 prover 的陈述具有较高的可信度 - -> 我们把 x 的取值范围定在 1 到 10⁷⁷, 那么计算结果不同的点的数量,就有 10⁷⁷ – d 个。因而 x 偶然“撞到”这 d 个结果相同的点中任意一个的概率就等于(可以认为是几乎不可能) $\frac{d}{10^{77}}$ - -### 商式 h(X) 保持"ZeroKnowledge" - -在不暴露多项式 p(x) 的系数的情况下给出令人信服的证明,也就是所谓的零知识 "Zero Knowledge". - -我们可以证明,存在一个多项式 h(x) 能够使得 t(x) 与之相乘后等于 p(x),由此得出, p(x) 中包含 t(x),所以 p(x) 的根中也包含 t(x) 的所有根,即找出一个 h(x) 使得 `p(x)=t(x)h(x)`. - -- verifier 挑选一个随机值 s, 计算 t = t(s) (即,求值) ,然后将 s 发送给 prover。 -- prover 计算 h(x) =p(x) / t(x) ,并对 p(s) 和 h(s) 进行求值,将计算结果 p, h 提供给 verifier。 -- verifier 验证 p= t⋅h,如果多项式相等,就意味着 t(x) 是 p(x) 的因式。 - -### 同态加密防止 prover 作弊 - -存在的问题 - -- prover 可能并不知道 p(x) 的系数,但是 prover 知道了 t(s),他就可以反过来任意构造一个可以整除 t(s) 的非法多项式 p‘(s) -- prover 知道了点(s, t(s) · h(s)) 的值,就可以构造经过这一点的任意多项式,同样满足校验 -- 协议并没有对 prover 的多项式阶数进行约束 - -所以要采用同同态加密隐藏秘密值 s : - -Verifier: - -- 取一个随机秘密值 s -- 指数 i 取值为 0,1,…,d 时分别计算对 s 求幂的加密结果,即: $E(s^i) = g^{s^i}$ -- 代入 s 计算未加密的目标多项式 t(s), 将对 s 求幂的加密结果提供给 prover - - $E(s^0),E(s^1),......, E(s^d)$ - -Prover: - -- 计算多项式 h(x) = p(x)/t(x) -- 获取加密值序列 $E(s^i)$, 以及系数 $C_i$ , 计算 E(p(s)), 以及 E(h(s)); -- 将结果 $g^p, g^h$ 提供给 verifier; - -Verifier: - -- 最后一步是 verifier 在加密域去校验 p = t(s) · h - - $g^{p} = (g^{h})^{t(s)} => g^{p} = g^{t(s)·h}$ - -### 约束 s - -尽管这个协议中 prover 的灵活性有限,他依然可以在实际不使用 verifier 所提供的加密值进行计算,而是通过其它的方式来伪造证明。 - -为了限制 prover 只能用 verifier 提供的加密的 s 进行计算,需要让 prover 只能将系数 c 赋给 verifier 提供的多项式,所以我们将 s 各个次幂的值放到加密域,并使用 KEA 来约束,让 prover 无法知晓各个项的值。 - -verifier 提供加密值 $g^{s^0} ,g^{s^1} ,…,g^{s^d}$ 和他们的 α-shift 偏移值 $g^{αs^0} ,g^{αs^1} ,…,g^{αs^d}$ - -在最后 Verifier 的流程增加一步: - -- ...验证(g^p)^α = g^p'即可 - -### 防止"知识"被暴力破解 - -在零知识 性质上也还依然存在一个很明显的缺陷:即理论上多项式参数 cᵢ 是一个很广的取值范围内的值,实际上这个范围可能很有限(比如前面例子中的 6),这就意味着 verifier 可以在有限范围的系数组合中进行暴力破解,最终计算出一个与 prover 的答案相等的结果。 - -prover 选择一个随机值 δ 作为偏移量,将知识在加密域上进行偏移,这样即能保持 "ZeroKnowledge",也能为 Verifier 提供有效验证 - -$$ -g^{\delta} \cdot p=g {\delta} \cdot t(s)h \\ -g^{\delta αp} = g^{\delta p'} -$$ - -### 非交互式 - -目前我们的协议是交互式的,必须由 prover 和 verifier 产生互动,才能完成流程,存在下列问题: - -- verifier 和 prover 串通作恶 -- 每次产生的 proof 都需要长期存储,且期间可能存在私钥泄漏的风险 - -我们使用的同态加密并不支持两个秘密值相乘,这一点对 t(s) 和 h 的加密值相乘以及 p 和 α 的加密值相乘的验证都很重要。 - -Pairing 配对操作(双线性映射)是一个数学结构,表示为函数 e(g,g),它给定一个数据集中的两个加密的输入(即 -$ g^a, g^b $ -),可以将他们确定性地映射到另一组不同的输出数据集上的它们的乘积,即 - -$e(g^a, g^b) = e(g, g)^{ab}$ - -### 简化的 zk-SNARKs 流程 - -- proving key(也被称为 evaluation key) - $g^{s^i},g^{\alpha s^i}$ - -- verification key $g^{t(s)},g^α$ - -有了 verification key,verifier 就可以处理从 prover 那里得到的加密多项式的值 $g^p,g^h ,g^{p'}$ - -- 在加密空间中校验 p = t·h
- $e(g^p,g^1) = e(g^t,g^h)$ - -- 校验多项式的限制
- $e(g^p,g^α) = e(g^{p'},g)$ - -### 完整的 zk-SNARKs 流程 - -- Setup - - - 选择一个生成元 g 和加密 pairing 函数 e - - - 对于函数 f(u)=y ,含有 n 个变量,其中有 m 个输入/输出变量,将其转换成 dgree 为 d,项数 n+1 的 QAP $(\{ l_i(x), r_i(x), o_i(x) \}_{i \in \{0,...,n\}}, t(x))$ - - - 选取随机值 $s, \rho_l, \rho_r, \alpha_l, \alpha_r, \alpha_o, \beta, \gamma$ - - - 设置 - $\rho_o=\rho_l \cdot \rho_r, \space g_l=g^{\rho_l}, g_r=g^{\rho_r}, g_o=g^{\rho_o}$ - - - Proving key: - -$$(\{ g^{s^k} \}_{k \in [d]}, \{ g_l^{l_i(s)}, g_r^{r_i(s)}, g_r^{o_i(s)} \}_{i \in \{0,...,n\}},$$ - -$$\{ g_l^{\alpha_l l_i(s)}, g_r^{\alpha_r r_i(s)}, g_o^{\alpha_o o_i(s)}, g_l^{\beta l_i(s)}, g_r^{\beta r_i(s)}, g_o^{\beta o_i(s)} \}_{i \in \{m+1,...,n\}},$$ - -$${\color{red} g_l^{t(s)}, g_r^{t(s)}, g_o^{t(s)}, g_l^{\alpha_l t(s)}, g_r^{\alpha_r t(s)}, g_o^{\alpha_o t(s)}, g_l^{\beta t(s)}, g_r^{\beta t(s)}, g_o^{\beta t(s)}} ) $$ - -- Verification key: - - $(g^1, g_o^{t(s)}, \{g_l^{l_i(s)}, g_r^{r_i(s)}, g_o^{o_i(s)}\}_{i \in \{0,...,m\}}, g^{\alpha_l}, g^{\alpha_r}, g^{\alpha_o}, g^{\gamma}, g^{\beta \gamma})$ - -- Proving - - - 根据 f(u) , 赋值计算过程中的中间变量 - $\{v_i\}_{m+1,..,n}$ - - - 赋值操作数函数 - $$L(x)=l_o(x)+ \sum_{i=1}^{n}{v_i \cdot l_i(x)}$$ - - R(x), O(x) 同样操作 - - - 选取秘密值 - $\delta_l, \delta_r, \delta_o$ - - - 计算 - $h(x)=\frac{L(x)R(x)-O(x)}{t(x)} \color{red} + \delta_r L(x) + \delta_l R(x) + \delta_l \delta_r t(x) - \delta_o$ - - - 将多项式赋值到加密域,并应用 δ-shift 偏移,使其变成”zero knowledge”, 无法被 Verifier 破解 - - $$g_l^{L_p(s)}={\color{red}(g_l^{t(s)})^{\delta_l}} \cdot \prod_{i=m+1}^{n}{(g_l^{l_i(s)})^{v_i}}$$ - - $g_r^{R_p(s)}, g_o^{O_p(s)}$ 同样操作 - - - 应用 α-shift 生成操作数一致性证明 - - $$g_l^{L_p'(s)} = {\color{red} (g_l^{\alpha_l t(s)})^{\delta_l}} \cdot \prod_{i=m+1}^{n}{(g_l^{\alpha_l l_i(s)})^{v_i}}$$ - - $g_r^{R_p(s)}, g_o^{O_p(s)}$ 同样操作 - - - 应用 β 生成变量一致性证明 - - $$g^{Z(s)}={\color{red} (g_l^{\beta t(s)})^{\delta_l} (g_r^{\beta t(s)})^{\delta_r} (g_o^{\beta t(s)})^{\delta_o}} \cdot \prod_{i=m+1}^{n}{(g_l^{\beta l_i(s)} g_r^{\beta r_i(s) g_o^{\beta o_i(s)}})^{v_i}}$$ - - - Proof - - $$(g_l^{L_p(s)}, g_r^{R_p(s)}, g_o^{O_p(s)}, g^{h(s)}, g_l^{L_p'(s)}, g_r^{R_p'(s)}, g_o^{O_p'(s)}, g^{Z(s)})$$ - -- Verification - - - 解析 proof - - - 赋值 输入/输出 部分的多项式变量,计算加密域的 - - $$g_l^{L_v(s)} = g_l^{l_0(s)} \cdot \prod_{i=1}^{m}{(g_l^{l_i(s)})^{v_i}}$$ - - $g_r^{R_v(s)}, g_o^{O_v(s)}$ 同样操作 - - - 通过 pairing 验证变量多项式约束 - $e(g_l^{L_p}, g^{\alpha_l})=e(g_l^{L_p'},g), \space g_r^{R_p}, g_o^{O_v(s)}$ 同样操作 - - 验证变量值的一致性 - $e(g_l^{L_p}, g_r^{R_p}, g_o^{O_p}, g^{\beta \gamma}) = e(g^Z, g^{\gamma})$ - - 验证结果合法性(h 不存在余数) - - $e(g_l^{L_p},g_l^{L_v(s)}, g_r^{R_p}, g_r^{R_v(s)}) = e(g_o^{t(s)}, g^h) \cdot e(g_o^{O_p} g_o^{O_v(s)}, g)$ - -## paper - -paper pdf files store at here: - -paper list: - -- A Taxonomy of Circuit Languages -- How to Make SNARKs -- MEV -- Security of ZK Friendly Hash Functions -- SNARKs from Hash Functions -- Verifiable Delay Functions -- Why and How zk-SNARK Works: Definitive Explanation -- zksnark 在 Zcash 中的作用 -- zkSNARKs from Polynomial Commitments - -## zk hardware - -reference: - -1. Paradigm: -2. Paradigm cite 的 paper: -3. Justin Drake talk: - -## Reference - -- **Why and How zk-SNARK Works** by Makym - - - original articles - - - [Why and How zk-SNARK Works 1: Introduction & the Medium of a Proof](https://medium.com/@imolfar/why-and-how-zk-snark-works-1-introduction-the-medium-of-a-proof-d946e931160) - - [Why and How zk-SNARK Works 2: Proving Knowledge of a Polynomial](https://medium.com/@imolfar/why-and-how-zk-snark-works-2-proving-knowledge-of-a-polynomial-f817760e2805) - - [Why and How zk-SNARK Works 3: Non-interactivity & Distributed Setup](https://medium.com/@imolfar/why-and-how-zk-snark-works-3-non-interactivity-distributed-setup-c0310c0e5d1c) - - [Why and How zk-SNARK Works 4: General-Purpose Computation](https://medium.com/@imolfar/why-and-how-zk-snark-works-4-general-purpose-computation-dcdc8081ee42) - - [Why and How zk-SNARK Works 5: Variable Polynomials](https://medium.com/@imolfar/why-and-how-zk-snark-works-5-variable-polynomials-3b4e06859e30) - - [Why and How zk-SNARK Works 6: Verifiable Computation Protocol](https://medium.com/@imolfar/why-and-how-zk-snark-works-6-verifiable-computation-protocol-1aa19f95a5cc) - - [Why and How zk-SNARK Works 7: Constraints and Public Inputs](https://medium.com/@imolfar/why-and-how-zk-snark-works-7-constraints-and-public-inputs-e95f6596dd1c) - - [Why and How zk-SNARK Works 8: Zero-Knowledge Computation](https://medium.com/@imolfar/why-and-how-zk-snark-works-8-zero-knowledge-computation-f120339c2c55) - - - [Scroll 翻译版本](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzkyMTQxNTg0MQ==&action=getalbum&album_id=2695488884776058880&scene=173&from_msgid=2247485331&from_itemidx=1&count=3&nolastread=1#wechat_redirect) - - - 安比实验室 SECBIT 翻译版本 - - - [从零开始学习 zk-SNARK(一)——多项式的性质与证明](https://secbit.io/blog/2019/12/25/learn-zk-snark-from-zero-part-one/) - - [从零开始学习 zk-SNARK(二)——多项式的非交互式零知识证明](https://secbit.io/blog/2020/01/01/learn-zk-snark-from-zero-part-two/) - - [从零开始学习 zk-SNARK(三)——从程序到多项式的构造](https://secbit.io/blog/2020/01/08/learn-zk-snark-from-zero-part-three/) - - [从零开始学习 zk-SNARK(四)——多项式的约束](https://secbit.io/blog/2020/01/15/learn-zk-snark-from-zero-part-four/) - - [从零开始学习 zk-SNARK(五)——Pinocchio 协议](https://secbit.io/blog/2020/01/22/learn-zk-snark-from-zero-part-five/) - -- Vitalik's blog - - - [Quadratic Arithmetic Programs: from Zero to Hero](https://medium.com/@VitalikButerin/quadratic-arithmetic-programs-from-zero-to-hero-f6d558cea649) - - [Exploring Elliptic Curve Pairings](https://medium.com/@VitalikButerin/exploring-elliptic-curve-pairings-c73c1864e627) - - [Zk-SNARKs: Under the Hood](https://medium.com/@VitalikButerin/zk-snarks-under-the-hood-b33151a013f6) - -- [Star Li 零知识证明 - zkSNARK 入门](https://mp.weixin.qq.com/s/vO6-34W1qUFdLWRM0QjZXQ) -- [星辰实验室-zk 文档](https://drive.google.com/file/d/1A5EtvJaNz17fgSbgBfgKWYY6OBX6PDrT/view?usp=sharing) -- [星辰实验室-zkPPT](https://drive.google.com/file/d/1pP8HdRSflWo93xYaIpfUSkhtNICS0hDr/view?usp=sharing) -- [入门视频](https://www.youtube.com/watch?v=lGogdTnD4SE) -- [CTN zkdapp 实战](https://www.bilibili.com/video/BV1oL4y1h7iE?p=1&share_medium=android&share_plat=android&share_session_id=9d2f7c31-a4dc-46a5-a2d9-4d6d0ebc3997&share_source=WEIXIN&share_tag=s_i×tamp=1653798331&unique_k=921Lj1L) -- [Awesome-ZK-kurtpan](https://kurtpan666.github.io/ktpzkp22.html) -- [0xparc -ZK 学习资料](https://learn.0xparc.org/) -- [tss-教程](https://github.com/ZenGo-X/awesome-tss) -- [devcon What to know about Zero Knowledge](https://www.youtube.com/watch?v=hBupNf1igbY&t=1370s) -- [zkdoc](https://github.com/a16z/zkdocs) diff --git a/crypto/ZKStark/readme.md b/crypto/ZKStark/readme.md deleted file mode 100644 index 28aed2ddc..000000000 --- a/crypto/ZKStark/readme.md +++ /dev/null @@ -1,125 +0,0 @@ -# ZK-STARK - -## 知识回顾:FFT -zkstark和FFT的思路类似,均采用了分治的思想,使得时间复杂度变为O(NlogN)。这里先回顾下FFT的知识。 - -FFT用于求解这么一个问题:给定一个某个域上的多项式f(x),还有一组输入D(也就是横坐标),求这组输入对应的纵坐标。通过分治法,FFT的性能上可以比朴素做法高出一个数量级。本文重点讲解正变换的原理,因为它和ZKSTARK的FRI协议思路很相像。 - -此外,FFT还有一个逆变换IFFT,给定一组点值,求多项式,功能类似于插值法。本文不讨论它的实现。 - - -### FFT的输入 -FFT对输入数据有要求,它们必须构成一个循环群,而且群的阶必须是2的幂,例如2,4,8,16...。 - -现在考虑这样一个4阶的循环群,其中生成元是g: -$\{g^0, g^1, g^2, g^3\}$ - -如果我们把每个元素的都做一次幂操作: -- $(g^0)^2 = g^0$ -- $(g^1)^2 = g^2$ -- $(g^2)^2 = g^4 = g^0$ -- $(g^3)^2 = g^6 = g^2$ - -做这样的幂操作,会恰好得到2个元素:${g^0, g^2}$. 同样,如果我们把这个2阶的元素继续做幂操作,会得到唯一的元素$g^0$. - -现在,假设有一个阶为$2^n$的循环群: $\{g^0, g^1, g^2, ..,g^i, .., g^{2^n-1}\}$ - -如果对每个元素做上述幂操作,得到: -$\{g^0, g^2, g^4, ..,g^{2i}, .., g^{2^{n+1}-2}\}$ -这个集合中,独特的元素只有一半个,即$2^{n-1}$个。 - -为了理解这一点,可以把原始集合分解成数量相等的前后两段,分别考察: -- 前半段$\{g^0, g^1, .., g^{2^{n-1}-1}\}$ -- 后半段$\{g^{2^{n-1}}, g^{2^{n-1}+1}, .., g^{2^n-1}\}$ - -前半段和后半段分别取第一个元素求幂,一个得到$g^0$,一个得到$g^{2^n}=g^0$;分别取第二个元素求幂,也相等,均等于$g^2$。也就是说,通过对原始循环群的每个元素求幂,得到的新的集合,它相当于循环群前半段的各元素求幂。也就是说,所得集合,相当于从原循环群里从第1个元素$g^0$开始,每隔1个元素取一个,所得就是取幂后的新集合。 - -接下来看得到的这个新的集合,它也构成一个循环子群,它的元素数目为$2^{n-1}$,也是2的幂。它的每个元素,可以通过生成元$g^2$得到。所以,我们可以将它继续求幂,得到容量为原始循环子群四分之一的循环子群,...,直到得到1阶的循环子群:$\{g^0\}$。 - -再考察一个具体的例子: - -假设有一个模13乘法群$\{0, 1, 2, 3, ,..12\}$,我们取8作为生成元,取8的所有的幂,发现只有4个可能的值:$\{1, 8, 12, 5\}$,它构成一个循环子群,这个循环子群的阶为4,也就意味着可以通过求幂得到:$\{8^0, 8^2, 8^4, 8^6\}$ = $\{1, 12, 1, 12\}$,即循环子群$\{1,12\}$;进一步求幂,得到$\{1\}$。 - - -理解了这个性质,谁理解FFT的一大关键。 - -### FFT变换过程 -现在来通过一个例子看FFT变换的原理。 - -假设有一个多项式$f(x)=3x^5 + 7x^4 + x^3 + 2x^2 + 3x + 6$,它构建在模13乘法群$\{0, 1, 2, 3, ,..12\}$上。给定输入集合:$\{1, 8, 12, 5\}$。注意,这个集合实际上是通过8生成的循环子群,容量为2的某个幂,意味着可以通过对每个元素求幂(从第一个元素开始,每隔1个元素取一个)的方式,得到一个容量减半的循环子群,直到得到集合$\{1\}。这个过程我们这里简称为“**求幂分解**” - -接下来我们来处理多项式f(x). - -如果按照传统做法,我们要把每个输入元素带入多项式,得到多项式的解。如果采用FFT的做法,会先把f(x),提取出幂为偶数的部分: - -$even(x) = 7x^4 + 2x^2 + 6$ - -如果我们把$x^2$看成一个整体,那么可以简化为 -$even(x) = 7x^2 + 2x + 6$ - -对于f(x)幂为奇数的部分$3x^5 + x^3 + 3x$,它可以看作: - -$x(3x^4 + x^2 + 3) = x*odd(x^2)$ -其中 -$odd(x) = 3x^2 + x + 3$. - -所以f(x)用多项式event、odd重构为 -$f(x) = even(x^2) + x*odd(x^2)$ - -这个过程我们这里简称为“**奇偶分解**”。理解这个过程,是理解FFT的另一关键。 - -注意到,如果我们知道每个输入值x对应的幂$x^2$,构成了一个容积为2的循环子群,如果我们分别知道even和odd在这个折半循环子群上的解,就可以将结果归并出来,得到最终f(x)在每个x的取值。 - -有了对输入的"求幂分解",和对多项式的"奇偶分解",我们就可以对问题进一步分解下去。这里画了一张图来整理一下,图中每个节点的输入,均由上一个节点输入“求幂分解”得来,图中每个节点的多项式,则由上一个节点的多项式“奇偶分解”得来: - -![](https://i.imgur.com/yPxQh5t.jpg) - - -我们按照自底向上的方式求值。 - -对于最底层的情况,将$8^0$也就是1,分别带入各个多项式,得到的结果为(注意一切计算结果需要模13): -- $7*1 + 6 = 13 = 0$ -- $2$ -- $3*1 + 3 = 6$ -- $1$ - -我们利用最底层的计算结果,来计算倒数第二层的多项式计算结果: -- $7x^2 + 2x +6 = even(x^2) + x*odd(x^2)$,那么 - - 若$x=8^0$,那么该多项式结果为$even(8^0) + 8^0*odd(8^0) = 0 + 8^0 * 2 = 2$ - - 若$x=8^2$,那么该多项式结果为$even(8^4) + 8^2*odd(8^4) = even(8^0) + 8^2*odd(8^0)=0 + 8^2*2 = 11$ - -- $3x^2 + x + 3 = even(x^2) + x*odd(x^2)$,那么 - - 若$x=8^0$,那么该多项式结果为$even(8^0) + 8^0*odd(8^0) = 6 + 8^0 * 1 = 7$ - - 若$x=8^2$,那么该多项式结果为$even(8^4) + 8^2*odd(8^4) = even(8^0) + 8^2*odd(8^0) = 6 + 8^2*1 = 5$ - -最后,我们来计算顶层的结果: -- $3*x^5 + 7*x^4 + x^3 + 2*x^2 + 3*x + 6 = even(x^2) + x*odd(x^2)$,那么 - - 若$x=8^0$,那么该多项式结果为$even(8^0) + 8^0*odd(8^0) = 2 + 8^0*7 = 9$ - - 若$x=8^1$,那么该多项式结果为$even(8^2) + 8^1*odd(8^2) = 11 + 8^1*5 = 12$ - - 若$x=8^2$,那么该多项式结果为$even(8^4) + 8^2*odd(8^4) = even(8^0) + 8^2*odd(8^0) = 2 + 8^2*7 = 8$ - - 若$x=8^3$,那么该多项式结果为$even(8^6) + 8^3*odd(8^6) = even(8^2) + 8^3*odd(8^2) = 11 + 8^3*5 = 10$ - -我们把上述计算结果也整理一下,红色标记为输出: - -![](https://i.imgur.com/h2UZXfR.jpg) - -这个过程和归并排序很像,它们都遵循这样一个模式(源自[V神的文章](https://vitalik.ca/general/2019/05/12/fft.html)): - -![](https://vitalik.ca/images/fft-files/sorting.png) - -### FFT总结 -FFT用于求解这么一个问题:给定一个某个域上的多项式f(x),还有一组输入D(也就是横坐标),求这组输入对应的纵坐标。其中输入D必须是阶为2的某个幂的循环子群。 - -我们将问题的两个部分进行分解: -- 对于输入D,通过“求幂分解”,得到阶折半的循环子群 -- 对于多项式f(x),通过“奇偶分解”,得到两个子多项式 - -分别求解两个子问题,再对结果进行归并,所得的时间复杂度就是O(NlogN),因为相当于每一行都操作了N个元素,总共有logN行。 - - - -## 参考链接 -- FFT: https://vitalik.ca/general/2019/05/12/fft.html -- stark课程介绍:https://aszepieniec.github.io/stark-anatomy/ -- stark 科普:https://mp.weixin.qq.com/s/OrSNhNUncnzh7_bmvRpkbw -- dydx: https://mp.weixin.qq.com/s/Jnm7eOunGyaiGVMPBzz70g \ No newline at end of file diff --git a/crypto/Zcash/readme.md b/crypto/Zcash/readme.md deleted file mode 100644 index 2fc199e01..000000000 --- a/crypto/Zcash/readme.md +++ /dev/null @@ -1,34 +0,0 @@ -# Zcash - -## 原理介绍 -ZCash是在Bitcoin上的改进,所以也是基于UTXO模型,zcash中用note代替。 -note为ZCash的基本交易单位。一个交易的输入和输出都是数个note。 -### 数据结构 -以note=(PK, v, r)来表示note,PK为公钥(Public Key)、v是金额(Value)、r是序列号(Random Serial Number)。 -PK为接收者地址,v是金额,r为随机数,用于作废note - -ZCash的节点会包含两个集合,每个集合都包含: -- Note Commitment -交易的输出,表示一张新的note被发出,一张有效的commitment即为一张note的存在证明,此commitment为hash(note),因此可以确保他人不知道所有者、金额。 -- Nullifier Commitment -交易的输入,表示要将一张note花掉了,一个nullifier对应唯一的commitment,为了要知道是哪个commitment,nullifier为hash(r)。现在大家应该知道为什么需要序列号了吧! - -### 交易流程 -屏蔽交易(Shielding Transaction)。 - -Alice 想向Bob发送ZEC(ZCash所发的代币), Alice可以控制PK1(她的公钥)而Bob可以控制PK2(他的公钥)。与比特币相比,Zcash的一个不同之处在于Alice生成一个零知识证明来证明她有权使用Note1。转账后note1会输出为note4和其他note(找零)。 - -过程如下: -1. Alice随机选择一个序列号(r) 并定义一个新的Note4。 -2. 她将Note4 发送给Bob。 -3. Alice 通过将Nullifier发送到所有节点来使Note1无效。 -4. Alice 将新Note4的hash发送给所有节点 -5. Alice 发布一个​​证明(proof)告诉节点,Note1的Hash存在于Hash集合中,sk1是PK1的私钥,而hash(r) 是Note1的Nullifier。 - - - -## 参考链接 -- zcash readthedocs: https://zcash.readthedocs.io/en/latest/rtd_pages/basics.html -- 原理介绍: https://www.panewslab.com/zh/articledetails/95d38u443373.html -- ZEXE: https://mirror.xyz/kurtpan.eth/Y3r-STH3NLo4hY3P7vetL9hXRfvihUnNBvaTv0Kqezk -- zether: https://eprint.iacr.org/2019/191.pdf \ No newline at end of file diff --git a/crypto/readme.md b/crypto/readme.md deleted file mode 100644 index 7240ea2b0..000000000 --- a/crypto/readme.md +++ /dev/null @@ -1,32 +0,0 @@ -# 密码学 - -## 密码学基础 -请完成习题: https://0xparc.notion.site/Prerequisite-understanding-questions-c5ebb77a5cc049f39577ec9a7fb7b22c - -## snark 入门文章 -vitalik: https://vitalik.ca/general/2017/11/09/starks_part_1.html -vitalik: https://vitalik.ca/general/2017/02/01/zk_snarks.html -安比实验室入门系列: https://mp.weixin.qq.com/s/V5C7-kwdHRrEVGJjINJ3hQ - - - -## zkEVM -介绍: https://hackmd.io/@yezhang/S1_KMMbGt -zkevm架构:https://mp.weixin.qq.com/s/q-BmJfsRIqTa2zL93Rq0eg -Scroll Tech: https://hackmd.io/@yezhang/S1sJ2cEWY -0x parc: https://0xparc.org/blog/zk-learning-group -https://blog.goodaudience.com/understanding-zero-knowledge-proofs-through-simple-examples-df673f796d99 -zkclub: https://www.youtube.com/playlist?list=PLj80z0cJm8QHm_9BdZ1BqcGbgE-BEn-3Y -zkevm-specification: https://ethresear.ch/t/a-zk-evm-specification/11549 - -## 参考链接 -- zk workshop: https://www.zkhack.dev/ -- zkp: https://github.com/appliedzkp -- vitalik ca: https://vitalik.ca/general/2021/11/05/halo.html -- zkevm book: https://hackmd.io/@liangcc/zkvmbook/https%3A%2F%2Fhackmd.io%2FHfCsKWfWRT-B_k5j3LjIVw -- 笔记: https://www.yuque.com/u428635/scg32w/edmn74#a8ffe0d3 -- stark: https://aszepieniec.github.io/stark-anatomy/ -- readpaper: https://readpaper.com/ -- Cryptograph course by Dr. Julian Hosp -- 公开课: https://people.cs.georgetown.edu/jthaler/ProofsArgsAndZK.pdf -- 关于零知识应用安全性的几点思考: https://mirror.xyz/bubb1es.eth/V9pqaI7l5U08yq-kRhL6kYcrpCALMYuxJQ3TP-Pa0iA \ No newline at end of file diff --git a/defi/Aave/graph/package.json b/defi/Aave/graph/package.json index dd3fbb757..2c1d67949 100644 --- a/defi/Aave/graph/package.json +++ b/defi/Aave/graph/package.json @@ -19,14 +19,12 @@ "ts-node": "^9.1.1", "tsconfig": "^7.0.0", "tsconfig-paths": "^3.10.1", - "typechain": "^4.0.0", "typescript": "^4.2.3", "@types/react": "17.0.24", "@types/react-dom": "17.0.9", - "urql": "2.0.5", + "node-fetch": "3.2.10", - "graphql-request": "3.5.0", - "@aave/protocol-js": "4.1.0", + "@typechain/ethers-v5": "7.1.2" }, "dependencies": { diff --git a/lib/openzeppelin-contracts b/lib/openzeppelin-contracts deleted file mode 160000 index a5445b0af..000000000 --- a/lib/openzeppelin-contracts +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a5445b0afb8b350417b6e6ab3160554967bc151f diff --git a/socialfi/lens/README.md b/socialfi/lens/README.md deleted file mode 100644 index ef4c6b598..000000000 --- a/socialfi/lens/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# 介绍 - -Lens是面向社交的基础设施。使用Lens提交的协议,用户可以: - -- 创建Profile -- 关注Profile -- 发表内容 -- 转发内容 - -此外,用户还可以参与治理,自己定制相关的逻辑 - -# 概念 - -- Profile NFT: 每一个Profile都用一个NFT来表示。 -- Follow NFT:每一个用户关注Profile,这种关注关系用follow NFT来表示 -- Publications:用户发表的内容,它们自身的内容用contentURI表示,通常存储在分布式存储上。包括三种: - - post:发布帖子。这是最基本的Publications。它 - - comment:用户对publications的评论。 - - mirror:类似retweet。 - -- Modules:一个模块是一个合约,它类似于勾子,决定了特定行为的定制化逻辑。 - - Follow Module:Profile可以指定别人follow自己时的逻辑,比如支付特定的代币才可以关注自己等等 - - Reference Module:Profile可以指定别人引用自己创作时的逻辑,比如支付多少钱才可以引用等。 - -# 应用 -目前的一些应用包括: -- LensFrens:官网的lens推特 -- Lenster:去中心化的推特 -- Sepena:基于lens的搜索引擎,可以根据关键字搜索lenster等网站上的内容 -- MadFinance:一个reference 模块,可以根据流支付协议来给创作者资助 -- 0xRig:一个基于lens的通信,无需号码,直接给对方拨打电话 -- lensCollectionAuctions:一个collect模块,通过拍卖的方式获取价格 -- AuraReputation:一个reference模块,结合chainlink提供的用户信誉信息,只允许有足够信誉的用户引用自己的内容。 - - -# 参考 -[lens源码](https://github.com/lens-protocol/core) -[lens文档](https://docs.lens.xyz/docs/deploying-the-protocol) -[lens介绍](https://www.youtube.com/watch?v=2ex8Ns4MzZk) diff --git a/socialfi/lens/minitwitter/client/.gitignore b/socialfi/lens/minitwitter/client/.gitignore deleted file mode 100644 index 4d29575de..000000000 --- a/socialfi/lens/minitwitter/client/.gitignore +++ /dev/null @@ -1,23 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# production -/build - -# misc -.DS_Store -.env.local -.env.development.local -.env.test.local -.env.production.local - -npm-debug.log* -yarn-debug.log* -yarn-error.log* diff --git a/socialfi/lens/minitwitter/client/README.md b/socialfi/lens/minitwitter/client/README.md deleted file mode 100644 index c0541f9c0..000000000 --- a/socialfi/lens/minitwitter/client/README.md +++ /dev/null @@ -1,70 +0,0 @@ -# Getting Started with Create React App - -This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). - -## Available Scripts - -In the project directory, you can run: - -### `yarn start` - -Runs the app in the development mode.\ -Open [http://localhost:3000](http://localhost:3000) to view it in your browser. - -The page will reload when you make changes.\ -You may also see any lint errors in the console. - -### `yarn test` - -Launches the test runner in the interactive watch mode.\ -See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. - -### `yarn build` - -Builds the app for production to the `build` folder.\ -It correctly bundles React in production mode and optimizes the build for the best performance. - -The build is minified and the filenames include the hashes.\ -Your app is ready to be deployed! - -See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. - -### `yarn eject` - -**Note: this is a one-way operation. Once you `eject`, you can't go back!** - -If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. - -Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own. - -You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it. - -## Learn More - -You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). - -To learn React, check out the [React documentation](https://reactjs.org/). - -### Code Splitting - -This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) - -### Analyzing the Bundle Size - -This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) - -### Making a Progressive Web App - -This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) - -### Advanced Configuration - -This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) - -### Deployment - -This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) - -### `yarn build` fails to minify - -This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) diff --git a/socialfi/lens/minitwitter/client/package.json b/socialfi/lens/minitwitter/client/package.json deleted file mode 100644 index 19b3432b0..000000000 --- a/socialfi/lens/minitwitter/client/package.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "name": "client", - "version": "0.1.0", - "private": true, - "dependencies": { - "@testing-library/jest-dom": "^5.14.1", - "@testing-library/react": "^13.0.0", - "@testing-library/user-event": "^13.2.1", - "ethers": "^5.7.1", - "graphql": "^16.6.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-native": "^0.70.2", - "react-native-web": "^0.18.9", - "react-scripts": "5.0.1", - "urql": "^3.0.3", - "web-vitals": "^2.1.0" - }, - "scripts": { - "start": "react-scripts start", - "build": "react-scripts build", - "test": "react-scripts test", - "eject": "react-scripts eject" - }, - "eslintConfig": { - "extends": [ - "react-app", - "react-app/jest" - ] - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - } -} diff --git a/socialfi/lens/minitwitter/client/public/favicon.ico b/socialfi/lens/minitwitter/client/public/favicon.ico deleted file mode 100644 index a11777cc471a4344702741ab1c8a588998b1311a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3870 zcma);c{J4h9>;%nil|2-o+rCuEF-(I%-F}ijC~o(k~HKAkr0)!FCj~d>`RtpD?8b; zXOC1OD!V*IsqUwzbMF1)-gEDD=A573Z-&G7^LoAC9|WO7Xc0Cx1g^Zu0u_SjAPB3vGa^W|sj)80f#V0@M_CAZTIO(t--xg= z!sii`1giyH7EKL_+Wi0ab<)&E_0KD!3Rp2^HNB*K2@PHCs4PWSA32*-^7d{9nH2_E zmC{C*N*)(vEF1_aMamw2A{ZH5aIDqiabnFdJ|y0%aS|64E$`s2ccV~3lR!u<){eS` z#^Mx6o(iP1Ix%4dv`t@!&Za-K@mTm#vadc{0aWDV*_%EiGK7qMC_(`exc>-$Gb9~W!w_^{*pYRm~G zBN{nA;cm^w$VWg1O^^<6vY`1XCD|s_zv*g*5&V#wv&s#h$xlUilPe4U@I&UXZbL z0)%9Uj&@yd03n;!7do+bfixH^FeZ-Ema}s;DQX2gY+7g0s(9;`8GyvPY1*vxiF&|w z>!vA~GA<~JUqH}d;DfBSi^IT*#lrzXl$fNpq0_T1tA+`A$1?(gLb?e#0>UELvljtQ zK+*74m0jn&)5yk8mLBv;=@}c{t0ztT<v;Avck$S6D`Z)^c0(jiwKhQsn|LDRY&w(Fmi91I7H6S;b0XM{e zXp0~(T@k_r-!jkLwd1_Vre^v$G4|kh4}=Gi?$AaJ)3I+^m|Zyj#*?Kp@w(lQdJZf4 z#|IJW5z+S^e9@(6hW6N~{pj8|NO*>1)E=%?nNUAkmv~OY&ZV;m-%?pQ_11)hAr0oAwILrlsGawpxx4D43J&K=n+p3WLnlDsQ$b(9+4 z?mO^hmV^F8MV{4Lx>(Q=aHhQ1){0d*(e&s%G=i5rq3;t{JC zmgbn5Nkl)t@fPH$v;af26lyhH!k+#}_&aBK4baYPbZy$5aFx4}ka&qxl z$=Rh$W;U)>-=S-0=?7FH9dUAd2(q#4TCAHky!$^~;Dz^j|8_wuKc*YzfdAht@Q&ror?91Dm!N03=4=O!a)I*0q~p0g$Fm$pmr$ zb;wD;STDIi$@M%y1>p&_>%?UP($15gou_ue1u0!4(%81;qcIW8NyxFEvXpiJ|H4wz z*mFT(qVx1FKufG11hByuX%lPk4t#WZ{>8ka2efjY`~;AL6vWyQKpJun2nRiZYDij$ zP>4jQXPaP$UC$yIVgGa)jDV;F0l^n(V=HMRB5)20V7&r$jmk{UUIe zVjKroK}JAbD>B`2cwNQ&GDLx8{pg`7hbA~grk|W6LgiZ`8y`{Iq0i>t!3p2}MS6S+ zO_ruKyAElt)rdS>CtF7j{&6rP-#c=7evGMt7B6`7HG|-(WL`bDUAjyn+k$mx$CH;q2Dz4x;cPP$hW=`pFfLO)!jaCL@V2+F)So3}vg|%O*^T1j>C2lx zsURO-zIJC$^$g2byVbRIo^w>UxK}74^TqUiRR#7s_X$e)$6iYG1(PcW7un-va-S&u zHk9-6Zn&>T==A)lM^D~bk{&rFzCi35>UR!ZjQkdSiNX*-;l4z9j*7|q`TBl~Au`5& z+c)*8?#-tgUR$Zd%Q3bs96w6k7q@#tUn`5rj+r@_sAVVLqco|6O{ILX&U-&-cbVa3 zY?ngHR@%l{;`ri%H*0EhBWrGjv!LE4db?HEWb5mu*t@{kv|XwK8?npOshmzf=vZA@ zVSN9sL~!sn?r(AK)Q7Jk2(|M67Uy3I{eRy z_l&Y@A>;vjkWN5I2xvFFTLX0i+`{qz7C_@bo`ZUzDugfq4+>a3?1v%)O+YTd6@Ul7 zAfLfm=nhZ`)P~&v90$&UcF+yXm9sq!qCx3^9gzIcO|Y(js^Fj)Rvq>nQAHI92ap=P z10A4@prk+AGWCb`2)dQYFuR$|H6iDE8p}9a?#nV2}LBCoCf(Xi2@szia7#gY>b|l!-U`c}@ zLdhvQjc!BdLJvYvzzzngnw51yRYCqh4}$oRCy-z|v3Hc*d|?^Wj=l~18*E~*cR_kU z{XsxM1i{V*4GujHQ3DBpl2w4FgFR48Nma@HPgnyKoIEY-MqmMeY=I<%oG~l!f<+FN z1ZY^;10j4M4#HYXP zw5eJpA_y(>uLQ~OucgxDLuf}fVs272FaMxhn4xnDGIyLXnw>Xsd^J8XhcWIwIoQ9} z%FoSJTAGW(SRGwJwb=@pY7r$uQRK3Zd~XbxU)ts!4XsJrCycrWSI?e!IqwqIR8+Jh zlRjZ`UO1I!BtJR_2~7AbkbSm%XQqxEPkz6BTGWx8e}nQ=w7bZ|eVP4?*Tb!$(R)iC z9)&%bS*u(lXqzitAN)Oo=&Ytn>%Hzjc<5liuPi>zC_nw;Z0AE3Y$Jao_Q90R-gl~5 z_xAb2J%eArrC1CN4G$}-zVvCqF1;H;abAu6G*+PDHSYFx@Tdbfox*uEd3}BUyYY-l zTfEsOqsi#f9^FoLO;ChK<554qkri&Av~SIM*{fEYRE?vH7pTAOmu2pz3X?Wn*!ROX ztd54huAk&mFBemMooL33RV-*1f0Q3_(7hl$<#*|WF9P!;r;4_+X~k~uKEqdzZ$5Al zV63XN@)j$FN#cCD;ek1R#l zv%pGrhB~KWgoCj%GT?%{@@o(AJGt*PG#l3i>lhmb_twKH^EYvacVY-6bsCl5*^~L0 zonm@lk2UvvTKr2RS%}T>^~EYqdL1q4nD%0n&Xqr^cK^`J5W;lRRB^R-O8b&HENO||mo0xaD+S=I8RTlIfVgqN@SXDr2&-)we--K7w= zJVU8?Z+7k9dy;s;^gDkQa`0nz6N{T?(A&Iz)2!DEecLyRa&FI!id#5Z7B*O2=PsR0 zEvc|8{NS^)!d)MDX(97Xw}m&kEO@5jqRaDZ!+%`wYOI<23q|&js`&o4xvjP7D_xv@ z5hEwpsp{HezI9!~6O{~)lLR@oF7?J7i>1|5a~UuoN=q&6N}EJPV_GD`&M*v8Y`^2j zKII*d_@Fi$+i*YEW+Hbzn{iQk~yP z>7N{S4)r*!NwQ`(qcN#8SRQsNK6>{)X12nbF`*7#ecO7I)Q$uZsV+xS4E7aUn+U(K baj7?x%VD!5Cxk2YbYLNVeiXvvpMCWYo=by@ diff --git a/socialfi/lens/minitwitter/client/public/index.html b/socialfi/lens/minitwitter/client/public/index.html deleted file mode 100644 index aa069f27c..000000000 --- a/socialfi/lens/minitwitter/client/public/index.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - React App - - - -
- - - diff --git a/socialfi/lens/minitwitter/client/public/manifest.json b/socialfi/lens/minitwitter/client/public/manifest.json deleted file mode 100644 index 080d6c77a..000000000 --- a/socialfi/lens/minitwitter/client/public/manifest.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "short_name": "React App", - "name": "Create React App Sample", - "icons": [ - { - "src": "favicon.ico", - "sizes": "64x64 32x32 24x24 16x16", - "type": "image/x-icon" - }, - { - "src": "logo192.png", - "type": "image/png", - "sizes": "192x192" - }, - { - "src": "logo512.png", - "type": "image/png", - "sizes": "512x512" - } - ], - "start_url": ".", - "display": "standalone", - "theme_color": "#000000", - "background_color": "#ffffff" -} diff --git a/socialfi/lens/minitwitter/client/public/robots.txt b/socialfi/lens/minitwitter/client/public/robots.txt deleted file mode 100644 index e9e57dc4d..000000000 --- a/socialfi/lens/minitwitter/client/public/robots.txt +++ /dev/null @@ -1,3 +0,0 @@ -# https://www.robotstxt.org/robotstxt.html -User-agent: * -Disallow: diff --git a/socialfi/lens/minitwitter/client/src/App.css b/socialfi/lens/minitwitter/client/src/App.css deleted file mode 100644 index a2c0aa029..000000000 --- a/socialfi/lens/minitwitter/client/src/App.css +++ /dev/null @@ -1,15 +0,0 @@ -.loading { - margin:auto; - width: 50%; - height: 0px; - padding-bottom: 50%; - background: rgba(0, 0, 0, 0.834) - url("https://media.giphy.com/media/8agqybiK5LW8qrG3vJ/giphy.gif") center - no-repeat; - z-index: 1; -} - - -.profile { - border: 1px solid red; -} \ No newline at end of file diff --git a/socialfi/lens/minitwitter/client/src/App.js b/socialfi/lens/minitwitter/client/src/App.js deleted file mode 100644 index 32ba00fa4..000000000 --- a/socialfi/lens/minitwitter/client/src/App.js +++ /dev/null @@ -1,60 +0,0 @@ -import {client, recommendProfiles} from './api/api' -import {useState, useEffect} from 'react'; -import { Image } from 'react-native'; -import './App.css'; - -function App() { - const [profiles, setProfiles] = useState([]) - - useEffect(()=>{ - fetchProfiles().then(users=>{ - setProfiles(users) - }) - }, []) - - if (profiles.length == 0){ - return ( -
-
- ) - } - - return ( -
- { - profiles.map((p, index)=> ( - - )) - } -
- ); -} - -function UserContent(props) { - const profile = props.profile; - return ( -
-
- {profile.picture?.original?.url? - () : - (
) - } -

{profile.handle}

-

{profile.bio}

-
-
- - ) -} - -async function fetchProfiles() { - try { - const response = await client.query(recommendProfiles).toPromise(); - return response.data.recommendedProfiles; - } - catch(err){ - console.log({err}) - } -} - -export default App; diff --git a/socialfi/lens/minitwitter/client/src/api/api.js b/socialfi/lens/minitwitter/client/src/api/api.js deleted file mode 100644 index 845f48056..000000000 --- a/socialfi/lens/minitwitter/client/src/api/api.js +++ /dev/null @@ -1,92 +0,0 @@ -import { createClient } from "urql"; - -const APIURL = "https://api.lens.dev"; - -export const client = createClient({ - url: APIURL -}) - -export const recommendProfiles = ` -query RecommendedProfiles { - recommendedProfiles { - id - name - bio - attributes { - displayType - traitType - key - value - } - followNftAddress - metadata - isDefault - picture { - ... on NftImage { - contractAddress - tokenId - uri - verified - } - ... on MediaSet { - original { - url - mimeType - } - } - __typename - } - handle - coverPicture { - ... on NftImage { - contractAddress - tokenId - uri - verified - } - ... on MediaSet { - original { - url - mimeType - } - } - __typename - } - ownedBy - dispatcher { - address - canUseRelay - } - stats { - totalFollowers - totalFollowing - totalPosts - totalComments - totalMirrors - totalPublications - totalCollects - } - followModule { - ... on FeeFollowModuleSettings { - type - amount { - asset { - symbol - name - decimals - address - } - value - } - recipient - } - ... on ProfileFollowModuleSettings { - type - } - ... on RevertFollowModuleSettings { - type - } - } - } - } -` \ No newline at end of file diff --git a/socialfi/lens/minitwitter/client/src/index.css b/socialfi/lens/minitwitter/client/src/index.css deleted file mode 100644 index ec2585e8c..000000000 --- a/socialfi/lens/minitwitter/client/src/index.css +++ /dev/null @@ -1,13 +0,0 @@ -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; -} diff --git a/socialfi/lens/minitwitter/client/src/index.js b/socialfi/lens/minitwitter/client/src/index.js deleted file mode 100644 index c812139db..000000000 --- a/socialfi/lens/minitwitter/client/src/index.js +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom/client'; -import './index.css'; -import App from './App'; - -const root = ReactDOM.createRoot(document.getElementById('root')); -root.render( - - - -); - -// If you want to start measuring performance in your app, pass a function -// to log results (for example: reportWebVitals(console.log)) -// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals diff --git a/socialfi/lens/package.json b/socialfi/lens/package.json deleted file mode 100644 index e69de29bb..000000000