Skip to main content

Provides OpenPGP facilities using Sequoia-PGP library

Project description

PySequoia

PyPI version PyPI Downloads CI

This library provides OpenPGP facilities in Python through the Sequoia PGP library. If you need to work with encryption and digital signatures using an IETF standardized protocol, this package is for you!

Note: This is a work in progress. The API is not stable!

Building

set -euxo pipefail
python -m venv .env
source .env/bin/activate
pip install maturin
maturin develop

Installing

PySequoia can be installed through pip:

pip install pysequoia

Note that since pysequoia is implemented largely in Rust, a Rust toolchain is necessary for the installation to succeed.

Testing

This entire document is used for end-to-end integration tests that exercise the package's API surface.

The tests assume that these keys and cards exist:

# generate a key with password
gpg --batch --pinentry-mode loopback --passphrase hunter22 --quick-gen-key passwd@example.com
gpg --batch --pinentry-mode loopback --passphrase hunter22 --export-secret-key passwd@example.com > passwd.pgp

# generate a key without password
gpg --batch --pinentry-mode loopback --passphrase '' --quick-gen-key no-passwd@example.com future-default
gpg --batch --pinentry-mode loopback --passphrase '' --export-secret-key no-passwd@example.com > no-passwd.pgp

# initialize dummy OpenPGP Card
sh /start.sh
echo 12345678 > pin
CARD_ADMIN="opgpcard admin --card 0000:00000000 --admin-pin pin"
$CARD_ADMIN import full-key.asc
$CARD_ADMIN name "John Doe"
$CARD_ADMIN url "https://example.com/key.pgp"
$CARD_ADMIN touch --key SIG --policy Fixed
$CARD_ADMIN touch --key DEC --policy Off
$CARD_ADMIN touch --key AUT --policy Fixed

Functions

All examples assume that these basic classes have been imported:

from pysequoia import Cert

sign

Signs data and returns armored output:

from pysequoia import sign

s = Cert.from_file("signing-key.asc")
signed = sign(s.secrets.signer(), "data to be signed".encode("utf8"))
print(f"Signed data: {signed}")
assert "PGP MESSAGE" in str(signed)

verify

Verifies signed data and returns verified data:

from pysequoia import verify

# sign some data
signing_key = Cert.from_file("signing-key.asc")
signed = sign(s.secrets.signer(), "data to be signed".encode("utf8"))

def get_certs(key_ids):
  # key_ids is an array of required signing keys
  print(f"For verification, we need these keys: {key_ids}")
  return [signing_key]

# verify the data
result = verify(signed, get_certs)
assert result.bytes.decode("utf8") == "data to be signed"

# let's check the valid signature's certificate and signing subkey fingerprints
assert result.valid_sigs[0].certificate == "afcf5405e8f49dbcd5dc548a86375b854b86acf9"
assert result.valid_sigs[0].signing_key == "afcf5405e8f49dbcd5dc548a86375b854b86acf9"

The function that returns certificates (here get_certs) may return more certificates than necessary.

verify succeeds if at least one correct signature has been made by any of the certificates supplied. If you need more advanced policies they can be implemented by inspecting the valid_sigs property.

encrypt

Signs and encrypts a string to one or more recipients:

from pysequoia import encrypt

s = Cert.from_file("passwd.pgp")
r = Cert.from_bytes(open("wiktor.asc", "rb").read())
bytes = "content to encrypt".encode("utf8")
encrypted = encrypt(signer = s.secrets.signer("hunter22"), recipients = [r], bytes = bytes).decode("utf8")
print(f"Encrypted data: {encrypted}")

The signer argument is optional and when omitted the function will return an unsigned (but encrypted) message.

decrypt

Decrypts plain data:

from pysequoia import decrypt

sender = Cert.from_file("no-passwd.pgp")
receiver = Cert.from_file("passwd.pgp")

content = "Red Green Blue"

encrypted = encrypt(recipients = [receiver], bytes = content.encode("utf8"))

decrypted = decrypt(decryptor = receiver.secrets.decryptor("hunter22"), bytes = encrypted)

assert content == decrypted.bytes.decode("utf8");

# this message did not contain any valid signatures
assert len(decrypted.valid_sigs) == 0

Decrypt can also verify signatures while decrypting:

from pysequoia import decrypt

sender = Cert.from_file("no-passwd.pgp")
receiver = Cert.from_file("passwd.pgp")

content = "Red Green Blue"

encrypted = encrypt(signer = sender.secrets.signer(), recipients = [receiver], bytes = content.encode("utf8"))

def get_certs(key_ids):
  print(f"For verification after decryption, we need these keys: {key_ids}")
  return [sender]

decrypted = decrypt(decryptor = receiver.secrets.decryptor("hunter22"), bytes = encrypted, store = get_certs)

assert content == decrypted.bytes.decode("utf8");

# let's check the valid signature's certificate and signing subkey fingerprints
assert decrypted.valid_sigs[0].certificate == sender.fingerprint
assert decrypted.valid_sigs[0].signing_key == sender.fingerprint

Here, the same remarks as to verify also apply.

Certificates

The Cert class represents one OpenPGP certificate (commonly called a "public key").

This package additionally verifies the certificate using Sequoia PGP's StandardPolicy. This means that certificates using weak cryptography can fail to load, or present a different view than in other OpenPGP software (e.g. if a User ID uses SHA-1 in its back-signature, it may be missing from the list of User IDs returned by this package).

Certificates have two forms, one is ASCII armored and one is raw bytes:

cert = Cert.generate("Test <test@example.com>")

print(f"Armored cert: {cert}")
print(f"Bytes of the cert: {cert.bytes()}")

Parsing

Certificates can be parsed from files (Cert.from_file) or bytes in memory (Cert.from_bytes).

cert1 = Cert.generate("Test <test@example.com>")
buffer = cert1.bytes()

parsed_cert = Cert.from_bytes(buffer)
assert str(parsed_cert.user_ids[0]) == "Test <test@example.com>"

They can also be picked from "keyring" files (Cert.split_file) or bytes in memory (Cert.split_bytes) which are collections of binary certificates.

cert1 = Cert.generate("Test 1 <test-1@example.com>")
cert2 = Cert.generate("Test 2 <test-2@example.com>")
cert3 = Cert.generate("Test 3 <test-3@example.com>")

buffer = cert1.bytes() + cert2.bytes() + cert3.bytes()
certs = Cert.split_bytes(buffer)
assert len(certs) == 3

generate

Creates a new general purpose key with a given User ID:

alice = Cert.generate("Alice <alice@example.com>")
fpr = alice.fingerprint
print(f"Generated cert with fingerprint {fpr}:\n{alice}")

Multiple User IDs can be passed as a list to the generate function:

cert = Cert.generate(user_ids = ["First", "Second", "Third"])
assert len(cert.user_ids) == 3

Newly generated certificates are usable in both encryption and signing contexts:

alice = Cert.generate("Alice <alice@example.com>")
bob = Cert.generate("Bob <bob@example.com>")

bytes = "content to encrypt".encode("utf8")

encrypted = encrypt(signer = alice.secrets.signer(), recipients = [bob], bytes = bytes)
print(f"Encrypted data: {encrypted}")

merge

Merges packets from a new version into an old version of a certificate:

old = Cert.from_file("wiktor.asc")
new = Cert.from_file("wiktor-fresh.asc")
merged = old.merge(new)

User IDs

Listing existing User IDs:

cert = Cert.from_file("wiktor.asc")
user_id = cert.user_ids[0]
assert str(user_id).startswith("Wiktor Kwapisiewicz")

Adding new User IDs:

cert = Cert.generate("Alice <alice@example.com>")
assert len(cert.user_ids) == 1;

cert = cert.add_user_id(value = "Alice <alice@company.invalid>", certifier = cert.secrets.certifier())

assert len(cert.user_ids) == 2;

Revoking User IDs:

cert = Cert.generate("Bob <bob@example.com>")

cert = cert.add_user_id(value = "Bob <bob@company.invalid>", certifier = cert.secrets.certifier())
assert len(cert.user_ids) == 2

# create User ID revocation
revocation = cert.revoke_user_id(user_id = cert.user_ids[1], certifier = cert.secrets.certifier())

# merge the revocation with the cert
cert = Cert.from_bytes(cert.bytes() + revocation.bytes())
assert len(cert.user_ids) == 1

Notations

Notations are small pieces of data that can be attached to signatures (and, indirectly, to User IDs).

The following example reads and displays a Keyoxide proof URI:

cert = Cert.from_file("wiktor.asc")
user_id = cert.user_ids[0]
notation = user_id.notations[0]

assert notation.key == "proof@metacode.biz";
assert notation.value == "dns:metacode.biz?type=TXT";

Notations can also be added:

from pysequoia import Notation

cert = Cert.from_file("signing-key.asc")

# No notations initially
assert len(cert.user_ids[0].notations) == 0;

cert = cert.set_notations(cert.secrets.certifier(), [Notation("proof@metacode.biz", "dns:metacode.biz")])

# Has one notation now
print(str(cert.user_ids[0].notations))
assert len(cert.user_ids[0].notations) == 1;

# Check the notation data
notation = cert.user_ids[0].notations[0]

assert notation.key == "proof@metacode.biz";
assert notation.value == "dns:metacode.biz";

Key expiration

Certs have an expiration getter for retrieving the current key expiry time:

cert = Cert.from_file("signing-key.asc")

# Cert does not have any expiration date:
assert cert.expiration is None

cert = Cert.from_file("wiktor.asc")
# Cert expires on New Year's Eve
assert str(cert.expiration) == "2022-12-31 12:00:02+00:00"

Key expiration can also be adjusted with set_expiration:

from datetime import datetime

cert = Cert.from_file("signing-key.asc")

# Cert does not have any expiration date:
assert cert.expiration is None

# Set the expiration to some specified point in time
expiration = datetime.fromisoformat("2021-11-04T00:05:23+00:00")
cert = cert.set_expiration(expiration = expiration, certifier = cert.secrets.certifier())
assert str(cert.expiration) == "2021-11-04 00:05:23+00:00"

Key revocation

Certs can be revoked. While expiration makes the key unusable temporarily to encourage the user to refresh a copy revocation is irreversible.

cert = Cert.generate("Test Revocation <revoke@example.com>")
revocation = cert.revoke(certifier = cert.secrets.certifier())

# creating revocation signature does not revoke the key
assert not cert.is_revoked

# importing revocation signature marks the key as revoked
revoked_cert = Cert.from_bytes(cert.bytes() + revocation.bytes())
assert revoked_cert.is_revoked

Secret keys

Certificates generated through Cert.generate() contain secret keys and can be used for signing and decryption.

To avoid accidental leakage secret keys are never directly printed when the Cert is written to a string. To enable this behavior use Cert.secrets. secrets returns None on certificates which do not contain any secret key material ("public keys").

c = Cert.generate("Testing key <test@example.com>")
assert c.has_secret_keys

# by default only public parts are exported
public_parts = Cert.from_bytes(f"{c}".encode("utf8"))
assert not public_parts.has_secret_keys
assert public_parts.secrets is None

# to export secret parts use the following:
private_parts = Cert.from_bytes(f"{c.secrets}".encode("utf8"))
assert private_parts.has_secret_keys

Signatures

Detached signatures can be read directly from files (Sig.from_file) or bytes in memory (Sig.from_bytes):

from pysequoia import Sig

sig = Sig.from_file("sig.pgp")

print(f"Parsed signature: {repr(sig)}")

assert sig.issuer_fpr == "e8f23996f23218640cb44cbe75cf5ac418b8e74c"
assert sig.created == datetime.fromisoformat("2023-07-19T18:14:01+00:00")

OpenPGP Cards

There's an experimental feature allowing communication with OpenPGP Cards (like YubiKey or Nitrokey).

from pysequoia import Card

# enumerate all cards
all = Card.all()

# open card by card ident
card = Card.open("0000:00000000")

print(f"Card ident: {card.ident}")
assert card.cardholder == "John Doe"
assert card.cert_url == "https://example.com/key.pgp"

Cards provide keys property that can be used to see which keys are imported on the card:

keys = card.keys
print(f"Keys: {keys}")
assert len(keys) == 3

assert keys[0].fingerprint == "ddc3e03c91fb52ca2d95c2444566f2743ed5f382"
assert "sign" in keys[0].usage
assert keys[0].touch_required

assert keys[1].fingerprint == "689e152a7420be13dcaf2c142ac27adc1db9395e"
assert "decrypt" in keys[1].usage
assert not keys[1].touch_required

assert keys[2].fingerprint == "731fbca93ce9821347bf8e696444723371d3c650"
assert "authenticate" in keys[2].usage
assert keys[2].touch_required

Cards can be used for signing data:

signer = card.signer("123456")

signed = sign(signer, "data to be signed".encode("utf8"))
print(f"Signed data: {signed}")

As well as for decryption:

decryptor = card.decryptor("123456")

sender = Cert.from_file("passwd.pgp")
receiver = Cert.from_file("full-key.asc")

content = "Red Green Blue"

encrypted = encrypt(signer = sender.secrets.signer("hunter22"), recipients = [receiver], bytes = content.encode("utf8"))

print(f"Encrypted data: {encrypted}")

decrypted = decrypt(decryptor = decryptor, bytes = encrypted)

assert content == decrypted.bytes.decode("utf8");

Note that while this package allows using cards for signing and decryption, the provisioning process is not supported. OpenPGP card tools can be used to initialize the card.

License

This project is licensed under Apache License, Version 2.0.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the package by you shall be under the terms and conditions of this license, without any additional terms or conditions.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pysequoia-0.1.24.tar.gz (275.7 kB view details)

Uploaded Source

Built Distributions

pysequoia-0.1.24-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.6 MB view details)

Uploaded PyPy manylinux: glibc 2.17+ x86-64

pysequoia-0.1.24-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.6 MB view details)

Uploaded PyPy manylinux: glibc 2.17+ x86-64

pysequoia-0.1.24-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.6 MB view details)

Uploaded PyPy manylinux: glibc 2.17+ x86-64

pysequoia-0.1.24-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.6 MB view details)

Uploaded PyPy manylinux: glibc 2.17+ x86-64

pysequoia-0.1.24-cp312-none-win_amd64.whl (1.4 MB view details)

Uploaded CPython 3.12 Windows x86-64

pysequoia-0.1.24-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.6 MB view details)

Uploaded CPython 3.12 manylinux: glibc 2.17+ x86-64

pysequoia-0.1.24-cp312-cp312-macosx_11_0_arm64.whl (1.7 MB view details)

Uploaded CPython 3.12 macOS 11.0+ ARM64

pysequoia-0.1.24-cp312-cp312-macosx_10_12_x86_64.whl (1.8 MB view details)

Uploaded CPython 3.12 macOS 10.12+ x86-64

pysequoia-0.1.24-cp311-none-win_amd64.whl (1.4 MB view details)

Uploaded CPython 3.11 Windows x86-64

pysequoia-0.1.24-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.6 MB view details)

Uploaded CPython 3.11 manylinux: glibc 2.17+ x86-64

pysequoia-0.1.24-cp311-cp311-macosx_11_0_arm64.whl (1.7 MB view details)

Uploaded CPython 3.11 macOS 11.0+ ARM64

pysequoia-0.1.24-cp311-cp311-macosx_10_12_x86_64.whl (1.8 MB view details)

Uploaded CPython 3.11 macOS 10.12+ x86-64

pysequoia-0.1.24-cp310-none-win_amd64.whl (1.4 MB view details)

Uploaded CPython 3.10 Windows x86-64

pysequoia-0.1.24-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.6 MB view details)

Uploaded CPython 3.10 manylinux: glibc 2.17+ x86-64

pysequoia-0.1.24-cp310-cp310-macosx_11_0_arm64.whl (1.7 MB view details)

Uploaded CPython 3.10 macOS 11.0+ ARM64

pysequoia-0.1.24-cp310-cp310-macosx_10_12_x86_64.whl (1.8 MB view details)

Uploaded CPython 3.10 macOS 10.12+ x86-64

pysequoia-0.1.24-cp39-none-win_amd64.whl (1.4 MB view details)

Uploaded CPython 3.9 Windows x86-64

pysequoia-0.1.24-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.6 MB view details)

Uploaded CPython 3.9 manylinux: glibc 2.17+ x86-64

pysequoia-0.1.24-cp38-none-win_amd64.whl (1.4 MB view details)

Uploaded CPython 3.8 Windows x86-64

pysequoia-0.1.24-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.6 MB view details)

Uploaded CPython 3.8 manylinux: glibc 2.17+ x86-64

pysequoia-0.1.24-cp37-none-win_amd64.whl (1.4 MB view details)

Uploaded CPython 3.7 Windows x86-64

pysequoia-0.1.24-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.6 MB view details)

Uploaded CPython 3.7m manylinux: glibc 2.17+ x86-64

File details

Details for the file pysequoia-0.1.24.tar.gz.

File metadata

  • Download URL: pysequoia-0.1.24.tar.gz
  • Upload date:
  • Size: 275.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: maturin/1.5.1

File hashes

Hashes for pysequoia-0.1.24.tar.gz
Algorithm Hash digest
SHA256 b0b18f572515875331009cfcf77df1180c5a23dfb42ff0fac158b2e4044b7b8e
MD5 74df8efbfaeb44a9dc84680bf70b5e4e
BLAKE2b-256 f4489f578fb84d784b88c3a13edb0bcdaa1dab9f5caffea6f17f5f809eeea272

See more details on using hashes here.

File details

Details for the file pysequoia-0.1.24-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pysequoia-0.1.24-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 df945f762ce8541fa6dcc6afcf1df80a2daa22f51610f177fe16d81b3d76631e
MD5 1f6c97e23459e422c87e562ebb3c00fa
BLAKE2b-256 d2490f7f419246fdd3055dd9acc3a5385cd533fd04a71981965d4d522b715134

See more details on using hashes here.

File details

Details for the file pysequoia-0.1.24-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pysequoia-0.1.24-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 f4e7ab1af7a4a0d92f4ac7634fc68cd17d64c934b412f374eb6fa8484d72bcfa
MD5 ef719dc1244bd4d381c5c54d41a7a85a
BLAKE2b-256 e63310bf80f14e503967ec1388cda1b86329f897a509b2aa6b35a16fa8b0a4f3

See more details on using hashes here.

File details

Details for the file pysequoia-0.1.24-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pysequoia-0.1.24-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 7d7cb24b4aacce92bed135f72d61c1027ead34c56bd7bcf460474741fbc2cd3d
MD5 6a722f35a21e2794430af57bb3ba37ec
BLAKE2b-256 01d2938638799348ccbaf70459e8cd85167b09f093fb79611c9d38d5a9324697

See more details on using hashes here.

File details

Details for the file pysequoia-0.1.24-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pysequoia-0.1.24-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 23fe45ab006237794d3bab9beffa506b8a7c4193c707df297369e78dd13d8c96
MD5 5607df25e0585e0b6e820391c845d64c
BLAKE2b-256 4835f1c6e2caf037cd3ae83ffd408493988f224cf634a059ad892c7e1059af0d

See more details on using hashes here.

File details

Details for the file pysequoia-0.1.24-cp312-none-win_amd64.whl.

File metadata

File hashes

Hashes for pysequoia-0.1.24-cp312-none-win_amd64.whl
Algorithm Hash digest
SHA256 2920c06471097b4b81c2c7bfd4ac3dff4c66c7f1276625e53a338bb1f8698e16
MD5 706c8e49ad4053ba62092c9fe522ac08
BLAKE2b-256 5941b379d47c2e18ebc56bd05f74aed6bb72ddf56fe9f50d259dece8f7c9cb5e

See more details on using hashes here.

File details

Details for the file pysequoia-0.1.24-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pysequoia-0.1.24-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 0cf987235a38e59490a8e69f9adc618b31dac34cb1bacd4f51ffc0ff80e6206e
MD5 67c08e44db9c5e59bff190624715f8e4
BLAKE2b-256 0ced49770432466227fdd7579fccb88e741db568904907a372c484430810ce37

See more details on using hashes here.

File details

Details for the file pysequoia-0.1.24-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for pysequoia-0.1.24-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 399cdd8df3761eb2c68d9b3d741cfb6530e48078a8d84ad3366bbd670975fb69
MD5 fa1132b19bdb2d6e37a3d564ced8e215
BLAKE2b-256 b9148786e42fdd754f7ff3b493583ea64297186b9fdb5a3af91d1afad770d70a

See more details on using hashes here.

File details

Details for the file pysequoia-0.1.24-cp312-cp312-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for pysequoia-0.1.24-cp312-cp312-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 358473ed5ff8602b9b6daf0653bdf92610ba989b9b4d4f9f40a512798044785c
MD5 5e93b6181e49a6fa9067ce0c62009dc8
BLAKE2b-256 c5f5c948f4677a0b14e67f177930a10a9b1c9bafecc155079beba8489ef9cea1

See more details on using hashes here.

File details

Details for the file pysequoia-0.1.24-cp311-none-win_amd64.whl.

File metadata

File hashes

Hashes for pysequoia-0.1.24-cp311-none-win_amd64.whl
Algorithm Hash digest
SHA256 574db1f7474550035963e3cd1398325c587df257cec57589bdefaeeb971a18d4
MD5 afefa52474833d7778f571224c2e2753
BLAKE2b-256 1de933207b82b1a0a12803f23fe0fe6764ca78cd608ab9ead8332228cfcfa3b2

See more details on using hashes here.

File details

Details for the file pysequoia-0.1.24-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pysequoia-0.1.24-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 7500cc92a5ec309230c43e9da8e25d3932f82d4338d70d607d1d3f0597b450e8
MD5 74e183546f1d66dadbe0a208962d480e
BLAKE2b-256 0635b988c86bfea65f2a8f37bfac954735d83a215b312b70ddd0ea8cfae753f6

See more details on using hashes here.

File details

Details for the file pysequoia-0.1.24-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for pysequoia-0.1.24-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 c70224872b5cd4912081fb994129c9767fe5768d99bdfe3a37e275e241ecfe12
MD5 50732e3db318f3ef2fd5a966ce109262
BLAKE2b-256 79a516ff4b23b5cf12770713f25d5d951424136a1e7f4e1cd614f8d095556804

See more details on using hashes here.

File details

Details for the file pysequoia-0.1.24-cp311-cp311-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for pysequoia-0.1.24-cp311-cp311-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 71cb2e3ec5169b3d41b0d8219c29912f699043c60dee4d2dd99e16ba418bd493
MD5 f1051aa1a268ac3a42c8507e1f572e3e
BLAKE2b-256 dc966fbf03d7745fb05dbeefe5bea6ac2e19ed0818d0b5ebff46742d59a0a213

See more details on using hashes here.

File details

Details for the file pysequoia-0.1.24-cp310-none-win_amd64.whl.

File metadata

File hashes

Hashes for pysequoia-0.1.24-cp310-none-win_amd64.whl
Algorithm Hash digest
SHA256 307169078ccb4f256f8243f6852b2dbb536c5b7f99dddf135d6d18c04f3cccb9
MD5 f89ce7fe0657709674f10542731544d2
BLAKE2b-256 eaca48db6dc3e52ac5d0eadf401ec973046ed21b6ed269eeb543c2adc1f674ec

See more details on using hashes here.

File details

Details for the file pysequoia-0.1.24-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pysequoia-0.1.24-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 0c1be5372bec9dbb7bc625d1a618e8528118f1fae4da0d93958dcaf36d86e824
MD5 10499fdb29fe1bc6d94e361126ade563
BLAKE2b-256 6c6528a2b4e7a876794faacdaa9baccb03043aa059925920d124b725ceaa4a7e

See more details on using hashes here.

File details

Details for the file pysequoia-0.1.24-cp310-cp310-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for pysequoia-0.1.24-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 cc5d2e0613e79ad2535cb4e929b82500e6ba54a1d7764e4cb52920cdeae7cad3
MD5 16c4bd5a050d5d0e8d5011b6af79f128
BLAKE2b-256 e806054ab2d9b542eb9ec51ceb37fd3cb03bddb98ffae4b12e6f1e427bebc703

See more details on using hashes here.

File details

Details for the file pysequoia-0.1.24-cp310-cp310-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for pysequoia-0.1.24-cp310-cp310-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 4301e081aaa67a39c15acc8cc4692267a24f4001363dca40dc30c0d219a1053b
MD5 a6a1c78806a9cfd6420fd0dac7f1d017
BLAKE2b-256 d7ef968d3aeb571f59a3592dbb5d2f0ed8b42198b2139420418d001234ddad9c

See more details on using hashes here.

File details

Details for the file pysequoia-0.1.24-cp39-none-win_amd64.whl.

File metadata

File hashes

Hashes for pysequoia-0.1.24-cp39-none-win_amd64.whl
Algorithm Hash digest
SHA256 23b25b11bac9112234127ac70b5546907d69c2b7f912d830118e67a43fc5e26c
MD5 0fa338a42b5c48ca86a5f23d3bb246d1
BLAKE2b-256 34f87106b0e1ce1629cd75aed3dea59cf4c06e5626324aceae4e866207de6e1a

See more details on using hashes here.

File details

Details for the file pysequoia-0.1.24-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pysequoia-0.1.24-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 375436a329c5fbc8f14c0291d00316dd9ea6d5fd5b4d79584621fa060558a147
MD5 654f840389d07bb11b3e6e92b9c3e6ba
BLAKE2b-256 a4c3119f594574556b63148e18c5a08524e1c0645336ea097a0f30d7f0fbc170

See more details on using hashes here.

File details

Details for the file pysequoia-0.1.24-cp38-none-win_amd64.whl.

File metadata

File hashes

Hashes for pysequoia-0.1.24-cp38-none-win_amd64.whl
Algorithm Hash digest
SHA256 7884c1838d99314d3b09c294918979e87e8031793aea3c31445943e5bab4e9e0
MD5 2c093899996d666baaa4cfc5bd644c6e
BLAKE2b-256 569921cca06bc61782a6d29c25e7e5616104b4a8f7587c5a50ab7d27512de18d

See more details on using hashes here.

File details

Details for the file pysequoia-0.1.24-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pysequoia-0.1.24-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 a10272331f522ed4900213a53a07e7a84d777ca932c2391388032ab2eb00dbe3
MD5 d42d0f960cb5449b5b8ed0dde8367848
BLAKE2b-256 0a4ff555d2f3d1db8e5263fa85e9f4fa480863f12ad9265c55bc67daec6a143b

See more details on using hashes here.

File details

Details for the file pysequoia-0.1.24-cp37-none-win_amd64.whl.

File metadata

File hashes

Hashes for pysequoia-0.1.24-cp37-none-win_amd64.whl
Algorithm Hash digest
SHA256 0e698d00bb0fe07f574e10305eab587fa7341ce7b87a8f20190a511aad24fc15
MD5 d47e6f20b1d1a0061bc3cb9e907e442b
BLAKE2b-256 516bdd406bfb3ac5a74fbb2e97550f4840e16a1982c904a7ba4012a74a6a06ca

See more details on using hashes here.

File details

Details for the file pysequoia-0.1.24-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pysequoia-0.1.24-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 111cfb5503824f62b113d316a385c5f8b8ad6ad2a75ac81f5a7ecf4ca8e2f39b
MD5 828706db0d5fe5a66edd6283c2c12942
BLAKE2b-256 b091dd076272473f682177bf8ff9e4f2146caf6445e6206d17eaff60ad663a46

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page