Skip to content

Commit f1deab9

Browse files
committed
chore(doc): New example + fixes
1 parent 0a90178 commit f1deab9

File tree

7 files changed

+140
-32
lines changed

7 files changed

+140
-32
lines changed

.github/workflows/rust.yml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,6 @@ jobs:
2525
components: rustfmt, clippy
2626
override: true
2727

28-
- name: Run Clippy
29-
run: cargo clippy --all-targets --all-features -- -D warnings
30-
3128
- name: Build
3229
run: cargo build --lib --verbose
3330

@@ -37,6 +34,12 @@ jobs:
3734
- name: Run extensive tests
3835
run: cargo test --release --verbose -- --ignored
3936

37+
- name: Run a basic example
38+
run: cargo run --release --example new_struct
39+
40+
- name: Run Clippy
41+
run: cargo clippy --all-targets --all-features --no-deps -- -D warnings
42+
4043
- name: Check formatting
4144
run: cargo fmt -- --check
4245

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ edition = "2021"
77

88
[dependencies]
99
getrandom = { version = "0.2.15", default-features = false, features = ["rdrand"] }
10-
zeroize = { version = "1.8.1", features = ["zeroize_derive"] }
10+
zeroize = { version = "1.8.1", default-features = false, features = ["alloc","zeroize_derive"] }
1111

1212
[dev-dependencies]
1313
mimalloc = { version = "0.1.43", features = ["secure"] }

examples/new_struct.rs

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
//! This example runs perfectly on bare metal
2+
//! (assuming there's an `alloc` crate)
3+
#![no_std]
4+
5+
extern crate alloc;
6+
use alloc::vec::Vec;
7+
8+
use homomorph::prelude::*;
9+
10+
type Coordinate = u16;
11+
12+
#[derive(Clone, Debug, PartialEq, Eq)]
13+
struct Vec3 {
14+
x: Coordinate,
15+
y: Coordinate,
16+
z: Coordinate,
17+
}
18+
19+
// If you don't want to implement `ByteConvertible` for your struct,
20+
// use repr(C) and derive Copy
21+
unsafe impl ByteConvertible for Vec3 {
22+
fn to_bytes(&self) -> Vec<u8> {
23+
let mut bytes = Vec::with_capacity(3 * size_of::<Coordinate>());
24+
bytes.extend_from_slice(&self.x.to_le_bytes());
25+
bytes.extend_from_slice(&self.y.to_le_bytes());
26+
bytes.extend_from_slice(&self.z.to_le_bytes());
27+
bytes
28+
}
29+
30+
fn from_bytes(bytes: &[u8]) -> Self {
31+
if bytes.len() != 3 * size_of::<Coordinate>() {
32+
panic!(
33+
"Invalid size of bytes for conversion: {} instead of {}",
34+
bytes.len(),
35+
3 * size_of::<Coordinate>()
36+
);
37+
}
38+
39+
let x = u16::from_le_bytes([bytes[0], bytes[1]]);
40+
let y = u16::from_le_bytes([bytes[2], bytes[3]]);
41+
let z = u16::from_le_bytes([bytes[4], bytes[5]]);
42+
Vec3 { x, y, z }
43+
}
44+
}
45+
46+
struct Vec3Add;
47+
48+
impl HomomorphicOperation2<Vec3> for Vec3Add {
49+
/// ## Safety
50+
///
51+
/// `d/delta` on cipher must have been at least `21*sizeof::<Coordinates>()`.
52+
unsafe fn apply(a: &Ciphered<Vec3>, b: &Ciphered<Vec3>) -> Ciphered<Vec3> {
53+
// Unwrap the first `Vec3`
54+
let (ax, a) = a.split_at(Coordinate::BITS as usize);
55+
let ax: Ciphered<Coordinate> = Ciphered::new_from_raw(ax.to_vec());
56+
let (ay, az) = a.split_at(Coordinate::BITS as usize);
57+
let ay: Ciphered<Coordinate> = Ciphered::new_from_raw(ay.to_vec());
58+
let az: Ciphered<Coordinate> = Ciphered::new_from_raw(az.to_vec());
59+
60+
// Unwrap the second `Vec3`
61+
let (bx, b) = b.split_at(Coordinate::BITS as usize);
62+
let bx: Ciphered<Coordinate> = Ciphered::new_from_raw(bx.to_vec());
63+
let (by, bz) = b.split_at(Coordinate::BITS as usize);
64+
let by: Ciphered<Coordinate> = Ciphered::new_from_raw(by.to_vec());
65+
let bz: Ciphered<Coordinate> = Ciphered::new_from_raw(bz.to_vec());
66+
67+
// Perform already implemented homomorphic addition over `Coordinate` (`uint` is already implemented)
68+
let x = homomorph_impls::numbers::HomomorphicAddition::apply(&ax, &bx);
69+
let y = homomorph_impls::numbers::HomomorphicAddition::apply(&ay, &by);
70+
let z = homomorph_impls::numbers::HomomorphicAddition::apply(&az, &bz);
71+
72+
assert_eq!(x.len(), Coordinate::BITS as usize);
73+
assert_eq!(y.len(), Coordinate::BITS as usize);
74+
assert_eq!(z.len(), Coordinate::BITS as usize);
75+
76+
// Merge the results
77+
let mut res = Vec::with_capacity(8 * size_of::<Vec3>());
78+
res.extend_from_slice(x.as_slice());
79+
res.extend_from_slice(y.as_slice());
80+
res.extend_from_slice(z.as_slice());
81+
82+
Ciphered::new_from_raw(res)
83+
}
84+
}
85+
86+
fn main() {
87+
let params = Parameters::new(64, 32, 1, 32);
88+
let mut context = Context::new(params);
89+
context.generate_secret_key();
90+
context.generate_public_key();
91+
let sk = context.get_secret_key().unwrap();
92+
let pk = context.get_public_key().unwrap();
93+
94+
let a = Ciphered::cipher(&Vec3 { x: 1, y: 2, z: 3 }, pk);
95+
let b = Ciphered::cipher(&Vec3 { x: 9, y: 8, z: 7 }, pk);
96+
let c = unsafe { Vec3Add::apply(&a, &b) };
97+
let d = Ciphered::decipher(&c, sk);
98+
99+
assert_eq!(
100+
Vec3 {
101+
x: 10,
102+
y: 10,
103+
z: 10
104+
},
105+
d
106+
);
107+
}

src/cipher.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ mod tests {
266266
assert_eq!(data, decrypted);
267267

268268
#[derive(Copy, Clone, Debug, PartialEq)]
269+
#[repr(C)]
269270
struct MyStruct {
270271
a: usize,
271272
b: usize,

src/impls/numbers/uint.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,15 +77,15 @@ fn homomorph_add_internal(a: &[CipheredBit], b: &[CipheredBit]) -> Vec<CipheredB
7777
// c <- (p1+p2)*c + p1*p2 + p1*p2*(p1+p2)*c
7878
// c <- c*(p1+p2)*(1+p1*p2) + p1*p2
7979
let p1_p2 = p1.and(p2);
80-
carry = p1
81-
.xor(p2)
82-
.and(&carry)
83-
.and(&CipheredBit::one().xor(&p1_p2))
84-
.xor(&p1_p2);
80+
if i + 1 < longest {
81+
carry = carry
82+
.and(&p1.xor(p2))
83+
.and(&CipheredBit::one().xor(&p1_p2))
84+
.xor(&p1_p2);
85+
}
8586

8687
result.push(s);
8788
}
88-
result.push(carry);
8989

9090
result
9191
}

src/lib.rs

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -184,48 +184,39 @@
184184
//! use core::ptr::copy_nonoverlapping as memcpy;
185185
//!
186186
//! struct MyStruct {
187-
//! a: usize,
188-
//! b: usize,
187+
//! a: u32,
188+
//! b: u32,
189189
//! }
190190
//!
191191
//! // Fortunately, `MyStruct` is `Sized`!
192192
//! unsafe impl ByteConvertible for MyStruct {
193193
//! fn to_bytes(&self) -> Vec<u8> {
194194
//! let mut bytes = Vec::with_capacity(size_of::<MyStruct>());
195-
//! unsafe {
196-
//! memcpy(
197-
//! self as *const MyStruct as *const u8,
198-
//! bytes.as_mut_ptr(),
199-
//! size_of::<MyStruct>(),
200-
//! );
201-
//! bytes.set_len(size_of::<MyStruct>());
202-
//! }
195+
//! bytes.extend_from_slice(&self.a.to_le_bytes());
196+
//! bytes.extend_from_slice(&self.b.to_le_bytes());
203197
//! bytes
204198
//! }
205199
//!
206200
//! fn from_bytes(bytes: &[u8]) -> Self {
207-
//! if bytes.len() < size_of::<MyStruct>() {
201+
//! if bytes.len() != size_of::<MyStruct>() {
208202
//! panic!(
209203
//! "Invalid size of bytes for conversion: {} instead of {}",
210204
//! bytes.len(),
211205
//! size_of::<MyStruct>()
212206
//! );
213207
//! }
214208
//!
215-
//! let mut data = core::mem::MaybeUninit::uninit();
216-
//! unsafe {
217-
//! memcpy(
218-
//! bytes.as_ptr(),
219-
//! data.as_mut_ptr() as *mut u8,
220-
//! size_of::<MyStruct>(),
221-
//! );
222-
//! data.assume_init()
223-
//! }
209+
//! let (a_bytes, b_bytes) = bytes.split_at(size_of::<u32>());
210+
//!
211+
//! let a = u32::from_le_bytes([a_bytes[0], a_bytes[1], a_bytes[2], a_bytes[3]]);
212+
//! let b = u32::from_le_bytes([b_bytes[0], b_bytes[1], b_bytes[2], b_bytes[3]]);
213+
//! MyStruct { a, b }
224214
//! }
225215
//! }
226216
//! ```
227217
//!
228-
//! If we then want to implement an homomorphic addition for `usize`, we will have to define a struct `HomomorphicAddition`
218+
//! If we then want to implement an homomorphic addition for our struct,
219+
//! we will have to define a struct `HomomorphicAddition`
229220
//! that implements the trait `HomomorphicOperation2<usize>`.
230221
//!
231222
//! The key to implement such operations is to mimic the behavior of the operation on unciphered bits.
@@ -238,7 +229,8 @@
238229
//! ```rust
239230
//! use homomorph::prelude::*;
240231
//!
241-
//! // Here, we derive Copy so that the system can cipher the struct
232+
//! // Here, we derive Copy so that `ByteConvertible` is automatically implemented
233+
//! #[repr(C)]
242234
//! #[derive(Copy, Clone)]
243235
//! struct MyStruct {
244236
//! a: usize,
@@ -269,6 +261,8 @@
269261
//! You simply have to compute the boolean degree of the operation you want to implement.
270262
//! This can also be done by trial and error.
271263
//!
264+
//! For a more precise example, you can take a look at the examples in `./examples/`.
265+
//!
272266
//! ## Source
273267
//!
274268
//! The source code is available on [GitHub](<https://github.com/mathisbot/homomorph-rust>).

src/operations.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ use crate::{ByteConvertible, Ciphered};
4242
/// ```rust
4343
/// use homomorph::prelude::*;
4444
///
45+
/// #[repr(C)]
4546
/// #[derive(Copy, Clone)]
4647
/// struct MyStruct {
4748
/// a: usize,
@@ -90,6 +91,7 @@ pub trait HomomorphicOperation1<T: ByteConvertible> {
9091
/// ```rust
9192
/// use homomorph::prelude::*;
9293
///
94+
/// #[repr(C)]
9395
/// #[derive(Copy, Clone)]
9496
/// struct MyStruct {
9597
/// a: usize,
@@ -147,6 +149,7 @@ pub trait HomomorphicOperation2<T: ByteConvertible> {
147149
/// use homomorph::prelude::*;
148150
/// use core::ops::Deref;
149151
///
152+
/// #[repr(C)]
150153
/// #[derive(Copy, Clone)]
151154
/// struct MyStruct {
152155
/// a: usize,

0 commit comments

Comments
 (0)