1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// Copyright 2019-2024 ChainSafe Systems
// SPDX-License-Identifier: Apache-2.0, MIT

use crate::shim::{
    address::Address,
    crypto::{Signature, SignatureType},
};
use crate::utils::encoding::blake2b_256;
use bls_signatures::{PrivateKey as BlsPrivate, Serialize};
use libsecp256k1::{Message as SecpMessage, PublicKey as SecpPublic, SecretKey as SecpPrivate};
use rand::rngs::OsRng;

use super::errors::Error;

/// Return the public key for a given private key and `SignatureType`
pub fn to_public(sig_type: SignatureType, private_key: &[u8]) -> Result<Vec<u8>, Error> {
    match sig_type {
        SignatureType::Bls => Ok(BlsPrivate::from_bytes(private_key)
            .map_err(|err| Error::Other(err.to_string()))?
            .public_key()
            .as_bytes()),
        SignatureType::Secp256k1 => {
            let private_key = SecpPrivate::parse_slice(private_key)
                .map_err(|err| Error::Other(err.to_string()))?;
            let public_key = SecpPublic::from_secret_key(&private_key);
            Ok(public_key.serialize().to_vec())
        }
        SignatureType::Delegated => {
            unimplemented!()
        }
    }
}

/// Return a new Address that is of a given `SignatureType` and uses the
/// supplied public key
pub fn new_address(sig_type: SignatureType, public_key: &[u8]) -> Result<Address, Error> {
    match sig_type {
        SignatureType::Bls => {
            let addr = Address::new_bls(public_key).map_err(|err| Error::Other(err.to_string()))?;
            Ok(addr)
        }
        SignatureType::Secp256k1 => {
            let addr =
                Address::new_secp256k1(public_key).map_err(|err| Error::Other(err.to_string()))?;
            Ok(addr)
        }
        SignatureType::Delegated => {
            unimplemented!()
        }
    }
}

/// Sign takes in `SignatureType`, private key and message. Returns a Signature
/// for that message
pub fn sign(sig_type: SignatureType, private_key: &[u8], msg: &[u8]) -> Result<Signature, Error> {
    match sig_type {
        SignatureType::Bls => {
            let priv_key =
                BlsPrivate::from_bytes(private_key).map_err(|err| Error::Other(err.to_string()))?;
            // this returns a signature from bls-signatures, so we need to convert this to a
            // crypto signature
            let sig = priv_key.sign(msg);
            let crypto_sig = Signature::new_bls(sig.as_bytes());
            Ok(crypto_sig)
        }
        SignatureType::Secp256k1 => {
            let priv_key = SecpPrivate::parse_slice(private_key)
                .map_err(|err| Error::Other(err.to_string()))?;
            let msg_hash = blake2b_256(msg);
            let message = SecpMessage::parse(&msg_hash);
            let (sig, recovery_id) = libsecp256k1::sign(&message, &priv_key);
            let mut new_bytes = [0; 65];
            new_bytes[..64].copy_from_slice(&sig.serialize());
            new_bytes[64] = recovery_id.serialize();
            let crypto_sig = Signature::new_secp256k1(new_bytes.to_vec());
            Ok(crypto_sig)
        }
        SignatureType::Delegated => {
            unimplemented!()
        }
    }
}

/// Generate a new private key
pub fn generate(sig_type: SignatureType) -> Result<Vec<u8>, Error> {
    let rng = &mut OsRng;
    match sig_type {
        SignatureType::Bls => {
            let key = BlsPrivate::generate(rng);
            Ok(key.as_bytes())
        }
        SignatureType::Secp256k1 => {
            let key = SecpPrivate::random(rng);
            Ok(key.serialize().to_vec())
        }
        SignatureType::Delegated => {
            unimplemented!()
        }
    }
}