Skip to content

Commit

Permalink
add hpke_open and generate_hpke_keypair functions; test roundtrip (#15)
Browse files Browse the repository at this point in the history
  • Loading branch information
jvmncs authored Aug 2, 2022
1 parent fede62b commit 18c1a94
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 4 deletions.
7 changes: 7 additions & 0 deletions hpke_spec_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,10 @@ def test_wrong_pk_size(self):
raise AssertionError(
"hpke_seal failed to raise Exception on malformed public key"
)

def test_hpke_roundtrip(self):
skR, pkR = hpke_spec.generate_hpke_keypair()
ptxt = b"my name is Vincent Law"
ctxt = hpke_spec.hpke_seal(pkR, ptxt)
ptxt_roundtrip = hpke_spec.hpke_open(skR, ctxt)
assert ptxt == ptxt_roundtrip
65 changes: 61 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use hacspec_lib::{Seq, U8};
use hpke::{AdditionalData, HPKECiphertext, HPKEConfig, HpkePublicKey, HpkeSeal, Mode};
use hacspec_lib::{ByteSeq, Seq, U8};
use hpke::{
AdditionalData, Ciphertext, HPKECiphertext, HPKEConfig, HpkeOpen, HpkePrivateKey,
HpkePublicKey, HpkeSeal, KemOutput, Mode,
};
use hpke_aead::AEAD;
use hpke_errors::HpkeError;
use hpke_kdf::{Info, KDF};
use hpke_kem::{Randomness, KEM};
use hpke_kdf::{Info, InputKeyMaterial, KDF};
use hpke_kem::{DeriveKeyPair, Nsk, Randomness, KEM};
use pyo3::exceptions::PyRuntimeError;
use pyo3::prelude::*;
use pyo3::types::PyBytes;
Expand All @@ -17,6 +20,28 @@ fn get_default_hpke_config() -> HPKEConfig {
HPKEConfig(mode, kem, kdf, aead)
}

fn hpke_open_bytes(ctxtb: &[u8], skb: &[u8]) -> Result<Vec<u8>, HpkeError> {
let hpke_config = get_default_hpke_config();
let kem_output = KemOutput::from_public_slice(&ctxtb[..32]);
let ctxt = Ciphertext::from_public_slice(&ctxtb[32..]);
let ciphertext = HPKECiphertext(kem_output, ctxt);
let sk_r = HpkePrivateKey::from_public_slice(skb);
let info = Info::new(0);
let aad = AdditionalData::new(0);
let result: ByteSeq = HpkeOpen(
hpke_config,
&ciphertext,
&sk_r,
&info,
&aad,
None,
None,
None,
)?;
let plaintext = result.into_native();
Ok(plaintext)
}

fn hpke_seal_bytes(pkb: &[u8], ptxtb: &[u8]) -> Result<Vec<u8>, HpkeError> {
let hpke_config = get_default_hpke_config();
let pk = HpkePublicKey::from_public_slice(pkb);
Expand All @@ -43,6 +68,26 @@ fn hpke_seal_bytes(pkb: &[u8], ptxtb: &[u8]) -> Result<Vec<u8>, HpkeError> {
Ok(encapsulated)
}

fn generate_keypair() -> Result<(Vec<u8>, Vec<u8>), HpkeError> {
let hpke_config = get_default_hpke_config();
let kem = hpke_config.1;
let nbytes = Nsk(kem);
let mut rand_bytes = vec![0u8; nbytes];
OsRng.fill_bytes(&mut rand_bytes);
let randomness = InputKeyMaterial::from_public_slice(&rand_bytes);
let keypair = DeriveKeyPair(kem, &randomness)?;
Ok((keypair.0.into_native(), keypair.1.into_native()))
}

#[pyfunction]
fn generate_hpke_keypair(py: Python) -> PyResult<(&PyBytes, &PyBytes)> {
let keypair_bytes = generate_keypair()
.map_err(|hpke_error| PyRuntimeError::new_err(format!("{hpke_error:?}")))?;
let sk_py = PyBytes::new(py, &keypair_bytes.0);
let pk_py = PyBytes::new(py, &keypair_bytes.1);
Ok((sk_py, pk_py))
}

/// Python binding to hpke-spec's Single-Shot API function hpke::HpkeSeal
#[pyfunction]
fn hpke_seal<'p>(py: Python<'p>, pk_py: &PyBytes, ptxt_py: &PyBytes) -> PyResult<&'p PyBytes> {
Expand All @@ -53,9 +98,21 @@ fn hpke_seal<'p>(py: Python<'p>, pk_py: &PyBytes, ptxt_py: &PyBytes) -> PyResult
Ok(PyBytes::new(py, &ciphertext_bytes))
}

/// Python binding to hpke-spec's Single-Shot API function hpke::HpkeOpen
#[pyfunction]
fn hpke_open<'p>(py: Python<'p>, sk_py: &PyBytes, ctxt_py: &PyBytes) -> PyResult<&'p PyBytes> {
let skb = sk_py.as_bytes();
let ctxtb = ctxt_py.as_bytes();
let plaintext_bytes = hpke_open_bytes(ctxtb, skb)
.map_err(|hpke_error| PyRuntimeError::new_err(format!("{hpke_error:?}")))?;
Ok(PyBytes::new(py, &plaintext_bytes))
}

/// A Python module implemented in Rust.
#[pymodule]
fn hpke_spec(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(generate_hpke_keypair, m)?)?;
m.add_function(wrap_pyfunction!(hpke_open, m)?)?;
m.add_function(wrap_pyfunction!(hpke_seal, m)?)?;
Ok(())
}

0 comments on commit 18c1a94

Please sign in to comment.