filecoin_signer/
lib.rs

1#![cfg_attr(not(test), deny(clippy::expect_used,))]
2use std::convert::TryFrom;
3
4use bip39::{Language, MnemonicType, Seed};
5use bls_signatures::Serialize;
6use fvm_shared::crypto::signature::{Signature, SignatureType};
7use fvm_shared::message::Message;
8use libsecp256k1::util::{COMPRESSED_PUBLIC_KEY_SIZE, SECRET_KEY_SIZE, SIGNATURE_SIZE};
9use num_traits::FromPrimitive;
10use rayon::prelude::*;
11use zx_bip44::BIP44Path;
12
13use fil_actor_init::{ExecParams, Method as MethodInit};
14use fil_actor_multisig as multisig;
15use fil_actor_paych as paych;
16use fvm_ipld_encoding::{from_slice, to_vec, RawBytes};
17use fvm_shared::address::{Address, Network, Protocol};
18
19use bls_signatures::PublicKey as BLSPublicKey;
20use libsecp256k1::PublicKey as SECP256K1PublicKey;
21
22use extras::signed_message::ref_fvm::SignedMessage;
23
24use cid::multihash::MultihashDigest;
25use fvm_ipld_encoding::DAG_CBOR;
26use fvm_shared::econ::TokenAmount;
27use fvm_shared::MethodNum;
28
29use crate::api::{MessageParams, MessageTx, MessageTxAPI, MessageTxNetwork};
30use crate::error::SignerError;
31use crate::extended_key::ExtendedSecretKey;
32use crate::multisig_deprecated::ConstructorParamsV1;
33
34pub mod api;
35pub mod error;
36pub mod extended_key;
37pub mod multisig_deprecated;
38pub mod utils;
39
40/// Mnemonic string
41pub struct Mnemonic(pub String);
42
43pub const SIGNATURE_RECOVERY_SIZE: usize = SIGNATURE_SIZE + 1;
44
45/// Private key buffer
46pub struct PrivateKey(pub [u8; SECRET_KEY_SIZE]);
47
48pub enum PublicKey {
49    SECP256K1PublicKey(SECP256K1PublicKey),
50    BLSPublicKey(BLSPublicKey),
51}
52
53impl PublicKey {
54    pub fn to_vec(&self) -> Vec<u8> {
55        match self {
56            // Uncompressed public key 65 bytes
57            PublicKey::SECP256K1PublicKey(pk) => pk.serialize().to_vec(),
58            PublicKey::BLSPublicKey(pk) => pk.as_bytes(),
59        }
60    }
61}
62
63/// Compressed public key buffer
64pub struct PublicKeyCompressed(pub [u8; COMPRESSED_PUBLIC_KEY_SIZE]);
65
66/// Extended key structure
67pub struct ExtendedKey {
68    pub private_key: PrivateKey,
69    pub public_key: PublicKey,
70    pub address: String,
71}
72
73#[cfg(feature = "with-ffi-support")]
74ffi_support::implement_into_ffi_by_pointer!(ExtendedKey);
75
76impl TryFrom<String> for PrivateKey {
77    type Error = SignerError;
78
79    fn try_from(s: String) -> Result<PrivateKey, Self::Error> {
80        let v = base64::decode(&s)?;
81
82        PrivateKey::try_from(v)
83    }
84}
85
86impl TryFrom<Vec<u8>> for PrivateKey {
87    type Error = SignerError;
88
89    fn try_from(v: Vec<u8>) -> Result<PrivateKey, Self::Error> {
90        if v.len() != SECRET_KEY_SIZE {
91            return Err(SignerError::GenericString("Invalid Key Length".to_string()));
92        }
93        let mut sk = PrivateKey([0; SECRET_KEY_SIZE]);
94        sk.0.copy_from_slice(&v[..SECRET_KEY_SIZE]);
95        Ok(sk)
96    }
97}
98
99#[derive(serde::Serialize, serde::Deserialize)]
100#[serde(rename_all = "PascalCase")]
101pub struct ProposalHashDataAPI {
102    #[serde(with = "extras::json::option_address")]
103    pub requester: Option<Address>,
104    #[serde(with = "extras::json::address")]
105    pub to: Address,
106    #[serde(with = "extras::json::tokenamount")]
107    pub value: TokenAmount,
108    pub method: MethodNum,
109    #[serde(with = "extras::json::rawbytes")]
110    pub params: RawBytes,
111}
112
113#[derive(serde::Serialize, serde::Deserialize)]
114#[serde(transparent)]
115pub struct SignedVoucherWrapper(
116    #[serde(with = "extras::paych::SignedVoucherAPI")] paych::SignedVoucher,
117);
118
119/// Generates a random mnemonic (English - 24 words)
120pub fn key_generate_mnemonic() -> Result<Mnemonic, SignerError> {
121    let mnemonic = bip39::Mnemonic::new(MnemonicType::Words24, Language::English);
122    Ok(Mnemonic(mnemonic.to_string()))
123}
124
125fn derive_extended_secret_key(seed: &[u8], path: &str) -> Result<ExtendedSecretKey, SignerError> {
126    let master = ExtendedSecretKey::try_from(seed)?;
127    let bip44_path = BIP44Path::from_string(path)?;
128    let esk = master.derive_bip44(&bip44_path)?;
129
130    Ok(esk)
131}
132
133fn derive_extended_secret_key_from_mnemonic(
134    mnemonic: &str,
135    path: &str,
136    password: &str,
137    language_code: &str,
138) -> Result<ExtendedSecretKey, SignerError> {
139    let lang = Language::from_language_code(language_code);
140
141    match lang {
142        Some(l) => {
143            let mnemonic = bip39::Mnemonic::from_phrase(mnemonic, l)
144                .map_err(|err| SignerError::GenericString(err.to_string()))?;
145
146            let seed = Seed::new(&mnemonic, password);
147
148            derive_extended_secret_key(seed.as_bytes(), path)
149        }
150        None => Err(SignerError::GenericString(
151            "Unknown language code".to_string(),
152        )),
153    }
154}
155
156/// Returns a public key, private key and address given a mnemonic, derivation path and a password (support chinese mnemonic)
157///
158/// # Arguments
159///
160/// * `mnemonic` - A string containing a 24-words English mnemonic
161/// * `path` - A string containing a derivation path
162/// * `password` - Password to decrypt seed, if none use and empty string (e.g "")
163/// * `language_code` - The language code for the mnemonic (e.g "en" if english words are used)
164pub fn key_derive(
165    mnemonic: &str,
166    path: &str,
167    password: &str,
168    language_code: &str,
169) -> Result<ExtendedKey, SignerError> {
170    let esk = derive_extended_secret_key_from_mnemonic(mnemonic, path, password, language_code)?;
171
172    let address = Address::new_secp256k1(esk.public_key().as_ref())?;
173
174    let bip44_path = BIP44Path::from_string(path)?;
175
176    let mut network_str = "f".to_owned();
177    if bip44_path.is_testnet() {
178        network_str = "t".to_owned();
179    }
180
181    let address = network_str + &address.to_string()[1..];
182
183    Ok(ExtendedKey {
184        private_key: PrivateKey(esk.secret_key()),
185        public_key: PublicKey::SECP256K1PublicKey(SECP256K1PublicKey::parse(&esk.public_key())?),
186        address,
187    })
188}
189
190/// Returns a public key, private key and address given a seed and derivation path
191///
192/// # Arguments
193///
194/// * `seed` - A seed as bytes array
195/// * `path` - A string containing a derivation path
196///
197pub fn key_derive_from_seed(seed: &[u8], path: &str) -> Result<ExtendedKey, SignerError> {
198    let esk = derive_extended_secret_key(seed, path)?;
199
200    let address = Address::new_secp256k1(esk.public_key().as_ref())?;
201
202    let bip44_path = BIP44Path::from_string(path)?;
203
204    let mut network_str = "f".to_owned();
205    if bip44_path.is_testnet() {
206        network_str = "t".to_owned();
207    }
208
209    let address = network_str + &address.to_string()[1..];
210
211    Ok(ExtendedKey {
212        private_key: PrivateKey(esk.secret_key()),
213        public_key: PublicKey::SECP256K1PublicKey(SECP256K1PublicKey::parse(&esk.public_key())?),
214        address,
215    })
216}
217
218/// Get extended key from private key
219///
220/// # Arguments
221///
222/// * `private_key` - A `PrivateKey`
223/// * `testnet` - specify the network, `true` if testnet else `false` for mainnet
224///
225pub fn key_recover(private_key: &PrivateKey, testnet: bool) -> Result<ExtendedKey, SignerError> {
226    let secret_key = libsecp256k1::SecretKey::parse_slice(&private_key.0)?;
227    let public_key = libsecp256k1::PublicKey::from_secret_key(&secret_key);
228    let address = Address::new_secp256k1(&public_key.serialize())?;
229
230    let mut network_str = "f".to_owned();
231    if testnet {
232        network_str = "t".to_owned();
233    }
234
235    let address = network_str + &address.to_string()[1..];
236
237    Ok(ExtendedKey {
238        private_key: PrivateKey(secret_key.serialize()),
239        public_key: PublicKey::SECP256K1PublicKey(public_key),
240        address: address,
241    })
242}
243
244/// Get extended key from BLS private key
245///
246/// # Arguments
247///
248/// * `private_key` - A `bls_signatures::PrivateKey`
249/// * `testnet` - specify the network, `true` if testnet else `false` for mainnet
250///
251pub fn key_recover_bls(
252    private_key: &PrivateKey,
253    testnet: bool,
254) -> Result<ExtendedKey, SignerError> {
255    let sk = bls_signatures::PrivateKey::from_bytes(&private_key.0)?;
256
257    let address = Address::new_bls(&sk.public_key().as_bytes())?;
258
259    let mut network_str = "f".to_owned();
260    if testnet {
261        network_str = "t".to_owned();
262    }
263
264    let address = network_str + &address.to_string()[1..];
265
266    let mut secret_key = PrivateKey([0; SECRET_KEY_SIZE]);
267    secret_key.0.copy_from_slice(&sk.as_bytes());
268
269    Ok(ExtendedKey {
270        private_key: secret_key,
271        public_key: PublicKey::BLSPublicKey(sk.public_key()),
272        address,
273    })
274}
275
276/// Serialize a transaction and return a CBOR hexstring.
277///
278/// # Arguments
279///
280/// * `message` - a filecoin message (aka transaction)
281///
282pub fn transaction_serialize(message: &Message) -> Result<Vec<u8>, SignerError> {
283    let message_cbor = to_vec(message)?;
284    Ok(message_cbor)
285}
286
287/// Parse a CBOR hextring into a filecoin transaction (signed or unsigned).
288///
289/// # Arguments
290///
291/// * `hexstring` - the cbor hexstring to parse
292/// * `testnet` - boolean value `true` if testnet or `false` for mainnet
293///
294pub fn transaction_parse(cbor: &[u8], testnet: bool) -> Result<MessageTxAPI, SignerError> {
295    let message: MessageTx = from_slice(cbor)?;
296
297    let message_tx_with_network = MessageTxNetwork {
298        message_tx: MessageTxAPI::from(message),
299        testnet,
300    };
301
302    let parsed_message = MessageTxAPI::try_from(message_tx_with_network)?;
303
304    Ok(parsed_message)
305}
306
307fn transaction_sign_secp56k1_raw(
308    message: &Message,
309    private_key: &PrivateKey,
310) -> Result<Signature, SignerError> {
311    let secret_key = libsecp256k1::SecretKey::parse_slice(&private_key.0)?;
312    let message_ser = to_vec(message)?;
313    let hash = cid::multihash::Code::Blake2b256.digest(&message_ser);
314    let message_cid = cid::Cid::new_v1(DAG_CBOR, hash);
315    let message_digest =
316        libsecp256k1::Message::parse_slice(&utils::blake2b_256(&message_cid.to_bytes()))?;
317
318    let (signature_rs, recovery_id) = libsecp256k1::sign(&message_digest, &secret_key);
319
320    let mut sig = [0; 65];
321    sig[..64].copy_from_slice(&signature_rs.serialize().to_vec());
322    sig[64] = recovery_id.serialize();
323
324    let signature = Signature::new_secp256k1(sig.to_vec());
325
326    Ok(signature)
327}
328
329fn transaction_sign_bls_raw(
330    message: &Message,
331    private_key: &PrivateKey,
332) -> Result<Signature, SignerError> {
333    let sk = bls_signatures::PrivateKey::from_bytes(&private_key.0)?;
334    let message_ser = to_vec(message)?;
335    let hash = cid::multihash::Code::Blake2b256.digest(&message_ser);
336    let message_cid = cid::Cid::new_v1(DAG_CBOR, hash);
337    let sig = sk.sign(&message_cid.to_bytes());
338    let signature = Signature::new_bls(sig.as_bytes());
339
340    Ok(signature)
341}
342
343/// Sign a transaction and return a raw signature (RSV format).
344///
345/// # Arguments
346///
347/// * `message` - an unsigned filecoin message
348/// * `private_key` - a `PrivateKey`
349///
350pub fn transaction_sign_raw(
351    message: &Message,
352    private_key: &PrivateKey,
353) -> Result<Signature, SignerError> {
354    // the `from` address protocol let us know which signing scheme to use
355    let signature = match message.from.protocol() {
356        fvm_shared::address::Protocol::Secp256k1 => {
357            transaction_sign_secp56k1_raw(message, private_key)?
358        }
359        fvm_shared::address::Protocol::BLS => transaction_sign_bls_raw(message, private_key)?,
360        _ => {
361            return Err(SignerError::GenericString(
362                "Unknown signing protocol".to_string(),
363            ));
364        }
365    };
366
367    Ok(signature)
368}
369
370/// Sign a transaction and return a signed message (message + signature).
371///
372/// # Arguments
373///
374/// * `message` - an unsigned filecoin message
375/// * `private_key` - a `PrivateKey`
376///
377pub fn transaction_sign(
378    message: &Message,
379    private_key: &PrivateKey,
380) -> Result<SignedMessage, SignerError> {
381    let signature = transaction_sign_raw(message, private_key)?;
382
383    let signed_message = SignedMessage {
384        message: message.to_owned(),
385        signature,
386    };
387
388    Ok(signed_message)
389}
390
391fn verify_secp256k1_signature(signature: &Signature, cbor: &Vec<u8>) -> Result<bool, SignerError> {
392    let network = Network::Testnet;
393
394    let signature_rs = libsecp256k1::Signature::parse_standard_slice(&signature.bytes[..64])?;
395    let recovery_id = libsecp256k1::RecoveryId::parse(signature.bytes[64])?;
396
397    // Should be default network here
398    // FIXME: For now only testnet
399    // NOTE: It doesn't matter anymore because address don't understand network anymore. Bad.
400    let tx = transaction_parse(cbor, network == Network::Testnet)?;
401
402    // Decode the CBOR transaction hex string into CBOR transaction buffer
403    let message_digest = utils::get_digest(cbor.as_ref())?;
404
405    let blob_to_sign = libsecp256k1::Message::parse_slice(&message_digest)?;
406
407    let public_key = libsecp256k1::recover(&blob_to_sign, &signature_rs, &recovery_id)?;
408    let from = Address::new_secp256k1(public_key.serialize().as_ref())?;
409
410    let tx_from = match tx {
411        MessageTxAPI::Message(tx) => tx.from,
412        MessageTxAPI::SignedMessage(tx) => tx.message.from,
413    };
414    let expected_from = from.to_string();
415
416    // Compare recovered public key with the public key from the transaction
417    if tx_from.to_string() != expected_from {
418        return Ok(false);
419    }
420
421    Ok(libsecp256k1::verify(
422        &blob_to_sign,
423        &signature_rs,
424        &public_key,
425    ))
426}
427
428fn verify_bls_signature(signature: &Signature, cbor: &Vec<u8>) -> Result<bool, SignerError> {
429    // TODO: need a function to extract from public key from cbor buffer directly
430    let message = transaction_parse(cbor, true)?;
431    let message = message.get_message();
432
433    let pk = bls_signatures::PublicKey::from_bytes(&message.from.payload_bytes())?;
434
435    let sig = bls_signatures::Signature::from_bytes(signature.bytes())?;
436
437    let message_ser = to_vec(&message)?;
438    let hash = cid::multihash::Code::Blake2b256.digest(&message_ser);
439    let message_cid = cid::Cid::new_v1(DAG_CBOR, hash);
440    let signing_bytes = message_cid.to_bytes();
441
442    let result = pk.verify(sig, signing_bytes);
443
444    Ok(result)
445}
446
447/// Verify a signature. Return a boolean.
448///
449/// # Arguments
450///
451/// * `signature` - RSV format signature or BLS signature
452/// * `cbor_buffer` - the CBOR transaction to verify the signature against
453///
454pub fn verify_signature(signature: &Signature, cbor: &Vec<u8>) -> Result<bool, SignerError> {
455    // TODO: pass signature.bytes instead of the full signature
456    let result = match signature.sig_type {
457        SignatureType::Secp256k1 => verify_secp256k1_signature(signature, cbor)?,
458        SignatureType::BLS => verify_bls_signature(signature, cbor)?,
459    };
460
461    Ok(result)
462}
463
464fn extract_from_pub_key_from_message(
465    cbor_message: &Vec<u8>,
466) -> Result<bls_signatures::PublicKey, SignerError> {
467    let message = transaction_parse(cbor_message, true)?;
468    let unsigned_message_api = message.get_message();
469    let pk = bls_signatures::PublicKey::from_bytes(&unsigned_message_api.from.payload_bytes())?;
470
471    Ok(pk)
472}
473
474fn extract_bls_signing_bytes_from_message(cbor_message: &Vec<u8>) -> Result<Vec<u8>, SignerError> {
475    let message = transaction_parse(cbor_message, true)?;
476    let unsigned_message_api = message.get_message();
477
478    let message_ser = to_vec(&unsigned_message_api)?;
479    let hash = cid::multihash::Code::Blake2b256.digest(&message_ser);
480    let message_cid = cid::Cid::new_v1(DAG_CBOR, hash);
481    Ok(message_cid.to_bytes())
482}
483
484pub fn verify_aggregated_signature(
485    signature: &Signature,
486    cbor_messages: &[Vec<u8>],
487) -> Result<bool, SignerError> {
488    let sig = bls_signatures::Signature::from_bytes(signature.bytes())?;
489
490    // Get public keys from message
491    let tmp: Result<Vec<_>, SignerError> = cbor_messages
492        .iter()
493        .map(extract_from_pub_key_from_message)
494        .collect();
495
496    let pks = match tmp {
497        Ok(public_keys) => public_keys,
498        Err(_) => {
499            return Err(SignerError::GenericString(
500                "Invalid public key extracted from message".to_string(),
501            ));
502        }
503    };
504
505    // Hashes
506    let tmp: Result<Vec<_>, SignerError> = cbor_messages
507        .iter()
508        .map(extract_bls_signing_bytes_from_message)
509        .collect();
510
511    let signing_bytes = match tmp {
512        Ok(bytes) => bytes,
513        Err(_) => {
514            return Err(SignerError::GenericString(
515                "An invalid message was provided".to_string(),
516            ));
517        }
518    };
519
520    let hashes = signing_bytes
521        .par_iter()
522        .map(|signing_bytes| bls_signatures::hash(signing_bytes.as_ref()))
523        .collect::<Vec<_>>();
524
525    Ok(bls_signatures::verify(&sig, &hashes, pks.as_slice()))
526}
527
528/// Utilitary function to serialize parameters of a message. Return a CBOR hexstring.
529///
530/// # Arguments
531///
532/// * `params` - Parameters to serialize
533
534pub fn serialize_params(params: MessageParams) -> Result<Vec<u8>, SignerError> {
535    let serialized_params = params.serialize()?;
536    let message_cbor = serialized_params.bytes().to_vec();
537    Ok(message_cbor)
538}
539
540/// Sign a voucher for payment channel
541///
542/// # Arguments
543///
544/// * `voucher_string` - Voucher as base64 string;
545/// * `private_key` - Private key as base64 string;
546///
547pub fn sign_voucher(
548    voucher_string: String,
549    private_key: &PrivateKey,
550) -> Result<String, SignerError> {
551    let decoded_voucher = base64::decode(voucher_string)?;
552    let mut voucher: paych::SignedVoucher = from_slice(&decoded_voucher)?;
553
554    let secret_key = libsecp256k1::SecretKey::parse_slice(&private_key.0)?;
555
556    let svb = voucher
557        .signing_bytes()
558        .map_err(|err| SignerError::GenericString(err.to_string()))?;
559    let digest = utils::get_digest_voucher(&svb)?;
560
561    let blob_to_sign = libsecp256k1::Message::parse_slice(&digest)?;
562
563    let (signature_rs, recovery_id) = libsecp256k1::sign(&blob_to_sign, &secret_key);
564
565    let mut sig = [0; 65];
566    sig[..64].copy_from_slice(&signature_rs.serialize()[..]);
567    sig[64] = recovery_id.serialize();
568
569    voucher.signature = Some(Signature::new_secp256k1(sig.to_vec()));
570
571    let binary_voucher = to_vec(&voucher)?;
572    let cbor_voucher = base64::encode(binary_voucher);
573
574    Ok(cbor_voucher)
575}
576
577/// Create a voucher for payment channel
578///
579/// # Arguments
580///
581/// * `payment_channel_address` - The payment channel address;
582/// * `time_lock_min` - Time lock min;
583/// * `time_lock_maax` - Time lock max;
584/// * `amount` - Amount in the voucher;
585/// * `lane` - Lane of the voucher;
586/// * `nonce` - Next nonce of the voucher;
587///
588pub fn create_voucher(
589    payment_channel_address: String,
590    time_lock_min: i64,
591    time_lock_max: i64,
592    amount: String,
593    lane: u64,
594    nonce: u64,
595    min_settle_height: i64,
596) -> Result<String, SignerError> {
597    let network: Network;
598    if payment_channel_address.starts_with("f") {
599        network = Network::Mainnet;
600    } else {
601        network = Network::Testnet;
602    }
603
604    let pch = network.parse_address(&payment_channel_address)?;
605    let amount = match fvm_shared::bigint::BigInt::parse_bytes(amount.as_bytes(), 10) {
606        Some(value) => value,
607        None => {
608            return Err(SignerError::GenericString(
609                "`amount` couldn't be parsed.".to_string(),
610            ));
611        }
612    };
613
614    let voucher = paych::SignedVoucher {
615        channel_addr: pch,
616        time_lock_min,
617        time_lock_max,
618        secret_pre_image: Vec::new(),
619        extra: None,
620        lane,
621        nonce,
622        amount: TokenAmount::from_atto(amount),
623        min_settle_height,
624        merges: Vec::new(),
625        signature: None,
626    };
627
628    let cbor_voucher = base64::encode(to_vec(&voucher)?);
629
630    Ok(cbor_voucher)
631}
632
633/// Deserialize Params
634///
635/// # Arguments
636///
637/// * `params_b64_string` - The base64 params string;
638/// * `actor_type` - The string that tell the actor type;
639/// * `method` - Method for which we want to deserialize the params;
640pub fn deserialize_params(
641    params_b64_string: String,
642    actor_type: String,
643    method: u64,
644) -> Result<MessageParams, SignerError> {
645    let params_decode = base64::decode(params_b64_string)?;
646    let serialized_params = RawBytes::new(params_decode);
647
648    // Deserialize pre-FVM init actor
649    if actor_type.as_str() == "init" {
650        match FromPrimitive::from_u64(method) {
651            Some(MethodInit::Exec) => {
652                let params: ExecParams = RawBytes::deserialize(&serialized_params)?;
653                return Ok(MessageParams::ExecParams(params));
654            }
655            _ => {
656                return Err(SignerError::GenericString(
657                    "Unknown method for init actor.".to_string(),
658                ));
659            }
660        }
661    }
662
663    // Deserialize pre-FVM multisig actor
664    if actor_type.as_str() == "multisig" {
665        match FromPrimitive::from_u64(method) {
666            Some(multisig::Method::Propose) => {
667                let params = serialized_params.deserialize::<multisig::ProposeParams>()?;
668
669                return Ok(MessageParams::ProposeParams(params));
670            }
671            Some(multisig::Method::Approve) | Some(multisig::Method::Cancel) => {
672                let params = serialized_params.deserialize::<multisig::TxnIDParams>()?;
673
674                return Ok(MessageParams::TxnIDParams(params));
675            }
676            Some(multisig::Method::AddSigner) => {
677                let params = serialized_params.deserialize::<multisig::AddSignerParams>()?;
678
679                return Ok(MessageParams::AddSignerParams(params));
680            }
681            Some(multisig::Method::RemoveSigner) => {
682                let params = serialized_params.deserialize::<multisig::RemoveSignerParams>()?;
683
684                return Ok(MessageParams::RemoveSignerParams(params));
685            }
686            Some(multisig::Method::SwapSigner) => {
687                let params = serialized_params.deserialize::<multisig::SwapSignerParams>()?;
688
689                return Ok(MessageParams::SwapSignerParams(params));
690            }
691            Some(multisig::Method::ChangeNumApprovalsThreshold) => {
692                let params = serialized_params
693                    .deserialize::<multisig::ChangeNumApprovalsThresholdParams>()?;
694
695                return Ok(MessageParams::ChangeNumApprovalsThresholdParams(params));
696            }
697            Some(multisig::Method::LockBalance) => {
698                let params = serialized_params.deserialize::<multisig::LockBalanceParams>()?;
699
700                return Ok(MessageParams::LockBalanceParams(params));
701            }
702            _ => {
703                return Err(SignerError::GenericString(
704                    "Unknown method for multisig actor.".to_string(),
705                ));
706            }
707        }
708    }
709
710    // Deserialize pre-FVM paymentchannel actor
711    if actor_type.as_str() == "paymentchannel" {
712        match FromPrimitive::from_u64(method) {
713            Some(paych::Method::UpdateChannelState) => {
714                let params: fil_actor_paych::UpdateChannelStateParams =
715                    RawBytes::deserialize(&serialized_params)?;
716
717                return Ok(MessageParams::UpdateChannelStateParams(params));
718            }
719            Some(paych::Method::Settle) | Some(paych::Method::Collect) => {
720                /* Note : those method doesn't have params to decode */
721                return Ok(MessageParams::MessageParamsSerialized("".to_string()));
722            }
723            _ => {
724                return Err(SignerError::GenericString(
725                    "Unknown method for paymentchannel actor.".to_string(),
726                ));
727            }
728        }
729    }
730
731    Err(SignerError::GenericString(
732        "Actor type not supported.".to_string(),
733    ))
734}
735
736/// Deserialize Constructor Params
737///
738/// # Arguments
739///
740/// * `params_b64_string` - The base64 params string;
741/// * `code_cid` - The string that tell the actor type which is being crated with this parameters;
742pub fn deserialize_constructor_params(
743    params_b64_string: String,
744    code_cid: String,
745) -> Result<MessageParams, SignerError> {
746    let params_decode = base64::decode(params_b64_string)?;
747    let serialized_params = RawBytes::new(params_decode);
748
749    if code_cid.as_str() == "multisig" {
750        let params = serialized_params.deserialize::<multisig::ConstructorParams>()?;
751        return Ok(MessageParams::MultisigConstructorParams(params));
752    }
753
754    if code_cid.as_str() == "paymentchannel" {
755        let params = serialized_params.deserialize::<paych::ConstructorParams>()?;
756        return Ok(MessageParams::PaychConstructorParams(params.into()));
757    }
758
759    if code_cid.as_str() == "fil/1/multisig" {
760        let deprecated_multisig_params = serialized_params.deserialize::<ConstructorParamsV1>()?;
761        let params = multisig::ConstructorParams {
762            signers: deprecated_multisig_params.signers,
763            num_approvals_threshold: deprecated_multisig_params.num_approvals_threshold,
764            unlock_duration: deprecated_multisig_params.unlock_duration,
765            start_epoch: 0,
766        };
767        return Ok(MessageParams::MultisigConstructorParams(params));
768    }
769
770    Err(SignerError::GenericString(
771        "Code CID not supported.".to_string(),
772    ))
773}
774
775/// Verify Voucher signature
776///
777/// # Arguments
778///
779/// * `voucher_base64_string` - The voucher as a base64 string;
780/// * `address_signer` - The address matching the private key that signed the voucher;
781pub fn verify_voucher_signature(
782    voucher_base64_string: String,
783    address_signer: String,
784) -> Result<bool, SignerError> {
785    let decoded_voucher = base64::decode(voucher_base64_string)?;
786    let signed_voucher: paych::SignedVoucher = from_slice(&decoded_voucher)?;
787
788    let network: Network;
789    if address_signer.starts_with("f") {
790        network = Network::Mainnet;
791    } else {
792        network = Network::Testnet;
793    }
794    let address = network.parse_address(&address_signer)?;
795
796    let sv_bytes = signed_voucher
797        .signing_bytes()
798        .map_err(|err| SignerError::GenericString(err.to_string()))?;
799    let digest = utils::get_digest_voucher(&sv_bytes)?;
800
801    match &signed_voucher.signature {
802        Some(signature) => match address.protocol() {
803            Protocol::Secp256k1 => {
804                let sig = libsecp256k1::Signature::parse_standard_slice(&signature.bytes()[..64])?;
805                let recovery_id = libsecp256k1::RecoveryId::parse(signature.bytes()[64])?;
806                let message = libsecp256k1::Message::parse(&digest);
807                let public_key = libsecp256k1::recover(&message, &sig, &recovery_id)?;
808                let signer = Address::new_secp256k1(public_key.serialize().as_ref())?;
809
810                if signer.to_string() != address.to_string() {
811                    Err(SignerError::GenericString(
812                        "Address recovered doesn't match address given".to_string(),
813                    ))
814                } else {
815                    Ok(libsecp256k1::verify(&message, &sig, &public_key))
816                }
817            }
818            Protocol::BLS => {
819                let pk = bls_signatures::PublicKey::from_bytes(&address.payload_bytes())?;
820                let sig = bls_signatures::Signature::from_bytes(signature.bytes())?;
821
822                Ok(pk.verify(sig, digest))
823            }
824            _ => Err(SignerError::GenericString(
825                "Address should BLS or Secp256k1.".to_string(),
826            )),
827        },
828        None => Err(SignerError::GenericString(
829            "Voucher not signed.".to_string(),
830        )),
831    }
832}
833
834/// Serialize voucher
835///
836/// # Arguments
837///
838/// * `voucher` - The voucher data;
839pub fn serialize_voucher(voucher: SignedVoucherWrapper) -> Result<String, SignerError> {
840    let serialized_voucher = to_vec(&voucher)?;
841
842    Ok(base64::encode(serialized_voucher))
843}
844
845/// Deserialize voucher
846///
847/// # Arguments
848///
849/// * `voucher_base64_string` - The voucher data;
850pub fn deserialize_voucher(
851    voucher_base64_string: String,
852) -> Result<SignedVoucherWrapper, SignerError> {
853    let serialized_voucher = base64::decode(&voucher_base64_string)?;
854
855    let signed_voucher: paych::SignedVoucher = from_slice(&serialized_voucher)?;
856
857    Ok(SignedVoucherWrapper(signed_voucher))
858}
859
860/// Compute proposal hash
861///
862/// # Arguments
863///
864/// * `proposal_hash_data` - The proposal hash;
865pub fn compute_proposal_hash(
866    proposal_hash_data: ProposalHashDataAPI,
867) -> Result<String, SignerError> {
868    let proposal_data = multisig::ProposalHashData {
869        requester: proposal_hash_data.requester.as_ref(),
870        to: &proposal_hash_data.to,
871        value: &proposal_hash_data.value,
872        method: &proposal_hash_data.method,
873        params: &proposal_hash_data.params,
874    };
875
876    let serialize_proposal_data = RawBytes::serialize(proposal_data)
877        .map_err(|err| SignerError::GenericString(err.to_string()))?;
878    let proposal_hash = utils::blake2b_256(&serialize_proposal_data);
879
880    Ok(base64::encode(proposal_hash))
881}
882
883/// Return the CID of a message
884///
885/// # Arguments
886///
887/// * `message_api` - The message;
888pub fn get_cid(message_api: MessageTxAPI) -> Result<String, SignerError> {
889    match message_api {
890        MessageTxAPI::Message(message) => {
891            let message_ser = to_vec(&message)?;
892            let hash = cid::multihash::Code::Blake2b256.digest(&message_ser);
893            let message_cid = cid::Cid::new_v1(DAG_CBOR, hash);
894
895            Ok(message_cid.to_string())
896        }
897        MessageTxAPI::SignedMessage(signed_message) => {
898            let message_ser = to_vec(&signed_message)?;
899            let hash = cid::multihash::Code::Blake2b256.digest(&message_ser);
900            let message_cid = cid::Cid::new_v1(DAG_CBOR, hash);
901
902            Ok(message_cid.to_string())
903        }
904    }
905}