Example #1
0
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
Example #2
0
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
Example #3
0
    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
Example #4
0
 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
Example #5
0
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
Example #6
0
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
Example #7
0
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
Example #8
0
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
Example #9
0
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
Example #10
0
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)