-
Notifications
You must be signed in to change notification settings - Fork 367
CIP-0166? | Efficient scalars for BLS12-381 #1087
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: master
Are you sure you want to change the base?
CIP-0166? | Efficient scalars for BLS12-381 #1087
Conversation
I think this CIP will add considerable value to the ZK capabilities in Cardano L1. The rationale is correct and spot-on regarding one of the biggest use cases where we encounter these Plutus/Plinth limitations. It's quite unfortunate that we almost exhaust the Plutus execution budget with just a few elements using bilinear accumulators, and it's even worse to consider that most of the budget is spent on unoptimized 'simple' multiplication and addition operations on Fr. I have a couple of observations:
|
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.
Tagging Triage
to introduce at the CIP meeting in a few hours: https://hackmd.io/@cip-editors/119
@euonymos it's nice to see that Plutus expert review has already started & as usual we would be happy to hear from @zliu41 @effectfully @kwxm and others about this.
and considers different ways of evolving Plutus | ||
toward efficient implementation of scalars for BLS12-381 curve. | ||
|
||
## Motivation: why is this CIP necessary? |
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.
Most of the subsections her actually belong in the Rationale section, in which implementation details and comparative approaches are considered. This includes performance considerations for what you have simply described the need for doing here in the Motivation section.
```aiignore | ||
(a, 1) final_poly_int | ||
|
||
memory units cpu units | ||
⡁⠈⠀⠁⠈⠀⠁⠈⠀⠁⠈⠀⠁⠈⠀⠁⠈⠀⠁⠈⠀⠁⠈⠀⠁⠈⠀⠁⠈⠀⠁⠈⠀⠁⠈⠀⠁⠈⢀⠕⡁ 5189564.0 ⡁⠈⠀⠁⠈⠀⠁⠈⠀⠁⠈⠀⠁⠈⠀⠁⠈⠀⠁⠈⠀⠁⠈⠀⠁⠈⠀⠁⠈⠀⠁⠈⠀⠁⠈⠀⠁⠈⢀⠕⡁ 1669321088.0 |
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.
I think it would serve this CIP & the repository well, by assuring portability / readability / responsiveness, if you could implement these graphs in Mermaid (I think the same set of points that produced the text renderings can be applied to a graph). And if & when someday it is possible for an AI to interpret these graphs, that would make it more achievable.
@euonymos we decided to leave this in A potential benefit for prompt review was also suggested at the meeting: the upcoming mid-term hard fork, in which some similar improvements for curve primitive support is planned, might also be able to include this change. |
Yes, this would be ideal since otherwise, we would end up having two sets of functions - old for integers and new for Fr. But how can we decide whether and And speaking more broadly, do we want to support only the scalar field of BLS of prime fields in general, at the level of Plutus API, in case we add another curve in the future, for example? |
It would be nice to hear the thoughts of the Plutus team @effectfully @ana-pantilie @zliu41 @SeungheonOh. |
Still hoping for Plutus participation... there were some likely reviewers at the CIP meeting today, but discussion went entirely towards Leios CIP review due to massive turnout of those stakeholders & concerned devs. I think we are on track to consider this as a candidate at the following CIP meeting: https://hackmd.io/@cip-editors/121 |
I'll try to take a close look at this by the end of the week. Sorry for the delay. |
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.
Left some comments. Thanks for the nice writing and nice plots. These seem like a reasonable and very useful addition.
With addition of new type for scalar in
(which corresponds to `blst_fr` type) can be used along with introducing and eliminating from/to a _byte string_: | ||
|
||
``` | ||
bytestring_to_bls12_381_fr: [bool, 𝚋𝚢𝚝𝚎𝚜𝚝𝚛𝚒𝚗𝚐] -> bls12_381_fr |
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.
is it
bytestring_to_bls12_381_fr: bool -> bytestring -> bls12_381_fr
or
bytestring_to_bls12_381_fr: [(bool, bytestring)] -> bls12_381_fr
I assume it's former. It's just a bit confusing; please update to clarify. Same goes with other ones below.
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.
also these belong in the below section in "Function definition"
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.
Given the shared correspondence between the underlying blst
lib it is
bytestring_to_bls12_381_fr: bool -> bytestring -> bls12_381_fr
is understandable but not quite satisfying for several reasons. | ||
|
||
The main argument showcased by this use case is that the significant share of work | ||
(20% using pointwise multiplication, which will be bigger with MSM) |
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.
20% of onchain exbudget I assume?
``` | ||
TBD: Scalar and multi-scalar multiplication in $G1$ and $G2$ are typical downstream functions | ||
for `bls12_381_fr` values, but in the current Plutus, they use integers, i.e., double conversion is needed: | ||
`bls12_381_fr -> bytestring -> integer` to call them. |
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.
nitpick: this looks like a type signature. It'd be better to write out
"bls12_381_fr
to bytestring
to integer
"
|---------------------:|---------------|---------|---------------|---------|--------------| | ||
| **(a)** Coefficients | 1_669_321_088 | 19% | 1_847_736_704 | 21% | +178_415_616 | | ||
| **(b)** Commitment | 5_908_456_448 | 68% | 5_892_875_264 | 67% | −15_581_184 | | ||
| **(c)** Pairing | 1_098_158_336 | 13% | 1_098_158_336 | 12% | - | |
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.
How come "percent" for 1 is 13% and for 2 is 12% when they have exactly same CPU budget?
also diff is 0 for consistency.
* It's counterintuitive since it clashes with the mental model of the finite field. | ||
* Representation of field elements as `Integers` (and even worse, peculiarities of the cost model as we saw) | ||
pushes developers to use unbounded integers, which may lead to misunderstanding and unexpected bugs. | ||
* It complicates the cost model by (mis)using `Integer` type for scalars. |
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.
Cost of integer operation depends on the sizes of integers used. So it doesn't really complicate cost in perspective of VM. Not sure how else using Integer
can complicates the cost model.
can you explain what exactly you mean with
|
I initially thought that My first idea was to use plain Mainly because I think using the blst conversion interface approach could cause problems within Plutus scripts. For instance, in polynomial multiplication (e.g., when constructing a polynomial from terms like Moreover, the use of Fr here doesn’t seem to provide any additional benefit, since the Montgomery representation is mainly an internal optimization for arithmetic efficiency. That’s why I was considering keeping Fr as an internal detail, only using it at the interface between Plutus and the blst library. Exposing it more widely to end users might not add much value. However, as @euonymos pointed out, this could also become computationally expensive, since every function argument and return value would require a conversion between Integer and Fr. |
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.
Accepted as CIP candidate at today's CIP meeting based mainly on positive response from Plutus stakeholders. @euonymos please rename this directory to CIP-0166
and update your "Link for reading current version" 🎉
While working on the Hydrozoa project, we decided to use pair-based accumulators as part of ZKifing proofs of membership for the L2 utxo set in the rule-based regime. We are pretty happy with the results, since KZG commitments are easier to work with than Merkle tree-like structures we wanted to use previously.
Operations over scalars for BLS12-381 in Plutus might require some improvements; probably it will become the next bottleneck for this particular use case after MSM makes it to Plutus, as our benchmarks suggest.
By drafting this CIP, I mostly wanted to share those results with the community and establish a place for a potential discussion on the topic, since the current state of things feels a bit rough around the edges, at least it questions
Scalar
module in Aiken and other frameworks (initially we ported it to Scalus, but now we likely will use unbounded integers as this approach proves to be less expensive).I am happy to hear from everyone who has a take or related ideas. Thanks.
Link for reading current version: here