Skip to main content

rlwe_pke/
rlwe_pke.rs

1// MIT License
2//
3// Copyright (c) 2026 Raja Lehtihet & Wael El Oraiby
4//
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to deal
7// in the Software without restriction, including without limitation the rights
8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9// copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in all
13// copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21// SOFTWARE.
22
23//! Demonstrates the example RLWE-style PKE API end to end.
24//!
25//! Run with:
26//! `cargo run --example rlwe_pke`
27//!
28//! Flow:
29//! 1. Build `R_q = Z_q[x] / (x^32 + 1)`.
30//! 2. Generate keypair (`a`, `b`, `s`) with small-noise secret.
31//! 3. Encrypt a short message.
32//! 4. Decrypt and assert round-trip equality.
33
34mod common;
35
36use common::pke::{decrypt_example, encrypt_example, keygen_example};
37use core::convert::Infallible;
38use nc_polynomial::RingContext;
39use rand_core::{TryCryptoRng, TryRng};
40
41#[derive(Debug, Clone)]
42struct ExampleRng {
43    state: u64,
44}
45
46impl ExampleRng {
47    /// Creates a deterministic RNG state for reproducible example output.
48    fn new(seed: u64) -> Self {
49        Self { state: seed }
50    }
51
52    /// xorshift64* transition.
53    ///
54    /// This is a deterministic example RNG, not a production CSPRNG.
55    fn step(&mut self) -> u64 {
56        let mut x = self.state;
57        x ^= x >> 12;
58        x ^= x << 25;
59        x ^= x >> 27;
60        self.state = x;
61        x.wrapping_mul(0x2545_F491_4F6C_DD1D)
62    }
63}
64
65impl TryRng for ExampleRng {
66    type Error = Infallible;
67
68    fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
69        Ok(self.step() as u32)
70    }
71
72    fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
73        Ok(self.step())
74    }
75
76    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Self::Error> {
77        let mut offset = 0;
78        while offset < dest.len() {
79            let word = self.step().to_le_bytes();
80            let chunk = (dest.len() - offset).min(8);
81            dest[offset..offset + chunk].copy_from_slice(&word[..chunk]);
82            offset += chunk;
83        }
84        Ok(())
85    }
86}
87
88impl TryCryptoRng for ExampleRng {}
89
90fn main() {
91    // Ring modulus polynomial `x^32 + 1`.
92    let mut modulus_poly = vec![0_u64; 32 + 1];
93    modulus_poly[0] = 1;
94    modulus_poly[32] = 1;
95    // Standard NTT-friendly prime modulus used elsewhere in the crate examples.
96    let ctx =
97        RingContext::from_parts(32, 998_244_353, &modulus_poly, 3).expect("context should build");
98
99    // Key generation randomness.
100    let mut key_rng = ExampleRng::new(0xDEAD_BEEF_1234_0001);
101    // Generates:
102    // - public key (a, b = a*s + e)
103    // - secret key (s)
104    let (public_key, secret_key) =
105        keygen_example(&ctx, 2, &mut key_rng).expect("keygen should work");
106
107    // Message payload.
108    let message = b"ok";
109    // Encryption randomness must be independent from keygen randomness.
110    let mut enc_rng = ExampleRng::new(0xFACE_CAFE_2222_0002);
111    // Produces ciphertext (u, v).
112    let ciphertext =
113        encrypt_example(&ctx, &public_key, message, 2, &mut enc_rng).expect("encrypt should work");
114
115    // Decrypt and verify.
116    let decrypted = decrypt_example(&ctx, &secret_key, &ciphertext, message.len())
117        .expect("decrypt should work");
118    assert_eq!(decrypted, message);
119
120    // Human-readable output for quick manual check.
121    println!("message={:?}", String::from_utf8_lossy(message));
122    println!("decrypted={:?}", String::from_utf8_lossy(&decrypted));
123}