Skip to content

Implement BLS12-381 contracttype support #1449

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

Merged
merged 14 commits into from
May 16, 2025
Merged

Conversation

jayz22
Copy link
Contributor

@jayz22 jayz22 commented Mar 6, 2025

What

Add support for BLS12-381 curve points (Fp, Fp2, G1Affine, G2Affine, Fr) for internal data storage (via contracttype) and contract invocation arguments (contract spec).

Why

Improves usability of the BLS12-381 features in a Groth16 verifier application (example contract)

  • Arbitrary and several missing conversions are needed to use G1Affine, G2Affine as contract data.

Known limitations

[TODO or N/A]

@jayz22 jayz22 requested a review from leighmcculloch March 6, 2025 02:26
Copy link
Member

@leighmcculloch leighmcculloch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for making these types usable with contracttype 👏🏻.

This pull request looks like it contains a bundle of changes related only by topic, and otherwise independent. It's helpful if it's split, both for changelog capturing, visibility, and readers. I understand that because the example (stellar/soroban-examples#350) was being developed at the same time that also might not be desirable. No need to do now if too inconvenient, just fyi as the reader initially felt like things were related and had to piece through what was and wasn't, and intent for each change.

I've left a few comments inline to do with rust conventions, and changing a runtime check to a compile time check.

For the low-level BLS operations, I'm not the best person to review, so I'm tagging @stellar/contract-committers to review.

@leighmcculloch leighmcculloch requested a review from a team March 10, 2025 13:55
@jayz22 jayz22 changed the title Implement BLS12-381 point negation and contracttype support Implement BLS12-381 contracttype support Apr 3, 2025
@jayz22
Copy link
Contributor Author

jayz22 commented Apr 3, 2025

@leighmcculloch I've split out this PR into three parts

  1. Fix bls documentation - G1/G2 compression flag must be *unset* #1455 contains the comment fix
  2. Implement BLS12-381 point negation #1456 contains the implementation of point negation
  3. this PR just contains the contracttype support

they are currently based on top of one another, so they should be merged in the above order. I will mention and address your review comments pertaining to the those changes in the their corresponding PR.

github-merge-queue bot pushed a commit that referenced this pull request Apr 14, 2025
### What

Fix a bug in the documentation. The G1/G2 compression flag must be
**unset (0)**.
Splits out from #1449 and
addresses
#1449 (comment)

### Why

In our BLS12-381 implementation all input points are expected in an
uncompressed format.
Here is the [validation
logic](https://github.com/stellar/rs-soroban-env/blob/02d4b525f9231d8b82dadde9d06224099405be1d/soroban-env-host/src/crypto/bls12_381.rs#L146-L158)
on the host side, which is consistent with uncompressed point checking
(the only allowed set flag is the infinity flag).

### Known limitations

[TODO or N/A]
Copy link
Member

@leighmcculloch leighmcculloch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me. I only have one concern, mentioned inline, and my concern may be naive.

Let's get #1456 merged, and then once this PR is updated I'll approve this PR.

github-merge-queue bot pushed a commit that referenced this pull request May 9, 2025
### What

Split out point negation part
([0945897](0945897))
from #1449, and address
review comments on this part.

### Why

Improves usability of the BLS12-381 features in a Groth16 verifier
application ([example
contract](stellar/soroban-examples#350))

- `Neg` is an common operation, needed for using the proof parameter as
pairing input, and is cheap and simple enough to be implemented as an
sdk function.

### Known limitations

[TODO or N/A]
Add comment for clearing flags, remove dead code

properly handle infinity bit in the `Arbitrary` type generation
Copy link
Member

@leighmcculloch leighmcculloch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add support for BLS12-381 curve points (G1Affine, G2Affine, Fr) as contract data (via contracttype)

There's no test testing that we've got everything we need here for it to work. Could you add a test in the sdk tests directory to make sure we aren't missing something?

Is the goal only to be able to write and read these from storage? Or also to be able to pass it as parameters into the contract? For the latter, which I think makes sense, we need to hook up specs. Normally types that live in the SDK end up in the ScSpecType list.

The only other SDK types that use contracttype macros internally are for auth, and those conveniently don't need exporting of specs (we turn that off) because they aren't externally callable so this limitation and gap hasn't had an impact until now.

The way we did this in the token sdk was use the contracttype macro, and when you import the crate its spec gets reexported implicitly. But that won't work to do that here because everyone imports this SDK.

These types are all aliases for BytesN<_>. The other case we have for that is Hash, but again that was a case not callable.

🤔 This is a bit of a conundrum.

We can merge this as is, it'll work for storage, but fall apart at the boundaries of the contract as a fn input or output and when other tools like the CLI try and pass the value.

We have a couple paths:

  • Do nothing, maybe that's enough for now.
  • Add to the spec XDR as a type
  • Find a way for the specs to see it as a BytesN for the sake of specs
    ScSpecTypeDef::BytesN(b) => {
    let n = Literal::u32_unsuffixed(b.n);
    quote! { soroban_sdk::BytesN<#n> }
    }
  • Explore other approaches

Related issues:

@leighmcculloch
Copy link
Member

leighmcculloch commented May 9, 2025

  • Find a way for the specs to see it as a BytesN for the sake of specs

The way we'd do this is modify the contractimpl macro that generates the functions, so that for any input parameter named one of these types, we map them to the BytesN<_> type of appropriate size.

That is probably the shortest path and least complexity way to address this.

I think it sets good precedence too for types that thinly wrap other SDK types.

Copy link
Member

@leighmcculloch leighmcculloch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test shows that we don't have everything we need here for these to work everywhere contracttypes do.

If I deploy the test and run this command, it errors:

$ stellar contract invoke --id c -- --help
❌ error: Missing Entry G1Affine

But there is enough here for these to work as internal types for storage. So I think we can merge this, because it is additive, and what's added works for that narrow purpose, but we should follow up on filling the gap on contract function params / return values.

@leighmcculloch
Copy link
Member

The way we'd do this is modify the contractimpl macro that generates the functions, so that for any input parameter named one of these types, we map them to the BytesN<_> type of appropriate size.

If we solve this problem generically, not just hard code these types specifically, then I think we are also solving the type alias issue, if we also solve it for type wrapping:

@leighmcculloch
Copy link
Member

leighmcculloch commented May 14, 2025

To be clearer there are two contracttype issues outstanding:

In the interim, until both problems above are solved, I think it is okay if the contractimpl macro sees G1Affine and treats it as if the user had typed BytesN<...>. Doing that will avoid both problems for the moment.

@jayz22
Copy link
Contributor Author

jayz22 commented May 15, 2025

To be clearer there are two contracttype issues outstanding:

* The SDK doesn't have a way to define a type that is optionally exported, although the stellar-cli may do that for us in the future. [`stellar contract build` should strip contract specs, removing types that are not referenced by functions or events stellar-cli#2030](https://github.com/stellar/stellar-cli/issues/2030)

* The contract specs don't have a way to define type aliases, where one type is really another type. In this case it is the G1Affine newtype idiom around the BytesN type. This will be addressed by [Support type aliases as contracttypes #1063](https://github.com/stellar/rs-soroban-sdk/issues/1063).

In the interim, until both problems above are solved, I think it is okay if the contractimpl macro sees G1Affine and treats it as if the user had typed BytesN<...>. Doing that will avoid both problems for the moment.

Thanks @leighmcculloch, I've added the type spec mapping for the BLS types to its inner types (with a comment referencing #1063).
Also added a contract example and a test invoking it. I think that should do it for now.
Agree it would be nice to support a generic way of inferring a type (either defined via new type idiom or type alias) from its actual type.

@leighmcculloch
Copy link
Member

I pushed a small change to make the warning stand out a little more, using rustdocs warning class:

Before:
Screenshot 2025-05-16 at 1 44 16 pm

After:
Screenshot 2025-05-16 at 1 43 56 pm

@leighmcculloch leighmcculloch enabled auto-merge May 16, 2025 03:45
@leighmcculloch leighmcculloch added this pull request to the merge queue May 16, 2025
Merged via the queue into stellar:main with commit 61b7d6f May 16, 2025
17 checks passed
@jayz22 jayz22 deleted the bls branch May 16, 2025 14:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants