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:18 UTC

[incubator-milagro-MPC] 02/05: Add GGN and GMR

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 50cc432b8c93e478272cb649264e96aa88bfb835
Author: Samuele Andreoli <sa...@yahoo.it>
AuthorDate: Fri Apr 16 14:03:19 2021 +0100

    Add GGN and GMR
---
 benchmark/bench_ggn.c                      | 225 ++++++++++++++++++++++
 benchmark/bench_gmr.c                      | 151 +++++++++++++++
 examples/example_ggn.c                     | 236 +++++++++++++++++++++++
 examples/example_gmr.c                     | 123 ++++++++++++
 include/amcl/ggn.h                         | 196 +++++++++++++++++++
 include/amcl/gmr.h                         | 108 +++++++++++
 python/amcl/core_utils.py                  | 123 +++++++++++-
 python/amcl/ggn.py                         |  26 +++
 python/amcl/gmr.py                         | 177 +++++++++++++++++
 python/benchmark/bench_gmr.py              |  65 +++++++
 python/benchmark/bench_schnorr.py          |   2 +-
 python/examples/example_gmr.py             |  71 +++++++
 python/test/test_gmr.py                    | 123 ++++++++++++
 src/ggn.c                                  | 161 ++++++++++++++++
 src/gmr.c                                  | 298 +++++++++++++++++++++++++++++
 test/smoke/test_ggn_smoke.c                | 226 ++++++++++++++++++++++
 test/smoke/test_gmr_smoke.c                |  91 +++++++++
 test/unit/CMakeLists.txt                   |   7 +
 test/unit/test_gg20_zkp_generator.c        |  86 +++++++++
 test/unit/test_gg20_zkp_octets.c           | 138 +++++++++++++
 test/unit/test_gg20_zkp_phase3_challenge.c | 119 ++++++++++++
 test/unit/test_gg20_zkp_phase3_commit.c    |  94 +++++++++
 test/unit/test_gg20_zkp_phase3_prove.c     | 112 +++++++++++
 test/unit/test_gg20_zkp_phase3_verify.c    | 120 ++++++++++++
 test/unit/test_gg20_zkp_phase6_challenge.c | 131 +++++++++++++
 test/unit/test_gg20_zkp_phase6_commit.c    | 110 +++++++++++
 test/unit/test_gg20_zkp_phase6_prove.c     | 112 +++++++++++
 test/unit/test_gg20_zkp_phase6_verify.c    | 143 ++++++++++++++
 test/unit/test_ggn.c                       | 155 +++++++++++++++
 test/unit/test_gmr_octets.c                | 104 ++++++++++
 test/unit/test_gmr_prove.c                 | 131 +++++++++++++
 test/unit/test_gmr_verify.c                | 144 ++++++++++++++
 testVectors/ggn/challenge.json             | 172 +++++++++++++++++
 testVectors/ggn/challenge.txt              | 160 ++++++++++++++++
 testVectors/gmr/prove.json                 |  82 ++++++++
 testVectors/gmr/prove.txt                  |  70 +++++++
 testVectors/gmr/verify.json                |  72 +++++++
 testVectors/gmr/verify.txt                 |  60 ++++++
 38 files changed, 4719 insertions(+), 5 deletions(-)

diff --git a/benchmark/bench_ggn.c b/benchmark/bench_ggn.c
new file mode 100644
index 0000000..6f6ffd7
--- /dev/null
+++ b/benchmark/bench_ggn.c
@@ -0,0 +1,225 @@
+/*
+    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 GGN Proof.
+ */
+
+#include "bench.h"
+#include "amcl/ggn.h"
+
+#define MIN_TIME 5.0
+#define MIN_ITERS 10
+
+// Primes for Paillier key
+char *P_hex = "c39f253734727ac925e786ec50abcf9b5bb46e1cba747342dee478c6efdb59d6c63c8495ab18e1b4c56e9bed152ad63681e0af18a6a21db1fe5faa9e7eae17e17013ccb3b4fbd4efb86a50b4b25fa081ccc90b9c22d455452fd0f7b878f36da06b82285fbdb0511e8a01eea7f79e4381cffb3b0e5f34755c086d51be5584200f";
+char *Q_hex = "d1f98d7be4e10120eec3f0225af8f33c8fbecc4bd846ac36bcf0bafedbc03bb6eb3f121c65a9c27b9931cda44eed1d4a5eeb32a3fe8f5643f01caebd75e37206b2c7debe83d9ce7197831e9fd5954eb61f1bcba4c1f64a3bf5cc73a488298998f4650cc82ac8a0fc17c0f698f09bb560c41341dd70d1ceef1ac7df7e286a3941";
+
+// BC setup
+char *PT_hex = "CA5F37B7C0DDF6530B30A41116588218DE95F1F36B807FD7C28E4C467EE3F35967BC01D28B71F8A627A353675A81C86A1FF03DCECAF1686891183FA317BA34A4A1148D40A89F1F3AC0C200511C6CFE02342CD75354C25A2E069886DD4FB73BD365660D163F1282B143119AB8F375A73875EC16B634F52593B73BC6D875F2D3EF";
+char *QT_hex = "C2FC545C1C803F6C7625FBC4ECF9355734D6B6058FD714816D3ECFB93F1F705C9CE90D4F8796A05148AB5ABC201F90889231CC6BF5F68ED15EE4D901F603930A280EEABF10C613BFCB67A816363C839EB902B02607EB48AB8325E2B72620D4D294A232803217090DFB50AF8C620D4679E77CE3053437ED518F4F68840DCF1AA3";
+char *ALPHA_hex = "1128dc85f9bbdde2826244bcefd0ec6668c19ee254b81bbbfc7575ec45922fc573567d45dc27fc659ec29e8909548a94f1d1ed280cfa49d75192c8cb04925884fa2e7ee9cce71bf5f699f73c07a9bcfbeed87aa4446099a940a03b6828a292319f3a4a71206bd902e9f99f6d6226344a14a0eb2b127b0e8925db779c21fa15ef 465212e8b5c0a8bd2fb3d171bfdad345d15676ad65f20447d8d28d9f7a3be092903966725054e94d95f7aff0ff854efeae993e9b97a2942fa7426cd1bfb843cd635c1058fb73d21ab7f9cc2319a307129f4f84369c01f0e29ea3716dfa692c56a3e4aae1437e9110464003af [...]
+char *B0_hex =    "544c8b0766c7490f7c6abfe0517709f3ab2c9b81fa8455cd8f99302dc58efa8d73318b078b31e49336d05caae1be491e620ec4893dfd50153c75d99d81970995c48b73cbb379097f69d55d4fb07de6124388b30c5718ccc5bd251945a1a51de335a7ebc4e226d7a60d82a7afc485845e849228de10211b2b8d7a759dd24ec4a4 57fdae3380b96fa8f3e12ba112a2ea07c1a74484ae7938e80afd4f17e17dddb7257fdcddfbcf2d2c51f350fb0c30a4eed76625039e5310da553ceaad1f9993c3b25bff1a657800308d4864199baeec8036945a9ac2bb429bd92d568b500f65268743179451623d45e7e25234 [...]
+
+// Paillier ciphertext and plaintext
+char* K_hex = "316e5fe3f60876f456e3c15e05e2d4ee79649e6a18008f08ff7a4c67bcdf5391";
+char* C_hex = "2373194729f056ef064cae6f98f5da88f0d39ad77884a04009fe3741bdc9354ae25fe1b0d42b6b6e0cb81e02a22f112fc1d8b3649344b08a6d10dff8988a806040f5b46ad971711f23b254da53d73ec1a4592327b07297cb6cce74855f7f5401efcf1eb7c5f2c344119321b2f3ee54da292e5e65930e1655f524194664f148bcf715267e08f489c1762473edaf47f233c123bc2b17015f12cef26c282ed13d91035ddac65b058f2e7b28718679785fe5d70d803d503bfe098f1cf4fb713051e90dab945c05eecbefa39dbe7660689f71a3cfcebe37f874435a56546a70cb0c2fb098ce6427fd525c6b6e12aaff954 [...]
+char* R_hex = "2174746e69b220c3ee9512b3e4da121866b7c656de08febb40e774ec90b459df9af8c22523e2816a23e33f134ede2fc35c49458f5f3a1e6c5b3578cc74b461e0b4a6ea83bdbe66a368692376d02bda4f80fbc1d1e9255c07aae2a2f8d7122ef00bd5fea48c8317124ebdba0545d9e43d87ee1f1b6117cefb484d8df4fb752cefb3d99af3ea070e2cb06bbf644aa781687c82f76e87324ba8fe0b9cd3b617f679081bc0e371cf6e3157edd82cc1b07f2629908847d109af71d9c802b1ca5e481a024968581dcbd2b4d668bfc7a0b338fe5f8801a79d6ba8852af580f5a72bcd2efb3a580ceeab2d5fc5587bd2c6b0e [...]
+
+// ECP for DLOG
+char* ECPR_hex  = "0274ec825739bb45d8e451dec0cb85baf356b931c754b5ccdef159389a27422b57";
+char* ECPRT_hex = "02a143a6f56e92af5e0ecaae7b8ae133750de551d6a00e9fa7c3e993deea0be12f";
+
+// RV for Range Proof
+char *RP_ALPHA_hex = "000000000000000000000000000000000000000000000000000000000000000000000034c0ff00df5f36f8800e0bcd51642ab69326cb3ad5cdfe042daa9750fbaffd56802f7f7b0a49846d15cf7b96450b88361ca4b4bb18bdfa094a03eed4015dc89a0899ef71379abe57612c55cb164728a2973d2788d2306cb49402badf67";
+char *BETA_hex     = "14acae6984a03a7927d162a3f94cd66dbd920936128e6a5c6f8d9a46291fb86c9b29a538d8c2313f38abfdfd531414aa3a54d0692de748fc0a65ec7ae5e1998b86ccc198e9f3e8135312f222c7df878c52ac09fc8675f6862c0b8ee9cb83850c829f2ab6d7fba66d55ec4bcadba53aa2577dd9a2007a89badc84645b635aa579132ff5c26911b613763130cc684def93bac53dbeccb81459db35feb1c2a6d217ab1941904d29b7029ee39bd784e86cb6567af7c2b8283cc45185475b9feae2395a74dfc646adb4a482f716caa98290f1a17dc371798c40e927ef561eda5213da0db93bcf3665455f3bc033 [...]
+char *GAMMA_hex    = "00000000000000000000000000000000000000000000000000000000000000000000005081190690c2aae12a2bf970d225865d08b9a469c675a3af3e34addb83f88f7d74bd1aaae27079b161e9926b7850ec939224fa5e8da08e7d1aa2276f605a55c519aa5ae20c9ee1f7fdb3d642d9c2655a4cbdd151d92ec18609f656ca70520001f396b52e8870068e327cef08bb5382be986b0de414bb25d1366562566f0b63ac459bbf4c5c427b5e59d4e384772497d4f78f867f003633b161bf1cc5f748a98f428774c9d661d5b3fd5f60e7b879b564ef4a2b9563b93131cc2a5a32211e4b34387a1b098ca80b5e [...]
+char *RHO_hex      = "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000033328f754ce65910a3d10719b59bd6f0ddd401a38381e98a76a44f34471f3d0d0c920237578a30f061c0f031d1907d3e6c5a687c5ef75473b4ee43e719c4b0e68229ab21dc3d573c005487380ee5d060f015e5f74db5575ff91e2859828cbd83bad80e37087ddb7a176b0f9012c02da70116213b2a37a82304062ed5d00f111bfcef8d821c2ed699fc33 [...]
+
+int main()
+{
+    int rc;
+
+    int iterations;
+    clock_t start;
+    double elapsed;
+
+    PAILLIER_private_key priv_key;
+    PAILLIER_public_key  pub_key;
+
+    BIT_COMMITMENT_priv priv_mod;
+    BIT_COMMITMENT_pub  pub_mod;
+
+    GGN_commitment co;
+    GGN_rv         rv;
+    GGN_proof      proof;
+
+    char c[2*FS_2048];
+    octet C = {0, sizeof(c), c};
+
+    char r[2*FS_2048];
+    octet R = {0, sizeof(r), r};
+
+    char k[MODBYTES_256_56];
+    octet K = {0, sizeof(k), k};
+
+    char e[MODBYTES_256_56];
+    octet E = {0, sizeof(e), e};
+
+    char p[HFS_2048];
+    octet P = {0, sizeof(p), p};
+
+    char q[HFS_2048];
+    octet Q = {0, sizeof(q), q};
+
+    char alpha[FS_2048];
+    octet ALPHA = {0, sizeof(alpha), alpha};
+
+    char b0[FS_2048];
+    octet B0 = {0, sizeof(b0), b0};
+
+    char ecpr_oct[MODBITS_SECP256K1];
+    octet ECPR_OCT = {0, sizeof(ecpr_oct), ecpr_oct};
+
+    char ecprt_oct[MODBITS_SECP256K1];
+    octet ECPRT_OCT = {0, sizeof(ecprt_oct), ecprt_oct};
+
+    char oct[FS_2048 + HFS_2048];
+    octet OCT = {0, sizeof(oct), oct};
+
+    // Leave these blank (but not empty!)
+    char id[32] = {0};
+    octet ID = {sizeof(id), sizeof(id), id};
+
+    char ad[32] = {0};
+    octet AD = {sizeof(ad), sizeof(ad), ad};
+
+    // Load paillier key
+    OCT_fromHex(&P, P_hex);
+    OCT_fromHex(&Q, Q_hex);
+
+    PAILLIER_KEY_PAIR(NULL, &P, &Q, &pub_key, &priv_key);
+
+    // Generate BC commitment modulus
+    OCT_fromHex(&P, PT_hex);
+    OCT_fromHex(&Q, QT_hex);
+    OCT_fromHex(&ALPHA, ALPHA_hex);
+    OCT_fromHex(&B0,    B0_hex);
+    BIT_COMMITMENT_setup(NULL, &priv_mod, &P, &Q, &ALPHA, &B0);
+
+    BIT_COMMITMENT_priv_to_pub(&pub_mod, &priv_mod);
+
+    // Load Paillier encryption values
+    OCT_fromHex(&K, K_hex);
+    OCT_fromHex(&R, R_hex);
+    OCT_fromHex(&C, C_hex);
+
+    // Load values for DLOG
+    OCT_fromHex(&ECPR_OCT, ECPR_hex);
+    OCT_fromHex(&ECPRT_OCT, ECPRT_hex);
+
+    // Load Random Values for Range Proof
+    OCT_fromHex(&OCT, RP_ALPHA_hex);
+    OCT_pad(&OCT, FS_2048);
+    FF_2048_fromOctet(rv.alpha, &OCT, FFLEN_2048);
+
+    OCT_fromHex(&OCT, BETA_hex);
+    FF_2048_fromOctet(rv.beta, &OCT, FFLEN_2048);
+
+    OCT_fromHex(&OCT, GAMMA_hex);
+    FF_2048_fromOctet(rv.gamma, &OCT, FFLEN_2048 + HFLEN_2048);
+
+    OCT_fromHex(&OCT, RHO_hex);
+    FF_2048_fromOctet(rv.rho, &OCT, FFLEN_2048 + HFLEN_2048);
+
+    print_system_info();
+
+    printf("Timing info\n");
+    printf("===========\n");
+
+    iterations = 0;
+    start = clock();
+    do
+    {
+        rc = GGN_commit(NULL, &priv_key, &pub_mod, &ECPR_OCT, &K, &rv, &co);
+        iterations++;
+        elapsed = (clock() - start) / (double)CLOCKS_PER_SEC;
+    }
+    while (elapsed < MIN_TIME || iterations < MIN_ITERS);
+
+    if (rc != GGN_OK)
+    {
+        printf("FAILURE GGN_commit: rc %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    elapsed = MILLISECOND * elapsed / iterations;
+    printf("\tGGN_commit\t%8d iterations\t", iterations);
+    printf("%8.2lf ms per iteration\n", elapsed);
+
+    iterations = 0;
+    start = clock();
+    do
+    {
+        GGN_challenge(&pub_key, &pub_mod, &ECPR_OCT, &ECPRT_OCT, &C, &co, &ID, &AD, &E);
+        iterations++;
+        elapsed = (clock() - start) / (double)CLOCKS_PER_SEC;
+    }
+    while (elapsed < MIN_TIME || iterations < MIN_ITERS);
+
+    elapsed = MICROSECOND * elapsed / iterations;
+    printf("\tGGN_challenge\t%8d iterations\t", iterations);
+    printf("%8.2lf us per iteration\n", elapsed);
+
+    iterations = 0;
+    start = clock();
+    do
+    {
+        GGN_prove(&priv_key, &K, &R, &rv, &E, &proof);
+        iterations++;
+        elapsed = (clock() - start) / (double)CLOCKS_PER_SEC;
+    }
+    while (elapsed < MIN_TIME || iterations < MIN_ITERS);
+
+    elapsed = MILLISECOND * elapsed / iterations;
+    printf("\tGGN_prove\t%8d iterations\t", iterations);
+    printf("%8.2lf ms per iteration\n", elapsed);
+
+    iterations = 0;
+    start = clock();
+    do
+    {
+        rc = GGN_verify(&pub_key, &priv_mod, &ECPR_OCT, &ECPRT_OCT, &C, &co, &E, &proof);
+        iterations++;
+        elapsed = (clock() - start) / (double)CLOCKS_PER_SEC;
+    }
+    while (elapsed < MIN_TIME || iterations < MIN_ITERS);
+
+    if (rc != GGN_OK)
+    {
+        printf("FAILURE GGN_verify: rc %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    elapsed = MILLISECOND * elapsed / iterations;
+    printf("\tGGN_verify\t%8d iterations\t", iterations);
+    printf("%8.2lf ms per iteration\n", elapsed);
+
+    exit(EXIT_SUCCESS);
+}
diff --git a/benchmark/bench_gmr.c b/benchmark/bench_gmr.c
new file mode 100644
index 0000000..66c4045
--- /dev/null
+++ b/benchmark/bench_gmr.c
@@ -0,0 +1,151 @@
+/*
+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 GMR ZKP of Square Freeness.
+ */
+
+#include "bench.h"
+#include "amcl/gmr.h"
+
+#define MIN_TIME 5.0
+#define MIN_ITERS 10
+
+char *ID_str = "unique_identifier_123";
+char *AD_hex = "d7d3155616778fb436a1eb2070892205";
+
+char *P_hex = "e008507e09c24d756280f3d94912fb9ac16c0a8a1757ee01a350736acfc7f65880f87eca55d6680253383fc546d03fd9ebab7d8fa746455180888cb7c17edf58d3327296468e5ab736374bc9a0fa02606ed5d3a4a5fb1677891f87fbf3c655c3e0549a86b17b7ddce07c8f73e253105e59f5d3ed2c7ba5bdf8495df40ae71a7f";
+char *Q_hex = "d344c02d8379387e773ab6fa6de6b92b395d5b7f0c41660778766a1ec4740468203bff2d05f263ff6f22740d4b2e799fd1fd2e2339e328c62d31eeecba30fd4892e0c1637e0f62b4de34f5d778a7dfd181b94464f3669751264a0058708a360552535653efc75e3035485e966df30a17146d692747e20b2f04f3877dd1f56dcf";
+
+int main()
+{
+    int rc;
+
+    int iterations;
+    clock_t start;
+    double elapsed;
+
+    char id[32];
+    octet ID = {0, sizeof(id), id};
+
+    char ad[32];
+    octet AD = {0, sizeof(ad), ad};
+
+    char p[HFS_2048] = {0};
+    octet P = {0, sizeof(p), p};
+
+    char q[HFS_2048];
+    octet Q = {0, sizeof(q), q};
+
+    char n[FS_2048];
+    octet N = {0, sizeof(n), n};
+
+    MODULUS_priv m;
+
+    GMR_proof Y;
+
+    char yoct[GMR_PROOF_SIZE];
+    octet Yoct = {0, sizeof(yoct), yoct};
+
+    // Load values
+    OCT_jstring(&ID, ID_str);
+    OCT_fromHex(&AD, AD_hex);
+
+    OCT_fromHex(&P, P_hex);
+    OCT_fromHex(&Q, Q_hex);
+
+    MODULUS_fromOctets(&m, &P, &Q);
+
+    FF_2048_toOctet(&N, m.n, FFLEN_2048);
+
+    print_system_info();
+
+    printf("Timing info\n");
+    printf("===========\n");
+
+    iterations = 0;
+    start = clock();
+    do
+    {
+        GMR_prove(&m, &ID, &AD, Y);
+        iterations++;
+        elapsed = (clock() - start) / (double)CLOCKS_PER_SEC;
+    }
+    while (elapsed < MIN_TIME || iterations < MIN_ITERS);
+
+    elapsed = MILLISECOND * elapsed / iterations;
+    printf("\tGMR_prove\t\t%8d iterations\t", iterations);
+    printf("%8.2lf ms per iteration\n", elapsed);
+
+    iterations = 0;
+    start = clock();
+    do
+    {
+        GMR_proof_toOctet(&Yoct, Y);
+        iterations++;
+        elapsed = (clock() - start) / (double)CLOCKS_PER_SEC;
+    }
+    while (elapsed < MIN_TIME || iterations < MIN_ITERS);
+
+    elapsed = MICROSECOND * elapsed / iterations;
+    printf("\tGMR_proof_toOctet\t%8d iterations\t", iterations);
+    printf("%8.2lf us per iteration\n", elapsed);
+
+    iterations = 0;
+    start = clock();
+    do
+    {
+        rc = GMR_proof_fromOctet(Y, &Yoct);
+        iterations++;
+        elapsed = (clock() - start) / (double)CLOCKS_PER_SEC;
+    }
+    while (elapsed < MIN_TIME || iterations < MIN_ITERS);
+
+    if (rc != GMR_OK)
+    {
+        printf("FAILURE GMR_proof_fromOctet: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    elapsed = MICROSECOND * elapsed / iterations;
+    printf("\tGMR_proof_fromOctet\t%8d iterations\t", iterations);
+    printf("%8.2lf us per iteration\n", elapsed);
+
+    iterations = 0;
+    start = clock();
+    do
+    {
+        rc = GMR_verify(&N, Y, &ID, &AD);
+        iterations++;
+        elapsed = (clock() - start) / (double)CLOCKS_PER_SEC;
+    }
+    while (elapsed < MIN_TIME || iterations < MIN_ITERS);
+
+    if (rc != GMR_OK)
+    {
+        printf("FAILURE GMR_verify: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    elapsed = MILLISECOND * elapsed / iterations;
+    printf("\tGMR_verify\t\t%8d iterations\t", iterations);
+    printf("%8.2lf ms per iteration\n", elapsed);
+
+    exit(EXIT_SUCCESS);
+}
diff --git a/examples/example_ggn.c b/examples/example_ggn.c
new file mode 100644
index 0000000..9970259
--- /dev/null
+++ b/examples/example_ggn.c
@@ -0,0 +1,236 @@
+/*
+    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.
+*/
+
+/* GGN Proof example */
+
+#include <string.h>
+#include "amcl/ggn.h"
+
+// Primes for Paillier key
+char *P_hex = "c39f253734727ac925e786ec50abcf9b5bb46e1cba747342dee478c6efdb59d6c63c8495ab18e1b4c56e9bed152ad63681e0af18a6a21db1fe5faa9e7eae17e17013ccb3b4fbd4efb86a50b4b25fa081ccc90b9c22d455452fd0f7b878f36da06b82285fbdb0511e8a01eea7f79e4381cffb3b0e5f34755c086d51be5584200f";
+char *Q_hex = "d1f98d7be4e10120eec3f0225af8f33c8fbecc4bd846ac36bcf0bafedbc03bb6eb3f121c65a9c27b9931cda44eed1d4a5eeb32a3fe8f5643f01caebd75e37206b2c7debe83d9ce7197831e9fd5954eb61f1bcba4c1f64a3bf5cc73a488298998f4650cc82ac8a0fc17c0f698f09bb560c41341dd70d1ceef1ac7df7e286a3941";
+
+// Safe primes for BC setup
+char *PT_hex = "CA5F37B7C0DDF6530B30A41116588218DE95F1F36B807FD7C28E4C467EE3F35967BC01D28B71F8A627A353675A81C86A1FF03DCECAF1686891183FA317BA34A4A1148D40A89F1F3AC0C200511C6CFE02342CD75354C25A2E069886DD4FB73BD365660D163F1282B143119AB8F375A73875EC16B634F52593B73BC6D875F2D3EF";
+char *QT_hex = "C2FC545C1C803F6C7625FBC4ECF9355734D6B6058FD714816D3ECFB93F1F705C9CE90D4F8796A05148AB5ABC201F90889231CC6BF5F68ED15EE4D901F603930A280EEABF10C613BFCB67A816363C839EB902B02607EB48AB8325E2B72620D4D294A232803217090DFB50AF8C620D4679E77CE3053437ED518F4F68840DCF1AA3";
+
+// Paillier ciphertext and plaintext
+char* K_hex = "316e5fe3f60876f456e3c15e05e2d4ee79649e6a18008f08ff7a4c67bcdf5391";
+char* C_hex = "2373194729f056ef064cae6f98f5da88f0d39ad77884a04009fe3741bdc9354ae25fe1b0d42b6b6e0cb81e02a22f112fc1d8b3649344b08a6d10dff8988a806040f5b46ad971711f23b254da53d73ec1a4592327b07297cb6cce74855f7f5401efcf1eb7c5f2c344119321b2f3ee54da292e5e65930e1655f524194664f148bcf715267e08f489c1762473edaf47f233c123bc2b17015f12cef26c282ed13d91035ddac65b058f2e7b28718679785fe5d70d803d503bfe098f1cf4fb713051e90dab945c05eecbefa39dbe7660689f71a3cfcebe37f874435a56546a70cb0c2fb098ce6427fd525c6b6e12aaff954 [...]
+char* R_hex = "2174746e69b220c3ee9512b3e4da121866b7c656de08febb40e774ec90b459df9af8c22523e2816a23e33f134ede2fc35c49458f5f3a1e6c5b3578cc74b461e0b4a6ea83bdbe66a368692376d02bda4f80fbc1d1e9255c07aae2a2f8d7122ef00bd5fea48c8317124ebdba0545d9e43d87ee1f1b6117cefb484d8df4fb752cefb3d99af3ea070e2cb06bbf644aa781687c82f76e87324ba8fe0b9cd3b617f679081bc0e371cf6e3157edd82cc1b07f2629908847d109af71d9c802b1ca5e481a024968581dcbd2b4d668bfc7a0b338fe5f8801a79d6ba8852af580f5a72bcd2efb3a580ceeab2d5fc5587bd2c6b0e [...]
+
+// ECP for DLOG
+char* ECPR_hex  = "0274ec825739bb45d8e451dec0cb85baf356b931c754b5ccdef159389a27422b57";
+char* ECPRT_hex = "02a143a6f56e92af5e0ecaae7b8ae133750de551d6a00e9fa7c3e993deea0be12f";
+
+int main()
+{
+    int rc;
+
+    PAILLIER_private_key priv_key;
+    PAILLIER_public_key  pub_key;
+
+    BIT_COMMITMENT_priv priv_mod;
+    BIT_COMMITMENT_pub  pub_mod;
+
+    GGN_commitment co;
+    GGN_rv         rv;
+    GGN_proof      proof;
+
+    char c[2*FS_2048];
+    octet C = {0, sizeof(c), c};
+
+    char r[2*FS_2048];
+    octet R = {0, sizeof(r), r};
+
+    char k[MODBYTES_256_56];
+    octet K = {0, sizeof(k), k};
+
+    char e[MODBYTES_256_56];
+    octet E = {0, sizeof(e), e};
+
+    char p[HFS_2048];
+    octet P = {0, sizeof(p), p};
+
+    char q[HFS_2048];
+    octet Q = {0, sizeof(q), q};
+
+    char id[32];
+    octet ID = {0, sizeof(id), id};
+
+    char ad[32];
+    octet AD = {0, sizeof(ad), ad};
+
+    char ecpr_oct[MODBITS_SECP256K1];
+    octet ECPR_OCT = {0, sizeof(ecpr_oct), ecpr_oct};
+
+    char ecprt_oct[MODBITS_SECP256K1];
+    octet ECPRT_OCT = {0, sizeof(ecprt_oct), ecprt_oct};
+
+    char z[FS_2048];
+    octet Z = {0, sizeof(z), z};
+
+    char u1[EFS_SECP256K1 + 1];
+    octet U1 = {0, sizeof(u1), u1};
+
+    char u2[FS_4096];
+    octet U2 = {0, sizeof(u2), u2};
+
+    char u3[FS_2048];
+    octet U3 = {0, sizeof(u3), u3};
+
+    char s1[HFS_4096];
+    octet S1 = {0, sizeof(s1), s1};
+
+    char s2[HFS_2048];
+    octet S2 = {0, sizeof(s2), s2};
+
+    char s3[FS_2048 + HFS_2048];
+    octet S3 = {0, sizeof(s3), s3};
+
+    // Deterministic RNG for testing
+    char seed[32] = {0};
+    csprng RNG;
+    RAND_seed(&RNG, 32, seed);
+
+    // Pseudorandom ID and AD
+    OCT_rand(&ID, &RNG, ID.len);
+    OCT_rand(&AD, &RNG, AD.len);
+
+    // Load paillier key
+    OCT_fromHex(&P, P_hex);
+    OCT_fromHex(&Q, Q_hex);
+
+    PAILLIER_KEY_PAIR(NULL, &P, &Q, &pub_key, &priv_key);
+
+    printf("Run GGN Proof\nParameters:\n");
+    printf("\tPaillier Key\n");
+    printf("\t\tP = ");
+    OCT_output(&P);
+    printf("\t\tQ = ");
+    OCT_output(&Q);
+
+    // Generate BC commitment modulus
+    OCT_fromHex(&P, PT_hex);
+    OCT_fromHex(&Q, QT_hex);
+    BIT_COMMITMENT_setup(&RNG, &priv_mod, &P, &Q, NULL, NULL);
+
+    BIT_COMMITMENT_priv_to_pub(&pub_mod, &priv_mod);
+
+    FF_2048_output(priv_mod.alpha, FFLEN_2048);
+    printf("\n");
+    FF_2048_output(priv_mod.b0, FFLEN_2048);
+
+    printf("\n\tBit Commitment Modulus\n");
+    printf("\t\tP = ");
+    OCT_output(&P);
+    printf("\t\tQ = ");
+    OCT_output(&Q);
+
+    // Load Paillier encryption values
+    OCT_fromHex(&K, K_hex);
+    OCT_fromHex(&R, R_hex);
+    OCT_fromHex(&C, C_hex);
+
+    printf("\n\tPaillier Input:\n");
+    printf("\t\tK = ");
+    OCT_output(&K);
+    printf("\t\tC = ");
+    OCT_output(&C);
+    printf("\t\tr = ");
+    OCT_output(&R);
+
+    // Load values for DLOG
+    OCT_fromHex(&ECPR_OCT, ECPR_hex);
+    OCT_fromHex(&ECPRT_OCT, ECPRT_hex);
+
+    printf("\n\tECP Input\n");
+    printf("\t\tR  =");
+    OCT_output(&ECPR_OCT);
+    printf("\t\tRt = ");
+    OCT_output(&ECPRT_OCT);
+
+    // Prover - commit to values for the proof and output
+    // the commitment to octets for transmission
+    rc = GGN_commit(&RNG, &priv_key, &pub_mod, &ECPR_OCT, &K, &rv, &co);
+    if (rc != GGN_OK)
+    {
+        printf("\nFAILURE GGN_commit: rc %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    GGN_commitment_toOctets(&Z, &U1, &U2, &U3, &co);
+
+    printf("\nCommitment Phase\n");
+    printf("\tGenerate Random Values:");
+    printf("\n\t\tALPHA = ");
+    FF_2048_output(rv.alpha, HFLEN_2048);
+    printf("\n\t\tBETA  = ");
+    FF_2048_output(rv.beta, FFLEN_2048);
+    printf("\n\t\tGAMMA = ");
+    FF_2048_output(rv.gamma, FFLEN_2048 + HFLEN_2048);
+    printf("\n\t\tRHO   = ");
+    FF_2048_output(rv.rho, FFLEN_2048 + HFLEN_2048);
+    printf("\n\n\tGenerate Commitment:\n");
+    printf("\t\tZ  = ");
+    OCT_output(&Z);
+    printf("\t\tU1 = ");
+    OCT_output(&U1);
+    printf("\t\tU2 = ");
+    OCT_output(&U2);
+    printf("\t\tU2 = ");
+    OCT_output(&U2);
+
+    // Prover - compute deterministic challenge
+    GGN_challenge(&pub_key, &pub_mod, &ECPR_OCT, &ECPRT_OCT, &C, &co, &ID, &AD, &E);
+
+    printf("\nCompute deterministic challenge\n");
+    printf("\t\tE = ");
+    OCT_output(&E);
+
+    // Prover - generate proof and output it to octets for transmission
+    GGN_prove(&priv_key, &K, &R, &rv, &E, &proof);
+    GGN_proof_toOctets(&S1, &S2, &S3, &proof);
+
+    printf("\nProof Phase\n");
+    printf("\t\tS1 = ");
+    OCT_output(&S1);
+    printf("\t\tS2 = ");
+    OCT_output(&S2);
+    printf("\t\tS3 = ");
+    OCT_output(&S3);
+
+    // Prover - clean random values
+    GGN_rv_kill(&rv);
+
+    // Verifier - compute deterministic challenge and verify proofs
+    GGN_challenge(&pub_key, &pub_mod, &ECPR_OCT, &ECPRT_OCT, &C, &co, &ID, &AD, &E);
+
+    printf("\nVerification\n");
+
+    rc = GGN_verify(&pub_key, &priv_mod, &ECPR_OCT, &ECPRT_OCT, &C, &co, &E, &proof);
+    if (rc == GGN_OK)
+    {
+        printf("\t\tSuccess!\n");
+    }
+    else
+    {
+        printf("\t\tFailure!\n");
+    }
+}
diff --git a/examples/example_gmr.c b/examples/example_gmr.c
new file mode 100644
index 0000000..4738e73
--- /dev/null
+++ b/examples/example_gmr.c
@@ -0,0 +1,123 @@
+/*
+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.
+*/
+
+/* Example of the GMR ZKP of Square Freeness*/
+
+#include "amcl/gmr.h"
+
+char *P_hex = "e008507e09c24d756280f3d94912fb9ac16c0a8a1757ee01a350736acfc7f65880f87eca55d6680253383fc546d03fd9ebab7d8fa746455180888cb7c17edf58d3327296468e5ab736374bc9a0fa02606ed5d3a4a5fb1677891f87fbf3c655c3e0549a86b17b7ddce07c8f73e253105e59f5d3ed2c7ba5bdf8495df40ae71a7f";
+char *Q_hex = "d344c02d8379387e773ab6fa6de6b92b395d5b7f0c41660778766a1ec4740468203bff2d05f263ff6f22740d4b2e799fd1fd2e2339e328c62d31eeecba30fd4892e0c1637e0f62b4de34f5d778a7dfd181b94464f3669751264a0058708a360552535653efc75e3035485e966df30a17146d692747e20b2f04f3877dd1f56dcf";
+
+int main()
+{
+    int rc;
+
+    char id[32];
+    octet ID = {0, sizeof(id), id};
+
+    char ad[32];
+    octet AD = {0, sizeof(ad), ad};
+
+    char p[HFS_2048] = {0};
+    octet P = {0, sizeof(p), p};
+
+    char q[HFS_2048];
+    octet Q = {0, sizeof(q), q};
+
+    char n[FS_2048];
+    octet N = {0, sizeof(n), n};
+
+    MODULUS_priv m;
+
+    GMR_proof Y;
+
+    char yoct[GMR_PROOF_SIZE];
+    octet Yoct = {0, sizeof(yoct), yoct};
+
+    // Deterministic RNG for testing
+    char seed[32] = {0};
+    csprng RNG;
+    RAND_seed(&RNG, 32, seed);
+
+    // Pseudorandom ID and AD
+    OCT_rand(&ID, &RNG, ID.len);
+    OCT_rand(&AD, &RNG, AD.len);
+
+    // Load RSA modulus
+    OCT_fromHex(&P, P_hex);
+    OCT_fromHex(&Q, Q_hex);
+
+    MODULUS_fromOctets(&m, &P, &Q);
+
+    FF_2048_toOctet(&N, m.n, FFLEN_2048);
+
+    printf("Prove Square Freeness for");
+    printf("\n\tP  = ");
+    FF_2048_output(m.p, HFLEN_2048);
+    printf("\n\tQ  = ");
+    FF_2048_output(m.q, HFLEN_2048);
+    printf("\n\tN  = ");
+    FF_2048_output(m.n, FFLEN_2048);
+    printf("\n\tID = ");
+    OCT_output(&ID);
+    printf("\tAD = ");
+    OCT_output(&AD);
+
+    // ZK Proof
+    GMR_prove(&m, &ID, &AD, Y);
+    GMR_proof_toOctet(&Yoct, Y);
+
+    printf("\nGenerate GMR Proof of Square Freeness\n");
+    printf("and encode it into an octet\n");
+    printf("Y = ");
+    OCT_output(&Yoct);
+
+    // Clear memory once the proof is generated
+    MODULUS_kill(&m);
+
+    // ZK Verify
+    printf("\nVerification\n");
+    printf("\tDecode the Proof from the octet:\n");
+
+    rc = GMR_proof_fromOctet(Y, &Yoct);
+    if (rc == GMR_OK)
+    {
+        printf("\t\tSuccess!\n");
+    }
+    else
+    {
+        printf("\t\tFailure!\n");
+        exit(EXIT_FAILURE);
+    }
+
+    printf("\tVerify the Proof:\n");
+
+    rc = GMR_verify(&N, Y, &ID, &AD);
+    if (rc == GMR_OK)
+    {
+        printf("\t\tSuccess!\n");
+    }
+    else
+    {
+        printf("\t\tFailure!\n");
+        exit(EXIT_FAILURE);
+    }
+
+    exit(EXIT_SUCCESS);
+}
\ No newline at end of file
diff --git a/include/amcl/ggn.h b/include/amcl/ggn.h
new file mode 100644
index 0000000..8c0b8e2
--- /dev/null
+++ b/include/amcl/ggn.h
@@ -0,0 +1,196 @@
+/*
+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 ggn.h
+ * @brief Gennaro, Goldfeder, Narayanan ZKP of consistency of a Paillier Ciphertext
+ *
+ */
+
+#ifndef GGN_H
+#define GGN_H
+
+#include "amcl/amcl.h"
+#include "amcl/paillier.h"
+#include "amcl/bit_commitment.h"
+#include "amcl/ecp_SECP256K1.h"
+#include "amcl/ecdh_SECP256K1.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define GGN_OK             0    /**< Proof successfully verified */
+#define GGN_INVALID_ECP    131  /**< Invalid ECP octet */
+
+/** \brief Secret random values for the GGN commitment */
+typedef BIT_COMMITMENT_rv GGN_rv;
+
+/** \brief Public commitment for the GGN Proof */
+typedef struct
+{
+    BIT_COMMITMENT_commitment c; /**< Commitment for the base ZKP */
+    ECP_SECP256K1 u1;            /**< Commitment for the DLOG knowledge proof */
+} GGN_commitment;
+
+/** \brief GGN Proof */
+typedef BIT_COMMITMENT_proof GGN_proof;
+
+/** \brief GGN Commitment Generation
+ *
+ *  Generate a commitment for the message M
+ *
+ *  <ol>
+ *  <li> \f$ \alpha \in_R [0, \ldots, q^3]\f$
+ *  <li> \f$ \beta  \in_R [0, \ldots, N]\f$
+ *  <li> \f$ \gamma \in_R [0, \ldots, q^{3}\tilde{N}]\f$
+ *  <li> \f$ \rho   \in_R [0, \ldots, q\tilde{N}]\f$
+ *  <li> \f$ z = h_1^{m}h_2^{\rho} \text{ }\mathrm{mod}\text{ }\tilde{N} \f$
+ *  <li> \f$ u1 = \alpha.R \f$
+ *  <li> \f$ u2 = g^{\alpha}\beta^{N} \text{ }\mathrm{mod}\text{ }N^2 \f$
+ *  <li> \f$ u3 = h_1^{\alpha}h_2^{\gamma} \text{ }\mathrm{mod}\text{ }\tilde{N} \f$
+ *  </ol>
+ *
+ *  @param RNG         csprng for random generation
+ *  @param key         Paillier key used to encrypt M
+ *  @param mod         Public BC modulus of the verifier
+ *  @param R           Public ECp, base of the DLOG
+ *  @param M           Message to prove knowledge and consistency
+ *  @param c           Destination commitment
+ *  @param rv          Random values associated to the commitment. If RNG is NULL this is read
+ *  @return            GGN_OK or GGN_INVALID_ECP if the octet R is not a valid ECp
+ */
+extern int GGN_commit(csprng *RNG, PAILLIER_private_key *key, BIT_COMMITMENT_pub *mod, octet *R, octet *M, GGN_rv *rv, GGN_commitment *c);
+
+/** \brief Deterministic Challenge generations for the GGN ZKP
+ *
+ *  Generate a challenge binding together public parameters and commitment
+ *
+ *  <ol>
+ *  <li> \f$ e = H( N | \tilde{N} | h_1 | h_2 | R | \tilde{R} | C | z | u1 | u2 | u3 | ID | AD ) \f$
+ *  </ol>
+ *
+ *  @param key         Public Paillier key of the prover
+ *  @param m           Public BC modulus of the verifier
+ *  @param R           Public ECp, base of the DLOG
+ *  @param Rt          Public ECp, DLOG
+ *  @param CT           Paillier Ciphertext to prove knowledge and range
+ *  @param c           Commitment of the prover
+ *  @param ID          Unique prover identifier
+ *  @param AD          Additional data to bind in the proof. Optional
+ *  @param E           Destination challenge
+ */
+extern void GGN_challenge(PAILLIER_public_key *key, BIT_COMMITMENT_pub *m, const octet *R, const octet *Rt, const octet *CT, GGN_commitment *c, const octet *ID, const octet *AD, octet *E);
+
+/** \brief Proof generation for Receiver ZKP with check
+ *
+ *  Generate a proof of knowledge of x, y and a range proof for x.
+ *  These values are the same as for the ZKP without check. The
+ *  knowledge of the DLOG can be verified using the value U in the
+ *  commitment
+ *
+ *  <ol>
+ *  <li> \f$ s_1 = ex + \alpha \f$
+ *  <li> \f$ s_2 = \beta r^e \text{ }\mathrm{mod}\text{ }N \f$
+ *  <li> \f$ s_3 = e\rho + \gamma \f$
+ *  </ol>
+ *
+ *  @param key         Private Paillier key of the prover
+ *  @param K           Message to prove knowledge and range
+ *  @param R           Random value used in the Paillier encryption
+ *  @param rv          Random values associated to the commitment
+ *  @param E           Generated challenge
+ *  @param p           Destination proof
+ */
+extern void GGN_prove(PAILLIER_private_key *key, octet *K, octet *R, GGN_rv *rv, octet *E, GGN_proof *p);
+
+/** \brief Verify a Proof for Receiver ZKP with check
+ *
+ *  Verify the proof of knowledge and range of x associated to C.
+ *  Additionally verify the knowledge of \f$ \tilda{R} = x.G \f{R} \f$
+ *
+ *  <ol>
+ *  <li> \f$ s_1 \stackrel{?}{\leq} q^3 \f$
+ *  <li> \f$ u_1 \stackrel{?}{=} s_1.R - e.\tilda{R} \f$
+ *  <li> \f$ u_2 \stackrel{?}{=} g^{s_1}s_2^{N}C^{-e} \text{ }\mathrm{mod}\text{ }N^2 \f$
+ *  <li> \f$ u_3 \stackrel{?}{=} h_1^{s_1}h_2^{s_3}z^{-e} \text{ }\mathrm{mod}\text{ }\tilde{N} \f$
+ *  </ol>
+ *
+ *  @param key         Public Paillier key of the prover
+ *  @param m           Private BC modulus of the verifier
+ *  @param R           Public ECp, base of the DLOG
+ *  @param Rt          Public ECp, DLOG
+ *  @param CT          Paillier Ciphertext to prove knowledge and range
+ *  @param c           Commitment of the prover
+ *  @param E           Generated challenge
+ *  @param p           Received proof
+ *  @return            GGN_OK if the proof is valid or an error code
+ */
+extern int GGN_verify(PAILLIER_public_key *key, BIT_COMMITMENT_priv *m, octet *R, octet *Rt, octet *CT, GGN_commitment *c, octet *E, GGN_proof *p);
+
+/** \brief Dump the commitment to octets
+ *
+ *  @param Z           Destination Octet for the z component of the commitment. FS_4096 long
+ *  @param U1          Destination Octet for the u1 component of the commitment. EGS_SECP256K1 + 1 long
+ *  @param U2          Destination Octet for the u2 component of the commitment. FS_2048 long
+ *  @param U3          Destination Octet for the u3 component of the commitment. FS_2048 long
+ *  @param c           Commitment to export
+ */
+extern void GGN_commitment_toOctets(octet *Z, octet *U1, octet *U2, octet *U3, GGN_commitment *c);
+
+/** \brief Read the commitments from octets
+ *
+ *  @param c           Destination Commitment
+ *  @param Z           Octet with the z component of the commitment
+ *  @param U1          Octet with the u1 component of the commitment
+ *  @param U2          Octet with the u2 component of the commitment
+ *  @param U3          Octet with the u3 component of the commitment
+ */
+extern int GGN_commitment_fromOctets(GGN_commitment *c, octet *Z, octet *U1, octet *U2, octet *U3);
+
+/** \brief Dump the proof to octets
+ *
+ *  @param S1          Destination Octet for the s1 component of the proof. HFS_2048 long
+ *  @param S2          Destination Octet for the s2 component of the proof. FS_2048 long
+ *  @param S3          Destination Octet for the s3 component of the proof. FS_2048 + HFS_2048 long
+ *  @param p           Proof to export
+ */
+extern void GGN_proof_toOctets(octet *S1, octet *S2, octet *S3, GGN_proof *p);
+
+/** \brief Read the proof from octets
+ *
+ *  @param p           Destination Proof
+ *  @param S1          Octet with the s1 component of the proof
+ *  @param S2          Octet with the s2 component of the proof
+ *  @param S3          Octet with the s3 component of the proof
+ */
+extern void GGN_proof_fromOctets(GGN_proof *p, octet *S1, octet *S2, octet *S3);
+
+/** \brief Clean the memory containing the random values
+ *
+ *   @param rv         Random values to clean
+ */
+extern void GGN_rv_kill(GGN_rv *rv);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
\ No newline at end of file
diff --git a/include/amcl/gmr.h b/include/amcl/gmr.h
new file mode 100644
index 0000000..0c361a5
--- /dev/null
+++ b/include/amcl/gmr.h
@@ -0,0 +1,108 @@
+/*
+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 gmr.h
+ * @brief Gennaro, Micciancio, Rabin ZKP for the Square Free language
+ *
+ */
+
+#ifndef GMR_H
+#define GMR_H
+
+#include "amcl/amcl.h"
+#include "amcl/modulus.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define GMR_OK   0            /**< Proof successfully verified */
+#define GMR_FAIL 111          /**< Invalid proof */
+#define GMR_INVALID_PROOF 112 /**< Invalid proof bounds */
+
+#define GMR_PROOF_ITERS 10                        /**< Iterations necessary for the Proof, n */
+#define GMR_PROOF_SIZE  GMR_PROOF_ITERS * FS_2048 /**< Length of the Proof in bytes */
+
+/*! \brief Holds the values for each iteration of the protocol */
+typedef BIG_1024_58 GMR_proof[GMR_PROOF_ITERS][FFLEN_2048];
+
+/*! \brief Generate the GMR Proofs
+ *
+ *  Generate the proofs \f$ Y_i \f$ for the pseudorandom challenges
+ *  computed from N, ID, AD
+ *
+ *  <ol>
+ *  <li> For each \f$ i = 0, \ldots, n-1 \f$
+ *  <li> \f$ X_i = H(N, ID, AD, I2OSP(i), I2OSP(k)) \f$
+ *  <li>
+ *  <li> \f$ M = N^(-1) mod \phi(N) \f$
+ *  <li> \f$ Y_i = X_i^M mod N \f$
+ *  </ol>
+ *
+ *  @param  m           Private Modulus to prove Square Freeness
+ *  @param  ID          Prover unique identifier
+ *  @param  AD          Additional data to bind in the proof. Optional
+ *  @param  Y           Destination GMR proof
+ */
+extern void GMR_prove(MODULUS_priv *m, const octet *ID, const octet *AD, GMR_proof Y);
+
+/*! \brief Verify the GMR Proofs
+ *
+ *  Verify the proofs \f$ Y_i \f$ against the pseudorandom challenges
+ *  computed from N, ID, AD
+ *
+ *  <ol>
+ *  <li> For each \f$ i = 0, \ldots, n-1 \f$
+ *  <li> \f$ X_i = H(N, ID, AD, I2OSP(i), I2OSP(k)) \f$
+ *  <li>
+ *  <li> \f$ X_i = Y_i^N mod N \f$
+ *  </ol>
+ *
+ *  @param  N           Public RSA Modulus
+ *  @param  Y           GMR Proof
+ *  @param  ID          Prover unique identifier
+ *  @param  AD          Additional data to bind in the proof. Optional
+ *  @return             GMR_OK if the proof is valid or aNn error code
+ */
+extern int GMR_verify(octet *N, GMR_proof Y, const octet *ID, const octet *AD);
+
+/*! \brief Encode a GMR Proof into an octet
+ *
+ * @param O      Destination Octet
+ * @param p      Source proof
+ */
+extern void GMR_proof_toOctet(octet *O, GMR_proof p);
+
+/*! \brief Decode an octet into a GMR Proof
+ *
+ * @param p      Destination proof. Must be at least GMR_PROOF_SIZE bytes long
+ * @param O      Source Octet
+ * @return       GMR_OK if the octet is valid or an error code
+ */
+extern int GMR_proof_fromOctet(GMR_proof p, octet *O);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/python/amcl/core_utils.py b/python/amcl/core_utils.py
index cfad037..0f5b2d4 100644
--- a/python/amcl/core_utils.py
+++ b/python/amcl/core_utils.py
@@ -28,8 +28,34 @@ import platform
 
 _ffi = cffi.FFI()
 _ffi.cdef("""
-typedef long unsigned int BIG_512_60[9];
-typedef long unsigned int BIG_1024_58[18];
+// Necessary typedefs for milagro-crypto-c
+typedef signed int sign32;
+
+#define NLEN_256_56 5
+#define NLEN_512_60 9
+#define NLEN_1024_58 18
+
+typedef long unsigned int BIG_256_56[NLEN_256_56];
+typedef long unsigned int BIG_512_60[NLEN_512_60];
+typedef long unsigned int BIG_1024_58[NLEN_1024_58];
+
+#define HFLEN_2048 1
+#define FFLEN_2048 2
+#define HFLEN_4096 4
+#define FFLEN_4096 8
+
+typedef struct
+{
+    BIG_256_56 g;
+    sign32 XES;
+} FP_SECP256K1;
+
+typedef struct
+{
+    FP_SECP256K1 x;
+    FP_SECP256K1 y;
+    FP_SECP256K1 z;
+} ECP_SECP256K1;
 
 typedef struct {
 unsigned int ira[21];  /* random number...   */
@@ -50,6 +76,17 @@ extern void RAND_seed(csprng *R,int n,char *b);
 extern void RAND_clean(csprng *R);
 extern void OCT_clear(octet *O);
 extern void generateRandom(csprng* RNG, octet* randomValue);
+
+typedef struct
+{
+    BIG_1024_58 p[HFLEN_2048];
+    BIG_1024_58 q[HFLEN_2048];
+    BIG_1024_58 invpq[HFLEN_2048];
+    BIG_1024_58 n[FFLEN_2048];
+} MODULUS_priv;
+
+void MODULUS_fromOctets(MODULUS_priv *m, octet *P, octet *Q);
+void MODULUS_kill(MODULUS_priv *m);
 """)
 
 if (platform.system() == 'Windows'):
@@ -107,7 +144,7 @@ def make_octet(length, value=None):
     """
     oct_ptr = _ffi.new("octet*")
     if value:
-        val = _ffi.new("char [%s]" % len(value), value)
+        val = _ffi.new(f"char [{len(value)}]", value)
         oct_ptr.val = val
         oct_ptr.max = len(value)
         oct_ptr.len = len(value)
@@ -115,7 +152,7 @@ def make_octet(length, value=None):
         val = _ffi.new("char []", length)
         oct_ptr.val = val
         oct_ptr.max = length
-        oct_ptr.len = length
+        oct_ptr.len = 0
     return oct_ptr, val
 
 
@@ -135,6 +172,80 @@ def clear_octet(octet):
     _libamcl_core.OCT_clear(octet)
 
 
+def make_empty_octets(n, length):
+    """ Generate an n-array of empty octets of the specified length
+
+    Generate an array of empty octets, or fill them with the values.
+
+    If values is specified it MUST be a list of n strings
+
+    Args::
+        n      : Length of the octets array
+        length : Length of the octets to create
+
+    Returns::
+        oct_ptr : pointer to the octet array
+        vals    : list with the data associated to the octets to prevent garbage collection
+   """
+    oct_ptr = _ffi.new(f"octet [{n}]")
+
+    vals = []
+
+    for i in range(n):
+        val = _ffi.new("char []", length)
+
+        oct_ptr[i].val = val
+        oct_ptr[i].max = length
+        oct_ptr[i].len = 0
+
+        vals.append(val)
+
+    return oct_ptr, vals
+
+
+def make_octets(values):
+    """ Generate an n-array of octets from the given values
+
+    Generate an array of empty octets, or fill them with the values.
+
+    Args::
+        values : Values to fill the octets
+
+    Return::
+        oct_ptr : pointer to the octet array
+        vals    : list with the data associated to the octets to prevent garbage collection
+   """
+    oct_ptr = _ffi.new(f"octet [{len(values)}]")
+
+    vals = []
+
+    for i, v in enumerate(values):
+        length = len(v)
+
+        val = _ffi.new(f"char [{length}]", v)
+
+        oct_ptr[i].val = val
+        oct_ptr[i].max = length
+        oct_ptr[i].len = length
+
+        vals.append(val)
+
+    return oct_ptr, vals
+
+
+def clear_octets(octets, n):
+    """ Clear an octet array
+
+    Empty the octets in the array and zero out the underlying memory
+
+    Args::
+
+        octets : array of octets to clear
+    """
+    for i in range(n):
+        _libamcl_core.OCT_clear(_ffi.addressof(octets, i))
+
+
 def create_csprng(seed):
     """Make a Cryptographically secure pseudo-random number generator instance
 
@@ -199,6 +310,10 @@ def generate_random(rng, length):
     random_value1, random_value1_val = make_octet(length)
     _ = random_value1_val # Suppress warning
 
+    # Set length of random value to tell the generateRandom
+    # how long the random octet needs to be
+    random_value1.len = length
+
     _libamcl_core.generateRandom(rng, random_value1)
 
     random_value = to_str(random_value1)
diff --git a/python/amcl/ggn.py b/python/amcl/ggn.py
new file mode 100644
index 0000000..2b3ff41
--- /dev/null
+++ b/python/amcl/ggn.py
@@ -0,0 +1,26 @@
+#!/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.
+"""
+
+"""
+
+This module use cffi to access the c functions in the amcl_mpc library.
+
+"""
\ No newline at end of file
diff --git a/python/amcl/gmr.py b/python/amcl/gmr.py
new file mode 100644
index 0000000..9cbcdec
--- /dev/null
+++ b/python/amcl/gmr.py
@@ -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.
+"""
+
+"""
+
+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("""
+#define GMR_n_iters 10
+
+typedef BIG_1024_58 GMR_proof[GMR_n_iters][FFLEN_2048];
+
+void GMR_prove(MODULUS_priv *m, const octet *ID, const octet *AD, GMR_proof Y);
+int GMR_verify(octet *N, GMR_proof Y, const octet *ID, const octet *AD);
+void GMR_proof_toOctet(octet *O, GMR_proof p);
+int GMR_proof_fromOctet(GMR_proof p, octet *O);
+""")
+
+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
+FS_2048 = 256               # Size of an FF_2048 in bytes
+HFS_2048 = 128              # Half-size of an FF_2048 in bytes
+
+SHA256 = 32                 # Chosen hash function size in bytes
+
+OK            = 0           # Proof successfully verified
+FAIL          = 111         # Invalid proof
+INVALID_PROOF = 112         # Invalid proof bounds */
+
+PROOF_SIZE = 10 * FS_2048   # 10 Iterations are necessary for the GMR proof
+
+
+def prove(p, q, ID, AD=None):
+    """ Generate GMR Square Freeness Proof of n = p*q
+
+    Args::
+        p  : First prime factor of n. HFS_2048 bytes long
+        q  : Second prime factor of n. HFS_2048 bytes long
+        ID : Unique identifier of the prover
+        AD : Additional data to bind in the proof. Optional
+
+    Returns::
+        y  : GMR Proof of Square Freeness of n
+
+    Raises::
+
+    """
+
+    if AD is None:
+        ad_oct = _ffi.NULL
+    else:
+        ad_oct, ad_val = core_utils.make_octet(None, AD)
+        _ = ad_val # Suppress warning
+
+    p_oct, p_val   = core_utils.make_octet(None, p)
+    q_oct, q_val   = core_utils.make_octet(None, q)
+    id_oct, id_val = core_utils.make_octet(None, ID)
+    _ = p_val, q_val, id_val # Suppress warnings
+
+    y = _ffi.new('GMR_proof')
+
+    modulus = _ffi.new('MODULUS_priv*')
+
+    _libamcl_mpc.MODULUS_fromOctets(modulus, p_oct, q_oct)
+    _libamcl_mpc.GMR_prove(modulus, id_oct, ad_oct, y)
+
+    # Clear memory
+    _libamcl_mpc.MODULUS_kill(modulus)
+    core_utils.clear_octet(p_oct)
+    core_utils.clear_octet(q_oct)
+
+    return y
+
+
+def verify(n, y, ID, AD=None):
+    """ Verify GMR Proof of Square Freeness of y
+
+    Args::
+        n  : public modulus
+        y  : Proof of Square Freeness
+        ID : Unique identifier of the prover
+        AD : Additional data to bind in the challenge. Optional
+
+    Returns::
+        rc : OK if the verification is successful or an error code
+
+    Raises::
+
+    """
+
+    if AD is None:
+        ad_oct = _ffi.NULL
+    else:
+        ad_oct, ad_val = core_utils.make_octet(None, AD)
+        _ = ad_val # Suppress warning
+
+    n_oct, n_val   = core_utils.make_octet(None, n)
+    id_oct, id_val = core_utils.make_octet(None, ID)
+    _ = n_val, id_val # Suppress warning
+
+    rc = _libamcl_mpc.GMR_verify(n_oct, y, id_oct, ad_oct)
+
+    return rc
+
+
+def proof_to_octet(p):
+    """ Write a GMR Proof to a string
+
+    Args::
+        p     : GMR Proof
+
+    Returns::
+        p_str : string encoding the GMR Proof
+
+    Raises::
+
+    """
+
+    p_oct, _ = core_utils.make_octet(PROOF_SIZE)
+
+    _libamcl_mpc.GMR_proof_toOctet(p_oct, p)
+
+    return core_utils.to_str(p_oct)
+
+
+def proof_from_octet(p_str):
+    """ Read a GMR Proof from a string
+
+    Args::
+        p_str : string encoding the GMR Proof
+
+    Returns::
+        p     : GMR Proof
+        rc    : OK or an error code
+
+    Raises::
+
+    """
+
+    p_oct, _ = core_utils.make_octet(None, p_str)
+
+    p = _ffi.new('GMR_proof')
+
+    rc = _libamcl_mpc.GMR_proof_fromOctet(p, p_oct)
+
+    if rc != OK:
+        return _ffi.NULL, rc
+
+    return p, rc
diff --git a/python/benchmark/bench_gmr.py b/python/benchmark/bench_gmr.py
new file mode 100755
index 0000000..7201988
--- /dev/null
+++ b/python/benchmark/bench_gmr.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, gmr
+
+
+p_hex = "e008507e09c24d756280f3d94912fb9ac16c0a8a1757ee01a350736acfc7f65880f87eca55d6680253383fc546d03fd9ebab7d8fa746455180888cb7c17edf58d3327296468e5ab736374bc9a0fa02606ed5d3a4a5fb1677891f87fbf3c655c3e0549a86b17b7ddce07c8f73e253105e59f5d3ed2c7ba5bdf8495df40ae71a7f"
+q_hex = "d344c02d8379387e773ab6fa6de6b92b395d5b7f0c41660778766a1ec4740468203bff2d05f263ff6f22740d4b2e799fd1fd2e2339e328c62d31eeecba30fd4892e0c1637e0f62b4de34f5d778a7dfd181b94464f3669751264a0058708a360552535653efc75e3035485e966df30a17146d692747e20b2f04f3877dd1f56dcf"
+n_hex = "b8e304bb5468c17ccd3994d2c5946d5033d58853123fe43b9cf9d95315eac9f8797a31737cc5804d9273d83de0a5cc8614737b439348f99d3698071ef686b97d89543569078c1f392cbc6a7d37776139bbee82325d97542e78a35cd545feb86ebbf830016f0aedb920b5c69c829e3cfaaaa774cf44722d2b668fdaa05c20dd1dbf156abfd4a52953947fd46abaf5150dd4f4ed0d28660d0f13e003bc7428c13ad92d4bafd6cb8f60a4790d00931306dda5edf191a3e9dd3db7862d281e14e587b3e907a3b0447ef1e4d6335d097ce6fe10016e5d6731d634fecae718aade2fd3423d935da7ecdb33e219e37133b47c01186 [...]
+
+
+if __name__ == "__main__":
+    ID = b'unique_identifier'
+    AD = b'additional_data'
+
+    p = bytes.fromhex(p_hex)
+    q = bytes.fromhex(q_hex)
+    n = bytes.fromhex(n_hex)
+
+    # Generate quantities for benchmark
+    y = gmr.prove(p, q, ID, AD=AD)
+
+    y_str = gmr.proof_to_octet(y)
+    y, rc = gmr.proof_from_octet(y_str)
+    assert rc == gmr.OK, "Error setting up proof_from_octet"
+
+    rc = gmr.verify(n, y, ID, AD=AD)
+    assert rc == gmr.OK, "Error setting up verify"
+
+    # Run benchmark
+    fncall = lambda: gmr.prove(p, q, ID, AD=AD)
+    time_func("prove           ", fncall)
+
+    fncall = lambda: gmr.verify(n, y, ID, AD=AD)
+    time_func("verify          ", fncall)
+
+    fncall = lambda: gmr.proof_to_octet(y)
+    time_func("proof_to_octet  ", fncall, unit='us')
+
+    fncall = lambda: gmr.proof_from_octet(y_str)
+    time_func("proof_from_octet", fncall, unit='us')
diff --git a/python/benchmark/bench_schnorr.py b/python/benchmark/bench_schnorr.py
index e70e68c..976b2c7 100755
--- a/python/benchmark/bench_schnorr.py
+++ b/python/benchmark/bench_schnorr.py
@@ -31,7 +31,7 @@ x_hex = "fab4ce512dff74bd9c71c89a14de5b877af45dca0329ee3fcb72611c0784fef3"
 V_hex = "032cf4b348c9d00718f01ed98923e164df53b5e8bc4c2250662ed2df784e1784f4"
 
 ID = b"unique_user_identifier"
-AD_hex = "d7d3155616778fb436a1eb2070892205" 
+AD_hex = "d7d3155616778fb436a1eb2070892205"
 
 if __name__ == "__main__":
     r  = bytes.fromhex(r_hex)
diff --git a/python/examples/example_gmr.py b/python/examples/example_gmr.py
new file mode 100755
index 0000000..588014e
--- /dev/null
+++ b/python/examples/example_gmr.py
@@ -0,0 +1,71 @@
+#!/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
+
+sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
+
+from amcl import core_utils, gmr
+
+
+p_hex = "e008507e09c24d756280f3d94912fb9ac16c0a8a1757ee01a350736acfc7f65880f87eca55d6680253383fc546d03fd9ebab7d8fa746455180888cb7c17edf58d3327296468e5ab736374bc9a0fa02606ed5d3a4a5fb1677891f87fbf3c655c3e0549a86b17b7ddce07c8f73e253105e59f5d3ed2c7ba5bdf8495df40ae71a7f"
+q_hex = "d344c02d8379387e773ab6fa6de6b92b395d5b7f0c41660778766a1ec4740468203bff2d05f263ff6f22740d4b2e799fd1fd2e2339e328c62d31eeecba30fd4892e0c1637e0f62b4de34f5d778a7dfd181b94464f3669751264a0058708a360552535653efc75e3035485e966df30a17146d692747e20b2f04f3877dd1f56dcf"
+n_hex = "b8e304bb5468c17ccd3994d2c5946d5033d58853123fe43b9cf9d95315eac9f8797a31737cc5804d9273d83de0a5cc8614737b439348f99d3698071ef686b97d89543569078c1f392cbc6a7d37776139bbee82325d97542e78a35cd545feb86ebbf830016f0aedb920b5c69c829e3cfaaaa774cf44722d2b668fdaa05c20dd1dbf156abfd4a52953947fd46abaf5150dd4f4ed0d28660d0f13e003bc7428c13ad92d4bafd6cb8f60a4790d00931306dda5edf191a3e9dd3db7862d281e14e587b3e907a3b0447ef1e4d6335d097ce6fe10016e5d6731d634fecae718aade2fd3423d935da7ecdb33e219e37133b47c01186 [...]
+
+
+if __name__ == "__main__":
+    ID = b'unique_identifier'
+    AD = b'additional_data'
+
+    p = bytes.fromhex(p_hex)
+    q = bytes.fromhex(q_hex)
+    n = bytes.fromhex(n_hex)
+
+    print("Example GMR Square Freeness ZKP")
+    print("\tID = {}".format(ID.decode('utf-8')))
+    print("\tAD = {}".format(AD.decode('utf-8')))
+    print("\tP  = {}".format(p.hex()))
+    print("\tQ  = {}".format(q.hex()))
+    print("\tN  = {}".format(n.hex()))
+    print("")
+
+    print("Prove n = p*q is Square Free")
+    y = gmr.prove(p, q, ID, AD=AD)
+    y_str = gmr.proof_to_octet(y)
+
+    print("\tY = {}".format(y_str.hex()))
+    print("")
+
+    print("Verify GMR Proof")
+    y, rc = gmr.proof_from_octet(y_str)
+
+    if rc != gmr.OK:
+        print("\tInvalid Proof Format")
+        sys.exit(1)
+
+    rc = gmr.verify(n, y, ID, AD=AD)
+
+    if rc == gmr.OK:
+        print("\tSuccess")
+    else:
+        print("\tFailure")
+        sys.exit(1)
diff --git a/python/test/test_gmr.py b/python/test/test_gmr.py
new file mode 100755
index 0000000..a2606ca
--- /dev/null
+++ b/python/test/test_gmr.py
@@ -0,0 +1,123 @@
+#!/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 json
+import unittest
+
+sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
+
+from amcl import core_utils, gmr
+
+
+p_hex  = "e008507e09c24d756280f3d94912fb9ac16c0a8a1757ee01a350736acfc7f65880f87eca55d6680253383fc546d03fd9ebab7d8fa746455180888cb7c17edf58d3327296468e5ab736374bc9a0fa02606ed5d3a4a5fb1677891f87fbf3c655c3e0549a86b17b7ddce07c8f73e253105e59f5d3ed2c7ba5bdf8495df40ae71a7f"
+q_hex  = "d344c02d8379387e773ab6fa6de6b92b395d5b7f0c41660778766a1ec4740468203bff2d05f263ff6f22740d4b2e799fd1fd2e2339e328c62d31eeecba30fd4892e0c1637e0f62b4de34f5d778a7dfd181b94464f3669751264a0058708a360552535653efc75e3035485e966df30a17146d692747e20b2f04f3877dd1f56dcf"
+id_str = "unique_identifier"
+ad_hex = "d7d3155616778fb436a1eb2070892205"
+
+
+def process_tv(vector):
+    for key, val in vector.items():
+        if key == "TEST":
+            vector[key] = val
+        elif not val:
+            vector[key] = None
+        else:
+            vector[key] = bytes.fromhex(val)
+
+    return vector
+
+
+class TestProve(unittest.TestCase):
+    """ Test GMR SF Proof """
+
+    def setUp(self):
+        with open("gmr/prove.json", "r") as f:
+            self.tv = json.load(f)
+
+        for vector in self.tv:
+            process_tv(vector)
+
+    def test(self):
+        """ test using test vector """
+
+        for vector in self.tv:
+            p  = vector['P']
+            q  = vector['Q']
+            ID = vector['ID']
+            AD = vector['AD']
+
+            y = gmr.prove(p, q, ID, AD=AD)
+            y_oct = gmr.proof_to_octet(y)
+
+            self.assertEqual(y_oct, vector['Y'])
+
+
+class TestVerify(unittest.TestCase):
+    """ Test GMR SF Verification """
+
+    def setUp(self):
+        with open("gmr/verify.json", "r") as f:
+            self.tv = json.load(f)
+
+        for vector in self.tv:
+            process_tv(vector)
+
+    def test(self):
+        """ test using test vector """
+
+        for vector in self.tv:
+            n  = vector['N']
+            ID = vector['ID']
+            AD = vector['AD']
+
+            y, rc = gmr.proof_from_octet(vector['Y'])
+            self.assertEqual(rc, gmr.OK)
+
+            rc = gmr.verify(n, y, ID, AD=AD)
+            self.assertEqual(rc, gmr.OK)
+
+
+class TestOctets(unittest.TestCase):
+    """ Test GMR octet functions """
+
+    def setUp(self):
+        with open("gmr/verify.json", "r") as f:
+            self.tv = json.load(f)
+
+        for vector in self.tv:
+            process_tv(vector)
+
+    def test(self):
+        """ test using test vector """
+
+        for vector in self.tv:
+            y, rc = gmr.proof_from_octet(vector['Y'])
+            self.assertEqual(rc, gmr.OK)
+
+            y_str = gmr.proof_to_octet(y)
+            self.assertEqual(y_str, vector['Y'])
+
+
+if __name__ == '__main__':
+    # Run tests
+    unittest.main()
diff --git a/src/ggn.c b/src/ggn.c
new file mode 100644
index 0000000..b187846
--- /dev/null
+++ b/src/ggn.c
@@ -0,0 +1,161 @@
+/*
+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 ggn.c
+ * @brief High level wrapping for the GGN proof based on the Bit Commitment proofs
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "amcl/hash_utils.h"
+#include "amcl/ggn.h"
+
+int GGN_commit(csprng *RNG, PAILLIER_private_key *key, BIT_COMMITMENT_pub *mod, octet *R, octet *M,  GGN_rv *rv, GGN_commitment *c)
+{
+    // Read base ECp for DLOG commitment
+    if (ECP_SECP256K1_fromOctet(&(c->u1), R) != 1)
+    {
+        return GGN_INVALID_ECP;
+    }
+
+    /* Commitment for the base Paillier plaintext proof */
+    BIT_COMMITMENT_commit(RNG, key, mod, M, (BIT_COMMITMENT_rv*)rv, (BIT_COMMITMENT_commitment*)c);
+
+    /* Commitment for the additional DLOG proof */
+    BIT_COMMITMENT_ECP_commit(&(c->u1), rv->alpha);
+
+    return GGN_OK;
+}
+
+void GGN_challenge(PAILLIER_public_key *key, BIT_COMMITMENT_pub *m, const octet *R, const octet *Rt, const octet *CT, GGN_commitment *c, const octet *ID, const octet *AD, octet *E)
+{
+    hash256 sha;
+
+    char oct[EFS_SECP256K1 + 1];
+    octet OCT = {0, sizeof(oct), oct};
+
+    BIG_256_56 q;
+    BIG_256_56 t;
+
+    HASH256_init(&sha);
+
+    /* Bind to public parameters */
+    BIT_COMMITMENT_hash_params(&sha, key, m);
+
+    /* Bind to proof input */
+    HASH_UTILS_hash_oct(&sha, CT);
+    HASH_UTILS_hash_oct(&sha, R);
+    HASH_UTILS_hash_oct(&sha, Rt);
+
+    /* Bind to proof commitment */
+    BIT_COMMITMENT_hash_commitment(&sha, (BIT_COMMITMENT_commitment*)&(c->c));
+
+    ECP_SECP256K1_toOctet(&OCT, &(c->u1), true);
+    HASH_UTILS_hash_oct(&sha, &OCT);
+
+    /* 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 GGN_prove(PAILLIER_private_key *key, octet *K, octet *R, GGN_rv *rv, octet *E, GGN_proof *p)
+{
+    BIT_COMMITMENT_prove(key, K, R, (BIT_COMMITMENT_rv*)rv, E, (BIT_COMMITMENT_proof*)p);
+}
+
+int GGN_verify(PAILLIER_public_key *key, BIT_COMMITMENT_priv *m, octet *R, octet *Rt, octet *CT, GGN_commitment *c, octet *E, GGN_proof *p)
+{
+    int rc;
+
+    ECP_SECP256K1 ECPR;
+    ECP_SECP256K1 ECPRT;
+
+    // Terminate early in case of invalid input
+    rc = ECP_SECP256K1_fromOctet(&ECPR, R);
+    if (rc != 1)
+    {
+        return GGN_INVALID_ECP;
+    }
+
+    rc = ECP_SECP256K1_fromOctet(&ECPRT, Rt);
+    if (rc != 1)
+    {
+        return GGN_INVALID_ECP;
+    }
+
+    /* Verify additional DLOG proof */
+    rc = BIT_COMMITMENT_ECP_verify(&ECPR, &ECPRT, &(c->u1), E, p->s1);
+    if (rc != BIT_COMMITMENT_OK)
+    {
+        return rc;
+    }
+
+    return BIT_COMMITMENT_verify(key, m, CT, (BIT_COMMITMENT_commitment*)c, E, (BIT_COMMITMENT_proof*) p);
+}
+
+void GGN_commitment_toOctets(octet *Z, octet *U1, octet *U2, octet *U3, GGN_commitment *c)
+{
+
+    BIT_COMMITMENT_commitment_toOctets(Z, U2, U3, (BIT_COMMITMENT_commitment*)c);
+    ECP_SECP256K1_toOctet(U1, &(c->u1), true);
+}
+
+int GGN_commitment_fromOctets(GGN_commitment *c, octet *Z, octet *U1, octet *U2, octet *U3)
+{
+    if (ECP_SECP256K1_fromOctet(&(c->u1), U1) != 1)
+    {
+        return GGN_INVALID_ECP;
+    }
+
+    BIT_COMMITMENT_commitment_fromOctets((BIT_COMMITMENT_commitment*)c, Z, U2, U3);
+
+    return GGN_OK;
+}
+
+void GGN_proof_toOctets(octet *S1, octet *S2, octet *S3, GGN_proof *p)
+{
+    BIT_COMMITMENT_proof_toOctets(S1, S2, S3, (BIT_COMMITMENT_proof*)p);
+}
+
+void GGN_proof_fromOctets(GGN_proof *p, octet *S1, octet *S2, octet *S3)
+{
+    BIT_COMMITMENT_proof_fromOctets((BIT_COMMITMENT_proof*)p, S1, S2, S3);
+}
+
+void GGN_rv_kill(GGN_rv *rv)
+{
+    BIT_COMMITMENT_rv_kill((BIT_COMMITMENT_rv*)rv);
+}
+
diff --git a/src/gmr.c b/src/gmr.c
new file mode 100644
index 0000000..84c909e
--- /dev/null
+++ b/src/gmr.c
@@ -0,0 +1,298 @@
+/*
+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.
+*/
+
+/* GMR ZKP for a Square Free RSA Modulus */
+
+#include "amcl/hash_utils.h"
+#include "amcl/gmr.h"
+
+// Prime buckets necessary for the 10 iterations protocol.
+#define GMR_PRIMES_LENGTH 417
+
+const sign32 GMR_primes[GMR_PRIMES_LENGTH] =
+{
+    111546435,   58642669,  600662303,   33984931,   89809099,  167375713,
+    371700317,  645328247, 1070560157, 1596463769,   11592209,   13420567,
+    16965341,   20193023,   23300239,   29884301,   35360399,   42749359,
+    49143869,   56466073,   65111573,   76027969,   84208541,   94593973,
+    103569859,  119319383,  133390067,  154769821,  178433279,  193397129,
+    213479407,  229580147,  250367549,  271661713,  293158127,  319512181,
+    357349471,  393806449,  422400701,  452366557,  507436351,  547978913,
+    575204137,  627947039,  666785731,  710381447,  777767161,  834985999,
+    894826021,  951747481, 1019050649, 1072651369, 1125878063, 1185362993,
+    1267745273, 1322520163, 1391119619, 1498299287, 1608372013, 1700725291,
+    1805418283, 1871456063, 2008071007, 2115193573,    1674427,    1695203,
+    1723933,    1752967,    1860487,    1896113,    1971191,    2030621,
+    2047757,    2082233,    2108303,    2146189,    2196323,    2214143,
+    2238007,    2301253,    2362333,    2405597,    2442953,    2480609,
+    2528051,    2572807,    2595317,    2624399,    2663399,    2755591,
+    2782223,    2873021,    2903591,    2965283,    3017153,    3062491,
+    3125743,    3186221,    3221989,    3301453,    3381857,    3474487,
+    3504383,    3526883,    3590989,    3648091,    3732623,    3802499,
+    3904567,    3960091,    3992003,    4028033,    4088459,    4137131,
+    4235339,    4305589,    4347221,    4384811,    4460543,    4536899,
+    4575317,    4613879,    4708819,    4862021,    4915073,    5008643,
+    5048993,    5143823,    5184713,    5244091,    5303773,    5391563,
+    5475599,    5517797,    5588447,    5659637,    5692987,    5740807,
+    5827387,    5904851,    5973127,    6066353,    6125621,    6310063,
+    6426209,    6482107,    6522907,    6682189,    6765137,    6859157,
+    6969551,    7064963,    7112873,    7182391,    7225343,    7268407,
+    7338677,    7376647,    7452899,    7535009,    7617551,    7745053,
+    7806427,    7851203,    7986227,    8065591,    8145307,    8236819,
+    8363639,    8444827,    8538059,    8678867,    8761591,    8820899,
+    8999999,    9090209,    9180851,    9272009,    9388087,    9492557,
+    9603701,    9734399,    9922331,   10036223,   10137847,   10220773,
+    10323353,   10400609,   10575503,   10614563,   10791029,   10916407,
+    10995847,   11062267,   11135533,   11242573,   11329931,   11431097,
+    11553137,   11716829,   11923193,   11985443,   12027023,   12215009,
+    12348187,   12446783,   12503287,   12559927,   12659363,   12787751,
+    12873719,   13032091,   13104391,   13205947,   13329737,   13483583,
+    13571807,   13682597,   13793771,   13912891,   14062379,   14197823,
+    14333747,   14439991,   14607683,   14745551,   14837903,   14976851,
+    15093209,   15280277,   15350723,   15413467,   15499933,   15657749,
+    15959989,   16040021,   16128247,   16192567,   16402499,   16524161,
+    16687189,   16777207,   16966097,   17065157,   17189267,   17288963,
+    17547577,   17757787,   17842151,   17943671,   18045479,   18147599,
+    18249983,   18369787,   18593119,   18818243,   18948593,   19079399,
+    19307227,   19492189,   19642543,   19793597,   19891591,   20088323,
+    20249951,   20385221,   20439437,   20684303,   20830087,   21040553,
+    21159991,   21427577,   21538877,   21622499,   21715591,   21864967,
+    22061773,   22297283,   22382357,   22610009,   22896221,   22953677,
+    23039999,   23184221,   23483491,   23755867,   23970767,   24147371,
+    24324623,   24403591,   24542107,   24681023,   24800351,   24960007,
+    25060027,   25160231,   25310897,   25553009,   25796237,   25938613,
+    26050807,   26173447,   26522491,   26718557,   26873831,   27071173,
+    27342437,   27405221,   27741253,   27878399,   28089991,   28259807,
+    28515551,   28793731,   29052091,   29192393,   29322221,   29430589,
+    29582717,   29658907,   29964667,   30041357,   30272003,   30393133,
+    30514567,   30735767,   30980347,   31102913,   31438193,   31809599,
+    31911197,   31979021,   32080871,   32330587,   32455793,   32649787,
+    32936117,   33016507,   33419957,   33593591,   33756091,   33918967,
+    34117277,   34222499,   34327877,   34433423,   34574399,   34809991,
+    35105621,   35354867,   35808247,   36108077,   36397073,   36542021,
+    36723551,   36917767,   37088099,   37295413,   37527851,   37675019,
+    37908613,   38254081,   38452397,   38613787,   38750609,   39087479,
+    39262747,   39363067,   39601813,   39765611,   39942391,   40106873,
+    40297079,   40449599,   40576891,   40755431,   41075137,   41447723,
+    41731519,   41951513,   42327811,   42745363,   42928703,   43112347,
+    43217467,   43428019,   43731733,   44155961,   44355599,   44568967,
+    44756099,   44916803,   45077771,   45360221,   45724643,   45968399,
+    46131263,   46416869,   46621583,   46744553,   47059591,   47196899,
+    47485817,   47734277,   48052399,   48358091,   48497287,   48636667,
+    48818153,   48985997,   49224247,   49463053,   49702451,   50041451,
+    50495227,   50751367,   50979479
+};
+
+/*
+ * Encode N, ID and AD and fill sha for the challenges generation
+ * i.e. N || len(ID) || ID || len(AD) || AD
+ * with ID and AD optional
+ */
+void GMR_prepare_hash(hash256 *sha, BIG_1024_58 *N, const octet *ID, const octet*AD)
+{
+    char o[FS_2048];
+    octet O = {0, sizeof(o), o};
+
+    FF_2048_toOctet(&O, N, FFLEN_2048);
+
+    HASH_UTILS_hash_oct(sha, &O);
+
+    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);
+    }
+}
+
+// Copy and complete sha with I2OSP(k) and sample a challenge
+void GMR_challenge(hash256 *sha, int k, BIG_1024_58 *N, BIG_1024_58 *X)
+{
+    hash256 sha_k;
+
+    HASH_UTILS_hash_copy(&sha_k, sha);
+    HASH_UTILS_hash_i2osp4(&sha_k, k);
+
+    HASH_UTILS_sample_mod_FF(&sha_k, N, X);
+}
+
+void GMR_prove(MODULUS_priv *m, const octet *ID, const octet *AD, GMR_proof Y)
+{
+    int i;
+
+    hash256 sha;
+
+    BIG_1024_58 Mp[HFLEN_2048], Mq[HFLEN_2048];
+    BIG_1024_58 Xp[HFLEN_2048], Xq[HFLEN_2048];
+    BIG_1024_58 ws[FFLEN_2048];
+
+    /* Compute Mp, Mq s.t.
+     *   M = CRT(Mp, Mq, P-1, Q-1) and
+     *   M = N^(-1) mod (P-1)(Q-1)
+     *
+     * i.e.
+     *   Mp = Q^(-1) mod P-1
+     *   Mq = P^(-1) mod Q-1
+     */
+
+    // Compute Mp
+
+    // Since P is odd P>>1 = (P-1)/2
+    FF_2048_copy(ws, m->p, HFLEN_2048);
+    FF_2048_shr(ws, HFLEN_2048);
+
+    // Compute inverse mod (P-1)/2
+    FF_2048_invmodp(Mp, m->q, ws, HFLEN_2048);
+
+    // Apply correction to obtain inverse mod P-1
+    if (!FF_2048_parity(Mp))
+    {
+        FF_2048_add(Mp, ws, Mp, HFLEN_2048);
+        FF_2048_norm(Mp, HFLEN_2048);
+    }
+
+    // Compute Mq
+
+    // Since Q is odd Q>>1 = (Q-1)/2
+    FF_2048_copy(ws, m->q, HFLEN_2048);
+    FF_2048_shr(ws, HFLEN_2048);
+
+    // Compute inverse mod (Q-1)/2
+    FF_2048_invmodp(Mq, m->p, ws, HFLEN_2048);
+
+    // Apply correction to obtain inverse mod Q-1
+    if (!FF_2048_parity(Mq))
+    {
+        FF_2048_add(Mq, ws, Mq, HFLEN_2048);
+        FF_2048_norm(Mq, HFLEN_2048);
+    }
+
+    // Prepare hash for Xs generation
+    HASH256_init(&sha);
+    GMR_prepare_hash(&sha, m->n, ID, AD);
+
+    for(i = 0; i < GMR_PROOF_ITERS; i++)
+    {
+        // Generate Xk and prepare reduced terms for CRT
+        GMR_challenge(&sha, i, m->n, ws);
+
+        FF_2048_dmod(Xp, ws, m->p, HFLEN_2048);
+        FF_2048_dmod(Xq, ws, m->q, HFLEN_2048);
+
+        // Compute Xk^M using Mp, Mq and CRT
+        FF_2048_ct_pow(Xp, Xp, Mp, m->p, HFLEN_2048, HFLEN_2048);
+        FF_2048_ct_pow(Xq, Xq, Mq, m->q, HFLEN_2048, HFLEN_2048);
+
+        FF_2048_crt(Y[i], Xp, Xq, m->p, m->invpq, m->n, HFLEN_2048);
+    }
+}
+
+int GMR_verify(octet *N, GMR_proof Y, const octet *ID, const octet *AD)
+{
+    int i, k;
+
+    hash256 sha;
+
+    BIG_1024_58 n[FFLEN_2048];
+    BIG_1024_58 x[FFLEN_2048];
+    BIG_1024_58 ws[FFLEN_2048];
+
+    FF_2048_fromOctet(n, N, FFLEN_2048);
+
+    // Check N parity since the buckets must be odd
+    // for cfactor to work
+    if (FF_2048_parity(n) == 0)
+    {
+        return GMR_FAIL;
+    }
+
+    // Common factor check with prime buckets
+    for (k = 0; k < GMR_PRIMES_LENGTH; k++)
+    {
+        // These values are all public so it is ok to
+        // terminate early
+        if (FF_2048_cfactor(n, GMR_primes[k], FFLEN_2048))
+        {
+            return GMR_FAIL;
+        }
+    }
+
+    // Prepare hash for Xs generation
+    HASH256_init(&sha);
+    GMR_prepare_hash(&sha, n, ID, AD);
+
+    // Generate each Xk and compute Yk^N
+    for(i = 0; i < GMR_PROOF_ITERS; i++)
+    {
+        GMR_challenge(&sha, i, n, x);
+
+        FF_2048_nt_pow(ws, Y[i], n, n, FFLEN_2048, FFLEN_2048);
+
+        // These values are all public so it is ok to
+        // terminate early
+        if (FF_2048_comp(ws, x, FFLEN_2048) != 0)
+        {
+            return GMR_FAIL;
+        }
+    }
+
+    return GMR_OK;
+}
+
+void GMR_proof_toOctet(octet *O, GMR_proof p)
+{
+    int i;
+
+    char w[FS_2048];
+    octet W = {0, sizeof(w), w};
+
+    OCT_clear(O);
+
+    for (i = 0; i < GMR_PROOF_ITERS; i++)
+    {
+        FF_2048_toOctet(&W, p[i], FFLEN_2048);
+        OCT_joctet(O, &W);
+    }
+}
+
+int GMR_proof_fromOctet(GMR_proof p, octet *O)
+{
+    int i;
+
+    char w[FS_2048];
+    octet W = {0, sizeof(w), w};
+
+    if (O->len != GMR_PROOF_SIZE)
+    {
+        return GMR_INVALID_PROOF;
+    }
+
+    for (i = GMR_PROOF_ITERS - 1; i >= 0; i--)
+    {
+        OCT_chop(O, &W, O->len - FS_2048);
+        FF_2048_fromOctet(p[i], &W, FFLEN_2048);
+    }
+
+    // Restore length of O
+    O->len = GMR_PROOF_SIZE;
+
+    return GMR_OK;
+}
diff --git a/test/smoke/test_ggn_smoke.c b/test/smoke/test_ggn_smoke.c
new file mode 100644
index 0000000..bb096fd
--- /dev/null
+++ b/test/smoke/test_ggn_smoke.c
@@ -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.
+*/
+
+/* GGN Proof smoke tests */
+
+#include <string.h>
+#include "amcl/ggn.h"
+
+void ff_2048_cleaned(BIG_1024_58 *a, char *name, int n)
+{
+    if(!FF_2048_iszilch(a, n))
+    {
+        fprintf(stderr, "FAILURE GGN_rv_kill. %s was not cleaned\n", name);
+        exit(EXIT_FAILURE);
+    }
+}
+
+// Primes for Paillier key
+char *P_hex = "c39f253734727ac925e786ec50abcf9b5bb46e1cba747342dee478c6efdb59d6c63c8495ab18e1b4c56e9bed152ad63681e0af18a6a21db1fe5faa9e7eae17e17013ccb3b4fbd4efb86a50b4b25fa081ccc90b9c22d455452fd0f7b878f36da06b82285fbdb0511e8a01eea7f79e4381cffb3b0e5f34755c086d51be5584200f";
+char *Q_hex = "d1f98d7be4e10120eec3f0225af8f33c8fbecc4bd846ac36bcf0bafedbc03bb6eb3f121c65a9c27b9931cda44eed1d4a5eeb32a3fe8f5643f01caebd75e37206b2c7debe83d9ce7197831e9fd5954eb61f1bcba4c1f64a3bf5cc73a488298998f4650cc82ac8a0fc17c0f698f09bb560c41341dd70d1ceef1ac7df7e286a3941";
+
+// Safe primes for BC setup
+char *PT_hex = "CA5F37B7C0DDF6530B30A41116588218DE95F1F36B807FD7C28E4C467EE3F35967BC01D28B71F8A627A353675A81C86A1FF03DCECAF1686891183FA317BA34A4A1148D40A89F1F3AC0C200511C6CFE02342CD75354C25A2E069886DD4FB73BD365660D163F1282B143119AB8F375A73875EC16B634F52593B73BC6D875F2D3EF";
+char *QT_hex = "C2FC545C1C803F6C7625FBC4ECF9355734D6B6058FD714816D3ECFB93F1F705C9CE90D4F8796A05148AB5ABC201F90889231CC6BF5F68ED15EE4D901F603930A280EEABF10C613BFCB67A816363C839EB902B02607EB48AB8325E2B72620D4D294A232803217090DFB50AF8C620D4679E77CE3053437ED518F4F68840DCF1AA3";
+
+// Paillier ciphertext and plaintext
+char* K_hex = "316e5fe3f60876f456e3c15e05e2d4ee79649e6a18008f08ff7a4c67bcdf5391";
+char* C_hex = "2373194729f056ef064cae6f98f5da88f0d39ad77884a04009fe3741bdc9354ae25fe1b0d42b6b6e0cb81e02a22f112fc1d8b3649344b08a6d10dff8988a806040f5b46ad971711f23b254da53d73ec1a4592327b07297cb6cce74855f7f5401efcf1eb7c5f2c344119321b2f3ee54da292e5e65930e1655f524194664f148bcf715267e08f489c1762473edaf47f233c123bc2b17015f12cef26c282ed13d91035ddac65b058f2e7b28718679785fe5d70d803d503bfe098f1cf4fb713051e90dab945c05eecbefa39dbe7660689f71a3cfcebe37f874435a56546a70cb0c2fb098ce6427fd525c6b6e12aaff954 [...]
+char* R_hex = "2174746e69b220c3ee9512b3e4da121866b7c656de08febb40e774ec90b459df9af8c22523e2816a23e33f134ede2fc35c49458f5f3a1e6c5b3578cc74b461e0b4a6ea83bdbe66a368692376d02bda4f80fbc1d1e9255c07aae2a2f8d7122ef00bd5fea48c8317124ebdba0545d9e43d87ee1f1b6117cefb484d8df4fb752cefb3d99af3ea070e2cb06bbf644aa781687c82f76e87324ba8fe0b9cd3b617f679081bc0e371cf6e3157edd82cc1b07f2629908847d109af71d9c802b1ca5e481a024968581dcbd2b4d668bfc7a0b338fe5f8801a79d6ba8852af580f5a72bcd2efb3a580ceeab2d5fc5587bd2c6b0e [...]
+
+// ECP for DLOG
+char* ECPR_hex  = "0274ec825739bb45d8e451dec0cb85baf356b931c754b5ccdef159389a27422b57";
+char* ECPRT_hex = "02a143a6f56e92af5e0ecaae7b8ae133750de551d6a00e9fa7c3e993deea0be12f";
+
+int main()
+{
+    int rc;
+
+    PAILLIER_private_key priv_key;
+    PAILLIER_public_key  pub_key;
+
+    BIT_COMMITMENT_priv priv_mod;
+    BIT_COMMITMENT_pub  pub_mod;
+
+    GGN_commitment co;
+    GGN_rv         rv;
+    GGN_proof      proof;
+
+    char c[2*FS_2048];
+    octet C = {0, sizeof(c), c};
+
+    char r[2*FS_2048];
+    octet R = {0, sizeof(r), r};
+
+    char k[MODBYTES_256_56];
+    octet K = {0, sizeof(k), k};
+
+    char e[MODBYTES_256_56];
+    octet E = {0, sizeof(e), e};
+
+    char p[HFS_2048];
+    octet P = {0, sizeof(p), p};
+
+    char q[HFS_2048];
+    octet Q = {0, sizeof(q), q};
+
+    char id[32];
+    octet ID = {0, sizeof(id), id};
+
+    char ad[32];
+    octet AD = {0, sizeof(ad), ad};
+
+    char ecpr_oct[MODBITS_SECP256K1];
+    octet ECPR_OCT = {0, sizeof(ecpr_oct), ecpr_oct};
+
+    char ecprt_oct[MODBITS_SECP256K1];
+    octet ECPRT_OCT = {0, sizeof(ecprt_oct), ecprt_oct};
+
+    // Deterministic RNG for testing
+    char seed[32] = {0};
+    csprng RNG;
+    RAND_seed(&RNG, 32, seed);
+
+    // Pseudorandom ID and AD
+    OCT_rand(&ID, &RNG, ID.len);
+    OCT_rand(&AD, &RNG, AD.len);
+
+    // Load paillier key
+    OCT_fromHex(&P, P_hex);
+    OCT_fromHex(&Q, Q_hex);
+
+    PAILLIER_KEY_PAIR(NULL, &P, &Q, &pub_key, &priv_key);
+
+    // Generate BC commitment modulus
+    OCT_fromHex(&P, PT_hex);
+    OCT_fromHex(&Q, QT_hex);
+    BIT_COMMITMENT_setup(&RNG, &priv_mod, &P, &Q, NULL, NULL);
+
+    BIT_COMMITMENT_priv_to_pub(&pub_mod, &priv_mod);
+
+    // Load Paillier encryption values
+    OCT_fromHex(&K, K_hex);
+    OCT_fromHex(&R, R_hex);
+    OCT_fromHex(&C, C_hex);
+
+    // Load values for DLOG
+    OCT_fromHex(&ECPR_OCT, ECPR_hex);
+    OCT_fromHex(&ECPRT_OCT, ECPRT_hex);
+
+
+    // Run smoke test
+    rc = GGN_commit(&RNG, &priv_key, &pub_mod, &ECPR_OCT, &K, &rv, &co);
+    if (rc != GGN_OK)
+    {
+        printf("FAILURE GGN_commit smoke test. error code %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    GGN_challenge(&pub_key, &pub_mod, &ECPR_OCT, &ECPRT_OCT, &C, &co, &ID, &AD, &E);
+    GGN_prove(&priv_key, &K, &R, &rv, &E, &proof);
+
+    rc = GGN_verify(&pub_key, &priv_mod, &ECPR_OCT, &ECPRT_OCT, &C, &co, &E, &proof);
+    if (rc != GGN_OK)
+    {
+        printf("FAILURE GGN_verify smoke test. error code %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    // Check error codes are propagated
+    rc = GGN_verify(&pub_key, &priv_mod, &ECPR_OCT, &ECPRT_OCT, &C, &co, &ID, &proof);
+    if (rc != BIT_COMMITMENT_FAIL)
+    {
+        printf("FAILURE GGN error code propagation\n");
+        exit(EXIT_FAILURE);
+    }
+
+    // Check input validation
+    rc = GGN_commit(&RNG, &priv_key, &pub_mod, &ID, &K, &rv, &co);
+    if (rc != GGN_INVALID_ECP)
+    {
+        printf("FAILURE GGN_commit invalid R. rc %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    rc = GGN_verify(&pub_key, &priv_mod, &ID, &ECPRT_OCT, &C, &co, &ID, &proof);
+    if (rc != GGN_INVALID_ECP)
+    {
+        printf("FAILURE GGN_verify invalid R. rc %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    rc = GGN_verify(&pub_key, &priv_mod, &ECPR_OCT, &ID, &C, &co, &ID, &proof);
+    if (rc != GGN_INVALID_ECP)
+    {
+        printf("FAILURE GGN_verify invalid Rt. rc %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    // Check octet functions consistency
+    char oct1[FS_2048];
+    octet OCT1 = {0, sizeof(oct1), oct1};
+
+    char oct2[2 * FS_2048];
+    octet OCT2 = {0, sizeof(oct2), oct2};
+
+    char oct3[2 * FS_2048];
+    octet OCT3 = {0, sizeof(oct3), oct3};
+
+    char u1[EGS_SECP256K1 + 1];
+    octet U1 = {0, sizeof(u1), u1};
+
+    GGN_commitment_toOctets(&OCT1, &U1, &OCT2, &OCT3, &co);
+
+    // Load Invalid ECP
+    rc = GGN_commitment_fromOctets(&co, &OCT1, &ID, &OCT2, &OCT3);
+    if (rc != GGN_INVALID_ECP)
+    {
+        printf("FAILURE GGN_commitment_fromOctets invalid ECP. rc = %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    // Continue loading correct ECP
+    rc = GGN_commitment_fromOctets(&co, &OCT1, &U1, &OCT2, &OCT3);
+    if (rc != GGN_OK)
+    {
+        printf("FAILURE GGN_commitment_fromOctets. rc = %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    GGN_proof_toOctets(&OCT1, &OCT2, &OCT3, &proof);
+    GGN_proof_fromOctets(&proof, &OCT1, &OCT2, &OCT3);
+
+    rc = GGN_verify(&pub_key, &priv_mod, &ECPR_OCT, &ECPRT_OCT, &C, &co, &E, &proof);
+    if (rc != GGN_OK)
+    {
+        printf("FAILURE GGN octet consistency. error code %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    // Clean random values
+    GGN_rv_kill(&rv);
+
+    ff_2048_cleaned(rv.alpha, "rv.alpha", FFLEN_2048);
+    ff_2048_cleaned(rv.beta,  "rv.beta",  FFLEN_2048);
+    ff_2048_cleaned(rv.gamma, "rv.gamma", FFLEN_2048 + HFLEN_2048);
+    ff_2048_cleaned(rv.rho,   "rv.rho",   FFLEN_2048 + HFLEN_2048);
+
+    printf("SUCCESS");
+    exit(EXIT_SUCCESS);
+}
diff --git a/test/smoke/test_gmr_smoke.c b/test/smoke/test_gmr_smoke.c
new file mode 100644
index 0000000..700718b
--- /dev/null
+++ b/test/smoke/test_gmr_smoke.c
@@ -0,0 +1,91 @@
+/*
+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.
+*/
+
+/* GMR ZKP of Square Freeness smoke test */
+
+#include "amcl/gmr.h"
+
+char *P_hex = "e008507e09c24d756280f3d94912fb9ac16c0a8a1757ee01a350736acfc7f65880f87eca55d6680253383fc546d03fd9ebab7d8fa746455180888cb7c17edf58d3327296468e5ab736374bc9a0fa02606ed5d3a4a5fb1677891f87fbf3c655c3e0549a86b17b7ddce07c8f73e253105e59f5d3ed2c7ba5bdf8495df40ae71a7f";
+char *Q_hex = "d344c02d8379387e773ab6fa6de6b92b395d5b7f0c41660778766a1ec4740468203bff2d05f263ff6f22740d4b2e799fd1fd2e2339e328c62d31eeecba30fd4892e0c1637e0f62b4de34f5d778a7dfd181b94464f3669751264a0058708a360552535653efc75e3035485e966df30a17146d692747e20b2f04f3877dd1f56dcf";
+
+int main()
+{
+    int rc;
+
+    char id[32];
+    octet ID = {0, sizeof(id), id};
+
+    char ad[32];
+    octet AD = {0, sizeof(ad), ad};
+
+    char p[HFS_2048] = {0};
+    octet P = {0, sizeof(p), p};
+
+    char q[HFS_2048];
+    octet Q = {0, sizeof(q), q};
+
+    char n[FS_2048];
+    octet N = {0, sizeof(n), n};
+
+    MODULUS_priv m;
+
+    GMR_proof Y;
+
+    char yoct[GMR_PROOF_SIZE];
+    octet Yoct = {0, sizeof(yoct), yoct};
+
+    // Deterministic RNG for testing
+    char seed[32] = {0};
+    csprng RNG;
+    RAND_seed(&RNG, 32, seed);
+
+    // Pseudorandom ID and AD
+    OCT_rand(&ID, &RNG, ID.len);
+    OCT_rand(&AD, &RNG, AD.len);
+
+    // Load RSA modulus
+    OCT_fromHex(&P, P_hex);
+    OCT_fromHex(&Q, Q_hex);
+
+    MODULUS_fromOctets(&m, &P, &Q);
+
+    FF_2048_toOctet(&N, m.n, FFLEN_2048);
+
+    // ZK Proof
+    GMR_prove(&m, &ID, &AD, Y);
+    GMR_proof_toOctet(&Yoct, Y);
+
+    // ZK Verify
+    rc = GMR_proof_fromOctet(Y, &Yoct);
+    if (rc != GMR_OK)
+    {
+        printf("FAILURE GMR_proof_fromOctet\n");
+        exit(EXIT_FAILURE);
+    }
+
+    rc = GMR_verify(&N, Y, &ID, &AD);
+    if (rc != GMR_OK)
+    {
+        printf("FAILURE GMR_verify\n");
+        exit(EXIT_FAILURE);
+    }
+
+    printf("SUCCESS");
+    exit(EXIT_SUCCESS);
+}
diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt
index 0dda107..338b0fd 100644
--- a/test/unit/CMakeLists.txt
+++ b/test/unit/CMakeLists.txt
@@ -53,6 +53,10 @@ amcl_test(test_nm_commit test_nm_commit.c amcl_mpc "SUCCESS" "nm_commitment/comm
 # ZKP of knowledge of factoring
 amcl_test(test_factoring_zk_prove  test_factoring_zk_prove.c  amcl_mpc "SUCCESS" "factoring_zk/prove.txt")
 amcl_test(test_factoring_zk_verify test_factoring_zk_verify.c amcl_mpc "SUCCESS" "factoring_zk/verify.txt")
+# GMR ZKP of Square Freeness
+amcl_test(test_gmr_prove  test_gmr_prove.c  amcl_mpc "SUCCESS" "gmr/prove.txt")
+amcl_test(test_gmr_verify test_gmr_verify.c amcl_mpc "SUCCESS" "gmr/verify.txt")
+amcl_test(test_gmr_octets test_gmr_octets.c amcl_mpc "SUCCESS" "gmr/verify.txt")
 
 # Classic Schnorr tests
 amcl_test(test_schnorr_commit    test_schnorr_commit.c    amcl_mpc "SUCCESS" "schnorr/commit.txt")
@@ -109,3 +113,6 @@ amcl_test(test_hidden_dlog_challenge test_hidden_dlog_challenge.c amcl_mpc "SUCC
 amcl_test(test_hidden_dlog_prove     test_hidden_dlog_prove.c     amcl_mpc "SUCCESS" "hidden_dlog/prove.txt")
 amcl_test(test_hidden_dlog_verify    test_hidden_dlog_verify.c    amcl_mpc "SUCCESS" "hidden_dlog/verify.txt")
 
+# GGN tests
+amcl_test(test_ggn test_ggn.c amcl_mpc "SUCCESS" "ggn/challenge.txt")
+
diff --git a/test/unit/test_gg20_zkp_generator.c b/test/unit/test_gg20_zkp_generator.c
new file mode 100644
index 0000000..a87d6f4
--- /dev/null
+++ b/test/unit/test_gg20_zkp_generator.c
@@ -0,0 +1,86 @@
+/*
+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.
+*/
+
+/* GG20 ZKPs alternative generator integrity check
+ *
+ * The purpose of this test is to check that the alternative
+ * generator for the GG20 ZKP is generated from the standard
+ * generator so that it is a NUMS number and the DLOG w.r.t the
+ * standard generator is not known
+ */
+
+#include <string.h>
+#include "amcl/gg20_zkp.h"
+#include "amcl/hash_utils.h"
+
+int main()
+{
+    int rc;
+    int attempt = 0;
+
+    hash256 sha_seed;
+    hash256 sha_attempt;
+
+    BIG_256_56 p;
+
+    char digest[SHA256];
+
+    ECP_SECP256K1 H;
+    ECP_SECP256K1 H_GOLDEN;
+
+    char o[GFS_SECP256K1 + 1];
+    octet O = {0, sizeof(o), o};
+
+    // Compute H using repeated hases of the standard generator
+    HASH256_init(&sha_seed);
+
+    ECP_SECP256K1_generator(&H);
+    ECP_SECP256K1_toOctet(&O, &H, true);
+    HASH_UTILS_hash_oct(&sha_seed, &O);
+
+    do
+    {
+        HASH_UTILS_hash_copy(&sha_attempt, &sha_seed);
+        HASH_UTILS_hash_i2osp4(&sha_attempt, attempt);
+        attempt++;
+
+        HASH256_hash(&sha_attempt, digest);
+        BIG_256_56_fromBytesLen(p, digest, GGS_SECP256K1);
+
+        rc = ECP_SECP256K1_setx(&H, p, 0);
+
+        // The cofactor check is trivial for secp256k1
+        // but it MUST be included if we decide to support
+        // curves with cofactor != 1
+    }
+    while(rc != 1);
+
+    // Check that the computed generator is equal to the one hard-coded
+    // in the library
+    GG20_ZKP_generator_2(&H_GOLDEN);
+
+    if (!ECP_SECP256K1_equals(&H, &H_GOLDEN))
+    {
+        printf("FAILURE mismatching generators\n");
+        exit(EXIT_FAILURE);
+    }
+
+    printf("SUCCESS\n");
+    exit(EXIT_SUCCESS);
+}
diff --git a/test/unit/test_gg20_zkp_octets.c b/test/unit/test_gg20_zkp_octets.c
new file mode 100644
index 0000000..7fd043f
--- /dev/null
+++ b/test/unit/test_gg20_zkp_octets.c
@@ -0,0 +1,138 @@
+/*
+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.
+*/
+
+/* GG20 ZKPs octet functions unit test */
+
+#include <string.h>
+#include "test.h"
+#include "amcl/gg20_zkp.h"
+
+#define LINE_LEN 1024
+
+int main(int argc, char **argv)
+{
+    if (argc != 2)
+    {
+        printf("usage: ./test_gg20_zkp_octets [path to test vector file]\n");
+        exit(EXIT_FAILURE);
+    }
+
+    int rc;
+    int test_run = 0;
+
+    FILE *fp;
+    char line[LINE_LEN] = {0};
+
+    const char *TESTline = "TEST = ";
+    int testNo = 0;
+
+    char alpha[GFS_SECP256K1 + 1];
+    char alpha_golden[GFS_SECP256K1 + 1];
+    octet ALPHA = {0, sizeof(alpha), alpha};
+    octet ALPHA_GOLDEN = {0, sizeof(alpha_golden), alpha_golden};
+    const char *ALPHAline = "ALPHA = ";
+
+    char beta[GFS_SECP256K1 + 1];
+    char beta_golden[GFS_SECP256K1 + 1];
+    octet BETA = {0, sizeof(beta), beta};
+    octet BETA_GOLDEN = {0, sizeof(beta_golden), beta_golden};
+    const char *BETAline = "BETA = ";
+
+    char t[GGS_SECP256K1];
+    char t_golden[GGS_SECP256K1];
+    octet T = {0, sizeof(t), t};
+    octet T_GOLDEN = {0, sizeof(t_golden), t_golden};
+    const char *Tline = "T = ";
+
+    char u[GFS_SECP256K1];
+    char u_golden[GFS_SECP256K1];
+    octet U = {0, sizeof(u), u};
+    octet U_GOLDEN = {0, sizeof(u_golden), u_golden};
+    const char *Uline = "U = ";
+
+    GG20_ZKP_proof p;
+    GG20_ZKP_phase6_commitment c;
+
+    // Line terminating a test vector
+    const char *last_line = Uline;
+
+    fp = fopen(argv[1], "r");
+    if (fp == NULL)
+    {
+        printf("ERROR opening test vector file\n");
+        exit(EXIT_FAILURE);
+    }
+
+    /* Test Happy Paths with test vectors */
+
+    while (fgets(line, LINE_LEN, fp) != NULL)
+    {
+        scan_int(&testNo, line, TESTline);
+
+        scan_OCTET(fp, &ALPHA_GOLDEN, line, ALPHAline);
+        scan_OCTET(fp, &BETA_GOLDEN,  line, BETAline);
+
+        scan_OCTET(fp, &T_GOLDEN, line, Tline);
+        scan_OCTET(fp, &U_GOLDEN, line, Uline);
+
+        if (!strncmp(line, last_line, strlen(last_line)))
+        {
+            // Phase 6 Commitment test
+            rc = GG20_ZKP_phase6_commitment_fromOctets(&c, &ALPHA_GOLDEN, &BETA_GOLDEN);
+            assert_tv(fp, testNo, "GG20_ZKP_phase6_commitment_fromOctet", rc == GG20_ZKP_OK);
+
+            GG20_ZKP_phase6_commitment_toOctets(&ALPHA, &BETA, &c);
+
+            compare_OCT(fp, testNo, "GG20_ZKP_phase6_commitment octets ALPHA", &ALPHA, &ALPHA_GOLDEN);
+            compare_OCT(fp, testNo, "GG20_ZKP_phase6_commitment octets BETA",  &BETA,  &BETA_GOLDEN);
+
+            // Proof test
+            GG20_ZKP_proof_fromOctets(&p, &T_GOLDEN, &U_GOLDEN);
+            GG20_ZKP_proof_toOctets(&T, &U, &p);
+
+            compare_OCT(fp, testNo, "GG20_ZKP_proof octet T", &T, &T_GOLDEN);
+            compare_OCT(fp, testNo, "GG20_ZKP_proof octet U", &U, &U_GOLDEN);
+
+            // Mark that at least one test vector was executed
+            test_run = 1;
+        }
+    }
+
+    fclose(fp);
+
+    if (test_run == 0)
+    {
+        printf("ERROR no test vector was executed\n");
+        exit(EXIT_FAILURE);
+    }
+
+    /* Test unhappy paths */
+
+    // Invalid Phase 6 Commitment ALPHA
+    rc = GG20_ZKP_phase6_commitment_fromOctets(&c, &T, &BETA);
+    assert(fp, "GG20_ZKP_phase6_commitment_fromOctets invalid ALPHA", rc == GG20_ZKP_INVALID_ECP);
+
+
+    // Invalid Phase 6 Commitment BETA
+    rc = GG20_ZKP_phase6_commitment_fromOctets(&c, &ALPHA, &U);
+    assert(fp, "GG20_ZKP_phase6_commitment_fromOctets invalid BETA", rc == GG20_ZKP_INVALID_ECP);
+
+    printf("SUCCESS\n");
+    exit(EXIT_SUCCESS);
+}
diff --git a/test/unit/test_gg20_zkp_phase3_challenge.c b/test/unit/test_gg20_zkp_phase3_challenge.c
new file mode 100644
index 0000000..360a0c9
--- /dev/null
+++ b/test/unit/test_gg20_zkp_phase3_challenge.c
@@ -0,0 +1,119 @@
+/*
+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.
+*/
+
+/* GG20 Phase 3 ZKP challenge unit test */
+
+#include <string.h>
+#include "test.h"
+#include "amcl/gg20_zkp.h"
+
+#define LINE_LEN 1024
+#define IDLEN 16
+#define ADLEN 16
+
+int main(int argc, char **argv)
+{
+    if (argc != 2)
+    {
+        printf("usage: ./test_gg20_zkp_phase3_challenge [path to test vector file]\n");
+        exit(EXIT_FAILURE);
+    }
+
+    int test_run = 0;
+
+    FILE *fp;
+    char line[LINE_LEN] = {0};
+
+    const char *TESTline = "TEST = ";
+    int testNo = 0;
+
+    char v[GFS_SECP256K1 + 1];
+    octet V = {0, sizeof(v), v};
+    const char *Vline = "V = ";
+
+    char c[GFS_SECP256K1 + 1];
+    octet C = {0, sizeof(c), c};
+    const char *Cline = "C = ";
+
+    char e[GGS_SECP256K1];
+    char e_golden[GGS_SECP256K1];
+    octet E = {0, sizeof(e), e};
+    octet E_GOLDEN = {0, sizeof(e_golden), e_golden};
+    const char *Eline = "E = ";
+
+    char id[IDLEN];
+    octet ID = {0, sizeof(id), id};
+    const char *IDline = "ID = ";
+
+    char ad[IDLEN];
+    octet AD = {0, sizeof(ad), ad};
+    octet *AD_ptr = NULL;
+    const char *ADline = "AD = ";
+
+    // Line terminating a test vector
+    const char *last_line = Eline;
+
+    fp = fopen(argv[1], "r");
+    if (fp == NULL)
+    {
+        printf("ERROR opening test vector file\n");
+        exit(EXIT_FAILURE);
+    }
+
+    while (fgets(line, LINE_LEN, fp) != NULL)
+    {
+        scan_int(&testNo, line, TESTline);
+
+        scan_OCTET(fp, &V, line, Vline);
+        scan_OCTET(fp, &C, line, Cline);
+
+        scan_OCTET(fp, &ID, line, IDline);
+        scan_OCTET(fp, &AD, line, ADline);
+
+        scan_OCTET(fp, &E_GOLDEN, line, Eline);
+
+        if (!strncmp(line, last_line, strlen(last_line)))
+        {
+            // Also input AD if it is not empty
+            AD_ptr = NULL;
+            if (AD.len > 0)
+            {
+                AD_ptr = &AD;
+            }
+
+            GG20_ZKP_phase3_challenge(&V, &C, &ID, AD_ptr, &E);
+
+            compare_OCT(fp, testNo, "GG20_ZKP_phase3_challenge", &E, &E_GOLDEN);
+
+            // Mark that at least one test vector was executed
+            test_run = 1;
+        }
+    }
+
+    fclose(fp);
+
+    if (test_run == 0)
+    {
+        printf("ERROR no test vector was executed\n");
+        exit(EXIT_FAILURE);
+    }
+
+    printf("SUCCESS\n");
+    exit(EXIT_SUCCESS);
+}
diff --git a/test/unit/test_gg20_zkp_phase3_commit.c b/test/unit/test_gg20_zkp_phase3_commit.c
new file mode 100644
index 0000000..4e0edee
--- /dev/null
+++ b/test/unit/test_gg20_zkp_phase3_commit.c
@@ -0,0 +1,94 @@
+/*
+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.
+*/
+
+/* GG20 Phase 3 ZKP commit unit test */
+
+#include <string.h>
+#include "test.h"
+#include "amcl/gg20_zkp.h"
+
+#define LINE_LEN 1024
+
+int main(int argc, char **argv)
+{
+    if (argc != 2)
+    {
+        printf("usage: ./test_gg20_zkp_phase3_commit [path to test vector file]\n");
+        exit(EXIT_FAILURE);
+    }
+
+    int test_run = 0;
+
+    FILE *fp;
+    char line[LINE_LEN] = {0};
+
+    const char *TESTline = "TEST = ";
+    int testNo = 0;
+
+    GG20_ZKP_rv r;
+    const char *Aline = "A = ";
+    const char *Bline = "B = ";
+
+    char c[GFS_SECP256K1 + 1];
+    char c_golden[GFS_SECP256K1 + 1];
+    octet C = {0, sizeof(c), c};
+    octet C_GOLDEN = {0, sizeof(c_golden), c_golden};
+    const char *Cline = "C = ";
+
+    // Line terminating a test vector
+    const char *last_line = Cline;
+
+    fp = fopen(argv[1], "r");
+    if (fp == NULL)
+    {
+        printf("ERROR opening test vector file\n");
+        exit(EXIT_FAILURE);
+    }
+
+    while (fgets(line, LINE_LEN, fp) != NULL)
+    {
+        scan_int(&testNo, line, TESTline);
+
+        scan_BIG_256_56(fp, r.a, line, Aline);
+        scan_BIG_256_56(fp, r.b, line, Bline);
+
+        scan_OCTET(fp, &C_GOLDEN, line, Cline);
+
+        if (!strncmp(line, last_line, strlen(last_line)))
+        {
+            GG20_ZKP_phase3_commit(NULL, &r, &C);
+
+            compare_OCT(fp, testNo, "GG20_ZKP_phase3_commit", &C, &C_GOLDEN);
+
+            // Mark that at least one test vector was executed
+            test_run = 1;
+        }
+    }
+
+    fclose(fp);
+
+    if (test_run == 0)
+    {
+        printf("ERROR no test vector was executed\n");
+        exit(EXIT_FAILURE);
+    }
+
+    printf("SUCCESS\n");
+    exit(EXIT_SUCCESS);
+}
diff --git a/test/unit/test_gg20_zkp_phase3_prove.c b/test/unit/test_gg20_zkp_phase3_prove.c
new file mode 100644
index 0000000..80125b1
--- /dev/null
+++ b/test/unit/test_gg20_zkp_phase3_prove.c
@@ -0,0 +1,112 @@
+/*
+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.
+*/
+
+/* GG20 Phase 3 ZKP prove unit test */
+
+#include <string.h>
+#include "test.h"
+#include "amcl/gg20_zkp.h"
+
+#define LINE_LEN 1024
+
+int main(int argc, char **argv)
+{
+    if (argc != 2)
+    {
+        printf("usage: ./test_gg20_zkp_phase3_prove [path to test vector file]\n");
+        exit(EXIT_FAILURE);
+    }
+
+    int test_run = 0;
+
+    FILE *fp;
+    char line[LINE_LEN] = {0};
+
+    const char *TESTline = "TEST = ";
+    int testNo = 0;
+
+    GG20_ZKP_rv r;
+    const char *Aline = "A = ";
+    const char *Bline = "B = ";
+
+    char e[GGS_SECP256K1];
+    octet E = {0, sizeof(e), e};
+    const char *Eline = "E = ";
+
+    char s[GGS_SECP256K1];
+    octet S = {0, sizeof(s), s};
+    const char *Sline = "S = ";
+
+    char l[GGS_SECP256K1];
+    octet L = {0, sizeof(l), l};
+    const char *Lline = "L = ";
+
+    GG20_ZKP_proof p;
+    GG20_ZKP_proof p_golden;
+    const char *Tline = "T = ";
+    const char *Uline = "U = ";
+
+    // Line terminating a test vector
+    const char *last_line = Uline;
+
+    fp = fopen(argv[1], "r");
+    if (fp == NULL)
+    {
+        printf("ERROR opening test vector file\n");
+        exit(EXIT_FAILURE);
+    }
+
+    while (fgets(line, LINE_LEN, fp) != NULL)
+    {
+        scan_int(&testNo, line, TESTline);
+
+        scan_BIG_256_56(fp, r.a, line, Aline);
+        scan_BIG_256_56(fp, r.b, line, Bline);
+
+        scan_OCTET(fp, &E, line, Eline);
+
+        scan_OCTET(fp, &S, line, Sline);
+        scan_OCTET(fp, &L, line, Lline);
+
+        scan_BIG_256_56(fp, p_golden.t, line, Tline);
+        scan_BIG_256_56(fp, p_golden.u, line, Uline);
+
+        if (!strncmp(line, last_line, strlen(last_line)))
+        {
+            GG20_ZKP_phase3_prove(&r, &E, &S, &L, &p);
+
+            compare_BIG_256_56(fp, testNo, "GG20_ZKP_phase3_prove t", p_golden.t, p.t);
+            compare_BIG_256_56(fp, testNo, "GG20_ZKP_phase3_prove u", p_golden.u, p.u);
+
+            // Mark that at least one test vector was executed
+            test_run = 1;
+        }
+    }
+
+    fclose(fp);
+
+    if (test_run == 0)
+    {
+        printf("ERROR no test vector was executed\n");
+        exit(EXIT_FAILURE);
+    }
+
+    printf("SUCCESS\n");
+    exit(EXIT_SUCCESS);
+}
diff --git a/test/unit/test_gg20_zkp_phase3_verify.c b/test/unit/test_gg20_zkp_phase3_verify.c
new file mode 100644
index 0000000..2f83dc5
--- /dev/null
+++ b/test/unit/test_gg20_zkp_phase3_verify.c
@@ -0,0 +1,120 @@
+/*
+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.
+*/
+
+/* GG20 Phase 3 ZKP verify unit test */
+
+#include <string.h>
+#include "test.h"
+#include "amcl/gg20_zkp.h"
+
+#define LINE_LEN 1024
+
+int main(int argc, char **argv)
+{
+    if (argc != 2)
+    {
+        printf("usage: ./test_gg20_zkp_phase3_verify [path to test vector file]\n");
+        exit(EXIT_FAILURE);
+    }
+
+    int rc;
+    int test_run = 0;
+
+    FILE *fp;
+    char line[LINE_LEN] = {0};
+
+    const char *TESTline = "TEST = ";
+    int testNo = 0;
+
+    char v[GFS_SECP256K1 + 1];
+    octet V = {0, sizeof(v), v};
+    const char *Vline = "V = ";
+
+    char c[GFS_SECP256K1 + 1];
+    octet C = {0, sizeof(c), c};
+    const char *Cline = "C = ";
+
+    char e[GGS_SECP256K1];
+    octet E = {0, sizeof(e), e};
+    const char *Eline = "E = ";
+
+    GG20_ZKP_proof p;
+    const char *Tline = "T = ";
+    const char *Uline = "U = ";
+
+    // Line terminating a test vector
+    const char *last_line = Uline;
+
+    fp = fopen(argv[1], "r");
+    if (fp == NULL)
+    {
+        printf("ERROR opening test vector file\n");
+        exit(EXIT_FAILURE);
+    }
+
+    /* Test Happy Path using test vectors */
+
+    while (fgets(line, LINE_LEN, fp) != NULL)
+    {
+        scan_int(&testNo, line, TESTline);
+
+        scan_OCTET(fp, &V, line, Vline);
+        scan_OCTET(fp, &C, line, Cline);
+        scan_OCTET(fp, &E, line, Eline);
+
+        scan_BIG_256_56(fp, p.t, line, Tline);
+        scan_BIG_256_56(fp, p.u, line, Uline);
+
+        if (!strncmp(line, last_line, strlen(last_line)))
+        {
+            rc = GG20_ZKP_phase3_verify(&V, &C, &E, &p);
+
+            assert_tv(fp, testNo, "GG20_ZKP_phase3_verify", rc == GG20_ZKP_OK);
+
+            // Mark that at least one test vector was executed
+            test_run = 1;
+        }
+    }
+
+    fclose(fp);
+
+    if (test_run == 0)
+    {
+        printf("ERROR no test vector was executed\n");
+        exit(EXIT_FAILURE);
+    }
+
+    /* Test unhappy paths */
+
+    // Test Invalid V
+    rc = GG20_ZKP_phase3_verify(&E, &C, &E, &p);
+    assert(fp, "GG20_ZKP_phase3 verify invalid V", rc == GG20_ZKP_INVALID_ECP);
+
+    // Test Invalid C
+    rc = GG20_ZKP_phase3_verify(&V, &E, &E, &p);
+    assert(fp, "GG20_ZKP_phase3 verify invalid C", rc == GG20_ZKP_INVALID_ECP);
+
+    // Test invalid Proof
+    BIG_256_56_zero(p.t);
+    rc = GG20_ZKP_phase3_verify(&V, &C, &E, &p);
+    assert(fp, "GG20_ZKP_phase3 verify invalid proof", rc == GG20_ZKP_FAIL);
+
+    printf("SUCCESS\n");
+    exit(EXIT_SUCCESS);
+}
diff --git a/test/unit/test_gg20_zkp_phase6_challenge.c b/test/unit/test_gg20_zkp_phase6_challenge.c
new file mode 100644
index 0000000..77bb61e
--- /dev/null
+++ b/test/unit/test_gg20_zkp_phase6_challenge.c
@@ -0,0 +1,131 @@
+/*
+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.
+*/
+
+/* GG20 Phase 6 ZKP challenge unit test */
+
+#include <string.h>
+#include "test.h"
+#include "amcl/gg20_zkp.h"
+
+#define LINE_LEN 1024
+#define IDLEN 16
+#define ADLEN 16
+
+int main(int argc, char **argv)
+{
+    if (argc != 2)
+    {
+        printf("usage: ./test_gg20_zkp_phase6_challenge [path to test vector file]\n");
+        exit(EXIT_FAILURE);
+    }
+
+    int test_run = 0;
+
+    FILE *fp;
+    char line[LINE_LEN] = {0};
+
+    const char *TESTline = "TEST = ";
+    int testNo = 0;
+
+    char r[GFS_SECP256K1 + 1];
+    octet R = {0, sizeof(r), r};
+    const char *Rline = "R = ";
+
+    char t[GFS_SECP256K1 + 1];
+    octet T = {0, sizeof(t), t};
+    const char *ECPTline = "ECPT = ";
+
+    char s[GFS_SECP256K1 + 1];
+    octet S = {0, sizeof(s), s};
+    const char *Sline = "ECPS = ";
+
+    GG20_ZKP_phase6_commitment c;
+    const char *ALPHAline = "ALPHA = ";
+    const char *BETAline = "BETA = ";
+
+    char e[GGS_SECP256K1];
+    char e_golden[GGS_SECP256K1];
+    octet E = {0, sizeof(e), e};
+    octet E_GOLDEN = {0, sizeof(e_golden), e_golden};
+    const char *Eline = "E = ";
+
+    char id[IDLEN];
+    octet ID = {0, sizeof(id), id};
+    const char *IDline = "ID = ";
+
+    char ad[IDLEN];
+    octet AD = {0, sizeof(ad), ad};
+    octet *AD_ptr = NULL;
+    const char *ADline = "AD = ";
+
+    // Line terminating a test vector
+    const char *last_line = Eline;
+
+    fp = fopen(argv[1], "r");
+    if (fp == NULL)
+    {
+        printf("ERROR opening test vector file\n");
+        exit(EXIT_FAILURE);
+    }
+
+    while (fgets(line, LINE_LEN, fp) != NULL)
+    {
+        scan_int(&testNo, line, TESTline);
+
+        scan_OCTET(fp, &R, line, Rline);
+        scan_OCTET(fp, &T, line, ECPTline);
+        scan_OCTET(fp, &S, line, Sline);
+
+        scan_ECP_SECP256K1(fp, &(c.ALPHA), line, ALPHAline);
+        scan_ECP_SECP256K1(fp, &(c.BETA),  line, BETAline);
+
+        scan_OCTET(fp, &ID, line, IDline);
+        scan_OCTET(fp, &AD, line, ADline);
+
+        scan_OCTET(fp, &E_GOLDEN, line, Eline);
+
+        if (!strncmp(line, last_line, strlen(last_line)))
+        {
+            // Also input AD if it is not empty
+            AD_ptr = NULL;
+            if (AD.len > 0)
+            {
+                AD_ptr = &AD;
+            }
+
+            GG20_ZKP_phase6_challenge(&R, &T, &S, &c, &ID, AD_ptr, &E);
+
+            compare_OCT(fp, testNo, "GG20_ZKP_phase6_challenge", &E, &E_GOLDEN);
+
+            // Mark that at least one test vector was executed
+            test_run = 1;
+        }
+    }
+
+    fclose(fp);
+
+    if (test_run == 0)
+    {
+        printf("ERROR no test vector was executed\n");
+        exit(EXIT_FAILURE);
+    }
+
+    printf("SUCCESS\n");
+    exit(EXIT_SUCCESS);
+}
diff --git a/test/unit/test_gg20_zkp_phase6_commit.c b/test/unit/test_gg20_zkp_phase6_commit.c
new file mode 100644
index 0000000..d7a8960
--- /dev/null
+++ b/test/unit/test_gg20_zkp_phase6_commit.c
@@ -0,0 +1,110 @@
+/*
+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.
+*/
+
+/* GG20 Phase 6 ZKP commit unit test */
+
+#include <string.h>
+#include "test.h"
+#include "amcl/gg20_zkp.h"
+
+#define LINE_LEN 1024
+
+int main(int argc, char **argv)
+{
+    if (argc != 2)
+    {
+        printf("usage: ./test_gg20_zkp_phase6_commit [path to test vector file]\n");
+        exit(EXIT_FAILURE);
+    }
+
+    int rc;
+    int test_run = 0;
+
+    FILE *fp;
+    char line[LINE_LEN] = {0};
+
+    const char *TESTline = "TEST = ";
+    int testNo = 0;
+
+    char r[GFS_SECP256K1 + 1];
+    octet R = {0, sizeof(r), r};
+    const char *Rline = "R = ";
+
+    GG20_ZKP_rv rv;
+    const char *Aline = "A = ";
+    const char *Bline = "B = ";
+
+    GG20_ZKP_phase6_commitment c;
+    GG20_ZKP_phase6_commitment c_golden;
+    const char *ALPHAline = "ALPHA = ";
+    const char *BETAline = "BETA = ";
+
+    // Line terminating a test vector
+    const char *last_line = BETAline;
+
+    fp = fopen(argv[1], "r");
+    if (fp == NULL)
+    {
+        printf("ERROR opening test vector file\n");
+        exit(EXIT_FAILURE);
+    }
+
+    while (fgets(line, LINE_LEN, fp) != NULL)
+    {
+        scan_int(&testNo, line, TESTline);
+
+        scan_OCTET(fp, &R, line, Rline);
+
+        scan_BIG_256_56(fp, rv.a, line, Aline);
+        scan_BIG_256_56(fp, rv.b, line, Bline);
+
+        scan_ECP_SECP256K1(fp, &(c_golden.ALPHA), line, ALPHAline);
+        scan_ECP_SECP256K1(fp, &(c_golden.BETA),  line, BETAline);
+
+        if (!strncmp(line, last_line, strlen(last_line)))
+        {
+            rc = GG20_ZKP_phase6_commit(NULL, &R, &rv, &c);
+            assert_tv(fp, testNo, "GG20_ZKP_phase6_commit", rc == GG20_ZKP_OK);
+
+            compare_ECP_SECP256K1(fp, testNo, "GG20_ZKP_phase6_commit ALPHA", &(c.ALPHA), &(c_golden.ALPHA));
+            compare_ECP_SECP256K1(fp, testNo, "GG20_ZKP_phase6_commit BETA",  &(c.BETA),  &(c_golden.BETA));
+
+            // Mark that at least one test vector was executed
+            test_run = 1;
+        }
+    }
+
+    fclose(fp);
+
+    if (test_run == 0)
+    {
+        printf("ERROR no test vector was executed\n");
+        exit(EXIT_FAILURE);
+    }
+
+    /* Test unhappy paths */
+
+    // Test invalid R
+    R.val[0] = 0xFF;
+    rc = GG20_ZKP_phase6_commit(NULL, &R, &rv, &c);
+    assert(NULL, "GG20_ZKP_phase6_commit invalid R", rc == GG20_ZKP_INVALID_ECP);
+
+    printf("SUCCESS\n");
+    exit(EXIT_SUCCESS);
+}
diff --git a/test/unit/test_gg20_zkp_phase6_prove.c b/test/unit/test_gg20_zkp_phase6_prove.c
new file mode 100644
index 0000000..1cda369
--- /dev/null
+++ b/test/unit/test_gg20_zkp_phase6_prove.c
@@ -0,0 +1,112 @@
+/*
+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.
+*/
+
+/* GG20 Phase 6 ZKP prove unit test */
+
+#include <string.h>
+#include "test.h"
+#include "amcl/gg20_zkp.h"
+
+#define LINE_LEN 1024
+
+int main(int argc, char **argv)
+{
+    if (argc != 2)
+    {
+        printf("usage: ./test_gg20_zkp_phase6_prove [path to test vector file]\n");
+        exit(EXIT_FAILURE);
+    }
+
+    int test_run = 0;
+
+    FILE *fp;
+    char line[LINE_LEN] = {0};
+
+    const char *TESTline = "TEST = ";
+    int testNo = 0;
+
+    GG20_ZKP_rv r;
+    const char *Aline = "A = ";
+    const char *Bline = "B = ";
+
+    char e[GGS_SECP256K1];
+    octet E = {0, sizeof(e), e};
+    const char *Eline = "E = ";
+
+    char s[GGS_SECP256K1];
+    octet S = {0, sizeof(s), s};
+    const char *Sline = "S = ";
+
+    char l[GGS_SECP256K1];
+    octet L = {0, sizeof(l), l};
+    const char *Lline = "L = ";
+
+    GG20_ZKP_proof p;
+    GG20_ZKP_proof p_golden;
+    const char *Tline = "T = ";
+    const char *Uline = "U = ";
+
+    // Line terminating a test vector
+    const char *last_line = Uline;
+
+    fp = fopen(argv[1], "r");
+    if (fp == NULL)
+    {
+        printf("ERROR opening test vector file\n");
+        exit(EXIT_FAILURE);
+    }
+
+    while (fgets(line, LINE_LEN, fp) != NULL)
+    {
+        scan_int(&testNo, line, TESTline);
+
+        scan_BIG_256_56(fp, r.a, line, Aline);
+        scan_BIG_256_56(fp, r.b, line, Bline);
+
+        scan_OCTET(fp, &E, line, Eline);
+
+        scan_OCTET(fp, &S, line, Sline);
+        scan_OCTET(fp, &L, line, Lline);
+
+        scan_BIG_256_56(fp, p_golden.t, line, Tline);
+        scan_BIG_256_56(fp, p_golden.u, line, Uline);
+
+        if (!strncmp(line, last_line, strlen(last_line)))
+        {
+            GG20_ZKP_phase6_prove(&r, &E, &S, &L, &p);
+
+            compare_BIG_256_56(fp, testNo, "GG20_ZKP_phase6_prove t", p_golden.t, p.t);
+            compare_BIG_256_56(fp, testNo, "GG20_ZKP_phase6_prove u", p_golden.u, p.u);
+
+            // Mark that at least one test vector was executed
+            test_run = 1;
+        }
+    }
+
+    fclose(fp);
+
+    if (test_run == 0)
+    {
+        printf("ERROR no test vector was executed\n");
+        exit(EXIT_FAILURE);
+    }
+
+    printf("SUCCESS\n");
+    exit(EXIT_SUCCESS);
+}
diff --git a/test/unit/test_gg20_zkp_phase6_verify.c b/test/unit/test_gg20_zkp_phase6_verify.c
new file mode 100644
index 0000000..773ccc5
--- /dev/null
+++ b/test/unit/test_gg20_zkp_phase6_verify.c
@@ -0,0 +1,143 @@
+/*
+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.
+*/
+
+/* GG20 Phase 3 ZKP verify unit test */
+
+#include <string.h>
+#include "test.h"
+#include "amcl/gg20_zkp.h"
+
+#define LINE_LEN 1024
+
+int main(int argc, char **argv)
+{
+    if (argc != 2)
+    {
+        printf("usage: ./test_gg20_zkp_phase3_verify [path to test vector file]\n");
+        exit(EXIT_FAILURE);
+    }
+
+    int rc;
+    int test_run = 0;
+
+    FILE *fp;
+    char line[LINE_LEN] = {0};
+
+    const char *TESTline = "TEST = ";
+    int testNo = 0;
+
+    char r[GFS_SECP256K1 + 1];
+    octet R = {0, sizeof(r), r};
+    const char *Rline = "R = ";
+
+    char t[GFS_SECP256K1 + 1];
+    octet T = {0, sizeof(t), t};
+    const char *ECPTline = "ECPT = ";
+
+    char s[GFS_SECP256K1 + 1];
+    octet S = {0, sizeof(s), s};
+    const char *ECPSline = "ECPS = ";
+
+    GG20_ZKP_phase6_commitment c;
+    const char *ALPHAline = "ALPHA = ";
+    const char *BETAline = "BETA = ";
+
+    char e[GGS_SECP256K1];
+    octet E = {0, sizeof(e), e};
+    const char *Eline = "E = ";
+
+    GG20_ZKP_proof p;
+    const char *Tline = "T = ";
+    const char *Uline = "U = ";
+
+    // Line terminating a test vector
+    const char *last_line = Uline;
+
+    fp = fopen(argv[1], "r");
+    if (fp == NULL)
+    {
+        printf("ERROR opening test vector file\n");
+        exit(EXIT_FAILURE);
+    }
+
+    /* Test Happy Path using test vectors */
+
+    while (fgets(line, LINE_LEN, fp) != NULL)
+    {
+        scan_int(&testNo, line, TESTline);
+
+        scan_OCTET(fp, &R, line, Rline);
+        scan_OCTET(fp, &T, line, ECPTline);
+        scan_OCTET(fp, &S, line, ECPSline);
+
+        scan_ECP_SECP256K1(fp, &(c.ALPHA), line, ALPHAline);
+        scan_ECP_SECP256K1(fp, &(c.BETA),  line, BETAline);
+
+        scan_OCTET(fp, &E, line, Eline);
+
+        scan_BIG_256_56(fp, p.t, line, Tline);
+        scan_BIG_256_56(fp, p.u, line, Uline);
+
+        if (!strncmp(line, last_line, strlen(last_line)))
+        {
+            rc = GG20_ZKP_phase6_verify(&R, &T, &S, &c, &E, &p);
+            assert_tv(fp, testNo, "GG20_ZKP_phase6_verify", rc == GG20_ZKP_OK);
+
+            // Mark that at least one test vector was executed
+            test_run = 1;
+        }
+    }
+
+    fclose(fp);
+
+    if (test_run == 0)
+    {
+        printf("ERROR no test vector was executed\n");
+        exit(EXIT_FAILURE);
+    }
+
+    /* Test unhappy paths */
+
+    // Test Invalid R
+    rc = GG20_ZKP_phase6_verify(&E, &T, &S, &c, &E, &p);
+    assert(fp, "GG20_ZKP_phase6 verify invalid R", rc == GG20_ZKP_INVALID_ECP);
+
+    // Test Invalid T
+    rc = GG20_ZKP_phase6_verify(&R, &E, &S, &c, &E, &p);
+    assert(fp, "GG20_ZKP_phase6 verify invalid E", rc == GG20_ZKP_INVALID_ECP);
+
+    // Test Invalid S
+    rc = GG20_ZKP_phase6_verify(&R, &T, &E, &c, &E, &p);
+    assert(fp, "GG20_ZKP_phase6 verify invalid S", rc == GG20_ZKP_INVALID_ECP);
+
+    // Test invalid Proof u
+    BIG_256_56_inc(p.u, 1);
+    rc = GG20_ZKP_phase6_verify(&R, &T, &S, &c, &E, &p);
+    assert(fp, "GG20_ZKP_phase3 verify invalid proof u", rc == GG20_ZKP_FAIL);
+    BIG_256_56_dec(p.u, 1);
+
+    // Test invalid Proof t
+    BIG_256_56_inc(p.t, 1);
+    rc = GG20_ZKP_phase6_verify(&R, &T, &S, &c, &E, &p);
+    assert(fp, "GG20_ZKP_phase3 verify invalid proof t", rc == GG20_ZKP_FAIL);
+    BIG_256_56_dec(p.t, 1);
+
+    printf("SUCCESS\n");
+    exit(EXIT_SUCCESS);
+}
diff --git a/test/unit/test_ggn.c b/test/unit/test_ggn.c
new file mode 100644
index 0000000..0f69d9b
--- /dev/null
+++ b/test/unit/test_ggn.c
@@ -0,0 +1,155 @@
+/*
+    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 <string.h>
+#include "test.h"
+#include "amcl/ggn.h"
+
+/* GGN Proof unit tests */
+
+#define LINE_LEN 2048
+#define IDLEN 16
+#define ADLEN 16
+
+int main(int argc, char **argv)
+{
+    if (argc != 2)
+    {
+        printf("usage: ./test_GGN [path to test vector file]\n");
+        exit(EXIT_FAILURE);
+    }
+
+    int test_run = 0;
+
+    FILE *fp;
+    char line[LINE_LEN] = {0};
+
+    const char *TESTline = "TEST = ";
+    int testNo = 0;
+
+    GGN_commitment co;
+    const char *Zline = "Z = ";
+    const char *U1line = "U1 = ";
+    const char *U2line = "U2 = ";
+    const char *U3line = "U3 = ";
+
+    BIT_COMMITMENT_pub mod;
+    const char *NTline = "NT = ";
+    const char *H1line = "H1 = ";
+    const char *H2line = "H2 = ";
+
+    PAILLIER_public_key pub;
+    const char *Nline = "N = ";
+
+    char c[2*FS_2048];
+    octet C = {0, sizeof(c), c};
+    const char *Cline = "C = ";
+
+    char ecpr[EGS_SECP256K1 + 1];
+    octet ECPR = {0, sizeof(ecpr), ecpr};
+    const char *ECPRline = "ECPR = ";
+
+    char ecprt[EGS_SECP256K1 + 1];
+    octet ECPRt = {0, sizeof(ecprt), ecprt};
+    const char *ECPRtline = "ECPRT = ";
+
+    char e_golden[MODBYTES_512_60];
+    octet E_GOLDEN = {0, sizeof(e_golden), e_golden};
+    const char *Eline = "E = ";
+
+    char e[MODBYTES_512_60];
+    octet E = {0, sizeof(e), e};
+
+    char id[IDLEN];
+    octet ID = {0, sizeof(id), id};
+    const char *IDline = "ID = ";
+
+    char ad[ADLEN];
+    octet AD = {0, sizeof(ad), ad};
+    octet *AD_ptr = NULL;
+    const char *ADline = "AD = ";
+
+    // Line terminating a test vector
+    const char *last_line = Eline;
+
+    /* Test happy path using test vectors */
+    fp = fopen(argv[1], "r");
+    if (fp == NULL)
+    {
+        printf("ERROR opening test vector file\n");
+        exit(EXIT_FAILURE);
+    }
+
+    while (fgets(line, LINE_LEN, fp) != NULL)
+    {
+        scan_int(&testNo, line, TESTline);
+
+        // Read ID and AD
+        scan_OCTET(fp, &ID, line, IDline);
+        scan_OCTET(fp, &AD, line, ADline);
+
+        // Read inputs
+        scan_OCTET(fp, &C, line, Cline);
+        scan_OCTET(fp, &ECPR,  line, ECPRline);
+        scan_OCTET(fp, &ECPRt,  line, ECPRtline);
+
+        scan_FF_2048(fp, mod.b0, line, H1line, FFLEN_2048);
+        scan_FF_2048(fp, mod.b1, line, H2line, FFLEN_2048);
+        scan_FF_2048(fp, mod.N, line, NTline, FFLEN_2048);
+
+        scan_FF_2048(fp, co.c.z, line, Zline, FFLEN_2048);
+        scan_FF_4096(fp, co.c.u, line, U2line, FFLEN_4096);
+        scan_FF_2048(fp, co.c.w, line, U3line, FFLEN_2048);
+
+        scan_ECP_SECP256K1(fp, &(co.u1), line, U1line);
+
+        scan_FF_4096(fp, pub.n, line, Nline, HFLEN_4096);
+
+        // Read ground truth
+        scan_OCTET(fp, &E_GOLDEN, line, Eline);
+
+        if (!strncmp(line, last_line, strlen(last_line)))
+        {
+            // Also input AD if it is not empty
+            AD_ptr = NULL;
+            if (AD.len > 0)
+            {
+                AD_ptr = &AD;
+            }
+
+            GGN_challenge(&pub, &mod, &ECPR, &ECPRt, &C, &co, &ID, AD_ptr, &E);
+
+            compare_OCT(fp, testNo, "GGN_challenge. E", &E, &E_GOLDEN);
+
+            // Mark that at least one test vector was executed
+            test_run = 1;
+        }
+    }
+
+    fclose(fp);
+
+    if (test_run == 0)
+    {
+        printf("ERROR no test vector was executed\n");
+        exit(EXIT_FAILURE);
+    }
+
+    printf("SUCCESS");
+    exit(EXIT_SUCCESS);
+}
diff --git a/test/unit/test_gmr_octets.c b/test/unit/test_gmr_octets.c
new file mode 100644
index 0000000..8e2704b
--- /dev/null
+++ b/test/unit/test_gmr_octets.c
@@ -0,0 +1,104 @@
+/*
+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.
+*/
+
+/* GMR ZKP of Square Freeness octet functions unit test */
+
+#include <string.h>
+#include "test.h"
+#include "amcl/gmr.h"
+
+#define LINE_LEN 65555
+#define IDLEN 16
+#define ADLEN 16
+
+int main(int argc, char **argv)
+{
+    if (argc != 2)
+    {
+        printf("usage: ./test_gmr_octets [path to test vector file]\n");
+        exit(EXIT_FAILURE);
+    }
+
+    int test_run = 0;
+    int rc;
+
+    FILE *fp;
+    char line[LINE_LEN] = {0};
+
+    const char *TESTline = "TEST = ";
+    int testNo = 0;
+
+    GMR_proof Y;
+
+    char yoct[GMR_PROOF_SIZE];
+    char yoct_golden[GMR_PROOF_SIZE];
+    octet YOCT = {0, sizeof(yoct), yoct};
+    octet YOCT_GOLDEN = {0, sizeof(yoct_golden), yoct_golden};
+    const char *Yline = "Y = ";
+
+    // Line terminating a test vector
+    const char *last_line = Yline;
+
+    fp = fopen(argv[1], "r");
+    if (fp == NULL)
+    {
+        printf("ERROR opening test vector file\n");
+        exit(EXIT_FAILURE);
+    }
+
+    while (fgets(line, LINE_LEN, fp) != NULL)
+    {
+        scan_int(&testNo, line, TESTline);
+
+        // Read proof
+        scan_OCTET(fp, &YOCT_GOLDEN, line, Yline);
+
+        if (!strncmp(line, last_line, strlen(last_line)))
+        {
+            rc = GMR_proof_fromOctet(Y, &YOCT_GOLDEN);
+            assert_tv(fp, testNo, "Error reading Y from TV", rc == GMR_OK);
+
+            GMR_proof_toOctet(&YOCT, Y);
+
+            compare_OCT(fp, testNo, "GMR octets consistency", &YOCT, &YOCT_GOLDEN);
+
+            // Mark that at least one test vector was executed
+            test_run = 1;
+        }
+    }
+
+    fclose(fp);
+
+    if (test_run == 0)
+    {
+        printf("ERROR no test vector was executed\n");
+        exit(EXIT_FAILURE);
+    }
+
+    /* Test unhappy path */
+
+    // Invalid Proof Format
+    YOCT.len--;
+
+    rc = GMR_proof_fromOctet(Y, &YOCT);
+    assert_tv(fp, testNo, "GMR proof_fromOctet invalid format", rc == GMR_INVALID_PROOF);
+
+    printf("SUCCESS\n");
+    exit(EXIT_SUCCESS);
+}
diff --git a/test/unit/test_gmr_prove.c b/test/unit/test_gmr_prove.c
new file mode 100644
index 0000000..aab613e
--- /dev/null
+++ b/test/unit/test_gmr_prove.c
@@ -0,0 +1,131 @@
+/*
+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.
+*/
+
+/* GMR ZKP of Square Freeness proof unit test */
+
+#include <string.h>
+#include "test.h"
+#include "amcl/gmr.h"
+
+#define LINE_LEN 65555
+#define IDLEN 16
+#define ADLEN 16
+
+int main(int argc, char **argv)
+{
+    if (argc != 2)
+    {
+        printf("usage: ./test_gmr_prove [path to test vector file]\n");
+        exit(EXIT_FAILURE);
+    }
+
+    int test_run = 0;
+
+    FILE *fp;
+    char line[LINE_LEN] = {0};
+
+    const char *TESTline = "TEST = ";
+    int testNo = 0;
+
+    char p[HFS_2048];
+    octet P = {0, sizeof(p), p};
+    const char *Pline = "P = ";
+
+    char q[HFS_2048];
+    octet Q = {0, sizeof(q), q};
+    const char *Qline = "Q = ";
+
+    char id[IDLEN];
+    octet ID = {0, sizeof(id), id};
+    const char *IDline = "ID = ";
+
+    char ad[ADLEN];
+    octet AD = {0, sizeof(ad), ad};
+    octet *AD_ptr = NULL;
+    const char *ADline = "AD = ";
+
+    GMR_proof Y;
+    char ygolden[GMR_PROOF_SIZE];
+    octet YGOLDEN = {0, sizeof(ygolden), ygolden};
+    char yoct[GMR_PROOF_SIZE];
+    octet YOCT = {0, sizeof(yoct), yoct};
+    const char *Yline = "Y = ";
+
+    MODULUS_priv m;
+
+    // Line terminating a test vector
+    const char *last_line = Yline;
+
+    fp = fopen(argv[1], "r");
+    if (fp == NULL)
+    {
+        printf("ERROR opening test vector file\n");
+        exit(EXIT_FAILURE);
+    }
+
+    while (fgets(line, LINE_LEN, fp) != NULL)
+    {
+        scan_int(&testNo, line, TESTline);
+
+        // Read ID and AD
+        scan_OCTET(fp, &ID, line, IDline);
+        scan_OCTET(fp, &AD, line, ADline);
+
+        // Read modulus
+        scan_OCTET(fp, &P, line, Pline);
+        scan_OCTET(fp, &Q, line, Qline);
+
+        // Read ground truth
+        scan_OCTET(fp, &YGOLDEN, line, Yline);
+
+        if (!strncmp(line, last_line, strlen(last_line)))
+        {
+            // Also input AD if it is not empty
+            if (AD.len > 0)
+            {
+                AD_ptr = &AD;
+            }
+
+            MODULUS_fromOctets(&m, &P, &Q);
+
+            GMR_prove(&m, &ID, AD_ptr, Y);
+
+            GMR_proof_toOctet(&YOCT, Y);
+
+            compare_OCT(fp, testNo, "GMR_prove Y", &YOCT, &YGOLDEN);
+
+            // Mark that at least one test vector was executed
+            test_run = 1;
+
+            // Restore AD_ptr
+            AD_ptr = NULL;
+        }
+    }
+
+    fclose(fp);
+
+    if (test_run == 0)
+    {
+        printf("ERROR no test vector was executed\n");
+        exit(EXIT_FAILURE);
+    }
+
+    printf("SUCCESS\n");
+    exit(EXIT_SUCCESS);
+}
diff --git a/test/unit/test_gmr_verify.c b/test/unit/test_gmr_verify.c
new file mode 100644
index 0000000..81ffe92
--- /dev/null
+++ b/test/unit/test_gmr_verify.c
@@ -0,0 +1,144 @@
+/*
+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.
+*/
+
+/* GMR ZKP of Square Freeness verification unit test */
+
+#include <string.h>
+#include "test.h"
+#include "amcl/gmr.h"
+
+#define LINE_LEN 65555
+#define IDLEN 16
+#define ADLEN 16
+
+int main(int argc, char **argv)
+{
+    if (argc != 2)
+    {
+        printf("usage: ./test_gmr_verify [path to test vector file]\n");
+        exit(EXIT_FAILURE);
+    }
+
+    int test_run = 0;
+    int rc;
+
+    FILE *fp;
+    char line[LINE_LEN] = {0};
+
+    const char *TESTline = "TEST = ";
+    int testNo = 0;
+
+    char n[FS_2048];
+    octet N = {0, sizeof(n), n};
+    const char *Nline = "N = ";
+
+    char id[IDLEN];
+    octet ID = {0, sizeof(id), id};
+    const char *IDline = "ID = ";
+
+    char ad[ADLEN];
+    octet AD = {0, sizeof(ad), ad};
+    octet *AD_ptr = NULL;
+    const char *ADline = "AD = ";
+
+    GMR_proof Y;
+    char yoct[GMR_PROOF_SIZE];
+    octet YOCT = {0, sizeof(yoct), yoct};
+    const char *Yline = "Y = ";
+
+    // Line terminating a test vector
+    const char *last_line = Yline;
+
+    fp = fopen(argv[1], "r");
+    if (fp == NULL)
+    {
+        printf("ERROR opening test vector file\n");
+        exit(EXIT_FAILURE);
+    }
+
+    while (fgets(line, LINE_LEN, fp) != NULL)
+    {
+        scan_int(&testNo, line, TESTline);
+
+        // Read ID and AD
+        scan_OCTET(fp, &ID, line, IDline);
+        scan_OCTET(fp, &AD, line, ADline);
+
+        // Read modulus
+        scan_OCTET(fp, &N, line, Nline);
+
+        // Read proof
+        scan_OCTET(fp, &YOCT, line, Yline);
+
+        if (!strncmp(line, last_line, strlen(last_line)))
+        {
+            // Also input AD if it is not empty
+            if (AD.len > 0)
+            {
+                AD_ptr = &AD;
+            }
+
+            rc = GMR_proof_fromOctet(Y, &YOCT);
+            assert_tv(fp, testNo, "Error reading Y from TV", rc == GMR_OK);
+
+            rc = GMR_verify(&N, Y, &ID, AD_ptr);
+            assert_tv(fp, testNo, "GMR verify", rc == GMR_OK);
+
+            // Mark that at least one test vector was executed
+            test_run = 1;
+
+            // Restore AD_ptr
+            AD_ptr = NULL;
+        }
+    }
+
+    fclose(fp);
+
+    if (test_run == 0)
+    {
+        printf("ERROR no test vector was executed\n");
+        exit(EXIT_FAILURE);
+    }
+
+    /* Test unhappy path */
+
+    // Invalid Proof
+    FF_2048_inc(Y[0], 1, FFLEN_2048);
+
+    rc = GMR_verify(&N, Y, &ID, AD_ptr);
+    assert_tv(fp, testNo, "GMR verify invalid proof", rc == GMR_FAIL);
+
+    FF_2048_dec(Y[0], 1, FFLEN_2048);
+
+    // N even
+    N.val[N.len-1] = '2';
+
+    rc = GMR_verify(&N, Y, &ID, AD_ptr);
+    assert_tv(fp, testNo, "GMR verify N is even", rc == GMR_FAIL);
+
+    // N has small factor (809 * 907)
+    OCT_fromHex(&N, "b3243");
+    OCT_pad(&N, FS_2048);
+
+    rc = GMR_verify(&N, Y, &ID, AD_ptr);
+    assert_tv(fp, testNo, "GMR verify N has small factor", rc == GMR_FAIL);
+
+    printf("SUCCESS\n");
+    exit(EXIT_SUCCESS);
+}
diff --git a/testVectors/ggn/challenge.json b/testVectors/ggn/challenge.json
new file mode 100644
index 0000000..279a478
--- /dev/null
+++ b/testVectors/ggn/challenge.json
@@ -0,0 +1,172 @@
+[
+  {
+    "TEST": 0,
+    "N": "921a553a20aa7e4cecdbc09d582ec1f0a7be36c8ab42f8fee848e8f27d4a2a7944a38d164d3aa60138288a53906db199cf1281c2e37fa6241bad302bfd61a6ea62420284243bb5122b1d7be76a5049069b733e37b4ef597450c8f541916dea02ecda99af27f4060aba4b681daa2e8d201aeafda76fff30d189182659658f058728b280c7b9defb8eec0459905cb2fbe36da65041fe98ab43f499349f71bc06cc6a77cb1578c550bd73ed59ebe6339114392031fce2288c9382e126c9f7247a1b30300a37c7c68aad6261f583ca9576ea37a092031dd32c4dadbcc5172f580bdd11ebc194ae42076c83790d7f6ee4e387ed [...]
+    "NT": "b5eed17dc8d2b334110128bd1b19e58d97c3286e2505283a9f8d060527e8aa76b08771ca8b16ac020b4e022f85f70422abe7ea8f78a0e066188a2ca022a01af3ab93b7c39ba2558425664ae00a3ac13540b9e73ffd44973fd0ed9030850d242cdbd7c8825ef164eb04de336f3e9565b3b9fedefcf5269f54c68d5d2751bd77142f2ddbe3eda0fb68f2397899515057729b7ef88e7c8a459f88b39c33592cd2d95461185522c90c4d8b0feed1c9d4e1d68b7eff16d0439b2a687b24b242521ef3af8ed11151e3b8d50bddf39d90d0d34ba6a13ddec9b0b1cea034ac6c87d9e550335b8e8268094770d137d022d51122dba [...]
+    "H1": "87c24f97195f07c03127004de18a7c538244cc16ca760e983e2c4d36c42474b57de39cb95c841e409251db6ba3e7bcd8f2dc69e8710fa0d41429d4296f95fcf17dfc10b5567241708d006ebcf1afedcb83b7f3f36f72604329b80014522a27986bf80ad6816ba9be7d33f766fe31c9d4412b4a19d306936b12f9d1a2b33c18e049334a1be9b0f90a806f82d5fbc00042960abd308930517df3683c7f364e91f10e384b15b675bea81248daf3feebf7c8a3b546a7cd1b8a41c8fb896cf3edc3585fe69da1573c620169928cee2f723c99c42267c4602e33e64e2dc152349ef954c03fbe052a9afb6308a7b8f6b37dffdc6 [...]
+    "H2": "8c100b902bb70c26c9388074cdcc67ef7a72d93b938f8efcfc2d6f6344e5ac12a9f0528372ae6423e688e0d2b0a6f391db56c9e3941cc68846553dcfe445ecd5db28df078e06e64b83c86cabe60e3243e9de6689ef8197a4e77ed51282ad0813e721d050efdd8b01dbc94fa34b1565da3c2eb59ed65939433dae5019ab57aa5f9ab433c00fbc63075650743f2a92d9b3cd4b3d3603cd28b8474073b628197a01d676c54696f7399ab18fe896589f81c4c8f9d80ab12c19373416a12a4ca3ec86eef17f2b6b025bd251cfcaee2e148552dfb40b2db0b8abbca02448cbc9697ec540a69a1b91866004e7e91cf545ae7cde2 [...]
+    "C": "0ac4d82997f0af02db5d2dfb734217b19ab54f698235c38d650a9d95d8d6f07f881b5df9afe5f2e2a49f80676ecd2ccb6ed668b904ed56652c708d766c6a083b469c0b2c10eb7b5626d613eff7d4a04af0e2c5ca67253a1ab515403581b756f909ea8f150615940dc432e0d7a7a954623becf6c7366448913cd317374b272b43de1b0f314a960c97365318bdd5aada878836ceb4580f5569f4bb36e6c2e46a218e569a33addca33a61f37def248e89f2e2a588b0ab1cf0c3061907794a839653ed95cf848f594c40f988f70f02798330dd9c65b9707263691710b84ffc72899408e76a931a757e04ab062e460fdc00c258 [...]
+    "ECPR": "02b25c0d104075e6177b2291246dbd191d2e54a82388131f6fd5f9ee833027558b",
+    "ECPRT": "0318fdca12289e48b050567ae7c2aaf7a8a85e6f6fa2cdd4df8a24c09240e47424",
+    "Z": "841fbdb92f421ad6e93a8fb22fe0be4287125494e8fcb703f1f35595cc601d94fb89297de4f22e732705d2d2d9fb92ecaa814d098919b4c8e5a2339b2437c4038ea8ce7c860b8bee2e81193129e643109e43a3f4e3952bac09b461912e0aa1226aa1f310cbc86b3dd92f79d46aba90481305838022086fc69479c25635f6cc0265b53225b062111db13f26c99c963ccfbb2ca9d2f66c118ec0ac65ba662a6513a9b2cbc72938ae5e369ec8ddba054423e948fd7bb916bc7e1193f345cb4a8c74a6dd60a0c0d629c0c5ab9bc1d0b3a91cf9e69511437d02ff3be25271a6e7053db33885c26516323eeed1696d032b72bf6c [...]
+    "U1": "02d4d8d4f88384b5b8e61eddea985dcbd3d56e8c0c5c3370f1fa03e833083e767e",
+    "U2": "315b61d3b206d20039849e12cd086d68137ff84148505552b8a7c2a9351b95a78ebf5ce3aae63a5800ad79e5a5e9f3073e7d622d557fd202b0f23df018684b464ebcb4079235b718252ce0796fe143873d3ac4b0f2c2231cbb67917a57953677f77e0c3240840f060eb2d4c78add369f582a77643b66ab13b4670c353a6fa4a4e6e05bf9c1a99f2e176632479357bbad82d2e058cb229f217791e42f3f5ba1febbd22de16f1ee68fd7195311d5718925b0ca4bbeb44cc72d6a08571af523fcde0a124ff378a732cdd476e2029414e11655e4d3440a7c75bc47433e7f1bd5003cbf7c604f1eb76b60cfb9c8f6cbd63dcd7 [...]
+    "U3": "18c356f3b99295df2b80695978efe4c902cb8a1b1e5df5186f6d214408b7a682f8deff06d3b4c789290f5556e2dd5fb52882e6365748665ea7580a155a54a97a9b66dcc5b586680b51eee0889750df8e887dbc6157164de77a89c71cc3996dd4834489b1ff3ab3d916158924491c2ae7f0e942f8ec74a169f3a1fc2c23d08feea3992b8ea565a18232789b1cf3b42b423cbd3bb327c9c6167ecad1a38a360b78ccac1b4b9a94d2c25692038d6b96fcfe2d52bdf45c134a82014f7de4de80065e3bebc8e87e8eec45afc3d45083b086c42fcd116cc00f4468f024c631270476b021c33b532442a8c3e60737466598ed05c [...]
+    "ID": "2f3c0ec3966ff009ddde5c2deddb7711",
+    "AD": null,
+    "E": "513137252fb05960bcf8fadc8086b6b8929a815e3eae910627df26630489dda5"
+  },
+  {
+    "TEST": 1,
+    "N": "ab10127b209faeaff7ebef8d8a617e369522008d30db32bf55651dfafe2416a1904e673ec8a79ce82daa3ded4ca8425e97061df0c1f1ba8624141fe6f1233cb788b57caad1fa5d2e31384be540af8dc7541f6d712161715d9a25d1dc3c98bac05cba014f66fd062423886942184286963c980c2148552a2dedc8a339053a6a249819821c82aea3587e5e19bf83d2d33b2a5a0f6c422ee23c2cc9a7dd698e9f65e3f15294eba9fb91cdd11a1ec81da3587b7bf73334c26d419f69b0d33ebc103eb0644f8a3b8da6563c57c71be06c8b8b469e5b70727b24d398e75ae52b08609080eff9cda40ac784dc70b6afb98ccf5dc7 [...]
+    "NT": "c1b8aab9caaf1f9021fcd135ef022089792684e7cdb1467ff522e46713609e7ebb633f19ad52e597f7dbdb59f6684f204f368b7104116a1fd8eabdc9ef7eb4b64867ad1f007f74bc57f2fb77b0b9b518af7df355e7a5d99217df442358543b76a51798e8ef194437fb4b58378943cc812942805a0b3d30eccae13fb56ea3500a781549d1d6fbd0b2ac57d63aedaa05987298201d8434b6e51b3c0e75bbd7eeb3cfbd4f79d28692110738954720784d269fabf4d4280d61e4fb8581803dd75e1be888d29d8ca419b68ea9850919c0d5563104c084f9fe0730b496b70612aa131b20b951ea8eb61c30b186a684698f22bf0 [...]
+    "H1": "6addf8658d9edaad4875c43ca84b6ef6492049260aa2797344bced04707df647c8d7cd1e983358ec1587c6f83321698e71f28f3d71b0e55f36b427084375aaa4c7b6c25b34b0f6cd97b40d315ea0c174dd0152ef16a31b7cc94e2bbbf075197f8b3b803d323d9f75ebb54134dcb3841e30cbc35d0fc26a5ab3e4d270c00bf131208bca93f55a1ce26df37d5d94457f58c00a279e1e060f74ea2fe1c52df45cafc4a653b43addfbcbdf14052472b37774ef32bbf32702df4c4a349ea2d9b1aea67bd8b2662cb593958eccdc24d3d7f3f0f5ffe25ea6e8139f4f962537764a7b27d7d2bdfcbe260eb30550ede6cf1bcdec6 [...]
+    "H2": "148a15af0de2ae53bf632c93c5670edd9681e771dcb03e24a7cfe4affde977589ad0ecdf6882fe17e2d69247988b092a4a8ee48969426bffa29564d7fbc3d79141a283ae722ba6a1a11ae9e6d507df4b29e4200607d20add1a7c89de951e64bbd69055476a1069db50d77455c452ade8258e74bb92a1a5008fcc89e3f89147b3de62dadb381247165bd0c5b57f8131b18fd78a54dc34685463efd08a106b506e382dc8debef4b23c83e220bb807a98bdeee672335b6c00c6e895cd1aa43119be0f4034b4005274c44978ed0f810d3f69729d202d4bbbff732b8b541f0b6eac41efb75b87d49becb8652067a734ba3c646 [...]
+    "C": "4e816a6dddfeba317790176e0e49c88a971a15efc924a0e2c98002c04a9149205c51d1b1833610c006d50e03ac3477abcb7bb21bd218eb89aa1c607937615dbf27f49cb6ba1c0d5f986c042c62feb374b771f701eea1123d7c2fb4f62a0d445a07b3043ccb314af9e928aa610364ae23cc934a12c2341df9f98612d36479ae6b88aaf55ceb84851a653efe32209082e506f09e70b2b04ccdcba71f25d91a049a1f37f03c9450019ecc4fe0f6fe3790df027672135d0e181f6fdc956c0556afcc02a0180f4649861af8ea150c9c104da03b93c87116e474206bb74a421cb72e4cb8acfac1a3c27fecd9891f66d3d2b72da9 [...]
+    "ECPR": "02dcfabcbaf44b48a6c8f7184f0fc34b4fcb2c4a0390807627d7c1512126e28c19",
+    "ECPRT": "032fefe6200f5e4586f8265529a9b4a9a92f25eba742d5b01429f8143efbe45f7f",
+    "Z": "b9059231a90071225a88b98cd3262e9fe65cb479a0376c0d9c5b2f4feec63b964523c904bb7fb842f284a3450802a8383b54dc6a340784ccb80c4812537b9d58f26fa3bbade6f97b6ea7bd120ef931b5b3f637e8a3d7afc1efa93883cdf7bc32964b4315dabd499e73896ca0fa12dda1bf398b22dae90e541402aeb4e477f9add6d337f24cd60f892e0467ee1016bba771bde8befb797f94b70cd2d771afe094d487b43419fdaf128dbbdb7b636a90db8ec13da8edf9ef5e407637878eac4cdd9aa4df93a6e819950cacb7486b136ab056a27ec9f1288d854967f0549a60d96365615f42ce4084d128bf76bf2bc6dc4b33 [...]
+    "U1": "025475000c7c4e9f27935bdef3a41c36b2475632dc7acbd6bcbcd7dd0bdbb1b988",
+    "U2": "5b1bc5c60613880fa3ff3528f1b48114c01716ca1a38b3cba72b1ac5d3bee815d232812a37d95457b9d4642621a04795a6c32ed7c854908a23ede96c5e3d1fd1b7e259ca27817c7b28f0a30f698c289b8145fa5bae979b021e4a584c42612c816a13487fcead1ab5bcdf0d2e80e79b1390ce497ab9058c323546aea1346eaf903bf8c26eb17f621b33a5915b8f9d623d0a0a939850d8c6e73fb0c52353f8416aea8795303736e5c7ef4beb4ad839419aee4932090511f4f901121394780ce78a215b407f2dd40fcf848e7dad70f546390afc4523d2ea60d214e9fb9b903b6326076808ea6510fd3d266c4df951469f434 [...]
+    "U3": "66f1c0851118b786926fe69ad012e5a8fae09830def38a2384715f1ef67e99a57bcdff5d10724551999cebca88175965573121d6e1e9f4b24150306c50a41250d5a4f8f4533553a9820ddacc8493fce7d8a8ee163d38967b012019af38f8581d8aa36a68b494619b566a7b9652a6b48d007489b0e69bda898c6b98dccee134cd508bfac201e05ac7758e337776cb280ae5a96d2a249559e2805d57caf4bb2da77ed503c66beb1a08d141e8c8b56ee38d949a671a152db6a24d511b8032b15ac5de05a0ac910346c7b9456d0466b148ad66c5b63053331b137441dee84b4daafe901c27643e75a339a666151e933397097 [...]
+    "ID": "60cb91d6f017d8cdefb2ec397e5be569",
+    "AD": null,
+    "E": "a8563cee1067e356189f74cddea2e89fda2a5b105d9c1cd31cbfcc762f67d67a"
+  },
+  {
+    "TEST": 2,
+    "N": "e9d53095e06f3b7dd1854387a032d2041a6368939bde281eabc2d7b9a9fdc2e95fdddc24c03a3872c56ff3d3036705c1928c27efacba6653d9c47c969336b302c1d0477f0ca6cad5f37e3ac07655237d6fb1ffc85482b8651762478a255f3115bfb50ff055a5f7f62c074211b482d87e0cb2f17d1c4e2077dbc217f38d8c8a1627069412007bea45edd8f6378dbb028df879ce1353e7112fdb033c4f7aa3a7c59cb2e0cae8581a383b27fb1237786a99d45da29ca2866fd0ee9bba042b1244b7b500ed24065b0aa9ee7d11cc48484c08957caf0e89d78b69a92d3c455cb6ea1b24a631bdf3c1049ac158236f956b256611 [...]
+    "NT": "dfbdfc2a4784522a0bcd93a9925e2d185ec9af22e3c76af9e3a55552ef2d22e01c3a9e5155420383305ae63787a6451f91d2ee741c24a695272fa1f3b7ed6830d7c9f519fe3afefd97b956029c9bb781ea3efe49bc9cfd911dd132f7b1c12d9002fe73782c148b299144b664200246b3a5336b46768afe63e8b508efb0aeb71022e27307663d1ff104865310e59edeb9220630561530a7de5e3c5a74abaa4549b80d37e851c8affc44eb1024387c63a7854346ba6cf9c9305d04350b93db8cde33c3260789feff3b3c4d55cd50216e4473db4fd83d138e6bf25a9d609f010769895dd1844fdaed0cca3a773ecb734a668 [...]
+    "H1": "7e9e7fa2017e570c35cdde8ba3fe095e03dbecf3c2142c62ecd8d28b225b7ac5edf75df534a0c344cf854d6403819988105b754814204b48265891da60caa01c63c6657590f2b8ab0186d73b5dd6d42030ebe74b2d7ed8ec25ab1d634c5d414c5e14c9c3b6e5024f01b738d0913f5394a28b720d6e92012a6da6540b474b42a6ea38df9eac0eb977c61030a49f87f35482a1b6ff98678824658114a562f799eff7b15f7fbc70af76d6c8bd06fd72075ec48d01ee3c512b179b465659bd768a6ce03480d6fed6d57c6c0ded176964584bbeb23c88e5f273d01d25b5c5caf1ec048040e5e1706a337423abfcb38168dfe71 [...]
+    "H2": "8260d72680ee7a036d8f4c34166b73f6818059acb570f7a44955dffed04546f42a4e399076b8a658ed8655f42f7bee3c3c3833e2a949d327e70fa7b03170aabcd2e120fe594ad4ee487a16bd546a503daed4c0f04d22f29c2f16a4c03d079ad788116f3f107bbe354e43507093db247968436fdf0d50b2cb0051d81e152d841db566590ebeea31bfdd1b034cd8adc41264efba2dcbadf4aaa5509bcb3df2cbf17e2ec9926baabc158e92a110be1c31c55e99322e6550866731a040f53ef23a70291d78cecc3d3544c0563c9baf62af3f9a5e17b5dead3353a58bc238c1a78f19178f718d241f6e4f962fb98825b9dbb27 [...]
+    "C": "43c0efcb124877d5af44c2eb628a4a50d3783117efad16eeb3f75ab6a3a3c384b56dccb454c6758c0bc7a3173a6ea2c36a818722361181b476c1526ae55857d00e1c31afbd9ebd048445a8a2ce3573aaa24f4948854108faf8a4ddcb5e84c010b15cdeeb58930c07a36a1d5290f5f32d9375b3764e6d93d90f32047c353f7689d4576500b293715267054e3046b60d05297f63daeae1befb1786f63770b6577f0d9b94e08eaf81a3215a7839d6a1aae2b45fc9e2512bf218358b3f724281149354a52386a12b42219728bcc3f8921f666117cb11c271fd672954d24d0bb66dd0beef73a917c56b6cc407173459d06236db [...]
+    "ECPR": "023a0ee411aad20e1df9ee97b130d4362124f5c8e9fb263296d0e0c4e06c880863",
+    "ECPRT": "0361a489bb687c74e131b87542d06b4a92b7a6ade047b1146d99783d0d9de18b3c",
+    "Z": "3846d14ea7c026a7eb32c35a50767a36ad86a52bf88520c321e32819fce1cb29322bfd91b9b2a5804619c96fa9ec0e1a7140c84c53157da075366b8f0c6e9a6db74c8a719890a48322401162c8fb985637f75c4e5e9e0355f71bb2e6a6adbe39162769037a74144acf5ce8b23b07d11af6791fa4c2569c6e98af915201f41a06c914e22c980d135db64f42f587e112b7aad084456948f33d6d45ab69ddc10f3331b8f5e8d9e7e90f95e69883120697fbb68a22682166bcf18b765ceb0cb0e4b4e5e30bfdacbf7ef78102832317dfdbdd64a9564ff7c717a52b70b6a223ab8920c151943afd67827dc5f6270907f2c515c2 [...]
+    "U1": "025481cdeb5c1114244e7f69f7d1e8616de69d43340c75d8959207c75e94ab928f",
+    "U2": "641340442e76f6a74350ec3ed5adc5fbacbc7867c9bb1205b5123016bba80e3484ed38df6bca08f0ef064c208864cb846c35dae33f5e0fd6e56ce0593f8d99f0ea21479155cc5531dc913bd511582da179b5dd61afe8db01e615bae93fae28d3c015020e197383261aba544bb890b5425fe0e326d83cebfc685455b40ba00125c64e569f6f49b7ae9b6c8148fcdd87b205dacedf69a4dbed01cd47b6b0466705d508db7dbe63ce3a00423f1e93a4cc7a54e6f774d23d8a6f4417365370f98b268eb2db8c3797c15e0c2903a5194b1b1c8f41b3f7c3d59189ee2174c235d94dcd729bee095cf5c1225fd0186f0fd2ddac3 [...]
+    "U3": "a1da912e78259a3cd5ba5f9ea623296a50a37082f7f1ffd62c9fde6375de1048bd81a27e4a847a8c4eb6b51ca6792cd5a4ebaa286c8d0fa5cc686f887c5169f9a1324367da0d2ab0570edfa6d7d3c26b956a7bdfb1fe64d1802d2575b3ff2f47ea7b4974f63eed7f6753ac2747aaaba72cff51bbe2940e90c64e0f5e6bbb6ede57f387d5e4e952755e5911818af29fd0b96ffa26992bd916068e39e320714433b1237a43a812a2edd336ed178c9b309f76446e2920a5e7152d0f4988edfe2b0c364797a2cdb8080da6be191e9f52415f83b90bf23f3bcb259d89974b2cd246d4c056be5011b024c8f6af714ea2a597638 [...]
+    "ID": "70e09bbfcf43d95dbc627a11fb3f8010",
+    "AD": null,
+    "E": "7e5e4991f0494d1fe780576db4f9420222790af9730593dfe89b8cb651fee6a0"
+  },
+  {
+    "TEST": 3,
+    "N": "a5b82d0e7fcece08feb3c5aa2b56cd23677f7f6f81552f3721995ccbc9578c95ae1fa16c7503eb39125ba11606550e15177997310fda4cda2ff45d1782318ebe3aa7ada2d679921a51b20cb2fbdac8afbce9b7390ee31845bdd7b5cd7e0f5dccafc89388fa4d1ba9ee4e967cbdeb082dcd427784a2191208a2bbae2dd3630010e4db918ca543928ce8b4edbd870527ebbee673d447ca6985f88e1fc18548e0394e642c21c366d138bc0aa49ad77620c15353d456c377e1fd4b7134cadc36ccdfc99d6c61e848057dd3adeb9dee8ff71741de3bed1ad5928c36d3f239f0c3f33bbdad338d5d543f80adaf31e4216749a161 [...]
+    "NT": "a86824e86c82674f33904dbdcb24e39d2464f3f906a90702ae2af8f71be38e87cb974493dbdfc40ec9477fde12be9f9c3d8ce49b31a9a55e8e7b56909b263106025cacbb8d454375f0078689f2c7df41e6c0a92a10aee5e53718ff1ed4ce08ac3eeef87d42e41e485f457720dd0173bea2d6aec0c6aa0046965e09c755244bf365c92f884dc2c38c415e041fda53b0226147ba3d8ded0b8d1cfb36f4aad7b98cf24f46dcbc6c83e9f40aa44d50c3c0cabc27d4c52a0c6e6fcc4736303bb65c5149a7a263a4524abdb512407a5a84267ee90412aef31d81251e20ed3735ce6f3ad0051138b21f58d95dc0bfa1b73b5b5ad [...]
+    "H1": "8ed8afbd7be92889040f643dffd32cec6cc11db3b9aee0b045700d66bbf8ecfc5a5f4588aaf6468756b3c733da42c1ff91348d86e442b431c70ca54bba81e2c7f0f91933d1766b92452b2fd1e480b456e3de978e0bc13c9f15241beeb6bd7ad7332353713e0cb4bc485dc470b7fcd66df062e6ddd8055533fd3a6f99cec100823fb95547e8766a6794eff1ef31668c01d30f93e5b9ca9eed454e5e2d2dfc7cc85994b3f98799b86d252ef16c5096548a75a64e458fd1ea0f6b10c0f5224abdb670dbd5b08efed90731dae1cf1744d76b627ff414724575626575baccd80c1f54adeb1cc7b1dc8e52b3b0a557757009aa1 [...]
+    "H2": "a0da9492d31ef206fec4d5ffb2edd70a8e3124177fe5bdb5594bac44041964564b263e4ef050f519519f80522c60ba16583f2f95c2af0c9e1585438b18c270053a84a2bd19c573c2377eab661a98fd9a345efaa051b4464d297d3dc521d1c42c1202311a76cdb068e161f784af8f771920bf709392e71bc262a19b7bd312d1ab4a2acc1dbdae23a0f905cb43a6f5c278da00764a1984dbc35dbdb4896aba57860a3b4c4ab45b9a9e4ebf7eddfbe430972e727a48d49f4c5ca0e7e206865ef994df3d8ebc72e47b82f187403ee590eb2ca9564c69e3097722ca91e4a0afc01c6308245885a042b602d24f4ce4ee6c7e77c [...]
+    "C": "32379a4997213f2aaffe05208cff63ca313e8e2cb01de473089ace4332830cc3ace7925c76a018e6355e26db7a0743ab9b9537d5b23df29582e669bc305928bfff488e88957f2527ea06d42d9a9868d05f446862e0794b37d6dfa64800c6a17dcfdf008e98a604d7ce0b48afdaef4e41df955a33d620df8b8778cdf1e3974cd534bf073bebdb9e38484cdab5deeeabddc5f3a15c750b5a3959732d02f233827720f8c6dcd132c724f6c541058d6ceae78d24a471e69953073c2d95def2d50607136154e3ddf729055bab8e8eb937f7da42463beecdc31b7174145551adc31400f28671ab57aba555f0e2db02c589c2ea22 [...]
+    "ECPR": "038bdfadc773fd1441098b5b0327a86f43f2d032a79ad647b1a08e7b56c2920b76",
+    "ECPRT": "021615e29ad7fb7316feae593c54476337f9a2ac0a899c2035badba5be1d130b82",
+    "Z": "199b26158c7c0b60e2c0f3289bce562177da809a98faa326da6d966af2929ec58d5558df467d50ca6db60d9a46833fb832f7574feaa3a13a7196955c34ddc195b33cc27070269af7643d82721933343fbf9ffae7f687c72afb225a8fd2bfe71243fb87830ba26650b842f1e1c9ad1a60e72951cf7ef10c42a2d4aa083016cbdc8f2cfcaa6027f3596f670f662985d132ca056a519f2ffa04f724d6170197c3a515874297dab2a655a3caf9e15c2c48fefb9882384de6e8f29a8e125f2ae7a5b5bfec63fd865db051fcacd85f7e971499eed7806b3465e874be102b7bdd9dbe0509c2c58b63e52e0c350fedfb3a8b55a78a [...]
+    "U1": "02142f2b52c7743ebc52dd8cdf271a804650ee032ea8bb7e3594430bf3243db506",
+    "U2": "6195dcf829c2a3dc31e53fe43a4c4a6da29e9b48beb71dab613675d07224e29bfb215346756c9bcb59cdad28dcd2a278acac81334b365035b4d2d9440c9d922e607cb2b7fd17a86335e1a42286b3ffbafd8f62a304bd74dbe5b1a6b8e7db427979303a77f4c206c61590381d82c35c8f35a5f8ed38102119f202f5960b29606239775263ec72ca95a45f7d96c46173bd03de79cb48400e562bab62af00a1e384e99f7ae79c5f4c974821980e3afbb24a725ce0e7d7c867246aa7d88b8037daa800f716946ee9c967bcb96b549b8e482a0e7230303575b35ed646c15622bf617799501df0dcace34100ee95f261d0917f9 [...]
+    "U3": "6d956ec5a3e5df993d32361ffad9cf40ef7c3be33f5a1be922ecc92b883867c50a5d18047d5f4f00e82bc3e442d6f5d2ff037d80cbcca4702abce52ef5be23602eda63ce8a30878ee3a80e63aef5344c6ef0f18048c6d177a88c4fbadf0bf1c4e264a1b47986434bb4c4223af42fadb5645351f6ed74ef73292991c66f815fb90bda49298ebb2be52eb58fd3af6e0a4fcfca02cf80170467ee4743970fff0e0900dcadafb7be18f2763b1d2ef1e2d80ef60d4c11f07f6b83176ac0d82dbf7e7466514c14442012bf822dbef19172885a53da8ddf1f82d1df5d892f8790ff60fc7b5bdfc2d7adf46a3f6bb2422c17f2027 [...]
+    "ID": "37f05c3cab30aa5e4f4a59c296ba61e7",
+    "AD": null,
+    "E": "f8ff6885c8035663725d758eed0a94f692296c3bf0ba58423d3e67a485d35308"
+  },
+  {
+    "TEST": 4,
+    "N": "cfc198ce68af5e0fabdedfd5bd34ce4f57f92ebb084ce0759f9abbf4e56e007e27636b79dc8829c2835713f16e61cbd3364b0ff4de9cd0bf3114ec775302dbffae6729cd38f7fe537b49ce89a589af82e805a0f37ce3cbce47695af45e6a4fd0ca0878578500e825d43e12a36a8a8b5dd0570d6e40ade363805e40c51d26ed0d646ba927b7b07ea6c72d77f81af1284a73191f61464cdca8c38487bb0509f00e6a2932aa2c2d974360ccce6cc92a0332f3f226744efcd995d5eef150b5bddaf973ef5c3a2a48037b6bc982a214ec1a343710ebd6ae84a2cd62a97c58147b077516d34723616c86a56a92c4358549e4bb63 [...]
+    "NT": "9c9bc9253874a40a5a355579224cba50de2b41b28e6090aff68358b3b427b6c1d380dd159830af170deb982bc00eced7f4fd1767584d8c2d9679112404d565caec1ab17d20a2f0266fdf318a98cebd98def0aaab434e5de8e2231f899cd48db142b2893bc3c61bf679e6ab1132969cf78764f27b42fc2fef54d08ef578d8b26fd6809e65540d8433d3d7624a0932b80a71733788371789c3fbc6328020e844e8b9630346bae67e04b6ef762321dc75aa4def408a27ff0b2954a7de9c6daff0a21a3081ffa60a98af89ffea10337c6a8644afe0f5072cf1748fec2653337a85a8bee2d088510863383893c86be8d76682a [...]
+    "H1": "19e865286ff730fd0faea1b69057e69411d48b2e871db81e53aa25a10c1431abef69332560587e4500d802682c52caf28957a3db4c5c59ecf8bbdbe14cb56013dbd376063471055f66e7258f25fe0093ce73f6d299f64625976998aecf4e575a770ab5cacec6567bf0cc73ec08ff4b6400ae08d5fd65edde9c2e0c6a847ae6442029b17835bacb470e400d94b76eb364ad5d5c5ecca48d9f1defd38893335a5d5114dad0c8b9008e2b790d936f90316fa6b363f439133c384b93d8ef7833a1b1d8a9bb81300740363e2e85b6461e675b20c2c8ab9e3053b930bfefd0b8d6cc6278d1e3370763807c732df45015a2dbfd8 [...]
+    "H2": "29b61646d7c009f3a467fb08e00fdcf1c7c37ffe5ba961bd87857e26269992441e93c4423e16250563f17cbe4a80fec45e7f1e7791b3f11d31bb5ce579f9057a020feebd4ee1f8127dc540470e2214b0ddea75c7a4fd6d97beb285d6fd90c483777934364cab1a515a19bc5fc073beb47078ba3009410ec4d25e8a553514c2f0029f02cbdade620554122b6c3255facbf7360f9c105fbe2ebc3b82c0b5db594931791154d4fe48cbf89e105248bdd953e31903acfaaf0c43e27f4399553c5d87f4e06323c51b50f24befc9dec8c1055dd8725446945772a7b7158d49031ebd063a217b580a929f3053912488a3781c245 [...]
+    "C": "19c2dda447cd17f96856e6cfe382e655d5fd838adc4a398f496c6b72638cebbe8cd643a6f81bc44a00f16cb5105963c82b113f3561b36514ddf32978dbd14cf6393c384204653fb4bb0c9150ba32e5ff3f65825ad531fef51e5fb1de94902199a185b9971a36b6f77839865cecbee89928f53921aebca5dec4a29fa00db861ee447da066726643f936086c36eb1838196bfe45b351de0c23a6f53e8b8c4ee8ad6a53b5c703965542f336f1607acf7e276ab35ee20b0883042d98c1fde891cd63da7e84a797de28e193902cc84e2258a9c20c98383d7910e9cd9feb8898ce69420dd7a3c3653b63b97f977c4b807be3ab9b [...]
+    "ECPR": "0287d1a1c8f61a876c3f48941e11d254080e4ec74f7e0242641c550bd2bb63069e",
+    "ECPRT": "0292076fb31da4656a1eb8d5d3a695a84cd89787aacd71dcca5906a7ce3fa8712f",
+    "Z": "66e568b01cbbd8ecf2457599d3cec7295138372ed4723088574231d6df3be84009b89e6a34c4c68fb6a53b8f4977996b1ee4edc8b2ba9058d5b2ed58a401528d966f5693d4e2dc6663ded6b3cc5e46a2e9eb8410ef70ddb95dcff2345412c5685ac8ce66f1a6758dcdb62bf74f1d6b9a8f71c90ca3ddcc5382af454dbd155b8b0bbb161b7029106fcd7db1b7a2c4a839c238036f1a1b86bbe7a65ac177018ca16232c2b9da437ad467c6f46a041d7177b3a235cd88e3213c3a4831cbd190b2fc0b9d820775fa0949a040d4f3618df127792cfd72a80cdb62bf74e77368538bf50bdccc57e5072917bb44b2405e2b672744 [...]
+    "U1": "0213e2a30f953e588d14ddbe8286e2113250cd1d0c5351a7c3be60a7b0f335cb8d",
+    "U2": "7565f30bc50d1fa40fb2fc6085caa9239ea9f084ad96248083efaa81c5d4ec65071875c107d4e8550f00b890f257d1c06718933575abeb776199f9f5fc06054523a9df54a9aa486f7e5aa1dbe87c7ac141d4e64b355b432cd375a0559e03d7dbd00a7526bf985ffa7a2dacc93822df13b5e22cbdd322146242bade6477843c7957f1d79a46bcf2d38f00f7f78b25d1ecbe4260c27b1531e50af7d77b4e2e1295d8db7680edffc8a1155135f3fe531b9e21bc44ad14a12e01c6ad53790efd28cd9932d822696ee7766c9927f0af4d385bc6668d1123e82f6d291801b6b225c0a4d9e04877720b71c0b0f4cbb4f4aa1451d [...]
+    "U3": "0c4d44ae8d88f7aa7abd9562b72fbeef471240337e9c748ef8d88d879cf890b069254608db10661e9d3ddd4e5827b60671de96cac8db139bf59267aac717ed63063422645da3f10c9f06959c3230793414fb449414ebfaedeee8bb23911d06ffa9bb0d0b0be858a502311536b88e3d9bb25cf4fa88048dd7c33ee1686e00157457e5d13d431fee8da65fbeb49874d310468913c692d3a8743e312904254184a8bd76dfea76dfc16657499f770d89d828d5fb72592856239b58bf46950f5947c744740f7cf30ffdffec6bdd8be05a5deee16d4477a592ed0b4d4649ba6e37e5cb62683dcd8256e1e44596b1e0f6f67cab1 [...]
+    "ID": "e92cf082a4f9483ccfdb50299800e239",
+    "AD": null,
+    "E": "37ffa8e546441821f5e111e33ae1af16be3681e8edac2cdec31230d72987911f"
+  },
+  {
+    "TEST": 5,
+    "N": "ce77b24d91a6e9e64f30a579ab160e5f91b12faf6981f334b712d70c72b65ed052c34c9b83852f60d9490e67cbc758fa876b32d2b135821def588b54f907605ff66fe0ff54214fd063896cfb76341b9c0d93c71a53d809901109f7b4402034d3c0948487164442cf18c3548b664faa5d848dd30f73eadd9455cc292dd406b04a6acec1bcc76cea7921e00d2c6e8a2b20859e51cc42a060a90ecb0e6011e95963253e6280e57190d86e14d0392d973eb91ff933f4809a9e6faf504b9ec3f8f532691a0685c90a26e3c3fcb63194f1e9ce1ccb50511b3aa1405b18bea84d4750a9fa22d7d6fe7c38031ed2691d2f5978471d [...]
+    "NT": "b8d5562cebee1ba65ed1bc96f5a10d7f76f804ff76065ae71ef8e9224c1e8ecaec249e4ef4794053866b9052780ca0adbb656e56427d5e7e041b358a5f23036655a3bf3d180a5795f1aea576670ddc9ee3403dfa1c17babc5d86bd569c8932e404d727dd4ce769646413617a00c11527d40ffaff50b205ceb73de9591a3e614c65f92e1bc01d6f78bc8a7bc349eac9f4d432efa76be3a18d89f49abe6ad2e8fca17a2f100103e6622e290adcaa7b9d80b5fd61c2cffb533de4b9a8c8a0376a595c360f193319bce77256812e972f1e4bb2e38895783f870f7958033a59e3023224da56f5479d6fd8d990d361c4b289872 [...]
+    "H1": "92a285a4bf2fa3e24e884883b846a7ae8359113b8bceece46a1c4fd8da98a8c651b20a03aa8c0ed8e69a1a461f90ec7cd3c87cb192cd833a3b641d722cc29ad77f70d530d733eeaabcbce161cad52dd0577c0219124542e1907797ce5a951174eeb83a913e92ef66dde7a40d971ed2a68efc31377df9ef00e6d1cc5bfba6d0db04775835ed21f05e2444c124fc830de4be04e583c42246ca0cd8960076b583e26dd96e6b266fa01ca5c9df56b76936224dfdb6aaee911b10d70ca92c551a2608369c1f5256dd0a6e4984da41501bbe1f6842a95e81c76ee4881485cb19f881c660cf8d0bbc8bfd66930064bf7def0ef1f [...]
+    "H2": "6716d80f8e51497f16fa7a0c98ec3b55fe0dd01953a1a7545463b8f1437ddd3b1ebbc435e1420ebec35685e6d044ef0f96bef6b1f4cf1986e2ebd1c9b998ffb5dbfe090640ba50ec1e1b4f2053db9c754e450b521e8778062fd6c252570c52336d46736d00e1dfb175103c49b2287156a4a5a554810944ea3df5f1d96c8d1965d84eac05c00fcbcdb7cc1c781ca20ab22b8a741c92ac70fc83fb8920d2cdd87ff95097563c067aafa475dfc15d967e978a7b410c87c0865b94ca41294fc2dca2236396b34315ae704d0edd58958c40ab4aea79510e46d91f0046b4a5c538f847f8831d4eb8d8545c165ba9f00056b7405 [...]
+    "C": "4d844d220247d6ed967db5b6aba73701eac73687be1f98ecde714c43fccca960988789bfea925bd9f09aa607d26e6e0c2f4f98fab9c742283bbf66cb1d645b6def73aaafd12febda784eea88b8df464e2f0fe2526bef8e99f040dd191b3915f4d4e16d8c9f233948a91e8f8decd315536bdefc3a77479c9bf2718df494d9626d7c6ab30455d50a6636a64b3b20cd54d40c84bbc3564e699b2cb78003f6fa4dae211adf8b1834bc167965e3ce488dd2f4152e3e5f33f7a2721a7f5deed6a11cda4ab111b1140dd5307c8730b11ccba9711ed2cdae84edd967bbdddbb83fcaab720c52dcabfa25da4d315a297fe9e7e7cfe1 [...]
+    "ECPR": "0358a0ae4458884ab4d9465072b3bf914d3d3f65a96fc406126488aac70287b48c",
+    "ECPRT": "0236512a896c48c73191cec93bc956a79c092b00fdd8c94e84187491f5ca971340",
+    "Z": "91c8c2c7c89fc2dcc21aa25834eb5e4d2d25b175abee77e411e82e9183ed1b7b8ca5cc9d8cef8481ab9863ded2db5dc59d96d6e2da1a47904c67e98ffa7d783cdc45b69c72012107c3b5dad947f41ce509d3fff86f3bd4e7e492f6f2ec6c0d70d8177131f52bf24b116c889ad3fdee7ee10c53b75796abe669d289ac61a11f98979e45d2f7982968af03288adfb9a439ac8b81dcaf1b9aa00c76ee4185164235b338719c65309861888bffb7c8d2e6957f210fa0acce7a0582b5f51f476f51b6d8a187e60e07587a9b13342ff6772385ed0535c2234b0066c8553bc38fd16c04c049a2dece75136fa8b52f600010533795 [...]
+    "U1": "03b67e554d716e8f77c98f66afa8e88787013d10d1362773cf98e27e63f7f7e827",
+    "U2": "3695764e6b14c56129a5e98d0ba25015b43d2da432fb467e50364d15ec3ffdf5947edfa8608329f1b3d767b3a1e660e0deff459ba229e1f7a4093d5ae0109d245561ed6eaaf70aacbbb9dee3149a2256278bd0e9674da48874e202bdf337dd5ac910c9861a0c95be9047efe0d1f1b1a17beb74d98f65081fd911be871ac62e8419e554efb60322b7adeb90ae4d03e6a0cdc37346717d7256e8ab3a10704cb65b039cf211b2e07440e5594ef81572bfc960b2b9180d6103fff72ea9699e4a15d4bca285aa71421e7e6b9993e3ce67a2a702da07ab8f49f3b7e7c8bce250f6c0055093463c0f3bc906608bb86cac378ce5d [...]
+    "U3": "37f88495bc86a6ddcf8a10200003c95d7a684509cb01598dadc25d4eb400eb0ee8f8e4724ab7221a6840fc45cf82d5f4c1b8c2046b71a51fa9395e6b747e7336c51378eff9a3e5c14642f8c84de3896ae46769838f884623df1cf4d992a3c043a24efb351596d9c67bcb2c6bac16ff6b43c141e6976116e7dae16a3f19ed1aa10b54d2b13ad62ee7b8aea1f91fa175f15c1c0c6c26749be019fd3e696ca47b1240ee2c659e401bf96f48d656519d968074bc03ed25d652beb5b779f8b18ac208dd51c1ff2e006921cb91f2db9f6a9b58ba094f8d94be362bf9bb0c0c2518bc37f1457c3cdb252e83dc4ec1f16808c2b4b [...]
+    "ID": "f3239328003e27792750269e1b20d11a",
+    "AD": "32ab8c244cf1814ace68f28885dcdd07",
+    "E": "42ec22f7ea75092bbcb15633e93e140933871c10f5329c28aaa0e96341c2cd32"
+  },
+  {
+    "TEST": 6,
+    "N": "b9e3727da2667c0275e10be602fc7c94e441e0a64231a4384ac691ab07b38beb2c9c78bb5e0877762105743bab3100dd897af199966daacf4e388dc5b8148025241b6f6353cd5ffbc16ed79e5f12264238dd7c5a8604ee6046bf49765945ef017c74f0ac50af0181203fa5a55e7c87925c8929552766da9054a7ef5e606d6ae353322d6223f3a9e38167e7ff345e5e9359266a4ae24786ea7bcae096073ec3887bea15988b3abcfbd6ab1c1448c77b230c1b33c5cfa7dc6fe1106502ec1b05774a305f48db5d5a7fb506f4df9b17bdc3b181ad90a7d20d0bfad0ccc8b9404462417736272b1c0188964dc0804d2d0a6076 [...]
+    "NT": "d732a7a46bf87b14bc8a80b47a2867203148a8e6835f02d0788a0624a0161fe67c447f4e542bab2ebc19afb9a4c279f06c3f3797ee6a98bc86f9ecf92118547db3c8a7241e3f184934d227b408f68958cba730b5889b159ef3f75f466228788455fbfecba32d3e7fc1e384b06d116b6f1403ddc9c0974a127dbfb009378fa38fd5042831da323fc7b491f98e4b9dd143fc3c94c339316fee2ead9f19e25047fc67f8ea8b3b11959f544fbdef7da6f663513cf4946d34990d989a8caf60112ec6c1278430715a53c0374d7a1f3834cdd1fb4663637f7a09398ea45950ceddfe667dafbb963f617513f0c65ee0588b85340 [...]
+    "H1": "d104437a6f27de75138693c5bcf2041f3f05b18ecad48079464e0c7a535527dae3d73ebe1d3ed6370eefd99073c5e19f39d0a352b79cc5739898b1f08baa983c5275cd66247faaf3071640164925157144f046a66a01b7f6e1a86b96324b6d2a443eb89417804a425d34cf1093555f3d7b4aeaa28c93ef2177dee3b41328e8f75f54410478da2dc18931402ec4eab1c9d136e5e513ee88fa40110d6c1d5eae29053eccebca76e45497c20503e7865c18e13dec96b16872691765afba102b885929dfd8f773acff22bfab298931fef3b86c385f25706bf78be73c0522275481e48b59a60200ff84a287bc2dbea53c4e1e4 [...]
+    "H2": "a437e6e3b89628cf299d92dac81cad27f9459c3459ddc6c90234573d928ebaf67f3700457a815223068d0af0fbb6a6460cda5b346e42c220ff46bc4640aa9c9c331cf966c4130321bd803c5234acb5f81ab58ae0a94d20e2b83f59e69ea3bf2326bbfcd1a33f65f965cd4cb602c3b862ab6002117dafe4a70d99ea52b3deaef13d74cd56f003abd78b6c78d2ba6c95d4910d9c8f3716889d898d2ab8b32632c06f153d697a811cc5587fad49f424fdda7ab49d939989e92078ffca33e44c8cfa64c3e83147473f2b411485c1a739faeca956ce1ac2092ce22d5ec75dc139b3a67592fc9e267d69e9c774fddf0144e6474 [...]
+    "C": "4f6ebfe3733cc03c759235225b25386d5af0b263a49f603305789f395b75657f447fb9d31f40b441abeb21236b4801938827570a40ce1cf4b5f8ec84c0453a89e47359f7500f86d79861d15dc1f55c6f884d05560e0eb3ff2149be7c1bf45598c655933b619e284ac9e87064ed0e3908036bbe8af38d16014e501daf6c74038ccd3fcf26941a63d4d990eed76e849e07ec08b5ca5d02a7ebeb843495a06aedbeac98056cab580bff6db85e1286b1ab34fdd93ce66a808ff3744b2405963f38be2d6c3328f3650c43af0d4ebffbdf79fa877ea6bca21e2c75e3ae4d561daa8aeeb494ec37d111fb9877208c2171a3246c1a [...]
+    "ECPR": "03c660a13d2dfcbe43ae64db364073ac41db5a6e3003c0a690eb3e9a13185ae973",
+    "ECPRT": "034a0d8cbe826618ea41b4d83bf8485eed857b5a715309aac6bac1c90374817cc7",
+    "Z": "1373dcc394b037e50bc59754e522a42bacda349ab4d603af6cd399af0b64e6c1969ae22f7fad625726f821ade0a919e68a96097a05ba6d079487da731162596012f2944bdaf1fec9d080062a4fd80134593dd473b117e03579bb595f908c1eb64bc9c70bbc0d8ba5223fce3202f00cc1c0483c786ad80eab2199170b2aefa013c3b64d6e4046ce7600c7a7c8980159df578e961f607daef37b81c53d9eba70b52ae740a010fc787ece165760f4fc0543757e9f77989f1ae15f124e638981530cd37d1bb88fea66983f605c0c76d7a610c6957a0635f72d8d975bc7f17be3e2faca4554a79be219df7c07a68aa8962539b9 [...]
+    "U1": "037d344f89d0de6bd560ba61d1bdebeb16f7def4eab74d7ab97af944b763fe3786",
+    "U2": "7843e5cb4bd53d69060355d8d2ebf886cc01fc252013d8a695a89784aa0afd07e944e1d2ced6b15457cbc9c28c08d9c5c7bb89d38736e13c08a4b79e8b127b50fab6ef9d5ee5d9f6349e9b4387acc26f2481cdc47998bae60abd80b9709b2d7791a6483cb92a598c4a9840dc2695c66e91ba9c487fde8b39e60db8e283cc2f7678580cd57b55bcdec8d29e97f6d58be163ba46657102ea9c4c0be6705bb310c1ca52d99a905c0bd39f89d268c1aa3598cb248d4eae0bda999d4f6ca2fc888e5ac8e378b82abac018823df328118781d32380dc33a292b0bc871856efdcd7e56e4773c04b2539a89949cbaf1bd1f25903c [...]
+    "U3": "7d2d4ac840a8f5241eac1e1411ab39154fec416bb0cb3ace088618c5f45dcb4eb1a343017fc80b7a6bf49b30b1af00930ab59ba513c47f48391276b0b5b3f4103f86a72ec33ebc482a55fa0983fec00bdca84443576523f1a041e729af3c63fdb1e3baaee2c5c06266da4fd5f38d7b9b8c17447afb73d966a211b4171a219e65db2961aee9c3e88ac9dbeabe4409fa9e47a87831e322f687922cf85d7766f375f220c0c64c67537ce814d19e7149966c3f27124b3974037f67970eaef0a0d4f1915cda9177a1e7fd0b2ea1bf533f737667f5b8f67c56bafdbcfb20f06a72a2e2fe54297aec8056283f83056419b692b0b [...]
+    "ID": "f3485352cbdcb6d5fb2118bea541faed",
+    "AD": "fed4e7638d7f80be9a76ad747000f217",
+    "E": "632e79bd50a46a07d2308f89663e8f3ea7c86213ff9bd5ae9279b8c21dcdd37c"
+  },
+  {
+    "TEST": 7,
+    "N": "9ff5e8e26eaa47c5df46b2e0ebba18c1ad52791a2916ded1415a6cab06b898af50adf2ac42030530b5d7259bcb625ffefb0e9a670375a8db61910f5bc423f95734d55f4707e39d38815363573b73fc786b86974158f674051d7aca32c8cbf53d75035cba7b7f6ec179dc16c505f5d723f2b8dafbfdcc013fbc7cba078bfe2e39399b4cc3f48595c876b4d4d9b0b08c9c6202446f124acb83e33ee82f822286b197fc81c18904424a3c691b27c67a6472c25e230c7fd568d0419c7b6c386fff26032b803478bf8d60662928d6e4620e7fd16bbfcb502130ee30f0d3ef1d00814720be270955922225badc23a2fbbfcd96d0 [...]
+    "NT": "c031847390333f4b8b1fd0bae9a57ddc4b34bb9819f5285d08d0943db0975b61a43286ca3f83e9fa8768d670189f6ecac37cc2b5ab7e1ec3341c21b5c66816c0ad65a3bb2c45825f85a53bb40b31a89c9ead55706eeb55f8a0819c8b3a5489de0c5911a3a3e9ebf42ea1f9cc152401419e33a7e15f8d3abfc4739890374472a2d714e17587350918ff7c82d9be44f5541f74a7de905b4dc9d0c8333fcd185982a5e7a9304551032115ea99e9cd0e33a9b0c3086cb296719394f95dbb0927d4857f8c4cc4d747e0fa14d1d8478a31a124607a91c7694d511e39c295282ba72953c1460958ade560cdd4f53a4a4191aa5a4 [...]
+    "H1": "bfdf9437d1b78c28afdde990ed0c4843f3f2e34dd36d7a6f422040bcc79ec4ade4f40de7360a7a0ccf6c9cb3816ad60ab0d6d3f0f63f162a098428b72bc8bcbd3f78bac0bdc99a48255ae9187e5fe569c508fc3670e8862e04e2a3c6d0fd63993ac719bed183250ac41ae43fd3c8a462383d99082334db6a559ebc8db1aee5cdb85abe3439309a9a008e86264e292bf7665ed6e161c3efc591f79f693475e96068a58dcb59c9a40bd0028e30c657358beafc9e48f468df7850b7801b6cd492cffe47214e120f54b4d213b85c64e82489e59bd1350d5c9c070da8fda7917961916a903b8a315076c49b0e8064385b73a0c [...]
+    "H2": "b39908e2028ca5364a0c426e1e351466b61ebc9a6cbb173f883571e457da322dc02125d38e58418117028953742b7117c129b58c1f0d8a675a716afa7a8eb645f0207bf2f46259922ba48ac45d790ebb1c29c876f4de6957f4793a7492506b44a0aec608713e08f2d3cab49719ceafb56ba2aa888d9bc63245f92be3e5e889b9a22e83ad0e7f1c6d6b317bba47511ea853f025003224ec8030f9f93a2be172e80b97df5bdc7f1864252881b2750a79e71c141901515ab29d94d543fb77fde99f1edcf7f4abdb04720a5d9e81fa446ae8ae7dd04fd3bd280caf36c1f6c4fe6dfcd0c43fac6c1d1c25188eeb8404efe2ec3 [...]
+    "C": "565e10d1dd2dfb627546b2c69e6d72a8bb97276802ebd19a1535c3007317c47106472e0277af7613b0aed3ec1e92d2ad5fe8acf9e2092e08806e05940edce01be53b3f68d82f53eea3d8aec50ec94c605b1539ab24c48429ecb088f320cd4c416a2e6ae9a1c2f70199aef301c6c54baf87112db42fc9232125d3c6f777cde08404eb5bdd4b68d85458251ce48f1d77137f179d5f07090b186680dbc780d69ae983b8308ba84584bced7a17aa45fc6e113a0e8e715935cff9c4a66503aaa324fadc04f44bcb8bb54c5b8ac2d5d60f22c1f6dfda264369be1dea9740078e0ff8d7ec3c492ad779509aa3c47de0c89a4f7191 [...]
+    "ECPR": "0313f099d8b1472c68ddd3d1750e9873300ef6404dcee76e64a198219d4198f2d7",
+    "ECPRT": "034403a332ab86c448db9b78b35aa3066bcabd06ac7f47f7e686692445035c685f",
+    "Z": "6eb41691f02074877c117b77abe6dba9f1e67b0861696ead0d2bde3f706eb3a7bd433668a130a6d7c38cf21723ee3be2d97ad598d95e4efbf1722a6405f3a70b5e638a3b3a22b0dc7cfc32be17645a74ed64a125df3268de8b449bdd2d040b30c4db64ffbbbe717dc558fe6ebfba8dd1abe96d1711385b7a98bfbb97bf04b7a992e332bd8b070d6adbb53b623903e1a5bfb22852e001a4176efe31acb118d2a92d379683bd222a0efb59d4dad104ea88de3dc974987943a14c170d5bc2aefb8b86cb95c99286cf0152651bcae563f27a25de4efc007e0d54552b7c2a262551674f447122f3d8b20b3f1f87ea24e2b42cfe [...]
+    "U1": "02fbd650b6c8af98111372a6e7619a556cf28192394db654ecc5970a73f7a80a0d",
+    "U2": "5e7e3fedbef8239a736e8b8a36f568e8bb8c24282e9c456edef513842c0a2e0dd7c342fcdc4f12a5f5233243db157d56bf0da1980a43e034118a395e8df10bef45777048131a5a7195c1ab7c31f9a4b203611f4fc460c937a9aa41b08c0022d83cc9903502bdb59c265a8fb4909216847f35a26ffa5d0c7379ed0ddd1beb59af643383cf983774911179e88bec486e2841893c70943d763c2dd50109f8c9e31fe33acde26b03e85dad5bf7ce653ea151f1e5fa60c8db83fbeee87988adc115d2d60e4e57dc658371f6d9305ebac32fd99ffa15611c2a7186831471e5a820638b064917461df34f22f421b23d66ab20c9e [...]
+    "U3": "98f7d8bf9ed0249319ad3ed7f03561a7c1580c429d30a6918803d41bd720bec83ac80f01c55967bedb86e60e9ebfacf0e265e3b27df40a82df6944366d1057c467f2d332462f9e4b37d351a67a492d9bc2664e15c10f08f8e6dfb6668ab11ef4f96715e3539d56d2343e2e68480188c392c4394fc6ecc992e854019d16063a0f23987b9bf24fc5e40f0e416ad7d1e87e085ea93bd0e4a7b21324afed966cb5364fd9dddece4b0a7c9b3497f71fab06c3be003243189d6f5b34e14db8f820d423b49607b6ddc84fdc26e7707ad0a65188435e4c2ecbac7a1d8ccd8f251b873e9d0f7e68cd6d68e33cf6f2517fbee238b99 [...]
+    "ID": "0a3a2c0e6a5f7973145f387f465c8870",
+    "AD": "91bd533fdadc39d5e0b38eed816b220b",
+    "E": "c847a0079ea425cdddd6bb1fb6be18624fc07382a4fef0b9898712078c689ea1"
+  },
+  {
+    "TEST": 8,
+    "N": "97389f50ad4f2e29bfbfd03fee511c01d047d9de3fe38a240fa121a7ce34fe74153a96414e0571c83f3654361d29460513d81872b2953556eac9374cbca475daeb5a61485c81140d3a66fce537564ed577918269ee5ee296faab259c41d888308d4903fa2f48039f40cb99fd7c53ed80c5f5b4fe2db7909a0a1f4481576c744f6f2653edede0dab20cda575066681d6b0e7e410a8a3c95593d3fb5f9403dcc5fe9b632b3906b7a57a97491ed7b1158ac04b812091f653489acbc35817fc8065960ffb2ab146cd2b28583ad27b24f6184f817ba955212047471ca9e63f7f1b1c1d91d94311b867e648b2ed58bfe8f7acc12 [...]
+    "NT": "aa3a57faaa2d2859140344aeeb482e83770b6ea2941c4bec7780251c6bdbd2aa247dedeb19642a8cb55f03ba8d129ea4ef10314f9aa73bedafa112afec5dcf54f90e8319cf8bb80acc148bc34cc8d731237a114d9d088ddc89d419f3180a16793dd927e77258e35260d7885aaf53e7c1338ec3e068bcb8e74e244f29caf01bd3b7da0d08a12128601c353b634bc2a85874d86d2849d69987461a68b670b7d414d7c1a6e0cb1f8aef00e647032b44c993f868b6c4940ee7f0b2c5a4ad07657d9ea889bd90aadca65e845af1a3ca449409939b5df9fbf28036b59c44bdb1d24a458d15976e7905e614fbc779094b6124159 [...]
+    "H1": "83e79bf4f1fa086bf22f83bd8573fdae18debe8fe3975b2a0c3e5b446969f7cb8116f2daad66168e576339b9e5865a54f4d962632f1fbd9213fb420808e16b8dbb65b3feccea75cfd175c1982fac30fd634a7b36f126bae8addd75eb578bde5032777dd32a03100edad5ecf0e62089975cefae0da055964565098372498549b81087edf0f9c118e1001064137ff27736d23a0ba0e8b168cf3f53adf0db99ae03102bfc63c65f8c9637fdf89a5b64eff7fd963ed9832ffb01daf8e538409bacc07e2d6e839fc2888e8dd2aadc2434899fc3d0d92237796104eca83e5834888925e2b10f12df6cdeeae394d6abc2742a1e9 [...]
+    "H2": "08eecabc2c3dd6be455c4ef1029dee1084bcb7327aebe2ef6f67f44d66d284d86263bf55c38f22e6ad5ecea5ba13ce725c20b1effc724cf4a125c12f3fea5e6bc94dffd7895f1eb94fc29687fc9d47d2347b4075630cfa6e9bf76ba1a748581da5399e539027b92a66705ceacc52b4ff5dfe45105e118c3853df999cc25f7eccbcf50c2fa020b17a41a7314e10786eea45b99b85d197e0788e335a0c452a51101cf8b98c54158485d17fe190380a4627572b9150b227112362932e7012c849b00cdc20d0acf379b5a5f67b934dea8261c3d94946a2d97e64144aae31149053f8fcf2d6c70c845aa5ee5c45a11417e9426 [...]
+    "C": "3735c474bbc1a9ae8a60fd89563f44c3f2f33a1ced3038daa29d727e5402ccb2d56da09fb7e193d7d9cb87c1c680618ef6a7768c30ff53b9e2631f47aa1c438601621d96ee6291df2f643bd9b189c658375204aac49c858a1ec7734a811d4457f92cb8e10f30c903fe99697bc65cf6a44cc33bd5b01a2ce0b86b5a83eb05bfde616d6ffac80a38802ac780031327bb4d2a9eb60ff7aec4c91ebbea3acec2a5239a77bd002c510a351f819056955b9e7ef07089aedc2ad4e4e9636b18d7bde86c646aae17b647c8a5a142f627d9fd7f0215651bad51903ef4f598d9ef3fbaf5c6c3386391cd10cdcb83d563140e492798c8 [...]
+    "ECPR": "0227fe9f89b72d7e4fb312683f6ff26707a3172cc35112d263dc5132732beb8fd9",
+    "ECPRT": "036c08513312ae66d0f769e7ba569de532afccc17db07ad1a9ef29f8956ada5f46",
+    "Z": "5378b46c460fee07d82f6c530d72d0bb31bbe6977483d261c80888c27f56e6714f84ce64e429f3c41168ad50366b05ee66e70afbb1e6dfc69fd60bbdf97d5a7ab78845e06ba087876c2bf1cf24b76cf9ef58bbfafc6840260bc193c8248031665d778ef776f5f8eeacf78d3fce00d17f9cb9302e0fef964fbc88580260a7d982f5013a2a29b0b8a690bbd53aef4a0672411f3505a0b3f1d0623c1042479c86a1e1de724c921a0060e897416e579985b87a216ddedf0707cd71bd77e1180c76c792c747e82d9d73aeedca55fd58563c79c474bc1ab4182cd63d18bfef9f0022ac95698942bf9ee4d34f63d83e6a370a9f88 [...]
+    "U1": "03d7e03cd311e4d7e9586bdcf9c3d050519f20ef520e92c09ffcffc5fca3034e70",
+    "U2": "39d4bceedc72f3a6fed9da6d7e45c78e0ae78a461c54161aab8dddbd01932d2731252b86426aa3e3623a390e0ff39d1ebfd9a9588ffa2b47c6d7916b0376fa4f3f6aed5aa73a796032d24a6dc8dfcc794273f455c086e15ff053fda00441c3b5d64653213d18346878641accd2efc194592b369c7c495e1e4e8135ecf5a7bdb89682ae9ec9a809842a6ef26a09dd0d4983989b34cc79160620ed2ae59fa83e369dd1c17337ff03614e7fec25e310fec8b90c50cf22e7716daaa325a732d4e5b86f995c385ed8fea1e9a9eda5eebb543bd262b26fbc31a2731439169da8a32f79bd882d2eb0f5e1d2639f5eb28e1fcdf95 [...]
+    "U3": "6640dbf4bac501c95c62c664673aac56ce4488b199c955c67108d0764f2022f3ae4aa25405312c3e4451030a16c917dffb8f367b4ea8331d01344f9a07922fb10e0cf9164c5490e22a9f88a90db18db9c1b09ef3d97a8807fbaa24f141b9606928b2db2423d3418b31b46d60cb28e84ad1c07539221893555433e4e09e9fca018346e77443497b095ac01f80a1a090b813c7cf52231598e46d8756612e9de481cbbeaac70821c2510b0770699782386ef49d90361508985a58df4f73b652185f996d0c2876662cd306bcd2a9bbf35d9107da9d45785e68c0bdd67e7711536f41adbccecda1e938142d648812c8b09597b [...]
+    "ID": "718a1cf04d069fb316f80a4c76b13ded",
+    "AD": "75499d13ebc6e28e19f50ece1503a4e8",
+    "E": "439ee149d88c6265dda5400efebd977ea423e687cc19e1b772a1ff959666d92f"
+  },
+  {
+    "TEST": 9,
+    "N": "b5ed6ca7d8c11c6097c33152897b7038514743f2b17db6353454264814ef7cfc4f68911bbd8bfcb900fd0ec1fe44bb978ef9fce66a1b83fc240bf7ccfb0b549fcac7aaae72138305515849bf8708f44c2d806c5eee44cc54f49e67354256916f37e9868f899a263a8355e6857f9c6553b8327cdb0d613a7dc8dbfaea422c94d3e8a105a4d4d011ae0a2e6fa2879bc915ff8ecf5569527ac29932ddf503a41356dfc72c9afb603784ffb67897ad6f1db11d4aef5b1b49fb8792c8111558a927dbc030a70d1a62a04da40afc6ca7e06b15031cc96fe41d6fa372dfe717d8af3cb1f5f20757a778b6efb475389df81718f023 [...]
+    "NT": "e2d11074958171a031686ab23db36f285b0e23f889cf881e66cfaccbbb4d0800fcc9972dc3469b733f0abf4222ad4981eeb748d23d82d8d2be337315b39bb1d87fb782cb59c3c21b14b05d1ba3e080f21c91be2b6a4986e961c03b405d4ab0626f603a992e450268a857e20acf91a0bc913a1d318240cbd8a4a3562fe0f84028931a63df780e9d16f756de3cb837e30412916c0ae01a5f491de64469b7a29cae5b3030314a60ee75d4aad22e0a8c7c523324e3cf402a865815e2f7bc2d51826dbc13527b9a6702f60416d0a72178e82f0e9e06762bd3fe78d4ccfc167e563ffda9bcf7b3eeac25419704d2c7a5e194eb5 [...]
+    "H1": "4b9366eb819300d02de8ecd7d68c5fc5acaddb94855137bfacd2f57c2e99e8fbc56606c98666c5f55b6d0610745a7365d74ed9669755be99ac3f19084e07b5b3bc3a4330e92d405d4132c4891e3e911f6db088e37912bdb62ba8c09f30adaa1e2acd51c5d0828c074156f2aa70916b1b7469a97f986fa13e02375f36f2f60687a4b547df95c7f2bf991113a57dac340fba7ae1430f537274faa0077ddac11e53dcc0f61c76ce92913f8e8e948272e2a2c27d202ef649db2586ecefad385d5a37b705f3d64873a303ed75015467cea32b287e3e430833df1e84b80fd2410c1e7097372bb14a1f839bea0ef51be5b80e28a [...]
+    "H2": "612641b5ccc6076044d1b268825f5b80f57525c819b5f91262144d18764805c72efa194d3815f704d9143d0f03660f642cfe8bd5152e7cb96426c9c303db0e6b70c58d5c10b1a5b9f2de94c5772a9a7388d51d18c80944945d056e975ff3a529b2b7818b65c6673def0420c3fac6323e27f40d9e01bd71db81007551499071f355c96fd782a780571f9aa2c7a078b80e9a0faf17d5e14ebd1db0090772662f8bdc294b576b25d809075252eed0a663b62cc58d12b36dc99db9cc00b240a72f8c232137d8ebbacc745e69667852716e11d93987de8f7b2053e723974fa0277ee3b28c74fd69d8057983aa56abcfc69055b [...]
+    "C": "5e148ef2ccdbe752a5c1cd87b632e2f875141f77b09839265cca08a86722b07f2c407e7a3a3ad6cf11af241e6206d8d9be0661680d783611302efdb1f249e6a60316e888e0bc0f3c24e19c764dec9f1093e838b33ef68bb4c838826f87f5bb1025d81bb7ef547ecf23a863a132a5038eb7d3bdef3be425a41d323b574edf8c6f2b25c21ea42a7a2792e24a3b8d25ec6ad935a21df83f1eb1f12ceaef516ba5a86d0167453d2ebf5bc406ae0aa62fbf8996dc59dcec67f0c5c4f2e83df26ee4f003995dcf0cb00e06c061dc74dadaa0dab0dfbe266499c26cefa5cda8c46ddfd3f0dca9b768f7508491fd453046d059c7e3 [...]
+    "ECPR": "02a391aed95d8f579f0bd815edf2e03790bc44025bf47ede4cf75e5cea4f56fce8",
+    "ECPRT": "0389ef4026d80f5df85bd9a904a24f6d926dd6ad7d9e093d848c075e817e86ce2b",
+    "Z": "0f98027cb792d5779e4a7bffcc70e0c527676aa99b271cbdaa9316f9428f1db6febbd761c5eb7e3f8e4ec4b62bcdd46f0dd5220a0fe49725c9ffb62b643d20bddd540df47944cf671fc63d1163a50831b562267ef7f4652dcd6e9140c4ee4067579d5b3a8b1be7bcdf46b0faea4d3fa1d2583ad99cfa25d614e2209f9dfc7b5676af05b9062aadf4e531abb3f2fbf0058f578b7afda4a8c7f8fdbeba4de82167fa2338159be579531b15d6c56e429e11d2701ea1a355580d941d72af0a586b98141fff9aaa461ac9608320c720f26b6763e30f5f69e8edcb0b8facb0db41c90aa85a598d1a48d0e7bc03aa8bc511258e80 [...]
+    "U1": "03ff9579fbb9301fb7ab44b9f190cc4b543f0555c7178a600effaa8c0a28a72f46",
+    "U2": "47631c6e431ea3262645a2e4b975c497310676b65adce8378957b68db4dd689ba3604b6a11770e7e7c6a2203bf534755dc5b2f8d93cbe887773c0bfed2ed65e6b10382246c935e54c4ba79d382558a185a2221d5d470b5250558b0da8d7fc5044a287e7f69275b26e6fc523eb305d9c24665cd7c3f5ba4dcf47e6db78ec79e644e5dca020a851c8efeab410aae60fdbb267aedda7f9f6c0217768793ce2c839ff05371c2dc211ec61d44de42dc9e7702e099de30408e11b32ea8d31613d64409fbd76329a7046184d5efe3fe665df9fdf59c05b1fa6ad983d7fd39dd50e6f8b76cf062c77106b91d8ccd13112a990a664 [...]
+    "U3": "b4eb3d55969c6efa979dc29a5b2eb9304c539e502aca1279fe42d3384bb14636e3439f00a6085f1ae7023cc43b02870544974f2efaaf38c8c0c68b2e71d8a125af4f91f223236107ef0b2eefb46f2cb3fca520a46eb63c4de819e07f7aec4f71807aca5a8549b9c37db18ce425ead253ffc92689456423c87e8ff9c5dc46418fda495bb5c8c1451b3ecbefd14371a21ade5355abd4bc77aabb07189cbb81fc36db3718bd2623d28ad204a3aafd94b300b72f15756a31ca9c47173e9a4a8095d6a39bcef93f6daf353455e1dd933a0747f5a85f6efa6e24d714a8d23e560ea02b234e71cce42ac2ef72aa79c2931caba4d [...]
+    "ID": "e18a8afea66d034f024e1cb443cd6c31",
+    "AD": "b9266e85c42d7440cefea436f290f30c",
+    "E": "432ca919a9d9baea6049f5b3cbfaf1e966c780d54c79923676f5f9a32b7032c4"
+  }
+]
\ No newline at end of file
diff --git a/testVectors/ggn/challenge.txt b/testVectors/ggn/challenge.txt
new file mode 100644
index 0000000..a95637a
--- /dev/null
+++ b/testVectors/ggn/challenge.txt
@@ -0,0 +1,160 @@
+TEST = 0,
+N = 921a553a20aa7e4cecdbc09d582ec1f0a7be36c8ab42f8fee848e8f27d4a2a7944a38d164d3aa60138288a53906db199cf1281c2e37fa6241bad302bfd61a6ea62420284243bb5122b1d7be76a5049069b733e37b4ef597450c8f541916dea02ecda99af27f4060aba4b681daa2e8d201aeafda76fff30d189182659658f058728b280c7b9defb8eec0459905cb2fbe36da65041fe98ab43f499349f71bc06cc6a77cb1578c550bd73ed59ebe6339114392031fce2288c9382e126c9f7247a1b30300a37c7c68aad6261f583ca9576ea37a092031dd32c4dadbcc5172f580bdd11ebc194ae42076c83790d7f6ee4e387ed0c4907 [...]
+NT = b5eed17dc8d2b334110128bd1b19e58d97c3286e2505283a9f8d060527e8aa76b08771ca8b16ac020b4e022f85f70422abe7ea8f78a0e066188a2ca022a01af3ab93b7c39ba2558425664ae00a3ac13540b9e73ffd44973fd0ed9030850d242cdbd7c8825ef164eb04de336f3e9565b3b9fedefcf5269f54c68d5d2751bd77142f2ddbe3eda0fb68f2397899515057729b7ef88e7c8a459f88b39c33592cd2d95461185522c90c4d8b0feed1c9d4e1d68b7eff16d0439b2a687b24b242521ef3af8ed11151e3b8d50bddf39d90d0d34ba6a13ddec9b0b1cea034ac6c87d9e550335b8e8268094770d137d022d51122dbaaa403a [...]
+H1 = 87c24f97195f07c03127004de18a7c538244cc16ca760e983e2c4d36c42474b57de39cb95c841e409251db6ba3e7bcd8f2dc69e8710fa0d41429d4296f95fcf17dfc10b5567241708d006ebcf1afedcb83b7f3f36f72604329b80014522a27986bf80ad6816ba9be7d33f766fe31c9d4412b4a19d306936b12f9d1a2b33c18e049334a1be9b0f90a806f82d5fbc00042960abd308930517df3683c7f364e91f10e384b15b675bea81248daf3feebf7c8a3b546a7cd1b8a41c8fb896cf3edc3585fe69da1573c620169928cee2f723c99c42267c4602e33e64e2dc152349ef954c03fbe052a9afb6308a7b8f6b37dffdc65ccc8a [...]
+H2 = 8c100b902bb70c26c9388074cdcc67ef7a72d93b938f8efcfc2d6f6344e5ac12a9f0528372ae6423e688e0d2b0a6f391db56c9e3941cc68846553dcfe445ecd5db28df078e06e64b83c86cabe60e3243e9de6689ef8197a4e77ed51282ad0813e721d050efdd8b01dbc94fa34b1565da3c2eb59ed65939433dae5019ab57aa5f9ab433c00fbc63075650743f2a92d9b3cd4b3d3603cd28b8474073b628197a01d676c54696f7399ab18fe896589f81c4c8f9d80ab12c19373416a12a4ca3ec86eef17f2b6b025bd251cfcaee2e148552dfb40b2db0b8abbca02448cbc9697ec540a69a1b91866004e7e91cf545ae7cde26a5b07 [...]
+C = 0ac4d82997f0af02db5d2dfb734217b19ab54f698235c38d650a9d95d8d6f07f881b5df9afe5f2e2a49f80676ecd2ccb6ed668b904ed56652c708d766c6a083b469c0b2c10eb7b5626d613eff7d4a04af0e2c5ca67253a1ab515403581b756f909ea8f150615940dc432e0d7a7a954623becf6c7366448913cd317374b272b43de1b0f314a960c97365318bdd5aada878836ceb4580f5569f4bb36e6c2e46a218e569a33addca33a61f37def248e89f2e2a588b0ab1cf0c3061907794a839653ed95cf848f594c40f988f70f02798330dd9c65b9707263691710b84ffc72899408e76a931a757e04ab062e460fdc00c258d1cbda [...]
+ECPR = 02b25c0d104075e6177b2291246dbd191d2e54a82388131f6fd5f9ee833027558b,
+ECPRT = 0318fdca12289e48b050567ae7c2aaf7a8a85e6f6fa2cdd4df8a24c09240e47424,
+Z = 841fbdb92f421ad6e93a8fb22fe0be4287125494e8fcb703f1f35595cc601d94fb89297de4f22e732705d2d2d9fb92ecaa814d098919b4c8e5a2339b2437c4038ea8ce7c860b8bee2e81193129e643109e43a3f4e3952bac09b461912e0aa1226aa1f310cbc86b3dd92f79d46aba90481305838022086fc69479c25635f6cc0265b53225b062111db13f26c99c963ccfbb2ca9d2f66c118ec0ac65ba662a6513a9b2cbc72938ae5e369ec8ddba054423e948fd7bb916bc7e1193f345cb4a8c74a6dd60a0c0d629c0c5ab9bc1d0b3a91cf9e69511437d02ff3be25271a6e7053db33885c26516323eeed1696d032b72bf6caef51c [...]
+U1 = 02d4d8d4f88384b5b8e61eddea985dcbd3d56e8c0c5c3370f1fa03e833083e767e,
+U2 = 315b61d3b206d20039849e12cd086d68137ff84148505552b8a7c2a9351b95a78ebf5ce3aae63a5800ad79e5a5e9f3073e7d622d557fd202b0f23df018684b464ebcb4079235b718252ce0796fe143873d3ac4b0f2c2231cbb67917a57953677f77e0c3240840f060eb2d4c78add369f582a77643b66ab13b4670c353a6fa4a4e6e05bf9c1a99f2e176632479357bbad82d2e058cb229f217791e42f3f5ba1febbd22de16f1ee68fd7195311d5718925b0ca4bbeb44cc72d6a08571af523fcde0a124ff378a732cdd476e2029414e11655e4d3440a7c75bc47433e7f1bd5003cbf7c604f1eb76b60cfb9c8f6cbd63dcd76c48b4 [...]
+U3 = 18c356f3b99295df2b80695978efe4c902cb8a1b1e5df5186f6d214408b7a682f8deff06d3b4c789290f5556e2dd5fb52882e6365748665ea7580a155a54a97a9b66dcc5b586680b51eee0889750df8e887dbc6157164de77a89c71cc3996dd4834489b1ff3ab3d916158924491c2ae7f0e942f8ec74a169f3a1fc2c23d08feea3992b8ea565a18232789b1cf3b42b423cbd3bb327c9c6167ecad1a38a360b78ccac1b4b9a94d2c25692038d6b96fcfe2d52bdf45c134a82014f7de4de80065e3bebc8e87e8eec45afc3d45083b086c42fcd116cc00f4468f024c631270476b021c33b532442a8c3e60737466598ed05c7b2508 [...]
+ID = 2f3c0ec3966ff009ddde5c2deddb7711,
+AD = ,
+E = 513137252fb05960bcf8fadc8086b6b8929a815e3eae910627df26630489dda5,
+
+TEST = 1,
+N = ab10127b209faeaff7ebef8d8a617e369522008d30db32bf55651dfafe2416a1904e673ec8a79ce82daa3ded4ca8425e97061df0c1f1ba8624141fe6f1233cb788b57caad1fa5d2e31384be540af8dc7541f6d712161715d9a25d1dc3c98bac05cba014f66fd062423886942184286963c980c2148552a2dedc8a339053a6a249819821c82aea3587e5e19bf83d2d33b2a5a0f6c422ee23c2cc9a7dd698e9f65e3f15294eba9fb91cdd11a1ec81da3587b7bf73334c26d419f69b0d33ebc103eb0644f8a3b8da6563c57c71be06c8b8b469e5b70727b24d398e75ae52b08609080eff9cda40ac784dc70b6afb98ccf5dc780b93c [...]
+NT = c1b8aab9caaf1f9021fcd135ef022089792684e7cdb1467ff522e46713609e7ebb633f19ad52e597f7dbdb59f6684f204f368b7104116a1fd8eabdc9ef7eb4b64867ad1f007f74bc57f2fb77b0b9b518af7df355e7a5d99217df442358543b76a51798e8ef194437fb4b58378943cc812942805a0b3d30eccae13fb56ea3500a781549d1d6fbd0b2ac57d63aedaa05987298201d8434b6e51b3c0e75bbd7eeb3cfbd4f79d28692110738954720784d269fabf4d4280d61e4fb8581803dd75e1be888d29d8ca419b68ea9850919c0d5563104c084f9fe0730b496b70612aa131b20b951ea8eb61c30b186a684698f22bf09d2b02 [...]
+H1 = 6addf8658d9edaad4875c43ca84b6ef6492049260aa2797344bced04707df647c8d7cd1e983358ec1587c6f83321698e71f28f3d71b0e55f36b427084375aaa4c7b6c25b34b0f6cd97b40d315ea0c174dd0152ef16a31b7cc94e2bbbf075197f8b3b803d323d9f75ebb54134dcb3841e30cbc35d0fc26a5ab3e4d270c00bf131208bca93f55a1ce26df37d5d94457f58c00a279e1e060f74ea2fe1c52df45cafc4a653b43addfbcbdf14052472b37774ef32bbf32702df4c4a349ea2d9b1aea67bd8b2662cb593958eccdc24d3d7f3f0f5ffe25ea6e8139f4f962537764a7b27d7d2bdfcbe260eb30550ede6cf1bcdec6ad84a5 [...]
+H2 = 148a15af0de2ae53bf632c93c5670edd9681e771dcb03e24a7cfe4affde977589ad0ecdf6882fe17e2d69247988b092a4a8ee48969426bffa29564d7fbc3d79141a283ae722ba6a1a11ae9e6d507df4b29e4200607d20add1a7c89de951e64bbd69055476a1069db50d77455c452ade8258e74bb92a1a5008fcc89e3f89147b3de62dadb381247165bd0c5b57f8131b18fd78a54dc34685463efd08a106b506e382dc8debef4b23c83e220bb807a98bdeee672335b6c00c6e895cd1aa43119be0f4034b4005274c44978ed0f810d3f69729d202d4bbbff732b8b541f0b6eac41efb75b87d49becb8652067a734ba3c646d3e6af [...]
+C = 4e816a6dddfeba317790176e0e49c88a971a15efc924a0e2c98002c04a9149205c51d1b1833610c006d50e03ac3477abcb7bb21bd218eb89aa1c607937615dbf27f49cb6ba1c0d5f986c042c62feb374b771f701eea1123d7c2fb4f62a0d445a07b3043ccb314af9e928aa610364ae23cc934a12c2341df9f98612d36479ae6b88aaf55ceb84851a653efe32209082e506f09e70b2b04ccdcba71f25d91a049a1f37f03c9450019ecc4fe0f6fe3790df027672135d0e181f6fdc956c0556afcc02a0180f4649861af8ea150c9c104da03b93c87116e474206bb74a421cb72e4cb8acfac1a3c27fecd9891f66d3d2b72da902e8e7 [...]
+ECPR = 02dcfabcbaf44b48a6c8f7184f0fc34b4fcb2c4a0390807627d7c1512126e28c19,
+ECPRT = 032fefe6200f5e4586f8265529a9b4a9a92f25eba742d5b01429f8143efbe45f7f,
+Z = b9059231a90071225a88b98cd3262e9fe65cb479a0376c0d9c5b2f4feec63b964523c904bb7fb842f284a3450802a8383b54dc6a340784ccb80c4812537b9d58f26fa3bbade6f97b6ea7bd120ef931b5b3f637e8a3d7afc1efa93883cdf7bc32964b4315dabd499e73896ca0fa12dda1bf398b22dae90e541402aeb4e477f9add6d337f24cd60f892e0467ee1016bba771bde8befb797f94b70cd2d771afe094d487b43419fdaf128dbbdb7b636a90db8ec13da8edf9ef5e407637878eac4cdd9aa4df93a6e819950cacb7486b136ab056a27ec9f1288d854967f0549a60d96365615f42ce4084d128bf76bf2bc6dc4b33c832ad [...]
+U1 = 025475000c7c4e9f27935bdef3a41c36b2475632dc7acbd6bcbcd7dd0bdbb1b988,
+U2 = 5b1bc5c60613880fa3ff3528f1b48114c01716ca1a38b3cba72b1ac5d3bee815d232812a37d95457b9d4642621a04795a6c32ed7c854908a23ede96c5e3d1fd1b7e259ca27817c7b28f0a30f698c289b8145fa5bae979b021e4a584c42612c816a13487fcead1ab5bcdf0d2e80e79b1390ce497ab9058c323546aea1346eaf903bf8c26eb17f621b33a5915b8f9d623d0a0a939850d8c6e73fb0c52353f8416aea8795303736e5c7ef4beb4ad839419aee4932090511f4f901121394780ce78a215b407f2dd40fcf848e7dad70f546390afc4523d2ea60d214e9fb9b903b6326076808ea6510fd3d266c4df951469f434bda6ce [...]
+U3 = 66f1c0851118b786926fe69ad012e5a8fae09830def38a2384715f1ef67e99a57bcdff5d10724551999cebca88175965573121d6e1e9f4b24150306c50a41250d5a4f8f4533553a9820ddacc8493fce7d8a8ee163d38967b012019af38f8581d8aa36a68b494619b566a7b9652a6b48d007489b0e69bda898c6b98dccee134cd508bfac201e05ac7758e337776cb280ae5a96d2a249559e2805d57caf4bb2da77ed503c66beb1a08d141e8c8b56ee38d949a671a152db6a24d511b8032b15ac5de05a0ac910346c7b9456d0466b148ad66c5b63053331b137441dee84b4daafe901c27643e75a339a666151e93339709759f435 [...]
+ID = 60cb91d6f017d8cdefb2ec397e5be569,
+AD = ,
+E = a8563cee1067e356189f74cddea2e89fda2a5b105d9c1cd31cbfcc762f67d67a,
+
+TEST = 2,
+N = e9d53095e06f3b7dd1854387a032d2041a6368939bde281eabc2d7b9a9fdc2e95fdddc24c03a3872c56ff3d3036705c1928c27efacba6653d9c47c969336b302c1d0477f0ca6cad5f37e3ac07655237d6fb1ffc85482b8651762478a255f3115bfb50ff055a5f7f62c074211b482d87e0cb2f17d1c4e2077dbc217f38d8c8a1627069412007bea45edd8f6378dbb028df879ce1353e7112fdb033c4f7aa3a7c59cb2e0cae8581a383b27fb1237786a99d45da29ca2866fd0ee9bba042b1244b7b500ed24065b0aa9ee7d11cc48484c08957caf0e89d78b69a92d3c455cb6ea1b24a631bdf3c1049ac158236f956b256611254dfe [...]
+NT = dfbdfc2a4784522a0bcd93a9925e2d185ec9af22e3c76af9e3a55552ef2d22e01c3a9e5155420383305ae63787a6451f91d2ee741c24a695272fa1f3b7ed6830d7c9f519fe3afefd97b956029c9bb781ea3efe49bc9cfd911dd132f7b1c12d9002fe73782c148b299144b664200246b3a5336b46768afe63e8b508efb0aeb71022e27307663d1ff104865310e59edeb9220630561530a7de5e3c5a74abaa4549b80d37e851c8affc44eb1024387c63a7854346ba6cf9c9305d04350b93db8cde33c3260789feff3b3c4d55cd50216e4473db4fd83d138e6bf25a9d609f010769895dd1844fdaed0cca3a773ecb734a6687ec074 [...]
+H1 = 7e9e7fa2017e570c35cdde8ba3fe095e03dbecf3c2142c62ecd8d28b225b7ac5edf75df534a0c344cf854d6403819988105b754814204b48265891da60caa01c63c6657590f2b8ab0186d73b5dd6d42030ebe74b2d7ed8ec25ab1d634c5d414c5e14c9c3b6e5024f01b738d0913f5394a28b720d6e92012a6da6540b474b42a6ea38df9eac0eb977c61030a49f87f35482a1b6ff98678824658114a562f799eff7b15f7fbc70af76d6c8bd06fd72075ec48d01ee3c512b179b465659bd768a6ce03480d6fed6d57c6c0ded176964584bbeb23c88e5f273d01d25b5c5caf1ec048040e5e1706a337423abfcb38168dfe71fb23e8 [...]
+H2 = 8260d72680ee7a036d8f4c34166b73f6818059acb570f7a44955dffed04546f42a4e399076b8a658ed8655f42f7bee3c3c3833e2a949d327e70fa7b03170aabcd2e120fe594ad4ee487a16bd546a503daed4c0f04d22f29c2f16a4c03d079ad788116f3f107bbe354e43507093db247968436fdf0d50b2cb0051d81e152d841db566590ebeea31bfdd1b034cd8adc41264efba2dcbadf4aaa5509bcb3df2cbf17e2ec9926baabc158e92a110be1c31c55e99322e6550866731a040f53ef23a70291d78cecc3d3544c0563c9baf62af3f9a5e17b5dead3353a58bc238c1a78f19178f718d241f6e4f962fb98825b9dbb27992f72 [...]
+C = 43c0efcb124877d5af44c2eb628a4a50d3783117efad16eeb3f75ab6a3a3c384b56dccb454c6758c0bc7a3173a6ea2c36a818722361181b476c1526ae55857d00e1c31afbd9ebd048445a8a2ce3573aaa24f4948854108faf8a4ddcb5e84c010b15cdeeb58930c07a36a1d5290f5f32d9375b3764e6d93d90f32047c353f7689d4576500b293715267054e3046b60d05297f63daeae1befb1786f63770b6577f0d9b94e08eaf81a3215a7839d6a1aae2b45fc9e2512bf218358b3f724281149354a52386a12b42219728bcc3f8921f666117cb11c271fd672954d24d0bb66dd0beef73a917c56b6cc407173459d06236db973390 [...]
+ECPR = 023a0ee411aad20e1df9ee97b130d4362124f5c8e9fb263296d0e0c4e06c880863,
+ECPRT = 0361a489bb687c74e131b87542d06b4a92b7a6ade047b1146d99783d0d9de18b3c,
+Z = 3846d14ea7c026a7eb32c35a50767a36ad86a52bf88520c321e32819fce1cb29322bfd91b9b2a5804619c96fa9ec0e1a7140c84c53157da075366b8f0c6e9a6db74c8a719890a48322401162c8fb985637f75c4e5e9e0355f71bb2e6a6adbe39162769037a74144acf5ce8b23b07d11af6791fa4c2569c6e98af915201f41a06c914e22c980d135db64f42f587e112b7aad084456948f33d6d45ab69ddc10f3331b8f5e8d9e7e90f95e69883120697fbb68a22682166bcf18b765ceb0cb0e4b4e5e30bfdacbf7ef78102832317dfdbdd64a9564ff7c717a52b70b6a223ab8920c151943afd67827dc5f6270907f2c515c2991511 [...]
+U1 = 025481cdeb5c1114244e7f69f7d1e8616de69d43340c75d8959207c75e94ab928f,
+U2 = 641340442e76f6a74350ec3ed5adc5fbacbc7867c9bb1205b5123016bba80e3484ed38df6bca08f0ef064c208864cb846c35dae33f5e0fd6e56ce0593f8d99f0ea21479155cc5531dc913bd511582da179b5dd61afe8db01e615bae93fae28d3c015020e197383261aba544bb890b5425fe0e326d83cebfc685455b40ba00125c64e569f6f49b7ae9b6c8148fcdd87b205dacedf69a4dbed01cd47b6b0466705d508db7dbe63ce3a00423f1e93a4cc7a54e6f774d23d8a6f4417365370f98b268eb2db8c3797c15e0c2903a5194b1b1c8f41b3f7c3d59189ee2174c235d94dcd729bee095cf5c1225fd0186f0fd2ddac30fb04e [...]
+U3 = a1da912e78259a3cd5ba5f9ea623296a50a37082f7f1ffd62c9fde6375de1048bd81a27e4a847a8c4eb6b51ca6792cd5a4ebaa286c8d0fa5cc686f887c5169f9a1324367da0d2ab0570edfa6d7d3c26b956a7bdfb1fe64d1802d2575b3ff2f47ea7b4974f63eed7f6753ac2747aaaba72cff51bbe2940e90c64e0f5e6bbb6ede57f387d5e4e952755e5911818af29fd0b96ffa26992bd916068e39e320714433b1237a43a812a2edd336ed178c9b309f76446e2920a5e7152d0f4988edfe2b0c364797a2cdb8080da6be191e9f52415f83b90bf23f3bcb259d89974b2cd246d4c056be5011b024c8f6af714ea2a59763832d14f [...]
+ID = 70e09bbfcf43d95dbc627a11fb3f8010,
+AD = ,
+E = 7e5e4991f0494d1fe780576db4f9420222790af9730593dfe89b8cb651fee6a0,
+
+TEST = 3,
+N = a5b82d0e7fcece08feb3c5aa2b56cd23677f7f6f81552f3721995ccbc9578c95ae1fa16c7503eb39125ba11606550e15177997310fda4cda2ff45d1782318ebe3aa7ada2d679921a51b20cb2fbdac8afbce9b7390ee31845bdd7b5cd7e0f5dccafc89388fa4d1ba9ee4e967cbdeb082dcd427784a2191208a2bbae2dd3630010e4db918ca543928ce8b4edbd870527ebbee673d447ca6985f88e1fc18548e0394e642c21c366d138bc0aa49ad77620c15353d456c377e1fd4b7134cadc36ccdfc99d6c61e848057dd3adeb9dee8ff71741de3bed1ad5928c36d3f239f0c3f33bbdad338d5d543f80adaf31e4216749a161bf53ec [...]
+NT = a86824e86c82674f33904dbdcb24e39d2464f3f906a90702ae2af8f71be38e87cb974493dbdfc40ec9477fde12be9f9c3d8ce49b31a9a55e8e7b56909b263106025cacbb8d454375f0078689f2c7df41e6c0a92a10aee5e53718ff1ed4ce08ac3eeef87d42e41e485f457720dd0173bea2d6aec0c6aa0046965e09c755244bf365c92f884dc2c38c415e041fda53b0226147ba3d8ded0b8d1cfb36f4aad7b98cf24f46dcbc6c83e9f40aa44d50c3c0cabc27d4c52a0c6e6fcc4736303bb65c5149a7a263a4524abdb512407a5a84267ee90412aef31d81251e20ed3735ce6f3ad0051138b21f58d95dc0bfa1b73b5b5adae3548 [...]
+H1 = 8ed8afbd7be92889040f643dffd32cec6cc11db3b9aee0b045700d66bbf8ecfc5a5f4588aaf6468756b3c733da42c1ff91348d86e442b431c70ca54bba81e2c7f0f91933d1766b92452b2fd1e480b456e3de978e0bc13c9f15241beeb6bd7ad7332353713e0cb4bc485dc470b7fcd66df062e6ddd8055533fd3a6f99cec100823fb95547e8766a6794eff1ef31668c01d30f93e5b9ca9eed454e5e2d2dfc7cc85994b3f98799b86d252ef16c5096548a75a64e458fd1ea0f6b10c0f5224abdb670dbd5b08efed90731dae1cf1744d76b627ff414724575626575baccd80c1f54adeb1cc7b1dc8e52b3b0a557757009aa1720d27 [...]
+H2 = a0da9492d31ef206fec4d5ffb2edd70a8e3124177fe5bdb5594bac44041964564b263e4ef050f519519f80522c60ba16583f2f95c2af0c9e1585438b18c270053a84a2bd19c573c2377eab661a98fd9a345efaa051b4464d297d3dc521d1c42c1202311a76cdb068e161f784af8f771920bf709392e71bc262a19b7bd312d1ab4a2acc1dbdae23a0f905cb43a6f5c278da00764a1984dbc35dbdb4896aba57860a3b4c4ab45b9a9e4ebf7eddfbe430972e727a48d49f4c5ca0e7e206865ef994df3d8ebc72e47b82f187403ee590eb2ca9564c69e3097722ca91e4a0afc01c6308245885a042b602d24f4ce4ee6c7e77c79e4d3 [...]
+C = 32379a4997213f2aaffe05208cff63ca313e8e2cb01de473089ace4332830cc3ace7925c76a018e6355e26db7a0743ab9b9537d5b23df29582e669bc305928bfff488e88957f2527ea06d42d9a9868d05f446862e0794b37d6dfa64800c6a17dcfdf008e98a604d7ce0b48afdaef4e41df955a33d620df8b8778cdf1e3974cd534bf073bebdb9e38484cdab5deeeabddc5f3a15c750b5a3959732d02f233827720f8c6dcd132c724f6c541058d6ceae78d24a471e69953073c2d95def2d50607136154e3ddf729055bab8e8eb937f7da42463beecdc31b7174145551adc31400f28671ab57aba555f0e2db02c589c2ea22247bb1 [...]
+ECPR = 038bdfadc773fd1441098b5b0327a86f43f2d032a79ad647b1a08e7b56c2920b76,
+ECPRT = 021615e29ad7fb7316feae593c54476337f9a2ac0a899c2035badba5be1d130b82,
+Z = 199b26158c7c0b60e2c0f3289bce562177da809a98faa326da6d966af2929ec58d5558df467d50ca6db60d9a46833fb832f7574feaa3a13a7196955c34ddc195b33cc27070269af7643d82721933343fbf9ffae7f687c72afb225a8fd2bfe71243fb87830ba26650b842f1e1c9ad1a60e72951cf7ef10c42a2d4aa083016cbdc8f2cfcaa6027f3596f670f662985d132ca056a519f2ffa04f724d6170197c3a515874297dab2a655a3caf9e15c2c48fefb9882384de6e8f29a8e125f2ae7a5b5bfec63fd865db051fcacd85f7e971499eed7806b3465e874be102b7bdd9dbe0509c2c58b63e52e0c350fedfb3a8b55a78aa18caf [...]
+U1 = 02142f2b52c7743ebc52dd8cdf271a804650ee032ea8bb7e3594430bf3243db506,
+U2 = 6195dcf829c2a3dc31e53fe43a4c4a6da29e9b48beb71dab613675d07224e29bfb215346756c9bcb59cdad28dcd2a278acac81334b365035b4d2d9440c9d922e607cb2b7fd17a86335e1a42286b3ffbafd8f62a304bd74dbe5b1a6b8e7db427979303a77f4c206c61590381d82c35c8f35a5f8ed38102119f202f5960b29606239775263ec72ca95a45f7d96c46173bd03de79cb48400e562bab62af00a1e384e99f7ae79c5f4c974821980e3afbb24a725ce0e7d7c867246aa7d88b8037daa800f716946ee9c967bcb96b549b8e482a0e7230303575b35ed646c15622bf617799501df0dcace34100ee95f261d0917f95b47a2 [...]
+U3 = 6d956ec5a3e5df993d32361ffad9cf40ef7c3be33f5a1be922ecc92b883867c50a5d18047d5f4f00e82bc3e442d6f5d2ff037d80cbcca4702abce52ef5be23602eda63ce8a30878ee3a80e63aef5344c6ef0f18048c6d177a88c4fbadf0bf1c4e264a1b47986434bb4c4223af42fadb5645351f6ed74ef73292991c66f815fb90bda49298ebb2be52eb58fd3af6e0a4fcfca02cf80170467ee4743970fff0e0900dcadafb7be18f2763b1d2ef1e2d80ef60d4c11f07f6b83176ac0d82dbf7e7466514c14442012bf822dbef19172885a53da8ddf1f82d1df5d892f8790ff60fc7b5bdfc2d7adf46a3f6bb2422c17f2027888c39 [...]
+ID = 37f05c3cab30aa5e4f4a59c296ba61e7,
+AD = ,
+E = f8ff6885c8035663725d758eed0a94f692296c3bf0ba58423d3e67a485d35308,
+
+TEST = 4,
+N = cfc198ce68af5e0fabdedfd5bd34ce4f57f92ebb084ce0759f9abbf4e56e007e27636b79dc8829c2835713f16e61cbd3364b0ff4de9cd0bf3114ec775302dbffae6729cd38f7fe537b49ce89a589af82e805a0f37ce3cbce47695af45e6a4fd0ca0878578500e825d43e12a36a8a8b5dd0570d6e40ade363805e40c51d26ed0d646ba927b7b07ea6c72d77f81af1284a73191f61464cdca8c38487bb0509f00e6a2932aa2c2d974360ccce6cc92a0332f3f226744efcd995d5eef150b5bddaf973ef5c3a2a48037b6bc982a214ec1a343710ebd6ae84a2cd62a97c58147b077516d34723616c86a56a92c4358549e4bb632913d1 [...]
+NT = 9c9bc9253874a40a5a355579224cba50de2b41b28e6090aff68358b3b427b6c1d380dd159830af170deb982bc00eced7f4fd1767584d8c2d9679112404d565caec1ab17d20a2f0266fdf318a98cebd98def0aaab434e5de8e2231f899cd48db142b2893bc3c61bf679e6ab1132969cf78764f27b42fc2fef54d08ef578d8b26fd6809e65540d8433d3d7624a0932b80a71733788371789c3fbc6328020e844e8b9630346bae67e04b6ef762321dc75aa4def408a27ff0b2954a7de9c6daff0a21a3081ffa60a98af89ffea10337c6a8644afe0f5072cf1748fec2653337a85a8bee2d088510863383893c86be8d76682a5b1d4b [...]
+H1 = 19e865286ff730fd0faea1b69057e69411d48b2e871db81e53aa25a10c1431abef69332560587e4500d802682c52caf28957a3db4c5c59ecf8bbdbe14cb56013dbd376063471055f66e7258f25fe0093ce73f6d299f64625976998aecf4e575a770ab5cacec6567bf0cc73ec08ff4b6400ae08d5fd65edde9c2e0c6a847ae6442029b17835bacb470e400d94b76eb364ad5d5c5ecca48d9f1defd38893335a5d5114dad0c8b9008e2b790d936f90316fa6b363f439133c384b93d8ef7833a1b1d8a9bb81300740363e2e85b6461e675b20c2c8ab9e3053b930bfefd0b8d6cc6278d1e3370763807c732df45015a2dbfd83a5633 [...]
+H2 = 29b61646d7c009f3a467fb08e00fdcf1c7c37ffe5ba961bd87857e26269992441e93c4423e16250563f17cbe4a80fec45e7f1e7791b3f11d31bb5ce579f9057a020feebd4ee1f8127dc540470e2214b0ddea75c7a4fd6d97beb285d6fd90c483777934364cab1a515a19bc5fc073beb47078ba3009410ec4d25e8a553514c2f0029f02cbdade620554122b6c3255facbf7360f9c105fbe2ebc3b82c0b5db594931791154d4fe48cbf89e105248bdd953e31903acfaaf0c43e27f4399553c5d87f4e06323c51b50f24befc9dec8c1055dd8725446945772a7b7158d49031ebd063a217b580a929f3053912488a3781c245049ff6 [...]
+C = 19c2dda447cd17f96856e6cfe382e655d5fd838adc4a398f496c6b72638cebbe8cd643a6f81bc44a00f16cb5105963c82b113f3561b36514ddf32978dbd14cf6393c384204653fb4bb0c9150ba32e5ff3f65825ad531fef51e5fb1de94902199a185b9971a36b6f77839865cecbee89928f53921aebca5dec4a29fa00db861ee447da066726643f936086c36eb1838196bfe45b351de0c23a6f53e8b8c4ee8ad6a53b5c703965542f336f1607acf7e276ab35ee20b0883042d98c1fde891cd63da7e84a797de28e193902cc84e2258a9c20c98383d7910e9cd9feb8898ce69420dd7a3c3653b63b97f977c4b807be3ab9b20bc98 [...]
+ECPR = 0287d1a1c8f61a876c3f48941e11d254080e4ec74f7e0242641c550bd2bb63069e,
+ECPRT = 0292076fb31da4656a1eb8d5d3a695a84cd89787aacd71dcca5906a7ce3fa8712f,
+Z = 66e568b01cbbd8ecf2457599d3cec7295138372ed4723088574231d6df3be84009b89e6a34c4c68fb6a53b8f4977996b1ee4edc8b2ba9058d5b2ed58a401528d966f5693d4e2dc6663ded6b3cc5e46a2e9eb8410ef70ddb95dcff2345412c5685ac8ce66f1a6758dcdb62bf74f1d6b9a8f71c90ca3ddcc5382af454dbd155b8b0bbb161b7029106fcd7db1b7a2c4a839c238036f1a1b86bbe7a65ac177018ca16232c2b9da437ad467c6f46a041d7177b3a235cd88e3213c3a4831cbd190b2fc0b9d820775fa0949a040d4f3618df127792cfd72a80cdb62bf74e77368538bf50bdccc57e5072917bb44b2405e2b672744c39f15 [...]
+U1 = 0213e2a30f953e588d14ddbe8286e2113250cd1d0c5351a7c3be60a7b0f335cb8d,
+U2 = 7565f30bc50d1fa40fb2fc6085caa9239ea9f084ad96248083efaa81c5d4ec65071875c107d4e8550f00b890f257d1c06718933575abeb776199f9f5fc06054523a9df54a9aa486f7e5aa1dbe87c7ac141d4e64b355b432cd375a0559e03d7dbd00a7526bf985ffa7a2dacc93822df13b5e22cbdd322146242bade6477843c7957f1d79a46bcf2d38f00f7f78b25d1ecbe4260c27b1531e50af7d77b4e2e1295d8db7680edffc8a1155135f3fe531b9e21bc44ad14a12e01c6ad53790efd28cd9932d822696ee7766c9927f0af4d385bc6668d1123e82f6d291801b6b225c0a4d9e04877720b71c0b0f4cbb4f4aa1451dc8ee22 [...]
+U3 = 0c4d44ae8d88f7aa7abd9562b72fbeef471240337e9c748ef8d88d879cf890b069254608db10661e9d3ddd4e5827b60671de96cac8db139bf59267aac717ed63063422645da3f10c9f06959c3230793414fb449414ebfaedeee8bb23911d06ffa9bb0d0b0be858a502311536b88e3d9bb25cf4fa88048dd7c33ee1686e00157457e5d13d431fee8da65fbeb49874d310468913c692d3a8743e312904254184a8bd76dfea76dfc16657499f770d89d828d5fb72592856239b58bf46950f5947c744740f7cf30ffdffec6bdd8be05a5deee16d4477a592ed0b4d4649ba6e37e5cb62683dcd8256e1e44596b1e0f6f67cab1ce7c04 [...]
+ID = e92cf082a4f9483ccfdb50299800e239,
+AD = ,
+E = 37ffa8e546441821f5e111e33ae1af16be3681e8edac2cdec31230d72987911f,
+
+TEST = 5,
+N = ce77b24d91a6e9e64f30a579ab160e5f91b12faf6981f334b712d70c72b65ed052c34c9b83852f60d9490e67cbc758fa876b32d2b135821def588b54f907605ff66fe0ff54214fd063896cfb76341b9c0d93c71a53d809901109f7b4402034d3c0948487164442cf18c3548b664faa5d848dd30f73eadd9455cc292dd406b04a6acec1bcc76cea7921e00d2c6e8a2b20859e51cc42a060a90ecb0e6011e95963253e6280e57190d86e14d0392d973eb91ff933f4809a9e6faf504b9ec3f8f532691a0685c90a26e3c3fcb63194f1e9ce1ccb50511b3aa1405b18bea84d4750a9fa22d7d6fe7c38031ed2691d2f5978471d939af1 [...]
+NT = b8d5562cebee1ba65ed1bc96f5a10d7f76f804ff76065ae71ef8e9224c1e8ecaec249e4ef4794053866b9052780ca0adbb656e56427d5e7e041b358a5f23036655a3bf3d180a5795f1aea576670ddc9ee3403dfa1c17babc5d86bd569c8932e404d727dd4ce769646413617a00c11527d40ffaff50b205ceb73de9591a3e614c65f92e1bc01d6f78bc8a7bc349eac9f4d432efa76be3a18d89f49abe6ad2e8fca17a2f100103e6622e290adcaa7b9d80b5fd61c2cffb533de4b9a8c8a0376a595c360f193319bce77256812e972f1e4bb2e38895783f870f7958033a59e3023224da56f5479d6fd8d990d361c4b28987232ae33 [...]
+H1 = 92a285a4bf2fa3e24e884883b846a7ae8359113b8bceece46a1c4fd8da98a8c651b20a03aa8c0ed8e69a1a461f90ec7cd3c87cb192cd833a3b641d722cc29ad77f70d530d733eeaabcbce161cad52dd0577c0219124542e1907797ce5a951174eeb83a913e92ef66dde7a40d971ed2a68efc31377df9ef00e6d1cc5bfba6d0db04775835ed21f05e2444c124fc830de4be04e583c42246ca0cd8960076b583e26dd96e6b266fa01ca5c9df56b76936224dfdb6aaee911b10d70ca92c551a2608369c1f5256dd0a6e4984da41501bbe1f6842a95e81c76ee4881485cb19f881c660cf8d0bbc8bfd66930064bf7def0ef1f2e278e [...]
+H2 = 6716d80f8e51497f16fa7a0c98ec3b55fe0dd01953a1a7545463b8f1437ddd3b1ebbc435e1420ebec35685e6d044ef0f96bef6b1f4cf1986e2ebd1c9b998ffb5dbfe090640ba50ec1e1b4f2053db9c754e450b521e8778062fd6c252570c52336d46736d00e1dfb175103c49b2287156a4a5a554810944ea3df5f1d96c8d1965d84eac05c00fcbcdb7cc1c781ca20ab22b8a741c92ac70fc83fb8920d2cdd87ff95097563c067aafa475dfc15d967e978a7b410c87c0865b94ca41294fc2dca2236396b34315ae704d0edd58958c40ab4aea79510e46d91f0046b4a5c538f847f8831d4eb8d8545c165ba9f00056b7405c5223e [...]
+C = 4d844d220247d6ed967db5b6aba73701eac73687be1f98ecde714c43fccca960988789bfea925bd9f09aa607d26e6e0c2f4f98fab9c742283bbf66cb1d645b6def73aaafd12febda784eea88b8df464e2f0fe2526bef8e99f040dd191b3915f4d4e16d8c9f233948a91e8f8decd315536bdefc3a77479c9bf2718df494d9626d7c6ab30455d50a6636a64b3b20cd54d40c84bbc3564e699b2cb78003f6fa4dae211adf8b1834bc167965e3ce488dd2f4152e3e5f33f7a2721a7f5deed6a11cda4ab111b1140dd5307c8730b11ccba9711ed2cdae84edd967bbdddbb83fcaab720c52dcabfa25da4d315a297fe9e7e7cfe189524f [...]
+ECPR = 0358a0ae4458884ab4d9465072b3bf914d3d3f65a96fc406126488aac70287b48c,
+ECPRT = 0236512a896c48c73191cec93bc956a79c092b00fdd8c94e84187491f5ca971340,
+Z = 91c8c2c7c89fc2dcc21aa25834eb5e4d2d25b175abee77e411e82e9183ed1b7b8ca5cc9d8cef8481ab9863ded2db5dc59d96d6e2da1a47904c67e98ffa7d783cdc45b69c72012107c3b5dad947f41ce509d3fff86f3bd4e7e492f6f2ec6c0d70d8177131f52bf24b116c889ad3fdee7ee10c53b75796abe669d289ac61a11f98979e45d2f7982968af03288adfb9a439ac8b81dcaf1b9aa00c76ee4185164235b338719c65309861888bffb7c8d2e6957f210fa0acce7a0582b5f51f476f51b6d8a187e60e07587a9b13342ff6772385ed0535c2234b0066c8553bc38fd16c04c049a2dece75136fa8b52f60001053379520a3c0 [...]
+U1 = 03b67e554d716e8f77c98f66afa8e88787013d10d1362773cf98e27e63f7f7e827,
+U2 = 3695764e6b14c56129a5e98d0ba25015b43d2da432fb467e50364d15ec3ffdf5947edfa8608329f1b3d767b3a1e660e0deff459ba229e1f7a4093d5ae0109d245561ed6eaaf70aacbbb9dee3149a2256278bd0e9674da48874e202bdf337dd5ac910c9861a0c95be9047efe0d1f1b1a17beb74d98f65081fd911be871ac62e8419e554efb60322b7adeb90ae4d03e6a0cdc37346717d7256e8ab3a10704cb65b039cf211b2e07440e5594ef81572bfc960b2b9180d6103fff72ea9699e4a15d4bca285aa71421e7e6b9993e3ce67a2a702da07ab8f49f3b7e7c8bce250f6c0055093463c0f3bc906608bb86cac378ce5d1be5be [...]
+U3 = 37f88495bc86a6ddcf8a10200003c95d7a684509cb01598dadc25d4eb400eb0ee8f8e4724ab7221a6840fc45cf82d5f4c1b8c2046b71a51fa9395e6b747e7336c51378eff9a3e5c14642f8c84de3896ae46769838f884623df1cf4d992a3c043a24efb351596d9c67bcb2c6bac16ff6b43c141e6976116e7dae16a3f19ed1aa10b54d2b13ad62ee7b8aea1f91fa175f15c1c0c6c26749be019fd3e696ca47b1240ee2c659e401bf96f48d656519d968074bc03ed25d652beb5b779f8b18ac208dd51c1ff2e006921cb91f2db9f6a9b58ba094f8d94be362bf9bb0c0c2518bc37f1457c3cdb252e83dc4ec1f16808c2b4bd89a70 [...]
+ID = f3239328003e27792750269e1b20d11a,
+AD = 32ab8c244cf1814ace68f28885dcdd07,
+E = 42ec22f7ea75092bbcb15633e93e140933871c10f5329c28aaa0e96341c2cd32,
+
+TEST = 6,
+N = b9e3727da2667c0275e10be602fc7c94e441e0a64231a4384ac691ab07b38beb2c9c78bb5e0877762105743bab3100dd897af199966daacf4e388dc5b8148025241b6f6353cd5ffbc16ed79e5f12264238dd7c5a8604ee6046bf49765945ef017c74f0ac50af0181203fa5a55e7c87925c8929552766da9054a7ef5e606d6ae353322d6223f3a9e38167e7ff345e5e9359266a4ae24786ea7bcae096073ec3887bea15988b3abcfbd6ab1c1448c77b230c1b33c5cfa7dc6fe1106502ec1b05774a305f48db5d5a7fb506f4df9b17bdc3b181ad90a7d20d0bfad0ccc8b9404462417736272b1c0188964dc0804d2d0a6076fcc700 [...]
+NT = d732a7a46bf87b14bc8a80b47a2867203148a8e6835f02d0788a0624a0161fe67c447f4e542bab2ebc19afb9a4c279f06c3f3797ee6a98bc86f9ecf92118547db3c8a7241e3f184934d227b408f68958cba730b5889b159ef3f75f466228788455fbfecba32d3e7fc1e384b06d116b6f1403ddc9c0974a127dbfb009378fa38fd5042831da323fc7b491f98e4b9dd143fc3c94c339316fee2ead9f19e25047fc67f8ea8b3b11959f544fbdef7da6f663513cf4946d34990d989a8caf60112ec6c1278430715a53c0374d7a1f3834cdd1fb4663637f7a09398ea45950ceddfe667dafbb963f617513f0c65ee0588b85340e268df [...]
+H1 = d104437a6f27de75138693c5bcf2041f3f05b18ecad48079464e0c7a535527dae3d73ebe1d3ed6370eefd99073c5e19f39d0a352b79cc5739898b1f08baa983c5275cd66247faaf3071640164925157144f046a66a01b7f6e1a86b96324b6d2a443eb89417804a425d34cf1093555f3d7b4aeaa28c93ef2177dee3b41328e8f75f54410478da2dc18931402ec4eab1c9d136e5e513ee88fa40110d6c1d5eae29053eccebca76e45497c20503e7865c18e13dec96b16872691765afba102b885929dfd8f773acff22bfab298931fef3b86c385f25706bf78be73c0522275481e48b59a60200ff84a287bc2dbea53c4e1e4605569 [...]
+H2 = a437e6e3b89628cf299d92dac81cad27f9459c3459ddc6c90234573d928ebaf67f3700457a815223068d0af0fbb6a6460cda5b346e42c220ff46bc4640aa9c9c331cf966c4130321bd803c5234acb5f81ab58ae0a94d20e2b83f59e69ea3bf2326bbfcd1a33f65f965cd4cb602c3b862ab6002117dafe4a70d99ea52b3deaef13d74cd56f003abd78b6c78d2ba6c95d4910d9c8f3716889d898d2ab8b32632c06f153d697a811cc5587fad49f424fdda7ab49d939989e92078ffca33e44c8cfa64c3e83147473f2b411485c1a739faeca956ce1ac2092ce22d5ec75dc139b3a67592fc9e267d69e9c774fddf0144e647430632a [...]
+C = 4f6ebfe3733cc03c759235225b25386d5af0b263a49f603305789f395b75657f447fb9d31f40b441abeb21236b4801938827570a40ce1cf4b5f8ec84c0453a89e47359f7500f86d79861d15dc1f55c6f884d05560e0eb3ff2149be7c1bf45598c655933b619e284ac9e87064ed0e3908036bbe8af38d16014e501daf6c74038ccd3fcf26941a63d4d990eed76e849e07ec08b5ca5d02a7ebeb843495a06aedbeac98056cab580bff6db85e1286b1ab34fdd93ce66a808ff3744b2405963f38be2d6c3328f3650c43af0d4ebffbdf79fa877ea6bca21e2c75e3ae4d561daa8aeeb494ec37d111fb9877208c2171a3246c1ae47c9a [...]
+ECPR = 03c660a13d2dfcbe43ae64db364073ac41db5a6e3003c0a690eb3e9a13185ae973,
+ECPRT = 034a0d8cbe826618ea41b4d83bf8485eed857b5a715309aac6bac1c90374817cc7,
+Z = 1373dcc394b037e50bc59754e522a42bacda349ab4d603af6cd399af0b64e6c1969ae22f7fad625726f821ade0a919e68a96097a05ba6d079487da731162596012f2944bdaf1fec9d080062a4fd80134593dd473b117e03579bb595f908c1eb64bc9c70bbc0d8ba5223fce3202f00cc1c0483c786ad80eab2199170b2aefa013c3b64d6e4046ce7600c7a7c8980159df578e961f607daef37b81c53d9eba70b52ae740a010fc787ece165760f4fc0543757e9f77989f1ae15f124e638981530cd37d1bb88fea66983f605c0c76d7a610c6957a0635f72d8d975bc7f17be3e2faca4554a79be219df7c07a68aa8962539b924417b [...]
+U1 = 037d344f89d0de6bd560ba61d1bdebeb16f7def4eab74d7ab97af944b763fe3786,
+U2 = 7843e5cb4bd53d69060355d8d2ebf886cc01fc252013d8a695a89784aa0afd07e944e1d2ced6b15457cbc9c28c08d9c5c7bb89d38736e13c08a4b79e8b127b50fab6ef9d5ee5d9f6349e9b4387acc26f2481cdc47998bae60abd80b9709b2d7791a6483cb92a598c4a9840dc2695c66e91ba9c487fde8b39e60db8e283cc2f7678580cd57b55bcdec8d29e97f6d58be163ba46657102ea9c4c0be6705bb310c1ca52d99a905c0bd39f89d268c1aa3598cb248d4eae0bda999d4f6ca2fc888e5ac8e378b82abac018823df328118781d32380dc33a292b0bc871856efdcd7e56e4773c04b2539a89949cbaf1bd1f25903c06f7fb [...]
+U3 = 7d2d4ac840a8f5241eac1e1411ab39154fec416bb0cb3ace088618c5f45dcb4eb1a343017fc80b7a6bf49b30b1af00930ab59ba513c47f48391276b0b5b3f4103f86a72ec33ebc482a55fa0983fec00bdca84443576523f1a041e729af3c63fdb1e3baaee2c5c06266da4fd5f38d7b9b8c17447afb73d966a211b4171a219e65db2961aee9c3e88ac9dbeabe4409fa9e47a87831e322f687922cf85d7766f375f220c0c64c67537ce814d19e7149966c3f27124b3974037f67970eaef0a0d4f1915cda9177a1e7fd0b2ea1bf533f737667f5b8f67c56bafdbcfb20f06a72a2e2fe54297aec8056283f83056419b692b0bba88cb [...]
+ID = f3485352cbdcb6d5fb2118bea541faed,
+AD = fed4e7638d7f80be9a76ad747000f217,
+E = 632e79bd50a46a07d2308f89663e8f3ea7c86213ff9bd5ae9279b8c21dcdd37c,
+
+TEST = 7,
+N = 9ff5e8e26eaa47c5df46b2e0ebba18c1ad52791a2916ded1415a6cab06b898af50adf2ac42030530b5d7259bcb625ffefb0e9a670375a8db61910f5bc423f95734d55f4707e39d38815363573b73fc786b86974158f674051d7aca32c8cbf53d75035cba7b7f6ec179dc16c505f5d723f2b8dafbfdcc013fbc7cba078bfe2e39399b4cc3f48595c876b4d4d9b0b08c9c6202446f124acb83e33ee82f822286b197fc81c18904424a3c691b27c67a6472c25e230c7fd568d0419c7b6c386fff26032b803478bf8d60662928d6e4620e7fd16bbfcb502130ee30f0d3ef1d00814720be270955922225badc23a2fbbfcd96d02501ae [...]
+NT = c031847390333f4b8b1fd0bae9a57ddc4b34bb9819f5285d08d0943db0975b61a43286ca3f83e9fa8768d670189f6ecac37cc2b5ab7e1ec3341c21b5c66816c0ad65a3bb2c45825f85a53bb40b31a89c9ead55706eeb55f8a0819c8b3a5489de0c5911a3a3e9ebf42ea1f9cc152401419e33a7e15f8d3abfc4739890374472a2d714e17587350918ff7c82d9be44f5541f74a7de905b4dc9d0c8333fcd185982a5e7a9304551032115ea99e9cd0e33a9b0c3086cb296719394f95dbb0927d4857f8c4cc4d747e0fa14d1d8478a31a124607a91c7694d511e39c295282ba72953c1460958ade560cdd4f53a4a4191aa5a4711cd9 [...]
+H1 = bfdf9437d1b78c28afdde990ed0c4843f3f2e34dd36d7a6f422040bcc79ec4ade4f40de7360a7a0ccf6c9cb3816ad60ab0d6d3f0f63f162a098428b72bc8bcbd3f78bac0bdc99a48255ae9187e5fe569c508fc3670e8862e04e2a3c6d0fd63993ac719bed183250ac41ae43fd3c8a462383d99082334db6a559ebc8db1aee5cdb85abe3439309a9a008e86264e292bf7665ed6e161c3efc591f79f693475e96068a58dcb59c9a40bd0028e30c657358beafc9e48f468df7850b7801b6cd492cffe47214e120f54b4d213b85c64e82489e59bd1350d5c9c070da8fda7917961916a903b8a315076c49b0e8064385b73a0c11931b [...]
+H2 = b39908e2028ca5364a0c426e1e351466b61ebc9a6cbb173f883571e457da322dc02125d38e58418117028953742b7117c129b58c1f0d8a675a716afa7a8eb645f0207bf2f46259922ba48ac45d790ebb1c29c876f4de6957f4793a7492506b44a0aec608713e08f2d3cab49719ceafb56ba2aa888d9bc63245f92be3e5e889b9a22e83ad0e7f1c6d6b317bba47511ea853f025003224ec8030f9f93a2be172e80b97df5bdc7f1864252881b2750a79e71c141901515ab29d94d543fb77fde99f1edcf7f4abdb04720a5d9e81fa446ae8ae7dd04fd3bd280caf36c1f6c4fe6dfcd0c43fac6c1d1c25188eeb8404efe2ec31cd750 [...]
+C = 565e10d1dd2dfb627546b2c69e6d72a8bb97276802ebd19a1535c3007317c47106472e0277af7613b0aed3ec1e92d2ad5fe8acf9e2092e08806e05940edce01be53b3f68d82f53eea3d8aec50ec94c605b1539ab24c48429ecb088f320cd4c416a2e6ae9a1c2f70199aef301c6c54baf87112db42fc9232125d3c6f777cde08404eb5bdd4b68d85458251ce48f1d77137f179d5f07090b186680dbc780d69ae983b8308ba84584bced7a17aa45fc6e113a0e8e715935cff9c4a66503aaa324fadc04f44bcb8bb54c5b8ac2d5d60f22c1f6dfda264369be1dea9740078e0ff8d7ec3c492ad779509aa3c47de0c89a4f71911af5ff [...]
+ECPR = 0313f099d8b1472c68ddd3d1750e9873300ef6404dcee76e64a198219d4198f2d7,
+ECPRT = 034403a332ab86c448db9b78b35aa3066bcabd06ac7f47f7e686692445035c685f,
+Z = 6eb41691f02074877c117b77abe6dba9f1e67b0861696ead0d2bde3f706eb3a7bd433668a130a6d7c38cf21723ee3be2d97ad598d95e4efbf1722a6405f3a70b5e638a3b3a22b0dc7cfc32be17645a74ed64a125df3268de8b449bdd2d040b30c4db64ffbbbe717dc558fe6ebfba8dd1abe96d1711385b7a98bfbb97bf04b7a992e332bd8b070d6adbb53b623903e1a5bfb22852e001a4176efe31acb118d2a92d379683bd222a0efb59d4dad104ea88de3dc974987943a14c170d5bc2aefb8b86cb95c99286cf0152651bcae563f27a25de4efc007e0d54552b7c2a262551674f447122f3d8b20b3f1f87ea24e2b42cfe9bc9d9 [...]
+U1 = 02fbd650b6c8af98111372a6e7619a556cf28192394db654ecc5970a73f7a80a0d,
+U2 = 5e7e3fedbef8239a736e8b8a36f568e8bb8c24282e9c456edef513842c0a2e0dd7c342fcdc4f12a5f5233243db157d56bf0da1980a43e034118a395e8df10bef45777048131a5a7195c1ab7c31f9a4b203611f4fc460c937a9aa41b08c0022d83cc9903502bdb59c265a8fb4909216847f35a26ffa5d0c7379ed0ddd1beb59af643383cf983774911179e88bec486e2841893c70943d763c2dd50109f8c9e31fe33acde26b03e85dad5bf7ce653ea151f1e5fa60c8db83fbeee87988adc115d2d60e4e57dc658371f6d9305ebac32fd99ffa15611c2a7186831471e5a820638b064917461df34f22f421b23d66ab20c9e85d888 [...]
+U3 = 98f7d8bf9ed0249319ad3ed7f03561a7c1580c429d30a6918803d41bd720bec83ac80f01c55967bedb86e60e9ebfacf0e265e3b27df40a82df6944366d1057c467f2d332462f9e4b37d351a67a492d9bc2664e15c10f08f8e6dfb6668ab11ef4f96715e3539d56d2343e2e68480188c392c4394fc6ecc992e854019d16063a0f23987b9bf24fc5e40f0e416ad7d1e87e085ea93bd0e4a7b21324afed966cb5364fd9dddece4b0a7c9b3497f71fab06c3be003243189d6f5b34e14db8f820d423b49607b6ddc84fdc26e7707ad0a65188435e4c2ecbac7a1d8ccd8f251b873e9d0f7e68cd6d68e33cf6f2517fbee238b997ee25e [...]
+ID = 0a3a2c0e6a5f7973145f387f465c8870,
+AD = 91bd533fdadc39d5e0b38eed816b220b,
+E = c847a0079ea425cdddd6bb1fb6be18624fc07382a4fef0b9898712078c689ea1,
+
+TEST = 8,
+N = 97389f50ad4f2e29bfbfd03fee511c01d047d9de3fe38a240fa121a7ce34fe74153a96414e0571c83f3654361d29460513d81872b2953556eac9374cbca475daeb5a61485c81140d3a66fce537564ed577918269ee5ee296faab259c41d888308d4903fa2f48039f40cb99fd7c53ed80c5f5b4fe2db7909a0a1f4481576c744f6f2653edede0dab20cda575066681d6b0e7e410a8a3c95593d3fb5f9403dcc5fe9b632b3906b7a57a97491ed7b1158ac04b812091f653489acbc35817fc8065960ffb2ab146cd2b28583ad27b24f6184f817ba955212047471ca9e63f7f1b1c1d91d94311b867e648b2ed58bfe8f7acc121efd3d [...]
+NT = aa3a57faaa2d2859140344aeeb482e83770b6ea2941c4bec7780251c6bdbd2aa247dedeb19642a8cb55f03ba8d129ea4ef10314f9aa73bedafa112afec5dcf54f90e8319cf8bb80acc148bc34cc8d731237a114d9d088ddc89d419f3180a16793dd927e77258e35260d7885aaf53e7c1338ec3e068bcb8e74e244f29caf01bd3b7da0d08a12128601c353b634bc2a85874d86d2849d69987461a68b670b7d414d7c1a6e0cb1f8aef00e647032b44c993f868b6c4940ee7f0b2c5a4ad07657d9ea889bd90aadca65e845af1a3ca449409939b5df9fbf28036b59c44bdb1d24a458d15976e7905e614fbc779094b6124159255883 [...]
+H1 = 83e79bf4f1fa086bf22f83bd8573fdae18debe8fe3975b2a0c3e5b446969f7cb8116f2daad66168e576339b9e5865a54f4d962632f1fbd9213fb420808e16b8dbb65b3feccea75cfd175c1982fac30fd634a7b36f126bae8addd75eb578bde5032777dd32a03100edad5ecf0e62089975cefae0da055964565098372498549b81087edf0f9c118e1001064137ff27736d23a0ba0e8b168cf3f53adf0db99ae03102bfc63c65f8c9637fdf89a5b64eff7fd963ed9832ffb01daf8e538409bacc07e2d6e839fc2888e8dd2aadc2434899fc3d0d92237796104eca83e5834888925e2b10f12df6cdeeae394d6abc2742a1e9cbd539 [...]
+H2 = 08eecabc2c3dd6be455c4ef1029dee1084bcb7327aebe2ef6f67f44d66d284d86263bf55c38f22e6ad5ecea5ba13ce725c20b1effc724cf4a125c12f3fea5e6bc94dffd7895f1eb94fc29687fc9d47d2347b4075630cfa6e9bf76ba1a748581da5399e539027b92a66705ceacc52b4ff5dfe45105e118c3853df999cc25f7eccbcf50c2fa020b17a41a7314e10786eea45b99b85d197e0788e335a0c452a51101cf8b98c54158485d17fe190380a4627572b9150b227112362932e7012c849b00cdc20d0acf379b5a5f67b934dea8261c3d94946a2d97e64144aae31149053f8fcf2d6c70c845aa5ee5c45a11417e94264967a3 [...]
+C = 3735c474bbc1a9ae8a60fd89563f44c3f2f33a1ced3038daa29d727e5402ccb2d56da09fb7e193d7d9cb87c1c680618ef6a7768c30ff53b9e2631f47aa1c438601621d96ee6291df2f643bd9b189c658375204aac49c858a1ec7734a811d4457f92cb8e10f30c903fe99697bc65cf6a44cc33bd5b01a2ce0b86b5a83eb05bfde616d6ffac80a38802ac780031327bb4d2a9eb60ff7aec4c91ebbea3acec2a5239a77bd002c510a351f819056955b9e7ef07089aedc2ad4e4e9636b18d7bde86c646aae17b647c8a5a142f627d9fd7f0215651bad51903ef4f598d9ef3fbaf5c6c3386391cd10cdcb83d563140e492798c845dfdc [...]
+ECPR = 0227fe9f89b72d7e4fb312683f6ff26707a3172cc35112d263dc5132732beb8fd9,
+ECPRT = 036c08513312ae66d0f769e7ba569de532afccc17db07ad1a9ef29f8956ada5f46,
+Z = 5378b46c460fee07d82f6c530d72d0bb31bbe6977483d261c80888c27f56e6714f84ce64e429f3c41168ad50366b05ee66e70afbb1e6dfc69fd60bbdf97d5a7ab78845e06ba087876c2bf1cf24b76cf9ef58bbfafc6840260bc193c8248031665d778ef776f5f8eeacf78d3fce00d17f9cb9302e0fef964fbc88580260a7d982f5013a2a29b0b8a690bbd53aef4a0672411f3505a0b3f1d0623c1042479c86a1e1de724c921a0060e897416e579985b87a216ddedf0707cd71bd77e1180c76c792c747e82d9d73aeedca55fd58563c79c474bc1ab4182cd63d18bfef9f0022ac95698942bf9ee4d34f63d83e6a370a9f88ce0495 [...]
+U1 = 03d7e03cd311e4d7e9586bdcf9c3d050519f20ef520e92c09ffcffc5fca3034e70,
+U2 = 39d4bceedc72f3a6fed9da6d7e45c78e0ae78a461c54161aab8dddbd01932d2731252b86426aa3e3623a390e0ff39d1ebfd9a9588ffa2b47c6d7916b0376fa4f3f6aed5aa73a796032d24a6dc8dfcc794273f455c086e15ff053fda00441c3b5d64653213d18346878641accd2efc194592b369c7c495e1e4e8135ecf5a7bdb89682ae9ec9a809842a6ef26a09dd0d4983989b34cc79160620ed2ae59fa83e369dd1c17337ff03614e7fec25e310fec8b90c50cf22e7716daaa325a732d4e5b86f995c385ed8fea1e9a9eda5eebb543bd262b26fbc31a2731439169da8a32f79bd882d2eb0f5e1d2639f5eb28e1fcdf95906f5c [...]
+U3 = 6640dbf4bac501c95c62c664673aac56ce4488b199c955c67108d0764f2022f3ae4aa25405312c3e4451030a16c917dffb8f367b4ea8331d01344f9a07922fb10e0cf9164c5490e22a9f88a90db18db9c1b09ef3d97a8807fbaa24f141b9606928b2db2423d3418b31b46d60cb28e84ad1c07539221893555433e4e09e9fca018346e77443497b095ac01f80a1a090b813c7cf52231598e46d8756612e9de481cbbeaac70821c2510b0770699782386ef49d90361508985a58df4f73b652185f996d0c2876662cd306bcd2a9bbf35d9107da9d45785e68c0bdd67e7711536f41adbccecda1e938142d648812c8b09597b12d100 [...]
+ID = 718a1cf04d069fb316f80a4c76b13ded,
+AD = 75499d13ebc6e28e19f50ece1503a4e8,
+E = 439ee149d88c6265dda5400efebd977ea423e687cc19e1b772a1ff959666d92f,
+
+TEST = 9,
+N = b5ed6ca7d8c11c6097c33152897b7038514743f2b17db6353454264814ef7cfc4f68911bbd8bfcb900fd0ec1fe44bb978ef9fce66a1b83fc240bf7ccfb0b549fcac7aaae72138305515849bf8708f44c2d806c5eee44cc54f49e67354256916f37e9868f899a263a8355e6857f9c6553b8327cdb0d613a7dc8dbfaea422c94d3e8a105a4d4d011ae0a2e6fa2879bc915ff8ecf5569527ac29932ddf503a41356dfc72c9afb603784ffb67897ad6f1db11d4aef5b1b49fb8792c8111558a927dbc030a70d1a62a04da40afc6ca7e06b15031cc96fe41d6fa372dfe717d8af3cb1f5f20757a778b6efb475389df81718f02359a716 [...]
+NT = e2d11074958171a031686ab23db36f285b0e23f889cf881e66cfaccbbb4d0800fcc9972dc3469b733f0abf4222ad4981eeb748d23d82d8d2be337315b39bb1d87fb782cb59c3c21b14b05d1ba3e080f21c91be2b6a4986e961c03b405d4ab0626f603a992e450268a857e20acf91a0bc913a1d318240cbd8a4a3562fe0f84028931a63df780e9d16f756de3cb837e30412916c0ae01a5f491de64469b7a29cae5b3030314a60ee75d4aad22e0a8c7c523324e3cf402a865815e2f7bc2d51826dbc13527b9a6702f60416d0a72178e82f0e9e06762bd3fe78d4ccfc167e563ffda9bcf7b3eeac25419704d2c7a5e194eb5710185 [...]
+H1 = 4b9366eb819300d02de8ecd7d68c5fc5acaddb94855137bfacd2f57c2e99e8fbc56606c98666c5f55b6d0610745a7365d74ed9669755be99ac3f19084e07b5b3bc3a4330e92d405d4132c4891e3e911f6db088e37912bdb62ba8c09f30adaa1e2acd51c5d0828c074156f2aa70916b1b7469a97f986fa13e02375f36f2f60687a4b547df95c7f2bf991113a57dac340fba7ae1430f537274faa0077ddac11e53dcc0f61c76ce92913f8e8e948272e2a2c27d202ef649db2586ecefad385d5a37b705f3d64873a303ed75015467cea32b287e3e430833df1e84b80fd2410c1e7097372bb14a1f839bea0ef51be5b80e28a2bcbf4 [...]
+H2 = 612641b5ccc6076044d1b268825f5b80f57525c819b5f91262144d18764805c72efa194d3815f704d9143d0f03660f642cfe8bd5152e7cb96426c9c303db0e6b70c58d5c10b1a5b9f2de94c5772a9a7388d51d18c80944945d056e975ff3a529b2b7818b65c6673def0420c3fac6323e27f40d9e01bd71db81007551499071f355c96fd782a780571f9aa2c7a078b80e9a0faf17d5e14ebd1db0090772662f8bdc294b576b25d809075252eed0a663b62cc58d12b36dc99db9cc00b240a72f8c232137d8ebbacc745e69667852716e11d93987de8f7b2053e723974fa0277ee3b28c74fd69d8057983aa56abcfc69055b2c2861 [...]
+C = 5e148ef2ccdbe752a5c1cd87b632e2f875141f77b09839265cca08a86722b07f2c407e7a3a3ad6cf11af241e6206d8d9be0661680d783611302efdb1f249e6a60316e888e0bc0f3c24e19c764dec9f1093e838b33ef68bb4c838826f87f5bb1025d81bb7ef547ecf23a863a132a5038eb7d3bdef3be425a41d323b574edf8c6f2b25c21ea42a7a2792e24a3b8d25ec6ad935a21df83f1eb1f12ceaef516ba5a86d0167453d2ebf5bc406ae0aa62fbf8996dc59dcec67f0c5c4f2e83df26ee4f003995dcf0cb00e06c061dc74dadaa0dab0dfbe266499c26cefa5cda8c46ddfd3f0dca9b768f7508491fd453046d059c7e39ff2e8 [...]
+ECPR = 02a391aed95d8f579f0bd815edf2e03790bc44025bf47ede4cf75e5cea4f56fce8,
+ECPRT = 0389ef4026d80f5df85bd9a904a24f6d926dd6ad7d9e093d848c075e817e86ce2b,
+Z = 0f98027cb792d5779e4a7bffcc70e0c527676aa99b271cbdaa9316f9428f1db6febbd761c5eb7e3f8e4ec4b62bcdd46f0dd5220a0fe49725c9ffb62b643d20bddd540df47944cf671fc63d1163a50831b562267ef7f4652dcd6e9140c4ee4067579d5b3a8b1be7bcdf46b0faea4d3fa1d2583ad99cfa25d614e2209f9dfc7b5676af05b9062aadf4e531abb3f2fbf0058f578b7afda4a8c7f8fdbeba4de82167fa2338159be579531b15d6c56e429e11d2701ea1a355580d941d72af0a586b98141fff9aaa461ac9608320c720f26b6763e30f5f69e8edcb0b8facb0db41c90aa85a598d1a48d0e7bc03aa8bc511258e807476ff [...]
+U1 = 03ff9579fbb9301fb7ab44b9f190cc4b543f0555c7178a600effaa8c0a28a72f46,
+U2 = 47631c6e431ea3262645a2e4b975c497310676b65adce8378957b68db4dd689ba3604b6a11770e7e7c6a2203bf534755dc5b2f8d93cbe887773c0bfed2ed65e6b10382246c935e54c4ba79d382558a185a2221d5d470b5250558b0da8d7fc5044a287e7f69275b26e6fc523eb305d9c24665cd7c3f5ba4dcf47e6db78ec79e644e5dca020a851c8efeab410aae60fdbb267aedda7f9f6c0217768793ce2c839ff05371c2dc211ec61d44de42dc9e7702e099de30408e11b32ea8d31613d64409fbd76329a7046184d5efe3fe665df9fdf59c05b1fa6ad983d7fd39dd50e6f8b76cf062c77106b91d8ccd13112a990a664bc0d33 [...]
+U3 = b4eb3d55969c6efa979dc29a5b2eb9304c539e502aca1279fe42d3384bb14636e3439f00a6085f1ae7023cc43b02870544974f2efaaf38c8c0c68b2e71d8a125af4f91f223236107ef0b2eefb46f2cb3fca520a46eb63c4de819e07f7aec4f71807aca5a8549b9c37db18ce425ead253ffc92689456423c87e8ff9c5dc46418fda495bb5c8c1451b3ecbefd14371a21ade5355abd4bc77aabb07189cbb81fc36db3718bd2623d28ad204a3aafd94b300b72f15756a31ca9c47173e9a4a8095d6a39bcef93f6daf353455e1dd933a0747f5a85f6efa6e24d714a8d23e560ea02b234e71cce42ac2ef72aa79c2931caba4d98be09 [...]
+ID = e18a8afea66d034f024e1cb443cd6c31,
+AD = b9266e85c42d7440cefea436f290f30c,
+E = 432ca919a9d9baea6049f5b3cbfaf1e966c780d54c79923676f5f9a32b7032c4,
+
diff --git a/testVectors/gmr/prove.json b/testVectors/gmr/prove.json
new file mode 100644
index 0000000..b33849e
--- /dev/null
+++ b/testVectors/gmr/prove.json
@@ -0,0 +1,82 @@
+[
+  {
+    "TEST": 0,
+    "P": "ff585e63113d5f3492533188904a03bc2ceada2c24676c6e84a55896fe8872bc362008c93f5341d73ae55882138704f07fda60d63137888142507f483b7f70532b0a8bc03ecbd7f31c4b3eff835b27e528ed36e9df324a65a62ce819606de1858dee82cce84859c9797c1bf3cd14da78426314c505cccaf4939cf7c5f008871f",
+    "ID": "a641b6d8d8363887b8186a7788dbfe7f",
+    "AD": null,
+    "Q": "f9f86d8f95defd44ddc569bec8d20829deec24a670d20c03e55716155b62f4a802f4f28e9b911a8ab38a059c3c023748856e90c9e529ff039a7d6c612f894cbb008616dd0b5819da136b825c5fc1819cebc97325142ccd8fd999086b08f9bff8fc7fc1ee6bfdfbfa3e85fa57fc58d8a434c84c73f65807e20a5e3012401da7ef",
+    "Y": "090a8f92b62a332155e01bd02ceffb722089987825a6cd545ba56cd847f31fbddd7395da39897a1e0dc41b29a80a5dddb50887135c8c6863861457b04d5b325bd06050e0502f649efaa60c6b5bb36f9f9cf080a4cb6858ab225d4124284cf70bd73ad4f78c40a0528a6a1cc7397c56ebd54ea2688cc8823d40f2649111f6bf48d23cb3247d6dd760ded5f34c504f06428dddac99fcea6a03bd82b830abcbd0b8ca1b8301f444fc79d64f2d07287e548e77365c8c267472cebaaa690581d22eae8526544a276b3171014fc2f4a73ea54a8a2ba0f776f04f7fc6f60bdd693c49a48cd9fe2cc86c6a6bb45749393473cdfe70 [...]
+  },
+  {
+    "TEST": 1,
+    "P": "cddd03a3ebe56ead88fc1633c7712d8ccb421a9caa22e6c46bdc6deeff5c3a44ac4b5f85d90b6c975d957c81b598096602096850b6998a3d17c47405e4a58c562983ed4bdf4bcb1822b0ffaaed4a9cf23731be9edd65d50e5f7217f2c3fa1b346106d64c580096bba88d0848e8670c6c684f6004d0a30702e7a4cf06a898db27",
+    "ID": "7656ca19c7a147b11befdd5c666cc761",
+    "AD": null,
+    "Q": "db44d33315f947c9506d9843ac982ef4936ef01dbb4c5afb52858836fdee3a3a61af56d2493a40876c9e5a8bbd02857ce84835a7e581ac8e64ce85d442336406d4d39343acafa1f315561da02ca21cc364643ad1e603bde42066e7ff18dea649a2d4ad6ba87e8aea623886f76c3c1e4fda44281cb9c3a07961d00cc3b2ad9d67",
+    "Y": "4d0d359b16c3bf9cf434158782020e920e2a957e11d2db57663ae9b8424f8254f32ffb1ad72eeee03ef6c81180ca94d8773a392e9021efb75e6935b6727f279f1aaf29acc15b4c46b6e1d0edccd037e73394113877d660f02f1480b6ef4c2ab0d1833dd871fe69c139eba7b8e56157bb9a07fe4c2ae9669683dbc1186950ea90da8701440dd7db9fb9454a808e335313fcf8d6d5c2ba8169b5f569e64260f0238fff19cb75fd53487f5f052fe73364c51dfe7092c3276d93fa2593b443e3d07f36b4ab3423d0ff9612c2a6d15670a6770ab87594ffb3132bb7d843955c34fbd6c9de6508adbe66afb86d377200aeb0e4f1 [...]
+  },
+  {
+    "TEST": 2,
+    "P": "e762dae52d0187c91883e1f2ef7670e5717d732c70f145724eee18f3cda98a46a1437d97d06761d214271e97a05516aef4660ffca0d1d5da4183af3bb4c302426e03b28e3f5afbf506f83f9687d1fd18553a59e2cebc9dc589d854ecdb5a490537806ff97decdf52f791e2104db4f1d7d5865448c09908438a7199e81d440dbb",
+    "ID": "a33819c78f8cb5f6e50936f4c51c0d79",
+    "AD": null,
+    "Q": "f9b835d6c9deba3f11597da88df4819f9401c1795b20eb4ef1f0a87ed9a9456d512c0bda3559479af6b3d120be7da1aa16d7f61bc33410464248f102ece408c699b675bcb56dcdc0fbb2f50c7e1eaa8450ff47043c227d1f5f2231a4437da37dbf35571248361809ae374a56b583931de0238689046cc8e6218b429fc370b9f3",
+    "Y": "1527e79d304c96be716dbee8591a3a54a84a8b1be9bb5ab2f291df05c96bb7f040c2d37f6debd5fca2ce8752a49569fcca7c3700f4bc9883cd67ff088e2869f70ea42495a69d8ebac4f988d562ad668f0169da8a86883d65393d1a24a4c5245cac4960a4dd64ed2fbe31905aab5bf9d066c000fc485bf38c5d69ad97ee244bf83d092f91dbf59846572487929b39eab1643faf7d8e0cc4069d18bc14f524c754c9f2848028253e845c369a15b7ea295ae0e5792711f42abb1541464851989944239d2795292f8f0cae4d4cef824eeb39bf8febf7a0b20186f6f447c8febfd73197ea5e9bb89d1a2f074397f7761d9a2a3b [...]
+  },
+  {
+    "TEST": 3,
+    "P": "d9473287796e9f277c9a35a86e1a58dff053c430f8e0a79aa58bdea7a5f2655dde5cb0dc91dfda57b6fe4df9961dc665c66918e28441b181f5118e7b021c103bf61d97023f62971a103bbb46be17984db146afe8a931bcf61174c8e71f41880dd5863d32e75f2a0ae0c087fd8837186dfb4ee19db85785234b8a1e4db9849b73",
+    "ID": "fd105f4bb071500d24f3e2ec51bb2278",
+    "AD": null,
+    "Q": "f5d2afce8cfca5a965b350bb7176f6d3d88fa83f47e509c1655558e4b5698f8f2ed52bf47d7b83a96325434e0997fcf31f22680ae2365b1cfb789892a553b291595d236d29b73d8bacac9804dcd088163533cc8eb8b622dcd208b55dc39a3e5aa2907f89a571ffcf23fb361a6fd8d1ca88d2e028f9f4df345e3fdfcbd4a4f19b",
+    "Y": "0e1292389b84750e62ba1acd4e93e2a8ba27fac24f588323608db30c32b1f3bc555d10975516fc7709c6a3472cbea1a6ef58abcc6f84ebd9a31024fa32538d59f086fe3099806d800eec92bdc12e4731066819cace201c4b9c7a53807ffe487643f4f06414ae20824e89f31fa9a83b582ad2e6b45d0821d97dcace260b59e039e92a4a0c673feb4cc3d2729a8237388c0914e12768a807ad74ecfa67c1e007797a328595dd89784cb32461c1f9d1929905b0682bffd6916ae00ec4d388a4f4b6c6ff714c88b2426082a3c471e8d8b26995091c7dd63849fc5099a06b9ff0517731397b77b4890bdf80c1de64d7dfbf1a25 [...]
+  },
+  {
+    "TEST": 4,
+    "P": "f9db447e907c2a2d53877e03b55db331dcda84f3169277b3dc3a56ea892517393cf1b37535cbafe03738b06b1513b8eb71dade681c2490a6c7d5e49af1ccb890080e2e0127b670e48f9c61aa2a3991cb6645dbe784b7b3070d05d9604719febfd82375c672fb2dee82615f607b186dcabc4c69881b1608de54fc25a58a588c03",
+    "ID": "8e55c989488925e51318ff1d4e24bb20",
+    "AD": null,
+    "Q": "f558ee1df99b97496b1ec3ac2abfdd77d4fdbb48d0896887e1e22dbb7e56ae6701d06ace11ccc79807217bb24704e5c206209c5a7438475323f2c745dcc7df460ff49957c7bc69b68e555830bd5683b4f915980d4c37af3826197a90c297942f48950584e8dfab717f6b6a42d4432b448a5503c2ac3fecf4a5c8f9b5f3342393",
+    "Y": "7545bb6acaad3018f3ba2e903c9a41ee91eeafdad7c874df3cc9add73be89e02e784c390109c6b3ea91c035bf6c9ca3add619e014067dd79a8161cb3921c154b309c40a76af9b1453cb5cf8c3c859b9eac41dd91c1da3f81a111f991f8d449b01530b05c22ab42207fae608b65823931e954a13fae046c8974f9a9b56034fb036fad8e85a7b3efebfd76eb51bc68edf29a5036a90bfe11e3bde868c4f7a3982652993bcc03fce152037482a4383c4c6027fdcc1fa088f8e31e3fdbfe09b454e3c2bd67ad80abbb2d48f6b1f8b4e935c1fad720e14b46287f615b6a96892df3435661e2e81df45175812e9d261784af3b89 [...]
+  },
+  {
+    "TEST": 5,
+    "P": "badfb03c311d23185cff7accd60fc644c274d912dd706cddab4443653db86e66e2c4aa11b3342ee01f1cb386c0221c245f6a9c466469a2a66189ddeca67365e4715585b04d832aac0e6caba39301a9d34eb46801e64b8b2ad812686e2661bb839a634a247b80ab80293504a366e0f8b7cbcb9ceadc59e69275629064b1a6effb",
+    "ID": "9f6f3dc1280694c09c2f557b28614503",
+    "AD": "c540ddbfbd684960ab0a0830be8dfd84",
+    "Q": "def05e4ce5bfb75ad081f40bdc51fb3c2b6f8ce78f2dd5033e23c73f059502d35f342556b53e3870938021f5a68c53369d41297660ef1fbc786c56186954d101117ec13914909e448d344c8591bdb1ae4c9b506344f94087e88af6dc91c1947918be904e788b62d8b73872552ab5b613d33e619bd9e0745e5611ede6a4696dc3",
+    "Y": "679c4ac4a9ba3ce993e862dcf8edee993a10c9b2084ca6c10b3715379c3d68dd73ef8ed7ced7e99a629e8d6696f1c9a018871347b2373cc138a102566d2d306eb03b1d9d7507673159dcb670a1b8944ecf6eaa3edf22447e4f318a8b6fb1c9c70d40bc33f7bd30e23e062babaf50dbd254d3a6fb44d82409735f5e6e1bbf528a48199eaf98f2b8e90ad1182b35d7292107ebf92fac47963e00e1eca0e6fabff05d469cba388c416258bb8f503240695f39a6a99a52c0a0b3e70ef957e6bcb51c8b1ba5013d74377c512c98798b6d0b89dc9d83c0e9ab6216496a294420d94599357e0fdfb65d94e2fb4ae6f7c9519bb7c3 [...]
+  },
+  {
+    "TEST": 6,
+    "P": "c50b0ed1cb35bbb3df60de3bb3072e47190ac884a705154b3e962e2957b745bf46748907806d078c3e20f31ca22917399c66e86e5aa34d8dbc3c98978ef1e4aa350d1bafda56e52b9ab6b570d8f96a92e795547dc63e4da51957eeedd41df423cba5f2af1de7acc5c525bf2fe9c530b036782d8f215f059ac998d3387ba9d0af",
+    "ID": "f39139fd36efd9d34f412891855b058c",
+    "AD": "cab156824ca86f72d44b727b42349f91",
+    "Q": "ffd7f37461a6fcb886d4a6475cf7c8c1fe7008538588057ca58d7223113c031cba2e02ad55eede5f62c7a655f0d456b445a3c02955716c06952e091f8ea6e8ba360d948c1a82f212f937416cb32a9d22315e1e19e0fa35902850b4429c12683c9b5ebc78cccc2f0d30543b305746c956ccaf0982421792c0517c8355f4d02cd3",
+    "Y": "1b9f2ac27c98208b37145f381e5a146cad291cd0c539fc35bb55bed1c7545f3f0f839e29b2080a67b0209a237123b3ab2b3f5285f628595bdbfdcfb5e190c09e3ade1319ef7e29452e7cf3a49c817e5125e9aba202bbd9bd081c7b7a38613243851cbfd73a1b0619670b75dde3efc9edc6b08628f1deb69bfc28116e6533c284b51b866d9144ccef78a2f625127f9618f63e2990b32d438cd16732e571285e754f4b46f7c25ee33f3dee002cf1b6dadecb8b4e7b2cb5a49be267b2612d2ca411cf2fbdaef8ecfe07d3bccac87f1187b7ba8a8391378812319af4440747b63a2a5d1dda20e7b6865bbf5b32074d33b9587c [...]
+  },
+  {
+    "TEST": 7,
+    "P": "dd4fefc4f1a733fc199c0fd5f9630156306444b62fe7042dcab72564a0b01460cff27e431a09efaabfb5e2cbbed9ab0f645e621dd9838f7a3d48a5fe194df10ac7921027fa2a4d82f7191453d70ad79d268f869435433479bfb5ffdca2b29c06f3cb8b3b79bc5db463a9d16811511ca4201da192eb485634790db034936a667b",
+    "ID": "948f107368ad33c5ce4ac57e6b9537ed",
+    "AD": "c79097e1d96a2a8c67374eb2cf9f8ac3",
+    "Q": "e00c4fe3f58d02e76f2af5fa4dfc8c138a4569ef3888699a615c0a28c823ef07abce1d92383b205c15586691b58e31c622ed9d293de3edd14df4b8fc48aecfef6005df5f075d9f026daa9b3fb882bb87365314bcb6fb4ae5f9a1938e3f9c4fe0106c29d07628675cfb1f2a81dd77f3c0177ef8ae5ccfcd2a32d011965356dffb",
+    "Y": "7bba767959ee05f33f8d0667c89f668f14f9d226e3332c77077f3dee5ab0e3416fcd57ab7d7d7a4af9a43c53f82b3acb8d2e92fe03993c004368aa17f22ea4aa2eb3c54429ef95debaee97f2fc103599198114d340958a2890f32342202ec3d7dd4fe6673e1cfa4bc34c6f9d5126248a712a34cdb6093e788f1e7f444461fa357cfc1e29e0ea5bbb5feb4212881a10c7913ef8c56375f1d42fadf59a75b624ec9eb03b4868b0b4660528144b958b460b40548c927cc333a53f192d5f921b1bfbbb7e2272cdae01c2208860dff41201b5943e2970bc29fcd4951f6fea1eb9c0d9107077c343194a960d29638a31fc7f911a [...]
+  },
+  {
+    "TEST": 8,
+    "P": "e1231c413e9b6ec5eba9cfa1a3a8b9e33f060e0f34c95dc84ca0b1f1a9d17cd12ba26704f7efe8a1c25c712a07c51e394fa6eef27b85d81f31d6a92c59613093d6e2927564cc353e2681e1a46c9f13a5e8fe75315e1b1350eeedaf9fe2c99f01d6a26fa6640def030801d0dcde2d8ffba7bce61215ec138958876a013beb6853",
+    "ID": "17799d45a9e2e8fcb13d8f4cb1ed84a6",
+    "AD": "cbd10a84405540aa527e4e3dc42dc34f",
+    "Q": "d5f1e66ec2c339b748620c67ae07eb1e5bddbc7ee36b507ac30c3b7b9aa2f5146c6b7c373b96a463e634283460484521ac692df0ec21d18ebd37477fe08436fdb790d56426b726c9180cc907fe6baa958ba1752208b99baa9389ffec1e216c26d7cd617c1eb62b7027cc0ef497912f400f47c3e897063c44a9a8c7ca3b5dcd1b",
+    "Y": "1cb1eb5c318b2fd726dfa99b6f738b57dac579450f4cf33466a66f4b1efa60443f7cf156c2b9c583c1b2fcb9eecace14670275b5a030ab4798b10158c725e26d2b8be3170f60b59ca7b98926be6e2e3ec0eec6c45f66cd7a54cb1956642a8e7208e267399e8d4f2e4747f8e6a6a8c07c8c06e3f06262d23636c232f7384d8bc593c4a6434ece4a423015fe43ae8bbec880d2ca8c8090dc27571168ca5a636d1285c98d776d8a0d23c920c2757e630f307597c7648107250194170b2d94bf86a3d0ffaa04f81ac2c46ce612596179da9aece000493e85d8944f872416c3344a97d76403d2835698fb719e8966896bb8a136 [...]
+  },
+  {
+    "TEST": 9,
+    "P": "dec78cae93ea55bab9113eafd1a75fbdd18c72110d7731fa06c71cc351759fcf2a6a2ca6ac99777657b7e2b12c858ae44360791dea79ecc7a4a218a42153e492767d7ee28155c3e55413121a943df186cf292af1e4cc6ba8f1d1a7535d969a2472cc3c2dd6a0f21cbaa57de48e0f863371a70072f814770a658080552d080cb7",
+    "ID": "dd87aa9034a9a8956ad76da1865fa130",
+    "AD": "02e9004867f51ff17944f1c6ef14c3b2",
+    "Q": "ff78db20f7007776d21b57b76ac31fc7ac0afab5dee5e76b1f68eda0b521adcece2de7c31d0f73baf1919cba96d1d4e1833a4626e14bb74915a31cf6829ccf984f61226da12702bae88a8efd7489f64512cab5d8620919c13888fb294563db1355ff55d7a68f4ba60d343658df6613caf54664641c689447d09fc5a206e677f7",
+    "Y": "06a78921fc1ab21adf3676a4365f4590897a546952debe2963c5750535d318104c33e7f3c79453643c2623bea584e0e98d23470cf93b44f9a2129f8260a2e09419c69cc1cd292fe31680344ef7b83d2a2da3022bf31035628762f760636b25611caa51311dee230d2ee074d8c9455ef2d2464f1b8a9d665a9a910d65801a756b2b26f616e1fc798fa6e001130a5f01559152f4284e5dd98c31e97f15639573bdf8e19d562b7e5dd13e85bd2573420d19c3e522f2a0a28ab39c6df9bf834fb8c60e25c6a7bc047c323b6ad84ff986aeb8870695a475abb8160a2c186b314810d2334887ab24fd05aa0ec562f1d71b4881bb [...]
+  }
+]
\ No newline at end of file
diff --git a/testVectors/gmr/prove.txt b/testVectors/gmr/prove.txt
new file mode 100644
index 0000000..2f0762a
--- /dev/null
+++ b/testVectors/gmr/prove.txt
@@ -0,0 +1,70 @@
+TEST = 0,
+P = ff585e63113d5f3492533188904a03bc2ceada2c24676c6e84a55896fe8872bc362008c93f5341d73ae55882138704f07fda60d63137888142507f483b7f70532b0a8bc03ecbd7f31c4b3eff835b27e528ed36e9df324a65a62ce819606de1858dee82cce84859c9797c1bf3cd14da78426314c505cccaf4939cf7c5f008871f,
+ID = a641b6d8d8363887b8186a7788dbfe7f,
+AD = ,
+Q = f9f86d8f95defd44ddc569bec8d20829deec24a670d20c03e55716155b62f4a802f4f28e9b911a8ab38a059c3c023748856e90c9e529ff039a7d6c612f894cbb008616dd0b5819da136b825c5fc1819cebc97325142ccd8fd999086b08f9bff8fc7fc1ee6bfdfbfa3e85fa57fc58d8a434c84c73f65807e20a5e3012401da7ef,
+Y = 090a8f92b62a332155e01bd02ceffb722089987825a6cd545ba56cd847f31fbddd7395da39897a1e0dc41b29a80a5dddb50887135c8c6863861457b04d5b325bd06050e0502f649efaa60c6b5bb36f9f9cf080a4cb6858ab225d4124284cf70bd73ad4f78c40a0528a6a1cc7397c56ebd54ea2688cc8823d40f2649111f6bf48d23cb3247d6dd760ded5f34c504f06428dddac99fcea6a03bd82b830abcbd0b8ca1b8301f444fc79d64f2d07287e548e77365c8c267472cebaaa690581d22eae8526544a276b3171014fc2f4a73ea54a8a2ba0f776f04f7fc6f60bdd693c49a48cd9fe2cc86c6a6bb45749393473cdfe7075b515 [...]
+
+TEST = 1,
+P = cddd03a3ebe56ead88fc1633c7712d8ccb421a9caa22e6c46bdc6deeff5c3a44ac4b5f85d90b6c975d957c81b598096602096850b6998a3d17c47405e4a58c562983ed4bdf4bcb1822b0ffaaed4a9cf23731be9edd65d50e5f7217f2c3fa1b346106d64c580096bba88d0848e8670c6c684f6004d0a30702e7a4cf06a898db27,
+ID = 7656ca19c7a147b11befdd5c666cc761,
+AD = ,
+Q = db44d33315f947c9506d9843ac982ef4936ef01dbb4c5afb52858836fdee3a3a61af56d2493a40876c9e5a8bbd02857ce84835a7e581ac8e64ce85d442336406d4d39343acafa1f315561da02ca21cc364643ad1e603bde42066e7ff18dea649a2d4ad6ba87e8aea623886f76c3c1e4fda44281cb9c3a07961d00cc3b2ad9d67,
+Y = 4d0d359b16c3bf9cf434158782020e920e2a957e11d2db57663ae9b8424f8254f32ffb1ad72eeee03ef6c81180ca94d8773a392e9021efb75e6935b6727f279f1aaf29acc15b4c46b6e1d0edccd037e73394113877d660f02f1480b6ef4c2ab0d1833dd871fe69c139eba7b8e56157bb9a07fe4c2ae9669683dbc1186950ea90da8701440dd7db9fb9454a808e335313fcf8d6d5c2ba8169b5f569e64260f0238fff19cb75fd53487f5f052fe73364c51dfe7092c3276d93fa2593b443e3d07f36b4ab3423d0ff9612c2a6d15670a6770ab87594ffb3132bb7d843955c34fbd6c9de6508adbe66afb86d377200aeb0e4f10b44cd [...]
+
+TEST = 2,
+P = e762dae52d0187c91883e1f2ef7670e5717d732c70f145724eee18f3cda98a46a1437d97d06761d214271e97a05516aef4660ffca0d1d5da4183af3bb4c302426e03b28e3f5afbf506f83f9687d1fd18553a59e2cebc9dc589d854ecdb5a490537806ff97decdf52f791e2104db4f1d7d5865448c09908438a7199e81d440dbb,
+ID = a33819c78f8cb5f6e50936f4c51c0d79,
+AD = ,
+Q = f9b835d6c9deba3f11597da88df4819f9401c1795b20eb4ef1f0a87ed9a9456d512c0bda3559479af6b3d120be7da1aa16d7f61bc33410464248f102ece408c699b675bcb56dcdc0fbb2f50c7e1eaa8450ff47043c227d1f5f2231a4437da37dbf35571248361809ae374a56b583931de0238689046cc8e6218b429fc370b9f3,
+Y = 1527e79d304c96be716dbee8591a3a54a84a8b1be9bb5ab2f291df05c96bb7f040c2d37f6debd5fca2ce8752a49569fcca7c3700f4bc9883cd67ff088e2869f70ea42495a69d8ebac4f988d562ad668f0169da8a86883d65393d1a24a4c5245cac4960a4dd64ed2fbe31905aab5bf9d066c000fc485bf38c5d69ad97ee244bf83d092f91dbf59846572487929b39eab1643faf7d8e0cc4069d18bc14f524c754c9f2848028253e845c369a15b7ea295ae0e5792711f42abb1541464851989944239d2795292f8f0cae4d4cef824eeb39bf8febf7a0b20186f6f447c8febfd73197ea5e9bb89d1a2f074397f7761d9a2a3b4c0c94 [...]
+
+TEST = 3,
+P = d9473287796e9f277c9a35a86e1a58dff053c430f8e0a79aa58bdea7a5f2655dde5cb0dc91dfda57b6fe4df9961dc665c66918e28441b181f5118e7b021c103bf61d97023f62971a103bbb46be17984db146afe8a931bcf61174c8e71f41880dd5863d32e75f2a0ae0c087fd8837186dfb4ee19db85785234b8a1e4db9849b73,
+ID = fd105f4bb071500d24f3e2ec51bb2278,
+AD = ,
+Q = f5d2afce8cfca5a965b350bb7176f6d3d88fa83f47e509c1655558e4b5698f8f2ed52bf47d7b83a96325434e0997fcf31f22680ae2365b1cfb789892a553b291595d236d29b73d8bacac9804dcd088163533cc8eb8b622dcd208b55dc39a3e5aa2907f89a571ffcf23fb361a6fd8d1ca88d2e028f9f4df345e3fdfcbd4a4f19b,
+Y = 0e1292389b84750e62ba1acd4e93e2a8ba27fac24f588323608db30c32b1f3bc555d10975516fc7709c6a3472cbea1a6ef58abcc6f84ebd9a31024fa32538d59f086fe3099806d800eec92bdc12e4731066819cace201c4b9c7a53807ffe487643f4f06414ae20824e89f31fa9a83b582ad2e6b45d0821d97dcace260b59e039e92a4a0c673feb4cc3d2729a8237388c0914e12768a807ad74ecfa67c1e007797a328595dd89784cb32461c1f9d1929905b0682bffd6916ae00ec4d388a4f4b6c6ff714c88b2426082a3c471e8d8b26995091c7dd63849fc5099a06b9ff0517731397b77b4890bdf80c1de64d7dfbf1a25405e70 [...]
+
+TEST = 4,
+P = f9db447e907c2a2d53877e03b55db331dcda84f3169277b3dc3a56ea892517393cf1b37535cbafe03738b06b1513b8eb71dade681c2490a6c7d5e49af1ccb890080e2e0127b670e48f9c61aa2a3991cb6645dbe784b7b3070d05d9604719febfd82375c672fb2dee82615f607b186dcabc4c69881b1608de54fc25a58a588c03,
+ID = 8e55c989488925e51318ff1d4e24bb20,
+AD = ,
+Q = f558ee1df99b97496b1ec3ac2abfdd77d4fdbb48d0896887e1e22dbb7e56ae6701d06ace11ccc79807217bb24704e5c206209c5a7438475323f2c745dcc7df460ff49957c7bc69b68e555830bd5683b4f915980d4c37af3826197a90c297942f48950584e8dfab717f6b6a42d4432b448a5503c2ac3fecf4a5c8f9b5f3342393,
+Y = 7545bb6acaad3018f3ba2e903c9a41ee91eeafdad7c874df3cc9add73be89e02e784c390109c6b3ea91c035bf6c9ca3add619e014067dd79a8161cb3921c154b309c40a76af9b1453cb5cf8c3c859b9eac41dd91c1da3f81a111f991f8d449b01530b05c22ab42207fae608b65823931e954a13fae046c8974f9a9b56034fb036fad8e85a7b3efebfd76eb51bc68edf29a5036a90bfe11e3bde868c4f7a3982652993bcc03fce152037482a4383c4c6027fdcc1fa088f8e31e3fdbfe09b454e3c2bd67ad80abbb2d48f6b1f8b4e935c1fad720e14b46287f615b6a96892df3435661e2e81df45175812e9d261784af3b89f2862f [...]
+
+TEST = 5,
+P = badfb03c311d23185cff7accd60fc644c274d912dd706cddab4443653db86e66e2c4aa11b3342ee01f1cb386c0221c245f6a9c466469a2a66189ddeca67365e4715585b04d832aac0e6caba39301a9d34eb46801e64b8b2ad812686e2661bb839a634a247b80ab80293504a366e0f8b7cbcb9ceadc59e69275629064b1a6effb,
+ID = 9f6f3dc1280694c09c2f557b28614503,
+AD = c540ddbfbd684960ab0a0830be8dfd84,
+Q = def05e4ce5bfb75ad081f40bdc51fb3c2b6f8ce78f2dd5033e23c73f059502d35f342556b53e3870938021f5a68c53369d41297660ef1fbc786c56186954d101117ec13914909e448d344c8591bdb1ae4c9b506344f94087e88af6dc91c1947918be904e788b62d8b73872552ab5b613d33e619bd9e0745e5611ede6a4696dc3,
+Y = 679c4ac4a9ba3ce993e862dcf8edee993a10c9b2084ca6c10b3715379c3d68dd73ef8ed7ced7e99a629e8d6696f1c9a018871347b2373cc138a102566d2d306eb03b1d9d7507673159dcb670a1b8944ecf6eaa3edf22447e4f318a8b6fb1c9c70d40bc33f7bd30e23e062babaf50dbd254d3a6fb44d82409735f5e6e1bbf528a48199eaf98f2b8e90ad1182b35d7292107ebf92fac47963e00e1eca0e6fabff05d469cba388c416258bb8f503240695f39a6a99a52c0a0b3e70ef957e6bcb51c8b1ba5013d74377c512c98798b6d0b89dc9d83c0e9ab6216496a294420d94599357e0fdfb65d94e2fb4ae6f7c9519bb7c3735cad [...]
+
+TEST = 6,
+P = c50b0ed1cb35bbb3df60de3bb3072e47190ac884a705154b3e962e2957b745bf46748907806d078c3e20f31ca22917399c66e86e5aa34d8dbc3c98978ef1e4aa350d1bafda56e52b9ab6b570d8f96a92e795547dc63e4da51957eeedd41df423cba5f2af1de7acc5c525bf2fe9c530b036782d8f215f059ac998d3387ba9d0af,
+ID = f39139fd36efd9d34f412891855b058c,
+AD = cab156824ca86f72d44b727b42349f91,
+Q = ffd7f37461a6fcb886d4a6475cf7c8c1fe7008538588057ca58d7223113c031cba2e02ad55eede5f62c7a655f0d456b445a3c02955716c06952e091f8ea6e8ba360d948c1a82f212f937416cb32a9d22315e1e19e0fa35902850b4429c12683c9b5ebc78cccc2f0d30543b305746c956ccaf0982421792c0517c8355f4d02cd3,
+Y = 1b9f2ac27c98208b37145f381e5a146cad291cd0c539fc35bb55bed1c7545f3f0f839e29b2080a67b0209a237123b3ab2b3f5285f628595bdbfdcfb5e190c09e3ade1319ef7e29452e7cf3a49c817e5125e9aba202bbd9bd081c7b7a38613243851cbfd73a1b0619670b75dde3efc9edc6b08628f1deb69bfc28116e6533c284b51b866d9144ccef78a2f625127f9618f63e2990b32d438cd16732e571285e754f4b46f7c25ee33f3dee002cf1b6dadecb8b4e7b2cb5a49be267b2612d2ca411cf2fbdaef8ecfe07d3bccac87f1187b7ba8a8391378812319af4440747b63a2a5d1dda20e7b6865bbf5b32074d33b9587cba8add [...]
+
+TEST = 7,
+P = dd4fefc4f1a733fc199c0fd5f9630156306444b62fe7042dcab72564a0b01460cff27e431a09efaabfb5e2cbbed9ab0f645e621dd9838f7a3d48a5fe194df10ac7921027fa2a4d82f7191453d70ad79d268f869435433479bfb5ffdca2b29c06f3cb8b3b79bc5db463a9d16811511ca4201da192eb485634790db034936a667b,
+ID = 948f107368ad33c5ce4ac57e6b9537ed,
+AD = c79097e1d96a2a8c67374eb2cf9f8ac3,
+Q = e00c4fe3f58d02e76f2af5fa4dfc8c138a4569ef3888699a615c0a28c823ef07abce1d92383b205c15586691b58e31c622ed9d293de3edd14df4b8fc48aecfef6005df5f075d9f026daa9b3fb882bb87365314bcb6fb4ae5f9a1938e3f9c4fe0106c29d07628675cfb1f2a81dd77f3c0177ef8ae5ccfcd2a32d011965356dffb,
+Y = 7bba767959ee05f33f8d0667c89f668f14f9d226e3332c77077f3dee5ab0e3416fcd57ab7d7d7a4af9a43c53f82b3acb8d2e92fe03993c004368aa17f22ea4aa2eb3c54429ef95debaee97f2fc103599198114d340958a2890f32342202ec3d7dd4fe6673e1cfa4bc34c6f9d5126248a712a34cdb6093e788f1e7f444461fa357cfc1e29e0ea5bbb5feb4212881a10c7913ef8c56375f1d42fadf59a75b624ec9eb03b4868b0b4660528144b958b460b40548c927cc333a53f192d5f921b1bfbbb7e2272cdae01c2208860dff41201b5943e2970bc29fcd4951f6fea1eb9c0d9107077c343194a960d29638a31fc7f911a4e39d6 [...]
+
+TEST = 8,
+P = e1231c413e9b6ec5eba9cfa1a3a8b9e33f060e0f34c95dc84ca0b1f1a9d17cd12ba26704f7efe8a1c25c712a07c51e394fa6eef27b85d81f31d6a92c59613093d6e2927564cc353e2681e1a46c9f13a5e8fe75315e1b1350eeedaf9fe2c99f01d6a26fa6640def030801d0dcde2d8ffba7bce61215ec138958876a013beb6853,
+ID = 17799d45a9e2e8fcb13d8f4cb1ed84a6,
+AD = cbd10a84405540aa527e4e3dc42dc34f,
+Q = d5f1e66ec2c339b748620c67ae07eb1e5bddbc7ee36b507ac30c3b7b9aa2f5146c6b7c373b96a463e634283460484521ac692df0ec21d18ebd37477fe08436fdb790d56426b726c9180cc907fe6baa958ba1752208b99baa9389ffec1e216c26d7cd617c1eb62b7027cc0ef497912f400f47c3e897063c44a9a8c7ca3b5dcd1b,
+Y = 1cb1eb5c318b2fd726dfa99b6f738b57dac579450f4cf33466a66f4b1efa60443f7cf156c2b9c583c1b2fcb9eecace14670275b5a030ab4798b10158c725e26d2b8be3170f60b59ca7b98926be6e2e3ec0eec6c45f66cd7a54cb1956642a8e7208e267399e8d4f2e4747f8e6a6a8c07c8c06e3f06262d23636c232f7384d8bc593c4a6434ece4a423015fe43ae8bbec880d2ca8c8090dc27571168ca5a636d1285c98d776d8a0d23c920c2757e630f307597c7648107250194170b2d94bf86a3d0ffaa04f81ac2c46ce612596179da9aece000493e85d8944f872416c3344a97d76403d2835698fb719e8966896bb8a136890d53 [...]
+
+TEST = 9,
+P = dec78cae93ea55bab9113eafd1a75fbdd18c72110d7731fa06c71cc351759fcf2a6a2ca6ac99777657b7e2b12c858ae44360791dea79ecc7a4a218a42153e492767d7ee28155c3e55413121a943df186cf292af1e4cc6ba8f1d1a7535d969a2472cc3c2dd6a0f21cbaa57de48e0f863371a70072f814770a658080552d080cb7,
+ID = dd87aa9034a9a8956ad76da1865fa130,
+AD = 02e9004867f51ff17944f1c6ef14c3b2,
+Q = ff78db20f7007776d21b57b76ac31fc7ac0afab5dee5e76b1f68eda0b521adcece2de7c31d0f73baf1919cba96d1d4e1833a4626e14bb74915a31cf6829ccf984f61226da12702bae88a8efd7489f64512cab5d8620919c13888fb294563db1355ff55d7a68f4ba60d343658df6613caf54664641c689447d09fc5a206e677f7,
+Y = 06a78921fc1ab21adf3676a4365f4590897a546952debe2963c5750535d318104c33e7f3c79453643c2623bea584e0e98d23470cf93b44f9a2129f8260a2e09419c69cc1cd292fe31680344ef7b83d2a2da3022bf31035628762f760636b25611caa51311dee230d2ee074d8c9455ef2d2464f1b8a9d665a9a910d65801a756b2b26f616e1fc798fa6e001130a5f01559152f4284e5dd98c31e97f15639573bdf8e19d562b7e5dd13e85bd2573420d19c3e522f2a0a28ab39c6df9bf834fb8c60e25c6a7bc047c323b6ad84ff986aeb8870695a475abb8160a2c186b314810d2334887ab24fd05aa0ec562f1d71b4881bba2a374 [...]
+
diff --git a/testVectors/gmr/verify.json b/testVectors/gmr/verify.json
new file mode 100644
index 0000000..8e7cd08
--- /dev/null
+++ b/testVectors/gmr/verify.json
@@ -0,0 +1,72 @@
+[
+  {
+    "TEST": 0,
+    "N": "b567d2252a0986075c30ae011e7e0318babcd15ea12b4b770e118b52da2aba615ee28cc2dfc190887a0746f3f1733a1c7526857386b70d70c31d61e054f2dac22f063b0a2344d02c05706d307e3044b1d678e22f94862aa9c1e14e4dde4565dac85c0e51bd288002346c130339242b2bdfbde60fafc2b01cb4290ad1019d219ea7dca6615a2dcd7a52a2d3c0970f2c27ad2d892e1778d8d3f1772ccb820edb6d91e2b04ccff8ed6ab7877603b45340fc86de7e1b4f1654804890253bb2a6f9c076e23ba2a1ce0b331ca91d385b89a358753ea2d5611829acab3bb178151349d94c40262a47601902918014c839ed1de323 [...]
+    "ID": "311929b8e4a1f145fb5ffb207d53f48c",
+    "AD": null,
+    "Y": "8363b4eddf104e104e501f5395b8d378ae82b34faaffe249ddb2c8ac0ccbf5753b323b467df51327e1824c2a72e73e095d27e5f49f83ad225ed404624b828d0953558a1ff1effce1606d4c9a43f545e95a48d0a96b9e898491e8c92b3ac20a67a3b61ca6ff912fa65235e7a207d17515a641ca9cdd9f03d6f721e0dd338403bb9b3823eb7cb48d2af9fbc5516ba3796881670f62b5c69c9206587f128adb782c11fcb1d884a14ad9d252c736bb22b1302b09a4d47de8ff15ecfae5f79bbe6ae9e8d6e02512439be5cfd25878762fc14d3d7fd725b0e0e1c8261818f01e2d3b2b5346fd5d717f9065ccb0a0480909a05663 [...]
+  },
+  {
+    "TEST": 1,
+    "N": "b5072498e0cb0df29eb80b374caf0d8767a41a1828cb173491a76399c7f343c30a8718f64367afe9860a55e5dfff3db4c965247eea5eeb5fe05cd065b780ab9c8f60a7c5ebcce67ca54e47629f9ee08d84d4a798ad1ea8110c51a14a55ed529be539b01f6161e1859e5db580a542012b67d415fe1c7807ddf4e0153994ce26e78dd5fd5cfddeb8e7540e84f3c84f66bf9f5e758ab410eeb11a418f9e02d33f9b50f811b801212712fe0b82a42bafc0d0ddee048c3f0ebc4bbc20b71ca24115133e46c35e47beb219556e96e8958f9fc217df8a7897eb3cb52cbd3e0f1677c9126e1db897bdb465f5e6a731bc71002f9dd9 [...]
+    "ID": "dae4c40ecfa7ab0aa030456a8bea0cda",
+    "AD": null,
+    "Y": "7da673e434708d233d7f12b7366993c7821174c4e0524eeeeef916bb4c192b36dd11350f61f1ddd2de508b9465f97986ee0669447d458ca0be0499763cb1efef5169cce86b2deb37876ee0c5ff92034fcd83bd0d101712e5dd2a8c5adaba3a5934f0d7051a4f3cda1e9f4381197f39b894e85a7f399abb1dc88467bae0a7b56bdffde176f505833ff0a772a33013df8d241344c633867a9277cdbf9f6aef9b19ef4ff8f0d224b59ed5275893cf94eb283becc83e64b448961b7d22e3137113708f1ca31c66557531e3b20919fea19490f0e64737f5d14fcd970e53d45edc94e5ba5abbee355c02c13349e3f98405344984 [...]
+  },
+  {
+    "TEST": 2,
+    "N": "c9bea2fd84754032345803d0aa119b794bff8d5e07499d5d01d9c9061592955c0a29bd16eb63d927bbdaa8e87a2ed861f9588b608bdb73b1782bd7f31b6941fa4213e169a2623b0aaee91e92b0ea2399fd98d9601ce40eff3baad0a9219e5914aae42ab3dbc8c35b5c6e613373b3f265992aaaeaf0c3b5fee87937502b8d5bc86d1e383d353fe5ddd487d6eb2bf407a70767e9546f81222aa0a47b71c62622192fb1c87b44280cd150fc38e0a2df8851d62dcbe45fba192790b487b1c35e7169d31947de47c0d056f7ab0bae420c4f9aff458d39e6ee0ff392f13c935a4cde34d39e68b7037cf44d5fd908bc3d6eea0d04 [...]
+    "ID": "a4d54d9d6438486bb82064e845fb8989",
+    "AD": null,
+    "Y": "71502b795176f6f201f68072aee53c8708bb610bf85e20038f891a14af719aaff442218843e70094405649ab6641ee2671e0af10f82fa2985ad25313ca005652015fd6d329bdff5ee021f35f39cb812ab9650dfa76803079ac91c7667fa6467ba2784e8750c29f7c0be9d2e2a58e0cba06fcaa11977453255396bd15fb8c9ea9b05e6a381a029995952242447f10bb887a9f4d6fb3469a092417e49ee66fb704d11f10e7e8d5eb5fbdeacc093f40b04bc8d6f196c21705605b2766ccbee9eb3ea25af2121f5b097a51c97406e9c54d67149ff89aea27d6d04057dcc249cf6b1c2de69003e2d98796dff4f75a9c9eba81fe [...]
+  },
+  {
+    "TEST": 3,
+    "N": "c45dd9d42e20f9493457d6b91f5956ddf9fb514a0328f89b9cb295720b5b466e52f0826a12e1b77e5a872aff36e91cea88817518b27e3352bc47321ff214126d75fd45017d4891d9f5aae1fa3766e8949a43158c6256d46cbe71512f699bc70141aed8af776901593657b7e3a73da6621520204335ce5e56664a07fa795a854fbb487c320850e146e2a928f740e0fddd4ba78040f30e5cb6ef3850028c88a9cb3f43427f282a0e461d0418eb29f92d7b69eba05669af1ec77bdac07ca2b7ed36032cf666b4e2c8f4b8001d0895bf3280a2abf22baa67ac8f42a77badd75a4eace2b5916b11d67fc4a63908d8b81a396619 [...]
+    "ID": "0a057231d55f08561d9dc266af8c89f3",
+    "AD": null,
+    "Y": "70d107f72a4b30bca07ab976dd2720dd741e35363fe8c0788ee9efe580af83f94aa82fdb674d293639734fa20a6242c1b1fa7d0991215ba6a4d1fa164a774dc476458a9aa0c7928e2c364cbbc2b920d53fdb03a16d5711d43deaf10122f1af3fbed10d67bdfe7af96c21262e536d77df7e2961fbc1f19ec652d6b1df16b70078c520c00544bd8030d8e5dc31bf0eb714dc5bdb8628311d7b1247427272b39065a2144b8c875eca51b2482f2fef663393de6ecd54f899494a6ff24607ef30b3c366bb964e9b055acbfbd332e101835b16d0716ed7070284fed5e4a5db5d2f24c562aae30c0f08a6a79a618f66b83f470687 [...]
+  },
+  {
+    "TEST": 4,
+    "N": "c22ca0dbb1dea809bceb95d38899c2d9fccd1387e3e36a6def501c99528d8c7d062b506368d0da15bf786a9c81938fbf725489036ff2370d2357c0b2f9f6d8b745fb414740636071cc6d16794aaf00e38377ebbab20335f0d7940c85b44f81819edfa8d1a4e183d631bedac62784ad861cd26d43c37db0a6b1441c3df24bb6dca17e52e729d0ed8857f47d1ca99f18745b78d952685be5ae4007561f49922c0ec8d64f11153b79121fb97aba0a65e50401c4e26be0f4e30b56e654b1fefc95b3d9fb2993fa9cf6f9c375b798900e5aa7cf3ef85241ae950f5b76edece6450a32a9a1be0e0ab182cc4c625d13875044b0ee [...]
+    "ID": "926e9cd633993c2f549620e4ab588e61",
+    "AD": null,
+    "Y": "6fad1c61cfa4ca59816862a38424805de3fc2ef018cfe107cd036fa31f647a3446afd0230e1f86560697542baec1783cc67680a4dd606fe29a196a3e176dc17461f74fceb33444fb50691c0277285ce84d65e65c998b45be56fc6a68dfd307249ff5035039db6fa0b3596110785b02daa90405b0d9c6d1fe50ddbd4107b22f5594e24b0c1f75105e4b45435b7fb6ccd7b8756d955972eb62bcf766ac586a306e700b86653585be8eb97e81b7aa6ea792404f889b646f0c4129b2c371a74947eb158bf66e1107b2f030d8c465343fafc2364e2ec733f7edd96f7217c15ccc08865a592a422ef01f59e57636d21679e90236 [...]
+  },
+  {
+    "TEST": 5,
+    "N": "bcb28786ad459efd7e20b83515301535a4f309201c2ca6b8259220390221bc6803eb15435117115b1a2e605ee757990b36afccf27037018bbd76b0703f2c3d04ddbc81795d8c62144d9176b05f94da5768f66c4407fbfce9de45fbf6cf0b8d88b21e7c5e3d63d92423f7e73758c9712ee2a11c513de108fa66153a00d6955d7a6dd32cc206f13518f7f5d1a62be80b99722ebd7e4e2986ce7828916864106e71ac8eb648d7920832b21aae31582cd326d1cd3b6e2f77be40ab987d4031bbdeb574ced7a94ef32eb6ac9f04fcb1ec93c2d40ca21f0966f56dda46c38a67063100a3391b6434a45dbfedfe0f9a4af8e4f889 [...]
+    "ID": "679e59a3a80fdc91e98081d5e2de33f2",
+    "AD": "2837ea217086d8fd5277be33d393e68f",
+    "Y": "6210daa96c6d17b355f254fe4478f11b94d1414c3a1367692751762eab24dee32386a5d75e55c2e56e1f4b913aab9e214e39aff6c45409f59da638fdcff24146e7433bab70f61ff2d4f6fe5e0da6af3364523e90625eae59f6534f741680c02e270080405959ed72cd0d88f05e487f4b270c9b3b12d26063ffaa813b95c7af572541b686b724ef8681b34c370f4c159a5665c4993a7ff420015756d2ec629c98feab58551280ddc58f162793b8a7c943745c69f9bcbb4fc3416b2ffd7cfa324f68e170173443718675a2259a29566a20f1d5dabc7f471293907750f51da3f746d2e8124a825bd28a898b9d88e1ff2d3731 [...]
+  },
+  {
+    "TEST": 6,
+    "N": "a9cf20f99c7f99577dee7dcf49f0cc8a9d78510b10583f6b0dfb895ffae17f322ad4bc4da2f61663d63f0f319cd0e7f70e3459ee2bcd95e44b9a57aaee3c186c1c6b056ff2a5fdcc76d6dc523a60fcdff7f01032c50d09c4828af53884069e11b67d6bbfe9e034302e5ff5d3226f7a7068d30276f84fdd2dcc20932ef57df367dde34393324065c14fa5ad54edc22fa0deae1e02de0689cb02e1f000bbc147d6e0869d66123e38eee84f8736b1d11f723d98fdd20befdfbc3ba446c999ecb1a4391d788c717e335b1b67f6a5083f51fde4dd46109fa9cd6caa54018a2c0eefe2f48e0b069b5f7507e19c0301abc225e331 [...]
+    "ID": "1ddfce08e78c7a02e4165c883c2b0723",
+    "AD": "b2bf073199917d1d088706d44ec36129",
+    "Y": "198fd7ae5b35279f5eb0ca2b53a3f9d561fe28bc0f64445a2d5b4560e40b88917c4d92c46c115c263a6b043324312faaa8a08e8d1f7231956af83145517390e425b6fd4a75b8554f2b17da89468c1bf218d8ef8a9bea8d052479d6a4a4e425c1acf040268e34b291b495db391fca681010b962575466cf0617f623f01aef9bfca96d62ecb79692c0a1fae3da1ed3e463157e21209b6ac3908aaaa3965edecbe918cbce1e2997246ca30f154b8b17213a5774ebe0d64e39c0e36767ff1e018cc608efd09ce118f681fc2a7fdbe241c3fad4d0e3fa49d690ecc550c69518bc29d660ca287200b4d3c6440cc07805bbeac0ea [...]
+  },
+  {
+    "TEST": 7,
+    "N": "9b9f8b7334ea8f8bf3b793c7cc2f8a600aa901a4bcfa3e4347036c03a696b890c04e2b5aafe0ed08f004b3b486124335c058815dcf3d885d49447fa0a0e9d3569603357d9c09f3c8afe3104d69725a19113627539adf2ccb0404c84b1384181c2691f058eaf393c32c786dc412c741e3a424e613644335fc1e6738d8d6d7cd6297f4bfdea4acbe37f6a822a243b5b0078347e7f0941309e8cd1ac64386a2c979088e9b634fb984ba9af6c3a123a51b9596873e4fb4323793e6d9d3726cfef43254ebaab044eaf21f61644cf10030ddae7d20bbc0cb5802676397e169e414b46e7ce6bd4083f01fffcae712d5a0cdc04abb [...]
+    "ID": "7c87a5fd6985450d81fcd040e5fb1d7e",
+    "AD": "98d5adc998f71c8e0841ca81056c4abe",
+    "Y": "0f09e41b4acdf78968ffe8833a6df25def0d543745fbac7e9714ac59cc616debec3917e883240d72a5edc4ade2e0bb94ca8c52447ce56dd9b4ad97c53f055335503f1877116814c7a11dc8eed058b6705d48f36db21d7f4fded13c0dc97be2e87c3a399c466fcad4b00bb2e8199efb15a292a93afd4ec212301b54c3a01902338b2dbed4210213badc0ced066380c1c4ada94473d0149cffa286fe1effe4f935346a35bfc4f182d04c23a2d0d50d1336b5f7322d3fe431d571674131b2cbd1cacc55d477eab5c0bad7e308a1a9735cca9f12c44a4d54b4d56da25c0cd9ef39f26a85ae3d889d6659b15cda65403415d82a [...]
+  },
+  {
+    "TEST": 8,
+    "N": "d80537899f467dea3eb621b6420055229b27f4cb89fba92411cf47e4e438e3f5b8cf982c7c6bdac143514be7112c98eac7386c16c7f3c1c15ffb833660a7f05ea7176c47c77edc8ffcc2811a824b6fac1cc589e28e6a2ba1ed7f275d117eec1f4c209930446388b0c8de5c232c5511b946e6fd94b7904443c64c61084c448a66f69474f09511e7e0361b639aba2d9eb6edf89d7d21314d18cfc63e040d8eb6cfc28bd57cc6a7f326bb53559625183dd49d371cd97720841127fff77e59f7f9b54ed75313a220c75e6be2c4e9ab3783e448ee1d618bd16ed22c8e19309406aa61a0d56019f2d571400a790060a5b2541680 [...]
+    "ID": "34000b01de7f4e4bb1b7034962bf0ddc",
+    "AD": "d6d0fb20b4d983244223691256854216",
+    "Y": "42f11330fc0b18b7d0789de908320577da870001607ea333315923bd0689e44e1f684fcb01cd58ba95b3c568df33845a7be7d501f1349f5a2bcf7ec27c6cdcce71fabb2db515b7fd9a6aaa4d348625b3f831f266d9330b5cbe14e163a557fca5b4254a9bc0b1bb31c26fe9cf9a19073ffeb4f8b719d4eb560ecb591ddce232e0ed5bafd64bd2e495bf84672387e89da6a860670894a27bb769a0724bd052ba4ac515d65c66b6c4458a509461b488b6558806b2735778226b3ecb43ae2eabde294b7c38b9526a3d4ed4f94c79c16ad30049127896b0f035fae5b2c3343dbb7a9287c82a3292d00544df63c521eca5bfb1d4 [...]
+  },
+  {
+    "TEST": 9,
+    "N": "a9d89f0efd30cd1d39637d3e293ad875db655e285e35c74fcfaa8003eeb3b9c9836fcc52a752172aa7621b8bf745e6bcc430102201ba9e30253ab14cc47181c2f24b7f96946e1035bd8fcceba57c9c7833fe08621ead85f7b89be769b3c1c8c7ae9ea4b6591ac811a77a0e4abcc31278b069bb7c40972988a685319971e643560604cd04e298b2a38b64b79b7eab3dc15a040dd0cc2b4c07c35fdb005a71efbae5e22b99663262626654d612a1d7a16221b0a9fbf95367d91080bf068b09708f236bd85712fbb06f17767e7ef61050738fcc6a78907ec24d57040a74601d65359ac8068852209eb8408765687fad0ba095 [...]
+    "ID": "164af3722b02922becc7713cdba4509e",
+    "AD": "ea29ae0678801ceb22f3191bc17c4793",
+    "Y": "96ff469d8173decaa50edff540c60bb9e35d9ff9b35965826df6ab3906ca72a8efe856028754fb7cb10ff0e15069b76f40c9cb054bd715f93529d8cb9f9c3415b8a99f1b53677c20066cac381e549e9519739cee3f83cb06337f4404f15a0ad61cbe45caeb096b83bf56236e437a770a1624862ccdc5eba46fe904d1ef4f94aff098c9edf3efb55e8ba2132f683ab7a711f360c74858288f4ae8720130d4dee2c7f45dd55e42745f314b2c208c9eb26a219e530f95a83047e84870bb9959cceafaa557a9380a0c8d82de41e4ac0484c9adc020e6289d7c0662de9befbd8f399ecdd1107177ee466e1ba122b9442f0ae895 [...]
+  }
+]
\ No newline at end of file
diff --git a/testVectors/gmr/verify.txt b/testVectors/gmr/verify.txt
new file mode 100644
index 0000000..e06762d
--- /dev/null
+++ b/testVectors/gmr/verify.txt
@@ -0,0 +1,60 @@
+TEST = 0,
+N = b567d2252a0986075c30ae011e7e0318babcd15ea12b4b770e118b52da2aba615ee28cc2dfc190887a0746f3f1733a1c7526857386b70d70c31d61e054f2dac22f063b0a2344d02c05706d307e3044b1d678e22f94862aa9c1e14e4dde4565dac85c0e51bd288002346c130339242b2bdfbde60fafc2b01cb4290ad1019d219ea7dca6615a2dcd7a52a2d3c0970f2c27ad2d892e1778d8d3f1772ccb820edb6d91e2b04ccff8ed6ab7877603b45340fc86de7e1b4f1654804890253bb2a6f9c076e23ba2a1ce0b331ca91d385b89a358753ea2d5611829acab3bb178151349d94c40262a47601902918014c839ed1de323a53154 [...]
+ID = 311929b8e4a1f145fb5ffb207d53f48c,
+AD = ,
+Y = 8363b4eddf104e104e501f5395b8d378ae82b34faaffe249ddb2c8ac0ccbf5753b323b467df51327e1824c2a72e73e095d27e5f49f83ad225ed404624b828d0953558a1ff1effce1606d4c9a43f545e95a48d0a96b9e898491e8c92b3ac20a67a3b61ca6ff912fa65235e7a207d17515a641ca9cdd9f03d6f721e0dd338403bb9b3823eb7cb48d2af9fbc5516ba3796881670f62b5c69c9206587f128adb782c11fcb1d884a14ad9d252c736bb22b1302b09a4d47de8ff15ecfae5f79bbe6ae9e8d6e02512439be5cfd25878762fc14d3d7fd725b0e0e1c8261818f01e2d3b2b5346fd5d717f9065ccb0a0480909a0566354a02f [...]
+
+TEST = 1,
+N = b5072498e0cb0df29eb80b374caf0d8767a41a1828cb173491a76399c7f343c30a8718f64367afe9860a55e5dfff3db4c965247eea5eeb5fe05cd065b780ab9c8f60a7c5ebcce67ca54e47629f9ee08d84d4a798ad1ea8110c51a14a55ed529be539b01f6161e1859e5db580a542012b67d415fe1c7807ddf4e0153994ce26e78dd5fd5cfddeb8e7540e84f3c84f66bf9f5e758ab410eeb11a418f9e02d33f9b50f811b801212712fe0b82a42bafc0d0ddee048c3f0ebc4bbc20b71ca24115133e46c35e47beb219556e96e8958f9fc217df8a7897eb3cb52cbd3e0f1677c9126e1db897bdb465f5e6a731bc71002f9dd97aae4f [...]
+ID = dae4c40ecfa7ab0aa030456a8bea0cda,
+AD = ,
+Y = 7da673e434708d233d7f12b7366993c7821174c4e0524eeeeef916bb4c192b36dd11350f61f1ddd2de508b9465f97986ee0669447d458ca0be0499763cb1efef5169cce86b2deb37876ee0c5ff92034fcd83bd0d101712e5dd2a8c5adaba3a5934f0d7051a4f3cda1e9f4381197f39b894e85a7f399abb1dc88467bae0a7b56bdffde176f505833ff0a772a33013df8d241344c633867a9277cdbf9f6aef9b19ef4ff8f0d224b59ed5275893cf94eb283becc83e64b448961b7d22e3137113708f1ca31c66557531e3b20919fea19490f0e64737f5d14fcd970e53d45edc94e5ba5abbee355c02c13349e3f98405344984010757 [...]
+
+TEST = 2,
+N = c9bea2fd84754032345803d0aa119b794bff8d5e07499d5d01d9c9061592955c0a29bd16eb63d927bbdaa8e87a2ed861f9588b608bdb73b1782bd7f31b6941fa4213e169a2623b0aaee91e92b0ea2399fd98d9601ce40eff3baad0a9219e5914aae42ab3dbc8c35b5c6e613373b3f265992aaaeaf0c3b5fee87937502b8d5bc86d1e383d353fe5ddd487d6eb2bf407a70767e9546f81222aa0a47b71c62622192fb1c87b44280cd150fc38e0a2df8851d62dcbe45fba192790b487b1c35e7169d31947de47c0d056f7ab0bae420c4f9aff458d39e6ee0ff392f13c935a4cde34d39e68b7037cf44d5fd908bc3d6eea0d04775730 [...]
+ID = a4d54d9d6438486bb82064e845fb8989,
+AD = ,
+Y = 71502b795176f6f201f68072aee53c8708bb610bf85e20038f891a14af719aaff442218843e70094405649ab6641ee2671e0af10f82fa2985ad25313ca005652015fd6d329bdff5ee021f35f39cb812ab9650dfa76803079ac91c7667fa6467ba2784e8750c29f7c0be9d2e2a58e0cba06fcaa11977453255396bd15fb8c9ea9b05e6a381a029995952242447f10bb887a9f4d6fb3469a092417e49ee66fb704d11f10e7e8d5eb5fbdeacc093f40b04bc8d6f196c21705605b2766ccbee9eb3ea25af2121f5b097a51c97406e9c54d67149ff89aea27d6d04057dcc249cf6b1c2de69003e2d98796dff4f75a9c9eba81fe426ff9 [...]
+
+TEST = 3,
+N = c45dd9d42e20f9493457d6b91f5956ddf9fb514a0328f89b9cb295720b5b466e52f0826a12e1b77e5a872aff36e91cea88817518b27e3352bc47321ff214126d75fd45017d4891d9f5aae1fa3766e8949a43158c6256d46cbe71512f699bc70141aed8af776901593657b7e3a73da6621520204335ce5e56664a07fa795a854fbb487c320850e146e2a928f740e0fddd4ba78040f30e5cb6ef3850028c88a9cb3f43427f282a0e461d0418eb29f92d7b69eba05669af1ec77bdac07ca2b7ed36032cf666b4e2c8f4b8001d0895bf3280a2abf22baa67ac8f42a77badd75a4eace2b5916b11d67fc4a63908d8b81a3966196f92ec [...]
+ID = 0a057231d55f08561d9dc266af8c89f3,
+AD = ,
+Y = 70d107f72a4b30bca07ab976dd2720dd741e35363fe8c0788ee9efe580af83f94aa82fdb674d293639734fa20a6242c1b1fa7d0991215ba6a4d1fa164a774dc476458a9aa0c7928e2c364cbbc2b920d53fdb03a16d5711d43deaf10122f1af3fbed10d67bdfe7af96c21262e536d77df7e2961fbc1f19ec652d6b1df16b70078c520c00544bd8030d8e5dc31bf0eb714dc5bdb8628311d7b1247427272b39065a2144b8c875eca51b2482f2fef663393de6ecd54f899494a6ff24607ef30b3c366bb964e9b055acbfbd332e101835b16d0716ed7070284fed5e4a5db5d2f24c562aae30c0f08a6a79a618f66b83f470687ad12c4 [...]
+
+TEST = 4,
+N = c22ca0dbb1dea809bceb95d38899c2d9fccd1387e3e36a6def501c99528d8c7d062b506368d0da15bf786a9c81938fbf725489036ff2370d2357c0b2f9f6d8b745fb414740636071cc6d16794aaf00e38377ebbab20335f0d7940c85b44f81819edfa8d1a4e183d631bedac62784ad861cd26d43c37db0a6b1441c3df24bb6dca17e52e729d0ed8857f47d1ca99f18745b78d952685be5ae4007561f49922c0ec8d64f11153b79121fb97aba0a65e50401c4e26be0f4e30b56e654b1fefc95b3d9fb2993fa9cf6f9c375b798900e5aa7cf3ef85241ae950f5b76edece6450a32a9a1be0e0ab182cc4c625d13875044b0ee8ce7b8 [...]
+ID = 926e9cd633993c2f549620e4ab588e61,
+AD = ,
+Y = 6fad1c61cfa4ca59816862a38424805de3fc2ef018cfe107cd036fa31f647a3446afd0230e1f86560697542baec1783cc67680a4dd606fe29a196a3e176dc17461f74fceb33444fb50691c0277285ce84d65e65c998b45be56fc6a68dfd307249ff5035039db6fa0b3596110785b02daa90405b0d9c6d1fe50ddbd4107b22f5594e24b0c1f75105e4b45435b7fb6ccd7b8756d955972eb62bcf766ac586a306e700b86653585be8eb97e81b7aa6ea792404f889b646f0c4129b2c371a74947eb158bf66e1107b2f030d8c465343fafc2364e2ec733f7edd96f7217c15ccc08865a592a422ef01f59e57636d21679e90236b79eb3 [...]
+
+TEST = 5,
+N = bcb28786ad459efd7e20b83515301535a4f309201c2ca6b8259220390221bc6803eb15435117115b1a2e605ee757990b36afccf27037018bbd76b0703f2c3d04ddbc81795d8c62144d9176b05f94da5768f66c4407fbfce9de45fbf6cf0b8d88b21e7c5e3d63d92423f7e73758c9712ee2a11c513de108fa66153a00d6955d7a6dd32cc206f13518f7f5d1a62be80b99722ebd7e4e2986ce7828916864106e71ac8eb648d7920832b21aae31582cd326d1cd3b6e2f77be40ab987d4031bbdeb574ced7a94ef32eb6ac9f04fcb1ec93c2d40ca21f0966f56dda46c38a67063100a3391b6434a45dbfedfe0f9a4af8e4f889f319db [...]
+ID = 679e59a3a80fdc91e98081d5e2de33f2,
+AD = 2837ea217086d8fd5277be33d393e68f,
+Y = 6210daa96c6d17b355f254fe4478f11b94d1414c3a1367692751762eab24dee32386a5d75e55c2e56e1f4b913aab9e214e39aff6c45409f59da638fdcff24146e7433bab70f61ff2d4f6fe5e0da6af3364523e90625eae59f6534f741680c02e270080405959ed72cd0d88f05e487f4b270c9b3b12d26063ffaa813b95c7af572541b686b724ef8681b34c370f4c159a5665c4993a7ff420015756d2ec629c98feab58551280ddc58f162793b8a7c943745c69f9bcbb4fc3416b2ffd7cfa324f68e170173443718675a2259a29566a20f1d5dabc7f471293907750f51da3f746d2e8124a825bd28a898b9d88e1ff2d373136a7fb [...]
+
+TEST = 6,
+N = a9cf20f99c7f99577dee7dcf49f0cc8a9d78510b10583f6b0dfb895ffae17f322ad4bc4da2f61663d63f0f319cd0e7f70e3459ee2bcd95e44b9a57aaee3c186c1c6b056ff2a5fdcc76d6dc523a60fcdff7f01032c50d09c4828af53884069e11b67d6bbfe9e034302e5ff5d3226f7a7068d30276f84fdd2dcc20932ef57df367dde34393324065c14fa5ad54edc22fa0deae1e02de0689cb02e1f000bbc147d6e0869d66123e38eee84f8736b1d11f723d98fdd20befdfbc3ba446c999ecb1a4391d788c717e335b1b67f6a5083f51fde4dd46109fa9cd6caa54018a2c0eefe2f48e0b069b5f7507e19c0301abc225e3318caa73 [...]
+ID = 1ddfce08e78c7a02e4165c883c2b0723,
+AD = b2bf073199917d1d088706d44ec36129,
+Y = 198fd7ae5b35279f5eb0ca2b53a3f9d561fe28bc0f64445a2d5b4560e40b88917c4d92c46c115c263a6b043324312faaa8a08e8d1f7231956af83145517390e425b6fd4a75b8554f2b17da89468c1bf218d8ef8a9bea8d052479d6a4a4e425c1acf040268e34b291b495db391fca681010b962575466cf0617f623f01aef9bfca96d62ecb79692c0a1fae3da1ed3e463157e21209b6ac3908aaaa3965edecbe918cbce1e2997246ca30f154b8b17213a5774ebe0d64e39c0e36767ff1e018cc608efd09ce118f681fc2a7fdbe241c3fad4d0e3fa49d690ecc550c69518bc29d660ca287200b4d3c6440cc07805bbeac0ea7004df [...]
+
+TEST = 7,
+N = 9b9f8b7334ea8f8bf3b793c7cc2f8a600aa901a4bcfa3e4347036c03a696b890c04e2b5aafe0ed08f004b3b486124335c058815dcf3d885d49447fa0a0e9d3569603357d9c09f3c8afe3104d69725a19113627539adf2ccb0404c84b1384181c2691f058eaf393c32c786dc412c741e3a424e613644335fc1e6738d8d6d7cd6297f4bfdea4acbe37f6a822a243b5b0078347e7f0941309e8cd1ac64386a2c979088e9b634fb984ba9af6c3a123a51b9596873e4fb4323793e6d9d3726cfef43254ebaab044eaf21f61644cf10030ddae7d20bbc0cb5802676397e169e414b46e7ce6bd4083f01fffcae712d5a0cdc04abb9101b2 [...]
+ID = 7c87a5fd6985450d81fcd040e5fb1d7e,
+AD = 98d5adc998f71c8e0841ca81056c4abe,
+Y = 0f09e41b4acdf78968ffe8833a6df25def0d543745fbac7e9714ac59cc616debec3917e883240d72a5edc4ade2e0bb94ca8c52447ce56dd9b4ad97c53f055335503f1877116814c7a11dc8eed058b6705d48f36db21d7f4fded13c0dc97be2e87c3a399c466fcad4b00bb2e8199efb15a292a93afd4ec212301b54c3a01902338b2dbed4210213badc0ced066380c1c4ada94473d0149cffa286fe1effe4f935346a35bfc4f182d04c23a2d0d50d1336b5f7322d3fe431d571674131b2cbd1cacc55d477eab5c0bad7e308a1a9735cca9f12c44a4d54b4d56da25c0cd9ef39f26a85ae3d889d6659b15cda65403415d82a23b57b [...]
+
+TEST = 8,
+N = d80537899f467dea3eb621b6420055229b27f4cb89fba92411cf47e4e438e3f5b8cf982c7c6bdac143514be7112c98eac7386c16c7f3c1c15ffb833660a7f05ea7176c47c77edc8ffcc2811a824b6fac1cc589e28e6a2ba1ed7f275d117eec1f4c209930446388b0c8de5c232c5511b946e6fd94b7904443c64c61084c448a66f69474f09511e7e0361b639aba2d9eb6edf89d7d21314d18cfc63e040d8eb6cfc28bd57cc6a7f326bb53559625183dd49d371cd97720841127fff77e59f7f9b54ed75313a220c75e6be2c4e9ab3783e448ee1d618bd16ed22c8e19309406aa61a0d56019f2d571400a790060a5b25416800a0976 [...]
+ID = 34000b01de7f4e4bb1b7034962bf0ddc,
+AD = d6d0fb20b4d983244223691256854216,
+Y = 42f11330fc0b18b7d0789de908320577da870001607ea333315923bd0689e44e1f684fcb01cd58ba95b3c568df33845a7be7d501f1349f5a2bcf7ec27c6cdcce71fabb2db515b7fd9a6aaa4d348625b3f831f266d9330b5cbe14e163a557fca5b4254a9bc0b1bb31c26fe9cf9a19073ffeb4f8b719d4eb560ecb591ddce232e0ed5bafd64bd2e495bf84672387e89da6a860670894a27bb769a0724bd052ba4ac515d65c66b6c4458a509461b488b6558806b2735778226b3ecb43ae2eabde294b7c38b9526a3d4ed4f94c79c16ad30049127896b0f035fae5b2c3343dbb7a9287c82a3292d00544df63c521eca5bfb1d48bd033 [...]
+
+TEST = 9,
+N = a9d89f0efd30cd1d39637d3e293ad875db655e285e35c74fcfaa8003eeb3b9c9836fcc52a752172aa7621b8bf745e6bcc430102201ba9e30253ab14cc47181c2f24b7f96946e1035bd8fcceba57c9c7833fe08621ead85f7b89be769b3c1c8c7ae9ea4b6591ac811a77a0e4abcc31278b069bb7c40972988a685319971e643560604cd04e298b2a38b64b79b7eab3dc15a040dd0cc2b4c07c35fdb005a71efbae5e22b99663262626654d612a1d7a16221b0a9fbf95367d91080bf068b09708f236bd85712fbb06f17767e7ef61050738fcc6a78907ec24d57040a74601d65359ac8068852209eb8408765687fad0ba095c63bea [...]
+ID = 164af3722b02922becc7713cdba4509e,
+AD = ea29ae0678801ceb22f3191bc17c4793,
+Y = 96ff469d8173decaa50edff540c60bb9e35d9ff9b35965826df6ab3906ca72a8efe856028754fb7cb10ff0e15069b76f40c9cb054bd715f93529d8cb9f9c3415b8a99f1b53677c20066cac381e549e9519739cee3f83cb06337f4404f15a0ad61cbe45caeb096b83bf56236e437a770a1624862ccdc5eba46fe904d1ef4f94aff098c9edf3efb55e8ba2132f683ab7a711f360c74858288f4ae8720130d4dee2c7f45dd55e42745f314b2c208c9eb26a219e530f95a83047e84870bb9959cceafaa557a9380a0c8d82de41e4ac0484c9adc020e6289d7c0662de9befbd8f399ecdd1107177ee466e1ba122b9442f0ae8953e80ed [...]
+