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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
//! Secp256k1 signatures.
use base64::prelude::*;
use digest::{consts::U32, Digest, FixedOutput};
use k256::{
    self,
    ecdsa::{
        self,
        signature::{DigestSigner as _, DigestVerifier, Signer as _, Verifier as _},
    },
    elliptic_curve::sec1::{FromEncodedPoint, ToEncodedPoint},
    sha2::Sha512_256,
};

use crate::crypto::signature::{Error, Signature};

/// A Secp256k1 public key (in compressed form).
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PublicKey(k256::EncodedPoint);

impl PublicKey {
    /// Return a byte representation of this public key.
    pub fn as_bytes(&self) -> &[u8] {
        self.0.as_bytes()
    }

    /// Return an alternative byte representation used in deriving Ethereum-compatible addresses.
    pub fn to_uncompressed_untagged_bytes(&self) -> Vec<u8> {
        // Our wrapper type only accepts compressed points, so we shouldn't get None.
        let pk = k256::PublicKey::from_encoded_point(&self.0).unwrap();
        pk.to_encoded_point(false).as_bytes()[1..].to_vec()
    }

    /// Derive an Ethereum-compatible address.
    pub fn to_eth_address(&self) -> Vec<u8> {
        sha3::Keccak256::digest(self.to_uncompressed_untagged_bytes())[32 - 20..].to_vec()
    }

    /// Construct a public key from a slice of bytes.
    pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
        k256::EncodedPoint::from_bytes(bytes)
            .map_err(|_| Error::MalformedPublicKey)
            .map(PublicKey)
    }

    /// Verify a signature.
    pub fn verify(
        &self,
        context: &[u8],
        message: &[u8],
        signature: &Signature,
    ) -> Result<(), Error> {
        let digest = Sha512_256::new()
            .chain_update(context)
            .chain_update(message);
        self.verify_digest(digest, signature)
            .map_err(|_| Error::VerificationFailed)
    }

    /// Verify signature without using any domain separation scheme.
    pub fn verify_raw(&self, message: &[u8], signature: &Signature) -> Result<(), Error> {
        let sig = ecdsa::Signature::from_der(signature.0.as_ref())
            .map_err(|_| Error::MalformedSignature)?;
        let verify_key = ecdsa::VerifyingKey::from_encoded_point(&self.0)
            .map_err(|_| Error::MalformedPublicKey)?;
        verify_key
            .verify(message, &sig)
            .map_err(|_| Error::VerificationFailed)
    }

    /// Verify signature of a pre-hashed message.
    pub fn verify_digest<D>(&self, digest: D, signature: &Signature) -> Result<(), Error>
    where
        D: Digest + FixedOutput<OutputSize = U32>,
    {
        let sig = ecdsa::Signature::from_der(signature.as_ref())
            .map_err(|_| Error::MalformedSignature)?;
        let verify_key = ecdsa::VerifyingKey::from_encoded_point(&self.0)
            .map_err(|_| Error::MalformedPublicKey)?;
        verify_key
            .verify_digest(digest, &sig)
            .map_err(|_| Error::VerificationFailed)
    }
}

impl From<&'static str> for PublicKey {
    fn from(s: &'static str) -> PublicKey {
        PublicKey::from_bytes(&BASE64_STANDARD.decode(s).unwrap()).unwrap()
    }
}

impl cbor::Encode for PublicKey {
    fn into_cbor_value(self) -> cbor::Value {
        cbor::Value::ByteString(self.as_bytes().to_vec())
    }
}

impl cbor::Decode for PublicKey {
    fn try_from_cbor_value(value: cbor::Value) -> Result<Self, cbor::DecodeError> {
        match value {
            cbor::Value::ByteString(data) => {
                Self::from_bytes(&data).map_err(|_| cbor::DecodeError::UnexpectedType)
            }
            _ => Err(cbor::DecodeError::UnexpectedType),
        }
    }
}

/// A memory-backed signer for Secp256k1.
pub struct MemorySigner {
    sk: ecdsa::SigningKey,
}

impl MemorySigner {
    pub fn sign_digest<D>(&self, digest: D) -> Result<Signature, Error>
    where
        D: Digest + FixedOutput<OutputSize = U32>,
    {
        let signature: ecdsa::Signature = self.sk.sign_digest(digest);
        Ok(signature.to_der().as_bytes().to_vec().into())
    }
}

impl super::Signer for MemorySigner {
    fn new_from_seed(seed: &[u8]) -> Result<Self, Error> {
        let sk = ecdsa::SigningKey::from_slice(seed).map_err(|_| Error::InvalidArgument)?;
        Ok(Self { sk })
    }

    fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
        Ok(Self {
            sk: ecdsa::SigningKey::from_slice(bytes).map_err(|_| Error::MalformedPrivateKey)?,
        })
    }

    fn to_bytes(&self) -> Vec<u8> {
        self.sk.to_bytes().to_vec()
    }

    fn public_key(&self) -> super::PublicKey {
        super::PublicKey::Secp256k1(PublicKey(self.sk.verifying_key().to_encoded_point(true)))
    }

    fn sign(&self, context: &[u8], message: &[u8]) -> Result<Signature, Error> {
        let digest = Sha512_256::new()
            .chain_update(context)
            .chain_update(message);
        let signature: ecdsa::Signature = self.sk.sign_digest(digest);
        Ok(signature.to_der().as_bytes().to_vec().into())
    }

    fn sign_raw(&self, message: &[u8]) -> Result<Signature, Error> {
        let signature: ecdsa::Signature = self.sk.sign(message);
        Ok(signature.to_der().as_bytes().to_vec().into())
    }
}