1use std::{
5 borrow::Cow,
6 cmp,
7 ops::{Index, IndexMut},
8};
9
10use binius_utils::serialization::{DeserializeBytes, SerializationError, SerializeBytes};
11use bytes::{Buf, BufMut};
12
13use crate::{consts, error::ConstraintSystemError, word::Word};
14
15#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
17pub struct ValueIndex(pub u32);
18
19impl ValueIndex {
20 pub const INVALID: ValueIndex = ValueIndex(u32::MAX);
22}
23
24impl Default for ValueIndex {
26 fn default() -> Self {
27 Self::INVALID
28 }
29}
30
31impl SerializeBytes for ValueIndex {
32 fn serialize(&self, write_buf: impl BufMut) -> Result<(), SerializationError> {
33 self.0.serialize(write_buf)
34 }
35}
36
37impl DeserializeBytes for ValueIndex {
38 fn deserialize(read_buf: impl Buf) -> Result<Self, SerializationError>
39 where
40 Self: Sized,
41 {
42 Ok(ValueIndex(u32::deserialize(read_buf)?))
43 }
44}
45
46#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
50pub enum ShiftVariant {
51 Sll,
53 Slr,
55 Sar,
60 Rotr,
64 Sll32,
69 Srl32,
74 Sra32,
80 Rotr32,
86}
87
88impl SerializeBytes for ShiftVariant {
89 fn serialize(&self, write_buf: impl BufMut) -> Result<(), SerializationError> {
90 let index = match self {
91 ShiftVariant::Sll => 0u8,
92 ShiftVariant::Slr => 1u8,
93 ShiftVariant::Sar => 2u8,
94 ShiftVariant::Rotr => 3u8,
95 ShiftVariant::Sll32 => 4u8,
96 ShiftVariant::Srl32 => 5u8,
97 ShiftVariant::Sra32 => 6u8,
98 ShiftVariant::Rotr32 => 7u8,
99 };
100 index.serialize(write_buf)
101 }
102}
103
104impl DeserializeBytes for ShiftVariant {
105 fn deserialize(read_buf: impl Buf) -> Result<Self, SerializationError>
106 where
107 Self: Sized,
108 {
109 let index = u8::deserialize(read_buf)?;
110 match index {
111 0 => Ok(ShiftVariant::Sll),
112 1 => Ok(ShiftVariant::Slr),
113 2 => Ok(ShiftVariant::Sar),
114 3 => Ok(ShiftVariant::Rotr),
115 4 => Ok(ShiftVariant::Sll32),
116 5 => Ok(ShiftVariant::Srl32),
117 6 => Ok(ShiftVariant::Sra32),
118 7 => Ok(ShiftVariant::Rotr32),
119 _ => Err(SerializationError::UnknownEnumVariant {
120 name: "ShiftVariant",
121 index,
122 }),
123 }
124 }
125}
126
127#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
134pub struct ShiftedValueIndex {
135 pub value_index: ValueIndex,
137 pub shift_variant: ShiftVariant,
139 pub amount: usize,
143}
144
145impl ShiftedValueIndex {
146 pub fn plain(value_index: ValueIndex) -> Self {
149 Self {
150 value_index,
151 shift_variant: ShiftVariant::Sll,
152 amount: 0,
153 }
154 }
155
156 pub fn sll(value_index: ValueIndex, amount: usize) -> Self {
161 assert!(amount < 64, "shift amount n={amount} out of range");
162 Self {
163 value_index,
164 shift_variant: ShiftVariant::Sll,
165 amount,
166 }
167 }
168
169 pub fn srl(value_index: ValueIndex, amount: usize) -> Self {
174 assert!(amount < 64, "shift amount n={amount} out of range");
175 Self {
176 value_index,
177 shift_variant: ShiftVariant::Slr,
178 amount,
179 }
180 }
181
182 pub fn sar(value_index: ValueIndex, amount: usize) -> Self {
190 assert!(amount < 64, "shift amount n={amount} out of range");
191 Self {
192 value_index,
193 shift_variant: ShiftVariant::Sar,
194 amount,
195 }
196 }
197
198 pub fn rotr(value_index: ValueIndex, amount: usize) -> Self {
205 assert!(amount < 64, "shift amount n={amount} out of range");
206 Self {
207 value_index,
208 shift_variant: ShiftVariant::Rotr,
209 amount,
210 }
211 }
212
213 pub fn sll32(value_index: ValueIndex, amount: usize) -> Self {
221 assert!(amount < 32, "shift amount n={amount} out of range for 32-bit shift");
222 Self {
223 value_index,
224 shift_variant: ShiftVariant::Sll32,
225 amount,
226 }
227 }
228
229 pub fn srl32(value_index: ValueIndex, amount: usize) -> Self {
237 assert!(amount < 32, "shift amount n={amount} out of range for 32-bit shift");
238 Self {
239 value_index,
240 shift_variant: ShiftVariant::Srl32,
241 amount,
242 }
243 }
244
245 pub fn sra32(value_index: ValueIndex, amount: usize) -> Self {
254 assert!(amount < 32, "shift amount n={amount} out of range for 32-bit shift");
255 Self {
256 value_index,
257 shift_variant: ShiftVariant::Sra32,
258 amount,
259 }
260 }
261
262 pub fn rotr32(value_index: ValueIndex, amount: usize) -> Self {
271 assert!(amount < 32, "shift amount n={amount} out of range for 32-bit rotate");
272 Self {
273 value_index,
274 shift_variant: ShiftVariant::Rotr32,
275 amount,
276 }
277 }
278}
279
280impl SerializeBytes for ShiftedValueIndex {
281 fn serialize(&self, mut write_buf: impl BufMut) -> Result<(), SerializationError> {
282 self.value_index.serialize(&mut write_buf)?;
283 self.shift_variant.serialize(&mut write_buf)?;
284 self.amount.serialize(write_buf)
285 }
286}
287
288impl DeserializeBytes for ShiftedValueIndex {
289 fn deserialize(mut read_buf: impl Buf) -> Result<Self, SerializationError>
290 where
291 Self: Sized,
292 {
293 let value_index = ValueIndex::deserialize(&mut read_buf)?;
294 let shift_variant = ShiftVariant::deserialize(&mut read_buf)?;
295 let amount = usize::deserialize(read_buf)?;
296
297 if amount >= 64 {
299 return Err(SerializationError::InvalidConstruction {
300 name: "ShiftedValueIndex::amount",
301 });
302 }
303
304 Ok(ShiftedValueIndex {
305 value_index,
306 shift_variant,
307 amount,
308 })
309 }
310}
311
312pub type Operand = Vec<ShiftedValueIndex>;
326
327#[derive(Debug, Clone, Default)]
332pub struct AndConstraint {
333 pub a: Operand,
335 pub b: Operand,
337 pub c: Operand,
339}
340
341impl AndConstraint {
342 pub fn plain_abc(
344 a: impl IntoIterator<Item = ValueIndex>,
345 b: impl IntoIterator<Item = ValueIndex>,
346 c: impl IntoIterator<Item = ValueIndex>,
347 ) -> AndConstraint {
348 AndConstraint {
349 a: a.into_iter().map(ShiftedValueIndex::plain).collect(),
350 b: b.into_iter().map(ShiftedValueIndex::plain).collect(),
351 c: c.into_iter().map(ShiftedValueIndex::plain).collect(),
352 }
353 }
354
355 pub fn abc(
357 a: impl IntoIterator<Item = ShiftedValueIndex>,
358 b: impl IntoIterator<Item = ShiftedValueIndex>,
359 c: impl IntoIterator<Item = ShiftedValueIndex>,
360 ) -> AndConstraint {
361 AndConstraint {
362 a: a.into_iter().collect(),
363 b: b.into_iter().collect(),
364 c: c.into_iter().collect(),
365 }
366 }
367}
368
369impl SerializeBytes for AndConstraint {
370 fn serialize(&self, mut write_buf: impl BufMut) -> Result<(), SerializationError> {
371 self.a.serialize(&mut write_buf)?;
372 self.b.serialize(&mut write_buf)?;
373 self.c.serialize(write_buf)
374 }
375}
376
377impl DeserializeBytes for AndConstraint {
378 fn deserialize(mut read_buf: impl Buf) -> Result<Self, SerializationError>
379 where
380 Self: Sized,
381 {
382 let a = Vec::<ShiftedValueIndex>::deserialize(&mut read_buf)?;
383 let b = Vec::<ShiftedValueIndex>::deserialize(&mut read_buf)?;
384 let c = Vec::<ShiftedValueIndex>::deserialize(read_buf)?;
385
386 Ok(AndConstraint { a, b, c })
387 }
388}
389
390#[derive(Debug, Clone, Default)]
395pub struct MulConstraint {
396 pub a: Operand,
398 pub b: Operand,
400 pub hi: Operand,
404 pub lo: Operand,
408}
409
410impl SerializeBytes for MulConstraint {
411 fn serialize(&self, mut write_buf: impl BufMut) -> Result<(), SerializationError> {
412 self.a.serialize(&mut write_buf)?;
413 self.b.serialize(&mut write_buf)?;
414 self.hi.serialize(&mut write_buf)?;
415 self.lo.serialize(write_buf)
416 }
417}
418
419impl DeserializeBytes for MulConstraint {
420 fn deserialize(mut read_buf: impl Buf) -> Result<Self, SerializationError>
421 where
422 Self: Sized,
423 {
424 let a = Vec::<ShiftedValueIndex>::deserialize(&mut read_buf)?;
425 let b = Vec::<ShiftedValueIndex>::deserialize(&mut read_buf)?;
426 let hi = Vec::<ShiftedValueIndex>::deserialize(&mut read_buf)?;
427 let lo = Vec::<ShiftedValueIndex>::deserialize(read_buf)?;
428
429 Ok(MulConstraint { a, b, hi, lo })
430 }
431}
432
433#[derive(Debug, Clone)]
442pub struct ConstraintSystem {
443 pub value_vec_layout: ValueVecLayout,
445 pub constants: Vec<Word>,
450 pub and_constraints: Vec<AndConstraint>,
452 pub mul_constraints: Vec<MulConstraint>,
454}
455
456impl ConstraintSystem {
457 pub const SERIALIZATION_VERSION: u32 = 2;
459}
460
461impl ConstraintSystem {
462 pub fn new(
464 constants: Vec<Word>,
465 value_vec_layout: ValueVecLayout,
466 and_constraints: Vec<AndConstraint>,
467 mul_constraints: Vec<MulConstraint>,
468 ) -> Self {
469 assert_eq!(constants.len(), value_vec_layout.n_const);
470 ConstraintSystem {
471 constants,
472 value_vec_layout,
473 and_constraints,
474 mul_constraints,
475 }
476 }
477
478 pub fn validate(&self) -> Result<(), ConstraintSystemError> {
488 self.value_vec_layout.validate()?;
490
491 for i in 0..self.and_constraints.len() {
492 validate_operand(&self.and_constraints[i].a, &self.value_vec_layout, "and", i, "a")?;
493 validate_operand(&self.and_constraints[i].b, &self.value_vec_layout, "and", i, "b")?;
494 validate_operand(&self.and_constraints[i].c, &self.value_vec_layout, "and", i, "c")?;
495 }
496 for i in 0..self.mul_constraints.len() {
497 validate_operand(&self.mul_constraints[i].a, &self.value_vec_layout, "mul", i, "a")?;
498 validate_operand(&self.mul_constraints[i].b, &self.value_vec_layout, "mul", i, "b")?;
499 validate_operand(&self.mul_constraints[i].lo, &self.value_vec_layout, "mul", i, "lo")?;
500 validate_operand(&self.mul_constraints[i].hi, &self.value_vec_layout, "mul", i, "hi")?;
501 }
502
503 return Ok(());
504
505 fn validate_operand(
506 operand: &Operand,
507 value_vec_layout: &ValueVecLayout,
508 constraint_type: &'static str,
509 constraint_index: usize,
510 operand_name: &'static str,
511 ) -> Result<(), ConstraintSystemError> {
512 for term in operand {
513 if term.amount == 0 && term.shift_variant != ShiftVariant::Sll {
515 return Err(ConstraintSystemError::NonCanonicalShift {
516 constraint_type,
517 constraint_index,
518 operand_name,
519 });
520 }
521 if term.amount >= 64 {
522 return Err(ConstraintSystemError::ShiftAmountTooLarge {
523 constraint_type,
524 constraint_index,
525 operand_name,
526 shift_amount: term.amount,
527 });
528 }
529 if value_vec_layout.is_committed_oob(term.value_index) {
531 return Err(ConstraintSystemError::OutOfRangeValueIndex {
532 constraint_type,
533 constraint_index,
534 operand_name,
535 value_index: term.value_index.0,
536 total_len: value_vec_layout.committed_total_len,
537 });
538 }
539 if value_vec_layout.is_padding(term.value_index) {
541 return Err(ConstraintSystemError::PaddingValueIndex {
542 constraint_type,
543 constraint_index,
544 operand_name,
545 });
546 }
547 }
548 Ok(())
549 }
550 }
551
552 pub fn validate_and_prepare(&mut self) -> Result<(), ConstraintSystemError> {
559 self.validate()?;
560
561 let and_target_size =
563 cmp::max(consts::MIN_AND_CONSTRAINTS, self.and_constraints.len()).next_power_of_two();
564 let mul_target_size =
565 cmp::max(consts::MIN_MUL_CONSTRAINTS, self.mul_constraints.len()).next_power_of_two();
566
567 self.and_constraints
568 .resize_with(and_target_size, AndConstraint::default);
569 self.mul_constraints
570 .resize_with(mul_target_size, MulConstraint::default);
571
572 Ok(())
573 }
574
575 #[cfg(test)]
576 fn add_and_constraint(&mut self, and_constraint: AndConstraint) {
577 self.and_constraints.push(and_constraint);
578 }
579
580 #[cfg(test)]
581 fn add_mul_constraint(&mut self, mul_constraint: MulConstraint) {
582 self.mul_constraints.push(mul_constraint);
583 }
584
585 pub fn n_and_constraints(&self) -> usize {
587 self.and_constraints.len()
588 }
589
590 pub fn n_mul_constraints(&self) -> usize {
592 self.mul_constraints.len()
593 }
594
595 pub fn value_vec_len(&self) -> usize {
597 self.value_vec_layout.committed_total_len
598 }
599
600 pub fn new_value_vec(&self) -> ValueVec {
602 ValueVec::new(self.value_vec_layout.clone())
603 }
604}
605
606impl SerializeBytes for ConstraintSystem {
607 fn serialize(&self, mut write_buf: impl BufMut) -> Result<(), SerializationError> {
608 Self::SERIALIZATION_VERSION.serialize(&mut write_buf)?;
609
610 self.value_vec_layout.serialize(&mut write_buf)?;
611 self.constants.serialize(&mut write_buf)?;
612 self.and_constraints.serialize(&mut write_buf)?;
613 self.mul_constraints.serialize(write_buf)
614 }
615}
616
617impl DeserializeBytes for ConstraintSystem {
618 fn deserialize(mut read_buf: impl Buf) -> Result<Self, SerializationError>
619 where
620 Self: Sized,
621 {
622 let version = u32::deserialize(&mut read_buf)?;
623 if version != Self::SERIALIZATION_VERSION {
624 return Err(SerializationError::InvalidConstruction {
625 name: "ConstraintSystem::version",
626 });
627 }
628
629 let value_vec_layout = ValueVecLayout::deserialize(&mut read_buf)?;
630 let constants = Vec::<Word>::deserialize(&mut read_buf)?;
631 let and_constraints = Vec::<AndConstraint>::deserialize(&mut read_buf)?;
632 let mul_constraints = Vec::<MulConstraint>::deserialize(read_buf)?;
633
634 if constants.len() != value_vec_layout.n_const {
635 return Err(SerializationError::InvalidConstruction {
636 name: "ConstraintSystem::constants",
637 });
638 }
639
640 Ok(ConstraintSystem {
641 value_vec_layout,
642 constants,
643 and_constraints,
644 mul_constraints,
645 })
646 }
647}
648
649#[derive(Clone, Debug, PartialEq, Eq)]
651pub struct ValueVecLayout {
652 pub n_const: usize,
654 pub n_inout: usize,
656 pub n_witness: usize,
658 pub n_internal: usize,
662
663 pub offset_inout: usize,
665 pub offset_witness: usize,
670 pub committed_total_len: usize,
675 pub n_scratch: usize,
677}
678
679impl ValueVecLayout {
680 pub fn validate(&self) -> Result<(), ConstraintSystemError> {
688 if !self.committed_total_len.is_power_of_two() {
689 return Err(ConstraintSystemError::ValueVecLenNotPowerOfTwo);
690 }
691
692 if !self.offset_witness.is_power_of_two() {
693 return Err(ConstraintSystemError::PublicInputPowerOfTwo);
694 }
695
696 let pub_input_size = self.offset_witness;
697 if pub_input_size < consts::MIN_WORDS_PER_SEGMENT {
698 return Err(ConstraintSystemError::PublicInputTooShort { pub_input_size });
699 }
700
701 Ok(())
702 }
703
704 fn is_padding(&self, index: ValueIndex) -> bool {
706 let idx = index.0 as usize;
707
708 if idx >= self.n_const && idx < self.offset_inout {
710 return true;
711 }
712
713 let end_of_inout = self.offset_inout + self.n_inout;
715 if idx >= end_of_inout && idx < self.offset_witness {
716 return true;
717 }
718
719 let end_of_internal = self.offset_witness + self.n_witness + self.n_internal;
721 if idx >= end_of_internal && idx < self.committed_total_len {
722 return true;
723 }
724
725 false
726 }
727
728 fn is_committed_oob(&self, index: ValueIndex) -> bool {
730 index.0 as usize >= self.committed_total_len
731 }
732}
733
734impl SerializeBytes for ValueVecLayout {
735 fn serialize(&self, mut write_buf: impl BufMut) -> Result<(), SerializationError> {
736 self.n_const.serialize(&mut write_buf)?;
737 self.n_inout.serialize(&mut write_buf)?;
738 self.n_witness.serialize(&mut write_buf)?;
739 self.n_internal.serialize(&mut write_buf)?;
740 self.offset_inout.serialize(&mut write_buf)?;
741 self.offset_witness.serialize(&mut write_buf)?;
742 self.committed_total_len.serialize(&mut write_buf)?;
743 self.n_scratch.serialize(write_buf)
744 }
745}
746
747impl DeserializeBytes for ValueVecLayout {
748 fn deserialize(mut read_buf: impl Buf) -> Result<Self, SerializationError>
749 where
750 Self: Sized,
751 {
752 let n_const = usize::deserialize(&mut read_buf)?;
753 let n_inout = usize::deserialize(&mut read_buf)?;
754 let n_witness = usize::deserialize(&mut read_buf)?;
755 let n_internal = usize::deserialize(&mut read_buf)?;
756 let offset_inout = usize::deserialize(&mut read_buf)?;
757 let offset_witness = usize::deserialize(&mut read_buf)?;
758 let committed_total_len = usize::deserialize(&mut read_buf)?;
759 let n_scratch = usize::deserialize(read_buf)?;
760
761 Ok(ValueVecLayout {
762 n_const,
763 n_inout,
764 n_witness,
765 n_internal,
766 offset_inout,
767 offset_witness,
768 committed_total_len,
769 n_scratch,
770 })
771 }
772}
773
774#[derive(Clone, Debug)]
783pub struct ValueVec {
784 layout: ValueVecLayout,
785 data: Vec<Word>,
786}
787
788impl ValueVec {
789 pub fn new(layout: ValueVecLayout) -> ValueVec {
793 let size = layout.committed_total_len + layout.n_scratch;
794 ValueVec {
795 layout,
796 data: vec![Word::ZERO; size],
797 }
798 }
799
800 pub fn new_from_data(
804 layout: ValueVecLayout,
805 public: Vec<Word>,
806 private: Vec<Word>,
807 ) -> Result<ValueVec, ConstraintSystemError> {
808 let committed_len = public.len() + private.len();
809 if committed_len != layout.committed_total_len {
810 return Err(ConstraintSystemError::ValueVecLenMismatch {
811 expected: layout.committed_total_len,
812 actual: committed_len,
813 });
814 }
815
816 let full_len = layout.committed_total_len + layout.n_scratch;
817 let mut data = public;
818 data.reserve(full_len);
819 data.extend_from_slice(&private);
820 data.resize(full_len, Word::ZERO);
821
822 Ok(ValueVec { layout, data })
823 }
824
825 pub fn size(&self) -> usize {
827 self.layout.committed_total_len
828 }
829
830 pub fn get(&self, index: usize) -> Word {
834 self.data[index]
835 }
836
837 pub fn set(&mut self, index: usize, value: Word) {
841 self.data[index] = value;
842 }
843
844 pub fn public(&self) -> &[Word] {
846 &self.data[..self.layout.offset_witness]
847 }
848
849 pub fn non_public(&self) -> &[Word] {
851 &self.data[self.layout.offset_witness..self.layout.committed_total_len]
852 }
853
854 pub fn witness(&self) -> &[Word] {
856 let start = self.layout.offset_witness;
857 let end = start + self.layout.n_witness;
858 &self.data[start..end]
859 }
860
861 pub fn combined_witness(&self) -> &[Word] {
863 let start = 0;
864 let end = self.layout.committed_total_len;
865 &self.data[start..end]
866 }
867}
868
869impl Index<ValueIndex> for ValueVec {
870 type Output = Word;
871
872 fn index(&self, index: ValueIndex) -> &Self::Output {
873 &self.data[index.0 as usize]
874 }
875}
876
877impl IndexMut<ValueIndex> for ValueVec {
878 fn index_mut(&mut self, index: ValueIndex) -> &mut Self::Output {
879 &mut self.data[index.0 as usize]
880 }
881}
882
883#[derive(Clone, Debug, PartialEq, Eq)]
889pub struct ValuesData<'a> {
890 data: Cow<'a, [Word]>,
891}
892
893impl<'a> ValuesData<'a> {
894 pub const SERIALIZATION_VERSION: u32 = 1;
896
897 pub fn borrowed(data: &'a [Word]) -> Self {
899 Self {
900 data: Cow::Borrowed(data),
901 }
902 }
903
904 pub fn owned(data: Vec<Word>) -> Self {
906 Self {
907 data: Cow::Owned(data),
908 }
909 }
910
911 pub fn as_slice(&self) -> &[Word] {
913 &self.data
914 }
915
916 pub fn len(&self) -> usize {
918 self.data.len()
919 }
920
921 pub fn is_empty(&self) -> bool {
923 self.data.is_empty()
924 }
925
926 pub fn into_owned(self) -> Vec<Word> {
928 self.data.into_owned()
929 }
930
931 pub fn to_owned(&self) -> ValuesData<'static> {
933 ValuesData {
934 data: Cow::Owned(self.data.to_vec()),
935 }
936 }
937}
938
939impl<'a> SerializeBytes for ValuesData<'a> {
940 fn serialize(&self, mut write_buf: impl BufMut) -> Result<(), SerializationError> {
941 Self::SERIALIZATION_VERSION.serialize(&mut write_buf)?;
942
943 self.data.as_ref().serialize(write_buf)
944 }
945}
946
947impl DeserializeBytes for ValuesData<'static> {
948 fn deserialize(mut read_buf: impl Buf) -> Result<Self, SerializationError>
949 where
950 Self: Sized,
951 {
952 let version = u32::deserialize(&mut read_buf)?;
953 if version != Self::SERIALIZATION_VERSION {
954 return Err(SerializationError::InvalidConstruction {
955 name: "Witness::version",
956 });
957 }
958
959 let data = Vec::<Word>::deserialize(read_buf)?;
960
961 Ok(ValuesData::owned(data))
962 }
963}
964
965impl<'a> From<&'a [Word]> for ValuesData<'a> {
966 fn from(data: &'a [Word]) -> Self {
967 ValuesData::borrowed(data)
968 }
969}
970
971impl From<Vec<Word>> for ValuesData<'static> {
972 fn from(data: Vec<Word>) -> Self {
973 ValuesData::owned(data)
974 }
975}
976
977impl<'a> AsRef<[Word]> for ValuesData<'a> {
978 fn as_ref(&self) -> &[Word] {
979 self.as_slice()
980 }
981}
982
983impl<'a> std::ops::Deref for ValuesData<'a> {
984 type Target = [Word];
985
986 fn deref(&self) -> &Self::Target {
987 self.as_slice()
988 }
989}
990
991impl<'a> From<ValuesData<'a>> for Vec<Word> {
992 fn from(value: ValuesData<'a>) -> Self {
993 value.into_owned()
994 }
995}
996
997#[derive(Clone, Debug, PartialEq, Eq)]
1014pub struct Proof<'a> {
1015 data: Cow<'a, [u8]>,
1016 challenger_type: String,
1017}
1018
1019impl<'a> Proof<'a> {
1020 pub const SERIALIZATION_VERSION: u32 = 1;
1022
1023 pub fn borrowed(data: &'a [u8], challenger_type: String) -> Self {
1025 Self {
1026 data: Cow::Borrowed(data),
1027 challenger_type,
1028 }
1029 }
1030
1031 pub fn owned(data: Vec<u8>, challenger_type: String) -> Self {
1033 Self {
1034 data: Cow::Owned(data),
1035 challenger_type,
1036 }
1037 }
1038
1039 pub fn as_slice(&self) -> &[u8] {
1041 &self.data
1042 }
1043
1044 pub fn challenger_type(&self) -> &str {
1046 &self.challenger_type
1047 }
1048
1049 pub fn len(&self) -> usize {
1051 self.data.len()
1052 }
1053
1054 pub fn is_empty(&self) -> bool {
1056 self.data.is_empty()
1057 }
1058
1059 pub fn into_owned(self) -> (Vec<u8>, String) {
1061 (self.data.into_owned(), self.challenger_type)
1062 }
1063
1064 pub fn to_owned(&self) -> Proof<'static> {
1066 Proof {
1067 data: Cow::Owned(self.data.to_vec()),
1068 challenger_type: self.challenger_type.clone(),
1069 }
1070 }
1071}
1072
1073impl<'a> SerializeBytes for Proof<'a> {
1074 fn serialize(&self, mut write_buf: impl BufMut) -> Result<(), SerializationError> {
1075 Self::SERIALIZATION_VERSION.serialize(&mut write_buf)?;
1076
1077 self.challenger_type.serialize(&mut write_buf)?;
1078
1079 self.data.as_ref().serialize(write_buf)
1080 }
1081}
1082
1083impl DeserializeBytes for Proof<'static> {
1084 fn deserialize(mut read_buf: impl Buf) -> Result<Self, SerializationError>
1085 where
1086 Self: Sized,
1087 {
1088 let version = u32::deserialize(&mut read_buf)?;
1089 if version != Self::SERIALIZATION_VERSION {
1090 return Err(SerializationError::InvalidConstruction {
1091 name: "Proof::version",
1092 });
1093 }
1094
1095 let challenger_type = String::deserialize(&mut read_buf)?;
1096 let data = Vec::<u8>::deserialize(read_buf)?;
1097
1098 Ok(Proof::owned(data, challenger_type))
1099 }
1100}
1101
1102impl<'a> From<(&'a [u8], String)> for Proof<'a> {
1103 fn from((data, challenger_type): (&'a [u8], String)) -> Self {
1104 Proof::borrowed(data, challenger_type)
1105 }
1106}
1107
1108impl From<(Vec<u8>, String)> for Proof<'static> {
1109 fn from((data, challenger_type): (Vec<u8>, String)) -> Self {
1110 Proof::owned(data, challenger_type)
1111 }
1112}
1113
1114impl<'a> AsRef<[u8]> for Proof<'a> {
1115 fn as_ref(&self) -> &[u8] {
1116 self.as_slice()
1117 }
1118}
1119
1120impl<'a> std::ops::Deref for Proof<'a> {
1121 type Target = [u8];
1122
1123 fn deref(&self) -> &Self::Target {
1124 self.as_slice()
1125 }
1126}
1127
1128#[cfg(test)]
1129mod serialization_tests {
1130 use rand::{RngCore, SeedableRng, rngs::StdRng};
1131
1132 use super::*;
1133
1134 pub(crate) fn create_test_constraint_system() -> ConstraintSystem {
1135 let constants = vec![
1136 Word::from_u64(1),
1137 Word::from_u64(42),
1138 Word::from_u64(0xDEADBEEF),
1139 ];
1140
1141 let value_vec_layout = ValueVecLayout {
1142 n_const: 3,
1143 n_inout: 2,
1144 n_witness: 10,
1145 n_internal: 3,
1146 offset_inout: 4, offset_witness: 8, committed_total_len: 16, n_scratch: 0,
1150 };
1151
1152 let and_constraints = vec![
1153 AndConstraint::plain_abc(
1154 vec![ValueIndex(0), ValueIndex(1)],
1155 vec![ValueIndex(2)],
1156 vec![ValueIndex(3), ValueIndex(4)],
1157 ),
1158 AndConstraint::abc(
1159 vec![ShiftedValueIndex::sll(ValueIndex(0), 5)],
1160 vec![ShiftedValueIndex::srl(ValueIndex(1), 10)],
1161 vec![ShiftedValueIndex::sar(ValueIndex(2), 15)],
1162 ),
1163 ];
1164
1165 let mul_constraints = vec![MulConstraint {
1166 a: vec![ShiftedValueIndex::plain(ValueIndex(0))],
1167 b: vec![ShiftedValueIndex::plain(ValueIndex(1))],
1168 hi: vec![ShiftedValueIndex::plain(ValueIndex(2))],
1169 lo: vec![ShiftedValueIndex::plain(ValueIndex(3))],
1170 }];
1171
1172 ConstraintSystem::new(constants, value_vec_layout, and_constraints, mul_constraints)
1173 }
1174
1175 #[test]
1176 fn test_word_serialization_round_trip() {
1177 let mut rng = StdRng::seed_from_u64(0);
1178 let word = Word::from_u64(rng.next_u64());
1179
1180 let mut buf = Vec::new();
1181 word.serialize(&mut buf).unwrap();
1182
1183 let deserialized = Word::deserialize(&mut buf.as_slice()).unwrap();
1184 assert_eq!(word, deserialized);
1185 }
1186
1187 #[test]
1188 fn test_shift_variant_serialization_round_trip() {
1189 let variants = [
1190 ShiftVariant::Sll,
1191 ShiftVariant::Slr,
1192 ShiftVariant::Sar,
1193 ShiftVariant::Rotr,
1194 ];
1195
1196 for variant in variants {
1197 let mut buf = Vec::new();
1198 variant.serialize(&mut buf).unwrap();
1199
1200 let deserialized = ShiftVariant::deserialize(&mut buf.as_slice()).unwrap();
1201 match (variant, deserialized) {
1202 (ShiftVariant::Sll, ShiftVariant::Sll)
1203 | (ShiftVariant::Slr, ShiftVariant::Slr)
1204 | (ShiftVariant::Sar, ShiftVariant::Sar)
1205 | (ShiftVariant::Rotr, ShiftVariant::Rotr) => {}
1206 _ => panic!("ShiftVariant round trip failed: {:?} != {:?}", variant, deserialized),
1207 }
1208 }
1209 }
1210
1211 #[test]
1212 fn test_shift_variant_unknown_variant() {
1213 let mut buf = Vec::new();
1215 255u8.serialize(&mut buf).unwrap();
1216
1217 let result = ShiftVariant::deserialize(&mut buf.as_slice());
1218 assert!(result.is_err());
1219 match result.unwrap_err() {
1220 SerializationError::UnknownEnumVariant { name, index } => {
1221 assert_eq!(name, "ShiftVariant");
1222 assert_eq!(index, 255);
1223 }
1224 _ => panic!("Expected UnknownEnumVariant error"),
1225 }
1226 }
1227
1228 #[test]
1229 fn test_value_index_serialization_round_trip() {
1230 let value_index = ValueIndex(12345);
1231
1232 let mut buf = Vec::new();
1233 value_index.serialize(&mut buf).unwrap();
1234
1235 let deserialized = ValueIndex::deserialize(&mut buf.as_slice()).unwrap();
1236 assert_eq!(value_index, deserialized);
1237 }
1238
1239 #[test]
1240 fn test_shifted_value_index_serialization_round_trip() {
1241 let shifted_value_index = ShiftedValueIndex::srl(ValueIndex(42), 23);
1242
1243 let mut buf = Vec::new();
1244 shifted_value_index.serialize(&mut buf).unwrap();
1245
1246 let deserialized = ShiftedValueIndex::deserialize(&mut buf.as_slice()).unwrap();
1247 assert_eq!(shifted_value_index.value_index, deserialized.value_index);
1248 assert_eq!(shifted_value_index.amount, deserialized.amount);
1249 match (shifted_value_index.shift_variant, deserialized.shift_variant) {
1250 (ShiftVariant::Slr, ShiftVariant::Slr) => {}
1251 _ => panic!("ShiftVariant mismatch"),
1252 }
1253 }
1254
1255 #[test]
1256 fn test_shifted_value_index_invalid_amount() {
1257 let mut buf = Vec::new();
1259 ValueIndex(0).serialize(&mut buf).unwrap();
1260 ShiftVariant::Sll.serialize(&mut buf).unwrap();
1261 64usize.serialize(&mut buf).unwrap(); let result = ShiftedValueIndex::deserialize(&mut buf.as_slice());
1264 assert!(result.is_err());
1265 match result.unwrap_err() {
1266 SerializationError::InvalidConstruction { name } => {
1267 assert_eq!(name, "ShiftedValueIndex::amount");
1268 }
1269 _ => panic!("Expected InvalidConstruction error"),
1270 }
1271 }
1272
1273 #[test]
1274 fn test_and_constraint_serialization_round_trip() {
1275 let constraint = AndConstraint::abc(
1276 vec![ShiftedValueIndex::sll(ValueIndex(1), 5)],
1277 vec![ShiftedValueIndex::srl(ValueIndex(2), 10)],
1278 vec![
1279 ShiftedValueIndex::sar(ValueIndex(3), 15),
1280 ShiftedValueIndex::plain(ValueIndex(4)),
1281 ],
1282 );
1283
1284 let mut buf = Vec::new();
1285 constraint.serialize(&mut buf).unwrap();
1286
1287 let deserialized = AndConstraint::deserialize(&mut buf.as_slice()).unwrap();
1288 assert_eq!(constraint.a.len(), deserialized.a.len());
1289 assert_eq!(constraint.b.len(), deserialized.b.len());
1290 assert_eq!(constraint.c.len(), deserialized.c.len());
1291
1292 for (orig, deser) in constraint.a.iter().zip(deserialized.a.iter()) {
1293 assert_eq!(orig.value_index, deser.value_index);
1294 assert_eq!(orig.amount, deser.amount);
1295 }
1296 }
1297
1298 #[test]
1299 fn test_mul_constraint_serialization_round_trip() {
1300 let constraint = MulConstraint {
1301 a: vec![ShiftedValueIndex::plain(ValueIndex(0))],
1302 b: vec![ShiftedValueIndex::srl(ValueIndex(1), 32)],
1303 hi: vec![ShiftedValueIndex::plain(ValueIndex(2))],
1304 lo: vec![ShiftedValueIndex::plain(ValueIndex(3))],
1305 };
1306
1307 let mut buf = Vec::new();
1308 constraint.serialize(&mut buf).unwrap();
1309
1310 let deserialized = MulConstraint::deserialize(&mut buf.as_slice()).unwrap();
1311 assert_eq!(constraint.a.len(), deserialized.a.len());
1312 assert_eq!(constraint.b.len(), deserialized.b.len());
1313 assert_eq!(constraint.hi.len(), deserialized.hi.len());
1314 assert_eq!(constraint.lo.len(), deserialized.lo.len());
1315 }
1316
1317 #[test]
1318 fn test_value_vec_layout_serialization_round_trip() {
1319 let layout = ValueVecLayout {
1320 n_const: 5,
1321 n_inout: 3,
1322 n_witness: 12,
1323 n_internal: 7,
1324 offset_inout: 8,
1325 offset_witness: 16,
1326 committed_total_len: 32,
1327 n_scratch: 0,
1328 };
1329
1330 let mut buf = Vec::new();
1331 layout.serialize(&mut buf).unwrap();
1332
1333 let deserialized = ValueVecLayout::deserialize(&mut buf.as_slice()).unwrap();
1334 assert_eq!(layout, deserialized);
1335 }
1336
1337 #[test]
1338 fn test_constraint_system_serialization_round_trip() {
1339 let original = create_test_constraint_system();
1340
1341 let mut buf = Vec::new();
1342 original.serialize(&mut buf).unwrap();
1343
1344 let deserialized = ConstraintSystem::deserialize(&mut buf.as_slice()).unwrap();
1345
1346 assert_eq!(ConstraintSystem::SERIALIZATION_VERSION, 2);
1348
1349 assert_eq!(original.value_vec_layout, deserialized.value_vec_layout);
1351
1352 assert_eq!(original.constants.len(), deserialized.constants.len());
1354 for (orig, deser) in original.constants.iter().zip(deserialized.constants.iter()) {
1355 assert_eq!(orig, deser);
1356 }
1357
1358 assert_eq!(original.and_constraints.len(), deserialized.and_constraints.len());
1360
1361 assert_eq!(original.mul_constraints.len(), deserialized.mul_constraints.len());
1363 }
1364
1365 #[test]
1366 fn test_constraint_system_version_mismatch() {
1367 let mut buf = Vec::new();
1369 999u32.serialize(&mut buf).unwrap(); let result = ConstraintSystem::deserialize(&mut buf.as_slice());
1372 assert!(result.is_err());
1373 match result.unwrap_err() {
1374 SerializationError::InvalidConstruction { name } => {
1375 assert_eq!(name, "ConstraintSystem::version");
1376 }
1377 _ => panic!("Expected InvalidConstruction error"),
1378 }
1379 }
1380
1381 #[test]
1382 fn test_constraint_system_constants_length_mismatch() {
1383 let value_vec_layout = ValueVecLayout {
1385 n_const: 5, n_inout: 2,
1387 n_witness: 10,
1388 n_internal: 3,
1389 offset_inout: 8,
1390 offset_witness: 16,
1391 committed_total_len: 32,
1392 n_scratch: 0,
1393 };
1394
1395 let constants = vec![Word::from_u64(1), Word::from_u64(2)]; let and_constraints: Vec<AndConstraint> = vec![];
1397 let mul_constraints: Vec<MulConstraint> = vec![];
1398
1399 let mut buf = Vec::new();
1401 ConstraintSystem::SERIALIZATION_VERSION
1402 .serialize(&mut buf)
1403 .unwrap();
1404 value_vec_layout.serialize(&mut buf).unwrap();
1405 constants.serialize(&mut buf).unwrap();
1406 and_constraints.serialize(&mut buf).unwrap();
1407 mul_constraints.serialize(&mut buf).unwrap();
1408
1409 let result = ConstraintSystem::deserialize(&mut buf.as_slice());
1410 assert!(result.is_err());
1411 match result.unwrap_err() {
1412 SerializationError::InvalidConstruction { name } => {
1413 assert_eq!(name, "ConstraintSystem::constants");
1414 }
1415 _ => panic!("Expected InvalidConstruction error"),
1416 }
1417 }
1418
1419 #[test]
1420 fn test_serialization_with_different_sources() {
1421 let original = create_test_constraint_system();
1422
1423 let mut vec_buf = Vec::new();
1425 original.serialize(&mut vec_buf).unwrap();
1426 let deserialized1 = ConstraintSystem::deserialize(&mut vec_buf.as_slice()).unwrap();
1427 assert_eq!(original.constants.len(), deserialized1.constants.len());
1428
1429 let mut bytes_buf = bytes::BytesMut::new();
1431 original.serialize(&mut bytes_buf).unwrap();
1432 let deserialized2 = ConstraintSystem::deserialize(bytes_buf.freeze()).unwrap();
1433 assert_eq!(original.constants.len(), deserialized2.constants.len());
1434 }
1435
1436 #[test]
1440 #[ignore] fn create_reference_binary_file() {
1442 let constraint_system = create_test_constraint_system();
1443
1444 let mut buf = Vec::new();
1446 constraint_system.serialize(&mut buf).unwrap();
1447
1448 let test_data_path = std::path::Path::new("test_data/constraint_system_v2.bin");
1450
1451 if let Some(parent) = test_data_path.parent() {
1453 std::fs::create_dir_all(parent).unwrap();
1454 }
1455
1456 std::fs::write(test_data_path, &buf).unwrap();
1457
1458 println!("Created reference binary file at: {:?}", test_data_path);
1459 println!("Binary data length: {} bytes", buf.len());
1460 }
1461
1462 #[test]
1465 fn test_deserialize_from_reference_binary_file() {
1466 let binary_data = include_bytes!("../test_data/constraint_system_v2.bin");
1469
1470 let deserialized = ConstraintSystem::deserialize(&mut binary_data.as_slice()).unwrap();
1471
1472 assert_eq!(deserialized.value_vec_layout.n_const, 3);
1473 assert_eq!(deserialized.value_vec_layout.n_inout, 2);
1474 assert_eq!(deserialized.value_vec_layout.n_witness, 10);
1475 assert_eq!(deserialized.value_vec_layout.n_internal, 3);
1476 assert_eq!(deserialized.value_vec_layout.offset_inout, 4);
1477 assert_eq!(deserialized.value_vec_layout.offset_witness, 8);
1478 assert_eq!(deserialized.value_vec_layout.committed_total_len, 16);
1479 assert_eq!(deserialized.value_vec_layout.n_scratch, 0);
1480
1481 assert_eq!(deserialized.constants.len(), 3);
1482 assert_eq!(deserialized.constants[0].as_u64(), 1);
1483 assert_eq!(deserialized.constants[1].as_u64(), 42);
1484 assert_eq!(deserialized.constants[2].as_u64(), 0xDEADBEEF);
1485
1486 assert_eq!(deserialized.and_constraints.len(), 2);
1487 assert_eq!(deserialized.mul_constraints.len(), 1);
1488
1489 let version_bytes = &binary_data[0..4]; let expected_version_bytes = 2u32.to_le_bytes(); assert_eq!(
1495 version_bytes, expected_version_bytes,
1496 "Binary file version mismatch. If you made breaking changes, increment ConstraintSystem::SERIALIZATION_VERSION"
1497 );
1498 }
1499
1500 #[test]
1501 fn test_witness_serialization_round_trip_owned() {
1502 let data = vec![
1503 Word::from_u64(1),
1504 Word::from_u64(42),
1505 Word::from_u64(0xDEADBEEF),
1506 Word::from_u64(0x1234567890ABCDEF),
1507 ];
1508 let witness = ValuesData::owned(data.clone());
1509
1510 let mut buf = Vec::new();
1511 witness.serialize(&mut buf).unwrap();
1512
1513 let deserialized = ValuesData::deserialize(&mut buf.as_slice()).unwrap();
1514 assert_eq!(witness, deserialized);
1515 assert_eq!(deserialized.as_slice(), data.as_slice());
1516 }
1517
1518 #[test]
1519 fn test_witness_serialization_round_trip_borrowed() {
1520 let data = vec![Word::from_u64(123), Word::from_u64(456)];
1521 let witness = ValuesData::borrowed(&data);
1522
1523 let mut buf = Vec::new();
1524 witness.serialize(&mut buf).unwrap();
1525
1526 let deserialized = ValuesData::deserialize(&mut buf.as_slice()).unwrap();
1527 assert_eq!(witness, deserialized);
1528 assert_eq!(deserialized.as_slice(), data.as_slice());
1529 }
1530
1531 #[test]
1532 fn test_witness_version_mismatch() {
1533 let mut buf = Vec::new();
1534 999u32.serialize(&mut buf).unwrap(); vec![Word::from_u64(1)].serialize(&mut buf).unwrap(); let result = ValuesData::deserialize(&mut buf.as_slice());
1538 assert!(result.is_err());
1539 match result.unwrap_err() {
1540 SerializationError::InvalidConstruction { name } => {
1541 assert_eq!(name, "Witness::version");
1542 }
1543 _ => panic!("Expected version mismatch error"),
1544 }
1545 }
1546
1547 #[test]
1550 #[ignore] fn create_witness_reference_binary_file() {
1552 let data = vec![
1553 Word::from_u64(1),
1554 Word::from_u64(42),
1555 Word::from_u64(0xDEADBEEF),
1556 Word::from_u64(0x1234567890ABCDEF),
1557 ];
1558 let witness = ValuesData::owned(data);
1559
1560 let mut buf = Vec::new();
1561 witness.serialize(&mut buf).unwrap();
1562
1563 let test_data_path = std::path::Path::new("verifier/core/test_data/witness_v1.bin");
1564
1565 if let Some(parent) = test_data_path.parent() {
1566 std::fs::create_dir_all(parent).unwrap();
1567 }
1568
1569 std::fs::write(test_data_path, &buf).unwrap();
1570
1571 println!("Created Witness reference binary file at: {:?}", test_data_path);
1572 println!("Binary data length: {} bytes", buf.len());
1573 }
1574
1575 #[test]
1579 fn test_witness_deserialize_from_reference_binary_file() {
1580 let binary_data = include_bytes!("../test_data/witness_v1.bin");
1581
1582 let deserialized = ValuesData::deserialize(&mut binary_data.as_slice()).unwrap();
1583
1584 assert_eq!(deserialized.len(), 4);
1585 assert_eq!(deserialized.as_slice()[0].as_u64(), 1);
1586 assert_eq!(deserialized.as_slice()[1].as_u64(), 42);
1587 assert_eq!(deserialized.as_slice()[2].as_u64(), 0xDEADBEEF);
1588 assert_eq!(deserialized.as_slice()[3].as_u64(), 0x1234567890ABCDEF);
1589
1590 let version_bytes = &binary_data[0..4]; let expected_version_bytes = 1u32.to_le_bytes(); assert_eq!(
1596 version_bytes, expected_version_bytes,
1597 "WitnessData binary file version mismatch. If you made breaking changes, increment WitnessData::SERIALIZATION_VERSION"
1598 );
1599 }
1600
1601 #[test]
1602 fn test_proof_serialization_round_trip_owned() {
1603 let transcript_data = vec![0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0];
1604 let challenger_type = "HasherChallenger<Sha256>".to_string();
1605 let proof = Proof::owned(transcript_data.clone(), challenger_type.clone());
1606
1607 let mut buf = Vec::new();
1608 proof.serialize(&mut buf).unwrap();
1609
1610 let deserialized = Proof::deserialize(&mut buf.as_slice()).unwrap();
1611 assert_eq!(proof, deserialized);
1612 assert_eq!(deserialized.as_slice(), transcript_data.as_slice());
1613 assert_eq!(deserialized.challenger_type(), &challenger_type);
1614 }
1615
1616 #[test]
1617 fn test_proof_serialization_round_trip_borrowed() {
1618 let transcript_data = vec![0xAA, 0xBB, 0xCC, 0xDD];
1619 let challenger_type = "TestChallenger".to_string();
1620 let proof = Proof::borrowed(&transcript_data, challenger_type.clone());
1621
1622 let mut buf = Vec::new();
1623 proof.serialize(&mut buf).unwrap();
1624
1625 let deserialized = Proof::deserialize(&mut buf.as_slice()).unwrap();
1626 assert_eq!(proof, deserialized);
1627 assert_eq!(deserialized.as_slice(), transcript_data.as_slice());
1628 assert_eq!(deserialized.challenger_type(), &challenger_type);
1629 }
1630
1631 #[test]
1632 fn test_proof_empty_transcript() {
1633 let proof = Proof::owned(vec![], "EmptyProof".to_string());
1634 assert!(proof.is_empty());
1635 assert_eq!(proof.len(), 0);
1636
1637 let mut buf = Vec::new();
1638 proof.serialize(&mut buf).unwrap();
1639
1640 let deserialized = Proof::deserialize(&mut buf.as_slice()).unwrap();
1641 assert_eq!(proof, deserialized);
1642 assert!(deserialized.is_empty());
1643 }
1644
1645 #[test]
1646 fn test_proof_large_transcript() {
1647 let mut rng = StdRng::seed_from_u64(12345);
1648 let mut large_data = vec![0u8; 10000];
1649 rng.fill_bytes(&mut large_data);
1650
1651 let challenger_type = "LargeProofChallenger".to_string();
1652 let proof = Proof::owned(large_data.clone(), challenger_type.clone());
1653
1654 let mut buf = Vec::new();
1655 proof.serialize(&mut buf).unwrap();
1656
1657 let deserialized = Proof::deserialize(&mut buf.as_slice()).unwrap();
1658 assert_eq!(proof, deserialized);
1659 assert_eq!(deserialized.len(), 10000);
1660 assert_eq!(deserialized.challenger_type(), &challenger_type);
1661 }
1662
1663 #[test]
1664 fn test_proof_version_mismatch() {
1665 let mut buf = Vec::new();
1666 999u32.serialize(&mut buf).unwrap(); "TestChallenger".serialize(&mut buf).unwrap(); vec![0xAAu8].serialize(&mut buf).unwrap(); let result = Proof::deserialize(&mut buf.as_slice());
1671 assert!(result.is_err());
1672 match result.unwrap_err() {
1673 SerializationError::InvalidConstruction { name } => {
1674 assert_eq!(name, "Proof::version");
1675 }
1676 _ => panic!("Expected version mismatch error"),
1677 }
1678 }
1679
1680 #[test]
1681 fn test_proof_into_owned() {
1682 let original_data = vec![1, 2, 3, 4, 5];
1683 let original_challenger = "TestChallenger".to_string();
1684 let proof = Proof::owned(original_data.clone(), original_challenger.clone());
1685
1686 let (data, challenger_type) = proof.into_owned();
1687 assert_eq!(data, original_data);
1688 assert_eq!(challenger_type, original_challenger);
1689 }
1690
1691 #[test]
1692 fn test_proof_to_owned() {
1693 let data = vec![0xFF, 0xEE, 0xDD];
1694 let challenger_type = "BorrowedChallenger".to_string();
1695 let borrowed_proof = Proof::borrowed(&data, challenger_type.clone());
1696
1697 let owned_proof = borrowed_proof.to_owned();
1698 assert_eq!(owned_proof.as_slice(), data);
1699 assert_eq!(owned_proof.challenger_type(), &challenger_type);
1700 drop(data); assert_eq!(owned_proof.len(), 3);
1703 }
1704
1705 #[test]
1706 fn test_proof_different_challenger_types() {
1707 let data = vec![0x42];
1708 let challengers = vec![
1709 "HasherChallenger<Sha256>".to_string(),
1710 "HasherChallenger<Blake2b>".to_string(),
1711 "CustomChallenger".to_string(),
1712 "".to_string(), ];
1714
1715 for challenger_type in challengers {
1716 let proof = Proof::owned(data.clone(), challenger_type.clone());
1717 let mut buf = Vec::new();
1718 proof.serialize(&mut buf).unwrap();
1719
1720 let deserialized = Proof::deserialize(&mut buf.as_slice()).unwrap();
1721 assert_eq!(deserialized.challenger_type(), &challenger_type);
1722 }
1723 }
1724
1725 #[test]
1726 fn test_proof_serialization_with_different_sources() {
1727 let transcript_data = vec![0x11, 0x22, 0x33, 0x44];
1728 let challenger_type = "MultiSourceChallenger".to_string();
1729 let original = Proof::owned(transcript_data, challenger_type);
1730
1731 let mut vec_buf = Vec::new();
1733 original.serialize(&mut vec_buf).unwrap();
1734 let deserialized1 = Proof::deserialize(&mut vec_buf.as_slice()).unwrap();
1735 assert_eq!(original, deserialized1);
1736
1737 let mut bytes_buf = bytes::BytesMut::new();
1739 original.serialize(&mut bytes_buf).unwrap();
1740 let deserialized2 = Proof::deserialize(bytes_buf.freeze()).unwrap();
1741 assert_eq!(original, deserialized2);
1742 }
1743
1744 #[test]
1747 #[ignore] fn create_proof_reference_binary_file() {
1749 let transcript_data = vec![
1750 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54,
1751 0x32, 0x10, 0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE,
1752 ];
1753 let challenger_type = "HasherChallenger<Sha256>".to_string();
1754 let proof = Proof::owned(transcript_data, challenger_type);
1755
1756 let mut buf = Vec::new();
1757 proof.serialize(&mut buf).unwrap();
1758
1759 let test_data_path = std::path::Path::new("verifier/core/test_data/proof_v1.bin");
1760
1761 if let Some(parent) = test_data_path.parent() {
1762 std::fs::create_dir_all(parent).unwrap();
1763 }
1764
1765 std::fs::write(test_data_path, &buf).unwrap();
1766
1767 println!("Created Proof reference binary file at: {:?}", test_data_path);
1768 println!("Binary data length: {} bytes", buf.len());
1769 }
1770
1771 #[test]
1775 fn test_proof_deserialize_from_reference_binary_file() {
1776 let binary_data = include_bytes!("../test_data/proof_v1.bin");
1777
1778 let deserialized = Proof::deserialize(&mut binary_data.as_slice()).unwrap();
1779
1780 assert_eq!(deserialized.len(), 24); assert_eq!(deserialized.challenger_type(), "HasherChallenger<Sha256>");
1782
1783 let expected_data = vec![
1784 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54,
1785 0x32, 0x10, 0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE,
1786 ];
1787 assert_eq!(deserialized.as_slice(), expected_data);
1788
1789 let version_bytes = &binary_data[0..4]; let expected_version_bytes = 1u32.to_le_bytes(); assert_eq!(
1795 version_bytes, expected_version_bytes,
1796 "Proof binary file version mismatch. If you made breaking changes, increment Proof::SERIALIZATION_VERSION"
1797 );
1798 }
1799
1800 #[test]
1801 fn split_values_vec_and_combine() {
1802 let values = ValueVec::new(ValueVecLayout {
1803 n_const: 2,
1804 n_inout: 2,
1805 n_witness: 2,
1806 n_internal: 2,
1807 offset_inout: 2,
1808 offset_witness: 4,
1809 committed_total_len: 8,
1810 n_scratch: 0,
1811 });
1812
1813 let public = values.public();
1814 let non_public = values.non_public();
1815 let combined =
1816 ValueVec::new_from_data(values.layout.clone(), public.to_vec(), non_public.to_vec())
1817 .unwrap();
1818 assert_eq!(combined.combined_witness(), values.combined_witness());
1819 }
1820
1821 #[test]
1822 fn test_roundtrip_cs_and_witnesses_reconstruct_valuevec_with_scratch() {
1823 let layout = ValueVecLayout {
1825 n_const: 2,
1826 n_inout: 3,
1827 n_witness: 4,
1828 n_internal: 3,
1829 offset_inout: 4, offset_witness: 8, committed_total_len: 16,
1832 n_scratch: 5, };
1834
1835 let constants = vec![Word::from_u64(11), Word::from_u64(22)];
1836 let cs = ConstraintSystem::new(constants, layout.clone(), vec![], vec![]);
1837
1838 let mut values = cs.new_value_vec();
1840 let full_len = layout.committed_total_len + layout.n_scratch;
1841 for i in 0..full_len {
1842 let val = Word::from_u64(0xA5A5_5A5A ^ (i as u64 * 0x9E37_79B9));
1844 values.set(i, val);
1845 }
1846
1847 let public_data = ValuesData::from(values.public());
1849 let non_public_data = ValuesData::from(values.non_public());
1850
1851 let mut buf_cs = Vec::new();
1852 cs.serialize(&mut buf_cs).unwrap();
1853
1854 let mut buf_pub = Vec::new();
1855 public_data.serialize(&mut buf_pub).unwrap();
1856
1857 let mut buf_non_pub = Vec::new();
1858 non_public_data.serialize(&mut buf_non_pub).unwrap();
1859
1860 let cs2 = ConstraintSystem::deserialize(&mut buf_cs.as_slice()).unwrap();
1862 let pub2 = ValuesData::deserialize(&mut buf_pub.as_slice()).unwrap();
1863 let non_pub2 = ValuesData::deserialize(&mut buf_non_pub.as_slice()).unwrap();
1864
1865 let reconstructed = ValueVec::new_from_data(
1867 cs2.value_vec_layout.clone(),
1868 pub2.into_owned(),
1869 non_pub2.into_owned(),
1870 )
1871 .unwrap();
1872
1873 assert_eq!(reconstructed.combined_witness(), values.combined_witness());
1875
1876 let scratch_start = layout.committed_total_len;
1878 let scratch_end = scratch_start + layout.n_scratch;
1879 for i in scratch_start..scratch_end {
1880 assert_eq!(reconstructed.get(i), Word::ZERO, "scratch index {i} should be zero");
1881 }
1882 }
1883
1884 #[test]
1885 fn test_is_padding_comprehensive() {
1886 let layout = ValueVecLayout {
1888 n_const: 2, n_inout: 3, n_witness: 5, n_internal: 10, offset_inout: 4, offset_witness: 16, committed_total_len: 64, n_scratch: 0,
1896 };
1897
1898 assert!(!layout.is_padding(ValueIndex(0)), "index 0 should be constant");
1900 assert!(!layout.is_padding(ValueIndex(1)), "index 1 should be constant");
1901
1902 assert!(
1904 layout.is_padding(ValueIndex(2)),
1905 "index 2 should be padding between const and inout"
1906 );
1907 assert!(
1908 layout.is_padding(ValueIndex(3)),
1909 "index 3 should be padding between const and inout"
1910 );
1911
1912 assert!(!layout.is_padding(ValueIndex(4)), "index 4 should be inout");
1914 assert!(!layout.is_padding(ValueIndex(5)), "index 5 should be inout");
1915 assert!(!layout.is_padding(ValueIndex(6)), "index 6 should be inout");
1916
1917 for i in 7..16 {
1919 assert!(
1920 layout.is_padding(ValueIndex(i)),
1921 "index {} should be padding between inout and witness",
1922 i
1923 );
1924 }
1925
1926 for i in 16..21 {
1928 assert!(!layout.is_padding(ValueIndex(i)), "index {} should be witness", i);
1929 }
1930
1931 for i in 21..31 {
1933 assert!(!layout.is_padding(ValueIndex(i)), "index {} should be internal", i);
1934 }
1935
1936 for i in 31..64 {
1938 assert!(
1939 layout.is_padding(ValueIndex(i)),
1940 "index {} should be padding after internal",
1941 i
1942 );
1943 }
1944 }
1945
1946 #[test]
1947 fn test_is_padding_minimal_layout() {
1948 let layout = ValueVecLayout {
1950 n_const: 4, n_inout: 4, n_witness: 4, n_internal: 4, offset_inout: 4, offset_witness: 8, committed_total_len: 16, n_scratch: 0,
1958 };
1959
1960 for i in 0..16 {
1962 assert!(
1963 !layout.is_padding(ValueIndex(i)),
1964 "index {} should not be padding in minimal layout",
1965 i
1966 );
1967 }
1968 }
1969
1970 #[test]
1971 fn test_is_padding_public_section_min_size() {
1972 let layout = ValueVecLayout {
1974 n_const: 1, n_inout: 1, n_witness: 2, n_internal: 2, offset_inout: 4, offset_witness: 8, committed_total_len: 16, n_scratch: 0,
1982 };
1983
1984 assert!(!layout.is_padding(ValueIndex(0)), "index 0 should be constant");
1986
1987 assert!(layout.is_padding(ValueIndex(1)), "index 1 should be padding");
1989 assert!(layout.is_padding(ValueIndex(2)), "index 2 should be padding");
1990 assert!(layout.is_padding(ValueIndex(3)), "index 3 should be padding");
1991
1992 assert!(!layout.is_padding(ValueIndex(4)), "index 4 should be inout");
1994
1995 assert!(layout.is_padding(ValueIndex(5)), "index 5 should be padding");
1997 assert!(layout.is_padding(ValueIndex(6)), "index 6 should be padding");
1998 assert!(layout.is_padding(ValueIndex(7)), "index 7 should be padding");
1999
2000 assert!(!layout.is_padding(ValueIndex(8)), "index 8 should be witness");
2002 assert!(!layout.is_padding(ValueIndex(9)), "index 9 should be witness");
2003
2004 assert!(!layout.is_padding(ValueIndex(10)), "index 10 should be internal");
2006 assert!(!layout.is_padding(ValueIndex(11)), "index 11 should be internal");
2007
2008 for i in 12..16 {
2010 assert!(layout.is_padding(ValueIndex(i)), "index {} should be end padding", i);
2011 }
2012 }
2013
2014 #[test]
2015 fn test_is_padding_boundary_conditions() {
2016 let layout = ValueVecLayout {
2017 n_const: 2,
2018 n_inout: 2,
2019 n_witness: 4,
2020 n_internal: 4,
2021 offset_inout: 4,
2022 offset_witness: 8,
2023 committed_total_len: 16,
2024 n_scratch: 0,
2025 };
2026
2027 assert!(!layout.is_padding(ValueIndex(1)), "last constant should not be padding");
2029 assert!(layout.is_padding(ValueIndex(2)), "first padding after const should be padding");
2030
2031 assert!(layout.is_padding(ValueIndex(3)), "last padding before inout should be padding");
2032 assert!(!layout.is_padding(ValueIndex(4)), "first inout should not be padding");
2033
2034 assert!(!layout.is_padding(ValueIndex(5)), "last inout should not be padding");
2035 assert!(layout.is_padding(ValueIndex(6)), "first padding after inout should be padding");
2036
2037 assert!(layout.is_padding(ValueIndex(7)), "last padding before witness should be padding");
2038 assert!(!layout.is_padding(ValueIndex(8)), "first witness should not be padding");
2039
2040 assert!(!layout.is_padding(ValueIndex(11)), "last witness should not be padding");
2041 assert!(!layout.is_padding(ValueIndex(12)), "first internal should not be padding");
2042
2043 assert!(!layout.is_padding(ValueIndex(15)), "last internal should not be padding");
2044 }
2046
2047 #[test]
2048 fn test_validate_rejects_padding_references() {
2049 let mut cs = ConstraintSystem::new(
2050 vec![Word::from_u64(1)],
2051 ValueVecLayout {
2052 n_const: 1,
2053 n_inout: 1,
2054 n_witness: 2,
2055 n_internal: 2,
2056 offset_inout: 4,
2057 offset_witness: 8,
2058 committed_total_len: 16,
2059 n_scratch: 0,
2060 },
2061 vec![],
2062 vec![],
2063 );
2064
2065 cs.add_and_constraint(AndConstraint::plain_abc(
2067 vec![ValueIndex(0)], vec![ValueIndex(2)], vec![ValueIndex(8)], ));
2071
2072 let result = cs.validate_and_prepare();
2073 assert!(result.is_err(), "Should reject constraint referencing padding");
2074
2075 match result.unwrap_err() {
2076 ConstraintSystemError::PaddingValueIndex {
2077 constraint_type, ..
2078 } => {
2079 assert_eq!(constraint_type, "and");
2080 }
2081 other => panic!("Expected PaddingValueIndex error, got: {:?}", other),
2082 }
2083 }
2084
2085 #[test]
2086 fn test_validate_accepts_non_padding_references() {
2087 let mut cs = ConstraintSystem::new(
2088 vec![Word::from_u64(1), Word::from_u64(2)],
2089 ValueVecLayout {
2090 n_const: 2,
2091 n_inout: 2,
2092 n_witness: 4,
2093 n_internal: 4,
2094 offset_inout: 2,
2095 offset_witness: 4,
2096 committed_total_len: 16,
2097 n_scratch: 0,
2098 },
2099 vec![],
2100 vec![],
2101 );
2102
2103 cs.add_and_constraint(AndConstraint::plain_abc(
2105 vec![ValueIndex(0), ValueIndex(1)], vec![ValueIndex(2), ValueIndex(3)], vec![ValueIndex(4), ValueIndex(5)], ));
2109
2110 cs.add_mul_constraint(MulConstraint {
2111 a: vec![ShiftedValueIndex::plain(ValueIndex(6))], b: vec![ShiftedValueIndex::plain(ValueIndex(7))], hi: vec![ShiftedValueIndex::plain(ValueIndex(8))], lo: vec![ShiftedValueIndex::plain(ValueIndex(9))], });
2116
2117 let result = cs.validate_and_prepare();
2118 assert!(
2119 result.is_ok(),
2120 "Should accept constraints with only valid references: {:?}",
2121 result
2122 );
2123 }
2124
2125 #[test]
2126 fn test_is_padding_matches_compiler_requirements() {
2127 let layout1 = ValueVecLayout {
2135 n_const: 1,
2136 n_inout: 1,
2137 n_witness: 4,
2138 n_internal: 4,
2139 offset_inout: 1, offset_witness: 8, committed_total_len: 16,
2142 n_scratch: 0,
2143 };
2144
2145 assert!(!layout1.is_padding(ValueIndex(0)), "const should not be padding");
2147 assert!(!layout1.is_padding(ValueIndex(1)), "inout should not be padding");
2148 for i in 2..8 {
2149 assert!(
2150 layout1.is_padding(ValueIndex(i)),
2151 "index {} should be padding to meet MIN_WORDS_PER_SEGMENT",
2152 i
2153 );
2154 }
2155
2156 let layout2 = ValueVecLayout {
2158 n_const: 4,
2159 n_inout: 4,
2160 n_witness: 8,
2161 n_internal: 0,
2162 offset_inout: 4,
2163 offset_witness: 8, committed_total_len: 16,
2165 n_scratch: 0,
2166 };
2167
2168 for i in 0..8 {
2170 assert!(!layout2.is_padding(ValueIndex(i)), "index {} should not be padding", i);
2171 }
2172
2173 let layout3 = ValueVecLayout {
2176 n_const: 5,
2177 n_inout: 5,
2178 n_witness: 16,
2179 n_internal: 0,
2180 offset_inout: 5,
2181 offset_witness: 16, committed_total_len: 32,
2183 n_scratch: 0,
2184 };
2185
2186 for i in 0..5 {
2188 assert!(!layout3.is_padding(ValueIndex(i)), "const {} should not be padding", i);
2189 }
2190 for i in 5..10 {
2191 assert!(!layout3.is_padding(ValueIndex(i)), "inout {} should not be padding", i);
2192 }
2193 for i in 10..16 {
2194 assert!(
2195 layout3.is_padding(ValueIndex(i)),
2196 "index {} should be padding for power-of-2 alignment",
2197 i
2198 );
2199 }
2200
2201 let layout4 = ValueVecLayout {
2203 n_const: 2, n_inout: 2, n_witness: 4, n_internal: 4, offset_inout: 8, offset_witness: 16, committed_total_len: 32, n_scratch: 0,
2211 };
2212
2213 assert!(!layout4.is_padding(ValueIndex(0)));
2215 assert!(!layout4.is_padding(ValueIndex(1)));
2216
2217 for i in 2..8 {
2219 assert!(layout4.is_padding(ValueIndex(i)), "padding between const and inout at {}", i);
2220 }
2221
2222 assert!(!layout4.is_padding(ValueIndex(8)));
2224 assert!(!layout4.is_padding(ValueIndex(9)));
2225
2226 for i in 10..16 {
2228 assert!(
2229 layout4.is_padding(ValueIndex(i)),
2230 "padding between inout and witness at {}",
2231 i
2232 );
2233 }
2234
2235 for i in 16..20 {
2237 assert!(!layout4.is_padding(ValueIndex(i)), "witness at {}", i);
2238 }
2239
2240 for i in 20..24 {
2242 assert!(!layout4.is_padding(ValueIndex(i)), "internal at {}", i);
2243 }
2244
2245 for i in 24..32 {
2247 assert!(layout4.is_padding(ValueIndex(i)), "padding after internal at {}", i);
2248 }
2249 }
2250
2251 #[test]
2252 fn test_validate_rejects_out_of_range_indices() {
2253 let mut cs = ConstraintSystem::new(
2254 vec![Word::from_u64(1)],
2255 ValueVecLayout {
2256 n_const: 1,
2257 n_inout: 1,
2258 n_witness: 2,
2259 n_internal: 2,
2260 offset_inout: 4,
2261 offset_witness: 8,
2262 committed_total_len: 16,
2263 n_scratch: 0,
2264 },
2265 vec![],
2266 vec![],
2267 );
2268
2269 cs.add_and_constraint(AndConstraint::plain_abc(
2271 vec![ValueIndex(0)], vec![ValueIndex(16)], vec![ValueIndex(8)], ));
2275
2276 let result = cs.validate_and_prepare();
2277 assert!(result.is_err(), "Should reject constraint with out-of-range index");
2278
2279 match result.unwrap_err() {
2280 ConstraintSystemError::OutOfRangeValueIndex {
2281 constraint_type,
2282 operand_name,
2283 value_index,
2284 total_len,
2285 ..
2286 } => {
2287 assert_eq!(constraint_type, "and");
2288 assert_eq!(operand_name, "b");
2289 assert_eq!(value_index, 16);
2290 assert_eq!(total_len, 16);
2291 }
2292 other => panic!("Expected OutOfRangeValueIndex error, got: {:?}", other),
2293 }
2294 }
2295
2296 #[test]
2297 fn test_validate_rejects_out_of_range_in_mul_constraint() {
2298 let mut cs = ConstraintSystem::new(
2299 vec![Word::from_u64(1), Word::from_u64(2)],
2300 ValueVecLayout {
2301 n_const: 2,
2302 n_inout: 2,
2303 n_witness: 4,
2304 n_internal: 4,
2305 offset_inout: 2,
2306 offset_witness: 4,
2307 committed_total_len: 16,
2308 n_scratch: 0,
2309 },
2310 vec![],
2311 vec![],
2312 );
2313
2314 cs.add_mul_constraint(MulConstraint {
2316 a: vec![ShiftedValueIndex::plain(ValueIndex(0))], b: vec![ShiftedValueIndex::plain(ValueIndex(1))], hi: vec![ShiftedValueIndex::plain(ValueIndex(100))], lo: vec![ShiftedValueIndex::plain(ValueIndex(3))], });
2321
2322 let result = cs.validate_and_prepare();
2323 assert!(result.is_err(), "Should reject MUL constraint with out-of-range index");
2324
2325 match result.unwrap_err() {
2326 ConstraintSystemError::OutOfRangeValueIndex {
2327 constraint_type,
2328 operand_name,
2329 value_index,
2330 total_len,
2331 ..
2332 } => {
2333 assert_eq!(constraint_type, "mul");
2334 assert_eq!(operand_name, "hi");
2335 assert_eq!(value_index, 100);
2336 assert_eq!(total_len, 16);
2337 }
2338 other => panic!("Expected OutOfRangeValueIndex error, got: {:?}", other),
2339 }
2340 }
2341
2342 #[test]
2343 fn test_validate_checks_out_of_range_before_padding() {
2344 let mut cs = ConstraintSystem::new(
2348 vec![Word::from_u64(1)],
2349 ValueVecLayout {
2350 n_const: 1,
2351 n_inout: 1,
2352 n_witness: 2,
2353 n_internal: 2,
2354 offset_inout: 4,
2355 offset_witness: 8,
2356 committed_total_len: 16,
2357 n_scratch: 0,
2358 },
2359 vec![],
2360 vec![],
2361 );
2362
2363 cs.add_and_constraint(AndConstraint::plain_abc(
2366 vec![ValueIndex(0)],
2367 vec![ValueIndex(20)], vec![ValueIndex(8)],
2369 ));
2370
2371 let result = cs.validate_and_prepare();
2372 assert!(result.is_err());
2373
2374 match result.unwrap_err() {
2376 ConstraintSystemError::OutOfRangeValueIndex { .. } => {
2377 }
2379 other => panic!(
2380 "Expected OutOfRangeValueIndex to be detected before padding check, got: {:?}",
2381 other
2382 ),
2383 }
2384 }
2385}