_binary From 25b03883c3d7dbf51ffb9d5dde269fc893e645f9 Mon Sep 17 00:00:00 2001
From: Akash Patel <akash3664@yahoo.com>
Date: Sun, 13 Apr 2014 00:43:15 -0700
Subject: [PATCH] implemented zkp

---
 configs/config.php                                 |   5 +-
 configs/createdb.php                               |   9 +
 controllers/admin_controller.php                   |  79 ++-
 controllers/components/accountaccess_component.php |   4 +-
 controllers/components/blogmixes_component.php     |   4 +-
 controllers/components/crawl_component.php         |   2 +-
 controllers/components/system_component.php        |   8 +-
 controllers/controller.php                         |   2 +-
 controllers/register_controller.php                |  92 ++-
 controllers/settings_controller.php                |   2 +-
 lib/locale_functions.php                           |   2 +-
 lib/upgrade_functions.php                          |  26 +
 locale/en-US/configure.ini                         |   9 +
 models/crawl_model.php                             |   2 +-
 models/group_model.php                             |   2 +-
 models/machine_model.php                           |   2 +-
 models/model.php                                   |  54 +-
 models/profile_model.php                           |  27 +-
 models/role_model.php                              |   2 +-
 models/signin_model.php                            |  55 +-
 models/source_model.php                            |   2 +-
 models/user_model.php                              |  34 +-
 scripts/BigInt2.js                                 | 559 ++++++++++++++++++
 scripts/BigInt3.js                                 | 656 +++++++++++++++++++++
 scripts/basic.js                                   |  12 +-
 scripts/hashcaptcha.js                             | 201 -------
 scripts/sha1.js                                    | 232 ++++++++
 scripts/zkp.js                                     | 179 ++++++
 views/crawlstatus_view.php                         |   2 +-
 views/elements/editmix_element.php                 |   2 +-
 views/elements/groupfeed_element.php               |   2 +-
 views/elements/manageaccount_element.php           |   2 +-
 views/elements/manageclassifiers_element.php       |   4 +-
 views/elements/managecrawls_element.php            |   2 +-
 views/elements/managegroups_element.php            |  12 +-
 views/elements/manageusers_element.php             |  18 +-
 views/elements/mixcrawls_element.php               |   4 +-
 views/elements/serversettings_element.php          |  16 +-
 views/elements/signin_element.php                  |   2 +-
 views/helpers/feeds_helper.php                     |   2 +-
 views/helpers/pagingtable_helper.php               |   2 +-
 views/layouts/web_layout.php                       |   2 +-
 views/recover_view.php                             |  76 ++-
 views/register_view.php                            |  17 +-
 views/settings_view.php                            |   2 +-
 views/signin_view.php                              |  20 +-
 46 files changed, 2090 insertions(+), 360 deletions(-)
 create mode 100644 scripts/BigInt2.js
 create mode 100644 scripts/BigInt3.js
 create mode 100644 scripts/sha1.js
 create mode 100644 scripts/zkp.js

diff --git a/configs/config.php b/configs/config.php
index fbd2f81..115d3bc 100755
--- a/configs/config.php
+++ b/configs/config.php
@@ -158,6 +158,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);
@@ -645,4 +646,4 @@ define('GROUP_READ', 2);
  *   read items posted to the group as well as post new items
  */
 define('GROUP_READ_WRITE', 3);
-?>
+?>
\ No newline at end of file
diff --git a/configs/createdb.php b/configs/createdb.php
index ed6d18e..0054c8a 100755
--- a/configs/createdb.php
+++ b/configs/createdb.php
@@ -101,6 +101,15 @@ $sql ="INSERT INTO USERS VALUES (".ROOT_ID.", 'admin', 'admin','root',
         "', '".crawlCrypt('root'.AUTH_KEY.$creation_time)."','$creation_time')";
 
 $db->execute($sql);
+
+//default account is root without a password in case of ZKP system
+$sql ="INSERT INTO USERS_ZKP VALUES (".ROOT_ID.", 'admin', 'admin','root',
+        'root@dev.null', '15521307879384003485799427706675365031492835831
+        81838649171366591924563160025427690176245139603025','".ACTIVE_STATUS."'
+        , '".crawlCrypt('root'.AUTH_KEY.$creation_time)."','$creation_time')";
+
+$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',
diff --git a/controllers/admin_controller.php b/controllers/admin_controller.php
index 3565a3d..d82c02c 100755
--- a/controllers/admin_controller.php
+++ b/controllers/admin_controller.php
@@ -62,6 +62,13 @@ foreach(glob(BASE_DIR."/lib/processors/*_processor.php") as $filename) {
 class AdminController extends Controller implements CrawlConstants
 {
     /**
+     * Number of Fiat-shamir iteration in case of zero knowledge authentication
+     * syste,
+     * @var int
+     */
+    const NUM_FIAT_SHAMIR_ITERATION = 8;
+
+    /**
      * Says which activities (roughly methods invoke from the web) this
      * controller will respond to (note: more activities will be loaded from
      * components)
@@ -88,6 +95,15 @@ class AdminController extends Controller implements CrawlConstants
     function processRequest()
     {
         $data = array();
+        $profile_model = $this->model("profile");
+        $profile = $profile_model->getProfile(WORK_DIRECTORY);
+        if($profile['AUTHENTICATION_MODE'] == 'zkp_authentication') {
+           if (!isset($_SESSION["COUNT"])) {
+                $_SESSION['COUNT'] = 1;
+           }
+        } else {
+                $_SESSION['COUNT'] = self::NUM_FIAT_SHAMIR_ITERATION;
+        }
 
         if(!PROFILE) {
             return $this->configureRequest();
@@ -116,32 +132,36 @@ 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;
-                }
-
-                $_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";
+                $_SESSION['USER_NAME'] = $_REQUEST['u'];
+                if ($_SESSION['COUNT'] == self::NUM_FIAT_SHAMIR_ITERATION) {
+                    $_SESSION['COUNT'] = 1;
+                    $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 {
+                    $_SESSION['COUNT'] = 1;
+                    $data['SCRIPT'] = "doMessage('<h1 class=\"red\" >".
+                        tl('admin_controller_login_failed')."</h1>');";
                     unset($_SESSION['USER_ID']);
                 }
-                $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 +177,15 @@ class AdminController extends Controller implements CrawlConstants
             $data["ADMIN"] = false;
         }
         if($view == 'signin') {
+            if (isset($_SESSION['salt_value'])) {
+                unset($_SESSION['salt_value']);
+            }
+            $profile_model = $this->model("profile");
+            $profile = $profile_model->getProfile(WORK_DIRECTORY);
+            if($profile['AUTHENTICATION_MODE'] == 'zkp_authentication') {
+                $_SESSION['salt_value'] = rand(0, 1);
+                $data['INCLUDE_SCRIPTS'] = array("zkp","BigInt2","BigInt3","sha1");
+            }
             unset($_SESSION['USER_ID']);
             $data[CSRF_TOKEN] = $this->generateCSRFToken(
                 $_SERVER['REMOTE_ADDR']);
@@ -400,4 +429,4 @@ class AdminController extends Controller implements CrawlConstants
         }
     }
 }
-?>
+?>
\ No newline at end of file
diff --git a/controllers/components/accountaccess_component.php b/controllers/components/accountaccess_component.php
index faefde4..16ab3ba 100644
--- a/controllers/components/accountaccess_component.php
+++ b/controllers/components/accountaccess_component.php
@@ -311,7 +311,7 @@ class AccountaccessComponent extends Component
                                         $update = true;
                                     }
                                 }
-                                $data['CURRENT_USER'][$field] = 
+                                $data['CURRENT_USER'][$field] =
                                     $user[$upper_field];
                             } else if($_REQUEST["password"] !=
                                 $_REQUEST["retypepassword"]) {
@@ -1444,4 +1444,4 @@ class AccountaccessComponent extends Component
             }
         }
     }
-}
+}
\ No newline at end of file
diff --git a/controllers/components/blogmixes_component.php b/controllers/components/blogmixes_component.php
index d3019ba..5ec741b 100644
--- a/controllers/components/blogmixes_component.php
+++ b/controllers/components/blogmixes_component.php
@@ -321,7 +321,7 @@ class BlogmixesComponent extends Component implements CrawlConstants
             if($item['OWNER_ID'] == $user_id || $user_id == ROOT_ID) {
                 $page['MEMBER_ACCESS'] = GROUP_READ_WRITE;
             }
-            if(!$recent_found && $time - $item["PUBDATE"] < 
+            if(!$recent_found && $time - $item["PUBDATE"] <
                 5 * self::ONE_MINUTE) {
                 $recent_found = true;
                 $data['SCRIPT'] .= 'doUpdate();';
@@ -731,4 +731,4 @@ class BlogmixesComponent extends Component implements CrawlConstants
         }
         $data['SCRIPT'] .= ']; drawFragments();';
     }
-}
+}
\ No newline at end of file
diff --git a/controllers/components/crawl_component.php b/controllers/components/crawl_component.php
index 1bb6c10..63d73a1 100644
--- a/controllers/components/crawl_component.php
+++ b/controllers/components/crawl_component.php
@@ -1465,4 +1465,4 @@ class CrawlComponent extends Component implements CrawlConstants
             "switchSourceType()";
         return $data;
     }
-}
+}
\ No newline at end of file
diff --git a/controllers/components/system_component.php b/controllers/components/system_component.php
index da3b744..f4fa203 100644
--- a/controllers/components/system_component.php
+++ b/controllers/components/system_component.php
@@ -612,6 +612,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(
@@ -1046,4 +1052,4 @@ EOD;
      }
 
 
-}
+}
\ No newline at end of file
diff --git a/controllers/controller.php b/controllers/controller.php
index 854abb9..63a28a7 100755
--- a/controllers/controller.php
+++ b/controllers/controller.php
@@ -560,4 +560,4 @@ abstract class Controller
         return true;
     }
 }
-?>
+?>
\ No newline at end of file
diff --git a/controllers/register_controller.php b/controllers/register_controller.php
index ede9a69..6238be2 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 (isset($_SESSION['salt_value'])) {
+                unset($_SESSION['salt_value']);
+        }
+        if($profile['AUTHENTICATION_MODE'] == 'zkp_authentication') {
+            $_SESSION['salt_value'] = rand(0, 1);
+            $_SESSION['COUNT'] = 1;
+            $data['INCLUDE_SCRIPTS'] = array("sha1","zkp","BigInt2","BigInt3");
+        }
+        if($profile['CAPTCHA_MODE'] == HASH_CAPTCHA) {
+            if(isset($data['INCLUDE_SCRIPTS'])) {
+                array_push($data['INCLUDE_SCRIPTS'], "hashcaptcha");
+            } else {
+               $data['INCLUDE_SCRIPTS'] = array("sha1","hashcaptcha");
+            }
+        }
         //used to ensure that we have sessions active
         $_SESSION['REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR'];
         $this->displayView($view, $data);
@@ -439,6 +458,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 +474,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>');";
@@ -769,8 +792,20 @@ 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","BigInt2","BigInt3");
+         }
+         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'],"hashcaptcha");
+            } else {
+                $data['INCLUDE_SCRIPTS'] = array("hashcaptcha","sha1");
+            }
             $time = time();
             $_SESSION["request_time"] = $time;
             $_SESSION["level"] = self::HASH_CAPTCHA_LEVEL;
@@ -1013,6 +1048,7 @@ class RegisterController extends Controller implements CrawlConstants
      */
     function getCleanFields(&$data)
     {
+        
         $fields = $this->register_fields;
         if(isset($data["check_fields"])) {
             $fields = $data["check_fields"];
@@ -1050,25 +1086,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/controllers/settings_controller.php b/controllers/settings_controller.php
index d6d2120..e1d9f71 100755
--- a/controllers/settings_controller.php
+++ b/controllers/settings_controller.php
@@ -149,4 +149,4 @@ class SettingsController extends Controller
 
 }
 
-?>
+?>
\ No newline at end of file
diff --git a/lib/locale_functions.php b/lib/locale_functions.php
index caa3b6d..902190a 100755
--- a/lib/locale_functions.php
+++ b/lib/locale_functions.php
@@ -496,4 +496,4 @@ function formatDateByLocale($timestamp, $locale_tag)
             return date("F d Y H:i", intval($timestamp));
     }
 }
-?>
+?>
\ No newline at end of file
diff --git a/lib/upgrade_functions.php b/lib/upgrade_functions.php
index 5d99653..d712dff 100644
--- a/lib/upgrade_functions.php
+++ b/lib/upgrade_functions.php
@@ -145,6 +145,7 @@ function upgradeDatabaseVersion2(&$db)
 {
     $db->execute("UPDATE VERSION SET ID=2 WHERE ID=1");
     $db->execute("ALTER TABLE USERS ADD UNIQUE ( USER_NAME )" );
+    $db->execute("ALTER TABLE USERS_ZKP ADD UNIQUE ( USER_NAME )" );
     $db->execute("INSERT INTO LOCALE VALUES (
         17, 'kn', 'ಕನ್ನಡ', 'lr-tb')");
     $db->execute("INSERT INTO LOCALE VALUES (
@@ -600,11 +601,18 @@ function upgradeDatabaseVersion19(&$db)
         "DB_PASSWORD" => DB_PASSWORD);
     $sql = "ALTER TABLE USERS RENAME TO USER_OLD";
     $db->execute($sql);
+    $sql = "ALTER TABLE USERS_ZKP RENAME TO USER_ZKP_OLD";
+    $db->execute($sql);
     $auto_increment = $db->autoIncrement($dbinfo);
     $db->execute("CREATE TABLE USERS(USER_ID INTEGER PRIMARY KEY $auto_increment,
         FIRST_NAME VARCHAR(16), LAST_NAME VARCHAR(16),
         USER_NAME VARCHAR(16) UNIQUE, EMAIL VARCHAR(60),
         PASSWORD CHAR(60), STATUS INTEGER, HASH CHAR(60))");
+    $db->execute( "CREATE TABLE USERS_ZKP(USER_ID $serial
+         PRIMARY KEY $auto_increment,FIRST_NAME VARCHAR(16),
+         LAST_NAME VARCHAR(16), USER_NAME VARCHAR(16) UNIQUE,
+         EMAIL VARCHAR(60), PASSWORD CHAR(200),
+         STATUS INTEGER, HASH CHAR(300),CREATION_TIME VARCHAR(20))",);
     $sql = "SELECT USER_ID, USER_NAME FROM USER_OLD";
     $result = $db->execute($sql);
     while($row = $db->fetchArray($result)) {
@@ -620,11 +628,29 @@ function upgradeDatabaseVersion19(&$db)
             $creation_time."')";
         $db->execute($sql);
     }
+    $sql = "SELECT USER_ID, USER_NAME FROM USER_ZKP_OLD";
+    $result = $db->execute($sql);
+    while($row = $db->fetchArray($result)) {
+        $status = ($row['USER_NAME'] == 'root') ? ACTIVE_STATUS :
+            INACTIVE_STATUS;
+        $creation_time = microTimestamp();
+        $sql = "INSERT INTO USER_ZKP (USER_ID, USER_NAME, FIRST_NAME, LAST_NAME,
+            EMAIL, PASSWORD, STATUS, HASH)
+            VALUES ('{$row['USER_ID']}', '{$row['USER_NAME']}',
+            '{$row['FIRST_NAME']}', '{$row['LAST_NAME']}', '{$row['EMAIL']}',
+            '1552130787938400348579942770667536503149283583181838649171366591
+            924563160025427690176245139603025', '".$status."', '".
+            crawlCrypt($row['USER_NAME'].AUTH_KEY.$creation_time)."', '".
+            $creation_time."')";
+        $db->execute($sql);
+    }
     $db->disconnect();
     $db->connect();
     $db->dbname = NULL;
     $sql = "DROP TABLE USER_OLD";
     $db->execute($sql);
+    $sql = "DROP TABLE USER_ZKP_OLD";
+    $db->execute($sql);
 
 }
 
diff --git a/locale/en-US/configure.ini b/locale/en-US/configure.ini
index 55b3fd0..5c15c40 100755
--- a/locale/en-US/configure.ini
+++ b/locale/en-US/configure.ini
@@ -882,6 +882,12 @@ serversettings_element_text_captcha = "Text Captcha"
 ; system_component.php line: 612
 serversettings_element_hash_captcha = "Hash Captcha"
 ;
+; system_component.php line: 610
+serversettings_element_normal_authentication = "Normal Authentication"
+;
+; system_component.php line: 612
+serversettings_element_zkp_authentication = "ZKP Authentication"
+;
 ; system_component.php line: 716
 system_component_configure_use_absolute_path = "Must use an Absolute path for Work Directory"
 ;
@@ -2708,6 +2714,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/models/crawl_model.php b/models/crawl_model.php
index 48d3241..75cfc3c 100755
--- a/models/crawl_model.php
+++ b/models/crawl_model.php
@@ -1472,4 +1472,4 @@ EOT;
      }
 
 }
-?>
+?>
\ No newline at end of file
diff --git a/models/group_model.php b/models/group_model.php
index e8bcbe2..e91bd93 100644
--- a/models/group_model.php
+++ b/models/group_model.php
@@ -688,4 +688,4 @@ class GroupModel extends Model
         return $row['NUM'];
     }
 }
-?>
+?>
\ No newline at end of file
diff --git a/models/machine_model.php b/models/machine_model.php
index 41e6a39..1a05f17 100644
--- a/models/machine_model.php
+++ b/models/machine_model.php
@@ -339,4 +339,4 @@ class MachineModel extends Model
     }
 }
 
- ?>
+ ?>
\ No newline at end of file
diff --git a/models/model.php b/models/model.php
index e1ffd43..da07f31 100755
--- a/models/model.php
+++ b/models/model.php
@@ -443,7 +443,8 @@ class Model implements CrawlConstants
     function getUserId($username)
     {
         $db = $this->db;
-        $sql = "SELECT USER_ID FROM USERS WHERE
+        $user_table_name = $this->getUserTableName();
+        $sql = "SELECT USER_ID FROM $user_table_name WHERE
             UPPER(USER_NAME) = UPPER(?) ". $db->limitOffset(1);
         $result = $db->execute($sql, array($username));
         if(!$result) {
@@ -454,6 +455,55 @@ class Model implements CrawlConstants
         return $user_id;
     }
 
+    /** Dynamic loader for Model objects
+     *
+     * @param string $model name of model to return
+     */
+    function model($model)
+    {
+        if(!isset($this->model_instances[$model])) {
+            if(file_exists(APP_DIR."/models/".$model."_model.php")){
+                require_once APP_DIR."/models/".$model."_model.php";
+            } else {
+                require_once BASE_DIR."/models/".$model."_model.php";
+            }
+            $model_name = ucfirst($model)."Model";
+            $this->model_instances[$model] = new $model_name();
+        }
+        return $this->model_instances[$model];
+    }
+
+    /**
+     * Get the authentication mode from the profile model
+     *
+     * @param string name of the authentication mode
+     */
+    function getAuthenticationMode()
+    {
+        $profile_model = $this->model("profile");
+        $profile = $profile_model->getProfile(WORK_DIRECTORY);
+        return $profile['AUTHENTICATION_MODE'];
+    }
+
+     /**
+     * Get the user table name based on the authentication mode.
+     * If it is a normal authentication then this method returns
+     * USERS and if the authentication mode is a zkp authentication
+     * it returns USERS_ZKP
+     *
+     * @param string name of user table
+     */
+    function getUserTableName()
+    {
+        $authentication_mode = $this->getAuthenticationMode();
+        if($authentication_mode == 'zkp_authentication') {
+            $user_table_name = 'USERS_ZKP';
+        }else {
+            $user_table_name = 'USERS';
+        }
+        return $user_table_name;
+    }
+
     /**
      *  Creates the WHERE and ORDER BY clauses for a query of a Yioop
      *  table such as USERS, ROLE, GROUP, which have associated search web
@@ -584,4 +634,4 @@ class Model implements CrawlConstants
         return $rows;
     }
 }
-?>
+?>
\ No newline at end of file
diff --git a/models/profile_model.php b/models/profile_model.php
index 240d9a7..37ec95e 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_DESCRIPTION',
-        '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',
+        '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_DESCRIPTION','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}
@@ -335,6 +335,11 @@ EOT;
                 USER_NAME VARCHAR(16) UNIQUE, EMAIL VARCHAR(60),
                 PASSWORD CHAR(60), STATUS INTEGER, HASH CHAR(60),
                 CREATION_TIME VARCHAR(20))",
+            "CREATE TABLE USERS_ZKP(USER_ID $serial PRIMARY KEY $auto_increment,
+                FIRST_NAME VARCHAR(16), LAST_NAME VARCHAR(16),
+                USER_NAME VARCHAR(16) UNIQUE, EMAIL VARCHAR(60),
+                PASSWORD CHAR(200), STATUS INTEGER, HASH CHAR(300),
+                CREATION_TIME VARCHAR(20))",
             "CREATE TABLE USER_GROUP (USER_ID INTEGER , GROUP_ID INTEGER,
                    STATUS INTEGER, JOIN_DATE NUMERIC(11),
                    PRIMARY KEY (GROUP_ID, USER_ID) )",
diff --git a/models/role_model.php b/models/role_model.php
index 361b29b..aaf2f42 100644
--- a/models/role_model.php
+++ b/models/role_model.php
@@ -329,4 +329,4 @@ class RoleModel extends Model
         $this->db->execute($sql, array($role_id, $activity_id));
     }
 }
- ?>
+ ?>
\ No newline at end of file
diff --git a/models/signin_model.php b/models/signin_model.php
index bd50044..6a9d8d8 100755
--- a/models/signin_model.php
+++ b/models/signin_model.php
@@ -50,6 +50,37 @@ require_once BASE_DIR."/lib/utility.php";
 class SigninModel extends Model
 {
     /**
+     * Checks that a username and password pair is valid in case
+     * of zero knowledge authentication system.
+     *
+     * @param string $username the username to check
+     * @param string $database_username the username stored in database
+     * @param string $database_password the password stored in database
+     * @return bool  where the password is that of the given user
+     */
+    function checkValidSigninForZKP($username,$database_username,
+        $database_password)
+    {
+        $x1 =  $_REQUEST['x1'];
+        $y1 =  $_REQUEST['y1'];
+        $n = "4911896143611633780682402453849989800775189204252065".
+             "7264082207290936669351692953333549721159585615965418".
+             "82926741138174142872698595829944178957090296779606642".
+             "580976458630868510407440881709556568052691";
+        $v = $database_password;
+        $e = $_SESSION['salt_value'];
+        $rp = bcmul($x1, bcmod(bcpow($v, $e), $n));
+        $lp = bcmul($y1, $y1);
+        if ($username == $database_username && bccomp($rp, $lp) == 0) {
+            $_SESSION['COUNT'] = $_SESSION['COUNT'] + 1;
+            return true;
+        } else {
+            unset( $_SESSION['COUNT']);
+            return false;
+        }
+    }
+
+    /**
      * Checks that a username password pair is valid
      *
      * @param string $username the username to check
@@ -60,7 +91,8 @@ class SigninModel extends Model
     function checkValidSignin($username, $password)
     {
         $db = $this->db;
-        $sql = "SELECT USER_NAME, PASSWORD FROM USERS ".
+        $user_table_name = $this->getUserTableName();
+        $sql = "SELECT USER_NAME, PASSWORD FROM $user_table_name ".
             "WHERE USER_NAME = ? " . $db->limitOffset(1);
         $i = 0;
         do {
@@ -74,7 +106,11 @@ class SigninModel extends Model
             return false;
         }
         $row = $db->fetchArray($result);
-
+        $authentication_mode = $this->getAuthenticationMode();
+        if($authentication_mode == 'zkp_authentication') {
+            return $this->checkValidSigninForZKP($username,$row['USER_NAME'],
+                $row['PASSWORD']);
+        }
         return ($username == $row['USER_NAME'] &&
             crawlCrypt($password, $row['PASSWORD']) == $row['PASSWORD']) ;
     }
@@ -91,7 +127,8 @@ class SigninModel extends Model
     function checkValidEmail($username, $email)
     {
         $db = $this->db;
-        $sql = "SELECT USER_NAME, EMAIL FROM USERS ".
+        $user_table_name = $this->getUserTableName();
+        $sql = "SELECT USER_NAME, EMAIL FROM $user_table_name ".
             "WHERE USER_NAME = ? " . $db->limitOffset(1);
 
         $result = $db->execute($sql, array($username));
@@ -112,7 +149,8 @@ class SigninModel extends Model
    function getUserName($user_id)
    {
         $db = $this->db;
-        $sql = "SELECT USER_NAME FROM USERS WHERE USER_ID = ? " .
+        $user_table_name = $this->getUserTableName();
+        $sql = "SELECT USER_NAME FROM $user_table_name WHERE USER_ID = ? " .
             $db->limitOffset(1);
         $result = $db->execute($sql, array($user_id));
         $row = $db->fetchArray($result);
@@ -129,7 +167,8 @@ class SigninModel extends Model
    function getEmail($user_id, $limit = 1)
    {
         $db = $this->db;
-        $sql = "SELECT EMAIL FROM USERS WHERE
+        $user_table_name = $this->getUserTableName();
+        $sql = "SELECT EMAIL FROM $user_table_name WHERE
             USER_ID = ?  " . $db->limitOffset($limit);
         $result = $db->execute($sql, array($user_id));
         $row = $db->fetchArray($result);
@@ -147,7 +186,8 @@ class SigninModel extends Model
 
     function changeEmail($username, $email)
     {
-        $sql = "UPDATE USERS SET EMAIL= ? WHERE USER_NAME = ? ";
+        $user_table_name = $this->getUserTableName();
+        $sql = "UPDATE $user_table_name SET EMAIL= ? WHERE USER_NAME = ? ";
         $result = $this->db->execute($sql, array($email, $username));
         return $result != false;
     }
@@ -161,7 +201,8 @@ class SigninModel extends Model
      */
     function changePassword($username, $password)
     {
-        $sql = "UPDATE USERS SET PASSWORD=? WHERE USER_NAME = ? ";
+        $user_table_name = $this->getUserTableName();
+        $sql = "UPDATE $user_table_name SET PASSWORD=? WHERE USER_NAME = ? ";
         $result = $this->db->execute($sql,
             array(crawlCrypt($password), $username) );
         return $result != false;
diff --git a/models/source_model.php b/models/source_model.php
index 2e5865c..20852d2 100644
--- a/models/source_model.php
+++ b/models/source_model.php
@@ -485,4 +485,4 @@ class SourceModel extends Model
         return $meta_ids;
     }
 }
- ?>
+ ?>
\ No newline at end of file
diff --git a/models/user_model.php b/models/user_model.php
index 586446c..5e25593 100755
--- a/models/user_model.php
+++ b/models/user_model.php
@@ -52,7 +52,7 @@ class UserModel extends Model
     /**
      * @var string
      */
-    var $from_tables = "USERS";
+    var $from_table = "USER";
 
     /**
      *  @var string
@@ -214,8 +214,9 @@ class UserModel extends Model
      */
     function getUsername($user_id)
     {
+        $user_table_name = $this->getUserTableName();
         $db = $this->db;
-        $sql = "SELECT USER_NAME FROM USERS WHERE USER_ID=?";
+        $sql = "SELECT USER_NAME FROM $user_table_name WHERE USER_ID=?";
         $result = $db->execute($sql, array($user_id));
         $row = $db->fetchArray($result);
         return $row['USER_NAME'];
@@ -229,8 +230,9 @@ class UserModel extends Model
      */
     function getUserStatus($user_id)
     {
+        $user_table_name = $this->getUserTableName();
         $db = $this->db;
-        $sql = "SELECT STATUS FROM USERS WHERE USER_ID=?";
+        $sql = "SELECT STATUS FROM $user_table_name WHERE USER_ID=?";
         $result = $db->execute($sql, array($user_id));
         $row = $db->fetchArray($result);
         return $row['STATUS'];
@@ -244,8 +246,9 @@ class UserModel extends Model
      */
     function getUser($username)
     {
+        $user_table_name = $this->getUserTableName();
         $db = $this->db;
-        $sql = "SELECT * FROM USERS WHERE UPPER(USER_NAME) = UPPER(?) " .
+        $sql = "SELECT * FROM $user_table_name WHERE UPPER(USER_NAME) = UPPER(?) " .
             $db->limitOffset(1);
         $result = $db->execute($sql, array($username));
         if(!$result) {
@@ -265,8 +268,9 @@ class UserModel extends Model
      */
     function getUserByEmailTime($email, $creation_time)
     {
+        $user_table_name = $this->getUserTableName();
         $db = $this->db;
-        $sql = "SELECT * FROM USERS WHERE UPPER(EMAIL) = UPPER(?)
+        $sql = "SELECT * FROM $user_table_name WHERE UPPER(EMAIL) = UPPER(?)
             AND CREATION_TIME=? " . $db->limitOffset(1);
         $result = $db->execute($sql, array($email, $creation_time));
         if(!$result) {
@@ -283,12 +287,13 @@ class UserModel extends Model
      */
     function updateUserStatus($user_id, $status)
     {
+        $user_table_name = $this->getUserTableName();
         $db = $this->db;
         if(!in_array($status, array(ACTIVE_STATUS, INACTIVE_STATUS,
             BANNED_STATUS))) {
             return;
         }
-        $sql = "UPDATE USERS SET STATUS=? WHERE USER_ID=?";
+        $sql = "UPDATE $user_table_name SET STATUS=? WHERE USER_ID=?";
         $db->execute($sql, array($status, $user_id));
     }
 
@@ -307,12 +312,17 @@ class UserModel extends Model
         $email='', $status = ACTIVE_STATUS)
     {
         $creation_time = microTimestamp();
+        $user_table_name = $this->getUserTableName();
+        if($user_table_name=='USERS')
+        {
+            $password = crawlCrypt($password) ;
+        }
         $db = $this->db;
-        $sql = "INSERT INTO USERS(FIRST_NAME, LAST_NAME,
+        $sql = "INSERT INTO $user_table_name(FIRST_NAME, LAST_NAME,
             USER_NAME, EMAIL, PASSWORD, STATUS, HASH, CREATION_TIME) VALUES (
             ?, ?, ?, ?, ?, ?, ?, ?)";
         $result = $db->execute($sql, array($firstname, $lastname,
-            $username, $email, crawlCrypt($password), $status,
+            $username, $email, $password, $status,
             crawlCrypt($username.AUTH_KEY.$creation_time), $creation_time));
         if(!$user_id = $this->getUserId($username)) {
             return false;
@@ -348,7 +358,8 @@ class UserModel extends Model
             $sql = "DELETE FROM USER_SESSION WHERE USER_ID=?";
             $result = $db->execute($sql, array($user_id));
         }
-        $sql = "DELETE FROM USERS WHERE USER_ID=?";
+        $user_table_name = $this->getUserTableName();
+        $sql = "DELETE FROM $user_table_name WHERE USER_ID=?";
         $result = $db->execute($sql, array($user_id));
     }
 
@@ -360,10 +371,11 @@ class UserModel extends Model
      */
     function updateUser($user)
     {
+        $user_table_name = $this->getUserTableName();
         $user_id = $user['USER_ID'];
         unset($user['USER_ID']);
         unset($user['USER_NAME']);
-        $sql = "UPDATE USERS SET ";
+        $sql = "UPDATE $user_table_name SET ";
         $comma ="";
         $params = array();
         foreach($user as $field => $value) {
@@ -376,4 +388,4 @@ class UserModel extends Model
         $this->db->execute($sql, $params);
     }
 }
-?>
+?>
\ No newline at end of file
diff --git a/scripts/BigInt2.js b/scripts/BigInt2.js
new file mode 100644
index 0000000..fe90b60
--- /dev/null
+++ b/scripts/BigInt2.js
@@ -0,0 +1,559 @@
+// Copyright (c) 2005  Tom Wu
+// All Rights Reserved.
+// See "LICENSE" for details.
+
+// Basic JavaScript BN library - subset useful for RSA encryption.
+
+// Bits per digit
+var dbits;
+
+// JavaScript engine analysis
+var canary = 0xdeadbeefcafe;
+var j_lm = ((canary&0xffffff)==0xefcafe);
+
+// (public) Constructor
+function BigInteger(a,b,c) {
+  if(a != null)
+    if("number" == typeof a) this.fromNumber(a,b,c);
+    else if(b == null && "string" != typeof a) this.fromString(a,256);
+    else this.fromString(a,b);
+}
+
+// return new, unset BigInteger
+function nbi() { return new BigInteger(null); }
+
+// am: Compute w_j += (x*this_i), propagate carries,
+// c is initial carry, returns final carry.
+// c < 3*dvalue, x < 2*dvalue, this_i < dvalue
+// We need to select the fastest one that works in this environment.
+
+// am1: use a single mult and divide to get the high bits,
+// max digit bits should be 26 because
+// max internal value = 2*dvalue^2-2*dvalue (< 2^53)
+function am1(i,x,w,j,c,n) {
+  while(--n >= 0) {
+    var v = x*this[i++]+w[j]+c;
+    c = Math.floor(v/0x4000000);
+    w[j++] = v&0x3ffffff;
+  }
+  return c;
+}
+// am2 avoids a big mult-and-extract completely.
+// Max digit bits should be <= 30 because we do bitwise ops
+// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)
+function am2(i,x,w,j,c,n) {
+  var xl = x&0x7fff, xh = x>>15;
+  while(--n >= 0) {
+    var l = this[i]&0x7fff;
+    var h = this[i++]>>15;
+    var m = xh*l+h*xl;
+    l = xl*l+((m&0x7fff)<<15)+w[j]+(c&0x3fffffff);
+    c = (l>>>30)+(m>>>15)+xh*h+(c>>>30);
+    w[j++] = l&0x3fffffff;
+  }
+  return c;
+}
+// Alternately, set max digit bits to 28 since some
+// browsers slow down when dealing with 32-bit numbers.
+function am3(i,x,w,j,c,n) {
+  var xl = x&0x3fff, xh = x>>14;
+  while(--n >= 0) {
+    var l = this[i]&0x3fff;
+    var h = this[i++]>>14;
+    var m = xh*l+h*xl;
+    l = xl*l+((m&0x3fff)<<14)+w[j]+c;
+    c = (l>>28)+(m>>14)+xh*h;
+    w[j++] = l&0xfffffff;
+  }
+  return c;
+}
+if(j_lm && (navigator.appName == "Microsoft Internet Explorer")) {
+  BigInteger.prototype.am = am2;
+  dbits = 30;
+}
+else if(j_lm && (navigator.appName != "Netscape")) {
+  BigInteger.prototype.am = am1;
+  dbits = 26;
+}
+else { // Mozilla/Netscape seems to prefer am3
+  BigInteger.prototype.am = am3;
+  dbits = 28;
+}
+
+BigInteger.prototype.DB = dbits;
+BigInteger.prototype.DM = ((1<<dbits)-1);
+BigInteger.prototype.DV = (1<<dbits);
+
+var BI_FP = 52;
+BigInteger.prototype.FV = Math.pow(2,BI_FP);
+BigInteger.prototype.F1 = BI_FP-dbits;
+BigInteger.prototype.F2 = 2*dbits-BI_FP;
+
+// Digit conversions
+var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
+var BI_RC = new Array();
+var rr,vv;
+rr = "0".charCodeAt(0);
+for(vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv;
+rr = "a".charCodeAt(0);
+for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
+rr = "A".charCodeAt(0);
+for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
+
+function int2char(n) { return BI_RM.charAt(n); }
+function intAt(s,i) {
+  var c = BI_RC[s.charCodeAt(i)];
+  return (c==null)?-1:c;
+}
+
+// (protected) copy this to r
+function bnpCopyTo(r) {
+  for(var i = this.t-1; i >= 0; --i) r[i] = this[i];
+  r.t = this.t;
+  r.s = this.s;
+}
+
+// (protected) set from integer value x, -DV <= x < DV
+function bnpFromInt(x) {
+  this.t = 1;
+  this.s = (x<0)?-1:0;
+  if(x > 0) this[0] = x;
+  else if(x < -1) this[0] = x+this.DV;
+  else this.t = 0;
+}
+
+// return bigint initialized to value
+function nbv(i) { var r = nbi(); r.fromInt(i); return r; }
+
+// (protected) set from string and radix
+function bnpFromString(s,b) {
+  var k;
+  if(b == 16) k = 4;
+  else if(b == 8) k = 3;
+  else if(b == 256) k = 8; // byte array
+  else if(b == 2) k = 1;
+  else if(b == 32) k = 5;
+  else if(b == 4) k = 2;
+  else { this.fromRadix(s,b); return; }
+  this.t = 0;
+  this.s = 0;
+  var i = s.length, mi = false, sh = 0;
+  while(--i >= 0) {
+    var x = (k==8)?s[i]&0xff:intAt(s,i);
+    if(x < 0) {
+      if(s.charAt(i) == "-") mi = true;
+      continue;
+    }
+    mi = false;
+    if(sh == 0)
+      this[this.t++] = x;
+    else if(sh+k > this.DB) {
+      this[this.t-1] |= (x&((1<<(this.DB-sh))-1))<<sh;
+      this[this.t++] = (x>>(this.DB-sh));
+    }
+    else
+      this[this.t-1] |= x<<sh;
+    sh += k;
+    if(sh >= this.DB) sh -= this.DB;
+  }
+  if(k == 8 && (s[0]&0x80) != 0) {
+    this.s = -1;
+    if(sh > 0) this[this.t-1] |= ((1<<(this.DB-sh))-1)<<sh;
+  }
+  this.clamp();
+  if(mi) BigInteger.ZERO.subTo(this,this);
+}
+
+// (protected) clamp off excess high words
+function bnpClamp() {
+  var c = this.s&this.DM;
+  while(this.t > 0 && this[this.t-1] == c) --this.t;
+}
+
+// (public) return string representation in given radix
+function bnToString(b) {
+  if(this.s < 0) return "-"+this.negate().toString(b);
+  var k;
+  if(b == 16) k = 4;
+  else if(b == 8) k = 3;
+  else if(b == 2) k = 1;
+  else if(b == 32) k = 5;
+  else if(b == 4) k = 2;
+  else return this.toRadix(b);
+  var km = (1<<k)-1, d, m = false, r = "", i = this.t;
+  var p = this.DB-(i*this.DB)%k;
+  if(i-- > 0) {
+    if(p < this.DB && (d = this[i]>>p) > 0) { m = true; r = int2char(d); }
+    while(i >= 0) {
+      if(p < k) {
+        d = (this[i]&((1<<p)-1))<<(k-p);
+        d |= this[--i]>>(p+=this.DB-k);
+      }
+      else {
+        d = (this[i]>>(p-=k))&km;
+        if(p <= 0) { p += this.DB; --i; }
+      }
+      if(d > 0) m = true;
+      if(m) r += int2char(d);
+    }
+  }
+  return m?r:"0";
+}
+
+// (public) -this
+function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; }
+
+// (public) |this|
+function bnAbs() { return (this.s<0)?this.negate():this; }
+
+// (public) return + if this > a, - if this < a, 0 if equal
+function bnCompareTo(a) {
+  var r = this.s-a.s;
+  if(r != 0) return r;
+  var i = this.t;
+  r = i-a.t;
+  if(r != 0) return (this.s<0)?-r:r;
+  while(--i >= 0) if((r=this[i]-a[i]) != 0) return r;
+  return 0;
+}
+
+// returns bit length of the integer x
+function nbits(x) {
+  var r = 1, t;
+  if((t=x>>>16) != 0) { x = t; r += 16; }
+  if((t=x>>8) != 0) { x = t; r += 8; }
+  if((t=x>>4) != 0) { x = t; r += 4; }
+  if((t=x>>2) != 0) { x = t; r += 2; }
+  if((t=x>>1) != 0) { x = t; r += 1; }
+  return r;
+}
+
+// (public) return the number of bits in "this"
+function bnBitLength() {
+  if(this.t <= 0) return 0;
+  return this.DB*(this.t-1)+nbits(this[this.t-1]^(this.s&this.DM));
+}
+
+// (protected) r = this << n*DB
+function bnpDLShiftTo(n,r) {
+  var i;
+  for(i = this.t-1; i >= 0; --i) r[i+n] = this[i];
+  for(i = n-1; i >= 0; --i) r[i] = 0;
+  r.t = this.t+n;
+  r.s = this.s;
+}
+
+// (protected) r = this >> n*DB
+function bnpDRShiftTo(n,r) {
+  for(var i = n; i < this.t; ++i) r[i-n] = this[i];
+  r.t = Math.max(this.t-n,0);
+  r.s = this.s;
+}
+
+// (protected) r = this << n
+function bnpLShiftTo(n,r) {
+  var bs = n%this.DB;
+  var cbs = this.DB-bs;
+  var bm = (1<<cbs)-1;
+  var ds = Math.floor(n/this.DB), c = (this.s<<bs)&this.DM, i;
+  for(i = this.t-1; i >= 0; --i) {
+    r[i+ds+1] = (this[i]>>cbs)|c;
+    c = (this[i]&bm)<<bs;
+  }
+  for(i = ds-1; i >= 0; --i) r[i] = 0;
+  r[ds] = c;
+  r.t = this.t+ds+1;
+  r.s = this.s;
+  r.clamp();
+}
+
+// (protected) r = this >> n
+function bnpRShiftTo(n,r) {
+  r.s = this.s;
+  var ds = Math.floor(n/this.DB);
+  if(ds >= this.t) { r.t = 0; return; }
+  var bs = n%this.DB;
+  var cbs = this.DB-bs;
+  var bm = (1<<bs)-1;
+  r[0] = this[ds]>>bs;
+  for(var i = ds+1; i < this.t; ++i) {
+    r[i-ds-1] |= (this[i]&bm)<<cbs;
+    r[i-ds] = this[i]>>bs;
+  }
+  if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<<cbs;
+  r.t = this.t-ds;
+  r.clamp();
+}
+
+// (protected) r = this - a
+function bnpSubTo(a,r) {
+  var i = 0, c = 0, m = Math.min(a.t,this.t);
+  while(i < m) {
+    c += this[i]-a[i];
+    r[i++] = c&this.DM;
+    c >>= this.DB;
+  }
+  if(a.t < this.t) {
+    c -= a.s;
+    while(i < this.t) {
+      c += this[i];
+      r[i++] = c&this.DM;
+      c >>= this.DB;
+    }
+    c += this.s;
+  }
+  else {
+    c += this.s;
+    while(i < a.t) {
+      c -= a[i];
+      r[i++] = c&this.DM;
+      c >>= this.DB;
+    }
+    c -= a.s;
+  }
+  r.s = (c<0)?-1:0;
+  if(c < -1) r[i++] = this.DV+c;
+  else if(c > 0) r[i++] = c;
+  r.t = i;
+  r.clamp();
+}
+
+// (protected) r = this * a, r != this,a (HAC 14.12)
+// "this" should be the larger one if appropriate.
+function bnpMultiplyTo(a,r) {
+  var x = this.abs(), y = a.abs();
+  var i = x.t;
+  r.t = i+y.t;
+  while(--i >= 0) r[i] = 0;
+  for(i = 0; i < y.t; ++i) r[i+x.t] = x.am(0,y[i],r,i,0,x.t);
+  r.s = 0;
+  r.clamp();
+  if(this.s != a.s) BigInteger.ZERO.subTo(r,r);
+}
+
+// (protected) r = this^2, r != this (HAC 14.16)
+function bnpSquareTo(r) {
+  var x = this.abs();
+  var i = r.t = 2*x.t;
+  while(--i >= 0) r[i] = 0;
+  for(i = 0; i < x.t-1; ++i) {
+    var c = x.am(i,x[i],r,2*i,0,1);
+    if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1)) >= x.DV) {
+      r[i+x.t] -= x.DV;
+      r[i+x.t+1] = 1;
+    }
+  }
+  if(r.t > 0) r[r.t-1] += x.am(i,x[i],r,2*i,0,1);
+  r.s = 0;
+  r.clamp();
+}
+
+// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
+// r != q, this != m.  q or r may be null.
+function bnpDivRemTo(m,q,r) {
+  var pm = m.abs();
+  if(pm.t <= 0) return;
+  var pt = this.abs();
+  if(pt.t < pm.t) {
+    if(q != null) q.fromInt(0);
+    if(r != null) this.copyTo(r);
+    return;
+  }
+  if(r == null) r = nbi();
+  var y = nbi(), ts = this.s, ms = m.s;
+  var nsh = this.DB-nbits(pm[pm.t-1]);    // normalize modulus
+  if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); }
+  else { pm.copyTo(y); pt.copyTo(r); }
+  var ys = y.t;
+  var y0 = y[ys-1];
+  if(y0 == 0) return;
+  var yt = y0*(1<<this.F1)+((ys>1)?y[ys-2]>>this.F2:0);
+  var d1 = this.FV/yt, d2 = (1<<this.F1)/yt, e = 1<<this.F2;
+  var i = r.t, j = i-ys, t = (q==null)?nbi():q;
+  y.dlShiftTo(j,t);
+  if(r.compareTo(t) >= 0) {
+    r[r.t++] = 1;
+    r.subTo(t,r);
+  }
+  BigInteger.ONE.dlShiftTo(ys,t);
+  t.subTo(y,y);    // "negative" y so we can replace sub with am later
+  while(y.t < ys) y[y.t++] = 0;
+  while(--j >= 0) {
+    // Estimate quotient digit
+    var qd = (r[--i]==y0)?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2);
+    if((r[i]+=y.am(0,qd,r,j,0,ys)) < qd) {    // Try it out
+      y.dlShiftTo(j,t);
+      r.subTo(t,r);
+      while(r[i] < --qd) r.subTo(t,r);
+    }
+  }
+  if(q != null) {
+    r.drShiftTo(ys,q);
+    if(ts != ms) BigInteger.ZERO.subTo(q,q);
+  }
+  r.t = ys;
+  r.clamp();
+  if(nsh > 0) r.rShiftTo(nsh,r);    // Denormalize remainder
+  if(ts < 0) BigInteger.ZERO.subTo(r,r);
+}
+
+// (public) this mod a
+function bnMod(a) {
+  var r = nbi();
+  this.abs().divRemTo(a,null,r);
+  if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r);
+  return r;
+}
+
+// Modular reduction using "classic" algorithm
+function Classic(m) { this.m = m; }
+function cConvert(x) {
+  if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
+  else return x;
+}
+function cRevert(x) { return x; }
+function cReduce(x) { x.divRemTo(this.m,null,x); }
+function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
+function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
+
+Classic.prototype.convert = cConvert;
+Classic.prototype.revert = cRevert;
+Classic.prototype.reduce = cReduce;
+Classic.prototype.mulTo = cMulTo;
+Classic.prototype.sqrTo = cSqrTo;
+
+// (protected) return "-1/this % 2^DB"; useful for Mont. reduction
+// justification:
+//         xy == 1 (mod m)
+//         xy =  1+km
+//   xy(2-xy) = (1+km)(1-km)
+// x[y(2-xy)] = 1-k^2m^2
+// x[y(2-xy)] == 1 (mod m^2)
+// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
+// should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
+// JS multiply "overflows" differently from C/C++, so care is needed here.
+function bnpInvDigit() {
+  if(this.t < 1) return 0;
+  var x = this[0];
+  if((x&1) == 0) return 0;
+  var y = x&3;        // y == 1/x mod 2^2
+  y = (y*(2-(x&0xf)*y))&0xf;    // y == 1/x mod 2^4
+  y = (y*(2-(x&0xff)*y))&0xff;    // y == 1/x mod 2^8
+  y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff;    // y == 1/x mod 2^16
+  // last step - calculate inverse mod DV directly;
+  // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
+  y = (y*(2-x*y%this.DV))%this.DV;        // y == 1/x mod 2^dbits
+  // we really want the negative inverse, and -DV < y < DV
+  return (y>0)?this.DV-y:-y;
+}
+
+// Montgomery reduction
+function Montgomery(m) {
+  this.m = m;
+  this.mp = m.invDigit();
+  this.mpl = this.mp&0x7fff;
+  this.mph = this.mp>>15;
+  this.um = (1<<(m.DB-15))-1;
+  this.mt2 = 2*m.t;
+}
+
+// xR mod m
+function montConvert(x) {
+  var r = nbi();
+  x.abs().dlShiftTo(this.m.t,r);
+  r.divRemTo(this.m,null,r);
+  if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r);
+  return r;
+}
+
+// x/R mod m
+function montRevert(x) {
+  var r = nbi();
+  x.copyTo(r);
+  this.reduce(r);
+  return r;
+}
+
+// x = x/R mod m (HAC 14.32)
+function montReduce(x) {
+  while(x.t <= this.mt2)    // pad x so am has enough room later
+    x[x.t++] = 0;
+  for(var i = 0; i < this.m.t; ++i) {
+    // faster way of calculating u0 = x[i]*mp mod DV
+    var j = x[i]&0x7fff;
+    var u0 = (j*this.mpl+(((j*this.mph+(x[i]>>15)*this.mpl)&this.um)<<15))&x.DM;
+    // use am to combine the multiply-shift-add into one call
+    j = i+this.m.t;
+    x[j] += this.m.am(0,u0,x,i,0,this.m.t);
+    // propagate carry
+    while(x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; }
+  }
+  x.clamp();
+  x.drShiftTo(this.m.t,x);
+  if(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
+}
+
+// r = "x^2/R mod m"; x != r
+function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
+
+// r = "xy/R mod m"; x,y != r
+function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
+
+Montgomery.prototype.convert = montConvert;
+Montgomery.prototype.revert = montRevert;
+Montgomery.prototype.reduce = montReduce;
+Montgomery.prototype.mulTo = montMulTo;
+Montgomery.prototype.sqrTo = montSqrTo;
+
+// (protected) true iff this is even
+function bnpIsEven() { return ((this.t>0)?(this[0]&1):this.s) == 0; }
+
+// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
+function bnpExp(e,z) {
+  if(e > 0xffffffff || e < 1) return BigInteger.ONE;
+  var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1;
+  g.copyTo(r);
+  while(--i >= 0) {
+    z.sqrTo(r,r2);
+    if((e&(1<<i)) > 0) z.mulTo(r2,g,r);
+    else { var t = r; r = r2; r2 = t; }
+  }
+  return z.revert(r);
+}
+
+// (public) this^e % m, 0 <= e < 2^32
+function bnModPowInt(e,m) {
+  var z;
+  if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m);
+  return this.exp(e,z);
+}
+
+// protected
+BigInteger.prototype.copyTo = bnpCopyTo;
+BigInteger.prototype.fromInt = bnpFromInt;
+BigInteger.prototype.fromString = bnpFromString;
+BigInteger.prototype.clamp = bnpClamp;
+BigInteger.prototype.dlShiftTo = bnpDLShiftTo;
+BigInteger.prototype.drShiftTo = bnpDRShiftTo;
+BigInteger.prototype.lShiftTo = bnpLShiftTo;
+BigInteger.prototype.rShiftTo = bnpRShiftTo;
+BigInteger.prototype.subTo = bnpSubTo;
+BigInteger.prototype.multiplyTo = bnpMultiplyTo;
+BigInteger.prototype.squareTo = bnpSquareTo;
+BigInteger.prototype.divRemTo = bnpDivRemTo;
+BigInteger.prototype.invDigit = bnpInvDigit;
+BigInteger.prototype.isEven = bnpIsEven;
+BigInteger.prototype.exp = bnpExp;
+
+// public
+BigInteger.prototype.toString = bnToString;
+BigInteger.prototype.negate = bnNegate;
+BigInteger.prototype.abs = bnAbs;
+BigInteger.prototype.compareTo = bnCompareTo;
+BigInteger.prototype.bitLength = bnBitLength;
+BigInteger.prototype.mod = bnMod;
+BigInteger.prototype.modPowInt = bnModPowInt;
+
+// "constants"
+BigInteger.ZERO = nbv(0);
+BigInteger.ONE = nbv(1);
\ No newline at end of file
diff --git a/scripts/BigInt3.js b/scripts/BigInt3.js
new file mode 100644
index 0000000..3f4ff0d
--- /dev/null
+++ b/scripts/BigInt3.js
@@ -0,0 +1,656 @@
+// Copyright (c) 2005-2009  Tom Wu
+// All Rights Reserved.
+// See "LICENSE" for details.
+
+// Extended JavaScript BN functions, required for RSA private ops.
+
+// Version 1.1: new BigInteger("0", 10) returns "proper" zero
+// Version 1.2: square() API, isProbablePrime fix
+
+// (public)
+function bnClone() { var r = nbi(); this.copyTo(r); return r; }
+
+// (public) return value as integer
+function bnIntValue() {
+  if(this.s < 0) {
+    if(this.t == 1) return this[0]-this.DV;
+    else if(this.t == 0) return -1;
+  }
+  else if(this.t == 1) return this[0];
+  else if(this.t == 0) return 0;
+  // assumes 16 < DB < 32
+  return ((this[1]&((1<<(32-this.DB))-1))<<this.DB)|this[0];
+}
+
+// (public) return value as byte
+function bnByteValue() { return (this.t==0)?this.s:(this[0]<<24)>>24; }
+
+// (public) return value as short (assumes DB>=16)
+function bnShortValue() { return (this.t==0)?this.s:(this[0]<<16)>>16; }
+
+// (protected) return x s.t. r^x < DV
+function bnpChunkSize(r) { return Math.floor(Math.LN2*this.DB/Math.log(r)); }
+
+// (public) 0 if this == 0, 1 if this > 0
+function bnSigNum() {
+  if(this.s < 0) return -1;
+  else if(this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0;
+  else return 1;
+}
+
+// (protected) convert to radix string
+function bnpToRadix(b) {
+  if(b == null) b = 10;
+  if(this.signum() == 0 || b < 2 || b > 36) return "0";
+  var cs = this.chunkSize(b);
+  var a = Math.pow(b,cs);
+  var d = nbv(a), y = nbi(), z = nbi(), r = "";
+  this.divRemTo(d,y,z);
+  while(y.signum() > 0) {
+    r = (a+z.intValue()).toString(b).substr(1) + r;
+    y.divRemTo(d,y,z);
+  }
+  return z.intValue().toString(b) + r;
+}
+
+// (protected) convert from radix string
+function bnpFromRadix(s,b) {
+  this.fromInt(0);
+  if(b == null) b = 10;
+  var cs = this.chunkSize(b);
+  var d = Math.pow(b,cs), mi = false, j = 0, w = 0;
+  for(var i = 0; i < s.length; ++i) {
+    var x = intAt(s,i);
+    if(x < 0) {
+      if(s.charAt(i) == "-" && this.signum() == 0) mi = true;
+      continue;
+    }
+    w = b*w+x;
+    if(++j >= cs) {
+      this.dMultiply(d);
+      this.dAddOffset(w,0);
+      j = 0;
+      w = 0;
+    }
+  }
+  if(j > 0) {
+    this.dMultiply(Math.pow(b,j));
+    this.dAddOffset(w,0);
+  }
+  if(mi) BigInteger.ZERO.subTo(this,this);
+}
+
+// (protected) alternate constructor
+function bnpFromNumber(a,b,c) {
+  if("number" == typeof b) {
+    // new BigInteger(int,int,RNG)
+    if(a < 2) this.fromInt(1);
+    else {
+      this.fromNumber(a,c);
+      if(!this.testBit(a-1))    // force MSB set
+        this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this);
+      if(this.isEven()) this.dAddOffset(1,0); // force odd
+      while(!this.isProbablePrime(b)) {
+        this.dAddOffset(2,0);
+        if(this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a-1),this);
+      }
+    }
+  }
+  else {
+    // new BigInteger(int,RNG)
+    var x = new Array(), t = a&7;
+    x.length = (a>>3)+1;
+    b.nextBytes(x);
+    if(t > 0) x[0] &= ((1<<t)-1); else x[0] = 0;
+    this.fromString(x,256);
+  }
+}
+
+// (public) convert to bigendian byte array
+function bnToByteArray() {
+  var i = this.t, r = new Array();
+  r[0] = this.s;
+  var p = this.DB-(i*this.DB)%8, d, k = 0;
+  if(i-- > 0) {
+    if(p < this.DB && (d = this[i]>>p) != (this.s&this.DM)>>p)
+      r[k++] = d|(this.s<<(this.DB-p));
+    while(i >= 0) {
+      if(p < 8) {
+        d = (this[i]&((1<<p)-1))<<(8-p);
+        d |= this[--i]>>(p+=this.DB-8);
+      }
+      else {
+        d = (this[i]>>(p-=8))&0xff;
+        if(p <= 0) { p += this.DB; --i; }
+      }
+      if((d&0x80) != 0) d |= -256;
+      if(k == 0 && (this.s&0x80) != (d&0x80)) ++k;
+      if(k > 0 || d != this.s) r[k++] = d;
+    }
+  }
+  return r;
+}
+
+function bnEquals(a) { return(this.compareTo(a)==0); }
+function bnMin(a) { return(this.compareTo(a)<0)?this:a; }
+function bnMax(a) { return(this.compareTo(a)>0)?this:a; }
+
+// (protected) r = this op a (bitwise)
+function bnpBitwiseTo(a,op,r) {
+  var i, f, m = Math.min(a.t,this.t);
+  for(i = 0; i < m; ++i) r[i] = op(this[i],a[i]);
+  if(a.t < this.t) {
+    f = a.s&this.DM;
+    for(i = m; i < this.t; ++i) r[i] = op(this[i],f);
+    r.t = this.t;
+  }
+  else {
+    f = this.s&this.DM;
+    for(i = m; i < a.t; ++i) r[i] = op(f,a[i]);
+    r.t = a.t;
+  }
+  r.s = op(this.s,a.s);
+  r.clamp();
+}
+
+// (public) this & a
+function op_and(x,y) { return x&y; }
+function bnAnd(a) { var r = nbi(); this.bitwiseTo(a,op_and,r); return r; }
+
+// (public) this | a
+function op_or(x,y) { return x|y; }
+function bnOr(a) { var r = nbi(); this.bitwiseTo(a,op_or,r); return r; }
+
+// (public) this ^ a
+function op_xor(x,y) { return x^y; }
+function bnXor(a) { var r = nbi(); this.bitwiseTo(a,op_xor,r); return r; }
+
+// (public) this & ~a
+function op_andnot(x,y) { return x&~y; }
+function bnAndNot(a) { var r = nbi(); this.bitwiseTo(a,op_andnot,r); return r; }
+
+// (public) ~this
+function bnNot() {
+  var r = nbi();
+  for(var i = 0; i < this.t; ++i) r[i] = this.DM&~this[i];
+  r.t = this.t;
+  r.s = ~this.s;
+  return r;
+}
+
+// (public) this << n
+function bnShiftLeft(n) {
+  var r = nbi();
+  if(n < 0) this.rShiftTo(-n,r); else this.lShiftTo(n,r);
+  return r;
+}
+
+// (public) this >> n
+function bnShiftRight(n) {
+  var r = nbi();
+  if(n < 0) this.lShiftTo(-n,r); else this.rShiftTo(n,r);
+  return r;
+}
+
+// return index of lowest 1-bit in x, x < 2^31
+function lbit(x) {
+  if(x == 0) return -1;
+  var r = 0;
+  if((x&0xffff) == 0) { x >>= 16; r += 16; }
+  if((x&0xff) == 0) { x >>= 8; r += 8; }
+  if((x&0xf) == 0) { x >>= 4; r += 4; }
+  if((x&3) == 0) { x >>= 2; r += 2; }
+  if((x&1) == 0) ++r;
+  return r;
+}
+
+// (public) returns index of lowest 1-bit (or -1 if none)
+function bnGetLowestSetBit() {
+  for(var i = 0; i < this.t; ++i)
+    if(this[i] != 0) return i*this.DB+lbit(this[i]);
+  if(this.s < 0) return this.t*this.DB;
+  return -1;
+}
+
+// return number of 1 bits in x
+function cbit(x) {
+  var r = 0;
+  while(x != 0) { x &= x-1; ++r; }
+  return r;
+}
+
+// (public) return number of set bits
+function bnBitCount() {
+  var r = 0, x = this.s&this.DM;
+  for(var i = 0; i < this.t; ++i) r += cbit(this[i]^x);
+  return r;
+}
+
+// (public) true iff nth bit is set
+function bnTestBit(n) {
+  var j = Math.floor(n/this.DB);
+  if(j >= this.t) return(this.s!=0);
+  return((this[j]&(1<<(n%this.DB)))!=0);
+}
+
+// (protected) this op (1<<n)
+function bnpChangeBit(n,op) {
+  var r = BigInteger.ONE.shiftLeft(n);
+  this.bitwiseTo(r,op,r);
+  return r;
+}
+
+// (public) this | (1<<n)
+function bnSetBit(n) { return this.changeBit(n,op_or); }
+
+// (public) this & ~(1<<n)
+function bnClearBit(n) { return this.changeBit(n,op_andnot); }
+
+// (public) this ^ (1<<n)
+function bnFlipBit(n) { return this.changeBit(n,op_xor); }
+
+// (protected) r = this + a
+function bnpAddTo(a,r) {
+  var i = 0, c = 0, m = Math.min(a.t,this.t);
+  while(i < m) {
+    c += this[i]+a[i];
+    r[i++] = c&this.DM;
+    c >>= this.DB;
+  }
+  if(a.t < this.t) {
+    c += a.s;
+    while(i < this.t) {
+      c += this[i];
+      r[i++] = c&this.DM;
+      c >>= this.DB;
+    }
+    c += this.s;
+  }
+  else {
+    c += this.s;
+    while(i < a.t) {
+      c += a[i];
+      r[i++] = c&this.DM;
+      c >>= this.DB;
+    }
+    c += a.s;
+  }
+  r.s = (c<0)?-1:0;
+  if(c > 0) r[i++] = c;
+  else if(c < -1) r[i++] = this.DV+c;
+  r.t = i;
+  r.clamp();
+}
+
+// (public) this + a
+function bnAdd(a) { var r = nbi(); this.addTo(a,r); return r; }
+
+// (public) this - a
+function bnSubtract(a) { var r = nbi(); this.subTo(a,r); return r; }
+
+// (public) this * a
+function bnMultiply(a) { var r = nbi(); this.multiplyTo(a,r); return r; }
+
+// (public) this^2
+function bnSquare() { var r = nbi(); this.squareTo(r); return r; }
+
+// (public) this / a
+function bnDivide(a) { var r = nbi(); this.divRemTo(a,r,null); return r; }
+
+// (public) this % a
+function bnRemainder(a) { var r = nbi(); this.divRemTo(a,null,r); return r; }
+
+// (public) [this/a,this%a]
+function bnDivideAndRemainder(a) {
+  var q = nbi(), r = nbi();
+  this.divRemTo(a,q,r);
+  return new Array(q,r);
+}
+
+// (protected) this *= n, this >= 0, 1 < n < DV
+function bnpDMultiply(n) {
+  this[this.t] = this.am(0,n-1,this,0,0,this.t);
+  ++this.t;
+  this.clamp();
+}
+
+// (protected) this += n << w words, this >= 0
+function bnpDAddOffset(n,w) {
+  if(n == 0) return;
+  while(this.t <= w) this[this.t++] = 0;
+  this[w] += n;
+  while(this[w] >= this.DV) {
+    this[w] -= this.DV;
+    if(++w >= this.t) this[this.t++] = 0;
+    ++this[w];
+  }
+}
+
+// A "null" reducer
+function NullExp() {}
+function nNop(x) { return x; }
+function nMulTo(x,y,r) { x.multiplyTo(y,r); }
+function nSqrTo(x,r) { x.squareTo(r); }
+
+NullExp.prototype.convert = nNop;
+NullExp.prototype.revert = nNop;
+NullExp.prototype.mulTo = nMulTo;
+NullExp.prototype.sqrTo = nSqrTo;
+
+// (public) this^e
+function bnPow(e) { return this.exp(e,new NullExp()); }
+
+// (protected) r = lower n words of "this * a", a.t <= n
+// "this" should be the larger one if appropriate.
+function bnpMultiplyLowerTo(a,n,r) {
+  var i = Math.min(this.t+a.t,n);
+  r.s = 0; // assumes a,this >= 0
+  r.t = i;
+  while(i > 0) r[--i] = 0;
+  var j;
+  for(j = r.t-this.t; i < j; ++i) r[i+this.t] = this.am(0,a[i],r,i,0,this.t);
+  for(j = Math.min(a.t,n); i < j; ++i) this.am(0,a[i],r,i,0,n-i);
+  r.clamp();
+}
+
+// (protected) r = "this * a" without lower n words, n > 0
+// "this" should be the larger one if appropriate.
+function bnpMultiplyUpperTo(a,n,r) {
+  --n;
+  var i = r.t = this.t+a.t-n;
+  r.s = 0; // assumes a,this >= 0
+  while(--i >= 0) r[i] = 0;
+  for(i = Math.max(n-this.t,0); i < a.t; ++i)
+    r[this.t+i-n] = this.am(n-i,a[i],r,0,0,this.t+i-n);
+  r.clamp();
+  r.drShiftTo(1,r);
+}
+
+// Barrett modular reduction
+function Barrett(m) {
+  // setup Barrett
+  this.r2 = nbi();
+  this.q3 = nbi();
+  BigInteger.ONE.dlShiftTo(2*m.t,this.r2);
+  this.mu = this.r2.divide(m);
+  this.m = m;
+}
+
+function barrettConvert(x) {
+  if(x.s < 0 || x.t > 2*this.m.t) return x.mod(this.m);
+  else if(x.compareTo(this.m) < 0) return x;
+  else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; }
+}
+
+function barrettRevert(x) { return x; }
+
+// x = x mod m (HAC 14.42)
+function barrettReduce(x) {
+  x.drShiftTo(this.m.t-1,this.r2);
+  if(x.t > this.m.t+1) { x.t = this.m.t+1; x.clamp(); }
+  this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3);
+  this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2);
+  while(x.compareTo(this.r2) < 0) x.dAddOffset(1,this.m.t+1);
+  x.subTo(this.r2,x);
+  while(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
+}
+
+// r = x^2 mod m; x != r
+function barrettSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
+
+// r = x*y mod m; x,y != r
+function barrettMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
+
+Barrett.prototype.convert = barrettConvert;
+Barrett.prototype.revert = barrettRevert;
+Barrett.prototype.reduce = barrettReduce;
+Barrett.prototype.mulTo = barrettMulTo;
+Barrett.prototype.sqrTo = barrettSqrTo;
+
+// (public) this^e % m (HAC 14.85)
+function bnModPow(e,m) {
+  var i = e.bitLength(), k, r = nbv(1), z;
+  if(i <= 0) return r;
+  else if(i < 18) k = 1;
+  else if(i < 48) k = 3;
+  else if(i < 144) k = 4;
+  else if(i < 768) k = 5;
+  else k = 6;
+  if(i < 8)
+    z = new Classic(m);
+  else if(m.isEven())
+    z = new Barrett(m);
+  else
+    z = new Montgomery(m);
+
+  // precomputation
+  var g = new Array(), n = 3, k1 = k-1, km = (1<<k)-1;
+  g[1] = z.convert(this);
+  if(k > 1) {
+    var g2 = nbi();
+    z.sqrTo(g[1],g2);
+    while(n <= km) {
+      g[n] = nbi();
+      z.mulTo(g2,g[n-2],g[n]);
+      n += 2;
+    }
+  }
+
+  var j = e.t-1, w, is1 = true, r2 = nbi(), t;
+  i = nbits(e[j])-1;
+  while(j >= 0) {
+    if(i >= k1) w = (e[j]>>(i-k1))&km;
+    else {
+      w = (e[j]&((1<<(i+1))-1))<<(k1-i);
+      if(j > 0) w |= e[j-1]>>(this.DB+i-k1);
+    }
+
+    n = k;
+    while((w&1) == 0) { w >>= 1; --n; }
+    if((i -= n) < 0) { i += this.DB; --j; }
+    if(is1) {    // ret == 1, don't bother squaring or multiplying it
+      g[w].copyTo(r);
+      is1 = false;
+    }
+    else {
+      while(n > 1) { z.sqrTo(r,r2); z.sqrTo(r2,r); n -= 2; }
+      if(n > 0) z.sqrTo(r,r2); else { t = r; r = r2; r2 = t; }
+      z.mulTo(r2,g[w],r);
+    }
+
+    while(j >= 0 && (e[j]&(1<<i)) == 0) {
+      z.sqrTo(r,r2); t = r; r = r2; r2 = t;
+      if(--i < 0) { i = this.DB-1; --j; }
+    }
+  }
+  return z.revert(r);
+}
+
+// (public) gcd(this,a) (HAC 14.54)
+function bnGCD(a) {
+  var x = (this.s<0)?this.negate():this.clone();
+  var y = (a.s<0)?a.negate():a.clone();
+  if(x.compareTo(y) < 0) { var t = x; x = y; y = t; }
+  var i = x.getLowestSetBit(), g = y.getLowestSetBit();
+  if(g < 0) return x;
+  if(i < g) g = i;
+  if(g > 0) {
+    x.rShiftTo(g,x);
+    y.rShiftTo(g,y);
+  }
+  while(x.signum() > 0) {
+    if((i = x.getLowestSetBit()) > 0) x.rShiftTo(i,x);
+    if((i = y.getLowestSetBit()) > 0) y.rShiftTo(i,y);
+    if(x.compareTo(y) >= 0) {
+      x.subTo(y,x);
+      x.rShiftTo(1,x);
+    }
+    else {
+      y.subTo(x,y);
+      y.rShiftTo(1,y);
+    }
+  }
+  if(g > 0) y.lShiftTo(g,y);
+  return y;
+}
+
+// (protected) this % n, n < 2^26
+function bnpModInt(n) {
+  if(n <= 0) return 0;
+  var d = this.DV%n, r = (this.s<0)?n-1:0;
+  if(this.t > 0)
+    if(d == 0) r = this[0]%n;
+    else for(var i = this.t-1; i >= 0; --i) r = (d*r+this[i])%n;
+  return r;
+}
+
+// (public) 1/this % m (HAC 14.61)
+function bnModInverse(m) {
+  var ac = m.isEven();
+  if((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO;
+  var u = m.clone(), v = this.clone();
+  var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1);
+  while(u.signum() != 0) {
+    while(u.isEven()) {
+      u.rShiftTo(1,u);
+      if(ac) {
+        if(!a.isEven() || !b.isEven()) { a.addTo(this,a); b.subTo(m,b); }
+        a.rShiftTo(1,a);
+      }
+      else if(!b.isEven()) b.subTo(m,b);
+      b.rShiftTo(1,b);
+    }
+    while(v.isEven()) {
+      v.rShiftTo(1,v);
+      if(ac) {
+        if(!c.isEven() || !d.isEven()) { c.addTo(this,c); d.subTo(m,d); }
+        c.rShiftTo(1,c);
+      }
+      else if(!d.isEven()) d.subTo(m,d);
+      d.rShiftTo(1,d);
+    }
+    if(u.compareTo(v) >= 0) {
+      u.subTo(v,u);
+      if(ac) a.subTo(c,a);
+      b.subTo(d,b);
+    }
+    else {
+      v.subTo(u,v);
+      if(ac) c.subTo(a,c);
+      d.subTo(b,d);
+    }
+  }
+  if(v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO;
+  if(d.compareTo(m) >= 0) return d.subtract(m);
+  if(d.signum() < 0) d.addTo(m,d); else return d;
+  if(d.signum() < 0) return d.add(m); else return d;
+}
+
+var lowprimes = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997];
+var lplim = (1<<26)/lowprimes[lowprimes.length-1];
+
+// (public) test primality with certainty >= 1-.5^t
+function bnIsProbablePrime(t) {
+  var i, x = this.abs();
+  if(x.t == 1 && x[0] <= lowprimes[lowprimes.length-1]) {
+    for(i = 0; i < lowprimes.length; ++i)
+      if(x[0] == lowprimes[i]) return true;
+    return false;
+  }
+  if(x.isEven()) return false;
+  i = 1;
+  while(i < lowprimes.length) {
+    var m = lowprimes[i], j = i+1;
+    while(j < lowprimes.length && m < lplim) m *= lowprimes[j++];
+    m = x.modInt(m);
+    while(i < j) if(m%lowprimes[i++] == 0) return false;
+  }
+  return x.millerRabin(t);
+}
+
+// (protected) true if probably prime (HAC 4.24, Miller-Rabin)
+function bnpMillerRabin(t) {
+  var n1 = this.subtract(BigInteger.ONE);
+  var k = n1.getLowestSetBit();
+  if(k <= 0) return false;
+  var r = n1.shiftRight(k);
+  t = (t+1)>>1;
+  if(t > lowprimes.length) t = lowprimes.length;
+  var a = nbi();
+  for(var i = 0; i < t; ++i) {
+    //Pick bases at random, instead of starting at 2
+    a.fromInt(lowprimes[Math.floor(Math.random()*lowprimes.length)]);
+    var y = a.modPow(r,this);
+    if(y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) {
+      var j = 1;
+      while(j++ < k && y.compareTo(n1) != 0) {
+        y = y.modPowInt(2,this);
+        if(y.compareTo(BigInteger.ONE) == 0) return false;
+      }
+      if(y.compareTo(n1) != 0) return false;
+    }
+  }
+  return true;
+}
+
+// protected
+BigInteger.prototype.chunkSize = bnpChunkSize;
+BigInteger.prototype.toRadix = bnpToRadix;
+BigInteger.prototype.fromRadix = bnpFromRadix;
+BigInteger.prototype.fromNumber = bnpFromNumber;
+BigInteger.prototype.bitwiseTo = bnpBitwiseTo;
+BigInteger.prototype.changeBit = bnpChangeBit;
+BigInteger.prototype.addTo = bnpAddTo;
+BigInteger.prototype.dMultiply = bnpDMultiply;
+BigInteger.prototype.dAddOffset = bnpDAddOffset;
+BigInteger.prototype.multiplyLowerTo = bnpMultiplyLowerTo;
+BigInteger.prototype.multiplyUpperTo = bnpMultiplyUpperTo;
+BigInteger.prototype.modInt = bnpModInt;
+BigInteger.prototype.millerRabin = bnpMillerRabin;
+
+// public
+BigInteger.prototype.clone = bnClone;
+BigInteger.prototype.intValue = bnIntValue;
+BigInteger.prototype.byteValue = bnByteValue;
+BigInteger.prototype.shortValue = bnShortValue;
+BigInteger.prototype.signum = bnSigNum;
+BigInteger.prototype.toByteArray = bnToByteArray;
+BigInteger.prototype.equals = bnEquals;
+BigInteger.prototype.min = bnMin;
+BigInteger.prototype.max = bnMax;
+BigInteger.prototype.and = bnAnd;
+BigInteger.prototype.or = bnOr;
+BigInteger.prototype.xor = bnXor;
+BigInteger.prototype.andNot = bnAndNot;
+BigInteger.prototype.not = bnNot;
+BigInteger.prototype.shiftLeft = bnShiftLeft;
+BigInteger.prototype.shiftRight = bnShiftRight;
+BigInteger.prototype.getLowestSetBit = bnGetLowestSetBit;
+BigInteger.prototype.bitCount = bnBitCount;
+BigInteger.prototype.testBit = bnTestBit;
+BigInteger.prototype.setBit = bnSetBit;
+BigInteger.prototype.clearBit = bnClearBit;
+BigInteger.prototype.flipBit = bnFlipBit;
+BigInteger.prototype.add = bnAdd;
+BigInteger.prototype.subtract = bnSubtract;
+BigInteger.prototype.multiply = bnMultiply;
+BigInteger.prototype.divide = bnDivide;
+BigInteger.prototype.remainder = bnRemainder;
+BigInteger.prototype.divideAndRemainder = bnDivideAndRemainder;
+BigInteger.prototype.modPow = bnModPow;
+BigInteger.prototype.modInverse = bnModInverse;
+BigInteger.prototype.pow = bnPow;
+BigInteger.prototype.gcd = bnGCD;
+BigInteger.prototype.isProbablePrime = bnIsProbablePrime;
+
+// JSBN-specific extension
+BigInteger.prototype.square = bnSquare;
+
+// BigInteger interfaces not implemented in jsbn:
+
+// BigInteger(int signum, byte[] magnitude)
+// double doubleValue()
+// float floatValue()
+// int hashCode()
+// long longValue()
+// static BigInteger valueOf(long val)
\ No newline at end of file
diff --git a/scripts/basic.js b/scripts/basic.js
index 80e840a..d73536e 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 of the 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/hashcaptcha.js b/scripts/hashcaptcha.js
index 620dc24..0bb99bb 100644
--- a/scripts/hashcaptcha.js
+++ b/scripts/hashcaptcha.js
@@ -72,205 +72,4 @@ function hashStamp(random_string, time, level)
         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/sha1.js b/scripts/sha1.js
new file mode 100644
index 0000000..96ae429
--- /dev/null
+++ b/scripts/sha1.js
@@ -0,0 +1,232 @@
+/**
+ *  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;
+
+    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..a29a59c
--- /dev/null
+++ b/scripts/zkp.js
@@ -0,0 +1,179 @@
+/*
+ *  To set the user_name and passsword in the cookies. This cookie is used in the
+ *  zero knowldge authentication module
+ *
+ *  @param String cname name of the cookie. user_name is used as cname
+ *  @param String cvalue value of the cookie. Password is used as cvalue
+ *  @param int exdays expiration time for the cookie
+ */
+function setCookie(cname, cvalue, exdays)
+{
+    var date = new Date();
+    date.setTime(date.getTime() + (exdays * 1000 * 60 * 2));
+    var expires = "expires=" + date.toGMTString();
+    document.cookie = cname + "=" + cvalue + "; " + expires;
+}
+
+/*
+ *  To get the passsword from the cookies. This cookie is used in the
+ *  zero knowldge authentication module
+ *
+ *  @param String cname name of the cookie. user_name is used as cname
+ *  @return String c cookie associated with the cookie name
+ */
+function getCookie(cname)
+{
+    var name = cname + "=";
+    var ca = document.cookie.split(';');
+    for (var i = 0; i < ca.length; i++) {
+        var c = ca[i].trim();
+        if (c.indexOf(name) == 0)
+            return c.substring(name.length, c.length);
+    }
+    return "";
+}
+
+/*
+ *  Returns RSA like modulus.
+ *
+ *  @return BigInteger RSA like modulus.
+ */
+
+function getN()
+{
+    return new BigInteger("49118961436116337806824024538499898007751892042"+
+    "5206572640822072909366693516929533335497211595856159654188292674113817"+
+    "4142872698595829944178957090296779606642580976458630868510407440881709"+
+    "556568052691", 10);
+}
+
+/*
+ *  Generates Fiat shamir parameters such as x and y and append
+ *  with the input form
+ *
+ *  @param Object form1 id of the form
+ *  @param int e random value sent by the server. Either 0 or 1.
+ *  @param String user_name id of the form
+ */
+function dynamicForm(form1, e, user_name)
+{
+    var theForm,newInput1,newInput2;
+    theForm = elt(form1);
+
+    var n = getN();
+    var r = getR(n);
+    final_r2 = r.pow(2);
+    var x = final_r2.mod(n);
+    var y = getY('', e, r, n);
+    newInput1 = ce('input');
+    newInput1.type = 'hidden';
+    newInput1.name = 'x1';
+    newInput1.value = x.toString(10);
+    newInput2 = ce('input');
+    newInput2.type = 'hidden';
+    newInput2.name = 'y1';
+    newInput2.value = y.toString(10);
+    newInput3 = ce('input');
+    newInput3.type = 'hidden';
+    newInput3.name = 'u';
+    newInput3.value = user_name;
+
+    theForm.appendChild(newInput1);
+    theForm.appendChild(newInput2);
+    theForm.appendChild(newInput3);
+    elt('hidden_form_container').appendChild(theForm);
+    theForm.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 BigInteger r random value picked by the client
+ *  @param BigInteger n RSA like modulus
+ *  @return BigInteger y fiat-shamir parameter Y.
+ */
+function getY(sha1, e, r, n)
+{
+    if (sha1 == '') {
+        sha1 = getCookie("user_name");
+    } else {
+        setCookie("user_name", sha1, 1);
+    }
+    var s = new BigInteger(sha1, 16);
+    se = s.pow(e);
+    ym = r.multiply(se);
+    y = ym.mod(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 + '';
+    var final_r = new BigInteger(r, 10);
+    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 password1 password provided by user
+ *  @param int e1 random value send by the server. Either 0 or 1.
+ */
+function generateKeys(form1, password1, e)
+{
+
+    var form = document.getElementById(form1);
+    var password = document.getElementById(password1).value;
+    alert(1);
+    var n = new getN();
+    var r = getR();
+    final_r2 = r.pow(2);
+    var x = final_r2.mod(n);
+    var sha1 = generateSha1(password);
+    var y = getY(sha1, e, r, n);
+    newInput1 = document.createElement('input');
+    newInput1.type = 'hidden';
+    newInput1.name = 'x1';
+    newInput1.value = x.toString(10);
+
+    newInput2 = document.createElement('input');
+    newInput2.type = 'hidden';
+    newInput2.name = 'y1';
+    newInput2.value = y.toString(10);
+    form.appendChild(newInput1);
+    form.appendChild(newInput2);
+}
+
+/*
+ *  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)
+{
+    var password1 = document.getElementById(password);
+    var repassword1 = document.getElementById(repassword);
+    var sha1 = generateSha1(password1.value);
+    var x = new BigInteger(sha1, 16);
+    x2 = x.pow(2);
+    var n = getN();
+    var z = x2.mod(n);
+    password1.value = z.toString(10);
+    repassword1.value = z.toString(10);
+}
\ No newline at end of file
diff --git a/views/crawlstatus_view.php b/views/crawlstatus_view.php
index e1aac40..da7d5a2 100755
--- a/views/crawlstatus_view.php
+++ b/views/crawlstatus_view.php
@@ -264,4 +264,4 @@ class CrawlstatusView extends View
     <?php
     }
 }
-?>
+?>
\ No newline at end of file
diff --git a/views/elements/editmix_element.php b/views/elements/editmix_element.php
index 9334642..b5849ac 100644
--- a/views/elements/editmix_element.php
+++ b/views/elements/editmix_element.php
@@ -95,4 +95,4 @@ class EditmixElement extends Element
     <?php
     }
 }
-?>
+?>
\ No newline at end of file
diff --git a/views/elements/groupfeed_element.php b/views/elements/groupfeed_element.php
index a9ecdbe..461d438 100644
--- a/views/elements/groupfeed_element.php
+++ b/views/elements/groupfeed_element.php
@@ -340,4 +340,4 @@ class GroupfeedElement extends Element implements CrawlConstants
         }
     }
 }
- ?>
+ ?>
\ No newline at end of file
diff --git a/views/elements/manageaccount_element.php b/views/elements/manageaccount_element.php
index 5417461..7f5b43b 100755
--- a/views/elements/manageaccount_element.php
+++ b/views/elements/manageaccount_element.php
@@ -193,4 +193,4 @@ class ManageaccountElement extends Element
         <?php
     }
 }
-?>
+?>
\ No newline at end of file
diff --git a/views/elements/manageclassifiers_element.php b/views/elements/manageclassifiers_element.php
index 85a6bc4..7b60a40 100644
--- a/views/elements/manageclassifiers_element.php
+++ b/views/elements/manageclassifiers_element.php
@@ -72,7 +72,7 @@ class ManageclassifiersElement extends Element
                 e(tl('manageclassifiers_create_button')) ?></button>
         </div>
         </form>
-        <?php if (!empty($data['classifiers'])) { 
+        <?php if (!empty($data['classifiers'])) {
         $data['TABLE_TITLE'] = tl('manageclassifiers_available_classifiers');
         $data['ACTIVITY'] = 'manageClassifiers';
         $data['VIEW'] = $this->view;
@@ -143,4 +143,4 @@ class ManageclassifiersElement extends Element
     <?php
     }
 }
-?>
+?>
\ No newline at end of file
diff --git a/views/elements/managecrawls_element.php b/views/elements/managecrawls_element.php
index 8479083..233e186 100755
--- a/views/elements/managecrawls_element.php
+++ b/views/elements/managecrawls_element.php
@@ -112,4 +112,4 @@ class ManagecrawlsElement
     <?php
     }
 }
-?>
+?>
\ No newline at end of file
diff --git a/views/elements/managegroups_element.php b/views/elements/managegroups_element.php
index 9b4a4ef..2be1a30 100755
--- a/views/elements/managegroups_element.php
+++ b/views/elements/managegroups_element.php
@@ -190,7 +190,7 @@ class ManagegroupsElement extends Element
                 <td><?php
                     if($group['OWNER_ID']!=$_SESSION['USER_ID']||
                         $group['GROUP_NAME'] == 'Public') {
-                        if(isset($group['STATUS']) && 
+                        if(isset($group['STATUS']) &&
                             $group['STATUS'] == INVITED_STATUS) {
                             ?><a href="<?php e($join_url . 'group_id='.
                                 $group['GROUP_ID'].'&amp;user_id=' .
@@ -210,7 +210,7 @@ class ManagegroupsElement extends Element
                     if($group['GROUP_NAME'] == 'Public') {
                         e('<span class="gray">'.
                             tl('managegroups_element_delete').'</span>');
-                    } else if(isset($data['browse']) && 
+                    } else if(isset($data['browse']) &&
                         $data['browse'] == 'true') {
                         if( $group['REGISTER_TYPE'] == NO_JOIN &&
                             $_SESSION['USER_ID']  != ROOT_ID) {
@@ -300,12 +300,12 @@ class ManagegroupsElement extends Element
                 }
                 ?> /></td><?php
                 if($addgroup) { ?>
-                    <td>[<a href="<?php e($browse_url); ?>"><?php 
+                    <td>[<a href="<?php e($browse_url); ?>"><?php
                         e(tl('managegroups_element_browse')); ?></a>]</td>
                 <?php
                 }
         ?></tr>
-        <?php 
+        <?php
         if($creategroup || $editgroup) { ?>
             <tr><th class="table-label"><label for="register-type"><?php
                 e(tl('managegroups_element_register'))?></label>:</th>
@@ -412,7 +412,7 @@ class ManagegroupsElement extends Element
                             </td>
                             <td colspan="2" class="center">
                                 <input class="very-narrow-field center"
-                                    name="user_filter" type="text" 
+                                    name="user_filter" type="text"
                                     max-length="10" value='<?php
                                     e($data['USER_FILTER']); ?>' /><br />
                                 <button type="submit" name="change_filter"
@@ -715,4 +715,4 @@ class ManagegroupsElement extends Element
         <?php
     }
 }
-?>
+?>
\ No newline at end of file
diff --git a/views/elements/manageusers_element.php b/views/elements/manageusers_element.php
index af419ed..7c3e8a2 100644
--- a/views/elements/manageusers_element.php
+++ b/views/elements/manageusers_element.php
@@ -286,7 +286,7 @@ class ManageusersElement extends Element
                     if($data['ROLE_FILTER'] != "" ||
                         (isset($data['NUM_USER_ROLES']) &&
                         $data['NUM_USER_ROLES'] > NUM_RESULTS_PER_PAGE)) {
-                        $limit = isset($data['ROLE_LIMIT']) ? 
+                        $limit = isset($data['ROLE_LIMIT']) ?
                             $data['ROLE_LIMIT']: 0;
                     ?>
                         <div class="center">
@@ -302,7 +302,7 @@ class ManageusersElement extends Element
                                 >&lt;&lt;</a><?php
                             }
                             ?>
-                        <input class="very-narrow-field center" 
+                        <input class="very-narrow-field center"
                             name="role_filter" type="text" max-length="10"
                             value='<?php e($data['ROLE_FILTER']); ?>' />
                             <?php
@@ -368,7 +368,7 @@ class ManageusersElement extends Element
                     if($data['GROUP_FILTER'] != "" ||
                         (isset($data['NUM_USER_GROUPS']) &&
                         $data['NUM_USER_GROUPS'] > NUM_RESULTS_PER_PAGE)) {
-                        $limit = isset($data['GROUP_LIMIT']) ? 
+                        $limit = isset($data['GROUP_LIMIT']) ?
                             $data['GROUP_LIMIT']: 0;
                     ?>
                         <div class="center">
@@ -384,22 +384,22 @@ class ManageusersElement extends Element
                                 >&lt;&lt;</a><?php
                             }
                             ?>
-                        <input class="very-narrow-field center" 
-                            name="group_filter" type="text" max-length="10" 
+                        <input class="very-narrow-field center"
+                            name="group_filter" type="text" max-length="10"
                             value='<?php  e($data['GROUP_FILTER']); ?>' />
                         <?php
                             if($data['NUM_USER_GROUPS'] > $limit +
                                 NUM_RESULTS_PER_PAGE) {
                                 ?><a href='<?php e(
                                 "$action_url&amp;arg=edituser&amp;group_limit=".
-                                ($limit + NUM_RESULTS_PER_PAGE)); 
+                                ($limit + NUM_RESULTS_PER_PAGE));
                                 ?>'>&gt;&gt;</a>
                             <?php
                             }
                         ?><br />
                         <button type="submit" name="change_filter"
                             value="group"><?php
-                        e(tl('manageusers_element_filter')); 
+                        e(tl('manageusers_element_filter'));
                         ?></button><br />&nbsp;
                     </div>
                     <?php
@@ -411,7 +411,7 @@ class ManageusersElement extends Element
                     <button type="submit"
                         class="button-box">
                         <label for='select-group'><?php
-                        e(tl('manageusers_element_add_group')); 
+                        e(tl('manageusers_element_add_group'));
                         ?></label></button>
                     </div>
                     </div>
@@ -602,4 +602,4 @@ class ManageusersElement extends Element
         <?php
     }
 }
-?>
+?>
\ No newline at end of file
diff --git a/views/elements/mixcrawls_element.php b/views/elements/mixcrawls_element.php
index 61c52e7..f3ead51 100644
--- a/views/elements/mixcrawls_element.php
+++ b/views/elements/mixcrawls_element.php
@@ -65,7 +65,7 @@ class MixcrawlsElement extends Element
         } else {
             $this->renderMixForm($data);
         }
-        if($mixes_exist) { 
+        if($mixes_exist) {
         $data['TABLE_TITLE'] = tl('mixcrawls_element_available_mixes');
         $data['ACTIVITY'] = 'mixCrawls';
         $data['VIEW'] = $this->view;
@@ -250,4 +250,4 @@ class MixcrawlsElement extends Element
         <?php
     }
 }
-?>
+?>
\ No newline at end of file
diff --git a/views/elements/serversettings_element.php b/views/elements/serversettings_element.php
index 2d4bb08..d3c2742 100644
--- a/views/elements/serversettings_element.php
+++ b/views/elements/serversettings_element.php
@@ -251,6 +251,20 @@ class ServersettingsElement extends Element
                 ?>
             </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>
             <div class="top-margin center">
             <button class="button-box" type="submit"><?php
                 e(tl('serversettings_element_submit')); ?></button>
@@ -262,4 +276,4 @@ class ServersettingsElement extends Element
     <?php
     }
 }
-?>
+?>
\ No newline at end of file
diff --git a/views/elements/signin_element.php b/views/elements/signin_element.php
index 2b136b5..c78b377 100755
--- a/views/elements/signin_element.php
+++ b/views/elements/signin_element.php
@@ -84,4 +84,4 @@ class SigninElement extends Element
     <?php
     }
 }
-?>
+?>
\ No newline at end of file
diff --git a/views/helpers/feeds_helper.php b/views/helpers/feeds_helper.php
index 7523629..7d352b8 100644
--- a/views/helpers/feeds_helper.php
+++ b/views/helpers/feeds_helper.php
@@ -175,4 +175,4 @@ class FeedsHelper extends Helper implements CrawlConstants
         return $pub_date;
     }
 }
-?>
+?>
\ No newline at end of file
diff --git a/views/helpers/pagingtable_helper.php b/views/helpers/pagingtable_helper.php
index df2b101..5b636b5 100644
--- a/views/helpers/pagingtable_helper.php
+++ b/views/helpers/pagingtable_helper.php
@@ -221,4 +221,4 @@ class PagingtableHelper extends Helper
         }
     }
 }
-?>
+?>
\ No newline at end of file
diff --git a/views/layouts/web_layout.php b/views/layouts/web_layout.php
index 74d79e3..aaa0157 100755
--- a/views/layouts/web_layout.php
+++ b/views/layouts/web_layout.php
@@ -152,4 +152,4 @@ class WebLayout extends Layout
     </html><?php
     }
 }
-?>
+?>
\ No newline at end of file
diff --git a/views/recover_view.php b/views/recover_view.php
index 57fe7e6..01bd558 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..f8cc86b 100755
--- a/views/register_view.php
+++ b/views/register_view.php
@@ -73,6 +73,15 @@ class RegisterView extends View
                 src="<?php e($logo); ?>" alt="Yioop!"/></a>
                 <span> - <?php e(tl('register_view_create_account'));
                 ?></span></h1>
+               <?php if($data['AUTHENTICATION_MODE'] == 'zkp_authentication')
+                  { ?>
+                        <form action="" method="post" onsubmit="registration('password','repassword')">
+                        <input type="hidden" name="numericPassword" id="numericPassword"/>
+                  <?php }
+                  else
+                  { ?>
+                        <form method="post" action="#">
+            <?php }?>
             <form method="post" action="#">
             <input type="hidden" name="c" value="register" />
             <input type="hidden" name="a" value="processAccountData" />
@@ -150,8 +159,7 @@ class RegisterView extends View
                             <td class="table-input">
                                 <input id="password" type="password"
                                     class="narrow-field" maxlength="80"
-                                    name="password" value="<?php
-                                    e($data['PASSWORD']); ?>" />
+                                    name="password" />
                                 <?php echo in_array("password", $missing)
                                     ? '<span class="red">*</span>':'';?></td>
                         </tr>
@@ -164,8 +172,7 @@ class RegisterView extends View
                             <td class="table-input">
                                 <input id="repassword" type="password"
                                     class="narrow-field" maxlength="80"
-                                    name="repassword" value="<?php
-                                    e($data['REPASSWORD']); ?>" />
+                                    name="repassword"  />
                                 <?php echo in_array("repassword", $missing)
                                     ?'<span class="red">*</span>':''; ?></td>
                         </tr>
@@ -243,4 +250,4 @@ class RegisterView extends View
     <?php
         }
     }
-    ?>
+    ?>
\ No newline at end of file
diff --git a/views/settings_view.php b/views/settings_view.php
index fdbd4c9..ff24159 100755
--- a/views/settings_view.php
+++ b/views/settings_view.php
@@ -120,4 +120,4 @@ class SettingsView extends View
 <?php
     }
 }
-?>
+?>
\ No newline at end of file
diff --git a/views/signin_view.php b/views/signin_view.php
index 55b79e9..7a5db0d 100755
--- a/views/signin_view.php
+++ b/views/signin_view.php
@@ -66,7 +66,14 @@ 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($_SESSION['salt_value']) && ($_SESSION['COUNT'] == 1))
+        {?>
+           <form action="http://localhost/yioop/?c=admin" method="post"
+                id="form1" onsubmit="generateKeys('form1','password',
+                '<?php echo $_SESSION['salt_value'];  ?>')">
+        <?php } else {?>
+        <form  id="form1" method="post" action="#">
+        <?php } ?>
         <div class="login">
             <table>
             <tr>
@@ -113,7 +120,18 @@ class SigninView extends View
         </div>
         </div>
         <div class='landing-spacer'></div>
+        <div class='landing-spacer'></div>
+        <?php  if ( isset($_SESSION['salt_value']) && ($_SESSION['COUNT'] > 1)) {  ?>
+        <div id="hidden_form_container" style="display:none;"></div>
+        <script type="text/javascript" >
+            document.addEventListener('DOMContentLoaded', function() {
+            var body = tag(body);
+            body.onload = dynamicForm('form1','<?php echo $_SESSION['salt_value'];
+                ?>','<?php echo $_SESSION['USER_NAME']; ?>');
+            }, false);
+        </script>
         <?php
+        }
     }
 }
 ?>
\ No newline at end of file
-- 
1.8.0.msysgit.0

