libcrux-ml-dsa 0.0.4

Libcrux ML-DSA implementation
Documentation
use crate::{helper::cloop, polynomial::PolynomialRingElement, simd::traits::Operations};

// Each coefficient takes up 10 bits.

#[inline(always)]
pub(crate) fn serialize<SIMDUnit: Operations>(
    re: &PolynomialRingElement<SIMDUnit>,
    serialized: &mut [u8], // len RING_ELEMENT_OF_T1S_SIZE
) {
    const OUTPUT_BYTES_PER_SIMD_UNIT: usize = 10;

    cloop! {
        for (i, simd_unit) in re.simd_units.iter().enumerate() {
            SIMDUnit::t1_serialize(simd_unit, &mut serialized[i * OUTPUT_BYTES_PER_SIMD_UNIT..(i + 1) * OUTPUT_BYTES_PER_SIMD_UNIT]);
        }
    }
}

pub(crate) fn deserialize<SIMDUnit: Operations>(
    serialized: &[u8],
    result: &mut PolynomialRingElement<SIMDUnit>,
) {
    const WINDOW: usize = 10;
    for i in 0..result.simd_units.len() {
        SIMDUnit::t1_deserialize(
            &serialized[i * WINDOW..(i + 1) * WINDOW],
            &mut result.simd_units[i],
        );
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    use crate::{
        constants::RING_ELEMENT_OF_T1S_SIZE,
        simd::{self, traits::Operations},
    };

    fn test_serialize_generic<SIMDUnit: Operations>() {
        let coefficients = [
            127, 627, 86, 834, 463, 169, 792, 8, 595, 212, 1015, 213, 321, 501, 471, 633, 686, 333,
            973, 464, 737, 30, 761, 358, 659, 607, 177, 826, 147, 995, 89, 365, 302, 585, 406, 76,
            535, 406, 952, 664, 102, 270, 879, 877, 127, 437, 1010, 418, 695, 596, 847, 131, 1004,
            228, 882, 433, 39, 569, 284, 225, 676, 740, 712, 165, 912, 71, 491, 887, 668, 607, 919,
            607, 891, 647, 904, 957, 846, 256, 353, 57, 712, 98, 200, 722, 734, 596, 187, 470, 501,
            524, 1000, 435, 195, 594, 834, 848, 438, 548, 819, 533, 898, 777, 676, 284, 215, 95,
            811, 134, 338, 915, 12, 951, 124, 246, 365, 532, 359, 561, 280, 923, 236, 299, 916,
            394, 266, 946, 645, 872, 898, 228, 737, 229, 452, 562, 355, 403, 321, 161, 202, 983,
            306, 898, 172, 304, 921, 796, 232, 1011, 293, 183, 130, 376, 874, 1018, 501, 154, 747,
            62, 262, 185, 397, 208, 75, 933, 459, 687, 574, 803, 570, 635, 57, 548, 253, 970, 583,
            425, 626, 562, 96, 52, 715, 240, 58, 451, 888, 932, 179, 632, 605, 394, 941, 646, 286,
            217, 477, 443, 80, 639, 64, 139, 394, 227, 2, 927, 455, 719, 377, 533, 438, 120, 788,
            811, 650, 402, 240, 516, 354, 950, 372, 105, 247, 762, 445, 108, 1009, 862, 885, 870,
            53, 346, 392, 710, 434, 72, 899, 610, 543, 937, 501, 41, 615, 97, 557, 168, 105, 665,
            179, 708, 137, 849, 508, 742, 512, 879, 534, 490,
        ];
        let re = PolynomialRingElement::<SIMDUnit>::from_i32_array_test(&coefficients);

        let expected_bytes = [
            127, 204, 105, 133, 208, 207, 165, 130, 49, 2, 83, 82, 115, 127, 53, 65, 213, 119, 93,
            158, 174, 54, 213, 60, 116, 225, 122, 144, 175, 89, 147, 126, 25, 139, 206, 147, 140,
            159, 69, 91, 46, 37, 105, 25, 19, 23, 90, 134, 59, 166, 102, 56, 244, 118, 219, 127,
            212, 38, 191, 104, 183, 82, 249, 244, 32, 236, 147, 35, 119, 108, 39, 228, 200, 81, 56,
            164, 146, 139, 108, 41, 144, 31, 177, 222, 221, 156, 126, 121, 249, 151, 123, 31, 138,
            120, 239, 78, 3, 20, 86, 14, 200, 138, 129, 140, 180, 222, 82, 185, 139, 117, 245, 49,
            136, 254, 108, 195, 72, 41, 52, 212, 182, 145, 56, 115, 133, 130, 39, 76, 42, 71, 215,
            124, 177, 178, 33, 82, 77, 206, 192, 237, 124, 216, 211, 22, 133, 103, 197, 136, 209,
            230, 236, 172, 68, 185, 98, 10, 201, 94, 40, 218, 130, 147, 19, 110, 57, 196, 201, 56,
            214, 100, 65, 133, 162, 204, 245, 50, 9, 206, 10, 76, 153, 115, 140, 206, 252, 37, 221,
            34, 8, 94, 106, 235, 95, 159, 38, 235, 250, 96, 80, 46, 141, 65, 179, 68, 233, 203,
            189, 234, 227, 200, 58, 238, 153, 3, 137, 253, 40, 127, 100, 106, 114, 202, 8, 6, 13,
            203, 194, 163, 195, 112, 120, 147, 62, 11, 158, 93, 42, 214, 186, 161, 30, 101, 211,
            221, 110, 80, 252, 9, 196, 34, 138, 141, 35, 192, 231, 199, 61, 155, 87, 133, 182, 225,
            65, 241, 202, 138, 74, 6, 15, 129, 98, 217, 78, 87, 26, 247, 232, 219, 27, 27, 241,
            123, 93, 183, 217, 53, 104, 133, 152, 177, 178, 33, 49, 184, 152, 31, 166, 94, 95, 10,
            103, 134, 209, 34, 42, 105, 100, 58, 11, 177, 137, 68, 205, 159, 185, 0, 190, 109, 161,
            122,
        ];

        let mut result = [0u8; RING_ELEMENT_OF_T1S_SIZE];
        serialize::<SIMDUnit>(&re, &mut result);
        assert_eq!(result, expected_bytes);
    }

    fn test_deserialize_generic<SIMDUnit: Operations>() {
        let serialized = [
            119, 58, 128, 223, 132, 103, 124, 239, 83, 8, 180, 159, 151, 194, 206, 175, 85, 51, 94,
            182, 82, 48, 222, 183, 22, 181, 204, 94, 31, 8, 252, 22, 248, 249, 50, 217, 158, 209,
            158, 215, 152, 9, 2, 51, 197, 189, 243, 123, 155, 192, 182, 82, 253, 93, 123, 241, 67,
            175, 236, 91, 205, 195, 152, 48, 20, 117, 249, 157, 65, 105, 116, 191, 254, 179, 184,
            178, 86, 110, 123, 40, 127, 66, 226, 251, 180, 221, 70, 171, 27, 145, 75, 229, 102, 33,
            254, 69, 18, 55, 189, 90, 133, 26, 192, 66, 97, 120, 137, 64, 152, 90, 120, 254, 138,
            26, 134, 116, 225, 126, 160, 45, 255, 68, 150, 244, 125, 184, 189, 8, 190, 165, 31,
            108, 10, 207, 68, 166, 68, 47, 127, 232, 0, 52, 14, 171, 159, 205, 16, 200, 137, 149,
            99, 140, 175, 130, 58, 230, 43, 36, 18, 121, 248, 65, 112, 155, 184, 223, 79, 159, 176,
            172, 117, 19, 242, 54, 92, 36, 52, 236, 37, 34, 244, 231, 120, 103, 75, 78, 210, 112,
            74, 40, 36, 204, 49, 235, 223, 9, 78, 158, 49, 106, 179, 143, 198, 19, 74, 248, 57, 22,
            104, 205, 240, 27, 172, 23, 183, 127, 102, 172, 198, 106, 213, 26, 138, 197, 241, 15,
            103, 169, 114, 47, 115, 55, 79, 19, 238, 239, 64, 27, 173, 112, 148, 186, 212, 215, 67,
            162, 77, 110, 153, 19, 153, 109, 144, 25, 2, 98, 64, 191, 88, 138, 95, 115, 180, 131,
            19, 137, 77, 51, 9, 126, 146, 94, 25, 135, 222, 245, 80, 19, 39, 167, 171, 134, 144,
            34, 8, 15, 76, 179, 46, 39, 255, 150, 204, 84, 190, 181, 193, 4, 118, 35, 81, 105, 15,
            35, 233, 118, 139, 243, 93, 95, 164, 67, 55, 220, 228, 206, 104, 38, 25, 225,
        ];

        let expected_coefficients = [
            631, 14, 504, 531, 103, 991, 318, 33, 948, 487, 41, 827, 431, 213, 483, 729, 82, 908,
            893, 90, 181, 947, 501, 32, 764, 517, 927, 203, 729, 103, 493, 862, 408, 130, 816, 788,
            957, 764, 439, 770, 694, 852, 479, 493, 1009, 976, 714, 367, 973, 560, 777, 80, 373,
            894, 25, 421, 884, 943, 831, 738, 690, 917, 950, 161, 639, 144, 958, 723, 733, 721,
            442, 580, 331, 441, 534, 1016, 581, 452, 979, 362, 645, 6, 44, 389, 376, 34, 388, 362,
            632, 703, 424, 536, 372, 952, 519, 182, 255, 401, 841, 503, 440, 559, 992, 662, 31,
            667, 240, 275, 166, 977, 1010, 929, 0, 909, 688, 638, 205, 516, 156, 598, 99, 995, 42,
            234, 998, 266, 290, 484, 504, 16, 439, 738, 991, 979, 777, 690, 885, 132, 879, 368, 36,
            781, 606, 136, 1012, 569, 631, 301, 590, 52, 167, 161, 36, 115, 691, 895, 521, 915,
            793, 424, 947, 419, 316, 296, 504, 398, 641, 821, 1008, 774, 378, 732, 639, 793, 106,
            427, 725, 646, 88, 967, 783, 601, 810, 189, 883, 973, 308, 952, 239, 720, 721, 450,
            660, 302, 381, 271, 418, 915, 406, 78, 409, 27, 409, 8, 98, 976, 395, 553, 863, 284,
            59, 78, 393, 211, 147, 504, 658, 599, 113, 890, 245, 212, 625, 668, 683, 33, 553, 32,
            15, 211, 747, 156, 767, 805, 332, 761, 437, 304, 864, 141, 337, 986, 560, 932, 886,
            226, 479, 381, 932, 464, 451, 915, 206, 410, 402, 900,
        ];

        let mut deserialized = PolynomialRingElement::<SIMDUnit>::zero();
        deserialize::<SIMDUnit>(&serialized, &mut deserialized);
        assert_eq!(deserialized.to_i32_array(), expected_coefficients);
    }

    #[test]
    fn test_serialize_portable() {
        test_serialize_generic::<simd::portable::PortableSIMDUnit>();
    }

    #[test]
    fn test_deserialize_portable() {
        test_deserialize_generic::<simd::portable::PortableSIMDUnit>();
    }

    #[cfg(feature = "simd256")]
    #[test]
    fn test_serialize_simd256() {
        test_serialize_generic::<simd::avx2::AVX2SIMDUnit>();
    }

    #[cfg(feature = "simd256")]
    #[test]
    fn test_deserialize_simd256() {
        test_deserialize_generic::<simd::avx2::AVX2SIMDUnit>();
    }
}