def split_rekey(priv_a: Union[UmbralPrivateKey, CurveBN], pubkey_b_point: Union[UmbralPublicKey, Point], threshold: int, N: int, params: UmbralParameters=None) -> List[KFrag]: """ Creates a re-encryption key from Alice to Bob and splits it in KFrags, using Shamir's Secret Sharing. Requires a threshold number of KFrags out of N to guarantee correctness of re-encryption. Returns a list of KFrags. """ params = params if params is not None else default_params() if isinstance(priv_a, UmbralPrivateKey): priv_a = priv_a.bn_key if isinstance(pubkey_b_point, UmbralPublicKey): pubkey_b_point = pubkey_b_point.point_key g = params.g pubkey_a_point = priv_a * g x = CurveBN.gen_rand(params.curve) xcomp = x * g d = CurveBN.hash(xcomp, pubkey_b_point, pubkey_b_point * x, params=params) coeffs = [priv_a * (~d)] coeffs += [CurveBN.gen_rand(params.curve) for _ in range(threshold - 1)] u = params.u g_ab = priv_a * pubkey_b_point blake2b = hashes.Hash(hashes.BLAKE2b(64), backend=backend) blake2b.update(pubkey_a_point.to_bytes()) blake2b.update(pubkey_b_point.to_bytes()) blake2b.update(g_ab.to_bytes()) hashed_dh_tuple = blake2b.finalize() kfrags = [] for _ in range(N): id_kfrag = CurveBN.gen_rand(params.curve) share_x = CurveBN.hash(id_kfrag, hashed_dh_tuple, params=params) rk = poly_eval(coeffs, share_x) u1 = rk * u y = CurveBN.gen_rand(params.curve) signature_input = [y * g, id_kfrag, pubkey_a_point, pubkey_b_point, u1, xcomp] z1 = CurveBN.hash(*signature_input, params=params) z2 = y - priv_a * z1 kfrag = KFrag(bn_id=id_kfrag, bn_key=rk, point_noninteractive=xcomp, point_commitment=u1, bn_sig1=z1, bn_sig2=z2) kfrags.append(kfrag) return kfrags
def split_rekey(priv_a: Union[UmbralPrivateKey, BigNum], pub_b: Union[UmbralPublicKey, Point], threshold: int, N: int, params: UmbralParameters = None) -> List[KFrag]: """ Creates a re-encryption key from Alice to Bob and splits it in KFrags, using Shamir's Secret Sharing. Requires a threshold number of KFrags out of N to guarantee correctness of re-encryption. Returns a list of KFrags. """ params = params if params is not None else default_params() if isinstance(priv_a, UmbralPrivateKey): priv_a = priv_a.bn_key if isinstance(pub_b, UmbralPublicKey): pub_b = pub_b.point_key g = params.g pub_a = priv_a * g x = BigNum.gen_rand(params.curve) xcomp = x * g d = hash_to_bn([xcomp, pub_b, pub_b * x], params) coeffs = [priv_a * (~d)] coeffs += [BigNum.gen_rand(params.curve) for _ in range(threshold - 1)] u = params.u g_ab = priv_a * pub_b blake2b = hashes.Hash(hashes.BLAKE2b(64), backend=backend) blake2b.update(pub_a.to_bytes()) blake2b.update(pub_b.to_bytes()) blake2b.update(g_ab.to_bytes()) hashed_dh_tuple = blake2b.finalize() kfrags = [] for _ in range(N): id_kfrag = BigNum.gen_rand(params.curve) share_x = hash_to_bn([id_kfrag, hashed_dh_tuple], params) rk = poly_eval(coeffs, share_x) u1 = rk * u y = BigNum.gen_rand(params.curve) z1 = hash_to_bn([y * g, id_kfrag, pub_a, pub_b, u1, xcomp], params) z2 = y - priv_a * z1 kfrag = KFrag(id_=id_kfrag, key=rk, x=xcomp, u1=u1, z1=z1, z2=z2) kfrags.append(kfrag) return kfrags
def split_rekey( priv_a: Union[UmbralPrivateKey, BigNum], pub_b: Union[UmbralPublicKey, Point], threshold: int, N: int, params: UmbralParameters = None) -> Tuple[List[KFrag], List[Point]]: """ Creates a re-encryption key and splits it using Shamir's Secret Sharing. Requires a threshold number of fragments out of N to rebuild rekey. Returns rekeys and the vKeys. """ params = params if params is not None else default_params() if isinstance(priv_a, UmbralPrivateKey): priv_a = priv_a.bn_key if isinstance(pub_b, UmbralPublicKey): pub_b = pub_b.point_key g = params.g pub_a = priv_a * g x = BigNum.gen_rand(params.curve) xcomp = x * g d = hash_to_bn([xcomp, pub_b, pub_b * x], params) coeffs = [priv_a * (~d)] coeffs += [BigNum.gen_rand(params.curve) for _ in range(threshold - 1)] h = params.h u = params.u v_keys = [coeff * h for coeff in coeffs] rk_shares = [] for _ in range(N): id_kfrag = BigNum.gen_rand(params.curve) rk = poly_eval(coeffs, id_kfrag) u1 = rk * u y = BigNum.gen_rand(params.curve) z1 = hash_to_bn([y * g, id_kfrag, pub_a, pub_b, u1, xcomp], params) z2 = y - priv_a * z1 kFrag = KFrag(id_=id_kfrag, key=rk, x=xcomp, u1=u1, z1=z1, z2=z2) rk_shares.append(kFrag) return rk_shares, v_keys
def split_rekey(delegating_privkey: UmbralPrivateKey, signer: Signer, receiving_pubkey: UmbralPublicKey, threshold: int, N: int) -> List[KFrag]: """ Creates a re-encryption key from Alice to Bob and splits it in KFrags, using Shamir's Secret Sharing. Requires a threshold number of KFrags out of N to guarantee correctness of re-encryption. Returns a list of KFrags. """ if threshold <= 0 or threshold > N: raise ValueError( 'Arguments threshold and N must satisfy 0 < threshold <= N') if delegating_privkey.params != receiving_pubkey.params: raise ValueError("Keys must have the same parameter set.") params = delegating_privkey.params g = params.g pubkey_a_point = delegating_privkey.get_pubkey().point_key privkey_a_bn = delegating_privkey.bn_key pubkey_b_point = receiving_pubkey.point_key # 'ni' stands for 'Non Interactive'. # This point is used as an ephemeral public key in a DH key exchange, # and the resulting shared secret 'd' allows to make Umbral non-interactive priv_ni = CurveBN.gen_rand(params.curve) ni = priv_ni * g d = CurveBN.hash(ni, pubkey_b_point, pubkey_b_point * priv_ni, params=params) coeffs = [privkey_a_bn * (~d)] coeffs += [CurveBN.gen_rand(params.curve) for _ in range(threshold - 1)] u = params.u # 'xcoord' stands for 'X coordinate'. # This point is used as an ephemeral public key in a DH key exchange, # and the resulting shared secret 'dh_xcoord' contributes to prevent # reconstruction of the re-encryption key without Bob's intervention priv_xcoord = CurveBN.gen_rand(params.curve) xcoord = priv_xcoord * g dh_xcoord = priv_xcoord * pubkey_b_point blake2b = hashes.Hash(hashes.BLAKE2b(64), backend=backend) blake2b.update(xcoord.to_bytes()) blake2b.update(pubkey_b_point.to_bytes()) blake2b.update(dh_xcoord.to_bytes()) hashed_dh_tuple = blake2b.finalize() bn_size = CurveBN.expected_bytes_length(params.curve) kfrags = [] for _ in range(N): id = os.urandom(bn_size) share_x = CurveBN.hash(id, hashed_dh_tuple, params=params) rk = poly_eval(coeffs, share_x) u1 = rk * u kfrag_validity_message = bytes().join( bytes(material) for material in (id, pubkey_a_point, pubkey_b_point, u1, ni, xcoord)) signature = signer(kfrag_validity_message) kfrag = KFrag(id=id, bn_key=rk, point_noninteractive=ni, point_commitment=u1, point_xcoord=xcoord, signature=signature) kfrags.append(kfrag) return kfrags
def split_rekey(privkey_a_bn: Union[UmbralPrivateKey, CurveBN], signer_a: Signer, pubkey_b_point: Union[UmbralPublicKey, Point], threshold: int, N: int, params: UmbralParameters = None) -> List[KFrag]: """ Creates a re-encryption key from Alice to Bob and splits it in KFrags, using Shamir's Secret Sharing. Requires a threshold number of KFrags out of N to guarantee correctness of re-encryption. Returns a list of KFrags. """ params = params if params is not None else default_params() g = params.g if isinstance(privkey_a_bn, UmbralPrivateKey): pubkey_a_point = privkey_a_bn.get_pubkey().point_key privkey_a_bn = privkey_a_bn.bn_key else: pubkey_a_point = privkey_a_bn * g if isinstance(pubkey_b_point, UmbralPublicKey): pubkey_b_point = pubkey_b_point.point_key # 'ni' stands for 'Non Interactive'. # This point is used as an ephemeral public key in a DH key exchange, # and the resulting shared secret 'd' allows to make Umbral non-interactive priv_ni = CurveBN.gen_rand(params.curve) ni = priv_ni * g d = CurveBN.hash(ni, pubkey_b_point, pubkey_b_point * priv_ni, params=params) coeffs = [privkey_a_bn * (~d)] coeffs += [CurveBN.gen_rand(params.curve) for _ in range(threshold - 1)] u = params.u # 'xcoord' stands for 'X coordinate'. # This point is used as an ephemeral public key in a DH key exchange, # and the resulting shared secret 'dh_xcoord' contributes to prevent # reconstruction of the re-encryption key without Bob's intervention priv_xcoord = CurveBN.gen_rand(params.curve) xcoord = priv_xcoord * g dh_xcoord = priv_xcoord * pubkey_b_point blake2b = hashes.Hash(hashes.BLAKE2b(64), backend=backend) blake2b.update(xcoord.to_bytes()) blake2b.update(pubkey_b_point.to_bytes()) blake2b.update(dh_xcoord.to_bytes()) hashed_dh_tuple = blake2b.finalize() bn_size = CurveBN.expected_bytes_length(params.curve) kfrags = [] for _ in range(N): id = os.urandom(bn_size) share_x = CurveBN.hash(id, hashed_dh_tuple, params=params) rk = poly_eval(coeffs, share_x) u1 = rk * u kfrag_validity_message = bytes().join( bytes(material) for material in (id, pubkey_a_point, pubkey_b_point, u1, ni, xcoord)) signature = signer_a(kfrag_validity_message) kfrag = KFrag(id=id, bn_key=rk, point_noninteractive=ni, point_commitment=u1, point_xcoord=xcoord, signature=signature) kfrags.append(kfrag) return kfrags
def share_secret(secret, threshold, n): coeff = [secret] + [CurveBN.gen_rand() for _ in range(threshold - 1)] xs = [CurveBN.gen_rand() for _ in range(n)] points = [(x, utils.poly_eval(coeff, x)) for x in xs] return points
def generate_kfrags( delegating_privkey: UmbralPrivateKey, receiving_pubkey: UmbralPublicKey, threshold: int, N: int, signer: Signer, sign_delegating_key: Optional[bool] = True, sign_receiving_key: Optional[bool] = True, ) -> List[KFrag]: """ Creates a re-encryption key from Alice's delegating public key to Bob's receiving public key, and splits it in KFrags, using Shamir's Secret Sharing. Requires a threshold number of KFrags out of N. Returns a list of N KFrags """ if threshold <= 0 or threshold > N: raise ValueError( 'Arguments threshold and N must satisfy 0 < threshold <= N') if delegating_privkey.params != receiving_pubkey.params: raise ValueError("Keys must have the same parameter set.") params = delegating_privkey.params g = params.g delegating_pubkey = delegating_privkey.get_pubkey() bob_pubkey_point = receiving_pubkey.point_key # The precursor point is used as an ephemeral public key in a DH key exchange, # and the resulting shared secret 'dh_point' is used to derive other secret values private_precursor = CurveBN.gen_rand(params.curve) precursor = private_precursor * g # type: Any dh_point = private_precursor * bob_pubkey_point # Secret value 'd' allows to make Umbral non-interactive d = hash_to_curvebn(precursor, bob_pubkey_point, dh_point, bytes(constants.NON_INTERACTIVE), params=params) # Coefficients of the generating polynomial coefficients = [delegating_privkey.bn_key * (~d)] coefficients += [ CurveBN.gen_rand(params.curve) for _ in range(threshold - 1) ] bn_size = CurveBN.expected_bytes_length(params.curve) kfrags = list() for _ in range(N): kfrag_id = os.urandom(bn_size) # The index of the re-encryption key share (which in Shamir's Secret # Sharing corresponds to x in the tuple (x, f(x)), with f being the # generating polynomial), is used to prevent reconstruction of the # re-encryption key without Bob's intervention share_index = hash_to_curvebn(precursor, bob_pubkey_point, dh_point, bytes(constants.X_COORDINATE), kfrag_id, params=params) # The re-encryption key share is the result of evaluating the generating # polynomial for the index value rk = poly_eval(coefficients, share_index) commitment = rk * params.u # type: Any validity_message_for_bob = ( kfrag_id, delegating_pubkey, receiving_pubkey, commitment, precursor, ) # type: Any validity_message_for_bob = bytes().join( bytes(item) for item in validity_message_for_bob) signature_for_bob = signer(validity_message_for_bob) if sign_delegating_key and sign_receiving_key: mode = DELEGATING_AND_RECEIVING elif sign_delegating_key: mode = DELEGATING_ONLY elif sign_receiving_key: mode = RECEIVING_ONLY else: mode = NO_KEY validity_message_for_proxy = [kfrag_id, commitment, precursor, mode] # type: Any if sign_delegating_key: validity_message_for_proxy.append(delegating_pubkey) if sign_receiving_key: validity_message_for_proxy.append(receiving_pubkey) validity_message_for_proxy = bytes().join( bytes(item) for item in validity_message_for_proxy) signature_for_proxy = signer(validity_message_for_proxy) kfrag = KFrag( identifier=kfrag_id, bn_key=rk, point_commitment=commitment, point_precursor=precursor, signature_for_proxy=signature_for_proxy, signature_for_bob=signature_for_bob, keys_in_signature=mode, ) kfrags.append(kfrag) return kfrags
import random from umbral.utils import poly_eval, lambda_coeff prime = 2**127 - 1 n_voters = 100 n_authorities = 10 choices = [1, -1] votes = random.sample(choibces, n_voters) polynoms = [[random.randint(prime) for _ in range(n_authorities - 1)] for _ in range(n_voters)] for i in range(n_voters): polynoms[i] = [votes[i]] + polynoms[i] autorities_keys = [random.randint(prime)] vote_parts = [[poly_eval(polynom, key) for polynom in polynoms] for key in authority_keys]