Skip to main content

sqisign_verify/params/
level1.rs

1//!
2//! Prime: `p = 5 * 2^248 - 1` (251 bits).
3//! Field uses 5 limbs of 51-bit radix (unsaturated Montgomery form).
4
5use super::{Level1, SecurityLevel};
6use hybrid_array::sizes::{U129, U148, U212, U288, U32, U4, U5, U64, U65};
7
8/// The Level 1 prime `p = 5 * 2^248 - 1` as 32 little-endian bytes.
9///
10/// In hex this is `0x04ff..ff` (top byte `0x04`, then 31 bytes of `0xff`),
11/// matching `p` in `sqisign_parameters.txt`.
12pub const PRIME_LE_BYTES: [u8; 32] = {
13    let mut bytes = [0xffu8; 32];
14    bytes[31] = 0x04;
15    bytes
16};
17
18impl SecurityLevel for Level1 {
19    /// 5 limbs × 51-bit radix = 255 bits of storage for the 251-bit prime.
20    type FpLimbs = U5;
21    /// 4 limbs × 64 bits = 256-bit scalars for order arithmetic.
22    type MpLimbs = U4;
23    /// `p` fits in 32 bytes (251 bits).
24    type FpEncodedBytes = U32;
25    /// Two `Fp` elements = 64 bytes.
26    type Fp2EncodedBytes = U64;
27    /// Public key: 1-byte header + 2 × 32 bytes for the `Fp2` j-invariant.
28    type PkLen = U65;
29    /// Standard signature (148 bytes).
30    type SigLen = U148;
31    /// Expanded signature (212 bytes).
32    type ExpandedSigLen = U212;
33    /// Compressed signature (129 bytes).
34    type CompressedSigLen = U129;
35    /// Secret key: ideal norm + generator coords + basis-change matrix (288 bytes).
36    type SkLen = U288;
37
38    fn prime_le_bytes() -> &'static [u8] {
39        &PRIME_LE_BYTES
40    }
41
42    /// 128-bit post-quantum security.
43    const LAMBDA: u32 = 128;
44
45    /// `p + 1 = 5 × 2^248`, so the full `2^248`-torsion is available.
46    const F_CHR: u32 = 248;
47    /// Response isogeny has degree `2^126`.
48    const E_RSP: u32 = 126;
49    /// Challenge scalar is 128 bits (matching `LAMBDA`).
50    const E_CHL: u32 = 128;
51    /// Up to 64 SHAKE256 squeeze attempts to find a valid challenge.
52    const HASH_ITERATIONS: u32 = 64;
53    /// 4 limbs × 64 = 256-bit scalar width.
54    const NWORDS_ORDER: usize = 4;
55    /// `v_2(p + 1) = 248`.
56    const TORSION_EVEN_POWER: u32 = 248;
57    /// `(p + 1) / 2^248 = 5`, which is 3 bits.
58    const P_COFACTOR_FOR_2F_BITLENGTH: usize = 3;
59    /// Response isogeny length = 126 bits (same as `E_RSP`).
60    const SQISIGN_RESPONSE_LENGTH: u32 = 126;
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66
67    /// Reconstruct `p` from `PRIME_LE_BYTES` and verify it equals
68    /// `5 * 2^248 - 1`.
69    ///
70    /// We do the comparison limb-by-limb: little-endian, bytes 0..31 all
71    /// `0xFF` except byte 31 which is `0x04`. The integer is therefore
72    /// `4 * 2^248 + (2^248 - 1) = 5 * 2^248 - 1`.
73    #[test]
74    fn level1_prime_is_correct() {
75        let bytes = Level1::prime_le_bytes();
76        assert_eq!(bytes.len(), 32);
77        for &b in &bytes[..31] {
78            assert_eq!(b, 0xFF, "low 31 bytes of p must all be 0xFF");
79        }
80        assert_eq!(bytes[31], 0x04, "top byte of p must be 0x04");
81    }
82
83    /// `p = 5 * 2^248 - 1`, so `p mod 4 = (5*2^248 mod 4) - 1 mod 4 =
84    /// 0 - 1 mod 4 = 3`. Required for the 𝔽p² = 𝔽p[i]/(i² + 1)
85    /// construction and the Fermat-style `Fp` square root.
86    #[test]
87    fn level1_prime_is_3_mod_4() {
88        let bytes = Level1::prime_le_bytes();
89        // Bottom byte determines the value mod 4 (since 256 = 0 mod 4).
90        assert_eq!(bytes[0] & 0b11, 3, "p mod 4 must be 3");
91    }
92
93    /// Sanity: protocol exponents are in expected ranges. The two
94    /// `const _: () = assert!(...)` blocks fire at compile time if the
95    /// invariants are violated by future edits; the runtime asserts
96    /// just make the constants observable in the test output.
97    const _: () = assert!(Level1::F_CHR > Level1::LAMBDA);
98    const _: () = assert!(Level1::E_RSP > 0);
99
100    #[test]
101    fn level1_protocol_exponents_in_range() {
102        assert_eq!(Level1::LAMBDA, 128);
103        assert_eq!(Level1::F_CHR, 248);
104        assert_eq!(Level1::E_RSP, 126);
105    }
106}