• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

butlergroup / rust-libp2p / 18610913338

18 Oct 2025 04:41AM UTC coverage: 78.379% (+2.5%) from 75.842%
18610913338

push

github

butlergroup
	modified:   .github/workflows/ci.yml

36944 of 47135 relevant lines covered (78.38%)

37728.24 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

77.61
/identity/src/ecdsa.rs
1
// Copyright 2019 Parity Technologies (UK) Ltd.
2
//
3
// Permission is hereby granted, free of charge, to any person obtaining a
4
// copy of this software and associated documentation files (the "Software"),
5
// to deal in the Software without restriction, including without limitation
6
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
7
// and/or sell copies of the Software, and to permit persons to whom the
8
// Software is furnished to do so, subject to the following conditions:
9
//
10
// The above copyright notice and this permission notice shall be included in
11
// all copies or substantial portions of the Software.
12
//
13
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19
// DEALINGS IN THE SOFTWARE.
20

21
//! ECDSA keys with secp256r1 curve support.
22

23
use core::{cmp, fmt, hash};
24
use std::convert::Infallible;
25

26
use p256::{
27
    ecdsa::{
28
        signature::{Signer, Verifier},
29
        Signature, SigningKey, VerifyingKey,
30
    },
31
    EncodedPoint,
32
};
33
use sec1::{DecodeEcPrivateKey, EncodeEcPrivateKey};
34
use zeroize::Zeroize;
35

36
use super::error::DecodingError;
37

38
/// An ECDSA keypair generated using `secp256r1` curve.
39
#[derive(Clone)]
40
pub struct Keypair {
41
    secret: SecretKey,
42
    public: PublicKey,
43
}
44

45
impl Keypair {
46
    /// Generate a new random ECDSA keypair.
47
    #[cfg(feature = "rand")]
48
    pub fn generate() -> Keypair {
3✔
49
        Keypair::from(SecretKey::generate())
3✔
50
    }
3✔
51

52
    /// Sign a message using the private key of this keypair.
53
    pub fn sign(&self, msg: &[u8]) -> Vec<u8> {
1✔
54
        self.secret.sign(msg)
1✔
55
    }
1✔
56

57
    /// Get the public key of this keypair.
58
    pub fn public(&self) -> &PublicKey {
7✔
59
        &self.public
7✔
60
    }
7✔
61

62
    /// Get the secret key of this keypair.
63
    pub fn secret(&self) -> &SecretKey {
2✔
64
        &self.secret
2✔
65
    }
2✔
66
}
67

68
impl fmt::Debug for Keypair {
69
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
×
70
        f.debug_struct("Keypair")
×
71
            .field("public", &self.public())
×
72
            .finish()
×
73
    }
×
74
}
75

76
/// Promote an ECDSA secret key into a keypair.
77
impl From<SecretKey> for Keypair {
78
    fn from(secret: SecretKey) -> Keypair {
5✔
79
        let public = PublicKey(VerifyingKey::from(&secret.0));
5✔
80
        Keypair { secret, public }
5✔
81
    }
5✔
82
}
83

84
/// Demote an ECDSA keypair to a secret key.
85
impl From<Keypair> for SecretKey {
86
    fn from(kp: Keypair) -> SecretKey {
×
87
        kp.secret
×
88
    }
×
89
}
90

91
/// An ECDSA secret key generated using `secp256r1` curve.
92
#[derive(Clone)]
93
pub struct SecretKey(SigningKey);
94

95
impl SecretKey {
96
    /// Generate a new random ECDSA secret key.
97
    #[cfg(feature = "rand")]
98
    pub fn generate() -> SecretKey {
3✔
99
        SecretKey(SigningKey::random(&mut rand::thread_rng()))
3✔
100
    }
3✔
101

102
    /// Sign a message with this secret key, producing a DER-encoded ECDSA signature.
103
    pub fn sign(&self, msg: &[u8]) -> Vec<u8> {
1✔
104
        let signature: p256::ecdsa::DerSignature = self.0.sign(msg);
1✔
105

106
        signature.as_bytes().to_owned()
1✔
107
    }
1✔
108

109
    /// Convert a secret key into a byte buffer containing raw scalar of the key.
110
    pub fn to_bytes(&self) -> Vec<u8> {
1✔
111
        self.0.to_bytes().to_vec()
1✔
112
    }
1✔
113

114
    /// Try to parse a secret key from a byte buffer containing raw scalar of the key.
115
    pub fn try_from_bytes(buf: impl AsRef<[u8]>) -> Result<SecretKey, DecodingError> {
×
116
        SigningKey::from_bytes(buf.as_ref().into())
×
117
            .map_err(|err| DecodingError::failed_to_parse("ecdsa p256 secret key", err))
×
118
            .map(SecretKey)
×
119
    }
×
120

121
    /// Encode the secret key into DER-encoded byte buffer.
122
    pub(crate) fn encode_der(&self) -> Vec<u8> {
1✔
123
        self.0
1✔
124
            .to_sec1_der()
1✔
125
            .expect("Encoding to pkcs#8 format to succeed")
1✔
126
            .to_bytes()
1✔
127
            .to_vec()
1✔
128
    }
1✔
129

130
    /// Try to decode a secret key from a DER-encoded byte buffer, zeroize the buffer on success.
131
    pub(crate) fn try_decode_der(buf: &mut [u8]) -> Result<Self, DecodingError> {
2✔
132
        match SigningKey::from_sec1_der(buf) {
2✔
133
            Ok(key) => {
2✔
134
                buf.zeroize();
2✔
135
                Ok(SecretKey(key))
2✔
136
            }
137
            Err(e) => Err(DecodingError::failed_to_parse("ECDSA", e)),
×
138
        }
139
    }
2✔
140
}
141

142
impl fmt::Debug for SecretKey {
143
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
×
144
        write!(f, "SecretKey")
×
145
    }
×
146
}
147

148
/// An ECDSA public key.
149
#[derive(Clone, Eq, PartialOrd, Ord)]
150
pub struct PublicKey(VerifyingKey);
151

152
impl PublicKey {
153
    /// Verify an ECDSA signature on a message using the public key.
154
    pub fn verify(&self, msg: &[u8], sig: &[u8]) -> bool {
3✔
155
        let Ok(sig) = Signature::from_der(sig) else {
3✔
156
            return false;
1✔
157
        };
158
        self.0.verify(msg, &sig).is_ok()
2✔
159
    }
3✔
160

161
    /// Try to parse a public key from a byte buffer containing raw
162
    /// components of a key with or without compression.
163
    pub fn try_from_bytes(k: &[u8]) -> Result<PublicKey, DecodingError> {
2✔
164
        let enc_pt = EncodedPoint::from_bytes(k)
2✔
165
            .map_err(|e| DecodingError::failed_to_parse("ecdsa p256 encoded point", e))?;
2✔
166

167
        VerifyingKey::from_encoded_point(&enc_pt)
2✔
168
            .map_err(|err| DecodingError::failed_to_parse("ecdsa p256 public key", err))
2✔
169
            .map(PublicKey)
2✔
170
    }
2✔
171

172
    /// Convert a public key into a byte buffer containing
173
    /// raw components of the key without compression.
174
    pub fn to_bytes(&self) -> Vec<u8> {
9✔
175
        self.0.to_encoded_point(false).as_bytes().to_owned()
9✔
176
    }
9✔
177

178
    /// Encode a public key into a DER encoded byte buffer as defined by SEC1 standard.
179
    pub fn encode_der(&self) -> Vec<u8> {
5✔
180
        let buf = self.to_bytes();
5✔
181
        Self::add_asn1_header(&buf)
5✔
182
    }
5✔
183

184
    /// Try to decode a public key from a DER encoded byte buffer as defined by SEC1 standard.
185
    pub fn try_decode_der(k: &[u8]) -> Result<PublicKey, DecodingError> {
2✔
186
        let buf = Self::del_asn1_header(k).ok_or_else(|| {
2✔
187
            DecodingError::failed_to_parse::<Infallible, _>(
×
188
                "ASN.1-encoded ecdsa p256 public key",
189
                None,
×
190
            )
191
        })?;
×
192
        Self::try_from_bytes(buf)
2✔
193
    }
2✔
194

195
    // ecPublicKey (ANSI X9.62 public key type) OID: 1.2.840.10045.2.1
196
    const EC_PUBLIC_KEY_OID: [u8; 9] = [0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01];
197
    // secp256r1 OID: 1.2.840.10045.3.1.7
198
    const SECP_256_R1_OID: [u8; 10] = [0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07];
199

200
    // Add ASN1 header.
201
    fn add_asn1_header(key_buf: &[u8]) -> Vec<u8> {
5✔
202
        // ASN.1 struct type and length.
203
        let mut asn1_buf = vec![
5✔
204
            0x30,
205
            0x00,
206
            0x30,
207
            (Self::EC_PUBLIC_KEY_OID.len() + Self::SECP_256_R1_OID.len()) as u8,
5✔
208
        ];
209
        // Append OIDs.
210
        asn1_buf.extend_from_slice(&Self::EC_PUBLIC_KEY_OID);
5✔
211
        asn1_buf.extend_from_slice(&Self::SECP_256_R1_OID);
5✔
212
        // Append key bitstring type and length.
213
        asn1_buf.extend_from_slice(&[0x03, (key_buf.len() + 1) as u8, 0x00]);
5✔
214
        // Append key bitstring value.
215
        asn1_buf.extend_from_slice(key_buf);
5✔
216
        // Update overall length field.
217
        asn1_buf[1] = (asn1_buf.len() - 2) as u8;
5✔
218

219
        asn1_buf
5✔
220
    }
5✔
221

222
    // Check and remove ASN.1 header.
223
    fn del_asn1_header(asn1_buf: &[u8]) -> Option<&[u8]> {
2✔
224
        let oids_len = Self::EC_PUBLIC_KEY_OID.len() + Self::SECP_256_R1_OID.len();
2✔
225
        let asn1_head = asn1_buf.get(..4)?;
2✔
226
        let oids_buf = asn1_buf.get(4..4 + oids_len)?;
2✔
227
        let bitstr_head = asn1_buf.get(4 + oids_len..4 + oids_len + 3)?;
2✔
228

229
        // Sanity check
230
        if asn1_head[0] != 0x30
2✔
231
            || asn1_head[2] != 0x30
2✔
232
            || asn1_head[3] as usize != oids_len
2✔
233
            || oids_buf[..Self::EC_PUBLIC_KEY_OID.len()] != Self::EC_PUBLIC_KEY_OID
2✔
234
            || oids_buf[Self::EC_PUBLIC_KEY_OID.len()..] != Self::SECP_256_R1_OID
2✔
235
            || bitstr_head[0] != 0x03
2✔
236
            || bitstr_head[2] != 0x00
2✔
237
        {
238
            return None;
×
239
        }
2✔
240

241
        let key_len = bitstr_head[1].checked_sub(1)? as usize;
2✔
242
        let key_buf = asn1_buf.get(4 + oids_len + 3..4 + oids_len + 3 + key_len)?;
2✔
243
        Some(key_buf)
2✔
244
    }
2✔
245
}
246

247
impl fmt::Debug for PublicKey {
248
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
×
249
        f.write_str("PublicKey(asn.1 uncompressed): ")?;
×
250
        for byte in &self.encode_der() {
×
251
            write!(f, "{byte:x}")?;
×
252
        }
253
        Ok(())
×
254
    }
×
255
}
256

257
impl cmp::PartialEq for PublicKey {
258
    fn eq(&self, other: &Self) -> bool {
2✔
259
        self.to_bytes().eq(&other.to_bytes())
2✔
260
    }
2✔
261
}
262

263
impl hash::Hash for PublicKey {
264
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
×
265
        self.to_bytes().hash(state);
×
266
    }
×
267
}
268

269
#[cfg(test)]
270
mod tests {
271
    use super::*;
272

273
    #[test]
274
    #[cfg(feature = "rand")]
275
    fn sign_verify() {
1✔
276
        let pair = Keypair::generate();
1✔
277
        let pk = pair.public();
1✔
278

279
        let msg = "hello world".as_bytes();
1✔
280
        let sig = pair.sign(msg);
1✔
281
        assert!(pk.verify(msg, &sig));
1✔
282

283
        let mut invalid_sig = sig.clone();
1✔
284
        invalid_sig[3..6].copy_from_slice(&[10, 23, 42]);
1✔
285
        assert!(!pk.verify(msg, &invalid_sig));
1✔
286

287
        let invalid_msg = "h3ll0 w0rld".as_bytes();
1✔
288
        assert!(!pk.verify(invalid_msg, &sig));
1✔
289
    }
1✔
290
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc