Use official trusted setup (#377)

This commit is contained in:
Justin Traglia 2023-10-18 13:31:55 -05:00 committed by GitHub
parent f3fffecd1c
commit d637761a2e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
372 changed files with 9200 additions and 21717 deletions

View File

@ -35,34 +35,10 @@ jobs:
make format
git diff --exit-code
# Build and test with minimal preset.
- name: Build (minimal)
run: |
export FIELD_ELEMENTS_PER_BLOB=4
make clean && make test_c_kzg_4844
unset FIELD_ELEMENTS_PER_BLOB
- name: Save test binary (minimal)
if: matrix.os == 'windows-latest'
uses: actions/upload-artifact@v3
with:
name: test_minimal_${{matrix.os}}
path: src/test_c_kzg_4844.exe
- name: Test (minimal)
run: make test
# Build and test with mainnet preset.
- name: Build (mainnet)
run: |
export FIELD_ELEMENTS_PER_BLOB=4096
make clean && make test_c_kzg_4844
unset FIELD_ELEMENTS_PER_BLOB
- name: Save test binary (mainnet)
if: matrix.os == 'windows-latest'
uses: actions/upload-artifact@v3
with:
name: test_mainnet_${{matrix.os}}
path: src/test_c_kzg_4844.exe
- name: Test (mainnet)
# Build and test.
- name: Build
run: make test_c_kzg_4844
- name: Test
run: make test
# Run sanitizers.

View File

@ -26,11 +26,7 @@ jobs:
run: |
cd src
make blst
- name: Build and Test (mainnet preset)
- name: Build and Test
run: |
cd bindings/java
make build test
- name: Build and Test (minimal preset)
run: |
cd bindings/java
make PRESET=minimal build test

View File

@ -36,12 +36,9 @@ jobs:
submodules: recursive
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Build and Test (minimal preset)
- name: Build and Test
working-directory: bindings/rust
run: cargo test --features minimal-spec
- name: Build and Test (mainnet preset)
working-directory: bindings/rust
run: cargo test --features mainnet-spec
run: cargo test
- name: Benchmark
working-directory: bindings/rust
run: cargo bench

View File

@ -38,12 +38,10 @@ else
CKZG_LIBRARY_PATH = Ckzg.Bindings/runtimes/$(LOCATION)/native/ckzg$(EXTENSION)
endif
FIELD_ELEMENTS_PER_BLOB ?= 4096
INCLUDE_DIRS = ../../src ../../blst/bindings
TARGETS = ckzg.c ../../src/c_kzg_4844.c ../../blst/$(BLST_OBJ)
CFLAGS += -O2 -Wall -Wextra -Wpedantic -shared
CFLAGS += -DFIELD_ELEMENTS_PER_BLOB=$(FIELD_ELEMENTS_PER_BLOB)
CFLAGS += -O2 -Wall -Wextra -shared
CFLAGS += ${addprefix -I,${INCLUDE_DIRS}}
BLST_BUILDSCRIPT_FLAGS += -D__BLST_PORTABLE__
ifdef ARCH

View File

@ -29,14 +29,6 @@ Run the benchmarks with this command:
go test -bench=Benchmark
```
## Minimal
By default, `FIELD_ELEMENTS_PER_BLOB` will be 4096 (mainnet), but you can
manually set it to 4 (minimal), like so:
```
CGO_CFLAGS="-DFIELD_ELEMENTS_PER_BLOB=4" go build
```
## Note
The `go.mod` and `go.sum` files are in the project's root directory because the

View File

@ -2,9 +2,6 @@ package ckzg4844
// #cgo CFLAGS: -I${SRCDIR}/../../src
// #cgo CFLAGS: -I${SRCDIR}/blst_headers
// #ifndef FIELD_ELEMENTS_PER_BLOB
// #define FIELD_ELEMENTS_PER_BLOB 4096
// #endif
// #include "c_kzg_4844.c"
import "C"

View File

@ -42,15 +42,7 @@ else
GRADLE_COMMAND=./gradlew
endif
PRESET ?= mainnet
ifeq ($(PRESET),minimal)
FIELD_ELEMENTS_PER_BLOB ?= 4
else
FIELD_ELEMENTS_PER_BLOB ?= 4096
endif
LIBRARY_FOLDER=src/main/resources/ethereum/ckzg4844/lib/${OS_ARCH}/${PRESET}
LIBRARY_FOLDER=src/main/resources/ethereum/ckzg4844/lib/${OS_ARCH}
ifeq ($(JAVA_HOME),)
$(error JAVA_HOME is not set and autodetection failed)
@ -61,7 +53,7 @@ all: build test benchmark
.PHONY: build
build:
mkdir -p ${LIBRARY_FOLDER}
${CLANG_EXECUTABLE} ${CC_FLAGS} ${CLANG_FLAGS} ${OPTIMIZATION_LEVEL} -Wall -Wextra -Wpedantic -Werror -Wno-missing-braces -Wno-unused-parameter -Wno-format ${addprefix -I,${INCLUDE_DIRS}} -I"${JAVA_HOME}/include" -I"${JAVA_HOME}/include/${JNI_INCLUDE_FOLDER}" -DFIELD_ELEMENTS_PER_BLOB=${FIELD_ELEMENTS_PER_BLOB} -o ${LIBRARY_FOLDER}/${LIBRARY_RESOURCE} ${TARGETS}
${CLANG_EXECUTABLE} ${CC_FLAGS} ${CLANG_FLAGS} ${OPTIMIZATION_LEVEL} -Wall -Wextra -Werror -Wno-missing-braces -Wno-unused-parameter -Wno-format ${addprefix -I,${INCLUDE_DIRS}} -I"${JAVA_HOME}/include" -I"${JAVA_HOME}/include/${JNI_INCLUDE_FOLDER}" -o ${LIBRARY_FOLDER}/${LIBRARY_RESOURCE} ${TARGETS}
.PHONY: test
test:

View File

@ -14,8 +14,7 @@ make build
```
This will install the shared library in `src/main/resources/ethereum/ckzg4844/lib` with a folder
structure
and name according to the preset selected (mainnet or minimal) and your OS.
structure and name according your OS.
All variables which could be passed to the `make` command and the defaults can be found in
the [Makefile](./Makefile).

View File

@ -56,11 +56,6 @@ KZGSettings *allocate_settings(JNIEnv *env)
return s;
}
JNIEXPORT jint JNICALL Java_ethereum_ckzg4844_CKZG4844JNI_getFieldElementsPerBlob(JNIEnv *env, jclass thisCls)
{
return (jint)FIELD_ELEMENTS_PER_BLOB;
}
JNIEXPORT void JNICALL Java_ethereum_ckzg4844_CKZG4844JNI_loadTrustedSetup__Ljava_lang_String_2(JNIEnv *env, jclass thisCls, jstring file)
{
if (settings)

View File

@ -13,13 +13,10 @@ extern "C" {
#define ethereum_ckzg4844_CKZG4844JNI_BYTES_PER_PROOF 48L
#undef ethereum_ckzg4844_CKZG4844JNI_BYTES_PER_FIELD_ELEMENT
#define ethereum_ckzg4844_CKZG4844JNI_BYTES_PER_FIELD_ELEMENT 32L
/*
* Class: ethereum_ckzg4844_CKZG4844JNI
* Method: getFieldElementsPerBlob
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_ethereum_ckzg4844_CKZG4844JNI_getFieldElementsPerBlob
(JNIEnv *, jclass);
#undef ethereum_ckzg4844_CKZG4844JNI_FIELD_ELEMENTS_PER_BLOB
#define ethereum_ckzg4844_CKZG4844JNI_FIELD_ELEMENTS_PER_BLOB 4096L
#undef ethereum_ckzg4844_CKZG4844JNI_BYTES_PER_BLOB
#define ethereum_ckzg4844_CKZG4844JNI_BYTES_PER_BLOB 131072L
/*
* Class: ethereum_ckzg4844_CKZG4844JNI

View File

@ -1,6 +1,5 @@
package ethereum.ckzg4844;
import ethereum.ckzg4844.CKZG4844JNI.Preset;
import java.util.concurrent.TimeUnit;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
@ -25,7 +24,7 @@ import org.openjdk.jmh.annotations.Warmup;
public class CKZG4844JNIBenchmark {
static {
CKZG4844JNI.loadNativeLibrary(Preset.MAINNET);
CKZG4844JNI.loadNativeLibrary();
}
@State(Scope.Benchmark)

View File

@ -13,19 +13,10 @@ public class CKZG4844JNI {
private static final String LIBRARY_NAME = "ckzg4844jni";
private static final String PLATFORM_NATIVE_LIBRARY_NAME = System.mapLibraryName(LIBRARY_NAME);
/**
* Loads the appropriate native library based on your platform and the selected {@link Preset}
*
* @param preset the preset
*/
public static void loadNativeLibrary(Preset preset) {
/** Loads the appropriate native library based on your platform. */
public static void loadNativeLibrary() {
String libraryResourcePath =
"lib/"
+ System.getProperty("os.arch")
+ "/"
+ preset.name().toLowerCase()
+ "/"
+ PLATFORM_NATIVE_LIBRARY_NAME;
"lib/" + System.getProperty("os.arch") + "/" + PLATFORM_NATIVE_LIBRARY_NAME;
InputStream libraryResource = CKZG4844JNI.class.getResourceAsStream(libraryResourcePath);
if (libraryResource == null) {
try {
@ -52,17 +43,6 @@ public class CKZG4844JNI {
}
}
public enum Preset {
MAINNET(4096),
MINIMAL(4);
public final int fieldElementsPerBlob;
Preset(int fieldElementsPerBlob) {
this.fieldElementsPerBlob = fieldElementsPerBlob;
}
}
/** Scalar field modulus of BLS12-381 */
public static final BigInteger BLS_MODULUS =
new BigInteger(
@ -77,26 +57,13 @@ public class CKZG4844JNI {
public static final int BYTES_PER_PROOF = 48;
/** Bytes used to encode a BLS scalar field element */
public static final int BYTES_PER_FIELD_ELEMENT = 32;
/** Number of field elements in a blob */
public static final int FIELD_ELEMENTS_PER_BLOB = 4096;
/** Number of field elements in a blob */
public static final int BYTES_PER_BLOB = FIELD_ELEMENTS_PER_BLOB * BYTES_PER_FIELD_ELEMENT;
private CKZG4844JNI() {}
/**
* Calculates the bytes per blob based on the output from {@link #getFieldElementsPerBlob()}
*
* @return the bytes per blob
*/
public static int getBytesPerBlob() {
return getFieldElementsPerBlob() * BYTES_PER_FIELD_ELEMENT;
}
/**
* Retrieves the compile-time configured FIELD_ELEMENTS_PER_BLOB. The value will be based on the
* selected {@link Preset} when loading the native library.
*
* @return the field elements per blob
*/
public static native int getFieldElementsPerBlob();
/**
* Loads the trusted setup from a file. Once loaded, the same setup will be used for all the
* crypto native calls. To load a new setup, free the current one by calling {@link

View File

@ -8,10 +8,7 @@ import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import ethereum.ckzg4844.CKZG4844JNI.Preset;
import ethereum.ckzg4844.test_formats.*;
import java.util.Map;
import java.util.Optional;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
@ -26,43 +23,18 @@ public class CKZG4844JNITest {
RESOURCE
}
private static final Preset PRESET;
private static final Map<Preset, String> TRUSTED_SETUP_FILE_BY_PRESET =
Map.of(
Preset.MAINNET,
"../../src/trusted_setup.txt",
Preset.MINIMAL,
"../../src/trusted_setup_4.txt");
private static final Map<Preset, String> TRUSTED_SETUP_RESOURCE_BY_PRESET =
Map.of(
Preset.MAINNET,
"/trusted-setups/trusted_setup.txt",
Preset.MINIMAL,
"/trusted-setups/trusted_setup_4.txt");
private static final Map<Preset, String> OLD_TRUSTED_SETUP_FILE_BY_PRESET =
Map.of(
Preset.MAINNET,
"./src/testFixtures/resources/trusted-setups/trusted_setup_old.txt",
Preset.MINIMAL,
"./src/testFixtures/resources/trusted-setups/trusted_setup_4_old.txt");
private static final String TRUSTED_SETUP_FILE = "../../src/trusted_setup.txt";
private static final String TRUSTED_SETUP_RESOURCE = "/trusted-setups/trusted_setup.txt";
private static final String OLD_TRUSTED_SETUP_FILE =
"./src/testFixtures/resources/trusted-setups/trusted_setup_old.txt";
static {
PRESET =
Optional.ofNullable(System.getenv("PRESET"))
.map(String::toUpperCase)
.map(Preset::valueOf)
.orElse(Preset.MAINNET);
CKZG4844JNI.loadNativeLibrary(PRESET);
CKZG4844JNI.loadNativeLibrary();
}
@ParameterizedTest
@MethodSource("getBlobToKzgCommitmentTests")
public void blobToKzgCommitmentTests(final BlobToKzgCommitmentTest test) {
if (PRESET != Preset.MAINNET) return;
try {
byte[] commitment = CKZG4844JNI.blobToKzgCommitment(test.getInput().getBlob());
assertArrayEquals(test.getOutput(), commitment);
@ -74,8 +46,6 @@ public class CKZG4844JNITest {
@ParameterizedTest
@MethodSource("getComputeKzgProofTests")
public void computeKzgProofTests(final ComputeKzgProofTest test) {
if (PRESET != Preset.MAINNET) return;
try {
ProofAndY proofAndY =
CKZG4844JNI.computeKzgProof(test.getInput().getBlob(), test.getInput().getZ());
@ -89,8 +59,6 @@ public class CKZG4844JNITest {
@ParameterizedTest
@MethodSource("getComputeBlobKzgProofTests")
public void computeBlobKzgProofTests(final ComputeBlobKzgProofTest test) {
if (PRESET != Preset.MAINNET) return;
try {
byte[] proof =
CKZG4844JNI.computeBlobKzgProof(
@ -104,8 +72,6 @@ public class CKZG4844JNITest {
@ParameterizedTest
@MethodSource("getVerifyKzgProofTests")
public void verifyKzgProofTests(final VerifyKzgProofTest test) {
if (PRESET != Preset.MAINNET) return;
try {
boolean valid =
CKZG4844JNI.verifyKzgProof(
@ -122,8 +88,6 @@ public class CKZG4844JNITest {
@ParameterizedTest
@MethodSource("getVerifyBlobKzgProofTests")
public void verifyBlobKzgProofTests(final VerifyBlobKzgProofTest test) {
if (PRESET != Preset.MAINNET) return;
try {
boolean valid =
CKZG4844JNI.verifyBlobKzgProof(
@ -139,10 +103,8 @@ public class CKZG4844JNITest {
@ParameterizedTest
@MethodSource("getVerifyBlobKzgProofBatchTests")
public void verifyBlobKzgProofBatchTests(final VerifyBlobKzgProofBatchTest test) {
if (PRESET != Preset.MAINNET) return;
try {
int count = test.getInput().getBlobs().length / CKZG4844JNI.getBytesPerBlob();
int count = test.getInput().getBlobs().length / CKZG4844JNI.BYTES_PER_BLOB;
boolean valid =
CKZG4844JNI.verifyBlobKzgProofBatch(
test.getInput().getBlobs(),
@ -155,14 +117,6 @@ public class CKZG4844JNITest {
}
}
@Test
public void getsTheConfiguredFieldElementsPerBlob() {
assertEquals(PRESET.fieldElementsPerBlob, CKZG4844JNI.getFieldElementsPerBlob());
assertEquals(
PRESET.fieldElementsPerBlob * CKZG4844JNI.BYTES_PER_FIELD_ELEMENT,
CKZG4844JNI.getBytesPerBlob());
}
@ParameterizedTest
@EnumSource(TrustedSetupSource.class)
public void testVerifyBlobKzgProofBatch(final TrustedSetupSource trustedSetupSource) {
@ -263,7 +217,7 @@ public class CKZG4844JNITest {
assertEquals(C_KZG_BADARGS, exception.getError());
assertEquals(
String.format(
"Invalid blob size. Expected %d bytes but got 0.", CKZG4844JNI.getBytesPerBlob()),
"Invalid blob size. Expected %d bytes but got 0.", CKZG4844JNI.BYTES_PER_BLOB),
exception.getErrorMessage());
exception =
@ -274,7 +228,7 @@ public class CKZG4844JNITest {
assertEquals(C_KZG_BADARGS, exception.getError());
assertEquals(
String.format(
"Invalid blob size. Expected %d bytes but got 123.", CKZG4844JNI.getBytesPerBlob()),
"Invalid blob size. Expected %d bytes but got 123.", CKZG4844JNI.BYTES_PER_BLOB),
exception.getErrorMessage());
exception =
@ -282,7 +236,7 @@ public class CKZG4844JNITest {
CKZGException.class,
() ->
CKZG4844JNI.computeBlobKzgProof(
new byte[CKZG4844JNI.getBytesPerBlob()], new byte[49]));
new byte[CKZG4844JNI.BYTES_PER_BLOB], new byte[49]));
assertEquals(C_KZG_BADARGS, exception.getError());
assertEquals(
@ -301,7 +255,7 @@ public class CKZG4844JNITest {
assertEquals(C_KZG_BADARGS, exception.getError());
assertEquals(
String.format(
"Invalid blobs size. Expected %d bytes but got 42.", CKZG4844JNI.getBytesPerBlob() * 2),
"Invalid blobs size. Expected %d bytes but got 42.", CKZG4844JNI.BYTES_PER_BLOB * 2),
exception.getErrorMessage());
CKZG4844JNI.freeTrustedSetup();
@ -346,8 +300,7 @@ public class CKZG4844JNITest {
public void shouldThrowExceptionIfTrustedSetupIsNotInLagrangeForm() {
CKZGException exception =
assertThrows(
CKZGException.class,
() -> CKZG4844JNI.loadTrustedSetup(OLD_TRUSTED_SETUP_FILE_BY_PRESET.get(PRESET)));
CKZGException.class, () -> CKZG4844JNI.loadTrustedSetup(OLD_TRUSTED_SETUP_FILE));
assertEquals(C_KZG_BADARGS, exception.getError());
}
@ -355,7 +308,7 @@ public class CKZG4844JNITest {
@Test
public void shouldThrowExceptionOnIncorrectTrustedSetupParameters() {
final LoadTrustedSetupParameters parameters =
TestUtils.createLoadTrustedSetupParameters(TRUSTED_SETUP_FILE_BY_PRESET.get(PRESET));
TestUtils.createLoadTrustedSetupParameters(TRUSTED_SETUP_FILE);
// wrong g1Count
CKZGException exception =
@ -384,16 +337,6 @@ public class CKZG4844JNITest {
assertTrue(exception.getErrorMessage().contains("Invalid g2 size."));
}
@Test
public void shouldThrowExceptionOnIncorrectTrustedSetupFromFile() {
final Preset incorrectPreset = PRESET == Preset.MAINNET ? Preset.MINIMAL : Preset.MAINNET;
final CKZGException exception =
assertThrows(
CKZGException.class,
() -> CKZG4844JNI.loadTrustedSetup(TRUSTED_SETUP_FILE_BY_PRESET.get(incorrectPreset)));
assertEquals(C_KZG_BADARGS, exception.getError());
}
private void assertExceptionIsTrustedSetupIsNotLoaded(final RuntimeException exception) {
assertEquals("Trusted Setup is not loaded.", exception.getMessage());
}
@ -413,19 +356,18 @@ public class CKZG4844JNITest {
}
private static void loadTrustedSetup() {
CKZG4844JNI.loadTrustedSetup(TRUSTED_SETUP_FILE_BY_PRESET.get(PRESET));
CKZG4844JNI.loadTrustedSetup(TRUSTED_SETUP_FILE);
}
private static void loadTrustedSetupFromParameters() {
final LoadTrustedSetupParameters parameters =
TestUtils.createLoadTrustedSetupParameters(TRUSTED_SETUP_FILE_BY_PRESET.get(PRESET));
TestUtils.createLoadTrustedSetupParameters(TRUSTED_SETUP_FILE);
CKZG4844JNI.loadTrustedSetup(
parameters.getG1(), parameters.getG1Count(), parameters.getG2(), parameters.getG2Count());
}
public static void loadTrustedSetupFromResource() {
CKZG4844JNI.loadTrustedSetupFromResource(
TRUSTED_SETUP_RESOURCE_BY_PRESET.get(PRESET), CKZG4844JNITest.class);
CKZG4844JNI.loadTrustedSetupFromResource(TRUSTED_SETUP_RESOURCE, CKZG4844JNITest.class);
}
private static Stream<BlobToKzgCommitmentTest> getBlobToKzgCommitmentTests() {

View File

@ -46,7 +46,7 @@ public class TestUtils {
public static byte[] createRandomBlob() {
final byte[][] blob =
IntStream.range(0, CKZG4844JNI.getFieldElementsPerBlob())
IntStream.range(0, CKZG4844JNI.FIELD_ELEMENTS_PER_BLOB)
.mapToObj(__ -> randomBLSFieldElement())
.map(fieldElement -> fieldElement.toArray(ByteOrder.BIG_ENDIAN))
.toArray(byte[][]::new);
@ -81,7 +81,7 @@ public class TestUtils {
public static byte[] createNonCanonicalBlob() {
final byte[][] blob =
IntStream.range(0, CKZG4844JNI.getFieldElementsPerBlob())
IntStream.range(0, CKZG4844JNI.FIELD_ELEMENTS_PER_BLOB)
.mapToObj(__ -> UInt256.valueOf(CKZG4844JNI.BLS_MODULUS.add(BigInteger.valueOf(42))))
.map(greaterThanModulus -> greaterThanModulus.toArray(ByteOrder.BIG_ENDIAN))
.toArray(byte[][]::new);

View File

@ -1,71 +0,0 @@
4
65
91131b2e3c1e5f0b51df8970e67080032f411571b66d301436c46f25bbfddf9ca16756430dc470bdb0d85b47fedcdbc1
934d35b2a46e169915718b77127b0d4efbacdad7fdde4593af7d21d37ebcb77fe6c8dde6b8a9537854d70ef1f291a585
9410ca1d0342fe7419f02194281df45e1c1ff42fd8b439de5644cc312815c21ddd2e3eeb63fb807cf837e68b76668bd5
b163df7e9baeb60f69b6ee5faa538c3a564b62eb8cde6a3616083c8cb2171eedd583c9143e7e916df59bf27da5e024e8
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8

View File

@ -1,71 +0,0 @@
4
65
97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb
854262641262cb9e056a8512808ea6864d903dbcad713fd6da8dddfa5ce40d85612c912063ace060ed8c4bf005bab839
86f708eee5ae0cf40be36993e760d9cb3b2371f22db3209947c5d21ea68e55186b30871c50bf11ef29e5248bf42d5678
94f9c0bafb23cbbf34a93a64243e3e0f934b57593651f3464de7dc174468123d9698f1b9dfa22bb5b6eb96eae002f29f
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8

View File

@ -3,14 +3,11 @@
############################################################
import
std/[strformat, strutils]
std/strutils
from os import DirSep, AltSep
const
# FIELD_ELEMENTS_PER_BLOB is overrideable from
# compiler switch -d: or --define:
FIELD_ELEMENTS_PER_BLOB* {.intdefine.} = 4096
# kzgPath: c-kzg-4844 project path, removing 3 last elem
kzgPath = currentSourcePath.rsplit({DirSep, AltSep}, 3)[0] & "/"
blstPath = kzgPath & "blst/"
@ -25,12 +22,11 @@ when not defined(kzgExternalBlst):
{.compile: srcPath & "c_kzg_4844.c"}
{.passc: "-I" & bindingsPath &
" -DFIELD_ELEMENTS_PER_BLOB=" &
fmt"{FIELD_ELEMENTS_PER_BLOB}".}
{.passc: "-I" & bindingsPath .}
{.passc: "-I" & srcPath .}
const
FIELD_ELEMENTS_PER_BLOB* = 4096
BYTES_PER_FIELD_ELEMENT* = 32
KzgBlobSize* = FIELD_ELEMENTS_PER_BLOB*BYTES_PER_FIELD_ELEMENT

View File

@ -77,7 +77,7 @@ suite "verify proof (high-level)":
test "template aliases":
# no need to check return value
# only test if those templates can be compiled succesfully
# only test if those templates can be compiled successfully
let res = loadTrustedSetupFile(trustedSetupFile)
check res.isOk
ctx = res.get

View File

@ -74,7 +74,7 @@ suite "verify proof (extended version)":
test "template aliases":
# no need to check return value
# only test if those templates can be compiled succesfully
# only test if those templates can be compiled successfully
check Kzg.freeTrustedSetup().isOk
check Kzg.loadTrustedSetupFile(trustedSetupFile).isOk
discard blobToKzgCommitment(blob)

File diff suppressed because one or more lines are too long

View File

@ -3,4 +3,4 @@ deps
dist
*.node
node_modules
test/__fixtures__/testing_trusted_setups.*
test/__fixtures__/trusted_setup.*

View File

@ -19,7 +19,6 @@
"conditions": [
["OS!='win'", {
"sources": ["deps/blst/build/assembly.S"],
"defines": ["FIELD_ELEMENTS_PER_BLOB=<!(echo ${FIELD_ELEMENTS_PER_BLOB:-4096})"],
"cflags_cc": [
"-std=c++17",
"-fPIC"
@ -29,7 +28,6 @@
"sources": ["deps/blst/build/win64/*-x86_64.asm"],
"defines": [
"_CRT_SECURE_NO_WARNINGS",
"FIELD_ELEMENTS_PER_BLOB=<!(powershell -Command \"if ($env:FIELD_ELEMENTS_PER_BLOB) { $env:FIELD_ELEMENTS_PER_BLOB } else { 4096 }\")"
],
"msbuild_settings": {
"ClCompile": {

View File

@ -23,9 +23,9 @@ function transformTrustedSetupJson(filePath) {
const setupText =
bindings.FIELD_ELEMENTS_PER_BLOB +
"\n65\n" +
trustedSetup.setup_G1_lagrange.map((p) => p.substring(2)).join("\n") +
trustedSetup.g1_lagrange.map((p) => p.substring(2)).join("\n") +
"\n" +
trustedSetup.setup_G2.map((p) => p.substring(2)).join("\n");
trustedSetup.g2_monomial.map((p) => p.substring(2)).join("\n");
const outputPath = filePath.replace(".json", ".txt");
fs.writeFileSync(outputPath, setupText);
return outputPath;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -25,7 +25,7 @@ import {
ProofResult,
} from "../lib/kzg";
const SETUP_FILE_PATH = resolve(__dirname, "__fixtures__", "testing_trusted_setups.json");
const SETUP_FILE_PATH = resolve(__dirname, "__fixtures__", "trusted_setup.json");
const MAX_TOP_BYTE = 114;

View File

@ -10,7 +10,6 @@ def main():
"ckzg",
sources=["ckzg.c", "../../src/c_kzg_4844.c"],
include_dirs=["../../inc", "../../src"],
define_macros=[("FIELD_ELEMENTS_PER_BLOB", "4096")],
library_dirs=["../../lib"],
libraries=["blst"])])

View File

@ -3,18 +3,14 @@ name = "c-kzg"
version = "0.1.0"
edition = "2021"
license = "Apache-2.0"
# XXX: Note that we don't set a `links` attribute for Cargo, because this library may link
# either `ckzg` or `ckzg_min`. This allows the crate to be linked twice as minimal/mainnet variants
# without Cargo complaining.
links = "ckzg"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
default = ["std", "mainnet-spec"]
default = ["std"]
std = ["hex/std", "libc/std", "serde?/std"]
serde = ["dep:serde"]
mainnet-spec = []
minimal-spec = []
# BLST Compilation:
# Suppress multi-threading.

View File

@ -8,9 +8,6 @@ Generates the rust bindings for the c-kzg library.
cargo build --release
```
Build with `--features="minimal-spec"` to set the `FIELD_ELEMENTS_PER_BLOB`
compile time parameter to the pre-determined minimal spec value.
## Test
```

View File

@ -1,9 +1,6 @@
use std::env;
use std::path::PathBuf;
const MAINNET_FIELD_ELEMENTS_PER_BLOB: usize = 4096;
const MINIMAL_FIELD_ELEMENTS_PER_BLOB: usize = 4;
fn main() {
let cargo_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let root_dir = cargo_dir
@ -12,15 +9,6 @@ fn main() {
.parent()
.expect("bindings dir is nested");
let (lib_name, field_elements_per_blob) = if cfg!(feature = "minimal-spec") {
("ckzg_min", MINIMAL_FIELD_ELEMENTS_PER_BLOB)
} else {
("ckzg", MAINNET_FIELD_ELEMENTS_PER_BLOB)
};
eprintln!("Using LIB_PREFIX={lib_name}");
eprintln!("Using FIELD_ELEMENTS_PER_BLOB={field_elements_per_blob}");
// Obtain the header files of blst
let blst_base_dir = root_dir.join("blst");
let blst_headers_dir = blst_base_dir.join("bindings");
@ -42,11 +30,9 @@ fn main() {
cc.include(blst_headers_dir.clone());
cc.warnings(false);
cc.flag(format!("-DLIB_PREFIX={lib_name}").as_str());
cc.flag(format!("-DFIELD_ELEMENTS_PER_BLOB={}", field_elements_per_blob).as_str());
cc.file(c_src_dir.join("c_kzg_4844.c"));
cc.try_compile(lib_name).expect("Failed to compile ckzg");
cc.try_compile("ckzg").expect("Failed to compile ckzg");
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
let bindings_out_path = out_dir.join("generated.rs");
@ -54,20 +40,16 @@ fn main() {
let header_file = header_file_path.to_str().expect("valid header file");
make_bindings(
lib_name,
field_elements_per_blob,
header_file,
&blst_headers_dir.to_string_lossy(),
bindings_out_path,
);
// Finally, tell cargo this provides ckzg/ckzg_min
println!("cargo:rustc-link-lib={lib_name}");
println!("cargo:rustc-link-lib=ckzg");
}
fn make_bindings<P>(
lib_name: &str,
field_elements_per_blob: usize,
header_path: &str,
blst_headers_dir: &str,
bindings_out_path: P,
@ -98,20 +80,8 @@ fn make_bindings<P>(
/*
* 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 LIB_PREFIX {lib_name}
#define FIELD_ELEMENTS_PER_BLOB {field_elements_per_blob}"
),
)
.header(header_path)
.clang_args([format!("-I{blst_headers_dir}")])
// Since this is not part of the header file, needs to be allowed explicitly.
.allowlist_var("LIB_PREFIX")
.allowlist_var("FIELD_ELEMENTS_PER_BLOB")
// Get bindings only for the header file.
.allowlist_file(".*c_kzg_4844.h")
/*

View File

@ -9,30 +9,6 @@ mod test_formats;
include!(concat!(env!("OUT_DIR"), "/generated.rs"));
#[cfg(not(feature = "minimal-spec"))]
use {
ckzg_blob_to_kzg_commitment as blob_to_kzg_commitment,
ckzg_compute_blob_kzg_proof as compute_blob_kzg_proof,
ckzg_compute_kzg_proof as compute_kzg_proof, ckzg_free_trusted_setup as free_trusted_setup,
ckzg_load_trusted_setup as load_trusted_setup,
ckzg_load_trusted_setup_file as load_trusted_setup_file,
ckzg_verify_blob_kzg_proof as verify_blob_kzg_proof,
ckzg_verify_blob_kzg_proof_batch as verify_blob_kzg_proof_batch,
ckzg_verify_kzg_proof as verify_kzg_proof,
};
#[cfg(feature = "minimal-spec")]
use {
ckzg_min_blob_to_kzg_commitment as blob_to_kzg_commitment,
ckzg_min_compute_blob_kzg_proof as compute_blob_kzg_proof,
ckzg_min_compute_kzg_proof as compute_kzg_proof,
ckzg_min_free_trusted_setup as free_trusted_setup,
ckzg_min_load_trusted_setup as load_trusted_setup,
ckzg_min_load_trusted_setup_file as load_trusted_setup_file,
ckzg_min_verify_blob_kzg_proof as verify_blob_kzg_proof,
ckzg_min_verify_blob_kzg_proof_batch as verify_blob_kzg_proof_batch,
ckzg_min_verify_kzg_proof as verify_kzg_proof,
};
use alloc::string::String;
use alloc::vec::Vec;
use core::ffi::CStr;
@ -660,11 +636,7 @@ mod tests {
#[test]
fn test_end_to_end() {
let trusted_setup_file = if cfg!(feature = "minimal-spec") {
Path::new("../../src/trusted_setup_4.txt")
} else {
Path::new("../../src/trusted_setup.txt")
};
let trusted_setup_file = Path::new("../../src/trusted_setup.txt");
test_simple(trusted_setup_file);
}
@ -675,7 +647,6 @@ mod tests {
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 = Path::new("../../src/trusted_setup.txt");
@ -702,7 +673,6 @@ mod tests {
}
}
#[cfg(not(feature = "minimal-spec"))]
#[test]
fn test_compute_kzg_proof() {
let trusted_setup_file = Path::new("../../src/trusted_setup.txt");
@ -732,7 +702,6 @@ mod tests {
}
}
#[cfg(not(feature = "minimal-spec"))]
#[test]
fn test_compute_blob_kzg_proof() {
let trusted_setup_file = Path::new("../../src/trusted_setup.txt");
@ -760,7 +729,6 @@ mod tests {
}
}
#[cfg(not(feature = "minimal-spec"))]
#[test]
fn test_verify_kzg_proof() {
let trusted_setup_file = Path::new("../../src/trusted_setup.txt");
@ -792,7 +760,6 @@ mod tests {
}
}
#[cfg(not(feature = "minimal-spec"))]
#[test]
fn test_verify_blob_kzg_proof() {
let trusted_setup_file = Path::new("../../src/trusted_setup.txt");
@ -823,7 +790,6 @@ mod tests {
}
}
#[cfg(not(feature = "minimal-spec"))]
#[test]
fn test_verify_blob_kzg_proof_batch() {
let trusted_setup_file = Path::new("../../src/trusted_setup.txt");

View File

@ -82,11 +82,7 @@ mod tests {
}
fn trusted_setup_file() -> &'static Path {
if cfg!(feature = "minimal-spec") {
Path::new("../../src/trusted_setup_4.txt")
} else {
Path::new("../../src/trusted_setup.txt")
}
Path::new("../../src/trusted_setup.txt")
}
#[test]

View File

@ -7,7 +7,7 @@ CC = clang
FIELD_ELEMENTS_PER_BLOB ?= 4096
CFLAGS += -I../inc
CFLAGS += -Wall -Wextra -Wpedantic -Werror -O0
CFLAGS += -Wall -Wextra -Werror -O0
CFLAGS += -DFIELD_ELEMENTS_PER_BLOB=$(FIELD_ELEMENTS_PER_BLOB)
CFLAGS += -g -fsanitize=fuzzer

View File

@ -19,13 +19,8 @@ ifeq ($(PLATFORM),Darwin)
XCRUN = xcrun
endif
# By default, this is set to the mainnet value.
FIELD_ELEMENTS_PER_BLOB ?= 4096
# The base compiler flags. More can be added on command line.
CFLAGS += -I../inc
CFLAGS += -DFIELD_ELEMENTS_PER_BLOB=$(FIELD_ELEMENTS_PER_BLOB)
CFLAGS += -O2 -Wall -Wextra -Wpedantic
CFLAGS += -I../inc -O2 -Wall -Wextra
# Cross-platform compilation settings.
ifeq ($(PLATFORM),Windows)

View File

@ -863,7 +863,7 @@ static C_KZG_RET poly_to_kzg_commitment(
* @param[in] blob The blob representing the polynomial to be committed to
* @param[in] s The trusted setup
*/
C_KZG_RET BLOB_TO_KZG_COMMITMENT(
C_KZG_RET blob_to_kzg_commitment(
KZGCommitment *out, const Blob *blob, const KZGSettings *s
) {
C_KZG_RET ret;
@ -898,7 +898,7 @@ static C_KZG_RET verify_kzg_proof_impl(
* @param[in] kzg_proof The KZG proof
* @param[in] s The trusted setup
*/
C_KZG_RET VERIFY_KZG_PROOF(
C_KZG_RET verify_kzg_proof(
bool *ok,
const Bytes48 *commitment_bytes,
const Bytes32 *z_bytes,
@ -987,7 +987,7 @@ static C_KZG_RET compute_kzg_proof_impl(
* @param[in] z The generator z-value for the evaluation points
* @param[in] s The trusted setup
*/
C_KZG_RET COMPUTE_KZG_PROOF(
C_KZG_RET compute_kzg_proof(
KZGProof *proof_out,
Bytes32 *y_out,
const Blob *blob,
@ -1113,7 +1113,7 @@ out:
* @param[in] commitment_bytes Commitment to verify
* @param[in] s The trusted setup
*/
C_KZG_RET COMPUTE_BLOB_KZG_PROOF(
C_KZG_RET compute_blob_kzg_proof(
KZGProof *out,
const Blob *blob,
const Bytes48 *commitment_bytes,
@ -1154,7 +1154,7 @@ out:
* @param[in] proof_bytes Proof used for verification
* @param[in] s The trusted setup
*/
C_KZG_RET VERIFY_BLOB_KZG_PROOF(
C_KZG_RET verify_blob_kzg_proof(
bool *ok,
const Blob *blob,
const Bytes48 *commitment_bytes,
@ -1367,7 +1367,7 @@ out:
* @param[in] n The number of blobs/commitments/proofs
* @param[in] s The trusted setup
*/
C_KZG_RET VERIFY_BLOB_KZG_PROOF_BATCH(
C_KZG_RET verify_blob_kzg_proof_batch(
bool *ok,
const Blob *blobs,
const Bytes48 *commitments_bytes,
@ -1389,7 +1389,7 @@ C_KZG_RET VERIFY_BLOB_KZG_PROOF_BATCH(
/* For a single blob, just do a regular single verification */
if (n == 1) {
return VERIFY_BLOB_KZG_PROOF(
return verify_blob_kzg_proof(
ok, &blobs[0], &commitments_bytes[0], &proofs_bytes[0], s
);
}
@ -1627,7 +1627,7 @@ out:
*
* @param[in] s The trusted setup to free
*/
void FREE_TRUSTED_SETUP(KZGSettings *s) {
void free_trusted_setup(KZGSettings *s) {
if (s == NULL) return;
s->max_width = 0;
c_kzg_free(s->roots_of_unity);
@ -1673,7 +1673,7 @@ static C_KZG_RET is_trusted_setup_in_lagrange_form(
* @param[in] g2_bytes Array of G2 points in monomial form
* @param[in] n2 Number of `g2` points in g2_bytes
*/
C_KZG_RET LOAD_TRUSTED_SETUP(
C_KZG_RET load_trusted_setup(
KZGSettings *out,
const uint8_t *g1_bytes,
size_t n1,
@ -1751,7 +1751,7 @@ out_error:
* (roots_of_unity, g1_values, g2_values). It does not free the KZGSettings
* structure memory. If necessary, that must be done by the caller.
*/
FREE_TRUSTED_SETUP(out);
free_trusted_setup(out);
out_success:
return ret;
}
@ -1769,7 +1769,7 @@ out_success:
* @param[out] out Pointer to the loaded trusted setup data
* @param[in] in File handle for input
*/
C_KZG_RET LOAD_TRUSTED_SETUP_FILE(KZGSettings *out, FILE *in) {
C_KZG_RET load_trusted_setup_file(KZGSettings *out, FILE *in) {
int num_matches;
uint64_t i;
uint8_t g1_bytes[TRUSTED_SETUP_NUM_G1_POINTS * BYTES_PER_G1];
@ -1797,7 +1797,7 @@ C_KZG_RET LOAD_TRUSTED_SETUP_FILE(KZGSettings *out, FILE *in) {
CHECK(num_matches == 1);
}
return LOAD_TRUSTED_SETUP(
return load_trusted_setup(
out,
g1_bytes,
TRUSTED_SETUP_NUM_G1_POINTS,

View File

@ -36,62 +36,6 @@ extern "C" {
// Macros
///////////////////////////////////////////////////////////////////////////////
/*
* Helper function for when LIB_PREFIX is defined.
*/
#ifdef LIB_PREFIX
#define CONCAT_IMPL(a, b) a##_##b
#define CONCAT(a, b) CONCAT_IMPL(a, b)
#define PREFIX_FUNCNAME(name) CONCAT(LIB_PREFIX, name)
#else
#define PREFIX_FUNCNAME(name) (name)
#endif /* LIB_PREFIX */
/*
* If LIB_PREFIX is defined, the following functions will prepend `LIB_PREFIX`
* to all public methods of this library. If LIB_PREFIX is undefined,
* everything stays as is.
*/
#define BLOB_TO_KZG_COMMITMENT PREFIX_FUNCNAME(blob_to_kzg_commitment)
#define COMPUTE_KZG_PROOF PREFIX_FUNCNAME(compute_kzg_proof)
#define COMPUTE_BLOB_KZG_PROOF PREFIX_FUNCNAME(compute_blob_kzg_proof)
#define VERIFY_KZG_PROOF PREFIX_FUNCNAME(verify_kzg_proof)
#define VERIFY_BLOB_KZG_PROOF PREFIX_FUNCNAME(verify_blob_kzg_proof)
#define VERIFY_BLOB_KZG_PROOF_BATCH PREFIX_FUNCNAME(verify_blob_kzg_proof_batch)
#define LOAD_TRUSTED_SETUP PREFIX_FUNCNAME(load_trusted_setup)
#define LOAD_TRUSTED_SETUP_FILE PREFIX_FUNCNAME(load_trusted_setup_file)
#define FREE_TRUSTED_SETUP PREFIX_FUNCNAME(free_trusted_setup)
/*
* This value represents the number of field elements in a blob. It must be
* supplied externally. It is expected to be 4096 for mainnet and 4 for minimal.
*/
#ifndef FIELD_ELEMENTS_PER_BLOB
#error FIELD_ELEMENTS_PER_BLOB must be defined
#endif /* FIELD_ELEMENTS_PER_BLOB */
/*
* There are only 1<<32 2-adic roots of unity in the field, limiting the
* possible values of FIELD_ELEMENTS_PER_BLOB. The restriction to 1<<31 is a
* current implementation limitation. Notably, the size of the FFT setup would
* overflow uint32_t, which would cause issues.
*/
#if FIELD_ELEMENTS_PER_BLOB <= 0 || FIELD_ELEMENTS_PER_BLOB > (1UL << 31)
#error FIELD_ELEMENTS_PER_BLOB must be between 1 and 2^31
#endif /* FIELD_ELEMENTS_PER_BLOB */
/*
* If FIELD_ELEMENTS_PER_BLOB is not a power of 2, the size of the FFT domain
* should be chosen as the the next-largest power of two and polynomials
* represented by their evaluations at a subset of the 2^i'th roots of unity.
* While the code in this library tries to take this into account, we do not
* need the case where FIELD_ELEMENTS_PER_BLOB is not a power of 2. As this
* case is neither maintained nor tested, we prefer to not support it.
*/
#if (FIELD_ELEMENTS_PER_BLOB & (FIELD_ELEMENTS_PER_BLOB - 1)) != 0
#error FIELD_ELEMENTS_PER_BLOB must be a power of two
#endif /* FIELD_ELEMENTS_PER_BLOB */
/** The number of bytes in a KZG commitment. */
#define BYTES_PER_COMMITMENT 48
@ -101,6 +45,9 @@ extern "C" {
/** The number of bytes in a BLS scalar field element. */
#define BYTES_PER_FIELD_ELEMENT 32
/** The number of field elements in a blob. */
#define FIELD_ELEMENTS_PER_BLOB 4096
/** The number of bytes in a blob. */
#define BYTES_PER_BLOB (FIELD_ELEMENTS_PER_BLOB * BYTES_PER_FIELD_ELEMENT)
@ -176,7 +123,7 @@ typedef struct {
// Interface functions
///////////////////////////////////////////////////////////////////////////////
C_KZG_RET LOAD_TRUSTED_SETUP(
C_KZG_RET load_trusted_setup(
KZGSettings *out,
const uint8_t *g1_bytes, /* n1 * 48 bytes */
size_t n1,
@ -184,15 +131,15 @@ C_KZG_RET LOAD_TRUSTED_SETUP(
size_t n2
);
C_KZG_RET LOAD_TRUSTED_SETUP_FILE(KZGSettings *out, FILE *in);
C_KZG_RET load_trusted_setup_file(KZGSettings *out, FILE *in);
void FREE_TRUSTED_SETUP(KZGSettings *s);
void free_trusted_setup(KZGSettings *s);
C_KZG_RET BLOB_TO_KZG_COMMITMENT(
C_KZG_RET blob_to_kzg_commitment(
KZGCommitment *out, const Blob *blob, const KZGSettings *s
);
C_KZG_RET COMPUTE_KZG_PROOF(
C_KZG_RET compute_kzg_proof(
KZGProof *proof_out,
Bytes32 *y_out,
const Blob *blob,
@ -200,14 +147,14 @@ C_KZG_RET COMPUTE_KZG_PROOF(
const KZGSettings *s
);
C_KZG_RET COMPUTE_BLOB_KZG_PROOF(
C_KZG_RET compute_blob_kzg_proof(
KZGProof *out,
const Blob *blob,
const Bytes48 *commitment_bytes,
const KZGSettings *s
);
C_KZG_RET VERIFY_KZG_PROOF(
C_KZG_RET verify_kzg_proof(
bool *ok,
const Bytes48 *commitment_bytes,
const Bytes32 *z_bytes,
@ -216,7 +163,7 @@ C_KZG_RET VERIFY_KZG_PROOF(
const KZGSettings *s
);
C_KZG_RET VERIFY_BLOB_KZG_PROOF(
C_KZG_RET verify_blob_kzg_proof(
bool *ok,
const Blob *blob,
const Bytes48 *commitment_bytes,
@ -224,7 +171,7 @@ C_KZG_RET VERIFY_BLOB_KZG_PROOF(
const KZGSettings *s
);
C_KZG_RET VERIFY_BLOB_KZG_PROOF_BATCH(
C_KZG_RET verify_blob_kzg_proof_batch(
bool *ok,
const Blob *blobs,
const Bytes48 *commitments_bytes,

View File

@ -12,22 +12,6 @@
#include <gperftools/profiler.h>
#endif
///////////////////////////////////////////////////////////////////////////////
// Macros
///////////////////////////////////////////////////////////////////////////////
#if FIELD_ELEMENTS_PER_BLOB == 4096
#define MAINNET
#define TRUSTED_SETUP_FILE "trusted_setup.txt"
#define MAX_WIDTH 32
#elif FIELD_ELEMENTS_PER_BLOB == 4
#define MINIMAL
#define TRUSTED_SETUP_FILE "trusted_setup_4.txt"
#define MAX_WIDTH 4
#else
#error FIELD_ELEMENTS_PER_BLOB must be 4096 or 4
#endif
///////////////////////////////////////////////////////////////////////////////
// Globals
///////////////////////////////////////////////////////////////////////////////
@ -537,13 +521,8 @@ static void test_blob_to_kzg_commitment__succeeds_expected_commitment(void) {
*/
bytes48_from_hex(
&expected_commitment,
#ifdef MAINNET
"9815ded2101b6d233fdf31d826ba0557778506df8526f42a"
"87ccd82db36a238b50f8965c25d4484782097436d29e458e"
#else
"95d2d20379b60c353a9c2c75333a5d7d26d5ef5137c5200b"
"51bc9d0fd82d0270e98ac9d41a44c366684089e385e815e6"
#endif
"91a5e1c143820d2e7bec38a5404c5145807cb88c0abbbecb"
"cb4bccc83a4b417326e337574cff43303f8a6648ecbee7ac"
);
diff = memcmp(c.bytes, expected_commitment.bytes, BYTES_PER_COMMITMENT);
ASSERT_EQUALS(diff, 0);
@ -1120,13 +1099,8 @@ static void test_compute_kzg_proof__succeeds_expected_proof(void) {
bytes48_from_hex(
&expected_proof,
#ifdef MAINNET
"899b7e1e7ff2e9b28c631d2f9d6b9ae828749c9dbf84f3f4"
"3b910bda9558f360f2fa0dac1143460b55908406038eb538"
#else
"a846d83184f6d5b67bbbe905a875f6cfaf1c905e527ea49c"
"0616992fb8cce56d202c702b83d6fbe1fa75cacb050ffc27"
#endif
"b21f8f9b85e52fd9c4a6d4fb4e9a27ebdc5a09c3f5ca17f6"
"bcd85c26f04953b0e6925607aaebed1087e5cc2fe4b2b356"
);
/* Compare the computed proof to the expected proof */
@ -1837,7 +1811,7 @@ static void setup(void) {
C_KZG_RET ret;
/* Open the mainnet trusted setup file */
fp = fopen(TRUSTED_SETUP_FILE, "r");
fp = fopen("trusted_setup.txt", "r");
assert(fp != NULL);
/* Load that trusted setup file */

File diff suppressed because it is too large Load Diff

View File

@ -1,71 +0,0 @@
4
65
91131b2e3c1e5f0b51df8970e67080032f411571b66d301436c46f25bbfddf9ca16756430dc470bdb0d85b47fedcdbc1
934d35b2a46e169915718b77127b0d4efbacdad7fdde4593af7d21d37ebcb77fe6c8dde6b8a9537854d70ef1f291a585
9410ca1d0342fe7419f02194281df45e1c1ff42fd8b439de5644cc312815c21ddd2e3eeb63fb807cf837e68b76668bd5
b163df7e9baeb60f69b6ee5faa538c3a564b62eb8cde6a3616083c8cb2171eedd583c9143e7e916df59bf27da5e024e8
93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8
99aca9fb2f7760cecb892bf7262c176b334824f5727f680bba701a33e322cb6667531410dfc7c8e4321a3f0ea8af48cb1436638a2093123f046f0f504cc2a864825542873edbbc5d7ed17af125a4f2cf6433c6f4f61b81173726981dd989761d
88e2e982982bf8231e747e9dfcd14c05bd02623d1332734d2af26246c6869fb56ee6c994843f593178a040495ba61f4a083b0e18110b1d9f5224783d8f9a895e8ee744e87929430e9ba96bd29251cbf61240b256d1525600f3d562894d93d659
a2d33775e3d9e6af0d1b27d389e6c021a578e617a3d6627686db6288d4b3dffd7a847a00f7ef01828b7f42885b660e4204923402aca18fbae74ccd4e9c50dd8c2281b38dc09c022342ed1ac695d53f7081cb21f05fdfc0a3508c04759196fcd3
af565445d2ad54c83a75c40e8895f5ad7219a8c728bce9d58d7a83716e095432993ebbd3f6911c66415a6f920d1a4d171478509b54a114308a020b33bf4487a7a8d0aa76ae4676a9b54e765a680f562d3a4fcb2e92c58b14b49b5b2917cc258f
8aa99cfaf514cef4801599cadd780d222194ca1ad69a34779c2bcfda93e5dbeb931e13914421b5809a6c81f12cf7038b04a35257cc9e94c33761e68565b1274aa6a6f9d66477229747a66b308b138f92aa4326a3bf23df65a1fe33b3b289bfe1
99ba36d8b4f56bde026099278548b1afc0a987cbd7c9baa51fc8e6cbb8237a17636f1a44a385cec69b05a5802059956a11fe793cabb939c38800f9c239ca2518e898ade1ec2513c9ee492071a35aabd78182392a09123d28dbc233313c9120c4
a7dc40c36afccb30a2eaff250860b28b227c195cf05674704c567d77d6655c446ae835f8fc8667e71147ab02afcb2dad0babe60cbfa37d7c2cddc68d2dec54f28a4142f8353590a3902d5ddaa22066ab563dd1435dda83f276387b9767d69120
939e6cc97a8b88572852a5b7f25e4838556307f60aeafb5d2b6961edbcafd4b48cb6ac980ffbacf4be963f324ba81e3d12de4f1459d8c746d0762c66ae1b166027f7fbe641d9c48f3c7d97b06d956b0be51dcc9aab65f3e99e1388e63bdd79f9
b391e156541dfd4003d1697cdb7ec815b309807320574906b2e652ef0175828b356d215cd374b1b34d9f470b3fa0e643113e67b2273268f922f04f072cfb89008358185b25cd631f82911a3f20f90f75758ffb99bebb8076458ae1e9d1ae898c
b9ac9c84934cc2a85c876eff65577e1dfce1935cd6392c877dd881a7d2f5c3e9344f28c04f90c62a6db4237ca00f9e0d00cb5f63e3f060fc7303916e19273b6fe455f331cabbe2fe5a22d584484f0d4176120fec9819fbb0a01e6d38695acfcd
88209eb030c5d78734bf2c2a5c539653fd3c24b4c08e624f9ddc4a6550efbdc1054a56eb0c807595aad6de56fda326aa196d032a8b4b48d40140a2d77df3c7243eda6507936389a321a5811eb38e32ee433c788deeae1eb928b00940e2944bcc
a8632ddc9cf7cbc1e8b74a05b7d4a89618c64afe30367ca0c9550ae7d320bf4e51c5a69e1501a1d8bee4240d13d7835501aa39fdc401a74f4d5734e268a7ce29a1fcfdb0a8bc64e0dd4a9e8578d6985bc2bc6a3764ce7a3703f6fb2e52557a2b
a037ac67e8bb6f4193ac967e05d080a489f58ef8d3d30a89798246f3e4936121ee445b03e410a09e8ebc0db2e2477d110aad0ade99b0887f1eb016e750f42135866907f150bd6f4f99a8cb94281474166874808ebe03b118c5daab16dafdc38b
a50d9143116bffa3b237da8e1805327e81e9cd25e658289bd727d5f9e0020172cc8690dcfe31a240e5cbc48353b88c4908baa1dd7320165556e0aa633f62fcbe7870222d345a3bbcdb7ab6c07f0fd86be559964afabf56f0a8cbc0b4b91d477e
afa988ea6fa4f40c5ad07d2d580d29025ddf56d6ef1171a8b8de3464203f70b97d6f5ace72747345204b35150e06154d1477516a989ce8eea7871cc0d0de00a077c0fb23ad4837e409d0b885bf3f2dde11a30fa6273d662e68e09f461e52932f
97fa1a943ed8b81574304a3d03f4f15907f6e6e0cd36a66bd2ad2c75afafc70a61d3ff69b77ebe4dae9ca0fcedef80081062705e60bbb6ea0f1f398c84d2f8e4a3ac142ac66426c21ad5e9994ebbcc406af474c4aec5e32fadcb21875af7c9f1
b30a564614493886f14a5dd71c89457504f8c59a7ac01b665ed167e9a8f9ee5832198fd319ecd234196ee57031bdf3840bd5a923e203a1938bc795c704b5285389750e1fd10d7050061ba19db00a60a2c0384a7d661d7d48ebe6962272230859
84c8dea942cfae71cb02e705ec496d967425793ce8812e7ee53c2f23713abeaff566a658cd1c73dfd18187d16253a6ee0a623e82cd18e31cd1a1875d19c078835dc9292e141686150a88065226ada264740143e87c03a0f6c4da8c187438ebf4
8c3abae8aed60338f8c4ff80aab22f8a2ae56756a93566c906f490a97151d34a1c3318054e1c494c60cc53327ad86a2d02c6c76a406726ce4f88635bc32eff0db0b61762dc518b95fa8da82e87e4bf3de54f1d72180ef53ed7bc5413e6a9a510
a328230c92a6b1cef6a444bcb64edb992f71e3d7b93f0b6b8b408ba7c908db746d92ddb2c7588bab438ef3bc61be1c2f0dfc86ba2ff514b42b35c80f89b2e780f813ea1dfb977fbded2cd9b553b747fa952e227ebd8f071163d421fc337f04c9
b482cab423cd5f1c5df036070aade7aa016283d69619d664025c3feab866a0a5691d344b2ee2bedc5dedd1f9a73eae16003a3827c9e5bbe22ded32d848fba840ffad1141ad158f5c40bc8ae0d03781b9705d851a7f1391b096c576c0f4f2a6b0
919ee1df27fabcb21237a1b7b98f53d41d849e1b6a8f9e28c3fae2841c6b5a250e4041c737e6725476e5cd715e34d3880f58d80f61efaabc261bdc703e8750f48a923e9bf8980931b9fd9e40014c66c54b3e7c98241d76d1aa47af43313a65a1
ac94830145dbe9a8f7e6e0fc1f5fb454502d22abcafdc2dd96c6933c604461fa83b2b37385f4bc454875a02a6d4157841250956783515d11c7456e7f11b745f12856d89f5feedaf6a61a483a6c33a21cd2ba0c18eb41a1a2e7fc33bb53e4c570
b209c699f1233735c5bb4bce848e4365fd76651ae2184d2279a90df0c2f69ffa2a24d84a9b9f274021072953c0d65e1a0202d490d6c37186af240114e445d87bff754b4824937e4f2c90a574061b1c4910fed88d90f698025a2a264e656cb8a4
93320dc0576b0d069de63c40e5582b4486d9adf5e69e77e3ebaf3da26976fe42147a65051501bc8383f99e7ba75479c70a6726c2cd08bf98c7481f1f819712292d833a879f21a1221a9610bc748fb5e911055122fdb4055cdc84e8bfe0f4df9b
a4380b240e998cdf668591f71a0c88ed143b0185a920787627ce65095f8223dc606fa5bce93377af100de92d663e675c0736d7f1973603a84a5c4162fb5e01c88c7493503ae1d7e9fbe8ece9b418397d68c21eeb88dae226e09875d372c646dd
aab48517d69135a16b36b685adfe9b2544a709135a21ba3e75981a2cba4ec81d1fe28ac0f72fde0c0001c15300ed6a810f58d3117bdd58d0149751d6508cf8a1a1ff7b63dd02d2730a9d6fe96c77c502fe8ed46d50a181ec4bb35e37dfbd6af4
8277265fe75ab89ce4ec65b33fb4084bec0a56d81faf2f7a9070d2ca3065678e03a790350eba56323a54e0285bc32fe8007d5259740fde226e16cbde8354eacd562294eb9b7f727ed72ffbdad86f467cf057c737b34b80a41deb92634ed866f5
aa40a24cb2ebe606d969392c03020070f044c95088d80f57f771b837c048342d2cd3474600d7660441090ffb8d2ffb7f0eddd67eb378e3e1477a6ba0bc38096d5d2d3355bc8b60f605f57f0c1899da591457440352381d2b38c0aa9acc7fe419
80815d10685808cb630820629bcd2fa9041c9b74433630c0b9c1b7f7e8edf1440b520217f76ec9a50c125cf4438aa66006a1928a9ed2321da7ea325c3d56b65462b72118ca2c99a0ea733aa11da9abbeda6cc71ffeed301ae70213a29e697dcd
ac235d079f91b00b1fead7523da8f73a5409fa8970907af0c5d5e4c6a0996dccfcdb0d822d08c7fbc0c24799457d011d04312d20831825f23cf988141056a6814c8a1cac9efe37bdcbfa272aed24cd92810fea7c49b0d07683a5c53643872179
b8aa59534d75fa5ac1c2c3f963bf73899aff5210059dbde8a8635561c6249e5143affee3bd2fd57575213b52d9a73d5702525867a7dcbb1d0a49b98c2925556fc5463ff0209742046a24ab29e74257d6419401093cc4371944d811cc300b6a67
80bbfc5b816eea29a6d84e2217dee4d547306994d39e5592515e1b0807b67fe960d1d5addb0ff1a20c158bdb294c04bf093d28996121845a2c9268e2c9ac0f4067e889c6aaca62f8535d35b45036954bd069e3afa84f04721538c26003304c20
a535c17d0e151d0e03d42dd58ba8c715bee3fabca2890e0e016071d34184b6b34e770d2be29c8ec76b69bcc471d50f4d043c2c240e9b93a81cff7ee2724e02018dfd9b534e40be641fdb4884abcd83b76f517557ffba508f1ba2f56313f4de94
b237eb7465df0d325a3aa58269be2627e4978f9863f4f100ed4c303cb1f6549e606f2e3c9180824d8049191965c8dacd0a0c76cc56cb22cf1bcfdb39372c8aa29b4f7b34582b1719e6bd59c930d87d5ccd838743b585d6e229d5ed42337315c0
805c335a2a9d2de30809cf30808ef836d88e9453c510716f01696f14c72dd60505eca8f128970edc8e63a9aa1f8792ac0dd50dcc84fbf4cc8b32349c682a6a27bc7551c7aa273a94c1606d07710188d93579afe3be1781bded15a34ed6047922
b25dadf385ddd3c39bcb0a014d3d4f66127946b1aceae8809e3a03d66cc25e27142ca108316391f857fe82fdea4db2520cc73793b695eafbf3ade00ef7ec747b0457e49303f5e1a370f5263b436566fe24a0876e5fe088238c7be37a0718d65f
b0f753081cabe2c8fce73aba82ff67dbc9842598b3e7fa3ce2a1f534536f8ac63c532fe66552ac6b7adb28c73ed4c8a4184849be7c1756a4681ce29ebf5e1c3aa806b667ee6bd68f6397aba3215dc1caec6742f21d681e32cd1160d6a3b1d7ee
b798771eeb3d7a17c62ba5916cc034bba870da6b1ac14c2e1cae71af3ad4e0c0d1ff983f691e0e55289d5a33b131f2ec12430c9566dd71f4d8be9c79155357a5c30c5efcfd75bbe1bb6d5ada4d50604ea49ed838d3641f268ca6e25c9c4b6b72
b52554c017388b099804abbe565346591a086d9979e10140ddaccc0a3680e506db775d7cbeafde67563adf0f09f5c2420caf19629f4e8f03e6fe02e9416ecd5269989e482b90004a083967d1141387eb74865bac6bd17e7a6d5f58225e52d4b7
b520ff694520919023d44d53f98a7de2f78ff37b2d9193dcaa35556a6a0febf767781a4c961dce7c804bfdf81935f8f0082865253da52e79dfa1c5ff74d61495b2da76e167d46114709e877a7791a3a95e33a42f56b83f5f5afe271c67ae997c
b721401983440797a03d5b99f2088a0b249aa911969c34dd6c615b0060325da555d2ad99d931170c0868b0488a2234a4114cc0013d5163b833f5c45c5eb536421c016cf85788390176bb2dc4c196d6be26bbbfceae048b82f0d8039222e71c94
acd9d833ba0a8cbd8d1ba939a11ea0fa5607e1bc6e693ec318bdb097aedd042d76e695dcebebd142e2e4ac30b1905dff03ec36d9cc70577e4dbe5e9ed7c20c7afb13a7f0155f203c6b83b9f1ad3d20a0d4aef0fbbbcf466ffc1bcd482bc2f5e0
8cc1795de015f2b0e72116f169f3b4624b7738ceebea354e0bd9051c27b86f647ea36cad57ea6884c1a8adf9b45cd83514fa687e68878bbd613d793aa10986d5a0411f081689229e0d72133b3667b9f3f1a02211d0e680564eb1ea43393e1f36
aa9281c61113c343a108de1036570feefc72fb7a96ff11f73024de12b83f29631f5a8a5900e6f10b15227c6f7462881511271bf785ebdf95ce288100e5dab391f664f6ff76c72b65b34479a4f43e5e8eba292209d6654157286ad3242ac342db
aaf16866275082e59d415db317aa874267d048ee405a553e852e6d175711d31a1fee99912345915bce121f43bc3e00d81338e5fcd3c8a1012fb4f172a9fe15622dd368b4d9d5cb60d189f423b071791fe26cea7676aca8df07965cacf80b0cd0
accc80b3d8a6ffa648487a3d3c0ce1aeeb5401edf3cf2e385ea4a6d5fc110054fcce38f01f1da7141bbed30eb7a0a6810c82212bbb9da75d6033082dbcf6bc6a5791f85aa0f045a10da5de015edbf369b4d23b32b0c058962d2ee88e6911f994
83f1089395a16077738cc7c9a6d6a3dc9033aac4abc508af5a1f007ca92e1a80b2e6f2dbda7fdcf0d5646de790a6201d0a9cfbcb6620a1426600e3a6a425ec004384f49fb9dcd166691a47177d45dcbcb761a11d46220b0aa09fc946131f7aa5
9246bb586d43cb817c2e15ed609156e9f1cd284ba2f4797bbfa51c0341e1ba382eaac059aa9f63fb88d228a1a932839a171e7c7d00199dc7c4d6c5ea038a02cbc3cc5297c70401520e70ebbcffacd6a703f62896f3c788f94dde3c33ab0ecbdb
a316cb7c74feb0563c56cc79015e2774fbeca458bf8e9fb07894f9d6bcd73f7fb9428e87c816e5629e4bf7f3ec567fbc091549471b75492dde08217cb334b716b4582b24384586e53388873a78a90ec01bd7c3bace9cfc52161467df16e27c33
ade18c74bbe60d1d69f4a570f8e5fd8696c26cc9e02829040b6b14cb9c49a4b3263b5bd5e16ec0b29010b4be054c16ab09304e23442af7d7f5fcc60bc6c5634ab6e4aed7ef334b2785e4c7672d59a687278e42d310342db5e5975d716e6d1595
b7728800bb2039acf228fa3d8028569c426cb85d28b2b5820bbef938d5ca8c4df981d3e01a309e26ca101e8295d0f6990c03b8c239798323575874a4ee5bfe46cfe99b9657189142aacd8f8d1f26cf4c0e73c6397c31ba8f18102b9ea315b638
8fb14f2a9be193f54977ecd3021663108ea143627b9a9d9faff85d1a86b855f6c437eab435fad3304f245bd7732af07f1173494cdb802fb96e85d2db89e1643206e183f3b228ca8d3f586e71aa9308eaf0223100bf07942fc39e465016d1f775
ac1e025e53d98fdb3380489dce82d9d4bd3a6c98f0a523b841cb09a6f26ddd4d22efd98776e78d10fd996995fd00e81e08d3c25dd14a54b25a9d483677a24bbb8d1cb41a443b2c71038e6893b1b30f70758424e0f2039a48060191389033ef55
a4c017311b9e930868132527a9849072b91db04fd36c619ae39c98da9e2174e6201d3c2ff1246c06b1b6815bbf3ea4a1116564f55ee2fe4c4d655e2294c0ded842cba209c255ca3d7b7f82d162f97890dfdeed087aa2f87cbfc61d61815da39d
89516315a3956b455843c2555248bd94dcb19993060fe75fdd51f7aa9c9147ab13997d8a98036a8f04bee5c91d78d2990907e35a52537a8ab3ed15f1a71afdcd38044a5b6e93f662b9d36c16933a881927cacae668c4c06ee6f004c9e3989bad
a1e78a011e210400c68ca76045f7da74119bff3cbe382efd2bd2ac76567c52d68d75536a91999d084043e1ce2d07d02e0b69fb99924101d2543521747536fbc51b0454aa9a4cbbec101121f597863a5c0fee2ca5eab35dff9b9085bef8b2b0d0
830fd8d083e39153ecab43cabb22e29d7b44a55fba467af4ddd3f069439d2972ef53c3518de788f96b3f4f64963987d0155ba27afc28643af3de8e476ff515a68285728167408f45d99e574680bda6bacdd4322e587e4aa99386e035c0e931ad
b89584da22237e3061d991b1a55a5e55dc637b8b671130d304587729348138ef87885180310efe9f9f6d3580b9d7fdcf0649e8a79d2dec8c25a9f53df0fac5d517db999029cbfdd7c2cbd3e9a5503e5d267d3d8ad752335915c92b850b14bafb
959b8030733799882c5e3735479924b013756e57b893f9792bab4043e2d362d77cf308166d782e3989caa771b8a0c0a01302cb7b5e8ca12e2d6cebd59d4cd173c9dc25f438bac597fab17b4ff44997a489c168e7204b7d7c21d0938f0a2e3b51
a0a9e5503d9afe0027891dab890c687fd5f5fac5741418490c64d7c15f59533dd603a50163c79402afa61bd02de486761983c94501da17e6bbe78c497f2122210071602f578adc0ebe7a4679f87fe77e09c8c122de69105f13455fea25f08e6f
9811487283ad620cd7c9b303ae2f348d0e6f5ee17b504baaa817ae207adb912a00d3cc36dbf48745eb899e6b6e22f09f0f9ba29d949ecd7350fbbfe87a8c7cdd5d0e687fc807751d07634aaf7c38baf3b24a0670c38fa6ccd7431436fc95525f
8a13aa5071c526e560def7d8583393942f07d88c9d8d26c98738fd65f57af2e3326dbb1edff0f39fe98eda4a13ed4fd71844254b954690154c4804e1c4a53df9dc4643f4b7b09d0860070f6b2318d0d63d28fb56bf5b6ff456a18dfc72fdfbbe
b9c90ff6bff5dd97d90aee27ea1c61c1afe64b054c258b097709561fe00710e9e616773fc4bdedcbf91fbd1a6cf139bf14d20db07297418694c12c6c9b801638eeb537cb3741584a686d69532e3b6c12d8a376837f712032421987f1e770c258

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More