Skip to content

Commit 8f652bc

Browse files
committed
move decoding functionalities to separate module
1 parent 8ad0075 commit 8f652bc

File tree

10 files changed

+378
-314
lines changed

10 files changed

+378
-314
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//! Elgamal objects decoding implementation
2+
3+
use anyhow::anyhow;
4+
5+
use super::{Ciphertext, GroupElement};
6+
7+
impl Ciphertext {
8+
/// `Ciphertext` bytes size
9+
pub const BYTES_SIZE: usize = GroupElement::BYTES_SIZE * 2;
10+
11+
/// Convert this `Ciphertext` to its underlying sequence of bytes.
12+
pub fn to_bytes(&self) -> [u8; Self::BYTES_SIZE] {
13+
let mut res = [0; Self::BYTES_SIZE];
14+
res[0..32].copy_from_slice(&self.0.to_bytes());
15+
res[32..64].copy_from_slice(&self.1.to_bytes());
16+
res
17+
}
18+
19+
/// Attempt to construct a `Scalar` from a compressed value byte representation.
20+
///
21+
/// # Errors
22+
/// - Cannot decode group element field.
23+
#[allow(clippy::unwrap_used)]
24+
pub fn from_bytes(bytes: &[u8; Self::BYTES_SIZE]) -> anyhow::Result<Self> {
25+
Ok(Self(
26+
GroupElement::from_bytes(bytes[0..32].try_into().unwrap())
27+
.map_err(|_| anyhow!("Cannot decode first group element field."))?,
28+
GroupElement::from_bytes(bytes[32..64].try_into().unwrap())
29+
.map_err(|_| anyhow!("Cannot decode second group element field."))?,
30+
))
31+
}
32+
}
33+
34+
#[cfg(test)]
35+
mod tests {
36+
use test_strategy::proptest;
37+
38+
use super::*;
39+
40+
#[proptest]
41+
fn ciphertext_to_bytes_from_bytes_test(c1: Ciphertext) {
42+
let bytes = c1.to_bytes();
43+
let c2 = Ciphertext::from_bytes(&bytes).unwrap();
44+
assert_eq!(c1, c2);
45+
}
46+
}

rust/catalyst-voting/src/crypto/elgamal.rs renamed to rust/catalyst-voting/src/crypto/elgamal/mod.rs

Lines changed: 2 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
//! Implementation of the lifted ``ElGamal`` crypto system, and combine with `ChaCha`
22
//! stream cipher to produce a hybrid encryption scheme.
33
4+
mod decoding;
5+
46
use std::ops::{Add, Deref, Mul};
57

6-
use anyhow::anyhow;
78
use rand_core::CryptoRngCore;
89

910
use crate::crypto::group::{GroupElement, Scalar};
@@ -50,9 +51,6 @@ impl SecretKey {
5051
}
5152

5253
impl Ciphertext {
53-
/// `Ciphertext` bytes size
54-
pub const BYTES_SIZE: usize = GroupElement::BYTES_SIZE * 2;
55-
5654
/// Generate a zero `Ciphertext`.
5755
/// The same as encrypt a `Scalar::zero()` message and `Scalar::zero()` randomness.
5856
pub fn zero() -> Self {
@@ -68,28 +66,6 @@ impl Ciphertext {
6866
pub fn second(&self) -> &GroupElement {
6967
&self.1
7068
}
71-
72-
/// Convert this `Ciphertext` to its underlying sequence of bytes.
73-
pub fn to_bytes(&self) -> [u8; Self::BYTES_SIZE] {
74-
let mut res = [0; Self::BYTES_SIZE];
75-
res[0..32].copy_from_slice(&self.0.to_bytes());
76-
res[32..64].copy_from_slice(&self.1.to_bytes());
77-
res
78-
}
79-
80-
/// Attempt to construct a `Scalar` from a compressed value byte representation.
81-
///
82-
/// # Errors
83-
/// - Cannot decode group element field.
84-
#[allow(clippy::unwrap_used)]
85-
pub fn from_bytes(bytes: &[u8; Self::BYTES_SIZE]) -> anyhow::Result<Self> {
86-
Ok(Self(
87-
GroupElement::from_bytes(bytes[0..32].try_into().unwrap())
88-
.map_err(|_| anyhow!("Cannot decode first group element field."))?,
89-
GroupElement::from_bytes(bytes[32..64].try_into().unwrap())
90-
.map_err(|_| anyhow!("Cannot decode second group element field."))?,
91-
))
92-
}
9369
}
9470

9571
/// Given a `message` represented as a `Scalar`, return a ciphertext using the
@@ -153,13 +129,6 @@ mod tests {
153129
}
154130
}
155131

156-
#[proptest]
157-
fn ciphertext_to_bytes_from_bytes_test(c1: Ciphertext) {
158-
let bytes = c1.to_bytes();
159-
let c2 = Ciphertext::from_bytes(&bytes).unwrap();
160-
assert_eq!(c1, c2);
161-
}
162-
163132
#[proptest]
164133
fn ciphertext_add_test(e1: Scalar, e2: Scalar, e3: Scalar, e4: Scalar) {
165134
let g1 = GroupElement::GENERATOR.mul(&e1);
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
//! ristretto255 objects decoding implementation
2+
3+
use anyhow::anyhow;
4+
use curve25519_dalek::{ristretto::CompressedRistretto, scalar::Scalar as IScalar};
5+
6+
use super::{GroupElement, Scalar};
7+
8+
impl Scalar {
9+
/// `Scalar` bytes size
10+
pub const BYTES_SIZE: usize = 32;
11+
12+
/// Attempt to construct a `Scalar` from a canonical byte representation.
13+
///
14+
/// # Errors
15+
/// - Cannot decode scalar.
16+
pub fn from_bytes(bytes: [u8; Self::BYTES_SIZE]) -> anyhow::Result<Scalar> {
17+
IScalar::from_canonical_bytes(bytes)
18+
.map(Scalar)
19+
.into_option()
20+
.ok_or(anyhow!("Cannot decode scalar."))
21+
}
22+
23+
/// Convert this `Scalar` to its underlying sequence of bytes.
24+
pub fn to_bytes(&self) -> [u8; Self::BYTES_SIZE] {
25+
self.0.to_bytes()
26+
}
27+
}
28+
29+
impl GroupElement {
30+
/// `Scalar` bytes size
31+
pub const BYTES_SIZE: usize = 32;
32+
33+
/// Attempt to construct a `Scalar` from a compressed value byte representation.
34+
///
35+
/// # Errors
36+
/// - Cannot decode group element.
37+
pub fn from_bytes(bytes: &[u8; Self::BYTES_SIZE]) -> anyhow::Result<Self> {
38+
Ok(GroupElement(
39+
CompressedRistretto::from_slice(bytes)?
40+
.decompress()
41+
.ok_or(anyhow!("Cannot decode group element."))?,
42+
))
43+
}
44+
45+
/// Convert this `GroupElement` to its underlying sequence of bytes.
46+
/// Always encode the compressed value.
47+
pub fn to_bytes(&self) -> [u8; Self::BYTES_SIZE] {
48+
self.0.compress().to_bytes()
49+
}
50+
}
51+
52+
#[cfg(test)]
53+
mod tests {
54+
use test_strategy::proptest;
55+
56+
use super::*;
57+
58+
#[proptest]
59+
fn scalar_to_bytes_from_bytes_test(e1: Scalar) {
60+
let bytes = e1.to_bytes();
61+
let e2 = Scalar::from_bytes(bytes).unwrap();
62+
assert_eq!(e1, e2);
63+
}
64+
65+
#[proptest]
66+
fn group_element_to_bytes_from_bytes_test(ge1: GroupElement) {
67+
let bytes = ge1.to_bytes();
68+
let ge2 = GroupElement::from_bytes(&bytes).unwrap();
69+
assert_eq!(ge1, ge2);
70+
}
71+
}

rust/catalyst-voting/src/crypto/group/ristretto255.rs renamed to rust/catalyst-voting/src/crypto/group/ristretto255/mod.rs

Lines changed: 3 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,17 @@
22
33
// cspell: words BASEPOINT
44

5+
mod decoding;
6+
57
use std::{
68
hash::Hash,
79
ops::{Add, Mul, Sub},
810
};
911

10-
use anyhow::anyhow;
1112
use curve25519_dalek::{
1213
constants::{RISTRETTO_BASEPOINT_POINT, RISTRETTO_BASEPOINT_TABLE},
1314
digest::{consts::U64, Digest},
14-
ristretto::{CompressedRistretto, RistrettoPoint as Point},
15+
ristretto::RistrettoPoint as Point,
1516
scalar::Scalar as IScalar,
1617
traits::Identity,
1718
};
@@ -38,9 +39,6 @@ impl Hash for GroupElement {
3839
}
3940

4041
impl Scalar {
41-
/// `Scalar` bytes size
42-
pub const BYTES_SIZE: usize = 32;
43-
4442
/// Generate a random scalar value from the random number generator.
4543
pub fn random<R: CryptoRngCore>(rng: &mut R) -> Self {
4644
let mut scalar_bytes = [0u8; 64];
@@ -73,22 +71,6 @@ impl Scalar {
7371
Scalar(self.0.invert())
7472
}
7573

76-
/// Convert this `Scalar` to its underlying sequence of bytes.
77-
pub fn to_bytes(&self) -> [u8; Self::BYTES_SIZE] {
78-
self.0.to_bytes()
79-
}
80-
81-
/// Attempt to construct a `Scalar` from a canonical byte representation.
82-
///
83-
/// # Errors
84-
/// - Cannot decode scalar.
85-
pub fn from_bytes(bytes: [u8; Self::BYTES_SIZE]) -> anyhow::Result<Scalar> {
86-
IScalar::from_canonical_bytes(bytes)
87-
.map(Scalar)
88-
.into_option()
89-
.ok_or(anyhow!("Cannot decode scalar."))
90-
}
91-
9274
/// Generate a `Scalar` from a hash digest.
9375
pub fn from_hash<D>(hash: D) -> Scalar
9476
where D: Digest<OutputSize = U64> {
@@ -97,33 +79,13 @@ impl Scalar {
9779
}
9880

9981
impl GroupElement {
100-
/// `GroupElement` bytes size
101-
pub const BYTES_SIZE: usize = 32;
10282
/// ristretto255 group generator.
10383
pub const GENERATOR: GroupElement = GroupElement(RISTRETTO_BASEPOINT_POINT);
10484

10585
/// Generate a zero group element.
10686
pub fn zero() -> Self {
10787
GroupElement(Point::identity())
10888
}
109-
110-
/// Convert this `GroupElement` to its underlying sequence of bytes.
111-
/// Always encode the compressed value.
112-
pub fn to_bytes(&self) -> [u8; Self::BYTES_SIZE] {
113-
self.0.compress().to_bytes()
114-
}
115-
116-
/// Attempt to construct a `Scalar` from a compressed value byte representation.
117-
///
118-
/// # Errors
119-
/// - Cannot decode group element.
120-
pub fn from_bytes(bytes: &[u8; Self::BYTES_SIZE]) -> anyhow::Result<Self> {
121-
Ok(GroupElement(
122-
CompressedRistretto::from_slice(bytes)?
123-
.decompress()
124-
.ok_or(anyhow!("Cannot decode group element."))?,
125-
))
126-
}
12789
}
12890

12991
// `std::ops` traits implementations
@@ -218,20 +180,6 @@ mod tests {
218180
}
219181
}
220182

221-
#[proptest]
222-
fn scalar_to_bytes_from_bytes_test(e1: Scalar) {
223-
let bytes = e1.to_bytes();
224-
let e2 = Scalar::from_bytes(bytes).unwrap();
225-
assert_eq!(e1, e2);
226-
}
227-
228-
#[proptest]
229-
fn group_element_to_bytes_from_bytes_test(ge1: GroupElement) {
230-
let bytes = ge1.to_bytes();
231-
let ge2 = GroupElement::from_bytes(&bytes).unwrap();
232-
assert_eq!(ge1, ge2);
233-
}
234-
235183
#[proptest]
236184
fn scalar_arithmetic_tests(e1: Scalar, e2: Scalar, e3: Scalar) {
237185
assert_eq!(&(&e1 + &e2) + &e3, &e1 + &(&e2 + &e3));

0 commit comments

Comments
 (0)