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)
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
def __eq__(self, other): return (eq(self.m1, other.m1) and eq(self.m2, other.m2))
def eq(self, other: "WrappedCurvePoint") -> bool: return eq(self.py_ecc_object, other.py_ecc_object)
def equal(xxx: G1Point, yyy: G1Point) -> bool: return bls12_381.eq(xxx, yyy)