diff --git a/Blockchain/Backend/API/Client_calls/BaseCurl.php b/Blockchain/Backend/API/Client_calls/BaseCurl.php index e347860..fb91d6a 100644 --- a/Blockchain/Backend/API/Client_calls/BaseCurl.php +++ b/Blockchain/Backend/API/Client_calls/BaseCurl.php @@ -1,5 +1,5 @@ coinbaseTransaction(); + $merkleRoot = $coinbaseTx->TxId; $bits = 'ffff001f'; $blockheader = new BlockHeader($GLOBALS['VERSION'], $prevBlockHash, $merkleRoot, $timestamp, $bits); $blockheader->mine(); - $block = new Block($BlockHeight, 1, (array)$blockheader, 1, $Transaction); + $block = new Block($BlockHeight, 1, (array)$blockheader, 1, $coinbaseTx); +// print_r((array)$block); +// die(); $this->writeOnDisk((array)$block); } diff --git a/Blockchain/Backend/core/Script.php b/Blockchain/Backend/core/Script.php new file mode 100644 index 0000000..5bc00f1 --- /dev/null +++ b/Blockchain/Backend/core/Script.php @@ -0,0 +1,21 @@ +cmds = []; + } else { + $this->cmds = $cmds; + } + } + + public static function p2pkhScript($h160) + { + // Takes a hash160 and returns the p2 public key hash ScriptPubKey + $script = new Script([0x76, 0xA9, $h160, 0x88, 0xAC]); + return $script; + } +} \ No newline at end of file diff --git a/Blockchain/Backend/core/transactions/Coinbase.php b/Blockchain/Backend/core/transactions/Coinbase.php new file mode 100644 index 0000000..23c54eb --- /dev/null +++ b/Blockchain/Backend/core/transactions/Coinbase.php @@ -0,0 +1,133 @@ +blockHeightIntLittleEndian = intToLittleEndian($blockHeight, bytesNeeded($blockHeight)); + } + + public function coinbaseTransaction() { + $prevTx = hex2bin(ZERO_HASH); + $prevIndex = 0xFFFFFFFF; + + $txIns = []; + $txIns[] = new TxIn($prevTx, $prevIndex); + $txIns[0]->scriptSig->cmds[] = $this->blockHeightIntLittleEndian; + + $txOuts = []; + $targetAmount = REWARD * 100000000; + $hexValue = $this->decodeBase58API(MINER_ADDRESS); + $targetH160 = $hexValue; + $targetScript = Script::p2pkhScript($targetH160); + $txOuts[] = new TxOut($targetAmount, $targetScript); + + $coinBaseTx = new Tx(1, $txIns, $txOuts, 0); + $coinBaseTx->TxId = $coinBaseTx->id(); + + return $coinBaseTx; + } + + public function decodeBase58API($value) + { + $address = PluginHelperAPI::$clientAddress; + $url = $address."get_decode_base58"; + $ch = curl_init($url); + $data = json_encode(array( + "value" => $value + )); + $val = PluginHelperAPI::curlSkeletonIfDataSend($ch, "POST", $data); + $data = json_decode($val['data'], true); + return $data['byte_data']; + } + +} + +//$address = PluginHelperAPI::$clientAddress; +//$url = $address."get_decode_base58"; +//$ch = curl_init($url); +//$data = json_encode(array( +// "value" => "1K3if2mFojLAWVtdD1eeYYKNVCwghpBvgb" +//)); +//$val = PluginHelperAPI::curlSkeletonIfDataSend($ch, "POST", $data); +//$data = json_decode($val['data'], true); +//echo "\n\n"; +//print_r($data['byte_data']); +//function decodeBase58API($value) +//{ +// $address = PluginHelperAPI::$clientAddress; +// $url = $address . "get_decode_base58"; +// $ch = curl_init($url); +// $data = json_encode(array( +// "value" => $value +// )); +// $val = PluginHelperAPI::curlSkeletonIfDataSend($ch, "POST", $data); +// $data = json_decode($val['data'], true); +// return $data['byte_data']; +//} +// +//$data = decodeBase58API("1K3if2mFojLAWVtdD1eeYYKNVCwghpBvgb"); +//echo "\n\n"; +//print_r($data); +//echo "\n\n"; +// +// +//$binaryData = hex2bin($data); +//print_r($binaryData); +//echo "\n\n"; +// +//// Perform operations on the binary data (if needed) +// +//// Convert the binary data back to a hexadecimal string +//$resultHexadecimal = bin2hex($binaryData); +// +//// Output the result +//echo $resultHexadecimal; + +////$hexString = $data; +////$byteString = 'b"' . implode('\x', str_split($hexString, 2)) . '"'; +//$byteString = hex2bin($data); +//$formattedBinary = 'b"'; +//foreach (str_split($byteString) as $byte) { +// $formattedBinary .= '\x' . bin2hex($byte); +//} +//$formattedBinary .= '",'; +// +//echo $formattedBinary; +//echo "\n\n"; +// +//$hexString = ''; +//$matches = []; +//if (preg_match('/b"(.+)",/', $formattedBinary, $matches)) { +// $hexBytes = explode('\x', $matches[1]); +// foreach ($hexBytes as $hexByte) { +// $hexString .= chr(hexdec($hexByte)); +// } +// $hexString = bin2hex($hexString); +// echo $hexString; +//} else { +// echo "Invalid format."; +//} +//echo "\n\n"; +// +//$hexString = ''; +//$matches = []; +// +//if (preg_match('/b"(.+)",/', $formattedBinary, $matches)) { +// $hexBytes = explode('\x', $matches[1]); +// foreach ($hexBytes as $hexByte) { +// $hexString .= bin2hex(hex2bin($hexByte)); +// } +// echo $hexString; +//} else { +// echo "Invalid format."; +//} \ No newline at end of file diff --git a/Blockchain/Backend/core/transactions/Tx.php b/Blockchain/Backend/core/transactions/Tx.php new file mode 100644 index 0000000..d711f93 --- /dev/null +++ b/Blockchain/Backend/core/transactions/Tx.php @@ -0,0 +1,108 @@ +version = $version; + $this->txIns = $txIns; + $this->txOuts = $txOuts; + $this->locktime = $locktime; + } + + /** + * @throws Exception + */ + public function serialize() { + // Initialize an empty result string + $result = ""; + + // Serialize the version as a little-endian 4-byte integer + $result .= intToLittleEndian($this->version, 4); + + // Serialize the number of transaction inputs as a variable-length integer + $result .= encode_varint(count($this->tx_ins)); + + // Serialize each transaction input + foreach ($this->tx_ins as $tx_in) { + $result .= $tx_in->serialize(); + } + + // Serialize the number of transaction outputs as a variable-length integer + $result .= encode_varint(count($this->tx_outs)); + + // Serialize each transaction output + foreach ($this->tx_outs as $tx_out) { + $result .= $tx_out->serialize(); + } + + // Serialize the locktime as a little-endian 4-byte integer + $result .= intToLittleEndian($this->locktime, 4); + + // Return the serialized result + return $result; + } + + public function id() { + // Human-readable Tx id + return $this->hash()->hex(); + } + + /** + * @throws Exception + */ + public function hash() { + // Binary Hash of serialization + return strrev(hash256($this->serialize())); + } + + public function isCoinbase() { + if (count($this->txIns) !== 1) { + return false; + } + + $firstInput = $this->txIns[0]; + if ($firstInput->prevTx !== hex2bin(ZERO_HASH)) { + return false; + } + + if ($firstInput->prevIndex !== 0xFFFFFFFF) { + return false; + } + + return true; + } + + public function toDict() { + // Convert Transaction Input to dict + foreach ($this->txIns as $txIndex => $txIn) { + if ($this->isCoinbase()) { + $txIn->scriptSig->cmds[0] = littleEndianToInt($txIn->scriptSig->cmds[0]); + } + + $txIn->prevTx = bin2hex($txIn->prevTx); + + foreach ($txIn->scriptSig->cmds as $index => $cmd) { + if (is_string($cmd)) { + $txIn->scriptSig->cmds[$index] = bin2hex($cmd); + } + } + + $txIn->scriptSig = (array) $txIn->scriptSig; + $this->txIns[$txIndex] = (array) $txIn; + } + + // Convert Transaction Output to dict + foreach ($this->txOuts as $index => $txOut) { + $txOut->scriptPubkey->cmds[2] = bin2hex($txOut->scriptPubkey->cmds[2]); + $txOut->scriptPubkey = (array) $txOut->scriptPubkey; + $this->txOuts[$index] = (array) $txOut; + } + + return (array) $this; + } +} \ No newline at end of file diff --git a/Blockchain/Backend/core/transactions/TxIn.php b/Blockchain/Backend/core/transactions/TxIn.php new file mode 100644 index 0000000..d7ddf39 --- /dev/null +++ b/Blockchain/Backend/core/transactions/TxIn.php @@ -0,0 +1,26 @@ +prevTx = $prevTx; + $this->prevIndex = $prevIndex; + $this->scriptSig = $scriptSig ?? new Script(); + $this->sequence = $sequence; + } + + public function serialize() + { + $result = strrev($this->prev_tx); + $result .= intToLittleEndian($this->prev_index, 4); + $result .= $this->script_sig->serialize(); + $result .= intToLittleEndian($this->sequence, 4); + return $result; + } +} \ No newline at end of file diff --git a/Blockchain/Backend/core/transactions/TxOut.php b/Blockchain/Backend/core/transactions/TxOut.php new file mode 100644 index 0000000..00d8e57 --- /dev/null +++ b/Blockchain/Backend/core/transactions/TxOut.php @@ -0,0 +1,19 @@ +amount = $amount; + $this->scriptPubkey = $scriptPubkey; + } + + public function serialize() + { + $result = intToLittleEndian($this->amount, 8); + $result .= $this->script_pubkey->serialize(); + return $result; + } +} \ No newline at end of file diff --git a/Blockchain/Backend/util/util.php b/Blockchain/Backend/util/util.php index 9bd1b95..d064a7d 100644 --- a/Blockchain/Backend/util/util.php +++ b/Blockchain/Backend/util/util.php @@ -10,10 +10,58 @@ function hash160($data) { return hash('ripemd160', $sha256Hash, true); } -// Example usage -$input = 'some data to hash'; -$hashed256 = hash256($input); -$hashed160 = hash160($input); +function intToLittleEndian($n, $length) { + // Convert an integer to a little-endian byte string of a specified length + $result = ''; + for ($i = 0; $i < $length; $i++) { + $byte = $n & 0xFF; // Get the least significant byte + $result .= chr($byte); // Convert to a character and append to the result + $n >>= 8; // Shift the integer right by 8 bits + } + return $result; +} + +function bytesNeeded($n) +{ + if ($n == 0) { + return 1; + } + return intval(log($n, 256)) + 1; +} + +function littleEndianToInt($b) +{ + // Reverse the byte array and convert it to an integer + $reversedBytes = array_reverse(str_split($b)); + $littleEndian = implode('', $reversedBytes); + return hexdec(bin2hex($littleEndian)); +} -echo "Hashed 256: " . bin2hex($hashed256) . PHP_EOL; -echo "Hashed 160: " . bin2hex($hashed160) . PHP_EOL; \ No newline at end of file + +function encode_varint($i) { + if ($i < 0xFD) { + return chr($i); + } elseif ($i < 0x10000) { + return "\xFD" . intToLittleEndian($i, 2); + } elseif ($i < 0x100000000) { + return "\xFE" . intToLittleEndian($i, 4); + } elseif ($i < 0x10000000000000000) { + return "\xFF" . intToLittleEndian($i, 8); + } else { + throw new Exception("integer too large: $i"); + } +} + +//try { +// $encoded = encode_varint(500); +//} catch (Exception $e) { +//} +//echo bin2hex($encoded); + +// Example usage +//$input = 'some data to hash'; +//$hashed256 = hash256($input); +//$hashed160 = hash160($input); +// +//echo "Hashed 256: " . bin2hex($hashed256) . PHP_EOL; +//echo "Hashed 160: " . bin2hex($hashed160) . PHP_EOL; \ No newline at end of file diff --git a/Blockchain/Python_Package/test.py b/Blockchain/Python_Package/keyGenerate.py similarity index 88% rename from Blockchain/Python_Package/test.py rename to Blockchain/Python_Package/keyGenerate.py index f2de86f..f0437a7 100644 --- a/Blockchain/Python_Package/test.py +++ b/Blockchain/Python_Package/keyGenerate.py @@ -1,13 +1,9 @@ -from flask import Flask, jsonify import secrets from EllepticCurve.EllepticCurve import Sha256Point from util import hash160, hash256 -app = Flask(__name__) - -@app.route('/generate_keys', methods=['GET']) -def generate_keys(): +def generatePrivateKeyPublicAddress(): Gx = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798 Gy = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8 @@ -53,7 +49,3 @@ def generate_keys(): PublicAddress = prefix + result return {"privateKey": privateKey, "publicAddress": PublicAddress} - - -if __name__ == '__main__': - app.run(debug=True) diff --git a/Blockchain/Python_Package/main.py b/Blockchain/Python_Package/main.py new file mode 100644 index 0000000..271220f --- /dev/null +++ b/Blockchain/Python_Package/main.py @@ -0,0 +1,45 @@ +from flask import Flask, jsonify, request +from keyGenerate import generatePrivateKeyPublicAddress +from util import bytes_needed, decode_base58, little_endian_to_int, int_to_little_endian +import json +import sys + + +app = Flask(__name__) + + +@app.route('/generate_keys', methods=['GET']) +def generate_keys(): + result = generatePrivateKeyPublicAddress() + return result + + +# ====================================================================================================================== + +@app.route('/get_bytes_needed', methods=['POST']) +def get_bytes_needed(): + data = request.get_json() + if 'value' not in data: + return jsonify({'error': 'Missing values'}), 400 + val = int(data['value']) + result = bytes_needed(val) + return jsonify({"result": result}), 201 + + +# ====================================================================================================================== + +@app.route('/get_decode_base58', methods=['POST']) +def get_decode_base58(): + data = request.get_json() + if 'value' not in data: + return jsonify({'error': 'Missing values'}), 400 + byte_data = decode_base58(data['value']) + hex_data = byte_data.hex() + response = { + 'byte_data': hex_data + } + return jsonify(response) + + +if __name__ == '__main__': + app.run(debug=True) diff --git a/Blockchain/Python_Package/util.py b/Blockchain/Python_Package/util.py index 48739d1..88de17c 100644 --- a/Blockchain/Python_Package/util.py +++ b/Blockchain/Python_Package/util.py @@ -1,6 +1,9 @@ import hashlib from Crypto.Hash import RIPEMD160 from hashlib import sha256 +from math import log +from EllepticCurve.EllepticCurve import BASE58_ALPHABET + def hash256(s): @@ -9,4 +12,39 @@ def hash256(s): def hash160(s): - return RIPEMD160.new(sha256(s).digest()).digest() \ No newline at end of file + return RIPEMD160.new(sha256(s).digest()).digest() + + +def bytes_needed(n: int): + """ Returns byte length """ + if n == 0: + return 1 + return int(log(n, 256)) + 1 + + +def int_to_little_endian(n: int, length): + """ Takes integer and return the little endian byte of length """ + return n.to_bytes(length, 'little') + + +def little_endian_to_int(b): + """ takes bit AND RETURNS AN INTEGER """ + return int.from_bytes(b, 'little') + + +def decode_base58(s): + num = 0 + for c in s: + num *= 58 + num += BASE58_ALPHABET.index(c) + + combined = num.to_bytes(25, byteorder='big') + checksum = combined[-4:] + + if hash256(combined[:-4])[:4] != checksum: + raise ValueError(f'Bad address {checksum} {hash256(combined[:-4])[:4]}') + + value = combined[1:-4] + return value + +# b"\xc5\xf5\xdeS\x1f\xfb\xc9G\x16G\x81E\x9b\x06!\xda\xb5'\xee," diff --git a/Blockchain/data/blockchain b/Blockchain/data/blockchain index a2b05ae..e69de29 100644 --- a/Blockchain/data/blockchain +++ b/Blockchain/data/blockchain @@ -1,107 +0,0 @@ -[ - { - "Height": 0, - "Blocksize": 1, - "BlockHeader": { - "bits": "ffff001f", - "timestamp": 1692918870, - "merkleRoot": "01d3c8ffac385f49854b12bc69248645efddb80a0435dd09631643bdc605d1d1", - "prevBlockHash": "0000000000000000000000000000000000000000000000000000000000000000", - "version": 1, - "nonce": 57706, - "blockHash": "0000d0f7be9722a4d33a1147995f54e00dd09304c3de35b86abf3c73d493f269" - }, - "TxCount": 1, - "Txs": "Code Architect sent 0 Bitcoins to Indranil" - }, - { - "Height": 1, - "Blocksize": 1, - "BlockHeader": { - "bits": "ffff001f", - "timestamp": 1692918885, - "merkleRoot": "ede8645e1159205c35365fc6b765fbea7acab3d30d83f2094e87b1dc2829b69b", - "prevBlockHash": "0000d0f7be9722a4d33a1147995f54e00dd09304c3de35b86abf3c73d493f269", - "version": 1, - "nonce": 30400, - "blockHash": "0000145cbce04e57681a3492198f05ca5f68f730d2a49ced6f62a22e1e0fb89e" - }, - "TxCount": 1, - "Txs": "Code Architect sent 1 Bitcoins to Indranil" - }, - { - "Height": 2, - "Blocksize": 1, - "BlockHeader": { - "bits": "ffff001f", - "timestamp": 1692918893, - "merkleRoot": "ee3d44bff24ade0bd29fbf90bcfa1a8a2ef2c991a92bf92e8e8d7bf85cf75e30", - "prevBlockHash": "0000145cbce04e57681a3492198f05ca5f68f730d2a49ced6f62a22e1e0fb89e", - "version": 1, - "nonce": 57819, - "blockHash": "0000b8ef9e602a62196ef75a05dc898ac1e599b4cfe69fd23fcef020ffe70e82" - }, - "TxCount": 1, - "Txs": "Code Architect sent 2 Bitcoins to Indranil" - }, - { - "Height": 3, - "Blocksize": 1, - "BlockHeader": { - "bits": "ffff001f", - "timestamp": 1692918912, - "merkleRoot": "d0249e654794fa76a823925895732057dc5c51075131f4784a65d31f93754113", - "prevBlockHash": "0000b8ef9e602a62196ef75a05dc898ac1e599b4cfe69fd23fcef020ffe70e82", - "version": 1, - "nonce": 91549, - "blockHash": "000046cfcf21c1ef5ae5abdc09ee2f5d2a95dc4b19dea21e312b1ce3f8cc2718" - }, - "TxCount": 1, - "Txs": "Code Architect sent 3 Bitcoins to Indranil" - }, - { - "Height": 4, - "Blocksize": 1, - "BlockHeader": { - "bits": "ffff001f", - "timestamp": 1692918942, - "merkleRoot": "3bf90cb05ba2fb3325fec0def457cd7cc6126b204c8963d4939350b2add27c6d", - "prevBlockHash": "000046cfcf21c1ef5ae5abdc09ee2f5d2a95dc4b19dea21e312b1ce3f8cc2718", - "version": 1, - "nonce": 88482, - "blockHash": "00008541d660a151dc1d3d4ca81c5dd844c0c37b07e643322192eace6b5e50b7" - }, - "TxCount": 1, - "Txs": "Code Architect sent 4 Bitcoins to Indranil" - }, - { - "Height": 5, - "Blocksize": 1, - "BlockHeader": { - "bits": "ffff001f", - "timestamp": 1692918975, - "merkleRoot": "5957ff49fe734ffde6fb685fd313afff54a59671e98acab4f5c84fa8ded0b177", - "prevBlockHash": "00008541d660a151dc1d3d4ca81c5dd844c0c37b07e643322192eace6b5e50b7", - "version": 1, - "nonce": 8339, - "blockHash": "00005c7fd514f61cd3173a7cbd5fa54a0eb90b0ba28e9c442bc0a666fdb1dc71" - }, - "TxCount": 1, - "Txs": "Code Architect sent 5 Bitcoins to Indranil" - }, - { - "Height": 6, - "Blocksize": 1, - "BlockHeader": { - "bits": "ffff001f", - "timestamp": 1692918978, - "merkleRoot": "fc73585acb5dfb029ad461c0a2caa7259d33e3e9c613eec7ea9926a7fdceb92c", - "prevBlockHash": "00005c7fd514f61cd3173a7cbd5fa54a0eb90b0ba28e9c442bc0a666fdb1dc71", - "version": 1, - "nonce": 268283, - "blockHash": "0000210da7a197c7734b55f27751ecfdc7bb3f881bf49f230d5866625fd3dd54" - }, - "TxCount": 1, - "Txs": "Code Architect sent 6 Bitcoins to Indranil" - } -] \ No newline at end of file diff --git a/README.md b/README.md index 576900e..122acac 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,10 @@ # Blockchain with php -A personal project \ No newline at end of file +This is just a demo project just for concept purposes. Please don't use this in production. Reasons not to use PHP for blockchain development or in production: + +**Security**: Blockchain systems require a high level of security because they deal with valuable assets and transactions. PHP, while it can be secure when used correctly, has had security vulnerabilities in the past. Languages like C++ and Rust have better memory management features that can help prevent common vulnerabilities like buffer overflows. + +**Community and Ecosystem**: Blockchain development relies heavily on available libraries, tools, and an active community for support. PHP has a limited ecosystem for blockchain development compared to languages like Python, JavaScript, or Solidity (Ethereum's smart contract language). + +**Concurrency**: Many blockchain systems require high levels of concurrency and parallelism. PHP's architecture is typically designed around a request-response model, which may not be well-suited for handling the concurrent nature of blockchain networks. + +**Blockchain-specific Libraries**: Most blockchain networks have their own specific libraries and APIs for development. While there might be PHP libraries for blockchain integration, they are not as prevalent or well-maintained as libraries in other languages.
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: