1#![allow(non_camel_case_types, non_snake_case, non_upper_case_globals)]
2
3#[cfg(feature = "serde")]
4mod serde;
5#[cfg(test)]
6mod test_formats;
7
8include!("./generated.rs");
9
10use alloc::string::String;
11use alloc::vec::Vec;
12use core::ffi::CStr;
13use core::fmt;
14use core::mem::MaybeUninit;
15use core::ops::{Deref, DerefMut};
16
17#[cfg(feature = "std")]
18use alloc::ffi::CString;
19#[cfg(feature = "std")]
20use std::path::Path;
21
22pub const BYTES_PER_G1_POINT: usize = 48;
23pub const BYTES_PER_G2_POINT: usize = 96;
24
25pub const NUM_G1_POINTS: usize = 4096;
27
28pub const NUM_G2_POINTS: usize = 65;
31
32#[repr(C)]
37pub struct KZGCommitment {
38 bytes: [u8; BYTES_PER_COMMITMENT],
39}
40
41#[repr(C)]
46pub struct KZGProof {
47 bytes: [u8; BYTES_PER_PROOF],
48}
49
50#[derive(Debug)]
51pub enum Error {
52 InvalidBytesLength(String),
54 InvalidHexFormat(String),
56 InvalidKzgProof(String),
58 InvalidKzgCommitment(String),
60 InvalidTrustedSetup(String),
62 MismatchLength(String),
64 LoadingTrustedSetupFailed(KzgErrors),
66 CError(C_KZG_RET),
68}
69
70#[cfg(feature = "std")]
71impl std::error::Error for Error {}
72
73impl fmt::Display for Error {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75 match self {
76 Self::InvalidBytesLength(s)
77 | Self::InvalidHexFormat(s)
78 | Self::InvalidKzgProof(s)
79 | Self::InvalidKzgCommitment(s)
80 | Self::InvalidTrustedSetup(s)
81 | Self::MismatchLength(s) => f.write_str(s),
82 Self::LoadingTrustedSetupFailed(s) => write!(f, "KzgErrors: {:?}", s),
83 Self::CError(s) => fmt::Debug::fmt(s, f),
84 }
85 }
86}
87
88impl From<KzgErrors> for Error {
89 fn from(e: KzgErrors) -> Self {
90 Error::LoadingTrustedSetupFailed(e)
91 }
92}
93
94#[derive(Debug)]
95pub enum KzgErrors {
96 FailedCurrentDirectory,
98 PathNotExists,
100 IOError,
102 NotValidFile,
104 FileFormatError,
106 ParseError,
108 MismatchedNumberOfPoints,
110}
111
112pub fn hex_to_bytes(hex_str: &str) -> Result<Vec<u8>, Error> {
114 let trimmed_str = hex_str.strip_prefix("0x").unwrap_or(hex_str);
115 hex::decode(trimmed_str)
116 .map_err(|e| Error::InvalidHexFormat(format!("Failed to decode hex: {}", e)))
117}
118
119impl KZGSettings {
121 pub fn load_trusted_setup(
124 g1_bytes: &[[u8; BYTES_PER_G1_POINT]],
125 g2_bytes: &[[u8; BYTES_PER_G2_POINT]],
126 ) -> Result<Self, Error> {
127 if g1_bytes.len() != FIELD_ELEMENTS_PER_BLOB {
128 return Err(Error::InvalidTrustedSetup(format!(
129 "Invalid number of g1 points in trusted setup. Expected {} got {}",
130 FIELD_ELEMENTS_PER_BLOB,
131 g1_bytes.len()
132 )));
133 }
134 if g2_bytes.len() != NUM_G2_POINTS {
135 return Err(Error::InvalidTrustedSetup(format!(
136 "Invalid number of g2 points in trusted setup. Expected {} got {}",
137 NUM_G2_POINTS,
138 g2_bytes.len()
139 )));
140 }
141 let mut kzg_settings = MaybeUninit::<KZGSettings>::uninit();
142 unsafe {
143 let res = load_trusted_setup(
144 kzg_settings.as_mut_ptr(),
145 g1_bytes.as_ptr().cast(),
146 g1_bytes.len(),
147 g2_bytes.as_ptr().cast(),
148 g2_bytes.len(),
149 );
150 if let C_KZG_RET::C_KZG_OK = res {
151 Ok(kzg_settings.assume_init())
152 } else {
153 Err(Error::InvalidTrustedSetup(format!(
154 "Invalid trusted setup: {res:?}",
155 )))
156 }
157 }
158 }
159
160 #[cfg(feature = "std")]
167 pub fn load_trusted_setup_file(file_path: &Path) -> Result<Self, Error> {
168 #[cfg(unix)]
169 let file_path_bytes = {
170 use std::os::unix::prelude::OsStrExt;
171 file_path.as_os_str().as_bytes()
172 };
173
174 #[cfg(windows)]
175 let file_path_bytes = file_path
176 .as_os_str()
177 .to_str()
178 .ok_or_else(|| Error::InvalidTrustedSetup("Unsupported non unicode file path".into()))?
179 .as_bytes();
180
181 let file_path = CString::new(file_path_bytes)
182 .map_err(|e| Error::InvalidTrustedSetup(format!("Invalid trusted setup file: {e}")))?;
183
184 Self::load_trusted_setup_file_inner(&file_path)
185 }
186
187 pub fn parse_kzg_trusted_setup(trusted_setup: &str) -> Result<Self, Error> {
189 let mut lines = trusted_setup.lines();
190
191 let n_g1 = lines
193 .next()
194 .ok_or(KzgErrors::FileFormatError)?
195 .parse::<usize>()
196 .map_err(|_| KzgErrors::ParseError)?;
197 let n_g2 = lines
198 .next()
199 .ok_or(KzgErrors::FileFormatError)?
200 .parse::<usize>()
201 .map_err(|_| KzgErrors::ParseError)?;
202
203 if n_g1 != NUM_G1_POINTS {
204 return Err(KzgErrors::MismatchedNumberOfPoints.into());
205 }
206
207 if n_g2 != NUM_G2_POINTS {
208 return Err(KzgErrors::MismatchedNumberOfPoints.into());
209 }
210
211 let mut g1_points = alloc::boxed::Box::new([[0; BYTES_PER_G1_POINT]; NUM_G1_POINTS]);
213 for bytes in g1_points.iter_mut() {
214 let line = lines.next().ok_or(KzgErrors::FileFormatError)?;
215 hex::decode_to_slice(line, bytes).map_err(|_| KzgErrors::ParseError)?;
216 }
217
218 let mut g2_points = alloc::boxed::Box::new([[0; BYTES_PER_G2_POINT]; NUM_G2_POINTS]);
220 for bytes in g2_points.iter_mut() {
221 let line = lines.next().ok_or(KzgErrors::FileFormatError)?;
222 hex::decode_to_slice(line, bytes).map_err(|_| KzgErrors::ParseError)?;
223 }
224
225 if lines.next().is_some() {
226 return Err(KzgErrors::FileFormatError.into());
227 }
228
229 Self::load_trusted_setup(g1_points.as_ref(), g2_points.as_ref())
230 }
231
232 #[cfg(not(feature = "std"))]
239 pub fn load_trusted_setup_file(file_path: &CStr) -> Result<Self, Error> {
240 Self::load_trusted_setup_file_inner(file_path)
241 }
242
243 #[cfg_attr(not(feature = "std"), doc = ", but takes a `CStr` instead of a `Path`")]
247 pub fn load_trusted_setup_file_inner(file_path: &CStr) -> Result<Self, Error> {
249 const MODE: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"r\0") };
251
252 let file_ptr = unsafe { libc::fopen(file_path.as_ptr(), MODE.as_ptr()) };
256 if file_ptr.is_null() {
257 #[cfg(not(feature = "std"))]
258 return Err(Error::InvalidTrustedSetup(format!(
259 "Failed to open trusted setup file {file_path:?}"
260 )));
261
262 #[cfg(feature = "std")]
263 return Err(Error::InvalidTrustedSetup(format!(
264 "Failed to open trusted setup file {file_path:?}: {}",
265 std::io::Error::last_os_error()
266 )));
267 }
268 let mut kzg_settings = MaybeUninit::<KZGSettings>::uninit();
269 let result = unsafe {
270 let res = load_trusted_setup_file(kzg_settings.as_mut_ptr(), file_ptr);
271 let _unchecked_close_result = libc::fclose(file_ptr);
272
273 if let C_KZG_RET::C_KZG_OK = res {
274 Ok(kzg_settings.assume_init())
275 } else {
276 Err(Error::InvalidTrustedSetup(format!(
277 "Invalid trusted setup: {res:?}"
278 )))
279 }
280 };
281
282 result
283 }
284}
285
286impl Drop for KZGSettings {
287 fn drop(&mut self) {
288 unsafe { free_trusted_setup(self) }
289 }
290}
291
292impl Blob {
293 pub const fn new(bytes: [u8; BYTES_PER_BLOB]) -> Self {
295 Self { bytes }
296 }
297
298 pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
299 if bytes.len() != BYTES_PER_BLOB {
300 return Err(Error::InvalidBytesLength(format!(
301 "Invalid byte length. Expected {} got {}",
302 BYTES_PER_BLOB,
303 bytes.len(),
304 )));
305 }
306 let mut new_bytes = [0; BYTES_PER_BLOB];
307 new_bytes.copy_from_slice(bytes);
308 Ok(Self::new(new_bytes))
309 }
310
311 pub fn from_hex(hex_str: &str) -> Result<Self, Error> {
312 Self::from_bytes(&hex_to_bytes(hex_str)?)
313 }
314}
315
316impl AsRef<[u8]> for Blob {
317 fn as_ref(&self) -> &[u8] {
318 &self.bytes
319 }
320}
321
322impl Bytes32 {
323 pub const fn new(bytes: [u8; 32]) -> Self {
325 Self { bytes }
326 }
327
328 pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
329 if bytes.len() != 32 {
330 return Err(Error::InvalidBytesLength(format!(
331 "Invalid byte length. Expected {} got {}",
332 32,
333 bytes.len(),
334 )));
335 }
336 let mut new_bytes = [0; 32];
337 new_bytes.copy_from_slice(bytes);
338 Ok(Self::new(new_bytes))
339 }
340
341 pub fn from_hex(hex_str: &str) -> Result<Self, Error> {
342 Self::from_bytes(&hex_to_bytes(hex_str)?)
343 }
344}
345
346impl Bytes48 {
347 pub const fn new(bytes: [u8; 48]) -> Self {
349 Self { bytes }
350 }
351
352 pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
353 if bytes.len() != 48 {
354 return Err(Error::InvalidBytesLength(format!(
355 "Invalid byte length. Expected {} got {}",
356 48,
357 bytes.len(),
358 )));
359 }
360 let mut new_bytes = [0; 48];
361 new_bytes.copy_from_slice(bytes);
362 Ok(Self::new(new_bytes))
363 }
364
365 pub fn from_hex(hex_str: &str) -> Result<Self, Error> {
366 Self::from_bytes(&hex_to_bytes(hex_str)?)
367 }
368
369 pub fn into_inner(self) -> [u8; 48] {
370 self.bytes
371 }
372}
373
374impl KZGProof {
375 pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
376 if bytes.len() != BYTES_PER_PROOF {
377 return Err(Error::InvalidKzgProof(format!(
378 "Invalid byte length. Expected {} got {}",
379 BYTES_PER_PROOF,
380 bytes.len(),
381 )));
382 }
383 let mut proof_bytes = [0; BYTES_PER_PROOF];
384 proof_bytes.copy_from_slice(bytes);
385 Ok(Self { bytes: proof_bytes })
386 }
387
388 pub fn to_bytes(&self) -> Bytes48 {
389 Bytes48 { bytes: self.bytes }
390 }
391
392 pub fn as_hex_string(&self) -> String {
393 hex::encode(self.bytes)
394 }
395
396 pub fn compute_kzg_proof(
397 blob: &Blob,
398 z_bytes: &Bytes32,
399 kzg_settings: &KZGSettings,
400 ) -> Result<(Self, Bytes32), Error> {
401 let mut kzg_proof = MaybeUninit::<KZGProof>::uninit();
402 let mut y_out = MaybeUninit::<Bytes32>::uninit();
403 unsafe {
404 let res = compute_kzg_proof(
405 kzg_proof.as_mut_ptr(),
406 y_out.as_mut_ptr(),
407 blob,
408 z_bytes,
409 kzg_settings,
410 );
411 if let C_KZG_RET::C_KZG_OK = res {
412 Ok((kzg_proof.assume_init(), y_out.assume_init()))
413 } else {
414 Err(Error::CError(res))
415 }
416 }
417 }
418
419 pub fn compute_blob_kzg_proof(
420 blob: &Blob,
421 commitment_bytes: &Bytes48,
422 kzg_settings: &KZGSettings,
423 ) -> Result<Self, Error> {
424 let mut kzg_proof = MaybeUninit::<KZGProof>::uninit();
425 unsafe {
426 let res = compute_blob_kzg_proof(
427 kzg_proof.as_mut_ptr(),
428 blob,
429 commitment_bytes,
430 kzg_settings,
431 );
432 if let C_KZG_RET::C_KZG_OK = res {
433 Ok(kzg_proof.assume_init())
434 } else {
435 Err(Error::CError(res))
436 }
437 }
438 }
439
440 pub fn verify_kzg_proof(
441 commitment_bytes: &Bytes48,
442 z_bytes: &Bytes32,
443 y_bytes: &Bytes32,
444 proof_bytes: &Bytes48,
445 kzg_settings: &KZGSettings,
446 ) -> Result<bool, Error> {
447 let mut verified: MaybeUninit<bool> = MaybeUninit::uninit();
448 unsafe {
449 let res = verify_kzg_proof(
450 verified.as_mut_ptr(),
451 commitment_bytes,
452 z_bytes,
453 y_bytes,
454 proof_bytes,
455 kzg_settings,
456 );
457 if let C_KZG_RET::C_KZG_OK = res {
458 Ok(verified.assume_init())
459 } else {
460 Err(Error::CError(res))
461 }
462 }
463 }
464
465 pub fn verify_blob_kzg_proof(
466 blob: &Blob,
467 commitment_bytes: &Bytes48,
468 proof_bytes: &Bytes48,
469 kzg_settings: &KZGSettings,
470 ) -> Result<bool, Error> {
471 let mut verified: MaybeUninit<bool> = MaybeUninit::uninit();
472 unsafe {
473 let res = verify_blob_kzg_proof(
474 verified.as_mut_ptr(),
475 blob,
476 commitment_bytes,
477 proof_bytes,
478 kzg_settings,
479 );
480 if let C_KZG_RET::C_KZG_OK = res {
481 Ok(verified.assume_init())
482 } else {
483 Err(Error::CError(res))
484 }
485 }
486 }
487
488 pub fn verify_blob_kzg_proof_batch(
489 blobs: &[Blob],
490 commitments_bytes: &[Bytes48],
491 proofs_bytes: &[Bytes48],
492 kzg_settings: &KZGSettings,
493 ) -> Result<bool, Error> {
494 if blobs.len() != commitments_bytes.len() {
495 return Err(Error::MismatchLength(format!(
496 "There are {} blobs and {} commitments",
497 blobs.len(),
498 commitments_bytes.len()
499 )));
500 }
501 if blobs.len() != proofs_bytes.len() {
502 return Err(Error::MismatchLength(format!(
503 "There are {} blobs and {} proofs",
504 blobs.len(),
505 proofs_bytes.len()
506 )));
507 }
508 let mut verified: MaybeUninit<bool> = MaybeUninit::uninit();
509 unsafe {
510 let res = verify_blob_kzg_proof_batch(
511 verified.as_mut_ptr(),
512 blobs.as_ptr(),
513 commitments_bytes.as_ptr(),
514 proofs_bytes.as_ptr(),
515 blobs.len(),
516 kzg_settings,
517 );
518 if let C_KZG_RET::C_KZG_OK = res {
519 Ok(verified.assume_init())
520 } else {
521 Err(Error::CError(res))
522 }
523 }
524 }
525}
526
527impl KZGCommitment {
528 pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
529 if bytes.len() != BYTES_PER_COMMITMENT {
530 return Err(Error::InvalidKzgCommitment(format!(
531 "Invalid byte length. Expected {} got {}",
532 BYTES_PER_PROOF,
533 bytes.len(),
534 )));
535 }
536 let mut commitment = [0; BYTES_PER_COMMITMENT];
537 commitment.copy_from_slice(bytes);
538 Ok(Self { bytes: commitment })
539 }
540
541 pub fn to_bytes(&self) -> Bytes48 {
542 Bytes48 { bytes: self.bytes }
543 }
544
545 pub fn as_hex_string(&self) -> String {
546 hex::encode(self.bytes)
547 }
548
549 pub fn blob_to_kzg_commitment(blob: &Blob, kzg_settings: &KZGSettings) -> Result<Self, Error> {
550 let mut kzg_commitment: MaybeUninit<KZGCommitment> = MaybeUninit::uninit();
551 unsafe {
552 let res = blob_to_kzg_commitment(kzg_commitment.as_mut_ptr(), blob, kzg_settings);
553 if let C_KZG_RET::C_KZG_OK = res {
554 Ok(kzg_commitment.assume_init())
555 } else {
556 Err(Error::CError(res))
557 }
558 }
559 }
560}
561
562impl From<[u8; BYTES_PER_COMMITMENT]> for KZGCommitment {
563 fn from(value: [u8; BYTES_PER_COMMITMENT]) -> Self {
564 Self { bytes: value }
565 }
566}
567
568impl From<[u8; BYTES_PER_PROOF]> for KZGProof {
569 fn from(value: [u8; BYTES_PER_PROOF]) -> Self {
570 Self { bytes: value }
571 }
572}
573
574impl From<[u8; BYTES_PER_BLOB]> for Blob {
575 fn from(value: [u8; BYTES_PER_BLOB]) -> Self {
576 Self { bytes: value }
577 }
578}
579
580impl From<[u8; 32]> for Bytes32 {
581 fn from(value: [u8; 32]) -> Self {
582 Self { bytes: value }
583 }
584}
585
586impl AsRef<[u8; 32]> for Bytes32 {
587 fn as_ref(&self) -> &[u8; 32] {
588 &self.bytes
589 }
590}
591
592impl From<[u8; 48]> for Bytes48 {
593 fn from(value: [u8; 48]) -> Self {
594 Self { bytes: value }
595 }
596}
597
598impl AsRef<[u8; 48]> for Bytes48 {
599 fn as_ref(&self) -> &[u8; 48] {
600 &self.bytes
601 }
602}
603
604impl Deref for Bytes32 {
605 type Target = [u8; 32];
606 fn deref(&self) -> &Self::Target {
607 &self.bytes
608 }
609}
610
611impl Deref for Bytes48 {
612 type Target = [u8; 48];
613 fn deref(&self) -> &Self::Target {
614 &self.bytes
615 }
616}
617
618impl DerefMut for Bytes48 {
619 fn deref_mut(&mut self) -> &mut Self::Target {
620 &mut self.bytes
621 }
622}
623
624impl Deref for Blob {
625 type Target = [u8; BYTES_PER_BLOB];
626 fn deref(&self) -> &Self::Target {
627 &self.bytes
628 }
629}
630
631impl DerefMut for Blob {
632 fn deref_mut(&mut self) -> &mut Self::Target {
633 &mut self.bytes
634 }
635}
636
637impl Clone for Blob {
638 fn clone(&self) -> Self {
639 Blob { bytes: self.bytes }
640 }
641}
642
643impl Deref for KZGProof {
644 type Target = [u8; BYTES_PER_PROOF];
645 fn deref(&self) -> &Self::Target {
646 &self.bytes
647 }
648}
649
650impl Deref for KZGCommitment {
651 type Target = [u8; BYTES_PER_COMMITMENT];
652 fn deref(&self) -> &Self::Target {
653 &self.bytes
654 }
655}
656
657unsafe impl Sync for KZGSettings {}
660unsafe impl Send for KZGSettings {}
661
662#[cfg(test)]
663#[allow(unused_imports, dead_code)]
664mod tests {
665 use super::*;
666 use rand::{rngs::ThreadRng, Rng};
667 use std::{fs, path::PathBuf};
668 use test_formats::{
669 blob_to_kzg_commitment_test, compute_blob_kzg_proof, compute_kzg_proof,
670 verify_blob_kzg_proof, verify_blob_kzg_proof_batch, verify_kzg_proof,
671 };
672
673 fn generate_random_blob(rng: &mut ThreadRng) -> Blob {
674 let mut arr = [0u8; BYTES_PER_BLOB];
675 rng.fill(&mut arr[..]);
676 for i in 0..FIELD_ELEMENTS_PER_BLOB {
679 arr[i * BYTES_PER_FIELD_ELEMENT] = 0;
680 }
681 arr.into()
682 }
683
684 fn test_simple(trusted_setup_file: &Path) {
685 let mut rng = rand::thread_rng();
686 assert!(trusted_setup_file.exists());
687 let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file).unwrap();
688
689 let num_blobs: usize = rng.gen_range(1..16);
690 let mut blobs: Vec<Blob> = (0..num_blobs)
691 .map(|_| generate_random_blob(&mut rng))
692 .collect();
693
694 let commitments: Vec<Bytes48> = blobs
695 .iter()
696 .map(|blob| KZGCommitment::blob_to_kzg_commitment(blob, &kzg_settings).unwrap())
697 .map(|commitment| commitment.to_bytes())
698 .collect();
699
700 let proofs: Vec<Bytes48> = blobs
701 .iter()
702 .zip(commitments.iter())
703 .map(|(blob, commitment)| {
704 KZGProof::compute_blob_kzg_proof(blob, commitment, &kzg_settings).unwrap()
705 })
706 .map(|proof| proof.to_bytes())
707 .collect();
708
709 assert!(KZGProof::verify_blob_kzg_proof_batch(
710 &blobs,
711 &commitments,
712 &proofs,
713 &kzg_settings
714 )
715 .unwrap());
716
717 blobs.pop();
718
719 let error =
720 KZGProof::verify_blob_kzg_proof_batch(&blobs, &commitments, &proofs, &kzg_settings)
721 .unwrap_err();
722 assert!(matches!(error, Error::MismatchLength(_)));
723
724 let incorrect_blob = generate_random_blob(&mut rng);
725 blobs.push(incorrect_blob);
726
727 assert!(!KZGProof::verify_blob_kzg_proof_batch(
728 &blobs,
729 &commitments,
730 &proofs,
731 &kzg_settings
732 )
733 .unwrap());
734 }
735
736 #[test]
737 fn test_end_to_end() {
738 let trusted_setup_file = Path::new("src/trusted_setup.txt");
739 test_simple(trusted_setup_file);
740 }
741
742 const BLOB_TO_KZG_COMMITMENT_TESTS: &str = "tests/blob_to_kzg_commitment/*/*/*";
743 const COMPUTE_KZG_PROOF_TESTS: &str = "tests/compute_kzg_proof/*/*/*";
744 const COMPUTE_BLOB_KZG_PROOF_TESTS: &str = "tests/compute_blob_kzg_proof/*/*/*";
745 const VERIFY_KZG_PROOF_TESTS: &str = "tests/verify_kzg_proof/*/*/*";
746 const VERIFY_BLOB_KZG_PROOF_TESTS: &str = "tests/verify_blob_kzg_proof/*/*/*";
747 const VERIFY_BLOB_KZG_PROOF_BATCH_TESTS: &str = "tests/verify_blob_kzg_proof_batch/*/*/*";
748
749 #[test]
750 fn test_blob_to_kzg_commitment() {
751 let trusted_setup_file = Path::new("src/trusted_setup.txt");
752 assert!(trusted_setup_file.exists());
753 let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file).unwrap();
754 let test_files: Vec<PathBuf> = glob::glob(BLOB_TO_KZG_COMMITMENT_TESTS)
755 .unwrap()
756 .map(Result::unwrap)
757 .collect();
758 assert!(!test_files.is_empty());
759
760 for test_file in test_files {
761 let yaml_data = fs::read_to_string(test_file).unwrap();
762 let test: blob_to_kzg_commitment_test::Test = serde_yaml::from_str(&yaml_data).unwrap();
763 let Ok(blob) = test.input.get_blob() else {
764 assert!(test.get_output().is_none());
765 continue;
766 };
767
768 match KZGCommitment::blob_to_kzg_commitment(&blob, &kzg_settings) {
769 Ok(res) => assert_eq!(res.bytes, test.get_output().unwrap().bytes),
770 _ => assert!(test.get_output().is_none()),
771 }
772 }
773 }
774
775 #[test]
776 fn test_parse_kzg_trusted_setup() {
777 let trusted_setup_file = Path::new("src/trusted_setup.txt");
778 assert!(trusted_setup_file.exists());
779 let trusted_setup = fs::read_to_string(trusted_setup_file).unwrap();
780 let _ = KZGSettings::parse_kzg_trusted_setup(&trusted_setup).unwrap();
781 }
782
783 #[test]
784 fn test_compute_kzg_proof() {
785 let trusted_setup_file = Path::new("src/trusted_setup.txt");
786 assert!(trusted_setup_file.exists());
787 let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file).unwrap();
788 let test_files: Vec<PathBuf> = glob::glob(COMPUTE_KZG_PROOF_TESTS)
789 .unwrap()
790 .map(Result::unwrap)
791 .collect();
792 assert!(!test_files.is_empty());
793
794 for test_file in test_files {
795 let yaml_data = fs::read_to_string(test_file).unwrap();
796 let test: compute_kzg_proof::Test = serde_yaml::from_str(&yaml_data).unwrap();
797 let (Ok(blob), Ok(z)) = (test.input.get_blob(), test.input.get_z()) else {
798 assert!(test.get_output().is_none());
799 continue;
800 };
801
802 match KZGProof::compute_kzg_proof(&blob, &z, &kzg_settings) {
803 Ok((proof, y)) => {
804 assert_eq!(proof.bytes, test.get_output().unwrap().0.bytes);
805 assert_eq!(y.bytes, test.get_output().unwrap().1.bytes);
806 }
807 _ => assert!(test.get_output().is_none()),
808 }
809 }
810 }
811
812 #[test]
813 fn test_compute_blob_kzg_proof() {
814 let trusted_setup_file = Path::new("src/trusted_setup.txt");
815 assert!(trusted_setup_file.exists());
816 let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file).unwrap();
817 let test_files: Vec<PathBuf> = glob::glob(COMPUTE_BLOB_KZG_PROOF_TESTS)
818 .unwrap()
819 .map(Result::unwrap)
820 .collect();
821 assert!(!test_files.is_empty());
822
823 for test_file in test_files {
824 let yaml_data = fs::read_to_string(test_file).unwrap();
825 let test: compute_blob_kzg_proof::Test = serde_yaml::from_str(&yaml_data).unwrap();
826 let (Ok(blob), Ok(commitment)) = (test.input.get_blob(), test.input.get_commitment())
827 else {
828 assert!(test.get_output().is_none());
829 continue;
830 };
831
832 match KZGProof::compute_blob_kzg_proof(&blob, &commitment, &kzg_settings) {
833 Ok(res) => assert_eq!(res.bytes, test.get_output().unwrap().bytes),
834 _ => assert!(test.get_output().is_none()),
835 }
836 }
837 }
838
839 #[test]
840 fn test_verify_kzg_proof() {
841 let trusted_setup_file = Path::new("src/trusted_setup.txt");
842 assert!(trusted_setup_file.exists());
843 let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file).unwrap();
844 let test_files: Vec<PathBuf> = glob::glob(VERIFY_KZG_PROOF_TESTS)
845 .unwrap()
846 .map(Result::unwrap)
847 .collect();
848 assert!(!test_files.is_empty());
849
850 for test_file in test_files {
851 let yaml_data = fs::read_to_string(test_file).unwrap();
852 let test: verify_kzg_proof::Test = serde_yaml::from_str(&yaml_data).unwrap();
853 let (Ok(commitment), Ok(z), Ok(y), Ok(proof)) = (
854 test.input.get_commitment(),
855 test.input.get_z(),
856 test.input.get_y(),
857 test.input.get_proof(),
858 ) else {
859 assert!(test.get_output().is_none());
860 continue;
861 };
862
863 match KZGProof::verify_kzg_proof(&commitment, &z, &y, &proof, &kzg_settings) {
864 Ok(res) => assert_eq!(res, test.get_output().unwrap()),
865 _ => assert!(test.get_output().is_none()),
866 }
867 }
868 }
869
870 #[test]
871 fn test_verify_blob_kzg_proof() {
872 let trusted_setup_file = Path::new("src/trusted_setup.txt");
873 assert!(trusted_setup_file.exists());
874 let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file).unwrap();
875 let test_files: Vec<PathBuf> = glob::glob(VERIFY_BLOB_KZG_PROOF_TESTS)
876 .unwrap()
877 .map(Result::unwrap)
878 .collect();
879 assert!(!test_files.is_empty());
880
881 for test_file in test_files {
882 let yaml_data = fs::read_to_string(test_file).unwrap();
883 let test: verify_blob_kzg_proof::Test = serde_yaml::from_str(&yaml_data).unwrap();
884 let (Ok(blob), Ok(commitment), Ok(proof)) = (
885 test.input.get_blob(),
886 test.input.get_commitment(),
887 test.input.get_proof(),
888 ) else {
889 assert!(test.get_output().is_none());
890 continue;
891 };
892
893 match KZGProof::verify_blob_kzg_proof(&blob, &commitment, &proof, &kzg_settings) {
894 Ok(res) => assert_eq!(res, test.get_output().unwrap()),
895 _ => assert!(test.get_output().is_none()),
896 }
897 }
898 }
899
900 #[test]
901 fn test_verify_blob_kzg_proof_batch() {
902 let trusted_setup_file = Path::new("src/trusted_setup.txt");
903 assert!(trusted_setup_file.exists());
904 let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file).unwrap();
905 let test_files: Vec<PathBuf> = glob::glob(VERIFY_BLOB_KZG_PROOF_BATCH_TESTS)
906 .unwrap()
907 .map(Result::unwrap)
908 .collect();
909 assert!(!test_files.is_empty());
910
911 for test_file in test_files {
912 let yaml_data = fs::read_to_string(test_file).unwrap();
913 let test: verify_blob_kzg_proof_batch::Test = serde_yaml::from_str(&yaml_data).unwrap();
914 let (Ok(blobs), Ok(commitments), Ok(proofs)) = (
915 test.input.get_blobs(),
916 test.input.get_commitments(),
917 test.input.get_proofs(),
918 ) else {
919 assert!(test.get_output().is_none());
920 continue;
921 };
922
923 match KZGProof::verify_blob_kzg_proof_batch(
924 &blobs,
925 &commitments,
926 &proofs,
927 &kzg_settings,
928 ) {
929 Ok(res) => assert_eq!(res, test.get_output().unwrap()),
930 _ => assert!(test.get_output().is_none()),
931 }
932 }
933 }
934}