pub mod secp256k1;
use std;
use std::borrow::Borrow;
use std::error::Error as StdError;
#[derive(Debug)]
pub enum Error {
NoSuchAlgorithm(String),
ParseError(String),
SigningError(Box<StdError>),
KeyGenError(String),
}
impl StdError for Error {
fn description(&self) -> &str {
match *self {
Error::NoSuchAlgorithm(ref msg) => msg,
Error::ParseError(ref msg) => msg,
Error::SigningError(ref err) => err.description(),
Error::KeyGenError(ref msg) => msg,
}
}
fn cause(&self) -> Option<&StdError> {
match *self {
Error::NoSuchAlgorithm(_) => None,
Error::ParseError(_) => None,
Error::SigningError(ref err) => Some(err.borrow()),
Error::KeyGenError(_) => None,
}
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match *self {
Error::NoSuchAlgorithm(ref s) => write!(f, "NoSuchAlgorithm: {}", s),
Error::ParseError(ref s) => write!(f, "ParseError: {}", s),
Error::SigningError(ref err) => write!(f, "SigningError: {}", err.description()),
Error::KeyGenError(ref s) => write!(f, "KeyGenError: {}", s),
}
}
}
pub trait PrivateKey {
fn get_algorithm_name(&self) -> &str;
fn as_hex(&self) -> String;
fn as_slice(&self) -> &[u8];
}
pub trait PublicKey {
fn get_algorithm_name(&self) -> &str;
fn as_hex(&self) -> String;
fn as_slice(&self) -> &[u8];
}
pub trait Context {
fn get_algorithm_name(&self) -> &str;
fn sign(&self, message: &[u8], key: &PrivateKey) -> Result<String, Error>;
fn verify(&self, signature: &str, message: &[u8], key: &PublicKey) -> Result<bool, Error>;
fn get_public_key(&self, private_key: &PrivateKey) -> Result<Box<PublicKey>, Error>;
fn new_random_private_key(&self) -> Result<Box<PrivateKey>, Error>;
}
pub fn create_context(algorithm_name: &str) -> Result<Box<Context>, Error> {
match algorithm_name {
"secp256k1" => Ok(Box::new(secp256k1::Secp256k1Context::new())),
_ => Err(Error::NoSuchAlgorithm(format!(
"no such algorithm: {}",
algorithm_name
))),
}
}
pub struct CryptoFactory<'a> {
context: &'a Context,
}
impl<'a> CryptoFactory<'a> {
pub fn new(context: &'a Context) -> Self {
CryptoFactory { context }
}
pub fn get_context(&self) -> &Context {
self.context
}
pub fn new_signer(&self, key: &'a PrivateKey) -> Signer {
Signer::new(self.context, key)
}
}
pub struct Signer<'a> {
context: &'a Context,
key: &'a PrivateKey,
}
impl<'a> Signer<'a> {
pub fn new(context: &'a Context, key: &'a PrivateKey) -> Self {
Signer { context, key }
}
pub fn sign(&self, message: &[u8]) -> Result<String, Error> {
self.context.sign(message, self.key)
}
pub fn get_public_key(&self) -> Result<Box<PublicKey>, Error> {
self.context.get_public_key(self.key)
}
}
#[cfg(test)]
mod signing_test {
use super::create_context;
#[test]
fn no_such_algorithm() {
let result = create_context("invalid");
assert!(result.is_err())
}
}