You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@milagro.apache.org by sa...@apache.org on 2021/04/16 13:12:19 UTC

[incubator-milagro-MPC] 03/05: Add GG20 ZKP

This is an automated email from the ASF dual-hosted git repository.

sandreoli pushed a commit to branch gg20
in repository https://gitbox.apache.org/repos/asf/incubator-milagro-MPC.git

commit ce9f6d5fe6635807fac647580dd6f1f71ec78dc1
Author: Samuele Andreoli <sa...@yahoo.it>
AuthorDate: Fri Apr 16 14:05:38 2021 +0100

    Add GG20 ZKP
---
 benchmark/bench_gg20_zkp_phase3.c          |  162 +++
 benchmark/bench_gg20_zkp_phase6.c          |  177 +++
 benchmark/bench_modulus.c                  |  100 ++
 benchmark/bench_shamir.c                   |  175 +++
 examples/example_gg20_full.c               | 2056 ++++++++++++++++++++++++++++
 examples/example_gg20_reshare.c            |  903 ++++++++++++
 examples/example_gg20_zkp_phase3.c         |  137 ++
 examples/example_gg20_zkp_phase6.c         |  165 +++
 include/amcl/gg20_zkp.h                    |  226 +++
 python/amcl/gg20_zkp.py                    |  417 ++++++
 python/amcl/schnorr.py                     |    3 -
 python/benchmark/bench_bc_setup.py         |   65 +
 python/benchmark/bench_gg20_zkp.py         |  112 ++
 python/examples/example_gg20_zkp.py        |  195 +++
 python/test/test_gg20_zkp.py               |  225 +++
 python/test/test_schnorr.py                |    6 +-
 src/gg20_zkp.c                             |  375 +++++
 src/mta_zkp.c                              |  318 +++++
 src/schnorr.c                              |   62 +-
 test/smoke/test_gg20_zkp_phase3_smoke.c    |  102 ++
 test/smoke/test_gg20_zkp_phase6_smoke.c    |  124 ++
 test/test.c                                |  104 +-
 test/test.h                                |   50 +-
 testVectors/gg20_zkp/octets.txt            |   59 +
 testVectors/gg20_zkp/phase3_challenge.json |   82 ++
 testVectors/gg20_zkp/phase3_challenge.txt  |   70 +
 testVectors/gg20_zkp/phase3_commit.json    |   62 +
 testVectors/gg20_zkp/phase3_commit.txt     |   50 +
 testVectors/gg20_zkp/phase3_prove.json     |  102 ++
 testVectors/gg20_zkp/phase3_prove.txt      |   90 ++
 testVectors/gg20_zkp/phase3_verify.json    |   82 ++
 testVectors/gg20_zkp/phase3_verify.txt     |   70 +
 testVectors/gg20_zkp/phase6_challenge.json |  112 ++
 testVectors/gg20_zkp/phase6_challenge.txt  |  100 ++
 testVectors/gg20_zkp/phase6_commit.json    |   82 ++
 testVectors/gg20_zkp/phase6_commit.txt     |   70 +
 testVectors/gg20_zkp/phase6_prove.json     |  102 ++
 testVectors/gg20_zkp/phase6_prove.txt      |   90 ++
 testVectors/gg20_zkp/phase6_verify.json    |  112 ++
 testVectors/gg20_zkp/phase6_verify.txt     |  100 ++
 testVectors/schnorr/challenge.json         |   90 +-
 testVectors/schnorr/challenge.txt          |   90 +-
 testVectors/schnorr/dchallenge.json        |  110 +-
 testVectors/schnorr/dchallenge.txt         |  110 +-
 testVectors/schnorr/dprove.json            |  140 +-
 testVectors/schnorr/dprove.txt             |  140 +-
 testVectors/schnorr/dverify.json           |  120 +-
 testVectors/schnorr/dverify.txt            |  120 +-
 48 files changed, 8111 insertions(+), 503 deletions(-)

diff --git a/benchmark/bench_gg20_zkp_phase3.c b/benchmark/bench_gg20_zkp_phase3.c
new file mode 100644
index 0000000..e2387a9
--- /dev/null
+++ b/benchmark/bench_gg20_zkp_phase3.c
@@ -0,0 +1,162 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+/*
+ * Benchmark GG20 Phase 3 ZKP
+ */
+
+#include "bench.h"
+#include "amcl/gg20_zkp.h"
+
+#define MIN_TIME  5.0
+#define MIN_ITERS 10
+
+char *S_hex = "00f1f45c44eb4298562677dfc945064ac5d45d683ec2d87efbd2f527bb5a768c";
+char *L_hex = "ab5aa1e7740f849b974fcaaa98840d828a42b16dd59be32f39e3c637730ee9e4";
+
+char *V_hex = "02879452f0c552b01c2cc91101062ca02a1ff3eab1e9c18873992670198bf54f3e";
+
+char *A_hex = "fab4ce512dff74bd9c71c89a14de5b877af45dca0329ee3fcb72611c0784fef3";
+char *B_hex = "803ccd21cddad626e15f21b1ad787949e9beef08e6e68a9e00df59dec16ed290";
+
+int main()
+{
+    int rc;
+
+    int iterations;
+    clock_t start;
+    double elapsed;
+
+    GG20_ZKP_rv    r;
+    GG20_ZKP_proof p;
+
+    char id[32];
+    octet ID = {0, sizeof(id), id};
+
+    char ad[32];
+    octet AD = {0, sizeof(ad), ad};
+
+    char s[GGS_SECP256K1];
+    octet S = {0, sizeof(s), s};
+
+    char l[GGS_SECP256K1];
+    octet L = {0, sizeof(l), l};
+
+    char v[GFS_SECP256K1+1];
+    octet V = {0, sizeof(v), v};
+
+    char c[GFS_SECP256K1+1];
+    octet C = {0, sizeof(c), c};
+
+    char e[GGS_SECP256K1];
+    octet E = {0, sizeof(e), e};
+
+    char o[GGS_SECP256K1];
+    octet O = {0, sizeof(o), o};
+
+    // Deterministic RNG for testing
+    char seed[32] = {0};
+    csprng RNG;
+    RAND_seed(&RNG, 32, seed);
+
+    // Generate ID and AD
+    OCT_rand(&ID, &RNG, ID.len);
+    OCT_rand(&AD, &RNG, AD.len);
+
+    // Load hex values
+    OCT_fromHex(&S, S_hex);
+    OCT_fromHex(&L, L_hex);
+    OCT_fromHex(&V, V_hex);
+
+    OCT_fromHex(&O, A_hex);
+    BIG_256_56_fromBytesLen(r.a, O.val, O.len);
+
+    OCT_fromHex(&O, B_hex);
+    BIG_256_56_fromBytesLen(r.b, O.val, O.len);
+
+    // Begin benchmark
+    print_system_info();
+
+    printf("Timing info\n");
+    printf("===========\n");
+
+    iterations = 0;
+    start = clock();
+    do
+    {
+        GG20_ZKP_phase3_commit(NULL, &r, &C);
+        iterations++;
+        elapsed = (clock() - start) / (double)CLOCKS_PER_SEC;
+    }
+    while (elapsed < MIN_TIME || iterations < MIN_ITERS);
+
+    elapsed = MILLISECOND * elapsed / iterations;
+    printf("\tGG20_ZKP_phase3_commit\t\t%8d iterations\t", iterations);
+    printf("%8.2lf ms per iteration\n", elapsed);
+
+    iterations = 0;
+    start = clock();
+    do
+    {
+        GG20_ZKP_phase3_challenge(&V, &C, &ID, &AD, &E);
+        iterations++;
+        elapsed = (clock() - start) / (double)CLOCKS_PER_SEC;
+    }
+    while (elapsed < MIN_TIME || iterations < MIN_ITERS);
+
+    elapsed = MICROSECOND * elapsed / iterations;
+    printf("\tGG20_ZKP_phase3_challenge\t%8d iterations\t", iterations);
+    printf("%8.2lf us per iteration\n", elapsed);
+
+    iterations = 0;
+    start = clock();
+    do
+    {
+        GG20_ZKP_phase3_prove(&r, &E, &S, &L, &p);
+        iterations++;
+        elapsed = (clock() - start) / (double)CLOCKS_PER_SEC;
+    }
+    while (elapsed < MIN_TIME || iterations < MIN_ITERS);
+
+    elapsed = MICROSECOND * elapsed / iterations;
+    printf("\tGG20_ZKP_phase3_prove\t\t%8d iterations\t", iterations);
+    printf("%8.2lf us per iteration\n", elapsed);
+
+    iterations = 0;
+    start = clock();
+    do
+    {
+        rc = GG20_ZKP_phase3_verify(&V, &C, &E, &p);
+        iterations++;
+        elapsed = (clock() - start) / (double)CLOCKS_PER_SEC;
+    }
+    while (elapsed < MIN_TIME || iterations < MIN_ITERS);
+
+    if (rc != GG20_ZKP_OK)
+    {
+        printf("FAILURE  GG20_ZKP_phase6_verify rc %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    elapsed = MILLISECOND * elapsed / iterations;
+    printf("\tGG20_ZKP_phase3_verify\t\t%8d iterations\t", iterations);
+    printf("%8.2lf ms per iteration\n", elapsed);
+
+    exit(EXIT_SUCCESS);
+}
\ No newline at end of file
diff --git a/benchmark/bench_gg20_zkp_phase6.c b/benchmark/bench_gg20_zkp_phase6.c
new file mode 100644
index 0000000..6fa982b
--- /dev/null
+++ b/benchmark/bench_gg20_zkp_phase6.c
@@ -0,0 +1,177 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+/*
+ * Benchmark GG20 Phase 6 ZKP
+ */
+
+#include "bench.h"
+#include "amcl/gg20_zkp.h"
+
+#define MIN_TIME  5.0
+#define MIN_ITERS 10
+
+char *S_hex = "843b282505357e075bd98104f42fe7ea6b41310da7c769b4c402442c1ede922b";
+char *L_hex = "584edf9db99551ff2e0d56218a44fea0943032f7864b8359c213ec36465512c5";
+
+char *ECPR_hex = "03e03cda61f087f9ba381695dc816a4ca42f38bbfc3fc88ffe897594b94ee7b80b";
+char *ECPT_hex = "02863528287942ab88dec016c2e1993bf9e459ffcbfcc48c25ef68f2ec750e55a8";
+char *ECPS_hex = "02ef03c8ecb7cf65b58d85f368c5fc2725b4e4fe93306f98cf53f8e1531cea2bc4";
+
+char *A_hex = "fab4ce512dff74bd9c71c89a14de5b877af45dca0329ee3fcb72611c0784fef3";
+char *B_hex = "803ccd21cddad626e15f21b1ad787949e9beef08e6e68a9e00df59dec16ed290";
+
+int main()
+{
+    int rc;
+
+    int iterations;
+    clock_t start;
+    double elapsed;
+
+    GG20_ZKP_rv                r;
+    GG20_ZKP_phase6_commitment c;
+    GG20_ZKP_proof             p;
+
+    char id[32];
+    octet ID = {0, sizeof(id), id};
+
+    char ad[32];
+    octet AD = {0, sizeof(ad), ad};
+
+    char s[GGS_SECP256K1];
+    octet S = {0, sizeof(s), s};
+
+    char l[GGS_SECP256K1];
+    octet L = {0, sizeof(l), l};
+
+    char ecpr[GFS_SECP256K1+1];
+    octet ECPR = {0, sizeof(ecpr), ecpr};
+
+    char ecpt[GFS_SECP256K1+1];
+    octet ECPT = {0, sizeof(ecpt), ecpt};
+
+    char ecps[GFS_SECP256K1+1];
+    octet ECPS = {0, sizeof(ecps), ecps};
+
+    char e[GGS_SECP256K1];
+    octet E = {0, sizeof(e), e};
+
+    char o[GGS_SECP256K1];
+    octet O = {0, sizeof(o), o};
+
+    // Deterministic RNG for testing
+    char seed[32] = {0};
+    csprng RNG;
+    RAND_seed(&RNG, 32, seed);
+
+    // Generate ID and AD
+    OCT_rand(&ID, &RNG, ID.len);
+    OCT_rand(&AD, &RNG, AD.len);
+
+    // Load hex values
+    OCT_fromHex(&S, S_hex);
+    OCT_fromHex(&L, L_hex);
+
+    OCT_fromHex(&ECPR, ECPR_hex);
+    OCT_fromHex(&ECPT, ECPT_hex);
+    OCT_fromHex(&ECPS, ECPS_hex);
+
+    OCT_fromHex(&O, A_hex);
+    BIG_256_56_fromBytesLen(r.a, O.val, O.len);
+
+    OCT_fromHex(&O, B_hex);
+    BIG_256_56_fromBytesLen(r.b, O.val, O.len);
+
+    // Begin benchmark
+    print_system_info();
+
+    printf("Timing info\n");
+    printf("===========\n");
+
+    iterations = 0;
+    start = clock();
+    do
+    {
+        rc = GG20_ZKP_phase6_commit(NULL, &ECPR, &r, &c);
+        iterations++;
+        elapsed = (clock() - start) / (double)CLOCKS_PER_SEC;
+    }
+    while (elapsed < MIN_TIME || iterations < MIN_ITERS);
+
+    if (rc != GG20_ZKP_OK)
+    {
+        printf("FAILURE  GG20_ZKP_phase6_commit rc %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    elapsed = MILLISECOND * elapsed / iterations;
+    printf("\tGG20_ZKP_phase6_commit\t\t%8d iterations\t", iterations);
+    printf("%8.2lf ms per iteration\n", elapsed);
+
+    iterations = 0;
+    start = clock();
+    do
+    {
+        GG20_ZKP_phase6_challenge(&ECPR, &ECPT, &ECPS, &c, &ID, &AD, &E);
+        iterations++;
+        elapsed = (clock() - start) / (double)CLOCKS_PER_SEC;
+    }
+    while (elapsed < MIN_TIME || iterations < MIN_ITERS);
+
+    elapsed = MICROSECOND * elapsed / iterations;
+    printf("\tGG20_ZKP_phase6_challenge\t%8d iterations\t", iterations);
+    printf("%8.2lf us per iteration\n", elapsed);
+
+    iterations = 0;
+    start = clock();
+    do
+    {
+        GG20_ZKP_phase6_prove(&r, &E, &S, &L, &p);
+        iterations++;
+        elapsed = (clock() - start) / (double)CLOCKS_PER_SEC;
+    }
+    while (elapsed < MIN_TIME || iterations < MIN_ITERS);
+
+    elapsed = MICROSECOND * elapsed / iterations;
+    printf("\tGG20_ZKP_phase6_prove\t\t%8d iterations\t", iterations);
+    printf("%8.2lf us per iteration\n", elapsed);
+
+    iterations = 0;
+    start = clock();
+    do
+    {
+        rc = GG20_ZKP_phase6_verify(&ECPR, &ECPT, &ECPS, &c, &E, &p);
+        iterations++;
+        elapsed = (clock() - start) / (double)CLOCKS_PER_SEC;
+    }
+    while (elapsed < MIN_TIME || iterations < MIN_ITERS);
+
+    if (rc != GG20_ZKP_OK)
+    {
+        printf("FAILURE  GG20_ZKP_phase6_verify rc %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    elapsed = MILLISECOND * elapsed / iterations;
+    printf("\tGG20_ZKP_phase6_verify\t\t%8d iterations\t", iterations);
+    printf("%8.2lf ms per iteration\n", elapsed);
+
+    exit(EXIT_SUCCESS);
+}
\ No newline at end of file
diff --git a/benchmark/bench_modulus.c b/benchmark/bench_modulus.c
new file mode 100644
index 0000000..42f2c26
--- /dev/null
+++ b/benchmark/bench_modulus.c
@@ -0,0 +1,100 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+/*
+   Benchmark modulus utilities.
+ */
+
+#include "bench.h"
+#include "amcl/modulus.h"
+
+#define MIN_TIME 5.0
+#define MIN_ITERS 10
+
+char *P_hex = "e008507e09c24d756280f3d94912fb9ac16c0a8a1757ee01a350736acfc7f65880f87eca55d6680253383fc546d03fd9ebab7d8fa746455180888cb7c17edf58d3327296468e5ab736374bc9a0fa02606ed5d3a4a5fb1677891f87fbf3c655c3e0549a86b17b7ddce07c8f73e253105e59f5d3ed2c7ba5bdf8495df40ae71a7f";
+char *Q_hex = "dbffe278edd44c2655714e5a4cc82e66e46063f9ab69df9d0ed20eb3d7f2d8c7d985df71c28707f32b961d160ca938e9cf909cd77c4f8c630aec34b67714cbfd4942d7147c509db131bc2d6a667eb30df146f64b710f8f5247848b0a75738a38772e31014fd63f0b769209928d586499616dcc90700b393156e12eea7e15a835";
+
+int main()
+{
+    int iterations;
+    clock_t start;
+    double elapsed;
+
+    char p[HFS_2048] = {0};
+    octet P = {0, sizeof(p), p};
+
+    char q[HFS_2048];
+    octet Q = {0, sizeof(q), q};
+
+    MODULUS_priv m;
+
+    // Load values
+    OCT_fromHex(&P, P_hex);
+    OCT_fromHex(&Q, Q_hex);
+
+    print_system_info();
+
+    printf("Timing info\n");
+    printf("===========\n");
+
+    iterations = 0;
+    start = clock();
+    do
+    {
+        MODULUS_fromOctets(&m, &P, &Q);
+        iterations++;
+        elapsed = (clock() - start) / (double)CLOCKS_PER_SEC;
+    }
+    while (elapsed < MIN_TIME || iterations < MIN_ITERS);
+
+    elapsed = MICROSECOND * elapsed / iterations;
+    printf("\tMODULUS_fromOctets\t%8d iterations\t", iterations);
+    printf("%8.2lf us per iteration\n", elapsed);
+
+    iterations = 0;
+    start = clock();
+    do
+    {
+        MODULUS_toOctets(&P, &Q, &m);
+        iterations++;
+        elapsed = (clock() - start) / (double)CLOCKS_PER_SEC;
+    }
+    while (elapsed < MIN_TIME || iterations < MIN_ITERS);
+
+    elapsed = MICROSECOND * elapsed / iterations;
+    printf("\tMODULUS_toOctets\t%8d iterations\t", iterations);
+    printf("%8.2lf us per iteration\n", elapsed);
+
+
+    iterations = 0;
+    start = clock();
+    do
+    {
+        MODULUS_kill(&m);
+        iterations++;
+        elapsed = (clock() - start) / (double)CLOCKS_PER_SEC;
+    }
+    while (elapsed < MIN_TIME || iterations < MIN_ITERS);
+
+    elapsed = MICROSECOND * elapsed / iterations;
+    printf("\tMODULUS_kill\t\t%8d iterations\t", iterations);
+    printf("%8.2lf us per iteration\n", elapsed);
+
+    exit(EXIT_SUCCESS);
+}
diff --git a/benchmark/bench_shamir.c b/benchmark/bench_shamir.c
new file mode 100644
index 0000000..09cfd71
--- /dev/null
+++ b/benchmark/bench_shamir.c
@@ -0,0 +1,175 @@
+/*
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+*/
+
+/*
+ * Benchmark Shamir Secret Sharing
+ */
+
+#include "bench.h"
+#include "amcl/shamir.h"
+
+#define MIN_TIME    5.0
+#define MIN_ITERS   10
+
+char *S_hex = "fab4ce512dff74bd9c71c89a14de5b877af45dca0329ee3fcb72611c0784fef3";
+
+int n = 30;
+int k = 20;
+
+int main()
+{
+    int i, rc;
+
+    int iterations;
+    clock_t start;
+    double elapsed;
+
+    // Secret
+    char s[SGS_SECP256K1];
+    octet S = {0,sizeof(s),s};
+
+    // Secret shares
+    char x[n][SGS_SECP256K1];
+    octet X[n];
+    char y[n][SGS_SECP256K1];
+    octet Y[n];
+
+    for(i = 0; i < n; i++)
+    {
+        Y[i].max = SGS_SECP256K1;
+        Y[i].len = SGS_SECP256K1;
+        Y[i].val = y[i];
+
+        X[i].max = SGS_SECP256K1;
+        X[i].len = SGS_SECP256K1;
+        X[i].val = x[i];
+    }
+
+    SSS_shares shares = {X, Y};
+
+    // Additive share for conversion
+    char sh[SGS_SECP256K1];
+    octet SH = {0, sizeof(sh), sh};
+
+    // Additional checks for verification
+    char c[k][1 + SFS_SECP256K1];
+    octet C[k];
+
+    for(i = 0; i < k; i++)
+    {
+        C[i].max = 1 + SFS_SECP256K1;
+        C[i].len = 1 + SFS_SECP256K1;
+        C[i].val = c[i];
+    }
+
+    // Deterministic RNG for testing
+    char seed[32] = {0};
+    csprng RNG;
+    RAND_seed(&RNG, 32, seed);
+
+    // Load Secret from hex
+    OCT_fromHex(&S, S_hex);
+
+    /* Benchmark */
+    print_system_info();
+
+    printf("Timing info\n");
+    printf("===========\n");
+
+    // Shamir Secret Sharing
+    iterations=0;
+    start=clock();
+    do
+    {
+        SSS_make_shares(k, n, &RNG, &shares, &S);
+        iterations++;
+        elapsed=(clock()-start)/(double)CLOCKS_PER_SEC;
+    }
+    while (elapsed<MIN_TIME || iterations<MIN_ITERS);
+
+    elapsed= MILLISECOND * elapsed / iterations;
+    printf("\tSSS_make_shares\t\t%8d iterations\t",iterations);
+    printf("%8.2lf ms per iteration\n",elapsed);
+
+    iterations=0;
+    start=clock();
+    do
+    {
+        SSS_recover_secret(k, &shares, &S);
+        iterations++;
+        elapsed=(clock()-start)/(double)CLOCKS_PER_SEC;
+    }
+    while (elapsed<MIN_TIME || iterations<MIN_ITERS);
+
+    elapsed= MILLISECOND * elapsed / iterations;
+    printf("\tSSS_recover_secret\t%8d iterations\t",iterations);
+    printf("%8.2lf ms per iteration\n",elapsed);
+
+    // Shamir to additive conversion
+    iterations=0;
+    start=clock();
+    do
+    {
+        SSS_shamir_to_additive(k, X, Y, X+1, &SH);
+        iterations++;
+        elapsed=(clock()-start)/(double)CLOCKS_PER_SEC;
+    }
+    while (elapsed<MIN_TIME || iterations<MIN_ITERS);
+
+    elapsed= MICROSECOND * elapsed / iterations;
+    printf("\tSSS_shamir_to_additive\t%8d iterations\t",iterations);
+    printf("%8.2lf us per iteration\n",elapsed);
+
+    // Verifiable Secret Sharing
+    iterations=0;
+    start=clock();
+    do
+    {
+        VSS_make_shares(k, n, &RNG, &shares, C, &S);
+        iterations++;
+        elapsed=(clock()-start)/(double)CLOCKS_PER_SEC;
+    }
+    while (elapsed<MIN_TIME || iterations<MIN_ITERS);
+
+    elapsed= MILLISECOND * elapsed / iterations;
+    printf("\tVSS_make_shares\t\t%8d iterations\t",iterations);
+    printf("%8.2lf ms per iteration\n",elapsed);
+
+    iterations=0;
+    start=clock();
+    do
+    {
+        rc = VSS_verify_shares(k, X, Y, C);
+        iterations++;
+        elapsed=(clock()-start)/(double)CLOCKS_PER_SEC;
+    }
+    while (elapsed<MIN_TIME || iterations<MIN_ITERS);
+
+    if (rc != VSS_OK)
+    {
+        printf("FAILURE  VSS_verify_shares: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    elapsed= MILLISECOND * elapsed / iterations;
+    printf("\tVSS_verify_shares\t%8d iterations\t",iterations);
+    printf("%8.2lf ms per iteration\n",elapsed);
+
+    exit(EXIT_SUCCESS);
+}
diff --git a/examples/example_gg20_full.c b/examples/example_gg20_full.c
new file mode 100644
index 0000000..e8608e0
--- /dev/null
+++ b/examples/example_gg20_full.c
@@ -0,0 +1,2056 @@
+/*
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include "amcl/mta.h"
+#include "amcl/mpc.h"
+#include "amcl/mta_zkp.h"
+#include "amcl/nm_commitment.h"
+#include "amcl/gmr.h"
+#include "amcl/ggn.h"
+#include "amcl/schnorr.h"
+#include "amcl/gg20_zkp.h"
+#include "amcl/shamir.h"
+
+#define IDLEN 16
+
+/* Example of the full flow */
+
+// Safe primes for BC Setup
+int primes_len = 4;
+
+char *primes[] =
+{
+    "C421122418EF6FE4D4F14F0F03EABA927C20B1A22BCBE90EC227EFE34AC912095D389ADE615CF55C80874533F4270BB705ABFFDB6007FEF0B44B2DBF31EDA0D5F39523B5826F9854FBF733B98EF450E77DD8B5B15C4E3CE5C195F46E524C8BF6F0C9F6D86CE8642A8B9A0C79CA64A103AB76CD65261F97AED4C17C433CEA5DEF",
+    "ED7859031659B9A5AC011687A60444B19F5A73F31F9EE83D710F2FEAE1C4FED558A1C5C3842EA01DB86C6D07BE9971F8AA7820DD1E8BB8C9AE888319F0E03BDCD8D3DBEBF8A48765188C001A121F7E48D458E1E8A43684A861F0FBE87DC541A06CA98CECB6954F906A52C2B3D0978AE945A1EA2F9285978F76F01E99FD8B6EEF",
+    "D93E4899805ED36219F38C3030D6FF92012E2B41ADC38DFFFFDB110AEAA36D619A5CFD63B02711EA482941E20A3F89A36E2CAF0BD675B154FDE6D5A457BCBD337383EE65B33CDAB078EE8F8E36E55D22BB5DF75D14F570E529A4681B4947A4F5ECCC575763BD765FDE1038DEDF24BEF02BA9A1EA4C17ACA3A1B33D2FB7D974AB",
+    "E4481CEDDBDDDF6E980FBC825B004E52D028784CD3B8290D9810FD987AF2053C3F4056C3A354BFF55B9BB5867A819A22B71BC1069A310087E4FBF98FD291DBCC443AB910301B34A2DEE68D1365E77EDF9A0A21B3928C38046BC15AC338F7E38B9E4586E02655F98523CD041FBB51A358E505A5D1B0A161955B6AC60CB0E37707",
+    "F5F3BB1CEECD21110EFB4BC9CF0AA7AEBB98675A7567D6A1EA4E866FED4838F1B41D8232599718CD82F2936CD15198DC16ADD280C32D6860882704AEF397E1A956DB17E36AEB92D5CF76689DACC9CEFE418EF699C948CE680AFF878768CE8F4BB68F14AB5E8C38209E6C2C54125533B22960BBD350CF76C3B12BBC9FBAAAAA27",
+    "E8E1F9281CB8C10BC01B42197E834F648A5C8AE111F7DB40DD25A6F8896A703D0F84D36EB6D1FC048DC74FD3164742CA86607C81670199FC3F1BF5AB22F2B11E4E2434E757C0484A4162E26B75A0715167C5E8E293B7CEFD475FAA8B10F2324D78150E56B1186E257066D8860603FBCE59865FB0A25FB41014C1740C8EAA29AF",
+    "C3278DF1CD5330CD6DABE2FC9E32B9A560C32F7F140C601D2A5788F856A387531EFA695D728038F8CA2945D01C10A5DA823025BA27D7640E96593C031674380592AF4B8FE29A9C464FF41B1CACD47A4B255A5CA93E2F2A806AF00A67FB78A15D3ED8A37CEBA10CA7D0036412805AEBB88EC8A745F237AC01002D49C459EB2AB7",
+    "DCE9B24D4DE749296335C0F0DB421A330E21DF04C722ADDECC4B72448C387072C84CD7DB1146E1E07BE78585DEF4F1D5E15F53B0942CCA89B0E812B0F6653C7DA8ACB771593D4B2B37A28AD80DD7184698742C110F0506B86BF8A2A20E8975DF2D2A57930438B8528E63C3430DBFCE204712E8D40550E81DA03622953BEA2DFB",
+    "D09A3ECE562DD033EC2C562C2B0B4EEB0D2262FE046C030BAAFD7CBA8F73E9734E337D3551FC6B487CA359A84F598EC5EC6FDBA014A0A0009EF582B9F90DE90C0BA7F941648C4F3A8CF904974BA05E8C23EDA5895025441251B2CFC5A216568E702427DEA178D37BF3D28F1B35E17E58F5551511331961703F3D410924859107",
+    "C03136A1E1E5BA88568A19142F41E9FAC2E76A2D839B550038005E420008AF7D6D7C80EA8A31A936D39C93D2031B20845F23464371909EE589BF80E850C94B9F0FBF516C3DE362868C811505EE15B869844A54FFB32B0620A7FC5BA040898A91AA68657D8B43990166E5A5AF06828AE0F7C1D0EE333C2AF8DE7603F2F662792F",
+    "DF88593FBF2482954BAAA2A48C59E2FDF85936C282514FFB47F18B8D1484C7E8BE1862D0A84D5B753389A2BFBAFF63B03406AC29893B88911F8664E547A63CB58E9A941463D7946CF0909E24E7BD8EF11AFC4EEAFC8F3366DB0A9AB091325AC82C9BAE218B115F8700BAA1F478E194A927F1FBE3A3EF423BCFAE78850059B69B",
+    "D3AE06CD993690F64104D4ECBE6B2386693B766431B86E038CAE39EE81BD8A71387FBCB9D17B5BFAAFB883D68B005E228CD455A4BFF69843F948A9168D1F87545FCBB969260E07BDD44F10E79E7409DED45ADDF32BA1CF33F9B2F68758622FE660F4E47A651F6403D99E7B148768CDDBEC71EBE931D5A95B820B5A75BD495003",
+    "DAA27689A7D8F9B21106DBE472C324EB1CA899F58F0F72F336957312A8ECDB4EBC3B50C38D5A2E9C2D1E552C7EA8D89315DD9C5CA7F9EB99C41F7A857D44F420109FE17092799E60E3537FC9193056979E0FF886B36C2898F45F599E4C5CCDDF9A8EC8DA0D20A53A6849124E027D30D641E21E69FF374792534BD682FCDCA35B",
+    "FBF9D46697C40BCA51A759C47E360F2DD8B81B6241B0A3645645FAC692E9E8F3407EFB6F238AE91F9DEA49240D26E37904673F55E91927CDEA248FE1352B97B226AB159A1539747383B1168FE8CF1B1DF4CD9147053E3702AE491FBCA4CCE835B4B351DF44F5333C185275DB21B807D0BC180BF697EC07AB843E0FA595851A87",
+    "FD44B39DF09A18F215EB391D50D21CD5EAC8BE2E5CC901DF852DE85C93341F82633AAAD07C19863E0CD7861AEEE1C0B4B69275AA8DD2D33C0F5E048EA13E9A6D8E01B77FED72347D527BD7508D2F5EC18E5CB2B27D40BAB5C10A17123E75042F4047C3B1AEB6D36BF0F93BB214501ECBB8F95CC1A3A99219F6933763580CDA2F",
+    "C2442E9569C8999831594E818A159C8C0AF6F7ED2989358E8D9E01D6B8A0D354F5F97D9CEAB766AF12F3CC5C511FE19A587FF1E7029C8E500432D357D90E3EF042E4F308C325760D726BC9B1D78BA439FB0236D85DB301E548C4201B9E74D5832AD3ED06E37CD6DBFD9C23D194068DB1B9209813557FBC0714142AD6F6C56AA3",
+    "DC3B22CFF90690B10EC73C115FED0E3AD3FA01A68F8C8AA1905CA47008E8C4AF9D7922AE4D41794D8123D1768A3E0F8B35DA0001086ADC5EBB92640DD2514CBAD000283F7C5A6C340C040C09654A204C3947A22AC05F72E13C3EBDE61B9D281016E40C559474D33381C974767408EE9E108619AE96E4CC87EB11E39772BA00B3",
+    "C5E0280A5F1B358D16EDEF14540C3C9D468D4AEBC74C9DB605A2E4CEC9F27095A3FDE659E1E6C95FB4BB60533DD89E71D808A8C5EB5A8A51B9FED24F7AE9003FFD6F5401D991153C52002E7DB4F6766363B2CA77E9A113808E7C35713D188AD55CE25B9DB1308A08F3366523E425F77D924346078D8E0E9948674BAD88EA59B7",
+    "FC33DF361A7B1D3C3D1C06FBF3CCAD6C067B27FF28B61B1EFDB364FFFEE79993D9D10213A778A02C6C823DB101CB7C7A483B9F2B060BD1B7EDC13DB890B323AE02B7209DA66B3289069EE8C7747A6D7242194DC48DBDFFB740534A591AE2F41446B08F9966DA045FC9C3F9188F1EF1308509D50BC970314B6AA335EA2839993B",
+    "E63B5740DDB573CF1F0A72DAF3EA00D65CA2A538036D20078CC7E3BDC95529F1D13ABC182EBF8BE42CA87C0AEED4952C1D1FADC3C3C8A363F66FABCA012890FBC76C935B479B4F302F1DC12289D34F1F69EC2278045603F5FE532B0CD86E6261852F99517B6226F013B04DCE1D940DF7FB8BC8A799D153C1490A915A8342B77F"
+};
+
+/* Party related structures */
+typedef struct
+{
+    PAILLIER_private_key paillier_sk;
+    BIT_COMMITMENT_priv bc_sm;
+
+    octet *SKX; // X share of the full key (t,n) sharing
+    octet *SKY; // Y share of the full key (t,n) sharing
+} MPC_priv_key_material;
+
+typedef struct
+{
+    octet *PK;  // Full ECDSA PK
+    octet *SPK; // ECDSA PK associated to the player share
+
+    PAILLIER_public_key paillier_pk;
+    BIT_COMMITMENT_pub  bc_pm;
+} MPC_pub_key_material;
+
+typedef struct
+{
+    octet *ID;
+
+    MPC_priv_key_material skm;
+    MPC_pub_key_material  pkm;
+} MPC_player;
+
+typedef struct
+{
+    int t;
+    int n;
+
+    MPC_player *players;
+} MPC_party;
+
+/* Keygen related structures
+ *
+ * Note that these structures hold all the values
+ * generated in the round, even if they are not to be
+ * transmitted. The values to be transmitted and what channel
+ * to use are specified in the keygen functions
+ */
+
+typedef struct
+{
+    octet *SK;  // ECDSA secret key
+    octet *PK;  // ECDSA pubilc key
+
+    octet *R; // Decommitment string
+    octet *C; // Commitment string to PK
+} MPC_keygen_round1;
+
+typedef struct
+{
+    SSS_shares SHARES; // Shares for VSS
+    octet *CHECKS;     // Checks for VSS
+} MPC_keygen_round2;
+
+typedef struct
+{
+    octet *SCHNORR_C;
+    octet *SCHNORR_P;
+
+    GMR_proof Y;
+
+    BIT_COMMITMENT_setup_proof BCP;
+} MPC_keygen_round3;
+
+typedef struct
+{
+    octet *ID;
+
+    MPC_party *party;
+
+    MPC_keygen_round1 *round1;
+    MPC_keygen_round2 *round2;
+    MPC_keygen_round3 *round3;
+} MPC_keygen_session;
+
+/* Signing related structures
+ *
+ * Note that these structures hold all the values
+ * generated in the round, even if they are not to be
+ * transmitted. The values to be transmitted and what channel
+ * to use are specified in the signing functions
+ */
+
+typedef struct
+{
+    octet *W;   // Secret additive share
+    octet *WG;  // Public Key associated with the additive share
+} MPC_signing_additive_shares;
+
+typedef struct
+{
+    octet *GAMMA;
+    octet *GAMMAPT;
+    octet *K;
+    octet *R;       // Decommitment for GAMMAPT
+    octet *C;       // Commitment for GAMMAPT
+} MPC_signing_round1;
+
+typedef struct
+{
+    octet *R;     // Random value from K encryption. Saved for round 5
+    octet *CA;    // Encryption of K. Saved for round 5
+    octet *DELTA;
+    octet *SIGMA;
+} MPC_signing_round2;
+
+typedef struct
+{
+    octet *INVKGAMMA;
+    octet *T;         // Check for SIGMA
+    octet *L;         // Random value used in computing T
+    octet *C;         // Phase3 commitment. ECP
+    GG20_ZKP_proof p;
+} MPC_signing_round3;
+
+typedef struct
+{
+    octet *R;
+    octet *RP;
+} MPC_signing_round4;
+
+typedef struct
+{
+    octet *RI;         // Checks for K, R
+    GGN_commitment *c; // t commitments, since they are tailored for each player
+    GGN_proof *p;      // t proofs, since they are tailored for each player
+} MPC_signing_round5;
+
+typedef struct
+{
+    octet *SI;                     // Check for SIGMAs
+    GG20_ZKP_phase6_commitment c;  // Commitment for SI consistency
+    GG20_ZKP_proof p;              // Proof for SI consistency              
+} MPC_signing_round6;
+
+typedef struct
+{
+    octet *SI; // Signature S shares
+    octet *S;  // Reconciled S component
+} MPC_signing_round7;
+
+typedef struct
+{
+    octet *ID;
+
+    MPC_party *party;
+
+    MPC_signing_additive_shares *shares;
+
+    MPC_signing_round1 *round1;
+    MPC_signing_round2 *round2;
+    MPC_signing_round3 *round3;
+    MPC_signing_round4 *round4;
+    MPC_signing_round5 *round5;
+    MPC_signing_round6 *round6;
+    MPC_signing_round7 *round7;
+} MPC_signing_session;
+
+// Utility functions
+void init_octets(char* mem, octet *OCTETS, int max, int n)
+{
+    int i = 0;
+
+    for (i = 0; i < n; i++)
+    {
+        OCTETS[i].val = mem + (i*max);
+        OCTETS[i].len = 0;
+        OCTETS[i].max = max;
+    }
+}
+
+/* *** Keygen functions *** */
+
+/* Keygen - Round 1
+ *
+ * This can be viewed as the secret key material generation.
+ * In particular, we generate keypairs for the ECDSA Signature
+ * and the Paillier cryptosystem, in addition to the modulus
+ * for the Bit Commitment ZKP.
+ *
+ * The ECDSA Public Key is not broadcast here, but a NM Commitment
+ * to it is generated and the commitment string broadcast here.
+ * The decommitment string MUST be saved for later.
+ *
+ * The rest of the (public) key material is broadcast as is.
+ * The reason for broadcasting the Paillier Key here is the specification
+ * in the paper. The moment to broadcast the modulus is not
+ * specified, so there is a case to be done for broadcasting it
+ * in round 3.
+ */
+int MPC_keygen_round1_generate(csprng *RNG, MPC_player *p, MPC_keygen_round1 *r, int i)
+{
+    int rc;
+
+    char oct1[HFS_2048];
+    octet OCT1 = {0, sizeof(oct1), oct1};
+    char oct2[HFS_2048];
+    octet OCT2 = {0, sizeof(oct2), oct2};
+
+    ECP_SECP256K1 ECP;
+
+    char pk[2 * EFS_SECP256K1 + 1];
+    octet PK = {0, sizeof(pk), pk};
+
+    // Generate ECDSA Key Pair
+    printf("\t[Player %d] Generate ECDSA key pair\n", i);
+
+    MPC_ECDSA_KEY_PAIR_GENERATE(RNG, r->SK, &PK);
+    rc = ECP_SECP256K1_PUBLIC_KEY_VALIDATE(&PK);
+    if (rc != 0)
+    {
+        printf("\t\tError generating ECDSA key pair. rc %d\n", rc);
+        return rc;
+    }
+
+    // Convert PK to compressed form
+    ECP_SECP256K1_fromOctet(&ECP, &PK);
+    ECP_SECP256K1_toOctet(r->PK, &ECP, true);
+
+    // Commit to the ECDSA public key
+    printf("\t[Player %d] Commit to ECDSA PK\n", i);
+
+    NM_COMMITMENT_commit(RNG, &PK, r->R, r->C);
+
+    // Generate Paillier Key pair
+    printf("\t[Player %d] Generate Paillier key pair\n", i);
+
+    PAILLIER_KEY_PAIR(RNG, NULL, NULL, &p->pkm.paillier_pk, &p->skm.paillier_sk);
+
+    // Load Primes for BC setup
+    OCT_fromHex(&OCT1, primes[(2 * i) % primes_len]);
+    OCT_fromHex(&OCT2, primes[(2 * i + 1) % primes_len]);
+
+    // Generate BC modulus
+    printf("\t[Player %d] Generate BC modulus\n", i);
+
+    BIT_COMMITMENT_setup(RNG, &p->skm.bc_sm, &OCT1, &OCT2, NULL, NULL);
+    BIT_COMMITMENT_priv_to_pub(&p->pkm.bc_pm, &p->skm.bc_sm);
+
+    printf("\t[Player %d] Broadcast commitment C, Paillier PK and BC modulus (N, B0, B1)\n", i);
+
+    return MPC_OK;
+}
+
+/* Keygen - VSS of ECDSA SK for Round 2
+ *
+ * The output of this computation are the shares and checks for this playe
+ * ECDSA secret key. Note that the check for the coefficient
+ * of degree 0 is the ECDSA PK generated in Round 1. So it
+ * will pass the decommitment for the commitment sent in Round 1
+ *
+ * This part of computation can be performed as soon as the ECDSA
+ * keypair from Round 1 is done. There is a case to be done
+ * for moving this in the body of Round 1, given how inexpensive it
+ * is, but I'm separating it to better reflect the paper.
+ * Either way, the shares and decommitment for the free term in the exponent
+ * MUST NOT be broadcast until every other player broadcasts the
+ * result of its Round 1
+ */
+void MPC_keygen_round2_vss(csprng *RNG, MPC_keygen_round1 *r1, MPC_keygen_round2 *r2, int i, int t, int n)
+{
+    printf("\t[Player %d] Generate VSS Shares for secret key\n", i);
+
+    VSS_make_shares(t, n, RNG, &r2->SHARES, r2->CHECKS, r1->SK);
+
+    printf("\t[Player %d] Broadcast Checks and decommitment string.\n", i);
+    printf("\t[Player %d] Transmit shares with point2point channel\n", i);
+}
+
+/* Keygen - VSS verification and shares composition for Round 2
+ *
+ * Once the shares and decommitments are received they can be
+ * verified and summed to compute the full key share for the player.
+ * Moreover, the full public key can be computed by adding all the
+ * free terms in the exponents from the checks.
+ *
+ * Note that it would be beneficial to have a routine to verify
+ * shares and the decommitment of the free term in the exponent
+ * so they can be processed as they are received, instead of processing
+ * them in bulk. Here it is done in bulk for simplicity.
+ */
+int MPC_keygen_round2_compose(MPC_keygen_session *s, int i)
+{
+    int j, n, rc;
+
+    n = s->party->n;
+
+    char ws[n][EFS_SECP256K1 + 1];
+    octet WS[n];
+
+    init_octets((char *)ws, WS, EFS_SECP256K1 + 1, n);
+
+    SSS_shares *SHARES;
+    octet *CHECKS;
+    MPC_player *p;
+
+    printf("\t[Player %d] Verify Shares\n", i);
+
+    /* Decommit Free term in the exponent and verify shares */
+    for (j = 0; j < n; j++)
+    {
+        if (i == j) continue; // Trust ourselves
+
+        // Load appropriate shares and checks
+        SHARES = &(s->round2[j].SHARES);
+        CHECKS = s->round2[j].CHECKS;
+
+        // Decommit free term in the exponent
+        rc = NM_COMMITMENT_decommit(CHECKS + 0, (s->round1)[j].R, (s->round1)[j].C);
+        if (rc != NM_COMMITMENT_OK)
+        {
+            printf("\t\tInvalid Commitment for Player %d. rc %d\n", j, rc);
+            return rc;
+        }
+
+        // Check the share is for the right player
+        if (!OCT_comp(SHARES->X+i, s->round2[i].SHARES.X+i))
+        {
+            printf("\t\tInvalid X share for Player %d.\n", j);
+            return MPC_FAIL;
+        }
+
+        // VSS Verification for the received share
+        rc = VSS_verify_shares(s->party->t, SHARES->X+i, SHARES->Y+i, CHECKS);
+        if (rc != VSS_OK)
+        {
+            printf("\t\tInvalid Shares for Player %d. rc %d\n", j, rc);
+            return rc;
+        }
+    }
+
+    /* Compose Public Key */
+
+    printf("\t[Player %d] Generate full PK\n", i);
+
+    p = s->party->players + i;
+
+    for (j = 0; j < n; j++)
+    {
+        OCT_copy(WS+j, s->round2[j].CHECKS + 0);
+    }
+
+    rc = MPC_SUM_ECPS(p->pkm.PK, WS, n);
+    if (rc != MPC_OK)
+    {
+        printf("\t\tInvalid format for PK Shares for Player %d. rc %d\n", i, rc);
+        return rc;
+    }
+
+    /* Compose Shares */
+
+    printf("\t[Player %d] Combine full share\n", i);
+
+    for (j = 0; j < n; j++)
+    {
+        OCT_copy(WS+j, s->round2[j].SHARES.Y + i);
+    }
+
+    MPC_SUM_BIGS(p->skm.SKY, WS, n);
+
+    OCT_copy(p->skm.SKX, s->round2[i].SHARES.X+i);
+
+    /* TODO This should not be stored here
+     *
+     * This should be computed by each player for all players
+     */
+    BIG_256_56 w;
+    ECP_SECP256K1 G;
+    ECP_SECP256K1_generator(&G);
+    BIG_256_56_fromBytesLen(w, p->skm.SKY->val, p->skm.SKY->len);
+    ECP_SECP256K1_mul(&G, w);
+    ECP_SECP256K1_toOctet(p->pkm.SPK, &G, true);
+
+    return MPC_OK;
+}
+
+/* Keygen - Generate Proofs of well formedness of the key material
+ *
+ * Generate a Schnorr Proof of knowledge of the secret share
+ * Generate a Square-Freeness proof for the Paillier Keys
+ * Generate a proof of well formedness for the ZKP modulus N, b0, b1
+ *
+ * The Schnorr Proof is performed here as specified in the paper,
+ * but it is inexpensive enough that it could be moved in round 1 and
+ * verified in round 2 to fail early. As for the other two proofs,
+ * they are quite slow and it is a good idea to have them performed
+ * as the last step.
+ */
+void MPC_keygen_round3_proofs(csprng *RNG, MPC_player *p, MPC_keygen_round3 *r3, octet *SESSION_ID, int i)
+{
+    char rv[EGS_SECP256K1];
+    octet RV = {0, sizeof(rv), rv};
+    char e[EGS_SECP256K1];
+    octet E = {0, sizeof(e), e};
+
+    char mp[HFS_2048];
+    octet MP = {0, sizeof(mp), mp};
+    char mq[HFS_2048];
+    octet MQ = {0, sizeof(mq), mq};
+
+    MODULUS_priv m;
+
+    /* Prove knowledge of DLOG PK = s.G */
+    printf("\t[Player %d] Prove knowledge of secret key\n", i);
+
+    SCHNORR_commit(RNG, &RV, r3->SCHNORR_C);
+    SCHNORR_challenge(p->pkm.SPK, r3->SCHNORR_C, p->ID, SESSION_ID, &E);
+    SCHNORR_prove(&RV, &E, p->skm.SKY, r3->SCHNORR_P);
+
+    OCT_clear(&RV);
+
+    /* Prove Square Freeness of the Paillier modulus */
+    printf("\t[Player %d] Prove Square-Freeness of Paillier modulus\n", i);
+
+    FF_2048_toOctet(&MP, p->skm.paillier_sk.p, HFLEN_2048);
+    FF_2048_toOctet(&MQ, p->skm.paillier_sk.q, HFLEN_2048);
+    MODULUS_fromOctets(&m, &MP, &MQ);
+
+    GMR_prove(&m, p->ID, SESSION_ID, r3->Y);
+
+    OCT_clear(&MP);
+    OCT_clear(&MQ);
+    MODULUS_kill(&m);
+
+    /* Prove well formedness of the BC modulus */
+    printf("\t[Player %d] Prove Well formedness of BC modulus\n", i);
+
+    BIT_COMMITMENT_setup_prove(RNG, &p->skm.bc_sm, &r3->BCP, p->ID, SESSION_ID);
+
+    printf("\t[Player %d] Broadcast Schnorr Proof (C, P), GMR Proof Y and BC proof values\n", i);
+}
+
+/* Keygen - Verify the ZKP for round 3
+ *
+ * Verify the Schnorr Proof for the secret key u
+ * Verify the Square-Freeness proof for the paillier PK
+ * Verify the proof of well formedness for the BC modulus
+ *
+ * This is done in bulk here for simplicity, but as for Round 2
+ * there is a strong case to be made to have a routine to perform
+ * this asyncronously as soon as the proofs come in from the other
+ * players.
+ */
+int MPC_keygen_round3_verify(MPC_keygen_session *s, int i)
+{
+    int j, n, rc;
+
+    char e[EGS_SECP256K1];
+    octet E = {0, sizeof(e), e};
+
+    char mn[FS_2048];
+    octet MN = {0, sizeof(mn), mn};
+
+    MPC_keygen_round3 *r;
+    MPC_player *p;
+
+    n = s->party->n;
+
+    printf("\t[Player %d] Verify key material ZKP\n", i);
+
+    for (j = 0; j < n; j++)
+    {
+        if(j == i) continue; // Trust ourselves
+
+        // Load appropriate player and round communications
+        r  = s->round3 + j;
+        p  = s->party->players + j;
+
+        /* Verify Schnorr Proof */
+        SCHNORR_challenge(p->pkm.SPK, r->SCHNORR_C, p->ID, s->ID, &E);
+        rc = SCHNORR_verify(p->pkm.SPK, r->SCHNORR_C, &E, r->SCHNORR_P);
+        if (rc != SCHNORR_OK)
+        {
+            printf("\t\tInvalid Schnorr Proof for Player %d. rc %d\n", j, rc);
+            return rc;
+        }
+
+        /* Verify GMR proof of Square-Freeness */
+        PAILLIER_PK_toOctet(&MN, &p->pkm.paillier_pk);
+        rc = GMR_verify(&MN, r->Y, p->ID, s->ID);
+        if (rc != GMR_OK)
+        {
+            printf("\t\tInvalid GMR Proof for Player %d. rc %d\n", j, rc);
+            return rc;
+        }
+
+        /* Verify well formedness of BC modulus */
+        rc = BIT_COMMITMENT_setup_verify(&p->pkm.bc_pm, &r->BCP, p->ID, s->ID);
+        if (rc != BIT_COMMITMENT_OK)
+        {
+            printf("\t\tInvalid BC Proof for Player %d. rc %d\n", j, rc);
+            return rc;
+        }
+    }
+
+    printf("\t[Player %d] Broadcast Success\n", i);
+
+    return MPC_OK;
+}
+
+/* Keygen - Orchestrate the Key Setup for all players */
+int key_setup(csprng *RNG, MPC_party *p)
+{
+    int i, t, n, rc;
+
+    n = p->n;
+    t = p->t;
+
+    /* Setup Keygen memory */
+
+    // Round1 memory
+    char round1_sk[n][EGS_SECP256K1];
+    char round1_pk[n][EFS_SECP256K1 + 1];
+    char round1_r[n][EGS_SECP256K1];
+    char round1_c[n][EGS_SECP256K1];
+    octet ROUND1_SK[n];
+    octet ROUND1_PK[n];
+    octet ROUND1_R[n];
+    octet ROUND1_C[n];
+
+    init_octets((char *)round1_sk, ROUND1_SK, EGS_SECP256K1,     n);
+    init_octets((char *)round1_pk, ROUND1_PK, EFS_SECP256K1 + 1, n);
+    init_octets((char *)round1_r,  ROUND1_R,  EGS_SECP256K1,     n);
+    init_octets((char *)round1_c,  ROUND1_C,  EGS_SECP256K1,     n);
+
+    MPC_keygen_round1 r1[n];
+
+    for (i = 0; i < n; i++)
+    {
+        r1[i].SK = ROUND1_SK + i;
+        r1[i].PK = ROUND1_PK + i;
+        r1[i].C  = ROUND1_C + i;
+        r1[i].R  = ROUND1_R + i;
+    }
+
+    // Keygen Round2 memory
+    char round2_shares_x[n][n][EGS_SECP256K1];
+    char round2_shares_y[n][n][EGS_SECP256K1];
+    char round2_checks[n][t][EFS_SECP256K1 + 1];
+    octet ROUND2_CHECKS[n * t];
+    octet ROUND2_SHARES_X[n * n];
+    octet ROUND2_SHARES_Y[n * n];
+
+    init_octets((char *)round2_shares_x, ROUND2_SHARES_X, EGS_SECP256K1,     n * n);
+    init_octets((char *)round2_shares_y, ROUND2_SHARES_Y, EGS_SECP256K1,     n * n);
+    init_octets((char *)round2_checks,   ROUND2_CHECKS,   EFS_SECP256K1 + 1, n * t);
+
+    MPC_keygen_round2 r2[n];
+
+    for (i = 0; i < n; i++)
+    {
+        r2[i].SHARES.X = ROUND2_SHARES_X + (n * i);
+        r2[i].SHARES.Y = ROUND2_SHARES_Y + (n * i);
+        r2[i].CHECKS   = ROUND2_CHECKS + (t * i);
+    }
+
+    // Keygen Round3 memory
+    char round3_sc[n][EFS_SECP256K1 + 1];
+    char round3_sp[n][EGS_SECP256K1];
+
+    octet ROUND3_SC[n];
+    octet ROUND3_SP[n];
+
+    init_octets((char *)round3_sc, ROUND3_SC, EFS_SECP256K1 + 1, n);
+    init_octets((char *)round3_sp, ROUND3_SP, EGS_SECP256K1,     n);
+
+    MPC_keygen_round3 r3[n];
+
+    for (i = 0; i < n; i++)
+    {
+        r3[i].SCHNORR_C = ROUND3_SC + i;
+        r3[i].SCHNORR_P = ROUND3_SP + i;
+    }
+
+    // Keygen Session memory
+    char id[IDLEN];
+    octet ID = {0, sizeof(id), id};
+    MPC_keygen_session s;
+
+    s.ID     = &ID;
+    s.party  = p;
+    s.round1 = r1;
+    s.round2 = r2;
+    s.round3 = r3;
+
+    /* Agree on session ID for keygen */
+    OCT_rand(s.ID, RNG, s.ID->max);
+
+    printf("\n *** Keygen ***\n");
+
+    /* Round 1 - generate key material, commitment */
+
+    printf("\nRound 1 - Generate Key Material\n");
+
+    for (i = 0; i < n; i++)
+    {
+        rc = MPC_keygen_round1_generate(RNG, p->players +i, s.round1 + i, i);
+        if (rc != MPC_OK)
+        {
+            return rc;
+        }
+
+        printf("\n");
+    }
+
+    /* Round 2 - compute VSS shares and checks */
+
+    printf("\nRound 2 - Compute VSS Shares and Checks\n");
+
+    for (i = 0; i < n; i++)
+    {
+        MPC_keygen_round2_vss(RNG, s.round1 + i, s.round2 + i, i, t, n);
+
+        printf("\n");
+    }
+
+    /* Round 2 - Verify VSS Shares and combine them */
+
+    printf("\nRound 2 - Verify and combine VSS Shares\n");
+
+    for (i = 0; i < n; i++)
+    {
+        rc = MPC_keygen_round2_compose(&s, i);
+        if (rc != MPC_OK)
+        {
+            return rc;
+        }
+
+        printf("\n");
+    }
+
+    /* Round 3 - Generate Proofs for Key Material */
+
+    printf("\nRound 3 - Generate Proofs for key material\n");
+
+    for (i = 0; i < n; i++)
+    {
+        MPC_keygen_round3_proofs(RNG, p->players + i, s.round3 + i, s.ID, i);
+        printf("\n");
+    }
+
+    /* Round 3 - Verify Proofs for Key Material */
+    printf("\n\nRound 3 - Verify Proofs for Key Material\n");
+
+    for (i = 0; i < n; i++)
+    {
+        rc = MPC_keygen_round3_verify(&s, i);
+        if (rc != MPC_OK)
+        {
+            return rc;
+        }
+
+        printf("\n");
+    }
+
+    return MPC_OK;
+}
+
+/* *** Signature functions ***/
+
+/* Sign - Convert shamir shares to additive */
+void MPC_sign_share_conversion(MPC_signing_session *s, int i)
+{
+    int j, k, t;
+
+    t = s->party->t;
+
+    char x[t-1][EGS_SECP256K1];
+    octet X[t-1];
+
+    init_octets((char *) x, X, EGS_SECP256K1, t-1);
+
+    MPC_player *p;
+    MPC_signing_additive_shares *sh;
+
+    k = 0;
+    for (j = 0; j < t; j++)
+    {
+        if (i == j) continue; // Do not include own shares in computation
+
+        // This looks like we are accessing the secret key material,
+        // but it is the X component of the Shamir Share, which
+        // is not secret
+        OCT_copy(X + k, s->party->players[j].skm.SKX);
+        k++;
+    }
+
+    printf("\t[Player %d] Convert Shamir Share to additive Share\n", i);
+
+    p  = s->party->players + i;
+    sh = s->shares + i;
+
+    SSS_shamir_to_additive(t, p->skm.SKX, p->skm.SKY, X, sh->W);
+
+    /* TODO This should not be computed here
+     *
+     * This should be computed by each player for all players
+     * using the same Lagrange coefficient above and the stored
+     * xi.G from the keygen
+     */
+    BIG_256_56 w;
+    ECP_SECP256K1 G;
+    ECP_SECP256K1_generator(&G);
+    BIG_256_56_fromBytesLen(w, sh->W->val, sh->W->len);
+    ECP_SECP256K1_mul(&G, w);
+    ECP_SECP256K1_toOctet(sh->WG, &G, true);
+}
+
+/* Sign - Generate secret values k, gamma for signature */
+void MPC_sign_round1_generate(csprng *RNG, MPC_signing_round1* r, int i)
+{
+    BIG_256_56 k;
+    BIG_256_56 q;
+
+    char gammapt[2 * EFS_SECP256K1 + 1];
+    octet GAMMAPT = {0, sizeof(gammapt), gammapt};
+
+    ECP_SECP256K1 ECP;
+
+    BIG_256_56_rcopy(q, CURVE_Order_SECP256K1);
+
+    printf("\t[Player %d] Generate Random k, gamma\n", i);
+
+    BIG_256_56_randomnum(k, q, RNG);
+    BIG_256_56_toBytes(r->K->val, k);
+    r->K->len = EGS_SECP256K1;
+
+    MPC_ECDSA_KEY_PAIR_GENERATE(RNG, r->GAMMA, &GAMMAPT);
+
+    // Convert GAMMAPT to compressed form
+    ECP_SECP256K1_fromOctet(&ECP, &GAMMAPT);
+    ECP_SECP256K1_toOctet(r->GAMMAPT, &ECP, true);
+
+    printf("\t[Player %d] Commit to gamma.G\n", i);
+
+    NM_COMMITMENT_commit(RNG, r->GAMMAPT, r->R, r->C);
+
+    printf("\t[Player %d] Transmit commitment C\n", i);
+}
+
+/* Sign -
+ * Perform MTA with Range Proof and Receiver ZK Proof for all players
+ * Instead of saving all the shares and then summing them, each player
+ * initialises DELTA with its own KGAMMA share and then accumulates the
+ * shares on top of it as they come. This saves memory and it is still
+ * fairly easy to parallelise with an opportune lock on DELTA.
+ *
+ * Given a Alice in the players:
+ * Step 1.  Alice encrypts its share and proves it is in the appropriate range in ZK
+ *
+ * The result from Step 1. is then transmitted to all the other players.
+ *
+ * Let's call Bob a generic receinver:
+ * Step 2.  Bob verifies the ZK proof and aborts if the verification fails
+ * Step 2A. Bob homomorphically multiplies its share and adds an obfuscation value z
+ * Step 2B. Bob proves knowledge of z and range of its share
+ * Step 2C. Bob adds BETA to its DELTA
+ * Step 3.  Alice verifies the ZK proof and aborts if the verification fails
+ * Step 3A. Alice decrypts the obfuscated product, retrieving ALPHA
+ * Step 3B. Alice adds ALPHA to its DELTA
+ *
+ */
+int MPC_sign_round2_mta(csprng *RNG, MPC_signing_session *s)
+{
+    int i, j, t, rc;
+
+    t = s->party->t;
+
+    /* Memory Setup */
+
+    BIG_256_56 delta[t];
+
+    char cb[FS_4096];
+    octet CB = {0, sizeof(cb), cb};
+
+    char rb[FS_4096];
+    octet RB = {0, sizeof(rb), rb};
+
+    char z[EGS_SECP256K1];
+    octet Z = {0, sizeof(z), z};
+
+    char e[EGS_SECP256K1];
+    octet E = {0, sizeof(e), e};
+
+    char alpha[EGS_SECP256K1];
+    octet ALPHA = {0, sizeof(alpha), alpha};
+
+    char beta[EGS_SECP256K1];
+    octet BETA = {0, sizeof(beta), beta};
+
+    MTA_RP_commitment alice_rp_c;
+    MTA_RP_rv         alice_rp_rv;
+    MTA_RP_proof      alice_rp_proof;
+
+    MTA_ZK_commitment bob_zk_c;
+    MTA_ZK_rv         bob_zk_rv;
+    MTA_ZK_proof      bob_zk_proof;
+
+    MPC_player *alice;
+    MPC_player *bob;
+
+    MPC_signing_round1 *alice_r1;
+    MPC_signing_round2 *alice_r2;
+    MPC_signing_round1 *bob_r1;
+
+    // Initialize accumulator for delta = k * gamma
+    for (i = 0; i < t; i++)
+    {
+        MTA_ACCUMULATOR_SET(delta[i], s->round1[i].GAMMA, s->round1[i].K);
+    }
+
+    /* MtA runs */
+    for (i = 0; i < t; i++)
+    {
+        alice    = s->party->players + i;
+        alice_r1 = s->round1 + i;
+        alice_r2 = s->round2 + i;
+
+        /* Alice - Initiate MTA protocol
+        *
+        * This is reused for all instances of the MTA protocol initiated
+        * by Alice
+        */
+
+        printf("\t[Player %d] MTA Pass 1\n", i);
+
+        MTA_CLIENT1(RNG, &alice->pkm.paillier_pk, alice_r1->K, alice_r2->CA, alice_r2->R);
+
+        for (j = 0; j < t; j++)
+        {
+            if (i == j) continue; // No MtA with ourselves
+
+            /* Alice - Generate Range Proof with Bob BC Public Modulus */
+
+            printf("\t[Player %d] Generate Range Proof for Pass 1\n", i);
+
+            bob    = s->party->players + j;
+            bob_r1 = s->round1 + j;
+
+            MTA_RP_commit(RNG, &alice->skm.paillier_sk, &bob->pkm.bc_pm, alice_r1->K, &alice_rp_rv, &alice_rp_c);
+            MTA_RP_challenge(&alice->pkm.paillier_pk, &bob->pkm.bc_pm, alice_r2->CA, &alice_rp_c, alice->ID, s->ID, &E);
+            MTA_RP_prove(&alice->skm.paillier_sk, alice_r1->K, alice_r2->R, &alice_rp_rv, &E, &alice_rp_proof);
+
+            MTA_RP_rv_kill(&alice_rp_rv);
+
+            printf("\t[Player %d] Transmit CA and proof (Z, U, W, S, S1, S2) to Player %d\n", i, j);
+
+            /* Bob - Verify Range Proof and perform second step of MTA protocol */
+
+            printf("\t[Player %d] Verify proof\n", j);
+
+            OCT_clear(&E);
+            MTA_RP_challenge(&alice->pkm.paillier_pk, &bob->pkm.bc_pm, alice_r2->CA, &alice_rp_c, alice->ID, s->ID, &E);
+
+            rc = MTA_RP_verify(&alice->pkm.paillier_pk, &bob->skm.bc_sm, alice_r2->CA, &alice_rp_c, &E, &alice_rp_proof);
+            if (rc != MTA_OK)
+            {
+                printf("\t\tInvalid Range Proof for Player %d. rc %d\n", i, rc);
+                return MPC_FAIL;
+            }
+
+            printf("\t[Player %d] MTA Pass 2 with ZK Proof\n", j);
+
+            MTA_SERVER(RNG, &alice->pkm.paillier_pk, bob_r1->GAMMA, alice_r2->CA, &Z, &RB, &CB, &BETA);
+
+            MTA_ZK_commit(RNG, &alice->pkm.paillier_pk, &alice->pkm.bc_pm, bob_r1->GAMMA, &Z, alice_r2->CA, &bob_zk_rv, &bob_zk_c);
+            MTA_ZK_challenge(&alice->pkm.paillier_pk, &alice->pkm.bc_pm, alice_r2->CA, &CB, &bob_zk_c, bob->ID, s->ID, &E);
+            MTA_ZK_prove(&alice->pkm.paillier_pk, bob_r1->GAMMA, &Z, &RB, &bob_zk_rv, &E, &bob_zk_proof);
+
+            MTA_ZK_rv_kill(&bob_zk_rv);
+            OCT_clear(&RB);
+            OCT_clear(&Z);
+
+            printf("\t[Player %d] Add BETA to the accumulator\n", j);
+
+            MTA_ACCUMULATOR_ADD(delta[j], &BETA);
+
+            printf("\t[Player %d] Transmit CB and proof (Z, Z1, T, V, W, S, S1, S2, T1, T2)\n", j);
+
+            /* Alice - Verify ZK proof and perform last step of MTA protocol */
+
+            printf("\t[Player %d] Verify proof\n", i);
+
+            OCT_clear(&E);
+            MTA_ZK_challenge(&alice->pkm.paillier_pk, &alice->pkm.bc_pm, alice_r2->CA, &CB, &bob_zk_c, bob->ID, s->ID, &E);
+
+            rc = MTA_ZK_verify(&alice->skm.paillier_sk, &alice->skm.bc_sm, alice_r2->CA, &CB, &bob_zk_c, &E, &bob_zk_proof);
+            if (rc != MTA_OK)
+            {
+                printf("\t\tInvalid ZK Proof for Player %d. rc %d\n", j, rc);
+                return MPC_FAIL;
+            }
+
+            printf("\t[Player %d] MTA Pass 3 and sum with accumulator\n", i);
+
+            MTA_CLIENT2(&alice->skm.paillier_sk, &CB, &ALPHA);
+
+            MTA_ACCUMULATOR_ADD(delta[i], &ALPHA);
+        }
+    }
+
+    // Put the accumulators in the correct round structs
+    for (i = 0; i < t; i++)
+    {
+        BIG_256_56_toBytes(s->round2[i].DELTA->val, delta[i]);
+        s->round2[i].DELTA->len = EGS_SECP256K1;
+    }
+
+    return MPC_OK;
+}
+
+/* Perform MTA with Range Proof and Receiver ZK Proof with check for all
+ * players.
+ * The same consideration aobut parallelisation done for the MtA holds.
+ *
+ * There is a case to be done for reusing the same encryption of k
+ * and RP Proof for both the MtA and MtAwC. I'm doing it separately here
+ * to better reflect the paper.
+ *
+ * Given a Alice in the players:
+ * Step 1.  Alice encrypts its share and proves it is in the appropriate range in ZK
+ *
+ * The result from Step 1. is then transmitted to all the other players.
+ *
+ * Let's call Bob a gneric receinver:
+ * Step 2.  Bob verifies the ZK proof and aborts if the verification fails
+ * Step 2A. Bob homomorphically multiplies its share and adds an obfuscation value z
+ * Step 2B. Bob proves knowledge of z and range and DLOG knowledge for its share
+ * Step 2C. Bob adds BETA to its DELTA
+ * Step 3.  Alice verifies the ZK proof and aborts if the verification fails
+ * Step 3A. Alice decrypts the obfuscated product, retrieving ALPHA
+ * Step 3B. Alice adds ALPHA to its DELTA
+ *
+ */
+int MPC_sign_round2_mtawc(csprng *RNG, MPC_signing_session *s)
+{
+    int i, j, t, rc;
+
+    t = s->party->t;
+
+    /* Memory Setup */
+
+    BIG_256_56 sigma[t];
+
+    char ca[FS_4096];
+    octet CA = {0, sizeof(ca), ca};
+
+    char cb[FS_4096];
+    octet CB = {0, sizeof(cb), cb};
+
+    char ra[FS_4096];
+    octet RA = {0, sizeof(ra), ra};
+
+    char rb[FS_4096];
+    octet RB = {0, sizeof(rb), rb};
+
+    char z[EGS_SECP256K1];
+    octet Z = {0, sizeof(z), z};
+
+    char e[EGS_SECP256K1];
+    octet E = {0, sizeof(e), e};
+
+    char alpha[EGS_SECP256K1];
+    octet ALPHA = {0, sizeof(alpha), alpha};
+
+    char beta[EGS_SECP256K1];
+    octet BETA = {0, sizeof(beta), beta};
+
+    MTA_RP_commitment alice_rp_c;
+    MTA_RP_rv         alice_rp_rv;
+    MTA_RP_proof      alice_rp_proof;
+
+    MTA_ZKWC_commitment bob_zkwc_c;
+    MTA_ZKWC_rv         bob_zkwc_rv;
+    MTA_ZKWC_proof      bob_zkwc_proof;
+
+    MPC_player *alice;
+    MPC_player *bob;
+
+    MPC_signing_round1 *alice_r1;
+
+    // Initialize accumulator for sigma = k * w
+    for (i = 0; i < t; i++)
+    {
+        MTA_ACCUMULATOR_SET(sigma[i], s->shares[i].W, s->round1[i].K);
+    }
+
+    /* MtAWC runs */
+    for (i = 0; i < t; i++)
+    {
+        alice    = s->party->players + i;
+        alice_r1 = s->round1 + i;
+
+        /* Alice - Initiate MTAWC protocol
+        *
+        * This is reused for all instances of the MTAWC protocol initiated
+        * by Alice
+        */
+
+        printf("\t[Player %d] MTAWC Pass 1\n", i);
+
+        MTA_CLIENT1(RNG, &alice->pkm.paillier_pk, alice_r1->K, &CA, &RA);
+
+        for (j = 0; j < t; j++)
+        {
+            if (i == j) continue; // No MtAWC with ourselves
+
+            /* Alice - Generate Range Proof with Bob BC Public Modulus */
+
+            printf("\t[Player %d] Generate Range Proof for Pass 1\n", i);
+
+            bob = s->party->players + j;
+
+            MTA_RP_commit(RNG, &alice->skm.paillier_sk, &bob->pkm.bc_pm, alice_r1->K, &alice_rp_rv, &alice_rp_c);
+            MTA_RP_challenge(&alice->pkm.paillier_pk, &bob->pkm.bc_pm, &CA, &alice_rp_c, alice->ID, s->ID, &E);
+            MTA_RP_prove(&alice->skm.paillier_sk, alice_r1->K, &RA, &alice_rp_rv, &E, &alice_rp_proof);
+
+            MTA_RP_rv_kill(&alice_rp_rv);
+
+            printf("\t[Player %d] Transmit CA and proof (Z, U, W, S, S1, S2) to Player %d\n", i, j);
+
+            /* Bob - Verify Range Proof and perform second step of MTAWC protocol */
+
+            printf("\t[Player %d] Verify proof\n", j);
+
+            OCT_clear(&E);
+            MTA_RP_challenge(&alice->pkm.paillier_pk, &bob->pkm.bc_pm, &CA, &alice_rp_c, alice->ID, s->ID, &E);
+
+            rc = MTA_RP_verify(&alice->pkm.paillier_pk, &bob->skm.bc_sm, &CA, &alice_rp_c, &E, &alice_rp_proof);
+            if (rc != MTA_OK)
+            {
+                printf("\t\tInvalid Range Proof for Player %d. rc %d\n", i, rc);
+                return MPC_FAIL;
+            }
+
+            printf("\t[Player %d] MTA Pass 2 with ZKWC Proof\n", j);
+
+            MTA_SERVER(RNG, &alice->pkm.paillier_pk, s->shares[j].W, &CA, &Z, &RB, &CB, &BETA);
+
+            MTA_ZKWC_commit(RNG, &alice->pkm.paillier_pk, &alice->pkm.bc_pm, s->shares[j].W, &Z, &CA, &bob_zkwc_rv, &bob_zkwc_c);
+            MTA_ZKWC_challenge(&alice->pkm.paillier_pk, &alice->pkm.bc_pm, &CA, &CB, s->shares[j].WG, &bob_zkwc_c, bob->ID, s->ID, &E);
+            MTA_ZKWC_prove(&alice->pkm.paillier_pk, s->shares[j].W, &Z, &RB, &bob_zkwc_rv, &E, &bob_zkwc_proof);
+
+            MTA_ZKWC_rv_kill(&bob_zkwc_rv);
+            OCT_clear(&RB);
+            OCT_clear(&Z);
+
+            printf("\t[Player %d] Add BETA to the accumulator\n", j);
+
+            MTA_ACCUMULATOR_ADD(sigma[j], &BETA);
+
+            printf("\t[Player %d] Transmit CB and proof (Z, Z1, T, V, W, S, S1, S2, T1, T2)\n", j);
+
+            /* Alice - Verify ZK proof and perform last step of MTA protocol */
+
+            printf("\t[Player %d] Verify proof\n", i);
+
+            OCT_clear(&E);
+            MTA_ZKWC_challenge(&alice->pkm.paillier_pk, &alice->pkm.bc_pm, &CA, &CB, s->shares[j].WG, &bob_zkwc_c, bob->ID, s->ID, &E);
+
+            rc = MTA_ZKWC_verify(&alice->skm.paillier_sk, &alice->skm.bc_sm, &CA, &CB, s->shares[j].WG, &bob_zkwc_c, &E, &bob_zkwc_proof);
+            if (rc != MTA_OK)
+            {
+                printf("\t\tInvalid ZKWC Proof for Player %d. rc %d\n", j, rc);
+                return MPC_FAIL;
+            }
+
+            printf("\t[Player %d] MTA Pass 3 and sum with accumulator\n", i);
+
+            MTA_CLIENT2(&alice->skm.paillier_sk, &CB, &ALPHA);
+
+            MTA_ACCUMULATOR_ADD(sigma[i], &ALPHA);
+        }
+
+        OCT_clear(&RA);
+    }
+
+    // Put the accumulators in the correct round structs
+    for (i = 0; i < t; i++)
+    {
+        BIG_256_56_toBytes(s->round2[i].SIGMA->val, sigma[i]);
+        s->round2[i].SIGMA->len = EGS_SECP256K1;
+    }
+
+    return MPC_OK;
+}
+
+/* Sign - Compute commitment and well formedness proof for Phase3 */
+void MPC_sign_round3_commitment(csprng *RNG, MPC_signing_session *s, int i)
+{
+    MPC_player *p;
+    MPC_signing_round2 *r2;
+    MPC_signing_round3 *r3;
+
+    char e[EGS_SECP256K1];
+    octet E = {0, sizeof(e), e};
+
+    GG20_ZKP_rv rv;
+
+    p = s->party->players + i;
+    r2 = s->round2 + i;
+    r3 = s->round3 + i;
+
+    printf("\t[Player %d] Compute commitment to sigma T and ZKP that T is well formed\n", i);
+
+    MPC_PHASE3_T(RNG, r2->SIGMA, r3->L, r3->T);
+
+    GG20_ZKP_phase3_commit(RNG, &rv, r3->C);
+    GG20_ZKP_phase3_challenge(r3->T, r3->C, p->ID, s->ID, &E);
+    GG20_ZKP_phase3_prove(&rv, &E, r2->SIGMA, r3->L, &r3->p);
+
+    printf("\t[Player %d] Broadcast T value and ZK Proof, along with the DELTA value\n", i);
+
+    GG20_ZKP_rv_kill(&rv);
+}
+
+/* Sign - Verify well formedness proof for Phase3 */
+int MPC_sign_round3_verify(MPC_signing_session *s, int i)
+{
+    int t, j, rc;
+
+    t = s->party->t;
+
+    MPC_player *p;
+    MPC_signing_round3 *r3;
+
+    char e[EGS_SECP256K1];
+    octet E = {0, sizeof(e), e};
+
+    /* Verify ZKP for T */
+
+    printf("\t[Player %d] Verify ZKP of well formedness for T\n", i);
+
+    for(j = 0; j < t; j++)
+    {
+        if (i == j) continue; // Trust self
+
+        r3 = s->round3 + j;
+        p  = s->party->players + j;
+
+        GG20_ZKP_phase3_challenge(r3->T, r3->C, p->ID, s->ID, &E);
+        rc = GG20_ZKP_phase3_verify(r3->T, r3->C, &E, &r3->p);
+        if (rc != GG20_ZKP_OK)
+        {
+            printf("\t\tInvalid ZKP for player %d. rc %d\n", j, rc);
+            return MPC_FAIL;
+        }
+    }
+
+    return MPC_OK;
+}
+
+/* Sign - Combine the k * gamma shares and combine (k * gamma) ^ -1 */
+void MPC_sign_round3_invkgamma(MPC_signing_session *s, int i)
+{
+    int j, t;
+
+    t = s->party->t;
+
+    char kgamma[t][EGS_SECP256K1];
+    octet KGAMMA[t];
+
+    init_octets((char *) kgamma, KGAMMA, EGS_SECP256K1, t);
+
+    printf("\t[Player %d] Combine receinved delta in k * gamma and invert it\n", i);
+
+    // Load all KGAMMA shares (DELTAs)
+    for (j = 0; j < t; j++)
+    {
+        OCT_copy(KGAMMA + j, s->round2[j].DELTA);
+    }
+
+    MPC_INVKGAMMA(KGAMMA, s->round3[i].INVKGAMMA, t);
+}
+
+/* Sign - decommit gamma_i.G and combine them
+ *
+ * Doing this in bulk, but the same reasoning to bulk
+ * operations in keygen apply here.
+ */
+int MPC_sign_round4_combine_R(MPC_signing_session *s, int i)
+{
+    int j, t, rc;
+
+    MPC_signing_round1 *r1;
+    MPC_signing_round4 *r4;
+
+    t = s->party->t;
+    r4 = s->round4 + i;
+
+    char gammapt[t][EFS_SECP256K1 + 1];
+    octet GAMMAPT[t];
+
+    init_octets((char *)gammapt, GAMMAPT, EFS_SECP256K1 + 1, t);
+
+    /* Verify Decommitmet of gamma_i.G */
+    for (j = 0; j < t; j++)
+    {
+        r1 = s->round1 + j;
+        OCT_copy(GAMMAPT + j, r1->GAMMAPT);
+
+        if (i == j) continue; // Trust ourselves
+
+        rc = NM_COMMITMENT_decommit(r1->GAMMAPT, r1->R, r1->C);
+        if (rc != NM_COMMITMENT_OK)
+        {
+            printf("\t\tInvalid Commitment for Player %d\n", j);
+            return MPC_FAIL;
+        }
+    }
+
+    /* Combine to retreive R component */
+    printf("\t[Player %d] Recombine R component of the signautre\n", i);
+
+    rc = MPC_R(s->round3[i].INVKGAMMA, GAMMAPT, r4->R, r4->RP, t);
+    if (rc != MPC_OK)
+    {
+        printf("\t\tError recombining R component. rc %d", rc);
+        return rc;
+    }
+
+    return MPC_OK;
+}
+
+/* Sign - Compute proof of consistency with Paillier ciphertext */
+int MPC_sign_round5_prove(csprng *RNG, MPC_signing_session *s, int i)
+{
+    int j, rc;
+
+    MPC_player *p;
+    MPC_player *o;
+
+    MPC_signing_round1 *r1;
+    MPC_signing_round2 *r2;
+    MPC_signing_round4 *r4;
+    MPC_signing_round5 *r5;
+
+    p  = s->party->players + i;
+    r1 = s->round1 + i;
+    r2 = s->round2 + i;
+    r4 = s->round4 + i;
+    r5 = s->round5 + i;
+
+    GGN_rv rv;
+
+    char e[EGS_SECP256K1];
+    octet E = {0, sizeof(e), e};
+
+    printf("\t[Player %d] Generate check Rt = k.R\n", i);
+
+    rc = MPC_ECP_GENERATE_CHECK(r4->RP, r1->K, r5->RI);
+    if (rc != MPC_OK)
+    {
+        printf("\t\tError generatring Rt\n");
+        return rc;
+    }
+
+    printf("\t[Player %d] Generate consistency proofs for Rt and E(K)\n", i);
+
+    for (j = 0; j < s->party->t; j++)
+    {
+        if (i == j) continue; // No proof for self
+
+        o = s->party->players + j;
+
+        rc = GGN_commit(RNG, &p->skm.paillier_sk, &o->pkm.bc_pm, r4->RP, r1->K, &rv, r5->c + j);
+        if (rc != GGN_OK)
+        {
+            printf("\t\tError generating proof for player %d\n rc %d", i, rc);
+            return MPC_FAIL;
+        }
+
+        GGN_challenge(&p->pkm.paillier_pk, &o->pkm.bc_pm, r4->RP, r5->RI, r2->CA, r5->c + j, p->ID, s->ID, &E);
+        GGN_prove(&p->skm.paillier_sk, r1->K, r2->R, &rv, &E, r5->p + j);
+
+        GGN_rv_kill(&rv);
+    }
+
+    printf("\t[Player %d] Broadcast Rt and consistency proof\n", i);
+
+    return MPC_OK;
+}
+
+/* Sign - Verify proof of consistency with Paillier ciphertext
+ * and check that recombining the Ri the public key is retrieved
+ *
+ * The same reasoning on parallelisation made for the other functions applies
+ */
+int MPC_sign_round5_verify(MPC_signing_session *s, int i)
+{
+    int j, t, rc;
+
+    t = s->party->t;
+
+    char rt[t][EFS_SECP256K1 + 1];
+    octet RT[t];
+
+    char e[EGS_SECP256K1];
+    octet E = {0, sizeof(e), e};
+
+    init_octets((char *)rt, RT, EFS_SECP256K1 + 1, t);
+
+    MPC_player *p;
+    MPC_player *o;
+    MPC_signing_round2 *r2;
+    MPC_signing_round4 *r4;
+    MPC_signing_round5 *r5;
+
+    p  = s->party->players + i;
+
+    /* Verify the proofs of consistency for the checks */
+
+    printf("\t[Player %d] Verify Proofs of consistency for Rt\n", i);
+
+    for (j = 0; j < t; j++)
+    {
+        o = s->party->players + j;
+        r2 = s->round2 + j;
+        r4 = s->round4 + j;
+        r5 = s->round5 + j;
+
+        OCT_copy(RT + j, r5->RI);
+
+        if (i == j) continue; // Trust ourselves
+
+        GGN_challenge(&o->pkm.paillier_pk, &p->pkm.bc_pm, r4->RP, r5->RI, r2->CA, r5->c + i, o->ID, s->ID, &E);
+        rc = GGN_verify(&o->pkm.paillier_pk, &p->skm.bc_sm, r4->RP, r5->RI, r2->CA, r5->c + i, &E, r5->p + i);
+        if (rc != GGN_OK)
+        {
+            printf("\t\tInvalid Proof for Player %d. rc %d\n", j, rc);
+            return MPC_FAIL;
+        }
+    }
+
+    /* Verify R using the checks */
+
+    printf("\t[Player %d] Verify R with the received checks\n", i);
+
+    rc = MPC_ECP_VERIFY(RT, NULL, t);
+    if (rc != MPC_OK)
+    {
+        printf("\t\tInvalid checks for R. rc %d\n", rc);
+        return MPC_FAIL;
+    }
+
+    return MPC_OK;
+}
+
+/* Sign - compute check for sigma and ZKP of consistency with T from round 3 */
+int MPC_sign_round6_prove(csprng *RNG, MPC_signing_session *s, int i)
+{
+    int rc;
+
+    char e[EGS_SECP256K1];
+    octet E = {0, sizeof(e), e};
+
+    MPC_player *p;
+    MPC_signing_round2 *r2;
+    MPC_signing_round3 *r3;
+    MPC_signing_round4 *r4;
+    MPC_signing_round6 *r6;
+
+    p  = s->party->players + i;
+    r2 = s->round2 + i;
+    r3 = s->round3 + i;
+    r4 = s->round4 + i;
+    r6 = s->round6 + i;
+
+    GG20_ZKP_rv rv;
+
+    /* Generate check for consistency of sigma */
+
+    printf("\t[Player %d] Generate check for consistency of sigma\n", i);
+
+    rc = MPC_ECP_GENERATE_CHECK(r4->RP, r2->SIGMA, r6->SI);
+    if (rc != MPC_OK)
+    {
+        printf("\t\tError genereting Si. rc %d\n", rc);
+        return rc;
+    }
+
+    /* Generate ZKP of consistency of the check */
+    rc = GG20_ZKP_phase6_commit(RNG, r4->RP, &rv, &r6->c);
+    if (rc != GG20_ZKP_OK)
+    {
+        printf("\t\tError generating commit for phase6 proof. rc %d\n", rc);
+        return rc;
+    }
+
+    GG20_ZKP_phase6_challenge(r4->RP, r3->T, r6->SI, &r6->c, p->ID, s->ID, &E);
+    GG20_ZKP_phase6_prove(&rv, &E, r2->SIGMA, r3->L, &r6->p);
+
+    // Clean memory
+    GG20_ZKP_rv_kill(&rv);
+
+    return MPC_OK;
+}
+
+/* Sign - Verify the checks and consistency proofs for Phase 6 */
+int MPC_sign_round6_verify(MPC_signing_session *s, int i)
+{
+    int j, t, rc;
+
+    t = s->party->t;
+
+    char e[EGS_SECP256K1];
+    octet E = {0, sizeof(e), e};
+
+    char si[t][EFS_SECP256K1 + 1];
+    octet SI[t];
+
+    init_octets((char *)si, SI, EFS_SECP256K1 + 1, t);
+
+    MPC_signing_round3 *r3;
+    MPC_signing_round4 *r4;
+    MPC_signing_round6 *r6;
+
+    /* Verify the consistency of the SI checks */
+
+    printf("\t[Player %d] Verify the consistency of the SI checks\n", i);
+
+    for (j = 0; j < t; j++)
+    {
+        r3 = s->round3 + j;
+        r4 = s->round4 + j;
+        r6 = s->round6 + j;
+
+        OCT_copy(SI + j, r6->SI);
+
+        if (i == j) continue; // Trust ourselves
+
+        GG20_ZKP_phase6_challenge(r4->RP, r3->T, r6->SI, &r6->c, s->party->players[j].ID, s->ID, &E);
+        rc = GG20_ZKP_phase6_verify(r4->RP, r3->T, r6->SI, &r6->c, &E, &r6->p);
+        if (rc != GG20_ZKP_OK)
+        {
+            printf("\t\tInvalid check for player %d. rc %d\n", j, rc);
+            return MPC_FAIL;
+        }
+    }
+
+    /* Verify R, SIGMA using the checks */
+
+    printf("\t[Player %d] Verify R, SIGMA using checks\n", i);
+
+    rc = MPC_ECP_VERIFY(SI, s->party->players[i].pkm.PK, t);
+    if (rc != MPC_OK)
+    {
+        printf("\t\tInvalid checks for R, SIGMA. rc %d\n", rc);
+        return MPC_FAIL;
+    }
+
+    return MPC_OK;
+}
+
+/* Sign - compute S component of the signature */
+int MPC_sign_round7_si(MPC_signing_session *s, octet *HM, int i)
+{
+    int rc;
+
+    printf("\t[Player %d] Compute share s_i of the signature S component\n", i);
+
+    rc = MPC_S(HM, s->round4[i].R, s->round1[i].K, s->round2[i].SIGMA, s->round7[i].SI);
+    if (rc != MPC_OK)
+    {
+        printf("\t\tError generating S share. rc %d\n", rc);
+        return rc;
+    }
+
+    return MPC_OK;
+}
+
+/* Sign - compute S component of the signature */
+int MPC_sign_round7_combine(MPC_signing_session *s, octet *HM, int i)
+{
+    int j, t, rc;
+
+    t = s->party->t;
+
+    char si[t][EGS_SECP256K1];
+    octet SI[t];
+
+    init_octets((char *)si, SI, EGS_SECP256K1, t);
+
+    for (j = 0; j < t; j++)
+    {
+        OCT_copy(SI + j, s->round7[j].SI);
+    }
+
+    printf("\t[Player %d] Recombine S component of signature\n", i);
+
+    MPC_SUM_BIGS(s->round7[i].S, SI, t);
+
+    printf("\t[Player %d] Verify Signature\n", i);
+
+    rc = MPC_ECDSA_VERIFY(HM, s->party->players[i].pkm.PK, s->round4[i].R, s->round7[i].S);
+    if (rc != MPC_OK)
+    {
+        fprintf(stderr, "\t\tInvalid signature. rc: %d\n", rc);
+        return rc;
+    }
+
+    return MPC_OK;
+}
+
+/* Sign - Orchestrate the signing functions
+ *
+ * Step 1.  Each player generates random k, gamma and commits to gamma.G
+ * Step 2.  Each player performs a MTA with shares k_i, gamma_j and accumulates the shares
+ * Step 2A. Each player performs a MTAWC with shares k_i, sk_j and accumulates the shares
+ * Step 3.  Players compute the Phase3 values and ZKP and sigma.
+ * Step 3A. Players broadcast delta shares and recombine (k * gamma)^-1
+ * Step 4.  Players decommit gamma_i.G and recombine the R component
+ * Step 5.  Compute checks Rt for R, K and ZKP of consistency with the encryption from round 2
+ * Step 5A. Verify Rt consistency and then use them to check R, K
+ * Step 6.  Compute checks SI for R, SIGMA and ZKP of consistency with T from round 3
+ * Step 6A  Verify  SI consistency and use them to check R, SIGMA
+ * Step 7.  Compute the signature S component share
+ * Step 7A. Recombine the full S component
+ */
+int signature(csprng *RNG, MPC_party *p, octet *MSG)
+{
+    int i, t, rc;
+
+    t = p->t;
+
+    /* Signing Session Memory Setup */
+    char hm[SHA256];
+    octet HM = {0, sizeof(hm), hm};
+
+    // Additive shares
+    char as_w[t][EGS_SECP256K1];
+    char as_wg[t][EFS_SECP256K1 + 1];
+
+    octet AS_W[t];
+    octet AS_WG[t];
+
+    init_octets((char *)as_w,  AS_W,  EGS_SECP256K1,     t);
+    init_octets((char *)as_wg, AS_WG, EFS_SECP256K1 + 1, t);
+
+    MPC_signing_additive_shares as[t];
+
+    for (i = 0; i < t; i++)
+    {
+        as[i].W  = AS_W + i;
+        as[i].WG = AS_WG + i;
+    }
+
+    // Round 1
+    char phase1_gamma[t][EGS_SECP256K1];
+    char phase1_gammapt[t][EFS_SECP256K1 + 1];
+    char phase1_k[t][EGS_SECP256K1];
+    char phase1_r[t][EGS_SECP256K1];
+    char phase1_c[t][EGS_SECP256K1];
+
+    octet PHASE1_GAMMA[t];
+    octet PHASE1_GAMMAPT[t];
+    octet PHASE1_K[t];
+    octet PHASE1_R[t];
+    octet PHASE1_C[t];
+
+    init_octets((char *)phase1_gamma,   PHASE1_GAMMA,   EGS_SECP256K1,     t);
+    init_octets((char *)phase1_gammapt, PHASE1_GAMMAPT, EFS_SECP256K1 + 1, t);
+    init_octets((char *)phase1_k,       PHASE1_K,       EGS_SECP256K1,     t);
+    init_octets((char *)phase1_r,       PHASE1_R,       EGS_SECP256K1,     t);
+    init_octets((char *)phase1_c,       PHASE1_C,       EGS_SECP256K1,     t);
+
+    MPC_signing_round1 r1[t];
+
+    for (i = 0; i < t; i++)
+    {
+        r1[i].GAMMA   = PHASE1_GAMMA + i;
+        r1[i].GAMMAPT = PHASE1_GAMMAPT + i;
+        r1[i].K       = PHASE1_K + i;
+        r1[i].R       = PHASE1_R + i;
+        r1[i].C       = PHASE1_C + i;
+    }
+
+    // Round 2
+    char phase2_r[t][FS_4096];
+    char phase2_ca[t][FS_4096];
+    char phase2_delta[t][EGS_SECP256K1];
+    char phase2_sigma[t][EGS_SECP256K1];
+
+    octet PHASE2_R[t];
+    octet PHASE2_CA[t];
+    octet PHASE2_DELTA[t];
+    octet PHASE2_SIGMA[t];
+
+    init_octets((char *)phase2_r,     PHASE2_R,     FS_4096,       t);
+    init_octets((char *)phase2_ca,    PHASE2_CA,    FS_4096,       t);
+    init_octets((char *)phase2_delta, PHASE2_DELTA, EGS_SECP256K1, t);
+    init_octets((char *)phase2_sigma, PHASE2_SIGMA, EGS_SECP256K1, t);
+
+    MPC_signing_round2 r2[t];
+
+    for (i = 0; i < t; i++)
+    {
+        r2[i].R     = PHASE2_R + i;
+        r2[i].CA    = PHASE2_CA + i;
+        r2[i].DELTA = PHASE2_DELTA + i;
+        r2[i].SIGMA = PHASE2_SIGMA + i;
+    }
+
+    // Round 3
+    char phase3_invkgamma[t][EGS_SECP256K1];
+    char phase3_t[t][EFS_SECP256K1 + 1];
+    char phase3_l[t][EGS_SECP256K1];
+    char phase3_c[t][EFS_SECP256K1 + 1];
+
+    octet PHASE3_INVKGAMMA[t];
+    octet PHASE3_T[t];
+    octet PHASE3_L[t];
+    octet PHASE3_C[t];
+
+    init_octets((char *)phase3_invkgamma, PHASE3_INVKGAMMA, EGS_SECP256K1,     t);
+    init_octets((char *)phase3_t,         PHASE3_T,         EFS_SECP256K1 + 1, t);
+    init_octets((char *)phase3_l,         PHASE3_L,         EGS_SECP256K1,     t);
+    init_octets((char *)phase3_c,         PHASE3_C,         EFS_SECP256K1 + 1, t);
+
+    MPC_signing_round3 r3[t];
+
+    for (i = 0; i < t; i++)
+    {
+        r3[i].INVKGAMMA = PHASE3_INVKGAMMA + i;
+        r3[i].T         = PHASE3_T + i;
+        r3[i].L         = PHASE3_L + i;
+        r3[i].C         = PHASE3_C + i;
+    }
+
+    // Round 4
+    char phase4_r[t][EGS_SECP256K1];
+    char phase4_rp[t][EFS_SECP256K1 + 1];
+
+    octet PHASE4_R[t];
+    octet PHASE4_RP[t];
+
+    init_octets((char *)phase4_r,  PHASE4_R,  EGS_SECP256K1,     t);
+    init_octets((char *)phase4_rp, PHASE4_RP, EFS_SECP256K1 + 1, t);
+
+    MPC_signing_round4 r4[t];
+
+    for (i = 0; i < t; i++)
+    {
+        r4[i].R  = PHASE4_R  + i;
+        r4[i].RP = PHASE4_RP + i;
+    }
+
+    // Round 5
+    char phase5_ri[t][EFS_SECP256K1 + 1];
+    octet PHASE5_RI[t];
+    init_octets((char *)phase5_ri, PHASE5_RI, EFS_SECP256K1 + 1, t);
+
+    GGN_commitment phase5_c[t][t];
+    GGN_proof phase5_p[t][t];
+
+    MPC_signing_round5 r5[t];
+
+    for (i = 0; i < t; i++)
+    {
+        r5[i].RI = PHASE5_RI + i;
+        r5[i].c  = phase5_c[i];
+        r5[i].p  = phase5_p[i];
+    }
+
+    // Round 6
+    char phase6_si[t][EFS_SECP256K1 + 1];
+    octet PHASE6_SI[t];
+    init_octets((char *)phase6_si, PHASE6_SI, EFS_SECP256K1 + 1, t);
+
+    MPC_signing_round6 r6[t];
+
+    for (i = 0; i < t; i++)
+    {
+        r6[i].SI = PHASE6_SI + i;
+    }
+
+    // Round 7
+    char phase7_si[t][EGS_SECP256K1];
+    char phase7_s[t][EGS_SECP256K1];
+
+    octet PHASE7_SI[t];
+    octet PHASE7_S[t];
+
+    init_octets((char *)phase7_si, PHASE7_SI, EGS_SECP256K1, t);
+    init_octets((char *)phase7_s,  PHASE7_S,  EGS_SECP256K1, t);
+
+    MPC_signing_round7 r7[t];
+
+    for (i = 0; i < t; i++)
+    {
+        r7[i].SI = PHASE7_SI + i;
+        r7[i].S  = PHASE7_S  + i;
+    }
+
+    // Session
+    char id[IDLEN];
+    octet ID = {0, sizeof(id), id};
+
+    MPC_signing_session s;
+
+    s.ID     = &ID;
+    s.shares = as;
+    s.party  = p;
+    s.round1 = r1;
+    s.round2 = r2;
+    s.round3 = r3;
+    s.round4 = r4;
+    s.round5 = r5;
+    s.round6 = r6;
+    s.round7 = r7;
+
+    /* Agree on session ID for signature */
+    OCT_rand(s.ID, RNG, s.ID->max);
+
+    printf("\n *** Signature ***\n");
+
+    printf("\nSign message '%s'\n", MSG->val);
+
+    printf("\nPreparation\n");
+
+    /* Preparation - hash message */
+
+    printf("\t[Everyone] Compute Message hash\n");
+
+    MPC_HASH(SHA256, MSG, &HM);
+
+    /* Preparation - convert shares to additive */
+    for (i = 0; i < t; i++)
+    {
+        MPC_sign_share_conversion(&s, i);
+        printf("\n");
+    }
+
+    char w[EFS_SECP256K1 + 1];
+    octet W = {0, sizeof(w), w};
+    MPC_SUM_ECPS(&W, AS_WG, t);
+
+    if (!OCT_comp(&W, p->players->pkm.PK))
+    {
+        printf("Not te same\n");
+        OCT_output(&W);
+        OCT_output(p->players->pkm.PK);
+        return MPC_FAIL;
+    }
+
+    /* Round 1 - Generate Secret values */
+    printf("\nRound 1\n");
+
+    for (i = 0; i < t; i++)
+    {
+        MPC_sign_round1_generate(RNG, s.round1 + i, i);
+        printf("\n");
+    }
+
+    /* Round 2 - MTA/WC runs */
+    printf("\nRound 2\n");
+
+    rc = MPC_sign_round2_mta(RNG, &s);
+    if (rc != MPC_OK)
+    {
+        return rc;
+    }
+
+    rc = MPC_sign_round2_mtawc(RNG, &s);
+    if (rc != MPC_OK)
+    {
+        return rc;
+    }
+
+    /* Round 3 - Generate commitment for sigma and its ZKP */
+    printf("\nRound 3\n");
+
+    for (i = 0; i < t; i++)
+    {
+        MPC_sign_round3_commitment(RNG, &s, i);
+        printf("\n");
+    }
+
+    /* Round 3 - Verify commitment ZKP */
+    for (i = 0; i < t; i++)
+    {
+        rc = MPC_sign_round3_verify(&s, i);
+        if (rc != MPC_OK)
+        {
+            return rc;
+        }
+        printf("\n");
+    }
+
+    /* Round 3 - Recombine inverse of k * gamma */
+    for (i = 0; i < t; i++)
+    {
+        MPC_sign_round3_invkgamma(&s, i);
+        printf("\n");
+    }
+
+    /* Round 4 - Combine R component */
+
+    printf("\nRound 4\n");
+
+    for (i = 0; i < t; i++)
+    {
+        rc = MPC_sign_round4_combine_R(&s, i);
+        if (rc != MPC_OK)
+        {
+            return rc;
+        }
+        printf("\n");
+    }
+
+    /* Round 5 - Generate checks and proofs */
+    printf("\nRound 5\n");
+
+    for (i = 0; i < t; i++)
+    {
+        rc = MPC_sign_round5_prove(RNG, &s, i);
+        if (rc != MPC_OK)
+        {
+            return rc;
+        }
+        printf("\n");
+    }
+
+    /* Round 5 - Verify checks and proofs */
+    for (i = 0; i < t; i++)
+    {
+        rc = MPC_sign_round5_verify(&s, i);
+        if (rc != MPC_OK)
+        {
+            return rc;
+        }
+        printf("\n");
+    }
+
+    /* Round 6 - Generate checks and proofs */
+    printf("\nRound 6\n");
+
+    for (i = 0; i < t; i++)
+    {
+        rc = MPC_sign_round6_prove(RNG, &s, i);
+        if (rc != MPC_OK)
+        {
+            return rc;
+        }
+        printf("\n");
+    }
+
+    /* Round 6 - Verify checks and proofs */
+    for (i = 0; i < t; i++)
+    {
+        rc = MPC_sign_round6_verify(&s, i);
+        if (rc != MPC_OK)
+        {
+            return rc;
+        }
+        printf("\n");
+    }
+
+    /* Round 7 - Compute S shares */
+    printf("\nRound 7\n");
+
+    for (i = 0; i < t; i++)
+    {
+        rc = MPC_sign_round7_si(&s, &HM, i);
+        if (rc != MPC_OK)
+        {
+            return rc;
+        }
+        printf("\n");
+    }
+
+    /* Round 7 - Combine S shares */
+    for (i = 0; i < t; i++)
+    {
+        rc = MPC_sign_round7_combine(&s, &HM, i);
+        if (rc != MPC_OK)
+        {
+            return rc;
+        }
+        printf("\n");
+    }
+
+    printf("\nGenerated Signature:\n");
+
+    printf("\tR = ");
+    OCT_output(s.round4->R);
+    printf("\tS = ");
+    OCT_output(s.round7->S);
+
+    return MPC_OK;
+}
+
+void usage(char *name)
+{
+    printf("Usage: %s t n\n", name);
+    printf("Run a full (t, n) keygen and signature flow\n");
+    printf("\n");
+    printf("  t  Threshold for the MPC protocol. t <= n\n");
+    printf("  n  Number of participants in the MPC protocol. t <= n, n>1\n");
+    printf("\n");
+    printf("Example:\n");
+    printf("  %s 3 4\n", name);
+}
+
+int main(int argc, char *argv[])
+{
+    int i, t, n, rc;
+
+    /* Read arguments */
+    if (argc != 3)
+    {
+        usage(argv[0]);
+        exit(EXIT_FAILURE);
+    }
+
+    t = atoi(argv[1]);
+    n = atoi(argv[2]);
+
+    if (t < 1 || n < 2 || t > n)
+    {
+        usage(argv[0]);
+        exit(EXIT_FAILURE);
+    }
+
+    /* Memory setup
+     *
+     * Setup the necessary memory for a (t, n) party
+     */
+    char player_ids[n][IDLEN];
+    char player_pks[n][EFS_SECP256K1 + 1];
+    char player_spks[n][EFS_SECP256K1 + 1];
+    char player_skx[n][EGS_SECP256K1];
+    char player_sky[n][EGS_SECP256K1];
+    octet PLAYER_IDS[n];
+    octet PLAYER_PKS[n];
+    octet PLAYER_SPKS[n];
+    octet PLAYER_SKX[n];
+    octet PLAYER_SKY[n];
+
+    init_octets((char *)player_ids,  PLAYER_IDS,  IDLEN,             n);
+    init_octets((char *)player_pks,  PLAYER_PKS,  EFS_SECP256K1 + 1, n);
+    init_octets((char *)player_spks, PLAYER_SPKS, EFS_SECP256K1 + 1, n);
+    init_octets((char *)player_skx,  PLAYER_SKX,  EGS_SECP256K1,     n);
+    init_octets((char *)player_sky,  PLAYER_SKY,  EGS_SECP256K1,     n);
+
+    MPC_player players[n];
+
+    for (i = 0; i < n; i++)
+    {
+        players[i].ID      = PLAYER_IDS + i;
+        players[i].pkm.PK  = PLAYER_PKS + i;
+        players[i].pkm.SPK = PLAYER_SPKS + i;
+        players[i].skm.SKX = PLAYER_SKX + i;
+        players[i].skm.SKY = PLAYER_SKY + i;
+    }
+
+    MPC_party p = {t, n, players};
+
+    // Deterministic RNG for example
+    char seed[32] = {0};
+    csprng RNG;
+    RAND_seed(&RNG, 32, seed);
+
+    // Assign IDs to players
+    for (i = 0; i < n; i++)
+    {
+        OCT_rand(PLAYER_IDS+i, &RNG, IDLEN);
+    }
+
+    printf("MPC full flow example\n");
+
+    // Key setup phase
+    rc = key_setup(&RNG, &p);
+    if (rc != MPC_OK)
+    {
+        exit(EXIT_FAILURE);
+    }
+
+    // Signature phase
+    char* msg = "BANANA";
+    octet MSG = {0, sizeof(msg), msg};
+
+    rc = signature(&RNG, &p, &MSG);
+    if (rc != MPC_OK)
+    {
+        exit(EXIT_FAILURE);
+    }
+
+    printf("\nDone\n");
+}
diff --git a/examples/example_gg20_reshare.c b/examples/example_gg20_reshare.c
new file mode 100644
index 0000000..da717bc
--- /dev/null
+++ b/examples/example_gg20_reshare.c
@@ -0,0 +1,903 @@
+/*
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include "amcl/mta.h"
+#include "amcl/mpc.h"
+#include "amcl/mta_zkp.h"
+#include "amcl/nm_commitment.h"
+#include "amcl/gmr.h"
+#include "amcl/ggn.h"
+#include "amcl/schnorr.h"
+#include "amcl/gg20_zkp.h"
+#include "amcl/shamir.h"
+
+#define IDLEN 16
+
+/* Example of the resharing */
+
+// Safe primes for BC Setup
+int primes_len = 4;
+
+char *primes[] =
+{
+    "C421122418EF6FE4D4F14F0F03EABA927C20B1A22BCBE90EC227EFE34AC912095D389ADE615CF55C80874533F4270BB705ABFFDB6007FEF0B44B2DBF31EDA0D5F39523B5826F9854FBF733B98EF450E77DD8B5B15C4E3CE5C195F46E524C8BF6F0C9F6D86CE8642A8B9A0C79CA64A103AB76CD65261F97AED4C17C433CEA5DEF",
+    "ED7859031659B9A5AC011687A60444B19F5A73F31F9EE83D710F2FEAE1C4FED558A1C5C3842EA01DB86C6D07BE9971F8AA7820DD1E8BB8C9AE888319F0E03BDCD8D3DBEBF8A48765188C001A121F7E48D458E1E8A43684A861F0FBE87DC541A06CA98CECB6954F906A52C2B3D0978AE945A1EA2F9285978F76F01E99FD8B6EEF",
+    "D93E4899805ED36219F38C3030D6FF92012E2B41ADC38DFFFFDB110AEAA36D619A5CFD63B02711EA482941E20A3F89A36E2CAF0BD675B154FDE6D5A457BCBD337383EE65B33CDAB078EE8F8E36E55D22BB5DF75D14F570E529A4681B4947A4F5ECCC575763BD765FDE1038DEDF24BEF02BA9A1EA4C17ACA3A1B33D2FB7D974AB",
+    "E4481CEDDBDDDF6E980FBC825B004E52D028784CD3B8290D9810FD987AF2053C3F4056C3A354BFF55B9BB5867A819A22B71BC1069A310087E4FBF98FD291DBCC443AB910301B34A2DEE68D1365E77EDF9A0A21B3928C38046BC15AC338F7E38B9E4586E02655F98523CD041FBB51A358E505A5D1B0A161955B6AC60CB0E37707",
+    "F5F3BB1CEECD21110EFB4BC9CF0AA7AEBB98675A7567D6A1EA4E866FED4838F1B41D8232599718CD82F2936CD15198DC16ADD280C32D6860882704AEF397E1A956DB17E36AEB92D5CF76689DACC9CEFE418EF699C948CE680AFF878768CE8F4BB68F14AB5E8C38209E6C2C54125533B22960BBD350CF76C3B12BBC9FBAAAAA27",
+    "E8E1F9281CB8C10BC01B42197E834F648A5C8AE111F7DB40DD25A6F8896A703D0F84D36EB6D1FC048DC74FD3164742CA86607C81670199FC3F1BF5AB22F2B11E4E2434E757C0484A4162E26B75A0715167C5E8E293B7CEFD475FAA8B10F2324D78150E56B1186E257066D8860603FBCE59865FB0A25FB41014C1740C8EAA29AF",
+    "C3278DF1CD5330CD6DABE2FC9E32B9A560C32F7F140C601D2A5788F856A387531EFA695D728038F8CA2945D01C10A5DA823025BA27D7640E96593C031674380592AF4B8FE29A9C464FF41B1CACD47A4B255A5CA93E2F2A806AF00A67FB78A15D3ED8A37CEBA10CA7D0036412805AEBB88EC8A745F237AC01002D49C459EB2AB7",
+    "DCE9B24D4DE749296335C0F0DB421A330E21DF04C722ADDECC4B72448C387072C84CD7DB1146E1E07BE78585DEF4F1D5E15F53B0942CCA89B0E812B0F6653C7DA8ACB771593D4B2B37A28AD80DD7184698742C110F0506B86BF8A2A20E8975DF2D2A57930438B8528E63C3430DBFCE204712E8D40550E81DA03622953BEA2DFB",
+    "D09A3ECE562DD033EC2C562C2B0B4EEB0D2262FE046C030BAAFD7CBA8F73E9734E337D3551FC6B487CA359A84F598EC5EC6FDBA014A0A0009EF582B9F90DE90C0BA7F941648C4F3A8CF904974BA05E8C23EDA5895025441251B2CFC5A216568E702427DEA178D37BF3D28F1B35E17E58F5551511331961703F3D410924859107",
+    "C03136A1E1E5BA88568A19142F41E9FAC2E76A2D839B550038005E420008AF7D6D7C80EA8A31A936D39C93D2031B20845F23464371909EE589BF80E850C94B9F0FBF516C3DE362868C811505EE15B869844A54FFB32B0620A7FC5BA040898A91AA68657D8B43990166E5A5AF06828AE0F7C1D0EE333C2AF8DE7603F2F662792F",
+    "DF88593FBF2482954BAAA2A48C59E2FDF85936C282514FFB47F18B8D1484C7E8BE1862D0A84D5B753389A2BFBAFF63B03406AC29893B88911F8664E547A63CB58E9A941463D7946CF0909E24E7BD8EF11AFC4EEAFC8F3366DB0A9AB091325AC82C9BAE218B115F8700BAA1F478E194A927F1FBE3A3EF423BCFAE78850059B69B",
+    "D3AE06CD993690F64104D4ECBE6B2386693B766431B86E038CAE39EE81BD8A71387FBCB9D17B5BFAAFB883D68B005E228CD455A4BFF69843F948A9168D1F87545FCBB969260E07BDD44F10E79E7409DED45ADDF32BA1CF33F9B2F68758622FE660F4E47A651F6403D99E7B148768CDDBEC71EBE931D5A95B820B5A75BD495003",
+    "DAA27689A7D8F9B21106DBE472C324EB1CA899F58F0F72F336957312A8ECDB4EBC3B50C38D5A2E9C2D1E552C7EA8D89315DD9C5CA7F9EB99C41F7A857D44F420109FE17092799E60E3537FC9193056979E0FF886B36C2898F45F599E4C5CCDDF9A8EC8DA0D20A53A6849124E027D30D641E21E69FF374792534BD682FCDCA35B",
+    "FBF9D46697C40BCA51A759C47E360F2DD8B81B6241B0A3645645FAC692E9E8F3407EFB6F238AE91F9DEA49240D26E37904673F55E91927CDEA248FE1352B97B226AB159A1539747383B1168FE8CF1B1DF4CD9147053E3702AE491FBCA4CCE835B4B351DF44F5333C185275DB21B807D0BC180BF697EC07AB843E0FA595851A87",
+    "FD44B39DF09A18F215EB391D50D21CD5EAC8BE2E5CC901DF852DE85C93341F82633AAAD07C19863E0CD7861AEEE1C0B4B69275AA8DD2D33C0F5E048EA13E9A6D8E01B77FED72347D527BD7508D2F5EC18E5CB2B27D40BAB5C10A17123E75042F4047C3B1AEB6D36BF0F93BB214501ECBB8F95CC1A3A99219F6933763580CDA2F",
+    "C2442E9569C8999831594E818A159C8C0AF6F7ED2989358E8D9E01D6B8A0D354F5F97D9CEAB766AF12F3CC5C511FE19A587FF1E7029C8E500432D357D90E3EF042E4F308C325760D726BC9B1D78BA439FB0236D85DB301E548C4201B9E74D5832AD3ED06E37CD6DBFD9C23D194068DB1B9209813557FBC0714142AD6F6C56AA3",
+    "DC3B22CFF90690B10EC73C115FED0E3AD3FA01A68F8C8AA1905CA47008E8C4AF9D7922AE4D41794D8123D1768A3E0F8B35DA0001086ADC5EBB92640DD2514CBAD000283F7C5A6C340C040C09654A204C3947A22AC05F72E13C3EBDE61B9D281016E40C559474D33381C974767408EE9E108619AE96E4CC87EB11E39772BA00B3",
+    "C5E0280A5F1B358D16EDEF14540C3C9D468D4AEBC74C9DB605A2E4CEC9F27095A3FDE659E1E6C95FB4BB60533DD89E71D808A8C5EB5A8A51B9FED24F7AE9003FFD6F5401D991153C52002E7DB4F6766363B2CA77E9A113808E7C35713D188AD55CE25B9DB1308A08F3366523E425F77D924346078D8E0E9948674BAD88EA59B7",
+    "FC33DF361A7B1D3C3D1C06FBF3CCAD6C067B27FF28B61B1EFDB364FFFEE79993D9D10213A778A02C6C823DB101CB7C7A483B9F2B060BD1B7EDC13DB890B323AE02B7209DA66B3289069EE8C7747A6D7242194DC48DBDFFB740534A591AE2F41446B08F9966DA045FC9C3F9188F1EF1308509D50BC970314B6AA335EA2839993B",
+    "E63B5740DDB573CF1F0A72DAF3EA00D65CA2A538036D20078CC7E3BDC95529F1D13ABC182EBF8BE42CA87C0AEED4952C1D1FADC3C3C8A363F66FABCA012890FBC76C935B479B4F302F1DC12289D34F1F69EC2278045603F5FE532B0CD86E6261852F99517B6226F013B04DCE1D940DF7FB8BC8A799D153C1490A915A8342B77F"
+};
+
+/* Party related structures */
+typedef struct
+{
+    PAILLIER_private_key paillier_sk;
+    BIT_COMMITMENT_priv bc_sm;
+
+    octet *SKX; // X share of the full key (t,n) sharing
+    octet *SKY; // Y share of the full key (t,n) sharing
+} MPC_priv_key_material;
+
+typedef struct
+{
+    octet *PK;  // Full ECDSA PK
+    octet *SPK; // ECDSA PK associated to the player share
+
+    PAILLIER_public_key paillier_pk;
+    BIT_COMMITMENT_pub  bc_pm;
+} MPC_pub_key_material;
+
+typedef struct
+{
+    octet *ID;
+
+    MPC_priv_key_material skm;
+    MPC_pub_key_material  pkm;
+} MPC_player;
+
+typedef struct
+{
+    int t;
+    int n;
+
+    MPC_player *players;
+} MPC_party;
+
+/* Reshare related structures
+ *
+ * Note that these structures hold all the values
+ * generated in the round, even if they are not to be
+ * transmitted. The values to be transmitted and what channel
+ * to use are specified in the reshare functions
+ */
+
+typedef struct
+{
+    octet *R;   // Decommitment string
+    octet *C;   // Commitment string to PK
+} MPC_reshare_round1;
+
+typedef struct
+{
+    SSS_shares SHARES; // Shares for VSS
+    octet *CHECKS;     // Checks for VSS
+} MPC_reshare_round2;
+
+typedef struct
+{
+    octet *SCHNORR_C;
+    octet *SCHNORR_P;
+
+    GMR_proof Y;
+    BIT_COMMITMENT_setup_proof BCP;
+} MPC_reshare_round3;
+
+typedef struct
+{
+    octet *W;   // Secret additive share
+    octet *WG;  // Public Key associated with the additive share
+} MPC_reshare_additive_shares;
+
+typedef struct
+{
+    octet *ID;
+
+    MPC_party *old_party;
+    MPC_party *new_party;
+
+    MPC_reshare_additive_shares* shares;
+
+    MPC_reshare_round1 *round1;
+    MPC_reshare_round2 *round2;
+    MPC_reshare_round3 *round3;
+} MPC_reshare_session;
+
+// Utility functions
+void init_octets(char* mem, octet *OCTETS, int max, int n)
+{
+    int i = 0;
+
+    for (i = 0; i < n; i++)
+    {
+        OCTETS[i].val = mem + (i*max);
+        OCTETS[i].len = 0;
+        OCTETS[i].max = max;
+    }
+}
+
+/* DEMO ONLY
+ * Trusted Key Setup for old party. This generates the SSS shares
+ * with a trusted dealer to have the starting setup. In a real
+ * world scenario this would have been set up with a proper
+ * trustless Keygen
+ */
+int trusted_key_setup(csprng *RNG, MPC_party *p)
+{
+    int i, n, rc;
+
+    n = p->n;
+
+    ECP_SECP256K1 ECP;
+
+    char sk[EGS_SECP256K1];
+    octet SK = {0, sizeof(sk), sk};
+
+    char pk[2 * EFS_SECP256K1 + 1];
+    octet PK = {0, sizeof(pk), pk};
+
+    char skx[n][EGS_SECP256K1];
+    char sky[n][EGS_SECP256K1];
+    octet SKX[n];
+    octet SKY[n];
+
+    init_octets((char *)skx, SKX, EGS_SECP256K1, n);
+    init_octets((char *)sky, SKY, EGS_SECP256K1, n);
+
+    SSS_shares shares = {SKX, SKY};
+
+    // Generate ECDSA Key Pair
+    printf("\t[Dealer] Generate ECDSA key pair\n");
+
+    MPC_ECDSA_KEY_PAIR_GENERATE(RNG, &SK, &PK);
+    rc = ECP_SECP256K1_PUBLIC_KEY_VALIDATE(&PK);
+    if (rc != 0)
+    {
+        printf("\t\tError generating ECDSA key pair. rc %d\n", rc);
+        return rc;
+    }
+
+    // Generate shares
+    SSS_make_shares(p->t, n, RNG, &shares, &SK);
+
+    for(i = 0; i < n; i++)
+    {
+        OCT_copy(p->players[i].skm.SKX, SKX+i);
+        OCT_copy(p->players[i].skm.SKY, SKY+i);
+    }
+
+    // Convert PK to compressed form
+    ECP_SECP256K1_fromOctet(&ECP, &PK);
+    ECP_SECP256K1_toOctet(p->players[0].pkm.PK, &ECP, true);
+
+    for (i = 1; i < n; i++)
+    {
+        OCT_copy(p->players[i].pkm.PK, p->players[0].pkm.PK);
+    }
+
+    return MPC_OK;
+}
+
+/* *** Resharing functions *** */
+
+/* Reshare - Round 1
+ *
+ * The old party converts their SSS shares to additive shares
+ * and commit to the equivalent public keys.
+ */
+void MPC_reshare_round1_commit(csprng *RNG, MPC_reshare_session *s, int i)
+{
+    int j, k, oldt;
+
+    oldt = s->old_party->t;
+
+    char x[oldt-1][EGS_SECP256K1];
+    octet X[oldt-1];
+
+    init_octets((char *) x, X, EGS_SECP256K1, oldt-1);
+
+    MPC_player *p;
+    MPC_reshare_round1 *r;
+    MPC_reshare_additive_shares *sh;
+
+    p = s->old_party->players + i;
+    r = s->round1 + i;
+    sh = s->shares + i;
+
+    printf("\t[Old Player %d] Convert Shamir Share to additive\n", i);
+
+    k = 0;
+    for (j = 0; j < oldt; j++)
+    {
+        if (i == j) continue; // Do not include own shares in computation
+
+        // This looks like we are accessing the secret key material,
+        // but it is the X component of the Shamir Share, which
+        // is not secret
+        OCT_copy(X + k, s->old_party->players[j].skm.SKX);
+        k++;
+    }
+
+    SSS_shamir_to_additive(oldt, p->skm.SKX, p->skm.SKY, X, sh->W);
+
+    /* TODO This should not be stored here
+     *
+     * This should be computed by each player for all players
+     * using the same Lagrange coefficient above and the stored
+     * xi.G from the original keygen
+     */
+    BIG_256_56 w;
+    ECP_SECP256K1 G;
+    ECP_SECP256K1_generator(&G);
+    BIG_256_56_fromBytesLen(w, sh->W->val, sh->W->len);
+    ECP_SECP256K1_mul(&G, w);
+    ECP_SECP256K1_toOctet(sh->WG, &G, true);
+
+    // Commit to the ECDSA public key
+    printf("\t[Old Player %d] Commit to additive share PK\n", i);
+
+    NM_COMMITMENT_commit(RNG, sh->WG, r->R, r->C);
+
+    printf("\t[Old Player %d] Broadcast commitment C\n", i);
+}
+
+/* Reshare - Round 2 - Generate VSS Shares
+ *
+ * Generate the (newt, newn) VSS shares for the old party additive shares.
+ */
+void MPC_reshare_round2_vss(csprng *RNG, MPC_reshare_session *s, int i)
+{
+    int newt, newn;
+
+    newt = s->new_party->t;
+    newn = s->new_party->n;
+
+    MPC_reshare_round2 *r;
+    MPC_reshare_additive_shares *sh;
+
+    r  = s->round2 + i;
+    sh = s->shares + i;
+
+    printf("\t[Old Player %d] Generate VSS Shares for additive share\n", i);
+
+    VSS_make_shares(newt, newn, RNG, &r->SHARES, r->CHECKS, sh->W);
+
+    printf("\t[Old Player %d] Broadcast Checks and decommitment string.\n", i);
+    printf("\t[Old Player %d] Transmit shares with point2point channel\n", i);
+}
+
+/* Reshare - Round 2 - Compose New Party shares
+ *
+ * Once the shares and decommitments are received they can be
+ * verified and summed to compute the full key share for the player.
+ * Moreover, the full public key can be computed by adding all the
+ * free terms in the exponents from the checks.
+ *
+ * This is equivalent to the Keygen Round 2 and the same parallelisation
+ * observation applies.
+ */
+int MPC_reshare_round2_compose(MPC_reshare_session *s, int i)
+{
+    int j, oldt, rc;
+
+    oldt = s->old_party->t;
+
+    char ws[oldt][EFS_SECP256K1 + 1];
+    octet WS[oldt];
+
+    init_octets((char *)ws, WS, EFS_SECP256K1 + 1, oldt);
+
+    MPC_player *p;
+    MPC_reshare_round1 *r1;
+    MPC_reshare_round2 *r2;
+
+    printf("\t[New Player %d] Verify Shares\n", i);
+
+    /* Decommit Free term in the exponent and verify shares */
+    for (j = 0; j < oldt; j++)
+    {
+        p = s->old_party->players + j;
+        r1 = s->round1 + j;
+        r2 = s->round2 + j;
+
+        // Decommit free term in the exponent
+        rc = NM_COMMITMENT_decommit(r2->CHECKS + 0, r1->R, r1->C);
+        if (rc != NM_COMMITMENT_OK)
+        {
+            printf("\t\tInvalid Commitment for Old Player %d. rc %d\n", j, rc);
+            return rc;
+        }
+
+        // Check all the shares are for the same player
+        if (!OCT_comp(r2->SHARES.X+i, s->round2->SHARES.X+i))
+        {
+            printf("\t\tInvalid X share from Old Player %d.\n", j);
+            return MPC_FAIL;
+        }
+
+        // VSS Verification for the received share
+        rc = VSS_verify_shares(s->new_party->t, r2->SHARES.X+i, r2->SHARES.Y+i, r2->CHECKS);
+        if (rc != VSS_OK)
+        {
+            printf("\t\tInvalid Shares from Old Player %d. rc %d\n", j, rc);
+            return MPC_FAIL;
+        }
+    }
+
+    /* Compose Public Key */
+
+    printf("\t[New Player %d] Compose full PK\n", i);
+
+    p = s->new_party->players + i;
+
+    for (j = 0; j < oldt; j++)
+    {
+        OCT_copy(WS+j, s->round2[j].CHECKS + 0);
+    }
+
+    rc = MPC_SUM_ECPS(p->pkm.PK, WS, oldt);
+    if (rc != MPC_OK)
+    {
+        printf("\t\tInvalid format for PK Shares from Player %d. rc %d\n", i, rc);
+        return rc;
+    }
+
+    printf("\t[New Player %d] Verify the public key is still the same\n", i);
+
+    if (!OCT_comp(s->old_party->players->pkm.PK, p->pkm.PK))
+    {
+        printf("\t\tNew Public Key does not match\n");
+        return MPC_FAIL;
+    }
+
+    /* Compose Shares */
+
+    printf("\t[New Player %d] Combine full share\n", i);
+
+    for (j = 0; j < oldt; j++)
+    {
+        OCT_copy(WS+j, s->round2[j].SHARES.Y + i);
+    }
+
+    MPC_SUM_BIGS(p->skm.SKY, WS, oldt);
+
+    OCT_copy(p->skm.SKX, s->round2->SHARES.X+i);
+
+    /* TODO This should not be stored here
+     *
+     * This should be computed by each player for all players
+     */
+    BIG_256_56 w;
+    ECP_SECP256K1 G;
+    ECP_SECP256K1_generator(&G);
+    BIG_256_56_fromBytesLen(w, p->skm.SKY->val, p->skm.SKY->len);
+    ECP_SECP256K1_mul(&G, w);
+    ECP_SECP256K1_toOctet(p->pkm.SPK, &G, true);
+
+    return MPC_OK;
+}
+
+/* Reshare - Round 3 - Generate additional key material
+ *
+ * Generate additional key material: Paillier Keypair and BC modulus
+ * Generate a Schnorr Proof of knowledge of the secret share
+ * Generate a Square-Freeness proof for the Paillier Keys
+ * Generate a proof of well formedness for the ZKP modulus N, b0, b1
+ */
+void MPC_reshare_round3_proofs(csprng *RNG, MPC_reshare_session *s, int i)
+{
+    char oct1[HFS_2048];
+    octet OCT1 = {0, sizeof(oct1), oct1};
+    char oct2[HFS_2048];
+    octet OCT2 = {0, sizeof(oct2), oct2};
+
+    char rv[EGS_SECP256K1];
+    octet RV = {0, sizeof(rv), rv};
+
+    char e[EGS_SECP256K1];
+    octet E = {0, sizeof(e), e};
+
+    MODULUS_priv m;
+
+    MPC_player *p;
+    MPC_reshare_round3 *r;
+
+    p = s->new_party->players + i;
+    r = s->round3 + i;
+
+    // Generate Paillier Key pair
+    printf("\t[New Player %d] Generate Paillier key pair\n", i);
+
+    PAILLIER_KEY_PAIR(RNG, NULL, NULL, &p->pkm.paillier_pk, &p->skm.paillier_sk);
+
+    // Load Primes for BC setup
+    OCT_fromHex(&OCT1, primes[(2 * i) % primes_len]);
+    OCT_fromHex(&OCT2, primes[(2 * i + 1) % primes_len]);
+
+    // Generate BC modulus
+    printf("\t[New Player %d] Generate BC modulus\n", i);
+
+    BIT_COMMITMENT_setup(RNG, &p->skm.bc_sm, &OCT1, &OCT2, NULL, NULL);
+    BIT_COMMITMENT_priv_to_pub(&p->pkm.bc_pm, &p->skm.bc_sm);
+
+    /* Prove knowledge of DLOG PK = s.G */
+    printf("\t[New Player %d] Prove knowledge of secret key\n", i);
+
+    SCHNORR_commit(RNG, &RV, r->SCHNORR_C);
+    SCHNORR_challenge(p->pkm.SPK, r->SCHNORR_C, p->ID, s->ID, &E);
+    SCHNORR_prove(&RV, &E, p->skm.SKY, r->SCHNORR_P);
+
+    OCT_clear(&RV);
+
+    /* Prove Square Freeness of the Paillier modulus */
+    printf("\t[New Player %d] Prove Square-Freeness of Paillier modulus\n", i);
+
+    FF_2048_toOctet(&OCT1, p->skm.paillier_sk.p, HFLEN_2048);
+    FF_2048_toOctet(&OCT2, p->skm.paillier_sk.q, HFLEN_2048);
+    MODULUS_fromOctets(&m, &OCT1, &OCT2);
+
+    GMR_prove(&m, p->ID, s->ID, r->Y);
+
+    OCT_clear(&OCT1);
+    OCT_clear(&OCT2);
+    MODULUS_kill(&m);
+
+    /* Prove well formedness of the BC modulus */
+    printf("\t[New Player %d] Prove Well formedness of BC modulus\n", i);
+
+    BIT_COMMITMENT_setup_prove(RNG, &p->skm.bc_sm, &r->BCP, p->ID, s->ID);
+
+    printf("\t[New Player %d] Broadcast Public Key material, GMR Proof Y and BC proof values\n", i);
+}
+
+/* Reshare - Round 3 - Verify Key Material
+ *
+ * Verify the Square-Freeness proof for the paillier PK
+ * Verify the proof of well formedness for the BC modulus
+ *
+ * This is equivalent to the verification of Round 3 of the Keygen,
+ * without the Schnorr Proof. The same observation on parallelisation
+ * applies.
+ */
+int MPC_reshare_round3_verify(MPC_reshare_session *s, int i)
+{
+    int j, n, rc;
+
+    char e[EGS_SECP256K1];
+    octet E = {0, sizeof(e), e};
+
+    char mn[FS_2048];
+    octet MN = {0, sizeof(mn), mn};
+
+    MPC_reshare_round3 *r;
+    MPC_player *p;
+
+    n = s->new_party->n;
+
+    printf("\t[New Player %d] Verify key material ZKP\n", i);
+
+    for (j = 0; j < n; j++)
+    {
+        if(j == i) continue; // Trust ourselves
+
+        // Load appropriate player and round communications
+        r = s->round3 + j;
+        p = s->new_party->players + j;
+
+        /* Verify Schnorr Proof */
+        SCHNORR_challenge(p->pkm.SPK, r->SCHNORR_C, p->ID, s->ID, &E);
+        rc = SCHNORR_verify(p->pkm.SPK, r->SCHNORR_C, &E, r->SCHNORR_P);
+        if (rc != SCHNORR_OK)
+        {
+            printf("\t\tInvalid Schnorr Proof for Player %d. rc %d\n", j, rc);
+            return rc;
+        }
+
+        /* Verify GMR proof of Square-Freeness */
+        PAILLIER_PK_toOctet(&MN, &p->pkm.paillier_pk);
+        rc = GMR_verify(&MN, r->Y, p->ID, s->ID);
+        if (rc != GMR_OK)
+        {
+            printf("\t\tInvalid GMR Proof for New Player %d. rc %d\n", j, rc);
+            return rc;
+        }
+
+        /* Verify well formedness of BC modulus */
+        rc = BIT_COMMITMENT_setup_verify(&p->pkm.bc_pm, &r->BCP, p->ID, s->ID);
+        if (rc != BIT_COMMITMENT_OK)
+        {
+            printf("\t\tInvalid BC Proof for New Player %d. rc %d\n", j, rc);
+            return rc;
+        }
+    }
+
+    printf("\t[New Player %d] Broadcast Success\n", i);
+
+    return MPC_OK;
+}
+
+/* Reshare - Orchestrate the Key Setup for all players
+ *
+ * Step 1.  The Old Party Players convert their SSS shares to additive shares
+ * Step 1A. The Old Party Players commit to the equivalent PK for the additive shares
+ * Step 2.  The Old Party Players generate VSS shares and checks for the additive shares
+ * Step 2A. The New Party Players combine the shares and checks into their new SSS share and full PK
+ * Step 2B. The New Party Players verify that the full PK is unchanged
+ * Step 3.  The New Party Players generate the additional key material and proofs for it
+ * Step 3A. The New Party Players verify the additional key material proofs.
+ * Step 3B. The New Party Players broadcast their success
+ * Step 3C. The Old Party Players delete the old key material
+ */
+int reshare(csprng *RNG, MPC_party *old_p, MPC_party *new_p)
+{
+    int i, oldt, newt, newn, rc;
+
+    oldt = old_p->t;
+    newn = new_p->n;
+    newt = new_p->t;
+
+    /* Setup Keygen memory */
+
+    // Reshare Round1 memory
+    char round1_r[oldt][EGS_SECP256K1];
+    char round1_c[oldt][EGS_SECP256K1];
+    octet ROUND1_R[oldt];
+    octet ROUND1_C[oldt];
+
+    init_octets((char *)round1_r,  ROUND1_R,  EGS_SECP256K1, oldt);
+    init_octets((char *)round1_c,  ROUND1_C,  EGS_SECP256K1, oldt);
+
+    MPC_reshare_round1 r1[oldt];
+
+    for (i = 0; i < oldt; i++)
+    {
+        r1[i].C = ROUND1_C + i;
+        r1[i].R = ROUND1_R + i;
+    }
+
+    // Reshare Round2 memory
+    char round2_shares_x[oldt][newn][EGS_SECP256K1];
+    char round2_shares_y[oldt][newn][EGS_SECP256K1];
+    char round2_checks[oldt][newt][EFS_SECP256K1 + 1];
+
+    octet ROUND2_SHARES_X[oldt * newn];
+    octet ROUND2_SHARES_Y[oldt * newn];
+    octet ROUND2_CHECKS[oldt * newt];
+
+    init_octets((char *)round2_shares_x, ROUND2_SHARES_X, EGS_SECP256K1,     oldt * newn);
+    init_octets((char *)round2_shares_y, ROUND2_SHARES_Y, EGS_SECP256K1,     oldt * newn);
+    init_octets((char *)round2_checks,   ROUND2_CHECKS,   EFS_SECP256K1 + 1, oldt * newt);
+
+    MPC_reshare_round2 r2[oldt];
+
+    for (i = 0; i < oldt; i++)
+    {
+        r2[i].SHARES.X  = ROUND2_SHARES_X + (newn * i);
+        r2[i].SHARES.Y  = ROUND2_SHARES_Y + (newn * i);
+        r2[i].CHECKS    = ROUND2_CHECKS + (newt * i);
+    }
+
+    // Reshare Round3 memory
+    char round3_schnorr_c[newn][EFS_SECP256K1 + 1];
+    char round3_schnorr_p[newn][EGS_SECP256K1];
+    octet ROUND3_SCHNORR_C[newn];
+    octet ROUND3_SCHNORR_P[newn];
+
+    init_octets((char *)round3_schnorr_c, ROUND3_SCHNORR_C, EFS_SECP256K1 + 1, newn);
+    init_octets((char *)round3_schnorr_p, ROUND3_SCHNORR_P, EGS_SECP256K1,     newn);
+
+    MPC_reshare_round3 r3[newn];
+
+    for (i = 0; i < newn; i++)
+    {
+        r3[i].SCHNORR_C = ROUND3_SCHNORR_C + i;
+        r3[i].SCHNORR_P = ROUND3_SCHNORR_P + i;
+    }
+
+    // Keygen Session memory
+    char id[IDLEN];
+    octet ID = {0, sizeof(id), id};
+
+    char as_w[oldt][EGS_SECP256K1];
+    char as_wg[oldt][EFS_SECP256K1 + 1];
+
+    octet AS_W[oldt];
+    octet AS_WG[oldt];
+
+    init_octets((char *)as_w,  AS_W,  EGS_SECP256K1,     oldt);
+    init_octets((char *)as_wg, AS_WG, EFS_SECP256K1 + 1, oldt);
+
+    MPC_reshare_additive_shares shares[oldt];
+
+    for (i = 0; i < oldt; i++)
+    {
+        shares[i].W  = AS_W + i;
+        shares[i].WG = AS_WG + i;
+    }
+
+    MPC_reshare_session s;
+
+    s.ID        = &ID;
+    s.shares    = shares;
+    s.old_party = old_p;
+    s.new_party = new_p;
+    s.round1    = r1;
+    s.round2    = r2;
+    s.round3    = r3;
+
+    /* Agree on session ID for keygen */
+    OCT_rand(s.ID, RNG, s.ID->max);
+
+    printf("\n *** Keygen ***\n");
+
+    /* Round 1 - Commit to old PK shares */
+
+    printf("\nRound 1 - Old party - Commit to old PK shares\n");
+
+    for (i = 0; i < oldt; i++)
+    {
+        MPC_reshare_round1_commit(RNG, &s, i);
+        printf("\n");
+    }
+
+    /* Round 2 - Old Party - Compute VSS shares and checks */
+
+    printf("\nRound 2 - Old Party - Generate Schnorr Proof, compute VSS Shares and Checks\n");
+
+    for (i = 0; i < oldt; i++)
+    {
+        MPC_reshare_round2_vss(RNG, &s, i);
+
+        printf("\n");
+    }
+
+    /* Round 2 - New Party - Verify VSS Shares and combine them */
+
+    printf("\nRound 2 - New Party - Combine VSS Shares and check Schnorr Proof\n");
+
+    for (i = 0; i < newn; i++)
+    {
+        rc = MPC_reshare_round2_compose(&s, i);
+        if (rc != MPC_OK)
+        {
+            return rc;
+        }
+
+        printf("\n");
+    }
+
+    /* Round 3 - New Party - Generate Proofs for Key Material */
+
+    printf("\nRound 3 - New Party - Generate additional key material and Proofs\n");
+
+    for (i = 0; i < newn; i++)
+    {
+        MPC_reshare_round3_proofs(RNG, &s, i);
+        printf("\n");
+    }
+
+    /* Round 3 - New Party - Verify Proofs for Key Material */
+
+    printf("\n\nRound 3 - New Party - Verify Proofs for Key Material\n");
+
+    for (i = 0; i < newn; i++)
+    {
+        rc = MPC_reshare_round3_verify(&s, i);
+        if (rc != MPC_OK)
+        {
+            return rc;
+        }
+
+        printf("\n");
+    }
+
+    /* The old party deletes its key material
+     *
+     * All the material in the player skm must be cleaned, except
+     * for the X share, which may be left alone.
+     *
+     * Not doing it here so the resharing can be verified manually
+     * in the main
+     */
+    printf("\nThe old party can now delete the old key material\n");
+
+    return MPC_OK;
+}
+
+void usage(char *name)
+{
+    printf("Usage: %s t n t1 n2\n", name);
+    printf("Run a resharing from a (t, n) to a (t1, n1)\n");
+    printf("\n");
+    printf("  t    Old threshold. 2 <= t <= n\n");
+    printf("  n    Old number of participants. t <= n\n");
+    printf("  t1   New threshold. 2 <= t1 <= n\n");
+    printf("  n1   New number of participants. t1 <= n\n");
+    printf("\n");
+    printf("Example:\n");
+    printf("  %s 3 4 5 6\n", name);
+}
+
+int main(int argc, char *argv[])
+{
+    int i, t, n, t1, n1, rc;
+
+    /* Read arguments */
+    if (argc != 5)
+    {
+        usage(argv[0]);
+        exit(EXIT_FAILURE);
+    }
+
+    t = atoi(argv[1]);
+    n = atoi(argv[2]);
+
+    if (t < 2 || n < 2 || t > n)
+    {
+        usage(argv[0]);
+        exit(EXIT_FAILURE);
+    }
+
+    t1 = atoi(argv[3]);
+    n1 = atoi(argv[4]);
+
+    if (t1 < 2 || n1 < 2 || t1 > n1)
+    {
+        usage(argv[0]);
+        exit(EXIT_FAILURE);
+    }
+
+    /* Memory setup */
+
+    // Old Party
+    char old_player_ids[n][IDLEN];
+    char old_player_pks[n][EFS_SECP256K1 + 1];
+    char old_player_skx[n][EGS_SECP256K1];
+    char old_player_sky[n][EGS_SECP256K1];
+    octet OLD_PLAYER_IDS[n];
+    octet OLD_PLAYER_PKS[n];
+    octet OLD_PLAYER_SKX[n];
+    octet OLD_PLAYER_SKY[n];
+
+    init_octets((char *)old_player_ids, OLD_PLAYER_IDS, IDLEN,             n);
+    init_octets((char *)old_player_pks, OLD_PLAYER_PKS, EFS_SECP256K1 + 1, n);
+    init_octets((char *)old_player_skx, OLD_PLAYER_SKX, EGS_SECP256K1,     n);
+    init_octets((char *)old_player_sky, OLD_PLAYER_SKY, EGS_SECP256K1,     n);
+
+    MPC_player old_players[n];
+
+    for (i = 0; i < n; i++)
+    {
+        old_players[i].ID      = OLD_PLAYER_IDS + i;
+        old_players[i].pkm.PK  = OLD_PLAYER_PKS + i;
+        old_players[i].skm.SKX = OLD_PLAYER_SKX + i;
+        old_players[i].skm.SKY = OLD_PLAYER_SKY + i;
+    }
+
+    MPC_party old_p = {t, n, old_players};
+
+    // New Party
+
+    char new_player_ids[n1][IDLEN];
+    char new_player_pks[n1][EFS_SECP256K1 + 1];
+    char new_player_spks[n1][EFS_SECP256K1 + 1];
+    char new_player_skx[n1][EGS_SECP256K1];
+    char new_player_sky[n1][EGS_SECP256K1];
+    octet NEW_PLAYER_IDS[n1];
+    octet NEW_PLAYER_PKS[n1];
+    octet NEW_PLAYER_SPKS[n1];
+    octet NEW_PLAYER_SKX[n1];
+    octet NEW_PLAYER_SKY[n1];
+
+    init_octets((char *)new_player_ids,  NEW_PLAYER_IDS,  IDLEN,             n1);
+    init_octets((char *)new_player_pks,  NEW_PLAYER_PKS,  EFS_SECP256K1 + 1, n1);
+    init_octets((char *)new_player_spks, NEW_PLAYER_SPKS, EFS_SECP256K1 + 1, n1);
+    init_octets((char *)new_player_skx,  NEW_PLAYER_SKX,  EGS_SECP256K1,     n1);
+    init_octets((char *)new_player_sky,  NEW_PLAYER_SKY,  EGS_SECP256K1,     n1);
+
+    MPC_player new_players[n1];
+
+    for (i = 0; i < n1; i++)
+    {
+        new_players[i].ID      = NEW_PLAYER_IDS + i;
+        new_players[i].pkm.PK  = NEW_PLAYER_PKS + i;
+        new_players[i].pkm.SPK = NEW_PLAYER_SPKS + i;
+        new_players[i].skm.SKX = NEW_PLAYER_SKX + i;
+        new_players[i].skm.SKY = NEW_PLAYER_SKY + i;
+    }
+
+    MPC_party new_p = {t1, n1, new_players};
+
+    // Deterministic RNG for example
+    char seed[32] = {0};
+    csprng RNG;
+    RAND_seed(&RNG, 32, seed);
+
+    // Assign IDs to players
+    for (i = 0; i < n; i++)
+    {
+        OCT_rand(OLD_PLAYER_IDS+i, &RNG, IDLEN);
+    }
+
+    for (i = 0; i < n1; i++)
+    {
+        OCT_rand(NEW_PLAYER_IDS+i, &RNG, IDLEN);
+    }
+
+    printf("MPC resharing example\n");
+
+    // Minimal Key Setup for old party
+    rc = trusted_key_setup(&RNG, &old_p);
+    if (rc != MPC_OK)
+    {
+        exit(EXIT_FAILURE);
+    }
+
+    // Resharing
+    rc = reshare(&RNG, &old_p, &new_p);
+    if (rc != MPC_OK)
+    {
+        exit(EXIT_FAILURE);
+    }
+
+    // Check the full SK is the same
+    char old_sk[EGS_SECP256K1];
+    char new_sk[EGS_SECP256K1];
+    octet OLD_SK = {0, sizeof(old_sk), old_sk};
+    octet NEW_SK = {0, sizeof(new_sk), new_sk};
+
+    SSS_shares old_shares = {OLD_PLAYER_SKX, OLD_PLAYER_SKY};
+    SSS_shares new_shares = {NEW_PLAYER_SKX, NEW_PLAYER_SKY};
+
+    SSS_recover_secret(t,  &old_shares, &OLD_SK);
+    SSS_recover_secret(t1, &new_shares, &NEW_SK);
+
+    if (!OCT_comp(&OLD_SK, &NEW_SK))
+    {
+        printf("ERROR Old Key does not match New Key\n");
+        exit(EXIT_FAILURE);
+    }
+
+    printf("\nDone\n");
+}
diff --git a/examples/example_gg20_zkp_phase3.c b/examples/example_gg20_zkp_phase3.c
new file mode 100644
index 0000000..0e882f0
--- /dev/null
+++ b/examples/example_gg20_zkp_phase3.c
@@ -0,0 +1,137 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+#include "amcl/gg20_zkp.h"
+
+/* Example of GG20 Phase 3 ZKP */
+
+char *S_hex = "00f1f45c44eb4298562677dfc945064ac5d45d683ec2d87efbd2f527bb5a768c";
+char *L_hex = "ab5aa1e7740f849b974fcaaa98840d828a42b16dd59be32f39e3c637730ee9e4";
+
+char *V_hex = "02879452f0c552b01c2cc91101062ca02a1ff3eab1e9c18873992670198bf54f3e";
+
+int main()
+{
+    int rc;
+
+    GG20_ZKP_rv    r;
+    GG20_ZKP_proof p;
+
+    char id[32];
+    octet ID = {0, sizeof(id), id};
+
+    char ad[32];
+    octet AD = {0, sizeof(ad), ad};
+
+    char s[GGS_SECP256K1];
+    octet S = {0, sizeof(s), s};
+
+    char l[GGS_SECP256K1];
+    octet L = {0, sizeof(l), l};
+
+    char v[GFS_SECP256K1+1];
+    octet V = {0, sizeof(v), v};
+
+    char c[GFS_SECP256K1+1];
+    octet C = {0, sizeof(c), c};
+
+    char e[GGS_SECP256K1];
+    octet E = {0, sizeof(e), e};
+
+    char t[GGS_SECP256K1];
+    octet T = {0, sizeof(t), t};
+
+    char u[GGS_SECP256K1];
+    octet U = {0, sizeof(u), u};
+
+    // Deterministic RNG for testing
+    char seed[32] = {0};
+    csprng RNG;
+    RAND_seed(&RNG, 32, seed);
+
+    // Generate ID and AD
+    OCT_rand(&ID, &RNG, ID.len);
+    OCT_rand(&AD, &RNG, AD.len);
+
+    // Load hex values
+    OCT_fromHex(&S, S_hex);
+    OCT_fromHex(&L, L_hex);
+    OCT_fromHex(&V, V_hex);
+
+    printf("Prove knowledge of s, l s.t V = s.G + l.H\n");
+    printf("\tS = ");
+    OCT_output(&S);
+    printf("\tL = ");
+    OCT_output(&L);
+    printf("\tV = ");
+    OCT_output(&V);
+
+    // Commitment Phase
+    GG20_ZKP_phase3_commit(&RNG, &r, &C);
+
+    printf("\n[Alice] Compute commitment");
+    printf("\n\t\tA = ");
+    BIG_256_56_output(r.a);
+    printf("\n\t\tB = ");
+    BIG_256_56_output(r.b);
+    printf("\n\t\tC = ");
+    OCT_output(&C);
+
+    GG20_ZKP_phase3_challenge(&V, &C, &ID, &AD, &E);
+
+    printf("\n[Alice] Comupte pseudo random challenge");
+    printf("\n\t\tE = ");
+    OCT_output(&E);
+
+    // Proof Phase
+    GG20_ZKP_phase3_prove(&r, &E, &S, &L, &p);
+    GG20_ZKP_proof_toOctets(&T, &U, &p);
+
+    printf("\n[Alice] Compute proof and export it to octets for transmission");
+    printf("\n\t\tT = ");
+    OCT_output(&T);
+    printf("\t\tU = ");
+    OCT_output(&U);
+
+    // Clean random values used for proof
+    GG20_ZKP_rv_kill(&r);
+
+    // Verification Phase - compute pseudorandom challenge and verify proof
+    GG20_ZKP_phase3_challenge(&V, &C, &ID, &AD, &E);
+
+    printf("\n[Bob  ] Compute pseudo random challenge");
+    printf("\n\t\tE = ");
+    OCT_output(&E);
+
+    rc = GG20_ZKP_phase3_verify(&V, &C, &E, &p);
+
+    printf("\n[Bob  ] Verify proof\n");
+
+    if (rc == GG20_ZKP_OK)
+    {
+        printf("Success!\n");
+    }
+    else
+    {
+        printf("Failure!\n");
+        exit(EXIT_FAILURE);
+    }
+
+    exit(EXIT_SUCCESS);
+}
\ No newline at end of file
diff --git a/examples/example_gg20_zkp_phase6.c b/examples/example_gg20_zkp_phase6.c
new file mode 100644
index 0000000..1dee659
--- /dev/null
+++ b/examples/example_gg20_zkp_phase6.c
@@ -0,0 +1,165 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+#include "amcl/gg20_zkp.h"
+
+/* Example of GG20 Phase 6 ZKP */
+
+char *S_hex = "843b282505357e075bd98104f42fe7ea6b41310da7c769b4c402442c1ede922b";
+char *L_hex = "584edf9db99551ff2e0d56218a44fea0943032f7864b8359c213ec36465512c5";
+
+char *ECPR_hex = "03e03cda61f087f9ba381695dc816a4ca42f38bbfc3fc88ffe897594b94ee7b80b";
+char *ECPT_hex = "02863528287942ab88dec016c2e1993bf9e459ffcbfcc48c25ef68f2ec750e55a8";
+char *ECPS_hex = "02ef03c8ecb7cf65b58d85f368c5fc2725b4e4fe93306f98cf53f8e1531cea2bc4";
+
+int main()
+{
+    int rc;
+
+    GG20_ZKP_rv                r;
+    GG20_ZKP_phase6_commitment c;
+    GG20_ZKP_proof             p;
+
+    char id[32];
+    octet ID = {0, sizeof(id), id};
+
+    char ad[32];
+    octet AD = {0, sizeof(ad), ad};
+
+    char s[GGS_SECP256K1];
+    octet S = {0, sizeof(s), s};
+
+    char l[GGS_SECP256K1];
+    octet L = {0, sizeof(l), l};
+
+    char ecpr[GFS_SECP256K1+1];
+    octet ECPR = {0, sizeof(ecpr), ecpr};
+
+    char ecpt[GFS_SECP256K1+1];
+    octet ECPT = {0, sizeof(ecpt), ecpt};
+
+    char ecps[GFS_SECP256K1+1];
+    octet ECPS = {0, sizeof(ecps), ecps};
+
+    char alpha[GFS_SECP256K1+1];
+    octet ALPHA = {0, sizeof(alpha), alpha};
+
+    char beta[GFS_SECP256K1+1];
+    octet BETA = {0, sizeof(beta), beta};
+
+    char e[GGS_SECP256K1];
+    octet E = {0, sizeof(e), e};
+
+    char t[GGS_SECP256K1];
+    octet T = {0, sizeof(t), t};
+
+    char u[GGS_SECP256K1];
+    octet U = {0, sizeof(u), u};
+
+    // Deterministic RNG for testing
+    char seed[32] = {0};
+    csprng RNG;
+    RAND_seed(&RNG, 32, seed);
+
+    // Generate ID and AD
+    OCT_rand(&ID, &RNG, ID.len);
+    OCT_rand(&AD, &RNG, AD.len);
+
+    // Load hex values
+    OCT_fromHex(&S, S_hex);
+    OCT_fromHex(&L, L_hex);
+
+    OCT_fromHex(&ECPR, ECPR_hex);
+    OCT_fromHex(&ECPT, ECPT_hex);
+    OCT_fromHex(&ECPS, ECPS_hex);
+
+    printf("Prove knowledge of s, l s.t V = s.G + l.H, S = s.R\n");
+    printf("\tS    = ");
+    OCT_output(&S);
+    printf("\tL    = ");
+    OCT_output(&L);
+    printf("\tECPR = ");
+    OCT_output(&ECPR);
+    printf("\tECPT = ");
+    OCT_output(&ECPT);
+    printf("\tECPS = ");
+    OCT_output(&ECPS);
+
+    // Commitment Phase
+    rc = GG20_ZKP_phase6_commit(&RNG, &ECPR, &r, &c);
+    if (rc != GG20_ZKP_OK)
+    {
+        printf("FAILURE Invalid R\n");
+        exit(EXIT_FAILURE);
+    }
+
+    GG20_ZKP_phase6_commitment_toOctets(&ALPHA, &BETA, &c);
+
+    printf("\n[Alice] Compute commitment and export it to octets for transmission");
+    printf("\n\t\tA     = ");
+    BIG_256_56_output(r.a);
+    printf("\n\t\tB     = ");
+    BIG_256_56_output(r.b);
+    printf("\n\t\tALPHA = ");
+    OCT_output(&ALPHA);
+    printf("\t\tBETA  = ");
+    OCT_output(&BETA);
+
+    GG20_ZKP_phase6_challenge(&ECPR, &ECPT, &ECPS, &c, &ID, &AD, &E);
+
+    printf("\n[Alice] Comupte pseudo random challenge");
+    printf("\n\t\tE = ");
+    OCT_output(&E);
+
+    // Proof Phase
+    GG20_ZKP_phase6_prove(&r, &E, &S, &L, &p);
+    GG20_ZKP_proof_toOctets(&T, &U, &p);
+
+    printf("\n[Alice] Compute proof and export it to octets for transmission");
+    printf("\n\t\tT = ");
+    OCT_output(&T);
+    printf("\t\tU = ");
+    OCT_output(&U);
+
+    // Clean random values used for proof
+    GG20_ZKP_rv_kill(&r);
+
+    // Verification Phase - compute pseudorandom challenge and verify proof
+    GG20_ZKP_phase6_challenge(&ECPR, &ECPT, &ECPS, &c, &ID, &AD, &E);
+
+    printf("\n[Bob  ] Compute pseudo random challenge");
+    printf("\n\t\tE = ");
+    OCT_output(&E);
+
+    rc = GG20_ZKP_phase6_verify(&ECPR, &ECPT, &ECPS, &c, &E, &p);
+
+    printf("\n[Bob  ] Verify proof\n");
+
+    if (rc == GG20_ZKP_OK)
+    {
+        printf("Success!\n");
+    }
+    else
+    {
+        printf("Failure!\n");
+        exit(EXIT_FAILURE);
+    }
+
+    exit(EXIT_SUCCESS);
+}
\ No newline at end of file
diff --git a/include/amcl/gg20_zkp.h b/include/amcl/gg20_zkp.h
new file mode 100644
index 0000000..2b72e35
--- /dev/null
+++ b/include/amcl/gg20_zkp.h
@@ -0,0 +1,226 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+/**
+ * @file gg20_zkp.h
+ * @brief Gennaro 2020 - Schnorr-like proofs declarations
+ *
+ */
+
+#ifndef GG20_ZKP_H
+#define GG20_ZKP_H
+
+#include "amcl/amcl.h"
+#include "amcl/big_256_56.h"
+#include "amcl/ecp_SECP256K1.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Field size is assumed to be greater than or equal to group size */
+
+#define GGS_SECP256K1 MODBYTES_256_56  /**< ECP Group Size */
+#define GFS_SECP256K1 MODBYTES_256_56  /**< ECP Field Size */
+
+#define GG20_ZKP_OK           0    /**< Valid proof */
+#define GG20_ZKP_FAIL	        141  /**< Invalid proof */
+#define GG20_ZKP_INVALID_ECP  142  /**< Not a valid point on the curve */
+
+/* Structs for the GG20 ZKPs */
+
+/*! \brief Random values for both Phase 3 and Phase 6 ZKP commitment */
+typedef struct
+{
+    BIG_256_56 a;      /**< Randomness for the G commitment */
+    BIG_256_56 b;      /**< Randomness for the H commitment */
+} GG20_ZKP_rv;
+
+/*! \brief Proof for both Phase 3 and Phase 6 */
+typedef struct
+{
+    BIG_256_56 t;      /**< Proof for the s component */
+    BIG_256_56 u;      /**< Proof for the l component */
+} GG20_ZKP_proof;
+
+/*! \brief Commitment for the Phase 6 ZKP */
+typedef struct
+{
+    ECP_SECP256K1 ALPHA;      /**< Commitment for the additional DLOG proof */
+    ECP_SECP256K1 BETA;       /**< Commitment for the base double DLOG proof*/
+} GG20_ZKP_phase6_commitment;
+
+/* ROM for SECP256K1 alternative generator */
+
+/*! \brief Read the alternative generator for the proof from ROM
+ *
+ * Alternative generator of unknown DLOG w.r.t. the standard generator
+ * for SECP256K1.
+ *
+ * @param G      Destination ECP
+ */
+extern void GG20_ZKP_generator_2(ECP_SECP256K1 *G);
+
+/* Octet functions */
+
+/*! \brief Import a Proof values from octets
+ *
+ * @param p      Destination Proof
+ * @param T      Octet with the t value of the proof. GGS_SECP256K1 long
+ * @param U      Octet with the u value of the proof. GGS_SECP256K1 long
+ */
+extern void GG20_ZKP_proof_fromOctets(GG20_ZKP_proof *p, octet *T, octet *U);
+
+/*! \brief Exprot a Proof to octets
+ *
+ * @param T      Destination octet for the t value of the proof. GGS_SECP256K1 long
+ * @param U      Destination octet for the u value of the proof. GGS_SECP256K1 long
+ * @param p      Proof to export
+ */
+extern void GG20_ZKP_proof_toOctets(octet *T, octet *U, GG20_ZKP_proof *p);
+
+/*! \brief Import a Phase 6 Commitment from octets
+ *
+ * @param c      Destination Commitment
+ * @param ALPHA  Octet with the alpha value of the commtiment. 1 + GFS_SECP256K1 long
+ * @param BETA   Octet with the beta value of the commtiment. 1 + GFS_SECP256K1 long
+ * @return       GG20_ZKP_OK if ALPHA and BETA are valid ECPs, GG20_ZKP_INVALID_ECP otherwise
+ */
+extern int GG20_ZKP_phase6_commitment_fromOctets(GG20_ZKP_phase6_commitment *c, octet *ALPHA, octet *BETA);
+
+/*! \brief Export a Phase 6 Commitment to octets
+ *
+ * @param ALPHA  Destination octet for the alpha value of the commtiment. 1 + GFS_SECP256K1 long
+ * @param BETA   Destination octet for the beta value of the commtiment. 1 + GFS_SECP256K1 long
+ * @param c      Destination Commitment
+ */
+extern void GG20_ZKP_phase6_commitment_toOctets(octet *ALPHA, octet *BETA, GG20_ZKP_phase6_commitment *c);
+
+/* Cleanup functions */
+
+/*! \brief Clean the random values for a GG20 ZKP
+ *
+ * @param r     Random values to clean
+ */
+extern void GG20_ZKP_rv_kill(GG20_ZKP_rv *r);
+
+/* Phase 3 ZKP API */
+
+/*! \brief Generate a commitment for the proof
+ *
+ * @param RNG   CSPRNG to use for commitment
+ * @param r     Secret values used for the commitment. If RNG is NULL this is read
+ * @param C     Public commitment value. An ECP in compressed form
+ */
+extern void GG20_ZKP_phase3_commit(csprng *RNG, GG20_ZKP_rv *r, octet *C);
+
+/*! \brief Generate the challenge for the proof
+ *
+ * Compute the challenge for the proof.
+ * The challenge is inspired by RFC8235#section-3.3, with the needed tweak to
+ * also bind the secondary generator H
+ * Returns H(G, H, C, V, ID[, AD])
+ *
+ * @param V     Public ECP result of the DLOG. V = s.G + l.H. Compressed form
+ * @param C     Public commitment value. Compressed form
+ * @param ID    Prover unique identifier
+ * @param AD    Additional data to bind in the challenge - Optional
+ * @param E     Challenge generated
+ */
+extern void GG20_ZKP_phase3_challenge(const octet *V, const octet *C, const octet* ID, const octet *AD, octet *E);
+
+/*! \brief Generate the proof for the given commitment and challenge
+ *
+ * @param r     Random values used in the commitment
+ * @param E     Pseudorandom challenge
+ * @param S     Secret exponent of the double DLOG. V = s.G + l.H
+ * @param L     Secret exponent of the double DLOG. V = s.G + l.H
+ * @param p     Proof for the ZKP
+ */
+extern void GG20_ZKP_phase3_prove(GG20_ZKP_rv *r, const octet *E, const octet *S, const octet *L, GG20_ZKP_proof *p);
+
+/*! \brief Verify the proof of knowledge for the DLOG
+ *
+ * @param V     Public ECP of the DLOG. V = s.G + l.H. Compressed form
+ * @param C     Commitment value received from the prover
+ * @param E     Pseudorandom challenge
+ * @param p     Proof for the ZKP
+ * @return      GG20_ZKP_OK if the prove is valid or an error code
+ */
+extern int GG20_ZKP_phase3_verify(octet *V, octet *C, const octet *E, GG20_ZKP_proof *p);
+
+/* Phase 6 ZKP API */
+
+/*! \brief Generate a commitment for the proof
+ *
+ * @param RNG   CSPRNG to use for commitment
+ * @param R     DLOG Base for additional consistency Proof
+ * @param r     Random values for the commitment. If RNG is NULL this is read
+ * @param c     Public commitment value
+ * @return      GG20_ZKP_INVALID_ECP if R is not a valid ECP, GG20_ZKP_OK otherwise
+ */
+extern int GG20_ZKP_phase6_commit(csprng *RNG, octet *R, GG20_ZKP_rv *r, GG20_ZKP_phase6_commitment *c);
+
+/*! \brief Generate the challenge for the proof
+ *
+ * Compute the challenge for the proof.
+ * The challenge is inspired by RFC8235#section-3.3, with the needed tweak to
+ * also bind the secondary generator H and the base point R, as well as the
+ * additional commitment value BETA.
+ *
+ * Returns H(G, H, R, ALPHA, BETA, T, S, ID[, AD])
+ *
+ * @param R     Base of the additional DLOG S = s.R. Compressed form
+ * @param T     Public ECP result of the additional DLOG S = s.R. Compressed form
+ * @param S     Public ECP result of the DLOG V = s.G + l.H. Compressed form
+ * @param c     Public commitment values
+ * @param ID    Prover unique identifier
+ * @param AD    Additional data to bind in the challenge - Optional
+ * @param E     Challenge generated
+ */
+void GG20_ZKP_phase6_challenge(const octet *R, const octet *T, const octet *S, GG20_ZKP_phase6_commitment *c, const octet *ID, const octet *AD, octet *E);
+
+/*! \brief Generate the proof for the given commitment and challenge
+ *
+ * @param r     Random values used in the commitment
+ * @param E     Pseudorandom challenge
+ * @param S     Secret exponent of the double DLOG. T = s.G + l.H
+ * @param L     Secret exponent of the double DLOG. T = s.G + l.H
+ * @param p     Proof for the ZKP
+ */
+extern void GG20_ZKP_phase6_prove(GG20_ZKP_rv *r, const octet *E, const octet *S, const octet *L, GG20_ZKP_proof *p);
+
+/*! \brief Verify the proof of knowledge for the DLOG
+ *
+ * @param R     Base of the additional DLOG S = s.R. Compressed form
+ * @param T     Public ECP result of the DLOG T = s.G + l.H. Compressed form
+ * @param S     Public ECP result of the additional DLOG S = s.R. Compressed form
+ * @param c     Received Phase6 commitment
+ * @param E     Pseudorandom challenge
+ * @param p     Received Phase6 proof
+ * @return      GG20_ZKP_OK if the prove is valid or an error code
+ */
+int GG20_ZKP_phase6_verify(octet *R, octet *T, octet *S, GG20_ZKP_phase6_commitment *c, const octet *E, GG20_ZKP_proof *p);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/python/amcl/gg20_zkp.py b/python/amcl/gg20_zkp.py
new file mode 100644
index 0000000..b246bff
--- /dev/null
+++ b/python/amcl/gg20_zkp.py
@@ -0,0 +1,417 @@
+"""
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+"""
+
+"""
+
+This module use cffi to access the c functions in the amcl_mpc library.
+
+"""
+
+import platform
+from . import core_utils
+
+_ffi = core_utils._ffi
+_ffi.cdef("""
+typedef struct {
+    BIG_256_56 a;
+    BIG_256_56 b;
+} GG20_ZKP_rv;
+
+typedef struct {
+    BIG_256_56 t;
+    BIG_256_56 u;
+} GG20_ZKP_proof;
+
+typedef struct {
+    ECP_SECP256K1 ALPHA;
+    ECP_SECP256K1 BETA;
+} GG20_ZKP_phase6_commitment;
+
+void GG20_ZKP_proof_fromOctets(GG20_ZKP_proof *p, octet *T, octet *U);
+void GG20_ZKP_proof_toOctets(octet *T, octet *U, GG20_ZKP_proof *p);
+int GG20_ZKP_phase6_commitment_fromOctets(GG20_ZKP_phase6_commitment *c, octet *ALPHA, octet *BETA);
+void GG20_ZKP_phase6_commitment_toOctets(octet *ALPHA, octet *BETA, GG20_ZKP_phase6_commitment *c);
+
+void GG20_ZKP_rv_kill(GG20_ZKP_rv *r);
+
+void GG20_ZKP_phase3_commit(csprng *RNG, GG20_ZKP_rv *r, octet *C);
+void GG20_ZKP_phase3_challenge(const octet *V, const octet *C, const octet* ID, const octet *AD, octet *E);
+void GG20_ZKP_phase3_prove(GG20_ZKP_rv *r, const octet *E, const octet *S, const octet *L, GG20_ZKP_proof *p);
+int GG20_ZKP_phase3_verify(octet *V, octet *C, const octet *E, GG20_ZKP_proof *p);
+
+int GG20_ZKP_phase6_commit(csprng *RNG, octet *R, GG20_ZKP_rv *r, GG20_ZKP_phase6_commitment *c);
+void GG20_ZKP_phase6_challenge(const octet *R, const octet *T, const octet *S, GG20_ZKP_phase6_commitment *c, const octet *ID, const octet *AD, octet *E);
+void GG20_ZKP_phase6_prove(GG20_ZKP_rv *r, const octet *E, const octet *S, const octet *L, GG20_ZKP_proof *p);
+int GG20_ZKP_phase6_verify(octet *R, octet *T, octet *S, GG20_ZKP_phase6_commitment *c, const octet *E, GG20_ZKP_proof *p);
+
+""")
+
+if (platform.system() == 'Windows'):
+    _libamcl_mpc = _ffi.dlopen("libamcl_mpc.dll")
+elif (platform.system() == 'Darwin'):
+    _libamcl_mpc = _ffi.dlopen("libamcl_mpc.dylib")
+else:
+    _libamcl_mpc = _ffi.dlopen("libamcl_mpc.so")
+
+# Constants
+EGS = 32      # Size of a Z/qZ element in bytes
+EFS = 32      # Size of a Fp element in bytes
+PTS = EFS + 1 # Size of a ECP in compressed form
+
+OK          = 0
+FAIL        = 141
+INVALID_ECP = 142
+
+
+# Octet functions
+
+
+def proof_from_octets(t, u):
+    """ Import a proof from its components octets
+
+    Args::
+        t : t component of the proof
+        u : u component of the proof
+
+    Returns::
+        p : pointer to the proof
+
+    """
+    p = _ffi.new('GG20_ZKP_proof*')
+
+    t_oct, t_val = core_utils.make_octet(None, t)
+    u_oct, u_val = core_utils.make_octet(None, u)
+    _ = t_val, u_val  # Suppress warnings
+
+    _libamcl_mpc.GG20_ZKP_proof_fromOctets(p, t_oct, u_oct)
+
+    return p
+
+
+def proof_to_octets(p):
+    """ Export the proof to octets
+
+    Args::
+        p : pointer to the proof
+
+    Returns::
+        t : t component of the proof
+        u : u component of the proof
+
+    """
+    t_oct, t_val = core_utils.make_octet(EGS)
+    u_oct, u_val = core_utils.make_octet(EGS)
+    _ = t_val, u_val  # Suppress warnings
+
+    _libamcl_mpc.GG20_ZKP_proof_toOctets(t_oct, u_oct, p)
+
+    t = core_utils.to_str(t_oct)
+    u = core_utils.to_str(u_oct)
+
+    return t, u
+
+
+def phase6_commitment_from_octets(alpha, beta):
+    """ Import a Phase 6 commitment from its components octets
+
+    Args::
+        alpha : commitment for the additional DLOG
+        beta  : commitment for the double DLOG
+
+    Returns::
+        c  : pointer to the commitment. NULL if rc is not OK
+        rc : OK or an error code
+
+    """
+    c = _ffi.new('GG20_ZKP_phase6_commitment*')
+
+    alpha_oct, alpha_val = core_utils.make_octet(None, alpha)
+    beta_oct,  beta_val  = core_utils.make_octet(None, beta)
+    _ = alpha_val, beta_val  # Suppress warnings
+
+    rc = _libamcl_mpc.GG20_ZKP_phase6_commitment_fromOctets(c, alpha_oct, beta_oct)
+    if rc != OK:
+        c = _ffi.NULL
+
+    return c, rc
+
+
+def phase6_commitment_to_octets(c):
+    """ Export a Phase 6 commitment to octets
+
+    Args::
+        c : pointer to the commitment
+
+    Returns::
+        t : t component of the proof
+        u : u component of the proof
+
+    """
+    alpha_oct, alpha_val = core_utils.make_octet(PTS)
+    beta_oct,  beta_val  = core_utils.make_octet(PTS)
+    _ = alpha_val, beta_val  # Suppress warnings
+
+    _libamcl_mpc.GG20_ZKP_phase6_commitment_toOctets(alpha_oct, beta_oct, c)
+
+    alpha = core_utils.to_str(alpha_oct)
+    beta  = core_utils.to_str(beta_oct)
+
+    return alpha, beta
+
+
+# Cleanup functions
+
+
+def rv_kill(rv):
+    """ Clean memory for the commitment random values
+
+    Args::
+        rv : the random values to clean
+    """
+
+    _libamcl_mpc.GG20_ZKP_rv_kill(rv)
+
+
+# GG20 ZKP Phase 3
+
+
+def phase3_commit(rng, rv=None):
+    ''' Generate a commitment for the GG20 Phase 3 ZKP
+
+    Compute random values and commitment. If r is given as input, use
+    the given values instead of generating random ones.
+
+    Args::
+        rng : Pointer to csprng
+        rv  : Pointer to deterministic values for commitment. Optional
+
+    Returns::
+        r : Pointer to random values used in commitments
+        C : commitment
+    '''
+
+    if rv is None:
+        rv = _ffi.new('GG20_ZKP_rv*')
+    else:
+        rng = _ffi.NULL
+
+    c_oct, _ = core_utils.make_octet(PTS)
+
+    _libamcl_mpc.GG20_ZKP_phase3_commit(rng, rv, c_oct)
+
+    return rv, core_utils.to_str(c_oct)
+
+
+def phase3_challenge(V, C, ID, AD=None):
+    """ Bind public parameters and commitment in challenge
+
+    Args::
+        V  : Public ECP of the double DLOG
+        C  : Generated Commitment
+        ID : Unique user identifier
+        AD : Additional data to bind in the challenge. Optional
+
+    Returns::
+        E  : Pseudorandom challenge
+    """
+
+    if AD is None:
+        ad_oct = _ffi.NULL
+    else:
+        ad_oct, ad_val = core_utils.make_octet(None, AD)
+        _ = ad_val  # Suppress warning
+
+    v_oct,  v_val  = core_utils.make_octet(None, V)
+    c_oct,  c_val  = core_utils.make_octet(None, C)
+    id_oct, id_val = core_utils.make_octet(None, ID)
+    e_oct,  e_val  = core_utils.make_octet(EGS)
+    _ = v_val, c_val, id_val, e_val  # Suppress warning
+
+    _libamcl_mpc.GG20_ZKP_phase3_challenge(v_oct, c_oct, id_oct, ad_oct, e_oct)
+
+    return core_utils.to_str(e_oct)
+
+
+def phase3_prove(r, e, s, l):
+    """ Generate proof from commitment random values and ZKP secret input
+
+    Args::
+        r : Pointer to commitment random values from commitment
+        e : pseudorandom challenge
+        s : secret exponent of the double DLOG for G
+        l : secret exponent of the double DLOG for H
+
+    Returns::
+        p : Pointer to generated proof
+    """
+
+    e_oct, e_val = core_utils.make_octet(None, e)
+    s_oct, s_val = core_utils.make_octet(None, s)
+    l_oct, l_val = core_utils.make_octet(None, l)
+    _ = e_val, s_val, l_val  # Suppress warning
+
+    p = _ffi.new('GG20_ZKP_proof*')
+
+    _libamcl_mpc.GG20_ZKP_phase3_prove(r, e_oct, s_oct, l_oct, p)
+
+    return p
+
+
+def phase3_verify(V, C, e, p):
+    ''' Verify a GG20 ZKP
+
+    Args::
+        V : Public ECP of the DLOG
+        C : Received Commitment
+        e : Pesudo random challenge
+        p : Pointer to Received Proof
+
+    Returns::
+        ok : OK or an error code
+    '''
+
+    v_oct, v_val = core_utils.make_octet(None, V)
+    c_oct, c_val = core_utils.make_octet(None, C)
+    e_oct, e_val = core_utils.make_octet(None, e)
+    _ = v_val, c_val, e_val   # Suppress warnings
+
+    rc = _libamcl_mpc.GG20_ZKP_phase3_verify(v_oct, c_oct, e_oct, p)
+
+    return rc
+
+
+# GG20 ZKP Phase 6
+
+
+def phase6_commit(rng, R, rv=None):
+    ''' Generate a commitment for the GG20 Phase 6 ZKP
+
+    Compute random values and commitment. If rv is given as input, use
+    the given values instead of generating random ones.
+
+    Args::
+        rng : Pointer to csprng
+        R   : Base of the additional DLOG
+        rv  : Pointer to deterministic values for commitment. Optional
+
+    Returns::
+        rv    : Pointer to random values used in commitments
+        c     : Pointer to the commitment
+        rc    : OK or an error code
+    '''
+
+    if rv is None:
+        rv = _ffi.new('GG20_ZKP_rv*')
+    else:
+        rng = _ffi.NULL
+
+    c = _ffi.new('GG20_ZKP_phase6_commitment*')
+    r_oct, _ = core_utils.make_octet(None, R)
+
+    rc = _libamcl_mpc.GG20_ZKP_phase6_commit(rng, r_oct, rv, c)
+
+    if rc != OK:
+        rv = _ffi.NULL
+        c = _ffi.NULL
+
+    return rv, c, rc
+
+
+def phase6_challenge(R, T, S, c, ID, AD=None):
+    """ Bind public parameters and commitment in challenge.
+
+    Args::
+        R  : Base ECP of the additional DLOG
+        T  : Double DLOG public ECP
+        S  : Additional DLOG public ECP
+        c  : Pointer to generated Commitment
+        ID : Unique user identifier
+        AD : Additional data to bind in the challenge. Optional
+
+    Returns::
+        E : Pesudorandom challenge
+    """
+
+    if AD is None:
+        ad_oct = _ffi.NULL
+    else:
+        ad_oct, ad_val = core_utils.make_octet(None, AD)
+        _ = ad_val  # Suppress warning
+
+    r_oct,  r_val  = core_utils.make_octet(None, R)
+    t_oct,  t_val  = core_utils.make_octet(None, T)
+    s_oct,  s_val  = core_utils.make_octet(None, S)
+    id_oct, id_val = core_utils.make_octet(None, ID)
+    e_oct,  e_val  = core_utils.make_octet(EGS)
+    _ = r_val, t_val, s_val, id_val, e_val  # Suppress warning
+
+    _libamcl_mpc.GG20_ZKP_phase6_challenge(r_oct, t_oct, s_oct, c, id_oct, ad_oct, e_oct)
+
+    return core_utils.to_str(e_oct)
+
+
+def phase6_prove(r, e, s, l):
+    """ Generate proof from commitment random values and ZKP secret input
+
+    Args::
+        r : Pointer to commitment random values from commitment
+        e : pseudorandom challenge
+        s : secret exponent of the double DLOG for G
+        l : secret exponent of the double DLOG for H
+
+    Returns::
+        p : Pointer to generated proof
+    """
+
+    e_oct, e_val = core_utils.make_octet(None, e)
+    s_oct, s_val = core_utils.make_octet(None, s)
+    l_oct, l_val = core_utils.make_octet(None, l)
+    _ = e_val, s_val, l_val  # Suppress warning
+
+    p = _ffi.new('GG20_ZKP_proof*')
+
+    _libamcl_mpc.GG20_ZKP_phase6_prove(r, e_oct, s_oct, l_oct, p)
+
+    return p
+
+
+def phase6_verify(R, T, S, c, e, p):
+    ''' Verify a GG20 ZKP
+
+    Args::
+        R : Base ECP of the additional DLOG
+        T : Double DLOG public ECP
+        S : Additional DLOG public ECP
+        c : Pointer to received Commitment
+        e : Pesudo random challenge
+        p : Pointer to Received Proof
+
+    Returns::
+        ok : OK or an error code
+    '''
+
+    r_oct, r_val  = core_utils.make_octet(None, R)
+    t_oct, t_val  = core_utils.make_octet(None, T)
+    s_oct, s_val  = core_utils.make_octet(None, S)
+    e_oct, e_val = core_utils.make_octet(None, e)
+    _ = r_val, t_val, s_val, e_val   # Suppress warnings
+
+    rc = _libamcl_mpc.GG20_ZKP_phase6_verify(r_oct, t_oct, s_oct, c, e_oct, p)
+
+    return rc
diff --git a/python/amcl/schnorr.py b/python/amcl/schnorr.py
index 49b57d3..5473ea7 100644
--- a/python/amcl/schnorr.py
+++ b/python/amcl/schnorr.py
@@ -37,13 +37,10 @@ extern int SCHNORR_verify(octet *V, octet *C, const octet *E, const octet *P);
 
 if (platform.system() == 'Windows'):
     _libamcl_mpc = _ffi.dlopen("libamcl_mpc.dll")
-    _libamcl_curve_secp256k1 = _ffi.dlopen("libamcl_curve_SECP256K1.dll")
 elif (platform.system() == 'Darwin'):
     _libamcl_mpc = _ffi.dlopen("libamcl_mpc.dylib")
-    _libamcl_curve_secp256k1 = _ffi.dlopen("libamcl_curve_SECP256K1.dylib")
 else:
     _libamcl_mpc = _ffi.dlopen("libamcl_mpc.so")
-    _libamcl_curve_secp256k1 = _ffi.dlopen("libamcl_curve_SECP256K1.so")
 
 # Constants
 EGS = 32      # Size of a Z/qZ element in bytes
diff --git a/python/benchmark/bench_bc_setup.py b/python/benchmark/bench_bc_setup.py
new file mode 100755
index 0000000..47fc811
--- /dev/null
+++ b/python/benchmark/bench_bc_setup.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python3
+
+"""
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+"""
+
+import os
+import sys
+from bench import time_func
+
+sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
+
+from amcl import core_utils
+from amcl import bit_commitment as bc
+
+seed_hex = "78d0fb6705ce77dee47d03eb5b9c5d30"
+
+p_hex = "CA5F37B7C0DDF6530B30A41116588218DE95F1F36B807FD7C28E4C467EE3F35967BC01D28B71F8A627A353675A81C86A1FF03DCECAF1686891183FA317BA34A4A1148D40A89F1F3AC0C200511C6CFE02342CD75354C25A2E069886DD4FB73BD365660D163F1282B143119AB8F375A73875EC16B634F52593B73BC6D875F2D3EF"
+q_hex = "C2FC545C1C803F6C7625FBC4ECF9355734D6B6058FD714816D3ECFB93F1F705C9CE90D4F8796A05148AB5ABC201F90889231CC6BF5F68ED15EE4D901F603930A280EEABF10C613BFCB67A816363C839EB902B02607EB48AB8325E2B72620D4D294A232803217090DFB50AF8C620D4679E77CE3053437ED518F4F68840DCF1AA3"
+
+if __name__ == "__main__":
+    p = bytes.fromhex(p_hex)
+    q = bytes.fromhex(q_hex)
+
+    seed = bytes.fromhex(seed_hex)
+    rng = core_utils.create_csprng(seed)
+
+    id = b'unique_identifier'
+    ad = b'additional_data'
+
+    # Generate quantities for benchmark
+    priv = bc.setup(rng, p=p, q=q)
+    pub = bc.priv_to_pub(priv)
+    proof = bc.setup_prove(rng, priv, id, ad=ad)
+    rc = bc.setup_verify(pub, proof, id, ad=ad)
+
+    assert rc == bc.OK
+
+    # Run benchmark
+    fncall = lambda: bc.setup(rng, p=p, q=q)
+    time_func("bc_setup       ", fncall, unit="ms")
+
+    fncall = lambda: bc.priv_to_pub(priv)
+    time_func("bc_priv_to_pub ", fncall, unit="us")
+
+    fncall = lambda: bc.setup_prove(rng, priv, id, ad=ad)
+    time_func("bc_setup_prove ", fncall, unit="ms")
+
+    fncall = lambda: bc.setup_verify(pub, proof, id, ad=ad)
+    time_func("bc_setup_verify", fncall, unit="ms")
\ No newline at end of file
diff --git a/python/benchmark/bench_gg20_zkp.py b/python/benchmark/bench_gg20_zkp.py
new file mode 100755
index 0000000..d367de8
--- /dev/null
+++ b/python/benchmark/bench_gg20_zkp.py
@@ -0,0 +1,112 @@
+#!/usr/bin/env python3
+
+import os
+import sys
+from bench import time_func
+
+sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
+
+from amcl import core_utils, gg20_zkp
+
+
+seed_hex = "78d0fb6705ce77dee47d03eb5b9c5d30"
+
+l_hex = "584edf9db99551ff2e0d56218a44fea0943032f7864b8359c213ec36465512c5"
+s_hex = "843b282505357e075bd98104f42fe7ea6b41310da7c769b4c402442c1ede922b"
+
+R_hex = "03e03cda61f087f9ba381695dc816a4ca42f38bbfc3fc88ffe897594b94ee7b80b"
+T_hex = "02863528287942ab88dec016c2e1993bf9e459ffcbfcc48c25ef68f2ec750e55a8"
+S_hex = "02ef03c8ecb7cf65b58d85f368c5fc2725b4e4fe93306f98cf53f8e1531cea2bc4"
+
+ID = "unique_user_identifier".encode('utf-8')
+AD = "additional_data".encode('utf-8')
+
+if __name__ == "__main__":
+    seed = bytes.fromhex(seed_hex)
+    rng = core_utils.create_csprng(seed)
+
+    # Generate quantities for Phase 3 Benchmark
+    s = bytes.fromhex(s_hex)
+    l = bytes.fromhex(l_hex)
+    V = bytes.fromhex(T_hex)
+
+    rv, c = gg20_zkp.phase3_commit(rng)
+    e = gg20_zkp.phase3_challenge(V, c,ID, AD = AD)
+    p = gg20_zkp.phase3_prove(rv, e, s, l)
+    rc = gg20_zkp.phase3_verify(V, c, e, p)
+
+    assert rc == gg20_zkp.OK, "Error Setting up Phase 3 ZKP"
+
+    # Run Phase 3 ZKP Benchmark
+    print(" *** Phase 3 ZKP ***")
+
+    fncall = lambda: gg20_zkp.phase3_commit(rng, rv=rv)
+    time_func("phase3_commit   ", fncall)
+
+    fncall = lambda: gg20_zkp.phase3_challenge(V, c,ID, AD = AD)
+    time_func("phase3_challenge", fncall)
+
+    fncall = lambda: gg20_zkp.phase3_prove(rv, e, s, l)
+    time_func("phase3_prove    ", fncall)
+
+    fncall = lambda: gg20_zkp.phase3_verify(V, c, e, p)
+    time_func("phase3_verify   ", fncall)
+
+    print("")
+
+    #  Generate quantities for Phase 6 benchmark
+    R = bytes.fromhex(R_hex)
+    T = bytes.fromhex(T_hex)
+    S = bytes.fromhex(S_hex)
+
+    rv, c, rc = gg20_zkp.phase6_commit(rng, R)
+
+    assert rc == gg20_zkp.OK, "Error setting up Phase 6 Commit"
+
+    e = gg20_zkp.phase6_challenge(R, T, S, c, ID, AD=AD)
+    p = gg20_zkp.phase6_prove(rv, e, s, l)
+    rc = gg20_zkp.phase6_verify(R, T, S, c, e, p)
+
+    assert rc == gg20_zkp.OK, "Error Setting up Phase 6 ZKP"
+
+    # Run Phase 6 ZKP Benchmark
+    print(" *** Phase 6 ZKP ***")
+
+    fncall = lambda: gg20_zkp.phase6_commit(rng, R, rv=rv)
+    time_func("phase6_commit   ", fncall)
+
+    fncall = lambda: gg20_zkp.phase6_challenge(R, T, S, c, ID, AD = AD)
+    time_func("phase6_challenge", fncall)
+
+    fncall = lambda: gg20_zkp.phase6_prove(rv, e, s, l)
+    time_func("phase6_prove    ", fncall)
+
+    fncall = lambda: gg20_zkp.phase6_verify(R, T, S, c, e, p)
+    time_func("phase6_verify   ", fncall)
+
+    # Generate quantities for additional benchmakrs
+    t, u = gg20_zkp.proof_to_octets(p)
+
+    alpha, beta = gg20_zkp.phase6_commitment_to_octets(c)
+    c, rc = gg20_zkp.phase6_commitment_from_octets(alpha, beta)
+    assert rc == gg20_zkp.OK, "Error setting up octets"
+
+    gg20_zkp.rv_kill(rv)
+
+    # Run Additional Benchmark
+    print(" *** Additional functions ***")
+
+    fncall = lambda: gg20_zkp.proof_to_octets(p)
+    time_func("proof_to_octets              ", fncall)
+
+    fncall = lambda: gg20_zkp.proof_from_octets(t, u)
+    time_func("proof_from_octets            ", fncall)
+
+    fncall = lambda: gg20_zkp.phase6_commitment_to_octets(c)
+    time_func("phase6_commitment_to_octets  ", fncall)
+
+    fncall = lambda: gg20_zkp.phase6_commitment_from_octets(alpha, beta)
+    time_func("phase6_commitment_from_octets", fncall)
+
+    fncall = lambda: gg20_zkp.rv_kill(rv)
+    time_func("rv_kill                      ", fncall)
diff --git a/python/examples/example_gg20_zkp.py b/python/examples/example_gg20_zkp.py
new file mode 100755
index 0000000..6ed3914
--- /dev/null
+++ b/python/examples/example_gg20_zkp.py
@@ -0,0 +1,195 @@
+#!/usr/bin/env python3
+
+import os
+import sys
+
+sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
+
+from amcl import core_utils, gg20_zkp
+
+
+seed_hex = "78d0fb6705ce77dee47d03eb5b9c5d30"
+
+l_hex = "584edf9db99551ff2e0d56218a44fea0943032f7864b8359c213ec36465512c5"
+s_hex = "843b282505357e075bd98104f42fe7ea6b41310da7c769b4c402442c1ede922b"
+
+R_hex = "03e03cda61f087f9ba381695dc816a4ca42f38bbfc3fc88ffe897594b94ee7b80b"
+T_hex = "02863528287942ab88dec016c2e1993bf9e459ffcbfcc48c25ef68f2ec750e55a8"
+S_hex = "02ef03c8ecb7cf65b58d85f368c5fc2725b4e4fe93306f98cf53f8e1531cea2bc4"
+
+ID = "unique_user_identifier".encode('utf-8')
+AD = "additional_data".encode('utf-8')
+
+if __name__ == "__main__":
+    seed = bytes.fromhex(seed_hex)
+    rng = core_utils.create_csprng(seed)
+
+    print("Example GG20 ZKPs for Phase 3/6\n")
+
+    # Phase 3 GG20 ZKP
+    s = bytes.fromhex(s_hex)
+    l = bytes.fromhex(l_hex)
+    V = bytes.fromhex(T_hex)
+
+    print("*** Phase 3 ZKP ***\n")
+    print("Parameters")
+    print("\ts  = {}".format(s.hex()))
+    print("\tl  = {}".format(l.hex()))
+    print("\tT  = {}".format(V.hex()))
+    print("\tID = {}".format(ID.decode('utf-8')))
+    print("\tAD = {}".format(AD.decode('utf-8')))
+    print("")
+
+    print("Begin Phase 3 ZK proof\n")
+
+    ## Prover
+
+    # Commitment
+    rv, c = gg20_zkp.phase3_commit(rng)
+
+    print("[Alice] Commit")
+    print("\tC = {}".format(c))
+    print("")
+
+    # Challenge
+    e = gg20_zkp.phase3_challenge(V, c,ID, AD = AD)
+
+    print("[Alice] Challenge")
+    print("\te = {}".format(e.hex()))
+    print("")
+
+    # Proof
+    p = gg20_zkp.phase3_prove(rv, e, s, l)
+
+    # Export proof to octets for transmission
+    t, u = gg20_zkp.proof_to_octets(p)
+
+    print("[Alice] Proof")
+    print("\tt = {}".format(t.hex()))
+    print("\tu = {}".format(u.hex()))
+    print("")
+
+    # Clean rv memory
+    gg20_zkp.rv_kill(rv)
+
+    ## Verifier
+
+    # Import proof from received octets
+    p = gg20_zkp.proof_from_octets(t, u)
+    print("[Bob  ] Received Proof")
+    print("\tt = {}".format(t.hex()))
+    print("\tu = {}".format(u.hex()))
+    print("")
+
+    # Challenge
+    e = gg20_zkp.phase3_challenge(V, c,ID, AD = AD)
+
+    print("[Bob  ] Challenge")
+    print("\te = {}".format(e.hex()))
+    print("")
+
+    # Verify proof
+    rc = gg20_zkp.phase3_verify(V, c, e, p)
+
+    print("[Bob  ] Verification")
+    if rc == gg20_zkp.OK:
+        print("\tSuccess")
+    else:
+        print("\tFailure: {}".format(rc))
+        sys.exit(1)
+
+    print("")
+
+    # Phase 6 GG20 ZKP
+    R = bytes.fromhex(R_hex)
+    T = bytes.fromhex(T_hex)
+    S = bytes.fromhex(S_hex)
+
+    print("\n*** Phase 6 ZKP ***\n")
+    print("Parameters")
+    print("\ts  = {}".format(s.hex()))
+    print("\tl  = {}".format(l.hex()))
+    print("\tR  = {}".format(R.hex()))
+    print("\tT  = {}".format(T.hex()))
+    print("\tS  = {}".format(S.hex()))
+    print("\tID = {}".format(ID.decode('utf-8')))
+    print("\tAD = {}".format(AD.decode('utf-8')))
+    print("")
+
+    print("Begin Phase 3 ZK proof\n")
+
+    ## Prover
+
+    # Commitment
+    rv, c, rc = gg20_zkp.phase6_commit(rng, R)
+
+    if rc != gg20_zkp.OK:
+        print("[Alice] Commit Error: {}".format(rc))
+        sys.exit(1)
+
+    # Export commitment to octets for transmission
+    alpha, beta = gg20_zkp.phase6_commitment_to_octets(c)
+
+    print("[Alice] Commit")
+    print("\talpha = {}\n".format(alpha.hex()))
+    print("\tbeta  = {}\n".format(beta.hex()))
+    print("")
+
+    # Challenge
+    e = gg20_zkp.phase6_challenge(R, T, S, c, ID, AD=AD)
+
+    print("[Alice] Challenge")
+    print("\te = {}".format(e.hex()))
+    print("")
+
+    # Proof
+    p = gg20_zkp.phase6_prove(rv, e, s, l)
+
+    # Export proof to octets for transmission
+    t, u = gg20_zkp.proof_to_octets(p)
+
+    print("[Alice] Proof")
+    print("\tt = {}".format(t.hex()))
+    print("\tu = {}".format(u.hex()))
+    print("")
+
+    # Clean rv memory
+    gg20_zkp.rv_kill(rv)
+
+    ## Verifier
+
+    # Import proof from received octets
+    p = gg20_zkp.proof_from_octets(t, u)
+    print("[Bob  ] Received Proof")
+    print("\tt = {}".format(t.hex()))
+    print("\tu = {}".format(u.hex()))
+    print("")
+
+    # Import commitment from received octets
+    c, rc = gg20_zkp.phase6_commitment_from_octets(alpha, beta)
+
+    if rc != gg20_zkp.OK:
+        print("[Bob  ] Error importing Commitment: {}".format(rc))
+        sys.exit(1)
+
+    print("[Bob  ] Received Commitment")
+    print("\talpha = {}\n".format(alpha.hex()))
+    print("\tbeta  = {}\n".format(beta.hex()))
+    print("")
+
+    # Challenge
+    e = gg20_zkp.phase6_challenge(R, T, S, c,ID, AD = AD)
+
+    print("[Bob  ] Challenge")
+    print("\te = {}".format(e.hex()))
+    print("")
+
+    # Verification
+    rc = gg20_zkp.phase6_verify(R, T, S, c, e, p)
+
+    print("[Bob  ] Verification")
+    if rc == gg20_zkp.OK:
+        print("\tSuccess")
+    else:
+        print("\tFailure: {}".format(rc))
+        sys.exit(1)
diff --git a/python/test/test_gg20_zkp.py b/python/test/test_gg20_zkp.py
new file mode 100755
index 0000000..0bb8535
--- /dev/null
+++ b/python/test/test_gg20_zkp.py
@@ -0,0 +1,225 @@
+#!/usr/bin/env python3
+
+"""
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+"""
+
+import os
+import sys
+import unittest
+
+sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
+
+from amcl import core_utils, gg20_zkp
+
+
+
+class TestPhase3(unittest.TestCase):
+    """ Test Phase 3 ZKP """
+
+    def setUp(self):
+        # Deterministic PRNG for testing purposes
+        seed_hex = "78d0fb6705ce77dee47d03eb5b9c5d30"
+        seed = bytes.fromhex(seed_hex)
+        self.rng = core_utils.create_csprng(seed)
+
+        # Proof input
+        self.s = bytes.fromhex("00f1f45c44eb4298562677dfc945064ac5d45d683ec2d87efbd2f527bb5a768c")
+        self.l = bytes.fromhex("ab5aa1e7740f849b974fcaaa98840d828a42b16dd59be32f39e3c637730ee9e4")
+
+        self.v = bytes.fromhex("02879452f0c552b01c2cc91101062ca02a1ff3eab1e9c18873992670198bf54f3e")
+
+        self.id = b'user-id'
+        self.ad = b'more-data'
+
+        # Pre-generate rv for deterministic test
+        self.rv, self.c = gg20_zkp.phase3_commit(self.rng)
+
+
+    def test(self):
+        """ Test Phase 3 ZKP """
+
+        rv, c = gg20_zkp.phase3_commit(self.rng)
+        e = gg20_zkp.phase3_challenge(self.v, c, self.id, AD = self.ad)
+        p = gg20_zkp.phase3_prove(rv, e, self.s, self.l)
+
+        gg20_zkp.rv_kill(self.rv)
+
+        t, u = gg20_zkp.proof_to_octets(p)
+        p = gg20_zkp.proof_from_octets(t, u)
+
+        rc = gg20_zkp.phase3_verify(self.v, c, e, p)
+
+        self.assertEqual(rc, gg20_zkp.OK, "Invalid Proof")
+
+
+    def test_no_ad(self):
+        """ Test Phase 3 ZKP without AD """
+
+        rv, c = gg20_zkp.phase3_commit(self.rng)
+        e = gg20_zkp.phase3_challenge(self.v, c, self.id)
+        p = gg20_zkp.phase3_prove(rv, e, self.s, self.l)
+
+        gg20_zkp.rv_kill(self.rv)
+
+        t, u = gg20_zkp.proof_to_octets(p)
+        p = gg20_zkp.proof_from_octets(t, u)
+
+        rc = gg20_zkp.phase3_verify(self.v, c, e, p)
+
+        self.assertEqual(rc, gg20_zkp.OK, "Invalid Proof")
+
+
+    def test_deterministic(self):
+        """ Test Phase 3 ZKP commitment with pre-generated rv"""
+
+        rv, c = gg20_zkp.phase3_commit(self.rng, rv = self.rv)
+
+        self.assertEqual(c, self.c, "Inconsistent commitment")
+
+        e = gg20_zkp.phase3_challenge(self.v, c, self.id, AD = self.ad)
+        p = gg20_zkp.phase3_prove(rv, e, self.s, self.l)
+
+        gg20_zkp.rv_kill(self.rv)
+
+        t, u = gg20_zkp.proof_to_octets(p)
+        p = gg20_zkp.proof_from_octets(t, u)
+
+        rc = gg20_zkp.phase3_verify(self.v, c, e, p)
+
+        self.assertEqual(rc, gg20_zkp.OK, "Invalid Proof")
+
+
+class TestPhase6(unittest.TestCase):
+    """ Test Phase 6 ZKP """
+
+    def setUp(self):
+        # Deterministic PRNG for testing purposes
+        seed_hex = "78d0fb6705ce77dee47d03eb5b9c5d30"
+        seed = bytes.fromhex(seed_hex)
+        self.rng = core_utils.create_csprng(seed)
+
+        # Proof input
+        self.s = bytes.fromhex("843b282505357e075bd98104f42fe7ea6b41310da7c769b4c402442c1ede922b")
+        self.l = bytes.fromhex("584edf9db99551ff2e0d56218a44fea0943032f7864b8359c213ec36465512c5")
+
+        self.R = bytes.fromhex("03e03cda61f087f9ba381695dc816a4ca42f38bbfc3fc88ffe897594b94ee7b80b")
+        self.T = bytes.fromhex("02863528287942ab88dec016c2e1993bf9e459ffcbfcc48c25ef68f2ec750e55a8")
+        self.S = bytes.fromhex("02ef03c8ecb7cf65b58d85f368c5fc2725b4e4fe93306f98cf53f8e1531cea2bc4")
+
+        self.id = b'user-id'
+        self.ad = b'more-data'
+
+        # Pre-generate rv for deterministic test
+        self.rv, c, rc = gg20_zkp.phase6_commit(self.rng, self.R)
+        self.assertEqual(rc, gg20_zkp.OK, f"Commitment error. RC: {rc}")
+
+        self.alpha, self.beta = gg20_zkp.phase6_commitment_to_octets(c)
+
+
+    def test(self):
+        """ Test Phase 6 ZKP """
+
+        rv, c, rc = gg20_zkp.phase6_commit(self.rng, self.R)
+        self.assertEqual(rc, gg20_zkp.OK, f"Commitment error. RC: {rc}")
+
+        e = gg20_zkp.phase6_challenge(self.R, self.T, self.S, c, self.id, AD = self.ad)
+        p = gg20_zkp.phase3_prove(rv, e, self.s, self.l)
+
+        gg20_zkp.rv_kill(self.rv)
+
+        t, u = gg20_zkp.proof_to_octets(p)
+        p = gg20_zkp.proof_from_octets(t, u)
+
+        alpha, beta = gg20_zkp.phase6_commitment_to_octets(c)
+        c, rc = gg20_zkp.phase6_commitment_from_octets(alpha, beta)
+        self.assertEqual(rc, gg20_zkp.OK, f"Commitment octet functions error. RC: {rc}")
+
+        rc = gg20_zkp.phase6_verify(self.R, self.T, self.S, c, e, p)
+
+        self.assertEqual(rc, gg20_zkp.OK, "Invalid Proof")
+
+
+    def test_no_ad(self):
+        """ Test Phase 6 ZKP without AD """
+
+        rv, c, rc = gg20_zkp.phase6_commit(self.rng, self.R)
+        self.assertEqual(rc, gg20_zkp.OK, f"Commitment error. RC: {rc}")
+
+        e = gg20_zkp.phase6_challenge(self.R, self.T, self.S, c, self.id)
+        p = gg20_zkp.phase3_prove(rv, e, self.s, self.l)
+
+        gg20_zkp.rv_kill(self.rv)
+
+        t, u = gg20_zkp.proof_to_octets(p)
+        p = gg20_zkp.proof_from_octets(t, u)
+
+        alpha, beta = gg20_zkp.phase6_commitment_to_octets(c)
+        c, rc = gg20_zkp.phase6_commitment_from_octets(alpha, beta)
+        self.assertEqual(rc, gg20_zkp.OK, f"Commitment octet functions error. RC: {rc}")
+
+        rc = gg20_zkp.phase6_verify(self.R, self.T, self.S, c, e, p)
+
+        self.assertEqual(rc, gg20_zkp.OK, "Invalid Proof")
+
+
+    def test_deterministic(self):
+        """ Test Phase 6 ZKP commitment with pre-generated rv"""
+
+        rv, c, rc = gg20_zkp.phase6_commit(self.rng, self.R, rv = self.rv)
+        self.assertEqual(rc, gg20_zkp.OK, f"Commitment error. RC: {rc}")
+
+        alpha, beta = gg20_zkp.phase6_commitment_to_octets(c)
+        self.assertEqual(alpha, self.alpha, "Inconsistent commitment alpha")
+        self.assertEqual(beta,  self.beta,  "Inconsistent commitment beta")
+
+        e = gg20_zkp.phase6_challenge(self.R, self.T, self.S, c, self.id, AD = self.ad)
+        p = gg20_zkp.phase3_prove(rv, e, self.s, self.l)
+
+        gg20_zkp.rv_kill(self.rv)
+
+        t, u = gg20_zkp.proof_to_octets(p)
+        p = gg20_zkp.proof_from_octets(t, u)
+
+        alpha, beta = gg20_zkp.phase6_commitment_to_octets(c)
+        c, rc = gg20_zkp.phase6_commitment_from_octets(alpha, beta)
+        self.assertEqual(rc, gg20_zkp.OK, f"Commitment octet functions error. RC: {rc}")
+
+        rc = gg20_zkp.phase6_verify(self.R, self.T, self.S, c, e, p)
+
+        self.assertEqual(rc, gg20_zkp.OK, "Invalid Proof")
+
+
+    def test_error_propagation(self):
+        """ Test Error Code propagation for invalid ECP """
+
+        rv, c, rc = gg20_zkp.phase6_commit(self.rng, self.l)
+
+        self.assertEqual(rv, gg20_zkp._ffi.NULL, "Commit rv not NULL")
+        self.assertEqual(c,  gg20_zkp._ffi.NULL, "Commit c not NULL")
+        self.assertEqual(rc, gg20_zkp.INVALID_ECP, "Commit error code not propagated")
+
+        c = "not_none"
+        c, rc = gg20_zkp.phase6_commitment_from_octets(self.l, self.s)
+
+        self.assertEqual(c,  gg20_zkp._ffi.NULL, "Octets c not NULL")
+        self.assertEqual(rc, gg20_zkp.INVALID_ECP, "Octets error code not propagated")
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/python/test/test_schnorr.py b/python/test/test_schnorr.py
index 9423265..b36604d 100755
--- a/python/test/test_schnorr.py
+++ b/python/test/test_schnorr.py
@@ -81,10 +81,10 @@ class TestChallenge(unittest.TestCase):
             V  = bytes.fromhex(vector["V"])
             C  = bytes.fromhex(vector["C"])
             ID = bytes.fromhex(vector["ID"])
-            AD = bytes.fromhex(vector["AD"])
 
-            if not AD:
-                AD = None
+            AD = None
+            if vector["AD"]:
+                AD = bytes.fromhex(vector["AD"])
 
             e_golden = bytes.fromhex(vector["E"])
 
diff --git a/src/gg20_zkp.c b/src/gg20_zkp.c
new file mode 100644
index 0000000..6de8e39
--- /dev/null
+++ b/src/gg20_zkp.c
@@ -0,0 +1,375 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+#include "amcl/gg20_zkp.h"
+#include "amcl/hash_utils.h"
+
+/* Rom for SEC256K1 alternative generator
+ *
+ * This is tested in the unit tests to make sure it is a NUMS number
+ */
+
+const BIG_256_56 CURVE_G2x_SECP256K1= {0x072FA321534A94L, 0x1E5494E1366DF5L, 0x5544A7C6B1AE84L, 0x361809F7E86B0AL, 0x00000050E61A4DL};
+const BIG_256_56 CURVE_G2y_SECP256K1= {0x2EDE1FF33BE530L, 0x3BF41E26F5E241L, 0xB21F8B17AFDFBFL, 0xC7F68F0FD917E8L, 0x000000F1AF85F2L};
+
+void GG20_ZKP_generator_2(ECP_SECP256K1 *G)
+{
+    BIG_256_56 x,y;
+
+    BIG_256_56_rcopy(x,CURVE_G2x_SECP256K1);
+    BIG_256_56_rcopy(y,CURVE_G2y_SECP256K1);
+
+    ECP_SECP256K1_set(G,x,y);
+}
+
+/* Octet functions */
+
+void GG20_ZKP_proof_fromOctets(GG20_ZKP_proof *p, octet *T, octet *U)
+{
+    BIG_256_56_fromBytesLen(p->t, T->val, T->len);
+    BIG_256_56_fromBytesLen(p->u, U->val, U->len);
+}
+
+void GG20_ZKP_proof_toOctets(octet *T, octet *U, GG20_ZKP_proof *p)
+{
+    BIG_256_56_toBytes(T->val, p->t);
+    T->len = GGS_SECP256K1;
+
+    BIG_256_56_toBytes(U->val, p->u);
+    U->len = GGS_SECP256K1;
+}
+
+int GG20_ZKP_phase6_commitment_fromOctets(GG20_ZKP_phase6_commitment *c, octet *ALPHA, octet *BETA)
+{
+    if (!ECP_SECP256K1_fromOctet(&(c->ALPHA), ALPHA))
+    {
+        return GG20_ZKP_INVALID_ECP;
+    }
+
+    if (!ECP_SECP256K1_fromOctet(&(c->BETA), BETA))
+    {
+        return GG20_ZKP_INVALID_ECP;
+    }
+
+    return GG20_ZKP_OK;
+}
+
+void GG20_ZKP_phase6_commitment_toOctets(octet *ALPHA, octet *BETA, GG20_ZKP_phase6_commitment *c)
+{
+    ECP_SECP256K1_toOctet(ALPHA, &(c->ALPHA), true);
+    ECP_SECP256K1_toOctet(BETA, &(c->BETA), true);
+}
+
+/* Cleanup functions definitions */
+
+void GG20_ZKP_rv_kill(GG20_ZKP_rv *r)
+{
+    BIG_256_56_zero(r->a);
+    BIG_256_56_zero(r->b);
+}
+
+/* Phase 3 Proof Definitions */
+
+void GG20_ZKP_phase3_commit(csprng *RNG, GG20_ZKP_rv *r, octet *C)
+{
+    BIG_256_56 q;
+
+    ECP_SECP256K1 G;
+    ECP_SECP256K1 H;
+
+    ECP_SECP256K1_generator(&G);
+    GG20_ZKP_generator_2(&H);
+
+    // Read or generate secrets A, B
+    if (RNG != NULL)
+    {
+        BIG_256_56_rcopy(q, CURVE_Order_SECP256K1);
+
+        BIG_256_56_randomnum(r->a, q, RNG);
+        BIG_256_56_randomnum(r->b, q, RNG);
+    }
+
+    // Generate commitment C = a.G + b.H
+    ECP_SECP256K1_mul2(&G, &H, r->a, r->b);
+    ECP_SECP256K1_toOctet(C, &G, true);
+}
+
+void GG20_ZKP_phase3_challenge(const octet *V, const octet *C, const octet *ID, const octet *AD, octet *E)
+{
+    hash256 sha;
+
+    BIG_256_56 e;
+    BIG_256_56 q;
+    ECP_SECP256K1 G;
+
+    char o[GFS_SECP256K1 + 1];
+    octet O = {0, sizeof(o), o};
+
+    HASH256_init(&sha);
+
+    /* Bind Curve generators */
+    ECP_SECP256K1_generator(&G);
+    ECP_SECP256K1_toOctet(&O, &G, true);
+    HASH_UTILS_hash_oct(&sha, &O);
+
+    GG20_ZKP_generator_2(&G);
+    ECP_SECP256K1_toOctet(&O, &G, true);
+    HASH_UTILS_hash_oct(&sha, &O);
+
+    /* Bind Commitment */
+    HASH_UTILS_hash_oct(&sha, C);
+
+    /* Bind Proof Input */
+    HASH_UTILS_hash_oct(&sha, V);
+
+    /* Bind ID and AD */
+    HASH_UTILS_hash_i2osp4(&sha, ID->len);
+    HASH_UTILS_hash_oct(&sha, ID);
+
+    if (AD != NULL)
+    {
+        HASH_UTILS_hash_i2osp4(&sha, AD->len);
+        HASH_UTILS_hash_oct(&sha, AD);
+    }
+
+    // Compute challenge
+    BIG_256_56_rcopy(q, CURVE_Order_SECP256K1);
+    HASH_UTILS_rejection_sample_mod_BIG(&sha, q, e);
+
+    BIG_256_56_toBytes(E->val, e);
+    E->len = MODBYTES_256_56;
+}
+
+void GG20_ZKP_phase3_prove(GG20_ZKP_rv *r, const octet *E, const octet *S, const octet *L, GG20_ZKP_proof *p)
+{
+    BIG_256_56 e;
+    BIG_256_56 q;
+
+    DBIG_256_56 d;
+
+    BIG_256_56_rcopy(q, CURVE_Order_SECP256K1);
+
+    BIG_256_56_fromBytesLen(e, E->val, E->len);
+    BIG_256_56_modneg(e, e, q);
+
+    // Generate proof t = a - (e * s) mod the curve order
+    BIG_256_56_fromBytesLen(p->t, S->val, S->len);
+
+    BIG_256_56_mul(d, e, p->t);
+    BIG_256_56_dmod(p->t, d, q);
+    BIG_256_56_add(p->t, p->t, r->a);
+    BIG_256_56_mod(p->t, q);
+
+    // Generate proof u = b - (e * l) mod the curve order
+    BIG_256_56_fromBytesLen(p->u, L->val, L->len);
+
+    BIG_256_56_mul(d, e, p->u);
+    BIG_256_56_dmod(p->u, d, q);
+    BIG_256_56_add(p->u, p->u, r->b);
+    BIG_256_56_mod(p->u, q);
+
+    // Clean memory
+    BIG_256_56_dzero(d);
+}
+
+int GG20_ZKP_phase3_verify(octet *V, octet *C, const octet *E, GG20_ZKP_proof *p)
+{
+    ECP_SECP256K1 G;
+    ECP_SECP256K1 H;
+
+    BIG_256_56 e;
+
+    BIG_256_56_fromBytesLen(e, E->val, E->len);
+
+    // Compute first part of verification t.G + u.H
+    ECP_SECP256K1_generator(&G);
+    GG20_ZKP_generator_2(&H);
+    ECP_SECP256K1_mul2(&G, &H, p->t, p->u);
+
+    // Compute second part of verification e.V
+    if (!ECP_SECP256K1_fromOctet(&H, V))
+    {
+        return GG20_ZKP_INVALID_ECP;
+    }
+
+    ECP_SECP256K1_mul(&H, e);
+
+    // Combine full verification t.G + u.H + e.V
+    ECP_SECP256K1_add(&G, &H);
+
+    // Read commitment and verify
+    if (!ECP_SECP256K1_fromOctet(&H, C))
+    {
+        return GG20_ZKP_INVALID_ECP;
+    }
+
+    if (!ECP_SECP256K1_equals(&G, &H))
+    {
+        return GG20_ZKP_FAIL;
+    }
+
+    return GG20_ZKP_OK;
+}
+
+/* Phase 6 Proof Definitions */
+
+int GG20_ZKP_phase6_commit(csprng *RNG, octet *R, GG20_ZKP_rv *r, GG20_ZKP_phase6_commitment *c)
+{
+    BIG_256_56 q;
+
+    // Read or generate secrets A, B
+    if (RNG != NULL)
+    {
+        BIG_256_56_rcopy(q, CURVE_Order_SECP256K1);
+
+        BIG_256_56_randomnum(r->a, q, RNG);
+        BIG_256_56_randomnum(r->b, q, RNG);
+    }
+
+
+    // Generate commitment BETA = a.G + b.H
+    // Use ALPHA as temporary workspace
+    ECP_SECP256K1_generator(&(c->BETA));
+    GG20_ZKP_generator_2(&(c->ALPHA));
+
+    ECP_SECP256K1_mul2(&(c->BETA), &(c->ALPHA), r->a, r->b);
+
+    // Generate commitment ALPHA = a.R
+    if (!ECP_SECP256K1_fromOctet(&(c->ALPHA), R))
+    {
+        return GG20_ZKP_INVALID_ECP;
+    }
+
+    ECP_SECP256K1_mul(&(c->ALPHA), r->a);
+
+    return GG20_ZKP_OK;
+}
+
+void GG20_ZKP_phase6_challenge(const octet *R, const octet *T, const octet *S, GG20_ZKP_phase6_commitment *c, const octet *ID, const octet *AD, octet *E)
+{
+    hash256 sha;
+
+    BIG_256_56 e;
+    BIG_256_56 q;
+
+    ECP_SECP256K1 G;
+
+    char o[GFS_SECP256K1 + 1];
+    octet O = {0, sizeof(o), o};
+
+    HASH256_init(&sha);
+
+    /* Bind Curve generators */
+    ECP_SECP256K1_generator(&G);
+    ECP_SECP256K1_toOctet(&O, &G, true);
+    HASH_UTILS_hash_oct(&sha, &O);
+
+    GG20_ZKP_generator_2(&G);
+    ECP_SECP256K1_toOctet(&O, &G, true);
+    HASH_UTILS_hash_oct(&sha, &O);
+
+    /* Bind R as an additional generator */
+    HASH_UTILS_hash_oct(&sha, R);
+
+    /* Bind Commitment */
+    ECP_SECP256K1_toOctet(&O, &(c->ALPHA), true);
+    HASH_UTILS_hash_oct(&sha, &O);
+    ECP_SECP256K1_toOctet(&O, &(c->BETA), true);
+    HASH_UTILS_hash_oct(&sha, &O);
+
+    /* Bind Proof Input */
+    HASH_UTILS_hash_oct(&sha, T);
+    HASH_UTILS_hash_oct(&sha, S);
+
+    /* Bind ID and AD */
+    HASH_UTILS_hash_i2osp4(&sha, ID->len);
+    HASH_UTILS_hash_oct(&sha, ID);
+
+    if (AD != NULL)
+    {
+        HASH_UTILS_hash_i2osp4(&sha, AD->len);
+        HASH_UTILS_hash_oct(&sha, AD);
+    }
+
+    // Compute challenge
+    BIG_256_56_rcopy(q, CURVE_Order_SECP256K1);
+    HASH_UTILS_rejection_sample_mod_BIG(&sha, q, e);
+
+    BIG_256_56_toBytes(E->val, e);
+    E->len = MODBYTES_256_56;
+}
+
+void GG20_ZKP_phase6_prove(GG20_ZKP_rv *r, const octet *E, const octet *S, const octet *L, GG20_ZKP_proof *p)
+{
+    // The same values from the Phase 3 Proof can be used here
+    GG20_ZKP_phase3_prove(r, E, S, L, p);
+}
+
+int GG20_ZKP_phase6_verify(octet *R, octet *T, octet *S, GG20_ZKP_phase6_commitment *c, const octet *E, GG20_ZKP_proof *p)
+{
+    ECP_SECP256K1 G;
+    ECP_SECP256K1 H;
+
+    BIG_256_56 e;
+
+    BIG_256_56_fromBytesLen(e, E->val, E->len);
+
+    /* Compute verification for t.R + e.S =? ALPHA */
+    if (!ECP_SECP256K1_fromOctet(&G, R))
+    {
+        return GG20_ZKP_INVALID_ECP;
+    }
+
+    if (!ECP_SECP256K1_fromOctet(&H, S))
+    {
+        return GG20_ZKP_INVALID_ECP;
+    }
+
+    ECP_SECP256K1_mul2(&G, &H, p->t, e);
+
+    if (!ECP_SECP256K1_equals(&G, &(c->ALPHA)))
+    {
+        return GG20_ZKP_FAIL;
+    }
+
+    /* Compute verification for t.G + u.H + e.T =? BETA */
+
+    // Compute first part of verification t.G + u.H
+    ECP_SECP256K1_generator(&G);
+    GG20_ZKP_generator_2(&H);
+    ECP_SECP256K1_mul2(&G, &H, p->t, p->u);
+
+    // Read e and T
+    if (!ECP_SECP256K1_fromOctet(&H, T))
+    {
+        return GG20_ZKP_INVALID_ECP;
+    }
+
+    ECP_SECP256K1_mul(&H, e);
+
+    // Combine full verification t.G + u.H + e.V
+    ECP_SECP256K1_add(&G, &H);
+
+    if (!ECP_SECP256K1_equals(&G, &(c->BETA)))
+    {
+        return GG20_ZKP_FAIL;
+    }
+
+    return GG20_ZKP_OK;
+}
diff --git a/src/mta_zkp.c b/src/mta_zkp.c
new file mode 100644
index 0000000..b362be1
--- /dev/null
+++ b/src/mta_zkp.c
@@ -0,0 +1,318 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+/**
+ * @file mta_zkp.c
+ * @brief High level wrapping for the MTA proofs based on the Bit Commitment proofs
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "amcl/hash_utils.h"
+#include "amcl/mta_zkp.h"
+
+/* MTA Range Proof */
+
+void MTA_RP_commit(csprng *RNG, PAILLIER_private_key *key, BIT_COMMITMENT_pub *mod,  octet *M,  MTA_RP_rv *rv, MTA_RP_commitment *c)
+{
+    BIT_COMMITMENT_commit(RNG, key, mod, M, (BIT_COMMITMENT_rv*)rv, (BIT_COMMITMENT_commitment*)c);
+}
+
+void MTA_RP_challenge(PAILLIER_public_key *key, BIT_COMMITMENT_pub *mod, const octet *CT, MTA_RP_commitment *c, const octet *ID, const octet *AD, octet *E)
+{
+    hash256 sha;
+
+
+    BIG_256_56 q;
+    BIG_256_56 t;
+
+    HASH256_init(&sha);
+
+    /* Bind to public parameters */
+    BIT_COMMITMENT_hash_params(&sha, key, mod);
+
+    /* Bind to proof input */
+    HASH_UTILS_hash_oct(&sha, CT);
+
+    /* Bind to proof commitment */
+    BIT_COMMITMENT_hash_commitment(&sha, (BIT_COMMITMENT_commitment*)c);
+
+    /* Bind to ID and optional AD */
+    HASH_UTILS_hash_i2osp4(&sha, ID->len);
+    HASH_UTILS_hash_oct(&sha, ID);
+
+    if (AD != NULL)
+    {
+        HASH_UTILS_hash_i2osp4(&sha, AD->len);
+        HASH_UTILS_hash_oct(&sha, AD);
+    }
+
+    /* Output */
+    BIG_256_56_rcopy(q, CURVE_Order_SECP256K1);
+    HASH_UTILS_rejection_sample_mod_BIG(&sha, q, t);
+
+    BIG_256_56_toBytes(E->val, t);
+    E->len = EGS_SECP256K1;
+}
+
+void MTA_RP_prove(PAILLIER_private_key *key, octet *M, octet *R, MTA_RP_rv *rv, octet *E, MTA_RP_proof *p)
+{
+    BIT_COMMITMENT_prove(key, M, R, (BIT_COMMITMENT_rv*)rv, E, (BIT_COMMITMENT_proof*)p);
+}
+
+int MTA_RP_verify(PAILLIER_public_key *key, BIT_COMMITMENT_priv *mod, octet *CT, MTA_RP_commitment *c, octet *E, MTA_RP_proof *p)
+{
+    return BIT_COMMITMENT_verify(key, mod, CT, (BIT_COMMITMENT_commitment*)c, E, (BIT_COMMITMENT_proof*) p);
+}
+
+void MTA_RP_commitment_toOctets(octet *Z, octet *U, octet *W, MTA_RP_commitment *c)
+{
+    BIT_COMMITMENT_commitment_toOctets(Z, U, W, (BIT_COMMITMENT_commitment*)c);
+}
+
+void MTA_RP_commitment_fromOctets(MTA_RP_commitment *c, octet *Z, octet *U, octet *W)
+{
+    BIT_COMMITMENT_commitment_fromOctets((BIT_COMMITMENT_commitment*)c, Z, U, W);
+}
+
+void MTA_RP_proof_toOctets(octet *S, octet *S1, octet *S2, MTA_RP_proof *p)
+{
+    BIT_COMMITMENT_proof_toOctets(S, S1, S2, (BIT_COMMITMENT_proof*)p);
+}
+
+void MTA_RP_proof_fromOctets(MTA_RP_proof *p, octet *S, octet *S1, octet *S2)
+{
+    BIT_COMMITMENT_proof_fromOctets((BIT_COMMITMENT_proof*)p, S, S1, S2);
+}
+
+void MTA_RP_rv_kill(MTA_RP_rv *rv)
+{
+    BIT_COMMITMENT_rv_kill((BIT_COMMITMENT_rv*)rv);
+}
+
+
+/* MTA Receiver Proof */
+
+void MTA_ZK_commit(csprng *RNG, PAILLIER_public_key *key, BIT_COMMITMENT_pub *mod,  octet *X, octet *Y, octet *C1, MTA_ZK_rv *rv, MTA_ZK_commitment *c)
+{
+    BIT_COMMITMENT_muladd_commit(RNG, key, mod, X, Y, C1, (BIT_COMMITMENT_muladd_rv*)rv, (BIT_COMMITMENT_muladd_commitment*)c);
+}
+
+void MTA_ZK_challenge(PAILLIER_public_key *key, BIT_COMMITMENT_pub *mod, const octet *C1, const octet *C2, MTA_ZK_commitment *c, const octet *ID, const octet *AD, octet *E)
+{
+    hash256 sha;
+
+    BIG_256_56 q;
+    BIG_256_56 t;
+
+    HASH256_init(&sha);
+
+    /* Bind to public parameters */
+    BIT_COMMITMENT_hash_params(&sha, key, mod);
+
+    /* Bind to proof input */
+    HASH_UTILS_hash_oct(&sha, C1);
+    HASH_UTILS_hash_oct(&sha, C2);
+
+    /* Bind to proof commitment */
+    BIT_COMMITMENT_hash_muladd_commitment(&sha, c);
+
+    /* Bind to ID and optional AD */
+    HASH_UTILS_hash_i2osp4(&sha, ID->len);
+    HASH_UTILS_hash_oct(&sha, ID);
+
+    if (AD != NULL)
+    {
+        HASH_UTILS_hash_i2osp4(&sha, AD->len);
+        HASH_UTILS_hash_oct(&sha, AD);
+    }
+
+    /* Output */
+    BIG_256_56_rcopy(q, CURVE_Order_SECP256K1);
+    HASH_UTILS_rejection_sample_mod_BIG(&sha, q, t);
+
+    BIG_256_56_toBytes(E->val, t);
+    E->len = EGS_SECP256K1;
+}
+
+void MTA_ZK_prove(PAILLIER_public_key *key, octet *X, octet *Y, octet *R, MTA_ZK_rv *rv, octet *E, MTA_ZK_proof *p)
+{
+    BIT_COMMITMENT_muladd_prove(key, X, Y, R, (BIT_COMMITMENT_muladd_rv*)rv, E, (BIT_COMMITMENT_muladd_proof*)p);
+}
+
+int MTA_ZK_verify(PAILLIER_private_key *key, BIT_COMMITMENT_priv *mod, octet *C1, octet *C2, MTA_ZK_commitment *c, octet *E, MTA_ZK_proof *p)
+{
+    return BIT_COMMITMENT_muladd_verify(key, mod, C1, C2, (BIT_COMMITMENT_muladd_commitment *)c, E, (BIT_COMMITMENT_muladd_proof*)p);
+}
+
+void MTA_ZK_commitment_toOctets(octet *Z, octet *Z1, octet *T, octet *V, octet *W, MTA_ZK_commitment *c)
+{
+    BIT_COMMITMENT_muladd_commitment_toOctets(Z, Z1, T, V, W, c);
+}
+
+void MTA_ZK_commitment_fromOctets(MTA_ZK_commitment *c, octet *Z, octet *Z1, octet *T, octet *V, octet *W)
+{
+    BIT_COMMITMENT_muladd_commitment_fromOctets(c, Z, Z1, T, V, W);
+}
+
+void MTA_ZK_proof_toOctets(octet *S, octet *S1, octet *S2, octet *T1, octet *T2, MTA_ZK_proof *p)
+{
+    BIT_COMMITMENT_muladd_proof_toOctets(S, S1, S2, T1, T2, p);
+}
+
+void MTA_ZK_proof_fromOctets(MTA_ZK_proof *p, octet *S, octet *S1, octet *S2, octet *T1, octet *T2)
+{
+    BIT_COMMITMENT_muladd_proof_fromOctets(p, S, S1, S2, T1, T2);
+}
+
+void MTA_ZK_rv_kill(MTA_ZK_rv *rv)
+{
+    BIT_COMMITMENT_muladd_rv_kill(rv);
+}
+
+/* MTA Receiver Proof with check for known DLOG */
+
+void MTA_ZKWC_commit(csprng *RNG, PAILLIER_public_key *key, BIT_COMMITMENT_pub *mod, octet *X, octet *Y, octet *C1, MTA_ZKWC_rv *rv, MTA_ZKWC_commitment *c)
+{
+    /* Compute base commitment for the range and knowledge ZKP */
+    BIT_COMMITMENT_muladd_commit(RNG, key, mod, X, Y, C1, (BIT_COMMITMENT_muladd_rv*)rv, &(c->mc));
+
+    /* Compute commitment for DLOG knowledge ZKP */
+    ECP_SECP256K1_generator(&(c->U));
+    BIT_COMMITMENT_ECP_commit(&(c->U), rv->alpha);
+}
+
+void MTA_ZKWC_challenge(PAILLIER_public_key *key, BIT_COMMITMENT_pub *mod, const octet *C1, const octet *C2, const octet *X, MTA_ZKWC_commitment *c, const octet *ID, const octet *AD, octet *E)
+{
+    hash256 sha;
+
+    char oct[EFS_SECP256K1 + 1];
+    octet OCT = {0, sizeof(oct), oct};
+
+    ECP_SECP256K1 G;
+
+    BIG_256_56 q;
+    BIG_256_56 t;
+
+    HASH256_init(&sha);
+
+    /* Bind to public parameters */
+    BIT_COMMITMENT_hash_params(&sha, key, mod);
+
+    // Bind to Curve generator
+    ECP_SECP256K1_generator(&G);
+    ECP_SECP256K1_toOctet(&OCT, &G, true);
+    HASH_UTILS_hash_oct(&sha, &OCT);
+
+    /* Bind to proof input */
+    HASH_UTILS_hash_oct(&sha, C1);
+    HASH_UTILS_hash_oct(&sha, C2);
+    HASH_UTILS_hash_oct(&sha, X);
+
+    /* Bind to proof commitment for DLOG */
+    ECP_SECP256K1_toOctet(&OCT, &(c->U), true);
+    HASH_UTILS_hash_oct(&sha, &OCT);
+
+    /* Bind to proof commitment for muladd ZKP */
+    BIT_COMMITMENT_hash_muladd_commitment(&sha, &(c->mc));
+
+    /* Bind to ID and optional AD */
+    HASH_UTILS_hash_i2osp4(&sha, ID->len);
+    HASH_UTILS_hash_oct(&sha, ID);
+
+    if (AD != NULL)
+    {
+        HASH_UTILS_hash_i2osp4(&sha, AD->len);
+        HASH_UTILS_hash_oct(&sha, AD);
+    }
+
+    /* Output */
+    BIG_256_56_rcopy(q, CURVE_Order_SECP256K1);
+    HASH_UTILS_rejection_sample_mod_BIG(&sha, q, t);
+
+    BIG_256_56_toBytes(E->val, t);
+    E->len = EGS_SECP256K1;
+}
+
+void MTA_ZKWC_prove(PAILLIER_public_key *key, octet *X, octet *Y, octet *R, MTA_ZKWC_rv *rv, octet *E, MTA_ZKWC_proof *p)
+{
+    BIT_COMMITMENT_muladd_prove(key, X, Y, R, (BIT_COMMITMENT_muladd_rv*)rv, E, (BIT_COMMITMENT_muladd_proof*)p);
+}
+
+int MTA_ZKWC_verify(PAILLIER_private_key *key, BIT_COMMITMENT_priv *mod, octet *C1, octet *C2, octet *X, MTA_ZKWC_commitment *c, octet *E, MTA_ZKWC_proof *p)
+{
+    int rc;
+
+    ECP_SECP256K1 x;
+    ECP_SECP256K1 g;
+
+    ECP_SECP256K1_generator(&g);
+
+    // Terminate early in case of invalid input
+    rc = ECP_SECP256K1_fromOctet(&x, X);
+    if (rc != 1)
+    {
+        return MTA_INVALID_ECP;
+    }
+
+    /* Verify additional DLOG proof */
+    rc = BIT_COMMITMENT_ECP_verify(&g, &x, &(c->U), E, p->s1);
+    if (rc != BIT_COMMITMENT_OK)
+    {
+        return rc;
+    }
+
+    /* Verify muladd proof*/
+    return BIT_COMMITMENT_muladd_verify(key, mod, C1, C2, &(c->mc), E, p);
+}
+
+void MTA_ZKWC_commitment_toOctets(octet *U, octet *Z, octet *Z1, octet *T, octet *V, octet *W, MTA_ZKWC_commitment *c)
+{
+    BIT_COMMITMENT_muladd_commitment_toOctets(Z, Z1, T, V, W, &(c->mc));
+    ECP_SECP256K1_toOctet(U, &(c->U), true);
+}
+
+int MTA_ZKWC_commitment_fromOctets(MTA_ZKWC_commitment *c, octet *U, octet *Z, octet *Z1, octet *T, octet *V, octet *W)
+{
+    if (ECP_SECP256K1_fromOctet(&(c->U), U) != 1)
+    {
+        return MTA_INVALID_ECP;
+    }
+
+    BIT_COMMITMENT_muladd_commitment_fromOctets(&(c->mc), Z, Z1, T, V, W);
+
+    return MTA_OK;
+}
+
+void MTA_ZKWC_proof_toOctets(octet *S, octet *S1, octet *S2, octet *T1, octet *T2, MTA_ZKWC_proof *p)
+{
+    BIT_COMMITMENT_muladd_proof_toOctets(S, S1, S2, T1, T2, p);
+}
+
+void MTA_ZKWC_proof_fromOctets(MTA_ZKWC_proof *p, octet *S, octet *S1, octet *S2, octet *T1, octet *T2)
+{
+    BIT_COMMITMENT_muladd_proof_fromOctets(p, S, S1, S2, T1, T2);
+}
+
+void MTA_ZKWC_rv_kill(MTA_ZKWC_rv *rv)
+{
+    BIT_COMMITMENT_muladd_rv_kill(rv);
+}
diff --git a/src/schnorr.c b/src/schnorr.c
index 4e72740..cd831c1 100644
--- a/src/schnorr.c
+++ b/src/schnorr.c
@@ -18,16 +18,7 @@ under the License.
 */
 
 #include "amcl/schnorr.h"
-
-static void hash_octet(hash256 *sha, const octet *O)
-{
-    int i;
-
-    for (i = 0; i < O->len; i++)
-    {
-        HASH256_process(sha, O->val[i]);
-    }
-}
+#include "amcl/hash_utils.h"
 
 void SCHNORR_random_challenge(csprng *RNG, octet *E)
 {
@@ -93,20 +84,20 @@ void SCHNORR_challenge(const octet *V, const octet *C, const octet *ID, const oc
 
     // e = H(G,C,V,ID,AD) mod q
     HASH256_init(&sha);
-    hash_octet(&sha, &O);
-    hash_octet(&sha, C);
-    hash_octet(&sha, V);
-    hash_octet(&sha, ID);
+    HASH_UTILS_hash_oct(&sha, &O);
+    HASH_UTILS_hash_oct(&sha, C);
+    HASH_UTILS_hash_oct(&sha, V);
+
+    HASH_UTILS_hash_i2osp4(&sha, ID->len);
+    HASH_UTILS_hash_oct(&sha, ID);
 
     if (AD != NULL)
     {
-        hash_octet(&sha, AD);
+        HASH_UTILS_hash_i2osp4(&sha, AD->len);
+        HASH_UTILS_hash_oct(&sha, AD);
     }
 
-    HASH256_hash(&sha, o);
-
-    BIG_256_56_fromBytesLen(e, o, SHA256);
-    BIG_256_56_mod(e, q);
+    HASH_UTILS_rejection_sample_mod_BIG(&sha, q, e);
 
     BIG_256_56_toBytes(E->val, e);
     E->len = SGS_SECP256K1;
@@ -244,21 +235,21 @@ void SCHNORR_D_challenge(const octet *R, const octet *V, const octet *C, const o
 
     // e = H(G,R,C,V,ID,AD) mod q
     HASH256_init(&sha);
-    hash_octet(&sha, &O);
-    hash_octet(&sha, R);
-    hash_octet(&sha, C);
-    hash_octet(&sha, V);
-    hash_octet(&sha, ID);
+    HASH_UTILS_hash_oct(&sha, &O);
+    HASH_UTILS_hash_oct(&sha, R);
+    HASH_UTILS_hash_oct(&sha, C);
+    HASH_UTILS_hash_oct(&sha, V);
+
+    HASH_UTILS_hash_i2osp4(&sha, ID->len);
+    HASH_UTILS_hash_oct(&sha, ID);
 
     if (AD != NULL)
     {
-        hash_octet(&sha, AD);
+        HASH_UTILS_hash_i2osp4(&sha, AD->len);
+        HASH_UTILS_hash_oct(&sha, AD);
     }
 
-    HASH256_hash(&sha, o);
-
-    BIG_256_56_fromBytesLen(e, o, SHA256);
-    BIG_256_56_mod(e, q);
+    HASH_UTILS_rejection_sample_mod_BIG(&sha, q, e);
 
     BIG_256_56_toBytes(E->val, e);
     E->len = MODBYTES_256_56;
@@ -275,24 +266,26 @@ void SCHNORR_D_prove(const octet *A, const octet *B, const octet *E, const octet
     BIG_256_56_rcopy(q, CURVE_Order_SECP256K1);
     BIG_256_56_fromBytesLen(e, E->val, E->len);
 
-    // Generate proof t = a + (e * s) mod the curve order
+    // Generate proof t = a - (e * s) mod the curve order
     BIG_256_56_fromBytesLen(x, S->val, S->len);
     BIG_256_56_fromBytesLen(r, A->val, A->len);
 
     BIG_256_56_mul(d, e, x);
     BIG_256_56_dmod(x, d, q);
+    BIG_256_56_modneg(x, x, q);
     BIG_256_56_add(x, x, r);
     BIG_256_56_mod(x, q);
 
     BIG_256_56_toBytes(T->val, x);
     T->len = SGS_SECP256K1;
 
-    // Generate proof u = b + (e * l) mod the curve order
+    // Generate proof u = b - (e * l) mod the curve order
     BIG_256_56_fromBytesLen(x, L->val, L->len);
     BIG_256_56_fromBytesLen(r, B->val, B->len);
 
     BIG_256_56_mul(d, e, x);
     BIG_256_56_dmod(x, d, q);
+    BIG_256_56_modneg(x, x, q);
     BIG_256_56_add(x, x, r);
     BIG_256_56_mod(x, q);
 
@@ -333,16 +326,15 @@ int SCHNORR_D_verify(octet *R, octet *V, octet *C, const octet *E, const octet *
     BIG_256_56_fromBytesLen(t, T->val, T->len);
     BIG_256_56_fromBytesLen(u, U->val, U->len);
 
-    // Compute verification t.R + u.G
+    // Compute verification t.R + u.G + e.V
     ECP_SECP256K1_generator(&G);
     ECP_SECP256K1_mul2(&ECPR, &G, t, u);
 
-    // Compute ground truth C + e.V
     BIG_256_56_fromBytesLen(t, E->val, E->len);
     ECP_SECP256K1_mul(&ECPV, t);
-    ECP_SECP256K1_add(&ECPV, &ECPC);
+    ECP_SECP256K1_add(&ECPR, &ECPV);
 
-    if (!ECP_SECP256K1_equals(&ECPV, &ECPR))
+    if (!ECP_SECP256K1_equals(&ECPC, &ECPR))
     {
         return SCHNORR_FAIL;
     }
diff --git a/test/smoke/test_gg20_zkp_phase3_smoke.c b/test/smoke/test_gg20_zkp_phase3_smoke.c
new file mode 100644
index 0000000..c8712b1
--- /dev/null
+++ b/test/smoke/test_gg20_zkp_phase3_smoke.c
@@ -0,0 +1,102 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+#include "amcl/gg20_zkp.h"
+#include "amcl/mpc.h"
+
+void big_245_56_cleaned(BIG_256_56 a, char *name)
+{
+    if (!BIG_256_56_iszilch(a))
+    {
+        printf("FAILURE GG20_ZKP_rv_kill. %s is not clean.\n", name);
+        exit(EXIT_FAILURE);
+    }
+}
+
+/* GG20 Phase 3 ZKP smoke test */
+
+int main()
+{
+    int rc;
+
+    BIG_256_56 s;
+    BIG_256_56 q;
+
+    GG20_ZKP_rv    r;
+    GG20_ZKP_proof p;
+
+    char id[32];
+    octet ID = {0, sizeof(id), id};
+
+    char ad[32];
+    octet AD = {0, sizeof(ad), ad};
+
+    char oct_s[GGS_SECP256K1];
+    octet S = {0, sizeof(oct_s), oct_s};
+
+    char oct_l[GGS_SECP256K1];
+    octet L = {0, sizeof(oct_l), oct_l};
+
+    char v[GFS_SECP256K1+1];
+    octet V = {0, sizeof(v), v};
+
+    char c[GFS_SECP256K1+1];
+    octet C = {0, sizeof(c), c};
+
+    char e[GGS_SECP256K1];
+    octet E = {0, sizeof(e), e};
+
+    // Deterministic RNG for testing
+    char seed[32] = {0};
+    csprng RNG;
+    RAND_seed(&RNG, 32, seed);
+
+    // Generate ID and AD
+    OCT_rand(&ID, &RNG, ID.len);
+    OCT_rand(&AD, &RNG, AD.len);
+
+    // Generate s, l and compute V = s.G + l.H
+    BIG_256_56_rcopy(q, CURVE_Order_SECP256K1);
+    BIG_256_56_randomnum(s, q, &RNG);
+
+    BIG_256_56_toBytes(S.val, s);
+    S.len = GGS_SECP256K1;
+
+    MPC_PHASE3_T(&RNG, &S, &L, &V);
+
+    // Run test
+    GG20_ZKP_phase3_commit(&RNG, &r, &C);
+    GG20_ZKP_phase3_challenge(&V, &C, &ID, &AD, &E);
+    GG20_ZKP_phase3_prove(&r, &E, &S, &L, &p);
+
+    rc = GG20_ZKP_phase3_verify(&V, &C, &E, &p);
+    if (rc != GG20_ZKP_OK)
+    {
+        printf("FAILURE GG20_ZKP_phase3_verify. rc %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    // Clean memory
+    GG20_ZKP_rv_kill(&r);
+    big_245_56_cleaned(r.a, "a");
+    big_245_56_cleaned(r.b, "b");
+
+    printf("SUCCESS\n");
+    exit(EXIT_SUCCESS);
+}
\ No newline at end of file
diff --git a/test/smoke/test_gg20_zkp_phase6_smoke.c b/test/smoke/test_gg20_zkp_phase6_smoke.c
new file mode 100644
index 0000000..1e41f27
--- /dev/null
+++ b/test/smoke/test_gg20_zkp_phase6_smoke.c
@@ -0,0 +1,124 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+#include "amcl/gg20_zkp.h"
+#include "amcl/mpc.h"
+
+void big_245_56_cleaned(BIG_256_56 a, char *name)
+{
+    if (!BIG_256_56_iszilch(a))
+    {
+        printf("FAILURE GG20_ZKP_rv_kill. %s is not clean.\n", name);
+        exit(EXIT_FAILURE);
+    }
+}
+
+/* GG20 Phase 6 ZKP smoke test */
+
+int main()
+{
+    int rc;
+
+    BIG_256_56 s;
+    BIG_256_56 l;
+    BIG_256_56 q;
+
+    ECP_SECP256K1 G;
+
+    GG20_ZKP_rv                rv;
+    GG20_ZKP_phase6_commitment c;
+    GG20_ZKP_proof             p;
+
+    char id[32];
+    octet ID = {0, sizeof(id), id};
+
+    char ad[32];
+    octet AD = {0, sizeof(ad), ad};
+
+    char oct_s[GGS_SECP256K1];
+    octet S = {0, sizeof(oct_s), oct_s};
+
+    char oct_l[GGS_SECP256K1];
+    octet L = {0, sizeof(oct_l), oct_l};
+
+    char r[GFS_SECP256K1+1];
+    octet R = {0, sizeof(r), r};
+
+    char t[GFS_SECP256K1+1];
+    octet T = {0, sizeof(t), t};
+
+    char ecps[GFS_SECP256K1+1];
+    octet ECPS = {0, sizeof(ecps), ecps};
+
+    char e[GGS_SECP256K1];
+    octet E = {0, sizeof(e), e};
+
+    // Deterministic RNG for testing
+    char seed[32] = {0};
+    csprng RNG;
+    RAND_seed(&RNG, 32, seed);
+
+    // Generate ID and AD
+    OCT_rand(&ID, &RNG, ID.len);
+    OCT_rand(&AD, &RNG, AD.len);
+
+    // Generate s, l and compute V = s.G + l.H
+    BIG_256_56_rcopy(q, CURVE_Order_SECP256K1);
+    BIG_256_56_randomnum(s, q, &RNG);
+
+    BIG_256_56_toBytes(S.val, s);
+    S.len = GGS_SECP256K1;
+
+    MPC_PHASE3_T(&RNG, &S, &L, &T);
+
+    // Generate R and S = s.R
+    BIG_256_56_randomnum(l, q, &RNG);
+
+    ECP_SECP256K1_generator(&G);
+    ECP_SECP256K1_mul(&G, l);
+    ECP_SECP256K1_toOctet(&R, &G, true);
+
+    MPC_ECP_GENERATE_CHECK(&R, &S, &ECPS);
+
+    // Run test
+    rc = GG20_ZKP_phase6_commit(&RNG, &R, &rv, &c);
+    if (rc != GG20_ZKP_OK)
+    {
+        printf("FAILURE GG20_ZKP_phase6_commit. rc %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    GG20_ZKP_phase6_challenge(&R, &T, &ECPS, &c, &ID, &AD, &E);
+    GG20_ZKP_phase6_prove(&rv, &E, &S, &L, &p);
+
+    rc = GG20_ZKP_phase6_verify(&R, &T, &ECPS, &c, &E, &p);
+    if (rc != GG20_ZKP_OK)
+    {
+        printf("FAILURE GG20_ZKP_phase6_verify. rc %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    // Clean memory
+    GG20_ZKP_rv_kill(&rv);
+    big_245_56_cleaned(rv.a, "a");
+    big_245_56_cleaned(rv.b, "b");
+
+    printf("SUCCESS\n");
+    exit(EXIT_SUCCESS);
+}
\ No newline at end of file
diff --git a/test/test.c b/test/test.c
index 0e84760..15e0862 100644
--- a/test/test.c
+++ b/test/test.c
@@ -45,6 +45,62 @@ void read_OCTET(FILE *fp, octet *OCT, char *string)
     OCT_fromHex(OCT, buff);
 }
 
+void read_OCTET_ARRAY(FILE *fp, octet *OCT_ARRAY, char *string, int n)
+{
+    int i;
+    char *next, *end;
+
+    if (string[0] != '[')
+    {
+        fclose(fp);
+
+        printf("ERROR unexpected character at position 0 at %s\n", string);
+        exit(EXIT_FAILURE);
+    }
+
+    next = string+1;
+
+    for (i = 0; i < n-1; i++)
+    {
+        end = strchr(next, ',');
+        if (end == NULL)
+        {
+            fclose(fp);
+
+            printf("ERROR separator not found at octet %d at %s\n", i, next);
+            exit(EXIT_FAILURE);
+        }
+        *end = '\0';
+
+        OCT_fromHex(OCT_ARRAY+i, next);
+
+        next = end+1;
+    }
+
+    end = strchr(next, ']');
+    if (end == NULL)
+    {
+        fclose(fp);
+
+        printf("ERROR unexpected closing character at %s\n", next);
+        exit(EXIT_FAILURE);
+    }
+
+    *end = '\0';
+
+    OCT_fromHex(OCT_ARRAY+n-1, next);
+}
+
+void read_BIG_256_56(FILE *fp, BIG_256_56 x, char *string)
+{
+    int len = strlen(string);
+    char oct[len/2];
+    octet OCT = {0, sizeof(oct), oct};
+
+    read_OCTET(fp, &OCT, string);
+    BIG_256_56_fromBytesLen(x, OCT.val, OCT.len);
+}
+
 void read_FF_2048(FILE *fp, BIG_1024_58 *x, char *string, int n)
 {
     int len = strlen(string);
@@ -121,6 +177,30 @@ void scan_OCTET(FILE *fp, octet *OCT, char *line, const char *prefix)
     }
 }
 
+void scan_OCTET_ARRAY(FILE *fp, octet *OCT_ARRAY, char *line, const char *prefix, int n)
+{
+    if (!strncmp(line, prefix, strlen(prefix)))
+    {
+        line+=strlen(prefix);
+        read_OCTET_ARRAY(fp, OCT_ARRAY, line, n);
+    }
+}
+
+void scan_BIG_256_56(FILE *fp, BIG_256_56 x, char *line, const char *prefix)
+{
+    if (!strncmp(line, prefix, strlen(prefix)))
+    {
+        line+=strlen(prefix);
+        read_BIG_256_56(fp, x, line);
+
+#ifdef DEBUG
+        printf("%s", prefix);
+        BIG_256_56_output(x);
+        printf("\n");
+#endif
+    }
+}
+
 void scan_FF_2048(FILE *fp, BIG_1024_58 *x, char *line, const char *prefix, int n)
 {
     if (!strncmp(line, prefix, strlen(prefix)))
@@ -155,7 +235,6 @@ void scan_ECP_SECP256K1(FILE *fp, ECP_SECP256K1 *P, char *line, const char *pref
 {
     if (!strncmp(line, prefix, strlen(prefix)))
     {
-
         line+=strlen(prefix);
         read_ECP_SECP256K1(fp, P, line);
 
@@ -215,6 +294,29 @@ void compare_OCT(FILE* fp, int testNo, char *name, octet *X, octet *Y)
     }
 }
 
+void compare_BIG_256_56(FILE* fp, int testNo, char* name, BIG_256_56 x, BIG_256_56 y)
+{
+    if(BIG_256_56_comp(x, y))
+    {
+        if (fp != NULL)
+        {
+            fclose(fp);
+        }
+
+        fprintf(stderr, "FAILURE %s. Test %d\n", name, testNo);
+
+#ifdef DEBUG
+        printf("x = ");
+        BIG_256_56_output(x);
+        printf("\ny = ");
+        BIG_256_56_output(y);
+        printf("\n");
+#endif
+
+        exit(EXIT_FAILURE);
+    }
+}
+
 void compare_FF_2048(FILE* fp, int testNo, char* name, BIG_1024_58 *x, BIG_1024_58 *y, int n)
 {
     if(FF_2048_comp(x, y, n))
diff --git a/test/test.h b/test/test.h
index 98bbe13..e8d1d77 100644
--- a/test/test.h
+++ b/test/test.h
@@ -42,7 +42,24 @@ extern "C"
  *  @param  OCT     Output octet
  *  @param  string  Input string
  */
-void read_OCTET(FILE *fp, octet *OCT, char *string);
+extern void read_OCTET(FILE *fp, octet *OCT, char *string);
+
+/*! \brief Read string into an octet array
+ *
+ *  @param  fp        TV file pointer to close in case of error
+ *  @param  OCT_ARRAY Output octet
+ *  @param  string    Input string
+ *  @param  n         Length of the array to read
+ */
+extern void read_OCTET_ARRAY(FILE *fp, octet *OCT_ARRAY, char *string, int n);
+
+/*! \brief Read string into a big_256_56
+ *
+ *  @param  fp      TV file pointer to close in case of error
+ *  @param  x       Output big
+ *  @param  string  Input string
+ */
+extern void read_BIG_256_56(FILE *fp, BIG_256_56 x, char *string);
 
 /*! \brief Read string into an ff_2048
  *
@@ -95,6 +112,25 @@ extern void scan_int(int *v, char *line, const char *prefix);
  */
 extern void scan_OCTET(FILE *fp, octet *OCT, char *line, const char *prefix);
 
+/*! \brief Read octet array if the line has the correct prefix
+ *
+ *  @param  fp        TV file pointer to close in case of error
+ *  @param  OCT_ARRAY Output octet array
+ *  @param  line      TV line
+ *  @param  prefix    Line prefix for the octet to read
+ *  @param  n         Length of the array to read
+ */
+extern void scan_OCTET_ARRAY(FILE *fp, octet *OCT_ARRAY, char *line, const char *prefix, int n);
+
+/*! \brief Read big_256_56 if the line has the correct prefix
+ *
+ *  @param  fp      TV file pointer to close in case of error
+ *  @param  x       Output big
+ *  @param  line    TV line
+ *  @param  prefix  Line prefix for the element to read
+ */
+extern void scan_BIG_256_56(FILE *fp, BIG_256_56 x, char *line, const char *prefix);
+
 /*! \brief Read ff_2048 element if the line has the correct prefix
  *
  *  @param  fp      TV file pointer to close in case of error
@@ -147,6 +183,18 @@ extern void scan_HDLOG_iv(FILE *fp, HDLOG_iter_values V, char *line, const char
  */
 extern void compare_OCT(FILE *fp, int testNo, char *name, octet *X, octet *Y);
 
+/*! \brief Compare two big_256_56 elements
+ *
+ *  Compare two big_s and fail the test if they are not equal
+ *
+ *  @param  fp      TV file pointer to close in case of failure
+ *  @param  testNo  Test Vector identifier
+ *  @param  name    Descriptor for the elements compared
+ *  @param  x       First element to compare
+ *  @param  y       Second element to compare
+ */
+extern void compare_BIG_256_56(FILE *fp, int testNo, char* name, BIG_256_56 x, BIG_256_56 y);
+
 /*! \brief Compare two ff_2048 elements
  *
  *  Compare two ff_2048 elements and fail the test if they are not equal
diff --git a/testVectors/gg20_zkp/octets.txt b/testVectors/gg20_zkp/octets.txt
new file mode 100644
index 0000000..664c0e4
--- /dev/null
+++ b/testVectors/gg20_zkp/octets.txt
@@ -0,0 +1,59 @@
+TEST = 0,
+ALPHA = 02c6fb6f18f732f8906b11690c41c412103d95e12cb9bf974d10b0239baeeffd3c,
+BETA = 02893028961112ee8c139e6c1991249b737434215d50bd9edabcede1aff24b2afa,
+T = 66acee60b6318fcdbecddd22ef73589e61b8ab63432aa4927898539f93687728,
+U = 2600691de9fb297862476be002ad22a9c5b697f1237793c132bbc8555aab4849,
+
+TEST = 1,
+ALPHA = 033efe70bc113af12c6e1a1e4804a5d6140e36da8438fd238c5245420d46035cb4,
+BETA = 03b0df256256a4d1ebabd3d088f785fa4256e35b15d87c8118982a382eae9a5fd5,
+T = 81fd655525685886f9bb8fef01f00bac1370e1da5872054447a069c2b45a7e9b,
+U = 6910582b4cefb1621e8d09d789cf4342b26b9b077463aaab2fd62aaf5e92f5a7,
+
+TEST = 2,
+ALPHA = 02a58b93a867ef13d8c4ece3c1fd7d88b1ee4fb7b0ae88fd644ca65fa9bbaaa91a,
+BETA = 02bdb475ba532e8e4bdc75c8d3da665524e16897646f133ff1f46debb23db518cd,
+T = 941f3cc74204fc2811f5aa31f33b8e2c5bef4958448c4aa200cee38c4b592206,
+U = 2a5f42f32f32399f69844a4e2bc04cb69d65d69c92e96178e44cced18ac8e167,
+
+TEST = 3,
+ALPHA = 024a9d38c6dd6464dfd5f1c48b54a93d1dbefbc9df6c5d73ed484eb5d2ed2c39ac,
+BETA = 039674b4d13d3fd8bd969959cc69a93b459e9db4cdd93760ee0392ea9c4abeb802,
+T = 34a6c9e13a4e02dc86e248af2a48c5ef8980031d8ebbe316bfbe5e6637db56d8,
+U = 36ba7fa7b2823c14bd756ecd7c06f75195529a5a6b8b945b319ca00558332274,
+
+TEST = 4,
+ALPHA = 0358491775a269318fde1a684fda434c5362d14cfd3cd00dbc625d1f50dbd9f6e8,
+BETA = 037977bcdb620361355bf7d9d29689d90a5fb5a4766905275b9b6ddb31cc4b673d,
+T = ee673c77d320e127ea49093b23d169f6c4345e6d26e65d4499097d208bfaa87b,
+U = 6ecde180aa8a032d7a4b28993e44fc880d83fca83c1cc7831190989c42dd941e,
+
+TEST = 5,
+ALPHA = 02a9f78b24582fa72c45027682e6c578266cfe0087563f03e49a6ab6eba94ae0e6,
+BETA = 03c4ca090151d7a4c1cb178835ff43e4d0e1a93f6efb25661399fd1ed0b43bb98a,
+T = b12bd41c9d68375ea89dd6e20c410175c3812f4251756345d6a66460fa6f89fa,
+U = ddc340dc4f5e73bc95ef16ca641571a4252dab6e620d4e15b476727ec24cc233,
+
+TEST = 6,
+ALPHA = 0337f7a55ec8ecc01d4ec8d9b5c13b671832cf11aceb405f7b1476d2ba46a957fd,
+BETA = 02894aed53ee60156b0cf61d71647424d2cc80de8dde6659a2a04c81073246f2cc,
+T = b1e8f902af4db8af60d5a2f84db34e4bf87ec381a3d1cdee7806c38f978da505,
+U = 2d54c4b7802b98456a9995af65696bb821352cceec9b496304f6c4f3601f02ea,
+
+TEST = 7,
+ALPHA = 0229012eede68a4b0fb89d41c45123567b689de83977e0d4eee23197352051a458,
+BETA = 02132c61a945337a7b9770a9633c7961a64cc0af4d2532ce3412aefeed2e0e796d,
+T = d932de6113c941ac01a12fff7e6fd6700b4d7fb5293559ea6e99b6a61ef213af,
+U = 2074cf4cc1683f5518af734558abab4b41a07b87449fa199896660f978badcbf,
+
+TEST = 8,
+ALPHA = 027dc0edd1eec628621c8210a6749f165a1d9c4fc34d2a8324db59b29a3aea17c5,
+BETA = 033d16586629c904d6fc6e9ed0f28fd0fc7a2f82fb33eedabf980c0b68a53dc2c0,
+T = d5c4fa580680643afdd91650cde82a4a417120adecd04c67d98f7d1254f3b38b,
+U = ddf7c9345fd0590affa8e7b6ef7d56929b097ef16e0c63a7c85a5dd437928775,
+
+TEST = 9,
+ALPHA = 02057f0324b16eddaefde206a00ad6cac24b33ff4b9db9512168485016e557ab30,
+BETA = 036f4486b6f8d2b591ad1f2acdef02dfe6d59f9f933a56e0da30a39d67a5e6aa6e,
+T = 625e09fa9aeb0144f99cf6df869938f3132c4bcba72804d0ab627b35ffd0c19e,
+U = 9c0bf3c5d4a6b0a5933184fffd0365ba4bc72c1a526ca2c7d0d8f4b5d7ca48b0,
diff --git a/testVectors/gg20_zkp/phase3_challenge.json b/testVectors/gg20_zkp/phase3_challenge.json
new file mode 100644
index 0000000..09a44bf
--- /dev/null
+++ b/testVectors/gg20_zkp/phase3_challenge.json
@@ -0,0 +1,82 @@
+[
+  {
+    "TEST": 0,
+    "V": "02e03da4554a06bb9f90cc5d77edcdcc69d96a707f6d8191a8c6fbe8044cb4f363",
+    "C": "034eaa5630192ece97b664c54ab8b111c48f964b263170500b9e109b8fb85d85c3",
+    "ID": "f65b3c27e5698be4ea94d95ce5259ef2",
+    "AD": "",
+    "E": "a8effbed850f9f978a88926f895db5575a2372902a5f116fb1b66e53500d0f29"
+  },
+  {
+    "TEST": 1,
+    "V": "02a5e9c0299060fba18865a71f5073a3d2d2b147e8580f4307cfec444d11e5aa09",
+    "C": "038f8768a2dcd60714d3c19ac06e656867796dbc3808051805c6d6d866e7389a05",
+    "ID": "a81470aaf7afc061dc24193d4446c96e",
+    "AD": "",
+    "E": "598838c9113415caccb6fbd389b758650b1cb3ecc2b72aa24a7dad2bcfa979d9"
+  },
+  {
+    "TEST": 2,
+    "V": "0320280219053d45a0c5c90e73cdefd8a593f4a7be5da01e4d1db9af68aaa23299",
+    "C": "0282616f5db217d92e6c98fe5972e940c0e7d49c87f122fbddd25b79cd3e7218bc",
+    "ID": "03ebed6dacbc4902145678434808e180",
+    "AD": "",
+    "E": "e172dd9e5bf1c1bb56ba8bc773c2d5163fbbe0c67443211d4100e0c8a63de0b9"
+  },
+  {
+    "TEST": 3,
+    "V": "0379b3f04bcb5c09d1bb9f315d1d90c35ee1622f68349dbfc0e234a4aee8f57216",
+    "C": "02307df7d70d833f0116f1f6c0b2fd4108a0514fccc196ed9ad18e7c64dd0d5baf",
+    "ID": "008c44b943f505813212b480e19d261c",
+    "AD": "",
+    "E": "39d2b208df6db374cbb0ab5618965691ab0c811aa0a6b5b7854811b9f034f534"
+  },
+  {
+    "TEST": 4,
+    "V": "02ffdca77078ef81ebf5be576b38eb69ac4dbb29eb4070400629104eb63d9c2df8",
+    "C": "021c674cef387256d884f55c67b808b4d85db2d17abc642e616ef7975a287e101e",
+    "ID": "cf58c2bb64a703b541250d19e9586215",
+    "AD": "",
+    "E": "7c291362f4212c3b022898334435d2cbf9d7c0e0a24d52fecf01cead5ae01bb9"
+  },
+  {
+    "TEST": 5,
+    "V": "03834f82bccf7b71714e90e1898b0d3cfecb599cda83c76d2dac04a9455cfc1748",
+    "C": "035b74645d08ea1c8ddeaf57702564919410cfa837cb24c0ab891b64431ba106d6",
+    "ID": "cc4e19f9a166f5eeace94d5b32157cab",
+    "AD": "09a505518af94a8552547e0a8729af8e",
+    "E": "e63279c737313382adf615739cfdb95393e506a3834451ff2e1e9dfd3fa8e67d"
+  },
+  {
+    "TEST": 6,
+    "V": "037166b6f25b8888aad6007287b284f6bbbcba04622663effa3297cdd9f1a39c3d",
+    "C": "03932b6703940d748f041653451df0b6104e86c7d1dc04261a4c940a15cab64b18",
+    "ID": "4e8e1482f967f3f3c6e84dd27717fe2b",
+    "AD": "f9c26bddde765e5128d1158f987755ff",
+    "E": "73029e753eaf4b1091f1e4da11a17a36906694f9d73cdbf34794d2b5238cece6"
+  },
+  {
+    "TEST": 7,
+    "V": "0265fb889364196c591a5e58f50ec4884aac6042c5734e18931209364be7e64ac5",
+    "C": "035eba13445bad376a4918abfc897e829a1fe6a3277ec8b7929a72b361c838f4c3",
+    "ID": "4399776dc1ec5490710e52f59fb219e4",
+    "AD": "99a2774bd166ac93a6d87dbc2bd523dc",
+    "E": "1f6f52e6872082be4959ab37b5b59119493601103a24f14c39525de08c3458fe"
+  },
+  {
+    "TEST": 8,
+    "V": "03fcc77f61f3d0974dfb272385db0ec7735611bc27640135bad3724585e9250964",
+    "C": "036eed182bb4fe28f7c214e82c4a8914747eae1571f627a59f3b87cb9465635348",
+    "ID": "16f29291d8cd840d76af1b3728f4d3e2",
+    "AD": "d31dfe881b63e7d5bd783c6ed1bc84bb",
+    "E": "914798fb16ac6a91ca18c11cf0ef9b35316e257415c72a9676d25dd5b536f7f6"
+  },
+  {
+    "TEST": 9,
+    "V": "024f0042345303c658b2ee6eb84fb1b0d46deac42fe9221f23a0387f961e021491",
+    "C": "02a8131a3fd62c2413e24a89b069d5856c7ccc9e8d3dd4686bb0cb878d8b7ba229",
+    "ID": "7acce926f027b501739e59438987004e",
+    "AD": "1a9699eaff721e651dc06ff4b69aea64",
+    "E": "0deb6a24b8b0345c01abbccad6b58379bf71c63dc16e89cde479d8613641ac01"
+  }
+]
\ No newline at end of file
diff --git a/testVectors/gg20_zkp/phase3_challenge.txt b/testVectors/gg20_zkp/phase3_challenge.txt
new file mode 100644
index 0000000..473a6ac
--- /dev/null
+++ b/testVectors/gg20_zkp/phase3_challenge.txt
@@ -0,0 +1,70 @@
+TEST = 0,
+V = 02e03da4554a06bb9f90cc5d77edcdcc69d96a707f6d8191a8c6fbe8044cb4f363,
+C = 034eaa5630192ece97b664c54ab8b111c48f964b263170500b9e109b8fb85d85c3,
+ID = f65b3c27e5698be4ea94d95ce5259ef2,
+AD = ,
+E = a8effbed850f9f978a88926f895db5575a2372902a5f116fb1b66e53500d0f29,
+
+TEST = 1,
+V = 02a5e9c0299060fba18865a71f5073a3d2d2b147e8580f4307cfec444d11e5aa09,
+C = 038f8768a2dcd60714d3c19ac06e656867796dbc3808051805c6d6d866e7389a05,
+ID = a81470aaf7afc061dc24193d4446c96e,
+AD = ,
+E = 598838c9113415caccb6fbd389b758650b1cb3ecc2b72aa24a7dad2bcfa979d9,
+
+TEST = 2,
+V = 0320280219053d45a0c5c90e73cdefd8a593f4a7be5da01e4d1db9af68aaa23299,
+C = 0282616f5db217d92e6c98fe5972e940c0e7d49c87f122fbddd25b79cd3e7218bc,
+ID = 03ebed6dacbc4902145678434808e180,
+AD = ,
+E = e172dd9e5bf1c1bb56ba8bc773c2d5163fbbe0c67443211d4100e0c8a63de0b9,
+
+TEST = 3,
+V = 0379b3f04bcb5c09d1bb9f315d1d90c35ee1622f68349dbfc0e234a4aee8f57216,
+C = 02307df7d70d833f0116f1f6c0b2fd4108a0514fccc196ed9ad18e7c64dd0d5baf,
+ID = 008c44b943f505813212b480e19d261c,
+AD = ,
+E = 39d2b208df6db374cbb0ab5618965691ab0c811aa0a6b5b7854811b9f034f534,
+
+TEST = 4,
+V = 02ffdca77078ef81ebf5be576b38eb69ac4dbb29eb4070400629104eb63d9c2df8,
+C = 021c674cef387256d884f55c67b808b4d85db2d17abc642e616ef7975a287e101e,
+ID = cf58c2bb64a703b541250d19e9586215,
+AD = ,
+E = 7c291362f4212c3b022898334435d2cbf9d7c0e0a24d52fecf01cead5ae01bb9,
+
+TEST = 5,
+V = 03834f82bccf7b71714e90e1898b0d3cfecb599cda83c76d2dac04a9455cfc1748,
+C = 035b74645d08ea1c8ddeaf57702564919410cfa837cb24c0ab891b64431ba106d6,
+ID = cc4e19f9a166f5eeace94d5b32157cab,
+AD = 09a505518af94a8552547e0a8729af8e,
+E = e63279c737313382adf615739cfdb95393e506a3834451ff2e1e9dfd3fa8e67d,
+
+TEST = 6,
+V = 037166b6f25b8888aad6007287b284f6bbbcba04622663effa3297cdd9f1a39c3d,
+C = 03932b6703940d748f041653451df0b6104e86c7d1dc04261a4c940a15cab64b18,
+ID = 4e8e1482f967f3f3c6e84dd27717fe2b,
+AD = f9c26bddde765e5128d1158f987755ff,
+E = 73029e753eaf4b1091f1e4da11a17a36906694f9d73cdbf34794d2b5238cece6,
+
+TEST = 7,
+V = 0265fb889364196c591a5e58f50ec4884aac6042c5734e18931209364be7e64ac5,
+C = 035eba13445bad376a4918abfc897e829a1fe6a3277ec8b7929a72b361c838f4c3,
+ID = 4399776dc1ec5490710e52f59fb219e4,
+AD = 99a2774bd166ac93a6d87dbc2bd523dc,
+E = 1f6f52e6872082be4959ab37b5b59119493601103a24f14c39525de08c3458fe,
+
+TEST = 8,
+V = 03fcc77f61f3d0974dfb272385db0ec7735611bc27640135bad3724585e9250964,
+C = 036eed182bb4fe28f7c214e82c4a8914747eae1571f627a59f3b87cb9465635348,
+ID = 16f29291d8cd840d76af1b3728f4d3e2,
+AD = d31dfe881b63e7d5bd783c6ed1bc84bb,
+E = 914798fb16ac6a91ca18c11cf0ef9b35316e257415c72a9676d25dd5b536f7f6,
+
+TEST = 9,
+V = 024f0042345303c658b2ee6eb84fb1b0d46deac42fe9221f23a0387f961e021491,
+C = 02a8131a3fd62c2413e24a89b069d5856c7ccc9e8d3dd4686bb0cb878d8b7ba229,
+ID = 7acce926f027b501739e59438987004e,
+AD = 1a9699eaff721e651dc06ff4b69aea64,
+E = 0deb6a24b8b0345c01abbccad6b58379bf71c63dc16e89cde479d8613641ac01,
+
diff --git a/testVectors/gg20_zkp/phase3_commit.json b/testVectors/gg20_zkp/phase3_commit.json
new file mode 100644
index 0000000..07206f8
--- /dev/null
+++ b/testVectors/gg20_zkp/phase3_commit.json
@@ -0,0 +1,62 @@
+[
+  {
+    "TEST": 0,
+    "A": "a0edd5b4d2c80b907fc54c480297f77c0804573e7c77e28c909ebab9e860de25",
+    "B": "364dc1be76f6846e39274ecf9b00ea8e026531a046f152e28787036bed1ecf18",
+    "C": "030773cfe787c7a9941db71e1c1760db1bbe5d5ff74fcf2a42f729a7d7abba69a2"
+  },
+  {
+    "TEST": 1,
+    "A": "a54f755af7c10d7d97cd06d4782315ae123d42810034f7d4c55f9b870460156e",
+    "B": "7df16cb8e67b2d77035952d2611e21f6e7f51c120b35ea6f1740460d34abe8cc",
+    "C": "03905a11c91f4720700fb8290698788026552d9437c1e359a6f58d71ac9b3f3ce6"
+  },
+  {
+    "TEST": 2,
+    "A": "5f53ca3702ec3da889d0973108ce477a8462f51fbbd8c1bba1124ebf97fcf3fd",
+    "B": "b6e67fbaa4a2d57145853a85085d25ceaea25f65843095eb733a61eff0df6a2d",
+    "C": "031857e5f3eefde534c0a259e6394cb449cf51c1286956682b52b18519e5118a76"
+  },
+  {
+    "TEST": 3,
+    "A": "4d6eb39b268d5720f896ed72ba78e4997cf14e4abe85c432144ea7c95bc678ad",
+    "B": "bbcb79743e4a4995a64d2acb2921da36e6a3e50fd9a8b1a6c1c6adb6d3cebfad",
+    "C": "03e5f510082f59c5287b807ba8d8f1cb379ff0ca00d2d502791bd47552c06a4df6"
+  },
+  {
+    "TEST": 4,
+    "A": "ec435643a44de0eae104b552b1d37b47f4f0f01519d1c3561f2a9455711a831e",
+    "B": "37e83c3516929e9efd4635d421424173545daf91173c71bce2fcd5941bf5e6f4",
+    "C": "0308849364e0a3a5ce1d5afa56cdce1a1135f2d0f81e55f497e7d18148e4e9410f"
+  },
+  {
+    "TEST": 5,
+    "A": "82ebfdea537c424300d95efb7df11bd11d10cc7b6f5b7719d9453d322ffb5b99",
+    "B": "8d8255f6b119d624db24b1cb314ab176ff86a9c4c8b6d8a75f7d27b6e782591e",
+    "C": "038afd7cbc2d0354aece112bbcca28ce0acccd0b5ff57db307cc8fd938c9a57255"
+  },
+  {
+    "TEST": 6,
+    "A": "ffd2f3dfde7003eb5adaf7c102b1e2c2d1720122eb66931d8ffef2f06c5dc5bc",
+    "B": "c05070559e971f0c794b6b310fb47de3b2971b98d99faff9843c1dab9f7f4407",
+    "C": "03a58deb3ec6359cb309d22ad889cdeb77ef229bd43d1ad66ba583f74d33e25aee"
+  },
+  {
+    "TEST": 7,
+    "A": "fa02c28fe4b0ad42a7e268430d2e6ea5bbc4cf5026582e9f143b5b94102280cb",
+    "B": "ac59c363be14ddcc3528fa8a2eb95fe20b577bff7d50e8a210ab62b72d9a138f",
+    "C": "03dc643c3a18a0fa4a38d6d072143d9a351100e6e383b3ee06aa75be806b4aef17"
+  },
+  {
+    "TEST": 8,
+    "A": "498ffb6510deac034014ab028abed96ffdf6191866061c92478966e69ea85dda",
+    "B": "a2a00a33092103346dcefa66f1820aef5180a752475ce17ca9e2e9287999cda8",
+    "C": "02ff67db861bf0a41b24f4de08cb332424aac174fa526993c246d88c3da38dd90a"
+  },
+  {
+    "TEST": 9,
+    "A": "e96afdc9381612b3c8eb6e0ed6f928b24e6513d91c15d8a0cda184746a69bbf5",
+    "B": "2d404a6a440abb043ec2fdd93aefe02617b182cf20d41e69bfee192051188299",
+    "C": "0315dbf65e577707b07175d486337d1a499d7074a3177f9add8660e709492338b8"
+  }
+]
\ No newline at end of file
diff --git a/testVectors/gg20_zkp/phase3_commit.txt b/testVectors/gg20_zkp/phase3_commit.txt
new file mode 100644
index 0000000..4f15b2a
--- /dev/null
+++ b/testVectors/gg20_zkp/phase3_commit.txt
@@ -0,0 +1,50 @@
+TEST = 0,
+A = a0edd5b4d2c80b907fc54c480297f77c0804573e7c77e28c909ebab9e860de25,
+B = 364dc1be76f6846e39274ecf9b00ea8e026531a046f152e28787036bed1ecf18,
+C = 030773cfe787c7a9941db71e1c1760db1bbe5d5ff74fcf2a42f729a7d7abba69a2,
+
+TEST = 1,
+A = a54f755af7c10d7d97cd06d4782315ae123d42810034f7d4c55f9b870460156e,
+B = 7df16cb8e67b2d77035952d2611e21f6e7f51c120b35ea6f1740460d34abe8cc,
+C = 03905a11c91f4720700fb8290698788026552d9437c1e359a6f58d71ac9b3f3ce6,
+
+TEST = 2,
+A = 5f53ca3702ec3da889d0973108ce477a8462f51fbbd8c1bba1124ebf97fcf3fd,
+B = b6e67fbaa4a2d57145853a85085d25ceaea25f65843095eb733a61eff0df6a2d,
+C = 031857e5f3eefde534c0a259e6394cb449cf51c1286956682b52b18519e5118a76,
+
+TEST = 3,
+A = 4d6eb39b268d5720f896ed72ba78e4997cf14e4abe85c432144ea7c95bc678ad,
+B = bbcb79743e4a4995a64d2acb2921da36e6a3e50fd9a8b1a6c1c6adb6d3cebfad,
+C = 03e5f510082f59c5287b807ba8d8f1cb379ff0ca00d2d502791bd47552c06a4df6,
+
+TEST = 4,
+A = ec435643a44de0eae104b552b1d37b47f4f0f01519d1c3561f2a9455711a831e,
+B = 37e83c3516929e9efd4635d421424173545daf91173c71bce2fcd5941bf5e6f4,
+C = 0308849364e0a3a5ce1d5afa56cdce1a1135f2d0f81e55f497e7d18148e4e9410f,
+
+TEST = 5,
+A = 82ebfdea537c424300d95efb7df11bd11d10cc7b6f5b7719d9453d322ffb5b99,
+B = 8d8255f6b119d624db24b1cb314ab176ff86a9c4c8b6d8a75f7d27b6e782591e,
+C = 038afd7cbc2d0354aece112bbcca28ce0acccd0b5ff57db307cc8fd938c9a57255,
+
+TEST = 6,
+A = ffd2f3dfde7003eb5adaf7c102b1e2c2d1720122eb66931d8ffef2f06c5dc5bc,
+B = c05070559e971f0c794b6b310fb47de3b2971b98d99faff9843c1dab9f7f4407,
+C = 03a58deb3ec6359cb309d22ad889cdeb77ef229bd43d1ad66ba583f74d33e25aee,
+
+TEST = 7,
+A = fa02c28fe4b0ad42a7e268430d2e6ea5bbc4cf5026582e9f143b5b94102280cb,
+B = ac59c363be14ddcc3528fa8a2eb95fe20b577bff7d50e8a210ab62b72d9a138f,
+C = 03dc643c3a18a0fa4a38d6d072143d9a351100e6e383b3ee06aa75be806b4aef17,
+
+TEST = 8,
+A = 498ffb6510deac034014ab028abed96ffdf6191866061c92478966e69ea85dda,
+B = a2a00a33092103346dcefa66f1820aef5180a752475ce17ca9e2e9287999cda8,
+C = 02ff67db861bf0a41b24f4de08cb332424aac174fa526993c246d88c3da38dd90a,
+
+TEST = 9,
+A = e96afdc9381612b3c8eb6e0ed6f928b24e6513d91c15d8a0cda184746a69bbf5,
+B = 2d404a6a440abb043ec2fdd93aefe02617b182cf20d41e69bfee192051188299,
+C = 0315dbf65e577707b07175d486337d1a499d7074a3177f9add8660e709492338b8,
+
diff --git a/testVectors/gg20_zkp/phase3_prove.json b/testVectors/gg20_zkp/phase3_prove.json
new file mode 100644
index 0000000..a8a0711
--- /dev/null
+++ b/testVectors/gg20_zkp/phase3_prove.json
@@ -0,0 +1,102 @@
+[
+  {
+    "TEST": 0,
+    "A": "cb9805c14b825c898b03281716fa3baac4fed1d081f26f3335237b2375ecdf25",
+    "B": "275fe3e42d66b3db53cdfc0e6307a4bfbfa10fc11c84fde66cb728b11b99aaba",
+    "E": "a05d5bdd616d9bbc72bee04e72bc045026be6a355183c7704e122f614ab607be",
+    "S": "07051d73757dca22d877ca18610194d6713a815c081c1fccb818cb17f4f55ffd",
+    "L": "64152434654ae61db2a9d9a0132a7dbb9c5eb5c8b491018683d563a10804f436",
+    "T": "66acee60b6318fcdbecddd22ef73589e61b8ab63432aa4927898539f93687728",
+    "U": "2600691de9fb297862476be002ad22a9c5b697f1237793c132bbc8555aab4849"
+  },
+  {
+    "TEST": 1,
+    "A": "9e89d4a2c83d2a5a843cd092969a9c625a62d84a754043e2b4d486f53c615819",
+    "B": "4a2c793806ba9fa56167f178dede03150c9f17993b36c412491e01043c0d9294",
+    "E": "8aefe199192c99baf7da45978063c799e754b252bb40f06d826da05db08b4e28",
+    "S": "983247c2d5eec09633afb1b28db3e7cedfc321cbc8dca864389ddbb139181655",
+    "L": "d932677581e35a7e679eceffa029193173db013b4a3a787c2944c47ea8a6f71c",
+    "T": "81fd655525685886f9bb8fef01f00bac1370e1da5872054447a069c2b45a7e9b",
+    "U": "6910582b4cefb1621e8d09d789cf4342b26b9b077463aaab2fd62aaf5e92f5a7"
+  },
+  {
+    "TEST": 2,
+    "A": "ae01ecfe3747020e4c9300782b2e1db9ab883356dc77a54774f2755bdf1203f3",
+    "B": "749050d6a83aa5ecf943db78f0b686c7d094fd37c95f535849e6c0e16394a491",
+    "E": "aeb915132914f2d4773002d7afb3e4ccd0f7c78be0b40380671cda08480d3e10",
+    "S": "6e1c4094280821e95f6051dd0bc9f2b4009ca84195a9140533f4032ce0fef491",
+    "L": "dd5a97559d9defd22805e35b5b22c35ecd94bc3667069b1e5977c001e377e8e6",
+    "T": "941f3cc74204fc2811f5aa31f33b8e2c5bef4958448c4aa200cee38c4b592206",
+    "U": "2a5f42f32f32399f69844a4e2bc04cb69d65d69c92e96178e44cced18ac8e167"
+  },
+  {
+    "TEST": 3,
+    "A": "ae8caf22f68275ac14099909068c3a36d6a3214412d413e6200bc5734b36b722",
+    "B": "3cf6351ecfa07702ff36111b4805f8f6d150a67c7a04849b6536ff2d702b5f93",
+    "E": "449a3ef8f76e1942386da035a6257e85fd4dcda0b2e537f11b7acc06c55935ef",
+    "S": "3a6086b1b4a564074e366e52531be77d892e74e24ebcbfb96c584555aa95ebef",
+    "L": "e8421eef435bbf01582c6020a23ccdf4b342a019f9b349ffad5e90deb54dccfd",
+    "T": "34a6c9e13a4e02dc86e248af2a48c5ef8980031d8ebbe316bfbe5e6637db56d8",
+    "U": "36ba7fa7b2823c14bd756ecd7c06f75195529a5a6b8b945b319ca00558332274"
+  },
+  {
+    "TEST": 4,
+    "A": "9eec4667cc3c9e82b140d53da7ab12985b5492d6a2c3ba889ce656ca85122ec3",
+    "B": "6a5d1f0ef028747d959292bd4075add723c68f4bd932743cbcd58989b39105dd",
+    "E": "aab7aace82d0f0fe4131e3543dbed99d99b49b254ace9aa506fbd87bfcc1a0ce",
+    "S": "180ada88c2251413676b334e0ebd4e21193a5ce36f56df390be7882fc9b7bb67",
+    "L": "2cd12668c480fe23c13744bffeeca18e9fb50e8fefbd7982105d2701668c9bba",
+    "T": "ee673c77d320e127ea49093b23d169f6c4345e6d26e65d4499097d208bfaa87b",
+    "U": "6ecde180aa8a032d7a4b28993e44fc880d83fca83c1cc7831190989c42dd941e"
+  },
+  {
+    "TEST": 5,
+    "A": "85062da0e3f1dcc4eef63cc5f464df5d8b0645197b93dcc1081668bd9959483f",
+    "B": "38cb62a0a116a027f006401b61da2f4a67bc21af1ee90f0d78b0aad6e7b8660a",
+    "E": "84fca2de11cdf2bdb40bef141908887d904c8cd88f3c8f1fb58684a8cdb6c36b",
+    "S": "ec1928bc7633ea64d958c87f4dce8d1f92f4470c89d2dbd9a0bcab78addb7406",
+    "L": "6c59d9854aa263c7c55b17b25bfc0622e9005e9fede95ff4429bb32253fdd2ab",
+    "T": "b12bd41c9d68375ea89dd6e20c410175c3812f4251756345d6a66460fa6f89fa",
+    "U": "ddc340dc4f5e73bc95ef16ca641571a4252dab6e620d4e15b476727ec24cc233"
+  },
+  {
+    "TEST": 6,
+    "A": "5d0913b12b751ad4d04b3a3b9e50161c7cc7df43dbbac49d0e6ac1db3a09f27d",
+    "B": "7e2a66aae55e73baba851ca3f5ce8b4db1e84bd31d6bebbbb17aa6ef660edf33",
+    "E": "4d06e19d49851e42015e788a57b0668a609f9d5a3dad3e6b17aea969c5a0b8a9",
+    "S": "58cf2c473821475f02f05f488e064dde4f0c512899269594270d45d121615517",
+    "L": "39411ef7b8c30d0de2e3ff6ad210e6b97f6393579f92644acb54a4de0ca63448",
+    "T": "b1e8f902af4db8af60d5a2f84db34e4bf87ec381a3d1cdee7806c38f978da505",
+    "U": "2d54c4b7802b98456a9995af65696bb821352cceec9b496304f6c4f3601f02ea"
+  },
+  {
+    "TEST": 7,
+    "A": "f745d69d473fd9dbe04d96f4faff200d4008f3d1087be44c7a1717bee009f53c",
+    "B": "58759d84dbd02b20caaea6b5e92a2a1c262ad41057aca1a211902b2cf5bb6541",
+    "E": "8376c812f6c88b79d9bc908a1441ba94ac6ca511a860b295c48d8c48cad5fee0",
+    "S": "a982ed831b7fffc7b7f3179c2f5d1fed78b724096e8a22390c7760fe78fde324",
+    "L": "2c4c7be22d125402ba2de4dbf54d838c1cc5bfcb27101ec1f2f77d5afc8a123a",
+    "T": "d932de6113c941ac01a12fff7e6fd6700b4d7fb5293559ea6e99b6a61ef213af",
+    "U": "2074cf4cc1683f5518af734558abab4b41a07b87449fa199896660f978badcbf"
+  },
+  {
+    "TEST": 8,
+    "A": "6ffeee4e0d42c52adfa5a2c42f6f1c5762bb6094b164582c08dcd46b99f920b2",
+    "B": "0151835c109674131c20cafe1778ea2ce772f496269ff3ef55171e69c5840107",
+    "E": "e8803eddc165604f852d3faafd3958255c18e1c692f3663ef0b1798a613b6c30",
+    "S": "ec90afce0a28e498a89a582b67f58fadc45f307bedb981bf6153f2d7fc3ca6cd",
+    "L": "dcbd6545e11499ae13470bd689f3ecb203669e99a5077ab9e1cd8481790520b0",
+    "T": "d5c4fa580680643afdd91650cde82a4a417120adecd04c67d98f7d1254f3b38b",
+    "U": "ddf7c9345fd0590affa8e7b6ef7d56929b097ef16e0c63a7c85a5dd437928775"
+  },
+  {
+    "TEST": 9,
+    "A": "650b0680dec70fa7683a361e8347be4401b3ed90858d5c01b5c3b9d42de6cc12",
+    "B": "b88fbc1e2b93dfaedb0885bb52bb51c841b93941989a7d61e713f93065432e85",
+    "E": "31de91626dff5d62fe193b3710b7ff39798a6f34c02ae2246edf8fd6da555b1c",
+    "S": "af3d203f370b67441bb5cc65348cb54a043985e573958e04eccca61f6a4ada9a",
+    "L": "752508bba08fc69838c6f75ede9edd0ca9ad7bc99e2222dc46c2f91f0e9e96a5",
+    "T": "625e09fa9aeb0144f99cf6df869938f3132c4bcba72804d0ab627b35ffd0c19e",
+    "U": "9c0bf3c5d4a6b0a5933184fffd0365ba4bc72c1a526ca2c7d0d8f4b5d7ca48b0"
+  }
+]
\ No newline at end of file
diff --git a/testVectors/gg20_zkp/phase3_prove.txt b/testVectors/gg20_zkp/phase3_prove.txt
new file mode 100644
index 0000000..7231456
--- /dev/null
+++ b/testVectors/gg20_zkp/phase3_prove.txt
@@ -0,0 +1,90 @@
+TEST = 0,
+A = cb9805c14b825c898b03281716fa3baac4fed1d081f26f3335237b2375ecdf25,
+B = 275fe3e42d66b3db53cdfc0e6307a4bfbfa10fc11c84fde66cb728b11b99aaba,
+E = a05d5bdd616d9bbc72bee04e72bc045026be6a355183c7704e122f614ab607be,
+S = 07051d73757dca22d877ca18610194d6713a815c081c1fccb818cb17f4f55ffd,
+L = 64152434654ae61db2a9d9a0132a7dbb9c5eb5c8b491018683d563a10804f436,
+T = 66acee60b6318fcdbecddd22ef73589e61b8ab63432aa4927898539f93687728,
+U = 2600691de9fb297862476be002ad22a9c5b697f1237793c132bbc8555aab4849,
+
+TEST = 1,
+A = 9e89d4a2c83d2a5a843cd092969a9c625a62d84a754043e2b4d486f53c615819,
+B = 4a2c793806ba9fa56167f178dede03150c9f17993b36c412491e01043c0d9294,
+E = 8aefe199192c99baf7da45978063c799e754b252bb40f06d826da05db08b4e28,
+S = 983247c2d5eec09633afb1b28db3e7cedfc321cbc8dca864389ddbb139181655,
+L = d932677581e35a7e679eceffa029193173db013b4a3a787c2944c47ea8a6f71c,
+T = 81fd655525685886f9bb8fef01f00bac1370e1da5872054447a069c2b45a7e9b,
+U = 6910582b4cefb1621e8d09d789cf4342b26b9b077463aaab2fd62aaf5e92f5a7,
+
+TEST = 2,
+A = ae01ecfe3747020e4c9300782b2e1db9ab883356dc77a54774f2755bdf1203f3,
+B = 749050d6a83aa5ecf943db78f0b686c7d094fd37c95f535849e6c0e16394a491,
+E = aeb915132914f2d4773002d7afb3e4ccd0f7c78be0b40380671cda08480d3e10,
+S = 6e1c4094280821e95f6051dd0bc9f2b4009ca84195a9140533f4032ce0fef491,
+L = dd5a97559d9defd22805e35b5b22c35ecd94bc3667069b1e5977c001e377e8e6,
+T = 941f3cc74204fc2811f5aa31f33b8e2c5bef4958448c4aa200cee38c4b592206,
+U = 2a5f42f32f32399f69844a4e2bc04cb69d65d69c92e96178e44cced18ac8e167,
+
+TEST = 3,
+A = ae8caf22f68275ac14099909068c3a36d6a3214412d413e6200bc5734b36b722,
+B = 3cf6351ecfa07702ff36111b4805f8f6d150a67c7a04849b6536ff2d702b5f93,
+E = 449a3ef8f76e1942386da035a6257e85fd4dcda0b2e537f11b7acc06c55935ef,
+S = 3a6086b1b4a564074e366e52531be77d892e74e24ebcbfb96c584555aa95ebef,
+L = e8421eef435bbf01582c6020a23ccdf4b342a019f9b349ffad5e90deb54dccfd,
+T = 34a6c9e13a4e02dc86e248af2a48c5ef8980031d8ebbe316bfbe5e6637db56d8,
+U = 36ba7fa7b2823c14bd756ecd7c06f75195529a5a6b8b945b319ca00558332274,
+
+TEST = 4,
+A = 9eec4667cc3c9e82b140d53da7ab12985b5492d6a2c3ba889ce656ca85122ec3,
+B = 6a5d1f0ef028747d959292bd4075add723c68f4bd932743cbcd58989b39105dd,
+E = aab7aace82d0f0fe4131e3543dbed99d99b49b254ace9aa506fbd87bfcc1a0ce,
+S = 180ada88c2251413676b334e0ebd4e21193a5ce36f56df390be7882fc9b7bb67,
+L = 2cd12668c480fe23c13744bffeeca18e9fb50e8fefbd7982105d2701668c9bba,
+T = ee673c77d320e127ea49093b23d169f6c4345e6d26e65d4499097d208bfaa87b,
+U = 6ecde180aa8a032d7a4b28993e44fc880d83fca83c1cc7831190989c42dd941e,
+
+TEST = 5,
+A = 85062da0e3f1dcc4eef63cc5f464df5d8b0645197b93dcc1081668bd9959483f,
+B = 38cb62a0a116a027f006401b61da2f4a67bc21af1ee90f0d78b0aad6e7b8660a,
+E = 84fca2de11cdf2bdb40bef141908887d904c8cd88f3c8f1fb58684a8cdb6c36b,
+S = ec1928bc7633ea64d958c87f4dce8d1f92f4470c89d2dbd9a0bcab78addb7406,
+L = 6c59d9854aa263c7c55b17b25bfc0622e9005e9fede95ff4429bb32253fdd2ab,
+T = b12bd41c9d68375ea89dd6e20c410175c3812f4251756345d6a66460fa6f89fa,
+U = ddc340dc4f5e73bc95ef16ca641571a4252dab6e620d4e15b476727ec24cc233,
+
+TEST = 6,
+A = 5d0913b12b751ad4d04b3a3b9e50161c7cc7df43dbbac49d0e6ac1db3a09f27d,
+B = 7e2a66aae55e73baba851ca3f5ce8b4db1e84bd31d6bebbbb17aa6ef660edf33,
+E = 4d06e19d49851e42015e788a57b0668a609f9d5a3dad3e6b17aea969c5a0b8a9,
+S = 58cf2c473821475f02f05f488e064dde4f0c512899269594270d45d121615517,
+L = 39411ef7b8c30d0de2e3ff6ad210e6b97f6393579f92644acb54a4de0ca63448,
+T = b1e8f902af4db8af60d5a2f84db34e4bf87ec381a3d1cdee7806c38f978da505,
+U = 2d54c4b7802b98456a9995af65696bb821352cceec9b496304f6c4f3601f02ea,
+
+TEST = 7,
+A = f745d69d473fd9dbe04d96f4faff200d4008f3d1087be44c7a1717bee009f53c,
+B = 58759d84dbd02b20caaea6b5e92a2a1c262ad41057aca1a211902b2cf5bb6541,
+E = 8376c812f6c88b79d9bc908a1441ba94ac6ca511a860b295c48d8c48cad5fee0,
+S = a982ed831b7fffc7b7f3179c2f5d1fed78b724096e8a22390c7760fe78fde324,
+L = 2c4c7be22d125402ba2de4dbf54d838c1cc5bfcb27101ec1f2f77d5afc8a123a,
+T = d932de6113c941ac01a12fff7e6fd6700b4d7fb5293559ea6e99b6a61ef213af,
+U = 2074cf4cc1683f5518af734558abab4b41a07b87449fa199896660f978badcbf,
+
+TEST = 8,
+A = 6ffeee4e0d42c52adfa5a2c42f6f1c5762bb6094b164582c08dcd46b99f920b2,
+B = 0151835c109674131c20cafe1778ea2ce772f496269ff3ef55171e69c5840107,
+E = e8803eddc165604f852d3faafd3958255c18e1c692f3663ef0b1798a613b6c30,
+S = ec90afce0a28e498a89a582b67f58fadc45f307bedb981bf6153f2d7fc3ca6cd,
+L = dcbd6545e11499ae13470bd689f3ecb203669e99a5077ab9e1cd8481790520b0,
+T = d5c4fa580680643afdd91650cde82a4a417120adecd04c67d98f7d1254f3b38b,
+U = ddf7c9345fd0590affa8e7b6ef7d56929b097ef16e0c63a7c85a5dd437928775,
+
+TEST = 9,
+A = 650b0680dec70fa7683a361e8347be4401b3ed90858d5c01b5c3b9d42de6cc12,
+B = b88fbc1e2b93dfaedb0885bb52bb51c841b93941989a7d61e713f93065432e85,
+E = 31de91626dff5d62fe193b3710b7ff39798a6f34c02ae2246edf8fd6da555b1c,
+S = af3d203f370b67441bb5cc65348cb54a043985e573958e04eccca61f6a4ada9a,
+L = 752508bba08fc69838c6f75ede9edd0ca9ad7bc99e2222dc46c2f91f0e9e96a5,
+T = 625e09fa9aeb0144f99cf6df869938f3132c4bcba72804d0ab627b35ffd0c19e,
+U = 9c0bf3c5d4a6b0a5933184fffd0365ba4bc72c1a526ca2c7d0d8f4b5d7ca48b0,
+
diff --git a/testVectors/gg20_zkp/phase3_verify.json b/testVectors/gg20_zkp/phase3_verify.json
new file mode 100644
index 0000000..ffb54f5
--- /dev/null
+++ b/testVectors/gg20_zkp/phase3_verify.json
@@ -0,0 +1,82 @@
+[
+  {
+    "TEST": 0,
+    "V": "02caf97404649fb0c3322a2ec2a0905aa0dd89e256e08b4543bb8b9a2d91563e63",
+    "C": "02d2e0cf0d7780db39d2f9eb21b8fa5c2c02990898535f30e54374221f9636dd46",
+    "E": "f8a8ee7dbe3c12a674fba0cef4d6cf9fdfd384d41045f9652bdce2a8667aaccb",
+    "T": "73a1ac5734453d3bd41b0044d064dc51fc327d17f4454d99d3055c31f06f7929",
+    "U": "66bfbbf3b5c1cdd5369dd32443c46a9becb74663ee16eae0ac6f3264783fb967"
+  },
+  {
+    "TEST": 1,
+    "V": "0330718a71cfdc42b829e2df4668ee073d8e5f6e9f58de4b1f4a8c9a78fd79a92e",
+    "C": "02bc011ea0ef994372aa0f9f3e0b6df00a0cb525be2faea08165978b6955bffbfb",
+    "E": "1afa41e8af97edf2a0843b7baa5ce134c2ae9cc27042692e9597084d7e396d15",
+    "T": "3accdec2afb6a0c68fc20a2f00aa6d0944f181b8641c5d0838b709080719ad66",
+    "U": "ef97580c9b04576faa4d25edc506ba2c7ddb7d726a78449d320a5e2aa92afd2b"
+  },
+  {
+    "TEST": 2,
+    "V": "02404dd2c8c188bbdd4506ac959f84e425b82a0880a0945755cb715ff58f4bfec1",
+    "C": "0303f889b066feb0888ebefcc5595e184d22a0224ee3db6e2b3e017cccb6934e67",
+    "E": "ff4a29be578c91d68785a031c9eb890d8ef84eedde55b3b45c4bc041ecd144ad",
+    "T": "ad1e1e0952ef6a88110e503b0507870871f0aae4dba46d571afaacc341a05838",
+    "U": "00cc4a14d1fd95bc41fd2b8c722d8c78c552c10f27724748085dfa81ee9c280c"
+  },
+  {
+    "TEST": 3,
+    "V": "034a01512bfb1e41c6ea31a46fa3ca292506a532325559b63e8546ec570e15ec70",
+    "C": "03a2b9796c1afab3ffd6c941eac65c480f77d6adb8d9c202de625d4a638b4d717f",
+    "E": "8be434c5e97ac5235b48ad74abf67b484734609e6d86061bc3baa6ca51d25e13",
+    "T": "338262276b185f23b22f0e81147bc11f3942278648f0dee3c6130a9e4528deb7",
+    "U": "b5007f16c5cec34799d8ab3c11521bf9e8e308595b1428414c6011af7f0a7b0d"
+  },
+  {
+    "TEST": 4,
+    "V": "031f326ee2b6516392b2264bc4250417b7d9c1f8a1d2f9d3982e281547a0d1202f",
+    "C": "0351a76b3dd3e952865a810ebe5f4b817afd2068f88f4dca966be9819066de1bde",
+    "E": "5b631d30d3b0a88d13437c6e0433d4a3029eea4462a7f955db35a35a2d614ff2",
+    "T": "267501982dcd76ac6a33b12f11062aefa1a9e438c70c76fd441c76fcca13d0e6",
+    "U": "a176ca15c29b6983995b7c523ae552bedf55d77b0cae47e5e0d3fe30d80e37d1"
+  },
+  {
+    "TEST": 5,
+    "V": "02e1fafe90dfcbf1c785419d4a4e72befe74523b1c60b43d8b38b10de3f29a6754",
+    "C": "021f475f5670660eed6c5113a816f1e8edfb190373b514cf558e30fa77172b0430",
+    "E": "dae91da06071d586bd11c2fcf9ce825171112974cf2caa1b8050867d6c36d9b9",
+    "T": "7379d9994d8f4ea5bbae8728c70d784e5f9c71daed6a1b531950b89ddc933c09",
+    "U": "3e13309cf6b4867f307c9ae02b9838ee2324f5b61ad42d134fcde4cf21166869"
+  },
+  {
+    "TEST": 6,
+    "V": "0210d5be90b83e654da4267503a9cc00a3610ab948e25f77aebada2b7d12705aa6",
+    "C": "02afd060a0ebd3ce012514dffbc2be0a70b315bbb5d62d3e72e9401be92e71794e",
+    "E": "9b2cde1d21de47296cb8811818c670056ad555104ffd868917920a80982447f2",
+    "T": "ab1e867cc9c890da4f9d8ad31351bd72d3bdd27e9d9a5ef3a796195367cd3671",
+    "U": "8508f58d0262260a4ffacfeb99d2427da4486d362347f3017b9938cc687b68e6"
+  },
+  {
+    "TEST": 7,
+    "V": "0309e693f283a54f188f5c378c353b12cfdcd374b901d86a8532be20f0e27f943f",
+    "C": "02029af8ca721b2daa9d0f9bdb44b0574ca4988c153c65d4c4d557d99838f14da0",
+    "E": "296bf112d3a89ed5bba4e4415635ce694c3ac268040293868505eff1fecd7b78",
+    "T": "dccbf07ca8756eea746abc1a4a8d63713855c7cfdc774f9af5a541d32b3709dc",
+    "U": "36d8502dd38c08eb50e9542a24a76501d327484c2330b04c471ac4d12eeba61b"
+  },
+  {
+    "TEST": 8,
+    "V": "03021294323293aadd733fd13fab1dc576020e56fa3c57523b6d2fa50b1f23098f",
+    "C": "02b14488d16bb85f0886783cda8d9243877846952cbadfe94ddcb778ad684ced31",
+    "E": "ad3227111c986626d930b3a676e8a7fb83bb198d4325b073c3103c4b4d7bb60d",
+    "T": "d928893084dba94030cfef37f55bbbb9d430c7b62585530ccad09028e3486c65",
+    "U": "9c915549fad8e8b1b30d4b611f2a2f342c36419eeffc95c8c8d25149d0552bb3"
+  },
+  {
+    "TEST": 9,
+    "V": "02d00e227702127cbd26940ff8cdfc70ccb864234ec878dd21772a0fb6b1cc0bcc",
+    "C": "028f20c5ae0a3926e3faa7fdd2f1a51c9c097edfb406cfbb4ee4bda4652be346ff",
+    "E": "21be94962dd0c84a42f3b94dc71e6cfcdfd1f6001c471e7b60250acdb2d8556b",
+    "T": "ba6b049fdf7c46e52ce15d07a5cf582c91a380dbd4e896c76569245cf997a9cf",
+    "U": "15247bb2dcdb6d82e4134c1cda043edcff74d7983b8bb488c37decb83f950299"
+  }
+]
\ No newline at end of file
diff --git a/testVectors/gg20_zkp/phase3_verify.txt b/testVectors/gg20_zkp/phase3_verify.txt
new file mode 100644
index 0000000..be8ed49
--- /dev/null
+++ b/testVectors/gg20_zkp/phase3_verify.txt
@@ -0,0 +1,70 @@
+TEST = 0,
+V = 02caf97404649fb0c3322a2ec2a0905aa0dd89e256e08b4543bb8b9a2d91563e63,
+C = 02d2e0cf0d7780db39d2f9eb21b8fa5c2c02990898535f30e54374221f9636dd46,
+E = f8a8ee7dbe3c12a674fba0cef4d6cf9fdfd384d41045f9652bdce2a8667aaccb,
+T = 73a1ac5734453d3bd41b0044d064dc51fc327d17f4454d99d3055c31f06f7929,
+U = 66bfbbf3b5c1cdd5369dd32443c46a9becb74663ee16eae0ac6f3264783fb967,
+
+TEST = 1,
+V = 0330718a71cfdc42b829e2df4668ee073d8e5f6e9f58de4b1f4a8c9a78fd79a92e,
+C = 02bc011ea0ef994372aa0f9f3e0b6df00a0cb525be2faea08165978b6955bffbfb,
+E = 1afa41e8af97edf2a0843b7baa5ce134c2ae9cc27042692e9597084d7e396d15,
+T = 3accdec2afb6a0c68fc20a2f00aa6d0944f181b8641c5d0838b709080719ad66,
+U = ef97580c9b04576faa4d25edc506ba2c7ddb7d726a78449d320a5e2aa92afd2b,
+
+TEST = 2,
+V = 02404dd2c8c188bbdd4506ac959f84e425b82a0880a0945755cb715ff58f4bfec1,
+C = 0303f889b066feb0888ebefcc5595e184d22a0224ee3db6e2b3e017cccb6934e67,
+E = ff4a29be578c91d68785a031c9eb890d8ef84eedde55b3b45c4bc041ecd144ad,
+T = ad1e1e0952ef6a88110e503b0507870871f0aae4dba46d571afaacc341a05838,
+U = 00cc4a14d1fd95bc41fd2b8c722d8c78c552c10f27724748085dfa81ee9c280c,
+
+TEST = 3,
+V = 034a01512bfb1e41c6ea31a46fa3ca292506a532325559b63e8546ec570e15ec70,
+C = 03a2b9796c1afab3ffd6c941eac65c480f77d6adb8d9c202de625d4a638b4d717f,
+E = 8be434c5e97ac5235b48ad74abf67b484734609e6d86061bc3baa6ca51d25e13,
+T = 338262276b185f23b22f0e81147bc11f3942278648f0dee3c6130a9e4528deb7,
+U = b5007f16c5cec34799d8ab3c11521bf9e8e308595b1428414c6011af7f0a7b0d,
+
+TEST = 4,
+V = 031f326ee2b6516392b2264bc4250417b7d9c1f8a1d2f9d3982e281547a0d1202f,
+C = 0351a76b3dd3e952865a810ebe5f4b817afd2068f88f4dca966be9819066de1bde,
+E = 5b631d30d3b0a88d13437c6e0433d4a3029eea4462a7f955db35a35a2d614ff2,
+T = 267501982dcd76ac6a33b12f11062aefa1a9e438c70c76fd441c76fcca13d0e6,
+U = a176ca15c29b6983995b7c523ae552bedf55d77b0cae47e5e0d3fe30d80e37d1,
+
+TEST = 5,
+V = 02e1fafe90dfcbf1c785419d4a4e72befe74523b1c60b43d8b38b10de3f29a6754,
+C = 021f475f5670660eed6c5113a816f1e8edfb190373b514cf558e30fa77172b0430,
+E = dae91da06071d586bd11c2fcf9ce825171112974cf2caa1b8050867d6c36d9b9,
+T = 7379d9994d8f4ea5bbae8728c70d784e5f9c71daed6a1b531950b89ddc933c09,
+U = 3e13309cf6b4867f307c9ae02b9838ee2324f5b61ad42d134fcde4cf21166869,
+
+TEST = 6,
+V = 0210d5be90b83e654da4267503a9cc00a3610ab948e25f77aebada2b7d12705aa6,
+C = 02afd060a0ebd3ce012514dffbc2be0a70b315bbb5d62d3e72e9401be92e71794e,
+E = 9b2cde1d21de47296cb8811818c670056ad555104ffd868917920a80982447f2,
+T = ab1e867cc9c890da4f9d8ad31351bd72d3bdd27e9d9a5ef3a796195367cd3671,
+U = 8508f58d0262260a4ffacfeb99d2427da4486d362347f3017b9938cc687b68e6,
+
+TEST = 7,
+V = 0309e693f283a54f188f5c378c353b12cfdcd374b901d86a8532be20f0e27f943f,
+C = 02029af8ca721b2daa9d0f9bdb44b0574ca4988c153c65d4c4d557d99838f14da0,
+E = 296bf112d3a89ed5bba4e4415635ce694c3ac268040293868505eff1fecd7b78,
+T = dccbf07ca8756eea746abc1a4a8d63713855c7cfdc774f9af5a541d32b3709dc,
+U = 36d8502dd38c08eb50e9542a24a76501d327484c2330b04c471ac4d12eeba61b,
+
+TEST = 8,
+V = 03021294323293aadd733fd13fab1dc576020e56fa3c57523b6d2fa50b1f23098f,
+C = 02b14488d16bb85f0886783cda8d9243877846952cbadfe94ddcb778ad684ced31,
+E = ad3227111c986626d930b3a676e8a7fb83bb198d4325b073c3103c4b4d7bb60d,
+T = d928893084dba94030cfef37f55bbbb9d430c7b62585530ccad09028e3486c65,
+U = 9c915549fad8e8b1b30d4b611f2a2f342c36419eeffc95c8c8d25149d0552bb3,
+
+TEST = 9,
+V = 02d00e227702127cbd26940ff8cdfc70ccb864234ec878dd21772a0fb6b1cc0bcc,
+C = 028f20c5ae0a3926e3faa7fdd2f1a51c9c097edfb406cfbb4ee4bda4652be346ff,
+E = 21be94962dd0c84a42f3b94dc71e6cfcdfd1f6001c471e7b60250acdb2d8556b,
+T = ba6b049fdf7c46e52ce15d07a5cf582c91a380dbd4e896c76569245cf997a9cf,
+U = 15247bb2dcdb6d82e4134c1cda043edcff74d7983b8bb488c37decb83f950299,
+
diff --git a/testVectors/gg20_zkp/phase6_challenge.json b/testVectors/gg20_zkp/phase6_challenge.json
new file mode 100644
index 0000000..1ccb34d
--- /dev/null
+++ b/testVectors/gg20_zkp/phase6_challenge.json
@@ -0,0 +1,112 @@
+[
+  {
+    "TEST": 0,
+    "R": "0354475938e75d0758f68802730fd684e47a39ae17b5cc7c11edede9bc8e2cd5d4",
+    "ECPT": "0309716b9647851724598b9dd81a5a9a5ceb6504d482e70723eb36c9d368889696",
+    "ECPS": "02389a9a1dd9353486be655cdb5ff19a12e7fc7e734642f5f376c331106f70f3f7",
+    "ALPHA": "039482cca8df14a76f75f1ad1999ced9c79e2a8a9273eb829adb054394eaf46025",
+    "BETA": "025f0379e1c8f3903b235a6cc3720e494acaac79bf696a397272f3abece30e7710",
+    "ID": "eeb100ac7e8fba9d1ab74903cdad83f1",
+    "AD": "",
+    "E": "f62cf3a81f5804e49645b5a3f8734adf128989554db41072f3f8b99334171a06"
+  },
+  {
+    "TEST": 1,
+    "R": "02ddb150fb1da230896a8c6927af2940ab173101a3f79e047319d8d63d32395998",
+    "ECPT": "0268afb804eb127a0d4e0d62c124623450d34794ac70659a1f49f8e3c99a245678",
+    "ECPS": "0359a4097cb654ac954abb35b146689434e4858a83ed7d85e394af9db9bf831745",
+    "ALPHA": "025c3e79194dbd97bfd3007eb07b8c38cab7222ca2efac5e9dcd3ca19f85bf78b1",
+    "BETA": "026aae66f4baed01b34473825fd26d4ca81f6381ba9d8479456352814334c5e793",
+    "ID": "353b15ce8cc5970c9f600676246a84c6",
+    "AD": "",
+    "E": "56faf16927b96f0b77c1f893748ffe084395dd56850aab3317b76e76894e2e7b"
+  },
+  {
+    "TEST": 2,
+    "R": "022a34247efebe83ca8b37038e6f77de6ace7d2b965b9c67d2eff94c1d0224f7a3",
+    "ECPT": "02cc5ec6e5b1685492776049d8597330e8c610b4522ea3b0fb102b87e354e53348",
+    "ECPS": "0331eab8a0f1f864d61526027c33f9c11251acca1132aafbd986d14b4bdf802a5e",
+    "ALPHA": "02387d3942d232ae24063e34a32e0746f6cdc1895f3c1b473ac2f4272ba201d6eb",
+    "BETA": "029185494c1b48bf0fd2ad5d3b0be61798194e95c13407ccba81d7f8f284e9e267",
+    "ID": "ef7ac188e34f2fb9e35db42481f26d47",
+    "AD": "",
+    "E": "22e0be495be895a7ebcfdb81b3dd05de631f167c141e47b8ca50b9afac3280bc"
+  },
+  {
+    "TEST": 3,
+    "R": "0390defac91dae4cc3f364d967719c678c0bd4ea251ba1054223fba9688adc3c56",
+    "ECPT": "035034f368f448a6a277225e3cdb124302fdc942eae6aa1b64a680aacf78869d0e",
+    "ECPS": "02a19b8481f7c8de6fb30c5031ae8a15490b0c2a758f9aefaaf15d3904321dad07",
+    "ALPHA": "02ca814f396e313972d00140567b12f7474a527fb9b390afb256fea46a7a7ecfa5",
+    "BETA": "029d318274c93a9ff8fd90073884659c82dafa66d16b19e0f52144521e794cbcc6",
+    "ID": "1b49574f4c21f41b39ce83332f41333d",
+    "AD": "",
+    "E": "2a5792e835e36cd16c486cda418a40d663113ac2c3ee302c17584462a4f41834"
+  },
+  {
+    "TEST": 4,
+    "R": "035ad96d26b6baf8aed78966f0a644ae736a900bde5d3cdde6c387d7d5a0b0f512",
+    "ECPT": "02161555ec9e569529c058c71352d45ac59ab76aab54df7e20f4a87871e6b673b8",
+    "ECPS": "027ca8c30011b57a3c91f716ba2ebd5156794d57bb96ffef78de66004e1b33c4a4",
+    "ALPHA": "025347b0712617cef345b2e4a2e18423b2161aadd98bbcb9c7bd8c1275e12a8971",
+    "BETA": "02cc2306e87e16bd67b48d2fc25870fa4eea231630d2100fcfbc6e81cd3a52b690",
+    "ID": "8f6d9b7701ec269ea270feb2ec91e318",
+    "AD": "",
+    "E": "5c389ad728f051ead0419585143e17f873072fc370f5ab854c0c6ea7bfb716a8"
+  },
+  {
+    "TEST": 5,
+    "R": "0279df7cf044d99369f9c93421bff3f78f6757c177e2f7f87d3567379ec9190c26",
+    "ECPT": "0334b3a774949b3591f28f02397e0c9ec66afac07f9f9e41b21c8057a7fcd4ca00",
+    "ECPS": "0237285d6b3efeceed33001c33f4d5f53de8b373b3fca5bb0b513541780fbdacaf",
+    "ALPHA": "03c71cf5c62fb9a156f9a03c4d906ce1ee8fbd4151ef2dee23aea639fe7c37d528",
+    "BETA": "03109e23bd81982f7785745354c2b028376d5907d1188429d8276d16a217ccd3d0",
+    "ID": "bfa83a06e6d2dd6f1a745ce02b174372",
+    "AD": "b06c21b98910963763693ed9449d98fd",
+    "E": "a6077eaa1c8ec1b012a29d783e07693116cc021289798de10fc739864ddeed31"
+  },
+  {
+    "TEST": 6,
+    "R": "024a4cc9696b93c927c20c3d91b831ee761b492b09b050c121b48ae4062122a747",
+    "ECPT": "0322cb50ba4c6b8532750d6cd19221e781850dfb144540fba3e731d98cb92e3a80",
+    "ECPS": "0251768a7ad18977533e7baf949684efa6b8bec022fa2a90ab909624c9bf4b7faa",
+    "ALPHA": "026cd424b8b53da925091aef993c902f4e26da7edb6ac8693f86151d4fd3a76c85",
+    "BETA": "02eeae4892bd107dfb893d05af3180a1dab884132e4254c71df1a97adf7f36e7ba",
+    "ID": "71db72ad3d3f60cb4125922ea03bf7d0",
+    "AD": "4469883560394592203d768229e0cbfc",
+    "E": "4b51f084be732ef17d0916a6817a1c4f6c700ef8e1d7d37a02ba88227e5017d4"
+  },
+  {
+    "TEST": 7,
+    "R": "0344f9a8b27b2fab7d74a8d8ffc5dccebe4a7ce995ece6f279ae20df44152582f4",
+    "ECPT": "03000d43caf7f3acd69737d304bee2a96d1f53210e94ff5d0c0cc3e8495ae08357",
+    "ECPS": "02b8e0cf56b022d72fc14cf041ee0ba0b49407d051cface598f9eeefe7c1453629",
+    "ALPHA": "03b9b2387f985051979c108062b976d7f3e2919b8290b1f0ef25e9bcbeee9469e4",
+    "BETA": "02144e08ad48e3f3c166956e81849b510ecb75d8ef87a605f7e8f8a0c7abb06122",
+    "ID": "8b32f6690774743069ee5a6d40cc6870",
+    "AD": "2b3846f25ed3365bbd884f83e6f4548c",
+    "E": "3664df952f1c577e7e2df04c389534bad473dc6af295d044d91b0975284a40e8"
+  },
+  {
+    "TEST": 8,
+    "R": "0257f95048f77b44a1798c0bc71679204359d9a5fb3ab703eba3111fc1f7b09c80",
+    "ECPT": "0394b8365a0c5ef360fd3ce65c591ab7622fedb4169968befbe20dcf33908a00a1",
+    "ECPS": "0297fa2ed1cff034cbc79acc1166676d2a7dd4386fb6d186f45fb04f5376d79316",
+    "ALPHA": "025bd9ebc89644a9130ff710ac31017dcd5474d3bca0f916761e70895606295dd9",
+    "BETA": "027d56e955a33e6e5aa13f6a824dd937979768d6e8c11ffe0471643086f252ab4c",
+    "ID": "b25a1c88e887ee364c5116c2f665ce31",
+    "AD": "6a294254b33675dbb59af7ef489755e3",
+    "E": "2e6c16f6cd496d6e02fd7be9b5b0ac01a16fb43bca842274e16f61b90474bef3"
+  },
+  {
+    "TEST": 9,
+    "R": "02d520f3e4ef26290c24c6b6e48b3ecbc6a3dc0d0fa22252c041c04d5955849928",
+    "ECPT": "02479429d2de02de00128138e9203d611fb14a21de594804f614e082e24bcd0e28",
+    "ECPS": "02b71c2b73b5ae3a2bb29bfd7a5ea2683966d5ccd1dcff243325978d049a7d46cf",
+    "ALPHA": "03b85d472305bdf3f2c98d8d7c3cff9b97ca1b5e80660f837043ac67075b1e9737",
+    "BETA": "02d0983aeb40e1829b55d4d87f5c3186147ec14eb2048e817a114986e053e5298f",
+    "ID": "1e43f22b907d8afaaf7d19f04f77f196",
+    "AD": "0b059b699d94059fc7f0664b4f23aa64",
+    "E": "38dd0bdb76aaeb1799b5af882924999a6538c3916af94f2f6e795ce2180497b3"
+  }
+]
\ No newline at end of file
diff --git a/testVectors/gg20_zkp/phase6_challenge.txt b/testVectors/gg20_zkp/phase6_challenge.txt
new file mode 100644
index 0000000..2426765
--- /dev/null
+++ b/testVectors/gg20_zkp/phase6_challenge.txt
@@ -0,0 +1,100 @@
+TEST = 0,
+R = 0354475938e75d0758f68802730fd684e47a39ae17b5cc7c11edede9bc8e2cd5d4,
+ECPT = 0309716b9647851724598b9dd81a5a9a5ceb6504d482e70723eb36c9d368889696,
+ECPS = 02389a9a1dd9353486be655cdb5ff19a12e7fc7e734642f5f376c331106f70f3f7,
+ALPHA = 039482cca8df14a76f75f1ad1999ced9c79e2a8a9273eb829adb054394eaf46025,
+BETA = 025f0379e1c8f3903b235a6cc3720e494acaac79bf696a397272f3abece30e7710,
+ID = eeb100ac7e8fba9d1ab74903cdad83f1,
+AD = ,
+E = f62cf3a81f5804e49645b5a3f8734adf128989554db41072f3f8b99334171a06,
+
+TEST = 1,
+R = 02ddb150fb1da230896a8c6927af2940ab173101a3f79e047319d8d63d32395998,
+ECPT = 0268afb804eb127a0d4e0d62c124623450d34794ac70659a1f49f8e3c99a245678,
+ECPS = 0359a4097cb654ac954abb35b146689434e4858a83ed7d85e394af9db9bf831745,
+ALPHA = 025c3e79194dbd97bfd3007eb07b8c38cab7222ca2efac5e9dcd3ca19f85bf78b1,
+BETA = 026aae66f4baed01b34473825fd26d4ca81f6381ba9d8479456352814334c5e793,
+ID = 353b15ce8cc5970c9f600676246a84c6,
+AD = ,
+E = 56faf16927b96f0b77c1f893748ffe084395dd56850aab3317b76e76894e2e7b,
+
+TEST = 2,
+R = 022a34247efebe83ca8b37038e6f77de6ace7d2b965b9c67d2eff94c1d0224f7a3,
+ECPT = 02cc5ec6e5b1685492776049d8597330e8c610b4522ea3b0fb102b87e354e53348,
+ECPS = 0331eab8a0f1f864d61526027c33f9c11251acca1132aafbd986d14b4bdf802a5e,
+ALPHA = 02387d3942d232ae24063e34a32e0746f6cdc1895f3c1b473ac2f4272ba201d6eb,
+BETA = 029185494c1b48bf0fd2ad5d3b0be61798194e95c13407ccba81d7f8f284e9e267,
+ID = ef7ac188e34f2fb9e35db42481f26d47,
+AD = ,
+E = 22e0be495be895a7ebcfdb81b3dd05de631f167c141e47b8ca50b9afac3280bc,
+
+TEST = 3,
+R = 0390defac91dae4cc3f364d967719c678c0bd4ea251ba1054223fba9688adc3c56,
+ECPT = 035034f368f448a6a277225e3cdb124302fdc942eae6aa1b64a680aacf78869d0e,
+ECPS = 02a19b8481f7c8de6fb30c5031ae8a15490b0c2a758f9aefaaf15d3904321dad07,
+ALPHA = 02ca814f396e313972d00140567b12f7474a527fb9b390afb256fea46a7a7ecfa5,
+BETA = 029d318274c93a9ff8fd90073884659c82dafa66d16b19e0f52144521e794cbcc6,
+ID = 1b49574f4c21f41b39ce83332f41333d,
+AD = ,
+E = 2a5792e835e36cd16c486cda418a40d663113ac2c3ee302c17584462a4f41834,
+
+TEST = 4,
+R = 035ad96d26b6baf8aed78966f0a644ae736a900bde5d3cdde6c387d7d5a0b0f512,
+ECPT = 02161555ec9e569529c058c71352d45ac59ab76aab54df7e20f4a87871e6b673b8,
+ECPS = 027ca8c30011b57a3c91f716ba2ebd5156794d57bb96ffef78de66004e1b33c4a4,
+ALPHA = 025347b0712617cef345b2e4a2e18423b2161aadd98bbcb9c7bd8c1275e12a8971,
+BETA = 02cc2306e87e16bd67b48d2fc25870fa4eea231630d2100fcfbc6e81cd3a52b690,
+ID = 8f6d9b7701ec269ea270feb2ec91e318,
+AD = ,
+E = 5c389ad728f051ead0419585143e17f873072fc370f5ab854c0c6ea7bfb716a8,
+
+TEST = 5,
+R = 0279df7cf044d99369f9c93421bff3f78f6757c177e2f7f87d3567379ec9190c26,
+ECPT = 0334b3a774949b3591f28f02397e0c9ec66afac07f9f9e41b21c8057a7fcd4ca00,
+ECPS = 0237285d6b3efeceed33001c33f4d5f53de8b373b3fca5bb0b513541780fbdacaf,
+ALPHA = 03c71cf5c62fb9a156f9a03c4d906ce1ee8fbd4151ef2dee23aea639fe7c37d528,
+BETA = 03109e23bd81982f7785745354c2b028376d5907d1188429d8276d16a217ccd3d0,
+ID = bfa83a06e6d2dd6f1a745ce02b174372,
+AD = b06c21b98910963763693ed9449d98fd,
+E = a6077eaa1c8ec1b012a29d783e07693116cc021289798de10fc739864ddeed31,
+
+TEST = 6,
+R = 024a4cc9696b93c927c20c3d91b831ee761b492b09b050c121b48ae4062122a747,
+ECPT = 0322cb50ba4c6b8532750d6cd19221e781850dfb144540fba3e731d98cb92e3a80,
+ECPS = 0251768a7ad18977533e7baf949684efa6b8bec022fa2a90ab909624c9bf4b7faa,
+ALPHA = 026cd424b8b53da925091aef993c902f4e26da7edb6ac8693f86151d4fd3a76c85,
+BETA = 02eeae4892bd107dfb893d05af3180a1dab884132e4254c71df1a97adf7f36e7ba,
+ID = 71db72ad3d3f60cb4125922ea03bf7d0,
+AD = 4469883560394592203d768229e0cbfc,
+E = 4b51f084be732ef17d0916a6817a1c4f6c700ef8e1d7d37a02ba88227e5017d4,
+
+TEST = 7,
+R = 0344f9a8b27b2fab7d74a8d8ffc5dccebe4a7ce995ece6f279ae20df44152582f4,
+ECPT = 03000d43caf7f3acd69737d304bee2a96d1f53210e94ff5d0c0cc3e8495ae08357,
+ECPS = 02b8e0cf56b022d72fc14cf041ee0ba0b49407d051cface598f9eeefe7c1453629,
+ALPHA = 03b9b2387f985051979c108062b976d7f3e2919b8290b1f0ef25e9bcbeee9469e4,
+BETA = 02144e08ad48e3f3c166956e81849b510ecb75d8ef87a605f7e8f8a0c7abb06122,
+ID = 8b32f6690774743069ee5a6d40cc6870,
+AD = 2b3846f25ed3365bbd884f83e6f4548c,
+E = 3664df952f1c577e7e2df04c389534bad473dc6af295d044d91b0975284a40e8,
+
+TEST = 8,
+R = 0257f95048f77b44a1798c0bc71679204359d9a5fb3ab703eba3111fc1f7b09c80,
+ECPT = 0394b8365a0c5ef360fd3ce65c591ab7622fedb4169968befbe20dcf33908a00a1,
+ECPS = 0297fa2ed1cff034cbc79acc1166676d2a7dd4386fb6d186f45fb04f5376d79316,
+ALPHA = 025bd9ebc89644a9130ff710ac31017dcd5474d3bca0f916761e70895606295dd9,
+BETA = 027d56e955a33e6e5aa13f6a824dd937979768d6e8c11ffe0471643086f252ab4c,
+ID = b25a1c88e887ee364c5116c2f665ce31,
+AD = 6a294254b33675dbb59af7ef489755e3,
+E = 2e6c16f6cd496d6e02fd7be9b5b0ac01a16fb43bca842274e16f61b90474bef3,
+
+TEST = 9,
+R = 02d520f3e4ef26290c24c6b6e48b3ecbc6a3dc0d0fa22252c041c04d5955849928,
+ECPT = 02479429d2de02de00128138e9203d611fb14a21de594804f614e082e24bcd0e28,
+ECPS = 02b71c2b73b5ae3a2bb29bfd7a5ea2683966d5ccd1dcff243325978d049a7d46cf,
+ALPHA = 03b85d472305bdf3f2c98d8d7c3cff9b97ca1b5e80660f837043ac67075b1e9737,
+BETA = 02d0983aeb40e1829b55d4d87f5c3186147ec14eb2048e817a114986e053e5298f,
+ID = 1e43f22b907d8afaaf7d19f04f77f196,
+AD = 0b059b699d94059fc7f0664b4f23aa64,
+E = 38dd0bdb76aaeb1799b5af882924999a6538c3916af94f2f6e795ce2180497b3,
+
diff --git a/testVectors/gg20_zkp/phase6_commit.json b/testVectors/gg20_zkp/phase6_commit.json
new file mode 100644
index 0000000..8f76a9b
--- /dev/null
+++ b/testVectors/gg20_zkp/phase6_commit.json
@@ -0,0 +1,82 @@
+[
+  {
+    "TEST": 0,
+    "R": "03a9d19d66ca686d47787b0bccc4db0d962056e8b8d03d1ea2329a62667ee0b14e",
+    "A": "a311086946e737cb90f4f3575bd8f17bf004724add7bd7ef9220302903a025f9",
+    "B": "0e1425a719cc271acff9ca0bb140c19c9ad82ea8c2418fbfa0ea47550bcc39d9",
+    "ALPHA": "02c6fb6f18f732f8906b11690c41c412103d95e12cb9bf974d10b0239baeeffd3c",
+    "BETA": "02893028961112ee8c139e6c1991249b737434215d50bd9edabcede1aff24b2afa"
+  },
+  {
+    "TEST": 1,
+    "R": "02dda806c7c882ce7d467871068a6ca69e4dc7e42a912a13275acb71b74d798867",
+    "A": "df884589c960c5dd4638c2472cd1e2008d1fb41a09be81a843b541a22b177c9b",
+    "B": "c33adcc15c9dd5e0b0acf82f854c93b30e182d4b66de8538e30e487e3a7835a7",
+    "ALPHA": "033efe70bc113af12c6e1a1e4804a5d6140e36da8438fd238c5245420d46035cb4",
+    "BETA": "03b0df256256a4d1ebabd3d088f785fa4256e35b15d87c8118982a382eae9a5fd5"
+  },
+  {
+    "TEST": 2,
+    "R": "02073a783927377ec51028e65b5a17702fa4e26ec720490592303393d0d085cb39",
+    "A": "bba11de9d0c4ff9bbb9c674dafa1a27fa02882b2ffaba1d8caac6935ee776f50",
+    "B": "181462ec77ab2d6324a990d3e9395cd1fa7ac8b128354c0882196f388893ea97",
+    "ALPHA": "02a58b93a867ef13d8c4ece3c1fd7d88b1ee4fb7b0ae88fd644ca65fa9bbaaa91a",
+    "BETA": "02bdb475ba532e8e4bdc75c8d3da665524e16897646f133ff1f46debb23db518cd"
+  },
+  {
+    "TEST": 3,
+    "R": "02f83367446b99a2fceade742113410ee82c6edb5eb7a69ce3d11de04edec27446",
+    "A": "4fa23c8f86896304647e1619be5a3451755cb1fe35ff06f3b7e9a71a49ba97ab",
+    "B": "3ea1a7a6c80a63a04b696c307de3caa13b5b1dc9ec7cbc5bb925edc2f7c2b432",
+    "ALPHA": "024a9d38c6dd6464dfd5f1c48b54a93d1dbefbc9df6c5d73ed484eb5d2ed2c39ac",
+    "BETA": "039674b4d13d3fd8bd969959cc69a93b459e9db4cdd93760ee0392ea9c4abeb802"
+  },
+  {
+    "TEST": 4,
+    "R": "033ecc8a569e26ed22ba2788d51c9e93044e349eecced0509099e8924cc385bfe2",
+    "A": "335596410f3b5b5fec92bbc83e17b3821daf182537bc5c6756fe228af1724e41",
+    "B": "06a803ceeab3bf20d3e7b0f94f4b30257bfe05d00e4962aa6325f8bed01a20f2",
+    "ALPHA": "0358491775a269318fde1a684fda434c5362d14cfd3cd00dbc625d1f50dbd9f6e8",
+    "BETA": "037977bcdb620361355bf7d9d29689d90a5fb5a4766905275b9b6ddb31cc4b673d"
+  },
+  {
+    "TEST": 5,
+    "R": "029f8cfb62ad66b310837e3129f71dbcc7b24901a595ac9ab19ceaff26ebfef873",
+    "A": "829bfe5e2c6a0f0d6d53dbff1b07cfd94e2168e35dc854c71e15b54717bb2b62",
+    "B": "512c45b56c25fd7b0e3359b833232dcc523aa4208eba91bd4cf0a66cf48b7d07",
+    "ALPHA": "02a9f78b24582fa72c45027682e6c578266cfe0087563f03e49a6ab6eba94ae0e6",
+    "BETA": "03c4ca090151d7a4c1cb178835ff43e4d0e1a93f6efb25661399fd1ed0b43bb98a"
+  },
+  {
+    "TEST": 6,
+    "R": "03e8fb870790ec9d699ea56804385541888af40400bce96b3a5e23d19107b57fa4",
+    "A": "bca79a26189a3655c35bb74d94c49f22726d4ea23f0572fe8add29607884ea19",
+    "B": "ad446ab7e674ab18f2310081db5782540b701fc0f3c4d3b8367fc21315612966",
+    "ALPHA": "0337f7a55ec8ecc01d4ec8d9b5c13b671832cf11aceb405f7b1476d2ba46a957fd",
+    "BETA": "02894aed53ee60156b0cf61d71647424d2cc80de8dde6659a2a04c81073246f2cc"
+  },
+  {
+    "TEST": 7,
+    "R": "024fc393a6716b185ebdedf856c7fc12d5506b8ad90a6734ee96f8413d6f35dd16",
+    "A": "5fcddb1c976d2dc7ca8ff035251e6f94f542695860890864730ea6d2749cfd95",
+    "B": "187c5cbe3d5b8d6e42743fe4faf09565e1f26a96f66ee55d291137691d6e256a",
+    "ALPHA": "0229012eede68a4b0fb89d41c45123567b689de83977e0d4eee23197352051a458",
+    "BETA": "02132c61a945337a7b9770a9633c7961a64cc0af4d2532ce3412aefeed2e0e796d"
+  },
+  {
+    "TEST": 8,
+    "R": "02e2aba9954d7bedb5e29cdc5808903720a119496e9f6303e0fc1199f13f07d954",
+    "A": "4b94e36c6589eeab2df7988198998cd61ecc7599abf7581ec7571d4572cf761e",
+    "B": "e40a7d67b009563ce732ef1d50e97652afb7b8c5ac81da9ab0e59c228dcf36d3",
+    "ALPHA": "027dc0edd1eec628621c8210a6749f165a1d9c4fc34d2a8324db59b29a3aea17c5",
+    "BETA": "033d16586629c904d6fc6e9ed0f28fd0fc7a2f82fb33eedabf980c0b68a53dc2c0"
+  },
+  {
+    "TEST": 9,
+    "R": "03b175d872b8e3009cb5f81c0c383b7c9603f5f203403d00100da08d1fea20ec85",
+    "A": "16a872b0055ef25fb7fe08bc8eb2e9085d7fe10548d5dc3f64e6f4b5fd807eff",
+    "B": "766d3a5818cb17b0e3c3008bf9e1007db24ded41947cf05619dae8e99a6ca5d0",
+    "ALPHA": "02057f0324b16eddaefde206a00ad6cac24b33ff4b9db9512168485016e557ab30",
+    "BETA": "036f4486b6f8d2b591ad1f2acdef02dfe6d59f9f933a56e0da30a39d67a5e6aa6e"
+  }
+]
\ No newline at end of file
diff --git a/testVectors/gg20_zkp/phase6_commit.txt b/testVectors/gg20_zkp/phase6_commit.txt
new file mode 100644
index 0000000..27a319b
--- /dev/null
+++ b/testVectors/gg20_zkp/phase6_commit.txt
@@ -0,0 +1,70 @@
+TEST = 0,
+R = 03a9d19d66ca686d47787b0bccc4db0d962056e8b8d03d1ea2329a62667ee0b14e,
+A = a311086946e737cb90f4f3575bd8f17bf004724add7bd7ef9220302903a025f9,
+B = 0e1425a719cc271acff9ca0bb140c19c9ad82ea8c2418fbfa0ea47550bcc39d9,
+ALPHA = 02c6fb6f18f732f8906b11690c41c412103d95e12cb9bf974d10b0239baeeffd3c,
+BETA = 02893028961112ee8c139e6c1991249b737434215d50bd9edabcede1aff24b2afa,
+
+TEST = 1,
+R = 02dda806c7c882ce7d467871068a6ca69e4dc7e42a912a13275acb71b74d798867,
+A = df884589c960c5dd4638c2472cd1e2008d1fb41a09be81a843b541a22b177c9b,
+B = c33adcc15c9dd5e0b0acf82f854c93b30e182d4b66de8538e30e487e3a7835a7,
+ALPHA = 033efe70bc113af12c6e1a1e4804a5d6140e36da8438fd238c5245420d46035cb4,
+BETA = 03b0df256256a4d1ebabd3d088f785fa4256e35b15d87c8118982a382eae9a5fd5,
+
+TEST = 2,
+R = 02073a783927377ec51028e65b5a17702fa4e26ec720490592303393d0d085cb39,
+A = bba11de9d0c4ff9bbb9c674dafa1a27fa02882b2ffaba1d8caac6935ee776f50,
+B = 181462ec77ab2d6324a990d3e9395cd1fa7ac8b128354c0882196f388893ea97,
+ALPHA = 02a58b93a867ef13d8c4ece3c1fd7d88b1ee4fb7b0ae88fd644ca65fa9bbaaa91a,
+BETA = 02bdb475ba532e8e4bdc75c8d3da665524e16897646f133ff1f46debb23db518cd,
+
+TEST = 3,
+R = 02f83367446b99a2fceade742113410ee82c6edb5eb7a69ce3d11de04edec27446,
+A = 4fa23c8f86896304647e1619be5a3451755cb1fe35ff06f3b7e9a71a49ba97ab,
+B = 3ea1a7a6c80a63a04b696c307de3caa13b5b1dc9ec7cbc5bb925edc2f7c2b432,
+ALPHA = 024a9d38c6dd6464dfd5f1c48b54a93d1dbefbc9df6c5d73ed484eb5d2ed2c39ac,
+BETA = 039674b4d13d3fd8bd969959cc69a93b459e9db4cdd93760ee0392ea9c4abeb802,
+
+TEST = 4,
+R = 033ecc8a569e26ed22ba2788d51c9e93044e349eecced0509099e8924cc385bfe2,
+A = 335596410f3b5b5fec92bbc83e17b3821daf182537bc5c6756fe228af1724e41,
+B = 06a803ceeab3bf20d3e7b0f94f4b30257bfe05d00e4962aa6325f8bed01a20f2,
+ALPHA = 0358491775a269318fde1a684fda434c5362d14cfd3cd00dbc625d1f50dbd9f6e8,
+BETA = 037977bcdb620361355bf7d9d29689d90a5fb5a4766905275b9b6ddb31cc4b673d,
+
+TEST = 5,
+R = 029f8cfb62ad66b310837e3129f71dbcc7b24901a595ac9ab19ceaff26ebfef873,
+A = 829bfe5e2c6a0f0d6d53dbff1b07cfd94e2168e35dc854c71e15b54717bb2b62,
+B = 512c45b56c25fd7b0e3359b833232dcc523aa4208eba91bd4cf0a66cf48b7d07,
+ALPHA = 02a9f78b24582fa72c45027682e6c578266cfe0087563f03e49a6ab6eba94ae0e6,
+BETA = 03c4ca090151d7a4c1cb178835ff43e4d0e1a93f6efb25661399fd1ed0b43bb98a,
+
+TEST = 6,
+R = 03e8fb870790ec9d699ea56804385541888af40400bce96b3a5e23d19107b57fa4,
+A = bca79a26189a3655c35bb74d94c49f22726d4ea23f0572fe8add29607884ea19,
+B = ad446ab7e674ab18f2310081db5782540b701fc0f3c4d3b8367fc21315612966,
+ALPHA = 0337f7a55ec8ecc01d4ec8d9b5c13b671832cf11aceb405f7b1476d2ba46a957fd,
+BETA = 02894aed53ee60156b0cf61d71647424d2cc80de8dde6659a2a04c81073246f2cc,
+
+TEST = 7,
+R = 024fc393a6716b185ebdedf856c7fc12d5506b8ad90a6734ee96f8413d6f35dd16,
+A = 5fcddb1c976d2dc7ca8ff035251e6f94f542695860890864730ea6d2749cfd95,
+B = 187c5cbe3d5b8d6e42743fe4faf09565e1f26a96f66ee55d291137691d6e256a,
+ALPHA = 0229012eede68a4b0fb89d41c45123567b689de83977e0d4eee23197352051a458,
+BETA = 02132c61a945337a7b9770a9633c7961a64cc0af4d2532ce3412aefeed2e0e796d,
+
+TEST = 8,
+R = 02e2aba9954d7bedb5e29cdc5808903720a119496e9f6303e0fc1199f13f07d954,
+A = 4b94e36c6589eeab2df7988198998cd61ecc7599abf7581ec7571d4572cf761e,
+B = e40a7d67b009563ce732ef1d50e97652afb7b8c5ac81da9ab0e59c228dcf36d3,
+ALPHA = 027dc0edd1eec628621c8210a6749f165a1d9c4fc34d2a8324db59b29a3aea17c5,
+BETA = 033d16586629c904d6fc6e9ed0f28fd0fc7a2f82fb33eedabf980c0b68a53dc2c0,
+
+TEST = 9,
+R = 03b175d872b8e3009cb5f81c0c383b7c9603f5f203403d00100da08d1fea20ec85,
+A = 16a872b0055ef25fb7fe08bc8eb2e9085d7fe10548d5dc3f64e6f4b5fd807eff,
+B = 766d3a5818cb17b0e3c3008bf9e1007db24ded41947cf05619dae8e99a6ca5d0,
+ALPHA = 02057f0324b16eddaefde206a00ad6cac24b33ff4b9db9512168485016e557ab30,
+BETA = 036f4486b6f8d2b591ad1f2acdef02dfe6d59f9f933a56e0da30a39d67a5e6aa6e,
+
diff --git a/testVectors/gg20_zkp/phase6_prove.json b/testVectors/gg20_zkp/phase6_prove.json
new file mode 100644
index 0000000..182f723
--- /dev/null
+++ b/testVectors/gg20_zkp/phase6_prove.json
@@ -0,0 +1,102 @@
+[
+  {
+    "TEST": 0,
+    "A": "c46280bdcfe7041c9b85864a19f551fd76ba019b3ddf225be838b6f8367ff554",
+    "B": "8d6aedfe66bfb78d8b6b93fb36a87dba034a97d22652f3b88800897ce779382d",
+    "E": "bc116191af9b64db4068237e6a44c21eb5d9d0fed4ad2866a204067edfc08dbf",
+    "S": "e2bf8d7db4a2520473ed3ec7ffbbe952811f4ebf12748318474a0c8c6f39454a",
+    "L": "e168ecd5e2c9d342bc0c338e2ea5ac328093cd3719152ef0b9e91e31dc7103b6",
+    "T": "0cf0cdf21c8f45ecad7ab34795b9a1a0b6890be17f48cc99431c52f7ae4a6a5b",
+    "U": "fa09d8bfa7483ee3e0f34f5e6dccb5c34c2380f2bf54dd7dc70fce8ffe54b904"
+  },
+  {
+    "TEST": 1,
+    "A": "f49f8be15d580b34504f7e9d4fa91fa2194709128f9b15eb29075150df727d71",
+    "B": "98d5943dfcf8fcab987a56422d68d3449805aee3cb4ce8d416af1477dd0127f2",
+    "E": "cd41053395c5ea4deddf7ffbe91e6621094fb9c9a5d5fc411bdab67679fdcdcc",
+    "S": "e172f5910de057942c5b988a22d642f537c1f41c499db0c58b69cfa8788388f7",
+    "L": "d37c515f7603e27bda8d2073e81d7b5fb1678e4ffd82ee112024850e13725fdb",
+    "T": "262c67803f4c9824d406184086467d56a71d97df1ea330e4cf72b28aba9ed14a",
+    "U": "1dcb1ba668cff08e8574d083acf92e0f60d767e7686a815ac51ec16cd7238c84"
+  },
+  {
+    "TEST": 2,
+    "A": "351b4bbf2dde9f96dc4512ae30b6750c2710d7c466d541d6835b8aeee171b835",
+    "B": "c187170626360045315129dabba599325912a4a69a4996fb0b262682db02b830",
+    "E": "e6bce745a963b36bce5a47543cef3048ca1c4b9b236f052b0c32e94d6f34693d",
+    "S": "1177001af7747f2458cb04e60ebcb751bd5f927da53a7f930dfd56ca902f0205",
+    "L": "9fd89ecd4f2828ab2eff8cc4289388bfa2be9f94fa090fc06cadaec10615d770",
+    "T": "4e3b6e7412da2122288435f980c9658ac28ebd0064ea33eaa536156f01a0d106",
+    "U": "0a91d097025689b8a94e50f19f55c28dae4d607aee2b91b51e933ba8affc23c1"
+  },
+  {
+    "TEST": 3,
+    "A": "eb994bc958a9cb43e1a6b943e941fcf3c1fe18a68410b7a5896b205d99eac388",
+    "B": "0ed7a273d5e0fb13a57ab567dff28134eb83b3f43a472a4a0e7c5f098c695069",
+    "E": "0a876cb0f03608b1935212bb748a26ef64b617a8e81e6bf0b54e5b1b8ebd5d5d",
+    "S": "f6a73b8752ac0353a447e2e6990d4b8c163e45f840b7fd8d7bc4b7db4863f38a",
+    "L": "d7eb77dc26fbec4db52be2e632d27c6eb9d24db93f728cfa601b430988bea7c5",
+    "T": "743b7bac6dae30896cd051064fc93287376f2da22f760eea74f755785931d619",
+    "U": "fef1d7d796c06dd56a21f54ecbc1a0aecb650d018c937e83a845d50f1322afa9"
+  },
+  {
+    "TEST": 4,
+    "A": "23b7b72a2b11af03b1aeaf05d01bfbed7fde418e699380d4bf93fa067c6c4f6c",
+    "B": "30787257dfcc8aa31d280a1228512313083e75ec8a60dd241c68eca888a09489",
+    "E": "e8277d16a233ddac9a07f16b65c32886441e9499c8359c9d4e0b41748cf2e017",
+    "S": "abdad043c00ac98e6eed683f146a82cffad5959e30fce9e7b9c54aa9074c0bc9",
+    "L": "e2fc682fd024d71cc255df1357a671ea2dc29f079e5360064e402160e216bf10",
+    "T": "14edbb7b5dc688215da48e0b19c638cd81be751f2cb2f85f24645352fb22c70e",
+    "U": "20e87a78d7b2bad5bfc03193f9e37fb648ced02af9b59767b94adca0bbaaa3ac"
+  },
+  {
+    "TEST": 5,
+    "A": "494f89875089d78a7a2f41b3a8b6996f0974f98f659960da6eae1a2d940290fb",
+    "B": "d42667e74c7361d5411e4dcb6c45cba47635d11c81c4558cccbbd9ad479bb85b",
+    "E": "31007a72dfff9162e05c643bdc50f5f8a36021afc2e38fc42169a09bda6ff29f",
+    "S": "9e9a1a632d469e2e564644b0860393fbfa4f37484f35eb2461480b214d526766",
+    "L": "848ae0144f742f7f14b01b001cf221a9ab0db08bfccc79897f5b10e4ec22bb49",
+    "T": "3e0365a79f7384e617d4cf0c510ddb94ec8bdad808bc66892e5769d774a25a18",
+    "U": "487290d3a463d4f7a176d7f6a6615e934030379dae904c534fe9b06da318a7c7"
+  },
+  {
+    "TEST": 6,
+    "A": "55e94add79364194bf46e94d17fcbca0185d0e16f269819041ae3caddfcbf0c6",
+    "B": "43d4b7fac31343c36558581b5fc51213103199c0d414edc26a58a5b02ee3f22e",
+    "E": "42f4f3fb31c702104935721de193f7be5998bd62ffa3857df04d2f7fcbc01efe",
+    "S": "0dac4075445bcaad18313ca539e5bc42f8d1c39efe310ea6211ff5fed3c8cc3d",
+    "L": "831151a6b53173abd585e0cdd1f022177266a1110f089d1a9bdd1385259da3b5",
+    "T": "3de019de8722fa8175a72262abd0acf56e89286703f92f12bf78c149a2770f89",
+    "U": "ef05d65dd4be5c535f062aedd268cd4e962f37500890ab57e24d9eb5a698805c"
+  },
+  {
+    "TEST": 7,
+    "A": "c4e6710e39d30929099ae283806c0773317fc8c441e0b58c9f85f1cac382f756",
+    "B": "b0e6af5e8ccfc10a07561396e37024971850facede8d3d8d6ddb4879c7af43a9",
+    "E": "00b74306805a268c19eccbc082d6d83e2043e7003e51c256648f71fc7290cb07",
+    "S": "6e85ad6abeceb3d09f3a057efb72d3e4efed256b285ae042c4b69319ef7c1f73",
+    "L": "6570c0ec97642edeeace0fb86b217addaed54b969a59261af12f769b0e553f73",
+    "T": "8f602dab8c0e43cce8e4cc27c00f69fa6dd24ee6c4bced176491ff06f6d6b1ea",
+    "U": "c689ba49b0b190ad115d1d8453e9c957d2e404fe7ba7c06f7f911b289950b6a7"
+  },
+  {
+    "TEST": 8,
+    "A": "e7c3f95b6e903e610432a3f91dc94f5061755d869dbb2ea1573f15668654d229",
+    "B": "e5e62572036c81ba0fe43877e0072b16b75233dc011904353eaca882ae148147",
+    "E": "d3b793bf89e953a66f3b6db6f3a1028950fd508524b049a8163ec58a8c239c34",
+    "S": "4d3d25d3cd62a0e6777358279f30fc92a20204dd5d235b5a788430c1103d9a70",
+    "L": "2201e6ea9f8e95f322f09f72d9f335a5c1e71daaa63197b06a55443fc678be8a",
+    "T": "4424c3965b77294a6bf8b7b6a8802ba331681e81d85584a701aca9c5219a173d",
+    "U": "94f29f5fb184adb206c5913c8ac7e4bd72bdce8c822eaf9266db9ee13b78a1ad"
+  },
+  {
+    "TEST": 9,
+    "A": "79f9007692e6ccb44311dffb39650b464a090b74c243ba71b53b5f2864115e84",
+    "B": "ddf6a062e5b0713e44ee603bf76ef50b9c814a90fd070b3a2584c39330a42079",
+    "E": "f01d8981018757bec7ccd7e478593e4d6712a1211f04077fffdbaf4ed774fbb2",
+    "S": "e17f9b31b2d217c0f57ba02a2f444daa402066d8220884477ee52ac868ad74d2",
+    "L": "b96dae35aecb8c199d52b1c94f1a111ab6ac9cec10d961f05ef6ad31fdde0bb0",
+    "T": "9ed876d2dc350ccf23d9891e2455724ec23de37ea8fef76ddb32eae76c98309d",
+    "U": "c8573e32004c8326cb3cf89b266e40232a2bb80b3c67b36798a60e434fd1cfa3"
+  }
+]
\ No newline at end of file
diff --git a/testVectors/gg20_zkp/phase6_prove.txt b/testVectors/gg20_zkp/phase6_prove.txt
new file mode 100644
index 0000000..60902af
--- /dev/null
+++ b/testVectors/gg20_zkp/phase6_prove.txt
@@ -0,0 +1,90 @@
+TEST = 0,
+A = c46280bdcfe7041c9b85864a19f551fd76ba019b3ddf225be838b6f8367ff554,
+B = 8d6aedfe66bfb78d8b6b93fb36a87dba034a97d22652f3b88800897ce779382d,
+E = bc116191af9b64db4068237e6a44c21eb5d9d0fed4ad2866a204067edfc08dbf,
+S = e2bf8d7db4a2520473ed3ec7ffbbe952811f4ebf12748318474a0c8c6f39454a,
+L = e168ecd5e2c9d342bc0c338e2ea5ac328093cd3719152ef0b9e91e31dc7103b6,
+T = 0cf0cdf21c8f45ecad7ab34795b9a1a0b6890be17f48cc99431c52f7ae4a6a5b,
+U = fa09d8bfa7483ee3e0f34f5e6dccb5c34c2380f2bf54dd7dc70fce8ffe54b904,
+
+TEST = 1,
+A = f49f8be15d580b34504f7e9d4fa91fa2194709128f9b15eb29075150df727d71,
+B = 98d5943dfcf8fcab987a56422d68d3449805aee3cb4ce8d416af1477dd0127f2,
+E = cd41053395c5ea4deddf7ffbe91e6621094fb9c9a5d5fc411bdab67679fdcdcc,
+S = e172f5910de057942c5b988a22d642f537c1f41c499db0c58b69cfa8788388f7,
+L = d37c515f7603e27bda8d2073e81d7b5fb1678e4ffd82ee112024850e13725fdb,
+T = 262c67803f4c9824d406184086467d56a71d97df1ea330e4cf72b28aba9ed14a,
+U = 1dcb1ba668cff08e8574d083acf92e0f60d767e7686a815ac51ec16cd7238c84,
+
+TEST = 2,
+A = 351b4bbf2dde9f96dc4512ae30b6750c2710d7c466d541d6835b8aeee171b835,
+B = c187170626360045315129dabba599325912a4a69a4996fb0b262682db02b830,
+E = e6bce745a963b36bce5a47543cef3048ca1c4b9b236f052b0c32e94d6f34693d,
+S = 1177001af7747f2458cb04e60ebcb751bd5f927da53a7f930dfd56ca902f0205,
+L = 9fd89ecd4f2828ab2eff8cc4289388bfa2be9f94fa090fc06cadaec10615d770,
+T = 4e3b6e7412da2122288435f980c9658ac28ebd0064ea33eaa536156f01a0d106,
+U = 0a91d097025689b8a94e50f19f55c28dae4d607aee2b91b51e933ba8affc23c1,
+
+TEST = 3,
+A = eb994bc958a9cb43e1a6b943e941fcf3c1fe18a68410b7a5896b205d99eac388,
+B = 0ed7a273d5e0fb13a57ab567dff28134eb83b3f43a472a4a0e7c5f098c695069,
+E = 0a876cb0f03608b1935212bb748a26ef64b617a8e81e6bf0b54e5b1b8ebd5d5d,
+S = f6a73b8752ac0353a447e2e6990d4b8c163e45f840b7fd8d7bc4b7db4863f38a,
+L = d7eb77dc26fbec4db52be2e632d27c6eb9d24db93f728cfa601b430988bea7c5,
+T = 743b7bac6dae30896cd051064fc93287376f2da22f760eea74f755785931d619,
+U = fef1d7d796c06dd56a21f54ecbc1a0aecb650d018c937e83a845d50f1322afa9,
+
+TEST = 4,
+A = 23b7b72a2b11af03b1aeaf05d01bfbed7fde418e699380d4bf93fa067c6c4f6c,
+B = 30787257dfcc8aa31d280a1228512313083e75ec8a60dd241c68eca888a09489,
+E = e8277d16a233ddac9a07f16b65c32886441e9499c8359c9d4e0b41748cf2e017,
+S = abdad043c00ac98e6eed683f146a82cffad5959e30fce9e7b9c54aa9074c0bc9,
+L = e2fc682fd024d71cc255df1357a671ea2dc29f079e5360064e402160e216bf10,
+T = 14edbb7b5dc688215da48e0b19c638cd81be751f2cb2f85f24645352fb22c70e,
+U = 20e87a78d7b2bad5bfc03193f9e37fb648ced02af9b59767b94adca0bbaaa3ac,
+
+TEST = 5,
+A = 494f89875089d78a7a2f41b3a8b6996f0974f98f659960da6eae1a2d940290fb,
+B = d42667e74c7361d5411e4dcb6c45cba47635d11c81c4558cccbbd9ad479bb85b,
+E = 31007a72dfff9162e05c643bdc50f5f8a36021afc2e38fc42169a09bda6ff29f,
+S = 9e9a1a632d469e2e564644b0860393fbfa4f37484f35eb2461480b214d526766,
+L = 848ae0144f742f7f14b01b001cf221a9ab0db08bfccc79897f5b10e4ec22bb49,
+T = 3e0365a79f7384e617d4cf0c510ddb94ec8bdad808bc66892e5769d774a25a18,
+U = 487290d3a463d4f7a176d7f6a6615e934030379dae904c534fe9b06da318a7c7,
+
+TEST = 6,
+A = 55e94add79364194bf46e94d17fcbca0185d0e16f269819041ae3caddfcbf0c6,
+B = 43d4b7fac31343c36558581b5fc51213103199c0d414edc26a58a5b02ee3f22e,
+E = 42f4f3fb31c702104935721de193f7be5998bd62ffa3857df04d2f7fcbc01efe,
+S = 0dac4075445bcaad18313ca539e5bc42f8d1c39efe310ea6211ff5fed3c8cc3d,
+L = 831151a6b53173abd585e0cdd1f022177266a1110f089d1a9bdd1385259da3b5,
+T = 3de019de8722fa8175a72262abd0acf56e89286703f92f12bf78c149a2770f89,
+U = ef05d65dd4be5c535f062aedd268cd4e962f37500890ab57e24d9eb5a698805c,
+
+TEST = 7,
+A = c4e6710e39d30929099ae283806c0773317fc8c441e0b58c9f85f1cac382f756,
+B = b0e6af5e8ccfc10a07561396e37024971850facede8d3d8d6ddb4879c7af43a9,
+E = 00b74306805a268c19eccbc082d6d83e2043e7003e51c256648f71fc7290cb07,
+S = 6e85ad6abeceb3d09f3a057efb72d3e4efed256b285ae042c4b69319ef7c1f73,
+L = 6570c0ec97642edeeace0fb86b217addaed54b969a59261af12f769b0e553f73,
+T = 8f602dab8c0e43cce8e4cc27c00f69fa6dd24ee6c4bced176491ff06f6d6b1ea,
+U = c689ba49b0b190ad115d1d8453e9c957d2e404fe7ba7c06f7f911b289950b6a7,
+
+TEST = 8,
+A = e7c3f95b6e903e610432a3f91dc94f5061755d869dbb2ea1573f15668654d229,
+B = e5e62572036c81ba0fe43877e0072b16b75233dc011904353eaca882ae148147,
+E = d3b793bf89e953a66f3b6db6f3a1028950fd508524b049a8163ec58a8c239c34,
+S = 4d3d25d3cd62a0e6777358279f30fc92a20204dd5d235b5a788430c1103d9a70,
+L = 2201e6ea9f8e95f322f09f72d9f335a5c1e71daaa63197b06a55443fc678be8a,
+T = 4424c3965b77294a6bf8b7b6a8802ba331681e81d85584a701aca9c5219a173d,
+U = 94f29f5fb184adb206c5913c8ac7e4bd72bdce8c822eaf9266db9ee13b78a1ad,
+
+TEST = 9,
+A = 79f9007692e6ccb44311dffb39650b464a090b74c243ba71b53b5f2864115e84,
+B = ddf6a062e5b0713e44ee603bf76ef50b9c814a90fd070b3a2584c39330a42079,
+E = f01d8981018757bec7ccd7e478593e4d6712a1211f04077fffdbaf4ed774fbb2,
+S = e17f9b31b2d217c0f57ba02a2f444daa402066d8220884477ee52ac868ad74d2,
+L = b96dae35aecb8c199d52b1c94f1a111ab6ac9cec10d961f05ef6ad31fdde0bb0,
+T = 9ed876d2dc350ccf23d9891e2455724ec23de37ea8fef76ddb32eae76c98309d,
+U = c8573e32004c8326cb3cf89b266e40232a2bb80b3c67b36798a60e434fd1cfa3,
+
diff --git a/testVectors/gg20_zkp/phase6_verify.json b/testVectors/gg20_zkp/phase6_verify.json
new file mode 100644
index 0000000..a0f00a5
--- /dev/null
+++ b/testVectors/gg20_zkp/phase6_verify.json
@@ -0,0 +1,112 @@
+[
+  {
+    "TEST": 0,
+    "R": "025653713d2fcd58fd182adc457f0a8a28b5ff627bc7ce08daccfcce3012ae8447",
+    "ECPT": "025198bcf9b5209bd757ebee5e4fef17b9d6ce5b2c9d05dbfce7a79c039064e515",
+    "ECPS": "024b2fb257840247d17265b0be92187bc7d104f8b3c5ff134631dd13a6c4f3706d",
+    "ALPHA": "0311a5de9be61f4992b9b44428a9f829b3b415622db7a6a043664f9b2bc022fabd",
+    "BETA": "0310caaa12677542d646f0c1f5d08f3ef618bfae3068cbad9fc99f22134055b692",
+    "E": "259a141dcfbfdc9685aefdf5468c4b8bf6884832e2777aab04b6a9c46916e96a",
+    "T": "efeef201b47cab80eb0c5c3081f9dd8207d1317074bf3123942c8f8a0a2a637c",
+    "U": "fecadde1a26e91bfc65adf14085d4eacd8beb7df1f4ff630f49d3153e25bb172"
+  },
+  {
+    "TEST": 1,
+    "R": "035cf8c0e804e61b29d1a3016dc0121ec71a6ddbcdf71b407df801570a670efa07",
+    "ECPT": "021a82066441c27e48999632934724d902c7fa36a8da48055a0d87ea36a8eaf609",
+    "ECPS": "0373a864abd8e8cdad5d15339f617a3d6b6f9aa1f47ef8165202a06625e9ceee47",
+    "ALPHA": "0286a478888a1c0f8d2489cfed552aead5773971d72c3228e526156f5891eb3646",
+    "BETA": "03d2ae50e09885a2da1dbfe916d76178c465179122848f00da2219dd9e1156d830",
+    "E": "500865b4c9c81db293fb1b30089de62356b5094696abd04c2c1dcb8344713d24",
+    "T": "7c424818c7dc23091814084d7765e9c25568b4f2d4b9e3e5b8e3fe9064c6a31e",
+    "U": "c20afde07345e45a13195e883513090a249cfbcabd70473e5d0ecd632bef3565"
+  },
+  {
+    "TEST": 2,
+    "R": "0262a372b4d73033a094d2fa82aa093f9ed4d15bd25c4dcc8597d1e0a9d52daacd",
+    "ECPT": "038177b3ea8f0d608b6116235a817f429a4239723a6dd98e1383f85ce32b4f2e24",
+    "ECPS": "03d2819d2c0729446b35f384d2748463c53d7c6fa78e2de760da1fac588e669783",
+    "ALPHA": "0376e6c94dd0a56fcbeb9e7e747f804ec0d2d9f7e19c63170c3d522d20e93e86dd",
+    "BETA": "03ac03b7bfee911df5e567117790e3706136aba8bf1d443b65f0827a5483c93554",
+    "E": "8583cb4346897e0dddf2e3fe352c967c81d0283b04c0d5b7c179c65a29a56873",
+    "T": "b087f672d9df56049c4df01e7a7557f4f8197b48aa1d33a93801509dd4d6e095",
+    "U": "92df0343eaa0ad4ed2d7208faa35b23258a7023fa333483589d6911fa3ace351"
+  },
+  {
+    "TEST": 3,
+    "R": "031a8b4d3d9c89ba80415bc0e4eadb1633b88319b0bf7d6158a7a48b3d9ed9c4cc",
+    "ECPT": "03a4398f43acccc5a879a98b8c686ea8bc8e0ddd8563be29a57264591e1d26a517",
+    "ECPS": "03d0d5a7ac53e8ca512a72f1baa7f0e342daeeda55915a0f966bf35764d6e724fa",
+    "ALPHA": "023e7e2c6ee1b23c4c1141c467d32d31eb3e432451ed7f58f60fe02c5a984cb8ae",
+    "BETA": "0366fd37d5adeab6e25869b63d70a286d8de3d61f63e0efca20b2a864b0c1c1024",
+    "E": "84c194d04479a87829fb884c383bd0c39f0587a1f7a87a9130d4de389e57cde8",
+    "T": "cb7805ab00a7ba8b1c4a6285b9a5317cdfd179d9d805df8cbe1d59370fc6a9cf",
+    "U": "80a0ac137f9aa09c165cdc7e1ca37e9166f391163e0742969c04eb867cf14caf"
+  },
+  {
+    "TEST": 4,
+    "R": "03f705659c214f2a8bf5232ff47f5aa84aa97af71973a09d1bfda985e01b604090",
+    "ECPT": "0234650e123f90ffdcaffa76e8df6ac91475f8039c82dba6b17da4a19ca4685d02",
+    "ECPS": "029d459ddbac6ef76c316b6eda2f5d3aaad93fe8ad31c9239ba03c8980a9eceb0d",
+    "ALPHA": "02d0045014f16eb10254b17ab07fe3ea3753b7996b8823c6c2cb1373ca1b040ad0",
+    "BETA": "03249029b65568a93ea24e109bf50c1c08c06ad7de22c8bff33446c2b1c0625a65",
+    "E": "752198636483dd7e5cf65b04e3d1590b4f105b7480154c3d7b171b470b48798a",
+    "T": "aeb2631fc90e50407e5eadc3d654ce67c57e60b38fb1a1d9aa5a7dade7f65d81",
+    "U": "7fab6242fa551aa24e0088ed76a2bf4baaa7437ef455bf4f6bf76704be6dc5c4"
+  },
+  {
+    "TEST": 5,
+    "R": "02c027fe77da5b05ef3cc17b6737d1cb6130f244b3548713c928aa3e0ba0a54f06",
+    "ECPT": "031ce592dee24708742cb3e82a9dac2f344923b508397bf6fe754075e8819289c1",
+    "ECPS": "02702ae0ba3985031cee549383ec0c268d54d3812fd0bc03fbbeafa4a0f5971fed",
+    "ALPHA": "0225edbb623d849f72b972aa32dccae57590e8645a3cba518ce5413bd679b1e95c",
+    "BETA": "03703c36ca8afa1e630a8eec1917dd7c6cd2551b418980203c9c7de5b3a12b694d",
+    "E": "73a2c0e26289d7d29788c73e8505a9d937c70c3612da4b43d590d117c903fdd1",
+    "T": "34c55dcd770dab187c09723a580566476f15226fb8d43d3f878849937341180f",
+    "U": "5615c91cbb050c8c9695d7f6c7d01b0f9514c548fb6fb209f1632910dbcfdd97"
+  },
+  {
+    "TEST": 6,
+    "R": "02eb33b1c09509f2d9a0a1dcc104e58a20904c0a53c36e37bca75f37ecfe624f00",
+    "ECPT": "027078071c042aab8e30408c33b165d71c662f76431f9e28086dd210eb30579502",
+    "ECPS": "02732f7c260ce6307365a31d7db5994e2610522e32fc6d7388e9adcc92a3817e64",
+    "ALPHA": "039e8630942c599f2fdc9afc4788770f37c17a446471c1e4b2ea61add0997b16ac",
+    "BETA": "038650929e2ab0c8cfc12e6748eedd9a5759f55e698384fea664c760b5a1623fb0",
+    "E": "9a14a622c4f704365308f573ba8758a80289882a2c3466e27cbdeffb58d1a0f6",
+    "T": "68e84f71edd0589309a1da391709c67e61cb238d005c3b51b4a6a028a7116289",
+    "U": "ea6a9937bc7dfc02e473e6afeb04ad5b253b6eb8b4f61d8eb923c801a2ec5624"
+  },
+  {
+    "TEST": 7,
+    "R": "02634853c61bf8dd1cb73136e4aa7bb6952ac43f17d023b703cdfea6edd98879d3",
+    "ECPT": "0235d1bf1139d0ecd0a2bb7338803914b6a210f6ffce3765d26994f0c99a28a8e8",
+    "ECPS": "02cf47d9a0839cb3e776639a59d746ecf02a65cf6225986e6a7d174a26ba33ebb7",
+    "ALPHA": "0202eadd9f208f398998b1abd30c96de38855bc69f81e2ac74a7acba8cf58ebf87",
+    "BETA": "03857b1d22f80064a97cebb390fbd0b4429979d3c0bb1560f3f376692ec20f39b4",
+    "E": "1cc738dd865f4e63a2f32d3e6de6f7c8c8b0ed70087975279d758f799cb2660b",
+    "T": "bc4e6deff64854489892f7e1c1c9d7b479d1a60b40955f3dbe707b6f4fb8b593",
+    "U": "76a9e7b39adec1a642a6726fdb791e039ea1dfdb1de6e7a2f7bed08d2ea90845"
+  },
+  {
+    "TEST": 8,
+    "R": "03e799d910eade8157d1e983ab6fc2cead6a3d9cf73f0560423a7decf0eee4aa86",
+    "ECPT": "03e00884c86423d26f159993eef320f01ce50cbe580e74216cde175827584d2b18",
+    "ECPS": "03da39cfdfdd57449e4ddc93554d98dc5fe63e34c11efae5e0bedbc37d09886373",
+    "ALPHA": "0383db43a93fc170610199805f644c24e4732f3275dc26bc8e4317dd26c63ddb48",
+    "BETA": "02a03043f112c0b8fa3b0dbe5e251d0c5bdfbd8d710e40705c9bee7b0ccf7c595d",
+    "E": "b34c62cd05beb4de7fcf9d6cddf5fd5d7f6a3e13a5ae2e3846e2e8c5a5914de2",
+    "T": "59e601d8f367d80f3306b659cada19d527e4a46ad7afdd7f59fbc47119e545ca",
+    "U": "67155b19d185fce6fe4ba6b93130b6ba34eb44fe9bd9751ac5ab93c4d35842df"
+  },
+  {
+    "TEST": 9,
+    "R": "03e39e29dce344b76227d753c3d630a255cf7f16cdd33a19f72e4152c7a26bb3ef",
+    "ECPT": "023b830a4aa6c6a7aaf8a432fee29c1688d9afdef41e9981ff873861f00dc78c10",
+    "ECPS": "0259dcd1aedeebbed7efd3b70f25975430ca7028ce56aaac38184f28c101252e5c",
+    "ALPHA": "0206efadb74156a84f9483f4cbaa8bac936697675f68689489966d0ceccd44b80a",
+    "BETA": "032f2f5e491dbd761bc286b7cf777dbe5ced9b65506dac5ce25fdf83bdb5ce9546",
+    "E": "4fd40c3f3cfa2dc76d3799d8ce3cb55db9af2abb367a673250ce6def60ec23c5",
+    "T": "8f1b054d6a8443d6d112e66384abfb63f7539889ee83cdaf5fbc87558cca0bc8",
+    "U": "c72702fc9de49fb34e2b48c97ab90b443b7d18afec669f652e6885cd80ffc451"
+  }
+]
\ No newline at end of file
diff --git a/testVectors/gg20_zkp/phase6_verify.txt b/testVectors/gg20_zkp/phase6_verify.txt
new file mode 100644
index 0000000..fed05bb
--- /dev/null
+++ b/testVectors/gg20_zkp/phase6_verify.txt
@@ -0,0 +1,100 @@
+TEST = 0,
+R = 025653713d2fcd58fd182adc457f0a8a28b5ff627bc7ce08daccfcce3012ae8447,
+ECPT = 025198bcf9b5209bd757ebee5e4fef17b9d6ce5b2c9d05dbfce7a79c039064e515,
+ECPS = 024b2fb257840247d17265b0be92187bc7d104f8b3c5ff134631dd13a6c4f3706d,
+ALPHA = 0311a5de9be61f4992b9b44428a9f829b3b415622db7a6a043664f9b2bc022fabd,
+BETA = 0310caaa12677542d646f0c1f5d08f3ef618bfae3068cbad9fc99f22134055b692,
+E = 259a141dcfbfdc9685aefdf5468c4b8bf6884832e2777aab04b6a9c46916e96a,
+T = efeef201b47cab80eb0c5c3081f9dd8207d1317074bf3123942c8f8a0a2a637c,
+U = fecadde1a26e91bfc65adf14085d4eacd8beb7df1f4ff630f49d3153e25bb172,
+
+TEST = 1,
+R = 035cf8c0e804e61b29d1a3016dc0121ec71a6ddbcdf71b407df801570a670efa07,
+ECPT = 021a82066441c27e48999632934724d902c7fa36a8da48055a0d87ea36a8eaf609,
+ECPS = 0373a864abd8e8cdad5d15339f617a3d6b6f9aa1f47ef8165202a06625e9ceee47,
+ALPHA = 0286a478888a1c0f8d2489cfed552aead5773971d72c3228e526156f5891eb3646,
+BETA = 03d2ae50e09885a2da1dbfe916d76178c465179122848f00da2219dd9e1156d830,
+E = 500865b4c9c81db293fb1b30089de62356b5094696abd04c2c1dcb8344713d24,
+T = 7c424818c7dc23091814084d7765e9c25568b4f2d4b9e3e5b8e3fe9064c6a31e,
+U = c20afde07345e45a13195e883513090a249cfbcabd70473e5d0ecd632bef3565,
+
+TEST = 2,
+R = 0262a372b4d73033a094d2fa82aa093f9ed4d15bd25c4dcc8597d1e0a9d52daacd,
+ECPT = 038177b3ea8f0d608b6116235a817f429a4239723a6dd98e1383f85ce32b4f2e24,
+ECPS = 03d2819d2c0729446b35f384d2748463c53d7c6fa78e2de760da1fac588e669783,
+ALPHA = 0376e6c94dd0a56fcbeb9e7e747f804ec0d2d9f7e19c63170c3d522d20e93e86dd,
+BETA = 03ac03b7bfee911df5e567117790e3706136aba8bf1d443b65f0827a5483c93554,
+E = 8583cb4346897e0dddf2e3fe352c967c81d0283b04c0d5b7c179c65a29a56873,
+T = b087f672d9df56049c4df01e7a7557f4f8197b48aa1d33a93801509dd4d6e095,
+U = 92df0343eaa0ad4ed2d7208faa35b23258a7023fa333483589d6911fa3ace351,
+
+TEST = 3,
+R = 031a8b4d3d9c89ba80415bc0e4eadb1633b88319b0bf7d6158a7a48b3d9ed9c4cc,
+ECPT = 03a4398f43acccc5a879a98b8c686ea8bc8e0ddd8563be29a57264591e1d26a517,
+ECPS = 03d0d5a7ac53e8ca512a72f1baa7f0e342daeeda55915a0f966bf35764d6e724fa,
+ALPHA = 023e7e2c6ee1b23c4c1141c467d32d31eb3e432451ed7f58f60fe02c5a984cb8ae,
+BETA = 0366fd37d5adeab6e25869b63d70a286d8de3d61f63e0efca20b2a864b0c1c1024,
+E = 84c194d04479a87829fb884c383bd0c39f0587a1f7a87a9130d4de389e57cde8,
+T = cb7805ab00a7ba8b1c4a6285b9a5317cdfd179d9d805df8cbe1d59370fc6a9cf,
+U = 80a0ac137f9aa09c165cdc7e1ca37e9166f391163e0742969c04eb867cf14caf,
+
+TEST = 4,
+R = 03f705659c214f2a8bf5232ff47f5aa84aa97af71973a09d1bfda985e01b604090,
+ECPT = 0234650e123f90ffdcaffa76e8df6ac91475f8039c82dba6b17da4a19ca4685d02,
+ECPS = 029d459ddbac6ef76c316b6eda2f5d3aaad93fe8ad31c9239ba03c8980a9eceb0d,
+ALPHA = 02d0045014f16eb10254b17ab07fe3ea3753b7996b8823c6c2cb1373ca1b040ad0,
+BETA = 03249029b65568a93ea24e109bf50c1c08c06ad7de22c8bff33446c2b1c0625a65,
+E = 752198636483dd7e5cf65b04e3d1590b4f105b7480154c3d7b171b470b48798a,
+T = aeb2631fc90e50407e5eadc3d654ce67c57e60b38fb1a1d9aa5a7dade7f65d81,
+U = 7fab6242fa551aa24e0088ed76a2bf4baaa7437ef455bf4f6bf76704be6dc5c4,
+
+TEST = 5,
+R = 02c027fe77da5b05ef3cc17b6737d1cb6130f244b3548713c928aa3e0ba0a54f06,
+ECPT = 031ce592dee24708742cb3e82a9dac2f344923b508397bf6fe754075e8819289c1,
+ECPS = 02702ae0ba3985031cee549383ec0c268d54d3812fd0bc03fbbeafa4a0f5971fed,
+ALPHA = 0225edbb623d849f72b972aa32dccae57590e8645a3cba518ce5413bd679b1e95c,
+BETA = 03703c36ca8afa1e630a8eec1917dd7c6cd2551b418980203c9c7de5b3a12b694d,
+E = 73a2c0e26289d7d29788c73e8505a9d937c70c3612da4b43d590d117c903fdd1,
+T = 34c55dcd770dab187c09723a580566476f15226fb8d43d3f878849937341180f,
+U = 5615c91cbb050c8c9695d7f6c7d01b0f9514c548fb6fb209f1632910dbcfdd97,
+
+TEST = 6,
+R = 02eb33b1c09509f2d9a0a1dcc104e58a20904c0a53c36e37bca75f37ecfe624f00,
+ECPT = 027078071c042aab8e30408c33b165d71c662f76431f9e28086dd210eb30579502,
+ECPS = 02732f7c260ce6307365a31d7db5994e2610522e32fc6d7388e9adcc92a3817e64,
+ALPHA = 039e8630942c599f2fdc9afc4788770f37c17a446471c1e4b2ea61add0997b16ac,
+BETA = 038650929e2ab0c8cfc12e6748eedd9a5759f55e698384fea664c760b5a1623fb0,
+E = 9a14a622c4f704365308f573ba8758a80289882a2c3466e27cbdeffb58d1a0f6,
+T = 68e84f71edd0589309a1da391709c67e61cb238d005c3b51b4a6a028a7116289,
+U = ea6a9937bc7dfc02e473e6afeb04ad5b253b6eb8b4f61d8eb923c801a2ec5624,
+
+TEST = 7,
+R = 02634853c61bf8dd1cb73136e4aa7bb6952ac43f17d023b703cdfea6edd98879d3,
+ECPT = 0235d1bf1139d0ecd0a2bb7338803914b6a210f6ffce3765d26994f0c99a28a8e8,
+ECPS = 02cf47d9a0839cb3e776639a59d746ecf02a65cf6225986e6a7d174a26ba33ebb7,
+ALPHA = 0202eadd9f208f398998b1abd30c96de38855bc69f81e2ac74a7acba8cf58ebf87,
+BETA = 03857b1d22f80064a97cebb390fbd0b4429979d3c0bb1560f3f376692ec20f39b4,
+E = 1cc738dd865f4e63a2f32d3e6de6f7c8c8b0ed70087975279d758f799cb2660b,
+T = bc4e6deff64854489892f7e1c1c9d7b479d1a60b40955f3dbe707b6f4fb8b593,
+U = 76a9e7b39adec1a642a6726fdb791e039ea1dfdb1de6e7a2f7bed08d2ea90845,
+
+TEST = 8,
+R = 03e799d910eade8157d1e983ab6fc2cead6a3d9cf73f0560423a7decf0eee4aa86,
+ECPT = 03e00884c86423d26f159993eef320f01ce50cbe580e74216cde175827584d2b18,
+ECPS = 03da39cfdfdd57449e4ddc93554d98dc5fe63e34c11efae5e0bedbc37d09886373,
+ALPHA = 0383db43a93fc170610199805f644c24e4732f3275dc26bc8e4317dd26c63ddb48,
+BETA = 02a03043f112c0b8fa3b0dbe5e251d0c5bdfbd8d710e40705c9bee7b0ccf7c595d,
+E = b34c62cd05beb4de7fcf9d6cddf5fd5d7f6a3e13a5ae2e3846e2e8c5a5914de2,
+T = 59e601d8f367d80f3306b659cada19d527e4a46ad7afdd7f59fbc47119e545ca,
+U = 67155b19d185fce6fe4ba6b93130b6ba34eb44fe9bd9751ac5ab93c4d35842df,
+
+TEST = 9,
+R = 03e39e29dce344b76227d753c3d630a255cf7f16cdd33a19f72e4152c7a26bb3ef,
+ECPT = 023b830a4aa6c6a7aaf8a432fee29c1688d9afdef41e9981ff873861f00dc78c10,
+ECPS = 0259dcd1aedeebbed7efd3b70f25975430ca7028ce56aaac38184f28c101252e5c,
+ALPHA = 0206efadb74156a84f9483f4cbaa8bac936697675f68689489966d0ceccd44b80a,
+BETA = 032f2f5e491dbd761bc286b7cf777dbe5ced9b65506dac5ce25fdf83bdb5ce9546,
+E = 4fd40c3f3cfa2dc76d3799d8ce3cb55db9af2abb367a673250ce6def60ec23c5,
+T = 8f1b054d6a8443d6d112e66384abfb63f7539889ee83cdaf5fbc87558cca0bc8,
+U = c72702fc9de49fb34e2b48c97ab90b443b7d18afec669f652e6885cd80ffc451,
+
diff --git a/testVectors/schnorr/challenge.json b/testVectors/schnorr/challenge.json
index b6a6ff5..89c6f77 100644
--- a/testVectors/schnorr/challenge.json
+++ b/testVectors/schnorr/challenge.json
@@ -1,82 +1,82 @@
 [
   {
     "TEST": 0,
-    "V": "03c4e1855e5a0784bef9bb7ddc36f8dc2da6662a6443b4429266681943fb93b76b",
-    "C": "0229c5b60e0e3f3298dd3b0c090393a77161be92f9ab446ce103f7928293556325",
-    "E": "72470568ba42a1f395874483800cdb0f7cd1d74e550f476fe8bd00a910a43d89",
-    "ID": "ddfa4ce8ba4eb4ce3a9e85ff8a597d4a",
+    "V": "02a176790583cb46afccce262a4bc017ed2158220838931508ef057f43f367773d",
+    "C": "024b8ab626b59072b6af4bef79fbf2e9bb06ed624c9ecaa50976149cd8e7c96acc",
+    "E": "039bf63791581ac0be5f994edc2d18f368ebdea8bdf9d96af175556f61902528",
+    "ID": "d5cbc9979fef22eb7f2c7229a555ae78",
     "AD": ""
   },
   {
     "TEST": 1,
-    "V": "03791b3200f8590630ca3e43d0c13653bd17797f605b6a964d9dc513f92556b90e",
-    "C": "0314fa950d98212826f0af0acbcb64aeb671de4fda7cf813e3c1a0fa6ba15497c2",
-    "E": "1faaaf805a78d7d077d09c25de23158b7f2b05a1ac8d3508e76e959990de5da9",
-    "ID": "e6513d21d4bdac0e2225fcee5fc70882",
+    "V": "0318a8489034bb5c463574df14b2e01ee874d4f1dafd3ccb5bd5a896f70a2a603e",
+    "C": "02cfaa97966c2165c2ac45180fb25c7605e4e7b8df54ca44ded4a51e1ffca2becd",
+    "E": "393f5c11a666f00fa6a2a900b5291f97e0d6ca6a0b3d926d1ef88ad6e8e7bc98",
+    "ID": "21760c2a45dbf928d4bffe84e8eb1580",
     "AD": ""
   },
   {
     "TEST": 2,
-    "V": "03068dc0ad4aa0de5fdc584bf0c60f480614cae40f63c6857181132110438079e6",
-    "C": "02f1ac9f3bfa370e73da6d7c01aff1677be8c214adfc05ee164db9d3c7750f58f8",
-    "E": "09ca506983461796d06835e5bafb180f9621df7604ed88c895752121af49bd7d",
-    "ID": "64c03cd8b578e70c57ca5348be1a1320",
+    "V": "03f22588a2ed1bad9c268f43d11a5543354c96a6af88dd3ecde41457f0bdb9f502",
+    "C": "03942bd98066baaa416df52d80df211bf9e79e660e30ac8330442ddf2ab5483203",
+    "E": "4c4a3993a2a63bf72178cb80ade4448e28ee0789c6cac67835f41e3402242d2f",
+    "ID": "aad7998056d3a55dcc0bf97a25c11861",
     "AD": ""
   },
   {
     "TEST": 3,
-    "V": "023c71c88abd5d66e6dc41168f3ee44b6e8d8180309b216653261e491a19552e38",
-    "C": "02b7e6856389728b09cc4cdbe1649061fee09973207687ba036abd028151a1e99d",
-    "E": "d7a0a7765a99930b002c73d0d260ca3921b27923c547951c779f8aee8b5abb3b",
-    "ID": "c164da3fa78d42407450982b1701f64e",
+    "V": "02945b518fcc06a093fbb9f61486ca3e17cb34851b4d1fba2fa9d49ad794ada85c",
+    "C": "028e59bfb66b0d94eeaa8f5646081dd7a040336c28ff05fc7fcc58cfa7cf854e80",
+    "E": "7128b92b5fc492cdae6dc465986da78b513fbcec7c2f59173350bbd98d996164",
+    "ID": "33d06f26117fc7dca35d271ac985157e",
     "AD": ""
   },
   {
     "TEST": 4,
-    "V": "02fa5f0016e46f8b5f339a46c4c25de8b527fb6824b1f859f20619d016dd58e36c",
-    "C": "0371f807cebdc3c1bb9fbeb9168c91248d6c24289e06ca001de2d8348baf6fb90e",
-    "E": "c699d59b4e1f4e03d934b7c6d532bffdfaf2066291861eb8b41572b71fc3c17a",
-    "ID": "5fe038405254fede5fd901eeedc445f0",
+    "V": "02470debd491384cdf0e01b0e6327206e48a5fdce6040baad766fe2feb2b0bd0d2",
+    "C": "025ccf01a8dc4cc179fde4643681e598adab65ee97bc27c5682973c4e28b577642",
+    "E": "78e39b1a50cfb9510c12df628e74b223ec86332cfc54b09236956bbc833a1597",
+    "ID": "69f1242f71a3e7dbdf5e5d3a95c10b96",
     "AD": ""
   },
   {
     "TEST": 5,
-    "V": "035cb223c6ebd4c338fef485058f370279a0f67ff519f4348f24b188259134f0f3",
-    "C": "03b8c1205f605e441b1e617aef085946560d6fcbd238fdacb545a583c94b8cb2dd",
-    "E": "6a3a02bcc5c833b3f34e4e04f29d34da7485b2504d55a7a6a97b518c81b4fc71",
-    "ID": "2b68aa2631a9564972dcb3cbd7f9ed3d",
-    "AD": "d48cbbf78bd74a2c26e57d2354c9225a"
+    "V": "02cfc213d2bc4ec8e8953ce4a4145b730fb6163362035d15cd162f8a97ebf5e1b4",
+    "C": "03c100078d60bd6b14f9c61a5acab37876df8beb6a1bc95b38c6eba22d59d4012c",
+    "E": "86b7f2deb6b2c6d41b9bfd9ca6c69a99acdd6b4e96b69d6d9b0c786f5517e164",
+    "ID": "9ca5174cb1aa9bae6370d25d6785e341",
+    "AD": "1591f421f41ac4cd8ac5269e4b99e0f9"
   },
   {
     "TEST": 6,
-    "V": "025345ca601fe14205ed9cd31514c252ed26a4cf6036af1de95076dcc167768c23",
-    "C": "032035339b6cba6446c2c81d29c6afe204d6ada0b636f487150a7959f0014c9377",
-    "E": "4ac5512263b781b0be01d0774a4d7b8cebb059b330540cbe805e7213cb30fbc8",
-    "ID": "e2283fbb76c2765eb88c8680d98525ee",
-    "AD": "6f3678b8dcc8f1b57608367c18076d43"
+    "V": "03480bb05fd84efc13bff7c8b598d3c039c29ec87bdd708ca713f441100a21dd3a",
+    "C": "0300e504f796b9d43c8a405f1f3cc037a36c1cd50816387a6fdaaabded39c1bf18",
+    "E": "ef2dd1f4e70ff6c100400c35e208a2e07e6b1afe271bb965c764f69f0abc17da",
+    "ID": "da6f7ad762b7aee88f4ace681fd1bc66",
+    "AD": "98ba1bf3d76807e3b302e1797d4d3f80"
   },
   {
     "TEST": 7,
-    "V": "0231994000293db76ee3403eaffc3e524d7aad7eb347a26eeba1ffb9576e9030f8",
-    "C": "036b84067e7d74302a932c73b55d4b41e4ba361857b0081fc668d8a6fbbe27e689",
-    "E": "b1d2c1156a3a77a610bc95fd313fc6498c231cad039b6ffce674694c72a00fb2",
-    "ID": "ced168e07cdf38765ab691510e9f06ae",
-    "AD": "2b972ace06c1956b6410d3f9bb21461c"
+    "V": "033abe7b79955e901a74a238e741a203994f920d4722bb19cf33fec18001631e95",
+    "C": "036ae855d9afca5f9603a5c3c8760700ead0fdd4d410fe2b4b4ec807b99397ef34",
+    "E": "393e98668698d9ebaca2ff6eb5b2a3db0aae25508da09c8004b75333078f3f3a",
+    "ID": "a8294309da772456164b5032d0e8c3a3",
+    "AD": "b42d44242c8d0356c4a35598279d9258"
   },
   {
     "TEST": 8,
-    "V": "020f0d1431c74358682de3467bd363466c0725e588af837a3d8f340a4286d9ff57",
-    "C": "03ae3b1014391deb514e3b3bc798f9d77980888fb6c0497125494c423ea02838f8",
-    "E": "e1af4adc2b3854e1c8405adbdffec39a02e0464217af90e6c6239e274a9cb09b",
-    "ID": "798fafd60415b818d4075394c0b1bfdb",
-    "AD": "aa40c4178a5af48ad56d692516677eca"
+    "V": "0212802ceb98750059574a30e98ddfdc2923f8e44b0a6d5f331036b2fb7728287e",
+    "C": "02b23ed8faf6d64e9dc4ce13956ac81bf1ef562b397afdc91f60a684816a6f57f3",
+    "E": "ea7aee412a9990829e6963ab2b992f546e1c48d3f79b1564cf0a50678003a130",
+    "ID": "942f4ccccb572383ffc1f03a7d7c63c1",
+    "AD": "828b337445277d7deb1e5f74b8c21efe"
   },
   {
     "TEST": 9,
-    "V": "025101370b069de8131800b15ec74854b0a8d21611336a53f020708c8ee84c2fed",
-    "C": "024d55b47c8182c7fb9d926323dd9ba785d101f6c354a2be18d7928d73d9c6958c",
-    "E": "5e76c14ba93e72462bddc3f16efbb575147210fd3deca55350c59ae5afff6e09",
-    "ID": "f1ba4a6b31acc1e72d3f4a2deecf9ed9",
-    "AD": "6193b0e56bf856f17ec1c75ae1a4f210"
+    "V": "022a2791c4fb15b75da5d699da051f3ee55219ef10ccd66a49971d49460c104388",
+    "C": "03ea3f63538bb4a6ebb4e3560d946b656f6c2ecd8064fe827e2e08b1c58f9bb6f0",
+    "E": "cff867b78bbb1e7487e3ed124cd029e2c9e231febfeb9169b4e25fdd06665258",
+    "ID": "574f0bbfe941096ddc7f0042d01b4b82",
+    "AD": "f28a3d2395a30ca99a24e78cca947435"
   }
 ]
\ No newline at end of file
diff --git a/testVectors/schnorr/challenge.txt b/testVectors/schnorr/challenge.txt
index f532bb8..1826e83 100644
--- a/testVectors/schnorr/challenge.txt
+++ b/testVectors/schnorr/challenge.txt
@@ -1,70 +1,70 @@
 TEST = 0,
-V = 03c4e1855e5a0784bef9bb7ddc36f8dc2da6662a6443b4429266681943fb93b76b,
-C = 0229c5b60e0e3f3298dd3b0c090393a77161be92f9ab446ce103f7928293556325,
-E = 72470568ba42a1f395874483800cdb0f7cd1d74e550f476fe8bd00a910a43d89,
-ID = ddfa4ce8ba4eb4ce3a9e85ff8a597d4a,
+V = 02a176790583cb46afccce262a4bc017ed2158220838931508ef057f43f367773d,
+C = 024b8ab626b59072b6af4bef79fbf2e9bb06ed624c9ecaa50976149cd8e7c96acc,
+E = 039bf63791581ac0be5f994edc2d18f368ebdea8bdf9d96af175556f61902528,
+ID = d5cbc9979fef22eb7f2c7229a555ae78,
 AD = ,
 
 TEST = 1,
-V = 03791b3200f8590630ca3e43d0c13653bd17797f605b6a964d9dc513f92556b90e,
-C = 0314fa950d98212826f0af0acbcb64aeb671de4fda7cf813e3c1a0fa6ba15497c2,
-E = 1faaaf805a78d7d077d09c25de23158b7f2b05a1ac8d3508e76e959990de5da9,
-ID = e6513d21d4bdac0e2225fcee5fc70882,
+V = 0318a8489034bb5c463574df14b2e01ee874d4f1dafd3ccb5bd5a896f70a2a603e,
+C = 02cfaa97966c2165c2ac45180fb25c7605e4e7b8df54ca44ded4a51e1ffca2becd,
+E = 393f5c11a666f00fa6a2a900b5291f97e0d6ca6a0b3d926d1ef88ad6e8e7bc98,
+ID = 21760c2a45dbf928d4bffe84e8eb1580,
 AD = ,
 
 TEST = 2,
-V = 03068dc0ad4aa0de5fdc584bf0c60f480614cae40f63c6857181132110438079e6,
-C = 02f1ac9f3bfa370e73da6d7c01aff1677be8c214adfc05ee164db9d3c7750f58f8,
-E = 09ca506983461796d06835e5bafb180f9621df7604ed88c895752121af49bd7d,
-ID = 64c03cd8b578e70c57ca5348be1a1320,
+V = 03f22588a2ed1bad9c268f43d11a5543354c96a6af88dd3ecde41457f0bdb9f502,
+C = 03942bd98066baaa416df52d80df211bf9e79e660e30ac8330442ddf2ab5483203,
+E = 4c4a3993a2a63bf72178cb80ade4448e28ee0789c6cac67835f41e3402242d2f,
+ID = aad7998056d3a55dcc0bf97a25c11861,
 AD = ,
 
 TEST = 3,
-V = 023c71c88abd5d66e6dc41168f3ee44b6e8d8180309b216653261e491a19552e38,
-C = 02b7e6856389728b09cc4cdbe1649061fee09973207687ba036abd028151a1e99d,
-E = d7a0a7765a99930b002c73d0d260ca3921b27923c547951c779f8aee8b5abb3b,
-ID = c164da3fa78d42407450982b1701f64e,
+V = 02945b518fcc06a093fbb9f61486ca3e17cb34851b4d1fba2fa9d49ad794ada85c,
+C = 028e59bfb66b0d94eeaa8f5646081dd7a040336c28ff05fc7fcc58cfa7cf854e80,
+E = 7128b92b5fc492cdae6dc465986da78b513fbcec7c2f59173350bbd98d996164,
+ID = 33d06f26117fc7dca35d271ac985157e,
 AD = ,
 
 TEST = 4,
-V = 02fa5f0016e46f8b5f339a46c4c25de8b527fb6824b1f859f20619d016dd58e36c,
-C = 0371f807cebdc3c1bb9fbeb9168c91248d6c24289e06ca001de2d8348baf6fb90e,
-E = c699d59b4e1f4e03d934b7c6d532bffdfaf2066291861eb8b41572b71fc3c17a,
-ID = 5fe038405254fede5fd901eeedc445f0,
+V = 02470debd491384cdf0e01b0e6327206e48a5fdce6040baad766fe2feb2b0bd0d2,
+C = 025ccf01a8dc4cc179fde4643681e598adab65ee97bc27c5682973c4e28b577642,
+E = 78e39b1a50cfb9510c12df628e74b223ec86332cfc54b09236956bbc833a1597,
+ID = 69f1242f71a3e7dbdf5e5d3a95c10b96,
 AD = ,
 
 TEST = 5,
-V = 035cb223c6ebd4c338fef485058f370279a0f67ff519f4348f24b188259134f0f3,
-C = 03b8c1205f605e441b1e617aef085946560d6fcbd238fdacb545a583c94b8cb2dd,
-E = 6a3a02bcc5c833b3f34e4e04f29d34da7485b2504d55a7a6a97b518c81b4fc71,
-ID = 2b68aa2631a9564972dcb3cbd7f9ed3d,
-AD = d48cbbf78bd74a2c26e57d2354c9225a,
+V = 02cfc213d2bc4ec8e8953ce4a4145b730fb6163362035d15cd162f8a97ebf5e1b4,
+C = 03c100078d60bd6b14f9c61a5acab37876df8beb6a1bc95b38c6eba22d59d4012c,
+E = 86b7f2deb6b2c6d41b9bfd9ca6c69a99acdd6b4e96b69d6d9b0c786f5517e164,
+ID = 9ca5174cb1aa9bae6370d25d6785e341,
+AD = 1591f421f41ac4cd8ac5269e4b99e0f9,
 
 TEST = 6,
-V = 025345ca601fe14205ed9cd31514c252ed26a4cf6036af1de95076dcc167768c23,
-C = 032035339b6cba6446c2c81d29c6afe204d6ada0b636f487150a7959f0014c9377,
-E = 4ac5512263b781b0be01d0774a4d7b8cebb059b330540cbe805e7213cb30fbc8,
-ID = e2283fbb76c2765eb88c8680d98525ee,
-AD = 6f3678b8dcc8f1b57608367c18076d43,
+V = 03480bb05fd84efc13bff7c8b598d3c039c29ec87bdd708ca713f441100a21dd3a,
+C = 0300e504f796b9d43c8a405f1f3cc037a36c1cd50816387a6fdaaabded39c1bf18,
+E = ef2dd1f4e70ff6c100400c35e208a2e07e6b1afe271bb965c764f69f0abc17da,
+ID = da6f7ad762b7aee88f4ace681fd1bc66,
+AD = 98ba1bf3d76807e3b302e1797d4d3f80,
 
 TEST = 7,
-V = 0231994000293db76ee3403eaffc3e524d7aad7eb347a26eeba1ffb9576e9030f8,
-C = 036b84067e7d74302a932c73b55d4b41e4ba361857b0081fc668d8a6fbbe27e689,
-E = b1d2c1156a3a77a610bc95fd313fc6498c231cad039b6ffce674694c72a00fb2,
-ID = ced168e07cdf38765ab691510e9f06ae,
-AD = 2b972ace06c1956b6410d3f9bb21461c,
+V = 033abe7b79955e901a74a238e741a203994f920d4722bb19cf33fec18001631e95,
+C = 036ae855d9afca5f9603a5c3c8760700ead0fdd4d410fe2b4b4ec807b99397ef34,
+E = 393e98668698d9ebaca2ff6eb5b2a3db0aae25508da09c8004b75333078f3f3a,
+ID = a8294309da772456164b5032d0e8c3a3,
+AD = b42d44242c8d0356c4a35598279d9258,
 
 TEST = 8,
-V = 020f0d1431c74358682de3467bd363466c0725e588af837a3d8f340a4286d9ff57,
-C = 03ae3b1014391deb514e3b3bc798f9d77980888fb6c0497125494c423ea02838f8,
-E = e1af4adc2b3854e1c8405adbdffec39a02e0464217af90e6c6239e274a9cb09b,
-ID = 798fafd60415b818d4075394c0b1bfdb,
-AD = aa40c4178a5af48ad56d692516677eca,
+V = 0212802ceb98750059574a30e98ddfdc2923f8e44b0a6d5f331036b2fb7728287e,
+C = 02b23ed8faf6d64e9dc4ce13956ac81bf1ef562b397afdc91f60a684816a6f57f3,
+E = ea7aee412a9990829e6963ab2b992f546e1c48d3f79b1564cf0a50678003a130,
+ID = 942f4ccccb572383ffc1f03a7d7c63c1,
+AD = 828b337445277d7deb1e5f74b8c21efe,
 
 TEST = 9,
-V = 025101370b069de8131800b15ec74854b0a8d21611336a53f020708c8ee84c2fed,
-C = 024d55b47c8182c7fb9d926323dd9ba785d101f6c354a2be18d7928d73d9c6958c,
-E = 5e76c14ba93e72462bddc3f16efbb575147210fd3deca55350c59ae5afff6e09,
-ID = f1ba4a6b31acc1e72d3f4a2deecf9ed9,
-AD = 6193b0e56bf856f17ec1c75ae1a4f210,
+V = 022a2791c4fb15b75da5d699da051f3ee55219ef10ccd66a49971d49460c104388,
+C = 03ea3f63538bb4a6ebb4e3560d946b656f6c2ecd8064fe827e2e08b1c58f9bb6f0,
+E = cff867b78bbb1e7487e3ed124cd029e2c9e231febfeb9169b4e25fdd06665258,
+ID = 574f0bbfe941096ddc7f0042d01b4b82,
+AD = f28a3d2395a30ca99a24e78cca947435,
 
diff --git a/testVectors/schnorr/dchallenge.json b/testVectors/schnorr/dchallenge.json
index 7b7c57c..6d042a9 100644
--- a/testVectors/schnorr/dchallenge.json
+++ b/testVectors/schnorr/dchallenge.json
@@ -1,92 +1,92 @@
 [
   {
     "TEST": 0,
-    "R": "038f6876d53b3b8f858feaf34ea139354cc2daf210162f8d89258e36cc89d1ea15",
-    "V": "03f17f5e29ec8dc9de0a3284fed2d925efceaba371eb9625bff8dc2b60f78e767d",
-    "C": "03d68c95f6691138a14674ae80a31f1cb1ef1da3deb693c4c326c57516d1492dd9",
-    "E": "fa45c59892d02bd2e32059b4a3c39a2e822e245de49eff26c4f9d8004565cfd3",
-    "ID": "d0085a45525d1436e41889b7b6cae7db",
+    "R": "031f34b29baecc9d2612cb0fc2f76ab044c4e3d680f5fe59cc11c1ae8c89cb2838",
+    "V": "027471aa6cec039a6b451ac6e5e4559ba2c8d287cd75fcf1dfa6c3461f39d3a9f2",
+    "C": "0385559d63ebe60eeecac4b3e54ca5525b3553b2f805bdb7b4e9a05624a63644d4",
+    "E": "731e1fbcb9dfb310e6a23a6e362a0bc6647e7433907ccc5b8d05657fb14aaa56",
+    "ID": "4567587cca20c3912ba02fe14b649829",
     "AD": ""
   },
   {
     "TEST": 1,
-    "R": "03203ca28db780126db0551ee203f5fdc1a51e2152185eeefaca5abe854cf9e5f6",
-    "V": "03f1bf89af15b7f5c1e7cd4f64377cafc61edf2fefc1ee1a06ba60423aaf387f86",
-    "C": "03abba83dd5f78cd4c6ec8b56003226fbc78389692eea912826c7ec326aaa854df",
-    "E": "a5120e188ee5159db3a53d9033564e7f9f2d6abe26bd7932761820c835285f24",
-    "ID": "916500443089980b552495ea07205280",
+    "R": "0371a9bd0dcade30fe1b70bfebf45e6e3df9ee185925d8c1462e1dfa2c1586f502",
+    "V": "0367b4b5a89b2f222682a5b454af779b161f76b6488f4a3e15b25814b88f6b0ed9",
+    "C": "03df434aa5e9fe202e5b75aadda91e7916e03348c9abbf7e6a45d44835969c993a",
+    "E": "a5a05e68ef3c28196de4c1a722c588f345fef6e0a90c2ba783e9832cc71ace28",
+    "ID": "7e5a46b87c3952ffae977101fbe4aa5a",
     "AD": ""
   },
   {
     "TEST": 2,
-    "R": "038123e9c9495c7c0586715bcb95730d34228ded11cbcd303c9d89306d49a02900",
-    "V": "03f72ee114d5945f60bc781575568b96d5296d61fb15775fb9be63c7f7d5b5b2ba",
-    "C": "029909e097e12eb3ae0e9afd11b3ed44ff645cbaac2b967c404ca55986a6743af6",
-    "E": "a9180558479fa9f5157d26c63b1d434d44902095c7ea2eadeb3fc9cd9ca0374e",
-    "ID": "5e452e6dd894d61567d9e475b6c2d230",
+    "R": "02faf84fff3ddc4ca81fdef16a0951230f559db8cfa8ef96b22fe0d1fc84793348",
+    "V": "02f6c3eb625c33ac65c790cfb8a123c5fc96a9162163d94549d50ab77b76668cc4",
+    "C": "02d2a1d5b09ddd0895d3cecddb9e07286dc610fa96bcc646bab100746eda7ba98d",
+    "E": "df26a6994b268ecf1e6e0513b581dbd961615ddb3afb36b0a7e246e0e9f03403",
+    "ID": "2c2d1edbba148f9c9fc9c43f5329dcdc",
     "AD": ""
   },
   {
     "TEST": 3,
-    "R": "024d05a823ab116021580039cb43a964c24289163fca16772b36018a528dff639d",
-    "V": "03e7b821d69776c189e02c853accb62ed61f1dd7e34b976b79a2ae5fb95ab6b3e2",
-    "C": "02c7b222f108cc7aa566237e7743519196d36aa7d93e99ab9e4c7d5b35afca4448",
-    "E": "5a83f414fb278146866addaee6c90ba4d2fa879c302808137ca06870a25821b7",
-    "ID": "06609e8b9b7fb626bb7f2ea8b47f4582",
+    "R": "020d395eca9daf2bde61d683336be0b7158e81060456482f252c6a0902335cbd5b",
+    "V": "02b3bac2f4ae4b5774c0b2118bd282f7bdae2508da4d50a0b6b15bba03161bbbaf",
+    "C": "03cd22d4c01b912fe98482930d17111cc3963d7032e9bc2670a9e3b37f2eddbbf6",
+    "E": "096c19ae7b41bd11a3383c393b8cec0e00d21bdf0d1eaea3b322d7925303c5a5",
+    "ID": "702f48e6c8ada26fd0bdc58271292b5d",
     "AD": ""
   },
   {
     "TEST": 4,
-    "R": "03453c2a1183008506540c1eb410953699ab6a95591cceb8e38761d897c845761d",
-    "V": "037f93df77762c37d253f1afe663322f12f970f23a6a2d204682e13aa76c99b538",
-    "C": "03eb1236bc465f35669a0f98649fa852bce6f5bb8770d9096f31fad5cce1767d6d",
-    "E": "748ff317b056c57b4fd366678f266d16fcf94f69bfe877fba4393d267f93b658",
-    "ID": "7486107a9dbcde68c8e388e24129d9c5",
+    "R": "0349eb8974c86282418e5e1f8156ddacf18a0e9302604e36a55af1ed450471071d",
+    "V": "02e246387da4fceb844492f939b87a37554b93cebc8812e5be44e293380f458758",
+    "C": "03b0e1f9a308984968622bd239bdfd82a95cc6f467b8c5e5ba1c50647f74d5d967",
+    "E": "13dce3548d40c3dcad1b266b90f83157ff9520169eefcb372c5595f91f15440a",
+    "ID": "2a9b11dd314c26d04bc5b6b3fee2f9fb",
     "AD": ""
   },
   {
     "TEST": 5,
-    "R": "0253090ba3693f7f8865c9d2e7fbabcf19c24b27b03237dc11b653277a18821271",
-    "V": "03df3271f482174215145c57515c291ccd3cc258cf9e6b99e9e533f36b22a7f073",
-    "C": "0304e404f060065805140a3107c32962d925f3199e48a40f476080b0d7bad112b4",
-    "E": "7d0b02747cb75a23135d75717e1717d3524c1c8896cf8b976f0fcdcba142a35f",
-    "ID": "9d914a43ecf839b2843e54a42fe4c009",
-    "AD": "2164c3ae3e3436b841e740cf809b2795"
+    "R": "030b74e1973bf10a1b5b57656d533bd9bc6c5369a8b50dc02f4da313609c4b4cae",
+    "V": "03e461314f61dcefee5107194a30e09bc001aa9fc1dcb539eb37b9d9b86142a9b9",
+    "C": "02df2d6ec6490963c56cfb47c18fdc03ad0adf48e5598b020cad4fe2a21bb192d8",
+    "E": "7587b910b49680f41a788e79405d378859aeca5a58df58722fc648d8cc6871ed",
+    "ID": "a8dfe3b9507a2f8dd3f8e4c26e5e0303",
+    "AD": "4baa8e08f18f8bc426a726caa9e3f60c"
   },
   {
     "TEST": 6,
-    "R": "0393f5387d1e20fc0472b388662238a2a2239e9c5516115f13abc57f7f58430dbf",
-    "V": "038e0b62ea7798093e7c512136b69d096cd00c1c84393bf5bb5947bc930f0db31c",
-    "C": "02f4bb70005ac5adc974a2ce6093ed2269fef48c8c9f45913ab3684c1fcea90bf4",
-    "E": "b0134e65f16518ba896f98363dc5fecd920d9490d57cdbd5f937242f039066d6",
-    "ID": "3a7e76440dd7adf8cd622e24c8e4f199",
-    "AD": "c47299eaa266b0c1a920deab65fa7cdf"
+    "R": "03bb193bfc8ece97320807a2a7ebbf7b86743e618efea217f98dc721604eb38de4",
+    "V": "028fe6aa66ed30218ba0eab95cece4ebac13b4ba57a1e369ff8f0075235fa25551",
+    "C": "0389a1e979398764bb184b776db5cbab8ec6d5a35ca1afcbc48a0212807b44f78f",
+    "E": "fd095efb0352f3092090a73ab1c8256d6ce91c1200a9ce94cc78ad0972387324",
+    "ID": "3c5335f5b78fd07397d2afa043261d8e",
+    "AD": "af5db16b80f07b104dd2ed17ec9855fa"
   },
   {
     "TEST": 7,
-    "R": "0309f0fb8c0e32bb1dcdb5cd810ae1c0b0e1c5418c1f29cb7b7696c139dd37611e",
-    "V": "03bb6b807b0be4262af130e34e663f7682032a3eab2fce282c56a7ea35b89c0f96",
-    "C": "03cdc87374f522dcff6c16d7be17a432066b7065646c0c6e67d6fe58c5db0dd6a4",
-    "E": "d933e039daf386d798cf38f4d5fcea4e587fcd386bac0eeceb92a241b354d71b",
-    "ID": "e08c5e4e3eb08d0c54ab91f1bbb472a2",
-    "AD": "b5c96c751c18209f8ff8bf369a5ddfc2"
+    "R": "033bdfe6658839c138ab920092342c0bde0ac18b21acebc45c4702327da49d25fe",
+    "V": "02f2805b6468ad19a784b79af287b33e3ec02360d27adc45e49303a5841ba2f96f",
+    "C": "0202f41283ab55d988431ddeb11c1d2ba6072b2310a810199c70add17884652adc",
+    "E": "d1c3151e9d035de98a7d440a1b0355e7aa48b482ded2f6d4d32e3d595b765c4b",
+    "ID": "ca79704548b90cb2f6fcb2691fd9ac4b",
+    "AD": "50bd088a6040960420c2a592c82f11b9"
   },
   {
     "TEST": 8,
-    "R": "0217571b58356c8dcc258e8ce7787d90d0557f911cea7747ad97cb1416ff06d57c",
-    "V": "025c264cdf73fcfaf7f6afba17009807271b15f85062022c1cc0c3c74e03da35de",
-    "C": "03b86b7c0b3ca05fd8975af66f3b9a2f5ab338205aa8dbace6f9a2dce12085ae31",
-    "E": "583c9d20a4df474615d0ee2f8762e16ec23db022f1f05d55a3166b95f3009bff",
-    "ID": "ee99fe3e0e15220ffcfe792fdd9c1498",
-    "AD": "748cf346cf2817b826446cf6af22a503"
+    "R": "02a7d55d997faca384d6784923d49a5ba36b185c0427f56118738736ed304318ac",
+    "V": "024ca8a828ae901debfa693e416540e267e2bf53a4e393cf748352372c44a0c528",
+    "C": "03fd319a8cf14cf7edbb740461035901aff1ba52911a13a8e9a9251b8805edaa6b",
+    "E": "729441880dab1973d24ddce4af1319367a568fe80ee26f0135d677aaf77e04ac",
+    "ID": "14d194a9a7bb50067b75030a2a4b31aa",
+    "AD": "9efbe273c43ef2d3a9ab67907b3db77c"
   },
   {
     "TEST": 9,
-    "R": "02e3a46f35ce40e59194a7dd349cd701c9940f58a6d75824094e15c00598f66525",
-    "V": "032459eb39f986ec51c24717d6c211717f8d8bb24a951148c2324e410d15528a81",
-    "C": "036152bf63d0f3cd012afb9326c260a757c148f30f7de60db2c7819f4eaf74a9ec",
-    "E": "9616c3a9c752ecca4bf58eca5ed8853f8c0296f318b98ee7dbefe327d55742bd",
-    "ID": "b910c484dbc541799639071705b90234",
-    "AD": "9b5fa9d07790980f318bf3a705f5bc58"
+    "R": "021e221451eb615632912423657e9b79fe0ea58c333667893a6c205eaf3a75822a",
+    "V": "0242a2fabc74574a78453dd9db7b0b9eaf32890cb2188f5c855c0723db0d3b92a1",
+    "C": "03409379b58af01fea446e18df1b465a4634806900825200334d5390cc3ae3fc89",
+    "E": "66343214024de8c3f31e4985628f446f43c17c82bbff3b401324124aeb494e9f",
+    "ID": "8151b308bee69f9dfe705c290ce4dea9",
+    "AD": "cace19ad3775febf42974c801012b386"
   }
 ]
\ No newline at end of file
diff --git a/testVectors/schnorr/dchallenge.txt b/testVectors/schnorr/dchallenge.txt
index 10cf669..784697d 100644
--- a/testVectors/schnorr/dchallenge.txt
+++ b/testVectors/schnorr/dchallenge.txt
@@ -1,80 +1,80 @@
 TEST = 0,
-R = 038f6876d53b3b8f858feaf34ea139354cc2daf210162f8d89258e36cc89d1ea15,
-V = 03f17f5e29ec8dc9de0a3284fed2d925efceaba371eb9625bff8dc2b60f78e767d,
-C = 03d68c95f6691138a14674ae80a31f1cb1ef1da3deb693c4c326c57516d1492dd9,
-E = fa45c59892d02bd2e32059b4a3c39a2e822e245de49eff26c4f9d8004565cfd3,
-ID = d0085a45525d1436e41889b7b6cae7db,
+R = 031f34b29baecc9d2612cb0fc2f76ab044c4e3d680f5fe59cc11c1ae8c89cb2838,
+V = 027471aa6cec039a6b451ac6e5e4559ba2c8d287cd75fcf1dfa6c3461f39d3a9f2,
+C = 0385559d63ebe60eeecac4b3e54ca5525b3553b2f805bdb7b4e9a05624a63644d4,
+E = 731e1fbcb9dfb310e6a23a6e362a0bc6647e7433907ccc5b8d05657fb14aaa56,
+ID = 4567587cca20c3912ba02fe14b649829,
 AD = ,
 
 TEST = 1,
-R = 03203ca28db780126db0551ee203f5fdc1a51e2152185eeefaca5abe854cf9e5f6,
-V = 03f1bf89af15b7f5c1e7cd4f64377cafc61edf2fefc1ee1a06ba60423aaf387f86,
-C = 03abba83dd5f78cd4c6ec8b56003226fbc78389692eea912826c7ec326aaa854df,
-E = a5120e188ee5159db3a53d9033564e7f9f2d6abe26bd7932761820c835285f24,
-ID = 916500443089980b552495ea07205280,
+R = 0371a9bd0dcade30fe1b70bfebf45e6e3df9ee185925d8c1462e1dfa2c1586f502,
+V = 0367b4b5a89b2f222682a5b454af779b161f76b6488f4a3e15b25814b88f6b0ed9,
+C = 03df434aa5e9fe202e5b75aadda91e7916e03348c9abbf7e6a45d44835969c993a,
+E = a5a05e68ef3c28196de4c1a722c588f345fef6e0a90c2ba783e9832cc71ace28,
+ID = 7e5a46b87c3952ffae977101fbe4aa5a,
 AD = ,
 
 TEST = 2,
-R = 038123e9c9495c7c0586715bcb95730d34228ded11cbcd303c9d89306d49a02900,
-V = 03f72ee114d5945f60bc781575568b96d5296d61fb15775fb9be63c7f7d5b5b2ba,
-C = 029909e097e12eb3ae0e9afd11b3ed44ff645cbaac2b967c404ca55986a6743af6,
-E = a9180558479fa9f5157d26c63b1d434d44902095c7ea2eadeb3fc9cd9ca0374e,
-ID = 5e452e6dd894d61567d9e475b6c2d230,
+R = 02faf84fff3ddc4ca81fdef16a0951230f559db8cfa8ef96b22fe0d1fc84793348,
+V = 02f6c3eb625c33ac65c790cfb8a123c5fc96a9162163d94549d50ab77b76668cc4,
+C = 02d2a1d5b09ddd0895d3cecddb9e07286dc610fa96bcc646bab100746eda7ba98d,
+E = df26a6994b268ecf1e6e0513b581dbd961615ddb3afb36b0a7e246e0e9f03403,
+ID = 2c2d1edbba148f9c9fc9c43f5329dcdc,
 AD = ,
 
 TEST = 3,
-R = 024d05a823ab116021580039cb43a964c24289163fca16772b36018a528dff639d,
-V = 03e7b821d69776c189e02c853accb62ed61f1dd7e34b976b79a2ae5fb95ab6b3e2,
-C = 02c7b222f108cc7aa566237e7743519196d36aa7d93e99ab9e4c7d5b35afca4448,
-E = 5a83f414fb278146866addaee6c90ba4d2fa879c302808137ca06870a25821b7,
-ID = 06609e8b9b7fb626bb7f2ea8b47f4582,
+R = 020d395eca9daf2bde61d683336be0b7158e81060456482f252c6a0902335cbd5b,
+V = 02b3bac2f4ae4b5774c0b2118bd282f7bdae2508da4d50a0b6b15bba03161bbbaf,
+C = 03cd22d4c01b912fe98482930d17111cc3963d7032e9bc2670a9e3b37f2eddbbf6,
+E = 096c19ae7b41bd11a3383c393b8cec0e00d21bdf0d1eaea3b322d7925303c5a5,
+ID = 702f48e6c8ada26fd0bdc58271292b5d,
 AD = ,
 
 TEST = 4,
-R = 03453c2a1183008506540c1eb410953699ab6a95591cceb8e38761d897c845761d,
-V = 037f93df77762c37d253f1afe663322f12f970f23a6a2d204682e13aa76c99b538,
-C = 03eb1236bc465f35669a0f98649fa852bce6f5bb8770d9096f31fad5cce1767d6d,
-E = 748ff317b056c57b4fd366678f266d16fcf94f69bfe877fba4393d267f93b658,
-ID = 7486107a9dbcde68c8e388e24129d9c5,
+R = 0349eb8974c86282418e5e1f8156ddacf18a0e9302604e36a55af1ed450471071d,
+V = 02e246387da4fceb844492f939b87a37554b93cebc8812e5be44e293380f458758,
+C = 03b0e1f9a308984968622bd239bdfd82a95cc6f467b8c5e5ba1c50647f74d5d967,
+E = 13dce3548d40c3dcad1b266b90f83157ff9520169eefcb372c5595f91f15440a,
+ID = 2a9b11dd314c26d04bc5b6b3fee2f9fb,
 AD = ,
 
 TEST = 5,
-R = 0253090ba3693f7f8865c9d2e7fbabcf19c24b27b03237dc11b653277a18821271,
-V = 03df3271f482174215145c57515c291ccd3cc258cf9e6b99e9e533f36b22a7f073,
-C = 0304e404f060065805140a3107c32962d925f3199e48a40f476080b0d7bad112b4,
-E = 7d0b02747cb75a23135d75717e1717d3524c1c8896cf8b976f0fcdcba142a35f,
-ID = 9d914a43ecf839b2843e54a42fe4c009,
-AD = 2164c3ae3e3436b841e740cf809b2795,
+R = 030b74e1973bf10a1b5b57656d533bd9bc6c5369a8b50dc02f4da313609c4b4cae,
+V = 03e461314f61dcefee5107194a30e09bc001aa9fc1dcb539eb37b9d9b86142a9b9,
+C = 02df2d6ec6490963c56cfb47c18fdc03ad0adf48e5598b020cad4fe2a21bb192d8,
+E = 7587b910b49680f41a788e79405d378859aeca5a58df58722fc648d8cc6871ed,
+ID = a8dfe3b9507a2f8dd3f8e4c26e5e0303,
+AD = 4baa8e08f18f8bc426a726caa9e3f60c,
 
 TEST = 6,
-R = 0393f5387d1e20fc0472b388662238a2a2239e9c5516115f13abc57f7f58430dbf,
-V = 038e0b62ea7798093e7c512136b69d096cd00c1c84393bf5bb5947bc930f0db31c,
-C = 02f4bb70005ac5adc974a2ce6093ed2269fef48c8c9f45913ab3684c1fcea90bf4,
-E = b0134e65f16518ba896f98363dc5fecd920d9490d57cdbd5f937242f039066d6,
-ID = 3a7e76440dd7adf8cd622e24c8e4f199,
-AD = c47299eaa266b0c1a920deab65fa7cdf,
+R = 03bb193bfc8ece97320807a2a7ebbf7b86743e618efea217f98dc721604eb38de4,
+V = 028fe6aa66ed30218ba0eab95cece4ebac13b4ba57a1e369ff8f0075235fa25551,
+C = 0389a1e979398764bb184b776db5cbab8ec6d5a35ca1afcbc48a0212807b44f78f,
+E = fd095efb0352f3092090a73ab1c8256d6ce91c1200a9ce94cc78ad0972387324,
+ID = 3c5335f5b78fd07397d2afa043261d8e,
+AD = af5db16b80f07b104dd2ed17ec9855fa,
 
 TEST = 7,
-R = 0309f0fb8c0e32bb1dcdb5cd810ae1c0b0e1c5418c1f29cb7b7696c139dd37611e,
-V = 03bb6b807b0be4262af130e34e663f7682032a3eab2fce282c56a7ea35b89c0f96,
-C = 03cdc87374f522dcff6c16d7be17a432066b7065646c0c6e67d6fe58c5db0dd6a4,
-E = d933e039daf386d798cf38f4d5fcea4e587fcd386bac0eeceb92a241b354d71b,
-ID = e08c5e4e3eb08d0c54ab91f1bbb472a2,
-AD = b5c96c751c18209f8ff8bf369a5ddfc2,
+R = 033bdfe6658839c138ab920092342c0bde0ac18b21acebc45c4702327da49d25fe,
+V = 02f2805b6468ad19a784b79af287b33e3ec02360d27adc45e49303a5841ba2f96f,
+C = 0202f41283ab55d988431ddeb11c1d2ba6072b2310a810199c70add17884652adc,
+E = d1c3151e9d035de98a7d440a1b0355e7aa48b482ded2f6d4d32e3d595b765c4b,
+ID = ca79704548b90cb2f6fcb2691fd9ac4b,
+AD = 50bd088a6040960420c2a592c82f11b9,
 
 TEST = 8,
-R = 0217571b58356c8dcc258e8ce7787d90d0557f911cea7747ad97cb1416ff06d57c,
-V = 025c264cdf73fcfaf7f6afba17009807271b15f85062022c1cc0c3c74e03da35de,
-C = 03b86b7c0b3ca05fd8975af66f3b9a2f5ab338205aa8dbace6f9a2dce12085ae31,
-E = 583c9d20a4df474615d0ee2f8762e16ec23db022f1f05d55a3166b95f3009bff,
-ID = ee99fe3e0e15220ffcfe792fdd9c1498,
-AD = 748cf346cf2817b826446cf6af22a503,
+R = 02a7d55d997faca384d6784923d49a5ba36b185c0427f56118738736ed304318ac,
+V = 024ca8a828ae901debfa693e416540e267e2bf53a4e393cf748352372c44a0c528,
+C = 03fd319a8cf14cf7edbb740461035901aff1ba52911a13a8e9a9251b8805edaa6b,
+E = 729441880dab1973d24ddce4af1319367a568fe80ee26f0135d677aaf77e04ac,
+ID = 14d194a9a7bb50067b75030a2a4b31aa,
+AD = 9efbe273c43ef2d3a9ab67907b3db77c,
 
 TEST = 9,
-R = 02e3a46f35ce40e59194a7dd349cd701c9940f58a6d75824094e15c00598f66525,
-V = 032459eb39f986ec51c24717d6c211717f8d8bb24a951148c2324e410d15528a81,
-C = 036152bf63d0f3cd012afb9326c260a757c148f30f7de60db2c7819f4eaf74a9ec,
-E = 9616c3a9c752ecca4bf58eca5ed8853f8c0296f318b98ee7dbefe327d55742bd,
-ID = b910c484dbc541799639071705b90234,
-AD = 9b5fa9d07790980f318bf3a705f5bc58,
+R = 021e221451eb615632912423657e9b79fe0ea58c333667893a6c205eaf3a75822a,
+V = 0242a2fabc74574a78453dd9db7b0b9eaf32890cb2188f5c855c0723db0d3b92a1,
+C = 03409379b58af01fea446e18df1b465a4634806900825200334d5390cc3ae3fc89,
+E = 66343214024de8c3f31e4985628f446f43c17c82bbff3b401324124aeb494e9f,
+ID = 8151b308bee69f9dfe705c290ce4dea9,
+AD = cace19ad3775febf42974c801012b386,
 
diff --git a/testVectors/schnorr/dprove.json b/testVectors/schnorr/dprove.json
index a422c3c..2933611 100644
--- a/testVectors/schnorr/dprove.json
+++ b/testVectors/schnorr/dprove.json
@@ -1,102 +1,102 @@
 [
   {
     "TEST": 0,
-    "A": "c3658c336985e9415ac8395a5a97dcd9bd0cb566f7c7fc23e4c53726627fc3d2",
-    "B": "c8d085e5ea92fb4086caf99c27ba68d0cf075531f9a45527e49667558d9d79ff",
-    "E": "744953855c767494d6f4fdc48e852a54027e2b7aa6c6552c217dd98b152f6395",
-    "S": "4ba56d82ab4fd7f34eb58be3e3b1b23c06270f1d4d51d4662742b37700a70a06",
-    "L": "3e13bc076f821b97aaabb9b5a65fa5ef7a1c7e200009d2fa11f17a1858d0a52f",
-    "T": "2d01dec8512cdd6e880c25053de5f807ed48ebf831de4235754d825b0d1494a5",
-    "U": "54bf98385efdb40d39827c52d2f4e6d4df8dc0938655a7b0a57cace7986e895d"
+    "A": "98805901e0372ed6d0a40b6713fefc8287e8d1db602e019f2ed5351409d9706d",
+    "B": "26cc836888ad8d992f6a9147d708fe9a8f2d65fe86004730d12592c7b8b040ef",
+    "E": "1461d3a0ab285ff20abb1f57feab8d5177f48f7886ec7b40295daebb028f3585",
+    "S": "7a576ef122d172a58e5fe6dd5d99420b0ba1c484e3f3c4b7c68f1b61e62c0743",
+    "L": "0886d359c3d6d968e013364166ff8a99c19cbf8cf31682cac557033206616515",
+    "T": "82620066f763e041c98582a702a9c96862acb2ff1e8ddc41453d7de181649109",
+    "U": "b6808109110b2f095dff929e6f70ffb212ed541bea0e9c502393b77354892e06"
   },
   {
     "TEST": 1,
-    "A": "931f39d36bfc27283f5b3d791ad3f6df1c55f144fa2b52bd443fc4eb24f26281",
-    "B": "b6fdb0f8402d57e166816f281b48c2b5a5c04d6c4ab52be80620feb98118957e",
-    "E": "9675ad591af467de8c64a39b438c213d86e5bbba431bb3880c186b4e8282a672",
-    "S": "b6683ed0c7f7bb9b53250bb5cbdaf15aa84673d44c011f970b27c4dedc79a7c3",
-    "L": "6450fb92cefca0594fe5e37a2fab9eed46fcd44eaee464adf1237b8c3f9855ec",
-    "T": "30e4a42f280a7a135654a4af59a445ce09ed5683b7404d575bccf9d7a2c8c760",
-    "U": "db60d0b8ba2d3ba0b884774259b8fc40e92595b01ffbc0aa36ee63e3126b194f"
+    "A": "0cb56a12df35413544e656003152984ef3ca4dcdc0521eaf8c64e6bc6c1e64f4",
+    "B": "f0d0b41a157ce4fbb7d1489a35a9292a9613d04a762b4a2877fc00e65e8403ca",
+    "E": "0fd895b69a81143a766bc083b0b2438a056db9c7eaba689bf3eef1a27289a957",
+    "S": "4ca7684fe26ab68f8add3d5c7ffd93cabe7d1a40d6ac7275289c14e949f783cb",
+    "L": "f3183da05f4eacd598ecfee13aafab0a66c4e8305fcdd6a125551b28421e4a18",
+    "T": "9a80b742ac91e1dfabdacc7beda876630da20fdfa68371594f0fc91767f97ef5",
+    "U": "09bd1bcc47053e8eaa41e620e0afcacbeffe9204b94b7adc4ea672791feaeae4"
   },
   {
     "TEST": 2,
-    "A": "f65387fd820997e523d1099ff99727dde285bac05a0cd9e63fb75e28284df79d",
-    "B": "94d0c8ba02ebde9f728d1fffd0ec743db34192366c42a9063580ea971d8d8d4b",
-    "E": "37ce44b6fcd5617c4470e9a83cdb9c2a5057eb71bdf656de4ad1a50cee70334c",
-    "S": "626e6215eae0f7f304af9abeac0d5267d9c83cbb9ed0beacb0090faaf0fc18eb",
-    "L": "0da04fe6194cc495ccb9d43225f0b29d7ef322665d37347c441b1a054f4a60b4",
-    "T": "3e0ff7c4fddb1f58933cf1d5ba9388ff2a6d0e4be347c59bf2be18457c7ab5e7",
-    "U": "71ee5b78721471d2ac47073eb92d979477208b44a16e8425293902e134c41d34"
+    "A": "2470fd1f08b27218902e84f7831b145a3397feea9063bb6dbc1dc58043793d36",
+    "B": "aac9c4169145697d2be942b35b477d8f5e05d3380bf4a477b155a0b5b1cdca04",
+    "E": "557b85666a49026cf91b4f1131378a1e6b95bc9bbdc73a7dcd305ccc40005af7",
+    "S": "9f43938ac39a90d371ce160f091ec669b972f8406ca38cde8f14c17461e2294f",
+    "L": "38709c38e13a8d52051f5ddf14266c4179abaf37ef553bdf4871e343e51bcef7",
+    "T": "1e7ab0926591ea57389515a97932c5195f467a65154f1814b8c63990fe5c80d7",
+    "U": "ff9a8a42430a35c1a667887a9cad3241f244e8823884ceb27cb576019fd8b09b"
   },
   {
     "TEST": 3,
-    "A": "0e3cebfb2e5ef09c85305b6d400b35ed581729ecac51782cdb8908043d6bf4af",
-    "B": "192db7270206618045a6a83cc26babc89eb0f68946bec5b8b99d71a70f391505",
-    "E": "b1568c9ef268cb8eca2f95a6b9bfa4fe90f65c368a44fbf105305263cf99b396",
-    "S": "57339ac50d52d6778fcd5787c5578d454c31d285d98e53e60dbfaee5eb22b5de",
-    "L": "6bffa4f19113e216da05bd988cde2fbbb1553f2f32b03893dad8569f61da8e59",
-    "T": "60c391d164811208e890f9b1b596b948b423ceca295a2f5e2bc3066dab605051",
-    "U": "a410308bf97a4b2db7f809bdd7193a91191dfdbd7dc20e9d60ffa91602f2ad02"
+    "A": "c5a4d6df2f2764c9218a8e83725f2d7ff489135f7b2ea0f83b06ed307d189540",
+    "B": "ed016425bbb01beca9566bbf781774a5599ec9dcbf85f3e1a10698aaba5a5861",
+    "E": "d046ffb08dcf4e6252943b222d5197bb82b6e564fce6bd772bb27a8e3e5944bb",
+    "S": "cac09fc7c620c462f53d1793aec83182405ffa71f89e6e26a6fb461ad7bf90ac",
+    "L": "53c088a61f158eff3bd18592e595ed15474b1ac60c12fd84f5e4c59a07ccdc3c",
+    "T": "26452cf9fa404db00ae243e45d5a9902a8e11bb4f6025904b04e58bf0b3f513d",
+    "U": "3643906e09efca1b1edfbbe9dd10c3d9aacbadfffba6f3bd539bdfc79fb11f62"
   },
   {
     "TEST": 4,
-    "A": "a6720ad0cd437e1fad7b6cb831748de9a4c113d7a4407ac48d1c1c649a32cfa7",
-    "B": "b7001f7b29784a455a9de707f496498e776af6cace3281a5d6dc877c3b960feb",
-    "E": "de8bd108f9ece11b75fb01241477fb361609105d9874696121c678ceb39dbca1",
-    "S": "f03a58d3248464d8a1d77e3107151f69ea0a3217238305e43208adb296d27deb",
-    "L": "5ce20cf65990bf869cb82b4d1b8a7a3dea605340419e86968d31266ad7ceb7cb",
-    "T": "b7f424831ddbe2061f78e9c505748f30c719d0c813932a957bd62f98dd35bfe4",
-    "U": "6f10117963601ad31ef4c6ad7baf3753e4febd6b64e7772d741d5db2d7cdcd18"
+    "A": "2c3cc0f8606707858227db376e49d0539b35bb9a13e09394feda22125802d2fd",
+    "B": "b20fd6417866c586ecbafcd3f3893baedd81897091beca86d6420eaf10d87931",
+    "E": "7c9d86a12b86d6fb2f17f528fa37832f85668dc967e7730e2a5299d59faf60f4",
+    "S": "e73f8faf79981194c4ee0f1eadbd942d6e9297a6f7f2aa48ca384564392f6ef1",
+    "L": "4ce5e76bb95c0930d3fd86dde66b60f6810af5e27d7af9084ab2c1163dd292e5",
+    "T": "ea39d54be9c92890cfb7ee8aba9b6403301dd69df490c29c0ef4a98fde987309",
+    "U": "f8f44f48ab719fa71612f39c74416bcd9dad664c1be35f8b68c39519de49275d"
   },
   {
     "TEST": 5,
-    "A": "e064c90e03b7774ecea6f0c5633d9dd98fc6f8416d7baf39cf83df372bbd1a8f",
-    "B": "b89bf2b48410d26cd0b2450bc384bde59caecd03d1b534b9dee14c4ffb718cc0",
-    "E": "4a12fe6e64639407ad01860b3cdc10e69dc7d6b319a2160abcac5b4cf1a609f9",
-    "S": "892a19776ba393756e325ae26eb1be8d058d1978b0cb20dfbbd6f1f514fbdccb",
-    "L": "06584dc2fbcb24bd8dcefa2ecb75468ca3ee594cafb7e65223fdb49357e7e2f0",
-    "T": "722402d368c0818577f357aad04d9195ea80e0b013d164f89cf7f3c8f2761f14",
-    "U": "778d3d0e10ea34e5379297027c1e5f9a0470f126cd19f6bfc21e881652563b5e"
+    "A": "c3df2d0f74fe039e5fbddf583555399f0ab564034eaa5eaa871e734021f77689",
+    "B": "d30ec4e0969fa9cf0dd1c61b725e5b5faac8c96e12f5bfc8ac441180a85357c1",
+    "E": "67bd9cd0b2e0695346b66d07053f26ba60022473f986ab4956b0c20ca5eeb7d4",
+    "S": "e86b00ec424317d9e6c983682b76e0589149c2be2de586515ccb403bb61613ea",
+    "L": "6345b6f3ec1ec358e700f8d19a0dfde21a4a91cc262a1f4673b451c72539a294",
+    "T": "85148b51e33264a188b79df3cac87e78041047e2300678d0d8984ec2af8043ff",
+    "U": "096147a069b0d63da7a85d68047a827cec23c3da65d590345291cbe491e769c3"
   },
   {
     "TEST": 6,
-    "A": "1cb8713e7dba86e70d446668d75bc9c992e6c10c9f6ed108ff0006a6d1b0937b",
-    "B": "f5cca22f672064914108a628be72e54380471853c91cd92904973944d3671631",
-    "E": "f54feab6fc6679e536521834a395893c4dcbb9f5cbd79dc6a9b54661eebb3166",
-    "S": "b69c37cc0963f8619645e9bf2f949ef829aace7604835f08579ecff67049782a",
-    "L": "e3f71b7a4f66283eab2cc81ae718723105ac4284f668271d53a5053bcb86f449",
-    "T": "03fec2defb4cb0037aa1fe3e98062b7d3265e6fe6b96257e961203daa7bb20ab",
-    "U": "b9710f2a2824a140aa970cf2aff3d898c9fe0e69352e5ceee4281549bade7ffe"
+    "A": "7f65618bf4531471c0b419bde1c06dcf7f20064fc65a97510658fe81db7eba0b",
+    "B": "1a141938c4c0e7e3ad4f648be35ab96f39b9329129556d8f549e1995d0af503e",
+    "E": "2449978fa5cca2b27e17085429f9071d5d8bbe3f8f53df285eee5f6cc5efe1e5",
+    "S": "f4e7cccc8bf490e705720a33776fab2ec700010dd971b8430abba2cdb77d48e7",
+    "L": "e58b630fc1350574468489f76a6c5fe3298a6174343a261c9af87bdbfe79dd80",
+    "T": "dd0d19687a3ce16fd50720f3f06971089ca91ea50c22d489bcf2c1cdfce6a83c",
+    "U": "dba67e6ef893225ec8a86ffe4f5fba51820117efd25dbbe1dadcd8f9dffe1174"
   },
   {
     "TEST": 7,
-    "A": "38c3298372a795c04c9bf3490d01f6f366bf3ac64c6a5c921581be6fb8263922",
-    "B": "eb922d0b0694a1e7973742dbff6bfc65cf29cfdf50d22cb7304dc060292adea2",
-    "E": "bf22c8d94b8b6005b6790ff357647e61b3cb853994f358e4fca9ddc9e191232b",
-    "S": "692622cb87e36d76b72f5726cc47877cbdd20e5f09ed37a69f9e3483432f8832",
-    "L": "35459a922c7dee62d1bd2cc240d5ced07bb978f7e2519f93cc5c8f24985593d1",
-    "T": "4075007fe3a002a59f723027738a37b90dfe8237dc92588769e3e8bae191ec28",
-    "U": "67caf11bef014d06b9f4467c8b520af8ef9cce399be37997d37f34f1e5cfe367"
+    "A": "c712cd92b407de5731a351dfb230b1ae0f65f99184ff97d7e7dbd3d9921ffd1e",
+    "B": "08e02f9c632d3fd1f48bdddcfdaca3588b168f0b6ff4cbaee99356d23d1e355a",
+    "E": "e0eb9c89aa93820c6a81431ca3c3e2d33088f1d0c1bddea749bb91a252425145",
+    "S": "c212f5fe66de61ebf95c0e0797bea72fcf10bb5f4aa903085aef685e35f68220",
+    "L": "234d8df29b1ee7f841b6d74a9bb8139d379df056716187225acc45fcc7d364f3",
+    "T": "3e82ff64fde662cec1730ca59d759c22f191326dbbbeaf09fa2c01a9184782ab",
+    "U": "51e0c8ba1580270fd2b69b37cdde5d28ed42c4de9d69c8676b1863879082bfed"
   },
   {
     "TEST": 8,
-    "A": "45776a977fbb24669f0f5b14d7acbead19b1f23e67d8355156e4d2ad835b3ecb",
-    "B": "e30e8c0c7b4ada29ae217d87a7ce3a645354b6fa6585650e7e749f6b3c6a8cd6",
-    "E": "be816305456e6074737eb32e141a1cef89003ed5448d013a43f890ffa7d9eeb6",
-    "S": "b8bea737a5195af618cbc05f7d0af60df5f2f20805074e4b0b16f086134a0d2c",
-    "L": "f7ba14eafb15ee44511b0b7fc8f77cc2b0c3a4f7ec77f71286c022eb7ecc284c",
-    "T": "0c0c3e3cd44061869ccca4a6b9c449a2b46dbf2e73174822d9b2899cda6349a2",
-    "U": "787c5a03a3b443ee3fa7ff3ff90983b15fbd225b91dad900c2e115f9802c43f7"
+    "A": "8c445e5b7ded4cbe35c3ee3f7099c8e934f91af1c40769f8393e41accf99b0e0",
+    "B": "4a1e2a5cf808072ea5c16e1fb30c50937917bcd820d2ca6b576d46ec3921ae9a",
+    "E": "edf5287bd261774cb5bb598cb3cf2a0fceae399bd11052ae3d49981f7eb208e4",
+    "S": "a810da8072d0d8a25d80804a4b42aa271266bfdd9d5a381d16159ca68c99364b",
+    "L": "31029b181072637a6f1c37e78f43a027c5914a9d3e6490ee44a6556e5aa78479",
+    "T": "74929c82affb7002b6498f8eb4fa4a3f3c885555a76ad123ebe509b3e0563095",
+    "U": "eaf7f0aa49345ea20bcf7a0b6455d7ee93a22250578f685a4a47a2a1e00708e3"
   },
   {
     "TEST": 9,
-    "A": "a2dad6ce28cf198caa48eaddcdbd925452ece6cad4107559356a055a0fe24893",
-    "B": "ecc961fbe43346c86b5d4d39df3dcef0d10b7705e82b6efc150a0af912ee2b6d",
-    "E": "789ab333343a7d16cbc282cb8e4e19782443f31c1d49282d7a39229a85a83d38",
-    "S": "630f2d213eb0eb0f7bbe51999b55f6e66483e84c3658122b54bc5eec79885df6",
-    "L": "49f0f6e0465c04217d317516c0c1b844c96c113adcd4d48144ea83e2389c0d0d",
-    "T": "55a5b26fa437690e5cedb136b26d248459ee49801b7ae1423d12be5e6e28dc23",
-    "U": "59cf48a53168290f13e8df8ca62f45e2fbb9172e9b9161c95894d5ceef2300ab"
+    "A": "0ee46716e7ff3dd305539228c6b43eaa5e4b62eeff4774040f58e4a525dc3507",
+    "B": "9f89f7464b6d8b6696b993fd8d9d67e340a00ce74d20d451ef12f480cdb586e1",
+    "E": "fe5401db00e97272706a38f44a9e1242842124fb8961b5ee3c1d9c15224755e4",
+    "S": "5c4b0eb387613f0051b3d015470b82f0ad4cb2ae6b8ddf509f43098cd001b025",
+    "L": "3d1e96f31d07cd0ee32e5f427e8649509792443cee564ab9ad271277b14ed16d",
+    "T": "c3c448911a041b09b90f2e70c32f0a46e4c8051f243048473f9f9fc705b89b0e",
+    "U": "ef6ba05a3654d955ab2d5ce2331e1eaac4d6610d89b397deceb87377d15609c2"
   }
 ]
\ No newline at end of file
diff --git a/testVectors/schnorr/dprove.txt b/testVectors/schnorr/dprove.txt
index fca06d2..2d03af3 100644
--- a/testVectors/schnorr/dprove.txt
+++ b/testVectors/schnorr/dprove.txt
@@ -1,90 +1,90 @@
 TEST = 0,
-A = c3658c336985e9415ac8395a5a97dcd9bd0cb566f7c7fc23e4c53726627fc3d2,
-B = c8d085e5ea92fb4086caf99c27ba68d0cf075531f9a45527e49667558d9d79ff,
-E = 744953855c767494d6f4fdc48e852a54027e2b7aa6c6552c217dd98b152f6395,
-S = 4ba56d82ab4fd7f34eb58be3e3b1b23c06270f1d4d51d4662742b37700a70a06,
-L = 3e13bc076f821b97aaabb9b5a65fa5ef7a1c7e200009d2fa11f17a1858d0a52f,
-T = 2d01dec8512cdd6e880c25053de5f807ed48ebf831de4235754d825b0d1494a5,
-U = 54bf98385efdb40d39827c52d2f4e6d4df8dc0938655a7b0a57cace7986e895d,
+A = 98805901e0372ed6d0a40b6713fefc8287e8d1db602e019f2ed5351409d9706d,
+B = 26cc836888ad8d992f6a9147d708fe9a8f2d65fe86004730d12592c7b8b040ef,
+E = 1461d3a0ab285ff20abb1f57feab8d5177f48f7886ec7b40295daebb028f3585,
+S = 7a576ef122d172a58e5fe6dd5d99420b0ba1c484e3f3c4b7c68f1b61e62c0743,
+L = 0886d359c3d6d968e013364166ff8a99c19cbf8cf31682cac557033206616515,
+T = 82620066f763e041c98582a702a9c96862acb2ff1e8ddc41453d7de181649109,
+U = b6808109110b2f095dff929e6f70ffb212ed541bea0e9c502393b77354892e06,
 
 TEST = 1,
-A = 931f39d36bfc27283f5b3d791ad3f6df1c55f144fa2b52bd443fc4eb24f26281,
-B = b6fdb0f8402d57e166816f281b48c2b5a5c04d6c4ab52be80620feb98118957e,
-E = 9675ad591af467de8c64a39b438c213d86e5bbba431bb3880c186b4e8282a672,
-S = b6683ed0c7f7bb9b53250bb5cbdaf15aa84673d44c011f970b27c4dedc79a7c3,
-L = 6450fb92cefca0594fe5e37a2fab9eed46fcd44eaee464adf1237b8c3f9855ec,
-T = 30e4a42f280a7a135654a4af59a445ce09ed5683b7404d575bccf9d7a2c8c760,
-U = db60d0b8ba2d3ba0b884774259b8fc40e92595b01ffbc0aa36ee63e3126b194f,
+A = 0cb56a12df35413544e656003152984ef3ca4dcdc0521eaf8c64e6bc6c1e64f4,
+B = f0d0b41a157ce4fbb7d1489a35a9292a9613d04a762b4a2877fc00e65e8403ca,
+E = 0fd895b69a81143a766bc083b0b2438a056db9c7eaba689bf3eef1a27289a957,
+S = 4ca7684fe26ab68f8add3d5c7ffd93cabe7d1a40d6ac7275289c14e949f783cb,
+L = f3183da05f4eacd598ecfee13aafab0a66c4e8305fcdd6a125551b28421e4a18,
+T = 9a80b742ac91e1dfabdacc7beda876630da20fdfa68371594f0fc91767f97ef5,
+U = 09bd1bcc47053e8eaa41e620e0afcacbeffe9204b94b7adc4ea672791feaeae4,
 
 TEST = 2,
-A = f65387fd820997e523d1099ff99727dde285bac05a0cd9e63fb75e28284df79d,
-B = 94d0c8ba02ebde9f728d1fffd0ec743db34192366c42a9063580ea971d8d8d4b,
-E = 37ce44b6fcd5617c4470e9a83cdb9c2a5057eb71bdf656de4ad1a50cee70334c,
-S = 626e6215eae0f7f304af9abeac0d5267d9c83cbb9ed0beacb0090faaf0fc18eb,
-L = 0da04fe6194cc495ccb9d43225f0b29d7ef322665d37347c441b1a054f4a60b4,
-T = 3e0ff7c4fddb1f58933cf1d5ba9388ff2a6d0e4be347c59bf2be18457c7ab5e7,
-U = 71ee5b78721471d2ac47073eb92d979477208b44a16e8425293902e134c41d34,
+A = 2470fd1f08b27218902e84f7831b145a3397feea9063bb6dbc1dc58043793d36,
+B = aac9c4169145697d2be942b35b477d8f5e05d3380bf4a477b155a0b5b1cdca04,
+E = 557b85666a49026cf91b4f1131378a1e6b95bc9bbdc73a7dcd305ccc40005af7,
+S = 9f43938ac39a90d371ce160f091ec669b972f8406ca38cde8f14c17461e2294f,
+L = 38709c38e13a8d52051f5ddf14266c4179abaf37ef553bdf4871e343e51bcef7,
+T = 1e7ab0926591ea57389515a97932c5195f467a65154f1814b8c63990fe5c80d7,
+U = ff9a8a42430a35c1a667887a9cad3241f244e8823884ceb27cb576019fd8b09b,
 
 TEST = 3,
-A = 0e3cebfb2e5ef09c85305b6d400b35ed581729ecac51782cdb8908043d6bf4af,
-B = 192db7270206618045a6a83cc26babc89eb0f68946bec5b8b99d71a70f391505,
-E = b1568c9ef268cb8eca2f95a6b9bfa4fe90f65c368a44fbf105305263cf99b396,
-S = 57339ac50d52d6778fcd5787c5578d454c31d285d98e53e60dbfaee5eb22b5de,
-L = 6bffa4f19113e216da05bd988cde2fbbb1553f2f32b03893dad8569f61da8e59,
-T = 60c391d164811208e890f9b1b596b948b423ceca295a2f5e2bc3066dab605051,
-U = a410308bf97a4b2db7f809bdd7193a91191dfdbd7dc20e9d60ffa91602f2ad02,
+A = c5a4d6df2f2764c9218a8e83725f2d7ff489135f7b2ea0f83b06ed307d189540,
+B = ed016425bbb01beca9566bbf781774a5599ec9dcbf85f3e1a10698aaba5a5861,
+E = d046ffb08dcf4e6252943b222d5197bb82b6e564fce6bd772bb27a8e3e5944bb,
+S = cac09fc7c620c462f53d1793aec83182405ffa71f89e6e26a6fb461ad7bf90ac,
+L = 53c088a61f158eff3bd18592e595ed15474b1ac60c12fd84f5e4c59a07ccdc3c,
+T = 26452cf9fa404db00ae243e45d5a9902a8e11bb4f6025904b04e58bf0b3f513d,
+U = 3643906e09efca1b1edfbbe9dd10c3d9aacbadfffba6f3bd539bdfc79fb11f62,
 
 TEST = 4,
-A = a6720ad0cd437e1fad7b6cb831748de9a4c113d7a4407ac48d1c1c649a32cfa7,
-B = b7001f7b29784a455a9de707f496498e776af6cace3281a5d6dc877c3b960feb,
-E = de8bd108f9ece11b75fb01241477fb361609105d9874696121c678ceb39dbca1,
-S = f03a58d3248464d8a1d77e3107151f69ea0a3217238305e43208adb296d27deb,
-L = 5ce20cf65990bf869cb82b4d1b8a7a3dea605340419e86968d31266ad7ceb7cb,
-T = b7f424831ddbe2061f78e9c505748f30c719d0c813932a957bd62f98dd35bfe4,
-U = 6f10117963601ad31ef4c6ad7baf3753e4febd6b64e7772d741d5db2d7cdcd18,
+A = 2c3cc0f8606707858227db376e49d0539b35bb9a13e09394feda22125802d2fd,
+B = b20fd6417866c586ecbafcd3f3893baedd81897091beca86d6420eaf10d87931,
+E = 7c9d86a12b86d6fb2f17f528fa37832f85668dc967e7730e2a5299d59faf60f4,
+S = e73f8faf79981194c4ee0f1eadbd942d6e9297a6f7f2aa48ca384564392f6ef1,
+L = 4ce5e76bb95c0930d3fd86dde66b60f6810af5e27d7af9084ab2c1163dd292e5,
+T = ea39d54be9c92890cfb7ee8aba9b6403301dd69df490c29c0ef4a98fde987309,
+U = f8f44f48ab719fa71612f39c74416bcd9dad664c1be35f8b68c39519de49275d,
 
 TEST = 5,
-A = e064c90e03b7774ecea6f0c5633d9dd98fc6f8416d7baf39cf83df372bbd1a8f,
-B = b89bf2b48410d26cd0b2450bc384bde59caecd03d1b534b9dee14c4ffb718cc0,
-E = 4a12fe6e64639407ad01860b3cdc10e69dc7d6b319a2160abcac5b4cf1a609f9,
-S = 892a19776ba393756e325ae26eb1be8d058d1978b0cb20dfbbd6f1f514fbdccb,
-L = 06584dc2fbcb24bd8dcefa2ecb75468ca3ee594cafb7e65223fdb49357e7e2f0,
-T = 722402d368c0818577f357aad04d9195ea80e0b013d164f89cf7f3c8f2761f14,
-U = 778d3d0e10ea34e5379297027c1e5f9a0470f126cd19f6bfc21e881652563b5e,
+A = c3df2d0f74fe039e5fbddf583555399f0ab564034eaa5eaa871e734021f77689,
+B = d30ec4e0969fa9cf0dd1c61b725e5b5faac8c96e12f5bfc8ac441180a85357c1,
+E = 67bd9cd0b2e0695346b66d07053f26ba60022473f986ab4956b0c20ca5eeb7d4,
+S = e86b00ec424317d9e6c983682b76e0589149c2be2de586515ccb403bb61613ea,
+L = 6345b6f3ec1ec358e700f8d19a0dfde21a4a91cc262a1f4673b451c72539a294,
+T = 85148b51e33264a188b79df3cac87e78041047e2300678d0d8984ec2af8043ff,
+U = 096147a069b0d63da7a85d68047a827cec23c3da65d590345291cbe491e769c3,
 
 TEST = 6,
-A = 1cb8713e7dba86e70d446668d75bc9c992e6c10c9f6ed108ff0006a6d1b0937b,
-B = f5cca22f672064914108a628be72e54380471853c91cd92904973944d3671631,
-E = f54feab6fc6679e536521834a395893c4dcbb9f5cbd79dc6a9b54661eebb3166,
-S = b69c37cc0963f8619645e9bf2f949ef829aace7604835f08579ecff67049782a,
-L = e3f71b7a4f66283eab2cc81ae718723105ac4284f668271d53a5053bcb86f449,
-T = 03fec2defb4cb0037aa1fe3e98062b7d3265e6fe6b96257e961203daa7bb20ab,
-U = b9710f2a2824a140aa970cf2aff3d898c9fe0e69352e5ceee4281549bade7ffe,
+A = 7f65618bf4531471c0b419bde1c06dcf7f20064fc65a97510658fe81db7eba0b,
+B = 1a141938c4c0e7e3ad4f648be35ab96f39b9329129556d8f549e1995d0af503e,
+E = 2449978fa5cca2b27e17085429f9071d5d8bbe3f8f53df285eee5f6cc5efe1e5,
+S = f4e7cccc8bf490e705720a33776fab2ec700010dd971b8430abba2cdb77d48e7,
+L = e58b630fc1350574468489f76a6c5fe3298a6174343a261c9af87bdbfe79dd80,
+T = dd0d19687a3ce16fd50720f3f06971089ca91ea50c22d489bcf2c1cdfce6a83c,
+U = dba67e6ef893225ec8a86ffe4f5fba51820117efd25dbbe1dadcd8f9dffe1174,
 
 TEST = 7,
-A = 38c3298372a795c04c9bf3490d01f6f366bf3ac64c6a5c921581be6fb8263922,
-B = eb922d0b0694a1e7973742dbff6bfc65cf29cfdf50d22cb7304dc060292adea2,
-E = bf22c8d94b8b6005b6790ff357647e61b3cb853994f358e4fca9ddc9e191232b,
-S = 692622cb87e36d76b72f5726cc47877cbdd20e5f09ed37a69f9e3483432f8832,
-L = 35459a922c7dee62d1bd2cc240d5ced07bb978f7e2519f93cc5c8f24985593d1,
-T = 4075007fe3a002a59f723027738a37b90dfe8237dc92588769e3e8bae191ec28,
-U = 67caf11bef014d06b9f4467c8b520af8ef9cce399be37997d37f34f1e5cfe367,
+A = c712cd92b407de5731a351dfb230b1ae0f65f99184ff97d7e7dbd3d9921ffd1e,
+B = 08e02f9c632d3fd1f48bdddcfdaca3588b168f0b6ff4cbaee99356d23d1e355a,
+E = e0eb9c89aa93820c6a81431ca3c3e2d33088f1d0c1bddea749bb91a252425145,
+S = c212f5fe66de61ebf95c0e0797bea72fcf10bb5f4aa903085aef685e35f68220,
+L = 234d8df29b1ee7f841b6d74a9bb8139d379df056716187225acc45fcc7d364f3,
+T = 3e82ff64fde662cec1730ca59d759c22f191326dbbbeaf09fa2c01a9184782ab,
+U = 51e0c8ba1580270fd2b69b37cdde5d28ed42c4de9d69c8676b1863879082bfed,
 
 TEST = 8,
-A = 45776a977fbb24669f0f5b14d7acbead19b1f23e67d8355156e4d2ad835b3ecb,
-B = e30e8c0c7b4ada29ae217d87a7ce3a645354b6fa6585650e7e749f6b3c6a8cd6,
-E = be816305456e6074737eb32e141a1cef89003ed5448d013a43f890ffa7d9eeb6,
-S = b8bea737a5195af618cbc05f7d0af60df5f2f20805074e4b0b16f086134a0d2c,
-L = f7ba14eafb15ee44511b0b7fc8f77cc2b0c3a4f7ec77f71286c022eb7ecc284c,
-T = 0c0c3e3cd44061869ccca4a6b9c449a2b46dbf2e73174822d9b2899cda6349a2,
-U = 787c5a03a3b443ee3fa7ff3ff90983b15fbd225b91dad900c2e115f9802c43f7,
+A = 8c445e5b7ded4cbe35c3ee3f7099c8e934f91af1c40769f8393e41accf99b0e0,
+B = 4a1e2a5cf808072ea5c16e1fb30c50937917bcd820d2ca6b576d46ec3921ae9a,
+E = edf5287bd261774cb5bb598cb3cf2a0fceae399bd11052ae3d49981f7eb208e4,
+S = a810da8072d0d8a25d80804a4b42aa271266bfdd9d5a381d16159ca68c99364b,
+L = 31029b181072637a6f1c37e78f43a027c5914a9d3e6490ee44a6556e5aa78479,
+T = 74929c82affb7002b6498f8eb4fa4a3f3c885555a76ad123ebe509b3e0563095,
+U = eaf7f0aa49345ea20bcf7a0b6455d7ee93a22250578f685a4a47a2a1e00708e3,
 
 TEST = 9,
-A = a2dad6ce28cf198caa48eaddcdbd925452ece6cad4107559356a055a0fe24893,
-B = ecc961fbe43346c86b5d4d39df3dcef0d10b7705e82b6efc150a0af912ee2b6d,
-E = 789ab333343a7d16cbc282cb8e4e19782443f31c1d49282d7a39229a85a83d38,
-S = 630f2d213eb0eb0f7bbe51999b55f6e66483e84c3658122b54bc5eec79885df6,
-L = 49f0f6e0465c04217d317516c0c1b844c96c113adcd4d48144ea83e2389c0d0d,
-T = 55a5b26fa437690e5cedb136b26d248459ee49801b7ae1423d12be5e6e28dc23,
-U = 59cf48a53168290f13e8df8ca62f45e2fbb9172e9b9161c95894d5ceef2300ab,
+A = 0ee46716e7ff3dd305539228c6b43eaa5e4b62eeff4774040f58e4a525dc3507,
+B = 9f89f7464b6d8b6696b993fd8d9d67e340a00ce74d20d451ef12f480cdb586e1,
+E = fe5401db00e97272706a38f44a9e1242842124fb8961b5ee3c1d9c15224755e4,
+S = 5c4b0eb387613f0051b3d015470b82f0ad4cb2ae6b8ddf509f43098cd001b025,
+L = 3d1e96f31d07cd0ee32e5f427e8649509792443cee564ab9ad271277b14ed16d,
+T = c3c448911a041b09b90f2e70c32f0a46e4c8051f243048473f9f9fc705b89b0e,
+U = ef6ba05a3654d955ab2d5ce2331e1eaac4d6610d89b397deceb87377d15609c2,
 
diff --git a/testVectors/schnorr/dverify.json b/testVectors/schnorr/dverify.json
index f0bfff8..86e9b88 100644
--- a/testVectors/schnorr/dverify.json
+++ b/testVectors/schnorr/dverify.json
@@ -1,92 +1,92 @@
 [
   {
     "TEST": 0,
-    "R": "0337f69333ec13ff263492807e1da7efccf880dda2d3e54062ebe1e56a4ac8114f",
-    "V": "03da9f79c96ede4add43f6da69c13c24d441c418ccf9266a0794d4b60139b769f8",
-    "C": "03be659529d5b0e5e895c98fe4a1615019a0ef506e8be65a844ea3e846e06ab06c",
-    "E": "5d163667398926b52b47f8164fc92795a9cad7e43efe9f71b78fb6b9d623dc10",
-    "T": "9b802924c454fa018f220d92c431e927a68bd861f3a823815b5bce9d59291f79",
-    "U": "9825d990f6a0219cfe6cd8385ed3124f3d20211b8fc8a53440dbf565d6435e21"
+    "R": "020537773ffc3da376e2f3dabba54b84f3c865ad8acf3d77f72afaf20a5cb44e57",
+    "V": "033b69f8bdf508ca2bebe2518e177b20f12c4d8335f628b318160a5b4201ef93ad",
+    "C": "028053a7ddd2d195913e2e520b1b6be09d6f3dd3b3dcc7f5dad04ba2afc2307d90",
+    "E": "edebdfc8bda2088507f63a7dea84a2a2b704c97e42e48127f68dcea818325d8d",
+    "T": "d1d8e4894b8c5c7262d1aaba981a7a75d31e7bb269890d53116e70be0cdf99d9",
+    "U": "bb7b364ec9d428e273f5e71e689fe1ded08f9805416fb366894fec518b5ab9f8"
   },
   {
     "TEST": 1,
-    "R": "0310d9f650695d137ca05adec60b1b78445a40bf403e4f641fe38c2897aaa67769",
-    "V": "02555ec03ecd2e1585b708a8fe7a1d514057e3152381de479281e083d783a7beb9",
-    "C": "031072f0b4d488f0e8f93aae1957d5894f0dc3a98c1bc7bae8ea86fd8eb3222565",
-    "E": "1a45745881d6a22056c4734b068b7d92877a51aead03432774347880f860aa65",
-    "T": "52b37b5e9e38d8e26fc1b21fcafc63474cb6539134f9931145804bc925913032",
-    "U": "e148e44602200a79114daa2458f09a8a6e372cf1af472eca05ff2c17f12b42a9"
+    "R": "02daa4bb8bfcdd6293e04b68686d3b05c06b195cc880062c2625e3007ea4cfe0c0",
+    "V": "029485b64dc10ac2d0ce3555c94975998af4d9c71d29fe5ae0649bcc7ffce5e7e6",
+    "C": "03874b1fae542def460a696815b5a903c5d37ff7adfc2baa49fb8b9433a25d1509",
+    "E": "587b8ccd7122bb35e02c94b2db3e23f1ee65bccdc8f9e71d034c89b94a090cb8",
+    "T": "b93f24de57b859db76a884313aa730ef18c63e2ca53ad6d2c7d90b337450c16d",
+    "U": "64cc0abb4245a5d37359a324324a7e9e64d115b39ea0a2f5b7d9ad6f210e5c3b"
   },
   {
     "TEST": 2,
-    "R": "03903e4bb60f886668c5cdfadd0ddd349cacc4879de7fe8b7fa43ba79a6cbe01b3",
-    "V": "03ade35a1e50500a4bc8ed3fecb3f1aa2570a39499044c6282398f4dd071ed6c85",
-    "C": "02cbd3a2714376e1f3cab63feb5e9d23b36135b4565e7d4b4a85afae0882baa4ed",
-    "E": "450a269d202de9a6d2573b510bcc02f1e7c7d5b4a5779c55fbb4bd25241a1f9f",
-    "T": "e96ce1c43cbe59f6f6946dea0ff1f3bc15227da9758308f48a53e4fc4c666249",
-    "U": "a42aa5d5efceb63a480e8718d6e7930c3a156ba9ff971bae8538062305e502c7"
+    "R": "02913dc55b4d1e8e89d9e7c3e38702add012aae04a42439f9fe1d5d690d3255566",
+    "V": "023ec4892b5efe9e5db85104034a20b9cca6b7d7129f760b65ea19c33e6f4287a9",
+    "C": "03adab79913fc68007fe6db89ab64240edc864bc1a08dbea210492837707b53458",
+    "E": "d455924c96c02ec532e137a2b288aa04745ecb18cc1000a55613cdf412a46427",
+    "T": "97e10ec3f596284e1efdbb20dfc53593339e5aa9e3117ac3dc7e0087c0ffc831",
+    "U": "2425097f2bdedd1b7294e6c35a036e1968bf5ec0cee387b948f4afc6827566b4"
   },
   {
     "TEST": 3,
-    "R": "02ac3a849571574161e53aaf3cb9c8c323c3498e7d329f02d723a6b9b3a1848a67",
-    "V": "025fbc82aa7b986a386ad2fa524f085a0e23dadd259a01e2dda66bf79d4fef9fb5",
-    "C": "039436f7a6a41ef3e624090f34ac24331fc9b233d03430f263ac62e3b6555817ba",
-    "E": "670dcf5cca02ce7bb776e48fd01f06119da99af75581ce715cca828e14627771",
-    "T": "b4702324fa24b547850709fc0874809b638aa5e8ef10f8715100d116f5683702",
-    "U": "f708022da7a842e68094699df0cd1124a7ae40d17a9bbb5788bf4fec85e9a1b8"
+    "R": "02cb97763b448ee16c0dbdcdef765e2ae257ec129fc7ef992b04850a51137ff5f5",
+    "V": "0211d00ede35b17508461d8d31323a86825bdd0b7458626a76a83705c0f95a5351",
+    "C": "03c4d0adc3e672fb70a9a0138b173d1d09ff23f9e4329035f5a7136c6fd9564849",
+    "E": "83c5149c51cf6a9c246a6b407b0c8dc7b47e99977b1deba413d88437aebe813c",
+    "T": "50ed725d57e38dbda89a2e87fe9cd72dad2434e5583243cb183cf611679e7972",
+    "U": "254066df913b9132a6534451968844058ab803f485642e686e30ac19c78d88f5"
   },
   {
     "TEST": 4,
-    "R": "0316ddced170deb5eee2121216c5a714e25ed0cbc5ef5646cc754234f778eb1c0b",
-    "V": "03b5302ae8d3061ebeebd34ad3e74f4be7ff11b20d321716f10d4e0a409059b2fa",
-    "C": "021e20bf1693d7515137d274938beb4faa5b6e5fa4fe81d2706cd1c9ad04c07a62",
-    "E": "7d9690223a556bcbcd86d24b20d85a520199ae39299dfc4f1f1ee36ffeda24e3",
-    "T": "d6bab7bb975b18d876909c797fd3c70ee4ab59168d0bdad29620c517e5af324b",
-    "U": "a3a0e66ed30df31b1e3195c964a00e731939ea5ea2c9176fc6fdd39c0dde4701"
+    "R": "03c5c2ba8cf4e0ddd06803f2eab8426e7250467e8a521e6e4764f8ed50f99e8ead",
+    "V": "03dcb5f6ead7e81963ab4a3f1f5c6d77e4c079001343b7058e8bff7c5d84f5da4a",
+    "C": "036410928e258ce7800407f127141ae617f5e2e89864b66c1dfa72a401fb5fbb61",
+    "E": "ec74f330ac0ceea0d1c957fb01a07dccd1798d98d33b567b0c931dcc2c3e90ea",
+    "T": "dc77f3cc4b31c8677ef566fc182a8c32bd98188aaa5255062104019dfc3b09dc",
+    "U": "6774443dbc5ecc5bcaf4597f36ede169372611417c53b8445ca56cb92aafe852"
   },
   {
     "TEST": 5,
-    "R": "03d28743c72ab145876065f39a3105d9b0f55bb225ef797c0674e65bf85c3439c3",
-    "V": "03708abbfa0a807e3540d8aa6c589c6993bcc0238986b317cfecbdc962fb459860",
-    "C": "02804191a4f52d8cf6948596122d89c079e4f6212420a263e66a693c1da94c3223",
-    "E": "ff5bfd05347b361da4d159a29dae99df2ecdf2eec94fd4ade894398d9c4bc239",
-    "T": "4ca83780f3ab9e30e29c87c3cb6fa0eabb3e0f664d2c27a6bce05380c9ae92ae",
-    "U": "4edeef14e75585e7fd197c719fd3948f1f420a724d5c3a95eb5bff0bb38681a6"
+    "R": "02d1ee046200382c654c90a02fcc1b025ac15b34d26cb864b7278e359d04779792",
+    "V": "02380955f1798a27cd14802b947ec8b4b57fa206ac44707d3bc0d4beb7e2b1db5e",
+    "C": "02aab91a349d395b360362ca157a005c2cf9feab3ea25a86e62ee6f6bb8948968a",
+    "E": "8e50b3197f779789bcb082d9be490863fd2b68b9357d951b222fc5724e2aedcd",
+    "T": "abc2b26aa50342df17c1adb5d600557d1460fa21360a386af8d4042b86ae87e6",
+    "U": "e9f3f4669b61ace1037c04b0273500cadd2bdac058d1f50fccec4b0b71893c74"
   },
   {
     "TEST": 6,
-    "R": "0375cd1b2c2de801df582927c5b7bb823d03544d818dc2b4ff754cdf3ef30c4c03",
-    "V": "039fe1711cd9f775105caa6db9cdea37023fccd81d2c03a36141cc15a009e3ee58",
-    "C": "03271d03e3c2105cd8dce4e17d7e76cb4174cd1631c8c2dcbdee5ef9d67312b2a4",
-    "E": "56eec5122920560f0b88db05c7912d517f1ba492d1f21e9ab747e354df7e6665",
-    "T": "f53dc9b0e3580638a7ea996318663d207c73495ebadf47e8061597cf7addb557",
-    "U": "af3c5fa843e6bb582820c9f8a7a050f4162980c2aaf15952cb615ec0c86e53ab"
+    "R": "02bb995b6ef4415dac329d0f02aaebf248121e2cf844fce54d947b14e7b1c756c8",
+    "V": "03b4f1b72b07951c4db6ed445f1386fdd9859813b9bbcf3d59b78f2c41a1b0f417",
+    "C": "0258882ae61e1e8549cb4c2af92d479819c87bc02714106eabb1d1e8eaec36b26f",
+    "E": "70bb1893f91f520378838b35a240e65e3153d5b891ffafc7ecdd838c2042cbde",
+    "T": "88e8d7350400868a8d48f630868cbbc2ef97112696b985a3ad0c78d833a33625",
+    "U": "bc4471af39ffe173f59807badbe79ffc9548f6d8fcaa8ecdccf6c3f7797f82cb"
   },
   {
     "TEST": 7,
-    "R": "03a487f61837e87c747c2737172b962f79f90f3e485792db349390393c7bbec009",
-    "V": "025c58b47fac4b2bc4556782fd0ff5d6f2761520b256150167144bfe1589531d2b",
-    "C": "02de1aac64d96206096d82a9782d890593492c33b6fb2cd0eb3d5da13e37a0571e",
-    "E": "608e104063ace2a703cdb85d79a9817f7732fada6cd2447af523df25083fe01c",
-    "T": "36c6489ecae5ccb524d2f3166bcdfc71b77aac8cc25a61433cd1062e113103aa",
-    "U": "b6dadf473f9e7a341848f0a6ea84962694afe9776cd5f45175d6902b64709e96"
+    "R": "038bb34386bc9c7f065136d04f1c62c936ddbe9874235b2b27e378cf7514e34e10",
+    "V": "03a02e15a584f591c5fc8f0b4c1408552433c8547225643eff5414afdbaec8abf2",
+    "C": "021d1064a0e59a75d7e0f8b08d958c6a7f25882dc838acee5a962300e1b02de047",
+    "E": "5623eeafec05f5a592647f78b351f8adca1d4d99aec7992fdc1db4c830a39366",
+    "T": "fea34fc356079b51b529bd6681ba0bd8d01f3417cce03944b21386ca9ddc7e3b",
+    "U": "74071f2a607cbc64255c8d64df7eb5cd31ab8a85d91d6497288c6339ca1fb526"
   },
   {
     "TEST": 8,
-    "R": "0345c3278b4d2e9fbb697b4a497bd41b068314b20a3556984286a348195e4bf87d",
-    "V": "028c61a27347c094aa299e95dc648cfde1d0ab65ee48a70bbc1d2fddbb43cea989",
-    "C": "0369298338f45f3e501e7f46d31ff4010425074b128e557bbc8ac5f80dbf764aa9",
-    "E": "9f553102958aecaf0d00130c36f5bc7c42eaa2ace113853ede0001ae5164a07b",
-    "T": "a0b325d9e5b895ceae62621c1cf29d9a2fc4498fd1fc9937a63c8f32446080cc",
-    "U": "a552b6f899eba8c5c2fdc67d2e8f20420a79002b2a8ed545c1332b2b2675eeb7"
+    "R": "0390d1fe5c60463086f65d1b44dbdf65c001f4e532f763e45646765d06019960de",
+    "V": "03a603e43e1a98b839f6971eb0fe73c7a70130e0c27411fda59617c8365ac6cdf2",
+    "C": "02938dcf17c55d78aa6b871d38ae838ea56d38c321c470527340212c4ada21fbd5",
+    "E": "51902fda78bb40a1eb2099512ae3e4853f596f0be0e73f478a01f4fff9c48e4c",
+    "T": "8daf81313b9aa20c44bbe6daa070618b571ad03df23e390ae7ec2585f1205ffd",
+    "U": "a77503c8846192032f79f882ad9e8e21b7534553c2db6f0e988659c3675b5aa5"
   },
   {
     "TEST": 9,
-    "R": "02c9ce032faa136eb3ad72225300a592a620d5a9a9f90bf303fab853e29bb68276",
-    "V": "02313802a1e8c0e23d830d0ddbc81f4b9bdf8636f79823a84ba57e3beb8d11c35d",
-    "C": "026647a49f2daed3ff69d03c9638bea864f125485af059fe60d640f9e9a0685944",
-    "E": "fb92fc530bb01d308afc30190ec261d4474346107f33809abe4bef288891e2cb",
-    "T": "f1be16549e065da6bf96466c9330194e92f2dde14fffb883922c98e6361f19f8",
-    "U": "e9a57b8486df4a58021fb1f57e3fb8ac5a30a73de5868d6542a196fbf3fc47fb"
+    "R": "025e534768bafa3171b850bcccbfad82702adc69d90f9db32debe7afe7fdd06f1c",
+    "V": "0229bc145f45468201a47c3e62785503d006fa9be41cd5892a65002a7aef0e79cd",
+    "C": "0248d59ed28567a329f442051fb7e91069a136e68751c52d5e592693295ecc0e81",
+    "E": "104b7d4a22cd1cee0d853f5b3d0e4e9a14e5156201b92b4860bcd8a07423e7b0",
+    "T": "b4a9bf92910036da6342cf59bb6b545e7faf8dd3affb4ff1223d1c1805de7884",
+    "U": "4e78b645d5dba4a43f1fd896f62ba089608c4410bb6478de9a2ca9323dd7b0dc"
   }
 ]
\ No newline at end of file
diff --git a/testVectors/schnorr/dverify.txt b/testVectors/schnorr/dverify.txt
index 41b2438..235bf07 100644
--- a/testVectors/schnorr/dverify.txt
+++ b/testVectors/schnorr/dverify.txt
@@ -1,80 +1,80 @@
 TEST = 0,
-R = 0337f69333ec13ff263492807e1da7efccf880dda2d3e54062ebe1e56a4ac8114f,
-V = 03da9f79c96ede4add43f6da69c13c24d441c418ccf9266a0794d4b60139b769f8,
-C = 03be659529d5b0e5e895c98fe4a1615019a0ef506e8be65a844ea3e846e06ab06c,
-E = 5d163667398926b52b47f8164fc92795a9cad7e43efe9f71b78fb6b9d623dc10,
-T = 9b802924c454fa018f220d92c431e927a68bd861f3a823815b5bce9d59291f79,
-U = 9825d990f6a0219cfe6cd8385ed3124f3d20211b8fc8a53440dbf565d6435e21,
+R = 020537773ffc3da376e2f3dabba54b84f3c865ad8acf3d77f72afaf20a5cb44e57,
+V = 033b69f8bdf508ca2bebe2518e177b20f12c4d8335f628b318160a5b4201ef93ad,
+C = 028053a7ddd2d195913e2e520b1b6be09d6f3dd3b3dcc7f5dad04ba2afc2307d90,
+E = edebdfc8bda2088507f63a7dea84a2a2b704c97e42e48127f68dcea818325d8d,
+T = d1d8e4894b8c5c7262d1aaba981a7a75d31e7bb269890d53116e70be0cdf99d9,
+U = bb7b364ec9d428e273f5e71e689fe1ded08f9805416fb366894fec518b5ab9f8,
 
 TEST = 1,
-R = 0310d9f650695d137ca05adec60b1b78445a40bf403e4f641fe38c2897aaa67769,
-V = 02555ec03ecd2e1585b708a8fe7a1d514057e3152381de479281e083d783a7beb9,
-C = 031072f0b4d488f0e8f93aae1957d5894f0dc3a98c1bc7bae8ea86fd8eb3222565,
-E = 1a45745881d6a22056c4734b068b7d92877a51aead03432774347880f860aa65,
-T = 52b37b5e9e38d8e26fc1b21fcafc63474cb6539134f9931145804bc925913032,
-U = e148e44602200a79114daa2458f09a8a6e372cf1af472eca05ff2c17f12b42a9,
+R = 02daa4bb8bfcdd6293e04b68686d3b05c06b195cc880062c2625e3007ea4cfe0c0,
+V = 029485b64dc10ac2d0ce3555c94975998af4d9c71d29fe5ae0649bcc7ffce5e7e6,
+C = 03874b1fae542def460a696815b5a903c5d37ff7adfc2baa49fb8b9433a25d1509,
+E = 587b8ccd7122bb35e02c94b2db3e23f1ee65bccdc8f9e71d034c89b94a090cb8,
+T = b93f24de57b859db76a884313aa730ef18c63e2ca53ad6d2c7d90b337450c16d,
+U = 64cc0abb4245a5d37359a324324a7e9e64d115b39ea0a2f5b7d9ad6f210e5c3b,
 
 TEST = 2,
-R = 03903e4bb60f886668c5cdfadd0ddd349cacc4879de7fe8b7fa43ba79a6cbe01b3,
-V = 03ade35a1e50500a4bc8ed3fecb3f1aa2570a39499044c6282398f4dd071ed6c85,
-C = 02cbd3a2714376e1f3cab63feb5e9d23b36135b4565e7d4b4a85afae0882baa4ed,
-E = 450a269d202de9a6d2573b510bcc02f1e7c7d5b4a5779c55fbb4bd25241a1f9f,
-T = e96ce1c43cbe59f6f6946dea0ff1f3bc15227da9758308f48a53e4fc4c666249,
-U = a42aa5d5efceb63a480e8718d6e7930c3a156ba9ff971bae8538062305e502c7,
+R = 02913dc55b4d1e8e89d9e7c3e38702add012aae04a42439f9fe1d5d690d3255566,
+V = 023ec4892b5efe9e5db85104034a20b9cca6b7d7129f760b65ea19c33e6f4287a9,
+C = 03adab79913fc68007fe6db89ab64240edc864bc1a08dbea210492837707b53458,
+E = d455924c96c02ec532e137a2b288aa04745ecb18cc1000a55613cdf412a46427,
+T = 97e10ec3f596284e1efdbb20dfc53593339e5aa9e3117ac3dc7e0087c0ffc831,
+U = 2425097f2bdedd1b7294e6c35a036e1968bf5ec0cee387b948f4afc6827566b4,
 
 TEST = 3,
-R = 02ac3a849571574161e53aaf3cb9c8c323c3498e7d329f02d723a6b9b3a1848a67,
-V = 025fbc82aa7b986a386ad2fa524f085a0e23dadd259a01e2dda66bf79d4fef9fb5,
-C = 039436f7a6a41ef3e624090f34ac24331fc9b233d03430f263ac62e3b6555817ba,
-E = 670dcf5cca02ce7bb776e48fd01f06119da99af75581ce715cca828e14627771,
-T = b4702324fa24b547850709fc0874809b638aa5e8ef10f8715100d116f5683702,
-U = f708022da7a842e68094699df0cd1124a7ae40d17a9bbb5788bf4fec85e9a1b8,
+R = 02cb97763b448ee16c0dbdcdef765e2ae257ec129fc7ef992b04850a51137ff5f5,
+V = 0211d00ede35b17508461d8d31323a86825bdd0b7458626a76a83705c0f95a5351,
+C = 03c4d0adc3e672fb70a9a0138b173d1d09ff23f9e4329035f5a7136c6fd9564849,
+E = 83c5149c51cf6a9c246a6b407b0c8dc7b47e99977b1deba413d88437aebe813c,
+T = 50ed725d57e38dbda89a2e87fe9cd72dad2434e5583243cb183cf611679e7972,
+U = 254066df913b9132a6534451968844058ab803f485642e686e30ac19c78d88f5,
 
 TEST = 4,
-R = 0316ddced170deb5eee2121216c5a714e25ed0cbc5ef5646cc754234f778eb1c0b,
-V = 03b5302ae8d3061ebeebd34ad3e74f4be7ff11b20d321716f10d4e0a409059b2fa,
-C = 021e20bf1693d7515137d274938beb4faa5b6e5fa4fe81d2706cd1c9ad04c07a62,
-E = 7d9690223a556bcbcd86d24b20d85a520199ae39299dfc4f1f1ee36ffeda24e3,
-T = d6bab7bb975b18d876909c797fd3c70ee4ab59168d0bdad29620c517e5af324b,
-U = a3a0e66ed30df31b1e3195c964a00e731939ea5ea2c9176fc6fdd39c0dde4701,
+R = 03c5c2ba8cf4e0ddd06803f2eab8426e7250467e8a521e6e4764f8ed50f99e8ead,
+V = 03dcb5f6ead7e81963ab4a3f1f5c6d77e4c079001343b7058e8bff7c5d84f5da4a,
+C = 036410928e258ce7800407f127141ae617f5e2e89864b66c1dfa72a401fb5fbb61,
+E = ec74f330ac0ceea0d1c957fb01a07dccd1798d98d33b567b0c931dcc2c3e90ea,
+T = dc77f3cc4b31c8677ef566fc182a8c32bd98188aaa5255062104019dfc3b09dc,
+U = 6774443dbc5ecc5bcaf4597f36ede169372611417c53b8445ca56cb92aafe852,
 
 TEST = 5,
-R = 03d28743c72ab145876065f39a3105d9b0f55bb225ef797c0674e65bf85c3439c3,
-V = 03708abbfa0a807e3540d8aa6c589c6993bcc0238986b317cfecbdc962fb459860,
-C = 02804191a4f52d8cf6948596122d89c079e4f6212420a263e66a693c1da94c3223,
-E = ff5bfd05347b361da4d159a29dae99df2ecdf2eec94fd4ade894398d9c4bc239,
-T = 4ca83780f3ab9e30e29c87c3cb6fa0eabb3e0f664d2c27a6bce05380c9ae92ae,
-U = 4edeef14e75585e7fd197c719fd3948f1f420a724d5c3a95eb5bff0bb38681a6,
+R = 02d1ee046200382c654c90a02fcc1b025ac15b34d26cb864b7278e359d04779792,
+V = 02380955f1798a27cd14802b947ec8b4b57fa206ac44707d3bc0d4beb7e2b1db5e,
+C = 02aab91a349d395b360362ca157a005c2cf9feab3ea25a86e62ee6f6bb8948968a,
+E = 8e50b3197f779789bcb082d9be490863fd2b68b9357d951b222fc5724e2aedcd,
+T = abc2b26aa50342df17c1adb5d600557d1460fa21360a386af8d4042b86ae87e6,
+U = e9f3f4669b61ace1037c04b0273500cadd2bdac058d1f50fccec4b0b71893c74,
 
 TEST = 6,
-R = 0375cd1b2c2de801df582927c5b7bb823d03544d818dc2b4ff754cdf3ef30c4c03,
-V = 039fe1711cd9f775105caa6db9cdea37023fccd81d2c03a36141cc15a009e3ee58,
-C = 03271d03e3c2105cd8dce4e17d7e76cb4174cd1631c8c2dcbdee5ef9d67312b2a4,
-E = 56eec5122920560f0b88db05c7912d517f1ba492d1f21e9ab747e354df7e6665,
-T = f53dc9b0e3580638a7ea996318663d207c73495ebadf47e8061597cf7addb557,
-U = af3c5fa843e6bb582820c9f8a7a050f4162980c2aaf15952cb615ec0c86e53ab,
+R = 02bb995b6ef4415dac329d0f02aaebf248121e2cf844fce54d947b14e7b1c756c8,
+V = 03b4f1b72b07951c4db6ed445f1386fdd9859813b9bbcf3d59b78f2c41a1b0f417,
+C = 0258882ae61e1e8549cb4c2af92d479819c87bc02714106eabb1d1e8eaec36b26f,
+E = 70bb1893f91f520378838b35a240e65e3153d5b891ffafc7ecdd838c2042cbde,
+T = 88e8d7350400868a8d48f630868cbbc2ef97112696b985a3ad0c78d833a33625,
+U = bc4471af39ffe173f59807badbe79ffc9548f6d8fcaa8ecdccf6c3f7797f82cb,
 
 TEST = 7,
-R = 03a487f61837e87c747c2737172b962f79f90f3e485792db349390393c7bbec009,
-V = 025c58b47fac4b2bc4556782fd0ff5d6f2761520b256150167144bfe1589531d2b,
-C = 02de1aac64d96206096d82a9782d890593492c33b6fb2cd0eb3d5da13e37a0571e,
-E = 608e104063ace2a703cdb85d79a9817f7732fada6cd2447af523df25083fe01c,
-T = 36c6489ecae5ccb524d2f3166bcdfc71b77aac8cc25a61433cd1062e113103aa,
-U = b6dadf473f9e7a341848f0a6ea84962694afe9776cd5f45175d6902b64709e96,
+R = 038bb34386bc9c7f065136d04f1c62c936ddbe9874235b2b27e378cf7514e34e10,
+V = 03a02e15a584f591c5fc8f0b4c1408552433c8547225643eff5414afdbaec8abf2,
+C = 021d1064a0e59a75d7e0f8b08d958c6a7f25882dc838acee5a962300e1b02de047,
+E = 5623eeafec05f5a592647f78b351f8adca1d4d99aec7992fdc1db4c830a39366,
+T = fea34fc356079b51b529bd6681ba0bd8d01f3417cce03944b21386ca9ddc7e3b,
+U = 74071f2a607cbc64255c8d64df7eb5cd31ab8a85d91d6497288c6339ca1fb526,
 
 TEST = 8,
-R = 0345c3278b4d2e9fbb697b4a497bd41b068314b20a3556984286a348195e4bf87d,
-V = 028c61a27347c094aa299e95dc648cfde1d0ab65ee48a70bbc1d2fddbb43cea989,
-C = 0369298338f45f3e501e7f46d31ff4010425074b128e557bbc8ac5f80dbf764aa9,
-E = 9f553102958aecaf0d00130c36f5bc7c42eaa2ace113853ede0001ae5164a07b,
-T = a0b325d9e5b895ceae62621c1cf29d9a2fc4498fd1fc9937a63c8f32446080cc,
-U = a552b6f899eba8c5c2fdc67d2e8f20420a79002b2a8ed545c1332b2b2675eeb7,
+R = 0390d1fe5c60463086f65d1b44dbdf65c001f4e532f763e45646765d06019960de,
+V = 03a603e43e1a98b839f6971eb0fe73c7a70130e0c27411fda59617c8365ac6cdf2,
+C = 02938dcf17c55d78aa6b871d38ae838ea56d38c321c470527340212c4ada21fbd5,
+E = 51902fda78bb40a1eb2099512ae3e4853f596f0be0e73f478a01f4fff9c48e4c,
+T = 8daf81313b9aa20c44bbe6daa070618b571ad03df23e390ae7ec2585f1205ffd,
+U = a77503c8846192032f79f882ad9e8e21b7534553c2db6f0e988659c3675b5aa5,
 
 TEST = 9,
-R = 02c9ce032faa136eb3ad72225300a592a620d5a9a9f90bf303fab853e29bb68276,
-V = 02313802a1e8c0e23d830d0ddbc81f4b9bdf8636f79823a84ba57e3beb8d11c35d,
-C = 026647a49f2daed3ff69d03c9638bea864f125485af059fe60d640f9e9a0685944,
-E = fb92fc530bb01d308afc30190ec261d4474346107f33809abe4bef288891e2cb,
-T = f1be16549e065da6bf96466c9330194e92f2dde14fffb883922c98e6361f19f8,
-U = e9a57b8486df4a58021fb1f57e3fb8ac5a30a73de5868d6542a196fbf3fc47fb,
+R = 025e534768bafa3171b850bcccbfad82702adc69d90f9db32debe7afe7fdd06f1c,
+V = 0229bc145f45468201a47c3e62785503d006fa9be41cd5892a65002a7aef0e79cd,
+C = 0248d59ed28567a329f442051fb7e91069a136e68751c52d5e592693295ecc0e81,
+E = 104b7d4a22cd1cee0d853f5b3d0e4e9a14e5156201b92b4860bcd8a07423e7b0,
+T = b4a9bf92910036da6342cf59bb6b545e7faf8dd3affb4ff1223d1c1805de7884,
+U = 4e78b645d5dba4a43f1fd896f62ba089608c4410bb6478de9a2ca9323dd7b0dc,