Skip to content

bovine.crypto.helper

content_digest_sha256

content_digest_sha256(
    content: str | bytes, prefix: str = "sha-256"
) -> str

Computes the SHA256 digest of given content

>>> content_digest_sha256(b"moo")
'sha-256=R9+ukoir89XSJSq/sL1qyWYmN9ZG5t+dXSdLwzbierw='

>>> content_digest_sha256(b"moo", prefix="SHA-256")
'SHA-256=R9+ukoir89XSJSq/sL1qyWYmN9ZG5t+dXSdLwzbierw='

Parameters:

Name Type Description Default
content str | bytes

Content to be encoded

required
prefix str

Prefix to use should be either “SHA-256” or “sha-256” depending on taste

'sha-256'
Source code in bovine/bovine/crypto/helper.py
def content_digest_sha256(content: str | bytes, prefix: str = "sha-256") -> str:
    """Computes the SHA256 digest of given content

    ```pycon
    >>> content_digest_sha256(b"moo")
    'sha-256=R9+ukoir89XSJSq/sL1qyWYmN9ZG5t+dXSdLwzbierw='

    >>> content_digest_sha256(b"moo", prefix="SHA-256")
    'SHA-256=R9+ukoir89XSJSq/sL1qyWYmN9ZG5t+dXSdLwzbierw='

    ```

    :param content: Content to be encoded
    :param prefix: Prefix to use should be either "SHA-256" or "sha-256" depending on taste
    """
    if isinstance(content, str):
        content = content.encode("utf-8")

    digest = base64.standard_b64encode(hashlib.sha256(content).digest()).decode("utf-8")
    return "=".join([prefix, digest])

content_digest_sha256_rfc_9530

content_digest_sha256_rfc_9530(
    content: bytes,
) -> Tuple[str, str]

Computes the content digest according to RFC 9530

>>> content_digest_sha256_rfc_9530(b'{"hello": "world"}\n')
('content-digest', 'sha-256=:RK/0qy18MlBSVnWgjwz6lZEWjP/lF5HF9bvEF8FabDg=:')

Parameters:

Name Type Description Default
content bytes

Usually the request body to compute the digest from

required

Returns:

Type Description
Tuple[str, str]

Tuple of header name, header value

Source code in bovine/bovine/crypto/helper.py
def content_digest_sha256_rfc_9530(content: bytes) -> Tuple[str, str]:
    """Computes the content digest according to [RFC 9530](https://www.rfc-editor.org/authors/rfc9530.html)

    ```pycon
    >>> content_digest_sha256_rfc_9530(b'{"hello": "world"}\\n')
    ('content-digest', 'sha-256=:RK/0qy18MlBSVnWgjwz6lZEWjP/lF5HF9bvEF8FabDg=:')

    ```

    :param content: Usually the request body to compute the digest from
    :return: Tuple of header name, header value"""
    return "content-digest", ser({"sha-256": hashlib.sha256(content).digest()})

did_key_to_public_key

did_key_to_public_key(did: str) -> Ed25519PublicKey

Transform a did key to a public key

>>> did = "did:key:z6MkekwC6R9bj9ErToB7AiZJfyCSDhaZe1UxhDbCqJrhqpS5"
>>> did_key_to_public_key(did)
<cryptography.hazmat.bindings._rust.openssl.ed25519.Ed25519PublicKey object at ...>
Source code in bovine/bovine/crypto/helper.py
def did_key_to_public_key(did: str) -> ed25519.Ed25519PublicKey:
    """Transform a did key to a public key

    ```pycon
    >>> did = "did:key:z6MkekwC6R9bj9ErToB7AiZJfyCSDhaZe1UxhDbCqJrhqpS5"
    >>> did_key_to_public_key(did)
    <cryptography.hazmat.bindings._rust.openssl.ed25519.Ed25519PublicKey object at ...>

    ```
    """
    scheme, _, path, _, _ = urlsplit(did)
    if scheme != "did":
        raise ValueError(f"Scheme should be did, got {scheme}, for {did}")
    if not path.startswith("key:"):
        raise ValueError(f"Path should start with key:, got {path}, for {did}")
    return decode_multibase_public_key(path[4:])

ensure_data_integrity_context

ensure_data_integrity_context(doc: dict) -> dict

Performs context injection according to Verifiable Credentials: Data Integrity. The data integrity context being added is https://w3id.org/security/data-integrity/v2.

Parameters:

Name Type Description Default
doc dict

Document

required

Returns:

Type Description
dict

The same document with the data integrity context added.

Source code in bovine/bovine/crypto/helper.py
def ensure_data_integrity_context(doc: dict) -> dict:
    """Performs context injection according to
    [Verifiable Credentials: Data Integrity](https://w3c.github.io/vc-data-integrity/#context-injection). The data integrity
    context being added is `https://w3id.org/security/data-integrity/v2`.

    :param doc: Document
    :return: The same document with the data integrity context added.
    """
    integrity_context = "https://w3id.org/security/data-integrity/v2"
    alternate_context = "https://w3id.org/security/data-integrity/v1"
    context = doc.get("@context")
    if context is None:
        return {"@context": integrity_context, **doc}
    if isinstance(context, str):
        context: list = [context]
    if integrity_context in context or alternate_context in context:
        return doc
    return jsonld.compact(doc, context + [integrity_context])

jcs_sha256

jcs_sha256(doc: dict, context: dict | None = None) -> bytes

Returns the sha256 digest of the representation of dict according to JCS. This assumes that doc is JSON serializable.

JCS is defined in RFC8785.

Parameters:

Name Type Description Default
doc dict

The document

required
context dict | None

ignored used in rdfc_sha256

None
Source code in bovine/bovine/crypto/helper.py
def jcs_sha256(doc: dict, context: dict | None = None) -> bytes:
    """Returns the sha256 digest of the representation
    of dict according to JCS. This assumes that `doc`
    is JSON serializable.

    JCS is defined in [RFC8785](https://www.rfc-editor.org/rfc/rfc8785).

    :param doc: The document
    :param context: ignored used in [rdfc_sha256][bovine.crypto.helper.rdfc_sha256]
    """
    return hashlib.sha256(jcs.canonicalize(doc)).digest()

jcs_sha384

jcs_sha384(doc: dict, context: dict | None = None) -> bytes

Returns the sha384 digest of the representation of dict according to JCS. This assumes that doc is JSON serializable.

JCS is defined in RFC8785.

Parameters:

Name Type Description Default
doc dict

The document

required
context dict | None

ignored used in rdfc_sha256

None
Source code in bovine/bovine/crypto/helper.py
def jcs_sha384(doc: dict, context: dict | None = None) -> bytes:
    """Returns the sha384 digest of the representation
    of dict according to JCS. This assumes that `doc`
    is JSON serializable.

    JCS is defined in [RFC8785](https://www.rfc-editor.org/rfc/rfc8785).

    :param doc: The document
    :param context: ignored used in [rdfc_sha256][bovine.crypto.helper.rdfc_sha256]
    """
    return hashlib.sha384(jcs.canonicalize(doc)).digest()

public_key_to_did_key

public_key_to_did_key(
    public_key: Union[
        Ed25519PublicKey,
        RSAPublicKey,
        EllipticCurvePublicKey,
    ],
) -> str

Converts a public key to a did:key.

Parameters:

Name Type Description Default
public_key Union[Ed25519PublicKey, RSAPublicKey, EllipticCurvePublicKey]

The public key

required
Source code in bovine/bovine/crypto/helper.py
def public_key_to_did_key(
    public_key: Union[
        ed25519.Ed25519PublicKey, rsa.RSAPublicKey, ec.EllipticCurvePublicKey
    ],
) -> str:
    """Converts a public key to a [did:key](https://w3c-ccg.github.io/did-method-key/).

    :param public_key: The public key
    """
    return urlunsplit(
        ("did", "", "key:" + encode_public_key_to_multibase(public_key), "", "")
    )

rdfc_sha256

rdfc_sha256(doc: dict, context: dict = {}) -> bytes

Returns the sha256 digest of the representation of dict according to RDF-Canon

The algorithm used is URDNA2015 and the result are n-quads.

Parameters:

Name Type Description Default
doc dict

The document

required
context dict

If doc has no @context property, it is set to this parameter

{}
Source code in bovine/bovine/crypto/helper.py
def rdfc_sha256(doc: dict, context: dict = {}) -> bytes:
    """Returns the sha256 digest of the representation
    of dict according to [RDF-Canon](https://www.w3.org/TR/rdf-canon/)

    The algorithm used is URDNA2015 and the result are n-quads.

    :param doc: The document
    :param context: If doc has no `@context` property, it is set to this parameter
    """
    if "@context" not in doc:
        doc["@context"] = context

    normalized = jsonld.normalize(
        doc, {"algorithm": "URDNA2015", "format": "application/n-quads"}
    )
    return hashlib.sha256(normalized.encode("utf-8")).digest()

rdfc_sha384

rdfc_sha384(doc: dict, context: dict = {}) -> bytes

Returns the sha384 digest of the representation of dict according to RDF-Canon

The algorithm used is URDNA2015 and the result are n-quads.

Parameters:

Name Type Description Default
doc dict

The document

required
context dict

If doc has no @context property, it is set to this parameter

{}
Source code in bovine/bovine/crypto/helper.py
def rdfc_sha384(doc: dict, context: dict = {}) -> bytes:
    """Returns the sha384 digest of the representation
    of dict according to [RDF-Canon](https://www.w3.org/TR/rdf-canon/)

    The algorithm used is URDNA2015 and the result are n-quads.

    :param doc: The document
    :param context: If doc has no `@context` property, it is set to this parameter
    """
    if "@context" not in doc:
        doc["@context"] = context

    normalized = jsonld.normalize(
        doc, {"algorithm": "URDNA2015", "format": "application/n-quads"}
    )
    logger.debug(normalized)
    return hashlib.sha384(normalized.encode("utf-8")).digest()