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

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}")

decrypt

Decrypts data:

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"))

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

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

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 Store, verify

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

# verify the data
store = Store("/tmp/store")
store.put(signing_key)

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

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)
print(f"Merged, updated cert: {merged}")

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

Certificate management

CertD integration

This library exposes OpenPGP Certificate Directory integration, which allows storing and retrieving OpenPGP certificates in a persistent way directly in the file system.

Note that this will not allow you to read GnuPG-specific key directories. Cert-D does not allow certificate removal.

from pysequoia import Store

cert = Cert.from_file("wiktor.asc")
s = Store("/tmp/store")
s.put(cert)
assert s.get(cert.fingerprint) != None

The certificate is now stored in the given directory and can be retrieved later by its fingerprint:

s = Store("/tmp/store")
assert s.get("653909a2f0e37c106f5faf546c8857e0d8e8f074") != None

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.

Sponsors

My work was supported by these generous organizations (alphabetical order):

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.22.tar.gz (273.5 kB view details)

Uploaded Source

Built Distributions

pysequoia-0.1.22-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.8 MB view details)

Uploaded PyPy manylinux: glibc 2.17+ x86-64

pysequoia-0.1.22-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.8 MB view details)

Uploaded PyPy manylinux: glibc 2.17+ x86-64

pysequoia-0.1.22-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.8 MB view details)

Uploaded PyPy manylinux: glibc 2.17+ x86-64

pysequoia-0.1.22-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.8 MB view details)

Uploaded PyPy manylinux: glibc 2.17+ x86-64

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

Uploaded CPython 3.12 Windows x86-64

pysequoia-0.1.22-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.8 MB view details)

Uploaded CPython 3.12 manylinux: glibc 2.17+ x86-64

pysequoia-0.1.22-cp312-cp312-macosx_11_0_arm64.whl (1.8 MB view details)

Uploaded CPython 3.12 macOS 11.0+ ARM64

pysequoia-0.1.22-cp312-cp312-macosx_10_7_x86_64.whl (1.9 MB view details)

Uploaded CPython 3.12 macOS 10.7+ x86-64

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

Uploaded CPython 3.11 Windows x86-64

pysequoia-0.1.22-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.8 MB view details)

Uploaded CPython 3.11 manylinux: glibc 2.17+ x86-64

pysequoia-0.1.22-cp311-cp311-macosx_11_0_arm64.whl (1.8 MB view details)

Uploaded CPython 3.11 macOS 11.0+ ARM64

pysequoia-0.1.22-cp311-cp311-macosx_10_7_x86_64.whl (1.9 MB view details)

Uploaded CPython 3.11 macOS 10.7+ x86-64

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

Uploaded CPython 3.10 Windows x86-64

pysequoia-0.1.22-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.8 MB view details)

Uploaded CPython 3.10 manylinux: glibc 2.17+ x86-64

pysequoia-0.1.22-cp310-cp310-macosx_11_0_arm64.whl (1.8 MB view details)

Uploaded CPython 3.10 macOS 11.0+ ARM64

pysequoia-0.1.22-cp310-cp310-macosx_10_7_x86_64.whl (1.9 MB view details)

Uploaded CPython 3.10 macOS 10.7+ x86-64

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

Uploaded CPython 3.9 Windows x86-64

pysequoia-0.1.22-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.8 MB view details)

Uploaded CPython 3.9 manylinux: glibc 2.17+ x86-64

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

Uploaded CPython 3.8 Windows x86-64

pysequoia-0.1.22-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.8 MB view details)

Uploaded CPython 3.8 manylinux: glibc 2.17+ x86-64

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

Uploaded CPython 3.7 Windows x86-64

pysequoia-0.1.22-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.8 MB view details)

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

File details

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

File metadata

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

File hashes

Hashes for pysequoia-0.1.22.tar.gz
Algorithm Hash digest
SHA256 d5d2c0b10d00374ccbb2bf5234c5416994db0f97f13d10ec48e221ff713a46d7
MD5 e8efeb29529c0e3b8e98ca15d2fe6b3a
BLAKE2b-256 8da4b3869f04579c601470c3fbb156dbb0b97bcf4894d591e8f82a8780c317bf

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pysequoia-0.1.22-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 da1166402e97971642ee06b9dd8cb19184b12aadf794a6edd643678f498c5008
MD5 58e7d78d11109d06aef6d14727501902
BLAKE2b-256 57975f1a94f6e83f5b2f84ebc658fb70345501fcddb6510d91f2f72a88b8d4b6

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pysequoia-0.1.22-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 416a221fc34e58ed669b2a5e157104252d676a94c404318593197310e9e1cd51
MD5 b762bb66918a9443d1086fe92a0d5324
BLAKE2b-256 347815e0c172f2fee16fac8e7cfd47e4141381dc78e617d81fb948c150430348

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pysequoia-0.1.22-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 b4f432c95a7c0f184ff5525922dc02e98a02d856a9f026960cfb1a7bde56c5f6
MD5 a1683becf09cf9b9c17f9eaaa0523780
BLAKE2b-256 4bf149fc6a97b034e330e66b9be69a166ab204dafbf09aaa43eb12b567bddf50

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pysequoia-0.1.22-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 69af86af71a9787200387facdb40010f6411bd2f30f7f3ee6272874510e28c39
MD5 673d2a978c38b5739d4d4f2d6bd09543
BLAKE2b-256 b07703d1f5d99e6078aa714158d97007460b6f0cee54df8d4445134724310685

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pysequoia-0.1.22-cp312-none-win_amd64.whl
Algorithm Hash digest
SHA256 588ccd302a0c9d06285d262d1fc4679dfb918e0e9b1b800bf7e344009f061123
MD5 4a21fcb979992762335496e21c2ea217
BLAKE2b-256 df230a665b5b28b4098f206fc6083ae7cf314727bd98bc2671d4a1fc9050601e

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pysequoia-0.1.22-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 1b91610f0c3389fa43dfd5681af101a8f4572decf9fbc3529a4c8255f397ba20
MD5 0ff30ebe652576f3c1b37fc299d3c9d2
BLAKE2b-256 f43efaeba4cd0d16baf35c24efe6c3fc60447b613ccd55d31d64d9063e164848

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pysequoia-0.1.22-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 c7ab67c01feb3e4be0b83c8fb2cc8d555a905cd56a499f9114ba2650335a3308
MD5 1cd401483cc8cf8e4036e146357fcfa5
BLAKE2b-256 8f42d49412dffdb9e460a0af79ce75c31c20aa4972a63487497a774da6b987e6

See more details on using hashes here.

File details

Details for the file pysequoia-0.1.22-cp312-cp312-macosx_10_7_x86_64.whl.

File metadata

File hashes

Hashes for pysequoia-0.1.22-cp312-cp312-macosx_10_7_x86_64.whl
Algorithm Hash digest
SHA256 8bc751b7e6e0bb2c0c2069bb5643ea7e65de90dbf7a54af94c43bbc00e7a4076
MD5 e9cd63b205db8879d316dcd803949688
BLAKE2b-256 950a5051a584b952e3e69dada52427489201de89e3f364e2fe4098234397c706

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pysequoia-0.1.22-cp311-none-win_amd64.whl
Algorithm Hash digest
SHA256 44b2a2b67ae9021c5a276f15e263fef635c167d7fd70ef5d52f0ff5cf7b280bb
MD5 9f6f3e81b2093b24ecc2c070179ca726
BLAKE2b-256 01fc861ade2a4220b5b7abdff1a97b3a861388ca3e2727ae004b88cd3086db94

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pysequoia-0.1.22-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 800febff9e347f8e7e4028288c030cfb65327ff5ce611fc49012d8446b703b89
MD5 26c3e18a9de5c48e5a15943e134a0ef8
BLAKE2b-256 cef2bb50f91ea44d482ed33943a9ff37f97226faaf41e4167aeb1f4e699cbd1a

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pysequoia-0.1.22-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 259d4770ea43d62569f0797ba68e5d2c7813ae5717401f1ed8a6c083dfd79860
MD5 5bfdc00892ec9b7c50f24fc69f2ebc48
BLAKE2b-256 4cc0f461d7a96e0379754d97f9fadbf4908d60d5bd440622fce9f0042cd8c60a

See more details on using hashes here.

File details

Details for the file pysequoia-0.1.22-cp311-cp311-macosx_10_7_x86_64.whl.

File metadata

File hashes

Hashes for pysequoia-0.1.22-cp311-cp311-macosx_10_7_x86_64.whl
Algorithm Hash digest
SHA256 d856b24945dc0611cd87510831cf37965d42caae948655a5f7217e7dcdadf74c
MD5 26e72418452c88c478b0022ef57456b5
BLAKE2b-256 56ff923a464286183099e1458a8d41d3224a5eaba9a924ba94590d3ec780f846

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pysequoia-0.1.22-cp310-none-win_amd64.whl
Algorithm Hash digest
SHA256 4a4bc96d59fb4f68c7f2e30921d9089882acec99b6c56a91cf6b5648e7a614ef
MD5 45d7d6565da1f8857b2c4d9126b5b9fb
BLAKE2b-256 db4b9efa4d8d13e87aed07bbfa906497e329a4335e69b4901d4211ba5591f526

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pysequoia-0.1.22-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 6804f78c328eb7aeab6b9b488ac198f953f46f80ba54d5a0c2d8e2afca45b12b
MD5 872a28494653c7ace95fe21dc2d5e48c
BLAKE2b-256 9f181bf0234992512ef93338b2ff61104ab32820f3f4861e4e59eb76317b0b60

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pysequoia-0.1.22-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 4fe322fe188907a5ddf236be4a664d8ed1ca588215dfc41d94cdeb9f4f0eee43
MD5 5172aa9474be49650c3eb5ad7f9fbde1
BLAKE2b-256 4f1d557e30b90d0bdc30e61fe00512f9d1f14489ef7f5ad00d52c43e546ffd29

See more details on using hashes here.

File details

Details for the file pysequoia-0.1.22-cp310-cp310-macosx_10_7_x86_64.whl.

File metadata

File hashes

Hashes for pysequoia-0.1.22-cp310-cp310-macosx_10_7_x86_64.whl
Algorithm Hash digest
SHA256 287af5f0db6635ed429ede3b9361211b71f8acef1439ad2312cc5db71b35d5d6
MD5 8caa74120df126c4bec7ba994f69e714
BLAKE2b-256 daac37176d769c540bec1b48c261e665218d641e7fe5923c9f2e2b2b455294c9

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pysequoia-0.1.22-cp39-none-win_amd64.whl
Algorithm Hash digest
SHA256 909c7f471897cf031a9d3e8082dfeeb0d630468781c5be571bf6c07996fed4d6
MD5 3689f5a9483a336ad3538f29bbe20208
BLAKE2b-256 3ea3237ad26b89894403d550c58d3056e8bd0209b034c776da43e7cc39c53416

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pysequoia-0.1.22-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 77e22e5dba1effa17ff7bdffedd79cad2b415590b008bbcb9818f2c343591c36
MD5 d4801693b01cf6fd797912d5bb6e592c
BLAKE2b-256 3f76e9bb6ce0299f1d147a85c5470bd68da46e3d653dff090a628f17b6c949e4

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pysequoia-0.1.22-cp38-none-win_amd64.whl
Algorithm Hash digest
SHA256 438b10d443aa8c3054e1272fb314019dacc52def19231c44c5b11644fc18b1bb
MD5 84eb180a2c6e210bac55defe2653da38
BLAKE2b-256 29bcdded0572ee4d73fed03e3d09263251104851f0c2bc09ccc15321ec25cd8a

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pysequoia-0.1.22-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 1c0cbbe5df4df025abd228e6cc4c2c5d45cf23d2352ad6c0a9d91ac276cf7b8d
MD5 df08dcc84b6d8a072392183399334f2c
BLAKE2b-256 56d1ffa99e9864590dfe211b3fe5687399c42633921484164356d917d1f6e63a

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pysequoia-0.1.22-cp37-none-win_amd64.whl
Algorithm Hash digest
SHA256 911e2eb00b77f90e417039832b260d66c78c02a05896889d6ac53891141e4d75
MD5 999783beeff4ce89ea63357f885a8a20
BLAKE2b-256 c48711d1f4571592a80d742d7675bdeeef7d9c1bace5db3cd7315c12f6e5874f

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pysequoia-0.1.22-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 277354f4f822ac76de6173b5ba878ccebe122b54ad68fd4618714165c1f6b1b3
MD5 c61926215409d2985130f3e0b56b1784
BLAKE2b-256 78b7392bd4a050cbf52b432a03a9321d3f4b54f4b80b5690d07f56393acc19c0

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