diff --git a/src/ecdsa.js b/src/ecdsa.js
index 77a3ca7..1f84456 100644
--- a/src/ecdsa.js
+++ b/src/ecdsa.js
@@ -40,11 +40,12 @@ ECPointFp.prototype.getEncoded = function (compressed) {
 };
 
 ECPointFp.decodeFrom = function (curve, enc) {
-	var type = enc.shift();
+	var type = enc[0];
+  var dataLen = enc.length-1;
 
 	// Extract x and y as byte arrays
-	var xBa = enc.slice(0, enc.length/2);
-	var yBa = enc.slice(enc.length/2, enc.length);
+	var xBa = enc.slice(1, 1 + dataLen/2);
+	var yBa = enc.slice(1 + dataLen/2, 1 + dataLen);
 
 	// Prepend zero byte to prevent interpretation as negative integer
 	xBa.unshift(0);
@@ -101,16 +102,16 @@ ECPointFp.prototype.twice2D = function () {
 
 ECPointFp.prototype.multiply2D = function (k) {
 	if(this.isInfinity()) return this;
-    if(k.signum() == 0) return this.curve.getInfinity();
+  if(k.signum() == 0) return this.curve.getInfinity();
 
-    var e = k;
-    var h = e.multiply(new BigInteger("3"));
+  var e = k;
+  var h = e.multiply(new BigInteger("3"));
 
-    var neg = this.negate();
-    var R = this;
+  var neg = this.negate();
+  var R = this;
 
-    var i;
-    for (i = h.bitLength() - 2; i > 0; --i) {
+  var i;
+  for (i = h.bitLength() - 2; i > 0; --i) {
 		R = R.twice();
 
 		var hBit = h.testBit(i);
@@ -119,9 +120,55 @@ ECPointFp.prototype.multiply2D = function (k) {
 		if (hBit != eBit) {
 			R = R.add2D(hBit ? this : neg);
 		}
-    }
+  }
 
-    return R;
+  return R;
+};
+
+ECPointFp.prototype.isOnCurve = function () {
+  var x = this.getX().toBigInteger();
+  var y = this.getY().toBigInteger();
+  var a = this.curve.getA().toBigInteger();
+  var b = this.curve.getB().toBigInteger();
+  var n = this.curve.getQ();
+  var lhs = y.multiply(y).mod(n);
+  var rhs = x.multiply(x).multiply(x)
+    .add(a.multiply(x)).add(b).mod(n);
+  return lhs.equals(rhs);
+};
+
+ECPointFp.prototype.validate = function () {
+  var n = this.curve.getQ();
+
+  // Check Q != O
+  if (this.isInfinity()) {
+    throw new Error("Point is at infinity.");
+  }
+
+  // Check coordinate bounds
+  var x = this.getX().toBigInteger();
+  var y = this.getY().toBigInteger();
+  if (x.compareTo(BigInteger.ONE) < 0 ||
+      x.compareTo(n.subtract(BigInteger.ONE)) > 0) {
+    throw new Error('x coordinate out of bounds');
+  }
+  if (y.compareTo(BigInteger.ONE) < 0 ||
+      y.compareTo(n.subtract(BigInteger.ONE)) > 0) {
+    throw new Error('y coordinate out of bounds');
+  }
+
+  // Check y^2 = x^3 + ax + b (mod n)
+  if (!this.isOnCurve()) {
+    throw new Error("Point is not on the curve.");
+  }
+
+  // Check nQ = 0 (Q is a scalar multiple of G)
+  if (this.multiply(n).isInfinity()) {
+    // TODO: This check doesn't work - fix.
+    throw new Error("Point is not a scalar multiple of G.");
+  }
+
+  return true;
 };
 
 function dmp(v) {
@@ -181,6 +228,10 @@ Bitcoin.ECDSA = (function () {
 
 			var s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n);
 
+      return ECDSA.serializeSig(r, s);
+		},
+
+    serializeSig: function (r, s) {
 			var rBa = r.toByteArrayUnsigned();
 			var sBa = s.toByteArrayUnsigned();
 
@@ -197,34 +248,16 @@ Bitcoin.ECDSA = (function () {
 			sequence.unshift(0x30) // SEQUENCE
 
 			return sequence;
-		},
+    },
 
 		verify: function (hash, sig, pubkey) {
-			var cursor;
-			if (sig[0] != 0x30)
-				throw new Error("Signature not a valid DERSequence");
-
-			cursor = 2;
-			if (sig[cursor] != 0x02)
-				throw new Error("First element in signature must be a DERInteger");;
-			var rBa = sig.slice(cursor+2, cursor+2+sig[cursor+1]);
-
-			cursor += 2+sig[cursor+1];
-			if (sig[cursor] != 0x02)
-				throw new Error("Second element in signature must be a DERInteger");
-			var sBa = sig.slice(cursor+2, cursor+2+sig[cursor+1]);
-
-			cursor += 2+sig[cursor+1];
-
-			//if (cursor != sig.length)
-			//	throw new Error("Extra bytes in signature");
+      var obj = ECDSA.parseSig(sig);
+      var r = obj.r;
+      var s = obj.s;
 
 			var n = ecparams.getN();
 			var e = BigInteger.fromByteArrayUnsigned(hash);
 
-			var r = BigInteger.fromByteArrayUnsigned(rBa);
-			var s = BigInteger.fromByteArrayUnsigned(sBa);
-
 			if (r.compareTo(BigInteger.ONE) < 0 ||
 				r.compareTo(n) >= 0)
 				return false;
@@ -246,7 +279,33 @@ Bitcoin.ECDSA = (function () {
 			var v = point.x.toBigInteger().mod(n);
 
 			return v.equals(r);
-		}
+		},
+
+    parseSig: function (sig) {
+			var cursor;
+			if (sig[0] != 0x30)
+				throw new Error("Signature not a valid DERSequence");
+
+			cursor = 2;
+			if (sig[cursor] != 0x02)
+				throw new Error("First element in signature must be a DERInteger");;
+			var rBa = sig.slice(cursor+2, cursor+2+sig[cursor+1]);
+
+			cursor += 2+sig[cursor+1];
+			if (sig[cursor] != 0x02)
+				throw new Error("Second element in signature must be a DERInteger");
+			var sBa = sig.slice(cursor+2, cursor+2+sig[cursor+1]);
+
+			cursor += 2+sig[cursor+1];
+
+			//if (cursor != sig.length)
+			//	throw new Error("Extra bytes in signature");
+
+			var r = BigInteger.fromByteArrayUnsigned(rBa);
+			var s = BigInteger.fromByteArrayUnsigned(sBa);
+
+      return {r: r, s: s};
+    }
 	};
 
 	return ECDSA;