-
Notifications
You must be signed in to change notification settings - Fork 479
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
Bitwise operation primops and types #4252
Comments
Historically we've deliberately not wanted to have fixed-size numeric types to avoid overflow-related issues. I agree that if we were going to do this we would want fixed-width byte-based types. However we have also historically not wanted to encourage people to implement such operations in user code, and rather preferred to add builtins for it. It's not clear if this is a sustainable policy, however. |
@michaelpj I agree: fixed-size numerical types yield many surprises, usually of the sort that nobody wants to deal with. Overflow is just the tip of the iceberg here. The idea I'm putting forward is for only bitwise types: these should not support arithmetic operations at all. That wasn't something I stated clearly, and should have. As my writeup above mentions, I don't think it's even possible to implement this without builtins. You can get a crude approximation via the arithmetic operations on |
+1 on this - it's pretty critical in order to efficiently perform zero knowledge proof work. |
I don't think this is sustainable. I know you're against "rolling your own crypto", however, I argue that this is an exception. There are many many different reasons to roll your own crypto with Plutus. What if I want to do ZKPs on Cardano? Should I implement all the specific algorithms I'm using in the interpreter? |
The set of builtins is easily extensible for this reason. We probably will add ZKP primitives in due course! |
I think that you will bottleneck Cardano dapps if you necessitate that any advanced algorithm be implemented in the interpreter. |
I'd also add that bitwise primitives give support for things that aren't cryptographic in nature. Open any book or paper on data structures and algorithms, and bitwise operations are front-and-centre in almost anything. Not having support for this severely limits what can be written at all, and especially efficiently, on-chain. |
@michaelpj Any thoughts on my comment regarding bitwise primitives for non-cryptographical tasks on-chain above? |
This needs to be a more fully thought-out proposal. What's in your issue won't fly: adding 7 new builtin types, and primitive operations on all of them (so 7*whatever) would be a lot of work. All of those need to be costed. I think we'd be much more likely to implement a small set of primitives that cover most of the interesting usecases. For example, adding the most useful functions over |
@michaelpj Thanks for your feedback. In light of this, would you be OK with the following, reduced proposal? This still contains 12 primitives overall, but it is significantly more focused, and would still give us most of what we want. Version TwoWe add the following primitive operations over
Additionally, we add the following primitive operations over
|
We need to decide on the encoding for integerToByteString |
@L-as I assume this is regarding endianness? Since |
There is also signedness.
|
This stuff always makes my head spin, but let's try and pin it down as carefully as we can.
I'm not sure you can check "greater than or equal to the number of bits in bs". It can't just be "greater than the index of the highest 1", since otherwise you can't test bits in the zero bytestring. I think you just have to accept that you can test bits that our out of your implied range. |
@michaelpj - I've substantially formalized and rewritten my proposal, with the intended semantics, and attached a |
(I realised I was confused in my comment above: for future readers, bytestrings do have a length! Which removes a few of my concerns.) Thanks, this is generally great! Comments:
|
I'd also love to put this up as a CIP. I can see why you prefer the latex version, so perhaps the following compromise would work:
|
@michaelpj A CIP is definitely the goal: I think your suggestion works, as the semantics section is a 'last resort of clarity', so can be kept as a separate addendum. |
@michaelpj I've drafted a new version of the proposal, aiming to address all of your comments. I've also added a section about costing, and tried to clarify as much as I can. I'll also respond to a few of your points here, for added clarity.
As mentioned in the proposal, 'failing fast' can be just as hard to track down! At MLabs specifically, we have had severe issues tracking down division-by-zero, which also 'fails fast', leading to literal days of lost productivity. The original idea of 'truncation semantics' was based on
This arguably reveals a personal bias of mine - I happen to love rank-select dictionary-based structures, for which these operations are extremely important. However, given that I've not been able to easily think of another place where they are critical, they have now been dropped from the proposal. |
I still disagree with this pretty fundamentally. I really dislike the truncating I don't think your variant is better. I think I was wrong when I said the problem was throwing away information. The problem is that you can get a result which is not what the user intended without them noticing. That relies on two claims:
Putting it another way: since we care even more than usual about our users producing correct programs, it is better for us to rule out wrong programs aggressively, even if that is less pleasant for our users during development.
I think this points to a weakness of the current proposal: examples! There is now some reasoning about why these operations are useful, but if we had some motivating examples it would be much easier to think about whether we have an adequate (or excessive) set.
I do think we should just remove one.
Citation? I feel like usually I see either
|
An on-chain Bloom filter might be useful. |
@michaelpj I've tried to address all of your concerns in yet another version. In summary:
|
@michaelpj Any chance you could review the proposal? We have just today had a task at MLabs where my very first motivating example would have been the ideal solution. |
I think this is pretty good. Would you like to turn it into a CIP as we discussed?
|
Since there's now a CIP for this discussion, I'm closing the issue. Do feel free to reopen if you think we should keep the issue open. |
Describe the feature you'd like
A collection of primitives for bit manipulation, including, but not necessarily limited to, the following:
While providing these operations is theoretically possible over
Integer
already, having such operations possible overBuiltinByteString
would also be helpful. Furthermore, having some fixed-width, binary-only on-chain types (similar toWord*
in GHC) would be helpful for a range of applications.Describe alternatives you've considered
This, to some degree, is an extension and generalization of #4168, and is needed for features such as #4233. Furthermore, bitwise primitives are useful in a range of applications, especially where efficiency is important. While they can sort-of be defined already over
Integer
, the resulting implementations are brittle, easy to get wrong, and not very efficient. Furthermore, many problem domains that want bitwise operations need to operate on byte sequences whose semantics have nothing to do with numbers:BuiltinByteString
is arguably the better type to work over here, but as-current, these operations are not definable over it. Lastly, especially for cryptographic operations, fixed-width byte blobs are often the right data type: as current, while such types can be faked, it's only by convention.In general, the only solutions that exist right now are either slow and complex
Integer
-based workarounds, or nothing at all.Describe the approach you would take to implement this
I would first add primitive types and operations, plus relevant functionality in the Plutus libraries and core. Specifically:
Bits8
,Bits16
,Bits32
,Bits64
,Bits128
,Bits256
,Bits512
BooleanAlgebra
type class, containing the necessary logical operations as either methods or implementations based on themBooleanAlgebra
forBits*
BooleanAlgebra
forInteger
andBuiltinByteString
, or similar functionality as separate functionsplutus-size-check
Shifts, rotates, population counting and find-first-set don't quite fit into this scheme, but they would be needed somehow too. Following this, I would comb through existing Plutus functionality that these operations and types could improve or replace. Lastly, I'd want to add support (or rather, wrappers) around common bit twiddling techniques, so that other developers can use them for efficient implementations of higher-level functionality, without needing to know the relevant bit twiddling folklore.
The text was updated successfully, but these errors were encountered: