From 69c52d51b3362047f6791ce2e12d75f125fb4c45 Mon Sep 17 00:00:00 2001
From: lilia <liliakai@gmail.com>
Date: Thu, 6 Nov 2014 14:54:31 -0800
Subject: [PATCH] Abstract out curve25519 tests

Also rename the internal variable in crypto.js to be a little more
explicit about which curve we're dealing with.
---
 js/crypto.js              |  14 ++---
 test/curve25519_test.js   | 111 ++++++++++++++++++++++++++++++++++++++
 test/index.html           |   1 +
 test/nativeclient_test.js |  73 +------------------------
 4 files changed, 121 insertions(+), 78 deletions(-)
 create mode 100644 test/curve25519_test.js

diff --git a/js/crypto.js b/js/crypto.js
index be06af99b..477eba0fc 100644
--- a/js/crypto.js
+++ b/js/crypto.js
@@ -22,9 +22,9 @@
      *    for all low-level crypto operations,
      */
 
-    // TODO Select an ecc implementation
-    //var ecc = textsecure.NATIVE_CLIENT ? textsecure.nativeclient : textsecure.tweetnacl || asmjs;
-    var ecc = textsecure.nativeclient;
+    // TODO Select an curve25519 implementation
+    //var curve25519 = textsecure.NATIVE_CLIENT ? textsecure.nativeclient : textsecure.tweetnacl || asmjs;
+    var curve25519 = textsecure.nativeclient;
 
     window.textsecure.crypto = {
         getRandomBytes: function(size) {
@@ -82,7 +82,7 @@
                 throw new Error("Invalid private key");
             }
 
-            return ecc.privToPub(privKey).then(function(raw_keys) {
+            return curve25519.privToPub(privKey).then(function(raw_keys) {
                 // prepend version byte
                 var origPub = new Uint8Array(raw_keys.pubKey);
                 var pub = new Uint8Array(33);
@@ -100,7 +100,7 @@
             if (pubKey === undefined || pubKey.byteLength != 32)
                 throw new Error("Invalid public key");
 
-            return ecc.ECDHE(pubKey, privKey);
+            return curve25519.ECDHE(pubKey, privKey);
         },
         Ed25519Sign: function(privKey, message) {
             if (privKey === undefined || privKey.byteLength != 32)
@@ -109,7 +109,7 @@
             if (message === undefined)
                 throw new Error("Invalid message");
 
-            return ecc.Ed25519Sign(privKey, message);
+            return curve25519.Ed25519Sign(privKey, message);
         },
         Ed25519Verify: function(pubKey, msg, sig) {
             pubKey = validatePubKeyFormat(pubKey);
@@ -123,7 +123,7 @@
             if (sig === undefined || sig.byteLength != 64)
                 throw new Error("Invalid signature");
 
-            return ecc.Ed25519Verify(pubKey, msg, sig);
+            return curve25519.Ed25519Verify(pubKey, msg, sig);
         }
     };
 
diff --git a/test/curve25519_test.js b/test/curve25519_test.js
new file mode 100644
index 000000000..4e54cd8d3
--- /dev/null
+++ b/test/curve25519_test.js
@@ -0,0 +1,111 @@
+/* vim: ts=4:sw=4
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+'use strict';
+
+/*
+ * We don't run any tests here, just define an abstract test function
+ * that excercises our requirements for curve25519 interface, which are
+ *
+ * privTopub(privateKey)
+ *   takes a 32-byte private key array buffer and outputs the corresponding
+ *   public key as an array buffer
+ *
+ * ECDHE(publicKey, privateKey)
+ *  computes a shared secret from two curve25519 keys using the given keys
+ *
+ * Ed25519Sign(privateKey, message)
+ *  computes a signature for the given message using a private key
+ *
+ * Ed25519Verify(publicKey, message, signature)
+ *  verifies a signature for the given message using a public key
+ *
+ */
+
+var test_curve25519_implementation = function(implementation) {
+  describe("Curve25519", function() {
+    var alice_bytes = hexToArrayBuffer("77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a");
+    var alice_priv  = hexToArrayBuffer("70076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c6a");
+    var alice_pub   = hexToArrayBuffer("8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a");
+    var bob_bytes   = hexToArrayBuffer("5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb");
+    var bob_priv    = hexToArrayBuffer("58ab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e06b");
+    var bob_pub     = hexToArrayBuffer("de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f");
+    var shared_sec  = hexToArrayBuffer("4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742");
+
+    describe("privToPub", function() {
+        it ('converts alice private keys to a keypair', function(done) {
+            implementation.privToPub(alice_bytes).then(function(keypair) {
+              assertEqualArrayBuffers(keypair.privKey, alice_priv);
+              assertEqualArrayBuffers(keypair.pubKey, alice_pub);
+              done();
+            }).catch(done);
+        });
+        it ('converts bob private keys to a keypair', function(done) {
+            implementation.privToPub(bob_bytes).then(function(keypair) {
+              assertEqualArrayBuffers(keypair.privKey, bob_priv);
+              assertEqualArrayBuffers(keypair.pubKey, bob_pub);
+              done();
+            }).catch(done);
+        });
+    });
+
+    describe("ECDHE", function() {
+      it("computes the shared secret for alice", function(done) {
+          implementation.ECDHE(bob_pub, alice_priv).then(function(secret) {
+              assertEqualArrayBuffers(shared_sec, secret);
+              done();
+          }).catch(done);
+      });
+      it("computes the shared secret for bob", function(done) {
+          implementation.ECDHE(alice_pub, bob_priv).then(function(secret) {
+              assertEqualArrayBuffers(shared_sec, secret);
+              done();
+          }).catch(done);
+      });
+    });
+
+    var priv = hexToArrayBuffer("48a8892cc4e49124b7b57d94fa15becfce071830d6449004685e387c62409973");
+    var pub  = hexToArrayBuffer("55f1bfede27b6a03e0dd389478ffb01462e5c52dbbac32cf870f00af1ed9af3a");
+    var msg  = hexToArrayBuffer("617364666173646661736466");
+    var sig  = hexToArrayBuffer("2bc06c745acb8bae10fbc607ee306084d0c28e2b3bb819133392473431291fd0dfa9c7f11479996cf520730d2901267387e08d85bbf2af941590e3035a545285");
+    describe("Ed25519Sign", function() {
+      it("computes the signature", function(done) {
+        implementation.Ed25519Sign(priv, msg).then(function(signature) {
+            assertEqualArrayBuffers(sig, signature);
+            done();
+        }).catch(done);
+      });
+    });
+
+    describe("Ed25519Verify", function() {
+      it("throws on bad signature", function(done) {
+        var badsig = sig.slice(0);
+        new Uint8Array(badsig).set([0], 0);
+
+          implementation.Ed25519Verify(pub, msg, badsig).catch(function(e) {
+            if (e.message === 'Invalid signature') {
+              done();
+            } else { throw e; }
+          }).catch(done);
+      });
+
+      it("does not throw on good signature", function(done) {
+        implementation.Ed25519Verify(pub, msg, sig).then(done).catch(done);
+      });
+    });
+  });
+};
+
diff --git a/test/index.html b/test/index.html
index b23555e38..977e9804f 100644
--- a/test/index.html
+++ b/test/index.html
@@ -156,6 +156,7 @@
 
 	<script type="text/javascript" src="fake_api.js"></script>
 	<script type="text/javascript" src="testvectors.js"></script>
+	<script type="text/javascript" src="curve25519_test.js"></script>
 	<script type="text/javascript" src="crypto_test.js"></script>
 	<script type="text/javascript" src="protocol_test.js"></script>
 	<script type="text/javascript" src="nativeclient_test.js"></script>
diff --git a/test/nativeclient_test.js b/test/nativeclient_test.js
index 3f6a9b8bb..582bc9907 100644
--- a/test/nativeclient_test.js
+++ b/test/nativeclient_test.js
@@ -16,81 +16,12 @@
 
 'use strict';
 
-describe("textsecure.nativeclient", function() {
-    var alice_bytes = hexToArrayBuffer("77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a");
-    var alice_priv  = hexToArrayBuffer("70076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c6a");
-    var alice_pub   = hexToArrayBuffer("8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a");
-    var bob_bytes   = hexToArrayBuffer("5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb");
-    var bob_priv    = hexToArrayBuffer("58ab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e06b");
-    var bob_pub     = hexToArrayBuffer("de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f");
-    var shared_sec  = hexToArrayBuffer("4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742");
-
-    describe("privToPub", function() {
-        it ('converts alice private keys to a keypair', function(done) {
-            textsecure.nativeclient.privToPub(alice_bytes).then(function(keypair) {
-              assertEqualArrayBuffers(keypair.privKey, alice_priv);
-              assertEqualArrayBuffers(keypair.pubKey, alice_pub);
-              done();
-            }).catch(done);
-        });
-        it ('converts bob private keys to a keypair', function(done) {
-            textsecure.nativeclient.privToPub(bob_bytes).then(function(keypair) {
-              assertEqualArrayBuffers(keypair.privKey, bob_priv);
-              assertEqualArrayBuffers(keypair.pubKey, bob_pub);
-              done();
-            }).catch(done);
-        });
-    });
-
-    describe("ECDHE", function() {
-      it("computes the shared secret for alice", function(done) {
-          textsecure.nativeclient.ECDHE(bob_pub, alice_priv).then(function(secret) {
-              assertEqualArrayBuffers(shared_sec, secret);
-              done();
-          }).catch(done);
-      });
-      it("computes the shared secret for bob", function(done) {
-          textsecure.nativeclient.ECDHE(alice_pub, bob_priv).then(function(secret) {
-              assertEqualArrayBuffers(shared_sec, secret);
-              done();
-          }).catch(done);
-      });
-    });
-
-    var priv = hexToArrayBuffer("48a8892cc4e49124b7b57d94fa15becfce071830d6449004685e387c62409973");
-    var pub  = hexToArrayBuffer("55f1bfede27b6a03e0dd389478ffb01462e5c52dbbac32cf870f00af1ed9af3a");
-    var msg  = hexToArrayBuffer("617364666173646661736466");
-    var sig  = hexToArrayBuffer("2bc06c745acb8bae10fbc607ee306084d0c28e2b3bb819133392473431291fd0dfa9c7f11479996cf520730d2901267387e08d85bbf2af941590e3035a545285");
-    describe("Ed25519Sign", function() {
-      it("computes the signature", function(done) {
-        textsecure.nativeclient.Ed25519Sign(priv, msg).then(function(signature) {
-            assertEqualArrayBuffers(sig, signature);
-            done();
-        }).catch(done);
-      });
-    });
-
-    describe("Ed25519Verify", function() {
-      it("throws on bad signature", function(done) {
-        var badsig = sig.slice(0);
-        new Uint8Array(badsig).set([0], 0);
-
-          textsecure.nativeclient.Ed25519Verify(pub, msg, badsig).catch(function(e) {
-            if (e.message === 'Invalid signature') {
-              done();
-            } else { throw e; }
-          }).catch(done);
-      });
-
-      it("does not throw on good signature", function(done) {
-        textsecure.nativeclient.Ed25519Verify(pub, msg, sig).then(done).catch(done);
-      });
-    });
+describe("Native Client", function()  {
+    test_curve25519_implementation(textsecure.nativeclient);
 
     describe("registerOnLoadFunction", function() {
       it('queues a callback til native client is loaded', function(done) {
         textsecure.nativeclient.registerOnLoadFunction(done);
       });
     });
-
 });