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/01 14:05:26 UTC

[incubator-milagro-crypto-c] 01/01: add bls wrapper

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

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

commit 1efd0962cde9acc0797adc37df6e821e11e7e421
Author: Kealan McCusker <ke...@gmail.com>
AuthorDate: Thu Aug 1 15:04:52 2019 +0100

    add bls wrapper
---
 CPackConfig.cmake                         |   2 +
 cmake/PythonSiteDirs.cmake                |  11 +
 wrappers/python/CMakeLists.txt            |   5 +
 wrappers/python/README.md                 |   5 +-
 wrappers/python/TestMPINInstall_ZZZ.py.in |  49 ++--
 wrappers/python/TestMPIN_BN254CX.py       | 140 ---------
 wrappers/python/TimeMPIN_ZZZ.py.in        |  58 ++--
 wrappers/python/bls_ZZZ.py.in             | 469 ++++++++++++++++++++++++++++++
 wrappers/python/mpin_ZZZ.py.in            |  78 ++---
 wrappers/python/wcc_ZZZ.py.in             |  85 +++---
 10 files changed, 631 insertions(+), 271 deletions(-)

diff --git a/CPackConfig.cmake b/CPackConfig.cmake
index f46fc79..fd584ae 100644
--- a/CPackConfig.cmake
+++ b/CPackConfig.cmake
@@ -44,6 +44,8 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
   list(APPEND CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "${CPACK_PACKAGING_INSTALL_PREFIX}/lib")
   list(APPEND CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "${PYTHON_SITE_LIB}")
   list(APPEND CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "${PYTHON_SITE_PACKAGES}")
+  list(APPEND CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "${PYTHON3_SITE_LIB}")
+  list(APPEND CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "${PYTHON3_SITE_PACKAGES}")  
   set(CPACK_GENERATOR "RPM")
 endif()
 
diff --git a/cmake/PythonSiteDirs.cmake b/cmake/PythonSiteDirs.cmake
index ea57c06..bf0f968 100644
--- a/cmake/PythonSiteDirs.cmake
+++ b/cmake/PythonSiteDirs.cmake
@@ -27,3 +27,14 @@ execute_process(COMMAND
   python -c "from distutils.sysconfig import get_python_lib; from os.path import dirname; print dirname(get_python_lib())"
   OUTPUT_VARIABLE PYTHON_SITE_LIB
 )
+
+execute_process(COMMAND
+  python3 -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())"
+  OUTPUT_VARIABLE PYTHON3_SITE_PACKAGES
+  OUTPUT_STRIP_TRAILING_WHITESPACE
+)
+
+execute_process(COMMAND
+  python3 -c "from distutils.sysconfig import get_python_lib; from os.path import dirname; print(dirname(get_python_lib()))"
+  OUTPUT_VARIABLE PYTHON3_SITE_LIB
+)
diff --git a/wrappers/python/CMakeLists.txt b/wrappers/python/CMakeLists.txt
index 8063948..a0a7961 100644
--- a/wrappers/python/CMakeLists.txt
+++ b/wrappers/python/CMakeLists.txt
@@ -50,5 +50,10 @@ foreach(curve ${AMCL_CURVE})
     amcl_configure_file_curve(wcc_ZZZ.py.in wcc_${TC}.py ${curve} amcl_wcc_${TC}_GEN_PYS)
     install(FILES "${amcl_wcc_${TC}_GEN_PYS}" DESTINATION ${PYTHON_SITE_PACKAGES})
   endif()
+
+  if(TARGET amcl_bls_${TC})
+    amcl_configure_file_curve(bls_ZZZ.py.in bls_${TC}.py ${curve} amcl_bls_${TC}_GEN_PYS)
+    install(FILES "${amcl_bls_${TC}_GEN_PYS}" DESTINATION ${PYTHON3_SITE_PACKAGES})
+  endif()
   
 endforeach()
diff --git a/wrappers/python/README.md b/wrappers/python/README.md
index 16688af..a65806e 100644
--- a/wrappers/python/README.md
+++ b/wrappers/python/README.md
@@ -3,5 +3,6 @@ interacts with the c code using CFFI.
 
 To run all MPIN tests
 
-    ./TestMPINInstall.py -v
-
+```
+./TestMPINInstall.py -v
+```
diff --git a/wrappers/python/TestMPINInstall_ZZZ.py.in b/wrappers/python/TestMPINInstall_ZZZ.py.in
index 28f3a1b..1b46807 100644
--- a/wrappers/python/TestMPINInstall_ZZZ.py.in
+++ b/wrappers/python/TestMPINInstall_ZZZ.py.in
@@ -24,9 +24,6 @@ import json
 import hashlib
 import mpin_ZZZ
 
-HASH_TYPE_MPIN_ZZZ = mpin_ZZZ.SHA256
-
-
 class TestMPIN(unittest.TestCase):
     """Tests M-Pin crypto code"""
 
@@ -42,7 +39,7 @@ class TestMPIN(unittest.TestCase):
         self.mpin_id = json.dumps(endUserData)
 
         # Hash value of MPIN_ID
-        self.hash_mpin_id = mpin_ZZZ.hash_id(HASH_TYPE_MPIN_ZZZ, self.mpin_id)
+        self.hash_mpin_id = mpin_ZZZ.hash_id(mpin_ZZZ.HASH_TYPE_ZZZ, self.mpin_id)
 
         # Assign a seed value
         seedHex = "3ade3d4a5c698e8910bf92f25d97ceeb7c25ed838901a5cb5db2cf25434c1fe76c7f79b7af2e5e1e4988e4294dbd9bd9fa3960197fb7aec373609fb890d74b16a4b14b2ae7e23b75f15d36c21791272372863c4f8af39980283ae69a79cf4e48e908f9e0"
@@ -86,10 +83,10 @@ class TestMPIN(unittest.TestCase):
 
         # Generate Time Permit shares
         rtn, tp1 = mpin_ZZZ.get_client_permit(
-            HASH_TYPE_MPIN_ZZZ, self.date, ms1, self.hash_mpin_id)
+            mpin_ZZZ.HASH_TYPE_ZZZ, self.date, ms1, self.hash_mpin_id)
         self.assertEqual(rtn, 0)
         rtn, tp2 = mpin_ZZZ.get_client_permit(
-            HASH_TYPE_MPIN_ZZZ, self.date, ms2, self.hash_mpin_id)
+            mpin_ZZZ.HASH_TYPE_ZZZ, self.date, ms2, self.hash_mpin_id)
         self.assertEqual(rtn, 0)
 
         # Combine Time Permit shares
@@ -98,17 +95,17 @@ class TestMPIN(unittest.TestCase):
 
         # Client extracts PIN from secret to create Token
         rtn, token = mpin_ZZZ.extract_pin(
-            HASH_TYPE_MPIN_ZZZ, self.mpin_id, PIN1, client_secret)
+            mpin_ZZZ.HASH_TYPE_ZZZ, self.mpin_id, PIN1, client_secret)
         self.assertEqual(rtn, 0)
 
         # Client first pass
         rtn, x, u, ut, sec = mpin_ZZZ.client_1(
-            HASH_TYPE_MPIN_ZZZ, self.date, self.mpin_id, rng, None, PIN2, token, time_permit)
+            mpin_ZZZ.HASH_TYPE_ZZZ, self.date, self.mpin_id, rng, None, PIN2, token, time_permit)
         self.assertEqual(rtn, 0)
 
         # Server calculates H(ID) and H(T|H(ID))
         HID, HTID = mpin_ZZZ.server_1(
-            HASH_TYPE_MPIN_ZZZ, self.date, self.mpin_id)
+            mpin_ZZZ.HASH_TYPE_ZZZ, self.date, self.mpin_id)
 
         # Server generates Random number Y and sends it to Client
         rtn, y = mpin_ZZZ.random_generate(rng)
@@ -159,10 +156,10 @@ class TestMPIN(unittest.TestCase):
 
         # Generate Time Permit shares
         rtn, tp1 = mpin_ZZZ.get_client_permit(
-            HASH_TYPE_MPIN_ZZZ, self.date, ms1, self.hash_mpin_id)
+            mpin_ZZZ.HASH_TYPE_ZZZ, self.date, ms1, self.hash_mpin_id)
         self.assertEqual(rtn, 0)
         rtn, tp2 = mpin_ZZZ.get_client_permit(
-            HASH_TYPE_MPIN_ZZZ, self.date, ms2, self.hash_mpin_id)
+            mpin_ZZZ.HASH_TYPE_ZZZ, self.date, ms2, self.hash_mpin_id)
         self.assertEqual(rtn, 0)
 
         # Combine Time Permit shares
@@ -171,17 +168,17 @@ class TestMPIN(unittest.TestCase):
 
         # Client extracts PIN from secret to create Token
         rtn, token = mpin_ZZZ.extract_pin(
-            HASH_TYPE_MPIN_ZZZ, self.mpin_id, PIN1, client_secret)
+            mpin_ZZZ.HASH_TYPE_ZZZ, self.mpin_id, PIN1, client_secret)
         self.assertEqual(rtn, 0)
 
         # Client first pass
         rtn, x, u, ut, sec = mpin_ZZZ.client_1(
-            HASH_TYPE_MPIN_ZZZ, self.date, self.mpin_id, rng, None, PIN2, token, time_permit)
+            mpin_ZZZ.HASH_TYPE_ZZZ, self.date, self.mpin_id, rng, None, PIN2, token, time_permit)
         self.assertEqual(rtn, 0)
 
         # Server calculates H(ID) and H(T|H(ID))
         HID, HTID = mpin_ZZZ.server_1(
-            HASH_TYPE_MPIN_ZZZ, self.date, self.mpin_id)
+            mpin_ZZZ.HASH_TYPE_ZZZ, self.date, self.mpin_id)
 
         # Server generates Random number Y and sends it to Client
         rtn, y = mpin_ZZZ.random_generate(rng)
@@ -232,10 +229,10 @@ class TestMPIN(unittest.TestCase):
 
         # Generate Time Permit shares
         rtn, tp1 = mpin_ZZZ.get_client_permit(
-            HASH_TYPE_MPIN_ZZZ, self.date, ms1, self.hash_mpin_id)
+            mpin_ZZZ.HASH_TYPE_ZZZ, self.date, ms1, self.hash_mpin_id)
         self.assertEqual(rtn, 0)
         rtn, tp2 = mpin_ZZZ.get_client_permit(
-            HASH_TYPE_MPIN_ZZZ, self.date, ms2, self.hash_mpin_id)
+            mpin_ZZZ.HASH_TYPE_ZZZ, self.date, ms2, self.hash_mpin_id)
         self.assertEqual(rtn, 0)
 
         # Combine Time Permit shares
@@ -244,17 +241,17 @@ class TestMPIN(unittest.TestCase):
 
         # Client extracts PIN from secret to create Token
         rtn, token = mpin_ZZZ.extract_pin(
-            HASH_TYPE_MPIN_ZZZ, self.mpin_id, PIN1, client_secret)
+            mpin_ZZZ.HASH_TYPE_ZZZ, self.mpin_id, PIN1, client_secret)
         self.assertEqual(rtn, 0)
 
         # Client first pass
         rtn, x, u, ut, sec = mpin_ZZZ.client_1(
-            HASH_TYPE_MPIN_ZZZ, self.date, self.mpin_id, rng, None, PIN2, token, time_permit)
+            mpin_ZZZ.HASH_TYPE_ZZZ, self.date, self.mpin_id, rng, None, PIN2, token, time_permit)
         self.assertEqual(rtn, 0)
 
         # Server calculates H(ID) and H(T|H(ID))
         HID, HTID = mpin_ZZZ.server_1(
-            HASH_TYPE_MPIN_ZZZ, self.date, self.mpin_id)
+            mpin_ZZZ.HASH_TYPE_ZZZ, self.date, self.mpin_id)
 
         # Server generates Random number Y and sends it to Client
         rtn, y = mpin_ZZZ.random_generate(rng)
@@ -283,7 +280,7 @@ class TestMPIN(unittest.TestCase):
         match = 0
         for i in range(1, 1000):
             rand_val = os.urandom(32)
-            hash_mpin_id = mpin_ZZZ.hash_id(HASH_TYPE_MPIN_ZZZ, rand_val)
+            hash_mpin_id = mpin_ZZZ.hash_id(mpin_ZZZ.HASH_TYPE_ZZZ, rand_val)
 
             # Generate client secret shares
             rtn, cs1 = mpin_ZZZ.get_client_secret(ms1, hash_mpin_id)
@@ -329,8 +326,8 @@ class TestMPIN(unittest.TestCase):
     def test_7(self):
         """test_7 AES-GCM: Successful encryption and decryption"""
 
-        # Generate 16 byte key
-        key = os.urandom(mpin_ZZZ.PAS)
+        # Generate key
+        key = os.urandom(mpin_ZZZ.AESKEY_ZZZ)
 
         # Generate 12 byte IV
         iv = os.urandom(mpin_ZZZ.IVL)
@@ -353,8 +350,8 @@ class TestMPIN(unittest.TestCase):
     def test_8(self):
         """test_8 AES-GCM: Failed encryption and decryption by changing a ciphertext byte"""
 
-        # Generate 16 byte key
-        key = os.urandom(mpin_ZZZ.PAS)
+        # Generate key
+        key = os.urandom(mpin_ZZZ.AESKEY_ZZZ)
 
         # Generate 12 byte IV
         iv = os.urandom(mpin_ZZZ.IVL)
@@ -381,8 +378,8 @@ class TestMPIN(unittest.TestCase):
     def test_9(self):
         """test_9 AES-GCM: Failed encryption and decryption by changing a header byte"""
 
-        # Generate 16 byte key
-        key = os.urandom(mpin_ZZZ.PAS)
+        # Generate key
+        key = os.urandom(mpin_ZZZ.AESKEY_ZZZ)
 
         # Generate 12 byte IV
         iv = os.urandom(mpin_ZZZ.IVL)
diff --git a/wrappers/python/TestMPIN_BN254CX.py b/wrappers/python/TestMPIN_BN254CX.py
deleted file mode 100644
index 1939704..0000000
--- a/wrappers/python/TestMPIN_BN254CX.py
+++ /dev/null
@@ -1,140 +0,0 @@
-#!/usr/bin/env python
-
-"""
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements.  See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership.  The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License.  You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied.  See the License for the
-specific language governing permissions and limitations
-under the License.
-"""
-import unittest
-import json
-import mpin_BN254CX
-
-HASH_TYPE_MPIN_ZZZ = mpin_BN254CX.SHA256
-
-
-class TestMPIN(unittest.TestCase):
-    """Tests M-Pin crypto code"""
-
-    def setUp(self):
-        pass
-
-    def test_1(self):
-        """test_1 Test Vector test"""
-        vectors = json.load(open("./MPINTestVectors.json", "r"))
-        for vector in vectors:
-            print "Test vector {}".format(vector['test_no'])
-
-            PIN1 = vector['PIN1']
-            PIN2 = vector['PIN2']
-            date = vector['DATE']
-
-            MS1_HEX = vector['MS1']
-            MS2_HEX = vector['MS2']
-
-            ms1 = MS1_HEX.decode("hex")
-            ms2 = MS2_HEX.decode("hex")
-
-            # Generate server secret shares
-            rtn, ss1 = mpin_BN254CX.get_server_secret(ms1)
-            self.assertEqual(rtn, 0)
-            self.assertEqual(vector['SS1'], ss1.encode("hex"))
-            rtn, ss2 = mpin_BN254CX.get_server_secret(ms2)
-            self.assertEqual(rtn, 0)
-            self.assertEqual(vector['SS2'], ss2.encode("hex"))
-
-            # Combine server secret shares
-            rtn, server_secret = mpin_BN254CX.recombine_G2(ss1, ss2)
-            self.assertEqual(rtn, 0)
-            self.assertEqual(
-                vector['SERVER_SECRET'],
-                server_secret.encode("hex"))
-
-            mpin_id = vector['MPIN_ID_HEX'].decode("hex")
-
-            # Hash value of MPIN_ID
-            hash_mpin_id = mpin_BN254CX.hash_id(HASH_TYPE_MPIN_ZZZ, mpin_id)
-            self.assertEqual(
-                vector['HASH_MPIN_ID_HEX'],
-                hash_mpin_id.encode("hex"))
-
-            # Generate client secret shares
-            rtn, cs1 = mpin_BN254CX.get_client_secret(ms1, hash_mpin_id)
-            self.assertEqual(rtn, 0)
-            self.assertEqual(vector['CS1'], cs1.encode("hex"))
-            rtn, cs2 = mpin_BN254CX.get_client_secret(ms2, hash_mpin_id)
-            self.assertEqual(rtn, 0)
-            self.assertEqual(vector['CS2'], cs2.encode("hex"))
-
-            # Combine client secret shares : TOKEN is the full client secret
-            rtn, client_secret = mpin_BN254CX.recombine_G1(cs1, cs2)
-            self.assertEqual(rtn, 0)
-            self.assertEqual(
-                vector['CLIENT_SECRET'],
-                client_secret.encode("hex"))
-
-            # Generate Time Permit shares
-            rtn, tp1 = mpin_BN254CX.get_client_permit(
-                HASH_TYPE_MPIN_ZZZ, date, ms1, hash_mpin_id)
-            self.assertEqual(rtn, 0)
-            self.assertEqual(vector['TP1'], tp1.encode("hex"))
-            rtn, tp2 = mpin_BN254CX.get_client_permit(
-                HASH_TYPE_MPIN_ZZZ, date, ms2, hash_mpin_id)
-            self.assertEqual(rtn, 0)
-            self.assertEqual(vector['TP2'], tp2.encode("hex"))
-
-            # Combine Time Permit shares
-            rtn, time_permit = mpin_BN254CX.recombine_G1(tp1, tp2)
-            self.assertEqual(rtn, 0)
-            self.assertEqual(vector['TIME_PERMIT'], time_permit.encode("hex"))
-
-            # Client extracts PIN from secret to create Token
-            rtn, token = mpin_BN254CX.extract_pin(
-                HASH_TYPE_MPIN_ZZZ, mpin_id, PIN1, client_secret)
-            self.assertEqual(rtn, 0)
-            self.assertEqual(vector['TOKEN'], token.encode("hex"))
-
-            x = vector['X'].decode("hex")
-
-            # Client first pass. Use X value from test vectors
-            rtn, x, u, ut, sec = mpin_BN254CX.client_1(
-                HASH_TYPE_MPIN_ZZZ, date, mpin_id, None, x, PIN2, token, time_permit)
-            self.assertEqual(rtn, 0)
-            self.assertEqual(vector['X'], x.encode("hex"))
-            self.assertEqual(vector['U'], u.encode("hex"))
-            self.assertEqual(vector['UT'], ut.encode("hex"))
-            self.assertEqual(vector['SEC'], sec.encode("hex"))
-
-            # Server calculates H(ID) and H(T|H(ID))
-            HID, HTID = mpin_BN254CX.server_1(
-                HASH_TYPE_MPIN_ZZZ, date, mpin_id)
-
-            # Use Y value from test vectors
-            y = vector['Y'].decode("hex")
-
-            # Client second pass
-            rtn, v = mpin_BN254CX.client_2(x, y, sec)
-            self.assertEqual(rtn, 0)
-            self.assertEqual(vector['V'], v.encode("hex"))
-
-            # Server second pass
-            rtn, E, F = mpin_BN254CX.server_2(
-                date, HID, HTID, y, server_secret, u, ut, v, None)
-            self.assertEqual(rtn, vector['SERVER_OUTPUT'])
-
-
-if __name__ == '__main__':
-    # Run tests
-    unittest.main()
diff --git a/wrappers/python/TimeMPIN_ZZZ.py.in b/wrappers/python/TimeMPIN_ZZZ.py.in
index 548a4bc..8305fb0 100755
--- a/wrappers/python/TimeMPIN_ZZZ.py.in
+++ b/wrappers/python/TimeMPIN_ZZZ.py.in
@@ -38,8 +38,6 @@ def time_func(stmt, n=10, setup='from __main__ import *'):
 
 nIter = 100
 
-HASH_TYPE_MPIN_ZZZ = mpin_ZZZ.SHA256
-
 if __name__ == "__main__":
     # Print hex values
     DEBUG = False
@@ -65,7 +63,7 @@ if __name__ == "__main__":
     mpin_id = "alice@milagro.com"
 
     # Hash mpin_id
-    hash_mpin_id = mpin_ZZZ.hash_id(HASH_TYPE_MPIN_ZZZ, mpin_id)
+    hash_mpin_id = mpin_ZZZ.hash_id(mpin_ZZZ.HASH_TYPE_ZZZ, mpin_id)
     if DEBUG:
         print "mpin_id: %s" % mpin_id.encode("hex")
         print "hash_mpin_id: %s" % hash_mpin_id.encode("hex")
@@ -127,16 +125,16 @@ if __name__ == "__main__":
     if DEBUG:
         print "Date %s" % date
     time_func(
-        'rtn, tp1 = mpin_ZZZ.get_client_permit(HASH_TYPE_MPIN_ZZZ, date, ms1, hash_mpin_id)',
+        'rtn, tp1 = mpin_ZZZ.get_client_permit(mpin_ZZZ.HASH_TYPE_ZZZ, date, ms1, hash_mpin_id)',
         nIter)
     rtn, tp1 = mpin_ZZZ.get_client_permit(
-        HASH_TYPE_MPIN_ZZZ, date, ms1, hash_mpin_id)
+        mpin_ZZZ.HASH_TYPE_ZZZ, date, ms1, hash_mpin_id)
     if rtn != 0:
-        print "get_client_permit(HASH_TYPE_MPIN_ZZZ, date, ms1, hash_mpin_id) Error %s" % rtn
+        print "get_client_permit(mpin_ZZZ.HASH_TYPE_ZZZ, date, ms1, hash_mpin_id) Error %s" % rtn
     rtn, tp2 = mpin_ZZZ.get_client_permit(
-        HASH_TYPE_MPIN_ZZZ, date, ms2, hash_mpin_id)
+        mpin_ZZZ.HASH_TYPE_ZZZ, date, ms2, hash_mpin_id)
     if rtn != 0:
-        print "get_client_permit(HASH_TYPE_MPIN_ZZZ, date, ms2, hash_mpin_id) Error %s" % rtn
+        print "get_client_permit(mpin_ZZZ.HASH_TYPE_ZZZ, date, ms2, hash_mpin_id) Error %s" % rtn
     if DEBUG:
         print "tp1: %s" % tp1.encode("hex")
         print "tp2: %s" % tp2.encode("hex")
@@ -151,12 +149,12 @@ if __name__ == "__main__":
     # Client extracts PIN from secret to create Token
     PIN = 1234
     time_func(
-        'rtn, token = mpin_ZZZ.extract_pin(HASH_TYPE_MPIN_ZZZ, mpin_id, PIN, client_secret)',
+        'rtn, token = mpin_ZZZ.extract_pin(mpin_ZZZ.HASH_TYPE_ZZZ, mpin_id, PIN, client_secret)',
         nIter)
     rtn, token = mpin_ZZZ.extract_pin(
-        HASH_TYPE_MPIN_ZZZ, mpin_id, PIN, client_secret)
+        mpin_ZZZ.HASH_TYPE_ZZZ, mpin_id, PIN, client_secret)
     if rtn != 0:
-        print "extract_pin(HASH_TYPE_MPIN_ZZZ, mpin_id, PIN, token) Error %s" % rtn
+        print "extract_pin(mpin_ZZZ.HASH_TYPE_ZZZ, mpin_id, PIN, token) Error %s" % rtn
     print "Token: %s" % token.encode("hex")
 
     if ONE_PASS:
@@ -176,10 +174,10 @@ if __name__ == "__main__":
 
         # Client MPIN
         time_func(
-            'rtn, x, u, ut, v, y = mpin_ZZZ.client(HASH_TYPE_MPIN_ZZZ, date, mpin_id, rng, None, PIN, token, time_permit, None, epoch_time)',
+            'rtn, x, u, ut, v, y = mpin_ZZZ.client(mpin_ZZZ.HASH_TYPE_ZZZ, date, mpin_id, rng, None, PIN, token, time_permit, None, epoch_time)',
             nIter)
         rtn, x, u, ut, v, y = mpin_ZZZ.client(
-            HASH_TYPE_MPIN_ZZZ, date, mpin_id, rng, None, PIN, token, time_permit, None, epoch_time)
+            mpin_ZZZ.HASH_TYPE_ZZZ, date, mpin_id, rng, None, PIN, token, time_permit, None, epoch_time)
         if rtn != 0:
             print "MPIN_CLIENT ERROR %s" % rtn
 
@@ -192,10 +190,10 @@ if __name__ == "__main__":
 
         # Server MPIN
         time_func(
-            'rtn, HID, HTID, E, F, y2 = mpin_ZZZ.server(HASH_TYPE_MPIN_ZZZ, date, server_secret, u, ut, v, mpin_id, None, epoch_time, None)',
+            'rtn, HID, HTID, E, F, y2 = mpin_ZZZ.server(mpin_ZZZ.HASH_TYPE_ZZZ, date, server_secret, u, ut, v, mpin_id, None, epoch_time, None)',
             nIter)
         rtn, HID, HTID, E, F, y2 = mpin_ZZZ.server(
-            HASH_TYPE_MPIN_ZZZ, date, server_secret, u, ut, v, mpin_id, None, epoch_time, None)
+            mpin_ZZZ.HASH_TYPE_ZZZ, date, server_secret, u, ut, v, mpin_id, None, epoch_time, None)
         if DEBUG:
             print "y2 ", y2.encode("hex")
         if rtn != 0:
@@ -225,22 +223,22 @@ if __name__ == "__main__":
 
         if MPIN_FULL:
             time_func(
-                'HM = mpin_ZZZ.hash_all(HASH_TYPE_MPIN_ZZZ, hash_mpin_id, u, ut, v, y, Z, T)',
+                'HM = mpin_ZZZ.hash_all(mpin_ZZZ.HASH_TYPE_ZZZ, hash_mpin_id, u, ut, v, y, Z, T)',
                 nIter)
             HM = mpin_ZZZ.hash_all(
-                HASH_TYPE_MPIN_ZZZ, hash_mpin_id, u, ut, v, y, Z, T)
+                mpin_ZZZ.HASH_TYPE_ZZZ, hash_mpin_id, u, ut, v, y, Z, T)
 
             time_func(
-                'rtn, client_aes_key = mpin_ZZZ.client_key(HASH_TYPE_MPIN_ZZZ, pc1, pc2, PIN, r, x, HM, T)',
+                'rtn, client_aes_key = mpin_ZZZ.client_key(mpin_ZZZ.HASH_TYPE_ZZZ, pc1, pc2, PIN, r, x, HM, T)',
                 nIter)
             rtn, client_aes_key = mpin_ZZZ.client_key(
-                HASH_TYPE_MPIN_ZZZ, pc1, pc2, PIN, r, x, HM, T)
+                mpin_ZZZ.HASH_TYPE_ZZZ, pc1, pc2, PIN, r, x, HM, T)
             if rtn != 0:
                 print "ERROR: Generating client_aes_key %s" % rtn
             print "Client AES Key: %s" % client_aes_key.encode("hex")
 
             rtn, server_aes_key = mpin_ZZZ.server_key(
-                HASH_TYPE_MPIN_ZZZ, Z, server_secret, w, HM, HID, u, ut)
+                mpin_ZZZ.HASH_TYPE_ZZZ, Z, server_secret, w, HM, HID, u, ut)
             if rtn != 0:
                 print "ERROR: Generating server_aes_key %s" % rtn
             print "Server AES Key: %s" % server_aes_key.encode("hex")
@@ -258,10 +256,10 @@ if __name__ == "__main__":
 
         # Client first pass
         time_func(
-            'rtn, x, u, ut, sec = mpin_ZZZ.client_1(HASH_TYPE_MPIN_ZZZ, date, mpin_id, rng, None, PIN, token, time_permit)',
+            'rtn, x, u, ut, sec = mpin_ZZZ.client_1(mpin_ZZZ.HASH_TYPE_ZZZ, date, mpin_id, rng, None, PIN, token, time_permit)',
             nIter)
         rtn, x, u, ut, sec = mpin_ZZZ.client_1(
-            HASH_TYPE_MPIN_ZZZ, date, mpin_id, rng, None, PIN, token, time_permit)
+            mpin_ZZZ.HASH_TYPE_ZZZ, date, mpin_id, rng, None, PIN, token, time_permit)
         if rtn != 0:
             print "client_1  ERROR %s" % rtn
         if DEBUG:
@@ -270,9 +268,9 @@ if __name__ == "__main__":
         # Server calculates H(ID) and H(T|H(ID)) (if time permits enabled),
         # and maps them to points on the curve HID and HTID resp.
         time_func(
-            'HID, HTID = mpin_ZZZ.server_1(HASH_TYPE_MPIN_ZZZ, date, mpin_id)',
+            'HID, HTID = mpin_ZZZ.server_1(mpin_ZZZ.HASH_TYPE_ZZZ, date, mpin_id)',
             nIter)
-        HID, HTID = mpin_ZZZ.server_1(HASH_TYPE_MPIN_ZZZ, date, mpin_id)
+        HID, HTID = mpin_ZZZ.server_1(mpin_ZZZ.HASH_TYPE_ZZZ, date, mpin_id)
 
         # Server generates Random number y and sends it to Client
         time_func('rtn, y = mpin_ZZZ.random_generate(rng)', nIter)
@@ -324,25 +322,25 @@ if __name__ == "__main__":
                 print "ERROR: Generating T %s" % rtn
 
             time_func(
-                'HM = mpin_ZZZ.hash_all(HASH_TYPE_MPIN_ZZZ, hash_mpin_id, u, ut, v, y, Z, T)',
+                'HM = mpin_ZZZ.hash_all(mpin_ZZZ.HASH_TYPE_ZZZ, hash_mpin_id, u, ut, v, y, Z, T)',
                 nIter)
             HM = mpin_ZZZ.hash_all(
-                HASH_TYPE_MPIN_ZZZ, hash_mpin_id, u, ut, v, y, Z, T)
+                mpin_ZZZ.HASH_TYPE_ZZZ, hash_mpin_id, u, ut, v, y, Z, T)
 
             time_func(
-                'rtn, client_aes_key = mpin_ZZZ.client_key(HASH_TYPE_MPIN_ZZZ, pc1, pc2, PIN, r, x, HM, T)',
+                'rtn, client_aes_key = mpin_ZZZ.client_key(mpin_ZZZ.HASH_TYPE_ZZZ, pc1, pc2, PIN, r, x, HM, T)',
                 nIter)
             rtn, client_aes_key = mpin_ZZZ.client_key(
-                HASH_TYPE_MPIN_ZZZ, pc1, pc2, PIN, r, x, HM, T)
+                mpin_ZZZ.HASH_TYPE_ZZZ, pc1, pc2, PIN, r, x, HM, T)
             if rtn != 0:
                 print "ERROR: Generating client_aes_key %s" % rtn
             print "Client AES Key: %s" % client_aes_key.encode("hex")
 
             time_func(
-                'rtn, server_aes_key = mpin_ZZZ.server_key(HASH_TYPE_MPIN_ZZZ, Z, server_secret, w, HM, HID, u, ut)',
+                'rtn, server_aes_key = mpin_ZZZ.server_key(mpin_ZZZ.HASH_TYPE_ZZZ, Z, server_secret, w, HM, HID, u, ut)',
                 nIter)
             rtn, server_aes_key = mpin_ZZZ.server_key(
-                HASH_TYPE_MPIN_ZZZ, Z, server_secret, w, HM, HID, u, ut)
+                mpin_ZZZ.HASH_TYPE_ZZZ, Z, server_secret, w, HM, HID, u, ut)
             if rtn != 0:
                 print "ERROR: Generating server_aes_key %s" % rtn
             print "Server AES Key: %s" % server_aes_key.encode("hex")
diff --git a/wrappers/python/bls_ZZZ.py.in b/wrappers/python/bls_ZZZ.py.in
new file mode 100755
index 0000000..2f78793
--- /dev/null
+++ b/wrappers/python/bls_ZZZ.py.in
@@ -0,0 +1,469 @@
+#!/usr/bin/env python3
+
+"""
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+"""
+
+
+"""
+bls
+
+This module use cffi to access the c functions in the BLS library.
+
+There is also an example usage program in this file.
+
+"""
+import cffi
+import platform
+import os
+
+ffi = cffi.FFI()
+ffi.cdef("""
+typedef struct {
+unsigned int ira[21];  /* random number...   */
+int rndptr;   /* ...array & pointer */
+unsigned int borrow;
+int pool_ptr;
+char pool[32];    /* random pool */
+} csprng;
+
+typedef struct
+{
+  int len;
+  int max;
+  char *val;
+} octet;
+
+extern void CREATE_CSPRNG(csprng *R,octet *S);
+extern void KILL_CSPRNG(csprng *R);
+extern void OCT_clear(octet *O);
+
+extern int BLS_ZZZ_KEY_PAIR_GENERATE(csprng *RNG,octet* S,octet *W);
+extern int BLS_ZZZ_SIGN(octet *SIG,char *m,octet *S);
+extern int BLS_ZZZ_VERIFY(octet *SIG,char *m,octet *W);
+extern int BLS_ZZZ_ADD_G1(octet *R1,octet *R2,octet *R);
+extern int BLS_ZZZ_ADD_G2(octet *W1,octet *W2,octet *W);
+
+
+""")
+
+if (platform.system() == 'Windows'):
+    libamcl_bls_ZZZ = ffi.dlopen("libamcl_bls_ZZZ.dll")
+    libamcl_core = ffi.dlopen("libamcl_core.dll")
+elif (platform.system() == 'Darwin'):
+    libamcl_bls_ZZZ = ffi.dlopen("libamcl_bls_ZZZ.dylib")
+    libamcl_core = ffi.dlopen("libamcl_core.dylib")
+else:
+    libamcl_bls_ZZZ = ffi.dlopen("libamcl_bls_ZZZ.so")
+    libamcl_core = ffi.dlopen("libamcl_core.so")
+
+# Group Size
+BGS = @NB@
+# Field Size
+BFS = @NB@
+
+CURVE_SECURITY = @CS@
+
+G1LEN = BFS+1
+
+if CURVE_SECURITY == 128:
+    G2LEN = 4*BFS
+
+if CURVE_SECURITY == 192:
+    G2LEN = 8*BFS
+
+if CURVE_SECURITY == 256:
+    G2LEN = 16*BFS
+    
+
+def to_hex(octet_value):
+    """Converts an octet type into a string
+
+    Add all the values in an octet into an array. This arrays is then
+    converted to a string and hex encoded.
+
+    Args::
+
+        octet_value. An octet pointer type
+
+    Returns::
+
+        String
+
+    Raises:
+        Exception
+    """
+    i = 0
+    val = []
+    while i < octet_value.len:
+        val.append(octet_value.val[i])
+        i = i + 1
+    out=b''
+    for x in val:
+        out = out + x
+    return out.hex()
+
+def make_octet(length, value=None):
+    """Generates an octet pointer
+
+    Generates an empty octet or one filled with the input value
+
+    Args::
+
+        length: Length of empty octet
+        value:  Data to assign to octet
+
+    Returns::
+
+        oct_ptr: octet pointer
+        val: data associated with octet to prevent garbage collection
+
+    Raises:
+
+    """
+    oct_ptr = ffi.new("octet*")
+    if value:
+        val = ffi.new("char [%s]" % len(value), value)
+        oct_ptr.val = val
+        oct_ptr.max = len(value)
+        oct_ptr.len = len(value)
+    else:
+        val = ffi.new("char []", length)
+        oct_ptr.val = val
+        oct_ptr.max = length
+        oct_ptr.len = length
+    return oct_ptr, val
+
+def create_csprng(seed):
+    """Make a Cryptographically secure pseudo-random number generator instance
+
+    Make a Cryptographically secure pseudo-random number generator instance
+
+    Args::
+
+        seed:   random seed value
+
+    Returns::
+
+        rng: Pointer to cryptographically secure pseudo-random number generator instance
+
+    Raises:
+
+    """
+    seed_oct, seed_val = make_octet(None, seed)
+
+    # random number generator
+    rng = ffi.new('csprng*')
+    libamcl_core.CREATE_CSPRNG(rng, seed_oct)
+    libamcl_core.OCT_clear(seed_oct)
+
+    return rng
+
+
+def kill_csprng(rng):
+    """Kill a random number generator
+
+    Deletes all internal state
+
+    Args::
+
+        rng: Pointer to cryptographically secure pseudo-random number generator instance
+
+    Returns::
+
+
+
+    Raises:
+
+    """
+    libamcl_core.KILL_CSPRNG(rng)
+
+    return 0
+
+def key_pair_generate(rng):
+    """Generate key pair
+
+    Generate key pair
+
+    Args::
+
+        rng: Pointer to cryptographically secure pseudo-random number generator instance
+
+    Returns::
+
+        error_code: error from the C function
+        sk: secret key
+        pk: public key
+
+    Raises:
+
+    """
+    sk1, sk1val = make_octet(BGS)
+    pk1, pk1val = make_octet(G2LEN)    
+    error_code = libamcl_bls_ZZZ.BLS_ZZZ_KEY_PAIR_GENERATE(rng, sk1,pk1)
+
+    sk_hex = to_hex(sk1)
+    pk_hex = to_hex(pk1)    
+
+    # clear memory
+    libamcl_core.OCT_clear(sk1)
+    libamcl_core.OCT_clear(pk1)    
+
+    sk = bytes.fromhex(sk_hex)
+    pk = bytes.fromhex(pk_hex)        
+    return error_code, sk, pk
+
+def sign(message, sk):
+    """Calculate a signature
+
+    Generate key pair
+
+    Args::
+
+        message: Message to sign
+        sk: BLS secret key
+
+    Returns::
+
+        error_code: Zero for success or else an error code
+        signature: BLS signature
+
+    Raises:
+
+    """
+    sk1, sk1_val = make_octet(None, sk)
+    signature1, signature1_val = make_octet(G1LEN)    
+    error_code = libamcl_bls_ZZZ.BLS_ZZZ_SIGN(signature1, message, sk1)
+
+    signature_hex = to_hex(signature1)
+
+    # clear memory
+    libamcl_core.OCT_clear(sk1)
+    libamcl_core.OCT_clear(signature1)    
+
+    signature = bytes.fromhex(signature_hex)
+    return error_code, signature
+
+def verify(signature, message, pk):
+    """Verify a signature
+
+    Verify a signature
+
+    Args::
+
+        message: Message to verify
+        signature: BLS signature
+        pk: BLS public key
+
+    Returns::
+
+        error_code: Zero for success or else an error code
+
+    Raises:
+
+    """
+    pk1, pk1_val = make_octet(None, pk)
+    signature1, signature1_val = make_octet(None, signature)
+    error_code = libamcl_bls_ZZZ.BLS_ZZZ_VERIFY(signature1, message, pk1)
+
+    # clear memory
+    libamcl_core.OCT_clear(pk1)
+    libamcl_core.OCT_clear(signature1)    
+
+    return error_code
+
+def add_G1(R1, R2):
+    """Add two members from the group G1
+
+    Add two members from the group G1
+
+    Args::
+
+        R1:   member of G1
+        R2:   member of G1
+
+    Returns::
+
+        R:          member of G1. R = R1+R2
+        error_code: Zero for success or else an error code
+
+    Raises:
+
+    """
+    R11, R11_val = make_octet(None, R1)
+    R21, R21_val = make_octet(None, R2)    
+    R1, R1_val = make_octet(G1LEN)        
+    error_code = libamcl_bls_ZZZ.BLS_ZZZ_ADD_G1(R11, R21, R1)
+
+    R_hex = to_hex(R1)
+    
+    # clear memory
+    libamcl_core.OCT_clear(R11)
+    libamcl_core.OCT_clear(R21)
+    libamcl_core.OCT_clear(R1)    
+
+    R = bytes.fromhex(R_hex)
+    return error_code, R
+
+def add_G2(R1, R2):
+    """Add two members from the group G2
+
+    Add two members from the group G2
+
+    Args::
+
+        R1:   member of G2
+        R2:   member of G2
+
+    Returns::
+
+        R:          member of G2. R = R1+R2
+        error_code: Zero for success or else an error code
+
+    Raises:
+
+    """
+    R11, R11_val = make_octet(None, R1)
+    R21, R21_val = make_octet(None, R2)    
+    R1, R1_val = make_octet(G2LEN)        
+    error_code = libamcl_bls_ZZZ.BLS_ZZZ_ADD_G2(R11, R21, R1)
+
+    R_hex = to_hex(R1)
+    
+    # clear memory
+    libamcl_core.OCT_clear(R11)
+    libamcl_core.OCT_clear(R21)
+    libamcl_core.OCT_clear(R1)    
+
+    R = bytes.fromhex(R_hex)
+    return error_code, R
+
+if __name__ == "__main__":
+    # Print hex values
+    DEBUG = False
+
+    # Seed
+    seed_hex = "78d0fb6705ce77dee47d03eb5b9c5d30"
+    seed = bytes.fromhex(seed_hex)
+
+    # Message
+    message = b"test message"
+
+    # random number generator
+    rng = create_csprng(seed)
+
+    # Generate key pairs
+    rtn, sk1, pk1 = key_pair_generate(rng)
+    if rtn != 0:
+        print("Error: key_pair_generate {}".format(rtn))                
+        raise SystemExit(0)        
+    print("sk1: {}".format(sk1.hex()))
+    print("pk1: {}".format(pk1.hex()))
+
+    rtn, sk2, pk2 = key_pair_generate(rng)
+    if rtn != 0:
+        print("Error: key_pair_generate {}".format(rtn))        
+        raise SystemExit(0)        
+    print("sk2: {}".format(sk2.hex()))
+    print("pk2: {}".format(pk2.hex()))
+
+    rtn, sk3, pk3 = key_pair_generate(rng)
+    if rtn != 0:
+        print("Error: key_pair_generate {}".format(rtn))        
+        raise SystemExit(0)        
+    print("sk3: {}".format(sk3.hex()))
+    print("pk3: {}".format(pk3.hex()))
+
+    # Sign and verify
+    rtn, sig1 = sign(message, sk1)
+    if rtn != 0:
+        print("Error: sign {}".format(rtn))
+        raise SystemExit(0)                
+    print("sig1: {}".format(sig1.hex()))
+
+    rtn = verify(sig1, message, pk1)
+    if rtn != 0:
+        print("Error: Invalid signature {}".format(rtn))
+        raise SystemExit(0)
+    print("Success: Signature is valid")
+
+    rtn, sig2 = sign(message, sk2)
+    if rtn != 0:
+        print("Error: sign {}".format(rtn))
+        raise SystemExit(0)                
+    print("sig2: {}".format(sig2.hex()))
+
+    rtn = verify(sig2, message, pk2)
+    if rtn != 0:
+        print("Error: Invalid signature {}".format(rtn))
+        raise SystemExit(0)
+    print("Success: Signature is valid")
+    
+    rtn, sig3 = sign(message, sk3)
+    if rtn != 0:
+        print("Error: sign {}".format(rtn))
+        raise SystemExit(0)                
+    print("sig3: {}".format(sig3.hex()))
+    
+    rtn = verify(sig3, message, pk3)
+    if rtn != 0:
+        print("Error: Invalid signature {}".format(rtn))
+        raise SystemExit(0)
+    print("Success: Signature is valid")
+
+    # Add Signatures
+    rtn, sig12 = add_G1(sig1, sig2)
+    if rtn != 0:
+        print("Error: add_G1 {}".format(rtn))
+        raise SystemExit(0)
+    print("sig12: {}".format(sig12.hex()))    
+
+    rtn, sig123 = add_G1(sig12, sig3)
+    if rtn != 0:
+        print("Error: add_G1 {}".format(rtn))
+        raise SystemExit(0)
+    print("sig123: {}".format(sig123.hex()))    
+
+    # Add Public keys
+    rtn, pk12 = add_G2(pk1, pk2)
+    if rtn != 0:
+        print("Error: add_G2 {}".format(rtn))
+        raise SystemExit(0)
+    print("pk12: {}".format(pk12.hex()))    
+
+    rtn, pk123 = add_G2(pk12, pk3)
+    if rtn != 0:
+        print("Error: add_G2 {}".format(rtn))
+        raise SystemExit(0)
+    print("pk123: {}".format(pk123.hex()))    
+
+    # Verify aggretated values
+    rtn = verify(sig123, message, pk123)
+    if rtn != 0:
+        print("Error: Invalid aggregated signature {}".format(rtn))
+        raise SystemExit(0)
+    print("Success: Aggregated signature is valid")
+    
+    # Clear memory    
+    kill_csprng(rng)
+    del sk1
+    del pk1    
+    del sk2
+    del pk2    
+    del sk3
+    del pk3    
diff --git a/wrappers/python/mpin_ZZZ.py.in b/wrappers/python/mpin_ZZZ.py.in
index 8535820..0632cc8 100644
--- a/wrappers/python/mpin_ZZZ.py.in
+++ b/wrappers/python/mpin_ZZZ.py.in
@@ -32,7 +32,6 @@ import cffi
 import platform
 import os
 
-
 ffi = cffi.FFI()
 ffi.cdef("""
 typedef struct {
@@ -101,22 +100,33 @@ else:
     libamcl_mpin_ZZZ = ffi.dlopen("libamcl_mpin_ZZZ.so")
     libamcl_core = ffi.dlopen("libamcl_core.so")
 
-# MPIN Group Size
+# Group Size
 PGS = @NB@
-# MPIN Field Size
+# Field Size
 PFS = @NB@
+
+CURVE_SECURITY = @CS@
+
+if CURVE_SECURITY == 128:
+    G2 = 4*PFS
+    HASH_TYPE_ZZZ = 32
+    AESKEY_ZZZ = 16    
+    
+if CURVE_SECURITY == 192:
+    G2 = 8*PFS
+    HASH_TYPE_ZZZ = 48    
+    AESKEY_ZZZ = 24
+    
+if CURVE_SECURITY == 256:
+    G2 = 16*PFS
+    HASH_TYPE_ZZZ = 64
+    AESKEY_ZZZ = 32
+    
 G1 = 2 * PFS + 1
-G2 = 4 * PFS
-GT = 12 * PFS
+GT = 3*G2
+
 # AES-GCM IV length
 IVL = 12
-# MPIN Symmetric Key Size
-PAS = 16
-
-# Hash function choice
-SHA256 = 32
-SHA384 = 48
-SHA512 = 64
 
 
 def to_hex(octet_value):
@@ -1164,7 +1174,7 @@ def client_key(hash_type, pc1, pc2, pin, r, x, hm, t):
     x1, x1_val = make_octet(None, x)
     hm1, hm1_val = make_octet(None, hm)
     t1, t1_val = make_octet(None, t)
-    client_aes_key1, client_aes_key_val1 = make_octet(PAS)
+    client_aes_key1, client_aes_key_val1 = make_octet(AESKEY_ZZZ)
     error_code = libamcl_mpin_ZZZ.MPIN_ZZZ_CLIENT_KEY(
         hash_type,
         pc11,
@@ -1225,7 +1235,7 @@ def server_key(hash_type, z, server_secret, w, hm, HID, u, ut):
     HID1, HID1_val = make_octet(None, HID)
     u1, u1_val = make_octet(None, u)
 
-    server_aes_key1, server_aes_key1_val = make_octet(PAS)
+    server_aes_key1, server_aes_key1_val = make_octet(AESKEY_ZZZ)
     error_code = libamcl_mpin_ZZZ.MPIN_ZZZ_SERVER_KEY(
         hash_type,
         z1,
@@ -1278,7 +1288,7 @@ def aes_gcm_encrypt(aes_key, iv, header, plaintext):
     iv1, iv1_val = make_octet(None, iv)
     header1, header1_val = make_octet(None, header)
     plaintext1, plaintext1_val = make_octet(None, plaintext)
-    tag1, tag1_val = make_octet(PAS)
+    tag1, tag1_val = make_octet(AESKEY_ZZZ)
     ciphertext1, ciphertext1_val = make_octet(len(plaintext))
 
     libamcl_core.AES_GCM_ENCRYPT(
@@ -1326,7 +1336,7 @@ def aes_gcm_decrypt(aes_key, iv, header, ciphertext):
     iv1, iv1_val = make_octet(None, iv)
     header1, header1_val = make_octet(None, header)
     ciphertext1, ciphertext1_val = make_octet(None, ciphertext)
-    tag1, tag1_val = make_octet(PAS)
+    tag1, tag1_val = make_octet(AESKEY_ZZZ)
     plaintext1, plaintext1_val = make_octet(len(ciphertext))
 
     libamcl_core.AES_GCM_DECRYPT(
@@ -1412,7 +1422,7 @@ if __name__ == "__main__":
     MPIN_ZZZ_FULL = True
     PIN_ERROR = True
 
-    HASH_TYPE_MPIN_ZZZ = SHA256
+
 
     if TIME_PERMITS:
         date = today()
@@ -1433,7 +1443,7 @@ if __name__ == "__main__":
         mpin_id = "user@milagro.com"
 
     # Hash mpin_id
-    hash_mpin_id = hash_id(HASH_TYPE_MPIN_ZZZ, mpin_id)
+    hash_mpin_id = hash_id(HASH_TYPE_ZZZ, mpin_id)
     if DEBUG:
         print "mpin_id: %s" % mpin_id.encode("hex")
         print "hash_mpin_id: %s" % hash_mpin_id.encode("hex")
@@ -1489,13 +1499,13 @@ if __name__ == "__main__":
         if DEBUG:
             print "Date %s" % date
         rtn, tp1 = get_client_permit(
-            HASH_TYPE_MPIN_ZZZ, date, ms1, hash_mpin_id)
+            HASH_TYPE_ZZZ, date, ms1, hash_mpin_id)
         if rtn != 0:
-            print "get_client_permit(HASH_TYPE_MPIN_ZZZ, date, ms1, hash_mpin_id) Error %s" % rtn
+            print "get_client_permit(HASH_TYPE_ZZZ, date, ms1, hash_mpin_id) Error %s" % rtn
         rtn, tp2 = get_client_permit(
-            HASH_TYPE_MPIN_ZZZ, date, ms2, hash_mpin_id)
+            HASH_TYPE_ZZZ, date, ms2, hash_mpin_id)
         if rtn != 0:
-            print "get_client_permit(HASH_TYPE_MPIN_ZZZ, date, ms2, hash_mpin_id) Error %s" % rtn
+            print "get_client_permit(HASH_TYPE_ZZZ, date, ms2, hash_mpin_id) Error %s" % rtn
         if DEBUG:
             print "tp1: %s" % tp1.encode("hex")
             print "tp2: %s" % tp2.encode("hex")
@@ -1515,9 +1525,9 @@ if __name__ == "__main__":
             raw_input("Please enter four digit PIN to create M-Pin Token:"))
     else:
         PIN = 1234
-    rtn, token = extract_pin(HASH_TYPE_MPIN_ZZZ, mpin_id, PIN, client_secret)
+    rtn, token = extract_pin(HASH_TYPE_ZZZ, mpin_id, PIN, client_secret)
     if rtn != 0:
-        print "extract_pin(HASH_TYPE_MPIN_ZZZ, mpin_id, PIN, token) Error %s" % rtn
+        print "extract_pin(HASH_TYPE_ZZZ, mpin_id, PIN, token) Error %s" % rtn
     print "Token: %s" % token.encode("hex")
 
     if ONE_PASS:
@@ -1536,7 +1546,7 @@ if __name__ == "__main__":
 
         # Client MPIN
         rtn, x, u, ut, v, y = client(
-            HASH_TYPE_MPIN_ZZZ, date, mpin_id, rng, None, PIN, token, time_permit, None, epoch_time)
+            HASH_TYPE_ZZZ, date, mpin_id, rng, None, PIN, token, time_permit, None, epoch_time)
         if rtn != 0:
             print "MPIN_ZZZ_CLIENT ERROR %s" % rtn
 
@@ -1546,7 +1556,7 @@ if __name__ == "__main__":
 
         # Server MPIN
         rtn, HID, HTID, E, F, y2 = server(
-            HASH_TYPE_MPIN_ZZZ, date, server_secret, u, ut, v, mpin_id, None, epoch_time)
+            HASH_TYPE_ZZZ, date, server_secret, u, ut, v, mpin_id, None, epoch_time)
         if DEBUG:
             print "y2 ", y2.encode("hex")
         if rtn != 0:
@@ -1571,16 +1581,16 @@ if __name__ == "__main__":
                 print "ERROR: Generating T %s" % rtn
 
         if MPIN_ZZZ_FULL:
-            HM = hash_all(HASH_TYPE_MPIN_ZZZ, hash_mpin_id, u, ut, v, y, Z, T)
+            HM = hash_all(HASH_TYPE_ZZZ, hash_mpin_id, u, ut, v, y, Z, T)
 
             rtn, client_aes_key = client_key(
-                HASH_TYPE_MPIN_ZZZ, pc1, pc2, PIN, r, x, HM, T)
+                HASH_TYPE_ZZZ, pc1, pc2, PIN, r, x, HM, T)
             if rtn != 0:
                 print "ERROR: Generating client_aes_key %s" % rtn
             print "Client AES Key: %s" % client_aes_key.encode("hex")
 
             rtn, server_aes_key = server_key(
-                HASH_TYPE_MPIN_ZZZ, Z, server_secret, w, HM, HID, u, ut)
+                HASH_TYPE_ZZZ, Z, server_secret, w, HM, HID, u, ut)
             if rtn != 0:
                 print "ERROR: Generating server_aes_key %s" % rtn
             print "Server AES Key: %s" % server_aes_key.encode("hex")
@@ -1598,7 +1608,7 @@ if __name__ == "__main__":
 
         # Client first pass
         rtn, x, u, ut, sec = client_1(
-            HASH_TYPE_MPIN_ZZZ, date, mpin_id, rng, None, PIN, token, time_permit)
+            HASH_TYPE_ZZZ, date, mpin_id, rng, None, PIN, token, time_permit)
         if rtn != 0:
             print "client_1  ERROR %s" % rtn
         if DEBUG:
@@ -1606,7 +1616,7 @@ if __name__ == "__main__":
 
         # Server calculates H(ID) and H(T|H(ID)) (if time permits enabled),
         # and maps them to points on the curve HID and HTID resp.
-        HID, HTID = server_1(HASH_TYPE_MPIN_ZZZ, date, mpin_id)
+        HID, HTID = server_1(HASH_TYPE_ZZZ, date, mpin_id)
 
         # Server generates Random number y and sends it to Client
         rtn, y = random_generate(rng)
@@ -1647,16 +1657,16 @@ if __name__ == "__main__":
             if rtn != 0:
                 print "ERROR: Generating T %s" % rtn
 
-            HM = hash_all(HASH_TYPE_MPIN_ZZZ, hash_mpin_id, u, ut, v, y, Z, T)
+            HM = hash_all(HASH_TYPE_ZZZ, hash_mpin_id, u, ut, v, y, Z, T)
 
             rtn, client_aes_key = client_key(
-                HASH_TYPE_MPIN_ZZZ, pc1, pc2, PIN, r, x, HM, T)
+                HASH_TYPE_ZZZ, pc1, pc2, PIN, r, x, HM, T)
             if rtn != 0:
                 print "ERROR: Generating client_aes_key %s" % rtn
             print "Client AES Key: %s" % client_aes_key.encode("hex")
 
             rtn, server_aes_key = server_key(
-                HASH_TYPE_MPIN_ZZZ, Z, server_secret, w, HM, HID, u, ut)
+                HASH_TYPE_ZZZ, Z, server_secret, w, HM, HID, u, ut)
             if rtn != 0:
                 print "ERROR: Generating server_aes_key %s" % rtn
             print "Server AES Key: %s" % server_aes_key.encode("hex")
diff --git a/wrappers/python/wcc_ZZZ.py.in b/wrappers/python/wcc_ZZZ.py.in
index 4457f12..2b083e8 100644
--- a/wrappers/python/wcc_ZZZ.py.in
+++ b/wrappers/python/wcc_ZZZ.py.in
@@ -31,25 +31,6 @@ There is also an example usage program in this file.
 import cffi
 import platform
 
-# WCC Group Size
-PGS = @NB@
-# WCC Field Size
-PFS = @NB@
-G1 = 2 * PFS + 1
-G2 = 4 * PFS
-# Length of hash
-HASH_BYTES = 32
-# AES-GCM IV length
-IVL = 12
-# AES Key length
-PAS = 16
-
-# Hash function choice
-SHA256 = 32
-SHA384 = 48
-SHA512 = 64
-HASH_TYPE_WCC_ZZZ = SHA256
-
 ffi = cffi.FFI()
 ffi.cdef("""
 typedef struct {
@@ -94,6 +75,32 @@ else:
     libamcl_wcc_ZZZ = ffi.dlopen("libamcl_wcc_ZZZ.so")
     libamcl_core = ffi.dlopen("libamcl_core.so")
 
+# Group Size
+PGS = @NB@
+# Field Size
+PFS = @NB@
+
+CURVE_SECURITY = @CS@
+
+if CURVE_SECURITY == 128:
+    G2 = 4*PFS
+    HASH_TYPE_ZZZ = 32
+    AESKEY_ZZZ = 16    
+    
+if CURVE_SECURITY == 192:
+    G2 = 8*PFS
+    HASH_TYPE_ZZZ = 48    
+    AESKEY_ZZZ = 24
+    
+if CURVE_SECURITY == 256:
+    G2 = 16*PFS
+    HASH_TYPE_ZZZ = 64
+    AESKEY_ZZZ = 32
+    
+G1 = 2 * PFS + 1
+
+# AES-GCM IV length
+IVL = 12
 
 def toHex(octetValue):
     """Converts an octet type into a string
@@ -151,10 +158,10 @@ if __name__ == "__main__":
 
     # Hash value of IdA
     HIdA = ffi.new("octet*")
-    HIdAval = ffi.new("char []", HASH_BYTES)
+    HIdAval = ffi.new("char []", PFS)
     HIdA[0].val = HIdAval
-    HIdA[0].max = HASH_BYTES
-    HIdA[0].len = HASH_BYTES
+    HIdA[0].max = PFS
+    HIdA[0].len = PFS
 
     # Bob Identity
     bob_id = raw_input("Please enter Bob's identity:")
@@ -166,10 +173,10 @@ if __name__ == "__main__":
 
     # Hash value of IdB
     HIdB = ffi.new("octet*")
-    HIdBval = ffi.new("char []", HASH_BYTES)
+    HIdBval = ffi.new("char []", PFS)
     HIdB[0].val = HIdBval
-    HIdB[0].max = HASH_BYTES
-    HIdB[0].len = HASH_BYTES
+    HIdB[0].max = PFS
+    HIdB[0].len = PFS
 
     # Sender keys
     A1KeyG1 = ffi.new("octet*")
@@ -211,16 +218,16 @@ if __name__ == "__main__":
 
     # AES Keys
     KEY1 = ffi.new("octet*")
-    KEY1val = ffi.new("char []", PAS)
+    KEY1val = ffi.new("char []", AESKEY_ZZZ)
     KEY1[0].val = KEY1val
-    KEY1[0].max = PAS
-    KEY1[0].len = PAS
+    KEY1[0].max = AESKEY_ZZZ
+    KEY1[0].len = AESKEY_ZZZ
 
     KEY2 = ffi.new("octet*")
-    KEY2val = ffi.new("char []", PAS)
+    KEY2val = ffi.new("char []", AESKEY_ZZZ)
     KEY2[0].val = KEY2val
-    KEY2[0].max = PAS
-    KEY2[0].len = PAS
+    KEY2[0].max = AESKEY_ZZZ
+    KEY2[0].len = AESKEY_ZZZ
 
     X = ffi.new("octet*")
     Xval = ffi.new("char []", PGS)
@@ -284,13 +291,13 @@ if __name__ == "__main__":
     libamcl_core.CREATE_CSPRNG(RNG, SEED)
 
     # Hash IdA
-    libamcl_core.HASH_ID(HASH_TYPE_WCC_ZZZ, IdA, HIdA)
+    libamcl_core.HASH_ID(HASH_TYPE_ZZZ, IdA, HIdA)
     if DEBUG:
         print "IdA: %s" % toHex(IdA)
         print "HIdA: %s" % toHex(HIdA)
 
     # Hash IdB
-    libamcl_core.HASH_ID(HASH_TYPE_WCC_ZZZ, IdB, HIdB)
+    libamcl_core.HASH_ID(HASH_TYPE_ZZZ, IdB, HIdB)
     if DEBUG:
         print "IdB: %s" % toHex(IdB)
         print "HIdB: %s" % toHex(HIdB)
@@ -377,18 +384,18 @@ if __name__ == "__main__":
         print "PbG2: %s" % toHex(PbG2)
 
     # PIA = Hq(PaG1,PbG2,PgG1,IdB)
-    libamcl_wcc_ZZZ.WCC_ZZZ_Hq(HASH_TYPE_WCC_ZZZ, PaG1, PbG2, PgG1, IdB, PIA)
+    libamcl_wcc_ZZZ.WCC_ZZZ_Hq(HASH_TYPE_ZZZ, PaG1, PbG2, PgG1, IdB, PIA)
     if DEBUG:
         print "PIA: %s" % toHex(PIA)
 
     # PIB = Hq(PbG2,PaG1,PgG1,IdA)
-    libamcl_wcc_ZZZ.WCC_ZZZ_Hq(HASH_TYPE_WCC_ZZZ, PbG2, PaG1, PgG1, IdA, PIB)
+    libamcl_wcc_ZZZ.WCC_ZZZ_Hq(HASH_TYPE_ZZZ, PbG2, PaG1, PgG1, IdA, PIB)
     if DEBUG:
         print "PIB: %s" % toHex(PIB)
 
     # Alice calculates AES Key
     rtn = libamcl_wcc_ZZZ.WCC_ZZZ_SENDER_KEY(
-        HASH_TYPE_WCC_ZZZ,
+        HASH_TYPE_ZZZ,
         X,
         PIA,
         PIB,
@@ -398,12 +405,12 @@ if __name__ == "__main__":
         IdB,
         KEY1)
     if rtn != 0:
-        print "libamcl_wcc_ZZZ.WCC_ZZZ_SENDER_KEY(HASH_TYPE_WCC_ZZZ, X, PIA, PIB, PbG2, PgG1, AKeyG1, IdB, KEY1) Error %s" % rtn
+        print "libamcl_wcc_ZZZ.WCC_ZZZ_SENDER_KEY(HASH_TYPE_ZZZ, X, PIA, PIB, PbG2, PgG1, AKeyG1, IdB, KEY1) Error %s" % rtn
     print "{0}'s AES Key: {1}".format(alice_id, toHex(KEY1))
 
     # Bob calculates AES Key
     rtn = libamcl_wcc_ZZZ.WCC_ZZZ_RECEIVER_KEY(
-        HASH_TYPE_WCC_ZZZ,
+        HASH_TYPE_ZZZ,
         Y,
         W,
         PIA,
@@ -414,7 +421,7 @@ if __name__ == "__main__":
         IdA,
         KEY2)
     if rtn != 0:
-        print "libamcl_wcc_ZZZ.WCC_ZZZ_RECEIVER_KEY(HASH_TYPE_WCC_ZZZ, Y, W, PIA, PIB, PaG1, PgG1, BKeyG2, IdA, KEY2) Error %s" % rtn
+        print "libamcl_wcc_ZZZ.WCC_ZZZ_RECEIVER_KEY(HASH_TYPE_ZZZ, Y, W, PIA, PIB, PaG1, PgG1, BKeyG2, IdA, KEY2) Error %s" % rtn
     print "{0}'s AES Key: {1}".format(bob_id, toHex(KEY2))
 
     libamcl_core.KILL_CSPRNG(RNG)