2019-03-11 13:42:53 +01:00
|
|
|
// Copyright 2019 Parity Technologies (UK) Ltd.
|
|
|
|
//
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
// copy of this software and associated documentation files (the "Software"),
|
|
|
|
// to deal in the Software without restriction, including without limitation
|
|
|
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
// and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
// Software is furnished to do so, subject to the following conditions:
|
|
|
|
//
|
|
|
|
// The above copyright notice and this permission notice shall be included in
|
|
|
|
// all copies or substantial portions of the Software.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
|
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
// DEALINGS IN THE SOFTWARE.
|
|
|
|
|
|
|
|
//! Secp256k1 keys.
|
|
|
|
|
|
|
|
use asn1_der::{FromDerObject, DerObject};
|
|
|
|
use lazy_static::lazy_static;
|
|
|
|
use sha2::{Digest as ShaDigestTrait, Sha256};
|
|
|
|
use secp256k1 as secp;
|
|
|
|
use secp::{Message, Signature};
|
|
|
|
use super::error::DecodingError;
|
|
|
|
use zeroize::Zeroize;
|
|
|
|
|
|
|
|
// Cached `Secp256k1` context, to avoid recreating it every time.
|
|
|
|
lazy_static! {
|
|
|
|
static ref SECP: secp::Secp256k1<secp::All> = secp::Secp256k1::new();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A Secp256k1 keypair.
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct Keypair {
|
|
|
|
secret: SecretKey,
|
|
|
|
public: PublicKey
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Keypair {
|
|
|
|
/// Generate a new sec256k1 `Keypair`.
|
|
|
|
pub fn generate() -> Keypair {
|
|
|
|
Keypair::from(SecretKey::generate())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get the public key of this keypair.
|
|
|
|
pub fn public(&self) -> &PublicKey {
|
|
|
|
&self.public
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get the secret key of this keypair.
|
|
|
|
pub fn secret(&self) -> &SecretKey {
|
|
|
|
&self.secret
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Promote a Secp256k1 secret key into a keypair.
|
|
|
|
impl From<SecretKey> for Keypair {
|
|
|
|
fn from(secret: SecretKey) -> Keypair {
|
|
|
|
let public = PublicKey(secp::key::PublicKey::from_secret_key(&SECP, &secret.0));
|
|
|
|
Keypair { secret, public }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Demote a Secp256k1 keypair into a secret key.
|
|
|
|
impl From<Keypair> for SecretKey {
|
|
|
|
fn from(kp: Keypair) -> SecretKey {
|
|
|
|
kp.secret
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A Secp256k1 secret key.
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct SecretKey(secp::key::SecretKey);
|
|
|
|
|
|
|
|
/// View the bytes of the secret key.
|
|
|
|
impl AsRef<[u8]> for SecretKey {
|
|
|
|
fn as_ref(&self) -> &[u8] {
|
|
|
|
&self.0[..]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SecretKey {
|
|
|
|
/// Generate a new Secp256k1 secret key.
|
|
|
|
pub fn generate() -> SecretKey {
|
|
|
|
SecretKey(secp::key::SecretKey::new(&mut secp::rand::thread_rng()))
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create a secret key from a byte slice, zeroing the slice on success.
|
|
|
|
/// If the bytes do not constitute a valid Secp256k1 secret key, an
|
|
|
|
/// error is returned.
|
|
|
|
pub fn from_bytes(mut sk: impl AsMut<[u8]>) -> Result<SecretKey, DecodingError> {
|
|
|
|
let sk_bytes = sk.as_mut();
|
|
|
|
let secret = secp::key::SecretKey::from_slice(&*sk_bytes)
|
|
|
|
.map_err(|e| DecodingError::new("Secp256k1 secret key", e))?;
|
2019-04-03 10:31:09 +02:00
|
|
|
sk_bytes.zeroize();
|
2019-03-11 13:42:53 +01:00
|
|
|
Ok(SecretKey(secret))
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Decode a DER-encoded Secp256k1 secret key in an ECPrivateKey
|
|
|
|
/// structure as defined in [RFC5915].
|
|
|
|
///
|
|
|
|
/// [RFC5915]: https://tools.ietf.org/html/rfc5915
|
|
|
|
pub fn from_der(mut der: impl AsMut<[u8]>) -> Result<SecretKey, DecodingError> {
|
|
|
|
// TODO: Stricter parsing.
|
|
|
|
let der_obj = der.as_mut();
|
|
|
|
let obj: Vec<DerObject> = FromDerObject::deserialize((&*der_obj).iter())
|
|
|
|
.map_err(|e| DecodingError::new("Secp256k1 DER ECPrivateKey", e))?;
|
|
|
|
der_obj.zeroize();
|
|
|
|
let sk_obj = obj.into_iter().nth(1)
|
|
|
|
.ok_or_else(|| "Not enough elements in DER".to_string())?;
|
|
|
|
let mut sk_bytes: Vec<u8> = FromDerObject::from_der_object(sk_obj)
|
|
|
|
.map_err(|e| e.to_string())?;
|
|
|
|
let sk = SecretKey::from_bytes(&mut sk_bytes)?;
|
|
|
|
sk_bytes.zeroize();
|
|
|
|
Ok(sk)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sign a message with this secret key, producing a DER-encoded
|
|
|
|
/// ECDSA signature, as defined in [RFC3278].
|
|
|
|
///
|
|
|
|
/// [RFC3278]: https://tools.ietf.org/html/rfc3278#section-8.2
|
|
|
|
pub fn sign(&self, msg: &[u8]) -> Vec<u8> {
|
|
|
|
let m = Message::from_slice(Sha256::digest(&msg).as_ref())
|
|
|
|
.expect("digest output length doesn't match secp256k1 input length");
|
|
|
|
SECP.sign(&m, &self.0).serialize_der()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A Secp256k1 public key.
|
|
|
|
#[derive(PartialEq, Eq, Clone, Debug)]
|
|
|
|
pub struct PublicKey(secp::key::PublicKey);
|
|
|
|
|
|
|
|
impl PublicKey {
|
|
|
|
/// Verify the Secp256k1 signature on a message using the public key.
|
|
|
|
pub fn verify(&self, msg: &[u8], sig: &[u8]) -> bool {
|
|
|
|
Message::from_slice(&Sha256::digest(msg))
|
|
|
|
.and_then(|m| Signature::from_der(sig)
|
|
|
|
.and_then(|s| SECP.verify(&m, &s, &self.0))).is_ok()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Encode the public key in compressed form, i.e. with one coordinate
|
|
|
|
/// represented by a single bit.
|
|
|
|
pub fn encode(&self) -> [u8; 33] {
|
|
|
|
self.0.serialize()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Decode a public key from a byte slice in the the format produced
|
|
|
|
/// by `encode`.
|
|
|
|
pub fn decode(k: &[u8]) -> Result<PublicKey, DecodingError> {
|
|
|
|
secp256k1::PublicKey::from_slice(k)
|
|
|
|
.map_err(|e| DecodingError::new("Secp256k1 public key", e))
|
|
|
|
.map(PublicKey)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-03 10:31:09 +02:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn secp256k1_secret_from_bytes() {
|
|
|
|
let sk1 = SecretKey::generate();
|
|
|
|
let mut sk_bytes = [0; 32];
|
|
|
|
sk_bytes.copy_from_slice(sk1.as_ref());
|
|
|
|
let sk2 = SecretKey::from_bytes(&mut sk_bytes).unwrap();
|
|
|
|
assert_eq!(sk1.as_ref(), sk2.as_ref());
|
|
|
|
assert_eq!(sk_bytes, [0; 32]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|