Skip to content

Commit 4cce9a0

Browse files
committed
feat(common): gate the rigid protocol message scheme behind 'future_snark'
1 parent 529d805 commit 4cce9a0

4 files changed

Lines changed: 56 additions & 10 deletions

File tree

mithril-common/src/certificate_chain/certificate_verifier.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1445,6 +1445,7 @@ mod tests {
14451445
}
14461446
}
14471447

1448+
#[cfg(feature = "future_snark")]
14481449
mod rigid_protocol_message_dispatch {
14491450
use super::*;
14501451

@@ -1550,6 +1551,7 @@ mod tests {
15501551
}
15511552
}
15521553

1554+
#[cfg(feature = "future_snark")]
15531555
mod era_transition_chain_linkage {
15541556
use super::*;
15551557

mithril-common/src/entities/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,10 @@ pub use http_server_error::{ClientError, ServerError};
6767
pub use mithril_network::MithrilNetwork;
6868
pub use mithril_stake_distribution::MithrilStakeDistribution;
6969
pub use mk_set_proof::*;
70+
#[cfg(all(test, feature = "future_snark"))]
71+
pub(crate) use protocol_message::RigidProtocolMessageIntegrityError;
7072
pub use protocol_message::{
7173
ProtocolMessage, ProtocolMessageHashScheme, ProtocolMessagePartKey, ProtocolMessagePartValue,
72-
RIGID_NEXT_AGGREGATE_VERIFICATION_KEY_BYTES, RigidProtocolMessageIntegrityError,
7374
};
7475
pub use protocol_parameters::ProtocolParameters;
7576
pub use signable_manifest::*;

mithril-common/src/entities/protocol_message.rs

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
use serde::{Deserialize, Serialize};
22
use sha2::{Digest, Sha256};
33
use std::{collections::BTreeMap, fmt::Display};
4+
5+
#[cfg(feature = "future_snark")]
46
use thiserror::Error;
57

68
#[cfg(test)]
79
use crate::entities::Epoch;
810

911
/// Error returned by [ProtocolMessage::check_rigid_integrity] when a rigid-segment value
1012
/// in a [ProtocolMessage] does not match the fixed-size SNARK-friendly slot it must fill.
13+
#[cfg(feature = "future_snark")]
1114
#[derive(Debug, Error, PartialEq, Eq)]
1215
pub enum RigidProtocolMessageIntegrityError {
1316
/// The decoded value of a fixed-size rigid field does not match the expected byte length.
@@ -87,42 +90,52 @@ fn decode_protocol_parameters_to_rigid_slot_bytes(
8790

8891
/// [ProtocolMessagePartKey] entries projected into a fixed-size segment of the rigid preimage,
8992
/// and therefore stripped from the dynamic-parts digest segment.
93+
#[cfg(feature = "future_snark")]
9094
const RIGID_SEGMENT_KEYS: &[ProtocolMessagePartKey] = &[
9195
ProtocolMessagePartKey::NextSnarkAggregateVerificationKey,
9296
ProtocolMessagePartKey::NextProtocolParameters,
9397
ProtocolMessagePartKey::CurrentEpoch,
9498
];
9599

96-
/// Byte length of the `digest` value segment in the rigid preimage.
100+
/// Byte length of the `digest` value segment in the rigid preimage. Kept ungated because the
101+
/// legacy hash path also uses it as the SHA-256 output buffer width.
97102
pub const RIGID_DIGEST_BYTES: usize = 32;
98103

99104
/// Byte length of the `next_aggregate_verification_key` value segment in the rigid preimage.
100105
///
101106
/// The slot holds the SNARK-friendly aggregate verification key bytes (the value sourced from
102107
/// [ProtocolMessagePartKey::NextSnarkAggregateVerificationKey]).
108+
#[cfg(feature = "future_snark")]
103109
pub const RIGID_NEXT_AGGREGATE_VERIFICATION_KEY_BYTES: usize = 44;
104110

105111
/// Byte length of the `next_protocol_parameters` value segment in the rigid preimage.
112+
#[cfg(feature = "future_snark")]
106113
pub const RIGID_NEXT_PROTOCOL_PARAMETERS_BYTES: usize = 32;
107114

108115
/// Byte length of the `current_epoch` value segment in the rigid preimage.
116+
#[cfg(feature = "future_snark")]
109117
pub const RIGID_CURRENT_EPOCH_BYTES: usize = 8;
110118

111119
/// ASCII label written immediately before the `digest` value segment in the rigid preimage.
120+
#[cfg(feature = "future_snark")]
112121
const RIGID_DIGEST_LABEL: &[u8] = b"digest";
113122

114123
/// ASCII label written immediately before the `next_aggregate_verification_key` value segment in the rigid preimage.
124+
#[cfg(feature = "future_snark")]
115125
const RIGID_NEXT_AGGREGATE_VERIFICATION_KEY_LABEL: &[u8] = b"next_aggregate_verification_key";
116126

117127
/// ASCII label written immediately before the `next_protocol_parameters` value segment in the rigid preimage.
128+
#[cfg(feature = "future_snark")]
118129
const RIGID_NEXT_PROTOCOL_PARAMETERS_LABEL: &[u8] = b"next_protocol_parameters";
119130

120131
/// ASCII label written immediately before the `current_epoch` value segment in the rigid preimage.
132+
#[cfg(feature = "future_snark")]
121133
const RIGID_CURRENT_EPOCH_LABEL: &[u8] = b"current_epoch";
122134

123135
/// Byte length of the full rigid preimage that [ProtocolMessage::rigid_preimage] assembles when
124136
/// the hash scheme is [ProtocolMessageHashScheme::Rigid]. Each named segment is prefixed by its ASCII
125137
/// label, mirroring the layout consumed by the IVC SNARK gadget.
138+
#[cfg(feature = "future_snark")]
126139
const RIGID_PROTOCOL_MESSAGE_PREIMAGE_BYTES: usize = RIGID_DIGEST_LABEL.len()
127140
+ RIGID_DIGEST_BYTES
128141
+ RIGID_NEXT_AGGREGATE_VERIFICATION_KEY_LABEL.len()
@@ -143,6 +156,7 @@ pub enum ProtocolMessageHashScheme {
143156
Legacy,
144157

145158
/// Lagrange SNARK-friendly hash scheme.
159+
#[cfg(feature = "future_snark")]
146160
#[serde(rename = "rigid")]
147161
Rigid,
148162
}
@@ -267,6 +281,7 @@ impl ProtocolMessage {
267281

268282
/// [ProtocolMessage] factory returning the rigid (Lagrange) [ProtocolMessageHashScheme::Rigid]
269283
/// variant.
284+
#[cfg(feature = "future_snark")]
270285
pub fn new_rigid() -> ProtocolMessage {
271286
ProtocolMessage {
272287
message_parts: BTreeMap::new(),
@@ -293,20 +308,17 @@ impl ProtocolMessage {
293308
self.message_parts.get(key)
294309
}
295310

296-
/// Return `true` if the protocol message uses the [ProtocolMessageHashScheme::Rigid] hash
297-
/// scheme.
311+
/// Return `true` if the protocol message uses the rigid hash scheme.
298312
pub fn is_rigid(&self) -> bool {
299-
matches!(self.hash_scheme, ProtocolMessageHashScheme::Rigid)
313+
!matches!(self.hash_scheme, ProtocolMessageHashScheme::Legacy)
300314
}
301315

302-
/// Compute the hex-encoded SHA-256 hash of the protocol message.
303-
///
304-
/// Dispatches over [ProtocolMessage::hash_scheme]: the legacy scheme keeps the pre-Lagrange
305-
/// byte-identical output, the rigid scheme hashes the SNARK-friendly
306-
/// [rigid_preimage](ProtocolMessage::rigid_preimage).
316+
/// Compute the hex-encoded SHA-256 hash of the protocol message, dispatching over
317+
/// [ProtocolMessage::hash_scheme].
307318
pub fn compute_hash(&self) -> String {
308319
match self.hash_scheme {
309320
ProtocolMessageHashScheme::Legacy => self.compute_legacy_hash(),
321+
#[cfg(feature = "future_snark")]
310322
ProtocolMessageHashScheme::Rigid => self.compute_rigid_hash(),
311323
}
312324
}
@@ -324,6 +336,7 @@ impl ProtocolMessage {
324336
hex::encode(self.compute_legacy_digest_bytes())
325337
}
326338

339+
#[cfg(feature = "future_snark")]
327340
fn compute_rigid_hash(&self) -> String {
328341
hex::encode(Sha256::digest(self.rigid_preimage()))
329342
}
@@ -332,6 +345,7 @@ impl ProtocolMessage {
332345
/// `"digest" || digest_value || "next_aggregate_verification_key" || avk_value
333346
/// || "next_protocol_parameters" || protocol_parameters_value
334347
/// || "current_epoch" || current_epoch_value`.
348+
#[cfg(feature = "future_snark")]
335349
pub fn rigid_preimage(&self) -> Vec<u8> {
336350
let mut preimage = Vec::with_capacity(RIGID_PROTOCOL_MESSAGE_PREIMAGE_BYTES);
337351
preimage.extend_from_slice(RIGID_DIGEST_LABEL);
@@ -421,6 +435,7 @@ impl ProtocolMessage {
421435
/// strict check is bypassed, the verifier recomputes a preimage that does not match the
422436
/// signed bytes and the signature-vs-message check fails as a `match_message` mismatch
423437
/// instead of a typed error.
438+
#[cfg(feature = "future_snark")]
424439
fn rigid_next_aggregate_verification_key_field(
425440
&self,
426441
) -> [u8; RIGID_NEXT_AGGREGATE_VERIFICATION_KEY_BYTES] {
@@ -702,6 +717,7 @@ mod tests {
702717
protocol_message
703718
}
704719

720+
#[cfg(feature = "future_snark")]
705721
fn build_rigid_protocol_message_reference() -> ProtocolMessage {
706722
let mut message = ProtocolMessage::new_rigid();
707723
message.set_message_part(
@@ -735,6 +751,7 @@ mod tests {
735751
);
736752
}
737753

754+
#[cfg(feature = "future_snark")]
738755
#[test]
739756
fn new_rigid_returns_a_message_with_rigid_hash_scheme() {
740757
let protocol_message = ProtocolMessage::new_rigid();
@@ -746,6 +763,7 @@ mod tests {
746763
);
747764
}
748765

766+
#[cfg(feature = "future_snark")]
749767
#[test]
750768
fn set_message_part_works_same_on_every_hash_scheme() {
751769
let mut legacy = ProtocolMessage::new();
@@ -764,6 +782,7 @@ mod tests {
764782
);
765783
}
766784

785+
#[cfg(feature = "future_snark")]
767786
#[test]
768787
fn legacy_and_rigid_compute_hash_outputs_do_not_collide_on_same_map() {
769788
let mut legacy = build_protocol_message_reference();
@@ -775,6 +794,7 @@ mod tests {
775794
assert_eq!(legacy.compute_hash(), rigid.compute_hash());
776795
}
777796

797+
#[cfg(feature = "future_snark")]
778798
#[test]
779799
fn rigid_compute_hash_produces_a_hex_encoded_32_bytes_digest() {
780800
let rigid = build_rigid_protocol_message_reference();
@@ -786,6 +806,7 @@ mod tests {
786806
assert_eq!(decoded.len(), 32);
787807
}
788808

809+
#[cfg(feature = "future_snark")]
789810
#[test]
790811
fn rigid_preimage_has_expected_fixed_byte_length() {
791812
let rigid = ProtocolMessage::new_rigid();
@@ -795,6 +816,7 @@ mod tests {
795816
assert_eq!(preimage.len(), RIGID_PROTOCOL_MESSAGE_PREIMAGE_BYTES);
796817
}
797818

819+
#[cfg(feature = "future_snark")]
798820
#[test]
799821
fn rigid_preimage_concatenates_labeled_segments_in_a_fixed_order() {
800822
let rigid = build_rigid_protocol_message_reference();
@@ -812,6 +834,7 @@ mod tests {
812834
assert_eq!(rigid.rigid_preimage(), expected);
813835
}
814836

837+
#[cfg(feature = "future_snark")]
815838
#[test]
816839
fn rigid_preimage_layout_pins_label_offsets_and_segment_lengths() {
817840
let rigid = build_rigid_protocol_message_reference();
@@ -884,6 +907,7 @@ mod tests {
884907
);
885908
}
886909

910+
#[cfg(feature = "future_snark")]
887911
#[test]
888912
fn rigid_preimage_total_byte_length_is_pinned_to_one_hundred_ninety() {
889913
let rigid = build_rigid_protocol_message_reference();
@@ -895,6 +919,7 @@ mod tests {
895919
);
896920
}
897921

922+
#[cfg(feature = "future_snark")]
898923
#[test]
899924
fn rigid_preimage_sources_aggregate_verification_key_segment_from_snark_avk_value() {
900925
let mut message = ProtocolMessage::new_rigid();
@@ -922,6 +947,7 @@ mod tests {
922947
assert_eq!(restored.hash_scheme, ProtocolMessageHashScheme::Legacy);
923948
}
924949

950+
#[cfg(feature = "future_snark")]
925951
#[test]
926952
fn serde_round_trips_rigid_shape() {
927953
let protocol_message = build_rigid_protocol_message_reference();
@@ -952,6 +978,7 @@ mod tests {
952978
);
953979
}
954980

981+
#[cfg(feature = "future_snark")]
955982
#[test]
956983
fn rigid_wire_shape_exposes_hash_scheme_discriminator() {
957984
let protocol_message = build_rigid_protocol_message_reference();
@@ -1012,6 +1039,7 @@ mod tests {
10121039
);
10131040
}
10141041

1042+
#[cfg(feature = "future_snark")]
10151043
#[test]
10161044
fn rigid_next_protocol_parameters_field_holds_raw_hex_decoded_bytes() {
10171045
let mut message = ProtocolMessage::new_rigid();
@@ -1024,6 +1052,7 @@ mod tests {
10241052
assert_eq!(message.rigid_next_protocol_parameters_field(), raw);
10251053
}
10261054

1055+
#[cfg(feature = "future_snark")]
10271056
#[test]
10281057
fn rigid_current_epoch_field_is_little_endian_encoded_parsed_integer() {
10291058
let mut message = ProtocolMessage::new_rigid();
@@ -1032,6 +1061,7 @@ mod tests {
10321061
assert_eq!(message.rigid_current_epoch_field(), 7u64.to_le_bytes());
10331062
}
10341063

1064+
#[cfg(feature = "future_snark")]
10351065
#[test]
10361066
fn stripped_for_rigid_digest_drops_only_rigid_segment_keys_and_forces_legacy_hash_scheme() {
10371067
let mut rigid = build_rigid_protocol_message_reference();
@@ -1056,6 +1086,7 @@ mod tests {
10561086
);
10571087
}
10581088

1089+
#[cfg(feature = "future_snark")]
10591090
#[test]
10601091
fn rigid_digest_field_is_invariant_under_changes_of_rigid_segment_keys() {
10611092
let mut base = build_rigid_protocol_message_reference();
@@ -1072,6 +1103,7 @@ mod tests {
10721103
);
10731104
}
10741105

1106+
#[cfg(feature = "future_snark")]
10751107
#[test]
10761108
fn rigid_compute_hash_changes_when_digest_related_parts_change() {
10771109
let mut base = build_rigid_protocol_message_reference();
@@ -1109,6 +1141,7 @@ mod tests {
11091141
assert_eq!(message.get_current_epoch(), None);
11101142
}
11111143

1144+
#[cfg(feature = "future_snark")]
11121145
#[test]
11131146
fn rigid_preimage_is_byte_identical_to_a_hand_built_labeled_concatenation() {
11141147
let snark_avk_bytes = [5u8; RIGID_NEXT_AGGREGATE_VERIFICATION_KEY_BYTES];
@@ -1150,6 +1183,7 @@ mod tests {
11501183
);
11511184
}
11521185

1186+
#[cfg(feature = "future_snark")]
11531187
#[test]
11541188
fn check_rigid_integrity_is_a_no_op_for_legacy_protocol_messages() {
11551189
let legacy = build_protocol_message_reference();
@@ -1159,6 +1193,7 @@ mod tests {
11591193
.expect("legacy protocol message must skip the rigid layout check");
11601194
}
11611195

1196+
#[cfg(feature = "future_snark")]
11621197
#[test]
11631198
fn check_rigid_integrity_succeeds_on_a_well_formed_rigid_protocol_message() {
11641199
let rigid = build_rigid_protocol_message_reference();
@@ -1168,6 +1203,7 @@ mod tests {
11681203
.expect("a well-formed rigid protocol message must pass the integrity check");
11691204
}
11701205

1206+
#[cfg(feature = "future_snark")]
11711207
#[test]
11721208
fn check_rigid_integrity_allows_an_empty_dynamic_digest_projection() {
11731209
let mut rigid = ProtocolMessage::new_rigid();
@@ -1186,6 +1222,7 @@ mod tests {
11861222
.expect("an empty dynamic-parts projection must be accepted");
11871223
}
11881224

1225+
#[cfg(feature = "future_snark")]
11891226
#[test]
11901227
fn check_rigid_integrity_fails_when_next_snark_avk_entry_is_missing() {
11911228
let mut rigid = build_rigid_protocol_message_reference();
@@ -1203,6 +1240,7 @@ mod tests {
12031240
);
12041241
}
12051242

1243+
#[cfg(feature = "future_snark")]
12061244
#[test]
12071245
fn check_rigid_integrity_fails_when_next_snark_avk_decodes_to_unexpected_length() {
12081246
let mut rigid = build_rigid_protocol_message_reference();
@@ -1225,6 +1263,7 @@ mod tests {
12251263
);
12261264
}
12271265

1266+
#[cfg(feature = "future_snark")]
12281267
#[test]
12291268
fn check_rigid_integrity_fails_when_next_protocol_parameters_entry_is_missing() {
12301269
let mut rigid = build_rigid_protocol_message_reference();
@@ -1242,6 +1281,7 @@ mod tests {
12421281
);
12431282
}
12441283

1284+
#[cfg(feature = "future_snark")]
12451285
#[test]
12461286
fn check_rigid_integrity_fails_when_next_protocol_parameters_decodes_to_unexpected_length() {
12471287
let mut rigid = build_rigid_protocol_message_reference();
@@ -1264,6 +1304,7 @@ mod tests {
12641304
);
12651305
}
12661306

1307+
#[cfg(feature = "future_snark")]
12671308
#[test]
12681309
fn check_rigid_integrity_fails_when_current_epoch_entry_is_missing() {
12691310
let mut rigid = build_rigid_protocol_message_reference();
@@ -1279,6 +1320,7 @@ mod tests {
12791320
);
12801321
}
12811322

1323+
#[cfg(feature = "future_snark")]
12821324
#[test]
12831325
fn check_rigid_integrity_fails_when_current_epoch_is_not_a_decimal_unsigned_integer() {
12841326
let mut rigid = build_rigid_protocol_message_reference();

mithril-common/src/signable_builder/signable_builder_service.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ impl SignableBuilderService for MithrilSignableBuilderService {
210210
.compute_signed_entity_protocol_message(signed_entity_type)
211211
.await?;
212212
let protocol_message = self.compute_seeded_protocol_message(protocol_message).await?;
213+
#[cfg(feature = "future_snark")]
213214
protocol_message.check_rigid_integrity().with_context(
214215
|| "Signable builder service produced a protocol message that violates the rigid layout",
215216
)?;

0 commit comments

Comments
 (0)