Skip to content

Commit

Permalink
Rename bitwise builtins, use proper costing
Browse files Browse the repository at this point in the history
  • Loading branch information
kozross committed Jun 6, 2024
1 parent f62c4de commit e2ce78a
Show file tree
Hide file tree
Showing 9 changed files with 127 additions and 124 deletions.
37 changes: 20 additions & 17 deletions plutus-core/plutus-core/src/PlutusCore/Bitwise/Logical.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

-- | Implementations of bitwise logical primops.
module PlutusCore.Bitwise.Logical (
bitwiseLogicalAnd,
bitwiseLogicalOr,
bitwiseLogicalXor,
bitwiseLogicalComplement,
andByteString,
orByteString,
xorByteString,
complementByteString,
readBit,
writeBits,
replicateByteString
Expand All @@ -30,8 +30,8 @@ import System.IO.Unsafe (unsafeDupablePerformIO)

{- Note [Binary bitwise operation implementation and manual specialization]
All of the 'binary' bitwise operations (namely `bitwiseLogicalAnd`,
`bitwiseLogicalOr` and `bitwiseLogicalXor`) operate similarly:
All of the 'binary' bitwise operations (namely `andByteString`,
`orByteString` and `xorByteString`) operate similarly:
1. Decide which of their two `ByteString` arguments determines the length
of the result. For padding semantics, this is the _longer_ argument,
Expand All @@ -41,8 +41,8 @@ import System.IO.Unsafe (unsafeDupablePerformIO)
2. Copy the choice made in step 1 into a fresh mutable buffer.
3. Traverse over each byte of the argument _not_ chosen in step 1, and
combine each of those bytes with the byte at the corresponding index of
the fresh mutable buffer from step 2 (`.&.` for `bitwiseLogicalAnd`,
`.|.` for `bitwiseLogicalOr`, `xor` for `bitwiseLogicalXor`).
the fresh mutable buffer from step 2 (`.&.` for `andByteString`,
`.|.` for `orByteString`, `xor` for `xorByteString`).
We also make use of loop sectioning to optimize this operation: see Note
[Loop sectioning] explaining why we do this. Fundamentally, this doesn't
Expand Down Expand Up @@ -103,8 +103,9 @@ import System.IO.Unsafe (unsafeDupablePerformIO)
-}

-- | Bitwise logical AND, as per [CIP-122](https://github.com/mlabs-haskell/CIPs/blob/koz/logic-ops/CIP-0122/CIP-0122.md).
bitwiseLogicalAnd :: Bool -> ByteString -> ByteString -> ByteString
bitwiseLogicalAnd shouldPad bs1 bs2 =
{-# INLINEABLE andByteString #-}
andByteString :: Bool -> ByteString -> ByteString -> ByteString
andByteString shouldPad bs1 bs2 =
let (shorter, longer) = if BS.length bs1 < BS.length bs2 then (bs1, bs2) else (bs2, bs1)
(toCopy, toTraverse) = if shouldPad then (longer, shorter) else (shorter, longer)
in go toCopy toTraverse (BS.length shorter)
Expand All @@ -131,8 +132,9 @@ bitwiseLogicalAnd shouldPad bs1 bs2 =
pokeElemOff smallDstPtr i $ w8_1 Bits..&. w8_2

-- | Bitwise logical OR, as per [CIP-122](https://github.com/mlabs-haskell/CIPs/blob/koz/logic-ops/CIP-0122/CIP-0122.md).
bitwiseLogicalOr :: Bool -> ByteString -> ByteString -> ByteString
bitwiseLogicalOr shouldPad bs1 bs2 =
{-# INLINEABLE orByteString #-}
orByteString :: Bool -> ByteString -> ByteString -> ByteString
orByteString shouldPad bs1 bs2 =
let (shorter, longer) = if BS.length bs1 < BS.length bs2 then (bs1, bs2) else (bs2, bs1)
(toCopy, toTraverse) = if shouldPad then (longer, shorter) else (shorter, longer)
in go toCopy toTraverse (BS.length shorter)
Expand All @@ -159,8 +161,9 @@ bitwiseLogicalOr shouldPad bs1 bs2 =
pokeElemOff smallDstPtr i $ w8_1 Bits..|. w8_2

-- | Bitwise logical XOR, as per [CIP-122](https://github.com/mlabs-haskell/CIPs/blob/koz/logic-ops/CIP-0122/CIP-0122.md).
bitwiseLogicalXor :: Bool -> ByteString -> ByteString -> ByteString
bitwiseLogicalXor shouldPad bs1 bs2 =
{-# INLINEABLE xorByteString #-}
xorByteString :: Bool -> ByteString -> ByteString -> ByteString
xorByteString shouldPad bs1 bs2 =
let (shorter, longer) = if BS.length bs1 < BS.length bs2 then (bs1, bs2) else (bs2, bs1)
(toCopy, toTraverse) = if shouldPad then (longer, shorter) else (shorter, longer)
in go toCopy toTraverse (BS.length shorter)
Expand All @@ -187,9 +190,9 @@ bitwiseLogicalXor shouldPad bs1 bs2 =
pokeElemOff smallDstPtr i $ Bits.xor w8_1 w8_2

-- | Bitwise logical complement, as per [CIP-122](https://github.com/mlabs-haskell/CIPs/blob/koz/logic-ops/CIP-0122/CIP-0122.md).
{-# INLINEABLE bitwiseLogicalComplement #-}
bitwiseLogicalComplement :: ByteString -> ByteString
bitwiseLogicalComplement bs = unsafeDupablePerformIO . BS.useAsCStringLen bs $ \(srcPtr, len) -> do
{-# INLINEABLE complementByteString #-}
complementByteString :: ByteString -> ByteString
complementByteString bs = unsafeDupablePerformIO . BS.useAsCStringLen bs $ \(srcPtr, len) -> do
-- We use loop sectioning here; see Note [Loop sectioning] as to why we do this
let (bigStrides, littleStrides) = len `quotRem` 8
let offset = bigStrides * 8
Expand Down
64 changes: 32 additions & 32 deletions plutus-core/plutus-core/src/PlutusCore/Default/Builtins.hs
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,10 @@ data DefaultFun
| IntegerToByteString
| ByteStringToInteger
-- Logical
| BitwiseLogicalAnd
| BitwiseLogicalOr
| BitwiseLogicalXor
| BitwiseLogicalComplement
| AndByteString
| OrByteString
| XorByteString
| ComplementByteString
| ReadBit
| WriteBits
| ReplicateByteString
Expand Down Expand Up @@ -1832,36 +1832,36 @@ instance uni ~ DefaultUni => ToBuiltinMeaning uni DefaultFun where
(runCostingFunTwoArguments . paramByteStringToInteger)

-- Logical
toBuiltinMeaning _semvar BitwiseLogicalAnd =
let bitwiseLogicalAndDenotation :: Bool -> BS.ByteString -> BS.ByteString -> BS.ByteString
bitwiseLogicalAndDenotation = Logical.bitwiseLogicalAnd
{-# INLINE bitwiseLogicalAndDenotation #-}
toBuiltinMeaning _semvar AndByteString =
let andByteStringDenotation :: Bool -> BS.ByteString -> BS.ByteString -> BS.ByteString
andByteStringDenotation = Logical.andByteString
{-# INLINE andByteStringDenotation #-}
in makeBuiltinMeaning
bitwiseLogicalAndDenotation
andByteStringDenotation
(runCostingFunThreeArguments . unimplementedCostingFun)

toBuiltinMeaning _semvar BitwiseLogicalOr =
let bitwiseLogicalOrDenotation :: Bool -> BS.ByteString -> BS.ByteString -> BS.ByteString
bitwiseLogicalOrDenotation = Logical.bitwiseLogicalOr
{-# INLINE bitwiseLogicalOrDenotation #-}
toBuiltinMeaning _semvar OrByteString =
let orByteStringDenotation :: Bool -> BS.ByteString -> BS.ByteString -> BS.ByteString
orByteStringDenotation = Logical.orByteString
{-# INLINE orByteStringDenotation #-}
in makeBuiltinMeaning
bitwiseLogicalOrDenotation
orByteStringDenotation
(runCostingFunThreeArguments . unimplementedCostingFun)

toBuiltinMeaning _semvar BitwiseLogicalXor =
let bitwiseLogicalXorDenotation :: Bool -> BS.ByteString -> BS.ByteString -> BS.ByteString
bitwiseLogicalXorDenotation = Logical.bitwiseLogicalXor
{-# INLINE bitwiseLogicalXorDenotation #-}
toBuiltinMeaning _semvar XorByteString =
let xorByteStringDenotation :: Bool -> BS.ByteString -> BS.ByteString -> BS.ByteString
xorByteStringDenotation = Logical.xorByteString
{-# INLINE xorByteStringDenotation #-}
in makeBuiltinMeaning
bitwiseLogicalXorDenotation
xorByteStringDenotation
(runCostingFunThreeArguments . unimplementedCostingFun)

toBuiltinMeaning _semvar BitwiseLogicalComplement =
let bitwiseLogicalComplementDenotation :: BS.ByteString -> BS.ByteString
bitwiseLogicalComplementDenotation = Logical.bitwiseLogicalComplement
{-# INLINE bitwiseLogicalComplementDenotation #-}
toBuiltinMeaning _semvar ComplementByteString =
let complementByteStringDenotation :: BS.ByteString -> BS.ByteString
complementByteStringDenotation = Logical.complementByteString
{-# INLINE complementByteStringDenotation #-}
in makeBuiltinMeaning
bitwiseLogicalComplementDenotation
complementByteStringDenotation
(runCostingFunOneArgument . unimplementedCostingFun)

toBuiltinMeaning _semvar ReadBit =
Expand Down Expand Up @@ -2015,10 +2015,10 @@ instance Flat DefaultFun where
IntegerToByteString -> 73
ByteStringToInteger -> 74

BitwiseLogicalAnd -> 75
BitwiseLogicalOr -> 76
BitwiseLogicalXor -> 77
BitwiseLogicalComplement -> 78
AndByteString -> 75
OrByteString -> 76
XorByteString -> 77
ComplementByteString -> 78
ReadBit -> 79
WriteBits -> 80
ReplicateByteString -> 81
Expand Down Expand Up @@ -2099,10 +2099,10 @@ instance Flat DefaultFun where
go 72 = pure Blake2b_224
go 73 = pure IntegerToByteString
go 74 = pure ByteStringToInteger
go 75 = pure BitwiseLogicalAnd
go 76 = pure BitwiseLogicalOr
go 77 = pure BitwiseLogicalXor
go 78 = pure BitwiseLogicalComplement
go 75 = pure AndByteString
go 76 = pure OrByteString
go 77 = pure XorByteString
go 78 = pure ComplementByteString
go 79 = pure ReadBit
go 80 = pure WriteBits
go 81 = pure ReplicateByteString
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,10 @@ isCommutative = \case
ByteStringToInteger -> False
-- Currently, this requires commutativity in all arguments, which the
-- logical operations are not.
BitwiseLogicalAnd -> False
BitwiseLogicalOr -> False
BitwiseLogicalXor -> False
BitwiseLogicalComplement -> False
AndByteString -> False
OrByteString -> False
XorByteString -> False
ComplementByteString -> False
ReadBit -> False
WriteBits -> False
ReplicateByteString -> False
Original file line number Diff line number Diff line change
Expand Up @@ -909,29 +909,29 @@ test_Logical =
adjustOption (\x -> max x . HedgehogTestLimit . Just $ 4000) .
testGroup "Logical" $ [
testGroup "bitwiseLogicalAnd" [
Laws.abelianSemigroupLaws "truncation" PLC.BitwiseLogicalAnd False,
Laws.idempotenceLaw "truncation" PLC.BitwiseLogicalAnd False,
Laws.absorbtionLaw "truncation" PLC.BitwiseLogicalAnd False "",
Laws.leftDistributiveLaw "truncation" "itself" PLC.BitwiseLogicalAnd PLC.BitwiseLogicalAnd False,
Laws.leftDistributiveLaw "truncation" "OR" PLC.BitwiseLogicalAnd PLC.BitwiseLogicalOr False,
Laws.leftDistributiveLaw "truncation" "XOR" PLC.BitwiseLogicalAnd PLC.BitwiseLogicalXor False,
Laws.abelianMonoidLaws "padding" PLC.BitwiseLogicalAnd True "",
Laws.distributiveLaws "padding" PLC.BitwiseLogicalAnd True
Laws.abelianSemigroupLaws "truncation" PLC.AndByteString False,
Laws.idempotenceLaw "truncation" PLC.AndByteString False,
Laws.absorbtionLaw "truncation" PLC.AndByteString False "",
Laws.leftDistributiveLaw "truncation" "itself" PLC.AndByteString PLC.AndByteString False,
Laws.leftDistributiveLaw "truncation" "OR" PLC.AndByteString PLC.OrByteString False,
Laws.leftDistributiveLaw "truncation" "XOR" PLC.AndByteString PLC.XorByteString False,
Laws.abelianMonoidLaws "padding" PLC.AndByteString True "",
Laws.distributiveLaws "padding" PLC.AndByteString True
],
testGroup "bitwiseLogicalOr" [
Laws.abelianSemigroupLaws "truncation" PLC.BitwiseLogicalOr False,
Laws.idempotenceLaw "truncation" PLC.BitwiseLogicalOr False,
Laws.absorbtionLaw "truncation" PLC.BitwiseLogicalOr False "",
Laws.leftDistributiveLaw "truncation" "itself" PLC.BitwiseLogicalOr PLC.BitwiseLogicalOr False,
Laws.leftDistributiveLaw "truncation" "AND" PLC.BitwiseLogicalOr PLC.BitwiseLogicalAnd False,
Laws.abelianMonoidLaws "padding" PLC.BitwiseLogicalOr True "",
Laws.distributiveLaws "padding" PLC.BitwiseLogicalOr True
Laws.abelianSemigroupLaws "truncation" PLC.OrByteString False,
Laws.idempotenceLaw "truncation" PLC.OrByteString False,
Laws.absorbtionLaw "truncation" PLC.OrByteString False "",
Laws.leftDistributiveLaw "truncation" "itself" PLC.OrByteString PLC.OrByteString False,
Laws.leftDistributiveLaw "truncation" "AND" PLC.OrByteString PLC.AndByteString False,
Laws.abelianMonoidLaws "padding" PLC.OrByteString True "",
Laws.distributiveLaws "padding" PLC.OrByteString True
],
testGroup "bitwiseLogicalXor" [
Laws.abelianSemigroupLaws "truncation" PLC.BitwiseLogicalXor False,
Laws.absorbtionLaw "truncation" PLC.BitwiseLogicalXor False "",
Laws.abelianSemigroupLaws "truncation" PLC.XorByteString False,
Laws.absorbtionLaw "truncation" PLC.XorByteString False "",
Laws.xorInvoluteLaw,
Laws.abelianMonoidLaws "padding" PLC.BitwiseLogicalXor True ""
Laws.abelianMonoidLaws "padding" PLC.XorByteString True ""
],
testGroup "bitwiseLogicalComplement" [
Laws.complementSelfInverse,
Expand Down
24 changes: 12 additions & 12 deletions plutus-core/untyped-plutus-core/test/Evaluation/Builtins/Laws.hs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import Hedgehog.Gen qualified as Gen
import Hedgehog.Range qualified as Range
import Numeric (showHex)
import PlutusCore qualified as PLC
import PlutusCore.Evaluation.Machine.ExBudgetingDefaults (defaultBuiltinCostModel)
import PlutusCore.Evaluation.Machine.ExBudgetingDefaults (defaultBuiltinCostModelForTesting)
import PlutusCore.MkPlc (builtin, mkConstant, mkIterAppNoAnn)
import PlutusPrelude (Word8, def)
import Test.Tasty (TestTree, testGroup)
Expand Down Expand Up @@ -69,7 +69,7 @@ getSet =
mkConstant @ByteString () bs,
mkConstant @Integer () i
]
case typecheckReadKnownCek def defaultBuiltinCostModel lookupExp of
case typecheckReadKnownCek def defaultBuiltinCostModelForTesting lookupExp of
Left err -> annotateShow err >> failure
Right (Left err) -> annotateShow err >> failure
Right (Right b) -> do
Expand Down Expand Up @@ -227,10 +227,10 @@ complementSelfInverse :: TestTree
complementSelfInverse =
testPropertyNamed "self-inverse" "self_inverse" . property $ do
bs <- forAllByteString
let lhsInner = mkIterAppNoAnn (builtin () PLC.BitwiseLogicalComplement) [
let lhsInner = mkIterAppNoAnn (builtin () PLC.ComplementByteString) [
mkConstant @ByteString () bs
]
let lhs = mkIterAppNoAnn (builtin () PLC.BitwiseLogicalComplement) [
let lhs = mkIterAppNoAnn (builtin () PLC.ComplementByteString) [
lhsInner
]
let compareExp = mkIterAppNoAnn (builtin () PLC.EqualsByteString) [
Expand All @@ -245,8 +245,8 @@ complementSelfInverse =
-- * The complement of an OR is an AND of complements.
deMorgan :: TestTree
deMorgan = testGroup "De Morgan's laws" [
testPropertyNamed "NOT AND -> OR" "demorgan_and" . go PLC.BitwiseLogicalAnd $ PLC.BitwiseLogicalOr,
testPropertyNamed "NOT OR -> AND" "demorgan_or" . go PLC.BitwiseLogicalOr $ PLC.BitwiseLogicalAnd
testPropertyNamed "NOT AND -> OR" "demorgan_and" . go PLC.AndByteString $ PLC.OrByteString,
testPropertyNamed "NOT OR -> AND" "demorgan_or" . go PLC.OrByteString $ PLC.AndByteString
]
where
go :: UPLC.DefaultFun -> UPLC.DefaultFun -> Property
Expand All @@ -259,13 +259,13 @@ deMorgan = testGroup "De Morgan's laws" [
mkConstant @ByteString () bs1,
mkConstant @ByteString () bs2
]
let lhs = mkIterAppNoAnn (builtin () PLC.BitwiseLogicalComplement) [
let lhs = mkIterAppNoAnn (builtin () PLC.ComplementByteString) [
lhsInner
]
let rhsInner1 = mkIterAppNoAnn (builtin () PLC.BitwiseLogicalComplement) [
let rhsInner1 = mkIterAppNoAnn (builtin () PLC.ComplementByteString) [
mkConstant @ByteString () bs1
]
let rhsInner2 = mkIterAppNoAnn (builtin () PLC.BitwiseLogicalComplement) [
let rhsInner2 = mkIterAppNoAnn (builtin () PLC.ComplementByteString) [
mkConstant @ByteString () bs2
]
let rhs = mkIterAppNoAnn (builtin () g) [
Expand All @@ -284,12 +284,12 @@ xorInvoluteLaw :: TestTree
xorInvoluteLaw = testPropertyNamed "involute (both)" "involute_both" . property $ do
bs <- forAllByteString
semantics <- forAllWith showSemantics Gen.bool
let lhsInner = mkIterAppNoAnn (builtin () PLC.BitwiseLogicalXor) [
let lhsInner = mkIterAppNoAnn (builtin () PLC.XorByteString) [
mkConstant @Bool () semantics,
mkConstant @ByteString () bs,
mkConstant @ByteString () bs
]
let lhs = mkIterAppNoAnn (builtin () PLC.BitwiseLogicalXor) [
let lhs = mkIterAppNoAnn (builtin () PLC.XorByteString) [
mkConstant @Bool () semantics,
mkConstant @ByteString () bs,
lhsInner
Expand Down Expand Up @@ -557,7 +557,7 @@ evaluateAndVerify ::
PLC.Term UPLC.TyName UPLC.Name UPLC.DefaultUni UPLC.DefaultFun () ->
PropertyT IO ()
evaluateAndVerify expected actual =
case typecheckEvaluateCek def defaultBuiltinCostModel actual of
case typecheckEvaluateCek def defaultBuiltinCostModelForTesting actual of
Left x -> annotateShow x >> failure
Right (res, logs) -> case res of
PLC.EvaluationFailure -> annotateShow logs >> failure
Expand Down
2 changes: 1 addition & 1 deletion plutus-ledger-api/src/PlutusLedgerApi/Common/Versions.hs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ builtinsIntroducedIn = Map.fromList [
Bls12_381_G2_compress, Bls12_381_G2_uncompress,
Bls12_381_millerLoop, Bls12_381_mulMlResult, Bls12_381_finalVerify,
Keccak_256, Blake2b_224, IntegerToByteString, ByteStringToInteger,
BitwiseLogicalAnd, BitwiseLogicalOr, BitwiseLogicalXor, BitwiseLogicalComplement,
AndByteString, OrByteString, XorByteString, ComplementByteString,
ReadBit, WriteBits, ReplicateByteString
])
]
Expand Down
16 changes: 8 additions & 8 deletions plutus-tx-plugin/src/PlutusTx/Compiler/Builtins.hs
Original file line number Diff line number Diff line change
Expand Up @@ -277,10 +277,10 @@ builtinNames = [
, 'Builtins.integerToByteString
, 'Builtins.byteStringToInteger

, 'Builtins.bitwiseLogicalAnd
, 'Builtins.bitwiseLogicalOr
, 'Builtins.bitwiseLogicalXor
, 'Builtins.bitwiseLogicalComplement
, 'Builtins.andByteString
, 'Builtins.orByteString
, 'Builtins.xorByteString
, 'Builtins.complementByteString
, 'Builtins.readBit
, 'Builtins.writeBits
, 'Builtins.replicateByteString
Expand Down Expand Up @@ -442,10 +442,10 @@ defineBuiltinTerms = do
PLC.ByteStringToInteger -> defineBuiltinInl 'Builtins.byteStringToInteger

-- Logical operations
PLC.BitwiseLogicalAnd -> defineBuiltinInl 'Builtins.bitwiseLogicalAnd
PLC.BitwiseLogicalOr -> defineBuiltinInl 'Builtins.bitwiseLogicalOr
PLC.BitwiseLogicalXor -> defineBuiltinInl 'Builtins.bitwiseLogicalXor
PLC.BitwiseLogicalComplement -> defineBuiltinInl 'Builtins.bitwiseLogicalComplement
PLC.AndByteString -> defineBuiltinInl 'Builtins.andByteString
PLC.OrByteString -> defineBuiltinInl 'Builtins.orByteString
PLC.XorByteString -> defineBuiltinInl 'Builtins.xorByteString
PLC.ComplementByteString -> defineBuiltinInl 'Builtins.complementByteString
PLC.ReadBit -> defineBuiltinInl 'Builtins.readBit
PLC.WriteBits -> defineBuiltinInl 'Builtins.writeBits
PLC.ReplicateByteString -> defineBuiltinInl 'Builtins.replicateByteString
Expand Down
Loading

0 comments on commit e2ce78a

Please sign in to comment.