def donation_address(reusable_donation_pubkey=None): if not reusable_donation_pubkey: reusable_donation_pubkey = ('02be838257fbfddabaea03afbb9f16e852' '9dfe2de921260a5c46036d97b5eacf2a') sign_k = binascii.hexlify(os.urandom(32)) c = btc.sha256(btc.multiply(sign_k, reusable_donation_pubkey, True)) sender_pubkey = btc.add_pubkeys([reusable_donation_pubkey, btc.privtopub(c+'01', True)], True) sender_address = btc.pubtoaddr(sender_pubkey, get_p2pk_vbyte()) log.info('sending coins to ' + sender_address) return sender_address, sign_k
def donation_address(reusable_donation_pubkey=None): if not reusable_donation_pubkey: reusable_donation_pubkey = ('02be838257fbfddabaea03afbb9f16e852' '9dfe2de921260a5c46036d97b5eacf2a') sign_k = binascii.hexlify(os.urandom(32)) c = btc.sha256(btc.multiply(sign_k, reusable_donation_pubkey, True)) sender_pubkey = btc.add_pubkeys( [reusable_donation_pubkey, btc.privtopub(c + '01', True)], True) sender_address = btc.pubtoaddr(sender_pubkey, get_p2pk_vbyte()) log.info('sending coins to ' + sender_address) return sender_address, sign_k
def donation_address(cjtx, wallet): privkey = wallet.get_key_from_addr(wallet.get_new_addr(0,0)) reusable_donation_pubkey = '02be838257fbfddabaea03afbb9f16e8529dfe2de921260a5c46036d97b5eacf2a' global sign_k import os import binascii sign_k = os.urandom(32) log.debug("Using the following nonce value: "+binascii.hexlify(sign_k)) c = btc.sha256(btc.multiply(binascii.hexlify(sign_k), reusable_donation_pubkey, True)) sender_pubkey = btc.add_pubkeys([reusable_donation_pubkey, btc.privtopub(c+'01', True)], True) sender_address = btc.pubtoaddr(sender_pubkey, get_p2pk_vbyte()) log.debug('sending coins to ' + sender_address) return privkey, sender_address
def donation_address(cjtx, wallet): privkey = wallet.get_key_from_addr(wallet.get_new_addr(0, 0)) reusable_donation_pubkey = '02be838257fbfddabaea03afbb9f16e8529dfe2de921260a5c46036d97b5eacf2a' global sign_k import os import binascii sign_k = os.urandom(32) log.debug("Using the following nonce value: " + binascii.hexlify(sign_k)) c = btc.sha256( btc.multiply(binascii.hexlify(sign_k), reusable_donation_pubkey, True)) sender_pubkey = btc.add_pubkeys( [reusable_donation_pubkey, btc.privtopub(c + '01', True)], True) sender_address = btc.pubtoaddr(sender_pubkey, get_p2pk_vbyte()) log.debug('sending coins to ' + sender_address) return privkey, sender_address
def donation_address(cjtx): reusable_donation_pubkey = '02be838257fbfddabaea03afbb9f16e8529dfe2de921260a5c46036d97b5eacf2a' donation_utxo_data = cjtx.input_utxos.iteritems().next() global donation_utxo donation_utxo = donation_utxo_data[0] privkey = cjtx.wallet.get_key_from_addr(donation_utxo_data[1]['address']) tx = btc.mktx(cjtx.utxo_tx, cjtx.outputs) #tx without our inputs and outputs #address = privtoaddr(privkey) #signing_tx = signature_form(tx, 0, mk_pubkey_script(address), SIGHASH_ALL) msghash = btc.bin_txhash(tx, btc.SIGHASH_ALL) #generate unpredictable k global sign_k sign_k = btc.deterministic_generate_k(msghash, privkey) c = btc.sha256(btc.multiply(reusable_donation_pubkey, sign_k)) sender_pubkey = btc.add_pubkeys(reusable_donation_pubkey, btc.multiply(btc.G, c)) sender_address = btc.pubtoaddr(sender_pubkey, get_p2pk_vbyte()) debug('sending coins to ' + sender_address) return sender_address
def derive_child_key(parent_key, parent_chain_code, index, key_type, hardened=False): if hardened: if key_type == KeyType.PUBLIC: exit_with_error("Can not derive a hardened public child key from parent public key") input_data = bytearray(b'\x00') + parent_key else: if key_type == KeyType.PUBLIC: input_data = bitcoin.compress(parent_key) else: public_key = bitcoin.privkey_to_pubkey(parent_key) input_data = bitcoin.compress(public_key) input_data += int(index).to_bytes(4, byteorder='big') key = parent_chain_code (key_offset, chain_code) = hmac_digest_and_split(key, input_data) if key_type == KeyType.PUBLIC: point = bitcoin.decompress(bitcoin.privkey_to_pubkey(key_offset)) parent_point = bitcoin.decompress(parent_key) return bitcoin.add_pubkeys(point, parent_point), chain_code else: key = (int.from_bytes(parent_key, byteorder='big', signed=False) + int.from_bytes(key_offset, byteorder='big', signed=False)) % bitcoin.N return key.to_bytes(32, byteorder='big', signed=False), chain_code
def test_donation_address(setup_donations, amount): wallets = make_wallets(1, wallet_structures=[[1, 1, 1, 0, 0]], mean_amt=0.5) wallet = wallets[0]['wallet'] jm_single().bc_interface.sync_wallet(wallet) #make a rdp from a simple privkey rdp_priv = "\x01" * 32 reusable_donation_pubkey = binascii.hexlify( secp256k1.PrivateKey(privkey=rdp_priv, raw=True, ctx=btc.ctx).pubkey.serialize()) dest_addr, sign_k = donation_address(reusable_donation_pubkey) print dest_addr jm_single().bc_interface.rpc('importaddress', [dest_addr, '', False]) ins_full = wallet.unspent total = sum(x['value'] for x in ins_full.values()) ins = ins_full.keys() output_addr = wallet.get_new_addr(1, 1) fee_est = 10000 outs = [{ 'value': amount, 'address': dest_addr }, { 'value': total - amount - fee_est, 'address': output_addr }] tx = btc.mktx(ins, outs) de_tx = btc.deserialize(tx) for index, ins in enumerate(de_tx['ins']): utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index']) addr = ins_full[utxo]['address'] priv = wallet.get_key_from_addr(addr) priv = binascii.unhexlify(priv) usenonce = binascii.unhexlify(sign_k) if index == 0 else None if index == 0: log.debug("Applying rdp to input: " + str(ins)) tx = btc.sign(tx, index, priv, usenonce=usenonce) #pushtx returns False on any error push_succeed = jm_single().bc_interface.pushtx(tx) if push_succeed: log.debug(btc.txhash(tx)) else: assert False #Role of receiver: regenerate the destination private key, #and address, from the nonce of the first input; check it has #received the coins. detx = btc.deserialize(tx) first_utxo_script = detx['ins'][0]['script'] sig, pub = btc.deserialize_script(first_utxo_script) log.debug(sig) sig = binascii.unhexlify(sig) kGlen = ord(sig[3]) kG = sig[4:4 + kGlen] log.debug(binascii.hexlify(kG)) if kG[0] == "\x00": kG = kG[1:] #H(rdp private key * K) + rdp should be ==> dest addr #Open issue: re-introduce recovery without ECC shenanigans #Just cheat by trying both signs for pubkey coerced_kG_1 = "02" + binascii.hexlify(kG) coerced_kG_2 = "03" + binascii.hexlify(kG) for coerc in [coerced_kG_1, coerced_kG_2]: c = btc.sha256(btc.multiply(binascii.hexlify(rdp_priv), coerc, True)) pub_check = btc.add_pubkeys( [reusable_donation_pubkey, btc.privtopub(c + '01', True)], True) addr_check = btc.pubtoaddr(pub_check, get_p2pk_vbyte()) log.debug("Found checked address: " + addr_check) if addr_check == dest_addr: time.sleep(3) received = jm_single().bc_interface.get_received_by_addr( [dest_addr], None)['data'][0]['balance'] assert received == amount return assert False
def test_donation_address(setup_donations, amount): wallets = make_wallets(1, wallet_structures=[[1,1,1,0,0]], mean_amt=0.5) wallet = wallets[0]['wallet'] jm_single().bc_interface.sync_wallet(wallet) #make a rdp from a simple privkey rdp_priv = "\x01"*32 reusable_donation_pubkey = binascii.hexlify(secp256k1.PrivateKey( privkey=rdp_priv, raw=True, ctx=btc.ctx).pubkey.serialize()) dest_addr, sign_k = donation_address(reusable_donation_pubkey) print dest_addr jm_single().bc_interface.rpc('importaddress', [dest_addr, '', False]) ins_full = wallet.unspent total = sum(x['value'] for x in ins_full.values()) ins = ins_full.keys() output_addr = wallet.get_new_addr(1, 1) fee_est = 10000 outs = [{'value': amount, 'address': dest_addr}, {'value': total - amount - fee_est, 'address': output_addr}] tx = btc.mktx(ins, outs) de_tx = btc.deserialize(tx) for index, ins in enumerate(de_tx['ins']): utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index']) addr = ins_full[utxo]['address'] priv = wallet.get_key_from_addr(addr) priv = binascii.unhexlify(priv) usenonce = binascii.unhexlify(sign_k) if index == 0 else None if index == 0: log.debug("Applying rdp to input: " + str(ins)) tx = btc.sign(tx, index, priv, usenonce=usenonce) #pushtx returns False on any error push_succeed = jm_single().bc_interface.pushtx(tx) if push_succeed: log.debug(btc.txhash(tx)) else: assert False #Role of receiver: regenerate the destination private key, #and address, from the nonce of the first input; check it has #received the coins. detx = btc.deserialize(tx) first_utxo_script = detx['ins'][0]['script'] sig, pub = btc.deserialize_script(first_utxo_script) log.debug(sig) sig = binascii.unhexlify(sig) kGlen = ord(sig[3]) kG = sig[4:4+kGlen] log.debug(binascii.hexlify(kG)) if kG[0] == "\x00": kG = kG[1:] #H(rdp private key * K) + rdp should be ==> dest addr #Open issue: re-introduce recovery without ECC shenanigans #Just cheat by trying both signs for pubkey coerced_kG_1 = "02" + binascii.hexlify(kG) coerced_kG_2 = "03" + binascii.hexlify(kG) for coerc in [coerced_kG_1, coerced_kG_2]: c = btc.sha256(btc.multiply(binascii.hexlify(rdp_priv), coerc, True)) pub_check = btc.add_pubkeys([reusable_donation_pubkey, btc.privtopub(c+'01', True)], True) addr_check = btc.pubtoaddr(pub_check, get_p2pk_vbyte()) log.debug("Found checked address: " + addr_check) if addr_check == dest_addr: time.sleep(3) received = jm_single().bc_interface.get_received_by_addr( [dest_addr], None)['data'][0]['balance'] assert received == amount return assert False
def main(): # Setup """ # crtSecretSharing(listPrimes(3000000000000, 3000000010000), 6) # crtSecretSharing(listPrimes(10000, 20000), 6) 由 crtSecretSharing 选取如下序列 105987830196477595229 < secret < 1022186603775641127185083 rate = 9644.37711 [10007, 10009, 10037, 10039, 10061, 10067, 10069, 10079, 10091, 10093, 10099, 10103, 10111, 10133, 10139] """ d = 105987830196477595231 # 随机选择的私钥 q = bitcoin.N # 比特币椭圆曲线上点群的阶数 sequence = [ 10007, 10009, 10037, 10039, 10061, 10067, 10069, 10079, 10091, 10093, 10099, 10103, 10111, 10133, 10139 ] """ 根据上述正整数序列,假设玩家权重依此为 [2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] 权重为 2,则 10061 * 10067 < p < 10099 * 10103 权重为 3,则 10039 * 10061 * 10067 < p < 10099 * 10103 * 10111 # listPrimes(10061 * 10067, 10099 * 10103) # listPrimes(10039 * 10061 * 10067, 10039 * 10061 * 10067 + 1000) 由 listPrimes 更新序列为如下 """ weighted_sequence = [ 101284093, 1016790949397, 10037, 10039, 10061, 10067, 10069, 10079, 10091, 10093, 10099, 10103, 10111, 10133, 10139 ] weighted_shares = [] for i in weighted_sequence: weighted_shares.append(d % i) print("weighted_shares:", end="") print(weighted_shares) print("lambda:%d" % int(1022186603775641127185083 / d)) # Signature Generation --- Calculating temporary shares """ 假设权重值为 2,3,1,1,1 的 5 个玩家参与签名,weighted_sequence[0:5] """ N = weighted_sequence[0] * weighted_sequence[1] * weighted_sequence[ 2] * weighted_sequence[3] * weighted_sequence[4] y_i = [] d_i = [] # 使用 N / p_i^j 计算会损失精度,所以将 N / p_i^j 换成如下的连续相乘 y_i.append( findModReverse( weighted_sequence[1] * weighted_sequence[2] * weighted_sequence[3] * weighted_sequence[4], weighted_sequence[0])) y_i.append( findModReverse( weighted_sequence[0] * weighted_sequence[2] * weighted_sequence[3] * weighted_sequence[4], weighted_sequence[1])) y_i.append( findModReverse( weighted_sequence[1] * weighted_sequence[0] * weighted_sequence[3] * weighted_sequence[4], weighted_sequence[2])) y_i.append( findModReverse( weighted_sequence[1] * weighted_sequence[2] * weighted_sequence[0] * weighted_sequence[4], weighted_sequence[3])) y_i.append( findModReverse( weighted_sequence[1] * weighted_sequence[2] * weighted_sequence[3] * weighted_sequence[0], weighted_sequence[4])) d_i.append( (weighted_shares[0] * weighted_sequence[1] * weighted_sequence[2] * weighted_sequence[3] * weighted_sequence[4] * y_i[0]) % N) d_i.append( (weighted_shares[1] * weighted_sequence[0] * weighted_sequence[2] * weighted_sequence[3] * weighted_sequence[4] * y_i[1]) % N) d_i.append( (weighted_shares[2] * weighted_sequence[1] * weighted_sequence[0] * weighted_sequence[3] * weighted_sequence[4] * y_i[2]) % N) d_i.append( (weighted_shares[3] * weighted_sequence[1] * weighted_sequence[2] * weighted_sequence[0] * weighted_sequence[4] * y_i[3]) % N) d_i.append( (weighted_shares[4] * weighted_sequence[1] * weighted_sequence[2] * weighted_sequence[3] * weighted_sequence[0] * y_i[4]) % N) print("y_i:", end="") print(y_i) print("d_i:", end="") print(d_i) recover_secret = 0 for i in d_i: recover_secret += i recover_secret %= N print("recover_secret:%d" % recover_secret) # Signature Generation --- Calculating temporary shares --- First run JRSS """ 5 个玩家分别选择次数为 (5 - 1) / 2 的随机多项式,并让自由项系数为 d_i[i],运行JRSS,玩家身份索引为 i 玩家 P1: f(x) = d_i[0] + 3*x + 4*x*x 玩家 P2: f(x) = d_i[1] + 5*x + 7*x*x 玩家 P3: f(x) = d_i[2] + 2*x + 4*x*x 玩家 P4: f(x) = d_i[3] + 7*x + 2*x*x 玩家 P5: f(x) = d_i[4] + 3*x + 5*x*x """ p1_to_others = [] for i in range(1, 6): p1_to_others.append(f_x(d_i[0], 3, 4, i)) p2_to_others = [] for i in range(1, 6): p2_to_others.append(f_x(d_i[1], 5, 7, i)) p3_to_others = [] for i in range(1, 6): p3_to_others.append(f_x(d_i[2], 2, 4, i)) p4_to_others = [] for i in range(1, 6): p4_to_others.append(f_x(d_i[3], 7, 2, i)) p5_to_others = [] for i in range(1, 6): p5_to_others.append(f_x(d_i[4], 3, 5, i)) jrss_1_d_shares = [] for i in range(0, 5): jrss_1_d_shares.append(p1_to_others[i] + p2_to_others[i] + p3_to_others[i] + p4_to_others[i] + p5_to_others[i]) print(jrss_1_d_shares) print("combined_d_i:%d" % (d_i[0] + d_i[1] + d_i[2] + d_i[3] + d_i[4])) print("recover_d_i: %d" % lagrange(jrss_1_d_shares)) # Signature Generation --- Calculating temporary shares --- Second run JRSS """ 5 个玩家分别选择次数为 (5 - 1) / 2 的随机多项式,并让自由项系数 v_i <= lambda / 5 = 9644 /5 = 1928.8,运行JRSS,玩家身份索引为 i 玩家 P1: f(x) = 5 + 3*x + 4*x*x 玩家 P2: f(x) = 9 + 5*x + 7*x*x 玩家 P3: f(x) = 10 + 2*x + 4*x*x 玩家 P4: f(x) = 14 + 7*x + 2*x*x 玩家 P5: f(x) = 23 + 3*x + 5*x*x """ p1_to_others = [] for i in range(1, 6): p1_to_others.append(f_x(5, 3, 4, i)) p2_to_others = [] for i in range(1, 6): p2_to_others.append(f_x(9, 5, 7, i)) p3_to_others = [] for i in range(1, 6): p3_to_others.append(f_x(10, 2, 4, i)) p4_to_others = [] for i in range(1, 6): p4_to_others.append(f_x(14, 7, 2, i)) p5_to_others = [] for i in range(1, 6): p5_to_others.append(f_x(23, 3, 5, i)) jrss_2_v_shares = [] for i in range(0, 5): jrss_2_v_shares.append(p1_to_others[i] + p2_to_others[i] + p3_to_others[i] + p4_to_others[i] + p5_to_others[i]) print(jrss_2_v_shares) print("combined_v_i:%d" % (5 + 9 + 10 + 14 + 23)) print("recover_v_i: %d" % lagrange(jrss_2_v_shares)) # Signature Generation --- Calculating temporary shares --- Locally compute v_i*d_i and recover v*d jrss_vd_shares = [] for i in range(0, 5): jrss_vd_shares.append(jrss_1_d_shares[i] * jrss_2_v_shares[i]) print(jrss_vd_shares) print("combined_vd:%d" % ((d_i[0] + d_i[1] + d_i[2] + d_i[3] + d_i[4]) * (5 + 9 + 10 + 14 + 23))) print("recover_vd: %d" % lagrange(jrss_vd_shares)) vd = lagrange(jrss_vd_shares) % N print("vd mod N: %d" % vd) # Signature Generation --- Calculating temporary shares --- Simple Reciprocal Protocol get shares of v^-1 without revealing v and v^-1 srp_v_reverse_shares = simpleRecPro(jrss_2_v_shares, q) print(srp_v_reverse_shares) # Signature Generation --- Calculating temporary shares --- Get temporary shares \alpha_i = v_i^-1 * vd mod q of private key d alpha_shares = [] for i in range(0, 5): alpha_shares.append(srp_v_reverse_shares[i] * vd % q) print("alpha_shares:", end="") print(alpha_shares) print("recover_secret:%d" % (lagrange(alpha_shares) % q)) # Signature Generation --- Calculating the first part of signature """ 5 个玩家分别选择次数为 (5 - 1) / 2 的随机多项式,并让自由项系数 1 < k_i < q,运行JRSS,玩家身份索引为 i 玩家 P2: f(x) = 24 + 5*x + 7*x*x mod q 玩家 P1: f(x) = 89 + 3*x + 4*x*x mod q 玩家 P3: f(x) = 10 + 2*x + 4*x*x mod q 玩家 P4: f(x) = 45 + 7*x + 2*x*x mod q 玩家 P5: f(x) = 23 + 3*x + 5*x*x mod q """ p1_to_others = [] for i in range(1, 6): p1_to_others.append(f_x(24, 3, 4, i)) p2_to_others = [] for i in range(1, 6): p2_to_others.append(f_x(89, 5, 7, i)) p3_to_others = [] for i in range(1, 6): p3_to_others.append(f_x(10, 2, 4, i)) p4_to_others = [] for i in range(1, 6): p4_to_others.append(f_x(45, 7, 2, i)) p5_to_others = [] for i in range(1, 6): p5_to_others.append(f_x(23, 3, 5, i)) jrss_k_shares = [] for i in range(0, 5): jrss_k_shares.append(p1_to_others[i] + p2_to_others[i] + p3_to_others[i] + p4_to_others[i] + p5_to_others[i]) print(jrss_k_shares) print("combined_k_i:%d" % (24 + 89 + 10 + 45 + 23)) print("recover_k_i: %d" % lagrange(jrss_k_shares)) V_shares = [] for i in range(len(jrss_k_shares)): l_i_0 = 1 for m in range(len(jrss_k_shares)): if m != i: l_i_0 *= fractions.Fraction((m + 1), ((m + 1) - (i + 1))) V_shares.append(jrss_k_shares[i] * l_i_0) print(V_shares) """ 将 V_shares 中的 l_i(0) * k_i 转换成比特币私钥,并利用 bitcoin 包计算点乘运算 为了使用 bitcoin.multiply(pub, priv) 方法,需要将整数 l_i(0) * k_i 转换为长度为 64 的十六进制字符串,不足的需补零。 或者不转换,直接当作十进制整数赋值给形参 priv """ V_shares_temp = [] for i in range(len(V_shares)): V_shares_temp.append(V_shares[i].numerator % q) print(V_shares_temp) V_point_shares = [] for i in V_shares_temp: V_point_shares.append(bitcoin.multiply(bitcoin.G, i)) print(V_point_shares) V_point_k_G = V_point_shares[0] i = 1 while i < len(V_point_shares): V_point_k_G = bitcoin.add_pubkeys(V_point_k_G, V_point_shares[i]) i += 1 print("V_point_k_G:", end="") print(V_point_k_G) r = V_point_k_G[0] % q # 签名对中的 r print("r:%d" % r) # Signature Generation --- Calculating the second part of signature srp_k_reverse_shares = simpleRecPro(jrss_k_shares, q) print("srp_k_reverse_shares:", end="") print(srp_k_reverse_shares) print("recover_k_reverse:%d" % lagrange(srp_k_reverse_shares)) """ 计算部分签名 s_i = k_i^-1 * hash + r * alpha_i * k_i^-1 mod q """ message_hash = 123456789 # 待签名消息的哈希 s_shares = [] for i in range(len(srp_k_reverse_shares)): s_shares.append((srp_k_reverse_shares[i] * message_hash + r * alpha_shares[i] * srp_k_reverse_shares[i]) % q) s = lagrange(s_shares) % q # 签名对中的 s print("s:%d" % s) # Signature Verification Q = bitcoin.multiply(bitcoin.G, d) # 私钥对应的公钥 w = findModReverse(s, q) u1 = message_hash * w % q u2 = r * w % q final_point = bitcoin.add_pubkeys(bitcoin.multiply(bitcoin.G, u1), bitcoin.multiply(Q, u2)) print(final_point[0] % q)