Merge pull request #4 from apache/add-phase5-api

Add phase5 api
diff --git a/benchmark/bench_phase5.c b/benchmark/bench_phase5.c
new file mode 100644
index 0000000..c22655e
--- /dev/null
+++ b/benchmark/bench_phase5.c
@@ -0,0 +1,197 @@
+/*
+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 Schnorr's Proof.
+ */
+
+#include "bench.h"
+#include "amcl/ecdh_SECP256K1.h"
+#include "amcl/mpc.h"
+
+#define MIN_TIME    5.0
+#define MIN_ITERS   10
+
+char *M_hex  = "4b7df9714ecf795cfd698129a6f5250cfb64b739ad163da2da93c728c3bd19be";
+char *PK_hex = "022008f40a4f5bc74ac3cbd41986e61e4229afae6658d51845978f18d33fe8318c";
+char *S_hex = "90c2d9dba55ef93dbfb234d04a2bea475f7067787a57556736c876eced465154";
+char *R_hex  = "028ae19ff44d023c774d6526a22bdb47ccfa5e22a91f9994a485660e9f2363da32";
+char *RX_hex = "8ae19ff44d023c774d6526a22bdb47ccfa5e22a91f9994a485660e9f2363da32";
+
+// Commitment random values
+char *RHO_hex = "803ccd21cddad626e15f21b1ad787949e9beef08e6e68a9e00df59dec16ed290";
+char *PHI_hex = "fab4ce512dff74bd9c71c89a14de5b877af45dca0329ee3fcb72611c0784fef3";
+
+// Simulated second player commitment
+char *V2_hex = "03a57c31470773c6468bce4a66cf73d07bede464782b211c9950bd233d66bb436a";
+char *A2_hex = "03ce088cbd6dfc8975c9e618252c8f7ba935bb9938d33eb42e8e64ba71e229af53";
+
+// Simulated second player proof
+char *U2_hex = "0263f7eed14bfe58bee053e4766d36e8befeb4a509c062c12a77dc9225fff9bac6";
+char *T2_hex = "03e1471efad959c8dfe58e8e29d255a9d5ebece0f4fd6d2c30557b54e865ec98e0";
+
+int main()
+{
+    int rc;
+
+    int iterations;
+    clock_t start;
+    double elapsed;
+
+    char m[SHA256];
+    octet M = {0, sizeof(m), m};
+
+    char s[EGS_SECP256K1];
+    octet S = {0, sizeof(s), s};
+
+    char rx[EGS_SECP256K1];
+    octet RX = {0, sizeof(rx), rx};
+
+    char pk[EFS_SECP256K1 + 1];
+    octet PK = {0, sizeof(pk), pk};
+
+    char r[EFS_SECP256K1 + 1];
+    octet R = {0, sizeof(r), r};
+
+    char rho[EGS_SECP256K1];
+    octet RHO = {0, sizeof(rho), rho};
+
+    char phi[EGS_SECP256K1];
+    octet PHI = {0, sizeof(phi), phi};
+
+    char v1[EFS_SECP256K1 + 1];
+    octet V1 = {0, sizeof(v1), v1};
+
+    char v2[EFS_SECP256K1 + 1];
+    octet V2 = {0, sizeof(v2), v2};
+
+    octet *V[2] = {&V1, &V2};
+
+    char a1[EFS_SECP256K1 + 1];
+    octet A1 = {0, sizeof(a1), a1};
+
+    char a2[EFS_SECP256K1 + 1];
+    octet A2 = {0, sizeof(a2), a2};
+
+    octet *A[2] = {&A1, &A2};
+
+    char u1[EFS_SECP256K1 + 1];
+    octet U1 = {0, sizeof(u1), u1};
+
+    char u2[EFS_SECP256K1 + 1];
+    octet U2 = {0, sizeof(u2), u2};
+
+    octet *U[2] = {&U1, &U2};
+
+    char t1[EFS_SECP256K1 + 1];
+    octet T1 = {0, sizeof(t1), t1};
+
+    char t2[EFS_SECP256K1 + 1];
+    octet T2 = {0, sizeof(t2), t2};
+
+    octet *T[2] = {&T1, &T2};
+
+    // Deterministic RNG for testing
+    char seed[32] = {0};
+    csprng RNG;
+    RAND_seed(&RNG, 32, seed);
+
+    // Load input
+    OCT_fromHex(&M,  M_hex);
+    OCT_fromHex(&PK, PK_hex);
+    OCT_fromHex(&S, S_hex);
+    OCT_fromHex(&R,  R_hex);
+    OCT_fromHex(&RX, RX_hex);
+
+    OCT_fromHex(&RHO, RHO_hex);
+    OCT_fromHex(&PHI, PHI_hex);
+
+    OCT_fromHex(&V2, V2_hex);
+    OCT_fromHex(&A2, A2_hex);
+
+    OCT_fromHex(&U2, U2_hex);
+    OCT_fromHex(&T2, T2_hex);
+
+    print_system_info();
+
+    printf("Timing info\n");
+    printf("===========\n");
+
+    iterations = 0;
+    start = clock();
+    do
+    {
+        rc = MPC_PHASE5_commit(NULL, &R, &S, &PHI, &RHO, V[0], A[0]);
+        iterations++;
+        elapsed = (clock() - start) / (double)CLOCKS_PER_SEC;
+    }
+    while (elapsed < MIN_TIME || iterations < MIN_ITERS);
+
+    if (rc != MPC_OK)
+    {
+        printf("FAILURE MPC_PHASE5_commit: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    elapsed = MILLISECOND * elapsed / iterations;
+    printf("\tMPC_PHASE5_commit\t\t%8d iterations\t", iterations);
+    printf("%8.2lf ms per iteration\n", elapsed);
+
+    iterations = 0;
+    start = clock();
+    do
+    {
+        rc = MPC_PHASE5_prove(&PHI, &RHO, V, A, &PK, &M, &RX, U[0], T[0]);
+        iterations++;
+        elapsed = (clock() - start) / (double)CLOCKS_PER_SEC;
+    }
+    while (elapsed < MIN_TIME || iterations < MIN_ITERS);
+
+    if (rc != MPC_OK)
+    {
+        printf("FAILURE MPC_PHASE5_prove: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    elapsed = MILLISECOND * elapsed / iterations;
+    printf("\tMPC_PHASE5_prove\t\t%8d iterations\t", iterations);
+    printf("%8.2lf ms per iteration\n", elapsed);
+
+    iterations = 0;
+    start = clock();
+    do
+    {
+        rc = MPC_PHASE5_verify(U, T);
+        iterations++;
+        elapsed = (clock() - start) / (double)CLOCKS_PER_SEC;
+    }
+    while (elapsed < MIN_TIME || iterations < MIN_ITERS);
+
+    if (rc != MPC_OK)
+    {
+        printf("FAILURE MPC_PHASE5_verify: %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    elapsed = MILLISECOND * elapsed / iterations;
+    printf("\tMPC_PHASE5_verify\t\t%8d iterations\t", iterations);
+    printf("%8.2lf ms per iteration\n", elapsed);
+
+    exit(EXIT_SUCCESS);
+}
diff --git a/examples/example_phase5.c b/examples/example_phase5.c
new file mode 100644
index 0000000..33f4039
--- /dev/null
+++ b/examples/example_phase5.c
@@ -0,0 +1,208 @@
+/*
+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.
+*/
+
+// MPC Phase 5 example
+
+#include <amcl/ecdh_SECP256K1.h>
+#include <amcl/mpc.h>
+
+char *M_hex  = "4b7df9714ecf795cfd698129a6f5250cfb64b739ad163da2da93c728c3bd19be";
+char *PK_hex = "022008f40a4f5bc74ac3cbd41986e61e4229afae6658d51845978f18d33fe8318c";
+char *S1_hex = "90c2d9dba55ef93dbfb234d04a2bea475f7067787a57556736c876eced465154";
+char *S2_hex = "8002233d6018c7e1497b42828e517364f0b5b79e9edb8a7d130fa21e76270ee2";
+char *R_hex  = "028ae19ff44d023c774d6526a22bdb47ccfa5e22a91f9994a485660e9f2363da32";
+char *RX_hex = "8ae19ff44d023c774d6526a22bdb47ccfa5e22a91f9994a485660e9f2363da32";
+
+int main()
+{
+    int rc;
+
+    char m[SHA256];
+    octet M = {0, sizeof(m), m};
+
+    char s1[EGS_SECP256K1];
+    octet S1 = {0, sizeof(s1), s1};
+
+    char s2[EGS_SECP256K1];
+    octet S2 = {0, sizeof(s2), s2};
+
+    char rx[EGS_SECP256K1];
+    octet RX = {0, sizeof(rx), rx};
+
+    char pk[EFS_SECP256K1 + 1];
+    octet PK = {0, sizeof(pk), pk};
+
+    char r[EFS_SECP256K1 + 1];
+    octet R = {0, sizeof(r), r};
+
+    char rho1[EGS_SECP256K1];
+    octet RHO1 = {0, sizeof(rho1), rho1};
+
+    char phi1[EGS_SECP256K1];
+    octet PHI1 = {0, sizeof(phi1), phi1};
+
+    char rho2[EGS_SECP256K1];
+    octet RHO2 = {0, sizeof(rho2), rho2};
+
+    char phi2[EGS_SECP256K1];
+    octet PHI2 = {0, sizeof(phi2), phi2};
+
+    char v1[EFS_SECP256K1 + 1];
+    octet V1 = {0, sizeof(v1), v1};
+
+    char v2[EFS_SECP256K1 + 1];
+    octet V2 = {0, sizeof(v2), v2};
+
+    octet *V[2] = {&V1, &V2};
+
+    char a1[EFS_SECP256K1 + 1];
+    octet A1 = {0, sizeof(a1), a1};
+
+    char a2[EFS_SECP256K1 + 1];
+    octet A2 = {0, sizeof(a2), a2};
+
+    octet *A[2] = {&A1, &A2};
+
+    char u1[EFS_SECP256K1 + 1];
+    octet U1 = {0, sizeof(u1), u1};
+
+    char u2[EFS_SECP256K1 + 1];
+    octet U2 = {0, sizeof(u2), u2};
+
+    octet *U[2] = {&U1, &U2};
+
+    char t1[EFS_SECP256K1 + 1];
+    octet T1 = {0, sizeof(t1), t1};
+
+    char t2[EFS_SECP256K1 + 1];
+    octet T2 = {0, sizeof(t2), t2};
+
+    octet *T[2] = {&T1, &T2};
+
+    // Deterministic RNG for testing
+    char seed[32] = {0};
+    csprng RNG;
+    RAND_seed(&RNG, 32, seed);
+
+    // Load input
+    OCT_fromHex(&M,  M_hex);
+    OCT_fromHex(&PK, PK_hex);
+    OCT_fromHex(&S1, S1_hex);
+    OCT_fromHex(&S2, S2_hex);
+    OCT_fromHex(&R,  R_hex);
+    OCT_fromHex(&RX, RX_hex);
+
+    printf("MPC Phase 5 example\n");
+    printf("\nCommon parameters:\n");
+    printf("\tPK = ");
+    OCT_output(&PK);
+    printf("\tR  = ");
+    OCT_output(&R);
+    printf("\tRX = ");
+    OCT_output(&RX);
+    printf("\tM  = ");
+    OCT_output(&M);
+
+    printf("\n[Alice] Signature share\n\tS1 = ");
+    OCT_output(&S1);
+    printf("\n[Bob]   Signature share\n\tS2 = ");
+    OCT_output(&S2);
+
+
+    // Alice - generate commitments and broadcast
+    printf("\n[Alice] Generate commitment\n");
+
+    rc = MPC_PHASE5_commit(&RNG, &R, &S1, &PHI1, &RHO1, V[0], A[0]);
+    if (rc != MPC_OK)
+    {
+        printf("FAILURE MPC_PHASE5_commit Alice. RC %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    printf("\tPHI = ");
+    OCT_output(&PHI1);
+    printf("\tRHO = ");
+    OCT_output(&RHO1);
+    printf("\tV = ");
+    OCT_output(&V1);
+    printf("\tA = ");
+    OCT_output(&A1);
+
+    // Bob - generate commitments and broadcast
+    printf("\n[Bob]   Generate commitment\n");
+
+    rc = MPC_PHASE5_commit(&RNG, &R, &S2, &PHI2, &RHO2, V[1], A[1]);
+    if (rc != MPC_OK)
+    {
+        printf("FAILURE MPC_PHASE5_commit Bob. RC %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    printf("\tPHI = ");
+    OCT_output(&PHI2);
+    printf("\tRHO = ");
+    OCT_output(&RHO2);
+    printf("\tV = ");
+    OCT_output(&V2);
+    printf("\tA = ");
+    OCT_output(&A2);
+
+    // Alice - generate proof for commitments and broadcast
+    printf("\n[Alice] Generate proof for commitments\n");
+
+    rc = MPC_PHASE5_prove(&PHI1, &RHO1, V, A, &PK, &M, &RX, U[0], T[0]);
+    if (rc != MPC_OK)
+    {
+        printf("FAILURE MPC_PHASE5_prove Alice. RC %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    printf("\tU = ");
+    OCT_output(&U1);
+    printf("\tT = ");
+    OCT_output(&T1);
+
+    // Bob - generate proof for commitments and broadcast
+    printf("\n[Bob]   Generate proof for commitments\n");
+
+    rc = MPC_PHASE5_prove(&PHI2, &RHO2, V, A, &PK, &M, &RX, U[1], T[1]);
+    if (rc != MPC_OK)
+    {
+        printf("FAILURE MPC_PHASE5_prove Bob. RC %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    printf("\tU = ");
+    OCT_output(&U2);
+    printf("\tT = ");
+    OCT_output(&T2);
+
+    // Each player verifies if the total of the proof material is valid
+    printf("\n[Both]  Verification\n");
+
+    rc = MPC_PHASE5_verify(U, T);
+    if (rc == MPC_OK)
+    {
+        printf("\tSuccess!\n");
+    }
+    else
+    {
+        printf("\tFailure!\n");
+    }
+}
diff --git a/include/amcl/mpc.h b/include/amcl/mpc.h
index e23e6a8..8818ac7 100644
--- a/include/amcl/mpc.h
+++ b/include/amcl/mpc.h
@@ -33,6 +33,10 @@
 extern "C" {
 #endif
 
+#define MPC_OK          0    /**< Execution Successful */
+#define MPC_FAIL        71   /**< Failure */
+#define MPC_INVALID_ECP 72   /**< Input is not a valid point on the curve */
+
 /** \brief ECDSA Sign message
  *
  *  Generate the ECDSA signature on message, M, with outputs (R,S)
@@ -156,6 +160,73 @@
  */
 int MPC_SUM_PK(octet *PK1, octet *PK2, octet *PK);
 
+/* MPC Phase 5 API */
+
+/** \brief Generate Commitment for the MPC Phase 5
+ *
+ *  Calculate player Commitment (A, V) for MPC Phase 5
+ *
+ *  <ol>
+ *  <li> \f$ \phi \in_R [0, \ldots, q] \f$
+ *  <li> \f$ \rho \in_R [0, \ldots, q] \f$
+ *  <li> \f$ V = \phi.G + s.R \f$
+ *  <li> \f$ A = \rho.G \f$
+ *  </ol>
+ *
+ *  @param RNG                csprng for random values generation
+ *  @param R                  Reconciled R for the signature
+ *  @param S                  Player signature share
+ *  @param PHI                Random value for the commitment. If RNG is null this is read
+ *  @param RHO                Random value for the commitment. If RNG is null this is read
+ *  @param V                  First component of the player commitment. An ECP in compressed form
+ *  @param A                  Second component of the player commitment. An ECP in compressed form
+ *  @return                   Returns MPC_OK or an error code
+ */
+extern int MPC_PHASE5_commit(csprng *RNG, octet *R, octet *S, octet *PHI, octet *RHO, octet *V, octet *A);
+
+/** \brief Generate Proof for the MPC Phase 5
+ *
+ *  Calculate player Proof (U, T) for MPC Phase 5
+ *
+ *  <ol>
+ *  <li> \f$ m = H(M) \f$
+ *  <li> \f$ A = A1 + A2 \f$
+ *  <li> \f$ V = V1 + V2 \f$
+ *  <li> \f$ U = \rho.(V - m.G - r.PK) \f$
+ *  <li> \f$ T = \phi.A \f$
+ *  </ol>
+ *
+ *  @param PHI                Random value used in the commitment
+ *  @param RHO                Random value used in the commitment
+ *  @param V                  Array with the commitments V from both players. ECPs in compressed form
+ *  @param A                  Array with the commitments A from both players. ECPs in compressed form
+ *  @param PK                 Shared public key for MPC
+ *  @param HM                 Hash of the message being signed
+ *  @param RX                 x component of the reconciled R for the signature
+ *  @param U                  First component of the player proof. An ECP in compressed form
+ *  @param T                  Second component of the player proof. An ECP in compressed form
+ *  @return                   Returns MPC_OK or an error code
+ */
+extern int MPC_PHASE5_prove(octet *PHI, octet *RHO, octet *V[2], octet *A[2], octet *PK, octet *HM, octet *RX, octet *U, octet *T);
+
+/** \brief Verify Proof for the MPC Phase 5
+ *
+ *  Combine player Proofs and verify the consistency of the signature shares
+ *  This does NOT prove that the signature is valid. It only verifies that
+ *  all players know the secret quantities used to generate their shares.
+ *
+ *  <ol>
+ *  <li> \f$ U = U1 + U2 \f$
+ *  <li> \f$ T = T1 + T2 \f$
+ *  <li> \f$ U \stackrel{?}{=} T \f$
+ *  </ol>
+ *
+ *  @param U                  Array with the proofs U from both players. ECPs in compressed form
+ *  @param T                  Array with the proofs T from both players. ECPs in compressed form
+ *  @return                   Returns MPC_OK or an error code
+ */
+extern int MPC_PHASE5_verify(octet *U[2], octet *T[2]);
+
 /*! \brief Write Paillier public key to octets
  *
  *  @param   PUB              Paillier public key
diff --git a/model/vectors/mpc/genPHASE5.py b/model/vectors/mpc/genPHASE5.py
new file mode 100755
index 0000000..f988e4b
--- /dev/null
+++ b/model/vectors/mpc/genPHASE5.py
@@ -0,0 +1,140 @@
+#!/usr/bin/env python3
+
+"""
+    Generates a set of test vectors for the schnorr zk proof.
+
+    usage: genPHASE5.py -h
+"""
+
+import sys
+sys.path.append("../../")
+
+import json
+import argparse
+from sec256k1 import big, ecp, curve, mpc
+
+def genVector(test_no):
+    """Generate a single test vector
+
+        Use parameters to generate a single test vector
+
+        Args::
+
+            test_no: Test vector identifier
+
+        Returns::
+
+            vector: A test vector
+
+        Raises::
+
+            Exception
+    """
+
+    # Generate distributed keypair
+    x1 = big.rand(curve.r)
+    x2 = big.rand(curve.r)
+    x = (x1 + x2) % curve.r
+    PK = x * ecp.generator()
+
+    # Generate message
+    M = "TEST_MESSAGE_{}".format(test_no).encode('utf-8')
+
+    # Generate ki, sigma, r, R for signature
+    k1 = big.rand(curve.r)
+    k2 = big.rand(curve.r)
+    k = (k1 + k2) % curve.r
+    invk = big.invmodp(k, curve.r)
+
+    R = invk * ecp.generator()
+    r = R.getx() % curve.r
+
+    # Fake additive split of sigma. This is not
+    # what you would get from the MTA, but it is
+    # fine here for testing purposes
+    sigma1 = (k1 * x1 + k1 * x2) % curve.r
+    sigma2 = (k2 * x2 + k2 * x1) % curve.r
+
+    # Generate sigmature shares
+    s1 = mpc.make_signature_share(M, k1, r, sigma1)
+    s2 = mpc.make_signature_share(M, k2, r, sigma2)
+
+    # Check consistency of signature values generated
+    s = (s1 + s2) % curve.r
+    s_gt = (k * (mpc.hashit(M) + r*x)) % curve .r
+    assert s == s_gt, "inconsistent signature values generated"
+
+    # Generate test vector
+    phi1, rho1, V1, A1 = mpc.phase5_commit(s1, R)
+    phi2, rho2, V2, A2 = mpc.phase5_commit(s2, R)
+
+    Vs = [V1, V2]
+    As = [A1, A2]
+
+    U1, T1 = mpc.phase5_prove(rho1, phi1, Vs, As, PK, M, r)
+    U2, T2 = mpc.phase5_prove(rho2, phi2, Vs, As, PK, M, r)
+
+    Us = [U1, U2]
+    Ts = [T1, T2]
+
+    assert mpc.phase5_verify(Us, Ts), "inconsistent test vector"
+
+    vector = {
+        "TEST"  : test_no,
+        "M"     : hex(mpc.hashit(M))[2:].zfill(64),
+        "PK"    : PK.toBytes(True).hex(),
+        "R"     : R.toBytes(True).hex(),
+        "K"     : hex(k1)[2:].zfill(64),
+        "S"     : hex(s1)[2:].zfill(64),
+        "RX"    : hex(r)[2:].zfill(64),
+        "PHI"   : hex(phi1)[2:].zfill(64),
+        "RHO"   : hex(rho1)[2:].zfill(64),
+        "A1"    : A1.toBytes(True).hex(),
+        "A2"    : A2.toBytes(True).hex(),
+        "V1"    : V1.toBytes(True).hex(),
+        "V2"    : V2.toBytes(True).hex(),
+        "U1"    : U1.toBytes(True).hex(),
+        "U2"    : U2.toBytes(True).hex(),
+        "T1"    : T1.toBytes(True).hex(),
+        "T2"    : T2.toBytes(True).hex(),
+    }
+
+    return vector
+
+
+
+vector_fields = {
+    "commit": ["TEST", "S", "R", "PHI", "RHO", "V1", "A1"],
+    "prove": ["TEST", "PHI", "RHO", "V1", "V2", "A1", "A2", "PK", "M", "RX", "U1", "T1"],
+    "verify": ["TEST", "U1", "U2", "T1", "T2",],
+}
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser()
+
+    parser.add_argument('-t', dest='type', type=str, default='commit', choices=["commit", "prove", "verify"],
+        help='test vector type')
+    parser.add_argument('-n', dest='n', type=int, default=10,
+        help='number of test vectors to generate')
+
+    args = parser.parse_args()
+
+    vec_type = args.type
+
+    keys = vector_fields[vec_type]
+
+    vectors = []
+
+    for i in range(args.n):
+        vector = genVector(i)
+
+        vector = {k: vector[k] for k in keys}
+        vectors.append(vector)
+
+    json.dump(vectors, open("phase5_{}.json".format(vec_type), "w"), indent=2)
+
+    with open("phase5_{}.txt".format(vec_type), "w") as f:
+        for vector in vectors:
+            for field in keys:
+                f.write("{} = {},\n".format(field, vector[field]))
+            f.write("\n")
diff --git a/src/mpc.c b/src/mpc.c
index d85f53f..82216f4 100644
--- a/src/mpc.c
+++ b/src/mpc.c
@@ -347,6 +347,164 @@
     return 0;
 }
 
+int MPC_PHASE5_commit(csprng *RNG, octet *R, octet *S, octet *PHI, octet *RHO, octet *V, octet *A)
+{
+    BIG_256_56 ws;
+    BIG_256_56 phi;
+    BIG_256_56 rho;
+
+    ECP_SECP256K1 P1;
+    ECP_SECP256K1 P2;
+
+    if (!ECP_SECP256K1_fromOctet(&P1, R))
+    {
+        return MPC_INVALID_ECP;
+    }
+
+    if (RNG != NULL)
+    {
+        BIG_256_56_rcopy(ws, CURVE_Order_SECP256K1);
+        BIG_256_56_randomnum(phi, ws, RNG);
+        BIG_256_56_randomnum(rho, ws, RNG);
+
+        BIG_256_56_toBytes(PHI->val, phi);
+        BIG_256_56_toBytes(RHO->val, rho);
+        PHI->len = EGS_SECP256K1;
+        RHO->len = EGS_SECP256K1;
+    }
+    else
+    {
+        BIG_256_56_fromBytesLen(phi, PHI->val, PHI->len);
+        BIG_256_56_fromBytesLen(rho, RHO->val, RHO->len);
+    }
+
+    // Compute V = phi.G + s.R
+    BIG_256_56_fromBytesLen(ws, S->val, S->len);
+    ECP_SECP256K1_generator(&P2);
+
+    ECP_SECP256K1_mul2(&P1, &P2, ws, phi);
+
+    // Compute A = rho.G
+    ECP_SECP256K1_mul(&P2, rho);
+
+    // Output ECPs
+    ECP_SECP256K1_toOctet(V, &P1, 1);
+    ECP_SECP256K1_toOctet(A, &P2, 1);
+
+    // Clean memory
+    BIG_256_56_zero(phi);
+    BIG_256_56_zero(rho);
+    BIG_256_56_zero(ws);
+
+    return MPC_OK;
+}
+
+int MPC_PHASE5_prove(octet *PHI, octet *RHO, octet *V[2], octet *A[2], octet *PK, octet *HM, octet *RX, octet *U, octet *T)
+{
+    BIG_256_56 m;
+    BIG_256_56 r;
+    BIG_256_56 ws;
+
+    ECP_SECP256K1 V1;
+    ECP_SECP256K1 V2;
+    ECP_SECP256K1 A1;
+    ECP_SECP256K1 A2;
+    ECP_SECP256K1 K;
+
+    if (!ECP_SECP256K1_fromOctet(&A1, A[0]))
+    {
+        return MPC_INVALID_ECP;
+    }
+
+    if (!ECP_SECP256K1_fromOctet(&A2, A[1]))
+    {
+        return MPC_INVALID_ECP;
+    }
+
+    if (!ECP_SECP256K1_fromOctet(&V1, V[0]))
+    {
+        return MPC_INVALID_ECP;
+    }
+
+    if (!ECP_SECP256K1_fromOctet(&V2, V[1]))
+    {
+        return MPC_INVALID_ECP;
+    }
+
+    if (!ECP_SECP256K1_fromOctet(&K, PK))
+    {
+        return MPC_INVALID_ECP;
+    }
+
+    // Compute A = phi.(A1 + A2)
+    BIG_256_56_fromBytesLen(ws, PHI->val, PHI->len);
+    ECP_SECP256K1_add(&A1, &A2);
+    ECP_SECP256K1_mul(&A1, ws);
+
+    ECP_SECP256K1_toOctet(T, &A1, 1);
+
+    // Compute V = rho.(V1 + V2 - m.G - r.PK)
+    BIG_256_56_fromBytesLen(m,  HM->val,  HM->len);
+    BIG_256_56_fromBytesLen(r,  RX->val,  RX->len);
+    BIG_256_56_fromBytesLen(ws, RHO->val, RHO->len);
+
+    // K = - m.G - r.PK
+    ECP_SECP256K1_generator(&A1);
+    ECP_SECP256K1_neg(&A1);
+    ECP_SECP256K1_neg(&K);
+    ECP_SECP256K1_mul2(&K, &A1, r, m);
+
+    // V = rho.(V1 + V2 + K)
+    ECP_SECP256K1_add(&V1, &V2);
+    ECP_SECP256K1_add(&V1, &K);
+    ECP_SECP256K1_mul(&V1, ws);
+
+    ECP_SECP256K1_toOctet(U, &V1, 1);
+
+    // Clean memory
+    BIG_256_56_zero(ws);
+
+    return MPC_OK;
+}
+
+int MPC_PHASE5_verify(octet *U[2], octet *T[2])
+{
+    ECP_SECP256K1 U1;
+    ECP_SECP256K1 U2;
+    ECP_SECP256K1 T1;
+    ECP_SECP256K1 T2;
+
+    if (!ECP_SECP256K1_fromOctet(&U1, U[0]))
+    {
+        return MPC_INVALID_ECP;
+    }
+
+    if (!ECP_SECP256K1_fromOctet(&U2, U[1]))
+    {
+        return MPC_INVALID_ECP;
+    }
+
+    if (!ECP_SECP256K1_fromOctet(&T1, T[0]))
+    {
+        return MPC_INVALID_ECP;
+    }
+
+    if (!ECP_SECP256K1_fromOctet(&T2, T[1]))
+    {
+        return MPC_INVALID_ECP;
+    }
+
+    ECP_SECP256K1_add(&U1, &U2);
+    ECP_SECP256K1_add(&T1, &T2);
+
+    if (!ECP_SECP256K1_equals(&U1, &T1))
+    {
+        return MPC_FAIL;
+    }
+
+    return MPC_OK;
+}
+
 // Write Paillier public key to octets
 void MPC_DUMP_PAILLIER_PK(PAILLIER_public_key *PUB, octet *N, octet *G, octet *N2)
 {
diff --git a/test/smoke/test_phase5_smoke.c b/test/smoke/test_phase5_smoke.c
new file mode 100644
index 0000000..2cb81ff
--- /dev/null
+++ b/test/smoke/test_phase5_smoke.c
@@ -0,0 +1,149 @@
+/*
+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.
+*/
+
+// MPC Phase 5 smoke test
+
+#include <amcl/ecdh_SECP256K1.h>
+#include <amcl/mpc.h>
+
+char *M_hex  = "4b7df9714ecf795cfd698129a6f5250cfb64b739ad163da2da93c728c3bd19be";
+char *PK_hex = "022008f40a4f5bc74ac3cbd41986e61e4229afae6658d51845978f18d33fe8318c";
+char *S1_hex = "90c2d9dba55ef93dbfb234d04a2bea475f7067787a57556736c876eced465154";
+char *S2_hex = "8002233d6018c7e1497b42828e517364f0b5b79e9edb8a7d130fa21e76270ee2";
+char *R_hex  = "028ae19ff44d023c774d6526a22bdb47ccfa5e22a91f9994a485660e9f2363da32";
+char *RX_hex = "8ae19ff44d023c774d6526a22bdb47ccfa5e22a91f9994a485660e9f2363da32";
+
+int main()
+{
+    int rc;
+
+    char m[SHA256];
+    octet M = {0, sizeof(m), m};
+
+    char s1[EGS_SECP256K1];
+    octet S1 = {0, sizeof(s1), s1};
+
+    char s2[EGS_SECP256K1];
+    octet S2 = {0, sizeof(s2), s2};
+
+    char rx[EGS_SECP256K1];
+    octet RX = {0, sizeof(rx), rx};
+
+    char pk[EFS_SECP256K1 + 1];
+    octet PK = {0, sizeof(pk), pk};
+
+    char r[EFS_SECP256K1 + 1];
+    octet R = {0, sizeof(r), r};
+
+    char rho1[EGS_SECP256K1];
+    octet RHO1 = {0, sizeof(rho1), rho1};
+
+    char phi1[EGS_SECP256K1];
+    octet PHI1 = {0, sizeof(phi1), phi1};
+
+    char rho2[EGS_SECP256K1];
+    octet RHO2 = {0, sizeof(rho2), rho2};
+
+    char phi2[EGS_SECP256K1];
+    octet PHI2 = {0, sizeof(phi2), phi2};
+
+    char v1[EFS_SECP256K1 + 1];
+    octet V1 = {0, sizeof(v1), v1};
+
+    char v2[EFS_SECP256K1 + 1];
+    octet V2 = {0, sizeof(v2), v2};
+
+    octet *V[2] = {&V1, &V2};
+
+    char a1[EFS_SECP256K1 + 1];
+    octet A1 = {0, sizeof(a1), a1};
+
+    char a2[EFS_SECP256K1 + 1];
+    octet A2 = {0, sizeof(a2), a2};
+
+    octet *A[2] = {&A1, &A2};
+
+    char u1[EFS_SECP256K1 + 1];
+    octet U1 = {0, sizeof(u1), u1};
+
+    char u2[EFS_SECP256K1 + 1];
+    octet U2 = {0, sizeof(u2), u2};
+
+    octet *U[2] = {&U1, &U2};
+
+    char t1[EFS_SECP256K1 + 1];
+    octet T1 = {0, sizeof(t1), t1};
+
+    char t2[EFS_SECP256K1 + 1];
+    octet T2 = {0, sizeof(t2), t2};
+
+    octet *T[2] = {&T1, &T2};
+
+    // Deterministic RNG for testing
+    char seed[32] = {0};
+    csprng RNG;
+    RAND_seed(&RNG, 32, seed);
+
+    // Load input
+    OCT_fromHex(&M,  M_hex);
+    OCT_fromHex(&PK, PK_hex);
+    OCT_fromHex(&S1, S1_hex);
+    OCT_fromHex(&S2, S2_hex);
+    OCT_fromHex(&R,  R_hex);
+    OCT_fromHex(&RX, RX_hex);
+
+    // Run test
+    rc = MPC_PHASE5_commit(&RNG, &R, &S1, &PHI1, &RHO1, V[0], A[0]);
+    if (rc != MPC_OK)
+    {
+        printf("FAILURE MPC_PHASE5_commit player 1. RC %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    rc = MPC_PHASE5_commit(&RNG, &R, &S2, &PHI2, &RHO2, V[1], A[1]);
+    if (rc != MPC_OK)
+    {
+        printf("FAILURE MPC_PHASE5_commit player 2. RC %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    rc = MPC_PHASE5_prove(&PHI1, &RHO1, V, A, &PK, &M, &RX, U[0], T[0]);
+    if (rc != MPC_OK)
+    {
+        printf("FAILURE MPC_PHASE5_prove player 1. RC %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    rc = MPC_PHASE5_prove(&PHI2, &RHO2, V, A, &PK, &M, &RX, U[1], T[1]);
+    if (rc != MPC_OK)
+    {
+        printf("FAILURE MPC_PHASE5_prove player 2. RC %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    rc = MPC_PHASE5_verify(U, T);
+    if (rc != MPC_OK)
+    {
+        printf("FAILURE MPC_PHASE5_verify. RC %d\n", rc);
+        exit(EXIT_FAILURE);
+    }
+
+    printf("SUCCESS\n");
+    exit(EXIT_SUCCESS);
+}
diff --git a/test/test.c b/test/test.c
index e18f6e9..b739b04 100644
--- a/test/test.c
+++ b/test/test.c
@@ -169,6 +169,14 @@
 #endif
 
         printf("FAILURE %s. Test %d\n", name, testNo);
+
+#ifdef DEBUG
+        printf("X = ");
+        OCT_output(X);
+        printf("Y = ");
+        OCT_output(Y);
+#endif
+
         exit(EXIT_FAILURE);
     }
 }
diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt
index a627306..4fa3bea 100644
--- a/test/unit/CMakeLists.txt
+++ b/test/unit/CMakeLists.txt
@@ -40,9 +40,12 @@
 endfunction()
 
 # MPC tests
-amcl_test(test_mta test_mta.c amcl_mpc "SUCCESS" "mpc/MTA.txt")
-amcl_test(test_r   test_r.c   amcl_mpc "SUCCESS" "mpc/R.txt")
-amcl_test(test_s   test_s.c   amcl_mpc "SUCCESS" "mpc/S.txt")
+amcl_test(test_mta           test_mta.c           amcl_mpc "SUCCESS" "mpc/MTA.txt")
+amcl_test(test_r             test_r.c             amcl_mpc "SUCCESS" "mpc/R.txt")
+amcl_test(test_s             test_s.c             amcl_mpc "SUCCESS" "mpc/S.txt")
+amcl_test(test_phase5_commit test_phase5_commit.c amcl_mpc "SUCCESS" "mpc/phase5_commit.txt")
+amcl_test(test_phase5_prove  test_phase5_prove.c  amcl_mpc "SUCCESS" "mpc/phase5_prove.txt")
+amcl_test(test_phase5_verify test_phase5_verify.c amcl_mpc "SUCCESS" "mpc/phase5_verify.txt")
 
 # NM Commitment tests
 amcl_test(test_nm_commit test_nm_commit.c amcl_mpc "SUCCESS" "commitments/nm_commit.txt")
diff --git a/test/unit/test_phase5_commit.c b/test/unit/test_phase5_commit.c
new file mode 100644
index 0000000..69708aa
--- /dev/null
+++ b/test/unit/test_phase5_commit.c
@@ -0,0 +1,132 @@
+/*
+    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/mpc.h"
+#include "amcl/ecdh_SECP256K1.h"
+
+/* MPC Phase 5 commitment unit test */
+
+#define LINE_LEN 256
+
+int main(int argc, char **argv)
+{
+    if (argc != 2)
+    {
+        printf("usage: ./test_phase5_commit [path to test vector file]\n");
+        exit(EXIT_FAILURE);
+    }
+
+    int rc;
+    int test_run = 0;
+
+    char err_msg[128];
+
+    FILE *fp;
+    char line[LINE_LEN] = {0};
+
+    const char *TESTline = "TEST = ";
+    int testNo = 0;
+
+    char s[EGS_SECP256K1];
+    octet S = {0, sizeof(s), s};
+    const char *Sline = "S = ";
+
+    char r[EFS_SECP256K1 + 1];
+    octet R = {0, sizeof(r), r};
+    const char *Rline = "R = ";
+
+    char phi[EGS_SECP256K1];
+    octet PHI = {0, sizeof(phi), phi};
+    const char *PHIline = "PHI = ";
+
+    char rho[EGS_SECP256K1];
+    octet RHO = {0, sizeof(rho), rho};
+    const char *RHOline = "RHO = ";
+
+    char v_golden[EFS_SECP256K1 + 1];
+    octet V_GOLDEN = {0, sizeof(v_golden), v_golden};
+    const char *Vline = "V1 = ";
+
+    char a_golden[EFS_SECP256K1 + 1];
+    octet A_GOLDEN = {0, sizeof(a_golden), a_golden};
+    const char *Aline = "A1 = ";
+
+    char v[EFS_SECP256K1 + 1];
+    octet V = {0, sizeof(v), v};
+
+    char a[EFS_SECP256K1 + 1];
+    octet A = {0, sizeof(a), a};
+
+    // Line terminating a test vector
+    const char *last_line = Aline;
+
+    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 input
+        scan_OCTET(fp, &S,   line, Sline);
+        scan_OCTET(fp, &R,   line, Rline);
+        scan_OCTET(fp, &PHI, line, PHIline);
+        scan_OCTET(fp, &RHO, line, RHOline);
+
+        // Read ground truth
+        scan_OCTET(fp, &V_GOLDEN, line, Vline);
+        scan_OCTET(fp, &A_GOLDEN, line, Aline);
+
+        if (!strncmp(line, last_line, strlen(last_line)))
+        {
+            rc = MPC_PHASE5_commit(NULL, &R, &S, &PHI, &RHO, &V, &A);
+            sprintf(err_msg, "FAILURE MPC_PHASE5_commit. RC %d", rc);
+            assert_tv(fp, testNo, err_msg, rc == MPC_OK);
+
+            compare_OCT(fp, testNo, "FAILURE MPC_PHASE5_commit V", &V, &V_GOLDEN);
+            compare_OCT(fp, testNo, "FAILURE MPC_PHASE5_commit A", &A, &A_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 */
+
+    rc = MPC_PHASE5_commit(NULL, &S, &S, &PHI, &RHO, &V, &A);
+    sprintf(err_msg, "FAILURE MPC_PHASE5_commit invalid R. RC %d", rc);
+    assert_tv(fp, testNo, err_msg, rc == MPC_INVALID_ECP);
+
+    printf("SUCCESS\n");
+    exit(EXIT_SUCCESS);
+}
diff --git a/test/unit/test_phase5_prove.c b/test/unit/test_phase5_prove.c
new file mode 100644
index 0000000..7661e28
--- /dev/null
+++ b/test/unit/test_phase5_prove.c
@@ -0,0 +1,200 @@
+/*
+    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/mpc.h"
+#include "amcl/ecdh_SECP256K1.h"
+
+/* MPC Phase 5 proof unit test */
+
+#define LINE_LEN 256
+
+int main(int argc, char **argv)
+{
+    if (argc != 2)
+    {
+        printf("usage: ./test_phase5_prove [path to test vector file]\n");
+        exit(EXIT_FAILURE);
+    }
+
+    int rc;
+    int test_run = 0;
+
+    char err_msg[128];
+
+    FILE *fp;
+    char line[LINE_LEN] = {0};
+
+    const char *TESTline = "TEST = ";
+    int testNo = 0;
+
+    char phi[EGS_SECP256K1];
+    octet PHI = {0, sizeof(phi), phi};
+    const char *PHIline = "PHI = ";
+
+    char rho[EGS_SECP256K1];
+    octet RHO = {0, sizeof(rho), rho};
+    const char *RHOline = "RHO = ";
+
+    char pk[EFS_SECP256K1 + 1];
+    octet PK = {0, sizeof(pk), pk};
+    const char *PKline = "PK = ";
+
+    char m[SHA256];
+    octet M = {0, sizeof(m), m};
+    const char *Mline = "M = ";
+
+    char rx[EFS_SECP256K1 + 1];
+    octet RX = {0, sizeof(rx), rx};
+    const char *RXline = "RX = ";
+
+    char v1[EFS_SECP256K1 + 1];
+    octet V1 = {0, sizeof(v1), v1};
+    const char *V1line = "V1 = ";
+
+    char v2[EFS_SECP256K1 + 1];
+    octet V2 = {0, sizeof(v2), v2};
+    const char *V2line = "V2 = ";
+
+    octet *V[2] = {&V1, &V2};
+
+    char a1[EFS_SECP256K1 + 1];
+    octet A1 = {0, sizeof(a1), a1};
+    const char *A1line = "A1 = ";
+
+    char a2[EFS_SECP256K1 + 1];
+    octet A2 = {0, sizeof(a2), a2};
+    const char *A2line = "A2 = ";
+
+    octet *A[2] = {&A1, &A2};
+
+    char u_golden[EFS_SECP256K1 + 1];
+    octet U_GOLDEN = {0, sizeof(u_golden), u_golden};
+    const char *Uline = "U1 = ";
+
+    char t_golden[EFS_SECP256K1 + 1];
+    octet T_GOLDEN = {0, sizeof(t_golden), t_golden};
+    const char *Tline = "T1 = ";
+
+    char u[EFS_SECP256K1 + 1];
+    octet U = {0, sizeof(u), u};
+
+    char t[EFS_SECP256K1 + 1];
+    octet T = {0, sizeof(t), t};
+
+    // Line terminating a test vector
+    const char *last_line = Tline;
+
+    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 input
+        scan_OCTET(fp, &PHI, line, PHIline);
+        scan_OCTET(fp, &RHO, line, RHOline);
+        scan_OCTET(fp, &V1,  line, V1line);
+        scan_OCTET(fp, &V2,  line, V2line);
+        scan_OCTET(fp, &A1,  line, A1line);
+        scan_OCTET(fp, &A2,  line, A2line);
+        scan_OCTET(fp, &PK,  line, PKline);
+        scan_OCTET(fp, &RX,  line, RXline);
+
+        // Read
+        scan_OCTET(fp, &M,   line, Mline);
+
+        // Read ground truth
+        scan_OCTET(fp, &T_GOLDEN, line, Tline);
+        scan_OCTET(fp, &U_GOLDEN, line, Uline);
+
+        if (!strncmp(line, last_line, strlen(last_line)))
+        {
+            rc = MPC_PHASE5_prove(&PHI, &RHO, V, A, &PK, &M, &RX, &U, &T);
+            sprintf(err_msg, "FAILURE MPC_PHASE5_prove. RC %d", rc);
+            assert_tv(fp, testNo, err_msg, rc == MPC_OK);
+
+            compare_OCT(fp, testNo, "FAILURE MPC_PHASE5_prove U", &U, &U_GOLDEN);
+            compare_OCT(fp, testNo, "FAILURE MPC_PHASE5_prove T", &T, &T_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 V[0]
+    V[0] = &PHI;
+
+    rc = MPC_PHASE5_prove(&PHI, &RHO, V, A, &PK, &M, &RX, &U_GOLDEN, &T_GOLDEN);
+    sprintf(err_msg, "FAILURE MPC_PHASE5_prove invalid V1. RC %d", rc);
+    assert_tv(fp, testNo, err_msg, rc == MPC_INVALID_ECP);
+
+    V[0] = &V1;
+
+    // Invalid V[1]
+    V[1] = &PHI;
+
+    rc = MPC_PHASE5_prove(&PHI, &RHO, V, A, &PK, &M, &RX, &U_GOLDEN, &T_GOLDEN);
+    sprintf(err_msg, "FAILURE MPC_PHASE5_prove invalid V2. RC %d", rc);
+    assert_tv(fp, testNo, err_msg, rc == MPC_INVALID_ECP);
+
+    V[1] = &V2;
+
+    // Invalid A[0]
+    A[0] = &PHI;
+
+    rc = MPC_PHASE5_prove(&PHI, &RHO, V, A, &PK, &M, &RX, &U_GOLDEN, &T_GOLDEN);
+    sprintf(err_msg, "FAILURE MPC_PHASE5_prove invalid A1. RC %d", rc);
+    assert_tv(fp, testNo, err_msg, rc == MPC_INVALID_ECP);
+
+    A[0] = &A1;
+
+    // Invalid A[1]
+    A[1] = &PHI;
+
+    rc = MPC_PHASE5_prove(&PHI, &RHO, V, A, &PK, &M, &RX, &U_GOLDEN, &T_GOLDEN);
+    sprintf(err_msg, "FAILURE MPC_PHASE5_prove invalid A2. RC %d", rc);
+    assert_tv(fp, testNo, err_msg, rc == MPC_INVALID_ECP);
+
+    A[1] = &A2;
+
+    // Invalid PK
+    rc = MPC_PHASE5_prove(&PHI, &RHO, V, A, &PHI, &M, &RX, &U_GOLDEN, &T_GOLDEN);
+    sprintf(err_msg, "FAILURE MPC_PHASE5_prove invalid PK. RC %d", rc);
+    assert_tv(fp, testNo, err_msg, rc == MPC_INVALID_ECP);
+
+    printf("SUCCESS\n");
+    exit(EXIT_SUCCESS);
+}
diff --git a/test/unit/test_phase5_verify.c b/test/unit/test_phase5_verify.c
new file mode 100644
index 0000000..19a4d68
--- /dev/null
+++ b/test/unit/test_phase5_verify.c
@@ -0,0 +1,160 @@
+/*
+    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/mpc.h"
+#include "amcl/ecdh_SECP256K1.h"
+
+/* MPC Phase 5 verification unit test */
+
+#define LINE_LEN 256
+
+int main(int argc, char **argv)
+{
+    if (argc != 2)
+    {
+        printf("usage: ./test_phase5_verify [path to test vector file]\n");
+        exit(EXIT_FAILURE);
+    }
+
+    int rc;
+    int test_run = 0;
+
+    char err_msg[128];
+
+    FILE *fp;
+    char line[LINE_LEN] = {0};
+
+    const char *TESTline = "TEST = ";
+    int testNo = 0;
+
+    char u1[EFS_SECP256K1 + 1];
+    octet U1 = {0, sizeof(u1), u1};
+    const char *U1line = "U1 = ";
+
+    char u2[EFS_SECP256K1 + 1];
+    octet U2 = {0, sizeof(u2), u2};
+    const char *U2line = "U2 = ";
+
+    octet *U[2] = {&U1, &U2};
+
+    char t1[EFS_SECP256K1 + 1];
+    octet T1 = {0, sizeof(t1), t1};
+    const char *T1line = "T1 = ";
+
+    char t2[EFS_SECP256K1 + 1];
+    octet T2 = {0, sizeof(t2), t2};
+    const char *T2line = "T2 = ";
+
+    octet *T[2] = {&T1, &T2};
+
+    char zero[EGS_SECP256K1];
+    octet ZERO = {0, sizeof(zero), zero};
+
+    // Line terminating a test vector
+    const char *last_line = T2line;
+
+    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 input
+        scan_OCTET(fp, &U1, line, U1line);
+        scan_OCTET(fp, &U2, line, U2line);
+        scan_OCTET(fp, &T1, line, T1line);
+        scan_OCTET(fp, &T2, line, T2line);
+
+        if (!strncmp(line, last_line, strlen(last_line)))
+        {
+            rc = MPC_PHASE5_verify(U, T);
+            sprintf(err_msg, "FAILURE MPC_PHASE5_verify. RC %d", rc);
+            assert_tv(fp, testNo, err_msg, rc == MPC_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 */
+
+    OCT_clear(&ZERO);
+    ZERO.len = ZERO.max;
+
+    // Invalid U[0]
+    U[0] = &ZERO;
+
+    rc = MPC_PHASE5_verify(U, T);
+    sprintf(err_msg, "FAILURE MPC_PHASE5_verify invalid U1. RC %d", rc);
+    assert_tv(fp, testNo, err_msg, rc == MPC_INVALID_ECP);
+
+    U[0] = &U1;
+
+    // Invalid U[1]
+    U[1] = &ZERO;
+
+    rc = MPC_PHASE5_verify(U, T);
+    sprintf(err_msg, "FAILURE MPC_PHASE5_verify invalid U2. RC %d", rc);
+    assert_tv(fp, testNo, err_msg, rc == MPC_INVALID_ECP);
+
+    U[1] = &U2;
+
+    // Invalid T[0]
+    T[0] = &ZERO;
+
+    rc = MPC_PHASE5_verify(U, T);
+    sprintf(err_msg, "FAILURE MPC_PHASE5_verify invalid T1. RC %d", rc);
+    assert_tv(fp, testNo, err_msg, rc == MPC_INVALID_ECP);
+
+    T[0] = &T1;
+
+    // Invalid T[1]
+    T[1] = &ZERO;
+
+    rc = MPC_PHASE5_verify(U, T);
+    sprintf(err_msg, "FAILURE MPC_PHASE5_verify invalid T2. RC %d", rc);
+    assert_tv(fp, testNo, err_msg, rc == MPC_INVALID_ECP);
+
+    T[1] = &T2;
+
+    // Invalid Proof
+    T[1] = T[0];
+
+    rc = MPC_PHASE5_verify(U, T);
+    sprintf(err_msg, "FAILURE MPC_PHASE5_verify invalid proof. RC %d", rc);
+    assert_tv(fp, testNo, err_msg, rc == MPC_FAIL);
+
+    printf("SUCCESS\n");
+    exit(EXIT_SUCCESS);
+}
diff --git a/testVectors/mpc/phase5_commit.json b/testVectors/mpc/phase5_commit.json
new file mode 100644
index 0000000..d4e53af
--- /dev/null
+++ b/testVectors/mpc/phase5_commit.json
@@ -0,0 +1,92 @@
+[
+  {
+    "TEST": 0,
+    "S": "e51b8e40c2ec54655e398e34f79d53038736b0fe7bc43bcb7576e1c2ea69ed0c",
+    "R": "02f666dd56143effb2ff8bd6a577bc0a737a95f6b19e155dd09f990d37b812ba72",
+    "PHI": "a119c5ec63b845317a4e333a0bbb4cb71ad41ee0b336ba896878a916c7da5c17",
+    "RHO": "ee4210e039334382e021991bfc5f459c2ff068e1b5be6f8411b75c07ddac2569",
+    "V1": "025c468de747a1108b5c58fe046cbca604767205eaa1cff74dae28fa65880cfde4",
+    "A1": "039c0085388bf852ce9755623393d96faa3995b3664ed7e156d68dfec9abf06c27"
+  },
+  {
+    "TEST": 1,
+    "S": "3194344513cf907fd8f899a99304c2fde6c6f8c7d29eb4159ba3d83020474edd",
+    "R": "02eb226fc5812bf1a51d426ca7958df8727da296438e5e4f5c717477bd4f0343de",
+    "PHI": "30966890d4f0c7cedf78aa74a7ccf68dd9afdcc7b7cfb5d960a0af1d661b48f6",
+    "RHO": "cc336a062316c18a78c501e887335c0cd9ef96164d931ec8d8fe6ce830685ef5",
+    "V1": "02c606d535292b81294d1331fd13d460f40c5f7682567b3a5ce574f4670e096f9f",
+    "A1": "029d66e1994e5bd735563514058386b5a8afc8ed83b3941a48961b1f00da406b18"
+  },
+  {
+    "TEST": 2,
+    "S": "f9dc1499de92142c078adba273e9aa9c5e54da81e4288a6ac13ee11dbde6cc7b",
+    "R": "0255e23064865c79f6a54e6208670848f8f3e3824985503b05c23e47d60e71f195",
+    "PHI": "c2f27ff77c939e55c463e25899f577464974d70c634ba0672d0f5efb2f5fa687",
+    "RHO": "c0bc20a6d6e91a64d523b8d7d3d6e4ed435d4a89654acf32784ef613c9c35bbc",
+    "V1": "03fc3fe34b51107b76629f593fcb48ab7a6c062c19e1c495df50996a43982ac4c4",
+    "A1": "034b5222a838098348bd658b863ce7e88369b6dea428f7511228e89561e1700cfd"
+  },
+  {
+    "TEST": 3,
+    "S": "78f7379bb01751c6933a568dbd8c868ca19a69519b3673910aecd43dca64902f",
+    "R": "02326c8a3c238a2982aa2d2fe644c10e274fb805fb281622373a6e9b7fc7502c12",
+    "PHI": "e4cfea43fce9c41d67b5ba62d12a3196bd5c6ec66d2352098b72f8b2434e64ce",
+    "RHO": "275e3922bb1f495b32101fe4cf591f00e9faeb882ab319719ad214767f98eb70",
+    "V1": "0272ce75ace35a4eeb416d5b2a240e2c74b542254b6a54e7364c29d9ee464c97dc",
+    "A1": "03fb1fa205064aa919b12a130eb68c7da0f93043e58cbaa77644be81feda4c5d60"
+  },
+  {
+    "TEST": 4,
+    "S": "bb0455894adaba0090823e281ca9847a22931306bb4fcdabd9c3fa205e84131e",
+    "R": "038c03cd239ef925e7f6041dbd7cc2e9692c1fcf0bc24b98897d6f908382b61888",
+    "PHI": "a59b7ad0c41b3e329415c766bb159dbf65e4cce4b5634f49af6994996d804001",
+    "RHO": "c25cce2544f8ac19ca07ca37d0a708f763c86ff7d8803fd179d9595b5978f815",
+    "V1": "02d2e39de79c01a8a420ca2c219a834e28b27765683b6b370c952a39cf56c35dcc",
+    "A1": "031b111341431dbcacf50e63f79e86b17cc96b19e01cb16fa81d3fb062f469adbb"
+  },
+  {
+    "TEST": 5,
+    "S": "5a82ba6fa60daacd7b83961baafd3ca8ed0522ed32e8f41c3ca42a929be3b180",
+    "R": "03e0318ef86d8dc50ef1bac489f555377c7d589644e12f0079735bb7afb8c556bc",
+    "PHI": "3f831fb0cbdc95e149cc3495a9e30fac14489c3f521f855f2a6a555d2befab60",
+    "RHO": "8faa2ef182458cafcaadd991b8f41ec6f4eb8f84872d8a8f553937dba4e7f1a4",
+    "V1": "033049c915878fa102950dd44e6beb08d2311ed208512a78c95f568ee2ca1386cf",
+    "A1": "026e53a32d27a3634bd7e93f70ed809fe902f227efabde0f9657c1edafa38323a5"
+  },
+  {
+    "TEST": 6,
+    "S": "f8ff36371d64a6f66eeb576b1de2eca7db0f5a9aa164ad5fd6f0cf79eb9f1d12",
+    "R": "0281a676e506b858a3c52f892436ef2bcebb6ee917a002e09c42117017b5a21744",
+    "PHI": "7b589d3b2756f6def4b02930069d64e25a814c13c801e46223908834eda9ef10",
+    "RHO": "4b5c5baae8574fcd0a46b7f1de754de5b1269752834a662d5feac4a4d7fda6c2",
+    "V1": "028a8512afffd786454b4ffcddd86f24dc34b9587e9b173ec2ddd328c5821a8ac3",
+    "A1": "020593f2dfac2af071f0ce42fc9bfa39cf57c1cf744c615abaff57c4ba2027b40d"
+  },
+  {
+    "TEST": 7,
+    "S": "839ea29f4f5627aeb5f9d3ca9902b1d346960ff3c747f3f9280632aad788b993",
+    "R": "0267559bd658b429403734bad273b113fbfcc6a600c959f48ad43cccda5e628e35",
+    "PHI": "9f19280d2ba8e63991ffbc8bbb35864c848774e9d0e88e22d25aab8cb7bf3786",
+    "RHO": "6dc19b5df395ef8f3bb3e9c079ed3d2ec5dbf776de46b4a2a37170faef987ddb",
+    "V1": "039b7396e35c9642678f296f842fb5ea4509cd70f8fcbafd473feb3cc0dd9ba059",
+    "A1": "03e765605f6785002cef2e1cade288f35417a790fe81d5dee665437d533256a1cf"
+  },
+  {
+    "TEST": 8,
+    "S": "b7b7a0b9e8a57ffcd4dc611c9d9097adf1e0793c1a2e519a7f3cfb579d84bc1c",
+    "R": "034948e1de149611af157dbb9e188b50734f0726e783c1db5d9dcf3b7159cd8313",
+    "PHI": "fcf4b149c1a1cab3ab06dbe50801a5ccbedc45aeff31e0f0760535081bfaac2d",
+    "RHO": "1039a703df08853f1b9e53fad2381f9b8a92e1c61f21c21195d7f549849b0937",
+    "V1": "0219946e7880117668c48c8f39b6457463a4774d73682dcba0cf03264ed97a72cd",
+    "A1": "02283ed21e357aa474f7b46cf59bdb275f05219ad0daa13c314c4fbf20f1f4f209"
+  },
+  {
+    "TEST": 9,
+    "S": "3e6c3213a3e62fec90b655692568a4d54e9d72eae1f1f8599a2cef0ada5eb028",
+    "R": "031623d89ae0a32372520da25fbf6c7f54fae42cb2205ed6960b00ab42511d5707",
+    "PHI": "cdd4163cfe3d8becc92b0a396d7d5a667ac54cf9354f1d55f7938b20feb43344",
+    "RHO": "f0a3a2d243cfa59065f7d1c6847cb6c317b703d46cecd198f196a40b8b73179b",
+    "V1": "03a93080b4cda427bd40844bd45ed993180216f2e4ed372172f605b5c66fe10810",
+    "A1": "02fcb444d9f100f591bbc5ba66399726205af26291215d927981aef7f4c0e2ddd6"
+  }
+]
\ No newline at end of file
diff --git a/testVectors/mpc/phase5_commit.txt b/testVectors/mpc/phase5_commit.txt
new file mode 100644
index 0000000..820e901
--- /dev/null
+++ b/testVectors/mpc/phase5_commit.txt
@@ -0,0 +1,80 @@
+TEST = 0,
+S = e51b8e40c2ec54655e398e34f79d53038736b0fe7bc43bcb7576e1c2ea69ed0c,
+R = 02f666dd56143effb2ff8bd6a577bc0a737a95f6b19e155dd09f990d37b812ba72,
+PHI = a119c5ec63b845317a4e333a0bbb4cb71ad41ee0b336ba896878a916c7da5c17,
+RHO = ee4210e039334382e021991bfc5f459c2ff068e1b5be6f8411b75c07ddac2569,
+V1 = 025c468de747a1108b5c58fe046cbca604767205eaa1cff74dae28fa65880cfde4,
+A1 = 039c0085388bf852ce9755623393d96faa3995b3664ed7e156d68dfec9abf06c27,
+
+TEST = 1,
+S = 3194344513cf907fd8f899a99304c2fde6c6f8c7d29eb4159ba3d83020474edd,
+R = 02eb226fc5812bf1a51d426ca7958df8727da296438e5e4f5c717477bd4f0343de,
+PHI = 30966890d4f0c7cedf78aa74a7ccf68dd9afdcc7b7cfb5d960a0af1d661b48f6,
+RHO = cc336a062316c18a78c501e887335c0cd9ef96164d931ec8d8fe6ce830685ef5,
+V1 = 02c606d535292b81294d1331fd13d460f40c5f7682567b3a5ce574f4670e096f9f,
+A1 = 029d66e1994e5bd735563514058386b5a8afc8ed83b3941a48961b1f00da406b18,
+
+TEST = 2,
+S = f9dc1499de92142c078adba273e9aa9c5e54da81e4288a6ac13ee11dbde6cc7b,
+R = 0255e23064865c79f6a54e6208670848f8f3e3824985503b05c23e47d60e71f195,
+PHI = c2f27ff77c939e55c463e25899f577464974d70c634ba0672d0f5efb2f5fa687,
+RHO = c0bc20a6d6e91a64d523b8d7d3d6e4ed435d4a89654acf32784ef613c9c35bbc,
+V1 = 03fc3fe34b51107b76629f593fcb48ab7a6c062c19e1c495df50996a43982ac4c4,
+A1 = 034b5222a838098348bd658b863ce7e88369b6dea428f7511228e89561e1700cfd,
+
+TEST = 3,
+S = 78f7379bb01751c6933a568dbd8c868ca19a69519b3673910aecd43dca64902f,
+R = 02326c8a3c238a2982aa2d2fe644c10e274fb805fb281622373a6e9b7fc7502c12,
+PHI = e4cfea43fce9c41d67b5ba62d12a3196bd5c6ec66d2352098b72f8b2434e64ce,
+RHO = 275e3922bb1f495b32101fe4cf591f00e9faeb882ab319719ad214767f98eb70,
+V1 = 0272ce75ace35a4eeb416d5b2a240e2c74b542254b6a54e7364c29d9ee464c97dc,
+A1 = 03fb1fa205064aa919b12a130eb68c7da0f93043e58cbaa77644be81feda4c5d60,
+
+TEST = 4,
+S = bb0455894adaba0090823e281ca9847a22931306bb4fcdabd9c3fa205e84131e,
+R = 038c03cd239ef925e7f6041dbd7cc2e9692c1fcf0bc24b98897d6f908382b61888,
+PHI = a59b7ad0c41b3e329415c766bb159dbf65e4cce4b5634f49af6994996d804001,
+RHO = c25cce2544f8ac19ca07ca37d0a708f763c86ff7d8803fd179d9595b5978f815,
+V1 = 02d2e39de79c01a8a420ca2c219a834e28b27765683b6b370c952a39cf56c35dcc,
+A1 = 031b111341431dbcacf50e63f79e86b17cc96b19e01cb16fa81d3fb062f469adbb,
+
+TEST = 5,
+S = 5a82ba6fa60daacd7b83961baafd3ca8ed0522ed32e8f41c3ca42a929be3b180,
+R = 03e0318ef86d8dc50ef1bac489f555377c7d589644e12f0079735bb7afb8c556bc,
+PHI = 3f831fb0cbdc95e149cc3495a9e30fac14489c3f521f855f2a6a555d2befab60,
+RHO = 8faa2ef182458cafcaadd991b8f41ec6f4eb8f84872d8a8f553937dba4e7f1a4,
+V1 = 033049c915878fa102950dd44e6beb08d2311ed208512a78c95f568ee2ca1386cf,
+A1 = 026e53a32d27a3634bd7e93f70ed809fe902f227efabde0f9657c1edafa38323a5,
+
+TEST = 6,
+S = f8ff36371d64a6f66eeb576b1de2eca7db0f5a9aa164ad5fd6f0cf79eb9f1d12,
+R = 0281a676e506b858a3c52f892436ef2bcebb6ee917a002e09c42117017b5a21744,
+PHI = 7b589d3b2756f6def4b02930069d64e25a814c13c801e46223908834eda9ef10,
+RHO = 4b5c5baae8574fcd0a46b7f1de754de5b1269752834a662d5feac4a4d7fda6c2,
+V1 = 028a8512afffd786454b4ffcddd86f24dc34b9587e9b173ec2ddd328c5821a8ac3,
+A1 = 020593f2dfac2af071f0ce42fc9bfa39cf57c1cf744c615abaff57c4ba2027b40d,
+
+TEST = 7,
+S = 839ea29f4f5627aeb5f9d3ca9902b1d346960ff3c747f3f9280632aad788b993,
+R = 0267559bd658b429403734bad273b113fbfcc6a600c959f48ad43cccda5e628e35,
+PHI = 9f19280d2ba8e63991ffbc8bbb35864c848774e9d0e88e22d25aab8cb7bf3786,
+RHO = 6dc19b5df395ef8f3bb3e9c079ed3d2ec5dbf776de46b4a2a37170faef987ddb,
+V1 = 039b7396e35c9642678f296f842fb5ea4509cd70f8fcbafd473feb3cc0dd9ba059,
+A1 = 03e765605f6785002cef2e1cade288f35417a790fe81d5dee665437d533256a1cf,
+
+TEST = 8,
+S = b7b7a0b9e8a57ffcd4dc611c9d9097adf1e0793c1a2e519a7f3cfb579d84bc1c,
+R = 034948e1de149611af157dbb9e188b50734f0726e783c1db5d9dcf3b7159cd8313,
+PHI = fcf4b149c1a1cab3ab06dbe50801a5ccbedc45aeff31e0f0760535081bfaac2d,
+RHO = 1039a703df08853f1b9e53fad2381f9b8a92e1c61f21c21195d7f549849b0937,
+V1 = 0219946e7880117668c48c8f39b6457463a4774d73682dcba0cf03264ed97a72cd,
+A1 = 02283ed21e357aa474f7b46cf59bdb275f05219ad0daa13c314c4fbf20f1f4f209,
+
+TEST = 9,
+S = 3e6c3213a3e62fec90b655692568a4d54e9d72eae1f1f8599a2cef0ada5eb028,
+R = 031623d89ae0a32372520da25fbf6c7f54fae42cb2205ed6960b00ab42511d5707,
+PHI = cdd4163cfe3d8becc92b0a396d7d5a667ac54cf9354f1d55f7938b20feb43344,
+RHO = f0a3a2d243cfa59065f7d1c6847cb6c317b703d46cecd198f196a40b8b73179b,
+V1 = 03a93080b4cda427bd40844bd45ed993180216f2e4ed372172f605b5c66fe10810,
+A1 = 02fcb444d9f100f591bbc5ba66399726205af26291215d927981aef7f4c0e2ddd6,
+
diff --git a/testVectors/mpc/phase5_prove.json b/testVectors/mpc/phase5_prove.json
new file mode 100644
index 0000000..b190cba
--- /dev/null
+++ b/testVectors/mpc/phase5_prove.json
@@ -0,0 +1,142 @@
+[
+  {
+    "TEST": 0,
+    "PHI": "42e9c17ded15a239981652376f587871860cea8ca80b600314dcd18f5e41f5e4",
+    "RHO": "60952570933cde980fca6d1c57ac4fa0ea72c3d7589eb06c2742b1e87925fc1f",
+    "V1": "0311241c85d737b3fdfc75f09d1168c1108b45fb98f3d2ad3e1f1dd8fec6da1cc6",
+    "V2": "02614a8d747ba485bef570099e6c1521baaedfc6eaba519f11dfc66f9c29942db0",
+    "A1": "029bcf3649d9c39e59d97670677dec4db91e7ae1cb438dac32afb9f98d66a70c2d",
+    "A2": "02f0e3aa5a7829d4d2ace5cc24d40af0e1d6409b4f948ca7c903da3858d6738915",
+    "PK": "020a8d50393669103474fd735586c6e6703ee767124ec06d8ff37e58b9b50ae357",
+    "M": "2d956cc45ebcbb5a69428c45482b11add5e4fe9ff86b9f22586a46707b51599d",
+    "RX": "7055a6caaefd7a40afaa6205ef6974cb7d948f5a33ffdea261d640eaaead27de",
+    "U1": "0310c82c83778a33410dfcb96eded135bb1217ff883fe76942d9fb6d7d29c33beb",
+    "T1": "03f0eb9a901fb930bbfd3f8531bbd43d1a238b5da26c3f4b865d6c41cd23690861"
+  },
+  {
+    "TEST": 1,
+    "PHI": "729c20f8762e01f26eef7f8c782f27a1d22fce57cb7ad511364b0b1adc8d8d15",
+    "RHO": "b75cbd1a48240ce610bba11d43cd8a877bfab77fe3fd1c6e9f1b76f66f82673d",
+    "V1": "0296b2e2b3f15b3b4097bd5f729d513cdae4f4e77a2bc2b74cb3eee9df92b08a53",
+    "V2": "03d9485f11eba4a4d7555ebc9b7fea8448ac76dfcafdd0251dd73f6ba9183f9f97",
+    "A1": "0377b9250db185312550172adff4bdf28d500edb93b045f7c09a1b4185f822eb2c",
+    "A2": "020d70ef5cb3ed3a39b267237825e328e4f16fb0f5c73635a0ccf78267fb831155",
+    "PK": "02f8485cfe45304209ede5aad54be3c33c0567e4285158900d3740ed1151095af2",
+    "M": "f48efdc380db92855fb87f3e100a5ec3192c941556c686b4071a2b66c21ab4e7",
+    "RX": "74a9d4a49613d0cda02d2d572e33787ef8d7b6102407e3648d82aaaae6830ad4",
+    "U1": "023b5bb086e17cf024b4aef5f64cded02c8d58e82dc0b81ca0280dbdab173f7337",
+    "T1": "033b0956620dfd80151e1b311c68296ca416b26a6dcaf17f758f61843fa7f20cca"
+  },
+  {
+    "TEST": 2,
+    "PHI": "4127f3f6854cccd081dac8363f4ca0ed59a6639ddabdd433f3e4bc15768624b7",
+    "RHO": "a58fa6b1939df7b712f2b6df8e9a6e8b5c604274a7e03749e96ee279ac45d16d",
+    "V1": "0324175baf9428de563820db7d6c3d139d9fbd198a701547c11ca54299af537deb",
+    "V2": "03afb4f0dc4842f7f978d866eee5ef05f8dc681e9ff944e39da9ae3431c2d562fe",
+    "A1": "03f999552e871536ad210796d754e93629a87b428ed59945ae1ebf5da012e97c82",
+    "A2": "03910b1d544336770d9a645ebdc5e416890f7a41ee8b65434d50a12e3b5bf618e7",
+    "PK": "0217e6c5058381f34c516f3327ef1d851d1c8fd2cd499c00502f3a0647d670ca5f",
+    "M": "ebc5c6fe5601f1b6910bf144f569cb4322ca9b35ace2197ebde565b3c0dd64f6",
+    "RX": "4d08976f1da7995e5cd8b493821d00921f8f55d95cac211404e4bc86642c112d",
+    "U1": "0223494dfa62fcd7160cb1b12aeda7511b1528bc69bd696b2226fee5152e8c2b94",
+    "T1": "02b9f3113642ea74c3059cae319b780b53a6f3d436552ac31c739908748420a068"
+  },
+  {
+    "TEST": 3,
+    "PHI": "9c50ec01024c7c80a54a6c16087042ed30dd45d1f418b0a53208bae83af056b5",
+    "RHO": "1f95b5145891fe4f166a520505562e02c1e89acf9430f1d4cb33220b6380ef38",
+    "V1": "0200d8ec18cd5ef909f7165fd597cc31acea5373ab559cba0412af6243e8dd99b6",
+    "V2": "039019343f99cd010fe48dd49e1cf0b1e40c4c5e6bad2b515e372f595318492578",
+    "A1": "027f4201b87630b3b075ec58770ee0062660b8dda5ab8cd814b012e3b0c42b8b6a",
+    "A2": "02cf23ba26f71335d1172bf81a237e39ec91af9a06eba84d553355c0e51117face",
+    "PK": "03e071ed02c27c2c34ef68f41e95faa5f6c6a89e74ba8a9d611db5bcc46a84627c",
+    "M": "7ddf90b23c2008e0aa1577a9841e94f2482eaeb19d74208514900a2c179401d6",
+    "RX": "8c18321da2cfa9f5bc1ad17c6b8047f14d87f20fa76fba8aac9f1347b7aab500",
+    "U1": "02a18d5cf7539c6cc684cd6d568f4e7d5a320f0216013e0ced2976e0b69f2b344a",
+    "T1": "024dd37fdfd8efe1d1c5a215b36db61fbd453c0d0e4c00de9198f2b4312975c02e"
+  },
+  {
+    "TEST": 4,
+    "PHI": "f79f1fcf203eb2874c5b436faaf07e4081baeb80ad3b9463107d037f63da0772",
+    "RHO": "4ed51dbdf41e52cae2c47cc480d74222cbf7649ae1a0d3edc340cacb326e3015",
+    "V1": "03c0150ef36692f13fed6487830be2e14d3ceb6cfa220bbc17a9142818ff3d1bf7",
+    "V2": "02f67cb06b73713f0b504a7f2367bc02d26a23e8b7a1ab06da4a584c9c43176aab",
+    "A1": "03c43e32a19af3b48a6ecf73f0fbabc300f8aae821f1fb4304bff40e47c68752d8",
+    "A2": "030f45a6cde8393127d9d491cf3f3a8055e64e521fd38238abf8fbadd907624a22",
+    "PK": "03e1dfa7cf66d2a8c61914030e1fcd4e23b1a3c829068d760a08e95747d23452f1",
+    "M": "cbbaff45d6808bde1886f5c95691aa2817f5a1e1eb19f5ab3c452fedb5aba216",
+    "RX": "9f08a5b179c29f3e8f73333c43c3f3e2760bc6ec9e2653900a420389fbf13571",
+    "U1": "02d87ae8ec1e60079d17b404ef7e7523563132349ed42820e6cbbbcda233dcb798",
+    "T1": "02db5d5856d65a24bfc9ad9db3647eb850d46af66be01dfa7b968cd65cc94b0f19"
+  },
+  {
+    "TEST": 5,
+    "PHI": "7c4da9e90e93a41e814230b20d65a793c6f66b20f7994f16e82e169d6fe93d1a",
+    "RHO": "051d3e656d9f8cfaee6a2d2bb91cb5d1e7b5001087d96fdc63bfa140a848c0e3",
+    "V1": "03c710231600d8b836f17e7b66802f1c1cefbe5b9846337112b03416c9010cb211",
+    "V2": "033cfe84a39bee0c6248b83ed1c12602933560272523812619c9687cbfc8b38040",
+    "A1": "02be99432a6d6cf87efd4323d76662a6924abc2acdd19222928471c7db8ca3e786",
+    "A2": "026da0a9086ead6b0555807cba09d0f93f1788305268ba5dab52bf9b0790cd43c0",
+    "PK": "02771aa3cf848cd12d533108350a5622cfc69298dffc26b438b5c3be760ea4562a",
+    "M": "569d753c4e677b6500541eb0fe705d6f500bff0d2da82d69f6fa89bd33b20115",
+    "RX": "777b142a8000117fca16506bf55c9b64e75af33b5550635e710ccc1db24fa192",
+    "U1": "0272bc0065ab1412d9f75ba9e7d135c7a09f62e8085b202d9037773e78c2b03c58",
+    "T1": "022aa5a3e74856e51b214a4a2587f1ff2b511875e82606bd57c23bdfa82a4005ce"
+  },
+  {
+    "TEST": 6,
+    "PHI": "25c6a0bb417d43c190de60a89e8d3eb14aa687f73ce3d0fe9e99073c667de395",
+    "RHO": "cdfa30a33b2948ec78b930b56ab80745424216f45fee07a53d2b1f3e5af7b475",
+    "V1": "0380e58804318fea8bbb5f2f65ebed3269f7010ac332afba7b3cf6942ac5d54c59",
+    "V2": "036c850b7ba9c00d7c605ee701e542a964eae189dfffc2b123b4d91b94fc917960",
+    "A1": "027403fa494a270057a477fd839760781e9eda2501998699b5af3b7b6ab2d10f1a",
+    "A2": "02cc354b44f8ce3e243cbf52dbaa89ff812ad91075c1d6473ebaf7607f24ad708a",
+    "PK": "0241f39b4993df0135146f71264ef05fc8e50ef19b8a8f05ab30b64863f2089061",
+    "M": "212c526c724b5872abc31a96135bb32ac300ed15b6772aa7506da32c780a0ba6",
+    "RX": "07ee12ae99ff2c1d62152a4ccf6d4c9d8270f9b9400e18380156f1f654ab96aa",
+    "U1": "038008bcd53f72c44e4986afc2b6422e8ac476ad9c78299be3b5c5e16bebaa0756",
+    "T1": "02e2587847318f43343d179ca5169daccd46e7f8686b743024375b5f99ff013d0c"
+  },
+  {
+    "TEST": 7,
+    "PHI": "f8b1bac1540010c5d9184e69144b2be7b65580711d2d31e8b1e38612878b9501",
+    "RHO": "084493c8d744e521570121ba0780d7eba459d83321b7c394cfb8f4ca06291984",
+    "V1": "038df7263f8e31351f32e9419bf8b61768238d051a98fd24a36eb4399f58b203d9",
+    "V2": "03b5fa35fd4725793fd891cbf14d1ad32f68fe8f0ccf9d35ea5ea51fbbff54bf45",
+    "A1": "024175c2e490f9760cc554323f3703839b9642a0afb71ff98f7b6857f2d62a6d1f",
+    "A2": "0297c770c6a5bd3a40a0d5e08a609b4437fe3a416e00ede47208f1820754c995de",
+    "PK": "02082187a353888872e5ce0a000988902473641e862b2c7cb56ba28ac57514edb9",
+    "M": "1ac6bde86b7b86caa709fdafc829d064a926d18a71b36f47cebd8321eda3efee",
+    "RX": "bbedbb0e02e74af6ae4c075c7ac7631de2e21ed310e9e00fa0ab0459e96497a0",
+    "U1": "03cba7f3122a524727b0fccc43cad0b355f821e92b13e6bf3aea465ee34a5a4a46",
+    "T1": "0289c48adcd2a94cc8d078423a895cbaeed18fff4db412264be756766cabbbab16"
+  },
+  {
+    "TEST": 8,
+    "PHI": "d1036f6a337d54fa70e5c939930d4f7b1f24dab01d28d145ea05c7b9b1263bd0",
+    "RHO": "1386ab80c60f36c189ac425811cb8e05c8505b0150ee781e5497cffe2dd2af9e",
+    "V1": "02fe9966c1b7a00359d509e641674932f8bb8a504480ad1f3ce6e3aaadbf6001eb",
+    "V2": "0310693e4782cbbb6ba1e6cd280cbf4901ba332473670ce3c594dd5b061b934efd",
+    "A1": "03a7cb39bfa6055e6c9fea90ebd7c61c9bba05ceb447b169802c265732f65cf6c5",
+    "A2": "031625d142fffe3896c47dc8ff0a22884c6353b96b51a2487526894dc24926d80b",
+    "PK": "024eabcc12a2b906b28ce6ce23c484815a551640038974092485068daf42354693",
+    "M": "7ee4018d7eb57e41630c13b8df4d92baaae783af4eb1a7d8df8163ef1e7ddb5b",
+    "RX": "7a07d53b20e3eb641d0f61a5d76dc385b180de95e431656546889918b8ed71e2",
+    "U1": "02f19a1ec7352bef71ff248ab5cbe45848c8e84f6c2cb047e1181ae9573eb449e0",
+    "T1": "021d9f8945799367f5795eb88623af8f899e70055d8a679aaaa0102d53dca55c9c"
+  },
+  {
+    "TEST": 9,
+    "PHI": "59bbdcf49e8e90a3f625ebc8574baa35ddc41f7800be71920db230e5b790c464",
+    "RHO": "cb41f82b44346b8fa51c05076089cebb937882d2fc77c2a395cb878da4cac558",
+    "V1": "025e39e199f14e9b48abfa549cb6fd68cf902a19f9762a400bb317524d2fc6edcd",
+    "V2": "02f2a908a179a4db10429a12e2ca003342dcb18430c56b1e776a86dec8c598293f",
+    "A1": "03e8684a5693a32f985fbbab6b3250f2c76b558c085f6639bea9e09b5f08f8b829",
+    "A2": "031e667f6984040fa4927e365c45c94c5bc93a54504f7a75412438a8ae29f92f0c",
+    "PK": "029f9e6e7fda7c4fe7c68f1069a093a08600670dc0a05f38bc16c46ffd5d67ac4d",
+    "M": "4b7df9714ecf795cfd698129a6f5250cfb64b739ad163da2da93c728c3bd19be",
+    "RX": "2017c881a593aa3ef98fec5e0b4ad24744ca33bc95490d8eec2e7992333e461a",
+    "U1": "0393de7621eb5fb37edc7364458f8013daecb02c94cc64228ff13984a237ccdd79",
+    "T1": "0267d92ec5c353dd939f527a74a8b1444d0be24e9e3585e490388e2e85a3102d3a"
+  }
+]
\ No newline at end of file
diff --git a/testVectors/mpc/phase5_prove.txt b/testVectors/mpc/phase5_prove.txt
new file mode 100644
index 0000000..a83dad4
--- /dev/null
+++ b/testVectors/mpc/phase5_prove.txt
@@ -0,0 +1,130 @@
+TEST = 0,
+PHI = 42e9c17ded15a239981652376f587871860cea8ca80b600314dcd18f5e41f5e4,
+RHO = 60952570933cde980fca6d1c57ac4fa0ea72c3d7589eb06c2742b1e87925fc1f,
+V1 = 0311241c85d737b3fdfc75f09d1168c1108b45fb98f3d2ad3e1f1dd8fec6da1cc6,
+V2 = 02614a8d747ba485bef570099e6c1521baaedfc6eaba519f11dfc66f9c29942db0,
+A1 = 029bcf3649d9c39e59d97670677dec4db91e7ae1cb438dac32afb9f98d66a70c2d,
+A2 = 02f0e3aa5a7829d4d2ace5cc24d40af0e1d6409b4f948ca7c903da3858d6738915,
+PK = 020a8d50393669103474fd735586c6e6703ee767124ec06d8ff37e58b9b50ae357,
+M = 2d956cc45ebcbb5a69428c45482b11add5e4fe9ff86b9f22586a46707b51599d,
+RX = 7055a6caaefd7a40afaa6205ef6974cb7d948f5a33ffdea261d640eaaead27de,
+U1 = 0310c82c83778a33410dfcb96eded135bb1217ff883fe76942d9fb6d7d29c33beb,
+T1 = 03f0eb9a901fb930bbfd3f8531bbd43d1a238b5da26c3f4b865d6c41cd23690861,
+
+TEST = 1,
+PHI = 729c20f8762e01f26eef7f8c782f27a1d22fce57cb7ad511364b0b1adc8d8d15,
+RHO = b75cbd1a48240ce610bba11d43cd8a877bfab77fe3fd1c6e9f1b76f66f82673d,
+V1 = 0296b2e2b3f15b3b4097bd5f729d513cdae4f4e77a2bc2b74cb3eee9df92b08a53,
+V2 = 03d9485f11eba4a4d7555ebc9b7fea8448ac76dfcafdd0251dd73f6ba9183f9f97,
+A1 = 0377b9250db185312550172adff4bdf28d500edb93b045f7c09a1b4185f822eb2c,
+A2 = 020d70ef5cb3ed3a39b267237825e328e4f16fb0f5c73635a0ccf78267fb831155,
+PK = 02f8485cfe45304209ede5aad54be3c33c0567e4285158900d3740ed1151095af2,
+M = f48efdc380db92855fb87f3e100a5ec3192c941556c686b4071a2b66c21ab4e7,
+RX = 74a9d4a49613d0cda02d2d572e33787ef8d7b6102407e3648d82aaaae6830ad4,
+U1 = 023b5bb086e17cf024b4aef5f64cded02c8d58e82dc0b81ca0280dbdab173f7337,
+T1 = 033b0956620dfd80151e1b311c68296ca416b26a6dcaf17f758f61843fa7f20cca,
+
+TEST = 2,
+PHI = 4127f3f6854cccd081dac8363f4ca0ed59a6639ddabdd433f3e4bc15768624b7,
+RHO = a58fa6b1939df7b712f2b6df8e9a6e8b5c604274a7e03749e96ee279ac45d16d,
+V1 = 0324175baf9428de563820db7d6c3d139d9fbd198a701547c11ca54299af537deb,
+V2 = 03afb4f0dc4842f7f978d866eee5ef05f8dc681e9ff944e39da9ae3431c2d562fe,
+A1 = 03f999552e871536ad210796d754e93629a87b428ed59945ae1ebf5da012e97c82,
+A2 = 03910b1d544336770d9a645ebdc5e416890f7a41ee8b65434d50a12e3b5bf618e7,
+PK = 0217e6c5058381f34c516f3327ef1d851d1c8fd2cd499c00502f3a0647d670ca5f,
+M = ebc5c6fe5601f1b6910bf144f569cb4322ca9b35ace2197ebde565b3c0dd64f6,
+RX = 4d08976f1da7995e5cd8b493821d00921f8f55d95cac211404e4bc86642c112d,
+U1 = 0223494dfa62fcd7160cb1b12aeda7511b1528bc69bd696b2226fee5152e8c2b94,
+T1 = 02b9f3113642ea74c3059cae319b780b53a6f3d436552ac31c739908748420a068,
+
+TEST = 3,
+PHI = 9c50ec01024c7c80a54a6c16087042ed30dd45d1f418b0a53208bae83af056b5,
+RHO = 1f95b5145891fe4f166a520505562e02c1e89acf9430f1d4cb33220b6380ef38,
+V1 = 0200d8ec18cd5ef909f7165fd597cc31acea5373ab559cba0412af6243e8dd99b6,
+V2 = 039019343f99cd010fe48dd49e1cf0b1e40c4c5e6bad2b515e372f595318492578,
+A1 = 027f4201b87630b3b075ec58770ee0062660b8dda5ab8cd814b012e3b0c42b8b6a,
+A2 = 02cf23ba26f71335d1172bf81a237e39ec91af9a06eba84d553355c0e51117face,
+PK = 03e071ed02c27c2c34ef68f41e95faa5f6c6a89e74ba8a9d611db5bcc46a84627c,
+M = 7ddf90b23c2008e0aa1577a9841e94f2482eaeb19d74208514900a2c179401d6,
+RX = 8c18321da2cfa9f5bc1ad17c6b8047f14d87f20fa76fba8aac9f1347b7aab500,
+U1 = 02a18d5cf7539c6cc684cd6d568f4e7d5a320f0216013e0ced2976e0b69f2b344a,
+T1 = 024dd37fdfd8efe1d1c5a215b36db61fbd453c0d0e4c00de9198f2b4312975c02e,
+
+TEST = 4,
+PHI = f79f1fcf203eb2874c5b436faaf07e4081baeb80ad3b9463107d037f63da0772,
+RHO = 4ed51dbdf41e52cae2c47cc480d74222cbf7649ae1a0d3edc340cacb326e3015,
+V1 = 03c0150ef36692f13fed6487830be2e14d3ceb6cfa220bbc17a9142818ff3d1bf7,
+V2 = 02f67cb06b73713f0b504a7f2367bc02d26a23e8b7a1ab06da4a584c9c43176aab,
+A1 = 03c43e32a19af3b48a6ecf73f0fbabc300f8aae821f1fb4304bff40e47c68752d8,
+A2 = 030f45a6cde8393127d9d491cf3f3a8055e64e521fd38238abf8fbadd907624a22,
+PK = 03e1dfa7cf66d2a8c61914030e1fcd4e23b1a3c829068d760a08e95747d23452f1,
+M = cbbaff45d6808bde1886f5c95691aa2817f5a1e1eb19f5ab3c452fedb5aba216,
+RX = 9f08a5b179c29f3e8f73333c43c3f3e2760bc6ec9e2653900a420389fbf13571,
+U1 = 02d87ae8ec1e60079d17b404ef7e7523563132349ed42820e6cbbbcda233dcb798,
+T1 = 02db5d5856d65a24bfc9ad9db3647eb850d46af66be01dfa7b968cd65cc94b0f19,
+
+TEST = 5,
+PHI = 7c4da9e90e93a41e814230b20d65a793c6f66b20f7994f16e82e169d6fe93d1a,
+RHO = 051d3e656d9f8cfaee6a2d2bb91cb5d1e7b5001087d96fdc63bfa140a848c0e3,
+V1 = 03c710231600d8b836f17e7b66802f1c1cefbe5b9846337112b03416c9010cb211,
+V2 = 033cfe84a39bee0c6248b83ed1c12602933560272523812619c9687cbfc8b38040,
+A1 = 02be99432a6d6cf87efd4323d76662a6924abc2acdd19222928471c7db8ca3e786,
+A2 = 026da0a9086ead6b0555807cba09d0f93f1788305268ba5dab52bf9b0790cd43c0,
+PK = 02771aa3cf848cd12d533108350a5622cfc69298dffc26b438b5c3be760ea4562a,
+M = 569d753c4e677b6500541eb0fe705d6f500bff0d2da82d69f6fa89bd33b20115,
+RX = 777b142a8000117fca16506bf55c9b64e75af33b5550635e710ccc1db24fa192,
+U1 = 0272bc0065ab1412d9f75ba9e7d135c7a09f62e8085b202d9037773e78c2b03c58,
+T1 = 022aa5a3e74856e51b214a4a2587f1ff2b511875e82606bd57c23bdfa82a4005ce,
+
+TEST = 6,
+PHI = 25c6a0bb417d43c190de60a89e8d3eb14aa687f73ce3d0fe9e99073c667de395,
+RHO = cdfa30a33b2948ec78b930b56ab80745424216f45fee07a53d2b1f3e5af7b475,
+V1 = 0380e58804318fea8bbb5f2f65ebed3269f7010ac332afba7b3cf6942ac5d54c59,
+V2 = 036c850b7ba9c00d7c605ee701e542a964eae189dfffc2b123b4d91b94fc917960,
+A1 = 027403fa494a270057a477fd839760781e9eda2501998699b5af3b7b6ab2d10f1a,
+A2 = 02cc354b44f8ce3e243cbf52dbaa89ff812ad91075c1d6473ebaf7607f24ad708a,
+PK = 0241f39b4993df0135146f71264ef05fc8e50ef19b8a8f05ab30b64863f2089061,
+M = 212c526c724b5872abc31a96135bb32ac300ed15b6772aa7506da32c780a0ba6,
+RX = 07ee12ae99ff2c1d62152a4ccf6d4c9d8270f9b9400e18380156f1f654ab96aa,
+U1 = 038008bcd53f72c44e4986afc2b6422e8ac476ad9c78299be3b5c5e16bebaa0756,
+T1 = 02e2587847318f43343d179ca5169daccd46e7f8686b743024375b5f99ff013d0c,
+
+TEST = 7,
+PHI = f8b1bac1540010c5d9184e69144b2be7b65580711d2d31e8b1e38612878b9501,
+RHO = 084493c8d744e521570121ba0780d7eba459d83321b7c394cfb8f4ca06291984,
+V1 = 038df7263f8e31351f32e9419bf8b61768238d051a98fd24a36eb4399f58b203d9,
+V2 = 03b5fa35fd4725793fd891cbf14d1ad32f68fe8f0ccf9d35ea5ea51fbbff54bf45,
+A1 = 024175c2e490f9760cc554323f3703839b9642a0afb71ff98f7b6857f2d62a6d1f,
+A2 = 0297c770c6a5bd3a40a0d5e08a609b4437fe3a416e00ede47208f1820754c995de,
+PK = 02082187a353888872e5ce0a000988902473641e862b2c7cb56ba28ac57514edb9,
+M = 1ac6bde86b7b86caa709fdafc829d064a926d18a71b36f47cebd8321eda3efee,
+RX = bbedbb0e02e74af6ae4c075c7ac7631de2e21ed310e9e00fa0ab0459e96497a0,
+U1 = 03cba7f3122a524727b0fccc43cad0b355f821e92b13e6bf3aea465ee34a5a4a46,
+T1 = 0289c48adcd2a94cc8d078423a895cbaeed18fff4db412264be756766cabbbab16,
+
+TEST = 8,
+PHI = d1036f6a337d54fa70e5c939930d4f7b1f24dab01d28d145ea05c7b9b1263bd0,
+RHO = 1386ab80c60f36c189ac425811cb8e05c8505b0150ee781e5497cffe2dd2af9e,
+V1 = 02fe9966c1b7a00359d509e641674932f8bb8a504480ad1f3ce6e3aaadbf6001eb,
+V2 = 0310693e4782cbbb6ba1e6cd280cbf4901ba332473670ce3c594dd5b061b934efd,
+A1 = 03a7cb39bfa6055e6c9fea90ebd7c61c9bba05ceb447b169802c265732f65cf6c5,
+A2 = 031625d142fffe3896c47dc8ff0a22884c6353b96b51a2487526894dc24926d80b,
+PK = 024eabcc12a2b906b28ce6ce23c484815a551640038974092485068daf42354693,
+M = 7ee4018d7eb57e41630c13b8df4d92baaae783af4eb1a7d8df8163ef1e7ddb5b,
+RX = 7a07d53b20e3eb641d0f61a5d76dc385b180de95e431656546889918b8ed71e2,
+U1 = 02f19a1ec7352bef71ff248ab5cbe45848c8e84f6c2cb047e1181ae9573eb449e0,
+T1 = 021d9f8945799367f5795eb88623af8f899e70055d8a679aaaa0102d53dca55c9c,
+
+TEST = 9,
+PHI = 59bbdcf49e8e90a3f625ebc8574baa35ddc41f7800be71920db230e5b790c464,
+RHO = cb41f82b44346b8fa51c05076089cebb937882d2fc77c2a395cb878da4cac558,
+V1 = 025e39e199f14e9b48abfa549cb6fd68cf902a19f9762a400bb317524d2fc6edcd,
+V2 = 02f2a908a179a4db10429a12e2ca003342dcb18430c56b1e776a86dec8c598293f,
+A1 = 03e8684a5693a32f985fbbab6b3250f2c76b558c085f6639bea9e09b5f08f8b829,
+A2 = 031e667f6984040fa4927e365c45c94c5bc93a54504f7a75412438a8ae29f92f0c,
+PK = 029f9e6e7fda7c4fe7c68f1069a093a08600670dc0a05f38bc16c46ffd5d67ac4d,
+M = 4b7df9714ecf795cfd698129a6f5250cfb64b739ad163da2da93c728c3bd19be,
+RX = 2017c881a593aa3ef98fec5e0b4ad24744ca33bc95490d8eec2e7992333e461a,
+U1 = 0393de7621eb5fb37edc7364458f8013daecb02c94cc64228ff13984a237ccdd79,
+T1 = 0267d92ec5c353dd939f527a74a8b1444d0be24e9e3585e490388e2e85a3102d3a,
+
diff --git a/testVectors/mpc/phase5_verify.json b/testVectors/mpc/phase5_verify.json
new file mode 100644
index 0000000..460764b
--- /dev/null
+++ b/testVectors/mpc/phase5_verify.json
@@ -0,0 +1,72 @@
+[
+  {
+    "TEST": 0,
+    "U1": "033f5da68af578469bab4c409a8a8605a4f0d75472d2346c54fc89f9468cfb6465",
+    "U2": "03832fb219980425f747e169537b4d0cb46e575f4396d4839d1bc70cc838becbc7",
+    "T1": "02467f3bebda11b2994ba002fec57774b4364377f2ac5f5ee97ae01cf5fef0b7ce",
+    "T2": "0202030a3b5bf5a0fa12ee2cdaf9753dec7a7a97bb86517d48cab86851f70a2322"
+  },
+  {
+    "TEST": 1,
+    "U1": "0216e4bb925115e198d8cbefa17bb881138139a4624d86b4e9131661e9ff10f297",
+    "U2": "03eee119aaa561be664e78cfc421422533342bc8655402243285d9b2528bdbe0fd",
+    "T1": "0255726c57f1e68b3b264acd445ef883eb8857ea3a2c585744c198158e981cac13",
+    "T2": "03c2aa2ed3040ba2730d41f50353f248cfe56f11081d6180ab4e3ed95c32f8ec9e"
+  },
+  {
+    "TEST": 2,
+    "U1": "0270930f61082c7466ac19214fda624be1b6316873ae6a167043b0c05cdc41386b",
+    "U2": "03b51a351a3d92e1cb07b6a43a18f1461af010d2a7de82f52b1c54cf22241da80d",
+    "T1": "03f072217716e9e29965b268dc336a1dfd047c195f1d716e8e0f659f679d80fd23",
+    "T2": "0225c528beeda5ba01e910b845979619f6e8ca40b27b547dd95b993dea27e04f8c"
+  },
+  {
+    "TEST": 3,
+    "U1": "0369c543585c9e12adb57b66c83c0f0e9a04a4f1fc5d5f216e36fbf1189768ff08",
+    "U2": "02f4a4c14d5b5d94b5196f38b45981c828f88045bb6371956a5d3d693c4e941d99",
+    "T1": "0300602208edd919ae02bd3e655ac4486b0448dcfec4bc715edbe055f1e1dcb0bb",
+    "T2": "03860d7e358f35e3b6fa974cbd5e9c6eee72e8722158773b2e067ecbb37d5c6f1f"
+  },
+  {
+    "TEST": 4,
+    "U1": "02cc71e4d1f81732a8f176018c7fe2cab174ac5589a46c7c5cddc3b92a8cacea58",
+    "U2": "02494af6fd578089b56ed19c44d223453026d28b338d942dbe32ed2691d843ae4f",
+    "T1": "02467aeb6b18ca05c6ae37c53cf9d84c9ed45e0dcfa2c6c3756331465ab43df72b",
+    "T2": "038a031d20e15dd8773143de94f0fa756ec8391fe6f930d43264260874ec0dfcca"
+  },
+  {
+    "TEST": 5,
+    "U1": "0232e33ac5577de12a6560179f763773a3fa771be0e1359be07b5f46c39230e2fb",
+    "U2": "032dfd613face20d59f33c07288d43fec86043aec211e3999966832a6b3d33c19b",
+    "T1": "02e6ecd68c55d7d546de373a2e702eab6f6249666166acf0b06ea369f16f60b04c",
+    "T2": "0206e50c4de02cf149b2b2393f29e02657bcfee165b28dde8043f7a7c510dfff48"
+  },
+  {
+    "TEST": 6,
+    "U1": "0246073f99b3c5c6f3022a53abf7ce6aaf4bd2c1424e8bb12f8a3d5dde5a2683cf",
+    "U2": "0357c6ad172eeb617d71b1f526303ac440eba6ebc2107528209377aa8c6b94494e",
+    "T1": "03524485e619276c5181b5a42d2a7a9b60ec32c0d9347f2960593985f14d1ca1a2",
+    "T2": "026203b02875471607bf3f709534d69e429566788e3a4a0b1ad1f5ad043b3f89fb"
+  },
+  {
+    "TEST": 7,
+    "U1": "026677976aff8866137e6118ddc6df9fef579e10e89d0fb524dffb5ed6f5a94370",
+    "U2": "02c198953702562f1a4c9e64d89b30beaad5ff07d9b1d1d3deac6b2203d359c537",
+    "T1": "0261bbfc24f2abe1a2db8f4c58cce99cdd98094675fc0b041240a5dec0f0dd4ae7",
+    "T2": "022d8229188b6ee201076de07412786ef17b0a179f0ecbbf98154eee98453fc9b8"
+  },
+  {
+    "TEST": 8,
+    "U1": "02691f1531d286c6ec16412c9f5c4354f70d1379bc89e1b74c0308e6b4f57fe591",
+    "U2": "031d181876c0f3c50717b33594a6a6796983dcfea44911c513603ec6cfc060ff63",
+    "T1": "03bbca24e57c42ab254a8f72c7cac20ccf1e0e10b93a160170ac2f103f74ed03ab",
+    "T2": "0315f0b3d52268ddb004ab06bb95a04251f504667be728beb83bb4f5b9b4b914a3"
+  },
+  {
+    "TEST": 9,
+    "U1": "03262fe60ab36974694625b3cfe30db36795366b585b0ba17689075dce2c9eeef4",
+    "U2": "0396277938940d825483b8d7be3e31c6c9d12b02f26089885fa6935756a3ad4a76",
+    "T1": "03da3bb1e00b5cc87ef9d7b338b4d5c7c44cd835a93cb446ccfa6cabae7e505553",
+    "T2": "02d6b9b7fca510b0cfb8cbf001e265b1a7866a68be40fdf659accae5d703ff65f2"
+  }
+]
\ No newline at end of file
diff --git a/testVectors/mpc/phase5_verify.txt b/testVectors/mpc/phase5_verify.txt
new file mode 100644
index 0000000..2380ad6
--- /dev/null
+++ b/testVectors/mpc/phase5_verify.txt
@@ -0,0 +1,60 @@
+TEST = 0,
+U1 = 033f5da68af578469bab4c409a8a8605a4f0d75472d2346c54fc89f9468cfb6465,
+U2 = 03832fb219980425f747e169537b4d0cb46e575f4396d4839d1bc70cc838becbc7,
+T1 = 02467f3bebda11b2994ba002fec57774b4364377f2ac5f5ee97ae01cf5fef0b7ce,
+T2 = 0202030a3b5bf5a0fa12ee2cdaf9753dec7a7a97bb86517d48cab86851f70a2322,
+
+TEST = 1,
+U1 = 0216e4bb925115e198d8cbefa17bb881138139a4624d86b4e9131661e9ff10f297,
+U2 = 03eee119aaa561be664e78cfc421422533342bc8655402243285d9b2528bdbe0fd,
+T1 = 0255726c57f1e68b3b264acd445ef883eb8857ea3a2c585744c198158e981cac13,
+T2 = 03c2aa2ed3040ba2730d41f50353f248cfe56f11081d6180ab4e3ed95c32f8ec9e,
+
+TEST = 2,
+U1 = 0270930f61082c7466ac19214fda624be1b6316873ae6a167043b0c05cdc41386b,
+U2 = 03b51a351a3d92e1cb07b6a43a18f1461af010d2a7de82f52b1c54cf22241da80d,
+T1 = 03f072217716e9e29965b268dc336a1dfd047c195f1d716e8e0f659f679d80fd23,
+T2 = 0225c528beeda5ba01e910b845979619f6e8ca40b27b547dd95b993dea27e04f8c,
+
+TEST = 3,
+U1 = 0369c543585c9e12adb57b66c83c0f0e9a04a4f1fc5d5f216e36fbf1189768ff08,
+U2 = 02f4a4c14d5b5d94b5196f38b45981c828f88045bb6371956a5d3d693c4e941d99,
+T1 = 0300602208edd919ae02bd3e655ac4486b0448dcfec4bc715edbe055f1e1dcb0bb,
+T2 = 03860d7e358f35e3b6fa974cbd5e9c6eee72e8722158773b2e067ecbb37d5c6f1f,
+
+TEST = 4,
+U1 = 02cc71e4d1f81732a8f176018c7fe2cab174ac5589a46c7c5cddc3b92a8cacea58,
+U2 = 02494af6fd578089b56ed19c44d223453026d28b338d942dbe32ed2691d843ae4f,
+T1 = 02467aeb6b18ca05c6ae37c53cf9d84c9ed45e0dcfa2c6c3756331465ab43df72b,
+T2 = 038a031d20e15dd8773143de94f0fa756ec8391fe6f930d43264260874ec0dfcca,
+
+TEST = 5,
+U1 = 0232e33ac5577de12a6560179f763773a3fa771be0e1359be07b5f46c39230e2fb,
+U2 = 032dfd613face20d59f33c07288d43fec86043aec211e3999966832a6b3d33c19b,
+T1 = 02e6ecd68c55d7d546de373a2e702eab6f6249666166acf0b06ea369f16f60b04c,
+T2 = 0206e50c4de02cf149b2b2393f29e02657bcfee165b28dde8043f7a7c510dfff48,
+
+TEST = 6,
+U1 = 0246073f99b3c5c6f3022a53abf7ce6aaf4bd2c1424e8bb12f8a3d5dde5a2683cf,
+U2 = 0357c6ad172eeb617d71b1f526303ac440eba6ebc2107528209377aa8c6b94494e,
+T1 = 03524485e619276c5181b5a42d2a7a9b60ec32c0d9347f2960593985f14d1ca1a2,
+T2 = 026203b02875471607bf3f709534d69e429566788e3a4a0b1ad1f5ad043b3f89fb,
+
+TEST = 7,
+U1 = 026677976aff8866137e6118ddc6df9fef579e10e89d0fb524dffb5ed6f5a94370,
+U2 = 02c198953702562f1a4c9e64d89b30beaad5ff07d9b1d1d3deac6b2203d359c537,
+T1 = 0261bbfc24f2abe1a2db8f4c58cce99cdd98094675fc0b041240a5dec0f0dd4ae7,
+T2 = 022d8229188b6ee201076de07412786ef17b0a179f0ecbbf98154eee98453fc9b8,
+
+TEST = 8,
+U1 = 02691f1531d286c6ec16412c9f5c4354f70d1379bc89e1b74c0308e6b4f57fe591,
+U2 = 031d181876c0f3c50717b33594a6a6796983dcfea44911c513603ec6cfc060ff63,
+T1 = 03bbca24e57c42ab254a8f72c7cac20ccf1e0e10b93a160170ac2f103f74ed03ab,
+T2 = 0315f0b3d52268ddb004ab06bb95a04251f504667be728beb83bb4f5b9b4b914a3,
+
+TEST = 9,
+U1 = 03262fe60ab36974694625b3cfe30db36795366b585b0ba17689075dce2c9eeef4,
+U2 = 0396277938940d825483b8d7be3e31c6c9d12b02f26089885fa6935756a3ad4a76,
+T1 = 03da3bb1e00b5cc87ef9d7b338b4d5c7c44cd835a93cb446ccfa6cabae7e505553,
+T2 = 02d6b9b7fca510b0cfb8cbf001e265b1a7866a68be40fdf659accae5d703ff65f2,
+