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

crypto: Add multisig to sui #7110

Merged
merged 1 commit into from
Feb 14, 2023
Merged

crypto: Add multisig to sui #7110

merged 1 commit into from
Feb 14, 2023

Conversation

joyqvq
Copy link
Contributor

@joyqvq joyqvq commented Jan 4, 2023

Multisig support in Sui: Now sui accepts Multisig signatures. [enum GenericSignature] now replaced all [enum Signature] for user signature verification logics.

Keytool command now supports 1) Generate multisig address 2) Combine single signatures to a multisig.

Design: #7187
PR: #7110

Step by step testing in localnet: https://gist.github.com/joyqvq/5febd8deb5cacc6f47afa1253224b7da

Main changes are in multisig.rs, signature.rs crypto.rs

Next step:

  • Typescript util to compute multisig address
  • Typescript util to combine partial sigs
  • Explorer rendering of multisig

@vercel
Copy link

vercel bot commented Jan 4, 2023

The latest updates on your projects. Learn more about Vercel for Git ↗︎

4 Ignored Deployments
Name Status Preview Comments Updated
explorer ⬜️ Ignored (Inspect) Feb 14, 2023 at 6:40PM (UTC)
explorer-storybook ⬜️ Ignored (Inspect) Feb 14, 2023 at 6:40PM (UTC)
frenemies ⬜️ Ignored (Inspect) Feb 14, 2023 at 6:40PM (UTC)
wallet-adapter ⬜️ Ignored (Inspect) Feb 14, 2023 at 6:40PM (UTC)

Copy link
Collaborator

@kchalkias kchalkias left a comment

Choose a reason for hiding this comment

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

Let's have a design doc for this first as there are many functionality decisions (ie weighted multisig)

@joyqvq
Copy link
Contributor Author

joyqvq commented Jan 6, 2023

#7187 linked design doc in this issue

@joyqvq joyqvq force-pushed the multisig branch 4 times, most recently from 00d8556 to 4ff57d7 Compare January 11, 2023 09:48
@joyqvq joyqvq marked this pull request as ready for review January 11, 2023 10:34
@joyqvq joyqvq requested a review from kchalkias January 11, 2023 15:35
@joyqvq joyqvq force-pushed the multisig branch 2 times, most recently from 4c14cbd to e8ca0e3 Compare January 12, 2023 10:04
@LeviHHH
Copy link

LeviHHH commented Jan 20, 2023

We should also consider supporting secp256r1 signature verification in the move library.

@joyqvq
Copy link
Contributor Author

joyqvq commented Jan 27, 2023

We should also consider supporting secp256r1 signature verification in the move library.

#7773

@joyqvq joyqvq force-pushed the multisig branch 2 times, most recently from 67d4a17 to 8cbb4a2 Compare January 30, 2023 22:54
crates/sui-core/src/consensus_validator.rs Outdated Show resolved Hide resolved
@@ -258,6 +259,25 @@ impl From<&PublicKey> for SuiAddress {
}
}

/// A Multisig address is the first 20 bytes of `threshold || pk_1 || weight_1 || ... || pk_n || weight_n`
Copy link
Collaborator

Choose a reason for hiding this comment

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

... is the first 20 bytes of the hash of flag || threshold || pk_1....

crates/sui-types/src/base_types.rs Outdated Show resolved Hide resolved
crates/sui-types/src/base_types.rs Show resolved Hide resolved
// Unwrap below is safe because the bytes are directly read from the signature bytes from [enum Signature].
match self.scheme() {
SignatureScheme::ED25519 => Ok(CompressedSignature::Ed25519(
Ed25519Signature::from_bytes(bytes).unwrap(),
Copy link
Collaborator

Choose a reason for hiding this comment

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

are these unwrap always successful?

Copy link
Contributor Author

@joyqvq joyqvq Feb 10, 2023

Choose a reason for hiding this comment

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

yeah i added a line above at 697, bc here we always use the signature_bytes()

Copy link
Contributor Author

Choose a reason for hiding this comment

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

edit: unwrap removed

crates/sui-types/src/multisig.rs Outdated Show resolved Hide resolved
crates/sui-types/src/multisig.rs Show resolved Hide resolved
crates/sui-types/src/multisig.rs Show resolved Hide resolved
|| pks.len() != weights.len()
|| pks.len() > MAX_SIGNER_IN_MULTISIG
{
return Err(SuiError::InvalidSignature {
Copy link
Collaborator

Choose a reason for hiding this comment

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

do we do these checks even when deserializing?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good point. added to from_bytes to validate the multisig itself and its pk

threshold: ThresholdUnit,
) -> Result<Self, SuiError> {
if pks.is_empty()
|| weights.is_empty()
Copy link
Collaborator

Choose a reason for hiding this comment

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

I believe we should even disallow any zero weights, no multisig key should carry any weight = 0 pk.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good point, added tests


/// The struct that contains the public key used for authenticating a multisig.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct MultiPublicKey {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit, and obviously very subjective - I view "MultiSig" as the scheme name, like ECDSA or EdDSA, and so MultiSigPublicKey sounds clearer to me here.

/// This way multisig (and future Authenticators) can implement its own `verify`.
#[enum_dispatch(AuthenticatorTrait)]
#[derive(Debug, Clone, PartialEq, Eq, JsonSchema, Hash)]
pub enum GenericSignature {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit, and also very subjective - maybe enum Signature { MultiSig, SingleSig }?

Copy link
Contributor Author

@joyqvq joyqvq Feb 10, 2023

Choose a reason for hiding this comment

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

agreed on both naming. renaming Signature -> SingleSig is quite invasive, will do this in a later PR.

let mut weight_sum = 0;
let message = bcs::to_bytes(&value).expect("Message serialization should not fail");

for (sig, i) in self.sigs.iter().zip(&self.bitmap) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Does it assume here that the sigs are sorted according to their public keys?

Copy link
Contributor

Choose a reason for hiding this comment

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

also, we depend here on bitmap to check that we don't have 2 signatures for the same public key, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah sigs are assumed sorted

Copy link
Contributor Author

@joyqvq joyqvq Feb 14, 2023

Choose a reason for hiding this comment

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

yeah roaring bitmap prevents inserting the same value twice.

however, it is technically possible if the multisig pubkey itself is constructed with two same pks (with different different index in bitmap ). i dont know if there is a good reason someone would do that but didnt check to fail for this.

Copy link
Collaborator

Choose a reason for hiding this comment

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

yeah as the user controls their multisig pubKey, there is no good incentive to have a double pubKey. Maybe an edge case is if a user wanted to double their max weight for some peculiar auth structure, but it's fine to omit that check.

@joyqvq joyqvq force-pushed the multisig branch 2 times, most recently from 8036589 to 44c51ba Compare February 14, 2023 16:09
@joyqvq
Copy link
Contributor Author

joyqvq commented Feb 14, 2023

@kchalkias @benr-ml addressed most of the comments PTAL

@joyqvq joyqvq requested a review from kchalkias February 14, 2023 16:11
Copy link
Collaborator

@kchalkias kchalkias left a comment

Choose a reason for hiding this comment

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

Great job Joy!

let mut weight_sum = 0;
let message = bcs::to_bytes(&value).expect("Message serialization should not fail");

for (sig, i) in self.sigs.iter().zip(&self.bitmap) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

yeah as the user controls their multisig pubKey, there is no good incentive to have a double pubKey. Maybe an edge case is if a user wanted to double their max weight for some peculiar auth structure, but it's fine to omit that check.

error: "Invalid address".to_string(),
});
}
let mut weight_sum = 0;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'd specifically add the type here (u16) just for readability. I understand we have weights being u8 atm and we aggregate them into a u16, but in any case I'd also add a test where all keys have max weight (just to capture any future update where for some reason we allow 256+ pubKeys)

@joyqvq joyqvq enabled auto-merge (squash) February 14, 2023 18:39
@joyqvq joyqvq merged commit 818406c into main Feb 14, 2023
@joyqvq joyqvq deleted the multisig branch February 14, 2023 19:06
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.

4 participants