-
Notifications
You must be signed in to change notification settings - Fork 0
feat(crypto): add MLDSA / FN-DSA / SLH-DSA / Ephemeral secp256k1 post-quantum schemes #22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: release_pqc_base
Are you sure you want to change the base?
Changes from all commits
02af25c
9ca04fb
c5a7bac
a08de98
51af6b6
dc59e65
d793a84
0c5d4c9
15c1742
7531eae
8de44b4
3476710
b94123e
a802fb0
22b0341
fe5ce69
775404d
d00d184
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -886,6 +886,41 @@ public static void validator(DynamicPropertiesStore dynamicPropertiesStore, | |
| } | ||
| break; | ||
| } | ||
| case ALLOW_ML_DSA_44: { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P1: Add fork-version gating for the new PQ proposal IDs; they currently bypass activation checks used by other recently added governance params. Prompt for AI agents |
||
| if (value != 0 && value != 1) { | ||
| throw new ContractValidateException( | ||
| "This value[ALLOW_ML_DSA_44] is only allowed to be 0 or 1"); | ||
| } | ||
| break; | ||
| } | ||
| case ALLOW_ML_DSA_65: { | ||
| if (value != 0 && value != 1) { | ||
| throw new ContractValidateException( | ||
| "This value[ALLOW_ML_DSA_65] is only allowed to be 0 or 1"); | ||
| } | ||
| break; | ||
| } | ||
| case ALLOW_SLH_DSA: { | ||
| if (value != 0 && value != 1) { | ||
| throw new ContractValidateException( | ||
| "This value[ALLOW_SLH_DSA] is only allowed to be 0 or 1"); | ||
| } | ||
| break; | ||
| } | ||
| case ALLOW_FN_DSA: { | ||
| if (value != 0 && value != 1) { | ||
| throw new ContractValidateException( | ||
| "This value[ALLOW_FN_DSA] is only allowed to be 0 or 1"); | ||
| } | ||
| break; | ||
| } | ||
| case ALLOW_EPHEMERAL_SECP256K1: { | ||
| if (value != 0 && value != 1) { | ||
| throw new ContractValidateException( | ||
| "This value[ALLOW_EPHEMERAL_SECP256K1] is only allowed to be 0 or 1"); | ||
| } | ||
| break; | ||
| } | ||
| default: | ||
| break; | ||
| } | ||
|
|
@@ -971,7 +1006,12 @@ public enum ProposalType { // current value, value range | |
| ALLOW_TVM_BLOB(89), // 0, 1 | ||
| PROPOSAL_EXPIRE_TIME(92), // (0, 31536003000) | ||
| ALLOW_TVM_SELFDESTRUCT_RESTRICTION(94), // 0, 1 | ||
| ALLOW_TVM_OSAKA(96); // 0, 1 | ||
| ALLOW_TVM_OSAKA(96), // 0, 1 | ||
| ALLOW_ML_DSA_44(97), // 0, 1 (renamed from ALLOW_ML_DSA; ID preserved) | ||
| ALLOW_ML_DSA_65(98), // 0, 1 | ||
| ALLOW_SLH_DSA(99), // 0, 1 | ||
| ALLOW_FN_DSA(100), // 0, 1 | ||
| ALLOW_EPHEMERAL_SECP256K1(101); // 0, 1 | ||
|
|
||
| private long code; | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,21 +18,42 @@ | |
| import com.google.common.collect.Lists; | ||
| import java.util.List; | ||
| import lombok.Getter; | ||
| import lombok.Setter; | ||
| import lombok.extern.slf4j.Slf4j; | ||
| import org.apache.commons.collections4.CollectionUtils; | ||
| import org.apache.commons.lang3.StringUtils; | ||
| import org.tron.common.crypto.ECKey; | ||
| import org.tron.common.crypto.SignInterface; | ||
| import org.tron.common.crypto.SignUtils; | ||
| import org.tron.common.crypto.pqc.MLDSA65; | ||
| import org.tron.common.crypto.pqc.PqSignatureRegistry; | ||
| import org.tron.core.config.Parameter.ChainConstant; | ||
| import org.tron.core.exception.TronError; | ||
| import org.tron.protos.Protocol.SignatureScheme; | ||
|
|
||
| @Slf4j(topic = "app") | ||
| public class LocalWitnesses { | ||
|
|
||
| @Getter | ||
| private List<String> privateKeys = Lists.newArrayList(); | ||
|
|
||
| /** ML-DSA seed values in hex format (64 hex chars = 32 bytes). */ | ||
| @Getter | ||
| private List<String> pqSeeds = Lists.newArrayList(); | ||
|
|
||
| /** PQ signature scheme used to derive keys from {@link #pqSeeds}. */ | ||
| @Getter | ||
| private SignatureScheme pqScheme = SignatureScheme.ML_DSA_65; | ||
|
|
||
| public void setPqScheme(SignatureScheme pqScheme) { | ||
| if (pqScheme == null || !PqSignatureRegistry.contains(pqScheme)) { | ||
| throw new TronError("unsupported PQ signature scheme: " + pqScheme, | ||
| TronError.ErrCode.WITNESS_INIT); | ||
| } | ||
| this.pqScheme = pqScheme; | ||
| } | ||
|
|
||
| @Setter | ||
| @Getter | ||
| private byte[] witnessAccountAddress; | ||
|
|
||
|
|
@@ -95,6 +116,35 @@ public void addPrivateKeys(String privateKey) { | |
| this.privateKeys.add(privateKey); | ||
| } | ||
|
|
||
| /** ML-DSA seed values (32 bytes = 64 hex chars). Keys are derived from seeds. */ | ||
| public void setPqSeeds(final List<String> pqSeeds) { | ||
| if (CollectionUtils.isEmpty(pqSeeds)) { | ||
| return; | ||
| } | ||
| for (String seed : pqSeeds) { | ||
| validatePqSeed(seed); | ||
| } | ||
| this.pqSeeds = pqSeeds; | ||
| } | ||
|
|
||
| private static void validatePqSeed(String seed) { | ||
| String hex = seed; | ||
| // Match downstream ByteArray.fromHexString, which only strips lowercase "0x". | ||
| if (StringUtils.startsWith(hex, "0x")) { | ||
| hex = hex.substring(2); | ||
| } | ||
| int expectedHexLen = MLDSA65.SEED_LENGTH * 2; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P1: Seed length validation is hardcoded to Prompt for AI agents |
||
| if (StringUtils.isBlank(hex) || hex.length() != expectedHexLen) { | ||
| throw new TronError(String.format("ML-DSA seed must be %d hex chars, actual: %d", | ||
| expectedHexLen, StringUtils.isBlank(hex) ? 0 : hex.length()), | ||
| TronError.ErrCode.WITNESS_INIT); | ||
| } | ||
| if (!StringUtil.isHexadecimal(hex)) { | ||
| throw new TronError("ML-DSA seed must be hex string", | ||
| TronError.ErrCode.WITNESS_INIT); | ||
| } | ||
| } | ||
|
|
||
| //get the first one recently | ||
| public String getPrivateKey() { | ||
| if (CollectionUtils.isEmpty(privateKeys)) { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2:
expectedPublicKeyLengthduplicatesPqSignatureRegistry.getPublicKeyLength; use the registry as the single source of truth. If a new scheme is added to the registry but not to this switch, valid keys will be rejected. Replace the manual switch with aPqSignatureRegistry.contains+getPublicKeyLengthcall.(Based on your team's feedback about treating the registry as the single source of truth for allowed schemes.)
View Feedback
Prompt for AI agents