_binary From ab1a148e22fab3c5097c6eb7c9b944581567d55f Mon Sep 17 00:00:00 2001
From: Akash Patel <akash3664@yahoo.com>
Date: Fri, 16 May 2014 16:47:27 -0700
Subject: [PATCH] zkp feature

Signed-off-by: Akash Patel <akash3664@yahoo.com>
---
 configs/config.php                                 |   7 +
 configs/createdb.php                               |  31 +-
 controllers/admin_controller.php                   | 105 +++-
 controllers/components/accountaccess_component.php |  55 +-
 controllers/components/system_component.php        |  45 ++
 controllers/register_controller.php                | 128 ++--
 lib/crawl_constants.php                            |   1 +
 locale/en-US/configure.ini                         |   9 +
 locale/en-US/statistics.txt                        |   2 +-
 models/profile_model.php                           |  24 +-
 models/signin_model.php                            |  57 +-
 models/user_model.php                              |  26 +-
 scripts/basic.js                                   |  12 +-
 scripts/big_int.js                                 | 677 +++++++++++++++++++++
 scripts/classifiers.js                             |   2 +-
 scripts/hash_captcha.js                            |  75 +++
 scripts/hashcaptcha.js                             | 276 ---------
 scripts/mix.js                                     |   2 +-
 scripts/sha1.js                                    | 231 +++++++
 scripts/zkp.js                                     | 199 ++++++
 tests/sha1_test.php                                |   3 +-
 views/elements/manageusers_element.php             |  10 +-
 views/elements/serversettings_element.php          |  18 +-
 views/recover_view.php                             |  76 ++-
 views/register_view.php                            |  13 +-
 views/signin_view.php                              |  19 +-
 26 files changed, 1692 insertions(+), 411 deletions(-)
 create mode 100644 scripts/big_int.js
 create mode 100644 scripts/hash_captcha.js
 delete mode 100644 scripts/hashcaptcha.js
 create mode 100644 scripts/sha1.js
 create mode 100644 scripts/zkp.js

diff --git a/configs/config.php b/configs/config.php
index e315deb..9113a44 100755
--- a/configs/config.php
+++ b/configs/config.php
@@ -128,6 +128,12 @@ define('TEXT_CAPTCHA', 1);
 /** Captcha Mode Possibility*/
 define('HASH_CAPTCHA', 2);
 
+/** Authentication Mode Possibility*/
+define('NORMAL_AUTHENTICATION', 1);
+
+/** Authentication Mode Possibility*/
+define('ZKP_AUTHENTICATION', 2);
+
 if(file_exists(WORK_DIRECTORY.PROFILE_FILE_NAME)) {
     require_once(WORK_DIRECTORY.PROFILE_FILE_NAME);
     define('PROFILE', true);
@@ -158,6 +164,7 @@ if(file_exists(WORK_DIRECTORY.PROFILE_FILE_NAME)) {
     define('PROFILE', false);
     define('DBMS', 'sqlite3');
     define('CAPTCHA_MODE', HASH_CAPTCHA);
+    define('AUTHENTICATION_MODE', NORMAL_AUTHENTICATION);
     define('DEBUG_LEVEL', NO_DEBUG_INFO);
     define('USE_FILECACHE', false);
     define('WEB_ACCESS', true);
diff --git a/configs/createdb.php b/configs/createdb.php
index 082652c..0187c38 100755
--- a/configs/createdb.php
+++ b/configs/createdb.php
@@ -98,19 +98,25 @@ $db->execute("INSERT INTO VERSION VALUES (19)");
 
 $creation_time = microTimestamp();
 
+//numerical value of the blank password
+$profile = $profile_model->getProfile(WORK_DIRECTORY);
+$sha1_of_blank_string =  bchexdec(sha1(''));
+//calculating V  = S ^ 2 mod N
+$temp = bcpow($sha1_of_blank_string.'', '2');
+$zkp_password = bcmod($temp,$profile['FIAT_SHAMIR_MODULUS']);
+
 //default account is root without a password
 $sql ="INSERT INTO USERS VALUES (".ROOT_ID.", 'admin', 'admin','root',
         'root@dev.null', '".crawlCrypt('')."', '".ACTIVE_STATUS.
         "', '".crawlCrypt('root'.AUTH_KEY.$creation_time)."','$creation_time',
-        0, 0)";
-
+        0, 0, '$zkp_password')";
 $db->execute($sql);
 // public account is an inactive account for used for public permissions
 //default account is root without a password
 $sql ="INSERT INTO USERS VALUES (".PUBLIC_USER_ID.", 'all', 'all','public',
         'public@dev.null', '".crawlCrypt('')."', '".INACTIVE_STATUS.
         "', '".crawlCrypt('public'.AUTH_KEY.$creation_time)."',
-        '$creation_time', 0, 0)";
+        '$creation_time', 0, 0, '$zkp_password')";
 $db->execute($sql);
 
 //default public group with group id 1
@@ -714,5 +720,24 @@ $db->disconnect();
 if(in_array(DBMS, array('sqlite','sqlite3' ))){
     chmod(CRAWL_DIR."/data/".DB_NAME.".db", 0666);
 }
+
 echo "Create DB succeeded\n";
+
+/**
+ * Convert hexadecimal number to decimal using BC math PHP
+ * library. It is used to convert very large hex value to decimal value
+ *
+ * @param string $hex  hexadecimal number
+ * @return string $dec string representation of decimal number
+ */
+function bchexdec($hex)
+{
+    $dec = 0;
+    $len = strlen($hex);
+    for ($i = 1; $i <= $len; $i++) {
+        $dec = bcadd($dec, bcmul(strval(hexdec($hex[$i - 1])),
+               bcpow('16', strval($len - $i))));
+    }
+    return $dec;
+}
 ?>
diff --git a/controllers/admin_controller.php b/controllers/admin_controller.php
index 610fc24..0621493 100755
--- a/controllers/admin_controller.php
+++ b/controllers/admin_controller.php
@@ -87,13 +87,13 @@ class AdminController extends Controller implements CrawlConstants
      */
     function processRequest()
     {
+        $profile_model = $this->model("profile");
+        $profile = $profile_model->getProfile(WORK_DIRECTORY);
         $data = array();
-
         if(!PROFILE) {
             return $this->configureRequest();
         }
         $view = "signin";
-
         if(isset($_SESSION['USER_ID'])) {
             $user = $_SESSION['USER_ID'];
         } else {
@@ -102,7 +102,6 @@ class AdminController extends Controller implements CrawlConstants
         $data['SCRIPT'] = "";
         $data[CSRF_TOKEN] = $this->generateCSRFToken($user);
         $token_okay = $this->checkCSRFToken(CSRF_TOKEN, $user);
-
         if($token_okay) {
             if(isset($_SESSION['USER_ID']) && !isset($_REQUEST['u'])) {
                 $data = array_merge($data, $this->processSession());
@@ -116,32 +115,58 @@ class AdminController extends Controller implements CrawlConstants
                     tl('admin_controller_need_cookies')."</h1>');";
                 unset($_SESSION['USER_ID']);
             } else if ($this->checkSignin()){
-                $user_id = $this->model("signin")->getUserId(
-                    $this->clean($_REQUEST['u'], "string"));
-                $session = $this->model("user")->getUserSession($user_id);
-                if(is_array($session)) {
-                    $_SESSION = $session;
+                if (!isset($_SESSION['AUTH_COUNT'])) {
+                    $_SESSION['AUTH_COUNT'] = 0;
                 }
-
-                $_SESSION['USER_ID'] = $user_id;
-                $data[CSRF_TOKEN] = $this->generateCSRFToken(
-                    $_SESSION['USER_ID']);
-                // now don't want to use remote address anymore
-                $data['SCRIPT'] = "doMessage('<h1 class=\"red\" >".
-                    tl('admin_controller_login_successful')."</h1>')";
-                $data = array_merge($data, $this->processSession());
-                if(isset($data['INACTIVE'])) {
-                    $data['SCRIPT'] .= "doMessage('<h1 class=\"red\" >".
-                        tl('admin_controller_account_not_active')."</h1>');";
-                    $view = "signin";
+                if($profile['AUTHENTICATION_MODE'] == NORMAL_AUTHENTICATION) {
+                    $_SESSION['AUTH_COUNT'] = self::FIAT_SHAMIR_ITERATIONS;
+                }
+                if($profile['AUTHENTICATION_MODE'] == ZKP_AUTHENTICATION) {
+                    $_SESSION['AUTH_COUNT']++;
+                }
+                if ($_SESSION['AUTH_COUNT'] != self::FIAT_SHAMIR_ITERATIONS) {
+                   $_SESSION['SALT_VALUE'] = rand(0, 1);
+                   echo $_SESSION['SALT_VALUE'];
+                   return;
+                }
+                $_SESSION['USER_NAME'] = $_REQUEST['u'];
+                if ($_SESSION['AUTH_COUNT'] == self::FIAT_SHAMIR_ITERATIONS) {
+                    $_SESSION['AUTH_COUNT'] = 0;
+                    $user_id = $this->model("signin")->getUserId(
+                        $this->clean($_REQUEST['u'], "string"));
+                    $session = $this->model("user")->getUserSession($user_id);
+                    if(is_array($session)) {
+                        $_SESSION = $session;
+                    }
+                    $_SESSION['USER_ID'] = $user_id;
+                    $data[CSRF_TOKEN] = $this->generateCSRFToken(
+                        $_SESSION['USER_ID']);
+                    // now don't want to use remote address anymore
+                    $data['SCRIPT'] = "doMessage('<h1 class=\"red\" >".
+                        tl('admin_controller_login_successful')."</h1>')";
+                    $data = array_merge($data, $this->processSession());
+                    if(isset($data['INACTIVE'])) {
+                        $data['SCRIPT'] .= "doMessage('<h1 class=\"red\" >".
+                            tl('admin_controller_account_not_active')."</h1>');";
+                        $view = "signin";
+                        unset($_SESSION['USER_ID']);
+                    }
+                    $view = "admin";
+                    }
+                } else {
+                    if($profile['AUTHENTICATION_MODE'] == ZKP_AUTHENTICATION
+                        && !isset($_SESSION['AUTH_FAILED'])) {
+                        $_SESSION['SALT_VALUE'] = 1;
+                        $_SESSION['AUTH_FAILED'] = -1;
+                        echo $_SESSION['AUTH_FAILED'];
+                        return;
+                    }
+                    $_SESSION['AUTH_COUNT'] = 0;
+                    $data['SCRIPT'] = "doMessage('<h1 class=\"red\" >".
+                        tl('admin_controller_login_failed')."</h1>');";
                     unset($_SESSION['USER_ID']);
+                    unset($_SESSION['AUTH_FAILED']);
                 }
-                $view = "admin";
-            } else {
-                $data['SCRIPT'] = "doMessage('<h1 class=\"red\" >".
-                    tl('admin_controller_login_failed')."</h1>');";
-                unset($_SESSION['USER_ID']);
-            }
         } else if($this->checkCSRFToken(CSRF_TOKEN, "config")) {
             $data['SCRIPT'] = "doMessage('<h1 class=\"red\" >".
                 tl('admin_controller_login_to_config')."</h1>')";
@@ -157,6 +182,14 @@ class AdminController extends Controller implements CrawlConstants
             $data["ADMIN"] = false;
         }
         if($view == 'signin') {
+            if($profile['AUTHENTICATION_MODE'] == ZKP_AUTHENTICATION) {
+                $data['AUTH_ITERATION'] = self::FIAT_SHAMIR_ITERATIONS;
+                $data['FIAT_SHAMIR_MODULUS'] = $profile['FIAT_SHAMIR_MODULUS'];
+                $_SESSION['SALT_VALUE'] = rand(0, 1);
+                $data['INCLUDE_SCRIPTS'] = array("zkp", "big_int", "sha1");
+            } else {
+                 unset($_SESSION['SALT_VALUE']);
+            }
             unset($_SESSION['USER_ID']);
             $data[CSRF_TOKEN] = $this->generateCSRFToken(
                 $_SERVER['REMOTE_ADDR']);
@@ -188,9 +221,23 @@ class AdminController extends Controller implements CrawlConstants
      */
     function checkSignin()
     {
-        $result = $this->model("signin")->checkValidSignin(
-        $this->clean($_REQUEST['u'], "string"),
-        $this->clean($_REQUEST['p'], "string") );
+        $profile_model = $this->model("profile");
+        $profile = $profile_model->getProfile(WORK_DIRECTORY);
+        if($profile['AUTHENTICATION_MODE'] == NORMAL_AUTHENTICATION) {
+            $result = $this->model("signin")->checkValidSignin(
+            $this->clean($_REQUEST['u'], "string"),
+            $this->clean($_REQUEST['p'], "string") );
+        } else {
+            $result = $this->model("signin")->checkValidSigninForZKP(
+            $this->clean($_REQUEST['u'], "string"),
+            $this->clean($_REQUEST['x1'], "string"),
+            $this->clean($_REQUEST['y1'], "string"),
+            $_SESSION['SALT_VALUE'],
+            $profile['FIAT_SHAMIR_MODULUS'] );
+            if(!$result){
+             $_SESSION['AUTH_COUNT'] = 0;
+            }
+        }
         return $result;
     }
 
diff --git a/controllers/components/accountaccess_component.php b/controllers/components/accountaccess_component.php
index 0bece6c..b28b67f 100644
--- a/controllers/components/accountaccess_component.php
+++ b/controllers/components/accountaccess_component.php
@@ -70,6 +70,8 @@ class AccountaccessComponent extends Component
     function manageAccount()
     {
         $parent = $this->parent;
+        $profile_model = $parent->model("profile");
+        $profile = $profile_model->getProfile(WORK_DIRECTORY);
         $signin_model = $parent->model("signin");
         $group_model = $parent->model("group");
         $user_model = $parent->model("user");
@@ -147,9 +149,16 @@ class AccountaccessComponent extends Component
                         return $data;
                     }
                     if(isset($data['EDIT_PASSWORD'])) {
-                        $signin_model->changePassword($username,
-                            $parent->clean($_REQUEST['new_password'],
-                            "string"));
+                        if($profile['AUTHENTICATION_MODE']
+                             == ZKP_AUTHENTICATION) {
+                            $signin_model->changePasswordZKP($username,
+                                $parent->clean($_REQUEST['new_password'],
+                                "string"));
+                        } else {
+                                $signin_model->changePassword($username,
+                                $parent->clean($_REQUEST['new_password'],
+                                "string"));
+                        }
                     }
                     $user = array();
                     $user['USER_ID'] = $user_id;
@@ -184,6 +193,18 @@ class AccountaccessComponent extends Component
     function manageUsers()
     {
         $parent = $this->parent;
+        $profile_model = $parent->model("profile");
+        $profile = $profile_model->getProfile(WORK_DIRECTORY);
+        if($profile['AUTHENTICATION_MODE'] == ZKP_AUTHENTICATION) {
+            $_SESSION['SALT_VALUE'] = rand(0, 1);
+            $_SESSION['AUTH_COUNT'] = 1;
+            $data['INCLUDE_SCRIPTS'] = array("sha1", "zkp", "big_int");
+            $data['AUTHENTICATION_MODE'] = ZKP_AUTHENTICATION;
+            $data['FIAT_SHAMIR_MODULUS'] = $profile['FIAT_SHAMIR_MODULUS'];
+        } else {
+            $data['AUTHENTICATION_MODE'] = NORMAL_AUTHENTICATION;
+            unset($_SESSION['SALT_VALUE']);
+        }
         $signin_model = $parent->model("signin");
         $user_model = $parent->model("user");
         $group_model = $parent->model("group");
@@ -257,13 +278,23 @@ class AccountaccessComponent extends Component
                         $_REQUEST['status']])) {
                         $_REQUEST['status'] = INACTIVE_STATUS;
                     } else {
-                        $user_model->addUser($username,
-                            $parent->clean($_REQUEST['password'], "string"),
-                            $parent->clean($_REQUEST['first_name'], "string"),
-                            $parent->clean($_REQUEST['last_name'], "string"),
-                            $parent->clean($_REQUEST['email'], "string"),
-                            $_REQUEST['status']
+                        if($profile['AUTHENTICATION_MODE'] == ZKP_AUTHENTICATION) {
+                            $user_model->addUser($username, '',
+                                $parent->clean($_REQUEST['first_name'], "string"),
+                                $parent->clean($_REQUEST['last_name'], "string"),
+                                $parent->clean($_REQUEST['email'], "string"),
+                                $_REQUEST['status'],
+                                $parent->clean($_REQUEST['password'], "string")
                             );
+                        } else {
+                            $user_model->addUser($username,
+                                $parent->clean($_REQUEST['password'], "string"),
+                                $parent->clean($_REQUEST['first_name'], "string"),
+                                $parent->clean($_REQUEST['last_name'], "string"),
+                                $parent->clean($_REQUEST['email'], "string"),
+                                $_REQUEST['status']
+                            );
+                        }
                         $data['USER_NAMES'][$username] = $username;
                         $data['SCRIPT'] .= "doMessage('<h1 class=\"red\" >".
                             tl('accountaccess_component_user_added').
@@ -292,6 +323,12 @@ class AccountaccessComponent extends Component
                                     $_REQUEST[$field], "string");
                                 if($tmp != $user[$upper_field]) {
                                     $user[$upper_field] = $tmp;
+                                     if($profile['AUTHENTICATION_MODE'] ==
+                                        ZKP_AUTHENTICATION && $upper_field
+                                        == "PASSWORD") {
+                                        $user["ZKP_PASSWORD"] = $tmp;
+                                        $user[$upper_field] ='';
+                                    }
                                     if(!isset($_REQUEST['change_filter'])) {
                                         $update = true;
                                     }
diff --git a/controllers/components/system_component.php b/controllers/components/system_component.php
index 6bcf8ff..0e5be23 100644
--- a/controllers/components/system_component.php
+++ b/controllers/components/system_component.php
@@ -607,6 +607,12 @@ class SystemComponent extends Component
                 HASH_CAPTCHA =>
                    tl('serversettings_element_hash_captcha'),
             );
+        $data['AUTHENTICATION_MODES'] = array (
+                NORMAL_AUTHENTICATION =>
+                   tl('serversettings_element_normal_authentication'),
+                ZKP_AUTHENTICATION =>
+                   tl('serversettings_element_zkp_authentication'),
+            );
         $data['show_mail_info'] = "false";
         if(isset($data['REGISTRATION_TYPE']) &&
             in_array($data['REGISTRATION_TYPE'], array(
@@ -780,6 +786,8 @@ EOD;
                         $profile['AUTH_KEY'] = crawlHash(
                             $data['WORK_DIRECTORY'].time());
                         $data['AUTH_KEY'] = $profile['AUTH_KEY'];
+                        $profile['FIAT_SHAMIR_MODULUS'] =
+                            $this->generateFiatShamirModulus();
                         $robot_instance = str_replace(".", "_",
                             $_SERVER['SERVER_NAME'])."-".time();
                         $profile['ROBOT_INSTANCE'] = $robot_instance;
@@ -1042,5 +1050,42 @@ EOD;
         return $out;
      }
 
+     /**
+      * This method generates Fiat-Shamir modulus. It uses
+      * openssl public key method to generate the public key and
+      * then extract modulus from the public key
+      *
+      * @return string $dec string representation of modulus
+      */
+     function generateFiatShamirModulus()
+     {
+        $config = array(
+            "digest_alg" => "sha256",
+            "public_key_bits" => 1024,
+            "public_key_type" => OPENSSL_KEYTYPE_RSA,
+        );
+        $res=openssl_pkey_new($config);
+        $pub_key=openssl_pkey_get_details($res);
+        return $this->bchexdec(bin2hex($pub_key["rsa"]["n"]));
+    }
+
+    /**
+     * Convert hexadecimal number to decimal using BC math PHP
+     * library. It is used to convert very large hex value to decimal value
+     *
+     * @param string $hex  hexadecimal number
+     * @return string $dec string representation of decimal number
+     */
+    function bchexdec($hex)
+    {
+        $dec = 0;
+        $len = strlen($hex);
+        for ($i = 1; $i <= $len; $i++) {
+            $dec = bcadd($dec, bcmul(strval(hexdec($hex[$i - 1])),
+                        bcpow('16', strval($len - $i))));
+        }
+        return $dec;
+    }
+
 
 }
diff --git a/controllers/register_controller.php b/controllers/register_controller.php
index ede9a69..fc43728 100755
--- a/controllers/register_controller.php
+++ b/controllers/register_controller.php
@@ -190,6 +190,8 @@ class RegisterController extends Controller implements CrawlConstants
      */
     function processRequest()
     {
+        $profile_model = $this->model("profile");
+        $profile = $profile_model->getProfile(WORK_DIRECTORY);
         $visitor_model = $this->model("visitor");
         if(isset($_SESSION['USER_ID'])) {
             $user = $_SESSION['USER_ID'];
@@ -224,8 +226,10 @@ class RegisterController extends Controller implements CrawlConstants
             'processAccountData', 'createAccount', $data);
         $data["check_fields"] = array("user");
         unset($data["check_user"]);
-        for($i = 0; $i < self::NUM_CAPTCHA_QUESTIONS; $i++) {
-            $data["check_fields"][] = "question_$i";
+        if($profile['CAPTCHA_MODE'] == TEXT_CAPTCHA) {
+            for($i = 0; $i < self::NUM_CAPTCHA_QUESTIONS; $i++) {
+                $data["check_fields"][] = "question_$i";
+            }
         }
         $this->preactivityPrerequisiteCheck($activity,
             'processRecoverData', 'recoverPassword', $data);
@@ -250,6 +254,21 @@ class RegisterController extends Controller implements CrawlConstants
             $visitor_model->updateVisitor(
                 $_SERVER['REMOTE_ADDR'], "captcha_time_out");
         }
+        if($profile['AUTHENTICATION_MODE'] == ZKP_AUTHENTICATION) {
+            $_SESSION['SALT_VALUE'] = rand(0, 1);
+            $data['AUTH_ITERATION'] = self::FIAT_SHAMIR_ITERATIONS;
+            $data['FIAT_SHAMIR_MODULUS'] = $profile['FIAT_SHAMIR_MODULUS'];
+            $data['INCLUDE_SCRIPTS'] = array("sha1", "zkp", "big_int");
+        } else {
+            unset($_SESSION['SALT_VALUE']);
+        }
+        if($profile['CAPTCHA_MODE'] == HASH_CAPTCHA) {
+            if(isset($data['INCLUDE_SCRIPTS'])) {
+                array_push($data['INCLUDE_SCRIPTS'], "hash_captcha");
+            } else {
+               $data['INCLUDE_SCRIPTS'] = array("sha1", "hash_captcha");
+            }
+        }
         //used to ensure that we have sessions active
         $_SESSION['REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR'];
         $this->displayView($view, $data);
@@ -281,7 +300,8 @@ class RegisterController extends Controller implements CrawlConstants
      *      or not
      */
     function processAccountData()
-    {
+    {   $profile_model = $this->model("profile");
+        $profile = $profile_model->getProfile(WORK_DIRECTORY);
         $data = array();
         $this->getCleanFields($data);
         $data['SCRIPT'] = "";
@@ -290,16 +310,28 @@ class RegisterController extends Controller implements CrawlConstants
         {
             case 'no_activation':
                 $data['REFRESH'] = "signin";
-                $user_model->addUser($data['USER'], $data['PASSWORD'],
-                    $data['FIRST'], $data['LAST'], $data['EMAIL']);
+                if($profile['AUTHENTICATION_MODE'] == NORMAL_AUTHENTICATION) {
+                    $user_model->addUser($data['USER'], $data['PASSWORD'],
+                        $data['FIRST'], $data['LAST'], $data['EMAIL']);
+                } else {
+                    $user_model->addUser($data['USER'], '',
+                        $data['FIRST'], $data['LAST'], $data['EMAIL'],
+                        ACTIVE_STATUS, $data['PASSWORD']);
+                }
                 $data['SCRIPT'] .= "doMessage('<h1 class=\"red\" >".
                     tl('register_controller_account_created')."</h1>')";
             break;
             case 'email_registration':
                 $data['REFRESH'] = "signin";
-                $user_model->addUser($data['USER'], $data['PASSWORD'],
-                    $data['FIRST'], $data['LAST'], $data['EMAIL'],
-                    INACTIVE_STATUS);
+                if($profile['AUTHENTICATION_MODE'] == NORMAL_AUTHENTICATION) {
+                    $user_model->addUser($data['USER'], $data['PASSWORD'],
+                        $data['FIRST'], $data['LAST'], $data['EMAIL'],
+                        INACTIVE_STATUS);
+                } else {
+                    $user_model->addUser($data['USER'], '',
+                        $data['FIRST'], $data['LAST'], $data['EMAIL'],
+                        INACTIVE_STATUS, $data['PASSWORD']);
+                }
                 $user = $user_model->getUser($data['USER']);
                 $server = new MailServer(MAIL_SENDER, MAIL_SERVER,
                     MAIL_SERVERPORT, MAIL_USERNAME, MAIL_PASSWORD,
@@ -328,9 +360,15 @@ class RegisterController extends Controller implements CrawlConstants
             break;
             case 'admin_activation':
                 $data['REFRESH'] = "signin";
-                $user_model->addUser($data['USER'], $data['PASSWORD'],
-                    $data['FIRST'], $data['LAST'], $data['EMAIL'],
-                    INACTIVE_STATUS);
+                if($profile['AUTHENTICATION_MODE'] == NORMAL_AUTHENTICATION) {
+                    $user_model->addUser($data['USER'], $data['PASSWORD'],
+                        $data['FIRST'], $data['LAST'], $data['EMAIL'],
+                        INACTIVE_STATUS);
+                } else {
+                    $user_model->addUser($data['USER'], '',
+                        $data['FIRST'], $data['LAST'], $data['EMAIL'],
+                        INACTIVE_STATUS, $data['PASSWORD']);
+                }
                 $data['SCRIPT'] .= "doMessage('<h1 class=\"red\" >".
                     tl('register_controller_account_request_made')."</h1>');";
                 $server = new MailServer(MAIL_SENDER, MAIL_SERVER,
@@ -439,6 +477,8 @@ class RegisterController extends Controller implements CrawlConstants
      */
     function processRecoverData()
     {
+        $profile_model = $this->model("profile");
+        $profile = $profile_model->getProfile(WORK_DIRECTORY);
         $data = array();
         $this->getCleanFields($data);
         $data['SCRIPT'] = "";
@@ -453,11 +493,13 @@ class RegisterController extends Controller implements CrawlConstants
             return $data;
         }
         $session = $user_model->getUserSession($user["USER_ID"]);
-        if(!isset($session['RECOVERY']) ||
-            !isset($session['RECOVERY_ANSWERS'])) {
-            $data['SCRIPT'] .= "doMessage('<h1 class=\"red\" >".
+        if($profile['CAPTCHA_MODE'] == TEXT_CAPTCHA) {
+            if(!isset($session['RECOVERY']) ||
+                !isset($session['RECOVERY_ANSWERS'])) {
+                $data['SCRIPT'] .= "doMessage('<h1 class=\"red\" >".
                 tl('register_controller_account_recover_fail')."</h1>');";
-            return $data;
+                return $data;
+            }
         }
         $data['SCRIPT'] .= "doMessage('<h1 class=\"red\" >".
             tl('register_controller_account_recover_email')."</h1>');";
@@ -608,7 +650,7 @@ class RegisterController extends Controller implements CrawlConstants
         $visitor_model = $this->model("visitor");
         $clear = false;
         if($profile['CAPTCHA_MODE'] == HASH_CAPTCHA) {
-            $data['INCLUDE_SCRIPTS'] = array("hashcaptcha");
+            $data['INCLUDE_SCRIPTS'] = array("sha1", "hash_captcha");
         }
         if($profile['CAPTCHA_MODE'] == TEXT_CAPTCHA) {
             $num_captchas = self::NUM_CAPTCHA_QUESTIONS;
@@ -769,8 +811,18 @@ class RegisterController extends Controller implements CrawlConstants
             self::NUM_CAPTCHA_CHOICES; $i++) {
             $data["question_$i"] = "-1";
         }
+        if($profile['AUTHENTICATION_MODE'] == ZKP_AUTHENTICATION) {
+            $data['AUTHENTICATION_MODE'] = ZKP_AUTHENTICATION;
+            $data['INCLUDE_SCRIPTS'] = array("sha1", "zkp"," big_int");
+         } else {
+            $data['AUTHENTICATION_MODE'] = NORMAL_AUTHENTICATION;
+         }
         if($profile['CAPTCHA_MODE'] == HASH_CAPTCHA) {
-            $data['INCLUDE_SCRIPTS'] = array("hashcaptcha");
+            if(isset($data['INCLUDE_SCRIPTS'])) {
+                array_push($data['INCLUDE_SCRIPTS'], "hash_captcha");
+            } else {
+                $data['INCLUDE_SCRIPTS'] = array("hash_captcha", "sha1");
+            }
             $time = time();
             $_SESSION["request_time"] = $time;
             $_SESSION["level"] = self::HASH_CAPTCHA_LEVEL;
@@ -1050,25 +1102,29 @@ class RegisterController extends Controller implements CrawlConstants
             $data["PASSWORD"] = "";
             $data["REPASSWORD"] = "";
         }
-        $num_questions = self::NUM_CAPTCHA_QUESTIONS +
-            self::NUM_RECOVERY_QUESTIONS;
-        $num_captchas = self::NUM_CAPTCHA_QUESTIONS;
-        for($i = 0; $i < $num_questions; $i++) {
-            $field = "question_$i";
-            if(!in_array($field, $fields)) {
-                continue;
-            }
-            $captchas = isset($_SESSION['CAPTCHAS'][$i]) ?
-                $_SESSION['CAPTCHAS'][$i] : array();
-            $recovery = isset($_SESSION['RECOVERY'][$i  - $num_captchas]) ?
-                $_SESSION['RECOVERY'][$i  - $num_captchas] : array();
-            $current_dropdown = ($i< $num_captchas) ?
-                $captchas : $recovery;
-            if(!isset($_REQUEST[$field]) || $_REQUEST[$field] == "-1" ||
-                !in_array($_REQUEST[$field], $current_dropdown)) {
-                $missing[] = $field;
-            } else {
-                $data[$field] = $_REQUEST[$field];
+        $profile_model = $this->model("profile");
+        $profile = $profile_model->getProfile(WORK_DIRECTORY);
+        if($profile['CAPTCHA_MODE'] == TEXT_CAPTCHA) {
+            $num_questions = self::NUM_CAPTCHA_QUESTIONS +
+                self::NUM_RECOVERY_QUESTIONS;
+            $num_captchas = self::NUM_CAPTCHA_QUESTIONS;
+            for($i = 0; $i < $num_questions; $i++) {
+                $field = "question_$i";
+                if(!in_array($field, $fields)) {
+                    continue;
+                }
+                $captchas = isset($_SESSION['CAPTCHAS'][$i]) ?
+                    $_SESSION['CAPTCHAS'][$i] : array();
+                $recovery = isset($_SESSION['RECOVERY'][$i  - $num_captchas]) ?
+                    $_SESSION['RECOVERY'][$i  - $num_captchas] : array();
+                $current_dropdown = ($i< $num_captchas) ?
+                    $captchas : $recovery;
+                if(!isset($_REQUEST[$field]) || $_REQUEST[$field] == "-1" ||
+                    !in_array($_REQUEST[$field], $current_dropdown)) {
+                    $missing[] = $field;
+                } else {
+                    $data[$field] = $_REQUEST[$field];
+                }
             }
         }
         $data['MISSING'] = $missing;
diff --git a/lib/crawl_constants.php b/lib/crawl_constants.php
index 61bf186..cc97026 100755
--- a/lib/crawl_constants.php
+++ b/lib/crawl_constants.php
@@ -253,5 +253,6 @@ interface CrawlConstants
     const CENTROID_SUMMARIZER = 'dl';
     const SUMMARIZER_OPTION = 'dm';
     const WORD_CLOUD = 'dn';
+    const FIAT_SHAMIR_ITERATIONS = 10;
 }
 ?>
\ No newline at end of file
diff --git a/locale/en-US/configure.ini b/locale/en-US/configure.ini
index 92abe03..fa0d38f 100755
--- a/locale/en-US/configure.ini
+++ b/locale/en-US/configure.ini
@@ -1074,6 +1074,12 @@ serversettings_element_text_captcha = "Text Captcha"
 ; system_component.php line: 607
 serversettings_element_hash_captcha = "Hash Captcha"
 ;
+; system_component.php line: 615
+serversettings_element_normal_authentication = "Normal Authentication"
+;
+; system_component.php line: 617
+serversettings_element_zkp_authentication = "ZKP Authentication"
+;
 ; system_component.php line: 712
 system_component_configure_use_absolute_path = "Must use an Absolute path for Work Directory"
 ;
@@ -2963,6 +2969,9 @@ serversettings_element_proxy_servers = "Proxy Servers (One per line. Format: add
 ; serversettings_element.php line: 243
 serversettings_element_captcha_setting = "Captcha Setting"
 ;
+; serversettings_element.php line: 258
+serversettings_element_authentication_mode = "Authentication Mode"
+;
 ; serversettings_element.php line: 255
 serversettings_element_submit = "Submit"
 ;
diff --git a/locale/en-US/statistics.txt b/locale/en-US/statistics.txt
index b6bef56..5a165df 100755
--- a/locale/en-US/statistics.txt
+++ b/locale/en-US/statistics.txt
@@ -1 +1 @@
-d:99;
\ No newline at end of file
+d:100;
\ No newline at end of file
diff --git a/models/profile_model.php b/models/profile_model.php
index 9e5aec9..02d1235 100755
--- a/models/profile_model.php
+++ b/models/profile_model.php
@@ -49,17 +49,17 @@ require_once(BASE_DIR.'/lib/url_parser.php');
  */
 class ProfileModel extends Model
 {
-    var $profile_fields = array('API_ACCESS', 'AUTH_KEY', 'CACHE_LINK',
-        'CAPTCHA_MODE','DEBUG_LEVEL', 'DESCRIPTION_WEIGHT', 'DB_HOST', 'DBMS',
-        'DB_NAME','DB_PASSWORD', 'DB_USER', 'DEFAULT_LOCALE', 'GROUP_ITEM',
-        'IN_LINK','IP_LINK', 'LINK_WEIGHT', 'MAIL_PASSWORD', 'MAIL_SECURITY',
-        'MAIL_SENDER', 'MAIL_SERVER', 'MAIL_SERVERPORT', 'MAIL_USERNAME',
-        'MEMCACHE_SERVERS', 'MIN_RESULTS_TO_GROUP', 'NAME_SERVER', 'NEWS_MODE',
-        'PROXY_SERVERS', 'REGISTRATION_TYPE',
-        'ROBOT_INSTANCE', 'RSS_ACCESS', 'SERVER_ALPHA', 'SIGNIN_LINK',
-        'SIMILAR_LINK', 'SUBSEARCH_LINK', 'TITLE_WEIGHT', 'TOR_PROXY',
-        'USE_FILECACHE', 'USE_MAIL_PHP', 'USE_MEMCACHE', 'USE_PROXY',
-        'USER_AGENT_SHORT', 'WEB_URI', 'WEB_ACCESS', 'WORD_SUGGEST'
+     var $profile_fields = array('API_ACCESS', 'AUTH_KEY', 'AUTHENTICATION_MODE',
+        'CACHE_LINK', 'CAPTCHA_MODE','DEBUG_LEVEL', 'DESCRIPTION_WEIGHT',
+        'DB_HOST', 'DBMS', 'DB_NAME','DB_PASSWORD', 'DB_USER', 'DEFAULT_LOCALE',
+        'FIAT_SHAMIR_MODULUS', 'GROUP_ITEM', 'IN_LINK','IP_LINK', 'LINK_WEIGHT',
+        'MAIL_PASSWORD', 'MAIL_SECURITY','MAIL_SENDER', 'MAIL_SERVER', 'MAIL_SERVERPORT',
+        'MAIL_USERNAME', 'MEMCACHE_SERVERS', 'MIN_RESULTS_TO_GROUP', 'NAME_SERVER',
+        'NEWS_MODE', 'PROXY_SERVERS', 'REGISTRATION_TYPE', 'ROBOT_INSTANCE',
+        'RSS_ACCESS', 'SERVER_ALPHA', 'SIGNIN_LINK', 'SIMILAR_LINK',
+        'SUBSEARCH_LINK', 'TITLE_WEIGHT', 'TOR_PROXY', 'USE_FILECACHE',
+        'USE_MAIL_PHP', 'USE_MEMCACHE', 'USE_PROXY', 'USER_AGENT_SHORT',
+        'WEB_URI', 'WEB_ACCESS', 'WORD_SUGGEST'
         );
     /**
      *  {@inheritdoc}
@@ -368,7 +368,7 @@ EOT;
                 USER_NAME VARCHAR(16) UNIQUE, EMAIL VARCHAR(60),
                 PASSWORD CHAR(60), STATUS INTEGER, HASH CHAR(60),
                 CREATION_TIME VARCHAR(20), UPS INTEGER DEFAULT 0,
-                DOWNS INTEGER DEFAULT 0)",
+                DOWNS INTEGER DEFAULT 0, ZKP_PASSWORD CHAR(200))",
             "CREATE INDEX USRS_USER_NAME_INDEX ON USERS(USER_NAME)",
             "CREATE TABLE USER_GROUP (USER_ID INTEGER , GROUP_ID INTEGER,
                    STATUS INTEGER, JOIN_DATE NUMERIC(11),
diff --git a/models/signin_model.php b/models/signin_model.php
index bd50044..45e29f2 100755
--- a/models/signin_model.php
+++ b/models/signin_model.php
@@ -60,7 +60,25 @@ class SigninModel extends Model
     function checkValidSignin($username, $password)
     {
         $db = $this->db;
-        $sql = "SELECT USER_NAME, PASSWORD FROM USERS ".
+        $result = $this->getUserDetails($username);
+        if(!$result) {
+            return false;
+        }
+        $row = $db->fetchArray($result);
+        return ($username == $row['USER_NAME'] &&
+            crawlCrypt($password, $row['PASSWORD']) == $row['PASSWORD']) ;
+    }
+    
+    /**
+     * Get user details from database
+     *
+     * @param string $username username
+     * @return array $result array of user data
+     */
+    function getUserDetails($username)
+    {
+        $db = $this->db;
+        $sql = "SELECT USER_NAME, PASSWORD,ZKP_PASSWORD FROM USERS ".
             "WHERE USER_NAME = ? " . $db->limitOffset(1);
         $i = 0;
         do {
@@ -70,13 +88,29 @@ class SigninModel extends Model
             $result = $db->execute($sql, array($username));
             $i++;
         } while(!$result && $i < 2);
+        return $result;
+    }
+    
+    /**
+     * To verify  username and password in case of ZKP authentication.
+     *
+     * @param string $username username
+     * @param string $database_username  username stored in database
+     * @param string $database_password  password stored in database
+     * @return bool  where the password is that of the given user
+     */
+    function checkValidSigninForZKP($username, $x, $y, $e, $n)
+    {
+        $db = $this->db;
+        $result = $this->getUserDetails($username);
         if(!$result) {
             return false;
         }
         $row = $db->fetchArray($result);
-
-        return ($username == $row['USER_NAME'] &&
-            crawlCrypt($password, $row['PASSWORD']) == $row['PASSWORD']) ;
+        $v = $row['ZKP_PASSWORD'];
+        $rp = bcmul($x, bcmod(bcpow($v, $e), $n));
+        $lp = bcmul($y, $y);
+        return ($username == $row['USER_NAME'] && bccomp($rp, $lp) == 0);
     }
 
     /**
@@ -167,6 +201,21 @@ class SigninModel extends Model
         return $result != false;
     }
 
+    /**
+     *  Changes the password of a given user in case of ZKP authentication
+     *
+     *  @param string $username username of user to change password of
+     *  @param string $password new password for user
+     *  @return bool update successful or not.
+     */
+    function changePasswordZKP($username, $password)
+    {
+        $sql = "UPDATE USERS SET ZKP_PASSWORD=? WHERE USER_NAME = ? ";
+        $result = $this->db->execute($sql,
+            array($password, $username) );
+        return $result != false;
+    }
+
 }
 
 ?>
\ No newline at end of file
diff --git a/models/user_model.php b/models/user_model.php
index bfbf246..5e4228c 100755
--- a/models/user_model.php
+++ b/models/user_model.php
@@ -291,6 +291,20 @@ class UserModel extends Model
         $db->execute($sql, array($status, $user_id));
     }
 
+    function addUserToUsersTable($username, $password, $firstname='',
+        $lastname='', $email='', $status = ACTIVE_STATUS, $zkp_password='')
+    {
+        $db = $this->db;
+        $sql = "INSERT INTO USERS(FIRST_NAME, LAST_NAME,
+            USER_NAME, EMAIL, PASSWORD, STATUS, HASH,
+            CREATION_TIME,ZKP_PASSWORD) VALUES (
+            ?, ?, ?, ?, ?, ?, ?, ?,?)";
+        $result = $db->execute($sql, array($firstname, $lastname,
+            $username, $email, crawlCrypt($password), $status,
+            crawlCrypt($username.AUTH_KEY.$creation_time),
+            $creation_time,$zkp_password));
+    }
+
     /**
      * Add a user with a given username and password to the list of users
      * that can login to the admin panel
@@ -303,16 +317,18 @@ class UserModel extends Model
      * @return mixed false if operation not successful, user_id otherwise
      */
     function addUser($username, $password, $firstname='', $lastname='',
-        $email='', $status = ACTIVE_STATUS)
+        $email='', $status = ACTIVE_STATUS, $zkp_password='')
     {
         $creation_time = microTimestamp();
         $db = $this->db;
         $sql = "INSERT INTO USERS(FIRST_NAME, LAST_NAME,
-            USER_NAME, EMAIL, PASSWORD, STATUS, HASH, CREATION_TIME) VALUES (
-            ?, ?, ?, ?, ?, ?, ?, ?)";
+            USER_NAME, EMAIL, PASSWORD, STATUS, HASH,
+            CREATION_TIME,ZKP_PASSWORD) VALUES (
+            ?, ?, ?, ?, ?, ?, ?, ?,?)";
         $result = $db->execute($sql, array($firstname, $lastname,
             $username, $email, crawlCrypt($password), $status,
-            crawlCrypt($username.AUTH_KEY.$creation_time), $creation_time));
+            crawlCrypt($username.AUTH_KEY.$creation_time),
+            $creation_time, $zkp_password));
         if(!$user_id = $this->getUserId($username)) {
             return false;
         }
@@ -377,4 +393,4 @@ class UserModel extends Model
         $this->db->execute($sql, $params);
     }
 }
-?>
+?>
\ No newline at end of file
diff --git a/scripts/basic.js b/scripts/basic.js
index 80e840a..616e4e9 100755
--- a/scripts/basic.js
+++ b/scripts/basic.js
@@ -102,6 +102,16 @@ function getPage(tag, url)
 }
 
 /*
+ *  Shorthand for document.createElement()
+ *
+ *  @param String input type element
+ */
+function ce(input)
+{
+    return document.createElement(input);
+}
+
+/*
  *  Shorthand for document.getElementById()
  *
  *  @param String id  the id of the DOM element one wants
@@ -153,4 +163,4 @@ function toggleDisplay(id)
         value = "block";
     }
     obj.style.display = value;
-}
+}
\ No newline at end of file
diff --git a/scripts/big_int.js b/scripts/big_int.js
new file mode 100644
index 0000000..29959d6
--- /dev/null
+++ b/scripts/big_int.js
@@ -0,0 +1,677 @@
+/**
+ *  SeekQuarry/Yioop --
+ *  Open Source Pure PHP Search Engine, Crawler, and Indexer
+ *
+ *  Copyright (C) 2009 - 2014  Chris Pollett chris@pollett.org
+ *
+ *  LICENSE:
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  END LICENSE
+ *
+ * @author Chris Pollett chris@pollett.org
+ * @package seek_quarry
+ * @subpackage javascript
+ * @license http://www.gnu.org/licenses/ GPL3
+ * @link http://www.seekquarry.com/
+ * @copyright 2009 - 2014
+ * @filesource
+ */
+
+/*
+ * Constant for number of bits per element
+ */
+var bits_per_element = 15;
+
+/*
+ * Constant to mask the overflow value
+ */
+var mask = 32767;
+
+/*
+ * Constant to define radix
+ */
+var radix = mask + 1;
+
+/*
+ *  To add bigInt and int number
+ *
+ *  @param bigInt x first operand
+ *  @param int n second operand
+ *  @return bigInt result
+ */
+function addInteger(x, n)
+{
+  var new_x = expandBigInt(x, x.length + 1);
+  addBigIntToInt(new_x, n);
+  return trimBigInt(new_x, 1);
+}
+
+/*
+ *  To return the bigInt with given number of leading zeroes
+ *
+ *  @param bigInt x input number
+ *  @param int k expected number of leading zeroes
+ *  @return bigInt result
+ */
+function trimBigInt(x, k)
+{
+  var i = x.length;
+  while(i > 0 && !x[i-1]){
+      i--;
+  }
+  var y = new Array(i + k);
+  copyBigIntToBigInt(y, x);
+  return y;
+}
+
+/*
+ *  To expand bigInt with atleast n elements.
+ *  adding zeroes if needed
+ *
+ *  @param bigInt x first operand
+ *  @param int n expected number of elements
+ *  @return bigInt result
+ */
+function expandBigInt(x, n)
+{
+  var bits = (x.length > n ? x.length : n) * bits_per_element;
+  var result = int2BigInt(0, bits, 0);
+  copyBigIntToBigInt(result, x);
+  return result;
+}
+
+/*
+ *  To convert normal int to BigInt.Pad the array with leading zeros so
+ *  that it has at least minSize elements
+ *
+ *  @param int t input number
+ *  @param int bits expected number of bits
+ *  @param int minSize minimum size of the BigInt.
+ *  @return Array stores the bigInt in bits_per_element-bit chunks,
+ *      little endian
+ */
+function int2BigInt(t, bits, minSize)
+{
+  var size_of_array = Math.ceil(bits / bits_per_element) + 1;
+  var buffer = new Array(size_of_array);
+  copyBigIntToInt(buffer, t);
+  return buffer;
+}
+
+/*
+ *  To copy one bigInt to another bigInt
+ *  x must be an array at least as big as y
+ *
+ *  @param bigInt x input number
+ *  @param bigInt bits expected number of bits
+ *  @return bigInt result
+ */
+function copyBigIntToBigInt(x, y)
+{
+  var length = x.length < y.length ? x.length : y.length;
+  for (var i = 0; i < length; i++){
+    x[i] = y[i];
+  }
+  for (var i = length; i < x.length ; i++){
+    x[i] = 0;
+  }
+}
+
+/*
+ *  To copy one bigInt to another int
+ *
+ *  @param bigInt x input number
+ *  @param  int n input number
+ *  @return bigInt result
+ */
+function copyBigIntToInt(x,n)
+{
+  var i, c;
+  for (c = n,i = 0; i < x.length; i++) {
+    x[i] = c & mask;
+    c >>= bits_per_element;
+  }
+}
+
+/*
+ *  To perform x=x+n where x is a bigInt and n is an integer
+ *
+ *  @param bigInt x input number
+ *  @param  int n input number
+ *  @return bigInt result of the summation
+ */
+function addBigIntToInt(x, n)
+{
+  var i, c, b;
+  x[0] += n;
+  c = 0;
+  for (i = 0; i < x.length; i++) {
+    c += x[i];
+    b = 0;
+    if (c < 0) {
+      b =- (c >> bits_per_element);
+      c += b * radix;
+    }
+    x[i] = c & mask;
+    c = (c >> bits_per_element) - b;
+    if (!c) {
+    return;
+    }
+  }
+}
+
+/*
+ *  To convert the string into the BigInt
+ *  Pad the array with leading zeros so that it has at least minSize elements.
+ *  The array will always have at least one leading zero, unless base=-1
+ *
+ *  @param String s input string
+ *  @param  int base base of the output number
+ *  @param  int minSize minimum size of the bigInt
+ *  @return bigInt
+ */
+function str2BigInt(s, base, min_size)
+{
+  var d, i, j, x, y, kk;
+  var digits_str = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
+  var k = s.length;
+  var x = int2BigInt(0, base * k, 0);
+   for (i = 0; i < k; i++) {
+    d = digits_str.indexOf(s.substring(i, i + 1), 0);
+    if (base <= 36 && d >= 36) {
+      d -= 26;
+    }
+    if (d >= base || d < 0) {
+      break;
+    }
+    multInt(x, base);
+    addBigIntToInt(x, d);
+  }
+  for (k = x.length; k > 0 && !x[k-1]; k --);
+  k = min_size > k+1 ? min_size : k+1;
+  y = new Array(k);
+  kk = k < x.length ? k : x.length;
+  for (i = 0; i < kk; i++){
+    y[i] = x[i];
+  }
+  for (;i < k;i++) {
+    y[i] = 0;
+  }
+  return y;
+}
+
+/*
+ *  convert a bigInt into a string in a given base, from base 2 up to base 95
+ *
+ *  @param bigInt x input number
+ *  @param  int base base of the output number
+ *  @return String result
+ */
+function bigInt2Str(x, base)
+{
+  var i,t,s = "";
+  var digits_str = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
+  var temp_array = new Array();
+  if (temp_array.length != x.length){
+    temp_array = dup(x);
+  } else {
+    copyBigIntToBigInt(temp_array, x);
+  }
+  while (!isZero(temp_array)) {
+      t = divInt(temp_array, base);  //t=s6 % base; s6=floor(s6/base);
+      s = digits_str.substring(t, t+1) + s;
+    }
+   if (s.length == 0){
+    s = "0";
+   }
+  return s;
+}
+
+/*
+ *  To make the copy of the bigInt
+ *
+ *  @param bigInt x input number
+ *  @return bigInt buffer copy of the bigInt x
+ */
+function dup(x)
+{
+ 
+  var buffer = new Array(x.length);
+  copyBigIntToBigInt(buffer, x);
+  return buffer;
+}
+
+/*
+ *  To check whether bigInt is zero or not.
+ *  Returns 0 if the bigInt is zero otherwise return 1
+ *  @param bigInt x input number
+ *  @return int
+ */
+function isZero(x) {
+  for (var i = 0; i < x.length; i++){
+    if (x[i]) {
+      return 0;
+    }
+  }
+  return 1;
+}
+
+/*
+ *  To do x=floor(x/n) for bigInt x and integer n, and
+ *
+ *  @param bigInt x numerator
+ *  @param int n denomenator
+ *  @return int r reminder
+ */
+function divInt(x, n)
+{
+  var r = 0, s;
+  for (var i = x.length-1; i >= 0; i--) {
+    s = r*radix + x[i];
+    x[i] = Math.floor(s/n);
+    r = s%n;
+  }
+  return r;
+}
+
+/*
+ *  To multiply bigInt with Int.
+ *
+ *  @param bigInt x  input number
+ *  @param int n input number
+ */
+function multInt(x, n)
+{
+  if (n == 0){
+    return;
+  }
+  var i, carry, borrow;
+  carry = 0;
+  for (i = 0; i < x.length ; i++) {
+    carry += x[i] * n;
+    borrow = 0;
+    if (carry < 0) {
+      borrow =- (carry >> bits_per_element);
+      carry += borrow * radix;
+    }
+    x[i] = carry & mask;
+    carry = (carry >> bits_per_element) - borrow;
+  }
+}
+
+/*
+ *  Performs x = x * y.
+ *
+ *  @param bigInt x  input number
+ *  @param bigInt y  input number
+ *  @return bigInt ans result of multiplication
+ */
+function mult(x, y)
+{
+
+  var ans = expandBigInt(x, x.length + y.length);
+  mult_(ans,y);
+  return trimBigInt(ans,1);
+}
+
+/*
+ *  Performs x = x * y. Stores the result in x
+ *
+ *  @param bigInt x  input number
+ *  @param bigInt y  input number
+ */
+function mult_(x, y) {
+  var result = new Array(2 * x.length);
+  copyBigIntToInt(result, 0);
+  for (var i = 0; i< y.length; i++){
+    if (y[i]){
+      linearCombShift(result, x, y[i], i);
+    }
+  }
+  copyBigIntToBigInt(x, result);
+}
+
+/*
+ *  To perform linear combination
+ *  for bigInts x and y, and integers a, b and ys
+ *
+ *  @param bigInt x  to store the result
+ *  @param bigInt y  input number
+ *  @param integer b  single digit of the second number
+ *  @param integer ys  to get bit shift operator
+ */
+function linearCombShift(x, y, b, ys)
+{
+  var i, c, k;
+  k = x.length < ys + y.length ? x.length : ys + y.length;
+  for(c = 0,i = ys; i < k; i++) {
+    c += x[i] + b * y[i-ys];
+    x[i] = c & mask;
+    c >>= bits_per_element;
+  }
+  for (i = k; c && i < x.length; i++) {
+    c  += x[i];
+    x[i] = c & mask;
+    c >>= bits_per_element;
+  }
+}
+
+/*
+ *  To perform divide operation
+ *
+ *  @param bigInt x  Dividend
+ *  @param bigInt y  Divisor
+ *  @param bigInt q  to store the quotient
+ *  @param integer r to store the reminder
+ */
+function divide(x, y, q, r)
+{
+  var kx, ky;
+  var i, j, y1, y2, c, a, b;
+  copyBigIntToBigInt(r, x);
+  for (ky = y.length; y[ky-1] == 0; ky--);
+  b = y[ky-1];
+  for (a = 0; b; a++)
+  b >>=1;
+  a = bits_per_element - a;
+  leftShift(y, a);
+  leftShift(r, a);
+  for (kx = r.length; r[kx-1] == 0 && kx > ky; kx--);
+  copyBigIntToInt(q, 0);
+  while (!greaterShift(y, r, kx - ky)) {
+    subShift(r, y, kx-ky);
+    q[kx - ky]++;
+  }
+  for (i = kx-1; i >= ky; i--) {
+      if (r[i] == y[ky-1]) {
+      q[i-ky] = mask;
+      } else {
+      q[i-ky] = Math.floor((r[i] * radix + r[i-1]) / y[ky-1]);
+      }
+      for (;;) {
+      y2 = (ky > 1 ? y[ky-2] : 0) * q[i-ky];
+      c = y2 >> bits_per_element;
+      y2 = y2 & mask;
+      y1 =c + q[i-ky] * y[ky-1];
+      c = y1 >> bits_per_element;
+      y1 = y1 & mask;
+      if (c == r[i] ? y1 == r[i-1] ? y2>(i > 1 ? r[i-2] : 0) : y1 > r[i-1] : c
+              > r[i]) {
+        q[i-ky]--;
+      } else {
+        break;
+      }
+    }
+    linearCombShift(r, y, -q[i-ky], i-ky);
+    if (negative(r)) {
+      addShift(r, y, i-ky);
+      q[i-ky]--;
+    }
+  }
+  rightShift(y, a);
+  rightShift(r, a);
+}
+
+/*
+ *  Performs left shift operation on bigInt by given nu,ber of bits
+ *
+ *  @param bigInt x  input number
+ *  @param integer n  number of bits to be shifted
+ */
+function leftShift(x, n)
+{
+  var i;
+  var length = Math.floor(n / bits_per_element);
+  if (length) {
+    for (i = x.length; i >= length; i--){
+      x[i] = x[i-length];
+    }
+    for (;i >= 0; i--) {
+      x[i] = 0;
+    }  
+    n %= bits_per_element;
+  }
+  if (!n) {
+    return;
+  }  
+  for (i = x.length-1; i > 0; i--) {
+  x[i] = mask & ((x[i] << n) | (x[i-1] >> (bits_per_element - n)));
+  }
+  x[i] = mask & (x[i] << n);
+}
+
+
+/*
+ *  Performs right shift operation on bigInt by given number of bits
+ *  @param bigInt x  input number
+ *  @param integer n  number of bits to be shifted
+ */
+function rightShift(x, n)
+{
+  var i;
+  var length = Math.floor(n / bits_per_element);
+  if (length) {
+    for (i = 0; i< x.length - length; i++){ 
+      x[i] = x[i + length];
+    }
+    for (; i< x.length; i++){
+      x[i] = 0;
+    }
+    n %= bits_per_element;
+  }
+  for (i = 0; i < x.length - 1; i++) {
+    x[i] = mask & ((x[i + 1] <<(bits_per_element - n)) | (x[i] >> n));
+  }
+  x[i] >>= n;
+}
+
+/*
+ *  To check whether BigInt is negative or not
+ *
+ *  @return integer output 1 if it is negative otherwise 0
+ */
+function negative(x)
+{
+  var result = (x[x.length - 1] >> (bits_per_element - 1)) & 1;
+  return result;
+}
+
+/*
+ *  To perfrom shift operation on y and add it to the x
+ *
+ *  @param bigInt x  first input number
+ *  @param bigInt y  second input number
+ *  @return integer output 1 if it is negative otherwise 0
+ */
+function addShift(x, y, ys)
+{
+  var i, sum;
+  length = x.length < ys + y.length ? x.length : ys + y.length;
+  for (c = 0,i = ys; i < length; i++) {
+    sum += x[i] + y[i-ys];
+    x[i] = sum & mask;
+    sum >>= bits_per_element;
+  }
+  for (i = length;sum && i < x.length; i++) {
+    sum += x[i];
+    x[i] = sum & mask;
+    sum >>= bits_per_element;
+  }
+}
+
+/*
+ *  It right shifts the x by given number of bits and check
+ *  whether it is greater than y
+ *
+ *  @param bigInt x  nonnegative input number
+ *  @param bigInt y  nonnegative input number
+ *  @param integer shift nonnegative integer
+ *  @return integer output 1 if the check passes otherwise returns 0
+ */
+function greaterShift(x, y, shift)
+{
+  var i;
+  var length = ((x.length + shift) < y.length) ? (x.length + shift) : y.length;
+  for (i = y.length - 1 - shift; i < x.length && i >= 0; i++)
+  {
+    if (x[i] > 0) {
+      return 1;
+    }
+  }
+  for (i = x.length - 1 + shift; i < y.length; i++)
+  {
+    if (y[i] > 0) {
+      return 0;
+    }
+  }
+  for (i = length-1; i >= shift; i--)
+  {
+    if (x[i-shift] > y[i]) {
+        return 1;
+    } else if (x[i-shift] < y[i]) {
+        return 0;
+    }
+ }
+  return 0;
+}
+
+/*
+ *  To left shift the y by given number of bits and performs
+ *  subtraction operation. The result is stored in x
+ *
+ *  @param bigInt x  BigInt number
+ *  @param bigInt y  BigInt number
+ *  @param integer shift number of shift bits
+ */
+function subShift(x, y, ys)
+{
+  var i, sum;
+  var length = x.length < ys + y.length ? x.length : ys + y.length;
+  for (c = 0,i = ys; i < length; i++) {
+    sum += x[i] - y[i-ys];
+    x[i] = sum & mask;
+    sum >>= bits_per_element;
+  }
+  for (i = length; sum && i < x.length; i++) {
+    sum += x[i];
+    x[i] = sum & mask;
+    sum >>= bits_per_element;
+  }
+}
+
+/*
+ *  Wrapper method for the mod operation
+ *
+ *  @param bigInt x  BigInt number
+ *  @param integer n  number
+ *  @return result result=x mod n
+ */
+function mod(x, n)
+{
+  var ans = dup(x);
+  modCalculation(ans, n);
+  var result = trim(ans, 1);
+  return result;
+}
+
+/*
+ *  To perform result= x mod n
+ *
+ *  @param bigInt x  BigInt number
+ *  @param integer n  number
+ *  @return result result=x mod n
+ */
+function modCalculation(x, n)
+{
+  var dividend = new Array(0);
+  var divisor = new Array(0);
+  if (dividend.length != x.length){
+	  dividend = dup(x);
+  }else{
+    copyBigIntToBigInt(dividend, x);
+  }
+  if (divisor.length != x.length){
+	  divisor = dup(x);
+  }
+  divide(dividend, n, divisor, x);
+}
+
+/*
+ *  To return x with exactly k leading zeroes
+ *
+ *  @param bigInt x  BigInt number
+ *  @param integer k  expected number of leading zeroes in x
+ *  @return result result=x mod n
+ */
+function trim(x, k)
+{
+  var i, y;
+  for (i= x.length; i > 0 && !x[i-1]; i--);
+  y = new Array(i + k);
+  copyBigIntToBigInt(y, x);
+  return y;
+}
+
+/*
+ *  Wrapper method for performing multplication modular opearion
+ *
+ *  @param bigInt x  BigInt number
+ *  @param bigInt y  BigInt number
+ *  @param bigInt n  modulus
+ *  @return bigInt x*y mod n
+ */
+function multMod(x, y, n)
+{
+  var result = expand(x, n.length);
+  multModOperation(result, y, n);
+  return trim(result, 1);
+}
+
+/*
+ *  To perform multplication modular opearion
+ *
+ *  @param bigInt x  BigInt number
+ *  @param bigInt y  BigInt number
+ *  @param bigInt n  modulus
+ *  @return bigInt x * y mod n
+ */
+ function multModOperation(x, y, n)
+ {
+  var input_number = new Array(2 * x.length);
+  copyBigIntToInt(input_number, 0);
+  for (var i=0; i< y.length; i++){
+    if (y[i]){
+      linearCombShift(input_number, x, y[i], i);
+    }
+  }
+  modCalculation(input_number, n);
+  copyBigIntToBigInt(x, input_number);
+}
+
+/*
+ *  To expand bigInt for the given number of elements.
+ *  Leadin zeros are added
+ *
+ *  @param bigInt x  BigInt number
+ *  @param integer n  expected number of elements
+ *  @return ans x * y mod n
+ */
+function expand(x, n)
+{
+  var ans = int2BigInt(0 ,(x.length > n ? x.length : n) * bits_per_element , 0);
+  copyBigIntToBigInt(ans, x);
+  return ans;
+}
\ No newline at end of file
diff --git a/scripts/classifiers.js b/scripts/classifiers.js
index f4a1071..5ea9177 100644
--- a/scripts/classifiers.js
+++ b/scripts/classifiers.js
@@ -836,4 +836,4 @@ var Classifier = (function() {
     }
 
     return self;
-})();
+})();
\ No newline at end of file
diff --git a/scripts/hash_captcha.js b/scripts/hash_captcha.js
new file mode 100644
index 0000000..0bb99bb
--- /dev/null
+++ b/scripts/hash_captcha.js
@@ -0,0 +1,75 @@
+/**
+ *  SeekQuarry/Yioop --
+ *  Open Source Pure PHP Search Engine, Crawler, and Indexer
+ *
+ *  Copyright (C) 2009 - 2014  Chris Pollett chris@pollett.org
+ *
+ *  LICENSE:
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  END LICENSE
+ *
+ * @author Chris Pollett chris@pollett.org
+ * @package seek_quarry
+ * @subpackage javascript
+ * @license http://www.gnu.org/licenses/ GPL3
+ * @link http://www.seekquarry.com/
+ * @copyright 2009 - 2014
+ * @filesource
+ */
+
+/*
+ *  To find the nonce for the input parameters given by the server.
+ *
+ *  @param Object nonce_for_string a DOM element to put the value of a nonce
+ *  @param Object random_string a DOM element to get the value of random_string
+ *  @param Object time a DOM element to get the value of the time
+ *  @param Object level a DOM element to get the value of a level
+ */
+function findNonce(nonce_for_string, random_string, time, level)
+{
+    if(elt(random_string).value) {
+        var random_string = elt(random_string).value;
+        var level = elt(level).value;
+        var time = elt(time).value;
+        var nonce = hashStamp(random_string, time, level);
+        var input = elt(nonce_for_string);
+        input.setAttribute('value', nonce);
+        input.setAttribute('type', 'hidden');
+    }
+}
+
+/*
+ *  This function calculates the sha1 on the strings until
+ *  numeber of a leading zeroes in the sha1 value matches with a level
+ *  parameter.
+ *
+ *  @param String random_string a string sent by the server
+ *  @param String time the time sent by the server
+ *  @param String level define number of leading zeroes
+ *  @return int nonce for which the sha1 of a string
+        produces the level number of a zeroes
+ */
+function hashStamp(random_string, time, level)
+{
+    var nonce = -1;
+    var input_string = '';
+    var pattern = new RegExp("^0{"+level+"}");
+    while (!generateSha1(input_string).match(pattern)) {
+        nonce = nonce + 1;
+        input_string = random_string +':'+time + ':' + nonce;
+    }
+    return nonce;
+}
\ No newline at end of file
diff --git a/scripts/hashcaptcha.js b/scripts/hashcaptcha.js
deleted file mode 100644
index 620dc24..0000000
--- a/scripts/hashcaptcha.js
+++ /dev/null
@@ -1,276 +0,0 @@
-/**
- *  SeekQuarry/Yioop --
- *  Open Source Pure PHP Search Engine, Crawler, and Indexer
- *
- *  Copyright (C) 2009 - 2014  Chris Pollett chris@pollett.org
- *
- *  LICENSE:
- *
- *  This program is free software: you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation, either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- *  END LICENSE
- *
- * @author Chris Pollett chris@pollett.org
- * @package seek_quarry
- * @subpackage javascript
- * @license http://www.gnu.org/licenses/ GPL3
- * @link http://www.seekquarry.com/
- * @copyright 2009 - 2014
- * @filesource
- */
-
-/*
- *  To find the nonce for the input parameters given by the server.
- *
- *  @param Object nonce_for_string a DOM element to put the value of a nonce
- *  @param Object random_string a DOM element to get the value of random_string
- *  @param Object time a DOM element to get the value of the time
- *  @param Object level a DOM element to get the value of a level
- */
-function findNonce(nonce_for_string, random_string, time, level)
-{
-    if(elt(random_string).value) {
-        var random_string = elt(random_string).value;
-        var level = elt(level).value;
-        var time = elt(time).value;
-        var nonce = hashStamp(random_string, time, level);
-        var input = elt(nonce_for_string);
-        input.setAttribute('value', nonce);
-        input.setAttribute('type', 'hidden');
-    }
-}
-
-/*
- *  This function calculates the sha1 on the strings until
- *  numeber of a leading zeroes in the sha1 value matches with a level
- *  parameter.
- *
- *  @param String random_string a string sent by the server
- *  @param String time the time sent by the server
- *  @param String level define number of leading zeroes
- *  @return int nonce for which the sha1 of a string
-        produces the level number of a zeroes
- */
-function hashStamp(random_string, time, level)
-{
-    var nonce = -1;
-    var input_string = '';
-    var pattern = new RegExp("^0{"+level+"}");
-    while (!generateSha1(input_string).match(pattern)) {
-        nonce = nonce + 1;
-        input_string = random_string +':'+time + ':' + nonce;
-    }
-    return nonce;
-}
-
-/*
- *  To calculate the sha1 on the given String.
- *
- *  @param String input string for the function
- *  @return String sha1 of the input string
- */
-function generateSha1(str)
-{
-    var n = ((str.toString().length + 8) >> 6) + 1;
-    var x = new Array();
-
-    for (var i = 0; i < n * 16; i++) {
-        x[i] = 0;
-    }
-
-    for (i = 0; i < str.toString().length; i++) {
-        x[i >> 2] +=
-            (str.toString().substr(i, 1)).charCodeAt(0) << (24 - (i % 4) * 8);
-    }
-
-    x[i >> 2] |= 0x80 << (24 - (i % 4) * 8);
-    x[n * 16 - 1] = str.toString().length * 8;
-
-    var a = 1732584193;
-    var b = -271733879;
-    var c = -1732584194;
-    var d = 271733878;
-    var e = -1009589776;
-
-    var w = new Array();
-
-    for (i = 0; i < x.length; i += 16) {
-        var olda = a;
-        var oldb = b;
-        var oldc = c;
-        var oldd = d;
-        var olde = e;
-
-        for (var j = 0; j < 80; j++) {
-            if (j < 16) {
-                w[j] = x[i + j];
-            } else {
-                w[j] = rotate(w[j - 3]^w[j - 8]^w[j - 14]^w[j - 16], 1);
-            }
-            var t = safeAdd(safeAdd(rotate(a, 5),
-                    hashOperationByIteration(j, b, c, d)),
-                    safeAdd(safeAdd(e, w[j]), constantForIteration(j)));
-            e = d;
-            d = c;
-            c = rotate(b, 30);
-            b = a;
-            a = t;
-        }
-
-        a = safeAdd(a, olda);
-        b = safeAdd(b, oldb);
-        c = safeAdd(c, oldc);
-        d = safeAdd(d, oldd);
-        e = safeAdd(e, olde);
-    }
-    return bin2hex(Array(a, b, c, d, e));
-}
-
-/*
- *  To conver a binary array into a hexadecimal value
- *
- *  @param array binarray array of a 5 binary values
- *  @return String hexadecimal
- */
-function bin2hex(binarray)
-{
-    var hex_case = 0;
-    var hex_tab = hex_case ? "0123456789ABCDEF" : "0123456789abcdef";
-    var str = "";
-    for (var i = 0; i < binarray.length * 4; i++) {
-        str += hex_tab.charAt((binarray[i >> 2] >> ((3 - i % 4) * 8 + 4))
-        & 0xF)+hex_tab.charAt((binarray[i >> 2] >> ((3 - i % 4) * 8))
-        & 0xF);
-    }
-    return str;
-}
-
-/*
- *  Calculate the one of the operand of a safe_add function
- *  based on the iteration value
- *
- *  @param int t value of iteration
- *  @param int b constant value
- *  @param int c constant value
- *  @param int d constant value
- *  @return int result of a xor value on constants
- */
-function hashOperationByIteration(t, b, c, d)
-{
-    if (t < 20) {
-        return (b & c) | ((~b) & d);
-    }
-    if (t < 40) {
-        return b^c^d;
-    }
-    if (t < 60) {
-        return (b & c) | (b & d) | (c & d);
-    }
-    return b^c^d;
-}
-
-/*
- *  To find a constant based on the iteration
- *
- *  @param int t value of iteration
- *  @return int constant value
- */
-function constantForIteration(t)
-{
-    if (t < 20) {
-        return 1518500249;
-    } else if (t < 40) {
-        return 1859775393;
-    } else if (t < 60) {
-        return -1894007588;
-    } else {
-        return -899497514;
-    }
-}
-
-/*
- *  To add integers, wrapping at 2^32
- *
- *  @param int x first operand of the add operation
- *  @param int y second operand of the add operation
- *  @return int result of the add operation
- */
-function safeAdd(x, y)
-{
-    var lsw = (x & 0xFFFF) + (y & 0xFFFF);
-    var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
-    return (msw << 16) | (lsw & 0xFFFF);
-}
-
-/*
- *  Bitwise rotate a 32-bit number
- *
- *  @param int num number on which rotation operation is performed
- *  @param int count define a number of times the shift opeation should perform
- *  @return int result of the rotate operation
- */
-function rotate(num, cnt)
-{
-    return (num << cnt) | zeroFill(num, 32 - cnt);
-}
-
-/*
- *  Use for a zero padding to the input number if a number is not 32 bit
- *
- *  @param int a input number
- *  @param int b to define how many leading zero should be added
- *  @return int 32 bit number
- */
-function zeroFill(a, b)
-{
-    var bin = dec2bin(a);
-
-    if (bin.toString().length < b) {
-        bin = 0;
-    } else {
-        var length = bin.toString().length;
-        bin = bin.toString().substr(0, length - b);
-    }
-
-    for (var i = 0; i < b; i++) {
-        bin = "0" + bin;
-    }
-    return bin2dec(bin);
-}
-
-/*
- *  Convert decimal number to binary string
- *
- *  @param int number input number
- *  @return string binary number
- */
-function dec2bin(number)
-{
-    if (number < 0) {
-        number = 0xFFFFFFFF + number + 1;
-    }
-    return parseInt(number, 10).toString(2);
-}
-
-/*
- *  Convert binary string to decimal number
- *
- *  @param string binary string input string
- *  @return int decimal number
- */
-function bin2dec(binary_string)
-{
-    binary_string = (binary_string + '').replace(/[^01]/gi, '');
-    return parseInt(binary_string, 2);
-}
\ No newline at end of file
diff --git a/scripts/mix.js b/scripts/mix.js
index e236e35..246424e 100644
--- a/scripts/mix.js
+++ b/scripts/mix.js
@@ -316,4 +316,4 @@ function drawNumResultSelect(i, selected_num) {
     }
     select += "</select>";
     return select;
-}
+}
\ No newline at end of file
diff --git a/scripts/sha1.js b/scripts/sha1.js
new file mode 100644
index 0000000..523f5b8
--- /dev/null
+++ b/scripts/sha1.js
@@ -0,0 +1,231 @@
+/**
+ *  SeekQuarry/Yioop --
+ *  Open Source Pure PHP Search Engine, Crawler, and Indexer
+ *
+ *  Copyright (C) 2009 - 2014  Chris Pollett chris@pollett.org
+ *
+ *  LICENSE:
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  END LICENSE
+ *
+ * @author Chris Pollett chris@pollett.org
+ * @package seek_quarry
+ * @subpackage javascript
+ * @license http://www.gnu.org/licenses/ GPL3
+ * @link http://www.seekquarry.com/
+ * @copyright 2009 - 2014
+ * @filesource
+ */
+
+ /*
+ *  To calculate the sha1 on the given String.
+ *
+ *  @param String input string for the function
+ *  @return String sha1 of the input string
+ */
+function generateSha1(str)
+{
+    var n = ((str.toString().length + 8) >> 6) + 1;
+    var x = new Array();
+
+    for (var i = 0; i < n * 16; i++) {
+        x[i] = 0;
+    }
+
+    for (i = 0; i < str.toString().length; i++) {
+        x[i >> 2] +=
+            (str.toString().substr(i, 1)).charCodeAt(0) << (24 - (i % 4) * 8);
+    }
+
+    x[i >> 2] |= 0x80 << (24 - (i % 4) * 8);
+    x[n * 16 - 1] = str.toString().length * 8;
+    //sha1 constants
+    var a = 1732584193;
+    var b = -271733879;
+    var c = -1732584194;
+    var d = 271733878;
+    var e = -1009589776;
+
+    var w = new Array();
+
+    for (i = 0; i < x.length; i += 16) {
+        var olda = a;
+        var oldb = b;
+        var oldc = c;
+        var oldd = d;
+        var olde = e;
+
+        for (var j = 0; j < 80; j++) {
+            if (j < 16) {
+                w[j] = x[i + j];
+            } else {
+                w[j] = rotate(w[j - 3]^w[j - 8]^w[j - 14]^w[j - 16], 1);
+            }
+            var t = safeAdd(safeAdd(rotate(a, 5),
+                    hashOperationByIteration(j, b, c, d)),
+                    safeAdd(safeAdd(e, w[j]), constantForIteration(j)));
+            e = d;
+            d = c;
+            c = rotate(b, 30);
+            b = a;
+            a = t;
+        }
+        a = safeAdd(a, olda);
+        b = safeAdd(b, oldb);
+        c = safeAdd(c, oldc);
+        d = safeAdd(d, oldd);
+        e = safeAdd(e, olde);
+    }
+    return bin2hex(Array(a, b, c, d, e));
+}
+
+/*
+ *  To conver a binary array into a hexadecimal value
+ *
+ *  @param array binarray array of a 5 binary values
+ *  @return String hexadecimal
+ */
+function bin2hex(binarray)
+{
+    var hex_case = 0;
+    var hex_tab = hex_case ? "0123456789ABCDEF" : "0123456789abcdef";
+    var str = "";
+    for (var i = 0; i < binarray.length * 4; i++) {
+        str += hex_tab.charAt((binarray[i >> 2] >> ((3 - i % 4) * 8 + 4))
+        & 0xF)+hex_tab.charAt((binarray[i >> 2] >> ((3 - i % 4) * 8))
+        & 0xF);
+    }
+    return str;
+}
+
+/*
+ *  Calculate the one of the operand of a safe_add function
+ *  based on the iteration value
+ *
+ *  @param int t value of iteration
+ *  @param int b constant value
+ *  @param int c constant value
+ *  @param int d constant value
+ *  @return int result of a xor value on constants
+ */
+function hashOperationByIteration(t, b, c, d)
+{
+    if (t < 20) {
+        return (b & c) | ((~b) & d);
+    }
+    if (t < 40) {
+        return b^c^d;
+    }
+    if (t < 60) {
+        return (b & c) | (b & d) | (c & d);
+    }
+    return b^c^d;
+}
+
+/*
+ *  To find a constant based on the iteration
+ *
+ *  @param int t value of iteration
+ *  @return int constant value
+ */
+function constantForIteration(t)
+{
+    if (t < 20) {
+        return 1518500249;
+    } else if (t < 40) {
+        return 1859775393;
+    } else if (t < 60) {
+        return -1894007588;
+    } else {
+        return -899497514;
+    }
+}
+
+/*
+ *  To add integers, wrapping at 2^32
+ *
+ *  @param int x first operand of the add operation
+ *  @param int y second operand of the add operation
+ *  @return int result of the add operation
+ */
+function safeAdd(x, y)
+{
+    var lsw = (x & 0xFFFF) + (y & 0xFFFF);
+    var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
+    return (msw << 16) | (lsw & 0xFFFF);
+}
+
+/*
+ *  Bitwise rotate a 32-bit number
+ *
+ *  @param int num number on which rotation operation is performed
+ *  @param int count define a number of times the shift opeation should perform
+ *  @return int result of the rotate operation
+ */
+function rotate(num, cnt)
+{
+    return (num << cnt) | zeroFill(num, 32 - cnt);
+}
+
+/*
+ *  Use for a zero padding to the input number if a number is not 32 bit
+ *
+ *  @param int a input number
+ *  @param int b to define how many leading zero should be added
+ *  @return int 32 bit number
+ */
+function zeroFill(a, b)
+{
+    var bin = dec2bin(a);
+
+    if (bin.toString().length < b) {
+        bin = 0;
+    } else {
+        var length = bin.toString().length;
+        bin = bin.toString().substr(0, length - b);
+    }
+
+    for (var i = 0; i < b; i++) {
+        bin = "0" + bin;
+    }
+    return bin2dec(bin);
+}
+
+/*
+ *  Convert decimal number to binary string
+ *
+ *  @param int number input number
+ *  @return string binary number
+ */
+function dec2bin(number)
+{
+    if (number < 0) {
+        number = 0xFFFFFFFF + number + 1;
+    }
+    return parseInt(number, 10).toString(2);
+}
+
+/*
+ *  Convert binary string to decimal number
+ *
+ *  @param string binary string input string
+ *  @return int decimal number
+ */
+function bin2dec(binary_string)
+{
+    binary_string = (binary_string + '').replace(/[^01]/gi, '');
+    return parseInt(binary_string, 2);
+}
\ No newline at end of file
diff --git a/scripts/zkp.js b/scripts/zkp.js
new file mode 100644
index 0000000..a85471d
--- /dev/null
+++ b/scripts/zkp.js
@@ -0,0 +1,199 @@
+/**
+ *  SeekQuarry/Yioop --
+ *  Open Source Pure PHP Search Engine, Crawler, and Indexer
+ *
+ *  Copyright (C) 2009 - 2014  Chris Pollett chris@pollett.org
+ *
+ *  LICENSE:
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  END LICENSE
+ *
+ * @author Chris Pollett chris@pollett.org
+ * @package seek_quarry
+ * @subpackage javascript
+ * @license http://www.gnu.org/licenses/ GPL3
+ * @link http://www.seekquarry.com/
+ * @copyright 2009 - 2014
+ * @filesource
+ */
+
+/*
+ *  Returns RSA like modulus.
+ *
+ *  @param Object fiatShamirModulus id of the fiatShamirModulus dom object
+ *  @return BigInteger RSA like modulus.
+ */
+function getN(fiatShamirModulus)
+{
+    var n = elt(fiatShamirModulus).value;
+    return str2BigInt(n, 10, 0);
+}
+
+/*
+ *  Generates Fiat shamir parameters such as x and y and append
+ *  with the input form
+ *
+ *  @param Object form1 id of the form
+ *  @param String sha1 of the user password
+ *  @param int e random value sent by the server. Either 0 or 1.
+ *  @param String user_name id of the form
+ *  @param String fiat shamir modulus
+ */
+function dynamicForm(form1, sha1, e, user_name, fiatShamirModulus)
+{
+    var form = elt(form1);
+    var n = getN(fiatShamirModulus);
+    var r = getR();
+    var x = multMod(r, r, n);
+    var y = getY(sha1, e, r, n);
+    var input_x = ce('input');
+    input_x.type = 'hidden';
+    input_x.name = 'x1';
+    input_x.value = bigInt2Str(x, 10);
+    var input_y = ce('input');
+    input_y.type = 'hidden';
+    input_y.name = 'y1';
+    input_y.value = bigInt2Str(y, 10);
+    var input_username = ce('input');
+    input_username.type = 'hidden';
+    input_username.name = 'u';
+    input_username.value = user_name;
+    form.appendChild(input_x);
+    form.appendChild(input_y);
+    form.appendChild(input_username);
+    form.submit();
+}
+
+/*
+ *  Generates Fiat shamir parameters Y. When user gives username, password
+ *  for the first time it stored the password on the cookie. From rest of
+ *  the Fiat shamir iteration it uses password stores on the client side
+ *  cookie.
+ *
+ *  @param String sha1 sha1 of the password
+ *  @param int e random value sent by the server. Either 0 or 1.
+ *  @param BigInt r random value picked by the client
+ *  @param BigInt n RSA like modulus
+ *  @return BigInt y fiat-shamir parameter Y.
+ */
+function getY(sha1, e, r, n)
+{
+    var s = str2BigInt(sha1, 16, 0);
+    var se;
+    if (e == 0) {
+        se = '1';
+        se = str2BigInt(se, 10, 0);
+    } else {
+        se = s;
+    }
+    y = multMod(r, se, n);
+    return y;
+}
+
+/*
+ *  Generates random number and convert into BigInteger.
+ *
+ *  @return BigInteger final_r random BigInteger
+ */
+function getR()
+{
+    var r = Math.floor((Math.random() * 21474) + 1);
+    r = r.toString();;
+    var final_r = str2BigInt(r, 10, 0);
+    return final_r;
+}
+
+/*
+ *  Generates Fiat shamir parameters such as x and y and append
+ *  with the input form. This method calls first time when user
+ *  provides user name and password
+ *
+ *  @param Object form1 id of the form
+ *  @param String username username provided by user
+ *  @param String password1 password provided by user
+ *  @param int e random value send by the server. Either 0 or 1.
+ *  @param int auth_count number of Fiat-Shamir iterations
+ */
+function generateKeys(form1, username, password1, fiatShamirModulus, e, auth_count)
+{
+    var password = elt(password1).value;
+    var u = elt(username).value;
+    var token = elt('YIOOP_TOKEN').value;
+    var sha1 = generateSha1(password);
+    var n = new getN(fiatShamirModulus);
+    for (var i = 0; i < auth_count - 1; i++) {
+        var r = getR();
+        var x = multMod(r, r, n);
+        var y = getY(sha1, e, r, n);
+        var x1 = bigInt2Str(x, 10);
+        var y1 = bigInt2Str(y, 10);
+        sendFiatShamirParameters(x1, y1, u, token);
+        var e_temp = elt("saltValue").value;
+        e_temp = e_temp + '';
+        e = parseInt(e_temp);
+        if(e == -1){
+            e = 1;
+            break;
+        }
+    }
+    elt(password1).value = null;
+    dynamicForm(form1, sha1, e, u, fiatShamirModulus);
+}
+
+/*
+ *  Make AJAX request to the server. This method sends Fiat-Shamir
+ *  parameters and receives parameter e from server
+ *
+ *  @param BigInt x1 Fiat-Shamir parameter x
+ *  @param BigInt y1 Fiat-Shamir parameter y
+ *  @param String u username provided by user
+ *  @param String token CSRF token sent by the server
+ */
+function sendFiatShamirParameters(x1, y1, u, token)
+{
+    var http = new XMLHttpRequest();
+    var url = "./?c=admin";
+    var params = "x1=" + x1 + "&y1=" + y1 +"&u=" + u + "&YIOOP_TOKEN=" + token;
+    http.open("POST", url, false);
+    http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
+    http.setRequestHeader("Content-length", params.length);
+    http.setRequestHeader("Connection", "close");
+    http.onreadystatechange = function () {
+        if (http.readyState == 4 && http.status == 200) {
+            elt("saltValue").value = http.responseText;
+        }
+    }
+    http.send(params);
+}
+
+/*
+ *  This function is used during create account module and when
+ *  authentication mode is ZKP.
+ *
+ *  @param String password password provided by user
+ *  @param String repassword repassword provided by user
+ */
+function registration(password, repassword, fiatShamirModulus)
+{
+    var password1 = elt(password);
+    var repassword1 = elt(repassword);
+    var sha1 = generateSha1(password1.value);
+    var x = str2BigInt(sha1, 16, 0);
+    var n = getN(fiatShamirModulus);
+    var z = multMod(x, x, n);
+    password1.value = bigInt2Str(z, 10);
+    repassword1.value = bigInt2Str(z, 10);
+}
diff --git a/tests/sha1_test.php b/tests/sha1_test.php
index 8b8136c..a18b144 100644
--- a/tests/sha1_test.php
+++ b/tests/sha1_test.php
@@ -66,7 +66,8 @@ class Sha1Test extends JavaScriptTest
         <div id="sha1Test">
         </div>
         <head>
-        <script type="text/javascript" src="../scripts/hashcaptcha.js" ></script>
+        <script type="text/javascript" src="../scripts/sha1.js" ></script>
+        <script type="text/javascript" src="../scripts/hash_captcha.js" ></script>
         <script type="text/javascript">
         var input_array = <?php echo $js_array; ?>;
         var total_test_cases = <?php echo self::NUM_TEST_CASES?>;
diff --git a/views/elements/manageusers_element.php b/views/elements/manageusers_element.php
index fcc8efa..3c8df34 100644
--- a/views/elements/manageusers_element.php
+++ b/views/elements/manageusers_element.php
@@ -193,7 +193,15 @@ class ManageusersElement extends Element
             e("<h2>".tl('manageusers_element_add_user'). "</h2>");
         }
         ?>
-        <form id="user-form" method="post" action='#' autocomplete="off">
+       <?php if($data['AUTHENTICATION_MODE'] == ZKP_AUTHENTICATION) { ?>
+                <form action="" method="post"
+                    onsubmit="registration('pass-word','retype-password',
+                             'fiatShamirModulus')">
+                <input type="hidden" name="fiatShamirModulus" id="fiatShamirModulus"
+                    value="<?php e($data['FIAT_SHAMIR_MODULUS']) ?>"/>
+       <?php } else { ?>
+               <form id="user-form" method="post" action='#' autocomplete="off">
+       <?php }?>
         <input type="hidden" name="c" value="admin" />
         <input type="hidden" name="<?php e(CSRF_TOKEN); ?>" value="<?php
             e($data[CSRF_TOKEN]); ?>" />
diff --git a/views/elements/serversettings_element.php b/views/elements/serversettings_element.php
index 2d4bb08..334fa7c 100644
--- a/views/elements/serversettings_element.php
+++ b/views/elements/serversettings_element.php
@@ -246,8 +246,22 @@ class ServersettingsElement extends Element
                 </label></legend>
                     <?php $this->view->helper("options")->render(
                         "captcha-setting", "CAPTCHA_MODE",
-                       $data['CAPTCHA_MODES'],
-                     $data['CAPTCHA_MODE']);
+                         $data['CAPTCHA_MODES'],
+                         $data['CAPTCHA_MODE']);
+                ?>
+            </fieldset>
+            </div>
+            <div class="top-margin">
+            <fieldset>
+                <legend><label
+                for="authentication-mode"><?php
+                e(tl('serversettings_element_authentication_mode'));
+                ?>
+                </label></legend>
+                    <?php $this->view->helper("options")->render(
+                        "authentication-mode", "AUTHENTICATION_MODE",
+                         $data['AUTHENTICATION_MODES'],
+                         $data['AUTHENTICATION_MODE']);
                 ?>
             </fieldset>
             </div>
diff --git a/views/recover_view.php b/views/recover_view.php
index 57fe7e6..1444ccb 100644
--- a/views/recover_view.php
+++ b/views/recover_view.php
@@ -78,7 +78,19 @@ class RecoverView extends View
             <form method="post" action="#">
             <input type="hidden" name="c" value="register" />
             <input type="hidden" name="a" value="<?php e($activity); ?>" />
+            <?php if(isset($_SESSION["random_string"])) { ?>
+            <input type='hidden' name='nonce_for_string'
+            id='nonce_for_string' />
+            <input type='hidden' name='random_string' id='random_string'
+                value='<?php e($_SESSION["random_string"]);?>' />
+            <input type='hidden' name='time1' id='time1'
+                value='<?php e($_SESSION["request_time"]);?>' />
+            <input type='hidden' name='level' id='level'
+                value='<?php e($_SESSION["level"]);?>' />
+            <input type='hidden' name='time' id='time'
+                value='<?php e(time());?>'/>
             <?php
+            }
             if(isset($data["RECOVER_COMPLETE"])) { ?>
                 <input type="hidden" name="user" value="<?php
                     e($data['user']); ?>" />
@@ -139,32 +151,39 @@ class RecoverView extends View
                             tl('register_view_account_recovery')
                                 =>$data['RECOVERY']);
                     } else {
-                        $question_sets = array(
-                            tl('register_view_human_check')=>$data['CAPTCHAS']);
+                       if(isset($_SESSION["random_string"])) {
+                            $question_sets = array();
+                        } else {
+                            $question_sets = array(
+                            tl('register_view_human_check')=>
+                            $data['CAPTCHAS']);
+                        }
                     }
-                    $i = 0;
-                    foreach($question_sets as $name => $set) {
-                        $first = true;
-                        $num = count($set);
-                        foreach($set as $question) {
-                            if($first) { ?>
-                                <tr><th class="table-label"
-                                    rowspan='<?php e($num); ?>'><?php
-                                    e($name);
-                                ?></th><td class="table-input border-top">
-                            <?php
-                            } else { ?>
-                                <tr><td class="table-input">
-                            <?php
+                    if(isset($_SESSION["random_string"])) {
+                        $i = 0;
+                        foreach($question_sets as $name => $set) {
+                            $first = true;
+                            $num = count($set);
+                            foreach($set as $question) {
+                                if($first) { ?>
+                                    <tr><th class="table-label"
+                                        rowspan='<?php e($num); ?>'><?php
+                                        e($name);
+                                    ?></th><td class="table-input border-top">
+                                <?php
+                                } else { ?>
+                                    <tr><td class="table-input">
+                                <?php
+                                }
+                                $this->helper("options")->render(
+                                    "question-$i", "question_$i",
+                                    $question, $data["question_$i"]);
+                                $first = false;
+                                e(in_array("question_$i", $missing)
+                                    ?'<span class="red">*</span>':'');
+                                e("</td></tr>");
+                                $i++;
                             }
-                            $this->helper("options")->render(
-                                "question-$i", "question_$i",
-                                $question, $data["question_$i"]);
-                            $first = false;
-                            e(in_array("question_$i", $missing)
-                                ?'<span class="red">*</span>':'');
-                            e("</td></tr>");
-                            $i++;
                         }
                     }
                     ?>
@@ -191,6 +210,15 @@ class RecoverView extends View
         </div>
         </div>
         <div class='tall-landing-spacer'></div>
+        <?php  if(isset($_SESSION["random_string"])) {?>
+        <script type="text/javascript" >
+            document.addEventListener('DOMContentLoaded', function() {
+            var body = tag(body);
+            body.onload = findNonce('nonce_for_string', 'random_string'
+                , 'time', 'level');
+            }, false);
+        </script>
         <?php
+        }
     }
 }
\ No newline at end of file
diff --git a/views/register_view.php b/views/register_view.php
index 782491a..df0d471 100755
--- a/views/register_view.php
+++ b/views/register_view.php
@@ -73,7 +73,16 @@ class RegisterView extends View
                 src="<?php e($logo); ?>" alt="Yioop!"/></a>
                 <span> - <?php e(tl('register_view_create_account'));
                 ?></span></h1>
-            <form method="post" action="#">
+            <?php if($data['AUTHENTICATION_MODE'] == ZKP_AUTHENTICATION) {  ?>
+                        <form action="" method="post"
+                            onsubmit="registration('password', 'repassword',
+                            'fiatShamirModulus')">
+                        <input type="hidden" name="fiatShamirModulus"
+                            id="fiatShamirModulus"
+                            value="<?php e($data['FIAT_SHAMIR_MODULUS']) ?>"/>
+            <?php } else { ?>
+                        <form method="post" action="#">
+            <?php } ?>
             <input type="hidden" name="c" value="register" />
             <input type="hidden" name="a" value="processAccountData" />
             <?php  if(isset($_SESSION["random_string"])) { ?>
@@ -233,6 +242,7 @@ class RegisterView extends View
         </div>
         </div>
         <div class='tall-landing-spacer'></div>
+         <?php  if(isset($_SESSION["random_string"])) {?>
         <script type="text/javascript" >
             document.addEventListener('DOMContentLoaded', function() {
             var body = tag(body);
@@ -242,5 +252,6 @@ class RegisterView extends View
         </script>
     <?php
         }
+      }
     }
     ?>
diff --git a/views/signin_view.php b/views/signin_view.php
index 55b79e9..d5ef523 100755
--- a/views/signin_view.php
+++ b/views/signin_view.php
@@ -66,7 +66,17 @@ class SigninView extends View
         <h1 class="logo"><a href="./?<?php e(CSRF_TOKEN."=".$data[CSRF_TOKEN])
                 ?>"><img src="<?php e($logo); ?>" alt="Yioop!"
                 /></a><span> - <?php e(tl('signin_view_signin')); ?></span></h1>
-        <form method="post" action="#">
+        <?php if (isset($data['AUTH_ITERATION'])) { ?>
+                <form  method="post" id="form1" action="./?c=admin"
+                    onsubmit="generateKeys('form1','username', 'password',
+                    'fiatShamirModulus', '<?php e($_SESSION['SALT_VALUE']); ?>',
+                    <?php e($data['AUTH_ITERATION']); ?>)" >
+                    <input type="hidden" name="fiatShamirModulus"
+                        id="fiatShamirModulus"
+                        value="<?php e($data['FIAT_SHAMIR_MODULUS']) ?>"/>
+        <?php } else {?>
+                <form  id="form1" method="post" action="#">
+        <?php } ?>
         <div class="login">
             <table>
             <tr>
@@ -80,8 +90,9 @@ class SigninView extends View
                 e(tl('signin_view_password')); ?></label>:</b></td><td
                 class="table-input"><input id="password" type="password"
                 class="narrow-field" maxlength="80" name="p" /></td>
-            <td><input type="hidden" name="<?php e(CSRF_TOKEN);?>" value="<?php
-                e($data[CSRF_TOKEN]); ?>" />
+            <td><input type="hidden" name="<?php e(CSRF_TOKEN);?>"
+                    id="<?php e(CSRF_TOKEN);?>" 
+                    value="<?php e($data[CSRF_TOKEN]); ?>" />
             </td>
             </tr>
             <tr><td>&nbsp;</td><td class="center">
@@ -89,9 +100,9 @@ class SigninView extends View
                 e(tl('signin_view_login')); ?></button>
             </td><td>&nbsp;</td></tr>
             </table>
+            <input type="hidden" name="saltValue" id="saltValue" />
         </div>
         </form>
-
         <div class="signin-exit">
             <ul>
                 <?php
-- 
1.8.0.msysgit.0

