Skip to content

Commit 8c5001f

Browse files
committed
Removed Signature from core types.rs, replaced all usages with Signature
from crypto types.rs
1 parent a4792e0 commit 8c5001f

9 files changed

Lines changed: 64 additions & 116 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/core/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ dyn-eq.workspace = true
1616
hex.workspace = true
1717
libp2p.workspace = true
1818
vise.workspace = true
19+
pluto-crypto.workspace = true
1920
pluto-eth2api.workspace = true
2021
prost.workspace = true
2122
prost-types.workspace = true

crates/core/src/parsigex_codec.rs

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
88
use std::any::Any;
99

10+
use base64::Engine as _;
11+
1012
use crate::{
1113
signeddata::{
1214
Attestation, BeaconCommitteeSelection, SignedAggregateAndProof, SignedRandao,
@@ -70,6 +72,25 @@ pub enum ParSigExCodecError {
7072
InvalidSignature(String),
7173
}
7274

75+
fn serialize_signature(sig: &Signature) -> Result<Vec<u8>, ParSigExCodecError> {
76+
let encoded = base64::engine::general_purpose::STANDARD.encode(sig);
77+
Ok(serde_json::to_vec(&encoded)?)
78+
}
79+
80+
fn deserialize_signature(bytes: &[u8]) -> Result<Box<dyn SignedData>, ParSigExCodecError> {
81+
let encoded: String = serde_json::from_slice(bytes)?;
82+
let raw = base64::engine::general_purpose::STANDARD
83+
.decode(encoded)
84+
.map_err(|e| ParSigExCodecError::SignedData(format!("invalid base64: {e}")))?;
85+
let sig: Signature = raw.try_into().map_err(|v: Vec<u8>| {
86+
ParSigExCodecError::SignedData(format!(
87+
"invalid signature length: got {}, want 96",
88+
v.len()
89+
))
90+
})?;
91+
Ok(Box::new(sig))
92+
}
93+
7394
pub(crate) fn serialize_signed_data(data: &dyn SignedData) -> Result<Vec<u8>, ParSigExCodecError> {
7495
let any = data as &dyn Any;
7596

@@ -131,7 +152,9 @@ pub(crate) fn serialize_signed_data(data: &dyn SignedData) -> Result<Vec<u8>, Pa
131152
serialize_json!(VersionedSignedValidatorRegistration);
132153
serialize_json!(SignedVoluntaryExit);
133154
serialize_json!(SignedRandao);
134-
serialize_json!(Signature);
155+
if let Some(value) = any.downcast_ref::<Signature>() {
156+
return serialize_signature(value);
157+
}
135158
serialize_json!(BeaconCommitteeSelection);
136159
serialize_json!(SyncCommitteeSelection);
137160

@@ -206,7 +229,7 @@ pub(crate) fn deserialize_signed_data(
206229
DutyType::Randao => deserialize_json!(SignedRandao),
207230

208231
// -- Signature: JSON-only --
209-
DutyType::Signature => deserialize_json!(Signature),
232+
DutyType::Signature => deserialize_signature(bytes),
210233

211234
// -- PrepareAggregator: JSON-only --
212235
DutyType::PrepareAggregator => deserialize_json!(BeaconCommitteeSelection),
@@ -455,4 +478,20 @@ mod tests {
455478
downcast(deserialize_signed_data(&DutyType::Aggregator, &json_bytes).unwrap());
456479
assert_eq!(sap, decoded);
457480
}
481+
482+
#[test]
483+
fn marshal_unmarshal_signature() {
484+
let sig: Signature = [0xab; 96];
485+
let bytes = serialize_signed_data(&sig).unwrap();
486+
487+
// Snapshot: Signature serializes as a base64-encoded JSON string.
488+
// Changing this breaks wire compatibility with Charon.
489+
const EXPECTED: &str = "\"q6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6ur\
490+
q6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6ur\"";
491+
assert_eq!(bytes, EXPECTED.as_bytes());
492+
493+
let decoded: Signature =
494+
downcast(deserialize_signed_data(&DutyType::Signature, &bytes).unwrap());
495+
assert_eq!(sig, decoded);
496+
}
458497
}

crates/core/src/signeddata.rs

Lines changed: 7 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
use serde::{Deserialize, Deserializer, Serialize, Serializer};
44
use tree_hash::TreeHash;
55

6-
use base64::Engine as _;
76
use pluto_eth2api::{
87
spec::{
98
altair, bellatrix, capella, deneb, electra, phase0, serde_legacy_builder_version,
@@ -94,57 +93,16 @@ struct VersionedRawAggregateAndProofJson<T> {
9493

9594
/// Converts an ETH2 signature to a core signature.
9695
pub fn sig_from_eth2(sig: phase0::BLSSignature) -> Signature {
97-
Signature::new(sig)
96+
sig
9897
}
9998

10099
fn sig_to_eth2(sig: &Signature) -> phase0::BLSSignature {
101-
*sig.as_ref()
102-
}
103-
104-
impl serde::Serialize for Signature {
105-
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
106-
where
107-
S: serde::Serializer,
108-
{
109-
let encoded = base64::engine::general_purpose::STANDARD.encode(self.as_ref());
110-
serializer.serialize_str(&encoded)
111-
}
112-
}
113-
114-
impl<'de> serde::Deserialize<'de> for Signature {
115-
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
116-
where
117-
D: serde::Deserializer<'de>,
118-
{
119-
let encoded = String::deserialize(deserializer)?;
120-
let bytes = base64::engine::general_purpose::STANDARD
121-
.decode(encoded)
122-
.map_err(|err| serde::de::Error::custom(format!("invalid base64 signature: {err}")))?;
123-
let sig: [u8; 96] = bytes.try_into().map_err(|bytes: Vec<u8>| {
124-
serde::de::Error::custom(format!(
125-
"invalid signature length: got {}, want 96",
126-
bytes.len()
127-
))
128-
})?;
129-
Ok(Signature::new(sig))
130-
}
131-
}
132-
133-
impl Signature {
134-
/// Converts the signature to an ETH2 signature.
135-
pub fn to_eth2(&self) -> phase0::BLSSignature {
136-
sig_to_eth2(self)
137-
}
138-
139-
/// Creates a partially signed signature wrapper.
140-
pub fn new_partial(sig: Self, share_idx: u64) -> ParSignedData {
141-
ParSignedData::new(sig, share_idx)
142-
}
100+
*sig
143101
}
144102

145103
impl SignedData for Signature {
146104
fn signature(&self) -> Result<Signature, SignedDataError> {
147-
Ok(self.clone())
105+
Ok(*self)
148106
}
149107

150108
fn set_signature(&self, signature: Signature) -> Result<Self, SignedDataError> {
@@ -1361,7 +1319,7 @@ mod tests {
13611319
}
13621320

13631321
fn sample_signature(byte: u8) -> Signature {
1364-
Signature::new([byte; 96])
1322+
[byte; 96]
13651323
}
13661324

13671325
fn sample_root(byte: u8) -> phase0::Root {
@@ -2563,37 +2521,17 @@ mod tests {
25632521
#[test]
25642522
fn signature() {
25652523
let sig1 = sample_signature(0x22);
2566-
let sig2 = sig1.clone();
2524+
let sig2 = sig1;
25672525

25682526
assert!(matches!(
25692527
sig1.message_root(),
25702528
Err(SignedDataError::UnsupportedSignatureMessageRoot)
25712529
));
25722530
assert_eq!(sig1, sig1.signature().unwrap());
2573-
assert_eq!(sig1.to_eth2(), sig2.signature().unwrap().to_eth2());
2531+
assert_eq!(sig1, sig2.signature().unwrap());
25742532

25752533
let ss = sig1.set_signature(sig2.signature().unwrap()).unwrap();
25762534
assert_eq!(sig2, ss);
2577-
2578-
let js = serde_json::to_vec(&sig1).unwrap();
2579-
let sig3: Signature = serde_json::from_slice(&js).unwrap();
2580-
assert_eq!(sig1, sig3);
2581-
}
2582-
2583-
#[test]
2584-
fn signature_json_errors() {
2585-
let invalid_base64 = serde_json::from_slice::<Signature>(br#""%%%""#);
2586-
assert!(matches!(
2587-
invalid_base64,
2588-
Err(err) if matches!(err.classify(), serde_json::error::Category::Data)
2589-
));
2590-
2591-
let short = base64::engine::general_purpose::STANDARD.encode([0x11_u8; 95]);
2592-
let wrong_len = serde_json::from_slice::<Signature>(format!("\"{short}\"").as_bytes());
2593-
assert!(matches!(
2594-
wrong_len,
2595-
Err(err) if matches!(err.classify(), serde_json::error::Category::Data)
2596-
));
25972535
}
25982536

25992537
#[test_case(false ; "unblinded")]
@@ -2751,7 +2689,7 @@ mod tests {
27512689
assert_ne!(msg_root, [0_u8; 32]);
27522690

27532691
let signature = sample_signature(0x99);
2754-
let updated = wrapped.set_signature(signature.clone()).unwrap();
2692+
let updated = wrapped.set_signature(signature).unwrap();
27552693
assert_eq!(signature, updated.signature().unwrap());
27562694

27572695
let js = serde_json::to_vec(&wrapped).unwrap();

crates/core/src/types.rs

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,8 @@ pub enum ProposalType {
300300
// the pub key as [u8; 48] instead of string.
301301
// [original implementation](https://github.com/ObolNetwork/charon/blob/b3008103c5429b031b63518195f4c49db4e9a68d/core/types.go#L264)
302302
const PK_LEN: usize = 48;
303-
const SIG_LEN: usize = 96;
303+
304+
pub use pluto_crypto::types::Signature;
304305

305306
/// Public key struct
306307
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -524,24 +525,6 @@ where
524525
}
525526
}
526527

527-
// todo: add proper signature type
528-
/// Signature type
529-
#[derive(Debug, Clone, PartialEq, Eq)]
530-
pub struct Signature(pub(crate) [u8; SIG_LEN]);
531-
532-
impl Signature {
533-
/// Create a new signature.
534-
pub fn new(signature: [u8; SIG_LEN]) -> Self {
535-
Signature(signature)
536-
}
537-
}
538-
539-
impl AsRef<[u8; SIG_LEN]> for Signature {
540-
fn as_ref(&self) -> &[u8; SIG_LEN] {
541-
&self.0
542-
}
543-
}
544-
545528
/// Signed data type
546529
pub trait SignedData: Any + DynClone + DynEq + StdDebug + Send + Sync {
547530
/// signature returns the signed duty data's signature.
@@ -1027,7 +1010,7 @@ mod tests {
10271010

10281011
impl SignedData for MockSignedData {
10291012
fn signature(&self) -> Result<Signature, SignedDataError> {
1030-
Ok(Signature::new([42u8; SIG_LEN]))
1013+
Ok([42u8; 96])
10311014
}
10321015

10331016
fn set_signature(&self, _signature: Signature) -> Result<Self, SignedDataError> {
@@ -1048,10 +1031,7 @@ mod tests {
10481031
assert!(retrieved.is_some());
10491032
let retrieved = retrieved.unwrap();
10501033
assert_eq!(retrieved.share_idx, 0);
1051-
assert_eq!(
1052-
retrieved.signed_data.signature().unwrap(),
1053-
Signature::new([42u8; SIG_LEN])
1054-
);
1034+
assert_eq!(retrieved.signed_data.signature().unwrap(), [42u8; 96]);
10551035
}
10561036

10571037
#[test]

crates/dkg/src/aggregate.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ pub fn agg_validator_registrations(
246246
.verify(&share.pub_key, &sig_root, &agg_sig)
247247
.map_err(AggregateError::InvalidValidatorRegistrationAggregatedSignature)?;
248248

249-
res.push(msg.set_signature(pluto_core::types::Signature::new(agg_sig))?);
249+
res.push(msg.set_signature(agg_sig)?);
250250
}
251251

252252
Ok(res)
@@ -355,7 +355,7 @@ mod tests {
355355
}
356356

357357
fn partial_signature(sig: Signature, share_idx: u64) -> ParSignedData {
358-
ParSignedData::new(pluto_core::types::Signature::new(sig), share_idx)
358+
ParSignedData::new(sig, share_idx)
359359
}
360360

361361
#[test]

crates/dkg/src/exchanger.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ mod tests {
332332
use anyhow::Context as _;
333333
use futures::StreamExt as _;
334334
use libp2p::{Multiaddr, swarm::SwarmEvent};
335-
use pluto_core::types::{DutyType, ParSignedData, ParSignedDataSet, PubKey, Signature};
335+
use pluto_core::types::{DutyType, ParSignedData, ParSignedDataSet, PubKey};
336336
use pluto_p2p::{
337337
config::P2PConfig,
338338
p2p::{Node, NodeType},
@@ -380,7 +380,7 @@ mod tests {
380380
let mut set = ParSignedDataSet::new();
381381
set.insert(
382382
PubKey::from(pk_bytes),
383-
Signature::new_partial(Signature::new(sig_bytes), share_idx),
383+
ParSignedData::new(sig_bytes, share_idx),
384384
);
385385
set
386386
}
@@ -493,7 +493,7 @@ mod tests {
493493
.map(|j| {
494494
let mut bytes = [0u8; 96];
495495
rand::thread_rng().fill(&mut bytes[..]);
496-
Signature::new_partial(Signature::new(bytes), (j + 1) as u64)
496+
ParSignedData::new(bytes, (j + 1) as u64)
497497
})
498498
.collect();
499499
expected_data.insert(*pk, psigs);

crates/dkg/src/signing.rs

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,7 @@ pub fn sign_lock_hash(share_idx: u64, shares: &[Share], hash: &[u8]) -> Result<P
114114
let pub_key = share_pubkey(share, "signing lock hash")?;
115115
let sig = BlstImpl.sign(&share.secret_share, hash)?;
116116

117-
set.insert(
118-
pub_key,
119-
ParSignedData::new(pluto_core::types::Signature::new(sig), share_idx),
120-
);
117+
set.insert(pub_key, ParSignedData::new(sig, share_idx));
121118
}
122119

123120
Ok(set)
@@ -149,10 +146,7 @@ pub fn sign_deposit_msgs(
149146
let sig_root = deposit::get_message_signing_root(&msg, network_name)?;
150147
let sig = BlstImpl.sign(&share.secret_share, &sig_root)?;
151148

152-
set.insert(
153-
pub_key,
154-
ParSignedData::new(pluto_core::types::Signature::new(sig), share_idx),
155-
);
149+
set.insert(pub_key, ParSignedData::new(sig, share_idx));
156150
msgs.insert(pub_key, msg);
157151
}
158152

@@ -205,10 +199,7 @@ pub fn sign_validator_registrations(
205199
},
206200
)?;
207201

208-
set.insert(
209-
pub_key,
210-
ParSignedData::new(pluto_core::types::Signature::new(sig), share_idx),
211-
);
202+
set.insert(pub_key, ParSignedData::new(sig, share_idx));
212203
msgs.insert(pub_key, signed_reg);
213204
}
214205

@@ -486,7 +477,7 @@ mod tests {
486477
.signature()
487478
.expect("signature should exist");
488479
BlstImpl
489-
.verify(&share.public_shares[&2], &hash, sig.as_ref())
480+
.verify(&share.public_shares[&2], &hash, &sig)
490481
.expect("partial signature should verify against share public key");
491482
}
492483
}

crates/dkg/src/validators.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -214,9 +214,7 @@ mod tests {
214214
fn set_registration_signature_updates_v1_signature() {
215215
let reg =
216216
make_core_registration([0x11; 48], [0x22; 20], 30_000_000, 1_746_843_400, [0; 96]);
217-
let updated =
218-
set_registration_signature(&reg, pluto_core::types::Signature::new([0x44; 96]))
219-
.expect("should work");
217+
let updated = set_registration_signature(&reg, [0x44u8; 96]).expect("should work");
220218

221219
let builder_registration =
222220
builder_registration_from_eth2(&updated).expect("conversion should succeed");

0 commit comments

Comments
 (0)