plutus icon indicating copy to clipboard operation
plutus copied to clipboard

`indexByteString` performs range check twice

Open effectfully opened this issue 3 weeks ago • 0 comments

This is how the denotation of indexByteString is defined:

        indexByteStringDenotation :: BS.ByteString -> Int -> BuiltinResult Word8
        indexByteStringDenotation xs n = do
            unless (n >= 0 && n < BS.length xs) $
                fail "Index out of bounds"
            pure $ BS.index xs n

There's an explicit range check, but BS.index performs one already:

index :: HasCallStack => ByteString -> Int -> Word8
index ps n
    | n < 0          = moduleError "index" ("negative index: " ++ show n)
    | n >= length ps = moduleError "index" ("index too large: " ++ show n
                                         ++ ", length = " ++ show (length ps))
    | otherwise      = ps `unsafeIndex` n

Obviously failing with an exception isn't an option for UPLC, but there's indexMaybe and unsafeIndex. I'd recommend using the former and not performing the check manually, that Maybe in there should compile away. Verify by dumping the Core of PlutusCore.Evaluation.Machine.MachineParameters.Default.

effectfully avatar Nov 29 '25 02:11 effectfully