背景

R1CS 的背景源于零常识证实和可验证计算畛域的钻研,它是一种用于示意计算束缚的形式化模型,能够形容计算中的输出、输入和约束条件之间的关系。R1CS 的设计旨在使计算过程的束缚可能以一种无效和紧凑的形式进行示意,并且可能利用于零常识证实的构建。

在 Bulletproofs 算法中,R1CS(Rank-1 Constraint System)是一种用于构建束缚的模型,用于形容计算过程中的束缚关系。R1CS 提供了一种形式来表白计算中的束缚,为构建零常识证实和爱护隐衷提供了根底。Bulletproofs 利用 R1CS 模型来构建零常识证实,从而实现在不泄露任何无关输出和计算过程的信息的状况下验证计算的正确性。

Bulletproofs 须要相熟其根底概念能力更好的把握和应用,请移步:https://www.yuque.com/tsdoc/ts/bulletproofs

命令行

公共参数(-ppgen/-pp)

  • 生成公共参数
$ tongsuo bulletproofs -ppgen -out ./pp.pem -curve_name sm2 -gens_capacity 64 -party_capacity 1

参数阐明,其中 bulletproofs 是 tongsuo 的子命令:bulletproofs 性能。不再赘述。

    • -ppgen:是 bulletproofs 的子命令,指公共参数的生成,pp 是 pub_param 的缩写,gen 是 generate 的缩写;
    • -out:输入文件门路;
    • -curve_name:椭圆曲线名称;
    • -gens_capacity:椭圆曲线点生成器的容量,对于 r1cs 来说,该数须大于约束条件表达式中乘法变量的数量;
    • -party_capacity:能够生成聚合证实的最大参与方数量,仅对 range proof 无效,r1cs proof 设置为1即可。

<!---->

  • 文本显示公共参数

-pp 是用来显示公共参数的子命令。

$ tongsuo bulletproofs -pp -in ./pp.pem -text -nooutBulletproofs Public Parameter:curve: SM2 (1172)gens_capacity: 64party_capacity: 1G[n]:    [0]: 02:a3:df:fe:3f:b6:88:0e:34:79:be:25:71:b2:03:97:0f:86:58:78:57:32:4d:b4:fa:70:0e:2f:0c:3b:d0:ea:85    [1]: 03:42:ee:45:da:e7:ee:84:78:8f:18:03:42:c4:0f:9e:0e:93:d8:82:54:08:a4:1a:30:38:bc:94:57:e7:9e:8b:61    [2]: 03:8a:7c:c7:fb:87:07:b0:a9:fe:65:1e:2a:b7:6a:98:02:0e:3d:1a:43:7d:7c:1a:d4:62:60:ce:00:87:e3:ec:04    [3]: 03:85:1b:e5:2f:be:1a:91:9c:6a:42:db:22:e0:35:7e:b8:61:67:56:f6:f4:04:51:2d:8d:13:82:58:ec:5a:2d:ec    # 太长了,两头省略了 #    [60]: 02:21:70:bc:20:33:2e:0b:b3:27:8d:c2:f3:38:f3:a6:8c:8b:05:5d:0a:15:df:ed:5f:ec:2a:3b:bf:d1:4c:fe:eb    [61]: 03:53:89:6e:6e:8a:9e:1f:b6:54:63:50:c5:59:14:c5:1f:c2:c4:32:35:d4:8f:43:22:25:cd:3d:52:25:ee:ea:d1    [62]: 03:e4:f5:ff:b3:25:f6:ff:d7:ed:01:db:17:fa:8b:9c:c6:79:84:e3:6a:bf:42:17:b6:7b:9e:f7:d1:3e:7d:41:54    [63]: 02:e8:de:7e:27:21:0d:95:03:5b:f1:0e:1d:04:cb:f0:cd:1d:96:25:e7:4f:8b:49:0c:fb:08:cb:e6:a9:af:7f:0aH[n]:    [0]: 03:e5:df:a2:8d:50:4e:d5:7f:64:a6:e5:88:a9:17:de:ff:d8:92:2b:57:1c:25:90:2e:8e:5d:ae:b2:21:f1:68:b4    [1]: 02:30:95:72:37:7c:9f:4c:ec:24:0d:fc:ff:08:38:77:73:49:e8:19:a8:84:cb:6f:0a:24:9e:39:31:01:a0:19:91    [2]: 03:a3:d1:84:c0:6d:c8:fa:1f:35:6c:65:75:e5:ff:63:45:16:29:bc:ee:5e:71:51:97:44:dd:03:15:bd:4f:bf:c3    [3]: 03:c3:06:44:b3:34:5c:ac:d7:ed:91:aa:24:e1:0a:cb:f7:04:61:12:d9:3d:bf:65:98:8b:f4:87:8d:9e:7f:b7:6e    # 太长了,两头省略了 #    [60]: 03:5f:30:c3:c7:29:02:38:18:5e:d2:ae:34:44:7f:44:52:fb:d1:97:24:7e:a6:7c:9e:f8:16:3f:f9:18:f3:7b:69    [61]: 02:ff:55:39:f5:be:2e:fb:29:b4:36:e6:f5:ce:d4:55:67:e9:59:3b:53:8a:af:ea:5b:6c:c6:db:45:de:5b:8b:71    [62]: 03:e2:2f:0c:fa:30:d2:ec:33:5e:aa:d0:c4:ba:7e:4e:6c:03:50:0f:26:27:72:ae:f0:d5:d8:ad:09:24:d0:94:de    [63]: 02:64:af:b1:25:f4:85:c4:6c:da:fe:e3:b6:24:2a:0d:ad:f9:8b:56:96:6c:6b:3e:f1:f5:ef:92:9d:b2:52:8c:40U: 03:85:44:28:a8:55:f4:db:cd:1b:60:42:d0:21:5b:31:ea:0e:fb:b2:2e:46:3d:a3:f0:40:48:50:05:0a:a3:a9:ecH: 02:e5:21:75:20:47:fb:c2:76:c2:86:3c:10:e0:4c:1e:72:66:26:7b:3d:5d:ac:5b:a0:de:ab:11:d3:56:bd:fc:f1

如上后果所示,G[n] 和 H[n] 就是随机生成椭圆曲线 SM2 上的点,n = gens_capacity * party_capacity,上图是 64,两头一些随机点因为太长太点篇幅省略掉了。

证据(-witness)

  • 生成证据
$ tongsuo bulletproofs -witness -pp_in ./pp.pem -out witness_r1cs.pem -r1cs a=5 b=25

参数阐明:

    • -witness 是用来生成/显示证据的子命令
    • -pp_in:指定公共参数文件所在门路
    • -out:生成的证据文件门路
    • -r1cs:是指定生成的是 r1cs 证据,否则生成的是 range proof 的证据
    • a=5 b=25 是有名变量,多个变量用空格隔开,=号后面是变量名,=号前面是变量值,目前仅反对整数(正/负均可)

<!---->

  • 显示证据
$ tongsuo bulletproofs -witness -in witness_r1cs.pem -textWitness:curve: SM2 (1172)H: 02:e5:21:75:20:47:fb:c2:76:c2:86:3c:10:e0:4c:1e:72:66:26:7b:3d:5d:ac:5b:a0:de:ab:11:d3:56:bd:fc:f1V[n]:    [a]: 02:2b:8b:0d:2c:79:f2:d6:8b:cb:11:40:6c:af:ee:f1:3f:32:f9:c9:11:68:92:81:a0:f8:c0:e9:c0:2c:e8:fe:72    [b]: 03:fb:d3:ce:8d:bb:d0:b3:71:f3:c6:3f:01:35:98:61:97:eb:af:da:08:00:7b:b3:15:35:6c:2a:a9:da:81:0a:06v[n]:    [a]: 5 (0x5)    [b]: 25 (0x19)r[n]:    [0]: 00:c7:05:43:9f:4c:72:46:61:60:36:04:5e:40:c7:1a:b2:2e:49:de:f1:b0:d1:9d:26:15:ae:ea:e3:73:a1:12:fc    [1]: 6f:3c:4c:9c:33:d3:a5:64:8e:19:4b:62:ad:43:81:f7:67:13:8d:47:f6:a7:cb:13:26:c4:03:e7:83:a7:1f:07-----BEGIN BULLETPROOFS WITNESS-----AAAElALlIXUgR/vCdsKGPBDgTB5yZiZ7PV2sW6DeqxHTVr388QAAAAICK4sNLHny1ovLEUBsr+7xPzL5yRFokoGg+MDpwCzo/nJhAAP7086Nu9CzcfPGPwE1mGGX66/aCAB7sxU1bCqp2oEKBmIAAAAAAivHBUOfTHJGYWA2BF5AxxqyLkne8bDRnSYVrurjc6ES/CtvPEycM9OlZI4ZS2KtQ4H3ZxONR/anyxMmxAPng6cfBwAAAAIrAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUrAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABk=-----END BULLETPROOFS WITNESS-----

如上后果所示,witness 中蕴含了椭圆曲线名称,H 点(与公共参数统一),密文证据 V,明文证据 v 和随机数 r。

证实(-prove/-proof)

  • 生成 r1cs 证实(-prove)
$ tongsuo bulletproofs -prove -pp_in ./pp.pem -witness_in witness_r1cs.pem -out proof-r1cs.pem -r1cs_constraint "a*a-b"$ tongsuo bulletproofs -prove -pp_in ./pp.pem -witness_in witness_r1cs.pem -out proof-r1cs.pem -r1cs_constraint "a*a-c"May be extra arguments error, please use -help for usage summary.80C58E0401000000:error:1F800070:lib(63):bp_r1cs_expression_evaluate_variable:reason(112):crypto/zkp/bulletproofs/r1cs_constraint_expression.c:266:80C58E0401000000:error:1F80006F:lib(63):bp_r1cs_expression_process:reason(111):crypto/zkp/bulletproofs/r1cs_constraint_expression.c:302:

参数阐明:

    • -pp_in:指定公共参数文件所在门路
    • -witness_in:指定证据文件所在门路
    • -out:指定证实的输入门路,输入的文件蕴含两段:R1CS PROOF 和 WITNESS,别离为 proof 和 witness
    • -r1cs_constraint:指定约束条件,外面援用的变量必须在生成证据时提交的变量名中,否则报错,能够看出第二条命令报错了

<!---->

  • 显示证实(-proof)
$ tongsuo bulletproofs -proof -in proof-r1cs.pem -textR1CS Proof:AI1: 03:1f:ed:4a:3a:ee:f3:db:a2:6a:b3:b8:96:bc:9c:c4:3d:47:69:55:96:a4:51:58:fe:99:f6:fa:db:d4:8c:42:f1AO1: 02:c1:96:7b:71:29:61:8a:e1:cf:9b:35:ef:87:da:f0:11:51:58:cd:7e:40:49:7d:48:a2:5d:c0:f3:26:f7:07:51S1: 03:da:33:9d:60:e5:07:a8:fc:f6:5b:ee:82:81:cf:28:6f:34:3f:46:04:c3:f7:93:e2:8b:0e:7a:c7:c1:05:ed:32AI2: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00AO2: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00S2: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00T1: 03:77:c3:ac:ef:56:09:18:a5:88:9a:f1:92:7c:f9:9a:ee:71:d2:66:75:5e:9c:08:9e:e1:a1:41:bb:d3:3e:3c:1cT3: 02:dd:4b:41:66:76:e6:be:59:3a:5b:6e:3e:a5:2a:10:24:b8:9f:b9:70:b0:12:09:a9:0c:72:5d:b8:82:b9:12:cfT4: 02:f9:f8:ec:7b:36:6a:b4:95:d2:5b:6b:01:ff:6e:bf:9d:74:a9:a0:3d:0d:52:e2:3b:76:70:11:57:99:fc:9e:2aT5: 03:03:de:a0:ef:5f:9e:dd:17:24:e3:4d:2b:1b:02:fc:ff:2b:fa:13:4a:58:ea:72:26:8f:15:b9:6a:c2:10:bf:1aT6: 03:dc:0b:69:a2:95:8a:f5:8d:50:5c:4e:c4:82:59:a6:e8:d6:fc:b1:c0:28:c5:27:d2:71:61:07:bf:46:61:f9:32taux: 00:8a:1e:5c:6d:8d:99:93:53:e9:6c:4c:a8:f5:c4:11:eb:df:51:36:3d:14:84:0a:0e:66:70:76:23:0f:8b:35:96mu: 00:f1:68:3f:51:06:02:a4:48:3d:06:6e:47:00:2f:39:62:54:c0:7c:88:c1:37:e3:df:8c:01:a2:05:e3:15:d5:bftx: 00:dd:60:0f:98:1e:1b:d5:9b:0b:c2:99:b4:98:4d:53:af:d3:1b:d3:31:9f:43:48:a0:90:80:07:68:dd:5b:35:96inner proof:    n: 0    L[n]:    R[n]:    a: 00:e6:9f:e7:68:89:5a:0c:74:99:d8:b3:59:51:95:d0:f2:93:5b:66:ca:eb:72:07:57:04:6b:5f:81:3b:32:ed:6a    b: 44:dd:57:f4:2f:3a:4d:b8:f3:20:93:5b:5d:dc:04:ff:4f:62:f8:26:66:e4:5f:61:28:e5:45:5e:4f:81:72:4d-----BEGIN BULLETPROOFS R1CS PROOF-----AAAElAAAAAgDH+1KOu7z26Jqs7iWvJzEPUdpVZakUVj+mfb629SMQvECwZZ7cSlhiuHPmzXvh9rwEVFYzX5ASX1Iol3A8yb3B1ED2jOdYOUHqPz2W+6Cgc8obzQ/RgTD95Piiw56x8EF7TIDd8Os71YJGKWImvGSfPma7nHSZnVenAie4aFBu9M+PBwC3UtBZnbmvlk6W24+pSoQJLifuXCwEgmpDHJduIK5Es8C+fjsezZqtJXSW2sB/26/nXSpoD0NUuI7dnARV5n8nioDA96g71+e3Rck400rGwL8/yv6E0pY6nImjxW5asIQvxoD3AtpopWK9Y1QXE7Eglmm6Nb8scAoxSfScWEHv0Zh+TIAAAADK4oeXG2NmZNT6WxMqPXEEevfUTY9FIQKDmZwdiMPizWWK/FoP1EGAqRIPQZuRwAvOWJUwHyIwTfj34wBogXjFdW/K91gD5geG9WbC8KZtJhNU6/TG9Mxn0NIoJCAB2jdWzWWAAAAAivmn+doiVoMdJnYs1lRldDyk1tmyutyB1cEa1+BOzLtaitE3Vf0LzpNuPMgk1td3AT/T2L4JmbkX2Eo5UVeT4FyTQAAAAAAAAAA-----END BULLETPROOFS R1CS PROOF-----Witness:curve: SM2 (1172)H: 02:e5:21:75:20:47:fb:c2:76:c2:86:3c:10:e0:4c:1e:72:66:26:7b:3d:5d:ac:5b:a0:de:ab:11:d3:56:bd:fc:f1V[n]:    [a]: 02:2b:8b:0d:2c:79:f2:d6:8b:cb:11:40:6c:af:ee:f1:3f:32:f9:c9:11:68:92:81:a0:f8:c0:e9:c0:2c:e8:fe:72    [b]: 03:fb:d3:ce:8d:bb:d0:b3:71:f3:c6:3f:01:35:98:61:97:eb:af:da:08:00:7b:b3:15:35:6c:2a:a9:da:81:0a:06-----BEGIN BULLETPROOFS WITNESS-----AAAElALlIXUgR/vCdsKGPBDgTB5yZiZ7PV2sW6DeqxHTVr388QAAAAICK4sNLHny1ovLEUBsr+7xPzL5yRFokoGg+MDpwCzo/nJhAAP7086Nu9CzcfPGPwE1mGGX66/aCAB7sxU1bCqp2oEKBmIA-----END BULLETPROOFS WITNESS-----

能够看出 proof-range.pem 中蕴含了两段:R1CS PROOF 和 WITNESS,这里 WITNESS 的 V 就是密文证据。

验证(-verify)

$ tongsuo bulletproofs -verify -pp_in ./pp.pem -in proof-r1cs.pem -r1cs_constraint "a*a-b"The proof is valid$ tongsuo bulletproofs -verify -pp_in ./pp.pem -in proof-r1cs.pem -r1cs_constraint "a*a-b+a*a-b"The proof is invalid$ tongsuo bulletproofs -verify -pp_in ./pp.pem -in proof-r1cs.pem -r1cs_constraint "a*5-b"The proof is invalid

验证 R1CS 的 Proof 时须要指定雷同的约束条件参数 -r1cs_constraint,否则验证失败。须要留神的是表达式肯定要统一,即便 a 和 b 的其余运算也能为 0,但不统一的约束条件会导致外部运算逻辑与 Prove 不统一而验证失败。

如上后果,能够看出,与 Prove 统一的约束条件的验证后果无效,其余有效。

Demo

代码

#include <stdio.h>#include <stdlib.h>#include <openssl/bulletproofs.h>typedef int (*r1cs_logic_func)(BP_R1CS_CTX *ctx,                               BP_R1CS_LINEAR_COMBINATION *a1,                               BP_R1CS_LINEAR_COMBINATION *a2,                               BP_R1CS_LINEAR_COMBINATION *b1,                               BP_R1CS_LINEAR_COMBINATION *b2,                               BP_R1CS_LINEAR_COMBINATION *c1,                               BP_R1CS_LINEAR_COMBINATION *c2);/* * Constrains a1*a2 + b1*b2 = c1*c2 */static int r1cs_example_logic(BP_R1CS_CTX *ctx,                              BP_R1CS_LINEAR_COMBINATION *a1,                              BP_R1CS_LINEAR_COMBINATION *a2,                              BP_R1CS_LINEAR_COMBINATION *b1,                              BP_R1CS_LINEAR_COMBINATION *b2,                              BP_R1CS_LINEAR_COMBINATION *c1,                              BP_R1CS_LINEAR_COMBINATION *c2){    int ret = 0;    BP_R1CS_LINEAR_COMBINATION *a = NULL, *b = NULL, *c = NULL;    if (!(a = BP_R1CS_LINEAR_COMBINATION_dup(a1))        || !(b = BP_R1CS_LINEAR_COMBINATION_dup(b1))        || !(c = BP_R1CS_LINEAR_COMBINATION_dup(c1)))        return 0;    /*     * 执行线性束缚运算:     * a = a1*a2     * b = b1*b2     * c = c1*c2     * a + b - c = 0     */    if (!BP_R1CS_LINEAR_COMBINATION_mul(a, a2, ctx)        || !BP_R1CS_LINEAR_COMBINATION_mul(b, b2, ctx)        || !BP_R1CS_LINEAR_COMBINATION_add(a, b)        || !BP_R1CS_LINEAR_COMBINATION_mul(c, c2, ctx)        || !BP_R1CS_LINEAR_COMBINATION_sub(a, c)        || !BP_R1CS_LINEAR_COMBINATION_constrain(a, ctx))        goto err;    ret = 1;err:    BP_R1CS_LINEAR_COMBINATION_free(a);    BP_R1CS_LINEAR_COMBINATION_free(b);    BP_R1CS_LINEAR_COMBINATION_free(c);    return ret;}static BP_R1CS_PROOF *r1cs_example_prove(BP_R1CS_CTX *ctx, BP_WITNESS *witness,                                         BIGNUM *a1, BIGNUM *a2,                                         BIGNUM *b1, BIGNUM *b2,                                         BIGNUM *c1, BIGNUM *c2,                                         r1cs_logic_func logic_func){    BP_R1CS_LINEAR_COMBINATION *lc_a1 = NULL, *lc_a2 = NULL;    BP_R1CS_LINEAR_COMBINATION *lc_b1 = NULL, *lc_b2 = NULL;    BP_R1CS_LINEAR_COMBINATION *lc_c1 = NULL, *lc_c2 = NULL;    BP_R1CS_PROOF *proof = NULL;    /*     * 往 witness 中提交有名变量:a1、a2、b1、b2、c1、c2     * 并获取相应的线性束缚对象,而后传递给 logic_func 函数中做逻辑运算     */    if (!(lc_a1 = BP_WITNESS_r1cs_linear_combination_commit(witness, "a1", a1))        || !(lc_a2 = BP_WITNESS_r1cs_linear_combination_commit(witness, "a2", a2))        || !(lc_b1 = BP_WITNESS_r1cs_linear_combination_commit(witness, "b1", b1))        || !(lc_b2 = BP_WITNESS_r1cs_linear_combination_commit(witness, "b2", b2))        || !(lc_c1 = BP_WITNESS_r1cs_linear_combination_commit(witness, "c1", c1))        || !(lc_c2 = BP_WITNESS_r1cs_linear_combination_commit(witness, "c2", c2)))        goto err;    if (!logic_func(ctx, lc_a1, lc_a2, lc_b1, lc_b2, lc_c1, lc_c2))        goto err;    /*     * 逻辑运算实现后执行 prove 操作获取 proof 对象     */    if (!(proof = BP_R1CS_PROOF_prove(ctx)))        goto err;    return proof;err:    BP_R1CS_LINEAR_COMBINATION_free(lc_a1);    BP_R1CS_LINEAR_COMBINATION_free(lc_a2);    BP_R1CS_LINEAR_COMBINATION_free(lc_b1);    BP_R1CS_LINEAR_COMBINATION_free(lc_b2);    BP_R1CS_LINEAR_COMBINATION_free(lc_c1);    BP_R1CS_LINEAR_COMBINATION_free(lc_c2);    BP_R1CS_PROOF_free(proof);    return NULL;}static int r1cs_example_verify(BP_R1CS_CTX *ctx, BP_WITNESS *witness,                               BP_R1CS_PROOF *proof, r1cs_logic_func logic_func){    BP_R1CS_LINEAR_COMBINATION *lc_a1 = NULL, *lc_a2 = NULL;    BP_R1CS_LINEAR_COMBINATION *lc_b1 = NULL, *lc_b2 = NULL;    BP_R1CS_LINEAR_COMBINATION *lc_c1 = NULL, *lc_c2 = NULL;    /*     * 从 witness 中获取有名变量(a1、a2、b1、b2、c1、c2)的线性束缚,而后传递给 logic_func 函数中做逻辑运算     */    if (!(lc_a1 = BP_WITNESS_r1cs_linear_combination_get(witness, "a1"))        || !(lc_a2 = BP_WITNESS_r1cs_linear_combination_get(witness, "a2"))        || !(lc_b1 = BP_WITNESS_r1cs_linear_combination_get(witness, "b1"))        || !(lc_b2 = BP_WITNESS_r1cs_linear_combination_get(witness, "b2"))        || !(lc_c1 = BP_WITNESS_r1cs_linear_combination_get(witness, "c1"))        || !(lc_c2 = BP_WITNESS_r1cs_linear_combination_get(witness, "c2")))        goto err;    if (!logic_func(ctx, lc_a1, lc_a2, lc_b1, lc_b2, lc_c1, lc_c2))        goto err;    /*     * 逻辑运算实现后执行 verify 操作验证 proof 对象是否无效     */    if (!BP_R1CS_PROOF_verify(ctx, proof))        goto err;    return 1;err:    BP_R1CS_LINEAR_COMBINATION_free(lc_a1);    BP_R1CS_LINEAR_COMBINATION_free(lc_a2);    BP_R1CS_LINEAR_COMBINATION_free(lc_b1);    BP_R1CS_LINEAR_COMBINATION_free(lc_b2);    BP_R1CS_LINEAR_COMBINATION_free(lc_c1);    BP_R1CS_LINEAR_COMBINATION_free(lc_c2);    return 0;}static int r1cs_proof_test(BIGNUM *a1, BIGNUM *a2, BIGNUM *b1, BIGNUM *b2, BIGNUM *c1, BIGNUM *c2,                           r1cs_logic_func logic_func){    int ret = 0;    BP_TRANSCRIPT *transcript = NULL;    BP_PUB_PARAM *pp = NULL;    BP_WITNESS *witness = NULL;    BP_R1CS_CTX *ctx = NULL;    BP_R1CS_PROOF *proof = NULL;    /* 创立交互抄本对象,证实者和验证者须要应用雷同的办法和标签,否则验证失败 */    transcript = BP_TRANSCRIPT_new(BP_TRANSCRIPT_METHOD_sha256(), "r1cs_test");    /* 创立公共参数对象 */    pp = BP_PUB_PARAM_new_by_curve_id(NID_secp256k1, 128, 1);    /* 创立该公共参数下的证据对象 */    witness = BP_WITNESS_new(pp);    ctx = BP_R1CS_CTX_new(pp, witness, transcript);    if (transcript == NULL || pp == NULL || witness == NULL || ctx == NULL)        goto err;    proof = r1cs_example_prove(ctx, witness, a1, a2, b1, b2, c1, c2, logic_func);    if (proof == NULL)        goto err;    if (!r1cs_example_verify(ctx, witness, proof, logic_func))        goto err;    ret = 1;err:    BP_R1CS_PROOF_free(proof);    BP_R1CS_CTX_free(ctx);    BP_TRANSCRIPT_free(transcript);    BP_PUB_PARAM_free(pp);    return ret;}int main(int argc, char *argv[]){    int i, a1, a2, b1, b2, c1, c2;    char *name, *value;    BIGNUM *bn_a1, *bn_a2, *bn_b1, *bn_b2, *bn_c1, *bn_c2;    BN_CTX *bn_ctx = NULL;    printf("test r1cs constraint: a1*a2 + b1*b2 = c1*c2\n");    if (argc != 7) {        printf("Invalid parameter!\n");        return -1;    }    for (i = 1; i < argc; i++) {        name = argv[i];        value = name + 3;        if (strncmp(name, "a1=", 3) == 0) {            a1 = atoi(value);        } else if (strncmp(name, "a2=", 3) == 0) {            a2 = atoi(value);        } else if (strncmp(name, "b1=", 3) == 0) {            b1 = atoi(value);        } else if (strncmp(name, "b2=", 3) == 0) {            b2 = atoi(value);        } else if (strncmp(name, "c1=", 3) == 0) {            c1 = atoi(value);        } else if (strncmp(name, "c2=", 3) == 0) {            c2 = atoi(value);        } else {            printf("Unknow parameter: %s\n", name);            return -1;        }    }    if (!(bn_ctx = BN_CTX_new()))        goto err;    bn_a1 = BN_CTX_get(bn_ctx);    bn_a2 = BN_CTX_get(bn_ctx);    bn_b1 = BN_CTX_get(bn_ctx);    bn_b2 = BN_CTX_get(bn_ctx);    bn_c1 = BN_CTX_get(bn_ctx);    bn_c2 = BN_CTX_get(bn_ctx);    if (bn_c2 == NULL)        goto err;    BN_set_word(bn_a1, a1);    BN_set_word(bn_a2, a2);    BN_set_word(bn_b1, b1);    BN_set_word(bn_b2, b2);    BN_set_word(bn_c1, c1);    BN_set_word(bn_c2, c2);    if (r1cs_proof_test(bn_a1, bn_a2, bn_b1, bn_b2, bn_c1, bn_c2, r1cs_example_logic))        printf("test ok, %d*%d + %d*%d = %d*%d\n", a1, a2, b1, b2, c1, c2);    else        printf("test failed, %d*%d + %d*%d != %d*%d\n", a1, a2, b1, b2, c1, c2);err:    BN_CTX_free(bn_ctx);    return 0;}

如上代码正文所示,一次残缺的 R1CS 调用波及6个数据结构,别离为:

  • BP_TRANSCRIPT

该数据结构是交互抄本的构造,用来模仿交互式零常识计划中的交互,是 Bulletproofs 为非交互式零常识证实算法的要害,利用了 Fiat-Shamir 变换将其转变为随机预言机模型中的非交互式零常识计划。

    • 创立/开释
/* * 创立 BP_TRANSCRIPT * 参数: *    method:目前仅实现了 sha256 的办法,通过调用 BP_TRANSCRIPT_METHOD_sha256() 取得,后续能够实现其余更高效的办法 *    label:证实者和验证者的标签/标识 */BP_TRANSCRIPT *BP_TRANSCRIPT_new(const BP_TRANSCRIPT_METHOD *method,                                 const char *label);/* * 开释 BP_TRANSCRIPT */void BP_TRANSCRIPT_free(BP_TRANSCRIPT *transcript);
  • BP_PUB_PARAM

该数据结构用来保留 Bulletproofs 的公共参数,证实者和验证者须要在同一个公共参数下才有意义,否则证实者生成的证实验证者永远无奈验证通过。

    • 创立/开释
/* * 创立 BP_PUB_PARAM * 参数: *    gens_capacity:对于 r1cs proof 来,该数须大于约束条件表达式中乘法变量的数量 *    party_capacity:仅对 range proof 无效,对 r1cs proof 设置为1即可 */BP_PUB_PARAM *BP_PUB_PARAM_new(const EC_GROUP *group, int gens_capacity,                               int party_capacity);BP_PUB_PARAM *BP_PUB_PARAM_new_by_curve_name(const char *curve_name,                                             int gens_capacity,                                             int party_capacity);BP_PUB_PARAM *BP_PUB_PARAM_new_by_curve_id(int curve_id,                                           int gens_capacity,                                           int party_capacity);/*  * 开释 BP_PUB_PARAM */void BP_PUB_PARAM_free(BP_PUB_PARAM *pp);
    • 编码/解码
/* * 编码 BP_PUB_PARAM 成二进制格局,写入 out 指定的内存区域中 * 参数: *    pp:公共参数对象 *       out:要写入的内存指针,如果为 NULL 则返回须要的内存大小,用于申请所需的内存 *    size:out 内存区域大小 */size_t BP_PUB_PARAM_encode(const BP_PUB_PARAM *pp, unsigned char *out, size_t size);/* * 解码 BP_PUB_PARAM * 参数: *    in:已编码的证实内存指针 *    size:in 指针内存区域大小 */BP_PUB_PARAM *BP_PUB_PARAM_decode(const unsigned char *in, size_t size);
  • BP_WITNESS

证据数据结构,用来保留明文证据和密文证据,其中明文证据用于 prove,密文证据用于 verify。

    • 创立/开释
/* * 创立 BP_WITNESS * 参数: *    pp:公共参数对象 */BP_WITNESS *BP_WITNESS_new(const BP_PUB_PARAM *pp);/* * 开释 BP_WITNESS */void BP_WITNESS_free(BP_WITNESS *witness);
    • 提交/获取
/* * 提交变量到证据中 * 参数: *    witness:证据对象 *       name:变量名称,个别由证实者绑定变量名称和变量值,验证者通过变量名称获取到对应的密文变量值(即密文证据),转换成线性组合后能够进行束缚表达式的运算 *       v:变量值,也就是明文证据值 */int BP_WITNESS_r1cs_commit(BP_WITNESS *witness, const char *name, BIGNUM *v);/* * 提交变量到证据中,并获取线性组合对象(用于束缚表达式的运算),个别由证实者调用 * 参数: *    witness:证据对象 *       name:变量名称 *       v:变量值 */BP_R1CS_LINEAR_COMBINATION *BP_WITNESS_r1cs_linear_combination_commit(BP_WITNESS *witness, const char *name, BIGNUM *v);/* * 从 witness 中获取变量名为 name 的变量,并转换成线性组合后返回线性组合的对象指针,个别由验证者调用 * 参数: *    witness:证据对象 *       name:变量名称 */BP_R1CS_LINEAR_COMBINATION *BP_WITNESS_r1cs_linear_combination_get(BP_WITNESS *witness, const char *name);
    • 编码/解码
/* * 编码 BP_WITNESS 成二进制格局,写入 out 指定的内存区域中 * 参数: *    witness:证据对象 *       out:要写入的内存指针,如果为 NULL 则返回须要的内存大小,用于申请所需的内存 *    size:out 内存区域大小 *    flag:是否编码明文证据的开关,1为编码,0为不编码 */size_t BP_WITNESS_encode(const BP_WITNESS *witness, unsigned char *out, size_t size, int flag);/* * 解码 BP_WITNESS * 参数: *    in:已编码的证据内存指针 *    size:in 指针内存区域大小 *    flag:是否解码明文证据的开关,1为解码,0为不解码 */BP_WITNESS *BP_WITNESS_decode(const unsigned char *in, size_t size, int flag);
  • BP_R1CS_LINEAR_COMBINATION

R1CS 线性组合数据结构,用来保留各个变量的组合关系。

    • 创立/开释
/* * 创立线性组合对象 */BP_R1CS_LINEAR_COMBINATION *BP_R1CS_LINEAR_COMBINATION_new(void);/* * 复制线性组合对象 */BP_R1CS_LINEAR_COMBINATION *BP_R1CS_LINEAR_COMBINATION_dup(const BP_R1CS_LINEAR_COMBINATION *lc);/* * 开释线性组合对象内存 */void BP_R1CS_LINEAR_COMBINATION_free(BP_R1CS_LINEAR_COMBINATION *lc);/* * 清空线性组合对象,复用对象之前须要清空一下 */int BP_R1CS_LINEAR_COMBINATION_clean(BP_R1CS_LINEAR_COMBINATION *lc);
    • 加/减/乘运算
/* * 线性组合底层乘法,将 l 和 r 别离转换成线性组合 left 和 right,并将 l * r 的后果转换成线性组合 output  * 参数: *       output:用来保留 l * r 转换成线性组合的指针 *       left:用来保留 l 转换成线性组合的指针 *       right:用来保留 r 转换成线性组合的指针 *       l:乘法右边参数 *       r:乘法左边参数 *       ctx:上下文对象 */int BP_R1CS_LINEAR_COMBINATION_raw_mul(BP_R1CS_LINEAR_COMBINATION **output,                                       BP_R1CS_LINEAR_COMBINATION **left,                                       BP_R1CS_LINEAR_COMBINATION **right,                                       const BIGNUM *l, const BIGNUM *r,                                       BP_R1CS_CTX *ctx);/* * 线性组合乘法,执行:lc *= other * 参数: *       lc:乘法第一个参数及保留乘法后果:lc *= other *       other:乘法另一个参数 *       ctx:上下文对象 */int BP_R1CS_LINEAR_COMBINATION_mul(BP_R1CS_LINEAR_COMBINATION *lc,                                   const BP_R1CS_LINEAR_COMBINATION *other,                                   BP_R1CS_CTX *ctx);/* * 线性组合加法,执行:lc += other * 参数: *       lc:加法第一个参数及保留加法后果:lc += other *       other:加法另一个参数 */int BP_R1CS_LINEAR_COMBINATION_add(BP_R1CS_LINEAR_COMBINATION *lc,                                   const BP_R1CS_LINEAR_COMBINATION *other);/* * 线性组合减法,执行:lc -= other * 参数: *       lc:减法第一个参数及保留减法后果:lc -= other *       other:减法另一个参数 */int BP_R1CS_LINEAR_COMBINATION_sub(BP_R1CS_LINEAR_COMBINATION *lc,                                   const BP_R1CS_LINEAR_COMBINATION *other);/* * 线性组合取正数,执行:lc = -lc * 参数: *       lc:线性组合 */int BP_R1CS_LINEAR_COMBINATION_neg(BP_R1CS_LINEAR_COMBINATION *lc);/* * 线性组合标量乘法,执行:lc *= value * 参数: *       lc:乘法第一个参数及保留乘法后果:lc *=  value *       value:常数标量 */int BP_R1CS_LINEAR_COMBINATION_mul_bn(BP_R1CS_LINEAR_COMBINATION *lc,                                      const BIGNUM *value);/* * 线性组合标量加法,执行:lc += value * 参数: *       lc:加油第一个参数及保留加法后果:lc +=  value *       value:常数标量 */int BP_R1CS_LINEAR_COMBINATION_add_bn(BP_R1CS_LINEAR_COMBINATION *lc,                                      const BIGNUM *value);/* * 线性组合标量减法,执行:lc -= value * 参数: *       lc:减法第一个参数及保留减法后果:lc -=  value *       value:常数标量 */int BP_R1CS_LINEAR_COMBINATION_sub_bn(BP_R1CS_LINEAR_COMBINATION *lc,                                      const BIGNUM *value);
    • 束缚
/* * 线性组合束缚,线性组合运算操作执行完结后须要对最终的线性组合后果进行束缚,目前仅反对束缚为0 * 参数: *       lc:线性组合运算后果的对象 *       ctx:上下文对象 */int BP_R1CS_LINEAR_COMBINATION_constrain(BP_R1CS_LINEAR_COMBINATION *lc, BP_R1CS_CTX *ctx);
  • BP_R1CS_CTX

range proof 操作上下文数据结构。

    • 创立/开释
/* * 创立 BP_R1CS_CTX * 参数: *    pp:公共参数对象 *    witness:证据对象 *       transcript:交互抄本对象 */BP_R1CS_CTX *BP_R1CS_CTX_new(BP_PUB_PARAM *pp, BP_WITNESS *witness, BP_TRANSCRIPT *transcript);/* * 开释 BP_R1CS_CTX */void BP_R1CS_CTX_free(BP_RANGE_CTX *ctx);
  • BP_R1CS_PROOF

该数据结构用来保留 Bulletproofs 执行生成证实算法的计算结果,称为证实或者证实对象,由证实者生成,编码后发送给验证者来验证其有效性。

    • 创立/开释
/* * 创立 BP_R1CS_PROOF * 参数: *    pp:公共参数对象 */BP_R1CS_PROOF *BP_R1CS_PROOF_new(const BP_PUB_PARAM *pp);/* * 开释 BP_R1CS_PROOF */void BP_R1CS_PROOF_free(BP_R1CS_PROOF *proof);
    • 编码/解码
/* * 编码 BP_R1CS_PROOF 成二进制格局,写入 out 指定的内存区域中 * 参数: *    proof:证实对象 *       out:要写入的内存指针,如果为 NULL 则返回须要的内存大小,用于申请所需的内存 *    size:out 内存区域大小 */size_t BP_R1CS_PROOF_encode(const BP_R1CS_PROOF *proof, unsigned char *out, size_t size);/* * 解码 BP_R1CS_PROOF * 参数: *    in:已编码的证实内存指针 *    size:in 指针内存区域大小 */BP_R1CS_PROOF *BP_R1CS_PROOF_decode(const unsigned char *in, size_t size);
    • 证实/验证
/* * 证实,执行证实算法并创立和返回 proof 对象 * 参数: *    ctx:上下文对象 * 返回值:胜利返回 proof 对象,否则返回 NULL */BP_R1CS_PROOF *BP_R1CS_PROOF_prove(BP_R1CS_CTX *ctx);/* * 验证 * 参数: *    ctx:上下文对象 *    proof: 证实对象,由证实者生成并发送给验证者来验证 * 返回值:胜利返回1,否则返回0 */int BP_R1CS_PROOF_verify(BP_R1CS_CTX *ctx, const BP_R1CS_PROOF *proof);

编译

$ gcc -Wall -g -o r1cs_proof ./r1cs_proof.c -I/opt/tongsuo-bulletproofs/include -L/opt/tongsuo-bulletproofs/lib -lcrypto

将 /opt/tongsuo-bulletproofs 替换成你的铜锁装置目录即可

运行

$ ./r1cs_proof a1=2 a2=4 b1=4 b2=5 c1=4 c2=7test r1cs constraint: a1*a2 + b1*b2 = c1*c2test ok, 2*4 + 4*5 = 4*7$ ./r1cs_proof a1=2 a2=4 b1=4 b2=5 c1=4 c2=8test r1cs constraint: a1*a2 + b1*b2 = c1*c2test failed, 2*4 + 4*5 != 4*8$ ./r1cs_proof a1=5 a2=6 b1=3 b2=5 c1=5 c2=9test r1cs constraint: a1*a2 + b1*b2 = c1*c2test ok, 5*6 + 3*5 = 5*9$ ./r1cs_proof a1=5 a2=6 b1=3 b2=5 c1=5 c2=10test r1cs constraint: a1*a2 + b1*b2 = c1*c2test failed, 5*6 + 3*5 != 5*10

如上后果所示,约束条件表达式为:a1*a2 + b1*b2 = c1*c2,如果输出的变量满足等式则验证胜利,否则验证失败。

铜锁/Tongsuo Star 一下✨:

https://github.com/Tongsuo-Project/Tongsuo