Skip to content

Commit

Permalink
Expose CurvePoint's coordinates as FieldElement objects
Browse files Browse the repository at this point in the history
  • Loading branch information
fjarri committed Apr 25, 2021
1 parent 91c2ec1 commit 214b2b8
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 48 deletions.
18 changes: 18 additions & 0 deletions umbral-pre-python/docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,22 @@ API reference
An integer with arithmetic operations modulo curve order.

.. py:method:: to_be_bytes() -> bytes
Serializes the object into a big-endian bytestring.

.. py:class:: FieldElement
.. py:method:: to_be_bytes() -> bytes
Serializes the object into a big-endian bytestring.

.. py:class:: CurvePoint
A point on the elliptic curve.

.. py:method:: to_affine() -> Tuple[FieldElement, FieldElement]
.. py:class:: SecretKey
An ``umbral-pre`` secret key object.
Expand Down Expand Up @@ -184,6 +196,12 @@ API reference
.. py:class:: CapsuleFrag
.. py:attribute:: point_e1: CurvePoint
.. py:attribute:: point_v1: CurvePoint
.. py:attribute:: proof: CapsuleFragProof
A reencrypted fragment of an encapsulated symmetric key.

.. py:attribute:: point_e1: CurvePoint
Expand Down
65 changes: 22 additions & 43 deletions umbral-pre-python/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,30 +100,25 @@ pub struct CurveScalar {
backend: umbral_pre::CurveScalar,
}

impl AsSerializableBackend<umbral_pre::CurveScalar> for CurveScalar {
fn as_backend(&self) -> &umbral_pre::CurveScalar {
&self.backend
#[pymethods]
impl CurveScalar {
fn to_be_bytes(&self) -> PyResult<PyObject> {
let serialized = self.backend.to_be_bytes();
Python::with_gil(|py| -> PyResult<PyObject> { Ok(PyBytes::new(py, &serialized).into()) })
}
}

impl HasName for CurveScalar {
fn name() -> &'static str {
"CurveScalar"
}
#[pyclass(module = "umbral")]
#[derive(PartialEq)]
pub struct FieldElement {
backend: umbral_pre::FieldElement,
}

#[pyproto]
impl PyObjectProtocol for CurveScalar {
fn __richcmp__(&self, other: PyRef<CurveScalar>, op: CompareOp) -> PyResult<bool> {
richcmp(self, other, op)
}

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

fn __str__(&self) -> PyResult<String> {
hexstr(self)
#[pymethods]
impl FieldElement {
fn to_be_bytes(&self) -> PyResult<PyObject> {
let serialized = self.backend.to_be_bytes();
Python::with_gil(|py| -> PyResult<PyObject> { Ok(PyBytes::new(py, &serialized).into()) })
}
}

Expand All @@ -133,30 +128,13 @@ pub struct CurvePoint {
backend: umbral_pre::CurvePoint,
}

impl AsSerializableBackend<umbral_pre::CurvePoint> for CurvePoint {
fn as_backend(&self) -> &umbral_pre::CurvePoint {
&self.backend
}
}

impl HasName for CurvePoint {
fn name() -> &'static str {
"CurvePoint"
}
}

#[pyproto]
impl PyObjectProtocol for CurvePoint {
fn __richcmp__(&self, other: PyRef<CurvePoint>, op: CompareOp) -> PyResult<bool> {
richcmp(self, other, op)
}

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

fn __str__(&self) -> PyResult<String> {
hexstr(self)
#[pymethods]
impl CurvePoint {
pub fn to_affine(&self) -> PyResult<(FieldElement, FieldElement)> {
self.backend
.to_affine()
.ok_or_else(|| PyRuntimeError::new_err("Cannot get coordinates of an identity point"))
.map(|(x, y)| (FieldElement { backend: x }, FieldElement { backend: y }))
}
}

Expand Down Expand Up @@ -982,6 +960,7 @@ pub fn decrypt_reencrypted(
#[pymodule]
fn _umbral(py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<CurveScalar>()?;
m.add_class::<FieldElement>()?;
m.add_class::<CurvePoint>()?;
m.add_class::<SecretKey>()?;
m.add_class::<SecretKeyFactory>()?;
Expand Down
1 change: 1 addition & 0 deletions umbral-pre-python/umbral_pre/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from ._umbral import (
CurveScalar,
FieldElement,
CurvePoint,
SecretKey,
SecretKeyFactory,
Expand Down
8 changes: 7 additions & 1 deletion umbral-pre-python/umbral_pre/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,16 @@ class CurveScalar:
...


class CurvePoint:
class FieldElement:
...


class CurvePoint:

def to_affine(self) -> Tuple[FieldElement, FieldElement]:
...


class SecretKey:
@staticmethod
def random() -> SecretKey:
Expand Down
41 changes: 39 additions & 2 deletions umbral-pre/src/curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use digest::Digest;
use elliptic_curve::ff::PrimeField;
use elliptic_curve::scalar::NonZeroScalar;
use elliptic_curve::sec1::{CompressedPointSize, EncodedPoint, FromEncodedPoint, ToEncodedPoint};
use elliptic_curve::{AffinePoint, Curve, FromDigest, ProjectiveArithmetic, Scalar};
use elliptic_curve::{AffinePoint, Curve, FieldBytes, FromDigest, ProjectiveArithmetic, Scalar};
use generic_array::GenericArray;
use k256::Secp256k1;
use rand_core::OsRng;
Expand Down Expand Up @@ -62,6 +62,17 @@ impl CurveScalar {
) -> Self {
Self(BackendScalar::from_digest(d))
}

/// Serializes this scalar into big-endian byte representation.
pub fn to_be_bytes(&self) -> [u8; 32] {
// This is made into a separate function in addition to `SerializableToArray` implementation
// because the idea of the `SerializableToArray`-`DeserializableFromArray` from array pair
// is that they complement each other; the exact byte representation is not guaranteed.
// This function's output will be used by a third-party application,
// so it must know what it gets.
// TODO (#11): this may be removed if we use `protobuf` or some other formal specification.
self.to_array().into()
}
}

impl Default for CurveScalar {
Expand Down Expand Up @@ -90,6 +101,21 @@ impl DeserializableFromArray for CurveScalar {
}
}

type BackendFieldBytes = FieldBytes<CurveType>;

/// A structure representing a coordinate of a [`CurvePoint`].
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct FieldElement(BackendFieldBytes);

impl FieldElement {
/// Serializes this scalar into big-endian byte representation.
pub fn to_be_bytes(&self) -> [u8; 32] {
// See comment in CurveScalar::to_be_bytes() explaining
// why this is not a `SerializableToArray` implementation.
self.0.into()
}
}

type BackendPoint = <CurveType as ProjectiveArithmetic>::ProjectivePoint;
type BackendPointAffine = AffinePoint<CurveType>;

Expand All @@ -110,10 +136,21 @@ impl CurvePoint {
Self(BackendPoint::identity())
}

pub(crate) fn to_affine(&self) -> BackendPointAffine {
pub(crate) fn to_affine_point(&self) -> BackendPointAffine {
self.0.to_affine()
}

/// Returns a tuple of affine coordinates of this point,
/// or `None` if it is an identity point.
pub fn to_affine(&self) -> Option<(FieldElement, FieldElement)> {
// convert to an uncompressed point
let p = self.0.to_affine().to_encoded_point(false);
match (p.x(), p.y()) {
(Some(x), Some(y)) => Some((FieldElement(*x), FieldElement(*y))),
_ => None,
}
}

pub(crate) fn from_compressed_array(
arr: &GenericArray<u8, CompressedPointSize<CurveType>>,
) -> Option<Self> {
Expand Down
2 changes: 1 addition & 1 deletion umbral-pre/src/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ impl SerializableToArray for PublicKey {
impl DeserializableFromArray for PublicKey {
fn from_array(arr: &GenericArray<u8, Self::Size>) -> Result<Self, DeserializationError> {
let cp = CurvePoint::from_array(&arr)?;
let backend_pk = BackendPublicKey::<CurveType>::from_affine(cp.to_affine())
let backend_pk = BackendPublicKey::<CurveType>::from_affine(cp.to_affine_point())
.or(Err(DeserializationError::ConstructionFailure))?;
Ok(Self(backend_pk))
}
Expand Down
2 changes: 1 addition & 1 deletion umbral-pre/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ pub use capsule::{Capsule, OpenReencryptedError};
pub use capsule_frag::{
CapsuleFrag, CapsuleFragProof, CapsuleFragVerificationError, VerifiedCapsuleFrag,
};
pub use curve::{CurvePoint, CurveScalar};
pub use curve::{CurvePoint, CurveScalar, FieldElement};
pub use dem::{DecryptionError, EncryptionError};
pub use key_frag::{KeyFrag, KeyFragVerificationError, VerifiedKeyFrag};
pub use keys::{
Expand Down

0 comments on commit 214b2b8

Please sign in to comment.