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 = self.and_constraints.len().max(1).next_power_of_two();
563 let mul_target_size =
564 cmp::max(consts::MIN_MUL_CONSTRAINTS, self.mul_constraints.len()).next_power_of_two();
565
566 self.and_constraints
567 .resize_with(and_target_size, AndConstraint::default);
568 self.mul_constraints
569 .resize_with(mul_target_size, MulConstraint::default);
570
571 Ok(())
572 }
573
574 #[cfg(test)]
575 fn add_and_constraint(&mut self, and_constraint: AndConstraint) {
576 self.and_constraints.push(and_constraint);
577 }
578
579 #[cfg(test)]
580 fn add_mul_constraint(&mut self, mul_constraint: MulConstraint) {
581 self.mul_constraints.push(mul_constraint);
582 }
583
584 pub fn n_and_constraints(&self) -> usize {
586 self.and_constraints.len()
587 }
588
589 pub fn n_mul_constraints(&self) -> usize {
591 self.mul_constraints.len()
592 }
593
594 pub fn value_vec_len(&self) -> usize {
596 self.value_vec_layout.committed_total_len
597 }
598
599 pub fn new_value_vec(&self) -> ValueVec {
601 ValueVec::new(self.value_vec_layout.clone())
602 }
603}
604
605impl SerializeBytes for ConstraintSystem {
606 fn serialize(&self, mut write_buf: impl BufMut) -> Result<(), SerializationError> {
607 Self::SERIALIZATION_VERSION.serialize(&mut write_buf)?;
608
609 self.value_vec_layout.serialize(&mut write_buf)?;
610 self.constants.serialize(&mut write_buf)?;
611 self.and_constraints.serialize(&mut write_buf)?;
612 self.mul_constraints.serialize(write_buf)
613 }
614}
615
616impl DeserializeBytes for ConstraintSystem {
617 fn deserialize(mut read_buf: impl Buf) -> Result<Self, SerializationError>
618 where
619 Self: Sized,
620 {
621 let version = u32::deserialize(&mut read_buf)?;
622 if version != Self::SERIALIZATION_VERSION {
623 return Err(SerializationError::InvalidConstruction {
624 name: "ConstraintSystem::version",
625 });
626 }
627
628 let value_vec_layout = ValueVecLayout::deserialize(&mut read_buf)?;
629 let constants = Vec::<Word>::deserialize(&mut read_buf)?;
630 let and_constraints = Vec::<AndConstraint>::deserialize(&mut read_buf)?;
631 let mul_constraints = Vec::<MulConstraint>::deserialize(read_buf)?;
632
633 if constants.len() != value_vec_layout.n_const {
634 return Err(SerializationError::InvalidConstruction {
635 name: "ConstraintSystem::constants",
636 });
637 }
638
639 Ok(ConstraintSystem {
640 value_vec_layout,
641 constants,
642 and_constraints,
643 mul_constraints,
644 })
645 }
646}
647
648#[derive(Clone, Debug, PartialEq, Eq)]
650pub struct ValueVecLayout {
651 pub n_const: usize,
653 pub n_inout: usize,
655 pub n_witness: usize,
657 pub n_internal: usize,
661
662 pub offset_inout: usize,
664 pub offset_witness: usize,
669 pub committed_total_len: usize,
674 pub n_scratch: usize,
676}
677
678impl ValueVecLayout {
679 pub fn validate(&self) -> Result<(), ConstraintSystemError> {
687 if !self.committed_total_len.is_power_of_two() {
688 return Err(ConstraintSystemError::ValueVecLenNotPowerOfTwo);
689 }
690
691 if !self.offset_witness.is_power_of_two() {
692 return Err(ConstraintSystemError::PublicInputPowerOfTwo);
693 }
694
695 let pub_input_size = self.offset_witness;
696 if pub_input_size < consts::MIN_WORDS_PER_SEGMENT {
697 return Err(ConstraintSystemError::PublicInputTooShort { pub_input_size });
698 }
699
700 Ok(())
701 }
702
703 fn is_padding(&self, index: ValueIndex) -> bool {
705 let idx = index.0 as usize;
706
707 if idx >= self.n_const && idx < self.offset_inout {
709 return true;
710 }
711
712 let end_of_inout = self.offset_inout + self.n_inout;
714 if idx >= end_of_inout && idx < self.offset_witness {
715 return true;
716 }
717
718 let end_of_internal = self.offset_witness + self.n_witness + self.n_internal;
720 if idx >= end_of_internal && idx < self.committed_total_len {
721 return true;
722 }
723
724 false
725 }
726
727 fn is_committed_oob(&self, index: ValueIndex) -> bool {
729 index.0 as usize >= self.committed_total_len
730 }
731}
732
733impl SerializeBytes for ValueVecLayout {
734 fn serialize(&self, mut write_buf: impl BufMut) -> Result<(), SerializationError> {
735 self.n_const.serialize(&mut write_buf)?;
736 self.n_inout.serialize(&mut write_buf)?;
737 self.n_witness.serialize(&mut write_buf)?;
738 self.n_internal.serialize(&mut write_buf)?;
739 self.offset_inout.serialize(&mut write_buf)?;
740 self.offset_witness.serialize(&mut write_buf)?;
741 self.committed_total_len.serialize(&mut write_buf)?;
742 self.n_scratch.serialize(write_buf)
743 }
744}
745
746impl DeserializeBytes for ValueVecLayout {
747 fn deserialize(mut read_buf: impl Buf) -> Result<Self, SerializationError>
748 where
749 Self: Sized,
750 {
751 let n_const = usize::deserialize(&mut read_buf)?;
752 let n_inout = usize::deserialize(&mut read_buf)?;
753 let n_witness = usize::deserialize(&mut read_buf)?;
754 let n_internal = usize::deserialize(&mut read_buf)?;
755 let offset_inout = usize::deserialize(&mut read_buf)?;
756 let offset_witness = usize::deserialize(&mut read_buf)?;
757 let committed_total_len = usize::deserialize(&mut read_buf)?;
758 let n_scratch = usize::deserialize(read_buf)?;
759
760 Ok(ValueVecLayout {
761 n_const,
762 n_inout,
763 n_witness,
764 n_internal,
765 offset_inout,
766 offset_witness,
767 committed_total_len,
768 n_scratch,
769 })
770 }
771}
772
773#[derive(Clone, Debug)]
782pub struct ValueVec {
783 layout: ValueVecLayout,
784 data: Vec<Word>,
785}
786
787impl ValueVec {
788 pub fn new(layout: ValueVecLayout) -> ValueVec {
792 let size = layout.committed_total_len + layout.n_scratch;
793 ValueVec {
794 layout,
795 data: vec![Word::ZERO; size],
796 }
797 }
798
799 pub fn new_from_data(
803 layout: ValueVecLayout,
804 public: Vec<Word>,
805 private: Vec<Word>,
806 ) -> Result<ValueVec, ConstraintSystemError> {
807 let committed_len = public.len() + private.len();
808 if committed_len != layout.committed_total_len {
809 return Err(ConstraintSystemError::ValueVecLenMismatch {
810 expected: layout.committed_total_len,
811 actual: committed_len,
812 });
813 }
814
815 let full_len = layout.committed_total_len + layout.n_scratch;
816 let mut data = public;
817 data.reserve(full_len);
818 data.extend_from_slice(&private);
819 data.resize(full_len, Word::ZERO);
820
821 Ok(ValueVec { layout, data })
822 }
823
824 pub fn size(&self) -> usize {
826 self.layout.committed_total_len
827 }
828
829 pub fn get(&self, index: usize) -> Word {
833 self.data[index]
834 }
835
836 pub fn set(&mut self, index: usize, value: Word) {
840 self.data[index] = value;
841 }
842
843 pub fn public(&self) -> &[Word] {
845 &self.data[..self.layout.offset_witness]
846 }
847
848 pub fn non_public(&self) -> &[Word] {
850 &self.data[self.layout.offset_witness..self.layout.committed_total_len]
851 }
852
853 pub fn witness(&self) -> &[Word] {
855 let start = self.layout.offset_witness;
856 let end = start + self.layout.n_witness;
857 &self.data[start..end]
858 }
859
860 pub fn combined_witness(&self) -> &[Word] {
862 let start = 0;
863 let end = self.layout.committed_total_len;
864 &self.data[start..end]
865 }
866}
867
868impl Index<ValueIndex> for ValueVec {
869 type Output = Word;
870
871 fn index(&self, index: ValueIndex) -> &Self::Output {
872 &self.data[index.0 as usize]
873 }
874}
875
876impl IndexMut<ValueIndex> for ValueVec {
877 fn index_mut(&mut self, index: ValueIndex) -> &mut Self::Output {
878 &mut self.data[index.0 as usize]
879 }
880}
881
882#[derive(Clone, Debug, PartialEq, Eq)]
888pub struct ValuesData<'a> {
889 data: Cow<'a, [Word]>,
890}
891
892impl<'a> ValuesData<'a> {
893 pub const SERIALIZATION_VERSION: u32 = 1;
895
896 pub fn borrowed(data: &'a [Word]) -> Self {
898 Self {
899 data: Cow::Borrowed(data),
900 }
901 }
902
903 pub fn owned(data: Vec<Word>) -> Self {
905 Self {
906 data: Cow::Owned(data),
907 }
908 }
909
910 pub fn as_slice(&self) -> &[Word] {
912 &self.data
913 }
914
915 pub fn len(&self) -> usize {
917 self.data.len()
918 }
919
920 pub fn is_empty(&self) -> bool {
922 self.data.is_empty()
923 }
924
925 pub fn into_owned(self) -> Vec<Word> {
927 self.data.into_owned()
928 }
929
930 pub fn to_owned(&self) -> ValuesData<'static> {
932 ValuesData {
933 data: Cow::Owned(self.data.to_vec()),
934 }
935 }
936}
937
938impl<'a> SerializeBytes for ValuesData<'a> {
939 fn serialize(&self, mut write_buf: impl BufMut) -> Result<(), SerializationError> {
940 Self::SERIALIZATION_VERSION.serialize(&mut write_buf)?;
941
942 self.data.as_ref().serialize(write_buf)
943 }
944}
945
946impl DeserializeBytes for ValuesData<'static> {
947 fn deserialize(mut read_buf: impl Buf) -> Result<Self, SerializationError>
948 where
949 Self: Sized,
950 {
951 let version = u32::deserialize(&mut read_buf)?;
952 if version != Self::SERIALIZATION_VERSION {
953 return Err(SerializationError::InvalidConstruction {
954 name: "Witness::version",
955 });
956 }
957
958 let data = Vec::<Word>::deserialize(read_buf)?;
959
960 Ok(ValuesData::owned(data))
961 }
962}
963
964impl<'a> From<&'a [Word]> for ValuesData<'a> {
965 fn from(data: &'a [Word]) -> Self {
966 ValuesData::borrowed(data)
967 }
968}
969
970impl From<Vec<Word>> for ValuesData<'static> {
971 fn from(data: Vec<Word>) -> Self {
972 ValuesData::owned(data)
973 }
974}
975
976impl<'a> AsRef<[Word]> for ValuesData<'a> {
977 fn as_ref(&self) -> &[Word] {
978 self.as_slice()
979 }
980}
981
982impl<'a> std::ops::Deref for ValuesData<'a> {
983 type Target = [Word];
984
985 fn deref(&self) -> &Self::Target {
986 self.as_slice()
987 }
988}
989
990impl<'a> From<ValuesData<'a>> for Vec<Word> {
991 fn from(value: ValuesData<'a>) -> Self {
992 value.into_owned()
993 }
994}
995
996#[derive(Clone, Debug, PartialEq, Eq)]
1013pub struct Proof<'a> {
1014 data: Cow<'a, [u8]>,
1015 challenger_type: String,
1016}
1017
1018impl<'a> Proof<'a> {
1019 pub const SERIALIZATION_VERSION: u32 = 1;
1021
1022 pub fn borrowed(data: &'a [u8], challenger_type: String) -> Self {
1024 Self {
1025 data: Cow::Borrowed(data),
1026 challenger_type,
1027 }
1028 }
1029
1030 pub fn owned(data: Vec<u8>, challenger_type: String) -> Self {
1032 Self {
1033 data: Cow::Owned(data),
1034 challenger_type,
1035 }
1036 }
1037
1038 pub fn as_slice(&self) -> &[u8] {
1040 &self.data
1041 }
1042
1043 pub fn challenger_type(&self) -> &str {
1045 &self.challenger_type
1046 }
1047
1048 pub fn len(&self) -> usize {
1050 self.data.len()
1051 }
1052
1053 pub fn is_empty(&self) -> bool {
1055 self.data.is_empty()
1056 }
1057
1058 pub fn into_owned(self) -> (Vec<u8>, String) {
1060 (self.data.into_owned(), self.challenger_type)
1061 }
1062
1063 pub fn to_owned(&self) -> Proof<'static> {
1065 Proof {
1066 data: Cow::Owned(self.data.to_vec()),
1067 challenger_type: self.challenger_type.clone(),
1068 }
1069 }
1070}
1071
1072impl<'a> SerializeBytes for Proof<'a> {
1073 fn serialize(&self, mut write_buf: impl BufMut) -> Result<(), SerializationError> {
1074 Self::SERIALIZATION_VERSION.serialize(&mut write_buf)?;
1075
1076 self.challenger_type.serialize(&mut write_buf)?;
1077
1078 self.data.as_ref().serialize(write_buf)
1079 }
1080}
1081
1082impl DeserializeBytes for Proof<'static> {
1083 fn deserialize(mut read_buf: impl Buf) -> Result<Self, SerializationError>
1084 where
1085 Self: Sized,
1086 {
1087 let version = u32::deserialize(&mut read_buf)?;
1088 if version != Self::SERIALIZATION_VERSION {
1089 return Err(SerializationError::InvalidConstruction {
1090 name: "Proof::version",
1091 });
1092 }
1093
1094 let challenger_type = String::deserialize(&mut read_buf)?;
1095 let data = Vec::<u8>::deserialize(read_buf)?;
1096
1097 Ok(Proof::owned(data, challenger_type))
1098 }
1099}
1100
1101impl<'a> From<(&'a [u8], String)> for Proof<'a> {
1102 fn from((data, challenger_type): (&'a [u8], String)) -> Self {
1103 Proof::borrowed(data, challenger_type)
1104 }
1105}
1106
1107impl From<(Vec<u8>, String)> for Proof<'static> {
1108 fn from((data, challenger_type): (Vec<u8>, String)) -> Self {
1109 Proof::owned(data, challenger_type)
1110 }
1111}
1112
1113impl<'a> AsRef<[u8]> for Proof<'a> {
1114 fn as_ref(&self) -> &[u8] {
1115 self.as_slice()
1116 }
1117}
1118
1119impl<'a> std::ops::Deref for Proof<'a> {
1120 type Target = [u8];
1121
1122 fn deref(&self) -> &Self::Target {
1123 self.as_slice()
1124 }
1125}
1126
1127#[cfg(test)]
1128mod serialization_tests {
1129 use rand::{RngCore, SeedableRng, rngs::StdRng};
1130
1131 use super::*;
1132
1133 pub(crate) fn create_test_constraint_system() -> ConstraintSystem {
1134 let constants = vec![
1135 Word::from_u64(1),
1136 Word::from_u64(42),
1137 Word::from_u64(0xDEADBEEF),
1138 ];
1139
1140 let value_vec_layout = ValueVecLayout {
1141 n_const: 3,
1142 n_inout: 2,
1143 n_witness: 10,
1144 n_internal: 3,
1145 offset_inout: 4, offset_witness: 8, committed_total_len: 16, n_scratch: 0,
1149 };
1150
1151 let and_constraints = vec![
1152 AndConstraint::plain_abc(
1153 vec![ValueIndex(0), ValueIndex(1)],
1154 vec![ValueIndex(2)],
1155 vec![ValueIndex(3), ValueIndex(4)],
1156 ),
1157 AndConstraint::abc(
1158 vec![ShiftedValueIndex::sll(ValueIndex(0), 5)],
1159 vec![ShiftedValueIndex::srl(ValueIndex(1), 10)],
1160 vec![ShiftedValueIndex::sar(ValueIndex(2), 15)],
1161 ),
1162 ];
1163
1164 let mul_constraints = vec![MulConstraint {
1165 a: vec![ShiftedValueIndex::plain(ValueIndex(0))],
1166 b: vec![ShiftedValueIndex::plain(ValueIndex(1))],
1167 hi: vec![ShiftedValueIndex::plain(ValueIndex(2))],
1168 lo: vec![ShiftedValueIndex::plain(ValueIndex(3))],
1169 }];
1170
1171 ConstraintSystem::new(constants, value_vec_layout, and_constraints, mul_constraints)
1172 }
1173
1174 #[test]
1175 fn test_word_serialization_round_trip() {
1176 let mut rng = StdRng::seed_from_u64(0);
1177 let word = Word::from_u64(rng.next_u64());
1178
1179 let mut buf = Vec::new();
1180 word.serialize(&mut buf).unwrap();
1181
1182 let deserialized = Word::deserialize(&mut buf.as_slice()).unwrap();
1183 assert_eq!(word, deserialized);
1184 }
1185
1186 #[test]
1187 fn test_shift_variant_serialization_round_trip() {
1188 let variants = [
1189 ShiftVariant::Sll,
1190 ShiftVariant::Slr,
1191 ShiftVariant::Sar,
1192 ShiftVariant::Rotr,
1193 ];
1194
1195 for variant in variants {
1196 let mut buf = Vec::new();
1197 variant.serialize(&mut buf).unwrap();
1198
1199 let deserialized = ShiftVariant::deserialize(&mut buf.as_slice()).unwrap();
1200 match (variant, deserialized) {
1201 (ShiftVariant::Sll, ShiftVariant::Sll)
1202 | (ShiftVariant::Slr, ShiftVariant::Slr)
1203 | (ShiftVariant::Sar, ShiftVariant::Sar)
1204 | (ShiftVariant::Rotr, ShiftVariant::Rotr) => {}
1205 _ => panic!("ShiftVariant round trip failed: {:?} != {:?}", variant, deserialized),
1206 }
1207 }
1208 }
1209
1210 #[test]
1211 fn test_shift_variant_unknown_variant() {
1212 let mut buf = Vec::new();
1214 255u8.serialize(&mut buf).unwrap();
1215
1216 let result = ShiftVariant::deserialize(&mut buf.as_slice());
1217 assert!(result.is_err());
1218 match result.unwrap_err() {
1219 SerializationError::UnknownEnumVariant { name, index } => {
1220 assert_eq!(name, "ShiftVariant");
1221 assert_eq!(index, 255);
1222 }
1223 _ => panic!("Expected UnknownEnumVariant error"),
1224 }
1225 }
1226
1227 #[test]
1228 fn test_value_index_serialization_round_trip() {
1229 let value_index = ValueIndex(12345);
1230
1231 let mut buf = Vec::new();
1232 value_index.serialize(&mut buf).unwrap();
1233
1234 let deserialized = ValueIndex::deserialize(&mut buf.as_slice()).unwrap();
1235 assert_eq!(value_index, deserialized);
1236 }
1237
1238 #[test]
1239 fn test_shifted_value_index_serialization_round_trip() {
1240 let shifted_value_index = ShiftedValueIndex::srl(ValueIndex(42), 23);
1241
1242 let mut buf = Vec::new();
1243 shifted_value_index.serialize(&mut buf).unwrap();
1244
1245 let deserialized = ShiftedValueIndex::deserialize(&mut buf.as_slice()).unwrap();
1246 assert_eq!(shifted_value_index.value_index, deserialized.value_index);
1247 assert_eq!(shifted_value_index.amount, deserialized.amount);
1248 match (shifted_value_index.shift_variant, deserialized.shift_variant) {
1249 (ShiftVariant::Slr, ShiftVariant::Slr) => {}
1250 _ => panic!("ShiftVariant mismatch"),
1251 }
1252 }
1253
1254 #[test]
1255 fn test_shifted_value_index_invalid_amount() {
1256 let mut buf = Vec::new();
1258 ValueIndex(0).serialize(&mut buf).unwrap();
1259 ShiftVariant::Sll.serialize(&mut buf).unwrap();
1260 64usize.serialize(&mut buf).unwrap(); let result = ShiftedValueIndex::deserialize(&mut buf.as_slice());
1263 assert!(result.is_err());
1264 match result.unwrap_err() {
1265 SerializationError::InvalidConstruction { name } => {
1266 assert_eq!(name, "ShiftedValueIndex::amount");
1267 }
1268 _ => panic!("Expected InvalidConstruction error"),
1269 }
1270 }
1271
1272 #[test]
1273 fn test_and_constraint_serialization_round_trip() {
1274 let constraint = AndConstraint::abc(
1275 vec![ShiftedValueIndex::sll(ValueIndex(1), 5)],
1276 vec![ShiftedValueIndex::srl(ValueIndex(2), 10)],
1277 vec![
1278 ShiftedValueIndex::sar(ValueIndex(3), 15),
1279 ShiftedValueIndex::plain(ValueIndex(4)),
1280 ],
1281 );
1282
1283 let mut buf = Vec::new();
1284 constraint.serialize(&mut buf).unwrap();
1285
1286 let deserialized = AndConstraint::deserialize(&mut buf.as_slice()).unwrap();
1287 assert_eq!(constraint.a.len(), deserialized.a.len());
1288 assert_eq!(constraint.b.len(), deserialized.b.len());
1289 assert_eq!(constraint.c.len(), deserialized.c.len());
1290
1291 for (orig, deser) in constraint.a.iter().zip(deserialized.a.iter()) {
1292 assert_eq!(orig.value_index, deser.value_index);
1293 assert_eq!(orig.amount, deser.amount);
1294 }
1295 }
1296
1297 #[test]
1298 fn test_mul_constraint_serialization_round_trip() {
1299 let constraint = MulConstraint {
1300 a: vec![ShiftedValueIndex::plain(ValueIndex(0))],
1301 b: vec![ShiftedValueIndex::srl(ValueIndex(1), 32)],
1302 hi: vec![ShiftedValueIndex::plain(ValueIndex(2))],
1303 lo: vec![ShiftedValueIndex::plain(ValueIndex(3))],
1304 };
1305
1306 let mut buf = Vec::new();
1307 constraint.serialize(&mut buf).unwrap();
1308
1309 let deserialized = MulConstraint::deserialize(&mut buf.as_slice()).unwrap();
1310 assert_eq!(constraint.a.len(), deserialized.a.len());
1311 assert_eq!(constraint.b.len(), deserialized.b.len());
1312 assert_eq!(constraint.hi.len(), deserialized.hi.len());
1313 assert_eq!(constraint.lo.len(), deserialized.lo.len());
1314 }
1315
1316 #[test]
1317 fn test_value_vec_layout_serialization_round_trip() {
1318 let layout = ValueVecLayout {
1319 n_const: 5,
1320 n_inout: 3,
1321 n_witness: 12,
1322 n_internal: 7,
1323 offset_inout: 8,
1324 offset_witness: 16,
1325 committed_total_len: 32,
1326 n_scratch: 0,
1327 };
1328
1329 let mut buf = Vec::new();
1330 layout.serialize(&mut buf).unwrap();
1331
1332 let deserialized = ValueVecLayout::deserialize(&mut buf.as_slice()).unwrap();
1333 assert_eq!(layout, deserialized);
1334 }
1335
1336 #[test]
1337 fn test_constraint_system_serialization_round_trip() {
1338 let original = create_test_constraint_system();
1339
1340 let mut buf = Vec::new();
1341 original.serialize(&mut buf).unwrap();
1342
1343 let deserialized = ConstraintSystem::deserialize(&mut buf.as_slice()).unwrap();
1344
1345 assert_eq!(ConstraintSystem::SERIALIZATION_VERSION, 2);
1347
1348 assert_eq!(original.value_vec_layout, deserialized.value_vec_layout);
1350
1351 assert_eq!(original.constants.len(), deserialized.constants.len());
1353 for (orig, deser) in original.constants.iter().zip(deserialized.constants.iter()) {
1354 assert_eq!(orig, deser);
1355 }
1356
1357 assert_eq!(original.and_constraints.len(), deserialized.and_constraints.len());
1359
1360 assert_eq!(original.mul_constraints.len(), deserialized.mul_constraints.len());
1362 }
1363
1364 #[test]
1365 fn test_constraint_system_version_mismatch() {
1366 let mut buf = Vec::new();
1368 999u32.serialize(&mut buf).unwrap(); let result = ConstraintSystem::deserialize(&mut buf.as_slice());
1371 assert!(result.is_err());
1372 match result.unwrap_err() {
1373 SerializationError::InvalidConstruction { name } => {
1374 assert_eq!(name, "ConstraintSystem::version");
1375 }
1376 _ => panic!("Expected InvalidConstruction error"),
1377 }
1378 }
1379
1380 #[test]
1381 fn test_constraint_system_constants_length_mismatch() {
1382 let value_vec_layout = ValueVecLayout {
1384 n_const: 5, n_inout: 2,
1386 n_witness: 10,
1387 n_internal: 3,
1388 offset_inout: 8,
1389 offset_witness: 16,
1390 committed_total_len: 32,
1391 n_scratch: 0,
1392 };
1393
1394 let constants = vec![Word::from_u64(1), Word::from_u64(2)]; let and_constraints: Vec<AndConstraint> = vec![];
1396 let mul_constraints: Vec<MulConstraint> = vec![];
1397
1398 let mut buf = Vec::new();
1400 ConstraintSystem::SERIALIZATION_VERSION
1401 .serialize(&mut buf)
1402 .unwrap();
1403 value_vec_layout.serialize(&mut buf).unwrap();
1404 constants.serialize(&mut buf).unwrap();
1405 and_constraints.serialize(&mut buf).unwrap();
1406 mul_constraints.serialize(&mut buf).unwrap();
1407
1408 let result = ConstraintSystem::deserialize(&mut buf.as_slice());
1409 assert!(result.is_err());
1410 match result.unwrap_err() {
1411 SerializationError::InvalidConstruction { name } => {
1412 assert_eq!(name, "ConstraintSystem::constants");
1413 }
1414 _ => panic!("Expected InvalidConstruction error"),
1415 }
1416 }
1417
1418 #[test]
1419 fn test_serialization_with_different_sources() {
1420 let original = create_test_constraint_system();
1421
1422 let mut vec_buf = Vec::new();
1424 original.serialize(&mut vec_buf).unwrap();
1425 let deserialized1 = ConstraintSystem::deserialize(&mut vec_buf.as_slice()).unwrap();
1426 assert_eq!(original.constants.len(), deserialized1.constants.len());
1427
1428 let mut bytes_buf = bytes::BytesMut::new();
1430 original.serialize(&mut bytes_buf).unwrap();
1431 let deserialized2 = ConstraintSystem::deserialize(bytes_buf.freeze()).unwrap();
1432 assert_eq!(original.constants.len(), deserialized2.constants.len());
1433 }
1434
1435 #[test]
1439 #[ignore] fn create_reference_binary_file() {
1441 let constraint_system = create_test_constraint_system();
1442
1443 let mut buf = Vec::new();
1445 constraint_system.serialize(&mut buf).unwrap();
1446
1447 let test_data_path = std::path::Path::new("test_data/constraint_system_v2.bin");
1449
1450 if let Some(parent) = test_data_path.parent() {
1452 std::fs::create_dir_all(parent).unwrap();
1453 }
1454
1455 std::fs::write(test_data_path, &buf).unwrap();
1456
1457 println!("Created reference binary file at: {:?}", test_data_path);
1458 println!("Binary data length: {} bytes", buf.len());
1459 }
1460
1461 #[test]
1464 fn test_deserialize_from_reference_binary_file() {
1465 let binary_data = include_bytes!("../test_data/constraint_system_v2.bin");
1468
1469 let deserialized = ConstraintSystem::deserialize(&mut binary_data.as_slice()).unwrap();
1470
1471 assert_eq!(deserialized.value_vec_layout.n_const, 3);
1472 assert_eq!(deserialized.value_vec_layout.n_inout, 2);
1473 assert_eq!(deserialized.value_vec_layout.n_witness, 10);
1474 assert_eq!(deserialized.value_vec_layout.n_internal, 3);
1475 assert_eq!(deserialized.value_vec_layout.offset_inout, 4);
1476 assert_eq!(deserialized.value_vec_layout.offset_witness, 8);
1477 assert_eq!(deserialized.value_vec_layout.committed_total_len, 16);
1478 assert_eq!(deserialized.value_vec_layout.n_scratch, 0);
1479
1480 assert_eq!(deserialized.constants.len(), 3);
1481 assert_eq!(deserialized.constants[0].as_u64(), 1);
1482 assert_eq!(deserialized.constants[1].as_u64(), 42);
1483 assert_eq!(deserialized.constants[2].as_u64(), 0xDEADBEEF);
1484
1485 assert_eq!(deserialized.and_constraints.len(), 2);
1486 assert_eq!(deserialized.mul_constraints.len(), 1);
1487
1488 let version_bytes = &binary_data[0..4]; let expected_version_bytes = 2u32.to_le_bytes(); assert_eq!(
1494 version_bytes, expected_version_bytes,
1495 "Binary file version mismatch. If you made breaking changes, increment ConstraintSystem::SERIALIZATION_VERSION"
1496 );
1497 }
1498
1499 #[test]
1500 fn test_witness_serialization_round_trip_owned() {
1501 let data = vec![
1502 Word::from_u64(1),
1503 Word::from_u64(42),
1504 Word::from_u64(0xDEADBEEF),
1505 Word::from_u64(0x1234567890ABCDEF),
1506 ];
1507 let witness = ValuesData::owned(data.clone());
1508
1509 let mut buf = Vec::new();
1510 witness.serialize(&mut buf).unwrap();
1511
1512 let deserialized = ValuesData::deserialize(&mut buf.as_slice()).unwrap();
1513 assert_eq!(witness, deserialized);
1514 assert_eq!(deserialized.as_slice(), data.as_slice());
1515 }
1516
1517 #[test]
1518 fn test_witness_serialization_round_trip_borrowed() {
1519 let data = vec![Word::from_u64(123), Word::from_u64(456)];
1520 let witness = ValuesData::borrowed(&data);
1521
1522 let mut buf = Vec::new();
1523 witness.serialize(&mut buf).unwrap();
1524
1525 let deserialized = ValuesData::deserialize(&mut buf.as_slice()).unwrap();
1526 assert_eq!(witness, deserialized);
1527 assert_eq!(deserialized.as_slice(), data.as_slice());
1528 }
1529
1530 #[test]
1531 fn test_witness_version_mismatch() {
1532 let mut buf = Vec::new();
1533 999u32.serialize(&mut buf).unwrap(); vec![Word::from_u64(1)].serialize(&mut buf).unwrap(); let result = ValuesData::deserialize(&mut buf.as_slice());
1537 assert!(result.is_err());
1538 match result.unwrap_err() {
1539 SerializationError::InvalidConstruction { name } => {
1540 assert_eq!(name, "Witness::version");
1541 }
1542 _ => panic!("Expected version mismatch error"),
1543 }
1544 }
1545
1546 #[test]
1549 #[ignore] fn create_witness_reference_binary_file() {
1551 let data = vec![
1552 Word::from_u64(1),
1553 Word::from_u64(42),
1554 Word::from_u64(0xDEADBEEF),
1555 Word::from_u64(0x1234567890ABCDEF),
1556 ];
1557 let witness = ValuesData::owned(data);
1558
1559 let mut buf = Vec::new();
1560 witness.serialize(&mut buf).unwrap();
1561
1562 let test_data_path = std::path::Path::new("verifier/core/test_data/witness_v1.bin");
1563
1564 if let Some(parent) = test_data_path.parent() {
1565 std::fs::create_dir_all(parent).unwrap();
1566 }
1567
1568 std::fs::write(test_data_path, &buf).unwrap();
1569
1570 println!("Created Witness reference binary file at: {:?}", test_data_path);
1571 println!("Binary data length: {} bytes", buf.len());
1572 }
1573
1574 #[test]
1578 fn test_witness_deserialize_from_reference_binary_file() {
1579 let binary_data = include_bytes!("../test_data/witness_v1.bin");
1580
1581 let deserialized = ValuesData::deserialize(&mut binary_data.as_slice()).unwrap();
1582
1583 assert_eq!(deserialized.len(), 4);
1584 assert_eq!(deserialized.as_slice()[0].as_u64(), 1);
1585 assert_eq!(deserialized.as_slice()[1].as_u64(), 42);
1586 assert_eq!(deserialized.as_slice()[2].as_u64(), 0xDEADBEEF);
1587 assert_eq!(deserialized.as_slice()[3].as_u64(), 0x1234567890ABCDEF);
1588
1589 let version_bytes = &binary_data[0..4]; let expected_version_bytes = 1u32.to_le_bytes(); assert_eq!(
1595 version_bytes, expected_version_bytes,
1596 "WitnessData binary file version mismatch. If you made breaking changes, increment WitnessData::SERIALIZATION_VERSION"
1597 );
1598 }
1599
1600 #[test]
1601 fn test_proof_serialization_round_trip_owned() {
1602 let transcript_data = vec![0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0];
1603 let challenger_type = "HasherChallenger<Sha256>".to_string();
1604 let proof = Proof::owned(transcript_data.clone(), challenger_type.clone());
1605
1606 let mut buf = Vec::new();
1607 proof.serialize(&mut buf).unwrap();
1608
1609 let deserialized = Proof::deserialize(&mut buf.as_slice()).unwrap();
1610 assert_eq!(proof, deserialized);
1611 assert_eq!(deserialized.as_slice(), transcript_data.as_slice());
1612 assert_eq!(deserialized.challenger_type(), &challenger_type);
1613 }
1614
1615 #[test]
1616 fn test_proof_serialization_round_trip_borrowed() {
1617 let transcript_data = vec![0xAA, 0xBB, 0xCC, 0xDD];
1618 let challenger_type = "TestChallenger".to_string();
1619 let proof = Proof::borrowed(&transcript_data, challenger_type.clone());
1620
1621 let mut buf = Vec::new();
1622 proof.serialize(&mut buf).unwrap();
1623
1624 let deserialized = Proof::deserialize(&mut buf.as_slice()).unwrap();
1625 assert_eq!(proof, deserialized);
1626 assert_eq!(deserialized.as_slice(), transcript_data.as_slice());
1627 assert_eq!(deserialized.challenger_type(), &challenger_type);
1628 }
1629
1630 #[test]
1631 fn test_proof_empty_transcript() {
1632 let proof = Proof::owned(vec![], "EmptyProof".to_string());
1633 assert!(proof.is_empty());
1634 assert_eq!(proof.len(), 0);
1635
1636 let mut buf = Vec::new();
1637 proof.serialize(&mut buf).unwrap();
1638
1639 let deserialized = Proof::deserialize(&mut buf.as_slice()).unwrap();
1640 assert_eq!(proof, deserialized);
1641 assert!(deserialized.is_empty());
1642 }
1643
1644 #[test]
1645 fn test_proof_large_transcript() {
1646 let mut rng = StdRng::seed_from_u64(12345);
1647 let mut large_data = vec![0u8; 10000];
1648 rng.fill_bytes(&mut large_data);
1649
1650 let challenger_type = "LargeProofChallenger".to_string();
1651 let proof = Proof::owned(large_data.clone(), challenger_type.clone());
1652
1653 let mut buf = Vec::new();
1654 proof.serialize(&mut buf).unwrap();
1655
1656 let deserialized = Proof::deserialize(&mut buf.as_slice()).unwrap();
1657 assert_eq!(proof, deserialized);
1658 assert_eq!(deserialized.len(), 10000);
1659 assert_eq!(deserialized.challenger_type(), &challenger_type);
1660 }
1661
1662 #[test]
1663 fn test_proof_version_mismatch() {
1664 let mut buf = Vec::new();
1665 999u32.serialize(&mut buf).unwrap(); "TestChallenger".serialize(&mut buf).unwrap(); vec![0xAAu8].serialize(&mut buf).unwrap(); let result = Proof::deserialize(&mut buf.as_slice());
1670 assert!(result.is_err());
1671 match result.unwrap_err() {
1672 SerializationError::InvalidConstruction { name } => {
1673 assert_eq!(name, "Proof::version");
1674 }
1675 _ => panic!("Expected version mismatch error"),
1676 }
1677 }
1678
1679 #[test]
1680 fn test_proof_into_owned() {
1681 let original_data = vec![1, 2, 3, 4, 5];
1682 let original_challenger = "TestChallenger".to_string();
1683 let proof = Proof::owned(original_data.clone(), original_challenger.clone());
1684
1685 let (data, challenger_type) = proof.into_owned();
1686 assert_eq!(data, original_data);
1687 assert_eq!(challenger_type, original_challenger);
1688 }
1689
1690 #[test]
1691 fn test_proof_to_owned() {
1692 let data = vec![0xFF, 0xEE, 0xDD];
1693 let challenger_type = "BorrowedChallenger".to_string();
1694 let borrowed_proof = Proof::borrowed(&data, challenger_type.clone());
1695
1696 let owned_proof = borrowed_proof.to_owned();
1697 assert_eq!(owned_proof.as_slice(), data);
1698 assert_eq!(owned_proof.challenger_type(), &challenger_type);
1699 drop(data); assert_eq!(owned_proof.len(), 3);
1702 }
1703
1704 #[test]
1705 fn test_proof_different_challenger_types() {
1706 let data = vec![0x42];
1707 let challengers = vec![
1708 "HasherChallenger<Sha256>".to_string(),
1709 "HasherChallenger<Blake2b>".to_string(),
1710 "CustomChallenger".to_string(),
1711 "".to_string(), ];
1713
1714 for challenger_type in challengers {
1715 let proof = Proof::owned(data.clone(), challenger_type.clone());
1716 let mut buf = Vec::new();
1717 proof.serialize(&mut buf).unwrap();
1718
1719 let deserialized = Proof::deserialize(&mut buf.as_slice()).unwrap();
1720 assert_eq!(deserialized.challenger_type(), &challenger_type);
1721 }
1722 }
1723
1724 #[test]
1725 fn test_proof_serialization_with_different_sources() {
1726 let transcript_data = vec![0x11, 0x22, 0x33, 0x44];
1727 let challenger_type = "MultiSourceChallenger".to_string();
1728 let original = Proof::owned(transcript_data, challenger_type);
1729
1730 let mut vec_buf = Vec::new();
1732 original.serialize(&mut vec_buf).unwrap();
1733 let deserialized1 = Proof::deserialize(&mut vec_buf.as_slice()).unwrap();
1734 assert_eq!(original, deserialized1);
1735
1736 let mut bytes_buf = bytes::BytesMut::new();
1738 original.serialize(&mut bytes_buf).unwrap();
1739 let deserialized2 = Proof::deserialize(bytes_buf.freeze()).unwrap();
1740 assert_eq!(original, deserialized2);
1741 }
1742
1743 #[test]
1746 #[ignore] fn create_proof_reference_binary_file() {
1748 let transcript_data = vec![
1749 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54,
1750 0x32, 0x10, 0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE,
1751 ];
1752 let challenger_type = "HasherChallenger<Sha256>".to_string();
1753 let proof = Proof::owned(transcript_data, challenger_type);
1754
1755 let mut buf = Vec::new();
1756 proof.serialize(&mut buf).unwrap();
1757
1758 let test_data_path = std::path::Path::new("verifier/core/test_data/proof_v1.bin");
1759
1760 if let Some(parent) = test_data_path.parent() {
1761 std::fs::create_dir_all(parent).unwrap();
1762 }
1763
1764 std::fs::write(test_data_path, &buf).unwrap();
1765
1766 println!("Created Proof reference binary file at: {:?}", test_data_path);
1767 println!("Binary data length: {} bytes", buf.len());
1768 }
1769
1770 #[test]
1774 fn test_proof_deserialize_from_reference_binary_file() {
1775 let binary_data = include_bytes!("../test_data/proof_v1.bin");
1776
1777 let deserialized = Proof::deserialize(&mut binary_data.as_slice()).unwrap();
1778
1779 assert_eq!(deserialized.len(), 24); assert_eq!(deserialized.challenger_type(), "HasherChallenger<Sha256>");
1781
1782 let expected_data = vec![
1783 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54,
1784 0x32, 0x10, 0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE,
1785 ];
1786 assert_eq!(deserialized.as_slice(), expected_data);
1787
1788 let version_bytes = &binary_data[0..4]; let expected_version_bytes = 1u32.to_le_bytes(); assert_eq!(
1794 version_bytes, expected_version_bytes,
1795 "Proof binary file version mismatch. If you made breaking changes, increment Proof::SERIALIZATION_VERSION"
1796 );
1797 }
1798
1799 #[test]
1800 fn split_values_vec_and_combine() {
1801 let values = ValueVec::new(ValueVecLayout {
1802 n_const: 2,
1803 n_inout: 2,
1804 n_witness: 2,
1805 n_internal: 2,
1806 offset_inout: 2,
1807 offset_witness: 4,
1808 committed_total_len: 8,
1809 n_scratch: 0,
1810 });
1811
1812 let public = values.public();
1813 let non_public = values.non_public();
1814 let combined =
1815 ValueVec::new_from_data(values.layout.clone(), public.to_vec(), non_public.to_vec())
1816 .unwrap();
1817 assert_eq!(combined.combined_witness(), values.combined_witness());
1818 }
1819
1820 #[test]
1821 fn test_roundtrip_cs_and_witnesses_reconstruct_valuevec_with_scratch() {
1822 let layout = ValueVecLayout {
1824 n_const: 2,
1825 n_inout: 3,
1826 n_witness: 4,
1827 n_internal: 3,
1828 offset_inout: 4, offset_witness: 8, committed_total_len: 16,
1831 n_scratch: 5, };
1833
1834 let constants = vec![Word::from_u64(11), Word::from_u64(22)];
1835 let cs = ConstraintSystem::new(constants, layout.clone(), vec![], vec![]);
1836
1837 let mut values = cs.new_value_vec();
1839 let full_len = layout.committed_total_len + layout.n_scratch;
1840 for i in 0..full_len {
1841 let val = Word::from_u64(0xA5A5_5A5A ^ (i as u64 * 0x9E37_79B9));
1843 values.set(i, val);
1844 }
1845
1846 let public_data = ValuesData::from(values.public());
1848 let non_public_data = ValuesData::from(values.non_public());
1849
1850 let mut buf_cs = Vec::new();
1851 cs.serialize(&mut buf_cs).unwrap();
1852
1853 let mut buf_pub = Vec::new();
1854 public_data.serialize(&mut buf_pub).unwrap();
1855
1856 let mut buf_non_pub = Vec::new();
1857 non_public_data.serialize(&mut buf_non_pub).unwrap();
1858
1859 let cs2 = ConstraintSystem::deserialize(&mut buf_cs.as_slice()).unwrap();
1861 let pub2 = ValuesData::deserialize(&mut buf_pub.as_slice()).unwrap();
1862 let non_pub2 = ValuesData::deserialize(&mut buf_non_pub.as_slice()).unwrap();
1863
1864 let reconstructed = ValueVec::new_from_data(
1866 cs2.value_vec_layout.clone(),
1867 pub2.into_owned(),
1868 non_pub2.into_owned(),
1869 )
1870 .unwrap();
1871
1872 assert_eq!(reconstructed.combined_witness(), values.combined_witness());
1874
1875 let scratch_start = layout.committed_total_len;
1877 let scratch_end = scratch_start + layout.n_scratch;
1878 for i in scratch_start..scratch_end {
1879 assert_eq!(reconstructed.get(i), Word::ZERO, "scratch index {i} should be zero");
1880 }
1881 }
1882
1883 #[test]
1884 fn test_is_padding_comprehensive() {
1885 let layout = ValueVecLayout {
1887 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,
1895 };
1896
1897 assert!(!layout.is_padding(ValueIndex(0)), "index 0 should be constant");
1899 assert!(!layout.is_padding(ValueIndex(1)), "index 1 should be constant");
1900
1901 assert!(
1903 layout.is_padding(ValueIndex(2)),
1904 "index 2 should be padding between const and inout"
1905 );
1906 assert!(
1907 layout.is_padding(ValueIndex(3)),
1908 "index 3 should be padding between const and inout"
1909 );
1910
1911 assert!(!layout.is_padding(ValueIndex(4)), "index 4 should be inout");
1913 assert!(!layout.is_padding(ValueIndex(5)), "index 5 should be inout");
1914 assert!(!layout.is_padding(ValueIndex(6)), "index 6 should be inout");
1915
1916 for i in 7..16 {
1918 assert!(
1919 layout.is_padding(ValueIndex(i)),
1920 "index {} should be padding between inout and witness",
1921 i
1922 );
1923 }
1924
1925 for i in 16..21 {
1927 assert!(!layout.is_padding(ValueIndex(i)), "index {} should be witness", i);
1928 }
1929
1930 for i in 21..31 {
1932 assert!(!layout.is_padding(ValueIndex(i)), "index {} should be internal", i);
1933 }
1934
1935 for i in 31..64 {
1937 assert!(
1938 layout.is_padding(ValueIndex(i)),
1939 "index {} should be padding after internal",
1940 i
1941 );
1942 }
1943 }
1944
1945 #[test]
1946 fn test_is_padding_minimal_layout() {
1947 let layout = ValueVecLayout {
1949 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,
1957 };
1958
1959 for i in 0..16 {
1961 assert!(
1962 !layout.is_padding(ValueIndex(i)),
1963 "index {} should not be padding in minimal layout",
1964 i
1965 );
1966 }
1967 }
1968
1969 #[test]
1970 fn test_is_padding_public_section_min_size() {
1971 let layout = ValueVecLayout {
1973 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,
1981 };
1982
1983 assert!(!layout.is_padding(ValueIndex(0)), "index 0 should be constant");
1985
1986 assert!(layout.is_padding(ValueIndex(1)), "index 1 should be padding");
1988 assert!(layout.is_padding(ValueIndex(2)), "index 2 should be padding");
1989 assert!(layout.is_padding(ValueIndex(3)), "index 3 should be padding");
1990
1991 assert!(!layout.is_padding(ValueIndex(4)), "index 4 should be inout");
1993
1994 assert!(layout.is_padding(ValueIndex(5)), "index 5 should be padding");
1996 assert!(layout.is_padding(ValueIndex(6)), "index 6 should be padding");
1997 assert!(layout.is_padding(ValueIndex(7)), "index 7 should be padding");
1998
1999 assert!(!layout.is_padding(ValueIndex(8)), "index 8 should be witness");
2001 assert!(!layout.is_padding(ValueIndex(9)), "index 9 should be witness");
2002
2003 assert!(!layout.is_padding(ValueIndex(10)), "index 10 should be internal");
2005 assert!(!layout.is_padding(ValueIndex(11)), "index 11 should be internal");
2006
2007 for i in 12..16 {
2009 assert!(layout.is_padding(ValueIndex(i)), "index {} should be end padding", i);
2010 }
2011 }
2012
2013 #[test]
2014 fn test_is_padding_boundary_conditions() {
2015 let layout = ValueVecLayout {
2016 n_const: 2,
2017 n_inout: 2,
2018 n_witness: 4,
2019 n_internal: 4,
2020 offset_inout: 4,
2021 offset_witness: 8,
2022 committed_total_len: 16,
2023 n_scratch: 0,
2024 };
2025
2026 assert!(!layout.is_padding(ValueIndex(1)), "last constant should not be padding");
2028 assert!(layout.is_padding(ValueIndex(2)), "first padding after const should be padding");
2029
2030 assert!(layout.is_padding(ValueIndex(3)), "last padding before inout should be padding");
2031 assert!(!layout.is_padding(ValueIndex(4)), "first inout should not be padding");
2032
2033 assert!(!layout.is_padding(ValueIndex(5)), "last inout should not be padding");
2034 assert!(layout.is_padding(ValueIndex(6)), "first padding after inout should be padding");
2035
2036 assert!(layout.is_padding(ValueIndex(7)), "last padding before witness should be padding");
2037 assert!(!layout.is_padding(ValueIndex(8)), "first witness should not be padding");
2038
2039 assert!(!layout.is_padding(ValueIndex(11)), "last witness should not be padding");
2040 assert!(!layout.is_padding(ValueIndex(12)), "first internal should not be padding");
2041
2042 assert!(!layout.is_padding(ValueIndex(15)), "last internal should not be padding");
2043 }
2045
2046 #[test]
2047 fn test_validate_rejects_padding_references() {
2048 let mut cs = ConstraintSystem::new(
2049 vec![Word::from_u64(1)],
2050 ValueVecLayout {
2051 n_const: 1,
2052 n_inout: 1,
2053 n_witness: 2,
2054 n_internal: 2,
2055 offset_inout: 4,
2056 offset_witness: 8,
2057 committed_total_len: 16,
2058 n_scratch: 0,
2059 },
2060 vec![],
2061 vec![],
2062 );
2063
2064 cs.add_and_constraint(AndConstraint::plain_abc(
2066 vec![ValueIndex(0)], vec![ValueIndex(2)], vec![ValueIndex(8)], ));
2070
2071 let result = cs.validate_and_prepare();
2072 assert!(result.is_err(), "Should reject constraint referencing padding");
2073
2074 match result.unwrap_err() {
2075 ConstraintSystemError::PaddingValueIndex {
2076 constraint_type, ..
2077 } => {
2078 assert_eq!(constraint_type, "and");
2079 }
2080 other => panic!("Expected PaddingValueIndex error, got: {:?}", other),
2081 }
2082 }
2083
2084 #[test]
2085 fn test_validate_accepts_non_padding_references() {
2086 let mut cs = ConstraintSystem::new(
2087 vec![Word::from_u64(1), Word::from_u64(2)],
2088 ValueVecLayout {
2089 n_const: 2,
2090 n_inout: 2,
2091 n_witness: 4,
2092 n_internal: 4,
2093 offset_inout: 2,
2094 offset_witness: 4,
2095 committed_total_len: 16,
2096 n_scratch: 0,
2097 },
2098 vec![],
2099 vec![],
2100 );
2101
2102 cs.add_and_constraint(AndConstraint::plain_abc(
2104 vec![ValueIndex(0), ValueIndex(1)], vec![ValueIndex(2), ValueIndex(3)], vec![ValueIndex(4), ValueIndex(5)], ));
2108
2109 cs.add_mul_constraint(MulConstraint {
2110 a: vec![ShiftedValueIndex::plain(ValueIndex(6))], b: vec![ShiftedValueIndex::plain(ValueIndex(7))], hi: vec![ShiftedValueIndex::plain(ValueIndex(8))], lo: vec![ShiftedValueIndex::plain(ValueIndex(9))], });
2115
2116 let result = cs.validate_and_prepare();
2117 assert!(
2118 result.is_ok(),
2119 "Should accept constraints with only valid references: {:?}",
2120 result
2121 );
2122 }
2123
2124 #[test]
2125 fn test_is_padding_matches_compiler_requirements() {
2126 let layout1 = ValueVecLayout {
2134 n_const: 1,
2135 n_inout: 1,
2136 n_witness: 4,
2137 n_internal: 4,
2138 offset_inout: 1, offset_witness: 8, committed_total_len: 16,
2141 n_scratch: 0,
2142 };
2143
2144 assert!(!layout1.is_padding(ValueIndex(0)), "const should not be padding");
2146 assert!(!layout1.is_padding(ValueIndex(1)), "inout should not be padding");
2147 for i in 2..8 {
2148 assert!(
2149 layout1.is_padding(ValueIndex(i)),
2150 "index {} should be padding to meet MIN_WORDS_PER_SEGMENT",
2151 i
2152 );
2153 }
2154
2155 let layout2 = ValueVecLayout {
2157 n_const: 4,
2158 n_inout: 4,
2159 n_witness: 8,
2160 n_internal: 0,
2161 offset_inout: 4,
2162 offset_witness: 8, committed_total_len: 16,
2164 n_scratch: 0,
2165 };
2166
2167 for i in 0..8 {
2169 assert!(!layout2.is_padding(ValueIndex(i)), "index {} should not be padding", i);
2170 }
2171
2172 let layout3 = ValueVecLayout {
2175 n_const: 5,
2176 n_inout: 5,
2177 n_witness: 16,
2178 n_internal: 0,
2179 offset_inout: 5,
2180 offset_witness: 16, committed_total_len: 32,
2182 n_scratch: 0,
2183 };
2184
2185 for i in 0..5 {
2187 assert!(!layout3.is_padding(ValueIndex(i)), "const {} should not be padding", i);
2188 }
2189 for i in 5..10 {
2190 assert!(!layout3.is_padding(ValueIndex(i)), "inout {} should not be padding", i);
2191 }
2192 for i in 10..16 {
2193 assert!(
2194 layout3.is_padding(ValueIndex(i)),
2195 "index {} should be padding for power-of-2 alignment",
2196 i
2197 );
2198 }
2199
2200 let layout4 = ValueVecLayout {
2202 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,
2210 };
2211
2212 assert!(!layout4.is_padding(ValueIndex(0)));
2214 assert!(!layout4.is_padding(ValueIndex(1)));
2215
2216 for i in 2..8 {
2218 assert!(layout4.is_padding(ValueIndex(i)), "padding between const and inout at {}", i);
2219 }
2220
2221 assert!(!layout4.is_padding(ValueIndex(8)));
2223 assert!(!layout4.is_padding(ValueIndex(9)));
2224
2225 for i in 10..16 {
2227 assert!(
2228 layout4.is_padding(ValueIndex(i)),
2229 "padding between inout and witness at {}",
2230 i
2231 );
2232 }
2233
2234 for i in 16..20 {
2236 assert!(!layout4.is_padding(ValueIndex(i)), "witness at {}", i);
2237 }
2238
2239 for i in 20..24 {
2241 assert!(!layout4.is_padding(ValueIndex(i)), "internal at {}", i);
2242 }
2243
2244 for i in 24..32 {
2246 assert!(layout4.is_padding(ValueIndex(i)), "padding after internal at {}", i);
2247 }
2248 }
2249
2250 #[test]
2251 fn test_validate_rejects_out_of_range_indices() {
2252 let mut cs = ConstraintSystem::new(
2253 vec![Word::from_u64(1)],
2254 ValueVecLayout {
2255 n_const: 1,
2256 n_inout: 1,
2257 n_witness: 2,
2258 n_internal: 2,
2259 offset_inout: 4,
2260 offset_witness: 8,
2261 committed_total_len: 16,
2262 n_scratch: 0,
2263 },
2264 vec![],
2265 vec![],
2266 );
2267
2268 cs.add_and_constraint(AndConstraint::plain_abc(
2270 vec![ValueIndex(0)], vec![ValueIndex(16)], vec![ValueIndex(8)], ));
2274
2275 let result = cs.validate_and_prepare();
2276 assert!(result.is_err(), "Should reject constraint with out-of-range index");
2277
2278 match result.unwrap_err() {
2279 ConstraintSystemError::OutOfRangeValueIndex {
2280 constraint_type,
2281 operand_name,
2282 value_index,
2283 total_len,
2284 ..
2285 } => {
2286 assert_eq!(constraint_type, "and");
2287 assert_eq!(operand_name, "b");
2288 assert_eq!(value_index, 16);
2289 assert_eq!(total_len, 16);
2290 }
2291 other => panic!("Expected OutOfRangeValueIndex error, got: {:?}", other),
2292 }
2293 }
2294
2295 #[test]
2296 fn test_validate_rejects_out_of_range_in_mul_constraint() {
2297 let mut cs = ConstraintSystem::new(
2298 vec![Word::from_u64(1), Word::from_u64(2)],
2299 ValueVecLayout {
2300 n_const: 2,
2301 n_inout: 2,
2302 n_witness: 4,
2303 n_internal: 4,
2304 offset_inout: 2,
2305 offset_witness: 4,
2306 committed_total_len: 16,
2307 n_scratch: 0,
2308 },
2309 vec![],
2310 vec![],
2311 );
2312
2313 cs.add_mul_constraint(MulConstraint {
2315 a: vec![ShiftedValueIndex::plain(ValueIndex(0))], b: vec![ShiftedValueIndex::plain(ValueIndex(1))], hi: vec![ShiftedValueIndex::plain(ValueIndex(100))], lo: vec![ShiftedValueIndex::plain(ValueIndex(3))], });
2320
2321 let result = cs.validate_and_prepare();
2322 assert!(result.is_err(), "Should reject MUL constraint with out-of-range index");
2323
2324 match result.unwrap_err() {
2325 ConstraintSystemError::OutOfRangeValueIndex {
2326 constraint_type,
2327 operand_name,
2328 value_index,
2329 total_len,
2330 ..
2331 } => {
2332 assert_eq!(constraint_type, "mul");
2333 assert_eq!(operand_name, "hi");
2334 assert_eq!(value_index, 100);
2335 assert_eq!(total_len, 16);
2336 }
2337 other => panic!("Expected OutOfRangeValueIndex error, got: {:?}", other),
2338 }
2339 }
2340
2341 #[test]
2342 fn test_validate_checks_out_of_range_before_padding() {
2343 let mut cs = ConstraintSystem::new(
2347 vec![Word::from_u64(1)],
2348 ValueVecLayout {
2349 n_const: 1,
2350 n_inout: 1,
2351 n_witness: 2,
2352 n_internal: 2,
2353 offset_inout: 4,
2354 offset_witness: 8,
2355 committed_total_len: 16,
2356 n_scratch: 0,
2357 },
2358 vec![],
2359 vec![],
2360 );
2361
2362 cs.add_and_constraint(AndConstraint::plain_abc(
2365 vec![ValueIndex(0)],
2366 vec![ValueIndex(20)], vec![ValueIndex(8)],
2368 ));
2369
2370 let result = cs.validate_and_prepare();
2371 assert!(result.is_err());
2372
2373 match result.unwrap_err() {
2375 ConstraintSystemError::OutOfRangeValueIndex { .. } => {
2376 }
2378 other => panic!(
2379 "Expected OutOfRangeValueIndex to be detected before padding check, got: {:?}",
2380 other
2381 ),
2382 }
2383 }
2384}