diff --git a/bindings/rust/.gitignore b/bindings/rust/.gitignore
index 685e955..af69316 100644
--- a/bindings/rust/.gitignore
+++ b/bindings/rust/.gitignore
@@ -1,2 +1,2 @@
-src/consts.rs
+src/bindings/generated.rs
target/
diff --git a/bindings/rust/Cargo.lock b/bindings/rust/Cargo.lock
index 05bc121..b100348 100644
--- a/bindings/rust/Cargo.lock
+++ b/bindings/rust/Cargo.lock
@@ -25,6 +25,27 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+[[package]]
+name = "bindgen"
+version = "0.64.0"
+source = "git+https://github.com/rust-lang/rust-bindgen?rev=0de11f0a521611ac8738b7b01d19dddaf3899e66#0de11f0a521611ac8738b7b01d19dddaf3899e66"
+dependencies = [
+ "bitflags",
+ "cexpr",
+ "clang-sys",
+ "lazy_static",
+ "lazycell",
+ "log",
+ "peeking_take_while",
+ "proc-macro2",
+ "quote",
+ "regex",
+ "rustc-hash",
+ "shlex",
+ "syn 2.0.8",
+ "which",
+]
+
[[package]]
name = "bitflags"
version = "1.3.2"
@@ -33,14 +54,15 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bumpalo"
-version = "3.11.1"
+version = "3.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba"
+checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
[[package]]
name = "c-kzg"
version = "0.1.0"
dependencies = [
+ "bindgen",
"criterion",
"glob",
"hex",
@@ -56,6 +78,15 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
+[[package]]
+name = "cexpr"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
+dependencies = [
+ "nom",
+]
+
[[package]]
name = "cfg-if"
version = "1.0.0"
@@ -89,6 +120,17 @@ dependencies = [
"half",
]
+[[package]]
+name = "clang-sys"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77ed9a53e5d4d9c573ae844bfac6872b159cb1d1585a83b29e7a64b7eef7332a"
+dependencies = [
+ "glob",
+ "libc",
+ "libloading",
+]
+
[[package]]
name = "clap"
version = "3.2.23"
@@ -148,9 +190,9 @@ dependencies = [
[[package]]
name = "crossbeam-channel"
-version = "0.5.6"
+version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521"
+checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c"
dependencies = [
"cfg-if",
"crossbeam-utils",
@@ -158,9 +200,9 @@ dependencies = [
[[package]]
name = "crossbeam-deque"
-version = "0.8.2"
+version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc"
+checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
dependencies = [
"cfg-if",
"crossbeam-epoch",
@@ -169,9 +211,9 @@ dependencies = [
[[package]]
name = "crossbeam-epoch"
-version = "0.9.13"
+version = "0.9.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a"
+checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695"
dependencies = [
"autocfg",
"cfg-if",
@@ -182,18 +224,18 @@ dependencies = [
[[package]]
name = "crossbeam-utils"
-version = "0.8.14"
+version = "0.8.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f"
+checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b"
dependencies = [
"cfg-if",
]
[[package]]
name = "either"
-version = "1.8.0"
+version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
+checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
[[package]]
name = "getrandom"
@@ -269,15 +311,15 @@ dependencies = [
[[package]]
name = "itoa"
-version = "1.0.4"
+version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
+checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
[[package]]
name = "js-sys"
-version = "0.3.60"
+version = "0.3.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47"
+checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730"
dependencies = [
"wasm-bindgen",
]
@@ -289,10 +331,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
-name = "libc"
-version = "0.2.137"
+name = "lazycell"
+version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
+checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
+
+[[package]]
+name = "libc"
+version = "0.2.140"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
+
+[[package]]
+name = "libloading"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
+dependencies = [
+ "cfg-if",
+ "winapi",
+]
[[package]]
name = "log"
@@ -304,14 +362,36 @@ dependencies = [
]
[[package]]
-name = "memoffset"
-version = "0.7.1"
+name = "memchr"
+version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
+checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
+
+[[package]]
+name = "memoffset"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1"
dependencies = [
"autocfg",
]
+[[package]]
+name = "minimal-lexical"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+
+[[package]]
+name = "nom"
+version = "7.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
+dependencies = [
+ "memchr",
+ "minimal-lexical",
+]
+
[[package]]
name = "num-traits"
version = "0.2.15"
@@ -333,9 +413,9 @@ dependencies = [
[[package]]
name = "once_cell"
-version = "1.17.0"
+version = "1.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
+checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
[[package]]
name = "oorandom"
@@ -345,9 +425,15 @@ checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
[[package]]
name = "os_str_bytes"
-version = "6.4.1"
+version = "6.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
+checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267"
+
+[[package]]
+name = "peeking_take_while"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
[[package]]
name = "plotters"
@@ -385,18 +471,18 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro2"
-version = "1.0.49"
+version = "1.0.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5"
+checksum = "ba466839c78239c09faf015484e5cc04860f88242cff4d03eb038f04b4699b73"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
-version = "1.0.23"
+version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
+checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
dependencies = [
"proc-macro2",
]
@@ -433,9 +519,9 @@ dependencies = [
[[package]]
name = "rayon"
-version = "1.6.1"
+version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7"
+checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b"
dependencies = [
"either",
"rayon-core",
@@ -443,9 +529,9 @@ dependencies = [
[[package]]
name = "rayon-core"
-version = "1.10.1"
+version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3"
+checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
@@ -455,24 +541,30 @@ dependencies = [
[[package]]
name = "regex"
-version = "1.7.0"
+version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
+checksum = "cce168fea28d3e05f158bda4576cf0c844d5045bc2cc3620fa0292ed5bb5814c"
dependencies = [
"regex-syntax",
]
[[package]]
name = "regex-syntax"
-version = "0.6.28"
+version = "0.6.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
+checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
+
+[[package]]
+name = "rustc-hash"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "ryu"
-version = "1.0.11"
+version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
+checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
[[package]]
name = "same-file"
@@ -491,29 +583,29 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "serde"
-version = "1.0.150"
+version = "1.0.158"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e326c9ec8042f1b5da33252c8a37e9ffbd2c9bef0155215b6e6c80c790e05f91"
+checksum = "771d4d9c4163ee138805e12c710dd365e4f44be8be0503cb1bb9eb989425d9c9"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.150"
+version = "1.0.158"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42a3df25b0713732468deadad63ab9da1f1fd75a48a15024b50363f128db627e"
+checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad"
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.8",
]
[[package]]
name = "serde_json"
-version = "1.0.89"
+version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db"
+checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea"
dependencies = [
"itoa",
"ryu",
@@ -522,9 +614,9 @@ dependencies = [
[[package]]
name = "serde_yaml"
-version = "0.9.17"
+version = "0.9.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8fb06d4b6cdaef0e0c51fa881acb721bed3c924cfaa71d9c94a3b771dfdf6567"
+checksum = "f82e6c8c047aa50a7328632d067bcae6ef38772a79e28daf32f735e0e4f3dd10"
dependencies = [
"indexmap",
"itoa",
@@ -534,10 +626,27 @@ dependencies = [
]
[[package]]
-name = "syn"
-version = "1.0.107"
+name = "shlex"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
+checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
+
+[[package]]
+name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bcc02725fd69ab9f26eab07fad303e2497fad6fb9eba4f96c4d1687bdf704ad9"
dependencies = [
"proc-macro2",
"quote",
@@ -562,24 +671,23 @@ dependencies = [
[[package]]
name = "unicode-ident"
-version = "1.0.6"
+version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
+checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
[[package]]
name = "unsafe-libyaml"
-version = "0.2.5"
+version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc7ed8ba44ca06be78ea1ad2c3682a43349126c8818054231ee6f4748012aed2"
+checksum = "ad2024452afd3874bf539695e04af6732ba06517424dbf958fdb16a01f3bef6c"
[[package]]
name = "walkdir"
-version = "2.3.2"
+version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
+checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698"
dependencies = [
"same-file",
- "winapi",
"winapi-util",
]
@@ -591,9 +699,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
-version = "0.2.83"
+version = "0.2.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268"
+checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
@@ -601,24 +709,24 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
-version = "0.2.83"
+version = "0.2.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142"
+checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
- "syn",
+ "syn 1.0.109",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
-version = "0.2.83"
+version = "0.2.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810"
+checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -626,33 +734,44 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
-version = "0.2.83"
+version = "0.2.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
+checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6"
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 1.0.109",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
-version = "0.2.83"
+version = "0.2.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f"
+checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
[[package]]
name = "web-sys"
-version = "0.3.60"
+version = "0.3.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f"
+checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97"
dependencies = [
"js-sys",
"wasm-bindgen",
]
+[[package]]
+name = "which"
+version = "4.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269"
+dependencies = [
+ "either",
+ "libc",
+ "once_cell",
+]
+
[[package]]
name = "winapi"
version = "0.3.9"
diff --git a/bindings/rust/Cargo.toml b/bindings/rust/Cargo.toml
index fc48b51..11accb6 100644
--- a/bindings/rust/Cargo.toml
+++ b/bindings/rust/Cargo.toml
@@ -21,6 +21,9 @@ glob = "0.3.1"
rand = "0.8.5"
serde_yaml = "0.9.17"
+[build-dependencies]
+bindgen = { git = "https://github.com/rust-lang/rust-bindgen" , rev = "0de11f0a521611ac8738b7b01d19dddaf3899e66" }
+
[[bench]]
name = "kzg_benches"
-harness = false
\ No newline at end of file
+harness = false
diff --git a/bindings/rust/build.rs b/bindings/rust/build.rs
index 06f341e..a39e0b7 100644
--- a/bindings/rust/build.rs
+++ b/bindings/rust/build.rs
@@ -14,7 +14,8 @@ fn move_file(src: &Path, dst: &Path) -> Result<(), String> {
}
fn main() {
- let root_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()).join("../../");
+ let cargo_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
+ let root_dir = cargo_dir.join("../../");
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
// Ensure libblst exists in `OUT_DIR`
@@ -72,16 +73,17 @@ fn main() {
println!("cargo:rustc-link-lib=static=ckzg");
println!("cargo:rustc-link-lib=static=blst");
- // Write the compile time variable to a consts.rs file to be imported to the bindings module.
- let const_file = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()).join("src/consts.rs");
- std::fs::write(
- const_file,
- format!(
- "pub const FIELD_ELEMENTS_PER_BLOB: usize = {};",
- field_elements_per_blob
- ),
- )
- .unwrap();
+ let bindings_out_path = cargo_dir.join("src/bindings/generated.rs");
+ let build_target = env::var("TARGET").unwrap();
+ let snapshot_path = cargo_dir.join("snapshots").join(format!(
+ "bindings_{build_target}_{field_elements_per_blob}.rs"
+ ));
+ make_bindings(
+ field_elements_per_blob,
+ &root_dir,
+ bindings_out_path,
+ snapshot_path,
+ );
// Cleanup
let obj_file = root_dir.join("src/c_kzg_4844.o");
@@ -89,3 +91,103 @@ fn main() {
std::fs::remove_file(obj_file).unwrap();
}
}
+
+fn make_bindings
(
+ field_elements_per_blob: usize,
+ root_dir: &Path,
+ bindings_out_path: P,
+ snapshot_path: P,
+) where
+ P: AsRef,
+{
+ use bindgen::Builder;
+
+ #[derive(Debug)]
+ struct Callbacks;
+ impl bindgen::callbacks::ParseCallbacks for Callbacks {
+ fn int_macro(&self, name: &str, _value: i64) -> Option {
+ match name {
+ "FIELD_ELEMENTS_PER_BLOB"
+ | "BYTES_PER_COMMITMENT"
+ | "BYTES_PER_PROOF"
+ | "BYTES_PER_FIELD_ELEMENT"
+ | "BYTES_PER_BLOB" => Some(bindgen::callbacks::IntKind::Custom {
+ name: "usize",
+ is_signed: false,
+ }),
+ _ => None,
+ }
+ }
+ }
+
+ let header_file_path = root_dir.join("src/c_kzg_4844.h");
+ let header_file = header_file_path.to_str().expect("valid header file");
+
+ let inc_dir_path = root_dir.join("inc");
+ let inc_dir = inc_dir_path.to_str().expect("valid inc dir");
+
+ let bindings = Builder::default()
+ /*
+ * Header definitions.
+ */
+ // Inject the constant as C code so that the C compiler can use it.
+ // -D is not supported by bindgen https://github.com/rust-lang/rust-bindgen/issues/2394
+ .header_contents(
+ "consts",
+ &format!("#define FIELD_ELEMENTS_PER_BLOB {field_elements_per_blob}"),
+ )
+ .header(header_file)
+ .clang_args([format!("-I{inc_dir}")])
+ // Since this is not part of the header file, needs to be allowed explicitly.
+ .allowlist_var("FIELD_ELEMENTS_PER_BLOB")
+ // Get bindings only for the header file.
+ .allowlist_file(".*/c_kzg_4844.h")
+ /*
+ * Cleanup instructions.
+ */
+ // Remove stdio definitions related to FILE.
+ .opaque_type("FILE")
+ // Remove the definition of FILE to use the libc one, which is more convenient.
+ .blocklist_type("FILE")
+ // Inject rust code using libc's FILE
+ .raw_line("use libc::FILE;")
+ // Do no generate layout tests.
+ .layout_tests(false)
+ // Extern functions do not need individual extern blocks.
+ .merge_extern_blocks(true)
+ // We implement Drop for this type. Copy is not allowed for types with destructors.
+ .no_copy("KZGSettings")
+ /*
+ * API improvements.
+ */
+ // Do not create individual constants for enum variants.
+ .rustified_enum("C_KZG_RET")
+ // Make constants used as sizes `usize`.
+ .parse_callbacks(Box::new(Callbacks))
+ // Add PartialEq and Eq impls to types.
+ .derive_eq(true)
+ // Blobs are big, we don't want rust to liberally copy them around.
+ .no_copy("Blob")
+ // Do not make fields public. If we want to modify them we can create setters/mutable
+ // getters when necessary.
+ .default_visibility(bindgen::FieldVisibilityKind::Private)
+ // Blocklist this type alias to use a custom implementation. If this stops being a type
+ // alias this line needs to be removed.
+ .blocklist_type("KZGCommitment")
+ // Blocklist this type alias to use a custom implementation. If this stops being a type
+ // alias this line needs to be removed.
+ .blocklist_type("KZGProof")
+ /*
+ * Re-build instructions
+ */
+ .parse_callbacks(Box::new(bindgen::CargoCallbacks))
+ .generate()
+ .unwrap();
+
+ bindings
+ .write_to_file(bindings_out_path)
+ .expect("Failed to write bindings");
+ bindings
+ .write_to_file(snapshot_path)
+ .expect("Failed to write snapshot");
+}
diff --git a/bindings/rust/snapshots/bindings_x86_64-unknown-linux-gnu_4096.rs b/bindings/rust/snapshots/bindings_x86_64-unknown-linux-gnu_4096.rs
new file mode 100644
index 0000000..1c62647
--- /dev/null
+++ b/bindings/rust/snapshots/bindings_x86_64-unknown-linux-gnu_4096.rs
@@ -0,0 +1,149 @@
+/* automatically generated by rust-bindgen 0.64.0 */
+
+use libc::FILE;
+
+pub const FIELD_ELEMENTS_PER_BLOB: usize = 4096;
+pub const BYTES_PER_COMMITMENT: usize = 48;
+pub const BYTES_PER_PROOF: usize = 48;
+pub const BYTES_PER_FIELD_ELEMENT: usize = 32;
+pub const BYTES_PER_BLOB: usize = 131072;
+pub type limb_t = u64;
+#[repr(C)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct blst_fr {
+ l: [limb_t; 4usize],
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct blst_fp {
+ l: [limb_t; 6usize],
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct blst_fp2 {
+ fp: [blst_fp; 2usize],
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct blst_p1 {
+ x: blst_fp,
+ y: blst_fp,
+ z: blst_fp,
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct blst_p2 {
+ x: blst_fp2,
+ y: blst_fp2,
+ z: blst_fp2,
+}
+pub type g1_t = blst_p1;
+pub type g2_t = blst_p2;
+pub type fr_t = blst_fr;
+#[doc = " An array of 32 bytes. Represents an untrusted\n (potentially invalid) field element."]
+#[repr(C)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct Bytes32 {
+ bytes: [u8; 32usize],
+}
+#[doc = " An array of 48 bytes. Represents an untrusted\n (potentially invalid) commitment/proof."]
+#[repr(C)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct Bytes48 {
+ bytes: [u8; 48usize],
+}
+#[doc = " A basic blob data."]
+#[repr(C)]
+#[derive(Debug, PartialEq, Eq)]
+pub struct Blob {
+ bytes: [u8; 131072usize],
+}
+#[repr(u32)]
+#[doc = " The common return type for all routines in which something can go wrong."]
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub enum C_KZG_RET {
+ #[doc = "< Success!"]
+ C_KZG_OK = 0,
+ #[doc = "< The supplied data is invalid in some way."]
+ C_KZG_BADARGS = 1,
+ #[doc = "< Internal error - this should never occur."]
+ C_KZG_ERROR = 2,
+ #[doc = "< Could not allocate memory."]
+ C_KZG_MALLOC = 3,
+}
+#[doc = " Stores the setup and parameters needed for performing FFTs."]
+#[repr(C)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct FFTSettings {
+ #[doc = " The maximum size of FFT these settings support, a power of 2."]
+ max_width: u64,
+ #[doc = " Ascending powers of the root of unity, length `max_width + 1`."]
+ expanded_roots_of_unity: *mut fr_t,
+ #[doc = " Descending powers of the root of unity, length `max_width + 1`."]
+ reverse_roots_of_unity: *mut fr_t,
+ #[doc = " Powers of the root of unity in bit-reversal permutation order, length\n `max_width`."]
+ roots_of_unity: *mut fr_t,
+}
+#[doc = " Stores the setup and parameters needed for computing KZG proofs."]
+#[repr(C)]
+#[derive(Debug, PartialEq, Eq)]
+pub struct KZGSettings {
+ #[doc = " The corresponding settings for performing FFTs."]
+ fs: *mut FFTSettings,
+ #[doc = " G1 group elements from the trusted setup,\n in Lagrange form bit-reversal permutation."]
+ g1_values: *mut g1_t,
+ #[doc = " G2 group elements from the trusted setup;\n both arrays have `FIELD_ELEMENTS_PER_BLOB` elements."]
+ g2_values: *mut g2_t,
+}
+extern "C" {
+ pub fn load_trusted_setup(
+ out: *mut KZGSettings,
+ g1_bytes: *const u8,
+ n1: usize,
+ g2_bytes: *const u8,
+ n2: usize,
+ ) -> C_KZG_RET;
+ pub fn load_trusted_setup_file(out: *mut KZGSettings, in_: *mut FILE) -> C_KZG_RET;
+ pub fn free_trusted_setup(s: *mut KZGSettings);
+ pub fn blob_to_kzg_commitment(
+ out: *mut KZGCommitment,
+ blob: *const Blob,
+ s: *const KZGSettings,
+ ) -> C_KZG_RET;
+ pub fn compute_kzg_proof(
+ proof_out: *mut KZGProof,
+ y_out: *mut Bytes32,
+ blob: *const Blob,
+ z_bytes: *const Bytes32,
+ s: *const KZGSettings,
+ ) -> C_KZG_RET;
+ pub fn compute_blob_kzg_proof(
+ out: *mut KZGProof,
+ blob: *const Blob,
+ commitment_bytes: *const Bytes48,
+ s: *const KZGSettings,
+ ) -> C_KZG_RET;
+ pub fn verify_kzg_proof(
+ ok: *mut bool,
+ commitment_bytes: *const Bytes48,
+ z_bytes: *const Bytes32,
+ y_bytes: *const Bytes32,
+ proof_bytes: *const Bytes48,
+ s: *const KZGSettings,
+ ) -> C_KZG_RET;
+ pub fn verify_blob_kzg_proof(
+ ok: *mut bool,
+ blob: *const Blob,
+ commitment_bytes: *const Bytes48,
+ proof_bytes: *const Bytes48,
+ s: *const KZGSettings,
+ ) -> C_KZG_RET;
+ pub fn verify_blob_kzg_proof_batch(
+ ok: *mut bool,
+ blobs: *const Blob,
+ commitments_bytes: *const Bytes48,
+ proofs_bytes: *const Bytes48,
+ n: usize,
+ s: *const KZGSettings,
+ ) -> C_KZG_RET;
+}
diff --git a/bindings/rust/src/bindings.rs b/bindings/rust/src/bindings.rs
deleted file mode 100644
index 7e3bb18..0000000
--- a/bindings/rust/src/bindings.rs
+++ /dev/null
@@ -1,262 +0,0 @@
-/* automatically generated by rust-bindgen 0.61.0 */
-
-include!("./consts.rs");
-
-use std::ops::{Deref, DerefMut};
-
-use libc::FILE;
-
-pub const BYTES_PER_COMMITMENT: usize = 48;
-pub const BYTES_PER_PROOF: usize = 48;
-pub const BYTES_PER_FIELD_ELEMENT: usize = 32;
-pub const BYTES_PER_BLOB: usize = FIELD_ELEMENTS_PER_BLOB * BYTES_PER_FIELD_ELEMENT;
-
-type byte = u8;
-type limb_t = u64;
-#[repr(C)]
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-struct blst_scalar {
- b: [byte; 32usize],
-}
-
-#[repr(C)]
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-struct blst_fr {
- l: [limb_t; 4usize],
-}
-
-#[repr(C)]
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-struct blst_fp {
- l: [limb_t; 6usize],
-}
-
-#[repr(C)]
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-struct blst_fp2 {
- fp: [blst_fp; 2usize],
-}
-
-#[repr(C)]
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-struct blst_fp6 {
- fp2: [blst_fp2; 3usize],
-}
-
-#[repr(C)]
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-struct blst_fp12 {
- fp6: [blst_fp6; 2usize],
-}
-
-#[repr(C)]
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-struct blst_p1 {
- x: blst_fp,
- y: blst_fp,
- z: blst_fp,
-}
-
-#[repr(C)]
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-struct blst_p1_affine {
- x: blst_fp,
- y: blst_fp,
-}
-
-#[repr(C)]
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-struct blst_p2 {
- x: blst_fp2,
- y: blst_fp2,
- z: blst_fp2,
-}
-
-#[repr(C)]
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-struct blst_p2_affine {
- x: blst_fp2,
- y: blst_fp2,
-}
-
-#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct Bytes32 {
- bytes: [u8; 32],
-}
-
-impl Deref for Bytes32 {
- type Target = [u8; 32];
- fn deref(&self) -> &Self::Target {
- &self.bytes
- }
-}
-
-#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct Bytes48 {
- bytes: [u8; 48],
-}
-
-impl Deref for Bytes48 {
- type Target = [u8; 48];
- fn deref(&self) -> &Self::Target {
- &self.bytes
- }
-}
-
-#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct Blob {
- bytes: [u8; BYTES_PER_BLOB],
-}
-
-impl Deref for Blob {
- type Target = [u8; BYTES_PER_BLOB];
- fn deref(&self) -> &Self::Target {
- &self.bytes
- }
-}
-
-impl DerefMut for Blob {
- fn deref_mut(&mut self) -> &mut Self::Target {
- &mut self.bytes
- }
-}
-
-#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct KZGProof {
- bytes: [u8; BYTES_PER_PROOF],
-}
-
-impl Deref for KZGProof {
- type Target = [u8; BYTES_PER_PROOF];
- fn deref(&self) -> &Self::Target {
- &self.bytes
- }
-}
-
-type g1_t = blst_p1;
-type g2_t = blst_p2;
-type fr_t = blst_fr;
-#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct KZGCommitment {
- bytes: [u8; BYTES_PER_COMMITMENT],
-}
-
-impl Deref for KZGCommitment {
- type Target = [u8; BYTES_PER_COMMITMENT];
- fn deref(&self) -> &Self::Target {
- &self.bytes
- }
-}
-
-#[must_use]
-#[repr(u32)]
-#[doc = " The common return type for all routines in which something can go wrong."]
-#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
-pub enum C_KZG_RET {
- #[doc = "< Success!"]
- C_KZG_OK = 0,
- #[doc = "< The supplied data is invalid in some way."]
- C_KZG_BADARGS = 1,
- #[doc = "< Internal error - this should never occur and may indicate a bug in the library."]
- C_KZG_ERROR = 2,
- #[doc = "< Could not allocate memory."]
- C_KZG_MALLOC = 3,
-}
-#[doc = " Stores the setup and parameters needed for performing FFTs."]
-#[repr(C)]
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct FFTSettings {
- #[doc = "< The maximum size of FFT these settings support, a power of 2."]
- max_width: u64,
- #[doc = "< Ascending powers of the root of unity, size `width + 1`."]
- expanded_roots_of_unity: *const fr_t,
- #[doc = "< Descending powers of the root of unity, size `width + 1`."]
- reverse_roots_of_unity: *const fr_t,
- #[doc = "< Powers of the root of unity in bit-reversal permutation, size `width`."]
- roots_of_unity: *const fr_t,
-}
-
-#[doc = " Stores the setup and parameters needed for computing KZG proofs."]
-#[repr(C)]
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct KZGSettings {
- #[doc = "< The corresponding settings for performing FFTs."]
- fs: *const FFTSettings,
- #[doc = "< G1 group elements from the trusted setup, in Lagrange form bit-reversal permutation."]
- g1_values: *const g1_t,
- #[doc = "< G2 group elements from the trusted setup; both arrays have FIELD_ELEMENTS_PER_BLOB elements."]
- g2_values: *const g2_t,
-}
-
-/// Safety: FFTSettings is initialized once on calling `load_trusted_setup`. After
-/// that, the struct is never modified. The memory for the arrays within `FFTSettings` and
-/// `g1_values` and `g2_values` are only freed on calling `free_trusted_setup` which only happens
-/// when we drop the struct.
-unsafe impl Sync for KZGSettings {}
-unsafe impl Send for KZGSettings {}
-
-extern "C" {
- pub fn load_trusted_setup(
- out: *mut KZGSettings,
- g1_bytes: *const u8, /* n1 * 48 bytes */
- n1: usize,
- g2_bytes: *const u8, /* n2 * 96 bytes */
- n2: usize,
- ) -> C_KZG_RET;
-
- pub fn load_trusted_setup_file(out: *mut KZGSettings, in_: *mut FILE) -> C_KZG_RET;
-
- pub fn free_trusted_setup(s: *mut KZGSettings);
-
- pub fn blob_to_kzg_commitment(
- out: *mut KZGCommitment,
- blob: *const Blob,
- s: *const KZGSettings,
- ) -> C_KZG_RET;
-
- pub fn compute_kzg_proof(
- proof_out: *mut KZGProof,
- y_out: *mut Bytes32,
- blob: *const Blob,
- z_bytes: *const Bytes32,
- s: *const KZGSettings,
- ) -> C_KZG_RET;
-
- pub fn compute_blob_kzg_proof(
- out: *mut KZGProof,
- blob: *const Blob,
- commitment_bytes: *const Bytes48,
- s: *const KZGSettings,
- ) -> C_KZG_RET;
-
- pub fn verify_kzg_proof(
- out: *mut bool,
- commitment_bytes: *const Bytes48,
- z_bytes: *const Bytes32,
- y_bytes: *const Bytes32,
- proof_bytes: *const Bytes48,
- s: *const KZGSettings,
- ) -> C_KZG_RET;
-
- pub fn verify_blob_kzg_proof(
- out: *mut bool,
- blob: *const Blob,
- commitment_bytes: *const Bytes48,
- proof_bytes: *const Bytes48,
- s: *const KZGSettings,
- ) -> C_KZG_RET;
-
- pub fn verify_blob_kzg_proof_batch(
- out: *mut bool,
- blobs: *const Blob,
- commitments_bytes: *const Bytes48,
- proofs_bytes: *const Bytes48,
- count: usize,
- s: *const KZGSettings,
- ) -> C_KZG_RET;
-}
diff --git a/bindings/rust/src/bindings/mod.rs b/bindings/rust/src/bindings/mod.rs
new file mode 100644
index 0000000..f385ca7
--- /dev/null
+++ b/bindings/rust/src/bindings/mod.rs
@@ -0,0 +1,745 @@
+#![allow(non_upper_case_globals)]
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+
+mod test_formats;
+
+include!("generated.rs");
+
+use libc::fopen;
+use std::ffi::CString;
+use std::mem::MaybeUninit;
+use std::os::unix::prelude::OsStrExt;
+use std::path::PathBuf;
+
+pub const BYTES_PER_G1_POINT: usize = 48;
+pub const BYTES_PER_G2_POINT: usize = 96;
+
+/// Number of G2 points required for the kzg trusted setup.
+/// 65 is fixed and is used for providing multiproofs up to 64 field elements.
+const NUM_G2_POINTS: usize = 65;
+
+/// A trusted (valid) KZG commitment.
+// NOTE: this is a type alias to the struct Bytes48, same as [`KZGProof`] in the C header files. To
+// facilitate type safety: proofs and commitments should not be interchangeable, we use a
+// custom implementation.
+#[repr(C)]
+pub struct KZGCommitment {
+ bytes: [u8; BYTES_PER_COMMITMENT],
+}
+
+/// A trusted (valid) KZG proof.
+// NOTE: this is a type alias to the struct Bytes48, same as [`KZGCommitment`] in the C header
+// files. To facilitate type safety: proofs and commitments should not be interchangeable, we
+// use a custom implementation.
+#[repr(C)]
+pub struct KZGProof {
+ bytes: [u8; BYTES_PER_PROOF],
+}
+
+#[derive(Debug)]
+pub enum Error {
+ /// Wrong number of bytes.
+ InvalidBytesLength(String),
+ /// The KZG proof is invalid.
+ InvalidKzgProof(String),
+ /// The KZG commitment is invalid.
+ InvalidKzgCommitment(String),
+ /// The provided trusted setup is invalid.
+ InvalidTrustedSetup(String),
+ /// Paired arguments have different lengths.
+ MismatchLength(String),
+ /// The underlying c-kzg library returned an error.
+ CError(C_KZG_RET),
+}
+
+/// Holds the parameters of a kzg trusted setup ceremony.
+impl KZGSettings {
+ /// Initializes a trusted setup from `FIELD_ELEMENTS_PER_BLOB` g1 points
+ /// and 65 g2 points in byte format.
+ pub fn load_trusted_setup(
+ g1_bytes: Vec<[u8; BYTES_PER_G1_POINT]>,
+ g2_bytes: Vec<[u8; BYTES_PER_G2_POINT]>,
+ ) -> Result {
+ if g1_bytes.len() != FIELD_ELEMENTS_PER_BLOB {
+ return Err(Error::InvalidTrustedSetup(format!(
+ "Invalid number of g1 points in trusted setup. Expected {} got {}",
+ FIELD_ELEMENTS_PER_BLOB,
+ g1_bytes.len()
+ )));
+ }
+ if g2_bytes.len() != NUM_G2_POINTS {
+ return Err(Error::InvalidTrustedSetup(format!(
+ "Invalid number of g2 points in trusted setup. Expected {} got {}",
+ NUM_G2_POINTS,
+ g2_bytes.len()
+ )));
+ }
+ let mut kzg_settings = MaybeUninit::::uninit();
+ unsafe {
+ let res = load_trusted_setup(
+ kzg_settings.as_mut_ptr(),
+ g1_bytes.as_ptr() as *const u8,
+ g1_bytes.len(),
+ g2_bytes.as_ptr() as *const u8,
+ g2_bytes.len(),
+ );
+ if let C_KZG_RET::C_KZG_OK = res {
+ Ok(kzg_settings.assume_init())
+ } else {
+ Err(Error::InvalidTrustedSetup(format!(
+ "Invalid trusted setup: {:?}",
+ res
+ )))
+ }
+ }
+ }
+
+ /// Loads the trusted setup parameters from a file. The file format is as follows:
+ ///
+ /// FIELD_ELEMENTS_PER_BLOB
+ /// 65 # This is fixed and is used for providing multiproofs up to 64 field elements.
+ /// FIELD_ELEMENT_PER_BLOB g1 byte values
+ /// 65 g2 byte values
+ pub fn load_trusted_setup_file(file_path: PathBuf) -> Result {
+ let file_path = CString::new(file_path.as_os_str().as_bytes()).map_err(|e| {
+ Error::InvalidTrustedSetup(format!("Invalid trusted setup file: {:?}", e))
+ })?;
+ let mut kzg_settings = MaybeUninit::::uninit();
+ unsafe {
+ let file_ptr = fopen(file_path.as_ptr(), &('r' as libc::c_char));
+ let res = load_trusted_setup_file(kzg_settings.as_mut_ptr(), file_ptr);
+ if let C_KZG_RET::C_KZG_OK = res {
+ Ok(kzg_settings.assume_init())
+ } else {
+ Err(Error::InvalidTrustedSetup(format!(
+ "Invalid trusted setup: {:?}",
+ res
+ )))
+ }
+ }
+ }
+}
+
+impl Drop for KZGSettings {
+ fn drop(&mut self) {
+ unsafe { free_trusted_setup(self) }
+ }
+}
+
+impl Blob {
+ pub fn from_bytes(bytes: &[u8]) -> Result {
+ if bytes.len() != BYTES_PER_BLOB {
+ return Err(Error::InvalidBytesLength(format!(
+ "Invalid byte length. Expected {} got {}",
+ BYTES_PER_BLOB,
+ bytes.len(),
+ )));
+ }
+ let mut new_bytes = [0; BYTES_PER_BLOB];
+ new_bytes.copy_from_slice(bytes);
+ Ok(Self { bytes: new_bytes })
+ }
+
+ pub fn from_hex(hex_str: &str) -> Result {
+ Self::from_bytes(&hex::decode(&hex_str[2..]).unwrap())
+ }
+}
+
+impl Bytes32 {
+ pub fn from_bytes(bytes: &[u8]) -> Result {
+ if bytes.len() != 32 {
+ return Err(Error::InvalidBytesLength(format!(
+ "Invalid byte length. Expected {} got {}",
+ 32,
+ bytes.len(),
+ )));
+ }
+ let mut new_bytes = [0; 32];
+ new_bytes.copy_from_slice(bytes);
+ Ok(Self { bytes: new_bytes })
+ }
+
+ pub fn from_hex(hex_str: &str) -> Result {
+ Self::from_bytes(&hex::decode(&hex_str[2..]).unwrap())
+ }
+}
+
+impl Bytes48 {
+ pub fn from_bytes(bytes: &[u8]) -> Result {
+ if bytes.len() != 48 {
+ return Err(Error::InvalidBytesLength(format!(
+ "Invalid byte length. Expected {} got {}",
+ 48,
+ bytes.len(),
+ )));
+ }
+ let mut new_bytes = [0; 48];
+ new_bytes.copy_from_slice(bytes);
+ Ok(Self { bytes: new_bytes })
+ }
+
+ pub fn from_hex(hex_str: &str) -> Result {
+ Self::from_bytes(&hex::decode(&hex_str[2..]).unwrap())
+ }
+
+ pub fn into_inner(self) -> [u8; 48] {
+ self.bytes
+ }
+}
+
+impl KZGProof {
+ pub fn from_bytes(bytes: &[u8]) -> Result {
+ if bytes.len() != BYTES_PER_PROOF {
+ return Err(Error::InvalidKzgProof(format!(
+ "Invalid byte length. Expected {} got {}",
+ BYTES_PER_PROOF,
+ bytes.len(),
+ )));
+ }
+ let mut proof_bytes = [0; BYTES_PER_PROOF];
+ proof_bytes.copy_from_slice(bytes);
+ Ok(Self { bytes: proof_bytes })
+ }
+
+ pub fn to_bytes(&self) -> Bytes48 {
+ Bytes48 { bytes: self.bytes }
+ }
+
+ pub fn as_hex_string(&self) -> String {
+ hex::encode(self.bytes)
+ }
+
+ pub fn compute_kzg_proof(
+ blob: Blob,
+ z_bytes: Bytes32,
+ kzg_settings: &KZGSettings,
+ ) -> Result<(Self, Bytes32), Error> {
+ let mut kzg_proof = MaybeUninit::::uninit();
+ let mut y_out = MaybeUninit::::uninit();
+ unsafe {
+ let res = compute_kzg_proof(
+ kzg_proof.as_mut_ptr(),
+ y_out.as_mut_ptr(),
+ &blob,
+ &z_bytes,
+ kzg_settings,
+ );
+ if let C_KZG_RET::C_KZG_OK = res {
+ Ok((kzg_proof.assume_init(), y_out.assume_init()))
+ } else {
+ Err(Error::CError(res))
+ }
+ }
+ }
+
+ pub fn compute_blob_kzg_proof(
+ blob: Blob,
+ commitment_bytes: Bytes48,
+ kzg_settings: &KZGSettings,
+ ) -> Result {
+ let mut kzg_proof = MaybeUninit::::uninit();
+ unsafe {
+ let res = compute_blob_kzg_proof(
+ kzg_proof.as_mut_ptr(),
+ &blob,
+ &commitment_bytes,
+ kzg_settings,
+ );
+ if let C_KZG_RET::C_KZG_OK = res {
+ Ok(kzg_proof.assume_init())
+ } else {
+ Err(Error::CError(res))
+ }
+ }
+ }
+
+ pub fn verify_kzg_proof(
+ commitment_bytes: Bytes48,
+ z_bytes: Bytes32,
+ y_bytes: Bytes32,
+ proof_bytes: Bytes48,
+ kzg_settings: &KZGSettings,
+ ) -> Result {
+ let mut verified: MaybeUninit = MaybeUninit::uninit();
+ unsafe {
+ let res = verify_kzg_proof(
+ verified.as_mut_ptr(),
+ &commitment_bytes,
+ &z_bytes,
+ &y_bytes,
+ &proof_bytes,
+ kzg_settings,
+ );
+ if let C_KZG_RET::C_KZG_OK = res {
+ Ok(verified.assume_init())
+ } else {
+ Err(Error::CError(res))
+ }
+ }
+ }
+
+ pub fn verify_blob_kzg_proof(
+ blob: Blob,
+ commitment_bytes: Bytes48,
+ proof_bytes: Bytes48,
+ kzg_settings: &KZGSettings,
+ ) -> Result {
+ let mut verified: MaybeUninit = MaybeUninit::uninit();
+ unsafe {
+ let res = verify_blob_kzg_proof(
+ verified.as_mut_ptr(),
+ &blob,
+ &commitment_bytes,
+ &proof_bytes,
+ kzg_settings,
+ );
+ if let C_KZG_RET::C_KZG_OK = res {
+ Ok(verified.assume_init())
+ } else {
+ Err(Error::CError(res))
+ }
+ }
+ }
+
+ pub fn verify_blob_kzg_proof_batch(
+ blobs: &[Blob],
+ commitments_bytes: &[Bytes48],
+ proofs_bytes: &[Bytes48],
+ kzg_settings: &KZGSettings,
+ ) -> Result {
+ if blobs.len() != commitments_bytes.len() {
+ return Err(Error::MismatchLength(format!(
+ "There are {} blobs and {} commitments",
+ blobs.len(),
+ commitments_bytes.len()
+ )));
+ }
+ if blobs.len() != proofs_bytes.len() {
+ return Err(Error::MismatchLength(format!(
+ "There are {} blobs and {} proofs",
+ blobs.len(),
+ proofs_bytes.len()
+ )));
+ }
+ let mut verified: MaybeUninit = MaybeUninit::uninit();
+ unsafe {
+ let res = verify_blob_kzg_proof_batch(
+ verified.as_mut_ptr(),
+ blobs.as_ptr(),
+ commitments_bytes.as_ptr(),
+ proofs_bytes.as_ptr(),
+ blobs.len(),
+ kzg_settings,
+ );
+ if let C_KZG_RET::C_KZG_OK = res {
+ Ok(verified.assume_init())
+ } else {
+ Err(Error::CError(res))
+ }
+ }
+ }
+}
+
+impl KZGCommitment {
+ pub fn from_bytes(bytes: &[u8]) -> Result {
+ if bytes.len() != BYTES_PER_COMMITMENT {
+ return Err(Error::InvalidKzgCommitment(format!(
+ "Invalid byte length. Expected {} got {}",
+ BYTES_PER_PROOF,
+ bytes.len(),
+ )));
+ }
+ let mut commitment = [0; BYTES_PER_COMMITMENT];
+ commitment.copy_from_slice(bytes);
+ Ok(Self { bytes: commitment })
+ }
+
+ pub fn to_bytes(&self) -> Bytes48 {
+ Bytes48 { bytes: self.bytes }
+ }
+
+ pub fn as_hex_string(&self) -> String {
+ hex::encode(self.bytes)
+ }
+
+ pub fn blob_to_kzg_commitment(blob: Blob, kzg_settings: &KZGSettings) -> Result {
+ let mut kzg_commitment: MaybeUninit = MaybeUninit::uninit();
+ unsafe {
+ let res = blob_to_kzg_commitment(
+ kzg_commitment.as_mut_ptr(),
+ blob.as_ptr() as *const Blob,
+ kzg_settings,
+ );
+ if let C_KZG_RET::C_KZG_OK = res {
+ Ok(kzg_commitment.assume_init())
+ } else {
+ Err(Error::CError(res))
+ }
+ }
+ }
+}
+
+impl From<[u8; BYTES_PER_COMMITMENT]> for KZGCommitment {
+ fn from(value: [u8; BYTES_PER_COMMITMENT]) -> Self {
+ Self { bytes: value }
+ }
+}
+
+impl From<[u8; BYTES_PER_PROOF]> for KZGProof {
+ fn from(value: [u8; BYTES_PER_PROOF]) -> Self {
+ Self { bytes: value }
+ }
+}
+
+impl From<[u8; BYTES_PER_BLOB]> for Blob {
+ fn from(value: [u8; BYTES_PER_BLOB]) -> Self {
+ Self { bytes: value }
+ }
+}
+
+impl From<[u8; 32]> for Bytes32 {
+ fn from(value: [u8; 32]) -> Self {
+ Self { bytes: value }
+ }
+}
+
+impl From<[u8; 48]> for Bytes48 {
+ fn from(value: [u8; 48]) -> Self {
+ Self { bytes: value }
+ }
+}
+
+use std::ops::{Deref, DerefMut};
+
+impl Deref for Bytes32 {
+ type Target = [u8; 32];
+ fn deref(&self) -> &Self::Target {
+ &self.bytes
+ }
+}
+
+impl Deref for Bytes48 {
+ type Target = [u8; 48];
+ fn deref(&self) -> &Self::Target {
+ &self.bytes
+ }
+}
+
+impl Deref for Blob {
+ type Target = [u8; BYTES_PER_BLOB];
+ fn deref(&self) -> &Self::Target {
+ &self.bytes
+ }
+}
+
+impl DerefMut for Blob {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.bytes
+ }
+}
+
+impl Clone for Blob {
+ fn clone(&self) -> Self {
+ Blob { bytes: self.bytes }
+ }
+}
+
+impl Deref for KZGProof {
+ type Target = [u8; BYTES_PER_PROOF];
+ fn deref(&self) -> &Self::Target {
+ &self.bytes
+ }
+}
+
+impl Deref for KZGCommitment {
+ type Target = [u8; BYTES_PER_COMMITMENT];
+ fn deref(&self) -> &Self::Target {
+ &self.bytes
+ }
+}
+
+/// Safety: FFTSettings is initialized once on calling `load_trusted_setup`. After
+/// that, the struct is never modified. The memory for the arrays within `FFTSettings` and
+/// `g1_values` and `g2_values` are only freed on calling `free_trusted_setup` which only happens
+/// when we drop the struct.
+unsafe impl Sync for KZGSettings {}
+unsafe impl Send for KZGSettings {}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use rand::{rngs::ThreadRng, Rng};
+ use std::fs;
+
+ use test_formats::{
+ blob_to_kzg_commitment_test, compute_blob_kzg_proof, compute_kzg_proof,
+ verify_blob_kzg_proof, verify_blob_kzg_proof_batch, verify_kzg_proof,
+ };
+
+ fn generate_random_blob(rng: &mut ThreadRng) -> Blob {
+ let mut arr = [0u8; BYTES_PER_BLOB];
+ rng.fill(&mut arr[..]);
+ // Ensure that the blob is canonical by ensuring that
+ // each field element contained in the blob is < BLS_MODULUS
+ for i in 0..FIELD_ELEMENTS_PER_BLOB {
+ arr[i * BYTES_PER_FIELD_ELEMENT + BYTES_PER_FIELD_ELEMENT - 1] = 0;
+ }
+ arr.into()
+ }
+
+ fn test_simple(trusted_setup_file: PathBuf) {
+ let mut rng = rand::thread_rng();
+ assert!(trusted_setup_file.exists());
+ let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file).unwrap();
+
+ let num_blobs: usize = rng.gen_range(1..16);
+ let mut blobs: Vec = (0..num_blobs)
+ .map(|_| generate_random_blob(&mut rng))
+ .collect();
+
+ let commitments: Vec = blobs
+ .iter()
+ .map(|blob| KZGCommitment::blob_to_kzg_commitment(blob.clone(), &kzg_settings).unwrap())
+ .map(|commitment| commitment.to_bytes())
+ .collect();
+
+ let proofs: Vec = blobs
+ .iter()
+ .zip(commitments.iter())
+ .map(|(blob, commitment)| {
+ KZGProof::compute_blob_kzg_proof(blob.clone(), *commitment, &kzg_settings).unwrap()
+ })
+ .map(|proof| proof.to_bytes())
+ .collect();
+
+ assert!(KZGProof::verify_blob_kzg_proof_batch(
+ &blobs,
+ &commitments,
+ &proofs,
+ &kzg_settings
+ )
+ .unwrap());
+
+ blobs.pop();
+
+ let error =
+ KZGProof::verify_blob_kzg_proof_batch(&blobs, &commitments, &proofs, &kzg_settings)
+ .unwrap_err();
+ assert!(matches!(error, Error::MismatchLength(_)));
+
+ let incorrect_blob = generate_random_blob(&mut rng);
+ blobs.push(incorrect_blob);
+
+ assert!(!KZGProof::verify_blob_kzg_proof_batch(
+ &blobs,
+ &commitments,
+ &proofs,
+ &kzg_settings
+ )
+ .unwrap());
+ }
+
+ #[test]
+ fn test_end_to_end() {
+ let trusted_setup_file = if cfg!(feature = "minimal-spec") {
+ PathBuf::from("../../src/trusted_setup_4.txt")
+ } else {
+ PathBuf::from("../../src/trusted_setup.txt")
+ };
+ test_simple(trusted_setup_file);
+ }
+
+ const BLOB_TO_KZG_COMMITMENT_TESTS: &str = "../../tests/blob_to_kzg_commitment/*/*/*";
+ const COMPUTE_KZG_PROOF_TESTS: &str = "../../tests/compute_kzg_proof/*/*/*";
+ const COMPUTE_BLOB_KZG_PROOF_TESTS: &str = "../../tests/compute_blob_kzg_proof/*/*/*";
+ const VERIFY_KZG_PROOF_TESTS: &str = "../../tests/verify_kzg_proof/*/*/*";
+ const VERIFY_BLOB_KZG_PROOF_TESTS: &str = "../../tests/verify_blob_kzg_proof/*/*/*";
+ const VERIFY_BLOB_KZG_PROOF_BATCH_TESTS: &str = "../../tests/verify_blob_kzg_proof_batch/*/*/*";
+
+ #[cfg(not(feature = "minimal-spec"))]
+ #[test]
+ fn test_blob_to_kzg_commitment() {
+ let trusted_setup_file = PathBuf::from("../../src/trusted_setup.txt");
+ assert!(trusted_setup_file.exists());
+ let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file).unwrap();
+ let test_files: Vec = glob::glob(BLOB_TO_KZG_COMMITMENT_TESTS)
+ .unwrap()
+ .map(Result::unwrap)
+ .collect();
+ assert!(!test_files.is_empty());
+
+ for test_file in test_files {
+ let yaml_data = fs::read_to_string(test_file).unwrap();
+ let test: blob_to_kzg_commitment_test::Test = serde_yaml::from_str(&yaml_data).unwrap();
+ let Ok(blob) = test.input.get_blob() else {
+ assert!(test.get_output().is_none());
+ continue;
+ };
+
+ match KZGCommitment::blob_to_kzg_commitment(blob, &kzg_settings) {
+ Ok(res) => assert_eq!(res.bytes, test.get_output().unwrap().bytes),
+ _ => assert!(test.get_output().is_none()),
+ }
+ }
+ }
+
+ #[cfg(not(feature = "minimal-spec"))]
+ #[test]
+ fn test_compute_kzg_proof() {
+ let trusted_setup_file = PathBuf::from("../../src/trusted_setup.txt");
+ assert!(trusted_setup_file.exists());
+ let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file).unwrap();
+ let test_files: Vec = glob::glob(COMPUTE_KZG_PROOF_TESTS)
+ .unwrap()
+ .map(Result::unwrap)
+ .collect();
+ assert!(!test_files.is_empty());
+
+ for test_file in test_files {
+ let yaml_data = fs::read_to_string(test_file).unwrap();
+ let test: compute_kzg_proof::Test = serde_yaml::from_str(&yaml_data).unwrap();
+ let (Ok(blob), Ok(z)) = (test.input.get_blob(), test.input.get_z()) else {
+ assert!(test.get_output().is_none());
+ continue;
+ };
+
+ match KZGProof::compute_kzg_proof(blob, z, &kzg_settings) {
+ Ok((proof, y)) => {
+ assert_eq!(proof.bytes, test.get_output().unwrap().0.bytes);
+ assert_eq!(y.bytes, test.get_output().unwrap().1.bytes);
+ }
+ _ => assert!(test.get_output().is_none()),
+ }
+ }
+ }
+
+ #[cfg(not(feature = "minimal-spec"))]
+ #[test]
+ fn test_compute_blob_kzg_proof() {
+ let trusted_setup_file = PathBuf::from("../../src/trusted_setup.txt");
+ assert!(trusted_setup_file.exists());
+ let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file).unwrap();
+ let test_files: Vec = glob::glob(COMPUTE_BLOB_KZG_PROOF_TESTS)
+ .unwrap()
+ .map(Result::unwrap)
+ .collect();
+ assert!(!test_files.is_empty());
+
+ for test_file in test_files {
+ let yaml_data = fs::read_to_string(test_file).unwrap();
+ let test: compute_blob_kzg_proof::Test = serde_yaml::from_str(&yaml_data).unwrap();
+ let (Ok(blob), Ok(commitment)) = (
+ test.input.get_blob(),
+ test.input.get_commitment()
+ ) else {
+ assert!(test.get_output().is_none());
+ continue;
+ };
+
+ match KZGProof::compute_blob_kzg_proof(blob, commitment, &kzg_settings) {
+ Ok(res) => assert_eq!(res.bytes, test.get_output().unwrap().bytes),
+ _ => assert!(test.get_output().is_none()),
+ }
+ }
+ }
+
+ #[cfg(not(feature = "minimal-spec"))]
+ #[test]
+ fn test_verify_kzg_proof() {
+ let trusted_setup_file = PathBuf::from("../../src/trusted_setup.txt");
+ assert!(trusted_setup_file.exists());
+ let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file).unwrap();
+ let test_files: Vec = glob::glob(VERIFY_KZG_PROOF_TESTS)
+ .unwrap()
+ .map(Result::unwrap)
+ .collect();
+ assert!(!test_files.is_empty());
+
+ for test_file in test_files {
+ let yaml_data = fs::read_to_string(test_file).unwrap();
+ let test: verify_kzg_proof::Test = serde_yaml::from_str(&yaml_data).unwrap();
+ let (Ok(commitment), Ok(z), Ok(y), Ok(proof)) = (
+ test.input.get_commitment(),
+ test.input.get_z(),
+ test.input.get_y(),
+ test.input.get_proof()
+ ) else {
+ assert!(test.get_output().is_none());
+ continue;
+ };
+
+ match KZGProof::verify_kzg_proof(commitment, z, y, proof, &kzg_settings) {
+ Ok(res) => assert_eq!(res, test.get_output().unwrap()),
+ _ => assert!(test.get_output().is_none()),
+ }
+ }
+ }
+
+ #[cfg(not(feature = "minimal-spec"))]
+ #[test]
+ fn test_verify_blob_kzg_proof() {
+ let trusted_setup_file = PathBuf::from("../../src/trusted_setup.txt");
+ assert!(trusted_setup_file.exists());
+ let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file).unwrap();
+ let test_files: Vec = glob::glob(VERIFY_BLOB_KZG_PROOF_TESTS)
+ .unwrap()
+ .map(Result::unwrap)
+ .collect();
+ assert!(!test_files.is_empty());
+
+ for test_file in test_files {
+ let yaml_data = fs::read_to_string(test_file).unwrap();
+ let test: verify_blob_kzg_proof::Test = serde_yaml::from_str(&yaml_data).unwrap();
+ let (Ok(blob), Ok(commitment), Ok(proof)) = (
+ test.input.get_blob(),
+ test.input.get_commitment(),
+ test.input.get_proof()
+ ) else {
+ assert!(test.get_output().is_none());
+ continue;
+ };
+
+ match KZGProof::verify_blob_kzg_proof(blob, commitment, proof, &kzg_settings) {
+ Ok(res) => assert_eq!(res, test.get_output().unwrap()),
+ _ => assert!(test.get_output().is_none()),
+ }
+ }
+ }
+
+ #[cfg(not(feature = "minimal-spec"))]
+ #[test]
+ fn test_verify_blob_kzg_proof_batch() {
+ let trusted_setup_file = PathBuf::from("../../src/trusted_setup.txt");
+ assert!(trusted_setup_file.exists());
+ let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file).unwrap();
+ let test_files: Vec = glob::glob(VERIFY_BLOB_KZG_PROOF_BATCH_TESTS)
+ .unwrap()
+ .map(Result::unwrap)
+ .collect();
+ assert!(!test_files.is_empty());
+
+ for test_file in test_files {
+ let yaml_data = fs::read_to_string(test_file).unwrap();
+ let test: verify_blob_kzg_proof_batch::Test = serde_yaml::from_str(&yaml_data).unwrap();
+ let (Ok(blobs), Ok(commitments), Ok(proofs)) = (
+ test.input.get_blobs(),
+ test.input.get_commitments(),
+ test.input.get_proofs()
+ ) else {
+ assert!(test.get_output().is_none());
+ continue;
+ };
+
+ match KZGProof::verify_blob_kzg_proof_batch(
+ &blobs,
+ &commitments,
+ &proofs,
+ &kzg_settings,
+ ) {
+ Ok(res) => assert_eq!(res, test.get_output().unwrap()),
+ _ => assert!(test.get_output().is_none()),
+ }
+ }
+ }
+}
diff --git a/bindings/rust/src/test_formats/blob_to_kzg_commitment_test.rs b/bindings/rust/src/bindings/test_formats/blob_to_kzg_commitment_test.rs
similarity index 100%
rename from bindings/rust/src/test_formats/blob_to_kzg_commitment_test.rs
rename to bindings/rust/src/bindings/test_formats/blob_to_kzg_commitment_test.rs
diff --git a/bindings/rust/src/test_formats/compute_blob_kzg_proof.rs b/bindings/rust/src/bindings/test_formats/compute_blob_kzg_proof.rs
similarity index 100%
rename from bindings/rust/src/test_formats/compute_blob_kzg_proof.rs
rename to bindings/rust/src/bindings/test_formats/compute_blob_kzg_proof.rs
diff --git a/bindings/rust/src/test_formats/compute_kzg_proof.rs b/bindings/rust/src/bindings/test_formats/compute_kzg_proof.rs
similarity index 100%
rename from bindings/rust/src/test_formats/compute_kzg_proof.rs
rename to bindings/rust/src/bindings/test_formats/compute_kzg_proof.rs
diff --git a/bindings/rust/src/test_formats/mod.rs b/bindings/rust/src/bindings/test_formats/mod.rs
similarity index 100%
rename from bindings/rust/src/test_formats/mod.rs
rename to bindings/rust/src/bindings/test_formats/mod.rs
diff --git a/bindings/rust/src/test_formats/verify_blob_kzg_proof.rs b/bindings/rust/src/bindings/test_formats/verify_blob_kzg_proof.rs
similarity index 100%
rename from bindings/rust/src/test_formats/verify_blob_kzg_proof.rs
rename to bindings/rust/src/bindings/test_formats/verify_blob_kzg_proof.rs
diff --git a/bindings/rust/src/test_formats/verify_blob_kzg_proof_batch.rs b/bindings/rust/src/bindings/test_formats/verify_blob_kzg_proof_batch.rs
similarity index 100%
rename from bindings/rust/src/test_formats/verify_blob_kzg_proof_batch.rs
rename to bindings/rust/src/bindings/test_formats/verify_blob_kzg_proof_batch.rs
diff --git a/bindings/rust/src/test_formats/verify_kzg_proof.rs b/bindings/rust/src/bindings/test_formats/verify_kzg_proof.rs
similarity index 100%
rename from bindings/rust/src/test_formats/verify_kzg_proof.rs
rename to bindings/rust/src/bindings/test_formats/verify_kzg_proof.rs
diff --git a/bindings/rust/src/lib.rs b/bindings/rust/src/lib.rs
index a9c236d..05bd6e9 100644
--- a/bindings/rust/src/lib.rs
+++ b/bindings/rust/src/lib.rs
@@ -1,675 +1,14 @@
-#![allow(non_upper_case_globals)]
-#![allow(non_camel_case_types)]
-#![allow(non_snake_case)]
-
-mod test_formats;
-
-include!("bindings.rs");
-
-use libc::fopen;
-use std::ffi::CString;
-use std::mem::MaybeUninit;
-use std::os::unix::prelude::OsStrExt;
-use std::path::PathBuf;
-
-pub const BYTES_PER_G1_POINT: usize = 48;
-pub const BYTES_PER_G2_POINT: usize = 96;
-
-/// Number of G2 points required for the kzg trusted setup.
-/// 65 is fixed and is used for providing multiproofs up to 64 field elements.
-const NUM_G2_POINTS: usize = 65;
-
-#[derive(Debug)]
-pub enum Error {
- /// Wrong number of bytes.
- InvalidBytesLength(String),
- /// The KZG proof is invalid.
- InvalidKzgProof(String),
- /// The KZG commitment is invalid.
- InvalidKzgCommitment(String),
- /// The provided trusted setup is invalid.
- InvalidTrustedSetup(String),
- /// Paired arguments have different lengths.
- MismatchLength(String),
- /// The underlying c-kzg library returned an error.
- CError(C_KZG_RET),
-}
-
-/// Holds the parameters of a kzg trusted setup ceremony.
-impl KZGSettings {
- /// Initializes a trusted setup from `FIELD_ELEMENTS_PER_BLOB` g1 points
- /// and 65 g2 points in byte format.
- pub fn load_trusted_setup(
- g1_bytes: Vec<[u8; BYTES_PER_G1_POINT]>,
- g2_bytes: Vec<[u8; BYTES_PER_G2_POINT]>,
- ) -> Result {
- if g1_bytes.len() != FIELD_ELEMENTS_PER_BLOB {
- return Err(Error::InvalidTrustedSetup(format!(
- "Invalid number of g1 points in trusted setup. Expected {} got {}",
- FIELD_ELEMENTS_PER_BLOB,
- g1_bytes.len()
- )));
- }
- if g2_bytes.len() != NUM_G2_POINTS {
- return Err(Error::InvalidTrustedSetup(format!(
- "Invalid number of g2 points in trusted setup. Expected {} got {}",
- NUM_G2_POINTS,
- g2_bytes.len()
- )));
- }
- let mut kzg_settings = MaybeUninit::::uninit();
- unsafe {
- let res = load_trusted_setup(
- kzg_settings.as_mut_ptr(),
- g1_bytes.as_ptr() as *const u8,
- g1_bytes.len(),
- g2_bytes.as_ptr() as *const u8,
- g2_bytes.len(),
- );
- if let C_KZG_RET::C_KZG_OK = res {
- Ok(kzg_settings.assume_init())
- } else {
- Err(Error::InvalidTrustedSetup(format!(
- "Invalid trusted setup: {:?}",
- res
- )))
- }
- }
- }
-
- /// Loads the trusted setup parameters from a file. The file format is as follows:
- ///
- /// FIELD_ELEMENTS_PER_BLOB
- /// 65 # This is fixed and is used for providing multiproofs up to 64 field elements.
- /// FIELD_ELEMENT_PER_BLOB g1 byte values
- /// 65 g2 byte values
- pub fn load_trusted_setup_file(file_path: PathBuf) -> Result {
- let file_path = CString::new(file_path.as_os_str().as_bytes()).map_err(|e| {
- Error::InvalidTrustedSetup(format!("Invalid trusted setup file: {:?}", e))
- })?;
- let mut kzg_settings = MaybeUninit::::uninit();
- unsafe {
- let file_ptr = fopen(file_path.as_ptr(), &('r' as libc::c_char));
- let res = load_trusted_setup_file(kzg_settings.as_mut_ptr(), file_ptr);
- if let C_KZG_RET::C_KZG_OK = res {
- Ok(kzg_settings.assume_init())
- } else {
- Err(Error::InvalidTrustedSetup(format!(
- "Invalid trusted setup: {:?}",
- res
- )))
- }
- }
- }
-}
-
-impl Drop for KZGSettings {
- fn drop(&mut self) {
- unsafe { free_trusted_setup(self) }
- }
-}
-
-impl Blob {
- pub fn from_bytes(bytes: &[u8]) -> Result {
- if bytes.len() != BYTES_PER_BLOB {
- return Err(Error::InvalidBytesLength(format!(
- "Invalid byte length. Expected {} got {}",
- BYTES_PER_BLOB,
- bytes.len(),
- )));
- }
- let mut new_bytes = [0; BYTES_PER_BLOB];
- new_bytes.copy_from_slice(bytes);
- Ok(Self { bytes: new_bytes })
- }
-
- pub fn from_hex(hex_str: &str) -> Result {
- Self::from_bytes(&hex::decode(&hex_str[2..]).unwrap())
- }
-}
-
-impl Bytes32 {
- pub fn from_bytes(bytes: &[u8]) -> Result {
- if bytes.len() != 32 {
- return Err(Error::InvalidBytesLength(format!(
- "Invalid byte length. Expected {} got {}",
- 32,
- bytes.len(),
- )));
- }
- let mut new_bytes = [0; 32];
- new_bytes.copy_from_slice(bytes);
- Ok(Self { bytes: new_bytes })
- }
-
- pub fn from_hex(hex_str: &str) -> Result {
- Self::from_bytes(&hex::decode(&hex_str[2..]).unwrap())
- }
-}
-
-impl Bytes48 {
- pub fn from_bytes(bytes: &[u8]) -> Result {
- if bytes.len() != 48 {
- return Err(Error::InvalidBytesLength(format!(
- "Invalid byte length. Expected {} got {}",
- 48,
- bytes.len(),
- )));
- }
- let mut new_bytes = [0; 48];
- new_bytes.copy_from_slice(bytes);
- Ok(Self { bytes: new_bytes })
- }
-
- pub fn from_hex(hex_str: &str) -> Result {
- Self::from_bytes(&hex::decode(&hex_str[2..]).unwrap())
- }
-
- pub fn into_inner(self) -> [u8; 48] {
- self.bytes
- }
-}
-
-impl KZGProof {
- pub fn from_bytes(bytes: &[u8]) -> Result {
- if bytes.len() != BYTES_PER_PROOF {
- return Err(Error::InvalidKzgProof(format!(
- "Invalid byte length. Expected {} got {}",
- BYTES_PER_PROOF,
- bytes.len(),
- )));
- }
- let mut proof_bytes = [0; BYTES_PER_PROOF];
- proof_bytes.copy_from_slice(bytes);
- Ok(Self { bytes: proof_bytes })
- }
-
- pub fn to_bytes(&self) -> Bytes48 {
- let mut bytes = [0; 48];
- bytes.copy_from_slice(&self.bytes);
- Bytes48 { bytes }
- }
-
- pub fn as_hex_string(&self) -> String {
- hex::encode(self.bytes)
- }
-
- pub fn compute_kzg_proof(
- blob: Blob,
- z_bytes: Bytes32,
- kzg_settings: &KZGSettings,
- ) -> Result<(Self, Bytes32), Error> {
- let mut kzg_proof = MaybeUninit::::uninit();
- let mut y_out = MaybeUninit::::uninit();
- unsafe {
- let res = compute_kzg_proof(
- kzg_proof.as_mut_ptr(),
- y_out.as_mut_ptr(),
- &blob,
- &z_bytes,
- kzg_settings,
- );
- if let C_KZG_RET::C_KZG_OK = res {
- Ok((kzg_proof.assume_init(), y_out.assume_init()))
- } else {
- Err(Error::CError(res))
- }
- }
- }
-
- pub fn compute_blob_kzg_proof(
- blob: Blob,
- commitment_bytes: Bytes48,
- kzg_settings: &KZGSettings,
- ) -> Result {
- let mut kzg_proof = MaybeUninit::::uninit();
- unsafe {
- let res = compute_blob_kzg_proof(
- kzg_proof.as_mut_ptr(),
- &blob,
- &commitment_bytes,
- kzg_settings,
- );
- if let C_KZG_RET::C_KZG_OK = res {
- Ok(kzg_proof.assume_init())
- } else {
- Err(Error::CError(res))
- }
- }
- }
-
- pub fn verify_kzg_proof(
- commitment_bytes: Bytes48,
- z_bytes: Bytes32,
- y_bytes: Bytes32,
- proof_bytes: Bytes48,
- kzg_settings: &KZGSettings,
- ) -> Result {
- let mut verified: MaybeUninit = MaybeUninit::uninit();
- unsafe {
- let res = verify_kzg_proof(
- verified.as_mut_ptr(),
- &commitment_bytes,
- &z_bytes,
- &y_bytes,
- &proof_bytes,
- kzg_settings,
- );
- if let C_KZG_RET::C_KZG_OK = res {
- Ok(verified.assume_init())
- } else {
- Err(Error::CError(res))
- }
- }
- }
-
- pub fn verify_blob_kzg_proof(
- blob: Blob,
- commitment_bytes: Bytes48,
- proof_bytes: Bytes48,
- kzg_settings: &KZGSettings,
- ) -> Result {
- let mut verified: MaybeUninit = MaybeUninit::uninit();
- unsafe {
- let res = verify_blob_kzg_proof(
- verified.as_mut_ptr(),
- &blob,
- &commitment_bytes,
- &proof_bytes,
- kzg_settings,
- );
- if let C_KZG_RET::C_KZG_OK = res {
- Ok(verified.assume_init())
- } else {
- Err(Error::CError(res))
- }
- }
- }
-
- pub fn verify_blob_kzg_proof_batch(
- blobs: &[Blob],
- commitments_bytes: &[Bytes48],
- proofs_bytes: &[Bytes48],
- kzg_settings: &KZGSettings,
- ) -> Result {
- if blobs.len() != commitments_bytes.len() {
- return Err(Error::MismatchLength(format!(
- "There are {} blobs and {} commitments",
- blobs.len(),
- commitments_bytes.len()
- )));
- }
- if blobs.len() != proofs_bytes.len() {
- return Err(Error::MismatchLength(format!(
- "There are {} blobs and {} proofs",
- blobs.len(),
- proofs_bytes.len()
- )));
- }
- let mut verified: MaybeUninit = MaybeUninit::uninit();
- unsafe {
- let res = verify_blob_kzg_proof_batch(
- verified.as_mut_ptr(),
- blobs.as_ptr(),
- commitments_bytes.as_ptr(),
- proofs_bytes.as_ptr(),
- blobs.len(),
- kzg_settings,
- );
- if let C_KZG_RET::C_KZG_OK = res {
- Ok(verified.assume_init())
- } else {
- Err(Error::CError(res))
- }
- }
- }
-}
-
-impl KZGCommitment {
- pub fn from_bytes(bytes: &[u8]) -> Result {
- if bytes.len() != BYTES_PER_COMMITMENT {
- return Err(Error::InvalidKzgCommitment(format!(
- "Invalid byte length. Expected {} got {}",
- BYTES_PER_PROOF,
- bytes.len(),
- )));
- }
- let mut commitment = [0; BYTES_PER_COMMITMENT];
- commitment.copy_from_slice(bytes);
- Ok(Self { bytes: commitment })
- }
-
- pub fn to_bytes(&self) -> Bytes48 {
- let mut bytes = [0; 48];
- bytes.copy_from_slice(&self.bytes);
- Bytes48 { bytes }
- }
-
- pub fn as_hex_string(&self) -> String {
- hex::encode(self.bytes)
- }
-
- pub fn blob_to_kzg_commitment(blob: Blob, kzg_settings: &KZGSettings) -> Result {
- let mut kzg_commitment: MaybeUninit = MaybeUninit::uninit();
- unsafe {
- let res = blob_to_kzg_commitment(
- kzg_commitment.as_mut_ptr(),
- blob.as_ptr() as *const Blob,
- kzg_settings,
- );
- if let C_KZG_RET::C_KZG_OK = res {
- Ok(kzg_commitment.assume_init())
- } else {
- Err(Error::CError(res))
- }
- }
- }
-}
-
-impl From<[u8; BYTES_PER_COMMITMENT]> for KZGCommitment {
- fn from(value: [u8; BYTES_PER_COMMITMENT]) -> Self {
- Self { bytes: value }
- }
-}
-
-impl From<[u8; BYTES_PER_PROOF]> for KZGProof {
- fn from(value: [u8; BYTES_PER_PROOF]) -> Self {
- Self { bytes: value }
- }
-}
-
-impl From<[u8; BYTES_PER_BLOB]> for Blob {
- fn from(value: [u8; BYTES_PER_BLOB]) -> Self {
- Self { bytes: value }
- }
-}
-
-impl From<[u8; 32]> for Bytes32 {
- fn from(value: [u8; 32]) -> Self {
- Self { bytes: value }
- }
-}
-
-impl From<[u8; 48]> for Bytes48 {
- fn from(value: [u8; 48]) -> Self {
- Self { bytes: value }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use rand::{rngs::ThreadRng, Rng};
- use std::fs;
-
- use crate::test_formats::{
- blob_to_kzg_commitment_test, compute_blob_kzg_proof, compute_kzg_proof,
- verify_blob_kzg_proof, verify_blob_kzg_proof_batch, verify_kzg_proof,
- };
-
- fn generate_random_blob(rng: &mut ThreadRng) -> Blob {
- let mut arr = [0u8; BYTES_PER_BLOB];
- rng.fill(&mut arr[..]);
- // Ensure that the blob is canonical by ensuring that
- // each field element contained in the blob is < BLS_MODULUS
- for i in 0..FIELD_ELEMENTS_PER_BLOB {
- arr[i * BYTES_PER_FIELD_ELEMENT + BYTES_PER_FIELD_ELEMENT - 1] = 0;
- }
- arr.into()
- }
-
- fn test_simple(trusted_setup_file: PathBuf) {
- let mut rng = rand::thread_rng();
- assert!(trusted_setup_file.exists());
- let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file).unwrap();
-
- let num_blobs: usize = rng.gen_range(1..16);
- let mut blobs: Vec = (0..num_blobs)
- .map(|_| generate_random_blob(&mut rng))
- .collect();
-
- let commitments: Vec = blobs
- .iter()
- .map(|blob| KZGCommitment::blob_to_kzg_commitment(*blob, &kzg_settings).unwrap())
- .map(|commitment| commitment.to_bytes())
- .collect();
-
- let proofs: Vec = blobs
- .iter()
- .zip(commitments.iter())
- .map(|(blob, commitment)| {
- KZGProof::compute_blob_kzg_proof(*blob, *commitment, &kzg_settings).unwrap()
- })
- .map(|proof| proof.to_bytes())
- .collect();
-
- assert!(KZGProof::verify_blob_kzg_proof_batch(
- &blobs,
- &commitments,
- &proofs,
- &kzg_settings
- )
- .unwrap());
-
- blobs.pop();
-
- let error =
- KZGProof::verify_blob_kzg_proof_batch(&blobs, &commitments, &proofs, &kzg_settings)
- .unwrap_err();
- assert!(matches!(error, Error::MismatchLength(_)));
-
- let incorrect_blob = generate_random_blob(&mut rng);
- blobs.push(incorrect_blob);
-
- assert!(!KZGProof::verify_blob_kzg_proof_batch(
- &blobs,
- &commitments,
- &proofs,
- &kzg_settings
- )
- .unwrap());
- }
-
- #[test]
- fn test_end_to_end() {
- let trusted_setup_file = if cfg!(feature = "minimal-spec") {
- PathBuf::from("../../src/trusted_setup_4.txt")
- } else {
- PathBuf::from("../../src/trusted_setup.txt")
- };
- test_simple(trusted_setup_file);
- }
-
- const BLOB_TO_KZG_COMMITMENT_TESTS: &str = "../../tests/blob_to_kzg_commitment/*/*/*";
- const COMPUTE_KZG_PROOF_TESTS: &str = "../../tests/compute_kzg_proof/*/*/*";
- const COMPUTE_BLOB_KZG_PROOF_TESTS: &str = "../../tests/compute_blob_kzg_proof/*/*/*";
- const VERIFY_KZG_PROOF_TESTS: &str = "../../tests/verify_kzg_proof/*/*/*";
- const VERIFY_BLOB_KZG_PROOF_TESTS: &str = "../../tests/verify_blob_kzg_proof/*/*/*";
- const VERIFY_BLOB_KZG_PROOF_BATCH_TESTS: &str = "../../tests/verify_blob_kzg_proof_batch/*/*/*";
-
- #[cfg(not(feature = "minimal-spec"))]
- #[test]
- fn test_blob_to_kzg_commitment() {
- let trusted_setup_file = PathBuf::from("../../src/trusted_setup.txt");
- assert!(trusted_setup_file.exists());
- let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file).unwrap();
- let test_files: Vec = glob::glob(BLOB_TO_KZG_COMMITMENT_TESTS)
- .unwrap()
- .map(Result::unwrap)
- .collect();
- assert!(!test_files.is_empty());
-
- for test_file in test_files {
- let yaml_data = fs::read_to_string(test_file).unwrap();
- let test: blob_to_kzg_commitment_test::Test = serde_yaml::from_str(&yaml_data).unwrap();
- let Ok(blob) = test.input.get_blob() else {
- assert!(test.get_output().is_none());
- continue;
- };
-
- match KZGCommitment::blob_to_kzg_commitment(blob, &kzg_settings) {
- Ok(res) => assert_eq!(res.bytes, test.get_output().unwrap().bytes),
- _ => assert!(test.get_output().is_none()),
- }
- }
- }
-
- #[cfg(not(feature = "minimal-spec"))]
- #[test]
- fn test_compute_kzg_proof() {
- let trusted_setup_file = PathBuf::from("../../src/trusted_setup.txt");
- assert!(trusted_setup_file.exists());
- let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file).unwrap();
- let test_files: Vec = glob::glob(COMPUTE_KZG_PROOF_TESTS)
- .unwrap()
- .map(Result::unwrap)
- .collect();
- assert!(!test_files.is_empty());
-
- for test_file in test_files {
- let yaml_data = fs::read_to_string(test_file).unwrap();
- let test: compute_kzg_proof::Test = serde_yaml::from_str(&yaml_data).unwrap();
- let (Ok(blob), Ok(z)) = (test.input.get_blob(), test.input.get_z()) else {
- assert!(test.get_output().is_none());
- continue;
- };
-
- match KZGProof::compute_kzg_proof(blob, z, &kzg_settings) {
- Ok((proof, y)) => {
- assert_eq!(proof.bytes, test.get_output().unwrap().0.bytes);
- assert_eq!(y.bytes, test.get_output().unwrap().1.bytes);
- }
- _ => assert!(test.get_output().is_none()),
- }
- }
- }
-
- #[cfg(not(feature = "minimal-spec"))]
- #[test]
- fn test_compute_blob_kzg_proof() {
- let trusted_setup_file = PathBuf::from("../../src/trusted_setup.txt");
- assert!(trusted_setup_file.exists());
- let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file).unwrap();
- let test_files: Vec = glob::glob(COMPUTE_BLOB_KZG_PROOF_TESTS)
- .unwrap()
- .map(Result::unwrap)
- .collect();
- assert!(!test_files.is_empty());
-
- for test_file in test_files {
- let yaml_data = fs::read_to_string(test_file).unwrap();
- let test: compute_blob_kzg_proof::Test = serde_yaml::from_str(&yaml_data).unwrap();
- let (Ok(blob), Ok(commitment)) = (
- test.input.get_blob(),
- test.input.get_commitment()
- ) else {
- assert!(test.get_output().is_none());
- continue;
- };
-
- match KZGProof::compute_blob_kzg_proof(blob, commitment, &kzg_settings) {
- Ok(res) => assert_eq!(res.bytes, test.get_output().unwrap().bytes),
- _ => assert!(test.get_output().is_none()),
- }
- }
- }
-
- #[cfg(not(feature = "minimal-spec"))]
- #[test]
- fn test_verify_kzg_proof() {
- let trusted_setup_file = PathBuf::from("../../src/trusted_setup.txt");
- assert!(trusted_setup_file.exists());
- let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file).unwrap();
- let test_files: Vec = glob::glob(VERIFY_KZG_PROOF_TESTS)
- .unwrap()
- .map(Result::unwrap)
- .collect();
- assert!(!test_files.is_empty());
-
- for test_file in test_files {
- let yaml_data = fs::read_to_string(test_file).unwrap();
- let test: verify_kzg_proof::Test = serde_yaml::from_str(&yaml_data).unwrap();
- let (Ok(commitment), Ok(z), Ok(y), Ok(proof)) = (
- test.input.get_commitment(),
- test.input.get_z(),
- test.input.get_y(),
- test.input.get_proof()
- ) else {
- assert!(test.get_output().is_none());
- continue;
- };
-
- match KZGProof::verify_kzg_proof(commitment, z, y, proof, &kzg_settings) {
- Ok(res) => assert_eq!(res, test.get_output().unwrap()),
- _ => assert!(test.get_output().is_none()),
- }
- }
- }
-
- #[cfg(not(feature = "minimal-spec"))]
- #[test]
- fn test_verify_blob_kzg_proof() {
- let trusted_setup_file = PathBuf::from("../../src/trusted_setup.txt");
- assert!(trusted_setup_file.exists());
- let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file).unwrap();
- let test_files: Vec = glob::glob(VERIFY_BLOB_KZG_PROOF_TESTS)
- .unwrap()
- .map(Result::unwrap)
- .collect();
- assert!(!test_files.is_empty());
-
- for test_file in test_files {
- let yaml_data = fs::read_to_string(test_file).unwrap();
- let test: verify_blob_kzg_proof::Test = serde_yaml::from_str(&yaml_data).unwrap();
- let (Ok(blob), Ok(commitment), Ok(proof)) = (
- test.input.get_blob(),
- test.input.get_commitment(),
- test.input.get_proof()
- ) else {
- assert!(test.get_output().is_none());
- continue;
- };
-
- match KZGProof::verify_blob_kzg_proof(blob, commitment, proof, &kzg_settings) {
- Ok(res) => assert_eq!(res, test.get_output().unwrap()),
- _ => assert!(test.get_output().is_none()),
- }
- }
- }
-
- #[cfg(not(feature = "minimal-spec"))]
- #[test]
- fn test_verify_blob_kzg_proof_batch() {
- let trusted_setup_file = PathBuf::from("../../src/trusted_setup.txt");
- assert!(trusted_setup_file.exists());
- let kzg_settings = KZGSettings::load_trusted_setup_file(trusted_setup_file).unwrap();
- let test_files: Vec = glob::glob(VERIFY_BLOB_KZG_PROOF_BATCH_TESTS)
- .unwrap()
- .map(Result::unwrap)
- .collect();
- assert!(!test_files.is_empty());
-
- for test_file in test_files {
- let yaml_data = fs::read_to_string(test_file).unwrap();
- let test: verify_blob_kzg_proof_batch::Test = serde_yaml::from_str(&yaml_data).unwrap();
- let (Ok(blobs), Ok(commitments), Ok(proofs)) = (
- test.input.get_blobs(),
- test.input.get_commitments(),
- test.input.get_proofs()
- ) else {
- assert!(test.get_output().is_none());
- continue;
- };
-
- match KZGProof::verify_blob_kzg_proof_batch(
- &blobs,
- &commitments,
- &proofs,
- &kzg_settings,
- ) {
- Ok(res) => assert_eq!(res, test.get_output().unwrap()),
- _ => assert!(test.get_output().is_none()),
- }
- }
- }
-}
+mod bindings;
+
+// Expose relevant types with idiomatic names.
+pub use bindings::{
+ KZGCommitment as KzgCommitment, KZGProof as KzgProof, KZGSettings as KzgSettings,
+ C_KZG_RET as CkzgError,
+};
+// Expose the constants.
+pub use bindings::{
+ BYTES_PER_BLOB, BYTES_PER_COMMITMENT, BYTES_PER_FIELD_ELEMENT, BYTES_PER_PROOF,
+ FIELD_ELEMENTS_PER_BLOB,
+};
+// Expose the remaining relevant types.
+pub use bindings::{Blob, Bytes32, Bytes48, Error, FFTSettings};