Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 26 additions & 26 deletions actuator/src/main/java/org/tron/core/vm/PrecompiledContracts.java
Original file line number Diff line number Diff line change
Expand Up @@ -235,34 +235,32 @@ public class PrecompiledContracts {
private static final DataWord kzgPointEvaluationAddr = new DataWord(
"000000000000000000000000000000000000000000000000000000000002000a");

// EIP-8052 0x16: FN-DSA / Falcon-512 verify (FIPS-206 draft). Input layout:
// EIP-8052 0x02000016: FN-DSA / Falcon-512 verify (FIPS-206 draft). Input layout:
// [msg 32B | sig 666B (headerless salt‖s2 slot, zero-padded; body ends at last
// non-zero byte) | pk 896B]. Total 1594 B. The slot holds the EIP-8052 headerless
// signature (no 0x39 byte); the precompile re-inserts the header before verifying.
private static final DataWord verifyFnDsa512Addr = new DataWord(
"0000000000000000000000000000000000000000000000000000000000000016");
"0000000000000000000000000000000000000000000000000000000002000016");

// 0x17: batch independent Falcon-512 verify — bitmap of (sig, pk, addr)
// matches; mixed-algorithm contracts call 0x0A and 0x18 separately and OR
// the bitmaps client-side.
// 0x02000017: batch independent Falcon-512 verify — bitmap of (sig, pk, addr) matches.
private static final DataWord batchValidateFnDsa512Addr = new DataWord(
"0000000000000000000000000000000000000000000000000000000000000017");
"0000000000000000000000000000000000000000000000000000000002000017");

// 0x18: ML-DSA-44 single verify (FIPS 204 / Dilithium-2).
// 0x02000018: ML-DSA-44 single verify (FIPS 204 / Dilithium-2).
private static final DataWord verifyMlDsa44Addr = new DataWord(
"0000000000000000000000000000000000000000000000000000000000000018");
"0000000000000000000000000000000000000000000000000000000002000018");

// 0x19: batch independent ML-DSA-44 verify — bitmap output, same shape as 0x18.
// 0x02000019: batch independent ML-DSA-44 verify — bitmap output, same shape as 0x02000017.
private static final DataWord batchValidateMlDsa44Addr = new DataWord(
"0000000000000000000000000000000000000000000000000000000000000019");
"0000000000000000000000000000000000000000000000000000000002000019");

// 0x1a: algorithm-agnostic Permission multi-sign — accepts ECDSA and any
// 0x0200001a: algorithm-agnostic Permission multi-sign — accepts ECDSA and any
// registered PQ scheme (Falcon-512, ML-DSA-44, ...) against the same
// Permission.keys[] in one call, dispatched by an explicit per-entry scheme
// tag. Replaces the earlier Falcon-only 0x17 and Dilithium-only draft, which
// tag. Replaces the earlier Falcon-only 0x02000017 and Dilithium-only draft, which
// were never activated.
private static final DataWord validateMultiPqSigAddr = new DataWord(
"000000000000000000000000000000000000000000000000000000000000001a");
"000000000000000000000000000000000000000000000000000000000200001a");

public static PrecompiledContract getOptimizedContractForConstant(PrecompiledContract contract) {
try {
Expand Down Expand Up @@ -352,7 +350,7 @@ public static PrecompiledContract getContractForAddress(DataWord address) {
return p256Verify;
}

// 0x1a ValidateMultiPQSig is algorithm-agnostic and dispatches per entry,
// 0x0200001a ValidateMultiPQSig is algorithm-agnostic and dispatches per entry,
// so it is available whenever ANY registered PQ scheme is active. Per-entry
// runtime checks inside the precompile still reject scheme tags whose
// proposal hasn't passed.
Expand Down Expand Up @@ -597,7 +595,7 @@ private static void cancelAll(List<? extends Future<?>> futures) {
* fixed slot {@code data[from..to)}: the offset of the last non-zero byte
* (exclusive). Canonical Falcon encodings always end in a non-zero byte
* ({@code compressed_s2}'s unary terminator), so anything beyond is zero
* padding. Returns 0 if the slot is all zero. Shared by 0x16, 0x18, and 0x1a
* padding. Returns 0 if the slot is all zero. Shared by 0x02000016, 0x02000017, and 0x0200001a
* because every precompile slot for Falcon sigs is the same 666-byte slot.
*/
static int recoverFalconSigLen(byte[] data, int from, int to) {
Expand All @@ -617,7 +615,7 @@ static int recoverFalconSigLen(byte[] data, int from, int to) {
* the logical body ends at the last non-zero byte. Returns
* {@code 0x39 ‖ body} so BC's {@code FalconSigner} (which requires the header)
* can verify it, or {@code null} if the recovered body length is out of range.
* Shared by 0x16, 0x18, and 0x1a.
* Shared by 0x02000016, 0x02000017, and 0x0200001a.
*/
static byte[] falconSlotToHeaderedSig(byte[] data, int from, int to) {
int bodyLen = recoverFalconSigLen(data, from, to);
Expand Down Expand Up @@ -2687,7 +2685,7 @@ public Pair<Boolean, byte[]> execute(byte[] data) {


/**
* 0x17 BatchValidateFnDsa512 — independent per-element Falcon-512 verify.
* 0x02000017 BatchValidateFnDsa512 — independent per-element Falcon-512 verify.
*
* <p>Returns a 256-bit bitmap (matching 0x09) where bit {@code i} is set iff
* {@code derive(pk_i) == expectedAddr_i} AND {@code FNDSA512.verify(pk_i, hash, sig_i)}.
Expand All @@ -2704,7 +2702,7 @@ public Pair<Boolean, byte[]> execute(byte[] data) {
* ) returns (bytes32)
* </pre>
*
* <p>Falcon sigs are pinned to the 666-byte slot from {@code VerifyFnDsa512} (0x16)
* <p>Falcon sigs are pinned to the 666-byte slot from {@code VerifyFnDsa512} (0x02000016)
* for cross-precompile consistency; {@link #falconSlotToHeaderedSig} recovers the
* headerless body and re-inserts the {@code 0x39} header before BC verification.
*
Expand Down Expand Up @@ -2882,7 +2880,7 @@ private static class PqVerifyResult {
* (precomputed {@code A_hat = ExpandA(rho)}). BC 1.84's {@code MLDSASigner}
* only accepts the standard form; we pay the per-call {@code ExpandA}
* cost so 1312 B Dilithium-2 keys work unchanged. The EIP-8051 expanded-pk
* variant is implemented separately at 0x12 — 0x19 stays as-is.
* variant is implemented separately at 0x12 — 0x02000019 stays as-is.
*/
public static class VerifyMlDsa44 extends PrecompiledContract {

Expand Down Expand Up @@ -2915,7 +2913,7 @@ public Pair<Boolean, byte[]> execute(byte[] data) {
}

/**
* 0x1a ValidateMultiPQSig — algorithm-agnostic Permission multi-sign. Accepts
* 0x0200001a ValidateMultiPQSig — algorithm-agnostic Permission multi-sign. Accepts
* ECDSA plus any registered post-quantum scheme (FN-DSA-512, ML-DSA-44, ...)
* against {@link Permission}{@code .keys[]} in a single call, dispatched per
* entry by an explicit {@code uint8[]} scheme tag array (PQScheme number).
Expand All @@ -2934,7 +2932,7 @@ public Pair<Boolean, byte[]> execute(byte[] data) {
* </pre>
*
* <p>Falcon sigs follow the EIP-8052 666-byte headerless slot convention
* (matches 0x16/0x18): the slot holds {@code salt ‖ s2_compressed} with no
* (matches 0x02000016/0x02000017): the slot holds {@code salt ‖ s2_compressed} with no
* leading {@code 0x39}, zero-padded, the body ending at the last non-zero byte
* (Falcon's {@code compressed_s2} always ends with a non-zero terminator);
* {@link #falconSlotToHeaderedSig} re-inserts the header before verification.
Expand All @@ -2946,7 +2944,7 @@ public Pair<Boolean, byte[]> execute(byte[] data) {
* cannot underpay by encoding a tag the dispatcher will then reject.
*
* <p>Per-entry runtime gate: a Falcon entry returns {@code DATA_FALSE} when
* {@code allowFnDsa512()} is false even though 0x1a itself is registered as
* {@code allowFnDsa512()} is false even though 0x0200001a itself is registered as
* long as one PQ proposal is active. Same for ML-DSA-44.
*/
public static class ValidateMultiPQSig extends PrecompiledContract {
Expand All @@ -2955,6 +2953,8 @@ public static class ValidateMultiPQSig extends PrecompiledContract {
private static final int FN_DSA_512_ENERGY = 220;
private static final int ML_DSA_44_ENERGY = 470;
private static final int WORST_PQ_ENERGY = ML_DSA_44_ENERGY;
private static final int WORST_ENERGY_PER_SIGN =
StrictMathWrapper.max(ECDSA_ENERGY_PER_SIGN, WORST_PQ_ENERGY);
private static final int MAX_SIZE = 5;
// address, permissionId, data, ecdsaOff, schemeOff, pqSigOff, pqPkOff.
private static final int ABI_HEAD_WORDS = 7;
Expand Down Expand Up @@ -2986,7 +2986,7 @@ public long getEnergyForData(byte[] data) {
}
return energy;
} catch (Throwable t) {
return (long) MAX_SIZE * WORST_PQ_ENERGY;
return (long) MAX_SIZE * WORST_ENERGY_PER_SIGN;
}
}

Expand Down Expand Up @@ -3075,7 +3075,7 @@ public Pair<Boolean, byte[]> execute(byte[] rawData) {
return Pair.of(true, DATA_FALSE);
}
// Per-entry runtime gate: the scheme's proposal must be active even
// though 0x1a was registered under (allowFnDsa512 || allowMlDsa44).
// though 0x0200001a was registered under (allowFnDsa512 || allowMlDsa44).
if (scheme == PQScheme.FN_DSA_512 && !VMConfig.allowFnDsa512()) {
return Pair.of(true, DATA_FALSE);
}
Expand Down Expand Up @@ -3138,10 +3138,10 @@ public Pair<Boolean, byte[]> execute(byte[] rawData) {
}

/**
* 0x19 BatchValidateMlDsa44 — independent per-element ML-DSA-44 verify.
* 0x02000019 BatchValidateMlDsa44 — independent per-element ML-DSA-44 verify.
* Returns a 256-bit bitmap where bit {@code i} is set iff
* {@code derive(pk_i) == expectedAddr_i} AND {@code MLDSA44.verify(pk_i, hash, sig_i)}.
* Same ABI shape as 0x17, with sigs 2420 B and pks 1312 B.
* Same ABI shape as 0x02000017, with sigs 2420 B and pks 1312 B.
* {@code MAX_SIZE = 16}; energy is {@code cnt × 470}.
*/
public static class BatchValidateMlDsa44 extends PrecompiledContract {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,16 @@
import org.tron.protos.Protocol.PQScheme;

/**
* Unit tests for the 0x17 batch independent Falcon-512 verify precompile.
* Unit tests for the 0x02000017 batch independent Falcon-512 verify precompile.
* Returns a 256-bit bitmap where bit i is set iff
* {@code derive(pk_i) == expectedAddr_i && FNDSA512.verify(pk_i, hash, sig_i)}.
* Stateless — no chain DB.
*/
@Slf4j
public class BatchValidateFnDsa512Test {

private static final DataWord ADDR_0X17 = new DataWord(
"0000000000000000000000000000000000000000000000000000000000000017");
private static final DataWord ADDR_0X02000017 = new DataWord(
"0000000000000000000000000000000000000000000000000000000002000017");

private static final String METHOD_SIGN =
"batchvalidatefndsa512(bytes32,bytes[],bytes[],bytes32[])";
Expand Down Expand Up @@ -58,12 +58,12 @@ public void disableProposal() {
@Test
public void switchOff_returnsNull() {
VMConfig.initAllowFnDsa512(0L);
Assert.assertNull(PrecompiledContracts.getContractForAddress(ADDR_0X17));
Assert.assertNull(PrecompiledContracts.getContractForAddress(ADDR_0X02000017));
}

@Test
public void switchOn_returnsContract() {
PrecompiledContract pc = PrecompiledContracts.getContractForAddress(ADDR_0X17);
PrecompiledContract pc = PrecompiledContracts.getContractForAddress(ADDR_0X02000017);
Assert.assertNotNull(pc);
Assert.assertTrue(pc instanceof BatchValidateFnDsa512);
}
Expand Down Expand Up @@ -430,7 +430,8 @@ public void pointerWordsExceedInput_returnsDataFalse() {

/**
* Pin a Falcon-512 signature into the precompile's fixed 666-byte slot using the
* EIP-8052 headerless convention enforced by 0x16 / 0x17 / 0x1a: strip BC's leading
* EIP-8052 headerless convention enforced by 0x02000016 / 0x02000017 / 0x0200001a:
* strip BC's leading
* 0x39 header so the slot holds {@code salt ‖ s2}; the tail is zero-padded.
*/
private static byte[] padSlot(byte[] sig) {
Expand All @@ -452,7 +453,7 @@ private Pair<Boolean, byte[]> run(byte[] hash, List<String> sigs,
contract.setVmShouldEndInUs(System.nanoTime() / 1000 + 5_000_000L);
}
Pair<Boolean, byte[]> ret = contract.execute(input);
logger.info("0x17 bitmap: {}", Hex.toHexString(ret.getRight()));
logger.info("0x02000017 bitmap: {}", Hex.toHexString(ret.getRight()));
return ret;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,16 @@
import org.tron.protos.Protocol.PQScheme;

/**
* Unit tests for the 0x19 batch independent ML-DSA-44 verify precompile.
* Unit tests for the 0x02000019 batch independent ML-DSA-44 verify precompile.
* Returns a 256-bit bitmap where bit i is set iff
* {@code derive(pk_i) == expectedAddr_i && MLDSA44.verify(pk_i, hash, sig_i)}.
* Stateless — no chain DB.
*/
@Slf4j
public class BatchValidateMlDsa44Test {

private static final DataWord ADDR_0X19 = new DataWord(
"0000000000000000000000000000000000000000000000000000000000000019");
private static final DataWord ADDR_0X02000019 = new DataWord(
"0000000000000000000000000000000000000000000000000000000002000019");

private static final String METHOD_SIGN =
"batchvalidatemldsa44(bytes32,bytes[],bytes[],bytes32[])";
Expand Down Expand Up @@ -58,12 +58,12 @@ public void disableProposal() {
@Test
public void switchOff_returnsNull() {
VMConfig.initAllowMlDsa44(0L);
Assert.assertNull(PrecompiledContracts.getContractForAddress(ADDR_0X19));
Assert.assertNull(PrecompiledContracts.getContractForAddress(ADDR_0X02000019));
}

@Test
public void switchOn_returnsContract() {
PrecompiledContract pc = PrecompiledContracts.getContractForAddress(ADDR_0X19);
PrecompiledContract pc = PrecompiledContracts.getContractForAddress(ADDR_0X02000019);
Assert.assertNotNull(pc);
Assert.assertTrue(pc instanceof BatchValidateMlDsa44);
}
Expand Down Expand Up @@ -311,7 +311,7 @@ private Pair<Boolean, byte[]> run(byte[] hash, List<String> sigs,
contract.setVmShouldEndInUs(System.nanoTime() / 1000 + 10_000_000L);
}
Pair<Boolean, byte[]> ret = contract.execute(input);
logger.info("0x19 bitmap: {}", Hex.toHexString(ret.getRight()));
logger.info("0x02000019 bitmap: {}", Hex.toHexString(ret.getRight()));
return ret;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import org.tron.core.vm.config.VMConfig;

/**
* Unit tests for the FN-DSA / Falcon-512 (0x16) verify precompile (EIP-8052 / TRON extension).
* Unit tests for the FN-DSA / Falcon-512 (0x02000016) verify precompile (EIP-8052 / TRON ext).
* Input layout (fixed-length): [msg 32B | sig 666B (zero-padded) | pk 896B] = 1594B total.
* The 666-byte sig slot holds the EIP-8052 <em>headerless</em> body (salt ‖ s2): BC's
* leading 0x39 header is stripped on the way in and re-inserted by the precompile.
Expand All @@ -20,7 +20,7 @@
public class FnDsaPrecompileTest {

private static final DataWord FNDSA_ADDR = new DataWord(
"0000000000000000000000000000000000000000000000000000000000000016");
"0000000000000000000000000000000000000000000000000000000002000016");

private static final int INPUT_LEN =
32 + FNDSA512.SIGNATURE_MAX_LENGTH - 1 + FNDSA512.PUBLIC_KEY_LENGTH;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@

/**
* Unit tests for the ML-DSA-44 verify precompile (FIPS 204 / Dilithium-2).
* Address 0x18: standard 1312-byte FIPS public key layout.
* Address 0x02000018: standard 1312-byte FIPS public key layout.
*/
public class MlDsa44PrecompileTest {

private static final DataWord MLDSA_DRAFT_ADDR = new DataWord(
"0000000000000000000000000000000000000000000000000000000000000018");
"0000000000000000000000000000000000000000000000000000000002000018");

private static final byte[] MESSAGE_HASH = new byte[32];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
import org.tron.protos.Protocol.PQScheme;

/**
* Unit tests for the unified 0x1a algorithm-agnostic Permission multi-sign
* Unit tests for the unified 0x0200001a algorithm-agnostic Permission multi-sign
* precompile. Replaces the per-scheme {@code ValidateMultiFnDsa512Test} and
* {@code ValidateMultiMlDsa44Test}: a single call may now mix ECDSA, FN-DSA-512
* and ML-DSA-44 entries against the same {@code Permission.keys[]}, dispatched
Expand All @@ -46,8 +46,8 @@
@Slf4j
public class ValidateMultiPQSigTest extends BaseTest {

private static final DataWord ADDR_0X1A = new DataWord(
"000000000000000000000000000000000000000000000000000000000000001a");
private static final DataWord ADDR_0X0200001A = new DataWord(
"000000000000000000000000000000000000000000000000000000000200001a");

private static final String METHOD_SIGN =
"validatemultipqsign(address,uint256,bytes32,bytes[],uint8[],bytes[],bytes[])";
Expand Down Expand Up @@ -85,28 +85,28 @@ public void after() {
public void bothSwitchesOff_returnsNull() {
VMConfig.initAllowFnDsa512(0L);
VMConfig.initAllowMlDsa44(0L);
Assert.assertNull(PrecompiledContracts.getContractForAddress(ADDR_0X1A));
Assert.assertNull(PrecompiledContracts.getContractForAddress(ADDR_0X0200001A));
}

@Test
public void onlyFalconSwitchOn_returnsContract() {
VMConfig.initAllowMlDsa44(0L);
PrecompiledContract pc = PrecompiledContracts.getContractForAddress(ADDR_0X1A);
PrecompiledContract pc = PrecompiledContracts.getContractForAddress(ADDR_0X0200001A);
Assert.assertNotNull(pc);
Assert.assertTrue(pc instanceof ValidateMultiPQSig);
}

@Test
public void onlyDilithiumSwitchOn_returnsContract() {
VMConfig.initAllowFnDsa512(0L);
PrecompiledContract pc = PrecompiledContracts.getContractForAddress(ADDR_0X1A);
PrecompiledContract pc = PrecompiledContracts.getContractForAddress(ADDR_0X0200001A);
Assert.assertNotNull(pc);
Assert.assertTrue(pc instanceof ValidateMultiPQSig);
}

@Test
public void bothSwitchesOn_returnsContract() {
PrecompiledContract pc = PrecompiledContracts.getContractForAddress(ADDR_0X1A);
PrecompiledContract pc = PrecompiledContracts.getContractForAddress(ADDR_0X0200001A);
Assert.assertNotNull(pc);
Assert.assertTrue(pc instanceof ValidateMultiPQSig);
}
Expand Down Expand Up @@ -367,7 +367,7 @@ public void mismatchedSchemeAndPqSigArrayLengths_returnsZero() {

@Test
public void falconEntryWhileFalconDisabled_returnsZero() {
// 0x1a stays registered because ML-DSA is still active, but a Falcon entry
// 0x0200001a stays registered because ML-DSA is still active, but a Falcon entry
// must be rejected per-entry when its proposal isn't passed.
VMConfig.initAllowFnDsa512(0L);
FNDSA512 falcon = new FNDSA512();
Expand Down Expand Up @@ -809,7 +809,7 @@ private Pair<Boolean, byte[]> runContract(byte[] ownerAddr, int permissionId, by
Repository deposit = RepositoryImpl.createRoot(StoreFactory.getInstance());
contract.setRepository(deposit);
Pair<Boolean, byte[]> ret = contract.execute(input);
logger.info("0x1a result: {}", Hex.toHexString(ret.getRight()));
logger.info("0x0200001a result: {}", Hex.toHexString(ret.getRight()));
return ret;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -816,9 +816,8 @@ public void validateAllowFnDsa512() {
long maintenanceTimeInterval = forkUtils.getManager().getDynamicPropertiesStore()
.getMaintenanceTimeInterval();
long hardForkTime =
((ForkBlockVersionEnum.VERSION_4_8_2_PQ1.getHardForkTime() - 1) / maintenanceTimeInterval +
1)
* maintenanceTimeInterval;
((ForkBlockVersionEnum.VERSION_4_8_2_PQ1.getHardForkTime() - 1) / maintenanceTimeInterval
+ 1) * maintenanceTimeInterval;
forkUtils.getManager().getDynamicPropertiesStore()
.saveLatestBlockHeaderTimestamp(hardForkTime - 1);

Expand Down Expand Up @@ -879,9 +878,8 @@ public void validateAllowMlDsa44() {
long maintenanceTimeInterval = forkUtils.getManager().getDynamicPropertiesStore()
.getMaintenanceTimeInterval();
long hardForkTime =
((ForkBlockVersionEnum.VERSION_4_8_2_PQ1.getHardForkTime() - 1) / maintenanceTimeInterval +
1)
* maintenanceTimeInterval;
((ForkBlockVersionEnum.VERSION_4_8_2_PQ1.getHardForkTime() - 1) / maintenanceTimeInterval
+ 1) * maintenanceTimeInterval;
forkUtils.getManager().getDynamicPropertiesStore()
.saveLatestBlockHeaderTimestamp(hardForkTime - 1);

Expand Down
Loading