Beispiel #1
0
def verify(points, commitment, proof):
    # Crop the base points to just what we need
    points = points[:2**len(proof.L)]
    # Fiat-shamir randomness value
    r = hash(serialize_point(commitment))
    # For verification, we need to generate the same random linear combination of
    # base points that the prover did.. But because we don't need to use it until
    # the end, we do it more efficiently here: when we progress through the rounds,
    # we keep track of how many times each points[i] will appear in the final
    # result...
    points_coeffs = [1]
    # log(n) rounds, just like the prover...
    for i in range(len(proof.L)):
        r = hash(r + serialize_point(proof.L[i]) + serialize_point(proof.R[i]))
        # Generate random coefficient for recombining (same as the prover)
        a = int.from_bytes(r, 'little') % b.curve_order
        # print('a value: ', a)
        # Add L and R into the commitment, applying the appropriate coefficients
        commitment = b.add(
            proof.L[i],
            b.add(b.multiply(commitment, a), b.multiply(proof.R[i], a**2)))
        # print('intermediate commitment:', commitment)
        # Update the coefficients (points_coeffs[i] = how many times points[i] will
        # appear in the single base point of the last round)
        points_coeffs = sum([[(x * a) % b.curve_order, x]
                             for x in points_coeffs], [])
    # Finally, we do the linear combination
    combined_point = lincomb(points, points_coeffs, b.add, b.Z1)
    # Base case check: base_point * coefficient ?= commitment
    return b.eq(b.multiply(combined_point, proof.tip), commitment)
Beispiel #2
0
def verify_evaluation(points, commitment, proof, x, y):
    # Crop the base points to just what we need. We add an additional base point,
    # which we will use to mix in the _evaluation_ of the polynomial.
    points, H = points[:2**len(proof.L)], points[2**len(proof.L)]
    # Powers of x, as in the prover
    xpowers = [pow(x, i, b.curve_order) for i in range(len(poly))]
    # Fiat-shamir randomness value
    r = hash(
        serialize_point(commitment) + x.to_bytes(32, 'little') +
        y.to_bytes(32, 'little'))
    # For security, we randomize H
    H = b.multiply(H, int.from_bytes(r, 'little') % b.curve_order)
    # We "mix in" H * the claimed evaluation P(x) = y. Notice that `H * P(x)` equals the
    # dot-product of `H * powers of x` and the polynomial coefficients, so it has the
    # "same format" as the polynomial commitment itself. This allows us to verify the
    # evaluation using the same technique that we use to just prove that the commitment
    # is valid
    commitment = b.add(commitment, b.multiply(H, y))
    # Track the linear combination so we can generate the final-round point and xpower,
    # just as before
    points_coeffs = [1]
    for i in range(len(proof.L)):
        # Generate random coefficient for recombining (same as the prover)
        r = hash(r + serialize_point(proof.L[i]) + serialize_point(proof.R[i]))
        a = int.from_bytes(r, 'little') % b.curve_order
        # print('a value: ', a)
        # Add L and R into the commitment, applying the appropriate coefficients
        commitment = b.add(
            proof.L[i],
            b.add(b.multiply(commitment, a), b.multiply(proof.R[i], a**2)))
        # print('intermediate commitment:', commitment)
        # Update the coefficients (as in basic verification above)
        points_coeffs = sum([[(x * a) % b.curve_order, x]
                             for x in points_coeffs], [])
    # Finally, we do the linear combination; same one for base points and x powers
    combined_point = lincomb(points, points_coeffs, b.add, b.Z1)
    combined_x_powers = sum(p * c for p, c in zip(xpowers, points_coeffs))
    # Base case check: base_point * coefficient ?= commitment. Note that here we
    # have to also mix H * the combined xpower into the final base point
    return b.eq(
        b.add(b.multiply(combined_point, proof.tip),
              b.multiply(H, (proof.tip * combined_x_powers) % b.curve_order)),
        commitment)
def generate_bls_key_shares_with_verification(rsa_key_files:Dict[int,str], threshold:int, integrity_passphrase:str):

    parties_ids = list(rsa_key_files.keys())

    # Generate and Shamir secret share root private key with related public keys and shares
    root_private_key_shares, root_private_key = _sample_shares(parties_ids, threshold)
    root_public_key = bls_conv.pubkey_to_G1(bls_basic.SkToPk(root_private_key))
    root_public_key_shares = {id : bls_conv.pubkey_to_G1(bls_basic.SkToPk(val)) for id, val in root_private_key_shares.items()}

    # Generate and Shamir secret share private chaincode with related public chaincode
    private_chaincode_shares, private_chaincode = _sample_shares(parties_ids, threshold)
    public_chaincode = bls_conv.pubkey_to_G1(bls_basic.SkToPk(private_chaincode))

    # Set master public key and private key shares
    master_pubkey = get_master_pubkey(root_public_key, public_chaincode)
    master_private_key_shares = {id : get_master_private_key(root_private_key_shares[id], private_chaincode_shares[id]) for id in parties_ids}

    # Senity check: verify all authorized set of keys (threshold size) generate the same root public key as above
    for auth_ids in itertools.combinations(parties_ids, threshold):
        curr_public_key = _interpolate_in_group({id : root_public_key_shares[id] for id in auth_ids}, bls_curve.G1)
        if not bls_curve.eq(root_public_key, curr_public_key):
            raise GenVerErrorBasic(f'Invalid Shamir secret sharing of public key for parties {auth_ids}')
    
    # Sign test message with each private key share, derived at test path
    test_derivation_path = _get_test_path()
    derived_pubkey_address = bls_conv.G1_to_pubkey(derive_public_child(master_pubkey, _get_test_path()))
    signature_shares = {}
    for id in parties_ids:
        try:
            derived_private_key_share = derive_private_child(master_private_key_shares[id], test_derivation_path, master_pubkey)             
            test_msg, _ = _get_msg_for_address(derived_pubkey_address)
            signature_shares[id] = bls_basic.Sign(derived_private_key_share, test_msg)
        except:
            raise GenVerErrorBasic(f'Unable to sign test message for id {id}')
    
    # Scrypt checksum of public key - to avoid manipulation and brute-force
    integrity_passphrase = bytes(integrity_passphrase,'utf-8')
    scrypt_checksum = _compute_scrypt_checksum(integrity_passphrase, master_pubkey)

    # Encrypt master private key shares and (common) integrity passphrase
    encrypted_master_private_key_shares = {}
    encrypted_integrity_passphrase = {}
    for id, rsa_key_file in rsa_key_files.items():
        try:
            rsa_key = RSA.importKey(open(rsa_key_file, 'r').read())
            cipher = PKCS1_OAEP.new(rsa_key)
        except:
            raise GenVerErrorBasic(f'Reading RSA key file {rsa_key_file}')

        if rsa_key.n.bit_length() < 4096:
            GenVerErrorBasic(f'RSA key is too short: {rsa_key.n.bit_length()}, should be at least 4096 bits')

        try:
            encrypted_master_private_key_shares[id] = cipher.encrypt(master_private_key_shares[id])
            encrypted_integrity_passphrase[id] = cipher.encrypt(integrity_passphrase)
        except:
            raise GenVerErrorBasic(f'Unable to encrypt master private key share for id {id}')
        
    # Prepare data to output to file
    
    data = {}
    data['master_pubkey'] = master_pubkey.hex()

    # Ingerity check for master public key
    data['integrity_checksum'] = scrypt_checksum.hex()

    data['threshold'] = threshold
    data['parties'] = {}
    for id in parties_ids:
        party = {}
        party['test_signature_share'] = signature_shares[id].hex()
        party['encrypted_master_private_key_share'] = encrypted_master_private_key_shares[id].hex()
        party['encrypted_integrity_passphrase'] = encrypted_integrity_passphrase[id].hex()
        data['parties'][id] = party
    
    # Output file for each party id (key id)
    for id in parties_ids:
        data['key_id'] = id
        # Write to file
        key_filename = f'id_{id}_fireblocks_bls_key_{master_pubkey[:4].hex()}.json'
        try:
            ver_file = open(key_filename, 'w+')
            json.dump(data, ver_file, indent=4)
            ver_file.close()
            print("Generated file:", colored(f'{key_filename}', "green"))
        except ValueError:
            raise GenVerErrorBasic(f'Error writing key file for id {id}')

    return master_pubkey
Beispiel #4
0
 def __eq__(self, other):
     return (eq(self.m1, other.m1) and eq(self.m2, other.m2))
Beispiel #5
0
 def eq(self, other: "WrappedCurvePoint") -> bool:
     return eq(self.py_ecc_object, other.py_ecc_object)
Beispiel #6
0
 def equal(xxx: G1Point, yyy: G1Point) -> bool:
     return bls12_381.eq(xxx, yyy)