<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def sign(check_request):
 """Obtains a signature for an operation in a `CheckRequest` Args: op (:class:`endpoints_management.gen.servicecontrol_v1_messages.Operation`):
 an operation used in a `CheckRequest` Returns: string: a secure hash generated from the operation """

    if not isinstance(check_request, sc_messages.CheckRequest):
        raise ValueError(u'Invalid request')
    op = check_request.operation
    if op is None or op.operationName is None or op.consumerId is None:
        logging.error(u'Bad %s: not initialized => not signed', check_request)
        raise ValueError(u'check request must be initialized with an operation')
    md5 = hashlib.md5()
    md5.update(op.operationName.encode('utf-8'))
    md5.update(b'\x00')
    md5.update(op.consumerId.encode('utf-8'))
    if op.labels:
        signing.add_dict_to_hash(md5, encoding.MessageToPyValue(op.labels))
    for value_set in op.metricValueSets:
        md5.update(b'\x00')
        md5.update(value_set.metricName.encode('utf-8'))
        for mv in value_set.metricValues:
            metric_value.update_hash(md5, mv)

    md5.update(b'\x00')
    if op.quotaProperties:
        # N.B: this differs form cxx implementation, which serializes the
        # protobuf. This should be OK as the exact hash used does not need to
        # match across implementations.
        md5.update(repr(op.quotaProperties).encode('utf-8'))

    md5.update(b'\x00')
    return md5.digest()