text: Bitcoin.KeyPool = (function () {
  	var KeyPool = function () {
  		this.keyArray = [];
  
  		this.push = function (item) {
  			if (item == null || item.priv == null) return;
  			var doAdd = true;
  			// prevent duplicates from being added to the array
  			for (var index in this.keyArray) {
  				var currentItem = this.keyArray[index];
  				if (currentItem != null && currentItem.priv != null && item.getBitcoinAddress() == currentItem.getBitcoinAddress()) {
  					doAdd = false;
  					break;
  				}
  			}
  			if (doAdd) this.keyArray.push(item);
  		};
  
  		this.reset = function () {
  			this.keyArray = [];
  		};
  
  		this.getArray = function () {
  			// copy array
  			return this.keyArray.slice(0);
  		};
  
  		this.setArray = function (ka) {
  			this.keyArray = ka;
  		};
  
  		this.length = function () {
  			return this.keyArray.length;
  		};
  
  		this.toString = function () {
  			var keyPoolString = "# = " + this.length() + "\n";
  			var pool = this.getArray();
  			for (var index in pool) {
  				var item = pool[index];
  				if (Bitcoin.Util.hasMethods(item, 'getBitcoinAddress', 'toString')) {
  					if (item != null) {
  						keyPoolString += "\"" + item.getBitcoinAddress() + "\"" + ", \"" + item.toString("wif") + "\"\n";
  					}
  				}
  			}
  
  			return keyPoolString;
  		};
  
  		return this;
  	};
  
  	return new KeyPool();
  })();
  
  Bitcoin.Bip38Key = (function () {
  	var Bip38 = function (address, encryptedKey) {
  		this.address = address;
  		this.priv = encryptedKey;
  	};
  
  	Bip38.prototype.getBitcoinAddress = function () {
  		return this.address;
  	};
  
  	Bip38.prototype.toString = function () {
  		return this.priv;
  	};
  
  	return Bip38;
  })();
  
  //https://raw.github.com/pointbiz/bitcoinjs-lib/9b2f94a028a7bc9bed94e0722563e9ff1d8e8db8/src/eckey.js
  Bitcoin.ECKey = (function () {
  	var ECDSA = Bitcoin.ECDSA;
  	var KeyPool = Bitcoin.KeyPool;
  	var ecparams = EllipticCurve.getSECCurveByName("secp256k1");
  
  	var ECKey = function (input) {
  		if (!input) {
  			// Generate new key
  			var n = ecparams.getN();
  			this.priv = ECDSA.getBigRandom(n);
  		} else if (input instanceof BigInteger) {
  			// Input is a private key value
  			this.priv = input;
  		} else if (Bitcoin.Util.isArray(input)) {
  			// Prepend zero byte to prevent interpretation as negative integer
  			this.priv = BigInteger.fromByteArrayUnsigned(input);
  		} else if ("string" == typeof input) {
  			var bytes = null;
  			try{
  				if (ECKey.isWalletImportFormat(input)) {
  					bytes = ECKey.decodeWalletImportFormat(input);
  				} else if (ECKey.isCompressedWalletImportFormat(input)) {
  					bytes = ECKey.decodeCompressedWalletImportFormat(input);
  					this.compressed = true;
  				} else if (ECKey.isMiniFormat(input)) {
  					bytes = Crypto.SHA256(input, { asBytes: true });
  				} else if (ECKey.isHexFormat(input)) {
  					bytes = Crypto.util.hexToBytes(input);
  				} else if (ECKey.isBase64Format(input)) {
  					bytes = Crypto.util.base64ToBytes(input);
  				}
  			} catch (exc1) {
  				this.setError(exc1);
  			}
  
  			if (ECKey.isBase6Format(input)) {
  				this.priv = new BigInteger(input, 6);
  			} else if (bytes == null || bytes.length != 32) {
  				this.priv = null;
  			} else {
  				// Prepend zero byte to prevent interpretation as negative integer
  				this.priv = BigInteger.fromByteArrayUnsigned(bytes);
  			}
  		}
  
  		this.compressed = (this.compressed == undefined) ? !!ECKey.compressByDefault : this.compressed;
  		try {
  			// check not zero
  			if (this.priv != null && BigInteger.ZERO.compareTo(this.priv) == 0) this.setError("Error: BigInteger equal to zero.");
  			// valid range [0x1, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140])
  			var hexKeyRangeLimit = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140";
  			var rangeLimitBytes = Crypto.util.hexToBytes(hexKeyRangeLimit);
  			var limitBigInt = BigInteger.fromByteArrayUnsigned(rangeLimitBytes);
  			if (this.priv != null && limitBigInt.compareTo(this.priv) < 0) this.setError("Error: BigInteger outside of curve range.")
  
  			if (this.priv != null) {
  				KeyPool.push(this);
  			}
  		} catch (exc2) {
  			this.setError(exc2);
  		}
  	};
  
  	ECKey.privateKeyPrefix = 0xBF; // mainnet 0x80    testnet 0xEF
  
  	/**
  	* Whether public keys should be returned compressed by default.
  	*/
  	ECKey.compressByDefault = false;
  
  	/**
  	* Set whether the public key should be returned compressed or not.
  	*/
  	ECKey.prototype.setError = function (err) {
  		this.error = err;
  		this.priv = null;
  		return this;
  	};
  
  	/**
  	* Set whether the public key should be returned compressed or not.
  	*/
  	ECKey.prototype.setCompressed = function (v) {
  		this.compressed = !!v;
  		if (this.pubPoint) this.pubPoint.compressed = this.compressed;
  		return this;
  	};
  
  	/*
  	* Return public key as a byte array in DER encoding
  	*/
  	ECKey.prototype.getPub = function () {
  		if (this.compressed) {
  			if (this.pubComp) return this.pubComp;
  			return this.pubComp = this.getPubPoint().getEncoded(1);
  		} else {
  			if (this.pubUncomp) return this.pubUncomp;
  			return this.pubUncomp = this.getPubPoint().getEncoded(0);
  		}
  	};
  
  	/**
  	* Return public point as ECPoint object.
  	*/
  	ECKey.prototype.getPubPoint = function () {
  		if (!this.pubPoint) {
  			this.pubPoint = ecparams.getG().multiply(this.priv);
  			this.pubPoint.compressed = this.compressed;
  		}
  		return this.pubPoint;
  	};
  
  	ECKey.prototype.getPubKeyHex = function () {
  		if (this.compressed) {
  			if (this.pubKeyHexComp) return this.pubKeyHexComp;
  			return this.pubKeyHexComp = Crypto.util.bytesToHex(this.getPub()).toString().toUpperCase();
  		} else {
  			if (this.pubKeyHexUncomp) return this.pubKeyHexUncomp;
  			return this.pubKeyHexUncomp = Crypto.util.bytesToHex(this.getPub()).toString().toUpperCase();
  		}
  	};
  
  	/**
  	* Get the pubKeyHash for this key.
  	*
  	* This is calculated as RIPE160(SHA256([encoded pubkey])) and returned as
  	* a byte array.
  	*/
  	ECKey.prototype.getPubKeyHash = function () {
  		if (this.compressed) {
  			if (this.pubKeyHashComp) return this.pubKeyHashComp;
  			return this.pubKeyHashComp = Bitcoin.Util.sha256ripe160(this.getPub());
  		} else {
  			if (this.pubKeyHashUncomp) return this.pubKeyHashUncomp;
  			return this.pubKeyHashUncomp = Bitcoin.Util.sha256ripe160(this.getPub());
  		}
  	};
  
  	ECKey.prototype.getBitcoinAddress = function () {
  		var hash = this.getPubKeyHex();
  		var addr = new Bitcoin.Address(hash);
  		return addr.toString();
  	};
  
  	/*
  	* Takes a public point as a hex string or byte array
  	*/
  	ECKey.prototype.setPub = function (pub) {
  		// byte array
  		if (Bitcoin.Util.isArray(pub)) {
  			pub = Crypto.util.bytesToHex(pub).toString().toUpperCase();
  		}
  		var ecPoint = ecparams.getCurve().decodePointHex(pub);
  		this.setCompressed(ecPoint.compressed);
  		this.pubPoint = ecPoint;
  		return this;
  	};
  
  	// Sipa Private Key Wallet Import Format 
  	ECKey.prototype.getBitcoinWalletImportFormat = function () {
  		var bytes = this.getBitcoinHexFormat().toLowerCase();
  		return prvKey_to_WIF(bytes, this.compressed);
  	};
  
  	// Private Key Hex Format 
  	ECKey.prototype.getBitcoinHexFormat = function () {
  		return Crypto.util.bytesToHex(this.getBitcoinPrivateKeyByteArray()).toString().toUpperCase();
  	};
  
  	// Private Key Base64 Format 
  	ECKey.prototype.getBitcoinBase64Format = function () {
  		return Crypto.util.bytesToBase64(this.getBitcoinPrivateKeyByteArray());
  	};
  
  	ECKey.prototype.getBitcoinPrivateKeyByteArray = function () {
  		if (this.priv == null) return null;
  		// Get a copy of private key as a byte array
  		var bytes = this.priv.toByteArrayUnsigned();
  		// zero pad if private key is less than 32 bytes 
  		while (bytes.length < 32) bytes.unshift(0x00);
  		return bytes;
  	};
  
  	ECKey.prototype.toString = function (format) {
  		format = format || "";
  		if (format.toString().toLowerCase() == "base64" || format.toString().toLowerCase() == "b64") {
  			return this.getBitcoinBase64Format();
  		}
  		// Wallet Import Format
  		else if (format.toString().toLowerCase() == "wif") {
  			return this.getBitcoinWalletImportFormat();
  		}
  		else {
  			return this.getBitcoinHexFormat();
  		}
  	};
  
  	ECKey.prototype.sign = function (hash) {
  		return ECDSA.sign(hash, this.priv);
  	};
  
  	ECKey.prototype.verify = function (hash, sig) {
  		return ECDSA.verify(hash, sig, this.getPub());
  	};
  
  	/**
  	* Parse a wallet import format private key contained in a string.
  	*/
  	ECKey.decodeWalletImportFormat = function (privStr) {
  		var bytes = Bitcoin.Base58.decode(privStr);
  		var hash = bytes.slice(0, 33);
  		var checksum = Crypto.SHA256(Crypto.SHA256(hash, { asBytes: true }), { asBytes: true });
  		if (checksum[0] != bytes[33] ||
  					checksum[1] != bytes[34] ||
  					checksum[2] != bytes[35] ||
  					checksum[3] != bytes[36]) {
  			throw "Checksum validation failed!";
  		}
  		var version = hash.shift();
  		if (version != ECKey.privateKeyPrefix) {
  			throw "Version " + version + " not supported!";
  		}
  		return hash;
  	};
  
  	/**
  	* Parse a compressed wallet import format private key contained in a string.
  	*/
  	ECKey.decodeCompressedWalletImportFormat = function (privStr) {
  		var bytes = Bitcoin.Base58.decode(privStr);
  		var hash = bytes.slice(0, 34);
  		var checksum = Crypto.SHA256(Crypto.SHA256(hash, { asBytes: true }), { asBytes: true });
  		if (checksum[0] != bytes[34] ||
  					checksum[1] != bytes[35] ||
  					checksum[2] != bytes[36] ||
  					checksum[3] != bytes[37]) {
  			throw "Checksum validation failed!";
  		}
  		var version = hash.shift();
  		if (version != ECKey.privateKeyPrefix) {
  			throw "Version " + version + " not supported!";
  		}
  		hash.pop();
  		return hash;
  	};
  
  	// 64 characters [0-9A-F]
  	ECKey.isHexFormat = function (key) {
  		key = key.toString();
  		return /^[A-Fa-f0-9]{64}$/.test(key);
  	};
  
  	// 51 characters base58, always starts with a '5'
  	ECKey.isWalletImportFormat = function (key) {
  		key = key.toString();
  		return (ECKey.privateKeyPrefix == 0xBF) ?
  							(/^7[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{50}$/.test(key)) :
  							(/^6[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{50}$/.test(key));
  	};
  
  	// 52 characters base58
  	ECKey.isCompressedWalletImportFormat = function (key) {
  		key = key.toString();
  		return (ECKey.privateKeyPrefix == 0xBF) ?
  							(/^V[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{51}$/.test(key)) :
  							(/^T[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{51}$/.test(key));
  	};
  
  	// 44 characters
  	ECKey.isBase64Format = function (key) {
  		key = key.toString();
  		return (/^[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789=+\/]{44}$/.test(key));
  	};
  
  	// 99 characters, 1=1, if using dice convert 6 to 0
  	ECKey.isBase6Format = function (key) {
  		key = key.toString();
  		return (/^[012345]{99}$/.test(key));
  	};
  
  	// 22, 26 or 30 characters, always starts with an 'S'
  	ECKey.isMiniFormat = function (key) {
  		key = key.toString();
  		var validChars22 = /^S[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21}$/.test(key);
  		var validChars26 = /^S[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{25}$/.test(key);
  		var validChars30 = /^S[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{29}$/.test(key);
  		var testBytes = Crypto.SHA256(key + "?", { asBytes: true });
  
  		return ((testBytes[0] === 0x00 || testBytes[0] === 0x01) && (validChars22 || validChars26 || validChars30));
  	};
  
  	return ECKey;
  })();