From e80f340082b7694216b4454ca1c0e868ec5c58c9 Mon Sep 17 00:00:00 2001 From: KadenaFriend <241389759+kdafriend@users.noreply.github.com> Date: Fri, 4 Sep 2026 05:59:11 +0000 Subject: [PATCH] Implement Post-quantum --- cabal.project | 2 +- src/Chainweb/Pact5/InitialGasModel.hs | 26 +++++++++++++++++-- src/Chainweb/Pact5/TransactionExec.hs | 9 ++++++- src/Chainweb/Version.hs | 3 +++ src/Chainweb/Version/Development.hs | 2 +- src/Chainweb/Version/Guards.hs | 5 ++++ src/Chainweb/Version/Mainnet.hs | 5 ++++ src/Chainweb/Version/RecapDevelopment.hs | 5 +++- src/Chainweb/Version/Testnet04.hs | 1 + src/Chainweb/Version/Testnet06.hs | 10 +++++-- test/lib/Chainweb/Test/Pact5/CmdBuilder.hs | 1 + test/lib/Chainweb/Test/TestVersions.hs | 2 ++ .../Chainweb/Test/Pact5/RemotePactTest.hs | 6 ++--- 13 files changed, 66 insertions(+), 11 deletions(-) diff --git a/cabal.project b/cabal.project index f5a73a451d..b82495a635 100644 --- a/cabal.project +++ b/cabal.project @@ -100,7 +100,7 @@ source-repository-package source-repository-package type: git location: https://github.com/kda-community/pact-5 - tag: 72f427605406df61be8284091922f1fe1af7541b + tag: f8c98346a85e6d8267cd62e6cd83d9139e6c1e80 source-repository-package type: git diff --git a/src/Chainweb/Pact5/InitialGasModel.hs b/src/Chainweb/Pact5/InitialGasModel.hs index 6027a0b581..10db5f3871 100644 --- a/src/Chainweb/Pact5/InitialGasModel.hs +++ b/src/Chainweb/Pact5/InitialGasModel.hs @@ -1,12 +1,14 @@ {-# LANGUAGE LambdaCase #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE BangPatterns #-} +{-# LANGUAGE NumericUnderscores #-} module Chainweb.Pact5.InitialGasModel ( InitialGasModel(..) , pre31GasModel , post31GasModel , post32GasModel + , post33GasModel -- Lenses , feePerByte , rawPayloadSizeFactor @@ -18,8 +20,11 @@ module Chainweb.Pact5.InitialGasModel import Control.DeepSeq import Pact.Core.Scheme +import Pact.Core.Gas import Control.Lens +absoluteGasLimit :: Rational +absoluteGasLimit = fromIntegral $ _gas $ maxBound data InitialGasModel = InitialGasModel { _feePerByte :: Rational @@ -72,6 +77,23 @@ post32GasModel = InitialGasModel , _signatureSizeFactor = 1.0 , _sizePenalty = \x -> (x / 512) ^ (7 :: Integer) , _signatureCost = \case - ED25519 -> 21.0 -- | Benchmarked at 52 ns - WebAuthn -> 526.0 -- | Benchmarked at 1.315 ms (worst case) + ED25519 -> 21.0 -- | Benchmarked at 52 ns + WebAuthn -> 526.0 -- | Benchmarked at 1.315 ms (worst case) + _ -> absoluteGasLimit -- | Make sure the transaction will fail for unsupported schemes => Should never happen + } + + +post33GasModel :: InitialGasModel +post33GasModel = InitialGasModel + { _feePerByte = 0.01 + , _rawPayloadSizeFactor = 1.0 + , _proofSizeFactor = 1.0 + , _signatureSizeFactor = 1.0 + , _sizePenalty = \x -> (x / 512) ^ (7 :: Integer) + , _signatureCost = \case + ED25519 -> 21.0 -- | Benchmarked at 52 ns + WebAuthn -> 526.0 -- | Benchmarked at 1.315 ms (worst case) + SlhDsaSha128s -> 816.0 -- | Becnhmarked at 2.04 ms with OpenSSL backend + SlhDsaSha192s -> 1584.0 -- | Benchmarked at 3.96 ms with OpenSSL backend + SlhDsaSha256s -> 3992.0 -- | Benchmarked at 9.98 ms with OpenSSL backend } diff --git a/src/Chainweb/Pact5/TransactionExec.hs b/src/Chainweb/Pact5/TransactionExec.hs index f88e8b3d7f..785d866138 100644 --- a/src/Chainweb/Pact5/TransactionExec.hs +++ b/src/Chainweb/Pact5/TransactionExec.hs @@ -320,6 +320,7 @@ applyLocal logger maybeGasLogger coreDb txCtx spvSupport cmd = do , guardDisablePact52And53Flags , guardDisablePact54Flags , guardDisablePact54FixFlags + , guardDisablePostQuantum ] -- | The main entry point to executing transactions. From here, @@ -360,6 +361,7 @@ applyCmd logger maybeGasLogger db txCtx txIdxInBlock spv initialGas cmd = do , guardDisablePact52And53Flags , guardDisablePact54Flags , guardDisablePact54FixFlags + , guardDisablePostQuantum ] let gasLogsEnabled = maybe GasLogsDisabled (const GasLogsEnabled) maybeGasLogger @@ -1063,4 +1065,9 @@ guardDisablePact54Flags txCtx guardDisablePact54FixFlags :: TxContext -> Set ExecutionFlag guardDisablePact54FixFlags txCtx | guardCtx' chainweb32 txCtx = Set.empty - | otherwise = Set.singleton FlagDisablePact54Fix \ No newline at end of file + | otherwise = Set.singleton FlagDisablePact54Fix + +guardDisablePostQuantum :: TxContext -> Set ExecutionFlag +guardDisablePostQuantum txCtx + | guardCtx' chainweb33 txCtx = Set.empty + | otherwise = Set.singleton FlagDisableSlhDsaSignatures \ No newline at end of file diff --git a/src/Chainweb/Version.hs b/src/Chainweb/Version.hs index 13c12d9620..104e4ab273 100644 --- a/src/Chainweb/Version.hs +++ b/src/Chainweb/Version.hs @@ -241,6 +241,7 @@ data Fork | Chainweb231Pact | Chainweb31 | Chainweb32 + | Chainweb33 | MigratePlatformShare -- always add new forks at the end, not in the middle of the constructors. deriving stock (Bounded, Generic, Eq, Enum, Ord, Show) @@ -283,6 +284,7 @@ instance HasTextRepresentation Fork where toText Chainweb231Pact = "chainweb231Pact" toText Chainweb31 = "Chainweb31" toText Chainweb32 = "Chainweb32" + toText Chainweb33 = "Chainweb33" toText MigratePlatformShare = "migratePlatformShare" fromText "slowEpoch" = return SlowEpoch @@ -321,6 +323,7 @@ instance HasTextRepresentation Fork where fromText "chainweb231Pact" = return Chainweb231Pact fromText "Chainweb31" = return Chainweb31 fromText "Chainweb32" = return Chainweb32 + fromText "Chainweb33" = return Chainweb33 fromText "migratePlatformShare" = return MigratePlatformShare fromText t = throwM . TextFormatException $ "Unknown Chainweb fork: " <> t diff --git a/src/Chainweb/Version/Development.hs b/src/Chainweb/Version/Development.hs index c8437f3a06..38e267a0f0 100644 --- a/src/Chainweb/Version/Development.hs +++ b/src/Chainweb/Version/Development.hs @@ -54,7 +54,7 @@ devnet = ChainwebVersion -- defaultChainwebConfiguration._configBlockGasLimit , _versionMaxBlockGasLimit = Bottom (minBound, Nothing) , _versionSpvProofRootValidWindow = Bottom (minBound, Nothing) - , _versionInitialGasModel = AllChains $ Bottom (minBound, post32GasModel) + , _versionInitialGasModel = AllChains $ Bottom (minBound, post33GasModel) , _versionCheats = VersionCheats { _disablePow = True , _fakeFirstEpochStart = True diff --git a/src/Chainweb/Version/Guards.hs b/src/Chainweb/Version/Guards.hs index 296dd19c3c..7f7cf2eb89 100644 --- a/src/Chainweb/Version/Guards.hs +++ b/src/Chainweb/Version/Guards.hs @@ -52,6 +52,7 @@ module Chainweb.Version.Guards , chainweb231Pact , chainweb31 , chainweb32 + , chainweb33 , migratePlatformShare , pact5 , pact44NewTrans @@ -329,6 +330,10 @@ chainweb31 = checkFork atOrAfter Chainweb31 chainweb32 :: ChainwebVersion -> ChainId -> ForkNumber -> Bool chainweb32 = checkFork' atOrAfter Chainweb32 +-- | Pact Post-Quantum +chainweb33 :: ChainwebVersion -> ChainId -> ForkNumber -> Bool +chainweb33 = checkFork' atOrAfter Chainweb33 + migratePlatformShare :: ChainwebVersion -> ChainId -> BlockHeight -> Bool migratePlatformShare = checkFork atNotGenesis MigratePlatformShare diff --git a/src/Chainweb/Version/Mainnet.hs b/src/Chainweb/Version/Mainnet.hs index b266440ff0..d9d27ea8a8 100644 --- a/src/Chainweb/Version/Mainnet.hs +++ b/src/Chainweb/Version/Mainnet.hs @@ -159,6 +159,7 @@ mainnet = ChainwebVersion MigratePlatformShare -> AllChains (ForkAtBlockHeight $ BlockHeight 6_335_858) -- 2025-11-07 04:00:00+00:00 Chainweb31 -> AllChains (ForkAtBlockHeight $ BlockHeight 6_510_742) -- 2026-01-08 00:00:00+00:00 Chainweb32-> AllChains (ForkAtForkNumber 1) + Chainweb33-> AllChains (ForkAtForkNumber 2) , _versionGraphs = (to20ChainsMainnet, twentyChainGraph) @@ -168,6 +169,8 @@ mainnet = ChainwebVersion , _versionWindow = WindowWidth 120 , _versionHeaderBaseSizeBytes = 318 - 110 , _versionAllowedSignatureSchemes = AllChains $ + (afterFork mainnet Chainweb33, Set.fromList $ SchemeV5 <$> [Pact5.ED25519, Pact5.WebAuthn, Pact5.SlhDsaSha128s, Pact5.SlhDsaSha192s, Pact5.SlhDsaSha256s]) + `Above` (afterFork mainnet Pact5Fork, Set.fromList $ SchemeV5 <$> [Pact5.ED25519, Pact5.WebAuthn]) `Above` (afterFork mainnet Chainweb221Pact, Set.fromList $ SchemeV4 <$> [Pact4.ED25519, Pact4.WebAuthn]) @@ -180,6 +183,8 @@ mainnet = ChainwebVersion Bottom (minBound, Nothing) , _versionInitialGasModel = AllChains $ + (afterFork mainnet Chainweb33, post33GasModel) + `Above` (afterFork mainnet Chainweb32, post32GasModel) `Above` (succByHeight $ afterFork mainnet Chainweb31, post31GasModel) diff --git a/src/Chainweb/Version/RecapDevelopment.hs b/src/Chainweb/Version/RecapDevelopment.hs index 38904a8b6a..02d28de9e1 100644 --- a/src/Chainweb/Version/RecapDevelopment.hs +++ b/src/Chainweb/Version/RecapDevelopment.hs @@ -84,6 +84,7 @@ recapDevnet = ChainwebVersion MigratePlatformShare -> AllChains $ ForkAtBlockHeight $ BlockHeight 700 Chainweb31 -> AllChains $ ForkAtBlockHeight $ BlockHeight 710 Chainweb32 -> AllChains $ ForkAtGenesis + Chainweb33 -> AllChains $ ForkAtGenesis -- TODO Something wrong here , _versionUpgrades = foldr (chainZip HM.union) (AllChains mempty) [ indexByForkHeights recapDevnet @@ -119,13 +120,15 @@ recapDevnet = ChainwebVersion , _versionMaxBlockGasLimit = Bottom (minBound, Just 180_000) , _versionInitialGasModel = AllChains $ - (ForkNever, post32GasModel) + (ForkNever, post33GasModel) -- TODO Something wrong here `Above` (succByHeight $ afterFork recapDevnet Chainweb231Pact, post31GasModel) `Above` Bottom (minBound, pre31GasModel) , _versionAllowedSignatureSchemes = AllChains $ + (afterFork recapDevnet Chainweb33, Set.fromList $ SchemeV5 <$> [Pact5.ED25519, Pact5.WebAuthn, Pact5.SlhDsaSha128s, Pact5.SlhDsaSha192s, Pact5.SlhDsaSha256s]) + `Above` (afterFork recapDevnet Pact5Fork, Set.fromList $ SchemeV5 <$> [Pact5.ED25519, Pact5.WebAuthn]) `Above` (afterFork recapDevnet Chainweb221Pact, Set.fromList $ SchemeV4 <$> [Pact4.ED25519, Pact4.WebAuthn]) diff --git a/src/Chainweb/Version/Testnet04.hs b/src/Chainweb/Version/Testnet04.hs index 31040b4a55..02ce995af3 100644 --- a/src/Chainweb/Version/Testnet04.hs +++ b/src/Chainweb/Version/Testnet04.hs @@ -140,6 +140,7 @@ testnet04 = ChainwebVersion Chainweb231Pact -> AllChains $ ForkAtBlockHeight $ BlockHeight 5_783_985 -- 2025-10-15 12:00:00+00:00 Chainweb31 -> AllChains ForkNever Chainweb32 -> AllChains ForkNever + Chainweb33 -> AllChains ForkNever MigratePlatformShare -> AllChains ForkNever , _versionGraphs = (to20ChainsTestnet, twentyChainGraph) diff --git a/src/Chainweb/Version/Testnet06.hs b/src/Chainweb/Version/Testnet06.hs index e3d4e4bd59..71e59fe9da 100644 --- a/src/Chainweb/Version/Testnet06.hs +++ b/src/Chainweb/Version/Testnet06.hs @@ -23,6 +23,7 @@ import Chainweb.Version import P2P.BootstrapNodes import Pact.Types.Verifier +import qualified Pact.Core.Scheme as Pact5 (PPKScheme(..)) import qualified Chainweb.Pact.Transactions.OtherTransactions as CoinV2 import qualified Chainweb.Pact.Transactions.CoinV3Transactions as CoinV3 @@ -79,6 +80,7 @@ testnet06 = ChainwebVersion Chainweb231Pact -> AllChains $ ForkAtBlockHeight $ BlockHeight 690 Chainweb31 -> AllChains $ ForkAtBlockHeight $ BlockHeight 700 Chainweb32-> AllChains (ForkAtForkNumber 1) + Chainweb33-> AllChains (ForkAtForkNumber 2) MigratePlatformShare -> AllChains $ ForkNever , _versionUpgrades = foldr (chainZip HM.union) (AllChains mempty) @@ -107,6 +109,8 @@ testnet06 = ChainwebVersion ] } , _versionInitialGasModel = AllChains $ + (afterFork testnet06 Chainweb33, post33GasModel) + `Above` (afterFork testnet06 Chainweb32, post32GasModel) `Above` Bottom (minBound, post31GasModel) @@ -125,8 +129,10 @@ testnet06 = ChainwebVersion (ForkAtBlockHeight $ BlockHeight 600, Set.fromList $ map VerifierName ["hyperlane_v3_message"]) `Above` Bottom (minBound, mempty) - , _versionAllowedSignatureSchemes = - AllChains $ Bottom (minBound, Set.empty) + , _versionAllowedSignatureSchemes = AllChains $ + (afterFork testnet06 Chainweb33, Set.fromList $ SchemeV5 <$> [Pact5.ED25519, Pact5.WebAuthn, Pact5.SlhDsaSha128s, Pact5.SlhDsaSha192s, Pact5.SlhDsaSha256s]) + `Above` + Bottom (minBound, Set.fromList $ SchemeV5 <$> [Pact5.ED25519, Pact5.WebAuthn]) , _versionQuirks = noQuirks , _versionForkNumber = 1 , _versionForkVoteCastingLength = 120 * 119 -- 5 days diff --git a/test/lib/Chainweb/Test/Pact5/CmdBuilder.hs b/test/lib/Chainweb/Test/Pact5/CmdBuilder.hs index 2672b553bd..5870c0c6cc 100644 --- a/test/lib/Chainweb/Test/Pact5/CmdBuilder.hs +++ b/test/lib/Chainweb/Test/Pact5/CmdBuilder.hs @@ -262,6 +262,7 @@ mkDynKeyPairs (CmdSigner Signer{..} privKey) = privWebAuthn <- either diePrivKey return (parseWebAuthnPrivateKey =<< parseB16TextOnly priv) return $ (DynWebAuthnKeyPair wasPrefixed pubWebAuthn privWebAuthn, _siCapList) + _ -> error "SLH DSA not implemented here for now" where diePubKey str = error $ "pubkey: " <> str diePrivKey str = error $ "privkey: " <> str diff --git a/test/lib/Chainweb/Test/TestVersions.hs b/test/lib/Chainweb/Test/TestVersions.hs index cc5e457679..44449b489a 100644 --- a/test/lib/Chainweb/Test/TestVersions.hs +++ b/test/lib/Chainweb/Test/TestVersions.hs @@ -346,6 +346,7 @@ slowForks = tabulateHashMap \case Chainweb231Pact -> AllChains $ ForkAtBlockHeight (BlockHeight 160) MigratePlatformShare -> AllChains $ ForkAtBlockHeight (BlockHeight 165) Chainweb31 -> AllChains $ ForkAtBlockHeight (BlockHeight 170) + Chainweb33 -> AllChains ForkNever -- | A set of fork heights which are relatively fast, but not fast enough to break anything. @@ -388,6 +389,7 @@ fastForks = tabulateHashMap $ \case Chainweb231Pact -> AllChains $ ForkAtBlockHeight $ BlockHeight 54 Chainweb31 -> AllChains $ ForkAtBlockHeight $ BlockHeight 56 MigratePlatformShare -> AllChains ForkNever + Chainweb33 -> AllChains ForkNever -- | CPM version (see `cpmTestVersion`) with forks and upgrades slowly enabled. slowForkingCpmTestVersion :: ChainGraph -> ChainwebVersion diff --git a/test/unit/Chainweb/Test/Pact5/RemotePactTest.hs b/test/unit/Chainweb/Test/Pact5/RemotePactTest.hs index 7c4f2c7cf3..ed3fd44c0d 100644 --- a/test/unit/Chainweb/Test/Pact5/RemotePactTest.hs +++ b/test/unit/Chainweb/Test/Pact5/RemotePactTest.hs @@ -474,7 +474,7 @@ sendInvalidTxsTest rdb = withResourceT (mkFixture v rdb) $ \fx -> { -- This is an invalid ED25519 signature, -- but length signers == length signatures is checked first - _cmdSigs = [ED25519Sig "fakeSig"] + _cmdSigs = [PlainSig "fakeSig"] } send fx v cid [cmdSignersSigsLengthMismatch2] & P.throws ? P.match _FailureResponse ? P.fun responseBody ? textContains @@ -609,7 +609,7 @@ sendInvalidTxsTest rdb = withResourceT (mkFixture v rdb) $ \fx -> validationFailed i cmd msg = "Transaction " <> sshow (_cmdHash cmd) <> " at index " <> sshow @Int i <> " failed with: " <> msg - mkCmdInvalidUserSig = mkCmdGood <&> set cmdSigs [ED25519Sig "fakeSig"] + mkCmdInvalidUserSig = mkCmdGood <&> set cmdSigs [PlainSig "fakeSig"] mkCmdGood = buildTextCmd v $ set cbRPC (mkExec "(+ 1 2)" (mkKeySetData "sender00" [sender00])) @@ -1102,7 +1102,7 @@ localTests baseRdb = let goodCmdHash <- _cmdHash <$> buildTextCmd v buildSender00Cmd sender01KeyPair <- either error return $ importEd25519KeyPair Nothing (PrivBS $ either error id $ B16.decode $ T.encodeUtf8 $ snd sender01) - let sender01Sig = ED25519Sig $ T.decodeUtf8 $ B16.encode $ exportEd25519Signature $ + let sender01Sig = PlainSig $ T.decodeUtf8 $ B16.encode $ exportEd25519Signature $ signEd25519 (fst sender01KeyPair) (snd sender01KeyPair) goodCmdHash buildTextCmd v buildSender00Cmd