1pub use super::fvm_shared_latest::{
4 self, IPLD_RAW, commcid::Commitment, crypto::signature::SECP_SIG_LEN,
5};
6use super::version::NetworkVersion;
7use crate::eth::{EthChainId, EthTx};
8use crate::message::{Message, SignedMessage};
9use anyhow::{Context, ensure};
10use bls_signatures::{PublicKey as BlsPublicKey, Signature as BlsSignature};
11use cid::Cid;
12use fvm_ipld_encoding::{
13 de,
14 repr::{Deserialize_repr, Serialize_repr},
15 ser, strict_bytes,
16};
17pub use fvm_shared_latest::crypto::signature::BLS_SIG_LEN;
18pub use fvm_shared3::TICKET_RANDOMNESS_LOOKBACK;
19use get_size2::GetSize;
20use num::FromPrimitive;
21use num_derive::FromPrimitive;
22use schemars::JsonSchema;
23use std::borrow::Cow;
24
25#[derive(Clone, Debug, PartialEq, Eq, Hash, GetSize, derive_more::Constructor)]
27#[cfg_attr(test, derive(derive_quickcheck_arbitrary::Arbitrary))]
28pub struct Signature {
29 pub sig_type: SignatureType,
30 pub bytes: Vec<u8>,
31}
32
33impl ser::Serialize for Signature {
34 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
35 where
36 S: ser::Serializer,
37 {
38 let mut bytes = Vec::with_capacity(self.bytes.len() + 1);
39 bytes.push(self.sig_type as u8);
41 bytes.extend_from_slice(&self.bytes);
42
43 strict_bytes::Serialize::serialize(&bytes, serializer)
44 }
45}
46
47impl<'de> de::Deserialize<'de> for Signature {
48 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
49 where
50 D: de::Deserializer<'de>,
51 {
52 let bytes: Cow<'de, [u8]> = strict_bytes::Deserialize::deserialize(deserializer)?;
53 match bytes.split_first() {
54 None => Err(de::Error::custom("Cannot deserialize empty bytes")),
55 Some((&sig_byte, rest)) => {
56 let sig_type = SignatureType::from_u8(sig_byte).ok_or_else(|| {
58 de::Error::custom(format!(
59 "Invalid signature type byte (must be 1, 2 or 3), was {sig_byte}"
60 ))
61 })?;
62
63 Ok(Signature {
64 bytes: rest.to_vec(),
65 sig_type,
66 })
67 }
68 }
69 }
70}
71
72impl Signature {
73 pub fn new_bls(bytes: Vec<u8>) -> Self {
75 Self {
76 sig_type: SignatureType::Bls,
77 bytes,
78 }
79 }
80
81 pub fn new_secp256k1(bytes: Vec<u8>) -> Self {
83 Self {
84 sig_type: SignatureType::Secp256k1,
85 bytes,
86 }
87 }
88
89 pub fn new_delegated(bytes: Vec<u8>) -> Self {
91 Self {
92 sig_type: SignatureType::Delegated,
93 bytes,
94 }
95 }
96
97 pub fn from_bytes(bytes: Vec<u8>) -> Result<Self, anyhow::Error> {
99 if bytes.is_empty() {
100 anyhow::bail!("Empty signature bytes");
101 }
102
103 let first_byte = bytes
104 .first()
105 .ok_or_else(|| anyhow::anyhow!("Invalid signature bytes"))?;
106
107 let signature_data = bytes
108 .get(1..)
109 .ok_or_else(|| anyhow::anyhow!("Invalid signature bytes"))?
110 .to_vec();
111
112 let sig_type = SignatureType::try_from(*first_byte)?;
114 match sig_type {
115 SignatureType::Secp256k1 => Ok(Self::new_secp256k1(signature_data)),
116 SignatureType::Bls => Ok(Self::new_bls(signature_data)),
117 SignatureType::Delegated => Ok(Self::new_delegated(signature_data)),
118 }
119 }
120
121 pub fn to_bytes(&self) -> Vec<u8> {
123 let mut bytes = Vec::with_capacity(self.bytes.len() + 1);
124 bytes.push(self.sig_type as u8);
125 bytes.extend_from_slice(&self.bytes);
126 bytes
127 }
128
129 pub fn signature_type(&self) -> SignatureType {
130 self.sig_type
131 }
132
133 pub fn authenticate_msg(
137 &self,
138 eth_chain_id: EthChainId,
139 msg: &SignedMessage,
140 addr: &crate::shim::address::Address,
141 ) -> anyhow::Result<()> {
142 match self.sig_type {
143 SignatureType::Delegated => {
144 let eth_tx = EthTx::from_signed_message(eth_chain_id, msg)?;
145 let filecoin_msg = eth_tx.get_unsigned_message(msg.from(), eth_chain_id)?;
146 ensure!(
147 msg.message().cid() == filecoin_msg.cid(),
148 "Ethereum transaction roundtrip mismatch"
149 );
150 let sig = Signature {
152 bytes: eth_tx.to_verifiable_signature(Vec::from(self.bytes()), eth_chain_id)?,
153 ..*self
154 };
155 let digest = eth_tx.rlp_unsigned_message(eth_chain_id)?;
157 sig.verify(&digest, addr)
158 }
159 _ => {
160 let digest = msg.message().cid().to_bytes();
161 self.verify(&digest, addr)
162 }
163 }
164 }
165
166 pub fn verify(&self, data: &[u8], addr: &crate::shim::address::Address) -> anyhow::Result<()> {
168 use super::fvm_shared_latest::crypto::signature::ops::{
169 verify_bls_sig, verify_secp256k1_sig,
170 };
171 match self.sig_type {
172 SignatureType::Bls => {
173 verify_bls_sig(&self.bytes, data, addr).map_err(anyhow::Error::msg)
174 }
175 SignatureType::Secp256k1 => {
176 verify_secp256k1_sig(&self.bytes, data, addr).map_err(anyhow::Error::msg)
177 }
178 SignatureType::Delegated => verify_delegated_sig(&self.bytes, data, addr),
179 }
180 }
181
182 pub fn bytes(&self) -> &[u8] {
184 &self.bytes
185 }
186
187 pub fn is_valid_secpk_sig_type(&self, network_version: NetworkVersion) -> bool {
189 if network_version < NetworkVersion::V18 {
190 matches!(self.sig_type, SignatureType::Secp256k1)
191 } else {
192 matches!(
193 self.sig_type,
194 SignatureType::Secp256k1 | SignatureType::Delegated
195 )
196 }
197 }
198}
199
200impl TryFrom<&Signature> for BlsSignature {
201 type Error = anyhow::Error;
202 fn try_from(value: &Signature) -> Result<Self, Self::Error> {
203 use bls_signatures::Serialize as _;
204
205 match value.sig_type {
206 SignatureType::Secp256k1 => {
207 anyhow::bail!("cannot convert Secp256k1 signature to bls signature")
208 }
209 SignatureType::Bls => Ok(BlsSignature::from_bytes(&value.bytes)?),
210 SignatureType::Delegated => {
211 anyhow::bail!("cannot convert delegated signature to bls signature")
212 }
213 }
214 }
215}
216
217pub fn verify_bls_aggregate(data: &[&[u8]], pub_keys: &[BlsPublicKey], sig: &Signature) -> bool {
221 if data.len() != pub_keys.len() {
223 return false;
224 }
225 if data.is_empty() {
226 return true;
227 }
228
229 let bls_sig = match sig.try_into() {
230 Ok(bls_sig) => bls_sig,
231 _ => return false,
232 };
233
234 bls_signatures::verify_messages(&bls_sig, data, pub_keys)
236}
237
238pub fn verify_bls_sig(
240 signature: &[u8],
241 data: &[u8],
242 addr: &crate::shim::address::Address,
243) -> Result<(), String> {
244 fvm_shared_latest::crypto::signature::ops::verify_bls_sig(signature, data, &addr.into())
245}
246
247pub fn verify_delegated_sig(
249 signature: &[u8],
250 data: &[u8],
251 addr: &crate::shim::address::Address,
252) -> anyhow::Result<()> {
253 use super::fvm_shared_latest::{
254 address::Protocol::Delegated,
255 crypto::signature::{SECP_SIG_LEN, ops::recover_secp_public_key},
256 };
257 use crate::rpc::eth::types::EthAddress;
258 use crate::utils::encoding::keccak_256;
259
260 anyhow::ensure!(
261 addr.protocol() == Delegated,
262 "cannot validate a delegated signature against a {} address expected",
263 addr.protocol()
264 );
265
266 let sig: [u8; SECP_SIG_LEN] = signature.try_into().with_context(|| {
267 format!(
268 "invalid delegated signature length. Was {}, must be {}",
269 signature.len(),
270 SECP_SIG_LEN,
271 )
272 })?;
273
274 let hash = keccak_256(data);
275 let pub_key = recover_secp_public_key(&hash, &sig)?;
276
277 let eth_addr = EthAddress::eth_address_from_pub_key(&pub_key)?;
278
279 let rec_addr = eth_addr.to_filecoin_address()?;
280
281 anyhow::ensure!(rec_addr == *addr, "Delegated signature verification failed");
283
284 Ok(())
285}
286
287pub fn cid_to_replica_commitment_v1(c: &Cid) -> Result<Commitment, &'static str> {
291 fvm_shared_latest::commcid::cid_to_replica_commitment_v1(c)
292}
293
294#[derive(
296 Clone,
297 Debug,
298 PartialEq,
299 FromPrimitive,
300 Copy,
301 Eq,
302 Serialize_repr,
303 Deserialize_repr,
304 Hash,
305 strum::Display,
306 strum::EnumString,
307 JsonSchema,
308 GetSize,
309)]
310#[cfg_attr(test, derive(derive_quickcheck_arbitrary::Arbitrary))]
311#[repr(u8)]
312#[strum(serialize_all = "lowercase")]
313pub enum SignatureType {
314 Secp256k1 = 1,
315 Bls = 2,
316 Delegated = 3,
317}
318
319impl TryFrom<u8> for SignatureType {
320 type Error = anyhow::Error;
321
322 fn try_from(value: u8) -> Result<Self, Self::Error> {
323 match value {
324 1 => Ok(SignatureType::Secp256k1),
325 2 => Ok(SignatureType::Bls),
326 3 => Ok(SignatureType::Delegated),
327 invalid => anyhow::bail!("Invalid signature type byte: {}", invalid),
328 }
329 }
330}
331
332#[cfg(test)]
333mod tests {
334 use super::*;
335 use crate::eth::EthEip1559TxArgsBuilder;
336 use crate::networks::calibnet;
337 use crate::{
338 key_management::{generate_key, sign},
339 message::SignedMessage,
340 shim::{address::Address, crypto::SignatureType},
341 };
342 use num_bigint::BigInt;
343 use std::str::FromStr;
344
345 const TEST_CHAIN_ID: EthChainId = calibnet::ETH_CHAIN_ID;
346
347 fn create_delegated_key() -> (Address, Vec<u8>) {
348 let key = generate_key(SignatureType::Delegated).unwrap();
349 let addr = key.address;
350 let priv_key = key.key_info.private_key().clone();
351 (addr, priv_key)
352 }
353
354 fn create_eip1559_tx() -> EthTx {
356 EthTx::Eip1559(Box::new(
357 EthEip1559TxArgsBuilder::default()
358 .chain_id(TEST_CHAIN_ID)
359 .nonce(486_u64)
360 .to(Some(ethereum_types::H160::from_str("0xeb4a9cdb9f42d3a503d580a39b6e3736eb21fffd").unwrap().into()))
361 .value(BigInt::from(0))
362 .max_fee_per_gas(BigInt::from(1500000120))
363 .max_priority_fee_per_gas(BigInt::from(1500000000))
364 .gas_limit(37442471_u64)
365 .input(hex::decode("383487be000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000660d4d120000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000003b6261666b726569656f6f75326d36356276376561786e7767656d7562723675787269696867366474646e6c7a663469616f37686c6e6a6d647372750000000000").unwrap())
366 .build()
367 .unwrap()
368 )
369 )
370 }
371
372 fn create_signed_message(signature_type: SignatureType) -> (Address, SignedMessage) {
373 let eth_tx = create_eip1559_tx();
374 let key = generate_key(signature_type).unwrap();
375 let from = key.address;
376 let encoded_msg = eth_tx.rlp_unsigned_message(calibnet::ETH_CHAIN_ID).unwrap();
377 let signature = sign(signature_type, key.key_info.private_key(), &encoded_msg).unwrap();
378 let msg = SignedMessage::new_unchecked(
379 eth_tx.get_unsigned_message(from, TEST_CHAIN_ID).unwrap(),
380 signature.clone(),
381 );
382 (from, msg)
383 }
384
385 #[test]
386 fn test_verify_delegated_sig_valid() {
387 let (address, priv_key) = create_delegated_key();
388 let message = b"important protocol message";
389 let signature = sign(SignatureType::Delegated, &priv_key, message).unwrap();
390
391 let result = verify_delegated_sig(&signature.bytes, message, &address);
392 assert!(result.is_ok(), "Valid delegated signature should verify");
393 }
394
395 #[test]
396 fn test_verify_delegated_sig_invalid_signature() {
397 let (address, priv_key) = create_delegated_key();
398 let message = b"important protocol message";
399 let mut signature = sign(SignatureType::Delegated, &priv_key, message).unwrap();
400
401 if let Some(last_byte) = signature.bytes.last_mut() {
403 *last_byte = last_byte.wrapping_add(1);
404 }
405
406 let result = verify_delegated_sig(&signature.bytes, message, &address);
407 assert!(result.is_err(), "Tampered signature should fail");
408 }
409
410 #[test]
411 fn test_verify_delegated_sig_wrong_address() {
412 let (_, priv_key) = create_delegated_key();
413 let (wrong_address, _) = create_delegated_key();
414 let signature = sign(SignatureType::Delegated, &priv_key, b"message").unwrap();
415
416 let result = verify_delegated_sig(&signature.bytes, b"message", &wrong_address);
417 assert!(
418 result.is_err(),
419 "Signature should not verify for wrong address"
420 );
421 }
422
423 #[test]
424 fn test_verify_delegated_sig_invalid_length() {
425 let (address, _) = create_delegated_key();
426 let invalid_sig = vec![0u8; 64]; let result = verify_delegated_sig(&invalid_sig, b"message", &address);
429 assert!(result.is_err(), "Should error on invalid signature length");
430 }
431
432 #[test]
433 fn test_verify_delegated_sig_non_delegated_address() {
434 let secp_key = generate_key(SignatureType::Secp256k1).unwrap();
435 let secp_addr = secp_key.address;
436 let (_, priv_key) = create_delegated_key();
437 let signature = sign(SignatureType::Delegated, &priv_key, b"message").unwrap();
438
439 let result = verify_delegated_sig(&signature.bytes, b"message", &secp_addr);
440 assert!(result.is_err(), "Should reject non-delegated address");
441 }
442
443 #[test]
444 fn test_verify_delegated_sig_empty_message() {
445 let (address, priv_key) = create_delegated_key();
446 let signature = sign(SignatureType::Delegated, &priv_key, &[]).unwrap();
447
448 let result = verify_delegated_sig(&signature.bytes, &[], &address);
449 assert!(result.is_ok(), "Should handle empty messages");
450 }
451
452 #[test]
453 fn authenticate_valid_signed_message() {
454 let (from, signed_msg) = create_signed_message(SignatureType::Delegated);
455 let result = signed_msg
456 .signature()
457 .authenticate_msg(TEST_CHAIN_ID, &signed_msg, &from);
458 assert!(result.is_ok(), "Invalid Delegated signature");
459 }
460
461 #[test]
462 fn authenticate_invalid_signature_type() {
463 let (addr, signed_msg) = create_signed_message(SignatureType::Bls);
464 let mut bad_sign = signed_msg.signature().clone();
465 bad_sign.sig_type = SignatureType::Delegated; let result = bad_sign.authenticate_msg(TEST_CHAIN_ID, &signed_msg, &addr);
468 assert!(result.is_err(), "Mismatched signature type should fail");
469 }
470
471 #[test]
472 fn authenticate_tampered_signature() {
473 let (addr, mut signed_msg) = create_signed_message(SignatureType::Delegated);
474 signed_msg.signature.bytes[32] = signed_msg.signature.bytes[32].wrapping_add(1);
475
476 let result = signed_msg
477 .signature()
478 .authenticate_msg(TEST_CHAIN_ID, &signed_msg, &addr);
479
480 assert!(result.is_err(), "Tampered signature should fail");
481 }
482
483 #[test]
484 fn authenticate_delegated_invalid_chain_id() {
485 let (addr, signed_msg) = create_signed_message(SignatureType::Delegated);
486
487 let result = signed_msg
488 .signature()
489 .authenticate_msg(0, &signed_msg, &addr); assert!(result.is_err(), "Chain ID mismatch should fail");
492 }
493}