helpers_codec/helpers_codec.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 message/packing codec helpers.
24//!
25//! Run with:
26//! `cargo run --example helpers_codec`
27//!
28//! Flow:
29//! 1. Build `R_q = Z_q[x] / (x^32 + 1)`.
30//! 2. Encode a short byte message into scaled-bit coefficients.
31//! 3. Decode back and assert equality.
32//! 4. Compress/decompress the ring element coefficients and print a summary.
33
34mod common;
35
36use common::codec::{
37 compress_ring_elem_example, decode_message_scaled_bits_example, decompress_ring_elem_example,
38 encode_message_scaled_bits_example,
39};
40use nc_polynomial::RingContext;
41
42fn main() {
43 // Use a power-of-two cyclotomic-style modulus polynomial `x^32 + 1`.
44 let mut modulus_poly = vec![0_u64; 32 + 1];
45 modulus_poly[0] = 1;
46 modulus_poly[32] = 1;
47 // Create validated context (n=32, q=998244353, primitive root=3).
48 let ctx =
49 RingContext::from_parts(32, 998_244_353, &modulus_poly, 3).expect("context should build");
50
51 // Message to encode. Each bit maps into one coefficient slot.
52 let message = b"Rust";
53 // Encode bytes -> ring element with coefficients in `{0, floor((q+1)/2)}`.
54 let encoded =
55 encode_message_scaled_bits_example(&ctx, message).expect("message encoding should work");
56 // Decode ring element -> bytes (threshold decoding in coefficient domain).
57 let decoded = decode_message_scaled_bits_example(&encoded, message.len())
58 .expect("message decoding should work");
59 // End-to-end correctness check.
60 assert_eq!(decoded, message);
61
62 // Quantize coefficients to 11-bit buckets.
63 let compressed = compress_ring_elem_example(&encoded, 11).expect("compression should work");
64 // Lift quantized coefficients back into `Z_q`.
65 let decompressed =
66 decompress_ring_elem_example(&ctx, &compressed, 11).expect("decompression should work");
67
68 // Print summary values to inspect behavior quickly.
69 println!("decoded_message={:?}", String::from_utf8_lossy(&decoded));
70 println!("compressed_coeffs={}", compressed.len());
71 println!("decompressed_degree={:?}", decompressed.degree());
72}