2014-12-02 00:36:49 +01:00
/ *
Coinjs 0.01 beta by OutCast3k { at } gmail . com
A bitcoin framework loosely based on bitcoinjs .
http : //github.com/OutCast3k/coinjs or http://coinb.in/coinjs
* /
( function ( ) {
var coinjs = window . coinjs = function ( ) { } ;
/* public vars */
coinjs . pub = 0x00 ;
coinjs . priv = 0x80 ;
coinjs . multisig = 0x05 ;
coinjs . compressed = false ;
/* other vars */
coinjs . developer = '1CWHWkTWaq1K5hevimJia3cyinQsrgXUvg' ;
/* bit(coinb.in) api vars */
2014-12-08 12:18:38 +01:00
coinjs . host = ( 'https:' == document . location . protocol ? 'https://' : 'http://' ) + 'coinb.in/api/' ;
2014-12-02 00:36:49 +01:00
coinjs . uid = '1' ;
coinjs . key = '12345678901234567890123456789012' ;
/* start of address functions */
/* generate a private and public keypair, with address and WIF address */
coinjs . newKeys = function ( string ) {
var privkey = ( string ) ? Crypto . SHA256 ( string ) : this . newPrivkey ( ) ;
var pubkey = this . newPubkey ( privkey ) ;
return {
'privkey' : privkey ,
'pubkey' : pubkey ,
'address' : this . pubkey2address ( pubkey ) ,
'wif' : this . privkey2wif ( privkey ) ,
'compressed' : this . compressed
} ;
}
/* generate a new random private key */
coinjs . newPrivkey = function ( ) {
2014-12-05 22:26:34 +01:00
var x = window . location ;
x += ( window . screen . height * window . screen . width * window . screen . colorDepth ) ;
x += coinjs . random ( 64 ) ;
2014-12-31 14:33:22 +01:00
x += ( window . screen . availHeight * window . screen . availWidth * window . screen . pixelDepth ) ;
2014-12-05 22:26:34 +01:00
x += navigator . language ;
x += window . history . length ;
x += coinjs . random ( 64 ) ;
x += navigator . userAgent ;
2014-12-05 22:30:21 +01:00
x += 'coinb.in' ;
2014-12-05 22:26:34 +01:00
x += ( Crypto . util . randomBytes ( 64 ) ) . join ( "" ) ;
x += x . length ;
var dateObj = new Date ( ) ;
x += dateObj . getTimezoneOffset ( ) ;
x += coinjs . random ( 64 ) ;
2014-12-31 15:20:00 +01:00
x += ( document . getElementById ( "entropybucket" ) ) ? document . getElementById ( "entropybucket" ) . innerHTML : '' ;
2014-12-05 22:26:34 +01:00
x += x + '' + x ;
var r = x ;
2014-12-31 14:33:22 +01:00
for ( i = 0 ; i < ( x ) . length / 25 ; i ++ ) {
2014-12-28 12:32:40 +01:00
r = Crypto . SHA256 ( r . concat ( x ) ) ;
2014-12-02 00:36:49 +01:00
}
2014-12-31 19:06:24 +01:00
var checkrBigInt = new BigInteger ( r ) ;
var orderBigInt = new BigInteger ( "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141" ) ;
while ( checkrBigInt . compareTo ( orderBigInt ) >= 0 || checkrBigInt . equals ( BigInteger . ZERO ) || checkrBigInt . equals ( BigInteger . ONE ) ) {
r = Crypto . SHA256 ( r . concat ( x ) ) ;
checkrBigInt = new BigInteger ( r ) ;
}
2014-12-05 22:26:34 +01:00
return r ;
2014-12-02 00:36:49 +01:00
}
/* generate a public key from a private key */
coinjs . newPubkey = function ( hash ) {
var privateKeyBigInt = BigInteger . fromByteArrayUnsigned ( Crypto . util . hexToBytes ( hash ) ) ;
var curve = EllipticCurve . getSECCurveByName ( "secp256k1" ) ;
var curvePt = curve . getG ( ) . multiply ( privateKeyBigInt ) ;
var x = curvePt . getX ( ) . toBigInteger ( ) ;
var y = curvePt . getY ( ) . toBigInteger ( ) ;
var publicKeyBytes = EllipticCurve . integerToBytes ( x , 32 ) ;
publicKeyBytes = publicKeyBytes . concat ( EllipticCurve . integerToBytes ( y , 32 ) ) ;
publicKeyBytes . unshift ( 0x04 ) ;
if ( coinjs . compressed == true ) {
var publicKeyBytesCompressed = EllipticCurve . integerToBytes ( x , 32 )
if ( y . isEven ( ) ) {
publicKeyBytesCompressed . unshift ( 0x02 )
} else {
publicKeyBytesCompressed . unshift ( 0x03 )
}
return Crypto . util . bytesToHex ( publicKeyBytesCompressed ) ;
} else {
return Crypto . util . bytesToHex ( publicKeyBytes ) ;
}
}
/* provide a public key and return address */
coinjs . pubkey2address = function ( h ) {
var r = ripemd160 ( Crypto . SHA256 ( Crypto . util . hexToBytes ( h ) , { asBytes : true } ) ) ;
r . unshift ( coinjs . pub ) ;
var hash = Crypto . SHA256 ( Crypto . SHA256 ( r , { asBytes : true } ) , { asBytes : true } ) ;
var checksum = hash . slice ( 0 , 4 ) ;
return coinjs . base58encode ( r . concat ( checksum ) ) ;
}
/* provide a scripthash and return address */
coinjs . scripthash2address = function ( h ) {
var x = Crypto . util . hexToBytes ( h ) ;
x . unshift ( coinjs . pub ) ;
var r = x ;
r = Crypto . SHA256 ( Crypto . SHA256 ( r , { asBytes : true } ) , { asBytes : true } ) ;
var checksum = r . slice ( 0 , 4 ) ;
return coinjs . base58encode ( x . concat ( checksum ) ) ;
}
/* new multisig address, provide the pubkeys AND required signatures to release the funds */
coinjs . pubkeys2MultisigAddress = function ( pubkeys , required ) {
var s = coinjs . script ( ) ;
s . writeOp ( 81 + ( required * 1 ) - 1 ) ; //OP_1
for ( var i = 0 ; i < pubkeys . length ; ++ i ) {
s . writeBytes ( Crypto . util . hexToBytes ( pubkeys [ i ] ) ) ;
}
s . writeOp ( 81 + pubkeys . length - 1 ) ; //OP_1
s . writeOp ( 174 ) ; //OP_CHECKMULTISIG
var x = ripemd160 ( Crypto . SHA256 ( s . buffer , { asBytes : true } ) , { asBytes : true } ) ;
x . unshift ( coinjs . multisig ) ;
var r = x ;
r = Crypto . SHA256 ( Crypto . SHA256 ( r , { asBytes : true } ) , { asBytes : true } ) ;
var checksum = r . slice ( 0 , 4 ) ;
var redeemScript = Crypto . util . bytesToHex ( s . buffer ) ;
var address = coinjs . base58encode ( x . concat ( checksum ) ) ;
return { 'address' : address , 'redeemScript' : redeemScript } ;
}
/* provide a privkey and return an WIF */
coinjs . privkey2wif = function ( h ) {
var r = Crypto . util . hexToBytes ( h ) ;
if ( coinjs . compressed == true ) {
r . push ( 0x01 ) ;
}
r . unshift ( coinjs . priv ) ;
var hash = Crypto . SHA256 ( Crypto . SHA256 ( r , { asBytes : true } ) , { asBytes : true } ) ;
var checksum = hash . slice ( 0 , 4 ) ;
return coinjs . base58encode ( r . concat ( checksum ) ) ;
}
/* convert a wif key back to a private key */
coinjs . wif2privkey = function ( wif ) {
var compressed = false ;
var decode = coinjs . base58decode ( wif ) ;
var key = decode . slice ( 0 , decode . length - 4 ) ;
key = key . slice ( 1 , key . length ) ;
if ( key . length >= 33 && key [ key . length - 1 ] == 0x01 ) {
key = key . slice ( 0 , key . length - 1 ) ;
compressed = true ;
}
return { 'privkey' : Crypto . util . bytesToHex ( key ) , 'compressed' : compressed } ;
}
/* convert a wif to a pubkey */
coinjs . wif2pubkey = function ( wif ) {
var compressed = coinjs . compressed ;
var r = coinjs . wif2privkey ( wif ) ;
coinjs . compressed = r [ 'compressed' ] ;
var pubkey = coinjs . newPubkey ( r [ 'privkey' ] ) ;
coinjs . compressed = compressed ;
return { 'pubkey' : pubkey , 'compressed' : r [ 'compressed' ] } ;
}
/* convert a wif to a address */
coinjs . wif2address = function ( wif ) {
var r = coinjs . wif2pubkey ( wif ) ;
return { 'address' : coinjs . pubkey2address ( r [ 'pubkey' ] ) , 'compressed' : r [ 'compressed' ] } ;
}
/* decode or validate an address and return the hash */
coinjs . addressDecode = function ( addr ) {
try {
var bytes = coinjs . base58decode ( addr ) ;
var front = bytes . slice ( 0 , bytes . length - 4 ) ;
var back = bytes . slice ( bytes . length - 4 ) ;
var checksum = Crypto . SHA256 ( Crypto . SHA256 ( front , { asBytes : true } ) , { asBytes : true } ) . slice ( 0 , 4 ) ;
if ( checksum + "" == back + "" ) {
var o = front . slice ( 1 ) ;
o . version = front [ 0 ] ;
return o ;
} else {
return false ;
}
} catch ( e ) {
return false ;
}
}
2014-12-30 04:40:30 +01:00
/* parse stealth address and return an object with the parts */
coinjs . stealthDecode = function ( stealth ) {
try {
var bytes = coinjs . base58decode ( stealth ) ;
var front = bytes . slice ( 0 , bytes . length - 4 ) ;
var back = bytes . slice ( bytes . length - 4 ) ;
var checksum = Crypto . SHA256 ( Crypto . SHA256 ( front , { asBytes : true } ) , { asBytes : true } ) . slice ( 0 , 4 ) ;
if ( checksum + "" == back + "" ) {
var o = { } ;
o . version = front [ 0 ] ;
if ( o . version != 42 ) {
return false ;
} ;
o . option = front [ 1 ] ;
if ( o . option != 0 ) {
alert ( "Stealth Address option other than 0 is currently not supported!" ) ;
return false ;
} ;
o . scankey = Crypto . util . bytesToHex ( front . slice ( 2 , 35 ) ) ;
o . n = front [ 35 ] ;
if ( o . n > 1 ) {
alert ( "Stealth Multisig is currently not supported!" ) ;
return false ;
} ;
o . spendkey = Crypto . util . bytesToHex ( front . slice ( 36 , 69 ) ) ;
o . m = front [ 69 ] ;
o . prefixlen = front [ 70 ] ;
if ( o . prefixlen > 0 ) {
alert ( "Stealth Address Prefixes are currently not supported!" ) ;
return false ;
} ;
o . prefix = front . slice ( 71 )
return o ;
} else {
return false ;
}
} catch ( e ) {
return false ;
}
}
2014-12-02 00:36:49 +01:00
/* retreive the balance from a given address */
coinjs . addressBalance = function ( address , callback ) {
2014-12-05 17:59:44 +01:00
coinjs . ajax ( coinjs . host + '?uid=' + coinjs . uid + '&key=' + coinjs . key + '&setmodule=addresses&request=bal&address=' + address + '&r=' + Math . random ( ) , callback , "GET" ) ;
2014-12-02 00:36:49 +01:00
}
/* decompress an compressed public key */
coinjs . pubkeydecompress = function ( pubkey ) {
var curve = EllipticCurve . getSECCurveByName ( "secp256k1" ) ;
try {
var pt = curve . curve . decodePointHex ( pubkey ) ;
var x = pt . getX ( ) . toBigInteger ( ) ;
var y = pt . getY ( ) . toBigInteger ( ) ;
var publicKeyBytes = EllipticCurve . integerToBytes ( x , 32 ) ;
publicKeyBytes = publicKeyBytes . concat ( EllipticCurve . integerToBytes ( y , 32 ) ) ;
publicKeyBytes . unshift ( 0x04 ) ;
return Crypto . util . bytesToHex ( publicKeyBytes ) ;
} catch ( e ) {
// console.log(e);
return false ;
}
}
/* start of script functions */
coinjs . script = function ( data ) {
var r = { } ;
if ( ! data ) {
r . buffer = [ ] ;
} else if ( "string" == typeof data ) {
r . buffer = Crypto . util . hexToBytes ( data ) ;
} else if ( coinjs . isArray ( data ) ) {
r . buffer = data ;
} else if ( data instanceof coinjs . script ) {
r . buffer = r . buffer ;
} else {
r . buffer = data ;
}
/* parse buffer array */
r . parse = function ( ) {
var self = this ;
r . chunks = [ ] ;
var i = 0 ;
function readChunk ( n ) {
self . chunks . push ( self . buffer . slice ( i , i + n ) ) ;
i += n ;
} ;
while ( i < this . buffer . length ) {
var opcode = this . buffer [ i ++ ] ;
if ( opcode >= 0xF0 ) {
opcode = ( opcode << 8 ) | this . buffer [ i ++ ] ;
}
var len ;
if ( opcode > 0 && opcode < 76 ) { //OP_PUSHDATA1
readChunk ( opcode ) ;
} else if ( opcode == 76 ) { //OP_PUSHDATA1
len = this . buffer [ i ++ ] ;
readChunk ( len ) ;
} else if ( opcode == 77 ) { //OP_PUSHDATA2
len = ( this . buffer [ i ++ ] << 8 ) | this . buffer [ i ++ ] ;
readChunk ( len ) ;
} else if ( opcode == 78 ) { //OP_PUSHDATA4
len = ( this . buffer [ i ++ ] << 24 ) | ( this . buffer [ i ++ ] << 16 ) | ( this . buffer [ i ++ ] << 8 ) | this . buffer [ i ++ ] ;
readChunk ( len ) ;
} else {
this . chunks . push ( opcode ) ;
}
2014-12-31 15:22:05 +01:00
if ( i < 0x00 ) {
break ;
}
2014-12-02 00:36:49 +01:00
}
return true ;
} ;
/* decode the redeemscript of a multisignature transaction */
r . decodeRedeemScript = function ( script ) {
var r = false ;
try {
var s = coinjs . script ( Crypto . util . hexToBytes ( script ) ) ;
if ( ( s . chunks . length >= 3 ) && s . chunks [ s . chunks . length - 1 ] == 174 ) { //OP_CHECKMULTISIG
r = { } ;
r . signaturesRequired = s . chunks [ 0 ] - 80 ;
var pubkeys = [ ] ;
for ( var i = 1 ; i < s . chunks . length - 2 ; i ++ ) {
pubkeys . push ( Crypto . util . bytesToHex ( s . chunks [ i ] ) ) ;
}
r . pubkeys = pubkeys ;
var multi = coinjs . pubkeys2MultisigAddress ( pubkeys , r . signaturesRequired ) ;
r . address = multi [ 'address' ] ;
}
} catch ( e ) {
// console.log(e);
r = false ;
}
return r ;
}
/* create output script to spend */
r . spendToScript = function ( address ) {
var addr = coinjs . addressDecode ( address ) ;
var s = coinjs . script ( ) ;
if ( addr . version == 5 ) { // multisig address
s . writeOp ( 169 ) ; //OP_HASH160
s . writeBytes ( addr ) ;
s . writeOp ( 135 ) ; //OP_EQUAL
} else { // regular address
s . writeOp ( 118 ) ; //OP_DUP
s . writeOp ( 169 ) ; //OP_HASH160
s . writeBytes ( addr ) ;
s . writeOp ( 136 ) ; //OP_EQUALVERIFY
s . writeOp ( 172 ) ; //OP_CHECKSIG
}
return s ;
}
/* geneate a (script) pubkey hash of the address - used for when signing */
r . pubkeyHash = function ( address ) {
var addr = coinjs . addressDecode ( address ) ;
var s = coinjs . script ( ) ;
s . writeOp ( 118 ) ; //OP_DUP
s . writeOp ( 169 ) ; //OP_HASH160
s . writeBytes ( addr ) ;
s . writeOp ( 136 ) ; //OP_EQUALVERIFY
s . writeOp ( 172 ) ; //OP_CHECKSIG
return s ;
}
/* write to buffer */
r . writeOp = function ( op ) {
this . buffer . push ( op ) ;
this . chunks . push ( op ) ;
return true ;
}
/* write bytes to buffer */
r . writeBytes = function ( data ) {
if ( data . length < 76 ) { //OP_PUSHDATA1
this . buffer . push ( data . length ) ;
} else if ( data . length <= 0xff ) {
this . buffer . push ( 76 ) ; //OP_PUSHDATA1
this . buffer . push ( data . length ) ;
} else if ( data . length <= 0xffff ) {
this . buffer . push ( 77 ) ; //OP_PUSHDATA2
this . buffer . push ( data . length & 0xff ) ;
this . buffer . push ( ( data . length >>> 8 ) & 0xff ) ;
} else {
this . buffer . push ( 78 ) ; //OP_PUSHDATA4
this . buffer . push ( data . length & 0xff ) ;
this . buffer . push ( ( data . length >>> 8 ) & 0xff ) ;
this . buffer . push ( ( data . length >>> 16 ) & 0xff ) ;
this . buffer . push ( ( data . length >>> 24 ) & 0xff ) ;
}
this . buffer = this . buffer . concat ( data ) ;
this . chunks . push ( data ) ;
return true ;
}
r . parse ( ) ;
return r ;
}
/* start of transaction functions */
/* create a new transaction object */
coinjs . transaction = function ( ) {
var r = { } ;
r . version = 1 ;
r . lock _time = 0 ;
r . ins = [ ] ;
r . outs = [ ] ;
r . timestamp = null ;
r . block = null ;
/* add an input to a transaction */
2014-12-15 16:11:09 +01:00
r . addinput = function ( txid , index , script ) {
2014-12-02 00:36:49 +01:00
var o = { } ;
o . outpoint = { 'hash' : txid , 'index' : index } ;
o . script = coinjs . script ( script || [ ] ) ;
2014-12-15 16:11:09 +01:00
o . sequence = ( r . lock _time == 0 ) ? 4294967295 : 0 ;
2014-12-02 00:36:49 +01:00
return this . ins . push ( o ) ;
}
/* add an output to a transaction */
r . addoutput = function ( address , value ) {
var o = { } ;
o . value = new BigInteger ( '' + Math . round ( ( value * 1 ) * 1e8 ) , 10 ) ;
var s = coinjs . script ( ) ;
o . script = s . spendToScript ( address ) ;
2014-12-29 23:55:28 +01:00
2014-12-02 00:36:49 +01:00
return this . outs . push ( o ) ;
}
2014-12-30 04:40:30 +01:00
/* add two outputs for stealth addresses to a transaction */
r . addstealth = function ( stealth , value ) {
var ephemeralKeyBigInt = BigInteger . fromByteArrayUnsigned ( Crypto . util . hexToBytes ( coinjs . newPrivkey ( ) ) ) ;
var curve = EllipticCurve . getSECCurveByName ( "secp256k1" ) ;
var p = EllipticCurve . fromHex ( "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F" ) ;
var a = BigInteger . ZERO ;
var b = EllipticCurve . fromHex ( "7" ) ;
var calccurve = new EllipticCurve . CurveFp ( p , a , b ) ;
var ephemeralPt = curve . getG ( ) . multiply ( ephemeralKeyBigInt ) ;
var scanPt = calccurve . decodePointHex ( stealth . scankey ) ;
var sharedPt = scanPt . multiply ( ephemeralKeyBigInt ) ;
var stealthindexKeyBigInt = BigInteger . fromByteArrayUnsigned ( Crypto . SHA256 ( sharedPt . getEncoded ( true ) , { asBytes : true } ) ) ;
var stealthindexPt = curve . getG ( ) . multiply ( stealthindexKeyBigInt ) ;
var spendPt = calccurve . decodePointHex ( stealth . spendkey ) ;
var addressPt = spendPt . add ( stealthindexPt ) ;
var sendaddress = coinjs . pubkey2address ( Crypto . util . bytesToHex ( addressPt . getEncoded ( true ) ) ) ;
var OPRETBytes = [ 6 ] . concat ( Crypto . util . randomBytes ( 4 ) ) . concat ( ephemeralPt . getEncoded ( true ) ) ; // ephemkey data
var q = coinjs . script ( ) ;
q . writeOp ( 106 ) ; // OP_RETURN
q . writeBytes ( OPRETBytes ) ;
v = { } ;
v . value = 0 ;
v . script = q ;
this . outs . push ( v ) ;
var o = { } ;
o . value = new BigInteger ( '' + Math . round ( ( value * 1 ) * 1e8 ) , 10 ) ;
var s = coinjs . script ( ) ;
o . script = s . spendToScript ( sendaddress ) ;
return this . outs . push ( o ) ;
}
2014-12-29 23:55:28 +01:00
/* add data to a transaction */
r . adddata = function ( data ) {
var r = false ;
if ( ( ( data . match ( /^[a-f0-9]+$/gi ) ) && data . length < 80 ) && ( data . length % 2 ) == 0 ) {
var s = coinjs . script ( ) ;
s . writeOp ( 106 ) ; // OP_RETURN
s . writeBytes ( Crypto . util . hexToBytes ( data ) ) ;
o = { } ;
o . value = 0 ;
o . script = s ;
return this . outs . push ( o ) ;
}
return r ;
}
2014-12-02 00:36:49 +01:00
/* list unspent transactions */
r . listUnspent = function ( address , callback ) {
2014-12-05 17:59:44 +01:00
coinjs . ajax ( coinjs . host + '?uid=' + coinjs . uid + '&key=' + coinjs . key + '&setmodule=addresses&request=unspent&address=' + address + '&r=' + Math . random ( ) , callback , "GET" ) ;
2014-12-02 00:36:49 +01:00
}
/* add unspent to transaction */
r . addUnspent = function ( address , callback ) {
var self = this ;
this . listUnspent ( address , function ( data ) {
var s = coinjs . script ( ) ;
var pubkeyScript = s . pubkeyHash ( address ) ;
var value = 0 ;
var total = 0 ;
var x = { } ;
2014-12-08 13:59:04 +01:00
if ( window . DOMParser ) {
parser = new DOMParser ( ) ;
xmlDoc = parser . parseFromString ( data , "text/xml" ) ;
} else {
xmlDoc = new ActiveXObject ( "Microsoft.XMLDOM" ) ;
xmlDoc . async = false ;
xmlDoc . loadXML ( data ) ;
}
var unspent = xmlDoc . getElementsByTagName ( "unspent" ) [ 0 ] ;
2014-12-02 00:36:49 +01:00
for ( i = 1 ; i <= unspent . childElementCount ; i ++ ) {
2014-12-08 13:59:04 +01:00
var u = xmlDoc . getElementsByTagName ( "unspent_" + i ) [ 0 ]
2014-12-08 16:31:53 +01:00
var txhash = ( u . getElementsByTagName ( "tx_hash" ) [ 0 ] . childNodes [ 0 ] . nodeValue ) . match ( /.{1,2}/g ) . reverse ( ) . join ( "" ) + '' ;
2014-12-02 00:36:49 +01:00
var n = u . getElementsByTagName ( "tx_output_n" ) [ 0 ] . childNodes [ 0 ] . nodeValue ;
2014-12-08 16:31:53 +01:00
var script = u . getElementsByTagName ( "script" ) [ 0 ] . childNodes [ 0 ] . nodeValue ;
self . addinput ( txhash , n , script ) ;
2014-12-02 00:36:49 +01:00
value += u . getElementsByTagName ( "value" ) [ 0 ] . childNodes [ 0 ] . nodeValue * 1 ;
total ++ ;
}
2014-12-08 16:31:53 +01:00
x . unspent = $ ( xmlDoc ) . find ( "unspent" ) ;
2014-12-02 00:36:49 +01:00
x . value = value ;
x . total = total ;
return callback ( x ) ;
} ) ;
}
/* add unspent and sign */
r . addUnspentAndSign = function ( wif , callback ) {
var self = this ;
var address = coinjs . wif2address ( wif ) ;
self . addUnspent ( address [ 'address' ] , function ( data ) {
self . sign ( wif ) ;
return callback ( data ) ;
} ) ;
}
/* broadcast a transaction */
r . broadcast = function ( callback , txhex ) {
2014-12-08 16:31:53 +01:00
var tx = txhex || this . serialize ( ) ;
2014-12-05 17:59:44 +01:00
coinjs . ajax ( coinjs . host + '?uid=' + coinjs . uid + '&key=' + coinjs . key + '&setmodule=bitcoin&request=sendrawtransaction&rawtx=' + tx + '&r=' + Math . random ( ) , callback , "GET" ) ;
2014-12-02 00:36:49 +01:00
}
/* generate the transaction hash to sign from a transaction input */
r . transactionHash = function ( index ) {
var clone = coinjs . clone ( this ) ;
if ( ( clone . ins ) && clone . ins [ index ] ) {
for ( var i = 0 ; i < clone . ins . length ; i ++ ) {
if ( index != i ) {
clone . ins [ i ] . script = coinjs . script ( ) ;
}
}
var extract = this . extractScriptKey ( index ) ;
clone . ins [ index ] . script = coinjs . script ( extract [ 'script' ] ) ;
var buffer = Crypto . util . hexToBytes ( clone . serialize ( ) ) ;
buffer = buffer . concat ( coinjs . numToBytes ( parseInt ( 1 ) , 4 ) ) ;
var hash = Crypto . SHA256 ( buffer , { asBytes : true } ) ;
var r = Crypto . util . bytesToHex ( Crypto . SHA256 ( hash , { asBytes : true } ) ) ;
return r ;
} else {
return false ;
}
}
/* extract the scriptSig, used in the transactionHash() function */
r . extractScriptKey = function ( index ) {
if ( this . ins [ index ] ) {
if ( ( this . ins [ index ] . script . chunks . length == 5 ) && this . ins [ index ] . script . chunks [ 4 ] == 172 && coinjs . isArray ( this . ins [ index ] . script . chunks [ 2 ] ) ) { //OP_CHECKSIG
// regular scriptPubkey (not signed)
return { 'type' : 'scriptpubkey' , 'signed' : 'false' , 'signatures' : 0 , 'script' : Crypto . util . bytesToHex ( this . ins [ index ] . script . buffer ) } ;
} else if ( ( this . ins [ index ] . script . chunks . length == 2 ) && this . ins [ index ] . script . chunks [ 0 ] [ 0 ] == 48 ) {
// regular scriptPubkey (probably signed)
return { 'type' : 'scriptpubkey' , 'signed' : 'true' , 'signatures' : 1 , 'script' : Crypto . util . bytesToHex ( this . ins [ index ] . script . buffer ) } ;
} else if ( this . ins [ index ] . script . chunks [ 0 ] == 0 && this . ins [ index ] . script . chunks [ this . ins [ index ] . script . chunks . length - 1 ] [ this . ins [ index ] . script . chunks [ this . ins [ index ] . script . chunks . length - 1 ] . length - 1 ] == 174 ) { // OP_CHECKMULTISIG
// multisig script, with signature(s) included
return { 'type' : 'multisig' , 'signed' : 'true' , 'signatures' : this . ins [ index ] . script . chunks . length - 2 , 'script' : Crypto . util . bytesToHex ( this . ins [ index ] . script . chunks [ this . ins [ index ] . script . chunks . length - 1 ] ) } ;
} else if ( this . ins [ index ] . script . chunks [ 0 ] >= 80 && this . ins [ index ] . script . chunks [ this . ins [ index ] . script . chunks . length - 1 ] == 174 ) { // OP_CHECKMULTISIG
// multisig script, without signature!
return { 'type' : 'multisig' , 'signed' : 'false' , 'signatures' : 0 , 'script' : Crypto . util . bytesToHex ( this . ins [ index ] . script . buffer ) } ;
} else if ( this . ins [ index ] . script . chunks . length == 0 ) {
// empty
return { 'type' : 'empty' , 'signed' : 'false' , 'signatures' : 0 , 'script' : '' } ;
} else {
// something else
return { 'type' : 'unknown' , 'signed' : 'false' , 'signatures' : 0 , 'script' : Crypto . util . bytesToHex ( this . ins [ index ] . script . buffer ) } ;
}
} else {
return false ;
}
}
/* generate a signature from a transaction hash */
r . transactionSig = function ( index , wif ) {
function serializeSig ( r , s ) {
var rBa = r . toByteArraySigned ( ) ;
var sBa = s . toByteArraySigned ( ) ;
var sequence = [ ] ;
sequence . push ( 0x02 ) ; // INTEGER
sequence . push ( rBa . length ) ;
sequence = sequence . concat ( rBa ) ;
sequence . push ( 0x02 ) ; // INTEGER
sequence . push ( sBa . length ) ;
sequence = sequence . concat ( sBa ) ;
sequence . unshift ( sequence . length ) ;
sequence . unshift ( 0x30 ) ; // SEQUENCE
return sequence ;
}
var hash = Crypto . util . hexToBytes ( this . transactionHash ( index ) ) ;
if ( hash ) {
var curve = EllipticCurve . getSECCurveByName ( "secp256k1" ) ;
var key = coinjs . wif2privkey ( wif ) ;
var priv = BigInteger . fromByteArrayUnsigned ( Crypto . util . hexToBytes ( key [ 'privkey' ] ) ) ;
var n = curve . getN ( ) ;
var e = BigInteger . fromByteArrayUnsigned ( hash ) ;
2015-01-01 17:09:55 +01:00
var badrs = 0
2014-12-02 00:36:49 +01:00
do {
2015-01-01 17:09:55 +01:00
var k = this . deterministicK ( wif , hash , badrs ) ;
2014-12-02 00:36:49 +01:00
var G = curve . getG ( ) ;
var Q = G . multiply ( k ) ;
var r = Q . getX ( ) . toBigInteger ( ) . mod ( n ) ;
2015-01-01 17:09:55 +01:00
var s = k . modInverse ( n ) . multiply ( e . add ( priv . multiply ( r ) ) ) . mod ( n ) ;
badrs ++
} while ( r . compareTo ( BigInteger . ZERO ) <= 0 || s . compareTo ( BigInteger . ZERO ) <= 0 ) ;
2014-12-02 00:36:49 +01:00
var sig = serializeSig ( r , s ) ;
sig . push ( parseInt ( 1 , 10 ) ) ;
return Crypto . util . bytesToHex ( sig ) ;
} else {
return false ;
}
}
2015-01-01 17:09:55 +01:00
// https://tools.ietf.org/html/rfc6979#section-3.2
r . deterministicK = function ( wif , hash , badrs ) {
// if r or s were invalid when this function was used in signing,
// we do not want to actually compute r, s here for efficiency, so,
// we can increment badrs. explained at end of RFC 6979 section 3.2
// wif is b58check encoded wif privkey.
// hash is byte array of transaction digest.
// badrs is used only if the k resulted in bad r or s.
// some necessary things out of the way for clarity.
badrs = badrs || 0 ;
var key = coinjs . wif2privkey ( wif ) ;
var x = Crypto . util . hexToBytes ( key [ 'privkey' ] )
var curve = EllipticCurve . getSECCurveByName ( "secp256k1" ) ;
var N = curve . getN ( ) ;
// Step: a
// hash is a byteArray of the message digest. so h1 == hash in our case
// Step: b
var v = new Uint8Array ( 32 ) ;
v = [ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ] ;
// Step: c
var k = new Uint8Array ( 32 ) ;
k = [ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ;
// Step: d
k = Crypto . HMAC ( Crypto . SHA256 , v . concat ( [ 0 ] ) . concat ( x ) . concat ( hash ) , k , { asBytes : true } ) ;
// Step: e
v = Crypto . HMAC ( Crypto . SHA256 , v , k , { asBytes : true } ) ;
// Step: f
k = Crypto . HMAC ( Crypto . SHA256 , v . concat ( [ 1 ] ) . concat ( x ) . concat ( hash ) , k , { asBytes : true } ) ;
// Step: g
v = Crypto . HMAC ( Crypto . SHA256 , v , k , { asBytes : true } ) ;
// Step: h1
var T = [ ] ;
// Step: h2 (since we know tlen = qlen, just copy v to T.)
v = Crypto . HMAC ( Crypto . SHA256 , v , k , { asBytes : true } ) ;
T = v ;
// Step: h3
var KBigInt = BigInteger . fromByteArrayUnsigned ( T ) ;
// loop if KBigInt is not in the range of [1, N-1] or if badrs needs incrementing.
var i = 0
while ( KBigInt . compareTo ( N ) >= 0 || KBigInt . compareTo ( BigInteger . ZERO ) <= 0 || i < badrs ) {
k = Crypto . HMAC ( Crypto . SHA256 , v . concat ( [ 0 ] ) , k , { asBytes : true } ) ;
v = Crypto . HMAC ( Crypto . SHA256 , v , k , { asBytes : true } ) ;
T = v ;
KBigInt = BigInteger . fromByteArrayUnsigned ( T ) ;
i ++
} ;
return KBigInt ;
} ;
r . testdeterministicK = function ( ) {
// https://github.com/bitpay/bitcore/blob/9a5193d8e94b0bd5b8e7f00038e7c0b935405a03/test/crypto/ecdsa.js
// Line 21 and 22 specify digest hash and privkey.
// Line 96-117 tells expected result.
var hash = Crypto . SHA256 ( 'test data' . split ( '' ) . map ( function ( c ) { return c . charCodeAt ( 0 ) ; } ) , { asBytes : true } ) ;
var wif = coinjs . privkey2wif ( "fee0a1f7afebf9d2a5a80c0c98a31c709681cce195cbcd06342b517970c0be1e" ) ;
var KBigInt = this . deterministicK ( wif , hash ) ;
var KBigInt0 = this . deterministicK ( wif , hash , 0 ) ;
var KBigInt1 = this . deterministicK ( wif , hash , 1 ) ;
var K = Crypto . util . bytesToHex ( KBigInt . toByteArrayUnsigned ( ) ) ;
var K0 = Crypto . util . bytesToHex ( KBigInt0 . toByteArrayUnsigned ( ) ) ;
var K1 = Crypto . util . bytesToHex ( KBigInt1 . toByteArrayUnsigned ( ) ) ;
if ( K != "fcce1de7a9bcd6b2d3defade6afa1913fb9229e3b7ddf4749b55c4848b2a196e" ) {
return false ;
} else if ( K0 != "fcce1de7a9bcd6b2d3defade6afa1913fb9229e3b7ddf4749b55c4848b2a196e" ) {
return false ;
} else if ( K1 != "6f4dcca6fa7a137ae9d110311905013b3c053c732ad18611ec2752bb3dcef9d8" ) {
return false ;
} ;
hash = Crypto . SHA256 ( 'Everything should be made as simple as possible, but not simpler.' . split ( '' ) . map ( function ( c ) { return c . charCodeAt ( 0 ) ; } ) , { asBytes : true } ) ;
wif = coinjs . privkey2wif ( "0000000000000000000000000000000000000000000000000000000000000001" ) ;
KBigInt = this . deterministicK ( wif , hash ) ;
KBigInt0 = this . deterministicK ( wif , hash , 0 ) ;
K = Crypto . util . bytesToHex ( KBigInt . toByteArrayUnsigned ( ) ) ;
K0 = Crypto . util . bytesToHex ( KBigInt0 . toByteArrayUnsigned ( ) ) ;
if ( K != "ec633bd56a5774a0940cb97e27a9e4e51dc94af737596a0c5cbb3d30332d92a5" ) {
return false ;
} else if ( K0 != "ec633bd56a5774a0940cb97e27a9e4e51dc94af737596a0c5cbb3d30332d92a5" ) {
return false ;
} ;
return true ;
} ;
2014-12-02 00:36:49 +01:00
/* sign a "standard" input */
r . signinput = function ( index , wif ) {
var key = coinjs . wif2pubkey ( wif ) ;
var signature = this . transactionSig ( index , wif ) ;
var s = coinjs . script ( ) ;
s . writeBytes ( Crypto . util . hexToBytes ( signature ) ) ;
s . writeBytes ( Crypto . util . hexToBytes ( key [ 'pubkey' ] ) ) ;
this . ins [ index ] . script = s ;
return true ;
}
/* sign a multisig input */
r . signmultisig = function ( index , wif ) {
function scriptListPubkey ( redeemScript ) {
var r = { } ;
for ( var i = 1 ; i < redeemScript . chunks . length - 2 ; i ++ ) {
r [ i ] = Crypto . util . hexToBytes ( coinjs . pubkeydecompress ( Crypto . util . bytesToHex ( redeemScript . chunks [ i ] ) ) ) ;
}
return r ;
}
function scriptListSigs ( scriptSig ) {
var r = { } ;
if ( scriptSig . chunks [ 0 ] == 0 && scriptSig . chunks [ scriptSig . chunks . length - 1 ] [ scriptSig . chunks [ scriptSig . chunks . length - 1 ] . length - 1 ] == 174 ) {
for ( var i = 1 ; i < scriptSig . chunks . length - 1 ; i ++ ) {
r [ i ] = scriptSig . chunks [ i ] ;
}
}
return r ;
}
var redeemScript = ( this . ins [ index ] . script . chunks [ this . ins [ index ] . script . chunks . length - 1 ] == 174 ) ? this . ins [ index ] . script . buffer : this . ins [ index ] . script . chunks [ this . ins [ index ] . script . chunks . length - 1 ] ;
var sighash = Crypto . util . hexToBytes ( this . transactionHash ( index ) ) ;
var signature = Crypto . util . hexToBytes ( this . transactionSig ( index , wif ) ) ;
var s = coinjs . script ( ) ;
s . writeOp ( 0 ) ;
if ( this . ins [ index ] . script . chunks [ this . ins [ index ] . script . chunks . length - 1 ] == 174 ) {
s . writeBytes ( signature ) ;
} else if ( this . ins [ index ] . script . chunks [ 0 ] == 0 && this . ins [ index ] . script . chunks [ this . ins [ index ] . script . chunks . length - 1 ] [ this . ins [ index ] . script . chunks [ this . ins [ index ] . script . chunks . length - 1 ] . length - 1 ] == 174 ) {
var pubkeyList = scriptListPubkey ( coinjs . script ( redeemScript ) ) ;
var sigsList = scriptListSigs ( this . ins [ index ] . script ) ;
sigsList [ coinjs . countObject ( sigsList ) + 1 ] = signature ;
for ( x in pubkeyList ) {
for ( y in sigsList ) {
if ( coinjs . verifySignature ( sighash , sigsList [ y ] , pubkeyList [ x ] ) ) {
s . writeBytes ( sigsList [ y ] ) ;
}
}
}
}
s . writeBytes ( redeemScript ) ;
this . ins [ index ] . script = s ;
return true ;
}
/* sign inputs */
r . sign = function ( wif ) {
for ( var i = 0 ; i < this . ins . length ; i ++ ) {
var d = this . extractScriptKey ( i ) ;
var w2a = coinjs . wif2address ( wif ) ;
var script = coinjs . script ( ) ;
var pubkeyHash = script . pubkeyHash ( w2a [ 'address' ] ) ;
if ( ( ( d [ 'type' ] == 'scriptpubkey' && d [ 'script' ] == Crypto . util . bytesToHex ( pubkeyHash . buffer ) ) || d [ 'type' ] == 'empty' ) && d [ 'signed' ] == "false" ) {
this . signinput ( i , wif ) ;
} else if ( d [ 'type' ] == 'multisig' ) {
this . signmultisig ( i , wif ) ;
} else {
// could not sign
}
}
return this . serialize ( ) ;
}
/* serialize a transaction */
r . serialize = function ( ) {
var buffer = [ ] ;
buffer = buffer . concat ( coinjs . numToBytes ( parseInt ( this . version ) , 4 ) ) ;
buffer = buffer . concat ( coinjs . numToVarInt ( this . ins . length ) ) ;
for ( var i = 0 ; i < this . ins . length ; i ++ ) {
var txin = this . ins [ i ] ;
buffer = buffer . concat ( Crypto . util . hexToBytes ( txin . outpoint . hash ) . reverse ( ) ) ;
buffer = buffer . concat ( coinjs . numToBytes ( parseInt ( txin . outpoint . index ) , 4 ) ) ;
var scriptBytes = txin . script . buffer ;
buffer = buffer . concat ( coinjs . numToVarInt ( scriptBytes . length ) ) ;
buffer = buffer . concat ( scriptBytes ) ;
buffer = buffer . concat ( coinjs . numToBytes ( parseInt ( txin . sequence ) , 4 ) ) ;
}
buffer = buffer . concat ( coinjs . numToVarInt ( this . outs . length ) ) ;
for ( var i = 0 ; i < this . outs . length ; i ++ ) {
var txout = this . outs [ i ] ;
buffer = buffer . concat ( coinjs . numToBytes ( txout . value , 8 ) ) ;
var scriptBytes = txout . script . buffer ;
buffer = buffer . concat ( coinjs . numToVarInt ( scriptBytes . length ) ) ;
buffer = buffer . concat ( scriptBytes ) ;
}
buffer = buffer . concat ( coinjs . numToBytes ( parseInt ( this . lock _time ) , 4 ) ) ;
return Crypto . util . bytesToHex ( buffer ) ;
}
/* deserialize a transaction */
r . deserialize = function ( buffer ) {
if ( typeof buffer == "string" ) {
buffer = Crypto . util . hexToBytes ( buffer )
}
var pos = 0 ;
var readAsInt = function ( bytes ) {
if ( bytes == 0 ) return 0 ;
pos ++ ;
return buffer [ pos - 1 ] + readAsInt ( bytes - 1 ) * 256 ;
}
var readVarInt = function ( ) {
pos ++ ;
if ( buffer [ pos - 1 ] < 253 ) {
return buffer [ pos - 1 ] ;
}
return readAsInt ( buffer [ pos - 1 ] - 251 ) ;
}
var readBytes = function ( bytes ) {
pos += bytes ;
return buffer . slice ( pos - bytes , pos ) ;
}
var readVarString = function ( ) {
var size = readVarInt ( ) ;
return readBytes ( size ) ;
}
var obj = new coinjs . transaction ( ) ;
obj . version = readAsInt ( 4 ) ;
var ins = readVarInt ( ) ;
for ( var i = 0 ; i < ins ; i ++ ) {
obj . ins . push ( {
outpoint : {
hash : Crypto . util . bytesToHex ( readBytes ( 32 ) . reverse ( ) ) ,
index : readAsInt ( 4 )
} ,
script : coinjs . script ( readVarString ( ) ) ,
sequence : readAsInt ( 4 )
} ) ;
}
var outs = readVarInt ( ) ;
for ( var i = 0 ; i < outs ; i ++ ) {
obj . outs . push ( {
value : coinjs . bytesToNum ( readBytes ( 8 ) ) ,
script : coinjs . script ( readVarString ( ) )
} ) ;
}
2014-12-15 13:15:28 +01:00
obj . lock _time = readAsInt ( 4 ) ;
2014-12-02 00:36:49 +01:00
return obj ;
}
r . size = function ( ) {
return ( ( this . serialize ( ) ) . length / 2 ) . toFixed ( 0 ) ;
}
return r ;
}
/* start of signature vertification functions */
coinjs . verifySignature = function ( hash , sig , pubkey ) {
function parseSig ( 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 ] ;
var r = BigInteger . fromByteArrayUnsigned ( rBa ) ;
var s = BigInteger . fromByteArrayUnsigned ( sBa ) ;
return { r : r , s : s } ;
}
var r , s ;
if ( coinjs . isArray ( sig ) ) {
var obj = parseSig ( sig ) ;
r = obj . r ;
s = obj . s ;
} else if ( "object" === typeof sig && sig . r && sig . s ) {
r = sig . r ;
s = sig . s ;
} else {
throw "Invalid value for signature" ;
}
var Q ;
if ( coinjs . isArray ( pubkey ) ) {
var ecparams = EllipticCurve . getSECCurveByName ( "secp256k1" ) ;
Q = EllipticCurve . PointFp . decodeFrom ( ecparams . getCurve ( ) , pubkey ) ;
} else {
throw "Invalid format for pubkey value, must be byte array" ;
}
var e = BigInteger . fromByteArrayUnsigned ( hash ) ;
return coinjs . verifySignatureRaw ( e , r , s , Q ) ;
}
coinjs . verifySignatureRaw = function ( e , r , s , Q ) {
var ecparams = EllipticCurve . getSECCurveByName ( "secp256k1" ) ;
var n = ecparams . getN ( ) ;
var G = ecparams . getG ( ) ;
if ( r . compareTo ( BigInteger . ONE ) < 0 || r . compareTo ( n ) >= 0 )
return false ;
if ( s . compareTo ( BigInteger . ONE ) < 0 || s . compareTo ( n ) >= 0 )
return false ;
var c = s . modInverse ( n ) ;
var u1 = e . multiply ( c ) . mod ( n ) ;
var u2 = r . multiply ( c ) . mod ( n ) ;
var point = G . multiply ( u1 ) . add ( Q . multiply ( u2 ) ) ;
var v = point . getX ( ) . toBigInteger ( ) . mod ( n ) ;
return v . equals ( r ) ;
}
/* start of privates functions */
/* base58 encode function */
coinjs . base58encode = function ( buffer ) {
var alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" ;
var base = BigInteger . valueOf ( 58 ) ;
var bi = BigInteger . fromByteArrayUnsigned ( buffer ) ;
var chars = [ ] ;
while ( bi . compareTo ( base ) >= 0 ) {
var mod = bi . mod ( base ) ;
chars . unshift ( alphabet [ mod . intValue ( ) ] ) ;
bi = bi . subtract ( mod ) . divide ( base ) ;
}
chars . unshift ( alphabet [ bi . intValue ( ) ] ) ;
for ( var i = 0 ; i < buffer . length ; i ++ ) {
if ( buffer [ i ] == 0x00 ) {
chars . unshift ( alphabet [ 0 ] ) ;
} else break ;
}
return chars . join ( '' ) ;
}
/* base58 decode function */
coinjs . base58decode = function ( buffer ) {
var alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" ;
var base = BigInteger . valueOf ( 58 ) ;
var validRegex = /^[1-9A-HJ-NP-Za-km-z]+$/ ;
var bi = BigInteger . valueOf ( 0 ) ;
var leadingZerosNum = 0 ;
for ( var i = buffer . length - 1 ; i >= 0 ; i -- ) {
var alphaIndex = alphabet . indexOf ( buffer [ i ] ) ;
if ( alphaIndex < 0 ) {
throw "Invalid character" ;
}
bi = bi . add ( BigInteger . valueOf ( alphaIndex ) . multiply ( base . pow ( buffer . length - 1 - i ) ) ) ;
if ( buffer [ i ] == "1" ) leadingZerosNum ++ ;
else leadingZerosNum = 0 ;
}
var bytes = bi . toByteArrayUnsigned ( ) ;
while ( leadingZerosNum -- > 0 ) bytes . unshift ( 0 ) ;
return bytes ;
}
/* raw ajax function to avoid needing bigger frame works like jquery, mootools etc */
coinjs . ajax = function ( u , f , m , a ) {
var x = false ;
try {
x = new ActiveXObject ( 'Msxml2.XMLHTTP' )
} catch ( e ) {
try {
x = new ActiveXObject ( 'Microsoft.XMLHTTP' )
} catch ( e ) {
x = new XMLHttpRequest ( )
}
}
if ( x == false ) {
return false ;
}
x . open ( m , u , true ) ;
x . onreadystatechange = function ( ) {
if ( ( x . readyState == 4 ) && f )
f ( x . responseText ) ;
} ;
if ( m == 'POST' ) {
x . setRequestHeader ( 'Content-type' , 'application/x-www-form-urlencoded' ) ;
}
x . send ( a ) ;
}
/* clone an object */
coinjs . clone = function ( obj ) {
if ( obj == null || typeof ( obj ) != 'object' ) return obj ;
var temp = obj . constructor ( ) ;
for ( var key in obj ) {
if ( obj . hasOwnProperty ( key ) ) {
temp [ key ] = coinjs . clone ( obj [ key ] ) ;
}
}
return temp ;
}
coinjs . numToBytes = function ( num , bytes ) {
2014-12-15 15:38:39 +01:00
if ( typeof bytes === undefined ) bytes = 8 ;
2014-12-02 00:36:49 +01:00
if ( bytes == 0 ) {
return [ ] ;
} else {
return [ num % 256 ] . concat ( coinjs . numToBytes ( Math . floor ( num / 256 ) , bytes - 1 ) ) ;
}
}
coinjs . numToVarInt = function ( num ) {
if ( num < 253 ) {
return [ num ] ;
} else if ( num < 65536 ) {
return [ 253 ] . concat ( coinjs . numToBytes ( num , 2 ) ) ;
} else if ( num < 4294967296 ) {
return [ 254 ] . concat ( coinjs . numToBytes ( num , 4 ) ) ;
} else {
return [ 253 ] . concat ( coinjs . numToBytes ( num , 8 ) ) ;
}
}
coinjs . bytesToNum = function ( bytes ) {
if ( bytes . length == 0 ) return 0 ;
else return bytes [ 0 ] + 256 * coinjs . bytesToNum ( bytes . slice ( 1 ) ) ;
}
coinjs . isArray = function ( o ) {
return Object . prototype . toString . call ( o ) === '[object Array]' ;
}
coinjs . countObject = function ( obj ) {
var count = 0 ;
var i ;
for ( i in obj ) {
if ( obj . hasOwnProperty ( i ) ) {
count ++ ;
}
}
return count ;
}
2014-12-05 22:26:34 +01:00
coinjs . random = function ( length ) {
var r = "" ;
var l = length || 25 ;
var chars = "!$%^&*()_+{}:@~?><|\./;'#][=-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" ;
for ( x = 0 ; x < l ; x ++ ) {
r += chars . charAt ( Math . floor ( Math . random ( ) * 62 ) ) ;
}
return r ;
}
2014-12-02 00:36:49 +01:00
} ) ( ) ;