def from_bytes(cls, capsule_bytes: bytes, params: UmbralParameters): """ Instantiates a Capsule object from the serialized data. """ curve = params.curve bn_size = CurveBN.expected_bytes_length(curve) point_size = Point.expected_bytes_length(curve) capsule_bytes_length = len(capsule_bytes) if capsule_bytes_length == cls.expected_bytes_length(curve, activated=True): splitter = BytestringSplitter( (Point, point_size), # point_e (Point, point_size), # point_v (CurveBN, bn_size), # bn_sig (Point, point_size), # point_e_prime (Point, point_size), # point_v_prime (Point, point_size) # point_noninteractive ) elif capsule_bytes_length == cls.expected_bytes_length( curve, activated=False): splitter = BytestringSplitter( (Point, point_size), # point_e (Point, point_size), # point_v (CurveBN, bn_size) # bn_sig ) else: raise ValueError( "Byte string does not have a valid length for a Capsule") components = splitter(capsule_bytes) return cls(params, *components)
def from_bytes(cls, data: bytes, curve: Optional[Curve] = None) -> 'KFrag': """ Instantiate a KFrag object from the serialized data. """ curve = curve if curve is not None else default_curve() bn_size = CurveBN.expected_bytes_length(curve) point_size = Point.expected_bytes_length(curve) signature_size = Signature.expected_bytes_length(curve) arguments = {'curve': curve} splitter = BytestringSplitter( bn_size, # id (CurveBN, bn_size, arguments), # bn_key (Point, point_size, arguments), # point_commitment (Point, point_size, arguments), # point_precursor 1, # keys_in_signature (Signature, signature_size, arguments), # signature_for_proxy (Signature, signature_size, arguments), # signature_for_bob ) components = splitter(data) return cls(identifier=components[0], bn_key=components[1], point_commitment=components[2], point_precursor=components[3], keys_in_signature=components[4], signature_for_proxy=components[5], signature_for_bob=components[6])
def from_bytes(cls, data: bytes, curve: Optional[Curve] = None) -> 'CapsuleFrag': """ Instantiates a CapsuleFrag object from the serialized data. """ curve = curve if curve is not None else default_curve() bn_size = CurveBN.expected_bytes_length(curve) point_size = Point.expected_bytes_length(curve) arguments = {'curve': curve} splitter = BytestringSplitter( (Point, point_size, arguments), # point_e1 (Point, point_size, arguments), # point_v1 bn_size, # kfrag_id (Point, point_size, arguments), # point_precursor ) components = splitter(data, return_remainder=True) proof = components.pop() or None components.append( CorrectnessProof.from_bytes(proof, curve) if proof else None) return cls(*components)
def from_bytes(cls, capsule_bytes: bytes, curve: ec.EllipticCurve = None): """ Instantiates a Capsule object from the serialized data. """ curve = curve if curve is not None else default_curve() bn_size = CurveBN.expected_bytes_length(curve) point_size = Point.expected_bytes_length(curve) if len(capsule_bytes) == cls.expected_bytes_length(curve, activated=True): splitter = BytestringSplitter( (Point, point_size), # point_e (Point, point_size), # point_v (CurveBN, bn_size), # bn_sig (Point, point_size), # point_e_prime (Point, point_size), # point_v_prime (Point, point_size) # point_noninteractive ) else: splitter = BytestringSplitter( (Point, point_size), # point_e (Point, point_size), # point_v (CurveBN, bn_size) # bn_sig ) components = splitter(capsule_bytes) return cls(*components)
def expected_bytes_length(cls, curve: Optional[Curve] = None) -> int: """ Returns the size (in bytes) of a Capsule given the curve. If no curve is provided, it will use the default curve. """ curve = curve if curve is not None else default_curve() bn_size = CurveBN.expected_bytes_length(curve) point_size = Point.expected_bytes_length(curve) return (bn_size * 1) + (point_size * 2)
def expected_bytes_length(cls, curve: ec.EllipticCurve = None): """ Returns the size (in bytes) of a KFrag given the curve. If no curve is provided, it will use the default curve. """ curve = curve if curve is not None else default_curve() bn_size = CurveBN.expected_bytes_length(curve) point_size = Point.expected_bytes_length(curve) return (bn_size * 4) + (point_size * 3)
def expected_bytes_length(cls, curve: Optional[Curve] = None): """ Returns the size (in bytes) of a CorrectnessProof without the metadata. If no curve is given, it will use the default curve. """ curve = curve if curve is not None else default_curve() bn_size = CurveBN.expected_bytes_length(curve=curve) point_size = Point.expected_bytes_length(curve=curve) return (bn_size * 3) + (point_size * 4)
def expected_bytes_length(cls, curve: Optional[EllipticCurve] = None) -> int: """ Returns the size (in bytes) of a CapsuleFrag given the curve without the CorrectnessProof. If no curve is provided, it will use the default curve. """ curve = curve if curve is not None else default_curve() bn_size = CurveBN.expected_bytes_length(curve) point_size = Point.expected_bytes_length(curve) return (bn_size * 1) + (point_size * 4)
def test_serialization_rotations_of_1(curve): size_in_bytes = CurveBN.expected_bytes_length(curve) for i in range(size_in_bytes): lonely_one = 1 << i bn = CurveBN.from_int(lonely_one, curve) lonely_one_in_bytes = lonely_one.to_bytes(size_in_bytes, 'big') # Check serialization assert bn.to_bytes() == lonely_one_in_bytes # Check deserialization assert CurveBN.from_bytes(lonely_one_in_bytes, curve) == bn
def expected_bytes_length(cls, curve: ec.EllipticCurve = None, activated=False): """ Returns the size (in bytes) of a Capsule given the curve. If no curve is provided, it will use the default curve. """ curve = curve if curve is not None else default_curve() bn_size = CurveBN.expected_bytes_length(curve) point_size = Point.expected_bytes_length(curve) if not activated: return (bn_size * 1) + (point_size * 2) else: return (bn_size * 1) + (point_size * 5)
def expected_bytes_length(cls, curve: Optional[Curve] = None) -> int: """ Returns the size (in bytes) of a KFrag given the curve. If no curve is provided, it will use the default curve. """ curve = curve if curve is not None else default_curve() bn_size = CurveBN.expected_bytes_length(curve) point_size = Point.expected_bytes_length(curve) # self.id --> 1 bn_size # self.bn_key --> 1 bn_size # self.point_commitment --> 1 point_size # self.point_precursor --> 1 point_size # self.signature_for_proxy --> 2 bn_size # self.signature_for_bob --> 2 bn_size # self.keys_in_signature --> 1 return bn_size * 6 + point_size * 2 + 1
def from_bytes(cls, data: bytes, curve: ec.EllipticCurve = None): """ Instantiate a KFrag object from the serialized data. """ curve = curve if curve is not None else default_curve() bn_size = CurveBN.expected_bytes_length(curve) point_size = Point.expected_bytes_length(curve) splitter = BytestringSplitter( bn_size, # id (CurveBN, bn_size), # bn_key (Point, point_size), # point_noninteractive (Point, point_size), # point_commitment (Point, point_size), # point_xcoord (Signature, Signature.expected_bytes_length(curve))) components = splitter(data) return cls(*components)
def from_bytes(cls, data: bytes, curve: ec.EllipticCurve = None): """ Instantiate CorrectnessProof from serialized data. """ curve = curve if curve is not None else default_curve() bn_size = CurveBN.expected_bytes_length(curve) point_size = Point.expected_bytes_length(curve) splitter = BytestringSplitter( (Point, point_size), # point_e2 (Point, point_size), # point_v2 (Point, point_size), # point_kfrag_commitment (Point, point_size), # point_kfrag_pok (CurveBN, bn_size), # bn_sig (Signature), # kfrag_signature ) components = splitter(data, return_remainder=True) metadata = components.pop(-1) or None return cls(*components, metadata=metadata)
def from_bytes(cls, data: bytes, curve: Optional[Curve] = None) -> 'CorrectnessProof': """ Instantiate CorrectnessProof from serialized data. """ curve = curve if curve is not None else default_curve() bn_size = CurveBN.expected_bytes_length(curve) point_size = Point.expected_bytes_length(curve) arguments = {'curve': curve} splitter = BytestringSplitter( (Point, point_size, arguments), # point_e2 (Point, point_size, arguments), # point_v2 (Point, point_size, arguments), # point_kfrag_commitment (Point, point_size, arguments), # point_kfrag_pok (CurveBN, bn_size, arguments), # bn_sig (Signature, Signature.expected_bytes_length(curve), arguments), # kfrag_signature ) components = splitter(data, return_remainder=True) components.append(components.pop() or None) return cls(*components)
def from_bytes(cls, data: bytes, curve: ec.EllipticCurve = None): """ Instantiates a CapsuleFrag object from the serialized data. """ curve = curve if curve is not None else default_curve() bn_size = CurveBN.expected_bytes_length(curve) point_size = Point.expected_bytes_length(curve) splitter = BytestringSplitter( (Point, point_size), # point_e1 (Point, point_size), # point_v1 bn_size, # kfrag_id (Point, point_size), # point_noninteractive (Point, point_size) # point_xcoord ) components = splitter(data, return_remainder=True) proof = components.pop(-1) or None proof = CorrectnessProof.from_bytes(proof, curve) if proof else None return cls(*components, proof)
def from_bytes(cls, capsule_bytes: bytes, params: UmbralParameters) -> 'Capsule': """ Instantiates a Capsule object from the serialized data. """ curve = params.curve bn_size = CurveBN.expected_bytes_length(curve) point_size = Point.expected_bytes_length(curve) arguments = {'curve': curve} if len(capsule_bytes) == cls.expected_bytes_length(curve): splitter = BytestringSplitter( (Point, point_size, arguments), # point_e (Point, point_size, arguments), # point_v (CurveBN, bn_size, arguments) # bn_sig ) else: raise ValueError( "Byte string does not have a valid length for a Capsule") components = splitter(capsule_bytes) return cls(params, *components)
def test_invalid_deserialization(curve): size_in_bytes = CurveBN.expected_bytes_length(curve) # All-zeros bytestring are invalid (i.e., 0 < bn < order of the curve) zero_bytes = bytes(size_in_bytes) with pytest.raises(ValueError): _bn = CurveBN.from_bytes(zero_bytes, curve) # All-ones bytestring is invalid too (since it's greater than order) lots_of_ones = 2**(8*size_in_bytes) - 1 lots_of_ones = lots_of_ones.to_bytes(size_in_bytes, 'big') with pytest.raises(ValueError): _bn = CurveBN.from_bytes(lots_of_ones, curve) # Serialization of `order` is invalid since it's not strictly lower than # the order of the curve order = default_backend()._bn_to_int(curve.order) with pytest.raises(ValueError): _bn = CurveBN.from_bytes(order.to_bytes(size_in_bytes, 'big'), curve) # On the other hand, serialization of `order - 1` is valid order -= 1 _bn = CurveBN.from_bytes(order.to_bytes(size_in_bytes, 'big'), curve)
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 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
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