def ringsig_verify_substitute(msghash, x0, s, Ix, Iy, pub_xs, pub_ys): # Number of pubkeys n = len(pub_xs) # Create list of pubkeys as (x, y) points pubs = [(pub_xs[i], recover_y(pub_xs[i], bit(pub_ys, i))) for i in range(n)] # Decompress the provided I value I = Ix, recover_y(Ix, Iy) # Store the list of intermediate values in the "ring" e = [None] * (n + 1) # Set the first value in the ring to that provided in the signature e[0] = [x0, hash_value(x0)] i = 1 while i < n + 1: prev_i = (i - 1) % n # Create the next values in the ring based on the provided s value pub1 = b.subtract_pubkeys(b.privtopub(s[prev_i]), b.multiply(pubs[i % n], e[prev_i][1])) pub2 = b.subtract_pubkeys(b.multiply(hash_to_pubkey(list(pubs[i % n])), s[prev_i]), b.multiply(I, e[prev_i][1])) left = hash_array([msghash, pub1[0], pub1[1], pub2[0], pub2[1]]) right = hash_value(left) # FOR DEBUGGING # if i >= 1: # print 'pre', pubs[i % n] # print 'pub1', pub1 # print 'pub2', pub2 # print 'left', left # print 'right', right e[i] = [left, right] i += 1 # Check that the ring is consistent return(e[n][0] == e[0][0] and e[n][1] == e[0][1])
def ringsig_verify_substitute(msghash, x0, s, Ix, Iy, pub_xs, pub_ys): # Number of pubkeys n = len(pub_xs) # Create list of pubkeys as (x, y) points pubs = [(pub_xs[i], recover_y(pub_xs[i], bit(pub_ys, i))) for i in range(n)] # Decompress the provided I value I = Ix, recover_y(Ix, Iy) # Store the list of intermediate values in the "ring" e = [None] * (n + 1) # Set the first value in the ring to that provided in the signature e[0] = [x0, hash_value(x0)] i = 1 while i < n + 1: prev_i = (i - 1) % n # Create the next values in the ring based on the provided s value pub1 = b.subtract_pubkeys(b.privtopub(s[prev_i]), b.multiply(pubs[i % n], e[prev_i][1])) pub2 = b.subtract_pubkeys( b.multiply(hash_to_pubkey(list(pubs[i % n])), s[prev_i]), b.multiply(I, e[prev_i][1])) left = hash_array([msghash, pub1[0], pub1[1], pub2[0], pub2[1]]) right = hash_value(left) # FOR DEBUGGING # if i >= 1: # print 'pre', pubs[i % n] # print 'pub1', pub1 # print 'pub2', pub2 # print 'left', left # print 'right', right e[i] = [left, right] i += 1 # Check that the ring is consistent return (e[n][0] == e[0][0] and e[n][1] == e[0][1])
def ringsig_sign_substitute(msghash, priv, pub_xs, pub_ys): # Number of pubkeys n = len(pub_xs) # Create list of pubkeys as (x, y) points pubs = [(pub_xs[i], recover_y(pub_xs[i], bit(pub_ys, i))) for i in range(n)] # My pubkey my_pub = b.decode_pubkey(b.privtopub(priv)) # Compute my index in the pubkey list my_index = 0 while my_index < n: if pubs[my_index] == my_pub: break my_index += 1 assert my_index < n # Compute the signer's I value I = b.multiply(hash_to_pubkey(list(my_pub)), priv) # Select a random ephemeral key k = b.hash_to_int(b.random_key()) # Store the list of intermediate values in the "ring" e = [None] * n # Compute the entry in the ring corresponding to the signer's index kpub = b.privtopub(k) kmulpub = b.multiply(hash_to_pubkey(list(my_pub)), k) orig_left = hash_array([msghash, kpub[0], kpub[1], kmulpub[0], kmulpub[1]]) orig_right = hash_value(orig_left) e[my_index] = {"left": orig_left, "right": orig_right} # Map of intermediate s values (part of the signature) s = [None] * n for i in list(range(my_index + 1, n)) + list(range(my_index + 1)): prev_i = (i - 1) % n # In your position in the ring, set the s value based on your private # knowledge of k; this lets you "invert" the hash function in order to # ensure a consistent ring. At all other positions, select a random s if i == my_index: s[prev_i] = b.add_privkeys( k, b.mul_privkeys(e[prev_i]["right"], priv)) else: s[prev_i] = b.hash_to_int(b.random_key()) # Create the next values in the ring based on the chosen s value pub1 = b.subtract_pubkeys(b.privtopub(s[prev_i]), b.multiply(pubs[i], e[prev_i]["right"])) pub2 = b.subtract_pubkeys( b.multiply(hash_to_pubkey(list(pubs[i])), s[prev_i]), b.multiply(I, e[prev_i]["right"])) left = hash_array([msghash, pub1[0], pub1[1], pub2[0], pub2[1]]) right = hash_value(left) e[i] = {"left": left, "right": right} # Check that the ring is consistent assert (left, right) == (orig_left, orig_right) # Return the first value in the ring, the s values, and the signer's # I value in compressed form return (e[0]["left"], s, I[0], I[1] % 2)
def ringsig_sign_substitute(msghash, priv, pub_xs, pub_ys): # Number of pubkeys n = len(pub_xs) # Create list of pubkeys as (x, y) points pubs = [(pub_xs[i], recover_y(pub_xs[i], bit(pub_ys, i))) for i in range(n)] # My pubkey my_pub = b.decode_pubkey(b.privtopub(priv)) # Compute my index in the pubkey list my_index = 0 while my_index < n: if pubs[my_index] == my_pub: break my_index += 1 assert my_index < n # Compute the signer's I value I = b.multiply(hash_to_pubkey(list(my_pub)), priv) # Select a random ephemeral key k = b.hash_to_int(b.random_key()) # Store the list of intermediate values in the "ring" e = [None] * n # Compute the entry in the ring corresponding to the signer's index kpub = b.privtopub(k) kmulpub = b.multiply(hash_to_pubkey(list(my_pub)), k) orig_left = hash_array([msghash, kpub[0], kpub[1], kmulpub[0], kmulpub[1]]) orig_right = hash_value(orig_left) e[my_index] = {"left": orig_left, "right": orig_right} # Map of intermediate s values (part of the signature) s = [None] * n for i in list(range(my_index + 1, n)) + list(range(my_index + 1)): prev_i = (i - 1) % n # In your position in the ring, set the s value based on your private # knowledge of k; this lets you "invert" the hash function in order to # ensure a consistent ring. At all other positions, select a random s if i == my_index: s[prev_i] = b.add_privkeys(k, b.mul_privkeys(e[prev_i]["right"], priv)) else: s[prev_i] = b.hash_to_int(b.random_key()) # Create the next values in the ring based on the chosen s value pub1 = b.subtract_pubkeys(b.privtopub(s[prev_i]), b.multiply(pubs[i], e[prev_i]["right"])) pub2 = b.subtract_pubkeys(b.multiply(hash_to_pubkey(list(pubs[i])), s[prev_i]), b.multiply(I, e[prev_i]["right"])) left = hash_array([msghash, pub1[0], pub1[1], pub2[0], pub2[1]]) right = hash_value(left) e[i] = {"left": left, "right": right} # Check that the ring is consistent assert (left, right) == (orig_left, orig_right) # Return the first value in the ring, the s values, and the signer's # I value in compressed form return (e[0]["left"], s, I[0], I[1] % 2)
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 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 encrypt(plaintext, pubkey, ephemeral_key=_secure_ephemeral()): optional_shared_info = ('', '') shared_secret = bitcoin.decode_pubkey( bitcoin.multiply(pubkey, ephemeral_key))[1] shared_secret_bin = _int2bin32b(shared_secret) ephemeral_pubkey = bitcoin.privtopub(ephemeral_key) symmetric_key, mac_key = ecies_derive_keys( shared_secret_bin, optional_shared_info0=optional_shared_info[0]) aes = AESCipher(symmetric_key) encrypted_string = aes.encrypt(plaintext) tag = ecies_compute_tag(mac_key=mac_key, encrypted_string=encrypted_string, optional_shared_info1=optional_shared_info[1]) return ephemeral_pubkey, encrypted_string, tag
def becies_shared_secret( private_key, public_key, optional_shared_info0='' ): #we do NOT use http://www.secg.org/sec1-v2.pdf ANSI KDF function, we use pkcs5_pbkdf2_hmac_sha512. It's got more hardening and it's more common and already a part of bitcoin shared_secret_point = bitcoin.multiply(public_key, private_key) shared_secret = bitcoin.decode_pubkey(shared_secret_point)[ 1] #todo: check point at infinity? todo: compressed pubkey? shared_secret_bin = _int2bin32b(shared_secret) salt = 'becies' key = shared_secret_bin + optional_shared_info0 hmac_result = pbkdf2_hmac( _becies_hashname, key, salt=salt + key, iterations=2048 ) #https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki symmetric_key = hmac_result[:(len(hmac_result) // 2)] mac_key = hmac_result[(len(hmac_result) // 2):] return symmetric_key, mac_key
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 decrypt(ciphertuple, privkey): optional_shared_info = ('', '') ephemeral_pubkey = ciphertuple[0] encrypted_string = ciphertuple[1] msgtag = ciphertuple[2] shared_secret = bitcoin.decode_pubkey( bitcoin.multiply(privkey, ephemeral_pubkey))[1] #todo: check point at infinity shared_secret_bin = _int2bin32b(shared_secret) symmetric_key, mac_key = ecies_derive_keys( shared_secret_bin, optional_shared_info0=optional_shared_info[0]) tag = ecies_compute_tag(mac_key=mac_key, encrypted_string=encrypted_string, optional_shared_info1=optional_shared_info[1]) if (tag != msgtag): raise "Decryption Failure...tag mismatch. The message may have been tampered with" aes = AESCipher(symmetric_key) return aes.decrypt(encrypted_string)
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
# Convert private key to WIF format wif_encoded_private_key = bitcoin.encode_privkey(decoded_private_key, 'wif') print("Private Key (WIF): ", wif_encoded_private_key) # Add suffix "01" to indicate a compressed private key compressed_private_key = private_key + '01' # print("Private Key Compressed (hex) is: ", compressed_private_key) // TODO VERBOSE # Generate a WIF format from the compressed private key (WIF-compressed) wif_compressed_private_key = bitcoin.encode_privkey( bitcoin.decode_privkey(compressed_private_key, 'hex'), 'wif') print("Private Key (WIF-Compressed): ", wif_compressed_private_key) # Multiply the EC generator point G with the private key to get a public key point public_key = bitcoin.multiply(bitcoin.G, decoded_private_key) # print("Public Key (x,y) coordinates is:", public_key) // TODO VERBOSE # Encode as hex, prefix 04 hex_encoded_public_key = bitcoin.encode_pubkey(public_key, 'hex') # print("Public Key (hex) is:", hex_encoded_public_key) // TODO VERBOSE # Compress public key, adjust prefix depending on whether y is even or odd (public_key_x, public_key_y) = public_key if (public_key_y % 2) == 0: compressed_prefix = '02' else: compressed_prefix = '03' hex_compressed_public_key = compressed_prefix + bitcoin.encode( public_key_x, 16) # print("Compressed Public Key (hex) is:", hex_compressed_public_key) // TODO VERBOSE
secret = bitcoin.random_key() relayNodes.append({ 'secret': secret, 'public': bitcoin.privtopub(secret) }) exitNode_sk = bitcoin.random_key() exitNode_pk = bitcoin.privtopub(exitNode_sk) ################################################################################ ############################ Connecting Process ############################ ################################################################################ # The user ask for a connection to relayNode1, wich ask to next node... until exitNode u_shared = user_pk for i in range(NB_RELAY_NODES): u_shared = bitcoin.multiply(u_shared, relayNodes[i]['secret']) # Then exitNode calculate and sign the global shared secret global_shared = bitcoin.multiply(u_shared, exitNode_sk) global_shared_signature = bitcoin.ecdsa_sign(global_shared, exitNode_sk) # Then, the exitNode accept the connection by sending back the signature # The relayNodes now calculate new shared with exitNode e_shared = exitNode_pk for i in range(NB_RELAY_NODES)[::-1]: e_shared = bitcoin.multiply(e_shared, relayNodes[i]['secret']) # User can now calculate global shared key and test if exitNode has the same assert exitNode_pk == bitcoin.ecdsa_recover(bitcoin.multiply(e_shared, user_sk), global_shared_signature) ################################################################################
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)