├── .gitignore ├── POC_code ├── README.md ├── bin │ ├── blind_rsa_test │ └── blind_rsa_test.dSYM │ │ └── Contents │ │ ├── Info.plist │ │ └── Resources │ │ └── DWARF │ │ └── blind_rsa_test ├── include │ ├── alice.h │ ├── alice_client.h │ ├── alice_interface.h │ ├── bin.h │ ├── blind_rsa.h │ ├── bob.h │ ├── constants.h │ ├── ec.h │ ├── encrypt.h │ ├── hash.h │ ├── memory.h │ ├── network.h │ ├── random.h │ ├── scc.h │ ├── scc_interface.h │ ├── scc_wrapper_interface.h │ ├── signer.h │ ├── signer_interface.h │ ├── timer.h │ ├── tumbler.h │ ├── tx.h │ ├── utility.h │ ├── zmq.hpp │ └── zmq_addon.hpp ├── keys │ ├── EC_private_alice.pem │ ├── EC_private_bob.pem │ ├── EC_private_test.pem │ ├── EC_private_tumbler.pem │ ├── EC_private_tumbler_main.pem │ ├── EC_public_alice.pem │ ├── EC_public_bob.pem │ ├── EC_public_test.pem │ ├── EC_public_tumbler.pem │ ├── EC_public_tumbler_main.pem │ ├── private_2048_test.pem │ ├── private_2048_tumbler.pem │ ├── public_2048_test.pem │ └── public_2048_tumbler.pem ├── makefile ├── python │ ├── tx.py │ ├── tx_server.py │ └── tx_test.py ├── requirements.txt ├── src │ ├── alice.cpp │ ├── alice_client.cpp │ ├── alice_client_test.cpp │ ├── bob.cpp │ ├── bob_client.cpp │ ├── crypto │ │ ├── blind_rsa.cpp │ │ ├── ec.cpp │ │ ├── encrypt.cpp │ │ ├── hash.cpp │ │ └── random.cpp │ ├── scc.cpp │ ├── signer.cpp │ ├── signer_server.cpp │ ├── test │ │ ├── bin_test.cpp │ │ ├── blind_rsa_test.cpp │ │ ├── ec_test.cpp │ │ ├── encrypt_test.cpp │ │ ├── hash_test.cpp │ │ ├── scc_test.cpp │ │ └── utility_test.cpp │ ├── tumbler.cpp │ ├── tumbler_server.cpp │ ├── tx.cpp │ └── utility │ │ ├── bin.cpp │ │ ├── generate_rsa.cpp │ │ ├── memory.cpp │ │ ├── network.cpp │ │ ├── timer.cpp │ │ └── utility.cpp └── ubuntu_setup.sh ├── README.md └── reference_implementation ├── README.md ├── requirements.txt ├── setup.py ├── tests ├── __init__.py ├── test_crypto.py ├── test_data │ ├── client_ec_keys │ │ ├── ec_client.pem │ │ ├── ec_privkey.der │ │ └── ec_pubkey.bin │ ├── server_ec_keys │ │ ├── ec_privkey.der │ │ ├── ec_pubkey.bin │ │ └── ec_server.pem │ └── server_rsa_keys │ │ ├── private_test.pem │ │ └── public_test.pem ├── test_ec.py ├── test_puzzle_promise.py ├── test_puzzle_solver.py └── test_rsa.py ├── tumblebit ├── __init__.py ├── crypto.py ├── ec.py ├── puzzle_promise.py ├── puzzle_solver.py ├── rsa.py └── tx.py └── ubuntu_setup.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | *.egg-info 3 | __pycache__ 4 | -------------------------------------------------------------------------------- /POC_code/README.md: -------------------------------------------------------------------------------- 1 | # Proof of Concept 2 | 3 | 4 | POC TumbleBit as an untrusted [classic tumbler](https://en.wikipedia.org/wiki/Cryptocurrency_tumbler). 5 | 6 | ---- 7 | ### Warning 8 | 9 | This is proof-of-concept code and is not intended and should not be used for production. 10 | 11 | * Don't use the default keys if you plan on posting transactions on testnet or mainnet. 12 | * We have not audited this code for vulnerabilities and we are actively fixing memory corruption vulnerabilities. 13 | * There are known memory leaks in the networking code of the servers. 14 | * The servers currently do not handle more than one client at a time. 15 | * There are known [side channel attacks on ECDSA in openssl](https://www.tau.ac.il/~tromer/mobilesc/). 16 | 17 | ---- 18 | ### Dependencies 19 | 20 | - LibreSSL Version 2.3.4 or higher 21 | - Boost 22 | - ZMQ 23 | - Bitcoind (Optional: for posting transactions) 24 | - Python dependencies: ```pip install -r requirements.txt``` 25 | + python-bitcoinlib 26 | + simplejson 27 | + pyzmq 28 | + pycrypto 29 | 30 | For ubuntu, you can install the dependencies by running: 31 | ``` 32 | ./ubuntu_setup.sh 33 | ``` 34 | 35 | ### Building 36 | 37 | Default build setting is to have the clients and 38 | the servers on the same machine. 39 | 40 | If you want to run the servers on different machines, 41 | change TUMBLER_SERVER_SOCKET and SIGNER_SERVER_SOCKET in 42 | include/constants.h to point to the ip of your machine. 43 | 44 | ##### Note 45 | Should be in the **POC_code** directory 46 | 47 | All resulting binaries will be in the **bin** directory 48 | 49 | - Clients & Servers: 50 | + ```make``` 51 | - Servers: 52 | + ```make tumbler_server``` 53 | + ```make signer_server``` 54 | - Clients: 55 | + ```make bob_client``` 56 | + ```make alice_client_test``` 57 | - Only runs the puzzle-solver protocol 58 | - Tests: Tests are located in src/test 59 | + ```make test_name``` 60 | 61 | ### Running 62 | 63 | - Full Tumbler run: 64 | + ```./python/tx_server.py``` 65 | + ```./bin/tumbler_server``` 66 | + ```./bin/signer_server``` 67 | + ```./bin/bob_client``` 68 | - Just the Puzzle Solver protocol: 69 | + ```./python/tx_server.py``` 70 | + ```./bin/signer_server``` 71 | + ```./bin/alice_client_test``` 72 | -------------------------------------------------------------------------------- /POC_code/bin/blind_rsa_test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUSEC/TumbleBit/55829dc75c36554e710e723dedb510d62a57ca0c/POC_code/bin/blind_rsa_test -------------------------------------------------------------------------------- /POC_code/bin/blind_rsa_test.dSYM/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleIdentifier 8 | com.apple.xcode.dsym.blind_rsa_test 9 | CFBundleInfoDictionaryVersion 10 | 6.0 11 | CFBundlePackageType 12 | dSYM 13 | CFBundleSignature 14 | ???? 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleVersion 18 | 1 19 | 20 | 21 | -------------------------------------------------------------------------------- /POC_code/bin/blind_rsa_test.dSYM/Contents/Resources/DWARF/blind_rsa_test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUSEC/TumbleBit/55829dc75c36554e710e723dedb510d62a57ca0c/POC_code/bin/blind_rsa_test.dSYM/Contents/Resources/DWARF/blind_rsa_test -------------------------------------------------------------------------------- /POC_code/include/alice.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _alice_h 3 | #define _alice_h 4 | 5 | #include "assert.h" 6 | 7 | // Local 8 | #include "scc.h" 9 | #include "ec.h" 10 | #include "encrypt.h" 11 | #include "tx.h" 12 | 13 | class Alice 14 | { 15 | 16 | protected: 17 | RSA* rsa; 18 | EC_KEY* ec_key; 19 | 20 | // EC 21 | Bin *public_key; 22 | Bin *tumbler_public_key; 23 | 24 | // TX 25 | Bin* address; 26 | Bin* tumbler_address; 27 | 28 | Bin* escrow_redeem_script; 29 | Bin* escrow_funding_tx_id; 30 | Bin* escrow_lock_time; 31 | Bin* escrow_P2SH; 32 | Bin* escrow_signature; 33 | 34 | Bin* preimage_redeem_script; 35 | Bin* preimage_funding_tx_id; 36 | Bin* preimage_lock_time; 37 | Bin* preimage_sighash; 38 | Bin* preimage_P2SH; 39 | Bin* preimage_signature; 40 | 41 | Bin *y; 42 | Bin *y_sk; 43 | 44 | std::vector blinded_set; 45 | std::vector R; // Indices of real set 46 | std::vector F; // Indices of fake set 47 | 48 | std::vector real_rpk; 49 | std::vector real_keys; 50 | std::vector real_blinds; 51 | 52 | std::vector fake_r; 53 | std::vector fake_rpk; 54 | 55 | std::vector C; // Encrypted signatures : Form IV||encrypted_sig 56 | std::vector H; // Key hashes 57 | 58 | // Methods 59 | void setup(); // Creates the blinded set 60 | bool sign(Bin* tx, Bin* serial_sig); // EC Sign TX 61 | 62 | 63 | public: 64 | int rsa_len; 65 | 66 | // Constructors & Destructors 67 | Alice(Bin* y); 68 | Alice(); 69 | ~Alice(); 70 | 71 | 72 | // Sets 73 | void set_rsa(Bin* public_rsa); 74 | void set_party_address(Bin* address); 75 | void set_party_pubkey(Bin* public_key); 76 | void set_real_keys(std::vector& keys); 77 | void set_C(std::vector& c); 78 | void set_H(std::vector& h); 79 | 80 | // Gets 81 | Bin* get_pubkey(); 82 | Bin* get_y_sk(); 83 | 84 | Bin* get_preimage_redeem_script(); 85 | Bin* get_preimage_signature(); 86 | Bin* get_preimage_P2SH(); 87 | 88 | Bin* get_escrow_redeem_script(); 89 | Bin* get_escrow_funding_tx_id(); 90 | Bin* get_escrow_signature(); 91 | Bin* get_escrow_P2SH(); 92 | 93 | 94 | std::vector get_R(); 95 | std::vector get_F(); 96 | 97 | std::vector* get_blinded_set(); 98 | std::vector* get_fake_blinds(); 99 | std::vector* get_real_blinds(); 100 | 101 | // Methods 102 | 103 | bool setup_escrow_tx(); 104 | bool setup_preimage_tx(); 105 | bool verify_preimage_signature(Bin* signature); 106 | 107 | /*! 108 | * Verify that the keys decrypt the fake values 109 | * 110 | * \param[in] k Keys for fake values 111 | * 112 | * \return true on success, false on error. 113 | */ 114 | bool verify_keys(std::vector& k); 115 | 116 | /*! 117 | * Get a valid decrytion and save it in y_sk. 118 | * real_keys should be set. 119 | * 120 | * 121 | * \return true on success, false on error. 122 | */ 123 | bool get_decryption(); 124 | 125 | 126 | }; 127 | 128 | #endif 129 | -------------------------------------------------------------------------------- /POC_code/include/alice_client.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _alice_client_h 3 | #define _alice_client_h 4 | 5 | #include "assert.h" 6 | 7 | // Local 8 | #include "alice.h" 9 | #include "scc_interface.h" 10 | #include "network.h" 11 | 12 | /*! 13 | * Runs the client (Alice) for the scc protocol 14 | * to get a decryption of y and save in y_sk. 15 | * 16 | * \param[in] y An item encrypted with rsa 17 | * \param[out] y_sk A decryption of the item 18 | * 19 | * \return true on success, false on error. 20 | */ 21 | bool get_decryption(Bin* y, Bin* y_sk); 22 | 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /POC_code/include/alice_interface.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _alice_interface_h 3 | #define _alice_interface_h 4 | 5 | #include "assert.h" 6 | 7 | // Local 8 | #include "scc.h" 9 | #include "ec.h" 10 | #include "encrypt.h" 11 | 12 | 13 | #include "zmq.hpp" 14 | 15 | class Alice_Interface 16 | { 17 | protected: 18 | 19 | Bin* y; 20 | 21 | std::vector C; // Commitments 22 | std::vector H; // Key hashes 23 | 24 | 25 | std::vector R; // Indices of real set 26 | std::vector F; // Indices of fake set 27 | 28 | std::vector fake_keys; 29 | std::vector real_keys; 30 | 31 | // TX related 32 | Bin* signer_pubkey; 33 | Bin* redeem_script; 34 | Bin* funding_tx_id; 35 | Bin* serial_real_keys; 36 | Bin* tx_fulfill; 37 | 38 | bool phase_0; 39 | bool phase_1; 40 | bool phase_2; 41 | bool phase_3; 42 | bool phase_4; 43 | 44 | void init(){ 45 | phase_0 = false; 46 | phase_1 = false; 47 | phase_2 = false; 48 | phase_3 = false; 49 | phase_4 = false; 50 | 51 | signer_pubkey = NULL; 52 | redeem_script = NULL; 53 | funding_tx_id = NULL; 54 | tx_fulfill = NULL; 55 | serial_real_keys = NULL; 56 | 57 | } 58 | 59 | /* 60 | * Phase 0: 61 | * 1/ Receive: 62 | - Signer's public key 63 | */ 64 | virtual bool exchange_public_key(){return false;}; 65 | 66 | /* 67 | * Phase 1: 68 | * 1/ Generate blinded set (Init an Alice instance) 69 | * 2/ Send: 70 | - blinded_set 71 | * 3/ Receive: 72 | - C 73 | - H 74 | */ 75 | virtual bool commitment(){return false;}; 76 | 77 | /* 78 | * Phase 2: 79 | * 1/ Send: 80 | - F 81 | - fake_blinds 82 | * 3/ Receive : 83 | - Fake value keys 84 | * 3 / Verify fake keys (verify_keys()) 85 | */ 86 | virtual bool verify_fakes(){return false;}; 87 | 88 | /* 89 | * Phase 3: 90 | * 1/ Get redeem_script & fund_tx_id from python 91 | * 1.1/ Send: 92 | - Alice's EC public key 93 | - Signer's EC public key 94 | - Real Key preimages 95 | * 1.2/ Receive: 96 | - redeem_script 97 | - fund_tx_id 98 | * 2/ Send: 99 | - redeem_script 100 | - funding_TX_id 101 | - y 102 | - real_blinds 103 | * 3/ Receive: 104 | - tx_fulfill 105 | */ 106 | virtual bool verify_reals(){return false;}; 107 | 108 | 109 | /* 110 | * Start SCC protocol 111 | */ 112 | virtual bool start(){return false;}; 113 | 114 | 115 | 116 | public: 117 | 118 | /* 119 | * Phase 4: 120 | * 1/ Get real keys from python 121 | * 1.1/ Send: 122 | - tx_fulfill 123 | * 1.2/ (Opt) Send number of keys - Default if 15 124 | * 1.3/ Receive: 125 | - real keys in serial form 126 | * 1.4/ Alice deserialize keys into vector 127 | * 2/ Get a valid decryption(y_sk) of y (get_decryption()) 128 | * 3/ Return: 129 | - y_sk 130 | */ 131 | virtual Bin* get_decryption(){return NULL;}; 132 | 133 | // Constructors & Destructors 134 | 135 | virtual ~Alice_Interface(){ 136 | 137 | // delete y; 138 | 139 | if (phase_0){ 140 | delete signer_pubkey; 141 | } 142 | 143 | if (phase_1){ 144 | free_Bins(C); 145 | free_Bins(H); 146 | 147 | } 148 | 149 | if (phase_2){ 150 | free_Bins(fake_keys); 151 | } 152 | 153 | if (phase_3){ 154 | delete redeem_script; 155 | delete funding_tx_id; 156 | delete tx_fulfill; 157 | } 158 | 159 | if (phase_4){ 160 | delete serial_real_keys; 161 | free_Bins(real_keys); 162 | } 163 | 164 | 165 | }; 166 | 167 | 168 | }; 169 | 170 | #endif 171 | -------------------------------------------------------------------------------- /POC_code/include/bin.h: -------------------------------------------------------------------------------- 1 | #ifndef _bin_h 2 | #define _bin_h 3 | 4 | #include 5 | #include 6 | 7 | class Bin 8 | { 9 | public: 10 | unsigned char * data; 11 | int len; 12 | 13 | // Constructors & Destructors 14 | Bin(){}; 15 | Bin(int len_c); 16 | Bin(int len_c, unsigned char *data_c); 17 | Bin(const Bin &bin); 18 | 19 | ~Bin(); 20 | 21 | // Methods 22 | unsigned char * serialize(); 23 | void print(); 24 | 25 | bool operator== (const Bin& b) const; 26 | bool operator!= (const Bin& b); 27 | }; 28 | 29 | template 30 | struct pointer_equal 31 | { 32 | const T* to_find; 33 | 34 | bool operator()(const T* other) const 35 | { 36 | return *to_find == *other; 37 | } 38 | }; 39 | 40 | // True if item is not null and len > 1 41 | bool defined(Bin* item); 42 | void delete_bin(Bin* item); 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /POC_code/include/blind_rsa.h: -------------------------------------------------------------------------------- 1 | #ifndef _blind_rsa_h 2 | #define _blind_rsa_h 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "bin.h" 9 | #include "memory.h" 10 | #include "utility.h" 11 | 12 | /*! 13 | * Notes: 14 | * - Key path to public and private keys are in 15 | * PUBLIC & PRIVATE 16 | * - RSA keys are blinded when loaded to protect 17 | * against timing attacks 18 | */ 19 | 20 | #define PUBLIC "./keys/public_" 21 | #define PRIVATE "./keys/private_" 22 | #define EXT ".pem" 23 | 24 | //============================================================================ 25 | 26 | /*! 27 | * Generates an RSA public/private key pair of size n bits 28 | * 29 | * \param[in] bits size of RSA key in bits 30 | * \param[in] public_suffix suffix to be used in filename/path to save public key 31 | * \param[in] private_suffix suffix to be used in filename/path to save private key 32 | * \param[out] rsa RSA public key. 33 | * 34 | * \return true on sucess 35 | */ 36 | bool generate_rsa_key(int bits, char* public_suffix, char* private_suffix); 37 | 38 | 39 | /*! 40 | * Loads RSA public key of size n bits and turns on key blinding. 41 | * 42 | * \param[in] bits size of RSA key in bits 43 | * \param[in] suffix suffix to be used in path to search for key 44 | * 45 | * \return a pointer to the RSA struct 46 | */ 47 | RSA * get_public_rsa(int bits, char *suffix); 48 | 49 | /*! 50 | * Loads RSA public and private keys of size n bits and turns on key blinding. 51 | * 52 | * \param[in] bits size of RSA key in bits 53 | * \param[in] suffix suffix to be used in path to search for key 54 | * 55 | * \return a pointer to the RSA struct 56 | */ 57 | RSA * get_private_rsa(int bits, char *suffix); 58 | 59 | //============================================================================ 60 | 61 | /*! 62 | * Setup BN_Blinding structure. 63 | * 64 | * \param[in] rsa RSA public key. 65 | * 66 | * \return initalized BN_Blinding structure, NULL on error. 67 | */ 68 | BN_BLINDING * setup_blinding(RSA *rsa); 69 | 70 | /*! 71 | * Setup BN_Blinding structure using r. 72 | * 73 | * \param[in] rsa RSA public key. 74 | * \param[in] r Random value of length RSA_size(rsa) 75 | * 76 | * \return initalized BN_Blinding structure, NULL on error. 77 | */ 78 | BN_BLINDING * setup_blinding(RSA *rsa, Bin* r); 79 | 80 | 81 | /*! 82 | * Blind data and store result in unblind 83 | * 84 | * \param[in] blinding BN_Blinding initialized struct. 85 | * \param[in] msg Input data. 86 | * \param[out] blinded Output buffer. 87 | * 88 | * \return true on success, false on error. 89 | */ 90 | bool blind(BN_BLINDING * blinding, Bin* msg, Bin* blinded); 91 | 92 | /*! 93 | * Unblind data and store result in unblind 94 | * 95 | * \param[in] blinding BN_Blinding initialized struct. 96 | * \param[in] rsa RSA public key. 97 | * \param[in] msg Input data. 98 | * \param[out] unblinded Output buffer. 99 | * 100 | * \return true on success, false on error. 101 | */ 102 | bool unblind(BN_BLINDING * blinding, Bin* msg, Bin* unblinded); 103 | 104 | /*! 105 | * Unblind data and store result in reverted 106 | * 107 | * \param[in] rsa RSA public key. 108 | * \param[in] message Blinded data 109 | * \param[in] A The blind that was applied to the message 110 | * \param[out] reverted data with blind removed 111 | * 112 | * \return true on success, false on error. 113 | */ 114 | bool revert_blind(RSA *rsa, Bin* message, Bin* A, Bin* reverted); 115 | 116 | //============================================================================ 117 | 118 | /*! 119 | * Verify RSA Signature. 120 | * 121 | * \param[in] rsa RSA public key. 122 | * \param[in] msg Input data. 123 | * \param[out] sig Output buffer. 124 | * 125 | * \return true on success, false on error. 126 | */ 127 | bool verify(RSA *rsa, Bin* msg, Bin* sig); 128 | 129 | /*! 130 | * Sign Message using RSA. 131 | * 132 | * \param[in] rsa RSA public key. 133 | * \param[in] msg Input data. 134 | * \param[out] sig Output buffer. 135 | * 136 | * \return true on success, false on error. 137 | */ 138 | bool sign(RSA *rsa, Bin* msg, Bin* sig); 139 | 140 | 141 | #endif 142 | -------------------------------------------------------------------------------- /POC_code/include/bob.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _bob_h 3 | #define _bob_h 4 | 5 | #include "assert.h" 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "scc.h" 15 | #include "ec.h" 16 | #include "tx.h" 17 | #include "utility.h" 18 | #include "encrypt.h" 19 | 20 | class Bob 21 | { 22 | 23 | protected: 24 | RSA* rsa; 25 | 26 | EC_KEY *ec_server; 27 | EC_KEY *ec_bob; 28 | Bin* pubkey; 29 | 30 | bool verified; 31 | 32 | 33 | //============================================= 34 | //======= TX Related 35 | //============================================= 36 | 37 | // Receive 38 | Bin* funding_tx_id; 39 | Bin* redeem_script; 40 | 41 | Bin* tx_fulfill; 42 | 43 | std::vector real_tx_addresses; // M real TX 44 | std::vector real_tx_hashes; // Hashed transactions - Hash256 45 | 46 | // Won't be sending the fakes 47 | std::vector fake_tx; // The r's for the N fake transaction 48 | std::vector fake_tx_hashes; // H(00...00||r's) 49 | 50 | //============================================= 51 | //======= Protocol 52 | //============================================= 53 | 54 | Bin* y_sk; 55 | Bin* W; 56 | Bin* W_blind; 57 | 58 | std::vector tx_set; // Superset of real_tx_hashes and fake_tx_hashes randomly permuted 59 | std::vector R; // Indices for real tx in tx_set 60 | std::vector F; // Indices for fake tx in tx_set 61 | 62 | Bin* salt; 63 | Bin* h_r; 64 | Bin* h_f; 65 | 66 | std::vector Z; 67 | std::vector commitments; 68 | std::vector quotients; 69 | std::vector epsilons; 70 | 71 | //============================================= 72 | //======= Functions 73 | //============================================= 74 | 75 | bool blind_epsilon(); 76 | 77 | // Verification 78 | bool verify_quotients(); // Verify that the quotients validate with Z 79 | bool verify_signatures(std::vector epsilon); // Verify the fake signatures 80 | bool verify_epsilon(); 81 | // Recovery 82 | bool recover_epsilons(); // Recover epsilons from Z using redeemed epsilon 83 | Bin* recover_signature(int* index); // Recover one valid signature 84 | 85 | // TX 86 | void generate_tx_set(); // Generates the set of fake and real txs 87 | bool create_txs(); // Uses tx_offer to generate real tx's 88 | bool submit_tx(); // Submits tx_fulfill 89 | 90 | 91 | // Other 92 | bool sign(Bin* tx, Bin* serial_sig); // EC Sign TX 93 | void write_state(); 94 | 95 | 96 | public: 97 | int rsa_len; // Size of RSA modulus in bytes 98 | 99 | // Constructors & Destructors 100 | Bob(); 101 | ~Bob(); 102 | 103 | // Sets 104 | void set_funding_tx_id(Bin* id); 105 | void set_redeem_script(Bin* script); 106 | void set_party_pubkey(Bin* serial); 107 | void set_rsa(Bin* public_rsa); 108 | void set_recovered_epsilon(Bin* epsilon); 109 | 110 | // Gets 111 | std::vector get_R(); 112 | std::vector get_F(); 113 | std::vector* get_tx_set(); 114 | std::vector* get_fake_tx(); 115 | Bin* get_pubkey(); 116 | Bin* get_W(); 117 | Bin* get_tx_fulfill(); 118 | Bin* get_salt(); 119 | Bin* get_h_r(); 120 | Bin* get_h_f(); 121 | 122 | /*! 123 | * Verify data recieved from intermediary 124 | * 125 | * \param[in] zs Encrypted epsilons. 126 | * \param[in] commitment 127 | * \param[in] epsilon Random numbers used to generate encryption keys used 128 | * on the EC signatures. For Fake tx. 129 | * \param[in] quotients Vector of epsilon quotients. For Real tx. 130 | * 131 | * \return true on successful verification 132 | */ 133 | bool verify_recieved_data( 134 | std::vector zs, 135 | std::vector commitment, 136 | std::vector epsilon, 137 | std::vector quotient); 138 | 139 | 140 | // Post fulfill TX 141 | // Recovers epsiolons and a signature in the process 142 | bool post_tx(); 143 | 144 | 145 | }; 146 | 147 | #endif 148 | -------------------------------------------------------------------------------- /POC_code/include/constants.h: -------------------------------------------------------------------------------- 1 | #ifndef _constants_h 2 | #define _constants_h 3 | 4 | #include 5 | #include 6 | 7 | // SCC 8 | static const unsigned int M = 15 ; // Number of reals 9 | static const unsigned int N = 285; // Number of fakes 10 | 11 | // SCC Wrapper 12 | static const int K = 42 ; // SCC Wrapper K reals and K fakes 13 | 14 | // Length of key used in commitments 15 | static const unsigned int KEY_LEN = 16; // bytes 16 | 17 | // Hash lengths 18 | static const int HASH_512 = SHA512_DIGEST_LENGTH; // bytes 19 | static const int HASH_256 = SHA256_DIGEST_LENGTH; // bytes 20 | static const int HASH_160 = RIPEMD160_DIGEST_LENGTH; // bytes 21 | 22 | // Testnet Addresses 23 | const char TUMBLER_ADDRESS[35] = "mzaMTvKBDiYoqkHaDz3w7AmHHETHEQKUiW"; 24 | const char ALICE_ADDRESS[35] = "mvESmmYToV1dugQjNdXvA8C8ra6Q2Hyu7d"; 25 | 26 | // Only change IP - Not port 27 | const char TUMBLER_SERVER_SOCKET[21] = "tcp://localhost:5557"; 28 | const char SIGNER_SERVER_SOCKET[21] = "tcp://localhost:5558"; 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /POC_code/include/ec.h: -------------------------------------------------------------------------------- 1 | #ifndef _ec_h 2 | #define _ec_h 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include "bin.h" 10 | #include "memory.h" 11 | #include "utility.h" 12 | #include "constants.h" 13 | 14 | /*! 15 | * Generates an Elliptic Curve (EC) public/private key pair 16 | * using secp256k1 curve. 17 | * 18 | * \param[in] public_suffix suffix used in filename/path to save public key 19 | * \param[in] private_suffix suffix used in filename/path to save private key 20 | * 21 | * \return true on sucess 22 | */ 23 | bool generate_EC_key(const char* public_suffix, const char* private_suffix); 24 | 25 | 26 | /*! 27 | * Gets the EC private or public key from key_path 28 | * 29 | * \param[in] key_path Path to .pem file 30 | * \param[in] private_key Bool indicating to fetch private key or not 31 | * 32 | * \return EC_KEY * on success, NULL on failure 33 | */ 34 | EC_KEY * get_ec_key(const char *key_path, bool private_key); 35 | 36 | 37 | /*! 38 | * Gets the EC private or public key by suffix 39 | * 40 | * \param[in] suffix key suffix 41 | * \param[in] private_key Bool indicating to fetch private key or not 42 | * 43 | * \return EC_KEY * on success, NULL on failure 44 | */ 45 | EC_KEY * get_ec_key_by_suffix(const char *suffix, bool private_key); 46 | 47 | 48 | /*! 49 | * Gets the EC key using secret 50 | * 51 | * \param[in] secret Secret to use 52 | * 53 | * \return EC_KEY * on success, NULL on failure 54 | */ 55 | EC_KEY * get_key_from_secret(Bin* secret); 56 | 57 | //============================================================================ 58 | 59 | 60 | /*! 61 | * Signs a message using ECDSA 62 | * 63 | * \param[in] key EC key 64 | * \param[in] hash Message to sign 65 | * 66 | * \return ECDSA_SIG * on success, NULL on failure 67 | */ 68 | ECDSA_SIG* EC_sign(EC_KEY * eckey, Bin* hash); 69 | 70 | /*! 71 | * Verifies a ECDSA signed message 72 | * 73 | * \param[in] key EC key 74 | * \param[in] hash Message to sign 75 | * \param[in] signature ECDSA signature 76 | * 77 | * \return true when message successfully verifies, false on failure 78 | */ 79 | bool EC_verify (EC_KEY * eckey, Bin* hash, ECDSA_SIG* signature); 80 | 81 | /*! 82 | * Converts ECDSA sig to a bitcoin compatible signature -- lower s value 83 | * 84 | * \param[in/out] sig ECDSA signature 85 | * \param[in] key EC key 86 | * 87 | * \return true when message successfully verifies, false on failure 88 | */ 89 | bool convert_sig_to_standard_der(ECDSA_SIG *sig, EC_KEY *key); 90 | 91 | //============================================================================ 92 | 93 | /*! 94 | * Serializes a ECDSA_SIG 95 | * Allocates a pointer that saves the serial representation that should freed later. 96 | * 97 | * \param[in] sig ECDSA signature 98 | * \param[out] serial Bin to save result 99 | * 100 | * \return true on success 101 | */ 102 | bool serialize_ec_signature(ECDSA_SIG *sig, Bin* serial); 103 | bool serialize_ec_signature_der(ECDSA_SIG *sig, Bin* serial); 104 | 105 | /*! 106 | * Deserializes a ECDSA_SIG 107 | * 108 | * \param[in] serial Serial representation of ECDSA signature 109 | * 110 | * \return ECDSA_SIG * on success, NULL on failure 111 | */ 112 | ECDSA_SIG *deserialize_ec_signature(Bin* serial); 113 | ECDSA_SIG *deserialize_ec_signature_der(Bin* serial); 114 | 115 | //============================================================================ 116 | 117 | 118 | /*! 119 | * Serializes a ec public key. 120 | * 121 | * \param[in] key ECDSA signature 122 | * \param[out] serial Bin to save result 123 | * 124 | * \return true on success 125 | */ 126 | bool serialize_ec_publickey(EC_KEY *key, Bin* serial); 127 | 128 | 129 | /*! 130 | * Deserializes a public ec key 131 | * 132 | * \param[in] serial Serial representation of ec public key 133 | * 134 | * \return EC_KEY* on success, NULL on failure 135 | */ 136 | EC_KEY* deserialize_ec_publickey(Bin* serial); 137 | 138 | 139 | /*! 140 | * Note: Might not be needed 141 | * Serializes a ec private key. 142 | * Allocates a pointer that saves the serial representation that should freed later. 143 | * 144 | * \param[in] key EC private key 145 | * \param[out] serial Bin to save result 146 | * 147 | * \return true on success 148 | */ 149 | bool serialize_ec_privatekey(EC_KEY *key, Bin* serial); 150 | 151 | 152 | #endif 153 | -------------------------------------------------------------------------------- /POC_code/include/encrypt.h: -------------------------------------------------------------------------------- 1 | #ifndef _encrypt_h 2 | #define _encrypt_h 3 | 4 | #include "bin.h" 5 | #include "memory.h" 6 | #include "random.h" 7 | #include "constants.h" 8 | 9 | #include 10 | 11 | //============================================================================ 12 | 13 | /*! 14 | * Encryptes message 15 | * 16 | * NOTE: Default encrypt uses xor and assumes message is 512 bits 17 | * 18 | * \param[in] plaintext Input data. 19 | * \param[out] key Key used in 20 | * \param[out] ciphertext Encrypted output iv||cipher 21 | * 22 | * \return true on success 23 | */ 24 | bool encrypt(Bin* plain_text, Bin *key, Bin* cipher_text); // XOR 25 | bool encrypt_chacha(Bin* plain_text, Bin *key, Bin* cipher_text); 26 | 27 | /*! 28 | * Decryptes message 29 | * 30 | * \param[in] key Key 31 | * \param[in] ciphertext Encrypted data in form iv||cipher 32 | * \param[out] plaintext Decrypted text 33 | * 34 | * \return true on success 35 | */ 36 | bool decrypt(Bin* cipher_text, Bin *key, Bin* plain_text); // XOR 37 | bool decrypt_chacha(Bin* cipher_text, Bin *key, Bin* plain_text); 38 | 39 | //============================================================================ 40 | 41 | /*! 42 | * Encrypts/Decryptes message using xor 43 | * Assumes message and key have the same length. 44 | * 45 | * \param[in] m Message to encrypt 46 | * \param[in] k Key to use 47 | * \param[out] len Length of message and key 48 | * 49 | * \return true on success 50 | */ 51 | unsigned char * XOR_enc_dec(Bin* m, Bin* k, int len); 52 | 53 | /*! 54 | * Encrypts/Decryptes message using chacha 55 | * 56 | * \param[out] out Result stored in out 57 | * \param[in] in Message to use 58 | * \param[in] key Key to use 59 | * \param[in] iv IV to use 60 | * 61 | * \return true on success 62 | */ 63 | bool chacha(Bin* out, Bin* in, Bin* key, Bin* iv); 64 | 65 | //============================================================================ 66 | #endif 67 | -------------------------------------------------------------------------------- /POC_code/include/hash.h: -------------------------------------------------------------------------------- 1 | #ifndef _hash_h 2 | #define _hash_h 3 | 4 | #include 5 | #include 6 | 7 | #include "bin.h" 8 | #include "memory.h" 9 | #include "constants.h" 10 | 11 | /*! 12 | * Compute Full Domain Hash. 13 | * 14 | * \param[in] rsa RSA public key. 15 | * \param[in] msg Input data. 16 | * \param[in] hash Hash function. 17 | * 18 | * \return pointer to the msg hash, NULL on error. 19 | */ 20 | Bin* full_domain_hash(RSA *rsa, Bin* msg, const EVP_MD *hash); 21 | 22 | /*! 23 | * Compute SHA256(SHA256(msg)) 24 | * 25 | * \param[in] msg Input data. 26 | * 27 | * \return pointer to the msg hash, NULL on error. 28 | */ 29 | Bin* hash256(Bin* msg); 30 | 31 | /*! 32 | * Compute hmac SHA256 of msg. 33 | * 34 | * \param[in] msg Input data. 35 | * 36 | * \return pointer to the msg hash, NULL on error. 37 | */ 38 | Bin* hmac256(Bin* msg, Bin* key); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /POC_code/include/memory.h: -------------------------------------------------------------------------------- 1 | #ifndef _memory_h 2 | #define _memory_h 3 | 4 | // Local 5 | #include "bin.h" 6 | 7 | // C 8 | #include 9 | // #include 10 | #include 11 | #include 12 | 13 | // C++ 14 | #include 15 | #include 16 | 17 | // SSL 18 | #include 19 | 20 | 21 | void tfree(void *ptr); 22 | void* tmalloc(size_t size); 23 | 24 | 25 | /*! 26 | * Frees BN_BLINDING structs pointed to in the vector 27 | * 28 | * \param[int] b A vector of BN_BLINDING structs 29 | * 30 | */ 31 | void free_blinds(std::vector b); 32 | 33 | /*! 34 | * Frees Bin objects pointed to in the vector 35 | * 36 | * \param[int] bins A vector of Bin pointers 37 | * 38 | */ 39 | void free_Bins(std::vector bins); 40 | 41 | int timingsafe_memcmp(const void *b1, const void *b2, size_t len); 42 | 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /POC_code/include/network.h: -------------------------------------------------------------------------------- 1 | #ifndef _network_h 2 | #define _network_h 3 | 4 | #include 5 | 6 | #include "zmq.hpp" 7 | 8 | #include "scc.h" 9 | 10 | // Interrupt handeler 11 | static inline void s_signal_handler (int signal_value) 12 | { 13 | } 14 | 15 | static inline void s_catch_signals (void) 16 | { 17 | struct sigaction action; 18 | action.sa_handler = s_signal_handler; 19 | action.sa_flags = 0; 20 | sigemptyset (&action.sa_mask); 21 | sigaction (SIGINT, &action, NULL); 22 | sigaction (SIGTERM, &action, NULL); 23 | }; 24 | 25 | void receive(zmq::socket_t &socket, std::vector& msgs); 26 | 27 | void send(zmq::socket_t &socket, std::vector& msgs); 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /POC_code/include/random.h: -------------------------------------------------------------------------------- 1 | #ifndef _random_h 2 | #define _random_h 3 | 4 | #include "bin.h" 5 | #include "memory.h" 6 | #include "utility.h" 7 | #include 8 | 9 | /*! 10 | * Generates a random number of bits length 11 | * 12 | * \param[in] bits bits to generate 13 | * 14 | * \return a random number of n bits 15 | */ 16 | unsigned char * get_random(int bits); 17 | 18 | /*! 19 | * Generates a random number of bits length less than n 20 | * 21 | * \param[in] bits bits to generate 22 | * \param[in] n A BIGNUM 23 | * 24 | * \return a random number of n bits 25 | */ 26 | unsigned char * get_random(int bits, BIGNUM *n); 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /POC_code/include/scc.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _scc_h 3 | #define _scc_h 4 | 5 | #include "utility.h" 6 | #include "blind_rsa.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | //============================================================================ 15 | 16 | /*! 17 | * Applies blinds to message 18 | * 19 | * \param[in] message A message to blind 20 | * \param[in] blinds A vector of initilized BN_BLINDING structs. 21 | * \param[out] blinded A vector that will hold the blinded m's. 22 | * 23 | * \return true on success, false on error. 24 | */ 25 | bool apply_blinds(Bin* message, std::vector &blinds, std::vector &blinded); 26 | 27 | /*! 28 | * Removes the blinds from the messages in blinded 29 | * 30 | * \param[out] blinded A vector that holds blinded messages. 31 | * \param[in] m_len Length of the blinded message. 32 | * \param[in] blinds A vector of initilized BN_BLINDING structs. 33 | * \param[out] blinded A vector that will hold the unblinded messages. 34 | * 35 | * \return true on success, false on error. 36 | */ 37 | bool remove_blinds(std::vector &blinded, int len, std::vector &blinds, 38 | std::vector &unblinded); 39 | 40 | /*! 41 | * Generate blinding factors 42 | * 43 | * \param[in] rsa RSA public key. 44 | * \param[in] n Number of blinds to generate 45 | * \param[out] blinds A vector to store the initilized BN_BLINDING structs. 46 | * 47 | * \return true on success, false on error. 48 | */ 49 | bool create_blinds(RSA * rsa, int n, std::vector &blinds); 50 | 51 | //============================================================================ 52 | 53 | 54 | /*! 55 | * Finds the indices of the elements of the "what" vector in "in" vector 56 | * 57 | * \param[in] in The main vector 58 | * \param[in] what The subvector to find the indices for 59 | * \param[out] indices A vector of indices for what 60 | * 61 | * \return true on success, false on error. 62 | */ 63 | bool find_indices(std::vector &in, std::vector &what, std::vector &indices); 64 | 65 | //============================================================================ 66 | 67 | /*! 68 | * Serializes a vector of size n with items of len 69 | * 70 | * \param[out] serial Serial representation 71 | * \param[in] vec Vector to store results in 72 | * \param[in] n Number of items 73 | * \param[in] len Length of items 74 | * 75 | * \return true on success, false on error. 76 | */ 77 | bool serialize_vector(Bin* serial, std::vector& vec, int n, int len); 78 | 79 | 80 | /*! 81 | * Deserializes to a vector of size n with items of len 82 | * 83 | * \param[in] serial Serial representation 84 | * \param[out] vec Vector to store results in 85 | * \param[in] n Number of items 86 | * \param[in] len Length of items 87 | * 88 | * \return true on success, false on error. 89 | */ 90 | bool deserialize_vector(Bin* serial, std::vector& vec, int n, int len); 91 | 92 | 93 | /*! 94 | * Serializes a integer vector of size n 95 | * 96 | * \param[out] serial Serial representation 97 | * \param[in] vec Vector to store results in 98 | * \param[in] n Number of items 99 | * 100 | * \return true on success, false on error. 101 | */ 102 | bool serialize_int_vector(Bin* serial, std::vector& vec, int n); 103 | 104 | 105 | /*! 106 | * Deserializes to an integer vector of size N 107 | * 108 | * \param[in] serial Serial representation 109 | * \param[out] vec Vector to store results in 110 | * \param[in] n Number of items 111 | * 112 | * \return true on success, false on error. 113 | */ 114 | bool deserialize_int_vector(Bin* serial, std::vector& vec, int n); 115 | 116 | //============================================================================ 117 | #endif 118 | -------------------------------------------------------------------------------- /POC_code/include/scc_interface.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _scc_interface_h 3 | #define _scc_interface_h 4 | 5 | #include "assert.h" 6 | 7 | // Local 8 | #include "scc.h" 9 | #include "ec.h" 10 | #include "encrypt.h" 11 | #include "constants.h" 12 | #include "tx.h" 13 | 14 | class SCC_Interface 15 | { 16 | protected: 17 | 18 | Bin* y; 19 | 20 | std::vector C; // Commitments 21 | std::vector H; // Key hashes 22 | 23 | 24 | std::vector R; // Indices of real set 25 | std::vector F; // Indices of fake set 26 | 27 | std::vector fake_keys; 28 | std::vector real_keys; 29 | 30 | // TX related 31 | Bin* signer_pubkey; 32 | Bin* alice_pubkey; 33 | 34 | Bin* redeem_script; 35 | Bin* funding_tx_id; 36 | Bin* serial_real_keys; 37 | Bin* tx_fulfill; 38 | 39 | bool phase_0; 40 | bool phase_1; 41 | bool phase_2; 42 | bool phase_4; 43 | 44 | void init(){ 45 | phase_0 = false; 46 | phase_1 = false; 47 | phase_2 = false; 48 | phase_4 = false; 49 | 50 | } 51 | 52 | /* 53 | * Phase 0: 54 | * Alice: 55 | * 1/ Receive: 56 | * - Signer's public key 57 | * 58 | * Signer: 59 | * 1/ Send: 60 | * - public key 61 | */ 62 | virtual bool exchange_public_key(){return false;}; 63 | 64 | /* 65 | * Phase 1: 66 | * Alice 67 | * 1/ Generate blinded set (Init an Alice instance) 68 | * 2/ Send: 69 | * - blinded_set 70 | * 3/ Receive: 71 | * - C 72 | * - H 73 | * 74 | * Signer: 75 | * 1/ Receive: 76 | * - blinded_set 77 | * 2/ Sign blinded set & encrypts sigs (sign_blinded_set()) 78 | * 3/ Send: 79 | * - C 80 | * - H 81 | */ 82 | virtual bool commitment(){return false;}; 83 | 84 | /* 85 | * Phase 2: 86 | * Alice: 87 | * 1/ Send: 88 | * - F 89 | * - R 90 | * - fake_blinds 91 | * 2/ Receive : 92 | * - Fake value keys 93 | * 3 / Verify fake keys (verify_keys()) 94 | * 95 | * Signer: 96 | * 1/ Receive: 97 | * - F 98 | * - R 99 | * - fake_blinds 100 | * 2/ Verify fake values (verify_fakes()) 101 | * 3/ Send: 102 | * - Fake value keys 103 | */ 104 | virtual bool verify_fakes(){return false;}; 105 | 106 | /* 107 | * Phase 3: 108 | * Alice: 109 | * 1/ Get redeem_script & fund_tx_id from python 110 | * 1.1/ Send: 111 | * - Alice's EC public key 112 | * - Signer's EC public key 113 | * - Real Key preimages 114 | * 1.2/ Receive: 115 | * - redeem_script 116 | * - fund_tx_id 117 | * 2/ Send: 118 | * - redeem_script 119 | * - funding_TX_id 120 | * - y 121 | * - real_blinds 122 | * 3/ Receive: 123 | * - tx_fulfill 124 | * 125 | * Signer: 126 | * 1/ Receive: 127 | * - redeem_script 128 | * - funding_TX_id 129 | * - y 130 | * - real_blinds 131 | * 2/ Verify real values (verify_reals()) 132 | * 3/ Get TX fulfill from python 133 | * 3.1/ Send: 134 | * - redeem_script 135 | * - address 136 | * - funding_TX_id 137 | * 3.2/ Receive: 138 | * - raw_tx 139 | * - sig_hash 140 | * 3.3/ Send: 141 | * - real Keys 142 | * - signed SigHash 143 | * - Raw_TX 144 | * - redeem_script 145 | * 3.4/ Receive: - tx_fulfill 146 | * 4/ Send: 147 | * - tx_fulfill 148 | */ 149 | virtual bool verify_reals(){return false;}; 150 | 151 | 152 | /* 153 | * Phase 4: 154 | * Alice only: 155 | * 1/ Get real keys from python 156 | * 1.1/ Send: 157 | * -tx_fulfill 158 | * 1.2/ (Opt) Send number of keys - Default if 15 159 | * 1.3/ Receive: 160 | * -real keys in serial form 161 | * 1.4/ Alice deserialize keys into vector 162 | * 2/ Get a valid decryption(y_sk) of y (get_decryption()) 163 | * 3/ Return: 164 | * - y_sk 165 | */ 166 | virtual bool get_decryption_from_tx(){return false;}; 167 | 168 | 169 | 170 | public: 171 | 172 | 173 | virtual Bin* get_decryption(){return NULL;}; 174 | 175 | /* 176 | * Start SCC protocol 177 | */ 178 | virtual bool start(){return false;}; 179 | 180 | // Constructors & Destructors 181 | 182 | virtual ~SCC_Interface(){ 183 | 184 | if (phase_0){ 185 | delete signer_pubkey; 186 | } 187 | 188 | if (phase_1){ 189 | free_Bins(C); 190 | free_Bins(H); 191 | 192 | } 193 | 194 | if (phase_2){ 195 | free_Bins(fake_keys); 196 | } 197 | 198 | 199 | if (phase_4){ 200 | free_Bins(real_keys); 201 | } 202 | 203 | 204 | }; 205 | 206 | 207 | }; 208 | 209 | #endif 210 | -------------------------------------------------------------------------------- /POC_code/include/scc_wrapper_interface.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _scc_wrapper_interface_h 3 | #define _scc_wrapper_interface_h 4 | 5 | #include "assert.h" 6 | 7 | // Local 8 | #include "scc.h" 9 | 10 | class SCC_Wrapper_Interface 11 | { 12 | protected: 13 | std::vector C; // Commitments 14 | std::vector Z; // Key hashes 15 | 16 | std::vector fake; 17 | std::vector quotients; 18 | std::vector fake_epsilons; 19 | 20 | 21 | std::vector R; // Indices of real set 22 | std::vector F; // Indices of fake set 23 | 24 | // TX related 25 | Bin* payer_pubkey; 26 | Bin* redeemer_pubkey; 27 | 28 | Bin* redeem_script; 29 | Bin* funding_tx_id; 30 | 31 | 32 | /* 33 | * Phase 0: 34 | * Bob: 35 | * 1/ Send: 36 | * - public key 37 | * 2/ Receive: 38 | * - Tumbler's RSA public key 39 | * - Tumbler's EC public key 40 | * - redeem_script 41 | * - funding_tx_id 42 | * 43 | * Tumbler: 44 | * 1/ Receive: 45 | * - Bob's EC public key 46 | * 2/ Create TX_offer 47 | * 3/ Send: 48 | * - public key 49 | * - redeem_script 50 | * - funding_tx_id 51 | */ 52 | virtual bool exchange(){return false;}; 53 | 54 | /* 55 | * Phase 1: 56 | * Bob: 57 | * 1/ Send: 58 | * - tx_set 59 | * 2/ Receive: 60 | * - C 61 | * - Z 62 | * 63 | * Tumbler: 64 | * 1/ Receive: 65 | * - tx_set 66 | * 2/ Sign tx_set set 67 | * 3/ Send: 68 | * - C 69 | * - Z 70 | */ 71 | virtual bool commitment(){return false;}; 72 | 73 | /* 74 | * Phase 2: 75 | * Bob: 76 | * 1/ Send: 77 | * - R 78 | * - F 79 | * - fake_tx's 80 | * 2/ Receive : 81 | * - fake epsilon's 82 | * - quotients 83 | * 3 / Verify fake epsilon's 84 | * 4 / Verify quotients 85 | * 86 | * Tumbler: 87 | * 1/ Receive: 88 | * - R 89 | * - F 90 | * - fake_tx's 91 | * 2/ Verify fake tx's 92 | * 3/ Send: 93 | * - fake epsilon's 94 | * - quotients 95 | */ 96 | virtual bool verify(){return false;}; 97 | 98 | /* 99 | * Phase 3: 100 | * Bob: 101 | * 1/ Send Alice encrypted epsiolon -- Z_0 102 | * 2/ Recieve decryption -- epsiolon_0 103 | * 3/ Recover epsiolons 104 | * 4/ Recover valid signature 105 | * 5/ post tx 106 | */ 107 | virtual bool post(){return false;}; 108 | 109 | 110 | 111 | public: 112 | 113 | /* 114 | * Start SCC Wrapper protocol 115 | */ 116 | virtual bool start(){return false;}; 117 | 118 | 119 | }; 120 | 121 | #endif 122 | -------------------------------------------------------------------------------- /POC_code/include/signer.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _signer_h 3 | #define _signer_h 4 | 5 | #include "assert.h" 6 | #include 7 | 8 | // Local 9 | #include "scc.h" 10 | #include "ec.h" 11 | #include "encrypt.h" 12 | #include "tx.h" 13 | 14 | 15 | class Signer 16 | { 17 | 18 | protected: 19 | RSA* rsa; 20 | Bin* rsa_pub; 21 | 22 | // EC 23 | EC_KEY *key; 24 | Bin *public_key; 25 | 26 | // Flags 27 | bool signed_values; 28 | bool verified_fakes; 29 | bool verified_real; 30 | 31 | std::vector blinded_set; 32 | std::vector R; // Indices of real set 33 | std::vector F; // Indices of fake set 34 | 35 | std::vector C; // Encrypted signatures : Form IV||encrypted_sig 36 | std::vector K; // Encryption keys 37 | std::vector H; // Key hashes 38 | 39 | 40 | // TX 41 | Bin* tumbler_address; 42 | 43 | Bin* escrow_redeem_script; 44 | Bin* escrow_funding_tx_id; 45 | Bin* escrow_party_signature; 46 | 47 | Bin* preimage_P2SH; 48 | Bin* preimage_redeem_script; 49 | Bin* preimage_funding_tx_id; 50 | Bin* preimage_party_signature; 51 | Bin* escrow_preimage_signature; 52 | 53 | Bin* fund_preimage_tx_fulfill; 54 | Bin* preimage_tx_fulfill; 55 | Bin* escrow_tx_fulfill; 56 | 57 | 58 | std::vector real_keys; // Keys used on real set 59 | std::vector fake_keys; // Keys used on fake set 60 | 61 | void write_state(); 62 | bool ec_sign(Bin* serial_sig, Bin* sig_hash); 63 | 64 | public: 65 | int rsa_len; 66 | 67 | // Constructors & Destructors 68 | Signer(); 69 | ~Signer(); 70 | 71 | // Gets 72 | Bin* get_rsa(); 73 | Bin* get_pubkey(); 74 | Bin* get_escrow_preimage_signature(); 75 | std::vector* get_C(); 76 | std::vector* get_H(); 77 | std::vector* get_fake_keys(); 78 | std::vector* get_real_keys(); 79 | 80 | // Sets 81 | void set_preimage_redeem_script(Bin* redeem_script); 82 | void set_preimage_signature(Bin* signature); 83 | void set_preimage_P2SH(Bin* address); 84 | 85 | void set_escrow_redeem_script(Bin* redeem_script); 86 | void set_escrow_funding_tx_id(Bin* funding_tx_id); 87 | void set_escrow_signature(Bin* signature); 88 | 89 | // Methods 90 | 91 | bool spend_escrow_tx(); 92 | bool spend_preimage_tx(); 93 | bool spend_escrow_preimage_tx(); 94 | bool sign_escrow_preimage_tx(); 95 | 96 | /*! 97 | * Signs blinded set using rsa private key 98 | * 99 | * \param[in] blinded_set set to sign 100 | * 101 | * \return true on success, false on error. 102 | */ 103 | bool sign_blinded_set(std::vector blinded_set); 104 | 105 | /*! 106 | * Verify values claimed to be fake 107 | * 108 | * \param[in] randoms The randoms used in fakes 109 | * \param[in] newF Indices of fake items 110 | * 111 | * \return true on success, false on error. 112 | */ 113 | bool verify_fakes(std::vector randoms, std::vector newF); 114 | 115 | /*! 116 | * Verify that real values all unblind to one value, y. 117 | * 118 | * \param[in] y The value the reals should ublind to 119 | * \param[in] blinds The blinds applied to y 120 | * \param[in] newR Indices of Real items 121 | * 122 | * \return true on success, false on error. 123 | */ 124 | bool verify_reals(Bin* y, std::vectorblinds, std::vector newR); 125 | 126 | 127 | }; 128 | 129 | #endif 130 | -------------------------------------------------------------------------------- /POC_code/include/signer_interface.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _signer_interface_h 3 | #define _signer_interface_h 4 | 5 | #include "assert.h" 6 | 7 | // Local 8 | #include "scc.h" 9 | #include "ec.h" 10 | #include "encrypt.h" 11 | 12 | class Signer_Interface 13 | { 14 | 15 | protected: 16 | 17 | std::vector blinded_set; 18 | 19 | // Blinds 20 | std::vector fake_blinds; 21 | std::vector real_blinds; 22 | 23 | std::vector R; // Indices of real set 24 | std::vector F; // Indices of fake set 25 | 26 | 27 | // Encrypted episolon 28 | Bin* y; 29 | 30 | 31 | // TX related 32 | Bin* redeem_script; 33 | Bin* funding_tx_id; 34 | Bin* sig_hash; 35 | Bin* raw_tx; 36 | Bin* tx_fulfill; 37 | 38 | bool phase_0; 39 | bool phase_1; 40 | bool phase_2; 41 | bool phase_3; 42 | 43 | /* 44 | * Phase 0: 45 | * 1/ Send: 46 | - public key 47 | */ 48 | virtual bool exchange_public_key(); 49 | 50 | /* 51 | * Phase 1: 52 | * 1/ Receive: 53 | - blinded_set 54 | * 2/ Sign blinded set & encrypts sigs (sign_blinded_set()) 55 | * 3/ Send: 56 | - C 57 | - H 58 | */ 59 | virtual bool commitment(); 60 | 61 | 62 | /* 63 | * Phase 2: 64 | * 1/ Receive: 65 | - F 66 | - fake_blinds 67 | * 2/ Verify fake values (verify_fakes()) 68 | * 3/ Send: 69 | - Fake value keys 70 | */ 71 | virtual bool verify_fakes(); 72 | 73 | 74 | 75 | /* 76 | * Phase 3: 77 | * 1/ Receive: 78 | - redeem_script 79 | - funding_TX_id 80 | - y 81 | - real_blinds 82 | * 2/ Verify real values (verify_reals()) 83 | * 3/ Get TX fulfill from python 84 | * 3.1/ Send: 85 | - redeem_script 86 | - address 87 | - funding_TX_id 88 | * 3.2/ Receive: 89 | - raw_tx 90 | - sig_hash 91 | * 3.3/ Send: 92 | - real Keys 93 | - signed SigHash 94 | - Raw_TX 95 | - redeem_script 96 | * 3.4/ Receive: - tx_fulfill 97 | * 4/ Send: 98 | - tx_fulfill 99 | */ 100 | virtual bool verify_reals(); 101 | 102 | 103 | 104 | public: 105 | /* 106 | * Start SCC protocol 107 | */ 108 | virtual bool start(); 109 | 110 | ~Signer_Interface(){ 111 | 112 | if (phase_1){ 113 | free_Bins(blinded_set); 114 | } 115 | 116 | if (phase_2){ 117 | free_Bins(fake_blinds); 118 | } 119 | 120 | if (phase_3){ 121 | 122 | free_Bins(real_blinds); 123 | 124 | delete y; 125 | delete raw_tx; 126 | delete sig_hash; 127 | delete redeem_script; 128 | delete funding_tx_id; 129 | delete tx_fulfill; 130 | } 131 | 132 | 133 | }; 134 | 135 | }; 136 | 137 | #endif 138 | -------------------------------------------------------------------------------- /POC_code/include/timer.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _timer_h 3 | #define _timer_h 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | typedef boost::chrono::process_real_cpu_clock::time_point time_point; 11 | typedef boost::chrono::duration double_second; 12 | typedef boost::chrono::process_real_cpu_clock real_time; 13 | 14 | class Timer 15 | { 16 | 17 | private: 18 | 19 | FILE *file; 20 | char* description; 21 | 22 | // Clock Time 23 | clock_t c_start; 24 | clock_t c_end; 25 | double c_duration; 26 | 27 | // Real Time 28 | time_point r_start; 29 | time_point r_end; 30 | double_second r_duration; 31 | 32 | public: 33 | Timer(); 34 | Timer(char *name); 35 | ~Timer(); 36 | 37 | void start(); 38 | void end(); 39 | void print(); 40 | 41 | // In seconds 42 | double get_clock_time(); 43 | double get_real_time(); 44 | 45 | }; 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /POC_code/include/tumbler.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _tumbler_h 3 | #define _tumbler_h 4 | 5 | #include "assert.h" 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "scc.h" 14 | #include "ec.h" 15 | #include "tx.h" 16 | #include "utility.h" 17 | #include "encrypt.h" 18 | 19 | #include "zmq.hpp" 20 | 21 | class Tumbler 22 | { 23 | 24 | protected: 25 | RSA* rsa; 26 | EC_KEY *ec; 27 | bool verified; 28 | 29 | Bin* rsa_pub; 30 | Bin* ec_pubkey; 31 | Bin* bob_ec_pubkey; 32 | Bin* address; 33 | 34 | Bin* p2sh_address; 35 | Bin* lock_time; 36 | Bin* redeem_script; 37 | Bin* funding_tx_id; 38 | 39 | std::vector tx; // TX set -- should be of size numN + numM 40 | 41 | std::vector epsilon; // N bit randoms 42 | std::vector C; // Commitment -- Encrypted signatures 43 | std::vector Z; // RSA encryptions of the epsilons 44 | std::vector quotients; // epsilon_(i+1) / epsilon_i mod rsa->n 45 | 46 | std::vector R; // Indices for real tx in tx_set 47 | std::vector F; // Indices for fake tx in tx_set 48 | std::vector epsilon_f; // epsilons for fakes 49 | 50 | Bin* salt; 51 | Bin* h_r; 52 | Bin* h_f; 53 | 54 | bool create_quotients(); 55 | bool create_refund_tx(); 56 | 57 | public: 58 | int rsa_len; // Size of RSA modulus in bytes 59 | 60 | bool create_offer_tx(); 61 | 62 | // Constructors & Destructors 63 | Tumbler(); 64 | ~Tumbler(); 65 | 66 | // Gets 67 | Bin* get_redeem_script(); 68 | Bin* get_funding_tx_id(); 69 | 70 | std::vector* get_Z(); 71 | std::vector* get_commitment(); 72 | std::vector* get_epsilons(); 73 | std::vector* get_quotients(); 74 | 75 | Bin* get_pubkey(); 76 | Bin* get_rsa(); 77 | 78 | // Sets 79 | void set_R(std::vector r); 80 | void set_F(std::vector f); 81 | void set_h_r(Bin* h); 82 | void set_h_f(Bin* h); 83 | void set_salt(Bin* r); 84 | void set_party_pubkey(Bin* public_key); 85 | 86 | /*! 87 | * Sign transactions using ECDSA 88 | * 89 | * \param[in] tx_set Bitcoin transactions to sign 90 | * 91 | * \return true on success 92 | */ 93 | bool sign_transactions(std::vector& tx_set); 94 | 95 | /*! 96 | * Verify that the recieved randoms hash to the fake transactions. 97 | * Needs R & F to be set before being called. 98 | * 99 | * \param[in] r Encrypted epsilons. 100 | * 101 | * \return true on success 102 | */ 103 | bool verify_fake_tx(std::vector& r); 104 | 105 | }; 106 | 107 | #endif 108 | -------------------------------------------------------------------------------- /POC_code/include/tx.h: -------------------------------------------------------------------------------- 1 | #ifndef _tx_h 2 | #define _tx_h 3 | 4 | 5 | #include "utility.h" 6 | #include "network.h" 7 | #include "constants.h" 8 | #include "hash.h" 9 | #include "scc.h" 10 | 11 | /*! 12 | * Gets the signature hash of a transaction spending from a P2SH address 13 | * Funds go to specified address 14 | * 15 | * \param[in] redeem_script P2SH redeem script 16 | * \param[in] address Output address 17 | * \param[in] funding_tx_id TXid of P2SH funding TX 18 | * \param[out] raw_tx TX in raw byte form 19 | * \param[out] sig_hash Signature Hash 20 | * 21 | * \return true on success 22 | */ 23 | bool get_tx(Bin* redeem_script, Bin* address, Bin* funding_tx_id, Bin* raw_tx, Bin* sig_hash, bool preimage=false); 24 | 25 | /*! 26 | * Gets the signature hash of a transaction spending from a P2SH address 27 | * Funds go to the returned random address (different address for each call) 28 | * 29 | * \param[in] redeem_script P2SH redeem script 30 | * \param[in] funding_tx_id TXid of P2SH funding TX 31 | * \param[out] sig_hash Signature Hash 32 | * \param[out] address Output address 33 | * 34 | * \return true on success 35 | */ 36 | bool get_tx_with_address(Bin* redeem_script, Bin* funding_tx_id, Bin* sig_hash, Bin* address); 37 | 38 | /*! 39 | * Gets the txid of the raw trandaction as a hex string 40 | * 41 | * \param[in] tx raw tx in byte form 42 | * \param[out] tx_id hex form big endian 43 | * 44 | * \return true on success 45 | */ 46 | bool get_id_from_tx(Bin* tx, Bin* tx_id); 47 | 48 | /*! 49 | * Gets the signature hash of a transaction refunding from a P2SH address 50 | * Funds go to specified address 51 | * 52 | * \param[in] redeem_script P2SH redeem script 53 | * \param[in] address Output address 54 | * \param[in] funding_tx_id TXid of P2SH funding TX 55 | * \param[in] lock_time The block the tx is locked to 56 | * \param[out] raw_tx TX in raw byte form 57 | * \param[out] sig_hash Signature Hash 58 | * 59 | * \return true on success 60 | */ 61 | bool get_refund_tx(Bin* redeem_script, Bin* address, Bin* funding_tx_id, Bin* lock_time, Bin* raw_tx, Bin* sig_hash); 62 | 63 | /*! 64 | * Creates a transaction that fulfills refunds the funds in the P2SH 65 | * Returns the complete raw tx that can be posted 66 | * 67 | * \param[in] signature EC signature of funder 68 | * \param[in] raw_tx TX in raw byte form 69 | * \param[in] redeem_script P2SH redeem script 70 | * \param[out] refund_tx Complete TX in raw byte form 71 | * 72 | * \return true on success 73 | */ 74 | bool send_refund_tx(Bin* signature, Bin* raw_tx, Bin* redeem_script, Bin* refund_tx); 75 | 76 | /*! 77 | * Sets up and funds a preimage P2SH address 78 | * 79 | * \param[in] real_hashes The images vector 80 | * \param[in] funder_pubkey EC public key of funder 81 | * \param[in] redeemer_pubkey EC public key of redeemer 82 | * \param[out] redeem_script P2SH redeem script 83 | * \param[out] funding_tx_id TXid of P2SH funding TX 84 | * 85 | * \return true on success 86 | */ 87 | bool setup_preimage(std::vector& real_hashes, Bin* funder_pubkey, Bin* redeemer_pubkey, Bin* redeem_script, Bin* funding_tx_id, Bin* p2sh_address, Bin* lock_time); 88 | 89 | /*! 90 | * Creates a transaction that fulfills that preimage P2SH conditions 91 | * Returns the complete raw tx that can be posted 92 | * 93 | * \param[in] real_keys The preimage vector 94 | * \param[in] redeem_script P2SH redeem script 95 | * \param[in] raw_tx TX in raw byte form 96 | * \param[in] redeemer_sig EC signature of redeemer 97 | * \param[out] tx_fulfill Complete TX in raw byte form 98 | * 99 | * \return true on success 100 | */ 101 | bool spend_preimage(std::vector& real_keys, Bin* redeem_script, Bin*raw_tx, Bin* redeemer_sig, Bin* tx_fulfill); 102 | 103 | /*! 104 | * Extracts the keys (images) in serial form from the raw tx that 105 | * fulfills the conditions of the preimage P2SH 106 | * 107 | * \param[in] tx_fulfill Complete TX in raw byte form 108 | * \param[out] serial_real_keys Keys in serial form 109 | * 110 | * \return true on success 111 | */ 112 | bool get_keys_from_tx(Bin* tx_fulfill, Bin* serial_real_keys); 113 | 114 | /*! 115 | * Sets up and funds a 2-of-2 escrow P2SH address 116 | * 117 | * \param[in] payer_pubkey EC public key of funder 118 | * \param[in] redeemer_pubkey EC public key of redeemer 119 | * \param[out] redeem_script P2SH redeem script 120 | * \param[out] funding_tx_id TXid of P2SH funding TX 121 | * 122 | * \return true on success 123 | */ 124 | bool setup_escrow(Bin* payer_pubkey, Bin* redeemer_pubkey, Bin* redeem_script, Bin* funding_tx_id, Bin* p2sh_address, Bin* lock_time); 125 | 126 | 127 | /*! 128 | * Creates a transaction that fulfills that escrow P2SH conditions 129 | * Returns the complete raw tx that can be posted 130 | * 131 | * \param[in] raw_tx TX in raw byte form 132 | * \param[in] payer_sig EC signature of redeemer 133 | * \param[in] redeemer_sig EC signature of redeemer 134 | * \param[in] address Output address 135 | * \param[in] redeem_script P2SH redeem script 136 | * \param[in] funding_tx_id TXid of P2SH funding TX 137 | * \param[out] tx_fulfill Complete TX in raw byte form 138 | * 139 | * \return true on success 140 | */ 141 | bool spend_escrow(Bin* payer_sig, Bin* redeemer_sig, Bin* address, Bin* redeem_script, Bin* funding_tx_id, Bin* tx_fulfill); 142 | 143 | #endif 144 | -------------------------------------------------------------------------------- /POC_code/include/utility.h: -------------------------------------------------------------------------------- 1 | #ifndef _utility_h 2 | #define _utility_h 3 | 4 | #include "bin.h" 5 | #include "memory.h" 6 | #include 7 | #include 8 | 9 | 10 | // Need this to print/access blinding struct values 11 | struct bn_blinding_st 12 | { 13 | BIGNUM *A; 14 | BIGNUM *Ai; 15 | BIGNUM *e; 16 | BIGNUM *mod; /* just a reference */ 17 | }; 18 | 19 | //============================================================================ 20 | 21 | /*! 22 | * Serialize a BigNum f to a buffer of fixed length. 23 | * 24 | * \param[in] f Bignum to be serialized. 25 | * \param[out] bin Binary string which f is serialized into. 26 | * \param[in] bin_len Length of bin. 27 | * 28 | * \return Size of bytes serialized. 29 | */ 30 | int BNToBin(BIGNUM *f, unsigned char * bin, int bin_len); 31 | 32 | //============================================================================ 33 | 34 | /*! 35 | * Prints bignum data in hex form 36 | * 37 | * \param[in] bn a BIGNUM 38 | * 39 | */ 40 | void print_BN(BIGNUM* bn); 41 | 42 | /*! 43 | * Prints input data in hex form 44 | * 45 | * \param[in] len Length of data 46 | * \param[in] data The string to print out in hex format 47 | * 48 | */ 49 | void print_hex(int len, unsigned char *data); 50 | 51 | /*! 52 | * Prints out all the key/strings in the vector. 53 | * 54 | * \param[int] m A vector of strings (keys) 55 | * 56 | */ 57 | void print_keys(std::vector m); 58 | 59 | /*! 60 | * Prints out R and R inverse from the blinding struct 61 | * 62 | * \param[int] blind An initilizes blinding struct 63 | * 64 | */ 65 | void print_blind(BN_BLINDING* blind); 66 | 67 | /*! 68 | * Prints out R and R inverse for all the blinds in the vector. 69 | * 70 | * \param[int] blinds A vector of blinds (BN_BLINDING) 71 | * 72 | */ 73 | void print_blinds(std::vector blinds); 74 | 75 | //============================================================================ 76 | 77 | /*! 78 | * Returns a pointer to the hex form of the input 79 | * 80 | * \param[in] msg in bin format 81 | * 82 | */ 83 | char * get_hex_str(Bin* msg); 84 | 85 | /*! 86 | * Returns a pointer to the reversed hex form of the input 87 | * 88 | * \param[in] msg in bin format 89 | * 90 | */ 91 | char * get_hex_str_rev(Bin* msg); 92 | 93 | //============================================================================ 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /POC_code/include/zmq_addon.hpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUSEC/TumbleBit/55829dc75c36554e710e723dedb510d62a57ca0c/POC_code/include/zmq_addon.hpp -------------------------------------------------------------------------------- /POC_code/keys/EC_private_alice.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIH1MIGuBgcqhkjOPQIBMIGiAgEBMCwGByqGSM49AQECIQD///////////////// 3 | ///////////////////+///8LzAGBAEABAEHBEEEeb5mfvncu6xVoGKVzocLBwKb 4 | /NstzijZWfKBWxb4F5hIOtp3JqPEZV2k+/wOEQio/Re0SKaFVBmcR9CP+xDUuAIh 5 | AP////////////////////66rtzmr0igO7/SXozQNkFBAgEBA0IABNG3DYhQqf9W 6 | ntpgRfW/D5pCihic80EQwmeCJ/F+abE68CFqNIVJ49QMZfL612dlBt6dPR7nSN5p 7 | knmoP7rNsTE= 8 | -----END PUBLIC KEY----- 9 | -----BEGIN PRIVATE KEY----- 10 | MIIBIwIBADCBrgYHKoZIzj0CATCBogIBATAsBgcqhkjOPQEBAiEA//////////// 11 | /////////////////////////v///C8wBgQBAAQBBwRBBHm+Zn753LusVaBilc6H 12 | CwcCm/zbLc4o2VnygVsW+BeYSDradyajxGVdpPv8DhEIqP0XtEimhVQZnEfQj/sQ 13 | 1LgCIQD////////////////////+uq7c5q9IoDu/0l6M0DZBQQIBAQRtMGsCAQEE 14 | IFDdeOkhwgaUQBWxjUmHhFJM3G98WbxImh6NHZBaK/ljoUQDQgAE0bcNiFCp/1ae 15 | 2mBF9b8PmkKKGJzzQRDCZ4In8X5psTrwIWo0hUnj1Axl8vrXZ2UG3p09HudI3mmS 16 | eag/us2xMQ== 17 | -----END PRIVATE KEY----- 18 | -------------------------------------------------------------------------------- /POC_code/keys/EC_private_bob.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIH1MIGuBgcqhkjOPQIBMIGiAgEBMCwGByqGSM49AQECIQD///////////////// 3 | ///////////////////+///8LzAGBAEABAEHBEEEeb5mfvncu6xVoGKVzocLBwKb 4 | /NstzijZWfKBWxb4F5hIOtp3JqPEZV2k+/wOEQio/Re0SKaFVBmcR9CP+xDUuAIh 5 | AP////////////////////66rtzmr0igO7/SXozQNkFBAgEBA0IABF97mocn5eka 6 | P9CPOQHcwBv/QIHTvCE4+kq/A2niVl4ESrF6FhY2Xuw0fb4mKzbVF4gk5ZwJ8Zz/ 7 | jMHJgfD9em4= 8 | -----END PUBLIC KEY----- 9 | -----BEGIN PRIVATE KEY----- 10 | MIIBIwIBADCBrgYHKoZIzj0CATCBogIBATAsBgcqhkjOPQEBAiEA//////////// 11 | /////////////////////////v///C8wBgQBAAQBBwRBBHm+Zn753LusVaBilc6H 12 | CwcCm/zbLc4o2VnygVsW+BeYSDradyajxGVdpPv8DhEIqP0XtEimhVQZnEfQj/sQ 13 | 1LgCIQD////////////////////+uq7c5q9IoDu/0l6M0DZBQQIBAQRtMGsCAQEE 14 | IC3RpJa+GRNJfORBtyokJiWmPtmbzBiZGY0wGzCTSygJoUQDQgAEX3uahyfl6Ro/ 15 | 0I85AdzAG/9AgdO8ITj6Sr8DaeJWXgRKsXoWFjZe7DR9viYrNtUXiCTlnAnxnP+M 16 | wcmB8P16bg== 17 | -----END PRIVATE KEY----- 18 | -------------------------------------------------------------------------------- /POC_code/keys/EC_private_test.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIH1MIGuBgcqhkjOPQIBMIGiAgEBMCwGByqGSM49AQECIQD///////////////// 3 | ///////////////////+///8LzAGBAEABAEHBEEEeb5mfvncu6xVoGKVzocLBwKb 4 | /NstzijZWfKBWxb4F5hIOtp3JqPEZV2k+/wOEQio/Re0SKaFVBmcR9CP+xDUuAIh 5 | AP////////////////////66rtzmr0igO7/SXozQNkFBAgEBA0IABPVeKpIv2bpE 6 | kmwvjkfonSlwkWrsAGp/aXZNXwhXUJhMnPzZTZu8CQKmwkmZmSJEyaFUBY+jAoWP 7 | S9vv/kz/yZ8= 8 | -----END PUBLIC KEY----- 9 | -----BEGIN PRIVATE KEY----- 10 | MIIBIwIBADCBrgYHKoZIzj0CATCBogIBATAsBgcqhkjOPQEBAiEA//////////// 11 | /////////////////////////v///C8wBgQBAAQBBwRBBHm+Zn753LusVaBilc6H 12 | CwcCm/zbLc4o2VnygVsW+BeYSDradyajxGVdpPv8DhEIqP0XtEimhVQZnEfQj/sQ 13 | 1LgCIQD////////////////////+uq7c5q9IoDu/0l6M0DZBQQIBAQRtMGsCAQEE 14 | IOOSqRpYEZmIsE87hdHZdejCJ1NBoN2b3f1euvrSnccAoUQDQgAE9V4qki/ZukSS 15 | bC+OR+idKXCRauwAan9pdk1fCFdQmEyc/NlNm7wJAqbCSZmZIkTJoVQFj6MChY9L 16 | 2+/+TP/Jnw== 17 | -----END PRIVATE KEY----- 18 | -------------------------------------------------------------------------------- /POC_code/keys/EC_private_tumbler.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIH1MIGuBgcqhkjOPQIBMIGiAgEBMCwGByqGSM49AQECIQD///////////////// 3 | ///////////////////+///8LzAGBAEABAEHBEEEeb5mfvncu6xVoGKVzocLBwKb 4 | /NstzijZWfKBWxb4F5hIOtp3JqPEZV2k+/wOEQio/Re0SKaFVBmcR9CP+xDUuAIh 5 | AP////////////////////66rtzmr0igO7/SXozQNkFBAgEBA0IABGQNimsBwJ8A 6 | jG5e8QyeueXTZTIBXVGlzNANAuFnzD5lrO10djaHOm0/m5ddrJKTPr8mQlmW9g0t 7 | BGhGeYZD/8w= 8 | -----END PUBLIC KEY----- 9 | -----BEGIN PRIVATE KEY----- 10 | MIIBIwIBADCBrgYHKoZIzj0CATCBogIBATAsBgcqhkjOPQEBAiEA//////////// 11 | /////////////////////////v///C8wBgQBAAQBBwRBBHm+Zn753LusVaBilc6H 12 | CwcCm/zbLc4o2VnygVsW+BeYSDradyajxGVdpPv8DhEIqP0XtEimhVQZnEfQj/sQ 13 | 1LgCIQD////////////////////+uq7c5q9IoDu/0l6M0DZBQQIBAQRtMGsCAQEE 14 | ILgAn20g75DhWYwbgdQy16KiFam09aXRpLvRW6gMXWahoUQDQgAEZA2KawHAnwCM 15 | bl7xDJ655dNlMgFdUaXM0A0C4WfMPmWs7XR2Noc6bT+bl12skpM+vyZCWZb2DS0E 16 | aEZ5hkP/zA== 17 | -----END PRIVATE KEY----- 18 | -------------------------------------------------------------------------------- /POC_code/keys/EC_private_tumbler_main.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIH1MIGuBgcqhkjOPQIBMIGiAgEBMCwGByqGSM49AQECIQD///////////////// 3 | ///////////////////+///8LzAGBAEABAEHBEEEeb5mfvncu6xVoGKVzocLBwKb 4 | /NstzijZWfKBWxb4F5hIOtp3JqPEZV2k+/wOEQio/Re0SKaFVBmcR9CP+xDUuAIh 5 | AP////////////////////66rtzmr0igO7/SXozQNkFBAgEBA0IABBGotNrxDMR9 6 | aF6aZHm51lGH19zDD4jfBvpeG7Nl7/PqyHbILbFx3ylUGh5wZoOG1dRyhfpvpTnf 7 | mask4YdNHdY= 8 | -----END PUBLIC KEY----- 9 | -----BEGIN PRIVATE KEY----- 10 | MIIBIwIBADCBrgYHKoZIzj0CATCBogIBATAsBgcqhkjOPQEBAiEA//////////// 11 | /////////////////////////v///C8wBgQBAAQBBwRBBHm+Zn753LusVaBilc6H 12 | CwcCm/zbLc4o2VnygVsW+BeYSDradyajxGVdpPv8DhEIqP0XtEimhVQZnEfQj/sQ 13 | 1LgCIQD////////////////////+uq7c5q9IoDu/0l6M0DZBQQIBAQRtMGsCAQEE 14 | IH+JhHr1DZ9UFibPPGRGvzJVxH1n0nq5+U/d4pnBLTDDoUQDQgAEEai02vEMxH1o 15 | XppkebnWUYfX3MMPiN8G+l4bs2Xv8+rIdsgtsXHfKVQaHnBmg4bV1HKF+m+lOd+Z 16 | qyThh00d1g== 17 | -----END PRIVATE KEY----- 18 | -------------------------------------------------------------------------------- /POC_code/keys/EC_public_alice.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIH1MIGuBgcqhkjOPQIBMIGiAgEBMCwGByqGSM49AQECIQD///////////////// 3 | ///////////////////+///8LzAGBAEABAEHBEEEeb5mfvncu6xVoGKVzocLBwKb 4 | /NstzijZWfKBWxb4F5hIOtp3JqPEZV2k+/wOEQio/Re0SKaFVBmcR9CP+xDUuAIh 5 | AP////////////////////66rtzmr0igO7/SXozQNkFBAgEBA0IABNG3DYhQqf9W 6 | ntpgRfW/D5pCihic80EQwmeCJ/F+abE68CFqNIVJ49QMZfL612dlBt6dPR7nSN5p 7 | knmoP7rNsTE= 8 | -----END PUBLIC KEY----- 9 | -------------------------------------------------------------------------------- /POC_code/keys/EC_public_bob.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIH1MIGuBgcqhkjOPQIBMIGiAgEBMCwGByqGSM49AQECIQD///////////////// 3 | ///////////////////+///8LzAGBAEABAEHBEEEeb5mfvncu6xVoGKVzocLBwKb 4 | /NstzijZWfKBWxb4F5hIOtp3JqPEZV2k+/wOEQio/Re0SKaFVBmcR9CP+xDUuAIh 5 | AP////////////////////66rtzmr0igO7/SXozQNkFBAgEBA0IABF97mocn5eka 6 | P9CPOQHcwBv/QIHTvCE4+kq/A2niVl4ESrF6FhY2Xuw0fb4mKzbVF4gk5ZwJ8Zz/ 7 | jMHJgfD9em4= 8 | -----END PUBLIC KEY----- 9 | -------------------------------------------------------------------------------- /POC_code/keys/EC_public_test.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIH1MIGuBgcqhkjOPQIBMIGiAgEBMCwGByqGSM49AQECIQD///////////////// 3 | ///////////////////+///8LzAGBAEABAEHBEEEeb5mfvncu6xVoGKVzocLBwKb 4 | /NstzijZWfKBWxb4F5hIOtp3JqPEZV2k+/wOEQio/Re0SKaFVBmcR9CP+xDUuAIh 5 | AP////////////////////66rtzmr0igO7/SXozQNkFBAgEBA0IABPVeKpIv2bpE 6 | kmwvjkfonSlwkWrsAGp/aXZNXwhXUJhMnPzZTZu8CQKmwkmZmSJEyaFUBY+jAoWP 7 | S9vv/kz/yZ8= 8 | -----END PUBLIC KEY----- 9 | -------------------------------------------------------------------------------- /POC_code/keys/EC_public_tumbler.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIH1MIGuBgcqhkjOPQIBMIGiAgEBMCwGByqGSM49AQECIQD///////////////// 3 | ///////////////////+///8LzAGBAEABAEHBEEEeb5mfvncu6xVoGKVzocLBwKb 4 | /NstzijZWfKBWxb4F5hIOtp3JqPEZV2k+/wOEQio/Re0SKaFVBmcR9CP+xDUuAIh 5 | AP////////////////////66rtzmr0igO7/SXozQNkFBAgEBA0IABGQNimsBwJ8A 6 | jG5e8QyeueXTZTIBXVGlzNANAuFnzD5lrO10djaHOm0/m5ddrJKTPr8mQlmW9g0t 7 | BGhGeYZD/8w= 8 | -----END PUBLIC KEY----- 9 | -------------------------------------------------------------------------------- /POC_code/keys/EC_public_tumbler_main.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIH1MIGuBgcqhkjOPQIBMIGiAgEBMCwGByqGSM49AQECIQD///////////////// 3 | ///////////////////+///8LzAGBAEABAEHBEEEeb5mfvncu6xVoGKVzocLBwKb 4 | /NstzijZWfKBWxb4F5hIOtp3JqPEZV2k+/wOEQio/Re0SKaFVBmcR9CP+xDUuAIh 5 | AP////////////////////66rtzmr0igO7/SXozQNkFBAgEBA0IABBGotNrxDMR9 6 | aF6aZHm51lGH19zDD4jfBvpeG7Nl7/PqyHbILbFx3ylUGh5wZoOG1dRyhfpvpTnf 7 | mask4YdNHdY= 8 | -----END PUBLIC KEY----- 9 | -------------------------------------------------------------------------------- /POC_code/keys/private_2048_test.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEArqDcYDN5G30tEr090DpwS7ZhASNTI/tHfZ/0qCHjjpQzKS5o 3 | cpgY6LGt9dqXqmSb7J32Uu0kbp9yd3BU7rwdiin8n4ke18GnquCy+3LuomkSvvDH 4 | PoI4gfSa7pfaFwoeb/95PA+1Z2WuIn6n7CICpzjNtMhrQUoUxKAxK/w2NjwjpXH+ 5 | ypK6CyvkBOg+Jm5vLxUQPiwZWdemznIMmAT6rR1bMqnl5B17HQkRYlXrzVtWXH24 6 | dpWi8h3SXynNPa1je1XcUrY04VVj+tSh0zbF/+FGvOu+3614sSgyymp/Y5GkdPhI 7 | cL/OamXtI7Dm1mf8JKQrS3YZiNWv8NzuC0cPDQIDAQABAoIBAQCqQXua75RsEKcZ 8 | VhgmJFPH/ZCmI2Kz+hHBkWpfYmsSX7thszVyRIhElrcctHqaTm0XTQsT3tFeaWaY 9 | vJSSDiZexoDeqjm/8bcfCuR186BmCDuWnfokH6IoUeucI8EmJV93ooT44ffjT2dv 10 | ijz+JEqh7ufgEmc/yJJnAifu0n+ob21EDGMROxhObzlvdCgAzKxTwFS7602eoFJE 11 | qHrzJW2MlCoIAsCV5HvzN+jLvNFBUrclQkhcSPZTw8lVVij+7ygFmmk9LdiQDbx8 12 | 0prjXAHWdzDqdQ6dogSRP5wOFmkWSpsfnotJJ8qr4qQU1ahhgI4uoueZrbxMCSq0 13 | 47W6H0WhAoGBANzUx40tmV1p37T56csZqkMJqEODctr5fNpHwIzMLPqBfa2BumTd 14 | Y09vL/ven+9dFGpYcCdSndVmo6O5GqERpHLgaVJjZehVq+rZP+tPyv1knBbIN4vD 15 | Y8KJqpEx8u5TwqTFlftXfKunhw1Ued5cHl66OaEKGGFmzpc0/93X5L77AoGBAMpw 16 | aCGvULKWbw6UWMY8usK5pbCy5xqhbbz1/83UHJbfC2EJs181cFjn4PwdWJkuRBFC 17 | rVL3FvqnvR5cmRE6VFzTdECBUIhMjup1BCCMwKs0cWvzZdwsqfy4SQtooq4VBK4q 18 | 8CbtBJ5ve1pIVTSNe6ZD6tHPLNkTSz6QJpzB/uuXAoGAIhffrxYpJVjhJsmmpKqT 19 | tMHa7oFuzAvUkMafHZ2wHAS96Hms00GywWLDH7mhK41NR5XbytZgc7/i57X+PHvC 20 | zdGDsSqTYylG330m9ydciX5s8r96g+NolXI3mS8C+HSKCnJO030QTFgS66XtIr1K 21 | GwnZN9mdJfx/TKzsC833DN0CgYANyS/eM2EseEAh3wpYnaQeRKQ670P7tUiS2LHN 22 | 44b64z+UISP89NesxkW1BY6WB+eMwVyqTLdc5HVljurBmJZMJ/4/sk64qXYGE2fv 23 | i4ZHYm/i6RVjtArzcd1PkJWbg0TpU3U9QWDSJUdiM5DR3lywSum/1fr44W57WTe3 24 | 7yIcCwKBgQCtRICk3b7HJE+L9Mq7KCUUXC6WyCMIp7n6j84H6TjqeWTil4lT/pZK 25 | lLlVEDWxIH9mtXgpVnj4RLvuk2jSC4TI/JecsQtqPi1raaZhkfiGu73HaesW2u6q 26 | zWtAq24EHkmMPyxjtP1Gv2FXD3ksbC/1tZnKb4tFSmc8hBOKD3PbjQ== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /POC_code/keys/private_2048_tumbler.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpQIBAAKCAQEAtYjVMf/U6qibELdSoo9L6K1RKId9Bc0h6epIWIxfc5P4bXqV 3 | y65ISzKdF9hu86LGUoGONyqmJV12Bs6AL59bTf6nBjuaz02T66jZ7+7PLRJEdcFf 4 | JgK5PeG1d9RVVUXiNvZ+nA6X0TnTfWyNKPKEskXrAj56UfHefWucoW6nQrPeY+7i 5 | dEw8BZ/WusFDJq5eFY7qKT2Pp2424huDPuQqfSBWMsQIvG26U9umYfBYEScwgOgp 6 | thXAqrEAvQW52QBFtLDG1gx+IXMRkur5b68c7ZNcFYCuXd8XbPfDFQxfG4wkJ0Ms 7 | AAtqR8nbfRG1x+/edhnAob5vsl+4jDjhp3E07QIDAQABAoIBAQCux1FMVF4wl6jE 8 | TVx4OrMBEG2FMf2DKl8ukWyaJHx6EMsszMuQUPo1vENXhAA+/kcnhKjiIGPascND 9 | BmqQb0M/MqCo9ZY1ZSG30NgTk79QS7gyD72GITUsiTVoa7zE3wXPmT+JDNvKi3w9 10 | 09eMxwJPidWcUX7/inmGE6e4HYtYQan8sJydB+rOm2TFers7JrOdinP6eGliCFwH 11 | DF/khUUtMX6QFlXS/qWxBVwMRPUTx5SaoMgFRxCxLQeVKmpIdo3aU1pYCB/gZ0Et 12 | Nm5b1496T+BJ/u/kvNwPX3o7FczRG6FFyPzmOBM/zhIOkjG4vuhbOFiiq0Q/tFlH 13 | 0C5+ezdZAoGBANt3XD+uxmrmX1++gQ2GuyjBnT2v1bRG9apVX549P5F3/n0izElw 14 | IdPZ8ynBGdj6AS12Hcqk3k0Tt5Xmb16oTUK3W5zXSmyBWl5Y0zG1TemptJjA1a9r 15 | C+sNimJ6NFXER1oBzygG5FEbSUhtzCoTGsi8M06mGLd86s2uxjFmKY+vAoGBANPA 16 | /wnVYldv3f/hE+0wOUGpJxWbuEEvmWEl/xPhI+Wmc3zLsJvn6WvvOKkWnzMg/yR9 17 | G67IUiXcfbwzPLPu9h/Q+5hSDNOripACOiNcx+X8BSZNWATVMC1J6v9V8dlCdjA2 18 | C8aRJaG9MTNIgmTmUb3IPlcxgLTL/e68JAbQ+nAjAoGBAKYk8HNNjuyyxpUnFW/2 19 | BY5PNQjUKsa1yZlP1HlpCMzJuKFnTJx0BUfqgcmkZDr82RNfjiIxOhHD0YHr13gj 20 | lYniYbqUycTnEFDIkenZxcgVL6FMqviH45fowlDXDvO3CgU7xWYaAZLdQ1dPt/ZK 21 | TEaXI4hw+dk++ksH+wa+vswFAoGANsNh8fQak8xdmJBoK95d4GpTrlXwaANcYnCG 22 | MGj4dKsAkRTInvlyN7TNbYVpNLri4Vftsd0iyaHlbqe9mjdBtebBOpp1sMRbeHTq 23 | /jw/gm4UEtzL16we4oeMW+6pNmvmzv8bOoZNOjAIql+lQV0DZNaFsN0fkSJ0kKpd 24 | ktm2+wsCgYEAqoDuBlQGr8HY4Ln/xbRIXrmY0V5lndYcnfUqxzlmTAYPynxQ407q 25 | I02jEFuj9HJKS71zZmNYaRBEv4P5f+RfpOXemGURjG6mcOSm12297ZU625nhHlKc 26 | ZnYqxwLMgJCWrDkN8pulG5K3SCgFNI4TURmu3qJ35fNoC11T0ycJX20= 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /POC_code/keys/public_2048_test.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PUBLIC KEY----- 2 | MIIBCgKCAQEArqDcYDN5G30tEr090DpwS7ZhASNTI/tHfZ/0qCHjjpQzKS5ocpgY 3 | 6LGt9dqXqmSb7J32Uu0kbp9yd3BU7rwdiin8n4ke18GnquCy+3LuomkSvvDHPoI4 4 | gfSa7pfaFwoeb/95PA+1Z2WuIn6n7CICpzjNtMhrQUoUxKAxK/w2NjwjpXH+ypK6 5 | CyvkBOg+Jm5vLxUQPiwZWdemznIMmAT6rR1bMqnl5B17HQkRYlXrzVtWXH24dpWi 6 | 8h3SXynNPa1je1XcUrY04VVj+tSh0zbF/+FGvOu+3614sSgyymp/Y5GkdPhIcL/O 7 | amXtI7Dm1mf8JKQrS3YZiNWv8NzuC0cPDQIDAQAB 8 | -----END RSA PUBLIC KEY----- 9 | -------------------------------------------------------------------------------- /POC_code/keys/public_2048_tumbler.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PUBLIC KEY----- 2 | MIIBCgKCAQEAtYjVMf/U6qibELdSoo9L6K1RKId9Bc0h6epIWIxfc5P4bXqVy65I 3 | SzKdF9hu86LGUoGONyqmJV12Bs6AL59bTf6nBjuaz02T66jZ7+7PLRJEdcFfJgK5 4 | PeG1d9RVVUXiNvZ+nA6X0TnTfWyNKPKEskXrAj56UfHefWucoW6nQrPeY+7idEw8 5 | BZ/WusFDJq5eFY7qKT2Pp2424huDPuQqfSBWMsQIvG26U9umYfBYEScwgOgpthXA 6 | qrEAvQW52QBFtLDG1gx+IXMRkur5b68c7ZNcFYCuXd8XbPfDFQxfG4wkJ0MsAAtq 7 | R8nbfRG1x+/edhnAob5vsl+4jDjhp3E07QIDAQAB 8 | -----END RSA PUBLIC KEY----- 9 | -------------------------------------------------------------------------------- /POC_code/makefile: -------------------------------------------------------------------------------- 1 | # Adapted from https://web.stanford.edu/class/cs107/guide_make.html 2 | 3 | ########################################################################### 4 | ## Build Flags & Library Dependencies 5 | ########################################################################### 6 | 7 | CC = g++ 8 | CFLAGS = -g -Wall 9 | # CFLAGS += -Dmemcmp=timingsafe_memcmp 10 | LDFLAGS = -lssl -lcrypto -lboost_unit_test_framework -lboost_chrono -lboost_system -lzmq 11 | INCLUDE = -I ./include 12 | 13 | # The CFLAGS variable sets compile flags for gcc: 14 | # -g compile with debug information 15 | # -Wall give verbose compiler warnings 16 | 17 | # Add path to libressl if OSX or Ubuntu-(if compiled from source) 18 | UNAME_S := $(shell uname -s) 19 | ifeq ($(UNAME_S),Darwin) 20 | LDFLAGS += -L/usr/local/opt/libressl/lib 21 | INCLUDE += -I/usr/local/opt/libressl/include 22 | endif 23 | 24 | ifeq ($(UNAME_S),Linux) 25 | LDFLAGS += -L/usr/local/lib 26 | endif 27 | 28 | .PHONY: clean BIN_DIR 29 | 30 | ########################################################################### 31 | ## Global Variables 32 | ########################################################################### 33 | 34 | BIN = bin/ 35 | SOURCE = src/ 36 | LIB = ./bin/ 37 | TEST = ./src/test/ 38 | CRYPTO = $(SOURCE)crypto/ 39 | UTILITY = $(SOURCE)utility/ 40 | 41 | all: BIN_DIR bob_client tumbler_server signer_server 42 | 43 | # Create Bin Directory 44 | BIN_DIR: 45 | test -d bin || mkdir bin 46 | 47 | ########################################################################### 48 | ## UTILITY 49 | ########################################################################### 50 | 51 | UTILITY_SOURCES = /utility.cpp /bin.cpp /network.cpp /timer.cpp /memory.cpp 52 | UTILITY_OBJECTS = $(subst /,$(BIN),$(UTILITY_SOURCES:.cpp=.o)) 53 | UTILITY_TEST_TARGETS = utility_test bin_test 54 | DEPEND = $(UTILITY_OBJECTS) 55 | 56 | # Compile Objects 57 | $(UTILITY_OBJECTS): 58 | $(CC) $(CFLAGS) -c $(subst $(BIN),$(UTILITY), $(@:.o=.cpp)) -o $@ $(INCLUDE) 59 | 60 | 61 | # Compile Targets 62 | $(UTILITY_TEST_TARGETS) : $(DEPEND) 63 | $(CC) $(CFLAGS) -o $(BIN)$@ $(TEST)$@.cpp $^ $(INCLUDE) $(LDFLAGS) 64 | 65 | ########################################################################### 66 | ## Crypto 67 | ########################################################################### 68 | 69 | CRYPTO_SOURCES = /blind_rsa.cpp /ec.cpp /encrypt.cpp /hash.cpp /random.cpp 70 | CRYPTO_OBJECTS = $(subst /,$(BIN),$(CRYPTO_SOURCES:.cpp=.o)) 71 | CRYPTO_TEST_TARGETS = blind_rsa_test ec_test encrypt_test hash_test 72 | DEPEND += $(CRYPTO_OBJECTS) 73 | 74 | # Compile Objects 75 | $(CRYPTO_OBJECTS): 76 | $(CC) $(CFLAGS) -c $(subst $(BIN),$(CRYPTO), $(@:.o=.cpp)) -o $@ $(INCLUDE) 77 | 78 | 79 | # Compile Targets 80 | $(CRYPTO_TEST_TARGETS) : $(DEPEND) 81 | $(CC) $(CFLAGS) -o $(BIN)$@ $(TEST)$@.cpp $^ $(INCLUDE) $(LDFLAGS) 82 | 83 | ########################################################################### 84 | ## Protocol Dependencies 85 | ########################################################################### 86 | 87 | SCC_SOURCES = /scc.cpp /tx.cpp 88 | SCC_OBJECTS = $(subst /,$(BIN),$(SCC_SOURCES:.cpp=.o)) 89 | SCC_TEST_TARGETS = scc_test 90 | DEPEND += $(SCC_OBJECTS) 91 | 92 | # Compile Objects 93 | $(SCC_OBJECTS): 94 | $(CC) $(CFLAGS) -c $(subst $(BIN),$(SOURCE), $(@:.o=.cpp)) -o $@ $(INCLUDE) 95 | 96 | 97 | # Compile Targets 98 | $(SCC_TEST_TARGETS) : $(DEPEND) 99 | $(CC) $(CFLAGS) -o $(BIN)$@ $(TEST)$@.cpp $^ $(INCLUDE) $(LDFLAGS) 100 | 101 | ########################################################################### 102 | ## Client -- Alice & Bob (same machine) 103 | ########################################################################### 104 | 105 | CLIENT_SOURCES = /alice.cpp /alice_client.cpp /bob.cpp 106 | CLIENT_OBJECTS = $(subst /,$(BIN),$(CLIENT_SOURCES:.cpp=.o)) 107 | CLIENT_TARGETS = bob_client alice_client_test 108 | 109 | # Compile Objects 110 | $(CLIENT_OBJECTS): 111 | $(CC) $(CFLAGS) -c $(subst $(BIN),$(SOURCE), $(@:.o=.cpp)) -o $@ $(INCLUDE) 112 | 113 | 114 | # Compile Targets 115 | $(CLIENT_TARGETS) : $(DEPEND) $(CLIENT_OBJECTS) 116 | $(CC) $(CFLAGS) -o $(BIN)$@ $(SOURCE)$@.cpp $^ $(INCLUDE) $(LDFLAGS) 117 | 118 | ########################################################################### 119 | ## Server -- The Tumbler System 120 | ########################################################################### 121 | 122 | SERVER_SOURCES = /tumbler.cpp /signer.cpp 123 | SERVER_OBJECTS = $(subst /,$(BIN),$(SERVER_SOURCES:.cpp=.o)) 124 | SERVER_TARGETS = tumbler_server signer_server 125 | 126 | # Compile Objects 127 | $(SERVER_OBJECTS): 128 | $(CC) $(CFLAGS) -c $(subst $(BIN),$(SOURCE), $(@:.o=.cpp)) -o $@ $(INCLUDE) 129 | 130 | 131 | # Compile Targets 132 | $(SERVER_TARGETS) :$(DEPEND) $(SERVER_OBJECTS) 133 | $(CC) $(CFLAGS) -o $(BIN)$@ $(SOURCE)$@.cpp $^ $(INCLUDE) $(LDFLAGS) 134 | 135 | ########################################################################### 136 | ## Other Targets 137 | ########################################################################### 138 | 139 | clean: 140 | rm -rf $(BIN)* 141 | -------------------------------------------------------------------------------- /POC_code/python/tx_server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from tx import * 3 | 4 | # stdlib 5 | import time 6 | import signal 7 | import hashlib 8 | import binascii 9 | 10 | # 3rd Party 11 | import zmq 12 | from bitcoin import SelectParams 13 | 14 | ########################################################################### 15 | ## SETTINGS 16 | ########################################################################### 17 | 18 | 19 | LOCK_TIME = 6 20 | N_HASHES = 15 21 | HASH_LEN = 20 22 | TUMBLER_ADDRESS = "mzaMTvKBDiYoqkHaDz3w7AmHHETHEQKUiWs" 23 | AMOUNT = 0.001 24 | FEE = 0.0006 25 | MINE_FEE = 0.0001 26 | 27 | AMOUNT_FUND = AMOUNT + FEE 28 | 29 | tx_o = TX(test=True) 30 | # tx_o = TX() 31 | 32 | ########################################################################### 33 | ## HELPERS 34 | ########################################################################### 35 | 36 | 37 | def error(n, e): 38 | return "Wrong number of arguments" + \ 39 | "got %d expected %d" % (n, e) 40 | 41 | 42 | def get_keys_from_tx(socket, msg): 43 | e = 2 44 | if len(msg) != e: 45 | socket.send(error(len(msg), e)) 46 | return 47 | 48 | keys = tx_o.get_keys_from_tx(msg[1], N_HASHES) 49 | serial_keys = tx_o.serialize_list(keys) 50 | 51 | socket.send(serial_keys) 52 | return 53 | 54 | ########################################################################### 55 | ## PREIMAGE 56 | ########################################################################### 57 | 58 | 59 | def setup_preimage(socket, msg): 60 | e = 4 61 | if len(msg) != e: 62 | socket.send(error(len(msg), e)) 63 | return 64 | 65 | hashes = tx_o.get_hashes_from_serial(msg[3], N_HASHES, 66 | HASH_LEN) 67 | 68 | amount2 = AMOUNT + FEE 69 | result = tx_o.setup_preimage(msg[1], msg[2], hashes, amount2, 70 | LOCK_TIME) 71 | reply = [result[0], result[1], result[2], result[3]] 72 | 73 | socket.send_multipart(reply) 74 | return 75 | 76 | 77 | def spend_preimage(socket, msg): 78 | e = 5 79 | if len(msg) != e: 80 | socket.send(error(len(msg), e)) 81 | return 82 | 83 | keys = tx_o.get_keys_from_serial(msg[1]) 84 | tx = tx_o.spend_preimage(keys, msg[2], msg[3], msg[4]) 85 | 86 | socket.send(tx) 87 | return 88 | 89 | ########################################################################### 90 | ## ESCROW 91 | ########################################################################### 92 | 93 | 94 | def setup_escrow(socket, msg): 95 | e = 3 96 | if len(msg) != e: 97 | socket.send(error(len(msg), e)) 98 | return 99 | 100 | result = tx_o.setup_escrow(msg[1], msg[2], AMOUNT, LOCK_TIME) 101 | reply = [result[0], result[1], result[2], result[3]] 102 | 103 | socket.send_multipart(reply) 104 | return 105 | 106 | 107 | def spend_escrow(socket, msg): 108 | e = 5 109 | if len(msg) != e: 110 | socket.send(error(len(msg), e)) 111 | return 112 | 113 | tx = tx_o.spend_escrow(msg[1], msg[2], msg[3], msg[4]) 114 | socket.send(tx) 115 | return 116 | 117 | 118 | def spend_escrow_with_address(socket, msg): 119 | e = 6 120 | if len(msg) != e: 121 | socket.send(error(len(msg), e)) 122 | return 123 | 124 | # 1 - payer_sig, 2 - redeemer_sig 125 | # 3 - address, 4 - redeem_script 126 | # 5 - funding_tx_id 127 | 128 | temp_tx, _ = tx_o.get_tx(msg[4], msg[3], 129 | AMOUNT - MINE_FEE, msg[5]) 130 | tx = tx_o.spend_escrow(msg[1], msg[2], temp_tx, msg[4]) 131 | 132 | socket.send(tx) 133 | return 134 | 135 | ########################################################################### 136 | ## GET TX 137 | ########################################################################### 138 | 139 | 140 | def get_tx_with_address(socket, msg): 141 | e = 3 142 | if len(msg) != e: 143 | socket.send(error(len(msg), e)) 144 | return 145 | 146 | address = get_btc_address()[0] 147 | _, sighash = tx_o.get_tx(msg[1], address, 148 | AMOUNT - MINE_FEE, msg[2]) 149 | reply = [sighash, address] 150 | 151 | socket.send_multipart(reply) 152 | return 153 | 154 | 155 | def get_tx_with_vout(socket, msg): 156 | e = 5 157 | if len(msg) != e: 158 | socket.send(error(len(msg), e)) 159 | return 160 | 161 | _, sighash = tx_o.get_tx(msg[1], msg[2], 162 | AMOUNT - MINE_FEE, msg[3], vout=msg[4]) 163 | 164 | reply = [sighash, address] 165 | socket.send_multipart(reply) 166 | return 167 | 168 | 169 | def get_tx(socket, msg): 170 | e = 5 171 | if len(msg) != e: 172 | socket.send(error(len(msg), e)) 173 | return 174 | 175 | if msg[4] == "preimage": 176 | amount = AMOUNT - (2 * MINE_FEE) 177 | print "PREIAMGE" 178 | else: 179 | amount = AMOUNT - MINE_FEE 180 | 181 | tx, sighash = tx_o.get_tx(msg[1], msg[2], 182 | amount, msg[3]) 183 | 184 | reply = [tx, sighash] 185 | socket.send_multipart(reply) 186 | 187 | ########################################################################### 188 | ## REFUND 189 | ########################################################################### 190 | 191 | 192 | def get_tx_refund(socket, msg): 193 | if len(msg) != 5: 194 | error = "Wrong number of arguments to %s, " + \ 195 | "got %d expected 4" % (msg[0], len(msg)) 196 | socket.send(error) 197 | 198 | print "Lock time is %d" % int(msg[4]) 199 | 200 | # Check to see if it's preimage tx 201 | if len(msg[1]) > 300: 202 | amount = AMOUNT - (2 * MINE_FEE) 203 | else: 204 | amount = AMOUNT - MINE_FEE 205 | 206 | tx, sighash = tx_o.get_tx(msg[1], msg[2], 207 | amount, msg[3], 208 | lock_time=int(msg[4])) 209 | 210 | reply = [tx, sighash] 211 | socket.send_multipart(reply) 212 | return 213 | 214 | 215 | def get_refund_tx_with_vout(socket, msg): 216 | e = 6 217 | if len(msg) != e: 218 | socket.send(error(len(msg), e)) 219 | return 220 | 221 | tx, sighash = tx_o.get_tx(msg[1], msg[2], 222 | amount, msg[3], 223 | lock_time=int(msg[4]), vout=msg[5]) 224 | 225 | reply = [tx, sighash] 226 | socket.send_multipart(reply) 227 | return 228 | 229 | 230 | def send_refund_tx(socket, msg): 231 | e = 4 232 | if len(msg) != e: 233 | socket.send(error(len(msg), e)) 234 | return 235 | 236 | tx = tx_o.refund_tx(msg[1], msg[2], msg[3]) 237 | socket.send(tx) 238 | return 239 | 240 | ########################################################################### 241 | ## MAIN 242 | ########################################################################### 243 | 244 | options = { 245 | "setup_preimage": setup_preimage, 246 | "spend_preimage": spend_preimage, 247 | "setup_escrow": setup_escrow, 248 | "spend_escrow": spend_escrow, 249 | "spend_escrow_with_address": spend_escrow_with_address, 250 | "get_tx_with_address": get_tx_with_address, 251 | "get_tx": get_tx, 252 | "get_tx_refund": get_tx_refund, 253 | "send_refund_tx": send_refund_tx, 254 | "get_keys_from_tx": get_keys_from_tx, 255 | "get_refund_tx_with_vout": get_refund_tx_with_vout, 256 | "get_tx_with_vout": get_tx_with_vout 257 | } 258 | 259 | 260 | def main(): 261 | 262 | SelectParams('testnet') 263 | 264 | context = zmq.Context() 265 | socket = context.socket(zmq.REP) 266 | socket.bind("ipc:///tmp/TumbleBit_tx") 267 | 268 | try: 269 | while True: 270 | 271 | msg = socket.recv_multipart() 272 | # print "Received message %s" % msg 273 | if msg[0] in options: 274 | print "Entering -> %s" % msg[0] 275 | options[msg[0]](socket, msg) 276 | print "Exiting -> %s" % msg[0] 277 | else: 278 | # printf 279 | socket.send(b"METHOD NOT AVAILABLE") 280 | except KeyboardInterrupt: 281 | print "Interrupt received. Stoping ...." 282 | finally: 283 | # Clean up 284 | socket.close() 285 | context.term() 286 | 287 | 288 | if __name__ == "__main__": 289 | main() 290 | -------------------------------------------------------------------------------- /POC_code/python/tx_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # TODO: Add unit tests 3 | 4 | # stdlib 5 | import hashlib 6 | import binascii 7 | 8 | # 3rd part 9 | import zmq 10 | from bitcoin import SelectParams 11 | from bitcoin.core.key import CECKey 12 | 13 | # Local 14 | from tx import TX 15 | 16 | 17 | ############################################################################### 18 | ## Helpers for Testing 19 | ############################################################################### 20 | 21 | 22 | def ripemd160(msg): 23 | h = hashlib.new('ripemd160') 24 | h.update(msg) 25 | return h.digest() 26 | 27 | 28 | def sha256(msg): 29 | h = hashlib.sha256() 30 | h.update(msg) 31 | return h.digest() 32 | 33 | ############################################################################### 34 | ## Server Tests 35 | ############################################################################### 36 | 37 | 38 | def preimage_client(): 39 | 40 | # Setup socket 41 | context = zmq.Context() 42 | socket = context.socket(zmq.REQ) 43 | socket.connect("ipc:///tmp/TumbleBit_tx") 44 | 45 | # Setup keys 46 | data = open("./keys/EC_private_test.bin", "rb").read() 47 | alice = CECKey() 48 | alice.set_privkey(data) 49 | 50 | data = open("./keys/EC_private_test2.bin", "rb").read() 51 | bob = CECKey() 52 | bob.set_privkey(data) 53 | 54 | # Setup Images & Hashes 55 | preimages = [(sha256("test" + str(x)))[:16] for x in range(1, 16)] 56 | hashes = [ripemd160(x) for x in preimages] 57 | 58 | serial_hashes = "" 59 | for i in range(len(hashes)): 60 | serial_hashes += hashes[i] 61 | 62 | serial_preimages = "" 63 | for i in range(len(preimages)): 64 | serial_preimages += preimages[i] 65 | 66 | # Phase 1 -- Setup 67 | msg = [b"setup_preimage", alice.get_pubkey(), bob.get_pubkey(), 68 | serial_hashes] 69 | socket.send_multipart(msg) 70 | 71 | reply = socket.recv_multipart() 72 | redeem_script = reply[0] 73 | fund_tx = reply[1] 74 | 75 | # print "Done with PHASE1" 76 | 77 | # Phase 2 -- Get TX sighash 78 | address = "mweZnPjTeyGHVS2d3SojAGujY36sd3wQ49" 79 | 80 | msg = [b"get_tx", redeem_script, address, fund_tx] 81 | socket.send_multipart(msg) 82 | 83 | reply = socket.recv_multipart() 84 | tx = reply[0] 85 | sighash = reply[1] 86 | 87 | # print "Done with PHASE2" 88 | 89 | # Sign 90 | alice_sig = alice.sign(sighash) # Used for refund 91 | bob_sig = bob.sign(sighash) # Used for redeem 92 | 93 | # Phase 3 -- Spending tx 94 | msg = [b"spend_preimage", serial_preimages, bob_sig, tx, redeem_script] 95 | socket.send_multipart(msg) 96 | 97 | reply = socket.recv() 98 | spending_tx = reply 99 | 100 | # print "Done with PHASE3" 101 | 102 | # Phase 4 -- Refunding tx 103 | msg = [b"send_refund_tx", alice_sig, tx, redeem_script] 104 | socket.send_multipart(msg) 105 | 106 | reply = socket.recv() 107 | refund_tx = reply 108 | 109 | # print "Done with PHASE4" 110 | 111 | print "PREIMAGE: Spending tx is: %s" % binascii.hexlify(spending_tx) 112 | print "\n\n" 113 | print "PREIMAGE: Refund tx is: %s" % binascii.hexlify(refund_tx) 114 | 115 | # Clean up 116 | socket.close() 117 | context.term() 118 | 119 | 120 | def escrow_client(): 121 | # Setup socket 122 | context = zmq.Context() 123 | socket = context.socket(zmq.REQ) 124 | socket.connect("ipc:///tmp/TumbleBit_tx") 125 | 126 | # Setup keys 127 | data = open("./keys/EC_private_test.bin", "rb").read() 128 | alice = CECKey() 129 | alice.set_privkey(data) 130 | 131 | data = open("./keys/EC_private_test2.bin", "rb").read() 132 | bob = CECKey() 133 | bob.set_privkey(data) 134 | 135 | # Phase 1 -- Setup 136 | msg = [b"setup_escrow", alice.get_pubkey(), bob.get_pubkey()] 137 | socket.send_multipart(msg) 138 | 139 | reply = socket.recv_multipart() 140 | redeem_script = reply[0] 141 | fund_tx = reply[1] 142 | 143 | # print "Done with PHASE1" 144 | 145 | # Phase 2 -- Get TX sighash 146 | address = "mweZnPjTeyGHVS2d3SojAGujY36sd3wQ49" 147 | 148 | msg = [b"get_tx", redeem_script, address, fund_tx] 149 | socket.send_multipart(msg) 150 | 151 | reply = socket.recv_multipart() 152 | tx = reply[0] 153 | sighash = reply[1] 154 | 155 | # print "Done with PHASE2" 156 | 157 | # Sign 158 | alice_sig = alice.sign(sighash) 159 | bob_sig = bob.sign(sighash) 160 | 161 | # Phase 3 -- Spending tx 162 | msg = [b"spend_escrow", alice_sig, bob_sig, tx, redeem_script] 163 | socket.send_multipart(msg) 164 | 165 | reply = socket.recv() 166 | spending_tx = reply 167 | 168 | # print "Done with PHASE3" 169 | 170 | # Phase 4 -- Refunding tx 171 | msg = [b"send_refund_tx", alice_sig, tx, redeem_script] 172 | socket.send_multipart(msg) 173 | 174 | reply = socket.recv() 175 | refund_tx = reply 176 | 177 | # print "Done with PHASE4" 178 | 179 | print "ESCROW: Spending tx is: %s" % binascii.hexlify(spending_tx) 180 | print "\n\n" 181 | print "ESCROW: Refund tx is: %s" % binascii.hexlify(refund_tx) 182 | 183 | # Clean up 184 | socket.close() 185 | context.term() 186 | 187 | ############################################################################### 188 | ## Module Tests 189 | ############################################################################### 190 | 191 | 192 | def preimage_example(): 193 | ''' 194 | Refund test: 195 | P2SH Address: 196 | 2MscMqe6Ag5NmZKCsELKDPJRJWnPR6GGD9B 197 | 198 | Funding tx: 199 | d49038dd9141f77c230208fe1cdd24937c61a1b63f40b8a87ab50971970ac2b7 200 | Spending tx nlocktime = 10: 201 | 202 | Refund TX: 203 | f77245db1c81b49c72464e61e3738a60f6e21c0bb744f8729def4a9877082e73 204 | 205 | Preimage test: 206 | P2SH Address: 207 | 2NEFkj2gMZguX3QtFp31XKfnRdUpEoXTVNv 208 | 209 | Funding tx: 210 | 91e6953fdcc15687ffc54e76d55ed4b92ef60cd483e0633ef226f7509513c7d2 211 | Spending tx nlocktime = 10: 212 | 213 | Spending TX: 214 | e006b7d1566045e136c13446114e51513f1453a7e2eb7e534d04bd7dc09532f7 215 | 216 | Other: 217 | 1/ 218 | P2SH Address: 2N6uq4bLT6UTqqxNo7YQ5TyRrFVWSRAFyxT 219 | Funding TX: 220 | 8f717d1babd532b337cb80e743844f270129c744ebfc1ff7f6b43c1d855adc75 221 | Spending TX: 222 | b9cfbbdef00319db95c0beae8f73de4f7639eacc9b2006a70d64b494673921eb 223 | 224 | ''' 225 | SelectParams('testnet') 226 | 227 | tx = TX(test=True) 228 | 229 | print "=" * 50 230 | print ("=" * 10 + " PREIMAGE EXAMPLE") 231 | print "=" * 50 + "\n" 232 | 233 | # Setup keys 234 | data = open("./keys/EC_private_test.bin", "rb").read() 235 | alice = CECKey() 236 | alice.set_privkey(data) 237 | 238 | data = open("./keys/EC_private_test2.bin", "rb").read() 239 | bob = CECKey() 240 | bob.set_privkey(data) 241 | 242 | preimages = [sha256("test" + str(x)) for x in range(1, 16)] 243 | hashes = [ripemd160(x) for x in preimages] 244 | 245 | # Serialize hashes 246 | serial_hashes = "" 247 | for i in range(len(hashes)): 248 | serial_hashes += hashes[i] 249 | tx.get_hashes_from_serial(serial_hashes, 15, 20) 250 | 251 | amount = 0.001 # In bitcoins 252 | redeem_script, funding_tx = tx.setup_preimage(alice.get_pubkey(), 253 | bob.get_pubkey(), hashes, 254 | amount, 10) 255 | 256 | # Funding tx id + redeeming bitcoin address 257 | funding_tx = "8f717d1babd532b337cb80e743844f270" + \ 258 | "129c744ebfc1ff7f6b43c1d855adc75" 259 | address = "mweZnPjTeyGHVS2d3SojAGujY36sd3wQ49" 260 | 261 | # Note: Make sure pick correct vout - default is 0 262 | tx2, sighash = tx.get_tx(redeem_script, address, 263 | amount - 0.0001, funding_tx, 5) 264 | 265 | # Sign 266 | alice_sig = alice.sign(sighash) 267 | bob_sig = bob.sign(sighash) 268 | 269 | redeem_tx = tx.spend_preimage(preimages, bob_sig, tx2, redeem_script) 270 | print "REDEEM TX is:\n%s\n" % binascii.hexlify(redeem_tx) 271 | 272 | refunded_tx = tx.refund_tx(alice_sig, tx2, redeem_script) 273 | print "REFUND TX is:\n%s\n" % binascii.hexlify(refunded_tx) 274 | 275 | serial_keys = tx.get_keys_from_tx(redeem_tx) 276 | # print "SERIAL KEYS:\n%s\n" % binascii.hexlify(serial_keys) 277 | 278 | # # write to file to test in c++ 279 | # target = open("keys.bin", 'wb') 280 | # target.write(serial_keys) 281 | # target.close() 282 | 283 | print "=" * 50 + "\n\n" 284 | 285 | 286 | def escrow_example(): 287 | ''' 288 | P2SH Address: 289 | 2MzDcMCxcZnNnAZzFqsyuyZ4vuNCB6Qjvxd 290 | 291 | Funding tx: 292 | db1b045ea09581a51a5b5f851e7e3a64542123885e071fd6d4ff7428703a2504 293 | Spending tx nlocktime = 30: 294 | 295 | Refund TX: 296 | 23daa9d3868255bab14d5dfe46f7fb787aaef49b17d0014902e36e4491440311 297 | ''' 298 | SelectParams('testnet') 299 | 300 | tx = TX(test=True) 301 | 302 | print "=" * 50 303 | print ("=" * 10 + " ESCROW EXAMPLE") 304 | print "=" * 50 + "\n" 305 | 306 | # Setup keys 307 | data = open("./keys/EC_private_test.bin", "rb").read() 308 | alice = CECKey() 309 | alice.set_privkey(data) 310 | 311 | data = open("./keys/EC_private_test2.bin", "rb").read() 312 | bob = CECKey() 313 | bob.set_privkey(data) 314 | 315 | amount = 0.001 # In bitcoins 316 | 317 | redeem_script, p2sh_address = tx.setup_escrow(alice.get_pubkey(), 318 | bob.get_pubkey(), amount, 30) 319 | 320 | # Funding tx id + redeeming bitcoin address 321 | funding_tx = "db1b045ea09581a51a5b5f851e7e3a6" + \ 322 | "4542123885e071fd6d4ff7428703a2504" 323 | address = "mweZnPjTeyGHVS2d3SojAGujY36sd3wQ49" 324 | 325 | # Note: Make sure pick correct vout - default is 0 326 | tx2, sighash = tx.get_tx(redeem_script, address, 327 | amount - 0.0001, funding_tx, 20, vout=1) 328 | 329 | # Sign 330 | alice_sig = alice.sign(sighash) 331 | bob_sig = bob.sign(sighash) 332 | 333 | print "P2SH %s" % p2sh_address 334 | print "Redeem script:\n%s\n" % binascii.hexlify(redeem_script) 335 | print "Redeem script Hash:\n%s\n" % binascii.hexlify(sha256(sha256(redeem_script))) 336 | 337 | redeem_tx = tx.spend_escrow(alice_sig, bob_sig, tx2, redeem_script) 338 | print "REDEEM TX is:\n%s\n" % binascii.hexlify(redeem_tx) 339 | 340 | refunded_tx = tx.refund_tx(alice_sig, tx2, redeem_script) 341 | print "REFUND TX is:\n%s\n" % binascii.hexlify(refunded_tx) 342 | print "=" * 50 + "\n\n" 343 | 344 | 345 | ############################################################################### 346 | ## MAIN 347 | ############################################################################### 348 | 349 | 350 | def main(): 351 | escrow_example() 352 | # preimage_example() 353 | # preimage_client() 354 | # escrow_client() 355 | 356 | if __name__ == '__main__': 357 | main() 358 | -------------------------------------------------------------------------------- /POC_code/requirements.txt: -------------------------------------------------------------------------------- 1 | python-bitcoinlib 2 | simplejson 3 | pyzmq 4 | pycrypto 5 | -------------------------------------------------------------------------------- /POC_code/src/alice_client.cpp: -------------------------------------------------------------------------------- 1 | #include "timer.h" 2 | #include "alice_client.h" 3 | 4 | class Alice_Client : public SCC_Interface { 5 | 6 | private: 7 | Alice alice; 8 | 9 | // Network 10 | zmq::socket_t& socket; 11 | 12 | std::vector requests; // Received 13 | std::vector reply; // Sent 14 | 15 | Bin* address; 16 | 17 | public: 18 | 19 | Alice_Client(zmq::socket_t& s, Bin* y, char* address_str): alice(y), socket(s){ 20 | 21 | socket.connect(SIGNER_SERVER_SOCKET); 22 | 23 | init(); 24 | this->y = y; 25 | 26 | address = new Bin(strlen(address_str)); 27 | memcpy(address->data, address_str, address->len); 28 | } 29 | 30 | Alice_Client(zmq::socket_t& s, Bin* y): alice(y), socket(s){ 31 | 32 | socket.connect(SIGNER_SERVER_SOCKET); 33 | 34 | init(); 35 | this->y = y; 36 | 37 | address = new Bin(strlen(TUMBLER_ADDRESS)); 38 | memcpy(address->data, TUMBLER_ADDRESS, address->len); 39 | } 40 | 41 | ~Alice_Client(){ 42 | 43 | delete address; 44 | }; 45 | 46 | bool start(){ 47 | 48 | alice.set_party_address(address); 49 | 50 | //===================================== 51 | // SCC Protocol 52 | //===================================== 53 | 54 | Timer timer = Timer((char *) "scc_protocol\0"); 55 | timer.start(); 56 | 57 | if (!exchange_public_key()){ 58 | printf("Failed in exchange_public_key\n"); 59 | return false; 60 | } 61 | 62 | if (!commitment()){ 63 | printf("Failed in commitment\n"); 64 | return false; 65 | } 66 | 67 | if (!verify_fakes()){ 68 | printf("Failed in verify_fakes\n"); 69 | return false; 70 | } 71 | 72 | if (!verify_reals()){ 73 | printf("Failed in verify_reals\n"); 74 | return false; 75 | } 76 | 77 | if(!get_decryption_from_tx()){ 78 | printf("Failed in get_decryption_from_tx\n"); 79 | return false; 80 | } 81 | 82 | timer.end(); 83 | 84 | return true; 85 | } 86 | 87 | Bin* get_decryption(){ 88 | return alice.get_y_sk(); 89 | } 90 | 91 | protected: 92 | 93 | bool exchange_public_key(){ 94 | 95 | Bin* temp = new Bin(19); 96 | memcpy(temp->data, "exchange_public_key", 19); 97 | 98 | requests.push_back(temp); 99 | send(socket, requests); 100 | 101 | delete temp; 102 | requests.clear(); 103 | 104 | receive(socket, reply); 105 | if(reply.size() != 2){ 106 | free_Bins(reply); 107 | reply.clear(); 108 | return false; 109 | } 110 | 111 | signer_pubkey = reply.at(0); 112 | alice.set_party_pubkey(signer_pubkey); 113 | alice.set_rsa(reply.at(1)); 114 | 115 | if(!alice.setup_escrow_tx()){ 116 | printf("Failed in setup escrow\n"); 117 | return false; 118 | } 119 | 120 | delete reply.at(1); 121 | reply.clear(); 122 | phase_0 = true; 123 | return true; 124 | } 125 | 126 | bool commitment(){ 127 | 128 | Bin* temp = new Bin(10); 129 | memcpy(temp->data, "commitment", 10); 130 | 131 | Bin *b_set = new Bin(); 132 | std::vector blinded_set = *alice.get_blinded_set(); 133 | 134 | if (!serialize_vector(b_set, blinded_set, (N + M), alice.rsa_len)){ 135 | return false; 136 | } 137 | 138 | requests.push_back(temp); 139 | requests.push_back(b_set); 140 | requests.push_back(alice.get_escrow_redeem_script()); 141 | requests.push_back(alice.get_escrow_funding_tx_id()); 142 | send(socket, requests); 143 | 144 | // free_Bins(requests); 145 | delete temp; 146 | delete b_set; 147 | requests.clear(); 148 | 149 | receive(socket, reply); 150 | if(reply.size() != 2){ 151 | free_Bins(reply); 152 | reply.clear(); 153 | return false; 154 | } 155 | 156 | if (!deserialize_vector(reply.at(0), C, M + N, alice.rsa_len + 8)){ 157 | return false; 158 | } 159 | 160 | if (!deserialize_vector(reply.at(1), H, M + N, HASH_160)){ 161 | return false; 162 | } 163 | 164 | alice.set_C(C); 165 | alice.set_H(H); 166 | 167 | free_Bins(reply); 168 | reply.clear(); 169 | 170 | phase_1 = true; 171 | return true; 172 | } 173 | 174 | bool verify_fakes(){ 175 | 176 | if(!alice.setup_preimage_tx()){ 177 | printf("Failed in setup preimage\n"); 178 | return false; 179 | } 180 | 181 | Bin *r = new Bin(); 182 | Bin *f = new Bin(); 183 | 184 | R = alice.get_R(); 185 | F = alice.get_F(); 186 | 187 | Bin* temp = new Bin(12); 188 | memcpy(temp->data, "verify_fakes", 12); 189 | 190 | if (!serialize_int_vector(r, R, M)){ 191 | delete r; 192 | return false; 193 | } 194 | 195 | if (!serialize_int_vector(f, F, N)){ 196 | delete f; 197 | return false; 198 | } 199 | 200 | Bin* fake_blinds = new Bin(); 201 | if (!serialize_vector(fake_blinds, *alice.get_fake_blinds(), N , alice.rsa_len)){ 202 | return false; 203 | } 204 | 205 | requests.push_back(temp); 206 | requests.push_back(f); 207 | requests.push_back(r); 208 | requests.push_back(fake_blinds); 209 | requests.push_back(alice.get_preimage_P2SH()); 210 | send(socket, requests); 211 | 212 | // Cleanup 213 | delete temp; 214 | delete f; 215 | delete r; 216 | delete fake_blinds; 217 | requests.clear(); 218 | 219 | receive(socket, reply); 220 | if(reply.size() != 2){ 221 | free_Bins(reply); 222 | reply.clear(); 223 | return false; 224 | } 225 | 226 | if (!deserialize_vector(reply.at(0), fake_keys, N, KEY_LEN)){ 227 | return false; 228 | } 229 | 230 | if(!alice.verify_preimage_signature(reply.at(1))){ 231 | return false; 232 | } 233 | 234 | if (!alice.verify_keys(fake_keys)){ 235 | return false; 236 | } 237 | 238 | free_Bins(reply); 239 | reply.clear(); 240 | 241 | phase_2 = true; 242 | return true; 243 | } 244 | 245 | bool verify_reals(){ 246 | 247 | Bin* temp = new Bin(12); 248 | memcpy(temp->data, "verify_reals", 12); 249 | 250 | 251 | Bin* real_blinds = new Bin(); 252 | if (!serialize_vector(real_blinds, *alice.get_real_blinds(), M , alice.rsa_len)){ 253 | return false; 254 | } 255 | 256 | Bin* sig = alice.get_preimage_signature(); 257 | if(sig == NULL){ 258 | printf("Failed in get signature\n"); 259 | return false; 260 | } 261 | 262 | 263 | requests.push_back(temp); 264 | requests.push_back(alice.get_preimage_redeem_script()); 265 | requests.push_back(sig); 266 | requests.push_back(y); 267 | requests.push_back(real_blinds); 268 | send(socket, requests); 269 | 270 | delete temp; 271 | delete real_blinds; 272 | requests.clear(); 273 | 274 | receive(socket, reply); 275 | if(reply.size() != 1){ 276 | free_Bins(reply); 277 | reply.clear(); 278 | return false; 279 | } 280 | 281 | serial_real_keys = reply.at(0); 282 | if(!deserialize_vector(serial_real_keys, real_keys, M, KEY_LEN)){ 283 | printf("Failed in deserialize_keys\n"); 284 | return false; 285 | } 286 | 287 | delete reply.at(0);; 288 | reply.clear(); 289 | return true; 290 | } 291 | 292 | bool get_decryption_from_tx(){ 293 | 294 | Timer timer = Timer((char *) "scc_decryption\0"); 295 | timer.start(); 296 | 297 | alice.set_real_keys(real_keys); 298 | if(!alice.get_decryption()){ 299 | printf("Failed in alice.get_decryption\n"); 300 | return false; 301 | } 302 | 303 | Bin* temp = new Bin(16); 304 | memcpy(temp->data, "escrow_signature", 16); 305 | 306 | requests.push_back(temp); 307 | requests.push_back(alice.get_escrow_signature()); 308 | 309 | send(socket, requests); 310 | delete temp; 311 | requests.clear(); 312 | 313 | receive(socket, reply); 314 | if(reply.size() != 1){ 315 | free_Bins(reply); 316 | reply.clear(); 317 | return false; 318 | } 319 | free_Bins(reply); 320 | reply.clear(); 321 | 322 | timer.end(); 323 | 324 | 325 | phase_4 = true; 326 | return true; 327 | } 328 | 329 | }; 330 | 331 | bool get_decryption(Bin* y, Bin* y_sk){ 332 | 333 | if(!defined(y) || y_sk == NULL){ 334 | return false; 335 | } 336 | 337 | zmq::context_t context(1); 338 | zmq::socket_t socket(context, ZMQ_REQ); 339 | 340 | 341 | Alice_Client alice_client = Alice_Client(socket, y); 342 | if(!alice_client.start()){ 343 | return false; 344 | } 345 | 346 | Bin* decryption = alice_client.get_decryption(); 347 | if (!defined(decryption)){ 348 | return false; 349 | } 350 | 351 | // Copy result 352 | y_sk->len = decryption->len; 353 | y_sk->data = (unsigned char *) malloc(y_sk->len); 354 | memcpy(y_sk->data, decryption->data, y_sk->len); 355 | 356 | return true; 357 | } 358 | -------------------------------------------------------------------------------- /POC_code/src/alice_client_test.cpp: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_DYN_LINK 2 | #define BOOST_TEST_MODULE alice_client 3 | #include 4 | 5 | #include "alice_client.h" 6 | 7 | 8 | BOOST_AUTO_TEST_CASE(client){ 9 | 10 | bool status; 11 | 12 | // Setup RSA 13 | RSA * rsa = get_public_rsa(2048, (char *)"tumbler"); 14 | BOOST_REQUIRE_MESSAGE(rsa != NULL, "test_alice_client: Failed load RSA key"); 15 | int rsa_len = RSA_size(rsa); 16 | 17 | Bin* y_sk = new Bin(); 18 | 19 | // Create epsilon 20 | Bin* epsilon = new Bin(); 21 | Bin *y = new Bin(rsa_len); 22 | epsilon->len = rsa_len; 23 | epsilon->data = get_random(rsa_len * 8, rsa->n); 24 | 25 | // Encrypt epsilon 26 | int s = RSA_public_encrypt(rsa_len, epsilon->data, y->data, rsa, RSA_NO_PADDING); 27 | BOOST_REQUIRE_MESSAGE(s != -1, "test_alice_client: Failed to create e^pk"); 28 | 29 | status = get_decryption(y, y_sk); 30 | BOOST_REQUIRE_MESSAGE(status == true, "test_alice_client: Failed to get decryption"); 31 | 32 | 33 | BOOST_REQUIRE_MESSAGE(*y_sk == *epsilon, "test_alice_client: Decryption is invalid!"); 34 | printf("Success!\n"); 35 | 36 | // Cleanup 37 | delete y; 38 | delete y_sk; 39 | delete epsilon; 40 | RSA_free(rsa); 41 | } 42 | -------------------------------------------------------------------------------- /POC_code/src/bob_client.cpp: -------------------------------------------------------------------------------- 1 | #include "bob.h" 2 | #include "alice_client.h" 3 | #include "network.h" 4 | #include "scc_wrapper_interface.h" 5 | #include "timer.h" 6 | 7 | class Bob_client: SCC_Wrapper_Interface { 8 | 9 | private: 10 | Bob bob; 11 | 12 | // Network 13 | zmq::socket_t& socket; 14 | 15 | std::vector requests; // Sent 16 | std::vector reply; // Received 17 | 18 | std::vector C; 19 | std::vector Z; 20 | std::vector quotients; 21 | std::vector fake_epsilons; 22 | 23 | 24 | Bin* redeem_script; 25 | Bin* funding_tx_id; 26 | Bin* pub_key; 27 | 28 | public: 29 | 30 | Bob_client(zmq::socket_t& s): socket(s){ 31 | 32 | socket.connect(TUMBLER_SERVER_SOCKET); 33 | 34 | } 35 | 36 | ~Bob_client(){ 37 | 38 | delete_bin(redeem_script); 39 | delete_bin(funding_tx_id); 40 | delete_bin(pub_key); 41 | 42 | free_Bins(C); 43 | free_Bins(Z); 44 | free_Bins(fake_epsilons); 45 | free_Bins(quotients); 46 | 47 | }; 48 | 49 | bool start(){ 50 | Timer timer = Timer((char *) "wrapper_protocol\0"); 51 | timer.start(); 52 | 53 | //===================================== 54 | // SCC Wrapper Protocol 55 | //===================================== 56 | if (!exchange()){ 57 | printf("Failed in exchange\n"); 58 | return false; 59 | } 60 | 61 | if (!commitment()){ 62 | printf("Failed in commitment\n"); 63 | return false; 64 | } 65 | 66 | if (!verify()){ 67 | printf("Failed in verify\n"); 68 | return false; 69 | } 70 | timer.end(); 71 | 72 | if(!post()){ 73 | printf("Failed in post\n"); 74 | return false; 75 | } 76 | 77 | return true; 78 | } 79 | 80 | protected: 81 | 82 | bool exchange(){ 83 | 84 | Bin* temp = new Bin(8); 85 | memcpy(temp->data, "exchange", 8); 86 | 87 | Bin* bob_pubkey = bob.get_pubkey(); 88 | 89 | requests.push_back(temp); 90 | requests.push_back(bob_pubkey); 91 | send(socket, requests); 92 | 93 | delete temp; 94 | requests.clear(); 95 | 96 | receive(socket, reply); 97 | 98 | if(reply.size() != 4){ 99 | free_Bins(reply); 100 | reply.clear(); 101 | return false; 102 | } 103 | 104 | pub_key = reply.at(0); 105 | redeem_script = reply.at(2); 106 | funding_tx_id = reply.at(3); 107 | 108 | bob.set_party_pubkey(pub_key); 109 | bob.set_rsa(reply.at(1)); 110 | bob.set_redeem_script(redeem_script); 111 | bob.set_funding_tx_id(funding_tx_id); 112 | 113 | 114 | delete reply.at(1); 115 | 116 | reply.clear(); 117 | 118 | return true; 119 | } 120 | 121 | bool commitment(){ 122 | 123 | Bin* temp = new Bin(10); 124 | memcpy(temp->data, "commitment", 10); 125 | 126 | Bin *tx_set = new Bin(); 127 | if (!serialize_vector(tx_set, *bob.get_tx_set(), (2 * K), HASH_256)){ 128 | return false; 129 | } 130 | 131 | requests.push_back(temp); 132 | requests.push_back(tx_set); 133 | requests.push_back(bob.get_h_r()); 134 | requests.push_back(bob.get_h_f()); 135 | send(socket, requests); 136 | 137 | delete temp; 138 | delete tx_set; 139 | requests.clear(); 140 | 141 | 142 | receive(socket, reply); 143 | if(reply.size() != 2){ 144 | free_Bins(reply); 145 | reply.clear(); 146 | return false; 147 | } 148 | 149 | 150 | if (!deserialize_vector(reply.at(0), C, 2 * K, HASH_512)){ 151 | return false; 152 | } 153 | 154 | if (!deserialize_vector(reply.at(1), Z, 2 * K, bob.rsa_len)){ 155 | return false; 156 | } 157 | 158 | free_Bins(reply); 159 | reply.clear(); 160 | 161 | return true; 162 | } 163 | 164 | bool verify(){ 165 | 166 | Bin *R = new Bin(); 167 | Bin *F = new Bin(); 168 | Bin *fake_tx = new Bin(); 169 | 170 | std::vectorr = bob.get_R(); 171 | std::vectorf = bob.get_F(); 172 | 173 | Bin* temp = new Bin(6); 174 | memcpy(temp->data, "verify", 6); 175 | 176 | if (!serialize_int_vector(R, r, K)){ 177 | delete R; 178 | return false; 179 | } 180 | 181 | if (!serialize_int_vector(F, f, K)){ 182 | delete F; 183 | return false; 184 | } 185 | 186 | 187 | if (!serialize_vector(fake_tx, *bob.get_fake_tx(), K, HASH_256)){ 188 | return false; 189 | } 190 | 191 | requests.push_back(temp); 192 | requests.push_back(R); 193 | requests.push_back(F); 194 | requests.push_back(fake_tx); 195 | requests.push_back(bob.get_salt()); 196 | send(socket, requests); 197 | 198 | requests.pop_back(); 199 | free_Bins(requests); 200 | requests.clear(); 201 | 202 | receive(socket, reply); 203 | if(reply.size() != 2){ 204 | free_Bins(reply); 205 | reply.clear(); 206 | return false; 207 | } 208 | 209 | 210 | if (!deserialize_vector(reply.at(0), quotients, K - 1, bob.rsa_len)){ 211 | return false; 212 | } 213 | 214 | if (!deserialize_vector(reply.at(1), fake_epsilons, K, bob.rsa_len)){ 215 | return false; 216 | } 217 | 218 | if (!bob.verify_recieved_data(Z, C, fake_epsilons, quotients)){ 219 | return false; 220 | } 221 | 222 | free_Bins(reply); 223 | reply.clear(); 224 | 225 | return true; 226 | } 227 | 228 | bool post(){ 229 | 230 | Bin* W = bob.get_W(); 231 | 232 | Bin* epsiolon = new Bin(); 233 | if (!get_decryption(W, epsiolon)){ 234 | return false; 235 | } 236 | 237 | 238 | bob.set_recovered_epsilon(epsiolon); 239 | if(!bob.post_tx()){ 240 | return false; 241 | } 242 | 243 | Bin* tx = bob.get_tx_fulfill(); 244 | printf("\n\nTX fulfill is:\n"); 245 | tx->print(); 246 | printf("\n\n"); 247 | 248 | // Cleanup 249 | delete epsiolon; 250 | 251 | return true; 252 | } 253 | 254 | }; 255 | 256 | int main () { 257 | 258 | zmq::context_t context(1); 259 | zmq::socket_t socket(context, ZMQ_REQ); 260 | 261 | Timer timer = Timer((char *) "total\0"); 262 | timer.start(); 263 | 264 | 265 | Bob_client bob_client = Bob_client(socket); 266 | bob_client.start(); 267 | 268 | timer.end(); 269 | printf("Total:\n"); 270 | timer.print(); 271 | 272 | } 273 | -------------------------------------------------------------------------------- /POC_code/src/crypto/encrypt.cpp: -------------------------------------------------------------------------------- 1 | #include "encrypt.h" 2 | 3 | //============================================================================ 4 | //====== XOR Functions 5 | //============================================================================ 6 | 7 | bool encrypt(Bin* plain_text, Bin *key, Bin* cipher_text){ 8 | 9 | if (!defined(plain_text) || !defined(key) || 10 | plain_text->len != 64 || cipher_text == NULL){ 11 | return false; 12 | } 13 | 14 | // Hash 15 | Bin *temp_h = new Bin(HASH_512); 16 | SHA512(key->data, key->len, temp_h->data); 17 | 18 | // Decrypt 19 | cipher_text->len = plain_text->len; 20 | cipher_text->data = XOR_enc_dec(plain_text, temp_h, plain_text->len); 21 | 22 | delete temp_h; 23 | 24 | return true; 25 | } 26 | 27 | bool decrypt(Bin* cipher_text, Bin *key, Bin* plain_text){ 28 | 29 | if (!defined(key) || !defined(cipher_text) || 30 | cipher_text->len != 64 || plain_text == NULL){ 31 | return false; 32 | } 33 | 34 | // Hash 35 | Bin *temp_h = new Bin(HASH_512); 36 | SHA512(key->data, key->len, temp_h->data); 37 | 38 | // Decrypt 39 | plain_text->len = cipher_text->len; 40 | plain_text->data = XOR_enc_dec(cipher_text, temp_h, cipher_text->len); 41 | 42 | delete temp_h; 43 | 44 | return true; 45 | } 46 | 47 | unsigned char * XOR_enc_dec(Bin* m, Bin* k, int len){ 48 | if (m->len != k->len){ 49 | return NULL; 50 | } 51 | 52 | unsigned char * result = (unsigned char *) tmalloc(len * sizeof(unsigned char)); 53 | for (int i = 0; i < len; i++){ 54 | result[i] = m->data[i] ^ k->data[i]; 55 | } 56 | return result; 57 | } 58 | 59 | //============================================================================ 60 | //====== CHACHA Functions 61 | //============================================================================ 62 | 63 | bool encrypt_chacha(Bin* plain_text, Bin *key, Bin* cipher_text){ 64 | 65 | if (!defined(plain_text) || key == NULL || plain_text == NULL){ 66 | return false; 67 | } 68 | 69 | key->len = KEY_LEN; 70 | key->data = get_random(KEY_LEN * 8); 71 | 72 | Bin iv = Bin(); 73 | iv.len = 8; 74 | iv.data = get_random(8*8); 75 | 76 | Bin cipher = Bin(plain_text->len); 77 | 78 | // Encrypt 79 | chacha(&cipher, plain_text, key, &iv); 80 | 81 | cipher_text->len = plain_text->len + 8; 82 | cipher_text->data = (unsigned char *) malloc(cipher_text->len); 83 | memcpy(cipher_text->data, iv.data, 8); 84 | memcpy(cipher_text->data + 8, cipher.data, plain_text->len); 85 | 86 | return true; 87 | } 88 | 89 | bool decrypt_chacha(Bin* cipher_text, Bin *key, Bin* plain_text){ 90 | 91 | if (!defined(key) || !defined(cipher_text) || plain_text == NULL){ 92 | return false; 93 | } 94 | 95 | Bin iv = Bin(8); 96 | Bin cipher = Bin(cipher_text->len - 8); 97 | 98 | memcpy(iv.data, cipher_text->data, 8); 99 | memcpy(cipher.data, cipher_text->data + 8, cipher.len); 100 | 101 | 102 | // Decrypt sig 103 | plain_text->len = cipher.len; 104 | plain_text->data = (unsigned char *) tmalloc(cipher.len); 105 | chacha(plain_text, &cipher, key, &iv); 106 | 107 | return true; 108 | } 109 | 110 | bool chacha(Bin* out, Bin* in, Bin* key, Bin* iv){ 111 | if (out == NULL || !defined(in) || !defined(key) || key->len != 16 || !defined(iv)){ 112 | return false; 113 | } 114 | 115 | ChaCha_ctx ctx; 116 | 117 | ChaCha_set_key(&ctx, key->data, 128); 118 | ChaCha_set_iv(&ctx, iv->data, NULL); 119 | ChaCha(&ctx, out->data, in->data, in->len); 120 | 121 | return true; 122 | } 123 | -------------------------------------------------------------------------------- /POC_code/src/crypto/hash.cpp: -------------------------------------------------------------------------------- 1 | #include "hash.h" 2 | 3 | Bin* full_domain_hash(RSA *rsa, Bin* msg, const EVP_MD *hash){ 4 | if (!defined(msg) || hash == NULL || rsa == NULL){ 5 | return NULL; 6 | } 7 | 8 | int mask_len = BN_num_bytes(rsa->n); 9 | unsigned char * mask = (unsigned char *) tmalloc(mask_len); 10 | mask[0] = 0; 11 | 12 | // Had a problem with sizeof(mask) - 1, since mask has changed to a pointer 13 | if (PKCS1_MGF1(mask + 1, mask_len - 1, msg->data, msg->len, hash) != 0) { 14 | printf("FDH failed.\n"); 15 | return NULL; 16 | } 17 | 18 | Bin* h = new Bin(); 19 | h->len = mask_len; 20 | h->data = mask; 21 | 22 | return h; 23 | } 24 | 25 | Bin* hash256(Bin* msg){ 26 | Bin* hash = new Bin(HASH_256); 27 | Bin* temp_hash = new Bin(HASH_256); 28 | 29 | SHA256(msg->data, msg->len, temp_hash->data); 30 | SHA256(temp_hash->data, temp_hash->len, hash->data); 31 | 32 | delete temp_hash; 33 | 34 | return hash; 35 | } 36 | 37 | Bin* hmac256(Bin* msg, Bin* key){ 38 | 39 | Bin* output = new Bin(32); 40 | 41 | if(HMAC(EVP_sha256(),key->data, key->len, msg->data, msg->len, 42 | output->data, NULL) == NULL){ 43 | return NULL; 44 | } 45 | 46 | return output; 47 | } 48 | -------------------------------------------------------------------------------- /POC_code/src/crypto/random.cpp: -------------------------------------------------------------------------------- 1 | #include "random.h" 2 | 3 | unsigned char * get_random(int bits){ 4 | BN_CTX *ctx; 5 | BIGNUM *r = NULL; 6 | unsigned char * r_str = NULL; 7 | int r_len; 8 | 9 | ctx = BN_CTX_new(); 10 | if (ctx == NULL) { 11 | printf("get_random: Couldn't get new CTX\n"); 12 | return NULL; 13 | } 14 | BN_CTX_start(ctx); 15 | r = BN_CTX_get(ctx); 16 | 17 | //https://www.openssl.org/docs/manmaster/crypto/BN_rand.html 18 | int s = BN_rand(r, bits, 0, 1); 19 | if (s == 0) { 20 | printf("get_random: Couldn't generate random number\n"); 21 | return NULL; 22 | } 23 | 24 | r_len = BN_num_bytes(r); 25 | r_str = (unsigned char *) tmalloc(r_len); 26 | BN_bn2bin(r, r_str); 27 | 28 | BN_free(r); 29 | BN_CTX_end(ctx); 30 | BN_CTX_free(ctx); 31 | 32 | return r_str; 33 | } 34 | 35 | unsigned char * get_random(int bits, BIGNUM *n){ 36 | BN_CTX *ctx; 37 | BIGNUM *r = NULL; 38 | unsigned char * r_str = NULL; 39 | 40 | ctx = BN_CTX_new(); 41 | if (ctx == NULL) { 42 | printf("get_random: Couldn't get new CTX\n"); 43 | return NULL; 44 | } 45 | BN_CTX_start(ctx); 46 | r = BN_CTX_get(ctx); 47 | 48 | //https://www.openssl.org/docs/manmaster/crypto/BN_rand.html 49 | int s = BN_rand_range(r, n); 50 | if (s == 0) { 51 | printf("get_random: Couldn't generate random number\n"); 52 | return NULL; 53 | } 54 | 55 | BN_num_bytes(r); 56 | r_str = (unsigned char *) tmalloc(bits / 8); 57 | BNToBin(r, r_str, bits / 8); 58 | 59 | BN_free(r); 60 | BN_CTX_end(ctx); 61 | BN_CTX_free(ctx); 62 | 63 | return r_str; 64 | } 65 | -------------------------------------------------------------------------------- /POC_code/src/scc.cpp: -------------------------------------------------------------------------------- 1 | #include "scc.h" 2 | 3 | //============================================================================ 4 | 5 | bool apply_blinds(Bin* message, std::vector &blinds, std::vector &blinded){ 6 | int r; 7 | Bin* temp; 8 | for (unsigned int i = 0; i < blinds.size(); i++){ 9 | temp = new Bin(message->len); 10 | r = blind(blinds.at(i), message, temp); 11 | if (r == 1){ 12 | blinded.push_back(temp); 13 | } 14 | else { 15 | // Something went wrong 16 | return false; 17 | } 18 | } 19 | 20 | return true; 21 | } 22 | 23 | bool remove_blinds(std::vector &blinded, int len, std::vector &blinds, 24 | std::vector &unblinded){ 25 | 26 | int r; 27 | Bin* temp; 28 | for (unsigned int i = 0; i < blinds.size(); i++){ 29 | temp = new Bin(len); 30 | r = unblind(blinds.at(i), blinded.at(i), temp); 31 | if (r == 1){ 32 | blinded.push_back(temp); 33 | } 34 | else { 35 | // Something went wrong 36 | return false; 37 | } 38 | } 39 | 40 | return true; 41 | } 42 | 43 | bool create_blinds(RSA * rsa, int n, std::vector &blinds){ 44 | BN_BLINDING * b; 45 | for (int i=0; i < n; i++){ 46 | b = setup_blinding(rsa); 47 | // b = setup_blinding_deterministic(rsa); 48 | if (b != NULL){ 49 | blinds.push_back(b); 50 | } 51 | else { 52 | printf("Couldn't generate blind."); 53 | return false; 54 | } 55 | } 56 | 57 | return true; 58 | } 59 | 60 | 61 | //============================================================================ 62 | 63 | int shuffle_random (int i) { return std::rand()%i;} 64 | 65 | 66 | bool find_indices(std::vector &in, std::vector &what, std::vector &indices) 67 | { 68 | std::vector::iterator iter; 69 | size_t id; 70 | for (unsigned int i = 0; i < what.size(); i++){ 71 | pointer_equal predicate = {what.at(i)}; 72 | iter = std::find_if(in.begin(),in.end(), predicate); 73 | id = iter - in.begin(); 74 | indices.push_back(id); 75 | } 76 | 77 | return true; 78 | } 79 | 80 | 81 | //============================================================================ 82 | 83 | // N is the number of items 84 | bool serialize_vector(Bin* serial, std::vector& vec, int n, int len){ 85 | if (vec.size() != (unsigned int) n){ 86 | printf("serialize_vector: Vec size is %lu, expected %d", vec.size(), n); 87 | return false; 88 | } 89 | 90 | serial->len = n * len; 91 | serial->data = (unsigned char *) tmalloc(serial->len); 92 | 93 | unsigned char *p = serial->data; 94 | for(int i=0; i < n; i++){ 95 | 96 | memcpy(p, vec.at(i)->data, len); 97 | p = p + len; 98 | } 99 | 100 | return true; 101 | } 102 | 103 | // N is the number of items 104 | bool deserialize_vector(Bin* serial, std::vector& vec, int n, int len){ 105 | if (serial== NULL || serial->len != (len * n)){ 106 | return false; 107 | } 108 | 109 | Bin *temp = NULL; 110 | unsigned char *p = serial->data; 111 | for(int i=0; i < n; i++){ 112 | temp = new Bin(len); 113 | memcpy(temp->data, p + (len * i), len); 114 | vec.push_back(temp); 115 | } 116 | 117 | return true; 118 | } 119 | 120 | // N is the number of items 121 | bool serialize_int_vector(Bin* serial, std::vector& vec, int n){ 122 | if (vec.size() != (unsigned int) n){ 123 | printf("serialize_vector: Vec size is %lu, expected %d", vec.size(), n); 124 | return false; 125 | } 126 | 127 | int len = sizeof(int); 128 | serial->len = n * len; 129 | serial->data = (unsigned char *) tmalloc(serial->len); 130 | 131 | unsigned char *p = serial->data; 132 | for(int i=0; i < n; i++){ 133 | 134 | memcpy(p, &vec.at(i), len); 135 | p = p + len; 136 | } 137 | 138 | return true; 139 | } 140 | 141 | // N is the number of items 142 | bool deserialize_int_vector(Bin* serial, std::vector& vec, int n){ 143 | 144 | int len = sizeof(int); 145 | if (serial== NULL || serial->len != (len * n)){ 146 | return false; 147 | } 148 | 149 | int temp; 150 | unsigned char *p = serial->data; 151 | for(int i=0; i < n; i++){ 152 | memcpy(&temp, p + (len * i), len); 153 | vec.push_back(temp); 154 | } 155 | 156 | return true; 157 | } 158 | 159 | 160 | //============================================================================ 161 | -------------------------------------------------------------------------------- /POC_code/src/signer_server.cpp: -------------------------------------------------------------------------------- 1 | #include "signer.h" 2 | #include "strings.h" 3 | #include "network.h" 4 | #include "tx.h" 5 | #include 6 | 7 | //============================================================================ 8 | //======= PROTOCOL 9 | //============================================================================ 10 | 11 | bool exchange_public_key(Signer &signer, std::vector& requests, std::vector& reply){ 12 | 13 | if (requests.size() != 1){ 14 | return false; 15 | } 16 | 17 | reply.push_back(signer.get_pubkey()); 18 | reply.push_back(signer.get_rsa()); 19 | 20 | return true; 21 | } 22 | 23 | bool commitment(Signer &signer, std::vector& requests, std::vector& reply, std::vector& blinded_set){ 24 | 25 | if (requests.size() != 4){ 26 | return false; 27 | } 28 | 29 | // Deserialize 30 | if (!deserialize_vector(requests.at(1), blinded_set, M + N, signer.rsa_len)){ 31 | return false; 32 | } 33 | 34 | signer.set_escrow_redeem_script(requests.at(2)); 35 | signer.set_escrow_funding_tx_id(requests.at(3)); 36 | 37 | delete requests.at(0); 38 | delete requests.at(1); 39 | 40 | // Sign 41 | if (!signer.sign_blinded_set(blinded_set)){ 42 | return false; 43 | } 44 | 45 | // Serialize 46 | Bin* C = new Bin(); 47 | if (!serialize_vector(C, *signer.get_C(), M + N, signer.rsa_len + 8)){ 48 | return false; 49 | } 50 | 51 | Bin* H = new Bin(); 52 | if (!serialize_vector(H, *signer.get_H(), M + N, HASH_160)){ 53 | return false; 54 | } 55 | 56 | reply.push_back(C); 57 | reply.push_back(H); 58 | 59 | return true; 60 | } 61 | 62 | bool verify_fakes(Signer &signer, std::vector& requests, std::vector& reply, std::vector& R){ 63 | 64 | if (requests.size() != 5){ 65 | return false; 66 | } 67 | 68 | // Deserialize to int vectors 69 | std::vector F; 70 | 71 | if(!deserialize_int_vector(requests.at(1), F, N)){ 72 | return false; 73 | } 74 | 75 | if(!deserialize_int_vector(requests.at(2), R, M)){ 76 | return false; 77 | } 78 | 79 | std::vector fake_blinds; 80 | if (!deserialize_vector(requests.at(3), fake_blinds, N, signer.rsa_len)){ 81 | return false; 82 | } 83 | 84 | signer.set_preimage_P2SH(requests.at(4)); 85 | requests.pop_back(); 86 | 87 | // Verify 88 | if (!signer.verify_fakes(fake_blinds, F)){ 89 | return false; 90 | } 91 | 92 | // Serialize 93 | Bin* fake_keys = new Bin(); 94 | if (!serialize_vector(fake_keys, *signer.get_fake_keys(), N, KEY_LEN)){ 95 | return false; 96 | } 97 | 98 | reply.push_back(fake_keys); 99 | reply.push_back(signer.get_escrow_preimage_signature()); 100 | 101 | free_Bins(fake_blinds); 102 | return true; 103 | } 104 | 105 | bool verify_reals(Signer &signer, std::vector& requests, std::vector& reply, std::vector& R){ 106 | 107 | if (requests.size() != 5){ 108 | return false; 109 | } 110 | 111 | signer.set_preimage_redeem_script(requests.at(1)); 112 | signer.set_preimage_signature(requests.at(2)); 113 | Bin* y = requests.at(3); 114 | 115 | std::vector real_blinds; 116 | if (!deserialize_vector(requests.at(4), real_blinds, M, signer.rsa_len)){ 117 | return false; 118 | } 119 | 120 | delete requests.at(4); 121 | 122 | 123 | if(!signer.verify_reals(y, real_blinds, R)){ 124 | printf("Failed in verify\n"); 125 | return false; 126 | } 127 | 128 | Bin* real_keys = new Bin(); 129 | if (!serialize_vector(real_keys, *signer.get_real_keys(), M, KEY_LEN)){ 130 | return false; 131 | } 132 | 133 | reply.push_back(real_keys); 134 | 135 | // Cleanup 136 | free_Bins(real_blinds); 137 | 138 | return true; 139 | } 140 | 141 | //============================================================================ 142 | //======= MAIN 143 | //============================================================================ 144 | 145 | int main () { 146 | 147 | // Prepare our context and socket 148 | zmq::context_t context(1); 149 | zmq::socket_t socket(context, ZMQ_REP); 150 | socket.bind("tcp://*:5558"); 151 | 152 | zmq::message_t fail_msg; 153 | fail_msg.rebuild(26); 154 | memcpy(fail_msg.data(), "Failed to process request.", 26); 155 | 156 | // Handle interrupt 157 | s_catch_signals(); 158 | 159 | std::vector requests; // Received 160 | std::vector reply; // Sent 161 | 162 | Signer* signer; 163 | std::vector blinded_set; 164 | std::vector R; 165 | 166 | 167 | /* 168 | * Not a multithreaded server. 169 | * Will definitly not work correctly 170 | * if multiple clients try to connect 171 | * during a run of the Protocol 172 | * TODO: Turn into multithreaded socket server 173 | * or multithreaded http server after getting 174 | * 1000 tx's through. 175 | */ 176 | while(true) { 177 | 178 | try{ 179 | 180 | receive(socket, requests); 181 | if(memcmp(requests.at(0)->data, "exchange_public_key", 19) == 0){ 182 | 183 | signer = new Signer(); 184 | 185 | if(!exchange_public_key(*signer, requests, reply)){ 186 | printf("Exchange failed\n"); 187 | socket.send(fail_msg); 188 | }else{ 189 | send(socket, reply); 190 | } 191 | 192 | free_Bins(requests); 193 | 194 | } else if(memcmp(requests.at(0)->data, "commitment", 10) == 0){ 195 | 196 | if(signer == NULL || !commitment(*signer, requests, reply, blinded_set)){ 197 | printf("Commitment failed\n"); 198 | socket.send(fail_msg); 199 | free_Bins(blinded_set); 200 | R.clear(); 201 | blinded_set.clear(); 202 | delete signer; 203 | free_Bins(requests); 204 | }else{ 205 | send(socket, reply); 206 | free_Bins(reply); 207 | } 208 | 209 | } else if(memcmp(requests.at(0)->data, "verify_fakes", 12) == 0){ 210 | 211 | if(signer == NULL || !verify_fakes(*signer, requests, reply, R)){ 212 | printf("verify_fakes failed\n"); 213 | delete signer; 214 | socket.send(fail_msg); 215 | 216 | free_Bins(blinded_set); 217 | R.clear(); 218 | blinded_set.clear(); 219 | }else{ 220 | send(socket, reply); 221 | delete reply.at(0); 222 | } 223 | 224 | free_Bins(requests); 225 | 226 | } else if(memcmp(requests.at(0)->data, "verify_reals", 12) == 0){ 227 | 228 | if(signer == NULL || !verify_reals(*signer, requests, reply, R)){ 229 | printf("verify_reals failed\n"); 230 | socket.send(fail_msg); 231 | 232 | free_Bins(blinded_set); 233 | R.clear(); 234 | blinded_set.clear(); 235 | }else{ 236 | send(socket, reply); 237 | free_Bins(reply); 238 | } 239 | 240 | } else if(memcmp(requests.at(0)->data, "escrow_signature", 16) == 0){ 241 | 242 | if(signer == NULL){ 243 | printf("escrow_signature failed\n"); 244 | socket.send(fail_msg); 245 | }else{ 246 | signer->set_escrow_signature(requests.at(1)); 247 | socket.send(fail_msg); 248 | } 249 | 250 | delete signer; 251 | free_Bins(blinded_set); 252 | R.clear(); 253 | blinded_set.clear(); 254 | } 255 | 256 | reply.clear(); 257 | requests.clear(); 258 | } catch(zmq::error_t& e) { 259 | printf("\nZMQ Error: %s\n", e.what()); 260 | free_Bins(requests); 261 | break; 262 | } 263 | 264 | 265 | } 266 | 267 | free_Bins(requests); 268 | 269 | return 0; 270 | } 271 | -------------------------------------------------------------------------------- /POC_code/src/test/bin_test.cpp: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_DYN_LINK 2 | #define BOOST_TEST_MODULE bin 3 | 4 | #include "bin.h" 5 | #include "utility.h" 6 | 7 | #include 8 | 9 | BOOST_AUTO_TEST_CASE(test_empty_constructor){ 10 | 11 | Bin b = Bin(); 12 | 13 | // Define 14 | int msg_len = 13; 15 | unsigned char *msg = (unsigned char *) malloc(msg_len - 1); 16 | 17 | memcpy(msg, "Test Message", msg_len - 1); 18 | 19 | b.data = msg; 20 | b.len = msg_len - 1; 21 | 22 | BOOST_REQUIRE_MESSAGE(memcmp(msg, b.data, b.len) == 0, "test_empty_constructor: Doesn't point to same memory"); 23 | } 24 | 25 | BOOST_AUTO_TEST_CASE(test_int_constructor){ 26 | 27 | // Define 28 | int msg_len = 13; 29 | Bin b = Bin(msg_len - 1); 30 | memcpy(b.data, "Test Message", b.len); 31 | 32 | 33 | BOOST_REQUIRE_MESSAGE(memcmp("Test Message", b.data, b.len) == 0, "test_int_constructor: Doesn't point to same memory"); 34 | } 35 | 36 | BOOST_AUTO_TEST_CASE(test_full_constructor){ 37 | 38 | // Define 39 | int msg_len = 13; 40 | unsigned char *msg = (unsigned char *) malloc(msg_len - 1); 41 | memcpy(msg, "Test Message", msg_len - 1); 42 | 43 | Bin b = Bin(msg_len - 1, msg); 44 | 45 | BOOST_REQUIRE_MESSAGE(memcmp(msg, b.data, b.len) == 0, "test_full_constructor: Doesn't point to same memory"); 46 | } 47 | 48 | BOOST_AUTO_TEST_CASE(test_serialize){ 49 | 50 | unsigned char expected[] = {0x0c, 0x00, 0x00, 0x00, 0x54, 0x65, 0x73, 0x74, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65}; 51 | 52 | // Define 53 | int msg_len = 13; 54 | Bin b = Bin(msg_len - 1); 55 | memcpy(b.data, "Test Message", b.len); 56 | 57 | 58 | unsigned char *serial = b.serialize(); 59 | 60 | BOOST_REQUIRE_MESSAGE(memcmp(expected, serial, b.len + sizeof(int)) == 0, "test_serialize: Doesn't point to same memory"); 61 | 62 | free(serial); 63 | } 64 | 65 | BOOST_AUTO_TEST_CASE(test_equality){ 66 | 67 | Bin b = Bin(); 68 | Bin b1 = Bin(); 69 | Bin b2 = Bin(); 70 | 71 | // Define 72 | int msg_len = 13; 73 | unsigned char *msg = (unsigned char *) malloc(msg_len - 1); 74 | unsigned char *msg1 = (unsigned char *) malloc(msg_len - 1); 75 | unsigned char *msg2 = (unsigned char *) malloc(msg_len - 1); 76 | 77 | memcpy(msg, "Test Message", msg_len - 1); 78 | memcpy(msg1, "Test Message", msg_len - 1); 79 | memcpy(msg2, "TEST MESSAGE", msg_len - 1); 80 | 81 | b.len = msg_len - 1; 82 | b.data = msg; 83 | 84 | b1.len = b.len; 85 | b1.data = msg1; 86 | 87 | b2.len = b.len; 88 | b2.data = msg2; 89 | 90 | 91 | BOOST_REQUIRE_MESSAGE( b == b1, "test_equality: b1 & b should be equal"); 92 | BOOST_REQUIRE_MESSAGE( b != b2, "test_equality: b2 & b shouldn't be equal"); 93 | } 94 | -------------------------------------------------------------------------------- /POC_code/src/test/ec_test.cpp: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_DYN_LINK 2 | #define BOOST_TEST_MODULE EC_Test 3 | 4 | #include "ec.h" 5 | #include 6 | 7 | BOOST_AUTO_TEST_CASE(test_key_generation){ 8 | 9 | bool status; 10 | 11 | // Generate new ec key 12 | const char *suffix = "test"; 13 | status = generate_EC_key(suffix, suffix); 14 | 15 | BOOST_REQUIRE_MESSAGE(status == true, "test_key_generation: Failed to generate EC key"); 16 | 17 | // Try to read key 18 | EC_KEY *key = get_ec_key_by_suffix(suffix, true); 19 | 20 | BOOST_REQUIRE_MESSAGE(key != NULL, "test_key_generation: Failed to get private EC key"); 21 | 22 | EC_KEY_free(key); 23 | } 24 | 25 | BOOST_AUTO_TEST_CASE(test_sign_verify) 26 | { 27 | // Get private key 28 | const char *suffix = "test"; 29 | EC_KEY * key = get_ec_key_by_suffix(suffix, true); 30 | 31 | BOOST_REQUIRE_MESSAGE(key != NULL, "test_sign_verify: Failed to get private EC key"); 32 | 33 | // Sign 34 | Bin hash = Bin(32); 35 | memcpy(hash.data, "c7fbca202a95a570285e3d700eb04ca2", hash.len); 36 | 37 | ECDSA_SIG * signature = EC_sign(key, &hash); 38 | 39 | BOOST_REQUIRE_MESSAGE(signature != NULL, "test_sign_verify: Failed to sign message"); 40 | 41 | // Cleanup 42 | EC_KEY_free(key); 43 | 44 | // Get key 45 | key = get_ec_key_by_suffix(suffix, false); 46 | 47 | BOOST_REQUIRE_MESSAGE(key != NULL, "test_sign_verify: Failed get public EC key"); 48 | 49 | // Verify 50 | bool s = EC_verify(key, &hash, signature); 51 | 52 | BOOST_REQUIRE_MESSAGE(s == true, "test_sign_verify: Failed to verify signature"); 53 | 54 | // Serialize + deserialize 55 | Bin serial = Bin(); 56 | 57 | s = serialize_ec_signature(signature, &serial); 58 | BOOST_REQUIRE_MESSAGE(s == true, "test_sign_verify: Failed serialize signature"); 59 | 60 | // printf("serial signature is:\n"); 61 | // serial.print(); 62 | 63 | ECDSA_SIG *sig2; 64 | sig2 = deserialize_ec_signature(&serial); 65 | BOOST_REQUIRE_MESSAGE(sig2 != NULL, "test_sign_verify: Failed to deserialize signature"); 66 | 67 | // Verify 68 | s = EC_verify(key, &hash, sig2); 69 | 70 | BOOST_REQUIRE_MESSAGE(s == true, "test_sign_verify: Failed to verify signature after serialization"); 71 | 72 | // Cleanup 73 | ECDSA_SIG_free(signature); 74 | ECDSA_SIG_free(sig2); 75 | EC_KEY_free(key); 76 | 77 | } 78 | 79 | BOOST_AUTO_TEST_CASE(test_sig_convert) 80 | { 81 | // Get private key 82 | const char *suffix = "test"; 83 | EC_KEY * key = get_ec_key_by_suffix(suffix, true); 84 | 85 | BOOST_REQUIRE_MESSAGE(key != NULL, "test_sign_verify: Failed to get private EC key"); 86 | 87 | // Sign 88 | Bin hash = Bin(32); 89 | memcpy(hash.data, "c7fbca202a95a570285e3d700eb04ca2", hash.len); 90 | 91 | // printf("Hash is:\n"); 92 | // hash.print(); 93 | 94 | ECDSA_SIG * signature = EC_sign(key, &hash); 95 | 96 | BOOST_REQUIRE_MESSAGE(signature != NULL, "test_sign_verify: Failed to sign message"); 97 | 98 | // Convert sig to standard format 99 | convert_sig_to_standard_der(signature, key); 100 | 101 | 102 | // Cleanup 103 | EC_KEY_free(key); 104 | 105 | // Get key 106 | key = get_ec_key_by_suffix(suffix, false); 107 | 108 | BOOST_REQUIRE_MESSAGE(key != NULL, "test_sign_verify: Failed get public EC key"); 109 | 110 | // Verify 111 | bool s = EC_verify(key, &hash, signature); 112 | 113 | BOOST_REQUIRE_MESSAGE(s == true, "test_sign_verify: Failed to verify signature"); 114 | 115 | // Cleanup 116 | ECDSA_SIG_free(signature); 117 | EC_KEY_free(key); 118 | 119 | } 120 | 121 | 122 | BOOST_AUTO_TEST_CASE(test_sig_serialize) 123 | { 124 | // Get private key 125 | const char *suffix = "test"; 126 | EC_KEY * key = get_ec_key_by_suffix(suffix, true); 127 | 128 | BOOST_REQUIRE_MESSAGE(key != NULL, "test_sig_serialize: Failed to get private EC key"); 129 | 130 | // Sign 131 | Bin hash = Bin(32); 132 | memcpy(hash.data, "c7fbca202a95a570285e3d700eb04ca2", hash.len); 133 | 134 | // printf("Hash is:\n"); 135 | // hash.print(); 136 | 137 | ECDSA_SIG * signature = EC_sign(key, &hash); 138 | 139 | BOOST_REQUIRE_MESSAGE(signature != NULL, "test_sig_serialize: Failed to sign message"); 140 | 141 | // Cleanup 142 | EC_KEY_free(key); 143 | 144 | // Get key 145 | key = get_ec_key_by_suffix(suffix, false); 146 | 147 | BOOST_REQUIRE_MESSAGE(key != NULL, "test_sig_serialize: Failed get public EC key"); 148 | 149 | // Verify 150 | bool s = EC_verify(key, &hash, signature); 151 | 152 | BOOST_REQUIRE_MESSAGE(s == true, "test_sig_serialize: Failed to verify signature"); 153 | 154 | // Serialize + deserialize 155 | Bin serial = Bin(); 156 | 157 | s = serialize_ec_signature(signature,& serial); 158 | BOOST_REQUIRE_MESSAGE(s == true, "test_sig_serialize: Failed serialize signature"); 159 | 160 | ECDSA_SIG *sig2; 161 | sig2 = deserialize_ec_signature(&serial); 162 | BOOST_REQUIRE_MESSAGE(sig2 != NULL, "test_sig_serialize: Failed to deserialize signature"); 163 | 164 | // Verify 165 | s = EC_verify(key, &hash, sig2); 166 | 167 | BOOST_REQUIRE_MESSAGE(s == true, "test_sig_serialize: Failed to verify signature after serialization"); 168 | 169 | // Cleanup 170 | ECDSA_SIG_free(signature); 171 | ECDSA_SIG_free(sig2); 172 | EC_KEY_free(key); 173 | } 174 | 175 | BOOST_AUTO_TEST_CASE(test_no_nonce_reuse) 176 | { 177 | 178 | const char *suffix = "test"; 179 | EC_KEY * key = get_ec_key_by_suffix(suffix, true); 180 | 181 | // Sign 182 | Bin hash1 = Bin(32); 183 | memcpy(hash1.data, "19ebca000095a201285e3d7002204edf", hash1.len); 184 | 185 | Bin hash2 = Bin(32); 186 | memcpy(hash2.data, "19ebca000095a201285e3d7002204edf", hash2.len); 187 | 188 | ECDSA_SIG * signature1 = EC_sign(key, &hash1); 189 | ECDSA_SIG * signature2 = EC_sign(key, &hash2); 190 | 191 | Bin serial1 = Bin(); 192 | Bin serial2 = Bin(); 193 | 194 | serialize_ec_signature(signature1, &serial1); 195 | serialize_ec_signature(signature2, &serial2); 196 | 197 | BOOST_CHECK_MESSAGE(memcmp(serial1.data, serial2.data, 32)!=0, "ECDSA nonces should not be the same"); 198 | 199 | 200 | // Cleanup 201 | ECDSA_SIG_free(signature1); 202 | ECDSA_SIG_free(signature2); 203 | EC_KEY_free(key); 204 | } 205 | 206 | BOOST_AUTO_TEST_CASE(test_key_from_secret) 207 | { 208 | 209 | Bin* secret = new Bin(20); 210 | memcpy(secret->data, "TumbleBit_4241304455", secret->len); 211 | EC_KEY * key = get_key_from_secret(secret); 212 | 213 | Bin* pubkey = new Bin(); 214 | bool status = serialize_ec_publickey(key, pubkey); 215 | BOOST_CHECK_MESSAGE(status, "test_key_from_secret: Failed to serialize public key"); 216 | 217 | 218 | char* pubkey_str = get_hex_str(pubkey); 219 | char* expected = (char *) "046ee5d82c7fece37c8f98f36bc619d2484e643ac10cb59df4ae9d4ae76816105ce2c85f960ad2726e058be242bc3b94e12c8ad033b9432ccb98fa61433557d933"; 220 | 221 | 222 | BOOST_CHECK_MESSAGE(strcmp(pubkey_str, expected) == 0, "test_key_from_secret: Public keys don't match"); 223 | 224 | delete pubkey; 225 | delete secret; 226 | free(pubkey_str); 227 | EC_KEY_free(key); 228 | } 229 | -------------------------------------------------------------------------------- /POC_code/src/test/encrypt_test.cpp: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_DYN_LINK 2 | #define BOOST_TEST_MODULE encrypt_test 3 | 4 | #include "encrypt.h" 5 | #include 6 | 7 | BOOST_AUTO_TEST_CASE(test_encrypt_xor){ 8 | 9 | bool status; 10 | 11 | Bin *message = new Bin(); 12 | Bin *key = new Bin(); 13 | Bin *cipher = new Bin(); 14 | Bin *decrypted = new Bin(); 15 | 16 | key->len = 2048/8; 17 | key->data = get_random(2048); 18 | 19 | message->len = 64; 20 | message->data = get_random(512); 21 | 22 | // Encrypt 23 | status = encrypt(message, key, cipher); 24 | BOOST_REQUIRE_MESSAGE(status == true, "test_encrypt: Failed to encrypt message"); 25 | BOOST_REQUIRE_MESSAGE(cipher != NULL, "test_encrypt: Cipher shouldn't be null"); 26 | 27 | // Decrypt 28 | status = decrypt(cipher, key, decrypted); 29 | BOOST_REQUIRE_MESSAGE(status == true, "test_encrypt: Failed to decrypt message"); 30 | 31 | 32 | // Verify 33 | BOOST_REQUIRE_MESSAGE(*message == *decrypted, "test_encrypt: Failed to decrypt message"); 34 | 35 | // Cleanup 36 | delete message; 37 | delete key; 38 | delete cipher; 39 | delete decrypted; 40 | } 41 | 42 | BOOST_AUTO_TEST_CASE(test_encrypt_chacha){ 43 | 44 | bool status; 45 | 46 | Bin *message = NULL; 47 | Bin *key = new Bin(); 48 | Bin *cipher = new Bin(); 49 | Bin *decrypted = new Bin(); 50 | 51 | int len = 5; 52 | message = new Bin(len); 53 | memcpy(message->data, "test1", len); 54 | 55 | // printf("Message is:\n"); 56 | // message->print(); 57 | 58 | // Encrypt 59 | status = encrypt_chacha(message, key, cipher); 60 | BOOST_REQUIRE_MESSAGE(status == true, "test_encrypt: Failed to encrypt message"); 61 | BOOST_REQUIRE_MESSAGE(cipher != NULL, "test_encrypt: Cipher shouldn't be null"); 62 | 63 | // printf("Cipher is %d:\n", cipher->len); 64 | // cipher->print(); 65 | // 66 | // printf("Key is %d:\n", key->len); 67 | // key->print(); 68 | 69 | // Decrypt 70 | status = decrypt_chacha(cipher, key, decrypted); 71 | BOOST_REQUIRE_MESSAGE(status == true, "test_encrypt: Failed to decrypt message"); 72 | 73 | // printf("Plain_text is:\n"); 74 | // decrypted->print(); 75 | 76 | // Verify 77 | BOOST_REQUIRE_MESSAGE(*message == *decrypted, "test_encrypt: Failed to decrypt message"); 78 | 79 | // Cleanup 80 | delete message; 81 | delete key; 82 | delete cipher; 83 | delete decrypted; 84 | } 85 | 86 | BOOST_AUTO_TEST_CASE(test_xor){ 87 | 88 | int len = 12; 89 | int bits = len * 8; 90 | 91 | Bin* key = new Bin(); 92 | Bin* enc = new Bin(); 93 | Bin* dec = new Bin(); 94 | Bin* message = new Bin(len); 95 | memcpy(message->data, "TESTMESSAGE", len); 96 | 97 | 98 | key->len = len; 99 | key->data = get_random(bits); 100 | 101 | enc->len = len; 102 | enc->data = XOR_enc_dec(message, key, len); 103 | 104 | dec->len = len; 105 | dec->data = XOR_enc_dec(enc, key, len); 106 | 107 | 108 | BOOST_REQUIRE_MESSAGE(*dec == *message, "test_xor_encrypt: Failed to decrypt message"); 109 | 110 | // Cleanup 111 | delete key; 112 | delete enc; 113 | delete dec; 114 | delete message; 115 | } 116 | -------------------------------------------------------------------------------- /POC_code/src/test/hash_test.cpp: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_DYN_LINK 2 | #define BOOST_TEST_MODULE hash_test 3 | 4 | #include "hash.h" 5 | #include "utility.h" 6 | #include 7 | BOOST_AUTO_TEST_CASE(test_hash256){ 8 | unsigned char raw_tx[371] = {0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x25, 0x3a, 9 | 0x70, 0x28, 0x74, 0xff, 0xd4, 0xd6, 0x1f, 0x07, 10 | 0x5e, 0x88, 0x23, 0x21, 0x54, 0x64, 0x3a, 0x7e, 11 | 0x1e, 0x85, 0x5f, 0x5b, 0x1a, 0xa5, 0x81, 0x95, 12 | 0xa0, 0x5e, 0x04, 0x1b, 0xdb, 0x01, 0x00, 0x00, 13 | 0x00, 0xfd, 0x1c, 0x01, 0x48, 0x30, 0x45, 0x02, 14 | 0x21, 0x00, 0x94, 0xf2, 0xbc, 0x26, 0xcc, 0x69, 15 | 0x6f, 0x0e, 0xa2, 0xb7, 0xf0, 0xe1, 0xe2, 0x90, 16 | 0x15, 0xe6, 0xa6, 0x51, 0x3a, 0xe5, 0x56, 0x9d, 17 | 0x1c, 0x6f, 0x5e, 0x5f, 0x06, 0xf6, 0xd2, 0x13, 18 | 0x7f, 0x1f, 0x02, 0x20, 0x30, 0x9e, 0x1f, 0xa6, 19 | 0x36, 0xf5, 0xce, 0x91, 0xd1, 0xf3, 0x8a, 0xf7, 20 | 0x15, 0xae, 0xbe, 0xfc, 0x32, 0x4f, 0xf2, 0xc0, 21 | 0x49, 0xce, 0x62, 0xd2, 0x1e, 0xcd, 0xb2, 0x08, 22 | 0xa1, 0xa4, 0x4f, 0x9d, 0x01, 0x00, 0x4c, 0xd0, 23 | 0x63, 0x52, 0x41, 0x04, 0x35, 0xfd, 0x62, 0x87, 24 | 0x13, 0x5f, 0x10, 0x70, 0x1b, 0x72, 0xc3, 0xd6, 25 | 0x17, 0xe4, 0xad, 0xe6, 0x38, 0x69, 0x1e, 0x59, 26 | 0x67, 0x31, 0xe7, 0x9f, 0x64, 0xda, 0x64, 0x90, 27 | 0xbb, 0x42, 0xb3, 0xa8, 0xe8, 0xe6, 0xf9, 0x01, 28 | 0xaf, 0x05, 0xbe, 0xb1, 0x6a, 0xe9, 0x7d, 0x6e, 29 | 0xac, 0xa0, 0x6c, 0x2f, 0xc0, 0x0b, 0x8c, 0xba, 30 | 0x65, 0xf6, 0x3e, 0xf2, 0x28, 0xdd, 0xb3, 0x80, 31 | 0x36, 0x75, 0x34, 0x7e, 0x41, 0x04, 0xc5, 0xa8, 32 | 0xdd, 0x46, 0xdb, 0x19, 0x75, 0xc4, 0x86, 0xe6, 33 | 0xfc, 0xab, 0x75, 0x44, 0x91, 0x73, 0xb8, 0x21, 34 | 0x7c, 0x93, 0x85, 0xea, 0xe3, 0x90, 0xff, 0xa1, 35 | 0xa9, 0x0b, 0x65, 0xd6, 0xcc, 0x1d, 0x9f, 0x8b, 36 | 0xa8, 0x74, 0x0d, 0x76, 0x42, 0x91, 0x82, 0xc8, 37 | 0xf9, 0x83, 0xc0, 0xad, 0x90, 0xc4, 0xe9, 0xed, 38 | 0x64, 0xe4, 0x4d, 0xc6, 0x46, 0xd5, 0xd2, 0x29, 39 | 0x3f, 0x92, 0x41, 0x31, 0x5c, 0x05, 0x52, 0xae, 40 | 0x67, 0x5a, 0xb1, 0x75, 0x41, 0x04, 0x35, 0xfd, 41 | 0x62, 0x87, 0x13, 0x5f, 0x10, 0x70, 0x1b, 0x72, 42 | 0xc3, 0xd6, 0x17, 0xe4, 0xad, 0xe6, 0x38, 0x69, 43 | 0x1e, 0x59, 0x67, 0x31, 0xe7, 0x9f, 0x64, 0xda, 44 | 0x64, 0x90, 0xbb, 0x42, 0xb3, 0xa8, 0xe8, 0xe6, 45 | 0xf9, 0x01, 0xaf, 0x05, 0xbe, 0xb1, 0x6a, 0xe9, 46 | 0x7d, 0x6e, 0xac, 0xa0, 0x6c, 0x2f, 0xc0, 0x0b, 47 | 0x8c, 0xba, 0x65, 0xf6, 0x3e, 0xf2, 0x28, 0xdd, 48 | 0xb3, 0x80, 0x36, 0x75, 0x34, 0x7e, 0xac, 0x68, 49 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x38, 0x01, 50 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 51 | 0x14, 0xb0, 0xf2, 0x8c, 0x75, 0x33, 0x3e, 0x6f, 52 | 0x7a, 0x65, 0xc9, 0x9e, 0x7e, 0xb1, 0xaa, 0x5c, 53 | 0x9d, 0x6b, 0x98, 0xdb, 0x5a, 0x88, 0xac, 0x1e, 54 | 0x00, 0x00, 0x00}; 55 | 56 | Bin* tx = new Bin(); 57 | tx->len = 371; 58 | tx->data = raw_tx; 59 | 60 | Bin* tx_id = hash256(tx); 61 | 62 | unsigned char * tx_id_str = (unsigned char *) get_hex_str_rev(tx_id); 63 | 64 | BOOST_CHECK_MESSAGE(memcmp(tx_id_str, "23daa9d3868255bab14d5dfe46f7fb787aaef49b17d0014902e36e4491440311", HASH_256 * 2) == 0 , "test_txid: TX ID's don't match"); 65 | delete tx_id; 66 | 67 | tx->len = 0; 68 | delete tx; 69 | free(tx_id_str); 70 | } 71 | 72 | BOOST_AUTO_TEST_CASE(test_hmac){ 73 | 74 | // From https://tools.ietf.org/html/rfc4231 75 | unsigned char key[20] = {0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 76 | 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 77 | 0xaa, 0xaa, 0xaa, 0xaa}; 78 | 79 | unsigned char data[50] = {0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 80 | 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 81 | 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 82 | 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 83 | 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 84 | 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 85 | 0xdd, 0xdd}; 86 | 87 | unsigned char e[32] = {0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46, 88 | 0x85, 0x4d, 0xb8, 0xeb, 0xd0, 0x91, 0x81, 0xa7, 89 | 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22, 90 | 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe}; 91 | 92 | 93 | Bin* bkey = new Bin(); 94 | bkey->len = 20; 95 | bkey->data = key; 96 | 97 | Bin* msg = new Bin(); 98 | msg->len = 50; 99 | msg->data = data; 100 | 101 | Bin* output = hmac256(msg, bkey); 102 | 103 | BOOST_CHECK_MESSAGE(memcmp(e, output->data, 32) == 0 , "test_hmac: Not expected"); 104 | 105 | // Cleanup 106 | msg->data = NULL; 107 | bkey->data = NULL; 108 | delete msg; 109 | delete bkey; 110 | delete output; 111 | } 112 | -------------------------------------------------------------------------------- /POC_code/src/test/scc_test.cpp: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_DYN_LINK 2 | #define BOOST_TEST_MODULE scc 3 | 4 | #include 5 | #include "hash.h" 6 | #include "scc.h" 7 | 8 | #include 9 | 10 | int myrandom (int i) { return rand()%i;} 11 | 12 | BOOST_AUTO_TEST_CASE(test_find_indices){ 13 | 14 | int len = 5; 15 | 16 | Bin* temp; 17 | 18 | std::vector v1; 19 | std::vector v2; 20 | std::vector v3; 21 | 22 | // Vector 1 23 | temp = new Bin(len); 24 | memcpy(temp->data, "test1", len); 25 | v1.push_back(temp); 26 | 27 | temp = new Bin(len); 28 | memcpy(temp->data, "test2", len); 29 | v1.push_back(temp); 30 | 31 | temp = new Bin(len); 32 | memcpy(temp->data, "test3", len); 33 | v1.push_back(temp); 34 | 35 | // Vector 2 36 | temp = new Bin(len); 37 | memcpy(temp->data, "test4", len); 38 | v2.push_back(temp); 39 | 40 | temp = new Bin(len); 41 | memcpy(temp->data, "test5", len); 42 | v2.push_back(temp); 43 | 44 | temp = new Bin(len); 45 | memcpy(temp->data, "test6", len); 46 | v2.push_back(temp); 47 | 48 | 49 | // Combine v1 & v2 50 | v3.insert(v3.end(), v1.begin(), v1.end()); 51 | v3.insert(v3.end(), v2.begin(), v2.end()); 52 | 53 | // Permute 54 | random_shuffle(v3.begin(),v3.end(), myrandom); 55 | 56 | 57 | std::vector i1; 58 | std::vector i2; 59 | int j = 0; 60 | 61 | find_indices(v3, v1, i1); 62 | find_indices(v3, v2, i2); 63 | 64 | for (unsigned int i = 0; i < v1.size(); i++){ 65 | j = i1[i]; 66 | BOOST_REQUIRE_MESSAGE(memcmp(v1[i]->data, v3[j]->data, len) == 0, "test_find_indices: Indices don't match"); 67 | } 68 | 69 | for (unsigned int i = 0; i < v2.size(); i++){ 70 | j = i2[i]; 71 | BOOST_REQUIRE_MESSAGE(memcmp(v2[i]->data, v3[j]->data, len) == 0, "test_find_indices: Indices don't match"); 72 | } 73 | 74 | free_Bins(v1); 75 | free_Bins(v2); 76 | } 77 | 78 | 79 | BOOST_AUTO_TEST_CASE(test_blind_vectors){ 80 | 81 | Bin* message; 82 | Bin* hash; 83 | int len = 5; 84 | bool status; 85 | 86 | std::vector blinded; 87 | std::vector sigs; 88 | std::vector unblinded; 89 | std::vector blinds; 90 | 91 | // Setup RSA 92 | RSA * rsa = get_private_rsa(2048, (char *)"test"); 93 | BOOST_REQUIRE_MESSAGE(rsa != NULL, "test_blind_vectors: Failed load RSA key"); 94 | 95 | // Setup vector 96 | message = new Bin(len); 97 | memcpy(message->data, "test1", len); 98 | 99 | // Hash message 100 | int rsa_len = RSA_size(rsa); 101 | hash = full_domain_hash(rsa, message, EVP_sha512()); 102 | BOOST_REQUIRE_MESSAGE(hash->data != NULL, "test_blind_vectors: Failed to hash message"); 103 | 104 | 105 | // Setup blinds 106 | status = create_blinds(rsa, 3, blinds); 107 | BOOST_REQUIRE_MESSAGE(status == true, "test_blind_vectors: Failed to create blinds"); 108 | 109 | // Apply blinds 110 | status = apply_blinds(hash, blinds, blinded); 111 | BOOST_REQUIRE_MESSAGE(status == true, "test_blind_vectors: Failed to apply blinds"); 112 | 113 | 114 | // Sign blinded messages 115 | Bin* temp; 116 | for(unsigned int i=0; i < blinds.size(); i++){ 117 | temp = new Bin(rsa_len); 118 | status = sign(rsa, blinded.at(i), temp); 119 | BOOST_REQUIRE_MESSAGE(status == true, "test_blind_vectors: Failed to sign blinds"); 120 | sigs.push_back(temp); 121 | } 122 | 123 | // Remove blinds 124 | status = remove_blinds(sigs, rsa_len, blinds, unblinded); 125 | BOOST_REQUIRE_MESSAGE(status == true, "test_blind_vectors: Failed to remove blinds"); 126 | 127 | // Verify unblinded message 128 | for(unsigned int i=0; i < unblinded.size(); i++){ 129 | BOOST_REQUIRE_MESSAGE(memcmp(unblinded.at(i)->data, hash->data, len) == true, "test_blind_vectors: Unblinded != message"); 130 | } 131 | 132 | // Cleanup 133 | delete message; 134 | delete hash; 135 | free_Bins(unblinded); 136 | free_Bins(blinded); 137 | free_Bins(sigs); 138 | free_blinds(blinds); 139 | RSA_free(rsa); 140 | 141 | } 142 | 143 | BOOST_AUTO_TEST_CASE(test_key_deserialization){ 144 | 145 | // Setup 146 | bool status; 147 | int n_keys = 15; 148 | int key_len = 32; // 256 bits 149 | Bin *serial_keys = new Bin(key_len * n_keys); 150 | 151 | std::vector keys; 152 | std::vector expected_keys; 153 | 154 | // Expected keys 155 | char *temp_str = NULL; 156 | Bin *temp_h = NULL; 157 | for(int i=1; i <= n_keys; i++){ 158 | 159 | // Create 160 | asprintf (&temp_str, "test%d", i); 161 | 162 | // Hash 163 | temp_h = new Bin(SHA256_DIGEST_LENGTH); 164 | SHA256((unsigned char *)temp_str, strlen(temp_str), temp_h->data); 165 | 166 | // Add 167 | expected_keys.push_back(temp_h); 168 | 169 | free(temp_str); 170 | } 171 | 172 | // Get key from file 173 | FILE *file; 174 | file = fopen("./keys/keys.bin","rb"); 175 | fread(serial_keys->data, serial_keys->len, 1, file); 176 | fclose(file); 177 | 178 | // Deserialize 179 | status = deserialize_vector(serial_keys, keys, n_keys, key_len); 180 | BOOST_REQUIRE_MESSAGE(status == true, "test_key_deserialization: Failed to deserialize keys"); 181 | 182 | // Check 183 | for(int i=0; i < n_keys; i++){ 184 | status = (*expected_keys.at(i) == *keys.at(i)); 185 | BOOST_REQUIRE_MESSAGE(status == true, "test_key_deserialization: key doesn't match expected key"); 186 | } 187 | 188 | // Cleanup 189 | delete serial_keys; 190 | free_Bins(expected_keys); 191 | free_Bins(keys); 192 | 193 | } 194 | 195 | BOOST_AUTO_TEST_CASE(test_serialization){ 196 | 197 | int n = 10; 198 | int len = 5; 199 | bool status; 200 | 201 | std::vector vec; 202 | std::vector vec_d; 203 | Bin *serial = new Bin(); 204 | 205 | // Setup vector 206 | char *temp_str = NULL; 207 | Bin *temp_bin = NULL; 208 | for (int i = 0; i < n; i++){ 209 | 210 | asprintf (&temp_str, "test%d", i); 211 | temp_bin = new Bin(len, (unsigned char *) temp_str); 212 | 213 | vec.push_back(temp_bin); 214 | } 215 | 216 | // Serialize 217 | status = serialize_vector(serial, vec, n, len); 218 | BOOST_REQUIRE_MESSAGE(status == true, "test_serialization: Failed to serialize vector"); 219 | 220 | // Deserialize 221 | status = deserialize_vector(serial, vec_d, n, len); 222 | BOOST_REQUIRE_MESSAGE(status == true, "test_serialization: Failed to deserialize vector"); 223 | 224 | // Compare vectors 225 | for (int i = 0; i < n; i++){ 226 | BOOST_REQUIRE_MESSAGE(*vec.at(i) == *vec_d.at(i), "test_serialization: vectors don't match"); 227 | } 228 | 229 | 230 | // Cleanup 231 | delete serial; 232 | free_Bins(vec); 233 | free_Bins(vec_d); 234 | } 235 | 236 | BOOST_AUTO_TEST_CASE(test_int_serialization){ 237 | 238 | int n = 10; 239 | bool status; 240 | 241 | std::vector vec; 242 | std::vector vec_d; 243 | Bin *serial = new Bin(); 244 | 245 | // Setup vector 246 | for (int i = 0; i < n; i++){ 247 | vec.push_back(i); 248 | } 249 | 250 | // Serialize 251 | status = serialize_int_vector(serial, vec, n); 252 | BOOST_REQUIRE_MESSAGE(status == true, "test_int_serialization: Failed to serialize vector"); 253 | 254 | // Deserialize 255 | status = deserialize_int_vector(serial, vec_d, n); 256 | BOOST_REQUIRE_MESSAGE(status == true, "test_int_serialization: Failed to deserialize vector"); 257 | 258 | // Compare vectors 259 | for (int i = 0; i < n; i++){ 260 | BOOST_REQUIRE_MESSAGE(vec.at(i) == vec_d.at(i), "test_int_serialization: vectors don't match"); 261 | } 262 | 263 | 264 | // Cleanup 265 | delete serial; 266 | } 267 | -------------------------------------------------------------------------------- /POC_code/src/test/utility_test.cpp: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_DYN_LINK 2 | #define BOOST_TEST_MODULE utility_test 3 | 4 | #include 5 | #include "utility.h" 6 | 7 | BOOST_AUTO_TEST_CASE(test_BNToBin){ 8 | 9 | BN_CTX* ctx = BN_CTX_new(); 10 | BN_CTX_start(ctx); 11 | BIGNUM* bn1 = BN_CTX_get(ctx); 12 | BIGNUM* bn2 = BN_CTX_get(ctx); 13 | BIGNUM* bn3 = BN_CTX_get(ctx); 14 | 15 | char *temp; 16 | 17 | BOOST_REQUIRE_MESSAGE(ctx != NULL , "test_BNToBin: Failed to setup context"); 18 | BOOST_REQUIRE_MESSAGE(bn1 != NULL && bn2 != NULL && bn3 != NULL , "test_BNToBin: Failed to setup bignums"); 19 | 20 | 21 | BN_zero(bn1); 22 | BN_ULONG longword = 0x0301FF00; 23 | BN_add_word(bn1, longword); 24 | 25 | //print_BN(bn1); 26 | 27 | int data_len = 256; 28 | unsigned char data1[data_len]; 29 | unsigned char data2[data_len]; 30 | 31 | memset(data1, 0xFF, data_len); 32 | memset(data2, 0xFF, data_len); 33 | 34 | int data1_len = BNToBin(bn1, data1, data_len); 35 | int data2_len = BN_bn2bin(bn1, data2); 36 | 37 | if (data1_len != data_len){ 38 | printf("Unexpected write BNToBin length actual: %d expected: %d \n", data1_len, data_len); 39 | } 40 | BOOST_CHECK(data1_len == data_len); 41 | 42 | int bn1_len = BN_num_bytes(bn1); 43 | if (data2_len != bn1_len){ 44 | printf("Unexpected write BN_bn2bin length actual: %d expected: %d \n", data2_len, bn1_len); 45 | } 46 | BOOST_CHECK(data2_len == bn1_len); 47 | 48 | 49 | BN_bin2bn(data2, data_len, bn2); 50 | temp = BN_bn2hex(bn2); 51 | char* expected_bn2_str = (char*) "0301FF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"; 52 | BOOST_CHECK_MESSAGE(memcmp(temp, expected_bn2_str, data_len) == 0 , "test_BNToBin: BN_bin2bn produced an unexpected input"); 53 | free(temp); 54 | 55 | BN_bin2bn(data1, data_len, bn3); 56 | temp = BN_bn2hex(bn3); 57 | char* expected_bn3_str = (char*) "0301FF00"; 58 | BOOST_CHECK_MESSAGE(memcmp(temp, expected_bn3_str, bn1_len) == 0 , "test_BNToBin: BNToBin serialization failure"); 59 | free(temp); 60 | 61 | // Cleanup 62 | BN_CTX_end(ctx); 63 | BN_CTX_free(ctx); 64 | 65 | } 66 | -------------------------------------------------------------------------------- /POC_code/src/tumbler.cpp: -------------------------------------------------------------------------------- 1 | #include "tumbler.h" 2 | #include "timer.h" 3 | 4 | //============================================================================ 5 | //======= Constructors 6 | //============================================================================ 7 | 8 | Tumbler::Tumbler(){ 9 | verified = false; 10 | const char* suffix = (const char*)"tumbler"; 11 | 12 | // RSA 13 | rsa = get_private_rsa(2048, (char *)suffix); 14 | assert(rsa != NULL); 15 | rsa_len = RSA_size(rsa); 16 | 17 | int len = i2d_RSAPublicKey(rsa, NULL); 18 | rsa_pub = new Bin(len); 19 | unsigned char *p; 20 | p = rsa_pub->data; 21 | i2d_RSAPublicKey(rsa, &p); 22 | 23 | // EC 24 | if(!generate_EC_key(suffix, suffix)){ 25 | exit(-1); 26 | } 27 | ec = get_ec_key_by_suffix(suffix, true); 28 | assert(ec!=NULL); 29 | 30 | ec_pubkey = new Bin(); 31 | bool status = serialize_ec_publickey(ec, ec_pubkey); 32 | assert(status != false); 33 | 34 | address = new Bin(strlen(TUMBLER_ADDRESS)); 35 | memcpy(address->data, TUMBLER_ADDRESS, address->len); 36 | 37 | p2sh_address = NULL; 38 | redeem_script = NULL; 39 | funding_tx_id = NULL; 40 | lock_time = NULL; 41 | 42 | } 43 | 44 | Tumbler::~Tumbler(){ 45 | RSA_free(rsa); 46 | EC_KEY_free(ec); 47 | 48 | delete_bin(rsa_pub); 49 | delete_bin(ec_pubkey); 50 | delete_bin(address); 51 | 52 | delete_bin(redeem_script); 53 | delete_bin(funding_tx_id); 54 | delete_bin(p2sh_address); 55 | delete_bin(lock_time); 56 | 57 | delete_bin(h_r); 58 | delete_bin(h_f); 59 | 60 | free_Bins(epsilon); 61 | free_Bins(quotients); 62 | free_Bins(C); 63 | free_Bins(Z); 64 | 65 | } 66 | 67 | //============================================================================ 68 | //======= Private Functions 69 | //============================================================================ 70 | 71 | bool Tumbler::create_quotients(){ 72 | 73 | Timer timer = Timer((char *) "wrapper_create_quotients\0"); 74 | timer.start(); 75 | 76 | int j, j2, s; 77 | 78 | BN_CTX *ctx; 79 | BIGNUM *q1; 80 | BIGNUM *q2; 81 | 82 | Bin* q_str; 83 | 84 | // Create context 85 | if ((ctx = BN_CTX_new()) == NULL){ 86 | return false; 87 | } 88 | 89 | BN_CTX_start(ctx); 90 | 91 | q1 = BN_CTX_get(ctx); 92 | q2 = BN_CTX_get(ctx); 93 | 94 | if(q1 == NULL || q2 == NULL){ 95 | return false; 96 | } 97 | 98 | 99 | for (unsigned int i=0; i < R.size() - 1; i++){ 100 | j = R.at(i); 101 | j2 = R.at(i + 1); 102 | 103 | // Convert to BN 104 | if (BN_bin2bn(epsilon.at(j)->data, rsa_len, q1) == NULL){ 105 | return false; 106 | } 107 | 108 | if (BN_bin2bn(epsilon.at(j2)->data, rsa_len, q2) == NULL){ 109 | return false; 110 | } 111 | 112 | // Invert q1 113 | BN_mod_inverse(q1, q1, rsa->n, ctx); 114 | 115 | // Multiplty q2 * (q1)^-1 116 | s = BN_mod_mul(q1, q1, q2,rsa->n, ctx); 117 | if (s != 1){ 118 | printf("create_quotients: couldn't multiply q1 & q2.\n"); 119 | return false; 120 | } 121 | 122 | // Convert result 123 | q_str = new Bin(rsa_len); 124 | BNToBin(q1, q_str->data, rsa_len); 125 | 126 | 127 | // Save result 128 | quotients.push_back(q_str); 129 | } 130 | 131 | BN_free(q1); 132 | BN_free(q2); 133 | 134 | BN_CTX_end(ctx); 135 | BN_CTX_free(ctx); 136 | 137 | timer.end(); 138 | 139 | return true; 140 | } 141 | 142 | bool Tumbler::create_refund_tx(){ 143 | Bin* temp_sighash = new Bin(); 144 | Bin* temp_raw_tx = new Bin(); 145 | 146 | if (!get_refund_tx(redeem_script, address, funding_tx_id, lock_time, temp_raw_tx, temp_sighash)){ 147 | return false; 148 | } 149 | 150 | // Sign 151 | Bin* serial_sig = new Bin(); 152 | ECDSA_SIG * sig = NULL; 153 | 154 | sig = EC_sign(ec, temp_sighash); 155 | if (sig == NULL){ 156 | return false; 157 | } 158 | 159 | convert_sig_to_standard_der(sig, ec); 160 | 161 | // Serialize EC signature 162 | if (!serialize_ec_signature_der(sig, serial_sig)){ 163 | return false; 164 | } 165 | ECDSA_SIG_free(sig); 166 | 167 | 168 | Bin* refund_tx_fulfill = new Bin(); 169 | if (!send_refund_tx(serial_sig, temp_raw_tx, redeem_script, refund_tx_fulfill)){ 170 | return false; 171 | } 172 | 173 | printf("puzzle_promise: Escrow Refund TX:\n"); 174 | refund_tx_fulfill->print(); 175 | 176 | delete temp_raw_tx; 177 | delete temp_sighash; 178 | delete refund_tx_fulfill; 179 | delete serial_sig; 180 | 181 | return true; 182 | } 183 | //============================================================================ 184 | //======= Public Functions 185 | //============================================================================ 186 | 187 | bool Tumbler::sign_transactions(std::vector& tx_set){ 188 | 189 | Timer timer = Timer((char *) "wrapper_sign\0"); 190 | timer.start(); 191 | 192 | bool status; 193 | int s; 194 | 195 | // Save Transactions 196 | tx = tx_set; 197 | 198 | 199 | ECDSA_SIG * sig = NULL; 200 | Bin* serial_sig = NULL; 201 | 202 | Bin* temp_epsilon = NULL; 203 | Bin* temp_enc = NULL; 204 | Bin* temp_commitment = NULL; 205 | 206 | int n = 2 * K; 207 | for (int i = 0; i < n; i++){ 208 | 209 | //========================= 210 | //======= ECDSA sign TX 211 | //========================= 212 | 213 | sig = EC_sign(ec, tx_set.at(i)); 214 | if (sig == NULL){ 215 | return false; 216 | } 217 | 218 | convert_sig_to_standard_der(sig, ec); 219 | 220 | // Serialize EC signature 221 | serial_sig = new Bin(); 222 | status = serialize_ec_signature(sig, serial_sig); 223 | if (!status){ 224 | return false; 225 | } 226 | 227 | //========================= 228 | //======= Commit 229 | //========================= 230 | 231 | temp_epsilon = new Bin(); 232 | temp_epsilon->len = rsa_len; 233 | temp_epsilon->data = get_random(rsa_len * 8, rsa->n); 234 | 235 | temp_commitment = new Bin(); 236 | status = encrypt(serial_sig, temp_epsilon, temp_commitment); 237 | if(!status){ 238 | return false; 239 | } 240 | 241 | epsilon.push_back(temp_epsilon); 242 | C.push_back(temp_commitment); 243 | 244 | //========================= 245 | //======= Encrypt epsiolon 246 | //========================= 247 | 248 | temp_enc = new Bin(rsa_len); 249 | s = RSA_public_encrypt(rsa_len, temp_epsilon->data, temp_enc->data, rsa, RSA_NO_PADDING); 250 | if (s == -1){ 251 | return false; 252 | } 253 | Z.push_back(temp_enc); 254 | 255 | // Cleanup 256 | ECDSA_SIG_free(sig); 257 | delete serial_sig; 258 | 259 | } 260 | 261 | timer.end(); 262 | 263 | return true; 264 | } 265 | 266 | bool Tumbler::verify_fake_tx(std::vector& r){ 267 | 268 | Timer timer = Timer((char *) "wrapper_verify_fakes\0"); 269 | timer.start(); 270 | 271 | // Check R & F hashes 272 | Bin* temp_h_r; 273 | Bin* temp_h_f; 274 | 275 | Bin *r2 = new Bin(); 276 | Bin *f = new Bin(); 277 | 278 | serialize_int_vector(r2, R, K); 279 | serialize_int_vector(f, F, K); 280 | 281 | temp_h_r = hmac256(r2, salt); 282 | temp_h_f = hmac256(f, salt); 283 | 284 | if (*h_r != *temp_h_r || *h_f != *temp_h_f){ 285 | printf("HMAC doesn't match\n"); 286 | return false; 287 | } 288 | 289 | delete temp_h_r; 290 | delete temp_h_f; 291 | delete r2; 292 | delete f; 293 | 294 | int j = 0; 295 | Bin *fake; 296 | Bin *hash; 297 | 298 | fake = new Bin(64); 299 | memset(fake->data, 0x00, 32); 300 | for (int i = 0; i < K; i++){ 301 | j = F.at(i); 302 | 303 | // Hash fake tx 304 | memcpy(fake->data + 32, r.at(i)->data, 32); 305 | hash = hash256(fake); 306 | 307 | if (*tx.at(j) != *hash){ 308 | printf("verify_fake_tx: Hashes don't match."); 309 | return false; 310 | } 311 | 312 | delete hash; 313 | } 314 | 315 | delete fake; 316 | timer.end(); 317 | 318 | 319 | verified = true; 320 | create_quotients(); 321 | 322 | for (unsigned int i=0; i < F.size(); i++){ 323 | j = F.at(i); 324 | epsilon_f.push_back(epsilon.at(j)); 325 | } 326 | 327 | return true; 328 | } 329 | 330 | bool Tumbler::create_offer_tx(){ 331 | 332 | funding_tx_id = new Bin(); 333 | redeem_script = new Bin(); 334 | p2sh_address = new Bin(); 335 | lock_time = new Bin(); 336 | 337 | if(!setup_escrow(ec_pubkey, bob_ec_pubkey, redeem_script, funding_tx_id, p2sh_address, lock_time)){ 338 | return false; 339 | } 340 | 341 | if(!create_refund_tx()){ 342 | return false; 343 | } 344 | 345 | return true; 346 | } 347 | 348 | //============================================================================ 349 | //======= GETS 350 | //============================================================================ 351 | 352 | std::vector* Tumbler::get_Z(){ 353 | return &Z; 354 | } 355 | 356 | std::vector* Tumbler::get_commitment(){ 357 | return &C; 358 | } 359 | 360 | std::vector* Tumbler::get_epsilons(){ 361 | if (verified == true){ 362 | return &epsilon_f; 363 | } 364 | return NULL; 365 | } 366 | 367 | std::vector* Tumbler::get_quotients(){ 368 | if (verified == true) { 369 | return "ients; 370 | } 371 | return NULL; 372 | } 373 | 374 | Bin* Tumbler::get_redeem_script(){ 375 | return redeem_script; 376 | } 377 | 378 | Bin* Tumbler::get_funding_tx_id(){ 379 | return funding_tx_id; 380 | } 381 | 382 | Bin* Tumbler::get_pubkey(){ 383 | return ec_pubkey; 384 | } 385 | 386 | Bin* Tumbler::get_rsa(){ 387 | return rsa_pub; 388 | } 389 | 390 | //============================================================================ 391 | //======= SETS 392 | //============================================================================ 393 | 394 | void Tumbler::set_R(std::vector r){ 395 | R = r; 396 | } 397 | 398 | void Tumbler::set_F(std::vector f){ 399 | F = f; 400 | } 401 | 402 | void Tumbler::set_h_r(Bin* h){ 403 | h_r = h; 404 | } 405 | 406 | void Tumbler::set_h_f(Bin* h){ 407 | h_f = h; 408 | } 409 | 410 | void Tumbler::set_salt(Bin* s){ 411 | salt = s; 412 | } 413 | 414 | void Tumbler::set_party_pubkey(Bin* public_key){ 415 | bob_ec_pubkey = public_key; 416 | } 417 | 418 | //============================================================================ 419 | -------------------------------------------------------------------------------- /POC_code/src/tumbler_server.cpp: -------------------------------------------------------------------------------- 1 | #include "tumbler.h" 2 | #include "strings.h" 3 | #include "network.h" 4 | 5 | //============================================================================ 6 | //======= PROTOCOL 7 | //============================================================================ 8 | 9 | bool exchange(Tumbler &tumbler, std::vector& requests, std::vector& reply){ 10 | 11 | if (requests.size() != 2){ 12 | return false; 13 | } 14 | 15 | tumbler.set_party_pubkey(requests.at(1)); 16 | 17 | // Create TX Offer 18 | if(!tumbler.create_offer_tx()){ 19 | return false; 20 | } 21 | 22 | reply.push_back(tumbler.get_pubkey()); 23 | reply.push_back(tumbler.get_rsa()); 24 | reply.push_back(tumbler.get_redeem_script()); 25 | reply.push_back(tumbler.get_funding_tx_id()); 26 | 27 | return true; 28 | } 29 | 30 | bool commitment(Tumbler &tumbler, std::vector& requests, std::vector& reply, std::vector& tx_set){ 31 | 32 | if (requests.size() != 4){ 33 | return false; 34 | } 35 | 36 | // Deserialize 37 | if (!deserialize_vector(requests.at(1), tx_set, 2 * K, HASH_256)){ 38 | return false; 39 | } 40 | 41 | tumbler.set_h_r(requests.at(2)); 42 | tumbler.set_h_f(requests.at(3)); 43 | 44 | // Sign 45 | if (!tumbler.sign_transactions(tx_set)){ 46 | return false; 47 | } 48 | 49 | // Serialize 50 | Bin* C = new Bin(); 51 | if (!serialize_vector(C, *tumbler.get_commitment(), 2 * K, HASH_512)){ 52 | return false; 53 | } 54 | 55 | Bin* Z = new Bin(); 56 | std::vector Z_vec = *tumbler.get_Z(); 57 | if (!serialize_vector(Z, Z_vec, 2 * K, Z_vec.at(0)->len)){ 58 | return false; 59 | } 60 | 61 | reply.push_back(C); 62 | reply.push_back(Z); 63 | 64 | return true; 65 | } 66 | 67 | bool verify(Tumbler &tumbler, std::vector& requests, std::vector& reply){ 68 | if (requests.size() != 5){ 69 | return false; 70 | } 71 | 72 | // Deserialize to int vectors 73 | std::vector R; 74 | std::vector F; 75 | 76 | if(!deserialize_int_vector(requests.at(1), R, K)){ 77 | return false; 78 | } 79 | 80 | if(!deserialize_int_vector(requests.at(2), F, K)){ 81 | return false; 82 | } 83 | 84 | std::vector fake_txs; 85 | if (!deserialize_vector(requests.at(3), fake_txs, K, HASH_256)){ 86 | return false; 87 | } 88 | 89 | tumbler.set_R(R); 90 | tumbler.set_F(F); 91 | tumbler.set_salt(requests.at(4)); 92 | 93 | // Verify fake tx's 94 | if (!tumbler.verify_fake_tx(fake_txs)){ 95 | return false; 96 | } 97 | 98 | // Serialize 99 | Bin* quotients = new Bin(); 100 | std::vector quot_vec =*tumbler.get_quotients(); 101 | if (!serialize_vector(quotients, quot_vec, K - 1, quot_vec.at(0)->len)){ 102 | return false; 103 | } 104 | 105 | Bin* fake_epsilons = new Bin(); 106 | std::vector ep_vec = *tumbler.get_epsilons(); 107 | if (!serialize_vector(fake_epsilons, ep_vec, K, ep_vec.at(0)->len)){ 108 | return false; 109 | } 110 | 111 | reply.push_back(quotients); 112 | reply.push_back(fake_epsilons); 113 | 114 | free_Bins(fake_txs); 115 | return true; 116 | } 117 | 118 | //============================================================================ 119 | //======= MAIN 120 | //============================================================================ 121 | 122 | int main () { 123 | 124 | // Prepare our context and socket 125 | zmq::context_t context(1); 126 | zmq::socket_t socket(context, ZMQ_REP); 127 | socket.bind("tcp://*:5557"); 128 | 129 | zmq::message_t fail_msg; 130 | fail_msg.rebuild(26); 131 | memcpy(fail_msg.data(), "Failed to process request.", 26); 132 | 133 | // Handle interrupt 134 | s_catch_signals(); 135 | 136 | std::vector requests; // Received 137 | std::vector reply; // Sent 138 | 139 | Tumbler* tumbler; 140 | std::vector tx_set; 141 | 142 | 143 | 144 | /* 145 | * Not a multithreaded server. 146 | * Will definitly not work correctly 147 | * if multiple clients try to connect 148 | * during a run of the Protocol 149 | * TODO: Turn into multithreaded socket server 150 | * or multithreaded http server after getting 151 | * 1000 tx's through. 152 | */ 153 | while(true) { 154 | 155 | try{ 156 | 157 | receive(socket, requests); 158 | if(memcmp(requests.at(0)->data, "exchange", 8) == 0){ 159 | tumbler = new Tumbler(); 160 | 161 | if(!exchange(*tumbler, requests, reply)){ 162 | printf("Exchange failed\n"); 163 | socket.send(fail_msg); 164 | }else{ 165 | send(socket, reply); 166 | } 167 | 168 | free_Bins(requests); 169 | 170 | }else if(memcmp(requests.at(0)->data, "commitment", 10) == 0){ 171 | 172 | if(!commitment(*tumbler, requests, reply, tx_set)){ 173 | printf("Commitment failed\n"); 174 | socket.send(fail_msg); 175 | delete tumbler; 176 | }else{ 177 | send(socket, reply); 178 | free_Bins(reply); 179 | } 180 | 181 | }else if(memcmp(requests.at(0)->data, "verify", 6) == 0){ 182 | if(!verify(*tumbler, requests, reply)){ 183 | printf("verify failed\n"); 184 | socket.send(fail_msg); 185 | }else{ 186 | send(socket, reply); 187 | free_Bins(reply); 188 | } 189 | 190 | free_Bins(tx_set); 191 | free_Bins(requests); 192 | tx_set.clear(); 193 | delete tumbler; 194 | } 195 | 196 | // Cleanup 197 | // free_Bins(requests); 198 | reply.clear(); 199 | requests.clear(); 200 | } catch(zmq::error_t& e) { 201 | printf("\nZMQ Error: %s\n", e.what()); 202 | free_Bins(requests); 203 | break; 204 | } 205 | 206 | 207 | } 208 | 209 | free_Bins(requests); 210 | 211 | return 0; 212 | } 213 | -------------------------------------------------------------------------------- /POC_code/src/utility/bin.cpp: -------------------------------------------------------------------------------- 1 | #include "bin.h" 2 | #include "utility.h" 3 | #include "memory.h" 4 | 5 | //============================================================================ 6 | //======= Constructors and Destructors 7 | //============================================================================ 8 | 9 | Bin::Bin(int len_c){ 10 | len = len_c; 11 | data = (unsigned char *) tmalloc(len); 12 | } 13 | 14 | Bin::Bin(int len_c, unsigned char *data_c){ 15 | len = len_c; 16 | data = data_c; 17 | } 18 | 19 | // Copy constructor 20 | Bin::Bin(const Bin &bin) 21 | { 22 | len = bin.len; 23 | data = (unsigned char *) tmalloc(len); 24 | memcpy(data, bin.data, len); 25 | } 26 | 27 | Bin::~Bin(){ 28 | if (len > 0){ 29 | tfree(data); 30 | } 31 | len = 0; 32 | } 33 | 34 | bool Bin::operator== (const Bin& b) const 35 | { 36 | if (len != b.len){ 37 | return false; 38 | } 39 | 40 | return (memcmp(data, b.data, len) == 0); 41 | } 42 | 43 | bool Bin::operator!= (const Bin& b) 44 | { 45 | if (len != b.len){ 46 | return true; 47 | } 48 | 49 | return (memcmp(data, b.data, len) != 0); 50 | } 51 | 52 | //============================================================================ 53 | //======= Public Methods 54 | //============================================================================ 55 | 56 | unsigned char * Bin::serialize(){ 57 | int int_len = sizeof(int); 58 | unsigned char * serial = (unsigned char *) malloc(len + int_len); 59 | 60 | memcpy(serial, &len, int_len); 61 | memcpy(serial + int_len, data, len); 62 | 63 | return serial; 64 | } 65 | 66 | void Bin::print(){ 67 | 68 | if (len == 0){ 69 | printf("Bin was freed, or is invalid!\n"); 70 | return; 71 | } 72 | 73 | printf("Len is: %d\n", len); 74 | printf("Hex is: \n"); 75 | print_hex(len, data); 76 | printf("\n"); 77 | } 78 | 79 | //============================================================================ 80 | //======= Non-Instance Methods 81 | //============================================================================ 82 | 83 | bool defined(Bin* item){ 84 | return !(item == NULL || item->len < 1); 85 | } 86 | 87 | void delete_bin(Bin* item){ 88 | if (item != NULL){ 89 | delete item; 90 | item = NULL; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /POC_code/src/utility/generate_rsa.cpp: -------------------------------------------------------------------------------- 1 | #include "utility.h" 2 | #include "blind_rsa.h" 3 | 4 | int main(){ 5 | // Cron job to generate new RSA key after every epoch 6 | char * suffix = (char *) "signer"; 7 | generate_rsa_key(2048, suffix, suffix); 8 | } 9 | -------------------------------------------------------------------------------- /POC_code/src/utility/memory.cpp: -------------------------------------------------------------------------------- 1 | #include "memory.h" 2 | 3 | //============================================================================ 4 | 5 | void tfree(void *ptr) 6 | { 7 | if (ptr != NULL){ 8 | free(ptr); 9 | ptr = NULL; 10 | } 11 | } 12 | 13 | void* tmalloc(size_t size) 14 | { 15 | void* res = malloc(size); 16 | if (res == NULL) { 17 | exit(-3); 18 | } 19 | memset(res, 0 , size); 20 | return res; 21 | } 22 | 23 | 24 | void free_blinds(std::vector b){ 25 | 26 | for (unsigned int i=0; i < b.size(); i++){ 27 | BN_BLINDING_free(b.at(i)); 28 | } 29 | } 30 | 31 | void free_Bins(std::vector bins){ 32 | Bin *temp; 33 | for (unsigned int i=0; i < bins.size(); i++){ 34 | temp = bins.at(i); 35 | delete temp; 36 | } 37 | } 38 | 39 | //============================================================================ 40 | //============================================================================ 41 | 42 | /* $OpenBSD: timingsafe_memcmp.c,v 1.2 2015/08/31 02:53:57 guenther Exp $ */ 43 | /* 44 | * Copyright (c) 2014 Google Inc. 45 | * 46 | * Permission to use, copy, modify, and distribute this software for any 47 | * purpose with or without fee is hereby granted, provided that the above 48 | * copyright notice and this permission notice appear in all copies. 49 | * 50 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 51 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 52 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 53 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 54 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 55 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 56 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 57 | */ 58 | 59 | int 60 | timingsafe_memcmp(const void *b1, const void *b2, size_t len) 61 | { 62 | // printf("Timing safe memcmp called\n"); 63 | const unsigned char *p1 = (const unsigned char *)b1, *p2 = (const unsigned char *)b2; 64 | size_t i; 65 | int res = 0, done = 0; 66 | 67 | for (i = 0; i < len; i++) { 68 | /* lt is -1 if p1[i] < p2[i]; else 0. */ 69 | int lt = (p1[i] - p2[i]) >> CHAR_BIT; 70 | 71 | /* gt is -1 if p1[i] > p2[i]; else 0. */ 72 | int gt = (p2[i] - p1[i]) >> CHAR_BIT; 73 | 74 | /* cmp is 1 if p1[i] > p2[i]; -1 if p1[i] < p2[i]; else 0. */ 75 | int cmp = lt - gt; 76 | 77 | /* set res = cmp if !done. */ 78 | res |= cmp & ~done; 79 | 80 | /* set done if p1[i] != p2[i]. */ 81 | done |= lt | gt; 82 | } 83 | 84 | return (res); 85 | } 86 | -------------------------------------------------------------------------------- /POC_code/src/utility/network.cpp: -------------------------------------------------------------------------------- 1 | #include "network.h" 2 | 3 | //============================================================================ 4 | //======= MSG PROCESSING 5 | //============================================================================ 6 | 7 | void receive(zmq::socket_t &socket, std::vector& msgs){ 8 | 9 | int64_t more = 1; 10 | size_t more_size = sizeof(more); 11 | zmq::message_t request; 12 | 13 | Bin* item = NULL; 14 | while(more > 0){ 15 | request.rebuild(); 16 | 17 | socket.recv(&request); 18 | item = new Bin(); 19 | item->len = request.size(); 20 | item->data = (unsigned char *) malloc(item->len); 21 | memcpy(item->data, request.data(), request.size()); 22 | 23 | // Add to vec 24 | msgs.push_back(item); 25 | 26 | // Check to see if there's more 27 | socket.getsockopt(ZMQ_RCVMORE, &more, &more_size); 28 | } 29 | } 30 | 31 | void send(zmq::socket_t &socket, std::vector& msgs){ 32 | 33 | zmq::message_t reply; 34 | int last_index = msgs.size() - 1; 35 | 36 | for(int i = 0; i < last_index; i++){ 37 | reply.rebuild(msgs.at(i)->len); 38 | memcpy(reply.data(), msgs.at(i)->data, msgs.at(i)->len); 39 | socket.send(reply, ZMQ_SNDMORE); 40 | } 41 | 42 | reply.rebuild(msgs.at(last_index)->len); 43 | memcpy(reply.data(), msgs.at(last_index)->data, msgs.at(last_index)->len); 44 | socket.send(reply, 0); 45 | } 46 | -------------------------------------------------------------------------------- /POC_code/src/utility/timer.cpp: -------------------------------------------------------------------------------- 1 | #include "timer.h" 2 | 3 | Timer::Timer(){ 4 | description = (char *) malloc(strlen("unknown")); 5 | memcpy(description, "unknown", strlen("unknown")); 6 | } 7 | 8 | Timer::Timer(char *name){ 9 | description = name; 10 | } 11 | 12 | Timer::~Timer(){ 13 | file = fopen("timing.json", "a+"); 14 | 15 | if(file == NULL){ 16 | printf("Failed to save timing info"); 17 | return; 18 | } 19 | 20 | char *summary; 21 | asprintf (&summary, "{\"%s\": {\"real_time\": \"%f\", \"cpu_time\": \"%f\"}}\n", description, get_real_time(), get_clock_time()); 22 | fwrite(summary, 1, strlen(summary), file); 23 | free(summary); 24 | fclose(file); 25 | 26 | } 27 | 28 | void Timer::start(){ 29 | r_start = real_time::now(); 30 | c_start = clock(); 31 | } 32 | 33 | void Timer::end(){ 34 | r_end = real_time::now(); 35 | c_end = clock(); 36 | 37 | r_duration = r_end - r_start; 38 | c_duration = double( c_end - c_start) / CLOCKS_PER_SEC; 39 | } 40 | 41 | void Timer::print(){ 42 | printf("Real Time: %f seconds\n", get_real_time()); 43 | printf("Clock Time: %f seconds\n\n", get_clock_time()); 44 | } 45 | 46 | // In seconds 47 | double Timer::get_clock_time(){ 48 | return c_duration; 49 | } 50 | 51 | double Timer::get_real_time(){ 52 | return r_duration.count(); 53 | } 54 | -------------------------------------------------------------------------------- /POC_code/src/utility/utility.cpp: -------------------------------------------------------------------------------- 1 | #include "utility.h" 2 | #include "constants.h" 3 | 4 | int BNToBin(BIGNUM *f, unsigned char * bin, int bin_len){ 5 | // We make the assumption that all bin representations of BIGNUMs will be the 6 | //same length. In semi-rare cases the bignum use than data_len bytes. Such 7 | //cases mean that less than data_len bytes will be written into bin, thus bin 8 | //will contain uninitialized values. We fix this by packeting zeros in the 9 | //front of bignum. Zeros will not impact the magnitude of bin, but will ensure 10 | //that all bytes are initalized. 11 | 12 | if (f == NULL || bin == NULL){ 13 | return 0; 14 | } 15 | 16 | int offset = bin_len-BN_num_bytes(f); 17 | 18 | int ret = BN_bn2bin(f, bin+offset); 19 | 20 | // Zero out any bytes not written to in BN_bn2bin. 21 | int i; 22 | for(i = 0; i < offset; i++){ 23 | bin[i] = 0x00; 24 | } 25 | 26 | return ret+offset; 27 | } 28 | 29 | //============================================================================ 30 | //======= Printing Methods 31 | //============================================================================ 32 | 33 | void print_BN(BIGNUM* bn){ 34 | char * r = BN_bn2hex(bn); 35 | printf("%s\n", r); 36 | } 37 | 38 | 39 | void print_hex(int len, unsigned char *data){ 40 | int x; 41 | for(x=0;xA); 51 | printf("%s\n", r); 52 | 53 | 54 | printf("R inverse is:\n"); 55 | char * ri = BN_bn2hex(blind->Ai); 56 | printf("%s\n", ri); 57 | 58 | } 59 | 60 | void print_blinds(std::vector blinds){ 61 | 62 | for(unsigned int i=0; i < blinds.size(); i++){ 63 | printf("Blind #%d is:\n", i); 64 | print_blind(blinds.at(i)); 65 | printf("\n"); 66 | } 67 | } 68 | 69 | //============================================================================ 70 | //======= String Representation Methods 71 | //============================================================================ 72 | 73 | char * get_hex_str_rev(Bin* msg){ 74 | int len = msg->len; 75 | char *buffer = (char *) tmalloc( (2*len) + 1); 76 | 77 | int x = 0; 78 | for(int i = len-1; i >= 0; i--) { 79 | sprintf(&buffer[x*2], "%02x", msg->data[i]); 80 | x++; 81 | } 82 | 83 | return buffer; 84 | } 85 | 86 | char * get_hex_str(Bin* msg){ 87 | int len = msg->len; 88 | char *buffer = (char *) tmalloc( (2*len) + 1); 89 | 90 | int x; 91 | for(x = 0; x < len; x++) { 92 | sprintf(&buffer[x*2], "%02x", msg->data[x]); 93 | } 94 | 95 | return buffer; 96 | } 97 | -------------------------------------------------------------------------------- /POC_code/ubuntu_setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Configure Ubuntu 4 | 5 | # Build essentials, OpenSSL & Boost 6 | sudo apt-get update 7 | sudo apt-get install libtool pkg-config build-essential autoconf automake 8 | sudo apt-get install libboost-all-dev 9 | sudo apt-get install libzmq3-dev 10 | sudo apt-get install python-pip 11 | 12 | # Install ZMQ 13 | git clone https://github.com/zeromq/libzmq 14 | CPPFLAGS=-DZMQ_MAKE_VALGRIND_HAPPY 15 | cd libzmq 16 | ./autogen.sh 17 | ./configure 18 | make -j 4 19 | make check 20 | make install 21 | sudo ldconfig 22 | cd .. 23 | rm -rf libzmq/ 24 | 25 | # Install LibreSSL 26 | wget http://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-2.3.4.tar.gz 27 | tar -xzvf libressl-2.3.4.tar.gz 28 | cd libressl-2.3.4 29 | ./configure 30 | make 31 | sudo make install 32 | sudo ldconfig 33 | cd .. 34 | rm -rf libressl-2.3.4 35 | rm libressl-2.3.4.tar.gz 36 | 37 | # Install python dependencies 38 | pip install -r requirements.txt 39 | 40 | sudo apt-get install libzmq-dev 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TumbleBit 2 | 3 | 4 | ["TumbleBit: An Untrusted Bitcoin-Compatible Anonymous Payment Hub"](http://cs-people.bu.edu/heilman/tumblebit/). 5 | 6 | This repo contains the [Proof of Concept](POC_code/README.md) implementation used in the paper, as well as a [reference implementation](reference_implementation/README.md) for the protocols in python3. 7 | These implementations are intended only to describe and prototype TumbleBit the protocols. They should not be deployed in production. 8 | 9 | [nTumbleBit](https://github.com/nTumbleBit/nTumbleBit) is being developed for production use and is the official opensource implementation of TumbleBit. 10 | 11 | 12 | **Description:** TumbleBit is a new anonymous payments protocol that is fully compatible with today’s Bitcoin protocol. TumbleBit allows parties to make payments through an untrusted Tumbler. No-one, not even the Tumbler, can tell which payer paid which payee during a TumbleBit epoch. TumbleBit consists of two interleaved fair-exchange protocols that prevent theft of bitcoins by cheating users or a malicious Tumbler. TumbleBit combines fast cryptographic computations (performed off the blockchain) with standard bitcoin scripting functionalities (on the blockchain) that realize smart contracts. TumbleBit was used to mix [800 input addresses](https://blockchain.info/tx/fd51bd844202ef050f1fbe0563e3babd2df3c3694b61af39ac811ad14f52b233) to [800 output addresses](https://blockchain.info/tx/8520da7116a1e634baf415280fdac45f96e680270ea06810512531a783f0c9f6) on Bitcoin's blockchain. 13 | -------------------------------------------------------------------------------- /reference_implementation/README.md: -------------------------------------------------------------------------------- 1 | # Reference Implementation 2 | 3 | This is a python3 reference implementation of the *Puzzle Solver* and *Puzzle Promise* protocols. 4 | 5 | ### Dependencies 6 | 7 | - LibreSSL 8 | - pytest 9 | - pycrypto 10 | - python-bitcoinlib 11 | 12 | You will need to install or build LibreSSL and you can install 13 | the python dependencies by running `sudo pip3 install -r requirements.txt` 14 | 15 | For ubuntu, you can install the dependencies by running: 16 | ``` 17 | ./ubuntu_setup.sh 18 | ``` 19 | 20 | ### Running Tests 21 | Our python code only supports python3. 22 | 23 | ``` 24 | sudo pip install -e . 25 | python3 -m pytest tests/ 26 | ``` 27 | 28 | ### TODO 29 | 30 | - [ ] Create script tests 31 | - [ ] Create a test that tests the protocols on testnet without timelocks. 32 | -------------------------------------------------------------------------------- /reference_implementation/requirements.txt: -------------------------------------------------------------------------------- 1 | python-bitcoinlib==0.7.0 2 | pycrypto==2.6.1 3 | pytest==3.0.6 4 | -------------------------------------------------------------------------------- /reference_implementation/setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from setuptools import setup, find_packages 4 | 5 | setup( 6 | name='tumblebit', 7 | version='0.0.1', 8 | packages=find_packages(exclude=('tests', 'docs')) 9 | ) 10 | -------------------------------------------------------------------------------- /reference_implementation/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUSEC/TumbleBit/55829dc75c36554e710e723dedb510d62a57ca0c/reference_implementation/tests/__init__.py -------------------------------------------------------------------------------- /reference_implementation/tests/test_crypto.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import pytest 4 | 5 | from binascii import hexlify, unhexlify 6 | 7 | from tumblebit.crypto import chacha 8 | 9 | @pytest.fixture() 10 | def keypath(tmpdir_factory): 11 | path = tmpdir_factory.mktemp('test_crypto', numbered=False) 12 | return str(path) 13 | 14 | class TestCHACHA20(): 15 | 16 | def test_chacha_128bit_key(self): 17 | msg1 = unhexlify("12345678901234567890123456") 18 | key1 = "x" * 16 # 128-bit key 19 | iv1 = "a" * 8 20 | ciphertext1 = chacha(key1, iv1, msg1) 21 | 22 | assert hexlify(ciphertext1) == b"f4d00b7237791f237a2ddebd20" 23 | assert chacha(key1, iv1, ciphertext1) == msg1 24 | 25 | def test_chacha_256bit_key(self): 26 | msg2 = unhexlify("12345678901234567890123456") 27 | key2 = "z" * 32 # 256-bit key 28 | iv2 = "b" * 8 29 | ciphertext2 = chacha(key2, iv2, msg2) 30 | 31 | assert hexlify(ciphertext2) == b"5b7e78078d16c5efb7c46aa2a3" 32 | assert chacha(key2, iv2, ciphertext2) == msg2 33 | -------------------------------------------------------------------------------- /reference_implementation/tests/test_data/client_ec_keys/ec_client.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PRIVATE KEY----- 2 | MHQCAQEEINL8Gpa7b6XnSCt0SHn3lx/MFA2c/mOBZQAIL8bxcxzeoAcGBSuBBAAK 3 | oUQDQgAECBHuNQiLnSuL4YqJbIaeRgjPYtuhOOWxA21nEKA8C8wNbWuDlFKS2tGj 4 | 6DD4pMpdqjHuxi2ELJ3RQTWRSBn4zw== 5 | -----END EC PRIVATE KEY----- 6 | -------------------------------------------------------------------------------- /reference_implementation/tests/test_data/client_ec_keys/ec_privkey.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUSEC/TumbleBit/55829dc75c36554e710e723dedb510d62a57ca0c/reference_implementation/tests/test_data/client_ec_keys/ec_privkey.der -------------------------------------------------------------------------------- /reference_implementation/tests/test_data/client_ec_keys/ec_pubkey.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUSEC/TumbleBit/55829dc75c36554e710e723dedb510d62a57ca0c/reference_implementation/tests/test_data/client_ec_keys/ec_pubkey.bin -------------------------------------------------------------------------------- /reference_implementation/tests/test_data/server_ec_keys/ec_privkey.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUSEC/TumbleBit/55829dc75c36554e710e723dedb510d62a57ca0c/reference_implementation/tests/test_data/server_ec_keys/ec_privkey.der -------------------------------------------------------------------------------- /reference_implementation/tests/test_data/server_ec_keys/ec_pubkey.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUSEC/TumbleBit/55829dc75c36554e710e723dedb510d62a57ca0c/reference_implementation/tests/test_data/server_ec_keys/ec_pubkey.bin -------------------------------------------------------------------------------- /reference_implementation/tests/test_data/server_ec_keys/ec_server.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PRIVATE KEY----- 2 | MHQCAQEEINAdnlCmLzPWx9tmdDIJJh1z2Se+uOvsWPmpaF9kmMtvoAcGBSuBBAAK 3 | oUQDQgAEQ8pBQkA+aVVxlx/1fmv2x+gWBgPUqqFW+WHbiEJLKmGPaMQ1IIuJmRXm 4 | 8sUtwZOXUmRm9Xz+j9YFcJxjcA3ayg== 5 | -----END EC PRIVATE KEY----- 6 | -------------------------------------------------------------------------------- /reference_implementation/tests/test_data/server_rsa_keys/private_test.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEA717cpC0m/sXsCjZwXCJrzFzcughE+2VFVITjY/DtvUvjbDQ7 3 | es7A4wQX+fgz65k8XwVnu5dZ6KTurBCeb9UA2aGCpOOTUIlrKpn9SWiI5+zkiR/H 4 | VefyIxpKNLPM4o0dkgNpVW7opVgPlxmCsOfFKb2rl/4MunrycfTQLS3UvblqKzT0 5 | Q8T/bx6+QCH2HmLL5xowTcUitd/ovU7Qr6Zfn9GYGjRtvmHWNUwYcgG8I1ebyoi1 6 | K4ux/srQJFrgytoqkxeKC8lnUr+iewlxHT8ZBtEp3F1s3Eg7fHq1YxFw9dLky8I+ 7 | InFsm14lirHQJ3oGAZZ0CA8m7v8UrVDHn0aaPQIDAQABAoIBACazi7Dvq/JdRcCQ 8 | 9LGwzwUHrphVZfHPedokci9icM2+S1LfTw6YBw+tRcMgoiRhbiVe1lq6Kcs3f29K 9 | cJNcOPr25gyKzvKihTUqGI2Z3SjCYGDbRntZOQj74yuKNoIalsFY09sAR5UUG9Eu 10 | SrcXggUxqWC1rpEn97L9BfuIAXF7DOckQ1QjMnfyUZHDdY0S8lH0v84Ics6L98Pv 11 | nv+vBAauJpAgAmJ4QOhy15UxdBXR0Eg1IYWK2ohDkh+XrbXTzWxtxrE56A1NpWpG 12 | khzkEi/sbJqx4Y7OONCBxxddIeun6K+XHWMGWe5ttBas85zoeEkEMh0blzoNwlgW 13 | hXvzdQECgYEA+CSG7EXGH3OblHfYY1IT/evjQ0oBzjuEyvW+toXb90qIkX0z9s5r 14 | N00AY2p5HGg4gmOENXodAg6xsGbv37L1RlXBy9P9aExnGMQnqZCjmAPYflTJf2gt 15 | Gm/fSf7CJIz98VUBUnyucarHi3IH14zaVkUSFKoJiLusLCjr4wdx+/ECgYEA9vM6 16 | GZIuQyfypkDF3o0X1Llszv0vczvb+oIX6FBNKzctdA08Uid3v0PR8I8YTA7c2ZIu 17 | ftr6hh0tppLBj/zlGlo/7G+j9MzNyyRHb4Xi8YBAK8rgRGnFUl3RpPY7KpD9b15n 18 | sqy533miCpOQsVXQXUQwOEsKDiqy9YTbPT/Evw0CgYBj1F4rpA6HDL2kx2pY2uaM 19 | G2B868M6MxvDg4ZMbCIIpQW4coR7YKQlxWbImEdNNGi3nE3OLeiJsVuvOlp6xsaC 20 | m3GyDQE/+qzne9LxFu2Z9MIeYQIHreOnZSaR4Fo+1jI76xTzGJIdzLUm1qNtBo+4 21 | cWVKxvW6+rXTtkrgNViYIQKBgA9qUXclK+QfS0Nbib6BujoaNROatGqSEwJJOqrS 22 | 0G5hLGIxLVHHiu8SkbldhVvCFcEzIdnjW34htibOxGxzke2aMqFUurxeSH5kzlzE 23 | 08zVf6v8JxG+NIYWuy57/GeE030vPHPn2lZ75kSYv5CCVdZsmkH5VTBbM/6lg3YI 24 | VATFAoGBANvO9RoPsqm+SJqMRAuyVV+hHlnUvulfiplQmmqq+T/FZ5pEd/JWWghN 25 | f0nGShVxQMKLKHUn9NOd4dLU5MKOzhIH8Hvdr6FXFs9qMtaauqFmnNqW8D2mrHtf 26 | nZFsR+FEDuNYWjZ3DDybe2NA8g+rvPxBGk9hnEZlqbK8pZWj6FKM 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /reference_implementation/tests/test_data/server_rsa_keys/public_test.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PUBLIC KEY----- 2 | MIIBCgKCAQEA717cpC0m/sXsCjZwXCJrzFzcughE+2VFVITjY/DtvUvjbDQ7es7A 3 | 4wQX+fgz65k8XwVnu5dZ6KTurBCeb9UA2aGCpOOTUIlrKpn9SWiI5+zkiR/HVefy 4 | IxpKNLPM4o0dkgNpVW7opVgPlxmCsOfFKb2rl/4MunrycfTQLS3UvblqKzT0Q8T/ 5 | bx6+QCH2HmLL5xowTcUitd/ovU7Qr6Zfn9GYGjRtvmHWNUwYcgG8I1ebyoi1K4ux 6 | /srQJFrgytoqkxeKC8lnUr+iewlxHT8ZBtEp3F1s3Eg7fHq1YxFw9dLky8I+InFs 7 | m14lirHQJ3oGAZZ0CA8m7v8UrVDHn0aaPQIDAQAB 8 | -----END RSA PUBLIC KEY----- 9 | -------------------------------------------------------------------------------- /reference_implementation/tests/test_ec.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import os 4 | 5 | import pytest 6 | 7 | from tumblebit.ec import EC 8 | from tumblebit.crypto import sha256 9 | 10 | BASE_PATH = os.path.dirname(__file__) + '/test_data/server_ec_keys/' 11 | 12 | def test_ec(): 13 | ec_key = EC() 14 | 15 | ec_key.load_public_key(BASE_PATH + 'ec_pubkey.bin') 16 | assert ec_key.is_private == False 17 | 18 | ec_key.load_private_key(BASE_PATH + 'ec_privkey.der') 19 | assert ec_key.is_private == True 20 | 21 | def test_signing(): 22 | ec_privkey = EC() 23 | ec_privkey.load_private_key(BASE_PATH + 'ec_privkey.der') 24 | 25 | msg = sha256(b'test_data') 26 | sig = ec_privkey.sign(msg) 27 | 28 | ec_key = EC() 29 | ec_key.load_public_key(BASE_PATH + 'ec_pubkey.bin') 30 | 31 | assert ec_key.verify(msg, sig) 32 | 33 | def test_serialization(): 34 | ec_key = EC() 35 | ec_key.load_private_key(BASE_PATH + 'ec_privkey.der') 36 | 37 | msg = sha256(b'test_data') 38 | sig = ec_key.sign(msg) 39 | 40 | serial_sig = ec_key.serialize_sig(sig) 41 | assert len(serial_sig) == 64 42 | 43 | deserialized_sig = ec_key.deserialize_sig(serial_sig) 44 | 45 | assert ec_key.verify(msg, deserialized_sig) 46 | -------------------------------------------------------------------------------- /reference_implementation/tests/test_puzzle_promise.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import os 4 | import pytest 5 | 6 | 7 | from tumblebit.ec import EC 8 | from tumblebit.rsa import RSA 9 | from tumblebit.puzzle_promise import PuzzlePromiseServer, PuzzlePromiseClient 10 | 11 | 12 | FUNDING_TX = "82026f66f615c9f4b454381865b364db6ea2e686e782af9a5a51ae6f0b5991ab" 13 | ADDRESS = "mweZnPjTeyGHVS2d3SojAGujY36sd3wQ49" 14 | AMOUNT = 0.001 15 | FEE = 0.0006 16 | 17 | def test_puzzle_promise(): 18 | 19 | ##################################### 20 | ## Key Setup 21 | ##################################### 22 | 23 | base_path = os.path.dirname(__file__) + '/test_data/' 24 | 25 | # Setup Tumbler keys 26 | server_ec_path = base_path + 'server_ec_keys/' 27 | 28 | server_ec_key = EC() 29 | server_ec_key.load_public_key(server_ec_path + 'ec_pubkey.bin') 30 | server_ec_key.load_private_key(server_ec_path + 'ec_privkey.der') 31 | 32 | server_rsa_path = base_path + 'server_rsa_keys/' 33 | rsa_key = RSA(server_rsa_path, 'test') 34 | rsa_key.load_public_key() 35 | 36 | # Setup Client EC key 37 | client_ec_path = base_path + 'client_ec_keys/' 38 | 39 | client_ec_key = EC() 40 | client_ec_key.load_public_key(client_ec_path + 'ec_pubkey.bin') 41 | client_ec_key.load_private_key(server_ec_path + 'ec_privkey.der') 42 | 43 | server_ec_pubkey = EC() 44 | server_ec_pubkey.load_public_key(server_ec_path + 'ec_pubkey.bin') 45 | 46 | 47 | ##################################### 48 | ## Puzzle Promise Protocol 49 | ##################################### 50 | 51 | server = PuzzlePromiseServer(rsa_key, server_ec_key, client_ec_key.get_pubkey()) 52 | client = PuzzlePromiseClient(rsa_key, server_ec_pubkey, client_ec_key) 53 | 54 | # Step 1. Setup Escrow 55 | redeem_script, p2sh_address = server.prepare_escrow(0) 56 | server.set_funding_tx(FUNDING_TX) 57 | 58 | # Steps 2 - 4 : Prepare tx set 59 | amt = AMOUNT - FEE 60 | tx_set, R_h, F_h = client.prepare_tx_set(redeem_script, FUNDING_TX, ADDRESS, amt) 61 | 62 | # Step 5: Get commitment & puzzles 63 | commitments, puzzles = server.sign_transactions(tx_set, R_h, F_h) 64 | 65 | # Step 6 - 7: Verify fakes 66 | assert server.verify_fake_txs(client.salt, client.R, client.F, client.fake_blinds) 67 | 68 | # Step 9: Get quotients 69 | fake_keys = server.get_fake_keys() 70 | assert fake_keys is not None 71 | assert client.verify_fake_signatures(commitments, puzzles, fake_keys) 72 | 73 | # Step 9: Get quotients 74 | quotients = server.prepare_quotients() 75 | # print("quotients length is %d" % len(quotients)) 76 | assert len(quotients) == (server.m - 1) 77 | 78 | # Step 10: Test quotients 79 | assert client.verify_quotients(quotients) 80 | 81 | # Step 12: Get one puzzle 82 | -------------------------------------------------------------------------------- /reference_implementation/tests/test_puzzle_solver.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import random 4 | from binascii import hexlify, unhexlify 5 | 6 | import pytest 7 | 8 | from tumblebit.rsa import RSA 9 | from tumblebit.puzzle_solver import PuzzleSolverClient, PuzzleSolverServer, PuzzleSolver 10 | 11 | 12 | def predictableRandomness(bits): 13 | return random.getrandbits(bits).to_bytes(int(bits/8), byteorder='big') 14 | 15 | PuzzleSolver.compute_rand = staticmethod(predictableRandomness) 16 | 17 | 18 | def test_puzzle_solver_complete(): 19 | random.seed(1) 20 | 21 | path = 'tests/test_data/server_rsa_keys' 22 | key_name = 'test' 23 | 24 | server_keys = RSA(path, key_name) 25 | server_keys.load_public_key() 26 | server_keys.load_private_key() 27 | 28 | server_pubkey = RSA(path, key_name) 29 | server_pubkey.load_public_key() 30 | 31 | 32 | epsilon = b'828134975835142c2062b33020e5b360bb8af6ceb137715ba95dc901f406970c34931500f93f4b73647691d1b4d7ca7fb1256e4aa3b56c90a42c9be263c76101d0df812b1b9cab0c7eae2e577c22ce2896edfc30c2f40002e4a37c682a7b2f8ffb8afa7afd24cca0764be74cda664a40f55940bed0ebe4f20f59f0038fd50eb3e8d19f0e2a90580eef3a549bd1111e077b1c88db171b8fa2297e75d9986b0316db71e239d4b5e0c01f5849a2ac0726a0dfdcd577c7ec96d3b4f10bdcabb3bf8596b5a34cb7e032f090c5eb078c9efc59cd5f14309ee09e565a74ca48af27db32d817733ad2bd91bbee802147cfa4efd1b113d59d8430094d2e33d08c6d3b10b5' 33 | 34 | puzzle = server_keys.encrypt(unhexlify(epsilon)) 35 | 36 | expected_puzzle = b'70e0a26c87f905a5d800eef677e055d0699a186682cbed9adde01d478f92a2abeff5d115a8ac54f78b52774f428f056887d0daea9d6c59069c5ee22985a9cc273bd57dee73ed0bebeb5f93b910fd170cae9f33b38c82a7db48b3a8c545db2bb10857f6ba316501cb6c24afda26d2869b43b98378eaef0c57019069ccbfd0e970e63d01e15a71c3949ff8373be1c38e50f2c8f6b96e6bfe6a342205ec3710d80b0506ee13798e435f7b55e9465748abcc77d316b0a1a45d7b9b239011a3b409608cf9eb909189a47f4466e368f7e33b0890975479f1182c640af588194d694f0aaa3b889ed9f9202c89926d1e2e18e2d2a9915569a332f39ae68391abe9eb6ed8' 37 | assert hexlify(puzzle) == expected_puzzle 38 | 39 | client = PuzzleSolverClient(server_pubkey, puzzle) 40 | server = PuzzleSolverServer(server_keys) 41 | 42 | puzzles = client.prepare_puzzle_set() 43 | 44 | assert puzzles is not None 45 | expected_num_puzzles = 300 46 | assert len(puzzles) == expected_num_puzzles 47 | 48 | assert client.F == [272, 259, 204, 38, 92, 219, 285, 138, 106, 44, 46, 189, 287, 105, 112, 83, 35, 227, 207, 161, 124, 73, 81, 174, 51, 186, 110, 94, 79, 104, 113, 5, 17, 65, 39, 84, 70, 128, 281, 215, 6, 175, 177, 249, 145, 209, 117, 13, 132, 68, 244, 114, 1, 168, 42, 288, 141, 263, 126, 149, 286, 9, 294, 271, 29, 7, 194, 202, 163, 282, 171, 53, 32, 11, 221, 66, 153, 197, 251, 30, 48, 136, 55, 16, 142, 164, 299, 108, 82, 203, 182, 150, 243, 54, 159, 57, 115, 61, 58, 239, 148, 257, 173, 236, 290, 200, 293, 22, 184, 237, 135, 109, 0, 179, 120, 248, 107, 12, 195, 191, 78, 27, 3, 144, 193, 89, 226, 125, 62, 176, 190, 49, 74, 160, 242, 245, 4, 15, 97, 198, 19, 118, 258, 147, 121, 289, 45, 140, 238, 232, 119, 283, 85, 96, 205, 100, 267, 64, 247, 278, 8, 220, 214, 223, 25, 273, 222, 23, 180, 72, 86, 246, 123, 265, 99, 199, 71, 130, 98, 268, 166, 201, 297, 181, 217, 20, 47, 231, 151, 14, 253, 279, 154, 262, 143, 261, 291, 169, 206, 213, 211, 162, 127, 2, 266, 170, 50, 131, 21, 255, 188, 59, 91, 102, 172, 295, 31, 93, 77, 178, 234, 10, 26, 277, 134, 187, 270, 183, 158, 229, 269, 157, 69, 67, 216, 28, 256, 76, 80, 254, 146, 56, 101, 24, 103, 167, 37, 111, 63, 192, 230, 296, 264, 225, 122, 36, 280, 276, 156, 43, 218, 87, 52, 75, 90, 240, 95, 152, 250, 129, 274, 224, 241, 33, 60, 252, 212, 133, 233, 298, 137, 196, 210, 185, 228] 49 | 50 | #TODO: add check for two of puzzles 51 | 52 | ret = server.solve_puzzles(puzzles) 53 | assert ret is not None 54 | 55 | ciphertexts, commits = ret 56 | assert len(ciphertexts) == expected_num_puzzles 57 | assert len(commits) == expected_num_puzzles 58 | 59 | assert commits[0] == b'|\x8e\x01\xe9\xcai\xc3M\xbb9\xf0\xe8\x1d;\xda\x04%\xcf\x1a\xc4' 60 | assert commits[1] == b'\xcfz\r\x80\xe7\xf6\x8e^?T\xd1\x11\t\xbd\x99q\xfd;\xd6\xbb' 61 | 62 | #TODO: add check for two of ciphertests 63 | 64 | fake_keys = server.verify_fake_set(client.F, client.fake_blinds) 65 | assert fake_keys is not None 66 | 67 | ret = client.verify_fake_solutions(ciphertexts, commits, fake_keys) 68 | assert ret is True 69 | 70 | keys = server.verify_real_set(client.puzzle, client.R, client.real_blinds) 71 | assert keys is not None 72 | 73 | solution = client.extract_solution(ciphertexts, keys) 74 | assert solution is not None 75 | 76 | assert solution == b'\x82\x814\x97X5\x14, b\xb30 \xe5\xb3`\xbb\x8a\xf6\xce\xb17q[\xa9]\xc9\x01\xf4\x06\x97\x0c4\x93\x15\x00\xf9?Ksdv\x91\xd1\xb4\xd7\xca\x7f\xb1%nJ\xa3\xb5l\x90\xa4,\x9b\xe2c\xc7a\x01\xd0\xdf\x81+\x1b\x9c\xab\x0c~\xae.W|"\xce(\x96\xed\xfc0\xc2\xf4\x00\x02\xe4\xa3|h*{/\x8f\xfb\x8a\xfaz\xfd$\xcc\xa0vK\xe7L\xdafJ@\xf5Y@\xbe\xd0\xeb\xe4\xf2\x0fY\xf0\x03\x8f\xd5\x0e\xb3\xe8\xd1\x9f\x0e*\x90X\x0e\xef:T\x9b\xd1\x11\x1e\x07{\x1c\x88\xdb\x17\x1b\x8f\xa2)~u\xd9\x98k\x03\x16\xdbq\xe29\xd4\xb5\xe0\xc0\x1fXI\xa2\xac\x07&\xa0\xdf\xdc\xd5w\xc7\xec\x96\xd3\xb4\xf1\x0b\xdc\xab\xb3\xbf\x85\x96\xb5\xa3L\xb7\xe02\xf0\x90\xc5\xeb\x07\x8c\x9e\xfcY\xcd_\x140\x9e\xe0\x9eVZt\xcaH\xaf\'\xdb2\xd8\x17s:\xd2\xbd\x91\xbb\xee\x80!G\xcf\xa4\xef\xd1\xb1\x13\xd5\x9d\x840\tM.3\xd0\x8cm;\x10\xb5' 77 | assert hexlify(solution) == epsilon 78 | -------------------------------------------------------------------------------- /reference_implementation/tests/test_rsa.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import binascii 4 | 5 | import pytest 6 | 7 | from tumblebit.rsa import RSA 8 | from tumblebit.crypto import get_random 9 | 10 | 11 | @pytest.fixture(scope='session') 12 | def key_path(tmpdir_factory): 13 | path = tmpdir_factory.mktemp('test_rsa', numbered=False) 14 | return str(path) 15 | 16 | 17 | @pytest.fixture(scope='module') 18 | def rsa_gen(key_path): 19 | return RSA(key_path, 'test') 20 | 21 | 22 | @pytest.fixture(scope='module') 23 | def private_rsa(key_path): 24 | return RSA(key_path, 'test') 25 | 26 | 27 | @pytest.fixture(scope='module') 28 | def public_rsa(key_path): 29 | return RSA(key_path, 'test') 30 | 31 | 32 | class TestRSA: 33 | 34 | def test_key_gen(self, rsa_gen): 35 | assert rsa_gen.generate(2048) is True 36 | 37 | def test_save_key(self, rsa_gen): 38 | assert rsa_gen.save_public_key() is True 39 | assert rsa_gen.save_private_key() is True 40 | 41 | def test_load_private_key(self, private_rsa): 42 | assert private_rsa.load_private_key() is True 43 | 44 | def test_load_public_key(self, public_rsa): 45 | assert public_rsa.load_public_key() is True 46 | 47 | def test_signing(self, private_rsa, public_rsa): 48 | rsa_size = public_rsa.size 49 | 50 | # Should get valid sig if msg == rsa_size 51 | msg = b'01' * (rsa_size // 2) 52 | sig = private_rsa.sign(msg) 53 | assert public_rsa.verify(msg, sig) 54 | 55 | # If msg != RSA_size(), no sig is produced 56 | msg2 = b'1' * (256 // 2) 57 | sig2 = private_rsa.sign(msg2) 58 | assert sig2 is None 59 | 60 | def test_blinding(self, private_rsa, public_rsa): 61 | msg = b'01' * (256 // 2) 62 | r = get_random(2048) 63 | blind = public_rsa.setup_blinding(r) 64 | assert blind is not None 65 | 66 | blinded_msg = public_rsa.blind(msg, blind) 67 | blinded_msg_2 = public_rsa.blind(msg, blind) 68 | 69 | assert blinded_msg is not None 70 | assert blinded_msg == blinded_msg_2 71 | 72 | sig = private_rsa.sign(blinded_msg) 73 | sig_2 = private_rsa.sign(blinded_msg_2) 74 | assert sig is not None 75 | assert sig_2 is not None 76 | 77 | unblinded_sig = public_rsa.unblind(sig, blind) 78 | unblinded_sig_2 = public_rsa.unblind(sig_2, blind) 79 | assert unblinded_sig is not None 80 | assert public_rsa.verify(msg, unblinded_sig) 81 | 82 | # Strip blinding factor from message 83 | unblinded_msg = public_rsa.revert_blind(blinded_msg, blind) 84 | unblinded_msg_2 = public_rsa.revert_blind(blinded_msg_2, blind) 85 | assert unblinded_msg is not None 86 | assert unblinded_msg == msg 87 | assert unblinded_msg_2 == msg 88 | -------------------------------------------------------------------------------- /reference_implementation/tumblebit/crypto.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | tumblebit.crypto 5 | ~~~~~~~~~~~~~~~~ 6 | 7 | """ 8 | 9 | import hmac 10 | import ctypes 11 | import hashlib 12 | import logging 13 | 14 | from tumblebit import _ssl, ChaCha_ctx, BNToBin 15 | 16 | ######################################################## 17 | ## Random 18 | ######################################################## 19 | 20 | def get_random(bits, mod=None): 21 | """ 22 | Returns a random byte string of size `bits`/8 bytes. 23 | 24 | Args: 25 | bits (int): The number of bits the random string should have. 26 | mod (:obj:`ctypes.c_void_p`, optional): A pointer to a BN instance 27 | Returns: 28 | A byte strings of length `bits`/8 or None if an error occured 29 | If mod is set the random byte string will have a value < mod 30 | """ 31 | ctx = _ssl.BN_CTX_new() 32 | _ssl.BN_CTX_start(ctx) 33 | r = _ssl.BN_CTX_get(ctx) 34 | ret = _ssl.BN_CTX_get(ctx) 35 | 36 | if mod: 37 | if _ssl.BN_rand_range(r, mod) == 0: 38 | logging.debug("get_random: failed to generate random number") 39 | return None 40 | 41 | while _ssl.BN_gcd(ret, r, mod, ctx) != 1: 42 | logging.debug("R is not a relative prime") 43 | if _ssl.BN_rand_range(r, mod) == 0: 44 | logging.debug("get_random: failed to generate random number") 45 | return None 46 | 47 | else: 48 | if _ssl.BN_rand(r, bits, 0, 1) == 0: 49 | logging.debug("get_random: failed to generate random number") 50 | return None 51 | 52 | rand = BNToBin(r, bits//8) 53 | 54 | _ssl.BN_free(r) 55 | _ssl.BN_free(ret) 56 | _ssl.BN_CTX_end(ctx) 57 | _ssl.BN_CTX_free(ctx) 58 | 59 | return rand 60 | 61 | ######################################################## 62 | ## Hash & MAC Functions 63 | ######################################################## 64 | 65 | def ripemd160(msg): 66 | h = hashlib.new('ripemd160') 67 | h.update(msg) 68 | return h.digest() 69 | 70 | def sha256(msg): 71 | h = hashlib.sha256() 72 | h.update(msg) 73 | return h.digest() 74 | 75 | def hash256(msg): 76 | return sha256(sha256(msg)) 77 | 78 | def sha512(msg): 79 | h = hashlib.sha512() 80 | h.update(msg) 81 | return h.digest() 82 | 83 | def hmac_sha256(key, msg): 84 | h = hmac.new(key, msg, hashlib.sha256) 85 | return h.digest() 86 | 87 | 88 | ######################################################## 89 | ## Encryption Functions 90 | ######################################################## 91 | 92 | 93 | def xor_bytes(a, b): 94 | """ XOR's the bytes of `a` and `b` 95 | 96 | All arguments should be byte strings. 97 | 98 | Returns: 99 | Result as a byte string or None in failure. 100 | """ 101 | if len(a) != len(b): 102 | return None 103 | return bytes(x ^ y for x, y in zip(a, b)) 104 | 105 | 106 | def chacha(key, iv, msg): 107 | """ Encryptes msg using chacha 108 | 109 | All arguments should be byte strings. 110 | 111 | Returns: 112 | Result as a byte string or None in failure. 113 | """ 114 | if len(iv) != 8 or len(key) not in [16, 32] or msg is None: 115 | return None 116 | 117 | # Setup 118 | ctx = ctypes.byref(ChaCha_ctx()) 119 | _ssl.ChaCha_set_key(ctx, key, len(key)) 120 | _ssl.ChaCha_set_iv(ctx, iv, None) 121 | 122 | out = ctypes.create_string_buffer(len(msg)) 123 | _ssl.ChaCha(ctx, ctypes.pointer(out), msg, len(msg)) 124 | 125 | return out.raw[:len(msg)] 126 | -------------------------------------------------------------------------------- /reference_implementation/tumblebit/ec.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | tumblebit.ec 5 | ~~~~~~~~~~~~ 6 | 7 | This module provides the capabilities to use 8 | sign/verify messages using EC keys 9 | 10 | """ 11 | 12 | import ctypes 13 | 14 | from bitcoin.core.key import CECKey 15 | 16 | from tumblebit import _ssl, ECDSA_SIG_st, BNToBin, BinToBN 17 | 18 | 19 | class EC(object): 20 | """ 21 | Wrapper around python-bitcoinlib's CECKey class 22 | """ 23 | 24 | def __init__(self): 25 | self.key = CECKey() 26 | self.init = False 27 | self.is_private = False 28 | 29 | def load_public_key(self, key_path): 30 | """ 31 | Loads a public key from file at `key_path` 32 | """ 33 | with open(key_path, 'rb') as f: 34 | temp_key = f.read() 35 | 36 | self.key.set_pubkey(temp_key) 37 | self.init = True 38 | 39 | def load_private_key(self, key_path): 40 | """ 41 | Loads a private key from file at `key_path` 42 | """ 43 | with open(key_path, 'rb') as f: 44 | temp_key = f.read() 45 | self.key.set_privkey(temp_key) 46 | 47 | self.init = True 48 | self.is_private = True 49 | 50 | def get_pubkey(self): 51 | """ 52 | Returns an octet byte string representing 53 | the EC public key 54 | or None if no public key has been loaded. 55 | """ 56 | if not self.init: 57 | return None 58 | return self.key.get_pubkey() 59 | 60 | 61 | def sign(self, msg): 62 | """ 63 | Sign `msg` using EC private key 64 | 65 | Raises: 66 | ValueError: If private key is not loaded. 67 | """ 68 | if self.init: 69 | if self.is_private: 70 | sig = self.key.sign(msg) 71 | return sig 72 | else: 73 | raise ValueError('Signing requires a private key') 74 | else: 75 | raise ValueError('No key is loaded.') 76 | 77 | def verify(self, msg, sig): 78 | """ 79 | Sign `msg` using EC private key 80 | 81 | Raises: 82 | ValueError: If no key is loaded. 83 | """ 84 | if self.init: 85 | return self.key.verify(msg, sig) == 1 86 | else: 87 | raise ValueError('No key is loaded.') 88 | 89 | 90 | def serialize_sig(self, sig): 91 | """ 92 | Takes in a signature in DER format and returns a byte 93 | string of R + S that should be 64 bytes in length 94 | """ 95 | 96 | sig_struct = ECDSA_SIG_st() 97 | p_sig_struct = ctypes.byref(ctypes.pointer(sig_struct)) 98 | p_sig = ctypes.byref(ctypes.c_char_p(sig)) 99 | _ssl.d2i_ECDSA_SIG(p_sig_struct, p_sig, len(sig)) 100 | 101 | r = BNToBin(sig_struct.r, 32) 102 | s = BNToBin(sig_struct.s, 32) 103 | 104 | return r + s 105 | 106 | def deserialize_sig(self, serial_sig): 107 | """ 108 | Converts a serial signature (R + S) into DER format 109 | 110 | Arguments: 111 | serial_sig (bytes): A 64 byte string that represents R and S where each 112 | is 32 bytes 113 | 114 | Returns: 115 | A signature in DER format 116 | 117 | Raises: 118 | Value error if serial sig is not 64 bytes 119 | """ 120 | if len(serial_sig) == 64: 121 | sig_struct = ECDSA_SIG_st() 122 | 123 | r = BinToBN(serial_sig[:32]) 124 | s = BinToBN(serial_sig[32:]) 125 | 126 | sig_struct.r = r 127 | sig_struct.s = s 128 | 129 | derlen = _ssl.i2d_ECDSA_SIG(ctypes.pointer(sig_struct), 0) 130 | if derlen == 0: 131 | _ssl.ECDSA_SIG_free(sig_struct) 132 | return None 133 | 134 | der_sig = ctypes.create_string_buffer(derlen) 135 | _ssl.i2d_ECDSA_SIG(ctypes.pointer(sig_struct), ctypes.byref(ctypes.pointer(der_sig))) 136 | return der_sig.raw 137 | else: 138 | raise ValueError('Serial sig has to be 64 bytes.') 139 | -------------------------------------------------------------------------------- /reference_implementation/ubuntu_setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Tested on Ubuntu 16.04.1 LTS 4 | 5 | sudo apt-get update 6 | sudo apt-get install libtool pkg-config build-essential autoconf automake 7 | 8 | # Install python3 & pip 9 | sudo apt install python3-pip 10 | pip3 install --upgrade pip 11 | 12 | # Install LibreSSL 13 | wget https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-2.5.1.tar.gz 14 | tar -xzvf libressl-2.5.1.tar.gz 15 | cd libressl-2.5.1 16 | ./configure 17 | make 18 | sudo make install 19 | sudo ldconfig 20 | cd .. 21 | rm -rf libressl-2.5.1 22 | rm libressl-2.5.1.tar.gz 23 | --------------------------------------------------------------------------------