mirror of https://github.com/hyperledger/besu
KZG point eval precompile (#4860)
* KZG implementation Signed-off-by: Justin Florentine <justin+github@florentine.us>pull/4983/head
parent
9034d31a05
commit
f8a0f87405
@ -0,0 +1,160 @@ |
|||||||
|
/* |
||||||
|
* Copyright Hyperledger Besu Contributors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||||
|
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||||
|
* specific language governing permissions and limitations under the License. |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||||
|
*/ |
||||||
|
package org.hyperledger.besu.evm.precompile; |
||||||
|
|
||||||
|
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; |
||||||
|
|
||||||
|
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason; |
||||||
|
import org.hyperledger.besu.evm.frame.MessageFrame; |
||||||
|
|
||||||
|
import java.io.BufferedReader; |
||||||
|
import java.io.File; |
||||||
|
import java.io.IOException; |
||||||
|
import java.io.InputStream; |
||||||
|
import java.nio.charset.Charset; |
||||||
|
import java.nio.file.Files; |
||||||
|
import java.nio.file.Path; |
||||||
|
import java.nio.file.Paths; |
||||||
|
import java.util.Optional; |
||||||
|
|
||||||
|
import com.google.common.annotations.VisibleForTesting; |
||||||
|
import ethereum.ckzg4844.CKZG4844JNI; |
||||||
|
import org.apache.tuweni.bytes.Bytes; |
||||||
|
import org.apache.tuweni.bytes.Bytes32; |
||||||
|
import org.jetbrains.annotations.NotNull; |
||||||
|
|
||||||
|
public class KZGPointEvalPrecompiledContract implements PrecompiledContract { |
||||||
|
|
||||||
|
public KZGPointEvalPrecompiledContract() { |
||||||
|
this(Optional.empty()); |
||||||
|
} |
||||||
|
|
||||||
|
public KZGPointEvalPrecompiledContract(final Optional<Path> pathToTrustedSetup) { |
||||||
|
|
||||||
|
String absolutePathToSetup; |
||||||
|
CKZG4844JNI.Preset bitLength; |
||||||
|
if (pathToTrustedSetup.isPresent()) { |
||||||
|
Path pathToSetup = pathToTrustedSetup.get(); |
||||||
|
absolutePathToSetup = pathToSetup.toAbsolutePath().toString(); |
||||||
|
} else { |
||||||
|
InputStream is = |
||||||
|
KZGPointEvalPrecompiledContract.class.getResourceAsStream( |
||||||
|
"mainnet_kzg_trusted_setup_4096.txt"); |
||||||
|
try { |
||||||
|
File jniWillLoadFrom = File.createTempFile("kzgTrustedSetup", "txt"); |
||||||
|
jniWillLoadFrom.deleteOnExit(); |
||||||
|
Files.copy(is, jniWillLoadFrom.toPath(), REPLACE_EXISTING); |
||||||
|
is.close(); |
||||||
|
absolutePathToSetup = jniWillLoadFrom.getAbsolutePath(); |
||||||
|
} catch (IOException e) { |
||||||
|
throw new RuntimeException(e); |
||||||
|
} |
||||||
|
} |
||||||
|
try (BufferedReader setupFile = |
||||||
|
Files.newBufferedReader(Paths.get(absolutePathToSetup), Charset.defaultCharset())) { |
||||||
|
String firstLine = setupFile.readLine(); |
||||||
|
if ("4".equals(firstLine)) { |
||||||
|
bitLength = CKZG4844JNI.Preset.MINIMAL; |
||||||
|
} else if ("4096".equals(firstLine)) { |
||||||
|
bitLength = CKZG4844JNI.Preset.MAINNET; |
||||||
|
} else { |
||||||
|
throw new IllegalArgumentException("provided file not a setup for either 4 or 4096 bits"); |
||||||
|
} |
||||||
|
CKZG4844JNI.loadNativeLibrary(bitLength); |
||||||
|
try { |
||||||
|
CKZG4844JNI.loadTrustedSetup(absolutePathToSetup); |
||||||
|
} catch (RuntimeException mightBeAlreadyLoaded) { |
||||||
|
if (!mightBeAlreadyLoaded.getMessage().contains("Trusted Setup is already loaded")) { |
||||||
|
throw mightBeAlreadyLoaded; |
||||||
|
} |
||||||
|
} |
||||||
|
} catch (IOException e) { |
||||||
|
throw new RuntimeException(e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@VisibleForTesting |
||||||
|
public void tearDown() { |
||||||
|
CKZG4844JNI.freeTrustedSetup(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getName() { |
||||||
|
return "KZGPointEval"; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long gasRequirement(final Bytes input) { |
||||||
|
// As defined in EIP-4844
|
||||||
|
return 50000; |
||||||
|
} |
||||||
|
|
||||||
|
@NotNull |
||||||
|
@Override |
||||||
|
public PrecompileContractResult computePrecompile( |
||||||
|
final Bytes input, @NotNull final MessageFrame messageFrame) { |
||||||
|
|
||||||
|
if (input.size() != 192) { |
||||||
|
return new PrecompileContractResult( |
||||||
|
Bytes.EMPTY, |
||||||
|
false, |
||||||
|
MessageFrame.State.COMPLETED_FAILED, |
||||||
|
Optional.of(ExceptionalHaltReason.PRECOMPILE_ERROR)); |
||||||
|
} |
||||||
|
Bytes z = input.slice(32, 32); |
||||||
|
Bytes y = input.slice(64, 32); |
||||||
|
Bytes commitment = input.slice(96, 48); |
||||||
|
Bytes proof = input.slice(144, 48); |
||||||
|
|
||||||
|
Bytes output = Bytes.EMPTY; |
||||||
|
PrecompileContractResult result; |
||||||
|
try { |
||||||
|
boolean proved = |
||||||
|
CKZG4844JNI.verifyKzgProof( |
||||||
|
commitment.toArray(), z.toArray(), y.toArray(), proof.toArray()); |
||||||
|
|
||||||
|
if (proved) { |
||||||
|
Bytes fieldElementsPerBlob = |
||||||
|
Bytes32.wrap( |
||||||
|
Bytes.of(CKZG4844JNI.getFieldElementsPerBlob()).xor(Bytes32.ZERO)); // usually 4096
|
||||||
|
Bytes blsModulus = |
||||||
|
Bytes32.wrap(Bytes.of(CKZG4844JNI.BLS_MODULUS.toByteArray()).xor(Bytes32.ZERO)); |
||||||
|
|
||||||
|
output = Bytes.concatenate(fieldElementsPerBlob, blsModulus); |
||||||
|
|
||||||
|
result = |
||||||
|
new PrecompileContractResult( |
||||||
|
output, false, MessageFrame.State.COMPLETED_SUCCESS, Optional.empty()); |
||||||
|
} else { |
||||||
|
result = |
||||||
|
new PrecompileContractResult( |
||||||
|
output, |
||||||
|
false, |
||||||
|
MessageFrame.State.COMPLETED_FAILED, |
||||||
|
Optional.of(ExceptionalHaltReason.PRECOMPILE_ERROR)); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} catch (RuntimeException kzgFailed) { |
||||||
|
System.out.println(kzgFailed.getMessage()); |
||||||
|
result = |
||||||
|
new PrecompileContractResult( |
||||||
|
output, |
||||||
|
false, |
||||||
|
MessageFrame.State.COMPLETED_FAILED, |
||||||
|
Optional.of(ExceptionalHaltReason.PRECOMPILE_ERROR)); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,91 @@ |
|||||||
|
/* |
||||||
|
* Copyright Hyperledger Besu Contributors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||||
|
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||||
|
* specific language governing permissions and limitations under the License. |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||||
|
*/ |
||||||
|
package org.hyperledger.besu.evm.precompile; |
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||||
|
import static org.assertj.core.api.Assertions.fail; |
||||||
|
import static org.mockito.Mockito.mock; |
||||||
|
|
||||||
|
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason; |
||||||
|
import org.hyperledger.besu.evm.frame.MessageFrame; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import java.io.InputStream; |
||||||
|
import java.nio.file.Path; |
||||||
|
import java.util.Optional; |
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode; |
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||||
|
import ethereum.ckzg4844.CKZG4844JNI; |
||||||
|
import org.apache.tuweni.bytes.Bytes; |
||||||
|
import org.apache.tuweni.bytes.Bytes32; |
||||||
|
import org.junit.BeforeClass; |
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
public class KZGPointEvalPrecompileContractTest { |
||||||
|
|
||||||
|
private static KZGPointEvalPrecompiledContract contract; |
||||||
|
private final MessageFrame toRun = mock(MessageFrame.class); |
||||||
|
|
||||||
|
@BeforeClass |
||||||
|
public static void init() { |
||||||
|
Path testSetupAbsolutePath = |
||||||
|
Path.of( |
||||||
|
KZGPointEvalPrecompileContractTest.class.getResource("trusted_setup_4.txt").getPath()); |
||||||
|
contract = new KZGPointEvalPrecompiledContract(Optional.of(testSetupAbsolutePath)); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void happyPath() { |
||||||
|
Bytes input = |
||||||
|
Bytes.fromHexString( |
||||||
|
"013c03613f6fc558fb7e61e75602241ed9a2f04e36d8670aadd286e71b5ca9cc420000000000000000000000000000000000000000000000000000000000000031e5a2356cbc2ef6a733eae8d54bf48719ae3d990017ca787c419c7d369f8e3c83fac17c3f237fc51f90e2c660eb202a438bc2025baded5cd193c1a018c5885bc9281ba704d5566082e851235c7be763b2a99adff965e0a121ee972ebc472d02944a74f5c6243e14052e105124b70bf65faf85ad3a494325e269fad097842cba"); |
||||||
|
|
||||||
|
Bytes fieldElementsPerBlob = |
||||||
|
Bytes32.wrap(Bytes.ofUnsignedInt(CKZG4844JNI.getFieldElementsPerBlob()).xor(Bytes32.ZERO)); |
||||||
|
Bytes blsModulus = |
||||||
|
Bytes32.wrap(Bytes.of(CKZG4844JNI.BLS_MODULUS.toByteArray()).xor(Bytes32.ZERO)); |
||||||
|
Bytes expectedOutput = Bytes.concatenate(fieldElementsPerBlob, blsModulus); |
||||||
|
// contract input is encoded as follows: versioned_hash | z | y | commitment | proof |
|
||||||
|
PrecompiledContract.PrecompileContractResult result = contract.computePrecompile(input, toRun); |
||||||
|
assertThat(result.getOutput()).isEqualTo(expectedOutput); |
||||||
|
MessageFrame.State endState = result.getState(); |
||||||
|
assertThat(endState).isEqualTo(MessageFrame.State.COMPLETED_SUCCESS); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void sadPaths() { |
||||||
|
try (InputStream failVectors = |
||||||
|
KZGPointEvalPrecompileContractTest.class.getResourceAsStream("fail_pointEvaluation.json")) { |
||||||
|
|
||||||
|
ObjectMapper jsonMapper = new ObjectMapper(); |
||||||
|
JsonNode failJson = jsonMapper.readTree(failVectors); |
||||||
|
|
||||||
|
for (JsonNode testCase : failJson) { |
||||||
|
|
||||||
|
Bytes input = Bytes.fromHexString(testCase.get("Input").asText()); |
||||||
|
|
||||||
|
PrecompiledContract.PrecompileContractResult result = |
||||||
|
contract.computePrecompile(input, toRun); |
||||||
|
MessageFrame.State endState = result.getState(); |
||||||
|
assertThat(endState).isEqualTo(MessageFrame.State.COMPLETED_FAILED); |
||||||
|
assertThat(result.getHaltReason()).isPresent(); |
||||||
|
assertThat(result.getHaltReason().get()).isEqualTo(ExceptionalHaltReason.PRECOMPILE_ERROR); |
||||||
|
} |
||||||
|
} catch (IOException ioe) { |
||||||
|
fail("couldn't load test vectors", ioe); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,71 @@ |
|||||||
|
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 |
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue