Skip to content

Commit

Permalink
Remove legacy MultiSig
Browse files Browse the repository at this point in the history
  • Loading branch information
piotrm50 committed Oct 21, 2024
1 parent 7023e37 commit f980d5b
Showing 1 changed file with 8 additions and 232 deletions.
240 changes: 8 additions & 232 deletions crates/iota-rust-sdk/src/types/crypto/multisig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ pub type WeightUnit = u8;
pub type ThresholdUnit = u16;
pub type BitmapUnit = u16;

#[cfg(feature = "serde")]
const MAX_COMMITTEE_SIZE: usize = 10;
// TODO validate sigs
// const MAX_BITMAP_VALUE: BitmapUnit = 0b1111111111;

Expand Down Expand Up @@ -86,17 +84,6 @@ pub struct MultisigAggregatedSignature {
/// A bitmap that indicates the position of which public key the signature
/// should be authenticated with.
bitmap: BitmapUnit,
/// Legacy encoding for the bitmap.
// TODO implement a strategy for legacy bitmap
#[cfg_attr(
feature = "schemars",
schemars(
skip_serializing_if = "Option::is_none",
with = "Option<crate::_schemars::Base64>",
)
)]
#[cfg_attr(test, strategy(proptest::strategy::Just(None)))]
legacy_bitmap: Option<roaring::RoaringBitmap>,
/// The public key encoded with each public key with its signature scheme
/// used along with the corresponding weight.
committee: MultisigCommittee,
Expand All @@ -111,19 +98,13 @@ impl MultisigAggregatedSignature {
self.bitmap
}

pub fn legacy_bitmap(&self) -> Option<&roaring::RoaringBitmap> {
self.legacy_bitmap.as_ref()
}

pub fn committee(&self) -> &MultisigCommittee {
&self.committee
}
}

impl PartialEq for MultisigAggregatedSignature {
fn eq(&self, other: &Self) -> bool {
// Skip comparing the legacy bitmap since we always convert to the new bitmap
// form
self.bitmap == other.bitmap
&& self.signatures == other.signatures
&& self.committee == other.committee
Expand All @@ -132,19 +113,6 @@ impl PartialEq for MultisigAggregatedSignature {

impl Eq for MultisigAggregatedSignature {}

/// Convert a roaring bitmap to plain bitmap.
#[cfg(feature = "serde")]
fn roaring_bitmap_to_u16(roaring: &roaring::RoaringBitmap) -> Result<BitmapUnit, &'static str> {
let mut val = 0;
for i in roaring.iter() {
if i >= MAX_COMMITTEE_SIZE as u32 {
return Err("invalid bitmap");
}
val |= 1 << i as u8;
}
Ok(val)
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(test_strategy::Arbitrary))]
#[allow(clippy::large_enum_variant)]
Expand All @@ -160,135 +128,11 @@ pub enum MultisigMemberSignature {
mod serialization {
use std::borrow::Cow;

use base64ct::{Base64, Encoding};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde_with::{Bytes, DeserializeAs, SerializeAs};
use serde_with::{Bytes, DeserializeAs};

use super::*;
use crate::types::{
Ed25519PublicKey, Secp256k1PublicKey, Secp256r1PublicKey, SignatureScheme,
crypto::{Base64Array33, Base64Array34},
};

pub struct Base64MultisigMemberPublicKey;

impl SerializeAs<MultisigMemberPublicKey> for Base64MultisigMemberPublicKey {
fn serialize_as<S>(
source: &MultisigMemberPublicKey,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match source {
MultisigMemberPublicKey::Ed25519(public_key) => {
let mut buf = [0; 1 + Ed25519PublicKey::LENGTH];
buf[0] = SignatureScheme::Ed25519 as u8;
buf[1..].copy_from_slice(public_key.as_ref());
Base64Array33::serialize_as(&buf, serializer)
}
MultisigMemberPublicKey::Secp256k1(public_key) => {
let mut buf = [0; 1 + Secp256k1PublicKey::LENGTH];
buf[0] = SignatureScheme::Secp256k1 as u8;
buf[1..].copy_from_slice(public_key.as_ref());
Base64Array34::serialize_as(&buf, serializer)
}
MultisigMemberPublicKey::Secp256r1(public_key) => {
let mut buf = [0; 1 + Secp256r1PublicKey::LENGTH];
buf[0] = SignatureScheme::Secp256r1 as u8;
buf[1..].copy_from_slice(public_key.as_ref());
Base64Array34::serialize_as(&buf, serializer)
}
MultisigMemberPublicKey::ZkLogin(_) => Err(serde::ser::Error::custom(
"zklogin not supported in legacy multisig",
)),
}
}
}

impl<'de> DeserializeAs<'de, MultisigMemberPublicKey> for Base64MultisigMemberPublicKey {
fn deserialize_as<D>(deserializer: D) -> Result<MultisigMemberPublicKey, D::Error>
where
D: Deserializer<'de>,
{
let b64: Cow<'de, str> = Deserialize::deserialize(deserializer)?;
let bytes = Base64::decode_vec(&b64).map_err(serde::de::Error::custom)?;
let flag = SignatureScheme::from_byte(
*bytes
.first()
.ok_or_else(|| serde::de::Error::custom("missing signature scheme flag"))?,
)
.map_err(serde::de::Error::custom)?;
let public_key_bytes = &bytes[1..];
match flag {
SignatureScheme::Ed25519 => {
let public_key = Ed25519PublicKey::from_bytes(public_key_bytes)
.map_err(serde::de::Error::custom)?;
Ok(MultisigMemberPublicKey::Ed25519(public_key))
}
SignatureScheme::Secp256k1 => {
let public_key = Secp256k1PublicKey::from_bytes(public_key_bytes)
.map_err(serde::de::Error::custom)?;
Ok(MultisigMemberPublicKey::Secp256k1(public_key))
}
SignatureScheme::Secp256r1 => {
let public_key = Secp256r1PublicKey::from_bytes(public_key_bytes)
.map_err(serde::de::Error::custom)?;
Ok(MultisigMemberPublicKey::Secp256r1(public_key))
}
SignatureScheme::Multisig
| SignatureScheme::Bls12381
| SignatureScheme::ZkLogin
| SignatureScheme::Passkey => {
Err(serde::de::Error::custom("invalid public key type"))
}
}
}
}

pub struct LegacyMultisigMember;

impl SerializeAs<MultisigMember> for LegacyMultisigMember {
fn serialize_as<S>(source: &MultisigMember, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
#[derive(serde_derive::Serialize)]
struct LegacyMember<'a> {
#[serde(with = "::serde_with::As::<Base64MultisigMemberPublicKey>")]
public_key: &'a MultisigMemberPublicKey,
weight: WeightUnit,
}

let legacy = LegacyMember {
public_key: &source.public_key,
weight: source.weight,
};

legacy.serialize(serializer)
}
}

impl<'de> DeserializeAs<'de, MultisigMember> for LegacyMultisigMember {
fn deserialize_as<D>(deserializer: D) -> Result<MultisigMember, D::Error>
where
D: Deserializer<'de>,
{
#[derive(serde_derive::Deserialize)]
struct LegacyMember {
#[serde(with = "::serde_with::As::<Base64MultisigMemberPublicKey>")]
public_key: MultisigMemberPublicKey,
weight: WeightUnit,
}

let legacy = LegacyMember::deserialize(deserializer)?;

Ok(MultisigMember {
public_key: legacy.public_key,
weight: legacy.weight,
})
}
}
use crate::types::{Ed25519PublicKey, Secp256k1PublicKey, Secp256r1PublicKey, SignatureScheme};

#[derive(serde_derive::Deserialize)]
pub struct Multisig {
Expand All @@ -304,53 +148,17 @@ mod serialization {
committee: &'a MultisigCommittee,
}

#[derive(serde_derive::Deserialize)]
pub struct LegacyMultisig {
signatures: Vec<MultisigMemberSignature>,
#[serde(with = "::serde_with::As::<crate::_serde::BinaryRoaringBitmap>")]
bitmap: roaring::RoaringBitmap,
committee: LegacyMultisigCommittee,
}

#[derive(serde_derive::Serialize)]
pub struct LegacyMultisigRef<'a> {
signatures: &'a [MultisigMemberSignature],
#[serde(with = "::serde_with::As::<crate::_serde::BinaryRoaringBitmap>")]
bitmap: &'a roaring::RoaringBitmap,
committee: LegacyMultisigCommitteeRef<'a>,
}

#[derive(serde_derive::Deserialize)]
struct LegacyMultisigCommittee {
#[serde(with = "::serde_with::As::<Vec<LegacyMultisigMember>>")]
members: Vec<MultisigMember>,
threshold: ThresholdUnit,
}

#[derive(serde_derive::Serialize)]
struct LegacyMultisigCommitteeRef<'a> {
#[serde(with = "::serde_with::As::<&[LegacyMultisigMember]>")]
members: &'a [MultisigMember],
threshold: ThresholdUnit,
}

#[derive(serde_derive::Deserialize)]
struct ReadableMultisigAggregatedSignature {
signatures: Vec<MultisigMemberSignature>,
bitmap: BitmapUnit,
#[serde(default)]
#[serde(with = "::serde_with::As::<Option<crate::_serde::Base64RoaringBitmap>>")]
legacy_bitmap: Option<roaring::RoaringBitmap>,
committee: MultisigCommittee,
}

#[derive(serde_derive::Serialize)]
struct ReadableMultisigAggregatedSignatureRef<'a> {
signatures: &'a [MultisigMemberSignature],
bitmap: BitmapUnit,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(with = "::serde_with::As::<Option<crate::_serde::Base64RoaringBitmap>>")]
legacy_bitmap: &'a Option<roaring::RoaringBitmap>,
committee: &'a MultisigCommittee,
}

Expand All @@ -363,33 +171,19 @@ mod serialization {
let readable = ReadableMultisigAggregatedSignatureRef {
signatures: &self.signatures,
bitmap: self.bitmap,
legacy_bitmap: &self.legacy_bitmap,
committee: &self.committee,
};
readable.serialize(serializer)
} else {
let mut buf = Vec::new();
buf.push(SignatureScheme::Multisig as u8);

if let Some(bitmap) = &self.legacy_bitmap {
let legacy = LegacyMultisigRef {
signatures: &self.signatures,
bitmap,
committee: LegacyMultisigCommitteeRef {
members: &self.committee.members,
threshold: self.committee.threshold,
},
};

bcs::serialize_into(&mut buf, &legacy).expect("serialization cannot fail");
} else {
let multisig = MultisigRef {
signatures: &self.signatures,
bitmap: self.bitmap,
committee: &self.committee,
};
bcs::serialize_into(&mut buf, &multisig).expect("serialization cannot fail");
}
let multisig = MultisigRef {
signatures: &self.signatures,
bitmap: self.bitmap,
committee: &self.committee,
};
bcs::serialize_into(&mut buf, &multisig).expect("serialization cannot fail");
serializer.serialize_bytes(&buf)
}
}
Expand All @@ -405,7 +199,6 @@ mod serialization {
Ok(Self {
signatures: readable.signatures,
bitmap: readable.bitmap,
legacy_bitmap: readable.legacy_bitmap,
committee: readable.committee,
})
} else {
Expand All @@ -431,29 +224,12 @@ mod serialization {
}
let bcs_bytes = &bytes[1..];

// Unfortunately we have no information in the serialized form of a Multisig to
// be able to determine if its a Legacy format or the new standard
// format so we just need to try each.
//
// We'll start with the newer format as that should be more prevalent.
if let Ok(multisig) = bcs::from_bytes::<Multisig>(bcs_bytes) {
Ok(Self {
signatures: multisig.signatures,
bitmap: multisig.bitmap,
legacy_bitmap: None,
committee: multisig.committee,
})
} else if let Ok(legacy) = bcs::from_bytes::<LegacyMultisig>(bcs_bytes) {
Ok(Self {
signatures: legacy.signatures,
bitmap: roaring_bitmap_to_u16(&legacy.bitmap)
.map_err(serde::de::Error::custom)?,
legacy_bitmap: Some(legacy.bitmap),
committee: MultisigCommittee {
members: legacy.committee.members,
threshold: legacy.committee.threshold,
},
})
} else {
Err(serde::de::Error::custom("invalid multisig"))
}
Expand Down

0 comments on commit f980d5b

Please sign in to comment.