Skip to content
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

Add Convenience Methods for Signed Data Structures #3388

Open
dete opened this issue Jun 3, 2024 · 3 comments
Open

Add Convenience Methods for Signed Data Structures #3388

dete opened this issue Jun 3, 2024 · 3 comments

Comments

@dete
Copy link

dete commented Jun 3, 2024

Issue to be solved

A frequent use-case in blockchains is to have a user sign some data structure, similarly to how we asks users to sign transactions. Depending on the application, the data structures could be very different. They could be as simple as a few integers, or it could be a complicated structure with nested arrays and dictionaries.

Ideally, there would be a way in Cadence to easily handle such data structures: make it easy for client software to generate signed structures, and make it easy for smart contracts (or off-chain code) to verify those structures.

Suggested Solution

I'm imagining a wrapper mechanism similar to Capabilities. If I had a structure called Foo, Cadence code could refer to Signed<Foo> datatypes. Signed<Foo> instances would look and act just like the base type with a few caveats:

  • The direct data members of the Signed instance would act like let declarations, so they couldn't be written directly.
  • A new data member signatureSet would be available, which is a list of KeyListSignature objects.
  • A new member method verify(keyList: Crypto.KeyList): Bool would check if the current contents of the structure (including the signatureSet) are consistent with the keys in the given KeyList.

The resulting code could look sort of like this:

access(all) struct AuctionBid {
    access(all) let bidderId: UInt64
    access(all) let auctionId: UInt64
    access(all) let bidAmount: UFixed64
}

access(all) fun submitBid(_ bid: Signed<AuctionBid>) {
    let bidder = auctionManager.getBidder(bid.bidderId)

    if bid.verify(bidder.keyList) {
        let auction = auctionManager.getAuction(bid.auctionId)
        auction.processBid(bidder, bid.bidAmount)
    }
}

As a rule, Signed<> structures would be constructed off-chain and serialized to be used as arguments to scripts and transactions, so we'd also need to make sure that any client libraries had convenience methods for constructing signed objects. I don't think it would typically make much sense for Cadence code to construct Signed<> instances directly. I don't believe signed resource objects are useful (or perhaps even possible).

The type of the wrapped object could be used as a domain tag to prevent cross-domain attacks.

Open Question: What (if any) protection against replay attacks can/should we provide here?

@dete
Copy link
Author

dete commented Jun 3, 2024

For clarity: This is merely a feature suggestion, and should not be considered until after C1.0…

@turbolent
Copy link
Member

Great idea!

I guess access on fields would return references, so that e.g. containers (arrays, dictionaries, nested composites, etc.) would be immutable?

@bluesign
Copy link
Contributor

bluesign commented Jun 5, 2024

If we add hash() method to struct we can make a Signed struct, then we don't need to worry about mutability.

It would be nice to be able to generate signed stuff from Cadence side too. ( if there are multiple signers for example )

access(all) struct Signed{
  access(all) var payload : AnyStruct
  access(all) var signatureSet: [Crypto.KeyListSignature]
  access(all) fun verify(keyList: Crypto.KeyList): Bool {
       keyList.isValid(
        signatureSet: signatureSet,
        signedData: self.payload.hash()
    )
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants