Skip to content

Commit

Permalink
Merge pull request #112 from fjarri/secret-serialization
Browse files Browse the repository at this point in the history
SecretKey serialization
  • Loading branch information
fjarri authored Jan 16, 2023
2 parents 5080d6d + 7d50d77 commit 50a7a6e
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 13 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `to_compressed_bytes()`/`try_from_compressed_bytes()` for `PublicKey` to give access to non-serde representation (just 33 bytes). These are exposed in the bindings in lieu of the "default" methods (e.g. `__bytes__()` or `toBytes()`). ([#110])
- `to_der_bytes()`/`try_from_der_bytes()` for `Signature` to give access to non-serde representation. These are exposed in the bindings in lieu of the "default" methods (e.g. `__bytes__()` or `toBytes()`). ([#110])
- `SecretKeyFactory::make_secret()` to provide a more straightforward replacement of `SecretKeyFactory::make_secret_key()`->`SecretKey::to_secret_bytes()`. ([#110])
- Added `SecretKey::to_be_bytes()` and `try_from_be_bytes()`. ([#112])


### Fixed
Expand All @@ -30,6 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

[#105]: https://github.com/nucypher/rust-umbral/pull/105
[#110]: https://github.com/nucypher/rust-umbral/pull/110
[#112]: https://github.com/nucypher/rust-umbral/pull/112


## [0.7.0] - 2022-09-30
Expand Down
5 changes: 4 additions & 1 deletion umbral-pre-python/umbral_pre/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ class SecretKey:
def public_key(self) -> PublicKey:
...

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

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


Expand Down
30 changes: 23 additions & 7 deletions umbral-pre/src/bindings_python.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use pyo3::wrap_pyfunction;
use sha2::{digest::Update, Digest, Sha256};

use crate as umbral_pre;
use crate::{DefaultDeserialize, DefaultSerialize};
use crate::{curve::ScalarSize, DefaultDeserialize, DefaultSerialize, SecretBox};

fn map_py_value_err<T: fmt::Display>(err: T) -> PyErr {
PyValueError::new_err(format!("{}", err))
Expand Down Expand Up @@ -94,6 +94,22 @@ impl SecretKey {
}
}

pub fn to_be_bytes(&self) -> PyObject {
let serialized = self.backend.to_be_bytes();
Python::with_gil(|py| PyBytes::new(py, serialized.as_secret()).into())
}

#[staticmethod]
pub fn from_be_bytes(data: &[u8]) -> PyResult<Self> {
let arr = SecretBox::new(
GenericArray::<u8, ScalarSize>::from_exact_iter(data.iter().cloned())
.ok_or_else(|| map_py_value_err("Invalid length of a curve scalar"))?,
);
umbral_pre::SecretKey::try_from_be_bytes(&arr)
.map_err(map_py_value_err)
.map(Self::from)
}

pub fn public_key(&self) -> PublicKey {
PublicKey {
backend: self.backend.public_key(),
Expand Down Expand Up @@ -130,10 +146,10 @@ impl SecretKeyFactory {
.map_err(map_py_value_err)
}

pub fn make_secret(&self, label: &[u8]) -> Vec<u8> {
pub fn make_secret(&self, label: &[u8]) -> PyObject {
let secret = self.backend.make_secret(label);
let bytes: &[u8] = secret.as_secret().as_ref();
bytes.into()
Python::with_gil(|py| PyBytes::new(py, bytes).into())
}

pub fn make_key(&self, label: &[u8]) -> SecretKey {
Expand Down Expand Up @@ -164,9 +180,9 @@ impl PublicKey {
.map(Self::from)
}

fn to_compressed_bytes(&self) -> PyResult<PyObject> {
fn to_compressed_bytes(&self) -> PyObject {
let serialized = self.backend.to_compressed_bytes();
Python::with_gil(|py| -> PyResult<PyObject> { Ok(PyBytes::new(py, &serialized).into()) })
Python::with_gil(|py| PyBytes::new(py, &serialized).into())
}

fn __richcmp__(&self, other: &Self, op: CompareOp) -> PyResult<bool> {
Expand Down Expand Up @@ -223,9 +239,9 @@ impl Signature {
.map(Self::from)
}

fn to_der_bytes(&self) -> PyResult<PyObject> {
fn to_der_bytes(&self) -> PyObject {
let serialized = self.backend.to_der_bytes();
Python::with_gil(|py| -> PyResult<PyObject> { Ok(PyBytes::new(py, &serialized).into()) })
Python::with_gil(|py| PyBytes::new(py, &serialized).into())
}

fn verify(&self, verifying_pk: &PublicKey, message: &[u8]) -> bool {
Expand Down
21 changes: 20 additions & 1 deletion umbral-pre/src/bindings_wasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ use alloc::string::String;
use alloc::vec::Vec;
use core::fmt;

use generic_array::GenericArray;
use js_sys::{Error, Uint8Array};
use wasm_bindgen::prelude::{wasm_bindgen, JsValue};
use wasm_bindgen::JsCast;
use wasm_bindgen_derive::TryFromJsValue;

use crate as umbral_pre;
use crate::{DefaultDeserialize, DefaultSerialize};
use crate::{curve::ScalarSize, DefaultDeserialize, DefaultSerialize, SecretBox};

#[wasm_bindgen]
extern "C" {
Expand Down Expand Up @@ -91,6 +92,24 @@ impl SecretKey {
Self(umbral_pre::SecretKey::random())
}

#[wasm_bindgen(js_name = toBEBytes)]
pub fn to_be_bytes(&self) -> Box<[u8]> {
let serialized = self.0.to_be_bytes();
let bytes: &[u8] = serialized.as_secret().as_ref();
bytes.into()
}

#[wasm_bindgen(js_name = fromBEBytes)]
pub fn from_be_bytes(data: &[u8]) -> Result<SecretKey, Error> {
let arr = SecretBox::new(
GenericArray::<u8, ScalarSize>::from_exact_iter(data.iter().cloned())
.ok_or_else(|| map_js_err("Invalid length of a curve scalar"))?,
);
umbral_pre::SecretKey::try_from_be_bytes(&arr)
.map(Self)
.map_err(map_js_err)
}

/// Generates a secret key using the default RNG and returns it.
#[wasm_bindgen(js_name = publicKey)]
pub fn public_key(&self) -> PublicKey {
Expand Down
20 changes: 16 additions & 4 deletions umbral-pre/src/keys.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
#[cfg(feature = "serde-support")]
use alloc::format;

use alloc::boxed::Box;
use alloc::format;
use alloc::string::String;
use core::cmp::Ordering;
use core::fmt;
Expand All @@ -21,7 +19,7 @@ use rand_core::OsRng;
#[cfg(feature = "serde-support")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};

use crate::curve::{CompressedPointSize, CurvePoint, CurveType, NonZeroCurveScalar};
use crate::curve::{CompressedPointSize, CurvePoint, CurveType, NonZeroCurveScalar, ScalarSize};
use crate::dem::kdf;
use crate::hashing::{BackendDigest, Hash, ScalarDigest};
use crate::secret_box::SecretBox;
Expand Down Expand Up @@ -134,6 +132,20 @@ impl SecretKey {
*backend_scalar.as_secret(),
))
}

/// Serializes the secret key as a scalar in the big-endian representation.
pub fn to_be_bytes(&self) -> SecretBox<GenericArray<u8, ScalarSize>> {
SecretBox::new(self.0.to_be_bytes())
}

/// Deserializes the secret key from a scalar in the big-endian representation.
pub fn try_from_be_bytes(
bytes: &SecretBox<GenericArray<u8, ScalarSize>>,
) -> Result<Self, String> {
BackendSecretKey::<CurveType>::from_be_bytes(bytes.as_secret().as_slice())
.map(Self::new)
.map_err(|err| format!("{}", err))
}
}

impl fmt::Display for SecretKey {
Expand Down

0 comments on commit 50a7a6e

Please sign in to comment.