1#[cfg(test)]
4mod tests;
5
6extern crate alloc;
7
8use alloc::collections::BTreeMap;
9use alloc::collections::btree_map::Entry;
10#[cfg(not(feature = "std"))]
11use alloc::string::{String, ToString};
12use alloc::sync::Arc;
13#[cfg(not(feature = "std"))]
14use alloc::vec::Vec;
15use core::mem;
16use derive_more::{AsMut, AsRef, Deref, DerefMut, From, Into};
17use kzg::eip_4844::{BYTES_PER_G1, BYTES_PER_G2};
18use kzg::{FFTFr, FFTSettings, Fr, G1, G2, KZGSettings};
19#[cfg(feature = "std")]
20use parking_lot::Mutex;
21use rust_kzg_blst::types::fft_settings::FsFFTSettings;
22use rust_kzg_blst::types::fr::FsFr;
23use rust_kzg_blst::types::g1::FsG1;
24use rust_kzg_blst::types::g2::FsG2;
25use rust_kzg_blst::types::kzg_settings::FsKZGSettings;
26use rust_kzg_blst::types::poly::FsPoly;
27#[cfg(not(feature = "std"))]
28use spin::Mutex;
29use static_assertions::const_assert_eq;
30use subspace_core_primitives::ScalarBytes;
31use subspace_core_primitives::pieces::{RecordCommitment, RecordWitness};
32use subspace_core_primitives::segments::SegmentCommitment;
33use subspace_core_primitives::solutions::ChunkWitness;
34use tracing::debug;
35
36pub const EMBEDDED_KZG_SETTINGS_BYTES: &[u8] = include_bytes!("eth-public-parameters.bin");
42pub const NUM_G1_POWERS: usize = 32_768;
44pub const NUM_G2_POWERS: usize = 65;
46
47fn bytes_to_kzg_settings(
51 bytes: &[u8],
52 num_g1_powers: usize,
53 num_g2_powers: usize,
54) -> Result<FsKZGSettings, String> {
55 if bytes.len() != BYTES_PER_G1 * num_g1_powers + BYTES_PER_G2 * num_g2_powers {
56 return Err("Invalid bytes length".to_string());
57 }
58
59 let (secret_g1_bytes, secret_g2_bytes) = bytes.split_at(BYTES_PER_G1 * num_g1_powers);
60 let secret_g1 = secret_g1_bytes
61 .as_chunks::<BYTES_PER_G1>()
62 .0
63 .iter()
64 .map(|bytes| FsG1::from_bytes(bytes))
65 .collect::<Result<Vec<_>, _>>()?;
66 let secret_g2 = secret_g2_bytes
67 .as_chunks::<BYTES_PER_G2>()
68 .0
69 .iter()
70 .map(|bytes| FsG2::from_bytes(bytes))
71 .collect::<Result<Vec<_>, _>>()?;
72
73 let fft_settings = FsFFTSettings::new(
74 num_g1_powers
75 .checked_sub(1)
76 .expect("Checked to be not empty above; qed")
77 .ilog2() as usize,
78 )
79 .expect("Scale is within allowed bounds; qed");
80
81 Ok(FsKZGSettings {
86 fs: fft_settings,
87 secret_g1,
88 secret_g2,
89 precomputation: None,
90 })
91}
92
93#[derive(Debug, Clone, From)]
95pub struct Polynomial(FsPoly);
96
97impl Polynomial {
98 pub fn normalize(&mut self) {
100 let trailing_zeroes = self
101 .0
102 .coeffs
103 .iter()
104 .rev()
105 .take_while(|coeff| coeff.is_zero())
106 .count();
107 self.0
108 .coeffs
109 .truncate((self.0.coeffs.len() - trailing_zeroes).max(1));
110 }
111}
112
113#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Deref, DerefMut)]
115#[repr(transparent)]
116pub struct Scalar(FsFr);
117
118const_assert_eq!(
119 mem::size_of::<Option<Scalar>>(),
120 mem::size_of::<Option<FsFr>>()
121);
122const_assert_eq!(
123 mem::align_of::<Option<Scalar>>(),
124 mem::align_of::<Option<FsFr>>()
125);
126
127impl From<&[u8; ScalarBytes::SAFE_BYTES]> for Scalar {
128 #[inline]
129 fn from(value: &[u8; ScalarBytes::SAFE_BYTES]) -> Self {
130 let mut bytes = [0u8; ScalarBytes::FULL_BYTES];
131 bytes[1..].copy_from_slice(value);
132 Self::try_from(bytes).expect("Safe bytes always fit into scalar and thus succeed; qed")
133 }
134}
135
136impl From<[u8; ScalarBytes::SAFE_BYTES]> for Scalar {
137 #[inline]
138 fn from(value: [u8; ScalarBytes::SAFE_BYTES]) -> Self {
139 Self::from(&value)
140 }
141}
142
143impl TryFrom<&[u8; ScalarBytes::FULL_BYTES]> for Scalar {
144 type Error = String;
145
146 #[inline]
147 fn try_from(value: &[u8; ScalarBytes::FULL_BYTES]) -> Result<Self, Self::Error> {
148 Self::try_from(*value)
149 }
150}
151
152impl TryFrom<[u8; ScalarBytes::FULL_BYTES]> for Scalar {
153 type Error = String;
154
155 #[inline]
156 fn try_from(value: [u8; ScalarBytes::FULL_BYTES]) -> Result<Self, Self::Error> {
157 FsFr::from_bytes(&value).map(Scalar)
158 }
159}
160
161impl TryFrom<&ScalarBytes> for Scalar {
162 type Error = String;
163
164 #[inline]
165 fn try_from(value: &ScalarBytes) -> Result<Self, Self::Error> {
166 FsFr::from_bytes(value.as_ref()).map(Scalar)
167 }
168}
169
170impl TryFrom<ScalarBytes> for Scalar {
171 type Error = String;
172
173 #[inline]
174 fn try_from(value: ScalarBytes) -> Result<Self, Self::Error> {
175 Self::try_from(&value)
176 }
177}
178
179impl From<&Scalar> for [u8; ScalarBytes::FULL_BYTES] {
180 #[inline]
181 fn from(value: &Scalar) -> Self {
182 value.0.to_bytes()
183 }
184}
185
186impl From<Scalar> for [u8; ScalarBytes::FULL_BYTES] {
187 #[inline]
188 fn from(value: Scalar) -> Self {
189 Self::from(&value)
190 }
191}
192
193impl From<&Scalar> for ScalarBytes {
194 #[inline]
195 fn from(value: &Scalar) -> Self {
196 ScalarBytes::from(value.0.to_bytes())
197 }
198}
199
200impl From<Scalar> for ScalarBytes {
201 #[inline]
202 fn from(value: Scalar) -> Self {
203 Self::from(&value)
204 }
205}
206
207impl Scalar {
208 pub fn to_bytes(&self) -> [u8; ScalarBytes::FULL_BYTES] {
210 self.into()
211 }
212
213 pub fn try_to_safe_bytes(&self) -> Option<[u8; ScalarBytes::SAFE_BYTES]> {
216 let bytes = self.to_bytes();
217 if bytes[0] == 0 {
218 Some(bytes[1..].try_into().expect("Correct length; qed"))
219 } else {
220 None
221 }
222 }
223
224 #[inline]
227 pub fn slice_to_repr(value: &[Self]) -> &[FsFr] {
228 unsafe { mem::transmute(value) }
230 }
231
232 #[inline]
235 pub fn slice_from_repr(value: &[FsFr]) -> &[Self] {
236 unsafe { mem::transmute(value) }
238 }
239
240 #[inline]
243 pub fn slice_option_to_repr(value: &[Option<Self>]) -> &[Option<FsFr>] {
244 unsafe { mem::transmute(value) }
248 }
249
250 #[inline]
253 pub fn slice_option_from_repr(value: &[Option<FsFr>]) -> &[Option<Self>] {
254 unsafe { mem::transmute(value) }
258 }
259
260 #[inline]
263 pub fn slice_mut_to_repr(value: &mut [Self]) -> &mut [FsFr] {
264 unsafe { mem::transmute(value) }
266 }
267
268 #[inline]
271 pub fn slice_mut_from_repr(value: &mut [FsFr]) -> &mut [Self] {
272 unsafe { mem::transmute(value) }
274 }
275
276 #[inline]
279 pub fn slice_option_mut_to_repr(value: &mut [Option<Self>]) -> &mut [Option<FsFr>] {
280 unsafe { mem::transmute(value) }
284 }
285
286 #[inline]
289 pub fn slice_option_mut_from_repr(value: &mut [Option<FsFr>]) -> &mut [Option<Self>] {
290 unsafe { mem::transmute(value) }
294 }
295
296 #[inline]
299 pub fn vec_to_repr(value: Vec<Self>) -> Vec<FsFr> {
300 unsafe {
303 let mut value = mem::ManuallyDrop::new(value);
304 Vec::from_raw_parts(
305 value.as_mut_ptr() as *mut FsFr,
306 value.len(),
307 value.capacity(),
308 )
309 }
310 }
311
312 #[inline]
315 pub fn vec_from_repr(value: Vec<FsFr>) -> Vec<Self> {
316 unsafe {
319 let mut value = mem::ManuallyDrop::new(value);
320 Vec::from_raw_parts(
321 value.as_mut_ptr() as *mut Self,
322 value.len(),
323 value.capacity(),
324 )
325 }
326 }
327
328 #[inline]
331 pub fn vec_option_to_repr(value: Vec<Option<Self>>) -> Vec<Option<FsFr>> {
332 unsafe {
336 let mut value = mem::ManuallyDrop::new(value);
337 Vec::from_raw_parts(
338 value.as_mut_ptr() as *mut Option<FsFr>,
339 value.len(),
340 value.capacity(),
341 )
342 }
343 }
344
345 #[inline]
348 pub fn vec_option_from_repr(value: Vec<Option<FsFr>>) -> Vec<Option<Self>> {
349 unsafe {
353 let mut value = mem::ManuallyDrop::new(value);
354 Vec::from_raw_parts(
355 value.as_mut_ptr() as *mut Option<Self>,
356 value.len(),
357 value.capacity(),
358 )
359 }
360 }
361}
362
363#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, From, Into, AsRef, AsMut, Deref, DerefMut)]
365#[repr(transparent)]
366pub struct Commitment(FsG1);
367
368const_assert_eq!(
369 mem::size_of::<Option<Commitment>>(),
370 mem::size_of::<Option<FsG1>>()
371);
372const_assert_eq!(
373 mem::align_of::<Option<Commitment>>(),
374 mem::align_of::<Option<FsG1>>()
375);
376
377impl Commitment {
378 const SIZE: usize = 48;
380
381 #[inline]
383 pub fn to_bytes(&self) -> [u8; Self::SIZE] {
384 self.0.to_bytes()
385 }
386
387 #[inline]
389 pub fn try_from_bytes(bytes: &[u8; Self::SIZE]) -> Result<Self, String> {
390 Ok(Commitment(FsG1::from_bytes(bytes)?))
391 }
392
393 #[inline]
396 pub fn slice_to_repr(value: &[Self]) -> &[FsG1] {
397 unsafe { mem::transmute(value) }
400 }
401
402 #[inline]
405 pub fn slice_from_repr(value: &[FsG1]) -> &[Self] {
406 unsafe { mem::transmute(value) }
409 }
410
411 #[inline]
414 pub fn slice_option_to_repr(value: &[Option<Self>]) -> &[Option<FsG1>] {
415 unsafe { mem::transmute(value) }
419 }
420
421 #[inline]
424 pub fn slice_option_from_repr(value: &[Option<FsG1>]) -> &[Option<Self>] {
425 unsafe { mem::transmute(value) }
429 }
430
431 #[inline]
434 pub fn slice_mut_to_repr(value: &mut [Self]) -> &mut [FsG1] {
435 unsafe { mem::transmute(value) }
438 }
439
440 #[inline]
443 pub fn slice_mut_from_repr(value: &mut [FsG1]) -> &mut [Self] {
444 unsafe { mem::transmute(value) }
447 }
448
449 #[inline]
452 pub fn slice_option_mut_to_repr(value: &mut [Option<Self>]) -> &mut [Option<FsG1>] {
453 unsafe { mem::transmute(value) }
457 }
458
459 #[inline]
462 pub fn slice_option_mut_from_repr(value: &mut [Option<FsG1>]) -> &mut [Option<Self>] {
463 unsafe { mem::transmute(value) }
467 }
468
469 #[inline]
472 pub fn vec_to_repr(value: Vec<Self>) -> Vec<FsG1> {
473 unsafe {
476 let mut value = mem::ManuallyDrop::new(value);
477 Vec::from_raw_parts(
478 value.as_mut_ptr() as *mut FsG1,
479 value.len(),
480 value.capacity(),
481 )
482 }
483 }
484
485 #[inline]
488 pub fn vec_from_repr(value: Vec<FsG1>) -> Vec<Self> {
489 unsafe {
492 let mut value = mem::ManuallyDrop::new(value);
493 Vec::from_raw_parts(
494 value.as_mut_ptr() as *mut Self,
495 value.len(),
496 value.capacity(),
497 )
498 }
499 }
500
501 #[inline]
504 pub fn vec_option_to_repr(value: Vec<Option<Self>>) -> Vec<Option<FsG1>> {
505 unsafe {
509 let mut value = mem::ManuallyDrop::new(value);
510 Vec::from_raw_parts(
511 value.as_mut_ptr() as *mut Option<FsG1>,
512 value.len(),
513 value.capacity(),
514 )
515 }
516 }
517
518 #[inline]
521 pub fn vec_option_from_repr(value: Vec<Option<FsG1>>) -> Vec<Option<Self>> {
522 unsafe {
526 let mut value = mem::ManuallyDrop::new(value);
527 Vec::from_raw_parts(
528 value.as_mut_ptr() as *mut Option<Self>,
529 value.len(),
530 value.capacity(),
531 )
532 }
533 }
534}
535
536impl From<Commitment> for RecordCommitment {
537 #[inline]
538 fn from(commitment: Commitment) -> Self {
539 RecordCommitment::from(commitment.to_bytes())
540 }
541}
542
543impl TryFrom<&RecordCommitment> for Commitment {
544 type Error = String;
545
546 #[inline]
547 fn try_from(commitment: &RecordCommitment) -> Result<Self, Self::Error> {
548 Commitment::try_from(**commitment)
549 }
550}
551
552impl TryFrom<RecordCommitment> for Commitment {
553 type Error = String;
554
555 #[inline]
556 fn try_from(commitment: RecordCommitment) -> Result<Self, Self::Error> {
557 Commitment::try_from(&commitment)
558 }
559}
560
561impl From<Commitment> for SegmentCommitment {
562 #[inline]
563 fn from(commitment: Commitment) -> Self {
564 SegmentCommitment::from(commitment.to_bytes())
565 }
566}
567
568impl TryFrom<&SegmentCommitment> for Commitment {
569 type Error = String;
570
571 #[inline]
572 fn try_from(commitment: &SegmentCommitment) -> Result<Self, Self::Error> {
573 Commitment::try_from(**commitment)
574 }
575}
576
577impl TryFrom<SegmentCommitment> for Commitment {
578 type Error = String;
579
580 #[inline]
581 fn try_from(commitment: SegmentCommitment) -> Result<Self, Self::Error> {
582 Commitment::try_from(&commitment)
583 }
584}
585
586impl From<Commitment> for [u8; Commitment::SIZE] {
587 #[inline]
588 fn from(commitment: Commitment) -> Self {
589 commitment.to_bytes()
590 }
591}
592
593impl From<&Commitment> for [u8; Commitment::SIZE] {
594 #[inline]
595 fn from(commitment: &Commitment) -> Self {
596 commitment.to_bytes()
597 }
598}
599
600impl TryFrom<&[u8; Self::SIZE]> for Commitment {
601 type Error = String;
602
603 #[inline]
604 fn try_from(bytes: &[u8; Self::SIZE]) -> Result<Self, Self::Error> {
605 Self::try_from_bytes(bytes)
606 }
607}
608
609impl TryFrom<[u8; Self::SIZE]> for Commitment {
610 type Error = String;
611
612 #[inline]
613 fn try_from(bytes: [u8; Self::SIZE]) -> Result<Self, Self::Error> {
614 Self::try_from(&bytes)
615 }
616}
617
618#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, From, Into, AsRef, AsMut, Deref, DerefMut)]
620#[repr(transparent)]
621pub struct Witness(FsG1);
622
623impl Witness {
624 const SIZE: usize = 48;
626
627 pub fn to_bytes(&self) -> [u8; Self::SIZE] {
629 self.0.to_bytes()
630 }
631
632 pub fn try_from_bytes(bytes: &[u8; Self::SIZE]) -> Result<Self, String> {
634 Ok(Witness(FsG1::from_bytes(bytes)?))
635 }
636}
637
638impl From<Witness> for RecordWitness {
639 #[inline]
640 fn from(witness: Witness) -> Self {
641 RecordWitness::from(witness.to_bytes())
642 }
643}
644
645impl TryFrom<&RecordWitness> for Witness {
646 type Error = String;
647
648 #[inline]
649 fn try_from(witness: &RecordWitness) -> Result<Self, Self::Error> {
650 Witness::try_from(**witness)
651 }
652}
653
654impl TryFrom<RecordWitness> for Witness {
655 type Error = String;
656
657 #[inline]
658 fn try_from(witness: RecordWitness) -> Result<Self, Self::Error> {
659 Witness::try_from(&witness)
660 }
661}
662
663impl From<Witness> for ChunkWitness {
664 #[inline]
665 fn from(witness: Witness) -> Self {
666 ChunkWitness::from(witness.to_bytes())
667 }
668}
669
670impl TryFrom<&ChunkWitness> for Witness {
671 type Error = String;
672
673 #[inline]
674 fn try_from(witness: &ChunkWitness) -> Result<Self, Self::Error> {
675 Witness::try_from(**witness)
676 }
677}
678
679impl TryFrom<ChunkWitness> for Witness {
680 type Error = String;
681
682 #[inline]
683 fn try_from(witness: ChunkWitness) -> Result<Self, Self::Error> {
684 Witness::try_from(&witness)
685 }
686}
687
688impl From<Witness> for [u8; Witness::SIZE] {
689 #[inline]
690 fn from(witness: Witness) -> Self {
691 witness.to_bytes()
692 }
693}
694
695impl From<&Witness> for [u8; Witness::SIZE] {
696 #[inline]
697 fn from(witness: &Witness) -> Self {
698 witness.to_bytes()
699 }
700}
701
702impl TryFrom<&[u8; Self::SIZE]> for Witness {
703 type Error = String;
704
705 #[inline]
706 fn try_from(bytes: &[u8; Self::SIZE]) -> Result<Self, Self::Error> {
707 Self::try_from_bytes(bytes)
708 }
709}
710
711impl TryFrom<[u8; Self::SIZE]> for Witness {
712 type Error = String;
713
714 #[inline]
715 fn try_from(bytes: [u8; Self::SIZE]) -> Result<Self, Self::Error> {
716 Self::try_from(&bytes)
717 }
718}
719
720#[derive(Debug)]
721struct Inner {
722 kzg_settings: FsKZGSettings,
723 fft_settings_cache: Mutex<BTreeMap<usize, Arc<FsFFTSettings>>>,
724}
725
726#[derive(Debug, Clone)]
728pub struct Kzg {
729 inner: Arc<Inner>,
730}
731
732impl Kzg {
733 #[expect(
737 clippy::new_without_default,
738 reason = "Default must not be implemented, because Kzg should be cloned instead. Cloning is cheap and instantiation is not."
739 )]
740 pub fn new() -> Self {
741 let kzg_settings =
742 bytes_to_kzg_settings(EMBEDDED_KZG_SETTINGS_BYTES, NUM_G1_POWERS, NUM_G2_POWERS)
743 .expect("Static bytes are correct, there is a test for this; qed");
744
745 let inner = Arc::new(Inner {
746 kzg_settings,
747 fft_settings_cache: Mutex::default(),
748 });
749
750 Self { inner }
751 }
752
753 pub fn poly(&self, data: &[Scalar]) -> Result<Polynomial, String> {
758 let poly = FsPoly {
759 coeffs: self
760 .get_fft_settings(data.len())?
761 .fft_fr(Scalar::slice_to_repr(data), true)?,
762 };
763 Ok(Polynomial(poly))
764 }
765
766 pub fn commit(&self, polynomial: &Polynomial) -> Result<Commitment, String> {
768 self.inner
769 .kzg_settings
770 .commit_to_poly(&polynomial.0)
771 .map(Commitment)
772 }
773
774 pub fn create_witness(
776 &self,
777 polynomial: &Polynomial,
778 num_values: usize,
779 index: u32,
780 ) -> Result<Witness, String> {
781 let x = self
782 .get_fft_settings(num_values)?
783 .get_expanded_roots_of_unity_at(index as usize);
784 self.inner
785 .kzg_settings
786 .compute_proof_single(&polynomial.0, &x)
787 .map(Witness)
788 }
789
790 pub fn verify(
793 &self,
794 commitment: &Commitment,
795 num_values: usize,
796 index: u32,
797 value: &Scalar,
798 witness: &Witness,
799 ) -> bool {
800 let fft_settings = match self.get_fft_settings(num_values) {
801 Ok(fft_settings) => fft_settings,
802 Err(error) => {
803 debug!(error, "Failed to derive fft settings");
804 return false;
805 }
806 };
807 let x = fft_settings.get_expanded_roots_of_unity_at(index as usize);
808
809 match self
810 .inner
811 .kzg_settings
812 .check_proof_single(&commitment.0, &witness.0, &x, value)
813 {
814 Ok(result) => result,
815 Err(error) => {
816 debug!(error, "Failed to check proof");
817 false
818 }
819 }
820 }
821
822 fn get_fft_settings(&self, num_values: usize) -> Result<Arc<FsFFTSettings>, String> {
825 let num_values = num_values.next_power_of_two();
826 Ok(
827 match self.inner.fft_settings_cache.lock().entry(num_values) {
828 Entry::Vacant(entry) => {
829 let fft_settings = Arc::new(FsFFTSettings::new(num_values.ilog2() as usize)?);
830 entry.insert(Arc::clone(&fft_settings));
831 fft_settings
832 }
833 Entry::Occupied(entry) => Arc::clone(entry.get()),
834 },
835 )
836 }
837}