Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce threshold decryption request/response and node metadata ferveo public key #48

Merged
merged 13 commits into from
May 2, 2023
4 changes: 2 additions & 2 deletions .github/workflows/nucypher-core.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
matrix:
include:
- target: x86_64-unknown-linux-gnu
rust: 1.63 # MSRV
rust: 1.64 # MSRV
- target: x86_64-unknown-linux-gnu
rust: stable

Expand All @@ -50,7 +50,7 @@ jobs:
strategy:
matrix:
rust:
- 1.63 # MSRV
- 1.64 # MSRV
- stable
target:
- wasm32-unknown-unknown
Expand Down
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).


## [0.7.0] - Unreleased

### Added

- Add `ThresholdDecryptionRequest`/`ThresholdDecryptionResponse` types and bindings. ([#48])`
- Add `ferveo_public_key` field to `NodeMetadataPayload`. ([#48])


### Changed

- Bumped MSRV to 1.64. ([#48])


[#48]: https://github.com/nucypher/nucypher-core/pull/48


## [0.6.1] - 2023-02-18

### Fixed
Expand Down
4 changes: 3 additions & 1 deletion nucypher-core-python/nucypher_core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@
MetadataRequest,
MetadataResponse,
MetadataResponsePayload,
)
ThresholdDecryptionRequest,
ThresholdDecryptionResponse,
)
57 changes: 55 additions & 2 deletions nucypher-core-python/nucypher_core/__init__.pyi
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
from typing import List, Dict, Sequence, Optional, Mapping, Tuple, Set

from .umbral import (
SecretKey, PublicKey, Signer, Capsule, VerifiedKeyFrag, VerifiedCapsuleFrag,
RecoverableSignature)
SecretKey,
PublicKey,
Signer,
Capsule,
VerifiedKeyFrag,
VerifiedCapsuleFrag,
RecoverableSignature
)


class Address:
Expand Down Expand Up @@ -294,6 +300,7 @@ class NodeMetadataPayload:
timestamp_epoch: int,
verifying_key: PublicKey,
encrypting_key: PublicKey,
ferveo_public_key: bytes,
certificate_der: bytes,
host: str,
port: int,
Expand All @@ -307,6 +314,8 @@ class NodeMetadataPayload:

encrypting_key: PublicKey

ferveo_public_key: bytes

operator_signature: RecoverableSignature

domain: str
Expand Down Expand Up @@ -392,3 +401,47 @@ class MetadataResponse:

def __bytes__(self) -> bytes:
...


class ThresholdDecryptionRequest:

def __init__(self, ritual_id: int, variant: int, ciphertext: bytes, conditions: Optional[Conditions], context: Optional[Context]):
...

def id(self) -> int:
...

def conditions(self) -> Optional[Conditions]:
...

def context(self) -> Optional[Context]:
...

def variant(self) -> int:
...

def ciphertext(self) -> bytes:
...

@staticmethod
def from_bytes(data: bytes) -> ThresholdDecryptionRequest:
...

def __bytes__(self) -> bytes:
...


class ThresholdDecryptionResponse:

def __init__(self, decryption_share: bytes):
...

def decryption_share(self) -> bytes:
...

@staticmethod
def from_bytes(data: bytes) -> ThresholdDecryptionResponse:
...

def __bytes__(self) -> bytes:
...
137 changes: 135 additions & 2 deletions nucypher-core-python/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ use pyo3::exceptions::{PyTypeError, PyValueError};
use pyo3::prelude::*;
use pyo3::pyclass::PyClass;
use pyo3::types::{PyBytes, PyUnicode};

use nucypher_core::ProtocolObject;
use umbral_pre::bindings_python::{
Capsule, PublicKey, RecoverableSignature, SecretKey, Signer, VerificationError,
VerifiedCapsuleFrag, VerifiedKeyFrag,
};

use nucypher_core::FerveoVariant;
use nucypher_core::ProtocolObject;

fn to_bytes<'a, T, U>(obj: &T) -> PyObject
where
T: AsRef<U>,
Expand Down Expand Up @@ -630,6 +631,129 @@ impl ReencryptionResponse {
}
}

//
// Threshold Decryption Request
//

#[pyclass(module = "nucypher_core")]
#[derive(derive_more::From, derive_more::AsRef)]
pub struct ThresholdDecryptionRequest {
backend: nucypher_core::ThresholdDecryptionRequest,
}

#[pymethods]
impl ThresholdDecryptionRequest {
#[new]
pub fn new(
id: u16,
variant: u8,
ciphertext: &[u8], // TODO use ferveo Ciphertext type
conditions: Option<&Conditions>,
context: Option<&Context>,
) -> PyResult<Self> {
let ferveo_variant = match variant {
0 => FerveoVariant::SIMPLE,
1 => FerveoVariant::PRECOMPUTED,
_ => {
return Err(PyValueError::new_err(
"Invalid ThresholdDecryptionRequest variant",
))
}
};

Ok(Self {
backend: nucypher_core::ThresholdDecryptionRequest::new(
id,
ciphertext,
conditions
.map(|conditions| conditions.backend.clone())
.as_ref(),
context.map(|context| context.backend.clone()).as_ref(),
ferveo_variant,
),
})
}

#[getter]
pub fn id(&self) -> u16 {
self.backend.ritual_id
}

#[getter]
pub fn conditions(&self) -> Option<Conditions> {
self.backend
.conditions
.clone()
.map(|conditions| Conditions {
backend: conditions,
})
}

#[getter]
pub fn context(&self) -> Option<Context> {
self.backend
.context
.clone()
.map(|context| Context { backend: context })
}

#[getter]
pub fn ciphertext(&self) -> &[u8] {
self.backend.ciphertext.as_ref()
}

#[getter]
pub fn variant(&self) -> u8 {
match self.backend.variant {
FerveoVariant::SIMPLE => 0,
FerveoVariant::PRECOMPUTED => 1,
}
}
KPrasch marked this conversation as resolved.
Show resolved Hide resolved

#[staticmethod]
pub fn from_bytes(data: &[u8]) -> PyResult<Self> {
from_bytes::<_, nucypher_core::ThresholdDecryptionRequest>(data)
}

fn __bytes__(&self) -> PyObject {
to_bytes(self)
}
}

//
// Threshold Decryption Response
//

#[pyclass(module = "nucypher_core")]
#[derive(derive_more::From, derive_more::AsRef)]
pub struct ThresholdDecryptionResponse {
backend: nucypher_core::ThresholdDecryptionResponse,
}

#[pymethods]
impl ThresholdDecryptionResponse {
#[new]
pub fn new(decryption_share: &[u8]) -> Self {
ThresholdDecryptionResponse {
backend: nucypher_core::ThresholdDecryptionResponse::new(decryption_share),
}
}

#[getter]
pub fn decryption_share(&self) -> &[u8] {
self.backend.decryption_share.as_ref()
}

#[staticmethod]
pub fn from_bytes(data: &[u8]) -> PyResult<Self> {
from_bytes::<_, nucypher_core::ThresholdDecryptionResponse>(data)
}

fn __bytes__(&self) -> PyObject {
to_bytes(self)
}
}

//
// RetrievalKit
//
Expand Down Expand Up @@ -771,6 +895,7 @@ impl NodeMetadataPayload {
timestamp_epoch: u32,
verifying_key: &PublicKey,
encrypting_key: &PublicKey,
ferveo_public_key: &[u8], // TODO use ferveo PublicKey type
certificate_der: &[u8],
host: &str,
port: u16,
Expand All @@ -783,6 +908,7 @@ impl NodeMetadataPayload {
timestamp_epoch,
verifying_key: *verifying_key.as_ref(),
encrypting_key: *encrypting_key.as_ref(),
ferveo_public_key: ferveo_public_key.into(),
certificate_der: certificate_der.into(),
host: host.to_string(),
port,
Expand All @@ -808,6 +934,11 @@ impl NodeMetadataPayload {
self.backend.encrypting_key.into()
}

#[getter]
fn ferveo_public_key(&self) -> &[u8] {
self.backend.ferveo_public_key.as_ref()
}

#[getter]
fn operator_signature(&self) -> RecoverableSignature {
self.backend.operator_signature.clone().into()
Expand Down Expand Up @@ -1088,6 +1219,8 @@ fn _nucypher_core(py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<MetadataRequest>()?;
m.add_class::<MetadataResponsePayload>()?;
m.add_class::<MetadataResponse>()?;
m.add_class::<ThresholdDecryptionRequest>()?;
m.add_class::<ThresholdDecryptionResponse>()?;

let umbral_module = PyModule::new(py, "umbral")?;

Expand Down
1 change: 1 addition & 0 deletions nucypher-core-wasm/examples/node/src/main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ const makeNodeMetadata = (sk: SecretKey) => {
(Date.now() / 1000) | 0,
sk.publicKey(),
SecretKey.random().publicKey(),
Buffer.from("fake-ferveo-public-key-bytes"), // TODO: use real ferveo public key
Buffer.from("fake-certificate-bytes"),
"example.com",
8080,
Expand Down
Loading