|
1 | 1 | """ |
2 | | -Defines the cryptographic constants for the XMSS specification. |
| 2 | +Defines the cryptographic constants and configuration presets for the |
| 3 | +XMSS spec. |
3 | 4 |
|
4 | 5 | This specification corresponds to the "hashing-optimized" Top Level Target Sum |
5 | | -instantiation from the canonical Rust implementation. |
| 6 | +instantiation from the canonical Rust implementation |
| 7 | +(production instantiation). |
| 8 | +
|
| 9 | +We also provide a test instantiation for testing purposes. |
6 | 10 |
|
7 | 11 | .. note:: |
8 | 12 | This specification uses the **KoalaBear** prime field, which is consistent |
|
14 | 18 | specification in the future. |
15 | 19 | """ |
16 | 20 |
|
| 21 | +from pydantic import BaseModel, ConfigDict |
| 22 | +from typing_extensions import Final |
| 23 | + |
17 | 24 | from ..koalabear import Fp |
18 | 25 |
|
19 | | -# ================================================================= |
20 | | -# Core Scheme Configuration |
21 | | -# ================================================================= |
22 | 26 |
|
23 | | -MESSAGE_LENGTH: int = 32 |
24 | | -"""The length in bytes for all messages to be signed.""" |
| 27 | +class XmssConfig(BaseModel): |
| 28 | + """A model holding the configuration constants for an XMSS preset.""" |
25 | 29 |
|
26 | | -LOG_LIFETIME: int = 32 |
27 | | -"""The base-2 logarithm of the scheme's maximum lifetime.""" |
| 30 | + model_config = ConfigDict(frozen=True, extra="forbid") |
28 | 31 |
|
29 | | -LIFETIME: int = 1 << LOG_LIFETIME |
30 | | -""" |
31 | | -The maximum number of epochs supported by this configuration. |
| 32 | + # --- Core Scheme Configuration --- |
| 33 | + MESSAGE_LENGTH: int |
| 34 | + """The length in bytes for all messages to be signed.""" |
32 | 35 |
|
33 | | -An individual key pair can be active for a smaller sub-range. |
34 | | -""" |
| 36 | + LOG_LIFETIME: int |
| 37 | + """The base-2 logarithm of the scheme's maximum lifetime.""" |
35 | 38 |
|
| 39 | + @property |
| 40 | + def LIFETIME(self) -> int: # noqa: N802 |
| 41 | + """ |
| 42 | + The maximum number of epochs supported by this configuration. |
36 | 43 |
|
37 | | -# ================================================================= |
38 | | -# Target Sum WOTS Parameters |
39 | | -# ================================================================= |
| 44 | + An individual key pair can be active for a smaller sub-range. |
| 45 | + """ |
| 46 | + return 1 << self.LOG_LIFETIME |
40 | 47 |
|
41 | | -DIMENSION: int = 64 |
42 | | -"""The total number of hash chains, `v`.""" |
| 48 | + DIMENSION: int |
| 49 | + """The total number of hash chains, `v`.""" |
43 | 50 |
|
44 | | -BASE: int = 8 |
45 | | -"""The alphabet size for the digits of the encoded message.""" |
| 51 | + BASE: int |
| 52 | + """The alphabet size for the digits of the encoded message.""" |
46 | 53 |
|
47 | | -FINAL_LAYER: int = 77 |
48 | | -"""The number of top layers of the hypercube to map the hash output into.""" |
| 54 | + FINAL_LAYER: int |
| 55 | + """Number of top layers of the hypercube to map the hash output into.""" |
49 | 56 |
|
50 | | -TARGET_SUM: int = 375 |
51 | | -"""The required sum of all codeword chunks for a signature to be valid.""" |
| 57 | + TARGET_SUM: int |
| 58 | + """The required sum of all codeword chunks for a signature to be valid.""" |
52 | 59 |
|
| 60 | + MAX_TRIES: int |
| 61 | + """ |
| 62 | + How often one should try at most to resample a random value. |
53 | 63 |
|
54 | | -# ================================================================= |
55 | | -# Hash and Encoding Length Parameters (in field elements) |
56 | | -# ================================================================= |
| 64 | + This is currently based on experiments with the Rust implementation. |
| 65 | + Should probably be modified in production. |
| 66 | + """ |
57 | 67 |
|
58 | | -PARAMETER_LEN: int = 5 |
59 | | -""" |
60 | | -The length of the public parameter `P`. |
| 68 | + PARAMETER_LEN: int |
| 69 | + """ |
| 70 | + The length of the public parameter `P`. |
61 | 71 |
|
62 | | -It is used to specialize the hash function. |
63 | | -""" |
| 72 | + It is used to specialize the hash function. |
| 73 | + """ |
64 | 74 |
|
65 | | -TWEAK_LEN_FE: int = 2 |
66 | | -"""The length of a domain-separating tweak.""" |
| 75 | + TWEAK_LEN_FE: int |
| 76 | + """The length of a domain-separating tweak.""" |
67 | 77 |
|
68 | | -MSG_LEN_FE: int = 9 |
69 | | -"""The length of a message after being encoded into field elements.""" |
| 78 | + MSG_LEN_FE: int |
| 79 | + """The length of a message after being encoded into field elements.""" |
70 | 80 |
|
71 | | -RAND_LEN_FE: int = 7 |
72 | | -"""The length of the randomness `rho` used during message encoding.""" |
| 81 | + RAND_LEN_FE: int |
| 82 | + """The length of the randomness `rho` used during message encoding.""" |
73 | 83 |
|
74 | | -HASH_LEN_FE: int = 8 |
75 | | -"""The output length of the main tweakable hash function.""" |
| 84 | + HASH_LEN_FE: int |
| 85 | + """The output length of the main tweakable hash function.""" |
76 | 86 |
|
77 | | -CAPACITY: int = 9 |
78 | | -"""The capacity of the Poseidon2 sponge, defining its security level.""" |
| 87 | + CAPACITY: int |
| 88 | + """The capacity of the Poseidon2 sponge, defining its security level.""" |
79 | 89 |
|
80 | | -POS_OUTPUT_LEN_PER_INV_FE: int = 15 |
81 | | -"""Output length per invocation for the message hash.""" |
| 90 | + POS_OUTPUT_LEN_PER_INV_FE: int |
| 91 | + """Output length per invocation for the message hash.""" |
82 | 92 |
|
83 | | -POS_INVOCATIONS: int = 1 |
84 | | -"""Number of invocations for the message hash.""" |
| 93 | + POS_INVOCATIONS: int |
| 94 | + """Number of invocations for the message hash.""" |
85 | 95 |
|
86 | | -POS_OUTPUT_LEN_FE: int = POS_OUTPUT_LEN_PER_INV_FE * POS_INVOCATIONS |
87 | | -"""Total output length for the message hash.""" |
| 96 | + @property |
| 97 | + def POS_OUTPUT_LEN_FE(self) -> int: # noqa: N802 |
| 98 | + """Total output length for the message hash.""" |
| 99 | + return self.POS_OUTPUT_LEN_PER_INV_FE * self.POS_INVOCATIONS |
88 | 100 |
|
89 | 101 |
|
90 | | -# ================================================================= |
91 | | -# Domain Separator Prefixes for Tweaks |
92 | | -# ================================================================= |
| 102 | +PROD_CONFIG: Final = XmssConfig( |
| 103 | + MESSAGE_LENGTH=32, |
| 104 | + LOG_LIFETIME=32, |
| 105 | + DIMENSION=64, |
| 106 | + BASE=8, |
| 107 | + FINAL_LAYER=77, |
| 108 | + TARGET_SUM=375, |
| 109 | + MAX_TRIES=100_000, |
| 110 | + PARAMETER_LEN=5, |
| 111 | + TWEAK_LEN_FE=2, |
| 112 | + MSG_LEN_FE=9, |
| 113 | + RAND_LEN_FE=7, |
| 114 | + HASH_LEN_FE=8, |
| 115 | + CAPACITY=9, |
| 116 | + POS_OUTPUT_LEN_PER_INV_FE=15, |
| 117 | + POS_INVOCATIONS=1, |
| 118 | +) |
93 | 119 |
|
94 | | -TWEAK_PREFIX_CHAIN = Fp(value=0x00) |
| 120 | + |
| 121 | +TEST_CONFIG: Final = XmssConfig( |
| 122 | + MESSAGE_LENGTH=32, |
| 123 | + LOG_LIFETIME=8, |
| 124 | + DIMENSION=16, |
| 125 | + BASE=4, |
| 126 | + FINAL_LAYER=24, |
| 127 | + TARGET_SUM=24, |
| 128 | + MAX_TRIES=100_000, |
| 129 | + PARAMETER_LEN=5, |
| 130 | + TWEAK_LEN_FE=2, |
| 131 | + MSG_LEN_FE=9, |
| 132 | + RAND_LEN_FE=7, |
| 133 | + HASH_LEN_FE=8, |
| 134 | + CAPACITY=9, |
| 135 | + POS_OUTPUT_LEN_PER_INV_FE=15, |
| 136 | + POS_INVOCATIONS=1, |
| 137 | +) |
| 138 | + |
| 139 | + |
| 140 | +TWEAK_PREFIX_CHAIN: Final = Fp(value=0x00) |
95 | 141 | """The unique prefix for tweaks used in Winternitz-style hash chains.""" |
96 | 142 |
|
97 | | -TWEAK_PREFIX_TREE = Fp(value=0x01) |
| 143 | +TWEAK_PREFIX_TREE: Final = Fp(value=0x01) |
98 | 144 | """The unique prefix for tweaks used when hashing Merkle tree nodes.""" |
99 | 145 |
|
100 | | -TWEAK_PREFIX_MESSAGE = Fp(value=0x02) |
| 146 | +TWEAK_PREFIX_MESSAGE: Final = Fp(value=0x02) |
101 | 147 | """The unique prefix for tweaks used in the initial message hashing step.""" |
| 148 | + |
| 149 | +PRF_KEY_LENGTH: int = 32 |
| 150 | +"""The length of the PRF secret key in bytes.""" |
0 commit comments