├── .distignore ├── .github └── workflows │ └── wordpress-new-version.yml ├── .gitignore ├── .wordpress-org ├── banner-1544x500.png ├── banner-772x250.png ├── icon-128x128.png ├── icon-256x256.png ├── icon.svg ├── screenshot-1.png ├── screenshot-2.png ├── screenshot-3.png ├── screenshot-4.png ├── screenshot-5.png ├── screenshot-6.png └── screenshot-7.png ├── LICENSE ├── README.md ├── css └── settings.css ├── dev ├── docker-compose.yml ├── i18n-extract.sh ├── rsync-exclude └── rsync.sh ├── includes ├── address_deriver.php ├── bulk_actions.php ├── crypto_manager.php ├── nimiq_currency.php ├── order_utils.php ├── validation_scheduler.php └── webhook.php ├── index.php ├── js ├── HubApi.standalone.umd.js ├── checkout.js └── settings.js ├── languages ├── wc-gateway-nimiq-es_ES.mo ├── wc-gateway-nimiq-es_ES.po ├── wc-gateway-nimiq-fil_PH.mo ├── wc-gateway-nimiq-fil_PH.po ├── wc-gateway-nimiq-fr_FR.mo ├── wc-gateway-nimiq-fr_FR.po ├── wc-gateway-nimiq-nl_NL.mo ├── wc-gateway-nimiq-nl_NL.po ├── wc-gateway-nimiq-pt_PT.mo ├── wc-gateway-nimiq-pt_PT.po ├── wc-gateway-nimiq-ru_RU.mo ├── wc-gateway-nimiq-ru_RU.po ├── wc-gateway-nimiq-uk_UA.mo ├── wc-gateway-nimiq-uk_UA.po ├── wc-gateway-nimiq-zh_CN.mo ├── wc-gateway-nimiq-zh_CN.po └── wc-gateway-nimiq.pot ├── nimiq-utils ├── JSONUtils.php └── RpcUtils.php ├── nimiq-xpub ├── README.md ├── composer.json ├── src │ └── XPub.php └── vendor │ ├── autoload.php │ ├── bitwasp │ └── bech32 │ │ ├── CONTRIBUTING.md │ │ ├── README.md │ │ ├── composer.json │ │ └── src │ │ ├── Exception │ │ └── Bech32Exception.php │ │ └── bech32.php │ ├── composer │ ├── ClassLoader.php │ ├── LICENSE │ ├── autoload_classmap.php │ ├── autoload_files.php │ ├── autoload_namespaces.php │ ├── autoload_psr4.php │ ├── autoload_real.php │ ├── autoload_static.php │ └── installed.json │ ├── kornrunner │ └── keccak │ │ ├── LICENSE │ │ ├── README.md │ │ ├── composer.json │ │ └── src │ │ └── Keccak.php │ ├── simplito │ ├── bigint-wrapper-php │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── composer.json │ │ └── lib │ │ │ └── BigInteger.php │ ├── bn-php │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── composer.json │ │ └── lib │ │ │ ├── BN.php │ │ │ └── Red.php │ └── elliptic-php │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── composer.json │ │ └── lib │ │ ├── Curve │ │ ├── BaseCurve.php │ │ ├── BaseCurve │ │ │ └── Point.php │ │ ├── EdwardsCurve.php │ │ ├── EdwardsCurve │ │ │ └── Point.php │ │ ├── MontCurve.php │ │ ├── MontCurve │ │ │ └── Point.php │ │ ├── PresetCurve.php │ │ ├── ShortCurve.php │ │ └── ShortCurve │ │ │ ├── JPoint.php │ │ │ └── Point.php │ │ ├── Curves.php │ │ ├── EC.php │ │ ├── EC │ │ ├── KeyPair.php │ │ └── Signature.php │ │ ├── EdDSA.php │ │ ├── EdDSA │ │ ├── KeyPair.php │ │ └── Signature.php │ │ ├── HmacDRBG.php │ │ └── Utils.php │ ├── stephenhill │ └── base58 │ │ ├── composer.json │ │ ├── contributing.md │ │ ├── license │ │ ├── readme.md │ │ └── src │ │ ├── BCMathService.php │ │ ├── Base58.php │ │ ├── GMPService.php │ │ └── ServiceInterface.php │ └── symfony │ └── polyfill-mbstring │ ├── LICENSE │ ├── Mbstring.php │ ├── README.md │ ├── Resources │ └── unidata │ │ ├── lowerCase.php │ │ ├── titleCaseRegexp.php │ │ └── upperCase.php │ ├── bootstrap.php │ └── composer.json ├── price_services ├── coingecko.php ├── fastspot.php ├── interface.php └── nimiqx.php ├── readme.txt ├── settings.php ├── styles.css ├── validation_services ├── blockstream.php ├── etherscan.php ├── interface.php ├── json_rpc_nim.php ├── nimiq_watch.php └── nimiqx.php └── woo-nimiq-gateway.php /.distignore: -------------------------------------------------------------------------------- 1 | /.wordpress-org 2 | /.git 3 | /.github 4 | /dev 5 | 6 | .distignore 7 | .gitignore 8 | -------------------------------------------------------------------------------- /.github/workflows/wordpress-new-version.yml: -------------------------------------------------------------------------------- 1 | name: Deploy to WordPress.org 2 | on: 3 | push: 4 | tags: 5 | - "*" 6 | jobs: 7 | tag: 8 | name: New tag 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@master 12 | # - name: Build 13 | # run: | 14 | # npm install 15 | # npm run build 16 | - name: WordPress Plugin Deploy 17 | uses: 10up/action-wordpress-plugin-deploy@master 18 | env: 19 | SVN_USERNAME: ${{ secrets.SVN_USERNAME }} 20 | SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }} 21 | SLUG: woo-nimiq-gateway 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | database 2 | html 3 | -------------------------------------------------------------------------------- /.wordpress-org/banner-1544x500.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nimiq/woocommerce-gateway-nimiq/512ed0168870cbe9996c7f43df29e302d18c64ec/.wordpress-org/banner-1544x500.png -------------------------------------------------------------------------------- /.wordpress-org/banner-772x250.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nimiq/woocommerce-gateway-nimiq/512ed0168870cbe9996c7f43df29e302d18c64ec/.wordpress-org/banner-772x250.png -------------------------------------------------------------------------------- /.wordpress-org/icon-128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nimiq/woocommerce-gateway-nimiq/512ed0168870cbe9996c7f43df29e302d18c64ec/.wordpress-org/icon-128x128.png -------------------------------------------------------------------------------- /.wordpress-org/icon-256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nimiq/woocommerce-gateway-nimiq/512ed0168870cbe9996c7f43df29e302d18c64ec/.wordpress-org/icon-256x256.png -------------------------------------------------------------------------------- /.wordpress-org/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /.wordpress-org/screenshot-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nimiq/woocommerce-gateway-nimiq/512ed0168870cbe9996c7f43df29e302d18c64ec/.wordpress-org/screenshot-1.png -------------------------------------------------------------------------------- /.wordpress-org/screenshot-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nimiq/woocommerce-gateway-nimiq/512ed0168870cbe9996c7f43df29e302d18c64ec/.wordpress-org/screenshot-2.png -------------------------------------------------------------------------------- /.wordpress-org/screenshot-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nimiq/woocommerce-gateway-nimiq/512ed0168870cbe9996c7f43df29e302d18c64ec/.wordpress-org/screenshot-3.png -------------------------------------------------------------------------------- /.wordpress-org/screenshot-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nimiq/woocommerce-gateway-nimiq/512ed0168870cbe9996c7f43df29e302d18c64ec/.wordpress-org/screenshot-4.png -------------------------------------------------------------------------------- /.wordpress-org/screenshot-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nimiq/woocommerce-gateway-nimiq/512ed0168870cbe9996c7f43df29e302d18c64ec/.wordpress-org/screenshot-5.png -------------------------------------------------------------------------------- /.wordpress-org/screenshot-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nimiq/woocommerce-gateway-nimiq/512ed0168870cbe9996c7f43df29e302d18c64ec/.wordpress-org/screenshot-6.png -------------------------------------------------------------------------------- /.wordpress-org/screenshot-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nimiq/woocommerce-gateway-nimiq/512ed0168870cbe9996c7f43df29e302d18c64ec/.wordpress-org/screenshot-7.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Cryptocurrency Checkout by Nimiq](https://raw.githubusercontent.com/nimiq/woocommerce-gateway-nimiq/master/.wordpress-org/banner-1544x500.png) 2 | 3 | # Cryptocurrency Checkout by Nimiq for WooCommerce 4 | 5 | A plugin for Wordpress to handle WooCommerce payments in the Nimiq (NIM), Bitcoin (BTC), and Ethereum (ETH) cryptocurrency. 6 | 7 | **Features Include:** 8 | 9 | * Bitcoin, Ethereum and Nimiq support 10 | * Automatic conversion from supported store currencies like USD or EUR to crypto at latest market prices 11 | * Full order status feedback in your WooCommerce panel 12 | * Decentralized and non-proprietary 13 | * Configurable conversion and validation service providers 14 | * Configurable confirmation times with sensible defaults 15 | 16 | ## Installation 17 | 18 | 1. Be sure you're running WooCommerce 3.5 or higher in your shop. 19 | 2. Search for "nimiq" in your Wordpress plugin section 20 | 3. Activate the plugin through the **Plugins** menu in WordPress. 21 | 4. Go to **WooCommerce > Settings > Payments** and select the "Nimiq" method to configure this plugin. 22 | 23 | [Check this in-depth tutorial for support.](https://nimiq.github.io/tutorials/wordpress-payment-plugin-installation) 24 | 25 | ## Changelog 26 | 27 | Please see the Changelog section in [readme.txt](readme.txt). 28 | 29 | ## Development 30 | 31 | ### Adding A New Validation Service 32 | 33 | Validation services are defined under [`./validation_services/`](./validation_services/). Each service class must implement the `WC_Gateway_Nimiq_Validation_Service_Interface`, defined in [`./validation_services/interface.php`](./validation_services/interface.php). The easiest way to start is to take an existing service (e.g. [`nimiq_watch.php`](./validation_services/nimiq_watch.php)) and rename and adapt it to the new service. The new service then also needs to be registered in the respective `validation_service_` setting. The value of the setting must match the file name (without the `.php` extension) of the service definition. If the new service requires additional setting fields, [`settings.js`](./js/settings.js) also needs to be adapted to show/hide those fields conditionally. 34 | 35 | ## Acknowledgement 36 | 37 | This Nimiq gateway is based on skyverge's [WooCommerce Offline Gateway](https://github.com/bekarice/woocommerce-gateway-offline), which in turn forks the WooCommerce core "Cheque" payment gateway. 38 | -------------------------------------------------------------------------------- /css/settings.css: -------------------------------------------------------------------------------- 1 | .wc-settings-sub-title.section-nimiq, 2 | .wc-settings-sub-title.section-bitcoin, 3 | .wc-settings-sub-title.section-bitcoin-disabled, 4 | .wc-settings-sub-title.section-ethereum, 5 | .wc-settings-sub-title.section-ethereum-disabled, 6 | .wc-settings-sub-title.section-advanced { 7 | margin-top: 2rem; 8 | padding-top: 1rem; 9 | border-top: solid 1px rgba(35, 40, 45, 0.1); 10 | } 11 | 12 | .wc-settings-sub-title.section-nimiq::after, 13 | .wc-settings-sub-title.section-bitcoin::after, 14 | .wc-settings-sub-title.section-bitcoin-disabled::after, 15 | .wc-settings-sub-title.section-ethereum::after, 16 | .wc-settings-sub-title.section-ethereum-disabled::after { 17 | content: ''; 18 | display: inline-block; 19 | width: 20px; 20 | height: 21px; 21 | background-size: contain; 22 | margin-left: 8px; 23 | margin-bottom: -5px; 24 | background-repeat: no-repeat; 25 | } 26 | 27 | .wc-settings-sub-title.section-nimiq::after { 28 | background-image: url('data:image/svg+xml,'); 29 | } 30 | 31 | .wc-settings-sub-title.section-bitcoin::after, 32 | .wc-settings-sub-title.section-bitcoin-disabled::after { 33 | background-image: url('data:image/svg+xml,'); 34 | } 35 | 36 | .wc-settings-sub-title.section-ethereum::after, 37 | .wc-settings-sub-title.section-ethereum-disabled::after { 38 | width: 14px; 39 | background-image: url('data:image/svg+xml, '); 40 | } 41 | 42 | .wc-settings-sub-title.section-bitcoin-disabled + p + table, 43 | .wc-settings-sub-title.section-ethereum-disabled + p + table { 44 | display: none; 45 | } 46 | 47 | .wc-settings-sub-title.section-advanced { 48 | cursor: pointer; 49 | margin-bottom: 0; 50 | padding-bottom: 1em; 51 | } 52 | 53 | .wc-settings-sub-title.section-advanced::after { 54 | content: '▼'; 55 | margin-left: 8px; 56 | font-weight: 900; 57 | opacity: 0.6; 58 | font-size: 0.9em; 59 | } 60 | 61 | .wc-settings-sub-title.section-advanced + p { 62 | margin-top: 0; 63 | } 64 | 65 | .wc-settings-sub-title.section-advanced + p + table { 66 | display: none; 67 | } 68 | 69 | .required + span { 70 | margin-left: 8px; 71 | color: red; 72 | vertical-align: top; 73 | } 74 | 75 | #nimiq_shop_logo_preview { 76 | display: inline-block; 77 | width: 50px; 78 | height: 50px; 79 | margin: -8px 0 -8px 16px; 80 | } 81 | -------------------------------------------------------------------------------- /dev/docker-compose.yml: -------------------------------------------------------------------------------- 1 | wordpress: 2 | image: wordpress 3 | links: 4 | - mariadb:mysql 5 | environment: 6 | - WORDPRESS_DB_PASSWORD=not-my-password 7 | - WORDPRESS_DB_USER=root 8 | ports: 9 | - "8083:80" 10 | volumes: 11 | - ./html:/var/www/html 12 | 13 | mariadb: 14 | image: mariadb 15 | environment: 16 | - MYSQL_ROOT_PASSWORD=not-my-password 17 | - MYSQL_DATABASE=wordpress 18 | volumes: 19 | - ./database:/var/lib/mysql 20 | -------------------------------------------------------------------------------- /dev/i18n-extract.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/sh 2 | 3 | wp i18n make-pot . --exclude=database,html --slug=wc-gateway-nimiq 4 | -------------------------------------------------------------------------------- /dev/rsync-exclude: -------------------------------------------------------------------------------- 1 | .* 2 | !.wordpress-org 3 | database 4 | html 5 | dev 6 | -------------------------------------------------------------------------------- /dev/rsync.sh: -------------------------------------------------------------------------------- 1 | sudo rsync -av --exclude-from=dev/rsync-exclude --chown=33:tape . html/wp-content/plugins/woo-nimiq-checkout 2 | -------------------------------------------------------------------------------- /includes/address_deriver.php: -------------------------------------------------------------------------------- 1 | gateway = $gateway; 10 | } 11 | 12 | public function get_next_address( $currency ) { 13 | if ( $currency === 'nim' ) return null; // TODO: Throw here instead? 14 | 15 | $reuse_eth_addresses = $this->gateway->get_option( 'reuse_eth_addresses', 'no' ); 16 | 17 | // Derive a new address for BTC and, if the re-use setting is disabled, for ETH 18 | if ( $currency === 'btc' || ( $currency === 'eth' && $reuse_eth_addresses == 'no' ) ) { 19 | return $this->derive_new_address( $currency ); 20 | } 21 | 22 | // Search for a re-usable address 23 | 24 | // 1. Find all orders that 25 | // - have an 'order_eth_address' (an ETH address was already assigned) 26 | // - have no 'transaction_hash' (no transaction was matched yet) 27 | // - are still 'pending' (order is still waiting for a matching transaction, e.g. was not cancelled) 28 | $posts = get_posts( [ 29 | 'post_type' => 'shop_order', 30 | 'post_status' => [ 'wc-pending' ], 31 | 'meta_query' => [ 32 | 'relation' => 'AND', 33 | [ 34 | 'key' => 'order_eth_address', 35 | 'compare' => 'EXISTS', 36 | ], 37 | [ 38 | 'key' => 'transaction_hash', 39 | 'compare' => 'NOT EXISTS', 40 | 'value' => 'bug #23268', // For Wordpress < 3.9, just in case 41 | ], 42 | ], 43 | ] ); 44 | 45 | if ( empty( $posts ) ) { 46 | // Use the first address 47 | return $this->derive_new_address( $currency, 0 ); 48 | }; 49 | 50 | // 2. Find the first derived address that is not used in any of the above orders 51 | $index = 0; 52 | $numderive = 5; 53 | while (true) { 54 | $indices = range($index, $index + $numderive - 1, 1); // Track indices of the derived addresses 55 | $addresses = $this->derive_addresses( $currency, $index, $numderive ); 56 | 57 | // Remove all currently used addresses from the derived $addresses 58 | foreach ( $posts as $post ) { 59 | $order = new WC_Order( (int) $post->ID ); 60 | $i = array_search( $order->get_meta( 'order_eth_address' ), $addresses ); 61 | if ( $i !== false ) { 62 | array_splice( $indices, $i, 1 ); 63 | array_splice( $addresses, $i, 1 ); 64 | } 65 | } 66 | 67 | // If unused addresses are found, return the first 68 | if ( count( $addresses ) > 0 ) { 69 | $this->maybe_update_address_index( $currency, $indices[ 0 ] ); 70 | return $addresses[ 0 ]; 71 | } 72 | 73 | // If no address of this batch is unused, increase the start index and rerun the loop 74 | $index += $numderive; 75 | } 76 | } 77 | 78 | private function maybe_update_address_index( $currency, $index, $current_index = null ) { 79 | $current_index = is_int( $current_index ) 80 | ? $current_index 81 | : $this->gateway->get_option( 'current_address_index_' . $currency, -1 ); 82 | 83 | if ( $index > $current_index ) { 84 | $this->gateway->update_option( 'current_address_index_' . $currency, $index ); 85 | } 86 | } 87 | 88 | public function derive_new_address( $currency, $index = null ) { 89 | $current_index = null; 90 | 91 | if ( !is_int( $index ) ) { 92 | $current_index = $this->gateway->get_option( 'current_address_index_' . $currency, -1 ); 93 | $index = $current_index + 1; 94 | } 95 | 96 | $address = $this->derive_addresses( $currency, $index, 1 )[ 0 ]; 97 | 98 | if ( !empty( $address ) ) { 99 | $this->maybe_update_address_index( $currency, $index, $current_index ); 100 | } 101 | 102 | return $address; 103 | } 104 | 105 | public function derive_addresses( $currency, $startindex, $numderive ) { 106 | $qualified_currency_name = Crypto_Manager::iso_to_name( $currency ); 107 | 108 | $xpub = $this->gateway->get_option( $qualified_currency_name . '_xpub' ); 109 | 110 | $xpub_type = $currency === 'btc' ? $this->gateway->get_option( $qualified_currency_name . '_xpub_type' ) : ''; 111 | $xpub_type = [ 112 | 'bip-44' => XPub::BIP44, 113 | 'bip-84' => XPub::BIP84, 114 | '' => '', 115 | ][ $xpub_type ]; 116 | 117 | if ( empty( $xpub ) ) { 118 | return null; 119 | } 120 | 121 | // Path 'm/0' from account xpub to external address space (BIP-44 for both BTC and ETH) 122 | $xpub_0 = XPub::fromString( $xpub, $xpub_type )->derive( 0 ); 123 | 124 | $addresses = []; 125 | 126 | for ($i = $startindex; $i < $startindex + $numderive; $i++) { 127 | $addresses[] = $xpub_0->derive( $i )->toAddress( $currency ); 128 | } 129 | 130 | return $addresses; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /includes/crypto_manager.php: -------------------------------------------------------------------------------- 1 | 5, 6 | 'btc' => 8, 7 | 'eth' => 18, 8 | ]; 9 | 10 | public static function iso_to_name( $iso ) { 11 | return [ 12 | 'nim' => 'nimiq', 13 | 'btc' => 'bitcoin', 14 | 'eth' => 'ethereum', 15 | ][ $iso ]; 16 | } 17 | 18 | public static function name_to_iso( $name ) { 19 | return [ 20 | 'nimiq' => 'nim', 21 | 'bitcoin' => 'btc', 22 | 'ethereum' => 'eth', 23 | ][ $name ]; 24 | } 25 | 26 | public static function coins_to_units( $values ) { 27 | $units = []; 28 | foreach ( $values as $crypto => $value ) { 29 | // Convert to smallest unit string 30 | 31 | // 1. Format as string without exponent 32 | $pad_length = self::DECIMALS[ $crypto ]; 33 | $coins = is_string( $value ) ? $value : number_format($value, $pad_length, '.', ''); 34 | 35 | // 2. Split by decimal dot 36 | $split = explode( '.', $coins, 2 ); 37 | $integers = $split[0]; 38 | $decimals = count( $split ) > 1 ? $split[1] : ''; 39 | 40 | // 3.1. Extend decimals with 0s until number of crypto-specific decimals is reached 41 | $decimals = str_pad( $decimals, $pad_length, '0', STR_PAD_RIGHT ); 42 | // 3.2. Ensure decimals are not too long 43 | $decimals = substr( $decimals, 0, $pad_length ); 44 | 45 | // 4. Join integers with decimals to create value string 46 | $unit = implode( '', [ $integers, $decimals ] ); 47 | 48 | // 5. Remove leading zeros 49 | $units[ $crypto ] = ltrim($unit, '0') ?: '0'; 50 | } 51 | return $units; 52 | } 53 | 54 | public static function required_decimals( $crypto, $price = 1000000 ) { 55 | // Find number of required significant decimals based on price, can be negative 56 | return min( ceil( log10( $price ) ) + 2, self::DECIMALS[ $crypto ] ); 57 | } 58 | 59 | public static function calculate_quotes( $value, $prices ) { 60 | $quotes = []; 61 | foreach ( $prices as $crypto => $price ) { 62 | $quotes[ $crypto ] = $value / $price; 63 | } 64 | return self::format_quotes( $value, $quotes, $prices ); 65 | } 66 | 67 | public static function format_quotes( $value, $quotes, $prices = null ) { 68 | foreach ( $quotes as $crypto => $quote ) { 69 | $price = !empty( $prices ) ? $prices[ $crypto ] : $value / $quote; 70 | $decimals = self::required_decimals( $crypto, $price ); 71 | $quotes[ $crypto ] = number_format( $quote, $decimals, '.', '' ); 72 | } 73 | return $quotes; 74 | } 75 | 76 | /** 77 | * Returns 1 if $a > $b, -1 if $b > $a, 0 if equal 78 | */ 79 | public static function unit_compare( $a, $b ) { 80 | $a = ltrim($a, '0'); 81 | $b = ltrim($b, '0'); 82 | 83 | $a_length = strlen( $a ); 84 | $b_length = strlen( $b ); 85 | 86 | if ( $a_length > $b_length ) return 1; 87 | if ( $a_length < $b_length ) return -1; 88 | 89 | return strcmp( $a, $b ); 90 | } 91 | 92 | public function __construct( $gateway ) { 93 | $this->gateway = $gateway; 94 | } 95 | 96 | public function get_accepted_cryptos() { 97 | $accepted_cryptos = [ 'nim' ]; 98 | if ( !empty( $this->gateway->get_option( 'bitcoin_xpub' ) ) ) $accepted_cryptos[] = 'btc'; 99 | if ( !empty( $this->gateway->get_option( 'ethereum_xpub' ) ) ) $accepted_cryptos[] = 'eth'; 100 | return $accepted_cryptos; 101 | } 102 | 103 | public function get_fees_per_byte() { 104 | return [ 105 | 'nim' => $this->gateway->get_setting( 'fee_nim' ), 106 | 'btc' => $this->gateway->get_setting( 'fee_btc' ), 107 | 'eth' => strval( $this->gateway->get_setting( 'fee_eth' ) * 1e9 ), // Option is in Gwei 108 | ]; 109 | } 110 | 111 | public function get_fees( $message_length ) { 112 | $perFees = $this->get_fees_per_byte(); 113 | return [ 114 | 'nim' => ( 166 + $message_length ) * $perFees[ 'nim' ], 115 | 'btc' => 250 * $perFees[ 'btc' ], 116 | 'eth' => [ 117 | 'gas_limit' => 21000, 118 | 'gas_price' => $perFees[ 'eth' ], 119 | ], 120 | ]; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /includes/nimiq_currency.php: -------------------------------------------------------------------------------- 1 | get_meta( 'order_crypto_currency' ) ?: ( $fallback_to_nim ? 'nim' : null ); 6 | } 7 | 8 | public static function get_order_total_crypto( $order ) { 9 | // 1. Get order crypto currency 10 | $currency = self::get_order_currency( $order ); 11 | 12 | // 2. Get order crypto total 13 | $order_total = $order->get_meta( 'order_total_' . $currency ); 14 | 15 | return Crypto_Manager::coins_to_units( [ $currency => $order_total ] )[ $currency ]; 16 | } 17 | 18 | public static function get_order_sender_address( $order ) { 19 | $currency = self::get_order_currency( $order ); 20 | return $order->get_meta( 'customer_' . $currency . '_address' ); 21 | } 22 | 23 | public static function get_order_recipient_address( $order, $gateway ) { 24 | $currency = self::get_order_currency( $order ); 25 | switch( $currency ) { 26 | case 'nim': return $gateway->get_option( 'nimiq_address' ); 27 | case 'btc': return $order->get_meta( 'order_' . $currency . '_address' ); 28 | case 'eth': return strtolower( $order->get_meta( 'order_' . $currency . '_address' ) ); 29 | } 30 | } 31 | 32 | public static function get_order_recipient_addresses( $order, $gateway ) { 33 | return [ 34 | 'nim' => $gateway->get_option( 'nimiq_address' ), 35 | 'btc' => $order->get_meta( 'order_btc_address' ), 36 | 'eth' => strtolower( $order->get_meta( 'order_eth_address' ) ), 37 | ]; 38 | } 39 | 40 | /** 41 | * @param {WC_Order} $order 42 | * @return {number|boolean} A timestamp or false if the order does not expire 43 | */ 44 | public static function get_order_hold_expiry( $order ) { 45 | // TODO: Respect $gateway->get_setting( 'tx_wait_duration' ) here? 46 | 47 | $order_hold_minutes = get_option( 'woocommerce_hold_stock_minutes' ); 48 | if ( empty( $order_hold_minutes ) ) return false; 49 | 50 | $order_date = $order->get_data()[ 'date_created' ]->getTimestamp(); 51 | return $order_date + $order_hold_minutes * 60; 52 | } 53 | 54 | public static function get_payment_state( $comparison ) { 55 | return $comparison > 0 ? 'OVERPAID' : ( $comparison < 0 ? 'UNDERPAID' : 'PAID' ); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /includes/validation_scheduler.php: -------------------------------------------------------------------------------- 1 | get_setting( 'validation_interval' ) ) ?: 30; 18 | $interval = $interval_minutes * 60; // Convert to seconds 19 | 20 | as_schedule_recurring_action( $next_quarter_hour, $interval, 'wc_nimiq_scheduled_validation' ); 21 | } 22 | } 23 | 24 | function wc_nimiq_end_validation_schedule() { 25 | as_unschedule_action( 'wc_nimiq_scheduled_validation' ); 26 | } 27 | 28 | function wc_nimiq_validate_orders() { 29 | $logger = wc_get_logger(); 30 | $log_context = array( 'source' => 'wc-gateway-nimiq' ); 31 | 32 | // Get all orders that are on-hold or pending, and have a crypto currency set 33 | $posts = get_posts( [ 34 | 'post_type' => 'shop_order', 35 | 'post_status' => [ 'wc-on-hold', 'wc-pending' ], 36 | 'meta_key' => 'order_crypto_currency', 37 | 'meta_compare' => '!=', 38 | 'meta_value' => '', 39 | ] ); 40 | 41 | /* translators: %d: Number of orders to process */ 42 | $logger->info( sprintf( _n( 'Processing %d order', 'Processing %d orders', count( $posts ), 'wc-gateway-nimiq' ), count( $posts ) ), $log_context ); 43 | 44 | if ( empty( $posts ) ) return; 45 | 46 | $ids = array_reduce( $posts, function( $acc, $post ) { 47 | $acc[] = $post->ID; 48 | return $acc; 49 | }, [] ); 50 | 51 | // $logger->info( 'Processing IDs [' . implode( ', ', $ids ) . ']', $log_context ); 52 | 53 | $gateway = new WC_Gateway_Nimiq(); 54 | $validation_results = _do_bulk_validate_transactions( $gateway, $ids ); 55 | 56 | if ( ! empty( $validation_results[ 'errors' ] ) ) { 57 | foreach ( $validation_results[ 'errors' ] as $error ) { 58 | $logger->error( $error, $log_context ); 59 | } 60 | // TODO: Send error email to admin? 61 | } 62 | 63 | $count_orders_updated = intval( $validation_results[ 'changed' ] ?: 0 ); 64 | $logger->info( sprintf( _n( 'Updated %d order', 'Updated %d orders', $count_orders_updated, 'wc-gateway-nimiq' ), $count_orders_updated ) . '.', $log_context ); 65 | } 66 | -------------------------------------------------------------------------------- /includes/webhook.php: -------------------------------------------------------------------------------- 1 | $message, 18 | 'status' => $status, 19 | ], $status ); 20 | } 21 | 22 | function woo_nimiq_checkout_get_param( $key, $method = 'get' ) { 23 | $data = $method === 'get' ? $_GET : $_POST; 24 | 25 | if ( !isset( $data[ $key ] ) ) return null; 26 | return sanitize_text_field( $data[ $key ] ); 27 | } 28 | 29 | /** 30 | * @param array $request Options for the function. 31 | */ 32 | function woo_nimiq_checkout_callback() { 33 | $request = [ 34 | 'id' => woo_nimiq_checkout_get_param( 'id' ), 35 | 'csrf' => woo_nimiq_checkout_get_param( 'csrf', 'post' ), 36 | 'command' => woo_nimiq_checkout_get_param( 'command', 'post' ), 37 | 'currency' => woo_nimiq_checkout_get_param( 'currency', 'post' ), 38 | ]; 39 | 40 | $gateway = new WC_Gateway_Nimiq(); 41 | 42 | // Set headers 43 | $cors_origin = $gateway->get_option( 'network' ) === 'main' ? 'https://hub.nimiq.com' : $_SERVER['HTTP_ORIGIN']; 44 | header( 'Access-Control-Allow-Origin: ' . $cors_origin ); 45 | header( 'Access-Control-Allow-Credentials: true'); 46 | 47 | $order = wc_get_order( $request[ 'id' ] ); 48 | 49 | // Validate that the order exists 50 | if ( !$order ) { 51 | return woo_nimiq_checkout_error( 'Invalid order ID', 404 ); 52 | } 53 | 54 | // Validate that the order's payment method is this plugin and that the order is currently 'pending' 55 | if ( $order->get_payment_method() !== $gateway->id || $order->get_status() !== 'pending' ) { 56 | return woo_nimiq_checkout_error( 'Bad order', 406 ); 57 | } 58 | 59 | // Validate CSRF token 60 | $order_csrf_token = $order->get_meta( 'checkout_csrf_token' ); 61 | if ( empty( $request[ 'csrf' ] ) || $order_csrf_token !== $request[ 'csrf' ] ) { 62 | return woo_nimiq_checkout_error( 'Invalid CSRF token', 403 ); 63 | } 64 | 65 | try { 66 | // Call handler depending on command 67 | switch ( strtolower( $request[ 'command' ] ) ) { 68 | case 'set_currency': 69 | return woo_nimiq_checkout_callback_set_currency( $request, $order, $gateway ); 70 | case 'get_state': 71 | return woo_nimiq_checkout_callback_get_state( $request, $order, $gateway ); 72 | default: 73 | return woo_nimiq_checkout_callback_unknown( $request, $order, $gateway ); 74 | } 75 | } catch (Exception $error) { 76 | return woo_nimiq_checkout_error( $error->getMessage(), 500 ); 77 | } 78 | } 79 | 80 | function woo_nimiq_checkout_array_find($function, $array) { 81 | foreach ($array as $item) { 82 | if (call_user_func($function, $item) === true) return $item; 83 | } 84 | return null; 85 | } 86 | 87 | function woo_nimiq_checkout_callback_set_currency( $request, $order, $gateway ) { 88 | $currency = strtolower( $request[ 'currency' ] ); 89 | 90 | $cryptoman = new Crypto_Manager( $gateway ); 91 | $accepted_currencies = $cryptoman->get_accepted_cryptos(); 92 | 93 | // Validate that the submitted currency is valid 94 | if ( !in_array( $currency, $accepted_currencies, true ) ) { 95 | return woo_nimiq_checkout_error( 'Bad currency', 406 ); 96 | } 97 | 98 | $order->update_meta_data( 'order_crypto_currency', $currency ); 99 | 100 | // Get payment option for the selected currency from stored request 101 | $stored_request = $order->get_meta( 'nc_payment_request' ) ?: null; 102 | if ( !$stored_request ) return woo_nimiq_checkout_error( 'Original request not found in order', 500 ); 103 | 104 | $request = json_decode( $stored_request, true ); 105 | 106 | $payment_option = woo_nimiq_checkout_array_find( function( $option ) use ( $currency ) { 107 | return $option[ 'currency' ] === $currency; 108 | }, $request[ 'paymentOptions' ] ); 109 | if ( !$payment_option ) return woo_nimiq_checkout_error( 'Selected currency not found in original request', 500 ); 110 | 111 | // Get the order address, or derive a new one 112 | $address = Order_Utils::get_order_recipient_address( $order, $gateway ); 113 | if ( empty( $address ) && ( $currency === 'btc' || $currency === 'eth' ) ) { 114 | include_once( dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'address_deriver.php' ); 115 | $deriver = new Address_Deriver( $gateway ); 116 | $address = $deriver->get_next_address( $currency ); 117 | if ( !empty( $address ) ) { 118 | $order->update_meta_data( 'order_' . $currency . '_address', $address ); 119 | } 120 | } 121 | 122 | $order->save(); 123 | 124 | $payment_option[ 'protocolSpecific' ][ 'recipient' ] = $address; 125 | 126 | return woo_nimiq_checkout_reply( $payment_option ); 127 | 128 | // // Rebuild the payment option for the selected currency from stored data 129 | // $protocolSpecific = [ 130 | // 'recipient' => $address, 131 | // ]; 132 | 133 | // $tx_message = ( !empty( $gateway->get_option( 'message' ) ) ? $gateway->get_option( 'message' ) . ' ' : '' ) 134 | // . '(' . $gateway->get_short_order_key( $order->get_order_key() ) . ')'; 135 | // $tx_message_bytes = unpack('C*', $tx_message); // Convert to byte array 136 | 137 | // // Get fees from order meta 138 | // $fee = $order->get_meta( 'crypto_fee_' . $currency ) ?: $cryptoman->get_fees( count( $tx_message_bytes ) )[ $currency ]; 139 | 140 | // if ( $currency === 'eth' ) { 141 | // // For ETH, the fee stored in the order is the gas_price, but the Crypto_Manager fallback returns a keyed array 142 | // $gas_price = is_array( $fee ) ? $fee[ 'gas_price' ] : $fee; 143 | // $protocolSpecific[ 'gasLimit' ] = 21000; 144 | // $protocolSpecific[ 'gasPrice' ] = $gas_price; 145 | // } else { 146 | // $protocolSpecific[ 'fee' ] = intval( $fee ); 147 | // } 148 | 149 | // return woo_nimiq_checkout_reply( [ 150 | // 'type' => 0, // DIRECT 151 | // 'currency' => $currency, 152 | // 'expires' => intval( $order->get_meta( 'crypto_rate_expires' ) ), 153 | // 'amount' => Order_Utils::get_order_total_crypto( $order ), 154 | // 'protocolSpecific' => $protocolSpecific, 155 | // ] ); 156 | } 157 | 158 | function woo_nimiq_checkout_callback_get_state( $request, $order, $gateway ) { 159 | $currency = Order_Utils::get_order_currency( $order, false ); 160 | 161 | if ( empty( $currency ) ) { 162 | // When no currency was selected, respond with the time only. 163 | return woo_nimiq_checkout_reply( [ 164 | 'time' => time(), 165 | 'payment_accepted' => false, 166 | 'payment_state' => 'NOT_FOUND', 167 | ] ); 168 | } 169 | 170 | $transaction_hash = $order->get_meta( 'transaction_hash' ); 171 | 172 | if ( !empty( $transaction_hash ) ) { 173 | return woo_nimiq_checkout_reply( [ 174 | 'time' => time(), 175 | 'payment_accepted' => true, 176 | 'payment_state' => $order->get_meta( 'nc_payment_state' ) ?: 'PAID', 177 | ] ); 178 | } 179 | 180 | // Init validation service 181 | $services = []; 182 | $service_slug = $gateway->get_option( 'validation_service_' . $currency ); 183 | include_once( dirname( dirname( __FILE__ ) ) . DIRECTORY_SEPARATOR . 'validation_services' . DIRECTORY_SEPARATOR . $service_slug . '.php' ); 184 | $service = $services[ $currency ]; 185 | 186 | $payment_state = $service->load_transaction( $transaction_hash, $order, $gateway ); 187 | if ( is_wp_error( $payment_state ) ) { 188 | return woo_nimiq_checkout_error( $payment_state->get_error_message(), 500 ); 189 | } 190 | 191 | $payment_accepted = $service->transaction_found(); 192 | 193 | $order->update_meta_data( 'nc_payment_state', $payment_state ); 194 | $order->save(); 195 | 196 | return woo_nimiq_checkout_reply( [ 197 | 'time' => time(), 198 | 'payment_accepted' => $payment_accepted, 199 | 'payment_state' => $payment_state, 200 | ] ); 201 | } 202 | 203 | function woo_nimiq_checkout_callback_unknown( $request, $order, $gateway ) { 204 | return woo_nimiq_checkout_error( 'Bad command', 406 ); 205 | } 206 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | '); 120 | } 121 | } 122 | $shop_logo_url.on('input', update_shop_logo_preview); 123 | update_shop_logo_preview(); 124 | 125 | // Add change listener for Bitcoin xpub 126 | const $bitcoin_xpub = $('#woocommerce_nimiq_gateway_bitcoin_xpub'); 127 | $bitcoin_xpub.on('input', function() { 128 | const xpub = $bitcoin_xpub.val(); 129 | if (!xpub) return; 130 | let type; 131 | switch (xpub.substr(0, 4)) { 132 | case 'xpub': 133 | case 'tpub': 134 | type = 'bip-44'; 135 | break; 136 | case 'zpub': 137 | case 'vpub': 138 | type = 'bip-84'; 139 | break; 140 | default: break; // TODO Show error feedback to user 141 | } 142 | $('#woocommerce_nimiq_gateway_bitcoin_xpub_type').val(type); 143 | }); 144 | 145 | // Add asterix to required fields 146 | $('.required').after('*'); 147 | 148 | })(jQuery); 149 | -------------------------------------------------------------------------------- /languages/wc-gateway-nimiq-es_ES.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nimiq/woocommerce-gateway-nimiq/512ed0168870cbe9996c7f43df29e302d18c64ec/languages/wc-gateway-nimiq-es_ES.mo -------------------------------------------------------------------------------- /languages/wc-gateway-nimiq-fil_PH.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nimiq/woocommerce-gateway-nimiq/512ed0168870cbe9996c7f43df29e302d18c64ec/languages/wc-gateway-nimiq-fil_PH.mo -------------------------------------------------------------------------------- /languages/wc-gateway-nimiq-fr_FR.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nimiq/woocommerce-gateway-nimiq/512ed0168870cbe9996c7f43df29e302d18c64ec/languages/wc-gateway-nimiq-fr_FR.mo -------------------------------------------------------------------------------- /languages/wc-gateway-nimiq-nl_NL.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nimiq/woocommerce-gateway-nimiq/512ed0168870cbe9996c7f43df29e302d18c64ec/languages/wc-gateway-nimiq-nl_NL.mo -------------------------------------------------------------------------------- /languages/wc-gateway-nimiq-pt_PT.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nimiq/woocommerce-gateway-nimiq/512ed0168870cbe9996c7f43df29e302d18c64ec/languages/wc-gateway-nimiq-pt_PT.mo -------------------------------------------------------------------------------- /languages/wc-gateway-nimiq-ru_RU.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nimiq/woocommerce-gateway-nimiq/512ed0168870cbe9996c7f43df29e302d18c64ec/languages/wc-gateway-nimiq-ru_RU.mo -------------------------------------------------------------------------------- /languages/wc-gateway-nimiq-uk_UA.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nimiq/woocommerce-gateway-nimiq/512ed0168870cbe9996c7f43df29e302d18c64ec/languages/wc-gateway-nimiq-uk_UA.mo -------------------------------------------------------------------------------- /languages/wc-gateway-nimiq-zh_CN.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nimiq/woocommerce-gateway-nimiq/512ed0168870cbe9996c7f43df29e302d18c64ec/languages/wc-gateway-nimiq-zh_CN.mo -------------------------------------------------------------------------------- /nimiq-utils/JSONUtils.php: -------------------------------------------------------------------------------- 1 | $id, 19 | 'returnURL' => $returnURL, 20 | 'command' => $command, 21 | 'responseMethod' => $responseMethod, 22 | ]; 23 | 24 | if (is_array($args)) { 25 | $fragment['args'] = JSONUtils::stringify($args); 26 | } 27 | 28 | // Test if we need to add a trailing slash 29 | $targetUrlComponents = parse_url($targetUrl); 30 | if(empty($targetUrlComponents['path']) && empty($targetUrlComponents['query']) && substr($targetUrl, -1) !== '/') { 31 | $targetUrl .= '/'; 32 | } 33 | 34 | // Append fragment 35 | $targetUrl .= '#' . http_build_query($fragment); 36 | 37 | return $targetUrl; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /nimiq-xpub/README.md: -------------------------------------------------------------------------------- 1 | # Nimiq XPub 2 | 3 | [![Build Status](https://travis-ci.com/nimiq/php-xpub.svg?branch=master)](https://travis-ci.com/nimiq/php-xpub) 4 | 5 | A simple class to derive BTC and ETH extended public keys and addresses without GMP. 6 | Only the BCMath extension is required (but GMP is still used for faster calculations when available). 7 | 8 | Supports `xpub`, `tpub`, `zpub` and `vpub` formats. 9 | 10 | ## Installation 11 | 12 | The Nimiq PHP Utilities are availabe via the [Packagist package registry](https://packagist.org/packages/nimiq/xpub) and can be installed with [Composer](https://getcomposer.org): 13 | 14 | ```bash 15 | composer require nimiq/xpub 16 | ``` 17 | 18 | ### Requirements 19 | 20 | * PHP >= 7.1 21 | * BCMath or GMP extension 22 | 23 | ## Usage 24 | 25 | ```php 26 | # PSR-4 autoloading with composer 27 | use Nimiq\XPub; 28 | 29 | # Create an XPub class instance from an xpub/tpub/zpub/vpub string. 30 | $xpub = XPub::fromString( 'xpub...' ); 31 | 32 | # Derive a child extended public key from it. 33 | $xpub_i = $xpub->derive( $i ); 34 | # You can also pass an array to derive a path. 35 | $xpub_i_k = $xpub->derive( [$i, $k]); 36 | 37 | # An XPub can be serialized back into a string. 38 | # Pass $asHex = true to serialize into a HEX string, base58 is the default. 39 | $xpub_string = $xpub_i->toString( $asHex = false ); 40 | 41 | # An XPub can be converted into an address. 42 | # Pass $coin = 'eth' to convert into an ETH address. 43 | # (xpubs are converted into regular addresses, zpubs are converted into segwit addresses.) 44 | $address = $xpub_i->toAddress( $coin = 'btc' ); 45 | ``` 46 | 47 | _[See the tests](test/test.php) for example usage._ 48 | 49 | The `XPub` class also exposes two common hashing methods: 50 | 51 | ```php 52 | # Get a hash160 53 | $hashed_hex = XPub::hash160( $input_hex ); 54 | 55 | # Get a double sha256 56 | $hashed_hex = XPub::doubleSha256( $input_hex ); 57 | ``` 58 | 59 | ## Development 60 | 61 | ### Testing 62 | 63 | To execute the test suite run: 64 | 65 | ```bash 66 | composer run-script test 67 | # or 68 | php test/test.php 69 | ``` 70 | -------------------------------------------------------------------------------- /nimiq-xpub/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nimiq/xpub", 3 | "version": "1.1.1", 4 | "description": "A simple class to derive BTC and ETH extended public keys and addresses without GMP.", 5 | "keywords": ["nimiq", "blockchain", "bitcoin", "ethereum", "address", "derivation", "bcmath"], 6 | "homepage": "https://github.com/nimiq/php-xpub", 7 | "type": "library", 8 | "license": "Apache-2.0", 9 | "authors": [ 10 | { 11 | "name": "Sören Schwert", 12 | "email": "soeren@nimiq.com" 13 | } 14 | ], 15 | "minimum-stability": "stable", 16 | "scripts": { 17 | "test": "php test/test.php" 18 | }, 19 | "require": { 20 | "php": "^7.1", 21 | "ext-bcmath": "*", 22 | "simplito/elliptic-php": "^1.0", 23 | "stephenhill/base58": "^1.1", 24 | "kornrunner/keccak": "^1.0", 25 | "bitwasp/bech32": "^0.0.1" 26 | }, 27 | "autoload": { 28 | "psr-4": { 29 | "Nimiq\\": "src/" 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /nimiq-xpub/src/XPub.php: -------------------------------------------------------------------------------- 1 | '0488b21e', 17 | 'tpub' => '043587cf', 18 | 'zpub' => '04b24746', 19 | 'vpub' => '045f1cf6', 20 | ]; 21 | 22 | // https://en.bitcoin.it/wiki/List_of_address_prefixes 23 | public const NETWORK_ID = [ 24 | 'xpub' => '00', 25 | 'tpub' => '6f', 26 | ]; 27 | 28 | public const SEGWIT_HRP = [ 29 | 'zpub' => 'bc', 30 | 'vpub' => 'tc', 31 | ]; 32 | 33 | public const SEGWIT_VERSION = 0; 34 | 35 | public static function fromString(string $xpub_base58, string $bip = ''): XPub { 36 | $version = self::bip2version($bip, substr($xpub_base58, 0, 4)); 37 | 38 | if (!array_key_exists($version, self::HEX_VERSION)) { 39 | throw new \Exception('Invalid version!'); 40 | } 41 | 42 | $xpub_bin = (new Base58())->decode($xpub_base58); 43 | 44 | // Validate length 45 | if (strlen($xpub_bin) !== 78 && strlen($xpub_bin) !== 82) { 46 | throw new \Exception('Invalid length!'); 47 | } 48 | 49 | $depth = self::bin2dec(substr($xpub_bin, 4, 1)); 50 | $fpr_par = bin2hex(substr($xpub_bin, 5, 4)); 51 | $i = self::bin2dec(substr($xpub_bin, 9, 4)); 52 | $c = bin2hex(substr($xpub_bin, 13, 32)); 53 | $K = bin2hex(substr($xpub_bin, 45, 33)); 54 | 55 | // Validate checksum if available 56 | $checksum = substr($xpub_bin, 78, 4); 57 | if (!empty($checksum)) { 58 | $base_xpub_hex = bin2hex(substr($xpub_bin, 0, 78)); 59 | if (substr(self::doubleSha256($base_xpub_hex), 0, 8) !== bin2hex($checksum)) { 60 | throw new \Exception('Invalid checksum!'); 61 | } 62 | } 63 | 64 | return new self( 65 | $version, 66 | $depth, 67 | $fpr_par, 68 | $i, 69 | $c, 70 | $K 71 | ); 72 | } 73 | 74 | public static function bin2dec(string $bin): int { 75 | return unpack('C', $bin)[1]; 76 | } 77 | 78 | public static function hash160(string $hex): string { 79 | return hash('ripemd160', hash('sha256', hex2bin($hex), TRUE)); 80 | } 81 | 82 | public static function doubleSha256(string $hex): string { 83 | return hash('sha256', hash('sha256', hex2bin($hex), TRUE)); 84 | } 85 | 86 | private static function bip2version(string $bip, string $prefix): string { 87 | switch($bip) { 88 | case self::BIP44: return in_array($prefix, ['xpub', 'zpub']) ? 'xpub' : 'tpub'; 89 | case self::BIP84: return in_array($prefix, ['xpub', 'zpub']) ? 'zpub' : 'vpub'; 90 | default: return $bip ?: $prefix; 91 | } 92 | } 93 | 94 | public function __construct( 95 | string $version, 96 | int $depth, 97 | string $parent_fingerprint, 98 | int $index, 99 | string $c, 100 | string $K 101 | ) { 102 | $this->version = $version; 103 | $this->depth = $depth; 104 | $this->parent_fingerprint = $parent_fingerprint; 105 | $this->index = $index; 106 | $this->c = $c; 107 | $this->K = $K; 108 | } 109 | 110 | public function derive($indices): XPub { 111 | if (!is_array($indices)) $indices = [$indices]; 112 | $i = array_shift($indices); 113 | 114 | $ec = new EC('secp256k1'); // BTC Elliptic Curve 115 | 116 | $I_key = hex2bin($this->c); 117 | $I_data = hex2bin($this->K) . pack('N', $i); 118 | $I = hash_hmac('sha512', $I_data, $I_key); 119 | $I_L = substr($I, 0, 64); 120 | $I_R = substr($I, 64, 64); 121 | $c_i = $I_R; // Child Chain Code 122 | 123 | $K_par_point = $ec->curve->decodePoint($this->K, 'hex'); 124 | $I_L_point = $ec->g->mul(new BN($I_L, 16)); 125 | $K_i = $K_par_point->add($I_L_point); 126 | $K_i = $K_i->encodeCompressed('hex'); // Child Public Key 127 | 128 | $fpr_par = substr(self::hash160($this->K), 0, 8); // Parent Fingerprint 129 | 130 | $child = new self( 131 | $this->version, 132 | $this->depth + 1, 133 | $fpr_par, 134 | $i, 135 | $c_i, 136 | $K_i 137 | ); 138 | 139 | // Recursive derivation 140 | if (count($indices) > 0) return $child->derive($indices); 141 | 142 | return $child; 143 | } 144 | 145 | public function toString(bool $asHex = false): string { 146 | $xpub_hex = self::HEX_VERSION[$this->version]; 147 | $xpub_hex .= str_pad(dechex($this->depth), 2, '0', STR_PAD_LEFT); 148 | $xpub_hex .= $this->parent_fingerprint; 149 | $xpub_hex .= str_pad(dechex($this->index), 8, '0', STR_PAD_LEFT); 150 | $xpub_hex .= $this->c; 151 | $xpub_hex .= $this->K; 152 | 153 | // Checksum 154 | $xpub_hex .= substr(self::doubleSha256($xpub_hex), 0, 8); 155 | 156 | if ($asHex) return $xpub_hex; 157 | 158 | return (new Base58())->encode(hex2bin($xpub_hex)); 159 | } 160 | 161 | public function toAddress(string $coin = 'btc'): string { 162 | switch ($coin) { 163 | case 'btc': return $this->toBTCAddress(); 164 | case 'eth': return $this->toETHAddress(); 165 | default: throw new \Exception('Coin type "' . $coin . '" not supported!'); 166 | } 167 | } 168 | 169 | private function toBTCAddress(): string { 170 | switch ($this->version) { 171 | case 'xpub': case 'tpub': return $this->toBTCP2PKHAddress(); 172 | case 'zpub': case 'vpub': return $this->toBTCP2WPKHAddress(); 173 | default: throw new \Exception('Version "' . $this->version . '" not supported!'); 174 | } 175 | } 176 | 177 | private function toBTCP2PKHAddress(): string { 178 | $base_address = self::NETWORK_ID[$this->version] . self::hash160($this->K); 179 | $checksum = substr(self::doubleSha256($base_address), 0, 8); 180 | 181 | $address_hex = $base_address . $checksum; 182 | 183 | return (new Base58())->encode(hex2bin($address_hex)); 184 | } 185 | 186 | private function toBTCP2WPKHAddress(): string { 187 | $programm = self::hash160($this->K); 188 | $version = self::SEGWIT_VERSION; 189 | $hrp = self::SEGWIT_HRP[$this->version]; 190 | return Bech32\encodeSegwit($hrp, $version, hex2bin($programm)); 191 | } 192 | 193 | private function toETHAddress(): string { 194 | $ec = new EC('secp256k1'); // ETH Elliptic Curve 195 | $K_full = $ec->keyFromPublic($this->K, 'hex')->getPublic('hex'); 196 | 197 | $K_bin = hex2bin(substr($K_full, 2)); 198 | $hash_hex = Keccak::hash($K_bin, 256); 199 | $base_address = substr($hash_hex, 24, 40); 200 | 201 | return '0x' . $this->encodeETHChecksum($base_address); 202 | } 203 | 204 | private function encodeETHChecksum(string $base_address): string { 205 | $binary = $this->hex2binary(Keccak::hash($base_address, 256)); 206 | 207 | $encoded = ''; 208 | foreach (str_split($base_address) as $i => $char) { 209 | if (strpos('abcdef', $char) !== false) { 210 | $encoded .= $binary[$i * 4] === '1' ? strtoupper($char) : strtolower($char); 211 | } else { 212 | $encoded .= $char; 213 | } 214 | } 215 | return $encoded; 216 | } 217 | 218 | private function hex2binary($hex): string { 219 | $binary = ''; 220 | foreach (str_split($hex, 2) as $hexit) { 221 | $binary .= str_pad(decbin(hexdec($hexit)), 8, '0', STR_PAD_LEFT); 222 | } 223 | return $binary; 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/autoload.php: -------------------------------------------------------------------------------- 1 | $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', 10 | 'a626201e4406003b96eee958a069f504' => $vendorDir . '/bitwasp/bech32/src/bech32.php', 11 | ); 12 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/composer/autoload_namespaces.php: -------------------------------------------------------------------------------- 1 | array($vendorDir . '/kornrunner/keccak/src'), 10 | 'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'), 11 | 'StephenHill\\Benchmarks\\' => array($vendorDir . '/stephenhill/base58/benchmarks'), 12 | 'StephenHill\\' => array($vendorDir . '/stephenhill/base58/src'), 13 | 'Nimiq\\' => array($baseDir . '/src'), 14 | 'Elliptic\\' => array($vendorDir . '/simplito/elliptic-php/lib'), 15 | 'BitWasp\\Bech32\\' => array($vendorDir . '/bitwasp/bech32/src'), 16 | 'BN\\' => array($vendorDir . '/simplito/bn-php/lib'), 17 | 'BI\\' => array($vendorDir . '/simplito/bigint-wrapper-php/lib'), 18 | ); 19 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/composer/autoload_real.php: -------------------------------------------------------------------------------- 1 | = 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); 27 | if ($useStaticLoader) { 28 | require_once __DIR__ . '/autoload_static.php'; 29 | 30 | call_user_func(\Composer\Autoload\ComposerStaticInitf38dd7bf910ade5fd72e09ef3328f74b::getInitializer($loader)); 31 | } else { 32 | $map = require __DIR__ . '/autoload_namespaces.php'; 33 | foreach ($map as $namespace => $path) { 34 | $loader->set($namespace, $path); 35 | } 36 | 37 | $map = require __DIR__ . '/autoload_psr4.php'; 38 | foreach ($map as $namespace => $path) { 39 | $loader->setPsr4($namespace, $path); 40 | } 41 | 42 | $classMap = require __DIR__ . '/autoload_classmap.php'; 43 | if ($classMap) { 44 | $loader->addClassMap($classMap); 45 | } 46 | } 47 | 48 | $loader->register(true); 49 | 50 | if ($useStaticLoader) { 51 | $includeFiles = Composer\Autoload\ComposerStaticInitf38dd7bf910ade5fd72e09ef3328f74b::$files; 52 | } else { 53 | $includeFiles = require __DIR__ . '/autoload_files.php'; 54 | } 55 | foreach ($includeFiles as $fileIdentifier => $file) { 56 | composerRequiref38dd7bf910ade5fd72e09ef3328f74b($fileIdentifier, $file); 57 | } 58 | 59 | return $loader; 60 | } 61 | } 62 | 63 | function composerRequiref38dd7bf910ade5fd72e09ef3328f74b($fileIdentifier, $file) 64 | { 65 | if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { 66 | require $file; 67 | 68 | $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/composer/autoload_static.php: -------------------------------------------------------------------------------- 1 | __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', 11 | 'a626201e4406003b96eee958a069f504' => __DIR__ . '/..' . '/bitwasp/bech32/src/bech32.php', 12 | ); 13 | 14 | public static $prefixLengthsPsr4 = array ( 15 | 'k' => 16 | array ( 17 | 'kornrunner\\' => 11, 18 | ), 19 | 'S' => 20 | array ( 21 | 'Symfony\\Polyfill\\Mbstring\\' => 26, 22 | 'StephenHill\\Benchmarks\\' => 23, 23 | 'StephenHill\\' => 12, 24 | ), 25 | 'N' => 26 | array ( 27 | 'Nimiq\\' => 6, 28 | ), 29 | 'E' => 30 | array ( 31 | 'Elliptic\\' => 9, 32 | ), 33 | 'B' => 34 | array ( 35 | 'BitWasp\\Bech32\\' => 15, 36 | 'BN\\' => 3, 37 | 'BI\\' => 3, 38 | ), 39 | ); 40 | 41 | public static $prefixDirsPsr4 = array ( 42 | 'kornrunner\\' => 43 | array ( 44 | 0 => __DIR__ . '/..' . '/kornrunner/keccak/src', 45 | ), 46 | 'Symfony\\Polyfill\\Mbstring\\' => 47 | array ( 48 | 0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring', 49 | ), 50 | 'StephenHill\\Benchmarks\\' => 51 | array ( 52 | 0 => __DIR__ . '/..' . '/stephenhill/base58/benchmarks', 53 | ), 54 | 'StephenHill\\' => 55 | array ( 56 | 0 => __DIR__ . '/..' . '/stephenhill/base58/src', 57 | ), 58 | 'Nimiq\\' => 59 | array ( 60 | 0 => __DIR__ . '/../..' . '/src', 61 | ), 62 | 'Elliptic\\' => 63 | array ( 64 | 0 => __DIR__ . '/..' . '/simplito/elliptic-php/lib', 65 | ), 66 | 'BitWasp\\Bech32\\' => 67 | array ( 68 | 0 => __DIR__ . '/..' . '/bitwasp/bech32/src', 69 | ), 70 | 'BN\\' => 71 | array ( 72 | 0 => __DIR__ . '/..' . '/simplito/bn-php/lib', 73 | ), 74 | 'BI\\' => 75 | array ( 76 | 0 => __DIR__ . '/..' . '/simplito/bigint-wrapper-php/lib', 77 | ), 78 | ); 79 | 80 | public static function getInitializer(ClassLoader $loader) 81 | { 82 | return \Closure::bind(function () use ($loader) { 83 | $loader->prefixLengthsPsr4 = ComposerStaticInitf38dd7bf910ade5fd72e09ef3328f74b::$prefixLengthsPsr4; 84 | $loader->prefixDirsPsr4 = ComposerStaticInitf38dd7bf910ade5fd72e09ef3328f74b::$prefixDirsPsr4; 85 | 86 | }, null, ClassLoader::class); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/kornrunner/keccak/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Boris Momčilović 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/kornrunner/keccak/README.md: -------------------------------------------------------------------------------- 1 | # php-keccak [![Build Status](https://travis-ci.org/kornrunner/php-keccak.svg?branch=master)](https://travis-ci.org/kornrunner/php-keccak) [![Coverage Status](https://coveralls.io/repos/github/kornrunner/php-keccak/badge.svg?branch=master)](https://coveralls.io/github/kornrunner/php-keccak?branch=master) 2 | Pure PHP implementation of Keccak (SHA-3) 3 | 4 | ## Usage 5 | 6 | ```php 7 | =7.1.0", 14 | "symfony/polyfill-mbstring": "^1.8" 15 | }, 16 | "autoload": { 17 | "psr-4": { 18 | "kornrunner\\": "src" 19 | } 20 | }, 21 | "autoload-dev": { 22 | "psr-4": { 23 | "kornrunner\\": "test" 24 | } 25 | }, 26 | "require-dev": { 27 | "phpunit/phpunit": "~7", 28 | "php-coveralls/php-coveralls": "^2.1" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/simplito/bigint-wrapper-php/LICENSE.md: -------------------------------------------------------------------------------- 1 | 2 | ## MIT LICENSE 3 | 4 | Copyright (C) 2018 Simplito 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a 7 | copy of this software and associated documentation files (the 8 | "Software"), to deal in the Software without restriction, including 9 | without limitation the rights to use, copy, modify, merge, publish, 10 | distribute, sublicense, and/or sell copies of the Software, and to permit 11 | persons to whom the Software is furnished to do so, subject to the 12 | following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 20 | NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 21 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 22 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 23 | USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/simplito/bigint-wrapper-php/README.md: -------------------------------------------------------------------------------- 1 | 2 | # BigInteger wrapper library for PHP 3 | 4 | ## Information 5 | 6 | This library is a common interface for php_gmp and php_bcmath modules. It automatically detects supported modules and uses the best of them (gmp>bcmath). Gmp is a lot faster, but is also missing on many hosting services -- that is why this wrapper has been created. It is used for example in encryption functions of the [PrivMX WebMail](https://privmx.com) software. 7 | 8 | ## Installation 9 | 10 | You can install this library via Composer: 11 | ``` 12 | composer require simplito/bigint-wrapper-php 13 | ``` 14 | 15 | ## Documentation 16 | 17 | If you want to force using a specific implementation, then define constant S_MATH_BIGINTEGER_MODE - set it to "gmp" or "bcmath". If you do not do this, mode of operation and the constant will be set automatically. 18 | 19 | If there are no gmp and bcmath modules, an exception will be thrown. If you want to prevent this, then simply define S_MATH_BIGINTEGER_QUIET constant. 20 | 21 | All functions of this library are implemented as members of class BigInteger, which is located under BI namespace. Instances of BigInteger are immutable - member functions usually return new instances of the BigInteger class. 22 | 23 | 24 | ### ConvertibleToBi - a placeholder type 25 | 26 | To make the below documentation more readable we use the "ConvertibleToBi" type symbol, which in reality can be one of the following types: 27 | - an instance of the BigInteger class 28 | - an integer 29 | - a decimal string 30 | - a gmp resource or class (only when you are in gmp mode) 31 | 32 | If you have a non-decimal string and want to use it -- first you have to convert it to BigInteger class using: 33 | ``` 34 | new BigInteger($myNonDecimalString, $baseOfMyNonDecimalString) 35 | ``` 36 | 37 | ### BI\BigInteger class members 38 | 39 | #### construct(ConvertibleToBi $value = 0, int $base = 10) 40 | Creates a new instance of BigInteger. If you pass an invalid value, an exception will be thrown. If $base === true then passed $value will be used without any check and conversion. Supported bases: 2, 10, 16, 256. 41 | - **GMP implementation:** gmp_init + bin2hex for 256 base 42 | - **Bcmath implementation:** custom(bcadd + bcmul) 43 | 44 | #### static BigInteger|false createSafe(ConvertibleToBi $value = 0, int $base = 10) 45 | Creates a new BigInteger instance in the same way as constructor, but if there is an error, false will be returned instead of throwing an exception. 46 | 47 | #### BigInteger add(ConvertibleToBi $x) 48 | Adds numbers 49 | - **GMP implementation:** gmp_add 50 | - **Bcmath implementation:** bcadd 51 | 52 | #### BigInteger sub(ConvertibleToBi $x) 53 | Subtracts numbers 54 | - **GMP implementation:** gmp_sub 55 | - **Bcmath implementation:** bcsub 56 | 57 | #### BigInteger mul(ConvertibleToBi $x) 58 | Multiplies numbers 59 | - **GMP implementation:** gmp_mul 60 | - **Bcmath implementation:** bcmul 61 | 62 | #### BigInteger div(ConvertibleToBi $x) 63 | Divides numbers 64 | - **GMP implementation:** gmp_div_q 65 | - **Bcmath implementation:** bcdiv 66 | 67 | #### BigInteger divR(ConvertibleToBi $x) 68 | Returns a remainder of the division of numbers. The remainder has the sign of the divided number. 69 | - **GMP implementation:** gmp_div_r 70 | - **Bcmath implementation:** bcmod 71 | 72 | #### array(BigInteger, BigInteger) divQR(ConvertibleToBi $x) 73 | Divides numbers and returns quotient and remainder. Returns an array(), with the first element being quotient, and the second being remainder. 74 | - **GMP implementation:** gmp_div_qr 75 | - **Bcmath implementation:** div + divR 76 | 77 | #### BigInteger mod(ConvertibleToBi $x) 78 | The "division modulo" operation. The result is always non-negative, the sign of divider is ignored. 79 | - **GMP implementation:** gmp_mod 80 | - **Bcmath implementation:** custom (bcmod + bcadd) 81 | 82 | #### BigInteger gcd(ConvertibleToBi $x) 83 | Calculates greatest common divisor 84 | - **GMP implementation:** gmp_gcd 85 | - **Bcmath implementation:** custom (bccomp + bcdiv + bcsub + bcmul) 86 | 87 | #### BigInteger|false modInverse(ConvertibleToBi $x) 88 | Inverses by modulo, returns false if inversion does not exist. 89 | - **GMP implementation:** gmp_invert 90 | - **Bcmath implementation:** custom (gcd) 91 | 92 | #### BigInteger pow(ConvertibleToBi $x) 93 | The power function. 94 | - **GMP implementation:** gmp_pow 95 | - **Bcmath implementation:** bcpow 96 | 97 | #### BigInteger powMod(ConvertibleToBi $x, ConvertibleToBi $n) 98 | The modular power function. 99 | - **GMP implementation:** gmp_powm 100 | - **Bcmath implementation:** bcpowmod 101 | 102 | #### BigInteger abs() 103 | Returns absolute value. 104 | - **GMP implementation:** gmp_abs 105 | - **Bcmath implementation:** check first character 106 | 107 | #### BigInteger neg() 108 | Negates the number 109 | - **GMP implementation:** gmp_neg 110 | - **Bcmath implementation:** check first character 111 | 112 | #### BigInteger binaryAnd(ConvertibleToBi $x) 113 | Bitwise AND. 114 | - **GMP implementation:** gmp_and 115 | - **Bcmath implementation:** custom (toBytes + php string and) 116 | 117 | #### BigInteger binaryOr(ConvertibleToBi $x) 118 | Bitwise OR 119 | - **GMP implementation:** gmp_or 120 | - **Bcmath implementation:** custom (toBytes + php string or) 121 | 122 | #### BigInteger binaryXor(ConvertibleToBi $x) 123 | Bitwise XOR 124 | - **GMP implementation:** gmp_xor 125 | - **Bcmath implementation:** custom (toBytes + php string xor) 126 | 127 | #### BigInteger setbit($index, $bitOn = true) 128 | Sets bit at given index 129 | - **GMP implementation:** gmp_setbit 130 | - **Bcmath implementation:** custom (toBits) 131 | 132 | #### bool testbit($index) 133 | Tests if a bit at given index is set 134 | - **GMP implementation:** gmp_testbit 135 | - **Bcmath implementation:** custom (toBits) 136 | 137 | #### int scan0($start) 138 | Scans for 0, and returns index of first found bit 139 | - **GMP implementation:** gmp_scan0 140 | - **Bcmath implementation:** custom (toBits) 141 | 142 | #### int scan1($start) 143 | Scans for 1, and returns index of first found bit 144 | - **GMP implementation:** gmp_scan1 145 | - **Bcmath implementation:** custom (toBits) 146 | 147 | #### int cmp(ConvertibleToBi $x) 148 | Compares numbers, returns <0, 0, >0 149 | - **GMP implementation:** gmp_cmp 150 | - **Bcmath implementation:** bccomp 151 | 152 | #### bool equals(ConvertibleToBi $x) 153 | Checks if numbers are equal 154 | - **GMP implementation:** gmp_cmp 155 | - **Bcmath implementation:** bccomp 156 | 157 | #### int sign() 158 | Sign of number, returns -1, 0, 1 159 | - **GMP implementation:** gmp_sign 160 | - **Bcmath implementation:** check first character 161 | 162 | #### int toNumber() 163 | Converts to number (use only with small 32/64bit numbers) 164 | - **GMP implementation:** gmp_intval 165 | - **Bcmath implementation:** intval 166 | 167 | #### string toDec() 168 | Converts to decimal string 169 | - **GMP implementation:** gmp_strval 170 | - **Bcmath implementation:** just the value 171 | 172 | #### string toHex() 173 | Converts to hex string 174 | - **GMP implementation:** gmp_strval 175 | - **Bcmath implementation:** toBytes + bin2hex 176 | 177 | #### string toBytes 178 | Converts to binary string 179 | - **GMP implementation:** gmp_strval + hex2bin 180 | - **Bcmath implementation:** custom (bcmod + bcdiv + bccomp) 181 | 182 | #### string toBits() 183 | Converts to bits string (0 and 1 characters) 184 | - **GMP implementation:** gmp_strval 185 | - **Bcmath implementation:** toBytes + decbin 186 | 187 | #### string toString(int $base = 10) 188 | Converts to string using given base (supported bases 2-62, 256) 189 | - **GMP implementation:** all above toX functions, and for non standard gmp_strval 190 | - **Bcmath implementation:** all above toX functions, and for non standard bcmod + bcdiv + bccomp 191 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/simplito/bigint-wrapper-php/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simplito/bigint-wrapper-php", 3 | "description": "Common interface for php_gmp and php_bcmath modules", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "Simplito Team", 8 | "email": "s.smyczynski@simplito.com", 9 | "homepage": "https://simplito.com" 10 | } 11 | ], 12 | "autoload": { 13 | "psr-4": { 14 | "BI\\": "lib/" 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/simplito/bn-php/LICENSE.md: -------------------------------------------------------------------------------- 1 | 2 | ## MIT LICENSE 3 | 4 | Copyright (C) 2018 Simplito 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a 7 | copy of this software and associated documentation files (the 8 | "Software"), to deal in the Software without restriction, including 9 | without limitation the rights to use, copy, modify, merge, publish, 10 | distribute, sublicense, and/or sell copies of the Software, and to permit 11 | persons to whom the Software is furnished to do so, subject to the 12 | following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 20 | NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 21 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 22 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 23 | USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/simplito/bn-php/README.md: -------------------------------------------------------------------------------- 1 | 2 | # BigNum library for PHP 3 | 4 | 5 | ## Information 6 | 7 | This library provides a PHP Big Number API compatible with [bn.js](https://github.com/indutny/bn.js) and is used in Fast PHP ECC library [elliptic-php](https://github.com/simplito/elliptic-php). 8 | 9 | This software is licensed under the MIT License. 10 | 11 | 12 | ## Installation 13 | 14 | You can install this library via Composer: 15 | ``` 16 | composer require simplito/bn-php 17 | ``` 18 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/simplito/bn-php/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simplito/bn-php", 3 | "description": "Big number implementation compatible with bn.js", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "Simplito Team", 8 | "email": "s.smyczynski@simplito.com", 9 | "homepage": "https://simplito.com" 10 | } 11 | ], 12 | "require": { 13 | "simplito/bigint-wrapper-php": "~1.0.0" 14 | }, 15 | "require-dev": { 16 | "phpunit/phpunit": "*" 17 | }, 18 | "autoload": { 19 | "psr-4": { 20 | "BN\\": "lib/" 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/simplito/bn-php/lib/Red.php: -------------------------------------------------------------------------------- 1 | m = Red::primeByName($m); 15 | else 16 | $this->m = $m; 17 | 18 | if( !$this->m->gtn(1) ) 19 | throw new Exception("Modulus must be greater than 1"); 20 | } 21 | 22 | 23 | public static function primeByName($name) 24 | { 25 | switch($name) { 26 | case "k256": 27 | return new BN("ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f", 16); 28 | case "p224": 29 | return new BN("ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001", 16); 30 | case "p192": 31 | return new BN("ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff", 16); 32 | case "p25519": 33 | return new BN("7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed", 16); 34 | default: 35 | throw new Exception("Unknown prime name " . $name); 36 | } 37 | } 38 | 39 | public function verify1(BN $num) 40 | { 41 | if (assert_options(ASSERT_ACTIVE)) assert(!$num->negative()); //,"red works only with positives"); 42 | assert($num->red); //, "red works only with red numbers"); 43 | } 44 | 45 | public function verify2(BN $a, BN $b) 46 | { 47 | if (assert_options(ASSERT_ACTIVE)) assert(!$a->negative() && !$b->negative()); //, "red works only with positives"); 48 | assert($a->red && ($a->red == $b->red)); //, "red works only with red numbers"); 49 | } 50 | 51 | public function imod(BN &$a) { 52 | return $a->umod($this->m)->_forceRed($this); 53 | } 54 | 55 | public function neg(BN $a) 56 | { 57 | if( $a->isZero() ) 58 | return $a->_clone(); 59 | return $this->m->sub($a)->_forceRed($this); 60 | } 61 | 62 | public function add(BN $a, BN $b) 63 | { 64 | $this->verify2($a, $b); 65 | 66 | $res = $a->add($b); 67 | if( $res->cmp($this->m) >= 0 ) 68 | $res->isub($this->m); 69 | return $res->_forceRed($this); 70 | } 71 | 72 | public function iadd(BN &$a, BN $b) 73 | { 74 | $this->verify2($a, $b); 75 | 76 | $a->iadd($b); 77 | if( $a->cmp($this->m) >= 0 ) 78 | $a->isub($this->m); 79 | 80 | return $a; 81 | } 82 | 83 | public function sub(BN $a, BN $b) 84 | { 85 | $this->verify2($a, $b); 86 | 87 | $res = $a->sub($b); 88 | if( $res->negative() ) 89 | $res->iadd($this->m); 90 | 91 | return $res->_forceRed($this); 92 | } 93 | 94 | public function isub(BN &$a, $b) 95 | { 96 | $this->verify2($a, $b); 97 | 98 | $a->isub($b); 99 | if( $a->negative() ) 100 | $a->iadd($this->m); 101 | 102 | return $a; 103 | } 104 | 105 | public function shl(BN $a, $num) { 106 | $this->verify1($a); 107 | return $this->imod($a->ushln($num)); 108 | } 109 | 110 | public function imul(BN &$a, BN $b) { 111 | $this->verify2($a, $b); 112 | $res = $a->imul($b); 113 | return $this->imod($res); 114 | } 115 | 116 | public function mul(BN $a, BN $b) { 117 | $this->verify2($a, $b); 118 | $res = $a->mul($b); 119 | return $this->imod($res); 120 | } 121 | 122 | public function sqr(BN $a) { 123 | $res = $a->_clone(); 124 | return $this->imul($res, $a); 125 | } 126 | 127 | public function isqr(BN &$a) { 128 | return $this->imul($a, $a); 129 | } 130 | 131 | public function sqrt(BN $a) { 132 | if ($a->isZero()) 133 | return $a->_clone(); 134 | 135 | $mod3 = $this->m->andln(3); 136 | assert($mod3 % 2 == 1); 137 | 138 | // Fast case 139 | if ($mod3 == 3) { 140 | $pow = $this->m->add(new BN(1))->iushrn(2); 141 | return $this->pow($a, $pow); 142 | } 143 | 144 | // Tonelli-Shanks algorithm (Totally unoptimized and slow) 145 | // 146 | // Find Q and S, that Q * 2 ^ S = (P - 1) 147 | $q = $this->m->subn(1); 148 | $s = 0; 149 | while (!$q->isZero() && $q->andln(1) == 0) { 150 | $s++; 151 | $q->iushrn(1); 152 | } 153 | if (assert_options(ASSERT_ACTIVE)) assert(!$q->isZero()); 154 | 155 | $one = (new BN(1))->toRed($this); 156 | $nOne = $one->redNeg(); 157 | 158 | // Find quadratic non-residue 159 | // NOTE: Max is such because of generalized Riemann hypothesis. 160 | $lpow = $this->m->subn(1)->iushrn(1); 161 | $z = $this->m->bitLength(); 162 | $z = (new BN(2 * $z * $z))->toRed($this); 163 | 164 | while ($this->pow($z, $lpow)->cmp($nOne) != 0) { 165 | $z->redIAdd($nOne); 166 | } 167 | 168 | $c = $this->pow($z, $q); 169 | $r = $this->pow($a, $q->addn(1)->iushrn(1)); 170 | $t = $this->pow($a, $q); 171 | $m = $s; 172 | while ($t->cmp($one) != 0) { 173 | $tmp = $t; 174 | for ($i = 0; $tmp->cmp($one) != 0; $i++) { 175 | $tmp = $tmp->redSqr(); 176 | } 177 | if ($i >= $m) { 178 | throw new \Exception("Assertion failed"); 179 | } 180 | if ($m - $i - 1 > 54) { 181 | $b = $this->pow($c, (new BN(1))->iushln($m - $i - 1)); 182 | } else { 183 | $b = clone($c); 184 | $b->bi = $c->bi->powMod(1 << ($m - $i - 1), $this->m->bi); 185 | } 186 | 187 | $r = $r->redMul($b); 188 | $c = $b->redSqr(); 189 | $t = $t->redMul($c); 190 | $m = $i; 191 | } 192 | 193 | return $r; 194 | } 195 | 196 | public function invm(BN &$a) { 197 | $res = $a->invm($this->m); 198 | return $this->imod($res); 199 | } 200 | 201 | public function pow(BN $a, BN $num) { 202 | $r = clone($a); 203 | $r->bi = $a->bi->powMod($num->bi, $this->m->bi); 204 | return $r; 205 | } 206 | 207 | public function convertTo(BN $num) { 208 | $r = $num->umod($this->m); 209 | return $r === $num ? $r->_clone() : $r; 210 | } 211 | 212 | public function convertFrom(BN $num) { 213 | $res = $num->_clone(); 214 | $res->red = null; 215 | return $res; 216 | } 217 | } 218 | 219 | ?> 220 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/simplito/elliptic-php/LICENSE.md: -------------------------------------------------------------------------------- 1 | 2 | ## MIT LICENSE 3 | 4 | Copyright (C) 2016 Simplito 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a 7 | copy of this software and associated documentation files (the 8 | "Software"), to deal in the Software without restriction, including 9 | without limitation the rights to use, copy, modify, merge, publish, 10 | distribute, sublicense, and/or sell copies of the Software, and to permit 11 | persons to whom the Software is furnished to do so, subject to the 12 | following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included 15 | in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 20 | NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 21 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 22 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 23 | USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/simplito/elliptic-php/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Fast Elliptic Curve Cryptography in PHP 3 | 4 | 5 | ## Information 6 | 7 | This library is a PHP port of [elliptic](https://github.com/indutny/elliptic), a great JavaScript ECC library. 8 | 9 | * Supported curve types: Short Weierstrass, Montgomery, Edwards, Twisted Edwards. 10 | * Curve 'presets': `secp256k1`, `p192`, `p224`, `p256`, `p384`, `p521`, `curve25519`, `ed25519`. 11 | 12 | This software is licensed under the MIT License. 13 | 14 | Projects which use Fast ECC PHP library: [PrivMX WebMail](https://privmx.com), ... 15 | 16 | 17 | ## Benchmarks 18 | 19 | ``` 20 | +------------------------+----------------+--------+-----+------+ 21 | | subject | mode | rstdev | its | revs | 22 | +------------------------+----------------+--------+-----+------+ 23 | | elliptic#genKeyPair | 323.682ops/s | 2.72% | 5 | 50 | 24 | | mdanter#genKeyPair | 13.794ops/s | 3.18% | 5 | 50 | 25 | +------------------------+----------------+--------+-----+------+ 26 | | elliptic#sign | 307.228ops/s | 3.82% | 5 | 50 | 27 | | mdanter#sign | 14.118ops/s | 2.12% | 5 | 50 | 28 | +------------------------+----------------+--------+-----+------+ 29 | | elliptic#verify | 93.913ops/s | 5.93% | 5 | 50 | 30 | | mdanter#verify | 6.859ops/s | 2.95% | 5 | 50 | 31 | +------------------------+----------------+--------+-----+------+ 32 | | elliptic#dh | 135.166ops/s | 1.67% | 5 | 50 | 33 | | mdanter#dh | 14.302ops/s | 0.89% | 5 | 50 | 34 | +------------------------+----------------+--------+-----+------+ 35 | | elliptic#EdDSASign | 296.756ops/s | 1.09% | 5 | 50 | 36 | +------------------------+----------------+--------+-----+------+ 37 | | elliptic#EdDSAVerify | 67.481ops/s | 2.76% | 5 | 50 | 38 | +------------------------+----------------+--------+-----+------+ 39 | ``` 40 | 41 | 42 | ## Installation 43 | 44 | You can install this library via Composer: 45 | ``` 46 | composer require simplito/elliptic-php 47 | ``` 48 | 49 | 50 | ## Implementation details 51 | 52 | ECDSA is using deterministic `k` value generation as per [RFC6979][0]. Most of 53 | the curve operations are performed on non-affine coordinates (either projective 54 | or extended), various windowing techniques are used for different cases. 55 | 56 | NOTE: `curve25519` could not be used for ECDSA, use `ed25519` instead. 57 | 58 | All operations are performed in reduction context using [bn-php][1]. 59 | 60 | 61 | ## API 62 | 63 | ### ECDSA 64 | 65 | ```php 66 | genKeyPair(); 75 | 76 | // Sign message (can be hex sequence or array) 77 | $msg = 'ab4c3451'; 78 | $signature = $key->sign($msg); 79 | 80 | // Export DER encoded signature to hex string 81 | $derSign = $signature->toDER('hex'); 82 | 83 | // Verify signature 84 | echo "Verified: " . (($key->verify($msg, $derSign) == TRUE) ? "true" : "false") . "\n"; 85 | 86 | // CHECK WITH NO PRIVATE KEY 87 | 88 | // Public key as '04 + x + y' 89 | $pub = "049a1eedae838f2f8ad94597dc4368899ecc751342b464862da80c280d841875ab4607fb6ce14100e71dd7648dd6b417c7872a6ff1ff29195dabd99f15eff023e5"; 90 | 91 | // Signature MUST be either: 92 | // 1) hex-string of DER-encoded signature; or 93 | // 2) DER-encoded signature as byte array; or 94 | // 3) object with two hex-string properties (r and s) 95 | 96 | // case 1 97 | $sig = '30450220233f8bab3f5df09e3d02f45914b0b519d2c04d13ac6964495623806a015df1cd022100c0c279c989b79885b3cc0f117643317bc59414bfb581f38e03557b8532f06603'; 98 | 99 | // case 2 100 | $sig = [48,69,2,32,35,63,139,171,63,93,240,158,61,2,244,89,20,176,181,25,210,192,77,19,172,105,100,73,86,35,128,106,1,93,241,205,2,33,0,192,194,121,201,137,183,152,133,179,204,15,17,118,67,49,123,197,148,20,191,181,129,243,142,3,85,123,133,50,240,102,3]; 101 | 102 | // case 3 103 | $sig = ['r' => '233f8bab3f5df09e3d02f45914b0b519d2c04d13ac6964495623806a015df1cd', 's' => 'c0c279c989b79885b3cc0f117643317bc59414bfb581f38e03557b8532f06603']; 104 | 105 | 106 | // Import public key 107 | $key = $ec->keyFromPublic($pub, 'hex'); 108 | 109 | // Verify signature 110 | echo "Verified: " . (($key->verify($msg, $sig) == TRUE) ? "true" : "false") . "\n"; 111 | ``` 112 | 113 | ### EdDSA 114 | 115 | ```php 116 | keyFromSecret('61233ca4590acd'); // hex string or array of bytes 125 | 126 | // Sign message (can be hex sequence or array) 127 | $msg = 'ab4c3451'; 128 | $signature = $key->sign($msg)->toHex(); 129 | 130 | // Verify signature 131 | echo "Verified: " . (($key->verify($msg, $signature) == TRUE) ? "true" : "false") . "\n"; 132 | 133 | // CHECK WITH NO PRIVATE KEY 134 | 135 | // Import public key 136 | $pub = '2763d01c334250d3e2dda459e5e3f949f667c6bbf0a35012c77ad40b00f0374d'; 137 | $key = $ec->keyFromPublic($pub, 'hex'); 138 | 139 | // Verify signature 140 | $signature = '93899915C2919181A3D244AAAC032CE78EF76D2FFC0355D4BE2C70F48202EBC5F2BB0541D236182F55B11AC6346B524150695E5DE1FEA570786E1CC1F7999404'; 141 | echo "Verified: " . (($key->verify($msg, $signature) == TRUE) ? "true" : "false") . "\n"; 142 | ``` 143 | 144 | ### ECDH 145 | 146 | ```php 147 | genKeyPair(); 154 | $key2 = $ec->genKeyPair(); 155 | 156 | $shared1 = $key1->derive($key2->getPublic()); 157 | $shared2 = $key2->derive($key1->getPublic()); 158 | 159 | echo "Both shared secrets are BN instances\n"; 160 | echo $shared1->toString(16) . "\n"; 161 | echo $shared2->toString(16) . "\n"; 162 | ``` 163 | 164 | NOTE: `.derive()` returns a [BN][1] instance. 165 | 166 | 167 | [0]: http://tools.ietf.org/html/rfc6979 168 | [1]: https://github.com/simplito/bn-php 169 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/simplito/elliptic-php/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simplito/elliptic-php", 3 | "description": "Fast elliptic curve cryptography", 4 | "type": "library", 5 | "homepage": "https://github.com/simplito/elliptic-php", 6 | "keywords": ["elliptic", "curve", "cryptography", "ECC", 7 | "ECDH", "ECDSA", "EdDSA", 8 | "secp256k1", "curve25519", "ed25519", 9 | "nistp192", "nistp224", "nistp256", "nistp384", "nistp521"], 10 | "license": "MIT", 11 | "authors": [ 12 | { 13 | "name": "Simplito Team", 14 | "email": "s.smyczynski@simplito.com", 15 | "homepage": "https://simplito.com" 16 | } 17 | ], 18 | "require": { 19 | "ext-gmp": "*", 20 | "simplito/bn-php": "~1.1.0" 21 | }, 22 | "require-dev": { 23 | "phpunit/phpunit": "*", 24 | "phpbench/phpbench": "@dev" 25 | }, 26 | "autoload": { 27 | "psr-4": { 28 | "Elliptic\\": "lib/" 29 | } 30 | }, 31 | "scripts": { 32 | "test": "phpunit --verbose" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/simplito/elliptic-php/lib/Curve/BaseCurve/Point.php: -------------------------------------------------------------------------------- 1 | curve = $curve; 16 | $this->type = $type; 17 | $this->precomputed = null; 18 | } 19 | 20 | abstract public function eq($other); 21 | 22 | public function validate() { 23 | return $this->curve->validate($this); 24 | } 25 | 26 | public function encodeCompressed($enc) { 27 | return $this->encode($enc, true); 28 | } 29 | 30 | public function encode($enc, $compact = false) { 31 | return Utils::encode($this->_encode($compact), $enc); 32 | } 33 | 34 | protected function _encode($compact) 35 | { 36 | $len = $this->curve->p->byteLength(); 37 | $x = $this->getX()->toArray("be", $len); 38 | 39 | if( $compact ) 40 | { 41 | array_unshift($x, ($this->getY()->isEven() ? 0x02 : 0x03)); 42 | return $x; 43 | } 44 | 45 | return array_merge(array(0x04), $x, $this->getY()->toArray("be", $len)); 46 | } 47 | 48 | public function precompute($power = null) 49 | { 50 | if( isset($this->precomputed) ) 51 | return $this; 52 | 53 | $this->precomputed = array( 54 | "naf" => $this->_getNAFPoints(8), 55 | "doubles" => $this->_getDoubles(4, $power), 56 | "beta" => $this->_getBeta() 57 | ); 58 | 59 | return $this; 60 | } 61 | 62 | protected function _hasDoubles($k) 63 | { 64 | if( !isset($this->precomputed) || !isset($this->precomputed["doubles"]) ) 65 | return false; 66 | 67 | return count($this->precomputed["doubles"]["points"]) >= ceil(($k->bitLength() + 1) / $this->precomputed["doubles"]["step"]); 68 | } 69 | 70 | public function _getDoubles($step = null, $power = null) 71 | { 72 | if( isset($this->precomputed) && isset($this->precomputed["doubles"]) ) 73 | return $this->precomputed["doubles"]; 74 | 75 | $doubles = array( $this ); 76 | $acc = $this; 77 | for($i = 0; $i < $power; $i += $step) 78 | { 79 | for($j = 0; $j < $step; $j++) 80 | $acc = $acc->dbl(); 81 | array_push($doubles, $acc); 82 | } 83 | 84 | return array( 85 | "step" => $step, 86 | "points" => $doubles 87 | ); 88 | } 89 | 90 | public function _getNAFPoints($wnd) 91 | { 92 | if( isset($this->precomputed) && isset($this->precomputed["naf"]) ) 93 | return $this->precomputed["naf"]; 94 | 95 | $res = array( $this ); 96 | $max = (1 << $wnd) - 1; 97 | $dbl = $max === 1 ? null : $this->dbl(); 98 | for($i = 1; $i < $max; $i++) 99 | array_push($res, $res[$i - 1]->add($dbl)); 100 | 101 | return array( 102 | "wnd" => $wnd, 103 | "points" => $res 104 | ); 105 | } 106 | 107 | public function _getBeta() { 108 | return null; 109 | } 110 | 111 | public function dblp($k) 112 | { 113 | $r = $this; 114 | for($i = 0; $i < $k; $i++) 115 | $r = $r->dbl(); 116 | return $r; 117 | } 118 | } 119 | 120 | ?> 121 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/simplito/elliptic-php/lib/Curve/EdwardsCurve.php: -------------------------------------------------------------------------------- 1 | twisted = ($conf["a"] | 0) != 1; 24 | $this->mOneA = $this->twisted && ($conf["a"] | 0) == -1; 25 | $this->extended = $this->mOneA; 26 | parent::__construct("edward", $conf); 27 | 28 | $this->a = (new BN($conf["a"], 16))->umod($this->red->m); 29 | $this->a = $this->a->toRed($this->red); 30 | $this->c = (new BN($conf["c"], 16))->toRed($this->red); 31 | $this->c2 = $this->c->redSqr(); 32 | $this->d = (new BN($conf["d"], 16))->toRed($this->red); 33 | $this->dd = $this->d->redAdd($this->d); 34 | if (assert_options(ASSERT_ACTIVE)) { 35 | assert(!$this->twisted || $this->c->fromRed()->cmpn(1) == 0); 36 | } 37 | $this->oneC = ($conf["c"] | 0) == 1; 38 | } 39 | 40 | public function _mulA($num) { 41 | if ($this->mOneA) 42 | return $num->redNeg(); 43 | else 44 | return $this->a->redMul($num); 45 | } 46 | 47 | public function _mulC($num) { 48 | if ($this->oneC) 49 | return $num; 50 | else 51 | return $this->c->redMul($num); 52 | } 53 | 54 | // Just for compatibility with Short curve 55 | public function jpoint($x, $y, $z, $t = null) { 56 | return $this->point($x, $y, $z, $t); 57 | } 58 | 59 | public function pointFromX($x, $odd = false) { 60 | $x = new BN($x, 16); 61 | if (!$x->red) 62 | $x = $x->toRed($this->red); 63 | 64 | $x2 = $x->redSqr(); 65 | $rhs = $this->c2->redSub($this->a->redMul($x2)); 66 | $lhs = $this->one->redSub($this->c2->redMul($this->d)->redMul($x2)); 67 | 68 | $y2 = $rhs->redMul($lhs->redInvm()); 69 | $y = $y2->redSqrt(); 70 | if ($y->redSqr()->redSub($y2)->cmp($this->zero) != 0) 71 | throw new \Exception('invalid point'); 72 | 73 | $isOdd = $y->fromRed()->isOdd(); 74 | if ($odd && !$isOdd || !$odd && $isOdd) 75 | $y = $y->redNeg(); 76 | 77 | return $this->point($x, $y); 78 | } 79 | 80 | public function pointFromY($y, $odd = false) { 81 | $y = new BN($y, 16); 82 | if (!$y->red) 83 | $y = $y->toRed($this->red); 84 | 85 | // x^2 = (y^2 - 1) / (d y^2 + 1) 86 | $y2 = $y->redSqr(); 87 | $lhs = $y2->redSub($this->one); 88 | $rhs = $y2->redMul($this->d)->redAdd($this->one); 89 | $x2 = $lhs->redMul($rhs->redInvm()); 90 | 91 | if ($x2->cmp($this->zero) == 0) { 92 | if ($odd) 93 | throw new \Exception('invalid point'); 94 | else 95 | return $this->point($this->zero, $y); 96 | } 97 | 98 | $x = $x2->redSqrt(); 99 | if ($x->redSqr()->redSub($x2)->cmp($this->zero) != 0) 100 | throw new \Exception('invalid point'); 101 | 102 | if ($x->isOdd() != $odd) 103 | $x = $x->redNeg(); 104 | 105 | return $this->point($x, $y); 106 | } 107 | 108 | public function validate($point) { 109 | if ($point->isInfinity()) 110 | return true; 111 | 112 | // Curve: A * X^2 + Y^2 = C^2 * (1 + D * X^2 * Y^2) 113 | $point->normalize(); 114 | 115 | $x2 = $point->x->redSqr(); 116 | $y2 = $point->y->redSqr(); 117 | $lhs = $x2->redMul($this->a)->redAdd($y2); 118 | $rhs = $this->c2->redMul($this->one->redAdd($this->d->redMul($x2)->redMul($y2))); 119 | 120 | return $lhs->cmp($rhs) == 0; 121 | } 122 | 123 | public function pointFromJSON($obj) { 124 | return Point::fromJSON($this, $obj); 125 | } 126 | 127 | public function point($x = null, $y = null, $z = null, $t = null) { 128 | return new Point($this, $x, $y, $z, $t); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/simplito/elliptic-php/lib/Curve/MontCurve.php: -------------------------------------------------------------------------------- 1 | a = (new BN($conf["a"], 16))->toRed($this->red); 21 | $this->b = (new BN($conf["b"], 16))->toRed($this->red); 22 | $this->i4 = (new BN(4))->toRed($this->red)->redInvm(); 23 | $this->a24 = $this->i4->redMul($this->a->redAdd($this->two)); 24 | } 25 | 26 | public function validate($point) 27 | { 28 | $x = $point->normalize()->x; 29 | $x2 = $x->redSqr(); 30 | $rhs = $x2->redMul($x)->redAdd($x2->redMul($this->a))->redAdd($x); 31 | $y = $rhs->redSqr(); 32 | 33 | return $y->redSqr()->cmp($rhs) ===0; 34 | } 35 | 36 | public function decodePoint($bytes, $enc = false) { 37 | return $this->point(Utils::toArray($bytes, $enc), 1); 38 | } 39 | 40 | public function point($x, $z) { 41 | return new Point($this, $x, $z); 42 | } 43 | 44 | public function pointFromJSON($obj) { 45 | return Point::fromJSON($this, $obj); 46 | } 47 | } 48 | 49 | ?> 50 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/simplito/elliptic-php/lib/Curve/MontCurve/Point.php: -------------------------------------------------------------------------------- 1 | x = $this->curve->one; 18 | $this->z = $this->curve->zero; 19 | } 20 | else 21 | { 22 | $this->x = new BN($x, 16); 23 | $this->z = new BN($z, 16); 24 | if( !$this->x->red ) 25 | $this->x = $this->x->toRed($this->curve->red); 26 | if( !$this->z->red ) 27 | $this->z = $this->z->toRed($this->curve->red); 28 | } 29 | } 30 | 31 | public function precompute($power = null) { 32 | // No-op 33 | } 34 | 35 | protected function _encode($compact) { 36 | return $this->getX()->toArray("be", $this->curve->p->byteLength()); 37 | } 38 | 39 | public static function fromJSON($curve, $obj) { 40 | return new Point($curve, $obj[0], isset($obj[1]) ? $obj[1] : $curve->one); 41 | } 42 | 43 | public function inspect() 44 | { 45 | if( $this->isInfinity() ) 46 | return ""; 47 | return "x->fromRed()->toString(16, 2) . 48 | " z: " . $this->z->fromRed()->toString(16, 2) + ">"; 49 | } 50 | 51 | public function isInfinity() { 52 | // XXX This code assumes that zero is always zero in red 53 | return $this->z->isZero(); 54 | } 55 | 56 | public function dbl() 57 | { 58 | // http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#doubling-dbl-1987-m-3 59 | // 2M + 2S + 4A 60 | 61 | // A = X1 + Z1 62 | $a = $this->x->redAdd($this->z); 63 | // AA = A^2 64 | $aa = $a->redSqr(); 65 | // B = X1 - Z1 66 | $b = $this->x->redSub($this->z); 67 | // BB = B^2 68 | $bb = $b->redSqr(); 69 | // C = AA - BB 70 | $c = $aa->redSub($bb); 71 | // X3 = AA * BB 72 | $nx = $aa->redMul($bb); 73 | // Z3 = C * (BB + A24 * C) 74 | $nz = $c->redMul( $bb->redAdd($this->curve->a24->redMul($c)) ); 75 | return $this->curve->point($nx, $nz); 76 | } 77 | 78 | public function add($p) { 79 | throw new \Exception('Not supported on Montgomery curve'); 80 | } 81 | 82 | public function diffAdd($p, $diff) 83 | { 84 | // http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#diffadd-dadd-1987-m-3 85 | // 4M + 2S + 6A 86 | 87 | // A = X2 + Z2 88 | $a = $this->x->redAdd($this->z); 89 | // B = X2 - Z2 90 | $b = $this->x->redSub($this->z); 91 | // C = X3 + Z3 92 | $c = $p->x->redAdd($p->z); 93 | // D = X3 - Z3 94 | $d = $p->x->redSub($p->z); 95 | // DA = D * A 96 | $da = $d->redMul($a); 97 | // CB = C * B 98 | $cb = $c->redMul($b); 99 | // X5 = Z1 * (DA + CB)^2 100 | $nx = $diff->z->redMul($da->redAdd($cb)->redSqr()); 101 | // Z5 = X1 * (DA - CB)^2 102 | $nz = $diff->x->redMul($da->redSub($cb)->redSqr()); 103 | 104 | return $this->curve->point($nx, $nz); 105 | } 106 | 107 | public function mul($k) 108 | { 109 | $t = $k->_clone(); 110 | $a = $this; // (N / 2) * Q + Q 111 | $b = $this->curve->point(null, null); // (N / 2) * Q 112 | $c = $this; // Q 113 | 114 | $bits = array(); 115 | while( !$t->isZero() ) 116 | { 117 | // TODO: Maybe it is faster to use toString(2)? 118 | array_push($bits, $t->andln(1)); 119 | $t->iushrn(1); 120 | } 121 | 122 | for($i = count($bits) - 1; $i >= 0; $i--) 123 | { 124 | if( $bits[$i] === 0 ) 125 | { 126 | // N * Q + Q = ((N / 2) * Q + Q)) + (N / 2) * Q 127 | $a = $a->diffAdd($b, $c); 128 | // N * Q = 2 * ((N / 2) * Q + Q)) 129 | $b = $b->dbl(); 130 | } 131 | else 132 | { 133 | // N * Q = ((N / 2) * Q + Q) + ((N / 2) * Q) 134 | $b = $a->diffAdd($b, $c); 135 | // N * Q + Q = 2 * ((N / 2) * Q + Q) 136 | $a = $a->dbl(); 137 | } 138 | } 139 | 140 | return $b; 141 | } 142 | 143 | public function eq($other) { 144 | return $this->getX()->cmp($other->getX()) === 0; 145 | } 146 | 147 | public function normalize() 148 | { 149 | $this->x = $this->x->redMul($this->z->redInvm()); 150 | $this->z = $this->curve->one; 151 | return $this; 152 | } 153 | 154 | public function getX() { 155 | $this->normalize(); 156 | return $this->x->fromRed(); 157 | } 158 | } 159 | 160 | ?> 161 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/simplito/elliptic-php/lib/Curve/PresetCurve.php: -------------------------------------------------------------------------------- 1 | curve = new ShortCurve($options); 16 | elseif ( $options["type"] === "edwards" ) 17 | $this->curve = new EdwardsCurve($options); 18 | else 19 | $this->curve = new MontCurve($options); 20 | 21 | $this->g = $this->curve->g; 22 | $this->n = $this->curve->n; 23 | $this->hash = isset($options["hash"]) ? $options["hash"] : null; 24 | } 25 | } 26 | 27 | ?> 28 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/simplito/elliptic-php/lib/EC.php: -------------------------------------------------------------------------------- 1 | $options); 27 | 28 | $this->curve = $options["curve"]->curve; 29 | $this->n = $this->curve->n; 30 | $this->nh = $this->n->ushrn(1); 31 | 32 | //Point on curve 33 | $this->g = $options["curve"]->g; 34 | $this->g->precompute($options["curve"]->n->bitLength() + 1); 35 | 36 | //Hash for function for DRBG 37 | if( isset($options["hash"]) ) 38 | $this->hash = $options["hash"]; 39 | else 40 | $this->hash = $options["curve"]->hash; 41 | } 42 | 43 | public function keyPair($options) { 44 | return new KeyPair($this, $options); 45 | } 46 | 47 | public function keyFromPrivate($priv, $enc = false) { 48 | return KeyPair::fromPrivate($this, $priv, $enc); 49 | } 50 | 51 | public function keyFromPublic($pub, $enc = false) { 52 | return KeyPair::fromPublic($this, $pub, $enc); 53 | } 54 | 55 | public function genKeyPair($options = null) 56 | { 57 | // Instantiate HmacDRBG 58 | $drbg = new HmacDRBG(array( 59 | "hash" => $this->hash, 60 | "pers" => isset($options["pers"]) ? $options["pers"] : "", 61 | "entropy" => isset($options["entropy"]) ? $options["entropy"] : Utils::randBytes($this->hash["hmacStrength"]), 62 | "nonce" => $this->n->toArray() 63 | )); 64 | 65 | $bytes = $this->n->byteLength(); 66 | $ns2 = $this->n->sub(new BN(2)); 67 | while(true) 68 | { 69 | $priv = new BN($drbg->generate($bytes)); 70 | if( $priv->cmp($ns2) > 0 ) 71 | continue; 72 | 73 | $priv->iaddn(1); 74 | return $this->keyFromPrivate($priv); 75 | } 76 | } 77 | 78 | private function _truncateToN($msg, $truncOnly = false) 79 | { 80 | $delta = intval(($msg->byteLength() * 8) - $this->n->bitLength()); 81 | if( $delta > 0 ) { 82 | $msg = $msg->ushrn($delta); 83 | } 84 | if( $truncOnly || $msg->cmp($this->n) < 0 ) 85 | return $msg; 86 | 87 | return $msg->sub($this->n); 88 | } 89 | 90 | public function sign($msg, $key, $enc = null, $options = null) 91 | { 92 | if( !is_string($enc) ) 93 | { 94 | $options = $enc; 95 | $enc = null; 96 | } 97 | 98 | $key = $this->keyFromPrivate($key, $enc); 99 | $msg = $this->_truncateToN(new BN($msg, 16)); 100 | 101 | // Zero-extend key to provide enough entropy 102 | $bytes = $this->n->byteLength(); 103 | $bkey = $key->getPrivate()->toArray("be", $bytes); 104 | 105 | // Zero-extend nonce to have the same byte size as N 106 | $nonce = $msg->toArray("be", $bytes); 107 | 108 | $kFunc = null; 109 | if( isset($options["k"]) ) 110 | $kFunc = $options["k"]; 111 | else 112 | { 113 | // Instatiate HmacDRBG 114 | $drbg = new HmacDRBG(array( 115 | "hash" => $this->hash, 116 | "entropy" => $bkey, 117 | "nonce" => $nonce, 118 | "pers" => isset($options["pers"]) ? $options["pers"] : "", 119 | "persEnc" => isset($options["persEnc"]) ? $options["persEnc"] : false 120 | )); 121 | 122 | $kFunc = function($iter) use ($drbg, $bytes) { 123 | return new BN($drbg->generate($bytes)); 124 | }; 125 | } 126 | 127 | // Number of bytes to generate 128 | $ns1 = $this->n->sub(new BN(1)); 129 | 130 | $canonical = isset($options["canonical"]) ? $options["canonical"] : false; 131 | for($iter = 0; true; $iter++) 132 | { 133 | $k = $kFunc($iter); 134 | $k = $this->_truncateToN($k, true); 135 | 136 | if( $k->cmpn(1) <= 0 || $k->cmp($ns1) >= 0 ) 137 | continue; 138 | 139 | $kp = $this->g->mul($k); 140 | if( $kp->isInfinity() ) 141 | continue; 142 | 143 | $kpX = $kp->getX(); 144 | $r = $kpX->umod($this->n); 145 | if( $r->isZero() ) 146 | continue; 147 | 148 | $s = $k->invm($this->n)->mul($r->mul($key->getPrivate())->iadd($msg)); 149 | $s = $s->umod($this->n); 150 | if( $s->isZero() ) 151 | continue; 152 | 153 | $recoveryParam = ($kp->getY()->isOdd() ? 1 : 0) | ($kpX->cmp($r) !== 0 ? 2 : 0); 154 | 155 | // Use complement of `s`, if it is > `n / 2` 156 | if( $canonical && $s->cmp($this->nh) > 0 ) 157 | { 158 | $s = $this->n->sub($s); 159 | $recoveryParam ^= 1; 160 | } 161 | 162 | return new Signature(array( 163 | "r" => $r, 164 | "s" => $s, 165 | "recoveryParam" => $recoveryParam 166 | )); 167 | } 168 | } 169 | 170 | public function verify($msg, $signature, $key, $enc = false) 171 | { 172 | $msg = $this->_truncateToN(new BN($msg, 16)); 173 | $key = $this->keyFromPublic($key, $enc); 174 | $signature = new Signature($signature, "hex"); 175 | 176 | // Perform primitive values validation 177 | $r = $signature->r; 178 | $s = $signature->s; 179 | 180 | if( $r->cmpn(1) < 0 || $r->cmp($this->n) >= 0 ) 181 | return false; 182 | if( $s->cmpn(1) < 0 || $s->cmp($this->n) >= 0 ) 183 | return false; 184 | 185 | // Validate signature 186 | $sinv = $s->invm($this->n); 187 | $u1 = $sinv->mul($msg)->umod($this->n); 188 | $u2 = $sinv->mul($r)->umod($this->n); 189 | 190 | if( !$this->curve->_maxwellTrick ) 191 | { 192 | $p = $this->g->mulAdd($u1, $key->getPublic(), $u2); 193 | if( $p->isInfinity() ) 194 | return false; 195 | 196 | return $p->getX()->umod($this->n)->cmp($r) === 0; 197 | } 198 | 199 | // NOTE: Greg Maxwell's trick, inspired by: 200 | // https://git.io/vad3K 201 | 202 | $p = $this->g->jmulAdd($u1, $key->getPublic(), $u2); 203 | if( $p->isInfinity() ) 204 | return false; 205 | 206 | // Compare `p.x` of Jacobian point with `r`, 207 | // this will do `p.x == r * p.z^2` instead of multiplying `p.x` by the 208 | // inverse of `p.z^2` 209 | return $p->eqXToP($r); 210 | } 211 | 212 | public function recoverPubKey($msg, $signature, $j, $enc = false) 213 | { 214 | assert((3 & $j) === $j); //, "The recovery param is more than two bits"); 215 | $signature = new Signature($signature, $enc); 216 | 217 | $e = new BN($msg, 16); 218 | $r = $signature->r; 219 | $s = $signature->s; 220 | 221 | // A set LSB signifies that the y-coordinate is odd 222 | $isYOdd = ($j & 1) == 1; 223 | $isSecondKey = $j >> 1; 224 | 225 | if ($r->cmp($this->curve->p->umod($this->curve->n)) >= 0 && $isSecondKey) 226 | throw new \Exception("Unable to find second key candinate"); 227 | 228 | // 1.1. Let x = r + jn. 229 | if( $isSecondKey ) 230 | $r = $this->curve->pointFromX($r->add($this->curve->n), $isYOdd); 231 | else 232 | $r = $this->curve->pointFromX($r, $isYOdd); 233 | 234 | $eNeg = $this->n->sub($e); 235 | 236 | // 1.6.1 Compute Q = r^-1 (sR - eG) 237 | // Q = r^-1 (sR + -eG) 238 | $rInv = $signature->r->invm($this->n); 239 | return $this->g->mulAdd($eNeg, $r, $s)->mul($rInv); 240 | } 241 | 242 | public function getKeyRecoveryParam($e, $signature, $Q, $enc = false) 243 | { 244 | $signature = new Signature($signature, $enc); 245 | if( $signature->recoveryParam != null ) 246 | return $signature->recoveryParam; 247 | 248 | for($i = 0; $i < 4; $i++) 249 | { 250 | $Qprime = null; 251 | try { 252 | $Qprime = $this->recoverPubKey($e, $signature, $i); 253 | } 254 | catch(\Exception $e) { 255 | continue; 256 | } 257 | 258 | if( $Qprime->eq($Q)) 259 | return $i; 260 | } 261 | throw new \Exception("Unable to find valid recovery factor"); 262 | } 263 | } 264 | 265 | ?> 266 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/simplito/elliptic-php/lib/EC/KeyPair.php: -------------------------------------------------------------------------------- 1 | ec = $ec; 16 | 17 | $this->priv = null; 18 | $this->pub = null; 19 | 20 | if( isset($options["priv"]) ) 21 | $this->_importPrivate($options["priv"], $options["privEnc"]); 22 | 23 | if( isset($options["pub"]) ) 24 | $this->_importPublic($options["pub"], $options["pubEnc"]); 25 | } 26 | 27 | public static function fromPublic($ec, $pub, $enc) 28 | { 29 | if( $pub instanceof KeyPair ) 30 | return $pub; 31 | 32 | return new KeyPair($ec, array( 33 | "pub" => $pub, 34 | "pubEnc" => $enc 35 | )); 36 | } 37 | 38 | public static function fromPrivate($ec, $priv, $enc) 39 | { 40 | if( $priv instanceof KeyPair ) 41 | return $priv; 42 | 43 | return new KeyPair($ec, array( 44 | "priv" => $priv, 45 | "privEnc" => $enc 46 | )); 47 | } 48 | 49 | public function validate() 50 | { 51 | $pub = $this->getPublic(); 52 | 53 | if( $pub->isInfinity() ) 54 | return array( "result" => false, "reason" => "Invalid public key" ); 55 | 56 | if( !$pub->validate() ) 57 | return array( "result" => false, "reason" => "Public key is not a point" ); 58 | 59 | if( !$pub->mul($this->ec->curve->n)->isInfinity() ) 60 | return array( "result" => false, "reason" => "Public key * N != O" ); 61 | 62 | return array( "result" => true, "reason" => null ); 63 | } 64 | 65 | public function getPublic($compact = false, $enc = "") 66 | { 67 | //compact is optional argument 68 | if( is_string($compact) ) 69 | { 70 | $enc = $compact; 71 | $compact = false; 72 | } 73 | 74 | if( $this->pub === null ) 75 | $this->pub = $this->ec->g->mul($this->priv); 76 | 77 | if( !$enc ) 78 | return $this->pub; 79 | 80 | return $this->pub->encode($enc, $compact); 81 | } 82 | 83 | public function getPrivate($enc = false) 84 | { 85 | if( $enc === "hex" ) 86 | return $this->priv->toString(16, 2); 87 | 88 | return $this->priv; 89 | } 90 | 91 | private function _importPrivate($key, $enc) 92 | { 93 | $this->priv = new BN($key, (isset($enc) && $enc) ? $enc : 16); 94 | 95 | // Ensure that the priv won't be bigger than n, otherwise we may fail 96 | // in fixed multiplication method 97 | $this->priv = $this->priv->umod($this->ec->curve->n); 98 | } 99 | 100 | private function _importPublic($key, $enc) 101 | { 102 | $x = $y = null; 103 | if ( is_object($key) ) { 104 | $x = $key->x; 105 | $y = $key->y; 106 | } elseif ( is_array($key) ) { 107 | $x = isset($key["x"]) ? $key["x"] : null; 108 | $y = isset($key["y"]) ? $key["y"] : null; 109 | } 110 | 111 | if( $x != null || $y != null ) 112 | $this->pub = $this->ec->curve->point($x, $y); 113 | else 114 | $this->pub = $this->ec->curve->decodePoint($key, $enc); 115 | } 116 | 117 | //ECDH 118 | public function derive($pub) { 119 | return $pub->mul($this->priv)->getX(); 120 | } 121 | 122 | //ECDSA 123 | public function sign($msg, $enc = false, $options = false) { 124 | return $this->ec->sign($msg, $this, $enc, $options); 125 | } 126 | 127 | public function verify($msg, $signature) { 128 | return $this->ec->verify($msg, $signature, $this); 129 | } 130 | 131 | public function inspect() { 132 | return "priv) ? $this->priv->toString(16, 2) : "") . 133 | " pub: " . (isset($this->pub) ? $this->pub->inspect() : "") . ">"; 134 | } 135 | 136 | public function __debugInfo() { 137 | return ["priv" => $this->priv, "pub" => $this->pub]; 138 | } 139 | } 140 | 141 | ?> 142 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/simplito/elliptic-php/lib/EC/Signature.php: -------------------------------------------------------------------------------- 1 | r = $options->r; 18 | $this->s = $options->s; 19 | $this->recoveryParam = $options->recoveryParam; 20 | return; 21 | } 22 | 23 | if (isset($options['r'])) { 24 | assert(isset($options["r"]) && isset($options["s"])); //, "Signature without r or s"); 25 | $this->r = new BN($options["r"], 16); 26 | $this->s = new BN($options["s"], 16); 27 | 28 | if( isset($options["recoveryParam"]) ) 29 | $this->recoveryParam = $options["recoveryParam"]; 30 | else 31 | $this->recoveryParam = null; 32 | return; 33 | } 34 | 35 | if (!$this->_importDER($options, $enc)) 36 | throw new \Exception('Unknown signature format'); 37 | 38 | } 39 | 40 | private static function getLength($buf, &$pos) 41 | { 42 | $initial = $buf[$pos++]; 43 | if( !($initial & 0x80) ) 44 | return $initial; 45 | 46 | $octetLen = $initial & 0xf; 47 | $val = 0; 48 | for($i = 0; $i < $octetLen; $i++) 49 | { 50 | $val = $val << 8; 51 | $val = $val | $buf[$pos]; 52 | $pos++; 53 | } 54 | return $val; 55 | } 56 | 57 | private static function rmPadding(&$buf) 58 | { 59 | $i = 0; 60 | $len = count($buf) - 1; 61 | while($i < $len && !$buf[$i] && !($buf[$i+1] & 0x80) ) 62 | $i++; 63 | 64 | if( $i === 0 ) 65 | return $buf; 66 | 67 | return array_slice($buf, $i); 68 | } 69 | 70 | private function _importDER($data, $enc) 71 | { 72 | $data = Utils::toArray($data, $enc); 73 | $dataLen = count($data); 74 | $place = 0; 75 | 76 | if( $data[$place++] !== 0x30) 77 | return false; 78 | 79 | $len = self::getLength($data, $place); 80 | if( ($len + $place) !== $dataLen ) 81 | return false; 82 | 83 | if( $data[$place++] !== 0x02 ) 84 | return false; 85 | 86 | $rlen = self::getLength($data, $place); 87 | $r = array_slice($data, $place, $rlen); 88 | $place += $rlen; 89 | 90 | if( $data[$place++] !== 0x02 ) 91 | return false; 92 | 93 | $slen = self::getLength($data, $place); 94 | if( $dataLen !== $slen + $place ) 95 | return false; 96 | $s = array_slice($data, $place, $slen); 97 | 98 | if( $r[0] === 0 && ($r[1] & 0x80 ) ) 99 | $r = array_slice($r, 1); 100 | if( $s[0] === 0 && ($s[1] & 0x80 ) ) 101 | $s = array_slice($s, 1); 102 | 103 | $this->r = new BN($r); 104 | $this->s = new BN($s); 105 | $this->recoveryParam = null; 106 | 107 | return true; 108 | } 109 | 110 | private static function constructLength(&$arr, $len) 111 | { 112 | if( $len < 0x80 ) 113 | { 114 | array_push($arr, $len); 115 | return; 116 | } 117 | 118 | $octets = 1 + (log($len) / M_LN2 >> 3); 119 | array_push($arr, $octets | 0x80); 120 | while(--$octets) 121 | array_push($arr, ($len >> ($octets << 3)) & 0xff); 122 | array_push($arr, $len); 123 | } 124 | 125 | public function toDER($enc = false) 126 | { 127 | $r = $this->r->toArray(); 128 | $s = $this->s->toArray(); 129 | 130 | //Pad values 131 | if( $r[0] & 0x80 ) 132 | array_unshift($r, 0); 133 | if( $s[0] & 0x80 ) 134 | array_unshift($s, 0); 135 | 136 | $r = self::rmPadding($r); 137 | $s = self::rmPadding($s); 138 | 139 | while(!$s[0] && !($s[1] & 0x80)) 140 | array_slice($s, 1); 141 | 142 | $arr = array(0x02); 143 | self::constructLength($arr, count($r)); 144 | $arr = array_merge($arr, $r, array(0x02)); 145 | self::constructLength($arr, count($s)); 146 | $backHalf = array_merge($arr, $s); 147 | $res = array(0x30); 148 | self::constructLength($res, count($backHalf)); 149 | $res = array_merge($res, $backHalf); 150 | 151 | return Utils::encode($res, $enc); 152 | } 153 | } 154 | 155 | ?> 156 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/simplito/elliptic-php/lib/EdDSA.php: -------------------------------------------------------------------------------- 1 | curve; 19 | $this->curve = $curve; 20 | $this->g = $curve->g; 21 | $this->g->precompute($curve->n->bitLength() + 1); 22 | 23 | $this->pointClass = get_class($curve->point()); 24 | $this->encodingLength = intval(ceil($curve->n->bitLength() / 8)); 25 | // TODO: !!! 26 | $this->hash = [ "algo" => "sha512" ]; 27 | } 28 | 29 | /** 30 | * @param {Array|String} message - message bytes 31 | * @param {Array|String|KeyPair} secret - secret bytes or a keypair 32 | * @returns {Signature} - signature 33 | */ 34 | public function sign($message, $secret) { 35 | $message = Utils::parseBytes($message); 36 | $key = $this->keyFromSecret($secret); 37 | $r = $this->hashInt($key->messagePrefix(), $message); 38 | $R = $this->g->mul($r); 39 | $Rencoded = $this->encodePoint($R); 40 | $s_ = $this->hashInt($Rencoded, $key->pubBytes(), $message) 41 | ->mul($key->priv()); 42 | $S = $r->add($s_)->umod($this->curve->n); 43 | return $this->makeSignature([ "R" => $R, "S" => $S, "Rencoded" => $Rencoded ]); 44 | } 45 | 46 | /** 47 | * @param {Array} message - message bytes 48 | * @param {Array|String|Signature} sig - sig bytes 49 | * @param {Array|String|Point|KeyPair} pub - public key 50 | * @returns {Boolean} - true if public key matches sig of message 51 | */ 52 | public function verify($message, $sig, $pub) { 53 | $message = Utils::parseBytes($message); 54 | $sig = $this->makeSignature($sig); 55 | $key = $this->keyFromPublic($pub); 56 | $h = $this->hashInt($sig->Rencoded(), $key->pubBytes(), $message); 57 | $SG = $this->g->mul($sig->S()); 58 | $RplusAh = $sig->R()->add($key->pub()->mul($h)); 59 | return $RplusAh->eq($SG); 60 | } 61 | 62 | public function hashInt() { 63 | $arguments = func_get_args(); 64 | // TODO: refactor when hash-php is ready 65 | $hash = hash_init($this->hash["algo"]); 66 | for ($i = 0; $i < count($arguments); $i++) 67 | hash_update($hash, Utils::toBin($arguments[$i])); 68 | return Utils::intFromLE(hash_final($hash))->umod($this->curve->n); 69 | } 70 | 71 | public function keyFromPublic($pub) { 72 | return KeyPair::fromPublic($this, $pub); 73 | } 74 | 75 | public function keyFromSecret($secret) { 76 | return KeyPair::fromSecret($this, $secret); 77 | } 78 | 79 | public function makeSignature($sig) { 80 | if ($sig instanceof Signature) 81 | return $sig; 82 | return new Signature($this, $sig); 83 | } 84 | 85 | /** 86 | * * https://tools.ietf.org/html/draft-josefsson-eddsa-ed25519-03#section-5.2 87 | * 88 | * EdDSA defines methods for encoding and decoding points and integers. These are 89 | * helper convenience methods, that pass along to utility functions implied 90 | * parameters. 91 | * 92 | */ 93 | public function encodePoint($point) { 94 | $enc = $point->getY()->toArray('le', $this->encodingLength); 95 | $enc[$this->encodingLength - 1] |= $point->getX()->isOdd() ? 0x80 : 0; 96 | return $enc; 97 | } 98 | 99 | public function decodePoint($bytes) { 100 | $bytes = Utils::parseBytes($bytes); 101 | 102 | $lastIx = count($bytes) - 1; 103 | $normed = $bytes; 104 | $normed[$lastIx] = $bytes[$lastIx] & ~0x80; 105 | $xIsOdd = ($bytes[$lastIx] & 0x80) !== 0; 106 | 107 | $y = Utils::intFromLE($normed); 108 | return $this->curve->pointFromY($y, $xIsOdd); 109 | } 110 | 111 | public function encodeInt($num) { 112 | return $num->toArray('le', $this->encodingLength); 113 | } 114 | 115 | public function decodeInt($bytes) { 116 | return Utils::intFromLE($bytes); 117 | } 118 | 119 | public function isPoint($val) { 120 | return is_a($val, $this->pointClass); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/simplito/elliptic-php/lib/EdDSA/KeyPair.php: -------------------------------------------------------------------------------- 1 | } [params.secret] - secret seed bytes 14 | * @param {Point} [params.pub] - public key point (aka `A` in eddsa terms) 15 | * @param {Array} [params.pub] - public key point encoded as bytes 16 | * 17 | */ 18 | function __construct($eddsa, $params) { 19 | $this->eddsa = $eddsa; 20 | $this->_secret = isset($params["secret"]) ? Utils::parseBytes($params["secret"]) : null; 21 | if (!isset($params["pub"])) { 22 | $this->_pub = null; 23 | $this->_pubBytes = null; 24 | return; 25 | } 26 | if ($eddsa->isPoint($params["pub"])) 27 | $this->_pub = $params["pub"]; 28 | else 29 | $this->_pubBytes = Utils::parseBytes($params["pub"]); 30 | } 31 | 32 | public static function fromPublic($eddsa, $pub) { 33 | if ($pub instanceof KeyPair) 34 | return $pub; 35 | return new KeyPair($eddsa, [ "pub" => $pub ]); 36 | } 37 | 38 | public static function fromSecret($eddsa, $secret) { 39 | if ($secret instanceof KeyPair) 40 | return $secret; 41 | return new KeyPair($eddsa, [ "secret" => $secret ]); 42 | } 43 | 44 | private $_secret; 45 | public function secret() { 46 | return $this->_secret; 47 | } 48 | 49 | public function pubBytes() { 50 | if (!$this->_pubBytes) 51 | $this->_pubBytes = $this->eddsa->encodePoint($this->pub()); 52 | return $this->_pubBytes; 53 | } 54 | 55 | private $_pub; 56 | public function pub() { 57 | if (!$this->_pub) { 58 | if ($this->_pubBytes) 59 | $this->_pub = $this->eddsa->decodePoint($this->_pubBytes); 60 | else 61 | $this->_pub = $this->eddsa->g->mul($this->priv()); 62 | } 63 | return $this->_pub; 64 | } 65 | 66 | private $_privBytes; 67 | public function privBytes() { 68 | if (!$this->_privBytes) { 69 | $eddsa = $this->eddsa; 70 | $hash = $this->hash(); 71 | $lastIx = $eddsa->encodingLength - 1; 72 | 73 | $a = array_slice($hash, 0, $eddsa->encodingLength); 74 | $a[0] &= 248; 75 | $a[$lastIx] &= 127; 76 | $a[$lastIx] |= 64; 77 | $this->_privBytes = $a; 78 | } 79 | return $this->_privBytes; 80 | } 81 | 82 | private $_priv; 83 | public function priv() { 84 | if (!$this->_priv) { 85 | $this->_priv = $this->eddsa->decodeInt($this->privBytes()); 86 | } 87 | return $this->_priv; 88 | } 89 | 90 | private $_hash; 91 | public function hash() { 92 | if (!$this->_hash) { 93 | // TODO: !!! 94 | $hash = hash_init('sha512'); 95 | hash_update($hash, Utils::toBin($this->secret())); 96 | $this->_hash = Utils::toArray( hash_final($hash), 'hex' ); 97 | } 98 | return $this->_hash; 99 | } 100 | 101 | private $_messagePrefix; 102 | public function messagePrefix() { 103 | if (!$this->_messagePrefix) { 104 | $this->_messagePrefix = array_slice($this->hash(), $this->eddsa->encodingLength); 105 | } 106 | return $this->_messagePrefix; 107 | } 108 | 109 | public function sign($message) { 110 | assert($this->_secret); //, 'KeyPair can only verify'); 111 | return $this->eddsa->sign($message, $this); 112 | } 113 | 114 | public function verify($message, $sig) { 115 | return $this->eddsa->verify($message, $sig, $this); 116 | } 117 | 118 | public function getSecret($enc = false) { 119 | assert($this->_secret); //, 'KeyPair is public only'); 120 | return Utils::encode($this->secret(), $enc); 121 | } 122 | 123 | public function getPublic($enc = false) { 124 | return Utils::encode($this->pubBytes(), $enc); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/simplito/elliptic-php/lib/EdDSA/Signature.php: -------------------------------------------------------------------------------- 1 | |Object} sig - 14 | * @param {Array|Point} [sig.R] - R point as Point or bytes 15 | * @param {Array|bn} [sig.S] - S scalar as bn or bytes 16 | * @param {Array} [sig.Rencoded] - R point encoded 17 | * @param {Array} [sig.Sencoded] - S scalar encoded 18 | */ 19 | function __construct($eddsa, $sig) { 20 | $this->eddsa = $eddsa; 21 | 22 | if (is_string($sig)) 23 | $sig = Utils::parseBytes($sig); 24 | 25 | if (is_array($sig) && !isset($sig["R"])) { 26 | $sig = [ 27 | "R" => array_slice($sig, 0, $eddsa->encodingLength), 28 | "S" => array_slice($sig, $eddsa->encodingLength) 29 | ]; 30 | } 31 | 32 | assert($sig["R"] && $sig["S"]); //, 'Signature without R or S'); 33 | 34 | if ($eddsa->isPoint($sig["R"])) 35 | $this->_R = $sig["R"]; 36 | if ($sig["S"] instanceof BN) 37 | $this->_S = $sig["S"]; 38 | 39 | $this->_Rencoded = is_array($sig["R"]) ? $sig["R"] : (isset($sig["Rencoded"]) ?$sig["Rencoded"] : null); 40 | $this->_Sencoded = is_array($sig["S"]) ? $sig["S"] : (isset($sig["Sencoded"]) ?$sig["Sencoded"] : null); 41 | } 42 | 43 | private $_S; 44 | public function S() { 45 | if (!$this->_S) { 46 | $this->_S = $this->eddsa->decodeInt($this->Sencoded()); 47 | } 48 | return $this->_S; 49 | } 50 | 51 | private $_R; 52 | public function R() { 53 | if (!$this->_R) { 54 | $this->_R = $this->eddsa->decodePoint($this->Rencoded()); 55 | } 56 | return $this->_R; 57 | } 58 | 59 | private $_Rencoded; 60 | public function Rencoded() { 61 | if (!$this->_Rencoded) { 62 | $this->_Rencoded = $this->eddsa->encodePoint($this->R()); 63 | } 64 | return $this->_Rencoded; 65 | } 66 | 67 | private $_Sencoded; 68 | public function Sencoded() { 69 | if (!$this->_Sencoded) { 70 | $this->_Sencoded = $this->eddsa->encodeInt($this->S()); 71 | } 72 | return $this->_Sencoded; 73 | } 74 | 75 | public function toBytes() { 76 | return array_merge($this->Rencoded(), $this->Sencoded()); 77 | } 78 | 79 | public function toHex() { 80 | return strtoupper(Utils::encode($this->toBytes(), 'hex')); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/simplito/elliptic-php/lib/HmacDRBG.php: -------------------------------------------------------------------------------- 1 | hash = $options["hash"]; 32 | $this->predResist = $options["predResist"]; 33 | 34 | $this->outLen = $this->hash["outSize"]; 35 | $this->minEntropy = $options["minEntropy"] ?: $this->hash["hmacStrength"]; 36 | 37 | $this->reseed = null; 38 | $this->reseedInterval = null; 39 | $this->K = null; 40 | $this->V = null; 41 | 42 | $entropy = Utils::toBin($options["entropy"], $options["entropyEnc"]); 43 | $nonce = Utils::toBin($options["nonce"], $options["nonceEnc"]); 44 | $pers = Utils::toBin($options["pers"], $options["persEnc"]); 45 | 46 | if (assert_options(ASSERT_ACTIVE)) { 47 | assert(strlen($entropy) >= ($this->minEntropy / 8)); 48 | } 49 | $this->_init($entropy, $nonce, $pers); 50 | } 51 | 52 | private function _init($entropy, $nonce, $pers) 53 | { 54 | $seed = $entropy . $nonce . $pers; 55 | 56 | $this->K = str_repeat(chr(0x00), $this->outLen / 8); 57 | $this->V = str_repeat(chr(0x01), $this->outLen / 8); 58 | 59 | $this->_update($seed); 60 | $this->reseed = 1; 61 | $this->reseedInterval = 0x1000000000000; // 2^48 62 | } 63 | 64 | private function _hmac() 65 | { 66 | return hash_init($this->hash["algo"], HASH_HMAC, $this->K); 67 | } 68 | 69 | private function _update($seed = false) 70 | { 71 | $kmac = $this->_hmac(); 72 | hash_update($kmac, $this->V); 73 | hash_update($kmac, chr(0x00)); 74 | 75 | if( $seed ) 76 | hash_update($kmac, $seed); 77 | $this->K = hash_final($kmac, true); 78 | 79 | $kmac = $this->_hmac(); 80 | hash_update($kmac, $this->V); 81 | $this->V = hash_final($kmac, true); 82 | 83 | if(!$seed) 84 | return; 85 | 86 | $kmac = $this->_hmac(); 87 | hash_update($kmac, $this->V); 88 | hash_update($kmac, chr(0x01)); 89 | hash_update($kmac, $seed); 90 | $this->K = hash_final($kmac, true); 91 | 92 | $kmac = $this->_hmac(); 93 | hash_update($kmac, $this->V); 94 | $this->V = hash_final($kmac, true); 95 | } 96 | 97 | // TODO: reseed() 98 | 99 | public function generate($len, $enc = null, $add = null, $addEnc = null) 100 | { 101 | if ($this->reseed > $this->reseedInterval) 102 | throw new \Exception("Reseed is required"); 103 | 104 | // Optional encoding 105 | if( !is_string($enc) ) 106 | { 107 | $addEnc = $enc; 108 | $add = $enc; 109 | $enc = null; 110 | } 111 | 112 | // Optional additional data 113 | if( $add != null ) { 114 | $add = Utils::toBin($add, $addEnc); 115 | $this->_update($add); 116 | } 117 | 118 | $temp = ""; 119 | while( strlen($temp) < $len ) 120 | { 121 | $hmac = $this->_hmac(); 122 | hash_update($hmac, $this->V); 123 | $this->V = hash_final($hmac, true); 124 | $temp .= $this->V; 125 | } 126 | 127 | $res = substr($temp, 0, $len); 128 | $this->_update($add); 129 | $this->reseed++; 130 | 131 | return Utils::encode(Utils::toArray($res), $enc); 132 | } 133 | } 134 | 135 | ?> 136 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/simplito/elliptic-php/lib/Utils.php: -------------------------------------------------------------------------------- 1 | cmpn(1) >= 0 ) 68 | { 69 | if( !$k->isOdd() ) 70 | array_push($naf, 0); 71 | else 72 | { 73 | $mod = $k->andln($ws - 1); 74 | $z = $mod; 75 | if( $mod > (($ws >> 1) - 1)) 76 | $z = ($ws >> 1) - $mod; 77 | $k->isubn($z); 78 | array_push($naf, $z); 79 | } 80 | 81 | // Optimization, shift by word if possible 82 | $shift = (!$k->isZero() && $k->andln($ws - 1) === 0) ? ($w + 1) : 1; 83 | for($i = 1; $i < $shift; $i++) 84 | array_push($naf, 0); 85 | $k->iushrn($shift); 86 | } 87 | 88 | return $naf; 89 | } 90 | 91 | // Represent k1, k2 in a Joint Sparse Form 92 | public static function getJSF($k1, $k2) 93 | { 94 | $jsf = array( array(), array() ); 95 | $k1 = $k1->_clone(); 96 | $k2 = $k2->_clone(); 97 | $d1 = 0; 98 | $d2 = 0; 99 | 100 | while( $k1->cmpn(-$d1) > 0 || $k2->cmpn(-$d2) > 0 ) 101 | { 102 | // First phase 103 | $m14 = ($k1->andln(3) + $d1) & 3; 104 | $m24 = ($k2->andln(3) + $d2) & 3; 105 | if( $m14 === 3 ) 106 | $m14 = -1; 107 | if( $m24 === 3 ) 108 | $m24 = -1; 109 | 110 | $u1 = 0; 111 | if( ($m14 & 1) !== 0 ) 112 | { 113 | $m8 = ($k1->andln(7) + $d1) & 7; 114 | $u1 = ( ($m8 === 3 || $m8 === 5) && $m24 === 2 ) ? -$m14 : $m14; 115 | } 116 | array_push($jsf[0], $u1); 117 | 118 | $u2 = 0; 119 | if( ($m24 & 1) !== 0 ) 120 | { 121 | $m8 = ($k2->andln(7) + $d2) & 7; 122 | $u2 = ( ($m8 === 3 || $m8 === 5) && $m14 === 2 ) ? -$m24 : $m24; 123 | } 124 | array_push($jsf[1], $u2); 125 | 126 | // Second phase 127 | if( (2 * $d1) === ($u1 + 1) ) 128 | $d1 = 1 - $d1; 129 | if( (2 * $d2) === ($u2 + 1) ) 130 | $d2 = 1 - $d2; 131 | $k1->iushrn(1); 132 | $k2->iushrn(1); 133 | } 134 | 135 | return $jsf; 136 | } 137 | 138 | public static function intFromLE($bytes) { 139 | return new BN($bytes, 'hex', 'le'); 140 | } 141 | 142 | public static function parseBytes($bytes) { 143 | if (is_string($bytes)) 144 | return self::toArray($bytes, 'hex'); 145 | return $bytes; 146 | } 147 | 148 | public static function randBytes($count) 149 | { 150 | $res = ""; 151 | for($i = 0; $i < $count; $i++) 152 | $res .= chr(rand(0, 255)); 153 | return $res; 154 | } 155 | 156 | public static function optionAssert(&$array, $key, $value = false, $required = false) 157 | { 158 | if( isset($array[$key]) ) 159 | return; 160 | if( $required ) 161 | throw new Exception("Missing option " . $key); 162 | $array[$key] = $value; 163 | } 164 | } 165 | 166 | ?> 167 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/stephenhill/base58/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stephenhill/base58", 3 | "description": "Base58 Encoding and Decoding Library for PHP", 4 | "require-dev": { 5 | "phpunit/phpunit": "4.*", 6 | "athletic/athletic": "~0.1" 7 | }, 8 | "license": "MIT", 9 | "authors": [ 10 | { 11 | "name": "Stephen Hill", 12 | "email": "stephen@gatekiller.co.uk" 13 | } 14 | ], 15 | "config": { 16 | "bin-dir": "bin" 17 | }, 18 | "autoload": { 19 | "psr-4": { 20 | "StephenHill\\": "src/", 21 | "StephenHill\\Benchmarks\\": "benchmarks/" 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /nimiq-xpub/vendor/stephenhill/base58/contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | I welcome anyone to contribute to this project. All bug reports, feature requests, and pull requests are greatly appriciated. 4 | 5 | To contribute some code, please do the following: 6 | 7 | 1. Fork this repository. 8 | 2. Create a new branch 9 | 3. Commit your changes to this branch. 10 | 4. Make sure your code follows the coding guidelines below. 11 | 5. When your happy with you changes, push this branch to Github. 12 | 6. Create a Pull Request into the master branch. 13 | 14 | ## Coding Guidelines 15 | 16 | Please ensure your pull request adheres to the following: 17 | 18 | * New code should be properly tested, and all tests must pass 19 | * PSR-1: Basic coding standard 20 | * PSR-2: Coding style guide 21 | * PSR-4: Autoloader 22 | * Semantic Versioning 2.0.0 23 | 24 | Thank you for your support! -------------------------------------------------------------------------------- /nimiq-xpub/vendor/stephenhill/base58/license: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Stephen Hill 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /nimiq-xpub/vendor/stephenhill/base58/readme.md: -------------------------------------------------------------------------------- 1 | # Base58 Encoding and Decoding Library for PHP 2 | 3 | [![Build Status](https://travis-ci.org/stephen-hill/base58php.png)](https://travis-ci.org/stephen-hill/base58php) 4 | [![Packagist Release](http://img.shields.io/packagist/v/stephenhill/base58.svg)](https://packagist.org/packages/stephenhill/base58) 5 | [![MIT License](http://img.shields.io/packagist/l/stephenhill/base58.svg)](https://github.com/stephen-hill/base58php/blob/master/license) 6 | [![Flattr this](https://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=stephen-hill&url=https%3A%2F%2Fgithub.com%2Fstephen-hill%2Fbase58php) 7 | 8 | ## Long Term Support 9 | 10 | Each major version of this library will be supported for 5 years after it's initial release. Support will be provided for security and bug fixes. 11 | 12 | Version 1 will therefore be supported until the 11th September 2019. 13 | 14 | ## Background 15 | 16 | I wanted a replacement for Base64 encoded strings and the [Base58 encoding used by Bitcoin](https://en.bitcoin.it/wiki/Base58Check_encoding) looked ideal. I looked around for an existing PHP library which would directly convert a string into Base58 but I couldn't find one, or at least one that worked correctly and was also well tested. 17 | 18 | So I decided to create a library with the following goals: 19 | 20 | - Encode/Decode PHP Strings 21 | - Simple and easy to use 22 | - Fully Tested 23 | - Available via Composer 24 | 25 | ## Requirements 26 | 27 | This library has the following requirements: 28 | 29 | - PHP => 5.3 30 | - BC Math Extension 31 | 32 | ## Installation 33 | 34 | I recommend you install this library via Composer. 35 | 36 | ```json 37 | { 38 | "require": { 39 | "stephenhill/base58": "~1.0" 40 | } 41 | } 42 | ``` 43 | 44 | ## Basic Usage 45 | 46 | ```php 47 | require_once('vendor/autoload.php'); 48 | 49 | $base58 = new StephenHill\Base58(); 50 | 51 | $base58->encode('Hello World'); 52 | $base58->decode('JxF12TrwUP45BMd'); 53 | ``` 54 | 55 | ## Advanced Usage 56 | 57 | By default this library chooses the encoding service provider to use, either GMPService or BCMathService (in that order). 58 | If you want to specify one of the included services or your own, you can inject it into the constructor. 59 | 60 | ```php 61 | require_once('vendor/autoload.php'); 62 | 63 | $gmp = new StephenHill\GMPService(); 64 | $base58 = new StephenHill\Base58(null, $gmp); 65 | 66 | $base58->encode('Hello World'); 67 | $base58->decode('JxF12TrwUP45BMd'); 68 | ``` 69 | 70 | Also by default, this library uses Bitcoin's Base58 alphabet. If you want to use another variant, you can do this in the constructor. 71 | 72 | ```php 73 | require_once('vendor/autoload.php'); 74 | 75 | // Flickr's Base58 Alphabet 76 | $base58 = new StephenHill\Base58('123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ'); 77 | 78 | $base58->encode('Hello World'); 79 | $base58->decode('iXf12sRWto45bmC'); 80 | ``` 81 | 82 | ## Testing 83 | 84 | This library is tested using PHPUnit. 85 | 86 | ```bash 87 | $ bin/phpunit 88 | ``` 89 | 90 | ## Benchmarking 91 | 92 | You can benchmark this library using [Athletic](https://github.com/polyfractal/athletic). 93 | The benchmarking suite also benchmarks PHP's built-in Base64 and Base16 encoding for comparison. 94 | 95 | ```bash 96 | $ bin/athletic -p benchmarks 97 | ``` 98 | 99 | Example output. 100 | 101 | ``` 102 | StephenHill\Benchmarks\Base16Event 103 | Method Name Iterations Average Time Ops/second 104 | ------------ ------------ -------------- ------------- 105 | encodeBase16: [10,000 ] [0.0000010839939] [922,514.40637] 106 | decodeBase16: [10,000 ] [0.0000011516809] [868,296.03561] 107 | 108 | 109 | StephenHill\Benchmarks\Base58BCMathEvent 110 | Method Name Iterations Average Time Ops/second 111 | ------------ ------------ -------------- ------------- 112 | encodeBase58: [10,000 ] [0.0001500048161] [6,666.45263] 113 | decodeBase58: [10,000 ] [0.0001741812706] [5,741.14540] 114 | 115 | 116 | StephenHill\Benchmarks\Base58GMPEvent 117 | Method Name Iterations Average Time Ops/second 118 | ------------ ------------ -------------- ------------- 119 | encodeBase58: [10,000 ] [0.0001168665648] [8,556.76730] 120 | decodeBase58: [10,000 ] [0.0001385705233] [7,216.54199] 121 | 122 | 123 | StephenHill\Benchmarks\Base64Event 124 | Method Name Iterations Average Time Ops/second 125 | ------------ ------------ -------------- ------------- 126 | encodeBase64: [10,000 ] [0.0000009050369] [1,104,927.29189] 127 | decodeBase64: [10,000 ] [0.0000009787321] [1,021,730.04312] 128 | ``` 129 | 130 | ## Contributing 131 | 132 | I welcome everyone to contribute to this library. Please see the Contributing document for details. 133 | 134 | ## License 135 | 136 | This library is license under the MIT License (MIT). Please see License File for more information. 137 | 138 | ## Credits 139 | 140 | This library was forked from [Jeremy Johnstone's](https://github.com/jsjohnst) Base58 methods on Gist https://gist.github.com/jsjohnst/126883. 141 | 142 | Some of the unit tests were based on the following: 143 | 144 | - https://code.google.com/p/bitcoinj/source/browse/core/src/test/java/com/google/bitcoin/core/Base58Test.java 145 | - https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/fixtures/base58.json 146 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/stephenhill/base58/src/BCMathService.php: -------------------------------------------------------------------------------- 1 | alphabet = $alphabet; 45 | $this->base = strlen($alphabet); 46 | } 47 | /** 48 | * Encode a string into base58. 49 | * 50 | * @param string $string The string you wish to encode. 51 | * @since Release v1.1.0 52 | * @return string The Base58 encoded string. 53 | */ 54 | public function encode($string) 55 | { 56 | // Type validation 57 | if (is_string($string) === false) { 58 | throw new InvalidArgumentException('Argument $string must be a string.'); 59 | } 60 | 61 | // If the string is empty, then the encoded string is obviously empty 62 | if (strlen($string) === 0) { 63 | return ''; 64 | } 65 | 66 | // Strings in PHP are essentially 8-bit byte arrays 67 | // so lets convert the string into a PHP array 68 | $bytes = array_values(unpack('C*', $string)); 69 | 70 | // Now we need to convert the byte array into an arbitrary-precision decimal 71 | // We basically do this by performing a base256 to base10 conversion 72 | $decimal = $bytes[0]; 73 | 74 | for ($i = 1, $l = count($bytes); $i < $l; $i++) { 75 | $decimal = bcmul($decimal, 256); 76 | $decimal = bcadd($decimal, $bytes[$i]); 77 | } 78 | 79 | // This loop now performs base 10 to base 58 conversion 80 | // The remainder or modulo on each loop becomes a base 58 character 81 | $output = ''; 82 | while ($decimal >= $this->base) { 83 | $div = bcdiv($decimal, $this->base, 0); 84 | $mod = (int) bcmod($decimal, $this->base); 85 | $output .= $this->alphabet[$mod]; 86 | $decimal = $div; 87 | } 88 | 89 | // If there's still a remainder, append it 90 | if ($decimal > 0) { 91 | $output .= $this->alphabet[$decimal]; 92 | } 93 | 94 | // Now we need to reverse the encoded data 95 | $output = strrev($output); 96 | 97 | // Now we need to add leading zeros 98 | foreach ($bytes as $byte) { 99 | if ($byte === 0) { 100 | $output = $this->alphabet[0] . $output; 101 | continue; 102 | } 103 | break; 104 | } 105 | 106 | return (string) $output; 107 | } 108 | 109 | /** 110 | * Decode base58 into a PHP string. 111 | * 112 | * @param string $base58 The base58 encoded string. 113 | * @since Release v1.1.0 114 | * @return string Returns the decoded string. 115 | */ 116 | public function decode($base58) 117 | { 118 | // Type Validation 119 | if (is_string($base58) === false) { 120 | throw new InvalidArgumentException('Argument $base58 must be a string.'); 121 | } 122 | 123 | // If the string is empty, then the decoded string is obviously empty 124 | if (strlen($base58) === 0) { 125 | return ''; 126 | } 127 | 128 | $indexes = array_flip(str_split($this->alphabet)); 129 | $chars = str_split($base58); 130 | 131 | // Check for invalid characters in the supplied base58 string 132 | foreach ($chars as $char) { 133 | if (isset($indexes[$char]) === false) { 134 | throw new InvalidArgumentException('Argument $base58 contains invalid characters. ($char: "'.$char.'" | $base58: "'.$base58.'") '); 135 | } 136 | } 137 | 138 | // Convert from base58 to base10 139 | $decimal = $indexes[$chars[0]]; 140 | 141 | for ($i = 1, $l = count($chars); $i < $l; $i++) { 142 | $decimal = bcmul($decimal, $this->base); 143 | $decimal = bcadd($decimal, $indexes[$chars[$i]]); 144 | } 145 | 146 | // Convert from base10 to base256 (8-bit byte array) 147 | $output = ''; 148 | while ($decimal > 0) { 149 | $byte = (int) bcmod($decimal, 256); 150 | $output = pack('C', $byte) . $output; 151 | $decimal = bcdiv($decimal, 256, 0); 152 | } 153 | 154 | // Now we need to add leading zeros 155 | foreach ($chars as $char) { 156 | if ($indexes[$char] === 0) { 157 | $output = "\x00" . $output; 158 | continue; 159 | } 160 | break; 161 | } 162 | 163 | return $output; 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/stephenhill/base58/src/Base58.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2014 Stephen Hill 11 | * @license http://www.opensource.org/licenses/MIT The MIT License 12 | * @link https://github.com/stephen-hill/base58php 13 | * @since Release v1.0.0 14 | */ 15 | class Base58 16 | { 17 | /** 18 | * @var StephenHill\ServiceInterface; 19 | * @since v1.1.0 20 | */ 21 | protected $service; 22 | 23 | /** 24 | * Constructor 25 | * 26 | * @param string $alphabet optional 27 | * @param ServiceInterface $service optional 28 | * @since v1.0.0 29 | * @since v1.1.0 Added the optional $service argument. 30 | */ 31 | public function __construct( 32 | $alphabet = null, 33 | ServiceInterface $service = null 34 | ) { 35 | // Handle null alphabet 36 | if (is_null($alphabet) === true) { 37 | $alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; 38 | } 39 | 40 | // Type validation 41 | if (is_string($alphabet) === false) { 42 | throw new InvalidArgumentException('Argument $alphabet must be a string.'); 43 | } 44 | 45 | // The alphabet must contain 58 characters 46 | if (strlen($alphabet) !== 58) { 47 | throw new InvalidArgumentException('Argument $alphabet must contain 58 characters.'); 48 | } 49 | 50 | // Provide a default service if one isn't injected 51 | if ($service === null) { 52 | // Check for GMP support first 53 | if (function_exists('\gmp_init') === true) { 54 | $service = new GMPService($alphabet); 55 | } 56 | else if (function_exists('\bcmul') === true) { 57 | $service = new BCMathService($alphabet); 58 | } 59 | else { 60 | throw new \Exception('Please install the BC Math or GMP extension.'); 61 | } 62 | } 63 | 64 | $this->service = $service; 65 | } 66 | 67 | /** 68 | * Encode a string into base58. 69 | * 70 | * @param string $string The string you wish to encode. 71 | * @since v1.0.0 72 | * @return string The Base58 encoded string. 73 | */ 74 | public function encode($string) 75 | { 76 | return $this->service->encode($string); 77 | } 78 | 79 | /** 80 | * Decode base58 into a PHP string. 81 | * 82 | * @param string $base58 The base58 encoded string. 83 | * @since v1.0.0 84 | * @return string Returns the decoded string. 85 | */ 86 | public function decode($base58) 87 | { 88 | return $this->service->decode($base58); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/stephenhill/base58/src/GMPService.php: -------------------------------------------------------------------------------- 1 | alphabet = $alphabet; 45 | $this->base = strlen($alphabet); 46 | } 47 | /** 48 | * Encode a string into base58. 49 | * 50 | * @param string $string The string you wish to encode. 51 | * @since Release v1.1.0 52 | * @return string The Base58 encoded string. 53 | */ 54 | public function encode($string) 55 | { 56 | // Type validation 57 | if (is_string($string) === false) { 58 | throw new InvalidArgumentException('Argument $string must be a string.'); 59 | } 60 | 61 | // If the string is empty, then the encoded string is obviously empty 62 | if (strlen($string) === 0) { 63 | return ''; 64 | } 65 | 66 | // Now we need to convert the byte array into an arbitrary-precision decimal 67 | // We basically do this by performing a base256 to base10 conversion 68 | $hex = unpack('H*', $string); 69 | $hex = reset($hex); 70 | $decimal = gmp_init($hex, 16); 71 | 72 | // This loop now performs base 10 to base 58 conversion 73 | // The remainder or modulo on each loop becomes a base 58 character 74 | $output = ''; 75 | while (gmp_cmp($decimal, $this->base) >= 0) { 76 | list($decimal, $mod) = gmp_div_qr($decimal, $this->base); 77 | $output .= $this->alphabet[gmp_intval($mod)]; 78 | } 79 | 80 | // If there's still a remainder, append it 81 | if (gmp_cmp($decimal, 0) > 0) { 82 | $output .= $this->alphabet[gmp_intval($decimal)]; 83 | } 84 | 85 | // Now we need to reverse the encoded data 86 | $output = strrev($output); 87 | 88 | // Now we need to add leading zeros 89 | $bytes = str_split($string); 90 | foreach ($bytes as $byte) { 91 | if ($byte === "\x00") { 92 | $output = $this->alphabet[0] . $output; 93 | continue; 94 | } 95 | break; 96 | } 97 | 98 | return (string) $output; 99 | } 100 | 101 | /** 102 | * Decode base58 into a PHP string. 103 | * 104 | * @param string $base58 The base58 encoded string. 105 | * @since Release v1.1.0 106 | * @return string Returns the decoded string. 107 | */ 108 | public function decode($base58) 109 | { 110 | // Type Validation 111 | if (is_string($base58) === false) { 112 | throw new InvalidArgumentException('Argument $base58 must be a string.'); 113 | } 114 | 115 | // If the string is empty, then the decoded string is obviously empty 116 | if (strlen($base58) === 0) { 117 | return ''; 118 | } 119 | 120 | $indexes = array_flip(str_split($this->alphabet)); 121 | $chars = str_split($base58); 122 | 123 | // Check for invalid characters in the supplied base58 string 124 | foreach ($chars as $char) { 125 | if (isset($indexes[$char]) === false) { 126 | throw new InvalidArgumentException('Argument $base58 contains invalid characters.'); 127 | } 128 | } 129 | 130 | // Convert from base58 to base10 131 | $decimal = gmp_init($indexes[$chars[0]], 10); 132 | 133 | for ($i = 1, $l = count($chars); $i < $l; $i++) { 134 | $decimal = gmp_mul($decimal, $this->base); 135 | $decimal = gmp_add($decimal, $indexes[$chars[$i]]); 136 | } 137 | 138 | // Convert from base10 to base256 (8-bit byte array) 139 | $output = ''; 140 | while (gmp_cmp($decimal, 0) > 0) { 141 | list($decimal, $byte) = gmp_div_qr($decimal, 256); 142 | $output = pack('C', gmp_intval($byte)) . $output; 143 | } 144 | 145 | // Now we need to add leading zeros 146 | foreach ($chars as $char) { 147 | if ($indexes[$char] === 0) { 148 | $output = "\x00" . $output; 149 | continue; 150 | } 151 | break; 152 | } 153 | 154 | return $output; 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/stephenhill/base58/src/ServiceInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use Symfony\Polyfill\Mbstring as p; 13 | 14 | if (!function_exists('mb_strlen')) { 15 | define('MB_CASE_UPPER', 0); 16 | define('MB_CASE_LOWER', 1); 17 | define('MB_CASE_TITLE', 2); 18 | 19 | function mb_convert_encoding($s, $to, $from = null) { return p\Mbstring::mb_convert_encoding($s, $to, $from); } 20 | function mb_decode_mimeheader($s) { return p\Mbstring::mb_decode_mimeheader($s); } 21 | function mb_encode_mimeheader($s, $charset = null, $transferEnc = null, $lf = null, $indent = null) { return p\Mbstring::mb_encode_mimeheader($s, $charset, $transferEnc, $lf, $indent); } 22 | function mb_decode_numericentity($s, $convmap, $enc = null) { return p\Mbstring::mb_decode_numericentity($s, $convmap, $enc); } 23 | function mb_encode_numericentity($s, $convmap, $enc = null, $is_hex = false) { return p\Mbstring::mb_encode_numericentity($s, $convmap, $enc, $is_hex); } 24 | function mb_convert_case($s, $mode, $enc = null) { return p\Mbstring::mb_convert_case($s, $mode, $enc); } 25 | function mb_internal_encoding($enc = null) { return p\Mbstring::mb_internal_encoding($enc); } 26 | function mb_language($lang = null) { return p\Mbstring::mb_language($lang); } 27 | function mb_list_encodings() { return p\Mbstring::mb_list_encodings(); } 28 | function mb_encoding_aliases($encoding) { return p\Mbstring::mb_encoding_aliases($encoding); } 29 | function mb_check_encoding($var = null, $encoding = null) { return p\Mbstring::mb_check_encoding($var, $encoding); } 30 | function mb_detect_encoding($str, $encodingList = null, $strict = false) { return p\Mbstring::mb_detect_encoding($str, $encodingList, $strict); } 31 | function mb_detect_order($encodingList = null) { return p\Mbstring::mb_detect_order($encodingList); } 32 | function mb_parse_str($s, &$result = array()) { parse_str($s, $result); } 33 | function mb_strlen($s, $enc = null) { return p\Mbstring::mb_strlen($s, $enc); } 34 | function mb_strpos($s, $needle, $offset = 0, $enc = null) { return p\Mbstring::mb_strpos($s, $needle, $offset, $enc); } 35 | function mb_strtolower($s, $enc = null) { return p\Mbstring::mb_strtolower($s, $enc); } 36 | function mb_strtoupper($s, $enc = null) { return p\Mbstring::mb_strtoupper($s, $enc); } 37 | function mb_substitute_character($char = null) { return p\Mbstring::mb_substitute_character($char); } 38 | function mb_substr($s, $start, $length = 2147483647, $enc = null) { return p\Mbstring::mb_substr($s, $start, $length, $enc); } 39 | function mb_stripos($s, $needle, $offset = 0, $enc = null) { return p\Mbstring::mb_stripos($s, $needle, $offset, $enc); } 40 | function mb_stristr($s, $needle, $part = false, $enc = null) { return p\Mbstring::mb_stristr($s, $needle, $part, $enc); } 41 | function mb_strrchr($s, $needle, $part = false, $enc = null) { return p\Mbstring::mb_strrchr($s, $needle, $part, $enc); } 42 | function mb_strrichr($s, $needle, $part = false, $enc = null) { return p\Mbstring::mb_strrichr($s, $needle, $part, $enc); } 43 | function mb_strripos($s, $needle, $offset = 0, $enc = null) { return p\Mbstring::mb_strripos($s, $needle, $offset, $enc); } 44 | function mb_strrpos($s, $needle, $offset = 0, $enc = null) { return p\Mbstring::mb_strrpos($s, $needle, $offset, $enc); } 45 | function mb_strstr($s, $needle, $part = false, $enc = null) { return p\Mbstring::mb_strstr($s, $needle, $part, $enc); } 46 | function mb_get_info($type = 'all') { return p\Mbstring::mb_get_info($type); } 47 | function mb_http_output($enc = null) { return p\Mbstring::mb_http_output($enc); } 48 | function mb_strwidth($s, $enc = null) { return p\Mbstring::mb_strwidth($s, $enc); } 49 | function mb_substr_count($haystack, $needle, $enc = null) { return p\Mbstring::mb_substr_count($haystack, $needle, $enc); } 50 | function mb_output_handler($contents, $status) { return p\Mbstring::mb_output_handler($contents, $status); } 51 | function mb_http_input($type = '') { return p\Mbstring::mb_http_input($type); } 52 | function mb_convert_variables($toEncoding, $fromEncoding, &$a = null, &$b = null, &$c = null, &$d = null, &$e = null, &$f = null) { return p\Mbstring::mb_convert_variables($toEncoding, $fromEncoding, $a, $b, $c, $d, $e, $f); } 53 | } 54 | if (!function_exists('mb_chr')) { 55 | function mb_ord($s, $enc = null) { return p\Mbstring::mb_ord($s, $enc); } 56 | function mb_chr($code, $enc = null) { return p\Mbstring::mb_chr($code, $enc); } 57 | function mb_scrub($s, $enc = null) { $enc = null === $enc ? mb_internal_encoding() : $enc; return mb_convert_encoding($s, $enc, $enc); } 58 | } 59 | 60 | if (!function_exists('mb_str_split')) { 61 | function mb_str_split($string, $split_length = 1, $encoding = null) { return p\Mbstring::mb_str_split($string, $split_length, $encoding); } 62 | } 63 | -------------------------------------------------------------------------------- /nimiq-xpub/vendor/symfony/polyfill-mbstring/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "symfony/polyfill-mbstring", 3 | "type": "library", 4 | "description": "Symfony polyfill for the Mbstring extension", 5 | "keywords": ["polyfill", "shim", "compatibility", "portable", "mbstring"], 6 | "homepage": "https://symfony.com", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Nicolas Grekas", 11 | "email": "p@tchwork.com" 12 | }, 13 | { 14 | "name": "Symfony Community", 15 | "homepage": "https://symfony.com/contributors" 16 | } 17 | ], 18 | "require": { 19 | "php": ">=5.3.3" 20 | }, 21 | "autoload": { 22 | "psr-4": { "Symfony\\Polyfill\\Mbstring\\": "" }, 23 | "files": [ "bootstrap.php" ] 24 | }, 25 | "suggest": { 26 | "ext-mbstring": "For best performance" 27 | }, 28 | "minimum-stability": "dev", 29 | "extra": { 30 | "branch-alias": { 31 | "dev-master": "1.12-dev" 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /price_services/coingecko.php: -------------------------------------------------------------------------------- 1 | gateway = $gateway; 17 | } 18 | 19 | /** 20 | * @param {string[]} $crypto_currencies 21 | * @param {string} $shop_currency 22 | * @param {number} $order_amount 23 | * @return {[ 24 | * 'prices'? => [[iso: string]: number]], 25 | * 'quotes'? => [[iso: string]: number]], 26 | * 'fees'? => [[iso: string]: number | ['gas_limit' => number, 'gas_price' => number]], 27 | * 'fees_per_byte'? => [[iso: string]: number], 28 | * ]} - Must include either prices or quotes, may include fees 29 | */ 30 | public function get_prices( $crypto_currencies, $shop_currency, $order_amount ) { 31 | $fiat_currency = strtolower( $shop_currency ); 32 | $ids = array_map( function( $currency_iso ) { 33 | return [ 34 | 'nim' => 'nimiq-2', 35 | 'btc' => 'bitcoin', 36 | 'eth' => 'ethereum', 37 | ][ $currency_iso ]; 38 | }, $crypto_currencies ); 39 | $api_response = wp_remote_get( $this->api_endpoint . '/simple/price?ids=' . implode( ',', $ids ) . '&vs_currencies=' . $fiat_currency ); 40 | 41 | if ( is_wp_error( $api_response ) ) { 42 | return $api_response; 43 | } 44 | 45 | $result = json_decode( $api_response[ 'body' ], true ); // Return as associative array (instead of object) 46 | 47 | if ( array_key_exists( 'error', $result ) ) { 48 | return new WP_Error( 'service', $result[ 'error' ] ); 49 | } 50 | 51 | $prices = []; 52 | foreach ( $result as $id => $price_object ) { 53 | $currency_iso = [ 54 | 'nimiq-2' => 'nim', 55 | 'bitcoin' => 'btc', 56 | 'ethereum' => 'eth', 57 | ][ $id ]; 58 | 59 | $price = $price_object[ $fiat_currency ]; 60 | 61 | if ( empty( $price ) ) { 62 | /* translators: %s: Uppercase three-letter currency code, e.g. PEN, SGD */ 63 | return new WP_Error( 'service', sprintf( __( 'The currency %s is not supported by Coingecko.', 'wc-gateway-nimiq' ), strtoupper( $fiat_currency ) ) ); 64 | }; 65 | 66 | $prices[ $currency_iso ] = $price; 67 | } 68 | 69 | return [ 70 | 'prices' => $prices, 71 | ]; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /price_services/fastspot.php: -------------------------------------------------------------------------------- 1 | gateway = $gateway; 17 | } 18 | 19 | /** 20 | * @param {string[]} $crypto_currencies 21 | * @param {string} $shop_currency 22 | * @param {number} $order_amount 23 | * @return {[ 24 | * 'prices'? => [[iso: string]: number]], 25 | * 'quotes'? => [[iso: string]: number]], 26 | * 'fees'? => [[iso: string]: number | ['gas_limit' => number, 'gas_price' => number]], 27 | * 'fees_per_byte'? => [[iso: string]: number], 28 | * ]} - Must include either prices or quotes, may include fees 29 | */ 30 | public function get_prices( $crypto_currencies, $shop_currency, $order_amount ) { 31 | $fiat_currency = strtoupper( $shop_currency ); 32 | $uppercase_cryptos = array_map( 'strtoupper', $crypto_currencies ); 33 | 34 | $options = [ 35 | 'from' => $uppercase_cryptos, 36 | 'to' => [ 37 | $fiat_currency => $order_amount, 38 | ], 39 | 'includedFees' => 'none', 40 | ]; 41 | 42 | $api_response = wp_remote_post( $this->api_endpoint . '/estimates', [ 43 | 'headers' => [ 44 | 'Accept' => 'application/json', 45 | 'Content-Type' => 'application/json', 46 | ], 47 | 'body' => json_encode( $options ), 48 | ] ); 49 | 50 | if ( is_wp_error( $api_response ) ) { 51 | return $api_response; 52 | } 53 | 54 | $result = json_decode( $api_response[ 'body' ], true ); // Return as associative array (instead of object) 55 | 56 | if ( array_key_exists( 'status', $result ) && $result[ 'status' ] >= 400 ) { 57 | return new WP_Error( 'service', $result[ 'detail' ] ); 58 | } 59 | 60 | $quotes = []; 61 | $fees = []; 62 | $feesPerByte = []; 63 | foreach ( $result as $estimate ) { 64 | $price_object = $estimate[ 'from' ][ 0 ]; 65 | $currency_iso = strtolower( $price_object[ 'symbol' ] ); 66 | 67 | $quotes[ $currency_iso ] = $price_object[ 'amount' ]; 68 | 69 | $fee = Crypto_Manager::coins_to_units( [ 70 | $currency_iso => $price_object[ 'fundingNetworkFee' ][ 'total' ], 71 | ] )[ $currency_iso ]; 72 | $feePerByte = Crypto_Manager::coins_to_units( [ 73 | $currency_iso => $price_object[ 'fundingNetworkFee' ][ 'perUnit' ], 74 | ] )[ $currency_iso ]; 75 | 76 | // Round ETH $feePerByte to its first three significant digits 77 | if ( $currency_iso === 'eth' ) { 78 | $feePerByte = strval( round( $feePerByte, -( strlen( $feePerByte ) - 3 ) ) ); 79 | } 80 | 81 | $fees[ $currency_iso ] = $currency_iso === 'eth' 82 | ? [ 83 | 'gas_limit' => 21000, 84 | 'gas_price' => $feePerByte, 85 | ] : $fee; 86 | $feesPerByte[ $currency_iso ] = $feePerByte; 87 | } 88 | 89 | return [ 90 | 'quotes' => $quotes, 91 | 'fees' => $fees, 92 | 'fees_per_byte' => $feesPerByte, 93 | ]; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /price_services/interface.php: -------------------------------------------------------------------------------- 1 | [[iso: string]: number]], 18 | * 'quotes'? => [[iso: string]: number]], 19 | * 'fees'? => [[iso: string]: number | ['gas_limit' => number, 'gas_price' => number]], 20 | * 'fees_per_byte'? => [[iso: string]: number], 21 | * ]} - Must include either prices or quotes, may include fees 22 | */ 23 | public function get_prices( $crypto_currencies, $shop_currency, $order_amount ); 24 | } 25 | -------------------------------------------------------------------------------- /price_services/nimiqx.php: -------------------------------------------------------------------------------- 1 | gateway = $gateway; 18 | 19 | $this->api_key = $gateway->get_option( 'nimiqx_api_key' ); 20 | if ( empty( $this->api_key ) ) { 21 | throw new Exception( __( 'API key not set.', 'wc-gateway-nimiq') ); 22 | } 23 | if ( !ctype_xdigit( $this->api_key ) ) { 24 | throw new Exception( __( 'Invalid API key.', 'wc-gateway-nimiq') ); 25 | } 26 | } 27 | 28 | /** 29 | * @param {string[]} $crypto_currencies 30 | * @param {string} $shop_currency 31 | * @param {number} $order_amount 32 | * @return {[ 33 | * 'prices'? => [[iso: string]: number]], 34 | * 'quotes'? => [[iso: string]: number]], 35 | * 'fees'? => [[iso: string]: number | ['gas_limit' => number, 'gas_price' => number]], 36 | * 'fees_per_byte'? => [[iso: string]: number], 37 | * ]} - Must include either prices or quotes, may include fees 38 | */ 39 | public function get_prices( $crypto_currencies, $shop_currency, $order_amount ) { 40 | $currency = strtolower( $shop_currency ); 41 | $api_response = wp_remote_get( $this->makeUrl( 'price/' . $currency ) ); 42 | 43 | if ( is_wp_error( $api_response ) ) { 44 | return $api_response; 45 | } 46 | 47 | $result = json_decode( $api_response[ 'body' ], true ); 48 | 49 | if ( $result->error ) { 50 | return new WP_Error( 'service', $result->error ); 51 | } 52 | 53 | $price = $result[ $currency ]; 54 | 55 | if ( empty( $price ) ) { 56 | /* translators: %s: Uppercase three-letter currency code, e.g. PEN, SGD */ 57 | return new WP_Error( 'service', sprintf( __( 'The currency %s is not supported by NimiqX.', 'wc-gateway-nimiq' ), strtoupper( $currency ) ) ); 58 | }; 59 | 60 | return [ 61 | 'prices' => [ 62 | 'nim' => $price, 63 | ], 64 | ]; 65 | } 66 | 67 | private function makeUrl( $path ) { 68 | return 'https://api.nimiqx.com/' . $path . '?api_key=' . $this->api_key; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | === Cryptocurrency Checkout - Accept Bitcoin, Ethereum and Nimiq === 2 | 3 | Contributors: nimiq 4 | Tags: woocommerce, cryptocurrency, crypto, checkout, gateway, nimiq, nim, bitcoin, btc, ethereum, eth 5 | Requires at least: 4.9 6 | Tested up to: 6.1 7 | Requires WooCommerce at least: 3.5 8 | Tested WooCommerce up to: 7.1 9 | Stable tag: 3.4.1 10 | Requires PHP: 7.1.0 11 | License: GPLv3 12 | License URI: https://www.gnu.org/licenses/gpl-3.0.html 13 | 14 | Receive crypto directly from your customers + easy integration + beautiful interface + no middleman + no fees. 15 | 16 | == Description == 17 | 18 | Seamlessly integrate Bitcoin, Ethereum and Nimiq payments into your webshop. Receive the equivalent of your regular price in crypto directly in your wallet. Easy to integrate and free of charge. Beautifully designed and easy to use. Open source and decentralized. 19 | 20 | **Features Include:** 21 | 22 | * Bitcoin, Ethereum and Nimiq support 23 | * Automatic conversion from supported store currencies like USD or EUR to crypto at latest market prices 24 | * Full order status feedback in your WooCommerce panel 25 | * Decentralized and non-proprietary 26 | * Configurable conversion and validation service providers 27 | * Configurable confirmation times with sensible defaults 28 | 29 | _This Plugin is just getting started. Additional features such as instant and decentralized Crypto-to-Euro swaps are being currently developed._ 30 | 31 | = How Does It Work? = 32 | 33 | 1. The customer selects “Cryptocurrency Checkout” and is sent to the Nimiq Checkout page. 34 | 2. Cryptocurrency Checkout by Nimiq offers to take payments in Bitcoin, Ethereum or Nimiq. 35 | 3. The customer selects a cryptocurrency and pays. An order is created in the WooCommerce panel and set to 'on-hold' by the plugin. 36 | 4. As soon as the transaction is confirmed on the blockchain, the plugin automatically updates the order status. 37 | 38 | = How To Integrate It? = 39 | 40 | 1. Install and activate the plugin 41 | 2. Find the **Cryptocurrency Checkout by Nimiq** in your list of plugins and click 'Settings' 42 | 3. Enter addresses and public keys of the currencies you want to accept 43 | 4. Tell your customers about your new payment option! 44 | 45 | Check out the documentation, with a more in-depth [tutorial](https://nimiq.github.io/tutorials/wordpress-payment-plugin-installation). 46 | 47 | = Where Does The Crypto Go? = 48 | 49 | You provide your wallet addresses in the WooCommerce admin panel and receive the crypto directly from your customer. 50 | 51 | If you are new to crypto, you can create a Bitcoin and Ethereum wallet with [Jaxx](https://jaxx.io) (a third-party application). For Nimiq, you don’t need to rely on third-parties and can create an address in just seconds and without the need to provide personal data, at [safe.nimiq.com](https://safe.nimiq.com). 52 | 53 | = What Is Nimiq? = 54 | 55 | Nimiq is a blockchain project, NIM is its cryptocurrency, designed for ease-of-use. Sending, receiving and storing NIM is as easy as using Facebook. Creating an account is even easier. 56 | 57 | Give it a try: [nimiq.com](https://nimiq.com) 58 | 59 | = Why Is This Plugin For Free? = 60 | 61 | We believe that cryptocurrencies are the future and will provide a better, more democratic and more open form of money. With this Checkout Plugin, we want to provide a tool for everyone interested in crypto. By providing BTC and ETH payments together with NIM, we wish to support cryptocurrencies in general while illustrating just how much more easy and convenient Nimiq is. 62 | 63 | == Screenshots == 64 | 65 | 1. Easy to set up and maintain 66 | 2. Clean and straight forward payment settings 67 | 3. Seamlessly add cryptocurrency to your payment options 68 | 4. Payment Step 1: Chose your preferred currency 69 | 5. Payment Step 2: Get all relevant info at a glance 70 | 6. Payment Step 3: Pay using an app, QR code or manual inputs 71 | 7. Receive the payments straight to your wallet 72 | 73 | == Changelog == 74 | 75 | = 3.4.1 - 2022.11.23 = 76 | 77 | * Add languages: Filipino, Portuguese, Russian, Ukrainian 78 | 79 | = 3.4.0 - 2022.01.10 = 80 | 81 | * Add support for Hub's acceptance of Nimiq payments from other wallets (for all three monitoring services) 82 | * Auto-complete orders that do not require shipping, after payment was confirmed 83 | 84 | = 3.3.2 - 2021.11.10 = 85 | 86 | * Rename plugin to "Cryptocurrency Checkout by Nimiq" 87 | 88 | = 3.3.1 - 2021.06.11 = 89 | 90 | * Fix bug where fee suggestions were sometimes converted wrongly from coins to units 91 | 92 | = 3.3.0 - 2021.01.25 = 93 | 94 | * Update Fastspot price service to new API 95 | * Add Dutch translations 96 | 97 | = 3.2.2 - 2020.08.11 = 98 | 99 | * Add Spanish translations 100 | 101 | = 3.2.1 - 2020.07.06 = 102 | 103 | * Add Chinese translations 104 | * Update French translations 105 | 106 | = 3.2.0 - 2020.06.22 = 107 | 108 | * Display vendor markup (margin) in Checkout price tooltip for transparency 109 | * Accept one decimal number for the margin setting 110 | * Nimiq Hub compatibility update 111 | 112 | = 3.1.4 - 2020.03.26 = 113 | 114 | * Change to custom CSRF token generation, as WP nonces sometimes have problems validating 115 | * Update HubApi to v1.2.1 116 | * Tested with WooCommerce 4.0 117 | 118 | = 3.1.3 - 2020.02.01 = 119 | 120 | * Improve French translations 121 | 122 | = 3.1.2 - 2020.01.17 = 123 | 124 | * Fix transaction validation not working when no Etherscan API key was set 125 | 126 | = 3.1.1 - 2019.12.16 = 127 | 128 | * Fix popup overlay positioning on scrollable pages 129 | * Fix endless loop for redirect payments from payment page 130 | 131 | = 3.1.0 - 2019.12.07 = 132 | 133 | * Add French translations 134 | * Add overlay to shop page when Nimiq Hub popup is open 135 | 136 | = 3.0.0 - 2019.11.22 = 137 | 138 | * Now accepting Bitcoin, Ethereum and Nimiq payments! 139 | * Huge usability improvements over previous versions. 140 | 141 | == Upgrade Notice == 142 | 143 | = 3.4.0 = 144 | 145 | Enable Hub support for Nimiq payments from other wallets: update to enable your users to pay with any NIM wallet. 146 | 147 | = 3.3.1 = 148 | 149 | Fix bug in calculation of fee suggestions that could sometimes show a too high fee suggestion. 150 | 151 | = 3.3.0 = 152 | 153 | Update Fastspot price service to new API (old API will soon be shut off). Update NOW if you are using Fastspot as your price service! Also added Dutch translations. 154 | 155 | = 3.2.2 = 156 | 157 | Added Spanish translations. 158 | 159 | = 3.2.1 = 160 | 161 | Added Chinese translations, update french. 162 | 163 | = 3.2.0 = 164 | 165 | Display vendor markup (margin) in Checkout price tooltip for transparency. 166 | 167 | = 3.1.4 = 168 | 169 | Fix a problem that sometimes prevented Nimiq Checkout from opening correctly. 170 | 171 | = 3.1.3 = 172 | 173 | Improved French translations. 174 | 175 | = 3.1.2 = 176 | 177 | Fixed transaction validation when no Etherscan API key is set. 178 | 179 | = 3.1.1 = 180 | 181 | Fixed popup overlay positioning and endless redirect payment loop. 182 | 183 | = 3.1.0 = 184 | 185 | Added French translations and an overlay when the Nimiq Hub popup is open. 186 | 187 | = 3.0.0 = 188 | 189 | Cryptocurrency Checkout by Nimiq now also supports accepting payments in Bitcoin and Ethereum! Update your settings to enable the new currencies. 190 | 191 | == Acknowledgement == 192 | 193 | This Nimiq payment gateway is based on skyverge's [WooCommerce Offline Gateway](https://github.com/bekarice/woocommerce-gateway-offline), which in turn forks the WooCommerce core "Cheque" payment gateway. 194 | -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | #nim_pay_button { 2 | margin: 0 auto 32px; 3 | background: #0582CA; 4 | background-image: radial-gradient(ellipse at bottom right, #265DD7, #0582CA); 5 | box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); 6 | color: white; 7 | font-size: 20px; 8 | line-height: 1; 9 | display: flex; 10 | flex-direction: row; 11 | align-items: center; 12 | border-radius: 500px; 13 | padding: 20px 36px; 14 | outline: none; 15 | position: relative; 16 | transition: transform 450ms cubic-bezier(0.25, 0, 0, 1), box-shadow 450ms cubic-bezier(0.25, 0, 0, 1); 17 | } 18 | 19 | #nim_pay_button:not([disabled]):hover, 20 | #nim_pay_button:not([disabled]):focus { 21 | box-shadow: 0 8px 20px rgba(0,0,0,0.2); 22 | transform: translateY(-2px); 23 | } 24 | 25 | #nim_pay_button span { 26 | text-transform: uppercase; 27 | letter-spacing: 0.1em; 28 | flex-shrink: 0; 29 | } 30 | 31 | #nim_pay_button img { 32 | margin-left: 16px; 33 | } 34 | 35 | #nim_pay_button:focus::before { 36 | content: ''; 37 | position: absolute; 38 | left: -5px; 39 | top: -5px; 40 | right: -5px; 41 | bottom: -5px; 42 | border: 2px solid rgba(5, 130, 202, 0.5); /* Based on Nimiq Light Blue */ 43 | border-radius: 500px; 44 | } 45 | 46 | #nim_gateway_info_block.hidden, 47 | #nim_payment_received_block.hidden { 48 | display: none; 49 | } 50 | 51 | #nim_gateway_info_block, 52 | #nim_payment_received_block { 53 | text-align: center; 54 | } 55 | 56 | #nim_payment_received_block .fa-check-circle { 57 | color: seagreen; 58 | font-size: 2em; 59 | margin-bottom: 8px; 60 | display: block; 61 | } 62 | 63 | #nim_payment_received_block small { 64 | display: block; 65 | } 66 | 67 | @media (max-width: 768px) { 68 | #nim_pay_button { 69 | margin: 16px auto 24px; 70 | font-size: 18px; 71 | padding: 18px 32px; 72 | } 73 | 74 | #nim_pay_button img { 75 | margin-left: 14px; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /validation_services/interface.php: -------------------------------------------------------------------------------- 1 |