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}
61
62impl SerializeBytes for ShiftVariant {
63 fn serialize(&self, write_buf: impl BufMut) -> Result<(), SerializationError> {
64 let index = match self {
65 ShiftVariant::Sll => 0u8,
66 ShiftVariant::Slr => 1u8,
67 ShiftVariant::Sar => 2u8,
68 };
69 index.serialize(write_buf)
70 }
71}
72
73impl DeserializeBytes for ShiftVariant {
74 fn deserialize(read_buf: impl Buf) -> Result<Self, SerializationError>
75 where
76 Self: Sized,
77 {
78 let index = u8::deserialize(read_buf)?;
79 match index {
80 0 => Ok(ShiftVariant::Sll),
81 1 => Ok(ShiftVariant::Slr),
82 2 => Ok(ShiftVariant::Sar),
83 _ => Err(SerializationError::UnknownEnumVariant {
84 name: "ShiftVariant",
85 index,
86 }),
87 }
88 }
89}
90
91#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
98pub struct ShiftedValueIndex {
99 pub value_index: ValueIndex,
101 pub shift_variant: ShiftVariant,
103 pub amount: usize,
107}
108
109impl ShiftedValueIndex {
110 pub fn plain(value_index: ValueIndex) -> Self {
113 Self {
114 value_index,
115 shift_variant: ShiftVariant::Sll,
116 amount: 0,
117 }
118 }
119
120 pub fn sll(value_index: ValueIndex, amount: usize) -> Self {
125 assert!(amount < 64, "shift amount n={amount} out of range");
126 Self {
127 value_index,
128 shift_variant: ShiftVariant::Sll,
129 amount,
130 }
131 }
132
133 pub fn srl(value_index: ValueIndex, amount: usize) -> Self {
138 assert!(amount < 64, "shift amount n={amount} out of range");
139 Self {
140 value_index,
141 shift_variant: ShiftVariant::Slr,
142 amount,
143 }
144 }
145
146 pub fn sar(value_index: ValueIndex, amount: usize) -> Self {
154 assert!(amount < 64, "shift amount n={amount} out of range");
155 Self {
156 value_index,
157 shift_variant: ShiftVariant::Sar,
158 amount,
159 }
160 }
161}
162
163impl SerializeBytes for ShiftedValueIndex {
164 fn serialize(&self, mut write_buf: impl BufMut) -> Result<(), SerializationError> {
165 self.value_index.serialize(&mut write_buf)?;
166 self.shift_variant.serialize(&mut write_buf)?;
167 self.amount.serialize(write_buf)
168 }
169}
170
171impl DeserializeBytes for ShiftedValueIndex {
172 fn deserialize(mut read_buf: impl Buf) -> Result<Self, SerializationError>
173 where
174 Self: Sized,
175 {
176 let value_index = ValueIndex::deserialize(&mut read_buf)?;
177 let shift_variant = ShiftVariant::deserialize(&mut read_buf)?;
178 let amount = usize::deserialize(read_buf)?;
179
180 if amount >= 64 {
182 return Err(SerializationError::InvalidConstruction {
183 name: "ShiftedValueIndex::amount",
184 });
185 }
186
187 Ok(ShiftedValueIndex {
188 value_index,
189 shift_variant,
190 amount,
191 })
192 }
193}
194
195pub type Operand = Vec<ShiftedValueIndex>;
209
210#[derive(Debug, Clone, Default)]
215pub struct AndConstraint {
216 pub a: Operand,
218 pub b: Operand,
220 pub c: Operand,
222}
223
224impl AndConstraint {
225 pub fn plain_abc(
227 a: impl IntoIterator<Item = ValueIndex>,
228 b: impl IntoIterator<Item = ValueIndex>,
229 c: impl IntoIterator<Item = ValueIndex>,
230 ) -> AndConstraint {
231 AndConstraint {
232 a: a.into_iter().map(ShiftedValueIndex::plain).collect(),
233 b: b.into_iter().map(ShiftedValueIndex::plain).collect(),
234 c: c.into_iter().map(ShiftedValueIndex::plain).collect(),
235 }
236 }
237
238 pub fn abc(
240 a: impl IntoIterator<Item = ShiftedValueIndex>,
241 b: impl IntoIterator<Item = ShiftedValueIndex>,
242 c: impl IntoIterator<Item = ShiftedValueIndex>,
243 ) -> AndConstraint {
244 AndConstraint {
245 a: a.into_iter().collect(),
246 b: b.into_iter().collect(),
247 c: c.into_iter().collect(),
248 }
249 }
250}
251
252impl SerializeBytes for AndConstraint {
253 fn serialize(&self, mut write_buf: impl BufMut) -> Result<(), SerializationError> {
254 self.a.serialize(&mut write_buf)?;
255 self.b.serialize(&mut write_buf)?;
256 self.c.serialize(write_buf)
257 }
258}
259
260impl DeserializeBytes for AndConstraint {
261 fn deserialize(mut read_buf: impl Buf) -> Result<Self, SerializationError>
262 where
263 Self: Sized,
264 {
265 let a = Vec::<ShiftedValueIndex>::deserialize(&mut read_buf)?;
266 let b = Vec::<ShiftedValueIndex>::deserialize(&mut read_buf)?;
267 let c = Vec::<ShiftedValueIndex>::deserialize(read_buf)?;
268
269 Ok(AndConstraint { a, b, c })
270 }
271}
272
273#[derive(Debug, Clone, Default)]
278pub struct MulConstraint {
279 pub a: Operand,
281 pub b: Operand,
283 pub hi: Operand,
287 pub lo: Operand,
291}
292
293impl SerializeBytes for MulConstraint {
294 fn serialize(&self, mut write_buf: impl BufMut) -> Result<(), SerializationError> {
295 self.a.serialize(&mut write_buf)?;
296 self.b.serialize(&mut write_buf)?;
297 self.hi.serialize(&mut write_buf)?;
298 self.lo.serialize(write_buf)
299 }
300}
301
302impl DeserializeBytes for MulConstraint {
303 fn deserialize(mut read_buf: impl Buf) -> Result<Self, SerializationError>
304 where
305 Self: Sized,
306 {
307 let a = Vec::<ShiftedValueIndex>::deserialize(&mut read_buf)?;
308 let b = Vec::<ShiftedValueIndex>::deserialize(&mut read_buf)?;
309 let hi = Vec::<ShiftedValueIndex>::deserialize(&mut read_buf)?;
310 let lo = Vec::<ShiftedValueIndex>::deserialize(read_buf)?;
311
312 Ok(MulConstraint { a, b, hi, lo })
313 }
314}
315
316#[derive(Debug, Clone)]
325pub struct ConstraintSystem {
326 pub value_vec_layout: ValueVecLayout,
328 pub constants: Vec<Word>,
333 pub and_constraints: Vec<AndConstraint>,
335 pub mul_constraints: Vec<MulConstraint>,
337}
338
339impl ConstraintSystem {
340 pub const SERIALIZATION_VERSION: u32 = 2;
342}
343
344impl ConstraintSystem {
345 pub fn new(
347 constants: Vec<Word>,
348 value_vec_layout: ValueVecLayout,
349 and_constraints: Vec<AndConstraint>,
350 mul_constraints: Vec<MulConstraint>,
351 ) -> Self {
352 assert_eq!(constants.len(), value_vec_layout.n_const);
353 ConstraintSystem {
354 constants,
355 value_vec_layout,
356 and_constraints,
357 mul_constraints,
358 }
359 }
360
361 pub fn validate(&self) -> Result<(), ConstraintSystemError> {
371 self.value_vec_layout.validate()?;
373
374 for i in 0..self.and_constraints.len() {
375 validate_operand(&self.and_constraints[i].a, &self.value_vec_layout, "and", i, "a")?;
376 validate_operand(&self.and_constraints[i].b, &self.value_vec_layout, "and", i, "b")?;
377 validate_operand(&self.and_constraints[i].c, &self.value_vec_layout, "and", i, "c")?;
378 }
379 for i in 0..self.mul_constraints.len() {
380 validate_operand(&self.mul_constraints[i].a, &self.value_vec_layout, "mul", i, "a")?;
381 validate_operand(&self.mul_constraints[i].b, &self.value_vec_layout, "mul", i, "b")?;
382 validate_operand(&self.mul_constraints[i].lo, &self.value_vec_layout, "mul", i, "lo")?;
383 validate_operand(&self.mul_constraints[i].hi, &self.value_vec_layout, "mul", i, "hi")?;
384 }
385
386 return Ok(());
387
388 fn validate_operand(
389 operand: &Operand,
390 value_vec_layout: &ValueVecLayout,
391 constraint_type: &'static str,
392 constraint_index: usize,
393 operand_name: &'static str,
394 ) -> Result<(), ConstraintSystemError> {
395 for term in operand {
396 if term.amount == 0 && term.shift_variant != ShiftVariant::Sll {
398 return Err(ConstraintSystemError::NonCanonicalShift {
399 constraint_type,
400 constraint_index,
401 operand_name,
402 });
403 }
404 if term.amount >= 64 {
405 return Err(ConstraintSystemError::ShiftAmountTooLarge {
406 constraint_type,
407 constraint_index,
408 operand_name,
409 shift_amount: term.amount,
410 });
411 }
412 if value_vec_layout.is_committed_oob(term.value_index) {
414 return Err(ConstraintSystemError::OutOfRangeValueIndex {
415 constraint_type,
416 constraint_index,
417 operand_name,
418 value_index: term.value_index.0,
419 total_len: value_vec_layout.committed_total_len,
420 });
421 }
422 if value_vec_layout.is_padding(term.value_index) {
424 return Err(ConstraintSystemError::PaddingValueIndex {
425 constraint_type,
426 constraint_index,
427 operand_name,
428 });
429 }
430 }
431 Ok(())
432 }
433 }
434
435 pub fn validate_and_prepare(&mut self) -> Result<(), ConstraintSystemError> {
442 self.validate()?;
443
444 let and_target_size =
446 cmp::max(consts::MIN_AND_CONSTRAINTS, self.and_constraints.len()).next_power_of_two();
447 let mul_target_size =
448 cmp::max(consts::MIN_MUL_CONSTRAINTS, self.mul_constraints.len()).next_power_of_two();
449
450 self.and_constraints
451 .resize_with(and_target_size, AndConstraint::default);
452 self.mul_constraints
453 .resize_with(mul_target_size, MulConstraint::default);
454
455 Ok(())
456 }
457
458 #[cfg(test)]
459 fn add_and_constraint(&mut self, and_constraint: AndConstraint) {
460 self.and_constraints.push(and_constraint);
461 }
462
463 #[cfg(test)]
464 fn add_mul_constraint(&mut self, mul_constraint: MulConstraint) {
465 self.mul_constraints.push(mul_constraint);
466 }
467
468 pub fn n_and_constraints(&self) -> usize {
470 self.and_constraints.len()
471 }
472
473 pub fn n_mul_constraints(&self) -> usize {
475 self.mul_constraints.len()
476 }
477
478 pub fn value_vec_len(&self) -> usize {
480 self.value_vec_layout.committed_total_len
481 }
482
483 pub fn new_value_vec(&self) -> ValueVec {
485 ValueVec::new(self.value_vec_layout.clone())
486 }
487}
488
489impl SerializeBytes for ConstraintSystem {
490 fn serialize(&self, mut write_buf: impl BufMut) -> Result<(), SerializationError> {
491 Self::SERIALIZATION_VERSION.serialize(&mut write_buf)?;
492
493 self.value_vec_layout.serialize(&mut write_buf)?;
494 self.constants.serialize(&mut write_buf)?;
495 self.and_constraints.serialize(&mut write_buf)?;
496 self.mul_constraints.serialize(write_buf)
497 }
498}
499
500impl DeserializeBytes for ConstraintSystem {
501 fn deserialize(mut read_buf: impl Buf) -> Result<Self, SerializationError>
502 where
503 Self: Sized,
504 {
505 let version = u32::deserialize(&mut read_buf)?;
506 if version != Self::SERIALIZATION_VERSION {
507 return Err(SerializationError::InvalidConstruction {
508 name: "ConstraintSystem::version",
509 });
510 }
511
512 let value_vec_layout = ValueVecLayout::deserialize(&mut read_buf)?;
513 let constants = Vec::<Word>::deserialize(&mut read_buf)?;
514 let and_constraints = Vec::<AndConstraint>::deserialize(&mut read_buf)?;
515 let mul_constraints = Vec::<MulConstraint>::deserialize(read_buf)?;
516
517 if constants.len() != value_vec_layout.n_const {
518 return Err(SerializationError::InvalidConstruction {
519 name: "ConstraintSystem::constants",
520 });
521 }
522
523 Ok(ConstraintSystem {
524 value_vec_layout,
525 constants,
526 and_constraints,
527 mul_constraints,
528 })
529 }
530}
531
532#[derive(Clone, Debug, PartialEq, Eq)]
534pub struct ValueVecLayout {
535 pub n_const: usize,
537 pub n_inout: usize,
539 pub n_witness: usize,
541 pub n_internal: usize,
545
546 pub offset_inout: usize,
548 pub offset_witness: usize,
553 pub committed_total_len: usize,
558 pub n_scratch: usize,
560}
561
562impl ValueVecLayout {
563 pub fn validate(&self) -> Result<(), ConstraintSystemError> {
571 if !self.committed_total_len.is_power_of_two() {
572 return Err(ConstraintSystemError::ValueVecLenNotPowerOfTwo);
573 }
574
575 if !self.offset_witness.is_power_of_two() {
576 return Err(ConstraintSystemError::PublicInputPowerOfTwo);
577 }
578
579 let pub_input_size = self.offset_witness;
580 if pub_input_size < consts::MIN_WORDS_PER_SEGMENT {
581 return Err(ConstraintSystemError::PublicInputTooShort { pub_input_size });
582 }
583
584 Ok(())
585 }
586
587 fn is_padding(&self, index: ValueIndex) -> bool {
589 let idx = index.0 as usize;
590
591 if idx >= self.n_const && idx < self.offset_inout {
593 return true;
594 }
595
596 let end_of_inout = self.offset_inout + self.n_inout;
598 if idx >= end_of_inout && idx < self.offset_witness {
599 return true;
600 }
601
602 let end_of_internal = self.offset_witness + self.n_witness + self.n_internal;
604 if idx >= end_of_internal && idx < self.committed_total_len {
605 return true;
606 }
607
608 false
609 }
610
611 fn is_committed_oob(&self, index: ValueIndex) -> bool {
613 index.0 as usize >= self.committed_total_len
614 }
615}
616
617impl SerializeBytes for ValueVecLayout {
618 fn serialize(&self, mut write_buf: impl BufMut) -> Result<(), SerializationError> {
619 self.n_const.serialize(&mut write_buf)?;
620 self.n_inout.serialize(&mut write_buf)?;
621 self.n_witness.serialize(&mut write_buf)?;
622 self.n_internal.serialize(&mut write_buf)?;
623 self.offset_inout.serialize(&mut write_buf)?;
624 self.offset_witness.serialize(&mut write_buf)?;
625 self.committed_total_len.serialize(&mut write_buf)?;
626 self.n_scratch.serialize(write_buf)
627 }
628}
629
630impl DeserializeBytes for ValueVecLayout {
631 fn deserialize(mut read_buf: impl Buf) -> Result<Self, SerializationError>
632 where
633 Self: Sized,
634 {
635 let n_const = usize::deserialize(&mut read_buf)?;
636 let n_inout = usize::deserialize(&mut read_buf)?;
637 let n_witness = usize::deserialize(&mut read_buf)?;
638 let n_internal = usize::deserialize(&mut read_buf)?;
639 let offset_inout = usize::deserialize(&mut read_buf)?;
640 let offset_witness = usize::deserialize(&mut read_buf)?;
641 let committed_total_len = usize::deserialize(&mut read_buf)?;
642 let n_scratch = usize::deserialize(read_buf)?;
643
644 Ok(ValueVecLayout {
645 n_const,
646 n_inout,
647 n_witness,
648 n_internal,
649 offset_inout,
650 offset_witness,
651 committed_total_len,
652 n_scratch,
653 })
654 }
655}
656
657#[derive(Clone, Debug)]
666pub struct ValueVec {
667 layout: ValueVecLayout,
668 data: Vec<Word>,
669}
670
671impl ValueVec {
672 pub fn new(layout: ValueVecLayout) -> ValueVec {
676 let size = layout.committed_total_len + layout.n_scratch;
677 ValueVec {
678 layout,
679 data: vec![Word::ZERO; size],
680 }
681 }
682
683 pub fn new_from_data(
687 layout: ValueVecLayout,
688 mut public: Vec<Word>,
689 private: Vec<Word>,
690 ) -> Result<ValueVec, ConstraintSystemError> {
691 public.extend_from_slice(&private);
692 if public.len() != layout.committed_total_len {
693 return Err(ConstraintSystemError::ValueVecLenMismatch {
694 expected: layout.committed_total_len,
695 actual: public.len(),
696 });
697 }
698
699 Ok(ValueVec {
700 layout,
701 data: public,
702 })
703 }
704
705 pub fn size(&self) -> usize {
707 self.layout.committed_total_len
708 }
709
710 pub fn get(&self, index: usize) -> Word {
714 self.data[index]
715 }
716
717 pub fn set(&mut self, index: usize, value: Word) {
721 self.data[index] = value;
722 }
723
724 pub fn public(&self) -> &[Word] {
726 &self.data[..self.layout.offset_witness]
727 }
728
729 pub fn non_public(&self) -> &[Word] {
731 &self.data[self.layout.offset_witness..]
732 }
733
734 pub fn witness(&self) -> &[Word] {
736 let start = self.layout.offset_witness;
737 let end = start + self.layout.n_witness;
738 &self.data[start..end]
739 }
740
741 pub fn combined_witness(&self) -> &[Word] {
743 let start = 0;
744 let end = self.layout.committed_total_len;
745 &self.data[start..end]
746 }
747}
748
749impl Index<ValueIndex> for ValueVec {
750 type Output = Word;
751
752 fn index(&self, index: ValueIndex) -> &Self::Output {
753 &self.data[index.0 as usize]
754 }
755}
756
757impl IndexMut<ValueIndex> for ValueVec {
758 fn index_mut(&mut self, index: ValueIndex) -> &mut Self::Output {
759 &mut self.data[index.0 as usize]
760 }
761}
762
763#[derive(Clone, Debug, PartialEq, Eq)]
769pub struct ValuesData<'a> {
770 data: Cow<'a, [Word]>,
771}
772
773impl<'a> ValuesData<'a> {
774 pub const SERIALIZATION_VERSION: u32 = 1;
776
777 pub fn borrowed(data: &'a [Word]) -> Self {
779 Self {
780 data: Cow::Borrowed(data),
781 }
782 }
783
784 pub fn owned(data: Vec<Word>) -> Self {
786 Self {
787 data: Cow::Owned(data),
788 }
789 }
790
791 pub fn as_slice(&self) -> &[Word] {
793 &self.data
794 }
795
796 pub fn len(&self) -> usize {
798 self.data.len()
799 }
800
801 pub fn is_empty(&self) -> bool {
803 self.data.is_empty()
804 }
805
806 pub fn into_owned(self) -> Vec<Word> {
808 self.data.into_owned()
809 }
810
811 pub fn to_owned(&self) -> ValuesData<'static> {
813 ValuesData {
814 data: Cow::Owned(self.data.to_vec()),
815 }
816 }
817}
818
819impl<'a> SerializeBytes for ValuesData<'a> {
820 fn serialize(&self, mut write_buf: impl BufMut) -> Result<(), SerializationError> {
821 Self::SERIALIZATION_VERSION.serialize(&mut write_buf)?;
822
823 self.data.as_ref().serialize(write_buf)
824 }
825}
826
827impl DeserializeBytes for ValuesData<'static> {
828 fn deserialize(mut read_buf: impl Buf) -> Result<Self, SerializationError>
829 where
830 Self: Sized,
831 {
832 let version = u32::deserialize(&mut read_buf)?;
833 if version != Self::SERIALIZATION_VERSION {
834 return Err(SerializationError::InvalidConstruction {
835 name: "Witness::version",
836 });
837 }
838
839 let data = Vec::<Word>::deserialize(read_buf)?;
840
841 Ok(ValuesData::owned(data))
842 }
843}
844
845impl<'a> From<&'a [Word]> for ValuesData<'a> {
846 fn from(data: &'a [Word]) -> Self {
847 ValuesData::borrowed(data)
848 }
849}
850
851impl From<Vec<Word>> for ValuesData<'static> {
852 fn from(data: Vec<Word>) -> Self {
853 ValuesData::owned(data)
854 }
855}
856
857impl<'a> AsRef<[Word]> for ValuesData<'a> {
858 fn as_ref(&self) -> &[Word] {
859 self.as_slice()
860 }
861}
862
863impl<'a> std::ops::Deref for ValuesData<'a> {
864 type Target = [Word];
865
866 fn deref(&self) -> &Self::Target {
867 self.as_slice()
868 }
869}
870
871impl<'a> From<ValuesData<'a>> for Vec<Word> {
872 fn from(value: ValuesData<'a>) -> Self {
873 value.into_owned()
874 }
875}
876
877#[derive(Clone, Debug, PartialEq, Eq)]
894pub struct Proof<'a> {
895 data: Cow<'a, [u8]>,
896 challenger_type: String,
897}
898
899impl<'a> Proof<'a> {
900 pub const SERIALIZATION_VERSION: u32 = 1;
902
903 pub fn borrowed(data: &'a [u8], challenger_type: String) -> Self {
905 Self {
906 data: Cow::Borrowed(data),
907 challenger_type,
908 }
909 }
910
911 pub fn owned(data: Vec<u8>, challenger_type: String) -> Self {
913 Self {
914 data: Cow::Owned(data),
915 challenger_type,
916 }
917 }
918
919 pub fn as_slice(&self) -> &[u8] {
921 &self.data
922 }
923
924 pub fn challenger_type(&self) -> &str {
926 &self.challenger_type
927 }
928
929 pub fn len(&self) -> usize {
931 self.data.len()
932 }
933
934 pub fn is_empty(&self) -> bool {
936 self.data.is_empty()
937 }
938
939 pub fn into_owned(self) -> (Vec<u8>, String) {
941 (self.data.into_owned(), self.challenger_type)
942 }
943
944 pub fn to_owned(&self) -> Proof<'static> {
946 Proof {
947 data: Cow::Owned(self.data.to_vec()),
948 challenger_type: self.challenger_type.clone(),
949 }
950 }
951}
952
953impl<'a> SerializeBytes for Proof<'a> {
954 fn serialize(&self, mut write_buf: impl BufMut) -> Result<(), SerializationError> {
955 Self::SERIALIZATION_VERSION.serialize(&mut write_buf)?;
956
957 self.challenger_type.serialize(&mut write_buf)?;
958
959 self.data.as_ref().serialize(write_buf)
960 }
961}
962
963impl DeserializeBytes for Proof<'static> {
964 fn deserialize(mut read_buf: impl Buf) -> Result<Self, SerializationError>
965 where
966 Self: Sized,
967 {
968 let version = u32::deserialize(&mut read_buf)?;
969 if version != Self::SERIALIZATION_VERSION {
970 return Err(SerializationError::InvalidConstruction {
971 name: "Proof::version",
972 });
973 }
974
975 let challenger_type = String::deserialize(&mut read_buf)?;
976 let data = Vec::<u8>::deserialize(read_buf)?;
977
978 Ok(Proof::owned(data, challenger_type))
979 }
980}
981
982impl<'a> From<(&'a [u8], String)> for Proof<'a> {
983 fn from((data, challenger_type): (&'a [u8], String)) -> Self {
984 Proof::borrowed(data, challenger_type)
985 }
986}
987
988impl From<(Vec<u8>, String)> for Proof<'static> {
989 fn from((data, challenger_type): (Vec<u8>, String)) -> Self {
990 Proof::owned(data, challenger_type)
991 }
992}
993
994impl<'a> AsRef<[u8]> for Proof<'a> {
995 fn as_ref(&self) -> &[u8] {
996 self.as_slice()
997 }
998}
999
1000impl<'a> std::ops::Deref for Proof<'a> {
1001 type Target = [u8];
1002
1003 fn deref(&self) -> &Self::Target {
1004 self.as_slice()
1005 }
1006}
1007
1008#[cfg(test)]
1009mod serialization_tests {
1010 use rand::{RngCore, SeedableRng, rngs::StdRng};
1011
1012 use super::*;
1013
1014 pub(crate) fn create_test_constraint_system() -> ConstraintSystem {
1015 let constants = vec![
1016 Word::from_u64(1),
1017 Word::from_u64(42),
1018 Word::from_u64(0xDEADBEEF),
1019 ];
1020
1021 let value_vec_layout = ValueVecLayout {
1022 n_const: 3,
1023 n_inout: 2,
1024 n_witness: 10,
1025 n_internal: 3,
1026 offset_inout: 4, offset_witness: 8, committed_total_len: 16, n_scratch: 0,
1030 };
1031
1032 let and_constraints = vec![
1033 AndConstraint::plain_abc(
1034 vec![ValueIndex(0), ValueIndex(1)],
1035 vec![ValueIndex(2)],
1036 vec![ValueIndex(3), ValueIndex(4)],
1037 ),
1038 AndConstraint::abc(
1039 vec![ShiftedValueIndex::sll(ValueIndex(0), 5)],
1040 vec![ShiftedValueIndex::srl(ValueIndex(1), 10)],
1041 vec![ShiftedValueIndex::sar(ValueIndex(2), 15)],
1042 ),
1043 ];
1044
1045 let mul_constraints = vec![MulConstraint {
1046 a: vec![ShiftedValueIndex::plain(ValueIndex(0))],
1047 b: vec![ShiftedValueIndex::plain(ValueIndex(1))],
1048 hi: vec![ShiftedValueIndex::plain(ValueIndex(2))],
1049 lo: vec![ShiftedValueIndex::plain(ValueIndex(3))],
1050 }];
1051
1052 ConstraintSystem::new(constants, value_vec_layout, and_constraints, mul_constraints)
1053 }
1054
1055 #[test]
1056 fn test_word_serialization_round_trip() {
1057 let mut rng = StdRng::seed_from_u64(0);
1058 let word = Word::from_u64(rng.next_u64());
1059
1060 let mut buf = Vec::new();
1061 word.serialize(&mut buf).unwrap();
1062
1063 let deserialized = Word::deserialize(&mut buf.as_slice()).unwrap();
1064 assert_eq!(word, deserialized);
1065 }
1066
1067 #[test]
1068 fn test_shift_variant_serialization_round_trip() {
1069 let variants = [ShiftVariant::Sll, ShiftVariant::Slr, ShiftVariant::Sar];
1070
1071 for variant in variants {
1072 let mut buf = Vec::new();
1073 variant.serialize(&mut buf).unwrap();
1074
1075 let deserialized = ShiftVariant::deserialize(&mut buf.as_slice()).unwrap();
1076 match (variant, deserialized) {
1077 (ShiftVariant::Sll, ShiftVariant::Sll)
1078 | (ShiftVariant::Slr, ShiftVariant::Slr)
1079 | (ShiftVariant::Sar, ShiftVariant::Sar) => {}
1080 _ => panic!("ShiftVariant round trip failed: {:?} != {:?}", variant, deserialized),
1081 }
1082 }
1083 }
1084
1085 #[test]
1086 fn test_shift_variant_unknown_variant() {
1087 let mut buf = Vec::new();
1089 255u8.serialize(&mut buf).unwrap();
1090
1091 let result = ShiftVariant::deserialize(&mut buf.as_slice());
1092 assert!(result.is_err());
1093 match result.unwrap_err() {
1094 SerializationError::UnknownEnumVariant { name, index } => {
1095 assert_eq!(name, "ShiftVariant");
1096 assert_eq!(index, 255);
1097 }
1098 _ => panic!("Expected UnknownEnumVariant error"),
1099 }
1100 }
1101
1102 #[test]
1103 fn test_value_index_serialization_round_trip() {
1104 let value_index = ValueIndex(12345);
1105
1106 let mut buf = Vec::new();
1107 value_index.serialize(&mut buf).unwrap();
1108
1109 let deserialized = ValueIndex::deserialize(&mut buf.as_slice()).unwrap();
1110 assert_eq!(value_index, deserialized);
1111 }
1112
1113 #[test]
1114 fn test_shifted_value_index_serialization_round_trip() {
1115 let shifted_value_index = ShiftedValueIndex::srl(ValueIndex(42), 23);
1116
1117 let mut buf = Vec::new();
1118 shifted_value_index.serialize(&mut buf).unwrap();
1119
1120 let deserialized = ShiftedValueIndex::deserialize(&mut buf.as_slice()).unwrap();
1121 assert_eq!(shifted_value_index.value_index, deserialized.value_index);
1122 assert_eq!(shifted_value_index.amount, deserialized.amount);
1123 match (shifted_value_index.shift_variant, deserialized.shift_variant) {
1124 (ShiftVariant::Slr, ShiftVariant::Slr) => {}
1125 _ => panic!("ShiftVariant mismatch"),
1126 }
1127 }
1128
1129 #[test]
1130 fn test_shifted_value_index_invalid_amount() {
1131 let mut buf = Vec::new();
1133 ValueIndex(0).serialize(&mut buf).unwrap();
1134 ShiftVariant::Sll.serialize(&mut buf).unwrap();
1135 64usize.serialize(&mut buf).unwrap(); let result = ShiftedValueIndex::deserialize(&mut buf.as_slice());
1138 assert!(result.is_err());
1139 match result.unwrap_err() {
1140 SerializationError::InvalidConstruction { name } => {
1141 assert_eq!(name, "ShiftedValueIndex::amount");
1142 }
1143 _ => panic!("Expected InvalidConstruction error"),
1144 }
1145 }
1146
1147 #[test]
1148 fn test_and_constraint_serialization_round_trip() {
1149 let constraint = AndConstraint::abc(
1150 vec![ShiftedValueIndex::sll(ValueIndex(1), 5)],
1151 vec![ShiftedValueIndex::srl(ValueIndex(2), 10)],
1152 vec![
1153 ShiftedValueIndex::sar(ValueIndex(3), 15),
1154 ShiftedValueIndex::plain(ValueIndex(4)),
1155 ],
1156 );
1157
1158 let mut buf = Vec::new();
1159 constraint.serialize(&mut buf).unwrap();
1160
1161 let deserialized = AndConstraint::deserialize(&mut buf.as_slice()).unwrap();
1162 assert_eq!(constraint.a.len(), deserialized.a.len());
1163 assert_eq!(constraint.b.len(), deserialized.b.len());
1164 assert_eq!(constraint.c.len(), deserialized.c.len());
1165
1166 for (orig, deser) in constraint.a.iter().zip(deserialized.a.iter()) {
1167 assert_eq!(orig.value_index, deser.value_index);
1168 assert_eq!(orig.amount, deser.amount);
1169 }
1170 }
1171
1172 #[test]
1173 fn test_mul_constraint_serialization_round_trip() {
1174 let constraint = MulConstraint {
1175 a: vec![ShiftedValueIndex::plain(ValueIndex(0))],
1176 b: vec![ShiftedValueIndex::srl(ValueIndex(1), 32)],
1177 hi: vec![ShiftedValueIndex::plain(ValueIndex(2))],
1178 lo: vec![ShiftedValueIndex::plain(ValueIndex(3))],
1179 };
1180
1181 let mut buf = Vec::new();
1182 constraint.serialize(&mut buf).unwrap();
1183
1184 let deserialized = MulConstraint::deserialize(&mut buf.as_slice()).unwrap();
1185 assert_eq!(constraint.a.len(), deserialized.a.len());
1186 assert_eq!(constraint.b.len(), deserialized.b.len());
1187 assert_eq!(constraint.hi.len(), deserialized.hi.len());
1188 assert_eq!(constraint.lo.len(), deserialized.lo.len());
1189 }
1190
1191 #[test]
1192 fn test_value_vec_layout_serialization_round_trip() {
1193 let layout = ValueVecLayout {
1194 n_const: 5,
1195 n_inout: 3,
1196 n_witness: 12,
1197 n_internal: 7,
1198 offset_inout: 8,
1199 offset_witness: 16,
1200 committed_total_len: 32,
1201 n_scratch: 0,
1202 };
1203
1204 let mut buf = Vec::new();
1205 layout.serialize(&mut buf).unwrap();
1206
1207 let deserialized = ValueVecLayout::deserialize(&mut buf.as_slice()).unwrap();
1208 assert_eq!(layout, deserialized);
1209 }
1210
1211 #[test]
1212 fn test_constraint_system_serialization_round_trip() {
1213 let original = create_test_constraint_system();
1214
1215 let mut buf = Vec::new();
1216 original.serialize(&mut buf).unwrap();
1217
1218 let deserialized = ConstraintSystem::deserialize(&mut buf.as_slice()).unwrap();
1219
1220 assert_eq!(ConstraintSystem::SERIALIZATION_VERSION, 2);
1222
1223 assert_eq!(original.value_vec_layout, deserialized.value_vec_layout);
1225
1226 assert_eq!(original.constants.len(), deserialized.constants.len());
1228 for (orig, deser) in original.constants.iter().zip(deserialized.constants.iter()) {
1229 assert_eq!(orig, deser);
1230 }
1231
1232 assert_eq!(original.and_constraints.len(), deserialized.and_constraints.len());
1234
1235 assert_eq!(original.mul_constraints.len(), deserialized.mul_constraints.len());
1237 }
1238
1239 #[test]
1240 fn test_constraint_system_version_mismatch() {
1241 let mut buf = Vec::new();
1243 999u32.serialize(&mut buf).unwrap(); let result = ConstraintSystem::deserialize(&mut buf.as_slice());
1246 assert!(result.is_err());
1247 match result.unwrap_err() {
1248 SerializationError::InvalidConstruction { name } => {
1249 assert_eq!(name, "ConstraintSystem::version");
1250 }
1251 _ => panic!("Expected InvalidConstruction error"),
1252 }
1253 }
1254
1255 #[test]
1256 fn test_constraint_system_constants_length_mismatch() {
1257 let value_vec_layout = ValueVecLayout {
1259 n_const: 5, n_inout: 2,
1261 n_witness: 10,
1262 n_internal: 3,
1263 offset_inout: 8,
1264 offset_witness: 16,
1265 committed_total_len: 32,
1266 n_scratch: 0,
1267 };
1268
1269 let constants = vec![Word::from_u64(1), Word::from_u64(2)]; let and_constraints: Vec<AndConstraint> = vec![];
1271 let mul_constraints: Vec<MulConstraint> = vec![];
1272
1273 let mut buf = Vec::new();
1275 ConstraintSystem::SERIALIZATION_VERSION
1276 .serialize(&mut buf)
1277 .unwrap();
1278 value_vec_layout.serialize(&mut buf).unwrap();
1279 constants.serialize(&mut buf).unwrap();
1280 and_constraints.serialize(&mut buf).unwrap();
1281 mul_constraints.serialize(&mut buf).unwrap();
1282
1283 let result = ConstraintSystem::deserialize(&mut buf.as_slice());
1284 assert!(result.is_err());
1285 match result.unwrap_err() {
1286 SerializationError::InvalidConstruction { name } => {
1287 assert_eq!(name, "ConstraintSystem::constants");
1288 }
1289 _ => panic!("Expected InvalidConstruction error"),
1290 }
1291 }
1292
1293 #[test]
1294 fn test_serialization_with_different_sources() {
1295 let original = create_test_constraint_system();
1296
1297 let mut vec_buf = Vec::new();
1299 original.serialize(&mut vec_buf).unwrap();
1300 let deserialized1 = ConstraintSystem::deserialize(&mut vec_buf.as_slice()).unwrap();
1301 assert_eq!(original.constants.len(), deserialized1.constants.len());
1302
1303 let mut bytes_buf = bytes::BytesMut::new();
1305 original.serialize(&mut bytes_buf).unwrap();
1306 let deserialized2 = ConstraintSystem::deserialize(bytes_buf.freeze()).unwrap();
1307 assert_eq!(original.constants.len(), deserialized2.constants.len());
1308 }
1309
1310 #[test]
1314 #[ignore] fn create_reference_binary_file() {
1316 let constraint_system = create_test_constraint_system();
1317
1318 let mut buf = Vec::new();
1320 constraint_system.serialize(&mut buf).unwrap();
1321
1322 let test_data_path = std::path::Path::new("test_data/constraint_system_v2.bin");
1324
1325 if let Some(parent) = test_data_path.parent() {
1327 std::fs::create_dir_all(parent).unwrap();
1328 }
1329
1330 std::fs::write(test_data_path, &buf).unwrap();
1331
1332 println!("Created reference binary file at: {:?}", test_data_path);
1333 println!("Binary data length: {} bytes", buf.len());
1334 }
1335
1336 #[test]
1339 fn test_deserialize_from_reference_binary_file() {
1340 let binary_data = include_bytes!("../test_data/constraint_system_v2.bin");
1343
1344 let deserialized = ConstraintSystem::deserialize(&mut binary_data.as_slice()).unwrap();
1345
1346 assert_eq!(deserialized.value_vec_layout.n_const, 3);
1347 assert_eq!(deserialized.value_vec_layout.n_inout, 2);
1348 assert_eq!(deserialized.value_vec_layout.n_witness, 10);
1349 assert_eq!(deserialized.value_vec_layout.n_internal, 3);
1350 assert_eq!(deserialized.value_vec_layout.offset_inout, 4);
1351 assert_eq!(deserialized.value_vec_layout.offset_witness, 8);
1352 assert_eq!(deserialized.value_vec_layout.committed_total_len, 16);
1353 assert_eq!(deserialized.value_vec_layout.n_scratch, 0);
1354
1355 assert_eq!(deserialized.constants.len(), 3);
1356 assert_eq!(deserialized.constants[0].as_u64(), 1);
1357 assert_eq!(deserialized.constants[1].as_u64(), 42);
1358 assert_eq!(deserialized.constants[2].as_u64(), 0xDEADBEEF);
1359
1360 assert_eq!(deserialized.and_constraints.len(), 2);
1361 assert_eq!(deserialized.mul_constraints.len(), 1);
1362
1363 let version_bytes = &binary_data[0..4]; let expected_version_bytes = 2u32.to_le_bytes(); assert_eq!(
1369 version_bytes, expected_version_bytes,
1370 "Binary file version mismatch. If you made breaking changes, increment ConstraintSystem::SERIALIZATION_VERSION"
1371 );
1372 }
1373
1374 #[test]
1375 fn test_witness_serialization_round_trip_owned() {
1376 let data = vec![
1377 Word::from_u64(1),
1378 Word::from_u64(42),
1379 Word::from_u64(0xDEADBEEF),
1380 Word::from_u64(0x1234567890ABCDEF),
1381 ];
1382 let witness = ValuesData::owned(data.clone());
1383
1384 let mut buf = Vec::new();
1385 witness.serialize(&mut buf).unwrap();
1386
1387 let deserialized = ValuesData::deserialize(&mut buf.as_slice()).unwrap();
1388 assert_eq!(witness, deserialized);
1389 assert_eq!(deserialized.as_slice(), data.as_slice());
1390 }
1391
1392 #[test]
1393 fn test_witness_serialization_round_trip_borrowed() {
1394 let data = vec![Word::from_u64(123), Word::from_u64(456)];
1395 let witness = ValuesData::borrowed(&data);
1396
1397 let mut buf = Vec::new();
1398 witness.serialize(&mut buf).unwrap();
1399
1400 let deserialized = ValuesData::deserialize(&mut buf.as_slice()).unwrap();
1401 assert_eq!(witness, deserialized);
1402 assert_eq!(deserialized.as_slice(), data.as_slice());
1403 }
1404
1405 #[test]
1406 fn test_witness_version_mismatch() {
1407 let mut buf = Vec::new();
1408 999u32.serialize(&mut buf).unwrap(); vec![Word::from_u64(1)].serialize(&mut buf).unwrap(); let result = ValuesData::deserialize(&mut buf.as_slice());
1412 assert!(result.is_err());
1413 match result.unwrap_err() {
1414 SerializationError::InvalidConstruction { name } => {
1415 assert_eq!(name, "Witness::version");
1416 }
1417 _ => panic!("Expected version mismatch error"),
1418 }
1419 }
1420
1421 #[test]
1424 #[ignore] fn create_witness_reference_binary_file() {
1426 let data = vec![
1427 Word::from_u64(1),
1428 Word::from_u64(42),
1429 Word::from_u64(0xDEADBEEF),
1430 Word::from_u64(0x1234567890ABCDEF),
1431 ];
1432 let witness = ValuesData::owned(data);
1433
1434 let mut buf = Vec::new();
1435 witness.serialize(&mut buf).unwrap();
1436
1437 let test_data_path = std::path::Path::new("verifier/core/test_data/witness_v1.bin");
1438
1439 if let Some(parent) = test_data_path.parent() {
1440 std::fs::create_dir_all(parent).unwrap();
1441 }
1442
1443 std::fs::write(test_data_path, &buf).unwrap();
1444
1445 println!("Created Witness reference binary file at: {:?}", test_data_path);
1446 println!("Binary data length: {} bytes", buf.len());
1447 }
1448
1449 #[test]
1453 fn test_witness_deserialize_from_reference_binary_file() {
1454 let binary_data = include_bytes!("../test_data/witness_v1.bin");
1455
1456 let deserialized = ValuesData::deserialize(&mut binary_data.as_slice()).unwrap();
1457
1458 assert_eq!(deserialized.len(), 4);
1459 assert_eq!(deserialized.as_slice()[0].as_u64(), 1);
1460 assert_eq!(deserialized.as_slice()[1].as_u64(), 42);
1461 assert_eq!(deserialized.as_slice()[2].as_u64(), 0xDEADBEEF);
1462 assert_eq!(deserialized.as_slice()[3].as_u64(), 0x1234567890ABCDEF);
1463
1464 let version_bytes = &binary_data[0..4]; let expected_version_bytes = 1u32.to_le_bytes(); assert_eq!(
1470 version_bytes, expected_version_bytes,
1471 "WitnessData binary file version mismatch. If you made breaking changes, increment WitnessData::SERIALIZATION_VERSION"
1472 );
1473 }
1474
1475 #[test]
1476 fn test_proof_serialization_round_trip_owned() {
1477 let transcript_data = vec![0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0];
1478 let challenger_type = "HasherChallenger<Sha256>".to_string();
1479 let proof = Proof::owned(transcript_data.clone(), challenger_type.clone());
1480
1481 let mut buf = Vec::new();
1482 proof.serialize(&mut buf).unwrap();
1483
1484 let deserialized = Proof::deserialize(&mut buf.as_slice()).unwrap();
1485 assert_eq!(proof, deserialized);
1486 assert_eq!(deserialized.as_slice(), transcript_data.as_slice());
1487 assert_eq!(deserialized.challenger_type(), &challenger_type);
1488 }
1489
1490 #[test]
1491 fn test_proof_serialization_round_trip_borrowed() {
1492 let transcript_data = vec![0xAA, 0xBB, 0xCC, 0xDD];
1493 let challenger_type = "TestChallenger".to_string();
1494 let proof = Proof::borrowed(&transcript_data, challenger_type.clone());
1495
1496 let mut buf = Vec::new();
1497 proof.serialize(&mut buf).unwrap();
1498
1499 let deserialized = Proof::deserialize(&mut buf.as_slice()).unwrap();
1500 assert_eq!(proof, deserialized);
1501 assert_eq!(deserialized.as_slice(), transcript_data.as_slice());
1502 assert_eq!(deserialized.challenger_type(), &challenger_type);
1503 }
1504
1505 #[test]
1506 fn test_proof_empty_transcript() {
1507 let proof = Proof::owned(vec![], "EmptyProof".to_string());
1508 assert!(proof.is_empty());
1509 assert_eq!(proof.len(), 0);
1510
1511 let mut buf = Vec::new();
1512 proof.serialize(&mut buf).unwrap();
1513
1514 let deserialized = Proof::deserialize(&mut buf.as_slice()).unwrap();
1515 assert_eq!(proof, deserialized);
1516 assert!(deserialized.is_empty());
1517 }
1518
1519 #[test]
1520 fn test_proof_large_transcript() {
1521 let mut rng = StdRng::seed_from_u64(12345);
1522 let mut large_data = vec![0u8; 10000];
1523 rng.fill_bytes(&mut large_data);
1524
1525 let challenger_type = "LargeProofChallenger".to_string();
1526 let proof = Proof::owned(large_data.clone(), challenger_type.clone());
1527
1528 let mut buf = Vec::new();
1529 proof.serialize(&mut buf).unwrap();
1530
1531 let deserialized = Proof::deserialize(&mut buf.as_slice()).unwrap();
1532 assert_eq!(proof, deserialized);
1533 assert_eq!(deserialized.len(), 10000);
1534 assert_eq!(deserialized.challenger_type(), &challenger_type);
1535 }
1536
1537 #[test]
1538 fn test_proof_version_mismatch() {
1539 let mut buf = Vec::new();
1540 999u32.serialize(&mut buf).unwrap(); "TestChallenger".serialize(&mut buf).unwrap(); vec![0xAAu8].serialize(&mut buf).unwrap(); let result = Proof::deserialize(&mut buf.as_slice());
1545 assert!(result.is_err());
1546 match result.unwrap_err() {
1547 SerializationError::InvalidConstruction { name } => {
1548 assert_eq!(name, "Proof::version");
1549 }
1550 _ => panic!("Expected version mismatch error"),
1551 }
1552 }
1553
1554 #[test]
1555 fn test_proof_into_owned() {
1556 let original_data = vec![1, 2, 3, 4, 5];
1557 let original_challenger = "TestChallenger".to_string();
1558 let proof = Proof::owned(original_data.clone(), original_challenger.clone());
1559
1560 let (data, challenger_type) = proof.into_owned();
1561 assert_eq!(data, original_data);
1562 assert_eq!(challenger_type, original_challenger);
1563 }
1564
1565 #[test]
1566 fn test_proof_to_owned() {
1567 let data = vec![0xFF, 0xEE, 0xDD];
1568 let challenger_type = "BorrowedChallenger".to_string();
1569 let borrowed_proof = Proof::borrowed(&data, challenger_type.clone());
1570
1571 let owned_proof = borrowed_proof.to_owned();
1572 assert_eq!(owned_proof.as_slice(), data);
1573 assert_eq!(owned_proof.challenger_type(), &challenger_type);
1574 drop(data); assert_eq!(owned_proof.len(), 3);
1577 }
1578
1579 #[test]
1580 fn test_proof_different_challenger_types() {
1581 let data = vec![0x42];
1582 let challengers = vec![
1583 "HasherChallenger<Sha256>".to_string(),
1584 "HasherChallenger<Blake2b>".to_string(),
1585 "CustomChallenger".to_string(),
1586 "".to_string(), ];
1588
1589 for challenger_type in challengers {
1590 let proof = Proof::owned(data.clone(), challenger_type.clone());
1591 let mut buf = Vec::new();
1592 proof.serialize(&mut buf).unwrap();
1593
1594 let deserialized = Proof::deserialize(&mut buf.as_slice()).unwrap();
1595 assert_eq!(deserialized.challenger_type(), &challenger_type);
1596 }
1597 }
1598
1599 #[test]
1600 fn test_proof_serialization_with_different_sources() {
1601 let transcript_data = vec![0x11, 0x22, 0x33, 0x44];
1602 let challenger_type = "MultiSourceChallenger".to_string();
1603 let original = Proof::owned(transcript_data, challenger_type);
1604
1605 let mut vec_buf = Vec::new();
1607 original.serialize(&mut vec_buf).unwrap();
1608 let deserialized1 = Proof::deserialize(&mut vec_buf.as_slice()).unwrap();
1609 assert_eq!(original, deserialized1);
1610
1611 let mut bytes_buf = bytes::BytesMut::new();
1613 original.serialize(&mut bytes_buf).unwrap();
1614 let deserialized2 = Proof::deserialize(bytes_buf.freeze()).unwrap();
1615 assert_eq!(original, deserialized2);
1616 }
1617
1618 #[test]
1621 #[ignore] fn create_proof_reference_binary_file() {
1623 let transcript_data = vec![
1624 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54,
1625 0x32, 0x10, 0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE,
1626 ];
1627 let challenger_type = "HasherChallenger<Sha256>".to_string();
1628 let proof = Proof::owned(transcript_data, challenger_type);
1629
1630 let mut buf = Vec::new();
1631 proof.serialize(&mut buf).unwrap();
1632
1633 let test_data_path = std::path::Path::new("verifier/core/test_data/proof_v1.bin");
1634
1635 if let Some(parent) = test_data_path.parent() {
1636 std::fs::create_dir_all(parent).unwrap();
1637 }
1638
1639 std::fs::write(test_data_path, &buf).unwrap();
1640
1641 println!("Created Proof reference binary file at: {:?}", test_data_path);
1642 println!("Binary data length: {} bytes", buf.len());
1643 }
1644
1645 #[test]
1649 fn test_proof_deserialize_from_reference_binary_file() {
1650 let binary_data = include_bytes!("../test_data/proof_v1.bin");
1651
1652 let deserialized = Proof::deserialize(&mut binary_data.as_slice()).unwrap();
1653
1654 assert_eq!(deserialized.len(), 24); assert_eq!(deserialized.challenger_type(), "HasherChallenger<Sha256>");
1656
1657 let expected_data = vec![
1658 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54,
1659 0x32, 0x10, 0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE,
1660 ];
1661 assert_eq!(deserialized.as_slice(), expected_data);
1662
1663 let version_bytes = &binary_data[0..4]; let expected_version_bytes = 1u32.to_le_bytes(); assert_eq!(
1669 version_bytes, expected_version_bytes,
1670 "Proof binary file version mismatch. If you made breaking changes, increment Proof::SERIALIZATION_VERSION"
1671 );
1672 }
1673
1674 #[test]
1675 fn split_values_vec_and_combine() {
1676 let values = ValueVec::new(ValueVecLayout {
1677 n_const: 2,
1678 n_inout: 2,
1679 n_witness: 2,
1680 n_internal: 2,
1681 offset_inout: 2,
1682 offset_witness: 4,
1683 committed_total_len: 8,
1684 n_scratch: 0,
1685 });
1686
1687 let public = values.public();
1688 let non_public = values.non_public();
1689 let combined =
1690 ValueVec::new_from_data(values.layout.clone(), public.to_vec(), non_public.to_vec())
1691 .unwrap();
1692 assert_eq!(combined.combined_witness(), values.combined_witness());
1693 }
1694
1695 #[test]
1696 fn test_is_padding_comprehensive() {
1697 let layout = ValueVecLayout {
1699 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,
1707 };
1708
1709 assert!(!layout.is_padding(ValueIndex(0)), "index 0 should be constant");
1711 assert!(!layout.is_padding(ValueIndex(1)), "index 1 should be constant");
1712
1713 assert!(
1715 layout.is_padding(ValueIndex(2)),
1716 "index 2 should be padding between const and inout"
1717 );
1718 assert!(
1719 layout.is_padding(ValueIndex(3)),
1720 "index 3 should be padding between const and inout"
1721 );
1722
1723 assert!(!layout.is_padding(ValueIndex(4)), "index 4 should be inout");
1725 assert!(!layout.is_padding(ValueIndex(5)), "index 5 should be inout");
1726 assert!(!layout.is_padding(ValueIndex(6)), "index 6 should be inout");
1727
1728 for i in 7..16 {
1730 assert!(
1731 layout.is_padding(ValueIndex(i)),
1732 "index {} should be padding between inout and witness",
1733 i
1734 );
1735 }
1736
1737 for i in 16..21 {
1739 assert!(!layout.is_padding(ValueIndex(i)), "index {} should be witness", i);
1740 }
1741
1742 for i in 21..31 {
1744 assert!(!layout.is_padding(ValueIndex(i)), "index {} should be internal", i);
1745 }
1746
1747 for i in 31..64 {
1749 assert!(
1750 layout.is_padding(ValueIndex(i)),
1751 "index {} should be padding after internal",
1752 i
1753 );
1754 }
1755 }
1756
1757 #[test]
1758 fn test_is_padding_minimal_layout() {
1759 let layout = ValueVecLayout {
1761 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,
1769 };
1770
1771 for i in 0..16 {
1773 assert!(
1774 !layout.is_padding(ValueIndex(i)),
1775 "index {} should not be padding in minimal layout",
1776 i
1777 );
1778 }
1779 }
1780
1781 #[test]
1782 fn test_is_padding_public_section_min_size() {
1783 let layout = ValueVecLayout {
1785 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,
1793 };
1794
1795 assert!(!layout.is_padding(ValueIndex(0)), "index 0 should be constant");
1797
1798 assert!(layout.is_padding(ValueIndex(1)), "index 1 should be padding");
1800 assert!(layout.is_padding(ValueIndex(2)), "index 2 should be padding");
1801 assert!(layout.is_padding(ValueIndex(3)), "index 3 should be padding");
1802
1803 assert!(!layout.is_padding(ValueIndex(4)), "index 4 should be inout");
1805
1806 assert!(layout.is_padding(ValueIndex(5)), "index 5 should be padding");
1808 assert!(layout.is_padding(ValueIndex(6)), "index 6 should be padding");
1809 assert!(layout.is_padding(ValueIndex(7)), "index 7 should be padding");
1810
1811 assert!(!layout.is_padding(ValueIndex(8)), "index 8 should be witness");
1813 assert!(!layout.is_padding(ValueIndex(9)), "index 9 should be witness");
1814
1815 assert!(!layout.is_padding(ValueIndex(10)), "index 10 should be internal");
1817 assert!(!layout.is_padding(ValueIndex(11)), "index 11 should be internal");
1818
1819 for i in 12..16 {
1821 assert!(layout.is_padding(ValueIndex(i)), "index {} should be end padding", i);
1822 }
1823 }
1824
1825 #[test]
1826 fn test_is_padding_boundary_conditions() {
1827 let layout = ValueVecLayout {
1828 n_const: 2,
1829 n_inout: 2,
1830 n_witness: 4,
1831 n_internal: 4,
1832 offset_inout: 4,
1833 offset_witness: 8,
1834 committed_total_len: 16,
1835 n_scratch: 0,
1836 };
1837
1838 assert!(!layout.is_padding(ValueIndex(1)), "last constant should not be padding");
1840 assert!(layout.is_padding(ValueIndex(2)), "first padding after const should be padding");
1841
1842 assert!(layout.is_padding(ValueIndex(3)), "last padding before inout should be padding");
1843 assert!(!layout.is_padding(ValueIndex(4)), "first inout should not be padding");
1844
1845 assert!(!layout.is_padding(ValueIndex(5)), "last inout should not be padding");
1846 assert!(layout.is_padding(ValueIndex(6)), "first padding after inout should be padding");
1847
1848 assert!(layout.is_padding(ValueIndex(7)), "last padding before witness should be padding");
1849 assert!(!layout.is_padding(ValueIndex(8)), "first witness should not be padding");
1850
1851 assert!(!layout.is_padding(ValueIndex(11)), "last witness should not be padding");
1852 assert!(!layout.is_padding(ValueIndex(12)), "first internal should not be padding");
1853
1854 assert!(!layout.is_padding(ValueIndex(15)), "last internal should not be padding");
1855 }
1857
1858 #[test]
1859 fn test_validate_rejects_padding_references() {
1860 let mut cs = ConstraintSystem::new(
1861 vec![Word::from_u64(1)],
1862 ValueVecLayout {
1863 n_const: 1,
1864 n_inout: 1,
1865 n_witness: 2,
1866 n_internal: 2,
1867 offset_inout: 4,
1868 offset_witness: 8,
1869 committed_total_len: 16,
1870 n_scratch: 0,
1871 },
1872 vec![],
1873 vec![],
1874 );
1875
1876 cs.add_and_constraint(AndConstraint::plain_abc(
1878 vec![ValueIndex(0)], vec![ValueIndex(2)], vec![ValueIndex(8)], ));
1882
1883 let result = cs.validate_and_prepare();
1884 assert!(result.is_err(), "Should reject constraint referencing padding");
1885
1886 match result.unwrap_err() {
1887 ConstraintSystemError::PaddingValueIndex {
1888 constraint_type, ..
1889 } => {
1890 assert_eq!(constraint_type, "and");
1891 }
1892 other => panic!("Expected PaddingValueIndex error, got: {:?}", other),
1893 }
1894 }
1895
1896 #[test]
1897 fn test_validate_accepts_non_padding_references() {
1898 let mut cs = ConstraintSystem::new(
1899 vec![Word::from_u64(1), Word::from_u64(2)],
1900 ValueVecLayout {
1901 n_const: 2,
1902 n_inout: 2,
1903 n_witness: 4,
1904 n_internal: 4,
1905 offset_inout: 2,
1906 offset_witness: 4,
1907 committed_total_len: 16,
1908 n_scratch: 0,
1909 },
1910 vec![],
1911 vec![],
1912 );
1913
1914 cs.add_and_constraint(AndConstraint::plain_abc(
1916 vec![ValueIndex(0), ValueIndex(1)], vec![ValueIndex(2), ValueIndex(3)], vec![ValueIndex(4), ValueIndex(5)], ));
1920
1921 cs.add_mul_constraint(MulConstraint {
1922 a: vec![ShiftedValueIndex::plain(ValueIndex(6))], b: vec![ShiftedValueIndex::plain(ValueIndex(7))], hi: vec![ShiftedValueIndex::plain(ValueIndex(8))], lo: vec![ShiftedValueIndex::plain(ValueIndex(9))], });
1927
1928 let result = cs.validate_and_prepare();
1929 assert!(
1930 result.is_ok(),
1931 "Should accept constraints with only valid references: {:?}",
1932 result
1933 );
1934 }
1935
1936 #[test]
1937 fn test_is_padding_matches_compiler_requirements() {
1938 let layout1 = ValueVecLayout {
1946 n_const: 1,
1947 n_inout: 1,
1948 n_witness: 4,
1949 n_internal: 4,
1950 offset_inout: 1, offset_witness: 8, committed_total_len: 16,
1953 n_scratch: 0,
1954 };
1955
1956 assert!(!layout1.is_padding(ValueIndex(0)), "const should not be padding");
1958 assert!(!layout1.is_padding(ValueIndex(1)), "inout should not be padding");
1959 for i in 2..8 {
1960 assert!(
1961 layout1.is_padding(ValueIndex(i)),
1962 "index {} should be padding to meet MIN_WORDS_PER_SEGMENT",
1963 i
1964 );
1965 }
1966
1967 let layout2 = ValueVecLayout {
1969 n_const: 4,
1970 n_inout: 4,
1971 n_witness: 8,
1972 n_internal: 0,
1973 offset_inout: 4,
1974 offset_witness: 8, committed_total_len: 16,
1976 n_scratch: 0,
1977 };
1978
1979 for i in 0..8 {
1981 assert!(!layout2.is_padding(ValueIndex(i)), "index {} should not be padding", i);
1982 }
1983
1984 let layout3 = ValueVecLayout {
1987 n_const: 5,
1988 n_inout: 5,
1989 n_witness: 16,
1990 n_internal: 0,
1991 offset_inout: 5,
1992 offset_witness: 16, committed_total_len: 32,
1994 n_scratch: 0,
1995 };
1996
1997 for i in 0..5 {
1999 assert!(!layout3.is_padding(ValueIndex(i)), "const {} should not be padding", i);
2000 }
2001 for i in 5..10 {
2002 assert!(!layout3.is_padding(ValueIndex(i)), "inout {} should not be padding", i);
2003 }
2004 for i in 10..16 {
2005 assert!(
2006 layout3.is_padding(ValueIndex(i)),
2007 "index {} should be padding for power-of-2 alignment",
2008 i
2009 );
2010 }
2011
2012 let layout4 = ValueVecLayout {
2014 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,
2022 };
2023
2024 assert!(!layout4.is_padding(ValueIndex(0)));
2026 assert!(!layout4.is_padding(ValueIndex(1)));
2027
2028 for i in 2..8 {
2030 assert!(layout4.is_padding(ValueIndex(i)), "padding between const and inout at {}", i);
2031 }
2032
2033 assert!(!layout4.is_padding(ValueIndex(8)));
2035 assert!(!layout4.is_padding(ValueIndex(9)));
2036
2037 for i in 10..16 {
2039 assert!(
2040 layout4.is_padding(ValueIndex(i)),
2041 "padding between inout and witness at {}",
2042 i
2043 );
2044 }
2045
2046 for i in 16..20 {
2048 assert!(!layout4.is_padding(ValueIndex(i)), "witness at {}", i);
2049 }
2050
2051 for i in 20..24 {
2053 assert!(!layout4.is_padding(ValueIndex(i)), "internal at {}", i);
2054 }
2055
2056 for i in 24..32 {
2058 assert!(layout4.is_padding(ValueIndex(i)), "padding after internal at {}", i);
2059 }
2060 }
2061
2062 #[test]
2063 fn test_validate_rejects_out_of_range_indices() {
2064 let mut cs = ConstraintSystem::new(
2065 vec![Word::from_u64(1)],
2066 ValueVecLayout {
2067 n_const: 1,
2068 n_inout: 1,
2069 n_witness: 2,
2070 n_internal: 2,
2071 offset_inout: 4,
2072 offset_witness: 8,
2073 committed_total_len: 16,
2074 n_scratch: 0,
2075 },
2076 vec![],
2077 vec![],
2078 );
2079
2080 cs.add_and_constraint(AndConstraint::plain_abc(
2082 vec![ValueIndex(0)], vec![ValueIndex(16)], vec![ValueIndex(8)], ));
2086
2087 let result = cs.validate_and_prepare();
2088 assert!(result.is_err(), "Should reject constraint with out-of-range index");
2089
2090 match result.unwrap_err() {
2091 ConstraintSystemError::OutOfRangeValueIndex {
2092 constraint_type,
2093 operand_name,
2094 value_index,
2095 total_len,
2096 ..
2097 } => {
2098 assert_eq!(constraint_type, "and");
2099 assert_eq!(operand_name, "b");
2100 assert_eq!(value_index, 16);
2101 assert_eq!(total_len, 16);
2102 }
2103 other => panic!("Expected OutOfRangeValueIndex error, got: {:?}", other),
2104 }
2105 }
2106
2107 #[test]
2108 fn test_validate_rejects_out_of_range_in_mul_constraint() {
2109 let mut cs = ConstraintSystem::new(
2110 vec![Word::from_u64(1), Word::from_u64(2)],
2111 ValueVecLayout {
2112 n_const: 2,
2113 n_inout: 2,
2114 n_witness: 4,
2115 n_internal: 4,
2116 offset_inout: 2,
2117 offset_witness: 4,
2118 committed_total_len: 16,
2119 n_scratch: 0,
2120 },
2121 vec![],
2122 vec![],
2123 );
2124
2125 cs.add_mul_constraint(MulConstraint {
2127 a: vec![ShiftedValueIndex::plain(ValueIndex(0))], b: vec![ShiftedValueIndex::plain(ValueIndex(1))], hi: vec![ShiftedValueIndex::plain(ValueIndex(100))], lo: vec![ShiftedValueIndex::plain(ValueIndex(3))], });
2132
2133 let result = cs.validate_and_prepare();
2134 assert!(result.is_err(), "Should reject MUL constraint with out-of-range index");
2135
2136 match result.unwrap_err() {
2137 ConstraintSystemError::OutOfRangeValueIndex {
2138 constraint_type,
2139 operand_name,
2140 value_index,
2141 total_len,
2142 ..
2143 } => {
2144 assert_eq!(constraint_type, "mul");
2145 assert_eq!(operand_name, "hi");
2146 assert_eq!(value_index, 100);
2147 assert_eq!(total_len, 16);
2148 }
2149 other => panic!("Expected OutOfRangeValueIndex error, got: {:?}", other),
2150 }
2151 }
2152
2153 #[test]
2154 fn test_validate_checks_out_of_range_before_padding() {
2155 let mut cs = ConstraintSystem::new(
2159 vec![Word::from_u64(1)],
2160 ValueVecLayout {
2161 n_const: 1,
2162 n_inout: 1,
2163 n_witness: 2,
2164 n_internal: 2,
2165 offset_inout: 4,
2166 offset_witness: 8,
2167 committed_total_len: 16,
2168 n_scratch: 0,
2169 },
2170 vec![],
2171 vec![],
2172 );
2173
2174 cs.add_and_constraint(AndConstraint::plain_abc(
2177 vec![ValueIndex(0)],
2178 vec![ValueIndex(20)], vec![ValueIndex(8)],
2180 ));
2181
2182 let result = cs.validate_and_prepare();
2183 assert!(result.is_err());
2184
2185 match result.unwrap_err() {
2187 ConstraintSystemError::OutOfRangeValueIndex { .. } => {
2188 }
2190 other => panic!(
2191 "Expected OutOfRangeValueIndex to be detected before padding check, got: {:?}",
2192 other
2193 ),
2194 }
2195 }
2196}