You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@milagro.apache.org by km...@apache.org on 2019/08/26 13:25:26 UTC

[incubator-milagro-crypto-c] 02/02: added BLS SSS to BLS library

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

kmccusker pushed a commit to branch bls-sss
in repository https://gitbox.apache.org/repos/asf/incubator-milagro-crypto-c.git

commit db8d27d0cc9987bed2d0c9531d6fe605e8833bb4
Author: Kealan McCusker <ke...@gmail.com>
AuthorDate: Mon Aug 26 14:25:04 2019 +0100

    added BLS SSS to BLS library
---
 VERSION                           |   2 +-
 examples/CMakeLists.txt           |   4 +
 examples/example_bls_ZZZ.c.in     |  16 ++-
 examples/example_bls_sss_ZZZ.c.in | 242 +++++++++++++++++++++++++++++++++++++
 include/bls.h.in                  |  57 +++++++--
 include/bls192.h.in               |  33 ++++++
 include/bls256.h.in               |  33 ++++++
 src/bls.c.in                      | 216 +++++++++++++++++++++++++++++++++
 src/bls192.c.in                   | 216 +++++++++++++++++++++++++++++++++
 src/bls256.c.in                   | 216 +++++++++++++++++++++++++++++++++
 test/CMakeLists.txt               |   1 +
 test/test_bls_ZZZ.c.in            |   6 +-
 test/test_bls_sss_ZZZ.c.in        | 243 ++++++++++++++++++++++++++++++++++++++
 13 files changed, 1265 insertions(+), 20 deletions(-)

diff --git a/VERSION b/VERSION
index 7dea76e..9084fa2 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.0.1
+1.1.0
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index d81e923..785630e 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -50,6 +50,10 @@ foreach(curve ${AMCL_CURVE})
     amcl_configure_file_curve(example_bls_ZZZ.c.in example_bls_${TC}.c "${curve}" example_bls_${TC}_GEN_SRCS)
     add_executable(example_bls_${TC} ${example_bls_${TC}_GEN_SRCS})
     target_link_libraries(example_bls_${TC} PRIVATE amcl_bls_${TC})
+    
+    amcl_configure_file_curve(example_bls_sss_ZZZ.c.in example_bls_sss_${TC}.c "${curve}" example_bls_sss_${TC}_GEN_SRCS)
+    add_executable(example_bls_sss_${TC} ${example_bls_sss_${TC}_GEN_SRCS})
+    target_link_libraries(example_bls_sss_${TC} PRIVATE amcl_bls_${TC})
   endif()
   
 endforeach()
diff --git a/examples/example_bls_ZZZ.c.in b/examples/example_bls_ZZZ.c.in
index 736e54d..d171a9d 100644
--- a/examples/example_bls_ZZZ.c.in
+++ b/examples/example_bls_ZZZ.c.in
@@ -16,9 +16,18 @@ specific language governing permissions and limitations
 under the License.
 */
 
-/* Build executable after installation:
+/* 
+  BLS example code. 
+  
+  Build executable after installation:
 
-  gcc -O0 -g ./testbls_ZZZ.c $(pkg-config --libs --cflags amcl) -o testbls_ZZZ
+  1. Change headers;
+    
+    #include "bls_ZZZ.h" -> #include <amcl/bls_ZZZ.h>
+
+  2. Build code
+
+    gcc -O0 -g ./example_bls_ZZZ.c $(pkg-config --libs --cflags amcl) -o example_bls_ZZZ
 
 */
 
@@ -269,12 +278,11 @@ int main()
     OCT_fromHex(&SEED,seedHex);
     printf("SEED: ");
     OCT_output(&SEED);
-    printf("\n");
 
     // initialise strong RNG
     CREATE_CSPRNG(&RNG,&SEED);
 
-    printf("\nTesting BLS signature for curve ZZZ\n");
+    printf("\nBLS example for curve ZZZ\n");
     bls(&RNG);
 
     KILL_CSPRNG(&RNG);
diff --git a/examples/example_bls_sss_ZZZ.c.in b/examples/example_bls_sss_ZZZ.c.in
new file mode 100644
index 0000000..c325d68
--- /dev/null
+++ b/examples/example_bls_sss_ZZZ.c.in
@@ -0,0 +1,242 @@
+/*
+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.
+*/
+
+/* 
+  BLS Shamir Secret Sharing example code. 
+  
+  Build executable after installation:
+
+  1. Change headers;
+    
+    #include "bls_ZZZ.h" -> #include <amcl/bls_ZZZ.h>
+
+  2. Build code
+
+    gcc -O0 -g ./example_bls_sss_ZZZ.c $(pkg-config --libs --cflags amcl) -o example_bls_sss_ZZZ
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "config_curve_ZZZ.h"
+#include "randapi.h"
+
+#if CURVE_SECURITY_ZZZ == 128
+#include "bls_ZZZ.h"
+#elif CURVE_SECURITY_ZZZ == 192
+#include "bls192_ZZZ.h"
+#elif CURVE_SECURITY_ZZZ == 256
+#include "bls256_ZZZ.h"
+#endif
+
+// Support multiple security levels
+#if CURVE_SECURITY_ZZZ == 128
+#define G2LEN 4*BFS_ZZZ
+#elif CURVE_SECURITY_ZZZ == 192
+#define G2LEN 8*BFS_ZZZ
+#elif CURVE_SECURITY_ZZZ == 256
+#define G2LEN 16*BFS_ZZZ
+#endif
+
+static char message[]="test message";
+
+int bls_sss(csprng *RNG)
+{
+    int rc;
+    int n=4;
+    int k=3;
+
+    char ski[BGS_ZZZ];
+    octet SKI = {0,sizeof(ski),ski};
+    char pki[G2LEN];
+    octet PKI = {0,sizeof(pki),pki};
+
+    char sko[BGS_ZZZ];
+    octet SKO = {sizeof(sko),sizeof(sko),sko};
+    char skr[BGS_ZZZ];
+    octet SKR = {sizeof(skr),sizeof(skr),skr};
+
+    char sigi[BFS_ZZZ+1];
+    octet SIGI = {0,sizeof(sigi),sigi};
+    char sigr[BFS_ZZZ+1];
+    octet SIGR = {0,sizeof(sigr),sigr};
+
+    // Secret shares
+    char x[n][BGS_ZZZ];
+    octet X[n];
+    char y[n][BGS_ZZZ];
+    octet Y[n];
+    
+    for(int i=0; i<n; i++)
+    {
+        memset(&y[i], 0, sizeof(y[i]));
+        Y[i].max = BGS_ZZZ;
+        Y[i].len = BGS_ZZZ;
+        Y[i].val = y[i];
+        memset(&x[i], 0, sizeof(x[i]));
+        X[i].max = BGS_ZZZ;
+        X[i].len = BGS_ZZZ;
+        X[i].val = x[i];
+    }
+    
+    // Generate key pair
+    BLS_ZZZ_KEY_PAIR_GENERATE(RNG,&SKI,&PKI);
+
+    printf("Private key SKI: ");
+    OCT_output(&SKI);
+    printf("Public key PKI: ");
+    OCT_output(&PKI);
+    printf("\n");
+
+    // Sign the message
+    BLS_ZZZ_SIGN(&SIGI,message,&SKI);
+
+    printf("SIGI: ");
+    OCT_output(&SIGI);
+
+    // Verify signature
+    rc=BLS_ZZZ_VERIFY(&SIGI,message,&PKI);
+    if (rc!=BLS_OK)
+    {
+        printf("Error: Invalid Signature\n");
+	return 1;
+    }
+    printf("Success: Signature is valid\n");
+
+    // Make shares of BLS secret key
+    rc = BLS_ZZZ_MAKE_SHARES(k, n, RNG, X, Y, &SKI, &SKO);
+    if (rc!=BLS_OK)
+    {
+        printf("Error: BLS_ZZZ_MAKE_SHARES\n");
+	return 1;
+    }    
+
+    for(int i=0; i<n; i++)
+    {
+        printf("X[%d] ", i);
+        OCT_output(&X[i]);
+        printf("Y[%d] ", i);
+        OCT_output(&Y[i]);
+    }
+    
+    printf("SKO: ");
+    OCT_output(&SKO);
+    
+    if (!OCT_comp(&SKI,&SKO))
+    {
+        printf("FAILURE SKI != SKO");
+        return 1;
+    }
+    
+    // Recover BLS secret key
+    rc = BLS_ZZZ_RECOVER_SECRET(k, X, Y, &SKR);
+    if (rc!=BLS_OK)
+    {
+        printf("Error: BLS_ZZZ_RECOVER_SECRET\n");
+	return 1;
+    }    
+    printf("SKR: ");
+    OCT_output(&SKR);
+    
+    if (!OCT_comp(&SKR,&SKO))
+    {
+        printf("FAILURE SKR != SKO");
+        return 1;
+    }
+    
+    // Generate public keys and signatures using shares
+    char pks[n][G2LEN];
+    octet PKS[n];
+    char sigs[n][BFS_ZZZ+1];
+    octet SIGS[n];
+    for(int i=0; i<n; i++)
+    {
+        memset(&sigs[i], 0, sizeof(sigs[i]));
+        SIGS[i].max = BFS_ZZZ+1;
+        SIGS[i].len = BFS_ZZZ+1;
+        SIGS[i].val = sigs[i];
+        memset(&PKS[i], 0, sizeof(PKS[i]));
+        PKS[i].max = G2LEN;
+        PKS[i].len = G2LEN;
+        PKS[i].val = pks[i];
+        BLS_ZZZ_KEY_PAIR_GENERATE(NULL,&Y[i],&PKS[i]);
+        BLS_ZZZ_SIGN(&SIGS[i],message,&Y[i]);
+    }
+
+    for(int i=0; i<n; i++)
+    {
+        printf("PKS[%d] ", i);
+        OCT_output(&PKS[i]);
+    }
+
+    for(int i=0; i<n; i++)
+    {
+        printf("SIGS[%d] ", i);
+        OCT_output(&SIGS[i]);
+    }
+    printf("\n\n");
+
+    // Recover BLS signature
+    rc = BLS_ZZZ_RECOVER_SIGNATURE(k, X, SIGS, &SIGR);
+    if (rc!=BLS_OK)
+    {
+        printf("Error: BLS_ZZZ_RECOVER_SIGNATURE\n");
+	return 1;
+    }    
+    printf("SIGR: ");
+    OCT_output(&SIGR);
+    
+    if (!OCT_comp(&SIGR,&SIGI))
+    {
+        printf("FAILURE SIGR != SIGI");
+        return 1;
+    }
+    
+    return 0;
+}
+
+
+int main()
+{
+#ifdef DEBUG
+    printf("%d bit build\n",CHUNK);
+#endif
+
+    char* seedHex = "78d0fb6705ce77dee47d03eb5b9c5d30";
+    char seed[16] = {0};
+    octet SEED = {sizeof(seed),sizeof(seed),seed};
+
+    // CSPRNG
+    csprng RNG;
+
+    // fake random source
+    OCT_fromHex(&SEED,seedHex);
+    printf("SEED: ");
+    OCT_output(&SEED);
+
+    // initialise strong RNG
+    CREATE_CSPRNG(&RNG,&SEED);
+
+    printf("\nBLS SSS example for curve ZZZ\n");
+    bls_sss(&RNG);
+
+    KILL_CSPRNG(&RNG);
+}
+
+
diff --git a/include/bls.h.in b/include/bls.h.in
index b500802..13332b2 100644
--- a/include/bls.h.in
+++ b/include/bls.h.in
@@ -75,39 +75,72 @@ int BLS_ZZZ_VERIFY(octet *SIG,char *m,octet *W);
 
 /**	@brief Add two members from the group G1
  *
-	@param      R1 member of G1
-	@param      R2 member of G1
-	@param      R member of G1. R = R1+R2
+	@param  R1  member of G1
+	@param  R2  member of G1
+	@param  R   member of G1. R = R1+R2
 	@return     Zero for success or else an error code
  */
 int BLS_ZZZ_ADD_G1(octet *R1,octet *R2,octet *R);
 
 /**	@brief Add two members from the group G2
  *
-	@param      W1 member of G2
-	@param      W2 member of G2
-	@param      W member of G2. W = W1+W2
+	@param  W1  member of G2
+	@param  W2  member of G2
+	@param  W   member of G2. W = W1+W2
 	@return     Zero for success or else an error code
  */
 int BLS_ZZZ_ADD_G2(octet *W1,octet *W2,octet *W);
 
 /**	@brief Multiply a member group G1 by an integer
  *
-	@param      P integer
-	@param      R member of G1
-	@param      T member of G1. T=P*R
+	@param  P   integer
+	@param  R   member of G1
+	@param  T   member of G1. T=P*R
 	@return     Zero for success or else an error code
  */
 int BLS_ZZZ_MUL_G1(octet *P,octet *R,octet *T);
 
 /**	@brief Multiply a member group G2 by an integer
  *
-	@param      P integer
-	@param      R member of G2
-	@param      T member of G2. T=P*R
+	@param  P   integer
+	@param  R   member of G2
+	@param  T   member of G2. T=P*R
 	@return     Zero for success or else an error code
  */
 int BLS_ZZZ_MUL_G2(octet *P,octet *R,octet *T);
 
+/**	@brief Use Shamir's secret sharing to distribute BLS secret keys
+ *
+	@param  k   Threshold
+	@param  n   Number of shares
+        @param  RNG Pointer to a cryptographically secure random number generator
+	@param  X   Output X values
+	@param  Y   Output Y values. Valid BLS secret keys
+	@param  SKI Input secret key to be shared. Ignored if set to NULL
+	@param  SKO Secret key that is shared
+	@return     Zero for success or else an error code
+ */
+int BLS_ZZZ_MAKE_SHARES(int k, int n, csprng *RNG, octet* X, octet* Y, octet* SKI, octet* SKO);
+
+/**	@brief Use Shamir's secret sharing to recover a BLS secret key
+ *
+	@param  k   Threshold
+	@param  X   Output X values
+	@param  Y   Output Y values. Valid BLS secret keys
+	@param  SK  Secret key that is recovered
+	@return     Zero for success or else an error code
+ */
+int BLS_ZZZ_RECOVER_SECRET(int k, octet* X, octet* Y, octet* SK);
+
+/**	@brief Use Shamir's secret sharing to recover a BLS signature
+ *
+	@param  k   Threshold
+	@param  X   Output X values
+	@param  Y   Output Y values. Valid BLS secret keys
+	@param  SIG Signature that is recovered
+	@return     Zero for success or else an error code
+ */
+int BLS_ZZZ_RECOVER_SIGNATURE(int k, octet* X, octet* Y, octet* SIG);
+
 #endif
 
diff --git a/include/bls192.h.in b/include/bls192.h.in
index b7d22cc..88355d0 100644
--- a/include/bls192.h.in
+++ b/include/bls192.h.in
@@ -109,6 +109,39 @@ int BLS_ZZZ_MUL_G1(octet *P,octet *R,octet *T);
  */
 int BLS_ZZZ_MUL_G2(octet *P,octet *R,octet *T);
 
+/**	@brief Use Shamir's secret sharing to distribute BLS secret keys
+ *
+	@param  k   Threshold
+	@param  n   Number of shares
+        @param  RNG Pointer to a cryptographically secure random number generator
+	@param  X   Output X values
+	@param  Y   Output Y values. Valid BLS secret keys
+	@param  SKI Input secret key to be shared. Ignored if set to NULL
+	@param  SKO Secret key that is shared
+	@return     Zero for success or else an error code
+ */
+int BLS_ZZZ_MAKE_SHARES(int k, int n, csprng *RNG, octet* X, octet* Y, octet* SKI, octet* SKO);
+
+/**	@brief Use Shamir's secret sharing to recover a BLS secret key
+ *
+	@param  k   Threshold
+	@param  X   Output X values
+	@param  Y   Output Y values. Valid BLS secret keys
+	@param  SK  Secret key that is recovered
+	@return     Zero for success or else an error code
+ */
+int BLS_ZZZ_RECOVER_SECRET(int k, octet* X, octet* Y, octet* SK);
+
+/**	@brief Use Shamir's secret sharing to recover a BLS signature
+ *
+	@param  k   Threshold
+	@param  X   Output X values
+	@param  Y   Output Y values. Valid BLS secret keys
+	@param  SIG Signature that is recovered
+	@return     Zero for success or else an error code
+ */
+int BLS_ZZZ_RECOVER_SIGNATURE(int k, octet* X, octet* Y, octet* SIG);
+
 
 #endif
 
diff --git a/include/bls256.h.in b/include/bls256.h.in
index cc2d94e..b5b8add 100644
--- a/include/bls256.h.in
+++ b/include/bls256.h.in
@@ -109,6 +109,39 @@ int BLS_ZZZ_MUL_G1(octet *P,octet *R,octet *T);
  */
 int BLS_ZZZ_MUL_G2(octet *P,octet *R,octet *T);
 
+/**	@brief Use Shamir's secret sharing to distribute BLS secret keys
+ *
+	@param  k   Threshold
+	@param  n   Number of shares
+        @param  RNG Pointer to a cryptographically secure random number generator
+	@param  X   Output X values
+	@param  Y   Output Y values. Valid BLS secret keys
+	@param  SKI Input secret key to be shared. Ignored if set to NULL
+	@param  SKO Secret key that is shared
+	@return     Zero for success or else an error code
+ */
+int BLS_ZZZ_MAKE_SHARES(int k, int n, csprng *RNG, octet* X, octet* Y, octet* SKI, octet* SKO);
+
+/**	@brief Use Shamir's secret sharing to recover a BLS secret key
+ *
+	@param  k   Threshold
+	@param  X   Output X values
+	@param  Y   Output Y values. Valid BLS secret keys
+	@param  SK  Secret key that is recovered
+	@return     Zero for success or else an error code
+ */
+int BLS_ZZZ_RECOVER_SECRET(int k, octet* X, octet* Y, octet* SK);
+
+/**	@brief Use Shamir's secret sharing to recover a BLS signature
+ *
+	@param  k   Threshold
+	@param  X   Output X values
+	@param  Y   Output Y values. Valid BLS secret keys
+	@param  SIG Signature that is recovered
+	@return     Zero for success or else an error code
+ */
+int BLS_ZZZ_RECOVER_SIGNATURE(int k, octet* X, octet* Y, octet* SIG);
+
 
 #endif
 
diff --git a/src/bls.c.in b/src/bls.c.in
index 6868ba8..1903a58 100644
--- a/src/bls.c.in
+++ b/src/bls.c.in
@@ -25,6 +25,61 @@ under the License.
 #include <time.h>
 #include "bls_ZZZ.h"
 
+// Polynomial interpolation coefficients
+static int recover_coefficients(int k, octet* X, octet* COEFS)
+{
+    BIG_XXX r;
+    BIG_XXX_rcopy(r,CURVE_Order_ZZZ);
+
+    BIG_XXX x2[k];
+    BIG_XXX coefs[k];
+
+    for(int i=0; i<k; i++)
+    {
+        BIG_XXX_fromBytes(x2[i],X[i].val);
+    }
+
+    for(int i=0; i<k; i++)
+    {
+        BIG_XXX numerator;
+        BIG_XXX_one(numerator);
+        BIG_XXX denominator;
+        BIG_XXX_one(denominator);
+        for(int j=0; j<k; j++)
+        {
+            // others = all - current
+            // current = x2[i]
+            if (i != j)
+            {
+                // numerator = numerator * other
+                BIG_XXX_modmul(numerator,numerator,x2[j],r);
+
+                // other - current
+                BIG_XXX s;
+                BIG_XXX c;
+
+                // c = -current
+                BIG_XXX_sub(c,r,x2[i]);
+                BIG_XXX_add(s,x2[j],c);
+
+                // denominator = denominator * s
+                BIG_XXX_modmul(denominator,denominator,s,r);
+
+            }
+
+        }
+        BIG_XXX_moddiv(coefs[i], numerator, denominator, r);
+    }
+
+    // Output coefficients
+    for(int i=0; i<k; i++)
+    {
+        BIG_XXX_toBytes(COEFS[i].val,coefs[i]);
+    }
+    return 0;
+
+}
+
 /* hash a message to an ECP point, using SHA3 */
 static void BLS_HASHIT(ECP_ZZZ *P,char *m)
 {
@@ -191,3 +246,164 @@ int BLS_ZZZ_MUL_G2(octet *P,octet *R,octet *T)
 
     return BLS_OK;
 }
+
+int BLS_ZZZ_MAKE_SHARES(int k, int n, csprng *RNG, octet* X, octet* Y, octet* SKI, octet* SKO)
+{
+    BIG_XXX y2[n];
+    BIG_XXX r;
+    BIG_XXX_rcopy(r,CURVE_Order_ZZZ);
+
+    // Generate polynomial: f(x) = a_0 + a_1x + a_2x^2 ... a_{k-1}x^{k-1}
+    BIG_XXX poly[k];
+    for(int i=0; i<k; i++)
+    {
+        BIG_XXX_randomnum(poly[i],r,RNG);
+    }
+
+    // Use predefined secret
+    if (SKI != NULL)
+    {
+        BIG_XXX_fromBytes(poly[0],SKI->val);
+    }
+
+    /* Calculate f(x) = a_0 + a_1x + a_2x^2 ... a_{k-1}x^{k-1}
+       a0 is the secret */
+    int x=0;
+    for(int j=0; j<n; j++)
+    {
+        x++;
+        BIG_XXX xb;
+        BIG_XXX_zero(y2[j]);
+        BIG_XXX_zero(xb);
+        BIG_XXX_inc(xb,x);
+
+        // Output X shares
+        BIG_XXX_toBytes(X[j].val,xb);
+
+        // y2[j] is the accmulator
+        for(int i=k-1; i>=0; i--)
+        {
+            BIG_XXX_modmul(y2[j],y2[j],xb,r);
+            BIG_XXX_add(y2[j],poly[i],y2[j]);
+        }
+    }
+
+    // Output Y shares
+    for(int j=0; j<n; j++)
+    {
+        BIG_XXX_toBytes(Y[j].val,y2[j]);
+    }
+
+    // Output secret
+    BIG_XXX_toBytes(SKO->val,poly[0]);
+
+    return BLS_OK;
+}
+
+int BLS_ZZZ_RECOVER_SECRET(int k, octet* X, octet* Y, octet* SK)
+{
+    int rc=0;
+    BIG_XXX r;
+    BIG_XXX_rcopy(r,CURVE_Order_ZZZ);
+
+    BIG_XXX y[k];
+    BIG_XXX coefs[k];
+
+    BIG_XXX secret;
+    BIG_XXX prod;
+    BIG_XXX_zero(secret);
+
+    char coefs2[k][BGS_ZZZ];
+    octet COEFS[k];
+    for(int i=0; i<k; i++)
+    {
+        memset(&coefs2[i], 0, sizeof(coefs2[i]));
+        COEFS[i].max = BGS_ZZZ;
+        COEFS[i].len = BGS_ZZZ;
+        COEFS[i].val = coefs2[i];
+    }
+
+    rc = recover_coefficients(k, X, COEFS);
+    if (rc)
+      {
+	return rc;
+      }
+
+    for(int i=0; i<k; i++)
+    {
+        BIG_XXX_fromBytes(y[i],Y[i].val);
+        BIG_XXX_fromBytes(coefs[i],COEFS[i].val);
+        BIG_XXX_modmul(prod,y[i],coefs[i],r);
+        BIG_XXX_add(secret, secret, prod);
+
+        if (BIG_XXX_comp(secret,r) == 1)
+        {
+            BIG_XXX_sub(secret,secret,r);
+        }
+    }
+
+    // Output secret
+    BIG_XXX_toBytes(SK->val,secret);
+
+    return BLS_OK;
+}
+
+int BLS_ZZZ_RECOVER_SIGNATURE(int k, octet* X, octet* Y, octet* SIG)
+{
+    int rc = 0;
+    char product[k][BFS_ZZZ+1];
+    octet PRODUCT[k];
+
+    char coefs[k][BGS_ZZZ];
+    octet COEFS[k];
+    for(int i=0; i<k; i++)
+    {
+        memset(&coefs[i], 0, sizeof(coefs[i]));
+        COEFS[i].max = BGS_ZZZ;
+        COEFS[i].len = BGS_ZZZ;
+        COEFS[i].val = coefs[i];
+    }
+
+    rc = recover_coefficients(k, X, COEFS);
+    if (rc)
+      {
+	return rc;
+      }
+
+    
+    for(int i=0; i<k; i++)
+    {
+        memset(&product[i], 0, sizeof(product[i]));
+        PRODUCT[i].max = BFS_ZZZ+1;
+        PRODUCT[i].len = BFS_ZZZ+1;
+        PRODUCT[i].val = product[i];
+    }
+
+    for(int i=0; i<k; i++)
+    {
+        rc = BLS_ZZZ_MUL_G1(&COEFS[i], &Y[i], &PRODUCT[i]);
+        if (rc != BLS_OK)
+        {
+            return rc;
+        }
+    }
+
+    BLS_ZZZ_ADD_G1(&PRODUCT[0],&PRODUCT[1],SIG);
+    if (rc != BLS_OK)
+    {
+        return rc;
+    }
+
+    for(int i=2; i<k; i++)
+    {
+        BLS_ZZZ_ADD_G1(&PRODUCT[i],SIG,SIG);
+        if (rc != BLS_OK)
+        {
+            return rc;
+        }
+    }
+
+    return BLS_OK;
+}
+
+
diff --git a/src/bls192.c.in b/src/bls192.c.in
index 617a94e..1c86954 100644
--- a/src/bls192.c.in
+++ b/src/bls192.c.in
@@ -25,6 +25,61 @@ under the License.
 #include <time.h>
 #include "bls192_ZZZ.h"
 
+// Polynomial interpolation coefficients
+static int recover_coefficients(int k, octet* X, octet* COEFS)
+{
+    BIG_XXX r;
+    BIG_XXX_rcopy(r,CURVE_Order_ZZZ);
+
+    BIG_XXX x2[k];
+    BIG_XXX coefs[k];
+
+    for(int i=0; i<k; i++)
+    {
+        BIG_XXX_fromBytes(x2[i],X[i].val);
+    }
+
+    for(int i=0; i<k; i++)
+    {
+        BIG_XXX numerator;
+        BIG_XXX_one(numerator);
+        BIG_XXX denominator;
+        BIG_XXX_one(denominator);
+        for(int j=0; j<k; j++)
+        {
+            // others = all - current
+            // current = x2[i]
+            if (i != j)
+            {
+                // numerator = numerator * other
+                BIG_XXX_modmul(numerator,numerator,x2[j],r);
+
+                // other - current
+                BIG_XXX s;
+                BIG_XXX c;
+
+                // c = -current
+                BIG_XXX_sub(c,r,x2[i]);
+                BIG_XXX_add(s,x2[j],c);
+
+                // denominator = denominator * s
+                BIG_XXX_modmul(denominator,denominator,s,r);
+
+            }
+
+        }
+        BIG_XXX_moddiv(coefs[i], numerator, denominator, r);
+    }
+
+    // Output coefficients
+    for(int i=0; i<k; i++)
+    {
+        BIG_XXX_toBytes(COEFS[i].val,coefs[i]);
+    }
+    return 0;
+
+}
+
 /* hash a message to an ECP point, using SHA3 */
 static void BLS_HASHIT(ECP_ZZZ *P,char *m)
 {
@@ -191,3 +246,164 @@ int BLS_ZZZ_MUL_G2(octet *P,octet *R,octet *T)
 
     return BLS_OK;
 }
+
+int BLS_ZZZ_MAKE_SHARES(int k, int n, csprng *RNG, octet* X, octet* Y, octet* SKI, octet* SKO)
+{
+    BIG_XXX y2[n];
+    BIG_XXX r;
+    BIG_XXX_rcopy(r,CURVE_Order_ZZZ);
+
+    // Generate polynomial: f(x) = a_0 + a_1x + a_2x^2 ... a_{k-1}x^{k-1}
+    BIG_XXX poly[k];
+    for(int i=0; i<k; i++)
+    {
+        BIG_XXX_randomnum(poly[i],r,RNG);
+    }
+
+    // Use predefined secret
+    if (SKI != NULL)
+    {
+        BIG_XXX_fromBytes(poly[0],SKI->val);
+    }
+
+    /* Calculate f(x) = a_0 + a_1x + a_2x^2 ... a_{k-1}x^{k-1}
+       a0 is the secret */
+    int x=0;
+    for(int j=0; j<n; j++)
+    {
+        x++;
+        BIG_XXX xb;
+        BIG_XXX_zero(y2[j]);
+        BIG_XXX_zero(xb);
+        BIG_XXX_inc(xb,x);
+
+        // Output X shares
+        BIG_XXX_toBytes(X[j].val,xb);
+
+        // y2[j] is the accmulator
+        for(int i=k-1; i>=0; i--)
+        {
+            BIG_XXX_modmul(y2[j],y2[j],xb,r);
+            BIG_XXX_add(y2[j],poly[i],y2[j]);
+        }
+    }
+
+    // Output Y shares
+    for(int j=0; j<n; j++)
+    {
+        BIG_XXX_toBytes(Y[j].val,y2[j]);
+    }
+
+    // Output secret
+    BIG_XXX_toBytes(SKO->val,poly[0]);
+
+    return BLS_OK;
+}
+
+int BLS_ZZZ_RECOVER_SECRET(int k, octet* X, octet* Y, octet* SK)
+{
+    int rc=0;
+    BIG_XXX r;
+    BIG_XXX_rcopy(r,CURVE_Order_ZZZ);
+
+    BIG_XXX y[k];
+    BIG_XXX coefs[k];
+
+    BIG_XXX secret;
+    BIG_XXX prod;
+    BIG_XXX_zero(secret);
+
+    char coefs2[k][BGS_ZZZ];
+    octet COEFS[k];
+    for(int i=0; i<k; i++)
+    {
+        memset(&coefs2[i], 0, sizeof(coefs2[i]));
+        COEFS[i].max = BGS_ZZZ;
+        COEFS[i].len = BGS_ZZZ;
+        COEFS[i].val = coefs2[i];
+    }
+
+    rc = recover_coefficients(k, X, COEFS);
+    if (rc)
+      {
+	return rc;
+      }
+
+    for(int i=0; i<k; i++)
+    {
+        BIG_XXX_fromBytes(y[i],Y[i].val);
+        BIG_XXX_fromBytes(coefs[i],COEFS[i].val);
+        BIG_XXX_modmul(prod,y[i],coefs[i],r);
+        BIG_XXX_add(secret, secret, prod);
+
+        if (BIG_XXX_comp(secret,r) == 1)
+        {
+            BIG_XXX_sub(secret,secret,r);
+        }
+    }
+
+    // Output secret
+    BIG_XXX_toBytes(SK->val,secret);
+
+    return BLS_OK;
+}
+
+int BLS_ZZZ_RECOVER_SIGNATURE(int k, octet* X, octet* Y, octet* SIG)
+{
+    int rc = 0;
+    char product[k][BFS_ZZZ+1];
+    octet PRODUCT[k];
+
+    char coefs[k][BGS_ZZZ];
+    octet COEFS[k];
+    for(int i=0; i<k; i++)
+    {
+        memset(&coefs[i], 0, sizeof(coefs[i]));
+        COEFS[i].max = BGS_ZZZ;
+        COEFS[i].len = BGS_ZZZ;
+        COEFS[i].val = coefs[i];
+    }
+
+    rc = recover_coefficients(k, X, COEFS);
+    if (rc)
+      {
+	return rc;
+      }
+
+    
+    for(int i=0; i<k; i++)
+    {
+        memset(&product[i], 0, sizeof(product[i]));
+        PRODUCT[i].max = BFS_ZZZ+1;
+        PRODUCT[i].len = BFS_ZZZ+1;
+        PRODUCT[i].val = product[i];
+    }
+
+    for(int i=0; i<k; i++)
+    {
+        rc = BLS_ZZZ_MUL_G1(&COEFS[i], &Y[i], &PRODUCT[i]);
+        if (rc != BLS_OK)
+        {
+            return rc;
+        }
+    }
+
+    BLS_ZZZ_ADD_G1(&PRODUCT[0],&PRODUCT[1],SIG);
+    if (rc != BLS_OK)
+    {
+        return rc;
+    }
+
+    for(int i=2; i<k; i++)
+    {
+        BLS_ZZZ_ADD_G1(&PRODUCT[i],SIG,SIG);
+        if (rc != BLS_OK)
+        {
+            return rc;
+        }
+    }
+
+    return BLS_OK;
+}
+
+
diff --git a/src/bls256.c.in b/src/bls256.c.in
index 18a8ab2..8e3ca1e 100644
--- a/src/bls256.c.in
+++ b/src/bls256.c.in
@@ -25,6 +25,61 @@ under the License.
 #include <time.h>
 #include "bls256_ZZZ.h"
 
+// Polynomial interpolation coefficients
+static int recover_coefficients(int k, octet* X, octet* COEFS)
+{
+    BIG_XXX r;
+    BIG_XXX_rcopy(r,CURVE_Order_ZZZ);
+
+    BIG_XXX x2[k];
+    BIG_XXX coefs[k];
+
+    for(int i=0; i<k; i++)
+    {
+        BIG_XXX_fromBytes(x2[i],X[i].val);
+    }
+
+    for(int i=0; i<k; i++)
+    {
+        BIG_XXX numerator;
+        BIG_XXX_one(numerator);
+        BIG_XXX denominator;
+        BIG_XXX_one(denominator);
+        for(int j=0; j<k; j++)
+        {
+            // others = all - current
+            // current = x2[i]
+            if (i != j)
+            {
+                // numerator = numerator * other
+                BIG_XXX_modmul(numerator,numerator,x2[j],r);
+
+                // other - current
+                BIG_XXX s;
+                BIG_XXX c;
+
+                // c = -current
+                BIG_XXX_sub(c,r,x2[i]);
+                BIG_XXX_add(s,x2[j],c);
+
+                // denominator = denominator * s
+                BIG_XXX_modmul(denominator,denominator,s,r);
+
+            }
+
+        }
+        BIG_XXX_moddiv(coefs[i], numerator, denominator, r);
+    }
+
+    // Output coefficients
+    for(int i=0; i<k; i++)
+    {
+        BIG_XXX_toBytes(COEFS[i].val,coefs[i]);
+    }
+    return 0;
+
+}
+
 /* hash a message to an ECP point, using SHA3 */
 static void BLS_HASHIT(ECP_ZZZ *P,char *m)
 {
@@ -191,3 +246,164 @@ int BLS_ZZZ_MUL_G2(octet *P,octet *R,octet *T)
 
     return BLS_OK;
 }
+
+int BLS_ZZZ_MAKE_SHARES(int k, int n, csprng *RNG, octet* X, octet* Y, octet* SKI, octet* SKO)
+{
+    BIG_XXX y2[n];
+    BIG_XXX r;
+    BIG_XXX_rcopy(r,CURVE_Order_ZZZ);
+
+    // Generate polynomial: f(x) = a_0 + a_1x + a_2x^2 ... a_{k-1}x^{k-1}
+    BIG_XXX poly[k];
+    for(int i=0; i<k; i++)
+    {
+        BIG_XXX_randomnum(poly[i],r,RNG);
+    }
+
+    // Use predefined secret
+    if (SKI != NULL)
+    {
+        BIG_XXX_fromBytes(poly[0],SKI->val);
+    }
+
+    /* Calculate f(x) = a_0 + a_1x + a_2x^2 ... a_{k-1}x^{k-1}
+       a0 is the secret */
+    int x=0;
+    for(int j=0; j<n; j++)
+    {
+        x++;
+        BIG_XXX xb;
+        BIG_XXX_zero(y2[j]);
+        BIG_XXX_zero(xb);
+        BIG_XXX_inc(xb,x);
+
+        // Output X shares
+        BIG_XXX_toBytes(X[j].val,xb);
+
+        // y2[j] is the accmulator
+        for(int i=k-1; i>=0; i--)
+        {
+            BIG_XXX_modmul(y2[j],y2[j],xb,r);
+            BIG_XXX_add(y2[j],poly[i],y2[j]);
+        }
+    }
+
+    // Output Y shares
+    for(int j=0; j<n; j++)
+    {
+        BIG_XXX_toBytes(Y[j].val,y2[j]);
+    }
+
+    // Output secret
+    BIG_XXX_toBytes(SKO->val,poly[0]);
+
+    return BLS_OK;
+}
+
+int BLS_ZZZ_RECOVER_SECRET(int k, octet* X, octet* Y, octet* SK)
+{
+    int rc=0;
+    BIG_XXX r;
+    BIG_XXX_rcopy(r,CURVE_Order_ZZZ);
+
+    BIG_XXX y[k];
+    BIG_XXX coefs[k];
+
+    BIG_XXX secret;
+    BIG_XXX prod;
+    BIG_XXX_zero(secret);
+
+    char coefs2[k][BGS_ZZZ];
+    octet COEFS[k];
+    for(int i=0; i<k; i++)
+    {
+        memset(&coefs2[i], 0, sizeof(coefs2[i]));
+        COEFS[i].max = BGS_ZZZ;
+        COEFS[i].len = BGS_ZZZ;
+        COEFS[i].val = coefs2[i];
+    }
+
+    rc = recover_coefficients(k, X, COEFS);
+    if (rc)
+      {
+	return rc;
+      }
+
+    for(int i=0; i<k; i++)
+    {
+        BIG_XXX_fromBytes(y[i],Y[i].val);
+        BIG_XXX_fromBytes(coefs[i],COEFS[i].val);
+        BIG_XXX_modmul(prod,y[i],coefs[i],r);
+        BIG_XXX_add(secret, secret, prod);
+
+        if (BIG_XXX_comp(secret,r) == 1)
+        {
+            BIG_XXX_sub(secret,secret,r);
+        }
+    }
+
+    // Output secret
+    BIG_XXX_toBytes(SK->val,secret);
+
+    return BLS_OK;
+}
+
+int BLS_ZZZ_RECOVER_SIGNATURE(int k, octet* X, octet* Y, octet* SIG)
+{
+    int rc = 0;
+    char product[k][BFS_ZZZ+1];
+    octet PRODUCT[k];
+
+    char coefs[k][BGS_ZZZ];
+    octet COEFS[k];
+    for(int i=0; i<k; i++)
+    {
+        memset(&coefs[i], 0, sizeof(coefs[i]));
+        COEFS[i].max = BGS_ZZZ;
+        COEFS[i].len = BGS_ZZZ;
+        COEFS[i].val = coefs[i];
+    }
+
+    rc = recover_coefficients(k, X, COEFS);
+    if (rc)
+      {
+	return rc;
+      }
+
+    
+    for(int i=0; i<k; i++)
+    {
+        memset(&product[i], 0, sizeof(product[i]));
+        PRODUCT[i].max = BFS_ZZZ+1;
+        PRODUCT[i].len = BFS_ZZZ+1;
+        PRODUCT[i].val = product[i];
+    }
+
+    for(int i=0; i<k; i++)
+    {
+        rc = BLS_ZZZ_MUL_G1(&COEFS[i], &Y[i], &PRODUCT[i]);
+        if (rc != BLS_OK)
+        {
+            return rc;
+        }
+    }
+
+    BLS_ZZZ_ADD_G1(&PRODUCT[0],&PRODUCT[1],SIG);
+    if (rc != BLS_OK)
+    {
+        return rc;
+    }
+
+    for(int i=2; i<k; i++)
+    {
+        BLS_ZZZ_ADD_G1(&PRODUCT[i],SIG,SIG);
+        if (rc != BLS_OK)
+        {
+            return rc;
+        }
+    }
+
+    return BLS_OK;
+}
+
+
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 9636194..c350acc 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -209,6 +209,7 @@ foreach(curve ${AMCL_CURVE})
     ################################################
     if(BUILD_BLS)
       amcl_curve_test(${curve} test_bls_${TC} test_bls_ZZZ.c.in amcl_bls_${TC} "SUCCESS")
+      amcl_curve_test(${curve} test_bls_sss_${TC} test_bls_sss_ZZZ.c.in amcl_bls_${TC} "SUCCESS")      
     endif()
     
   endif()
diff --git a/test/test_bls_ZZZ.c.in b/test/test_bls_ZZZ.c.in
index 92c4154..6a85fa8 100644
--- a/test/test_bls_ZZZ.c.in
+++ b/test/test_bls_ZZZ.c.in
@@ -44,7 +44,7 @@
 
 static char message[]="test message";
 
-int bls(csprng *RNG)
+int test(csprng *RNG)
 {
     int rc;
 
@@ -278,8 +278,8 @@ int main()
     // initialise strong RNG
     CREATE_CSPRNG(&RNG,&SEED);
 
-    printf("\nTesting BLS signature for curve ZZZ\n");
-    if (!bls(&RNG))
+    printf("\nTest BLS for curve ZZZ\n");
+    if (!test(&RNG))
     {
         printf("SUCCESS\n");
     }
diff --git a/test/test_bls_sss_ZZZ.c.in b/test/test_bls_sss_ZZZ.c.in
new file mode 100644
index 0000000..d7c6fc1
--- /dev/null
+++ b/test/test_bls_sss_ZZZ.c.in
@@ -0,0 +1,243 @@
+/*
+    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.
+*/
+
+// smoke test for BLS SSS
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "config_curve_ZZZ.h"
+#include "randapi.h"
+
+#if CURVE_SECURITY_ZZZ == 128
+#include "bls_ZZZ.h"
+#elif CURVE_SECURITY_ZZZ == 192
+#include "bls192_ZZZ.h"
+#elif CURVE_SECURITY_ZZZ == 256
+#include "bls256_ZZZ.h"
+#endif
+
+// Support multiple security levels
+#if CURVE_SECURITY_ZZZ == 128
+#define G2LEN 4*BFS_ZZZ
+#elif CURVE_SECURITY_ZZZ == 192
+#define G2LEN 8*BFS_ZZZ
+#elif CURVE_SECURITY_ZZZ == 256
+#define G2LEN 16*BFS_ZZZ
+#endif
+
+static char message[]="test message";
+
+int test(csprng *RNG)
+{
+    int rc;
+    int n=4;
+    int k=3;
+
+    char ski[BGS_ZZZ];
+    octet SKI = {0,sizeof(ski),ski};
+    char pki[G2LEN];
+    octet PKI = {0,sizeof(pki),pki};
+
+    char sko[BGS_ZZZ];
+    octet SKO = {sizeof(sko),sizeof(sko),sko};
+    char skr[BGS_ZZZ];
+    octet SKR = {sizeof(skr),sizeof(skr),skr};
+
+    char sigi[BFS_ZZZ+1];
+    octet SIGI = {0,sizeof(sigi),sigi};
+    char sigr[BFS_ZZZ+1];
+    octet SIGR = {0,sizeof(sigr),sigr};
+
+    // Secret shares
+    char x[n][BGS_ZZZ];
+    octet X[n];
+    char y[n][BGS_ZZZ];
+    octet Y[n];
+    
+    for(int i=0; i<n; i++)
+    {
+        memset(&y[i], 0, sizeof(y[i]));
+        Y[i].max = BGS_ZZZ;
+        Y[i].len = BGS_ZZZ;
+        Y[i].val = y[i];
+        memset(&x[i], 0, sizeof(x[i]));
+        X[i].max = BGS_ZZZ;
+        X[i].len = BGS_ZZZ;
+        X[i].val = x[i];
+    }
+    
+    // Generate key pair
+    BLS_ZZZ_KEY_PAIR_GENERATE(RNG,&SKI,&PKI);
+
+    printf("Private key SKI: ");
+    OCT_output(&SKI);
+    printf("Public key PKI: ");
+    OCT_output(&PKI);
+    printf("\n");
+
+    // Sign the message
+    BLS_ZZZ_SIGN(&SIGI,message,&SKI);
+
+    printf("SIGI: ");
+    OCT_output(&SIGI);
+
+    // Verify signature
+    rc=BLS_ZZZ_VERIFY(&SIGI,message,&PKI);
+    if (rc!=BLS_OK)
+    {
+        printf("Test Failed Invalid Signature\n");
+	return 1;
+    }
+    printf("Test Passed valid signature is valid\n");
+
+    // Make shares of BLS secret key
+    rc = BLS_ZZZ_MAKE_SHARES(k, n, RNG, X, Y, &SKI, &SKO);
+    if (rc!=BLS_OK)
+    {
+        printf("Test Failed BLS_ZZZ_MAKE_SHARES\n");      
+	return 1;
+    }
+    printf("Test Passed BLS_ZZZ_MAKE_SHARES\n");    
+
+    for(int i=0; i<n; i++)
+    {
+        printf("X[%d] ", i);
+        OCT_output(&X[i]);
+        printf("Y[%d] ", i);
+        OCT_output(&Y[i]);
+    }
+    
+    printf("SKO: ");
+    OCT_output(&SKO);
+    
+    if (!OCT_comp(&SKI,&SKO))
+    {
+        printf("Test Failed SKI != SKO\n");      
+        return 1;
+    }
+    printf("Test Passed SKI == SKO\n");
+	
+    // Recover BLS secret key
+    rc = BLS_ZZZ_RECOVER_SECRET(k, X, Y, &SKR);
+    if (rc!=BLS_OK)
+    {
+        printf("Test Failed BLS_ZZZ_RECOVER_SECRET\n");
+	return 1;
+    }
+    printf("Test Passed BLS_ZZZ_RECOVER_SECRET\n");    
+    printf("SKR: ");
+    OCT_output(&SKR);
+    
+    if (!OCT_comp(&SKR,&SKO))
+    {
+        printf("Test Failed SKR != SKO\n");            
+        return 1;
+    }
+    printf("Test Passed SKR == SKO\n");
+    
+    // Generate public keys and signatures using shares
+    char pks[n][G2LEN];
+    octet PKS[n];
+    char sigs[n][BFS_ZZZ+1];
+    octet SIGS[n];
+    for(int i=0; i<n; i++)
+    {
+        memset(&sigs[i], 0, sizeof(sigs[i]));
+        SIGS[i].max = BFS_ZZZ+1;
+        SIGS[i].len = BFS_ZZZ+1;
+        SIGS[i].val = sigs[i];
+        memset(&PKS[i], 0, sizeof(PKS[i]));
+        PKS[i].max = G2LEN;
+        PKS[i].len = G2LEN;
+        PKS[i].val = pks[i];
+        BLS_ZZZ_KEY_PAIR_GENERATE(NULL,&Y[i],&PKS[i]);
+        BLS_ZZZ_SIGN(&SIGS[i],message,&Y[i]);
+    }
+
+    for(int i=0; i<n; i++)
+    {
+        printf("PKS[%d] ", i);
+        OCT_output(&PKS[i]);
+    }
+
+    for(int i=0; i<n; i++)
+    {
+        printf("SIGS[%d] ", i);
+        OCT_output(&SIGS[i]);
+    }
+    printf("\n\n");
+
+    // Recover BLS signature
+    rc = BLS_ZZZ_RECOVER_SIGNATURE(k, X, SIGS, &SIGR);
+    if (rc!=BLS_OK)
+    {
+        printf("Test Failed BLS_ZZZ_RECOVER_SIGNATURE\n");
+	return 1;
+    }
+    printf("Test Passed BLS_ZZZ_RECOVER_SIGNATURE\n");    
+    printf("SIGR: ");
+    OCT_output(&SIGR);
+    
+    if (!OCT_comp(&SIGR,&SIGI))
+    {
+        printf("Test Failed SIGR != SIGI\n");            
+        return 1;
+    }
+    printf("Test Passed SIGR == SIGI\n");
+    
+    return 0;
+}
+
+
+int main()
+{
+#ifdef DEBUG
+    printf("%d bit build\n",CHUNK);
+#endif
+
+    char* seedHex = "78d0fb6705ce77dee47d03eb5b9c5d30";
+    char seed[16] = {0};
+    octet SEED = {sizeof(seed),sizeof(seed),seed};
+
+    // CSPRNG
+    csprng RNG;
+
+    // fake random source
+    OCT_fromHex(&SEED,seedHex);
+    printf("SEED: ");
+    OCT_output(&SEED);
+
+    // initialise strong RNG
+    CREATE_CSPRNG(&RNG,&SEED);
+
+    printf("\nTest BLS SSS for curve ZZZ\n");
+    if (!test(&RNG))
+    {
+        printf("SUCCESS\n");
+    }
+    else
+    {
+        printf("FAILURE\n");
+    }
+
+    KILL_CSPRNG(&RNG);
+}
+
+