Skip to main content

RingElem

Struct RingElem 

Source
pub struct RingElem { /* private fields */ }
Expand description

Canonical element of R_q = Z_q[x] / (f(x)).

Each operation applies the corresponding polynomial arithmetic and then reduces modulo f(x).

Implementations§

Source§

impl RingElem

Source

pub fn params(&self) -> &Params

Returns the validated parameter set that defines this element’s ring.

Examples found in repository?
examples/common/pke.rs (line 181)
176fn ensure_element_matches_context(
177    ctx: &RingContext,
178    element: &RingElem,
179) -> Result<(), ExamplePkeError> {
180    // Structural parameter equality check.
181    if element.params() != ctx.params() {
182        return Err(ExamplePkeError::ParameterMismatch);
183    }
184    Ok(())
185}
More examples
Hide additional examples
examples/common/codec.rs (line 137)
132pub fn decode_message_scaled_bits_example(
133    element: &RingElem,
134    output_len_bytes: usize,
135) -> Result<Vec<u8>, CodecError> {
136    // Decode limit follows the same bit-capacity convention used at encode time.
137    let capacity_bits = element.params().max_degree();
138    let requested_bits = output_len_bytes.saturating_mul(8);
139    if requested_bits > capacity_bits {
140        return Err(CodecError::DecodeLengthTooLong {
141            requested_bits,
142            capacity_bits,
143        });
144    }
145
146    let q = element.params().modulus();
147    // Threshold window near middle of modulus range.
148    // Values in `[q/4, 3q/4)` decode to 1; others decode to 0.
149    let lower = q / 4;
150    let upper = (3 * q) / 4;
151
152    let mut out = vec![0_u8; output_len_bytes];
153    for bit_index in 0..requested_bits {
154        let coeff = element.coefficients()[bit_index];
155        let bit = coeff >= lower && coeff < upper;
156        if bit {
157            // Restore little-endian bit position.
158            out[bit_index / 8] |= 1_u8 << (bit_index % 8);
159        }
160    }
161
162    Ok(out)
163}
164
165/// Compresses one coefficient into `bits` bits.
166pub fn compress_coefficient_example(value: u64, modulus: u64, bits: u8) -> Result<u16, CodecError> {
167    validate_compression_bits(bits)?;
168
169    // Quantization levels = 2^bits.
170    let levels = 1_u128 << bits;
171    let q = modulus as u128;
172    let v = (value % modulus) as u128;
173
174    // Rounded scaling from `[0, q)` into `[0, 2^bits)`.
175    let compressed = ((v * levels + (q / 2)) / q) % levels;
176    Ok(compressed as u16)
177}
178
179/// Decompresses one `bits`-bit coefficient back into `Z_q`.
180pub fn decompress_coefficient_example(
181    compressed: u16,
182    modulus: u64,
183    bits: u8,
184) -> Result<u64, CodecError> {
185    validate_compression_bits(bits)?;
186
187    let levels = 1_u128 << bits;
188    let q = modulus as u128;
189    let c = (compressed as u128) % levels;
190
191    // Rounded inverse scaling from `[0, 2^bits)` back into `[0, q)`.
192    let decompressed = (c * q + (levels / 2)) / levels;
193    Ok((decompressed % q) as u64)
194}
195
196/// Compresses all coefficients of a ring element into `bits` bits each.
197pub fn compress_ring_elem_example(element: &RingElem, bits: u8) -> Result<Vec<u16>, CodecError> {
198    validate_compression_bits(bits)?;
199
200    let q = element.params().modulus();
201    // Compress each coefficient independently.
202    let mut packed = Vec::with_capacity(element.coefficients().len());
203    for &coeff in element.coefficients() {
204        packed.push(compress_coefficient_example(coeff, q, bits)?);
205    }
206    Ok(packed)
207}
Source

pub fn polynomial(&self) -> &Polynomial

Returns the underlying canonical polynomial representative.

Source

pub fn into_polynomial(self) -> Polynomial

Consumes and returns the underlying polynomial representative.

Source

pub fn coefficients(&self) -> &[u64]

Returns the dense coefficient slice of the canonical representative.

Examples found in repository?
examples/common/codec.rs (line 154)
132pub fn decode_message_scaled_bits_example(
133    element: &RingElem,
134    output_len_bytes: usize,
135) -> Result<Vec<u8>, CodecError> {
136    // Decode limit follows the same bit-capacity convention used at encode time.
137    let capacity_bits = element.params().max_degree();
138    let requested_bits = output_len_bytes.saturating_mul(8);
139    if requested_bits > capacity_bits {
140        return Err(CodecError::DecodeLengthTooLong {
141            requested_bits,
142            capacity_bits,
143        });
144    }
145
146    let q = element.params().modulus();
147    // Threshold window near middle of modulus range.
148    // Values in `[q/4, 3q/4)` decode to 1; others decode to 0.
149    let lower = q / 4;
150    let upper = (3 * q) / 4;
151
152    let mut out = vec![0_u8; output_len_bytes];
153    for bit_index in 0..requested_bits {
154        let coeff = element.coefficients()[bit_index];
155        let bit = coeff >= lower && coeff < upper;
156        if bit {
157            // Restore little-endian bit position.
158            out[bit_index / 8] |= 1_u8 << (bit_index % 8);
159        }
160    }
161
162    Ok(out)
163}
164
165/// Compresses one coefficient into `bits` bits.
166pub fn compress_coefficient_example(value: u64, modulus: u64, bits: u8) -> Result<u16, CodecError> {
167    validate_compression_bits(bits)?;
168
169    // Quantization levels = 2^bits.
170    let levels = 1_u128 << bits;
171    let q = modulus as u128;
172    let v = (value % modulus) as u128;
173
174    // Rounded scaling from `[0, q)` into `[0, 2^bits)`.
175    let compressed = ((v * levels + (q / 2)) / q) % levels;
176    Ok(compressed as u16)
177}
178
179/// Decompresses one `bits`-bit coefficient back into `Z_q`.
180pub fn decompress_coefficient_example(
181    compressed: u16,
182    modulus: u64,
183    bits: u8,
184) -> Result<u64, CodecError> {
185    validate_compression_bits(bits)?;
186
187    let levels = 1_u128 << bits;
188    let q = modulus as u128;
189    let c = (compressed as u128) % levels;
190
191    // Rounded inverse scaling from `[0, 2^bits)` back into `[0, q)`.
192    let decompressed = (c * q + (levels / 2)) / levels;
193    Ok((decompressed % q) as u64)
194}
195
196/// Compresses all coefficients of a ring element into `bits` bits each.
197pub fn compress_ring_elem_example(element: &RingElem, bits: u8) -> Result<Vec<u16>, CodecError> {
198    validate_compression_bits(bits)?;
199
200    let q = element.params().modulus();
201    // Compress each coefficient independently.
202    let mut packed = Vec::with_capacity(element.coefficients().len());
203    for &coeff in element.coefficients() {
204        packed.push(compress_coefficient_example(coeff, q, bits)?);
205    }
206    Ok(packed)
207}
Source

pub fn trimmed_coefficients(&self) -> Vec<u64>

Returns coefficients trimmed to the actual degree.

Source

pub fn degree(&self) -> Option<usize>

Returns the representative’s polynomial degree.

Examples found in repository?
examples/helpers_codec.rs (line 71)
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}
More examples
Hide additional examples
examples/helpers_sampling.rs (line 128)
99fn main() {
100    // Configure modulus polynomial `x^16 + 1`.
101    //
102    // We allocate `max_degree + 1` coefficients and set:
103    // - constant term: 1
104    // - x^16 term: 1
105    // - all intermediate terms: 0
106    let mut modulus_poly = vec![0_u64; 16 + 1];
107    modulus_poly[0] = 1;
108    modulus_poly[16] = 1;
109    // Build validated ring context with NTT-friendly modulus and primitive root.
110    let ctx =
111        RingContext::from_parts(16, 998_244_353, &modulus_poly, 3).expect("context should build");
112
113    // Deterministic seed makes this executable reproducible.
114    let mut rng = ExampleRng::new(0xA11C_E123_0000_0001);
115
116    // Uniform sample in `R_q`: every coefficient is sampled independently in `[0, q)`.
117    let uniform =
118        sample_uniform_poly_example(&ctx, &mut rng).expect("uniform sampling should work");
119    // Centered-binomial sample: each coefficient is small noise around 0.
120    let cbd = sample_cbd_poly_example(&ctx, 3, &mut rng).expect("CBD sampling should work");
121    // Gaussian-like sample from Box-Muller + integer rounding.
122    let gaussian =
123        sample_discrete_gaussian_poly_example(&ctx, 2.5, &mut rng).expect("gaussian should work");
124    // Raw integer rejection sample in `[0, 1000)`.
125    let below = sample_rejection_u64_below_example(1_000, &mut rng).expect("rejection should work");
126
127    // Print concise observable properties so this can be used as a smoke run.
128    println!("uniform_degree={:?}", uniform.degree());
129    println!("cbd_degree={:?}", cbd.degree());
130    println!("gaussian_degree={:?}", gaussian.degree());
131    println!("sample_below_1000={below}");
132}
Source

pub fn is_zero(&self) -> bool

Returns whether the element is additive identity.

Source

pub fn add(&self, rhs: &Self) -> Result<Self, PolynomialError>

Adds two ring elements.

Examples found in repository?
examples/common/pke.rs (line 118)
105pub fn keygen_example<R: CryptoRng>(
106    ctx: &RingContext,
107    noise_eta: u8,
108    rng: &mut R,
109) -> Result<(ExamplePublicKey, ExampleSecretKey), ExamplePkeError> {
110    // Public random polynomial.
111    let a = sample_uniform_poly_example(ctx, rng)?;
112    // Secret small-noise polynomial.
113    let s = sample_cbd_poly_example(ctx, noise_eta, rng)?;
114    // Public error polynomial.
115    let e = sample_cbd_poly_example(ctx, noise_eta, rng)?;
116
117    // RLWE public relation: b = a*s + e.
118    let b = a.mul(&s)?.add(&e)?;
119
120    Ok((ExamplePublicKey { a, b }, ExampleSecretKey { s }))
121}
122
123/// Encrypts a byte message using the example key.
124///
125/// The message is encoded using scaled bits from [`encode_message_scaled_bits_example`].
126pub fn encrypt_example<R: CryptoRng>(
127    ctx: &RingContext,
128    public_key: &ExamplePublicKey,
129    message: &[u8],
130    noise_eta: u8,
131    rng: &mut R,
132) -> Result<ExampleCiphertext, ExamplePkeError> {
133    // Ensure all key elements come from the same validated parameter set.
134    ensure_element_matches_context(ctx, &public_key.a)?;
135    ensure_element_matches_context(ctx, &public_key.b)?;
136
137    // Encode message bits into ring element form.
138    let m = encode_message_scaled_bits_example(ctx, message)?;
139    // Fresh encryption randomness + masking errors.
140    let r = sample_cbd_poly_example(ctx, noise_eta, rng)?;
141    let e1 = sample_cbd_poly_example(ctx, noise_eta, rng)?;
142    let e2 = sample_cbd_poly_example(ctx, noise_eta, rng)?;
143
144    // RLWE encryption equations:
145    //   u = a*r + e1
146    //   v = b*r + e2 + m
147    let u = public_key.a.mul(&r)?.add(&e1)?;
148    let v = public_key.b.mul(&r)?.add(&e2)?.add(&m)?;
149
150    Ok(ExampleCiphertext { u, v })
151}
Source

pub fn sub(&self, rhs: &Self) -> Result<Self, PolynomialError>

Subtracts two ring elements.

Examples found in repository?
examples/common/pke.rs (line 169)
154pub fn decrypt_example(
155    ctx: &RingContext,
156    secret_key: &ExampleSecretKey,
157    ciphertext: &ExampleCiphertext,
158    output_len_bytes: usize,
159) -> Result<Vec<u8>, ExamplePkeError> {
160    // Context checks prevent cross-parameter misuse.
161    ensure_element_matches_context(ctx, &secret_key.s)?;
162    ensure_element_matches_context(ctx, &ciphertext.u)?;
163    ensure_element_matches_context(ctx, &ciphertext.v)?;
164
165    // Recover encoded message:
166    //   v - s*u = (a*s + e)r + e2 + m - s(a*r + e1)
167    //           = m + (e*r + e2 - s*e1)
168    // Small noise lets threshold decoder recover bits.
169    let recovered = ciphertext.v.sub(&secret_key.s.mul(&ciphertext.u)?)?;
170    Ok(decode_message_scaled_bits_example(
171        &recovered,
172        output_len_bytes,
173    )?)
174}
Source

pub fn mul(&self, rhs: &Self) -> Result<Self, PolynomialError>

Multiplies two ring elements.

Examples found in repository?
examples/common/pke.rs (line 118)
105pub fn keygen_example<R: CryptoRng>(
106    ctx: &RingContext,
107    noise_eta: u8,
108    rng: &mut R,
109) -> Result<(ExamplePublicKey, ExampleSecretKey), ExamplePkeError> {
110    // Public random polynomial.
111    let a = sample_uniform_poly_example(ctx, rng)?;
112    // Secret small-noise polynomial.
113    let s = sample_cbd_poly_example(ctx, noise_eta, rng)?;
114    // Public error polynomial.
115    let e = sample_cbd_poly_example(ctx, noise_eta, rng)?;
116
117    // RLWE public relation: b = a*s + e.
118    let b = a.mul(&s)?.add(&e)?;
119
120    Ok((ExamplePublicKey { a, b }, ExampleSecretKey { s }))
121}
122
123/// Encrypts a byte message using the example key.
124///
125/// The message is encoded using scaled bits from [`encode_message_scaled_bits_example`].
126pub fn encrypt_example<R: CryptoRng>(
127    ctx: &RingContext,
128    public_key: &ExamplePublicKey,
129    message: &[u8],
130    noise_eta: u8,
131    rng: &mut R,
132) -> Result<ExampleCiphertext, ExamplePkeError> {
133    // Ensure all key elements come from the same validated parameter set.
134    ensure_element_matches_context(ctx, &public_key.a)?;
135    ensure_element_matches_context(ctx, &public_key.b)?;
136
137    // Encode message bits into ring element form.
138    let m = encode_message_scaled_bits_example(ctx, message)?;
139    // Fresh encryption randomness + masking errors.
140    let r = sample_cbd_poly_example(ctx, noise_eta, rng)?;
141    let e1 = sample_cbd_poly_example(ctx, noise_eta, rng)?;
142    let e2 = sample_cbd_poly_example(ctx, noise_eta, rng)?;
143
144    // RLWE encryption equations:
145    //   u = a*r + e1
146    //   v = b*r + e2 + m
147    let u = public_key.a.mul(&r)?.add(&e1)?;
148    let v = public_key.b.mul(&r)?.add(&e2)?.add(&m)?;
149
150    Ok(ExampleCiphertext { u, v })
151}
152
153/// Decrypts an example ciphertext and decodes the requested number of output bytes.
154pub fn decrypt_example(
155    ctx: &RingContext,
156    secret_key: &ExampleSecretKey,
157    ciphertext: &ExampleCiphertext,
158    output_len_bytes: usize,
159) -> Result<Vec<u8>, ExamplePkeError> {
160    // Context checks prevent cross-parameter misuse.
161    ensure_element_matches_context(ctx, &secret_key.s)?;
162    ensure_element_matches_context(ctx, &ciphertext.u)?;
163    ensure_element_matches_context(ctx, &ciphertext.v)?;
164
165    // Recover encoded message:
166    //   v - s*u = (a*s + e)r + e2 + m - s(a*r + e1)
167    //           = m + (e*r + e2 - s*e1)
168    // Small noise lets threshold decoder recover bits.
169    let recovered = ciphertext.v.sub(&secret_key.s.mul(&ciphertext.u)?)?;
170    Ok(decode_message_scaled_bits_example(
171        &recovered,
172        output_len_bytes,
173    )?)
174}
Source

pub fn neg(&self) -> Self

Returns additive inverse.

Source

pub fn scalar_mul(&self, scalar: u64) -> Self

Multiplies by a scalar in Z_q.

Trait Implementations§

Source§

impl Clone for RingElem

Source§

fn clone(&self) -> RingElem

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for RingElem

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl PartialEq for RingElem

Source§

fn eq(&self, other: &RingElem) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Eq for RingElem

Source§

impl StructuralPartialEq for RingElem

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.