Skip to content

Instantly share code, notes, and snippets.

@maciej-trebacz
Last active December 24, 2015 07:59
Show Gist options
  • Save maciej-trebacz/6767913 to your computer and use it in GitHub Desktop.
Save maciej-trebacz/6767913 to your computer and use it in GitHub Desktop.
Bitcoin.Address class with P2SH support
var address_types = {
prod: 0,
testnet: 111
};
var p2sh_types = {
prod: 5,
testnet: 196
};
Bitcoin.Address = function (bytes, address_type) {
if (typeof bytes === 'string') {
this.decodeString(bytes, address_type);
} else {
this.hash = bytes;
this.version = address_types[address_type || 'prod'];
}
};
/**
* Serialize this object as a standard Bitcoin address.
*
* Returns the address as a base58-encoded string in the standardized format.
*/
Bitcoin.Address.prototype.toString = function () {
// Get a copy of the hash
var hash = this.hash.slice(0);
// Version
hash.unshift(this.version);
var checksum = Crypto.SHA256(Crypto.SHA256(hash, { asBytes: true }), { asBytes: true });
var bytes = hash.concat(checksum.slice(0, 4));
return Bitcoin.Base58.encode(bytes);
};
Bitcoin.Address.prototype.getHashBase64 = function () {
return Crypto.util.bytesToBase64(this.hash);
};
/**
* Validate if address has a supported version number
*/
Bitcoin.Address.validateType = function(version, type) {
if (type) {
return (version === address_types[type] || version === p2sh_types[type]);
}
for (var type in address_types) {
if (version == address_types[type]) {
return true;
}
}
for (var type in p2sh_types) {
if (version == p2sh_types[type]) {
return true;
}
}
return false;
};
/**
* Check if Bitcoin address is valid
*/
Bitcoin.Address.validate = function(string, type) {
try {
var bytes = Bitcoin.Base58.decode(string);
} catch (e) {
return false;
}
var hash = bytes.slice(0, 21);
var checksum = Crypto.SHA256(Crypto.SHA256(hash, {asBytes: true}), {asBytes: true});
if (checksum[0] != bytes[21] ||
checksum[1] != bytes[22] ||
checksum[2] != bytes[23] ||
checksum[3] != bytes[24]) {
return false;
}
if (!Address.validateType(hash[0], type)) {
return false;
}
return true;
};
/**
* Parse a Bitcoin address contained in a string.
*/
Bitcoin.Address.prototype.decodeString = function(string, address_type) {
var bytes = Bitcoin.Base58.decode(string);
var hash = bytes.slice(0, 21);
var checksum = Crypto.SHA256(Crypto.SHA256(hash, {asBytes: true}), {asBytes: true});
if (checksum[0] != bytes[21] ||
checksum[1] != bytes[22] ||
checksum[2] != bytes[23] ||
checksum[3] != bytes[24]) {
throw new Error('Address Checksum validation failed: ' + string);
}
var version = hash.shift();
if (!Bitcoin.Address.validateType(version, address_type)) {
throw new Error('Address version (' + version + ') not supported: ' + string +
' for ' + address_type);
}
this.hash = hash;
this.version = version;
};
/* Bitcoin.Script part */
/**
* Create a standard payToPubKeyHash output or a payToScriptHash output.
*/
Script.createOutputScript = function (address)
{
var script = new Script();
if (address.version == 0 || address.version == 111) {
script.writeOp(Opcode.map.OP_DUP);
script.writeOp(Opcode.map.OP_HASH160);
script.writeBytes(address.hash);
script.writeOp(Opcode.map.OP_EQUALVERIFY);
script.writeOp(Opcode.map.OP_CHECKSIG);
}
else if (address.version == 5 || address.version == 196) {
script.writeOp(Opcode.map.OP_HASH160);
script.writeBytes(address.hash);
script.writeOp(Opcode.map.OP_EQUAL);
}
return script;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment