Use existing Bytes48 for KZGCommitment and KZGProof (#5997)

Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>
pull/6024/head
Fabio Di Fabio 1 year ago committed by GitHub
parent 9ec055caac
commit e946276d21
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      datatypes/src/main/java/org/hyperledger/besu/datatypes/KZGCommitment.java
  2. 10
      datatypes/src/main/java/org/hyperledger/besu/datatypes/KZGProof.java
  3. 9
      datatypes/src/test/java/org/hyperledger/besu/datatypes/BlobsWithCommitmentsTest.java
  4. 12
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java
  5. 5
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java
  6. 52
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java
  7. 8
      ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlobTestFixture.java
  8. 5
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidatorTest.java
  9. 11
      ethereum/rlp/src/main/java/org/hyperledger/besu/ethereum/rlp/AbstractRLPInput.java
  10. 6
      ethereum/rlp/src/main/java/org/hyperledger/besu/ethereum/rlp/BytesValueRLPInput.java
  11. 11
      ethereum/rlp/src/main/java/org/hyperledger/besu/ethereum/rlp/RLPInput.java

@ -17,18 +17,18 @@ package org.hyperledger.besu.datatypes;
import org.hyperledger.besu.ethereum.rlp.RLPInput; import org.hyperledger.besu.ethereum.rlp.RLPInput;
import org.hyperledger.besu.ethereum.rlp.RLPOutput; import org.hyperledger.besu.ethereum.rlp.RLPOutput;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes48;
/** This class contains the data for a KZG commitment. */ /** This class contains the data for a KZG commitment. */
public class KZGCommitment { public class KZGCommitment {
final Bytes data; final Bytes48 data;
/** /**
* Constructor for a KZG commitment. * Constructor for a KZG commitment.
* *
* @param data The data for the KZG commitment. * @param data The data for the KZG commitment.
*/ */
public KZGCommitment(final Bytes data) { public KZGCommitment(final Bytes48 data) {
this.data = data; this.data = data;
} }
@ -39,7 +39,7 @@ public class KZGCommitment {
* @return The KZG commitment. * @return The KZG commitment.
*/ */
public static KZGCommitment readFrom(final RLPInput input) { public static KZGCommitment readFrom(final RLPInput input) {
final Bytes bytes = input.readBytes(); final Bytes48 bytes = input.readBytes48();
return new KZGCommitment(bytes); return new KZGCommitment(bytes);
} }
@ -57,7 +57,7 @@ public class KZGCommitment {
* *
* @return The data for the KZG commitment. * @return The data for the KZG commitment.
*/ */
public Bytes getData() { public Bytes48 getData() {
return data; return data;
} }
} }

@ -17,18 +17,18 @@ package org.hyperledger.besu.datatypes;
import org.hyperledger.besu.ethereum.rlp.RLPInput; import org.hyperledger.besu.ethereum.rlp.RLPInput;
import org.hyperledger.besu.ethereum.rlp.RLPOutput; import org.hyperledger.besu.ethereum.rlp.RLPOutput;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes48;
/** This class contains the data for a KZG proof for a KZG commitment. */ /** This class contains the data for a KZG proof for a KZG commitment. */
public class KZGProof { public class KZGProof {
final Bytes data; final Bytes48 data;
/** /**
* Constructor for a KZG proof. * Constructor for a KZG proof.
* *
* @param data The data for the KZG proof. * @param data The data for the KZG proof.
*/ */
public KZGProof(final Bytes data) { public KZGProof(final Bytes48 data) {
this.data = data; this.data = data;
} }
@ -39,7 +39,7 @@ public class KZGProof {
* @return The KZG proof. * @return The KZG proof.
*/ */
public static KZGProof readFrom(final RLPInput input) { public static KZGProof readFrom(final RLPInput input) {
final Bytes bytes = input.readBytes(); final Bytes48 bytes = input.readBytes48();
return new KZGProof(bytes); return new KZGProof(bytes);
} }
@ -57,7 +57,7 @@ public class KZGProof {
* *
* @return The data for the KZG proof. * @return The data for the KZG proof.
*/ */
public Bytes getData() { public Bytes48 getData() {
return data; return data;
} }
} }

@ -23,6 +23,7 @@ import java.util.List;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.bytes.Bytes48;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
public class BlobsWithCommitmentsTest { public class BlobsWithCommitmentsTest {
@ -45,9 +46,9 @@ public class BlobsWithCommitmentsTest {
InvalidParameterException.class, InvalidParameterException.class,
() -> () ->
new BlobsWithCommitments( new BlobsWithCommitments(
List.of(new KZGCommitment(Bytes.of(1))), List.of(new KZGCommitment(Bytes48.fromHexStringLenient("1"))),
List.of(new Blob(Bytes.EMPTY)), List.of(new Blob(Bytes.EMPTY)),
List.of(new KZGProof(Bytes.EMPTY)), List.of(new KZGProof(Bytes48.ZERO)),
List.of())) List.of()))
.getMessage(); .getMessage();
final String expectedMessage = final String expectedMessage =
@ -64,7 +65,7 @@ public class BlobsWithCommitmentsTest {
new BlobsWithCommitments( new BlobsWithCommitments(
List.of(), List.of(),
List.of(new Blob(Bytes.EMPTY)), List.of(new Blob(Bytes.EMPTY)),
List.of(new KZGProof(Bytes.EMPTY)), List.of(new KZGProof(Bytes48.ZERO)),
List.of(new VersionedHash(Bytes32.rightPad(Bytes.fromHexString("0x01")))))) List.of(new VersionedHash(Bytes32.rightPad(Bytes.fromHexString("0x01"))))))
.getMessage(); .getMessage();
final String expectedMessage = final String expectedMessage =
@ -79,7 +80,7 @@ public class BlobsWithCommitmentsTest {
InvalidParameterException.class, InvalidParameterException.class,
() -> () ->
new BlobsWithCommitments( new BlobsWithCommitments(
List.of(new KZGCommitment(Bytes.of(1))), List.of(new KZGCommitment(Bytes48.fromHexStringLenient("1"))),
List.of(new Blob(Bytes.EMPTY)), List.of(new Blob(Bytes.EMPTY)),
List.of(), List.of(),
List.of(new VersionedHash(Bytes32.rightPad(Bytes.fromHexString("0x01")))))) List.of(new VersionedHash(Bytes32.rightPad(Bytes.fromHexString("0x01"))))))

@ -927,17 +927,19 @@ public class Transaction
sb.append("nonce=").append(getNonce()).append(", "); sb.append("nonce=").append(getNonce()).append(", ");
getGasPrice() getGasPrice()
.ifPresent( .ifPresent(
gasPrice -> sb.append("gasPrice=").append(gasPrice.toShortHexString()).append(", ")); gasPrice ->
sb.append("gasPrice=").append(gasPrice.toHumanReadableString()).append(", "));
if (getMaxPriorityFeePerGas().isPresent() && getMaxFeePerGas().isPresent()) { if (getMaxPriorityFeePerGas().isPresent() && getMaxFeePerGas().isPresent()) {
sb.append("maxPriorityFeePerGas=") sb.append("maxPriorityFeePerGas=")
.append(getMaxPriorityFeePerGas().map(Wei::toShortHexString).get()) .append(getMaxPriorityFeePerGas().map(Wei::toHumanReadableString).get())
.append(", "); .append(", ");
sb.append("maxFeePerGas=") sb.append("maxFeePerGas=")
.append(getMaxFeePerGas().map(Wei::toShortHexString).get()) .append(getMaxFeePerGas().map(Wei::toHumanReadableString).get())
.append(", "); .append(", ");
getMaxFeePerBlobGas() getMaxFeePerBlobGas()
.ifPresent( .ifPresent(
wei -> sb.append("maxFeePerBlobGas=").append(wei.toShortHexString()).append(", ")); wei ->
sb.append("maxFeePerBlobGas=").append(wei.toHumanReadableString()).append(", "));
} }
sb.append("gasLimit=").append(getGasLimit()).append(", "); sb.append("gasLimit=").append(getGasLimit()).append(", ");
if (getTo().isPresent()) sb.append("to=").append(getTo().get()).append(", "); if (getTo().isPresent()) sb.append("to=").append(getTo().get()).append(", ");
@ -993,7 +995,7 @@ public class Transaction
} }
sb.append("gl: ").append(getGasLimit()).append(", "); sb.append("gl: ").append(getGasLimit()).append(", ");
sb.append("v: ").append(getValue().toHumanReadableString()).append(", "); sb.append("v: ").append(getValue().toHumanReadableString()).append(", ");
getTo().ifPresent(to -> sb.append(to)); getTo().ifPresent(to -> sb.append("to: ").append(to));
return sb.append("}").toString(); return sb.append("}").toString();
} }

@ -339,12 +339,11 @@ public class MainnetTransactionProcessor {
gasCalculator.accessListGasCost(accessListEntries.size(), accessListStorageCount); gasCalculator.accessListGasCost(accessListEntries.size(), accessListStorageCount);
final long gasAvailable = transaction.getGasLimit() - intrinsicGas - accessListGas; final long gasAvailable = transaction.getGasLimit() - intrinsicGas - accessListGas;
LOG.trace( LOG.trace(
"Gas available for execution {} = {} - {} - {} - {} (limit - intrinsic - accessList - data)", "Gas available for execution {} = {} - {} - {} (limit - intrinsic - accessList)",
gasAvailable, gasAvailable,
transaction.getGasLimit(), transaction.getGasLimit(),
intrinsicGas, intrinsicGas,
accessListGas, accessListGas);
blobGas);
final WorldUpdater worldUpdater = worldState.updater(); final WorldUpdater worldUpdater = worldState.updater();
final ImmutableMap.Builder<String, Object> contextVariablesBuilder = final ImmutableMap.Builder<String, Object> contextVariablesBuilder =

@ -22,7 +22,6 @@ import org.hyperledger.besu.datatypes.Blob;
import org.hyperledger.besu.datatypes.BlobsWithCommitments; import org.hyperledger.besu.datatypes.BlobsWithCommitments;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.KZGCommitment; import org.hyperledger.besu.datatypes.KZGCommitment;
import org.hyperledger.besu.datatypes.KZGProof;
import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.VersionedHash; import org.hyperledger.besu.datatypes.VersionedHash;
import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.Wei;
@ -51,8 +50,6 @@ import org.bouncycastle.crypto.digests.SHA256Digest;
*/ */
public class MainnetTransactionValidator implements TransactionValidator { public class MainnetTransactionValidator implements TransactionValidator {
private static final byte BLOB_COMMITMENT_VERSION_KZG = 0x01;
private final GasCalculator gasCalculator; private final GasCalculator gasCalculator;
private final GasLimitCalculator gasLimitCalculator; private final GasLimitCalculator gasLimitCalculator;
private final FeeMarket feeMarket; private final FeeMarket feeMarket;
@ -336,11 +333,11 @@ public class MainnetTransactionValidator implements TransactionValidator {
final KZGCommitment commitment = blobsWithCommitments.getKzgCommitments().get(i); final KZGCommitment commitment = blobsWithCommitments.getKzgCommitments().get(i);
final VersionedHash versionedHash = versionedHashes.get(i); final VersionedHash versionedHash = versionedHashes.get(i);
if (versionedHash.getVersionId() != BLOB_COMMITMENT_VERSION_KZG) { if (versionedHash.getVersionId() != VersionedHash.SHA256_VERSION_ID) {
return ValidationResult.invalid( return ValidationResult.invalid(
TransactionInvalidReason.INVALID_BLOBS, TransactionInvalidReason.INVALID_BLOBS,
"transaction blobs commitment version is not supported. Expected " "transaction blobs commitment version is not supported. Expected "
+ BLOB_COMMITMENT_VERSION_KZG + VersionedHash.SHA256_VERSION_ID
+ ", found " + ", found "
+ versionedHash.getVersionId()); + versionedHash.getVersionId());
} }
@ -353,30 +350,27 @@ public class MainnetTransactionValidator implements TransactionValidator {
} }
} }
final Bytes blobs = final byte[] blobs =
blobsWithCommitments.getBlobs().stream() Bytes.wrap(blobsWithCommitments.getBlobs().stream().map(Blob::getData).toList())
.map(Blob::getData) .toArrayUnsafe();
.reduce(Bytes::concatenate)
.orElseThrow();
final Bytes kzgCommitments = final byte[] kzgCommitments =
blobsWithCommitments.getKzgCommitments().stream() Bytes.wrap(
.map(KZGCommitment::getData) blobsWithCommitments.getKzgCommitments().stream()
.reduce(Bytes::concatenate) .map(kc -> (Bytes) kc.getData())
.orElseThrow(); .toList())
.toArrayUnsafe();
final Bytes kzgProofs = final byte[] kzgProofs =
blobsWithCommitments.getKzgProofs().stream() Bytes.wrap(
.map(KZGProof::getData) blobsWithCommitments.getKzgProofs().stream()
.reduce(Bytes::concatenate) .map(kp -> (Bytes) kp.getData())
.orElseThrow(); .toList())
.toArrayUnsafe();
final boolean kzgVerification = final boolean kzgVerification =
CKZG4844JNI.verifyBlobKzgProofBatch( CKZG4844JNI.verifyBlobKzgProofBatch(
blobs.toArrayUnsafe(), blobs, kzgCommitments, kzgProofs, blobsWithCommitments.getBlobs().size());
kzgCommitments.toArrayUnsafe(),
kzgProofs.toArrayUnsafe(),
blobsWithCommitments.getBlobs().size());
if (!kzgVerification) { if (!kzgVerification) {
return ValidationResult.invalid( return ValidationResult.invalid(
@ -387,14 +381,6 @@ public class MainnetTransactionValidator implements TransactionValidator {
return ValidationResult.valid(); return ValidationResult.valid();
} }
/*
private VersionedHash hashCommitment(final Bytes32 commitment) {
return new VersionedHash(
VersionedHash.SHA256_VERSION_ID, Sha256Hash.hash(commitment));
}
*/
private VersionedHash hashCommitment(final KZGCommitment commitment) { private VersionedHash hashCommitment(final KZGCommitment commitment) {
final SHA256Digest digest = new SHA256Digest(); final SHA256Digest digest = new SHA256Digest();
digest.update(commitment.getData().toArrayUnsafe(), 0, commitment.getData().size()); digest.update(commitment.getData().toArrayUnsafe(), 0, commitment.getData().size());
@ -403,7 +389,7 @@ public class MainnetTransactionValidator implements TransactionValidator {
digest.doFinal(dig, 0); digest.doFinal(dig, 0);
dig[0] = BLOB_COMMITMENT_VERSION_KZG; dig[0] = VersionedHash.SHA256_VERSION_ID;
return new VersionedHash(Bytes32.wrap(dig)); return new VersionedHash(Bytes32.wrap(dig));
} }
} }

@ -15,7 +15,6 @@
package org.hyperledger.besu.ethereum.core; package org.hyperledger.besu.ethereum.core;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail; import static org.assertj.core.api.Assertions.fail;
import org.hyperledger.besu.datatypes.Blob; import org.hyperledger.besu.datatypes.Blob;
@ -33,6 +32,7 @@ import java.util.List;
import ethereum.ckzg4844.CKZG4844JNI; import ethereum.ckzg4844.CKZG4844JNI;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.bytes.Bytes48;
import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.crypto.digests.SHA256Digest;
public class BlobTestFixture { public class BlobTestFixture {
@ -68,10 +68,10 @@ public class BlobTestFixture {
fail("Failed to read blob file", e); fail("Failed to read blob file", e);
} }
Bytes commitment = Bytes.wrap(CKZG4844JNI.blobToKzgCommitment(rawMaterial)); Bytes48 commitment = Bytes48.wrap(CKZG4844JNI.blobToKzgCommitment(rawMaterial));
assertThat(commitment.size()).isEqualTo(48); Bytes48 proof =
Bytes proof = Bytes.wrap(CKZG4844JNI.computeBlobKzgProof(rawMaterial, commitment.toArray())); Bytes48.wrap(CKZG4844JNI.computeBlobKzgProof(rawMaterial, commitment.toArray()));
VersionedHash versionedHash = hashCommitment(new KZGCommitment(commitment)); VersionedHash versionedHash = hashCommitment(new KZGCommitment(commitment));
return new BlobTriplet( return new BlobTriplet(
new Blob(Bytes.wrap(rawMaterial)), new Blob(Bytes.wrap(rawMaterial)),

@ -57,6 +57,7 @@ import java.util.function.Supplier;
import com.google.common.base.Suppliers; import com.google.common.base.Suppliers;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes48;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock; import org.mockito.Mock;
@ -503,9 +504,9 @@ public class MainnetTransactionValidatorTest {
.blobsWithCommitments( .blobsWithCommitments(
Optional.of( Optional.of(
new BlobsWithCommitments( new BlobsWithCommitments(
List.of(new KZGCommitment(Bytes.EMPTY)), List.of(new KZGCommitment(Bytes48.ZERO)),
List.of(new Blob(Bytes.EMPTY)), List.of(new Blob(Bytes.EMPTY)),
List.of(new KZGProof(Bytes.EMPTY)), List.of(new KZGProof(Bytes48.ZERO)),
List.of(VersionedHash.DEFAULT_VERSIONED_HASH)))) List.of(VersionedHash.DEFAULT_VERSIONED_HASH))))
.versionedHashes(Optional.of(List.of(VersionedHash.DEFAULT_VERSIONED_HASH))) .versionedHashes(Optional.of(List.of(VersionedHash.DEFAULT_VERSIONED_HASH)))
.createTransaction(senderKeys); .createTransaction(senderKeys);

@ -24,6 +24,7 @@ import java.util.function.Function;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.bytes.Bytes48;
import org.apache.tuweni.bytes.MutableBytes; import org.apache.tuweni.bytes.MutableBytes;
import org.apache.tuweni.bytes.MutableBytes32; import org.apache.tuweni.bytes.MutableBytes32;
import org.apache.tuweni.units.bigints.UInt256; import org.apache.tuweni.units.bigints.UInt256;
@ -98,6 +99,8 @@ abstract class AbstractRLPInput implements RLPInput {
protected abstract Bytes32 inputSlice32(long offset); protected abstract Bytes32 inputSlice32(long offset);
protected abstract Bytes48 inputSlice48(long offset);
protected abstract String inputHex(long offset, int length); protected abstract String inputHex(long offset, int length);
protected abstract BigInteger getUnsignedBigInteger(long offset, int length); protected abstract BigInteger getUnsignedBigInteger(long offset, int length);
@ -426,6 +429,14 @@ abstract class AbstractRLPInput implements RLPInput {
return res; return res;
} }
@Override
public Bytes48 readBytes48() {
checkElt("48 bytes value", 48);
final Bytes48 res = inputSlice48(currentPayloadOffset);
setTo(nextItem());
return res;
}
@Override @Override
public <T> T readBytes(final Function<Bytes, T> mapper) { public <T> T readBytes(final Function<Bytes, T> mapper) {
final Bytes res = readBytes(); final Bytes res = readBytes();

@ -18,6 +18,7 @@ import java.math.BigInteger;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.bytes.Bytes48;
/** An {@link RLPInput} that reads RLP encoded data from a {@link Bytes}. */ /** An {@link RLPInput} that reads RLP encoded data from a {@link Bytes}. */
public class BytesValueRLPInput extends AbstractRLPInput { public class BytesValueRLPInput extends AbstractRLPInput {
@ -51,6 +52,11 @@ public class BytesValueRLPInput extends AbstractRLPInput {
return Bytes32.wrap(inputSlice(offset, 32)); return Bytes32.wrap(inputSlice(offset, 32));
} }
@Override
protected Bytes48 inputSlice48(final long offset) {
return Bytes48.wrap(inputSlice(offset, 48));
}
@Override @Override
protected String inputHex(final long offset, final int length) { protected String inputHex(final long offset, final int length) {
return value.slice(Math.toIntExact(offset), length).toString().substring(2); return value.slice(Math.toIntExact(offset), length).toString().substring(2);

@ -22,6 +22,7 @@ import java.util.function.Function;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.bytes.Bytes48;
import org.apache.tuweni.units.bigints.UInt256; import org.apache.tuweni.units.bigints.UInt256;
import org.apache.tuweni.units.bigints.UInt64; import org.apache.tuweni.units.bigints.UInt64;
@ -300,6 +301,16 @@ public interface RLPInput {
*/ */
Bytes32 readBytes32(); Bytes32 readBytes32();
/**
* Reads the next item of this input (assuming it is not a list) that must be exact 48 bytes.
*
* @return The next item read of this input.
* @throws RLPException if the next item to read is a list, the input is at the end of its current
* list (and {@link #leaveList()} hasn't been called) or the next element is not exactly 48
* bytes.
*/
Bytes48 readBytes48();
/** /**
* Reads the next item of this input (assuming it is not a list) and transforms it with the * Reads the next item of this input (assuming it is not a list) and transforms it with the
* provided mapping function. * provided mapping function.

Loading…
Cancel
Save