1#![allow(non_upper_case_globals)]
2#![allow(non_camel_case_types)]
3#![allow(non_snake_case)]
4#![allow(dead_code)]
5
6#[cfg(feature = "serde")]
7mod serde;
8#[cfg(test)]
9mod test_formats;
10
11include!("./generated.rs");
12
13use alloc::boxed::Box;
14use alloc::string::String;
15use alloc::vec::Vec;
16use core::ffi::CStr;
17use core::fmt;
18use core::mem::MaybeUninit;
19use core::ops::{Deref, DerefMut};
20use core::ptr;
21
22#[cfg(feature = "std")]
23use alloc::ffi::CString;
24#[cfg(feature = "std")]
25use std::path::Path;
26
27const BYTES_PER_G1_POINT: usize = 48;
28const BYTES_PER_G2_POINT: usize = 96;
29
30const NUM_G1_POINTS: usize = 4096;
32
33const NUM_G2_POINTS: usize = 65;
36
37#[repr(C)]
42#[derive(Debug, Copy, Clone)]
43pub struct KZGCommitment {
44 bytes: [u8; BYTES_PER_COMMITMENT],
45}
46
47#[repr(C)]
52#[derive(Debug, Copy, Clone)]
53pub struct KZGProof {
54 bytes: [u8; BYTES_PER_PROOF],
55}
56
57#[derive(Debug)]
58pub enum Error {
59 InvalidBytesLength(String),
61 InvalidHexFormat(String),
63 InvalidKzgProof(String),
65 InvalidKzgCommitment(String),
67 InvalidTrustedSetup(String),
69 MismatchLength(String),
71 LoadingTrustedSetupFailed(KzgErrors),
73 CError(C_KZG_RET),
75}
76
77#[cfg(feature = "std")]
78impl std::error::Error for Error {}
79
80impl fmt::Display for Error {
81 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82 match self {
83 Self::InvalidBytesLength(s)
84 | Self::InvalidHexFormat(s)
85 | Self::InvalidKzgProof(s)
86 | Self::InvalidKzgCommitment(s)
87 | Self::InvalidTrustedSetup(s)
88 | Self::MismatchLength(s) => f.write_str(s),
89 Self::LoadingTrustedSetupFailed(s) => write!(f, "KzgErrors: {s:?}"),
90 Self::CError(s) => fmt::Debug::fmt(s, f),
91 }
92 }
93}
94
95impl From<KzgErrors> for Error {
96 fn from(e: KzgErrors) -> Self {
97 Error::LoadingTrustedSetupFailed(e)
98 }
99}
100
101pub type CellsPerExtBlob = [Cell; CELLS_PER_EXT_BLOB];
102pub type ProofsPerExtBlob = [KZGProof; CELLS_PER_EXT_BLOB];
103
104#[derive(Debug)]
105pub enum KzgErrors {
106 FailedCurrentDirectory,
108 PathNotExists,
110 IOError,
112 NotValidFile,
114 FileFormatError,
116 ParseError,
118 MismatchedNumberOfPoints,
120}
121
122pub fn hex_to_bytes(hex_str: &str) -> Result<Vec<u8>, Error> {
124 let trimmed_str = hex_str.strip_prefix("0x").unwrap_or(hex_str);
125 hex::decode(trimmed_str)
126 .map_err(|e| Error::InvalidHexFormat(format!("Failed to decode hex: {e}")))
127}
128
129impl KZGSettings {
131 pub fn load_trusted_setup(
135 g1_monomial_bytes: &[u8],
136 g1_lagrange_bytes: &[u8],
137 g2_monomial_bytes: &[u8],
138 precompute: u64,
139 ) -> Result<Self, Error> {
140 let mut kzg_settings = MaybeUninit::<KZGSettings>::uninit();
141 unsafe {
142 let res = load_trusted_setup(
143 kzg_settings.as_mut_ptr(),
144 g1_monomial_bytes.as_ptr().cast(),
145 g1_monomial_bytes.len() as u64,
146 g1_lagrange_bytes.as_ptr().cast(),
147 g1_lagrange_bytes.len() as u64,
148 g2_monomial_bytes.as_ptr().cast(),
149 g2_monomial_bytes.len() as u64,
150 precompute,
151 );
152 if let C_KZG_RET::C_KZG_OK = res {
153 Ok(kzg_settings.assume_init())
154 } else {
155 Err(Error::InvalidTrustedSetup(format!(
156 "Invalid trusted setup: {res:?}",
157 )))
158 }
159 }
160 }
161
162 #[cfg(feature = "std")]
170 pub fn load_trusted_setup_file(file_path: &Path, precompute: u64) -> Result<Self, Error> {
171 #[cfg(unix)]
172 let file_path_bytes = {
173 use std::os::unix::prelude::OsStrExt;
174 file_path.as_os_str().as_bytes()
175 };
176
177 #[cfg(windows)]
178 let file_path_bytes = file_path
179 .as_os_str()
180 .to_str()
181 .ok_or_else(|| Error::InvalidTrustedSetup("Unsupported non unicode file path".into()))?
182 .as_bytes();
183
184 let file_path = CString::new(file_path_bytes)
185 .map_err(|e| Error::InvalidTrustedSetup(format!("Invalid trusted setup file: {e}")))?;
186
187 Self::load_trusted_setup_file_inner(&file_path, precompute)
188 }
189
190 pub fn parse_kzg_trusted_setup(trusted_setup: &str, precompute: u64) -> Result<Self, Error> {
192 let mut lines = trusted_setup.lines();
193
194 let n_g1 = lines
196 .next()
197 .ok_or(KzgErrors::FileFormatError)?
198 .parse::<usize>()
199 .map_err(|_| KzgErrors::ParseError)?;
200 if n_g1 != NUM_G1_POINTS {
201 return Err(KzgErrors::MismatchedNumberOfPoints.into());
202 }
203
204 let n_g2 = lines
206 .next()
207 .ok_or(KzgErrors::FileFormatError)?
208 .parse::<usize>()
209 .map_err(|_| KzgErrors::ParseError)?;
210 if n_g2 != NUM_G2_POINTS {
211 return Err(KzgErrors::MismatchedNumberOfPoints.into());
212 }
213
214 let mut g1_lagrange_bytes = alloc::boxed::Box::new([0; BYTES_PER_G1_POINT * NUM_G1_POINTS]);
215 let mut g2_monomial_bytes = alloc::boxed::Box::new([0; BYTES_PER_G2_POINT * NUM_G2_POINTS]);
216 let mut g1_monomial_bytes = alloc::boxed::Box::new([0; BYTES_PER_G1_POINT * NUM_G1_POINTS]);
217
218 g1_lagrange_bytes
220 .chunks_mut(BYTES_PER_G1_POINT)
221 .try_for_each(|chunk| {
222 let line = lines.next().ok_or(KzgErrors::FileFormatError)?;
223 hex::decode_to_slice(line, chunk).map_err(|_| KzgErrors::ParseError)
224 })?;
225
226 g2_monomial_bytes
228 .chunks_mut(BYTES_PER_G2_POINT)
229 .try_for_each(|chunk| {
230 let line = lines.next().ok_or(KzgErrors::FileFormatError)?;
231 hex::decode_to_slice(line, chunk).map_err(|_| KzgErrors::ParseError)
232 })?;
233
234 g1_monomial_bytes
236 .chunks_mut(BYTES_PER_G1_POINT)
237 .try_for_each(|chunk| {
238 let line = lines.next().ok_or(KzgErrors::FileFormatError)?;
239 hex::decode_to_slice(line, chunk).map_err(|_| KzgErrors::ParseError)
240 })?;
241
242 if lines.next().is_some() {
243 return Err(KzgErrors::FileFormatError.into());
244 }
245
246 Self::load_trusted_setup(
247 g1_monomial_bytes.as_ref(),
248 g1_lagrange_bytes.as_ref(),
249 g2_monomial_bytes.as_ref(),
250 precompute,
251 )
252 }
253
254 #[cfg(not(feature = "std"))]
262 pub fn load_trusted_setup_file(file_path: &CStr, precompute: u64) -> Result<Self, Error> {
263 Self::load_trusted_setup_file_inner(file_path, precompute)
264 }
265
266 #[cfg_attr(not(feature = "std"), doc = ", but takes a `CStr` instead of a `Path`")]
270 pub fn load_trusted_setup_file_inner(file_path: &CStr, precompute: u64) -> Result<Self, Error> {
271 const MODE: &CStr = c"r";
273
274 let file_ptr = unsafe { libc::fopen(file_path.as_ptr(), MODE.as_ptr()) };
278 if file_ptr.is_null() {
279 #[cfg(not(feature = "std"))]
280 return Err(Error::InvalidTrustedSetup(format!(
281 "Failed to open trusted setup file {file_path:?}"
282 )));
283
284 #[cfg(feature = "std")]
285 return Err(Error::InvalidTrustedSetup(format!(
286 "Failed to open trusted setup file {file_path:?}: {}",
287 std::io::Error::last_os_error()
288 )));
289 }
290 let mut kzg_settings = MaybeUninit::<KZGSettings>::uninit();
291
292 unsafe {
293 let res = load_trusted_setup_file(kzg_settings.as_mut_ptr(), file_ptr, precompute);
294 let _unchecked_close_result = libc::fclose(file_ptr);
295
296 if let C_KZG_RET::C_KZG_OK = res {
297 Ok(kzg_settings.assume_init())
298 } else {
299 Err(Error::InvalidTrustedSetup(format!(
300 "Invalid trusted setup: {res:?}"
301 )))
302 }
303 }
304 }
305
306 pub fn blob_to_kzg_commitment(&self, blob: &Blob) -> Result<KZGCommitment, Error> {
307 let mut kzg_commitment: MaybeUninit<KZGCommitment> = MaybeUninit::uninit();
308 unsafe {
309 let res = blob_to_kzg_commitment(kzg_commitment.as_mut_ptr(), blob, self);
310 if let C_KZG_RET::C_KZG_OK = res {
311 Ok(kzg_commitment.assume_init())
312 } else {
313 Err(Error::CError(res))
314 }
315 }
316 }
317
318 pub fn compute_kzg_proof(
319 &self,
320 blob: &Blob,
321 z_bytes: &Bytes32,
322 ) -> Result<(KZGProof, Bytes32), Error> {
323 let mut kzg_proof = MaybeUninit::<KZGProof>::uninit();
324 let mut y_out = MaybeUninit::<Bytes32>::uninit();
325 unsafe {
326 let res = compute_kzg_proof(
327 kzg_proof.as_mut_ptr(),
328 y_out.as_mut_ptr(),
329 blob,
330 z_bytes,
331 self,
332 );
333 if let C_KZG_RET::C_KZG_OK = res {
334 Ok((kzg_proof.assume_init(), y_out.assume_init()))
335 } else {
336 Err(Error::CError(res))
337 }
338 }
339 }
340
341 pub fn compute_blob_kzg_proof(
342 &self,
343 blob: &Blob,
344 commitment_bytes: &Bytes48,
345 ) -> Result<KZGProof, Error> {
346 let mut kzg_proof = MaybeUninit::<KZGProof>::uninit();
347 unsafe {
348 let res = compute_blob_kzg_proof(kzg_proof.as_mut_ptr(), blob, commitment_bytes, self);
349 if let C_KZG_RET::C_KZG_OK = res {
350 Ok(kzg_proof.assume_init())
351 } else {
352 Err(Error::CError(res))
353 }
354 }
355 }
356
357 pub fn verify_kzg_proof(
358 &self,
359 commitment_bytes: &Bytes48,
360 z_bytes: &Bytes32,
361 y_bytes: &Bytes32,
362 proof_bytes: &Bytes48,
363 ) -> Result<bool, Error> {
364 let mut verified: MaybeUninit<bool> = MaybeUninit::uninit();
365 unsafe {
366 let res = verify_kzg_proof(
367 verified.as_mut_ptr(),
368 commitment_bytes,
369 z_bytes,
370 y_bytes,
371 proof_bytes,
372 self,
373 );
374 if let C_KZG_RET::C_KZG_OK = res {
375 Ok(verified.assume_init())
376 } else {
377 Err(Error::CError(res))
378 }
379 }
380 }
381
382 pub fn verify_blob_kzg_proof(
383 &self,
384 blob: &Blob,
385 commitment_bytes: &Bytes48,
386 proof_bytes: &Bytes48,
387 ) -> Result<bool, Error> {
388 let mut verified: MaybeUninit<bool> = MaybeUninit::uninit();
389 unsafe {
390 let res = verify_blob_kzg_proof(
391 verified.as_mut_ptr(),
392 blob,
393 commitment_bytes,
394 proof_bytes,
395 self,
396 );
397 if let C_KZG_RET::C_KZG_OK = res {
398 Ok(verified.assume_init())
399 } else {
400 Err(Error::CError(res))
401 }
402 }
403 }
404
405 pub fn verify_blob_kzg_proof_batch(
406 &self,
407 blobs: &[Blob],
408 commitments_bytes: &[Bytes48],
409 proofs_bytes: &[Bytes48],
410 ) -> Result<bool, Error> {
411 if blobs.len() != commitments_bytes.len() {
412 return Err(Error::MismatchLength(format!(
413 "There are {} blobs and {} commitments",
414 blobs.len(),
415 commitments_bytes.len()
416 )));
417 }
418 if blobs.len() != proofs_bytes.len() {
419 return Err(Error::MismatchLength(format!(
420 "There are {} blobs and {} proofs",
421 blobs.len(),
422 proofs_bytes.len()
423 )));
424 }
425 let mut verified: MaybeUninit<bool> = MaybeUninit::uninit();
426 unsafe {
427 let res = verify_blob_kzg_proof_batch(
428 verified.as_mut_ptr(),
429 blobs.as_ptr(),
430 commitments_bytes.as_ptr(),
431 proofs_bytes.as_ptr(),
432 blobs.len() as u64,
433 self,
434 );
435 if let C_KZG_RET::C_KZG_OK = res {
436 Ok(verified.assume_init())
437 } else {
438 Err(Error::CError(res))
439 }
440 }
441 }
442
443 pub fn compute_cells(&self, blob: &Blob) -> Result<Box<CellsPerExtBlob>, Error> {
444 let mut cells: Box<[Cell; CELLS_PER_EXT_BLOB]> = vec![Cell::default(); CELLS_PER_EXT_BLOB]
445 .into_boxed_slice()
446 .try_into()
447 .unwrap();
448 unsafe {
449 let res = compute_cells_and_kzg_proofs(cells.as_mut_ptr(), ptr::null_mut(), blob, self);
450 if let C_KZG_RET::C_KZG_OK = res {
451 Ok(cells)
452 } else {
453 Err(Error::CError(res))
454 }
455 }
456 }
457
458 pub fn compute_cells_and_kzg_proofs(
459 &self,
460 blob: &Blob,
461 ) -> Result<(Box<CellsPerExtBlob>, Box<ProofsPerExtBlob>), Error> {
462 let mut cells: Box<[Cell; CELLS_PER_EXT_BLOB]> = vec![Cell::default(); CELLS_PER_EXT_BLOB]
463 .into_boxed_slice()
464 .try_into()
465 .unwrap();
466 let mut proofs: Box<[KZGProof; CELLS_PER_EXT_BLOB]> =
467 vec![KZGProof::default(); CELLS_PER_EXT_BLOB]
468 .into_boxed_slice()
469 .try_into()
470 .unwrap();
471 unsafe {
472 let res =
473 compute_cells_and_kzg_proofs(cells.as_mut_ptr(), proofs.as_mut_ptr(), blob, self);
474 if let C_KZG_RET::C_KZG_OK = res {
475 Ok((cells, proofs))
476 } else {
477 Err(Error::CError(res))
478 }
479 }
480 }
481
482 pub fn recover_cells_and_kzg_proofs(
483 &self,
484 cell_indices: &[u64],
485 cells: &[Cell],
486 ) -> Result<(Box<CellsPerExtBlob>, Box<ProofsPerExtBlob>), Error> {
487 if cell_indices.len() != cells.len() {
488 return Err(Error::MismatchLength(format!(
489 "There are {} cell indices and {} cells",
490 cell_indices.len(),
491 cells.len()
492 )));
493 }
494 let mut recovered_cells: Box<[Cell; CELLS_PER_EXT_BLOB]> =
495 vec![Cell::default(); CELLS_PER_EXT_BLOB]
496 .into_boxed_slice()
497 .try_into()
498 .unwrap();
499 let mut recovered_proofs: Box<[KZGProof; CELLS_PER_EXT_BLOB]> =
500 vec![KZGProof::default(); CELLS_PER_EXT_BLOB]
501 .into_boxed_slice()
502 .try_into()
503 .unwrap();
504 unsafe {
505 let res = recover_cells_and_kzg_proofs(
506 recovered_cells.as_mut_ptr(),
507 recovered_proofs.as_mut_ptr(),
508 cell_indices.as_ptr(),
509 cells.as_ptr(),
510 cells.len() as u64,
511 self,
512 );
513 if let C_KZG_RET::C_KZG_OK = res {
514 Ok((recovered_cells, recovered_proofs))
515 } else {
516 Err(Error::CError(res))
517 }
518 }
519 }
520
521 pub fn verify_cell_kzg_proof_batch(
522 &self,
523 commitments_bytes: &[Bytes48],
524 cell_indices: &[u64],
525 cells: &[Cell],
526 proofs_bytes: &[Bytes48],
527 ) -> Result<bool, Error> {
528 if cells.len() != commitments_bytes.len() {
529 return Err(Error::MismatchLength(format!(
530 "There are {} cells and {} commitments",
531 cells.len(),
532 commitments_bytes.len()
533 )));
534 }
535 if cells.len() != cell_indices.len() {
536 return Err(Error::MismatchLength(format!(
537 "There are {} cells and {} column indices",
538 cells.len(),
539 cell_indices.len()
540 )));
541 }
542 if cells.len() != proofs_bytes.len() {
543 return Err(Error::MismatchLength(format!(
544 "There are {} cells and {} proofs",
545 cells.len(),
546 proofs_bytes.len()
547 )));
548 }
549 let mut verified: MaybeUninit<bool> = MaybeUninit::uninit();
550 unsafe {
551 let res = verify_cell_kzg_proof_batch(
552 verified.as_mut_ptr(),
553 commitments_bytes.as_ptr(),
554 cell_indices.as_ptr(),
555 cells.as_ptr(),
556 proofs_bytes.as_ptr(),
557 cells.len() as u64,
558 self,
559 );
560 if let C_KZG_RET::C_KZG_OK = res {
561 Ok(verified.assume_init())
562 } else {
563 Err(Error::CError(res))
564 }
565 }
566 }
567}
568
569impl Drop for KZGSettings {
570 fn drop(&mut self) {
571 unsafe { free_trusted_setup(self) }
572 }
573}
574
575impl Blob {
576 pub const fn new(bytes: [u8; BYTES_PER_BLOB]) -> Self {
578 Self { bytes }
579 }
580
581 pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
582 if bytes.len() != BYTES_PER_BLOB {
583 return Err(Error::InvalidBytesLength(format!(
584 "Invalid byte length. Expected {} got {}",
585 BYTES_PER_BLOB,
586 bytes.len(),
587 )));
588 }
589 let mut new_bytes = [0; BYTES_PER_BLOB];
590 new_bytes.copy_from_slice(bytes);
591 Ok(Self::new(new_bytes))
592 }
593
594 pub fn from_hex(hex_str: &str) -> Result<Self, Error> {
595 Self::from_bytes(&hex_to_bytes(hex_str)?)
596 }
597
598 pub fn into_inner(self) -> [u8; BYTES_PER_BLOB] {
599 self.bytes
600 }
601}
602
603impl AsRef<[u8]> for Blob {
604 fn as_ref(&self) -> &[u8] {
605 &self.bytes
606 }
607}
608
609impl Bytes32 {
610 pub const fn new(bytes: [u8; 32]) -> Self {
612 Self { bytes }
613 }
614
615 pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
616 if bytes.len() != 32 {
617 return Err(Error::InvalidBytesLength(format!(
618 "Invalid byte length. Expected {} got {}",
619 32,
620 bytes.len(),
621 )));
622 }
623 let mut new_bytes = [0; 32];
624 new_bytes.copy_from_slice(bytes);
625 Ok(Self::new(new_bytes))
626 }
627
628 pub fn from_hex(hex_str: &str) -> Result<Self, Error> {
629 Self::from_bytes(&hex_to_bytes(hex_str)?)
630 }
631}
632
633impl Bytes48 {
634 pub const fn new(bytes: [u8; 48]) -> Self {
636 Self { bytes }
637 }
638
639 pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
640 if bytes.len() != 48 {
641 return Err(Error::InvalidBytesLength(format!(
642 "Invalid byte length. Expected {} got {}",
643 48,
644 bytes.len(),
645 )));
646 }
647 let mut new_bytes = [0; 48];
648 new_bytes.copy_from_slice(bytes);
649 Ok(Self::new(new_bytes))
650 }
651
652 pub fn from_hex(hex_str: &str) -> Result<Self, Error> {
653 Self::from_bytes(&hex_to_bytes(hex_str)?)
654 }
655
656 pub fn into_inner(self) -> [u8; 48] {
657 self.bytes
658 }
659}
660
661impl KZGProof {
662 pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
663 if bytes.len() != BYTES_PER_PROOF {
664 return Err(Error::InvalidKzgProof(format!(
665 "Invalid byte length. Expected {} got {}",
666 BYTES_PER_PROOF,
667 bytes.len(),
668 )));
669 }
670 let mut proof_bytes = [0; BYTES_PER_PROOF];
671 proof_bytes.copy_from_slice(bytes);
672 Ok(Self { bytes: proof_bytes })
673 }
674
675 pub fn to_bytes(&self) -> Bytes48 {
676 Bytes48 { bytes: self.bytes }
677 }
678
679 pub fn as_hex_string(&self) -> String {
680 hex::encode(self.bytes)
681 }
682}
683
684impl KZGCommitment {
685 pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
686 if bytes.len() != BYTES_PER_COMMITMENT {
687 return Err(Error::InvalidKzgCommitment(format!(
688 "Invalid byte length. Expected {} got {}",
689 BYTES_PER_COMMITMENT,
690 bytes.len(),
691 )));
692 }
693 let mut commitment = [0; BYTES_PER_COMMITMENT];
694 commitment.copy_from_slice(bytes);
695 Ok(Self { bytes: commitment })
696 }
697
698 pub fn to_bytes(&self) -> Bytes48 {
699 Bytes48 { bytes: self.bytes }
700 }
701
702 pub fn as_hex_string(&self) -> String {
703 hex::encode(self.bytes)
704 }
705}
706
707impl Cell {
708 pub const fn new(bytes: [u8; BYTES_PER_CELL]) -> Self {
709 Self { bytes }
710 }
711
712 pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
713 if bytes.len() != BYTES_PER_CELL {
714 return Err(Error::InvalidBytesLength(format!(
715 "Invalid byte length. Expected {} got {}",
716 BYTES_PER_CELL,
717 bytes.len(),
718 )));
719 }
720 let mut new_bytes = [0; BYTES_PER_CELL];
721 new_bytes.copy_from_slice(bytes);
722 Ok(Self::new(new_bytes))
723 }
724
725 pub fn to_bytes(&self) -> [u8; BYTES_PER_CELL] {
726 self.bytes
727 }
728
729 pub fn from_hex(hex_str: &str) -> Result<Self, Error> {
730 Self::from_bytes(&hex_to_bytes(hex_str)?)
731 }
732}
733
734impl From<[u8; BYTES_PER_COMMITMENT]> for KZGCommitment {
735 fn from(value: [u8; BYTES_PER_COMMITMENT]) -> Self {
736 Self { bytes: value }
737 }
738}
739
740impl From<[u8; BYTES_PER_PROOF]> for KZGProof {
741 fn from(value: [u8; BYTES_PER_PROOF]) -> Self {
742 Self { bytes: value }
743 }
744}
745
746impl From<[u8; BYTES_PER_BLOB]> for Blob {
747 fn from(value: [u8; BYTES_PER_BLOB]) -> Self {
748 Self { bytes: value }
749 }
750}
751
752impl From<[u8; 32]> for Bytes32 {
753 fn from(value: [u8; 32]) -> Self {
754 Self { bytes: value }
755 }
756}
757
758impl AsRef<[u8; 32]> for Bytes32 {
759 fn as_ref(&self) -> &[u8; 32] {
760 &self.bytes
761 }
762}
763
764impl From<[u8; 48]> for Bytes48 {
765 fn from(value: [u8; 48]) -> Self {
766 Self { bytes: value }
767 }
768}
769
770impl AsRef<[u8; 48]> for Bytes48 {
771 fn as_ref(&self) -> &[u8; 48] {
772 &self.bytes
773 }
774}
775
776impl Deref for Bytes32 {
777 type Target = [u8; 32];
778 fn deref(&self) -> &Self::Target {
779 &self.bytes
780 }
781}
782
783impl Deref for Bytes48 {
784 type Target = [u8; 48];
785 fn deref(&self) -> &Self::Target {
786 &self.bytes
787 }
788}
789
790impl DerefMut for Bytes48 {
791 fn deref_mut(&mut self) -> &mut Self::Target {
792 &mut self.bytes
793 }
794}
795
796impl Deref for Blob {
797 type Target = [u8; BYTES_PER_BLOB];
798 fn deref(&self) -> &Self::Target {
799 &self.bytes
800 }
801}
802
803impl DerefMut for Blob {
804 fn deref_mut(&mut self) -> &mut Self::Target {
805 &mut self.bytes
806 }
807}
808
809impl Clone for Blob {
810 fn clone(&self) -> Self {
811 Blob { bytes: self.bytes }
812 }
813}
814
815impl Deref for KZGProof {
816 type Target = [u8; BYTES_PER_PROOF];
817 fn deref(&self) -> &Self::Target {
818 &self.bytes
819 }
820}
821
822impl Deref for KZGCommitment {
823 type Target = [u8; BYTES_PER_COMMITMENT];
824 fn deref(&self) -> &Self::Target {
825 &self.bytes
826 }
827}
828
829#[allow(clippy::derivable_impls)]
830impl Default for Bytes32 {
831 fn default() -> Self {
832 Bytes32 { bytes: [0; 32] }
833 }
834}
835
836impl Default for Bytes48 {
837 fn default() -> Self {
838 Bytes48 { bytes: [0; 48] }
839 }
840}
841
842impl Default for KZGCommitment {
843 fn default() -> Self {
844 KZGCommitment {
845 bytes: [0; BYTES_PER_COMMITMENT],
846 }
847 }
848}
849
850impl Default for KZGProof {
851 fn default() -> Self {
852 KZGProof {
853 bytes: [0; BYTES_PER_PROOF],
854 }
855 }
856}
857
858impl Default for Blob {
859 fn default() -> Self {
860 Blob {
861 bytes: [0; BYTES_PER_BLOB],
862 }
863 }
864}
865
866impl Default for Cell {
867 fn default() -> Self {
868 Cell {
869 bytes: [0; BYTES_PER_CELL],
870 }
871 }
872}
873
874#[cfg(feature = "arbitrary")]
875impl arbitrary::Arbitrary<'_> for Bytes32 {
876 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
877 let mut bytes = [0u8; 32];
878 u.fill_buffer(&mut bytes)?;
879 Ok(Bytes32::from(bytes))
880 }
881}
882
883#[cfg(feature = "arbitrary")]
884impl arbitrary::Arbitrary<'_> for Bytes48 {
885 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
886 let mut bytes = [0u8; 48];
887 u.fill_buffer(&mut bytes)?;
888 Ok(Bytes48::from(bytes))
889 }
890}
891
892#[cfg(feature = "arbitrary")]
893impl arbitrary::Arbitrary<'_> for Blob {
894 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
895 let mut bytes = [0u8; BYTES_PER_BLOB];
896 u.fill_buffer(&mut bytes)?;
897 Ok(Blob::from(bytes))
898 }
899}
900
901#[cfg(feature = "arbitrary")]
902impl arbitrary::Arbitrary<'_> for Cell {
903 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
904 let mut bytes = [0u8; BYTES_PER_CELL];
905 u.fill_buffer(&mut bytes)?;
906 Ok(Cell::new(bytes))
907 }
908}
909
910unsafe impl Sync for KZGSettings {}
913unsafe impl Send for KZGSettings {}
914
915#[cfg(test)]
916#[allow(unused_imports, dead_code)]
917mod tests {
918 use super::*;
919 use rand::{rngs::ThreadRng, Rng};
920 use std::{fs, path::PathBuf};
921 use test_formats::{
922 blob_to_kzg_commitment_test, compute_blob_kzg_proof, compute_cells,
923 compute_cells_and_kzg_proofs, compute_kzg_proof, recover_cells_and_kzg_proofs,
924 verify_blob_kzg_proof, verify_blob_kzg_proof_batch, verify_cell_kzg_proof_batch,
925 verify_kzg_proof,
926 };
927
928 fn generate_random_blob(rng: &mut ThreadRng) -> Blob {
929 let mut arr = [0u8; BYTES_PER_BLOB];
930 rng.fill(&mut arr[..]);
931 for i in 0..FIELD_ELEMENTS_PER_BLOB {
934 arr[i * BYTES_PER_FIELD_ELEMENT] = 0;
935 }
936 arr.into()
937 }
938
939 fn test_simple(trusted_setup_file: &Path) {
940 let mut rng = rand::rng();
941 assert!(trusted_setup_file.exists());
942 let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file, 0).unwrap();
943
944 let num_blobs: usize = rng.random_range(1..16);
945 let mut blobs: Vec<Blob> = (0..num_blobs)
946 .map(|_| generate_random_blob(&mut rng))
947 .collect();
948
949 let commitments: Vec<Bytes48> = blobs
950 .iter()
951 .map(|blob| kzg_settings.blob_to_kzg_commitment(blob).unwrap())
952 .map(|commitment| commitment.to_bytes())
953 .collect();
954
955 let proofs: Vec<Bytes48> = blobs
956 .iter()
957 .zip(commitments.iter())
958 .map(|(blob, commitment)| {
959 kzg_settings
960 .compute_blob_kzg_proof(blob, commitment)
961 .unwrap()
962 })
963 .map(|proof| proof.to_bytes())
964 .collect();
965
966 assert!(kzg_settings
967 .verify_blob_kzg_proof_batch(&blobs, &commitments, &proofs)
968 .unwrap());
969
970 blobs.pop();
971
972 let error = kzg_settings
973 .verify_blob_kzg_proof_batch(&blobs, &commitments, &proofs)
974 .unwrap_err();
975 assert!(matches!(error, Error::MismatchLength(_)));
976
977 let incorrect_blob = generate_random_blob(&mut rng);
978 blobs.push(incorrect_blob);
979
980 assert!(!kzg_settings
981 .verify_blob_kzg_proof_batch(&blobs, &commitments, &proofs)
982 .unwrap());
983 }
984
985 #[test]
986 fn test_end_to_end() {
987 let trusted_setup_file = Path::new("src/trusted_setup.txt");
988 test_simple(trusted_setup_file);
989 }
990
991 const BLOB_TO_KZG_COMMITMENT_TESTS: &str = "tests/blob_to_kzg_commitment/*/*/*";
992 const COMPUTE_KZG_PROOF_TESTS: &str = "tests/compute_kzg_proof/*/*/*";
993 const COMPUTE_BLOB_KZG_PROOF_TESTS: &str = "tests/compute_blob_kzg_proof/*/*/*";
994 const VERIFY_KZG_PROOF_TESTS: &str = "tests/verify_kzg_proof/*/*/*";
995 const VERIFY_BLOB_KZG_PROOF_TESTS: &str = "tests/verify_blob_kzg_proof/*/*/*";
996 const VERIFY_BLOB_KZG_PROOF_BATCH_TESTS: &str = "tests/verify_blob_kzg_proof_batch/*/*/*";
997
998 const COMPUTE_CELLS_TESTS: &str = "tests/compute_cells/*/*/*";
999 const COMPUTE_CELLS_AND_KZG_PROOFS_TESTS: &str = "tests/compute_cells_and_kzg_proofs/*/*/*";
1000 const RECOVER_CELLS_AND_KZG_PROOFS_TESTS: &str = "tests/recover_cells_and_kzg_proofs/*/*/*";
1001 const VERIFY_CELL_KZG_PROOF_BATCH_TESTS: &str = "tests/verify_cell_kzg_proof_batch/*/*/*";
1002
1003 #[test]
1004 fn test_blob_to_kzg_commitment() {
1005 let trusted_setup_file = Path::new("src/trusted_setup.txt");
1006 assert!(trusted_setup_file.exists());
1007 let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file, 0).unwrap();
1008 let test_files: Vec<PathBuf> = glob::glob(BLOB_TO_KZG_COMMITMENT_TESTS)
1009 .unwrap()
1010 .map(Result::unwrap)
1011 .collect();
1012 assert!(!test_files.is_empty());
1013
1014 #[allow(unused_variables)]
1015 for (index, test_file) in test_files.iter().enumerate() {
1016 let yaml_data = fs::read_to_string(test_file).unwrap();
1017 let test: blob_to_kzg_commitment_test::Test = serde_yaml::from_str(&yaml_data).unwrap();
1018 let Ok(blob) = test.input.get_blob() else {
1019 assert!(test.get_output().is_none());
1020 continue;
1021 };
1022
1023 #[cfg(feature = "generate-fuzz-corpus")]
1024 {
1025 use std::{env, fs::File, io::Write};
1026 let root_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
1027 let dir_path = root_dir
1028 .join("fuzz")
1029 .join("corpus")
1030 .join("fuzz_blob_to_kzg_commitment");
1031 fs::create_dir_all(&dir_path).unwrap();
1032 let file_path = dir_path.join(format!("data_{index}.bin"));
1033 let mut file = File::create(&file_path).unwrap();
1034 file.write_all(&blob.bytes).unwrap();
1035 }
1036
1037 match kzg_settings.blob_to_kzg_commitment(&blob) {
1038 Ok(res) => assert_eq!(res.bytes, test.get_output().unwrap().bytes),
1039 _ => assert!(test.get_output().is_none()),
1040 }
1041 }
1042 }
1043
1044 #[test]
1045 fn test_parse_kzg_trusted_setup() {
1046 let trusted_setup_file = Path::new("src/trusted_setup.txt");
1047 assert!(trusted_setup_file.exists());
1048 let trusted_setup = fs::read_to_string(trusted_setup_file).unwrap();
1049 let _ = KZGSettings::parse_kzg_trusted_setup(&trusted_setup, 0).unwrap();
1050 }
1051
1052 #[test]
1053 fn test_compute_kzg_proof() {
1054 let trusted_setup_file = Path::new("src/trusted_setup.txt");
1055 assert!(trusted_setup_file.exists());
1056 let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file, 0).unwrap();
1057 let test_files: Vec<PathBuf> = glob::glob(COMPUTE_KZG_PROOF_TESTS)
1058 .unwrap()
1059 .map(Result::unwrap)
1060 .collect();
1061 assert!(!test_files.is_empty());
1062
1063 #[allow(unused_variables)]
1064 for (index, test_file) in test_files.iter().enumerate() {
1065 let yaml_data = fs::read_to_string(test_file).unwrap();
1066 let test: compute_kzg_proof::Test = serde_yaml::from_str(&yaml_data).unwrap();
1067 let (Ok(blob), Ok(z)) = (test.input.get_blob(), test.input.get_z()) else {
1068 assert!(test.get_output().is_none());
1069 continue;
1070 };
1071
1072 #[cfg(feature = "generate-fuzz-corpus")]
1073 {
1074 use std::{env, fs::File, io::Write};
1075 let root_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
1076 let dir_path = root_dir
1077 .join("fuzz")
1078 .join("corpus")
1079 .join("fuzz_compute_kzg_proof");
1080 fs::create_dir_all(&dir_path).unwrap();
1081 let file_path = dir_path.join(format!("data_{index}.bin"));
1082 let mut file = File::create(&file_path).unwrap();
1083 file.write_all(&blob.bytes).unwrap();
1084 file.write_all(&z.bytes).unwrap();
1085 }
1086
1087 match kzg_settings.compute_kzg_proof(&blob, &z) {
1088 Ok((proof, y)) => {
1089 assert_eq!(proof.bytes, test.get_output().unwrap().0.bytes);
1090 assert_eq!(y.bytes, test.get_output().unwrap().1.bytes);
1091 }
1092 _ => assert!(test.get_output().is_none()),
1093 }
1094 }
1095 }
1096
1097 #[test]
1098 fn test_compute_blob_kzg_proof() {
1099 let trusted_setup_file = Path::new("src/trusted_setup.txt");
1100 assert!(trusted_setup_file.exists());
1101 let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file, 0).unwrap();
1102 let test_files: Vec<PathBuf> = glob::glob(COMPUTE_BLOB_KZG_PROOF_TESTS)
1103 .unwrap()
1104 .map(Result::unwrap)
1105 .collect();
1106 assert!(!test_files.is_empty());
1107
1108 #[allow(unused_variables)]
1109 for (index, test_file) in test_files.iter().enumerate() {
1110 let yaml_data = fs::read_to_string(test_file).unwrap();
1111 let test: compute_blob_kzg_proof::Test = serde_yaml::from_str(&yaml_data).unwrap();
1112 let (Ok(blob), Ok(commitment)) = (test.input.get_blob(), test.input.get_commitment())
1113 else {
1114 assert!(test.get_output().is_none());
1115 continue;
1116 };
1117
1118 #[cfg(feature = "generate-fuzz-corpus")]
1119 {
1120 use std::{env, fs::File, io::Write};
1121 let root_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
1122 let dir_path = root_dir
1123 .join("fuzz")
1124 .join("corpus")
1125 .join("fuzz_compute_blob_kzg_proof");
1126 fs::create_dir_all(&dir_path).unwrap();
1127 let file_path = dir_path.join(format!("data_{index}.bin"));
1128 let mut file = File::create(&file_path).unwrap();
1129 file.write_all(&blob.bytes).unwrap();
1130 file.write_all(&commitment.bytes).unwrap();
1131 }
1132
1133 match kzg_settings.compute_blob_kzg_proof(&blob, &commitment) {
1134 Ok(res) => assert_eq!(res.bytes, test.get_output().unwrap().bytes),
1135 _ => assert!(test.get_output().is_none()),
1136 }
1137 }
1138 }
1139
1140 #[test]
1141 fn test_verify_kzg_proof() {
1142 let trusted_setup_file = Path::new("src/trusted_setup.txt");
1143 assert!(trusted_setup_file.exists());
1144 let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file, 0).unwrap();
1145 let test_files: Vec<PathBuf> = glob::glob(VERIFY_KZG_PROOF_TESTS)
1146 .unwrap()
1147 .map(Result::unwrap)
1148 .collect();
1149 assert!(!test_files.is_empty());
1150
1151 #[allow(unused_variables)]
1152 for (index, test_file) in test_files.iter().enumerate() {
1153 let yaml_data = fs::read_to_string(test_file).unwrap();
1154 let test: verify_kzg_proof::Test = serde_yaml::from_str(&yaml_data).unwrap();
1155 let (Ok(commitment), Ok(z), Ok(y), Ok(proof)) = (
1156 test.input.get_commitment(),
1157 test.input.get_z(),
1158 test.input.get_y(),
1159 test.input.get_proof(),
1160 ) else {
1161 assert!(test.get_output().is_none());
1162 continue;
1163 };
1164
1165 #[cfg(feature = "generate-fuzz-corpus")]
1166 {
1167 use std::{env, fs::File, io::Write};
1168 let root_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
1169 let dir_path = root_dir
1170 .join("fuzz")
1171 .join("corpus")
1172 .join("fuzz_verify_kzg_proof");
1173 fs::create_dir_all(&dir_path).unwrap();
1174 let file_path = dir_path.join(format!("data_{index}.bin"));
1175 let mut file = File::create(&file_path).unwrap();
1176 file.write_all(&commitment.bytes).unwrap();
1177 file.write_all(&z.bytes).unwrap();
1178 file.write_all(&y.bytes).unwrap();
1179 file.write_all(&proof.bytes).unwrap();
1180 }
1181
1182 match kzg_settings.verify_kzg_proof(&commitment, &z, &y, &proof) {
1183 Ok(res) => assert_eq!(res, test.get_output().unwrap()),
1184 _ => assert!(test.get_output().is_none()),
1185 }
1186 }
1187 }
1188
1189 #[test]
1190 fn test_verify_blob_kzg_proof() {
1191 let trusted_setup_file = Path::new("src/trusted_setup.txt");
1192 assert!(trusted_setup_file.exists());
1193 let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file, 0).unwrap();
1194 let test_files: Vec<PathBuf> = glob::glob(VERIFY_BLOB_KZG_PROOF_TESTS)
1195 .unwrap()
1196 .map(Result::unwrap)
1197 .collect();
1198 assert!(!test_files.is_empty());
1199
1200 #[allow(unused_variables)]
1201 for (index, test_file) in test_files.iter().enumerate() {
1202 let yaml_data = fs::read_to_string(test_file).unwrap();
1203 let test: verify_blob_kzg_proof::Test = serde_yaml::from_str(&yaml_data).unwrap();
1204 let (Ok(blob), Ok(commitment), Ok(proof)) = (
1205 test.input.get_blob(),
1206 test.input.get_commitment(),
1207 test.input.get_proof(),
1208 ) else {
1209 assert!(test.get_output().is_none());
1210 continue;
1211 };
1212
1213 #[cfg(feature = "generate-fuzz-corpus")]
1214 {
1215 use std::{env, fs::File, io::Write};
1216 let root_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
1217 let dir_path = root_dir
1218 .join("fuzz")
1219 .join("corpus")
1220 .join("fuzz_verify_blob_kzg_proof");
1221 fs::create_dir_all(&dir_path).unwrap();
1222 let file_path = dir_path.join(format!("data_{index}.bin"));
1223 let mut file = File::create(&file_path).unwrap();
1224 file.write_all(&blob.bytes).unwrap();
1225 file.write_all(&commitment.bytes).unwrap();
1226 file.write_all(&proof.bytes).unwrap();
1227 }
1228
1229 match kzg_settings.verify_blob_kzg_proof(&blob, &commitment, &proof) {
1230 Ok(res) => assert_eq!(res, test.get_output().unwrap()),
1231 _ => assert!(test.get_output().is_none()),
1232 }
1233 }
1234 }
1235
1236 #[test]
1237 fn test_verify_blob_kzg_proof_batch() {
1238 let trusted_setup_file = Path::new("src/trusted_setup.txt");
1239 assert!(trusted_setup_file.exists());
1240 let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file, 0).unwrap();
1241 let test_files: Vec<PathBuf> = glob::glob(VERIFY_BLOB_KZG_PROOF_BATCH_TESTS)
1242 .unwrap()
1243 .map(Result::unwrap)
1244 .collect();
1245 assert!(!test_files.is_empty());
1246
1247 #[allow(unused_variables)]
1248 for (index, test_file) in test_files.iter().enumerate() {
1249 let yaml_data = fs::read_to_string(test_file).unwrap();
1250 let test: verify_blob_kzg_proof_batch::Test = serde_yaml::from_str(&yaml_data).unwrap();
1251 let (Ok(blobs), Ok(commitments), Ok(proofs)) = (
1252 test.input.get_blobs(),
1253 test.input.get_commitments(),
1254 test.input.get_proofs(),
1255 ) else {
1256 assert!(test.get_output().is_none());
1257 continue;
1258 };
1259
1260 #[cfg(feature = "generate-fuzz-corpus")]
1261 {
1262 use std::{env, fs::File, io::Write};
1263 let root_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
1264 let dir_path = root_dir
1265 .join("fuzz")
1266 .join("corpus")
1267 .join("fuzz_verify_blob_kzg_proof_batch");
1268 fs::create_dir_all(&dir_path).unwrap();
1269 let file_path = dir_path.join(format!("data_{index}.bin"));
1270 let mut file = File::create(&file_path).unwrap();
1271 for blob in &blobs {
1272 file.write_all(&blob.bytes).unwrap();
1273 }
1274 for commitment in &commitments {
1275 file.write_all(&commitment.bytes).unwrap();
1276 }
1277 for proof in &proofs {
1278 file.write_all(&proof.bytes).unwrap();
1279 }
1280 }
1281
1282 match kzg_settings.verify_blob_kzg_proof_batch(&blobs, &commitments, &proofs) {
1283 Ok(res) => assert_eq!(res, test.get_output().unwrap()),
1284 _ => assert!(test.get_output().is_none()),
1285 }
1286 }
1287 }
1288
1289 #[test]
1290 fn test_compute_cells() {
1291 let trusted_setup_file = Path::new("src/trusted_setup.txt");
1292 assert!(trusted_setup_file.exists());
1293 let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file, 0).unwrap();
1294 let test_files: Vec<PathBuf> = glob::glob(COMPUTE_CELLS_TESTS)
1295 .unwrap()
1296 .map(Result::unwrap)
1297 .collect();
1298 assert!(!test_files.is_empty());
1299
1300 #[allow(unused_variables)]
1301 for (index, test_file) in test_files.iter().enumerate() {
1302 let yaml_data = fs::read_to_string(test_file).unwrap();
1303 let test: compute_cells::Test = serde_yaml::from_str(&yaml_data).unwrap();
1304 let Ok(blob) = test.input.get_blob() else {
1305 assert!(test.get_output().is_none());
1306 continue;
1307 };
1308
1309 #[cfg(feature = "generate-fuzz-corpus")]
1310 {
1311 use std::{env, fs::File, io::Write};
1312 let root_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
1313 let dir_path = root_dir
1314 .join("fuzz")
1315 .join("corpus")
1316 .join("fuzz_compute_cells");
1317 fs::create_dir_all(&dir_path).unwrap();
1318 let file_path = dir_path.join(format!("data_{index}.bin"));
1319 let mut file = File::create(&file_path).unwrap();
1320 file.write_all(&blob.bytes).unwrap();
1321 }
1322
1323 match kzg_settings.compute_cells(&blob) {
1324 Ok(res) => assert_eq!(res.as_slice(), test.get_output().unwrap()),
1325 _ => assert!(test.get_output().is_none()),
1326 }
1327 }
1328 }
1329
1330 #[test]
1331 fn test_compute_cells_and_kzg_proofs() {
1332 let trusted_setup_file = Path::new("src/trusted_setup.txt");
1333 assert!(trusted_setup_file.exists());
1334 let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file, 0).unwrap();
1335 let test_files: Vec<PathBuf> = glob::glob(COMPUTE_CELLS_AND_KZG_PROOFS_TESTS)
1336 .unwrap()
1337 .map(Result::unwrap)
1338 .collect();
1339 assert!(!test_files.is_empty());
1340
1341 #[allow(unused_variables)]
1342 for (index, test_file) in test_files.iter().enumerate() {
1343 let yaml_data = fs::read_to_string(test_file).unwrap();
1344 let test: compute_cells_and_kzg_proofs::Test =
1345 serde_yaml::from_str(&yaml_data).unwrap();
1346 let Ok(blob) = test.input.get_blob() else {
1347 assert!(test.get_output().is_none());
1348 continue;
1349 };
1350
1351 #[cfg(feature = "generate-fuzz-corpus")]
1352 {
1353 use std::{env, fs::File, io::Write};
1354 let root_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
1355 let dir_path = root_dir
1356 .join("fuzz")
1357 .join("corpus")
1358 .join("fuzz_compute_cells_and_kzg_proofs");
1359 fs::create_dir_all(&dir_path).unwrap();
1360 let file_path = dir_path.join(format!("data_{index}.bin"));
1361 let mut file = File::create(&file_path).unwrap();
1362 file.write_all(&blob.bytes).unwrap();
1363 }
1364
1365 match kzg_settings.compute_cells_and_kzg_proofs(&blob) {
1366 Ok((cells, proofs)) => {
1367 let (expected_cells, expected_proofs) = test.get_output().unwrap();
1368 assert_eq!(cells.as_slice(), expected_cells);
1369 let proofs_as_bytes: Vec<Bytes48> =
1370 proofs.iter().map(|p| p.to_bytes()).collect();
1371 assert_eq!(proofs_as_bytes, expected_proofs);
1372 }
1373 _ => assert!(test.get_output().is_none()),
1374 }
1375 }
1376 }
1377
1378 #[test]
1379 fn test_recover_cells_and_kzg_proofs() {
1380 let trusted_setup_file = Path::new("src/trusted_setup.txt");
1381 assert!(trusted_setup_file.exists());
1382 let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file, 0).unwrap();
1383 let test_files: Vec<PathBuf> = glob::glob(RECOVER_CELLS_AND_KZG_PROOFS_TESTS)
1384 .unwrap()
1385 .map(Result::unwrap)
1386 .collect();
1387 assert!(!test_files.is_empty());
1388
1389 #[allow(unused_variables)]
1390 for (index, test_file) in test_files.iter().enumerate() {
1391 let yaml_data = fs::read_to_string(test_file).unwrap();
1392 let test: recover_cells_and_kzg_proofs::Test =
1393 serde_yaml::from_str(&yaml_data).unwrap();
1394 let (Ok(cell_indices), Ok(cells)) =
1395 (test.input.get_cell_indices(), test.input.get_cells())
1396 else {
1397 assert!(test.get_output().is_none());
1398 continue;
1399 };
1400
1401 #[cfg(feature = "generate-fuzz-corpus")]
1402 {
1403 use std::{env, fs::File, io::Write};
1404 let root_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
1405 let dir_path = root_dir
1406 .join("fuzz")
1407 .join("corpus")
1408 .join("fuzz_recover_cells_and_kzg_proofs");
1409 fs::create_dir_all(&dir_path).unwrap();
1410 let file_path = dir_path.join(format!("data_{index}.bin"));
1411 let mut file = File::create(&file_path).unwrap();
1412 for cell_index in &cell_indices {
1413 file.write_all(&cell_index.to_le_bytes()).unwrap();
1414 }
1415 for cell in &cells {
1416 file.write_all(&cell.bytes).unwrap();
1417 }
1418 }
1419
1420 match kzg_settings.recover_cells_and_kzg_proofs(&cell_indices, &cells) {
1421 Ok((recovered_cells, recovered_proofs)) => {
1422 let (expected_cells, expected_proofs) = test.get_output().unwrap();
1423 assert_eq!(recovered_cells.as_slice(), expected_cells);
1424 let proofs_as_bytes: Vec<Bytes48> =
1425 recovered_proofs.iter().map(|p| p.to_bytes()).collect();
1426 assert_eq!(proofs_as_bytes, expected_proofs);
1427 }
1428 _ => assert!(test.get_output().is_none()),
1429 }
1430 }
1431 }
1432
1433 #[test]
1434 fn test_verify_cell_kzg_proof_batch() {
1435 let trusted_setup_file = Path::new("src/trusted_setup.txt");
1436 assert!(trusted_setup_file.exists());
1437 let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file, 0).unwrap();
1438 let test_files: Vec<PathBuf> = glob::glob(VERIFY_CELL_KZG_PROOF_BATCH_TESTS)
1439 .unwrap()
1440 .map(Result::unwrap)
1441 .collect();
1442 assert!(!test_files.is_empty());
1443
1444 #[allow(unused_variables)]
1445 for (index, test_file) in test_files.iter().enumerate() {
1446 let yaml_data = fs::read_to_string(test_file).unwrap();
1447 let test: verify_cell_kzg_proof_batch::Test = serde_yaml::from_str(&yaml_data).unwrap();
1448 let (Ok(commitments), Ok(cell_indices), Ok(cells), Ok(proofs)) = (
1449 test.input.get_commitments(),
1450 test.input.get_cell_indices(),
1451 test.input.get_cells(),
1452 test.input.get_proofs(),
1453 ) else {
1454 assert!(test.get_output().is_none());
1455 continue;
1456 };
1457
1458 #[cfg(feature = "generate-fuzz-corpus")]
1459 {
1460 use std::{env, fs::File, io::Write};
1461 let root_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
1462 let dir_path = root_dir
1463 .join("fuzz")
1464 .join("corpus")
1465 .join("fuzz_verify_cell_kzg_proof_batch");
1466 fs::create_dir_all(&dir_path).unwrap();
1467 let file_path = dir_path.join(format!("data_{index}.bin"));
1468 let mut file = File::create(&file_path).unwrap();
1469 for commitment in &commitments {
1470 file.write_all(&commitment.bytes).unwrap();
1471 }
1472 for cell_index in &cell_indices {
1473 file.write_all(&cell_index.to_le_bytes()).unwrap();
1474 }
1475 for cell in &cells {
1476 file.write_all(&cell.bytes).unwrap();
1477 }
1478 for proof in &proofs {
1479 file.write_all(&proof.bytes).unwrap();
1480 }
1481 }
1482
1483 match kzg_settings.verify_cell_kzg_proof_batch(
1484 &commitments,
1485 &cell_indices,
1486 &cells,
1487 &proofs,
1488 ) {
1489 Ok(res) => assert_eq!(res, test.get_output().unwrap()),
1490 _ => assert!(test.get_output().is_none()),
1491 }
1492 }
1493 }
1494}