Skip to content

Commit

Permalink
Python bindings
Browse files Browse the repository at this point in the history
  • Loading branch information
dirvine committed Oct 30, 2024
1 parent 8974026 commit 178843c
Show file tree
Hide file tree
Showing 7 changed files with 189 additions and 4 deletions.
89 changes: 89 additions & 0 deletions .github/workflows/python-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
name: Build and Publish Python Package

on:
push:
tags:
- 'v*'

jobs:
macos:
runs-on: macos-latest
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
target: [x86_64, aarch64]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
args: --release --out dist
sccache: 'true'

windows:
runs-on: windows-latest
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
target: [x64]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
architecture: ${{ matrix.target }}
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
args: --release --out dist
sccache: 'true'

linux:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
target: [x86_64, aarch64]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
manylinux: auto
args: --release --out dist
sccache: 'true'

sdist:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build sdist
uses: PyO3/maturin-action@v1
with:
command: sdist
args: --out dist

release:
name: Release
runs-on: ubuntu-latest
needs: [macos, windows, linux, sdist]
steps:
- uses: actions/download-artifact@v3
with:
name: wheels
path: dist
- name: Publish to PyPI
uses: PyO3/maturin-action@v1
env:
MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
with:
command: upload
args: --skip-existing dist/*
9 changes: 9 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ readme = "README.md"
repository = "https://github.com/maidsafe/self_encryption"
version = "0.30.1"

[features]
default = []
python = ["pyo3/extension-module"]

[dependencies]
aes = "~0.8.1"
bincode = "~1.3.3"
Expand All @@ -23,6 +27,7 @@ num_cpus = "1.13.0"
itertools = "~0.10.0"
tempfile = "3.6.0"
xor_name = "5.0.0"
pyo3 = { version = "0.19", optional = true }

[dependencies.brotli]
version = "~3.3.0"
Expand Down Expand Up @@ -64,3 +69,7 @@ name = "basic_encryptor"
[[bench]]
name = "lib"
harness = false

[lib]
name = "self_encryption"
crate-type = ["cdylib", "rlib"]
24 changes: 21 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,27 @@ This library provides very secure encryption of the data, and the returned encry

[Self Encrypting Data](https://docs.maidsafe.net/Whitepapers/pdf/SelfEncryptingData.pdf), David Irvine, First published September 2010, Revised June 2015.

## Examples

### Using `self_encryptor`
# Python

## Installation

```bash
pip install self-encryption
```
'''python
from self_encryption import PyDataMap
## Create a data map and encrypt data
data = b"Hello, World!"
data_map = PyDataMap(data)
## Encrypt some data
encrypted_chunks = data_map.encrypt(data)
## Decrypt the chunks
decrypted = data_map.decrypt(encrypted_chunks)
assert data == decrypted
'''


### Rust - Using `self_encryptor` (Rust)

This library splits a set of bytes into encrypted chunks and also produces a secret key for the same. This secret key allows the file to be reconstituted. Instructions to use the 'basic_encryptor' example are as follows:

Expand Down
18 changes: 18 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[build-system]
requires = ["maturin>=1.0,<2.0"]
build-backend = "maturin"

[project]
name = "self_encryption"
version = "0.1.0"
description = "Python bindings for self-encryption library"
authors = [{name = "David Irvine", email = "[email protected]"}]
requires-python = ">=3.7"
classifiers = [
"Programming Language :: Python :: 3",
"Programming Language :: Rust",
"Operating System :: OS Independent",
]

[tool.maturin]
features = ["python"]
Binary file not shown.
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@
trivial_numeric_casts,
unused_extern_crates,
unused_import_braces,
unused_qualifications,
unused_results
)]
#![allow(
Expand All @@ -98,6 +97,8 @@ mod error;
pub mod test_helpers;
#[cfg(test)]
mod tests;
#[cfg(feature = "python")]
mod python;

use self::encryption::{Iv, Key, Pad, IV_SIZE, KEY_SIZE, PAD_SIZE};
pub use self::{
Expand Down
50 changes: 50 additions & 0 deletions src/python.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use pyo3::prelude::*;
use crate::{encrypt, decrypt_full_set, DataMap, EncryptedChunk};
use bytes::Bytes;

#[pyclass]
struct PyDataMap {
inner: DataMap
}

#[pymethods]
impl PyDataMap {
#[new]
fn new(data: &[u8]) -> PyResult<Self> {
let bytes = Bytes::from(data.to_vec());
let (data_map, _) = encrypt(bytes).map_err(|e| {
PyErr::new::<pyo3::exceptions::PyValueError, _>(format!("Encryption failed: {}", e))
})?;
Ok(PyDataMap { inner: data_map })
}

fn encrypt(mut slf: PyRefMut<'_, Self>, _py: Python<'_>, data: &[u8]) -> PyResult<Vec<Vec<u8>>> {
let bytes = Bytes::from(data.to_vec());
let (data_map, chunks) = encrypt(bytes).map_err(|e| {
PyErr::new::<pyo3::exceptions::PyValueError, _>(format!("Encryption failed: {}", e))
})?;

slf.inner = data_map;

Ok(chunks.into_iter().map(|c| c.content.to_vec()).collect())
}

fn decrypt(slf: PyRef<'_, Self>, _py: Python<'_>, chunks: Vec<Vec<u8>>) -> PyResult<Vec<u8>> {
let encrypted_chunks: Vec<EncryptedChunk> = chunks
.into_iter()
.map(|c| EncryptedChunk { content: Bytes::from(c) })
.collect();

let decrypted = decrypt_full_set(&slf.inner, &encrypted_chunks).map_err(|e| {
PyErr::new::<pyo3::exceptions::PyValueError, _>(format!("Decryption failed: {}", e))
})?;

Ok(decrypted.to_vec())
}
}

#[pymodule]
fn self_encryption(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
m.add_class::<PyDataMap>()?;
Ok(())
}

0 comments on commit 178843c

Please sign in to comment.