├── NFTtutorial ├── README.md ├── Token ├── README.md ├── index.html ├── script.js ├── jsbip39.js ├── wordlist_english.js └── sjcl-bip39.js └── Python ├── README.md ├── NFTtutorial ├── README.md ├── manage.py ├── lock.py ├── send.py ├── trust.py └── create.py ├── payment.py ├── keyfunc.py └── AssetCreate.py /NFTtutorial: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pi-network 2 | All Project is made by aszasz1234 3 | -------------------------------------------------------------------------------- /Token/README.md: -------------------------------------------------------------------------------- 1 | # Pi Network Token 2 | 3 | You can see the demo in https://pi-game.app/token/index 4 | -------------------------------------------------------------------------------- /Python/README.md: -------------------------------------------------------------------------------- 1 | # pi-network 2 | Submit payment BY Python 3 | 4 | You should install some library 5 | 6 | ``pip install mnemonic`` 7 | 8 | ``pip install stellar-sdk==4.1.0`` 9 | -------------------------------------------------------------------------------- /Python/NFTtutorial/README.md: -------------------------------------------------------------------------------- 1 | # pi-network 2 | Create NFT BY Python 3 | 4 | You should install some library 5 | keyfunc.py should put in the same folder 6 | 7 | ``pip install mnemonic`` 8 | 9 | ``pip install stellar-sdk==4.1.0`` 10 | 11 | Need to prepare 12 | 13 | two account(issuer and seller) 14 | 15 | the base test pi in issuer >30.0x (that base on how much operation you need) 16 | 17 | # Flow 18 | 19 | create.py --> 20 | 21 | trust.py(change trust) --> 22 | 23 | send.py(payment) --> 24 | 25 | manage.py(data operation) --> 26 | 27 | lock.py(not necessary step, only for stopping issuing) 28 | 29 | # Mention 30 | Server should change to ``https://api.testnet.minepi.com/`` if you don't have a node api service. 31 | 32 | It is possible to bind the operation together by using multiple `.append_operation(operation)` 33 | -------------------------------------------------------------------------------- /Python/NFTtutorial/manage.py: -------------------------------------------------------------------------------- 1 | from stellar_sdk import Server,Keypair,TransactionBuilder, Network ,Asset 2 | import requests 3 | server = Server("http://127.0.0.1:31401/")#https://api.testnet.minepi.com/ 4 | fee = server.fetch_base_fee() 5 | network = "Pi Testnet" 6 | account = server.load_account("GCUQCXPUX5WT3NOA5VJTLM35OCG4KVXCF3K7TYEEX377J2OD6O36OP5C") 7 | secret = Keypair.from_secret("SBZ33W7TBKT3LILEF44JZ6J3PJM5P2N63I423WB72PTF5TALWSYSGXZP") 8 | transaction=( 9 | TransactionBuilder( 10 | source_account = account, 11 | network_passphrase = network, 12 | base_fee = fee 13 | ) 14 | .append_manage_data_op("art","https://imgur.com/a/FwCi3PJ")#key,value ex.("ipfs","ipfs檔案hash") 15 | .build() 16 | ) 17 | transaction.sign(secret) 18 | res = server.submit_transaction(transaction) 19 | 20 | -------------------------------------------------------------------------------- /Python/NFTtutorial/lock.py: -------------------------------------------------------------------------------- 1 | from stellar_sdk import Server,Keypair,TransactionBuilder, Network ,Asset 2 | import requests 3 | server = Server("http://127.0.0.1:31401/")#https://api.testnet.minepi.com/ 4 | fee = server.fetch_base_fee() 5 | network = "Pi Testnet" 6 | account = server.load_account("GCUQCXPUX5WT3NOA5VJTLM35OCG4KVXCF3K7TYEEX377J2OD6O36OP5C") 7 | secret = Keypair.from_secret("SBZ33W7TBKT3LILEF44JZ6J3PJM5P2N63I423WB72PTF5TALWSYSGXZP") 8 | transaction=( 9 | TransactionBuilder( 10 | source_account = account, 11 | network_passphrase = network, 12 | base_fee = fee 13 | ) 14 | .append_set_options_op( 15 | inflation_dest="GCUQCXPUX5WT3NOA5VJTLM35OCG4KVXCF3K7TYEEX377J2OD6O36OP5C", 16 | master_weight = 0 17 | ) 18 | .build() 19 | ) 20 | transaction.sign(secret) 21 | res = server.submit_transaction(transaction) 22 | -------------------------------------------------------------------------------- /Python/NFTtutorial/send.py: -------------------------------------------------------------------------------- 1 | from stellar_sdk import Server, Keypair, TransactionBuilder, Network, ManageSellOffer, Asset 2 | import requests 3 | server = Server("http://127.0.0.1:31401/") 4 | fee = server.fetch_base_fee() 5 | network = "Pi Testnet" 6 | account = server.load_account("GCUQCXPUX5WT3NOA5VJTLM35OCG4KVXCF3K7TYEEX377J2OD6O36OP5C") 7 | secret = Keypair.from_secret("SBZ33W7TBKT3LILEF44JZ6J3PJM5P2N63I423WB72PTF5TALWSYSGXZP") 8 | transaction = ( 9 | TransactionBuilder( 10 | source_account = account, 11 | network_passphrase = network, 12 | base_fee = fee 13 | ) 14 | .append_payment_op("GAT55X4HMQ5W4OXH77P6GAXMJJI5TW3KBZEK45WUDKCB4CYFBJGJBO5H", 15 | "0.0000001", 16 | "TutorialNFT", 17 | "GCUQCXPUX5WT3NOA5VJTLM35OCG4KVXCF3K7TYEEX377J2OD6O36OP5C") 18 | .build() 19 | ) 20 | transaction.sign(secret) 21 | res = server.submit_transaction(transaction) 22 | print(res) 23 | -------------------------------------------------------------------------------- /Python/NFTtutorial/trust.py: -------------------------------------------------------------------------------- 1 | from stellar_sdk import Server,Keypair,TransactionBuilder, Network ,Asset 2 | import requests 3 | server = Server("http://127.0.0.1:31401/")#https://api.testnet.minepi.com/ 4 | fee = server.fetch_base_fee() 5 | network = "Pi Testnet" 6 | user_public_key = "GAT55X4HMQ5W4OXH77P6GAXMJJI5TW3KBZEK45WUDKCB4CYFBJGJBO5H" 7 | user_account = server.load_account(account_id=user_public_key) 8 | user_secret = Keypair.from_secret("SCW66AECE7J7NQI6QLP2R3BBHVT6WJ5DW7JXGFADVHPIBF35OTB32LBO") 9 | asset_coin = Asset("TutorialNFT","GCUQCXPUX5WT3NOA5VJTLM35OCG4KVXCF3K7TYEEX377J2OD6O36OP5C") 10 | transaction=( 11 | TransactionBuilder( 12 | source_account = user_account, 13 | network_passphrase = network, 14 | base_fee = fee 15 | ) 16 | .append_change_trust_op( 17 | asset_code = asset_coin.code, 18 | asset_issuer = asset_coin.issuer, 19 | limit="0.0000001" 20 | ) 21 | .build() 22 | ) 23 | transaction.sign(user_secret) 24 | response = server.submit_transaction(transaction) 25 | -------------------------------------------------------------------------------- /Python/NFTtutorial/create.py: -------------------------------------------------------------------------------- 1 | from stellar_sdk import Server, Keypair, TransactionBuilder, Network, ManageSellOffer, Asset 2 | from mnemonic import Mnemonic 3 | import requests 4 | server = Server("http://127.0.0.1:31401/") 5 | base_fee = server.fetch_base_fee() 6 | passphrase = 'PASSPHRASE from pi wallet' 7 | my_passphrase = '' 8 | my_language = 'english' 9 | mnemo = Mnemonic(my_language) 10 | if mnemo.check(friend): 11 | friend_seed = Mnemonic.to_seed(passphrase, my_passphrase) 12 | from keyfunc import account_keypair 13 | account_number = 0 14 | ff = account_keypair(friend_seed, account_number) 15 | friendt_key = Keypair.from_secret(ff.seed().decode()) 16 | print(ff.seed().decode()) #Original key 17 | issuer_public_key = friendt_key.public_key 18 | destination = Keypair.random() #This will create a keypair not in network 19 | source_account = server.load_account(account_id=friendt_key.public_key) 20 | transaction = ( 21 | TransactionBuilder( 22 | source_account=source_account, 23 | network_passphrase="Pi Testnet", 24 | base_fee=base_fee, 25 | ) 26 | .append_create_account_op( 27 | destination=destination.public_key, 28 | starting_balance="31" #Should more than 20, but if you want to create token it should be more than 30(without fee) 29 | ) 30 | .build() 31 | ) 32 | transaction.sign(friendt_key) 33 | response = server.submit_transaction(transaction) 34 | #Show keypair 35 | print( 36 | f"New Keypair: \n\t public: {destination.public_key}\n\t secret: {destination.secret}" 37 | ) 38 | -------------------------------------------------------------------------------- /Token/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Token 6 | 7 | 8 | 9 |
10 |
11 | Make TrustLine 12 |
13 | 輸入私鑰:
14 |
15 | 尚未解鎖
16 |
17 | 建立信任線 : 尚未執行

18 | 購買PAPC代幣(1 test-pi) : 尚未執行

19 | 查看自己的帳戶 :
20 |
21 | 退回PAPC代幣(不會退test-pi) : 尚未執行

22 | 刪除信任線 : 尚未執行
23 |
24 | 所有操作都是使用者處理,不會有私鑰外流的情形請安心使用 25 | 26 |
27 | 28 |
29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /Python/payment.py: -------------------------------------------------------------------------------- 1 | # pay 10.25 Pi 2 | from stellar_sdk import Server, Keypair, TransactionBuilder, Network 3 | from mnemonic import Mnemonic 4 | from keyfunc import account_keypair 5 | my_seed_phrase = 'passphrase' #you should add your secret key here 6 | my_passphrase = '' 7 | my_language = 'english' # or other language listed in 8 | # https://github.com/bitcoin/bips/blob/master/bip-0039/bip-0039-wordlists.md 9 | mnemo = Mnemonic(my_language) 10 | if mnemo.check(my_seed_phrase): 11 | # my_seed_phrase is a valid BIP39 phrase for my_language 12 | binary_seed = Mnemonic.to_seed(my_seed_phrase, my_passphrase) 13 | account_number = 0 # an small unsigned integer (0 for the primary account) 14 | kp = account_keypair(binary_seed, account_number) 15 | source_keypair = Keypair.from_secret(kp.seed().decode()) 16 | print(kp.seed().decode()) #it will show your original stellar key Like SXXX.... 17 | des_address = "GBFA4NMHFUGHUV2QNGKNEFDS5IC64BWU5HDSWTDFI3EWRUPRXRRRFMPY" #destination address 18 | server = Server("https://api.testnet.minepi.com/") 19 | source_account = server.load_account(source_keypair.public_key) 20 | base_fee = server.fetch_base_fee() 21 | transaction = ( 22 | TransactionBuilder( 23 | source_account=source_account, 24 | network_passphrase="Pi Testnet", 25 | base_fee=base_fee, 26 | ) 27 | .add_text_memo("Hello, PiNetwork!") 28 | .append_payment_op(des_address, "10.25", "XLM") # xlm = native base on stellar sdk setting and will be pi in pi blockchain 29 | .build() 30 | ) 31 | transaction.sign(source_keypair) 32 | response = server.submit_transaction(transaction) 33 | -------------------------------------------------------------------------------- /Python/keyfunc.py: -------------------------------------------------------------------------------- 1 | import struct 2 | import hashlib 3 | import hmac 4 | 5 | 6 | # BIP-0044 path format for Stellar keypair derivation, as specified in 7 | # https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0005.md 8 | ACCOUNT_PATH_FORMAT = "m/44'/314159'/0'" 9 | 10 | 11 | # the index of the first hardened key, per BIP-0032 and SLIP-0010 12 | HARDENED = 0x80000000 13 | 14 | # as defined in https://github.com/satoshilabs/slips/blob/master/slip-0010.md 15 | CURVE = b'ed25519 seed' 16 | 17 | 18 | hmac_sha_512 = lambda key, data: hmac.new(key, data, hashlib.sha512).digest() 19 | 20 | 21 | def key(v): 22 | """Return the private key part (the left half) of a 64-byte sequence v.""" 23 | return v[:32] 24 | 25 | 26 | def chain_code(v): 27 | """Return the chain code part (the right half) of a 64-byte sequence v.""" 28 | return v[32:] 29 | 30 | 31 | def ser32(i): 32 | """Serialize a 32-bit unsigned integer i as a 4-byte sequence. 33 | The most significant byte of i appears first in the serialization. 34 | """ 35 | return struct.pack('>L', i) 36 | 37 | 38 | def new_master_key(seed): 39 | """Return the extended master key derived from a 64-byte binary seed. 40 | 41 | BIP-0032 defines an extended key as a pair (private_key, chain_code). 42 | The extended master key is the pair (master_private_key, master_chain_code) 43 | specified by SLIP-0010. 44 | """ 45 | h = hmac_sha_512(CURVE, seed); 46 | return (key(h), chain_code(h)) 47 | 48 | 49 | def derive(parent_key, parent_chain_code, i): 50 | """Return the i-th extended child key from an extended parent key.""" 51 | assert len(parent_key) == 32 52 | assert len(parent_chain_code) == 32 53 | assert i >= HARDENED, 'no public derivation for ed25519' 54 | data = b'\x00' + parent_key + ser32(i) 55 | h = hmac_sha_512(parent_chain_code, data) 56 | return (key(h), chain_code(h)) 57 | 58 | 59 | def derive_along_path(path, seed): 60 | """Derive an extended key from a 64-byte binary seed and a BIP-0044 path. 61 | Returns the extended key obtained by following the given derivation path, 62 | starting at the extended master key derived from the given binary seed. 63 | """ 64 | elements = list(element.rstrip("'") for element in path.split('/'))[1:] 65 | (key, chain_code) = new_master_key(seed) 66 | for e in elements: 67 | (key, chain_code) = derive(key, chain_code, int(e) | HARDENED) 68 | return key 69 | 70 | 71 | def account_keypair(seed, account_number): 72 | """Return the account keypair for a 64-byte binary seed and account_number.""" 73 | from stellar_base.keypair import Keypair 74 | acc_seed = derive_along_path(ACCOUNT_PATH_FORMAT, seed); 75 | return Keypair.from_raw_seed(acc_seed) 76 | -------------------------------------------------------------------------------- /Python/AssetCreate.py: -------------------------------------------------------------------------------- 1 | from stellar_sdk import Server, Keypair, TransactionBuilder, Network, ManageSellOffer, Asset 2 | from mnemonic import Mnemonic 3 | import requests 4 | server = Server("https://api.testnet.minepi.com/") 5 | base_fee = server.fetch_base_fee() 6 | issuer_phrase = 'issuer passphrase' #need to change 7 | seller_phrase = 'seller passphrase' #need to change 8 | my_passphrase = '' 9 | my_language = 'english' 10 | mnemo = Mnemonic(my_language) 11 | if mnemo.check(issuer_phrase): 12 | issuer_seed = Mnemonic.to_seed(issuer_phrase, my_passphrase) 13 | if mnemo.check(seller_phrase): 14 | seller_seed = Mnemonic.to_seed(seller_phrase,my_passphrase) 15 | from keyfunc import account_keypair 16 | account_number = 0 # an small unsigned integer (0 for the primary account) 17 | issuer = account_keypair(issuer_seed, account_number) 18 | seller = account_keypair(seller_seed, account_number) 19 | seller_secret_key = Keypair.from_secret(seller.seed().decode()) 20 | issuer_secret_key = Keypair.from_secret(issuer.seed().decode()) 21 | issuer_public_key = issuer_secret_key.public_key 22 | seller_public_key = seller_secret_key.public_key 23 | issuer_account = server.load_account(account_id=issuer_public_key) 24 | seller_account = server.load_account(account_id=seller_public_key) 25 | #manage offer 26 | network_passphrase = "Pi Testnet" 27 | ## get fee from Pi Testnet 28 | fee = base_fee 29 | print("\nCreate new Asset\n") 30 | # create asset 31 | 32 | ## Create an object to represent the new asset 33 | asset_coin = Asset("PAPC", issuer_public_key) #You can change PAPC to what you want. Mention that the letters must<=12 34 | 35 | ## The Seller Account (the account that the custom asset receivs) must trust the asset. 36 | print( 37 | "The Seller Account must trust the new asset. \ 38 | \nCreate Trust." 39 | ) 40 | trust_transaction = ( 41 | TransactionBuilder( 42 | source_account=seller_account, 43 | network_passphrase=network_passphrase, 44 | base_fee=fee, 45 | ) 46 | # The `changeTrust` operation creates (or alters) a trustline 47 | # The `limit` parameter below is optional 48 | .append_change_trust_op( 49 | asset_code=asset_coin.code, 50 | asset_issuer=asset_coin.issuer, 51 | limit="5000", #this is the limit for your token, you can create more in future if your issuer account is not in lock status 52 | ) 53 | .set_timeout(100) 54 | .build() 55 | ) 56 | 57 | trust_transaction.sign(seller_secret_key) 58 | trust_transaction_resp = server.submit_transaction(trust_transaction) 59 | print("Trust created\n") 60 | ## Send 5000 PAPC asset to the seller account. 61 | print("Send PAPC to seller account") 62 | aac_payment_transaction = ( 63 | TransactionBuilder( 64 | source_account=issuer_account, 65 | network_passphrase=network_passphrase, 66 | base_fee=fee, 67 | ) 68 | .append_payment_op( 69 | destination=seller_public_key, 70 | amount="5000", 71 | asset_code=asset_coin.code, 72 | asset_issuer=asset_coin.issuer, 73 | ) 74 | .build() 75 | ) 76 | aac_payment_transaction.sign(issuer_secret_key) 77 | aac_payment_transaction_resp = server.submit_transaction(aac_payment_transaction) 78 | print(f"Sended 5000 PAPC to {seller_public_key}") 79 | print("#" * 30) 80 | -------------------------------------------------------------------------------- /Token/script.js: -------------------------------------------------------------------------------- 1 | var pubkey 2 | var privkey 3 | async function key(){ 4 | var mnemonics = { "english": new Mnemonic("english") }; 5 | var mnemonic = mnemonics["english"]; 6 | var phrase = document.getElementById('key').value; 7 | seed = mnemonic.toSeed(phrase, ""); 8 | var path = "m/44'/314159'/0'"; 9 | var keypair = libs.stellarUtil.getKeypair(path, seed); 10 | indexText = path; 11 | privkey = StellarSdk.Keypair.fromSecret(keypair.secret()); 12 | pubkey = keypair.publicKey(); 13 | document.getElementById("s0").innerHTML='解鎖'; 14 | }; 15 | async function trust() { 16 | const server = new StellarSdk.Server('https://api.testnet.minepi.com/'); 17 | const fee = 100000; 18 | const account = await server.loadAccount(pubkey); 19 | console.log(fee); 20 | const trustchange = new StellarSdk.TransactionBuilder(account, { 21 | fee, 22 | networkPassphrase: 'Pi Testnet' 23 | }) 24 | .addOperation(StellarSdk.Operation.changeTrust({ 25 | asset: new StellarSdk.Asset('PAPC','GBFA4NMHFUGHUV2QNGKNEFDS5IC64BWU5HDSWTDFI3EWRUPRXRRRFMPY'), 26 | limit: '1', 27 | })) 28 | .setTimeout(100) 29 | .build(); 30 | trustchange.sign(privkey); 31 | server.submitTransaction(trustchange); 32 | cooldown(); 33 | document.getElementById("s1").innerHTML='已執行'; 34 | } 35 | async function buy(){ 36 | const server = new StellarSdk.Server('https://api.testnet.minepi.com/'); 37 | const fee = 100000; 38 | account = await server.loadAccount(pubkey); 39 | const buyoffer = new StellarSdk.TransactionBuilder(account, { 40 | fee, 41 | // Uncomment the following line to build transactions for the live network. Be 42 | // sure to also change the horizon hostname. 43 | // networkPassphrase: StellarSdk.Networks.PUBLIC, 44 | networkPassphrase: 'Pi Testnet' 45 | }) 46 | // Add a payment operation to the transaction 47 | .addOperation(StellarSdk.Operation.manageBuyOffer({ 48 | selling:StellarSdk.Asset.native(), 49 | buying:new StellarSdk.Asset('PAPC','GBFA4NMHFUGHUV2QNGKNEFDS5IC64BWU5HDSWTDFI3EWRUPRXRRRFMPY'), 50 | buyAmount:'1', 51 | price:'1', 52 | })) 53 | // Make this transaction valid for the next 30 seconds only 54 | .setTimeout(100) 55 | // Uncomment to add a memo (https://www.stellar.org/developers/guides/concepts/transactions.html) 56 | // .addMemo(StellarSdk.Memo.text('Hello world!')) 57 | .build(); 58 | buyoffer.sign(privkey); 59 | server.submitTransaction(buyoffer); 60 | cooldown(); 61 | document.getElementById("s2").innerHTML='已執行'; 62 | }; 63 | async function sell(){ 64 | const server = new StellarSdk.Server('https://api.testnet.minepi.com/'); 65 | const fee = 100000; 66 | account = await server.loadAccount(pubkey); 67 | const buyoffer = new StellarSdk.TransactionBuilder(account, { 68 | fee, 69 | networkPassphrase: 'Pi Testnet' 70 | }) 71 | .addOperation(StellarSdk.Operation.payment({ 72 | destination:'GAHVUXJEP2BENC5AFGJI4XKTLPYO3TICGODOF5KTQV5BHWS3BBDLCC6O', 73 | asset: new StellarSdk.Asset('PAPC','GBFA4NMHFUGHUV2QNGKNEFDS5IC64BWU5HDSWTDFI3EWRUPRXRRRFMPY'), 74 | amount:'1', 75 | })) 76 | .setTimeout(100) 77 | .build(); 78 | buyoffer.sign(privkey); 79 | server.submitTransaction(buyoffer); 80 | cooldown(); 81 | document.getElementById("s3").innerHTML='已執行'; 82 | }; 83 | async function del_trust(){ 84 | const server = new StellarSdk.Server('https://api.testnet.minepi.com/'); 85 | const fee = 100000; 86 | account = await server.loadAccount(pubkey); 87 | const del_trust = new StellarSdk.TransactionBuilder(account, { 88 | fee, 89 | networkPassphrase: 'Pi Testnet' 90 | }) 91 | .addOperation(StellarSdk.Operation.changeTrust({ 92 | asset: new StellarSdk.Asset('PAPC','GBFA4NMHFUGHUV2QNGKNEFDS5IC64BWU5HDSWTDFI3EWRUPRXRRRFMPY'), 93 | limit: '0', 94 | })) 95 | .setTimeout(100) 96 | .build(); 97 | del_trust.sign(privkey); 98 | server.submitTransaction(del_trust); 99 | cooldown(); 100 | document.getElementById("s4").innerHTML='已執行'; 101 | }; 102 | function browse(){ 103 | var link = 'https://pi-blockchain.net/account/'+pubkey; 104 | window.location.href=link; 105 | } 106 | function cooldown(){ 107 | const b1 = document.getElementById('b1'); 108 | const b2 = document.getElementById('b2'); 109 | const b3 = document.getElementById('b3'); 110 | const b4 = document.getElementById('b4'); 111 | b1.disabled = true; 112 | b2.disabled = true; 113 | b3.disabled = true; 114 | b4.disabled = true; 115 | setTimeout(function(){ 116 | b1.disabled = false; 117 | b2.disabled = false; 118 | b3.disabled = false; 119 | b4.disabled = false; 120 | },5000); 121 | } 122 | -------------------------------------------------------------------------------- /Token/jsbip39.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Pavol Rusnak 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | * this software and associated documentation files (the "Software"), to deal in 6 | * the Software without restriction, including without limitation the rights to 7 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 | * of the Software, and to permit persons to whom the Software is furnished to do 9 | * so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | /* 23 | * Javascript port from python by Ian Coleman 24 | * 25 | * Requires code from sjcl 26 | * https://github.com/bitwiseshiftleft/sjcl 27 | */ 28 | 29 | var Mnemonic = function(language) { 30 | 31 | var PBKDF2_ROUNDS = 2048; 32 | var RADIX = 2048; 33 | 34 | var self = this; 35 | var wordlist = []; 36 | 37 | var hmacSHA512 = function(key) { 38 | var hasher = new sjcl.misc.hmac(key, sjcl.hash.sha512); 39 | this.encrypt = function() { 40 | return hasher.encrypt.apply(hasher, arguments); 41 | }; 42 | }; 43 | 44 | function init() { 45 | wordlist = WORDLISTS[language]; 46 | if (wordlist.length != RADIX) { 47 | err = 'Wordlist should contain ' + RADIX + ' words, but it contains ' + wordlist.length + ' words.'; 48 | throw err; 49 | } 50 | } 51 | 52 | self.generate = function(strength) { 53 | strength = strength || 128; 54 | var r = strength % 32; 55 | if (r > 0) { 56 | throw 'Strength should be divisible by 32, but it is not (' + r + ').'; 57 | } 58 | var hasStrongCrypto = 'crypto' in window && window['crypto'] !== null; 59 | if (!hasStrongCrypto) { 60 | throw 'Mnemonic should be generated with strong randomness, but crypto.getRandomValues is unavailable'; 61 | } 62 | var buffer = new Uint8Array(strength / 8); 63 | var data = crypto.getRandomValues(buffer); 64 | return self.toMnemonic(data); 65 | } 66 | 67 | self.toMnemonic = function(byteArray) { 68 | if (byteArray.length % 4 > 0) { 69 | throw 'Data length in bits should be divisible by 32, but it is not (' + byteArray.length + ' bytes = ' + byteArray.length*8 + ' bits).' 70 | } 71 | 72 | //h = hashlib.sha256(data).hexdigest() 73 | var data = byteArrayToWordArray(byteArray); 74 | var hash = sjcl.hash.sha256.hash(data); 75 | var h = sjcl.codec.hex.fromBits(hash); 76 | 77 | // b is a binary string, eg '00111010101100...' 78 | //b = bin(int(binascii.hexlify(data), 16))[2:].zfill(len(data) * 8) + \ 79 | // bin(int(h, 16))[2:].zfill(256)[:len(data) * 8 / 32] 80 | // 81 | // a = bin(int(binascii.hexlify(data), 16))[2:].zfill(len(data) * 8) 82 | // c = bin(int(h, 16))[2:].zfill(256) 83 | // d = c[:len(data) * 8 / 32] 84 | var a = byteArrayToBinaryString(byteArray); 85 | var c = zfill(hexStringToBinaryString(h), 256); 86 | var d = c.substring(0, byteArray.length * 8 / 32); 87 | // b = line1 + line2 88 | var b = a + d; 89 | 90 | var result = []; 91 | var blen = b.length / 11; 92 | for (var i=0; i 0) { 214 | return null; 215 | } 216 | // idx = map(lambda x: bin(self.wordlist.index(x))[2:].zfill(11), mnemonic) 217 | var idx = []; 218 | for (var i=0; i 98 | * These objects are the currency accepted by SJCL's crypto functions. 99 | *

100 | * 101 | *

102 | * Most of our crypto primitives operate on arrays of 4-byte words internally, 103 | * but many of them can take arguments that are not a multiple of 4 bytes. 104 | * This library encodes arrays of bits (whose size need not be a multiple of 8 105 | * bits) as arrays of 32-bit words. The bits are packed, big-endian, into an 106 | * array of words, 32 bits at a time. Since the words are double-precision 107 | * floating point numbers, they fit some extra data. We use this (in a private, 108 | * possibly-changing manner) to encode the number of bits actually present 109 | * in the last word of the array. 110 | *

111 | * 112 | *

113 | * Because bitwise ops clear this out-of-band data, these arrays can be passed 114 | * to ciphers like AES which want arrays of words. 115 | *

116 | */ 117 | sjcl.bitArray = { 118 | /** 119 | * Array slices in units of bits. 120 | * @param {bitArray} a The array to slice. 121 | * @param {Number} bstart The offset to the start of the slice, in bits. 122 | * @param {Number} bend The offset to the end of the slice, in bits. If this is undefined, 123 | * slice until the end of the array. 124 | * @return {bitArray} The requested slice. 125 | */ 126 | bitSlice: function (a, bstart, bend) { 127 | a = sjcl.bitArray._shiftRight(a.slice(bstart/32), 32 - (bstart & 31)).slice(1); 128 | return (bend === undefined) ? a : sjcl.bitArray.clamp(a, bend-bstart); 129 | }, 130 | 131 | /** 132 | * Extract a number packed into a bit array. 133 | * @param {bitArray} a The array to slice. 134 | * @param {Number} bstart The offset to the start of the slice, in bits. 135 | * @param {Number} length The length of the number to extract. 136 | * @return {Number} The requested slice. 137 | */ 138 | extract: function(a, bstart, blength) { 139 | // FIXME: this Math.floor is not necessary at all, but for some reason 140 | // seems to suppress a bug in the Chromium JIT. 141 | var x, sh = Math.floor((-bstart-blength) & 31); 142 | if ((bstart + blength - 1 ^ bstart) & -32) { 143 | // it crosses a boundary 144 | x = (a[bstart/32|0] << (32 - sh)) ^ (a[bstart/32+1|0] >>> sh); 145 | } else { 146 | // within a single word 147 | x = a[bstart/32|0] >>> sh; 148 | } 149 | return x & ((1< 0 && len) { 195 | a[l-1] = sjcl.bitArray.partial(len, a[l-1] & 0x80000000 >> (len-1), 1); 196 | } 197 | return a; 198 | }, 199 | 200 | /** 201 | * Make a partial word for a bit array. 202 | * @param {Number} len The number of bits in the word. 203 | * @param {Number} x The bits. 204 | * @param {Number} [0] _end Pass 1 if x has already been shifted to the high side. 205 | * @return {Number} The partial word. 206 | */ 207 | partial: function (len, x, _end) { 208 | if (len === 32) { return x; } 209 | return (_end ? x|0 : x << (32-len)) + len * 0x10000000000; 210 | }, 211 | 212 | /** 213 | * Get the number of bits used by a partial word. 214 | * @param {Number} x The partial word. 215 | * @return {Number} The number of bits used by the partial word. 216 | */ 217 | getPartial: function (x) { 218 | return Math.round(x/0x10000000000) || 32; 219 | }, 220 | 221 | /** 222 | * Compare two arrays for equality in a predictable amount of time. 223 | * @param {bitArray} a The first array. 224 | * @param {bitArray} b The second array. 225 | * @return {boolean} true if a == b; false otherwise. 226 | */ 227 | equal: function (a, b) { 228 | if (sjcl.bitArray.bitLength(a) !== sjcl.bitArray.bitLength(b)) { 229 | return false; 230 | } 231 | var x = 0, i; 232 | for (i=0; i= 32; shift -= 32) { 250 | out.push(carry); 251 | carry = 0; 252 | } 253 | if (shift === 0) { 254 | return out.concat(a); 255 | } 256 | 257 | for (i=0; i>>shift); 259 | carry = a[i] << (32-shift); 260 | } 261 | last2 = a.length ? a[a.length-1] : 0; 262 | shift2 = sjcl.bitArray.getPartial(last2); 263 | out.push(sjcl.bitArray.partial(shift+shift2 & 31, (shift + shift2 > 32) ? carry : out.pop(),1)); 264 | return out; 265 | }, 266 | 267 | /** xor a block of 4 words together. 268 | * @private 269 | */ 270 | _xor4: function(x,y) { 271 | return [x[0]^y[0],x[1]^y[1],x[2]^y[2],x[3]^y[3]]; 272 | }, 273 | 274 | /** byteswap a word array inplace. 275 | * (does not handle partial words) 276 | * @param {sjcl.bitArray} a word array 277 | * @return {sjcl.bitArray} byteswapped array 278 | */ 279 | byteswapM: function(a) { 280 | var i, v, m = 0xff00; 281 | for (i = 0; i < a.length; ++i) { 282 | v = a[i]; 283 | a[i] = (v >>> 24) | ((v >>> 8) & m) | ((v & m) << 8) | (v << 24); 284 | } 285 | return a; 286 | } 287 | }; 288 | 289 | 290 | //// codecString.js 291 | 292 | /** @fileOverview Bit array codec implementations. 293 | * 294 | * @author Emily Stark 295 | * @author Mike Hamburg 296 | * @author Dan Boneh 297 | */ 298 | 299 | /** @namespace UTF-8 strings */ 300 | sjcl.codec.utf8String = { 301 | /** Convert from a bitArray to a UTF-8 string. */ 302 | fromBits: function (arr) { 303 | var out = "", bl = sjcl.bitArray.bitLength(arr), i, tmp; 304 | for (i=0; i>> 24); 309 | tmp <<= 8; 310 | } 311 | return decodeURIComponent(escape(out)); 312 | }, 313 | 314 | /** Convert from a UTF-8 string to a bitArray. */ 315 | toBits: function (str) { 316 | str = unescape(encodeURIComponent(str)); 317 | var out = [], i, tmp=0; 318 | for (i=0; i>> 1)) ^ 604 | ((gamma0xl << 24) | (gamma0xh >>> 8)) ^ 605 | (gamma0xh >>> 7); 606 | var gamma0l = 607 | ((gamma0xh << 31) | (gamma0xl >>> 1)) ^ 608 | ((gamma0xh << 24) | (gamma0xl >>> 8)) ^ 609 | ((gamma0xh << 25) | (gamma0xl >>> 7)); 610 | 611 | // Gamma1 612 | var gamma1xh = w[(i-2) * 2]; 613 | var gamma1xl = w[(i-2) * 2 + 1]; 614 | var gamma1h = 615 | ((gamma1xl << 13) | (gamma1xh >>> 19)) ^ 616 | ((gamma1xh << 3) | (gamma1xl >>> 29)) ^ 617 | (gamma1xh >>> 6); 618 | var gamma1l = 619 | ((gamma1xh << 13) | (gamma1xl >>> 19)) ^ 620 | ((gamma1xl << 3) | (gamma1xh >>> 29)) ^ 621 | ((gamma1xh << 26) | (gamma1xl >>> 6)); 622 | 623 | // Shortcuts 624 | var wr7h = w[(i-7) * 2]; 625 | var wr7l = w[(i-7) * 2 + 1]; 626 | 627 | var wr16h = w[(i-16) * 2]; 628 | var wr16l = w[(i-16) * 2 + 1]; 629 | 630 | // W(round) = gamma0 + W(round - 7) + gamma1 + W(round - 16) 631 | wrl = gamma0l + wr7l; 632 | wrh = gamma0h + wr7h + ((wrl >>> 0) < (gamma0l >>> 0) ? 1 : 0); 633 | wrl += gamma1l; 634 | wrh += gamma1h + ((wrl >>> 0) < (gamma1l >>> 0) ? 1 : 0); 635 | wrl += wr16l; 636 | wrh += wr16h + ((wrl >>> 0) < (wr16l >>> 0) ? 1 : 0); 637 | } 638 | 639 | w[i*2] = wrh |= 0; 640 | w[i*2 + 1] = wrl |= 0; 641 | 642 | // Ch 643 | var chh = (eh & fh) ^ (~eh & gh); 644 | var chl = (el & fl) ^ (~el & gl); 645 | 646 | // Maj 647 | var majh = (ah & bh) ^ (ah & ch) ^ (bh & ch); 648 | var majl = (al & bl) ^ (al & cl) ^ (bl & cl); 649 | 650 | // Sigma0 651 | var sigma0h = ((al << 4) | (ah >>> 28)) ^ ((ah << 30) | (al >>> 2)) ^ ((ah << 25) | (al >>> 7)); 652 | var sigma0l = ((ah << 4) | (al >>> 28)) ^ ((al << 30) | (ah >>> 2)) ^ ((al << 25) | (ah >>> 7)); 653 | 654 | // Sigma1 655 | var sigma1h = ((el << 18) | (eh >>> 14)) ^ ((el << 14) | (eh >>> 18)) ^ ((eh << 23) | (el >>> 9)); 656 | var sigma1l = ((eh << 18) | (el >>> 14)) ^ ((eh << 14) | (el >>> 18)) ^ ((el << 23) | (eh >>> 9)); 657 | 658 | // K(round) 659 | var krh = k[i*2]; 660 | var krl = k[i*2+1]; 661 | 662 | // t1 = h + sigma1 + ch + K(round) + W(round) 663 | var t1l = hl + sigma1l; 664 | var t1h = hh + sigma1h + ((t1l >>> 0) < (hl >>> 0) ? 1 : 0); 665 | t1l += chl; 666 | t1h += chh + ((t1l >>> 0) < (chl >>> 0) ? 1 : 0); 667 | t1l += krl; 668 | t1h += krh + ((t1l >>> 0) < (krl >>> 0) ? 1 : 0); 669 | t1l = t1l + wrl|0; // FF32..FF34 perf issue https://bugzilla.mozilla.org/show_bug.cgi?id=1054972 670 | t1h += wrh + ((t1l >>> 0) < (wrl >>> 0) ? 1 : 0); 671 | 672 | // t2 = sigma0 + maj 673 | var t2l = sigma0l + majl; 674 | var t2h = sigma0h + majh + ((t2l >>> 0) < (sigma0l >>> 0) ? 1 : 0); 675 | 676 | // Update working variables 677 | hh = gh; 678 | hl = gl; 679 | gh = fh; 680 | gl = fl; 681 | fh = eh; 682 | fl = el; 683 | el = (dl + t1l) | 0; 684 | eh = (dh + t1h + ((el >>> 0) < (dl >>> 0) ? 1 : 0)) | 0; 685 | dh = ch; 686 | dl = cl; 687 | ch = bh; 688 | cl = bl; 689 | bh = ah; 690 | bl = al; 691 | al = (t1l + t2l) | 0; 692 | ah = (t1h + t2h + ((al >>> 0) < (t1l >>> 0) ? 1 : 0)) | 0; 693 | } 694 | 695 | // Intermediate hash 696 | h0l = h[1] = (h0l + al) | 0; 697 | h[0] = (h0h + ah + ((h0l >>> 0) < (al >>> 0) ? 1 : 0)) | 0; 698 | h1l = h[3] = (h1l + bl) | 0; 699 | h[2] = (h1h + bh + ((h1l >>> 0) < (bl >>> 0) ? 1 : 0)) | 0; 700 | h2l = h[5] = (h2l + cl) | 0; 701 | h[4] = (h2h + ch + ((h2l >>> 0) < (cl >>> 0) ? 1 : 0)) | 0; 702 | h3l = h[7] = (h3l + dl) | 0; 703 | h[6] = (h3h + dh + ((h3l >>> 0) < (dl >>> 0) ? 1 : 0)) | 0; 704 | h4l = h[9] = (h4l + el) | 0; 705 | h[8] = (h4h + eh + ((h4l >>> 0) < (el >>> 0) ? 1 : 0)) | 0; 706 | h5l = h[11] = (h5l + fl) | 0; 707 | h[10] = (h5h + fh + ((h5l >>> 0) < (fl >>> 0) ? 1 : 0)) | 0; 708 | h6l = h[13] = (h6l + gl) | 0; 709 | h[12] = (h6h + gh + ((h6l >>> 0) < (gl >>> 0) ? 1 : 0)) | 0; 710 | h7l = h[15] = (h7l + hl) | 0; 711 | h[14] = (h7h + hh + ((h7l >>> 0) < (hl >>> 0) ? 1 : 0)) | 0; 712 | } 713 | }; 714 | 715 | 716 | //// hmac.js 717 | 718 | /** @fileOverview HMAC implementation. 719 | * 720 | * @author Emily Stark 721 | * @author Mike Hamburg 722 | * @author Dan Boneh 723 | */ 724 | 725 | /** HMAC with the specified hash function. 726 | * @constructor 727 | * @param {bitArray} key the key for HMAC. 728 | * @param {Object} [hash=sjcl.hash.sha256] The hash function to use. 729 | */ 730 | sjcl.misc.hmac = function (key, Hash) { 731 | this._hash = Hash = Hash || sjcl.hash.sha256; 732 | var exKey = [[],[]], i, 733 | bs = Hash.prototype.blockSize / 32; 734 | this._baseHash = [new Hash(), new Hash()]; 735 | 736 | if (key.length > bs) { 737 | key = Hash.hash(key); 738 | } 739 | 740 | for (i=0; i>>7 ^ a>>>18 ^ a>>>3 ^ a<<25 ^ a<<14) + 1036 | (b>>>17 ^ b>>>19 ^ b>>>10 ^ b<<15 ^ b<<13) + 1037 | w[i&15] + w[(i+9) & 15]) | 0; 1038 | } 1039 | 1040 | tmp = (tmp + h7 + (h4>>>6 ^ h4>>>11 ^ h4>>>25 ^ h4<<26 ^ h4<<21 ^ h4<<7) + (h6 ^ h4&(h5^h6)) + k[i]); // | 0; 1041 | 1042 | // shift register 1043 | h7 = h6; h6 = h5; h5 = h4; 1044 | h4 = h3 + tmp | 0; 1045 | h3 = h2; h2 = h1; h1 = h0; 1046 | 1047 | h0 = (tmp + ((h1&h2) ^ (h3&(h1^h2))) + (h1>>>2 ^ h1>>>13 ^ h1>>>22 ^ h1<<30 ^ h1<<19 ^ h1<<10)) | 0; 1048 | } 1049 | 1050 | h[0] = h[0]+h0 | 0; 1051 | h[1] = h[1]+h1 | 0; 1052 | h[2] = h[2]+h2 | 0; 1053 | h[3] = h[3]+h3 | 0; 1054 | h[4] = h[4]+h4 | 0; 1055 | h[5] = h[5]+h5 | 0; 1056 | h[6] = h[6]+h6 | 0; 1057 | h[7] = h[7]+h7 | 0; 1058 | } 1059 | }; 1060 | --------------------------------------------------------------------------------